├── ios
├── Flutter
│ ├── Debug.xcconfig
│ ├── Release.xcconfig
│ └── AppFrameworkInfo.plist
├── Runner
│ ├── Runner-Bridging-Header.h
│ ├── Assets.xcassets
│ │ ├── AppIcon.appiconset
│ │ │ ├── AppIcon-29.png
│ │ │ ├── AppIcon@2x.png
│ │ │ ├── AppIcon@3x.png
│ │ │ ├── AppIcon-20@2x.png
│ │ │ ├── AppIcon-20@3x.png
│ │ │ ├── AppIcon-29@2x.png
│ │ │ ├── AppIcon-29@3x.png
│ │ │ ├── AppIcon-40@2x.png
│ │ │ ├── AppIcon-40@3x.png
│ │ │ ├── AppIcon~ipad.png
│ │ │ ├── AppIcon-20~ipad.png
│ │ │ ├── AppIcon-29~ipad.png
│ │ │ ├── AppIcon-40~ipad.png
│ │ │ ├── AppIcon@2x~ipad.png
│ │ │ ├── AppIcon-20@2x~ipad.png
│ │ │ ├── AppIcon-29@2x~ipad.png
│ │ │ ├── AppIcon-40@2x~ipad.png
│ │ │ ├── AppIcon-60@2x~car.png
│ │ │ ├── AppIcon-60@3x~car.png
│ │ │ ├── AppIcon-83.5@2x~ipad.png
│ │ │ ├── AppIcon~ios-marketing.png
│ │ │ └── Contents.json
│ │ ├── LaunchImage.imageset
│ │ │ ├── LaunchImage.png
│ │ │ ├── LaunchImage@2x.png
│ │ │ ├── LaunchImage@3x.png
│ │ │ ├── README.md
│ │ │ └── Contents.json
│ │ └── LaunchBackground.imageset
│ │ │ ├── background.png
│ │ │ └── Contents.json
│ ├── AppDelegate.swift
│ ├── GoogleService-Info.plist
│ ├── Base.lproj
│ │ ├── Main.storyboard
│ │ └── LaunchScreen.storyboard
│ └── Info.plist
├── Runner.xcodeproj
│ ├── project.xcworkspace
│ │ ├── contents.xcworkspacedata
│ │ └── xcshareddata
│ │ │ ├── WorkspaceSettings.xcsettings
│ │ │ └── IDEWorkspaceChecks.plist
│ └── xcshareddata
│ │ └── xcschemes
│ │ └── Runner.xcscheme
├── Runner.xcworkspace
│ ├── contents.xcworkspacedata
│ └── xcshareddata
│ │ ├── WorkspaceSettings.xcsettings
│ │ └── IDEWorkspaceChecks.plist
├── firebase_app_id_file.json
└── .gitignore
├── android
├── gradle.properties
├── app
│ ├── src
│ │ ├── main
│ │ │ ├── res
│ │ │ │ ├── drawable
│ │ │ │ │ ├── background.png
│ │ │ │ │ ├── notifications_logo.png
│ │ │ │ │ └── launch_background.xml
│ │ │ │ ├── drawable-hdpi
│ │ │ │ │ └── splash.png
│ │ │ │ ├── drawable-mdpi
│ │ │ │ │ └── splash.png
│ │ │ │ ├── drawable-xhdpi
│ │ │ │ │ └── splash.png
│ │ │ │ ├── drawable-xxhdpi
│ │ │ │ │ └── splash.png
│ │ │ │ ├── drawable-v21
│ │ │ │ │ ├── background.png
│ │ │ │ │ └── launch_background.xml
│ │ │ │ ├── drawable-xxxhdpi
│ │ │ │ │ └── splash.png
│ │ │ │ ├── mipmap-hdpi
│ │ │ │ │ ├── ic_launcher.png
│ │ │ │ │ ├── ic_launcher_background.png
│ │ │ │ │ ├── ic_launcher_foreground.png
│ │ │ │ │ └── ic_launcher_monochrome.png
│ │ │ │ ├── mipmap-mdpi
│ │ │ │ │ ├── ic_launcher.png
│ │ │ │ │ ├── ic_launcher_background.png
│ │ │ │ │ ├── ic_launcher_foreground.png
│ │ │ │ │ └── ic_launcher_monochrome.png
│ │ │ │ ├── mipmap-xhdpi
│ │ │ │ │ ├── ic_launcher.png
│ │ │ │ │ ├── ic_launcher_background.png
│ │ │ │ │ ├── ic_launcher_foreground.png
│ │ │ │ │ └── ic_launcher_monochrome.png
│ │ │ │ ├── mipmap-xxhdpi
│ │ │ │ │ ├── ic_launcher.png
│ │ │ │ │ ├── ic_launcher_background.png
│ │ │ │ │ ├── ic_launcher_foreground.png
│ │ │ │ │ └── ic_launcher_monochrome.png
│ │ │ │ ├── mipmap-xxxhdpi
│ │ │ │ │ ├── ic_launcher.png
│ │ │ │ │ ├── ic_launcher_background.png
│ │ │ │ │ ├── ic_launcher_foreground.png
│ │ │ │ │ └── ic_launcher_monochrome.png
│ │ │ │ ├── mipmap-anydpi-v26
│ │ │ │ │ └── ic_launcher.xml
│ │ │ │ ├── values-v31
│ │ │ │ │ └── styles.xml
│ │ │ │ ├── values-night-v31
│ │ │ │ │ └── styles.xml
│ │ │ │ ├── values
│ │ │ │ │ └── styles.xml
│ │ │ │ └── values-night
│ │ │ │ │ └── styles.xml
│ │ │ ├── kotlin
│ │ │ │ └── com
│ │ │ │ │ └── example
│ │ │ │ │ └── money_transfer_app
│ │ │ │ │ └── MainActivity.kt
│ │ │ └── AndroidManifest.xml
│ │ ├── debug
│ │ │ └── AndroidManifest.xml
│ │ └── profile
│ │ │ └── AndroidManifest.xml
│ ├── google-services.json
│ └── build.gradle
├── gradle
│ └── wrapper
│ │ └── gradle-wrapper.properties
├── .gitignore
├── settings.gradle
└── build.gradle
├── assets
├── images
│ ├── logo.png
│ ├── empty_list.png
│ ├── main_logo.png
│ ├── error_image.png
│ ├── no-internet.png
│ ├── card_chip_image.png
│ ├── gradient_circle.png
│ ├── Pay Mobile advert.png
│ ├── notifications_logo.png
│ ├── pay_mobile_advert.png
│ ├── dialog_success_image.png
│ ├── pin_feature_showcase.png
│ ├── responsive_showcase.png
│ ├── pay_mobile_full_stack.png
│ ├── customer_support_showcase.png
│ ├── forgort_password_showcase.png
│ ├── in_app_notification_image.png
│ ├── success_dialogs_showcase.png
│ ├── push_notification_showcase.png
│ ├── signup_verification_showcase.png
│ ├── transaction_details_showcase.png
│ ├── username_transfer_showcase.png
│ └── username_search_success_showcase.png
├── icons
│ ├── add_icon.png
│ ├── card_icon.png
│ ├── chat_icon.png
│ ├── home_icon.png
│ ├── more_icon.png
│ ├── send_icon.png
│ ├── wifi_icon.png
│ ├── bills_icon.png
│ ├── budget_icon.png
│ ├── credit_icon.png
│ ├── debit_icon.png
│ ├── info-circle.png
│ ├── logout_icon.png
│ ├── mobile_icon.png
│ ├── notification.png
│ ├── profile_icon.png
│ ├── settings_icon.png
│ ├── shopping_icon.png
│ ├── contactless_icon.png
│ ├── electricity_icon.png
│ └── transactions_icon.png
└── fonts
│ ├── Comfortaa-Bold.ttf
│ ├── Comfortaa-Medium.ttf
│ ├── Comfortaa-Regular.ttf
│ └── Comfortaa-SemiBold.ttf
├── lib
├── core
│ ├── utils
│ │ ├── custom_exception_handler.dart
│ │ ├── color_constants.dart
│ │ ├── assets.dart
│ │ ├── validators.dart
│ │ ├── custom_notifications.dart
│ │ └── global_constants.dart
│ └── error
│ │ └── error_handler.dart
├── features
│ ├── profile
│ │ ├── screens
│ │ │ ├── security_screen.dart
│ │ │ └── chat_screen.dart
│ │ ├── providers
│ │ │ └── chat_provider.dart
│ │ ├── models
│ │ │ ├── chat_model.dart
│ │ │ └── message_model.dart
│ │ └── widgets
│ │ │ ├── receivers_message_card.dart.dart
│ │ │ ├── senders_message_card.dart
│ │ │ └── profile_card.dart
│ ├── auth
│ │ ├── providers
│ │ │ ├── auth_provider.dart
│ │ │ └── user_provider.dart
│ │ ├── models
│ │ │ └── user.dart
│ │ └── screens
│ │ │ ├── create_new_password_screen.dart
│ │ │ ├── forgort_pin_screen.dart
│ │ │ ├── forgort_password_screen.dart
│ │ │ └── login_screen.dart
│ ├── transactions
│ │ ├── models
│ │ │ ├── transfer.dart
│ │ │ └── transactions.dart
│ │ ├── services
│ │ │ └── transactions_services.dart
│ │ └── widgets
│ │ │ ├── transaction_details_container.dart
│ │ │ └── transactions_card.dart
│ ├── home
│ │ ├── widgets
│ │ │ ├── add_send_funds_container.dart
│ │ │ ├── send_money_found_user_details_container.dart
│ │ │ └── payment_containers.dart
│ │ └── screens
│ │ │ ├── comming_soon_screen.dart
│ │ │ └── fund_wallet_screen.dart
│ └── onboarding
│ │ └── screens
│ │ ├── widgets
│ │ └── glassmorphic_card.dart
│ │ └── onboarding_screen.dart
├── widgets
│ ├── width_space.dart
│ ├── height_space.dart
│ ├── custom_app_bar.dart
│ ├── circular_loader.dart
│ ├── border_painter.dart
│ ├── pin_input_field.dart
│ ├── number_dial_pad.dart
│ ├── alert_message.dart
│ ├── custom_button.dart
│ ├── otp_input_field.dart
│ ├── custom_textfield.dart
│ └── main_app.dart
├── config
│ ├── routes
│ │ ├── custom_push_navigators.dart
│ │ ├── page_fade_transition.dart
│ │ ├── page_slide_transition.dart
│ │ └── router.dart
│ └── theme
│ │ └── theme_manager.dart
├── initialization_screen.dart
├── no_internet_screen.dart
└── main.dart
├── .gitignore
├── LICENSE.md
├── test
└── widget_test.dart
├── analysis_options.yaml
├── .metadata
├── pubspec.yaml
└── README.md
/ios/Flutter/Debug.xcconfig:
--------------------------------------------------------------------------------
1 | #include "Generated.xcconfig"
2 |
--------------------------------------------------------------------------------
/ios/Flutter/Release.xcconfig:
--------------------------------------------------------------------------------
1 | #include "Generated.xcconfig"
2 |
--------------------------------------------------------------------------------
/ios/Runner/Runner-Bridging-Header.h:
--------------------------------------------------------------------------------
1 | #import "GeneratedPluginRegistrant.h"
2 |
--------------------------------------------------------------------------------
/android/gradle.properties:
--------------------------------------------------------------------------------
1 | org.gradle.jvmargs=-Xmx1536M
2 | android.useAndroidX=true
3 | android.enableJetifier=true
4 |
--------------------------------------------------------------------------------
/assets/images/logo.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/adedayoniyi/Pay-Mobile-P2P-Money-Transfer-App/HEAD/assets/images/logo.png
--------------------------------------------------------------------------------
/assets/icons/add_icon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/adedayoniyi/Pay-Mobile-P2P-Money-Transfer-App/HEAD/assets/icons/add_icon.png
--------------------------------------------------------------------------------
/assets/icons/card_icon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/adedayoniyi/Pay-Mobile-P2P-Money-Transfer-App/HEAD/assets/icons/card_icon.png
--------------------------------------------------------------------------------
/assets/icons/chat_icon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/adedayoniyi/Pay-Mobile-P2P-Money-Transfer-App/HEAD/assets/icons/chat_icon.png
--------------------------------------------------------------------------------
/assets/icons/home_icon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/adedayoniyi/Pay-Mobile-P2P-Money-Transfer-App/HEAD/assets/icons/home_icon.png
--------------------------------------------------------------------------------
/assets/icons/more_icon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/adedayoniyi/Pay-Mobile-P2P-Money-Transfer-App/HEAD/assets/icons/more_icon.png
--------------------------------------------------------------------------------
/assets/icons/send_icon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/adedayoniyi/Pay-Mobile-P2P-Money-Transfer-App/HEAD/assets/icons/send_icon.png
--------------------------------------------------------------------------------
/assets/icons/wifi_icon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/adedayoniyi/Pay-Mobile-P2P-Money-Transfer-App/HEAD/assets/icons/wifi_icon.png
--------------------------------------------------------------------------------
/assets/icons/bills_icon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/adedayoniyi/Pay-Mobile-P2P-Money-Transfer-App/HEAD/assets/icons/bills_icon.png
--------------------------------------------------------------------------------
/assets/icons/budget_icon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/adedayoniyi/Pay-Mobile-P2P-Money-Transfer-App/HEAD/assets/icons/budget_icon.png
--------------------------------------------------------------------------------
/assets/icons/credit_icon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/adedayoniyi/Pay-Mobile-P2P-Money-Transfer-App/HEAD/assets/icons/credit_icon.png
--------------------------------------------------------------------------------
/assets/icons/debit_icon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/adedayoniyi/Pay-Mobile-P2P-Money-Transfer-App/HEAD/assets/icons/debit_icon.png
--------------------------------------------------------------------------------
/assets/icons/info-circle.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/adedayoniyi/Pay-Mobile-P2P-Money-Transfer-App/HEAD/assets/icons/info-circle.png
--------------------------------------------------------------------------------
/assets/icons/logout_icon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/adedayoniyi/Pay-Mobile-P2P-Money-Transfer-App/HEAD/assets/icons/logout_icon.png
--------------------------------------------------------------------------------
/assets/icons/mobile_icon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/adedayoniyi/Pay-Mobile-P2P-Money-Transfer-App/HEAD/assets/icons/mobile_icon.png
--------------------------------------------------------------------------------
/assets/images/empty_list.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/adedayoniyi/Pay-Mobile-P2P-Money-Transfer-App/HEAD/assets/images/empty_list.png
--------------------------------------------------------------------------------
/assets/images/main_logo.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/adedayoniyi/Pay-Mobile-P2P-Money-Transfer-App/HEAD/assets/images/main_logo.png
--------------------------------------------------------------------------------
/assets/fonts/Comfortaa-Bold.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/adedayoniyi/Pay-Mobile-P2P-Money-Transfer-App/HEAD/assets/fonts/Comfortaa-Bold.ttf
--------------------------------------------------------------------------------
/assets/icons/notification.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/adedayoniyi/Pay-Mobile-P2P-Money-Transfer-App/HEAD/assets/icons/notification.png
--------------------------------------------------------------------------------
/assets/icons/profile_icon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/adedayoniyi/Pay-Mobile-P2P-Money-Transfer-App/HEAD/assets/icons/profile_icon.png
--------------------------------------------------------------------------------
/assets/icons/settings_icon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/adedayoniyi/Pay-Mobile-P2P-Money-Transfer-App/HEAD/assets/icons/settings_icon.png
--------------------------------------------------------------------------------
/assets/icons/shopping_icon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/adedayoniyi/Pay-Mobile-P2P-Money-Transfer-App/HEAD/assets/icons/shopping_icon.png
--------------------------------------------------------------------------------
/assets/images/error_image.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/adedayoniyi/Pay-Mobile-P2P-Money-Transfer-App/HEAD/assets/images/error_image.png
--------------------------------------------------------------------------------
/assets/images/no-internet.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/adedayoniyi/Pay-Mobile-P2P-Money-Transfer-App/HEAD/assets/images/no-internet.png
--------------------------------------------------------------------------------
/assets/fonts/Comfortaa-Medium.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/adedayoniyi/Pay-Mobile-P2P-Money-Transfer-App/HEAD/assets/fonts/Comfortaa-Medium.ttf
--------------------------------------------------------------------------------
/assets/icons/contactless_icon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/adedayoniyi/Pay-Mobile-P2P-Money-Transfer-App/HEAD/assets/icons/contactless_icon.png
--------------------------------------------------------------------------------
/assets/icons/electricity_icon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/adedayoniyi/Pay-Mobile-P2P-Money-Transfer-App/HEAD/assets/icons/electricity_icon.png
--------------------------------------------------------------------------------
/assets/images/card_chip_image.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/adedayoniyi/Pay-Mobile-P2P-Money-Transfer-App/HEAD/assets/images/card_chip_image.png
--------------------------------------------------------------------------------
/assets/images/gradient_circle.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/adedayoniyi/Pay-Mobile-P2P-Money-Transfer-App/HEAD/assets/images/gradient_circle.png
--------------------------------------------------------------------------------
/assets/fonts/Comfortaa-Regular.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/adedayoniyi/Pay-Mobile-P2P-Money-Transfer-App/HEAD/assets/fonts/Comfortaa-Regular.ttf
--------------------------------------------------------------------------------
/assets/fonts/Comfortaa-SemiBold.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/adedayoniyi/Pay-Mobile-P2P-Money-Transfer-App/HEAD/assets/fonts/Comfortaa-SemiBold.ttf
--------------------------------------------------------------------------------
/assets/icons/transactions_icon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/adedayoniyi/Pay-Mobile-P2P-Money-Transfer-App/HEAD/assets/icons/transactions_icon.png
--------------------------------------------------------------------------------
/assets/images/Pay Mobile advert.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/adedayoniyi/Pay-Mobile-P2P-Money-Transfer-App/HEAD/assets/images/Pay Mobile advert.png
--------------------------------------------------------------------------------
/assets/images/notifications_logo.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/adedayoniyi/Pay-Mobile-P2P-Money-Transfer-App/HEAD/assets/images/notifications_logo.png
--------------------------------------------------------------------------------
/assets/images/pay_mobile_advert.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/adedayoniyi/Pay-Mobile-P2P-Money-Transfer-App/HEAD/assets/images/pay_mobile_advert.png
--------------------------------------------------------------------------------
/assets/images/dialog_success_image.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/adedayoniyi/Pay-Mobile-P2P-Money-Transfer-App/HEAD/assets/images/dialog_success_image.png
--------------------------------------------------------------------------------
/assets/images/pin_feature_showcase.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/adedayoniyi/Pay-Mobile-P2P-Money-Transfer-App/HEAD/assets/images/pin_feature_showcase.png
--------------------------------------------------------------------------------
/assets/images/responsive_showcase.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/adedayoniyi/Pay-Mobile-P2P-Money-Transfer-App/HEAD/assets/images/responsive_showcase.png
--------------------------------------------------------------------------------
/assets/images/pay_mobile_full_stack.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/adedayoniyi/Pay-Mobile-P2P-Money-Transfer-App/HEAD/assets/images/pay_mobile_full_stack.png
--------------------------------------------------------------------------------
/assets/images/customer_support_showcase.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/adedayoniyi/Pay-Mobile-P2P-Money-Transfer-App/HEAD/assets/images/customer_support_showcase.png
--------------------------------------------------------------------------------
/assets/images/forgort_password_showcase.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/adedayoniyi/Pay-Mobile-P2P-Money-Transfer-App/HEAD/assets/images/forgort_password_showcase.png
--------------------------------------------------------------------------------
/assets/images/in_app_notification_image.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/adedayoniyi/Pay-Mobile-P2P-Money-Transfer-App/HEAD/assets/images/in_app_notification_image.png
--------------------------------------------------------------------------------
/assets/images/success_dialogs_showcase.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/adedayoniyi/Pay-Mobile-P2P-Money-Transfer-App/HEAD/assets/images/success_dialogs_showcase.png
--------------------------------------------------------------------------------
/assets/images/push_notification_showcase.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/adedayoniyi/Pay-Mobile-P2P-Money-Transfer-App/HEAD/assets/images/push_notification_showcase.png
--------------------------------------------------------------------------------
/assets/images/signup_verification_showcase.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/adedayoniyi/Pay-Mobile-P2P-Money-Transfer-App/HEAD/assets/images/signup_verification_showcase.png
--------------------------------------------------------------------------------
/assets/images/transaction_details_showcase.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/adedayoniyi/Pay-Mobile-P2P-Money-Transfer-App/HEAD/assets/images/transaction_details_showcase.png
--------------------------------------------------------------------------------
/assets/images/username_transfer_showcase.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/adedayoniyi/Pay-Mobile-P2P-Money-Transfer-App/HEAD/assets/images/username_transfer_showcase.png
--------------------------------------------------------------------------------
/android/app/src/main/res/drawable/background.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/adedayoniyi/Pay-Mobile-P2P-Money-Transfer-App/HEAD/android/app/src/main/res/drawable/background.png
--------------------------------------------------------------------------------
/lib/core/utils/custom_exception_handler.dart:
--------------------------------------------------------------------------------
1 | // import 'dart:io';
2 |
3 | // httpE() {
4 | // switch (HttpException) {
5 | // case SocketException:
6 | // }
7 | // }
8 |
--------------------------------------------------------------------------------
/android/app/src/main/res/drawable-hdpi/splash.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/adedayoniyi/Pay-Mobile-P2P-Money-Transfer-App/HEAD/android/app/src/main/res/drawable-hdpi/splash.png
--------------------------------------------------------------------------------
/android/app/src/main/res/drawable-mdpi/splash.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/adedayoniyi/Pay-Mobile-P2P-Money-Transfer-App/HEAD/android/app/src/main/res/drawable-mdpi/splash.png
--------------------------------------------------------------------------------
/android/app/src/main/res/drawable-xhdpi/splash.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/adedayoniyi/Pay-Mobile-P2P-Money-Transfer-App/HEAD/android/app/src/main/res/drawable-xhdpi/splash.png
--------------------------------------------------------------------------------
/android/app/src/main/res/drawable-xxhdpi/splash.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/adedayoniyi/Pay-Mobile-P2P-Money-Transfer-App/HEAD/android/app/src/main/res/drawable-xxhdpi/splash.png
--------------------------------------------------------------------------------
/assets/images/username_search_success_showcase.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/adedayoniyi/Pay-Mobile-P2P-Money-Transfer-App/HEAD/assets/images/username_search_success_showcase.png
--------------------------------------------------------------------------------
/android/app/src/main/res/drawable-v21/background.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/adedayoniyi/Pay-Mobile-P2P-Money-Transfer-App/HEAD/android/app/src/main/res/drawable-v21/background.png
--------------------------------------------------------------------------------
/android/app/src/main/res/drawable-xxxhdpi/splash.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/adedayoniyi/Pay-Mobile-P2P-Money-Transfer-App/HEAD/android/app/src/main/res/drawable-xxxhdpi/splash.png
--------------------------------------------------------------------------------
/android/app/src/main/res/mipmap-hdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/adedayoniyi/Pay-Mobile-P2P-Money-Transfer-App/HEAD/android/app/src/main/res/mipmap-hdpi/ic_launcher.png
--------------------------------------------------------------------------------
/android/app/src/main/res/mipmap-mdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/adedayoniyi/Pay-Mobile-P2P-Money-Transfer-App/HEAD/android/app/src/main/res/mipmap-mdpi/ic_launcher.png
--------------------------------------------------------------------------------
/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/adedayoniyi/Pay-Mobile-P2P-Money-Transfer-App/HEAD/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/android/app/src/main/res/drawable/notifications_logo.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/adedayoniyi/Pay-Mobile-P2P-Money-Transfer-App/HEAD/android/app/src/main/res/drawable/notifications_logo.png
--------------------------------------------------------------------------------
/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/adedayoniyi/Pay-Mobile-P2P-Money-Transfer-App/HEAD/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/adedayoniyi/Pay-Mobile-P2P-Money-Transfer-App/HEAD/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/ios/Runner/Assets.xcassets/AppIcon.appiconset/AppIcon-29.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/adedayoniyi/Pay-Mobile-P2P-Money-Transfer-App/HEAD/ios/Runner/Assets.xcassets/AppIcon.appiconset/AppIcon-29.png
--------------------------------------------------------------------------------
/ios/Runner/Assets.xcassets/AppIcon.appiconset/AppIcon@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/adedayoniyi/Pay-Mobile-P2P-Money-Transfer-App/HEAD/ios/Runner/Assets.xcassets/AppIcon.appiconset/AppIcon@2x.png
--------------------------------------------------------------------------------
/ios/Runner/Assets.xcassets/AppIcon.appiconset/AppIcon@3x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/adedayoniyi/Pay-Mobile-P2P-Money-Transfer-App/HEAD/ios/Runner/Assets.xcassets/AppIcon.appiconset/AppIcon@3x.png
--------------------------------------------------------------------------------
/android/app/src/main/res/mipmap-hdpi/ic_launcher_background.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/adedayoniyi/Pay-Mobile-P2P-Money-Transfer-App/HEAD/android/app/src/main/res/mipmap-hdpi/ic_launcher_background.png
--------------------------------------------------------------------------------
/android/app/src/main/res/mipmap-hdpi/ic_launcher_foreground.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/adedayoniyi/Pay-Mobile-P2P-Money-Transfer-App/HEAD/android/app/src/main/res/mipmap-hdpi/ic_launcher_foreground.png
--------------------------------------------------------------------------------
/android/app/src/main/res/mipmap-hdpi/ic_launcher_monochrome.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/adedayoniyi/Pay-Mobile-P2P-Money-Transfer-App/HEAD/android/app/src/main/res/mipmap-hdpi/ic_launcher_monochrome.png
--------------------------------------------------------------------------------
/android/app/src/main/res/mipmap-mdpi/ic_launcher_background.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/adedayoniyi/Pay-Mobile-P2P-Money-Transfer-App/HEAD/android/app/src/main/res/mipmap-mdpi/ic_launcher_background.png
--------------------------------------------------------------------------------
/android/app/src/main/res/mipmap-mdpi/ic_launcher_foreground.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/adedayoniyi/Pay-Mobile-P2P-Money-Transfer-App/HEAD/android/app/src/main/res/mipmap-mdpi/ic_launcher_foreground.png
--------------------------------------------------------------------------------
/android/app/src/main/res/mipmap-mdpi/ic_launcher_monochrome.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/adedayoniyi/Pay-Mobile-P2P-Money-Transfer-App/HEAD/android/app/src/main/res/mipmap-mdpi/ic_launcher_monochrome.png
--------------------------------------------------------------------------------
/ios/Runner/Assets.xcassets/AppIcon.appiconset/AppIcon-20@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/adedayoniyi/Pay-Mobile-P2P-Money-Transfer-App/HEAD/ios/Runner/Assets.xcassets/AppIcon.appiconset/AppIcon-20@2x.png
--------------------------------------------------------------------------------
/ios/Runner/Assets.xcassets/AppIcon.appiconset/AppIcon-20@3x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/adedayoniyi/Pay-Mobile-P2P-Money-Transfer-App/HEAD/ios/Runner/Assets.xcassets/AppIcon.appiconset/AppIcon-20@3x.png
--------------------------------------------------------------------------------
/ios/Runner/Assets.xcassets/AppIcon.appiconset/AppIcon-29@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/adedayoniyi/Pay-Mobile-P2P-Money-Transfer-App/HEAD/ios/Runner/Assets.xcassets/AppIcon.appiconset/AppIcon-29@2x.png
--------------------------------------------------------------------------------
/ios/Runner/Assets.xcassets/AppIcon.appiconset/AppIcon-29@3x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/adedayoniyi/Pay-Mobile-P2P-Money-Transfer-App/HEAD/ios/Runner/Assets.xcassets/AppIcon.appiconset/AppIcon-29@3x.png
--------------------------------------------------------------------------------
/ios/Runner/Assets.xcassets/AppIcon.appiconset/AppIcon-40@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/adedayoniyi/Pay-Mobile-P2P-Money-Transfer-App/HEAD/ios/Runner/Assets.xcassets/AppIcon.appiconset/AppIcon-40@2x.png
--------------------------------------------------------------------------------
/ios/Runner/Assets.xcassets/AppIcon.appiconset/AppIcon-40@3x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/adedayoniyi/Pay-Mobile-P2P-Money-Transfer-App/HEAD/ios/Runner/Assets.xcassets/AppIcon.appiconset/AppIcon-40@3x.png
--------------------------------------------------------------------------------
/ios/Runner/Assets.xcassets/AppIcon.appiconset/AppIcon~ipad.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/adedayoniyi/Pay-Mobile-P2P-Money-Transfer-App/HEAD/ios/Runner/Assets.xcassets/AppIcon.appiconset/AppIcon~ipad.png
--------------------------------------------------------------------------------
/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/adedayoniyi/Pay-Mobile-P2P-Money-Transfer-App/HEAD/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage.png
--------------------------------------------------------------------------------
/android/app/src/main/res/mipmap-xhdpi/ic_launcher_background.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/adedayoniyi/Pay-Mobile-P2P-Money-Transfer-App/HEAD/android/app/src/main/res/mipmap-xhdpi/ic_launcher_background.png
--------------------------------------------------------------------------------
/android/app/src/main/res/mipmap-xhdpi/ic_launcher_foreground.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/adedayoniyi/Pay-Mobile-P2P-Money-Transfer-App/HEAD/android/app/src/main/res/mipmap-xhdpi/ic_launcher_foreground.png
--------------------------------------------------------------------------------
/android/app/src/main/res/mipmap-xhdpi/ic_launcher_monochrome.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/adedayoniyi/Pay-Mobile-P2P-Money-Transfer-App/HEAD/android/app/src/main/res/mipmap-xhdpi/ic_launcher_monochrome.png
--------------------------------------------------------------------------------
/android/app/src/main/res/mipmap-xxhdpi/ic_launcher_background.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/adedayoniyi/Pay-Mobile-P2P-Money-Transfer-App/HEAD/android/app/src/main/res/mipmap-xxhdpi/ic_launcher_background.png
--------------------------------------------------------------------------------
/android/app/src/main/res/mipmap-xxhdpi/ic_launcher_foreground.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/adedayoniyi/Pay-Mobile-P2P-Money-Transfer-App/HEAD/android/app/src/main/res/mipmap-xxhdpi/ic_launcher_foreground.png
--------------------------------------------------------------------------------
/android/app/src/main/res/mipmap-xxhdpi/ic_launcher_monochrome.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/adedayoniyi/Pay-Mobile-P2P-Money-Transfer-App/HEAD/android/app/src/main/res/mipmap-xxhdpi/ic_launcher_monochrome.png
--------------------------------------------------------------------------------
/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher_background.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/adedayoniyi/Pay-Mobile-P2P-Money-Transfer-App/HEAD/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher_background.png
--------------------------------------------------------------------------------
/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher_foreground.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/adedayoniyi/Pay-Mobile-P2P-Money-Transfer-App/HEAD/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher_foreground.png
--------------------------------------------------------------------------------
/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher_monochrome.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/adedayoniyi/Pay-Mobile-P2P-Money-Transfer-App/HEAD/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher_monochrome.png
--------------------------------------------------------------------------------
/ios/Runner/Assets.xcassets/AppIcon.appiconset/AppIcon-20~ipad.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/adedayoniyi/Pay-Mobile-P2P-Money-Transfer-App/HEAD/ios/Runner/Assets.xcassets/AppIcon.appiconset/AppIcon-20~ipad.png
--------------------------------------------------------------------------------
/ios/Runner/Assets.xcassets/AppIcon.appiconset/AppIcon-29~ipad.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/adedayoniyi/Pay-Mobile-P2P-Money-Transfer-App/HEAD/ios/Runner/Assets.xcassets/AppIcon.appiconset/AppIcon-29~ipad.png
--------------------------------------------------------------------------------
/ios/Runner/Assets.xcassets/AppIcon.appiconset/AppIcon-40~ipad.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/adedayoniyi/Pay-Mobile-P2P-Money-Transfer-App/HEAD/ios/Runner/Assets.xcassets/AppIcon.appiconset/AppIcon-40~ipad.png
--------------------------------------------------------------------------------
/ios/Runner/Assets.xcassets/AppIcon.appiconset/AppIcon@2x~ipad.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/adedayoniyi/Pay-Mobile-P2P-Money-Transfer-App/HEAD/ios/Runner/Assets.xcassets/AppIcon.appiconset/AppIcon@2x~ipad.png
--------------------------------------------------------------------------------
/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/adedayoniyi/Pay-Mobile-P2P-Money-Transfer-App/HEAD/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@2x.png
--------------------------------------------------------------------------------
/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@3x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/adedayoniyi/Pay-Mobile-P2P-Money-Transfer-App/HEAD/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@3x.png
--------------------------------------------------------------------------------
/ios/Runner/Assets.xcassets/AppIcon.appiconset/AppIcon-20@2x~ipad.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/adedayoniyi/Pay-Mobile-P2P-Money-Transfer-App/HEAD/ios/Runner/Assets.xcassets/AppIcon.appiconset/AppIcon-20@2x~ipad.png
--------------------------------------------------------------------------------
/ios/Runner/Assets.xcassets/AppIcon.appiconset/AppIcon-29@2x~ipad.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/adedayoniyi/Pay-Mobile-P2P-Money-Transfer-App/HEAD/ios/Runner/Assets.xcassets/AppIcon.appiconset/AppIcon-29@2x~ipad.png
--------------------------------------------------------------------------------
/ios/Runner/Assets.xcassets/AppIcon.appiconset/AppIcon-40@2x~ipad.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/adedayoniyi/Pay-Mobile-P2P-Money-Transfer-App/HEAD/ios/Runner/Assets.xcassets/AppIcon.appiconset/AppIcon-40@2x~ipad.png
--------------------------------------------------------------------------------
/ios/Runner/Assets.xcassets/AppIcon.appiconset/AppIcon-60@2x~car.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/adedayoniyi/Pay-Mobile-P2P-Money-Transfer-App/HEAD/ios/Runner/Assets.xcassets/AppIcon.appiconset/AppIcon-60@2x~car.png
--------------------------------------------------------------------------------
/ios/Runner/Assets.xcassets/AppIcon.appiconset/AppIcon-60@3x~car.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/adedayoniyi/Pay-Mobile-P2P-Money-Transfer-App/HEAD/ios/Runner/Assets.xcassets/AppIcon.appiconset/AppIcon-60@3x~car.png
--------------------------------------------------------------------------------
/ios/Runner/Assets.xcassets/LaunchBackground.imageset/background.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/adedayoniyi/Pay-Mobile-P2P-Money-Transfer-App/HEAD/ios/Runner/Assets.xcassets/LaunchBackground.imageset/background.png
--------------------------------------------------------------------------------
/ios/Runner/Assets.xcassets/AppIcon.appiconset/AppIcon-83.5@2x~ipad.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/adedayoniyi/Pay-Mobile-P2P-Money-Transfer-App/HEAD/ios/Runner/Assets.xcassets/AppIcon.appiconset/AppIcon-83.5@2x~ipad.png
--------------------------------------------------------------------------------
/ios/Runner/Assets.xcassets/AppIcon.appiconset/AppIcon~ios-marketing.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/adedayoniyi/Pay-Mobile-P2P-Money-Transfer-App/HEAD/ios/Runner/Assets.xcassets/AppIcon.appiconset/AppIcon~ios-marketing.png
--------------------------------------------------------------------------------
/ios/Runner.xcodeproj/project.xcworkspace/contents.xcworkspacedata:
--------------------------------------------------------------------------------
1 |
2 |
4 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/ios/Runner.xcworkspace/contents.xcworkspacedata:
--------------------------------------------------------------------------------
1 |
2 |
4 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/android/app/src/main/kotlin/com/example/money_transfer_app/MainActivity.kt:
--------------------------------------------------------------------------------
1 | package com.example.pay_mobile_app
2 |
3 | import io.flutter.embedding.android.FlutterActivity
4 |
5 | class MainActivity: FlutterActivity() {
6 | }
7 |
--------------------------------------------------------------------------------
/android/gradle/wrapper/gradle-wrapper.properties:
--------------------------------------------------------------------------------
1 | distributionBase=GRADLE_USER_HOME
2 | distributionPath=wrapper/dists
3 | zipStoreBase=GRADLE_USER_HOME
4 | zipStorePath=wrapper/dists
5 | distributionUrl=https\://services.gradle.org/distributions/gradle-7.5-all.zip
6 |
--------------------------------------------------------------------------------
/lib/features/profile/screens/security_screen.dart:
--------------------------------------------------------------------------------
1 | import 'package:flutter/material.dart';
2 |
3 | class SecurityScreen extends StatelessWidget {
4 | const SecurityScreen({super.key});
5 |
6 | @override
7 | Widget build(BuildContext context) {
8 | return Container();
9 | }
10 | }
11 |
--------------------------------------------------------------------------------
/ios/Runner.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | PreviewsEnabled
6 |
7 |
8 |
9 |
--------------------------------------------------------------------------------
/ios/firebase_app_id_file.json:
--------------------------------------------------------------------------------
1 | {
2 | "file_generated_by": "FlutterFire CLI",
3 | "purpose": "FirebaseAppID & ProjectID for this Firebase app in this directory",
4 | "GOOGLE_APP_ID": "1:722376799583:ios:d5a7f4fabc06bc20eef2ea",
5 | "FIREBASE_PROJECT_ID": "pay-mobile-ddab3",
6 | "GCM_SENDER_ID": "722376799583"
7 | }
--------------------------------------------------------------------------------
/ios/Runner.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | IDEDidComputeMac32BitWarning
6 |
7 |
8 |
9 |
--------------------------------------------------------------------------------
/ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | PreviewsEnabled
6 |
7 |
8 |
9 |
--------------------------------------------------------------------------------
/ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | IDEDidComputeMac32BitWarning
6 |
7 |
8 |
9 |
--------------------------------------------------------------------------------
/lib/widgets/width_space.dart:
--------------------------------------------------------------------------------
1 | import 'package:flutter/material.dart';
2 |
3 | class WidthSpace extends StatelessWidget {
4 | final double width;
5 | const WidthSpace(this.width, {super.key});
6 |
7 | @override
8 | Widget build(BuildContext context) {
9 | return SizedBox(
10 | width: width,
11 | );
12 | }
13 | }
14 |
--------------------------------------------------------------------------------
/lib/widgets/height_space.dart:
--------------------------------------------------------------------------------
1 | import 'package:flutter/material.dart';
2 |
3 | class HeightSpace extends StatelessWidget {
4 | final double height;
5 | const HeightSpace(this.height, {super.key});
6 |
7 | @override
8 | Widget build(BuildContext context) {
9 | return SizedBox(
10 | height: height,
11 | );
12 | }
13 | }
14 |
--------------------------------------------------------------------------------
/android/.gitignore:
--------------------------------------------------------------------------------
1 | gradle-wrapper.jar
2 | /.gradle
3 | /captures/
4 | /gradlew
5 | /gradlew.bat
6 | /local.properties
7 | GeneratedPluginRegistrant.java
8 |
9 | # Remember to never publicly share your keystore.
10 | # See https://flutter.dev/docs/deployment/android#reference-the-keystore-from-the-app
11 | key.properties
12 | app/upload-keystore.jks
13 | **/*.keystore
14 | **/*.jks
15 |
--------------------------------------------------------------------------------
/android/app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/ios/Runner/Assets.xcassets/LaunchImage.imageset/README.md:
--------------------------------------------------------------------------------
1 | # Launch Screen Assets
2 |
3 | You can customize the launch screen with your own desired assets by replacing the image files in this directory.
4 |
5 | You can also do it by opening your Flutter project's Xcode project with `open ios/Runner.xcworkspace`, selecting `Runner/Assets.xcassets` in the Project Navigator and dropping in the desired images.
--------------------------------------------------------------------------------
/android/app/src/main/res/drawable/launch_background.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | -
4 |
5 |
6 | -
7 |
8 |
9 |
10 |
--------------------------------------------------------------------------------
/android/app/src/main/res/drawable-v21/launch_background.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | -
4 |
5 |
6 | -
7 |
8 |
9 |
10 |
--------------------------------------------------------------------------------
/lib/config/routes/custom_push_navigators.dart:
--------------------------------------------------------------------------------
1 | import 'package:flutter/material.dart';
2 |
3 | void namedNav(BuildContext context, String route) {
4 | Navigator.pushNamed(context, route);
5 | }
6 |
7 | void popNav(BuildContext context) {
8 | Navigator.pop(context);
9 | }
10 |
11 | void namedNavRemoveUntil(BuildContext context, String route) {
12 | Navigator.pushNamedAndRemoveUntil(context, route, (route) => false);
13 | }
14 |
--------------------------------------------------------------------------------
/lib/features/auth/providers/auth_provider.dart:
--------------------------------------------------------------------------------
1 | import 'package:flutter/material.dart';
2 |
3 | class AuthProvider extends ChangeNotifier {
4 | String? deviceToken;
5 | String? emailAddress;
6 |
7 | void setDeviceToken(String? token) {
8 | deviceToken = token;
9 | notifyListeners();
10 | }
11 |
12 | void setUserEmail(String? email) {
13 | emailAddress = email;
14 | notifyListeners();
15 | }
16 | }
17 |
--------------------------------------------------------------------------------
/lib/initialization_screen.dart:
--------------------------------------------------------------------------------
1 | import 'package:flutter/material.dart';
2 | import 'package:pay_mobile_app/widgets/circular_loader.dart';
3 |
4 | class InitializationScreen extends StatelessWidget {
5 | const InitializationScreen({super.key});
6 |
7 | @override
8 | Widget build(BuildContext context) {
9 | return const Scaffold(
10 | body: SafeArea(
11 | child: CircularLoader(),
12 | ),
13 | );
14 | }
15 | }
16 |
--------------------------------------------------------------------------------
/ios/Runner/Assets.xcassets/LaunchBackground.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "filename" : "background.png",
5 | "idiom" : "universal",
6 | "scale" : "1x"
7 | },
8 | {
9 | "idiom" : "universal",
10 | "scale" : "2x"
11 | },
12 | {
13 | "idiom" : "universal",
14 | "scale" : "3x"
15 | }
16 | ],
17 | "info" : {
18 | "author" : "xcode",
19 | "version" : 1
20 | }
21 | }
22 |
--------------------------------------------------------------------------------
/android/app/src/debug/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
3 |
7 |
8 |
9 |
--------------------------------------------------------------------------------
/android/app/src/profile/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
3 |
7 |
8 |
9 |
--------------------------------------------------------------------------------
/ios/Runner/AppDelegate.swift:
--------------------------------------------------------------------------------
1 | import UIKit
2 | import Flutter
3 |
4 | @UIApplicationMain
5 | @objc class AppDelegate: FlutterAppDelegate {
6 | override func application(
7 | _ application: UIApplication,
8 | didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?
9 | ) -> Bool {
10 | GeneratedPluginRegistrant.register(with: self)
11 | return super.application(application, didFinishLaunchingWithOptions: launchOptions)
12 | }
13 | }
14 |
--------------------------------------------------------------------------------
/android/settings.gradle:
--------------------------------------------------------------------------------
1 | include ':app'
2 |
3 | def localPropertiesFile = new File(rootProject.projectDir, "local.properties")
4 | def properties = new Properties()
5 |
6 | assert localPropertiesFile.exists()
7 | localPropertiesFile.withReader("UTF-8") { reader -> properties.load(reader) }
8 |
9 | def flutterSdkPath = properties.getProperty("flutter.sdk")
10 | assert flutterSdkPath != null, "flutter.sdk not set in local.properties"
11 | apply from: "$flutterSdkPath/packages/flutter_tools/gradle/app_plugin_loader.gradle"
12 |
--------------------------------------------------------------------------------
/ios/Runner/Assets.xcassets/LaunchImage.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "filename" : "LaunchImage.png",
5 | "idiom" : "universal",
6 | "scale" : "1x"
7 | },
8 | {
9 | "filename" : "LaunchImage@2x.png",
10 | "idiom" : "universal",
11 | "scale" : "2x"
12 | },
13 | {
14 | "filename" : "LaunchImage@3x.png",
15 | "idiom" : "universal",
16 | "scale" : "3x"
17 | }
18 | ],
19 | "info" : {
20 | "author" : "xcode",
21 | "version" : 1
22 | }
23 | }
24 |
--------------------------------------------------------------------------------
/lib/features/profile/providers/chat_provider.dart:
--------------------------------------------------------------------------------
1 | import 'package:flutter/material.dart';
2 | import 'package:pay_mobile_app/features/profile/models/chat_model.dart';
3 |
4 | class ChatProvider extends ChangeNotifier {
5 | ChatModel _chatModel = ChatModel(
6 | id: "",
7 | chatName: '',
8 | sender: '',
9 | receiver: '',
10 | );
11 |
12 | //creating getter for user
13 | ChatModel get chat => _chatModel;
14 |
15 | void setChatModel(String chat) {
16 | //data fromjson coming from models/user.dart
17 | _chatModel = ChatModel.fromJson(chat);
18 | notifyListeners();
19 | }
20 | }
21 |
--------------------------------------------------------------------------------
/lib/features/auth/providers/user_provider.dart:
--------------------------------------------------------------------------------
1 | import 'package:flutter/material.dart';
2 | import 'package:pay_mobile_app/features/auth/models/user.dart';
3 |
4 | class UserProvider extends ChangeNotifier {
5 | User _user = User(
6 | fullname: '',
7 | username: '',
8 | email: '',
9 | password: '',
10 | token: '',
11 | type: '',
12 | id: '',
13 | pin: '',
14 | isVerified: false,
15 | );
16 |
17 | //creating getter for user
18 | User get user => _user;
19 |
20 | void setUser(String user) {
21 | //data fromjson coming from models/user.dart
22 | _user = User.fromJson(user);
23 | notifyListeners();
24 | }
25 | }
26 |
--------------------------------------------------------------------------------
/lib/widgets/custom_app_bar.dart:
--------------------------------------------------------------------------------
1 | import 'package:flutter/material.dart';
2 | import 'package:pay_mobile_app/core/utils/global_constants.dart';
3 |
4 | class CustomAppBar extends StatelessWidget implements PreferredSizeWidget {
5 | final String image;
6 | const CustomAppBar({
7 | super.key,
8 | required this.image,
9 | });
10 |
11 | @override
12 | Widget build(BuildContext context) {
13 | return AppBar(
14 | title: Image.asset(
15 | image,
16 | height: heightValue45,
17 | // width: heightValue26,
18 | ),
19 | centerTitle: true,
20 | );
21 | }
22 |
23 | @override
24 | Size get preferredSize {
25 | return Size.fromHeight(heightValue50);
26 | }
27 | }
28 |
--------------------------------------------------------------------------------
/ios/.gitignore:
--------------------------------------------------------------------------------
1 | **/dgph
2 | *.mode1v3
3 | *.mode2v3
4 | *.moved-aside
5 | *.pbxuser
6 | *.perspectivev3
7 | **/*sync/
8 | .sconsign.dblite
9 | .tags*
10 | **/.vagrant/
11 | **/DerivedData/
12 | Icon?
13 | **/Pods/
14 | **/.symlinks/
15 | profile
16 | xcuserdata
17 | **/.generated/
18 | Flutter/App.framework
19 | Flutter/Flutter.framework
20 | Flutter/Flutter.podspec
21 | Flutter/Generated.xcconfig
22 | Flutter/ephemeral/
23 | Flutter/app.flx
24 | Flutter/app.zip
25 | Flutter/flutter_assets/
26 | Flutter/flutter_export_environment.sh
27 | ServiceDefinitions.json
28 | Runner/GeneratedPluginRegistrant.*
29 |
30 | # Exceptions to above rules.
31 | !default.mode1v3
32 | !default.mode2v3
33 | !default.pbxuser
34 | !default.perspectivev3
35 |
--------------------------------------------------------------------------------
/lib/config/routes/page_fade_transition.dart:
--------------------------------------------------------------------------------
1 | // ignore_for_file: overridden_fields
2 |
3 | import 'package:flutter/material.dart';
4 |
5 | class PageFadeTransition extends PageRouteBuilder {
6 | @override
7 | final Widget Function(BuildContext, Animation, Animation)
8 | pageBuilder;
9 | @override
10 | final RouteSettings settings;
11 |
12 | PageFadeTransition({required this.pageBuilder, required this.settings})
13 | : super(
14 | pageBuilder: pageBuilder,
15 | transitionDuration: const Duration(seconds: 1),
16 | transitionsBuilder: (_, animation, __, child) =>
17 | FadeTransition(opacity: animation, child: child),
18 | settings: settings,
19 | );
20 | }
21 |
--------------------------------------------------------------------------------
/android/build.gradle:
--------------------------------------------------------------------------------
1 | buildscript {
2 | ext.kotlin_version = '1.7.10'
3 | repositories {
4 | google()
5 | mavenCentral()
6 | }
7 |
8 | dependencies {
9 | classpath 'com.android.tools.build:gradle:7.2.0'
10 | classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
11 | classpath 'com.google.gms:google-services:4.3.15'
12 | }
13 | }
14 |
15 | allprojects {
16 | repositories {
17 | google()
18 | mavenCentral()
19 | }
20 | }
21 |
22 | rootProject.buildDir = '../build'
23 | subprojects {
24 | project.buildDir = "${rootProject.buildDir}/${project.name}"
25 | }
26 | subprojects {
27 | project.evaluationDependsOn(':app')
28 | }
29 |
30 | tasks.register("clean", Delete) {
31 | delete rootProject.buildDir
32 | }
33 |
--------------------------------------------------------------------------------
/lib/widgets/circular_loader.dart:
--------------------------------------------------------------------------------
1 | import 'package:flutter/material.dart';
2 | import 'package:pay_mobile_app/core/utils/global_constants.dart';
3 | import 'package:pay_mobile_app/core/utils/assets.dart';
4 |
5 | class CircularLoader extends StatelessWidget {
6 | const CircularLoader({super.key});
7 |
8 | @override
9 | Widget build(BuildContext context) {
10 | return Stack(
11 | children: [
12 | Center(
13 | child: Image.asset(
14 | logo,
15 | height: heightValue35,
16 | ),
17 | ),
18 | Center(
19 | child: SizedBox(
20 | height: heightValue70,
21 | width: heightValue70,
22 | child: const CircularProgressIndicator(),
23 | ),
24 | ),
25 | ],
26 | );
27 | }
28 | }
29 |
--------------------------------------------------------------------------------
/lib/config/routes/page_slide_transition.dart:
--------------------------------------------------------------------------------
1 | // ignore_for_file: overridden_fields
2 |
3 | import 'package:flutter/material.dart';
4 |
5 | class PageSlideTransition extends PageRouteBuilder {
6 | @override
7 | final Widget Function(BuildContext, Animation, Animation)
8 | pageBuilder;
9 | @override
10 | final RouteSettings settings;
11 |
12 | PageSlideTransition({required this.pageBuilder, required this.settings})
13 | : super(
14 | pageBuilder: pageBuilder,
15 | transitionDuration: const Duration(seconds: 1),
16 | transitionsBuilder: (_, animation, __, child) => SlideTransition(
17 | position: Tween(
18 | begin: const Offset(1.0, 0.0), end: const Offset(0.0, 0.0))
19 | .animate(animation),
20 | child: child,
21 | ),
22 | settings: settings,
23 | );
24 | }
25 |
--------------------------------------------------------------------------------
/ios/Flutter/AppFrameworkInfo.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | CFBundleDevelopmentRegion
6 | en
7 | CFBundleExecutable
8 | App
9 | CFBundleIdentifier
10 | io.flutter.flutter.app
11 | CFBundleInfoDictionaryVersion
12 | 6.0
13 | CFBundleName
14 | App
15 | CFBundlePackageType
16 | FMWK
17 | CFBundleShortVersionString
18 | 1.0
19 | CFBundleSignature
20 | ????
21 | CFBundleVersion
22 | 1.0
23 | MinimumOSVersion
24 | 11.0
25 |
26 |
27 |
--------------------------------------------------------------------------------
/lib/config/theme/theme_manager.dart:
--------------------------------------------------------------------------------
1 | import 'package:flutter/material.dart';
2 | import 'package:pay_mobile_app/core/utils/color_constants.dart';
3 |
4 | class ThemeManager {
5 | final darkTheme = ThemeData(
6 | fontFamily: 'Comfortaa',
7 | useMaterial3: true,
8 | colorScheme: const ColorScheme.dark(
9 | primary: primaryAppColor,
10 | background: scaffoldBackgroundColor,
11 | brightness: Brightness.dark,
12 | error: errorColor,
13 | ),
14 | appBarTheme: const AppBarTheme(
15 | backgroundColor: scaffoldBackgroundColor,
16 | surfaceTintColor: transparentColor,
17 | ),
18 | elevatedButtonTheme: ElevatedButtonThemeData(
19 | style: ElevatedButton.styleFrom(
20 | backgroundColor: primaryAppColor,
21 | ),
22 | ),
23 | );
24 |
25 | final lightTheme = ThemeData(
26 | //To be implemented later if decided
27 | );
28 | }
29 |
--------------------------------------------------------------------------------
/lib/core/error/error_handler.dart:
--------------------------------------------------------------------------------
1 | import 'dart:convert';
2 |
3 | import 'package:flutter/material.dart';
4 | import 'package:http/http.dart' as http;
5 | import 'package:pay_mobile_app/config/routes/custom_push_navigators.dart';
6 | import 'package:pay_mobile_app/core/utils/utils.dart';
7 |
8 | void statusCodeHandler({
9 | required BuildContext context,
10 | required http.Response response,
11 | required VoidCallback onSuccess,
12 | }) {
13 | switch (response.statusCode) {
14 | case 201:
15 | case 200:
16 | onSuccess();
17 | break;
18 | case 400:
19 | case 409:
20 | showErrorMessage(
21 | context: context,
22 | title: "Error",
23 | message: jsonDecode(response.body)['message'],
24 | onTap: () => popNav(context),
25 | );
26 | break;
27 | case 500:
28 | showSnackBar(context, jsonDecode(response.body));
29 | break;
30 | }
31 | }
32 |
--------------------------------------------------------------------------------
/lib/core/utils/color_constants.dart:
--------------------------------------------------------------------------------
1 |
2 | import 'package:flutter/material.dart';
3 |
4 | const primaryAppColor = Color(0xFFB3E0B8);
5 | const scaffoldBackgroundColor = Color(0xFF141318);
6 | const secondaryAppColor = Color(0xFF141318);
7 | const tertiaryAppColor = Color(0xFF8100D4);
8 | const errorColor = Colors.red;
9 | const transparentColor = Colors.transparent;
10 | const whiteColor = Color(0xFFFFFFFF);
11 | const greyScale900 = Color(0xFF010E0E);
12 | const greyScale850 = Color(0xFF333333);
13 | const greyScale800 = Color(0xFF424242);
14 | const greyScale700 = Color(0xFF616161);
15 | const greyScale600 = Color(0xFF757575);
16 | const greyScale500 = Color(0xFF9E9E9E);
17 | const greyScale400 = Color(0xFFBDBDBD);
18 | const greyScale300 = Color(0xFFE0E0E0);
19 | const greyScale200 = Color(0xFFEEEEEE);
20 | const greyScale150 = Color(0xFFF2F2F2);
21 | const greyScale100 = Color(0xFFF5F5F5);
22 | const greyScale50 = Color(0xFFFAFAFA);
23 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | # Miscellaneous
2 | *.class
3 | *.log
4 | *.pyc
5 | *.swp
6 | .DS_Store
7 | .atom/
8 | .buildlog/
9 | .history
10 | .svn/
11 | migrate_working_dir/
12 |
13 | # IntelliJ related
14 | *.iml
15 | *.ipr
16 | *.iws
17 | .idea/
18 |
19 | # The .vscode folder contains launch configuration and tasks you configure in
20 | # VS Code which you may wish to be included in version control, so this line
21 | # is commented out by default.
22 | #.vscode/
23 |
24 | # Flutter/Dart/Pub related
25 | **/doc/api/
26 | **/ios/Flutter/.last_build_id
27 | .dart_tool/
28 | .flutter-plugins
29 | .flutter-plugins-dependencies
30 | .packages
31 | .pub-cache/
32 | .pub/
33 | /build/
34 |
35 | # Symbolication related
36 | app.*.symbols
37 |
38 | # Obfuscation related
39 | app.*.map.json
40 |
41 | # Android Studio will place build artifacts here
42 | /android/app/debug
43 | /android/app/profile
44 | /android/app/release
45 |
46 | lib/firebase_options.dart
47 |
48 |
--------------------------------------------------------------------------------
/lib/features/profile/models/chat_model.dart:
--------------------------------------------------------------------------------
1 | import 'dart:convert';
2 |
3 | class ChatModel {
4 | String chatName;
5 | String sender;
6 | String receiver;
7 | String id;
8 |
9 | ChatModel({
10 | required this.chatName,
11 | required this.sender,
12 | required this.receiver,
13 | required this.id,
14 | });
15 |
16 | Map toMap() {
17 | return {
18 | 'chatName': chatName,
19 | 'sender': sender,
20 | 'receiver': receiver,
21 | 'id': id,
22 | };
23 | }
24 |
25 | factory ChatModel.fromMap(Map map) {
26 | return ChatModel(
27 | chatName: map['chatName'] ?? '',
28 | sender: map['sender'] ?? '',
29 | receiver: map['receiver'] ?? '',
30 | id: map['_id'] ?? '',
31 | );
32 | }
33 |
34 | String toJson() => json.encode(toMap());
35 |
36 | factory ChatModel.fromJson(String source) =>
37 | ChatModel.fromMap(json.decode(source));
38 | }
39 |
--------------------------------------------------------------------------------
/lib/features/transactions/models/transfer.dart:
--------------------------------------------------------------------------------
1 | import 'dart:convert';
2 |
3 | class Transfer {
4 | final String sendersUsername;
5 | final String recipientsUsername;
6 | final int amount;
7 | final String description;
8 | Transfer({
9 | required this.sendersUsername,
10 | required this.recipientsUsername,
11 | required this.amount,
12 | required this.description,
13 | });
14 |
15 | Map toMap() {
16 | return {
17 | 'sendersUsername': sendersUsername,
18 | 'recipientsUsername': recipientsUsername,
19 | 'amount': amount,
20 | 'description': description,
21 | };
22 | }
23 |
24 | factory Transfer.fromMap(Map map) {
25 | return Transfer(
26 | sendersUsername: map['sendersUsername'] ?? '',
27 | recipientsUsername: map['recipientsUsername'] ?? '',
28 | amount: map['amount']?.toInt() ?? 0,
29 | description: map['description'] ?? '',
30 | );
31 | }
32 |
33 | String toJson() => json.encode(toMap());
34 |
35 | factory Transfer.fromJson(String source) =>
36 | Transfer.fromMap(json.decode(source));
37 | }
38 |
--------------------------------------------------------------------------------
/android/app/src/main/res/values-v31/styles.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
10 |
16 |
19 |
20 |
--------------------------------------------------------------------------------
/android/app/src/main/res/values-night-v31/styles.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
10 |
16 |
19 |
20 |
--------------------------------------------------------------------------------
/LICENSE.md:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2023 Adedayo
4 |
5 | Pay Mobile - P2P Money Transfer App
6 |
7 | Permission is hereby granted, free of charge, to any person obtaining a copy
8 | of this software and associated documentation files (the "Software"), to deal
9 | in the Software without restriction, including without limitation the rights
10 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
11 | copies of the Software, and to permit persons to whom the Software is
12 | furnished to do so, subject to the following conditions:
13 |
14 | The above copyright notice and this permission notice shall be included in all
15 | copies or substantial portions of the Software.
16 |
17 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
18 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
20 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
21 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
22 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
23 | SOFTWARE.
24 |
--------------------------------------------------------------------------------
/test/widget_test.dart:
--------------------------------------------------------------------------------
1 | // This is a basic Flutter widget test.
2 | //
3 | // To perform an interaction with a widget in your test, use the WidgetTester
4 | // utility in the flutter_test package. For example, you can send tap and scroll
5 | // gestures. You can also use WidgetTester to find child widgets in the widget
6 | // tree, read text, and verify that the values of widget properties are correct.
7 |
8 | import 'package:flutter/material.dart';
9 | import 'package:flutter_test/flutter_test.dart';
10 |
11 | import 'package:pay_mobile_app/main.dart';
12 |
13 | void main() {
14 | testWidgets('Counter increments smoke test', (WidgetTester tester) async {
15 | // Build our app and trigger a frame.
16 | await tester.pumpWidget(const MyApp());
17 |
18 | // Verify that our counter starts at 0.
19 | expect(find.text('0'), findsOneWidget);
20 | expect(find.text('1'), findsNothing);
21 |
22 | // Tap the '+' icon and trigger a frame.
23 | await tester.tap(find.byIcon(Icons.add));
24 | await tester.pump();
25 |
26 | // Verify that our counter has incremented.
27 | expect(find.text('0'), findsNothing);
28 | expect(find.text('1'), findsOneWidget);
29 | });
30 | }
31 |
--------------------------------------------------------------------------------
/lib/widgets/border_painter.dart:
--------------------------------------------------------------------------------
1 | import 'package:flutter/material.dart';
2 | import 'package:pay_mobile_app/core/utils/color_constants.dart';
3 |
4 | class BorderPainter extends CustomPainter {
5 | final Color firstColor;
6 | final Color secondColor;
7 | final double borderRadius;
8 | BorderPainter({
9 | this.firstColor = primaryAppColor,
10 | this.secondColor = tertiaryAppColor,
11 | required this.borderRadius,
12 | });
13 |
14 | @override
15 | void paint(Canvas canvas, Size size) {
16 | final rect = Rect.fromLTWH(0, 0, size.width, size.height);
17 | final gradient = LinearGradient(
18 | begin: Alignment.topLeft,
19 | end: Alignment.bottomRight,
20 | colors: [
21 | firstColor,
22 | secondColor.withOpacity(0.4),
23 | ],
24 | );
25 | final paint = Paint()
26 | ..shader = gradient.createShader(rect)
27 | ..style = PaintingStyle.stroke
28 | ..strokeWidth = 2.5;
29 | canvas.drawRRect(
30 | RRect.fromRectAndRadius(
31 | rect,
32 | Radius.circular(borderRadius),
33 | ),
34 | paint,
35 | );
36 | }
37 |
38 | @override
39 | bool shouldRepaint(covariant CustomPainter oldDelegate) => false;
40 | }
41 |
--------------------------------------------------------------------------------
/ios/Runner/GoogleService-Info.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | CLIENT_ID
6 | 722376799583-bcaotvdv59pdcjld239n4msn193j3t02.apps.googleusercontent.com
7 | REVERSED_CLIENT_ID
8 | com.googleusercontent.apps.722376799583-bcaotvdv59pdcjld239n4msn193j3t02
9 | API_KEY
10 | AIzaSyCKFSKfhaBZJAfLZwrphHnZMjz7yFR9urs
11 | GCM_SENDER_ID
12 | 722376799583
13 | PLIST_VERSION
14 | 1
15 | BUNDLE_ID
16 | com.dayoniyi.peertopeermoneytransferapp
17 | PROJECT_ID
18 | pay-mobile-ddab3
19 | STORAGE_BUCKET
20 | pay-mobile-ddab3.appspot.com
21 | IS_ADS_ENABLED
22 |
23 | IS_ANALYTICS_ENABLED
24 |
25 | IS_APPINVITE_ENABLED
26 |
27 | IS_GCM_ENABLED
28 |
29 | IS_SIGNIN_ENABLED
30 |
31 | GOOGLE_APP_ID
32 | 1:722376799583:ios:d5a7f4fabc06bc20eef2ea
33 |
34 |
--------------------------------------------------------------------------------
/lib/core/utils/assets.dart:
--------------------------------------------------------------------------------
1 | const contactLessIcon = "assets/icons/contactless_icon.png";
2 | const addIcon = "assets/icons/add_icon.png";
3 | const sendIcon = "assets/icons/send_icon.png";
4 | const mobileIcon = "assets/icons/mobile_icon.png";
5 | const budgetIcon = "assets/icons/budget_icon.png";
6 | const electricityIcon = "assets/icons/electricity_icon.png";
7 | const wifiIcon = "assets/icons/wifi_icon.png";
8 | const billsIcon = "assets/icons/bills_icon.png";
9 | const moreIcon = "assets/icons/more_icon.png";
10 | const cardIcon = "assets/icons/card_icon.png";
11 | const chatIcon = "assets/icons/chat_icon.png";
12 | const homeIcon = "assets/icons/home_icon.png";
13 | const transactionsIcon = "assets/icons/transactions_icon.png";
14 | const profileIcon = "assets/icons/profile_icon.png";
15 | const creditIcon = "assets/icons/credit_icon.png";
16 | const debitIcon = "assets/icons/debit_icon.png";
17 | const infoCircle = "assets/icons/info-circle.png";
18 |
19 | const mainLogo = "assets/images/main_logo.png";
20 | const logo = "assets/images/logo.png";
21 | const gradientCircle = "assets/images/gradient_circle.png";
22 | const cardChipImage = "assets/images/card_chip_image.png";
23 | const noInternetImage = "assets/images/no-internet.png.png";
24 | const notificationsLogo = "assets/images/notifications_logo.png";
25 |
--------------------------------------------------------------------------------
/android/app/src/main/res/values/styles.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
13 |
19 |
22 |
23 |
--------------------------------------------------------------------------------
/android/app/src/main/res/values-night/styles.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
13 |
19 |
22 |
23 |
--------------------------------------------------------------------------------
/lib/widgets/pin_input_field.dart:
--------------------------------------------------------------------------------
1 |
2 | import 'package:flutter/material.dart';
3 | import 'package:pay_mobile_app/core/utils/color_constants.dart';
4 | import 'package:pay_mobile_app/core/utils/global_constants.dart';
5 |
6 | class PinInputField extends StatelessWidget {
7 | final int selectedIndex;
8 | final int index;
9 | final String pin;
10 |
11 | const PinInputField({
12 | Key? key,
13 | required this.selectedIndex,
14 | required this.index,
15 | required this.pin,
16 | }) : super(key: key);
17 |
18 | @override
19 | Widget build(BuildContext context) {
20 | return Container(
21 | alignment: Alignment.center,
22 | height: heightValue80,
23 | width: heightValue80,
24 | margin: EdgeInsets.only(right: value10),
25 | decoration: BoxDecoration(
26 | color: greyScale850,
27 | shape: BoxShape.circle,
28 | border: Border.all(
29 | color: index == selectedIndex ? primaryAppColor : Colors.transparent,
30 | width: 3,
31 | ),
32 | ),
33 | child: pin.length > index
34 | ? Container(
35 | width: value15,
36 | height: value15,
37 | decoration: const BoxDecoration(
38 | color: whiteColor,
39 | shape: BoxShape.circle,
40 | ),
41 | )
42 | : const SizedBox(),
43 | );
44 | }
45 | }
46 |
--------------------------------------------------------------------------------
/lib/core/utils/validators.dart:
--------------------------------------------------------------------------------
1 | import 'package:pay_mobile_app/core/utils/global_constants.dart';
2 |
3 | String? validateField(String? value) {
4 | if (value!.isEmpty) {
5 | return notEmptyError;
6 | }
7 | if (value.length <= 4) {
8 | return 'Must be more than 4 character';
9 | } else {
10 | return null;
11 | }
12 | }
13 |
14 | String? validateName(String? value) {
15 | if (value!.isEmpty) {
16 | return notEmptyError;
17 | }
18 | if (value.length < 3) {
19 | return 'Name must be more than 2 character';
20 | } else {
21 | return null;
22 | }
23 | }
24 |
25 | String? validateEmail(String? value) {
26 | String pattern =
27 | r'^(([^<>()[\]\\.,;:\s@\"]+(\.[^<>()[\]\\.,;:\s@\"]+)*)|(\".+\"))@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$';
28 | RegExp regex = RegExp(pattern);
29 | if (value!.isEmpty) {
30 | return notEmptyError;
31 | }
32 | if (!regex.hasMatch(value)) {
33 | return fieldNotValidError;
34 | } else {
35 | return null;
36 | }
37 | }
38 |
39 | String? validatePassword(String? value) {
40 | String pattern =
41 | r'^(?!.*(.)\1\1)(?=.*[a-z])(?=.*[A-Z])(?=.*\d)(?=.*[@$!%*?&])[A-Za-z\d@$!%*?&]{8,}$';
42 | RegExp regex = RegExp(pattern);
43 | if (value!.isEmpty) {
44 | return notEmptyError;
45 | }
46 | if (!regex.hasMatch(value)) {
47 | return fieldNotValidError;
48 | } else {
49 | return null;
50 | }
51 | }
52 |
--------------------------------------------------------------------------------
/lib/widgets/number_dial_pad.dart:
--------------------------------------------------------------------------------
1 | import 'package:flutter/material.dart';
2 | import 'package:pay_mobile_app/core/utils/color_constants.dart';
3 | import 'package:pay_mobile_app/core/utils/global_constants.dart';
4 | import 'package:pay_mobile_app/widgets/border_painter.dart';
5 |
6 | class NumberDialPad extends StatelessWidget {
7 | final VoidCallback onTap;
8 | final String numberText;
9 | const NumberDialPad({
10 | Key? key,
11 | required this.onTap,
12 | required this.numberText,
13 | }) : super(key: key);
14 |
15 | @override
16 | Widget build(BuildContext context) {
17 | return GestureDetector(
18 | onTap: onTap,
19 | child: Stack(
20 | children: [
21 | SizedBox(
22 | height: heightValue75,
23 | width: heightValue75,
24 | child: CustomPaint(
25 | painter: BorderPainter(borderRadius: heightValue75),
26 | ),
27 | ),
28 | Positioned(
29 | left: 0,
30 | right: 0,
31 | top: 10,
32 | bottom: 0,
33 | child: Text(
34 | numberText,
35 | textAlign: TextAlign.center,
36 | style: TextStyle(
37 | color: primaryAppColor,
38 | fontSize: heightValue40,
39 | fontWeight: FontWeight.w800,
40 | ),
41 | ),
42 | ),
43 | ],
44 | ),
45 | );
46 | }
47 | }
48 |
--------------------------------------------------------------------------------
/android/app/google-services.json:
--------------------------------------------------------------------------------
1 | {
2 | "project_info": {
3 | "project_number": "722376799583",
4 | "project_id": "pay-mobile-ddab3",
5 | "storage_bucket": "pay-mobile-ddab3.appspot.com"
6 | },
7 | "client": [
8 | {
9 | "client_info": {
10 | "mobilesdk_app_id": "1:722376799583:android:43a63325c4852c6deef2ea",
11 | "android_client_info": {
12 | "package_name": "com.dayoniyi.peertopeermoneytransferapp"
13 | }
14 | },
15 | "oauth_client": [
16 | {
17 | "client_id": "722376799583-rmsvi8ala4mbllt9s8m6i46ght3d35k2.apps.googleusercontent.com",
18 | "client_type": 3
19 | }
20 | ],
21 | "api_key": [
22 | {
23 | "current_key": "AIzaSyCyNchM2NEz-4cernri4WZLJq7PJdzYhhw"
24 | }
25 | ],
26 | "services": {
27 | "appinvite_service": {
28 | "other_platform_oauth_client": [
29 | {
30 | "client_id": "722376799583-rmsvi8ala4mbllt9s8m6i46ght3d35k2.apps.googleusercontent.com",
31 | "client_type": 3
32 | },
33 | {
34 | "client_id": "722376799583-bcaotvdv59pdcjld239n4msn193j3t02.apps.googleusercontent.com",
35 | "client_type": 2,
36 | "ios_info": {
37 | "bundle_id": "com.dayoniyi.peertopeermoneytransferapp"
38 | }
39 | }
40 | ]
41 | }
42 | }
43 | }
44 | ],
45 | "configuration_version": "1"
46 | }
--------------------------------------------------------------------------------
/lib/features/auth/models/user.dart:
--------------------------------------------------------------------------------
1 | import 'dart:convert';
2 |
3 | class User {
4 | final String fullname;
5 | final String username;
6 | final String email;
7 | final String password;
8 | final String token;
9 | final String type;
10 | final String id;
11 | final String pin;
12 | final bool isVerified;
13 | User({
14 | required this.fullname,
15 | required this.username,
16 | required this.email,
17 | required this.password,
18 | required this.token,
19 | required this.type,
20 | required this.id,
21 | required this.pin,
22 | required this.isVerified,
23 | });
24 |
25 | Map toMap() {
26 | return {
27 | 'fullname': fullname,
28 | 'username': username,
29 | 'email': email,
30 | 'password': password,
31 | 'token': token,
32 | 'type': type,
33 | 'id': id,
34 | 'pin': pin,
35 | 'isVerified': isVerified,
36 | };
37 | }
38 |
39 | factory User.fromMap(Map map) {
40 | return User(
41 | fullname: map['fullname'] ?? '',
42 | username: map['username'] ?? '',
43 | email: map['email'] ?? '',
44 | password: map['password'] ?? '',
45 | token: map['token'] ?? '',
46 | type: map['type'] ?? '',
47 | id: map['_id'] ?? '',
48 | pin: map['pin'] ?? '',
49 | isVerified: map['isVerified'] ?? false,
50 | );
51 | }
52 |
53 | String toJson() => json.encode(toMap());
54 |
55 | factory User.fromJson(String source) => User.fromMap(json.decode(source));
56 | }
57 |
--------------------------------------------------------------------------------
/analysis_options.yaml:
--------------------------------------------------------------------------------
1 | # This file configures the analyzer, which statically analyzes Dart code to
2 | # check for errors, warnings, and lints.
3 | #
4 | # The issues identified by the analyzer are surfaced in the UI of Dart-enabled
5 | # IDEs (https://dart.dev/tools#ides-and-editors). The analyzer can also be
6 | # invoked from the command line by running `flutter analyze`.
7 |
8 | # The following line activates a set of recommended lints for Flutter apps,
9 | # packages, and plugins designed to encourage good coding practices.
10 | include: package:flutter_lints/flutter.yaml
11 |
12 | linter:
13 | # The lint rules applied to this project can be customized in the
14 | # section below to disable rules from the `package:flutter_lints/flutter.yaml`
15 | # included above or to enable additional rules. A list of all available lints
16 | # and their documentation is published at
17 | # https://dart-lang.github.io/linter/lints/index.html.
18 | #
19 | # Instead of disabling a lint rule for the entire project in the
20 | # section below, it can also be suppressed for a single line of code
21 | # or a specific dart file by using the `// ignore: name_of_lint` and
22 | # `// ignore_for_file: name_of_lint` syntax on the line or in the file
23 | # producing the lint.
24 | rules:
25 | # avoid_print: false # Uncomment to disable the `avoid_print` rule
26 | # prefer_single_quotes: true # Uncomment to enable the `prefer_single_quotes` rule
27 |
28 | # Additional information about this file can be found at
29 | # https://dart.dev/guides/language/analysis-options
30 |
--------------------------------------------------------------------------------
/lib/features/home/widgets/add_send_funds_container.dart:
--------------------------------------------------------------------------------
1 | import 'package:flutter/material.dart';
2 | import 'package:pay_mobile_app/core/utils/color_constants.dart';
3 | import 'package:pay_mobile_app/core/utils/global_constants.dart';
4 |
5 | class AddSendFundsContainers extends StatelessWidget {
6 | final String text;
7 | final String icon;
8 | final VoidCallback onTap;
9 | const AddSendFundsContainers({
10 | Key? key,
11 | required this.text,
12 | required this.icon,
13 | required this.onTap,
14 | }) : super(key: key);
15 |
16 | @override
17 | Widget build(BuildContext context) {
18 | return GestureDetector(
19 | onTap: onTap,
20 | child: Container(
21 | height: heightValue50,
22 | width: heightValue120,
23 | decoration: BoxDecoration(
24 | borderRadius: BorderRadius.circular(heightValue20),
25 | color: primaryAppColor,
26 | ),
27 | child: Row(
28 | mainAxisAlignment: MainAxisAlignment.center,
29 | children: [
30 | Image.asset(
31 | icon,
32 | height: heightValue35,
33 | color: secondaryAppColor,
34 | ),
35 | SizedBox(
36 | width: value5,
37 | ),
38 | Text(
39 | text,
40 | style: TextStyle(
41 | fontSize: heightValue17,
42 | color: secondaryAppColor,
43 | fontWeight: FontWeight.bold,
44 | ),
45 | )
46 | ],
47 | ),
48 | ),
49 | );
50 | }
51 | }
52 |
--------------------------------------------------------------------------------
/ios/Runner/Base.lproj/Main.storyboard:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
--------------------------------------------------------------------------------
/lib/features/profile/models/message_model.dart:
--------------------------------------------------------------------------------
1 |
2 | import 'dart:convert';
3 |
4 | List messageModelFromJson(String str) => List.from(
5 | json.decode(str).map((x) => MessageModel.fromJson(x)));
6 |
7 | String messageModelToJson(List data) =>
8 | json.encode(List.from(data.map((x) => x.toJson())));
9 |
10 | class MessageModel {
11 | String id;
12 | String sender;
13 | String content;
14 | String receiver;
15 | String chat;
16 | List readBy;
17 | DateTime createdAt;
18 | DateTime updatedAt;
19 | int v;
20 |
21 | MessageModel({
22 | required this.id,
23 | required this.sender,
24 | required this.content,
25 | required this.receiver,
26 | required this.chat,
27 | required this.readBy,
28 | required this.createdAt,
29 | required this.updatedAt,
30 | required this.v,
31 | });
32 |
33 | factory MessageModel.fromJson(Map json) => MessageModel(
34 | id: json["_id"],
35 | sender: json["sender"],
36 | content: json["content"],
37 | receiver: json["receiver"],
38 | chat: json["chat"],
39 | readBy: List.from(json["readBy"].map((x) => x)),
40 | createdAt: DateTime.parse(json["createdAt"]),
41 | updatedAt: DateTime.parse(json["updatedAt"]),
42 | v: json["__v"],
43 | );
44 |
45 | Map toJson() => {
46 | "_id": id,
47 | "sender": sender,
48 | "content": content,
49 | "receiver": receiver,
50 | "chat": chat,
51 | "readBy": List.from(readBy.map((x) => x)),
52 | "createdAt": createdAt.toIso8601String(),
53 | "updatedAt": updatedAt.toIso8601String(),
54 | "__v": v,
55 | };
56 | }
57 |
--------------------------------------------------------------------------------
/.metadata:
--------------------------------------------------------------------------------
1 | # This file tracks properties of this Flutter project.
2 | # Used by Flutter tool to assess capabilities and perform upgrades etc.
3 | #
4 | # This file should be version controlled.
5 |
6 | version:
7 | revision: 2ad6cd72c040113b47ee9055e722606a490ef0da
8 | channel: stable
9 |
10 | project_type: app
11 |
12 | # Tracks metadata for the flutter migrate command
13 | migration:
14 | platforms:
15 | - platform: root
16 | create_revision: 2ad6cd72c040113b47ee9055e722606a490ef0da
17 | base_revision: 2ad6cd72c040113b47ee9055e722606a490ef0da
18 | - platform: android
19 | create_revision: 2ad6cd72c040113b47ee9055e722606a490ef0da
20 | base_revision: 2ad6cd72c040113b47ee9055e722606a490ef0da
21 | - platform: ios
22 | create_revision: 2ad6cd72c040113b47ee9055e722606a490ef0da
23 | base_revision: 2ad6cd72c040113b47ee9055e722606a490ef0da
24 | - platform: linux
25 | create_revision: 2ad6cd72c040113b47ee9055e722606a490ef0da
26 | base_revision: 2ad6cd72c040113b47ee9055e722606a490ef0da
27 | - platform: macos
28 | create_revision: 2ad6cd72c040113b47ee9055e722606a490ef0da
29 | base_revision: 2ad6cd72c040113b47ee9055e722606a490ef0da
30 | - platform: web
31 | create_revision: 2ad6cd72c040113b47ee9055e722606a490ef0da
32 | base_revision: 2ad6cd72c040113b47ee9055e722606a490ef0da
33 | - platform: windows
34 | create_revision: 2ad6cd72c040113b47ee9055e722606a490ef0da
35 | base_revision: 2ad6cd72c040113b47ee9055e722606a490ef0da
36 |
37 | # User provided section
38 |
39 | # List of Local paths (relative to this file) that should be
40 | # ignored by the migrate tool.
41 | #
42 | # Files that are not part of the templates will be ignored by default.
43 | unmanaged_files:
44 | - 'lib/main.dart'
45 | - 'ios/Runner.xcodeproj/project.pbxproj'
46 |
--------------------------------------------------------------------------------
/lib/widgets/alert_message.dart:
--------------------------------------------------------------------------------
1 | // ignore_for_file: must_be_immutable
2 |
3 | import 'package:flutter/material.dart';
4 | import 'package:pay_mobile_app/core/utils/color_constants.dart';
5 | import 'package:pay_mobile_app/core/utils/global_constants.dart';
6 | import 'package:pay_mobile_app/widgets/custom_button.dart';
7 |
8 | class AlertMessage extends StatelessWidget {
9 | final String title;
10 | final String message;
11 | final VoidCallback onTap;
12 | final String alertImage;
13 | final Color buttonColor;
14 | const AlertMessage({
15 | Key? key,
16 | required this.title,
17 | required this.message,
18 | required this.onTap,
19 | this.alertImage = "assets/images/dialog_success_image.png",
20 | this.buttonColor = defaultAppColor,
21 | }) : super(key: key);
22 |
23 | @override
24 | Widget build(BuildContext context) {
25 | return WillPopScope(
26 | onWillPop: () async => false,
27 | child: AlertDialog(
28 | backgroundColor: greyScale850,
29 | surfaceTintColor: greyScale850,
30 | icon: Image.asset(
31 | alertImage,
32 | height: heightValue100,
33 | width: heightValue100,
34 | ),
35 | title: Text(
36 | title,
37 | style: TextStyle(
38 | fontSize: value18,
39 | fontWeight: FontWeight.bold,
40 | ),
41 | ),
42 | content: Text(
43 | message,
44 | textAlign: TextAlign.center,
45 | style: TextStyle(
46 | fontSize: heightValue15,
47 | color: Colors.grey[600],
48 | ),
49 | ),
50 | actions: [
51 | CustomButton(
52 | buttonText: "Okay",
53 | onTap: onTap,
54 | buttonColor: primaryAppColor,
55 | buttonTextColor: secondaryAppColor,
56 | )
57 | ],
58 | ),
59 | );
60 | }
61 | }
62 |
--------------------------------------------------------------------------------
/lib/widgets/custom_button.dart:
--------------------------------------------------------------------------------
1 | import 'package:flutter/material.dart';
2 | import 'package:pay_mobile_app/core/utils/color_constants.dart';
3 | import 'package:pay_mobile_app/core/utils/global_constants.dart';
4 |
5 | class CustomButton extends StatelessWidget {
6 | final String buttonText;
7 | final Color buttonColor;
8 | final Color buttonTextColor;
9 | final VoidCallback onTap;
10 | final double borderRadius;
11 | final Color? borderSideColor;
12 | const CustomButton({
13 | Key? key,
14 | required this.buttonText,
15 | this.buttonColor = primaryAppColor,
16 | required this.buttonTextColor,
17 | required this.onTap,
18 | this.borderRadius = 10,
19 | this.borderSideColor = transparentColor,
20 | }) : super(key: key);
21 |
22 | @override
23 | Widget build(BuildContext context) {
24 | return ElevatedButton(
25 | onPressed: onTap,
26 | style: ButtonStyle(
27 | splashFactory: InkSplash.splashFactory,
28 | overlayColor: MaterialStatePropertyAll(
29 | whiteColor.withOpacity(0.2),
30 | ),
31 | backgroundColor: MaterialStatePropertyAll(
32 | buttonColor,
33 | ),
34 | fixedSize: MaterialStatePropertyAll(
35 | Size(screenWidth, heightValue60),
36 | ),
37 | shape: MaterialStatePropertyAll(
38 | RoundedRectangleBorder(
39 | borderRadius: BorderRadius.circular(borderRadius),
40 | side: BorderSide(
41 | color: borderSideColor!,
42 | width: 1,
43 | ),
44 | ),
45 | )),
46 | child: Center(
47 | child: Text(
48 | buttonText,
49 | style: TextStyle(
50 | fontSize: heightValue19,
51 | color: buttonTextColor,
52 | fontWeight: FontWeight.w900,
53 | ),
54 | ),
55 | ),
56 | );
57 | }
58 | }
59 |
--------------------------------------------------------------------------------
/ios/Runner/Info.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | CFBundleDevelopmentRegion
6 | $(DEVELOPMENT_LANGUAGE)
7 | CFBundleDisplayName
8 | Pay Mobile
9 | CFBundleExecutable
10 | $(EXECUTABLE_NAME)
11 | CFBundleIdentifier
12 | $(PRODUCT_BUNDLE_IDENTIFIER)
13 | CFBundleInfoDictionaryVersion
14 | 6.0
15 | CFBundleName
16 | Pay Mobile
17 | CFBundlePackageType
18 | APPL
19 | CFBundleShortVersionString
20 | $(FLUTTER_BUILD_NAME)
21 | CFBundleSignature
22 | ????
23 | CFBundleVersion
24 | $(FLUTTER_BUILD_NUMBER)
25 | LSRequiresIPhoneOS
26 |
27 | UILaunchStoryboardName
28 | LaunchScreen
29 | UIMainStoryboardFile
30 | Main
31 | UISupportedInterfaceOrientations
32 |
33 | UIInterfaceOrientationPortrait
34 | UIInterfaceOrientationLandscapeLeft
35 | UIInterfaceOrientationLandscapeRight
36 |
37 | UISupportedInterfaceOrientations~ipad
38 |
39 | UIInterfaceOrientationPortrait
40 | UIInterfaceOrientationPortraitUpsideDown
41 | UIInterfaceOrientationLandscapeLeft
42 | UIInterfaceOrientationLandscapeRight
43 |
44 | UIViewControllerBasedStatusBarAppearance
45 |
46 | CADisableMinimumFrameDurationOnPhone
47 |
48 | UIApplicationSupportsIndirectInputEvents
49 |
50 | UIStatusBarHidden
51 |
52 |
53 |
54 |
--------------------------------------------------------------------------------
/lib/core/utils/custom_notifications.dart:
--------------------------------------------------------------------------------
1 | import 'package:awesome_notifications/awesome_notifications.dart';
2 | import 'package:firebase_messaging/firebase_messaging.dart';
3 |
4 | class CustomNotifications {
5 | initInfo() async {
6 | AwesomeNotifications().initialize(
7 | null,
8 | [
9 | NotificationChannel(
10 | playSound: true,
11 | channelKey: 'Pay Mobile',
12 | channelName: 'Pay Mobile',
13 | channelDescription: 'Notification channel for Pay Mobile',
14 | //defaultColor: primaryAppColor,
15 | //ledColor: const Color(0xFF9D50DD),
16 | importance: NotificationImportance.High,
17 | icon: 'resource://drawable/notifications_logo.png',
18 | )
19 | ],
20 | );
21 |
22 | FirebaseMessaging.onMessage.listen((RemoteMessage message) async {
23 | print('..................onMessage...................');
24 | print(
25 | 'onMessage: ${message.notification?.title}/${message.notification?.body}');
26 |
27 | await AwesomeNotifications().createNotification(
28 | content: NotificationContent(
29 | id: 0,
30 | channelKey: 'Pay Mobile',
31 | title: message.notification?.title,
32 | body: message.notification?.body,
33 | largeIcon: "asset://assets/images/notifications_logo.png",
34 | ),
35 | );
36 | });
37 | }
38 |
39 | void requestPermission() async {
40 | FirebaseMessaging messaging = FirebaseMessaging.instance;
41 |
42 | NotificationSettings settings = await messaging.requestPermission(
43 | alert: true,
44 | announcement: false,
45 | badge: true,
46 | carPlay: false,
47 | criticalAlert: false,
48 | provisional: false,
49 | sound: true,
50 | );
51 |
52 | if (settings.authorizationStatus == AuthorizationStatus.authorized) {
53 | print('User granted permission');
54 | } else if (settings.authorizationStatus ==
55 | AuthorizationStatus.provisional) {
56 | print('User granted provisional permission');
57 | } else {
58 | print("User declined or has accepted permission");
59 | }
60 | }
61 | }
62 |
--------------------------------------------------------------------------------
/android/app/src/main/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
3 |
4 |
8 |
16 |
20 |
24 |
25 |
26 |
27 |
28 |
29 |
31 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
--------------------------------------------------------------------------------
/lib/features/transactions/services/transactions_services.dart:
--------------------------------------------------------------------------------
1 | // ignore_for_file: use_build_context_synchronously, avoid_print, unused_catch_clause
2 |
3 | import 'dart:async';
4 | import 'dart:convert';
5 | import 'dart:io';
6 |
7 | import 'package:flutter/material.dart';
8 | import 'package:pay_mobile_app/core/utils/global_constants.dart';
9 | import 'package:pay_mobile_app/core/utils/utils.dart';
10 | import 'package:pay_mobile_app/features/transactions/models/transactions.dart';
11 | import 'package:http/http.dart' as http;
12 | import 'package:pay_mobile_app/features/auth/providers/user_provider.dart';
13 | import 'package:provider/provider.dart';
14 |
15 | class TransactionServices {
16 | Future> getAllTransactions({
17 | required BuildContext context,
18 | }) async {
19 | List transactions = [];
20 | final username =
21 | Provider.of(context, listen: false).user.username;
22 | final userToken =
23 | Provider.of(context, listen: false).user.token;
24 | try {
25 | //showDialogLoader(context);
26 | //CircularProgressIndicator();
27 | http.Response res = await http.get(
28 | Uri.parse("$uri/api/getTransactions/$username"),
29 | headers: {
30 | "Content-Type": "application/json; charset=UTF-8",
31 | 'x-auth-token': userToken,
32 | },
33 | ).timeout(const Duration(seconds: 25));
34 | //Navigator.of(context, rootNavigator: true).pop('dialog');
35 |
36 | switch (res.statusCode) {
37 | case 200:
38 | transactions = (json.decode(res.body) as List)
39 | .map((data) => Transactions.fromJson(data))
40 | .toList();
41 | break;
42 | case 404:
43 | print("No transactions found!!");
44 | transactions = [];
45 | break;
46 | case 500:
47 | print("Get Transactions Error");
48 | }
49 | } on TimeoutException catch (e) {
50 | showTimeOutError(
51 | context: context,
52 | );
53 | } on SocketException catch (e) {
54 | showNoInternetError(
55 | context: context,
56 | );
57 | } on Error catch (e) {
58 | print('Get All Transactions Error: $e');
59 | }
60 | return transactions;
61 | }
62 | }
63 |
--------------------------------------------------------------------------------
/lib/features/transactions/models/transactions.dart:
--------------------------------------------------------------------------------
1 | // To parse this JSON data, do
2 | //
3 | // final transactions = transactionsFromJson(jsonString);
4 |
5 | import 'dart:convert';
6 |
7 | List transactionsFromJson(String str) => List.from(
8 | json.decode(str).map((x) => Transactions.fromJson(x)));
9 |
10 | String transactionsToJson(List data) =>
11 | json.encode(List.from(data.map((x) => x.toJson())));
12 |
13 | class Transactions {
14 | Transactions({
15 | required this.trnxType,
16 | required this.purpose,
17 | required this.amount,
18 | required this.username,
19 | required this.reference,
20 | required this.balanceBefore,
21 | required this.balanceAfter,
22 | required this.description,
23 | required this.fullNameTransactionEntity,
24 | required this.createdAt,
25 | required this.updatedAt,
26 | });
27 |
28 | String trnxType;
29 | String purpose;
30 | int amount;
31 | String username;
32 | String reference;
33 | int balanceBefore;
34 | int balanceAfter;
35 | String fullNameTransactionEntity;
36 | String description;
37 | DateTime createdAt;
38 | DateTime updatedAt;
39 |
40 | factory Transactions.fromJson(Map json) => Transactions(
41 | trnxType: json["trnxType"],
42 | purpose: json["purpose"],
43 | amount: json["amount"],
44 | username: json["username"],
45 | reference: json["reference"],
46 | balanceBefore: json["balanceBefore"],
47 | balanceAfter: json["balanceAfter"],
48 | fullNameTransactionEntity: json["fullNameTransactionEntity"],
49 | description: json["description"],
50 | createdAt: DateTime.parse(json["createdAt"]),
51 | updatedAt: DateTime.parse(json["updatedAt"]),
52 | );
53 |
54 | Map toJson() => {
55 | "trnxType": trnxType,
56 | "purpose": purpose,
57 | "amount": amount,
58 | "username": username,
59 | "reference": reference,
60 | "balanceBefore": balanceBefore,
61 | "balanceAfter": balanceAfter,
62 | "fullNameTransactionEntity": fullNameTransactionEntity,
63 | "description": description,
64 | "createdAt": createdAt.toIso8601String(),
65 | "updatedAt": updatedAt.toIso8601String(),
66 | };
67 | }
68 |
--------------------------------------------------------------------------------
/lib/no_internet_screen.dart:
--------------------------------------------------------------------------------
1 | import 'package:flutter/material.dart';
2 | import 'package:pay_mobile_app/core/utils/assets.dart';
3 | import 'package:pay_mobile_app/core/utils/color_constants.dart';
4 | import 'package:pay_mobile_app/core/utils/global_constants.dart';
5 | import 'package:pay_mobile_app/widgets/custom_button.dart';
6 |
7 | class NoInternetScreen extends StatelessWidget {
8 | final VoidCallback onTap;
9 | const NoInternetScreen({
10 | super.key,
11 | required this.onTap,
12 | });
13 |
14 | @override
15 | Widget build(BuildContext context) {
16 | return Scaffold(
17 | body: SafeArea(
18 | child: Stack(
19 | children: [
20 | Center(
21 | child: Padding(
22 | padding: EdgeInsets.symmetric(horizontal: value30),
23 | child: Column(
24 | mainAxisAlignment: MainAxisAlignment.center,
25 | children: [
26 | Image.asset(
27 | noInternetImage,
28 | height: heightValue150,
29 | color: Colors.red,
30 | ),
31 | SizedBox(
32 | height: heightValue20,
33 | ),
34 | const Text("Please connect to the internet"),
35 | SizedBox(
36 | height: heightValue50,
37 | ),
38 | CustomButton(
39 | buttonText: "Try Again",
40 | buttonColor: primaryAppColor,
41 | buttonTextColor: whiteColor,
42 | onTap: () {
43 | onTap();
44 | })
45 | ],
46 | ),
47 | ),
48 | ),
49 | Align(
50 | alignment: Alignment.topCenter,
51 | child: Padding(
52 | padding: EdgeInsets.only(top: heightValue30),
53 | child: Column(
54 | children: [
55 | Image.asset(
56 | "assets/images/full_logo.png",
57 | height: value100,
58 | ),
59 | ],
60 | ),
61 | ),
62 | ),
63 | ],
64 | ),
65 | ),
66 | );
67 | }
68 | }
69 |
--------------------------------------------------------------------------------
/lib/widgets/otp_input_field.dart:
--------------------------------------------------------------------------------
1 | import 'package:flutter/material.dart';
2 | import 'package:pay_mobile_app/core/utils/color_constants.dart';
3 | import 'package:pay_mobile_app/core/utils/global_constants.dart';
4 |
5 | class OtpCodeInputField extends StatefulWidget {
6 | final TextEditingController controller;
7 | final Color fillColor;
8 | const OtpCodeInputField({
9 | Key? key,
10 | required this.controller,
11 | this.fillColor = greyScale850,
12 | }) : super(key: key);
13 |
14 | @override
15 | State createState() => _OtpCodeInputFieldState();
16 | }
17 |
18 | class _OtpCodeInputFieldState extends State {
19 | @override
20 | Widget build(BuildContext context) {
21 | return TextFormField(
22 | controller: widget.controller,
23 | style: TextStyle(fontSize: heightValue25),
24 | decoration: InputDecoration(
25 | floatingLabelBehavior: FloatingLabelBehavior.never,
26 | border: OutlineInputBorder(
27 | borderSide: BorderSide(
28 | color: widget.fillColor,
29 | ),
30 | borderRadius: BorderRadius.circular(heightValue10),
31 | ),
32 | enabledBorder: OutlineInputBorder(
33 | borderSide: BorderSide(
34 | color: widget.fillColor,
35 | ),
36 | borderRadius: BorderRadius.circular(heightValue10),
37 | ),
38 | focusedBorder: OutlineInputBorder(
39 | borderSide: const BorderSide(
40 | color: primaryAppColor,
41 | width: 2,
42 | ),
43 | borderRadius: BorderRadius.circular(heightValue10),
44 | ),
45 | isDense: true,
46 | counterText: '',
47 | contentPadding: EdgeInsets.all(heightValue10),
48 | filled: true,
49 | fillColor: widget.fillColor,
50 | ),
51 | keyboardType: TextInputType.number,
52 | validator: (value) {
53 | if (value!.isEmpty) {
54 | return notEmptyError;
55 | }
56 | return null;
57 | },
58 | onChanged: (value) {
59 | if (value.length == 1) {
60 | FocusScope.of(context).nextFocus();
61 | }
62 | if (value.isEmpty) {
63 | FocusScope.of(context).previousFocus();
64 | }
65 | },
66 | autofocus: true,
67 | showCursor: false,
68 | textAlign: TextAlign.center,
69 | maxLength: 1,
70 | );
71 | }
72 | }
73 |
--------------------------------------------------------------------------------
/lib/features/home/screens/comming_soon_screen.dart:
--------------------------------------------------------------------------------
1 | import 'package:flutter/material.dart';
2 | import 'package:pay_mobile_app/core/utils/global_constants.dart';
3 | import 'package:pay_mobile_app/core/utils/assets.dart';
4 | import 'package:pay_mobile_app/widgets/border_painter.dart';
5 | import 'package:pay_mobile_app/widgets/height_space.dart';
6 |
7 | class CommingSoonScreen extends StatelessWidget {
8 | static const String route = "/comming-soon-screen";
9 | const CommingSoonScreen({super.key});
10 |
11 | @override
12 | Widget build(BuildContext context) {
13 | return Scaffold(
14 | appBar: AppBar(),
15 | body: Padding(
16 | padding: EdgeInsets.symmetric(horizontal: value30),
17 | child: Column(
18 | children: [
19 | HeightSpace(heightValue30),
20 | Image.asset(
21 | mainLogo,
22 | height: heightValue130,
23 | ),
24 | HeightSpace(heightValue20),
25 | Text(
26 | "Comming Soon",
27 | style: TextStyle(
28 | fontSize: value25,
29 | fontWeight: FontWeight.bold,
30 | ),
31 | ),
32 | HeightSpace(heightValue20),
33 | Stack(
34 | children: [
35 | Positioned(
36 | top: 70,
37 | bottom: 0,
38 | left: 0,
39 | right: 0,
40 | child: Text(
41 | "Coming Soon",
42 | style: TextStyle(
43 | fontWeight: FontWeight.w900,
44 | fontSize: heightValue35,
45 | ),
46 | textAlign: TextAlign.center,
47 | ),
48 | ),
49 | SizedBox(
50 | height: heightValue200,
51 | width: screenWidth,
52 | child: CustomPaint(
53 | painter: BorderPainter(borderRadius: heightValue20),
54 | ),
55 | ),
56 | ],
57 | ),
58 | HeightSpace(heightValue40),
59 | Text(
60 | "This feature is Comming Soon. Stay tuned",
61 | textAlign: TextAlign.center,
62 | style: TextStyle(
63 | fontSize: value25,
64 | fontWeight: FontWeight.bold,
65 | ),
66 | ),
67 | ],
68 | ),
69 | ),
70 | );
71 | }
72 | }
73 |
--------------------------------------------------------------------------------
/lib/features/auth/screens/create_new_password_screen.dart:
--------------------------------------------------------------------------------
1 | import 'package:flutter/material.dart';
2 | import 'package:pay_mobile_app/core/utils/global_constants.dart';
3 | import 'package:pay_mobile_app/core/utils/assets.dart';
4 | import 'package:pay_mobile_app/core/utils/validators.dart';
5 | import 'package:pay_mobile_app/features/auth/services/auth_service.dart';
6 | import 'package:pay_mobile_app/widgets/custom_app_bar.dart';
7 | import 'package:pay_mobile_app/widgets/custom_textfield.dart';
8 | import 'package:pay_mobile_app/widgets/height_space.dart';
9 |
10 | class CreateNewPasswordScreen extends StatefulWidget {
11 | static const String route = "/create-new-password";
12 | const CreateNewPasswordScreen({super.key});
13 |
14 | @override
15 | State createState() =>
16 | _CreateNewPasswordScreenState();
17 | }
18 |
19 | class _CreateNewPasswordScreenState extends State {
20 | final createNewPasswordFormKey = GlobalKey();
21 | final AuthService authService = AuthService();
22 | final TextEditingController passwordController = TextEditingController();
23 | final TextEditingController confirmPasswordController =
24 | TextEditingController();
25 |
26 | @override
27 | Widget build(BuildContext context) {
28 | return Scaffold(
29 | appBar: const CustomAppBar(image: logo),
30 | body: screenUI(),
31 | );
32 | }
33 |
34 | void createNewPassword() {
35 | if (createNewPasswordFormKey.currentState!.validate()) {
36 | if (passwordController.text == confirmPasswordController.text) {
37 | authService.createNewPassword(
38 | context: context,
39 | password: passwordController.text,
40 | confirmPassword: confirmPasswordController.text,
41 | );
42 | }
43 | }
44 | }
45 |
46 | Widget screenUI() {
47 | return Form(
48 | key: createNewPasswordFormKey,
49 | child: Column(
50 | children: [
51 | HeightSpace(heightValue10),
52 | const Text("Create New Password"),
53 | CustomTextField(
54 | hintText: "Enter your password",
55 | controller: passwordController,
56 | labelText: "Password",
57 | validator: validateField,
58 | ),
59 | CustomTextField(
60 | hintText: "Enter your password",
61 | controller: confirmPasswordController,
62 | labelText: "ConfirmPassword",
63 | validator: validateField,
64 | ),
65 | ],
66 | ),
67 | );
68 | }
69 | }
70 |
--------------------------------------------------------------------------------
/lib/features/home/widgets/send_money_found_user_details_container.dart:
--------------------------------------------------------------------------------
1 | import 'package:flutter/material.dart';
2 |
3 | import 'package:pay_mobile_app/core/utils/global_constants.dart';
4 | import 'package:pay_mobile_app/widgets/border_painter.dart';
5 |
6 | class SendMoneyFoundUserDetailsContainer extends StatelessWidget {
7 | final String circleAvatarText;
8 | final String userFullName;
9 | final String userName;
10 | const SendMoneyFoundUserDetailsContainer({
11 | Key? key,
12 | required this.circleAvatarText,
13 | required this.userFullName,
14 | required this.userName,
15 | }) : super(key: key);
16 |
17 | @override
18 | Widget build(BuildContext context) {
19 | return Stack(
20 | children: [
21 | Container(
22 | width: screenWidth,
23 | height: heightValue80,
24 | decoration: BoxDecoration(
25 | borderRadius: BorderRadius.circular(heightValue20),
26 | ),
27 | child: CustomPaint(
28 | painter: BorderPainter(borderRadius: heightValue20),
29 | )),
30 | Positioned(
31 | top: 0,
32 | bottom: 0,
33 | child: Row(
34 | children: [
35 | SizedBox(
36 | width: value20,
37 | ),
38 | CircleAvatar(
39 | radius: heightValue25,
40 | child: Center(
41 | child: Text(
42 | circleAvatarText,
43 | style: TextStyle(
44 | fontSize: heightValue23,
45 | fontWeight: FontWeight.bold,
46 | ),
47 | ),
48 | ),
49 | ),
50 | SizedBox(
51 | width: value25,
52 | ),
53 | Column(
54 | mainAxisAlignment: MainAxisAlignment.center,
55 | crossAxisAlignment: CrossAxisAlignment.start,
56 | children: [
57 | Text(
58 | userFullName,
59 | style: TextStyle(
60 | fontSize: heightValue23,
61 | fontWeight: FontWeight.bold,
62 | ),
63 | ),
64 | Text(
65 | userName,
66 | style: TextStyle(
67 | fontSize: heightValue18,
68 | ),
69 | ),
70 | ],
71 | ),
72 | ],
73 | ),
74 | ),
75 | ],
76 | );
77 | }
78 | }
79 |
--------------------------------------------------------------------------------
/lib/features/profile/widgets/receivers_message_card.dart.dart:
--------------------------------------------------------------------------------
1 | import 'package:flutter/material.dart';
2 | import 'package:pay_mobile_app/core/utils/color_constants.dart';
3 | import 'package:pay_mobile_app/core/utils/global_constants.dart';
4 | import 'package:pay_mobile_app/widgets/height_space.dart';
5 |
6 | class ReceiversMessageCard extends StatelessWidget {
7 | final String message;
8 | final String dateTime;
9 | final String user;
10 | const ReceiversMessageCard({
11 | Key? key,
12 | required this.message,
13 | required this.dateTime,
14 | required this.user,
15 | }) : super(key: key);
16 |
17 | @override
18 | Widget build(BuildContext context) {
19 | return Align(
20 | alignment: Alignment.bottomLeft,
21 | child: ConstrainedBox(
22 | constraints: BoxConstraints(
23 | maxWidth: MediaQuery.of(context).size.width - value48,
24 | ),
25 | child: Padding(
26 | padding: EdgeInsets.only(
27 | left: value20,
28 | top: heightValue10,
29 | ),
30 | child: Container(
31 | decoration: BoxDecoration(
32 | borderRadius: BorderRadius.circular(15),
33 | color: const Color(0xFFb9b6c1),
34 | ),
35 | child: Padding(
36 | padding: EdgeInsets.symmetric(
37 | horizontal: heightValue10, vertical: value10),
38 | child: Column(
39 | crossAxisAlignment: CrossAxisAlignment.start,
40 | children: [
41 | Text(
42 | user,
43 | style: TextStyle(
44 | color: Colors.red,
45 | fontSize: heightValue15,
46 | fontWeight: FontWeight.bold,
47 | ),
48 | ),
49 | HeightSpace(heightValue10),
50 | Text(
51 | message,
52 | style: TextStyle(
53 | color: secondaryAppColor,
54 | fontSize: heightValue18,
55 | fontWeight: FontWeight.bold,
56 | ),
57 | ),
58 | HeightSpace(heightValue5),
59 | Text(
60 | dateTime,
61 | style: TextStyle(
62 | color: secondaryAppColor,
63 | fontSize: heightValue13,
64 | ),
65 | ),
66 | ],
67 | ),
68 | ),
69 | ),
70 | ),
71 | ),
72 | );
73 | }
74 | }
75 |
--------------------------------------------------------------------------------
/lib/features/profile/widgets/senders_message_card.dart:
--------------------------------------------------------------------------------
1 | import 'package:flutter/material.dart';
2 | import 'package:pay_mobile_app/core/utils/color_constants.dart';
3 | import 'package:pay_mobile_app/core/utils/global_constants.dart';
4 | import 'package:pay_mobile_app/widgets/height_space.dart';
5 |
6 | class SendersMessageCard extends StatelessWidget {
7 | final String message;
8 | final String dateTime;
9 | final String user;
10 |
11 | const SendersMessageCard({
12 | Key? key,
13 | required this.message,
14 | required this.dateTime,
15 | required this.user,
16 | }) : super(key: key);
17 |
18 | @override
19 | Widget build(BuildContext context) {
20 | return Align(
21 | alignment: Alignment.bottomRight,
22 | child: ConstrainedBox(
23 | constraints: BoxConstraints(
24 | maxWidth: MediaQuery.of(context).size.width - value48,
25 | ),
26 | child: Padding(
27 | padding: EdgeInsets.only(
28 | right: value20,
29 | top: heightValue15,
30 | ),
31 | child: Container(
32 | decoration: BoxDecoration(
33 | borderRadius: BorderRadius.circular(15),
34 | color: const Color(0xFFb8c2b7),
35 | ),
36 | child: Padding(
37 | padding: EdgeInsets.symmetric(
38 | horizontal: value10, vertical: heightValue10),
39 | child: Column(
40 | crossAxisAlignment: CrossAxisAlignment.start,
41 | children: [
42 | Text(
43 | user,
44 | style: TextStyle(
45 | color: tertiaryAppColor,
46 | fontSize: heightValue13,
47 | fontWeight: FontWeight.bold,
48 | ),
49 | ),
50 | HeightSpace(heightValue10),
51 | Text(
52 | message,
53 | style: TextStyle(
54 | color: secondaryAppColor,
55 | fontSize: heightValue18,
56 | fontWeight: FontWeight.bold,
57 | ),
58 | ),
59 | HeightSpace(heightValue5),
60 | Text(
61 | dateTime,
62 | style: TextStyle(
63 | color: secondaryAppColor,
64 | fontSize: heightValue13,
65 | ),
66 | ),
67 | ],
68 | ),
69 | ),
70 | ),
71 | ),
72 | ),
73 | );
74 | }
75 | }
76 |
--------------------------------------------------------------------------------
/lib/features/home/widgets/payment_containers.dart:
--------------------------------------------------------------------------------
1 | import 'dart:ui';
2 |
3 | import 'package:flutter/material.dart';
4 |
5 | import 'package:pay_mobile_app/core/utils/color_constants.dart';
6 | import 'package:pay_mobile_app/core/utils/global_constants.dart';
7 | import 'package:pay_mobile_app/widgets/border_painter.dart';
8 |
9 | class PaymentContainers extends StatelessWidget {
10 | final String icon;
11 | final Color color;
12 | final String text;
13 | const PaymentContainers({
14 | Key? key,
15 | required this.icon,
16 | required this.color,
17 | required this.text,
18 | }) : super(key: key);
19 |
20 | @override
21 | Widget build(BuildContext context) {
22 | return SizedBox(
23 | child: Stack(
24 | children: [
25 | // Positioned(
26 | // right: 20,
27 | // bottom: 40,
28 | // child: Image.asset(
29 | // gradientCircle,
30 | // height: heightValue50,
31 | // ),
32 | // ),
33 | Padding(
34 | padding: EdgeInsets.only(right: value10),
35 | child: ClipRRect(
36 | borderRadius: BorderRadius.circular(heightValue20),
37 | child: BackdropFilter(
38 | filter: ImageFilter.blur(sigmaX: 7, sigmaY: 5),
39 | child: Container(
40 | height: heightValue140,
41 | width: heightValue120,
42 | decoration: BoxDecoration(
43 | borderRadius: BorderRadius.circular(heightValue15),
44 | border: Border.all(
45 | color: Colors.white.withOpacity(0.2),
46 | width: 1.0,
47 | ),
48 | ),
49 | child: CustomPaint(
50 | painter: BorderPainter(
51 | firstColor: primaryAppColor,
52 | secondColor: tertiaryAppColor,
53 | borderRadius: heightValue20,
54 | ),
55 | ),
56 | ),
57 | ),
58 | ),
59 | ),
60 | Positioned(
61 | top: 10,
62 | left: 10,
63 | child: Image.asset(
64 | icon,
65 | color: whiteColor,
66 | height: heightValue33,
67 | ),
68 | ),
69 | Positioned(
70 | bottom: 10,
71 | left: 10,
72 | child: Text(
73 | text,
74 | style: TextStyle(
75 | fontWeight: FontWeight.bold,
76 | fontSize: heightValue17,
77 | ),
78 | ),
79 | )
80 | ],
81 | ),
82 | );
83 | }
84 | }
85 |
--------------------------------------------------------------------------------
/lib/features/transactions/widgets/transaction_details_container.dart:
--------------------------------------------------------------------------------
1 | import 'package:flutter/material.dart';
2 | import 'package:pay_mobile_app/core/utils/color_constants.dart';
3 |
4 | import 'package:pay_mobile_app/core/utils/global_constants.dart';
5 |
6 | class TransactionDetailsContainer extends StatelessWidget {
7 | final String label;
8 | final String content;
9 | final Color amountColor;
10 | final bool isRow;
11 | final bool isAmount;
12 | const TransactionDetailsContainer({
13 | Key? key,
14 | required this.label,
15 | required this.content,
16 | this.amountColor = defaultAppColor,
17 | this.isRow = false,
18 | this.isAmount = false,
19 | }) : super(key: key);
20 |
21 | @override
22 | Widget build(BuildContext context) {
23 | return Padding(
24 | padding: EdgeInsets.only(bottom: heightValue15),
25 | child: Container(
26 | width: screenWidth,
27 | height: heightValue100,
28 | decoration: BoxDecoration(
29 | borderRadius: BorderRadius.circular(heightValue10),
30 | color: greyScale850,
31 | ),
32 | child: Padding(
33 | padding: EdgeInsets.only(left: value10),
34 | child: Column(
35 | mainAxisAlignment: MainAxisAlignment.center,
36 | crossAxisAlignment: CrossAxisAlignment.start,
37 | children: [
38 | Text(
39 | label,
40 | style: TextStyle(
41 | fontSize: heightValue15,
42 | fontWeight: FontWeight.bold,
43 | ),
44 | ),
45 | isRow
46 | ? Row(
47 | children: [
48 | Image.asset(
49 | "assets/images/dialog_success_image.png",
50 | height: heightValue25,
51 | ),
52 | SizedBox(
53 | width: value5,
54 | ),
55 | Text(
56 | content,
57 | style: TextStyle(
58 | fontSize: heightValue24,
59 | color: primaryAppColor,
60 | ),
61 | ),
62 | ],
63 | )
64 | : Text(
65 | content,
66 | style: TextStyle(
67 | fontSize: heightValue24,
68 | color: primaryAppColor,
69 | fontWeight:
70 | isAmount ? FontWeight.bold : FontWeight.normal,
71 | ),
72 | )
73 | ],
74 | ),
75 | ),
76 | ),
77 | );
78 | }
79 | }
80 |
--------------------------------------------------------------------------------
/android/app/build.gradle:
--------------------------------------------------------------------------------
1 | def localProperties = new Properties()
2 | def localPropertiesFile = rootProject.file('local.properties')
3 | if (localPropertiesFile.exists()) {
4 | localPropertiesFile.withReader('UTF-8') { reader ->
5 | localProperties.load(reader)
6 | }
7 | }
8 |
9 | def flutterRoot = localProperties.getProperty('flutter.sdk')
10 | if (flutterRoot == null) {
11 | throw new GradleException("Flutter SDK not found. Define location with flutter.sdk in the local.properties file.")
12 | }
13 |
14 | def flutterVersionCode = localProperties.getProperty('flutter.versionCode')
15 | if (flutterVersionCode == null) {
16 | flutterVersionCode = '1'
17 | }
18 |
19 | def flutterVersionName = localProperties.getProperty('flutter.versionName')
20 | if (flutterVersionName == null) {
21 | flutterVersionName = '1.0'
22 | }
23 |
24 | apply plugin: 'com.android.application'
25 | apply plugin: 'kotlin-android'
26 | apply from: "$flutterRoot/packages/flutter_tools/gradle/flutter.gradle"
27 |
28 | def keystoreProperties = new Properties()
29 | def keystorePropertiesFile = rootProject.file('key.properties')
30 | if (keystorePropertiesFile.exists()) {
31 | keystoreProperties.load(new FileInputStream(keystorePropertiesFile))
32 | }
33 |
34 |
35 | android {
36 | compileSdkVersion 33
37 | ndkVersion flutter.ndkVersion
38 |
39 | compileOptions {
40 | sourceCompatibility JavaVersion.VERSION_1_8
41 | targetCompatibility JavaVersion.VERSION_1_8
42 | }
43 |
44 | kotlinOptions {
45 | jvmTarget = '1.8'
46 | }
47 |
48 | sourceSets {
49 | main.java.srcDirs += 'src/main/kotlin'
50 | }
51 |
52 | defaultConfig {
53 | // TODO: Specify your own unique Application ID (https://developer.android.com/studio/build/application-id.html).
54 | applicationId "com.dayoniyi.peertopeermoneytransferapp"
55 | // You can update the following values to match your application needs.
56 | // For more information, see: https://docs.flutter.dev/deployment/android#reviewing-the-gradle-build-configuration.
57 | minSdkVersion 21
58 | targetSdkVersion flutter.targetSdkVersion
59 | versionCode flutterVersionCode.toInteger()
60 | versionName flutterVersionName
61 | multiDexEnabled true
62 | }
63 |
64 | signingConfigs {
65 | release {
66 | keyAlias keystoreProperties['keyAlias']
67 | keyPassword keystoreProperties['keyPassword']
68 | storeFile keystoreProperties['storeFile'] ? file(keystoreProperties['storeFile']) : null
69 | storePassword keystoreProperties['storePassword']
70 | }
71 | }
72 | buildTypes {
73 | release {
74 | signingConfig signingConfigs.release
75 | shrinkResources false
76 | minifyEnabled false
77 | }
78 | }
79 |
80 | }
81 |
82 | flutter {
83 | source '../..'
84 | }
85 |
86 | dependencies {
87 | implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version"
88 | implementation 'com.android.support:multidex:1.0.3'
89 | }
90 |
91 |
92 |
--------------------------------------------------------------------------------
/lib/features/profile/widgets/profile_card.dart:
--------------------------------------------------------------------------------
1 | import 'package:flutter/material.dart';
2 | import 'package:pay_mobile_app/core/utils/color_constants.dart';
3 |
4 | import 'package:pay_mobile_app/core/utils/global_constants.dart';
5 |
6 | class ProfileCard extends StatelessWidget {
7 | final String iconImage;
8 | final String profileOperation;
9 | final String profileOperationDescription;
10 | final VoidCallback onPressed;
11 | const ProfileCard({
12 | Key? key,
13 | required this.iconImage,
14 | required this.profileOperation,
15 | required this.profileOperationDescription,
16 | required this.onPressed,
17 | }) : super(key: key);
18 |
19 | @override
20 | Widget build(BuildContext context) {
21 | return GestureDetector(
22 | onTap: onPressed,
23 | child: Container(
24 | height: heightValue80,
25 | width: screenWidth,
26 | decoration: BoxDecoration(
27 | borderRadius: BorderRadius.circular(heightValue20),
28 | color: greyScale850,
29 | ),
30 | child: Padding(
31 | padding: EdgeInsets.symmetric(horizontal: value20),
32 | child: Row(
33 | mainAxisAlignment: MainAxisAlignment.spaceBetween,
34 | crossAxisAlignment: CrossAxisAlignment.center,
35 | children: [
36 | Row(
37 | children: [
38 | Container(
39 | height: heightValue55,
40 | width: heightValue55,
41 | decoration: BoxDecoration(
42 | borderRadius: BorderRadius.circular(value10),
43 | color: secondaryAppColor,
44 | ),
45 | child: Center(
46 | child: Image.asset(
47 | iconImage,
48 | height: heightValue25,
49 | color: primaryAppColor,
50 | ),
51 | ),
52 | ),
53 | Padding(
54 | padding: EdgeInsets.only(left: value20),
55 | child: Center(
56 | child: Column(
57 | mainAxisAlignment: MainAxisAlignment.center,
58 | crossAxisAlignment: CrossAxisAlignment.start,
59 | children: [
60 | Text(
61 | profileOperation,
62 | style: TextStyle(
63 | fontWeight: FontWeight.bold,
64 | fontSize: heightValue20,
65 | ),
66 | ),
67 | Text(
68 | profileOperationDescription,
69 | style: TextStyle(
70 | fontSize: heightValue15,
71 | ),
72 | overflow: TextOverflow.ellipsis,
73 | )
74 | ],
75 | ),
76 | ),
77 | ),
78 | ],
79 | ),
80 | const Icon(Icons.arrow_forward)
81 | ],
82 | ),
83 | ),
84 | ),
85 | );
86 | }
87 | }
88 |
--------------------------------------------------------------------------------
/ios/Runner/Assets.xcassets/AppIcon.appiconset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images": [
3 | {
4 | "filename": "AppIcon@2x.png",
5 | "idiom": "iphone",
6 | "scale": "2x",
7 | "size": "60x60"
8 | },
9 | {
10 | "filename": "AppIcon@3x.png",
11 | "idiom": "iphone",
12 | "scale": "3x",
13 | "size": "60x60"
14 | },
15 | {
16 | "filename": "AppIcon~ipad.png",
17 | "idiom": "ipad",
18 | "scale": "1x",
19 | "size": "76x76"
20 | },
21 | {
22 | "filename": "AppIcon@2x~ipad.png",
23 | "idiom": "ipad",
24 | "scale": "2x",
25 | "size": "76x76"
26 | },
27 | {
28 | "filename": "AppIcon-83.5@2x~ipad.png",
29 | "idiom": "ipad",
30 | "scale": "2x",
31 | "size": "83.5x83.5"
32 | },
33 | {
34 | "filename": "AppIcon-40@2x.png",
35 | "idiom": "iphone",
36 | "scale": "2x",
37 | "size": "40x40"
38 | },
39 | {
40 | "filename": "AppIcon-40@3x.png",
41 | "idiom": "iphone",
42 | "scale": "3x",
43 | "size": "40x40"
44 | },
45 | {
46 | "filename": "AppIcon-40~ipad.png",
47 | "idiom": "ipad",
48 | "scale": "1x",
49 | "size": "40x40"
50 | },
51 | {
52 | "filename": "AppIcon-40@2x~ipad.png",
53 | "idiom": "ipad",
54 | "scale": "2x",
55 | "size": "40x40"
56 | },
57 | {
58 | "filename": "AppIcon-20@2x.png",
59 | "idiom": "iphone",
60 | "scale": "2x",
61 | "size": "20x20"
62 | },
63 | {
64 | "filename": "AppIcon-20@3x.png",
65 | "idiom": "iphone",
66 | "scale": "3x",
67 | "size": "20x20"
68 | },
69 | {
70 | "filename": "AppIcon-20~ipad.png",
71 | "idiom": "ipad",
72 | "scale": "1x",
73 | "size": "20x20"
74 | },
75 | {
76 | "filename": "AppIcon-20@2x~ipad.png",
77 | "idiom": "ipad",
78 | "scale": "2x",
79 | "size": "20x20"
80 | },
81 | {
82 | "filename": "AppIcon-29.png",
83 | "idiom": "iphone",
84 | "scale": "1x",
85 | "size": "29x29"
86 | },
87 | {
88 | "filename": "AppIcon-29@2x.png",
89 | "idiom": "iphone",
90 | "scale": "2x",
91 | "size": "29x29"
92 | },
93 | {
94 | "filename": "AppIcon-29@3x.png",
95 | "idiom": "iphone",
96 | "scale": "3x",
97 | "size": "29x29"
98 | },
99 | {
100 | "filename": "AppIcon-29~ipad.png",
101 | "idiom": "ipad",
102 | "scale": "1x",
103 | "size": "29x29"
104 | },
105 | {
106 | "filename": "AppIcon-29@2x~ipad.png",
107 | "idiom": "ipad",
108 | "scale": "2x",
109 | "size": "29x29"
110 | },
111 | {
112 | "filename": "AppIcon-60@2x~car.png",
113 | "idiom": "car",
114 | "scale": "2x",
115 | "size": "60x60"
116 | },
117 | {
118 | "filename": "AppIcon-60@3x~car.png",
119 | "idiom": "car",
120 | "scale": "3x",
121 | "size": "60x60"
122 | },
123 | {
124 | "filename": "AppIcon~ios-marketing.png",
125 | "idiom": "ios-marketing",
126 | "scale": "1x",
127 | "size": "1024x1024"
128 | }
129 | ],
130 | "info": {
131 | "author": "iconkitchen",
132 | "version": 1
133 | }
134 | }
--------------------------------------------------------------------------------
/lib/features/onboarding/screens/widgets/glassmorphic_card.dart:
--------------------------------------------------------------------------------
1 | import 'dart:ui';
2 | import 'package:flutter/material.dart';
3 | import 'package:pay_mobile_app/core/utils/global_constants.dart';
4 | import 'package:pay_mobile_app/core/utils/assets.dart';
5 |
6 | class GlassmorphicCard extends StatelessWidget {
7 | final double height;
8 | final double width;
9 |
10 | const GlassmorphicCard(
11 | {super.key, required this.height, required this.width});
12 |
13 | @override
14 | Widget build(BuildContext context) {
15 | return Stack(
16 | children: [
17 | Stack(
18 | children: [
19 | ClipRRect(
20 | borderRadius: BorderRadius.circular(20),
21 | child: BackdropFilter(
22 | filter: ImageFilter.blur(sigmaX: 10, sigmaY: 10),
23 | child: Container(
24 | height: height,
25 | width: width,
26 | decoration: BoxDecoration(
27 | color: Colors.white.withOpacity(0.2),
28 | borderRadius: BorderRadius.circular(20),
29 | border: Border.all(
30 | color: Colors.white.withOpacity(0.2),
31 | ),
32 | ),
33 | child: CustomPaint(
34 | painter: _GradientPainter(),
35 | ),
36 | ),
37 | ),
38 | ),
39 | Positioned(
40 | left: 15,
41 | top: 10,
42 | child: Image.asset(
43 | logo,
44 | height: heightValue50,
45 | ),
46 | ),
47 | Positioned(
48 | top: 93,
49 | left: 20,
50 | child: Image.asset(
51 | cardChipImage,
52 | height: heightValue50,
53 | ),
54 | ),
55 | const Positioned(
56 | top: 100,
57 | bottom: 0,
58 | left: 95,
59 | right: 0,
60 | child: Text(
61 | "1234 5678 9000",
62 | style: TextStyle(
63 | fontSize: 25,
64 | fontWeight: FontWeight.bold,
65 | ),
66 | ),
67 | ),
68 | Positioned(
69 | bottom: 20,
70 | right: 20,
71 | child: Image.asset(
72 | contactLessIcon,
73 | height: heightValue40,
74 | ),
75 | )
76 | ],
77 | ),
78 | ],
79 | );
80 | }
81 | }
82 |
83 | class _GradientPainter extends CustomPainter {
84 | @override
85 | void paint(Canvas canvas, Size size) {
86 | final rect = Rect.fromLTWH(0, 0, size.width, size.height);
87 | final gradient = LinearGradient(
88 | begin: Alignment.topLeft,
89 | end: Alignment.bottomRight,
90 | colors: [
91 | const Color(0xFFB3E0B8),
92 | Colors.white.withOpacity(0.2),
93 | ],
94 | );
95 | final paint = Paint()
96 | ..shader = gradient.createShader(rect)
97 | ..style = PaintingStyle.stroke
98 | ..strokeWidth = 2;
99 | canvas.drawRRect(
100 | RRect.fromRectAndRadius(rect, Radius.circular(heightValue20)), paint);
101 | }
102 |
103 | @override
104 | bool shouldRepaint(covariant CustomPainter oldDelegate) => false;
105 | }
106 |
--------------------------------------------------------------------------------
/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme:
--------------------------------------------------------------------------------
1 |
2 |
5 |
8 |
9 |
15 |
21 |
22 |
23 |
24 |
25 |
30 |
31 |
37 |
38 |
39 |
40 |
41 |
42 |
52 |
54 |
60 |
61 |
62 |
63 |
69 |
71 |
77 |
78 |
79 |
80 |
82 |
83 |
86 |
87 |
88 |
--------------------------------------------------------------------------------
/lib/widgets/custom_textfield.dart:
--------------------------------------------------------------------------------
1 | import 'package:flutter/material.dart';
2 | import 'package:flutter/services.dart';
3 | import 'package:pay_mobile_app/core/utils/color_constants.dart';
4 | import 'package:pay_mobile_app/core/utils/global_constants.dart';
5 |
6 | class CustomTextField extends StatelessWidget {
7 | final String? labelText;
8 | final String hintText;
9 | final TextEditingController controller;
10 | final Widget? icon;
11 | final bool obscureText;
12 | final int maxLines;
13 | final TextInputType keyboardType;
14 | final String? errorText;
15 | final void Function(String)? onChanged;
16 | final String? successMessage;
17 | final Icon? prefixIcon;
18 | final bool willContainPrefix;
19 | final List? inputFormatters;
20 | final String? Function(String?)? validator;
21 | const CustomTextField({
22 | Key? key,
23 | this.labelText = "",
24 | required this.hintText,
25 | required this.controller,
26 | this.icon,
27 | this.obscureText = false,
28 | this.maxLines = 1,
29 | this.keyboardType = TextInputType.name,
30 | this.validator,
31 | this.errorText,
32 | this.onChanged,
33 | this.successMessage,
34 | this.prefixIcon,
35 | this.willContainPrefix = false,
36 | this.inputFormatters,
37 | }) : super(key: key);
38 |
39 | @override
40 | Widget build(BuildContext context) {
41 | return Column(
42 | crossAxisAlignment: CrossAxisAlignment.start,
43 | children: [
44 | Padding(
45 | padding: EdgeInsets.only(bottom: heightValue5),
46 | child: Text(
47 | labelText!,
48 | style: TextStyle(
49 | fontSize: heightValue15,
50 | fontWeight: FontWeight.bold,
51 | ),
52 | ),
53 | ),
54 | TextFormField(
55 | autofocus: true,
56 | keyboardType: keyboardType,
57 | obscureText: obscureText,
58 | controller: controller,
59 | inputFormatters: inputFormatters,
60 | style: TextStyle(fontSize: heightValue20),
61 | decoration: InputDecoration(
62 | border: OutlineInputBorder(
63 | borderSide: const BorderSide(
64 | color: greyScale850,
65 | width: 2,
66 | ),
67 | borderRadius: BorderRadius.circular(heightValue15),
68 | ),
69 | enabledBorder: OutlineInputBorder(
70 | borderSide: const BorderSide(
71 | color: greyScale850,
72 | width: 2,
73 | ),
74 | borderRadius: BorderRadius.circular(heightValue15),
75 | ),
76 | focusedBorder: OutlineInputBorder(
77 | borderSide: const BorderSide(
78 | color: primaryAppColor,
79 | width: 2,
80 | ),
81 | borderRadius: BorderRadius.circular(heightValue15),
82 | ),
83 | hintText: hintText,
84 | suffixIcon: icon,
85 | errorText: errorText,
86 | prefixIcon: prefixIcon,
87 | filled: true,
88 | fillColor: greyScale850,
89 | contentPadding: EdgeInsets.all(heightValue20),
90 | ),
91 | maxLines: 1,
92 | validator: validator,
93 | onChanged: onChanged,
94 | ),
95 | Text(
96 | successMessage ?? "",
97 | style: const TextStyle(color: Colors.green),
98 | )
99 | ],
100 | );
101 | }
102 | }
103 |
--------------------------------------------------------------------------------
/ios/Runner/Base.lproj/LaunchScreen.storyboard:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
--------------------------------------------------------------------------------
/lib/widgets/main_app.dart:
--------------------------------------------------------------------------------
1 | //THis the the bottom navigation bar for the entire appplication
2 | import 'package:flutter/material.dart';
3 |
4 | import 'package:pay_mobile_app/core/utils/color_constants.dart';
5 | import 'package:pay_mobile_app/core/utils/global_constants.dart';
6 | import 'package:pay_mobile_app/core/utils/assets.dart';
7 | import 'package:pay_mobile_app/features/home/screens/home_screen.dart';
8 | import 'package:pay_mobile_app/features/profile/screens/profile_screen.dart';
9 | import 'package:pay_mobile_app/features/transactions/screens/all_transactions_screen.dart';
10 |
11 | class MainApp extends StatefulWidget {
12 | static const String route = '/main-app';
13 | int currentPage;
14 | MainApp({
15 | Key? key,
16 | this.currentPage = 0,
17 | }) : super(key: key);
18 |
19 | @override
20 | State createState() => _MainAppState();
21 | }
22 |
23 | class _MainAppState extends State {
24 | PageController pageController = PageController();
25 | void updatePage(int page) {
26 | setState(() {
27 | widget.currentPage = page;
28 | });
29 | pageController.jumpToPage(page);
30 | }
31 |
32 | @override
33 | void initState() {
34 | super.initState();
35 | pageController = PageController(initialPage: widget.currentPage);
36 | }
37 |
38 | @override
39 | Widget build(BuildContext context) {
40 | return Scaffold(
41 | //extendBody: true,
42 | backgroundColor: Colors.transparent,
43 | body: PageView(
44 | controller: pageController,
45 | physics: const NeverScrollableScrollPhysics(),
46 | onPageChanged: (page) {
47 | setState(() {
48 | widget.currentPage = page;
49 | });
50 | },
51 | children: const [
52 | HomeScreen(),
53 | TransactionsScreen(),
54 | ProfileScreen(),
55 | ],
56 | ),
57 | bottomNavigationBar: BottomNavigationBar(
58 | backgroundColor: primaryAppColor,
59 | elevation: 0,
60 | //fixedColor: primaryAppColor,
61 | type: BottomNavigationBarType.fixed,
62 | onTap: updatePage,
63 | currentIndex: widget.currentPage,
64 | selectedItemColor: secondaryAppColor,
65 | unselectedItemColor: greyScale600,
66 | selectedLabelStyle: const TextStyle(
67 | fontWeight: FontWeight.w900,
68 | color: secondaryAppColor,
69 | ),
70 | items: [
71 | BottomNavigationBarItem(
72 | icon: Image.asset(
73 | homeIcon,
74 | height: heightValue40,
75 | color:
76 | widget.currentPage == 0 ? secondaryAppColor : greyScale600,
77 | ),
78 | label: "Home",
79 | ),
80 | BottomNavigationBarItem(
81 | icon: Image.asset(
82 | transactionsIcon,
83 | height: heightValue45,
84 | color: widget.currentPage == 1
85 | ? secondaryAppColor
86 | : greyScale600,
87 | ),
88 | label: "Transactions"),
89 | BottomNavigationBarItem(
90 | icon: Image.asset(
91 | profileIcon,
92 | height: heightValue40,
93 | color: widget.currentPage == 2
94 | ? secondaryAppColor
95 | : greyScale600,
96 | ),
97 | label: "Profile"),
98 | ],
99 | ));
100 | }
101 | }
102 |
--------------------------------------------------------------------------------
/lib/features/auth/screens/forgort_pin_screen.dart:
--------------------------------------------------------------------------------
1 | import 'package:flutter/material.dart';
2 | import 'package:pay_mobile_app/config/routes/custom_push_navigators.dart';
3 | import 'package:pay_mobile_app/core/utils/color_constants.dart';
4 | import 'package:pay_mobile_app/core/utils/global_constants.dart';
5 | import 'package:pay_mobile_app/core/utils/assets.dart';
6 | import 'package:pay_mobile_app/core/utils/validators.dart';
7 | import 'package:pay_mobile_app/features/auth/screens/forgort_pin_verification_screen.dart';
8 | import 'package:pay_mobile_app/features/auth/services/auth_service.dart';
9 | import 'package:pay_mobile_app/features/auth/providers/auth_provider.dart';
10 | import 'package:pay_mobile_app/widgets/custom_app_bar.dart';
11 | import 'package:pay_mobile_app/widgets/custom_button.dart';
12 | import 'package:pay_mobile_app/widgets/custom_textfield.dart';
13 | import 'package:pay_mobile_app/widgets/height_space.dart';
14 | import 'package:provider/provider.dart';
15 |
16 | class ForgortPinScreen extends StatefulWidget {
17 | static const String route = '/forgort-pin';
18 | const ForgortPinScreen({super.key});
19 |
20 | @override
21 | State createState() => _ForgortPinScreenState();
22 | }
23 |
24 | class _ForgortPinScreenState extends State {
25 | final AuthService authService = AuthService();
26 | final TextEditingController emailController = TextEditingController();
27 | final emailFormkey = GlobalKey();
28 | sendOtp() {
29 | final authProvider = Provider.of(context, listen: false);
30 |
31 | if (emailFormkey.currentState!.validate()) {
32 | authService.sendOtp(
33 | context: context,
34 | email: emailController.text,
35 | onTapDialogButton: () =>
36 | namedNav(context, ForgortPinVerificationScreen.route),
37 | sendPurpose: 'forgort-pin',
38 | );
39 | authProvider.setUserEmail(emailController.text);
40 | }
41 | }
42 |
43 | @override
44 | Widget build(BuildContext context) {
45 | return GestureDetector(
46 | onTap: () => FocusScope.of(context).unfocus(),
47 | child: Scaffold(
48 | appBar: const CustomAppBar(image: logo),
49 | body: Padding(
50 | padding: EdgeInsets.symmetric(horizontal: value20),
51 | child: Stack(
52 | children: [
53 | screenUI(),
54 | Padding(
55 | padding: EdgeInsets.only(bottom: heightValue10),
56 | child: Align(
57 | alignment: Alignment.bottomCenter,
58 | child: CustomButton(
59 | buttonText: "Send Code",
60 | buttonTextColor: secondaryAppColor,
61 | borderRadius: heightValue30,
62 | onTap: () => sendOtp(),
63 | ),
64 | ),
65 | )
66 | ],
67 | ),
68 | ),
69 | ),
70 | );
71 | }
72 |
73 | Widget screenUI() {
74 | return Form(
75 | key: emailFormkey,
76 | child: Column(
77 | children: [
78 | HeightSpace(heightValue10),
79 | Text(
80 | "Forgort Pin",
81 | style:
82 | TextStyle(fontSize: heightValue30, fontWeight: FontWeight.bold),
83 | ),
84 | HeightSpace(heightValue10),
85 | Text(
86 | "Enter the email address connected to your account ",
87 | textAlign: TextAlign.center,
88 | style: TextStyle(
89 | fontSize: heightValue17,
90 | ),
91 | ),
92 | HeightSpace(heightValue10),
93 | CustomTextField(
94 | hintText: "Enter your email",
95 | labelText: "Email",
96 | controller: emailController,
97 | validator: validateEmail,
98 | )
99 | ],
100 | ),
101 | );
102 | }
103 | }
104 |
--------------------------------------------------------------------------------
/lib/features/auth/screens/forgort_password_screen.dart:
--------------------------------------------------------------------------------
1 | import 'package:flutter/material.dart';
2 | import 'package:pay_mobile_app/config/routes/custom_push_navigators.dart';
3 | import 'package:pay_mobile_app/core/utils/color_constants.dart';
4 | import 'package:pay_mobile_app/core/utils/global_constants.dart';
5 | import 'package:pay_mobile_app/core/utils/assets.dart';
6 | import 'package:pay_mobile_app/core/utils/validators.dart';
7 | import 'package:pay_mobile_app/features/auth/screens/forgort_password_verification_screen.dart';
8 | import 'package:pay_mobile_app/features/auth/services/auth_service.dart';
9 | import 'package:pay_mobile_app/features/auth/providers/auth_provider.dart';
10 | import 'package:pay_mobile_app/widgets/custom_app_bar.dart';
11 | import 'package:pay_mobile_app/widgets/custom_button.dart';
12 | import 'package:pay_mobile_app/widgets/custom_textfield.dart';
13 | import 'package:pay_mobile_app/widgets/height_space.dart';
14 | import 'package:provider/provider.dart';
15 |
16 | class ForgortPasswordScreen extends StatefulWidget {
17 | static const String route = '/forgort-password';
18 | const ForgortPasswordScreen({super.key});
19 |
20 | @override
21 | State createState() => _ForgortPasswordScreenState();
22 | }
23 |
24 | class _ForgortPasswordScreenState extends State {
25 | final AuthService authService = AuthService();
26 | final TextEditingController emailController = TextEditingController();
27 | final emailFormkey = GlobalKey();
28 | sendOtp() {
29 | if (emailFormkey.currentState!.validate()) {
30 | authService.sendOtp(
31 | context: context,
32 | email: emailController.text,
33 | onTapDialogButton: () => namedNavRemoveUntil(
34 | context, ForgortPasswordVerificationScreen.route),
35 | sendPurpose: 'forgort-password',
36 | );
37 | final authProvider = Provider.of(context, listen: false);
38 | authProvider.setUserEmail(emailController.text);
39 | }
40 | }
41 |
42 | @override
43 | Widget build(BuildContext context) {
44 | return GestureDetector(
45 | onTap: () => FocusScope.of(context).unfocus(),
46 | child: Scaffold(
47 | appBar: const CustomAppBar(image: logo),
48 | body: Padding(
49 | padding: EdgeInsets.symmetric(horizontal: value20),
50 | child: Stack(
51 | children: [
52 | screenUI(),
53 | Padding(
54 | padding: EdgeInsets.only(bottom: heightValue10),
55 | child: Align(
56 | alignment: Alignment.bottomCenter,
57 | child: CustomButton(
58 | buttonText: "Send Code",
59 | buttonTextColor: secondaryAppColor,
60 | borderRadius: heightValue30,
61 | onTap: () => sendOtp(),
62 | ),
63 | ),
64 | )
65 | ],
66 | ),
67 | ),
68 | ),
69 | );
70 | }
71 |
72 | Widget screenUI() {
73 | return Form(
74 | key: emailFormkey,
75 | child: Column(
76 | children: [
77 | HeightSpace(heightValue10),
78 | Text(
79 | "Forgort Password",
80 | style:
81 | TextStyle(fontSize: heightValue30, fontWeight: FontWeight.bold),
82 | ),
83 | HeightSpace(heightValue10),
84 | Text(
85 | "Enter the email address connected to your account ",
86 | textAlign: TextAlign.center,
87 | style: TextStyle(
88 | fontSize: heightValue17,
89 | ),
90 | ),
91 | HeightSpace(heightValue10),
92 | CustomTextField(
93 | hintText: "Enter your email",
94 | labelText: "Email",
95 | controller: emailController,
96 | validator: validateEmail,
97 | )
98 | ],
99 | ),
100 | );
101 | }
102 | }
103 |
--------------------------------------------------------------------------------
/pubspec.yaml:
--------------------------------------------------------------------------------
1 | name: pay_mobile_app
2 | description: A new Flutter project.
3 | # The following line prevents the package from being accidentally published to
4 | # pub.dev using `flutter pub publish`. This is preferred for private packages.
5 | publish_to: "none" # Remove this line if you wish to publish to pub.dev
6 |
7 | # The following defines the version and build number for your application.
8 | # A version number is three numbers separated by dots, like 1.2.43
9 | # followed by an optional build number separated by a +.
10 | # Both the version and the builder number may be overridden in flutter
11 | # build by specifying --build-name and --build-number, respectively.
12 | # In Android, build-name is used as versionName while build-number used as versionCode.
13 | # Read more about Android versioning at https://developer.android.com/studio/publish/versioning
14 | # In iOS, build-name is used as CFBundleShortVersionString while build-number is used as CFBundleVersion.
15 | # Read more about iOS versioning at
16 | # https://developer.apple.com/library/archive/documentation/General/Reference/InfoPlistKeyReference/Articles/CoreFoundationKeys.html
17 | # In Windows, build-name is used as the major, minor, and patch parts
18 | # of the product and file versions while build-number is used as the build suffix.
19 | version: 2.0.0
20 |
21 | environment:
22 | sdk: ">=2.19.4 <3.0.0"
23 |
24 | # Dependencies specify other packages that your package needs in order to work.
25 | # To automatically upgrade your package dependencies to the latest versions
26 | # consider running `flutter pub upgrade --major-versions`. Alternatively,
27 | # dependencies can be manually updated by changing the version numbers below to
28 | # the latest version available on pub.dev. To see which dependencies have newer
29 | # versions available, run `flutter pub outdated`.
30 | dependencies:
31 | flutter:
32 | sdk: flutter
33 |
34 | # The following adds the Cupertino Icons font to your application.
35 | # Use with the CupertinoIcons class for iOS style icons.
36 | cupertino_icons: ^1.0.2
37 | provider: ^6.0.5
38 | shared_preferences: ^2.0.18
39 | http: ^0.13.5
40 | intl: ^0.18.0
41 | internet_connection_checker: ^1.0.0+1
42 | firebase_core: ^2.14.0
43 | firebase_messaging: ^14.6.4
44 | cloud_firestore: ^4.8.2
45 | socket_io_client: ^2.0.2
46 | awesome_notifications: ^0.6.19
47 |
48 | dev_dependencies:
49 | flutter_test:
50 | sdk: flutter
51 | flutter_native_splash: ^2.2.19
52 |
53 | # The "flutter_lints" package below contains a set of recommended lints to
54 | # encourage good coding practices. The lint set provided by the package is
55 | # activated in the `analysis_options.yaml` file located at the root of your
56 | # package. See that file for information about deactivating specific lint
57 | # rules and activating additional ones.
58 | flutter_lints: ^2.0.0
59 |
60 | flutter_native_splash:
61 | color: "#141318"
62 | image: assets/images/main_logo.png
63 |
64 | # For information on the generic Dart part of this file, see the
65 | # following page: https://dart.dev/tools/pub/pubspec
66 |
67 | # The following section is specific to Flutter packages.
68 | flutter:
69 | # The following line ensures that the Material Icons font is
70 | # included with your application, so that you can use the icons in
71 | # the material Icons class.
72 | uses-material-design: true
73 |
74 | # To add assets to your application, add an assets section, like this:
75 | assets:
76 | - assets/images/
77 | - assets/fonts/
78 | - assets/icons/
79 |
80 | # - images/a_dot_ham.jpeg
81 |
82 | # An image asset can refer to one or more resolution-specific "variants", see
83 | # https://flutter.dev/assets-and-images/#resolution-aware
84 |
85 | # For details regarding adding assets from package dependencies, see
86 | # https://flutter.dev/assets-and-images/#from-packages
87 |
88 | # To add custom fonts to your application, add a fonts section here,
89 | # in this "flutter" section. Each entry in this list should have a
90 | # "family" key with the font family name, and a "fonts" key with a
91 | # list giving the asset and other descriptors for the font. For
92 | # example:
93 | fonts:
94 | - family: Comfortaa
95 | fonts:
96 | - asset: assets/fonts/Comfortaa-Regular.ttf
97 | - asset: assets/fonts/Comfortaa-Medium.ttf
98 | - asset: assets/fonts/Comfortaa-SemiBold.ttf
99 | - asset: assets/fonts/Comfortaa-Bold.ttf
100 |
101 | # - asset: fonts/Schyler-Italic.ttf
102 | # style: italic
103 | # - family: Trajan Pro
104 | # fonts:
105 | # - asset: fonts/TrajanPro.ttf
106 | # - asset: fonts/TrajanPro_Bold.ttf
107 | # weight: 700
108 | #
109 | # For details regarding fonts from package dependencies,
110 | # see https://flutter.dev/custom-fonts/#from-packages
111 |
--------------------------------------------------------------------------------
/lib/features/home/screens/fund_wallet_screen.dart:
--------------------------------------------------------------------------------
1 | /*nothing much here. This just asks the user for the amount they will like to add
2 | Then it confirms their pin and updates their balance
3 | You can implement an actual deposit feature if you want*/
4 |
5 | import 'package:flutter/material.dart';
6 | import 'package:pay_mobile_app/core/utils/color_constants.dart';
7 | import 'package:pay_mobile_app/core/utils/global_constants.dart';
8 | import 'package:pay_mobile_app/core/utils/assets.dart';
9 | import 'package:pay_mobile_app/features/home/services/home_service.dart';
10 | import 'package:pay_mobile_app/features/home/widgets/confirm_pin_to_send_money_dialpad.dart';
11 | import 'package:pay_mobile_app/features/auth/providers/user_provider.dart';
12 | import 'package:pay_mobile_app/widgets/custom_app_bar.dart';
13 | import 'package:pay_mobile_app/widgets/custom_button.dart';
14 | import 'package:pay_mobile_app/widgets/custom_textfield.dart';
15 | import 'package:provider/provider.dart';
16 |
17 | class FundWalletScreen extends StatefulWidget {
18 | static const String route = "/add-money";
19 | const FundWalletScreen({super.key});
20 |
21 | @override
22 | State createState() => _FundWalletScreenState();
23 | }
24 |
25 | class _FundWalletScreenState extends State {
26 | final TextEditingController amountController = TextEditingController();
27 | final HomeService homeService = HomeService();
28 |
29 | void fundAccontWallet() {
30 | final username =
31 | Provider.of(context, listen: false).user.username;
32 | homeService.fundWallet(
33 | context: context,
34 | username: username,
35 | amount: int.parse(amountController.text),
36 | onLandingOnHomePage: () {});
37 | }
38 |
39 | @override
40 | void dispose() {
41 | super.dispose();
42 | amountController.dispose();
43 | }
44 |
45 | @override
46 | Widget build(BuildContext context) {
47 | return GestureDetector(
48 | onTap: () => FocusScope.of(context).unfocus(),
49 | child: Scaffold(
50 | appBar: const CustomAppBar(
51 | image: logo,
52 | ),
53 | body: Padding(
54 | padding: EdgeInsets.symmetric(horizontal: value20),
55 | child: Column(
56 | children: [
57 | Text(
58 | "Add Money",
59 | style: TextStyle(
60 | fontSize: heightValue25,
61 | fontWeight: FontWeight.bold,
62 | ),
63 | ),
64 | Text(
65 | "Enter the amount you will like to add",
66 | style: TextStyle(
67 | fontSize: heightValue24,
68 | fontWeight: FontWeight.bold,
69 | ),
70 | ),
71 | SizedBox(
72 | height: heightValue10,
73 | ),
74 | Row(
75 | mainAxisAlignment: MainAxisAlignment.center,
76 | children: [
77 | Text(
78 | "Note: max = ",
79 | style: TextStyle(
80 | fontSize: heightValue20,
81 | fontWeight: FontWeight.bold,
82 | ),
83 | ),
84 | Text(
85 | "₦5,000",
86 | style: TextStyle(
87 | fontSize: value15,
88 | color: Colors.red,
89 | fontWeight: FontWeight.bold,
90 | ),
91 | ),
92 | ],
93 | ),
94 | CustomTextField(
95 | keyboardType: TextInputType.number,
96 | hintText: "Enter Amount",
97 | controller: amountController,
98 | ),
99 | SizedBox(
100 | height: heightValue40,
101 | ),
102 | Padding(
103 | padding: EdgeInsets.symmetric(horizontal: value40),
104 | child: CustomButton(
105 | buttonText: "Continue",
106 | buttonColor: primaryAppColor,
107 | buttonTextColor: secondaryAppColor,
108 | onTap: () => showModalBottomSheet(
109 | context: context,
110 | enableDrag: false,
111 | isDismissible: false,
112 | isScrollControlled: true,
113 | constraints: BoxConstraints.loose(
114 | Size(screenWidth, screenHeight),
115 | ),
116 | builder: (context) => ConfirmPinToSendMoneyDialPad(
117 | onSuccess: () {
118 | fundAccontWallet();
119 | },
120 | ),
121 | ),
122 | ),
123 | )
124 | ],
125 | ),
126 | ),
127 | ),
128 | );
129 | }
130 | }
131 |
--------------------------------------------------------------------------------
/lib/features/onboarding/screens/onboarding_screen.dart:
--------------------------------------------------------------------------------
1 | import 'package:flutter/material.dart';
2 | import 'package:pay_mobile_app/core/utils/color_constants.dart';
3 | import 'package:pay_mobile_app/core/utils/global_constants.dart';
4 | import 'package:pay_mobile_app/core/utils/assets.dart';
5 | import 'package:pay_mobile_app/features/auth/screens/login_screen.dart';
6 | import 'package:pay_mobile_app/features/auth/screens/signup_screen.dart';
7 | import 'package:pay_mobile_app/features/onboarding/screens/widgets/glassmorphic_card.dart';
8 | import 'package:pay_mobile_app/widgets/custom_button.dart';
9 | import 'package:pay_mobile_app/widgets/height_space.dart';
10 |
11 | class OnBoardingScreen extends StatelessWidget {
12 | static const String route = "/onboarding-screen";
13 | const OnBoardingScreen({super.key});
14 |
15 | @override
16 | Widget build(BuildContext context) {
17 | return Scaffold(
18 | body: SafeArea(
19 | child: Padding(
20 | padding: EdgeInsets.symmetric(horizontal: value10),
21 | child: Stack(
22 | children: [
23 | Align(
24 | alignment: Alignment.topCenter,
25 | child: Padding(
26 | padding: EdgeInsets.only(top: heightValue30),
27 | child: Column(
28 | children: [
29 | Image.asset(
30 | mainLogo,
31 | height: heightValue50,
32 | ),
33 | SizedBox(
34 | height: heightValue10,
35 | ),
36 | Text(
37 | "The Best Way to Transfer Money Safely",
38 | style: TextStyle(
39 | fontSize: heightValue15,
40 | color: greyScale500,
41 | ),
42 | ),
43 | ],
44 | ),
45 | ),
46 | ),
47 | Positioned(
48 | top: 150,
49 | right: 0,
50 | child: Image.asset(
51 | gradientCircle,
52 | height: heightValue200,
53 | ),
54 | ),
55 | Column(
56 | mainAxisAlignment: MainAxisAlignment.center,
57 | crossAxisAlignment: CrossAxisAlignment.center,
58 | children: [
59 | GlassmorphicCard(height: heightValue230, width: 355),
60 | HeightSpace(heightValue35),
61 | Text(
62 | "Send & request payments",
63 | style: TextStyle(
64 | fontWeight: FontWeight.bold,
65 | fontSize: heightValue30,
66 | ),
67 | textAlign: TextAlign.center,
68 | ),
69 | SizedBox(
70 | height: heightValue20,
71 | ),
72 | Text(
73 | "Send or recieve any payments from your accounts with ease and comfort.",
74 | textAlign: TextAlign.center,
75 | style: TextStyle(
76 | fontSize: heightValue18,
77 | color: greyScale500,
78 | ),
79 | )
80 | ],
81 | ),
82 | Align(
83 | alignment: Alignment.bottomCenter,
84 | child: Padding(
85 | padding: EdgeInsets.only(bottom: heightValue20),
86 | child: Column(
87 | mainAxisAlignment: MainAxisAlignment.end,
88 | children: [
89 | CustomButton(
90 | borderRadius: heightValue45,
91 | buttonText: "Create Account",
92 | buttonColor: primaryAppColor,
93 | buttonTextColor: scaffoldBackgroundColor,
94 | onTap: () {
95 | Navigator.pushNamed(context, SignUpScreen.route);
96 | }),
97 | SizedBox(
98 | height: heightValue10,
99 | ),
100 | TextButton(
101 | onPressed: () {
102 | Navigator.pushNamed(context, LoginScreen.route);
103 | },
104 | child: Text(
105 | "Already have an account?",
106 | style: TextStyle(
107 | fontWeight: FontWeight.bold,
108 | fontSize: heightValue18,
109 | ),
110 | ),
111 | )
112 | ],
113 | ),
114 | ),
115 | ),
116 | ],
117 | ),
118 | ),
119 | ),
120 | );
121 | }
122 | }
123 |
--------------------------------------------------------------------------------
/lib/features/transactions/widgets/transactions_card.dart:
--------------------------------------------------------------------------------
1 |
2 | import 'package:flutter/material.dart';
3 | import 'package:pay_mobile_app/core/utils/color_constants.dart';
4 |
5 | import 'package:pay_mobile_app/core/utils/global_constants.dart';
6 | import 'package:pay_mobile_app/core/utils/assets.dart';
7 |
8 | class TransactionsCard extends StatelessWidget {
9 | final String transactionTypeImage;
10 | final String transactionType;
11 | final String trnxSummary;
12 | final int amount;
13 | final Color amountColorBasedOnTransactionType;
14 | const TransactionsCard({
15 | Key? key,
16 | required this.transactionTypeImage,
17 | required this.transactionType,
18 | required this.trnxSummary,
19 | required this.amount,
20 | required this.amountColorBasedOnTransactionType,
21 | }) : super(key: key);
22 |
23 | @override
24 | Widget build(BuildContext context) {
25 | return Padding(
26 | padding: const EdgeInsets.all(8.0),
27 | child: Stack(
28 | children: [
29 | Positioned(
30 | bottom: 0,
31 | right: 0,
32 | child: ClipRRect(
33 | borderRadius: BorderRadius.only(
34 | bottomRight: Radius.circular(
35 | heightValue20,
36 | ),
37 | topLeft: Radius.circular(
38 | heightValue25,
39 | ),
40 | ),
41 | child: Image.asset(
42 | gradientCircle,
43 | height: heightValue30,
44 | ),
45 | ),
46 | ),
47 | Container(
48 | height: heightValue80,
49 | width: screenWidth,
50 | decoration: BoxDecoration(
51 | borderRadius: BorderRadius.circular(heightValue20),
52 | color: greyScale850,
53 | ),
54 | child: Padding(
55 | padding: EdgeInsets.symmetric(horizontal: value20),
56 | child: Row(
57 | mainAxisAlignment: MainAxisAlignment.spaceBetween,
58 | crossAxisAlignment: CrossAxisAlignment.center,
59 | children: [
60 | Container(
61 | height: heightValue50,
62 | width: heightValue50,
63 | decoration: BoxDecoration(
64 | borderRadius: BorderRadius.circular(heightValue15),
65 | color: scaffoldBackgroundColor,
66 | ),
67 | child: Center(
68 | child: Image.asset(
69 | transactionTypeImage,
70 | height: heightValue20,
71 | color: primaryAppColor,
72 | ),
73 | ),
74 | ),
75 | Flexible(
76 | child: Padding(
77 | padding: EdgeInsets.only(left: value20),
78 | child: Column(
79 | mainAxisAlignment: MainAxisAlignment.center,
80 | crossAxisAlignment: CrossAxisAlignment.start,
81 | children: [
82 | Text(
83 | transactionType,
84 | style: TextStyle(
85 | fontSize: heightValue20,
86 | fontWeight: FontWeight.bold,
87 | ),
88 | ),
89 | Text(
90 | trnxSummary,
91 | style: TextStyle(
92 | fontSize: heightValue17,
93 | ),
94 | overflow: TextOverflow.ellipsis,
95 | )
96 | ],
97 | ),
98 | ),
99 | ),
100 | Row(
101 | children: [
102 | Text(
103 | "₦${amountFormatter.format(amount)}",
104 | style: TextStyle(
105 | color: amountColorBasedOnTransactionType,
106 | fontSize: heightValue20,
107 | fontWeight: FontWeight.w700,
108 | ),
109 | ),
110 | SizedBox(
111 | width: value10,
112 | ),
113 | Icon(
114 | Icons.arrow_forward_ios,
115 | size: heightValue20,
116 | )
117 | ],
118 | )
119 | ],
120 | ),
121 | ),
122 | ),
123 |
124 | // Positioned(
125 | // left: 0,
126 | // top: 0,
127 | // child: ClipRRect(
128 | // borderRadius: BorderRadius.only(
129 | // bottomRight: Radius.circular(
130 | // heightValue25,
131 | // ),
132 | // topLeft: Radius.circular(
133 | // heightValue20,
134 | // ),
135 | // ),
136 | // child: Container(
137 | // height: heightValue25,
138 | // width: heightValue25,
139 | // decoration: const BoxDecoration(
140 | // color: Color(0xFF5337A5),
141 | // ),
142 | // ),
143 | // ),
144 | // )
145 | ],
146 | ),
147 | );
148 | }
149 | }
150 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # Pay Mobile - P2P Money Transfer App
2 |
3 |
4 |
5 | # Features (Don't forget to give it a star 🌟)
6 |
7 | ## You can perform some actions with the Pay Mobile Web Admin
8 |
9 | #### 1. Pin feature used for authorizing transactions and user login
10 |
11 |
12 |
13 | ##### 2. Custom in-app notifications
14 |
15 |
16 |
17 | ##### 3. Push notifications for transfers
18 |
19 |
20 |
21 | ##### 4. In-app customer service support
22 |
23 |
24 |
25 | ##### 5. Success Dialogs
26 |
27 |
28 |
29 | ##### 6. Fully responsive(Tablet View)
30 |
31 |
32 |
33 | ## New App Features 🌟
34 |
35 | #### 1. Sign Up Verification
36 |
37 |
38 |
39 | #### 2. Forgort Password
40 |
41 |
42 |
43 | ### QUICK START ⚡
44 |
45 | #### Visit: Pay Mobile Full Stack to access the full stack code of the software (i.e the Back End and the Web Admin Front End)
46 |
47 | ### Note: The server running this app has already been deployed to render.com, which means you can immediately clone this repo, run it and start using it (i.e The backend is already connected).
48 |
49 | #### Since every username on the app is unique, transfers are performed with usernames. Just enter the `@username` of the user and you can easily transfer funds
50 |
51 |
52 |
53 | #### After the username is found then transfers can be made
54 |
55 |
56 |
57 | #### Then tap the transaction to view its details
58 |
59 |
60 |
61 | #### After cloning don't forget to run:
62 |
63 | ```bash
64 | flutter pub get
65 | ```
66 |
67 | ## Packages Used 📦
68 |
69 | 1. provider
70 | 2. shared_preferences
71 | 3. http
72 | 4. intl
73 | 5. internet_connrction_checker
74 |
75 | 6. flutter_native_splash
76 | 7. firebase_core
77 | 8. firebase_messaging
78 | 9. cloud_firestore
79 | 10. socket_io_client
80 | 11. awesome_notifications
81 |
82 | #### Here are some test login details of verified users if you don't want to create an account
83 |
84 | ```json
85 | {
86 | "username":"lere",
87 | "pin":"7171",
88 | "password":"test123",
89 | }
90 | {
91 | "username":"johndoe",
92 | "pin":"7171",
93 | "password":"test123",
94 | }
95 | {
96 | "username":"alice",
97 | "pin":"7070",
98 | "password":"test123",
99 | }
100 | {
101 | "username":"bob",
102 | "pin":"7474",
103 | "password":"test123",
104 | }
105 | ```
106 |
107 | ### If you choose to run it on your own server, visit the Pay Mobile Server Repo
108 |
109 | ## This is the official Nodejs server code that this app is running on Pay Mobile Server
110 |
111 | ## Important
112 |
113 | ### After you are done with configuring the server, dont forget to update the uri in the global_constants.dart file
114 |
115 | 1. Locate lib\core\utils\global_constants.dart and edit line 6 using the server URL you generated or created. Changes will apply globally. Check Below:
116 |
117 | ```dart
118 | 6. const String uri = "https://transfer-dayo-niyi.onrender.com";
119 | ```
120 |
121 | To
122 |
123 | ```dart
124 | 6. const String uri = "Your server URL";
125 | ```
126 |
127 | ## That's All 🎉🎉🎉
128 |
129 | ## Contributing
130 |
131 | Pull requests are welcome. If you encounter any problem with the app or server, you can open an issue.
132 |
133 | ##### If you liked this project, don't forget to leave a star 🌟.
134 |
135 | ##### Note: As of now, no tests are available
136 |
137 | ## License
138 |
139 | This project is licensed under the MIT License - see the LICENSE file for details.
140 |
--------------------------------------------------------------------------------
/lib/config/routes/router.dart:
--------------------------------------------------------------------------------
1 | import 'package:flutter/material.dart';
2 | import 'package:pay_mobile_app/config/routes/page_fade_transition.dart';
3 | import 'package:pay_mobile_app/config/routes/page_slide_transition.dart';
4 | import 'package:pay_mobile_app/features/auth/screens/forgort_password_screen.dart';
5 | import 'package:pay_mobile_app/features/auth/screens/forgort_password_verification_screen.dart';
6 | import 'package:pay_mobile_app/features/auth/screens/forgort_pin_screen.dart';
7 | import 'package:pay_mobile_app/features/auth/screens/forgort_pin_verification_screen.dart';
8 | import 'package:pay_mobile_app/features/auth/screens/login_screen.dart';
9 | import 'package:pay_mobile_app/features/auth/screens/signup_screen.dart';
10 | import 'package:pay_mobile_app/features/auth/screens/signup_verification_screen.dart';
11 | import 'package:pay_mobile_app/features/home/screens/comming_soon_screen.dart';
12 | import 'package:pay_mobile_app/features/home/screens/fund_wallet_screen.dart';
13 | import 'package:pay_mobile_app/features/home/screens/home_screen.dart';
14 | import 'package:pay_mobile_app/features/home/screens/send_money_screen.dart';
15 | import 'package:pay_mobile_app/features/onboarding/screens/onboarding_screen.dart';
16 | import 'package:pay_mobile_app/features/profile/screens/change_pin_screen.dart';
17 | import 'package:pay_mobile_app/features/profile/screens/chat_screen.dart';
18 | import 'package:pay_mobile_app/features/transactions/screens/all_transactions_screen.dart';
19 | import 'package:pay_mobile_app/features/transactions/screens/transaction_details_screen.dart';
20 | import 'package:pay_mobile_app/main.dart';
21 | import 'package:pay_mobile_app/features/transactions/models/transactions.dart';
22 | import 'package:pay_mobile_app/widgets/main_app.dart';
23 |
24 | Route appRoutes(RouteSettings routeSettings) {
25 | switch (routeSettings.name) {
26 | case LoginScreen.route:
27 | return PageFadeTransition(
28 | pageBuilder: (_, __, ___) => const LoginScreen(),
29 | settings: routeSettings,
30 | );
31 | case SignUpScreen.route:
32 | return PageFadeTransition(
33 | pageBuilder: (_, __, ___) => const SignUpScreen(),
34 | settings: routeSettings,
35 | );
36 | case SignUpVerificationScreen.route:
37 | return PageSlideTransition(
38 | pageBuilder: (_, __, ___) => const SignUpVerificationScreen(),
39 | settings: routeSettings,
40 | );
41 | case ForgortPasswordScreen.route:
42 | return PageSlideTransition(
43 | pageBuilder: (_, __, ___) => const ForgortPasswordScreen(),
44 | settings: routeSettings,
45 | );
46 | case ForgortPasswordVerificationScreen.route:
47 | return PageSlideTransition(
48 | pageBuilder: (_, __, ___) => const ForgortPasswordVerificationScreen(),
49 | settings: routeSettings,
50 | );
51 | case MainApp.route:
52 | var currentPage = routeSettings.arguments as int;
53 | return PageFadeTransition(
54 | pageBuilder: (_, __, ___) => MainApp(
55 | currentPage: currentPage,
56 | ),
57 | settings: routeSettings,
58 | );
59 | case SendMoneyScreen.route:
60 | return PageSlideTransition(
61 | pageBuilder: (_, __, ___) => const SendMoneyScreen(),
62 | settings: routeSettings,
63 | );
64 | case HomeScreen.route:
65 | return PageFadeTransition(
66 | pageBuilder: (_, __, ___) => const HomeScreen(),
67 | settings: routeSettings,
68 | );
69 | case OnBoardingScreen.route:
70 | return PageFadeTransition(
71 | pageBuilder: (_, __, ___) => const OnBoardingScreen(),
72 | settings: routeSettings,
73 | );
74 | case TransactionsScreen.route:
75 | return PageFadeTransition(
76 | pageBuilder: (_, __, ___) => const TransactionsScreen(),
77 | settings: routeSettings,
78 | );
79 | case CommingSoonScreen.route:
80 | return PageSlideTransition(
81 | pageBuilder: (_, __, ___) => const CommingSoonScreen(),
82 | settings: routeSettings,
83 | );
84 | case ChangeLoginPinScreen.route:
85 | return PageSlideTransition(
86 | pageBuilder: (_, __, ___) => const ChangeLoginPinScreen(),
87 | settings: routeSettings,
88 | );
89 | case MyApp.route:
90 | return MaterialPageRoute(
91 | builder: (context) => const MyApp(),
92 | );
93 | case FundWalletScreen.route:
94 | return PageSlideTransition(
95 | pageBuilder: (_, __, ___) => const FundWalletScreen(),
96 | settings: routeSettings,
97 | );
98 | case TransactionDetailsScreen.route:
99 | var transactions = routeSettings.arguments as Transactions;
100 | return PageFadeTransition(
101 | pageBuilder: (_, __, ___) => TransactionDetailsScreen(
102 | transactions: transactions,
103 | ),
104 | settings: routeSettings,
105 | );
106 | case ChatScreen.route:
107 | return PageSlideTransition(
108 | pageBuilder: (_, __, ___) => const ChatScreen(),
109 | settings: routeSettings,
110 | );
111 | case ForgortPinScreen.route:
112 | return PageSlideTransition(
113 | pageBuilder: (_, __, ___) => const ForgortPinScreen(),
114 | settings: routeSettings,
115 | );
116 | case ForgortPinVerificationScreen.route:
117 | return PageSlideTransition(
118 | pageBuilder: (_, __, ___) => const ForgortPinVerificationScreen(),
119 | settings: routeSettings,
120 | );
121 | default:
122 | return MaterialPageRoute(
123 | builder: (_) => const Scaffold(
124 | body: Center(
125 | child: Text("This page dosent exist"),
126 | ),
127 | ),
128 | );
129 | }
130 | }
131 |
--------------------------------------------------------------------------------
/lib/main.dart:
--------------------------------------------------------------------------------
1 | //ATTENTION!!!!!
2 | /*
3 | 1. Please refer to lib/constants/global_constants.dart
4 | 2. Refer to lib/widgets to see custom made widgets that were used throughout the app.
5 | 3. Refer to lib/router.dart to see the navigation routes for the app
6 | 4. Refer to lib/providers/user_provider to see app's state manager for the users data
7 | 5. Refer to money_transfer_server to see the nodejs code controlling the backend
8 | */
9 |
10 | import 'package:awesome_notifications/awesome_notifications.dart';
11 | import 'package:firebase_core/firebase_core.dart';
12 | import 'package:firebase_messaging/firebase_messaging.dart';
13 | import 'package:flutter/material.dart';
14 | import 'package:flutter/services.dart';
15 | import 'package:internet_connection_checker/internet_connection_checker.dart';
16 | import 'package:pay_mobile_app/config/routes/custom_push_navigators.dart';
17 | import 'package:pay_mobile_app/config/theme/theme_manager.dart';
18 | import 'package:pay_mobile_app/core/utils/utils.dart';
19 | import 'package:pay_mobile_app/core/utils/custom_notifications.dart';
20 | import 'package:pay_mobile_app/features/auth/screens/login_pin_screen.dart';
21 | import 'package:pay_mobile_app/features/auth/screens/login_screen.dart';
22 | import 'package:pay_mobile_app/features/auth/services/auth_service.dart';
23 | import 'package:pay_mobile_app/features/onboarding/screens/onboarding_screen.dart';
24 | import 'package:pay_mobile_app/features/profile/providers/chat_provider.dart';
25 | import 'package:pay_mobile_app/firebase_options.dart';
26 | import 'package:pay_mobile_app/initialization_screen.dart';
27 | import 'package:pay_mobile_app/no_internet_screen.dart';
28 | import 'package:pay_mobile_app/features/auth/providers/auth_provider.dart';
29 | import 'package:pay_mobile_app/features/auth/providers/user_provider.dart';
30 | import 'package:pay_mobile_app/config/routes/router.dart';
31 | import 'package:pay_mobile_app/widgets/main_app.dart';
32 | import 'package:provider/provider.dart';
33 |
34 | Future _firebaseMessagingBackgroundHandler(RemoteMessage message) async {
35 | print("Handling a background message ${message.messageId}");
36 | }
37 |
38 | Future main() async {
39 | WidgetsFlutterBinding.ensureInitialized();
40 | await Firebase.initializeApp(options: DefaultFirebaseOptions.currentPlatform);
41 | await FirebaseMessaging.instance.getInitialMessage();
42 | FirebaseMessaging.onBackgroundMessage(_firebaseMessagingBackgroundHandler);
43 | runApp(
44 | MultiProvider(
45 | providers: [
46 | ChangeNotifierProvider(
47 | create: (context) => UserProvider(),
48 | ),
49 | ChangeNotifierProvider(
50 | create: (context) => AuthProvider(),
51 | ),
52 | ChangeNotifierProvider(
53 | create: (context) => ChatProvider(),
54 | )
55 | ],
56 | child: const MyApp(),
57 | ),
58 | );
59 | }
60 |
61 | class MyApp extends StatefulWidget {
62 | static const String route = "/my-app";
63 | const MyApp({super.key});
64 |
65 | @override
66 | State createState() => _MyAppState();
67 | }
68 |
69 | class _MyAppState extends State {
70 | final ThemeManager themeManager = ThemeManager();
71 | final AuthService authService = AuthService();
72 | final CustomNotifications customNotificatins = CustomNotifications();
73 | late Future _future;
74 | bool check = true;
75 |
76 | @override
77 | void initState() {
78 | super.initState();
79 | _future = obtainTokenAndUserData(context);
80 | checkInternetConnection();
81 | customNotificatins.requestPermission();
82 | customNotificatins.initInfo();
83 | AwesomeNotifications().requestPermissionToSendNotifications();
84 | }
85 |
86 | obtainTokenAndUserData(BuildContext context) async {
87 | await authService.obtainTokenAndUserData(context);
88 | }
89 |
90 | checkInternetConnection() async {
91 | check = await InternetConnectionChecker().hasConnection;
92 | return check;
93 | }
94 |
95 | @override
96 | Widget build(BuildContext context) {
97 | SystemChrome.setPreferredOrientations([
98 | DeviceOrientation.portraitUp,
99 | DeviceOrientation.portraitDown,
100 | ]);
101 | final user = Provider.of(context).user;
102 | return MaterialApp(
103 | theme: themeManager.darkTheme,
104 | darkTheme: themeManager.darkTheme,
105 | debugShowCheckedModeBanner: false,
106 | onGenerateRoute: (settings) => appRoutes(settings),
107 | home: FutureBuilder(
108 | future: _future,
109 | builder: (context, snapshot) {
110 | if (snapshot.connectionState == ConnectionState.done) {
111 | return check == true
112 | ? user.isVerified != false
113 | ? user.token.isNotEmpty
114 | ? user.pin.isNotEmpty
115 | ? const LoginPinScreen()
116 | : MainApp(
117 | currentPage: 0,
118 | )
119 | : const OnBoardingScreen()
120 | : const LoginScreen()
121 | : NoInternetScreen(onTap: () {
122 | checkInternetConnection();
123 | obtainTokenAndUserData(context);
124 | if (check == true) {
125 | Navigator.pushNamedAndRemoveUntil(
126 | context,
127 | MyApp.route,
128 | (route) => false,
129 | );
130 | } else {
131 | showDialogLoader(context);
132 | Future.delayed(const Duration(seconds: 5), () {
133 | popNav(context);
134 | });
135 | }
136 | });
137 | } else {}
138 |
139 | return const InitializationScreen();
140 | },
141 | ),
142 | );
143 | }
144 | }
145 |
--------------------------------------------------------------------------------
/lib/core/utils/global_constants.dart:
--------------------------------------------------------------------------------
1 | import 'dart:ui';
2 |
3 | import 'package:flutter/material.dart';
4 | import 'package:intl/intl.dart';
5 |
6 | const String uri = "https://transfer-dayo-niyi.onrender.com";
7 | const defaultAppColor = Color(0xFF000000);
8 | var amountFormatter = NumberFormat.decimalPattern('en_US');
9 | const String notEmptyError = "This field cannot be empty.";
10 | const String fieldNotValidError = "This field is not valid.";
11 |
12 | Color darken(Color color, [double amount = .1]) {
13 | assert(amount >= 0 && amount <= 1);
14 | final hsl = HSLColor.fromColor(color);
15 | final hslDark = hsl.withLightness((hsl.lightness - amount).clamp(0.0, 1.0));
16 | return hslDark.toColor();
17 | }
18 |
19 | var platformDispatcher = PlatformDispatcher.instance;
20 | var screenHeight = platformDispatcher.views.first.physicalSize.height /
21 | platformDispatcher.views.first.devicePixelRatio;
22 | var screenWidth = platformDispatcher.views.first.physicalSize.width /
23 | platformDispatcher.views.first.devicePixelRatio;
24 | var isTablet = (platformDispatcher.views.first.physicalSize.width /
25 | platformDispatcher.views.first.devicePixelRatio) >
26 | 600;
27 |
28 | /*This is the default screen width that is used to obtain the values below
29 | =>428
30 |
31 | This is the default screen height that is used to obtain the values below
32 | =>926
33 |
34 | These are dynamic width values that change if the screen width changes
35 | This is very important for adapting to screen sizes*/
36 |
37 | //This is mostly used for width value and font sizes
38 | //428
39 | final value3 = screenWidth / 142.66;
40 | final value5 = screenWidth / 85.6;
41 | final value10 = screenWidth / 42.8;
42 | final value11 = screenWidth / 38.90;
43 | final value12 = screenWidth / 35.66;
44 | final value14 = screenWidth / 30.57;
45 | final value15 = screenWidth / 28.5;
46 | final value16 = screenWidth / 26.75;
47 | final value18 = screenWidth / 23.77;
48 | final value20 = screenWidth / 21.4;
49 | final value24 = screenWidth / 17.83;
50 | final value25 = screenWidth / 17.12;
51 | final value30 = screenWidth / 14.26;
52 | final value35 = screenWidth / 12.22;
53 | final value40 = screenWidth / 10.7;
54 | final value45 = screenWidth / 9.51;
55 | final value50 = screenWidth / 8.56;
56 | final value55 = screenWidth / 7.78;
57 | final value48 = screenWidth / 8.91;
58 | final value60 = screenWidth / 7.13;
59 | final value65 = screenWidth / 6.58;
60 | final value70 = screenWidth / 6.11;
61 | final value80 = screenWidth / 5.35;
62 | final value90 = screenWidth / 4.755;
63 | final value100 = screenWidth / 4.28;
64 | final value110 = screenWidth / 3.89;
65 | final value130 = screenWidth / 3.29;
66 | final value145 = screenWidth / 2.95;
67 | final value165 = screenWidth / 2.59;
68 | final value200 = screenWidth / 2.14;
69 | final value220 = screenWidth / 1.94;
70 |
71 | //This is mostly used for height values
72 | //926
73 | final heightValue3 = screenHeight / 308.666;
74 | final heightValue5 = screenHeight / 185.2;
75 | final heightValue10 = screenHeight / 92.6;
76 | final heightValue13 = screenHeight / 71.23;
77 | final heightValue15 = screenHeight / 61.73;
78 | final heightValue17 = screenHeight / 54.47;
79 | final heightValue18 = screenHeight / 51.44;
80 | final heightValue19 = screenHeight / 48.73;
81 | final heightValue20 = screenHeight / 46.3;
82 | final heightValue21 = screenHeight / 44.09;
83 | final heightValue22 = screenHeight / 42.09;
84 | final heightValue23 = screenHeight / 40.26;
85 | final heightValue24 = screenHeight / 38.58;
86 | final heightValue25 = screenHeight / 37.04;
87 | final heightValue27 = screenHeight / 34.29;
88 | final heightValue28 = screenHeight / 33.07;
89 | final heightValue30 = screenHeight / 30.86;
90 | final heightValue32 = screenHeight / 28.93;
91 | final heightValue33 = screenHeight / 28.06;
92 | final heightValue35 = screenHeight / 26.45;
93 | final heightValue36 = screenHeight / 25.72;
94 | final heightValue37 = screenHeight / 25.02;
95 | final heightValue38 = screenHeight / 24.36;
96 | final heightValue40 = screenHeight / 23.15;
97 | final heightValue43 = screenHeight / 21.53;
98 | final heightValue45 = screenHeight / 20.57;
99 | final heightValue50 = screenHeight / 18.52;
100 | final heightValue55 = screenHeight / 16.83;
101 | final heightValue60 = screenHeight / 15.43;
102 | final heightValue65 = screenHeight / 14.24;
103 | final heightValue67 = screenHeight / 13.82;
104 | final heightValue70 = screenHeight / 13.22;
105 | final heightValue75 = screenHeight / 12.34;
106 | final heightValue80 = screenHeight / 11.575;
107 | final heightValue90 = screenHeight / 10.28;
108 | final heightValue93 = screenHeight / 9.95;
109 | final heightValue95 = screenHeight / 9.74;
110 | final heightValue98 = screenHeight / 9.44;
111 | final heightValue100 = screenHeight / 9.26;
112 | final heightValue110 = screenHeight / 8.41;
113 | final heightValue120 = screenHeight / 7.71;
114 | final heightValue130 = screenHeight / 7.12;
115 | final heightValue140 = screenHeight / 6.61;
116 | final heightValue150 = screenHeight / 6.17;
117 | final heightValue160 = screenHeight / 5.78;
118 | final heightValue165 = screenHeight / 5.61;
119 | final heightValue180 = screenHeight / 5.14;
120 | final heightValue200 = screenHeight / 4.63;
121 | final heightValue220 = screenHeight / 4.20;
122 | final heightValue224 = screenHeight / 4.13;
123 | final heightValue225 = screenHeight / 4.11;
124 | final heightValue228 = screenHeight / 4.06;
125 | final heightValue230 = screenHeight / 4.03;
126 | final heightValue240 = screenHeight / 3.85;
127 | final heightValue250 = screenHeight / 3.704;
128 | final heightValue255 = screenHeight / 3.63;
129 | final heightValue260 = screenHeight / 3.56;
130 | final heightValue270 = screenHeight / 3.42;
131 | final heightValue275 = screenHeight / 3.36;
132 | final heightValue280 = screenHeight / 3.30;
133 |
134 | final textFieldBorder = OutlineInputBorder(
135 | borderRadius: BorderRadius.all(
136 | Radius.circular(screenWidth / 52.97),
137 | ),
138 | borderSide: const BorderSide(
139 | color: Colors.transparent,
140 | ),
141 | );
142 |
143 | final textFieldBorderEnabled = OutlineInputBorder(
144 | borderRadius: BorderRadius.all(
145 | Radius.circular(screenWidth / 52.97),
146 | ),
147 | borderSide: const BorderSide(
148 | color: Colors.transparent,
149 | ),
150 | );
151 |
152 | final textFieldBorderFocused = OutlineInputBorder(
153 | borderRadius: BorderRadius.all(
154 | Radius.circular(screenWidth / 52.97),
155 | ),
156 | borderSide: const BorderSide(
157 | color: defaultAppColor,
158 | width: 1.0,
159 | ),
160 | );
161 |
--------------------------------------------------------------------------------
/lib/features/profile/screens/chat_screen.dart:
--------------------------------------------------------------------------------
1 | import 'dart:async';
2 | import 'package:flutter/material.dart';
3 | import 'package:pay_mobile_app/core/utils/global_constants.dart';
4 | import 'package:pay_mobile_app/features/profile/models/message_model.dart';
5 | import 'package:pay_mobile_app/features/profile/providers/chat_provider.dart';
6 | import 'package:pay_mobile_app/features/profile/services/profile_services.dart';
7 | import 'package:pay_mobile_app/features/profile/widgets/receivers_message_card.dart.dart';
8 | import 'package:pay_mobile_app/features/profile/widgets/senders_message_card.dart';
9 | import 'package:pay_mobile_app/features/auth/providers/user_provider.dart';
10 | import 'package:pay_mobile_app/widgets/custom_textfield.dart';
11 | import 'package:provider/provider.dart';
12 | import 'package:socket_io_client/socket_io_client.dart' as IO;
13 |
14 | class ChatScreen extends StatefulWidget {
15 | static const String route = "/chat-screen";
16 | const ChatScreen({Key? key}) : super(key: key);
17 |
18 | @override
19 | State createState() => _ChatScreenState();
20 | }
21 |
22 | class _ChatScreenState extends State {
23 | late final TextEditingController messageController;
24 | late final ScrollController scrollController;
25 | late final IO.Socket socket;
26 | late final StreamController> streamController;
27 | final ProfileServices profileServices = ProfileServices();
28 |
29 | @override
30 | void initState() {
31 | super.initState();
32 | final chatProvider = Provider.of(context, listen: false);
33 | print(chatProvider.chat.id);
34 | messageController = TextEditingController();
35 | scrollController = ScrollController();
36 | socket = IO.io(uri, {
37 | 'transports': ['websocket'],
38 | 'pingTimeout': 120000,
39 | 'cors': {'origin': uri},
40 | });
41 | streamController = StreamController>();
42 |
43 | socket.emit('join', {'chatId': chatProvider.chat.id});
44 | socket.on('message', (data) {
45 | streamController.add([MessageModel.fromJson(data)]);
46 | print(streamController);
47 | });
48 | loadMessages();
49 | // Future.delayed(Duration.zero, () {
50 | // scrollToBottom();
51 | // });
52 | }
53 |
54 | @override
55 | void dispose() {
56 | messageController.dispose();
57 | scrollController.dispose();
58 | socket.dispose();
59 | streamController.close();
60 | super.dispose();
61 | }
62 |
63 | Future loadMessages() async {
64 | final messages = await profileServices.getAllMessages(context: context);
65 | streamController.add(messages);
66 | }
67 |
68 | void scrollToBottom() {
69 | scrollController.animateTo(
70 | scrollController.position.maxScrollExtent,
71 | duration: const Duration(milliseconds: 200),
72 | curve: Curves.easeInOut,
73 | );
74 | }
75 |
76 | void sendMessage() async {
77 | if (messageController.text.isNotEmpty) {
78 | final chatProvider = Provider.of(context, listen: false);
79 | socket.emit('sendMessage', {
80 | 'chatId': chatProvider.chat.id,
81 | 'sender': chatProvider.chat.sender,
82 | 'receiver': chatProvider.chat.receiver,
83 | 'content': messageController.text,
84 | });
85 |
86 | messageController.clear();
87 | FocusScope.of(context).unfocus();
88 | Future.delayed(Duration.zero, () {
89 | scrollToBottom();
90 | });
91 | loadMessages();
92 | }
93 | }
94 |
95 | @override
96 | Widget build(BuildContext context) {
97 | return GestureDetector(
98 | onTap: () => FocusScope.of(context).unfocus(),
99 | child: Scaffold(
100 | appBar: AppBar(
101 | title: const Text('Pay Moblie Support'),
102 | centerTitle: true,
103 | ),
104 | body: Column(
105 | children: [
106 | Expanded(
107 | child: StreamBuilder>(
108 | stream: streamController.stream,
109 | builder: (context, snapshot) {
110 | if (snapshot.hasData) {
111 | final messages = snapshot.data!;
112 | return ListView.builder(
113 | controller: scrollController,
114 | itemCount: messages.length,
115 | itemBuilder: (context, index) {
116 | final message = messages[index];
117 | final userProvider =
118 | Provider.of(context, listen: false);
119 | if (message.sender == userProvider.user.username) {
120 | return SendersMessageCard(
121 | message: message.content,
122 | dateTime:
123 | '${message.createdAt.day}/${message.createdAt.month}/${message.createdAt.year} ${message.createdAt.hour}:${message.createdAt.minute}',
124 | user: 'You',
125 | );
126 | } else {
127 | return ReceiversMessageCard(
128 | message: message.content,
129 | dateTime:
130 | '${message.createdAt.day}/${message.createdAt.month}/${message.createdAt.year} ${message.createdAt.hour}:${message.createdAt.minute}',
131 | user: 'Pay Mobile Support',
132 | );
133 | }
134 | },
135 | );
136 | } else {
137 | return const Center(child: CircularProgressIndicator());
138 | }
139 | },
140 | ),
141 | ),
142 | Padding(
143 | padding:
144 | const EdgeInsets.symmetric(horizontal: 8.0, vertical: 8.0),
145 | child: Row(
146 | children: [
147 | Expanded(
148 | child: CustomTextField(
149 | controller: messageController,
150 | hintText: 'Enter your message',
151 | ),
152 | ),
153 | IconButton(
154 | onPressed: sendMessage,
155 | icon: const Icon(Icons.send),
156 | ),
157 | ],
158 | ),
159 | ),
160 | ],
161 | ),
162 | ),
163 | );
164 | }
165 | }
166 |
--------------------------------------------------------------------------------
/lib/features/auth/screens/login_screen.dart:
--------------------------------------------------------------------------------
1 | import 'package:flutter/material.dart';
2 | import 'package:pay_mobile_app/config/routes/custom_push_navigators.dart';
3 | import 'package:pay_mobile_app/core/utils/color_constants.dart';
4 | import 'package:pay_mobile_app/core/utils/global_constants.dart';
5 | import 'package:pay_mobile_app/core/utils/assets.dart';
6 | import 'package:pay_mobile_app/features/auth/screens/forgort_password_screen.dart';
7 | import 'package:pay_mobile_app/features/auth/screens/signup_screen.dart';
8 | import 'package:pay_mobile_app/features/auth/screens/signup_verification_screen.dart';
9 | import 'package:pay_mobile_app/features/auth/services/auth_service.dart';
10 | import 'package:pay_mobile_app/features/auth/providers/auth_provider.dart';
11 | import 'package:pay_mobile_app/features/auth/providers/user_provider.dart';
12 | import 'package:pay_mobile_app/widgets/custom_app_bar.dart';
13 | import 'package:pay_mobile_app/widgets/custom_button.dart';
14 | import 'package:pay_mobile_app/widgets/custom_textfield.dart';
15 | import 'package:pay_mobile_app/widgets/height_space.dart';
16 | import 'package:pay_mobile_app/widgets/main_app.dart';
17 | import 'package:provider/provider.dart';
18 |
19 | class LoginScreen extends StatefulWidget {
20 | static const route = '/login-screen';
21 | const LoginScreen({super.key});
22 |
23 | @override
24 | State createState() => _LoginScreenState();
25 | }
26 |
27 | class _LoginScreenState extends State {
28 | final TextEditingController usernameController = TextEditingController();
29 | final TextEditingController passwordController = TextEditingController();
30 | final AuthService authService = AuthService();
31 |
32 | bool obscureText = true;
33 | final loginFormKey = GlobalKey();
34 |
35 | @override
36 | void dispose() {
37 | super.dispose();
38 | usernameController.dispose();
39 | passwordController.dispose();
40 | }
41 |
42 | void loginUser() {
43 | if (loginFormKey.currentState!.validate()) {
44 | authService.loginInUser(
45 | context: context,
46 | username: usernameController.text,
47 | password: passwordController.text,
48 | onLoginSuccess: () {
49 | final userProvider =
50 | Provider.of(context, listen: false).user;
51 | final authProvider =
52 | Provider.of(context, listen: false);
53 | userProvider.isVerified == true
54 | ? Navigator.pushNamedAndRemoveUntil(
55 | context, MainApp.route, (route) => false,
56 | arguments: 0)
57 | : authService.sendOtp(
58 | context: context,
59 | email: userProvider.email,
60 | sendPurpose: 'sign-up-verification',
61 | onTapDialogButton: () => namedNavRemoveUntil(
62 | context,
63 | SignUpVerificationScreen.route,
64 | ),
65 | );
66 | authProvider.setUserEmail(userProvider.email);
67 | },
68 | );
69 | }
70 | }
71 |
72 | @override
73 | Widget build(BuildContext context) {
74 | return GestureDetector(
75 | onTap: () => FocusScope.of(context).unfocus(),
76 | child: Scaffold(
77 | appBar: const CustomAppBar(image: logo),
78 | body: SafeArea(
79 | child: Stack(
80 | children: [
81 | Padding(
82 | padding: const EdgeInsets.symmetric(horizontal: 20),
83 | child: SingleChildScrollView(
84 | child: Column(
85 | children: [
86 | HeightSpace(heightValue10),
87 | Padding(
88 | padding: EdgeInsets.only(right: value20),
89 | child: Text(
90 | "Login and start transfering",
91 | style: TextStyle(
92 | fontSize: heightValue35,
93 | fontWeight: FontWeight.w900,
94 | height: 1.5,
95 | ),
96 | ),
97 | ),
98 | formUI()
99 | ],
100 | ),
101 | ),
102 | ),
103 | Padding(
104 | padding: EdgeInsets.only(
105 | left: value20,
106 | right: value20,
107 | ),
108 | child: Column(
109 | mainAxisAlignment: MainAxisAlignment.end,
110 | children: [
111 | CustomButton(
112 | buttonText: "Login",
113 | buttonColor: primaryAppColor,
114 | borderRadius: heightValue30,
115 | buttonTextColor: scaffoldBackgroundColor,
116 | onTap: () {
117 | loginUser();
118 | },
119 | ),
120 | TextButton(
121 | onPressed: () {
122 | Navigator.pushNamed(context, SignUpScreen.route);
123 | },
124 | child: Text(
125 | "Create new account",
126 | style: TextStyle(
127 | fontWeight: FontWeight.bold,
128 | fontSize: heightValue17),
129 | ),
130 | )
131 | ],
132 | ),
133 | ),
134 | ],
135 | ),
136 | ),
137 | ),
138 | );
139 | }
140 |
141 | Widget formUI() {
142 | return Form(
143 | key: loginFormKey,
144 | child: Column(
145 | children: [
146 | CustomTextField(
147 | labelText: "Username",
148 | hintText: "Enter your unique username",
149 | prefixIcon: const Icon(Icons.alternate_email),
150 | willContainPrefix: true,
151 | controller: usernameController,
152 | ),
153 | CustomTextField(
154 | obscureText: obscureText,
155 | labelText: "Password",
156 | hintText: "Enter your password",
157 | controller: passwordController,
158 | icon: InkWell(
159 | onTap: () {
160 | setState(() {
161 | obscureText = !obscureText;
162 | });
163 | },
164 | child: Icon(
165 | obscureText ? Icons.visibility : Icons.visibility_off,
166 | ),
167 | ),
168 | ),
169 | TextButton(
170 | onPressed: () => namedNav(context, ForgortPasswordScreen.route),
171 | child: Text(
172 | "Forgort Password?",
173 | style: TextStyle(fontSize: heightValue17),
174 | ),
175 | )
176 | ],
177 | ),
178 | );
179 | }
180 | }
181 |
--------------------------------------------------------------------------------