Compare commits

...

18 Commits

59 changed files with 4891 additions and 390 deletions

View File

@ -1,4 +1,6 @@
<manifest xmlns:android="http://schemas.android.com/apk/res/android"> <manifest xmlns:android="http://schemas.android.com/apk/res/android">
<uses-permission android:name="android.permission.USE_BIOMETRIC"/>
<uses-permission android:name="android.permission.USE_FINGERPRINT"/>
<application <application
android:label="kmobile" android:label="kmobile"
android:name="${applicationName}" android:name="${applicationName}"

View File

@ -1,5 +1,5 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<!-- Modify this file to customize your launch splash screen --> <!-- Modify this file to customize your launch splash screens -->
<layer-list xmlns:android="http://schemas.android.com/apk/res/android"> <layer-list xmlns:android="http://schemas.android.com/apk/res/android">
<item android:drawable="?android:colorBackground" /> <item android:drawable="?android:colorBackground" />

View File

@ -1,5 +1,5 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<!-- Modify this file to customize your launch splash screen --> <!-- Modify this file to customize your launch splash screens -->
<layer-list xmlns:android="http://schemas.android.com/apk/res/android"> <layer-list xmlns:android="http://schemas.android.com/apk/res/android">
<item android:drawable="@android:color/white" /> <item android:drawable="@android:color/white" />

View File

@ -2,7 +2,7 @@
<resources> <resources>
<!-- Theme applied to the Android Window while the process is starting when the OS's Dark Mode setting is on --> <!-- Theme applied to the Android Window while the process is starting when the OS's Dark Mode setting is on -->
<style name="LaunchTheme" parent="@android:style/Theme.Black.NoTitleBar"> <style name="LaunchTheme" parent="@android:style/Theme.Black.NoTitleBar">
<!-- Show a splash screen on the activity. Automatically removed when <!-- Show a splash screens on the activity. Automatically removed when
the Flutter engine draws its first frame --> the Flutter engine draws its first frame -->
<item name="android:windowBackground">@drawable/launch_background</item> <item name="android:windowBackground">@drawable/launch_background</item>
</style> </style>

View File

@ -2,7 +2,7 @@
<resources> <resources>
<!-- Theme applied to the Android Window while the process is starting when the OS's Dark Mode setting is off --> <!-- Theme applied to the Android Window while the process is starting when the OS's Dark Mode setting is off -->
<style name="LaunchTheme" parent="@android:style/Theme.Light.NoTitleBar"> <style name="LaunchTheme" parent="@android:style/Theme.Light.NoTitleBar">
<!-- Show a splash screen on the activity. Automatically removed when <!-- Show a splash screens on the activity. Automatically removed when
the Flutter engine draws its first frame --> the Flutter engine draws its first frame -->
<item name="android:windowBackground">@drawable/launch_background</item> <item name="android:windowBackground">@drawable/launch_background</item>
</style> </style>

BIN
assets/fonts/Rubik-Bold.ttf Normal file

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 26 KiB

BIN
assets/images/avatar.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.7 KiB

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 26 KiB

3
devtools_options.yaml Normal file
View File

@ -0,0 +1,3 @@
description: This file stores settings for Dart & Flutter DevTools.
documentation: https://docs.flutter.dev/tools/devtools/extensions#configure-extension-enablement-states
extensions:

View File

@ -45,5 +45,7 @@
<true/> <true/>
<key>UIApplicationSupportsIndirectInputEvents</key> <key>UIApplicationSupportsIndirectInputEvents</key>
<true/> <true/>
<key>NSFaceIDUsageDescription</key>
<string>We use Face ID to secure your data.</string>
</dict> </dict>
</plist> </plist>

3
l10n.yaml Normal file
View File

@ -0,0 +1,3 @@
arb-dir: lib/l10n
template-arb-file: app_en.arb
output-localization-file: app_localizations.dart

View File

@ -13,7 +13,7 @@ class AuthInterceptor extends Interceptor {
RequestInterceptorHandler handler, RequestInterceptorHandler handler,
) async { ) async {
// Skip auth header for login and refresh endpoints // Skip auth header for login and refresh endpoints
if (options.path.contains('/auth/login') || if (options.path.contains('/login') ||
options.path.contains('/auth/refresh')) { options.path.contains('/auth/refresh')) {
return handler.next(options); return handler.next(options);
} }

View File

@ -1,20 +1,26 @@
import 'dart:developer'; import 'dart:developer';
import 'package:dio/dio.dart'; import 'package:dio/dio.dart';
import 'package:flutter/cupertino.dart';
import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart';
import '../../app.dart';
import '../../features/auth/models/auth_token.dart'; import '../../features/auth/models/auth_token.dart';
import '../../features/auth/models/auth_credentials.dart'; import '../../features/auth/models/auth_credentials.dart';
import '../../data/models/user.dart'; import '../../data/models/user.dart';
import '../../core/errors/exceptions.dart'; import '../../core/errors/exceptions.dart';
import 'package:local_auth/local_auth.dart';
import '../../features/dashboard/screens/dashboard_screen.dart';
class AuthService { class AuthService {
final Dio _dio; final Dio _dio;
AuthService(this._dio); AuthService(this._dio);
Future<AuthToken> login(AuthCredentials credentials) async { Future<AuthToken> login(AuthCredentials credentials) async {
try { try {
final response = await _dio.post( final response = await _dio.post(
'/auth/login', '/login',
data: credentials.toJson(), data: credentials.toJson(),
); );
@ -24,6 +30,9 @@ class AuthService {
throw AuthException('Login failed'); throw AuthException('Login failed');
} }
} on DioException catch (e) { } on DioException catch (e) {
if (kDebugMode) {
print(e.toString());
}
if (e.response?.statusCode == 401) { if (e.response?.statusCode == 401) {
throw AuthException('Invalid credentials'); throw AuthException('Invalid credentials');
} }

View File

@ -1,13 +1,17 @@
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter/services.dart'; import 'package:flutter/services.dart';
import 'package:flutter_bloc/flutter_bloc.dart'; import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:kmobile/features/customer_info/screens/customer_info_screen.dart';
import 'config/themes.dart'; import 'config/themes.dart';
import 'config/routes.dart'; import 'config/routes.dart';
import 'di/injection.dart'; import 'di/injection.dart';
import 'features/auth/controllers/auth_cubit.dart'; import 'features/auth/controllers/auth_cubit.dart';
import 'features/auth/controllers/auth_state.dart'; import 'features/auth/controllers/auth_state.dart';
import 'features/card/screens/card_management_screen.dart';
import 'features/auth/screens/login_screen.dart'; import 'features/auth/screens/login_screen.dart';
import 'features/service/screens/service_screen.dart';
import 'features/dashboard/screens/dashboard_screen.dart'; import 'features/dashboard/screens/dashboard_screen.dart';
import 'package:material_symbols_icons/material_symbols_icons.dart';
class KMobile extends StatelessWidget { class KMobile extends StatelessWidget {
const KMobile({super.key}); const KMobile({super.key});
@ -52,8 +56,12 @@ class KMobile extends StatelessWidget {
return const _SplashScreen(); return const _SplashScreen();
} }
if(state is ShowBiometricPermission){
return const BiometricPermissionScreen();
}
if (state is Authenticated) { if (state is Authenticated) {
return const DashboardScreen(); return const NavigationScaffold();
} }
return const LoginScreen(); return const LoginScreen();
@ -64,7 +72,7 @@ class KMobile extends StatelessWidget {
} }
} }
// Simple splash screen component // Simple splash screens component
class _SplashScreen extends StatelessWidget { class _SplashScreen extends StatelessWidget {
const _SplashScreen(); const _SplashScreen();
@ -104,3 +112,93 @@ class _SplashScreen extends StatelessWidget {
); );
} }
} }
class NavigationScaffold extends StatefulWidget {
const NavigationScaffold({super.key});
@override
State<NavigationScaffold> createState() => _NavigationScaffoldState();
}
class _NavigationScaffoldState extends State<NavigationScaffold> {
final PageController _pageController = PageController();
int _selectedIndex = 0;
final List<Widget> _pages = [
DashboardScreen(),
CardManagementScreen(),
ServiceScreen(),
CustomerInfoScreen()
];
void _onItemTapped(int index) {
setState(() {
_selectedIndex = index;
});
_pageController.jumpToPage(index);
}
@override
Widget build(BuildContext context) {
return Scaffold(
body: PageView(
controller: _pageController,
physics: const NeverScrollableScrollPhysics(),
children: _pages,
),
bottomNavigationBar: BottomNavigationBar(
currentIndex: _selectedIndex,
type: BottomNavigationBarType.fixed,
items: const [
BottomNavigationBarItem(
icon: Icon(Icons.home_filled),
label: 'Home',
),
BottomNavigationBarItem(
icon: Icon(Symbols.credit_card),
label: 'Card',
),
BottomNavigationBarItem(
icon: Icon(Symbols.concierge),
label: 'Services',
),
],
onTap: _onItemTapped,
backgroundColor: const Color(0xFFE0F7FA), // Light blue background
selectedItemColor: Colors.blue[800],
unselectedItemColor: Colors.black54,
),
);
}
}
class BiometricPermissionScreen extends StatelessWidget {
const BiometricPermissionScreen({super.key});
@override
Widget build(BuildContext context) {
final cubit = context.read<AuthCubit>();
return Scaffold(
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
const Text('Would you like to enable biometric authentication?'),
ElevatedButton(
onPressed: () => cubit.handleBiometricChoice(true),
child: const Text('Yes'),
),
TextButton(
onPressed: () => cubit.handleBiometricChoice(false),
child: const Text('No, thanks'),
),
],
),
),
);
}
}

View File

