commit ae60731d1c8608f56360ab80baa40b24812f0f15 Author: mirza.shafique Date: Mon Mar 20 17:00:41 2023 +0300 First Commit diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..a8e938c --- /dev/null +++ b/.gitignore @@ -0,0 +1,47 @@ +# Miscellaneous +*.class +*.log +*.pyc +*.swp +.DS_Store +.atom/ +.buildlog/ +.history +.svn/ +migrate_working_dir/ + +# IntelliJ related +*.iml +*.ipr +*.iws +.idea/ + +# The .vscode folder contains launch configuration and tasks you configure in +# VS Code which you may wish to be included in version control, so this line +# is commented out by default. +#.vscode/ + +# Flutter/Dart/Pub related +**/doc/api/ +**/ios/Flutter/.last_build_id +.dart_tool/ +.flutter-plugins +.flutter-plugins-dependencies +.packages +.pub-cache/ +.pub/ +/build/ + +# Web related +lib/generated_plugin_registrant.dart + +# Symbolication related +app.*.symbols + +# Obfuscation related +app.*.map.json + +# Android Studio will place build artifacts here +/android/app/debug +/android/app/profile +/android/app/release diff --git a/.metadata b/.metadata new file mode 100644 index 0000000..62eb0c0 --- /dev/null +++ b/.metadata @@ -0,0 +1,33 @@ +# This file tracks properties of this Flutter project. +# Used by Flutter tool to assess capabilities and perform upgrades etc. +# +# This file should be version controlled. + +version: + revision: ee4e09cce01d6f2d7f4baebd247fde02e5008851 + channel: stable + +project_type: app + +# Tracks metadata for the flutter migrate command +migration: + platforms: + - platform: root + create_revision: ee4e09cce01d6f2d7f4baebd247fde02e5008851 + base_revision: ee4e09cce01d6f2d7f4baebd247fde02e5008851 + - platform: android + create_revision: ee4e09cce01d6f2d7f4baebd247fde02e5008851 + base_revision: ee4e09cce01d6f2d7f4baebd247fde02e5008851 + - platform: ios + create_revision: ee4e09cce01d6f2d7f4baebd247fde02e5008851 + base_revision: ee4e09cce01d6f2d7f4baebd247fde02e5008851 + + # User provided section + + # List of Local paths (relative to this file) that should be + # ignored by the migrate tool. + # + # Files that are not part of the templates will be ignored by default. + unmanaged_files: + - 'lib/main.dart' + - 'ios/Runner.xcodeproj/project.pbxproj' diff --git a/README.md b/README.md new file mode 100644 index 0000000..ef96729 --- /dev/null +++ b/README.md @@ -0,0 +1,16 @@ +# mc_common_app + +A new Flutter project. + +## Getting Started + +This project is a starting point for a Flutter application. + +A few resources to get you started if this is your first Flutter project: + +- [Lab: Write your first Flutter app](https://docs.flutter.dev/get-started/codelab) +- [Cookbook: Useful Flutter samples](https://docs.flutter.dev/cookbook) + +For help getting started with Flutter development, view the +[online documentation](https://docs.flutter.dev/), which offers tutorials, +samples, guidance on mobile development, and a full API reference. diff --git a/analysis_options.yaml b/analysis_options.yaml new file mode 100644 index 0000000..61b6c4d --- /dev/null +++ b/analysis_options.yaml @@ -0,0 +1,29 @@ +# This file configures the analyzer, which statically analyzes Dart code to +# check for errors, warnings, and lints. +# +# The issues identified by the analyzer are surfaced in the UI of Dart-enabled +# IDEs (https://dart.dev/tools#ides-and-editors). The analyzer can also be +# invoked from the command line by running `flutter analyze`. + +# The following line activates a set of recommended lints for Flutter apps, +# packages, and plugins designed to encourage good coding practices. +include: package:flutter_lints/flutter.yaml + +linter: + # The lint rules applied to this project can be customized in the + # section below to disable rules from the `package:flutter_lints/flutter.yaml` + # included above or to enable additional rules. A list of all available lints + # and their documentation is published at + # https://dart-lang.github.io/linter/lints/index.html. + # + # Instead of disabling a lint rule for the entire project in the + # section below, it can also be suppressed for a single line of code + # or a specific dart file by using the `// ignore: name_of_lint` and + # `// ignore_for_file: name_of_lint` syntax on the line or in the file + # producing the lint. + rules: + # avoid_print: false # Uncomment to disable the `avoid_print` rule + # prefer_single_quotes: true # Uncomment to enable the `prefer_single_quotes` rule + +# Additional information about this file can be found at +# https://dart.dev/guides/language/analysis-options diff --git a/assets/fonts/Poppins-Medium.ttf b/assets/fonts/Poppins-Medium.ttf new file mode 100644 index 0000000..6bcdcc2 Binary files /dev/null and b/assets/fonts/Poppins-Medium.ttf differ diff --git a/assets/icons/Group 17.png b/assets/icons/Group 17.png new file mode 100644 index 0000000..7bb404a Binary files /dev/null and b/assets/icons/Group 17.png differ diff --git a/assets/icons/ic_branchs.svg b/assets/icons/ic_branchs.svg new file mode 100644 index 0000000..d074656 --- /dev/null +++ b/assets/icons/ic_branchs.svg @@ -0,0 +1,27 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/assets/icons/ic_close_account.svg b/assets/icons/ic_close_account.svg new file mode 100644 index 0000000..93adb61 --- /dev/null +++ b/assets/icons/ic_close_account.svg @@ -0,0 +1,10 @@ + + + + + + + + + + diff --git a/assets/icons/ic_face.svg b/assets/icons/ic_face.svg new file mode 100644 index 0000000..5fa9a9c --- /dev/null +++ b/assets/icons/ic_face.svg @@ -0,0 +1,18 @@ + + + + + + + + + + + + + + + + + + diff --git a/assets/icons/ic_face_id.png b/assets/icons/ic_face_id.png new file mode 100644 index 0000000..913e850 Binary files /dev/null and b/assets/icons/ic_face_id.png differ diff --git a/assets/icons/ic_fingerprint.png b/assets/icons/ic_fingerprint.png new file mode 100644 index 0000000..bf73197 Binary files /dev/null and b/assets/icons/ic_fingerprint.png differ diff --git a/assets/icons/ic_fingerprint.svg b/assets/icons/ic_fingerprint.svg new file mode 100644 index 0000000..ba45417 --- /dev/null +++ b/assets/icons/ic_fingerprint.svg @@ -0,0 +1,14 @@ + + + + + + + + + + + + + + diff --git a/assets/icons/ic_provider.svg b/assets/icons/ic_provider.svg new file mode 100644 index 0000000..e22c356 --- /dev/null +++ b/assets/icons/ic_provider.svg @@ -0,0 +1,3 @@ + + + diff --git a/assets/icons/ic_services.svg b/assets/icons/ic_services.svg new file mode 100644 index 0000000..b0d0606 --- /dev/null +++ b/assets/icons/ic_services.svg @@ -0,0 +1,13 @@ + + + + + + + + + + + + + diff --git a/assets/icons/ic_settings.svg b/assets/icons/ic_settings.svg new file mode 100644 index 0000000..6435135 --- /dev/null +++ b/assets/icons/ic_settings.svg @@ -0,0 +1,4 @@ + + + + diff --git a/assets/icons/ic_sms.png b/assets/icons/ic_sms.png new file mode 100644 index 0000000..aa72e0e Binary files /dev/null and b/assets/icons/ic_sms.png differ diff --git a/assets/icons/ic_sms.svg b/assets/icons/ic_sms.svg new file mode 100644 index 0000000..132ab7f --- /dev/null +++ b/assets/icons/ic_sms.svg @@ -0,0 +1,13 @@ + + + + + + + + + + + + + diff --git a/assets/icons/ic_whatsapp.png b/assets/icons/ic_whatsapp.png new file mode 100644 index 0000000..3f36403 Binary files /dev/null and b/assets/icons/ic_whatsapp.png differ diff --git a/assets/icons/ic_whatsapp.svg b/assets/icons/ic_whatsapp.svg new file mode 100644 index 0000000..073e581 --- /dev/null +++ b/assets/icons/ic_whatsapp.svg @@ -0,0 +1,13 @@ + + + + + + + + + + + + + diff --git a/assets/images/bc_Intro.svg b/assets/images/bc_Intro.svg new file mode 100644 index 0000000..deb4ffa --- /dev/null +++ b/assets/images/bc_Intro.svg @@ -0,0 +1,26 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/assets/images/bn_Intro.png b/assets/images/bn_Intro.png new file mode 100644 index 0000000..8c342d2 Binary files /dev/null and b/assets/images/bn_Intro.png differ diff --git a/assets/images/bn_car.jpeg b/assets/images/bn_car.jpeg new file mode 100644 index 0000000..5a6bd85 Binary files /dev/null and b/assets/images/bn_car.jpeg differ diff --git a/assets/images/bn_logo.svg b/assets/images/bn_logo.svg new file mode 100644 index 0000000..b0c971d --- /dev/null +++ b/assets/images/bn_logo.svg @@ -0,0 +1,560 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/assets/images/bn_map.png b/assets/images/bn_map.png new file mode 100644 index 0000000..b04b5aa Binary files /dev/null and b/assets/images/bn_map.png differ diff --git a/assets/images/ic_car.svg b/assets/images/ic_car.svg new file mode 100644 index 0000000..804f607 --- /dev/null +++ b/assets/images/ic_car.svg @@ -0,0 +1,11 @@ + + + + + + + + + + + diff --git a/assets/images/ic_edit.svg b/assets/images/ic_edit.svg new file mode 100644 index 0000000..c14165f --- /dev/null +++ b/assets/images/ic_edit.svg @@ -0,0 +1,4 @@ + + + + diff --git a/assets/images/ic_email.svg b/assets/images/ic_email.svg new file mode 100644 index 0000000..81c4573 --- /dev/null +++ b/assets/images/ic_email.svg @@ -0,0 +1,17 @@ + + + + + + + + + + + + + + + + + diff --git a/assets/images/ic_engine.png b/assets/images/ic_engine.png new file mode 100644 index 0000000..0256ff0 Binary files /dev/null and b/assets/images/ic_engine.png differ diff --git a/assets/images/ic_lock.svg b/assets/images/ic_lock.svg new file mode 100644 index 0000000..1273157 --- /dev/null +++ b/assets/images/ic_lock.svg @@ -0,0 +1,3 @@ + + + diff --git a/assets/images/ic_logo_white.png b/assets/images/ic_logo_white.png new file mode 100644 index 0000000..779fda4 Binary files /dev/null and b/assets/images/ic_logo_white.png differ diff --git a/assets/images/ic_logout.svg b/assets/images/ic_logout.svg new file mode 100644 index 0000000..2be107f --- /dev/null +++ b/assets/images/ic_logout.svg @@ -0,0 +1,11 @@ + + + + + + + + + + + diff --git a/assets/images/ic_mobile.svg b/assets/images/ic_mobile.svg new file mode 100644 index 0000000..068cf7a --- /dev/null +++ b/assets/images/ic_mobile.svg @@ -0,0 +1,10 @@ + + + + + + + + + + diff --git a/assets/images/ic_notes.svg b/assets/images/ic_notes.svg new file mode 100644 index 0000000..009cf17 --- /dev/null +++ b/assets/images/ic_notes.svg @@ -0,0 +1,12 @@ + + + + + + + + + + + + diff --git a/assets/images/ic_notification.svg b/assets/images/ic_notification.svg new file mode 100644 index 0000000..e45bab2 --- /dev/null +++ b/assets/images/ic_notification.svg @@ -0,0 +1,4 @@ + + + + diff --git a/assets/images/ic_settings.svg b/assets/images/ic_settings.svg new file mode 100644 index 0000000..83b64c9 --- /dev/null +++ b/assets/images/ic_settings.svg @@ -0,0 +1,4 @@ + + + + diff --git a/assets/images/ic_world.png b/assets/images/ic_world.png new file mode 100644 index 0000000..01ea634 Binary files /dev/null and b/assets/images/ic_world.png differ diff --git a/assets/images/logo.svg b/assets/images/logo.svg new file mode 100644 index 0000000..8552147 --- /dev/null +++ b/assets/images/logo.svg @@ -0,0 +1,38 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/assets/images/splash_logo.svg b/assets/images/splash_logo.svg new file mode 100644 index 0000000..481226e --- /dev/null +++ b/assets/images/splash_logo.svg @@ -0,0 +1,16 @@ + + + + + + + + + + + + + + + + diff --git a/assets/langs/ar-SA.json b/assets/langs/ar-SA.json new file mode 100644 index 0000000..4d542b6 --- /dev/null +++ b/assets/langs/ar-SA.json @@ -0,0 +1,138 @@ +{ + "firstTimeLogIn": "تسجيل الدخول لأول مره", + "signUp": "التسجيل", + "changeMobile": "تغيير رقم الجوال", + "notifications": "الاشعارات", + "general": "عام", + "defineLicences": "تحديد الرخص", + "dealershipSettings": "اعدادات البيع", + "changePassword": "تغيير كلمة المرور", + "retrievePassword" : "استرجاع كلمة المرور", + "changeEmail": "تغيير الايميل", + "verify": "تحقق", + "verified": "تم التحقق", + "signOut": "تسجيل خروج", + "enterEmail": "ادخل الايميل", + "enterNewEmail": "ادخل ايميل جديد", + "enterCurrentPassword": "كلمة المرور الحاليه", + "enterNewPassword": "كلمة المرور الجديده", + "enterOldPassword": "كلمة المرور القديمه", + "confirm": "تأكيد", + "enterNewPhoneNumber": "رقم جوال جديد", + "completeProfile": "الملف الشخصي", + "continu": "استمرار", + "confirmPassword": "تأكيد كلمة المرور", + "createPassword": "انشاء كلمة مرور جديده", + "email": "ايميل", + "firstName": "الأسم الأول *", + "surname": "اسم العائله *", + "confirmPass": "تأكيد كلمة المرور *", + "createPass": "انشاء كلمة مرور جديده *", + "newPassword": " كلمة مرور جديده", + "forgetPassword": "نسيت كلمة المرور", + "forgetPasswordRecover": "نسيت كلمة المرور؟ استعادة", + "editAccount": "تعديل الحساب", + "change": "تغيير", + "verifyAccount": "التحقق من الحساب", + "login" : "تسجيل دخول", + "welcomeMessage" : "مرحبا", + "forgetPass": "نسيت كلمة المرور ؟", + "enterPhoneNumber": "رقم جوال ", + "phoneNumberVerified": "تم التحقق من الجوال", + "verifyNewPassword": "التحقق من كلمة المرور", + "EnterPass": "ادخل كلمة المرور", + "alreadySigned": " تم تسجيل الدخول", + "emailChangedSuccessfully": "تم تغيير الايميل بنجاح", + "passwordIsUpdated" : "تم تحجيث كلمة المرور", + "passwordShouldContains" : "كلمة المرور يجب ان تحتوي على رمز رقم حرف كبير حرف صغير", + " successfullyRegistered": "تم التسجيل بنجاح", + "pleaseEnterSamePassword" : "ادخل كلمة مرور مطابقه", + "firstNameMandatory" : "ادخل الأسم الأول ", + "surnameNameMandatory" : "ادخل اسم العائله", + "passwordNameMandatory" : "ادخل كلمة المرور", + "enterValidEmail" : "ادخل ايميل صحيح", + "pleaseAcceptTerms" : "يجب الموافقه على الشروط", + "emailVerified" : "تم التحقق من الايميل بنجاح", + "selectMethod" : "اختر", + "emailAddress" : "ايميل", + "loginSelection" : "اختر", + "selectCountryCode" : "اختر رمز الدوله", + "selectProviderRole" : "اختر نوع الخدمه", + "addPhoneNo" : "اضف الهاتف", + "onlyCustomerApp": "نأسف هذا التطبيق فقط للعملاء", + "imageUploaded" : "تم تحميل الصوره", + "fileLarger" : "1KB حجم الملف اكبر من", + "account" : "الحساب", + "edit" : "تعديل", + "imageDeleted" : "تم حذف الصوره", + "dashboard" : "الصفحه الرئيسيه", + "termsOfService":"من خلال إنشاء حساب فإنك توافق على", + "userInformation": "معلومات المتسخدم", + "faceRecognition": "تحقق مع بصمة الوجه", + "fingerPrint" : "تحقق مع بصمة الاصبع", + "whatsapp": "تحقق مع Whatsapp", + "SMS": "رسائل قصيره", + "selectRole" : "حدد الدور", + "userRoleOrTitle" : "عنوان المستخدم", + "codeSentToEmail": "تم ارسال الرمز للايميل", + "number": "موبايل", + "english": "English", + "title": "Hello", + "msg": "Hello {} in the {} world ", + "msg_named": "{} are written in the {lang} language", + "clickMe": "Click me", + "profile": { + "reset_password": { + "label": "Reset Password", + "username": "Username", + "password": "password" + } + }, + "clicked": { + "zero": "You clicked {} times!", + "one": "You clicked {} time!", + "two": "You clicked {} times!", + "few": "You clicked {} times!", + "many": "You clicked {} times!", + "other": "You clicked {} times!" + }, + "amount": { + "zero": "Your amount : {} ", + "one": "Your amount : {} ", + "two": "Your amount : {} ", + "few": "Your amount : {} ", + "many": "Your amount : {} ", + "other": "Your amount : {} " + }, + "gender": { + "male": "Hi man ;) ", + "female": "Hello girl :)", + "with_arg": { + "male": "Hi man ;) {}", + "female": "Hello girl :) {}" + } + }, + "reset_locale": "Reset Language", + "welcomeDes": "أنت مكان واحد لكل ما تحتاجه سيارتك", + "log_in": "تسجيل الدخول", + "send": "إرسال", + "phoneNumber": "رقم الهاتف", + "forgetPasswordQ": "نسيت كلمة المرور؟", + "recover": "استعادة", + "retrivePassword": "استرجع كلمة المرور بإحدى الطرق التالية", + "retriveOnPhone": "سوف نرسل الاختيار إلى رقم هاتفك المحمول المسجل", + "retriveOnEmail": "سوف نرسل الاختيار إلى عنوان بريدك الإلكتروني المسجل", + "enterPhoneForVerfication": "الرجاء إدخال رقم هاتفك وسنرسل لك رمز التحقق", + "welcomeBack": "مرحبًا بعودتك!!!", + "selectYourCountry": "اختر بلدك", + "chooseCountry": "اختر الدوله", + "terms": "بنود الخدمة وخصوصية السياسة", + "profileMsg": "أدخل التفاصيل أدناه وأكمل معلومات الملف الشخصي", + "save": "حفظ", + "insert_otp_code": "ادخل الرمز", + "type_code": "الرجاء كتابة الرمز الذي أرسلناه إلى", + "resend_code": "أعد إرسال الرمز", + "check_code": "التحقق من الشفرة", + "time_will_expire": "إعادة إرسال الرمز بتنسيق", + "sec" : "ثانية" +} \ No newline at end of file diff --git a/assets/langs/en-US.json b/assets/langs/en-US.json new file mode 100644 index 0000000..ae3143e --- /dev/null +++ b/assets/langs/en-US.json @@ -0,0 +1,138 @@ +{ + "firstTimeLogIn" : "First Time Log In", + "signUp": "Sign Up", + "changeMobile": "Change Mobile", + "notifications": "Notifications", + "general": "General", + "defineLicences": "Define Licences", + "dealershipSettings": "Dealership Settings", + "changePassword": "Change Password", + "retrievePassword" : "Retrieve Password", + "changeEmail": "Change Email", + "verify": "Verify", + "verified": "Verified", + "signOut": "Sign Out", + "enterEmail": "Enter Email", + "enterNewEmail": "Enter New Email", + "enterNewPassword": "Enter New Password", + "enterCurrentPassword": "Enter Current Password", + "enterOldPassword": "Enter Old Password", + "confirm": "Confirm", + "completeProfile": "Complete Profile", + "enterNewPhoneNumber": "Enter New Phone Number", + "enterPhoneNumber": "Enter Phone Number", + "continu": "Continue", + "confirmPassword": "Confirm Password", + "createPassword": "Create Password", + "email": "Email", + "firstName": "First Name *", + "surname": "Surname *", + "confirmPass": "Confirm Password *", + "createPass": "Create Password *", + "newPassword": "New Password", + "forgetPassword": "Forget Password", + "forgetPasswordRecover": "Forget Password? Recover", + "editAccount": "Edit Account", + "change": "Change", + "verifyAccount": "Verify Account", + "login" : "Log In", + "welcomeMessage" : "Welcome Message", + "forgetPass": "Forget Password ?", + "phoneNumberVerified": "Phone Number Verified", + "verifyNewPassword": "Verify New Password", + "EnterPass": "Enter Password ?", + "alreadySigned": " Already Signed Up and Logged In", + "emailChangedSuccessfully": "Email is Changed Successfully", + "passwordIsUpdated" : "Password is Updated", + "passwordShouldContains" : "Password Should contains Character, Number, Capital and small letters,", + " successfullyRegistered": " Successfully Registered, Please login once,", + "pleaseEnterSamePassword" : "Please enter same password", + "firstNameMandatory" : "First name is mandatory", + "surnameNameMandatory" : "Surname is mandatory", + "passwordNameMandatory" : "Password is mandatory", + "enterValidEmail" : "Enter Valid Email", + "pleaseAcceptTerms" : "Please accept terms", + "emailVerified" : "Email is verified successfully", + "selectMethod" : "Select Method", + "emailAddress" : "Email Address", + "loginSelection" : "Login Selection", + "selectCountryCode" : "Please select Country Code", + "selectProviderRole" : "Please select Provider Role", + "addPhoneNo" : "Please add Phone No", + "onlyCustomerApp": "Sorry, Only Customer's can log in this app", + "imageUploaded" : "Image is uploaded", + "fileLarger" : "File is larger then 1KB", + "account" : "Account", + "edit" : "EDIT", + "imageDeleted" : "Image is Deleted", + "dashboard" : "Dashboard/Main Page", + "termsOfService":"By creating an account you agree to our", + "userInformation": "User Information", + "faceRecognition": "Face Recognition", + "fingerPrint" : "Finger Print", + "whatsapp": "With Whatsapp", + "SMS": "With SMS", + "selectRole" : "Select Role", + "userRoleOrTitle" : "User role or title", + "codeSentToEmail": "Code is sent to email", + "number": "Number", + "english": "عربي", + "title": "Hello", + "msg": "Hello {} in the {} world ", + "msg_named": "{} are written in the {lang} language", + "clickMe": "Click me", + "profile": { + "reset_password": { + "label": "Reset Password", + "username": "Username", + "password": "password" + } + }, + "clicked": { + "zero": "You clicked {} times!", + "one": "You clicked {} time!", + "two": "You clicked {} times!", + "few": "You clicked {} times!", + "many": "You clicked {} times!", + "other": "You clicked {} times!" + }, + "amount": { + "zero": "Your amount : {} ", + "one": "Your amount : {} ", + "two": "Your amount : {} ", + "few": "Your amount : {} ", + "many": "Your amount : {} ", + "other": "Your amount : {} " + }, + "gender": { + "male": "Hi man ;) ", + "female": "Hello girl :)", + "with_arg": { + "male": "Hi man ;) {}", + "female": "Hello girl :) {}" + } + }, + "reset_locale": "Reset Language", + "welcomeDes": "You one stop place all your car needs", + "log_in": "Log In", + "send": "Send", + "phoneNumber": "Phone Number", + "forgetPasswordQ": "Forget Password?", + "recover": "Recover", + "retrivePassword": "Retrive password by one of following method", + "retriveOnPhone": "We will send the opt to your registered mobile number", + "retriveOnEmail": "We will send the opt to your registered email address", + "enterPhoneForVerfication": "Please enter your phone number We will send you the verification code", + "welcomeBack": "Welcome Back!!!", + "selectYourCountry": "Select Your Country", + "chooseCountry": "Choose Country", + "terms": "Terms of Service and Privacy Policy", + "profileMsg": "Enter the details below and complete the profile info", + "save": "Save", + "insert_otp_code": "Enter the code", + "type_code": "Please type the code we sent to", + "resend_code": "Resend Code", + "check_code": "Check Code", + "time_will_expire": "Resend code in", + "sec" : "sec" +} \ No newline at end of file diff --git a/lib/api/api_client.dart b/lib/api/api_client.dart new file mode 100644 index 0000000..4819948 --- /dev/null +++ b/lib/api/api_client.dart @@ -0,0 +1,326 @@ +import 'dart:async'; +import 'dart:convert'; +import 'dart:io'; + +import 'package:flutter/foundation.dart'; +import 'package:http/http.dart'; +import 'package:http/io_client.dart'; +import 'package:mc_common_app/classes/app_state_cm.dart'; +import 'package:mc_common_app/classes/consts.dart'; +import 'package:mc_common_app/exceptions/api_exception.dart'; +import 'package:mc_common_app/models/user/refresh_token.dart'; +import 'package:mc_common_app/models/user/user.dart'; +import 'package:mc_common_app/utils/shared_prefrence.dart'; + +typedef FactoryConstructor = U Function(dynamic); + +class APIError { + int errorCode; + String errorMessage; + + APIError(this.errorCode, this.errorMessage); + + Map toJson() => {'errorCode': errorCode, 'errorMessage': errorMessage}; + + @override + String toString() { + return jsonEncode(this); + } + + static APIException throwAPIException(Response response) { + switch (response.statusCode) { + case 400: + APIError? apiError; + if (response.body != null && response.body.isNotEmpty) { + var jsonError = jsonDecode(response.body); + apiError = APIError(jsonError['errorCode'], jsonError['errorMessage']); + } + return APIException(APIException.BAD_REQUEST, error: apiError); + case 401: + return const APIException(APIException.UNAUTHORIZED); + case 403: + return const APIException(APIException.FORBIDDEN); + case 404: + return const APIException(APIException.NOT_FOUND); + case 500: + return const APIException(APIException.INTERNAL_SERVER_ERROR); + case 444: + var downloadUrl = response.headers["location"]; + return APIException(APIException.UPGRADE_REQUIRED, arguments: downloadUrl); + default: + return const APIException(APIException.OTHER); + } + } +} + +abstract class ApiClient { + Future postJsonForObject(FactoryConstructor factoryConstructor, String url, T jsonObject, + {String? token, Map? queryParameters, Map? headers, int retryTimes = 0}); + + Future postJsonForResponse(String url, T jsonObject, {String? token, Map? queryParameters, Map? headers, int retryTimes = 0}); + + Future getJsonForObject(FactoryConstructor factoryConstructor, String url, {String? token, Map? queryParameters, Map? headers, int retryTimes = 0}); + + Future getJsonForResponse(String url, {String? token, Map? queryParameters, Map? headers, int retryTimes = 0}); +} + +class ApiClientImp implements ApiClient { + @override + Future postJsonForObject(FactoryConstructor factoryConstructor, String url, T jsonObject, + {String? token, Map? queryParameters, Map? headers, int retryTimes = 0}) async { + var _headers = {'Accept': 'application/json'}; + if (headers != null && headers.isNotEmpty) { + _headers.addAll(headers); + } + if (!kReleaseMode) { + debugPrint("Url:$url"); + debugPrint("body:$jsonObject"); + } + var response = await postJsonForResponse(url, jsonObject, token: token, queryParameters: queryParameters, headers: _headers, retryTimes: retryTimes); + try { + if (!kReleaseMode) { + debugPrint("res121:" + response.body); + debugPrint("res121:" + response.statusCode.toString()); + } + var jsonData = jsonDecode(response.body); + return factoryConstructor(jsonData); + } catch (ex) { + debugPrint(ex.toString()); + debugPrint("exception:" + ex.toString()); + throw APIException(APIException.BAD_RESPONSE_FORMAT, arguments: ex); + } + } + + @override + Future postJsonForResponse(String url, T jsonObject, {String? token, Map? queryParameters, Map? headers, int retryTimes = 0}) async { + String? requestBody; + if (jsonObject != null) { + requestBody = jsonEncode(jsonObject); + if (headers == null) { + headers = {'Content-Type': 'application/json'}; + } else { + headers['Content-Type'] = 'application/json'; + } + } + + return await _postForResponse(url, requestBody, token: token, queryParameters: queryParameters, headers: headers, retryTimes: retryTimes); + } + + Future _postForResponse( + String url, + requestBody, { + String? token, + Map? queryParameters, + Map? headers, + int retryTimes = 0, + }) async { + try { + var _headers = {}; + if (token != null) { + _headers['Authorization'] = 'Bearer $token'; + } + + if (headers != null && headers.isNotEmpty) { + _headers.addAll(headers); + } + + if (queryParameters != null) { + var queryString = Uri(queryParameters: queryParameters).query; + url = url + '?' + queryString; + } + + Response response; + + response = await _post(Uri.parse(url), body: requestBody, headers: _headers).timeout(const Duration(seconds: 100)); + + if (!kReleaseMode) { + debugPrint("Url:$url"); + debugPrint("body:$requestBody"); + debugPrint("res: " + response.body); + } + if (response.statusCode >= 200 && response.statusCode < 500) { + var jsonData = jsonDecode(response.body); + if (jsonData["StatusMessage"] != null && jsonData["StatusMessage"] == "Unauthorized user attempt to access API") { + String mToken = await updateUserToken(); + return await _postForResponse(url, requestBody, token: mToken, queryParameters: queryParameters, headers: headers, retryTimes: retryTimes); + } + return response; + } else { + throw APIError.throwAPIException(response); + } + } on SocketException catch (e) { + if (retryTimes > 0) { + debugPrint('will retry after 3 seconds...'); + await Future.delayed(const Duration(seconds: 3)); + return await _postForResponse(url, requestBody, token: token, queryParameters: queryParameters, headers: headers, retryTimes: retryTimes - 1); + } else { + throw APIException(APIException.OTHER, arguments: e); + } + } on HttpException catch (e) { + if (retryTimes > 0) { + debugPrint('will retry after 3 seconds...'); + await Future.delayed(const Duration(seconds: 3)); + return await _postForResponse(url, requestBody, token: token, queryParameters: queryParameters, headers: headers, retryTimes: retryTimes - 1); + } else { + throw APIException(APIException.OTHER, arguments: e); + } + } on TimeoutException catch (e) { + throw APIException(APIException.TIMEOUT, arguments: e); + } on ClientException catch (e) { + if (retryTimes > 0) { + debugPrint('will retry after 3 seconds...'); + await Future.delayed(const Duration(seconds: 3)); + return await _postForResponse(url, requestBody, token: token, queryParameters: queryParameters, headers: headers, retryTimes: retryTimes - 1); + } else { + throw APIException(APIException.OTHER, arguments: e); + } + } catch (ex) { + debugPrint("exception1:" + ex.toString()); + throw APIException(APIException.BAD_RESPONSE_FORMAT, arguments: ex); + } + } + + bool _certificateCheck(X509Certificate cert, String host, int port) => true; + + Future _withClient(Future Function(Client) fn) async { + var httpClient = HttpClient()..badCertificateCallback = _certificateCheck; + var client = IOClient(httpClient); + try { + return await fn(client); + } finally { + client.close(); + } + } + + Future _post(url, {Map? headers, body, Encoding? encoding}) => _withClient((client) => client.post(url, headers: headers, body: body, encoding: encoding)); + + @override + Future getJsonForObject(FactoryConstructor factoryConstructor, String url, + {String? token, Map? queryParameters, Map? headers, int retryTimes = 0}) async { + var _headers = {'Accept': 'application/json'}; + if (headers != null && headers.isNotEmpty) { + _headers.addAll(headers); + } + var response = await getJsonForResponse(url, token: token, queryParameters: queryParameters, headers: _headers, retryTimes: retryTimes); + try { + if (!kReleaseMode) { + debugPrint("res:" + response.body); + } + var jsonData = jsonDecode(response.body); + return factoryConstructor(jsonData); + } catch (ex) { + debugPrint("exception:" + response.body); + throw APIException(APIException.BAD_RESPONSE_FORMAT, arguments: ex); + } + } + + @override + Future getJsonForResponse(String url, {String? token, Map? queryParameters, Map? headers, int retryTimes = 0}) async { + if (headers == null) { + headers = {'Content-Type': 'application/json'}; + } else { + headers['Content-Type'] = 'application/json'; + } + return await _getForResponse(url, token: token, queryParameters: queryParameters, headers: headers, retryTimes: retryTimes); + } + + bool isFirstCall = true; + + Future _getForResponse(String url, {String? token, Map? queryParameters, Map? headers, int retryTimes = 0}) async { + try { + var _headers = {}; + if (token != null) { + _headers['Authorization'] = 'Bearer $token'; + } + + if (headers != null && headers.isNotEmpty) { + _headers.addAll(headers); + } + if (queryParameters != null) { + String queryString = Uri(queryParameters: queryParameters).query; + if (isFirstCall) url = url + '?' + queryString.toString(); + } + + if (!kReleaseMode) { + debugPrint("Url:$url"); + debugPrint("queryParameters:$queryParameters"); + } + var response = await _get(Uri.parse(url), headers: _headers).timeout(const Duration(seconds: 60)); + + if (!kReleaseMode) { + debugPrint("res: " + response.body.toString()); + } + if (response.statusCode >= 200 && response.statusCode < 500) { + var jsonData = jsonDecode(response.body); + if (jsonData["StatusMessage"] != null && jsonData["StatusMessage"] == "Unauthorized user attempt to access API") { + String mToken = await updateUserToken(); + isFirstCall = false; + return await _getForResponse(url, token: mToken, queryParameters: queryParameters, headers: headers, retryTimes: retryTimes); + } + return response; + } else { + throw APIError.throwAPIException(response); + } + } on SocketException catch (e) { + if (retryTimes > 0) { + debugPrint('will retry after 3 seconds...'); + await Future.delayed(const Duration(seconds: 3)); + return await _getForResponse(url, token: token, queryParameters: queryParameters, headers: headers, retryTimes: retryTimes - 1); + } else { + throw APIException(APIException.OTHER, arguments: e); + } + } on HttpException catch (e) { + if (retryTimes > 0) { + debugPrint('will retry after 3 seconds...'); + await Future.delayed(const Duration(seconds: 3)); + return await _getForResponse(url, token: token, queryParameters: queryParameters, headers: headers, retryTimes: retryTimes - 1); + } else { + throw APIException(APIException.OTHER, arguments: e); + } + } on TimeoutException catch (e) { + throw APIException(APIException.TIMEOUT, arguments: e); + } on ClientException catch (e) { + if (retryTimes > 0) { + await Future.delayed(const Duration(seconds: 3)); + return await _getForResponse(url, token: token, queryParameters: queryParameters, headers: headers, retryTimes: retryTimes - 1); + } else { + throw APIException(APIException.OTHER, arguments: e); + } + } catch (e) { + throw APIException(APIException.OTHER, arguments: e); + } + } + + Future _get(url, {Map? headers}) => _withClient((client) => client.get(url, headers: headers)); + +// Future refreshTokenAPI(String token, String refreshToken) async { +// var postParams = {"token": token, "refreshToken": refreshToken}; +// // String t = AppStateCm().getUser.data!.accessToken ?? ""; +// return await postJsonForObject((json) => RefreshToken.fromJson(json), ApiConsts.RefreshToken, postParams); +// } + + // //TODO: needs to solve later this. + // String updateUserToken() { + // return ""; + // } + + Future refreshTokenAPI(String token, String refreshToken) async { + var postParams = {"token": token, "refreshToken": refreshToken}; + // String t = AppStateCm().getUser.data!.accessToken ?? ""; + return await postJsonForObject((json) => RefreshToken.fromJson(json), ApiConsts.RefreshToken, postParams); + } + + Future updateUserToken() async { + String token = await SharedPrefManager.getUserToken(); + String refreshToken = await SharedPrefManager.getRefreshToken(); + RefreshToken refresh = await refreshTokenAPI(token, refreshToken); + SharedPrefManager.setUserToken(refresh.data!.accessToken ?? ""); + SharedPrefManager.setRefreshToken(refresh.data!.refreshToken ?? ""); + String mdata = await SharedPrefManager.getData(); + UserInfo info = UserInfo.fromJson(jsonDecode(mdata)); + User user = User(); + user.data = UserData(accessToken: refresh.data!.accessToken ?? "", refreshToken: refresh.data!.refreshToken ?? "", userInfo: info); + AppStateCm().setUser = user; + return refresh.data!.accessToken??""; + } +} diff --git a/lib/classes/app_state_cm.dart b/lib/classes/app_state_cm.dart new file mode 100644 index 0000000..dcd2f86 --- /dev/null +++ b/lib/classes/app_state_cm.dart @@ -0,0 +1,35 @@ + + +import 'package:injector/injector.dart'; +import 'package:mc_common_app/models/post_params_model.dart'; +import 'package:mc_common_app/models/user/user.dart'; + + +class AppStateCm { + static final AppStateCm _instance = AppStateCm._internal(); + + AppStateCm._internal(); + + factory AppStateCm() => _instance; + + bool isLogged = false; + + set setLogged(v) => isLogged = v; + + bool? get getIsLogged => isLogged; + + User? _user = null; + + set setUser(v) => _user = v; + + User get getUser => _user??User(); + + PostParamsModel? _postParams; + + PostParamsModel? get postParamsObject => _postParams; + + Map get postParamsJson => _postParams?.toJson() ?? {}; + void setPostParamsModel(PostParamsModel _postParams) { + this._postParams = _postParams; + } +} diff --git a/lib/classes/consts.dart b/lib/classes/consts.dart new file mode 100644 index 0000000..ff16d46 --- /dev/null +++ b/lib/classes/consts.dart @@ -0,0 +1,69 @@ + +class AppCommonConst{ + static String baseUrl = "https://ms.hmg.com/"; // production server +} + +class ApiConsts { + // static String baseUrl = "http://10.200.204.20:2801/"; // Local server + static String baseUrl = "https://ms.hmg.com/"; // production server + static String baseUrlServices = baseUrl + ""; // production server + static String BasicOTP = baseUrlServices + "api/Register/BasicOTP"; + static String BasicVerify = baseUrlServices + "api/Register/BasicVerify"; + static String BasicComplete = baseUrlServices + "api/Register/BasicComplete"; + static String RefreshToken = baseUrlServices + "api/Account/RefreshToken"; + + + //User + static String Login_V1 = baseUrlServices + "api/Account/Login_V1"; + static String Login_V2_OTP = baseUrlServices + "api/Account/Login_V2_OTP"; + static String Login_V2_OTPVerify = baseUrlServices + "api/Account/Login_V2_OTPVerify"; + static String user = baseUrlServices + "api/User/"; + static String GetAllCountry = baseUrlServices + "api/Master/Country_Get"; + static String GetProviderRoles = baseUrlServices + "api/Master/RoleServiceProvider_Get"; + static String GetAllCities = baseUrlServices + "api/Master/City_Get"; + static String ForgetPasswordOTPRequest = baseUrlServices + "api/Account/ForgetPasswordOTPRequest"; + static String ForgetPasswordOTPCompare = baseUrlServices + "api/Account/ForgetPasswordOTPCompare"; + static String ForgetPassword = baseUrlServices + "api/Account/ForgetPassword"; + static String Login_Email_OTP = baseUrlServices + "api/Account/EmailVerify"; + static String Login_Email_OTPVerify = baseUrlServices + "api/Account/EmailVerifyOTPVerify"; + static String ChangePassword = baseUrlServices + "api/Account/ChangePassword"; + static String ChangeMobileNoOTPRequest = baseUrlServices + "api/Account/ChangeMobileNoOTPRequest"; + static String ChangeMobileNo = baseUrlServices + "api/Account/ChangeMobileNo"; + static String ChangeEmailOTPRequest = baseUrlServices + "api/Account/ChangeEmailOTPRequest"; + static String ChangeEmail = baseUrlServices + "api/Account/ChangeEmail"; + static String EmailVerify = baseUrlServices + "api/Account/EmailVerify"; + static String EmailVerifyOTPVerify = baseUrlServices + "api/Account/EmailVerifyOTPVerify"; + static String UpdateUserImage = baseUrlServices + "api/User_UpdateProfileImage"; + static String GetUserImage = baseUrlServices + "api/ProfileImage"; + + + //Profile + static String GetProviderDocument = baseUrlServices + "api/ServiceProviders/ServiceProviderDocument_Get"; + static String ServiceProviderDocument_Update = baseUrlServices + "api/ServiceProviders/ServiceProviderDocument_Update"; + + //Branch + static String createProviderBranch = baseUrlServices + "api/ServiceProviders/ServiceProviderBranch_Create"; + static String ServiceProviderBranchGet = baseUrlServices + "api/ServiceProviders/ServiceProviderBranch_Get"; + static String ServiceCategory_Get = baseUrlServices + "api/Master/ServiceCategory_Get"; + static String Services_Get = baseUrlServices + "api/ServiceProviders/Services_Get"; + static String ServiceProviderService_Create = baseUrlServices + "api/ServiceProviders/ServiceProviderService_Create"; +} + +class GlobalConsts { + static String isRememberMe = "remember_me"; + static String email = "email"; + static String password = "password"; + static String bookmark = "bookmark"; + static String fontZoomSize = "font_zoom_size"; + static String welcomeVideoUrl = "welcomeVideoUrl"; + static String doNotShowWelcomeVideo = "doNotShowWelcomeVideo"; +} + +const String icons = "assets/icons/"; +const String categorySvgIcons = "assets/category/svg/"; +const String svgIcons = "assets/svg/"; + +RegExp numReg = RegExp(r".*[0-9].*"); +RegExp letterReg = RegExp(r".*[A-Za-z].*"); + + diff --git a/lib/config/constants.dart b/lib/config/constants.dart new file mode 100644 index 0000000..8b13789 --- /dev/null +++ b/lib/config/constants.dart @@ -0,0 +1 @@ + diff --git a/lib/config/dependencies.dart b/lib/config/dependencies.dart new file mode 100644 index 0000000..857bc62 --- /dev/null +++ b/lib/config/dependencies.dart @@ -0,0 +1,25 @@ +// import 'package:firebase_crashlytics/firebase_crashlytics.dart'; +// import 'package:flutter/material.dart'; + + + +import 'package:injector/injector.dart'; +import 'package:mc_common_app/api/api_client.dart'; +import 'package:mc_common_app/classes/app_state_cm.dart'; +import 'package:mc_common_app/repositories/user_repo.dart'; +import 'package:mc_common_app/services/services.dart'; + +Injector injector = Injector.appInstance; + +class AppDependencies { + + static void addDependencies() { + //services + injector.registerSingleton(() => AppStateCm()); + injector.registerSingleton(() => ApiClientImp()); + injector.registerSingleton(() => CommonServicesImp()); + + //repos + injector.registerSingleton(() => UserRepoImp()); + } +} diff --git a/lib/config/routes.dart b/lib/config/routes.dart new file mode 100644 index 0000000..0c17e79 --- /dev/null +++ b/lib/config/routes.dart @@ -0,0 +1,80 @@ +import 'package:mc_common_app/models/user/register_user.dart'; + +// import 'package:mc_common_app/views/settings/create_services_page.dart'; +// import 'package:mc_common_app/views/settings/dealership_page.dart'; +// import 'package:mc_common_app/views/settings/define_branch_page.dart'; +// import 'package:mc_common_app/views/settings/define_license_page.dart'; +import 'package:mc_common_app/views/user/change_email_page.dart'; +import 'package:mc_common_app/views/user/change_mobile_page.dart'; +import 'package:mc_common_app/views/user/change_password_page.dart'; +import 'package:mc_common_app/views/user/complete_profile_page.dart'; +import 'package:mc_common_app/views/user/confirm_new_password_page.dart'; +import 'package:mc_common_app/views/user/edit_account_page.dart'; +import 'package:mc_common_app/views/user/forget_password_method_page.dart'; +import 'package:mc_common_app/views/user/forget_password_page.dart'; +import 'package:mc_common_app/views/user/login_method_selection_page.dart'; +import 'package:mc_common_app/views/user/login_verification_page.dart'; +import 'package:mc_common_app/views/user/login_verify_account_page.dart'; +import 'package:mc_common_app/views/user/login_with_password_page.dart'; + +// import 'package:mc_common_app/views/user/profile/profile_1_page.dart'; +// import 'package:mc_common_app/views/user/profile/profile_2_page.dart'; +// import 'package:mc_common_app/views/user/profile/profile_3_page.dart'; +import 'package:mc_common_app/views/user/register_page.dart'; +import 'package:mc_common_app/views/user/register_selection_page.dart'; +import 'package:mc_common_app/views/splash/splash_page.dart'; +import 'package:mc_common_app/views/user/vertify_password_page.dart'; +import 'package:flutter/material.dart'; + +class AppRoutes { + //User + static const String splash = "/splash"; + static const String registerSelection = "/registerSelection"; + static const String loginVerifyAccount = "/loginVerifyAccount"; + static const String register = "/register"; + static const String forgetPassword = "/forgetPassword"; + static const String loginVerification = "/loginVerification"; + static const String loginWithPassword = "/loginWithPassword"; + static const String loginMethodSelection = "/loginMethodSelection"; + static const String completeProfile = "/completeProfile"; + static const String profile1 = "/profile1"; + static const String profile2 = "/profile2"; + static const String profile3 = "/profile3"; + static const String verifyPassword = "/vertifyPassword"; + static const String confirmNewPasswordPage = "/confirmNewPasswordPage"; + static const String defineLicense = "/defineLicese"; + static const String changePassword = "/changePassword"; + static const String forgetPasswordMethodPage = "/forgetPasswordMethodPage"; + static const String changeMobilePage = "/changeMobilePage"; + static const String changeEmailPage = "/changeEmailPage"; + static const String editAccountPage = "/editAccoundPage"; + + static const String dashboard = "/dashboard"; + + //settings + static const String dealershipSetting = "/dealershipSetting"; + static const String defineBranch = "/defineBranch"; + static const String createServices = "/createServices"; + + static const String initialRoute = splash; + + static final Map routes = { + //User + splash: (context) => const SplashPage(), + registerSelection: (context) => RegisterSelectionPage(), + loginVerifyAccount: (context) => LoginVerifyAccountPage(), + register: (context) => RegisterPage(), + forgetPassword: (context) => ForgetPasswordPage(), + loginVerification: (context) => const LoginVerificationPage(), + loginWithPassword: (context) => LoginWithPassword(), + loginMethodSelection: (context) => LoginMethodSelectionPage(ModalRoute.of(context)!.settings.arguments as String), + completeProfile: (context) => CompleteProfilePage(ModalRoute.of(context)!.settings.arguments as RegisterUserRespModel), + verifyPassword: (context) => VerifyPasswordPage(), + confirmNewPasswordPage: (context) => ConfirmNewPasswordPage(ModalRoute.of(context)!.settings.arguments as String), + changePassword: (context) => ChangePasswordPage(), + forgetPasswordMethodPage: (context) => ForgetPasswordMethodPage(ModalRoute.of(context)!.settings.arguments as String), + changeMobilePage: (context) => ChangeMobilePage(), + changeEmailPage: (context) => const ChangeEmailPage(), + editAccountPage: (context) => EditAccountPage(), + }; +} diff --git a/lib/exceptions/api_exception.dart b/lib/exceptions/api_exception.dart new file mode 100644 index 0000000..1c9e02e --- /dev/null +++ b/lib/exceptions/api_exception.dart @@ -0,0 +1,31 @@ +import 'dart:convert'; + +import 'package:mc_common_app/api/api_client.dart'; + + + +class APIException implements Exception { + static const String BAD_REQUEST = 'api_common_bad_request'; + static const String UNAUTHORIZED = 'api_common_unauthorized'; + static const String FORBIDDEN = 'api_common_forbidden'; + static const String NOT_FOUND = 'api_common_not_found'; + static const String INTERNAL_SERVER_ERROR = 'api_common_internal_server_error'; + static const String UPGRADE_REQUIRED = 'api_common_upgrade_required'; + static const String BAD_RESPONSE_FORMAT = 'api_common_bad_response_format'; + static const String OTHER = 'api_common_http_error'; + static const String TIMEOUT = 'api_common_http_timeout'; + static const String UNKNOWN = 'unexpected_error'; + + final String message; + final APIError? error; + final arguments; + + const APIException(this.message, {this.arguments, this.error}); + + Map toJson() => {'message': message, 'error': error, 'arguments': '$arguments'}; + + @override + String toString() { + return jsonEncode(this); + } +} diff --git a/lib/extensions/int_extensions.dart b/lib/extensions/int_extensions.dart new file mode 100644 index 0000000..9b90b2f --- /dev/null +++ b/lib/extensions/int_extensions.dart @@ -0,0 +1,7 @@ +import 'package:flutter/cupertino.dart'; + +extension IntExtensions on int { + Widget get height => SizedBox(height: toDouble()); + + Widget get width => SizedBox(width: toDouble()); +} diff --git a/lib/extensions/string_extensions.dart b/lib/extensions/string_extensions.dart new file mode 100644 index 0000000..9c33a44 --- /dev/null +++ b/lib/extensions/string_extensions.dart @@ -0,0 +1,65 @@ + +import 'package:flutter/cupertino.dart'; +import 'package:intl/intl.dart'; +import 'package:mc_common_app/theme/colors.dart'; + +extension EmailValidator on String { + Widget toText({Color? color, bool isBold = false, double? fontSize, bool isUnderLine = false, TextDecoration? textDecoration, double letterSpacing = -0.4, TextAlign? textAlign, double? height}) => + Text( + this, + textAlign: textAlign, + style: TextStyle( + height: height, + decoration: textDecoration ?? TextDecoration.none, + fontSize: fontSize ?? 10, + fontWeight: isBold ? FontWeight.bold : FontWeight.w600, + color: color ?? MyColors.darkTextColor, + letterSpacing: letterSpacing, + ), + ); + + + bool isValidEmail() { + return RegExp(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,}))$').hasMatch(this); + } + + bool isNum() { + return RegExp(r'^[0-9]+$').hasMatch(this); + } + + String toFormattedDate() { + String date = split("T")[0]; + String time = split("T")[1]; + var dates = date.split("-"); + return "${dates[2]} ${getMonth(int.parse(dates[1]))} ${dates[0]} ${DateFormat('hh:mm a').format(DateFormat('hh:mm:ss').parse(time))}"; + } + + getMonth(int month) { + switch (month) { + case 1: + return "January"; + case 2: + return "February"; + case 3: + return "March"; + case 4: + return "April"; + case 5: + return "May"; + case 6: + return "June"; + case 7: + return "July"; + case 8: + return "August"; + case 9: + return "September"; + case 10: + return "October"; + case 11: + return "November"; + case 12: + return "December"; + } + } +} diff --git a/lib/extensions/widget_extensions.dart b/lib/extensions/widget_extensions.dart new file mode 100644 index 0000000..474cbee --- /dev/null +++ b/lib/extensions/widget_extensions.dart @@ -0,0 +1,10 @@ +import 'package:flutter/material.dart'; + +extension WidgetExtensions on Widget { + Widget onPress(VoidCallback onTap) => InkWell(onTap: onTap, child: this); + + Widget paddingAll(double _value) => Padding(padding: EdgeInsets.all(_value), child: this); + + Widget paddingOnly({double left = 0.0, double right = 0.0, double top = 0.0, double bottom = 0.0}) => + Padding(padding: EdgeInsets.only(left: left, right: right, top: top, bottom: bottom), child: this); +} diff --git a/lib/generated/locale_keys.g.dart b/lib/generated/locale_keys.g.dart new file mode 100644 index 0000000..b3e0e18 --- /dev/null +++ b/lib/generated/locale_keys.g.dart @@ -0,0 +1,164 @@ +// DO NOT EDIT. This is code generated via package:easy_localization/generate.dart + +abstract class LocaleKeys { + static const firstTimeLogIn = 'firstTimeLogIn'; + static const signUp = 'signUp'; + static const changeMobile = 'changeMobile'; + static const notifications = 'notifications'; + static const general = 'general'; + static const defineLicences = 'defineLicences'; + static const dealershipSettings = 'dealershipSettings'; + static const changePassword = 'changePassword'; + static const retrievePassword = 'retrievePassword'; + static const changeEmail = 'changeEmail'; + static const verify = 'verify'; + static const verified = 'verified'; + static const signOut = 'signOut'; + static const enterEmail = 'enterEmail'; + static const enterNewEmail = 'enterNewEmail'; + static const enterCurrentPassword = 'enterCurrentPassword'; + static const enterNewPassword = 'enterNewPassword'; + static const enterOldPassword = 'enterOldPassword'; + static const confirm = 'confirm'; + static const enterNewPhoneNumber = 'enterNewPhoneNumber'; + static const completeProfile = 'completeProfile'; + static const continu = 'continu'; + static const confirmPassword = 'confirmPassword'; + static const createPassword = 'createPassword'; + static const email = 'email'; + static const firstName = 'firstName'; + static const surname = 'surname'; + static const confirmPass = 'confirmPass'; + static const createPass = 'createPass'; + static const newPassword = 'newPassword'; + static const forgetPassword = 'forgetPassword'; + static const forgetPasswordQ = 'forgetPasswordQ'; + static const recover = 'recover'; + static const forgetPasswordRecover = 'forgetPasswordRecover'; + static const editAccount = 'editAccount'; + static const change = 'change'; + static const verifyAccount = 'verifyAccount'; + static const login = 'login'; + static const log_in = 'log_in'; + static const welcomeMessage = 'welcomeMessage'; + static const welcomeDes = 'welcomeDes'; + static const forgetPass = 'forgetPass'; + static const enterPhoneNumber = 'enterPhoneNumber'; + static const phoneNumberVerified = 'phoneNumberVerified'; + static const verifyNewPassword = 'verifyNewPassword'; + static const EnterPass = 'EnterPass'; + static const send = 'send'; + static const retrivePassword = 'retrivePassword'; + static const retriveOnPhone = 'retriveOnPhone'; + static const retriveOnEmail = 'retriveOnEmail'; + static const enterPhoneForVerfication = 'enterPhoneForVerfication'; + static const selectYourCountry = 'selectYourCountry'; + static const welcomeBack = 'welcomeBack'; + static const alreadySigned = 'alreadySigned'; + static const emailChangedSuccessfully = 'emailChangedSuccessfully'; + static const passwordIsUpdated = 'passwordIsUpdated'; + static const passwordShouldContains = 'passwordShouldContains'; + static const successfullyRegistered = ' successfullyRegistered'; + static const pleaseEnterSamePassword = 'pleaseEnterSamePassword'; + static const firstNameMandatory = 'firstNameMandatory'; + static const surnameNameMandatory = 'surnameNameMandatory'; + static const passwordNameMandatory = 'passwordNameMandatory'; + static const enterValidEmail = 'enterValidEmail'; + static const pleaseAcceptTerms = 'pleaseAcceptTerms'; + static const emailVerified = 'emailVerified'; + static const selectMethod = 'selectMethod'; + static const emailAddress = 'emailAddress'; + static const loginSelection = 'loginSelection'; + static const selectCountryCode = 'selectCountryCode'; + static const selectProviderRole = 'selectProviderRole'; + static const addPhoneNo = 'addPhoneNo'; + static const onlyProviderApp = 'onlyProviderApp'; + static const imageUploaded = 'imageUploaded'; + static const fileLarger = 'fileLarger'; + static const account = 'account'; + static const edit = 'edit'; + static const imageDeleted = 'imageDeleted'; + static const dashboard = 'dashboard'; + static const pickAddress = 'pickAddress'; + static const pickLocation = 'pickLocation'; + static const save = 'save'; + static const defineServices = 'defineServices'; + static const selectBranch = 'selectBranch '; + static const selectServiceCategory = 'selectServiceCategory'; + static const defineBranches = 'defineBranches'; + static const defineProviders = 'defineProviders'; + static const closeAccount = 'closeAccount'; + static const createBranch = 'createBranch'; + static const updateBranch = 'updateBranch'; + static const address = 'address'; + static const branchDescription = 'branchDescription'; + static const branchName = 'branchName'; + static const chooseCity = 'chooseCity'; + static const chooseCountry = 'chooseCountry'; + static const selectAttachment = 'selectAttachment'; + static const somethingWrong = 'somethingWrong'; + static const documentsUploaded = 'documentsUploaded'; + static const update = 'update'; + static const termsOfService = 'termsOfService'; + static const terms = 'terms'; + static const profileMsg = 'profileMsg'; + static const branchInfo = 'branchInfo'; + static const profileCompleted = 'profileCompleted'; + static const selectLocationMap = 'selectLocationMap'; + static const licensesAndCertifications = 'licensesAndCertifications'; + static const completeProfile1 = 'completeProfile1'; + static const completeProfile2 = 'completeProfile2'; + static const completeProfile3 = 'completeProfile3'; + static const userInformation = 'userInformation'; + static const faceRecognition = 'faceRecognition'; + static const fingerPrint = 'fingerPrint'; + static const whatsapp = 'whatsapp'; + static const SMS = 'SMS'; + static const selectRole = 'selectRole'; + static const userRoleOrTitle = 'userRoleOrTitle'; + static const codeSentToEmail = 'codeSentToEmail'; + static const number = 'number'; + static const phoneNumber = 'phoneNumber'; + static const english = 'english'; + static const provider = 'provider'; + static const title = 'title'; + static const msg = 'msg'; + static const msg_named = 'msg_named'; + static const clickMe = 'clickMe'; + static const profile_reset_password_label = 'profile.reset_password.label'; + static const profile_reset_password_username = 'profile.reset_password.username'; + static const profile_reset_password_password = 'profile.reset_password.password'; + static const profile_reset_password = 'profile.reset_password'; + static const profile = 'profile'; + static const clicked = 'clicked'; + static const amount = 'amount'; + static const gender_with_arg = 'gender.with_arg'; + static const gender = 'gender'; + static const reset_locale = 'reset_locale'; + static const insert_otp_code = 'insert_otp_code'; + static const type_code = 'type_code'; + static const resend_code = 'resend_code'; + static const check_code = 'check_code'; + static const time_will_expire = 'time_will_expire'; + static const sec = 'sec'; + static const no_city_available = 'no_city_available'; + static const branch_created = 'branch_created'; + static const branch_updated = 'branch_updated'; + static const branch_deleted = 'branch_deleted'; + static const dashboard_main = 'dashboard_main'; + static const logo_brand = 'logo_brand'; + static const remove = 'remove'; + static const no_branch = 'no_branch'; + static const login_once = 'login_once'; + static const defineLicenese = 'defineLicenese'; + static const description = 'description'; + static const attachFile = 'attachFile'; + static const branchLocation = 'branchLocation'; + static const tapToEdit = 'tapToEdit'; + static const myServiceBranches = 'myServiceBranches'; + static const enter_licence_detail = 'enter_licence_detail'; + static const country = 'country'; + static const city = 'city'; + static const editServices = 'editServices'; + +} diff --git a/lib/main.dart b/lib/main.dart new file mode 100644 index 0000000..9ad34b6 --- /dev/null +++ b/lib/main.dart @@ -0,0 +1,137 @@ +import 'dart:io'; + +import 'package:easy_localization/easy_localization.dart'; + +import 'package:flutter/material.dart'; +import 'package:mc_common_app/classes/app_state_cm.dart'; +import 'package:mc_common_app/classes/app_state_cm.dart'; +import 'package:mc_common_app/classes/app_state_cm.dart'; + +import 'package:mc_common_app/theme/app_theme.dart'; +import 'package:injector/injector.dart'; +import 'package:logger/logger.dart'; +import 'package:provider/provider.dart'; +import 'package:provider/single_child_widget.dart'; +import 'package:sizer/sizer.dart'; + +late AppStateCm appStateCm; + +final navigatorKey = GlobalKey(); + +Logger logger = Logger( + printer: PrettyPrinter( + lineLength: 0, + ), +); + +class MyHttpOverrides extends HttpOverrides { + @override + HttpClient createHttpClient(SecurityContext? context) { + return super.createHttpClient(context)..badCertificateCallback = (X509Certificate cert, String host, int port) => true; + } +} + +Future main() async { + WidgetsFlutterBinding.ensureInitialized(); + + await EasyLocalization.ensureInitialized(); + // AppStateCm().setPostParamsInitConfig(); + HttpOverrides.global = MyHttpOverrides(); + + runApp( + EasyLocalization( + supportedLocales: const [ + Locale('en', 'US'), + Locale('ar', 'SA'), + ], + path: 'resources', + // assetLoader: const CodegenLoader(), + child: MultiProvider( + providers: [ + // ChangeNotifierProvider( + // create: (_) => LoginProviderModel(), + // ), + ], + child: MyApp(), + ), + ), + ); +} + +// todo terminal command to genertate translation files +// flutter pub run easy_localization:generate -S resources -f keys -O lib/generated -o locale_keys.g.dart + +class MyApp extends StatelessWidget { + @override + Widget build(BuildContext context) { + return LayoutBuilder(builder: (context, constraints) { + return Sizer( + builder: ( + BuildContext context, + Orientation orientation, + DeviceType deviceType, + ) { + List> delegates = context.localizationDelegates; + // AppStateCm().setPostParamsModel( + // PostParamsModel( + // languageID: EasyLocalization.of(context)?.locale.languageCode == "ar" ? 1 : 2, + // ), + // ); + return MaterialApp( + // key: navigatorKey, + navigatorKey: navigatorKey, + theme: AppTheme.getTheme( + EasyLocalization.of(context)?.locale.languageCode == "ar", + ), + debugShowCheckedModeBanner: false, + localizationsDelegates: delegates, + supportedLocales: context.supportedLocales, + locale: context.locale, + ); + }, + ); + }); + } +} + +// class MyApp extends StatelessWidget { +// MyApp({super.key}) { +// AppDependencies.addDependencies(); +// AppStateCm = Injector.appInstance.get(); +// // AppStateCm.setPostParamsInitConfig(); +// } +// +// @override +// Widget build(BuildContext context) { +// return LayoutBuilder(builder: (context, constraints) { +// return Sizer( +// builder: ( +// BuildContext context, +// Orientation orientation, +// DeviceType deviceType, +// ) { +// SizeConfig().init(constraints, orientation); +// List> delegates = context.localizationDelegates; +// // AppStateCm().setPostParamsModel( +// // PostParamsModel( +// // languageID: EasyLocalization.of(context)?.locale.languageCode == "ar" ? 1 : 2, +// // ), +// // ); +// return MaterialApp( +// // key: navigatorKey, +// navigatorKey: navigatorKey, +// theme: AppTheme.getTheme( +// EasyLocalization.of(context)?.locale.languageCode == "ar", +// ), +// debugShowCheckedModeBanner: false, +// localizationsDelegates: delegates, +// supportedLocales: context.supportedLocales, +// locale: context.locale, +// initialRoute: AppRoutes.initialPage, +// routes: AppRoutes.routes, +// ); +// }, +// ); +// }); +// } +// } diff --git a/lib/models/account.dart b/lib/models/account.dart new file mode 100644 index 0000000..699bfba --- /dev/null +++ b/lib/models/account.dart @@ -0,0 +1,44 @@ +// To parse this JSON data, do +// +// final account = accountFromJson(jsonString); + +import 'dart:convert'; + +import 'package:mc_common_app/models/parent_list.dart'; + + + + +Account accountFromJson(String str) => Account.fromJson(json.decode(str)); + +String accountToJson(Account data) => json.encode(data.toJson()); + +class Account { + Account({ + required this.parentList, + required this.selectedItem, + }); + + List? parentList; + int selectedItem; + + factory Account.fromJson(Map json) => Account( + parentList: json["parentList"] == null + ? null + : List.from( + json["parentList"].map((x) => ParentList.fromJson(x))), + selectedItem: + json["selectedItem"], + ); + + Map toJson() => { + "parentList": parentList == null + ? null + : List.from(parentList!.map((x) => x.toJson())), + "selectedItem": selectedItem, + }; + + Map toJsonData() => { + "selectedItem": selectedItem, + }; +} diff --git a/lib/models/config_model.dart b/lib/models/config_model.dart new file mode 100644 index 0000000..0245ede --- /dev/null +++ b/lib/models/config_model.dart @@ -0,0 +1,12 @@ +class ConfigModel { + ConfigModel(this.endpoint, this.organizationName); + + String endpoint; + + String organizationName; + + factory ConfigModel.fromJson(Map json) => + ConfigModel("", ""); + +// Map toJson() => _$ConfigModelToJson(this); +} diff --git a/lib/models/content_info_model.dart b/lib/models/content_info_model.dart new file mode 100644 index 0000000..4eec746 --- /dev/null +++ b/lib/models/content_info_model.dart @@ -0,0 +1,65 @@ +class ContentInfoModel { + int? totalItemsCount; + int? statusCode; + String? message; + List? data; + + ContentInfoModel({this.totalItemsCount, this.statusCode, this.message, this.data}); + + ContentInfoModel.fromJson(Map json) { + totalItemsCount = json['totalItemsCount']; + statusCode = json['statusCode']; + message = json['message']; + if (json['data'] != null) { + data = []; + json['data'].forEach((v) { + data?.add(new ContentInfoDataModel.fromJson(v)); + }); + } + } + + Map toJson() { + final Map data = new Map(); + data['totalItemsCount'] = this.totalItemsCount; + data['statusCode'] = this.statusCode; + data['message'] = this.message; + if (this.data != null) { + data['data'] = this.data?.map((v) => v.toJson()).toList(); + } + return data; + } +} + +class ContentInfoDataModel { + int? contentInfoId; + int? contentTypeId; + String? content; + String? contentTypeNameEn; + String? contentTypeNameAr; + String? fileName; + String? exposeFilePath; + + ContentInfoDataModel({this.contentInfoId, this.contentTypeId, this.content, this.contentTypeNameEn, this.contentTypeNameAr, this.fileName, this.exposeFilePath}); + + ContentInfoDataModel.fromJson(Map json) { + contentInfoId = json['contentInfoId']; + contentTypeId = json['contentTypeId']; + content = json['content']; + contentTypeNameEn = json['contentTypeNameEn']; + contentTypeNameAr = json['contentTypeNameAr']; + fileName = json['fileName']; + exposeFilePath = json['exposeFilePath']; + } + + Map toJson() { + final Map data = new Map(); + data['contentInfoId'] = this.contentInfoId; + data['contentTypeId'] = this.contentTypeId; + data['content'] = this.content; + data['contentTypeNameEn'] = this.contentTypeNameEn; + data['contentTypeNameAr'] = this.contentTypeNameAr; + data['fileName'] = this.fileName; + data['exposeFilePath'] = this.exposeFilePath; + return data; + } +} diff --git a/lib/models/m_response.dart b/lib/models/m_response.dart new file mode 100644 index 0000000..5926e33 --- /dev/null +++ b/lib/models/m_response.dart @@ -0,0 +1,33 @@ +// To parse this JSON data, do +// +// final mResponse = mResponseFromJson(jsonString); + +import 'dart:convert'; + +MResponse mResponseFromJson(String str) => MResponse.fromJson(json.decode(str)); + +String mResponseToJson(MResponse data) => json.encode(data.toJson()); + +class MResponse { + MResponse({ + this.totalItemsCount, + this.messageStatus, + this.message, + }); + + int? totalItemsCount; + int? messageStatus; + String? message; + + factory MResponse.fromJson(Map json) => MResponse( + totalItemsCount: json["totalItemsCount"], + messageStatus: json["messageStatus"], + message: json["message"], + ); + + Map toJson() => { + "totalItemsCount": totalItemsCount, + "messageStatus": messageStatus, + "message": message, + }; +} diff --git a/lib/models/member_model.dart b/lib/models/member_model.dart new file mode 100644 index 0000000..d968827 --- /dev/null +++ b/lib/models/member_model.dart @@ -0,0 +1,62 @@ +class MemberModel { + int? totalItemsCount; + int? statusCode; + String? message; + List? data; + + MemberModel({this.totalItemsCount, this.statusCode, this.message, this.data}); + + MemberModel.fromJson(Map json) { + totalItemsCount = json['totalItemsCount']; + statusCode = json['statusCode']; + message = json['message']; + if (json['data'] != null) { + data = []; + json['data'].forEach((v) { + data?.add(new MemberDataModel.fromJson(v)); + }); + } + } + + Map toJson() { + final Map data = new Map(); + data['totalItemsCount'] = this.totalItemsCount; + data['statusCode'] = this.statusCode; + data['message'] = this.message; + if (this.data != null) { + data['data'] = this.data?.map((v) => v.toJson()).toList(); + } + return data; + } +} + +class MemberDataModel { + int? committeeId; + String? firstName; + String? lastName; + String? description; + String? picture; + int? orderNo; + + MemberDataModel({this.committeeId, this.firstName, this.lastName, this.description, this.picture, this.orderNo}); + + MemberDataModel.fromJson(Map json) { + committeeId = json['committeeId']; + firstName = json['firstName']; + lastName = json['lastName']; + description = json['description']; + picture = json['picture']; + orderNo = json['orderNo']; + } + + Map toJson() { + final Map data = new Map(); + data['committeeId'] = this.committeeId; + data['firstName'] = this.firstName; + data['lastName'] = this.lastName; + data['description'] = this.description; + data['picture'] = this.picture; + data['orderNo'] = this.orderNo; + return data; + } +} diff --git a/lib/models/parent_list.dart b/lib/models/parent_list.dart new file mode 100644 index 0000000..3f2286f --- /dev/null +++ b/lib/models/parent_list.dart @@ -0,0 +1,26 @@ +class ParentList { + ParentList({ + required this.dbId, + required this.text, + required this.path, + required this.isSelected, + }); + + int dbId; + String text; + String path; + bool isSelected; + + factory ParentList.fromJson(Map json) => ParentList( + dbId: json["dbId"] == null ? null : json["dbId"], + text: json["text"] == null ? null : json["text"], + path: json["path"] == null ? null : json["path"], + isSelected: false, + ); + + Map toJson() => { + "dbId": dbId == null ? null : dbId, + "text": text == null ? null : text, + "path": path == null ? null : path, + }; +} diff --git a/lib/models/post_params_model.dart b/lib/models/post_params_model.dart new file mode 100644 index 0000000..780210b --- /dev/null +++ b/lib/models/post_params_model.dart @@ -0,0 +1,35 @@ + +class PostParamsModel { + double? versionID; + int? channel; + int? languageID; + String? mobileType; + String? logInTokenID; + String? tokenID; + + PostParamsModel({this.versionID, this.channel, this.languageID, this.mobileType, this.logInTokenID, this.tokenID}); + + PostParamsModel.fromJson(Map json) { + versionID = json['VersionID']; + channel = json['Channel']; + languageID = json['LanguageID']; + mobileType = json['MobileType']; + logInTokenID = json['LogInTokenID']; + tokenID = json['TokenID']; + } + + Map toJson() { + final Map data = new Map(); + data['VersionID'] = this.versionID; + data['Channel'] = this.channel; + data['LanguageID'] = this.languageID; + data['MobileType'] = this.mobileType; + data['LogInTokenID'] = this.logInTokenID; + data['TokenID'] = this.tokenID; + return data; + } + + set setLogInTokenID(String? token) => logInTokenID = token; + + set setTokenID(String? token) => tokenID = token; +} diff --git a/lib/models/profile/branch.dart b/lib/models/profile/branch.dart new file mode 100644 index 0000000..cc7d68a --- /dev/null +++ b/lib/models/profile/branch.dart @@ -0,0 +1,85 @@ +// To parse this JSON data, do +// +// final branch = branchFromJson(jsonString); + +import 'dart:convert'; + +Branch branchFromJson(String str) => Branch.fromJson(json.decode(str)); + +String branchToJson(Branch data) => json.encode(data.toJson()); + +class Branch { + Branch({ + this.totalItemsCount, + this.data, + this.messageStatus, + this.message, + }); + + int? totalItemsCount; + List? data; + int? messageStatus; + String? message; + + factory Branch.fromJson(Map json) => Branch( + totalItemsCount: json["totalItemsCount"] == null ? null : json["totalItemsCount"], + data: json["data"] == null ? null : List.from(json["data"].map((x) => BranchData.fromJson(x))), + messageStatus: json["messageStatus"] == null ? null : json["messageStatus"], + message: json["message"] == null ? null : json["message"], + ); + + Map toJson() => { + "totalItemsCount": totalItemsCount == null ? null : totalItemsCount, + "data": data == null ? null : List.from(data!.map((x) => x.toJson())), + "messageStatus": messageStatus == null ? null : messageStatus, + "message": message == null ? null : message, + }; +} + +class BranchData { + BranchData({ + this.id, + this.serviceProviderId, + this.branchName, + this.branchDescription, + this.cityId, + this.address, + this.latitude, + this.longitude, + this.status, + }); + + int? id; + int? serviceProviderId; + String? branchName; + String? branchDescription; + int? cityId; + String? address; + String? latitude; + String? longitude; + int? status; + + factory BranchData.fromJson(Map json) => BranchData( + id: json["id"] == null ? null : json["id"], + serviceProviderId: json["serviceProviderID"] == null ? null : json["serviceProviderID"], + branchName: json["branchName"] == null ? null : json["branchName"], + branchDescription: json["branchDescription"] == null ? null : json["branchDescription"], + cityId: json["cityID"] == null ? null : json["cityID"], + address: json["address"] == null ? null : json["address"], + latitude: json["latitude"] == null ? null : json["latitude"], + longitude: json["longitude"] == null ? null : json["longitude"], + status: json["status"] == null ? null : json["status"], + ); + + Map toJson() => { + "id": id == null ? null : id, + "serviceProviderID": serviceProviderId == null ? null : serviceProviderId, + "branchName": branchName == null ? null : branchName, + "branchDescription": branchDescription == null ? null : branchDescription, + "cityID": cityId == null ? null : cityId, + "address": address == null ? null : address, + "latitude": latitude == null ? null : latitude, + "longitude": longitude == null ? null : longitude, + "status": status == null ? null : status, + }; +} diff --git a/lib/models/profile/categroy.dart b/lib/models/profile/categroy.dart new file mode 100644 index 0000000..6f566f1 --- /dev/null +++ b/lib/models/profile/categroy.dart @@ -0,0 +1,69 @@ +// To parse this JSON data, do +// +// final category = categoryFromJson(jsonString); + +import 'dart:convert'; + +Category categoryFromJson(String str) => Category.fromJson(json.decode(str)); + +String categoryToJson(Category data) => json.encode(data.toJson()); + +class Category { + Category({ + this.totalItemsCount, + this.data, + this.messageStatus, + this.message, + }); + + int? totalItemsCount; + List? data; + int? messageStatus; + String? message; + + factory Category.fromJson(Map json) => Category( + totalItemsCount: json["totalItemsCount"] == null ? null : json["totalItemsCount"], + data: json["data"] == null ? null : List.from(json["data"].map((x) => CategoryData.fromJson(x))), + messageStatus: json["messageStatus"] == null ? null : json["messageStatus"], + message: json["message"] == null ? null : json["message"], + ); + + Map toJson() => { + "totalItemsCount": totalItemsCount == null ? null : totalItemsCount, + "data": data == null ? null : List.from(data!.map((x) => x.toJson())), + "messageStatus": messageStatus == null ? null : messageStatus, + "message": message == null ? null : message, + }; +} + +class CategoryData { + CategoryData({ + this.id, + this.categoryName, + this.categoryNameN, + this.serviceCategoryIconUrl, + this.serviceCategoryImageUrl, + }); + + int? id; + String? categoryName; + String? categoryNameN; + dynamic? serviceCategoryIconUrl; + dynamic? serviceCategoryImageUrl; + + factory CategoryData.fromJson(Map json) => CategoryData( + id: json["id"] == null ? null : json["id"], + categoryName: json["categoryName"] == null ? null : json["categoryName"], + categoryNameN: json["categoryNameN"] == null ? null : json["categoryNameN"], + serviceCategoryIconUrl: json["serviceCategoryIconUrl"], + serviceCategoryImageUrl: json["serviceCategoryImageUrl"], + ); + + Map toJson() => { + "id": id == null ? null : id, + "categoryName": categoryName == null ? null : categoryName, + "categoryNameN": categoryNameN == null ? null : categoryNameN, + "serviceCategoryIconUrl": serviceCategoryIconUrl, + "serviceCategoryImageUrl": serviceCategoryImageUrl, + }; +} diff --git a/lib/models/profile/document.dart b/lib/models/profile/document.dart new file mode 100644 index 0000000..da082b3 --- /dev/null +++ b/lib/models/profile/document.dart @@ -0,0 +1,83 @@ +// To parse this JSON data, do +// +// final document = documentFromJson(jsonString); + +import 'dart:convert'; + +Document documentFromJson(String str) => Document.fromJson(json.decode(str)); + +String documentToJson(Document data) => json.encode(data.toJson()); + +class Document { + Document({ + this.totalItemsCount, + this.data, + this.messageStatus, + this.message, + }); + + int? totalItemsCount; + List? data; + int? messageStatus; + String? message; + + factory Document.fromJson(Map json) => Document( + totalItemsCount: json["totalItemsCount"] == null ? null : json["totalItemsCount"], + data: json["data"] == null ? null : List.from(json["data"].map((x) => DocumentData.fromJson(x))), + messageStatus: json["messageStatus"] == null ? null : json["messageStatus"], + message: json["message"] == null ? null : json["message"], + ); + + Map toJson() => { + "totalItemsCount": totalItemsCount == null ? null : totalItemsCount, + "data": data == null ? null : List.from(data!.map((x) => x.toJson())), + "messageStatus": messageStatus == null ? null : messageStatus, + "message": message == null ? null : message, + }; +} + +class DocumentData { + DocumentData({ + this.id, + this.serviceProviderId, + this.documentId, + this.documentUrl, + this.status, + this.comment, + this.isActive, + this.document, + this.fileExt, + }); + + int? id; + int? serviceProviderId; + int? documentId; + dynamic? documentUrl; + int? status; + dynamic? comment; + bool? isActive; + String? document; + String? fileExt; + + factory DocumentData.fromJson(Map json) => DocumentData( + id: json["id"] == null ? null : json["id"], + serviceProviderId: json["serviceProviderID"] == null ? null : json["serviceProviderID"], + documentId: json["documentID"] == null ? null : json["documentID"], + documentUrl: json["documentURL"], + status: json["status"] == null ? null : json["status"], + comment: json["comment"], + isActive: json["isActive"] == null ? null : json["isActive"], + document: null, + fileExt: null, + ); + + Map toJson() => { + "id": id == null ? null : id, + "serviceProviderID": serviceProviderId == null ? null : serviceProviderId, + "documentID": documentId == null ? null : documentId, + "documentURL": documentUrl, + "status": status == null ? null : status, + "comment": comment, + "isActive": isActive == null ? null : isActive, + }; +} diff --git a/lib/models/profile/services.dart b/lib/models/profile/services.dart new file mode 100644 index 0000000..d296300 --- /dev/null +++ b/lib/models/profile/services.dart @@ -0,0 +1,80 @@ +// To parse this JSON data, do +// +// final services = servicesFromJson(jsonString); + +import 'dart:convert'; + +Services servicesFromJson(String str) => Services.fromJson(json.decode(str)); + +String servicesToJson(Services data) => json.encode(data.toJson()); + +class Services { + Services({ + this.totalItemsCount, + this.data, + this.messageStatus, + this.message, + }); + + int? totalItemsCount; + List? data; + int? messageStatus; + String? message; + + factory Services.fromJson(Map json) => Services( + totalItemsCount: json["totalItemsCount"] == null ? null : json["totalItemsCount"], + data: json["data"] == null ? null : List.from(json["data"].map((x) => ServicesData.fromJson(x))), + messageStatus: json["messageStatus"] == null ? null : json["messageStatus"], + message: json["message"] == null ? null : json["message"], + ); + + Map toJson() => { + "totalItemsCount": totalItemsCount == null ? null : totalItemsCount, + "data": data == null ? null : List.from(data!.map((x) => x.toJson())), + "messageStatus": messageStatus == null ? null : messageStatus, + "message": message == null ? null : message, + }; +} + +class ServicesData { + ServicesData({ + this.id, + this.description, + this.descriptionN, + this.serviceIconUrl, + this.serviceImageUrl, + this.serviceCategoryId, + this.categoryName, + this.isSelected, + }); + + int? id; + String? description; + String? descriptionN; + dynamic? serviceIconUrl; + dynamic? serviceImageUrl; + int? serviceCategoryId; + dynamic? categoryName; + bool? isSelected; + + factory ServicesData.fromJson(Map json) => ServicesData( + id: json["id"] == null ? null : json["id"], + description: json["description"] == null ? null : json["description"], + descriptionN: json["descriptionN"] == null ? null : json["descriptionN"], + serviceIconUrl: json["serviceIconUrl"], + serviceImageUrl: json["serviceImageUrl"], + serviceCategoryId: json["serviceCategoryID"] == null ? null : json["serviceCategoryID"], + categoryName: json["categoryName"], + isSelected: false, + ); + + Map toJson() => { + "id": id == null ? null : id, + "description": description == null ? null : description, + "descriptionN": descriptionN == null ? null : descriptionN, + "serviceIconUrl": serviceIconUrl, + "serviceImageUrl": serviceImageUrl, + "serviceCategoryID": serviceCategoryId == null ? null : serviceCategoryId, + "categoryName": categoryName, + }; +} diff --git a/lib/models/response_models.dart b/lib/models/response_models.dart new file mode 100644 index 0000000..872893b --- /dev/null +++ b/lib/models/response_models.dart @@ -0,0 +1,34 @@ +/// +/// This example was taken from +/// https://flutter.dev/docs/development/data-and-backend/json +/// + +/// This allows the `User` class to access private members in +/// the generated file. The value for this is *.g.dart, where +/// the star denotes the source file name. + +/// An annotation for the code generator to know that this class needs the +/// JSON serialization logic to be generated. + +class BackendResponse { + BackendResponse({required this.id, required this.isOk, required this.result}); + + int id; + bool isOk; + dynamic result; + + /// A necessary factory constructor for creating a new User instance + /// from a map. Pass the map to the generated `_$UserFromJson()` constructor. + /// The constructor is named after the source class, in this case, User. + factory BackendResponse.fromJson(Map json) => + BackendResponse( + id: 1, + isOk: false, + result: null, + ); +// +// /// `toJson` is the convention for a class to declare support for serialization +// /// to JSON. The implementation simply calls the private, generated +// /// helper method `_$UserToJson`. +// Map toJson() => _$BackendResponseToJson(this); +} diff --git a/lib/models/surah_model.dart b/lib/models/surah_model.dart new file mode 100644 index 0000000..acc171a --- /dev/null +++ b/lib/models/surah_model.dart @@ -0,0 +1,74 @@ +class SurahModel { + int? totalItemsCount; + int? statusCode; + String? message; + List? data; + + SurahModel({this.totalItemsCount, this.statusCode, this.message, this.data}); + + SurahModel.fromJson(Map json) { + totalItemsCount = json['totalItemsCount']; + statusCode = json['statusCode']; + message = json['message']; + if (json['data'] != null) { + data = []; + json['data'].forEach((v) { + data?.add(SurahModelData.fromJson(v)); + }); + } + } + + Map toJson() { + final Map data = new Map(); + data['totalItemsCount'] = totalItemsCount; + data['statusCode'] = statusCode; + data['message'] = message; + if (this.data != null) { + data['data'] = this.data?.map((v) => v.toJson()).toList(); + } + return data; + } +} + +class SurahModelData { + int? id; + int? surahID; + String? nameAR; + String? nameEN; + int? numberOfAyahs; + String? englishNameTranslation; + int? revelationID; + String? revelationType; + int? startPageNo; + int? endPageNo; + + SurahModelData({this.id, this.surahID, this.nameAR, this.nameEN, this.numberOfAyahs, this.englishNameTranslation, this.revelationID, this.revelationType, this.startPageNo, this.endPageNo}); + + SurahModelData.fromJson(Map json) { + id = json['id']; + surahID = json['surahID']; + nameAR = json['nameAR']; + nameEN = json['nameEN']; + numberOfAyahs = json['numberOfAyahs']; + englishNameTranslation = json['englishNameTranslation']; + revelationID = json['revelation_ID']; + revelationType = json['revelationType']; + startPageNo = json['startPageNo']; + endPageNo = json['endPageNo']; + } + + Map toJson() { + final Map data = new Map(); + data['id'] = this.id; + data['surahID'] = this.surahID; + data['nameAR'] = this.nameAR; + data['nameEN'] = this.nameEN; + data['numberOfAyahs'] = this.numberOfAyahs; + data['englishNameTranslation'] = this.englishNameTranslation; + data['revelation_ID'] = this.revelationID; + data['revelationType'] = this.revelationType; + data['startPageNo'] = this.startPageNo; + data['endPageNo'] = this.endPageNo; + return data; + } +} diff --git a/lib/models/user/basic_otp.dart b/lib/models/user/basic_otp.dart new file mode 100644 index 0000000..bfa6d23 --- /dev/null +++ b/lib/models/user/basic_otp.dart @@ -0,0 +1,61 @@ +// To parse this JSON data, do +// +// final basicOtp = basicOtpFromJson(jsonString); + +import 'dart:convert'; + +BasicOtpRespModel basicOtpFromJson(String str) => BasicOtpRespModel.fromJson(json.decode(str)); + +String basicOtpToJson(BasicOtpRespModel data) => json.encode(data.toJson()); + +class BasicOtpRespModel { + BasicOtpRespModel({ + this.totalItemsCount, + this.data, + this.messageStatus, + this.message, + }); + + dynamic totalItemsCount; + Data? data; + int? messageStatus; + String? message; + + factory BasicOtpRespModel.fromJson(Map json) => BasicOtpRespModel( + totalItemsCount: json["totalItemsCount"], + data: json["data"] == null ? null : Data.fromJson(json["data"]), + messageStatus: json["messageStatus"] == null ? null : json["messageStatus"], + message: json["message"] == null ? null : json["message"], + ); + + Map toJson() => { + "totalItemsCount": totalItemsCount, + "data": data == null ? null : data!.toJson(), + "messageStatus": messageStatus == null ? null : messageStatus, + "message": message == null ? null : message, + }; +} + +class Data { + Data({ + this.userToken, + }); + + String? userToken; + + factory Data.fromJson(Map json) => Data( + userToken: checkValue(json), + ); + + static String checkValue(Map json) { + try { + return json["userToken"] == null ? null : json["userToken"]; + } catch (e) { + return json["token"] == null ? null : json["token"]; + } + } + + Map toJson() => { + "userToken": userToken == null ? null : userToken, + }; +} diff --git a/lib/models/user/change_email.dart b/lib/models/user/change_email.dart new file mode 100644 index 0000000..3e5d800 --- /dev/null +++ b/lib/models/user/change_email.dart @@ -0,0 +1,51 @@ + + +import 'dart:convert'; + +ChanEmailRespModel changeEmailFromJson(String str) => ChanEmailRespModel.fromJson(json.decode(str)); + +String changeEmailToJson(ChanEmailRespModel data) => json.encode(data.toJson()); + +class ChanEmailRespModel { + int? messageStatus; + Null? totalItemsCount; + Data? data; + String? message; + + ChanEmailRespModel( + {this.messageStatus, this.totalItemsCount, this.data, this.message}); + + ChanEmailRespModel.fromJson(Map json) { + messageStatus = json['messageStatus']; + totalItemsCount = json['totalItemsCount']; + data = json['data'] != null ? new Data.fromJson(json['data']) : null; + message = json['message']; + } + + Map toJson() { + final Map data = new Map(); + data['messageStatus'] = this.messageStatus; + data['totalItemsCount'] = this.totalItemsCount; + if (this.data != null) { + data['data'] = this.data!.toJson(); + } + data['message'] = this.message; + return data; + } +} + +class Data { + String? userToken; + + Data({this.userToken}); + + Data.fromJson(Map json) { + userToken = json['userToken']; + } + + Map toJson() { + final Map data = new Map(); + data['userToken'] = this.userToken; + return data; + } +} \ No newline at end of file diff --git a/lib/models/user/change_mobile.dart b/lib/models/user/change_mobile.dart new file mode 100644 index 0000000..4a3f7e0 --- /dev/null +++ b/lib/models/user/change_mobile.dart @@ -0,0 +1,51 @@ + + +import 'dart:convert'; + +ChangeMobileRespModel changeMobileFromJson(String str) => ChangeMobileRespModel.fromJson(json.decode(str)); + +String changeMobileToJson(ChangeMobileRespModel data) => json.encode(data.toJson()); + +class ChangeMobileRespModel { + int? messageStatus; + Null? totalItemsCount; + Data? data; + String? message; + + ChangeMobileRespModel( + {this.messageStatus, this.totalItemsCount, this.data, this.message}); + + ChangeMobileRespModel.fromJson(Map json) { + messageStatus = json['messageStatus']; + totalItemsCount = json['totalItemsCount']; + data = json['data'] != null ? new Data.fromJson(json['data']) : null; + message = json['message']; + } + + Map toJson() { + final Map data = new Map(); + data['messageStatus'] = this.messageStatus; + data['totalItemsCount'] = this.totalItemsCount; + if (this.data != null) { + data['data'] = this.data!.toJson(); + } + data['message'] = this.message; + return data; + } +} + +class Data { + String? userToken; + + Data({this.userToken}); + + Data.fromJson(Map json) { + userToken = json['userToken']; + } + + Map toJson() { + final Map data = new Map(); + data['userToken'] = this.userToken; + return data; + } +} \ No newline at end of file diff --git a/lib/models/user/change_password.dart b/lib/models/user/change_password.dart new file mode 100644 index 0000000..fc74d4b --- /dev/null +++ b/lib/models/user/change_password.dart @@ -0,0 +1,34 @@ + + + +import 'dart:convert'; + +ChangePassword changePasswordFromJson(String str) => ChangePassword.fromJson(json.decode(str)); + +String changePasswordToJson(ChangePassword data) => json.encode(data.toJson()); + +class ChangePassword { + int? messageStatus; + Null? totalItemsCount; + bool? data; + String? message; + + ChangePassword( + {this.messageStatus, this.totalItemsCount, this.data, this.message}); + + ChangePassword.fromJson(Map json) { + messageStatus = json['messageStatus']; + totalItemsCount = json['totalItemsCount']; + data = json['data']; + message = json['message']; + } + + Map toJson() { + final Map data = new Map(); + data['messageStatus'] = this.messageStatus; + data['totalItemsCount'] = this.totalItemsCount; + data['data'] = this.data; + data['message'] = this.message; + return data; + } +} \ No newline at end of file diff --git a/lib/models/user/cities.dart b/lib/models/user/cities.dart new file mode 100644 index 0000000..5c32405 --- /dev/null +++ b/lib/models/user/cities.dart @@ -0,0 +1,65 @@ +// To parse this JSON data, do +// +// final cities = citiesFromJson(jsonString); + +import 'dart:convert'; + +Cities citiesFromJson(String str) => Cities.fromJson(json.decode(str)); + +String citiesToJson(Cities data) => json.encode(data.toJson()); + +class Cities { + Cities({ + this.totalItemsCount, + this.data, + this.messageStatus, + this.message, + }); + + int? totalItemsCount; + List? data; + int? messageStatus; + String? message; + + factory Cities.fromJson(Map json) => Cities( + totalItemsCount: json["totalItemsCount"] == null ? null : json["totalItemsCount"], + data: json["data"] == null ? null : List.from(json["data"].map((x) => CityData.fromJson(x))), + messageStatus: json["messageStatus"] == null ? null : json["messageStatus"], + message: json["message"] == null ? null : json["message"], + ); + + Map toJson() => { + "totalItemsCount": totalItemsCount == null ? null : totalItemsCount, + "data": data == null ? null : List.from(data!.map((x) => x.toJson())), + "messageStatus": messageStatus == null ? null : messageStatus, + "message": message == null ? null : message, + }; +} + +class CityData { + CityData({ + this.id, + this.cityName, + this.cityNameN, + this.countryId, + }); + + int? id; + String? cityName; + String? cityNameN; + int? countryId; + + factory CityData.fromJson(Map json) => CityData( + id: json["id"] == null ? null : json["id"], + cityName: json["cityName"] == null ? null : json["cityName"], + cityNameN: json["cityNameN"] == null ? null : json["cityNameN"], + countryId: json["countryID"] == null ? null : json["countryID"], + ); + + Map toJson() => { + "id": id == null ? null : id, + "cityName": cityName == null ? null : cityName, + "cityNameN": cityNameN == null ? null : cityNameN, + "countryID": countryId == null ? null : countryId, + }; +} diff --git a/lib/models/user/confirm_email.dart b/lib/models/user/confirm_email.dart new file mode 100644 index 0000000..0292c8c --- /dev/null +++ b/lib/models/user/confirm_email.dart @@ -0,0 +1,51 @@ + + +import 'dart:convert'; + +ConfirmEmailRespModel confirmEmailFromJson(String str) => ConfirmEmailRespModel.fromJson(json.decode(str)); + +String confirmEmailToJson(ConfirmEmailRespModel data) => json.encode(data.toJson()); + +class ConfirmEmailRespModel { + int? messageStatus; + Null? totalItemsCount; + Data? data; + String? message; + + ConfirmEmailRespModel( + {this.messageStatus, this.totalItemsCount, this.data, this.message}); + + ConfirmEmailRespModel.fromJson(Map json) { + messageStatus = json['messageStatus']; + totalItemsCount = json['totalItemsCount']; + data = json['data'] != null ? new Data.fromJson(json['data']) : null; + message = json['message']; + } + + Map toJson() { + final Map data = new Map(); + data['messageStatus'] = this.messageStatus; + data['totalItemsCount'] = this.totalItemsCount; + if (this.data != null) { + data['data'] = this.data!.toJson(); + } + data['message'] = this.message; + return data; + } +} + +class Data { + String? userID; + + Data({this.userID}); + + Data.fromJson(Map json) { + userID = json['userID']; + } + + Map toJson() { + final Map data = new Map(); + data['userID'] = this.userID; + return data; + } +} \ No newline at end of file diff --git a/lib/models/user/confirm_mobile.dart b/lib/models/user/confirm_mobile.dart new file mode 100644 index 0000000..412e822 --- /dev/null +++ b/lib/models/user/confirm_mobile.dart @@ -0,0 +1,53 @@ + + + +import 'dart:convert'; + +ConfirmMobileRespModel confirmMobileFromJson(String str) => ConfirmMobileRespModel.fromJson(json.decode(str)); + +String confirmMobileToJson(ConfirmMobileRespModel data) => json.encode(data.toJson()); + + +class ConfirmMobileRespModel { + int? messageStatus; + Null? totalItemsCount; + Data? data; + String? message; + + ConfirmMobileRespModel( + {this.messageStatus, this.totalItemsCount, this.data, this.message}); + + ConfirmMobileRespModel.fromJson(Map json) { + messageStatus = json['messageStatus']; + totalItemsCount = json['totalItemsCount']; + data = json['data'] != null ? new Data.fromJson(json['data']) : null; + message = json['message']; + } + + Map toJson() { + final Map data = new Map(); + data['messageStatus'] = this.messageStatus; + data['totalItemsCount'] = this.totalItemsCount; + if (this.data != null) { + data['data'] = this.data!.toJson(); + } + data['message'] = this.message; + return data; + } +} + +class Data { + String? userID; + + Data({this.userID}); + + Data.fromJson(Map json) { + userID = json['userID']; + } + + Map toJson() { + final Map data = new Map(); + data['userID'] = this.userID; + return data; + } +} \ No newline at end of file diff --git a/lib/models/user/confirm_password.dart b/lib/models/user/confirm_password.dart new file mode 100644 index 0000000..53ab3ea --- /dev/null +++ b/lib/models/user/confirm_password.dart @@ -0,0 +1,30 @@ + +import 'dart:convert'; + +ConfirmPasswordRespModel confirmPasswordFromJson(String str) => ConfirmPasswordRespModel.fromJson(json.decode(str)); + +String confirmPasswordToJson(ConfirmPasswordRespModel data) => json.encode(data.toJson()); + +class ConfirmPasswordRespModel { + dynamic totalItemsCount; + int? messageStatus; + String? message; + + ConfirmPasswordRespModel( + {this.totalItemsCount, this.messageStatus, this.message}); + + ConfirmPasswordRespModel.fromJson(Map json) { + totalItemsCount = json['totalItemsCount']; + messageStatus = json['messageStatus']; + message = json['message']; + } + + Map toJson() { + final Map data = new Map(); + data['totalItemsCount'] = this.totalItemsCount; + data['messageStatus'] = this.messageStatus; + data['message'] = this.message; + return data; + } +} + diff --git a/lib/models/user/country.dart b/lib/models/user/country.dart new file mode 100644 index 0000000..f4036cf --- /dev/null +++ b/lib/models/user/country.dart @@ -0,0 +1,81 @@ +// To parse this JSON data, do +// +// final country = countryFromJson(jsonString); + +import 'dart:convert'; + +Country countryFromJson(String str) => Country.fromJson(json.decode(str)); + +String countryToJson(Country data) => json.encode(data.toJson()); + +class Country { + Country({ + this.totalItemsCount, + this.data, + this.messageStatus, + this.message, + }); + + int? totalItemsCount; + List? data; + int? messageStatus; + String? message; + + factory Country.fromJson(Map json) => Country( + totalItemsCount: json["totalItemsCount"] == null ? null : json["totalItemsCount"], + data: json["data"] == null ? null : List.from(json["data"].map((x) => CountryData.fromJson(x))), + messageStatus: json["messageStatus"] == null ? null : json["messageStatus"], + message: json["message"] == null ? null : json["message"], + ); + + Map toJson() => { + "totalItemsCount": totalItemsCount == null ? null : totalItemsCount, + "data": data == null ? null : List.from(data!.map((x) => x.toJson())), + "messageStatus": messageStatus == null ? null : messageStatus, + "message": message == null ? null : message, + }; +} + +class CountryData { + CountryData({ + this.id, + this.countryName, + this.countryNameN, + this.nationality, + this.nationalityN, + this.countryCode, + this.alpha2Code, + this.alpha3Code, + }); + + int? id; + String? countryName; + String? countryNameN; + String? nationality; + String? nationalityN; + String? countryCode; + String? alpha2Code; + String? alpha3Code; + + factory CountryData.fromJson(Map json) => CountryData( + id: json["id"] == null ? null : json["id"], + countryName: json["countryName"] == null ? null : json["countryName"], + countryNameN: json["countryNameN"] == null ? null : json["countryNameN"], + nationality: json["nationality"] == null ? null : json["nationality"], + nationalityN: json["nationalityN"] == null ? null : json["nationalityN"], + countryCode: json["countryCode"] == null ? null : json["countryCode"], + alpha2Code: json["alpha2Code"] == null ? null : json["alpha2Code"], + alpha3Code: json["alpha3Code"] == null ? null : json["alpha3Code"], + ); + + Map toJson() => { + "id": id == null ? null : id, + "countryName": countryName == null ? null : countryName, + "countryNameN": countryNameN == null ? null : countryNameN, + "nationality": nationality == null ? null : nationality, + "nationalityN": nationalityN == null ? null : nationalityN, + "countryCode": countryCode == null ? null : countryCode, + "alpha2Code": alpha2Code == null ? null : alpha2Code, + "alpha3Code": alpha3Code == null ? null : alpha3Code, + }; +} diff --git a/lib/models/user/email_verify.dart b/lib/models/user/email_verify.dart new file mode 100644 index 0000000..d39c963 --- /dev/null +++ b/lib/models/user/email_verify.dart @@ -0,0 +1,52 @@ + + +import 'dart:convert'; + +VerifyEmail verifyEmailFromJson(String str) => VerifyEmail.fromJson(json.decode(str)); + +String verifyEmailToJson(VerifyEmail data) => json.encode(data.toJson()); + + +class VerifyEmail { + Null? totalItemsCount; + Data? data; + int? messageStatus; + String? message; + + VerifyEmail( + {this.totalItemsCount, this.data, this.messageStatus, this.message}); + + VerifyEmail.fromJson(Map json) { + totalItemsCount = json['totalItemsCount']; + data = json['data'] != null ? new Data.fromJson(json['data']) : null; + messageStatus = json['messageStatus']; + message = json['message']; + } + + Map toJson() { + final Map data = new Map(); + data['totalItemsCount'] = this.totalItemsCount; + if (this.data != null) { + data['data'] = this.data!.toJson(); + } + data['messageStatus'] = this.messageStatus; + data['message'] = this.message; + return data; + } +} + +class Data { + String? userToken; + + Data({this.userToken}); + + Data.fromJson(Map json) { + userToken = json['userToken']; + } + + Map toJson() { + final Map data = new Map(); + data['userToken'] = this.userToken; + return data; + } +} \ No newline at end of file diff --git a/lib/models/user/email_verify_otp.dart b/lib/models/user/email_verify_otp.dart new file mode 100644 index 0000000..eea8503 --- /dev/null +++ b/lib/models/user/email_verify_otp.dart @@ -0,0 +1,26 @@ + + +import 'dart:convert'; + +VerifyEmailOTP verifyEmailOTPFromJson(String str) => VerifyEmailOTP.fromJson(json.decode(str)); + +String verifyEmailOTPToJson(VerifyEmailOTP data) => json.encode(data.toJson()); + +class VerifyEmailOTP { + bool? success; + Null? errors; + + VerifyEmailOTP({this.success, this.errors}); + + VerifyEmailOTP.fromJson(Map json) { + success = json['success']; + errors = json['errors']; + } + + Map toJson() { + final Map data = new Map(); + data['success'] = this.success; + data['errors'] = this.errors; + return data; + } +} \ No newline at end of file diff --git a/lib/models/user/forget_password_otp_compare.dart b/lib/models/user/forget_password_otp_compare.dart new file mode 100644 index 0000000..d234a79 --- /dev/null +++ b/lib/models/user/forget_password_otp_compare.dart @@ -0,0 +1,48 @@ +import 'dart:convert'; + +PasswordOTPCompareResModel otpCompareFromJson(String str) => PasswordOTPCompareResModel.fromJson(json.decode(str)); + +String otpCompareToJson(PasswordOTPCompareResModel data) => json.encode(data.toJson()); + +class PasswordOTPCompareResModel { + dynamic totalItemsCount; + Data? data; + int? messageStatus; + String? message; + + PasswordOTPCompareResModel({this.totalItemsCount, this.data, this.messageStatus, this.message}); + + PasswordOTPCompareResModel.fromJson(Map json) { + totalItemsCount = json['totalItemsCount']; + data = json['data'] != null ? new Data.fromJson(json['data']) : null; + messageStatus = json['messageStatus']; + message = json['message']; + } + + Map toJson() { + final Map data = new Map(); + data['totalItemsCount'] = this.totalItemsCount; + if (this.data != null) { + data['data'] = this.data!.toJson(); + } + data['messageStatus'] = this.messageStatus; + data['message'] = this.message; + return data; + } +} + +class Data { + String? userToken; + + Data({this.userToken}); + + Data.fromJson(Map json) { + userToken = json['userToken']; + } + + Map toJson() { + final Map data = new Map(); + data['userToken'] = this.userToken; + return data; + } +} diff --git a/lib/models/user/forget_password_otp_request.dart b/lib/models/user/forget_password_otp_request.dart new file mode 100644 index 0000000..2755978 --- /dev/null +++ b/lib/models/user/forget_password_otp_request.dart @@ -0,0 +1,50 @@ + +import 'dart:convert'; + +PasswordOTPRequestRespModel otpRequestFromJson(String str) => PasswordOTPRequestRespModel.fromJson(json.decode(str)); + +String otpRequestToJson(PasswordOTPRequestRespModel data) => json.encode(data.toJson()); + +class PasswordOTPRequestRespModel { + dynamic totalItemsCount; + Data? data; + int? messageStatus; + String? message; + + PasswordOTPRequestRespModel( + {this.totalItemsCount, this.data, this.messageStatus, this.message}); + + PasswordOTPRequestRespModel.fromJson(Map json) { + totalItemsCount = json['totalItemsCount']; + data = json['data'] != null ? new Data.fromJson(json['data']) : null; + messageStatus = json['messageStatus']; + message = json['message']; + } + + Map toJson() { + final Map data = new Map(); + data['totalItemsCount'] = this.totalItemsCount; + if (this.data != null) { + data['data'] = this.data!.toJson(); + } + data['messageStatus'] = this.messageStatus; + data['message'] = this.message; + return data; + } +} + +class Data { + String? userToken; + + Data({this.userToken}); + + Data.fromJson(Map json) { + userToken = json['userToken']; + } + + Map toJson() { + final Map data = new Map(); + data['userToken'] = this.userToken; + return data; + } +} \ No newline at end of file diff --git a/lib/models/user/image_response.dart b/lib/models/user/image_response.dart new file mode 100644 index 0000000..6ca0b41 --- /dev/null +++ b/lib/models/user/image_response.dart @@ -0,0 +1,37 @@ +// To parse this JSON data, do +// +// final imageResponse = imageResponseFromJson(jsonString); + +import 'dart:convert'; + +ImageResponse imageResponseFromJson(String str) => ImageResponse.fromJson(json.decode(str)); + +String imageResponseToJson(ImageResponse data) => json.encode(data.toJson()); + +class ImageResponse { + ImageResponse({ + this.totalItemsCount, + this.data, + this.messageStatus, + this.message, + }); + + dynamic? totalItemsCount; + String? data; + int? messageStatus; + String? message; + + factory ImageResponse.fromJson(Map json) => ImageResponse( + totalItemsCount: json["totalItemsCount"], + data: json["data"] == null ? null : json["data"], + messageStatus: json["messageStatus"] == null ? null : json["messageStatus"], + message: json["message"] == null ? null : json["message"], + ); + + Map toJson() => { + "totalItemsCount": totalItemsCount, + "data": data == null ? null : data, + "messageStatus": messageStatus == null ? null : messageStatus, + "message": message == null ? null : message, + }; +} diff --git a/lib/models/user/login_password.dart b/lib/models/user/login_password.dart new file mode 100644 index 0000000..d888811 --- /dev/null +++ b/lib/models/user/login_password.dart @@ -0,0 +1,53 @@ +// To parse this JSON data, do +// +// final loginPassword = loginPasswordFromJson(jsonString); + +import 'dart:convert'; + +LoginPasswordRespModel loginPasswordFromJson(String str) => LoginPasswordRespModel.fromJson(json.decode(str)); + +String loginPasswordToJson(LoginPasswordRespModel data) => json.encode(data.toJson()); + +class LoginPasswordRespModel { + LoginPasswordRespModel({ + this.totalItemsCount, + this.data, + this.messageStatus, + this.message, + }); + + dynamic totalItemsCount; + Data? data; + int? messageStatus; + String? message; + + factory LoginPasswordRespModel.fromJson(Map json) => LoginPasswordRespModel( + totalItemsCount: json["totalItemsCount"], + data: json["data"] == null ? null : Data.fromJson(json["data"]), + messageStatus: json["messageStatus"] == null ? null : json["messageStatus"], + message: json["message"] == null ? null : json["message"], + ); + + Map toJson() => { + "totalItemsCount": totalItemsCount, + "data": data == null ? null : data!.toJson(), + "messageStatus": messageStatus == null ? null : messageStatus, + "message": message == null ? null : message, + }; +} + +class Data { + Data({ + this.userToken, + }); + + String? userToken; + + factory Data.fromJson(Map json) => Data( + userToken: json["userToken"] == null ? null : json["userToken"], + ); + + Map toJson() => { + "userToken": userToken == null ? null : userToken, + }; +} diff --git a/lib/models/user/refresh_token.dart b/lib/models/user/refresh_token.dart new file mode 100644 index 0000000..7de1e59 --- /dev/null +++ b/lib/models/user/refresh_token.dart @@ -0,0 +1,65 @@ +// To parse this JSON data, do +// +// final refreshToken = refreshTokenFromJson(jsonString); + +import 'dart:convert'; + +RefreshToken refreshTokenFromJson(String str) => RefreshToken.fromJson(json.decode(str)); + +String refreshTokenToJson(RefreshToken data) => json.encode(data.toJson()); + +class RefreshToken { + RefreshToken({ + this.totalItemsCount, + this.data, + this.messageStatus, + this.message, + }); + + final dynamic? totalItemsCount; + final RefreshData? data; + final int? messageStatus; + final String? message; + + factory RefreshToken.fromJson(Map json) => RefreshToken( + totalItemsCount: json["totalItemsCount"], + data: json["data"] == null ? null : RefreshData.fromJson(json["data"]), + messageStatus: json["messageStatus"] == null ? null : json["messageStatus"], + message: json["message"] == null ? null : json["message"], + ); + + Map toJson() => { + "totalItemsCount": totalItemsCount, + "data": data == null ? null : data!.toJson(), + "messageStatus": messageStatus == null ? null : messageStatus, + "message": message == null ? null : message, + }; +} + +class RefreshData { + RefreshData({ + this.accessToken, + this.refreshToken, + this.expiryDate, + this.userInfo, + }); + + final String? accessToken; + final String? refreshToken; + final DateTime? expiryDate; + final dynamic? userInfo; + + factory RefreshData.fromJson(Map json) => RefreshData( + accessToken: json["accessToken"] == null ? null : json["accessToken"], + refreshToken: json["refreshToken"] == null ? null : json["refreshToken"], + expiryDate: json["expiryDate"] == null ? null : DateTime.parse(json["expiryDate"]), + userInfo: json["userInfo"], + ); + + Map toJson() => { + "accessToken": accessToken == null ? null : accessToken, + "refreshToken": refreshToken == null ? null : refreshToken, + "expiryDate": expiryDate == null ? null : expiryDate!.toIso8601String(), + "userInfo": userInfo, + }; +} diff --git a/lib/models/user/register_user.dart b/lib/models/user/register_user.dart new file mode 100644 index 0000000..5f5f79d --- /dev/null +++ b/lib/models/user/register_user.dart @@ -0,0 +1,129 @@ +// To parse this JSON data, do +// +// final registerUser = registerUserFromJson(jsonString); + +import 'dart:convert'; + +RegisterUserRespModel registerUserFromJson(String str) => RegisterUserRespModel.fromJson(json.decode(str)); + +String registerUserToJson(RegisterUserRespModel data) => json.encode(data.toJson()); + +class RegisterUserRespModel { + RegisterUserRespModel({ + this.messageStatus, + this.totalItemsCount, + this.data, + this.message, + }); + + final int? messageStatus; + final dynamic? totalItemsCount; + final Data? data; + final String? message; + + factory RegisterUserRespModel.fromJson(Map json) => RegisterUserRespModel( + messageStatus: json["messageStatus"] == null ? null : json["messageStatus"], + totalItemsCount: json["totalItemsCount"], + data: json["data"] == null ? null : Data.fromJson(json["data"]), + message: json["message"] == null ? null : json["message"], + ); + + Map toJson() => { + "messageStatus": messageStatus == null ? null : messageStatus, + "totalItemsCount": totalItemsCount, + "data": data == null ? null : data!.toJson(), + "message": message == null ? null : message, + }; +} + +class Data { + Data({ + this.id, + this.userId, + this.firstName, + this.lastName, + this.mobileNo, + this.email, + this.userImageUrl, + this.roleId, + this.roleName, + this.isEmailVerified, + this.serviceProviderBranch, + this.isVerified, + this.userRoles, + this.isCustomer, + this.isProviderDealership, + this.isProviderIndividual, + this.isDealershipUser, + this.providerId, + this.customerId, + this.dealershipId, + }); + + final int? id; + final String? userId; + final dynamic? firstName; + final dynamic? lastName; + final String? mobileNo; + final String? email; + final dynamic? userImageUrl; + final int? roleId; + final dynamic? roleName; + final bool? isEmailVerified; + final List? serviceProviderBranch; + final bool? isVerified; + final List? userRoles; + final bool? isCustomer; + final bool? isProviderDealership; + final bool? isProviderIndividual; + final bool? isDealershipUser; + final dynamic? providerId; + final dynamic? customerId; + final dynamic? dealershipId; + + factory Data.fromJson(Map json) => Data( + id: json["id"] == null ? null : json["id"], + userId: json["userID"] == null ? null : json["userID"], + firstName: json["firstName"], + lastName: json["lastName"], + mobileNo: json["mobileNo"] == null ? null : json["mobileNo"], + email: json["email"] == null ? null : json["email"], + userImageUrl: json["userImageUrl"], + roleId: json["roleID"] == null ? null : json["roleID"], + roleName: json["roleName"], + isEmailVerified: json["isEmailVerified"] == null ? null : json["isEmailVerified"], + serviceProviderBranch: json["serviceProviderBranch"] == null ? null : List.from(json["serviceProviderBranch"].map((x) => x)), + isVerified: json["isVerified"] == null ? null : json["isVerified"], + userRoles: json["userRoles"] == null ? null : List.from(json["userRoles"].map((x) => x)), + isCustomer: json["isCustomer"] == null ? null : json["isCustomer"], + isProviderDealership: json["isProviderDealership"] == null ? null : json["isProviderDealership"], + isProviderIndividual: json["isProviderIndividual"] == null ? null : json["isProviderIndividual"], + isDealershipUser: json["isDealershipUser"] == null ? null : json["isDealershipUser"], + providerId: json["providerID"], + customerId: json["customerID"], + dealershipId: json["dealershipID"], + ); + + Map toJson() => { + "id": id == null ? null : id, + "userID": userId == null ? null : userId, + "firstName": firstName, + "lastName": lastName, + "mobileNo": mobileNo == null ? null : mobileNo, + "email": email == null ? null : email, + "userImageUrl": userImageUrl, + "roleID": roleId == null ? null : roleId, + "roleName": roleName, + "isEmailVerified": isEmailVerified == null ? null : isEmailVerified, + "serviceProviderBranch": serviceProviderBranch == null ? null : List.from(serviceProviderBranch!.map((x) => x)), + "isVerified": isVerified == null ? null : isVerified, + "userRoles": userRoles == null ? null : List.from(userRoles!.map((x) => x)), + "isCustomer": isCustomer == null ? null : isCustomer, + "isProviderDealership": isProviderDealership == null ? null : isProviderDealership, + "isProviderIndividual": isProviderIndividual == null ? null : isProviderIndividual, + "isDealershipUser": isDealershipUser == null ? null : isDealershipUser, + "providerID": providerId, + "customerID": customerId, + "dealershipID": dealershipId, + }; +} diff --git a/lib/models/user/role.dart b/lib/models/user/role.dart new file mode 100644 index 0000000..2ea0054 --- /dev/null +++ b/lib/models/user/role.dart @@ -0,0 +1,65 @@ +// To parse this JSON data, do +// +// final role = roleFromJson(jsonString); + +import 'dart:convert'; + +Role roleFromJson(String str) => Role.fromJson(json.decode(str)); + +String roleToJson(Role data) => json.encode(data.toJson()); + +class Role { + Role({ + this.totalItemsCount, + this.data, + this.messageStatus, + this.message, + }); + + int? totalItemsCount; + List? data; + int? messageStatus; + String? message; + + factory Role.fromJson(Map json) => Role( + totalItemsCount: json["totalItemsCount"] == null ? null : json["totalItemsCount"], + data: json["data"] == null ? null : List.from(json["data"].map((x) => RoleData.fromJson(x))), + messageStatus: json["messageStatus"] == null ? null : json["messageStatus"], + message: json["message"] == null ? null : json["message"], + ); + + Map toJson() => { + "totalItemsCount": totalItemsCount == null ? null : totalItemsCount, + "data": data == null ? null : List.from(data!.map((x) => x.toJson())), + "messageStatus": messageStatus == null ? null : messageStatus, + "message": message == null ? null : message, + }; +} + +class RoleData { + RoleData({ + this.id, + this.roleName, + this.roleNameN, + this.isActive, + }); + + int? id; + String? roleName; + String? roleNameN; + bool? isActive; + + factory RoleData.fromJson(Map json) => RoleData( + id: json["id"] == null ? null : json["id"], + roleName: json["roleName"] == null ? null : json["roleName"], + roleNameN: json["roleNameN"] == null ? null : json["roleNameN"], + isActive: json["isActive"] == null ? null : json["isActive"], + ); + + Map toJson() => { + "id": id == null ? null : id, + "roleName": roleName == null ? null : roleName, + "roleNameN": roleNameN == null ? null : roleNameN, + "isActive": isActive == null ? null : isActive, + }; +} diff --git a/lib/models/user/user.dart b/lib/models/user/user.dart new file mode 100644 index 0000000..f1f0ee7 --- /dev/null +++ b/lib/models/user/user.dart @@ -0,0 +1,153 @@ +// To parse this JSON data, do +// +// final user = userFromJson(jsonString); + +import 'dart:convert'; + +User userFromJson(String str) => User.fromJson(json.decode(str)); + +String userToJson(User data) => json.encode(data.toJson()); + +class User { + User({ + this.totalItemsCount, + this.data, + this.messageStatus, + this.message, + }); + + dynamic totalItemsCount; + UserData? data; + int? messageStatus; + String? message; + + factory User.fromJson(Map json) => User( + totalItemsCount: json["totalItemsCount"], + data: json["data"] == null ? null : UserData.fromJson(json["data"]), + messageStatus: json["messageStatus"] == null ? null : json["messageStatus"], + message: json["message"] == null ? null : json["message"], + ); + + Map toJson() => { + "totalItemsCount": totalItemsCount, + "data": data == null ? null : data!.toJson(), + "messageStatus": messageStatus == null ? null : messageStatus, + "message": message == null ? null : message, + }; +} + +class UserData { + UserData({ + this.accessToken, + this.refreshToken, + this.expiryDate, + this.userInfo, + }); + + String? accessToken; + String? refreshToken; + DateTime? expiryDate; + UserInfo? userInfo; + + factory UserData.fromJson(Map json) => UserData( + accessToken: json["accessToken"] == null ? null : json["accessToken"], + refreshToken: json["refreshToken"] == null ? null : json["refreshToken"], + expiryDate: json["expiryDate"] == null ? null : DateTime.parse(json["expiryDate"]), + userInfo: json["userInfo"] == null ? null : UserInfo.fromJson(json["userInfo"]), + ); + + Map toJson() => { + "accessToken": accessToken == null ? null : accessToken, + "refreshToken": refreshToken == null ? null : refreshToken, + "expiryDate": expiryDate == null ? null : expiryDate!.toIso8601String(), + "userInfo": userInfo == null ? null : userInfo!.toJson(), + }; +} + +class UserInfo { + UserInfo({ + this.id, + this.userId, + this.firstName, + this.lastName, + this.mobileNo, + this.email, + this.userImageUrl, + this.roleId, + this.roleName, + this.isEmailVerified, + this.serviceProviderBranch, + this.isVerified, + this.userRoles, + this.isCustomer, + this.isProviderDealership, + this.isDealershipUser, + this.providerId, + this.customerId, + this.dealershipId, + }); + + int? id; + String? userId; + String? firstName; + String? lastName; + String? mobileNo; + String? email; + dynamic userImageUrl; + int? roleId; + String? roleName; + bool? isEmailVerified; + List? serviceProviderBranch; + bool? isVerified; + List? userRoles; + bool? isCustomer; + bool? isProviderDealership; + bool? isDealershipUser; + dynamic providerId; + int? customerId; + dynamic dealershipId; + + factory UserInfo.fromJson(Map json) => UserInfo( + id: json["id"] == null ? null : json["id"], + userId: json["userID"] == null ? null : json["userID"], + firstName: json["firstName"] == null ? null : json["firstName"], + lastName: json["lastName"] == null ? null : json["lastName"], + mobileNo: json["mobileNo"] == null ? null : json["mobileNo"], + email: json["email"] == null ? null : json["email"], + userImageUrl: json["userImageUrl"], + roleId: json["roleID"] == null ? null : json["roleID"], + roleName: json["roleName"] == null ? null : json["roleName"], + isEmailVerified: json["isEmailVerified"] == null ? null : json["isEmailVerified"], + serviceProviderBranch: json["serviceProviderBranch"] == null ? null : List.from(json["serviceProviderBranch"].map((x) => x)), + isVerified: json["isVerified"] == null ? null : json["isVerified"], + userRoles: json["userRoles"] == null ? null : List.from(json["userRoles"].map((x) => x)), + isCustomer: json["isCustomer"] == null ? null : json["isCustomer"], + isProviderDealership: json["isProviderDealership"] == null ? null : json["isProviderDealership"], + isDealershipUser: json["isDealershipUser"] == null ? null : json["isDealershipUser"], + providerId: json["providerID"], + customerId: json["customerID"] == null ? null : json["customerID"], + dealershipId: json["dealershipID"], + ); + + Map toJson() => { + "id": id == null ? null : id, + "userID": userId == null ? null : userId, + "firstName": firstName == null ? null : firstName, + "lastName": lastName == null ? null : lastName, + "mobileNo": mobileNo == null ? null : mobileNo, + "email": email == null ? null : email, + "userImageUrl": userImageUrl, + "roleID": roleId == null ? null : roleId, + "roleName": roleName == null ? null : roleName, + "isEmailVerified": isEmailVerified == null ? null : isEmailVerified, + "serviceProviderBranch": serviceProviderBranch == null ? null : List.from(serviceProviderBranch!.map((x) => x)), + "isVerified": isVerified == null ? null : isVerified, + "userRoles": userRoles == null ? null : List.from(userRoles!.map((x) => x)), + "isCustomer": isCustomer == null ? null : isCustomer, + "isProviderDealership": isProviderDealership == null ? null : isProviderDealership, + "isDealershipUser": isDealershipUser == null ? null : isDealershipUser, + "providerID": providerId, + "customerID": customerId == null ? null : customerId, + "dealershipID": dealershipId, + }; +} diff --git a/lib/models/user/verify_email.dart b/lib/models/user/verify_email.dart new file mode 100644 index 0000000..a097073 --- /dev/null +++ b/lib/models/user/verify_email.dart @@ -0,0 +1,53 @@ + + + +import 'dart:convert'; + +VerifyEmailRespModel verifyEmailFromJson(String str) => VerifyEmailRespModel.fromJson(json.decode(str)); + +String verifyEmailToJson(VerifyEmailRespModel data) => json.encode(data.toJson()); + + +class VerifyEmailRespModel { + Null? totalItemsCount; + Data? data; + int? messageStatus; + String? message; + + VerifyEmailRespModel( + {this.totalItemsCount, this.data, this.messageStatus, this.message}); + + VerifyEmailRespModel.fromJson(Map json) { + totalItemsCount = json['totalItemsCount']; + data = json['data'] != null ? new Data.fromJson(json['data']) : null; + messageStatus = json['messageStatus']; + message = json['message']; + } + + Map toJson() { + final Map data = new Map(); + data['totalItemsCount'] = this.totalItemsCount; + if (this.data != null) { + data['data'] = this.data!.toJson(); + } + data['messageStatus'] = this.messageStatus; + data['message'] = this.message; + return data; + } +} + +class Data { + String? userToken; + + Data({this.userToken}); + + Data.fromJson(Map json) { + userToken = json['userToken']; + } + + Map toJson() { + final Map data = new Map(); + data['userToken'] = this.userToken; + return data; + } +} \ No newline at end of file diff --git a/lib/models/user/verify_email_otp.dart b/lib/models/user/verify_email_otp.dart new file mode 100644 index 0000000..aa0827c --- /dev/null +++ b/lib/models/user/verify_email_otp.dart @@ -0,0 +1,27 @@ + + + +import 'dart:convert'; + +VerifyEmailOTP verifyEmailOTPFromJson(String str) => VerifyEmailOTP.fromJson(json.decode(str)); + +String verifyEmailOTPToJson(VerifyEmailOTP data) => json.encode(data.toJson()); + +class VerifyEmailOTP { + bool? success; + Null? errors; + + VerifyEmailOTP({this.success, this.errors}); + + VerifyEmailOTP.fromJson(Map json) { + success = json['success']; + errors = json['errors']; + } + + Map toJson() { + final Map data = new Map(); + data['success'] = this.success; + data['errors'] = this.errors; + return data; + } +} \ No newline at end of file diff --git a/lib/repositories/common_repo.dart b/lib/repositories/common_repo.dart new file mode 100644 index 0000000..8b13789 --- /dev/null +++ b/lib/repositories/common_repo.dart @@ -0,0 +1 @@ + diff --git a/lib/repositories/dashboard_repo.dart b/lib/repositories/dashboard_repo.dart new file mode 100644 index 0000000..e69de29 diff --git a/lib/repositories/user_repo.dart b/lib/repositories/user_repo.dart new file mode 100644 index 0000000..4bed7d6 --- /dev/null +++ b/lib/repositories/user_repo.dart @@ -0,0 +1,291 @@ +import 'dart:async'; +import 'dart:convert'; + +import 'package:flutter/cupertino.dart'; +import 'package:http/http.dart'; +import 'package:mc_common_app/api/api_client.dart'; +import 'package:mc_common_app/classes/app_state_cm.dart'; +import 'package:mc_common_app/classes/consts.dart'; +import 'package:mc_common_app/config/dependencies.dart'; +import 'package:mc_common_app/models/m_response.dart'; +import 'package:mc_common_app/models/user/basic_otp.dart'; +import 'package:mc_common_app/models/user/change_email.dart'; +import 'package:mc_common_app/models/user/change_mobile.dart'; +import 'package:mc_common_app/models/user/cities.dart'; +import 'package:mc_common_app/models/user/confirm_email.dart'; +import 'package:mc_common_app/models/user/confirm_mobile.dart'; +import 'package:mc_common_app/models/user/confirm_password.dart'; +import 'package:mc_common_app/models/user/country.dart'; +import 'package:mc_common_app/models/user/forget_password_otp_compare.dart'; +import 'package:mc_common_app/models/user/image_response.dart'; +import 'package:mc_common_app/models/user/login_password.dart'; +import 'package:mc_common_app/models/user/refresh_token.dart'; +import 'package:mc_common_app/models/user/register_user.dart'; +import 'package:mc_common_app/models/user/role.dart'; +import 'package:mc_common_app/models/user/user.dart'; +import 'package:mc_common_app/models/user/verify_email.dart'; +import 'package:mc_common_app/utils/shared_prefrence.dart'; + +abstract class UserRepo { + Future basicOtp(String phoneNo, {int otpType = 1, int roleId = 4, int countryId = 1}); + + Future basicVerify(String phoneNo, String otp, String userToken); + + Future basicComplete(String userId, String firstName, String lastName, String email, String password); + + Future loginV1(String phoneNo, String password); + + Future loginV2OTP(String userToken, String loginType); + + Future loginV2OTPVerify(String userToken, String otp); + + Future refreshTokenAPI(String token, String refreshToken); + + Future getAllCountries(); + + Future getAllCites(String countryId); + + Future getRoles(); + + Future forgetPasswordOTPRequest(String userName, int otpType); + + Future forgetPasswordOTPCompare(String userToken, String userOTP); + + Future forgetPassword(String userToken, String newPassword); + + Future changePassword(String currentPassword, String newPassword); + + Future changeMobileNoOTPRequest(countryID, String mobileNo, String password); + + Future changeMobileNo(String userToken, String userOTP); + + Future changeEmailOTPRequest(String email, String password); + + Future changeEmail(String userToken, String userOTP); + + Future emailVerify(String email, String userID); + + Future emailVerifyOTPVerify(String userToken, String userOTP); + + Future updateUserImage(String image); + + Future getUserImage(String image); + + Future updateUserToken(); +} + +class UserRepoImp implements UserRepo { + @override + Future basicOtp(String phoneNo, {int otpType = 1, int roleId = 4, int countryId = 1}) async { + var postParams = {"countryID": countryId, "userMobileNo": phoneNo, "otpType": otpType, "userRole": roleId}; + return await injector.get().postJsonForObject((json) => BasicOtpRespModel.fromJson(json), ApiConsts.BasicOTP, postParams); + } + + @override + Future basicVerify(String phoneNo, String otp, String userToken) async { + var postParams = { + "userMobileNo": phoneNo, + "userOTP": otp, + "userToken": userToken, + }; + return await injector.get().postJsonForObject((json) => RegisterUserRespModel.fromJson(json), ApiConsts.BasicVerify, postParams); + } + + @override + Future basicComplete(String userId, String firstName, String lastName, String email, String password) async { + Map postParams; + if (email.isEmpty) { + postParams = {"userID": userId, "firstName": firstName, "lastName": lastName, "companyName": "string", "isEmailVerified": true, "password": password}; + } else { + postParams = {"userID": userId, "firstName": firstName, "lastName": lastName, "email": email, "companyName": "string", "isEmailVerified": true, "password": password}; + } + + return await injector.get().postJsonForObject((json) => RegisterUserRespModel.fromJson(json), ApiConsts.BasicComplete, postParams); + } + + @override + Future loginV1(String phoneNo, String password) async { + var postParams = { + "mobileorEmail": phoneNo, + "password": password, + }; + return await injector.get().postJsonForResponse(ApiConsts.Login_V1, postParams); + //return await injector.get().postJsonForObject((json) => BasicOtp.fromJson(json), ApiConsts.Login_V1, postParams); + } + + @override + Future loginV2OTP(String userToken, String loginType) async { + var postParams = { + "userToken": userToken, + "loginType": loginType, + }; + + Response response = await injector.get().postJsonForResponse(ApiConsts.Login_V2_OTP, postParams); + LoginPasswordRespModel user = LoginPasswordRespModel.fromJson(jsonDecode(response.body)); + return user; + } + + @override + Future loginV2OTPVerify(String userToken, String otp) async { + var postParams = {"userToken": userToken, "userOTP": otp}; + return await injector.get().postJsonForResponse(ApiConsts.Login_V2_OTPVerify, postParams); + } + + @override + Future refreshTokenAPI(String token, String refreshToken) async { + var postParams = {"token": token, "refreshToken": refreshToken}; + // String t = AppStateCm().getUser.data!.accessToken ?? ""; + return await injector.get().postJsonForObject((json) => RefreshToken.fromJson(json), ApiConsts.RefreshToken, postParams); + } + + @override + Future getAllCountries() async { + return await injector.get().getJsonForObject((json) => Country.fromJson(json), ApiConsts.GetAllCountry); + } + + @override + Future getAllCites(String countryId) async { + var postParams = { + "CountryID": countryId, + }; + return await injector.get().getJsonForObject((json) => Cities.fromJson(json), ApiConsts.GetAllCities, queryParameters: postParams); + } + + @override + Future getRoles() async { + return await injector.get().getJsonForObject((json) => Role.fromJson(json), ApiConsts.GetProviderRoles); + } + + @override + Future forgetPasswordOTPRequest(String userName, int otpType) async { + var postParams = { + "userName": userName, + "otpType": 1, + }; + return await injector.get().postJsonForResponse(ApiConsts.ForgetPasswordOTPRequest, postParams); + //return await injector.get().postJsonForObject((json) => PasswordOTPRequest.fromJson(json), ApiConsts.ForgetPasswordOTPRequest, postParams); + } + + @override + Future forgetPasswordOTPCompare(String userToken, String userOTP) async { + var postParams = {"userToken": userToken, "userOTP": userOTP}; + Response response = await injector.get().postJsonForResponse(ApiConsts.ForgetPasswordOTPCompare, postParams); + + PasswordOTPCompareResModel otpCompare = PasswordOTPCompareResModel.fromJson(jsonDecode(response.body)); + return otpCompare; + } + + @override + Future forgetPassword(String userToken, String newPassword) async { + var postParams = { + "userToken": userToken, + "newPassword": newPassword, + }; + + Response response = await injector.get().postJsonForResponse(ApiConsts.ForgetPassword, postParams); + ConfirmPasswordRespModel data = ConfirmPasswordRespModel.fromJson(jsonDecode(response.body)); + + return data; + //return await injector.get().postJsonForObject((json) => ConfirmPassword.fromJson(json), ApiConsts.ForgetPassword, postParams); + } + + @override + Future changePassword(String currentPassword, String newPassword) async { + var postParams = { + "currentPassword": currentPassword, + "newPassword": newPassword, + }; + // return await injector.get().postJsonForResponse(ApiConsts.ChangePassword, postParams); + + String t = AppStateCm().getUser.data!.accessToken ?? ""; + debugPrint("token " + t); + return await injector.get().postJsonForObject((json) => MResponse.fromJson(json), ApiConsts.ChangePassword, postParams, token: t); + } + + @override + Future changeMobileNoOTPRequest(countryID, String mobileNo, String password) async { + var postParams = {"countryID": 1, "mobileNo": mobileNo, "password": password}; + String t = AppStateCm().getUser.data!.accessToken ?? ""; + return await injector.get().postJsonForObject((json) => ChangeMobileRespModel.fromJson(json), ApiConsts.ChangeMobileNoOTPRequest, postParams, token: t); + } + + @override + Future changeMobileNo(String userToken, String userOTP) async { + var postParams = { + "userToken": userToken, + "userOTP": userOTP, + }; + String t = AppStateCm().getUser.data!.accessToken ?? ""; + return await injector.get().postJsonForObject((json) => ConfirmMobileRespModel.fromJson(json), ApiConsts.ChangeMobileNo, postParams, token: t); + } + + @override + Future changeEmailOTPRequest(String email, String password) async { + var postParams = {"email": email, "password": password}; + String t = AppStateCm().getUser.data!.accessToken ?? ""; + return await injector.get().postJsonForObject((json) => ChanEmailRespModel.fromJson(json), ApiConsts.ChangeEmailOTPRequest, postParams, token: t); + } + + @override + Future changeEmail(String userToken, String userOTP) async { + var postParams = {"userToken": userToken, "userOTP": userOTP}; + String t = AppStateCm().getUser.data!.accessToken ?? ""; + return await injector.get().postJsonForObject((json) => ConfirmEmailRespModel.fromJson(json), ApiConsts.ChangeEmail, postParams, token: t); + } + + @override + Future emailVerify(String email, String userID) async { + var postParams = { + // "email": email, + // "userID": userID, + "email": AppStateCm().getUser.data!.userInfo!.email ?? "", + "userID": AppStateCm().getUser.data!.userInfo!.userId ?? "", + }; + + String t = AppStateCm().getUser.data!.accessToken ?? ""; + return await injector.get().postJsonForObject((json) => VerifyEmailRespModel.fromJson(json), ApiConsts.EmailVerify, postParams, token: t); + } + + @override + Future emailVerifyOTPVerify(String userToken, String userOTP) async { + var postParams = {"userToken": userToken, "userOTP": userOTP}; + + String t = AppStateCm().getUser.data!.accessToken ?? ""; + return await injector.get().postJsonForObject((json) => MResponse.fromJson(json), ApiConsts.EmailVerifyOTPVerify, postParams, token: t); + } + + @override + Future updateUserImage(String image) async { + var postParams = {"userID": AppStateCm().getUser.data!.userInfo!.userId, "userImage": image}; + // return await injector.get().postJsonForResponse(ApiConsts.ChangePassword, postParams); + + String t = AppStateCm().getUser.data!.accessToken ?? ""; + debugPrint("token " + t); + return await injector.get().postJsonForObject((json) => ImageResponse.fromJson(json), ApiConsts.UpdateUserImage, postParams, token: t); + } + + @override + Future getUserImage(String image) async { + var postParams = {}; + // return await injector.get().postJsonForResponse(ApiConsts.ChangePassword, postParams); + + String t = AppStateCm().getUser.data!.accessToken ?? ""; + debugPrint("token " + t); + return await injector.get().postJsonForObject((json) => ImageResponse.fromJson(json), ApiConsts.UpdateUserImage, postParams, token: t); + } + + @override + Future updateUserToken() async { + String token = await SharedPrefManager.getUserToken(); + String refreshToken = await SharedPrefManager.getRefreshToken(); + RefreshToken refresh = await refreshTokenAPI(token, refreshToken); + SharedPrefManager.setUserToken(refresh.data!.accessToken ?? ""); + SharedPrefManager.setRefreshToken(refresh.data!.refreshToken ?? ""); + String mdata = await SharedPrefManager.getData(); + UserInfo info = UserInfo.fromJson(jsonDecode(mdata)); + User user = User(); + user.data = UserData(accessToken: refresh.data!.accessToken ?? "", refreshToken: refresh.data!.refreshToken ?? "", userInfo: info); + AppStateCm().setUser = user; + return refresh.data!.accessToken ?? ""; + } +} diff --git a/lib/services/services.dart b/lib/services/services.dart new file mode 100644 index 0000000..8dd371f --- /dev/null +++ b/lib/services/services.dart @@ -0,0 +1,19 @@ +import 'dart:io'; + +import 'package:image_picker/image_picker.dart'; + +abstract class CommonServices { + Future pickImageFromPhone(int sourceFlag); +} + +class CommonServicesImp implements CommonServices { + @override + Future pickImageFromPhone(int sourceFlag) async { + final picker = ImagePicker(); + final pickedImage = await picker.pickImage( + source: sourceFlag == 0 ? ImageSource.camera : ImageSource.gallery, + ); + final pickedImageFile = File(pickedImage!.path); + return pickedImageFile; + } +} \ No newline at end of file diff --git a/lib/theme/app_theme.dart b/lib/theme/app_theme.dart new file mode 100644 index 0000000..8d0252d --- /dev/null +++ b/lib/theme/app_theme.dart @@ -0,0 +1,27 @@ +import 'package:flutter/material.dart'; + +import 'colors.dart'; + +class AppTheme { + static getTheme(isArabic) => ThemeData( + // This is the theme of your application. + // + // Try running your application with "flutter run". You'll see the + // application has a blue toolbar. Then, without quitting the app, try + // changing the primarySwatch below to Colors.green and then invoke + // "hot reload" (press "r" in the console where you ran "flutter run", + // or simply save your changes to "hot reload" in a Flutter IDE). + // Notice that the counter didn't reset back to zero; the application + // is not restarted. + primaryColor: primaryColor, + primaryTextTheme: const TextTheme( + titleLarge: TextStyle(color: Colors.white), + ), colorScheme: ColorScheme.fromSwatch(primarySwatch: Colors.orange).copyWith(background: Colors.white), + ); +} + +extension ExtendedRevoCheckTheme on TextTheme { + //add custom styles and colors here + //taken from https://medium.com/@crizantlai/flutter-how-to-extend-themedata-b5b987a95bb5 + TextStyle get price => const TextStyle(color: Colors.redAccent); +} diff --git a/lib/theme/colors.dart b/lib/theme/colors.dart new file mode 100644 index 0000000..d65575d --- /dev/null +++ b/lib/theme/colors.dart @@ -0,0 +1,73 @@ +import 'package:flutter/material.dart'; + +class MyColors { + static const Color darkPrimaryColor = Color(0xffF47F20); + static const Color primaryColor = Color(0xffF69521); + static const Color accentColor = Colors.blue; + static const Color lightTextColor = Color(0xff969696); + static const Color textColor = Color(0xff777777); + static const Color textFieldColor = Color(0xffF3F5F7); + static const Color darkIconColor = Color(0xff28323A); + static const Color darkTextColor = Color(0xff2B353E); + static const Color normalTextColor = Color(0xff5A5A5A); + static const Color gradiantStartColor = Color(0xff33c0a5); + static const Color gradiantEndColor = Color(0xff259db7); + static const Color textMixColor = Color(0xff2BB8A6); + static const Color backgroundColor = Color(0xffF8F8F8); + static const Color grey57Color = Color(0xff575757); + static const Color grey77Color = Color(0xff777777); + static const Color grey70Color = Color(0xff707070); + static const Color greyACColor = Color(0xffACACAC); + static const Color grey98Color = Color(0xff989898); + static const Color lightGreyEFColor = Color(0xffEFEFEF); + static const Color lightGreyEDColor = Color(0xffEDEDED); + static const Color lightGreyEAColor = Color(0xffEAEAEA); + static const Color darkWhiteColor = Color(0xffE0E0E0); + static const Color redColor = Color(0xffD02127); + static const Color yellowColor = Color(0xffF4E31C); + static const Color backgroundBlackColor = Color(0xff202529); + static const Color black = Color(0xff000000); + static const Color white = Color(0xffffffff); + static const Color green = Color(0xffffffff); + static const Color borderColor = Color(0xffE8E8E8); + + static Decoration gradient = BoxDecoration( + gradient: const LinearGradient(colors: [ + darkPrimaryColor, + primaryColor, + ]), + boxShadow: [ + BoxShadow( + color: primaryColor.withOpacity(0.5), + blurRadius: 20.0, + spreadRadius: 1.0, + ) + ], + ); + + static Decoration gradientButton = BoxDecoration( + gradient: const LinearGradient(colors: [ + darkPrimaryColor, + primaryColor, + ]), + borderRadius: BorderRadius.circular(6), + boxShadow: [ + BoxShadow( + color: primaryColor.withOpacity(0.2), + blurRadius: 4.0, + spreadRadius: 0.5, + ) + ], + ); +} + +const Color primaryColor = Colors.white; +const Color accentColor = Colors.blue; +const Color appBackgroundColor = Colors.white; +Color? accentColorDark = Colors.green[800]; +const Color borderColor = Colors.blueGrey; +Color? borderLightColor = Colors.blueGrey[50]; +const Color iconColor = Colors.blueGrey; +Color? headingColor = Colors.blueGrey[800]; +Color? txtColor = Colors.blueGrey[500]; + diff --git a/lib/utils/dialogs.dart b/lib/utils/dialogs.dart new file mode 100644 index 0000000..c0fabd8 --- /dev/null +++ b/lib/utils/dialogs.dart @@ -0,0 +1,35 @@ +import 'package:flutter/material.dart'; + +import 'permission_handler.dart'; + +Future showConfirmDialogs( + context, msg, positiveText, negativeText) async { + return showDialog( + context: context, + barrierDismissible: false, + builder: (context) { + return AlertDialog( + backgroundColor: Colors.white, + title: Text(msg, style: TextStyle(fontSize: 16)), + actions: [ + TextButton( + child: Text( + negativeText, + ), + onPressed: () { + Navigator.of(context).pop(ConfirmAction.CANCEL); + }, + ), + TextButton( + child: Text( + positiveText, + ), + onPressed: () { + Navigator.of(context).pop(ConfirmAction.ACCEPT); + }, + ) + ], + ); + }, + ); +} diff --git a/lib/utils/enums.dart b/lib/utils/enums.dart new file mode 100644 index 0000000..cf27602 --- /dev/null +++ b/lib/utils/enums.dart @@ -0,0 +1,29 @@ +// enum APPSTATUS { +// loading, +// unAuthenticated, +// authenticated, +// unverified, +// } + +enum AuthMethodTypes { + sms, + whatsApp, + fingerPrint, + faceID, + moreOptions, +} + +enum ViewState { + hide, + idle, + busy, + error, + busyLocal, + errorLocal, +} + +enum LoginType { + FROM_LOGIN, + SILENT_LOGIN, + SILENT_WITH_OTP, +} diff --git a/lib/utils/navigator.dart b/lib/utils/navigator.dart new file mode 100644 index 0000000..ef3900c --- /dev/null +++ b/lib/utils/navigator.dart @@ -0,0 +1,14 @@ +import 'package:flutter/material.dart'; + +navigateWithName(BuildContext context, String routeName, {Object? arguments}) { + Navigator.pushNamed(context, routeName, arguments: arguments); +} + + +navigateReplaceWithName(BuildContext context, String routeName, {Object? arguments}) { + Navigator.pushReplacementNamed(context, routeName, arguments: arguments); +} + +pop(BuildContext context) { + Navigator.of(context).pop(); +} diff --git a/lib/utils/permission_handler.dart b/lib/utils/permission_handler.dart new file mode 100644 index 0000000..3e3877e --- /dev/null +++ b/lib/utils/permission_handler.dart @@ -0,0 +1,36 @@ +import 'package:permission_handler/permission_handler.dart'; + +import 'dialogs.dart'; + +enum ConfirmAction { CANCEL, ACCEPT } + +Future requestPermissionGranted( + context, Permission requestPermissions) async { + var result = await requestPermissions.request(); + + switch (result) { + case PermissionStatus.granted: + // Application has been given permission to use the feature. + return true; + case PermissionStatus.denied: + // Application has been denied permission to use the feature. + return false; + case PermissionStatus.permanentlyDenied: + ConfirmAction? res = await showConfirmDialogs( + context, + 'You was denied Permission. You have give manual permission from app setting. ', + 'Open App Setting', + 'Cancel'); + if (res == ConfirmAction.ACCEPT) { + return false; + } else if (res == ConfirmAction.CANCEL) { + return false; + } + return false; + case PermissionStatus.restricted: + // iOS has restricted access to a specific feature. + return false; + default: + return false; + } +} diff --git a/lib/utils/shared_prefrence.dart b/lib/utils/shared_prefrence.dart new file mode 100644 index 0000000..f629755 --- /dev/null +++ b/lib/utils/shared_prefrence.dart @@ -0,0 +1,74 @@ +import 'dart:async'; + +import 'package:shared_preferences/shared_preferences.dart'; + +class SharedPrefManager { + static String USER_ID = "user.id"; + static String USER_TOKEN = "user.token"; + static String USER_NAME = "user.name"; + static String PASSWORD = "user.password"; + static String REFRESH_TOKEN = "user.refresh.token"; + static String DATA = "data"; + + static final Future _prefs = SharedPreferences.getInstance(); + + static setUserId(String cookie) async { + final prefs = await SharedPreferences.getInstance(); + prefs.setString(USER_ID, cookie) ; + } + + static Future getUserId() async { + SharedPreferences prefs = await _prefs; + return prefs.getString(USER_ID) ?? ""; + } + + static setUserToken(String cookie) async { + final prefs = await SharedPreferences.getInstance(); + prefs.setString(USER_TOKEN, cookie) ; + } + + static Future getUserToken() async { + SharedPreferences prefs = await _prefs; + return prefs.getString(USER_TOKEN) ?? ""; + } + + static setPhoneOrEmail(String cookie) async { + final prefs = await SharedPreferences.getInstance(); + prefs.setString(USER_NAME, cookie) ; + } + + static Future getPhoneOrEmail() async { + SharedPreferences prefs = await _prefs; + return prefs.getString(USER_NAME) ?? ""; + } + + static setUserPassword(String cookie) async { + final prefs = await SharedPreferences.getInstance(); + prefs.setString(PASSWORD, cookie) ; + } + + static Future getUserPassword() async { + SharedPreferences prefs = await _prefs; + return prefs.getString(PASSWORD) ?? ""; + } + + static setRefreshToken(String cookie) async { + final prefs = await SharedPreferences.getInstance(); + prefs.setString(REFRESH_TOKEN, cookie) ; + } + + static Future getRefreshToken() async { + SharedPreferences prefs = await _prefs; + return prefs.getString(REFRESH_TOKEN) ?? ""; + } + + static setData(String cookie) async { + final prefs = await SharedPreferences.getInstance(); + prefs.setString(DATA, cookie); + } + + static Future getData() async { + SharedPreferences prefs = await _prefs; + return prefs.getString(DATA) ?? ""; + } +} diff --git a/lib/utils/utils.dart b/lib/utils/utils.dart new file mode 100644 index 0000000..2438d79 --- /dev/null +++ b/lib/utils/utils.dart @@ -0,0 +1,308 @@ +import 'dart:convert'; +import 'dart:io'; +import 'dart:typed_data'; + + +import 'package:flutter/material.dart'; + + +import 'package:fluttertoast/fluttertoast.dart'; +import 'package:mc_common_app/exceptions/api_exception.dart'; +import 'package:mc_common_app/theme/colors.dart'; +import 'package:mc_common_app/widgets/loading_dialog.dart'; + +class Utils { + static bool _isLoadingVisible = false; + + static bool get isLoading => _isLoadingVisible; + + static void showToast(String message) { + Fluttertoast.showToast( + msg: message, toastLength: Toast.LENGTH_SHORT, gravity: ToastGravity.BOTTOM, timeInSecForIosWeb: 2, backgroundColor: Colors.black54, textColor: Colors.white, fontSize: 16.0); + } + + static dynamic getNotNullValue(List list, int index) { + try { + return list[index]; + } catch (ex) { + return null; + } + } + + static int stringToHex(String colorCode) { + try { + return int.parse(colorCode.replaceAll("#", "0xff")); + } catch (ex) { + return (0xff000000); + } + } + + static void showLoading(BuildContext context) { + WidgetsBinding.instance.addPostFrameCallback((_) { + _isLoadingVisible = true; + showDialog( + context: context, + barrierColor: Colors.black.withOpacity(0.5), + builder: (BuildContext context) => LoadingDialog(), + ).then((value) { + _isLoadingVisible = false; + }); + }); + } + + static void hideLoading(BuildContext context) { + if (_isLoadingVisible) { + _isLoadingVisible = false; + Navigator.of(context).pop(); + } + _isLoadingVisible = false; + } + + static void handleException(dynamic exception, Function(String)? onErrorMessage) { + String errorMessage; + if (exception is APIException) { + if (exception.message == APIException.UNAUTHORIZED) { + return; + } else { + errorMessage = exception.error?.errorMessage ?? exception.message; + } + } else { + errorMessage = APIException.UNKNOWN; + } + if (onErrorMessage != null) { + onErrorMessage(errorMessage); + } else { + showToast(errorMessage); + } + } + + static Color getColorFromHex(String hexColor) { + hexColor = hexColor.toUpperCase().replaceAll('#', ''); + + if (hexColor.length == 6) { + hexColor = 'FF' + hexColor; + } + + return Color(int.parse(hexColor, radix: 16)); + } + + static Widget spacerVertical(double v) { + return SizedBox( + height: v, + width: double.infinity, + ); + } + + static String convertFileToBase64(File file) { + List imageBytes = file.readAsBytesSync(); + return base64Encode(imageBytes); + } + + static Future delay(int millis) async { + return await Future.delayed(Duration(milliseconds: millis)); + } + + static inkWellCorner({double? r}) { + return RoundedRectangleBorder( + borderRadius: BorderRadius.circular(r ?? 4), + ); + } + + static Widget spacerHorizontal(double v) { + return SizedBox( + height: v, + width: v, + ); + } + + static Widget mDivider(Color color, {double? h}) { + return Container( + width: double.infinity, + height: h ?? 1, + color: color, + ); + } + + static Widget mDivider3({double? h}) { + return Container( + width: double.infinity, + height: h ?? 1, + color: borderLightColor!.withOpacity(0.7), + ); + } + + static Widget mDivider2(Color color, double w) { + return Container( + width: w, + height: 1, + color: color, + ); + } + + static InputDecoration txtField(String label) { + return InputDecoration( + border: InputBorder.none, + focusedBorder: InputBorder.none, + enabledBorder: InputBorder.none, + errorBorder: InputBorder.none, + hintText: label, + hintStyle: const TextStyle(color: Colors.grey), + disabledBorder: InputBorder.none, + isDense: false, + contentPadding: const EdgeInsets.only(left: 15, right: 15), + ); + } + + static Widget mFlex(int f) { + return Flexible( + flex: f, + child: const SizedBox( + width: double.infinity, + height: double.infinity, + ), + ); + } + + static Widget mExp(int f) { + return Expanded( + flex: f, + child: Container( + width: double.infinity, + ), + ); + } + + static spacer() { + return const SizedBox( + height: 8, + ); + } + + static cardRadius(double radius) { + return RoundedRectangleBorder( + side: const BorderSide(color: Colors.transparent, width: 1), + borderRadius: BorderRadius.circular(radius), + ); + } + + static cardRadiusWithoutBorder(double radius) { + return RoundedRectangleBorder( + side: const BorderSide(color: Colors.transparent, width: 1), + borderRadius: BorderRadius.circular(radius), + ); + } + + static Image imageFromBase64String(String base64String) { + return Image.memory(base64Decode(base64String)); + } + + static Uint8List dataFromBase64String(String base64String) { + return base64Decode(base64String); + } + + static String base64String(Uint8List data) { + return base64Encode(data); + } + + static Widget overLayWidget({double? width, double? height, List? color}) { + return Container( + width: width ?? double.infinity, + height: height ?? 60, + decoration: BoxDecoration( + gradient: LinearGradient( + colors: color ?? + [ + Colors.black.withOpacity(0.2), + Colors.black.withOpacity(0.1), + Colors.black.withOpacity(0.004), + ], + begin: Alignment.topCenter, + end: Alignment.bottomCenter, + tileMode: TileMode.clamp, + ), + ), + ); + } + + static Decoration containerRadius(Color color, double r) { + return BoxDecoration( + color: color, + borderRadius: BorderRadius.all(Radius.circular(r)), + ); + } + + static Decoration containerRadiusTop({Color? color, double? r}) { + return BoxDecoration( + color: color ?? Colors.white, + borderRadius: BorderRadius.only(topRight: Radius.circular(r ?? 12), topLeft: Radius.circular(r ?? 12)), + ); + } + + static Decoration containerRadiusBorder(Color color, double r) { + return BoxDecoration( + color: Colors.transparent, + border: Border.all(color: color, width: 1), + borderRadius: BorderRadius.all(Radius.circular(r)), + ); + } + + static Decoration containerRadiusBottom(Color color, double r) { + return BoxDecoration( + color: color, + borderRadius: BorderRadius.only(bottomLeft: Radius.circular(r), bottomRight: Radius.circular(r)), + ); + } + + static ShapeBorder cardRadiusTop(double radius) { + return RoundedRectangleBorder( + side: const BorderSide(color: Colors.transparent, width: 0), + borderRadius: BorderRadius.only(topLeft: Radius.circular(radius), topRight: Radius.circular(radius)), + ); + } + + static Decoration containerColorRadiusBorderWidth(Color background, double radius, Color color, double w) { + return BoxDecoration( + color: background, + border: Border.all( + width: w, // + color: color // <--- border width here + ), + borderRadius: BorderRadius.circular(radius), + ); + } + + static ShapeBorder cardRadiusTop2(double radius) { + return RoundedRectangleBorder( + borderRadius: BorderRadius.only(topLeft: Radius.circular(radius), topRight: Radius.circular(radius)), + ); + } + + static ShapeBorder cardRadiusBottom(double radius) { + return RoundedRectangleBorder( + borderRadius: BorderRadius.only(bottomLeft: Radius.circular(radius), bottomRight: Radius.circular(radius)), + ); + } + + static Decoration containerColorRadiusBorder(Color background, double radius, Color color) { + return BoxDecoration( + color: background, + border: Border.all( + width: 1, // + color: color // <--- border width here + ), + borderRadius: BorderRadius.circular(radius), + ); + } + + static bool passwordValidateStructure(String value) { + String pattern = r'^(?=.*?[A-Z])(?=.*?[a-z])(?=.*?[0-9])(?=.*?[!@#\$&*~]).{6,}$'; + RegExp regExp = RegExp(pattern); + return regExp.hasMatch(value); + } + + static bool isEmailValid(String email) { + String p = 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,}))$'; + RegExp regExp = RegExp(p); + return regExp.hasMatch(email); + } +} diff --git a/lib/view_models/base_view_model.dart b/lib/view_models/base_view_model.dart new file mode 100644 index 0000000..90d2f96 --- /dev/null +++ b/lib/view_models/base_view_model.dart @@ -0,0 +1,22 @@ + +import 'package:flutter/cupertino.dart'; + +import '../utils/enums.dart'; + +class BaseVM extends ChangeNotifier { + ViewState _state = ViewState.idle; + bool isInternetConnection = true; + + ViewState get state => _state; + + String error = ""; + + void setOnlyState(ViewState viewState) { + _state = viewState; + } + + void setState(ViewState viewState) { + _state = viewState; + notifyListeners(); + } +} diff --git a/lib/view_models/dashboard_view_model.dart b/lib/view_models/dashboard_view_model.dart new file mode 100644 index 0000000..af73312 --- /dev/null +++ b/lib/view_models/dashboard_view_model.dart @@ -0,0 +1,48 @@ +import 'dart:io'; + +import 'package:easy_localization/easy_localization.dart'; +import 'package:flutter/cupertino.dart'; +import 'package:mc_common_app/generated/locale_keys.g.dart'; +import 'package:mc_common_app/models/user/image_response.dart'; +import 'package:mc_common_app/repositories/user_repo.dart'; +import 'package:mc_common_app/services/services.dart'; +import 'package:mc_common_app/utils/utils.dart'; +import 'package:mc_common_app/view_models/base_view_model.dart'; + +class DashboardVM extends BaseVM { + final CommonServices commonServices; + final UserRepo userRepo; + + DashboardVM({required this.commonServices, required this.userRepo}); + + String pickedImage = ""; + + void pickImageFromPhone(BuildContext context, int sourceFlag) async { + final File? pickedImageFile = await commonServices.pickImageFromPhone(sourceFlag); + if (pickedImageFile == null) { + return; + } + int sizeInBytes = pickedImageFile.lengthSync(); + if (sizeInBytes > 1000) { + Utils.showToast(LocaleKeys.fileLarger.tr()); + return; + } else { + String image64 = Utils.convertFileToBase64(pickedImageFile); + + Utils.showLoading(context); + ImageResponse response = await userRepo.updateUserImage(image64); + Utils.hideLoading(context); + Navigator.pop(context); + if (response.messageStatus == 1) { + Utils.showToast(LocaleKeys.imageUploaded.tr()); + // AppStateCm().getUser.data!.userInfo!.userImageUrl = response.data; + } else { + Utils.showToast(response.message ?? ""); + } + } + } + + Future updateUserImage(String image) async { + return await userRepo.updateUserImage(image); + } +} diff --git a/lib/view_models/user_view_model.dart b/lib/view_models/user_view_model.dart new file mode 100644 index 0000000..81eb08f --- /dev/null +++ b/lib/view_models/user_view_model.dart @@ -0,0 +1,478 @@ +import 'dart:convert'; + + +import 'package:easy_localization/easy_localization.dart'; +import 'package:flutter/cupertino.dart'; + +import 'package:http/http.dart'; +import 'package:mc_common_app/classes/app_state_cm.dart'; +import 'package:mc_common_app/classes/consts.dart'; +import 'package:mc_common_app/config/routes.dart'; +import 'package:mc_common_app/generated/locale_keys.g.dart'; +import 'package:mc_common_app/models/m_response.dart'; +import 'package:mc_common_app/models/user/basic_otp.dart'; +import 'package:mc_common_app/models/user/change_email.dart'; +import 'package:mc_common_app/models/user/change_mobile.dart'; +import 'package:mc_common_app/models/user/confirm_email.dart'; +import 'package:mc_common_app/models/user/confirm_mobile.dart'; +import 'package:mc_common_app/models/user/confirm_password.dart'; +import 'package:mc_common_app/models/user/country.dart'; +import 'package:mc_common_app/models/user/forget_password_otp_compare.dart'; +import 'package:mc_common_app/models/user/forget_password_otp_request.dart'; +import 'package:mc_common_app/models/user/login_password.dart'; +import 'package:mc_common_app/models/user/register_user.dart'; +import 'package:mc_common_app/models/user/user.dart'; +import 'package:mc_common_app/models/user/verify_email.dart'; +import 'package:mc_common_app/repositories/user_repo.dart'; +import 'package:mc_common_app/utils/navigator.dart'; +import 'package:mc_common_app/utils/shared_prefrence.dart'; +import 'package:mc_common_app/utils/utils.dart'; +import 'package:mc_common_app/view_models/base_view_model.dart'; +import 'package:mc_common_app/widgets/dialog/dialogs.dart'; +import 'package:mc_common_app/widgets/dialog/message_dialog.dart'; +import 'package:mc_common_app/widgets/dialog/otp_dialog.dart'; +import 'package:mc_common_app/widgets/tab/login_email_tab.dart'; + +class UserVM extends BaseVM { + final UserRepo userRepo; + + UserVM({required this.userRepo}); + + bool completeProfilePageCheckbox = false; + + void updateCompleteProfilePageCheckbox(bool newValue) { + completeProfilePageCheckbox = newValue; + notifyListeners(); + } + + String displayStrengthText = ''; + + void updateStrengthText(String newValue) { + displayStrengthText = newValue; + notifyListeners(); + } + + double strengthThreshold = 0.0; + + void updateStrengthThreshold(double newValue) { + strengthThreshold = newValue; + notifyListeners(); + } + + Future changeUserEmail(BuildContext context, String email, String password) async { + Utils.showLoading(context); + ChanEmailRespModel otpRequest = await userRepo.changeEmailOTPRequest(email, password); + Utils.hideLoading(context); + if (otpRequest.messageStatus == 1) { + showMDialog(context, child: OtpDialog( + onClick: (String code) async { + pop(context); + Utils.showLoading(context); + ConfirmEmailRespModel otpCompare = await userRepo.changeEmail(otpRequest.data!.userToken ?? "", code); + Utils.hideLoading(context); + if (otpCompare.messageStatus == 1) { + showMDialog( + context, + child: MessageDialog( + title: LocaleKeys.emailChangedSuccessfully.tr(), + //"Email is Changed Successfully", + onClick: () { + Navigator.of(context).pushNamedAndRemoveUntil(AppRoutes.loginWithPassword, (Route route) => false); + }, + ), + ); + } else { + Utils.showToast(otpCompare.message ?? ""); + } + }, + )); + } else { + Utils.showToast(otpRequest.message ?? ""); + } + } + + Future changeUserMobile(BuildContext context, int countryId, String mobileNo, String password) async { + Utils.showLoading(context); + ChangeMobileRespModel otpRequest = await userRepo.changeMobileNoOTPRequest(countryId, mobileNo, password); + Utils.hideLoading(context); + if (otpRequest.messageStatus == 1) { + showMDialog(context, child: OtpDialog( + onClick: (String code) async { + pop(context); + Utils.showLoading(context); + ConfirmMobileRespModel otpCompare = await userRepo.changeMobileNo(otpRequest.data!.userToken ?? "", code); + Utils.hideLoading(context); + if (otpCompare.messageStatus == 1) { + showMDialog( + context, + child: MessageDialog( + title: LocaleKeys.phoneNumberVerified.tr(), + //"Phone Number Verified", + onClick: () { + Navigator.of(context).pushNamedAndRemoveUntil(AppRoutes.loginWithPassword, (Route route) => false); + }, + ), + ); + } else { + Utils.showToast(otpCompare.message ?? ""); + } + }, + )); + } else { + Utils.showToast(otpRequest.message ?? ""); + } + } + + Future changeUserPassword(BuildContext context, String newPassword, String currentPassword) async { + if (Utils.passwordValidateStructure(newPassword)) { + Utils.showLoading(context); + MResponse res = await userRepo.changePassword(currentPassword, newPassword); + Utils.hideLoading(context); + if (res.messageStatus == 1) { + Utils.showToast(LocaleKeys.passwordIsUpdated.tr()); + //("Password is Updated"); + // navigateWithName(context, AppRoutes.loginWithPassword); + Navigator.of(context).pushNamedAndRemoveUntil(AppRoutes.loginWithPassword, (Route route) => false); + } else { + Utils.showToast(res.message ?? ""); + } + } else { + Utils.showToast(LocaleKeys.passwordShouldContains.tr()); + //("Password Should contains Character, Number, Capital and small letters"); + } + } + + Future performCompleteProfile( + BuildContext context, { + required String password, + required String confirmPassword, + required String firstName, + required String lastName, + required String email, + required String? userId, + }) async { + if (Utils.passwordValidateStructure(password)) { + if (password == confirmPassword) { + Utils.showLoading(context); + RegisterUserRespModel user = await userRepo.basicComplete(userId ?? "", firstName, lastName, email, password); + Utils.hideLoading(context); + if (user.messageStatus == 1) { + Utils.showToast(LocaleKeys.successfullyRegistered.tr()); + pop(context); + } else { + Utils.showToast(user.message ?? ""); + } + } else { + Utils.showToast(LocaleKeys.pleaseEnterSamePassword.tr()); + //("Please enter same password"); + } + } else { + Utils.showToast(LocaleKeys.passwordShouldContains.tr()); + //("Password Should contains Character, Number, Capital and small letters"); + } + } + + bool dataValidation({ + required String password, + required String? firstName, + required String? lastName, + required String? email, + }) { + bool isValid = true; + if (firstName!.isEmpty) { + Utils.showToast(LocaleKeys.firstNameMandatory.tr()); + //("First name is mandatory"); + isValid = false; + } else if (lastName!.isEmpty) { + Utils.showToast(LocaleKeys.surnameNameMandatory.tr()); + //("Surname is mandatory"); + isValid = false; + } else if (email!.isNotEmpty) { + if (!Utils.isEmailValid(email)) { + Utils.showToast(LocaleKeys.enterValidEmail.tr()); + isValid = false; + } + } else if (password.isEmpty) { + Utils.showToast(LocaleKeys.passwordNameMandatory.tr()); + //("Password is mandatory"); + isValid = false; + } else if (!completeProfilePageCheckbox) { + Utils.showToast(LocaleKeys.pleaseAcceptTerms.tr()); + //("Please accept terms"); + isValid = false; + } + return isValid; + } + + void checkPassword(String password) { + if (password.length <= 6) { + updateStrengthThreshold(1 / 4); + updateStrengthText('Your password is too short'); + } else if (password.length < 8) { + updateStrengthThreshold(2 / 4); + updateStrengthText('Your password is acceptable but not strong'); + } else { + if (!letterReg.hasMatch(password) || !numReg.hasMatch(password)) { + updateStrengthThreshold(3 / 4); + updateStrengthText('Your password is strong'); + } else { + updateStrengthThreshold(1); + updateStrengthText('Your password is very strong'); + } + } + notifyListeners(); + } + + Future confirmPasswordOTP(BuildContext context, {required String userToken, required String newPassword}) async { + if (Utils.passwordValidateStructure(newPassword)) { + Utils.showLoading(context); + ConfirmPasswordRespModel data = await userRepo.forgetPassword(userToken, newPassword); + Utils.hideLoading(context); + if (data.messageStatus == 1) { + Utils.showToast(LocaleKeys.passwordIsUpdated.tr()); + navigateWithName(context, AppRoutes.loginWithPassword); + } else { + Utils.showToast(data.message ?? ""); + } + } else { + Utils.showToast(LocaleKeys.passwordShouldContains.tr()); + } + } + + Future verifyEmail(BuildContext context, {required String email, required String userID}) async { + Utils.showLoading(context); + VerifyEmailRespModel otpRequest = await userRepo.emailVerify(email, userID); + Utils.hideLoading(context); + if (otpRequest.messageStatus == 1) { + showMDialog(context, child: OtpDialog( + onClick: (String code) async { + pop(context); + Utils.showLoading(context); + MResponse otpCompare = await userRepo.emailVerifyOTPVerify(otpRequest.data!.userToken ?? "", code); + Utils.hideLoading(context); + if (otpCompare.messageStatus == 1) { + AppStateCm().getUser.data!.userInfo!.isEmailVerified = true; + Utils.showToast(LocaleKeys.emailVerified.tr()); + } else { + Utils.showToast(otpCompare.message ?? ""); + } + }, + )); + } else { + Utils.showToast(otpRequest.message ?? ""); + } + notifyListeners(); + } + + Future forgetPasswordOTPMethod(BuildContext context, {required String userToken}) async { + showMDialog(context, child: OtpDialog( + onClick: (String code) async { + pop(context); + Utils.showLoading(context); + PasswordOTPCompareResModel otpCompare = await userRepo.forgetPasswordOTPCompare(userToken, code); + Utils.hideLoading(context); + if (otpCompare.messageStatus == 1) { + var userToken = otpCompare.data!.userToken; + navigateWithName(context, AppRoutes.confirmNewPasswordPage, arguments: userToken); + } else { + Utils.showToast(otpCompare.message ?? ""); + } + }, + )); + } + + Future forgetPasswordPhoneOTP(BuildContext context, {required String countryCode, required String userName, required int otpType}) async { + Utils.showLoading(context); + Response response = await userRepo.forgetPasswordOTPRequest(countryCode + userName, otpType); + Utils.hideLoading(context); + PasswordOTPRequestRespModel otpRequest = PasswordOTPRequestRespModel.fromJson(jsonDecode(response.body)); + if (otpRequest.messageStatus == 1) { + var userToken = otpRequest.data!.userToken; + navigateReplaceWithName(context, AppRoutes.forgetPasswordMethodPage, arguments: userToken); + } else { + Utils.showToast(otpRequest.message ?? ""); + } + } + + Future forgetPasswordEmailOTP(BuildContext context, {required String countryCode, required String userName, required int otpType}) async { + Utils.showLoading(context); + Response response = await userRepo.forgetPasswordOTPRequest(userName, otpType); + Utils.hideLoading(context); + PasswordOTPRequestRespModel otpRequest = PasswordOTPRequestRespModel.fromJson(jsonDecode(response.body)); + if (otpRequest.messageStatus == 1) { + Utils.showToast(LocaleKeys.codeSentToEmail.tr()); + showMDialog(context, child: OtpDialog( + onClick: (String code) async { + pop(context); + Utils.showLoading(context); + PasswordOTPCompareResModel otpCompare = await userRepo.forgetPasswordOTPCompare(otpRequest.data!.userToken ?? "", code); + Utils.hideLoading(context); + if (otpCompare.messageStatus == 1) { + var userToken = otpCompare.data!.userToken; + navigateWithName(context, AppRoutes.confirmNewPasswordPage, arguments: userToken); + } else { + Utils.showToast(otpCompare.message ?? ""); + } + }, + )); + } else { + Utils.showToast(otpRequest.message ?? ""); + } + } + + Future performBasicOtpLoginSelectionPage(BuildContext context, {required String userToken}) async { + Utils.showLoading(context); + LoginPasswordRespModel user = await userRepo.loginV2OTP(userToken, "1"); + Utils.hideLoading(context); + if (user.messageStatus == 1) { + showMDialog(context, child: OtpDialog( + onClick: (String code) async { + pop(context); + Utils.showLoading(context); + Response response2 = await userRepo.loginV2OTPVerify(user.data!.userToken ?? "", code); + Utils.hideLoading(context); + RegisterUserRespModel verifiedUser = RegisterUserRespModel.fromJson(jsonDecode(response2.body)); + if (verifiedUser.messageStatus == 1) { + User user = User.fromJson(jsonDecode(response2.body)); + if (user.data!.userInfo!.roleId == 4) { + AppStateCm().setUser = user; + SharedPrefManager.setUserToken(user.data!.accessToken ?? ""); + SharedPrefManager.setUserId(user.data!.userInfo!.userId ?? ""); + SharedPrefManager.setRefreshToken(user.data!.refreshToken ?? ""); + SharedPrefManager.setData(jsonEncode(user.data!.userInfo!.toJson())); + navigateReplaceWithName(context, AppRoutes.dashboard); + } else { + Utils.showToast + ("Sorry, Only Customer's can log in this app"); + } + } else { + Utils.showToast(verifiedUser.message ?? ""); + } + }, + )); + } else { + Utils.showToast(user.message ?? ""); + } + } + + Future performApiCallLoginVerificationPage(BuildContext context) async { + String userToken = ""; + String userName = await SharedPrefManager.getPhoneOrEmail(); + String password = await SharedPrefManager.getUserPassword(); + if (userName.isNotEmpty && userName.isNotEmpty) { + Utils.showLoading(context); + Response response = await userRepo.loginV1(userName, password); + Utils.hideLoading(context); + LoginPasswordRespModel user = LoginPasswordRespModel.fromJson(jsonDecode(response.body)); + if (user.messageStatus == 1) { + userToken = user.data!.userToken ?? ""; + // navigateWithName(context, AppRoutes.loginMethodSelection, arguments: user.data!.userToken); + } else { + Utils.showToast(user.message ?? ""); + } + } + return userToken; + } + + Future performBasicOtpLoginVerificationPage(BuildContext context, {required String userToken}) async { + Utils.showLoading(context); + LoginPasswordRespModel user = await userRepo.loginV2OTP(userToken, "1"); + Utils.hideLoading(context); + if (user.messageStatus == 1) { + showMDialog(context, child: OtpDialog( + onClick: (String code) async { + pop(context); + Utils.showLoading(context); + Response response2 = await userRepo.loginV2OTPVerify(user.data!.userToken ?? "", code); + Utils.hideLoading(context); + RegisterUserRespModel verifiedUser = RegisterUserRespModel.fromJson(jsonDecode(response2.body)); + if (verifiedUser.messageStatus == 1) { + User user = User.fromJson(jsonDecode(response2.body)); + AppStateCm().setUser = user; + navigateReplaceWithName(context, AppRoutes.dashboard); + } else { + Utils.showToast(verifiedUser.message ?? ""); + } + }, + )); + } else { + Utils.showToast(user.message ?? ""); + } + } + + Future performBasicOtpLoginVerifyAccountPage(BuildContext context, {required String phoneNum, required int otpType}) async { + Utils.showLoading(context); + BasicOtpRespModel basicOtp = await userRepo.basicOtp(phoneNum, otpType: otpType); + Utils.hideLoading(context); + if (basicOtp.messageStatus == 1) { + showMDialog(context, child: OtpDialog( + onClick: (String code) async { + pop(context); + Utils.showLoading(context); + RegisterUserRespModel user = await userRepo.basicVerify(phoneNum, code, basicOtp.data!.userToken ?? ""); + Utils.hideLoading(context); + if (user.messageStatus == 1) { + Utils.showToast(user.message ?? ""); + showMDialog( + context, + child: MessageDialog( + title: LocaleKeys.phoneNumberVerified.tr(), + //"Phone Number Verified", + onClick: () { + pop(context); + navigateWithName(context, AppRoutes.profile1, arguments: user); + }, + ), + ); + } else { + Utils.showToast(user.message ?? ""); + } + }, + )); + } else { + Utils.showToast(basicOtp.message ?? ""); + } + } + + Future performBasicOtpLoginWithPasswordPage(BuildContext context, {required ClassType type, required String countryCode, required String phoneNum, required String password}) async { + Utils.showLoading(context); + Response response = await userRepo.loginV1(type == ClassType.NUMBER ? countryCode + phoneNum : phoneNum, password); + Utils.hideLoading(context); + LoginPasswordRespModel user = LoginPasswordRespModel.fromJson(jsonDecode(response.body)); + if (user.messageStatus == 1) { + SharedPrefManager.setPhoneOrEmail(type == ClassType.NUMBER ? countryCode + phoneNum : phoneNum); + SharedPrefManager.setUserPassword(password); + navigateReplaceWithName(context, AppRoutes.loginMethodSelection, arguments: user.data!.userToken); + } else { + Utils.showToast(user.message ?? ""); + } + } + + Future getAllCountries() async { + return await userRepo.getAllCountries(); + } + + Future performBasicOtpRegisterPage(BuildContext context, {required String countryCode, required String phoneNum, required int role}) async { + Utils.showLoading(context); + BasicOtpRespModel basicOtp = await userRepo.basicOtp(countryCode + phoneNum, roleId: role); + Utils.hideLoading(context); + if (basicOtp.messageStatus == 1) { + showMDialog(context, child: OtpDialog( + onClick: (String code) async { + pop(context); + Utils.showLoading(context); + RegisterUserRespModel user = await userRepo.basicVerify(countryCode + phoneNum, code, basicOtp.data!.userToken ?? ""); + Utils.hideLoading(context); + if (user.messageStatus == 1) { + Utils.showToast(user.message ?? ""); + navigateReplaceWithName(context, AppRoutes.completeProfile, arguments: user); + } else { + Utils.showToast(user.message ?? ""); + } + }, + )); + } else { + Utils.showToast(basicOtp.message ?? ""); + } + } +} diff --git a/lib/views/splash/splash_page.dart b/lib/views/splash/splash_page.dart new file mode 100644 index 0000000..a8b7d67 --- /dev/null +++ b/lib/views/splash/splash_page.dart @@ -0,0 +1,52 @@ +import 'package:mc_common_app/config/routes.dart'; +import 'package:mc_common_app/utils/navigator.dart'; +import 'package:mc_common_app/utils/utils.dart'; +import 'package:flutter/material.dart'; + +class SplashPage extends StatelessWidget { + const SplashPage({Key? key}) : super(key: key); + + @override + Widget build(BuildContext context) { + performTimer(context); + return Scaffold( + body: Container( + width: double.infinity, + height: double.infinity, + color: Colors.black, + child: Column( + children: [ + Utils. mExp(1), + Expanded( + child: Image.asset( + "assets/images/ic_logo_white.png", + ), + ), + Expanded( + flex: 10, + child: Image.asset( + "assets/images/bn_car.jpeg", + fit: BoxFit.cover, + width: double.infinity, + height: 00, + ), + ), + Expanded( + flex: 3, + child: Image.asset( + "assets/images/ic_engine.png", + ), + ), + Utils.mExp(1), + ], + ), + ), + ); + } + + performTimer(BuildContext context) { + Utils.delay(3).whenComplete(() { + navigateReplaceWithName(context, AppRoutes.registerSelection); + }); + } +} diff --git a/lib/views/user/change_email_page.dart b/lib/views/user/change_email_page.dart new file mode 100644 index 0000000..0874ff6 --- /dev/null +++ b/lib/views/user/change_email_page.dart @@ -0,0 +1,67 @@ +import 'package:mc_common_app/extensions/int_extensions.dart'; +import 'package:mc_common_app/extensions/string_extensions.dart'; +import 'package:mc_common_app/generated/locale_keys.g.dart'; +import 'package:mc_common_app/view_models/user_view_model.dart'; +import 'package:mc_common_app/widgets/app_bar.dart'; +import 'package:mc_common_app/widgets/show_fill_button.dart'; +import 'package:mc_common_app/widgets/txt_field.dart'; +import 'package:easy_localization/easy_localization.dart'; +import 'package:flutter/material.dart'; +import 'package:provider/provider.dart'; + +class ChangeEmailPage extends StatefulWidget { + const ChangeEmailPage({Key? key}) : super(key: key); + + @override + State createState() => _ChangeEmailPageState(); +} + +class _ChangeEmailPageState extends State { + String password = ""; + String email = ''; + + late UserVM userVM; + + @override + void initState() { + userVM = Provider.of(context, listen: false); + super.initState(); + } + + @override + Widget build(BuildContext context) { + return Scaffold( + appBar: appBar(context, title: LocaleKeys.changeEmail.tr()), + body: SingleChildScrollView( + child: Container( + // width: double.infinity, + // height: double.infinity, + padding: const EdgeInsets.all(20), + child: Column( + children: [ + LocaleKeys.enterEmail.tr().toText(height: 23 / 24, fontSize: 24, letterSpacing: -1.44,), + 12.height, + TxtField( + hint: LocaleKeys.enterNewEmail.tr(), + onChanged: (v) => email = v, + ), + 12.height, + TxtField( + hint: LocaleKeys.enterCurrentPassword.tr(), + onChanged: (v) => password = v, + ), + 40.height, + ShowFillButton( + title: LocaleKeys.confirm.tr(), + maxWidth: double.infinity, + onPressed: () async { + await userVM.changeUserEmail(context, email, password); + }, + ), + ], + ), + ), + ), + ); + } +} diff --git a/lib/views/user/change_mobile_page.dart b/lib/views/user/change_mobile_page.dart new file mode 100644 index 0000000..47e976a --- /dev/null +++ b/lib/views/user/change_mobile_page.dart @@ -0,0 +1,67 @@ +import 'package:mc_common_app/extensions/int_extensions.dart'; +import 'package:mc_common_app/extensions/string_extensions.dart'; +import 'package:mc_common_app/generated/locale_keys.g.dart'; +import 'package:mc_common_app/view_models/user_view_model.dart'; +import 'package:mc_common_app/widgets/app_bar.dart'; +import 'package:mc_common_app/widgets/show_fill_button.dart'; +import 'package:mc_common_app/widgets/txt_field.dart'; +import 'package:easy_localization/easy_localization.dart'; +import 'package:flutter/material.dart'; +import 'package:provider/provider.dart'; + +class ChangeMobilePage extends StatefulWidget { + @override + State createState() => _ChangeMobilePageState(); +} + +class _ChangeMobilePageState extends State { + int countryID = 1; + + String mobileNo = ''; + String password = ''; + + late UserVM userVM; + + @override + void initState() { + userVM = Provider.of(context, listen: false); + super.initState(); + } + + @override + Widget build(BuildContext context) { + return Scaffold( + appBar: appBar(context, title: LocaleKeys.changeMobile.tr()), + body: SingleChildScrollView( + child: Container( + // width: double.infinity, + // height: double.infinity, + padding: EdgeInsets.all(20), + child: Column( + children: [ + LocaleKeys.enterNewPhoneNumber.tr().toText(height: 23 / 24, fontSize: 24, letterSpacing: -1.44,), + 12.height, + TxtField( + hint: LocaleKeys.enterNewPhoneNumber.tr(), + onChanged: (v) => mobileNo = v, + ), + 12.height, + TxtField( + hint: LocaleKeys.enterCurrentPassword.tr(), + onChanged: (v) => password = v, + ), + 20.height, + ShowFillButton( + title: LocaleKeys.confirm.tr(), + maxWidth: double.infinity, + onPressed: () async { + await userVM.changeUserMobile(context, countryID, mobileNo, password); + }, + ), + ], + ), + ), + ), + ); + } +} diff --git a/lib/views/user/change_password_page.dart b/lib/views/user/change_password_page.dart new file mode 100644 index 0000000..4e65da2 --- /dev/null +++ b/lib/views/user/change_password_page.dart @@ -0,0 +1,67 @@ +import 'package:mc_common_app/extensions/int_extensions.dart'; +import 'package:mc_common_app/extensions/string_extensions.dart'; +import 'package:mc_common_app/generated/locale_keys.g.dart'; +import 'package:mc_common_app/view_models/user_view_model.dart'; +import 'package:mc_common_app/widgets/app_bar.dart'; +import 'package:mc_common_app/widgets/show_fill_button.dart'; +import 'package:mc_common_app/widgets/txt_field.dart'; +import 'package:easy_localization/easy_localization.dart'; +import 'package:flutter/material.dart'; +import 'package:provider/provider.dart'; + +class ChangePasswordPage extends StatefulWidget { + const ChangePasswordPage({Key? key}) : super(key: key); + + @override + State createState() => _ChangePasswordPageState(); +} + +class _ChangePasswordPageState extends State { + String newPassword = ""; + String currentPassword = ''; + + late UserVM userVM; + + @override + void initState() { + userVM = Provider.of(context, listen: false); + super.initState(); + } + + @override + Widget build(BuildContext context) { + return Scaffold( + appBar: appBar(context, title: LocaleKeys.changePassword.tr()), + body: SingleChildScrollView( + child: Container( + // width: double.infinity, + // height: double.infinity, + padding: EdgeInsets.all(40), + child: Column( + children: [ + LocaleKeys.enterNewPassword.tr().toText(height: 23 / 24, fontSize: 24, letterSpacing: -1.44,), + 12.height, + TxtField( + hint: LocaleKeys.enterOldPassword.tr(), + onChanged: (v) => currentPassword = v, + ), + 12.height, + TxtField( + hint: LocaleKeys.enterNewPassword.tr(), + onChanged: (v) => newPassword = v, + ), + 20.height, + ShowFillButton( + title: LocaleKeys.confirm.tr(), + maxWidth: double.infinity, + onPressed: () async { + await userVM.changeUserPassword(context, newPassword, currentPassword); + }, + ), + ], + ), + ), + ), + ); + } +} diff --git a/lib/views/user/complete_profile_page.dart b/lib/views/user/complete_profile_page.dart new file mode 100644 index 0000000..dd125ee --- /dev/null +++ b/lib/views/user/complete_profile_page.dart @@ -0,0 +1,164 @@ +import 'package:mc_common_app/theme/colors.dart'; +import 'package:mc_common_app/extensions/int_extensions.dart'; +import 'package:mc_common_app/extensions/string_extensions.dart'; +import 'package:mc_common_app/generated/locale_keys.g.dart'; +import 'package:mc_common_app/models/user/register_user.dart'; +import 'package:mc_common_app/view_models/user_view_model.dart'; +import 'package:mc_common_app/widgets/app_bar.dart'; +import 'package:mc_common_app/widgets/show_fill_button.dart'; +import 'package:mc_common_app/widgets/txt_field.dart'; +import 'package:easy_localization/easy_localization.dart'; +import 'package:flutter/material.dart'; +import 'package:provider/provider.dart'; + +class CompleteProfilePage extends StatefulWidget { + final RegisterUserRespModel user; + + const CompleteProfilePage(this.user, {Key? key}) : super(key: key); + + @override + State createState() => _CompleteProfilePageState(); +} + +class _CompleteProfilePageState extends State { + String? firstName = "", lastName = "", email = "", confirmPassword = ""; + late String password = ""; + bool isChecked = false; + late UserVM userVM; + + @override + void initState() { + userVM = Provider.of(context, listen: false); + super.initState(); + } + + @override + Widget build(BuildContext context) { + return Scaffold( + appBar: appBar( + context, + title: LocaleKeys.signUp.tr(), + ), + body: SizedBox( + width: double.infinity, + height: double.infinity, + child: SingleChildScrollView( + child: Padding( + padding: const EdgeInsets.all(20), + child: Column( + children: [ + 6.height, + LocaleKeys.completeProfile.tr().toText(height: 23 / 24, fontSize: 24, letterSpacing: -1.44,), + 12.height, + Padding( + padding: const EdgeInsets.symmetric(horizontal: 20), + child: LocaleKeys.profileMsg.tr().toText( + color: MyColors.lightTextColor, + textAlign: TextAlign.center, + fontSize: 14, + height: 23 / 24, + letterSpacing: -0.48, + ), + ), + 12.height, + TxtField( + hint: LocaleKeys.firstName.tr(), + value: firstName, + onChanged: (v) { + firstName = v; + }, + ), + 12.height, + TxtField( + hint: LocaleKeys.surname.tr(), + value: lastName, + onChanged: (v) { + lastName = v; + }, + ), + 12.height, + TxtField( + hint: LocaleKeys.email.tr(), + value: email, + // isButtonEnable: email!.length > 0 ? true : false, + buttonTitle: LocaleKeys.verify.tr(), + onChanged: (v) { + email = v; + }, + ), + 12.height, + TxtField( + hint: LocaleKeys.createPass.tr(), + isPasswordEnabled: true, + maxLines: 1, + value: password, + onChanged: (v) { + password = v; + }, + ), + 12.height, + TxtField( + hint: LocaleKeys.confirmPass.tr(), + isPasswordEnabled: true, + maxLines: 1, + value: confirmPassword, + onChanged: (v) { + confirmPassword = v; + }, + ), + 50.height, + Row( + children: [ + Consumer(builder: (BuildContext context, UserVM userVM, Widget? child) { + return Checkbox( + value: userVM.completeProfilePageCheckbox, + activeColor: Colors.blue, + onChanged: (value) { + userVM.updateCompleteProfilePageCheckbox(value!); + }, + ); + }), + Expanded( + child: Column( + children: [ + LocaleKeys.termsOfService.tr().toText(fontSize: 12), + LocaleKeys.terms.tr().toText(fontSize: 12, color: MyColors.darkPrimaryColor), + ], + ), + ), + Theme( + data: ThemeData(unselectedWidgetColor: Colors.transparent), + child: Checkbox( + value: false, + onChanged: (_) {}, + ), + ) + ], + ), + 16.height, + ShowFillButton( + title: LocaleKeys.save.tr(), + maxWidth: double.infinity, + onPressed: () { + bool validateStatus = userVM.dataValidation(password: password, firstName: firstName, lastName: lastName, email: email); + if (validateStatus) { + userVM.performCompleteProfile( + context, + password: password, + confirmPassword: confirmPassword!, + firstName: firstName!, + lastName: lastName!, + email: email!, + userId: widget.user.data!.userId ?? "", + ); + } + }), + 16.height, + ], + ), + ), + ), + ), + ); + } +} diff --git a/lib/views/user/confirm_new_password.dart b/lib/views/user/confirm_new_password.dart new file mode 100644 index 0000000..5f7dcb0 --- /dev/null +++ b/lib/views/user/confirm_new_password.dart @@ -0,0 +1,58 @@ + +import 'package:mc_common_app/extensions/string_extensions.dart'; +import 'package:mc_common_app/extensions/int_extensions.dart'; +import 'package:mc_common_app/generated/locale_keys.g.dart'; +import 'package:mc_common_app/view_models/user_view_model.dart'; +import 'package:mc_common_app/widgets/app_bar.dart'; +import 'package:mc_common_app/widgets/show_fill_button.dart'; +import 'package:mc_common_app/widgets/txt_field.dart'; +import 'package:easy_localization/easy_localization.dart'; +import 'package:flutter/material.dart'; +import 'package:provider/provider.dart'; + +class ConfirmNewPasswordPage extends StatelessWidget { + final String userToken; + + ConfirmNewPasswordPage(this.userToken, {Key? key}) : super(key: key); + + String newPassword = ""; + + @override + Widget build(BuildContext context) { + UserVM userVM = context.read(); + return Scaffold( + appBar: appBar(context, title: LocaleKeys.forgetPassword.tr()), + body: Container( + width: double.infinity, + height: double.infinity, + padding: const EdgeInsets.all(40), + child: Column( + children: [ + LocaleKeys.newPassword.tr().toText(height: 23 / 24, fontSize: 24, letterSpacing: -1.44,), + 12.height, + TxtField( + // hint: "Enter New Password", + hint: LocaleKeys.enterNewPassword.tr(), + value: newPassword, + onChanged: (v) { + newPassword = v; + }, + ), + 40.height, + ShowFillButton( + title: LocaleKeys.confirm.tr(), + maxWidth: double.infinity, + onPressed: () async { + await userVM.confirmPasswordOTP( + context, + newPassword: newPassword, + userToken: userToken, + ); + }, + ), + ], + ), + ), + ); + } +} diff --git a/lib/views/user/confirm_new_password_page.dart b/lib/views/user/confirm_new_password_page.dart new file mode 100644 index 0000000..5ea08fa --- /dev/null +++ b/lib/views/user/confirm_new_password_page.dart @@ -0,0 +1,91 @@ +import 'package:mc_common_app/utils/utils.dart'; +import 'package:mc_common_app/extensions/int_extensions.dart'; +import 'package:mc_common_app/extensions/string_extensions.dart'; +import 'package:mc_common_app/generated/locale_keys.g.dart'; +import 'package:mc_common_app/view_models/user_view_model.dart'; +import 'package:mc_common_app/widgets/app_bar.dart'; +import 'package:mc_common_app/widgets/show_fill_button.dart'; +import 'package:easy_localization/easy_localization.dart'; +import 'package:flutter/material.dart'; +import 'package:provider/provider.dart'; + +class ConfirmNewPasswordPage extends StatefulWidget { + final String userToken; + + const ConfirmNewPasswordPage(this.userToken, {Key? key}) : super(key: key); + + @override + State createState() => _ConfirmNewPasswordPageState(); +} + +class _ConfirmNewPasswordPageState extends State { + String newPassword = ""; + String confirmPassword = ''; + + @override + Widget build(BuildContext context) { + UserVM userVM = context.read(); + return Scaffold( + appBar: appBar(context, title: LocaleKeys.forgetPassword.tr()), + body: SingleChildScrollView( + child: Container( + // width: double.infinity, + // height: double.infinity, + padding: const EdgeInsets.all(40), + child: Column( + children: [ + LocaleKeys.newPassword.tr().toText(height: 23 / 24, fontSize: 24, letterSpacing: -1.44,), + 12.height, + TextFormField( + decoration: InputDecoration( + // hintText: "Enter New Password", + hintText: LocaleKeys.enterNewPassword.tr(), + hintStyle: const TextStyle(color: Colors.grey), + border: const OutlineInputBorder( + borderRadius: BorderRadius.all( + Radius.circular(5.0), + ), + ), + ), + obscureText: true, + onChanged: (v) => newPassword = v, + ), + 12.height, + TextFormField( + decoration: InputDecoration( + // hintText: "Confirm Password", + hintText: LocaleKeys.confirmPassword.tr(), + hintStyle: const TextStyle(color: Colors.grey), + border: const OutlineInputBorder( + borderRadius: BorderRadius.all( + Radius.circular(5.0), + ), + ), + ), + obscureText: true, + onChanged: (v) => confirmPassword = v, + ), + 40.height, + ShowFillButton( + title: LocaleKeys.confirm.tr(), + maxWidth: double.infinity, + onPressed: () { + if (validation()) userVM.confirmPasswordOTP(context, newPassword: newPassword, userToken: widget.userToken); + }, + ), + ], + ), + ), + ), + ); + } + + bool validation() { + bool isValid = true; + if (newPassword != confirmPassword) { + Utils.showToast(LocaleKeys.pleaseEnterSamePassword.tr()); + isValid = false; + } + return isValid; + } +} diff --git a/lib/views/user/edit_account_page.dart b/lib/views/user/edit_account_page.dart new file mode 100644 index 0000000..1888c34 --- /dev/null +++ b/lib/views/user/edit_account_page.dart @@ -0,0 +1,159 @@ +import 'package:mc_common_app/classes/app_state_cm.dart'; +import 'package:mc_common_app/config/routes.dart'; +import 'package:mc_common_app/extensions/int_extensions.dart'; +import 'package:mc_common_app/extensions/string_extensions.dart'; +import 'package:mc_common_app/generated/locale_keys.g.dart'; +import 'package:mc_common_app/utils/navigator.dart'; +import 'package:mc_common_app/view_models/user_view_model.dart'; +import 'package:mc_common_app/widgets/app_bar.dart'; +import 'package:easy_localization/easy_localization.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter_svg/flutter_svg.dart'; +import 'package:provider/provider.dart'; +import '../../theme/colors.dart'; + +class EditAccountPage extends StatefulWidget { + const EditAccountPage({Key? key}) : super(key: key); + + @override + State createState() => _EditAccountPageState(); +} + +class _EditAccountPageState extends State { + String userID = ""; + String email = ''; + + @override + Widget build(BuildContext context) { + UserVM userVM = context.read(); + return Scaffold( + appBar: appBar(context, title: LocaleKeys.editAccount.tr()), + body: Container( + width: double.infinity, + height: double.infinity, + padding: const EdgeInsets.all(20), + child: Column( + children: [ + 20.height, + Row( + crossAxisAlignment: CrossAxisAlignment.center, + mainAxisAlignment: MainAxisAlignment.start, + children: [ + SvgPicture.asset( + "assets/images/ic_lock.svg", + color: MyColors.darkPrimaryColor, + width: 16, + ), + 20.width, + Expanded(child: LocaleKeys.changePassword.tr().toText(isBold: true, fontSize: 12)), + ElevatedButton( + style: ElevatedButton.styleFrom( + textStyle: const TextStyle(color: Colors.white), + backgroundColor: MyColors.darkPrimaryColor, + padding: const EdgeInsets.symmetric(horizontal: 8, vertical: 8), + ), + onPressed: () { + navigateWithName(context, AppRoutes.changePassword); + }, + child: Text( + LocaleKeys.change.tr(), + style: const TextStyle( + fontSize: 14, letterSpacing: -0.48, + fontWeight: FontWeight.w600, + height: 23 / 24, + ), + ), + ), + ], + ), + 15.height, + Row( + crossAxisAlignment: CrossAxisAlignment.center, + mainAxisAlignment: MainAxisAlignment.start, + children: [ + SvgPicture.asset( + "assets/images/ic_mobile.svg", + color: MyColors.darkPrimaryColor, + width: 16, + ), + 20.width, + Expanded(child: LocaleKeys.changeMobile.tr().toText(isBold: true, fontSize: 12)), + LocaleKeys.verify.tr().toText(color: Colors.green, fontSize: 12), + 20.width, + ElevatedButton( + style: ElevatedButton.styleFrom( + textStyle: const TextStyle(color: Colors.white), + backgroundColor: MyColors.darkPrimaryColor, + padding: const EdgeInsets.symmetric(horizontal: 8, vertical: 8), + ), + onPressed: () { + navigateWithName(context, AppRoutes.changeMobilePage); + }, + child: Text( + LocaleKeys.change.tr(), + style: const TextStyle(fontSize: 14, height: 23 / 24,fontWeight: FontWeight.w600), + ), + ) + ], + ), + 20.height, + Row( + crossAxisAlignment: CrossAxisAlignment.center, + mainAxisAlignment: MainAxisAlignment.start, + children: [ + SvgPicture.asset( + "assets/images/ic_email.svg", + color: MyColors.darkPrimaryColor, + width: 16, + ), + 20.width, + Expanded(child: LocaleKeys.changeEmail.tr().toText(isBold: true, fontSize: 12)), + InkWell( + child: ((AppStateCm().getUser.data!.userInfo!.isEmailVerified ?? false) ? LocaleKeys.verified.tr() : LocaleKeys.verify.tr()).toText( + color: Colors.green, + fontSize: 12, + ), + onTap: (AppStateCm().getUser.data!.userInfo!.isEmailVerified ?? false) + ? null + : () async { + await userVM.verifyEmail(context, email: email, userID: userID); + }, + ), + 20.width, + ElevatedButton( + style: ElevatedButton.styleFrom( + textStyle: const TextStyle(color: Colors.white), + backgroundColor: MyColors.darkPrimaryColor, + padding: const EdgeInsets.symmetric(horizontal: 8, vertical: 8), + ), + onPressed: () { + navigateWithName(context, AppRoutes.changeEmailPage); + }, + child: Text( + LocaleKeys.change.tr(), + style: const TextStyle(fontSize: 14, height: 23 / 24, fontWeight: FontWeight.w600), + ), + ), + ], + ) + + // ListTile( + // leading: SvgPicture.asset("assets/images/ic_mobile.svg"), + // title: "Change Mobile".toText12(), + // onTap: () { + // navigateWithName(context, AppRoutes.changeMobilePage); + // }, + // ), + // ListTile( + // leading: Icon(Icons.email_outlined, color: Colors.blue,), + // title: "Change Email".toText12(), + // onTap: () { + // navigateWithName(context, AppRoutes.changeEmailPage); + // }, + // ), + ], + ), + ), + ); + } +} diff --git a/lib/views/user/forget_password_method_page.dart b/lib/views/user/forget_password_method_page.dart new file mode 100644 index 0000000..c38e9f8 --- /dev/null +++ b/lib/views/user/forget_password_method_page.dart @@ -0,0 +1,70 @@ +import 'package:mc_common_app/classes/consts.dart'; +import 'package:mc_common_app/extensions/string_extensions.dart'; +import 'package:mc_common_app/utils/utils.dart'; +import 'package:mc_common_app/extensions/int_extensions.dart'; +import 'package:mc_common_app/generated/locale_keys.g.dart'; +import 'package:mc_common_app/view_models/user_view_model.dart'; +import 'package:mc_common_app/widgets/app_bar.dart'; +import 'package:mc_common_app/widgets/button/show_image_button.dart'; +import 'package:easy_localization/easy_localization.dart'; +import 'package:flutter/material.dart'; +import 'package:provider/provider.dart'; + +class ForgetPasswordMethodPage extends StatefulWidget { + final String userToken; + + const ForgetPasswordMethodPage(this.userToken, {Key? key}) : super(key: key); + + @override + State createState() => _ForgetPasswordMethodPageState(); +} + +class _ForgetPasswordMethodPageState extends State { + int otpType = 1; + String userOTP = ""; + + @override + Widget build(BuildContext context) { + UserVM userVM = context.read(); + return Scaffold( + appBar: appBar(context, title: LocaleKeys.forgetPassword.tr()), + body: Container( + width: double.infinity, + height: double.infinity, + padding: const EdgeInsets.all(40), + child: Column( + children: [ + LocaleKeys.selectMethod.tr().toText(height: 23 / 24, fontSize: 24, letterSpacing: -1.44,), + 12.height, + Row( + children: [ + Expanded( + child: ShowImageButton( + onClick: () async { + otpType = 1; + await userVM.forgetPasswordOTPMethod(context, userToken: widget.userToken); + }, + title: LocaleKeys.SMS.tr(), + icon: icons + "ic_sms.svg", + ), + ), + 20.width, + Expanded( + child: ShowImageButton( + onClick: () async { + otpType = 1; + await userVM.forgetPasswordOTPMethod(context, userToken: widget.userToken); + }, + title: LocaleKeys.whatsapp.tr(), + icon: icons + "ic_whatsapp.svg", + ), + ), + ], + ), + Utils.mFlex(10), + ], + ), + ), + ); + } +} diff --git a/lib/views/user/forget_password_page.dart b/lib/views/user/forget_password_page.dart new file mode 100644 index 0000000..4f4fac0 --- /dev/null +++ b/lib/views/user/forget_password_page.dart @@ -0,0 +1,153 @@ +import 'dart:async'; +import 'package:mc_common_app/models/user/country.dart'; +import 'package:mc_common_app/theme/colors.dart'; +import 'package:mc_common_app/utils/utils.dart'; +import 'package:mc_common_app/extensions/int_extensions.dart'; +import 'package:mc_common_app/extensions/string_extensions.dart'; +import 'package:mc_common_app/generated/locale_keys.g.dart'; +import 'package:mc_common_app/view_models/user_view_model.dart'; +import 'package:mc_common_app/widgets/app_bar.dart'; +import 'package:mc_common_app/widgets/dropdown/dropdow_field.dart'; +import 'package:mc_common_app/widgets/show_fill_button.dart'; +import 'package:mc_common_app/widgets/tab/login_email_tab.dart'; +import 'package:mc_common_app/widgets/txt_field.dart'; +import 'package:easy_localization/easy_localization.dart'; +import 'package:flutter/material.dart'; +import 'package:provider/provider.dart'; + +class ForgetPasswordPage extends StatefulWidget { + const ForgetPasswordPage({Key? key}) : super(key: key); + + @override + State createState() => _ForgetPasswordPageState(); +} + +class _ForgetPasswordPageState extends State { + int otpType = 1; + + String userName = ""; + ClassType type = ClassType.EMAIL; + Country? _country; + String countryCode = ""; + + late UserVM userVM; + + @override + void initState() { + super.initState(); + + scheduleMicrotask(() { + userVM = Provider.of(context, listen: false); + getCountryList(); + }); + } + + getCountryList() async { + _country = await userVM.getAllCountries(); + setState(() {}); + } + + @override + Widget build(BuildContext context) { + return Scaffold( + appBar: appBar(context, title: LocaleKeys.changePassword.tr()), + body: Container( + width: double.infinity, + height: double.infinity, + padding: const EdgeInsets.all(20), + child: SingleChildScrollView( + child: SizedBox( + height: MediaQuery.of(context).size.height, + child: Column( + children: [ + 12.height, + LocaleKeys.forgetPassword.tr().toText( + fontSize: 20, + letterSpacing: -1.44, + ), + 20.height, + LocaleKeys.retrievePassword.tr().toText( + color: MyColors.lightTextColor, + textAlign: TextAlign.center, + fontSize: 14, + height: 23 / 24, + letterSpacing: -0.48, + ), + 30.height, + LoginEmailTab( + onSelection: (ClassType type) { + setState(() { + this.type = type; + }); + }, + ), + 12.height, + type == ClassType.NUMBER + ? Column( + children: [ + getCountry(), + 6.height, + TxtField( + hint: "5********", + value: userName, + onChanged: (v) { + userName = v; + }, + ) + ], + ) + : TxtField( + hint: LocaleKeys.emailAddress.tr(), + value: userName, + onChanged: (v) { + userName = v; + }, + ), + 20.height, + (type == ClassType.NUMBER ? LocaleKeys.retriveOnPhone.tr() : LocaleKeys.retriveOnEmail.tr()).toText( + color: MyColors.lightTextColor, + textAlign: TextAlign.center, + fontSize: 14, + height: 23 / 24, + letterSpacing: -0.48, + ), + 30.height, + ShowFillButton( + title: LocaleKeys.send.tr(), + maxWidth: double.infinity, + onPressed: () { + if (userName.isNum() && type == ClassType.NUMBER) { + userVM.forgetPasswordPhoneOTP(context, countryCode: countryCode, userName: userName, otpType: otpType); + } else if (!userName.isNum() && type == ClassType.EMAIL) { + userVM.forgetPasswordEmailOTP(context, countryCode: countryCode, userName: userName, otpType: otpType); + } + }, + ), + Utils.mFlex(10), + ], + ), + ), + ), + ), + ); + } + + Widget getCountry() { + if (_country != null) { + List dropList = []; + _country!.data?.forEach((element) { + dropList.add(DropValue(element.id ?? 0, (element.countryName ?? "") + " " + (element.countryCode ?? ""), element.countryCode ?? "")); + }); + return Padding( + padding: const EdgeInsets.all(2.0), + child: DropdownField((DropValue value) { + countryCode = value.subValue; + }, list: dropList, hint: LocaleKeys.selectCountryCode.tr()), + ); + } else { + return const Center( + child: CircularProgressIndicator(), + ); + } + } +} diff --git a/lib/views/user/login_method_selection_page.dart b/lib/views/user/login_method_selection_page.dart new file mode 100644 index 0000000..c144c9c --- /dev/null +++ b/lib/views/user/login_method_selection_page.dart @@ -0,0 +1,89 @@ + +import 'package:mc_common_app/classes/consts.dart'; +import 'package:mc_common_app/extensions/int_extensions.dart'; +import 'package:mc_common_app/extensions/string_extensions.dart'; +import 'package:mc_common_app/generated/locale_keys.g.dart'; +import 'package:mc_common_app/view_models/user_view_model.dart'; +import 'package:mc_common_app/widgets/app_bar.dart'; +import 'package:mc_common_app/widgets/button/show_image_button.dart'; +import 'package:easy_localization/easy_localization.dart'; +import 'package:flutter/material.dart'; +import 'package:provider/provider.dart'; + +class LoginMethodSelectionPage extends StatelessWidget { + final String userToken; + + const LoginMethodSelectionPage(this.userToken, {Key? key}) : super(key: key); + + @override + Widget build(BuildContext context) { + UserVM userVM = context.read(); + return Scaffold( + appBar: appBar(context, title: LocaleKeys.log_in.tr()), + body: Container( + width: double.infinity, + height: double.infinity, + padding: const EdgeInsets.all(20), + child: SingleChildScrollView( + child: Column( + children: [ + LocaleKeys.loginSelection.tr().toText(fontSize: 20, letterSpacing: -1.44,), + 30.height, + LocaleKeys.welcomeBack.tr().toText(fontSize: 20, letterSpacing: -1.44,), + 40.height, + Row( + children: [ + Expanded( + child: ShowImageButton( + onClick: () { + userVM.performBasicOtpLoginSelectionPage(context, userToken: userToken); + }, + title: LocaleKeys.fingerPrint.tr(), + icon: icons + "ic_fingerprint.svg", + ), + ), + 20.width, + Expanded( + child: ShowImageButton( + onClick: () { + userVM.performBasicOtpLoginSelectionPage(context, userToken: userToken); + }, + title: LocaleKeys.faceRecognition.tr(), + icon: icons + "ic_face.svg", + ), + ), + ], + ), + 40.height, + Row( + children: [ + Expanded( + child: ShowImageButton( + onClick: () { + userVM.performBasicOtpLoginSelectionPage(context, userToken: userToken); + }, + title: LocaleKeys.SMS.tr(), + icon: icons + "ic_sms.svg", + ), + ), + 20.width, + Expanded( + child: ShowImageButton( + onClick: () { + // navigateWithName(context, AppRoutes.dashboard); + userVM.performBasicOtpLoginSelectionPage(context, userToken: userToken); + }, + title: LocaleKeys.whatsapp.tr(), + icon: icons + "ic_whatsapp.svg", + ), + ), + ], + ), + ], + ), + ), + ), + ); + } + +} diff --git a/lib/views/user/login_verification_page.dart b/lib/views/user/login_verification_page.dart new file mode 100644 index 0000000..d766cb0 --- /dev/null +++ b/lib/views/user/login_verification_page.dart @@ -0,0 +1,132 @@ +import 'dart:async'; +import 'package:mc_common_app/classes/consts.dart'; +import 'package:mc_common_app/extensions/int_extensions.dart'; +import 'package:mc_common_app/extensions/string_extensions.dart'; +import 'package:mc_common_app/generated/locale_keys.g.dart'; + +import 'package:mc_common_app/utils/utils.dart'; +import 'package:mc_common_app/view_models/user_view_model.dart'; +import 'package:mc_common_app/widgets/app_bar.dart'; +import 'package:mc_common_app/widgets/button/show_image_button.dart'; + +import 'package:easy_localization/easy_localization.dart'; +import 'package:flutter/material.dart'; +import 'package:provider/provider.dart'; + +class LoginVerificationPage extends StatefulWidget { + const LoginVerificationPage({Key? key}) : super(key: key); + + @override + State createState() => _LoginVerificationPageState(); +} + +class _LoginVerificationPageState extends State { + String userToken = ""; + + late UserVM userVM; + + @override + void initState() { + // TODO: implement initState + super.initState(); + scheduleMicrotask(() async { + userVM = Provider.of(context, listen: false); + userToken = await userVM.performApiCallLoginVerificationPage(context); + }); + } + + @override + Widget build(BuildContext context) { + return Scaffold( + appBar: appBar(context, title: LocaleKeys.login.tr()), + body: Container( + width: double.infinity, + height: double.infinity, + padding: const EdgeInsets.all(40), + child: Column( + children: [ + LocaleKeys.verifyAccount.tr().toText(height: 23 / 24, fontSize: 24, letterSpacing: -1.44,), + Utils.mFlex(2), + Row( + children: [ + Expanded( + child: ShowImageButton( + onClick: () { + userVM.performBasicOtpLoginVerificationPage(context, userToken: userToken); + }, + title: LocaleKeys.fingerPrint.tr(), + icon: icons + "ic_fingerprint.png", + ), + ), + 20.width, + Expanded( + child: ShowImageButton( + onClick: () { + userVM.performBasicOtpLoginVerificationPage(context, userToken: userToken); + }, + title: LocaleKeys.faceRecognition.tr(), + icon: icons + "ic_face_id.png", + ), + ), + ], + ), + 40.height, + Row( + children: [ + Expanded( + child: ShowImageButton( + onClick: () { + userVM.performBasicOtpLoginVerificationPage(context, userToken: userToken); + }, + title: LocaleKeys.SMS.tr(), + icon: icons + "ic_sms.png", + ), + ), + 20.width, + Expanded( + child: ShowImageButton( + onClick: () { + userVM.performBasicOtpLoginVerificationPage(context, userToken: userToken); + }, + title: LocaleKeys.whatsapp.tr(), + icon: icons + "ic_whatsapp.png", + ), + ), + ], + ), + Utils.mFlex(10), + ], + ), + ), + ); + } + +// Future performBasicOtp(BuildContext context) async { +// Utils.showLoading(context); +// String userToken=await SharedPrefManager.getUserToken(); +// Response response = await UserApiClent().login_V2_OTP(userToken, "1"); +// Utils.hideLoading(context); +// if (response.statusCode == 200) { +// String userToken = jsonDecode(response.body)["token"]; +// showMDialog(context, child: OtpDialog( +// onClick: (String code) async { +// pop(context); +// Utils.showLoading(context); +// Response response2 = await UserApiClent().login_V2_OTPVerify(userToken, code); +// Utils.hideLoading(context); +// if (response2.statusCode == 200) { +// User user = User.fromJson(jsonDecode(response2.body)); +// SharedPrefManager.setUserToken(user.data!.accessToken ?? ""); +// SharedPrefManager.setUserId(user.data!.userInfo!.userId ?? ""); +// navigateWithName(context, AppRoutes.dashboard); +// } else { +// Utils.showToast("Something went wrong"); +// } +// }, +// )); +// } else { +// String res = jsonDecode(response.body)["errors"][0] ?? ""; +// Utils.showToast(res); +// } +// } +} diff --git a/lib/views/user/login_verify_account_page.dart b/lib/views/user/login_verify_account_page.dart new file mode 100644 index 0000000..377fa26 --- /dev/null +++ b/lib/views/user/login_verify_account_page.dart @@ -0,0 +1,109 @@ +import 'package:mc_common_app/classes/consts.dart'; +import 'package:mc_common_app/extensions/int_extensions.dart'; +import 'package:mc_common_app/extensions/string_extensions.dart'; +import 'package:mc_common_app/generated/locale_keys.g.dart'; +import 'package:mc_common_app/utils/utils.dart'; +import 'package:mc_common_app/view_models/user_view_model.dart'; +import 'package:mc_common_app/widgets/app_bar.dart'; +import 'package:mc_common_app/widgets/button/show_image_button.dart'; +import 'package:mc_common_app/widgets/txt_field.dart'; +import 'package:easy_localization/easy_localization.dart'; +import 'package:flutter/material.dart'; +import 'package:provider/provider.dart'; + +class LoginVerifyAccountPage extends StatelessWidget { + int otpType = 1; + String phoneNum = ""; + + LoginVerifyAccountPage({Key? key}) : super(key: key); + + @override + Widget build(BuildContext context) { + UserVM userVM = context.read(); + return Scaffold( + appBar: appBar(context,title: LocaleKeys.login.tr()), + body: Container( + width: double.infinity, + height: double.infinity, + padding: const EdgeInsets.all(40), + child: Column( + children: [ + LocaleKeys.verifyAccount.tr().toText(height: 23 / 24, fontSize: 24, letterSpacing: -1.44,), + Utils.mFlex(1), + TxtField( + hint: "966501234567", + value: phoneNum, + onChanged: (v) { + phoneNum = v; + }, + ), + Utils.mFlex(2), + Row( + children: [ + Expanded( + child: ShowImageButton( + onClick: () { + otpType = 1; + userVM.performBasicOtpLoginVerifyAccountPage(context, phoneNum: phoneNum, otpType: otpType); + // showMDialog(context, child: OtpDialog( + // onClick: (String code) { + // pop(context); + // delay(300).then( + // (value) => showMDialog( + // context, + // child: MessageDialog( + // title: "Phone Number Verified", + // onClick: () { + // otpType=1; + // performBasicOtp(context); + // // navigateWithName(context, AppRoutes.completeProfile); + // }, + // ), + // ), + // ); + // }, + // )); + }, + title: LocaleKeys.SMS.tr(), + icon: icons + "ic_sms.png", + ), + ), + 20.width, + Expanded( + child: ShowImageButton( + onClick: () { + otpType = 1; + userVM.performBasicOtpLoginVerifyAccountPage(context, phoneNum: phoneNum, otpType: otpType); + // showMDialog(context, child: OtpDialog( + // onClick: (String code) { + // pop(context); + // delay(300).then( + // (value) => showMDialog( + // context, + // child: MessageDialog( + // title: "Phone Number Verified", + // onClick: () { + // otpType=2; + // performBasicOtp(context); + // // navigateWithName(context, AppRoutes.completeProfile); + // }, + // ), + // ), + // ); + // }, + // )); + }, + title: LocaleKeys.whatsapp.tr(), + icon: icons + "ic_whatsapp.png", + ), + ), + ], + ), + Utils.mFlex(10), + ], + ), + ), + ); + } + +} diff --git a/lib/views/user/login_with_password_page.dart b/lib/views/user/login_with_password_page.dart new file mode 100644 index 0000000..748c397 --- /dev/null +++ b/lib/views/user/login_with_password_page.dart @@ -0,0 +1,154 @@ +import 'dart:async'; + +import 'package:mc_common_app/models/user/country.dart'; +import 'package:mc_common_app/theme/colors.dart'; +import 'package:mc_common_app/config/routes.dart'; +import 'package:mc_common_app/extensions/int_extensions.dart'; +import 'package:mc_common_app/extensions/string_extensions.dart'; +import 'package:mc_common_app/generated/locale_keys.g.dart'; +import 'package:mc_common_app/utils/navigator.dart'; +import 'package:mc_common_app/view_models/user_view_model.dart'; +import 'package:mc_common_app/widgets/app_bar.dart'; +import 'package:mc_common_app/widgets/dropdown/dropdow_field.dart'; +import 'package:mc_common_app/widgets/show_fill_button.dart'; +import 'package:mc_common_app/widgets/tab/login_email_tab.dart'; +import 'package:mc_common_app/widgets/txt_field.dart'; +import 'package:easy_localization/easy_localization.dart'; +import 'package:flutter/material.dart'; +import 'package:provider/provider.dart'; + +class LoginWithPassword extends StatefulWidget { + const LoginWithPassword({Key? key}) : super(key: key); + + @override + State createState() => _LoginWithPasswordState(); +} + +class _LoginWithPasswordState extends State { + int otpType = 1; + + ClassType type = ClassType.EMAIL; + String phoneNum = "", password = ""; + String email = ""; + String countryCode = ""; + Country? _country; + + late UserVM userVM; + + @override + void initState() { + super.initState(); + + scheduleMicrotask(() { + userVM = Provider.of(context, listen: false); + getCountryList(); + }); + } + + getCountryList() async { + _country = await userVM.getAllCountries(); + setState(() {}); + } + + @override + Widget build(BuildContext context) { + return Scaffold( + appBar: appBar(context, title: ""), + body: Container( + width: double.infinity, + height: double.infinity, + padding: const EdgeInsets.all(20), + child: SingleChildScrollView( + child: Column( + children: [ + 12.height, + LocaleKeys.login.tr().toText(fontSize: 20, letterSpacing: -1.44,), + // 20.height, + // (type == ClassType.NUMBER ? LocaleKeys.enterPhoneNumber.tr() : LocaleKeys.enterEmail.tr()).toText14( + // color: MyColors.lightTextColor, + // textAlign: TextAlign.center, + // ), + 30.height, + LoginEmailTab( + onSelection: (ClassType type) { + setState(() { + this.type = type; + }); + }, + ), + 10.height, + Column( + children: [ + if (type == ClassType.NUMBER) getCountry(context), + 10.height, + TxtField( + hint: type == ClassType.NUMBER ? LocaleKeys.enterPhoneNumber.tr() : LocaleKeys.enterEmail.tr(), + value: phoneNum, + isSidePaddingZero: true, + onChanged: (v) { + phoneNum = v; + }, + ), + 10.height, + TxtField( + hint: LocaleKeys.EnterPass.tr(), + value: password, + isPasswordEnabled: true, + isSidePaddingZero: true, + maxLines: 1, + onChanged: (v) { + password = v; + }, + ), + ], + ), + 20.height, + LocaleKeys.forgetPasswordQ.tr().toText( + color: MyColors.textColor, + fontSize: 14, + height: 23 / 24, + letterSpacing: -0.48, + ), + ShowFillButton( + title: LocaleKeys.recover.tr(), + isFlatButton: true, + isBold: false, + fontSize: 14, + maxHeight: 24, + txtColor: MyColors.darkPrimaryColor, + onPressed: () { + navigateWithName(context, AppRoutes.forgetPassword); + }, + ), + 30.height, + ShowFillButton( + title: LocaleKeys.continu.tr(), + maxWidth: double.infinity, + onPressed: () { + userVM.performBasicOtpLoginWithPasswordPage(context, type: type, countryCode: countryCode, phoneNum: phoneNum, password: password); + }, + ), + 20.height, + ], + ), + ), + ), + ); + } + + Widget getCountry(BuildContext context) { + if (_country != null) { + List dropList = []; + _country!.data?.forEach((element) { + dropList.add(DropValue(element.id ?? 0, (element.countryName ?? "") + " " + (element.countryCode ?? ""), element.countryCode ?? "")); + }); + return DropdownField((DropValue value) { + countryCode = value.subValue; + }, list: dropList, hint: LocaleKeys.selectCountryCode.tr()); + } else { + return const Center( + child: CircularProgressIndicator(), + ); + } + } +} diff --git a/lib/views/user/register_page.dart b/lib/views/user/register_page.dart new file mode 100644 index 0000000..b6be23f --- /dev/null +++ b/lib/views/user/register_page.dart @@ -0,0 +1,185 @@ +import 'package:mc_common_app/extensions/int_extensions.dart'; +import 'package:mc_common_app/extensions/string_extensions.dart'; +import 'package:mc_common_app/generated/locale_keys.g.dart'; +import 'package:mc_common_app/models/user/country.dart'; +import 'package:mc_common_app/utils/utils.dart'; +import 'package:mc_common_app/view_models/user_view_model.dart'; +import 'package:mc_common_app/widgets/app_bar.dart'; +import 'package:mc_common_app/widgets/dropdown/dropdow_field.dart'; +import 'package:mc_common_app/widgets/show_fill_button.dart'; +import 'package:easy_localization/easy_localization.dart'; +import 'package:flutter/material.dart'; +import 'package:provider/provider.dart'; +import '../../theme/colors.dart'; + +class RegisterPage extends StatefulWidget { + const RegisterPage({Key? key}) : super(key: key); + + @override + State createState() => _RegisterPageState(); +} + +class _RegisterPageState extends State { + String phoneNum = "", countryCode = ""; + + int role = 4, countryId = -1; + + TextEditingController emailController = TextEditingController(); + + @override + Widget build(BuildContext context) { + final UserVM userVM = context.read(); + return Scaffold( + appBar: appBar(context, title: ""), + body: Container( + width: double.infinity, + height: double.infinity, + padding: const EdgeInsets.all(20), + child: SingleChildScrollView( + child: SizedBox( + height: MediaQuery.of(context).size.height, + child: Column( + children: [ + 12.height, + LocaleKeys.signUp.tr().toText(fontSize: 20, letterSpacing: -1.44,), + 20.height, + LocaleKeys.enterPhoneNumber.tr().toText( + color: MyColors.lightTextColor, + textAlign: TextAlign.center, + fontSize: 14, + height: 23 / 24, + letterSpacing: -0.48, + ), + 30.height, + FutureBuilder( + future: userVM.getAllCountries(), + builder: (context, snapshot) { + if (snapshot.hasData) { + List dropList = []; + snapshot.data?.data?.forEach((element) { + dropList.add(DropValue( + element.id ?? 0, + EasyLocalization.of(context)?.currentLocale?.countryCode == "SA" + ? (element.countryNameN ?? "") + " " + (element.countryCode ?? "") + : (element.countryName ?? "") + " " + (element.countryCode ?? ""), + element.countryCode ?? "")); + }); + return Column( + children: [ + LocaleKeys.selectYourCountry.tr().toText( + color: MyColors.lightTextColor, + textAlign: TextAlign.center, + fontSize: 14, + height: 23 / 24, + letterSpacing: -0.48, + ), + 10.height, + DropdownField( + (DropValue value) { + setState(() { + countryCode = value.subValue; + countryId = value.id; + }); + }, + list: dropList, + hint: LocaleKeys.chooseCountry.tr(), + ), + ], + ); + } else { + return const CircularProgressIndicator(); + } + }, + ), + 18.height, + LocaleKeys.enterPhoneForVerfication.tr().toText( + color: MyColors.lightTextColor, + textAlign: TextAlign.center, + fontSize: 14, + height: 23 / 24, + letterSpacing: -0.48, + ), + 10.height, + Row( + mainAxisAlignment: MainAxisAlignment.center, + crossAxisAlignment: CrossAxisAlignment.center, + children: [ + Utils.mExp(1), + Expanded( + flex: 3, + child: Row( + children: [ + Text( + (countryCode.isEmpty ? "+00" : "+" + countryCode), + style: const TextStyle( + fontSize: 20, + color: MyColors.black, + fontWeight: FontWeight.bold, + ), + ), + const Text( + " | ", + style: TextStyle( + fontSize: 20, + color: MyColors.black, + fontWeight: FontWeight.bold, + ), + ), + Flexible( + child: TextField( + controller: emailController, + onChanged: (v) { + phoneNum = v; + }, + style: const TextStyle( + fontSize: 20, + color: MyColors.black, + ), + decoration: const InputDecoration( + hintStyle: TextStyle(color: MyColors.lightTextColor, fontSize: 20), + hintText: "546758594", + contentPadding: EdgeInsets.zero, + border: InputBorder.none, + ), + ), + ), + ], + ), + ), + Utils.mExp(1), + ], + ), + 40.height, + ShowFillButton( + title: LocaleKeys.continu.tr(), + maxWidth: double.infinity, + onPressed: () { + if (validation()) userVM.performBasicOtpRegisterPage(context, countryCode: countryCode, phoneNum: phoneNum, role: role); + }, + ), + ], + ), + ), + ), + ), + ); + } + + bool validation() { + bool isValid = true; + if (role == -1) { + Utils.showToast(LocaleKeys.selectProviderRole.tr()); + //("Please select Provider Role"); + isValid = false; + } else if (countryCode.isEmpty) { + Utils.showToast(LocaleKeys.selectCountryCode.tr()); + //("Please select Country Code"); + isValid = false; + } else if (phoneNum.isEmpty) { + Utils.showToast(LocaleKeys.addPhoneNo.tr()); + //("Please add Phone No"); + isValid = false; + } + return isValid; + } +} diff --git a/lib/views/user/register_selection_page.dart b/lib/views/user/register_selection_page.dart new file mode 100644 index 0000000..4293036 --- /dev/null +++ b/lib/views/user/register_selection_page.dart @@ -0,0 +1,83 @@ +import 'package:mc_common_app/config/routes.dart'; +import 'package:mc_common_app/extensions/int_extensions.dart'; +import 'package:mc_common_app/extensions/string_extensions.dart'; +import 'package:mc_common_app/generated/locale_keys.g.dart'; +import 'package:mc_common_app/utils/navigator.dart'; +import 'package:mc_common_app/utils/utils.dart'; +import 'package:mc_common_app/widgets/show_fill_button.dart'; +import 'package:easy_localization/easy_localization.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter_svg/flutter_svg.dart'; + +import '../../theme/colors.dart'; + +class RegisterSelectionPage extends StatelessWidget { + const RegisterSelectionPage({Key? key}) : super(key: key); + + @override + Widget build(BuildContext context) { + return Scaffold( + // appBar: appBar(title: LocaleKeys.login.tr()), + body: Container( + width: double.infinity, + height: double.infinity, + decoration: const BoxDecoration( + image: DecorationImage( + image: AssetImage("assets/images/bn_Intro.png"), + fit: BoxFit.cover, + ), + ), + child: Column( + children: [ + Utils.mFlex(6), + SvgPicture.asset("assets/images/logo.svg"), + Utils.mFlex(4), + LocaleKeys.welcomeMessage.tr().toText( + fontSize: 20, + letterSpacing: -1.44, + ), + LocaleKeys.welcomeDes.tr().toText( + color: MyColors.lightTextColor, + fontSize: 14, + height: 23 / 24, + letterSpacing: -0.48, + ), + Utils.mFlex(1), + ShowFillButton( + title: LocaleKeys.login.tr(), + maxWidth: double.infinity, + horizontalMargin: 20, + onPressed: () { + navigateWithName(context, AppRoutes.loginWithPassword); + }, + ), + 20.height, + ShowFillButton( + title: LocaleKeys.signUp.tr(), + maxWidth: double.infinity, + isFlatButton: true, + txtColor: Colors.black, + onPressed: () { + navigateWithName(context, AppRoutes.register); + }, + ), + 10.height, + Utils.mFlex(3), + TextButton( + onPressed: () {}, + child: const Text( + "Continue as Guest", + style: TextStyle( + color: MyColors.darkPrimaryColor, + fontWeight: FontWeight.bold, + decoration: TextDecoration.underline, + ), + ), + ), + Utils.mFlex(3), + ], + ), + ), + ); + } +} diff --git a/lib/views/user/vertify_password_page.dart b/lib/views/user/vertify_password_page.dart new file mode 100644 index 0000000..59ee590 --- /dev/null +++ b/lib/views/user/vertify_password_page.dart @@ -0,0 +1,155 @@ +import 'package:mc_common_app/classes/consts.dart'; +import 'package:mc_common_app/config/routes.dart'; +import 'package:mc_common_app/extensions/int_extensions.dart'; +import 'package:mc_common_app/extensions/string_extensions.dart'; +import 'package:mc_common_app/generated/locale_keys.g.dart'; +import 'package:mc_common_app/utils/navigator.dart'; +import 'package:mc_common_app/utils/utils.dart'; +import 'package:mc_common_app/widgets/app_bar.dart'; +import 'package:mc_common_app/widgets/button/show_image_button.dart'; +import 'package:mc_common_app/widgets/dialog/dialogs.dart'; +import 'package:mc_common_app/widgets/dialog/message_dialog.dart'; +import 'package:mc_common_app/widgets/dialog/otp_dialog.dart'; +import 'package:mc_common_app/widgets/txt_field.dart'; +import 'package:easy_localization/easy_localization.dart'; +import 'package:flutter/material.dart'; + +class VerifyPasswordPage extends StatelessWidget { + int otpType = 1; + String phoneNum = ""; + String userName = ""; + String userToken = ""; + String otp = ""; + + VerifyPasswordPage({Key? key}) : super(key: key); + + @override + Widget build(BuildContext context) { + return Scaffold( + appBar: appBar(context, title: LocaleKeys.changePassword.tr()), + body: Container( + width: double.infinity, + height: double.infinity, + padding: const EdgeInsets.all(40), + child: Column( + children: [ + LocaleKeys.verifyNewPassword.tr().toText(height: 23 / 24, fontSize: 24, letterSpacing: -1.44,), + Utils.mFlex(1), + TxtField( + hint: "966500000000", + value: phoneNum, + onChanged: (v) { + phoneNum = v; + }, + ), + Utils.mFlex(2), + Row( + children: [ + Expanded( + child: ShowImageButton( + onClick: () { + otpType = 1; + // sendPasswordOTP(context); + showMDialog(context, child: OtpDialog( + onClick: (String code) { + pop(context); + Utils.delay(300).then( + (value) => showMDialog( + context, + child: MessageDialog( + title: LocaleKeys.phoneNumberVerified.tr(), + onClick: () { + otpType = 1; + navigateWithName(context, AppRoutes.confirmNewPasswordPage); + // ForgetPasswordOTP(context); + }, + ), + ), + ); + }, + )); + }, + title: LocaleKeys.SMS.tr(), + icon: icons + "ic_sms.png", + ), + ), + 20.width, + Expanded( + child: ShowImageButton( + onClick: () { + otpType = 1; + // sendPasswordOTP(context); + showMDialog(context, child: OtpDialog( + onClick: (String code) { + pop(context); + Utils.delay(300).then( + (value) => showMDialog( + context, + child: MessageDialog( + title: LocaleKeys.phoneNumberVerified.tr(), + //"Phone Number Verified ", + onClick: () { + otpType = 2; + navigateWithName(context, AppRoutes.confirmNewPasswordPage); + // ForgetPasswordOTP(context); + }, + ), + ), + ); + }, + )); + }, + title: LocaleKeys.whatsapp.tr(), + icon: icons + "ic_whatsapp.png", + ), + ), + ], + ), + Utils.mFlex(10), + ], + ), + ), + ); + } + +// Future sendPasswordOTP(BuildContext context) async { +// Utils.showLoading(context); +// PasswordOTPCompare otpCompare = await UserApiClent().ForgetPasswordOTPCompare(userToken, otp); +// Utils.hideLoading(context); +// if (otpCompare.messageStatus == 1) { +// // navigateWithName(context, AppRoutes.confirmNewPasswordPage); +// showMDialog(context, child: OtpDialog( +// onClick: (String code) async { +// pop(context); +// Utils.showLoading(context); +// // PasswordOTPCompare otpCompare = await UserApiClent().ForgetPasswordOTPCompare(userToken, otp); +// Utils.hideLoading(context); +// }, +// )); +// } else { +// Utils.showToast(otpCompare.message ?? ""); +// } +// } + +// User otpRequest = User.fromJson(jsonDecode(res.body)); +// SharedPrefManager.setUserToken(otpRequest.data!.accessToken ?? ""); +// SharedPrefManager.setUserId(otpRequest.data!.userInfo!.userId ?? ""); +// showMDialog(context, child: OtpDialog( +// onClick: (String code) { +// pop(context); +// delay(300).then( +// (value) => showMDialog( +// context, +// child: MessageDialog( +// title: "Phone Number Verified", +// onClick: () { +// otpType=1; +// navigateWithName(context, AppRoutes.confirmNewPasswordPage); +// // ForgetPasswordOTP(context); +// }, +// ), +// ), +// ); +// }, +// )); +} diff --git a/lib/widgets/app_bar.dart b/lib/widgets/app_bar.dart new file mode 100644 index 0000000..9935442 --- /dev/null +++ b/lib/widgets/app_bar.dart @@ -0,0 +1,33 @@ + +import 'package:flutter/material.dart'; +import 'package:mc_common_app/extensions/string_extensions.dart'; +import 'package:mc_common_app/theme/colors.dart'; + +AppBar appBar( + BuildContext context, { + Color? backgroundColor, + double? elevation, + String? title, + Color? titleColor, + bool? isTitleCenter, + Color? backIconColor, + List? actions, + bool isRemoveBackButton = false, + }) { + return AppBar( + backgroundColor: backgroundColor ?? appBackgroundColor, + elevation: elevation ?? 0, + centerTitle: isTitleCenter ?? true, + leading: isRemoveBackButton + ? null + : IconButton( + icon: Icon(Icons.arrow_back_ios, color: Colors.black), + onPressed: () => Navigator.of(context).pop(), + ), + iconTheme: IconThemeData( + color: backIconColor ?? Colors.black, //change your color here + ), + actions: actions, + title: (title ?? "").toText(fontSize: 20, isBold: true), + ); +} diff --git a/lib/widgets/blurry_container.dart b/lib/widgets/blurry_container.dart new file mode 100644 index 0000000..8bebc4a --- /dev/null +++ b/lib/widgets/blurry_container.dart @@ -0,0 +1,62 @@ +import 'dart:ui'; + +import 'package:flutter/material.dart'; + +const kDemoText = Center( + child: Text( + '', + style: TextStyle( + fontSize: 25, + color: Colors.white, + letterSpacing: 2, + ), + textAlign: TextAlign.center, + ), +); +const double kBlur = 1.0; +const EdgeInsetsGeometry kDefaultPadding = EdgeInsets.all(16); +const Color kDefaultColor = Colors.transparent; +const BorderRadius kBorderRadius = BorderRadius.all(Radius.circular(20)); +const double kColorOpacity = 0.0; + +class BlurryContainer extends StatelessWidget { + final Widget child; + final double blur; + final double? height, width; + final EdgeInsetsGeometry padding; + final Color bgColor; + + final BorderRadius borderRadius; + + //final double colorOpacity; + + BlurryContainer({ + this.child = kDemoText, + this.blur = 5, + required this.height, + required this.width, + this.padding = kDefaultPadding, + this.bgColor = kDefaultColor, + this.borderRadius = kBorderRadius, + //this.colorOpacity = kColorOpacity, + }); + + @override + Widget build(BuildContext context) { + return ClipRRect( + borderRadius: borderRadius, + child: BackdropFilter( + filter: ImageFilter.blur(sigmaX: blur, sigmaY: blur), + child: Container( + height: height!, + width: width!, + padding: padding, + color: bgColor == Colors.transparent + ? bgColor + : bgColor.withOpacity(0.5), + child: child, + ), + ), + ); + } +} diff --git a/lib/widgets/button/show_circular_button.dart b/lib/widgets/button/show_circular_button.dart new file mode 100644 index 0000000..34e2e4e --- /dev/null +++ b/lib/widgets/button/show_circular_button.dart @@ -0,0 +1,24 @@ + +import 'package:flutter/material.dart'; +import 'package:mc_common_app/utils/utils.dart'; + +class ShowCircularButton extends StatelessWidget { + VoidCallback onPressed; + IconData? iconData; + ShowCircularButton({Key? key, this.iconData,required this.onPressed}) : super(key: key); + @override + Widget build(BuildContext context) { + return Card( + shape: Utils.cardRadius(1000), + color: Colors.black.withOpacity(0.2), + margin: const EdgeInsets.all(12), + child: IconButton( + onPressed: onPressed, + icon: Icon( + iconData?? Icons.amp_stories_outlined, + color: Colors.white, + ), + ), + ); + } +} diff --git a/lib/widgets/button/show_image_button.dart b/lib/widgets/button/show_image_button.dart new file mode 100644 index 0000000..fd96809 --- /dev/null +++ b/lib/widgets/button/show_image_button.dart @@ -0,0 +1,48 @@ + +import 'package:flutter/material.dart'; +import 'package:flutter_svg/flutter_svg.dart'; +import 'package:mc_common_app/extensions/int_extensions.dart'; +import 'package:mc_common_app/extensions/string_extensions.dart'; + +import '../../theme/colors.dart'; + +class ShowImageButton extends StatelessWidget { + String icon, title; + VoidCallback onClick; + + ShowImageButton({required this.icon, required this.title, required this.onClick}); + + @override + Widget build(BuildContext context) { + return InkWell( + onTap: onClick, + child: Container( + width: double.infinity, + child: Column( + children: [ + Container( + width: double.infinity, + height: 120, + child: Card( + color: MyColors.darkPrimaryColor, + shape: RoundedRectangleBorder( + side: BorderSide(color: Colors.transparent, width: 1), + borderRadius: BorderRadius.circular(8), + ), + child: Padding( + padding: EdgeInsets.all(26), + child: SvgPicture.asset( + icon, + color: Colors.white, + ), + ), + ), + ), + 6.height, + title.toText(color: Colors.black, isBold: true, fontSize: 16), + ], + ), + ), + ); + } +} diff --git a/lib/widgets/count_down_timer.dart b/lib/widgets/count_down_timer.dart new file mode 100644 index 0000000..3817e3c --- /dev/null +++ b/lib/widgets/count_down_timer.dart @@ -0,0 +1,108 @@ +import 'package:flutter/material.dart'; + +class CountDownTimer extends StatefulWidget { + const CountDownTimer({ + Key? key, + int? secondsRemaining, + this.countDownTimerStyle, + this.whenTimeExpires, + this.countDownFormatter, + }) + : secondsRemaining = secondsRemaining, + super(key: key); + + final int? secondsRemaining; + final Function? whenTimeExpires; + final Function? countDownFormatter; + final TextStyle ?countDownTimerStyle; + + State createState() => new _CountDownTimerState(); +} + +class _CountDownTimerState extends State + with TickerProviderStateMixin { + late AnimationController _controller; + late Duration duration; + + String get timerDisplayString { + Duration duration = _controller.duration! * _controller.value; + return widget.countDownFormatter != null + ? widget.countDownFormatter!(duration.inSeconds) + : formatHHMMSS(duration.inSeconds); + // In case user doesn't provide formatter use the default one + // for that create a method which will be called formatHHMMSS or whatever you like + } + + @override + void initState() { + super.initState(); + duration = new Duration(seconds: widget.secondsRemaining ?? 0); + _controller = new AnimationController( + vsync: this, + duration: duration, + ); + _controller.reverse(from: widget.secondsRemaining!.toDouble()); + _controller.addStatusListener((status) { + if (status == AnimationStatus.completed || status == AnimationStatus.dismissed) { + widget.whenTimeExpires!(); + } + }); + } + + @override + void didUpdateWidget(CountDownTimer oldWidget) { + if (widget.secondsRemaining != oldWidget.secondsRemaining) { + setState(() { + duration = new Duration(seconds: widget.secondsRemaining ?? 0); + _controller.dispose(); + _controller = new AnimationController( + vsync: this, + duration: duration, + ); + _controller.reverse(from: widget.secondsRemaining?.toDouble()); + _controller.addStatusListener((status) { + if (status == AnimationStatus.completed) { + widget.whenTimeExpires!(); + } else if (status == AnimationStatus.dismissed) { + print("Animation Complete"); + } + }); + }); + } + } + + @override + void dispose() { + _controller.dispose(); + super.dispose(); + } + + @override + Widget build(BuildContext context) { + return new Center( + child: AnimatedBuilder( + animation: _controller, + builder: (_, Widget? child) { + return Text( + timerDisplayString ??"", + style: widget.countDownTimerStyle, + ); + }),); + } +} + +String formatHHMMSS(int seconds) { + int hours = (seconds / 3600).truncate(); + seconds = (seconds % 3600).truncate(); + int minutes = (seconds / 60).truncate(); + + String hoursStr = (hours).toString().padLeft(2, '0'); + String minutesStr = (minutes).toString().padLeft(2, '0'); + String secondsStr = (seconds % 60).toString().padLeft(2, '0'); + + if (hours == 0) { + return "$minutesStr:$secondsStr"; + } + + return "$hoursStr:$minutesStr:$secondsStr"; +} \ No newline at end of file diff --git a/lib/widgets/dialog/dialogs.dart b/lib/widgets/dialog/dialogs.dart new file mode 100644 index 0000000..9a5a822 --- /dev/null +++ b/lib/widgets/dialog/dialogs.dart @@ -0,0 +1,16 @@ +import 'package:flutter/material.dart'; + +void showMDialog( + context, { + Widget? child, +}) async { + return showDialog( + context: context, + barrierDismissible: true, + builder: (context) { + return Dialog( + child: child, + ); + }, + ); +} diff --git a/lib/widgets/dialog/message_dialog.dart b/lib/widgets/dialog/message_dialog.dart new file mode 100644 index 0000000..f25c700 --- /dev/null +++ b/lib/widgets/dialog/message_dialog.dart @@ -0,0 +1,35 @@ + +import 'package:flutter/material.dart'; +import 'package:mc_common_app/extensions/int_extensions.dart'; +import 'package:mc_common_app/extensions/string_extensions.dart'; +import 'package:mc_common_app/widgets/show_fill_button.dart'; + +class MessageDialog extends StatelessWidget { + String? title, buttonTitle; + VoidCallback? onClick; + + MessageDialog({this.title, this.buttonTitle, this.onClick}); + + @override + Widget build(BuildContext context) { + return Container( + color: Colors.white, + padding: EdgeInsets.all(30), + child: Column( + mainAxisSize: MainAxisSize.min, + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + (title ?? "message").toText(height: 23 / 24, fontSize: 24, letterSpacing: -1.44,), + 40.height, + ShowFillButton( + title: buttonTitle ?? "Continue", + maxWidth: double.infinity, + onPressed: () { + onClick!(); + }, + ) + ], + ), + ); + } +} diff --git a/lib/widgets/dialog/otp_dialog.dart b/lib/widgets/dialog/otp_dialog.dart new file mode 100644 index 0000000..9a4f898 --- /dev/null +++ b/lib/widgets/dialog/otp_dialog.dart @@ -0,0 +1,134 @@ + +import 'package:easy_localization/easy_localization.dart'; +import 'package:flutter/material.dart'; +import 'package:mc_common_app/extensions/int_extensions.dart'; +import 'package:mc_common_app/extensions/string_extensions.dart'; +import 'package:mc_common_app/generated/locale_keys.g.dart'; +import 'package:mc_common_app/theme/colors.dart'; +import 'package:mc_common_app/widgets/count_down_timer.dart'; +import 'package:mc_common_app/widgets/show_fill_button.dart'; + +import '../otp_widget.dart'; + +class OtpDialog extends StatefulWidget { + String? userName; + Function(String) onClick; + + OtpDialog({Key? key, required this.onClick, this.userName}) : super(key: key); + + @override + State createState() => _OtpDialogState(); +} + +class _OtpDialogState extends State { + String code = ""; + bool hasTimerStopped = false; + + final TextEditingController _pinPutController = TextEditingController(); + + @override + Widget build(BuildContext context) { + return Container( + color: Colors.white, + padding: const EdgeInsets.all(24), + width: double.infinity, + child: Column( + mainAxisSize: MainAxisSize.min, + crossAxisAlignment: CrossAxisAlignment.center, + mainAxisAlignment: MainAxisAlignment.center, + children: [ + LocaleKeys.insert_otp_code.tr().toText( + height: 23 / 24, + fontSize: 24, + letterSpacing: -1.44, + ), + 8.height, + LocaleKeys.type_code.tr().toText(color: MyColors.textColor, fontSize: 12), + if (widget.userName != null) + (widget.userName ?? "").toText( + color: MyColors.darkPrimaryColor, + fontSize: 12, + ), + 20.height, + Center( + child: OTPWidget( + autoFocus: true, + controller: _pinPutController, + defaultBorderColor: const Color(0xffD8D8D8), + maxLength: 4, + onTextChanged: (text) {}, + pinBoxColor: Colors.white, + onDone: (code) => _onOtpCallBack(code, null), + textBorderColor: MyColors.darkPrimaryColor, + pinBoxWidth: 48, + pinBoxHeight: 48, + pinTextStyle: const TextStyle(fontSize: 24.0, color: MyColors.darkTextColor), + pinTextAnimatedSwitcherTransition: ProvidedPinBoxTextAnimation.scalingTransition, + pinTextAnimatedSwitcherDuration: const Duration(milliseconds: 300), + pinBoxRadius: 0, + keyboardType: TextInputType.number, + ), + ), + 40.height, + ShowFillButton( + title: LocaleKeys.check_code.tr(), + maxWidth: double.infinity, + onPressed: () { + widget.onClick(code); + }, + ), + if (!hasTimerStopped) + Padding( + padding: const EdgeInsets.all(12.0), + child: Row( + crossAxisAlignment: CrossAxisAlignment.center, + mainAxisAlignment: MainAxisAlignment.center, + children: [ + Text(LocaleKeys.time_will_expire.tr() + " "), + CountDownTimer( + secondsRemaining: 60, + whenTimeExpires: () { + setState(() { + hasTimerStopped = true; + }); + }, + countDownTimerStyle: const TextStyle( + color: Colors.blue, + height: 1.2, + ), + ), + Text(" " + LocaleKeys.sec.tr()), + ], + ), + ), + if (hasTimerStopped) + InkWell( + onTap: () { + setState(() { + hasTimerStopped = false; + }); + }, + child: Padding( + padding: const EdgeInsets.all(12.0), + child: Text( + LocaleKeys.resend_code.tr(), + style: const TextStyle( + decoration: TextDecoration.underline, + fontWeight: FontWeight.bold, + color: Colors.blue, + ), + ), + ), + ), + ], + ), + ); + } + + _onOtpCallBack(String otpCode, bool? isAutofill) { + if (otpCode.length == 4) { + // onSuccess(otpCode); + code = otpCode; + } + } +} diff --git a/lib/widgets/dragable_sheet.dart b/lib/widgets/dragable_sheet.dart new file mode 100644 index 0000000..86d468a --- /dev/null +++ b/lib/widgets/dragable_sheet.dart @@ -0,0 +1,25 @@ +import 'package:flutter/material.dart'; + +showDraggableDialog(BuildContext context, Widget child) { + showGeneralDialog( + barrierLabel: "Label", + barrierDismissible: false, + barrierColor: Colors.black.withOpacity(0.2), + transitionDuration: Duration(milliseconds: 200), + context: context, + pageBuilder: (context, anim1, anim2) { + return Dismissible( + direction: DismissDirection.vertical, + key: const Key('key'), + onDismissed: (_) => Navigator.of(context).pop(), + child: child, + ); + }, + transitionBuilder: (context, anim1, anim2, child) { + return SlideTransition( + position: Tween(begin: Offset(0, 1), end: Offset(0, 0)).animate(anim1), + child: child, + ); + }, + ); +} diff --git a/lib/widgets/dropdown/dropdow_field.dart b/lib/widgets/dropdown/dropdow_field.dart new file mode 100644 index 0000000..4692159 --- /dev/null +++ b/lib/widgets/dropdown/dropdow_field.dart @@ -0,0 +1,84 @@ + +import 'package:flutter/material.dart'; +import 'package:mc_common_app/extensions/string_extensions.dart'; +import 'package:mc_common_app/theme/colors.dart'; +import 'package:mc_common_app/utils/utils.dart'; + + +class DropValue { + int id; + String value; + String subValue; + + DropValue(this.id, this.value, this.subValue); + + bool operator ==(o) => o is DropValue && o.value == value && o.id == id; +} + +class DropdownField extends StatefulWidget { + String? hint; + List? list; + DropValue? dropdownValue; + Function(DropValue) onSelect; + + DropdownField(this.onSelect, {Key? key, this.hint, this.list,this.dropdownValue}) : super(key: key); + + @override + State createState() => _DropdownFieldState(); +} + +class _DropdownFieldState extends State { + DropValue? dropdownValue; + List defaultV = [ + DropValue(1, "One", ""), + DropValue(2, "Two", ""), + ]; + + @override + void initState() { + super.initState(); + dropdownValue = widget.dropdownValue; + } + + @override + Widget build(BuildContext context) { + return Container( + decoration: Utils.containerColorRadiusBorderWidth( + MyColors.white, + 0, + MyColors.darkPrimaryColor, + 2, + ), + margin: const EdgeInsets.all(0), + padding: const EdgeInsets.only(left: 8, right: 8), + child: DropdownButton( + value: dropdownValue, + icon: const Icon(Icons.keyboard_arrow_down_sharp), + elevation: 16, + iconSize: 16, + iconEnabledColor: borderColor, + iconDisabledColor: borderColor, + isExpanded: true, + style: const TextStyle(color: Colors.black, fontWeight: FontWeight.w600), + hint: (widget.hint ?? "").toText(color: borderColor, fontSize: 12), + underline: Container( + height: 0, + ), + onChanged: (DropValue? newValue) { + setState(() { + dropdownValue = newValue!; + widget.onSelect(newValue); + }); + }, + items: (widget.list ?? defaultV).map>( + (DropValue value) { + return DropdownMenuItem( + value: value, + child: value.value.toText(fontSize: 12), + ); + }, + ).toList(), + ), + ); + } +} diff --git a/lib/widgets/dropdown/dropdown_text.dart b/lib/widgets/dropdown/dropdown_text.dart new file mode 100644 index 0000000..bcf476d --- /dev/null +++ b/lib/widgets/dropdown/dropdown_text.dart @@ -0,0 +1,29 @@ + +import 'package:flutter/material.dart'; +import 'package:flutter_svg/flutter_svg.dart'; +import 'package:mc_common_app/extensions/int_extensions.dart'; +import 'package:mc_common_app/extensions/string_extensions.dart'; +import 'package:mc_common_app/theme/colors.dart'; + +class DropDownText extends StatelessWidget { + String title; + + DropDownText(this.title); + + @override + Widget build(BuildContext context) { + return Row( + crossAxisAlignment: CrossAxisAlignment.center, + mainAxisAlignment: MainAxisAlignment.center, + children: [ + title.toText(color: accentColor, fontSize: 16, letterSpacing: -0.64,), + 16.height, + SvgPicture.asset( + "assets/ic_arrow_down.svg", + width: 10, + height: 10, + ), + ], + ); + } +} diff --git a/lib/widgets/extensions/extensions_widget.dart b/lib/widgets/extensions/extensions_widget.dart new file mode 100644 index 0000000..c046072 --- /dev/null +++ b/lib/widgets/extensions/extensions_widget.dart @@ -0,0 +1,233 @@ +import 'package:flutter/material.dart'; + +extension ExtendedText on Widget { + showOverlay({double? width, double? height}){ + return Container( + width: width ?? double.infinity, + height: height ?? 60, + decoration: BoxDecoration( + gradient: LinearGradient(colors: [ + Colors.black.withOpacity(0.2), + Colors.black.withOpacity(0.1), + Colors.black.withOpacity(0.004), + ], begin: Alignment.topCenter, end: Alignment.bottomCenter, tileMode: TileMode.clamp), + ), + child: this, + ); + } +} + + + + + +extension ImageExt on Image { + Widget circular() { + return ClipRRect( + clipBehavior: Clip.hardEdge, + borderRadius: BorderRadius.circular(100), + child: this, + ); + } +} + +extension WidgetExt on Widget { + Widget toWidget() { + return this as Widget; + } + + Widget sized({double? width, double? height}) { + return SizedBox( + width: width, + height: height, + child: this, + ); + } + Widget inkWell({required VoidCallback onTap,double radius=0}){ + return InkWell( + child: Material(child: this,color: Colors.transparent,), + onTap: onTap, + ); + } + Widget sizeSq(double size) { + return SizedBox( + width: size, + height: size, + child: this, + ); + } + + Widget fillParent({double hFactor = 1, double? vFactor}) { + return FractionallySizedBox( + heightFactor: null, + widthFactor: hFactor, + child: this, + ); + } + + Widget margin( + {double top = 0, double bottom = 0, double left = 0, double right = 0}) { + var pad = + EdgeInsets.only(top: top, left: left, bottom: bottom, right: right); + try { + (this as dynamic).margin = pad; + } catch (err) { + return Padding( + padding: pad, + child: this, + ); + } + return this; + } + + Widget toClip({double r = 40}) { + return ClipRRect( + borderRadius: BorderRadius.all( + Radius.circular(r), + ), + clipBehavior: Clip.antiAlias, + child: this, + ); + } + + // Widget scrollable({Axis? direction, bool fadingEdge = true}) { + // var scrollview = SingleChildScrollView( + // child: this, + // controller: ScrollController(), + // scrollDirection: direction ?? Axis.vertical, + // ); + // return fadingEdge ? scrollview.fadingEdge() : scrollview; + // } + + Widget expand() { + return Expanded( + child: this, + ); + } + + Widget align(Alignment alignment) { + return Align( + alignment: alignment, + child: this, + ); + } + + Widget center() { + return Center( + child: this, + ); + } + + Widget padding(EdgeInsets padding) { + return Padding( + padding: padding, + child: this, + ); + } + + Widget paddingAll(double padding) { + return Padding( + padding: EdgeInsets.all(padding), + child: this, + ); + } + + // Widget onTap(VoidCallback onTap, {double corners = 0}) { + // return Clickable.widget(child: this, corners: corners, onTap: onTap); + // } + + Widget ignoreInteraction() { + return IgnorePointer( + child: this, + ); + } +} + +// extension xScrollView on ScrollView { +// Widget fadingEdge() => FadingEdgeScrollView.fromScrollView( +// child: this, +// gradientFractionOnEnd: 0.08, +// gradientFractionOnStart: 0.08, +// shouldDisposeScrollController: true, +// ); +// } +// +// extension x2ScrollView on SingleChildScrollView { +// Widget fadingEdge() => FadingEdgeScrollView.fromSingleChildScrollView( +// child: this, +// gradientFractionOnEnd: 0.08, +// gradientFractionOnStart: 0.08, +// shouldDisposeScrollController: true, +// ); +// } + +class Position { + final double x, y, w, h; + + Position(this.x, this.y, this.w, this.h); +} + +extension KeyExt on GlobalKey { + Position globalPosition() { + RenderBox box = currentContext!.findRenderObject() as RenderBox; + Offset xy = box.localToGlobal(Offset.zero); + Size wh = box.size; + return Position(xy.dx, xy.dy, wh.width, wh.height); + } +} + +extension StateExt on State { + reload({VoidCallback? b}) { + setState(b ?? () {}); + } +} + +// extension LocatiionExt on Location { +// LatLng toLatLng() { +// return LatLng(lat!, lng!); +// } +// } + +// extension xList on List { +// T randomItem() { +// final random = new Random(); +// var i = random.nextInt(this.length); +// return this[i]; +// } +// +// List append(List items) { +// this.addAll(items); +// return this; +// } +// +// bool isFirst(T item) => first == item; +// +// bool isLast(T item) => last == item; +// +// getOneByOne( +// {required int delayMillis, +// required Function(T) callback, VoidCallback? complete}) async { +// for (var i in this) { +// await delay(delayMillis); +// callback(i); +// } +// complete!(); +// } +// } + +extension xFuture on Future { + thenWithDelay(int millis, Function(T) thenBlock) { + then((value) { + Future.delayed(Duration(milliseconds: millis)) + .then((value) => thenBlock(value)); + }); + } +} + +extension xDouble on int { + Duration durationMillis() => Duration(milliseconds: this); + + Duration durationSec() => Duration(seconds: this); + + Duration durationHour() => Duration(hours: this); +} diff --git a/lib/widgets/gradient_app_bar.dart b/lib/widgets/gradient_app_bar.dart new file mode 100644 index 0000000..c3ded30 --- /dev/null +++ b/lib/widgets/gradient_app_bar.dart @@ -0,0 +1,63 @@ +import 'package:flutter/material.dart'; + +class GradientAppBar extends StatelessWidget { + final String title; + final double barHeight = 50.0; + IconData? iconData; + + GradientAppBar(this.title, {this.iconData}); + + @override + Widget build(BuildContext context) { + final double statusbarHeight = MediaQuery.of(context).padding.top; + + return new Container( + padding: EdgeInsets.only(top: statusbarHeight), + height: statusbarHeight + barHeight, + child: Row( + children: [ + IconButton( + onPressed: () { + Navigator.pop(context); + }, + icon: Icon( + Icons.arrow_back_ios, + color: Colors.white, + ), + ), + Expanded( + child: Center( + child: Text( + title, + style: TextStyle( + fontSize: 20.0, + color: Colors.white, + fontWeight: FontWeight.bold), + ), + ), + ), + if (iconData != null) + IconButton( + onPressed: () {}, + icon: Icon( + iconData, + color: Colors.white, + ), + ), + ], + ), + decoration: BoxDecoration( + gradient: LinearGradient( + colors: [ + Colors.black.withOpacity(0.4), + Colors.black.withOpacity(0.2), + Colors.black.withOpacity(0.0001), + ], + begin: Alignment.topCenter, + end: Alignment.bottomCenter, + tileMode: TileMode.clamp, + ), + ), + ); + } +} diff --git a/lib/widgets/images/circular_image.dart b/lib/widgets/images/circular_image.dart new file mode 100644 index 0000000..7cf4270 --- /dev/null +++ b/lib/widgets/images/circular_image.dart @@ -0,0 +1,30 @@ + +import 'package:flutter/material.dart'; +import 'package:mc_common_app/utils/utils.dart'; + +class CircularImage extends StatelessWidget { + final double? w, h, padding; + final String? image; + + const CircularImage({Key? key, this.w, this.h, this.image, this.padding}) : super(key: key); + + @override + Widget build(BuildContext context) { + return SizedBox( + width: w ?? 120, + height: h ?? 120, + child: Card( + shape: Utils.cardRadius(2000), + clipBehavior: Clip.antiAlias, + elevation: 4, + child: Card( + shape: Utils.cardRadius(2000), + clipBehavior: Clip.antiAlias, + elevation: 0, + margin: EdgeInsets.all(padding ?? 0), + child: Image.asset(image ?? "" + "green.jpg"), + ), + ), + ); + } +} diff --git a/lib/widgets/loading_dialog.dart b/lib/widgets/loading_dialog.dart new file mode 100644 index 0000000..bc2da89 --- /dev/null +++ b/lib/widgets/loading_dialog.dart @@ -0,0 +1,40 @@ +import 'package:flutter/material.dart'; + +class LoadingDialog extends StatefulWidget { + LoadingDialog({Key? key}) : super(key: key); + + @override + _LoadingDialogState createState() { + return _LoadingDialogState(); + } +} + +class _LoadingDialogState extends State { + @override + void initState() { + super.initState(); + } + + @override + void dispose() { + super.dispose(); + } + + @override + Widget build(BuildContext context) { + return Dialog( + insetPadding: const EdgeInsets.symmetric(horizontal: 60.0, vertical: 24.0), + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.circular(16), + ), + elevation: 0, + backgroundColor: Colors.transparent, + child: Directionality( + textDirection: TextDirection.rtl, + child: Center( + child: CircularProgressIndicator(), + ), + ), + ); + } +} diff --git a/lib/widgets/otp_widget.dart b/lib/widgets/otp_widget.dart new file mode 100644 index 0000000..c31c8cd --- /dev/null +++ b/lib/widgets/otp_widget.dart @@ -0,0 +1,371 @@ +import 'dart:async'; + +import 'package:flutter/foundation.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter/services.dart'; + +typedef OnDone = void Function(String text); + +class ProvidedPinBoxTextAnimation { + static AnimatedSwitcherTransitionBuilder scalingTransition = (child, animation) { + return ScaleTransition( + child: child, + scale: animation, + ); + }; + + static AnimatedSwitcherTransitionBuilder defaultNoTransition = (Widget child, Animation animation) { + return child; + }; +} + +class OTPWidget extends StatefulWidget { + final int maxLength; + final TextEditingController? controller; + + final Color defaultBorderColor; + final Color pinBoxColor; + final double pinBoxBorderWidth; + final double pinBoxRadius; + final bool hideDefaultKeyboard; + + final TextStyle? pinTextStyle; + final double pinBoxHeight; + final double pinBoxWidth; + final OnDone? onDone; + final bool hasError; + final Color errorBorderColor; + final Color textBorderColor; + final Function(String)? onTextChanged; + final bool autoFocus; + final FocusNode? focusNode; + final AnimatedSwitcherTransitionBuilder? pinTextAnimatedSwitcherTransition; + final Duration pinTextAnimatedSwitcherDuration; + final TextDirection textDirection; + final TextInputType keyboardType; + final EdgeInsets pinBoxOuterPadding; + + const OTPWidget({ + Key? key, + this.maxLength: 4, + this.controller, + this.pinBoxWidth: 70.0, + this.pinBoxHeight: 70.0, + this.pinTextStyle, + this.onDone, + this.defaultBorderColor: Colors.black, + this.textBorderColor: Colors.black, + this.pinTextAnimatedSwitcherTransition, + this.pinTextAnimatedSwitcherDuration: const Duration(), + this.hasError: false, + this.errorBorderColor: Colors.red, + this.onTextChanged, + this.autoFocus: false, + this.focusNode, + this.textDirection: TextDirection.ltr, + this.keyboardType: TextInputType.number, + this.pinBoxOuterPadding = const EdgeInsets.symmetric(horizontal: 4.0), + this.pinBoxColor = Colors.white, + this.pinBoxBorderWidth = 2.0, + this.pinBoxRadius = 0, + this.hideDefaultKeyboard = false, + }) : super(key: key); + + @override + State createState() { + return OTPWidgetState(); + } +} + +class OTPWidgetState extends State with SingleTickerProviderStateMixin { + AnimationController? _highlightAnimationController; + FocusNode? focusNode; + String text = ""; + int currentIndex = 0; + List strList = []; + bool hasFocus = false; + + @override + void didUpdateWidget(OTPWidget oldWidget) { + super.didUpdateWidget(oldWidget); + focusNode = widget.focusNode ?? focusNode; + + if (oldWidget.maxLength < widget.maxLength) { + setState(() { + currentIndex = text.length; + }); + widget.controller?.text = text; + widget.controller?.selection = TextSelection.collapsed(offset: text.length); + } else if (oldWidget.maxLength > widget.maxLength && widget.maxLength > 0 && text.length > 0 && text.length > widget.maxLength) { + setState(() { + text = text.substring(0, widget.maxLength); + currentIndex = text.length; + }); + widget.controller?.text = text; + widget.controller?.selection = TextSelection.collapsed(offset: text.length); + } + } + + _calculateStrList() { + if (strList.length > widget.maxLength) { + strList.length = widget.maxLength; + } + while (strList.length < widget.maxLength) { + strList.add(""); + } + } + + @override + void initState() { + super.initState(); + focusNode = widget.focusNode ?? FocusNode(); + + _initTextController(); + _calculateStrList(); + widget.controller?.addListener(_controllerListener); + focusNode?.addListener(_focusListener); + } + + void _controllerListener() { + if (mounted == true) { + setState(() { + _initTextController(); + }); + var onTextChanged = widget.onTextChanged; + if (onTextChanged != null) { + onTextChanged(widget.controller?.text ?? ""); + } + } + } + + void _focusListener() { + if (mounted == true) { + setState(() { + hasFocus = focusNode?.hasFocus ?? false; + }); + } + } + + void _initTextController() { + if (widget.controller == null) { + return; + } + strList.clear(); + var text = widget.controller?.text ?? ""; + if (text.isNotEmpty) { + if (text.length > widget.maxLength) { + throw Exception("TextEditingController length exceeded maxLength!"); + } + } + for (var i = 0; i < text.length; i++) { + strList.add(text[i]); + } + } + + double get _width { + var width = 0.0; + for (var i = 0; i < widget.maxLength; i++) { + width += widget.pinBoxWidth; + if (i == 0) { + width += widget.pinBoxOuterPadding.left; + } else if (i + 1 == widget.maxLength) { + width += widget.pinBoxOuterPadding.right; + } else { + width += widget.pinBoxOuterPadding.left; + } + } + return width; + } + + @override + void dispose() { + if (widget.focusNode == null) { + focusNode?.dispose(); + } else { + focusNode?.removeListener(_focusListener); + } + _highlightAnimationController?.dispose(); + widget.controller?.removeListener(_controllerListener); + + super.dispose(); + } + + @override + Widget build(BuildContext context) { + return Stack( + children: [ + _otpTextInput(), + _touchPinBoxRow(), + ], + ); + } + + Widget _touchPinBoxRow() { + return widget.hideDefaultKeyboard + ? _pinBoxRow(context) + : GestureDetector( + behavior: HitTestBehavior.opaque, + onTap: () { + if (hasFocus) { + FocusScope.of(context).requestFocus(FocusNode()); + Future.delayed(Duration(milliseconds: 100), () { + FocusScope.of(context).requestFocus(focusNode); + }); + } else { + FocusScope.of(context).requestFocus(focusNode); + } + }, + child: _pinBoxRow(context), + ); + } + + Widget _otpTextInput() { + var transparentBorder = OutlineInputBorder( + borderSide: BorderSide( + color: Colors.transparent, + width: 0.0, + ), + ); + return Container( + width: _width, + height: widget.pinBoxHeight, + child: TextField( + autofocus: !kIsWeb ? widget.autoFocus : false, + enableInteractiveSelection: false, + focusNode: focusNode, + controller: widget.controller, + keyboardType: widget.keyboardType, + inputFormatters: widget.keyboardType == TextInputType.number ? [FilteringTextInputFormatter.digitsOnly] : null, + style: TextStyle( + height: 0.1, + color: Colors.transparent, + ), + decoration: InputDecoration( + contentPadding: EdgeInsets.all(0), + focusedErrorBorder: transparentBorder, + errorBorder: transparentBorder, + disabledBorder: transparentBorder, + enabledBorder: transparentBorder, + focusedBorder: transparentBorder, + counterText: null, + counterStyle: null, + helperStyle: TextStyle( + height: 0.0, + color: Colors.transparent, + ), + labelStyle: TextStyle(height: 0.1), + fillColor: Colors.transparent, + border: InputBorder.none, + ), + cursorColor: Colors.transparent, + showCursor: false, + maxLength: widget.maxLength, + onChanged: _onTextChanged, + ), + ); + } + + void _onTextChanged(text) { + var onTextChanged = widget.onTextChanged; + if (onTextChanged != null) { + onTextChanged(text); + } + setState(() { + this.text = text; + if (text.length >= currentIndex) { + for (int i = currentIndex; i < text.length; i++) { + strList[i] = text[i]; + } + } + currentIndex = text.length; + }); + if (text.length == widget.maxLength) { + FocusScope.of(context).requestFocus(FocusNode()); + var onDone = widget.onDone; + if (onDone != null) { + onDone(text); + } + } + } + + Widget _pinBoxRow(BuildContext context) { + _calculateStrList(); + List pinCodes = List.generate(widget.maxLength, (int i) { + return _buildPinCode(i, context); + }); + return Row(children: pinCodes, mainAxisSize: MainAxisSize.min); + } + + Widget _buildPinCode(int i, BuildContext context) { + Color borderColor; + Color pinBoxColor = widget.pinBoxColor; + + if (widget.hasError) { + borderColor = widget.errorBorderColor; + } else if (i < text.length) { + borderColor = widget.textBorderColor; + } else { + borderColor = widget.defaultBorderColor; + pinBoxColor = widget.pinBoxColor; + } + + EdgeInsets insets; + if (i == 0) { + insets = EdgeInsets.only( + left: 0, + top: widget.pinBoxOuterPadding.top, + right: widget.pinBoxOuterPadding.right, + bottom: widget.pinBoxOuterPadding.bottom, + ); + } else if (i == strList.length - 1) { + insets = EdgeInsets.only( + left: widget.pinBoxOuterPadding.left, + top: widget.pinBoxOuterPadding.top, + right: 0, + bottom: widget.pinBoxOuterPadding.bottom, + ); + } else { + insets = widget.pinBoxOuterPadding; + } + return Container( + key: ValueKey("container$i"), + alignment: Alignment.center, + padding: EdgeInsets.symmetric(vertical: 4.0, horizontal: 1.0), + margin: insets, + child: _animatedTextBox(strList[i], i), + decoration: BoxDecoration( + border: Border.all( + color: borderColor, + width: widget.pinBoxBorderWidth, + ), + color: pinBoxColor, + borderRadius: BorderRadius.circular(widget.pinBoxRadius), + ), + width: widget.pinBoxWidth, + height: widget.pinBoxHeight, + ); + } + + Widget _animatedTextBox(String text, int i) { + if (widget.pinTextAnimatedSwitcherTransition != null) { + return AnimatedSwitcher( + duration: widget.pinTextAnimatedSwitcherDuration, + transitionBuilder: widget.pinTextAnimatedSwitcherTransition ?? + (Widget child, Animation animation) { + return child; + }, + child: Text( + text, + key: ValueKey("$text$i"), + style: widget.pinTextStyle, + ), + ); + } else { + return Text( + text, + key: ValueKey("${strList[i]}$i"), + style: widget.pinTextStyle, + ); + } + } +} diff --git a/lib/widgets/show_card_buttton.dart b/lib/widgets/show_card_buttton.dart new file mode 100644 index 0000000..34be3bd --- /dev/null +++ b/lib/widgets/show_card_buttton.dart @@ -0,0 +1,32 @@ + +import 'package:flutter/material.dart'; +import 'package:mc_common_app/widgets/show_fill_button.dart'; + +class ShowCardButton extends StatelessWidget { + String title; + VoidCallback onPressed; + Color txtColor; + + ShowCardButton({ + required this.title, + required this.onPressed, + this.txtColor = Colors.white, + }); + + @override + Widget build(BuildContext context) { + return Card( + margin: EdgeInsets.zero, + elevation: 20, + child: Container( + width: double.infinity, + padding: EdgeInsets.all(12), + child: ShowFillButton( + title: title, + onPressed: onPressed, + txtColor: txtColor, + ), + ), + ); + } +} diff --git a/lib/widgets/show_fill_button.dart b/lib/widgets/show_fill_button.dart new file mode 100644 index 0000000..b391be7 --- /dev/null +++ b/lib/widgets/show_fill_button.dart @@ -0,0 +1,70 @@ + +import 'package:flutter/material.dart'; +import 'package:mc_common_app/extensions/string_extensions.dart'; + +import '../theme/colors.dart'; + +class ShowFillButton extends StatelessWidget { + String title; + VoidCallback onPressed; + Color txtColor; + double elevation, radius, maxWidth, maxHeight, fontSize, horizontalPadding, horizontalMargin, verticalMargin; + bool isFlatButton, isBold; + + ShowFillButton({ + required this.title, + required this.onPressed, + this.txtColor = Colors.white, + this.elevation = 0, + this.radius = 0, + this.maxWidth = 88, + this.maxHeight = 45, + this.fontSize = 16, + this.horizontalPadding = 16, + this.isFlatButton = false, + this.isBold = true, + this.horizontalMargin = 0, + this.verticalMargin = 0, + }); + + @override + Widget build(BuildContext context) { + return isFlatButton + ? Container( + child: showButton(), + height: maxHeight, + padding: const EdgeInsets.only( + left: 20, + right: 20, + ), + ) + : ConstrainedBox( + constraints: BoxConstraints( + minHeight: maxHeight, + minWidth: maxWidth, + maxHeight: maxHeight, + maxWidth: maxWidth, + ), + child: showButton(), + ); + } + + Widget showButton() { + return Container( + // decoration: isFlatButton ? null : MyColors.gradientButton, + color:isFlatButton ? null : MyColors.darkPrimaryColor, + margin: EdgeInsets.symmetric(horizontal: horizontalMargin, vertical: verticalMargin), + child: MaterialButton( + onPressed: onPressed, + shape: new RoundedRectangleBorder( + borderRadius: new BorderRadius.circular(radius), + ), + child: title.toText( + fontSize: fontSize, + isBold: isBold, + color: txtColor, + ), + ), + ); + } +} diff --git a/lib/widgets/tab/login_email_tab.dart b/lib/widgets/tab/login_email_tab.dart new file mode 100644 index 0000000..a236dea --- /dev/null +++ b/lib/widgets/tab/login_email_tab.dart @@ -0,0 +1,85 @@ + +import 'package:easy_localization/src/public_ext.dart'; +import 'package:flutter/material.dart'; +import 'package:mc_common_app/extensions/int_extensions.dart'; +import 'package:mc_common_app/generated/locale_keys.g.dart'; + +import '../../theme/colors.dart'; + +enum ClassType { EMAIL, NUMBER } + +class LoginEmailTab extends StatefulWidget { + Function(ClassType) onSelection; + + LoginEmailTab({required this.onSelection}); + + @override + State createState() => _LoginEmailTabState(); +} + +class _LoginEmailTabState extends State { + ClassType type = ClassType.EMAIL; + + @override + Widget build(BuildContext context) { + return Container( + width: double.infinity, + child: Row( + children: [ + Expanded( + child: InkWell( + onTap: () { + type = ClassType.EMAIL; + widget.onSelection(ClassType.EMAIL); + }, + child: Container( + width: double.infinity, + height: 45, + decoration: BoxDecoration( + color: type == ClassType.EMAIL ? MyColors.darkPrimaryColor : Colors.grey[200], + // border: Border.all(color: type == ClassType.NUMBER ? MyColors.darkPrimaryColor : Colors.transparent, width: 2), + borderRadius: BorderRadius.all(Radius.circular(0)), + ), + child: Center( + child: Text( + LocaleKeys.email.tr(), + style: TextStyle( + color: type == ClassType.EMAIL ? MyColors.white : Colors.black, + ), + ), + ), + ), + ), + ), + 12.width, + Expanded( + child: InkWell( + onTap: () { + type = ClassType.NUMBER; + widget.onSelection(ClassType.NUMBER); + }, + child: Container( + width: double.infinity, + height: 45, + decoration: BoxDecoration( + color: type == ClassType.NUMBER ? MyColors.darkPrimaryColor : Colors.grey[200], + // border: Border.all(color: type == ClassType.NUMBER ? MyColors.darkPrimaryColor : Colors.transparent, width: 2), + borderRadius: BorderRadius.all(Radius.circular(0)), + ), + child: Center( + child: Text( + LocaleKeys.phoneNumber.tr(), + style: TextStyle( + color: type == ClassType.NUMBER ? MyColors.white : Colors.black, + ), + ), + ), + ), + ), + ), + + ], + ), + ); + } +} diff --git a/lib/widgets/txt_field.dart b/lib/widgets/txt_field.dart new file mode 100644 index 0000000..95f161a --- /dev/null +++ b/lib/widgets/txt_field.dart @@ -0,0 +1,165 @@ + +import 'package:flutter/material.dart'; +import 'package:mc_common_app/extensions/int_extensions.dart'; +import 'package:mc_common_app/extensions/string_extensions.dart'; +import 'package:mc_common_app/theme/colors.dart'; +import 'package:mc_common_app/utils/utils.dart'; +import 'package:sizer/sizer.dart'; + +class TxtField extends StatelessWidget { + TextEditingController controller = TextEditingController(); + String? value; + String? hint; + String? lable; + IconData? prefixData; + IconData? postfixData; + bool isNeedFilterButton; + bool isNeedClickAll; + bool isButtonEnable; + double? elevation; + VoidCallback? onTap; + String? buttonTitle; + int? maxLines; + bool isSidePaddingZero; + bool isNeedBorder; + bool? isPasswordEnabled; + Function(String)? onChanged; + TextInputType? keyboardType; + bool isBackgroundEnabled = false; + + TxtField({ + Key? key, + this.value, + this.lable, + this.hint, + this.prefixData, + this.postfixData, + this.isNeedClickAll = false, + this.isNeedFilterButton = false, + this.elevation, + this.onTap, + this.isButtonEnable = false, + this.buttonTitle, + this.maxLines, + this.isSidePaddingZero = false, + this.isNeedBorder = true, + this.onChanged, + this.isPasswordEnabled, + this.keyboardType, + this.isBackgroundEnabled = false, + }) : super(key: key); + + @override + Widget build(BuildContext context) { + controller.text = value ?? ""; + controller.selection = TextSelection.fromPosition(TextPosition(offset: controller.text.length)); + return InkWell( + onTap: isNeedClickAll == false + ? null + : () { + onTap!(); + }, + customBorder: Utils.inkWellCorner(), + child: Row( + children: [ + Expanded( + child: Container( + decoration: BoxDecoration( + color: isBackgroundEnabled ? MyColors.textFieldColor : Colors.white, + borderRadius: const BorderRadius.all(Radius.circular(0)), + ), + child: TextField( + keyboardType: keyboardType, + autofocus: false, + controller: controller, + enabled: isNeedClickAll == true ? false : true, + maxLines: maxLines, + onTap: () {}, + obscureText: isPasswordEnabled ?? false, + onChanged: onChanged, + decoration: InputDecoration( + labelText: lable, + alignLabelWithHint: true, + fillColor: Colors.white, + focusedBorder: OutlineInputBorder( + borderSide: BorderSide(color: MyColors.darkPrimaryColor, width: isNeedBorder ? 2.0 : 0), + borderRadius: BorderRadius.circular(0.0), + ), + enabledBorder: OutlineInputBorder( + // borderSide: BorderSide(color: MyColors.textFieldColor, width: isNeedBorder ? 1.0 : 0), + borderSide: BorderSide(color: MyColors.darkPrimaryColor, width: isNeedBorder ? 2.0 : 0), + borderRadius: BorderRadius.circular(0.0), + ), + disabledBorder: OutlineInputBorder( + // borderSide: BorderSide(color: MyColors.textFieldColor, width: isNeedBorder ? 1.0 : 0), + borderSide: BorderSide(color: MyColors.darkPrimaryColor, width: isNeedBorder ? 2.0 : 0), + borderRadius: BorderRadius.circular(0.0), + ), + prefixIcon: prefixData != null ? const Icon(Icons.search, color: borderColor) : null, + labelStyle: TextStyle(color: borderColor, fontSize: 13.sp), + hintStyle: TextStyle(color: borderColor, fontSize: 9.sp), + hintText: hint ?? "", + contentPadding: prefixData == null + ? EdgeInsets.only( + left: 12, + right: 12, + top: maxLines != null ? 12 : 0, + bottom: maxLines != null ? 12 : 0, + ) + : EdgeInsets.zero, + ), + ), + ), + ), + if (isNeedFilterButton) 8.width, + if (isNeedFilterButton) + InkWell( + onTap: isNeedClickAll + ? null + : () { + controller.clear(); + }, + child: SizedBox( + width: 55, + height: 55, + child: Card( + color: accentColor, + // margin: EdgeInsets.all(4), + // shape: cardRadius(0), + child: Icon( + postfixData ?? Icons.filter_alt, + color: Colors.white, + ), + ), + ), + ), + if (isButtonEnable) + Material( + child: InkWell( + onTap: onTap, + customBorder: Utils.inkWellCorner(), + child: SizedBox( + height: 55, + child: Card( + color: accentColor, + // margin: EdgeInsets.all(4), + // shape: cardRadius(0), + child: Center( + child: Padding( + padding: const EdgeInsets.only(left: 12, right: 12), + child: (buttonTitle ?? "Search").toText( + color: Colors.white, + fontSize: 16, + letterSpacing: -0.64, + ), + ), + ), + ), + ), + ), + ), + ], + ), + ); + } +} diff --git a/lib/widgets/user_image.dart b/lib/widgets/user_image.dart new file mode 100644 index 0000000..823c642 --- /dev/null +++ b/lib/widgets/user_image.dart @@ -0,0 +1,26 @@ + +import 'package:flutter/material.dart'; +import 'package:mc_common_app/utils/utils.dart'; + +class UserImage extends StatelessWidget { + final double? size; + final String? url; + + const UserImage({Key? key, this.size, this.url}) : super(key: key); + + @override + Widget build(BuildContext context) { + return Container( + height: size ?? 60, + width: size ?? 60, + decoration: Utils.containerRadius(Colors.transparent, 1000), + clipBehavior: Clip.antiAlias, + child: Image.asset( + url ?? "" + "Blue Masked.jpg", + width: double.infinity, + height: double.infinity, + fit: BoxFit.cover, + ), + ); + } +} diff --git a/pubspec.lock b/pubspec.lock new file mode 100644 index 0000000..70ed0f7 --- /dev/null +++ b/pubspec.lock @@ -0,0 +1,935 @@ +# Generated by pub +# See https://dart.dev/tools/pub/glossary#lockfile +packages: + args: + dependency: transitive + description: + name: args + sha256: "4cab82a83ffef80b262ddedf47a0a8e56ee6fbf7fe21e6e768b02792034dd440" + url: "https://pub.dev" + source: hosted + version: "2.4.0" + async: + dependency: transitive + description: + name: async + sha256: bfe67ef28df125b7dddcea62755991f807aa39a2492a23e1550161692950bbe0 + url: "https://pub.dev" + source: hosted + version: "2.10.0" + auto_size_text: + dependency: "direct main" + description: + name: auto_size_text + sha256: "3f5261cd3fb5f2a9ab4e2fc3fba84fd9fcaac8821f20a1d4e71f557521b22599" + url: "https://pub.dev" + source: hosted + version: "3.0.0" + boolean_selector: + dependency: transitive + description: + name: boolean_selector + sha256: "6cfb5af12253eaf2b368f07bacc5a80d1301a071c73360d746b7f2e32d762c66" + url: "https://pub.dev" + source: hosted + version: "2.1.1" + cached_network_image: + dependency: "direct main" + description: + name: cached_network_image + sha256: e764e48ef036cabdf84319ba7b8b5871b6b43266e14de787cb43f77639089ae5 + url: "https://pub.dev" + source: hosted + version: "3.2.1" + cached_network_image_platform_interface: + dependency: transitive + description: + name: cached_network_image_platform_interface + sha256: "8e2b5befefec5063bee8f209fda21751f6328d405d4237c70f21104568b2fee7" + url: "https://pub.dev" + source: hosted + version: "1.0.0" + cached_network_image_web: + dependency: transitive + description: + name: cached_network_image_web + sha256: d4351c7eb16767df129b0474a5ebc4e028870379c063e8ba265a56aa00831e70 + url: "https://pub.dev" + source: hosted + version: "1.0.1" + characters: + dependency: transitive + description: + name: characters + sha256: e6a326c8af69605aec75ed6c187d06b349707a27fbff8222ca9cc2cff167975c + url: "https://pub.dev" + source: hosted + version: "1.2.1" + clock: + dependency: transitive + description: + name: clock + sha256: cb6d7f03e1de671e34607e909a7213e31d7752be4fb66a86d29fe1eb14bfb5cf + url: "https://pub.dev" + source: hosted + version: "1.1.1" + collection: + dependency: transitive + description: + name: collection + sha256: cfc915e6923fe5ce6e153b0723c753045de46de1b4d63771530504004a45fae0 + url: "https://pub.dev" + source: hosted + version: "1.17.0" + cross_file: + dependency: transitive + description: + name: cross_file + sha256: "0b0036e8cccbfbe0555fd83c1d31a6f30b77a96b598b35a5d36dd41f718695e9" + url: "https://pub.dev" + source: hosted + version: "0.3.3+4" + crypto: + dependency: transitive + description: + name: crypto + sha256: aa274aa7774f8964e4f4f38cc994db7b6158dd36e9187aaceaddc994b35c6c67 + url: "https://pub.dev" + source: hosted + version: "3.0.2" + cupertino_icons: + dependency: "direct main" + description: + name: cupertino_icons + sha256: e35129dc44c9118cee2a5603506d823bab99c68393879edb440e0090d07586be + url: "https://pub.dev" + source: hosted + version: "1.0.5" + easy_localization: + dependency: "direct main" + description: + name: easy_localization + sha256: "6a2e99fa0bfe5765bf4c6ca9b137d5de2c75593007178c5e4cd2ae985f870080" + url: "https://pub.dev" + source: hosted + version: "3.0.1" + easy_logger: + dependency: transitive + description: + name: easy_logger + sha256: c764a6e024846f33405a2342caf91c62e357c24b02c04dbc712ef232bf30ffb7 + url: "https://pub.dev" + source: hosted + version: "0.0.2" + equatable: + dependency: "direct main" + description: + name: equatable + sha256: c2b87cb7756efdf69892005af546c56c0b5037f54d2a88269b4f347a505e3ca2 + url: "https://pub.dev" + source: hosted + version: "2.0.5" + fake_async: + dependency: transitive + description: + name: fake_async + sha256: "511392330127add0b769b75a987850d136345d9227c6b94c96a04cf4a391bf78" + url: "https://pub.dev" + source: hosted + version: "1.3.1" + ffi: + dependency: transitive + description: + name: ffi + sha256: "13a6ccf6a459a125b3fcdb6ec73bd5ff90822e071207c663bfd1f70062d51d18" + url: "https://pub.dev" + source: hosted + version: "1.2.1" + file: + dependency: transitive + description: + name: file + sha256: "1b92bec4fc2a72f59a8e15af5f52cd441e4a7860b49499d69dfa817af20e925d" + url: "https://pub.dev" + source: hosted + version: "6.1.4" + file_picker: + dependency: "direct main" + description: + name: file_picker + sha256: "704259669b5e9cb24e15c11cfcf02caf5f20d30901b3916d60b6d1c2d647035f" + url: "https://pub.dev" + source: hosted + version: "4.6.1" + flutter: + dependency: "direct main" + description: flutter + source: sdk + version: "0.0.0" + flutter_blurhash: + dependency: transitive + description: + name: flutter_blurhash + sha256: "05001537bd3fac7644fa6558b09ec8c0a3f2eba78c0765f88912882b1331a5c6" + url: "https://pub.dev" + source: hosted + version: "0.7.0" + flutter_cache_manager: + dependency: transitive + description: + name: flutter_cache_manager + sha256: "32cd900555219333326a2d0653aaaf8671264c29befa65bbd9856d204a4c9fb3" + url: "https://pub.dev" + source: hosted + version: "3.3.0" + flutter_lints: + dependency: "direct dev" + description: + name: flutter_lints + sha256: aeb0b80a8b3709709c9cc496cdc027c5b3216796bc0af0ce1007eaf24464fd4c + url: "https://pub.dev" + source: hosted + version: "2.0.1" + flutter_localizations: + dependency: transitive + description: flutter + source: sdk + version: "0.0.0" + flutter_plugin_android_lifecycle: + dependency: transitive + description: + name: flutter_plugin_android_lifecycle + sha256: "60fc7b78455b94e6de2333d2f95196d32cf5c22f4b0b0520a628804cb463503b" + url: "https://pub.dev" + source: hosted + version: "2.0.7" + flutter_svg: + dependency: "direct main" + description: + name: flutter_svg + sha256: "6ff9fa12892ae074092de2fa6a9938fb21dbabfdaa2ff57dc697ff912fc8d4b2" + url: "https://pub.dev" + source: hosted + version: "1.1.6" + flutter_test: + dependency: "direct dev" + description: flutter + source: sdk + version: "0.0.0" + flutter_web_plugins: + dependency: transitive + description: flutter + source: sdk + version: "0.0.0" + fluttertoast: + dependency: "direct main" + description: + name: fluttertoast + sha256: "7cc92eabe01e3f1babe1571c5560b135dfc762a34e41e9056881e2196b178ec1" + url: "https://pub.dev" + source: hosted + version: "8.1.2" + geocoding: + dependency: "direct main" + description: + name: geocoding + sha256: "26218460a902d4249b81e6baf9d55ce400fd1ebe6fc0a7e92b2c12b0b8e1e14e" + url: "https://pub.dev" + source: hosted + version: "2.0.5" + geocoding_platform_interface: + dependency: transitive + description: + name: geocoding_platform_interface + sha256: "8848605d307d844d89937cdb4b8ad7dfa880552078f310fa24d8a460f6dddab4" + url: "https://pub.dev" + source: hosted + version: "2.0.1" + geolocator: + dependency: "direct main" + description: + name: geolocator + sha256: "5c23f3613f50586c0bbb2b8f970240ae66b3bd992088cf60dd5ee2e6f7dde3a8" + url: "https://pub.dev" + source: hosted + version: "9.0.2" + geolocator_android: + dependency: transitive + description: + name: geolocator_android + sha256: fe90565c3a8789dc3b433d8f95cdb18343f9bde298a419d978337ba1ae1037d3 + url: "https://pub.dev" + source: hosted + version: "4.1.4" + geolocator_apple: + dependency: transitive + description: + name: geolocator_apple + sha256: "567cf6d9879b4c33b2bd8bbfff0995e75c62a14f87b1480c8522c5dca5d3b166" + url: "https://pub.dev" + source: hosted + version: "2.2.3" + geolocator_platform_interface: + dependency: transitive + description: + name: geolocator_platform_interface + sha256: af4d69231452f9620718588f41acc4cb58312368716bfff2e92e770b46ce6386 + url: "https://pub.dev" + source: hosted + version: "4.0.7" + geolocator_web: + dependency: transitive + description: + name: geolocator_web + sha256: f68a122da48fcfff68bbc9846bb0b74ef651afe84a1b1f6ec20939de4d6860e1 + url: "https://pub.dev" + source: hosted + version: "2.1.6" + geolocator_windows: + dependency: transitive + description: + name: geolocator_windows + sha256: f5911c88e23f48b598dd506c7c19eff0e001645bdc03bb6fecb9f4549208354d + url: "https://pub.dev" + source: hosted + version: "0.1.1" + google_maps_flutter: + dependency: "direct main" + description: + name: google_maps_flutter + sha256: "0c6b72b4b1e0f6204973e2b40868a75fe6380725d498f215cd7e35ed920d1c57" + url: "https://pub.dev" + source: hosted + version: "2.2.3" + google_maps_flutter_android: + dependency: transitive + description: + name: google_maps_flutter_android + sha256: "701761b234579b4cfc0f6ae0791e2bb7184b31207b0d716e536b6d1a190dc143" + url: "https://pub.dev" + source: hosted + version: "2.4.3" + google_maps_flutter_ios: + dependency: transitive + description: + name: google_maps_flutter_ios + sha256: "33bbca8d4148ed373251ea2ec2344fdc63009926b6d6be71a0854fd42409b1ba" + url: "https://pub.dev" + source: hosted + version: "2.1.13" + google_maps_flutter_platform_interface: + dependency: transitive + description: + name: google_maps_flutter_platform_interface + sha256: "0967430c25240836b794d42336bd4c61f0e78e9fd33d1365fa9316bb36b6b410" + url: "https://pub.dev" + source: hosted + version: "2.2.5" + hexcolor: + dependency: "direct main" + description: + name: hexcolor + sha256: e572c3346f4b26422a281dc4c10f83022131f56f7364837671b50f53c7adc5e7 + url: "https://pub.dev" + source: hosted + version: "2.0.7" + http: + dependency: "direct main" + description: + name: http + sha256: "6aa2946395183537c8b880962d935877325d6a09a2867c3970c05c0fed6ac482" + url: "https://pub.dev" + source: hosted + version: "0.13.5" + http_parser: + dependency: transitive + description: + name: http_parser + sha256: "2aa08ce0341cc9b354a498388e30986515406668dbcc4f7c950c3e715496693b" + url: "https://pub.dev" + source: hosted + version: "4.0.2" + image_picker: + dependency: "direct main" + description: + name: image_picker + sha256: "64b21d9f0e065f9ab0e4dde458076226c97382cc0c6949144cb874c62bf8e9f8" + url: "https://pub.dev" + source: hosted + version: "0.8.7" + image_picker_android: + dependency: transitive + description: + name: image_picker_android + sha256: b81db5f5ed8a69d54d5f0932c2af8120e8c0518a037d8beee494eec671da4d4c + url: "https://pub.dev" + source: hosted + version: "0.8.6+5" + image_picker_for_web: + dependency: transitive + description: + name: image_picker_for_web + sha256: "98f50d6b9f294c8ba35e25cc0d13b04bfddd25dbc8d32fa9d566a6572f2c081c" + url: "https://pub.dev" + source: hosted + version: "2.1.12" + image_picker_ios: + dependency: transitive + description: + name: image_picker_ios + sha256: "50e882fe0a06bf0c8f7f5bce78d30975f279213293afc9471dc35f05617c50ff" + url: "https://pub.dev" + source: hosted + version: "0.8.7+1" + image_picker_platform_interface: + dependency: transitive + description: + name: image_picker_platform_interface + sha256: "1991219d9dbc42a99aff77e663af8ca51ced592cd6685c9485e3458302d3d4f8" + url: "https://pub.dev" + source: hosted + version: "2.6.3" + injector: + dependency: "direct main" + description: + name: injector + sha256: "2a683124c716e93b45521794f55bfe770e069cb3d871fc4fbc65b5acef78e832" + url: "https://pub.dev" + source: hosted + version: "2.0.0" + intl: + dependency: transitive + description: + name: intl + sha256: "910f85bce16fb5c6f614e117efa303e85a1731bb0081edf3604a2ae6e9a3cc91" + url: "https://pub.dev" + source: hosted + version: "0.17.0" + js: + dependency: transitive + description: + name: js + sha256: "5528c2f391ededb7775ec1daa69e65a2d61276f7552de2b5f7b8d34ee9fd4ab7" + url: "https://pub.dev" + source: hosted + version: "0.6.5" + lints: + dependency: transitive + description: + name: lints + sha256: "5e4a9cd06d447758280a8ac2405101e0e2094d2a1dbdd3756aec3fe7775ba593" + url: "https://pub.dev" + source: hosted + version: "2.0.1" + local_auth: + dependency: "direct main" + description: + name: local_auth + sha256: d3fece0749101725b03206f84a7dab7aaafb702dbbd09131ff8d8173259a9b19 + url: "https://pub.dev" + source: hosted + version: "1.1.11" + logger: + dependency: "direct main" + description: + name: logger + sha256: "5076f09225f91dc49289a4ccb92df2eeea9ea01cf7c26d49b3a1f04c6a49eec1" + url: "https://pub.dev" + source: hosted + version: "1.1.0" + matcher: + dependency: transitive + description: + name: matcher + sha256: "16db949ceee371e9b99d22f88fa3a73c4e59fd0afed0bd25fc336eb76c198b72" + url: "https://pub.dev" + source: hosted + version: "0.12.13" + material_color_utilities: + dependency: transitive + description: + name: material_color_utilities + sha256: d92141dc6fe1dad30722f9aa826c7fbc896d021d792f80678280601aff8cf724 + url: "https://pub.dev" + source: hosted + version: "0.2.0" + meta: + dependency: transitive + description: + name: meta + sha256: "6c268b42ed578a53088d834796959e4a1814b5e9e164f147f580a386e5decf42" + url: "https://pub.dev" + source: hosted + version: "1.8.0" + nested: + dependency: transitive + description: + name: nested + sha256: "03bac4c528c64c95c722ec99280375a6f2fc708eec17c7b3f07253b626cd2a20" + url: "https://pub.dev" + source: hosted + version: "1.0.0" + octo_image: + dependency: transitive + description: + name: octo_image + sha256: "107f3ed1330006a3bea63615e81cf637433f5135a52466c7caa0e7152bca9143" + url: "https://pub.dev" + source: hosted + version: "1.0.2" + path: + dependency: transitive + description: + name: path + sha256: db9d4f58c908a4ba5953fcee2ae317c94889433e5024c27ce74a37f94267945b + url: "https://pub.dev" + source: hosted + version: "1.8.2" + path_drawing: + dependency: transitive + description: + name: path_drawing + sha256: bbb1934c0cbb03091af082a6389ca2080345291ef07a5fa6d6e078ba8682f977 + url: "https://pub.dev" + source: hosted + version: "1.0.1" + path_parsing: + dependency: transitive + description: + name: path_parsing + sha256: e3e67b1629e6f7e8100b367d3db6ba6af4b1f0bb80f64db18ef1fbabd2fa9ccf + url: "https://pub.dev" + source: hosted + version: "1.0.1" + path_provider: + dependency: "direct main" + description: + name: path_provider + sha256: "050e8e85e4b7fecdf2bb3682c1c64c4887a183720c802d323de8a5fd76d372dd" + url: "https://pub.dev" + source: hosted + version: "2.0.11" + path_provider_android: + dependency: transitive + description: + name: path_provider_android + sha256: a776c088d671b27f6e3aa8881d64b87b3e80201c64e8869b811325de7a76c15e + url: "https://pub.dev" + source: hosted + version: "2.0.22" + path_provider_ios: + dependency: transitive + description: + name: path_provider_ios + sha256: "03d639406f5343478352433f00d3c4394d52dac8df3d847869c5e2333e0bbce8" + url: "https://pub.dev" + source: hosted + version: "2.0.11" + path_provider_linux: + dependency: transitive + description: + name: path_provider_linux + sha256: ab0987bf95bc591da42dffb38c77398fc43309f0b9b894dcc5d6f40c4b26c379 + url: "https://pub.dev" + source: hosted + version: "2.1.7" + path_provider_macos: + dependency: transitive + description: + name: path_provider_macos + sha256: cd57cb98a30ce9d12fdd1896d9d3b0517ce689f942de6ccd2708cd39b3d18a7c + url: "https://pub.dev" + source: hosted + version: "2.0.7" + path_provider_platform_interface: + dependency: transitive + description: + name: path_provider_platform_interface + sha256: f0abc8ebd7253741f05488b4813d936b4d07c6bae3e86148a09e342ee4b08e76 + url: "https://pub.dev" + source: hosted + version: "2.0.5" + path_provider_windows: + dependency: transitive + description: + name: path_provider_windows + sha256: a34ecd7fb548f8e57321fd8e50d865d266941b54e6c3b7758cf8f37c24116905 + url: "https://pub.dev" + source: hosted + version: "2.0.7" + pedantic: + dependency: transitive + description: + name: pedantic + sha256: "67fc27ed9639506c856c840ccce7594d0bdcd91bc8d53d6e52359449a1d50602" + url: "https://pub.dev" + source: hosted + version: "1.11.1" + permission_handler: + dependency: "direct main" + description: + name: permission_handler + sha256: "5749ebeb7ec0c3865ea17e3eb337174b87747be816dab582c551e1aff6f6bbf3" + url: "https://pub.dev" + source: hosted + version: "9.2.0" + permission_handler_android: + dependency: transitive + description: + name: permission_handler_android + sha256: a512e0fa8abcb0659d938ec2df93a70eb1df1fdea5fdc6d79a866bfd858a28fc + url: "https://pub.dev" + source: hosted + version: "9.0.2+1" + permission_handler_apple: + dependency: transitive + description: + name: permission_handler_apple + sha256: "9c370ef6a18b1c4b2f7f35944d644a56aa23576f23abee654cf73968de93f163" + url: "https://pub.dev" + source: hosted + version: "9.0.7" + permission_handler_platform_interface: + dependency: transitive + description: + name: permission_handler_platform_interface + sha256: "68abbc472002b5e6dfce47fe9898c6b7d8328d58b5d2524f75e277c07a97eb84" + url: "https://pub.dev" + source: hosted + version: "3.9.0" + permission_handler_windows: + dependency: transitive + description: + name: permission_handler_windows + sha256: f67cab14b4328574938ecea2db3475dad7af7ead6afab6338772c5f88963e38b + url: "https://pub.dev" + source: hosted + version: "0.1.2" + petitparser: + dependency: transitive + description: + name: petitparser + sha256: "2ebb289dc4764ec397f5cd3ca9881c6d17196130a7d646ed022a0dd9c2e25a71" + url: "https://pub.dev" + source: hosted + version: "5.0.0" + platform: + dependency: transitive + description: + name: platform + sha256: "4a451831508d7d6ca779f7ac6e212b4023dd5a7d08a27a63da33756410e32b76" + url: "https://pub.dev" + source: hosted + version: "3.1.0" + plugin_platform_interface: + dependency: transitive + description: + name: plugin_platform_interface + sha256: dbf0f707c78beedc9200146ad3cb0ab4d5da13c246336987be6940f026500d3a + url: "https://pub.dev" + source: hosted + version: "2.1.3" + process: + dependency: transitive + description: + name: process + sha256: "53fd8db9cec1d37b0574e12f07520d582019cb6c44abf5479a01505099a34a09" + url: "https://pub.dev" + source: hosted + version: "4.2.4" + provider: + dependency: "direct main" + description: + name: provider + sha256: cdbe7530b12ecd9eb455bdaa2fcb8d4dad22e80b8afb4798b41479d5ce26847f + url: "https://pub.dev" + source: hosted + version: "6.0.5" + rxdart: + dependency: transitive + description: + name: rxdart + sha256: "0c7c0cedd93788d996e33041ffecda924cc54389199cde4e6a34b440f50044cb" + url: "https://pub.dev" + source: hosted + version: "0.27.7" + shared_preferences: + dependency: "direct main" + description: + name: shared_preferences + sha256: "5949029e70abe87f75cfe59d17bf5c397619c4b74a099b10116baeb34786fad9" + url: "https://pub.dev" + source: hosted + version: "2.0.17" + shared_preferences_android: + dependency: transitive + description: + name: shared_preferences_android + sha256: "955e9736a12ba776bdd261cf030232b30eadfcd9c79b32a3250dd4a494e8c8f7" + url: "https://pub.dev" + source: hosted + version: "2.0.15" + shared_preferences_foundation: + dependency: transitive + description: + name: shared_preferences_foundation + sha256: "1ffa239043ab8baf881ec3094a3c767af9d10399b2839020b9e4d44c0bb23951" + url: "https://pub.dev" + source: hosted + version: "2.1.2" + shared_preferences_linux: + dependency: transitive + description: + name: shared_preferences_linux + sha256: f8ea038aa6da37090093974ebdcf4397010605fd2ff65c37a66f9d28394cb874 + url: "https://pub.dev" + source: hosted + version: "2.1.3" + shared_preferences_platform_interface: + dependency: transitive + description: + name: shared_preferences_platform_interface + sha256: da9431745ede5ece47bc26d5d73a9d3c6936ef6945c101a5aca46f62e52c1cf3 + url: "https://pub.dev" + source: hosted + version: "2.1.0" + shared_preferences_web: + dependency: transitive + description: + name: shared_preferences_web + sha256: a4b5bc37fe1b368bbc81f953197d55e12f49d0296e7e412dfe2d2d77d6929958 + url: "https://pub.dev" + source: hosted + version: "2.0.4" + shared_preferences_windows: + dependency: transitive + description: + name: shared_preferences_windows + sha256: "5eaf05ae77658d3521d0e993ede1af962d4b326cd2153d312df716dc250f00c9" + url: "https://pub.dev" + source: hosted + version: "2.1.3" + shimmer: + dependency: "direct main" + description: + name: shimmer + sha256: "1f1009b5845a1f88f1c5630212279540486f97409e9fc3f63883e71070d107bf" + url: "https://pub.dev" + source: hosted + version: "2.0.0" + sizer: + dependency: "direct main" + description: + name: sizer + sha256: d2b3cb6cbc4a637f508dacd786bae55df31e5fc088044248a43e4fd1e050c117 + url: "https://pub.dev" + source: hosted + version: "2.0.15" + sky_engine: + dependency: transitive + description: flutter + source: sdk + version: "0.0.99" + source_span: + dependency: transitive + description: + name: source_span + sha256: dd904f795d4b4f3b870833847c461801f6750a9fa8e61ea5ac53f9422b31f250 + url: "https://pub.dev" + source: hosted + version: "1.9.1" + sqflite: + dependency: transitive + description: + name: sqflite + sha256: b3a8307b9519af28518e271e548594bdc435225fc77e8fb22e71a296c69281cf + url: "https://pub.dev" + source: hosted + version: "2.0.3+1" + sqflite_common: + dependency: transitive + description: + name: sqflite_common + sha256: "4aa3b917d48f9a3161419efa4a901e33a38721bf9a7465e7e07d2d6ef8895276" + url: "https://pub.dev" + source: hosted + version: "2.4.0" + stack_trace: + dependency: transitive + description: + name: stack_trace + sha256: c3c7d8edb15bee7f0f74debd4b9c5f3c2ea86766fe4178eb2a18eb30a0bdaed5 + url: "https://pub.dev" + source: hosted + version: "1.11.0" + stream_channel: + dependency: transitive + description: + name: stream_channel + sha256: "83615bee9045c1d322bbbd1ba209b7a749c2cbcdcb3fdd1df8eb488b3279c1c8" + url: "https://pub.dev" + source: hosted + version: "2.1.1" + stream_transform: + dependency: transitive + description: + name: stream_transform + sha256: "14a00e794c7c11aa145a170587321aedce29769c08d7f58b1d141da75e3b1c6f" + url: "https://pub.dev" + source: hosted + version: "2.1.0" + string_scanner: + dependency: transitive + description: + name: string_scanner + sha256: "556692adab6cfa87322a115640c11f13cb77b3f076ddcc5d6ae3c20242bedcde" + url: "https://pub.dev" + source: hosted + version: "1.2.0" + synchronized: + dependency: transitive + description: + name: synchronized + sha256: "7b530acd9cb7c71b0019a1e7fa22c4105e675557a4400b6a401c71c5e0ade1ac" + url: "https://pub.dev" + source: hosted + version: "3.0.0+3" + term_glyph: + dependency: transitive + description: + name: term_glyph + sha256: a29248a84fbb7c79282b40b8c72a1209db169a2e0542bce341da992fe1bc7e84 + url: "https://pub.dev" + source: hosted + version: "1.2.1" + test_api: + dependency: transitive + description: + name: test_api + sha256: ad540f65f92caa91bf21dfc8ffb8c589d6e4dc0c2267818b4cc2792857706206 + url: "https://pub.dev" + source: hosted + version: "0.4.16" + typed_data: + dependency: transitive + description: + name: typed_data + sha256: "26f87ade979c47a150c9eaab93ccd2bebe70a27dc0b4b29517f2904f04eb11a5" + url: "https://pub.dev" + source: hosted + version: "1.3.1" + universal_io: + dependency: transitive + description: + name: universal_io + sha256: "79f78ddad839ee3aae3ec7c01eb4575faf0d5c860f8e5223bc9f9c17f7f03cef" + url: "https://pub.dev" + source: hosted + version: "2.0.4" + url_launcher: + dependency: "direct main" + description: + name: url_launcher + sha256: "698fa0b4392effdc73e9e184403b627362eb5fbf904483ac9defbb1c2191d809" + url: "https://pub.dev" + source: hosted + version: "6.1.8" + url_launcher_android: + dependency: transitive + description: + name: url_launcher_android + sha256: "3e2f6dfd2c7d9cd123296cab8ef66cfc2c1a13f5845f42c7a0f365690a8a7dd1" + url: "https://pub.dev" + source: hosted + version: "6.0.23" + url_launcher_ios: + dependency: transitive + description: + name: url_launcher_ios + sha256: bb328b24d3bccc20bdf1024a0990ac4f869d57663660de9c936fb8c043edefe3 + url: "https://pub.dev" + source: hosted + version: "6.0.18" + url_launcher_linux: + dependency: transitive + description: + name: url_launcher_linux + sha256: "318c42cba924e18180c029be69caf0a1a710191b9ec49bb42b5998fdcccee3cc" + url: "https://pub.dev" + source: hosted + version: "3.0.2" + url_launcher_macos: + dependency: transitive + description: + name: url_launcher_macos + sha256: "41988b55570df53b3dd2a7fc90c76756a963de6a8c5f8e113330cb35992e2094" + url: "https://pub.dev" + source: hosted + version: "3.0.2" + url_launcher_platform_interface: + dependency: transitive + description: + name: url_launcher_platform_interface + sha256: "4eae912628763eb48fc214522e58e942fd16ce195407dbf45638239523c759a6" + url: "https://pub.dev" + source: hosted + version: "2.1.1" + url_launcher_web: + dependency: transitive + description: + name: url_launcher_web + sha256: "44d79408ce9f07052095ef1f9a693c258d6373dc3944249374e30eff7219ccb0" + url: "https://pub.dev" + source: hosted + version: "2.0.14" + url_launcher_windows: + dependency: transitive + description: + name: url_launcher_windows + sha256: "387e227c4b979034cc52afb11d66b04ed9b288ca1f45beeef39b2ea69e714fa5" + url: "https://pub.dev" + source: hosted + version: "3.0.2" + uuid: + dependency: transitive + description: + name: uuid + sha256: "648e103079f7c64a36dc7d39369cabb358d377078a051d6ae2ad3aa539519313" + url: "https://pub.dev" + source: hosted + version: "3.0.7" + vector_math: + dependency: transitive + description: + name: vector_math + sha256: "80b3257d1492ce4d091729e3a67a60407d227c27241d6927be0130c98e741803" + url: "https://pub.dev" + source: hosted + version: "2.1.4" + win32: + dependency: transitive + description: + name: win32 + sha256: c0e3a4f7be7dae51d8f152230b86627e3397c1ba8c3fa58e63d44a9f3edc9cef + url: "https://pub.dev" + source: hosted + version: "2.6.1" + xdg_directories: + dependency: transitive + description: + name: xdg_directories + sha256: bd512f03919aac5f1313eb8249f223bacf4927031bf60b02601f81f687689e86 + url: "https://pub.dev" + source: hosted + version: "0.2.0+3" + xml: + dependency: transitive + description: + name: xml + sha256: ac0e3f4bf00ba2708c33fbabbbe766300e509f8c82dbd4ab6525039813f7e2fb + url: "https://pub.dev" + source: hosted + version: "6.1.0" +sdks: + dart: ">=2.18.0 <3.0.0" + flutter: ">=3.3.0" diff --git a/pubspec.yaml b/pubspec.yaml new file mode 100644 index 0000000..7a2d993 --- /dev/null +++ b/pubspec.yaml @@ -0,0 +1,63 @@ +name: mc_common_app +description: A new Flutter project. +version: 1.0.0+1 + +environment: + sdk: ">=2.17.0 <3.0.0" + + + +dependencies: + flutter: + sdk: flutter + + cupertino_icons: ^1.0.2 + path_provider: ^2.0.4 + injector: ^2.0.0 + provider: ^6.0.0 + easy_localization: ^3.0.1 + http: ^0.13.3 + permission_handler: any + flutter_svg: ^1.0.3 + sizer: ^2.0.15 + fluttertoast: ^8.0.8 + shared_preferences: ^2.0.6 + file_picker: ^4.4.0 + image_picker: ^0.8.4+4 + equatable: ^2.0.3 + logger: ^1.1.0 + auto_size_text: any + shimmer: ^2.0.0 + local_auth: ^1.1.9 + hexcolor: ^2.0.4 + cached_network_image: any + url_launcher: ^6.1.7 + + + # google + google_maps_flutter: ^2.1.1 + geolocator: any + geocoding: any + + +dev_dependencies: + flutter_test: + sdk: flutter + + flutter_lints: ^2.0.0 + + +flutter: + uses-material-design: true + + assets: + - assets/ + - assets/langs/ + - assets/icons/ + - assets/images/ + + fonts: + - family: Poppins + fonts: + - asset: assets/fonts/Poppins-Medium.ttf + diff --git a/resources/ar-SA.json b/resources/ar-SA.json new file mode 100644 index 0000000..9a1099b --- /dev/null +++ b/resources/ar-SA.json @@ -0,0 +1,183 @@ +{ + "firstTimeLogIn": "تسجيل الدخول لأول مره", + "signUp": "التسجيل", + "changeMobile": "تغيير رقم الجوال", + "notifications": "الاشعارات", + "general": "عام", + "defineLicences": "تحديد الرخص", + "dealershipSettings": "اعدادات البيع", + "changePassword": "تغيير كلمة المرور", + "retrievePassword": "استرجاع كلمة المرور", + "changeEmail": "تغيير الايميل", + "verify": "تحقق", + "verified": "تم التحقق", + "signOut": "تسجيل خروج", + "enterEmail": "ادخل الايميل", + "enterNewEmail": "ادخل ايميل جديد", + "enterCurrentPassword": "كلمة المرور الحاليه", + "enterNewPassword": "كلمة المرور الجديده", + "enterOldPassword": "كلمة المرور القديمه", + "confirm": "تأكيد", + "enterNewPhoneNumber": "رقم جوال جديد", + "completeProfile": "الملف الشخصي", + "continu": "استمرار", + "confirmPassword": "تأكيد كلمة المرور", + "createPassword": "انشاء كلمة مرور جديده", + "email": "ايميل", + "firstName": "الأسم الأول *", + "surname": "اسم العائله *", + "confirmPass": "تأكيد كلمة المرور *", + "createPass": "انشاء كلمة مرور جديده *", + "newPassword": " كلمة مرور جديده", + "forgetPassword": "نسيت كلمة المرور", + "forgetPasswordQ": "نسيت كلمة المرور؟", + "recover": "استعادة", + "forgetPasswordRecover": "نسيت كلمة المرور؟ استعادة", + "editAccount": "تعديل الحساب", + "change": "تغيير", + "verifyAccount": "التحقق من الحساب", + "login": "تسجيل دخول", + "log_in": "تسجيل الدخول", + "welcomeMessage": "مرحبا", + "welcomeDes": "أنت مكان واحد لكل ما تحتاجه سيارتك", + "forgetPass": "نسيت كلمة المرور ؟", + "enterPhoneNumber": "رقم جوال ", + "phoneNumberVerified": "تم التحقق من الجوال", + "verifyNewPassword": "التحقق من كلمة المرور", + "EnterPass": "ادخل كلمة المرور", + "send": "إرسال", + "retrivePassword": "استرجع كلمة المرور بإحدى الطرق التالية", + "retriveOnPhone": "سوف نرسل الاختيار إلى رقم هاتفك المحمول المسجل", + "retriveOnEmail": "سوف نرسل الاختيار إلى عنوان بريدك الإلكتروني المسجل", + "enterPhoneForVerfication": "الرجاء إدخال رقم هاتفك وسنرسل لك رمز التحقق", + "selectYourCountry": "اختر بلدك", + "welcomeBack": "مرحبًا بعودتك!!!", + "alreadySigned": " تم تسجيل الدخول", + "emailChangedSuccessfully": "تم تغيير الايميل بنجاح", + "passwordIsUpdated": "تم تحجيث كلمة المرور", + "passwordShouldContains": "كلمة المرور يجب ان تحتوي على رمز رقم حرف كبير حرف صغير", + " successfullyRegistered": "تم التسجيل بنجاح", + "pleaseEnterSamePassword": "ادخل كلمة مرور مطابقه", + "firstNameMandatory": "ادخل الأسم الأول ", + "surnameNameMandatory": "ادخل اسم العائله", + "passwordNameMandatory": "ادخل كلمة المرور", + "enterValidEmail": "ادخل ايميل صحيح", + "pleaseAcceptTerms": "يجب الموافقه على الشروط", + "emailVerified": "تم التحقق من الايميل بنجاح", + "selectMethod": "اختر", + "emailAddress": "ايميل", + "loginSelection": "اختر", + "selectCountryCode": "اختر رمز الدوله", + "selectProviderRole": "اختر نوع الخدمه", + "addPhoneNo": "اضف الهاتف", + "onlyProviderApp": "نأسف هذا التطبيق فقط لمقدمي الخدمات", + "imageUploaded": "تم تحميل الصوره", + "fileLarger": "1KB حجم الملف اكبر من", + "account": "الحساب", + "edit": "تعديل", + "imageDeleted": "تم حذف الصوره", + "dashboard": "الصفحه الرئيسيه", + "pickAddress": "اختر العنوان", + "pickLocation": "اختر الموقع", + "save": "حفظ", + "defineServices": "تحديد الخدمات", + "selectBranch ": "اختر الفرع", + "selectServiceCategory": "اختر فئة الخدمة", + "defineBranches": "تحديد الفروع", + "defineProviders": "تحديد الموفرين", + "closeAccount": "اغلاق الحساب", + "createBranch": "انشاء فرع", + "updateBranch": "فرع التحديث", + "address": "العنوان", + "branchDescription": "وصف الفرع", + "branchName": "اسم الفرع", + "chooseCity": "اختر المدينه", + "chooseCountry": "اختر الدوله", + "selectAttachment": "اختيار مرفق", + "somethingWrong": "هناك خطأ ما", + "documentsUploaded": "تم ارفاق الملف بنجاح", + "update": "تحديث", + "termsOfService": "من خلال إنشاء حساب فإنك توافق على", + "terms": "بنود الخدمة وخصوصية السياسة", + "profileMsg": "أدخل التفاصيل أدناه وأكمل معلومات الملف الشخصي", + "branchInfo": "معلومات الفرع و الخدمات", + "profileCompleted": "الملف الشخصي مكتمل", + "selectLocationMap": "اختر الموقع", + "licensesAndCertifications": "الرخص و الشهادات", + "completeProfile1": "اكمل الملف الشخصي 1/3", + "completeProfile2": "اكمل الملف الشخصي 2/3", + "completeProfile3": "اكمل الملف الشخصي 3/3", + "userInformation": "معلومات المتسخدم", + "faceRecognition": "تحقق مع بصمة الوجه", + "fingerPrint": "تحقق مع بصمة الاصبع", + "whatsapp": "تحقق مع Whatsapp", + "SMS": "رسائل قصيره", + "selectRole": "حدد الدور", + "userRoleOrTitle": "عنوان المستخدم", + "codeSentToEmail": "تم ارسال الرمز للايميل", + "number": "موبايل", + "phoneNumber": "رقم الهاتف", + "english": "English", + "provider": "Provider", + "title": "Hello", + "msg": "Hello {} in the {} world ", + "msg_named": "{} are written in the {lang} language", + "clickMe": "Click me", + "profile": { + "reset_password": { + "label": "Reset Password", + "username": "Username", + "password": "password" + } + }, + "clicked": { + "zero": "You clicked {} times!", + "one": "You clicked {} time!", + "two": "You clicked {} times!", + "few": "You clicked {} times!", + "many": "You clicked {} times!", + "other": "You clicked {} times!" + }, + "amount": { + "zero": "Your amount : {} ", + "one": "Your amount : {} ", + "two": "Your amount : {} ", + "few": "Your amount : {} ", + "many": "Your amount : {} ", + "other": "Your amount : {} " + }, + "gender": { + "male": "Hi man ;) ", + "female": "Hello girl :)", + "with_arg": { + "male": "Hi man ;) {}", + "female": "Hello girl :) {}" + } + }, + "reset_locale": "Reset Language", + "insert_otp_code": "ادخل الرمز", + "type_code": "الرجاء كتابة الرمز الذي أرسلناه إلى", + "resend_code": "أعد إرسال الرمز", + "check_code": "التحقق من الشفرة", + "time_will_expire": "إعادة إرسال الرمز بتنسيق", + "sec" : "ثانية", + "no_city_available": "لا توجد مدينة متاحة لهذا البلد", + "branch_created": "تم إنشاء الفرع بنجاح", + "branch_updated": "تم تحديث الفرع بنجاح", + "branch_deleted": "تم حذف الفرع بنجاح", + "dashboard_main": "لوحة القيادة / الصفحة الرئيسية", + "logo_brand": "الشعار / العلامة التجارية", + "remove": "إزالة", + "no_branch": "لم يتم إضافة فرع حتى الآن", + "login_once": "الرجاء تسجيل الدخول مرة واحدة", + "defineLicenese": "تحميل التراخيص والشهادات", + "description": "وصف", + "attachFile": "أرفق ملف", + "branchLocation": "معلومات الفرع والموقع", + "tapToEdit": "انقر للتعديل", + "myServiceBranches": "فروع خدمتي", + "enter_licence_detail": "الرجاء إدخال تفاصيل السجلات التجارية وإرفاق صور الترخيص", + "country": "بلد", + "city": "مدينة", + "editServices": "تحرير الخدمات" +} diff --git a/resources/en-US.json b/resources/en-US.json new file mode 100644 index 0000000..6eb9fc0 --- /dev/null +++ b/resources/en-US.json @@ -0,0 +1,183 @@ +{ + "firstTimeLogIn": "First Time Log In", + "signUp": "Register", + "changeMobile": "Change Mobile", + "notifications": "Notifications", + "general": "General", + "defineLicences": "Register Licences", + "dealershipSettings": "Dealership Settings", + "changePassword": "Change Password", + "retrievePassword": "Retrieve Password", + "changeEmail": "Change Email", + "verify": "Verify", + "verified": "Verified", + "signOut": "Sign Out", + "enterEmail": "Enter Email and Password", + "enterNewEmail": "Enter New Email", + "enterNewPassword": "Enter New Password", + "enterCurrentPassword": "Enter Current Password", + "enterOldPassword": "Enter Old Password", + "confirm": "Confirm", + "completeProfile": "Complete Profile", + "enterNewPhoneNumber": "Enter New Phone Number", + "enterPhoneNumber": "Enter the login credentials", + "continu": "Continue", + "confirmPassword": "Confirm Password", + "createPassword": "Create Password", + "email": "Email", + "firstName": "First Name *", + "surname": "Surname *", + "confirmPass": "Confirm Password *", + "createPass": "Create Password *", + "newPassword": "New Password", + "forgetPassword": "Forget Password", + "forgetPasswordQ": "Forget Password?", + "recover": "Recover", + "forgetPasswordRecover": "Forget Password? Recover", + "editAccount": "Edit Account", + "change": "Change", + "verifyAccount": "Verify Account", + "login": "Login", + "log_in": "Log In", + "welcomeMessage": "Welcome To Mowater", + "welcomeDes": "You one stop place all your car needs", + "forgetPass": "Forget Password ?", + "phoneNumberVerified": "Phone Number Verified", + "verifyNewPassword": "Verify New Password", + "send": "Send", + "EnterPass": "Enter Password ?", + "retrivePassword": "Retrive password by one of following method", + "retriveOnPhone": "We will send the opt to your registered mobile number", + "retriveOnEmail": "We will send the opt to your registered email address", + "enterPhoneForVerfication": "Please enter your phone number We will send you the verification code", + "selectYourCountry": "Select Your Country", + "welcomeBack": "Welcome Back!!!", + "alreadySigned": " Already Signed Up and Logged In", + "emailChangedSuccessfully": "Email is Changed Successfully", + "passwordIsUpdated": "Password is Updated", + "passwordShouldContains": "Password Should contains Character, Number, Capital and small letters,", + " successfullyRegistered": " Successfully Registered, Please login once,", + "pleaseEnterSamePassword": "Please enter same password", + "firstNameMandatory": "First name is mandatory", + "surnameNameMandatory": "Surname is mandatory", + "passwordNameMandatory": "Password is mandatory", + "enterValidEmail": "Enter Valid Email", + "pleaseAcceptTerms": "Please accept terms", + "emailVerified": "Email is verified successfully", + "selectMethod": "Select Method", + "emailAddress": "Email Address", + "loginSelection": "Login Selection", + "selectCountryCode": "Please select Country Code", + "selectProviderRole": "Please select Provider Role", + "addPhoneNo": "Please add Phone No", + "onlyCustomerApp": "Sorry, Only Customer's can log in this app", + "imageUploaded": "Image is uploaded", + "fileLarger": "File is larger then 1KB", + "account": "Account", + "edit": "EDIT", + "imageDeleted": "Image is Deleted", + "dashboard": "Dashboard/Main Page", + "pickAddress": "Pick Address", + "pickLocation": "Pick Location", + "save": "Save", + "defineServices": "Define Services", + "selectBranch ": "Select Branch ", + "selectServiceCategory": "Select Service Category", + "defineBranches": "Define Branches", + "defineProviders": "Define Providers", + "closeAccount": "Close Account", + "createBranch": "Create Branch", + "updateBranch": "Update Branch", + "address": "Address", + "branchDescription": "Branch Description", + "branchName": "Branch Name", + "chooseCity": "Select City", + "chooseCountry": "Choose Country", + "selectAttachment": "Select Attachment", + "somethingWrong": "Something went wrong", + "documentsUploaded": "Documents uploaded successfully", + "update": "Update", + "termsOfService": "By creating an account you agree to our", + "terms": "Terms of Service and Privacy Policy", + "profileMsg": "Enter the details below and complete the profile info", + "branchInfo": "Branch Info and Services", + "profileCompleted": "Profile is Completed", + "selectLocationMap": "Select Location Map", + "licensesAndCertifications": "licenses & certifications", + "completeProfile1": "Complete Profile 1/3", + "completeProfile2": "Complete Profile 2/3", + "completeProfile3": "Complete Profile 3/3", + "userInformation": "User Information", + "provider": "Provider", + "faceRecognition": "Face Recognition", + "fingerPrint": "Finger Print", + "whatsapp": "With Whatsapp", + "SMS": "With SMS", + "selectRole": "Choose Role", + "userRoleOrTitle": "User role or title", + "codeSentToEmail": "Code is sent to email", + "number": "Number", + "phoneNumber": "Phone Number", + "english": "عربي", + "title": "Hello", + "msg": "Hello {} in the {} world ", + "msg_named": "{} are written in the {lang} language", + "clickMe": "Click me", + "profile": { + "reset_password": { + "label": "Reset Password", + "username": "Username", + "password": "password" + } + }, + "clicked": { + "zero": "You clicked {} times!", + "one": "You clicked {} time!", + "two": "You clicked {} times!", + "few": "You clicked {} times!", + "many": "You clicked {} times!", + "other": "You clicked {} times!" + }, + "amount": { + "zero": "Your amount : {} ", + "one": "Your amount : {} ", + "two": "Your amount : {} ", + "few": "Your amount : {} ", + "many": "Your amount : {} ", + "other": "Your amount : {} " + }, + "gender": { + "male": "Hi man ;) ", + "female": "Hello girl :)", + "with_arg": { + "male": "Hi man ;) {}", + "female": "Hello girl :) {}" + } + }, + "reset_locale": "Reset Language", + "insert_otp_code": "Enter the code", + "type_code": "Please type the code we sent to", + "resend_code": "Resend Code", + "check_code": "Check Code", + "time_will_expire": "Resend code in", + "sec" : "sec", + "no_city_available": "No City Available for this country", + "branch_created": "Branch is successfully created", + "branch_updated": "Branch is successfully Updated", + "branch_deleted": "Branch is successfully Deleted", + "dashboard_main": "Dashboard/Main Page", + "logo_brand": "Logo/Brand", + "remove": "Remove", + "no_branch": "No Branch Added Yet", + "login_once": "Please login once", + "defineLicenese": "Upload Licenses and Certificates", + "description": "Description", + "attachFile": "Attach File", + "branchLocation": "Branch info and Location", + "tapToEdit": "Tap to edit", + "myServiceBranches": "My Service Branches", + "enter_licence_detail": "Please enter the detail for commercial records and attach the license images", + "country": "country", + "city": "city", + "editServices": "Edit Services" +}