diff --git a/.github/workflows/android-release.yml b/.github/workflows/android-release.yml new file mode 100644 index 0000000..7fad732 --- /dev/null +++ b/.github/workflows/android-release.yml @@ -0,0 +1,106 @@ +name: Android App Release for development branch + +on: + push: + branches: + - development + +jobs: + version: + name: Create version number # using GitVersion + runs-on: ubuntu-latest #macos-latest + steps: + - uses: actions/checkout@v3 + - name: Fetch all history for all tags and branches + run: git fetch --prune --depth=10000 + - name: Install GitVersion + uses: gittools/actions/gitversion/setup@v0.9.15 + with: + versionSpec: '5.x' + - name: Use GitVersion + id: gitversion + uses: gittools/actions/gitversion/execute@v0.9.15 + - name: Create android-version.txt with nuGetVersion + run: echo ${{ steps.gitversion.outputs.nuGetVersion }} > android-version.txt + - name: Upload android-version.txt + uses: actions/upload-artifact@v3 + with: + name: gitversion + path: android-version.txt + build: + name: Build Appbundle and Apks + needs: [ version ] + runs-on: ubuntu-latest #macos-latest + steps: + - uses: actions/checkout@v3 + - uses: actions/setup-java@v3 + with: + java-version: '12.x' + distribution: 'zulu' + cache: 'gradle' + - uses: subosito/flutter-action@v2 + with: + flutter-version: '3.3.7' + cache: true + channel: 'stable' + - run: flutter upgrade + - run: flutter --version + - name: Get DEV_GOOGLE_SERVICES_JSON content write it into app/src/development/google-services.json + env: + DEV_GOOGLE_SERVICES_JSON: ${{ secrets.DEV_GOOGLE_SERVICES_JSON }} + run: echo "$DEV_GOOGLE_SERVICES_JSON" > android/app/src/development/google-services.json + - run: flutter pub get + # - run: flutter test + - run: flutter build apk --profile --flavor development --target lib/main_development.dart + # - run: flutter build appbundle + - name: upload app builds files + uses: actions/upload-artifact@v3 + with: + name: flutter-app-builds + path: | + build/app/outputs/flutter-apk/app-development-profile.apk + github-deploy: + name: Deploy Build to Github + needs: [ build, version ] + runs-on: ubuntu-latest #macos-latest + steps: + - name: Get android-version.txt + uses: actions/download-artifact@v3 + with: + name: gitversion + - name: Read version + id: version + uses: juliangruber/read-file-action@v1 + with: + path: android-version.txt + - name: Get app builds + uses: actions/download-artifact@v3 + with: + name: flutter-app-builds + - name: Echo android-version.txt + run: echo "${{ steps.version.outputs.content }}" + - name: Display structure of downloaded files + run: ls -R + - name: Create a Release in GitHub + uses: ncipollo/release-action@v1 + with: + artifacts: "flutter-apk/app-development-profile.apk" + token: ${{ secrets.GH_TOKEN }} + tag: ${{ steps.version.outputs.content }} + commit: ${{ github.sha }} + firebase-deploy: + name: Deploy Build to Firebase App Distribution + needs: [ build ] + runs-on: ubuntu-latest #macos-latest + steps: + - name: Get app builds + uses: actions/download-artifact@v3 + with: + name: flutter-app-builds + - name: upload artifact to Firebase App Distribution + uses: wzieba/Firebase-Distribution-Github-Action@v1 + with: + appId: ${{secrets.FIREBASE_ANDROID_APP_ID}} + serviceCredentialsFileContent: ${{ secrets.CREDENTIAL_FILE_CONTENT }} + groups: testers + file: flutter-apk/app-development-profile.apk \ No newline at end of file diff --git a/android/build.gradle b/android/build.gradle index 0a1af40..916d8cc 100644 --- a/android/build.gradle +++ b/android/build.gradle @@ -1,5 +1,5 @@ buildscript { - ext.kotlin_version = '1.6.10' + ext.kotlin_version = '1.6.10'//1.8.10 -> 1.8.10 because of release build failures repositories { google() mavenCentral() diff --git a/assets/fpb-assets/active_checkbox.svg b/assets/fpb-assets/active_checkbox.svg new file mode 100644 index 0000000..3963a5b --- /dev/null +++ b/assets/fpb-assets/active_checkbox.svg @@ -0,0 +1,3 @@ + + + diff --git a/assets/fpb-assets/apple_pay.svg b/assets/fpb-assets/apple_pay.svg new file mode 100644 index 0000000..6d477d8 --- /dev/null +++ b/assets/fpb-assets/apple_pay.svg @@ -0,0 +1,3 @@ + + + diff --git a/assets/fpb-assets/bank.svg b/assets/fpb-assets/bank.svg new file mode 100644 index 0000000..fc74e59 --- /dev/null +++ b/assets/fpb-assets/bank.svg @@ -0,0 +1,9 @@ + + + + + + + + + diff --git a/assets/fpb-assets/bank_account.svg b/assets/fpb-assets/bank_account.svg new file mode 100644 index 0000000..ad991e4 --- /dev/null +++ b/assets/fpb-assets/bank_account.svg @@ -0,0 +1,9 @@ + + + + + + + + + diff --git a/assets/fpb-assets/google_pay.svg b/assets/fpb-assets/google_pay.svg new file mode 100644 index 0000000..867164c --- /dev/null +++ b/assets/fpb-assets/google_pay.svg @@ -0,0 +1,9 @@ + + + + + + + + + diff --git a/assets/fpb-assets/paypal.svg b/assets/fpb-assets/paypal.svg new file mode 100644 index 0000000..22036bc --- /dev/null +++ b/assets/fpb-assets/paypal.svg @@ -0,0 +1,11 @@ + + + + + + + + + + + diff --git a/assets/fpb-assets/uncheck_tick.svg b/assets/fpb-assets/uncheck_tick.svg new file mode 100644 index 0000000..e9bf411 --- /dev/null +++ b/assets/fpb-assets/uncheck_tick.svg @@ -0,0 +1,4 @@ + + + + diff --git a/assets/fpb-assets/white_tick_check.svg b/assets/fpb-assets/white_tick_check.svg new file mode 100644 index 0000000..07cdc0f --- /dev/null +++ b/assets/fpb-assets/white_tick_check.svg @@ -0,0 +1,3 @@ + + + diff --git a/lib/assets/fpb_svg.dart b/lib/assets/fpb_svg.dart index f6ba322..1a7369d 100644 --- a/lib/assets/fpb_svg.dart +++ b/lib/assets/fpb_svg.dart @@ -15,6 +15,14 @@ class SvgNames { static String facebook = '${path}facebook.svg'; static String twitter = '${path}twitter.svg'; static String error = '${path}Cross.svg'; + static String paypal = '${path}paypal.svg'; + static String googlePay = '${path}google_pay.svg'; + static String applePay = '${path}apple_pay.svg'; + static String bank = '${path}bank_account.svg'; + static String whiteTickCheckbox = '${path}white_tick_check.svg'; + static String activeCheckbox = '${path}active_checkbox.svg'; + static String inactiveCheckbox = '${path}uncheck_tick.svg'; + static String timeCircle = '${path}time_circle.svg'; static String wallet = '${path}wallet.svg'; } diff --git a/lib/contact_us/view/contact_us_screen.dart b/lib/contact_us/view/contact_us_screen.dart index 00598b5..f39a7db 100644 --- a/lib/contact_us/view/contact_us_screen.dart +++ b/lib/contact_us/view/contact_us_screen.dart @@ -147,9 +147,7 @@ class _ContactUsScreenState extends State { label: l10n.contactUsSubmitBtnLabel, onTap: () { if (_formKey.currentState!.validate()) { - context.router.push( - ContactUsSuccessRoute() - ); + context.router.push(ContactUsSuccessRoute()); } else {} }) ]), diff --git a/lib/contact_us/view/contact_us_success_screen.dart b/lib/contact_us/view/contact_us_success_screen.dart index cc94e7d..84cc6d2 100644 --- a/lib/contact_us/view/contact_us_success_screen.dart +++ b/lib/contact_us/view/contact_us_success_screen.dart @@ -7,7 +7,9 @@ import 'package:fpb/l10n/l10n.dart'; import 'package:fpb/sign_in/view/sign_in_page.dart'; class ContactUsSuccessScreen extends StatelessWidget { - const ContactUsSuccessScreen({super.key, }); + const ContactUsSuccessScreen({ + super.key, + }); @override Widget build(BuildContext context) { @@ -16,8 +18,7 @@ class ContactUsSuccessScreen extends StatelessWidget { final style = theme.textTheme; //final colors = theme.colorScheme; - return LayoutBuilder( - builder: (context, box){ + return LayoutBuilder(builder: (context, box) { return Scaffold( resizeToAvoidBottomInset: false, body: Stack(children: [ @@ -45,7 +46,6 @@ class ContactUsSuccessScreen extends StatelessWidget { bottom: box.maxHeight * .005), child: Column( crossAxisAlignment: CrossAxisAlignment.center, - children: [ SizedBox( height: box.maxHeight * .1, @@ -54,9 +54,7 @@ class ContactUsSuccessScreen extends StatelessWidget { SizedBox( height: box.maxHeight * .0001, ), - ContactUsSuccessTexts( - - l10n: l10n, style: style, box: box), + ContactUsSuccessTexts(l10n: l10n, style: style, box: box), SizedBox( height: box.maxHeight * .15, ), @@ -74,6 +72,6 @@ class ContactUsSuccessScreen extends StatelessWidget { )) ]), ); - }); + }); } } diff --git a/lib/contact_us/view/widgets/contact_us_success_texts.dart b/lib/contact_us/view/widgets/contact_us_success_texts.dart index c64935c..689a2c1 100644 --- a/lib/contact_us/view/widgets/contact_us_success_texts.dart +++ b/lib/contact_us/view/widgets/contact_us_success_texts.dart @@ -26,11 +26,8 @@ class ContactUsSuccessTexts extends StatelessWidget { SizedBox( height: box.maxHeight * .025, ), - Text( - l10n.contactUsSuccessText, - maxLines: 3, - textAlign: TextAlign.center, - style: style.titleMedium), + Text(l10n.contactUsSuccessText, + maxLines: 3, textAlign: TextAlign.center, style: style.titleMedium), ], ); } diff --git a/lib/contact_us/view/widgets/message_textfield.dart b/lib/contact_us/view/widgets/message_textfield.dart index 0ad0ea6..1cd946e 100644 --- a/lib/contact_us/view/widgets/message_textfield.dart +++ b/lib/contact_us/view/widgets/message_textfield.dart @@ -40,7 +40,8 @@ class _MessageTextFieldState extends State { }, maxLength: 500, controller: messageController, - validator: (value) => widget.validator?.call(value) != null ? "" : null, + validator: (value) => + widget.validator?.call(value) != null ? "" : null, maxLines: 3, decoration: InputDecoration( hintText: l10n.contactUsMessageTextFieldHintText, @@ -53,12 +54,13 @@ class _MessageTextFieldState extends State { ), ), ), - ).card( - padding: - EdgeInsets.symmetric(vertical: widget.box.maxHeight * .007)). - validatorWidget( - //messageController.text.isEmpty ? null : - widget.validator?.call(messageController.text)), + ) + .card( + padding: + EdgeInsets.symmetric(vertical: widget.box.maxHeight * .007)) + .validatorWidget( + //messageController.text.isEmpty ? null : + widget.validator?.call(messageController.text)), ], ); } diff --git a/lib/core/presentation/animations/circular_slider_animation/double_circular_slider.dart b/lib/core/presentation/animations/circular_slider_animation/double_circular_slider.dart index bbf6acf..6465c72 100644 --- a/lib/core/presentation/animations/circular_slider_animation/double_circular_slider.dart +++ b/lib/core/presentation/animations/circular_slider_animation/double_circular_slider.dart @@ -114,7 +114,7 @@ class _DoubleCircularSliderState extends State { width: widget.width ?? 220, child: CircularSliderPaint( mode: CircularSliderMode.doubleHandler, - init: _init, + init: _init, end: _end, divisions: widget.divisions, primarySectors: widget.primarySectors ?? 0, diff --git a/lib/core/presentation/theming/colors/colors.dart b/lib/core/presentation/theming/colors/colors.dart index 45a1582..d19a5de 100644 --- a/lib/core/presentation/theming/colors/colors.dart +++ b/lib/core/presentation/theming/colors/colors.dart @@ -1,21 +1,36 @@ part of 'package:fpb/core/presentation/theming/themes/theme.dart'; class _AppColors { - static Color primaryColorW = const Color(0xff48A2DF); + static Color primaryColorW = const Color(0xFF5db1eb); + static Color primaryColorW2 = const Color(0xFF4285F4); + static Color primaryColorW3 = const Color(0xFF5eb1eb); + static Color secondaryColorW = const Color(0xff000000); - static Color secondaryContainerW = const Color(0xffDF602F); + static Color secondaryColorW2 = const Color(0xff181818); + static Color secondaryColorW3 = const Color(0xff414141); + static Color secondaryColorW4 = const Color(0xff0B0B0B); + + static Color greyWhite = Color(0xFFF0F0F0); + static Color lightGrey = Color(0xFFABABAB); + static Color greyMedium = Color(0xFFB2B3BD); + static Color greyOutline = Color(0xFFE4E4E4); + static Color greyDark = Color(0xFF808080); + + static Color warningColor = const Color(0xffFBBC04); + + static Color successColor = const Color(0xff34A853); + static Color errorContainerW = const Color(0xffFFE5E7); - static Color onErrorW = const Color(0xffFF000D); - // static Color bgColorW = const Color(0xffF7F7F7); - static Color bgColorW = Color(0xffFFFFFF); - static Color onBgColorW = Color(0xffD9D9D9); - // static Color surfaceW = const Color(0xffF5F5F5); // ; - // static Color surfacerW = Color(0xffFFFFFF); - - static Color onSurfaceW = Color(0xfff7f7f7); // const Color(0xff808191); - static Color greyLight = Color(0xFFABABAB); + static Color onErrorW = const Color(0xffEA4335); - static Color lightGrey = Color(0xffA7A7A7); + static Color orangePrimary = const Color(0xffDF602F); + static Color orangePrimaryW2 = const Color(0xffC95528); + static Color orangePrimaryW3 = const Color(0xffEC6936); + static Color orangePrimaryW4 = const Color(0xffA34420); // has shades of dark + + static Color bgColorW = Color(0xffFFFFFF); // use for some screen as bgColor + static Color onSurfaceW = Color(0xfff7f7f7); // use for some screen as bgColor + static Color onBgColorW = Color(0xffD9D9D9); static Color getShade(Color color, {bool darker = false, double value = .1}) { assert(value >= 0 && value <= 1, 'verify domain interval'); diff --git a/lib/core/presentation/theming/themes/light_theme.dart b/lib/core/presentation/theming/themes/light_theme.dart index ba77ae2..60c78ae 100644 --- a/lib/core/presentation/theming/themes/light_theme.dart +++ b/lib/core/presentation/theming/themes/light_theme.dart @@ -20,33 +20,44 @@ ThemeData whiteTheme(BuildContext context, BoxConstraints cts) { ), ), colorScheme: ColorScheme.light( - primary: _AppColors.primaryColorW, - onPrimary: _AppColors.onSurfaceW, + primary: _AppColors.primaryColorW, // main blue color + onPrimary: _AppColors.primaryColorW2, + primaryContainer: _AppColors.primaryColorW, - onPrimaryContainer: _AppColors.onSurfaceW, - secondary: _AppColors.secondaryColorW, - onSecondary: _AppColors.primaryColorW, - secondaryContainer: _AppColors.secondaryContainerW, - tertiary: _AppColors.onSurfaceW, - onTertiary: _AppColors.onSurfaceW, // use for static code (qrCode screen) - onTertiaryContainer: Colors - .blue, // set to odd color so we can see which component in the UI is affected - inverseSurface: Colors - .green, // set to odd color so we can see which component in the UI is affected - inversePrimary: Colors - .yellow, // set to odd color so we can see which component in the UI is affected - outline: _AppColors - .lightGrey, // set to odd color so we can see which component in the UI is affected - surface: _AppColors.bgColorW, - onSurface: _AppColors.onSurfaceW, - background: _AppColors.bgColorW, - onBackground: _AppColors.onBgColorW, - error: _AppColors.primaryColorW, + onPrimaryContainer: _AppColors.primaryColorW3, + + secondary: _AppColors.secondaryColorW, // black color (Text, btn etc) + onSecondary: _AppColors.secondaryColorW2, + + secondaryContainer: _AppColors.secondaryColorW3, + onSecondaryContainer: _AppColors.secondaryColorW4, + + tertiary: _AppColors.orangePrimary, // use orange + onTertiary: _AppColors.orangePrimaryW2, // use for cards and icon - Orange + + tertiaryContainer: _AppColors.orangePrimaryW3, + onTertiaryContainer: + _AppColors.orangePrimaryW4, // use for cards and icon - OrangeDark + + inverseSurface: _AppColors.successColor, // success color + inversePrimary: _AppColors.warningColor, // warning color + + outline: + _AppColors.greyOutline, // use for input borders - container borders + outlineVariant: _AppColors.greyMedium, + onInverseSurface: _AppColors.greyDark, + + surface: _AppColors.bgColorW, // white bg + onSurface: _AppColors.onSurfaceW, // darkGrey bg + onSurfaceVariant: _AppColors.onBgColorW, + + background: _AppColors.greyWhite, // used on tabBar bgColor, some text + onBackground: _AppColors.lightGrey, + + error: _AppColors.onErrorW, // error display onError: _AppColors.onErrorW, errorContainer: _AppColors.errorContainerW, - // onError: AppColors.errorColor, - brightness: Brightness.light, ), // primarySwatch: AppColors.getPrimaryMaterialColorWhiteTheme, @@ -72,7 +83,7 @@ ThemeData whiteTheme(BuildContext context, BoxConstraints cts) { ), titleSmall: style.titleSmall?.copyWith( fontSize: cts.maxWidth * 0.04, - color: _AppColors.greyLight, + color: _AppColors.lightGrey, ), bodyLarge: style.bodyLarge?.copyWith( fontSize: cts.maxWidth * 0.042, @@ -158,7 +169,7 @@ ThemeData whiteTheme(BuildContext context, BoxConstraints cts) { .purple, // _AppColors.onSurfaceW, // theme.colorScheme.onSurface, labelStyle: style.bodySmall, unselectedLabelStyle: style.bodySmall, - unselectedLabelColor: theme.colorScheme.onSurface, + unselectedLabelColor: theme.colorScheme.background, labelColor: theme.colorScheme.onBackground, dividerColor: Colors.purple, indicator: BoxDecoration( @@ -170,7 +181,7 @@ ThemeData whiteTheme(BuildContext context, BoxConstraints cts) { ), iconTheme: IconThemeData( - color: _AppColors.greyLight, + color: _AppColors.lightGrey, size: cts.maxWidth * 0.07, ), ); diff --git a/lib/core/presentation/widget/custom_btn_outline.dart b/lib/core/presentation/widget/custom_btn_outline.dart new file mode 100644 index 0000000..910ef29 --- /dev/null +++ b/lib/core/presentation/widget/custom_btn_outline.dart @@ -0,0 +1,65 @@ +import 'package:flutter/material.dart'; + +class CustomBtnOutline extends StatelessWidget { + const CustomBtnOutline({ + super.key, + required this.style, + required this.box, + required this.backgroundColor, + required this.borderColor, + required this.text, + required this.textColor, + this.leading, + required this.onPressed, + }); + + final TextTheme style; + final BoxConstraints box; + final Color textColor; + final Color backgroundColor; + final String text; + final Color borderColor; + final Widget? leading; + final void Function() onPressed; + + @override + Widget build(BuildContext context) { + return Container( + height: box.maxHeight * .06, + width: box.maxWidth, + child: ElevatedButton( + style: ButtonStyle( + foregroundColor: MaterialStateProperty.all(textColor), + elevation: MaterialStateProperty.all(0), + textStyle: MaterialStateProperty.all(style.titleMedium), + backgroundColor: MaterialStateProperty.all( + backgroundColor, + ), + shape: MaterialStateProperty.all( + RoundedRectangleBorder( + borderRadius: BorderRadius.circular( + box.maxHeight * .015, + ), + ), + ), + side: MaterialStateProperty.all( + BorderSide( + color: borderColor, + ), + ), + ), + onPressed: onPressed, + child: Wrap( + spacing: box.maxWidth * 0.05, + alignment: WrapAlignment.spaceAround, + children: [ + leading ?? const SizedBox.shrink(), + Text( + text, + ), + ], + ), + ), + ); + } +} diff --git a/lib/core/presentation/widget/custom_dialog_widget.dart b/lib/core/presentation/widget/custom_dialog_widget.dart new file mode 100644 index 0000000..6865335 --- /dev/null +++ b/lib/core/presentation/widget/custom_dialog_widget.dart @@ -0,0 +1,67 @@ +import 'package:flutter/material.dart'; + +Future> showCustomDialog( + BuildContext context, + BoxConstraints box, + double? height, + double? width, + Widget? widget, +) async { + return showGeneralDialog( + context: context, + barrierDismissible: true, + barrierLabel: MaterialLocalizations.of(context).modalBarrierDismissLabel, + barrierColor: Color.fromARGB(199, 3, 3, 3), + transitionDuration: const Duration( + milliseconds: 200, + ), + pageBuilder: ( + BuildContext buildContext, + Animation animation, + Animation secondaryAnimation, + ) { + return CustomDialogWidget( + height: height ?? box.maxHeight * 0.5, + width: width ?? box.maxWidth * 0.4, + childWidget: widget!, + ); + }, + ); +} + +class CustomDialogWidget extends StatelessWidget { + const CustomDialogWidget({ + super.key, + required this.height, + required this.width, + required this.childWidget, + }); + + final double height; + final double width; + final Widget childWidget; + + @override + Widget build(BuildContext context) { + return Center( + child: Material( + color: Colors.transparent, + child: GestureDetector( + onTap: () => + FocusScope.of(context).unfocus(), // close keyboard on screen tap + child: Container( + width: width, + height: height, + decoration: BoxDecoration( + color: Theme.of(context).colorScheme.surface, + borderRadius: BorderRadius.circular( + 10.0, + ), + ), + child: childWidget, + ), + ), + ), + ); + } +} diff --git a/lib/core/presentation/widget/fpb_button.dart b/lib/core/presentation/widget/fpb_button.dart index 5d0b417..6e75db0 100644 --- a/lib/core/presentation/widget/fpb_button.dart +++ b/lib/core/presentation/widget/fpb_button.dart @@ -48,7 +48,6 @@ class FpbButton extends StatelessWidget { label, style: Theme.of(context).textTheme.titleMedium?.copyWith( color: textColor ?? colors.surface, - // fontWeight: FontWeight.w400, ), ), if (trailing != null) @@ -62,10 +61,10 @@ class FpbButton extends StatelessWidget { ), style: ButtonStyle( backgroundColor: - MaterialStateProperty.all(backgroundColor ?? colors.error), + MaterialStateProperty.all(backgroundColor ?? colors.primary), side: MaterialStateProperty.all( BorderSide( - color: borderSideColor ?? colors.error, + color: borderSideColor ?? colors.primary, width: 1.0, style: BorderStyle.solid), ), diff --git a/lib/core/presentation/widget/fpb_text_form_field.dart b/lib/core/presentation/widget/fpb_text_form_field.dart index cfd0983..8990c4d 100644 --- a/lib/core/presentation/widget/fpb_text_form_field.dart +++ b/lib/core/presentation/widget/fpb_text_form_field.dart @@ -3,19 +3,21 @@ import 'package:fpb/assets/fpb_icons/fpb_icons_icons.dart'; import 'package:fpb/core/presentation/extension/extensions.dart'; class FpbTextFormField extends StatefulWidget { - const FpbTextFormField( - {super.key, - required this.label, - required this.hint, - this.textController, - this.node, - this.isEmail = false, - this.isPassword = false, - this.onChanged, - this.errorText, - this.showLabelText = true, - required this.box, - this.validator}); + const FpbTextFormField({ + super.key, + required this.label, + required this.hint, + this.textController, + this.node, + this.isEmail = false, + this.isPassword = false, + this.onChanged, + this.errorText, + this.showLabelText = true, + required this.box, + this.validator, + this.keyboardType = TextInputType.text, + }); final String label; final String hint; @@ -28,6 +30,7 @@ class FpbTextFormField extends StatefulWidget { final BoxConstraints box; final bool showLabelText; final String? Function(String?)? validator; + final TextInputType? keyboardType; @override State createState() => _FpbTextFormFieldState(); @@ -59,14 +62,15 @@ class _FpbTextFormFieldState extends State { : SizedBox(), TextFormField( autovalidateMode: AutovalidateMode.always, - validator: (value) => widget.validator?.call(value) != null ? "" : null, + validator: (value) => + widget.validator?.call(value) != null ? "" : null, controller: widget.textController, focusNode: widget.node, keyboardType: widget.isEmail ? TextInputType.emailAddress : widget.isPassword ? TextInputType.visiblePassword - : TextInputType.text, + : widget.keyboardType, onChanged: widget.onChanged, obscureText: hidePassword ?? false, style: textTheme @@ -117,14 +121,13 @@ class _FpbTextFormFieldState extends State { ), ) .card( - //height: widget.box.maxHeight * 0.14, - padding: EdgeInsets.symmetric( - vertical: widget.box.maxHeight * 0.009, - )).validatorWidget( + //height: widget.box.maxHeight * 0.14, + padding: EdgeInsets.symmetric( + vertical: widget.box.maxHeight * 0.009, + )) + .validatorWidget( //widget.textController != null && widget.textController!.text.isEmpty ? null : - widget.validator?.call( - widget.textController?.text)), - + widget.validator?.call(widget.textController?.text)), ], ); } diff --git a/lib/core/presentation/widget/selected_user_item.dart b/lib/core/presentation/widget/selected_user_item.dart new file mode 100644 index 0000000..31e28b4 --- /dev/null +++ b/lib/core/presentation/widget/selected_user_item.dart @@ -0,0 +1,60 @@ +import 'package:flutter/material.dart'; + +class SelectedUserItem extends StatelessWidget { + const SelectedUserItem({ + super.key, + required this.box, + required this.userPhoto, + required this.username, + required this.onTap, + }); + + final BoxConstraints box; + final String username; + final String userPhoto; + final void Function() onTap; + + @override + Widget build(BuildContext context) { + return Container( + padding: EdgeInsets.symmetric( + vertical: box.maxWidth * 0.02, + horizontal: box.maxWidth * 0.02, + ), + decoration: BoxDecoration( + color: Theme.of(context).colorScheme.onError.withOpacity(0.1), + borderRadius: BorderRadius.circular( + box.maxHeight * 0.01, + ), + ), + child: Wrap( + spacing: 6.0, + crossAxisAlignment: WrapCrossAlignment.center, + children: [ + CircleAvatar( + backgroundImage: NetworkImage( + '${userPhoto}', + ), + radius: box.maxHeight * 0.02, + child: userPhoto == '' + ? Icon( + Icons.person, + ) + : Container(), + ), + Text( + '${username}', + style: Theme.of(context).textTheme.titleSmall, + ), + GestureDetector( + onTap: onTap, + child: Icon( + Icons.close, + size: box.maxHeight * 0.02, + ), + ) + ], + ), + ); + } +} diff --git a/lib/core/shared/helpers/extensions.dart b/lib/core/shared/helpers/extensions.dart index 40445d2..2eb02ca 100644 --- a/lib/core/shared/helpers/extensions.dart +++ b/lib/core/shared/helpers/extensions.dart @@ -15,8 +15,9 @@ extension extString on String { bool get isNotNull { // ignore: unnecessary_null_comparison return this != null; - - }} + } +} + /// Padding for screens extension PaddingX on Widget { Widget paddingDefault(BoxConstraints box) { diff --git a/lib/home/view/budget_screen.dart b/lib/home/view/budget_screen.dart index d07f490..52f7cec 100644 --- a/lib/home/view/budget_screen.dart +++ b/lib/home/view/budget_screen.dart @@ -24,17 +24,11 @@ class _BudgetScreenState extends State { final baseColor = Color.fromRGBO(223, 96, 47, 1); - late int initTime; - late int endTime; + late int initBudget; + late int endBudget; - // amount of money - // late int initTime; - // late int endTime; - - - - late int inBedTime; - late int outBedTime; + late int inFinalBudget; + late int outFinalBudget; int days = 0; @override @@ -45,19 +39,19 @@ class _BudgetScreenState extends State { void _shuffle() { setState(() { - initTime = _generateRandomTime(); - endTime = _generateRandomTime(); + initBudget = _generateRandomAmount(); + // endBudget = __generateRandomAmount(); // print({'Gen': _generateRandomTime()}); // print({'Time': _generateRandomTime()}); - inBedTime = initTime; - outBedTime = endTime; + inFinalBudget = initBudget; + outFinalBudget = endBudget; }); } void _updateLabels(int init, int end, int laps) { setState(() { - inBedTime = init; - outBedTime = end; + inFinalBudget = init; + outFinalBudget = end; days = laps; }); } @@ -151,5 +145,5 @@ class _BudgetScreenState extends State { ); } - int _generateRandomTime() => Random().nextInt(288); + int _generateRandomAmount() => Random().nextInt(288); } diff --git a/lib/home/view/user_search_screen.dart b/lib/home/view/user_search_screen.dart index 1c3d3bd..b4a8a94 100644 --- a/lib/home/view/user_search_screen.dart +++ b/lib/home/view/user_search_screen.dart @@ -1,11 +1,11 @@ import 'package:flutter/material.dart'; +import 'package:flutter/services.dart'; import 'package:flutter_bloc/flutter_bloc.dart'; import 'package:fpb/authentication_with_firebase/application/bloc/auth_bloc.dart'; import 'package:fpb/core/domain/user.dart'; import 'package:fpb/core/shared/helpers/value_injector.dart'; import 'package:fpb/home/view/widgets/custom_appbar.dart'; import 'package:fpb/home/view/widgets/row_header_icons.dart'; -import 'package:fpb/home/view/widgets/search_input.dart'; import 'package:fpb/home/view/widgets/user_search_list.dart'; class UserSearchScreen extends StatelessWidget { @@ -18,27 +18,39 @@ class UserSearchScreen extends StatelessWidget { context.read()..add(AuthEvent.logoutRequest()); } return LayoutBuilder(builder: (context, box) { - return SafeArea( - child: Scaffold( - resizeToAvoidBottomInset: false, - appBar: CustomAppBar( - titleChildWidget: CircleAvatar( - backgroundImage: NetworkImage('${user.photo}'), - ), - actionChildWidget: [ - RowHeaderIcons(), - ], - ), - body: SingleChildScrollView( - child: Column( - children: [ - SearchInputWidget( - box: box, + return AnnotatedRegion( + value: SystemUiOverlayStyle( + statusBarColor: Theme.of(context).colorScheme.surface, + statusBarIconBrightness: Brightness.dark, // dark icon for iOS + statusBarBrightness: Brightness.dark, // set dark icon for android + ), + child: SafeArea( + child: GestureDetector( + onTap: () { + // close keyboard + FocusScope.of(context).unfocus(); + }, + child: Scaffold( + resizeToAvoidBottomInset: false, + backgroundColor: Theme.of(context).colorScheme.surface, + appBar: CustomAppBar( + backgroundColor: Theme.of(context).colorScheme.surface, + titleChildWidget: CircleAvatar( + backgroundImage: NetworkImage('${user.photo}'), ), - UserSearchList( - box: box, + actionChildWidget: [ + RowHeaderIcons(), + ], + ), + body: SingleChildScrollView( + child: Column( + children: [ + UserSearchList( + box: box, + ), + ], ), - ], + ), ), ), ), diff --git a/lib/home/view/widgets/custom_appbar.dart b/lib/home/view/widgets/custom_appbar.dart index 10f3846..65ee2a1 100644 --- a/lib/home/view/widgets/custom_appbar.dart +++ b/lib/home/view/widgets/custom_appbar.dart @@ -3,7 +3,7 @@ import 'package:flutter/material.dart'; class CustomAppBar extends StatelessWidget implements PreferredSizeWidget { final double height; final Widget titleChildWidget; - final List actionChildWidget; + final List? actionChildWidget; final bool showArrow; final Color? backgroundColor; final Color? foregroundColor; @@ -11,7 +11,7 @@ class CustomAppBar extends StatelessWidget implements PreferredSizeWidget { CustomAppBar({ this.height = kToolbarHeight, required this.titleChildWidget, - required this.actionChildWidget, + this.actionChildWidget, this.showArrow = false, this.backgroundColor, this.foregroundColor, diff --git a/lib/home/view/widgets/row_header_icons.dart b/lib/home/view/widgets/row_header_icons.dart index 53c8320..881e50f 100644 --- a/lib/home/view/widgets/row_header_icons.dart +++ b/lib/home/view/widgets/row_header_icons.dart @@ -1,8 +1,6 @@ import 'package:auto_route/auto_route.dart'; import 'package:flutter/material.dart'; import 'package:fpb/assets/fpb_icons/fpb_icons_icons.dart'; -import 'package:fpb/core/presentation/animations/slide_up_route_transition.dart'; -import 'package:fpb/qr_code_screen/view/qr_code_screen.dart'; import 'package:fpb/router/app_route.gr.dart'; class RowHeaderIcons extends StatelessWidget { @@ -27,6 +25,7 @@ class RowHeaderIcons extends StatelessWidget { ? InkWell( onTap: () { print('Activity screen'); + context.pushRoute(PaymentMethodRoute()); }, child: Icon( FpbIcons.search, diff --git a/lib/home/view/widgets/search_input.dart b/lib/home/view/widgets/search_input.dart index 9202d57..4a2aa73 100644 --- a/lib/home/view/widgets/search_input.dart +++ b/lib/home/view/widgets/search_input.dart @@ -3,6 +3,7 @@ import 'package:flutter_bloc/flutter_bloc.dart'; import 'package:fpb/core/application/search_user_bloc/search_user_bloc.dart'; import 'package:fpb/core/application/search_user_bloc/search_user_state.dart'; import 'package:fpb/core/domain/user.dart'; +import 'package:fpb/core/presentation/widget/vertical_spacing_widget.dart'; import 'package:fpb/core/presentation/widget/fpb_text_form_field.dart'; class SearchInputWidget extends StatelessWidget { @@ -16,10 +17,6 @@ class SearchInputWidget extends StatelessWidget { // final l10n = context.l10n; return Container( width: box.maxWidth, - padding: EdgeInsets.symmetric( - horizontal: box.maxWidth * 0.04, - vertical: box.maxHeight * 0.01, - ), child: Column( mainAxisAlignment: MainAxisAlignment.start, crossAxisAlignment: CrossAxisAlignment.start, @@ -31,22 +28,15 @@ class SearchInputWidget extends StatelessWidget { fontWeight: FontWeight.bold, ), ), - SizedBox( - height: box.maxHeight * 0.02, - ), + VerticalSpacingWidget(box: box), Container( width: box.maxWidth, child: FpbTextFormField( - key: const Key('SearchUserForPayments'), - box: box, + onChanged: (value) {}, label: '', - hint: 'Name, email, identifier', - isEmail: false, - onChanged: (search) async { - print(search); - }, showLabelText: false, - errorText: null, + hint: 'Name, email, identifier, number', + box: box, ), ), ], diff --git a/lib/home/view/widgets/user_radio_select.dart b/lib/home/view/widgets/user_check_select.dart similarity index 71% rename from lib/home/view/widgets/user_radio_select.dart rename to lib/home/view/widgets/user_check_select.dart index 9f567ba..ad2fc0d 100644 --- a/lib/home/view/widgets/user_radio_select.dart +++ b/lib/home/view/widgets/user_check_select.dart @@ -1,12 +1,15 @@ import 'package:flutter/material.dart'; +import 'package:flutter_svg/flutter_svg.dart'; +import 'package:fpb/assets/fpb_svg.dart'; -class UserRadioSelect extends StatelessWidget { - const UserRadioSelect({ +class UserCheckSelect extends StatelessWidget { + const UserCheckSelect({ super.key, required this.box, required this.username, required this.fullName, required this.onChanged, + required this.checked, required this.userPhoto, }); @@ -14,7 +17,8 @@ class UserRadioSelect extends StatelessWidget { final String username; final String fullName; final String userPhoto; - final void Function(String?) onChanged; + final bool checked; + final void Function() onChanged; @override Widget build(BuildContext context) { @@ -66,14 +70,26 @@ class UserRadioSelect extends StatelessWidget { ), ), - // radio select button - SizedBox( - child: Radio( - value: 'dezzy', - groupValue: username, - onChanged: onChanged, + // checkbox select button + if (checked) ...[ + GestureDetector( + onTap: onChanged, + child: SizedBox( + child: SvgPicture.asset( + SvgNames.activeCheckbox, + ), + ), ), - ), + ] else ...[ + GestureDetector( + onTap: onChanged, + child: SizedBox( + child: SvgPicture.asset( + SvgNames.inactiveCheckbox, + ), + ), + ), + ] ], ), ); diff --git a/lib/home/view/widgets/user_search_list.dart b/lib/home/view/widgets/user_search_list.dart index 4efdfb0..adfe59e 100644 --- a/lib/home/view/widgets/user_search_list.dart +++ b/lib/home/view/widgets/user_search_list.dart @@ -1,16 +1,126 @@ import 'package:flutter/material.dart'; import 'package:fpb/core/presentation/widget/vertical_spacing_widget.dart'; -import 'package:fpb/home/view/widgets/user_radio_select.dart'; +import 'package:fpb/home/view/widgets/search_input.dart'; +import 'package:fpb/core/presentation/widget/selected_user_item.dart'; +import 'package:fpb/home/view/widgets/user_check_select.dart'; import 'package:flutter_bloc/flutter_bloc.dart'; import 'package:fpb/authentication_with_firebase/application/bloc/auth_bloc.dart'; import 'package:fpb/core/domain/user.dart'; import 'package:fpb/core/shared/helpers/value_injector.dart'; -class UserSearchList extends StatelessWidget { +class UserSearchList extends StatefulWidget { const UserSearchList({super.key, required this.box}); final BoxConstraints box; + @override + State createState() => _UserSearchListState(); +} + +class _UserSearchListState extends State { + // list users + List users = [ + User( + id: '1', + isNewUser: false, + photo: + 'https://expertphotography.b-cdn.net/wp-content/uploads/2020/08/profile-photos-4.jpg', + providerId: '123', + name: 'Marry smith', + email: 'mary@smith.com', + phoneNumber: '15778783', + ), + User( + id: '2', + isNewUser: false, + photo: + 'https://marketplace.canva.com/EAFEits4-uw/1/0/1600w/canva-boy-cartoon-gamer-animated-twitch-profile-photo-oEqs2yqaL8s.jpg', + providerId: '123456', + name: 'Terry Scotch', + email: 'mary@smith.com', + phoneNumber: '177778783', + ), + User( + id: '3', + isNewUser: false, + photo: + 'https://media.istockphoto.com/id/1381221247/photo/beautiful-afro-girl-with-curly-hairstyle.jpg?b=1&s=170667a&w=0&k=20&c=0x91osZOkL8EfhTEEGNa2EeCGN2gdMTNULOsUFW_0i4=', + providerId: '123456789', + name: 'Amanda', + email: 'mary@smith.com', + phoneNumber: '15778783', + ), + User( + id: '4', + isNewUser: false, + photo: + 'https://media.istockphoto.com/id/1381221247/photo/beautiful-afro-girl-with-curly-hairstyle.jpg?b=1&s=170667a&w=0&k=20&c=0x91osZOkL8EfhTEEGNa2EeCGN2gdMTNULOsUFW_0i4=', + providerId: '123456789', + name: 'Amanda', + email: 'mary@smith.com', + phoneNumber: '15778783', + ), + User( + id: '5', + isNewUser: false, + photo: + 'https://media.istockphoto.com/id/1381221247/photo/beautiful-afro-girl-with-curly-hairstyle.jpg?b=1&s=170667a&w=0&k=20&c=0x91osZOkL8EfhTEEGNa2EeCGN2gdMTNULOsUFW_0i4=', + providerId: '123456789', + name: 'Amanda', + email: 'mary@smith.com', + phoneNumber: '15778783', + ), + User( + id: '6', + isNewUser: false, + photo: + 'https://media.istockphoto.com/id/1381221247/photo/beautiful-afro-girl-with-curly-hairstyle.jpg?b=1&s=170667a&w=0&k=20&c=0x91osZOkL8EfhTEEGNa2EeCGN2gdMTNULOsUFW_0i4=', + providerId: '123456789', + name: 'Amanda', + email: 'mary@smith.com', + phoneNumber: '15778783', + ), + User( + id: '7', + isNewUser: false, + photo: + 'https://media.istockphoto.com/id/1381221247/photo/beautiful-afro-girl-with-curly-hairstyle.jpg?b=1&s=170667a&w=0&k=20&c=0x91osZOkL8EfhTEEGNa2EeCGN2gdMTNULOsUFW_0i4=', + providerId: '123456789', + name: 'Amanda', + email: 'mary@smith.com', + phoneNumber: '15778783', + ), + User( + id: '8', + isNewUser: false, + photo: + 'https://media.istockphoto.com/id/1381221247/photo/beautiful-afro-girl-with-curly-hairstyle.jpg?b=1&s=170667a&w=0&k=20&c=0x91osZOkL8EfhTEEGNa2EeCGN2gdMTNULOsUFW_0i4=', + providerId: '123456789', + name: 'Amanda', + email: 'mary@smith.com', + phoneNumber: '15778783', + ), + User( + id: '9', + isNewUser: false, + photo: + 'https://media.istockphoto.com/id/1381221247/photo/beautiful-afro-girl-with-curly-hairstyle.jpg?b=1&s=170667a&w=0&k=20&c=0x91osZOkL8EfhTEEGNa2EeCGN2gdMTNULOsUFW_0i4=', + providerId: '123456789', + name: 'Amanda', + email: 'mary@smith.com', + phoneNumber: '15778783', + ), + ]; + + // recently sent list + List recentSentUsers = []; + + // checkbox state + bool selectUser = false; + + // list of selected users + List userSelected = []; + @override Widget build(BuildContext context) { final user = ValueInjector.of(context)?.value ?? User.empty; @@ -18,157 +128,141 @@ class UserSearchList extends StatelessWidget { context.read()..add(AuthEvent.logoutRequest()); } return Container( - width: box.maxWidth, + width: widget.box.maxWidth, padding: EdgeInsets.symmetric( - horizontal: box.maxWidth * 0.025, + horizontal: widget.box.maxWidth * 0.025, ), child: Column( mainAxisAlignment: MainAxisAlignment.start, crossAxisAlignment: CrossAxisAlignment.start, children: [ + SearchInputWidget( + box: widget.box, + ), + // display list of selected users + Container( + padding: EdgeInsets.symmetric( + vertical: widget.box.maxWidth * 0.02, + ), + width: widget.box.maxWidth, + child: SingleChildScrollView( + scrollDirection: Axis.horizontal, + child: Wrap( + spacing: 5.0, + children: userSelected + .map( + (e) => SelectedUserItem( + box: widget.box, + userPhoto: e.photo, + username: e.name, + onTap: () { + userSelected.remove(e); + setState(() {}); + }, + ), + ) + .toList(), + ), + ), + ), + VerticalSpacingWidget( + box: widget.box, + height: widget.box.maxHeight * 0.02, + ), Text( 'Recently sent', style: TextStyle( - fontSize: box.maxHeight * 0.025, + fontSize: widget.box.maxHeight * 0.025, ), ), VerticalSpacingWidget( - box: box, - height: box.maxHeight * 0.01, + box: widget.box, + height: widget.box.maxHeight * 0.01, ), // display user with recent sent transactions Container( - width: box.maxWidth, - height: box.maxHeight * 0.2, + width: widget.box.maxWidth, + // height: widget.box.maxHeight * 0.2, padding: EdgeInsets.symmetric( - horizontal: box.maxWidth * 0.01, + horizontal: widget.box.maxWidth * 0.01, ), - child: SingleChildScrollView( - child: Column( - // list will be coming from an API - this is just for demo UI - children: [ - UserRadioSelect( - box: box, - fullName: 'Tambe desmond', - username: 'dezzy', - userPhoto: '${user.photo}', - onChanged: (value) { - print(value); - }, - ), - UserRadioSelect( - box: box, - fullName: 'Rudy Mendy', - username: 'rudy', - userPhoto: '${user.photo}', - onChanged: (value) { - print(value); - }, - ), - UserRadioSelect( - box: box, - fullName: 'Gaelle Tiku', - username: 'gaelle', - userPhoto: '${user.photo}', - onChanged: (value) { - print(value); - }, - ), - ], - ), + child: Column( + children: users + .map( + (e) => UserCheckSelect( + box: widget.box, + fullName: e.name, + username: e.name, + userPhoto: '${e.photo}', + checked: userSelected.contains(e) ? true : false, + onChanged: () { + // check if item adde - if yes then remove + if (userSelected.contains(e)) { + userSelected.remove(e); + setState(() { + selectUser = false; + }); + } else { + // add use to userSelected + userSelected.add(e); + setState(() { + selectUser = true; + }); + } + }, + ), + ) + .toList(), ), ), VerticalSpacingWidget( - box: box, - height: box.maxHeight * 0.015, + box: widget.box, + height: widget.box.maxHeight * 0.015, ), Text( 'Contacts', style: TextStyle( - fontSize: box.maxHeight * 0.025, + fontSize: widget.box.maxHeight * 0.025, ), ), VerticalSpacingWidget( - box: box, - height: box.maxHeight * 0.01, + box: widget.box, + height: widget.box.maxHeight * 0.01, ), // display user with recent sent transactions Container( - width: box.maxWidth, - height: box.maxHeight * 0.5, + width: widget.box.maxWidth, padding: EdgeInsets.symmetric( - horizontal: box.maxWidth * 0.01, + horizontal: widget.box.maxWidth * 0.01, ), - child: SingleChildScrollView( - child: Column( - // list will be coming from an API - this is just for demo UI - children: [ - UserRadioSelect( - box: box, - fullName: 'Loic Fonkam', - username: 'loic', - userPhoto: '', - onChanged: (value) { - print(value); - }, - ), - UserRadioSelect( - box: box, - fullName: 'Tambe desmond', - username: 'dezzy', - userPhoto: '${user.photo}', - onChanged: (value) { - print(value); - }, - ), - UserRadioSelect( - box: box, - fullName: 'Amanda', - username: 'amanda', - userPhoto: '', - onChanged: (value) { - print(value); - }, - ), - UserRadioSelect( - box: box, - fullName: 'Desking La', - username: 'desking', - userPhoto: '', - onChanged: (value) { - print(value); - }, - ), - UserRadioSelect( - box: box, - fullName: 'Desking La', - username: 'desking', - userPhoto: '', - onChanged: (value) { - print(value); - }, - ), - UserRadioSelect( - box: box, - fullName: 'Desking La', - username: 'desking', - userPhoto: '', - onChanged: (value) { - print(value); - }, - ), - UserRadioSelect( - box: box, - fullName: 'Desking La', - username: 'desking', - userPhoto: '', - onChanged: (value) { - print(value); - }, - ), - ], - ), + child: Column( + children: users + .map( + (e) => UserCheckSelect( + box: widget.box, + fullName: e.name, + username: e.name, + userPhoto: '${e.photo}', + checked: userSelected.contains(e) ? true : false, + onChanged: () { + // check if item adde - if yes then remove + if (userSelected.contains(e)) { + userSelected.remove(e); + setState(() { + selectUser = false; + }); + } else { + // add use to userSelected + userSelected.add(e); + setState(() { + selectUser = true; + }); + } + }, + ), + ) + .toList(), ), ), ], diff --git a/lib/onboarding/view/onboarding_screens.dart b/lib/onboarding/view/onboarding_screens.dart index 16b6add..012ceb2 100644 --- a/lib/onboarding/view/onboarding_screens.dart +++ b/lib/onboarding/view/onboarding_screens.dart @@ -10,6 +10,7 @@ class OnboardingScreen extends HookWidget { const OnboardingScreen({this.onGetStartedPressed, super.key}); static const routeName = '/getStarted'; final void Function()? onGetStartedPressed; + @override Widget build(BuildContext context) { final l10n = context.l10n; @@ -18,13 +19,13 @@ class OnboardingScreen extends HookWidget { final listIllustration = [ Illustration( assetName: SvgNames.sendIllustration, - illustrationBgColor: colors.primary, + illustrationBgColor: colors.onPrimaryContainer, title: l10n.onboardingSendTitle, description: l10n.onboardingSendDescription, ), Illustration( assetName: SvgNames.saveIllustration, - illustrationBgColor: colors.secondaryContainer, + illustrationBgColor: colors.tertiary, title: l10n.onboardingSaveTitle, description: l10n.onboardingSaveDescription, ), @@ -45,23 +46,15 @@ class OnboardingScreen extends HookWidget { ..currentIndex = currentIndex; return Scaffold( - body: GestureDetector( - onPanUpdate: (details) async { - // Swiping in right direction. -> Back - const sensitivity = 12; - if (details.delta.dx > sensitivity) { - if (currentIndex.value - 1 >= 0) { - currentIndex.value -= 1; - } - } - // Swiping in left direction.-> Forward - if (details.delta.dx < -sensitivity) { - if (currentIndex.value + 1 < listIllustration.length) { - currentIndex.value += 1; - } - } + body: PageView.builder( + scrollDirection: Axis.horizontal, + onPageChanged: (value) { + currentIndex.value = value; + }, + itemCount: listIllustration.length, + itemBuilder: (context, index) { + return illustration; }, - child: illustration, ), ); } diff --git a/lib/onboarding/view/widgets/actions.dart b/lib/onboarding/view/widgets/actions.dart index 428d76e..35079c5 100644 --- a/lib/onboarding/view/widgets/actions.dart +++ b/lib/onboarding/view/widgets/actions.dart @@ -22,6 +22,7 @@ class Actions extends StatelessWidget { final l10n = context.l10n; final theme = Theme.of(context); final textTheme = theme.textTheme; + final colors = theme.colorScheme; return Row( mainAxisAlignment: MainAxisAlignment.spaceEvenly, children: [ @@ -41,7 +42,13 @@ class Actions extends StatelessWidget { onTap: onNextPressed, width: isLastPage ? cts.maxWidth * 0.65 : cts.maxWidth * 0.6, height: cts.maxHeight * 0.07, - trailing: !isLastPage ? Icon(FpbIcons.arrow_right) : null, + trailing: !isLastPage + ? Icon( + FpbIcons.arrow_right, + size: cts.maxHeight * 0.02, + color: colors.background, + ) + : null, ) ], ); diff --git a/lib/onboarding/view/widgets/illustration_image.dart b/lib/onboarding/view/widgets/illustration_image.dart index 7db3d10..44661d3 100644 --- a/lib/onboarding/view/widgets/illustration_image.dart +++ b/lib/onboarding/view/widgets/illustration_image.dart @@ -22,7 +22,7 @@ class IllustrationImage extends StatelessWidget { width: cts.maxWidth, child: Container( padding: EdgeInsets.all(cts.maxWidth * 0.1), - color: color ?? Colors.black, + color: color ?? Theme.of(context).colorScheme.secondary, child: SvgPicture.asset(illustration), ), ); diff --git a/lib/onboarding/view/widgets/my_stepper.dart b/lib/onboarding/view/widgets/my_stepper.dart index 077faeb..60fdb10 100644 --- a/lib/onboarding/view/widgets/my_stepper.dart +++ b/lib/onboarding/view/widgets/my_stepper.dart @@ -19,8 +19,9 @@ class MyStepper extends StatelessWidget { return LayoutBuilder( builder: (context, cts) { return Container( - padding: const EdgeInsets.only(top: 10), + padding: const EdgeInsets.symmetric(vertical: 5), child: Row( + crossAxisAlignment: CrossAxisAlignment.start, children: [const Spacer()] + [ ...List.generate(length - 1, (_) => StepDot(cts: cts)) @@ -50,7 +51,9 @@ class StepBar extends StatelessWidget { width: cts.maxWidth * 0.08, decoration: BoxDecoration( color: Theme.of(context).colorScheme.secondary, - borderRadius: BorderRadius.all(Radius.circular(5)), + borderRadius: BorderRadius.all( + Radius.circular(5), + ), ), ), ), @@ -74,7 +77,7 @@ class StepDot extends StatelessWidget { height: cts.maxWidth * 0.027, width: cts.maxWidth * 0.027, decoration: BoxDecoration( - color: Theme.of(context).colorScheme.onSurface, + color: Theme.of(context).colorScheme.onBackground, borderRadius: const BorderRadius.all(Radius.circular(5)), ), ), diff --git a/lib/payment_methods/payment_method_screen.dart b/lib/payment_methods/payment_method_screen.dart new file mode 100644 index 0000000..f8e3e71 --- /dev/null +++ b/lib/payment_methods/payment_method_screen.dart @@ -0,0 +1 @@ +export 'view/payment_methods.dart'; diff --git a/lib/payment_methods/view/payment_methods.dart b/lib/payment_methods/view/payment_methods.dart new file mode 100644 index 0000000..34a73c2 --- /dev/null +++ b/lib/payment_methods/view/payment_methods.dart @@ -0,0 +1,49 @@ +import 'package:flutter/material.dart'; +import 'package:flutter/services.dart'; +import 'package:fpb/home/view/widgets/custom_appbar.dart'; +import 'package:fpb/payment_methods/view/widget/link_accounts.dart'; +import 'package:fpb/payment_methods/view/widget/payment_cards_widget.dart'; + +class PaymentMethodScreen extends StatelessWidget { + const PaymentMethodScreen({super.key}); + + @override + Widget build(BuildContext context) { + return AnnotatedRegion( + value: SystemUiOverlayStyle( + statusBarColor: Theme.of(context).colorScheme.surface, + statusBarIconBrightness: Brightness.dark, // dark icon for iOS + statusBarBrightness: Brightness.dark, // set dark icon for android + ), + child: LayoutBuilder( + builder: (context, box) { + return SafeArea( + child: Scaffold( + backgroundColor: Theme.of(context).colorScheme.surface, + appBar: CustomAppBar( + showArrow: true, + backgroundColor: Theme.of(context).colorScheme.surface, + titleChildWidget: Text( + 'Payment methods', + ), + ), + body: SingleChildScrollView( + child: Column( + children: [ + PaymentCardsWidget( + box: box, + ), + // link accounts + LinkAccounts( + box: box, + ), + ], + ), + ), + ), + ); + }, + ), + ); + } +} diff --git a/lib/payment_methods/view/widget/account_linked.dart b/lib/payment_methods/view/widget/account_linked.dart new file mode 100644 index 0000000..a465420 --- /dev/null +++ b/lib/payment_methods/view/widget/account_linked.dart @@ -0,0 +1,79 @@ +import 'package:flutter/material.dart'; +import 'package:flutter_svg/flutter_svg.dart'; +import 'package:fpb/assets/fpb_svg.dart'; +import 'package:fpb/core/presentation/widget/vertical_spacing_widget.dart'; + +class AccountLinked extends StatelessWidget { + const AccountLinked({ + super.key, + required this.box, + required this.assetName, + required this.onTap, + }); + + final BoxConstraints box; + final String assetName; + final dynamic Function()? onTap; + + @override + Widget build(BuildContext context) { + return Container( + width: box.maxWidth, + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + SvgPicture.asset( + SvgNames.paypal, + ), + VerticalSpacingWidget(box: box), + Container( + width: box.maxWidth, + child: Wrap( + alignment: WrapAlignment.spaceBetween, + crossAxisAlignment: WrapCrossAlignment.center, + children: [ + Container( + child: Wrap( + spacing: 5.0, + children: [ + CircleAvatar( + backgroundImage: NetworkImage( + 'https://media.istockphoto.com/id/1381221247/photo/beautiful-afro-girl-with-curly-hairstyle.jpg?b=1&s=170667a&w=0&k=20&c=0x91osZOkL8EfhTEEGNa2EeCGN2gdMTNULOsUFW_0i4=', + ), + radius: box.maxHeight * 0.026, + ), + SizedBox( + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Text( + '@john_merry', + style: Theme.of(context).textTheme.titleSmall, + ), + SizedBox( + height: box.maxHeight * 0.009, + ), + Text( + 'John Merry', + style: Theme.of(context).textTheme.labelMedium, + ), + ], + ), + ), + ], + ), + ), + GestureDetector( + onTap: onTap, + child: Icon( + Icons.delete, + ), + ), + ], + ), + ), + ], + ), + ); + } +} diff --git a/lib/payment_methods/view/widget/card_info_widget.dart b/lib/payment_methods/view/widget/card_info_widget.dart new file mode 100644 index 0000000..1f85d07 --- /dev/null +++ b/lib/payment_methods/view/widget/card_info_widget.dart @@ -0,0 +1,97 @@ +import 'package:flutter/material.dart'; +import 'package:flutter_svg/svg.dart'; +import 'package:fpb/assets/fpb_svg.dart'; + +class CardInfoWidget extends StatelessWidget { + const CardInfoWidget({ + super.key, + required this.box, + this.expiryDate, + this.cvv, + this.defaulPayment, + }); + + final BoxConstraints box; + final String? expiryDate; + final String? cvv; + final bool? defaulPayment; + + @override + Widget build(BuildContext context) { + final theme = Theme.of(context); + final colors = theme.colorScheme; + return Container( + width: box.maxWidth, + child: Wrap( + alignment: WrapAlignment.spaceBetween, + crossAxisAlignment: WrapCrossAlignment.center, + children: [ + // expiry date + SizedBox( + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Text( + 'Expriy', + style: theme.textTheme.titleSmall?.copyWith( + fontWeight: FontWeight.w400, + ), + ), + Text( + expiryDate ?? '04/2025', + style: theme.textTheme.titleSmall?.copyWith( + color: colors.surface, + ), + ), + ], + ), + ), + // CVV + SizedBox( + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Text( + 'CVV', + style: theme.textTheme.titleSmall?.copyWith( + fontWeight: FontWeight.w400, + ), + ), + Text( + cvv ?? '04/2025', + style: theme.textTheme.titleSmall?.copyWith( + color: colors.surface, + ), + ), + ], + ), + ), + // default payment method + SizedBox( + width: box.maxWidth * 0.4, + child: Wrap( + spacing: 2.0, + crossAxisAlignment: WrapCrossAlignment.start, + children: [ + SvgPicture.asset( + SvgNames.whiteTickCheckbox, + ), + SizedBox( + width: box.maxWidth * 0.3, + child: Flexible( + child: Text( + 'Default payment method', + style: theme.textTheme.titleSmall?.copyWith( + color: colors.surface, + ), + ), + ), + ), + ], + ), + ), + ], + ), + ); + } +} diff --git a/lib/payment_methods/view/widget/card_number_dot.dart b/lib/payment_methods/view/widget/card_number_dot.dart new file mode 100644 index 0000000..a7114ac --- /dev/null +++ b/lib/payment_methods/view/widget/card_number_dot.dart @@ -0,0 +1,35 @@ +import 'package:flutter/material.dart'; + +class CardNumberDot extends StatelessWidget { + const CardNumberDot({super.key}); + + @override + Widget build(BuildContext context) { + final theme = Theme.of(context); + return Wrap( + spacing: 2.0, + children: [ + Icon( + Icons.circle, + size: 10.0, + color: theme.cardColor, + ), + Icon( + Icons.circle, + size: 10.0, + color: theme.cardColor, + ), + Icon( + Icons.circle, + size: 10.0, + color: theme.cardColor, + ), + Icon( + Icons.circle, + size: 10.0, + color: theme.cardColor, + ), + ], + ); + } +} diff --git a/lib/payment_methods/view/widget/link_accounts.dart b/lib/payment_methods/view/widget/link_accounts.dart new file mode 100644 index 0000000..ece2a2d --- /dev/null +++ b/lib/payment_methods/view/widget/link_accounts.dart @@ -0,0 +1,130 @@ +import 'package:flutter/material.dart'; +import 'package:flutter_svg/svg.dart'; +import 'package:fpb/assets/fpb_svg.dart'; +import 'package:fpb/core/presentation/widget/custom_btn_outline.dart'; +import 'package:fpb/core/presentation/widget/custom_dialog_widget.dart'; +import 'package:fpb/core/presentation/widget/vertical_spacing_widget.dart'; +import 'package:fpb/payment_methods/view/widget/account_linked.dart'; +import 'package:fpb/payment_methods/view/widget/stripe_payments_form.dart'; + +class LinkAccounts extends StatelessWidget { + const LinkAccounts({ + super.key, + required this.box, + }); + + final BoxConstraints box; + + @override + Widget build(BuildContext context) { + final theme = Theme.of(context); + final style = theme.textTheme; + + return Container( + width: box.maxWidth * 0.9, + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Text( + 'Other accounts', + style: theme.textTheme.titleLarge?.copyWith( + fontWeight: FontWeight.w400, + ), + ), + VerticalSpacingWidget(box: box), + // Paypay linked + AccountLinked( + assetName: SvgNames.paypal, + box: box, + onTap: () => print('delete'), + ), + VerticalSpacingWidget( + box: box, + height: box.maxHeight * 0.02, + ), + // btn link account - apple pay + CustomBtnOutline( + style: style, + box: box, + backgroundColor: theme.colorScheme.background, + borderColor: theme.colorScheme.secondary, + text: 'Link my Apple Pay', + textColor: theme.colorScheme.secondary, + leading: SvgPicture.asset( + SvgNames.applePay, + ), + onPressed: () => print('action'), + ), + VerticalSpacingWidget(box: box), + // btn link account - google pay + CustomBtnOutline( + style: style, + box: box, + backgroundColor: theme.colorScheme.background, + borderColor: theme.colorScheme.secondary, + text: 'Link my Google Pay', + textColor: theme.colorScheme.secondary, + leading: SvgPicture.asset( + SvgNames.googlePay, + ), + onPressed: () => print('action'), + ), + // VerticalSpacingWidget( + // box: box, + // ), + // btn link account - paypal + // CustomBtnOutline( + // style: style, + // box: box, + // backgroundColor: theme.colorScheme.background, + // borderColor: theme.colorScheme.secondary, + // text: 'Link Paypal', + // textColor: theme.colorScheme.secondary, + // leading: SvgPicture.asset( + // SvgNames.paypal, + // ), + // onPressed: () => print('action'), + // ), + // link stripe + VerticalSpacingWidget( + box: box, + ), + // btn link account - google pay + CustomBtnOutline( + style: style, + box: box, + backgroundColor: theme.colorScheme.background, + borderColor: theme.colorScheme.secondary, + text: 'Link Stripe account', + textColor: theme.colorScheme.secondary, + onPressed: () => { + showCustomDialog( + context, + box, + box.maxHeight * 0.45, + box.maxWidth * 0.95, + StripePaymentsForm( + box: box, + ), + ) + }, + ), + VerticalSpacingWidget( + box: box, + ), + // btn link account - bank + CustomBtnOutline( + style: style, + box: box, + backgroundColor: theme.colorScheme.background, + borderColor: theme.colorScheme.secondary, + text: 'Link bank account', + textColor: theme.colorScheme.secondary, + onPressed: () => print('action'), + ), + VerticalSpacingWidget(box: box), + ], + ), + ); + } +} diff --git a/lib/payment_methods/view/widget/mycard_item.dart b/lib/payment_methods/view/widget/mycard_item.dart new file mode 100644 index 0000000..2504865 --- /dev/null +++ b/lib/payment_methods/view/widget/mycard_item.dart @@ -0,0 +1,87 @@ +import 'package:flutter/material.dart'; +import 'package:fpb/core/presentation/widget/vertical_spacing_widget.dart'; +import 'package:fpb/payment_methods/view/widget/card_info_widget.dart'; +import 'package:fpb/payment_methods/view/widget/card_number_dot.dart'; + +class MyCardItem extends StatelessWidget { + const MyCardItem({ + super.key, + required this.box, + this.bgColor, + this.cardIndex, + }); + + final BoxConstraints box; + final Color? bgColor; + final int? cardIndex; + + @override + Widget build(BuildContext context) { + final theme = Theme.of(context); + final colors = Theme.of(context).colorScheme; + return Container( + width: box.maxWidth * 0.9, + height: box.maxHeight * 0.2, + decoration: BoxDecoration( + color: bgColor ?? colors.onTertiary, + borderRadius: BorderRadius.circular( + 10.0, + ), + ), + padding: EdgeInsets.symmetric( + horizontal: box.maxWidth * 0.04, + vertical: cardIndex == 0 || cardIndex == 1 + ? box.maxHeight * 0.0 + : box.maxHeight * 0.017, + ), + child: Column( + mainAxisAlignment: MainAxisAlignment.spaceAround, + children: [ + SizedBox( + width: box.maxWidth, + // color: Colors.red, + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Text( + 'Card Number', + style: theme.textTheme.titleSmall, + ), + SizedBox( + height: 5.0, + ), + SizedBox( + width: box.maxWidth, + child: Wrap( + alignment: WrapAlignment.spaceBetween, + crossAxisAlignment: WrapCrossAlignment.center, + children: [ + CardNumberDot(), + CardNumberDot(), + CardNumberDot(), + Text( + '1234', + style: theme.textTheme.titleSmall?.copyWith( + color: colors.surface, + ), + ), + ], + ), + ) + ], + ), + ), + CardInfoWidget( + box: box, + ), + if (cardIndex == 0 || cardIndex == 1) ...[ + VerticalSpacingWidget( + box: box, + height: box.maxHeight * 0.01, + ), + ] + ], + ), + ); + } +} diff --git a/lib/payment_methods/view/widget/payment_cards_widget.dart b/lib/payment_methods/view/widget/payment_cards_widget.dart new file mode 100644 index 0000000..7a6a0da --- /dev/null +++ b/lib/payment_methods/view/widget/payment_cards_widget.dart @@ -0,0 +1,128 @@ +import 'package:flutter/material.dart'; +import 'package:fpb/core/domain/virtualCard.dart'; +import 'package:fpb/core/presentation/widget/fpb_button.dart'; +import 'package:fpb/core/presentation/widget/vertical_spacing_widget.dart'; +import 'package:fpb/payment_methods/view/widget/mycard_item.dart'; + +class PaymentCardsWidget extends StatefulWidget { + const PaymentCardsWidget({ + super.key, + required this.box, + }); + + final BoxConstraints box; + + @override + State createState() => _PaymentCardsWidgetState(); +} + +class _PaymentCardsWidgetState extends State { + Duration kAnimationDuration = Duration(microseconds: 150); + + List cardItems = [ + const VirtualCard( + index: 0, + balance: '200', + cardNumber: '1234 6565 6577', + expiry: '04/25', + cvv: '123', + type: 'visa', + lastFourDigits: '1232', + ), + const VirtualCard( + index: 0, + balance: '1000', + cardNumber: '1234 6565 6577', + expiry: '04/25', + cvv: '123', + type: 'visa', + lastFourDigits: '5050', + ), + const VirtualCard( + index: 0, + balance: '550.50', + cardNumber: '1234 6565 6577', + expiry: '04/25', + cvv: '123', + type: 'visa', + lastFourDigits: '7070', + ), + ]; + + @override + Widget build(BuildContext context) { + final theme = Theme.of(context); + final colors = theme.colorScheme; + return Container( + width: widget.box.maxWidth, + child: Column( + children: [ + Container( + width: widget.box.maxWidth * 0.9, + child: Wrap( + alignment: WrapAlignment.spaceBetween, + crossAxisAlignment: WrapCrossAlignment.center, + children: [ + Text( + 'My Cards', + style: Theme.of(context).textTheme.titleLarge, + ), + FpbButton( + width: widget.box.maxWidth * 0.5, + height: widget.box.maxHeight * 0.055, + label: 'Add Card', + backgroundColor: Theme.of(context).colorScheme.secondary, + onTap: () => print('Add Card'), + spaceAround: true, + leading: Icon( + Icons.add, + ), + ), + ], + ), + ), + VerticalSpacingWidget( + box: widget.box, + height: widget.box.maxHeight * 0.02, + ), + // display cards + Container( + width: widget.box.maxWidth, + height: widget.box.maxHeight * 0.4, + padding: EdgeInsets.symmetric( + vertical: widget.box.maxWidth * 0.01, + ), + child: Stack( + alignment: Alignment.center, + children: [ + Positioned( + top: 0.0, + child: MyCardItem( + box: widget.box, + cardIndex: 0, + bgColor: colors.onTertiaryContainer, + ), + ), + Positioned( + top: 60.0, + child: MyCardItem( + box: widget.box, + bgColor: Color(0xFFC95528), + cardIndex: 1, + ), + ), + Positioned( + bottom: 20.0, + child: MyCardItem( + box: widget.box, + // bgColor: Colors.indigo, + ), + ), + ], + ), + ), + ], + ), + ); + } +} diff --git a/lib/payment_methods/view/widget/stripe_payments_form.dart b/lib/payment_methods/view/widget/stripe_payments_form.dart new file mode 100644 index 0000000..8380fcb --- /dev/null +++ b/lib/payment_methods/view/widget/stripe_payments_form.dart @@ -0,0 +1,101 @@ +import 'package:flutter/material.dart'; +import 'package:fpb/core/presentation/widget/fpb_button.dart'; +import 'package:fpb/core/presentation/widget/fpb_text_form_field.dart'; +import 'package:fpb/core/presentation/widget/vertical_spacing_widget.dart'; + +class StripePaymentsForm extends StatefulWidget { + const StripePaymentsForm({ + super.key, + required this.box, + }); + + final BoxConstraints box; + + @override + State createState() => _StripePaymentsFormState(); +} + +class _StripePaymentsFormState extends State { + bool isDefaultPayments = false; + + @override + Widget build(BuildContext context) { + return Container( + width: widget.box.maxWidth, + padding: EdgeInsets.symmetric( + horizontal: widget.box.maxWidth * 0.02, + vertical: widget.box.maxHeight * 0.02, + ), + child: Column( + children: [ + // card number input field + FpbTextFormField( + onChanged: (value) {}, + label: 'Card Number', + hint: '**** **** **** 1234', + box: widget.box, + keyboardType: TextInputType.number, + ), + // ExpiryDate and CVV + SizedBox( + width: widget.box.maxWidth, + child: Wrap( + alignment: WrapAlignment.spaceBetween, + children: [ + SizedBox( + width: widget.box.maxWidth * 0.55, + child: FpbTextFormField( + onChanged: (value) {}, + label: 'Expiry Date', + hint: 'DD.MM.YY', + box: widget.box, + ), + ), + SizedBox( + width: widget.box.maxWidth * 0.3, + child: FpbTextFormField( + onChanged: (value) {}, + label: 'CVV', + hint: '000', + box: widget.box, + keyboardType: TextInputType.number, + ), + ), + ], + ), + ), + // set payments as default + Container( + width: widget.box.maxWidth, + child: Wrap( + alignment: WrapAlignment.start, + crossAxisAlignment: WrapCrossAlignment.center, + children: [ + Checkbox( + value: isDefaultPayments, + activeColor: Theme.of(context).colorScheme.primary, + onChanged: (bool? value) { + print(value); + setState(() { + isDefaultPayments = value!; + }); + }, + ), + Text( + 'Set as your default payment method', + style: Theme.of(context).textTheme.bodyMedium, + ), + ], + ), + ), + VerticalSpacingWidget(box: widget.box), + // btn submit - Add payments + FpbButton( + label: 'Add', + onTap: () => print('Add Stripe'), + ), + ], + ), + ); + } +} diff --git a/lib/phone_number_confirmation/view/phone_number_confirmation.dart b/lib/phone_number_confirmation/view/phone_number_confirmation.dart index 50309e8..0ed8a35 100644 --- a/lib/phone_number_confirmation/view/phone_number_confirmation.dart +++ b/lib/phone_number_confirmation/view/phone_number_confirmation.dart @@ -34,8 +34,7 @@ class _PhoneNumberConfirmationScreenState SingleChildScrollView( child: Padding( padding: EdgeInsets.only( - left: box.maxHeight * .025, - right: box.maxHeight * .025), + left: box.maxHeight * .025, right: box.maxHeight * .025), child: Column( children: [ SizedBox( diff --git a/lib/profile/view/profile_page.dart b/lib/profile/view/profile_page.dart index ace6831..391474a 100644 --- a/lib/profile/view/profile_page.dart +++ b/lib/profile/view/profile_page.dart @@ -17,7 +17,7 @@ class _ProfileScreenState extends State { @override Widget build(BuildContext context) { final l10n = context.l10n; - final theme = Theme.of(context); + final theme = Theme.of(context); return Scaffold( backgroundColor: theme.colorScheme.onBackground, body: LayoutBuilder( @@ -32,39 +32,29 @@ class _ProfileScreenState extends State { child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ - TitleText( - box: box, - l10n: l10n), + TitleText(box: box, l10n: l10n), SizedBox( height: box.maxHeight * 0.03, ), - UserPic( - box: box), + UserPic(box: box), SizedBox( height: box.maxHeight * 0.01, ), Center( - child: UserName( - box: box), + child: UserName(box: box), ), SizedBox( height: box.maxHeight * 0.03, ), - UserProfileOptions( - box: box, - l10n: l10n), + UserProfileOptions(box: box, l10n: l10n), SizedBox( height: box.maxHeight * 0.02, ), - LogOutOption( - box:box, - l10n: l10n), + LogOutOption(box: box, l10n: l10n), SizedBox( height: box.maxHeight * 0.1, ), - AppVersion( - box: box, - l10n: l10n) + AppVersion(box: box, l10n: l10n) ], ), ), @@ -76,11 +66,7 @@ class _ProfileScreenState extends State { } class AppVersion extends StatelessWidget { - const AppVersion({ - super.key, - required this.l10n, - required this.box - }); + const AppVersion({super.key, required this.l10n, required this.box}); final AppLocalizations l10n; final BoxConstraints box; @@ -91,7 +77,7 @@ class AppVersion extends StatelessWidget { child: Column( children: [ Text( - 'Version 10.2', + 'Version 10.2', style: Theme.of(context).textTheme.titleSmall, ), SizedBox( @@ -112,11 +98,7 @@ class AppVersion extends StatelessWidget { } class LogOutOption extends StatelessWidget { - const LogOutOption({ - super.key, - required this.l10n, - required this.box - }); + const LogOutOption({super.key, required this.l10n, required this.box}); final AppLocalizations l10n; final BoxConstraints box; @@ -124,24 +106,22 @@ class LogOutOption extends StatelessWidget { @override Widget build(BuildContext context) { return Container( - decoration: BoxDecoration( - borderRadius: BorderRadius.circular(box.maxHeight * 0.025), - color: Colors.white, - ), - child: Padding( - padding: EdgeInsets.only( - left: box.maxHeight * 0.03, - top: box.maxHeight * 0.01, - bottom: box.maxHeight * 0.01, - ), - child: - ProfileInfoOptions( - text: l10n.profileLogOutText, - icon: FpbIcons.logout, - box: box, + decoration: BoxDecoration( + borderRadius: BorderRadius.circular(box.maxHeight * 0.025), + color: Colors.white, ), - ) - ); + child: Padding( + padding: EdgeInsets.only( + left: box.maxHeight * 0.03, + top: box.maxHeight * 0.01, + bottom: box.maxHeight * 0.01, + ), + child: ProfileInfoOptions( + text: l10n.profileLogOutText, + icon: FpbIcons.logout, + box: box, + ), + )); } } @@ -169,23 +149,23 @@ class UserProfileOptions extends StatelessWidget { bottom: box.maxHeight * 0.03, ), child: Column( - children: [ + children: [ ProfileInfoOptions( text: l10n.profileAccountText, icon: FpbIcons.profile, box: box, - ), + ), ProfileInfoOptions( text: l10n.profileSettingsText, icon: FpbIcons.setting, box: box, - ), + ), ProfileInfoOptions( text: l10n.profileNotificationsText, icon: Icons.notifications, box: box, - ), - ProfileInfoOptions( + ), + ProfileInfoOptions( text: l10n.profilePaymentMethodsText, icon: FpbIcons.credit_card, box: box, @@ -197,44 +177,43 @@ class UserProfileOptions extends StatelessWidget { } } -class UserPic extends StatelessWidget{ -const UserPic({ +class UserPic extends StatelessWidget { + const UserPic({ super.key, required this.box, }); -final BoxConstraints box; + final BoxConstraints box; @override Widget build(BuildContext context) { return Container( width: box.maxWidth, child: Stack( - alignment: Alignment(0.0, -1.5), - children: [ - Positioned( + alignment: Alignment(0.0, -1.5), + children: [ + Positioned( child: CircleAvatar( radius: box.maxHeight * 0.060, child: FlutterLogo(size: box.maxHeight * 0.1), ), ), - Positioned( - //top: 0, - right: box.maxWidth * .001, - child: IconButton( - onPressed: () { }, - icon: Icon( - FpbIcons.edit, - size: box.maxHeight * 0.028, + Positioned( + //top: 0, + right: box.maxWidth * .001, + child: IconButton( + onPressed: () {}, + icon: Icon( + FpbIcons.edit, + size: box.maxHeight * 0.028, ), ), - ), + ), ], ), ); } } - class UserName extends StatelessWidget { const UserName({ super.key, @@ -250,17 +229,15 @@ class UserName extends StatelessWidget { mainAxisAlignment: MainAxisAlignment.center, crossAxisAlignment: CrossAxisAlignment.center, children: [ - Text( - 'John Merry', - style: style.titleMedium?.copyWith( - fontWeight: FontWeight.w600 - ), - ), - Text( - '@john.merry', - style: style.titleSmall, - ), - ], + Text( + 'John Merry', + style: style.titleMedium?.copyWith(fontWeight: FontWeight.w600), + ), + Text( + '@john.merry', + style: style.titleSmall, + ), + ], ); } } @@ -277,15 +254,13 @@ class TitleText extends StatelessWidget { @override Widget build(BuildContext context) { - // final l10n = context.l10n; + // final l10n = context.l10n; final theme = Theme.of(context); final style = theme.textTheme; return Text( l10n.profileTitle, style: style.displayLarge?.copyWith( - color: theme.colorScheme.secondary, - fontWeight: FontWeight.w600 - ), + color: theme.colorScheme.secondary, fontWeight: FontWeight.w600), ); } } diff --git a/lib/profile/view/widgets/profileInfoOptions.dart b/lib/profile/view/widgets/profileInfoOptions.dart index 2da0286..d2d8796 100644 --- a/lib/profile/view/widgets/profileInfoOptions.dart +++ b/lib/profile/view/widgets/profileInfoOptions.dart @@ -1,44 +1,40 @@ import 'package:flutter/material.dart'; class ProfileInfoOptions extends StatelessWidget { - const ProfileInfoOptions({ - super.key, - required this.box, - required this.icon, - required this.text - }); + const ProfileInfoOptions( + {super.key, required this.box, required this.icon, required this.text}); - final BoxConstraints box; - final String text; - final IconData icon; + final BoxConstraints box; + final String text; + final IconData icon; @override Widget build(BuildContext context) { //final l10n = context.l10n; final theme = Theme.of(context); final style = theme.textTheme; - + return Container( child: Padding( - padding: EdgeInsets.symmetric(vertical: box.maxHeight * .007), + padding: EdgeInsets.symmetric(vertical: box.maxHeight * .007), child: Row( children: [ IconButton( - onPressed: ( ){}, - icon: Icon( - icon, - color: theme.colorScheme.secondaryContainer, - )), - SizedBox( - width: box.maxWidth * .03, - ), - Text(text, - style: style.titleMedium?.copyWith( - fontWeight: FontWeight.w600 - ),) + onPressed: () {}, + icon: Icon( + icon, + color: theme.colorScheme.secondaryContainer, + )), + SizedBox( + width: box.maxWidth * .03, + ), + Text( + text, + style: style.titleMedium?.copyWith(fontWeight: FontWeight.w600), + ) ], ), ), ); } -} \ No newline at end of file +} diff --git a/lib/qr_code_screen/qr_code_screen.dart b/lib/qr_code_screen/qr_code_screen.dart index ffcd3fe..d7bfc35 100644 --- a/lib/qr_code_screen/qr_code_screen.dart +++ b/lib/qr_code_screen/qr_code_screen.dart @@ -1 +1 @@ -export 'view/qr_code_screen.dart'; \ No newline at end of file +export 'view/qr_code_screen.dart'; diff --git a/lib/qr_code_screen/view/qr_code_screen.dart b/lib/qr_code_screen/view/qr_code_screen.dart index e0b386f..9571bf8 100644 --- a/lib/qr_code_screen/view/qr_code_screen.dart +++ b/lib/qr_code_screen/view/qr_code_screen.dart @@ -130,9 +130,7 @@ class _QrCodeScreenState extends State child: Text( "Cancel", style: TextStyle( - color: Theme.of(context) - .colorScheme - .onTertiary, + color: Theme.of(context).colorScheme.tertiary, fontSize: box.maxWidth * 0.05, ), textAlign: TextAlign.center, diff --git a/lib/qr_code_screen/view/widget/my_qrcode_widget.dart b/lib/qr_code_screen/view/widget/my_qrcode_widget.dart index 5f03ceb..cd17d85 100644 --- a/lib/qr_code_screen/view/widget/my_qrcode_widget.dart +++ b/lib/qr_code_screen/view/widget/my_qrcode_widget.dart @@ -25,7 +25,7 @@ class MyQrCode extends StatelessWidget { child: Text( "My QR Code", style: TextStyle( - color: Theme.of(context).colorScheme.onTertiary, + color: Theme.of(context).colorScheme.tertiary, fontSize: box.maxWidth * 0.056, ), textAlign: TextAlign.center, @@ -58,7 +58,7 @@ class MyQrCode extends StatelessWidget { Text( "John Doe", style: TextStyle( - color: Theme.of(context).colorScheme.onTertiary, + color: Theme.of(context).colorScheme.tertiary, fontSize: box.maxWidth * 0.056, ), textAlign: TextAlign.center, @@ -72,7 +72,10 @@ class MyQrCode extends StatelessWidget { child: Text( "@johndoe", style: TextStyle( - color: Theme.of(context).colorScheme.onTertiary.withOpacity(0.5), + color: Theme.of(context) + .colorScheme + .tertiary + .withOpacity(0.5), fontSize: box.maxWidth * 0.04, fontWeight: FontWeight.normal, ), diff --git a/lib/qr_code_screen/view/widget/scan_qrcode_widget.dart b/lib/qr_code_screen/view/widget/scan_qrcode_widget.dart index 6fbdf95..d61f3fe 100644 --- a/lib/qr_code_screen/view/widget/scan_qrcode_widget.dart +++ b/lib/qr_code_screen/view/widget/scan_qrcode_widget.dart @@ -25,8 +25,7 @@ class ScanQrCodeWidget extends StatelessWidget { child: Text( "Scan a code", style: TextStyle( - color: - Theme.of(context).colorScheme.onTertiary, + color: Theme.of(context).colorScheme.tertiary, fontSize: box.maxWidth * 0.056, ), textAlign: TextAlign.center, diff --git a/lib/router/app_route.dart b/lib/router/app_route.dart index c96f1ca..1225d28 100644 --- a/lib/router/app_route.dart +++ b/lib/router/app_route.dart @@ -6,6 +6,7 @@ import 'package:fpb/home/view/home_screen.dart'; import 'package:fpb/latest_activities/view/latest_activities_screen.dart'; import 'package:fpb/onboarding/view/onboarding_screens.dart'; import 'package:fpb/onboarding/view/splash_screen.dart'; +import 'package:fpb/payment_methods/payment_method_screen.dart'; import 'package:fpb/phone_number_confirmation/view/phone_number_confirmation.dart'; import 'package:fpb/profile/view/profile_page.dart'; import 'package:fpb/qr_code_screen/view/qr_code_screen.dart'; @@ -23,6 +24,7 @@ import 'package:fpb/sign_up/view/signup_page.dart'; AutoRoute(page: EmailConfirmationScreen), AutoRoute(page: SignUpScreen), AutoRoute(page: SaveMoneyScreen), + AutoRoute(page: PaymentMethodScreen), AutoRoute( name: 'HomeRouter', page: HomeScreen, diff --git a/lib/router/app_route.gr.dart b/lib/router/app_route.gr.dart index c50a83f..0868fac 100644 --- a/lib/router/app_route.gr.dart +++ b/lib/router/app_route.gr.dart @@ -11,186 +11,197 @@ // ignore_for_file: type=lint // ignore_for_file: no_leading_underscores_for_library_prefixes -import 'package:auto_route/auto_route.dart' as _i15; -import 'package:flutter/material.dart' as _i16; +import 'package:auto_route/auto_route.dart' as _i16; +import 'package:flutter/material.dart' as _i17; -import '../contact_us/view/contact_us_screen.dart' as _i11; -import '../contact_us/view/contact_us_success_screen.dart' as _i12; -import '../core/domain/user.dart' as _i17; +import '../contact_us/view/contact_us_screen.dart' as _i12; +import '../contact_us/view/contact_us_success_screen.dart' as _i13; +import '../core/domain/user.dart' as _i18; import '../email_confirmation/email_confirmation.dart' as _i4; -import '../home/view/home_screen.dart' as _i7; -import '../latest_activities/view/latest_activities_screen.dart' as _i8; -import '../onboarding/view/onboarding_screens.dart' as _i10; +import '../home/view/home_screen.dart' as _i8; +import '../latest_activities/view/latest_activities_screen.dart' as _i9; +import '../onboarding/view/onboarding_screens.dart' as _i11; import '../onboarding/view/splash_screen.dart' as _i1; +import '../payment_methods/payment_method_screen.dart' as _i7; import '../phone_number_confirmation/view/phone_number_confirmation.dart' as _i3; -import '../profile/view/profile_page.dart' as _i14; -import '../qr_code_screen/view/qr_code_screen.dart' as _i9; +import '../profile/view/profile_page.dart' as _i15; +import '../qr_code_screen/view/qr_code_screen.dart' as _i10; import '../savings/save_money_with_bucket/save_money_with_bucket.dart' as _i6; -import '../savings/view/savings_page.dart' as _i13; +import '../savings/view/savings_page.dart' as _i14; import '../sign_in/view/sign_in_page.dart' as _i2; import '../sign_up/view/signup_page.dart' as _i5; -class AppRoute extends _i15.RootStackRouter { - AppRoute([_i16.GlobalKey<_i16.NavigatorState>? navigatorKey]) +class AppRoute extends _i16.RootStackRouter { + AppRoute([_i17.GlobalKey<_i17.NavigatorState>? navigatorKey]) : super(navigatorKey); @override - final Map pagesMap = { + final Map pagesMap = { SplashRoute.name: (routeData) { - return _i15.MaterialPageX( + return _i16.MaterialPageX( routeData: routeData, child: const _i1.SplashScreen(), ); }, SignInRoute.name: (routeData) { - return _i15.MaterialPageX( + return _i16.MaterialPageX( routeData: routeData, child: const _i2.SignInScreen(), ); }, PhoneNumberConfirmationRoute.name: (routeData) { - return _i15.MaterialPageX( + return _i16.MaterialPageX( routeData: routeData, child: const _i3.PhoneNumberConfirmationScreen(), ); }, EmailConfirmationRoute.name: (routeData) { - return _i15.MaterialPageX( + return _i16.MaterialPageX( routeData: routeData, child: const _i4.EmailConfirmationScreen(), ); }, SignUpRoute.name: (routeData) { - return _i15.MaterialPageX( + return _i16.MaterialPageX( routeData: routeData, child: const _i5.SignUpScreen(), ); }, SaveMoneyRoute.name: (routeData) { - return _i15.MaterialPageX( + return _i16.MaterialPageX( routeData: routeData, child: const _i6.SaveMoneyScreen(), ); }, + PaymentMethodRoute.name: (routeData) { + return _i16.MaterialPageX( + routeData: routeData, + child: const _i7.PaymentMethodScreen(), + ); + }, HomeRouter.name: (routeData) { final args = routeData.argsAs(); - return _i15.MaterialPageX( + return _i16.MaterialPageX( routeData: routeData, - child: _i7.HomeScreen( + child: _i8.HomeScreen( key: args.key, user: args.user, ), ); }, LatestActivitiesPage.name: (routeData) { - return _i15.MaterialPageX( + return _i16.MaterialPageX( routeData: routeData, - child: const _i8.LatestActivitiesPage(), + child: const _i9.LatestActivitiesPage(), ); }, QrCodeRoute.name: (routeData) { - return _i15.MaterialPageX( + return _i16.MaterialPageX( routeData: routeData, - child: const _i9.QrCodeScreen(), + child: const _i10.QrCodeScreen(), ); }, OnboardingRoute.name: (routeData) { final args = routeData.argsAs( orElse: () => const OnboardingRouteArgs()); - return _i15.MaterialPageX( + return _i16.MaterialPageX( routeData: routeData, - child: _i10.OnboardingScreen( + child: _i11.OnboardingScreen( onGetStartedPressed: args.onGetStartedPressed, key: args.key, ), ); }, ContactUsRoute.name: (routeData) { - return _i15.MaterialPageX( + return _i16.MaterialPageX( routeData: routeData, - child: const _i11.ContactUsScreen(), + child: const _i12.ContactUsScreen(), ); }, ContactUsSuccessRoute.name: (routeData) { - return _i15.MaterialPageX( + return _i16.MaterialPageX( routeData: routeData, - child: const _i12.ContactUsSuccessScreen(), + child: const _i13.ContactUsSuccessScreen(), ); }, SavingsPage.name: (routeData) { - return _i15.MaterialPageX( + return _i16.MaterialPageX( routeData: routeData, - child: const _i13.SavingsPage(), + child: const _i14.SavingsPage(), ); }, ProfileRoute.name: (routeData) { - return _i15.MaterialPageX( + return _i16.MaterialPageX( routeData: routeData, - child: const _i14.ProfileScreen(), + child: const _i15.ProfileScreen(), ); }, }; @override - List<_i15.RouteConfig> get routes => [ - _i15.RouteConfig( + List<_i16.RouteConfig> get routes => [ + _i16.RouteConfig( SplashRoute.name, path: '/', ), - _i15.RouteConfig( + _i16.RouteConfig( SignInRoute.name, path: '/sign-in-screen', ), - _i15.RouteConfig( + _i16.RouteConfig( PhoneNumberConfirmationRoute.name, path: '/phone-number-confirmation-screen', ), - _i15.RouteConfig( + _i16.RouteConfig( EmailConfirmationRoute.name, path: '/email-confirmation-screen', ), - _i15.RouteConfig( + _i16.RouteConfig( SignUpRoute.name, path: '/sign-up-screen', ), - _i15.RouteConfig( + _i16.RouteConfig( SaveMoneyRoute.name, path: '/save-money-screen', ), - _i15.RouteConfig( + _i16.RouteConfig( + PaymentMethodRoute.name, + path: '/payment-method-screen', + ), + _i16.RouteConfig( HomeRouter.name, path: '/home-screen', children: [ - _i15.RouteConfig( + _i16.RouteConfig( SavingsPage.name, path: 'savings', parent: HomeRouter.name, ), - _i15.RouteConfig( + _i16.RouteConfig( ProfileRoute.name, path: 'profile', parent: HomeRouter.name, ), ], ), - _i15.RouteConfig( + _i16.RouteConfig( LatestActivitiesPage.name, path: 'latestActivities', ), - _i15.RouteConfig( + _i16.RouteConfig( QrCodeRoute.name, path: '/qr-code-screen', ), - _i15.RouteConfig( + _i16.RouteConfig( OnboardingRoute.name, path: '/onboarding-screen', ), - _i15.RouteConfig( + _i16.RouteConfig( ContactUsRoute.name, path: '/contact-us-screen', ), - _i15.RouteConfig( + _i16.RouteConfig( ContactUsSuccessRoute.name, path: '/contact-us-success-screen', ), @@ -199,7 +210,7 @@ class AppRoute extends _i15.RootStackRouter { /// generated route for /// [_i1.SplashScreen] -class SplashRoute extends _i15.PageRouteInfo { +class SplashRoute extends _i16.PageRouteInfo { const SplashRoute() : super( SplashRoute.name, @@ -211,7 +222,7 @@ class SplashRoute extends _i15.PageRouteInfo { /// generated route for /// [_i2.SignInScreen] -class SignInRoute extends _i15.PageRouteInfo { +class SignInRoute extends _i16.PageRouteInfo { const SignInRoute() : super( SignInRoute.name, @@ -223,7 +234,7 @@ class SignInRoute extends _i15.PageRouteInfo { /// generated route for /// [_i3.PhoneNumberConfirmationScreen] -class PhoneNumberConfirmationRoute extends _i15.PageRouteInfo { +class PhoneNumberConfirmationRoute extends _i16.PageRouteInfo { const PhoneNumberConfirmationRoute() : super( PhoneNumberConfirmationRoute.name, @@ -235,7 +246,7 @@ class PhoneNumberConfirmationRoute extends _i15.PageRouteInfo { /// generated route for /// [_i4.EmailConfirmationScreen] -class EmailConfirmationRoute extends _i15.PageRouteInfo { +class EmailConfirmationRoute extends _i16.PageRouteInfo { const EmailConfirmationRoute() : super( EmailConfirmationRoute.name, @@ -247,7 +258,7 @@ class EmailConfirmationRoute extends _i15.PageRouteInfo { /// generated route for /// [_i5.SignUpScreen] -class SignUpRoute extends _i15.PageRouteInfo { +class SignUpRoute extends _i16.PageRouteInfo { const SignUpRoute() : super( SignUpRoute.name, @@ -259,7 +270,7 @@ class SignUpRoute extends _i15.PageRouteInfo { /// generated route for /// [_i6.SaveMoneyScreen] -class SaveMoneyRoute extends _i15.PageRouteInfo { +class SaveMoneyRoute extends _i16.PageRouteInfo { const SaveMoneyRoute() : super( SaveMoneyRoute.name, @@ -270,12 +281,24 @@ class SaveMoneyRoute extends _i15.PageRouteInfo { } /// generated route for -/// [_i7.HomeScreen] -class HomeRouter extends _i15.PageRouteInfo { +/// [_i7.PaymentMethodScreen] +class PaymentMethodRoute extends _i16.PageRouteInfo { + const PaymentMethodRoute() + : super( + PaymentMethodRoute.name, + path: '/payment-method-screen', + ); + + static const String name = 'PaymentMethodRoute'; +} + +/// generated route for +/// [_i8.HomeScreen] +class HomeRouter extends _i16.PageRouteInfo { HomeRouter({ - _i16.Key? key, - required _i17.User user, - List<_i15.PageRouteInfo>? children, + _i17.Key? key, + required _i18.User user, + List<_i16.PageRouteInfo>? children, }) : super( HomeRouter.name, path: '/home-screen', @@ -295,9 +318,9 @@ class HomeRouterArgs { required this.user, }); - final _i16.Key? key; + final _i17.Key? key; - final _i17.User user; + final _i18.User user; @override String toString() { @@ -306,8 +329,8 @@ class HomeRouterArgs { } /// generated route for -/// [_i8.LatestActivitiesPage] -class LatestActivitiesPage extends _i15.PageRouteInfo { +/// [_i9.LatestActivitiesPage] +class LatestActivitiesPage extends _i16.PageRouteInfo { const LatestActivitiesPage() : super( LatestActivitiesPage.name, @@ -318,8 +341,8 @@ class LatestActivitiesPage extends _i15.PageRouteInfo { } /// generated route for -/// [_i9.QrCodeScreen] -class QrCodeRoute extends _i15.PageRouteInfo { +/// [_i10.QrCodeScreen] +class QrCodeRoute extends _i16.PageRouteInfo { const QrCodeRoute() : super( QrCodeRoute.name, @@ -330,11 +353,11 @@ class QrCodeRoute extends _i15.PageRouteInfo { } /// generated route for -/// [_i10.OnboardingScreen] -class OnboardingRoute extends _i15.PageRouteInfo { +/// [_i11.OnboardingScreen] +class OnboardingRoute extends _i16.PageRouteInfo { OnboardingRoute({ void Function()? onGetStartedPressed, - _i16.Key? key, + _i17.Key? key, }) : super( OnboardingRoute.name, path: '/onboarding-screen', @@ -355,7 +378,7 @@ class OnboardingRouteArgs { final void Function()? onGetStartedPressed; - final _i16.Key? key; + final _i17.Key? key; @override String toString() { @@ -364,8 +387,8 @@ class OnboardingRouteArgs { } /// generated route for -/// [_i11.ContactUsScreen] -class ContactUsRoute extends _i15.PageRouteInfo { +/// [_i12.ContactUsScreen] +class ContactUsRoute extends _i16.PageRouteInfo { const ContactUsRoute() : super( ContactUsRoute.name, @@ -376,8 +399,8 @@ class ContactUsRoute extends _i15.PageRouteInfo { } /// generated route for -/// [_i12.ContactUsSuccessScreen] -class ContactUsSuccessRoute extends _i15.PageRouteInfo { +/// [_i13.ContactUsSuccessScreen] +class ContactUsSuccessRoute extends _i16.PageRouteInfo { const ContactUsSuccessRoute() : super( ContactUsSuccessRoute.name, @@ -388,8 +411,8 @@ class ContactUsSuccessRoute extends _i15.PageRouteInfo { } /// generated route for -/// [_i13.SavingsPage] -class SavingsPage extends _i15.PageRouteInfo { +/// [_i14.SavingsPage] +class SavingsPage extends _i16.PageRouteInfo { const SavingsPage() : super( SavingsPage.name, @@ -400,8 +423,8 @@ class SavingsPage extends _i15.PageRouteInfo { } /// generated route for -/// [_i14.ProfileScreen] -class ProfileRoute extends _i15.PageRouteInfo { +/// [_i15.ProfileScreen] +class ProfileRoute extends _i16.PageRouteInfo { const ProfileRoute() : super( ProfileRoute.name, diff --git a/lib/savings/view/savings_page.dart b/lib/savings/view/savings_page.dart index f033fa5..970a618 100644 --- a/lib/savings/view/savings_page.dart +++ b/lib/savings/view/savings_page.dart @@ -16,7 +16,6 @@ class SavingsPage extends StatefulWidget { } class _SavingsPageState extends State { - @override Widget build(BuildContext context) { final l10n = context.l10n;