@ -1,4 +1,7 @@
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:kmobile/features/customer_info/screens/customer_info_screen.dart';
import 'package:kmobile/features/auth/screens/mpin_screen.dart';
import '../app.dart';
import '../features/auth/screens/login_screen.dart'; import '../features/auth/screens/login_screen.dart';
// import '../features/auth/screens/forgot_password_screen.dart'; // import '../features/auth/screens/forgot_password_screen.dart';
// import '../features/auth/screens/register_screen.dart'; // import '../features/auth/screens/register_screen.dart';
@ -15,18 +18,24 @@ class AppRoutes {
// Route names // Route names
static const String splash = '/'; static const String splash = '/';
static const String login = '/login'; static const String login = '/login';
static const String mPin = '/mPin';
static const String register = '/register'; static const String register = '/register';
static const String forgotPassword = '/forgot-password'; static const String forgotPassword = '/forgot-password';
static const String navigationScaffold = '/navigation-scaffold';
static const String dashboard = '/dashboard'; static const String dashboard = '/dashboard';
static const String accounts = '/accounts'; static const String accounts = '/accounts';
static const String transactions = '/transactions'; static const String transactions = '/transactions';
static const String payments = '/payments'; static const String payments = '/payments';
static const String customer_info = '/customer-info';
// Route generator // Route generator
static Route<dynamic> generateRoute(RouteSettings settings) { static Route<dynamic> generateRoute(RouteSettings settings) {
switch (settings.name) { switch (settings.name) {
case login: case login:
return MaterialPageRoute(builder: (_) => const LoginScreen()); return MaterialPageRoute(builder: (_) => const LoginScreen());
case mPin:
return MaterialPageRoute(builder: (_) => const MPinScreen());
case register: case register:
// Placeholder - create the RegisterScreen class and uncomment // Placeholder - create the RegisterScreen class and uncomment
@ -37,9 +46,15 @@ class AppRoutes {
// Placeholder - create the ForgotPasswordScreen class and uncomment // Placeholder - create the ForgotPasswordScreen class and uncomment
// return MaterialPageRoute(builder: (_) => const ForgotPasswordScreen()); // return MaterialPageRoute(builder: (_) => const ForgotPasswordScreen());
return _errorRoute(); return _errorRoute();
case navigationScaffold:
return MaterialPageRoute(builder: (_) => const NavigationScaffold());
case dashboard: case dashboard:
return MaterialPageRoute(builder: (_) => const DashboardScreen()); return MaterialPageRoute(builder: (_) => const DashboardScreen());
case customer_info:
return MaterialPageRoute(builder: (_) => const CustomerInfoScreen());
case accounts: case accounts:
// Placeholder - create the AccountsScreen class and uncomment // Placeholder - create the AccountsScreen class and uncomment

View File

@ -3,7 +3,7 @@ import 'package:flutter/material.dart';
class AppThemes { class AppThemes {
// Private constructor to prevent instantiation // Private constructor to prevent instantiation
AppThemes._(); AppThemes._();
// Light theme colors // Light theme colors
static const Color _primaryColorLight = Color(0xFF1E88E5); // Blue 600 static const Color _primaryColorLight = Color(0xFF1E88E5); // Blue 600
static const Color _secondaryColorLight = Color(0xFF26A69A); // Teal 400 static const Color _secondaryColorLight = Color(0xFF26A69A); // Teal 400
@ -22,51 +22,61 @@ class AppThemes {
fontSize: 96, fontSize: 96,
fontWeight: FontWeight.w300, fontWeight: FontWeight.w300,
color: Color(0xFF212121), color: Color(0xFF212121),
fontFamily: 'Rubik',
), ),
displayMedium: TextStyle( displayMedium: TextStyle(
fontSize: 60, fontSize: 60,
fontWeight: FontWeight.w300, fontWeight: FontWeight.w300,
color: Color(0xFF212121), color: Color(0xFF212121),
fontFamily: 'Rubik',
), ),
displaySmall: TextStyle( displaySmall: TextStyle(
fontSize: 48, fontSize: 48,
fontWeight: FontWeight.w400, fontWeight: FontWeight.w400,
color: Color(0xFF212121), color: Color(0xFF212121),
fontFamily: 'Rubik',
), ),
headlineMedium: TextStyle( headlineMedium: TextStyle(
fontSize: 34, fontSize: 34,
fontWeight: FontWeight.w400, fontWeight: FontWeight.w400,
color: Color(0xFF212121), color: Color(0xFF212121),
fontFamily: 'Rubik',
), ),
headlineSmall: TextStyle( headlineSmall: TextStyle(
fontSize: 24, fontSize: 24,
fontWeight: FontWeight.w400, fontWeight: FontWeight.w400,
color: Color(0xFF212121), color: Color(0xFF212121),
fontFamily: 'Rubik',
), ),
titleLarge: TextStyle( titleLarge: TextStyle(
fontSize: 20, fontSize: 20,
fontWeight: FontWeight.w500, fontWeight: FontWeight.w500,
color: Color(0xFF212121), color: Color(0xFF212121),
fontFamily: 'Rubik',
), ),
bodyLarge: TextStyle( bodyLarge: TextStyle(
fontSize: 16, fontSize: 16,
fontWeight: FontWeight.w400, fontWeight: FontWeight.w400,
color: Color(0xFF212121), color: Color(0xFF212121),
fontFamily: 'Rubik',
), ),
bodyMedium: TextStyle( bodyMedium: TextStyle(
fontSize: 14, fontSize: 14,
fontWeight: FontWeight.w400, fontWeight: FontWeight.w400,
color: Color(0xFF212121), color: Color(0xFF212121),
fontFamily: 'Rubik',
), ),
bodySmall: TextStyle( bodySmall: TextStyle(
fontSize: 12, fontSize: 12,
fontWeight: FontWeight.w400, fontWeight: FontWeight.w400,
color: Color(0xFF757575), color: Color(0xFF757575),
fontFamily: 'Rubik',
), ),
labelLarge: TextStyle( labelLarge: TextStyle(
fontSize: 14, fontSize: 14,
fontWeight: FontWeight.w500, fontWeight: FontWeight.w500,
color: Color(0xFF212121), color: Color(0xFF212121),
fontFamily: 'Rubik',
), ),
); );
@ -86,6 +96,7 @@ class AppThemes {
// Light theme // Light theme
static final ThemeData lightTheme = ThemeData( static final ThemeData lightTheme = ThemeData(
useMaterial3: true, useMaterial3: true,
fontFamily: 'Rubik',
colorScheme: const ColorScheme.light( colorScheme: const ColorScheme.light(
primary: _primaryColorLight, primary: _primaryColorLight,
secondary: _secondaryColorLight, secondary: _secondaryColorLight,
@ -167,6 +178,7 @@ class AppThemes {
// Dark theme // Dark theme
static final ThemeData darkTheme = ThemeData( static final ThemeData darkTheme = ThemeData(
fontFamily: 'Rubik',
useMaterial3: true, useMaterial3: true,
colorScheme: const ColorScheme.dark( colorScheme: const ColorScheme.dark(
primary: _primaryColorDark, primary: _primaryColorDark,

View File

@ -35,7 +35,7 @@ Future<void> setupDependencies() async {
Dio _createDioClient() { Dio _createDioClient() {
final dio = Dio( final dio = Dio(
BaseOptions( BaseOptions(
baseUrl: 'https://api.yourbank.com/v1', baseUrl: 'http://localhost:3000',
connectTimeout: const Duration(seconds: 5), connectTimeout: const Duration(seconds: 5),
receiveTimeout: const Duration(seconds: 3), receiveTimeout: const Duration(seconds: 3),
headers: { headers: {

View File

@ -0,0 +1,76 @@
import 'package:flutter/material.dart';
import 'package:material_symbols_icons/material_symbols_icons.dart';
class AccountInfoScreen extends StatefulWidget {
const AccountInfoScreen({super.key});
@override
State<AccountInfoScreen> createState() => _AccountInfoScreen();
}
class _AccountInfoScreen extends State<AccountInfoScreen>{
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
leading: IconButton(icon: const Icon(Symbols.arrow_back_ios_new),
onPressed: () {
Navigator.pop(context);
},),
title: const Text('Account Info', style: TextStyle(color: Colors.black,
fontWeight: FontWeight.w500),),
centerTitle: false,
actions: const [
Padding(
padding: EdgeInsets.only(right: 10.0),
child: CircleAvatar(
backgroundImage: AssetImage('assets/images/avatar.jpg'), // Replace with your image
radius: 20,
),
),
],
),
body: ListView(
padding: const EdgeInsets.all(16.0),
children: const [
InfoRow(title: 'Account Number', value: '700127638009871'),
InfoRow(title: 'Nominee Customer No', value: '700127638009871'),
InfoRow(title: 'SMS Service', value: 'Active'),
InfoRow(title: 'Missed Call Service', value: 'Active'),
InfoRow(title: 'Customer Number', value: '9000875272000212'),
InfoRow(title: 'Product Name', value: 'SAVINGS-PERSONAL'),
InfoRow(title: 'Account Opening Date', value: '12-09-2012'),
InfoRow(title: 'Account Status', value: 'OPEN'),
InfoRow(title: 'Available Balance', value: '12,000 CR'),
InfoRow(title: 'Interest Rate', value: '12.00'),
],
),
);
}
}
class InfoRow extends StatelessWidget {
final String title;
final String value;
const InfoRow({required this.title, required this.value, super.key});
@override
Widget build(BuildContext context) {
return Padding(
padding: const EdgeInsets.symmetric(vertical: 6.0),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(title,
style: const TextStyle(
fontWeight: FontWeight.bold, fontSize: 14)),
const SizedBox(height: 4),
Text(value, style: const TextStyle(fontSize: 14)),
const SizedBox(height: 10),
],
),
);
}
}

View File

@ -0,0 +1,220 @@
import 'package:flutter/material.dart';
import 'package:material_symbols_icons/material_symbols_icons.dart';
class AccountStatementScreen extends StatefulWidget {
const AccountStatementScreen({super.key});
@override
State<AccountStatementScreen> createState() => _AccountStatementScreen();
}
class _AccountStatementScreen extends State<AccountStatementScreen>{
DateTime? fromDate;
DateTime? toDate;
final _amountRangeController = TextEditingController(text: "");
final transactions = [
{"desc": "Transfer From ICICI Bank subsidy", "amount": "+₹133.98", "type": "Cr", "time": "21-02-2024 13:09:30"},
{"desc": "Mobile recharge", "amount": "-₹299.00", "type": "Dr", "time": "21-02-2024 13:09:30"},
{"desc": "NEFT received from Jaya Saha", "amount": "+₹987.80", "type": "Cr", "time": "21-02-2024 13:09:30"},
{"desc": "Transfer From ICICI Bank subsidy", "amount": "+₹100.00", "type": "Cr", "time": "21-02-2024 13:09:30"},
{"desc": "Transfer From ICICI Bank subsidy", "amount": "-₹100.00", "type": "Dr", "time": "21-02-2024 13:09:30"},
{"desc": "Transfer From ICICI Bank subsidy", "amount": "+₹100.00", "type": "Cr", "time": "21-02-2024 13:09:30"},
{"desc": "Transfer From ICICI Bank subsidy", "amount": "+₹100.00", "type": "Cr", "time": "21-02-2024 13:09:30"},
];
void _selectDate({required bool isFromDate}) async {
final DateTime initial = isFromDate ? fromDate ?? DateTime.now() : toDate ?? fromDate ?? DateTime.now();
final DateTime? picked = await showDatePicker(
context: context,
initialDate: initial,
firstDate: DateTime(2023),
lastDate: DateTime(2030),
);
if (picked != null) {
setState(() {
if (isFromDate) {
fromDate = picked;
if (toDate != null && toDate!.isBefore(fromDate!)) {
toDate = null; // reset invalid toDate
}
} else {
if (fromDate != null && picked.isBefore(fromDate!)) {
ScaffoldMessenger.of(context).showSnackBar(const SnackBar(
content: Text("To Date cannot be before From Date"),
));
} else {
toDate = picked;
}
}
});
}
}
String _formatDate(DateTime date) {
return "${date.day.toString().padLeft(2, '0')}-"
"${date.month.toString().padLeft(2, '0')}-"
"${date.year}";
}
@override
void dispose() {
_amountRangeController.dispose();
super.dispose();
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
leading: IconButton(icon: const Icon(Symbols.arrow_back_ios_new),
onPressed: () {
Navigator.pop(context);
},),
title: const Text('Account Statement', style: TextStyle(color: Colors.black,
fontWeight: FontWeight.w500),),
centerTitle: false,
actions: const [
Padding(
padding: EdgeInsets.only(right: 10.0),
child: CircleAvatar(
backgroundImage: AssetImage('assets/images/avatar.jpg'), // Replace with your image
radius: 20,
),
),
],
),
body: Padding(
padding: const EdgeInsets.all(12.0),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
const Text('Filters', style: TextStyle(fontSize: 17),),
const SizedBox(height: 15,),
Row(
children: [
Expanded(child: _buildFromDateSelector()),
const SizedBox(width: 10),
Expanded(child: _buildToDateSelector()),
],
),
const SizedBox(height: 20),
_buildFilterBox(""),
const SizedBox(height: 35),
Expanded(
child: ListView.builder(
itemCount: transactions.length,
itemBuilder: (context, index) {
final txn = transactions[index];
return _buildTransactionTile(txn);
},
),
),
],
),
),
);
}
Widget _buildFromDateSelector() {
return GestureDetector(
onTap: () => _selectDate(isFromDate: true),
child: Container(
padding: const EdgeInsets.symmetric(horizontal: 12, vertical: 14),
decoration: BoxDecoration(
border: Border.all(color: Colors.grey),
borderRadius: BorderRadius.circular(8),
),
child: Row(
children: [
Expanded(
child: Text(
fromDate != null ? _formatDate(fromDate!) : "From Date",
style: const TextStyle(fontSize: 16),
),
),
const Icon(Icons.arrow_drop_down),
],
),
),
);
}
Widget _buildToDateSelector() {
return GestureDetector(
onTap: () => _selectDate(isFromDate: false),
child: Container(
padding: const EdgeInsets.symmetric(horizontal: 12, vertical: 14),
decoration: BoxDecoration(
border: Border.all(color: Colors.grey),
borderRadius: BorderRadius.circular(8),
),
child: Row(
children: [
Expanded(
child: Text(
toDate != null ? _formatDate(toDate!) : "To Date",
style: const TextStyle(fontSize: 16),
),
),
const Icon(Icons.arrow_drop_down),
],
),
),
);
}
Widget _buildFilterBox(String text) {
return TextFormField(
controller: _amountRangeController,
decoration: const InputDecoration(
labelText: 'Amount Range',
// prefixIcon: Icon(Icons.person),
border: OutlineInputBorder(),
isDense: true,
filled: true,
fillColor: Colors.white,
enabledBorder: OutlineInputBorder(
borderSide: BorderSide(color: Colors.black),
),
focusedBorder: OutlineInputBorder(
borderSide: BorderSide(color: Colors.black, width: 2),
),
),
keyboardType: TextInputType.number,
textInputAction: TextInputAction.next,
validator: (value) {
if (value == null || value.isEmpty) {
return 'Please enter amount range';
}
return null;
},
);
}
Widget _buildTransactionTile(Map<String, String> txn) {
final isCredit = txn['type'] == "Cr";
final amountColor = isCredit ? Colors.green : Colors.red;
return Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(txn['time']!, style: const TextStyle(color: Colors.grey)),
const SizedBox(height: 4),
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Expanded(child: Text(txn['desc']!, style: const TextStyle(fontSize: 16))),
Text(
"${txn['amount']} ${txn['type']}",
style: TextStyle(color: amountColor, fontWeight: FontWeight.bold),
),
],
),
const SizedBox(height: 25),
],
);
}
}

View File

@ -1,4 +1,10 @@
import 'package:bloc/bloc.dart'; import 'package:bloc/bloc.dart';
import 'package:flutter/cupertino.dart';
import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart';
import 'package:local_auth/local_auth.dart';
import 'package:shared_preferences/shared_preferences.dart';
import '../../../app.dart';
import '../../../data/repositories/auth_repository.dart'; import '../../../data/repositories/auth_repository.dart';
import 'auth_state.dart'; import 'auth_state.dart';
@ -47,4 +53,60 @@ class AuthCubit extends Cubit<AuthState> {
emit(AuthError(e.toString())); emit(AuthError(e.toString()));
} }
} }
Future<void> checkFirstLaunch() async {
SharedPreferences prefs = await SharedPreferences.getInstance();
final isFirstLaunch = prefs.getBool('isFirstLaunch') ?? true;
if (isFirstLaunch) {
emit(ShowBiometricPermission());
} else {
// Continue to authentication logic (e.g., check token)
emit(AuthLoading()); // or Unauthenticated/Authenticated
}
}
Future<void> handleBiometricChoice(bool enabled) async {
SharedPreferences prefs = await SharedPreferences.getInstance();
await prefs.setBool('biometric_opt_in', enabled);
await prefs.setBool('isFirstLaunch', false);
// Then continue to auth logic or home
if (enabled) {
authenticateBiometric(); // implement biometric logic
} else {
emit(Unauthenticated());
}
}
Future<void> authenticateBiometric() async {
final LocalAuthentication auth = LocalAuthentication();
try {
final isAvailable = await auth.canCheckBiometrics;
final isDeviceSupported = await auth.isDeviceSupported();
if (isAvailable && isDeviceSupported) {
final authenticated = await auth.authenticate(
localizedReason: 'Touch the fingerprint sensor',
options: const AuthenticationOptions(
biometricOnly: true,
stickyAuth: true,
),
);
if (authenticated) {
// Continue to normal auth logic (e.g., auto login)
emit(AuthLoading());
await checkAuthStatus(); // Your existing method to verify token/session
} else {
emit(Unauthenticated());
}
} else {
emit(Unauthenticated());
}
} catch (e) {
emit(Unauthenticated());
}
}
} }

View File

@ -10,6 +10,8 @@ class AuthInitial extends AuthState {}
class AuthLoading extends AuthState {} class AuthLoading extends AuthState {}
class ShowBiometricPermission extends AuthState {}
class Authenticated extends AuthState { class Authenticated extends AuthState {
final User user; final User user;

View File

@ -5,7 +5,7 @@ class AuthCredentials {
AuthCredentials({required this.username, required this.password}); AuthCredentials({required this.username, required this.password});
Map<String, dynamic> toJson() => { Map<String, dynamic> toJson() => {
'username': username, 'customer_no': username,
'password': password, 'password': password,
}; };
} }

View File

@ -1,5 +1,8 @@
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart'; import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:flutter_svg/svg.dart';
import 'package:kmobile/features/auth/screens/mpin_screen.dart';
import '../../../app.dart';
import '../controllers/auth_cubit.dart'; import '../controllers/auth_cubit.dart';
import '../controllers/auth_state.dart'; import '../controllers/auth_state.dart';
import '../../dashboard/screens/dashboard_screen.dart'; import '../../dashboard/screens/dashboard_screen.dart';
@ -13,35 +16,39 @@ class LoginScreen extends StatefulWidget {
class LoginScreenState extends State<LoginScreen> { class LoginScreenState extends State<LoginScreen> {
final _formKey = GlobalKey<FormState>(); final _formKey = GlobalKey<FormState>();
final _usernameController = TextEditingController(); final _customerNumberController = TextEditingController();
final _passwordController = TextEditingController(); final _passwordController = TextEditingController();
bool _obscurePassword = true; bool _obscurePassword = true;
@override @override
void dispose() { void dispose() {
_usernameController.dispose(); _customerNumberController.dispose();
_passwordController.dispose(); _passwordController.dispose();
super.dispose(); super.dispose();
} }
void _submitForm() { void _submitForm() {
if (_formKey.currentState!.validate()) { // if (_formKey.currentState!.validate()) {
context.read<AuthCubit>().login( // context.read<AuthCubit>().login(
_usernameController.text.trim(), // _customerNumberController.text.trim(),
_passwordController.text, // _passwordController.text,
); // );
} // }
Navigator.of(context).pushReplacement(
MaterialPageRoute(builder: (context) => const MPinScreen()),
);
} }
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
return Scaffold( return Scaffold(
appBar: AppBar(title: const Text('Login')), // appBar: AppBar(title: const Text('Login')),
body: BlocConsumer<AuthCubit, AuthState>( body: BlocConsumer<AuthCubit, AuthState>(
listener: (context, state) { listener: (context, state) {
if (state is Authenticated) { if (state is Authenticated) {
Navigator.of(context).pushReplacement( Navigator.of(context).pushReplacement(
MaterialPageRoute(builder: (context) => const DashboardScreen()), MaterialPageRoute(builder: (context) => const NavigationScaffold()),
); );
} else if (state is AuthError) { } else if (state is AuthError) {
ScaffoldMessenger.of(context).showSnackBar( ScaffoldMessenger.of(context).showSnackBar(
@ -56,19 +63,35 @@ class LoginScreenState extends State<LoginScreen> {
key: _formKey, key: _formKey,
child: Column( child: Column(
mainAxisAlignment: MainAxisAlignment.center, mainAxisAlignment: MainAxisAlignment.center,
crossAxisAlignment: CrossAxisAlignment.stretch, // crossAxisAlignment: CrossAxisAlignment.stretch,
children: [ children: [
// Bank logo or app branding // Bank logo or app branding
const FlutterLogo(size: 80), SvgPicture.asset('assets/images/kccb_logo.svg', width: 100, height: 100,),
const SizedBox(height: 16),
// Title
const Text(
'KCCB',
style: TextStyle(fontSize: 28, fontWeight: FontWeight.bold, color: Colors.blue),
),
const SizedBox(height: 48), const SizedBox(height: 48),
TextFormField( TextFormField(
controller: _usernameController, controller: _customerNumberController,
decoration: const InputDecoration( decoration: const InputDecoration(
labelText: 'Username', labelText: 'Customer Number',
prefixIcon: Icon(Icons.person), // prefixIcon: Icon(Icons.person),
border: OutlineInputBorder(), border: OutlineInputBorder(),
isDense: true,
filled: true,
fillColor: Colors.white,
enabledBorder: OutlineInputBorder(
borderSide: BorderSide(color: Colors.black),
),
focusedBorder: OutlineInputBorder(
borderSide: BorderSide(color: Colors.black, width: 2),
),
), ),
keyboardType: TextInputType.number,
textInputAction: TextInputAction.next, textInputAction: TextInputAction.next,
validator: (value) { validator: (value) {
if (value == null || value.isEmpty) { if (value == null || value.isEmpty) {
@ -83,8 +106,17 @@ class LoginScreenState extends State<LoginScreen> {
controller: _passwordController, controller: _passwordController,
decoration: InputDecoration( decoration: InputDecoration(
labelText: 'Password', labelText: 'Password',
prefixIcon: const Icon(Icons.lock), // prefixIcon: const Icon(Icons.lock),
border: const OutlineInputBorder(), border: const OutlineInputBorder(),
isDense: true,
filled: true,
fillColor: Colors.white,
enabledBorder: const OutlineInputBorder(
borderSide: BorderSide(color: Colors.black),
),
focusedBorder: const OutlineInputBorder(
borderSide: BorderSide(color: Colors.black, width: 2),
),
suffixIcon: IconButton( suffixIcon: IconButton(
icon: Icon( icon: Icon(
_obscurePassword _obscurePassword
@ -98,6 +130,7 @@ class LoginScreenState extends State<LoginScreen> {
}, },
), ),
), ),
textInputAction: TextInputAction.done,
obscureText: _obscurePassword, obscureText: _obscurePassword,
validator: (value) { validator: (value) {
if (value == null || value.isEmpty) { if (value == null || value.isEmpty) {
@ -107,43 +140,72 @@ class LoginScreenState extends State<LoginScreen> {
}, },
), ),
Align( // Align(
alignment: Alignment.centerRight, // alignment: Alignment.centerRight,
child: TextButton( // child: TextButton(
onPressed: () { // onPressed: () {
// Navigate to forgot password screen // // Navigate to forgot password screen
}, // },
child: const Text('Forgot Password?'), // child: const Text('Forgot Password?'),
), // ),
), // ),
const SizedBox(height: 24), const SizedBox(height: 24),
ElevatedButton( SizedBox(
onPressed: state is AuthLoading ? null : _submitForm, width: 250,
style: ElevatedButton.styleFrom( child: ElevatedButton(
padding: const EdgeInsets.symmetric(vertical: 16), onPressed: state is AuthLoading ? null : _submitForm,
), style: ElevatedButton.styleFrom(
child: state is AuthLoading shape: const StadiumBorder(),
? const CircularProgressIndicator() padding: const EdgeInsets.symmetric(vertical: 16),
: const Text('LOGIN', style: TextStyle(fontSize: 16)), backgroundColor: Colors.white,
), foregroundColor: Colors.blueAccent,
side: const BorderSide(color: Colors.black, width: 1),
const SizedBox(height: 16), elevation: 0
// Registration option
Row(
mainAxisAlignment: MainAxisAlignment.center,
children: [
const Text("Don't have an account?"),
TextButton(
onPressed: () {
// Navigate to registration screen
},
child: const Text('Register'),
), ),
], child: state is AuthLoading
? const CircularProgressIndicator()
: const Text('Login', style: TextStyle(fontSize: 16),),
),
), ),
const SizedBox(height: 15),
// OR Divider
const Padding(
padding: EdgeInsets.symmetric(vertical: 16),
child: Row(
children: [
Expanded(child: Divider()),
Padding(
padding: EdgeInsets.symmetric(horizontal: 8),
child: Text('OR'),
),
Expanded(child: Divider()),
],
),
),
const SizedBox(height: 25),
// Register Button
SizedBox(
width: 250,
child: ElevatedButton(
onPressed: () {
// Handle register
},
style: OutlinedButton.styleFrom(
shape: const StadiumBorder(),
padding: const EdgeInsets.symmetric(vertical: 16),
backgroundColor: Colors.lightBlue[100],
foregroundColor: Colors.black
),
child: const Text('Register'),
),
),
], ],
), ),
), ),

View File

@ -0,0 +1,146 @@
import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:kmobile/features/auth/controllers/auth_cubit.dart';
import 'package:material_symbols_icons/material_symbols_icons.dart';
import '../../../app.dart';
class MPinScreen extends StatefulWidget {
const MPinScreen({super.key});
@override
MPinScreenState createState() => MPinScreenState();
}
class MPinScreenState extends State<MPinScreen> {
List<String> mPin = [];
void addDigit(String digit) {
if (mPin.length < 4) {
setState(() {
mPin.add(digit);
});
}
}
void deleteDigit() {
if (mPin.isNotEmpty) {
setState(() {
mPin.removeLast();
});
}
}
Widget buildMPinDots() {
return Row(
mainAxisAlignment: MainAxisAlignment.center,
children: List.generate(4, (index) {
return Container(
margin: const EdgeInsets.all(8),
width: 15,
height: 15,
decoration: BoxDecoration(
shape: BoxShape.circle,
color: index < mPin.length ? Colors.black : Colors.grey[400],
),
);
}),
);
}
Widget buildNumberPad() {
List<List<String>> keys = [
['1', '2', '3'],
['4', '5', '6'],
['7', '8', '9'],
['Enter', '0', '<']
];
return Column(
children: keys.map((row) {
return Row(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: row.map((key) {
return Padding(
padding: const EdgeInsets.all(8.0),
child: GestureDetector(
onTap: () {
if (key == '<') {
deleteDigit();
} else if (key == 'Enter') {
if (mPin.length == 4) {
Navigator.push(
context,
MaterialPageRoute(builder: (context) => const NavigationScaffold()),
);
} else {
ScaffoldMessenger.of(context).showSnackBar(
const SnackBar(content: Text("Please enter 4 digits")),
);
}
} else if (key.isNotEmpty) {
addDigit(key);
}
},
child: Container(
width: 70,
height: 70,
decoration: BoxDecoration(
shape: BoxShape.circle,
color: Colors.grey[200],
),
alignment: Alignment.center,
child: key == 'Enter' ? const Icon(Symbols.check) : Text(
key == '<' ? '' : key,
style: TextStyle(
fontSize: 20,
fontWeight: key == 'Enter' ?
FontWeight.normal : FontWeight.normal,
color: key == 'Enter' ? Colors.blue : Colors.black,
),
),
),
),
);
}).toList(),
);
}).toList(),
);
}
@override
Widget build(BuildContext context) {
final cubit = context.read<AuthCubit>();
return Scaffold(
body: SafeArea(
child: Column(
children: [
const Spacer(),
// Logo
const FlutterLogo(size: 100),
const SizedBox(height: 20),
const Text(
"Enter your mPIN",
style: TextStyle(fontSize: 20, fontWeight: FontWeight.w500),
),
const SizedBox(height: 20),
buildMPinDots(),
const Spacer(),
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
TextButton(onPressed: () {
cubit.authenticateBiometric();
}, child: const Text("Try another way")),
TextButton(onPressed: () {}, child: const Text("Register?")),
],
),
buildNumberPad(),
const Spacer(),
],
),
),
);
}
}

View File

@ -0,0 +1,299 @@
import 'package:flutter/material.dart';
import 'package:material_symbols_icons/material_symbols_icons.dart';
class AddBeneficiaryScreen extends StatefulWidget {
const AddBeneficiaryScreen({super.key});
@override
State<AddBeneficiaryScreen> createState() => _AddBeneficiaryScreen();
}
class _AddBeneficiaryScreen extends State<AddBeneficiaryScreen>{
final _formKey = GlobalKey<FormState>();
final TextEditingController accountNumberController = TextEditingController();
final TextEditingController nameController = TextEditingController();
final TextEditingController bankNameController = TextEditingController();
final TextEditingController branchNameController = TextEditingController();
final TextEditingController ifscController = TextEditingController();
final TextEditingController phoneController = TextEditingController();
String accountType = 'Savings';
void _submitForm() {
if (_formKey.currentState!.validate()) {
// Handle successful submission
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(
backgroundColor: Colors.grey[900],
behavior: SnackBarBehavior.floating,
margin: const EdgeInsets.all(12),
duration: const Duration(seconds: 5),
content: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
const Expanded(
child: Text(
'Beneficiary added successfully',
style: TextStyle(color: Colors.white),
),
),
TextButton(
onPressed: () {
// Navigate to Payment Screen or do something
},
style: TextButton.styleFrom(
foregroundColor: Colors.blue[200],
),
child: const Text('Pay Now'),
),
IconButton(
icon: const Icon(Icons.close, color: Colors.white),
onPressed: () {
ScaffoldMessenger.of(context).hideCurrentSnackBar();
},
),
],
),
),
);
}
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
leading: IconButton(icon: const Icon(Symbols.arrow_back_ios_new),
onPressed: () {
Navigator.pop(context);
},),
title: const Text('Add Beneficiary', style: TextStyle(color: Colors.black,
fontWeight: FontWeight.w500),),
centerTitle: false,
actions: const [
Padding(
padding: EdgeInsets.only(right: 10.0),
child: CircleAvatar(
backgroundImage: AssetImage('assets/images/avatar.jpg'), // Replace with your image
radius: 20,
),
),
],
),
body: SafeArea(
child: Form(
key: _formKey,
child: Column(
children: [
Expanded(
child: SingleChildScrollView(
physics: const AlwaysScrollableScrollPhysics(),
child: Padding(
padding: const EdgeInsets.all(10.0),
child: Column(
children: [
TextFormField(
controller: accountNumberController,
decoration: const InputDecoration(
labelText: 'Account Number',
// prefixIcon: Icon(Icons.person),
border: OutlineInputBorder(),
isDense: true,
filled: true,
fillColor: Colors.white,
enabledBorder: OutlineInputBorder(
borderSide: BorderSide(color: Colors.black),
),
focusedBorder: OutlineInputBorder(
borderSide: BorderSide(color: Colors.black, width: 2),
),
),
keyboardType: TextInputType.number,
textInputAction: TextInputAction.next,
validator: (value) {
if (value == null || value.length < 10) {
return "Enter a valid account number";
}
return null;
},
),
const SizedBox(height: 24),
TextFormField(
controller: nameController,
decoration: const InputDecoration(
labelText: 'Name',
// prefixIcon: Icon(Icons.person),
border: OutlineInputBorder(),
isDense: true,
filled: true,
fillColor: Colors.white,
enabledBorder: OutlineInputBorder(
borderSide: BorderSide(color: Colors.black),
),
focusedBorder: OutlineInputBorder(
borderSide: BorderSide(color: Colors.black, width: 2),
),
),
textInputAction: TextInputAction.next,
validator: (value) =>
value == null || value.isEmpty ? "Name is required" : null,
),
const SizedBox(height: 24),
TextFormField(
controller: bankNameController,
decoration: const InputDecoration(
labelText: 'Beneficiary Bank Name',
// prefixIcon: Icon(Icons.person),
border: OutlineInputBorder(),
isDense: true,
filled: true,
fillColor: Colors.white,
enabledBorder: OutlineInputBorder(
borderSide: BorderSide(color: Colors.black),
),
focusedBorder: OutlineInputBorder(
borderSide: BorderSide(color: Colors.black, width: 2),
),
),
textInputAction: TextInputAction.next,
validator: (value) =>
value == null || value.isEmpty ? "Bank name is required" : null,
),
const SizedBox(height: 24),
TextFormField(
controller: branchNameController,
decoration: const InputDecoration(
labelText: 'Branch Name',
// prefixIcon: Icon(Icons.person),
border: OutlineInputBorder(),
isDense: true,
filled: true,
fillColor: Colors.white,
enabledBorder: OutlineInputBorder(
borderSide: BorderSide(color: Colors.black),
),
focusedBorder: OutlineInputBorder(
borderSide: BorderSide(color: Colors.black, width: 2),
),
),
textInputAction: TextInputAction.next,
validator: (value) =>
value == null || value.isEmpty ? "Branch name is required" : null,
),
const SizedBox(height: 24),
Row(
children: [
Expanded(
flex: 2,
child: TextFormField(
controller: ifscController,
decoration: const InputDecoration(
labelText: 'IFSC Code',
// prefixIcon: Icon(Icons.person),
border: OutlineInputBorder(),
isDense: true,
filled: true,
fillColor: Colors.white,
enabledBorder: OutlineInputBorder(
borderSide: BorderSide(color: Colors.black),
),
focusedBorder: OutlineInputBorder(
borderSide: BorderSide(color: Colors.black, width: 2),
),
),
textInputAction: TextInputAction.next,
validator: (value) => value == null || value.length < 5
? "Enter a valid IFSC"
: null,
),
),
const SizedBox(width: 16),
Expanded(
flex: 2,
child: DropdownButtonFormField<String>(
value: accountType,
decoration: const InputDecoration(
labelText: 'Account Type',
// prefixIcon: Icon(Icons.person),
border: OutlineInputBorder(),
isDense: true,
filled: true,
fillColor: Colors.white,
enabledBorder: OutlineInputBorder(
borderSide: BorderSide(color: Colors.black),
),
focusedBorder: OutlineInputBorder(
borderSide: BorderSide(color: Colors.black, width: 2),
),
),
items: ['Savings', 'Current']
.map((type) => DropdownMenuItem(
value: type,
child: Text(type),
))
.toList(),
onChanged: (value) {
setState(() {
accountType = value!;
});
},
),
),
],
),
const SizedBox(height: 24),
TextFormField(
controller: phoneController,
keyboardType: TextInputType.phone,
decoration: const InputDecoration(
labelText: 'Phone',
prefixIcon: Icon(Icons.phone),
border: OutlineInputBorder(),
isDense: true,
filled: true,
fillColor: Colors.white,
enabledBorder: OutlineInputBorder(
borderSide: BorderSide(color: Colors.black),
),
focusedBorder: OutlineInputBorder(
borderSide: BorderSide(color: Colors.black, width: 2),
),
),
textInputAction: TextInputAction.done,
validator: (value) =>
value == null || value.length != 10 ? "Enter a valid phone" : null,
),
const SizedBox(height: 35),
],
),
),
),
),
Padding(
padding: const EdgeInsets.all(16.0),
child: SizedBox(
width: 250,
child: ElevatedButton(
onPressed: _submitForm,
style: ElevatedButton.styleFrom(
shape: const StadiumBorder(),
padding: const EdgeInsets.symmetric(vertical: 16),
backgroundColor: Colors.blue[900],
foregroundColor: Colors.white,
),
child: const Text("Add"),
),
),
),
],
),
),
),
);
}
}

View File

@ -0,0 +1,92 @@
import 'package:flutter/material.dart';
import 'package:kmobile/features/beneficiaries/screens/add_beneficiary_screen.dart';
import 'package:material_symbols_icons/material_symbols_icons.dart';
class ManageBeneficiariesScreen extends StatefulWidget {
const ManageBeneficiariesScreen({super.key});
@override
State<ManageBeneficiariesScreen> createState() => _ManageBeneficiariesScreen();
}
class _ManageBeneficiariesScreen extends State<ManageBeneficiariesScreen>{
final List<Map<String, String>> beneficiaries = [
{
'bank': 'State Bank Of India',
'name': 'Trina Bakshi',
},
{
'bank': 'State Bank Of India',
'name': 'Sheetal Rao',
},
{
'bank': 'Punjab National Bank',
'name': 'Manoj Kumar',
},
{
'bank': 'State Bank Of India',
'name': 'Rohit Mehra',
},
];
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
leading: IconButton(icon: const Icon(Symbols.arrow_back_ios_new),
onPressed: () {
Navigator.pop(context);
},),
title: const Text('Beneficiaries', style: TextStyle(color: Colors.black,
fontWeight: FontWeight.w500),),
centerTitle: false,
actions: const [
Padding(
padding: EdgeInsets.only(right: 10.0),
child: CircleAvatar(
backgroundImage: AssetImage('assets/images/avatar.jpg'), // Replace with your image
radius: 20,
),
),
],
),
body: Padding(
padding: const EdgeInsets.all(8.0),
child: ListView.builder(
itemCount: beneficiaries.length,
itemBuilder: (context, index) {
final beneficiary = beneficiaries[index];
return ListTile(
leading: const CircleAvatar(
backgroundColor: Colors.blue,
child: Text('A')),
title: Text(beneficiary['name']!),
subtitle: Text(beneficiary['bank']!),
trailing: IconButton(
icon: const Icon(Symbols.delete_forever, color: Colors.red),
onPressed: () {
// Delete action
},
),
);
},
),
),
floatingActionButton: Padding(
padding: const EdgeInsets.only(bottom: 8.0),
child: FloatingActionButton(
onPressed: () {
Navigator.push(context, MaterialPageRoute(
builder: (context) => const AddBeneficiaryScreen()));
},
backgroundColor: Colors.grey[300],
foregroundColor: Colors.blue[900],
elevation: 5,
child: const Icon(Icons.add),
),
),
);
}
}

View File

@ -0,0 +1,200 @@
import 'package:flutter/material.dart';
import 'package:intl/intl.dart';
import 'package:material_symbols_icons/material_symbols_icons.dart';
class BlockCardScreen extends StatefulWidget {
const BlockCardScreen({super.key});
@override
State<BlockCardScreen> createState() => _BlockCardScreen();
}
class _BlockCardScreen extends State<BlockCardScreen>{
final _formKey = GlobalKey<FormState>();
final _cardController = TextEditingController();
final _cvvController = TextEditingController();
final _expiryController = TextEditingController();
final _phoneController = TextEditingController();
Future<void> _pickExpiryDate() async {
final now = DateTime.now();
final selectedDate = await showDatePicker(
context: context,
initialDate: now,
firstDate: now,
lastDate: DateTime(now.year + 10),
);
if (selectedDate != null) {
_expiryController.text = DateFormat('dd/MM/yyyy').format(selectedDate);
}
}
void _blockCard() {
if (_formKey.currentState?.validate() ?? false) {
// Call your backend logic here
final snackBar = SnackBar(
content: const Text('Card has been blocked'),
action: SnackBarAction(
label: 'X',
onPressed: () {
// Just close the SnackBar
},
textColor: Colors.white,
),
backgroundColor: Colors.black,
behavior: SnackBarBehavior.floating,
);
ScaffoldMessenger.of(context).showSnackBar(snackBar);
}
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
leading: IconButton(icon: const Icon(Symbols.arrow_back_ios_new),
onPressed: () {
Navigator.pop(context);
},),
title: const Text('Block Card', style: TextStyle(color: Colors.black,
fontWeight: FontWeight.w500),),
centerTitle: false,
actions: const [
Padding(
padding: EdgeInsets.only(right: 10.0),
child: CircleAvatar(
backgroundImage: AssetImage('assets/images/avatar.jpg'), // Replace with your image
radius: 20,
),
),
],
),
body: Padding(
padding: const EdgeInsets.all(10.0),
child: Form(
key: _formKey,
child: ListView(
children: [
const SizedBox(height: 10),
TextFormField(
controller: _cardController,
decoration: const InputDecoration(
labelText: 'Card Number',
border: OutlineInputBorder(),
isDense: true,
filled: true,
fillColor: Colors.white,
enabledBorder: OutlineInputBorder(
borderSide: BorderSide(color: Colors.black),
),
focusedBorder: OutlineInputBorder(
borderSide: BorderSide(color: Colors.black, width: 2),
),
),
keyboardType: TextInputType.number,
textInputAction: TextInputAction.next,
validator: (value) =>
value != null && value.length == 16 ? null : 'Enter valid card number',
),
const SizedBox(height: 24),
Row(
children: [
Expanded(
child: TextFormField(
controller: _cvvController,
decoration: const InputDecoration(
labelText: 'CVV',
border: OutlineInputBorder(),
isDense: true,
filled: true,
fillColor: Colors.white,
enabledBorder: OutlineInputBorder(
borderSide: BorderSide(color: Colors.black),
),
focusedBorder: OutlineInputBorder(
borderSide: BorderSide(color: Colors.black, width: 2),
),
),
keyboardType: TextInputType.number,
textInputAction: TextInputAction.next,
obscureText: true,
validator: (value) =>
value != null && value.length == 3 ? null : 'CVV must be 3 digits',
),
),
const SizedBox(width: 16),
Expanded(
child: TextFormField(
controller: _expiryController,
readOnly: true,
onTap: _pickExpiryDate,
decoration: const InputDecoration(
labelText: 'Expiry Date',
suffixIcon: Icon(Icons.calendar_today),
border: OutlineInputBorder(),
isDense: true,
filled: true,
fillColor: Colors.white,
enabledBorder: OutlineInputBorder(
borderSide: BorderSide(color: Colors.black),
),
focusedBorder: OutlineInputBorder(
borderSide: BorderSide(color: Colors.black, width: 2),
),
),
validator: (value) =>
value != null && value.isNotEmpty ? null : 'Select expiry date',
),
),
],
),
const SizedBox(height: 24),
TextFormField(
controller: _phoneController,
decoration: const InputDecoration(
labelText: 'Phone',
prefixIcon: Icon(Icons.phone),
border: OutlineInputBorder(),
isDense: true,
filled: true,
fillColor: Colors.white,
enabledBorder: OutlineInputBorder(
borderSide: BorderSide(color: Colors.black),
),
focusedBorder: OutlineInputBorder(
borderSide: BorderSide(color: Colors.black, width: 2),
),
),
textInputAction: TextInputAction.done,
keyboardType: TextInputType.phone,
validator: (value) =>
value != null && value.length >= 10 ? null : 'Enter valid phone number',
),
const SizedBox(height: 45),
Align(
alignment: Alignment.center,
child: SizedBox(
width: 250,
child: ElevatedButton(
onPressed: _blockCard,
style: ElevatedButton.styleFrom(
shape: const StadiumBorder(),
padding: const EdgeInsets.symmetric(vertical: 16),
backgroundColor: Colors.blue[900],
foregroundColor: Colors.white,
),
child: const Text('Block'),
),
),
),
],
),
),
),
);
}
}

View File

@ -0,0 +1,95 @@
import 'package:flutter/material.dart';
import 'package:kmobile/features/card/screens/block_card_screen.dart';
import 'package:kmobile/features/card/screens/card_pin_change_details_screen.dart';
import 'package:material_symbols_icons/material_symbols_icons.dart';
class CardManagementScreen extends StatefulWidget {
const CardManagementScreen({super.key});
@override
State<CardManagementScreen> createState() => _CardManagementScreen();
}
class _CardManagementScreen extends State<CardManagementScreen>{
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
automaticallyImplyLeading: false,
title: const Text('Card Management', style: TextStyle(color: Colors.black,
fontWeight: FontWeight.w500),),
centerTitle: false,
actions: const [
Padding(
padding: EdgeInsets.only(right: 10.0),
child: CircleAvatar(
backgroundImage: AssetImage('assets/images/avatar.jpg'), // Replace with your image
radius: 20,
),
),
],
),
body: ListView(
children: [
CardManagementTile(
icon: Symbols.add,
label: 'Apply Debit Card',
onTap: () {
},
),
const Divider(height: 1,),
CardManagementTile(
icon: Symbols.remove_moderator,
label: 'Block / Unblock Card',
onTap: () {
Navigator.push(context, MaterialPageRoute(
builder: (context) => const BlockCardScreen()));
},
),
const Divider(height: 1,),
CardManagementTile(
icon: Symbols.password_2,
label: 'Change Card PIN',
onTap: () {
Navigator.push(context, MaterialPageRoute(
builder: (context) => const CardPinChangeDetailsScreen()));
},
),
const Divider(height: 1,),
],
),
);
}
}
class CardManagementTile extends StatelessWidget {
final IconData icon;
final String label;
final VoidCallback onTap;
const CardManagementTile({
super.key,
required this.icon,
required this.label,
required this.onTap,
});
@override
Widget build(BuildContext context) {
return ListTile(
leading: Icon(icon),
title: Text(label),
trailing: const Icon(Symbols.arrow_right, size: 20),
onTap: onTap,
);
}
}

View File

@ -0,0 +1,189 @@
import 'package:flutter/material.dart';
import 'package:intl/intl.dart';
import 'package:kmobile/features/card/screens/card_pin_set_screen.dart';
import 'package:material_symbols_icons/material_symbols_icons.dart';
class CardPinChangeDetailsScreen extends StatefulWidget {
const CardPinChangeDetailsScreen({super.key});
@override
State<CardPinChangeDetailsScreen> createState() => _CardPinChangeDetailsScreen();
}
class _CardPinChangeDetailsScreen extends State<CardPinChangeDetailsScreen>{
final _formKey = GlobalKey<FormState>();
final _cardController = TextEditingController();
final _cvvController = TextEditingController();
final _expiryController = TextEditingController();
final _phoneController = TextEditingController();
Future<void> _pickExpiryDate() async {
final now = DateTime.now();
final selectedDate = await showDatePicker(
context: context,
initialDate: now,
firstDate: now,
lastDate: DateTime(now.year + 10),
);
if (selectedDate != null) {
_expiryController.text = DateFormat('dd/MM/yyyy').format(selectedDate);
}
}
void _nextButton() {
if (_formKey.currentState?.validate() ?? false) {
// Call your backend logic here
Navigator.of(context).pushReplacement(
MaterialPageRoute(builder: (context) => const CardPinSetScreen()),
);
}
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
leading: IconButton(icon: const Icon(Symbols.arrow_back_ios_new),
onPressed: () {
Navigator.pop(context);
},),
title: const Text('Card Details', style: TextStyle(color: Colors.black,
fontWeight: FontWeight.w500),),
centerTitle: false,
actions: const [
Padding(
padding: EdgeInsets.only(right: 10.0),
child: CircleAvatar(
backgroundImage: AssetImage('assets/images/avatar.jpg'), // Replace with your image
radius: 20,
),
),
],
),
body: Padding(
padding: const EdgeInsets.all(10.0),
child: Form(
key: _formKey,
child: ListView(
children: [
const SizedBox(height: 10),
TextFormField(
controller: _cardController,
decoration: const InputDecoration(
labelText: 'Card Number',
border: OutlineInputBorder(),
isDense: true,
filled: true,
fillColor: Colors.white,
enabledBorder: OutlineInputBorder(
borderSide: BorderSide(color: Colors.black),
),
focusedBorder: OutlineInputBorder(
borderSide: BorderSide(color: Colors.black, width: 2),
),
),
keyboardType: TextInputType.number,
textInputAction: TextInputAction.next,
validator: (value) =>
value != null && value.length == 16 ? null : 'Enter valid card number',
),
const SizedBox(height: 24),
Row(
children: [
Expanded(
child: TextFormField(
controller: _cvvController,
decoration: const InputDecoration(
labelText: 'CVV',
border: OutlineInputBorder(),
isDense: true,
filled: true,
fillColor: Colors.white,
enabledBorder: OutlineInputBorder(
borderSide: BorderSide(color: Colors.black),
),
focusedBorder: OutlineInputBorder(
borderSide: BorderSide(color: Colors.black, width: 2),
),
),
keyboardType: TextInputType.number,
textInputAction: TextInputAction.next,
obscureText: true,
validator: (value) =>
value != null && value.length == 3 ? null : 'CVV must be 3 digits',
),
),
const SizedBox(width: 16),
Expanded(
child: TextFormField(
controller: _expiryController,
readOnly: true,
onTap: _pickExpiryDate,
decoration: const InputDecoration(
labelText: 'Expiry Date',
suffixIcon: Icon(Icons.calendar_today),
border: OutlineInputBorder(),
isDense: true,
filled: true,
fillColor: Colors.white,
enabledBorder: OutlineInputBorder(
borderSide: BorderSide(color: Colors.black),
),
focusedBorder: OutlineInputBorder(
borderSide: BorderSide(color: Colors.black, width: 2),
),
),
validator: (value) =>
value != null && value.isNotEmpty ? null : 'Select expiry date',
),
),
],
),
const SizedBox(height: 24),
TextFormField(
controller: _phoneController,
decoration: const InputDecoration(
labelText: 'Phone',
prefixIcon: Icon(Icons.phone),
border: OutlineInputBorder(),
isDense: true,
filled: true,
fillColor: Colors.white,
enabledBorder: OutlineInputBorder(
borderSide: BorderSide(color: Colors.black),
),
focusedBorder: OutlineInputBorder(
borderSide: BorderSide(color: Colors.black, width: 2),
),
),
textInputAction: TextInputAction.done,
keyboardType: TextInputType.phone,
validator: (value) =>
value != null && value.length >= 10 ? null : 'Enter valid phone number',
),
const SizedBox(height: 45),
Align(
alignment: Alignment.center,
child: SizedBox(
width: 250,
child: ElevatedButton(
onPressed: _nextButton,
style: ElevatedButton.styleFrom(
shape: const StadiumBorder(),
padding: const EdgeInsets.symmetric(vertical: 16),
backgroundColor: Colors.blue[900],
foregroundColor: Colors.white,
),
child: const Text('Next'),
),
),
),
],
),
),
),
);
}
}

View File

@ -0,0 +1,148 @@
import 'package:flutter/material.dart';
import 'package:material_symbols_icons/material_symbols_icons.dart';
class CardPinSetScreen extends StatefulWidget {
const CardPinSetScreen({super.key});
@override
State<CardPinSetScreen> createState() => _CardPinSetScreen();
}
class _CardPinSetScreen extends State<CardPinSetScreen>{
final _formKey = GlobalKey<FormState>();
final _pinController = TextEditingController();
final _confirmPinController = TextEditingController();
void _submit() {
if (_formKey.currentState!.validate()) {
// Handle PIN submission logic here
final snackBar = SnackBar(
content: const Text('PIN set successfully'),
action: SnackBarAction(
label: 'X',
onPressed: () {
// Just close the SnackBar
},
textColor: Colors.white,
),
backgroundColor: Colors.black,
behavior: SnackBarBehavior.floating,
);
ScaffoldMessenger.of(context).showSnackBar(snackBar);
}
}
@override
void dispose() {
_pinController.dispose();
_confirmPinController.dispose();
super.dispose();
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
leading: IconButton(icon: const Icon(Symbols.arrow_back_ios_new),
onPressed: () {
Navigator.pop(context);
},),
title: const Text('Card PIN', style: TextStyle(color: Colors.black,
fontWeight: FontWeight.w500),),
centerTitle: false,
actions: const [
Padding(
padding: EdgeInsets.only(right: 10.0),
child: CircleAvatar(
backgroundImage: AssetImage('assets/images/avatar.jpg'), // Replace with your image
radius: 20,
),
),
],
),
body: Padding(
padding: const EdgeInsets.all(16.0),
child: Form(
key: _formKey,
child: Column(
children: [
TextFormField(
controller: _pinController,
obscureText: true,
decoration: const InputDecoration(
labelText: 'Enter new PIN',
border: OutlineInputBorder(),
isDense: true,
filled: true,
fillColor: Colors.white,
enabledBorder: OutlineInputBorder(
borderSide: BorderSide(color: Colors.black),
),
focusedBorder: OutlineInputBorder(
borderSide: BorderSide(color: Colors.black, width: 2),
),
),
keyboardType: TextInputType.number,
textInputAction: TextInputAction.next,
validator: (value) {
if (value == null || value.isEmpty) {
return 'Please enter new PIN';
}
if (value.length < 4) {
return 'PIN must be at least 4 digits';
}
return null;
},
),
const SizedBox(height: 24),
TextFormField(
controller: _confirmPinController,
obscureText: true,
decoration: const InputDecoration(
labelText: 'Enter Again',
border: OutlineInputBorder(),
isDense: true,
filled: true,
fillColor: Colors.white,
enabledBorder: OutlineInputBorder(
borderSide: BorderSide(color: Colors.black),
),
focusedBorder: OutlineInputBorder(
borderSide: BorderSide(color: Colors.black, width: 2),
),
),
keyboardType: TextInputType.number,
textInputAction: TextInputAction.done,
validator: (value) {
if (value != _pinController.text) {
return 'PINs do not match';
}
return null;
},
),
const SizedBox(height: 45),
Align(
alignment: Alignment.center,
child: SizedBox(
width: 250,
child: ElevatedButton(
onPressed: _submit,
style: ElevatedButton.styleFrom(
shape: const StadiumBorder(),
padding: const EdgeInsets.symmetric(vertical: 16),
backgroundColor: Colors.blue[900],
foregroundColor: Colors.white,
),
child: const Text('Submit'),
),
),
),
],
),
),
),
);
}
}

View File

@ -0,0 +1,124 @@
import 'package:flutter/material.dart';
import 'package:kmobile/features/enquiry/screens/enquiry_screen.dart';
import 'package:material_symbols_icons/material_symbols_icons.dart';
class ChequeManagementScreen extends StatefulWidget {
const ChequeManagementScreen({super.key});
@override
State<ChequeManagementScreen> createState() => _ChequeManagementScreen();
}
class _ChequeManagementScreen extends State<ChequeManagementScreen>{
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
leading: IconButton(icon: const Icon(Symbols.arrow_back_ios_new),
onPressed: () {
Navigator.pop(context);
},),
title: const Text('Cheque Management', style: TextStyle(color: Colors.black,
fontWeight: FontWeight.w500),),
centerTitle: false,
actions: const [
Padding(
padding: EdgeInsets.only(right: 10.0),
child: CircleAvatar(
backgroundImage: AssetImage('assets/images/avatar.jpg'), // Replace with your image
radius: 20,
),
),
],
),
body: ListView(
children: [
const SizedBox(height: 15),
ChequeManagementTile(
icon: Symbols.add,
label: 'Request Checkbook',
onTap: () {
},
),
const Divider(height: 1,),
ChequeManagementTile(
icon: Symbols.data_alert,
label: 'Enquiry',
onTap: () {
Navigator.push(context, MaterialPageRoute(
builder: (context) => const EnquiryScreen()));
},
),
const Divider(height: 1,),
ChequeManagementTile(
icon: Symbols.approval_delegation,
label: 'Cheque Deposit',
onTap: () {
},
),
const Divider(height: 1,),
ChequeManagementTile(
icon: Symbols.front_hand,
label: 'Stop Cheque',
onTap: () {
},
),
const Divider(height: 1,),
ChequeManagementTile(
icon: Symbols.cancel_presentation,
label: 'Revoke Stop',
onTap: () {
},
),
const Divider(height: 1,),
ChequeManagementTile(
icon: Symbols.payments,
label: 'Positive Pay',
onTap: () {
},
),
const Divider(height: 1,),
],
),
);
}
}
class ChequeManagementTile extends StatelessWidget {
final IconData icon;
final String label;
final VoidCallback onTap;
const ChequeManagementTile({
super.key,
required this.icon,
required this.label,
required this.onTap,
});
@override
Widget build(BuildContext context) {
return ListTile(
leading: Icon(icon),
title: Text(label),
trailing: const Icon(Symbols.arrow_right, size: 20),
onTap: onTap,
);
}
}

View File

@ -0,0 +1,104 @@
import 'package:flutter/material.dart';
import 'package:material_symbols_icons/material_symbols_icons.dart';
class CustomerInfoScreen extends StatefulWidget {
const CustomerInfoScreen({super.key});
@override
State<CustomerInfoScreen> createState() => _CustomerInfoScreen();
}
class _CustomerInfoScreen extends State<CustomerInfoScreen>{
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
leading: IconButton(icon: const Icon(Symbols.arrow_back_ios_new),
onPressed: () {
Navigator.pop(context);
},),
title: const Text('kMobile', style: TextStyle(color: Colors.black,
fontWeight: FontWeight.w500),),
actions: const [
Padding(
padding: EdgeInsets.only(right: 10.0),
child: CircleAvatar(
backgroundImage: AssetImage('assets/images/avatar.jpg'), // Replace with your image
radius: 20,
),
),
],
),
body: const SingleChildScrollView(
physics: AlwaysScrollableScrollPhysics(),
child: Padding(
padding: EdgeInsets.all(16.0),
child: SafeArea(
child: Center(
child: Column(
children: [
SizedBox(height: 30),
CircleAvatar(
backgroundImage: AssetImage('assets/images/avatar.jpg'), // Replace with your image
radius: 50,
),
Padding(
padding: EdgeInsets.only(top: 10.0),
child: Text('Trina Bakshi', style: TextStyle(fontSize: 20,
color: Colors.black, fontWeight: FontWeight.w500),),
),
Text('CIF: 2553677487774', style: TextStyle(fontSize: 16, color: Colors.grey),),
SizedBox(height: 30,),
InfoField(label: 'Number of Active Accounts', value: '3'),
InfoField(label: 'Mobile Number', value: '987XXXXX78'),
InfoField(label: 'Date of Birth', value: '12-07-1984'),
InfoField(label: 'Branch', value: 'Krishnapur'),
InfoField(label: 'Aadhar Number', value: '7665 XXXX 1276'),
InfoField(label: 'PAN Number', value: '700127638009871'),
],
),
),
),
)),
);
}
}
class InfoField extends StatelessWidget {
final String label;
final String value;
const InfoField({Key? key, required this.label, required this.value}) : super(key: key);
@override
Widget build(BuildContext context) {
return Container(
width: double.infinity,
margin: const EdgeInsets.symmetric(vertical: 8),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
label,
style: const TextStyle(
fontSize: 15,
fontWeight: FontWeight.w500,
color: Colors.black87,
),
),
const SizedBox(height: 3),
Text(
value,
style: const TextStyle(
fontSize: 16,
color: Colors.black,
),
),
],
),
);
}
}

