diff --git a/devtools_options.yaml b/devtools_options.yaml new file mode 100644 index 0000000..fa0b357 --- /dev/null +++ b/devtools_options.yaml @@ -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: diff --git a/lib/app.dart b/lib/app.dart index 0aabad1..4921487 100644 --- a/lib/app.dart +++ b/lib/app.dart @@ -2,12 +2,8 @@ import 'package:flutter/material.dart'; import 'package:flutter/services.dart'; import 'package:flutter_bloc/flutter_bloc.dart'; import 'package:kmobile/features/customer_info/screens/customer_info_screen.dart'; -import 'package:kmobile/security/secure_storage.dart'; -import 'package:kmobile/src/preferences/preferences_cubit.dart'; -import 'api/services/auth_service.dart'; import 'config/themes.dart'; import 'config/routes.dart'; -import 'data/repositories/auth_repository.dart'; import 'di/injection.dart'; import 'features/auth/controllers/auth_cubit.dart'; import 'features/auth/controllers/auth_state.dart'; @@ -36,8 +32,6 @@ class KMobile extends StatelessWidget { create: (_) => getIt(), ), // Add other Bloc/Cubit providers here - BlocProvider( - create: (_) => PreferencesCubit()), ], child: MaterialApp( title: 'Banking App', diff --git a/lib/features/accounts/screens/account_statement_screen.dart b/lib/features/accounts/screens/account_statement_screen.dart index d2b1be0..04cfa9e 100644 --- a/lib/features/accounts/screens/account_statement_screen.dart +++ b/lib/features/accounts/screens/account_statement_screen.dart @@ -9,8 +9,9 @@ class AccountStatementScreen extends StatefulWidget { } class _AccountStatementScreen extends State{ - DateTimeRange? selectedDateRange; - final _amountRangeController = TextEditingController(text: "100-500"); + 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"}, @@ -21,20 +22,32 @@ class _AccountStatementScreen extends State{ {"desc": "Transfer From ICICI Bank subsidy", "amount": "+₹100.00", "type": "Cr", "time": "21-02-2024 13:09:30"}, ]; - Future _selectDateRange(BuildContext context) async { - final DateTime now = DateTime.now(); + void _selectDate({required bool isFromDate}) async { + final DateTime initial = isFromDate ? fromDate ?? DateTime.now() : toDate ?? fromDate ?? DateTime.now(); - final DateTimeRange? picked = await showDateRangePicker( + final DateTime? picked = await showDatePicker( context: context, + initialDate: initial, firstDate: DateTime(2023), - lastDate: now, // disables future dates - initialDateRange: selectedDateRange ?? - DateTimeRange(start: now.subtract(const Duration(days: 7)), end: now), + lastDate: DateTime(2030), ); if (picked != null) { setState(() { - selectedDateRange = picked; + 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; + } + } }); } } @@ -82,11 +95,13 @@ class _AccountStatementScreen extends State{ const SizedBox(height: 15,), Row( children: [ - Expanded(child: _buildDateRangeSelector()), + Expanded(child: _buildFromDateSelector()), const SizedBox(width: 10), - Expanded(child: _buildFilterBox("100-500")), + Expanded(child: _buildToDateSelector()), ], ), + const SizedBox(height: 20), + _buildFilterBox(""), const SizedBox(height: 35), Expanded( child: ListView.builder( @@ -104,16 +119,9 @@ class _AccountStatementScreen extends State{ ); } - Widget _buildDateRangeSelector() { - String label = "Select Date"; - if (selectedDateRange != null) { - final from = _formatDate(selectedDateRange!.start); - final to = _formatDate(selectedDateRange!.end); - label = "$from - $to"; - } - + Widget _buildFromDateSelector() { return GestureDetector( - onTap: () => _selectDateRange(context), + onTap: () => _selectDate(isFromDate: true), child: Container( padding: const EdgeInsets.symmetric(horizontal: 12, vertical: 14), decoration: BoxDecoration( @@ -122,8 +130,37 @@ class _AccountStatementScreen extends State{ ), child: Row( children: [ - Expanded(child: Text(label, style: const TextStyle(fontSize: 16))), - const Icon(Icons.calendar_today), + 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), ], ), ), diff --git a/lib/features/quick_pay/screens/quick_pay_outside_bank_screen.dart b/lib/features/quick_pay/screens/quick_pay_outside_bank_screen.dart index 82cb132..f129c8a 100644 --- a/lib/features/quick_pay/screens/quick_pay_outside_bank_screen.dart +++ b/lib/features/quick_pay/screens/quick_pay_outside_bank_screen.dart @@ -1,4 +1,5 @@ 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 { @@ -300,16 +301,20 @@ class _QuickPayOutsideBankScreen extends State { const SizedBox(height: 45), Align( alignment: Alignment.center, - child: SizedBox( - width: 250, - child: ElevatedButton( - style: ElevatedButton.styleFrom( - shape: const StadiumBorder(), - padding: const EdgeInsets.symmetric(vertical: 16), - backgroundColor: Colors.blue[900], - foregroundColor: Colors.white, + child: SwipeButton.expand( + thumb: const Icon( + Icons.arrow_forward, + color: Colors.white, ), - onPressed: () { + 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]; @@ -318,9 +323,8 @@ class _QuickPayOutsideBankScreen extends State { ); } }, - child: const Text('Pay'), - ), - ), + ) + ), ], ), diff --git a/lib/features/quick_pay/screens/quick_pay_within_bank_screen.dart b/lib/features/quick_pay/screens/quick_pay_within_bank_screen.dart index f5d267e..44ea63c 100644 --- a/lib/features/quick_pay/screens/quick_pay_within_bank_screen.dart +++ b/lib/features/quick_pay/screens/quick_pay_within_bank_screen.dart @@ -1,4 +1,5 @@ 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 { @@ -149,27 +150,28 @@ class _QuickPayWithinBankScreen extends State { const SizedBox(height: 45), Align( alignment: Alignment.center, - child: SizedBox( - width: 250, - height: 50, - child: ElevatedButton( - style: ElevatedButton.styleFrom( - shape: const StadiumBorder(), - padding: const EdgeInsets.symmetric(vertical: 16), - backgroundColor: Colors.blue[900], - foregroundColor: Colors.white, - ), - onPressed: () { - if (_formKey.currentState!.validate()) { - // Perform payment logic - ScaffoldMessenger.of(context).showSnackBar( - const SnackBar( - content: Text('Processing Payment...')), - ); - } - }, - child: const Text('Pay'), + 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...')), + ); + } + }, ), ), ], diff --git a/lib/main.dart b/lib/main.dart index 9ba4cd8..d553635 100644 --- a/lib/main.dart +++ b/lib/main.dart @@ -1,5 +1,7 @@ import 'package:flutter/material.dart'; import 'package:flutter/services.dart'; +import 'package:kmobile/src/preferences/preferences_provider.dart'; +import 'package:provider/provider.dart'; import 'di/injection.dart'; import 'app.dart'; @@ -15,5 +17,7 @@ void main() async { // Initialize dependencies await setupDependencies(); - runApp(const KMobile()); + runApp(MultiProvider(providers: [ + ChangeNotifierProvider(create: (_) => PreferencesProvider()), + ], child: const KMobile())); } diff --git a/lib/src/preferences/preference.dart b/lib/src/preferences/preference.dart index 95b5ab8..eafb364 100644 --- a/lib/src/preferences/preference.dart +++ b/lib/src/preferences/preference.dart @@ -1,72 +1,73 @@ import 'package:flutter/material.dart'; -import 'package:flutter_bloc/flutter_bloc.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'; -import 'package:kmobile/src/preferences/preferences_cubit.dart'; -import 'package:kmobile/src/preferences/preferences_state.dart'; class Preference extends StatelessWidget { const Preference({super.key}); @override Widget build(BuildContext context) { - return BlocBuilder( - builder: (context, state) { - return Scaffold( - backgroundColor: Theme.of(context).colorScheme.background, - appBar: AppBar( - title: Text(AppLocalizations.of(context)!.preferences), + PreferencesProvider preferencesProvider = + Provider.of(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; + }), ), - body: ListView( - children: [ - ListTile( - title: Text(AppLocalizations.of(context)!.dark_theme), - trailing: Switch( - value: state.themeMode == ThemeMode.dark, - onChanged: (value) { - context.read().setThemeMode( - 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), - ), - ], + 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 _changeCurrentTheme(BuildContext context) async { - final selectedColorScheme = await showDialog>( + Map selectedColorScheme = await showDialog( context: context, - builder: (context) => const ColorDialog(), + builder: (BuildContext context) { + return const ColorDialog(); + }, ); - - if (context.mounted && selectedColorScheme != null) { - context.read().setColorScheme(selectedColorScheme); + if (context.mounted) { + PreferencesProvider provider = + Provider.of(context, listen: false); + provider.colorScheme = selectedColorScheme; } } Future _changeCurrentLocale(BuildContext context) async { - final selectedLocale = await showDialog( + Locale selectedLocale = await showDialog( context: context, - builder: (context) => const LanguageDialog(), + builder: (BuildContext context) { + return const LanguageDialog(); + }, ); - - if (context.mounted && selectedLocale != null) { - context.read().setLocale(selectedLocale); + if (context.mounted) { + PreferencesProvider provider = + Provider.of(context, listen: false); + provider.locale = selectedLocale; } } } diff --git a/lib/src/preferences/preferences_cubit.dart b/lib/src/preferences/preferences_cubit.dart deleted file mode 100644 index df5fb3c..0000000 --- a/lib/src/preferences/preferences_cubit.dart +++ /dev/null @@ -1,25 +0,0 @@ -import 'package:flutter/material.dart'; -import 'package:flutter_bloc/flutter_bloc.dart'; -import 'preferences_state.dart'; -import 'package:kmobile/utils/theme/color/color_scheme.dart'; - -class PreferencesCubit extends Cubit { - PreferencesCubit() - : super(PreferencesState( - themeMode: ThemeMode.light, - colorScheme: KMobileColorScheme.everforest, - locale: const Locale.fromSubtags(languageCode: 'en'), - )); - - void setThemeMode(ThemeMode mode) { - emit(state.copyWith(themeMode: mode)); - } - - void setColorScheme(Map colorScheme) { - emit(state.copyWith(colorScheme: colorScheme)); - } - - void setLocale(Locale locale) { - emit(state.copyWith(locale: locale)); - } -} diff --git a/lib/src/preferences/preferences_provider.dart b/lib/src/preferences/preferences_provider.dart new file mode 100644 index 0000000..4ca611e --- /dev/null +++ b/lib/src/preferences/preferences_provider.dart @@ -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 _colorScheme = KMobileColorScheme.everforest; + Map get colorScheme => _colorScheme; + set colorScheme(Map currentColorScheme) { + _colorScheme = currentColorScheme; + notifyListeners(); + } + + Locale _locale = const Locale.fromSubtags(languageCode: 'en'); + Locale get locale => _locale; + set locale(Locale currentLocale) { + _locale = currentLocale; + notifyListeners(); + } +} diff --git a/lib/src/preferences/preferences_state.dart b/lib/src/preferences/preferences_state.dart deleted file mode 100644 index e74698a..0000000 --- a/lib/src/preferences/preferences_state.dart +++ /dev/null @@ -1,25 +0,0 @@ -import 'package:flutter/material.dart'; - -class PreferencesState { - final ThemeMode themeMode; - final Map colorScheme; - final Locale locale; - - PreferencesState({ - required this.themeMode, - required this.colorScheme, - required this.locale, - }); - - PreferencesState copyWith({ - ThemeMode? themeMode, - Map? colorScheme, - Locale? locale, - }) { - return PreferencesState( - themeMode: themeMode ?? this.themeMode, - colorScheme: colorScheme ?? this.colorScheme, - locale: locale ?? this.locale, - ); - } -} diff --git a/pubspec.lock b/pubspec.lock index b694848..c639059 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -211,6 +211,14 @@ packages: 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: dependency: "direct dev" description: flutter @@ -470,7 +478,7 @@ packages: source: hosted version: "2.1.8" provider: - dependency: transitive + dependency: "direct main" description: name: provider sha256: "4abbd070a04e9ddc287673bf5a030c7ca8b685ff70218720abab8b092f53dd84" diff --git a/pubspec.yaml b/pubspec.yaml index 082392e..838fb81 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -52,6 +52,8 @@ dependencies: social_share: ^2.3.1 screenshot: ^3.0.0 path_provider: ^2.1.5 + flutter_swipe_button: ^2.1.3 + provider: ^6.1.5