View File

@ -1,11 +1,14 @@
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart'; import 'package:kmobile/features/accounts/screens/account_info_screen.dart';
import '../../auth/controllers/auth_cubit.dart'; import 'package:kmobile/features/accounts/screens/account_statement_screen.dart';
import '../../auth/controllers/auth_state.dart'; import 'package:kmobile/features/cheque/screens/cheque_management_screen.dart';
import '../widgets/account_card.dart'; import 'package:kmobile/features/customer_info/screens/customer_info_screen.dart';
import '../widgets/transaction_list_item.dart'; import 'package:kmobile/features/beneficiaries/screens/manage_beneficiaries_screen.dart';
import '../../accounts/models/account.dart'; import 'package:kmobile/features/enquiry/screens/enquiry_screen.dart';
import '../../transactions/models/transaction.dart'; import 'package:kmobile/features/fund_transfer/screens/fund_transfer_beneficiary_screen.dart';
import 'package:kmobile/features/quick_pay/screens/quick_pay_screen.dart';
import 'package:kmobile/src/preferences/preference.dart';
import 'package:material_symbols_icons/material_symbols_icons.dart';
class DashboardScreen extends StatefulWidget { class DashboardScreen extends StatefulWidget {
const DashboardScreen({super.key}); const DashboardScreen({super.key});
@ -15,331 +18,173 @@ class DashboardScreen extends StatefulWidget {
} }
class _DashboardScreenState extends State<DashboardScreen> { class _DashboardScreenState extends State<DashboardScreen> {
// Mock data for demonstration // Mock data for transactions
final List<Account> _accounts = [ final List<Map<String, String>> transactions = [
Account( {'name': 'Raj Kumar', 'amount': '₹1,000', 'date': '09 March, 2025 16:04', 'type': 'in'},
id: '1', {'name': 'Sunita Joshi', 'amount': '₹1,45,000', 'date': '07 March, 2025 16:04', 'type': 'out'},
accountNumber: '**** 4589', {'name': 'Manoj Singh', 'amount': '₹2,400', 'date': '07 March, 2025 16:04', 'type': 'in'},
accountType: 'Savings', {'name': 'Raj Kumar', 'amount': '₹11,500', 'date': '09 March, 2025 16:04', 'type': 'in'},
balance: 12450.75, {'name': 'Manoj Singh', 'amount': '₹1,000', 'date': '', 'type': 'in'},
currency: 'USD',
),
Account(
id: '2',
accountNumber: '**** 7823',
accountType: 'Checking',
balance: 3840.50,
currency: 'USD',
),
];
final List<Transaction> _recentTransactions = [
Transaction(
id: 't1',
description: 'Coffee Shop',
amount: -4.50,
date: DateTime.now().subtract(const Duration(hours: 3)),
category: 'Food & Drink',
),
Transaction(
id: 't2',
description: 'Salary Deposit',
amount: 2500.00,
date: DateTime.now().subtract(const Duration(days: 2)),
category: 'Income',
),
Transaction(
id: 't3',
description: 'Electric Bill',
amount: -85.75,
date: DateTime.now().subtract(const Duration(days: 3)),
category: 'Utilities',
),
Transaction(
id: 't4',
description: 'Amazon Purchase',
amount: -32.50,
date: DateTime.now().subtract(const Duration(days: 5)),
category: 'Shopping',
),
]; ];
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
return Scaffold( return Scaffold(
backgroundColor: const Color(0xfff5f9fc),
appBar: AppBar( appBar: AppBar(
title: const Text('Dashboard'), backgroundColor: const Color(0xfff5f9fc),
automaticallyImplyLeading: false,
title: const Text('kMobile', style: TextStyle(color: Colors.blueAccent,
fontWeight: FontWeight.w500),),
actions: [ actions: [
IconButton( // IconButton(
icon: const Icon(Icons.notifications_outlined), // icon: const Icon(Icons.notifications_outlined),
onPressed: () { // onPressed: () {
// Navigate to notifications // // Navigate to notifications
}, // },
), // ),
IconButton( Padding(
icon: const Icon(Icons.logout), padding: const EdgeInsets.only(right: 10.0),
onPressed: () { child: InkWell(
_showLogoutConfirmation(context); borderRadius: BorderRadius.circular(20),
}, onTap: (){
Navigator.push(context, MaterialPageRoute(
builder: (context) => const Preference()));
},
child: const CircleAvatar(
backgroundImage: AssetImage('assets/images/avatar.jpg'), // Replace with your image
radius: 20,
),
),
), ),
], ],
), ),
body: RefreshIndicator( body: SingleChildScrollView(
onRefresh: () async { physics: const AlwaysScrollableScrollPhysics(),
// Implement refresh logic to fetch updated data child: Padding(
await Future.delayed(const Duration(seconds: 1)); padding: const EdgeInsets.all(16.0),
}, child: Column(
child: SingleChildScrollView( crossAxisAlignment: CrossAxisAlignment.start,
physics: const AlwaysScrollableScrollPhysics(), children: [
child: Padding( const SizedBox(height: 16),
padding: const EdgeInsets.all(16.0),
child: Column( // Account Info Card
crossAxisAlignment: CrossAxisAlignment.start, Container(
children: [ padding: const EdgeInsets.all(16),
// Greeting section decoration: BoxDecoration(
BlocBuilder<AuthCubit, AuthState>( color: Colors.blue[700],
builder: (context, state) { borderRadius: BorderRadius.circular(16),
if (state is Authenticated) {
return Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
'Hello, ${state.user.username}',
style: Theme.of(context).textTheme.headlineSmall,
),
const SizedBox(height: 4),
Text(
'Welcome back to your banking app',
style: Theme.of(context).textTheme.bodyMedium?.copyWith(
color: Colors.grey[600],
),
),
],
);
}
return Container();
},
), ),
child: const Column(
const SizedBox(height: 24), crossAxisAlignment: CrossAxisAlignment.start,
// Account cards section
const Text(
'Your Accounts',
style: TextStyle(
fontSize: 18,
fontWeight: FontWeight.bold,
),
),
const SizedBox(height: 12),
SizedBox(
height: 180,
child: ListView.builder(
scrollDirection: Axis.horizontal,
itemCount: _accounts.length + 1, // +1 for the "Add Account" card
itemBuilder: (context, index) {
if (index < _accounts.length) {
return Padding(
padding: const EdgeInsets.only(right: 16.0),
child: AccountCard(account: _accounts[index]),
);
} else {
// "Add Account" card
return Container(
width: 300,
margin: const EdgeInsets.only(right: 16.0),
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(12),
border: Border.all(color: Colors.grey[300]!),
),
child: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Icon(
Icons.add_circle_outline,
size: 40,
color: Theme.of(context).primaryColor,
),
const SizedBox(height: 8),
Text(
'Add New Account',
style: TextStyle(
color: Theme.of(context).primaryColor,
fontWeight: FontWeight.bold,
),
),
],
),
),
);
}
},
),
),
const SizedBox(height: 32),
// Quick Actions section
const Text(
'Quick Actions',
style: TextStyle(
fontSize: 18,
fontWeight: FontWeight.bold,
),
),
const SizedBox(height: 16),
Row(
mainAxisAlignment: MainAxisAlignment.spaceAround,
children: [ children: [
_buildQuickActionButton( Row(
icon: Icons.swap_horiz, children: [
label: 'Transfer', Text("Account Number: ", style:
onTap: () { TextStyle(color: Colors.white, fontSize: 12)),
// Navigate to transfer screen Text("03000156789462302", style:
}, TextStyle(color: Colors.white, fontSize: 14)),
Padding(
padding: EdgeInsets.only(left: 5.0),
child: Icon(Symbols.keyboard_arrow_down, color: Colors.white),
),
],
), ),
_buildQuickActionButton( SizedBox(height: 15),
icon: Icons.payment, Row(
label: 'Pay Bills', mainAxisAlignment: MainAxisAlignment.spaceBetween,
onTap: () { children: [
// Navigate to bill payment screen Text("₹ *****", style: TextStyle(color: Colors.white,
}, fontSize: 24, fontWeight: FontWeight.w700)),
), Icon(Symbols.visibility_lock, color: Colors.white),
_buildQuickActionButton( ],
icon: Icons.qr_code_scanner,
label: 'Scan & Pay',
onTap: () {
// Navigate to QR code scanner
},
),
_buildQuickActionButton(
icon: Icons.more_horiz,
label: 'More',
onTap: () {
// Show more options
},
), ),
SizedBox(height: 20),
], ],
), ),
),
const SizedBox(height: 32), const SizedBox(height: 18),
const Text('Quick Links', style: TextStyle(fontSize: 15),),
// Recent Transactions section const SizedBox(height: 16),
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween, // Quick Links
children: [ GridView.count(
const Text( crossAxisCount: 4,
'Recent Transactions', shrinkWrap: true,
style: TextStyle( physics: const NeverScrollableScrollPhysics(),
fontSize: 18, children: [
fontWeight: FontWeight.bold, _buildQuickLink(Symbols.id_card, "Customer \n Info", () {
), Navigator.push(context, MaterialPageRoute(
), builder: (context) => const CustomerInfoScreen()));
TextButton( }),
onPressed: () { _buildQuickLink(Symbols.currency_rupee, "Quick \n Pay",
// Navigate to all transactions () {
}, Navigator.push(context, MaterialPageRoute(
child: const Text('See All'), builder: (context) => const QuickPayScreen()));
), }),
], _buildQuickLink(Symbols.send_money, "Fund \n Transfer",
), () {
const SizedBox(height: 8), Navigator.push(context, MaterialPageRoute(
ListView.builder( builder: (context) => const FundTransferBeneficiaryScreen()));
physics: const NeverScrollableScrollPhysics(), }),
shrinkWrap: true, _buildQuickLink(Symbols.server_person, "Account \n Info",
itemCount: _recentTransactions.length, (){
itemBuilder: (context, index) { Navigator.push(context, MaterialPageRoute(
return TransactionListItem( builder: (context) => const AccountInfoScreen()));
transaction: _recentTransactions[index], }),
); _buildQuickLink(Symbols.receipt_long, "Account \n History",
}, () {
), Navigator.push(context, MaterialPageRoute(
], builder: (context) => const AccountStatementScreen()));
), }),
_buildQuickLink(Symbols.checkbook, "Handle \n Cheque",
() {
Navigator.push(context, MaterialPageRoute(
builder: (context) => const ChequeManagementScreen()));
}),
_buildQuickLink(Icons.group, "Manage \n Beneficiary",
() {
Navigator.push(context, MaterialPageRoute(
builder: (context) => const ManageBeneficiariesScreen()));
}),
_buildQuickLink(Symbols.support_agent, "Contact \n Us",
() {
Navigator.push(context, MaterialPageRoute(
builder: (context) => const EnquiryScreen()));
}),
],
),
const SizedBox(height: 10),
// Recent Transactions
const Align(
alignment: Alignment.centerLeft,
child: Text("Recent Transactions", style: TextStyle(fontSize: 16, fontWeight: FontWeight.bold)),
),
...transactions.map((tx) => ListTile(
leading: Icon(tx['type'] == 'in' ? Symbols.call_received : Symbols.call_made, color: tx['type'] == 'in' ? Colors.green : Colors.red),
title: Text(tx['name']!),
subtitle: Text(tx['date']!),
trailing: Text(tx['amount']!),
)),
],
), ),
), ),
), ),
bottomNavigationBar: BottomNavigationBar(
currentIndex: 0,
type: BottomNavigationBarType.fixed,
items: const [
BottomNavigationBarItem(
icon: Icon(Icons.dashboard),
label: 'Home',
),
BottomNavigationBarItem(
icon: Icon(Icons.account_balance_wallet),
label: 'Accounts',
),
BottomNavigationBarItem(
icon: Icon(Icons.show_chart),
label: 'Insights',
),
BottomNavigationBarItem(
icon: Icon(Icons.person),
label: 'Profile',
),
],
onTap: (index) {
// Handle navigation
},
),
); );
} }
Widget _buildQuickActionButton({ Widget _buildQuickLink(IconData icon, String label, VoidCallback onTap) {
required IconData icon, return InkWell(
required String label,
required VoidCallback onTap,
}) {
return GestureDetector(
onTap: onTap, onTap: onTap,
child: Column( child: Column(
mainAxisSize: MainAxisSize.min,
children: [ children: [
Container( Icon(icon, size: 30, color: Colors.blue[700]),
padding: const EdgeInsets.all(12), const SizedBox(height: 4),
decoration: BoxDecoration( Text(label, textAlign: TextAlign.center, style: const TextStyle(fontSize: 12)),
color: Theme.of(context).primaryColor.withAlpha((0.1 * 255).toInt()),
borderRadius: BorderRadius.circular(12),
),
child: Icon(
icon,
color: Theme.of(context).primaryColor,
size: 28,
),
),
const SizedBox(height: 8),
Text(
label,
style: const TextStyle(
fontSize: 12,
fontWeight: FontWeight.w500,
),
),
],
),
);
}
void _showLogoutConfirmation(BuildContext context) {
showDialog(
context: context,
builder: (context) => AlertDialog(
title: const Text('Logout'),
content: const Text('Are you sure you want to logout?'),
actions: [
TextButton(
onPressed: () => Navigator.pop(context),
child: const Text('CANCEL'),
),
TextButton(
onPressed: () {
Navigator.pop(context);
context.read<AuthCubit>().logout();
},
child: const Text('LOGOUT'),
),
], ],
), ),
); );

View File

@ -0,0 +1,93 @@
import 'package:flutter/material.dart';
import 'package:material_symbols_icons/material_symbols_icons.dart';
import 'package:url_launcher/url_launcher.dart';
class EnquiryScreen extends StatefulWidget {
const EnquiryScreen({super.key});
@override
State<EnquiryScreen> createState() => _EnquiryScreen();
}
class _EnquiryScreen extends State<EnquiryScreen>{
Future<void> _launchEmail() async {
final Uri emailUri = Uri(
scheme: 'mailto',
path: 'helpdesk@kccb.in',
);
if (await canLaunchUrl(emailUri)) {
await launchUrl(emailUri);
} else {
debugPrint('Could not launch email client');
}
}
Future<void> _launchPhone() async {
final Uri phoneUri = Uri(scheme: 'tel', path: '0651-312861');
if (await canLaunchUrl(phoneUri)) {
await launchUrl(phoneUri);
} else {
debugPrint('Could not launch phone dialer');
}
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
leading: IconButton(icon: const Icon(Symbols.arrow_back_ios_new),
onPressed: () {
Navigator.pop(context);
},),
title: const Text('Enquiry', style: TextStyle(color: Colors.black,
fontWeight: FontWeight.w500),),
centerTitle: false,
actions: const [
Padding(
padding: EdgeInsets.only(right: 10.0),
child: CircleAvatar(
backgroundImage: AssetImage('assets/images/avatar.jpg'), // Replace with your image
radius: 20,
),
),
],
),
body: Padding(
padding: const EdgeInsets.all(16.0),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
const Text("Mail us at", style: TextStyle(color: Colors.grey)),
const SizedBox(height: 4),
GestureDetector(
onTap: _launchEmail,
child: const Text(
"helpdesk@kccb.in",
style: TextStyle(color: Colors.blue),
),
),
const SizedBox(height: 20),
const Text("Call us at", style: TextStyle(color: Colors.grey)),
const SizedBox(height: 4),
GestureDetector(
onTap: _launchPhone,
child: const Text(
"0651-312861",
style: TextStyle(color: Colors.blue),
),
),
const SizedBox(height: 20),
const Text("Write to us", style: TextStyle(color: Colors.grey)),
const SizedBox(height: 4),
const Text(
"101 Street, Some Street, Some Address\nSome Address",
style: TextStyle(color: Colors.blue),
),
],
),
),
);
}
}

View File

@ -0,0 +1,96 @@
import 'package:flutter/material.dart';
import 'package:kmobile/features/beneficiaries/screens/add_beneficiary_screen.dart';
import 'package:kmobile/features/fund_transfer/screens/fund_transfer_screen.dart';
import 'package:material_symbols_icons/material_symbols_icons.dart';
class FundTransferBeneficiaryScreen extends StatefulWidget {
const FundTransferBeneficiaryScreen({super.key});
@override
State<FundTransferBeneficiaryScreen> createState() => _FundTransferBeneficiaryScreen();
}
class _FundTransferBeneficiaryScreen extends State<FundTransferBeneficiaryScreen>{
final List<Map<String, String>> beneficiaries = [
{
'bank': 'State Bank Of India',
'name': 'Trina Bakshi',
},
{
'bank': 'State Bank Of India',
'name': 'Sheetal Rao',
},
{
'bank': 'Punjab National Bank',
'name': 'Manoj Kumar',
},
{
'bank': 'State Bank Of India',
'name': 'Rohit Mehra',
},
];
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
leading: IconButton(icon: const Icon(Symbols.arrow_back_ios_new),
onPressed: () {
Navigator.pop(context);
},),
title: const Text('Fund Transfer - Beneficiary', style: TextStyle(color: Colors.black,
fontWeight: FontWeight.w500),),
centerTitle: false,
actions: const [
Padding(
padding: EdgeInsets.only(right: 10.0),
child: CircleAvatar(
backgroundImage: AssetImage('assets/images/avatar.jpg'), // Replace with your image
radius: 20,
),
),
],
),
body: Padding(
padding: const EdgeInsets.all(8.0),
child: ListView.builder(
itemCount: beneficiaries.length,
itemBuilder: (context, index) {
final beneficiary = beneficiaries[index];
return ListTile(
leading: const CircleAvatar(
backgroundColor: Colors.blue,
child: Text('A')),
title: Text(beneficiary['name']!),
subtitle: Text(beneficiary['bank']!),
trailing: IconButton(
icon: const Icon(Symbols.arrow_right, size: 20,),
onPressed: () {
// Delete action
},
),
onTap: () {
Navigator.push(context, MaterialPageRoute(
builder: (context) => const FundTransferScreen()));
},
);
},
),
),
floatingActionButton: Padding(
padding: const EdgeInsets.only(bottom: 8.0),
child: FloatingActionButton(
onPressed: () {
Navigator.push(context, MaterialPageRoute(
builder: (context) => const AddBeneficiaryScreen()));
},
backgroundColor: Colors.grey[300],
foregroundColor: Colors.blue[900],
elevation: 5,
child: const Icon(Icons.add),
),
),
);
}
}

View File

@ -0,0 +1,133 @@
import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart';
import 'package:kmobile/features/fund_transfer/screens/transaction_pin_screen.dart';
import 'package:material_symbols_icons/material_symbols_icons.dart';
class FundTransferScreen extends StatefulWidget {
const FundTransferScreen({super.key});
@override
State<FundTransferScreen> createState() => _FundTransferScreen();
}
class _FundTransferScreen extends State<FundTransferScreen> {
String amount = "";
void onKeyTap(String key) {
setState(() {
if (key == 'back') {
if (amount.isNotEmpty) {
amount = amount.substring(0, amount.length - 1);
}
} else if (key == 'done') {
if (kDebugMode) {
print('Amount entered: $amount');
Navigator.push(
context,
MaterialPageRoute(
builder: (context) => const TransactionPinScreen()));
}
} else {
amount += key;
}
});
}
Widget buildKey(String value) {
if (value == 'done') {
return GestureDetector(
onTap: () => onKeyTap(value),
child: const Icon(Symbols.check, size: 30),
);
} else if (value == 'back') {
return GestureDetector(
onTap: () => onKeyTap(value),
child: const Icon(Symbols.backspace, size: 30));
} else {
return GestureDetector(
onTap: () => onKeyTap(value),
child: Center(
child: Text(value,
style: const TextStyle(fontSize: 24, color: Colors.black)),
),
);
}
}
final keys = [
'1',
'2',
'3',
'4',
'5',
'6',
'7',
'8',
'9',
'done',
'0',
'back',
];
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
leading: IconButton(
icon: const Icon(Symbols.arrow_back_ios_new),
onPressed: () {
Navigator.pop(context);
},
),
title: const Text(
'Fund Transfer',
style: TextStyle(color: Colors.black, fontWeight: FontWeight.w500),
),
centerTitle: false,
actions: const [
Padding(
padding: EdgeInsets.only(right: 10.0),
child: CircleAvatar(
backgroundImage: AssetImage('assets/images/avatar.jpg'),
// Replace with your image
radius: 20,
),
),
],
),
body: Column(
children: [
const Spacer(),
const Text('Enter Amount', style: TextStyle(fontSize: 20)),
const SizedBox(height: 20),
Container(
padding: const EdgeInsets.symmetric(horizontal: 24, vertical: 16),
decoration: BoxDecoration(
color: Colors.grey.shade200,
borderRadius: BorderRadius.circular(12),
),
child: Text(
amount.isEmpty ? "0" : amount,
style: const TextStyle(fontSize: 32, fontWeight: FontWeight.bold),
),
),
const Spacer(),
Container(
padding: const EdgeInsets.all(16.0),
color: Colors.white,
child: GridView.count(
crossAxisCount: 3,
shrinkWrap: true,
physics: const NeverScrollableScrollPhysics(),
mainAxisSpacing: 12,
crossAxisSpacing: 12,
childAspectRatio: 1.2,
children:
keys.map((key) => buildKey(key)).toList(),
),
),
],
),
);
}
}

View File

@ -0,0 +1,139 @@
import 'package:flutter/material.dart';
import 'package:kmobile/features/fund_transfer/screens/transaction_success_screen.dart';
import 'package:material_symbols_icons/material_symbols_icons.dart';
class TransactionPinScreen extends StatefulWidget {
const TransactionPinScreen({super.key});
@override
State<TransactionPinScreen> createState() => _TransactionPinScreen();
}
class _TransactionPinScreen extends State<TransactionPinScreen> {
final List<String> _pin = [];
void _onKeyPressed(String value) {
setState(() {
if (value == 'back') {
if (_pin.isNotEmpty) _pin.removeLast();
} else if (_pin.length < 6) {
_pin.add(value);
}
});
}
Widget _buildPinIndicators() {
return Row(
mainAxisAlignment: MainAxisAlignment.center,
children: List.generate(6, (index) {
return Container(
margin: const EdgeInsets.symmetric(horizontal: 8),
width: 20,
height: 20,
decoration: BoxDecoration(
shape: BoxShape.circle,
border: Border.all(color: Colors.blue, width: 2),
color: index < _pin.length ? Colors.blue : Colors.transparent,
),
);
}),
);
}
Widget _buildKey(String label, {IconData? icon}) {
return Expanded(
child: InkWell(
onTap: () {
if (label == 'back') {
_onKeyPressed('back');
} else if (label == 'done') {
// Handle submit if needed
if (_pin.length == 6) {
Navigator.push(
context,
MaterialPageRoute(
builder: (context) => const TransactionSuccessScreen()));
} else {
ScaffoldMessenger.of(context).showSnackBar(
const SnackBar(content: Text("Please enter a 6-digit TPIN")),
);
}
} else {
_onKeyPressed(label);
}
},
child: Padding(
padding: const EdgeInsets.symmetric(vertical: 20),
child: Center(
child: icon != null
? Icon(icon, size: 28)
: Text(label, style: const TextStyle(fontSize: 24)),
),
),
),
);
}
Widget _buildKeypad() {
return Column(
mainAxisSize: MainAxisSize.min,
children: [
Row(children: [_buildKey('1'), _buildKey('2'), _buildKey('3')]),
Row(children: [_buildKey('4'), _buildKey('5'), _buildKey('6')]),
Row(children: [_buildKey('7'), _buildKey('8'), _buildKey('9')]),
Row(children: [
_buildKey('done', icon: Icons.check),
_buildKey('0'),
_buildKey('back', icon: Icons.backspace_outlined),
]),
],
);
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
leading: IconButton(
icon: const Icon(Symbols.arrow_back_ios_new),
onPressed: () {
Navigator.pop(context);
},
),
title: const Text(
'TPIN',
style: TextStyle(color: Colors.black, fontWeight: FontWeight.w500),
),
centerTitle: false,
actions: const [
Padding(
padding: EdgeInsets.only(right: 10.0),
child: CircleAvatar(
backgroundImage: AssetImage('assets/images/avatar.jpg'),
// Replace with your image
radius: 20,
),
),
],
),
body: Padding(
padding: const EdgeInsets.only(bottom: 20.0),
child: Column(
children: [
const Spacer(),
const Text(
'Enter Your TPIN',
style: TextStyle(fontSize: 18),
),
const SizedBox(height: 20),
_buildPinIndicators(),
const Spacer(),
_buildKeypad(),
],
),
),
);
}
}

View File

@ -0,0 +1,140 @@
import 'dart:io';
import 'dart:typed_data';
import 'package:flutter/material.dart';
import 'package:path_provider/path_provider.dart';
import 'package:screenshot/screenshot.dart';
import 'package:social_share/social_share.dart';
import '../../../app.dart';
class TransactionSuccessScreen extends StatefulWidget {
const TransactionSuccessScreen({super.key});
@override
State<TransactionSuccessScreen> createState() => _TransactionSuccessScreen();
}
class _TransactionSuccessScreen extends State<TransactionSuccessScreen> {
final String transactionDate = "18th March, 2025 04:30 PM";
final String referenceNumber = "TXN32131093012931993";
final ScreenshotController _screenshotController = ScreenshotController();
Future<void> _shareScreenshot() async {
final Uint8List? imageBytes = await _screenshotController.capture();
if (imageBytes != null) {
final directory = await getTemporaryDirectory();
final imagePath = File('${directory.path}/transaction_success.png');
await imagePath.writeAsBytes(imageBytes);
SocialShare.shareOptions(
"Transaction Successful",
imagePath: imagePath.path,
);
}
}
@override
Widget build(BuildContext context) {
return Scaffold(
body: SafeArea(
child: Stack(
children: [
// Main content
Align(
alignment: Alignment.center,
child: Column(
mainAxisSize: MainAxisSize.min,
children: [
const CircleAvatar(
radius: 50,
backgroundColor: Colors.blue,
child: Icon(
Icons.check,
color: Colors.white,
size: 60,
),
),
const SizedBox(height: 24),
const Text(
"Transaction Successful",
style: TextStyle(
fontSize: 18,
fontWeight: FontWeight.w600,
),
textAlign: TextAlign.center,
),
const SizedBox(height: 6),
Text(
"On $transactionDate",
style: const TextStyle(
fontSize: 14,
color: Colors.black54,
),
textAlign: TextAlign.center,
),
const SizedBox(height: 16),
Text(
"Reference No: $referenceNumber",
style: const TextStyle(
fontSize: 12,
color: Colors.black87,
),
textAlign: TextAlign.center,
),
],
),
),
// Buttons at the bottom
Align(
alignment: Alignment.bottomCenter,
child: Padding(
padding: const EdgeInsets.fromLTRB(36, 0, 36, 25),
child: Row(
children: [
Expanded(
child: OutlinedButton.icon(
onPressed: _shareScreenshot,
icon: const Icon(Icons.share, size: 18),
label: const Text("Share"),
style: ElevatedButton.styleFrom(
shape: const StadiumBorder(),
padding: const EdgeInsets.symmetric(vertical: 16),
backgroundColor: Colors.white,
foregroundColor: Colors.blueAccent,
side: const BorderSide(color: Colors.black, width: 1),
elevation: 0
),
),
),
const SizedBox(width: 12),
Expanded(
child: ElevatedButton(
onPressed: () {
// Done action
Navigator.push(
context,
MaterialPageRoute(
builder: (context) => const NavigationScaffold()));
},
style: ElevatedButton.styleFrom(
shape: const StadiumBorder(),
padding: const EdgeInsets.symmetric(vertical: 16),
backgroundColor: Colors.blue[900],
foregroundColor: Colors.white,
),
child: const Text("Done"),
),
),
],
),
),
),
],
),
),
);
}
}

View File

@ -0,0 +1,372 @@
import 'package:flutter/material.dart';
import 'package:flutter_swipe_button/flutter_swipe_button.dart';
import 'package:material_symbols_icons/material_symbols_icons.dart';
class QuickPayOutsideBankScreen extends StatefulWidget {
const QuickPayOutsideBankScreen({super.key});
@override
State<QuickPayOutsideBankScreen> createState() =>
_QuickPayOutsideBankScreen();
}
class _QuickPayOutsideBankScreen extends State<QuickPayOutsideBankScreen> {
final _formKey = GlobalKey<FormState>();
// Controllers
final accountNumberController = TextEditingController();
final nameController = TextEditingController();
final bankNameController = TextEditingController();
final branchNameController = TextEditingController();
final ifscController = TextEditingController();
final phoneController = TextEditingController();
final amountController = TextEditingController();
String accountType = 'Savings';
final List<String> transactionModes = ['NEFT', 'RTGS', 'IMPS'];
int selectedTransactionIndex = 0;
@override
void dispose() {
// Dispose controllers
accountNumberController.dispose();
nameController.dispose();
bankNameController.dispose();
branchNameController.dispose();
ifscController.dispose();
phoneController.dispose();
amountController.dispose();
super.dispose();
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
leading: IconButton(
icon: const Icon(Symbols.arrow_back_ios_new),
onPressed: () {
Navigator.pop(context);
},
),
title: const Text(
'Quick Pay - Other Bank',
style: TextStyle(color: Colors.black, fontWeight: FontWeight.w500),
),
centerTitle: false,
actions: const [
Padding(
padding: EdgeInsets.only(right: 10.0),
child: CircleAvatar(
backgroundImage: AssetImage('assets/images/avatar.jpg'),
// Replace with your image
radius: 20,
),
),
],
),
body: Padding(
padding: const EdgeInsets.all(12),
child: Form(
key: _formKey,
child: ListView(
children: [
const SizedBox(height: 25),
TextFormField(
decoration: const InputDecoration(
labelText: 'Account Number',
border: OutlineInputBorder(),
isDense: true,
filled: true,
fillColor: Colors.white,
enabledBorder: OutlineInputBorder(
borderSide: BorderSide(color: Colors.black),
),
focusedBorder: OutlineInputBorder(
borderSide: BorderSide(color: Colors.black, width: 2),
),
),
controller: accountNumberController,
keyboardType: TextInputType.number,
textInputAction: TextInputAction.next,
validator: (value) {
if (value == null || value.isEmpty) {
return 'Account number is required';
} else if (value.length != 16) {
return 'Enter a valid account number';
}
return null;
},
),
const SizedBox(height: 25),
TextFormField(
decoration: const InputDecoration(
labelText: 'Name',
border: OutlineInputBorder(),
isDense: true,
filled: true,
fillColor: Colors.white,
enabledBorder: OutlineInputBorder(
borderSide: BorderSide(color: Colors.black),
),
focusedBorder: OutlineInputBorder(
borderSide: BorderSide(color: Colors.black, width: 2),
),
),
controller: nameController,
keyboardType: TextInputType.name,
textInputAction: TextInputAction.next,
validator: (value) {
if (value == null || value.isEmpty) {
return 'Name is required';
}
return null;
},
),
const SizedBox(height: 25),
TextFormField(
decoration: const InputDecoration(
labelText: "Beneficiary Bank Name",
border: OutlineInputBorder(),
isDense: true,
filled: true,
fillColor: Colors.white,
enabledBorder: OutlineInputBorder(
borderSide: BorderSide(color: Colors.black),
),
focusedBorder: OutlineInputBorder(
borderSide: BorderSide(color: Colors.black, width: 2),
),
),
controller: bankNameController,
textInputAction: TextInputAction.next,
validator: (value) {
if (value == null || value.isEmpty) {
return 'Beneficiary Bank Name is required';
}
return null;
},
),
const SizedBox(height: 25),
TextFormField(
decoration: const InputDecoration(
labelText: "Branch Name",
border: OutlineInputBorder(),
isDense: true,
filled: true,
fillColor: Colors.white,
enabledBorder: OutlineInputBorder(
borderSide: BorderSide(color: Colors.black),
),
focusedBorder: OutlineInputBorder(
borderSide: BorderSide(color: Colors.black, width: 2),
),
),
controller: branchNameController,
textInputAction: TextInputAction.next,
validator: (value) {
if (value == null || value.isEmpty) {
return 'Branch Name is required';
}
return null;
},
),
const SizedBox(height: 25),
Row(
children: [
Expanded(
child: TextFormField(
decoration: const InputDecoration(
labelText: "IFSC Code",
border: OutlineInputBorder(),
isDense: true,
filled: true,
fillColor: Colors.white,
enabledBorder: OutlineInputBorder(
borderSide: BorderSide(color: Colors.black),
),
focusedBorder: OutlineInputBorder(
borderSide: BorderSide(color: Colors.black, width: 2),
),
),
controller: ifscController,
textInputAction: TextInputAction.next,
validator: (value) {
if (value == null || value.isEmpty) {
return 'IFSC Code is required';
}
return null;
},
)),
const SizedBox(width: 10),
Expanded(
child: DropdownButtonFormField<String>(
value: accountType,
decoration: const InputDecoration(
labelText: "Account Type",
border: OutlineInputBorder(),
isDense: true,
filled: true,
fillColor: Colors.white,
enabledBorder: OutlineInputBorder(
borderSide: BorderSide(color: Colors.black),
),
focusedBorder: OutlineInputBorder(
borderSide: BorderSide(color: Colors.black, width: 2),
),
),
items: ['Savings', 'Current']
.map((e) => DropdownMenuItem(
value: e,
child: Text(e),
))
.toList(),
onChanged: (value) => setState(() {
accountType = value!;
}),
),
),
],
),
const SizedBox(height: 25),
Row(
children: [
Expanded(
child: TextFormField(
controller: phoneController,
keyboardType: TextInputType.phone,
decoration: const InputDecoration(
labelText: "Phone",
prefixIcon: Icon(Icons.phone),
border: OutlineInputBorder(),
isDense: true,
filled: true,
fillColor: Colors.white,
enabledBorder: OutlineInputBorder(
borderSide: BorderSide(color: Colors.black),
),
focusedBorder: OutlineInputBorder(
borderSide: BorderSide(color: Colors.black, width: 2),
),
),
textInputAction: TextInputAction.next,
validator: (value) => value == null || value.isEmpty
? "Phone number is Required"
: null,
),
),
const SizedBox(width: 10),
Expanded(
child: TextFormField(
decoration: const InputDecoration(
labelText: 'Amount',
border: OutlineInputBorder(),
isDense: true,
filled: true,
fillColor: Colors.white,
enabledBorder: OutlineInputBorder(
borderSide: BorderSide(color: Colors.black),
),
focusedBorder: OutlineInputBorder(
borderSide: BorderSide(color: Colors.black, width: 2),
),
),
controller: amountController,
keyboardType: TextInputType.number,
textInputAction: TextInputAction.next,
validator: (value) {
if (value == null || value.isEmpty) {
return 'Amount is required';
}
final amount = double.tryParse(value);
if (amount == null || amount <= 0) {
return 'Enter a valid amount';
}
return null;
},
),
),
],
),
const SizedBox(height: 30),
Row(
children: [
const Text("Transaction Mode",
style: TextStyle(fontWeight: FontWeight.w500)),
const SizedBox(width: 12),
Expanded(child: buildTransactionModeSelector()),
],
),
const SizedBox(height: 45),
Align(
alignment: Alignment.center,
child: SwipeButton.expand(
thumb: const Icon(
Icons.arrow_forward,
color: Colors.white,
),
activeThumbColor: Colors.blue[900],
activeTrackColor: Colors.blue.shade100,
borderRadius: BorderRadius.circular(30),
height: 56,
child: const Text(
"Swipe to Pay",
style: TextStyle(fontSize: 16, fontWeight: FontWeight.bold),
),
onSwipe: () {
if (_formKey.currentState!.validate()) {
// Perform payment logic
final selectedMode = transactionModes[selectedTransactionIndex];
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(content: Text('Paying via $selectedMode...')),
);
}
},
)
),
],
),
),
),
);
}
Widget buildTransactionModeSelector() {
return Container(
padding: const EdgeInsets.all(4),
child: Row(
children: List.generate(transactionModes.length, (index) {
bool isSelected = selectedTransactionIndex == index;
return Expanded(
child: GestureDetector(
onTap: () {
setState(() => selectedTransactionIndex = index);
},
child: Container(
margin: const EdgeInsets.symmetric(horizontal: 4),
padding: const EdgeInsets.symmetric(vertical: 5),
decoration: BoxDecoration(
color: isSelected ? Colors.blue[200] : Colors.white,
borderRadius: BorderRadius.circular(5),
border: Border.all(
color: isSelected? Colors.blue : Colors.grey,
width: isSelected ? 0 : 1.2,
),
),
alignment: Alignment.center,
child: Text(
transactionModes[index],
style: const TextStyle(
color: Colors.black,
),
),
),
),
);
}),
),
);
}
}

View File

@ -0,0 +1,95 @@
import 'package:flutter/material.dart';
import 'package:kmobile/features/quick_pay/screens/quick_pay_outside_bank_screen.dart';
import 'package:kmobile/features/quick_pay/screens/quick_pay_within_bank_screen.dart';
import 'package:material_symbols_icons/material_symbols_icons.dart';
class QuickPayScreen extends StatefulWidget {
const QuickPayScreen({super.key});
@override
State<QuickPayScreen> createState() => _QuickPayScreen();
}
class _QuickPayScreen extends State<QuickPayScreen> {
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
leading: IconButton(
icon: const Icon(Symbols.arrow_back_ios_new),
onPressed: () {
Navigator.pop(context);
},
),
title: const Text(
'Quick Pay',
style: TextStyle(color: Colors.black, fontWeight: FontWeight.w500),
),
centerTitle: false,
actions: const [
Padding(
padding: EdgeInsets.only(right: 10.0),
child: CircleAvatar(
backgroundImage: AssetImage('assets/images/avatar.jpg'),
// Replace with your image
radius: 20,
),
),
],
),
body: ListView(
children: [
QuickPayManagementTile(
icon: Symbols.input_circle,
label: 'Own Bank',
onTap: () {
Navigator.push(
context,
MaterialPageRoute(
builder: (context) => const QuickPayWithinBankScreen()));
},
),
const Divider(
height: 1,
),
QuickPayManagementTile(
icon: Symbols.output_circle,
label: 'Outside Bank',
onTap: () {
Navigator.push(
context,
MaterialPageRoute(
builder: (context) => const QuickPayOutsideBankScreen()));
},
),
const Divider(
height: 1,
),
],
),
);
}
}
class QuickPayManagementTile extends StatelessWidget {
final IconData icon;
final String label;
final VoidCallback onTap;
const QuickPayManagementTile({
super.key,
required this.icon,
required this.label,
required this.onTap,
});
@override
Widget build(BuildContext context) {
return ListTile(
leading: Icon(icon),
title: Text(label),
trailing: const Icon(Symbols.arrow_right, size: 20),
onTap: onTap,
);
}
}

View File

@ -0,0 +1,209 @@
import 'package:flutter/material.dart';
import 'package:flutter_swipe_button/flutter_swipe_button.dart';
import 'package:material_symbols_icons/material_symbols_icons.dart';
class QuickPayWithinBankScreen extends StatefulWidget {
const QuickPayWithinBankScreen({super.key});
@override
State<QuickPayWithinBankScreen> createState() => _QuickPayWithinBankScreen();
}
class _QuickPayWithinBankScreen extends State<QuickPayWithinBankScreen> {
final _formKey = GlobalKey<FormState>();
final TextEditingController accountNumberController = TextEditingController();
final TextEditingController nameController = TextEditingController();
final TextEditingController amountController = TextEditingController();
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
leading: IconButton(
icon: const Icon(Symbols.arrow_back_ios_new),
onPressed: () {
Navigator.pop(context);
},
),
title: const Text(
'Quick Pay - Own Bank',
style: TextStyle(color: Colors.black, fontWeight: FontWeight.w500),
),
centerTitle: false,
actions: const [
Padding(
padding: EdgeInsets.only(right: 10.0),
child: CircleAvatar(
backgroundImage: AssetImage('assets/images/avatar.jpg'),
// Replace with your image
radius: 20,
),
),
],
),
body: Padding(
padding: const EdgeInsets.all(16.0),
child: Form(
key: _formKey,
child: Column(
children: [
const SizedBox(height: 25),
TextFormField(
decoration: const InputDecoration(
labelText: 'Account Number',
border: OutlineInputBorder(),
isDense: true,
filled: true,
fillColor: Colors.white,
enabledBorder: OutlineInputBorder(
borderSide: BorderSide(color: Colors.black),
),
focusedBorder: OutlineInputBorder(
borderSide: BorderSide(color: Colors.black, width: 2),
),
),
controller: accountNumberController,
keyboardType: TextInputType.number,
textInputAction: TextInputAction.next,
validator: (value) {
if (value == null || value.isEmpty) {
return 'Account number is required';
} else if (value.length != 16) {
return 'Enter a valid account number';
}
return null;
},
),
const Align(
alignment: Alignment.topLeft,
child: Padding(
padding: EdgeInsets.only(left: 15.0, top: 5),
child: Text(
'Beneficiary Account Number',
style: TextStyle(color: Colors.black54),
),
)),
const SizedBox(height: 25),
TextFormField(
decoration: const InputDecoration(
labelText: 'Name',
border: OutlineInputBorder(),
isDense: true,
filled: true,
fillColor: Colors.white,
enabledBorder: OutlineInputBorder(
borderSide: BorderSide(color: Colors.black),
),
focusedBorder: OutlineInputBorder(
borderSide: BorderSide(color: Colors.black, width: 2),
),
),
controller: nameController,
keyboardType: TextInputType.name,
textInputAction: TextInputAction.next,
validator: (value) {
if (value == null || value.isEmpty) {
return 'Name is required';
}
return null;
},
),
const Align(
alignment: Alignment.topLeft,
child: Padding(
padding: EdgeInsets.only(left: 15.0, top: 5),
child: Text(
'Beneficiary Name',
style: TextStyle(color: Colors.black54),
),
)),
const SizedBox(height: 25),
TextFormField(
decoration: const InputDecoration(
labelText: 'Amount',
border: OutlineInputBorder(),
isDense: true,
filled: true,
fillColor: Colors.white,
enabledBorder: OutlineInputBorder(
borderSide: BorderSide(color: Colors.black),
),
focusedBorder: OutlineInputBorder(
borderSide: BorderSide(color: Colors.black, width: 2),
),
),
controller: amountController,
keyboardType: TextInputType.number,
textInputAction: TextInputAction.next,
validator: (value) {
if (value == null || value.isEmpty) {
return 'Amount is required';
}
final amount = double.tryParse(value);
if (amount == null || amount <= 0) {
return 'Enter a valid amount';
}
return null;
},
),
const SizedBox(height: 45),
Align(
alignment: Alignment.center,
child: SwipeButton.expand(
thumb: const Icon(
Icons.arrow_forward,
color: Colors.white,
),
activeThumbColor: Colors.blue[900],
activeTrackColor: Colors.blue.shade100,
borderRadius: BorderRadius.circular(30),
height: 56,
child: const Text(
"Swipe to Pay",
style: TextStyle(fontSize: 16, fontWeight: FontWeight.bold),
),
onSwipe: () {
if (_formKey.currentState!.validate()) {
// Perform payment logic
ScaffoldMessenger.of(context).showSnackBar(
const SnackBar(
content: Text('Processing Payment...')),
);
}
},
),
),
],
),
),
),
);
}
Widget buildTextFormField({
required String label,
required TextEditingController controller,
TextInputType keyboardType = TextInputType.text,
String? Function(String?)? validator,
}) {
return TextFormField(
controller: controller,
keyboardType: keyboardType,
validator: validator,
decoration: InputDecoration(
labelText: label,
border: const OutlineInputBorder(),
isDense: true,
filled: true,
fillColor: Colors.white,
enabledBorder: const OutlineInputBorder(
borderSide: BorderSide(color: Colors.black),
),
focusedBorder: const OutlineInputBorder(
borderSide: BorderSide(color: Colors.black, width: 2),
),
),
);
}
}

View File

@ -0,0 +1,113 @@
import 'package:flutter/material.dart';
import 'package:material_symbols_icons/material_symbols_icons.dart';
class ServiceScreen extends StatefulWidget {
const ServiceScreen({super.key});
@override
State<ServiceScreen> createState() => _ServiceScreen();
}
class _ServiceScreen extends State<ServiceScreen>{
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
automaticallyImplyLeading: false,
title: const Text('Services', style: TextStyle(color: Colors.black,
fontWeight: FontWeight.w500),),
centerTitle: false,
actions: [
// IconButton(
// icon: const Icon(Icons.notifications_outlined),
// onPressed: () {
// // Navigate to notifications
// },
// ),
Padding(
padding: const EdgeInsets.only(right: 10.0),
child: InkWell(
borderRadius: BorderRadius.circular(20),
onTap: (){
// Navigator.push(context, MaterialPageRoute(
// builder: (context) => const CustomerInfoScreen()));
},
child: const CircleAvatar(
backgroundImage: AssetImage('assets/images/avatar.jpg'), // Replace with your image
radius: 20,
),
),
),
],
),
body: ListView(
children: [
ServiceManagementTile(
icon: Symbols.add,
label: 'Account Opening Request - Deposit',
onTap: () {
},
),
const Divider(height: 1,),
ServiceManagementTile(
icon: Symbols.add,
label: 'Account Opening Request - Loan',
onTap: () {
},
),
const Divider(height: 1,),
ServiceManagementTile(
icon: Symbols.captive_portal,
label: 'Quick Links',
onTap: () {
},
),
const Divider(height: 1,),
ServiceManagementTile(
icon: Symbols.missing_controller,
label: 'Branch Locator',
onTap: () {
},
),
const Divider(height: 1,)
],
),
);
}
}
class ServiceManagementTile extends StatelessWidget {
final IconData icon;
final String label;
final VoidCallback onTap;
const ServiceManagementTile({
super.key,
required this.icon,
required this.label,
required this.onTap,
});
@override
Widget build(BuildContext context) {
return ListTile(
leading: Icon(icon),
title: Text(label),
trailing: const Icon(Symbols.arrow_right, size: 20),
onTap: onTap,
);
}
}

174
lib/l10n/app_bn.arb Normal file
View File

@ -0,0 +1,174 @@
{
"@@locale": "bn",
"app_title": "আইপিকেএস ম্যাপ",
"ipks": "আইপিকেএস",
"fingerprint_reason": "অ্যাপ শুরু করতে প্রমাণীকরণ করুন",
"@fingerprint_reason": {},
"m_pin_entry_prompt": "আপনার এমপিআইএন লিখুন",
"register_prompt": "রেজিস্টার?",
"try_another_way": "অন্য উপায় চেষ্টা করুন",
"username": "ব্যবহারকারীর নাম",
"password": "পাসওয়ার্ড",
"login": "লগইন",
"register": "রেজিস্টার",
"mobile_number": "মোবাইল নম্বর",
"aadhaar_number": "আধার নম্বর",
"date_of_birth": "জন্ম তারিখ",
"pacs_id": "প্যাকস আইডি",
"view_full_kyc": "পূর্ণ কেওয়াইসি দেখুন",
"account_summary": "হিসাবের সংক্ষিপ্ত সমূহ",
"account_statement": "হিসাবের বিবৃতি",
"customer_details": "গ্রাহকের বিবরণ",
"home": "হোম",
"details": "বিস্তারিত",
"statement": "বিবৃতি",
"no_of_active_accounts": "সক্রিয় হিসাবের সংখ্যা",
"pan_number": "প্যান নম্বর",
"mirror_acct_no": "মিরর হিসাব নম্বর",
"cif": "সিআইএফ",
"product_name": "পণ্যের নাম",
"acct_opening_dt": "হিসাব খোলার তারিখ",
"account_status": "হিসাবের অবস্থা",
"available_bal": "উপলব্ধ ব্যালেন্স",
"interest_rate": "সুদের হার",
"acct_type": "হিসাবের ধরন",
"acct_no": "হিসাব নম্বর",
"date_range": "তারিখের পরিসীমা",
"amount_range": "পরিমাণের পরিসীমা",
"save": "সংরক্ষণ করুন",
"min": "সর্বনিম্ন",
"max": "সর্বোচ্চ",
"min_amt": "ন্যূনতম পরিমাণ",
"max_amt": "সর্বোচ্চ পরিমাণ",
"customer_no_search_message": "আপনার আইপিকেএস গ্রাহক নম্বর লিখুন দয়া করে। আপনার গ্রাহক নম্বরটি আইপিকেএস ডেটাবেসে আপনার বিবরণ খুঁজে পেতে ব্যবহৃত হয়।",
"search": "অনুসন্ধান",
"details_verification_message": "দয়া করে আপনার বিবরণ যাচাই করুন।",
"customer_no": "গ্রাহক নম্বর",
"name": "নাম",
"email": "ইমেল",
"pacs_name": "প্যাকস নাম",
"not_you_prompt": "না আপনি?",
"next": "পরবর্তী",
"otp_verification_message": "একটি ওটিপি মেসেজ আপনার নিবন্ধিত মোবাইল নম্বরে {masked_phone_number} প্রেরিত হয়েছে। এটি যাচাই করতে নিচে লিখুন।",
"@otp_verification_message": {
"placeholders": {
"masked_phone_number": {
"type": "String"
}
}
},
"otp": "ওটিপি",
"resend_otp_prompt": "পুনরায় ওটিপি প্রেরণ করুন?",
"new_credentials_message": "দয়া করে এমঅ্যাপ এর জন্য আপনার নতুন ব্যবহারকারী নাম এবং পাসওয়ার্ড তৈরি করুন",
"repeat_password": "পাসওয়ার্ড পুনরায় লিখুন",
"registration_success_display": "রেজিস্ট্রেশন সফল",
"goto_login_prompt": "লগইন পৃষ্ঠায় যান",
"marital_status": "বৈবাহিক অবস্থা",
"gender": "লিঙ্গ",
"address": "ঠিকানা",
"or": "অথবা",
"district": "জেলা",
"state": "রাজ্য",
"city": "শহর",
"pin_code": "পিন কোড",
"linked_sb_no": "সংযুক্ত এসবি হিসাব নম্বর",
"farmer_type": "কৃষকের ধরণ",
"guardian_name": "অভিভাবকের নাম",
"religion": "ধর্ম",
"caste": "জাতি",
"not_available": "পাওয়া যায়নি",
"no_accounts_found": "কোনও হিসাব পাওয়া যায়নি",
"account_holder": "হিসাব ধারক",
"customer_name": "গ্রাহকের নাম",
"sanction_amount": "অনুমোদিত পরিমাণ",
"sanction_date": "অনুমোদনের তারিখ",
"disbursed_amount": "বিতরণ করা পরিমাণ",
"interest_outstanding": "সুদের বকেয়া",
"principal_outstanding": "প্রধান বকেয়া",
"interest_paid": "সুদ প্রদান",
"principal_paid": "প্রধান প্রদান",
"emi_amount": "ইএমআই পরিমাণ",
"due_date": "নির্ধারিত তারিখ",
"last_repayment_date": "সর্বশেষ পরিশোধের তারিখ",
"interest_description": "সুদের বিবরণ",
"total_interest_outstanding": "মোট সুদের বকেয়া",
"total_interest_accrued": "মোট সুদ উত্থাপন",
"total_interest_paid": "মোট সুদ প্রদান",
"loan_type": "ঋণের ধরণ",
"old_account_number": "পুরাতন হিসাব নম্বর",
"penal_interest_rate": "জরিমানা সুদের হার",
"cbs_account_number": "সিবিএস হিসাব নম্বর",
"nominee_name": "নোমিনির নাম",
"open_date": "খোলার তারিখ",
"interest_available": "সুদ উপলব্ধ",
"interest_from_date": "সুদ শুরুর তারিখ",
"interest_to_date": "সুদ শেষের তারিখ",
"term_value": "মেয়াদ মান",
"maturity_value": "পরিপ্রেক্ষিত মূল্য",
"maturity_date": "পরিপ্রেক্ষিত তারিখ",
"term_start_date": "মেয়াদ শুরুর তারিখ",
"term_end_date": "মেয়াদ শেষের তারিখ",
"interest_projected": "সুদ প্রকাশ্য",
"interest_capitalized": "সুদ পুঁজিবদ্ধ",
"no_of_installments_paid": "পরিশোধিত কিস্তির সংখ্যা",
"next_due_date": "পরবর্তী মেয়াদ শেষের তারিখ",
"rd_penal_count": "আরডি জরিমানা গণনা",
"hold_value": "ধার মান",
"term_length": "মেয়াদের দৈর্ঘ্য",
"interest_repayment_method": "সুদ পরিশোধের পদ্ধতি",
"mode_of_account": "হিসাবের মোড",
"secondary_cif_number": "দ্বিতীয় সিআইএফ নম্বর",
"secondary_cif_name": "দ্বিতীয় সিআইএফ নাম",
"no_statements_found": "কোনও বিবৃতি পাওয়া যায়নি",
"date_range_exceeds_10_days": "10 দিনের বেশি সময়কাল নির্বাচন করুন না",
"last_10_transactions": "সর্বশেষ 10 লেনদেন প্রদর্শিত হচ্ছে",
"select_account_type": "হিসাবের ধরন নির্বাচন করুন",
"select_account_number": "হিসাব নম্বর নির্বাচন করুন",
"select_date_range": "তারিখের পরিসীমা নির্বাচন করুন",
"please_wait": "অপেক্ষা করুন...",
"preferences": "পছন্দসমূহ",
"everforest": "এভারফরেস্ট",
"rosy": "রোসি",
"skypeia": "স্কাইপিয়া",
"marigold": "গাঁদা ফুল",
"select_language": "ভাষা নির্বাচন করুন",
"english": "ইংরেজি",
"hindi": "হিন্দি",
"bengali": "বাংলা",
"malayalam": "মালায়ালম",
"dark_theme": "গা থিম",
"color_theme": "রঙের থিম",
"language": "ভাষা",
"deposit": "জমা",
"loan": "ঋণ",
"export": "রপ্তানি",
"invalid_credentials": "অবৈধ পরিচয়পত্র",
"logout": "লগআউট",
"backend_ip": "ব্যাকএন্ড আইপি",
"bank_branch_no": "ব্যাংক শাখা নম্বর",
"ifsc_code": "আইএফএসসি কোড",
"bank_branch_name": "ব্যাংক শাখার নাম",
"search_customer_paragraph": "অনুগ্রহ করে আপনার আইপিকেএস গ্রাহক নম্বর দিন। আপনার গ্রাহক নম্বর আইপিকেএস ডাটাবেসে আপনার বিবরণ খুঁজতে ব্যবহৃত হয়",
"invalid_customer_no": "অবৈধ গ্রাহক নম্বর",
"searching": "অনুসন্ধান করা হচ্ছে",
"invalid_otp": "অবৈধ ওটিপি",
"register_customer_message": "অনুগ্রহ করে এমঅ্যাপের জন্য আপনার নতুন ব্যবহারকারী নাম এবং পাসওয়ার্ড প্রবেশ করান",
"username_criteria": "৬টি অক্ষর, শুধুমাত্র অক্ষর এবং সংখ্যা",
"password_criteria": "একটি বড় হাতের অক্ষর, একটি ছোট হাতের অক্ষর, একটি সংখ্যা (৮টি অক্ষর)",
"passowrd_mismatch_msg": "পাসওয়ার্ডগুলি মেলে না",
"password_confirm": "পাসওয়ার্ড নিশ্চিত করুন",
"registration_successful": "নিবন্ধন সফল হয়েছে",
"registration_successful_message": "অনুগ্রহ করে আপনার নতুন পরিচয়পত্র দিয়ে লগইন করুন",
"goto_login": "লগইন পৃষ্ঠায় যান",
"socket_exception": "অনুগ্রহ করে আপনার ইন্টারনেট সংযোগ পরীক্ষা করুন",
"mpin_setup": "-সংখ্যার এমপিন সেট করুন",
"mpin_confirm": "আপনার এমপিন নিশ্চিত করুন",
"storage_permission_denied": "স্টোরেজ অনুমতি অস্বীকৃত হয়েছে",
"forgot_password": "পাসওয়ার্ড ভুলে গেছেন",
"forgot_password_search_user": "আপনার সিআইএফ নম্বর লিখুন",
"forgot_password_success": "রিসেট সফল হয়েছে",
"forgot_password_create": "আপনার নতুন পাসওয়ার্ড লিখুন",
"new_password": "নতুন পাসওয়ার্ড",
"security": "নিরাপত্তা",
"verify_mpin": "আপনার এমপিন যাচাই করুন"
}

174
lib/l10n/app_en.arb Normal file
View File

@ -0,0 +1,174 @@
{
"@@locale": "en",
"app_title": "mApp",
"ipks": "IPKS",
"fingerprint_reason": "Authenticate to start app",
"@fingerprint_reason": {},
"m_pin_entry_prompt": "Enter your mPIN",
"register_prompt": "Register?",
"try_another_way": "Try another way",
"username": "Username",
"password": "Password",
"login": "Login",
"register": "Register",
"mobile_number": "Mobile Number",
"aadhaar_number": "Aadhaar Number",
"date_of_birth": "Date of Birth",
"pacs_id": "PACS id",
"view_full_kyc": "View full KYC",
"account_summary": "Account Summary",
"account_statement": "Account Statement",
"customer_details": "Customer Details",
"home": "Home",
"details": "Details",
"statement": "Statement",
"no_of_active_accounts": "Number of active accounts",
"pan_number": "PAN Number",
"mirror_acct_no": "Mirror Account Number",
"cif": "CIF",
"product_name": "Product Name",
"acct_opening_dt": "Account Opening Date",
"account_status": "Account Status",
"available_bal": "Available Balance",
"interest_rate": "Interest Rate",
"acct_type": "Account Type",
"acct_no": "Account Number",
"date_range": "Date Range",
"amount_range": "Amount Range",
"save": "Save",
"min": "Min",
"max": "Max",
"min_amt": "Min Amount",
"max_amt": "Max Amount",
"customer_no_search_message": "Please enter your IPKS customer number. Your customer number is used to search your details in the IPKS database.",
"search": "Search",
"details_verification_message": "Please verify your details.",
"customer_no": "Customer Number",
"name": "Name",
"email": "Email",
"pacs_name": "PACS Name",
"not_you_prompt": "Not You?",
"next": "Next",
"otp_verification_message": "An OTP message has been sent to your registered mobile number {masked_phone_number}. Enter it below to verify your phone number.",
"@otp_verification_message": {
"placeholders": {
"masked_phone_number": {
"type": "String"
}
}
},
"otp": "OTP",
"resend_otp_prompt": "Resend OTP?",
"new_credentials_message": "Please create your new username and password for mApp",
"repeat_password": "Repeat Password",
"registration_success_display": "Registration success",
"goto_login_prompt": "Go to Login Page",
"marital_status": "Marital Status",
"gender": "Gender",
"address": "Address",
"or": "OR",
"district": "District",
"state": "State",
"city": "City",
"pin_code": "Pin code",
"linked_sb_no": "Linked SB Account Number",
"farmer_type": "Farmer Type",
"guardian_name": "Guardian Name",
"religion": "Religion",
"caste": "Caste",
"not_available": "Not Available",
"no_accounts_found": "No Accounts Found",
"account_holder": "Account Holder",
"customer_name": "Customer Name",
"sanction_amount": "Sanction Amount",
"sanction_date": "Sanction Date",
"disbursed_amount": "Disbursed Amount",
"interest_outstanding": "Interest Outstanding",
"principal_outstanding": "Principal Outstanding",
"interest_paid": "Interest Paid",
"principal_paid": "Principal Paid",
"emi_amount": "EMI Amount",
"due_date": "Due Date",
"last_repayment_date": "Last Repayment Date",
"interest_description": "Interest Description",
"total_interest_outstanding": "Total Interest Outstanding",
"total_interest_accrued": "Total Interest Accrued",
"total_interest_paid": "Total Interest Paid",
"loan_type": "Loan Type",
"old_account_number": "Old Account Number",
"penal_interest_rate": "Penal Interest Rate",
"cbs_account_number": "CBS Account Number",
"nominee_name": "Nominee Name",
"open_date": "Open Date",
"interest_available": "Interest Available",
"interest_from_date": "Interest From Date",
"interest_to_date": "Interest To Date",
"term_value": "Term Value",
"maturity_value": "Maturity Value",
"maturity_date": "Maturity Date",
"term_start_date": "Term Start Date",
"term_end_date": "Term End Date",
"interest_projected": "Interest Projected",
"interest_capitalized": "Interest Capitalized",
"no_of_installments_paid": "Number of Installments Paid",
"next_due_date": "Next Due Date",
"rd_penal_count": "RD Penal Count",
"hold_value": "Hold Value",
"term_length": "Term Length",
"interest_repayment_method": "Interest Repayment Method",
"mode_of_account": "Mode of Account",
"secondary_cif_number": "Secondary CIF Number",
"secondary_cif_name": "Secondary CIF Name",
"no_statements_found": "No Statements Found",
"date_range_exceeds_10_days": "Select duration of 10 days or less",
"last_10_transactions": "Displaying last 10 transactions",
"select_account_type": "Select Account Type",
"select_account_number": "Select Account Number",
"select_date_range": "Select Date Range",
"please_wait": "Please wait...",
"preferences": "Preferences",
"everforest": "Everforest",
"rosy": "Rosy",
"skypeia": "Skypeia",
"marigold": "Marigold",
"select_language": "Select Language",
"english": "English",
"hindi": "Hindi",
"bengali": "Bengali",
"malayalam": "Malayalam",
"dark_theme": "Dark Theme",
"color_theme": "Color Theme",
"language": "Language",
"deposit": "Deposit",
"loan": "Loan",
"export": "Export",
"invalid_credentials": "Invalid credentials",
"logout": "Logout",
"backend_ip": "Backend IP",
"bank_branch_no": "Bank Branch Number",
"ifsc_code": "IFSC code",
"bank_branch_name": "Bank Branch Name",
"search_customer_paragraph": "Please enter your IPKS customer number. Your customer number is used to search your details in the IPKS database",
"invalid_customer_no": "Invalid customer number",
"searching": "Searching",
"invalid_otp": "Invalid OTP",
"register_customer_message": "Please enter your new username and password for mApp",
"username_criteria": "6 characters, only letters and digits",
"password_criteria": "one uppercase, one lowercase, one number (8 characters)",
"passowrd_mismatch_msg": "The passwords doesn't match",
"password_confirm": "Confirm Password",
"registration_successful": "Registration Successful",
"registration_successful_message": "Please login with your new credentails",
"goto_login": "Got to Login Page",
"socket_exception": "Please check your internet connection",
"mpin_setup": "Setup 4-digit MPIN",
"mpin_confirm": "Confirm your MPIN",
"storage_permission_denied": "Storage Persmission denied",
"forgot_password": "Forgot Password",
"forgot_password_search_user": "Enter your CIF number",
"forgot_password_success": "Reset Successful",
"forgot_password_create": "Enter your new password",
"new_password": "New Password",
"security": "Security",
"verify_mpin": "Verify your MPIN"
}

174
lib/l10n/app_hi.arb Normal file
View File

@ -0,0 +1,174 @@
{
"@@locale": "hi",
"app_title": "आईपीकेएस ऐप",
"ipks": "आईपीकेएस",
"fingerprint_reason": "ऐप शुरू करने के लिए प्रमाणित करें",
"@fingerprint_reason": {},
"m_pin_entry_prompt": "अपना एम पिन दर्ज करें",
"register_prompt": "रजिस्टर करें?",
"try_another_way": "किसी अन्य तरीके की कोशिश करें",
"username": "उपयोगकर्ता नाम",
"password": "पासवर्ड",
"login": "लॉगिन",
"register": "रजिस्टर",
"mobile_number": "मोबाइल नंबर",
"aadhaar_number": "आधार नंबर",
"date_of_birth": "जन्म तिथि",
"pacs_id": "पैक्स आईडी",
"view_full_kyc": "पूरा केवाईसी देखें",
"account_summary": "हिसाब सारांश",
"account_statement": "हिसाब की बयान",
"customer_details": "ग्राहक विवरण",
"home": "होम",
"details": "विवरण",
"statement": "बयान",
"no_of_active_accounts": "सक्रिय खातों की संख्या",
"pan_number": "पैन नंबर",
"mirror_acct_no": "मिरर खाता नंबर",
"cif": "सीआईएफ",
"product_name": "उत्पाद का नाम",
"acct_opening_dt": "खाता खोलने की तिथि",
"account_status": "खाता की स्थिति",
"available_bal": "उपलब्ध शेष",
"interest_rate": "ब्याज दर",
"acct_type": "खाते का प्रकार",
"acct_no": "खाता संख्या",
"date_range": "तिथि सीमा",
"amount_range": "राशि सीमा",
"save": "सहेजें",
"min": "न्यूनतम",
"max": "अधिकतम",
"min_amt": "न्यूनतम राशि",
"max_amt": "अधिकतम राशि",
"customer_no_search_message": "कृपया अपना आईपीकेएस ग्राहक संख्या दर्ज करें। आपका ग्राहक संख्या आईपीकेएस डेटाबेस में आपका विवरण खोजने के लिए उपयोग किया जाता है।",
"search": "खोज",
"details_verification_message": "कृपया अपना विवरण सत्यापित करें।",
"customer_no": "ग्राहक संख्या",
"name": "नाम",
"email": "ईमेल",
"pacs_name": "पैक्स का नाम",
"not_you_prompt": "तुम नहीं?",
"next": "अगला",
"otp_verification_message": "एक ओटीपी संदेश आपके पंजीकृत मोबाइल नंबर {masked_phone_number} पर भेजा गया है। इसे नीचे दिए गए बॉक्स में दर्ज करके अपने फोन नंबर को सत्यापित करें।",
"@otp_verification_message": {
"placeholders": {
"masked_phone_number": {
"type": "String"
}
}
},
"otp": "ओटीपी",
"resend_otp_prompt": "ओटीपी पुनः भेजें?",
"new_credentials_message": "कृपया एमएपी के लिए अपना नया उपयोगकर्ता नाम और पासवर्ड बनाएं",
"repeat_password": "पासवर्ड दोहराएं",
"registration_success_display": "रजिस्ट्रेशन सफलता",
"goto_login_prompt": "लॉगिन पेज पर जाएं",
"marital_status": "वैवाहिक स्थिति",
"gender": "लिंग",
"address": "पता",
"or": "या",
"district": "जिला",
"state": "राज्य",
"city": "शहर",
"pin_code": "पिन कोड",
"linked_sb_no": "लिंक्ड एसबी खाता नंबर",
"farmer_type": "किसान प्रकार",
"guardian_name": "संरक्षक का नाम",
"religion": "धर्म",
"caste": "जाति",
"not_available": "उपलब्ध नहीं है",
"no_accounts_found": "कोई खाते नहीं मिला",
"account_holder": "खाता धारक",
"customer_name": "ग्राहक का नाम",
"sanction_amount": "स्वीकृत राशि",
"sanction_date": "स्वीकृति तिथि",
"disbursed_amount": "वितरित राशि",
"interest_outstanding": "बकाया ब्याज",
"principal_outstanding": "मुख्य बकाया",
"interest_paid": "ब्याज दिया",
"principal_paid": "मुख्य दिया",
"emi_amount": "ईएमआई राशि",
"due_date": "निर्धारित तिथि",
"last_repayment_date": "अंतिम प्रतिपूर्ति तिथि",
"interest_description": "ब्याज विवरण",
"total_interest_outstanding": "कुल बकाया ब्याज",
"total_interest_accrued": "कुल ब्याज बनाया गया",
"total_interest_paid": "कुल ब्याज दिया",
"loan_type": "ऋण प्रकार",
"old_account_number": "पुराना खाता नंबर",
"penal_interest_rate": "जुर्माना ब्याज दर",
"cbs_account_number": "सीबीएस खाता नंबर",
"nominee_name": "नामांकित नाम",
"open_date": "खोलने की तारीख",
"interest_available": "ब्याज उपलब्ध",
"interest_from_date": "ब्याज तिथि से",
"interest_to_date": "ब्याज तारीख तक",
"term_value": "मुद्रा मूल्य",
"maturity_value": "परिपक्ष्य मूल्य",
"maturity_date": "परिपक्ष्य तिथि",
"term_start_date": "अवधि प्रारंभ तिथि",
"term_end_date": "अवधि समाप्ति तिथि",
"interest_projected": "ब्याज परियोजित",
"interest_capitalized": "ब्याज पुँजीबद्ध",
"no_of_installments_paid": "भुगतान की गई किस्तों की संख्या",
"next_due_date": "अगली निर्धारित तिथि",
"rd_penal_count": "आरडी जुर्माना गणना",
"hold_value": "होल्ड मूल्य",
"term_length": "अवधि लंबाई",
"interest_repayment_method": "ब्याज प्रतिपूर्ति विधि",
"mode_of_account": "खाते का मोड",
"secondary_cif_number": "द्वितीय सीआईएफ नंबर",
"secondary_cif_name": "द्वितीय सीआईएफ नाम",
"no_statements_found": "कोई बयान नहीं मिला",
"date_range_exceeds_10_days": "10 दिनों से अधिक अवधि का चयन नहीं करें",
"last_10_transactions": "अंतिम 10 लेनदेन दिखा रहा है",
"select_account_type": "खाता प्रकार चुनें",
"select_account_number": "खाता संख्या चुनें",
"select_date_range": "तिथि सीमा चुनें",
"please_wait": "कृपया प्रतीक्षा करें...",
"preferences": "प्राथमिकताएँ",
"everforest": "एवरफॉरेस्ट",
"rosy": "रोसी",
"skypeia": "स्काइपिया",
"marigold": "मैरीगोल्ड",
"select_language": "भाषा चुनें",
"english": "अंग्रेज़ी",
"hindi": "हिंदी",
"bengali": "बंगाली",
"malayalam": "मलयालम",
"dark_theme": "डार्क थीम",
"color_theme": "रंग थीम",
"language": "भाषा",
"deposit": "जमा",
"loan": "ऋण",
"export": "निर्यात",
"invalid_credentials": "अमान्य प्रमाण पत्र",
"logout": "लॉगआउट",
"backend_ip": "बैकएंड आईपी",
"bank_branch_no": "बैंक शाखा संख्या",
"ifsc_code": "आईएफएससी कोड",
"bank_branch_name": "बैंक शाखा का नाम",
"search_customer_paragraph": "कृपया अपना आईपीकेएस ग्राहक नंबर दर्ज करें। आपका ग्राहक नंबर आईपीकेएस डेटाबेस में आपके विवरण खोजने के लिए उपयोग किया जाता है",
"invalid_customer_no": "अमान्य ग्राहक संख्या",
"searching": "खोज रहे हैं",
"invalid_otp": "अमान्य ओटीपी",
"register_customer_message": "कृपया एमऐप के लिए अपना नया उपयोगकर्ता नाम और पासवर्ड दर्ज करें",
"username_criteria": "6 अक्षर, केवल अक्षर और अंक",
"password_criteria": "एक अपरकेस, एक लोअरकेस, एक अंक (8 अक्षर)",
"passowrd_mismatch_msg": "पासवर्ड मेल नहीं खाते",
"password_confirm": "पासवर्ड की पुष्टि करें",
"registration_successful": "पंजीकरण सफल",
"registration_successful_message": "कृपया अपने नए प्रमाण पत्रों से लॉगिन करें",
"goto_login": "लॉगिन पेज पर जाएं",
"socket_exception": "कृपया अपना इंटरनेट कनेक्शन जांचें",
"mpin_setup": "4-अंकों का एम-पिन सेट करें",
"mpin_confirm": "अपने एम-पिन की पुष्टि करें",
"storage_permission_denied": "स्टोरेज अनुमति अस्वीकृत",
"forgot_password": "पासवर्ड भूल गए",
"forgot_password_search_user": "अपना सीआईएफ नंबर दर्ज करें",
"forgot_password_success": "रीसेट सफल",
"forgot_password_create": "अपना नया पासवर्ड दर्ज करें",
"new_password": "नया पासवर्ड",
"security": "सुरक्षा",
"verify_mpin": "अपना एम-पिन सत्यापित करें"
}

174
lib/l10n/app_ml.arb Normal file
View File

@ -0,0 +1,174 @@
{
"@@locale": "ml",
"app_title": "ഐപികെഎസ് ആപ്പ്",
"ipks": "ഐപികെഎസ്",
"fingerprint_reason": "ആപ്പ് ആരംഭിക്കുകയാണ് പ്രമാണിക്കുക",
"@fingerprint_reason": {},
"m_pin_entry_prompt": "നിങ്ങളുടെ എം പിൻ നൽകുക",
"register_prompt": "രജിസ്റ്റർ ചെയ്യുക?",
"try_another_way": "മറ്റൊരു വഴി പരീക്ഷിക്കുക",
"username": "ഉപയോക്തൃനാമം",
"password": "പാസ്‌വേഡ്",
"login": "ലോഗിൻ",
"register": "രജിസ്റ്റർ",
"mobile_number": "മൊബൈൽ നമ്പർ",
"aadhaar_number": "ആധാർ നമ്പർ",
"date_of_birth": "ജനന തീയതി",
"pacs_id": "പക്സ് ഐഡി",
"view_full_kyc": "പൂർണ്ണമായി KYC കാണുക",
"account_summary": "അക്കൗണ്ട് സംഗ്രഹം",
"account_statement": "അക്കൗണ്ട് സ്റ്റേറ്റ്മെന്റ്",
"customer_details": "ഗ്രാഹക വിവരങ്ങൾ",
"home": "ഹോം",
"details": "വിശദങ്ങൾ",
"statement": "സ്റ്റേറ്റ്മെന്റ്",
"no_of_active_accounts": "സജീവ അക്കൗണ്ടുകൾക്കായി നിലവിലെ അക്കൗണ്ടുകൾ",
"pan_number": "പാൻ നമ്പർ",
"mirror_acct_no": "മിറർ അക്കൗണ്ട് നമ്പർ",
"cif": "സിഐഎഫ്",
"product_name": "ഉൽപ്പന്നത്തിന്റെ പേര്",
"acct_opening_dt": "അക്കൗണ്ട് തുറക്കിയ തീയതി",
"account_status": "അക്കൗണ്ട് സ്റ്റാറ്റസ്",
"available_bal": "ലഭ്യമായ ബാലൻസ്",
"interest_rate": "ബായാജ് വരുമാനം",
"acct_type": "അക്കൗണ്ട് തരം",
"acct_no": "അക്കൗണ്ട് നമ്പർ",
"date_range": "തീയതി ശ്രേണി",
"amount_range": "രൂപ ശ്രേണി",
"save": "സേവ്",
"min": "അതിന്റെ",
"max": "പരമാവധി",
"min_amt": "അതിന്റെ തിരഞ്ഞെടുക്കണം",
"max_amt": "പരമാവധി തിരഞ്ഞെടുക്കണം",
"customer_no_search_message": "ദയവായി നിങ്ങളുടെ ഐപികെഎസ് ഗ്രാഹക നമ്പർ നൽകുക. ആപ്പ് ഡാറ്റാബേസിൽ നിങ്ങളുടെ വിവരങ്ങൾ തിരയുന്നതിനായി നിങ്ങളുടെ ഗ്രാഹക നമ്പർ ഉപയോഗിക്കുന്നു.",
"search": "തിരയുക",
"details_verification_message": "ദയവായി നിങ്ങളുടെ വിശദങ്ങൾ പരിശോധിക്കുക.",
"customer_no": "ഗ്രാഹക നമ്പർ",
"name": "പേര്",
"email": "ഇമെയിൽ",
"pacs_name": "പക്സ് പേര്",
"not_you_prompt": "നിന്ന് അല്ല?",
"next": "അടുത്തത്",
"otp_verification_message": "ഒരു OTP സന്ദേശം നിങ്ങളുടെ രജിസ്റ്റർ ചെയ്യപ്പെട്ട മൊബൈൽ നമ്പറിലേക്ക് {masked_phone_number} അയച്ചിരിക്കുന്നു. നിങ്ങൾക്ക് ഫോൺ നമ്പറിനെ പരിശോധിക്കാൻ അതിനു താഴെ നൽകുന്ന ബോക്സിൽ അതിൽ നൽകുക.",
"@otp_verification_message": {
"placeholders": {
"masked_phone_number": {
"type": "String"
}
}
},
"otp": "ഓടിപി",
"resend_otp_prompt": "OTP പുനഃക്രമീകരിക്കുക?",
"new_credentials_message": "ഐപികെഎസ് ആപ്പിനായി നിങ്ങളുടെ പുതിയ ഉപയോക്തൃനാമം മറികടക്കുക",
"repeat_password": "പാസ്വേഡ് പുനരാക്ഷരിക്കുക",
"registration_success_display": "രജിസ്ട്രേഷൻ വിജയം",
"goto_login_prompt": "ലോഗിൻ പേജിലേക്ക് പോകുക",
"marital_status": "വിവാഹിത സ്ഥിതി",
"gender": "ലിംഗം",
"address": "വിലാസം",
"or": "അഥവാ",
"district": "ജില്ല",
"state": "സംസ്ഥാനം",
"city": "നഗരം",
"pin_code": "പിൻ കോഡ്",
"linked_sb_no": "ലിങ്ക്ഡ് എസ്‌ബി അക്കൗണ്ട് നമ്പർ",
"farmer_type": "കൃഷിക്കാർ തരം",
"guardian_name": "ഗാർഡിയൻ പേര്",
"religion": "മതം",
"caste": "ജാതി",
"not_available": "ലഭ്യമല്ല",
"no_accounts_found": "അക്കൗണ്ടുകൾ കണ്ടെത്തിയില്ല",
"account_holder": "അക്കൗണ്ട് ഹോൾഡർ",
"customer_name": "ഗ്രാഹകനാമം",
"sanction_amount": "അനുവദിച്ച തുക",
"sanction_date": "അനുവദിച്ച തീയതി",
"disbursed_amount": "പിന്നീട് പിഴച്ച തുക",
"interest_outstanding": "ബായാജ് അടുപ്പുകൾ",
"principal_outstanding": "പ്രധാന അടുപ്പ്",
"interest_paid": "ബായാജ് ചെലവ്",
"principal_paid": "പ്രധാന ചെലവ്",
"emi_amount": "EMI തുക",
"due_date": "നിർബന്ധമായ തീയതി",
"last_repayment_date": "അവസാന തുക തീയതി",
"interest_description": "ബായാജ് വിവരണം",
"total_interest_outstanding": "മൊത്ത ബായാജ് അടുപ്പുകൾ",
"total_interest_accrued": "മൊത്ത ബായാജ് അക്ക്രൂട്ട്",
"total_interest_paid": "മൊത്ത ബായാജ് ചെലവ്",
"loan_type": "വായ്പ തരം",
"old_account_number": "പഴയ അക്കൗണ്ട് നമ്പർ",
"penal_interest_rate": "ശിക്ഷാ ബായാജ് വരുമാനം",
"cbs_account_number": "സിബിഎസ് അക്കൗണ്ട് നമ്പർ",
"nominee_name": "നോമിനീ പേര്",
"open_date": "തുറന്ന തീയതി",
"interest_available": "ബായാജ് ലഭ്യമാണ്",
"interest_from_date": "ബായാജ് തീയതി മുതൽ",
"interest_to_date": "ബായാജ് തീയതി വരെ",
"term_value": "അവധി മൂല്യം",
"maturity_value": "പരിപാലന മൂല്യം",
"maturity_date": "പരിപാലന തീയതി",
"term_start_date": "അവധി തുടക്കം തീയതി",
"term_end_date": "അവധി അവസാനം തീയതി",
"interest_projected": "ബായാജ് പ്രൊജക്ടുചെയ്യൽ",
"interest_capitalized": "ബായാജ് ക്യാപിറ്റലൈസ്ഡ്",
"no_of_installments_paid": "പിന്നീട് നടത്തിയ കിസ്തുകൾക്കായി നിരക്കുകൾ",
"next_due_date": "അടുത്ത നിർബന്ധ തീയതി",
"rd_penal_count": "ആർഡി പെനല്‍ എണ്ണം",
"hold_value": "ഹോൾഡ് മൂല്യം",
"term_length": "അവധി നീളം",
"interest_repayment_method": "ബായാജ് തിരിച്ചറിയൽ രീതി",
"mode_of_account": "അക്കൗണ്ട് മോഡ്",
"secondary_cif_number": "സെക്കന്ററി സിഐഎഫ് നമ്പർ",
"secondary_cif_name": "സെക്കന്ററി സിഐഎഫ് പേര്",
"no_statements_found": "സ്റ്റേറ്റ്മെന്റുകൾ കണ്ടെത്തിയില്ല",
"date_range_exceeds_10_days": "10 ദിവസങ്ങൾക്ക് അധികം തീയതി ശ്രേണി തിരഞ്ഞെടുക്കരുത്",
"last_10_transactions": "അവസാന 10 ലിങ്കുകൾ പ്രദർശിപ്പിക്കുന്നു",
"select_account_type": "അക്കൗണ്ട് തരം തിരഞ്ഞെടുക്കുക",
"select_account_number": "അക്കൗണ്ട് നമ്പർ തിരഞ്ഞെടുക്കുക",
"select_date_range": "തീയതി ശ്രേണി തിരഞ്ഞെടുക്കുക",
"please_wait": "ദയവായി കാത്തിരിക്കുക...",
"preferences": "മൊത്തത്തിന്റെ അഭിരുചികൾ",
"everforest": "എവർഫോറസ്റ്റ്",
"rosy": "റോസി",
"skypeia": "സ്കൈപ്പിയ",
"marigold": "മാരിഗോൾഡ്",
"select_language": "ഭാഷ തിരഞ്ഞെടുക്കുക",
"english": "ഇംഗ്ലീഷ്",
"hindi": "ഹിന്ദി",
"bengali": "ബംഗാളി",
"malayalam": "മലയാളം",
"dark_theme": "കറുത്ത തീം",
"color_theme": "നിറ തീം",
"language": "ഭാഷ",
"deposit": "ഡപ്പോസിറ്റ്",
"loan": "വായ്പ",
"export": "കയറ്റുമതി ചെയ്യുക",
"invalid_credentials": "അസാധുവായ ക്രെഡൻഷ്യലുകൾ",
"logout": "ലോഗ്ഔട്ട്",
"backend_ip": "ബാക്ക്എൻഡ് ഐപി",
"bank_branch_no": "ബാങ്ക് ശാഖ നമ്പർ",
"ifsc_code": "ഐഎഫ്എസ്സി കോഡ്",
"bank_branch_name": "ബാങ്ക് ശാഖയുടെ പേര്",
"search_customer_paragraph": "ദയവായി നിങ്ങളുടെ ഐപികെഎസ് ഉപഭോക്താവ് നമ്പർ നൽകുക. ഐപികെഎസ് ഡാറ്റാബേസിൽ നിങ്ങളുടെ വിശദാംശങ്ങൾ തിരയാൻ ഉപഭോക്താവ് നമ്പർ ഉപയോഗിക്കുന്നു",
"invalid_customer_no": "അസാധുവായ ഉപഭോക്താവ് നമ്പർ",
"searching": "തിരയുന്നു",
"invalid_otp": "അസാധുവായ ഒറ്റത്തവണ പാസ്‌വേഡ്",
"register_customer_message": "ദയവായി mApp-നായി നിങ്ങളുടെ പുതിയ ഉപയോക്തൃനാമവും പാസ്‌വേഡും നൽകുക",
"username_criteria": "6 അക്ഷരങ്ങൾ, അക്ഷരങ്ങളും അക്കങ്ങളും മാത്രം",
"password_criteria": "ഒരു അപ്പർകേസ്, ഒരു ലോവർകേസ്, ഒരു നമ്പർ (8 അക്ഷരങ്ങൾ)",
"passowrd_mismatch_msg": "പാസ്‌വേഡുകൾ പൊരുത്തപ്പെടുന്നില്ല",
"password_confirm": "പാസ്‌വേഡ് സ്ഥിരീകരിക്കുക",
"registration_successful": "രജിസ്ട്രേഷൻ വിജയകരമായി",
"registration_successful_message": "ദയവായി നിങ്ങളുടെ പുതിയ ക്രെഡൻഷ്യലുകൾ ഉപയോഗിച്ച് ലോഗിൻ ചെയ്യുക",
"goto_login": "ലോഗിൻ പേജിലേക്ക് പോകുക",
"socket_exception": "ദയവായി നിങ്ങളുടെ ഇന്റർനെറ്റ് കണക്ഷൻ പരിശോധിക്കുക",
"mpin_setup": "4-അക്ക എംപിൻ സജ്ജമാക്കുക",
"mpin_confirm": "നിങ്ങളുടെ എംപിൻ സ്ഥിരീകരിക്കുക",
"storage_permission_denied": "സ്റ്റോറേജ് അനുമതി നിഷേധിച്ചു",
"forgot_password": "പാസ്‌വേഡ് മറന്നോ",
"forgot_password_search_user": "നിങ്ങളുടെ സിഐഎഫ് നമ്പർ നൽകുക",
"forgot_password_success": "പുനഃസജ്ജീകരണം വിജയകരമായി",
"forgot_password_create": "നിങ്ങളുടെ പുതിയ പാസ്‌വേഡ് നൽകുക",
"new_password": "പുതിയ പാസ്‌വേഡ്",
"security": "സുരക്ഷ",
"verify_mpin": "നിങ്ങളുടെ എംപിൻ പരിശോധിക്കുക"
}

View File

@ -1,5 +1,7 @@
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter/services.dart'; import 'package:flutter/services.dart';
import 'package:kmobile/src/preferences/preferences_provider.dart';
import 'package:provider/provider.dart';
import 'di/injection.dart'; import 'di/injection.dart';
import 'app.dart'; import 'app.dart';
@ -15,5 +17,7 @@ void main() async {
// Initialize dependencies // Initialize dependencies
await setupDependencies(); await setupDependencies();
runApp(const KMobile()); runApp(MultiProvider(providers: [
ChangeNotifierProvider(create: (_) => PreferencesProvider()),
], child: const KMobile()));
} }

View File

@ -0,0 +1,70 @@
import 'package:flutter/material.dart';
import 'package:material_symbols_icons/symbols.dart';
import 'package:kmobile/utils/theme/color/color_scheme.dart';
import 'package:flutter_gen/gen_l10n/app_localizations.dart';
class ColorDialog extends StatelessWidget {
const ColorDialog({super.key});
@override
Widget build(BuildContext context) {
return SimpleDialog(
title: const Text('Select Theme'),
children: <Widget>[
SimpleDialogOption(
onPressed: () {
Navigator.pop(context, KMobileColorScheme.everforest);
},
child: ListTile(
leading: const Icon(
Symbols.circle,
color: Colors.greenAccent,
fill: 1.0,
),
title: Text(AppLocalizations.of(context)!.everforest),
),
),
SimpleDialogOption(
onPressed: () {
Navigator.pop(context, KMobileColorScheme.rosy);
},
child: ListTile(
leading: const Icon(
Symbols.circle,
color: Colors.pinkAccent,
fill: 1.0,
),
title: Text(AppLocalizations.of(context)!.rosy),
),
),
SimpleDialogOption(
onPressed: () {
Navigator.pop(context, KMobileColorScheme.skypeia);
},
child: ListTile(
leading: const Icon(
Symbols.circle,
color: Colors.lightBlueAccent,
fill: 1.0,
),
title: Text(AppLocalizations.of(context)!.skypeia),
),
),
SimpleDialogOption(
onPressed: () {
Navigator.pop(context, KMobileColorScheme.marigold);
},
child: ListTile(
leading: const Icon(
Symbols.circle,
color: Colors.amberAccent,
fill: 1.0,
),
title: Text(AppLocalizations.of(context)!.marigold),
),
),
// const Divider(height: 0),
],
);
}
}

View File

@ -0,0 +1,31 @@
import 'package:flutter/material.dart';
import 'package:flutter_gen/gen_l10n/app_localizations.dart';
class LanguageDialog extends StatelessWidget {
const LanguageDialog({super.key});
String getLocaleName(BuildContext context, String code) {
Map<String, String> localeCodeMap = {
'en': AppLocalizations.of(context)!.english,
'bn': AppLocalizations.of(context)!.bengali,
'ml': AppLocalizations.of(context)!.malayalam,
'hi': AppLocalizations.of(context)!.hindi,
};
return localeCodeMap[code] ?? 'Unknown';
}
@override
Widget build(BuildContext context) {
return SimpleDialog(
title: Text(AppLocalizations.of(context)!.select_language),
children: AppLocalizations.supportedLocales.map(
(locale) {
return SimpleDialogOption(
onPressed: () => Navigator.pop(context, locale),
child: ListTile(title: Text(getLocaleName(context, locale.languageCode))),
);
},
).toList(),
);
}
}

View File

@ -0,0 +1,73 @@
import 'package:flutter/material.dart';
import 'package:provider/provider.dart';
import 'package:kmobile/src/preferences/color_dialog.dart';
import 'package:kmobile/src/preferences/language_dialog.dart';
import 'package:kmobile/src/preferences/preferences_provider.dart';
import 'package:flutter_gen/gen_l10n/app_localizations.dart';
class Preference extends StatelessWidget {
const Preference({super.key});
@override
Widget build(BuildContext context) {
PreferencesProvider preferencesProvider =
Provider.of<PreferencesProvider>(context);
return Scaffold(
backgroundColor: Theme.of(context).colorScheme.background,
appBar: AppBar(
title: Text(AppLocalizations.of(context)!.preferences),
),
body: ListView(
children: [
ListTile(
title: Text(AppLocalizations.of(context)!.dark_theme),
trailing: Switch(
value: preferencesProvider.themeMode == ThemeMode.dark,
onChanged: (value) {
preferencesProvider.themeMode =
value ? ThemeMode.dark : ThemeMode.light;
}),
),
const Divider(height: 0),
ListTile(
title: Text(AppLocalizations.of(context)!.color_theme),
onTap: () => _changeCurrentTheme(context),
),
const Divider(height: 0),
ListTile(
title: Text(AppLocalizations.of(context)!.language),
onTap: () => _changeCurrentLocale(context),
)
],
),
);
}
Future<void> _changeCurrentTheme(BuildContext context) async {
Map<ThemeMode, ColorScheme> selectedColorScheme = await showDialog(
context: context,
builder: (BuildContext context) {
return const ColorDialog();
},
);
if (context.mounted) {
PreferencesProvider provider =
Provider.of<PreferencesProvider>(context, listen: false);
provider.colorScheme = selectedColorScheme;
}
}
Future<void> _changeCurrentLocale(BuildContext context) async {
Locale selectedLocale = await showDialog(
context: context,
builder: (BuildContext context) {
return const LanguageDialog();
},
);
if (context.mounted) {
PreferencesProvider provider =
Provider.of<PreferencesProvider>(context, listen: false);
provider.locale = selectedLocale;
}
}
}

View File

@ -0,0 +1,25 @@
import 'package:flutter/material.dart';
import 'package:kmobile/utils/theme/color/color_scheme.dart';
class PreferencesProvider with ChangeNotifier {
ThemeMode _themeMode = ThemeMode.light;
ThemeMode get themeMode => _themeMode;
set themeMode(ThemeMode currentMode) {
_themeMode = currentMode;
notifyListeners();
}
Map<ThemeMode, ColorScheme> _colorScheme = KMobileColorScheme.everforest;
Map<ThemeMode, ColorScheme> get colorScheme => _colorScheme;
set colorScheme(Map<ThemeMode, ColorScheme> currentColorScheme) {
_colorScheme = currentColorScheme;
notifyListeners();
}
Locale _locale = const Locale.fromSubtags(languageCode: 'en');
Locale get locale => _locale;
set locale(Locale currentLocale) {
_locale = currentLocale;
notifyListeners();
}
}

View File

@ -0,0 +1,67 @@
import 'package:flutter/material.dart';
class KMobileColorScheme {
KMobileColorScheme._();
static Map<ThemeMode, ColorScheme> everforest = {
ThemeMode.light: ColorScheme.fromSeed(
seedColor: const Color(0xFF008442),
brightness: Brightness.light,
primary: const Color(0xff2C6A45),
onPrimary: const Color(0xffffffff),
primaryContainer: const Color(0xffB0F1C3),
onPrimaryContainer: const Color(0xFF00210F),
secondary: const Color(0xFF4F6354),
onSecondary: const Color(0xFFFFFFFF),
error: const Color(0xFFBA1A1A),
onError: const Color(0xFFFFFFFF),
background: const Color(0xFFF6FBF3),
onBackground: const Color(0xFF181D19),
surface: const Color(0xFFF6FBF3),
onSurface: const Color(0xFF181D19),
),
ThemeMode.dark: ColorScheme.fromSeed(
seedColor: const Color(0xFF008442),
brightness: Brightness.dark,
primary: const Color(0xff95D5A8),
onPrimary: const Color(0xff00391E),
primaryContainer: const Color(0xff0E512F),
onPrimaryContainer: const Color(0xFFB0F1C3),
secondary: const Color(0xFFB6CCB9),
onSecondary: const Color(0xFF213527),
error: const Color(0xFFFFB4AB),
onError: const Color(0xFF690005),
background: const Color(0xFF0F1511),
onBackground: const Color(0xFFDFE4DD),
surface: const Color(0xFF0F1511),
onSurface: const Color(0xFFDFE4DD),
),
};
static Map<ThemeMode, ColorScheme> rosy = {
ThemeMode.light: ColorScheme.fromSeed(
seedColor: const Color.fromARGB(255, 132, 0, 66),
),
ThemeMode.dark: ColorScheme.fromSeed(
seedColor: const Color.fromARGB(255, 132, 0, 66),
brightness: Brightness.dark),
};
static Map<ThemeMode, ColorScheme> skypeia = {
ThemeMode.light: ColorScheme.fromSeed(
seedColor: const Color.fromARGB(255, 0, 62, 132),
),
ThemeMode.dark: ColorScheme.fromSeed(
seedColor: const Color.fromARGB(255, 0, 62, 132),
brightness: Brightness.dark),
};
static Map<ThemeMode, ColorScheme> marigold = {
ThemeMode.light: ColorScheme.fromSeed(
seedColor: const Color.fromARGB(255, 123, 132, 0),
),
ThemeMode.dark: ColorScheme.fromSeed(
seedColor: const Color.fromARGB(255, 123, 132, 0),
brightness: Brightness.dark),
};
}

View File

@ -1,6 +1,14 @@
# Generated by pub # Generated by pub
# See https://dart.dev/tools/pub/glossary#lockfile # See https://dart.dev/tools/pub/glossary#lockfile
packages: packages:
args:
dependency: transitive
description:
name: args
sha256: d0481093c50b1da8910eb0bb301626d4d8eb7284aa739614d2b394ee09e3ea04
url: "https://pub.dev"
source: hosted
version: "2.7.0"
async: async:
dependency: transitive dependency: transitive
description: description:
@ -25,6 +33,14 @@ packages:
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "2.1.2" version: "2.1.2"
chalkdart:
dependency: transitive
description:
name: chalkdart
sha256: "7ffc6bd39c81453fb9ba8dbce042a9c960219b75ea1c07196a7fa41c2fab9e86"
url: "https://pub.dev"
source: hosted
version: "3.0.5"
characters: characters:
dependency: transitive dependency: transitive
description: description:
@ -97,6 +113,14 @@ packages:
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "2.1.4" version: "2.1.4"
file:
dependency: transitive
description:
name: file
sha256: a3b4f84adafef897088c160faf7dfffb7696046cb13ae90b508c2cbc95d3b8d4
url: "https://pub.dev"
source: hosted
version: "7.0.1"
flutter: flutter:
dependency: "direct main" dependency: "direct main"
description: flutter description: flutter
@ -106,10 +130,10 @@ packages:
dependency: "direct main" dependency: "direct main"
description: description:
name: flutter_bloc name: flutter_bloc
sha256: "1046d719fbdf230330d3443187cc33cc11963d15c9089f6cc56faa42a4c5f0cc" sha256: cf51747952201a455a1c840f8171d273be009b932c75093020f9af64f2123e38
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "9.1.0" version: "9.1.1"
flutter_lints: flutter_lints:
dependency: "direct dev" dependency: "direct dev"
description: description:
@ -118,6 +142,19 @@ packages:
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "3.0.2" version: "3.0.2"
flutter_localizations:
dependency: "direct main"
description: flutter
source: sdk
version: "0.0.0"
flutter_plugin_android_lifecycle:
dependency: transitive
description:
name: flutter_plugin_android_lifecycle
sha256: f948e346c12f8d5480d2825e03de228d0eb8c3a737e4cdaa122267b89c022b5e
url: "https://pub.dev"
source: hosted
version: "2.0.28"
flutter_secure_storage: flutter_secure_storage:
dependency: "direct main" dependency: "direct main"
description: description:
@ -130,10 +167,10 @@ packages:
dependency: transitive dependency: transitive
description: description:
name: flutter_secure_storage_linux name: flutter_secure_storage_linux
sha256: bf7404619d7ab5c0a1151d7c4e802edad8f33535abfbeff2f9e1fe1274e2d705 sha256: be76c1d24a97d0b98f8b54bce6b481a380a6590df992d0098f868ad54dc8f688
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "1.2.2" version: "1.2.3"
flutter_secure_storage_macos: flutter_secure_storage_macos:
dependency: transitive dependency: transitive
description: description:
@ -166,6 +203,22 @@ packages:
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "3.1.2" version: "3.1.2"
flutter_svg:
dependency: "direct main"
description:
name: flutter_svg
sha256: d44bf546b13025ec7353091516f6881f1d4c633993cb109c3916c3a0159dadf1
url: "https://pub.dev"
source: hosted
version: "2.1.0"
flutter_swipe_button:
dependency: "direct main"
description:
name: flutter_swipe_button
sha256: "67df9f1121ad10429b900a723366403441634ebb2c064fd4babb7de274366a36"
url: "https://pub.dev"
source: hosted
version: "2.1.3"
flutter_test: flutter_test:
dependency: "direct dev" dependency: "direct dev"
description: flutter description: flutter
@ -184,6 +237,22 @@ packages:
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "8.0.3" version: "8.0.3"
glob:
dependency: transitive
description:
name: glob
sha256: c3f1ee72c96f8f78935e18aa8cecced9ab132419e8625dc187e1c2408efc20de
url: "https://pub.dev"
source: hosted
version: "2.1.3"
http:
dependency: transitive
description:
name: http
sha256: "2c11f3f94c687ee9bad77c171151672986360b2b001d109814ee7140b2cf261b"
url: "https://pub.dev"
source: hosted
version: "1.4.0"
http_parser: http_parser:
dependency: transitive dependency: transitive
description: description:
@ -196,10 +265,10 @@ packages:
dependency: "direct main" dependency: "direct main"
description: description:
name: intl name: intl
sha256: "3df61194eb431efc39c4ceba583b95633a403f46c9fd341e550ce0bfa50e9aa5" sha256: d6f56758b7d3014a48af9701c085700aac781a92a87a62b1333b46d8879661cf
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "0.20.2" version: "0.19.0"
js: js:
dependency: transitive dependency: transitive
description: description:
@ -240,6 +309,46 @@ packages:
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "3.0.0" version: "3.0.0"
local_auth:
dependency: "direct main"
description:
name: local_auth
sha256: "434d854cf478f17f12ab29a76a02b3067f86a63a6d6c4eb8fbfdcfe4879c1b7b"
url: "https://pub.dev"
source: hosted
version: "2.3.0"
local_auth_android:
dependency: transitive
description:
name: local_auth_android
sha256: "63ad7ca6396290626dc0cb34725a939e4cfe965d80d36112f08d49cf13a8136e"
url: "https://pub.dev"
source: hosted
version: "1.0.49"
local_auth_darwin:
dependency: transitive
description:
name: local_auth_darwin
sha256: "630996cd7b7f28f5ab92432c4b35d055dd03a747bc319e5ffbb3c4806a3e50d2"
url: "https://pub.dev"
source: hosted
version: "1.4.3"
local_auth_platform_interface:
dependency: transitive
description:
name: local_auth_platform_interface
sha256: "1b842ff177a7068442eae093b64abe3592f816afd2a533c0ebcdbe40f9d2075a"
url: "https://pub.dev"
source: hosted
version: "1.0.10"
local_auth_windows:
dependency: transitive
description:
name: local_auth_windows
sha256: bc4e66a29b0fdf751aafbec923b5bed7ad6ed3614875d8151afe2578520b2ab5
url: "https://pub.dev"
source: hosted
version: "1.0.11"
matcher: matcher:
dependency: transitive dependency: transitive
description: description:
@ -256,6 +365,14 @@ packages:
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "0.11.1" version: "0.11.1"
material_symbols_icons:
dependency: "direct main"
description:
name: material_symbols_icons
sha256: "7c50901b39d1ad645ee25d920aed008061e1fd541a897b4ebf2c01d966dbf16b"
url: "https://pub.dev"
source: hosted
version: "4.2815.1"
meta: meta:
dependency: transitive dependency: transitive
description: description:
@ -280,8 +397,16 @@ packages:
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "1.9.1" version: "1.9.1"
path_provider: path_parsing:
dependency: transitive dependency: transitive
description:
name: path_parsing
sha256: "883402936929eac138ee0a45da5b0f2c80f89913e6dc3bf77eb65b84b409c6ca"
url: "https://pub.dev"
source: hosted
version: "1.1.0"
path_provider:
dependency: "direct main"
description: description:
name: path_provider name: path_provider
sha256: "50c5dd5b6e1aaf6fb3a78b33f6aa3afca52bf903a8a5298f53101fdaee55bbcd" sha256: "50c5dd5b6e1aaf6fb3a78b33f6aa3afca52bf903a8a5298f53101fdaee55bbcd"
@ -292,10 +417,10 @@ packages:
dependency: transitive dependency: transitive
description: description:
name: path_provider_android name: path_provider_android
sha256: "0ca7359dad67fd7063cb2892ab0c0737b2daafd807cf1acecd62374c8fae6c12" sha256: d0d310befe2c8ab9e7f393288ccbb11b60c019c6b5afc21973eeee4dda2b35e9
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "2.2.16" version: "2.2.17"
path_provider_foundation: path_provider_foundation:
dependency: transitive dependency: transitive
description: description:
@ -328,6 +453,14 @@ packages:
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "2.3.0" version: "2.3.0"
petitparser:
dependency: transitive
description:
name: petitparser
sha256: "07c8f0b1913bcde1ff0d26e57ace2f3012ccbf2b204e070290dad3bb22797646"
url: "https://pub.dev"
source: hosted
version: "6.1.0"
platform: platform:
dependency: transitive dependency: transitive
description: description:
@ -345,18 +478,90 @@ packages:
source: hosted source: hosted
version: "2.1.8" version: "2.1.8"
provider: provider:
dependency: transitive dependency: "direct main"
description: description:
name: provider name: provider
sha256: "489024f942069c2920c844ee18bb3d467c69e48955a4f32d1677f71be103e310" sha256: "4abbd070a04e9ddc287673bf5a030c7ca8b685ff70218720abab8b092f53dd84"
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "6.1.4" version: "6.1.5"
screenshot:
dependency: "direct main"
description:
name: screenshot
sha256: "63817697a7835e6ce82add4228e15d233b74d42975c143ad8cfe07009fab866b"
url: "https://pub.dev"
source: hosted
version: "3.0.0"
shared_preferences:
dependency: "direct main"
description:
name: shared_preferences
sha256: "6e8bf70b7fef813df4e9a36f658ac46d107db4b4cfe1048b477d4e453a8159f5"
url: "https://pub.dev"
source: hosted
version: "2.5.3"
shared_preferences_android:
dependency: transitive
description:
name: shared_preferences_android
sha256: "20cbd561f743a342c76c151d6ddb93a9ce6005751e7aa458baad3858bfbfb6ac"
url: "https://pub.dev"
source: hosted
version: "2.4.10"
shared_preferences_foundation:
dependency: transitive
description:
name: shared_preferences_foundation
sha256: "6a52cfcdaeac77cad8c97b539ff688ccfc458c007b4db12be584fbe5c0e49e03"
url: "https://pub.dev"
source: hosted
version: "2.5.4"
shared_preferences_linux:
dependency: transitive
description:
name: shared_preferences_linux
sha256: "580abfd40f415611503cae30adf626e6656dfb2f0cee8f465ece7b6defb40f2f"
url: "https://pub.dev"
source: hosted
version: "2.4.1"
shared_preferences_platform_interface:
dependency: transitive
description:
name: shared_preferences_platform_interface
sha256: "57cbf196c486bc2cf1f02b85784932c6094376284b3ad5779d1b1c6c6a816b80"
url: "https://pub.dev"
source: hosted
version: "2.4.1"
shared_preferences_web:
dependency: transitive
description:
name: shared_preferences_web
sha256: c49bd060261c9a3f0ff445892695d6212ff603ef3115edbb448509d407600019
url: "https://pub.dev"
source: hosted
version: "2.4.3"
shared_preferences_windows:
dependency: transitive
description:
name: shared_preferences_windows
sha256: "94ef0f72b2d71bc3e700e025db3710911bd51a71cefb65cc609dd0d9a982e3c1"
url: "https://pub.dev"
source: hosted
version: "2.4.1"
sky_engine: sky_engine:
dependency: transitive dependency: transitive
description: flutter description: flutter
source: sdk source: sdk
version: "0.0.0" version: "0.0.0"
social_share:
dependency: "direct main"
description:
name: social_share
sha256: eb19a0f6f5a29c7bb71e5bb1991145eb52472184363b6e2da70695befd8be041
url: "https://pub.dev"
source: hosted
version: "2.3.1"
source_span: source_span:
dependency: transitive dependency: transitive
description: description:
@ -413,6 +618,94 @@ packages:
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "1.4.0" version: "1.4.0"
url_launcher:
dependency: "direct main"
description:
name: url_launcher
sha256: "9d06212b1362abc2f0f0d78e6f09f726608c74e3b9462e8368bb03314aa8d603"
url: "https://pub.dev"
source: hosted
version: "6.3.1"
url_launcher_android:
dependency: transitive
description:
name: url_launcher_android
sha256: "8582d7f6fe14d2652b4c45c9b6c14c0b678c2af2d083a11b604caeba51930d79"
url: "https://pub.dev"
source: hosted
version: "6.3.16"
url_launcher_ios:
dependency: transitive
description:
name: url_launcher_ios
sha256: "7f2022359d4c099eea7df3fdf739f7d3d3b9faf3166fb1dd390775176e0b76cb"
url: "https://pub.dev"
source: hosted
version: "6.3.3"
url_launcher_linux:
dependency: transitive
description:
name: url_launcher_linux
sha256: "4e9ba368772369e3e08f231d2301b4ef72b9ff87c31192ef471b380ef29a4935"
url: "https://pub.dev"
source: hosted
version: "3.2.1"
url_launcher_macos:
dependency: transitive
description:
name: url_launcher_macos
sha256: "17ba2000b847f334f16626a574c702b196723af2a289e7a93ffcb79acff855c2"
url: "https://pub.dev"
source: hosted
version: "3.2.2"
url_launcher_platform_interface:
dependency: transitive
description:
name: url_launcher_platform_interface
sha256: "552f8a1e663569be95a8190206a38187b531910283c3e982193e4f2733f01029"
url: "https://pub.dev"
source: hosted
version: "2.3.2"
url_launcher_web:
dependency: transitive
description:
name: url_launcher_web
sha256: "4bd2b7b4dc4d4d0b94e5babfffbca8eac1a126c7f3d6ecbc1a11013faa3abba2"
url: "https://pub.dev"
source: hosted
version: "2.4.1"
url_launcher_windows:
dependency: transitive
description:
name: url_launcher_windows
sha256: "3284b6d2ac454cf34f114e1d3319866fdd1e19cdc329999057e44ffe936cfa77"
url: "https://pub.dev"
source: hosted
version: "3.1.4"
vector_graphics:
dependency: transitive
description:
name: vector_graphics
sha256: "44cc7104ff32563122a929e4620cf3efd584194eec6d1d913eb5ba593dbcf6de"
url: "https://pub.dev"
source: hosted
version: "1.1.18"
vector_graphics_codec:
dependency: transitive
description:
name: vector_graphics_codec
sha256: "99fd9fbd34d9f9a32efd7b6a6aae14125d8237b10403b422a6a6dfeac2806146"
url: "https://pub.dev"
source: hosted
version: "1.1.13"
vector_graphics_compiler:
dependency: transitive
description:
name: vector_graphics_compiler
sha256: "557a315b7d2a6dbb0aaaff84d857967ce6bdc96a63dc6ee2a57ce5a6ee5d3331"
url: "https://pub.dev"
source: hosted
version: "1.1.17"
vector_math: vector_math:
dependency: transitive dependency: transitive
description: description:
@ -441,10 +734,10 @@ packages:
dependency: transitive dependency: transitive
description: description:
name: win32 name: win32
sha256: dc6ecaa00a7c708e5b4d10ee7bec8c270e9276dfcab1783f57e9962d7884305f sha256: "329edf97fdd893e0f1e3b9e88d6a0e627128cc17cc316a8d67fda8f1451178ba"
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "5.12.0" version: "5.13.0"
xdg_directories: xdg_directories:
dependency: transitive dependency: transitive
description: description:
@ -453,6 +746,14 @@ packages:
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "1.1.0" version: "1.1.0"
xml:
dependency: transitive
description:
name: xml
sha256: b015a8ad1c488f66851d762d3090a21c600e479dc75e68328c52774040cf9226
url: "https://pub.dev"
source: hosted
version: "6.5.0"
sdks: sdks:
dart: ">=3.7.0 <4.0.0" dart: ">=3.7.0 <4.0.0"
flutter: ">=3.27.0" flutter: ">=3.27.0"

View File

@ -41,7 +41,21 @@ dependencies:
bloc: ^9.0.0 bloc: ^9.0.0
flutter_bloc: ^9.1.0 flutter_bloc: ^9.1.0
get_it: ^8.0.3 get_it: ^8.0.3
flutter_localizations:
sdk: flutter
intl: any intl: any
flutter_svg: ^2.1.0
local_auth: ^2.3.0
material_symbols_icons: ^4.2815.0
shared_preferences: ^2.5.3
url_launcher: ^6.3.1
social_share: ^2.3.1
screenshot: ^3.0.0
path_provider: ^2.1.5
flutter_swipe_button: ^2.1.3
provider: ^6.1.5
dev_dependencies: dev_dependencies:
flutter_test: flutter_test:
@ -64,11 +78,12 @@ flutter:
# included with your application, so that you can use the icons in # included with your application, so that you can use the icons in
# the material Icons class. # the material Icons class.
uses-material-design: true uses-material-design: true
generate: true
# To add assets to your application, add an assets section, like this: # To add assets to your application, add an assets section, like this:
# assets: assets:
# - images/a_dot_burr.jpeg - assets/images/kccb_logo.svg
# - images/a_dot_ham.jpeg - assets/images/avatar.jpg
# An image asset can refer to one or more resolution-specific "variants", see # An image asset can refer to one or more resolution-specific "variants", see
# https://flutter.dev/assets-and-images/#resolution-aware # https://flutter.dev/assets-and-images/#resolution-aware
@ -81,11 +96,12 @@ flutter:
# "family" key with the font family name, and a "fonts" key with a # "family" key with the font family name, and a "fonts" key with a
# list giving the asset and other descriptors for the font. For # list giving the asset and other descriptors for the font. For
# example: # example:
# fonts: fonts:
# - family: Schyler - family: Rubik
# fonts: fonts:
# - asset: fonts/Schyler-Regular.ttf - asset: assets/fonts/Rubik-Regular.ttf
# - asset: fonts/Schyler-Italic.ttf - asset: assets/fonts/Rubik-Bold.ttf
weight: 700
# style: italic # style: italic
# - family: Trajan Pro # - family: Trajan Pro
# fonts: # fonts: