diff --git a/.github/workflows/build_release.yml b/.github/workflows/build_release.yml new file mode 100644 index 0000000..cccc1c1 --- /dev/null +++ b/.github/workflows/build_release.yml @@ -0,0 +1,33 @@ +name: Build and Release APK + +on: + push: + branches: + - master + +jobs: + build: + runs-on: ubuntu-latest + + steps: + - name: Checkout code + uses: actions/checkout@v2 + + - name: Set up Flutter + uses: subosito/flutter-action@v2 + with: + flutter-version: '3.13.0' # Adjust this to your Flutter version + + - name: Build APK + run: flutter build apk --release + + - name: Create Release + id: create_release + uses: softprops/action-gh-release@v1 + with: + files: build/app/outputs/flutter-apk/app-release.apk + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + + - name: Get Release URL + run: echo "Release URL: ${{ steps.create_release.outputs.upload_url }}" diff --git a/.gradle/buildOutputCleanup/cache.properties b/.gradle/buildOutputCleanup/cache.properties deleted file mode 100644 index 00990ad..0000000 --- a/.gradle/buildOutputCleanup/cache.properties +++ /dev/null @@ -1,2 +0,0 @@ -#Sat Mar 06 22:19:25 EET 2021 -gradle.version=6.1.1 diff --git a/.vscode/launch.json b/.vscode/launch.json new file mode 100644 index 0000000..27c8652 --- /dev/null +++ b/.vscode/launch.json @@ -0,0 +1,26 @@ +{ + "configurations": [ + { + "name": "Flutter Debug", + "type": "dart", + "request": "launch", + "program": "lib/main.dart", + "flutterMode": "debug" + }, + { + "name": "Flutter Profile", + "type": "dart", + "request": "launch", + "program": "lib/main.dart", + "flutterMode": "profile" + }, + + { + "name": "Flutter Release", + "type": "dart", + "request": "launch", + "program": "lib/main.dart", + "flutterMode": "release" + } + ] +} \ No newline at end of file diff --git a/.vscode/settings.json b/.vscode/settings.json new file mode 100644 index 0000000..7a55dae --- /dev/null +++ b/.vscode/settings.json @@ -0,0 +1,14 @@ +{ + "[dart]": { + "editor.tabSize": 2, + "editor.insertSpaces": true, + "editor.detectIndentation": false, + "editor.suggest.insertMode": "replace", + "editor.defaultFormatter": "Dart-Code.dart-code", + "editor.inlayHints.enabled": "offUnlessPressed", + "editor.formatOnSave": true, + "editor.codeActionsOnSave": { + "source.fixAll": true + } + } +} \ No newline at end of file diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..f5fba8f --- /dev/null +++ b/Makefile @@ -0,0 +1,11 @@ + +generate_localization: + flutter pub run easy_localization:generate -S "assets/translations" -O "lib/src/translations" + +generate_localization_keys: + flutter pub run easy_localization:generate -S "assets/translations" -O "lib/src/translations" -o "locale_keys.g.dart" -f keys + +gen_translate: generate_localization generate_localization_keys + +flutter_generate: + flutter packages pub run build_runner build --delete-conflicting-outputs diff --git a/android/app/build.gradle b/android/app/build.gradle index f1521a2..cb4b12e 100644 --- a/android/app/build.gradle +++ b/android/app/build.gradle @@ -71,7 +71,6 @@ android { release { signingConfig signingConfigs.release minifyEnabled true - useProguard true proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' } diff --git a/android/app/src/main/AndroidManifest.xml b/android/app/src/main/AndroidManifest.xml index 842de41..2dde25f 100644 --- a/android/app/src/main/AndroidManifest.xml +++ b/android/app/src/main/AndroidManifest.xml @@ -2,6 +2,7 @@ package="com.mazen.livine"> - - + - - + diff --git a/android/app/src/main/res/xml/filepaths.xml b/android/app/src/main/res/xml/filepaths.xml new file mode 100644 index 0000000..b3abc6b --- /dev/null +++ b/android/app/src/main/res/xml/filepaths.xml @@ -0,0 +1,4 @@ + + + + \ No newline at end of file diff --git a/android/app/src/main/res/xml/network_security_config.xml b/android/app/src/main/res/xml/network_security_config.xml new file mode 100644 index 0000000..dca93c0 --- /dev/null +++ b/android/app/src/main/res/xml/network_security_config.xml @@ -0,0 +1,4 @@ + + + + \ No newline at end of file diff --git a/android/build.gradle b/android/build.gradle index d499190..beada5c 100644 --- a/android/build.gradle +++ b/android/build.gradle @@ -1,12 +1,12 @@ buildscript { - ext.kotlin_version = '1.6.10' + ext.kotlin_version = '1.7.10' repositories { google() mavenCentral() } dependencies { - classpath 'com.android.tools.build:gradle:4.1.0' + classpath 'com.android.tools.build:gradle:7.2.0' classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version" } @@ -25,6 +25,6 @@ subprojects { project.evaluationDependsOn(':app') } -task clean(type: Delete) { +tasks.register("clean", Delete) { delete rootProject.buildDir } diff --git a/android/gradle.properties b/android/gradle.properties index 94adc3a..ffbfe84 100644 --- a/android/gradle.properties +++ b/android/gradle.properties @@ -1,3 +1,3 @@ -org.gradle.jvmargs=-Xmx1536M android.useAndroidX=true android.enableJetifier=true +org.gradle.jvmargs=-Xmx4608m diff --git a/android/gradle/wrapper/gradle-wrapper.properties b/android/gradle/wrapper/gradle-wrapper.properties index cc5527d..6b66533 100644 --- a/android/gradle/wrapper/gradle-wrapper.properties +++ b/android/gradle/wrapper/gradle-wrapper.properties @@ -3,4 +3,4 @@ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-7.4-all.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-7.5-all.zip diff --git a/assets/images/difficulty/sad.png b/assets/images/difficulty/sad.png deleted file mode 100644 index 1767962..0000000 Binary files a/assets/images/difficulty/sad.png and /dev/null differ diff --git a/assets/images/difficulty/smile.png b/assets/images/difficulty/smile.png deleted file mode 100644 index d1ba963..0000000 Binary files a/assets/images/difficulty/smile.png and /dev/null differ diff --git a/assets/images/difficulty/wow.png b/assets/images/difficulty/wow.png deleted file mode 100644 index be1897c..0000000 Binary files a/assets/images/difficulty/wow.png and /dev/null differ diff --git a/assets/images/icon/pristine.png b/assets/images/icon/pristine.png deleted file mode 100644 index 8fba438..0000000 Binary files a/assets/images/icon/pristine.png and /dev/null differ diff --git a/assets/images/icons/chief_hat.svg b/assets/images/icons/chief_hat.svg new file mode 100644 index 0000000..80971e4 --- /dev/null +++ b/assets/images/icons/chief_hat.svg @@ -0,0 +1,3 @@ + + + \ No newline at end of file diff --git a/assets/images/windows/login.webp b/assets/images/windows/login.webp deleted file mode 100644 index 0069099..0000000 Binary files a/assets/images/windows/login.webp and /dev/null differ diff --git a/assets/images/windows/register.webp b/assets/images/windows/register.webp deleted file mode 100644 index ee7bd22..0000000 Binary files a/assets/images/windows/register.webp and /dev/null differ diff --git a/assets/model/labels.txt b/assets/model/labels.txt deleted file mode 100644 index b1df57a..0000000 --- a/assets/model/labels.txt +++ /dev/null @@ -1,2 +0,0 @@ -0 Healthy -1 UnHealthy \ No newline at end of file diff --git a/assets/model/model.tflite b/assets/model/model.tflite deleted file mode 100644 index 1173942..0000000 Binary files a/assets/model/model.tflite and /dev/null differ diff --git a/assets/translations/ar.json b/assets/translations/ar.json deleted file mode 100644 index 8204941..0000000 --- a/assets/translations/ar.json +++ /dev/null @@ -1,85 +0,0 @@ -{ - "Welcome": "اهلا بك،", - "Settings": "الاعدادات", - "Logout": "تسجيل الخروج", - "Profile": "الحساب الشخصي", - "Languages": "اللغات", - "Theme": "الوضع", - "Feedback": "إبلاغ", - "Report_a_bug": "إبلاغ عن مشكلة ", - "Misc": "متفرقات", - "Terms_and_conditions": "الأحكام والشروط", - "Privacy_Policy": "سياسة الخصوصية", - "Info": "عن البرنامج", - "Version": "النسخة", - "Language": "اللغة", - "General": "عام", - "Breakfast": "الفطار", - "Dinner": "العشاء", - "Lunch": "الغذاء", - "Snacks": "وجبات خفيفة", - "Ingridents": "المكونات", - "Video": "فيديو", - "Shakshuka": "شكشوكة", - "Crustless_Quiche": "كيشي بدون قشرة", - "Burrito": "بوريتو", - "Baked_Oatmeal": "شوفان مشوي", - "Apple_Cinnamon_Oat": "التفاح بالقرفة والشوفان", - "Banana_Bread": "خبر بالموز", - "Waffles": "بسكويتات الوفل", - "Wild_Mushroom_Risotto": "ريزوتو بالفطر ", - "Grilled_Steak_Tortilla_Salad": "سلطة تورتيلا ستيك مشوي", - "Feta_Shrimp_and_Polenta": "روبيان فيتا وبولينتا", - "Black_Bean_Soup": "شربة فول", - "Bass_With_Radish_Salsa": "باس مع صلصة الفجل", - "Eggplant_Parmesan": "بارما الباذنجان", - "Roasted_Cauliflower_Tacos": "قرنبيط محمص تاكو", - "Carrot_with_Radish_Salad": "سلطة جزر بالفجل", - "Salmon_Salad": "سلطة سلمون", - "Panzanella": "بانزانيلا", - "Caesar_Salad": "سلطة سيزر", - "Mixed_Nuts": "مكسرات مشكله", - "Red_pepper_guacamole": "الفلفل الأحمر جواكامولي", - "Yogurt_with_mixed_berries": "زبادي مع توت مشكل", - "Apple_slices_with_peanut": "شرائح التفاح مع الفول السوداني", - "Cottage_cheese": "جبن", - "Celery_sticks_with_Cheese": "أعواد الكرفس بالجبن", - "System_Prefrence": "الوضع النظام ", - "Light_Mode": "الوضع الضوء", - "Dark_Mode": "الوضع المظلم", - "life_pristine": "اجعل حياتك نقية", - "Pristine_access": "يمنحك النظام الوصول إلى ميزاتنا باهظة الثمن بالكامل", - "gateway": "اختار طريقة الدفع", - "three_months": "3شهور", - "total_price": "السعر الكلي", - "monthly": "شهريا", - "cancel_sub": "يمكنك إلغاء اشتراكك في أي وقت من خلال google pay", - "choose_content": "اختار المحتوي", - "Iam_a": "انا", - "healthy": "تريد أن تحصل على وصفات صحية بجانب المكونات ومقاطع الفيديو", - "patient": "تريد أن تحصل علي وصفات علي حسب حالتك الصحية مع مكونات و مقاطع الفيديو", - "username": "اسم المستخدم", - "password": "كلمة السر", - "Forget_your_password": "نسيت كلمة المرور ؟", - "Sign_in": "تسجيل الدخول", - "no_account": "ليس لديك حساب ؟", - "Sign_up": "سجل الآن", - "have_an_account": "هل لديك حساب ؟", - "terms1": "من خلال إنشاء حساب ، فإنك توافق بالفعل على", - "terms2": "الأحكام والشروط", - "notfications": "إشعارات", - "ask_me_how_i_feel": "اسالني كيف اشعر كل يوم", - "continue_as_guest": "سجل كضيف", - "change_password": "تغيير كلمة المرور", - "enter_token": "أدخل الرمز الخاص بك", - "validate_token": "التحقق من صحة الرمز", - "Reset_pass": "إعادة تعيين كلمة المرور", - "pass_confirm": "تأكيد كلمة المرور", - "per_situation": "حالة معينة", - "Favorites": "المفضلة", - "delete_account": "حذف الحساب", - "account": "الحساب", - "update": "تحديث", - "livine": "ليفين", - "About_Livine": "عن ليفين" -} \ No newline at end of file diff --git a/assets/translations/en.json b/assets/translations/en.json deleted file mode 100644 index 1d9ada1..0000000 --- a/assets/translations/en.json +++ /dev/null @@ -1,85 +0,0 @@ -{ - "Welcome": "Welcome,", - "Settings": "Settings", - "Logout": "Logout", - "Profile": "Profile", - "Languages": "Languages", - "Theme": "Theme", - "Feedback": "Feedback", - "Report_a_bug": "Report a bug ", - "Misc": "Misc", - "Terms_and_conditions": "Terms and Conditions", - "Privacy_Policy": "Privacy Policy", - "Info": "Info", - "Version": "Version", - "Language": "Language", - "General": "General", - "Breakfast": "Breakfast", - "Dinner": "Dinner", - "Lunch": "Lunch", - "Snacks": "Snacks", - "Ingridents": "Ingridents", - "Video": "Video", - "Shakshuka": "Shakshuka", - "Crustless_Quiche": "Crustless Quiche", - "Burrito": "Burrito", - "Baked_Oatmeal": "Baked Oatmeal", - "Apple_Cinnamon_Oat": "Apple Cinnamon Oat", - "Banana_Bread": "Banana Bread", - "Waffles": "Waffles", - "Wild_Mushroom_Risotto": "Wild Mushroom Risotto", - "Grilled_Steak_Tortilla_Salad": "Grilled Steak Tortilla Salad", - "Feta_Shrimp_and_Polenta": "Feta Shrimp and Polenta", - "Black_Bean_Soup": "Black Bean Soup", - "Bass_With_Radish_Salsa": "Bass With Radish Salsa", - "Eggplant_Parmesan": "Eggplant Parmesan", - "Roasted_Cauliflower_Tacos": "Roasted Cauliflower Tacos", - "Carrot_with_Radish_Salad": "Carrot with Radish Salad", - "Caesar_Salad": "Caesar Salad", - "Salmon_Salad": "Salmon Salad", - "Panzanella": "Panzanella", - "Mixed_Nuts": "Mixed Nuts", - "Red_pepper_guacamole": "Red pepper guacamole", - "Yogurt_with_mixed_berries": "Yogurt with mixed berries", - "Apple_slices_with_peanut": "Apple slices with peanut", - "Cottage_cheese": "Cottage cheese", - "Celery_sticks_with_Cheese": "Celery sticks with Cheese", - "System_Prefrence": "System preference", - "Light_Mode": "Light Mode", - "Dark_Mode": "Dark Mode", - "life_pristine": "Make your life Pristine", - "Pristine_access": "Pristine give u access to our full expensive features", - "gateway": "Choose Gateway", - "three_months": "3 months", - "total_price": "total price", - "monthly": "Monthly", - "cancel_sub": "You can cancel your subscription at any time through google pay", - "choose_content": "Choose your content", - "Iam_a": "I'm a", - "healthy": "You want to be provided by healthy recipes that you should consume to remain healthy", - "patient": "You want to be provided per your health situation", - "username": "Username", - "password": "Password", - "Forget_your_password": "Forget your password ?", - "Sign_in": "Sign In", - "no_account": "Don't Have an account ?", - "Sign_up": "Sign Up", - "have_an_account": "Already have an account ?", - "terms1": "By creating an account , you already agree on", - "terms2": "Terms and Conditions", - "notfications": "Notfications", - "ask_me_how_i_feel": "Ask me how I feel everyday", - "continue_as_guest": "Continue as GUEST", - "change_password": "Change your password", - "enter_token": "Enter Your Code", - "validate_token": "Validate Code", - "Reset_pass": "Reset password", - "pass_confirm": "Password Confirmation", - "per_situation": "Per Situation", - "Favorites": "Favorites", - "delete_account": "Delete account", - "account": "Account", - "update": "Update", - "livine": "Livine", - "About_Livine": "About Livine" -} \ No newline at end of file diff --git a/debug/app.android-arm.symbols b/debug/app.android-arm.symbols new file mode 100644 index 0000000..5032a32 Binary files /dev/null and b/debug/app.android-arm.symbols differ diff --git a/debug/app.android-arm64.symbols b/debug/app.android-arm64.symbols new file mode 100644 index 0000000..9ef43f7 Binary files /dev/null and b/debug/app.android-arm64.symbols differ diff --git a/debug/app.android-x64.symbols b/debug/app.android-x64.symbols new file mode 100644 index 0000000..524c435 Binary files /dev/null and b/debug/app.android-x64.symbols differ diff --git a/l10n.yaml b/l10n.yaml new file mode 100644 index 0000000..db9756a --- /dev/null +++ b/l10n.yaml @@ -0,0 +1,3 @@ +arb-dir: lib/src/l10n +template-arb-file: app_en.arb +output-localization-file: app_localizations.dart diff --git a/lib/main.dart b/lib/main.dart index 9157ef4..3071bf7 100644 --- a/lib/main.dart +++ b/lib/main.dart @@ -1,9 +1,8 @@ import 'dart:io'; -import 'package:easy_localization/easy_localization.dart'; import 'package:flutter/foundation.dart'; +import 'package:livine/src/shared/device_info/device_info.dart'; -import 'package:google_mobile_ads/google_mobile_ads.dart'; import 'package:livine/src/shared/error_django/error_django.dart'; import 'package:window_manager/window_manager.dart'; @@ -15,7 +14,6 @@ import 'package:shared_preferences/shared_preferences.dart'; import 'src/constants/constants.dart'; import 'src/shared/cache/cache_helper.dart'; import 'src/features/get_recipes/application/vegan_service.dart'; -import 'src/translations/codegen_loader.g.dart'; import 'package:device_preview/device_preview.dart'; Future main() async { @@ -63,22 +61,15 @@ Future main() async { tools: [ ...DevicePreview.defaultTools, ], - builder: (context) => EasyLocalization( - supportedLocales: const [Locale('en'), Locale('ar')], - path: 'assets/translations', - fallbackLocale: const Locale('en'), - assetLoader: const CodegenLoader(), - child: const MyApp()), + builder: (context) => const MyApp(), ), ), ); - await EasyLocalization.ensureInitialized(); await CacheHelper.init(); - + await GetDeviceInfo.init(); final isVegan = await container.read(veganServiceProvider).getIsVegan(); container.read(isVeganProvider.notifier).state = isVegan; if (Platform.isAndroid) { - MobileAds.instance.initialize(); notificationControl.init(); } } diff --git a/lib/src/app.dart b/lib/src/app.dart index 96a8aa1..fa454ac 100644 --- a/lib/src/app.dart +++ b/lib/src/app.dart @@ -1,15 +1,18 @@ import 'dart:io'; import 'dart:ui' as ui; -import 'package:easy_localization/easy_localization.dart'; +import 'package:dynamic_color/dynamic_color.dart'; import 'package:flutter/foundation.dart'; import 'package:flutter/material.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart'; import 'package:responsive_framework/responsive_framework.dart'; - +import '../src/features/settings/presentation/theme/domain/theme_notifier.dart'; import 'features/settings/data/theme.dart'; import 'routing/routes.dart'; import 'shared/styles/lib_color_schemes.g.dart'; import 'shared/windows/title_bar.dart'; +import 'package:flutter_gen/gen_l10n/app_localizations.dart'; + +import 'translations/domain/translation_provider.dart'; class MyApp extends StatelessWidget { const MyApp({Key? key}) : super(key: key); @@ -26,34 +29,50 @@ class MaterialAppWithTheme extends ConsumerWidget { @override Widget build(BuildContext context, WidgetRef ref) { final theme = ref.watch(themeProvider); - final router = baseRoutes; - + Color themeSeed = ref.watch(themeSeedProvider) as Color; + bool isDynamic = ref.watch(dynamicThemeProvider) as bool; + final localeNotifier = ref.watch(localeNotifierProvider); return _App( theme: theme, enableCustomTitleBar: Platform.isWindows == true, - builder: (context) => MaterialApp.router( - showPerformanceOverlay: kProfileMode == true, - routeInformationProvider: router.routeInformationProvider, - useInheritedMediaQuery: true, - routeInformationParser: router.routeInformationParser, - routerDelegate: router.routerDelegate, - localizationsDelegates: context.localizationDelegates, - supportedLocales: context.supportedLocales, - locale: context.locale, - builder: (context, widget) => ResponsiveWrapper.builder( - ClampingScrollWrapper.builder(context, widget!), - breakpoints: const [ - ResponsiveBreakpoint.resize(480, name: MOBILE), - ResponsiveBreakpoint.autoScale(1000, name: TABLET), - ResponsiveBreakpoint.resize(1200, name: DESKTOP), - ]), - themeMode: theme.themeMode, - theme: ThemeData( - useMaterial3: true, - colorScheme: lightColorScheme, - ), - darkTheme: ThemeData(useMaterial3: true, colorScheme: darkColorScheme), + builder: (context) => DynamicColorBuilder( + builder: (ColorScheme? lightDynamic, ColorScheme? darkDynamic) { + print(lightDynamic.toString()); + + return MaterialApp.router( + showPerformanceOverlay: kProfileMode == true, + routeInformationProvider: router.routeInformationProvider, + routeInformationParser: router.routeInformationParser, + routerDelegate: router.routerDelegate, + locale: localeNotifier, + localizationsDelegates: AppLocalizations.localizationsDelegates, + supportedLocales: TranslationRepo.supportedLocales, + debugShowCheckedModeBanner: false, + builder: (context, child) => ResponsiveBreakpoints.builder( + child: child!, + breakpoints: [ + const Breakpoint(start: 0, end: 480, name: MOBILE), + const Breakpoint(start: 481, end: 1280, name: TABLET), + const Breakpoint(start: 1281, end: 1920, name: DESKTOP), + ], + ), + themeMode: theme.themeMode, + theme: ThemeData( + fontFamily: 'Kine', + useMaterial3: true, + colorSchemeSeed: + isDynamic ? lightDynamic?.primary ?? themeSeed : themeSeed, + ), + darkTheme: ThemeData( + fontFamily: 'Kine', + useMaterial3: true, + colorSchemeSeed: + isDynamic ? darkDynamic?.primary ?? themeSeed : themeSeed, + brightness: Brightness.dark, + ), + ); + }, ), ); } @@ -70,7 +89,6 @@ class _App extends StatelessWidget { final ThemeNotifer theme; @override Widget build(BuildContext context) { - if (!enableCustomTitleBar) { return builder(context); } @@ -82,18 +100,18 @@ class _App extends StatelessWidget { lightDynamic: lightColorScheme, child: Stack( children: [ - MediaQuery.fromWindow( - child: Builder(builder: (context) { - final mediaQueryData = MediaQuery.of(context); - return MediaQuery( - data: mediaQueryData.copyWith( - viewPadding: mediaQueryData.padding - .copyWith(top: mediaQueryData.viewPadding.top + 50), - ), - child: builder(context), - ); - }), - ), + // MediaQuery.fromWindow( + // child: Builder(builder: (context) { + // final mediaQueryData = MediaQuery.of(context); + // return MediaQuery( + // data: mediaQueryData.copyWith( + // viewPadding: mediaQueryData.padding + // .copyWith(top: mediaQueryData.viewPadding.top + 50), + // ), + // child: builder(context), + // ); + // }), + // ), const Align( alignment: Alignment.topCenter, child: TitleBar(), diff --git a/lib/src/common_widgets/auth/auth_widget.dart b/lib/src/common_widgets/auth/auth_widget.dart index 0a46c3f..400a6ba 100644 --- a/lib/src/common_widgets/auth/auth_widget.dart +++ b/lib/src/common_widgets/auth/auth_widget.dart @@ -1,14 +1,14 @@ -import 'package:easy_localization/easy_localization.dart'; import 'package:flutter/material.dart'; import 'package:go_router/go_router.dart'; -import 'package:google_fonts/google_fonts.dart'; -Widget authButton({ +Widget CustomButton({ required void Function() onPressed, required bool isLoading, required String text, Color? color, Color? textColor, + double width = 350, + Widget? icon, required BuildContext context, }) { final theme = Theme.of(context).colorScheme; @@ -18,7 +18,7 @@ Widget authButton({ onPressed: onPressed, color: color ?? theme.primaryContainer, elevation: 0, - minWidth: 350, + minWidth: width, height: 60, shape: RoundedRectangleBorder( borderRadius: BorderRadius.circular(15), @@ -27,14 +27,17 @@ Widget authButton({ ? const CircularProgressIndicator( color: Colors.white, ) - : Text( - text, - style: TextStyle( - fontSize: 15, - fontFamily: context.locale.languageCode == "en" - ? 'Kine' - : GoogleFonts.notoKufiArabic().fontFamily, - color: textColor ?? theme.onPrimaryContainer), + : Row( + mainAxisAlignment: MainAxisAlignment.spaceEvenly, + children: [ + Text( + text, + style: TextStyle( + fontSize: 15, + color: textColor ?? theme.onPrimaryContainer), + ), + icon ?? const SizedBox(), + ], ), ), ); diff --git a/lib/src/common_widgets/no_connection.dart b/lib/src/common_widgets/no_connection.dart index addc98f..b373ecd 100644 --- a/lib/src/common_widgets/no_connection.dart +++ b/lib/src/common_widgets/no_connection.dart @@ -1,8 +1,6 @@ -import 'package:flutter/cupertino.dart'; import 'package:flutter/material.dart'; import 'package:flutter_svg/flutter_svg.dart'; import 'package:hooks_riverpod/hooks_riverpod.dart'; -import 'package:livine/src/common_widgets/auth/auth_widget.dart'; import 'package:livine/src/constants/constants.dart'; import 'package:responsive_framework/responsive_framework.dart'; @@ -53,11 +51,29 @@ class NoConnection extends ConsumerWidget { ResponsiveRowColumnItem( child: Consumer( builder: (context, watch, child) { - return authButton( - context: context, - isLoading: false, - text: "Try again", - onPressed: () => ref.refresh(checkNetworkProvider)); + final theme = Theme.of(context).colorScheme; + return Padding( + padding: const EdgeInsets.symmetric(horizontal: 20.0), + child: MaterialButton( + onPressed: () => ref.refresh(checkNetworkProvider), + color: (null) ?? theme.primaryContainer, + elevation: 0, + minWidth: 350, + height: 60, + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.circular(15), + ), + child: Text( + "Try again", + style: TextStyle( + fontSize: 15, + // fontFamily: context.locale.languageCode == "en" + // ? 'Kine' + // : GoogleFonts.notoKufiArabic().fontFamily, + color: (null) ?? theme.onPrimaryContainer), + ), + ), + ); }, ), ), diff --git a/lib/src/common_widgets/recipe/food_category_widget.dart b/lib/src/common_widgets/recipe/food_category_widget.dart index dbbc589..6bfd06c 100644 --- a/lib/src/common_widgets/recipe/food_category_widget.dart +++ b/lib/src/common_widgets/recipe/food_category_widget.dart @@ -1,8 +1,6 @@ import 'package:cached_network_image/cached_network_image.dart'; -import 'package:easy_localization/easy_localization.dart'; import 'package:flutter/material.dart'; import 'package:go_router/go_router.dart'; -import 'package:google_fonts/google_fonts.dart'; class FoodCategory extends StatelessWidget { const FoodCategory({ @@ -49,9 +47,9 @@ class FoodCategory extends StatelessWidget { style: TextStyle( fontSize: 20.0, color: theme.onSurface, - fontFamily: context.locale.languageCode == "en" - ? 'Kine' - : GoogleFonts.notoKufiArabic().fontFamily, + // fontFamily: context.locale.languageCode == "en" + // ? 'Kine' + // : GoogleFonts.notoKufiArabic().fontFamily, letterSpacing: 1.0), ), ) diff --git a/lib/src/common_widgets/recipe/recipe_card_widget.dart b/lib/src/common_widgets/recipe/recipe_card_widget.dart index 2c83c54..2a9d179 100644 --- a/lib/src/common_widgets/recipe/recipe_card_widget.dart +++ b/lib/src/common_widgets/recipe/recipe_card_widget.dart @@ -1,9 +1,7 @@ import 'dart:ui'; import 'package:cached_network_image/cached_network_image.dart'; -import 'package:easy_localization/easy_localization.dart'; import 'package:flutter/material.dart'; -import 'package:google_fonts/google_fonts.dart'; import '../../constants/constants.dart'; @@ -86,11 +84,7 @@ class _RecipeCardNormalState extends State { style: TextStyle( fontWeight: FontWeight.bold, fontSize: 15.0, - fontFamily: - context.locale.languageCode == "en" - ? 'Kine' - : GoogleFonts.notoKufiArabic() - .fontFamily, + fontFamily: 'Kine', color: Theme.of(context) .colorScheme .onPrimaryContainer), @@ -109,12 +103,7 @@ class _RecipeCardNormalState extends State { widget.time.toUpperCase(), style: TextStyle( fontSize: 12.0, - fontFamily: - context.locale.languageCode == - "en" - ? 'Kine' - : GoogleFonts.notoKufiArabic() - .fontFamily, + fontFamily: 'Kine', color: Theme.of(context) .colorScheme .onPrimaryContainer), @@ -136,12 +125,7 @@ class _RecipeCardNormalState extends State { widget.difficulty.toUpperCase(), style: TextStyle( fontSize: 12.0, - fontFamily: - context.locale.languageCode == - "en" - ? 'Kine' - : GoogleFonts.notoKufiArabic() - .fontFamily, + fontFamily: 'Kine', color: Theme.of(context) .colorScheme .onPrimaryContainer), diff --git a/lib/src/common_widgets/recipe/recipe_details_widgets.dart b/lib/src/common_widgets/recipe/recipe_details_widgets.dart index 3306be8..56655c8 100644 --- a/lib/src/common_widgets/recipe/recipe_details_widgets.dart +++ b/lib/src/common_widgets/recipe/recipe_details_widgets.dart @@ -1,3 +1,4 @@ +import 'package:cached_network_image/cached_network_image.dart'; import 'package:flutter/material.dart'; class IconCard extends StatelessWidget { @@ -7,6 +8,7 @@ class IconCard extends StatelessWidget { required this.color, required this.name, this.takeColor = false, + this.isNetworkImage = false, this.calAmount}) : super(key: key); @@ -14,6 +16,7 @@ class IconCard extends StatelessWidget { final Color color; final bool takeColor; final String name; + final bool isNetworkImage; final String? calAmount; @@ -33,10 +36,15 @@ class IconCard extends StatelessWidget { child: Column( mainAxisAlignment: MainAxisAlignment.spaceEvenly, children: [ - Image.asset( - image, - width: 60, - ), + isNetworkImage + ? CachedNetworkImage( + imageUrl: image, + width: 60, + ) + : Image.asset( + image, + width: 60, + ), if (calAmount != null) Text(calAmount.toString()), FittedBox( child: Text( diff --git a/lib/src/common_widgets/recipe/recipe_grid_view.dart b/lib/src/common_widgets/recipe/recipe_grid_view.dart index 9b36c5e..0fa2252 100644 --- a/lib/src/common_widgets/recipe/recipe_grid_view.dart +++ b/lib/src/common_widgets/recipe/recipe_grid_view.dart @@ -1,7 +1,6 @@ import 'dart:developer'; import 'package:animations/animations.dart'; -import 'package:easy_localization/easy_localization.dart'; import 'package:flutter/material.dart'; import 'package:hooks_riverpod/hooks_riverpod.dart'; import 'package:infinite_scroll_pagination/infinite_scroll_pagination.dart'; @@ -29,7 +28,7 @@ class RecipesGridView extends ConsumerStatefulWidget { } class _RecipesGridViewState extends ConsumerState { - static const _pageSize = 6; + static const _pageSize = 10; final PagingController _pagingController = PagingController(firstPageKey: 1); @override @@ -47,6 +46,7 @@ class _RecipesGridViewState extends ConsumerState { bool guest = ref.watch(guestProvider); final guestRecipes = await ref.watch(getRecipesProvider( + context: context, id: recipesTypeData == 0 ? patientID : recipesTypeData, pageKey: pageKey) .future); @@ -54,10 +54,12 @@ class _RecipesGridViewState extends ConsumerState { final newItems = isGuest == false && guest == false ? await ref.watch(isUserVegan == true ? getVegRecipesProvider( + context: context, id: recipesTypeData == 0 ? patientID : recipesTypeData, pageKey: pageKey) .future : getRecipesProvider( + context: context, id: recipesTypeData == 0 ? patientID : recipesTypeData, pageKey: pageKey) .future) @@ -99,7 +101,6 @@ class _RecipesGridViewState extends ConsumerState { firstPageProgressIndicatorBuilder: (context) => LoadingGridView(), itemBuilder: (context, item, index) { final recipe = item as Recipe; - return OpenContainer( openElevation: 0, closedElevation: 0, @@ -110,18 +111,12 @@ class _RecipesGridViewState extends ConsumerState { transitionDuration: const Duration(milliseconds: 500), closedBuilder: (context, action) => RecipeCardNormal( id: recipe.id, - name: context.locale.languageCode == "en" - ? recipe.name - : recipe.name_in_arabic, + name: recipe.name, foodImage: '${item.imageURL}', - type: context.locale.languageCode == "en" - ? recipe.patient - : recipe.patient_in_arabic, - difficulty: changeDiffName(item.diff, context), - time: context.locale.languageCode == "en" - ? "${recipe.time_taken} min" - : "${recipe.time_taken} دقيقة", - dImage: changeDiffImage(difficulty: recipe.diff), + type: recipe.patient, + difficulty: recipe.difficulty, + time: "${recipe.time_taken} min", + dImage: "$restAPIMedia/${recipe.difficulty_image}", ), ); }, diff --git a/lib/src/common_widgets/recipe/web_view_widget.dart b/lib/src/common_widgets/recipe/web_view_widget.dart index 2fa2248..86c040f 100644 --- a/lib/src/common_widgets/recipe/web_view_widget.dart +++ b/lib/src/common_widgets/recipe/web_view_widget.dart @@ -1,38 +1,33 @@ -import 'package:easy_localization/easy_localization.dart'; import 'package:flutter/material.dart'; import 'package:go_router/go_router.dart'; import 'package:webview_flutter/webview_flutter.dart'; class RecipeVideoWidget extends StatelessWidget { - RecipeVideoWidget({Key? key, required this.url}) : super(key: key); final String url; - - final controller = WebViewController() - ..setJavaScriptMode(JavaScriptMode.unrestricted) - ..setBackgroundColor(const Color(0x00000000)) - ..setNavigationDelegate( - NavigationDelegate( - onProgress: (int progress) { - // Update loading bar. - }, - onPageStarted: (String url) {}, - onPageFinished: (String url) {}, - onWebResourceError: (WebResourceError error) {}, - onNavigationRequest: (NavigationRequest request) { - if (request.url.startsWith('https://www.youtube.com/')) { - return NavigationDecision.prevent; - } - return NavigationDecision.navigate; - }, - ), - ) - ..loadRequest(Uri.parse('https://flutter.dev')); + RecipeVideoWidget({Key? key, required this.url}) : super(key: key); @override Widget build(BuildContext context) { + print(url); + final controller = WebViewController() + // ..setJavaScriptMode(JavaScriptMode.unrestricted) + ..setBackgroundColor(const Color(0x00000000)) + ..setNavigationDelegate( + NavigationDelegate( + onProgress: (int progress) { + // Update loading bar. + }, + onPageStarted: (String url) {}, + onPageFinished: (String url) {}, + onWebResourceError: (WebResourceError error) { + print(error.description); + }, + ), + ) + ..loadRequest(Uri.parse("https://www.youtube.com/watch?v=-B-usxlRJj")); return Scaffold( appBar: AppBar( - title: Text(context.locale.languageCode == "en" ? "Video" : "فيديو"), + title: Text("Video"), leading: IconButton( onPressed: () => context.go('/navigate'), icon: const Icon(Icons.arrow_back)), diff --git a/lib/src/constants/constants.dart b/lib/src/constants/constants.dart index a34257b..789c8ef 100644 --- a/lib/src/constants/constants.dart +++ b/lib/src/constants/constants.dart @@ -1,18 +1,13 @@ import 'package:flutter/material.dart'; import 'package:livine/src/shared/notification_control/notifications_control.dart'; -import '../shared/ads/ads_help.dart'; -import '../features/scan_food/presentation/controllers/image_controller.dart'; -import '../features/scan_food/presentation/controllers/model_controller.dart'; import '../shared/responsive/responsive_controller.dart'; ResponsiveHelper rh = ResponsiveHelper(); -final adHelper = AdHelper(); +// final modelTF = ModelTFLite(); -final modelTF = ModelTFLite(); - -final imageController = ImageController(); +// final imageController = ImageController(); final notificationControl = NotificationControl(); @@ -20,7 +15,8 @@ const restAPIURL = "https://livine2.pythonanywhere.com/api"; const restAPIMedia = "https://livine2.pythonanywhere.com"; -ColorScheme getColorScheme(BuildContext context) { + + +ColorScheme colorScheme(BuildContext context) { return Theme.of(context).colorScheme; } - diff --git a/lib/src/constants/shared_constants.dart b/lib/src/constants/shared_constants.dart index 0618086..225870c 100644 --- a/lib/src/constants/shared_constants.dart +++ b/lib/src/constants/shared_constants.dart @@ -1,3 +1,5 @@ +import 'package:flutter/material.dart'; + import '../shared/cache/cache_helper.dart'; int patientID = CacheHelper.getInt("patientID") ?? 0; @@ -8,3 +10,5 @@ bool username = CacheHelper.getBool("username") ?? false; bool isGuest = CacheHelper.getBool("isGuest") ?? false; bool isBoarded = CacheHelper.getBool("isBoarded") ?? false; + +Object themeColor = CacheHelper.getString("themeColor") ?? Colors.green; diff --git a/lib/src/features/auth/application/auth_service.dart b/lib/src/features/auth/application/auth_service.dart index 67fca1f..765e04e 100644 --- a/lib/src/features/auth/application/auth_service.dart +++ b/lib/src/features/auth/application/auth_service.dart @@ -1,5 +1,7 @@ + // ignore_for_file: use_build_context_synchronously +import 'dart:async'; import 'dart:convert'; import 'dart:developer'; import 'dart:io'; @@ -7,13 +9,13 @@ import 'dart:io'; import 'package:flutter/material.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart'; import 'package:go_router/go_router.dart'; +import 'package:livine/src/features/auth/profiles/data/get_user_data.dart'; import 'package:livine/src/shared/cache/cache_helper.dart'; import '../data/user.dart'; import '../../../constants/constants.dart'; import '../../../constants/shared_constants.dart'; import '../../get_recipes/domain/recipe/recipe.dart'; -import '../profiles/data/get_user_data.dart'; final authHelperProvider = Provider(AuthService.new); @@ -55,7 +57,7 @@ class AuthService { GoRouter.of(context).go('/navigate'); } } else { - GoRouter.of(context).go('/navigate'); + GoRouter.of(context).go('/navigate'); } } else { if (!mounted) return null; @@ -117,10 +119,7 @@ class AuthService { context.go('/login'); } else { - log(error: "Error in logout", response.body); - ScaffoldMessenger.of(context).showSnackBar(const SnackBar( - content: Text("Error logging out"), - )); + logOutAsGuest(context); } } @@ -186,10 +185,9 @@ class AuthService { } } - Future getUserUsername() async { + Future getUserUsername() async{ final userData = await ref.watch(userDataProvider.future); - log(error: "Username", userData.toString()); - + // log(error: "Username", userData.toString()); return userData.username ?? ""; } } diff --git a/lib/src/features/auth/domain/user.dart b/lib/src/features/auth/domain/user.dart index d749bfd..ef10329 100644 --- a/lib/src/features/auth/domain/user.dart +++ b/lib/src/features/auth/domain/user.dart @@ -6,7 +6,7 @@ part 'user.g.dart'; @freezed class UserData with _$UserData { const factory UserData(int? id, String? username, String? email, int? patient, - bool? isVegan) = _UserData; + bool? isVegan, int? points) = _UserData; factory UserData.fromJson(Map json) => _$UserDataFromJson(json); } diff --git a/lib/src/features/auth/domain/user.freezed.dart b/lib/src/features/auth/domain/user.freezed.dart index 3c505bf..d4bdafb 100644 --- a/lib/src/features/auth/domain/user.freezed.dart +++ b/lib/src/features/auth/domain/user.freezed.dart @@ -1,7 +1,7 @@ // coverage:ignore-file // GENERATED CODE - DO NOT MODIFY BY HAND // ignore_for_file: type=lint -// ignore_for_file: unused_element, deprecated_member_use, deprecated_member_use_from_same_package, use_function_type_syntax_for_parameters, unnecessary_const, avoid_init_to_null, invalid_override_different_default_values_named, prefer_expression_function_bodies, annotate_overrides, invalid_annotation_target +// ignore_for_file: unused_element, deprecated_member_use, deprecated_member_use_from_same_package, use_function_type_syntax_for_parameters, unnecessary_const, avoid_init_to_null, invalid_override_different_default_values_named, prefer_expression_function_bodies, annotate_overrides, invalid_annotation_target, unnecessary_question_mark part of 'user.dart'; @@ -25,6 +25,7 @@ mixin _$UserData { String? get email => throw _privateConstructorUsedError; int? get patient => throw _privateConstructorUsedError; bool? get isVegan => throw _privateConstructorUsedError; + int? get points => throw _privateConstructorUsedError; Map toJson() => throw _privateConstructorUsedError; @JsonKey(ignore: true) @@ -35,19 +36,28 @@ mixin _$UserData { /// @nodoc abstract class $UserDataCopyWith<$Res> { factory $UserDataCopyWith(UserData value, $Res Function(UserData) then) = - _$UserDataCopyWithImpl<$Res>; + _$UserDataCopyWithImpl<$Res, UserData>; + @useResult $Res call( - {int? id, String? username, String? email, int? patient, bool? isVegan}); + {int? id, + String? username, + String? email, + int? patient, + bool? isVegan, + int? points}); } /// @nodoc -class _$UserDataCopyWithImpl<$Res> implements $UserDataCopyWith<$Res> { +class _$UserDataCopyWithImpl<$Res, $Val extends UserData> + implements $UserDataCopyWith<$Res> { _$UserDataCopyWithImpl(this._value, this._then); - final UserData _value; // ignore: unused_field - final $Res Function(UserData) _then; + final $Val _value; + // ignore: unused_field + final $Res Function($Val) _then; + @pragma('vm:prefer-inline') @override $Res call({ Object? id = freezed, @@ -55,29 +65,34 @@ class _$UserDataCopyWithImpl<$Res> implements $UserDataCopyWith<$Res> { Object? email = freezed, Object? patient = freezed, Object? isVegan = freezed, + Object? points = freezed, }) { return _then(_value.copyWith( - id: id == freezed + id: freezed == id ? _value.id : id // ignore: cast_nullable_to_non_nullable as int?, - username: username == freezed + username: freezed == username ? _value.username : username // ignore: cast_nullable_to_non_nullable as String?, - email: email == freezed + email: freezed == email ? _value.email : email // ignore: cast_nullable_to_non_nullable as String?, - patient: patient == freezed + patient: freezed == patient ? _value.patient : patient // ignore: cast_nullable_to_non_nullable as int?, - isVegan: isVegan == freezed + isVegan: freezed == isVegan ? _value.isVegan : isVegan // ignore: cast_nullable_to_non_nullable as bool?, - )); + points: freezed == points + ? _value.points + : points // ignore: cast_nullable_to_non_nullable + as int?, + ) as $Val); } } @@ -87,20 +102,25 @@ abstract class _$$_UserDataCopyWith<$Res> implements $UserDataCopyWith<$Res> { _$_UserData value, $Res Function(_$_UserData) then) = __$$_UserDataCopyWithImpl<$Res>; @override + @useResult $Res call( - {int? id, String? username, String? email, int? patient, bool? isVegan}); + {int? id, + String? username, + String? email, + int? patient, + bool? isVegan, + int? points}); } /// @nodoc -class __$$_UserDataCopyWithImpl<$Res> extends _$UserDataCopyWithImpl<$Res> +class __$$_UserDataCopyWithImpl<$Res> + extends _$UserDataCopyWithImpl<$Res, _$_UserData> implements _$$_UserDataCopyWith<$Res> { __$$_UserDataCopyWithImpl( _$_UserData _value, $Res Function(_$_UserData) _then) - : super(_value, (v) => _then(v as _$_UserData)); - - @override - _$_UserData get _value => super._value as _$_UserData; + : super(_value, _then); + @pragma('vm:prefer-inline') @override $Res call({ Object? id = freezed, @@ -108,28 +128,33 @@ class __$$_UserDataCopyWithImpl<$Res> extends _$UserDataCopyWithImpl<$Res> Object? email = freezed, Object? patient = freezed, Object? isVegan = freezed, + Object? points = freezed, }) { return _then(_$_UserData( - id == freezed + freezed == id ? _value.id : id // ignore: cast_nullable_to_non_nullable as int?, - username == freezed + freezed == username ? _value.username : username // ignore: cast_nullable_to_non_nullable as String?, - email == freezed + freezed == email ? _value.email : email // ignore: cast_nullable_to_non_nullable as String?, - patient == freezed + freezed == patient ? _value.patient : patient // ignore: cast_nullable_to_non_nullable as int?, - isVegan == freezed + freezed == isVegan ? _value.isVegan : isVegan // ignore: cast_nullable_to_non_nullable as bool?, + freezed == points + ? _value.points + : points // ignore: cast_nullable_to_non_nullable + as int?, )); } } @@ -137,8 +162,8 @@ class __$$_UserDataCopyWithImpl<$Res> extends _$UserDataCopyWithImpl<$Res> /// @nodoc @JsonSerializable() class _$_UserData implements _UserData { - const _$_UserData( - this.id, this.username, this.email, this.patient, this.isVegan); + const _$_UserData(this.id, this.username, this.email, this.patient, + this.isVegan, this.points); factory _$_UserData.fromJson(Map json) => _$$_UserDataFromJson(json); @@ -153,10 +178,12 @@ class _$_UserData implements _UserData { final int? patient; @override final bool? isVegan; + @override + final int? points; @override String toString() { - return 'UserData(id: $id, username: $username, email: $email, patient: $patient, isVegan: $isVegan)'; + return 'UserData(id: $id, username: $username, email: $email, patient: $patient, isVegan: $isVegan, points: $points)'; } @override @@ -164,25 +191,23 @@ class _$_UserData implements _UserData { return identical(this, other) || (other.runtimeType == runtimeType && other is _$_UserData && - const DeepCollectionEquality().equals(other.id, id) && - const DeepCollectionEquality().equals(other.username, username) && - const DeepCollectionEquality().equals(other.email, email) && - const DeepCollectionEquality().equals(other.patient, patient) && - const DeepCollectionEquality().equals(other.isVegan, isVegan)); + (identical(other.id, id) || other.id == id) && + (identical(other.username, username) || + other.username == username) && + (identical(other.email, email) || other.email == email) && + (identical(other.patient, patient) || other.patient == patient) && + (identical(other.isVegan, isVegan) || other.isVegan == isVegan) && + (identical(other.points, points) || other.points == points)); } @JsonKey(ignore: true) @override - int get hashCode => Object.hash( - runtimeType, - const DeepCollectionEquality().hash(id), - const DeepCollectionEquality().hash(username), - const DeepCollectionEquality().hash(email), - const DeepCollectionEquality().hash(patient), - const DeepCollectionEquality().hash(isVegan)); + int get hashCode => + Object.hash(runtimeType, id, username, email, patient, isVegan, points); @JsonKey(ignore: true) @override + @pragma('vm:prefer-inline') _$$_UserDataCopyWith<_$_UserData> get copyWith => __$$_UserDataCopyWithImpl<_$_UserData>(this, _$identity); @@ -200,7 +225,8 @@ abstract class _UserData implements UserData { final String? username, final String? email, final int? patient, - final bool? isVegan) = _$_UserData; + final bool? isVegan, + final int? points) = _$_UserData; factory _UserData.fromJson(Map json) = _$_UserData.fromJson; @@ -215,6 +241,8 @@ abstract class _UserData implements UserData { @override bool? get isVegan; @override + int? get points; + @override @JsonKey(ignore: true) _$$_UserDataCopyWith<_$_UserData> get copyWith => throw _privateConstructorUsedError; diff --git a/lib/src/features/auth/domain/user.g.dart b/lib/src/features/auth/domain/user.g.dart index 0096f66..f95eb80 100644 --- a/lib/src/features/auth/domain/user.g.dart +++ b/lib/src/features/auth/domain/user.g.dart @@ -12,6 +12,7 @@ _$_UserData _$$_UserDataFromJson(Map json) => _$_UserData( json['email'] as String?, json['patient'] as int?, json['isVegan'] as bool?, + json['points'] as int?, ); Map _$$_UserDataToJson(_$_UserData instance) => @@ -21,4 +22,5 @@ Map _$$_UserDataToJson(_$_UserData instance) => 'email': instance.email, 'patient': instance.patient, 'isVegan': instance.isVegan, + 'points': instance.points, }; diff --git a/lib/src/features/auth/favorites/data/favorites.dart b/lib/src/features/auth/favorites/data/favorites.dart index bd55b5d..e6cf2f5 100644 --- a/lib/src/features/auth/favorites/data/favorites.dart +++ b/lib/src/features/auth/favorites/data/favorites.dart @@ -3,25 +3,32 @@ import 'dart:developer'; import 'package:flutter/material.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart'; +import 'package:riverpod_annotation/riverpod_annotation.dart'; +import '../../../../translations/domain/translation_provider.dart'; import '../../application/auth_service.dart'; import '../../../../constants/constants.dart'; import '../../../get_recipes/domain/recipe/recipe.dart'; import '../domain/favorites.dart'; -final FutureProvider getFavoritesProvider = - FutureProvider((ref) async { - final url = '$restAPIURL/user/favorite/'; +part 'favorites.g.dart'; + +@riverpod +Future getFavorites(Ref ref,{required BuildContext context}) async{ + final url = '$restAPIURL/user/favorite/'; final response = await client.get( Uri.parse(url), headers: { + 'Accept-Language': ref.watch(localeNotifierProvider).languageCode, 'Authorization': 'Token ${ref.read(authHelperProvider).getToken()}', }, ); final responseDe = utf8.decode(response.bodyBytes); final responseJson = json.decode(responseDe); return FavoritesData.fromJson(responseJson["favorites"]); -}); + +} + Future addFavorite({ required WidgetRef ref, diff --git a/lib/src/features/auth/favorites/data/favorites.g.dart b/lib/src/features/auth/favorites/data/favorites.g.dart new file mode 100644 index 0000000..c3b7ee7 --- /dev/null +++ b/lib/src/features/auth/favorites/data/favorites.g.dart @@ -0,0 +1,159 @@ +// GENERATED CODE - DO NOT MODIFY BY HAND + +part of 'favorites.dart'; + +// ************************************************************************** +// RiverpodGenerator +// ************************************************************************** + +String _$getFavoritesHash() => r'25ef05d5eb37798fca37568e88253517a425806c'; + +/// Copied from Dart SDK +class _SystemHash { + _SystemHash._(); + + static int combine(int hash, int value) { + // ignore: parameter_assignments + hash = 0x1fffffff & (hash + value); + // ignore: parameter_assignments + hash = 0x1fffffff & (hash + ((0x0007ffff & hash) << 10)); + return hash ^ (hash >> 6); + } + + static int finish(int hash) { + // ignore: parameter_assignments + hash = 0x1fffffff & (hash + ((0x03ffffff & hash) << 3)); + // ignore: parameter_assignments + hash = hash ^ (hash >> 11); + return 0x1fffffff & (hash + ((0x00003fff & hash) << 15)); + } +} + +/// See also [getFavorites]. +@ProviderFor(getFavorites) +const getFavoritesProvider = GetFavoritesFamily(); + +/// See also [getFavorites]. +class GetFavoritesFamily extends Family> { + /// See also [getFavorites]. + const GetFavoritesFamily(); + + /// See also [getFavorites]. + GetFavoritesProvider call({ + required BuildContext context, + }) { + return GetFavoritesProvider( + context: context, + ); + } + + @override + GetFavoritesProvider getProviderOverride( + covariant GetFavoritesProvider provider, + ) { + return call( + context: provider.context, + ); + } + + static const Iterable? _dependencies = null; + + @override + Iterable? get dependencies => _dependencies; + + static const Iterable? _allTransitiveDependencies = null; + + @override + Iterable? get allTransitiveDependencies => + _allTransitiveDependencies; + + @override + String? get name => r'getFavoritesProvider'; +} + +/// See also [getFavorites]. +class GetFavoritesProvider extends AutoDisposeFutureProvider { + /// See also [getFavorites]. + GetFavoritesProvider({ + required BuildContext context, + }) : this._internal( + (ref) => getFavorites( + ref as GetFavoritesRef, + context: context, + ), + from: getFavoritesProvider, + name: r'getFavoritesProvider', + debugGetCreateSourceHash: + const bool.fromEnvironment('dart.vm.product') + ? null + : _$getFavoritesHash, + dependencies: GetFavoritesFamily._dependencies, + allTransitiveDependencies: + GetFavoritesFamily._allTransitiveDependencies, + context: context, + ); + + GetFavoritesProvider._internal( + super._createNotifier, { + required super.name, + required super.dependencies, + required super.allTransitiveDependencies, + required super.debugGetCreateSourceHash, + required super.from, + required this.context, + }) : super.internal(); + + final BuildContext context; + + @override + Override overrideWith( + FutureOr Function(GetFavoritesRef provider) create, + ) { + return ProviderOverride( + origin: this, + override: GetFavoritesProvider._internal( + (ref) => create(ref as GetFavoritesRef), + from: from, + name: null, + dependencies: null, + allTransitiveDependencies: null, + debugGetCreateSourceHash: null, + context: context, + ), + ); + } + + @override + AutoDisposeFutureProviderElement createElement() { + return _GetFavoritesProviderElement(this); + } + + @override + bool operator ==(Object other) { + return other is GetFavoritesProvider && other.context == context; + } + + @override + int get hashCode { + var hash = _SystemHash.combine(0, runtimeType.hashCode); + hash = _SystemHash.combine(hash, context.hashCode); + + return _SystemHash.finish(hash); + } +} + +mixin GetFavoritesRef on AutoDisposeFutureProviderRef { + /// The parameter `context` of this provider. + BuildContext get context; +} + +class _GetFavoritesProviderElement + extends AutoDisposeFutureProviderElement + with GetFavoritesRef { + _GetFavoritesProviderElement(super.provider); + + @override + BuildContext get context => (origin as GetFavoritesProvider).context; +} +// ignore_for_file: type=lint +// ignore_for_file: subtype_of_sealed_class, invalid_use_of_internal_member, invalid_use_of_visible_for_testing_member diff --git a/lib/src/features/auth/favorites/domain/favorites.dart b/lib/src/features/auth/favorites/domain/favorites.dart index 0f6d77b..ef9a63d 100644 --- a/lib/src/features/auth/favorites/domain/favorites.dart +++ b/lib/src/features/auth/favorites/domain/favorites.dart @@ -8,7 +8,7 @@ part 'favorites.g.dart'; @freezed class FavoritesData with _$FavoritesData { const factory FavoritesData( - List id, List name, List name_in_arabic, List imageURL) = _FavoritesData; + List id, List name, List imageURL) = _FavoritesData; factory FavoritesData.fromJson(Map json) => _$FavoritesDataFromJson(json); } diff --git a/lib/src/features/auth/favorites/domain/favorites.freezed.dart b/lib/src/features/auth/favorites/domain/favorites.freezed.dart index e50074a..bfa2871 100644 --- a/lib/src/features/auth/favorites/domain/favorites.freezed.dart +++ b/lib/src/features/auth/favorites/domain/favorites.freezed.dart @@ -1,7 +1,7 @@ // coverage:ignore-file // GENERATED CODE - DO NOT MODIFY BY HAND // ignore_for_file: type=lint -// ignore_for_file: unused_element, deprecated_member_use, deprecated_member_use_from_same_package, use_function_type_syntax_for_parameters, unnecessary_const, avoid_init_to_null, invalid_override_different_default_values_named, prefer_expression_function_bodies, annotate_overrides, invalid_annotation_target +// ignore_for_file: unused_element, deprecated_member_use, deprecated_member_use_from_same_package, use_function_type_syntax_for_parameters, unnecessary_const, avoid_init_to_null, invalid_override_different_default_values_named, prefer_expression_function_bodies, annotate_overrides, invalid_annotation_target, unnecessary_question_mark part of 'favorites.dart'; @@ -22,7 +22,6 @@ FavoritesData _$FavoritesDataFromJson(Map json) { mixin _$FavoritesData { List get id => throw _privateConstructorUsedError; List get name => throw _privateConstructorUsedError; - List get name_in_arabic => throw _privateConstructorUsedError; List get imageURL => throw _privateConstructorUsedError; Map toJson() => throw _privateConstructorUsedError; @@ -35,48 +34,42 @@ mixin _$FavoritesData { abstract class $FavoritesDataCopyWith<$Res> { factory $FavoritesDataCopyWith( FavoritesData value, $Res Function(FavoritesData) then) = - _$FavoritesDataCopyWithImpl<$Res>; - $Res call( - {List id, - List name, - List name_in_arabic, - List imageURL}); + _$FavoritesDataCopyWithImpl<$Res, FavoritesData>; + @useResult + $Res call({List id, List name, List imageURL}); } /// @nodoc -class _$FavoritesDataCopyWithImpl<$Res> +class _$FavoritesDataCopyWithImpl<$Res, $Val extends FavoritesData> implements $FavoritesDataCopyWith<$Res> { _$FavoritesDataCopyWithImpl(this._value, this._then); - final FavoritesData _value; // ignore: unused_field - final $Res Function(FavoritesData) _then; + final $Val _value; + // ignore: unused_field + final $Res Function($Val) _then; + @pragma('vm:prefer-inline') @override $Res call({ - Object? id = freezed, - Object? name = freezed, - Object? name_in_arabic = freezed, - Object? imageURL = freezed, + Object? id = null, + Object? name = null, + Object? imageURL = null, }) { return _then(_value.copyWith( - id: id == freezed + id: null == id ? _value.id : id // ignore: cast_nullable_to_non_nullable as List, - name: name == freezed + name: null == name ? _value.name : name // ignore: cast_nullable_to_non_nullable as List, - name_in_arabic: name_in_arabic == freezed - ? _value.name_in_arabic - : name_in_arabic // ignore: cast_nullable_to_non_nullable - as List, - imageURL: imageURL == freezed + imageURL: null == imageURL ? _value.imageURL : imageURL // ignore: cast_nullable_to_non_nullable as List, - )); + ) as $Val); } } @@ -87,45 +80,35 @@ abstract class _$$_FavoritesDataCopyWith<$Res> _$_FavoritesData value, $Res Function(_$_FavoritesData) then) = __$$_FavoritesDataCopyWithImpl<$Res>; @override - $Res call( - {List id, - List name, - List name_in_arabic, - List imageURL}); + @useResult + $Res call({List id, List name, List imageURL}); } /// @nodoc class __$$_FavoritesDataCopyWithImpl<$Res> - extends _$FavoritesDataCopyWithImpl<$Res> + extends _$FavoritesDataCopyWithImpl<$Res, _$_FavoritesData> implements _$$_FavoritesDataCopyWith<$Res> { __$$_FavoritesDataCopyWithImpl( _$_FavoritesData _value, $Res Function(_$_FavoritesData) _then) - : super(_value, (v) => _then(v as _$_FavoritesData)); - - @override - _$_FavoritesData get _value => super._value as _$_FavoritesData; + : super(_value, _then); + @pragma('vm:prefer-inline') @override $Res call({ - Object? id = freezed, - Object? name = freezed, - Object? name_in_arabic = freezed, - Object? imageURL = freezed, + Object? id = null, + Object? name = null, + Object? imageURL = null, }) { return _then(_$_FavoritesData( - id == freezed + null == id ? _value._id : id // ignore: cast_nullable_to_non_nullable as List, - name == freezed + null == name ? _value._name : name // ignore: cast_nullable_to_non_nullable as List, - name_in_arabic == freezed - ? _value._name_in_arabic - : name_in_arabic // ignore: cast_nullable_to_non_nullable - as List, - imageURL == freezed + null == imageURL ? _value._imageURL : imageURL // ignore: cast_nullable_to_non_nullable as List, @@ -137,10 +120,9 @@ class __$$_FavoritesDataCopyWithImpl<$Res> @JsonSerializable() class _$_FavoritesData implements _FavoritesData { const _$_FavoritesData(final List id, final List name, - final List name_in_arabic, final List imageURL) + final List imageURL) : _id = id, _name = name, - _name_in_arabic = name_in_arabic, _imageURL = imageURL; factory _$_FavoritesData.fromJson(Map json) => @@ -149,6 +131,7 @@ class _$_FavoritesData implements _FavoritesData { final List _id; @override List get id { + if (_id is EqualUnmodifiableListView) return _id; // ignore: implicit_dynamic_type return EqualUnmodifiableListView(_id); } @@ -156,27 +139,22 @@ class _$_FavoritesData implements _FavoritesData { final List _name; @override List get name { + if (_name is EqualUnmodifiableListView) return _name; // ignore: implicit_dynamic_type return EqualUnmodifiableListView(_name); } - final List _name_in_arabic; - @override - List get name_in_arabic { - // ignore: implicit_dynamic_type - return EqualUnmodifiableListView(_name_in_arabic); - } - final List _imageURL; @override List get imageURL { + if (_imageURL is EqualUnmodifiableListView) return _imageURL; // ignore: implicit_dynamic_type return EqualUnmodifiableListView(_imageURL); } @override String toString() { - return 'FavoritesData(id: $id, name: $name, name_in_arabic: $name_in_arabic, imageURL: $imageURL)'; + return 'FavoritesData(id: $id, name: $name, imageURL: $imageURL)'; } @override @@ -186,8 +164,6 @@ class _$_FavoritesData implements _FavoritesData { other is _$_FavoritesData && const DeepCollectionEquality().equals(other._id, _id) && const DeepCollectionEquality().equals(other._name, _name) && - const DeepCollectionEquality() - .equals(other._name_in_arabic, _name_in_arabic) && const DeepCollectionEquality().equals(other._imageURL, _imageURL)); } @@ -197,11 +173,11 @@ class _$_FavoritesData implements _FavoritesData { runtimeType, const DeepCollectionEquality().hash(_id), const DeepCollectionEquality().hash(_name), - const DeepCollectionEquality().hash(_name_in_arabic), const DeepCollectionEquality().hash(_imageURL)); @JsonKey(ignore: true) @override + @pragma('vm:prefer-inline') _$$_FavoritesDataCopyWith<_$_FavoritesData> get copyWith => __$$_FavoritesDataCopyWithImpl<_$_FavoritesData>(this, _$identity); @@ -214,10 +190,7 @@ class _$_FavoritesData implements _FavoritesData { } abstract class _FavoritesData implements FavoritesData { - const factory _FavoritesData( - final List id, - final List name, - final List name_in_arabic, + const factory _FavoritesData(final List id, final List name, final List imageURL) = _$_FavoritesData; factory _FavoritesData.fromJson(Map json) = @@ -228,8 +201,6 @@ abstract class _FavoritesData implements FavoritesData { @override List get name; @override - List get name_in_arabic; - @override List get imageURL; @override @JsonKey(ignore: true) diff --git a/lib/src/features/auth/favorites/domain/favorites.g.dart b/lib/src/features/auth/favorites/domain/favorites.g.dart index ea63bcb..a985368 100644 --- a/lib/src/features/auth/favorites/domain/favorites.g.dart +++ b/lib/src/features/auth/favorites/domain/favorites.g.dart @@ -10,7 +10,6 @@ _$_FavoritesData _$$_FavoritesDataFromJson(Map json) => _$_FavoritesData( json['id'] as List, json['name'] as List, - json['name_in_arabic'] as List, json['imageURL'] as List, ); @@ -18,6 +17,5 @@ Map _$$_FavoritesDataToJson(_$_FavoritesData instance) => { 'id': instance.id, 'name': instance.name, - 'name_in_arabic': instance.name_in_arabic, 'imageURL': instance.imageURL, }; diff --git a/lib/src/features/auth/favorites/presentation/favorites.dart b/lib/src/features/auth/favorites/presentation/favorites.dart index 5607eef..8b5d767 100644 --- a/lib/src/features/auth/favorites/presentation/favorites.dart +++ b/lib/src/features/auth/favorites/presentation/favorites.dart @@ -1,14 +1,13 @@ import 'dart:developer'; import 'package:cached_network_image/cached_network_image.dart'; -import 'package:easy_localization/easy_localization.dart'; import 'package:flutter/material.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart'; import 'package:livine/src/constants/constants.dart'; +import '../../../../translations/domain/translation_provider.dart'; import '../data/favorites.dart'; import '../../../loading/loading.dart'; -import '../../../../translations/locale_keys.g.dart'; class Favorites extends ConsumerStatefulWidget { const Favorites({Key? key}) : super(key: key); @@ -20,21 +19,21 @@ class Favorites extends ConsumerStatefulWidget { class _FavoritesState extends ConsumerState { @override Widget build(BuildContext context) { - final favorites = ref.watch(getFavoritesProvider); - + final favorites = ref.watch(getFavoritesProvider(context: context)); + final word = TranslationRepo.translate(context); return RefreshIndicator( onRefresh: () async { return Future.delayed(const Duration(seconds: 2)) - .then((_) => ref.refresh(getFavoritesProvider)); + .then((_) => ref.refresh(getFavoritesProvider(context: context))); }, - backgroundColor: getColorScheme(context).surface, + backgroundColor: colorScheme(context).surface, child: Scaffold( appBar: AppBar( - title: Text(LocaleKeys.Favorites.tr()), + title: Text(word?.favorites ?? ""), ), body: favorites.when( data: (data) => RawScrollbar( - thumbColor: getColorScheme(context).tertiary, + thumbColor: colorScheme(context).tertiary, thickness: 5, radius: const Radius.circular(10), child: ListView.builder( @@ -51,8 +50,8 @@ class _FavoritesState extends ConsumerState { recipeID: data.id[index], mounted: mounted, context: context) - .then((value) => - ref.refresh(getFavoritesProvider)); + .then((value) => ref.refresh( + getFavoritesProvider(context: context))); }, background: Container( color: Colors.red, @@ -75,9 +74,7 @@ class _FavoritesState extends ConsumerState { fit: BoxFit.cover, ), Text( - context.locale.languageCode == "en" - ? data.name[index] - : data.name_in_arabic[index], + data.name[index], maxLines: 1, overflow: TextOverflow.ellipsis, style: const TextStyle( diff --git a/lib/src/features/auth/login/presentation/login.dart b/lib/src/features/auth/login/presentation/login.dart index 13b5b70..673c3b8 100644 --- a/lib/src/features/auth/login/presentation/login.dart +++ b/lib/src/features/auth/login/presentation/login.dart @@ -2,19 +2,17 @@ import 'dart:io'; -import 'package:easy_localization/easy_localization.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart'; import 'package:go_router/go_router.dart'; import 'package:flutter/material.dart'; import 'package:http/http.dart'; import 'package:http/http.dart' as http; -import 'package:iconsax/iconsax.dart'; +import 'package:livine/src/constants/constants.dart'; import 'package:livine/src/features/auth/application/auth_service.dart'; import 'package:livine/src/shared/cache/cache_helper.dart'; +import 'package:livine/src/translations/domain/translation_provider.dart'; -import '../../../../common_widgets/auth/auth_widget.dart'; -import '../../../../translations/locale_keys.g.dart'; import '../../data/user.dart'; class Login extends ConsumerStatefulWidget { @@ -71,162 +69,234 @@ class _LoginState extends ConsumerState { @override Widget build(BuildContext context) { final theme = Theme.of(context).colorScheme; - + final word = TranslationRepo.translate(context); return Scaffold( - body: Row( - children: [ - Expanded( - child: Form( - key: _formKey, - child: Column( - mainAxisAlignment: MainAxisAlignment.center, - children: [ - Padding( - padding: const EdgeInsets.all(20.0), - child: TextFormField( - textInputAction: TextInputAction.next, - validator: (u) { - if (u!.isEmpty) { - return context.locale.languageCode == "en" - ? "Please enter your username" - : "من فضلك ادخل اسم المستخدم"; - } - if (u.contains(" ")) { - return context.locale.languageCode == "en" - ? "No space allowed in username" - : "يجب ان لا يكون هناك مسافة في اسم المستخدم"; - } - return null; - }, - controller: _username, - decoration: InputDecoration( - border: const OutlineInputBorder( - borderRadius: - BorderRadius.all(Radius.circular(10.0))), - labelText: LocaleKeys.username.tr(), - labelStyle: const TextStyle(fontSize: 15), - ), - ), - ), - Padding( - padding: const EdgeInsets.symmetric(horizontal: 20.0), - child: TextFormField( - validator: (p) { - if (p!.length < 6 && p.isNotEmpty) { - return context.locale.languageCode == "en" - ? "Password needs to be atleast 9 characters " - : "يجب أن تتكون كلمة المرور من 9 أحرف على الأقل"; - } else if (p.isEmpty) { - return context.locale.languageCode == "en" - ? "Please enter your password " - : "من فضلك أدخل كلمة السر"; - } - return null; - }, - controller: _password, - obscureText: _obscureText, - onFieldSubmitted: (_) => validateLoginForm(), - decoration: InputDecoration( - border: const OutlineInputBorder( - borderRadius: - BorderRadius.all(Radius.circular(10.0))), - suffixIcon: IconButton( - icon: Icon( - _obscureText ? Iconsax.eye_slash5 : Iconsax.eye, + body: SingleChildScrollView( + child: SafeArea( + child: Padding( + padding: EdgeInsets.only(top: rh.deviceHeight(context) * 0.1), + child: Row( + crossAxisAlignment: CrossAxisAlignment.center, + mainAxisAlignment: MainAxisAlignment.center, + children: [ + Expanded( + child: Form( + key: _formKey, + child: Column( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + Padding( + padding: const EdgeInsets.all(20.0), + child: TextFormField( + textInputAction: TextInputAction.next, + validator: (u) { + if (u!.isEmpty) { + return "Please enter your username"; + } + if (u.contains(" ")) { + return "No space allowed in username"; + } + return null; + }, + controller: _username, + decoration: InputDecoration( + border: const OutlineInputBorder( + borderRadius: + BorderRadius.all(Radius.circular(10.0))), + labelText: word?.username ?? "Username", + labelStyle: const TextStyle(fontSize: 15), + ), ), - onPressed: () { - setState(() { - _obscureText = !_obscureText; - }); - }, - ), - labelText: LocaleKeys.password.tr(), - labelStyle: const TextStyle(fontSize: 15), - ), - ), - ), - Padding( - padding: const EdgeInsets.only(top: 20, bottom: 5), - child: GestureDetector( - onTap: () => context.push('/reset_password'), - child: Text( - LocaleKeys.Forget_your_password.tr(), - textAlign: TextAlign.right, - style: TextStyle( - fontSize: 15, - fontFamily: 'Kine', - color: theme.tertiary, ), - ), - ), - ), - SizedBox( - height: 10, - ), - authButton( - isLoading: isLoading, - text: LocaleKeys.Sign_in.tr(), - onPressed: validateLoginForm, - context: context), - Padding( - padding: const EdgeInsets.only(top: 30), - child: Center( - child: Row( - mainAxisAlignment: MainAxisAlignment.center, - children: [ - Text( - LocaleKeys.no_account.tr(), - style: const TextStyle( - fontFamily: 'Kine', fontWeight: FontWeight.w100), - ), - const SizedBox( - width: 10, + Padding( + padding: const EdgeInsets.symmetric(horizontal: 20.0), + child: TextFormField( + validator: (p) { + if (p!.length < 6 && p.isNotEmpty) { + return "Password needs to be atleast 9 characters "; + } else if (p.isEmpty) { + return "Please enter your password "; + } + return null; + }, + controller: _password, + obscureText: _obscureText, + onFieldSubmitted: (_) => validateLoginForm(), + decoration: InputDecoration( + border: const OutlineInputBorder( + borderRadius: + BorderRadius.all(Radius.circular(10.0))), + suffixIcon: IconButton( + icon: Icon( + _obscureText + ? Icons.visibility_off + : Icons.visibility, + ), + onPressed: () { + setState(() { + _obscureText = !_obscureText; + }); + }, + ), + labelText: word?.password ?? "Password", + labelStyle: const TextStyle(fontSize: 15), + ), ), - GestureDetector( - onTap: () => context.push('/register'), + ), + Padding( + padding: const EdgeInsets.only(top: 20, bottom: 5), + child: GestureDetector( + onTap: () => context.push('/reset_password'), child: Text( - LocaleKeys.Sign_up.tr(), + word?.forget_your_password ?? "Forgot Password?", + textAlign: TextAlign.right, style: TextStyle( - fontSize: 15.0, - color: theme.tertiary, + fontSize: 15, fontFamily: 'Kine', - fontWeight: FontWeight.bold, + color: theme.tertiary, + ), + ), + ), + ), + SizedBox( + height: 10, + ), + ({ + required void Function() onPressed, + required bool isLoading, + required String text, + Color? color, + Color? textColor, + double width = 350, + required BuildContext context, + }) { + final theme = Theme.of(context).colorScheme; + return Padding( + padding: const EdgeInsets.symmetric(horizontal: 20.0), + child: MaterialButton( + onPressed: onPressed, + color: color ?? theme.primaryContainer, + elevation: 0, + minWidth: width, + height: 60, + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.circular(15), ), + child: isLoading + ? const CircularProgressIndicator( + color: Colors.white, + ) + : Text( + text, + style: TextStyle( + fontSize: 15, + color: textColor ?? + theme.onPrimaryContainer), + ), + ), + ); + }( + isLoading: isLoading, + text: word?.sign_in ?? "Sign In", + onPressed: validateLoginForm, + context: context), + Padding( + padding: const EdgeInsets.only(top: 30), + child: Center( + child: Row( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + Text( + word?.no_account ?? "No account yet?", + style: const TextStyle( + fontFamily: 'Kine', + fontWeight: FontWeight.w100), + ), + const SizedBox( + width: 10, + ), + GestureDetector( + onTap: () => context.push('/register'), + child: Text( + word?.sign_up ?? "Sign Up", + style: TextStyle( + fontSize: 15.0, + color: theme.tertiary, + fontFamily: 'Kine', + fontWeight: FontWeight.bold, + ), + ), + ), + ], ), ), - ], - ), + ), + SizedBox( + height: 10, + ), + // ({ + // required void Function() onPressed, + // required bool isLoading, + // required String text, + // Color? color, + // Color? textColor, + // double width = 350, + // required BuildContext context, + // }) { + // final theme = Theme.of(context).colorScheme; + // return Padding( + // padding: const EdgeInsets.symmetric(horizontal: 20.0), + // child: MaterialButton( + // onPressed: onPressed, + // color: color ?? theme.primaryContainer, + // elevation: 0, + // minWidth: width, + // height: 60, + // shape: RoundedRectangleBorder( + // borderRadius: BorderRadius.circular(15), + // ), + // child: isLoading + // ? const CircularProgressIndicator( + // color: Colors.white, + // ) + // : Text( + // text, + // style: TextStyle( + // fontSize: 15, + // color: textColor ?? + // theme.onPrimaryContainer), + // ), + // ), + // ); + // }( + // isLoading: false, + // text: word?.continue_as_guest ?? "Continue as Guest", + // textColor: theme.onSecondaryContainer, + // onPressed: validateGuest, + // context: context, + // color: theme.secondaryContainer), + ], ), ), - SizedBox( - height: 10, - ), - authButton( - isLoading: false, - text: LocaleKeys.continue_as_guest.tr(), - textColor: theme.onSecondaryContainer, - onPressed: validateGuest, - context: context, - color: theme.secondaryContainer), - ], - ), + ), + Visibility( + visible: Platform.isWindows, + child: Expanded( + flex: 2, + child: ClipRRect( + borderRadius: const BorderRadius.only( + topLeft: Radius.circular(20), + bottomLeft: Radius.circular(20)), + child: Image.asset( + 'assets/images/windows/login.webp', + fit: BoxFit.cover, + ), + )), + ), + ], ), ), - Visibility( - visible: Platform.isWindows, - child: Expanded( - flex: 2, - child: ClipRRect( - borderRadius: const BorderRadius.only( - topLeft: Radius.circular(20), - bottomLeft: Radius.circular(20)), - child: Image.asset( - 'assets/images/windows/login.webp', - fit: BoxFit.cover, - ), - )), - ), - ], + ), )); } } diff --git a/lib/src/features/auth/profiles/data/get_user_data.dart b/lib/src/features/auth/profiles/data/get_user_data.dart index 3025cbb..19e864e 100644 --- a/lib/src/features/auth/profiles/data/get_user_data.dart +++ b/lib/src/features/auth/profiles/data/get_user_data.dart @@ -7,15 +7,41 @@ import '../../application/auth_service.dart'; import '../../../../constants/constants.dart'; import '../../../get_recipes/domain/recipe/recipe.dart'; -final FutureProvider userDataProvider = - FutureProvider((ref) async { +final userDataProvider = FutureProvider((ref) async { final url = Uri.parse('$restAPIURL/user/?format=json'); - final token = ref.watch(authHelperProvider).getToken(); - - final response = await client.get( - url, - headers: token != '' ? {'Authorization': 'Token ${token}'} : {}, - ); + final token = await ref.watch(authHelperProvider).getToken(); + Map headers = {}; + if (token != '') { + headers["Authorization"] = 'Token ${token}'; + } + final response = await client.get(url, headers: headers); return UserData.fromJson(json.decode(response.body)); }); + +// getUserData({required WidgetRef ref}) async{ +// final url = Uri.parse('$restAPIURL/user/?format=json'); +// final token = await ref.watch(authHelperProvider).getToken(); +// Map headers = {}; +// if (token != '') { +// headers["Authorization"] = 'Token ${token}'; +// } +// final response = await client.get(url, headers: headers); + +// return UserData.fromJson(json.decode(response.body)); +// } + +final userDataStreamProvider = StreamProvider((ref) async* { + while (true) { + await Future.delayed(Duration(seconds: 3)); + final url = Uri.parse('$restAPIURL/user/?format=json'); + final token = await ref.watch(authHelperProvider).getToken(); + Map headers = {}; + if (token != '') { + headers["Authorization"] = 'Token ${token}'; + } + final response = await client.get(url, headers: headers); + + yield UserData.fromJson(json.decode(response.body)); + } +}); diff --git a/lib/src/features/auth/profiles/presentation/profile.dart b/lib/src/features/auth/profiles/presentation/profile.dart index c1c9530..0f5a261 100644 --- a/lib/src/features/auth/profiles/presentation/profile.dart +++ b/lib/src/features/auth/profiles/presentation/profile.dart @@ -1,38 +1,31 @@ import 'dart:developer'; -import 'package:easy_localization/easy_localization.dart'; -import 'package:flutter/foundation.dart'; import 'package:flutter/material.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart'; -import 'package:flutter_switch/flutter_switch.dart'; import 'package:go_router/go_router.dart'; -import 'package:google_fonts/google_fonts.dart'; -import 'package:iconsax/iconsax.dart'; import 'package:livine/src/common_widgets/no_connection.dart'; +import 'package:livine/src/translations/domain/translation_provider.dart'; +import 'package:sliding_up_panel2/sliding_up_panel2.dart'; -import '../../../../constants/constants.dart'; import '../../../../constants/shared_constants.dart'; import '../../../../shared/connectivity/check_network.dart'; -import '../../../loading/loading.dart'; import '../../../get_recipes/application/vegan_service.dart'; -import '../../../../shared/styles/lib_color_schemes.g.dart'; -import '../../../../translations/locale_keys.g.dart'; import '../../application/auth_service.dart'; -import '../../data/user.dart'; -import '../../domain/user.dart'; import '../data/get_user_data.dart'; +import 'package:percent_indicator/percent_indicator.dart'; class Profile extends ConsumerWidget { const Profile({Key? key}) : super(key: key); @override Widget build(BuildContext context, WidgetRef ref) { - bool guest = ref.watch(guestProvider); + // bool guest = ref.watch(guestProvider); ConnectivityStatus network = ref.watch(checkNetworkProvider); + bool isVeg = ref.watch(isVeganProvider); - AsyncValue userData = ref.watch(userDataProvider); - + final userData = ref.watch(userDataStreamProvider); + final word = TranslationRepo.translate(context); userData.whenOrNull( error: (error, stack) { log("PROFILE ERROR $error"); @@ -40,50 +33,114 @@ class Profile extends ConsumerWidget { }, ); + int? userPoints = + userData.maybeWhen(data: (data) => data.points, orElse: () => 0); return network == ConnectivityStatus.On ? Scaffold( appBar: AppBar( - backgroundColor: Theme.of(context).brightness == Brightness.dark - ? darkColorScheme.background - : lightColorScheme.secondaryContainer, title: Text( - LocaleKeys.Profile.tr(), + word?.profile ?? "", style: TextStyle( - fontFamily: context.locale.languageCode == "en" - ? 'Kine' - : GoogleFonts.notoKufiArabic().fontFamily, + color: Theme.of(context).colorScheme.onPrimary, ), ), centerTitle: true, + backgroundColor: Theme.of(context).colorScheme.primary, elevation: 0, ), - body: SingleChildScrollView( - child: Column(children: [ - userData.when( - data: (data) { - String guestChange() { - if (data.username == - "GUEST") if (context.locale.languageCode == "en") - return "Guest"; - else - return "ضيف"; - return data.username ?? ""; - } - - final isVeg = ref.watch(isVeganProvider); - - return Column( - crossAxisAlignment: CrossAxisAlignment.start, + body: SlidingUpPanel( + body: Container( + color: Theme.of(context).colorScheme.primary, + child: Column( + children: [ + SizedBox( + height: 15, + ), + CircularPercentIndicator( + percent: userPoints! / 100 > 1 ? 1 : userPoints / 100, + radius: 60, + curve: Curves.easeInCirc, + lineWidth: 5, + animation: true, + center: CircleAvatar( + backgroundImage: AssetImage( + 'assets/images/profile/default.png', + ), + radius: 50, + ), + circularStrokeCap: CircularStrokeCap.round, + backgroundColor: Theme.of(context).colorScheme.primary, + progressColor: Theme.of(context).colorScheme.onPrimary, + ), + SizedBox( + height: 15, + ), + Row( + mainAxisAlignment: MainAxisAlignment.spaceEvenly, children: [ - UserInfo( - name: guestChange(), - image: 'assets/images/profile/default.png', + CircleAvatar( + radius: 30, + backgroundColor: + Theme.of(context).colorScheme.secondary, + child: Icon( + Icons.emoji_events_rounded, + color: Theme.of(context).colorScheme.onSecondary, + size: 35.0, + ), ), - Visibility( - visible: isGuest == false && guest == false, - child: FlutterSwitch( + Column( + children: [ + Text( + "$userPoints", + style: TextStyle( + color: Theme.of(context).colorScheme.surface), + ), + Text( + word!.points, + style: TextStyle( + color: Theme.of(context).colorScheme.surface), + ) + ], + ), + ], + ) + ], + ), + ), + borderRadius: BorderRadius.only( + topLeft: Radius.circular(30), topRight: Radius.circular(30)), + minHeight: MediaQuery.of(context).size.height * 0.5, + isDraggable: true, + color: Theme.of(context).colorScheme.surface, + boxShadow: [], + panelBuilder: () => Padding( + padding: const EdgeInsets.only(top: 15.0), + child: Column( + children: [ + Padding( + padding: const EdgeInsets.symmetric(horizontal: 20), + child: Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + Row( + children: [ + CircleAvatar( + backgroundColor: + Theme.of(context).colorScheme.secondary, + child: Icon(Icons.eco, + color: Theme.of(context) + .colorScheme + .onSecondary), + ), + SizedBox( + width: 10, + ), + Text(word.vegetarian), + ], + ), + Switch.adaptive( value: isVeg, - onToggle: (v) async { + onChanged: (v) async { ref .read(isVeganProvider.notifier) .update((state) => v); @@ -91,120 +148,243 @@ class Profile extends ConsumerWidget { .read(veganServiceProvider) .updateIsVegan(v); }, - inactiveColor: Colors.brown[300]!, - inactiveIcon: Image.asset( - 'assets/images/icons/meat.png', - color: Colors.brown, - ), - activeColor: getColorScheme(context).secondary, - activeToggleColor: - getColorScheme(context).onSecondary, - activeIcon: Image.asset( - "assets/images/icons/vegan.png", - color: getColorScheme(context).secondary, - ), ), - ), - ], - ); - }, - error: (e, s) { - log('$e\n$s'); - - return kDebugMode ? Text(e.toString()) : const Loading(); - }, - loading: () => const Loading(), - ), - GridView.count( - shrinkWrap: true, - physics: NeverScrollableScrollPhysics(), - crossAxisCount: rh.deviceWidth(context) * 0.4 > 300 ? 4 : 3, - childAspectRatio: 1, - children: [ - if (isGuest == false && guest == false) - ProfileMenu( - bgColor: getColorScheme(context).primaryContainer, - icon: Iconsax.heart5, - color: getColorScheme(context).onPrimaryContainer, - press: () => context.push('/favorites'), + ], ), - ProfileMenu( - bgColor: getColorScheme(context).secondaryContainer, - color: getColorScheme(context).onSecondaryContainer, - icon: Icons.grass_rounded, - press: () => context.push('/choose_content'), ), - ProfileMenu( - bgColor: getColorScheme(context).inverseSurface, - color: getColorScheme(context).onInverseSurface, - icon: Iconsax.logout, - press: () => guest == false && isGuest == false - ? showDialog( - context: context, - builder: (context) => AlertDialog( - title: Text("Logout"), - content: Text( - "Are you sure you want to log out?"), - actions: [ - TextButton( - onPressed: () => - Navigator.pop(context), - child: Text("Cancel")), - TextButton( - onPressed: () => ref - .read(authHelperProvider) - .logOutfromDjango(context), - child: Text("Logout")), - ], - )) - : ref.read(authHelperProvider).logOutAsGuest(context), + SizedBox( + height: 20, ), - if (isGuest == false && guest == false) - ProfileMenu( - bgColor: getColorScheme(context).errorContainer, - color: getColorScheme(context).onErrorContainer, - icon: Iconsax.profile_delete, - press: () => showDialog( - context: context, - builder: (context) => AlertDialog( - title: Text("Delete Account"), - content: Text( - "Are you sure you want to delete your account?"), - actions: [ - TextButton( - onPressed: () => Navigator.pop(context), - child: Text("Cancel")), - TextButton( - onPressed: () => ref - .read(authHelperProvider) - .deleteUser(context), - child: Text( - "Delete", - style: TextStyle( - color: getColorScheme(context) - .error), - )), - ], - )), - ), + ProfileListTile( + onTap: () => context.push("/update_profile"), + icon: Icons.edit, + name: word.edit_profile), + SizedBox( + height: 20, + ), + ProfileListTile( + onTap: () => context.push('/choose_content'), + icon: Icons.change_circle, + name: word.choose_content), + SizedBox( + height: 20, + ), + ProfileListTile( + onTap: () => context.push('/favorites'), + icon: Icons.favorite, + name: word.favorites), + SizedBox( + height: 20, + ), + ProfileListTile( + onTap: () => context.push('/settings'), + icon: Icons.settings, + name: word.settings), + SizedBox( + height: 20, + ), + ProfileListTile( + onTap: () => isGuest == false + ? showDialog( + context: context, + builder: (context) => AlertDialog( + title: Text(word.logout), + content: Text(word.sure_to_logout), + actions: [ + TextButton( + onPressed: () => + Navigator.pop(context), + child: Text(word.cancel)), + TextButton( + onPressed: () => ref + .read(authHelperProvider) + .logOutfromDjango(context), + child: Text(word.logout)), + ], + )) + : ref + .read(authHelperProvider) + .logOutAsGuest(context), + icon: Icons.logout, + name: word.logout), ], - ) - ]), - ), - floatingActionButton: Visibility( - visible: isGuest == false && guest == false, - child: FloatingActionButton( - onPressed: () => context.push( - "/update_profile", ), - child: const Icon(Iconsax.edit), ), - ), - ) + ) + // SingleChildScrollView( + // child: Column(children: [ + // userData.when( + // data: (data) { + // String guestChange() { + // // if (data.username == + // // "GUEST") if (.languageCode == "en") + // // return "Guest"; + // // else + // // return "ضيف"; + // return data.username ?? ""; + // } + + // final isVeg = ref.watch(isVeganProvider); + + // return Column( + // crossAxisAlignment: CrossAxisAlignment.start, + // children: [ + // UserInfo( + // name: guestChange(), + // image: 'assets/images/profile/default.png', + // ), + // Visibility( + // visible: isGuest == false && guest == false, + // child: FlutterSwitch( + // value: isVeg, + // onToggle: (v) async { + // ref + // .read(isVeganProvider.notifier) + // .update((state) => v); + // await ref + // .read(veganServiceProvider) + // .updateIsVegan(v); + // }, + // inactiveColor: Colors.brown[300]!, + // inactiveIcon: Image.asset( + // 'assets/images/icons/meat.png', + // color: Colors.brown, + // ), + // activeColor: colorScheme(context).secondary, + // activeToggleColor: colorScheme(context).onSecondary, + // activeIcon: Image.asset( + // "assets/images/icons/vegan.png", + // color: colorScheme(context).secondary, + // ), + // ), + // ), + // ], + // ); + // }, + // error: (e, s) { + // log('$e\n$s'); + + // return kDebugMode ? Text(e.toString()) : const Loading(); + // }, + // loading: () => const Loading(), + // ), + // GridView.count( + // shrinkWrap: true, + // physics: NeverScrollableScrollPhysics(), + // crossAxisCount: rh.deviceWidth(context) * 0.4 > 300 ? 4 : 3, + // childAspectRatio: 1, + // children: [ + // if (isGuest == false && guest == false) + // ProfileMenu( + // bgColor: colorScheme(context).primaryContainer, + // icon: Icons.favorite_rounded, + // color: colorScheme(context).onPrimaryContainer, + // press: () => context.push('/favorites'), + // ), + // ProfileMenu( + // bgColor: colorScheme(context).tertiaryContainer, + // color: colorScheme(context).onTertiaryContainer, + // icon: Icons.grass_rounded, + // press: () => context.push('/choose_content'), + // ), + // ProfileMenu( + // bgColor: colorScheme(context).inverseSurface, + // color: colorScheme(context).onInverseSurface, + // icon: Icons.logout, + // press: () => guest == false && isGuest == false + // ? showDialog( + // context: context, + // builder: (context) => AlertDialog( + // title: Text(word?.logout ?? ""), + // content: Text(word?.sure_to_logout ?? ""), + // actions: [ + // TextButton( + // onPressed: () => + // Navigator.pop(context), + // child: Text(word?.cancel ?? "")), + // TextButton( + // onPressed: () => ref + // .read(authHelperProvider) + // .logOutfromDjango(context), + // child: Text(word?.logout ?? "")), + // ], + // )) + // : ref.read(authHelperProvider).logOutAsGuest(context), + // ), + // if (isGuest == false && guest == false) + // ProfileMenu( + // bgColor: colorScheme(context).errorContainer, + // color: colorScheme(context).onErrorContainer, + // icon: Icons.delete_forever, + // press: () => showDialog( + // context: context, + // builder: (context) => AlertDialog( + // title: Text(word?.delete_account ?? ""), + // content: Text(word?.sure_to_delete ?? ""), + // actions: [ + // TextButton( + // onPressed: () => Navigator.pop(context), + // child: Text(word?.cancel ?? "")), + // TextButton( + // onPressed: () => ref + // .read(authHelperProvider) + // .deleteUser(context), + // child: Text( + // word?.delete ?? "", + // style: TextStyle( + // color: + // colorScheme(context).error), + // )), + // ], + // )), + // ), + // ], + // ) + // ]), + // ), + // floatingActionButton: Visibility( + // visible: isGuest == false && guest == false, + // child: FloatingActionButton( + // onPressed: () => context.push( + // "/update_profile", + // ), + // child: const Icon(Icons.edit), + // ), + // ), + ) : NoConnection(); } } +class ProfileListTile extends StatelessWidget { + const ProfileListTile({ + super.key, + this.onTap, + required this.name, + required this.icon, + this.trailingIcon = const Icon(Icons.arrow_forward), + }); + final Function()? onTap; + final String name; + final IconData icon; + final Widget trailingIcon; + + @override + Widget build(BuildContext context) { + return ListTile( + onTap: onTap, + leading: CircleAvatar( + backgroundColor: Theme.of(context).colorScheme.secondary, + child: Icon( + icon, + color: Theme.of(context).colorScheme.onSecondary, + ), + ), + title: Text(name), + trailing: trailingIcon); + } +} + class ProfileMenu extends StatelessWidget { const ProfileMenu({ Key? key, @@ -253,29 +433,28 @@ class UserInfo extends StatelessWidget { ClipPath( clipper: CustomShape(), child: Container( - height: 150, - color: Theme.of(context).brightness == Brightness.dark - ? darkColorScheme.background - : lightColorScheme.secondaryContainer, - ), + height: 150, + color: Theme.of(context).colorScheme.secondaryContainer), ), Center( child: Column( mainAxisAlignment: MainAxisAlignment.center, children: [ - Container( - margin: const EdgeInsets.only(bottom: 10), - height: 140, - width: 140, - decoration: BoxDecoration( - shape: BoxShape.circle, - border: Border.all( - color: Colors.white, - width: 8, - ), - image: DecorationImage( - image: AssetImage(image), - fit: BoxFit.cover, + SafeArea( + child: Container( + margin: const EdgeInsets.only(bottom: 10), + height: 140, + width: 140, + decoration: BoxDecoration( + shape: BoxShape.circle, + border: Border.all( + color: Colors.white, + width: 8, + ), + image: DecorationImage( + image: AssetImage(image), + fit: BoxFit.cover, + ), ), ), ), @@ -283,9 +462,6 @@ class UserInfo extends StatelessWidget { name, style: TextStyle( fontSize: 22, - fontFamily: context.locale.languageCode == "en" - ? 'Kine' - : GoogleFonts.notoKufiArabic().fontFamily, ), ), ], diff --git a/lib/src/features/auth/profiles/presentation/update_profile.dart b/lib/src/features/auth/profiles/presentation/update_profile.dart index ffa3e0a..1c44a1c 100644 --- a/lib/src/features/auth/profiles/presentation/update_profile.dart +++ b/lib/src/features/auth/profiles/presentation/update_profile.dart @@ -1,18 +1,14 @@ -import 'package:easy_localization/easy_localization.dart'; import 'package:flutter/material.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart'; import 'package:go_router/go_router.dart'; -import 'package:google_fonts/google_fonts.dart'; import 'package:http/http.dart'; import 'package:http/http.dart' as http; -import 'package:iconsax/iconsax.dart'; import 'package:livine/src/features/auth/profiles/presentation/profile.dart'; import 'package:livine/src/common_widgets/auth/auth_widget.dart'; -import 'package:livine/src/translations/locale_keys.g.dart'; +import '../../../../translations/domain/translation_provider.dart'; import '../../application/auth_service.dart'; import '../../../get_recipes/application/vegan_service.dart'; -import '../../../../shared/styles/lib_color_schemes.g.dart'; import '../data/get_user_data.dart'; class UpdateProfile extends ConsumerStatefulWidget { @@ -39,19 +35,11 @@ class _UpdateProfileState extends ConsumerState { username.text = data?.username ?? ""; email.text = data?.email ?? ""; - + final word = TranslationRepo.translate(context); return Scaffold( appBar: AppBar( - title: Text(LocaleKeys.update.tr(), - style: TextStyle( - fontFamily: context.locale.languageCode == "en" - ? 'Kine' - : GoogleFonts.notoKufiArabic().fontFamily, - )), - centerTitle: true, - backgroundColor: Theme.of(context).brightness == Brightness.dark - ? darkColorScheme.background - : lightColorScheme.secondaryContainer, + title: Text(word!.edit_profile), + backgroundColor: Theme.of(context).colorScheme.secondaryContainer, ), body: Column(children: [ UserInfo( @@ -67,7 +55,7 @@ class _UpdateProfileState extends ConsumerState { authFormField( context: context, controller: username, - text: LocaleKeys.username.tr(), + text: word.username, setState: setState, validator: (u) { if (u!.isEmpty) { @@ -84,15 +72,11 @@ class _UpdateProfileState extends ConsumerState { authFormField( context: context, controller: email, - text: context.locale.languageCode == "en" - ? "Email" - : "البريد الإلكتروني", + text: "Email", setState: setState, validator: (e) { if (e!.isEmpty) { - return context.locale.languageCode == "en" - ? "Please enter your email" - : "من فضلك ادخل البريد الاكتروني"; + return "Please enter your email"; } return null; @@ -112,7 +96,7 @@ class _UpdateProfileState extends ConsumerState { context, username.text, email.text, data?.patient ?? 5, isVeg) .then((value) => context.pop()); }, - child: const Icon(Iconsax.arrow_up), + child: const Icon(Icons.save), ), ); } diff --git a/lib/src/features/auth/register/presentation/register.dart b/lib/src/features/auth/register/presentation/register.dart index e22f942..8c406ee 100644 --- a/lib/src/features/auth/register/presentation/register.dart +++ b/lib/src/features/auth/register/presentation/register.dart @@ -3,18 +3,16 @@ import 'dart:convert'; import 'dart:io'; -import 'package:easy_localization/easy_localization.dart'; import 'package:flutter/gestures.dart'; import 'package:flutter/material.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart'; import 'package:go_router/go_router.dart'; import 'package:http/http.dart'; import 'package:http/http.dart' as http; -import 'package:iconsax/iconsax.dart'; +import 'package:livine/src/constants/constants.dart'; import 'package:livine/src/features/auth/application/auth_service.dart'; -import '../../../../common_widgets/auth/auth_widget.dart'; -import '../../../../translations/locale_keys.g.dart'; +import '../../../../translations/domain/translation_provider.dart'; class Register extends ConsumerStatefulWidget { const Register({Key? key}) : super(key: key); @@ -67,196 +65,233 @@ class _RegisterState extends ConsumerState { @override Widget build(BuildContext context) { final theme = Theme.of(context).colorScheme; - + final word = TranslationRepo.translate(context); return Scaffold( - body: Row( - children: [ - Visibility( - visible: Platform.isWindows, - child: Expanded( - flex: 2, - child: ClipRRect( - borderRadius: const BorderRadius.only( - topRight: Radius.circular(20), - bottomRight: Radius.circular(20)), - child: Image.asset( - 'assets/images/windows/register.webp', - fit: BoxFit.cover, - ), - )), - ), - Expanded( - child: Form( - key: _formKey, - child: Column( - mainAxisAlignment: MainAxisAlignment.center, - children: [ - Padding( - padding: const EdgeInsets.symmetric(horizontal: 20), - child: TextFormField( - textInputAction: TextInputAction.next, - maxLength: 20, - validator: (u) { - if (u!.isEmpty) { - return "Please enter your username"; - } else if (u.length >= 20) { - return "Username shouldn't be more than 20 characters"; - } - return null; - }, - controller: _username, - decoration: InputDecoration( - errorText: usernameError is List - ? usernameError.first - : usernameError, - errorMaxLines: 2, - border: const OutlineInputBorder( - borderRadius: - BorderRadius.all(Radius.circular(10.0))), - labelText: LocaleKeys.username.tr(), - labelStyle: const TextStyle( - fontSize: 15, - ), + body: SafeArea( + child: Padding( + padding: EdgeInsets.only(top: rh.deviceHeight(context) * 0.1), + child: Row( + children: [ + Visibility( + visible: Platform.isWindows, + child: Expanded( + flex: 2, + child: ClipRRect( + borderRadius: const BorderRadius.only( + topRight: Radius.circular(20), + bottomRight: Radius.circular(20)), + child: Image.asset( + 'assets/images/windows/register.webp', + fit: BoxFit.cover, ), - ), - ), - Padding( - padding: const EdgeInsets.symmetric(horizontal: 20), - child: TextFormField( - textInputAction: TextInputAction.next, - validator: (e) { - if (e!.isEmpty) { - return context.locale.languageCode == "en" - ? "Please enter your email" - : "من فضلك ادخل البريد الاكتروني"; - } + )), + ), + Expanded( + child: Form( + key: _formKey, + child: SingleChildScrollView( + child: Column( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + Padding( + padding: const EdgeInsets.symmetric(horizontal: 20), + child: TextFormField( + textInputAction: TextInputAction.next, + maxLength: 20, + validator: (u) { + if (u!.isEmpty) { + return "Please enter your username"; + } else if (u.length >= 20) { + return "Username shouldn't be more than 20 characters"; + } + return null; + }, + controller: _username, + decoration: InputDecoration( + errorText: usernameError is List + ? usernameError.first + : usernameError, + errorMaxLines: 2, + border: const OutlineInputBorder( + borderRadius: + BorderRadius.all(Radius.circular(10.0))), + labelText: word?.username, + labelStyle: const TextStyle( + fontSize: 15, + ), + ), + ), + ), + Padding( + padding: const EdgeInsets.symmetric(horizontal: 20), + child: TextFormField( + textInputAction: TextInputAction.next, + validator: (e) { + if (e!.isEmpty) { + return "Please enter your email"; + } - return null; - }, - controller: _email, - decoration: InputDecoration( - errorText: emailError, - border: const OutlineInputBorder( - borderRadius: - BorderRadius.all(Radius.circular(10.0))), - labelText: context.locale.languageCode == "en" - ? 'Email' - : "البريد الاكتروني", - labelStyle: const TextStyle( - fontSize: 15, + return null; + }, + controller: _email, + decoration: InputDecoration( + errorText: emailError, + border: const OutlineInputBorder( + borderRadius: + BorderRadius.all(Radius.circular(10.0))), + labelText: word?.email_address, + labelStyle: const TextStyle( + fontSize: 15, + ), + ), + ), ), - ), - ), - ), - SizedBox( - height: 20, - ), - Padding( - padding: const EdgeInsets.symmetric(horizontal: 20), - child: TextFormField( - validator: (passwordValue) { - if (passwordValue!.length < 9 && - passwordValue.isNotEmpty) { - return context.locale.languageCode == "en" - ? "Password needs to be atleast 9 characters " - : "يجب أن تتكون كلمة المرور من 9 أحرف على الأقل"; - } else if (passwordValue.isEmpty) { - return context.locale.languageCode == "en" - ? "Please enter your password " - : "من فضلك أدخل كلمة السر"; - } - return null; - }, - controller: _password, - obscureText: _obscureText, - onFieldSubmitted: (_) => validateForm(), - decoration: InputDecoration( - suffixIcon: IconButton( - icon: Icon( - _obscureText ? Iconsax.eye_slash5 : Iconsax.eye, + SizedBox( + height: 20, + ), + Padding( + padding: const EdgeInsets.symmetric(horizontal: 20), + child: TextFormField( + validator: (passwordValue) { + if (passwordValue!.length < 9 && + passwordValue.isNotEmpty) { + return "Password needs to be atleast 9 characters "; + } else if (passwordValue.isEmpty) { + return "Please enter your password "; + } + return null; + }, + controller: _password, + obscureText: _obscureText, + onFieldSubmitted: (_) => validateForm(), + decoration: InputDecoration( + suffixIcon: IconButton( + icon: Icon( + _obscureText + ? Icons.visibility_off + : Icons.visibility, + ), + onPressed: () { + setState(() { + _obscureText = !_obscureText; + }); + }, + ), + border: const OutlineInputBorder( + borderRadius: + BorderRadius.all(Radius.circular(10.0))), + labelText: word?.password, + labelStyle: const TextStyle(fontSize: 15), + ), ), - onPressed: () { - setState(() { - _obscureText = !_obscureText; - }); - }, ), - border: const OutlineInputBorder( - borderRadius: - BorderRadius.all(Radius.circular(10.0))), - labelText: LocaleKeys.password.tr(), - labelStyle: const TextStyle(fontSize: 15), - ), - ), - ), - const SizedBox( - height: 20, - ), - authButton( - onPressed: validateForm, - isLoading: isLoading, - text: LocaleKeys.Sign_up.tr(), - context: context), - const SizedBox( - height: 20, - ), - Center( - child: Row( - mainAxisAlignment: MainAxisAlignment.center, - children: [ - Text( - LocaleKeys.have_an_account.tr(), - style: const TextStyle(fontFamily: 'Kine'), + const SizedBox( + height: 20, ), + ({ + required void Function() onPressed, + required bool isLoading, + required String text, + Color? color, + Color? textColor, + double width = 350, + required BuildContext context, + }) { + final theme = Theme.of(context).colorScheme; + return Padding( + padding: + const EdgeInsets.symmetric(horizontal: 20.0), + child: MaterialButton( + onPressed: onPressed, + color: color ?? theme.primaryContainer, + elevation: 0, + minWidth: width, + height: 60, + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.circular(15), + ), + child: isLoading + ? const CircularProgressIndicator( + color: Colors.white, + ) + : Text( + text, + style: TextStyle( + fontSize: 15, + color: textColor ?? + theme.onPrimaryContainer), + ), + ), + ); + }( + onPressed: validateForm, + isLoading: isLoading, + text: word?.sign_up ?? 'Sign Up', + context: context), const SizedBox( - width: 10, + height: 20, ), - GestureDetector( - onTap: () => context.go('/login'), - child: Text( - LocaleKeys.Sign_in.tr(), - style: TextStyle( - fontSize: 16.0, - color: theme.tertiary, - fontFamily: 'Kine'), + Center( + child: Row( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + Text( + word?.have_an_account ?? 'Have an account?', + style: const TextStyle(fontFamily: 'Kine'), + ), + const SizedBox( + width: 10, + ), + GestureDetector( + onTap: () => context.go('/login'), + child: Text( + word?.sign_in ?? 'Sign In', + style: TextStyle( + fontSize: 16.0, + color: theme.tertiary, + fontFamily: 'Kine'), + ), + ), + ], ), ), - ], - ), - ), - const SizedBox( - height: 10.0, - ), - RichText( - textAlign: TextAlign.center, - text: TextSpan( - children: [ - TextSpan( - text: LocaleKeys.terms1.tr(), - style: TextStyle( - fontSize: 15.0, color: theme.inverseSurface)), - const WidgetSpan( - child: Padding( - padding: EdgeInsets.only(left: 10.0), + const SizedBox( + height: 10.0, + ), + RichText( + textAlign: TextAlign.center, + text: TextSpan( + children: [ + TextSpan( + text: word?.terms1, + style: TextStyle( + fontSize: 15.0, + color: theme.inverseSurface)), + const WidgetSpan( + child: Padding( + padding: EdgeInsets.only(left: 10.0), + ), + ), + TextSpan( + text: word?.terms2, + recognizer: TapGestureRecognizer() + ..onTap = () => context.push('/terms'), + style: TextStyle( + fontSize: 15.0, + fontWeight: FontWeight.bold, + fontFamily: 'Kine', + color: theme.tertiary)), + ], ), ), - TextSpan( - text: LocaleKeys.terms2.tr(), - recognizer: TapGestureRecognizer() - ..onTap = () => context.push('/terms'), - style: TextStyle( - fontSize: 15.0, - fontWeight: FontWeight.bold, - fontFamily: 'Kine', - color: theme.tertiary)), ], ), ), - ], + ), ), - ), + ], ), - ], + ), ), ); } diff --git a/lib/src/features/auth/reset_password/presentation/reset_password.dart b/lib/src/features/auth/reset_password/presentation/reset_password.dart index 21454fa..bea3c09 100644 --- a/lib/src/features/auth/reset_password/presentation/reset_password.dart +++ b/lib/src/features/auth/reset_password/presentation/reset_password.dart @@ -1,14 +1,12 @@ import 'dart:developer'; -import 'package:easy_localization/easy_localization.dart'; import 'package:flutter/material.dart'; import 'package:go_router/go_router.dart'; import 'package:http/http.dart'; import 'package:http/http.dart' as http; +import 'package:livine/src/translations/domain/translation_provider.dart'; import '../../../../constants/constants.dart'; -import '../../../../common_widgets/auth/auth_widget.dart'; -import '../../../../translations/locale_keys.g.dart'; class ResetPassword extends StatefulWidget { const ResetPassword({Key? key}) : super(key: key); @@ -31,9 +29,7 @@ class _ResetPasswordState extends State { if (response.statusCode == 200) { if (!mounted) return; ScaffoldMessenger.of(context).showSnackBar(SnackBar( - content: Text(context.locale.languageCode == "en" - ? "Please check your email" - : "من فضلك تفقد بريدك الالكتروني"), + content: Text("Please check your email"), )); setState(() { isLoading = false; @@ -60,9 +56,10 @@ class _ResetPasswordState extends State { @override Widget build(BuildContext context) { + final word = TranslationRepo.translate(context); return Scaffold( appBar: AppBar( - title: Text(LocaleKeys.Reset_pass.tr()), + title: Text(word?.reset_pass ?? "Reset Password"), ), body: Column( children: [ @@ -76,9 +73,7 @@ class _ResetPasswordState extends State { textInputAction: TextInputAction.next, validator: (e) { if (e!.isEmpty) { - return context.locale.languageCode == "en" - ? "Please enter your email" - : "من فضلك ادخل البريد الاكتروني"; + return "Please enter your email"; } return null; @@ -88,18 +83,50 @@ class _ResetPasswordState extends State { border: const OutlineInputBorder( borderRadius: BorderRadius.all(Radius.circular(10.0))), - labelText: context.locale.languageCode == "en" - ? 'Email' - : "البريد الاكتروني", + labelText: word?.email_address, labelStyle: const TextStyle( fontSize: 15, ), ), ), - authButton( + ({ + required void Function() onPressed, + required bool isLoading, + required String text, + Color? color, + Color? textColor, + double width = 350, + required BuildContext context, + }) { + final theme = Theme.of(context).colorScheme; + return Padding( + padding: const EdgeInsets.symmetric(horizontal: 20.0), + child: MaterialButton( + onPressed: onPressed, + color: color ?? theme.primaryContainer, + elevation: 0, + minWidth: width, + height: 60, + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.circular(15), + ), + child: isLoading + ? const CircularProgressIndicator( + color: Colors.white, + ) + : Text( + text, + style: TextStyle( + fontSize: 15, + color: textColor ?? + theme.onPrimaryContainer), + ), + ), + ); + }( onPressed: validateRPForm, isLoading: isLoading, - text: LocaleKeys.Reset_pass.tr(), + text: word?.reset_pass ?? "Reset Password", context: context) ], ), diff --git a/lib/src/features/auth/reset_password/presentation/reset_password_confirm.dart b/lib/src/features/auth/reset_password/presentation/reset_password_confirm.dart index 78745ef..73876a3 100644 --- a/lib/src/features/auth/reset_password/presentation/reset_password_confirm.dart +++ b/lib/src/features/auth/reset_password/presentation/reset_password_confirm.dart @@ -1,15 +1,12 @@ import 'dart:developer'; -import 'package:easy_localization/easy_localization.dart'; import 'package:flutter/material.dart'; import 'package:go_router/go_router.dart'; import 'package:http/http.dart'; import 'package:http/http.dart' as http; +import 'package:livine/src/translations/domain/translation_provider.dart'; import '../../../../constants/constants.dart'; -import '../../../../shared/styles/colors.dart'; -import '../../../../common_widgets/auth/auth_widget.dart'; -import '../../../../translations/locale_keys.g.dart'; class PasswordConfirmation extends StatefulWidget { const PasswordConfirmation({Key? key, required this.token}) : super(key: key); @@ -41,11 +38,8 @@ class _PasswordConfirmationState extends State { if (response.statusCode == 200) { if (!mounted) return; - ScaffoldMessenger.of(context).showSnackBar(SnackBar( - content: Text(context.locale.languageCode == "en" - ? "Your password have succesfully changed" - : "تم تغيير كلمة السر بنجاح"), - )); + ScaffoldMessenger.of(context).showSnackBar( + SnackBar(content: Text("Your password have succesfully changed"))); setState(() { isLoading = false; }); @@ -71,9 +65,10 @@ class _PasswordConfirmationState extends State { @override Widget build(BuildContext context) { + final word = TranslationRepo.translate(context); return Scaffold( appBar: AppBar( - title: Text(LocaleKeys.pass_confirm.tr()), + title: Text(word?.pass_confirm ?? ""), centerTitle: true, ), body: Column( @@ -88,24 +83,19 @@ class _PasswordConfirmationState extends State { textInputAction: TextInputAction.next, validator: (e) { if (e!.isEmpty) { - return context.locale.languageCode == "en" - ? "Please enter your token" - : "من فضلك ادخل الرمز الخاص بك"; + return "Please enter your token"; } return null; }, controller: _token, decoration: InputDecoration( - helperText: context.locale.languageCode == " en " - ? "Enter the token that has been sent to your email" - : " أدخل الرمز المميز الذي تم إرساله إلى بريدك الإلكتروني الخاص بك", + helperText: + "Enter the token that has been sent to your email", enabledBorder: const UnderlineInputBorder( borderSide: BorderSide(), ), - labelText: context.locale.languageCode == "en" - ? 'Token' - : "الرمز", + labelText: 'Token', labelStyle: const TextStyle( fontSize: 15, color: Colors.black, @@ -116,9 +106,7 @@ class _PasswordConfirmationState extends State { textInputAction: TextInputAction.next, validator: (e) { if (e!.isEmpty) { - return context.locale.languageCode == "en" - ? "Please enter your new password" - : "من فضلك ادخل كلمة السر الجديدة"; + return "Please enter your new password"; } return null; @@ -131,8 +119,7 @@ class _PasswordConfirmationState extends State { _obscureText ? Icons.visibility_off : Icons.visibility, - color: - _obscureText ? Colors.grey : secondaryColor), + color: _obscureText ? Colors.grey : Colors.green), onPressed: () { setState(() { _obscureText = !_obscureText; @@ -142,18 +129,50 @@ class _PasswordConfirmationState extends State { border: const OutlineInputBorder( borderRadius: BorderRadius.all(Radius.circular(10.0))), - labelText: context.locale.languageCode == "en" - ? 'New Password' - : "كلمة المرور الجديدة", + labelText: 'New Password', labelStyle: const TextStyle( fontSize: 15, ), ), ), - authButton( + ({ + required void Function() onPressed, + required bool isLoading, + required String text, + Color? color, + Color? textColor, + double width = 350, + required BuildContext context, + }) { + final theme = Theme.of(context).colorScheme; + return Padding( + padding: const EdgeInsets.symmetric(horizontal: 20.0), + child: MaterialButton( + onPressed: onPressed, + color: color ?? theme.primaryContainer, + elevation: 0, + minWidth: width, + height: 60, + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.circular(15), + ), + child: isLoading + ? const CircularProgressIndicator( + color: Colors.white, + ) + : Text( + text, + style: TextStyle( + fontSize: 15, + color: textColor ?? + theme.onPrimaryContainer), + ), + ), + ); + }( onPressed: validatePasswordForm, isLoading: isLoading, - text: LocaleKeys.change_password.tr(), + text: word?.change_password ?? "", context: context) ], ), diff --git a/lib/src/features/auth/reset_password/presentation/token_validate.dart b/lib/src/features/auth/reset_password/presentation/token_validate.dart index 0bb196e..6228b59 100644 --- a/lib/src/features/auth/reset_password/presentation/token_validate.dart +++ b/lib/src/features/auth/reset_password/presentation/token_validate.dart @@ -1,14 +1,12 @@ import 'dart:developer'; -import 'package:easy_localization/easy_localization.dart'; import 'package:flutter/material.dart'; import 'package:go_router/go_router.dart'; import 'package:http/http.dart'; import 'package:http/http.dart' as http; +import 'package:livine/src/translations/domain/translation_provider.dart'; import '../../../../constants/constants.dart'; -import '../../../../common_widgets/auth/auth_widget.dart'; -import '../../../../translations/locale_keys.g.dart'; class TokenValidate extends StatefulWidget { const TokenValidate({Key? key}) : super(key: key); @@ -55,9 +53,10 @@ class _TokenValidateState extends State { @override Widget build(BuildContext context) { + final word = TranslationRepo.translate(context); return Scaffold( appBar: AppBar( - title: Text(LocaleKeys.enter_token.tr()), + title: Text(word?.validate_token ?? "Validate Token"), centerTitle: true, ), body: Column( @@ -72,33 +71,61 @@ class _TokenValidateState extends State { textInputAction: TextInputAction.next, validator: (e) { if (e!.isEmpty) { - return context.locale.languageCode == "en" - ? "Please enter your token" - : "من فضلك ادخل الرمز الخاص بك"; + return "Please enter your token"; } return null; }, controller: _token, decoration: InputDecoration( - helperText: context.locale.languageCode == "en" - ? "Enter the token that has been sent to your email" - : " أدخل الرمز المميز الذي تم إرساله إلى بريدك الإلكتروني الخاص بك", + helperText: word?.enter_token_has_sent, border: const OutlineInputBorder( borderRadius: BorderRadius.all(Radius.circular(10.0))), - labelText: context.locale.languageCode == "en" - ? 'Code' - : "الرمز", + labelText: word?.code, labelStyle: const TextStyle( fontSize: 15, ), ), ), - authButton( + ({ + required void Function() onPressed, + required bool isLoading, + required String text, + Color? color, + Color? textColor, + double width = 350, + required BuildContext context, + }) { + final theme = Theme.of(context).colorScheme; + return Padding( + padding: const EdgeInsets.symmetric(horizontal: 20.0), + child: MaterialButton( + onPressed: onPressed, + color: color ?? theme.primaryContainer, + elevation: 0, + minWidth: width, + height: 60, + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.circular(15), + ), + child: isLoading + ? const CircularProgressIndicator( + color: Colors.white, + ) + : Text( + text, + style: TextStyle( + fontSize: 15, + color: textColor ?? + theme.onPrimaryContainer), + ), + ), + ); + }( onPressed: validateTokenForm, isLoading: isLoading, - text: LocaleKeys.validate_token.tr(), + text: word?.validate_token ?? "Validate Token", context: context) ], ), diff --git a/lib/src/features/auth/welcome/presentation/welcome.dart b/lib/src/features/auth/welcome/presentation/welcome.dart index 3afe8f0..19ab6cd 100644 --- a/lib/src/features/auth/welcome/presentation/welcome.dart +++ b/lib/src/features/auth/welcome/presentation/welcome.dart @@ -3,10 +3,10 @@ import 'dart:developer'; import 'package:flutter/material.dart'; import 'package:flutter_svg/svg.dart'; import 'package:go_router/go_router.dart'; -import 'package:responsive_framework/responsive_framework.dart'; +import 'package:responsive_framework/responsive_row_column.dart'; import '../../../../constants/constants.dart'; -import '../../../../common_widgets/auth/auth_widget.dart'; +import '../../../../translations/domain/translation_provider.dart'; class Welcome extends StatelessWidget { const Welcome({Key? key}) : super(key: key); @@ -14,15 +14,17 @@ class Welcome extends StatelessWidget { @override Widget build(BuildContext context) { bool isLoading = false; + final word = TranslationRepo.translate(context); log(rh.deviceWidth(context).toString()); return Scaffold( body: SafeArea( child: ResponsiveRowColumn( - layout: rh.deviceWidth(context) <= 800 && - rh.deviceWidth(context) > 400 || - rh.largerThanMobile(context) + layout: rh.largerThanMobile(context) || rh.deviceLandScape(context) ? ResponsiveRowColumnType.ROW : ResponsiveRowColumnType.COLUMN, + columnMainAxisAlignment: MainAxisAlignment.spaceEvenly, + rowMainAxisAlignment: MainAxisAlignment.center, + rowCrossAxisAlignment: CrossAxisAlignment.center, children: [ ResponsiveRowColumnItem( child: Center( @@ -36,13 +38,10 @@ class Welcome extends StatelessWidget { ), ResponsiveRowColumnItem( child: Padding( - padding: EdgeInsets.symmetric( - vertical: rh.largerThanMobile(context) - ? rh.deviceHeight(context) * 0.25 - : rh.deviceHeight(context) * 0.03, - horizontal: 10), + padding: EdgeInsets.symmetric(horizontal: 10), child: Column( - crossAxisAlignment: CrossAxisAlignment.start, + crossAxisAlignment: CrossAxisAlignment.center, + mainAxisAlignment: MainAxisAlignment.center, children: [ Padding( padding: const EdgeInsets.symmetric(horizontal: 20), @@ -51,7 +50,7 @@ class Welcome extends StatelessWidget { crossAxisAlignment: CrossAxisAlignment.start, children: [ Text( - "Welcome", + word?.welcome ?? "Welcome", style: TextStyle( fontFamily: 'Kine', fontSize: 50.0, @@ -59,14 +58,15 @@ class Welcome extends StatelessWidget { ), Container( width: rh.deviceLandScape(context) - ? rh.deviceHeight(context) * 0.9 - : rh.deviceHeight(context) * 0.4, + ? rh.deviceWidth(context) * 0.4 + : null, child: Text( - "Let's live naturally without any type of medications", + word?.live_naturally ?? + "Live naturally, eat healthy, and be happy", style: TextStyle( fontFamily: 'Kine', fontSize: 20.0, - color: getColorScheme(context) + color: colorScheme(context) .onBackground .withOpacity(0.3)), ), @@ -74,34 +74,65 @@ class Welcome extends StatelessWidget { ], ), ), - SizedBox( - height: rh.deviceLandScape(context) - ? rh.deviceWidth(context) * 0.03 - : 80, - ), - Column( - children: [ - authButton( - onPressed: () { - context.push("/register"); - }, - isLoading: isLoading, - text: "Get Started", - context: context), - SizedBox( - height: 20, - ), - GestureDetector( - onTap: () { - context.push("/login"); - }, - child: Text( - "I already have an account", - style: - TextStyle(fontFamily: 'Kine', fontSize: 18.0), + Center( + child: ({ + required void Function() onPressed, + required bool isLoading, + required String text, + Color? color, + Color? textColor, + double width = 350, + required BuildContext context, + }) { + final theme = Theme.of(context).colorScheme; + return Padding( + padding: + const EdgeInsets.symmetric(horizontal: 20.0), + child: MaterialButton( + onPressed: onPressed, + color: color ?? theme.primaryContainer, + elevation: 0, + minWidth: width, + height: 60, + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.circular(15), + ), + child: isLoading + ? const CircularProgressIndicator( + color: Colors.white, + ) + : Text( + text, + style: TextStyle( + fontSize: 15, + color: textColor ?? + theme.onPrimaryContainer), + ), ), + ); + }( + onPressed: () { + context.push("/register"); + }, + isLoading: isLoading, + width: rh.deviceLandScape(context) + ? rh.deviceWidth(context) / 2.4 + : 360, + text: word?.get_started ?? "Get Started", + context: context), + ), + SizedBox(height: 20.0), + GestureDetector( + onTap: () { + context.push("/login"); + }, + child: Center( + child: Text( + word?.have_an_account ?? "Have an account?", + style: + TextStyle(fontFamily: 'Kine', fontSize: 18.0), ), - ], + ), ), ], ), diff --git a/lib/src/features/content/presentation/content.dart b/lib/src/features/content/presentation/content.dart index 00a6ba3..468f974 100644 --- a/lib/src/features/content/presentation/content.dart +++ b/lib/src/features/content/presentation/content.dart @@ -1,19 +1,16 @@ import 'package:cached_network_image/cached_network_image.dart'; -import 'package:easy_localization/easy_localization.dart'; import 'package:flutter/material.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart'; import 'package:go_router/go_router.dart'; -import 'package:google_fonts/google_fonts.dart'; import 'package:livine/src/constants/constants.dart'; import 'package:livine/src/features/loading/loading.dart'; import 'package:livine/src/shared/cache/cache_helper.dart'; import 'package:responsive_framework/responsive_framework.dart'; +import '../../../translations/domain/translation_provider.dart'; import '../../auth/data/user.dart'; import '../../auth/application/auth_service.dart'; -import '../../../common_widgets/auth/auth_widget.dart'; -import '../../../translations/locale_keys.g.dart'; import '../../auth/profiles/data/get_user_data.dart'; class ChooseContent extends StatefulWidget { @@ -26,6 +23,7 @@ class ChooseContent extends StatefulWidget { class _ChooseContentState extends State { @override Widget build(BuildContext context) { + final word = TranslationRepo.translate(context); return Scaffold( appBar: AppBar( backgroundColor: Colors.transparent, @@ -45,8 +43,8 @@ class _ChooseContentState extends State { ResponsiveRowColumnItem( rowFlex: 1, child: Options( - title: LocaleKeys.General.tr(), - description: LocaleKeys.healthy.tr(), + title: word?.general ?? "", + description: word?.healthy ?? "", networkImage: 'https://media.istockphoto.com/photos/healthy-lifestyle-concept-clean-food-good-health-dietary-in-heart-picture-id953674568?k=20&m=953674568&s=612x612&w=0&h=x_gq29MRpRyhdDIgwF5PVhdXAbINmaBUKMgs27w7i6s=', onpressed: () async { @@ -75,8 +73,8 @@ class _ChooseContentState extends State { ResponsiveRowColumnItem( rowFlex: 1, child: Options( - title: LocaleKeys.per_situation.tr(), - description: LocaleKeys.patient.tr(), + title: word?.per_situation ?? "", + description: word?.patient ?? "", networkImage: 'https://media.istockphoto.com/photos/its-the-season-of-sneezes-picture-id1085020818?b=1&k=20&m=1085020818&s=170667a&w=0&h=d4AbNzh6ztl2XV-oUo36FitS45O1AUraO2wJhOP5Roo=', onpressed: () => context.push('/content_patient'), @@ -107,6 +105,8 @@ class Options extends StatelessWidget { @override Widget build(BuildContext context) { + final word = TranslationRepo.translate(context); + return Column( children: [ ClipRRect( @@ -125,11 +125,7 @@ class Options extends StatelessWidget { const SizedBox(height: 20), Text( title, - style: TextStyle( - fontFamily: context.locale.languageCode == "en" - ? 'Kine' - : GoogleFonts.notoKufiArabic().fontFamily, - fontSize: 20.0), + style: TextStyle(fontSize: 20.0), ), const SizedBox( height: 10, @@ -137,20 +133,48 @@ class Options extends StatelessWidget { Padding( padding: const EdgeInsets.symmetric(horizontal: 50.0), child: Text(description, - textAlign: TextAlign.center, - style: TextStyle( - fontFamily: context.locale.languageCode == "en" - ? 'Kine' - : GoogleFonts.notoKufiArabic().fontFamily, - fontSize: 15.0)), + textAlign: TextAlign.center, style: TextStyle(fontSize: 15.0)), ), const SizedBox( height: 10, ), - authButton( + ({ + required void Function() onPressed, + required bool isLoading, + required String text, + Color? color, + Color? textColor, + double width = 350, + required BuildContext context, + }) { + final theme = Theme.of(context).colorScheme; + return Padding( + padding: const EdgeInsets.symmetric(horizontal: 20.0), + child: MaterialButton( + onPressed: onPressed, + color: color ?? theme.primaryContainer, + elevation: 0, + minWidth: width, + height: 60, + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.circular(15), + ), + child: isLoading + ? const CircularProgressIndicator( + color: Colors.white, + ) + : Text( + text, + style: TextStyle( + fontSize: 15, + color: textColor ?? theme.onPrimaryContainer), + ), + ), + ); + }( onPressed: onpressed, isLoading: false, - text: context.locale.languageCode == "en" ? "Continue" : "التالي", + text: word?.choose ?? "Choose", context: context) ], ); diff --git a/lib/src/features/content/presentation/content_patients.dart b/lib/src/features/content/presentation/content_patients.dart index 7db17b3..0459a75 100644 --- a/lib/src/features/content/presentation/content_patients.dart +++ b/lib/src/features/content/presentation/content_patients.dart @@ -2,22 +2,19 @@ import 'dart:developer'; import 'dart:ui'; import 'package:cached_network_image/cached_network_image.dart'; -import 'package:easy_localization/easy_localization.dart'; import 'package:flutter/foundation.dart'; import 'package:flutter/material.dart'; import 'package:go_router/go_router.dart'; -import 'package:google_fonts/google_fonts.dart'; import 'package:hooks_riverpod/hooks_riverpod.dart'; import 'package:livine/src/constants/constants.dart'; +import 'package:livine/src/translations/domain/translation_provider.dart'; import '../../auth/data/user.dart'; import '../../loading/loading.dart'; import '../../auth/application/auth_service.dart'; import '../../../shared/cache/cache_helper.dart'; -import '../../../common_widgets/auth/auth_widget.dart'; import '../../auth/profiles/data/get_user_data.dart'; -import '../../get_recipes/data/patient_types.dart'; -import '../../../translations/locale_keys.g.dart'; +import '../../get_recipes/data/patients.dart'; class ContentPatient extends StatefulWidget { const ContentPatient({Key? key}) : super(key: key); @@ -30,10 +27,11 @@ class _ContentPatientState extends State { int? checkedIndex; @override Widget build(BuildContext context) { + final word = TranslationRepo.translate(context); return Scaffold( appBar: AppBar( title: Text( - LocaleKeys.Iam_a.tr(), + word?.choose_content ?? "", style: const TextStyle(fontFamily: 'Kine'), ), backgroundColor: Colors.transparent, @@ -41,7 +39,7 @@ class _ContentPatientState extends State { ), body: HookConsumer( builder: ((context, ref, child) { - final recipesData = ref.watch(patientTypesProvider); + final recipesData = ref.watch(getPatientsProvider(context: context)); final guest = ref.watch(guestProvider); final userData = ref.watch(userDataProvider).asData?.value; @@ -51,17 +49,19 @@ class _ContentPatientState extends State { children: [ Expanded( child: RawScrollbar( - thumbColor: getColorScheme(context).tertiary, + thumbColor: colorScheme(context).tertiary, thickness: 5, radius: const Radius.circular(10), child: GridView.builder( gridDelegate: SliverGridDelegateWithFixedCrossAxisCount( - crossAxisCount: rh.deviceWidth(context) > 600 ? 4 : 2, + crossAxisCount: + rh.deviceWidth(context) > 600 ? 4 : 2, childAspectRatio: 0.7, ), itemCount: data.length, itemBuilder: (context, index) { + print(data[index].image); return GestureDetector( onTap: () { setState(() { @@ -72,14 +72,14 @@ class _ContentPatientState extends State { child: Card( clipBehavior: Clip.antiAliasWithSaveLayer, color: checkedIndex == index - ? getColorScheme(context).tertiary - : getColorScheme(context).surface, + ? colorScheme(context).tertiary + : colorScheme(context).surface, child: Stack( fit: StackFit.expand, children: [ CachedNetworkImage( imageUrl: - "$restAPIMedia/${data[index].imageURL}", + "$restAPIMedia/${data[index].image}", fit: BoxFit.cover, ), ClipRRect( @@ -93,7 +93,7 @@ class _ContentPatientState extends State { ), child: Container( color: checkedIndex == index - ? getColorScheme(context) + ? colorScheme(context) .primaryContainer .withOpacity(0.5) : Colors.transparent, @@ -118,25 +118,13 @@ class _ContentPatientState extends State { : Colors.transparent), child: Center( child: Text( - context.locale - .languageCode == - 'en' - ? "${data[index].name} Patient" - : "مريض ${data[index].name_in_arabic}", + data[index].name, textAlign: TextAlign.center, style: TextStyle( - color: getColorScheme( - context) - .onSurface, - fontFamily: context - .locale - .languageCode == - "en" - ? 'Kine' - : GoogleFonts - .notoKufiArabic() - .fontFamily, + color: + colorScheme(context) + .onSurface, ), ), ), @@ -155,7 +143,41 @@ class _ContentPatientState extends State { ), ), ), - authButton( + ({ + required void Function() onPressed, + required bool isLoading, + required String text, + Color? color, + Color? textColor, + double width = 350, + required BuildContext context, + }) { + final theme = Theme.of(context).colorScheme; + return Padding( + padding: const EdgeInsets.symmetric(horizontal: 20.0), + child: MaterialButton( + onPressed: onPressed, + color: color ?? theme.primaryContainer, + elevation: 0, + minWidth: width, + height: 60, + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.circular(15), + ), + child: isLoading + ? const CircularProgressIndicator( + color: Colors.white, + ) + : Text( + text, + style: TextStyle( + fontSize: 15, + color: textColor ?? + theme.onPrimaryContainer), + ), + ), + ); + }( onPressed: () { if (checkedIndex != null) { CacheHelper.setInt( @@ -183,9 +205,7 @@ class _ContentPatientState extends State { } }, isLoading: false, - text: context.locale.languageCode == "en" - ? "Continue" - : "التالي", + text: word?.choose ?? "Choose", context: context) ], ); diff --git a/lib/src/features/cooking/data/cooking_data.dart b/lib/src/features/cooking/data/cooking_data.dart new file mode 100644 index 0000000..c580a07 --- /dev/null +++ b/lib/src/features/cooking/data/cooking_data.dart @@ -0,0 +1,27 @@ +import 'dart:convert'; + +import 'package:hooks_riverpod/hooks_riverpod.dart'; + +import '../../../constants/constants.dart'; +import '../../auth/application/auth_service.dart'; +import '../../get_recipes/domain/recipe/recipe.dart'; + + +Future addPoints({required WidgetRef ref,required int points})async{ + final url = '$restAPIURL/user/update/points/'; + + final response = await client.put( + Uri.parse(url), + body: json.encode({"points": points}), + headers: { + 'Authorization': 'Token ${ref.read(authHelperProvider).getToken()}', + 'Content-Type': 'application/json', + }, + ); + print(response.body); + if (response.statusCode == 200) { + return "Successfully added points"; + } + return "Error adding points"; + +} \ No newline at end of file diff --git a/lib/src/features/cooking/data/cooking_domain.dart b/lib/src/features/cooking/data/cooking_domain.dart new file mode 100644 index 0000000..8b13789 --- /dev/null +++ b/lib/src/features/cooking/data/cooking_domain.dart @@ -0,0 +1 @@ + diff --git a/lib/src/features/cooking/presentation/cooking.dart b/lib/src/features/cooking/presentation/cooking.dart new file mode 100644 index 0000000..8f91f57 --- /dev/null +++ b/lib/src/features/cooking/presentation/cooking.dart @@ -0,0 +1,227 @@ +import 'package:flutter/material.dart'; +import 'package:flutter_hooks/flutter_hooks.dart'; +import 'package:go_router/go_router.dart'; +import 'package:hooks_riverpod/hooks_riverpod.dart'; +import 'package:percent_indicator/percent_indicator.dart'; + +import '../../../translations/domain/translation_provider.dart'; +import '../data/cooking_data.dart'; + +class Cooking extends HookConsumerWidget { + final dynamic data; + const Cooking({ + super.key, + required this.data, + }); + + final int endTimerinSeconds = 5; + + @override + Widget build(BuildContext context, WidgetRef ref) { + final index = useState(0); + final isPaused = useState(false); + final startTimer = useState(0.0); + final isPlaying = useAnimationController( + duration: const Duration(seconds: 1), initialValue: 0.0); + final pageController = usePageController(); + print(startTimer.value); + final directions = data["directions"]; + final video = data["video"]; + + useEffect( + () { + if (isPaused.value) { + startTimer.value = startTimer.value; + isPlaying.reverse(); + } else { + Future.delayed(Duration(seconds: 1), () async { + if (isPaused.value) { + startTimer.value = startTimer.value; + isPlaying.reverse(); + } + if (startTimer.value == endTimerinSeconds.toDouble() && + index.value == directions.length - 1 && + !isPaused.value) { + print("add points"); + addPoints(ref: ref, points: 10).then((value) { + isPaused.value = true; + startTimer.value = 0.0; + }); + } + if (startTimer.value < endTimerinSeconds) { + startTimer.value += 1; + isPlaying.forward(); + } else { + if (index.value < directions.length - 1) { + isPaused.value = true; + startTimer.value = 0.0; + pageController.animateToPage(index.value + 1, + duration: Duration(milliseconds: 300), + curve: Curves.easeInCirc); + isPlaying.reverse(); + } + } + }); + } + return null; + }, + ); + return Scaffold( + body: PageView.builder( + onPageChanged: (value) { + isPaused.value = true; + startTimer.value = 0; + index.value = value; + isPlaying.reverse(); + }, + itemCount: directions.length, + controller: pageController, + itemBuilder: (context, _) { + return DirectionsWidget( + index: index, + endTimerinSeconds: endTimerinSeconds, + directions: directions, + startTimer: startTimer, + isPaused: isPaused, + video: video, + isPlaying: isPlaying); + })); + } +} + +class DirectionsWidget extends StatelessWidget { + const DirectionsWidget({ + super.key, + required this.index, + required this.directions, + required this.startTimer, + required this.isPaused, + required this.isPlaying, + required this.endTimerinSeconds, + required this.video, + }); + + final ValueNotifier index; + final List directions; + final ValueNotifier startTimer; + final ValueNotifier isPaused; + final AnimationController isPlaying; + final int endTimerinSeconds; + final String video; + + @override + Widget build(BuildContext context) { + int timeLeftSeconds = endTimerinSeconds - startTimer.value.toInt(); + int timeLeftMin = timeLeftSeconds ~/ 60; + int timeLeftSec = timeLeftSeconds % 60; + String timeleftSec = timeLeftSec < 10 ? "0$timeLeftSec" : "$timeLeftSec"; + final word = TranslationRepo.translate(context); + + return SingleChildScrollView( + child: SafeArea( + child: Padding( + padding: const EdgeInsets.symmetric(horizontal: 10), + child: Column( + children: [ + const SizedBox( + height: 20.0, + ), + Align( + alignment: Alignment.topLeft, + child: GestureDetector( + onTap: () { + context.pop(); + }, + child: Icon(Icons.arrow_back_outlined))), + Align( + alignment: Alignment.topRight, + child: ElevatedButton.icon( + onPressed: () => context.pushNamed('recipeVideo',extra: video), + label: Text(word!.watch_video), + icon: Icon(Icons.play_arrow_outlined), + ), + ), + const SizedBox( + height: 40.0, + ), + RichText( + text: TextSpan(children: [ + TextSpan( + text: "${word.step} ${index.value + 1} ", + style: TextStyle( + fontSize: 18.0, + fontWeight: FontWeight.bold, + color: Theme.of(context).colorScheme.primary)), + TextSpan( + text: "${word.step_of} ${directions.length}", + style: TextStyle( + fontSize: 18.0, fontWeight: FontWeight.w100)), + ]), + ), + const SizedBox( + height: 30.0, + ), + Padding( + padding: const EdgeInsets.all(10.0), + child: Text( + " \"${directions[index.value]}\"", + style: TextStyle( + fontSize: 16.0, + color: Theme.of(context) + .colorScheme + .onSurface + .withOpacity(0.5)), + ), + ), + const SizedBox( + height: 50.0, + ), + CircularPercentIndicator( + radius: 80, + center: Icon( + Icons.soup_kitchen_outlined, + size: 50, + ), + progressColor: Theme.of(context).colorScheme.primary, + percent: startTimer.value / endTimerinSeconds, + animation: true, + lineWidth: 5, + animateFromLastPercent: true, + backgroundColor: + Theme.of(context).colorScheme.primary.withOpacity(0.1), + circularStrokeCap: CircularStrokeCap.round, + curve: Curves.easeIn, + ), + const SizedBox( + height: 20.0, + ), + Text("0${timeLeftMin}:${timeleftSec}", + style: TextStyle( + fontSize: 18.0, + fontWeight: FontWeight.bold, + color: Theme.of(context).colorScheme.primary)), + const SizedBox( + height: 60.0, + ), + CircleAvatar( + radius: 30, + child: IconButton( + onPressed: () { + isPaused.value = !isPaused.value; + }, + selectedIcon: Icon(Icons.pause_outlined), + isSelected: !isPaused.value, + icon: AnimatedIcon( + progress: isPlaying, + icon: AnimatedIcons.play_pause, + ))), + const SizedBox( + height: 50.0, + ), + ], + ), + ), + ), + ); + } +} diff --git a/lib/src/features/get_recipes/data/patient_types.dart b/lib/src/features/get_recipes/data/patient_types.dart deleted file mode 100644 index 7e525ab..0000000 --- a/lib/src/features/get_recipes/data/patient_types.dart +++ /dev/null @@ -1,20 +0,0 @@ -import 'dart:convert'; - -import 'package:flutter_riverpod/flutter_riverpod.dart'; - -import '../../../constants/constants.dart'; -import '../domain/recipe/recipe.dart'; -import '../domain/recipe/recipe_types.dart'; - -final patientTypesProvider = - FutureProvider>((ref) => patientTypes()); - -Future> patientTypes() async { - const url = '$restAPIURL/allPatients/?format=json'; - final response = await client.get(Uri.parse(url)); - final responseDe = utf8.decode(response.bodyBytes); - final recipeJson = await json.decode(responseDe); - return recipeJson - .map((data) => RecipeTypes.fromJson((data))) - .toList(); -} diff --git a/lib/src/features/get_recipes/data/patients.dart b/lib/src/features/get_recipes/data/patients.dart new file mode 100644 index 0000000..0a87d22 --- /dev/null +++ b/lib/src/features/get_recipes/data/patients.dart @@ -0,0 +1,23 @@ +import 'dart:convert'; + +import 'package:flutter/material.dart'; +import 'package:flutter_riverpod/flutter_riverpod.dart'; +import 'package:livine/src/translations/domain/translation_provider.dart'; + +import '../../../constants/constants.dart'; +import '../domain/recipe/recipe.dart'; +import '../domain/recipe/patients.dart'; +import 'package:riverpod_annotation/riverpod_annotation.dart'; + +part 'patients.g.dart'; + +@riverpod +Future> getPatients(Ref ref, + {required BuildContext context}) async { + final response = await client.get( + Uri.parse('$restAPIURL/allPatients/?format=json'), + headers: {"Accept-Language": ref.watch(localeNotifierProvider).languageCode}); + final responseDe = utf8.decode(response.bodyBytes); + final recipeJson = await json.decode(responseDe); + return recipeJson.map((data) => Patients.fromJson((data))).toList(); +} diff --git a/lib/src/features/get_recipes/data/patients.g.dart b/lib/src/features/get_recipes/data/patients.g.dart new file mode 100644 index 0000000..8732326 --- /dev/null +++ b/lib/src/features/get_recipes/data/patients.g.dart @@ -0,0 +1,159 @@ +// GENERATED CODE - DO NOT MODIFY BY HAND + +part of 'patients.dart'; + +// ************************************************************************** +// RiverpodGenerator +// ************************************************************************** + +String _$getPatientsHash() => r'193cdeebf7ebd0b814439a567599490c7345ec0d'; + +/// Copied from Dart SDK +class _SystemHash { + _SystemHash._(); + + static int combine(int hash, int value) { + // ignore: parameter_assignments + hash = 0x1fffffff & (hash + value); + // ignore: parameter_assignments + hash = 0x1fffffff & (hash + ((0x0007ffff & hash) << 10)); + return hash ^ (hash >> 6); + } + + static int finish(int hash) { + // ignore: parameter_assignments + hash = 0x1fffffff & (hash + ((0x03ffffff & hash) << 3)); + // ignore: parameter_assignments + hash = hash ^ (hash >> 11); + return 0x1fffffff & (hash + ((0x00003fff & hash) << 15)); + } +} + +/// See also [getPatients]. +@ProviderFor(getPatients) +const getPatientsProvider = GetPatientsFamily(); + +/// See also [getPatients]. +class GetPatientsFamily extends Family>> { + /// See also [getPatients]. + const GetPatientsFamily(); + + /// See also [getPatients]. + GetPatientsProvider call({ + required BuildContext context, + }) { + return GetPatientsProvider( + context: context, + ); + } + + @override + GetPatientsProvider getProviderOverride( + covariant GetPatientsProvider provider, + ) { + return call( + context: provider.context, + ); + } + + static const Iterable? _dependencies = null; + + @override + Iterable? get dependencies => _dependencies; + + static const Iterable? _allTransitiveDependencies = null; + + @override + Iterable? get allTransitiveDependencies => + _allTransitiveDependencies; + + @override + String? get name => r'getPatientsProvider'; +} + +/// See also [getPatients]. +class GetPatientsProvider extends AutoDisposeFutureProvider> { + /// See also [getPatients]. + GetPatientsProvider({ + required BuildContext context, + }) : this._internal( + (ref) => getPatients( + ref as GetPatientsRef, + context: context, + ), + from: getPatientsProvider, + name: r'getPatientsProvider', + debugGetCreateSourceHash: + const bool.fromEnvironment('dart.vm.product') + ? null + : _$getPatientsHash, + dependencies: GetPatientsFamily._dependencies, + allTransitiveDependencies: + GetPatientsFamily._allTransitiveDependencies, + context: context, + ); + + GetPatientsProvider._internal( + super._createNotifier, { + required super.name, + required super.dependencies, + required super.allTransitiveDependencies, + required super.debugGetCreateSourceHash, + required super.from, + required this.context, + }) : super.internal(); + + final BuildContext context; + + @override + Override overrideWith( + FutureOr> Function(GetPatientsRef provider) create, + ) { + return ProviderOverride( + origin: this, + override: GetPatientsProvider._internal( + (ref) => create(ref as GetPatientsRef), + from: from, + name: null, + dependencies: null, + allTransitiveDependencies: null, + debugGetCreateSourceHash: null, + context: context, + ), + ); + } + + @override + AutoDisposeFutureProviderElement> createElement() { + return _GetPatientsProviderElement(this); + } + + @override + bool operator ==(Object other) { + return other is GetPatientsProvider && other.context == context; + } + + @override + int get hashCode { + var hash = _SystemHash.combine(0, runtimeType.hashCode); + hash = _SystemHash.combine(hash, context.hashCode); + + return _SystemHash.finish(hash); + } +} + +mixin GetPatientsRef on AutoDisposeFutureProviderRef> { + /// The parameter `context` of this provider. + BuildContext get context; +} + +class _GetPatientsProviderElement + extends AutoDisposeFutureProviderElement> + with GetPatientsRef { + _GetPatientsProviderElement(super.provider); + + @override + BuildContext get context => (origin as GetPatientsProvider).context; +} +// ignore_for_file: type=lint +// ignore_for_file: subtype_of_sealed_class, invalid_use_of_internal_member, invalid_use_of_visible_for_testing_member diff --git a/lib/src/features/get_recipes/data/recipes.dart b/lib/src/features/get_recipes/data/recipes.dart index 4512645..b285802 100644 --- a/lib/src/features/get_recipes/data/recipes.dart +++ b/lib/src/features/get_recipes/data/recipes.dart @@ -1,29 +1,38 @@ import 'dart:convert'; +import 'package:flutter/material.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart'; import '../../../constants/constants.dart'; +import '../../../translations/domain/translation_provider.dart'; import '../domain/recipe/recipe.dart'; import 'package:riverpod_annotation/riverpod_annotation.dart'; part 'recipes.g.dart'; -final FutureProviderFamily recipesProviderID = - FutureProvider.family((ref, id) async { +@riverpod +Future recipesDetails(Ref ref, + {required int id, required BuildContext context}) async { final url = '$restAPIURL/recipe/$id?format=json'; - - final response = await client.get(Uri.parse(url)); + final response = await client.get(Uri.parse(url), headers: { + 'Accept-Language': ref.watch(localeNotifierProvider).languageCode, + }); final responseDe = utf8.decode(response.bodyBytes); final responseJson = json.decode(responseDe); return Recipe.fromJson( Map.from(responseJson as Map)); -}); +} @riverpod Future getRecipes(Ref ref, - {required int id, required int pageKey}) async { + {required int id, + required int pageKey, + required BuildContext context}) async { final url = '$restAPIURL/patient/$id?format=json&page=$pageKey'; - final response = await client.get(Uri.parse(url)); + final response = await client.get(Uri.parse(url), headers: { + 'Accept-Language': ref.watch(localeNotifierProvider).languageCode + }); + final responseDe = utf8.decode(response.bodyBytes); var responseJson = json.decode(responseDe); var recipesList = @@ -33,9 +42,13 @@ Future getRecipes(Ref ref, @riverpod Future getVegRecipes(Ref ref, - {required int id, required int pageKey}) async { + {required int id, + required int pageKey, + required BuildContext context}) async { final url = '$restAPIURL/recipe/veg/$id?format=json&page=$pageKey'; - final response = await client.get(Uri.parse(url)); + final response = await client.get(Uri.parse(url), headers: { + 'Accept-Language': ref.watch(localeNotifierProvider).languageCode + }); final responseDe = utf8.decode(response.bodyBytes); var responseJson = json.decode(responseDe); var recipesList = diff --git a/lib/src/features/get_recipes/data/recipes.g.dart b/lib/src/features/get_recipes/data/recipes.g.dart index 15ceaee..b962a72 100644 --- a/lib/src/features/get_recipes/data/recipes.g.dart +++ b/lib/src/features/get_recipes/data/recipes.g.dart @@ -6,7 +6,7 @@ part of 'recipes.dart'; // RiverpodGenerator // ************************************************************************** -// ignore_for_file: avoid_private_typedef_functions, non_constant_identifier_names, subtype_of_sealed_class, invalid_use_of_internal_member, unused_element, constant_identifier_names, unnecessary_raw_strings, library_private_types_in_public_api +String _$recipesDetailsHash() => r'0f959832e5dee7b167de4ccab7904e32ba923079'; /// Copied from Dart SDK class _SystemHash { @@ -29,114 +29,274 @@ class _SystemHash { } } -String $getRecipesHash() => r'90f07d1abe4044a71c4a09065c8f9d33df8d9f40'; +/// See also [recipesDetails]. +@ProviderFor(recipesDetails) +const recipesDetailsProvider = RecipesDetailsFamily(); -/// See also [getRecipes]. -class GetRecipesProvider extends AutoDisposeFutureProvider { - GetRecipesProvider({ - required this.id, - required this.pageKey, - }) : super( - (ref) => getRecipes( - ref, +/// See also [recipesDetails]. +class RecipesDetailsFamily extends Family> { + /// See also [recipesDetails]. + const RecipesDetailsFamily(); + + /// See also [recipesDetails]. + RecipesDetailsProvider call({ + required int id, + required BuildContext context, + }) { + return RecipesDetailsProvider( + id: id, + context: context, + ); + } + + @override + RecipesDetailsProvider getProviderOverride( + covariant RecipesDetailsProvider provider, + ) { + return call( + id: provider.id, + context: provider.context, + ); + } + + static const Iterable? _dependencies = null; + + @override + Iterable? get dependencies => _dependencies; + + static const Iterable? _allTransitiveDependencies = null; + + @override + Iterable? get allTransitiveDependencies => + _allTransitiveDependencies; + + @override + String? get name => r'recipesDetailsProvider'; +} + +/// See also [recipesDetails]. +class RecipesDetailsProvider extends AutoDisposeFutureProvider { + /// See also [recipesDetails]. + RecipesDetailsProvider({ + required int id, + required BuildContext context, + }) : this._internal( + (ref) => recipesDetails( + ref as RecipesDetailsRef, id: id, - pageKey: pageKey, + context: context, ), - from: getRecipesProvider, - name: r'getRecipesProvider', + from: recipesDetailsProvider, + name: r'recipesDetailsProvider', debugGetCreateSourceHash: const bool.fromEnvironment('dart.vm.product') ? null - : $getRecipesHash, + : _$recipesDetailsHash, + dependencies: RecipesDetailsFamily._dependencies, + allTransitiveDependencies: + RecipesDetailsFamily._allTransitiveDependencies, + id: id, + context: context, ); + RecipesDetailsProvider._internal( + super._createNotifier, { + required super.name, + required super.dependencies, + required super.allTransitiveDependencies, + required super.debugGetCreateSourceHash, + required super.from, + required this.id, + required this.context, + }) : super.internal(); + final int id; - final int pageKey; + final BuildContext context; + + @override + Override overrideWith( + FutureOr Function(RecipesDetailsRef provider) create, + ) { + return ProviderOverride( + origin: this, + override: RecipesDetailsProvider._internal( + (ref) => create(ref as RecipesDetailsRef), + from: from, + name: null, + dependencies: null, + allTransitiveDependencies: null, + debugGetCreateSourceHash: null, + id: id, + context: context, + ), + ); + } + + @override + AutoDisposeFutureProviderElement createElement() { + return _RecipesDetailsProviderElement(this); + } @override bool operator ==(Object other) { - return other is GetRecipesProvider && + return other is RecipesDetailsProvider && other.id == id && - other.pageKey == pageKey; + other.context == context; } @override int get hashCode { var hash = _SystemHash.combine(0, runtimeType.hashCode); hash = _SystemHash.combine(hash, id.hashCode); - hash = _SystemHash.combine(hash, pageKey.hashCode); + hash = _SystemHash.combine(hash, context.hashCode); return _SystemHash.finish(hash); } } -typedef GetRecipesRef = AutoDisposeFutureProviderRef; +mixin RecipesDetailsRef on AutoDisposeFutureProviderRef { + /// The parameter `id` of this provider. + int get id; + + /// The parameter `context` of this provider. + BuildContext get context; +} + +class _RecipesDetailsProviderElement + extends AutoDisposeFutureProviderElement with RecipesDetailsRef { + _RecipesDetailsProviderElement(super.provider); + + @override + int get id => (origin as RecipesDetailsProvider).id; + @override + BuildContext get context => (origin as RecipesDetailsProvider).context; +} + +String _$getRecipesHash() => r'844c07cc8dc308590cc248d2bc4f5b041a8b9b95'; /// See also [getRecipes]. -final getRecipesProvider = GetRecipesFamily(); +@ProviderFor(getRecipes) +const getRecipesProvider = GetRecipesFamily(); +/// See also [getRecipes]. class GetRecipesFamily extends Family> { - GetRecipesFamily(); + /// See also [getRecipes]. + const GetRecipesFamily(); + /// See also [getRecipes]. GetRecipesProvider call({ required int id, required int pageKey, + required BuildContext context, }) { return GetRecipesProvider( id: id, pageKey: pageKey, + context: context, ); } @override - AutoDisposeFutureProvider getProviderOverride( + GetRecipesProvider getProviderOverride( covariant GetRecipesProvider provider, ) { return call( id: provider.id, pageKey: provider.pageKey, + context: provider.context, ); } + static const Iterable? _dependencies = null; + @override - List? get allTransitiveDependencies => null; + Iterable? get dependencies => _dependencies; + + static const Iterable? _allTransitiveDependencies = null; @override - List? get dependencies => null; + Iterable? get allTransitiveDependencies => + _allTransitiveDependencies; @override String? get name => r'getRecipesProvider'; } -String $getVegRecipesHash() => r'84718619964ac5f5ff46ec1893252b7c7ef0c21b'; - -/// See also [getVegRecipes]. -class GetVegRecipesProvider extends AutoDisposeFutureProvider { - GetVegRecipesProvider({ - required this.id, - required this.pageKey, - }) : super( - (ref) => getVegRecipes( - ref, +/// See also [getRecipes]. +class GetRecipesProvider extends AutoDisposeFutureProvider { + /// See also [getRecipes]. + GetRecipesProvider({ + required int id, + required int pageKey, + required BuildContext context, + }) : this._internal( + (ref) => getRecipes( + ref as GetRecipesRef, id: id, pageKey: pageKey, + context: context, ), - from: getVegRecipesProvider, - name: r'getVegRecipesProvider', + from: getRecipesProvider, + name: r'getRecipesProvider', debugGetCreateSourceHash: const bool.fromEnvironment('dart.vm.product') ? null - : $getVegRecipesHash, + : _$getRecipesHash, + dependencies: GetRecipesFamily._dependencies, + allTransitiveDependencies: + GetRecipesFamily._allTransitiveDependencies, + id: id, + pageKey: pageKey, + context: context, ); + GetRecipesProvider._internal( + super._createNotifier, { + required super.name, + required super.dependencies, + required super.allTransitiveDependencies, + required super.debugGetCreateSourceHash, + required super.from, + required this.id, + required this.pageKey, + required this.context, + }) : super.internal(); + final int id; final int pageKey; + final BuildContext context; + + @override + Override overrideWith( + FutureOr Function(GetRecipesRef provider) create, + ) { + return ProviderOverride( + origin: this, + override: GetRecipesProvider._internal( + (ref) => create(ref as GetRecipesRef), + from: from, + name: null, + dependencies: null, + allTransitiveDependencies: null, + debugGetCreateSourceHash: null, + id: id, + pageKey: pageKey, + context: context, + ), + ); + } + + @override + AutoDisposeFutureProviderElement createElement() { + return _GetRecipesProviderElement(this); + } @override bool operator ==(Object other) { - return other is GetVegRecipesProvider && + return other is GetRecipesProvider && other.id == id && - other.pageKey == pageKey; + other.pageKey == pageKey && + other.context == context; } @override @@ -144,45 +304,194 @@ class GetVegRecipesProvider extends AutoDisposeFutureProvider { var hash = _SystemHash.combine(0, runtimeType.hashCode); hash = _SystemHash.combine(hash, id.hashCode); hash = _SystemHash.combine(hash, pageKey.hashCode); + hash = _SystemHash.combine(hash, context.hashCode); return _SystemHash.finish(hash); } } -typedef GetVegRecipesRef = AutoDisposeFutureProviderRef; +mixin GetRecipesRef on AutoDisposeFutureProviderRef { + /// The parameter `id` of this provider. + int get id; + + /// The parameter `pageKey` of this provider. + int get pageKey; + + /// The parameter `context` of this provider. + BuildContext get context; +} + +class _GetRecipesProviderElement + extends AutoDisposeFutureProviderElement with GetRecipesRef { + _GetRecipesProviderElement(super.provider); + + @override + int get id => (origin as GetRecipesProvider).id; + @override + int get pageKey => (origin as GetRecipesProvider).pageKey; + @override + BuildContext get context => (origin as GetRecipesProvider).context; +} + +String _$getVegRecipesHash() => r'262d6ac30dc0a18c52405ffd35a85a9137228eb0'; /// See also [getVegRecipes]. -final getVegRecipesProvider = GetVegRecipesFamily(); +@ProviderFor(getVegRecipes) +const getVegRecipesProvider = GetVegRecipesFamily(); +/// See also [getVegRecipes]. class GetVegRecipesFamily extends Family> { - GetVegRecipesFamily(); + /// See also [getVegRecipes]. + const GetVegRecipesFamily(); + /// See also [getVegRecipes]. GetVegRecipesProvider call({ required int id, required int pageKey, + required BuildContext context, }) { return GetVegRecipesProvider( id: id, pageKey: pageKey, + context: context, ); } @override - AutoDisposeFutureProvider getProviderOverride( + GetVegRecipesProvider getProviderOverride( covariant GetVegRecipesProvider provider, ) { return call( id: provider.id, pageKey: provider.pageKey, + context: provider.context, ); } + static const Iterable? _dependencies = null; + @override - List? get allTransitiveDependencies => null; + Iterable? get dependencies => _dependencies; + + static const Iterable? _allTransitiveDependencies = null; @override - List? get dependencies => null; + Iterable? get allTransitiveDependencies => + _allTransitiveDependencies; @override String? get name => r'getVegRecipesProvider'; } + +/// See also [getVegRecipes]. +class GetVegRecipesProvider extends AutoDisposeFutureProvider { + /// See also [getVegRecipes]. + GetVegRecipesProvider({ + required int id, + required int pageKey, + required BuildContext context, + }) : this._internal( + (ref) => getVegRecipes( + ref as GetVegRecipesRef, + id: id, + pageKey: pageKey, + context: context, + ), + from: getVegRecipesProvider, + name: r'getVegRecipesProvider', + debugGetCreateSourceHash: + const bool.fromEnvironment('dart.vm.product') + ? null + : _$getVegRecipesHash, + dependencies: GetVegRecipesFamily._dependencies, + allTransitiveDependencies: + GetVegRecipesFamily._allTransitiveDependencies, + id: id, + pageKey: pageKey, + context: context, + ); + + GetVegRecipesProvider._internal( + super._createNotifier, { + required super.name, + required super.dependencies, + required super.allTransitiveDependencies, + required super.debugGetCreateSourceHash, + required super.from, + required this.id, + required this.pageKey, + required this.context, + }) : super.internal(); + + final int id; + final int pageKey; + final BuildContext context; + + @override + Override overrideWith( + FutureOr Function(GetVegRecipesRef provider) create, + ) { + return ProviderOverride( + origin: this, + override: GetVegRecipesProvider._internal( + (ref) => create(ref as GetVegRecipesRef), + from: from, + name: null, + dependencies: null, + allTransitiveDependencies: null, + debugGetCreateSourceHash: null, + id: id, + pageKey: pageKey, + context: context, + ), + ); + } + + @override + AutoDisposeFutureProviderElement createElement() { + return _GetVegRecipesProviderElement(this); + } + + @override + bool operator ==(Object other) { + return other is GetVegRecipesProvider && + other.id == id && + other.pageKey == pageKey && + other.context == context; + } + + @override + int get hashCode { + var hash = _SystemHash.combine(0, runtimeType.hashCode); + hash = _SystemHash.combine(hash, id.hashCode); + hash = _SystemHash.combine(hash, pageKey.hashCode); + hash = _SystemHash.combine(hash, context.hashCode); + + return _SystemHash.finish(hash); + } +} + +mixin GetVegRecipesRef on AutoDisposeFutureProviderRef { + /// The parameter `id` of this provider. + int get id; + + /// The parameter `pageKey` of this provider. + int get pageKey; + + /// The parameter `context` of this provider. + BuildContext get context; +} + +class _GetVegRecipesProviderElement + extends AutoDisposeFutureProviderElement with GetVegRecipesRef { + _GetVegRecipesProviderElement(super.provider); + + @override + int get id => (origin as GetVegRecipesProvider).id; + @override + int get pageKey => (origin as GetVegRecipesProvider).pageKey; + @override + BuildContext get context => (origin as GetVegRecipesProvider).context; +} +// ignore_for_file: type=lint +// ignore_for_file: subtype_of_sealed_class, invalid_use_of_internal_member, invalid_use_of_visible_for_testing_member diff --git a/lib/src/features/get_recipes/domain/recipe/patients.dart b/lib/src/features/get_recipes/domain/recipe/patients.dart new file mode 100644 index 0000000..10a1cd0 --- /dev/null +++ b/lib/src/features/get_recipes/domain/recipe/patients.dart @@ -0,0 +1,17 @@ +// ignore_for_file: non_constant_identifier_names + +import 'package:freezed_annotation/freezed_annotation.dart'; + +part 'patients.freezed.dart'; +part 'patients.g.dart'; + +@freezed +class Patients with _$Patients { + const factory Patients( + int id, + String name, + String image, + ) = _Patients; + factory Patients.fromJson(Map json) => + _$PatientsFromJson(json); +} diff --git a/lib/src/features/get_recipes/domain/recipe/patients.freezed.dart b/lib/src/features/get_recipes/domain/recipe/patients.freezed.dart new file mode 100644 index 0000000..32afe82 --- /dev/null +++ b/lib/src/features/get_recipes/domain/recipe/patients.freezed.dart @@ -0,0 +1,181 @@ +// coverage:ignore-file +// GENERATED CODE - DO NOT MODIFY BY HAND +// ignore_for_file: type=lint +// ignore_for_file: unused_element, deprecated_member_use, deprecated_member_use_from_same_package, use_function_type_syntax_for_parameters, unnecessary_const, avoid_init_to_null, invalid_override_different_default_values_named, prefer_expression_function_bodies, annotate_overrides, invalid_annotation_target, unnecessary_question_mark + +part of 'patients.dart'; + +// ************************************************************************** +// FreezedGenerator +// ************************************************************************** + +T _$identity(T value) => value; + +final _privateConstructorUsedError = UnsupportedError( + 'It seems like you constructed your class using `MyClass._()`. This constructor is only meant to be used by freezed and you are not supposed to need it nor use it.\nPlease check the documentation here for more information: https://github.com/rrousselGit/freezed#custom-getters-and-methods'); + +Patients _$PatientsFromJson(Map json) { + return _Patients.fromJson(json); +} + +/// @nodoc +mixin _$Patients { + int get id => throw _privateConstructorUsedError; + String get name => throw _privateConstructorUsedError; + String get image => throw _privateConstructorUsedError; + + Map toJson() => throw _privateConstructorUsedError; + @JsonKey(ignore: true) + $PatientsCopyWith get copyWith => + throw _privateConstructorUsedError; +} + +/// @nodoc +abstract class $PatientsCopyWith<$Res> { + factory $PatientsCopyWith(Patients value, $Res Function(Patients) then) = + _$PatientsCopyWithImpl<$Res, Patients>; + @useResult + $Res call({int id, String name, String image}); +} + +/// @nodoc +class _$PatientsCopyWithImpl<$Res, $Val extends Patients> + implements $PatientsCopyWith<$Res> { + _$PatientsCopyWithImpl(this._value, this._then); + + // ignore: unused_field + final $Val _value; + // ignore: unused_field + final $Res Function($Val) _then; + + @pragma('vm:prefer-inline') + @override + $Res call({ + Object? id = null, + Object? name = null, + Object? image = null, + }) { + return _then(_value.copyWith( + id: null == id + ? _value.id + : id // ignore: cast_nullable_to_non_nullable + as int, + name: null == name + ? _value.name + : name // ignore: cast_nullable_to_non_nullable + as String, + image: null == image + ? _value.image + : image // ignore: cast_nullable_to_non_nullable + as String, + ) as $Val); + } +} + +/// @nodoc +abstract class _$$_PatientsCopyWith<$Res> implements $PatientsCopyWith<$Res> { + factory _$$_PatientsCopyWith( + _$_Patients value, $Res Function(_$_Patients) then) = + __$$_PatientsCopyWithImpl<$Res>; + @override + @useResult + $Res call({int id, String name, String image}); +} + +/// @nodoc +class __$$_PatientsCopyWithImpl<$Res> + extends _$PatientsCopyWithImpl<$Res, _$_Patients> + implements _$$_PatientsCopyWith<$Res> { + __$$_PatientsCopyWithImpl( + _$_Patients _value, $Res Function(_$_Patients) _then) + : super(_value, _then); + + @pragma('vm:prefer-inline') + @override + $Res call({ + Object? id = null, + Object? name = null, + Object? image = null, + }) { + return _then(_$_Patients( + null == id + ? _value.id + : id // ignore: cast_nullable_to_non_nullable + as int, + null == name + ? _value.name + : name // ignore: cast_nullable_to_non_nullable + as String, + null == image + ? _value.image + : image // ignore: cast_nullable_to_non_nullable + as String, + )); + } +} + +/// @nodoc +@JsonSerializable() +class _$_Patients implements _Patients { + const _$_Patients(this.id, this.name, this.image); + + factory _$_Patients.fromJson(Map json) => + _$$_PatientsFromJson(json); + + @override + final int id; + @override + final String name; + @override + final String image; + + @override + String toString() { + return 'Patients(id: $id, name: $name, image: $image)'; + } + + @override + bool operator ==(dynamic other) { + return identical(this, other) || + (other.runtimeType == runtimeType && + other is _$_Patients && + (identical(other.id, id) || other.id == id) && + (identical(other.name, name) || other.name == name) && + (identical(other.image, image) || other.image == image)); + } + + @JsonKey(ignore: true) + @override + int get hashCode => Object.hash(runtimeType, id, name, image); + + @JsonKey(ignore: true) + @override + @pragma('vm:prefer-inline') + _$$_PatientsCopyWith<_$_Patients> get copyWith => + __$$_PatientsCopyWithImpl<_$_Patients>(this, _$identity); + + @override + Map toJson() { + return _$$_PatientsToJson( + this, + ); + } +} + +abstract class _Patients implements Patients { + const factory _Patients(final int id, final String name, final String image) = + _$_Patients; + + factory _Patients.fromJson(Map json) = _$_Patients.fromJson; + + @override + int get id; + @override + String get name; + @override + String get image; + @override + @JsonKey(ignore: true) + _$$_PatientsCopyWith<_$_Patients> get copyWith => + throw _privateConstructorUsedError; +} diff --git a/lib/src/features/get_recipes/domain/recipe/recipe_types.g.dart b/lib/src/features/get_recipes/domain/recipe/patients.g.dart similarity index 51% rename from lib/src/features/get_recipes/domain/recipe/recipe_types.g.dart rename to lib/src/features/get_recipes/domain/recipe/patients.g.dart index f8212e1..be6da8e 100644 --- a/lib/src/features/get_recipes/domain/recipe/recipe_types.g.dart +++ b/lib/src/features/get_recipes/domain/recipe/patients.g.dart @@ -1,23 +1,20 @@ // GENERATED CODE - DO NOT MODIFY BY HAND -part of 'recipe_types.dart'; +part of 'patients.dart'; // ************************************************************************** // JsonSerializableGenerator // ************************************************************************** -_$_RecipeTypes _$$_RecipeTypesFromJson(Map json) => - _$_RecipeTypes( +_$_Patients _$$_PatientsFromJson(Map json) => _$_Patients( json['id'] as int, json['name'] as String, - json['name_in_arabic'] as String, - json['imageURL'] as String, + json['image'] as String, ); -Map _$$_RecipeTypesToJson(_$_RecipeTypes instance) => +Map _$$_PatientsToJson(_$_Patients instance) => { 'id': instance.id, 'name': instance.name, - 'name_in_arabic': instance.name_in_arabic, - 'imageURL': instance.imageURL, + 'image': instance.image, }; diff --git a/lib/src/features/get_recipes/domain/recipe/recipe.dart b/lib/src/features/get_recipes/domain/recipe/recipe.dart index be4b93c..0b5b94e 100644 --- a/lib/src/features/get_recipes/domain/recipe/recipe.dart +++ b/lib/src/features/get_recipes/domain/recipe/recipe.dart @@ -1,7 +1,5 @@ // ignore_for_file: non_constant_identifier_names -import 'package:easy_localization/easy_localization.dart'; -import 'package:flutter/cupertino.dart'; import 'package:freezed_annotation/freezed_annotation.dart'; import 'package:http/http.dart' as http; import 'package:http/http.dart'; @@ -14,57 +12,19 @@ Client client = http.Client(); @freezed class Recipe with _$Recipe { const factory Recipe( - int id, - List ingridents, - List ingridents_in_arabic, - List directions, - String patient, - String patient_in_arabic, - List directions_in_arabic, - String name, - String name_in_arabic, - String imageURL, - String diff, - bool isVegetarian, - int time_taken, - int calories, - String video, - String video_in_arabic, - String created_at - ) = _Recipe; + int id, + List ingridents, + List directions, + String patient, + String name, + String imageURL, + String difficulty, + bool isVegetarian, + String difficulty_image, + int time_taken, + int calories, + String video, + String created_at) = _Recipe; factory Recipe.fromJson(Map json) => _$RecipeFromJson(json); } -String changeDiffName(String difficulty, BuildContext context) { - if (context.locale.languageCode == "ar") { - if (difficulty.toUpperCase() == "EASY") { - return "سهل"; - } - if (difficulty.toUpperCase() == "MEDIUM") { - return "وسط"; - } - if (difficulty.toUpperCase() == "HARD") { - return "صعب"; - } - } - return difficulty; -} - -String changeDiffImage({String difficulty = '', bool isArabic = false}) { - switch (difficulty.toUpperCase()) { - case "EASY": - difficulty = 'assets/images/difficulty/smile.png'; - return difficulty; - - case "MEDIUM": - difficulty = 'assets/images/difficulty/wow.png'; - return difficulty; - - case "HARD": - difficulty = 'assets/images/difficulty/sad.png'; - return difficulty; - - default: - return difficulty; - } -} diff --git a/lib/src/features/get_recipes/domain/recipe/recipe.freezed.dart b/lib/src/features/get_recipes/domain/recipe/recipe.freezed.dart index 229bdb4..0ff8a51 100644 --- a/lib/src/features/get_recipes/domain/recipe/recipe.freezed.dart +++ b/lib/src/features/get_recipes/domain/recipe/recipe.freezed.dart @@ -1,7 +1,7 @@ // coverage:ignore-file // GENERATED CODE - DO NOT MODIFY BY HAND // ignore_for_file: type=lint -// ignore_for_file: unused_element, deprecated_member_use, deprecated_member_use_from_same_package, use_function_type_syntax_for_parameters, unnecessary_const, avoid_init_to_null, invalid_override_different_default_values_named, prefer_expression_function_bodies, annotate_overrides, invalid_annotation_target +// ignore_for_file: unused_element, deprecated_member_use, deprecated_member_use_from_same_package, use_function_type_syntax_for_parameters, unnecessary_const, avoid_init_to_null, invalid_override_different_default_values_named, prefer_expression_function_bodies, annotate_overrides, invalid_annotation_target, unnecessary_question_mark part of 'recipe.dart'; @@ -22,20 +22,16 @@ Recipe _$RecipeFromJson(Map json) { mixin _$Recipe { int get id => throw _privateConstructorUsedError; List get ingridents => throw _privateConstructorUsedError; - List get ingridents_in_arabic => throw _privateConstructorUsedError; List get directions => throw _privateConstructorUsedError; String get patient => throw _privateConstructorUsedError; - String get patient_in_arabic => throw _privateConstructorUsedError; - List get directions_in_arabic => throw _privateConstructorUsedError; String get name => throw _privateConstructorUsedError; - String get name_in_arabic => throw _privateConstructorUsedError; String get imageURL => throw _privateConstructorUsedError; - String get diff => throw _privateConstructorUsedError; + String get difficulty => throw _privateConstructorUsedError; bool get isVegetarian => throw _privateConstructorUsedError; + String get difficulty_image => throw _privateConstructorUsedError; int get time_taken => throw _privateConstructorUsedError; int get calories => throw _privateConstructorUsedError; String get video => throw _privateConstructorUsedError; - String get video_in_arabic => throw _privateConstructorUsedError; String get created_at => throw _privateConstructorUsedError; Map toJson() => throw _privateConstructorUsedError; @@ -46,125 +42,105 @@ mixin _$Recipe { /// @nodoc abstract class $RecipeCopyWith<$Res> { factory $RecipeCopyWith(Recipe value, $Res Function(Recipe) then) = - _$RecipeCopyWithImpl<$Res>; + _$RecipeCopyWithImpl<$Res, Recipe>; + @useResult $Res call( {int id, List ingridents, - List ingridents_in_arabic, List directions, String patient, - String patient_in_arabic, - List directions_in_arabic, String name, - String name_in_arabic, String imageURL, - String diff, + String difficulty, bool isVegetarian, + String difficulty_image, int time_taken, int calories, String video, - String video_in_arabic, String created_at}); } /// @nodoc -class _$RecipeCopyWithImpl<$Res> implements $RecipeCopyWith<$Res> { +class _$RecipeCopyWithImpl<$Res, $Val extends Recipe> + implements $RecipeCopyWith<$Res> { _$RecipeCopyWithImpl(this._value, this._then); - final Recipe _value; // ignore: unused_field - final $Res Function(Recipe) _then; + final $Val _value; + // ignore: unused_field + final $Res Function($Val) _then; + @pragma('vm:prefer-inline') @override $Res call({ - Object? id = freezed, - Object? ingridents = freezed, - Object? ingridents_in_arabic = freezed, - Object? directions = freezed, - Object? patient = freezed, - Object? patient_in_arabic = freezed, - Object? directions_in_arabic = freezed, - Object? name = freezed, - Object? name_in_arabic = freezed, - Object? imageURL = freezed, - Object? diff = freezed, - Object? isVegetarian = freezed, - Object? time_taken = freezed, - Object? calories = freezed, - Object? video = freezed, - Object? video_in_arabic = freezed, - Object? created_at = freezed, + Object? id = null, + Object? ingridents = null, + Object? directions = null, + Object? patient = null, + Object? name = null, + Object? imageURL = null, + Object? difficulty = null, + Object? isVegetarian = null, + Object? difficulty_image = null, + Object? time_taken = null, + Object? calories = null, + Object? video = null, + Object? created_at = null, }) { return _then(_value.copyWith( - id: id == freezed + id: null == id ? _value.id : id // ignore: cast_nullable_to_non_nullable as int, - ingridents: ingridents == freezed + ingridents: null == ingridents ? _value.ingridents : ingridents // ignore: cast_nullable_to_non_nullable as List, - ingridents_in_arabic: ingridents_in_arabic == freezed - ? _value.ingridents_in_arabic - : ingridents_in_arabic // ignore: cast_nullable_to_non_nullable - as List, - directions: directions == freezed + directions: null == directions ? _value.directions : directions // ignore: cast_nullable_to_non_nullable as List, - patient: patient == freezed + patient: null == patient ? _value.patient : patient // ignore: cast_nullable_to_non_nullable as String, - patient_in_arabic: patient_in_arabic == freezed - ? _value.patient_in_arabic - : patient_in_arabic // ignore: cast_nullable_to_non_nullable - as String, - directions_in_arabic: directions_in_arabic == freezed - ? _value.directions_in_arabic - : directions_in_arabic // ignore: cast_nullable_to_non_nullable - as List, - name: name == freezed + name: null == name ? _value.name : name // ignore: cast_nullable_to_non_nullable as String, - name_in_arabic: name_in_arabic == freezed - ? _value.name_in_arabic - : name_in_arabic // ignore: cast_nullable_to_non_nullable - as String, - imageURL: imageURL == freezed + imageURL: null == imageURL ? _value.imageURL : imageURL // ignore: cast_nullable_to_non_nullable as String, - diff: diff == freezed - ? _value.diff - : diff // ignore: cast_nullable_to_non_nullable + difficulty: null == difficulty + ? _value.difficulty + : difficulty // ignore: cast_nullable_to_non_nullable as String, - isVegetarian: isVegetarian == freezed + isVegetarian: null == isVegetarian ? _value.isVegetarian : isVegetarian // ignore: cast_nullable_to_non_nullable as bool, - time_taken: time_taken == freezed + difficulty_image: null == difficulty_image + ? _value.difficulty_image + : difficulty_image // ignore: cast_nullable_to_non_nullable + as String, + time_taken: null == time_taken ? _value.time_taken : time_taken // ignore: cast_nullable_to_non_nullable as int, - calories: calories == freezed + calories: null == calories ? _value.calories : calories // ignore: cast_nullable_to_non_nullable as int, - video: video == freezed + video: null == video ? _value.video : video // ignore: cast_nullable_to_non_nullable as String, - video_in_arabic: video_in_arabic == freezed - ? _value.video_in_arabic - : video_in_arabic // ignore: cast_nullable_to_non_nullable - as String, - created_at: created_at == freezed + created_at: null == created_at ? _value.created_at : created_at // ignore: cast_nullable_to_non_nullable as String, - )); + ) as $Val); } } @@ -173,121 +149,97 @@ abstract class _$$_RecipeCopyWith<$Res> implements $RecipeCopyWith<$Res> { factory _$$_RecipeCopyWith(_$_Recipe value, $Res Function(_$_Recipe) then) = __$$_RecipeCopyWithImpl<$Res>; @override + @useResult $Res call( {int id, List ingridents, - List ingridents_in_arabic, List directions, String patient, - String patient_in_arabic, - List directions_in_arabic, String name, - String name_in_arabic, String imageURL, - String diff, + String difficulty, bool isVegetarian, + String difficulty_image, int time_taken, int calories, String video, - String video_in_arabic, String created_at}); } /// @nodoc -class __$$_RecipeCopyWithImpl<$Res> extends _$RecipeCopyWithImpl<$Res> +class __$$_RecipeCopyWithImpl<$Res> + extends _$RecipeCopyWithImpl<$Res, _$_Recipe> implements _$$_RecipeCopyWith<$Res> { __$$_RecipeCopyWithImpl(_$_Recipe _value, $Res Function(_$_Recipe) _then) - : super(_value, (v) => _then(v as _$_Recipe)); - - @override - _$_Recipe get _value => super._value as _$_Recipe; + : super(_value, _then); + @pragma('vm:prefer-inline') @override $Res call({ - Object? id = freezed, - Object? ingridents = freezed, - Object? ingridents_in_arabic = freezed, - Object? directions = freezed, - Object? patient = freezed, - Object? patient_in_arabic = freezed, - Object? directions_in_arabic = freezed, - Object? name = freezed, - Object? name_in_arabic = freezed, - Object? imageURL = freezed, - Object? diff = freezed, - Object? isVegetarian = freezed, - Object? time_taken = freezed, - Object? calories = freezed, - Object? video = freezed, - Object? video_in_arabic = freezed, - Object? created_at = freezed, + Object? id = null, + Object? ingridents = null, + Object? directions = null, + Object? patient = null, + Object? name = null, + Object? imageURL = null, + Object? difficulty = null, + Object? isVegetarian = null, + Object? difficulty_image = null, + Object? time_taken = null, + Object? calories = null, + Object? video = null, + Object? created_at = null, }) { return _then(_$_Recipe( - id == freezed + null == id ? _value.id : id // ignore: cast_nullable_to_non_nullable as int, - ingridents == freezed + null == ingridents ? _value._ingridents : ingridents // ignore: cast_nullable_to_non_nullable as List, - ingridents_in_arabic == freezed - ? _value._ingridents_in_arabic - : ingridents_in_arabic // ignore: cast_nullable_to_non_nullable - as List, - directions == freezed + null == directions ? _value._directions : directions // ignore: cast_nullable_to_non_nullable as List, - patient == freezed + null == patient ? _value.patient : patient // ignore: cast_nullable_to_non_nullable as String, - patient_in_arabic == freezed - ? _value.patient_in_arabic - : patient_in_arabic // ignore: cast_nullable_to_non_nullable - as String, - directions_in_arabic == freezed - ? _value._directions_in_arabic - : directions_in_arabic // ignore: cast_nullable_to_non_nullable - as List, - name == freezed + null == name ? _value.name : name // ignore: cast_nullable_to_non_nullable as String, - name_in_arabic == freezed - ? _value.name_in_arabic - : name_in_arabic // ignore: cast_nullable_to_non_nullable - as String, - imageURL == freezed + null == imageURL ? _value.imageURL : imageURL // ignore: cast_nullable_to_non_nullable as String, - diff == freezed - ? _value.diff - : diff // ignore: cast_nullable_to_non_nullable + null == difficulty + ? _value.difficulty + : difficulty // ignore: cast_nullable_to_non_nullable as String, - isVegetarian == freezed + null == isVegetarian ? _value.isVegetarian : isVegetarian // ignore: cast_nullable_to_non_nullable as bool, - time_taken == freezed + null == difficulty_image + ? _value.difficulty_image + : difficulty_image // ignore: cast_nullable_to_non_nullable + as String, + null == time_taken ? _value.time_taken : time_taken // ignore: cast_nullable_to_non_nullable as int, - calories == freezed + null == calories ? _value.calories : calories // ignore: cast_nullable_to_non_nullable as int, - video == freezed + null == video ? _value.video : video // ignore: cast_nullable_to_non_nullable as String, - video_in_arabic == freezed - ? _value.video_in_arabic - : video_in_arabic // ignore: cast_nullable_to_non_nullable - as String, - created_at == freezed + null == created_at ? _value.created_at : created_at // ignore: cast_nullable_to_non_nullable as String, @@ -301,25 +253,19 @@ class _$_Recipe implements _Recipe { const _$_Recipe( this.id, final List ingridents, - final List ingridents_in_arabic, final List directions, this.patient, - this.patient_in_arabic, - final List directions_in_arabic, this.name, - this.name_in_arabic, this.imageURL, - this.diff, + this.difficulty, this.isVegetarian, + this.difficulty_image, this.time_taken, this.calories, this.video, - this.video_in_arabic, this.created_at) : _ingridents = ingridents, - _ingridents_in_arabic = ingridents_in_arabic, - _directions = directions, - _directions_in_arabic = directions_in_arabic; + _directions = directions; factory _$_Recipe.fromJson(Map json) => _$$_RecipeFromJson(json); @@ -329,59 +275,43 @@ class _$_Recipe implements _Recipe { final List _ingridents; @override List get ingridents { + if (_ingridents is EqualUnmodifiableListView) return _ingridents; // ignore: implicit_dynamic_type return EqualUnmodifiableListView(_ingridents); } - final List _ingridents_in_arabic; - @override - List get ingridents_in_arabic { - // ignore: implicit_dynamic_type - return EqualUnmodifiableListView(_ingridents_in_arabic); - } - final List _directions; @override List get directions { + if (_directions is EqualUnmodifiableListView) return _directions; // ignore: implicit_dynamic_type return EqualUnmodifiableListView(_directions); } @override final String patient; - @override - final String patient_in_arabic; - final List _directions_in_arabic; - @override - List get directions_in_arabic { - // ignore: implicit_dynamic_type - return EqualUnmodifiableListView(_directions_in_arabic); - } - @override final String name; @override - final String name_in_arabic; - @override final String imageURL; @override - final String diff; + final String difficulty; @override final bool isVegetarian; @override + final String difficulty_image; + @override final int time_taken; @override final int calories; @override final String video; @override - final String video_in_arabic; - @override final String created_at; @override String toString() { - return 'Recipe(id: $id, ingridents: $ingridents, ingridents_in_arabic: $ingridents_in_arabic, directions: $directions, patient: $patient, patient_in_arabic: $patient_in_arabic, directions_in_arabic: $directions_in_arabic, name: $name, name_in_arabic: $name_in_arabic, imageURL: $imageURL, diff: $diff, isVegetarian: $isVegetarian, time_taken: $time_taken, calories: $calories, video: $video, video_in_arabic: $video_in_arabic, created_at: $created_at)'; + return 'Recipe(id: $id, ingridents: $ingridents, directions: $directions, patient: $patient, name: $name, imageURL: $imageURL, difficulty: $difficulty, isVegetarian: $isVegetarian, difficulty_image: $difficulty_image, time_taken: $time_taken, calories: $calories, video: $video, created_at: $created_at)'; } @override @@ -389,59 +319,51 @@ class _$_Recipe implements _Recipe { return identical(this, other) || (other.runtimeType == runtimeType && other is _$_Recipe && - const DeepCollectionEquality().equals(other.id, id) && + (identical(other.id, id) || other.id == id) && const DeepCollectionEquality() .equals(other._ingridents, _ingridents) && - const DeepCollectionEquality() - .equals(other._ingridents_in_arabic, _ingridents_in_arabic) && const DeepCollectionEquality() .equals(other._directions, _directions) && - const DeepCollectionEquality().equals(other.patient, patient) && - const DeepCollectionEquality() - .equals(other.patient_in_arabic, patient_in_arabic) && - const DeepCollectionEquality() - .equals(other._directions_in_arabic, _directions_in_arabic) && - const DeepCollectionEquality().equals(other.name, name) && - const DeepCollectionEquality() - .equals(other.name_in_arabic, name_in_arabic) && - const DeepCollectionEquality().equals(other.imageURL, imageURL) && - const DeepCollectionEquality().equals(other.diff, diff) && - const DeepCollectionEquality() - .equals(other.isVegetarian, isVegetarian) && - const DeepCollectionEquality() - .equals(other.time_taken, time_taken) && - const DeepCollectionEquality().equals(other.calories, calories) && - const DeepCollectionEquality().equals(other.video, video) && - const DeepCollectionEquality() - .equals(other.video_in_arabic, video_in_arabic) && - const DeepCollectionEquality() - .equals(other.created_at, created_at)); + (identical(other.patient, patient) || other.patient == patient) && + (identical(other.name, name) || other.name == name) && + (identical(other.imageURL, imageURL) || + other.imageURL == imageURL) && + (identical(other.difficulty, difficulty) || + other.difficulty == difficulty) && + (identical(other.isVegetarian, isVegetarian) || + other.isVegetarian == isVegetarian) && + (identical(other.difficulty_image, difficulty_image) || + other.difficulty_image == difficulty_image) && + (identical(other.time_taken, time_taken) || + other.time_taken == time_taken) && + (identical(other.calories, calories) || + other.calories == calories) && + (identical(other.video, video) || other.video == video) && + (identical(other.created_at, created_at) || + other.created_at == created_at)); } @JsonKey(ignore: true) @override int get hashCode => Object.hash( runtimeType, - const DeepCollectionEquality().hash(id), + id, const DeepCollectionEquality().hash(_ingridents), - const DeepCollectionEquality().hash(_ingridents_in_arabic), const DeepCollectionEquality().hash(_directions), - const DeepCollectionEquality().hash(patient), - const DeepCollectionEquality().hash(patient_in_arabic), - const DeepCollectionEquality().hash(_directions_in_arabic), - const DeepCollectionEquality().hash(name), - const DeepCollectionEquality().hash(name_in_arabic), - const DeepCollectionEquality().hash(imageURL), - const DeepCollectionEquality().hash(diff), - const DeepCollectionEquality().hash(isVegetarian), - const DeepCollectionEquality().hash(time_taken), - const DeepCollectionEquality().hash(calories), - const DeepCollectionEquality().hash(video), - const DeepCollectionEquality().hash(video_in_arabic), - const DeepCollectionEquality().hash(created_at)); + patient, + name, + imageURL, + difficulty, + isVegetarian, + difficulty_image, + time_taken, + calories, + video, + created_at); @JsonKey(ignore: true) @override + @pragma('vm:prefer-inline') _$$_RecipeCopyWith<_$_Recipe> get copyWith => __$$_RecipeCopyWithImpl<_$_Recipe>(this, _$identity); @@ -457,20 +379,16 @@ abstract class _Recipe implements Recipe { const factory _Recipe( final int id, final List ingridents, - final List ingridents_in_arabic, final List directions, final String patient, - final String patient_in_arabic, - final List directions_in_arabic, final String name, - final String name_in_arabic, final String imageURL, - final String diff, + final String difficulty, final bool isVegetarian, + final String difficulty_image, final int time_taken, final int calories, final String video, - final String video_in_arabic, final String created_at) = _$_Recipe; factory _Recipe.fromJson(Map json) = _$_Recipe.fromJson; @@ -480,34 +398,26 @@ abstract class _Recipe implements Recipe { @override List get ingridents; @override - List get ingridents_in_arabic; - @override List get directions; @override String get patient; @override - String get patient_in_arabic; - @override - List get directions_in_arabic; - @override String get name; @override - String get name_in_arabic; - @override String get imageURL; @override - String get diff; + String get difficulty; @override bool get isVegetarian; @override + String get difficulty_image; + @override int get time_taken; @override int get calories; @override String get video; @override - String get video_in_arabic; - @override String get created_at; @override @JsonKey(ignore: true) diff --git a/lib/src/features/get_recipes/domain/recipe/recipe.g.dart b/lib/src/features/get_recipes/domain/recipe/recipe.g.dart index b4ce7a1..89d44ba 100644 --- a/lib/src/features/get_recipes/domain/recipe/recipe.g.dart +++ b/lib/src/features/get_recipes/domain/recipe/recipe.g.dart @@ -9,39 +9,31 @@ part of 'recipe.dart'; _$_Recipe _$$_RecipeFromJson(Map json) => _$_Recipe( json['id'] as int, json['ingridents'] as List, - json['ingridents_in_arabic'] as List, json['directions'] as List, json['patient'] as String, - json['patient_in_arabic'] as String, - json['directions_in_arabic'] as List, json['name'] as String, - json['name_in_arabic'] as String, json['imageURL'] as String, - json['diff'] as String, + json['difficulty'] as String, json['isVegetarian'] as bool, + json['difficulty_image'] as String, json['time_taken'] as int, json['calories'] as int, json['video'] as String, - json['video_in_arabic'] as String, json['created_at'] as String, ); Map _$$_RecipeToJson(_$_Recipe instance) => { 'id': instance.id, 'ingridents': instance.ingridents, - 'ingridents_in_arabic': instance.ingridents_in_arabic, 'directions': instance.directions, 'patient': instance.patient, - 'patient_in_arabic': instance.patient_in_arabic, - 'directions_in_arabic': instance.directions_in_arabic, 'name': instance.name, - 'name_in_arabic': instance.name_in_arabic, 'imageURL': instance.imageURL, - 'diff': instance.diff, + 'difficulty': instance.difficulty, 'isVegetarian': instance.isVegetarian, + 'difficulty_image': instance.difficulty_image, 'time_taken': instance.time_taken, 'calories': instance.calories, 'video': instance.video, - 'video_in_arabic': instance.video_in_arabic, 'created_at': instance.created_at, }; diff --git a/lib/src/features/get_recipes/domain/recipe/recipe_types.dart b/lib/src/features/get_recipes/domain/recipe/recipe_types.dart deleted file mode 100644 index 892e521..0000000 --- a/lib/src/features/get_recipes/domain/recipe/recipe_types.dart +++ /dev/null @@ -1,18 +0,0 @@ -// ignore_for_file: non_constant_identifier_names - -import 'package:freezed_annotation/freezed_annotation.dart'; - -part 'recipe_types.freezed.dart'; -part 'recipe_types.g.dart'; - -@freezed -class RecipeTypes with _$RecipeTypes { - const factory RecipeTypes( - int id, - String name, - String name_in_arabic, - String imageURL, - ) = _RecipeTypes; - factory RecipeTypes.fromJson(Map json) => - _$RecipeTypesFromJson(json); -} diff --git a/lib/src/features/get_recipes/domain/recipe/recipe_types.freezed.dart b/lib/src/features/get_recipes/domain/recipe/recipe_types.freezed.dart deleted file mode 100644 index b3ebf91..0000000 --- a/lib/src/features/get_recipes/domain/recipe/recipe_types.freezed.dart +++ /dev/null @@ -1,201 +0,0 @@ -// coverage:ignore-file -// GENERATED CODE - DO NOT MODIFY BY HAND -// ignore_for_file: type=lint -// ignore_for_file: unused_element, deprecated_member_use, deprecated_member_use_from_same_package, use_function_type_syntax_for_parameters, unnecessary_const, avoid_init_to_null, invalid_override_different_default_values_named, prefer_expression_function_bodies, annotate_overrides, invalid_annotation_target - -part of 'recipe_types.dart'; - -// ************************************************************************** -// FreezedGenerator -// ************************************************************************** - -T _$identity(T value) => value; - -final _privateConstructorUsedError = UnsupportedError( - 'It seems like you constructed your class using `MyClass._()`. This constructor is only meant to be used by freezed and you are not supposed to need it nor use it.\nPlease check the documentation here for more information: https://github.com/rrousselGit/freezed#custom-getters-and-methods'); - -RecipeTypes _$RecipeTypesFromJson(Map json) { - return _RecipeTypes.fromJson(json); -} - -/// @nodoc -mixin _$RecipeTypes { - int get id => throw _privateConstructorUsedError; - String get name => throw _privateConstructorUsedError; - String get name_in_arabic => throw _privateConstructorUsedError; - String get imageURL => throw _privateConstructorUsedError; - - Map toJson() => throw _privateConstructorUsedError; - @JsonKey(ignore: true) - $RecipeTypesCopyWith get copyWith => - throw _privateConstructorUsedError; -} - -/// @nodoc -abstract class $RecipeTypesCopyWith<$Res> { - factory $RecipeTypesCopyWith( - RecipeTypes value, $Res Function(RecipeTypes) then) = - _$RecipeTypesCopyWithImpl<$Res>; - $Res call({int id, String name, String name_in_arabic, String imageURL}); -} - -/// @nodoc -class _$RecipeTypesCopyWithImpl<$Res> implements $RecipeTypesCopyWith<$Res> { - _$RecipeTypesCopyWithImpl(this._value, this._then); - - final RecipeTypes _value; - // ignore: unused_field - final $Res Function(RecipeTypes) _then; - - @override - $Res call({ - Object? id = freezed, - Object? name = freezed, - Object? name_in_arabic = freezed, - Object? imageURL = freezed, - }) { - return _then(_value.copyWith( - id: id == freezed - ? _value.id - : id // ignore: cast_nullable_to_non_nullable - as int, - name: name == freezed - ? _value.name - : name // ignore: cast_nullable_to_non_nullable - as String, - name_in_arabic: name_in_arabic == freezed - ? _value.name_in_arabic - : name_in_arabic // ignore: cast_nullable_to_non_nullable - as String, - imageURL: imageURL == freezed - ? _value.imageURL - : imageURL // ignore: cast_nullable_to_non_nullable - as String, - )); - } -} - -/// @nodoc -abstract class _$$_RecipeTypesCopyWith<$Res> - implements $RecipeTypesCopyWith<$Res> { - factory _$$_RecipeTypesCopyWith( - _$_RecipeTypes value, $Res Function(_$_RecipeTypes) then) = - __$$_RecipeTypesCopyWithImpl<$Res>; - @override - $Res call({int id, String name, String name_in_arabic, String imageURL}); -} - -/// @nodoc -class __$$_RecipeTypesCopyWithImpl<$Res> extends _$RecipeTypesCopyWithImpl<$Res> - implements _$$_RecipeTypesCopyWith<$Res> { - __$$_RecipeTypesCopyWithImpl( - _$_RecipeTypes _value, $Res Function(_$_RecipeTypes) _then) - : super(_value, (v) => _then(v as _$_RecipeTypes)); - - @override - _$_RecipeTypes get _value => super._value as _$_RecipeTypes; - - @override - $Res call({ - Object? id = freezed, - Object? name = freezed, - Object? name_in_arabic = freezed, - Object? imageURL = freezed, - }) { - return _then(_$_RecipeTypes( - id == freezed - ? _value.id - : id // ignore: cast_nullable_to_non_nullable - as int, - name == freezed - ? _value.name - : name // ignore: cast_nullable_to_non_nullable - as String, - name_in_arabic == freezed - ? _value.name_in_arabic - : name_in_arabic // ignore: cast_nullable_to_non_nullable - as String, - imageURL == freezed - ? _value.imageURL - : imageURL // ignore: cast_nullable_to_non_nullable - as String, - )); - } -} - -/// @nodoc -@JsonSerializable() -class _$_RecipeTypes implements _RecipeTypes { - const _$_RecipeTypes(this.id, this.name, this.name_in_arabic, this.imageURL); - - factory _$_RecipeTypes.fromJson(Map json) => - _$$_RecipeTypesFromJson(json); - - @override - final int id; - @override - final String name; - @override - final String name_in_arabic; - @override - final String imageURL; - - @override - String toString() { - return 'RecipeTypes(id: $id, name: $name, name_in_arabic: $name_in_arabic, imageURL: $imageURL)'; - } - - @override - bool operator ==(dynamic other) { - return identical(this, other) || - (other.runtimeType == runtimeType && - other is _$_RecipeTypes && - const DeepCollectionEquality().equals(other.id, id) && - const DeepCollectionEquality().equals(other.name, name) && - const DeepCollectionEquality() - .equals(other.name_in_arabic, name_in_arabic) && - const DeepCollectionEquality().equals(other.imageURL, imageURL)); - } - - @JsonKey(ignore: true) - @override - int get hashCode => Object.hash( - runtimeType, - const DeepCollectionEquality().hash(id), - const DeepCollectionEquality().hash(name), - const DeepCollectionEquality().hash(name_in_arabic), - const DeepCollectionEquality().hash(imageURL)); - - @JsonKey(ignore: true) - @override - _$$_RecipeTypesCopyWith<_$_RecipeTypes> get copyWith => - __$$_RecipeTypesCopyWithImpl<_$_RecipeTypes>(this, _$identity); - - @override - Map toJson() { - return _$$_RecipeTypesToJson( - this, - ); - } -} - -abstract class _RecipeTypes implements RecipeTypes { - const factory _RecipeTypes(final int id, final String name, - final String name_in_arabic, final String imageURL) = _$_RecipeTypes; - - factory _RecipeTypes.fromJson(Map json) = - _$_RecipeTypes.fromJson; - - @override - int get id; - @override - String get name; - @override - String get name_in_arabic; - @override - String get imageURL; - @override - @JsonKey(ignore: true) - _$$_RecipeTypesCopyWith<_$_RecipeTypes> get copyWith => - throw _privateConstructorUsedError; -} diff --git a/lib/src/features/get_recipes/presentation/home.dart b/lib/src/features/get_recipes/presentation/home.dart index 350fe9e..de7166c 100644 --- a/lib/src/features/get_recipes/presentation/home.dart +++ b/lib/src/features/get_recipes/presentation/home.dart @@ -2,13 +2,7 @@ import 'dart:io'; -import 'package:easy_localization/easy_localization.dart'; -import 'package:flutter/foundation.dart'; -import 'package:go_router/go_router.dart'; -import 'package:google_fonts/google_fonts.dart'; -import 'package:google_mobile_ads/google_mobile_ads.dart'; import 'package:hooks_riverpod/hooks_riverpod.dart'; -import 'package:iconsax/iconsax.dart'; import 'package:livine/src/shared/connectivity/check_network.dart'; import '../../../common_widgets/no_connection.dart'; import '../../../common_widgets/recipe/recipe_grid_view.dart'; @@ -17,7 +11,7 @@ import 'package:flutter/material.dart'; import '../../../constants/constants.dart'; import '../../../shared/notifications/health_notification.dart'; -import '../../../translations/locale_keys.g.dart'; +import '../../../translations/domain/translation_provider.dart'; import '../data/get_user_name.dart'; import 'search/search_delegate.dart'; @@ -29,15 +23,6 @@ class Home extends ConsumerStatefulWidget { } class _HomeState extends ConsumerState { - @override - void dispose() async { - if (Platform.isAndroid) { - adHelper.nativeAdBanner.dispose(); - } - - super.dispose(); - } - @override void initState() { super.initState(); @@ -47,8 +32,6 @@ class _HomeState extends ConsumerState { onlyAndroid() async { if (Platform.isAndroid) { showNotification(); - - adHelper.nativeBannerFunction(setState); } } @@ -56,11 +39,13 @@ class _HomeState extends ConsumerState { Widget build(BuildContext context) { ConnectivityStatus network = ref.watch(checkNetworkProvider); String name = ref.watch(userNameProvider).valueOrNull ?? ''; + final word = TranslationRepo.translate(context); + return network == ConnectivityStatus.On ? Scaffold( body: SafeArea( child: RawScrollbar( - thumbColor: getColorScheme(context).tertiary, + thumbColor: colorScheme(context).tertiary, thickness: 5, radius: const Radius.circular(10), child: SingleChildScrollView( @@ -76,24 +61,18 @@ class _HomeState extends ConsumerState { RichText( text: TextSpan(children: [ TextSpan( - text: "${LocaleKeys.Welcome.tr()}\n", + text: "${word?.welcome}\n", style: TextStyle( fontSize: 35.0, - fontFamily: - context.locale.languageCode == - "en" - ? 'Kine' - : GoogleFonts.notoKufiArabic() - .fontFamily, - color: getColorScheme(context) - .onSurface)), + + color: + colorScheme(context).onSurface)), TextSpan( text: name, style: TextStyle( fontSize: 35.0, fontFamily: 'Kine', - color: - getColorScheme(context).onSurface, + color: colorScheme(context).onSurface, overflow: TextOverflow.ellipsis, )) ])), @@ -103,39 +82,27 @@ class _HomeState extends ConsumerState { context: context, delegate: CustomSearchDelegate()); }, - icon: Icon(Iconsax.search_normal)) + icon: Icon(Icons.search)) ], )), - if (adHelper.isnativeBannerAdLoaded && - kReleaseMode) ...[ - Center( - child: SizedBox( - height: adHelper.nativeAdBanner.size.height - .toDouble(), - width: - adHelper.nativeAdBanner.size.width.toDouble(), - child: AdWidget(ad: adHelper.nativeAdBanner), - ), - ), - ], const SizedBox(height: 20.0), RecipesGridView(), ]), ), ), ), - floatingActionButton: Visibility( - visible: Platform.isAndroid == true, - child: FloatingActionButton( - heroTag: "btn1", - onPressed: () => context.push("/scan"), - child: Image.asset( - 'assets/images/icons/scan.png', - width: 40, - color: getColorScheme(context).onPrimaryContainer, - ), - ), - ), + // floatingActionButton: Visibility( + // visible: Platform.isAndroid == true, + // child: FloatingActionButton( + // heroTag: "btn1", + // onPressed: () => context.push("/scan"), + // child: Image.asset( + // 'assets/images/icons/scan.png', + // width: 40, + // color: getColorScheme(context).onPrimaryContainer, + // ), + // ), + // ), ) : NoConnection(); } diff --git a/lib/src/features/get_recipes/presentation/ingridents.dart b/lib/src/features/get_recipes/presentation/ingridents.dart index 2090392..71ffcb4 100644 --- a/lib/src/features/get_recipes/presentation/ingridents.dart +++ b/lib/src/features/get_recipes/presentation/ingridents.dart @@ -1,28 +1,26 @@ -import 'package:easy_localization/easy_localization.dart'; import 'package:flutter/material.dart'; -import 'package:font_awesome_flutter/font_awesome_flutter.dart'; -import '../../../translations/locale_keys.g.dart'; +import '../../../translations/domain/translation_provider.dart'; class Ingridents extends StatelessWidget { - const Ingridents({Key? key, required this.ingridentsRecipe}) : super(key: key); + const Ingridents({Key? key, required this.ingridentsRecipe}) + : super(key: key); // ignore: type_annotate_public_apis final dynamic ingridentsRecipe; @override Widget build(BuildContext context) { + final word = TranslationRepo.translate(context); return Scaffold( appBar: AppBar( centerTitle: true, - leading: IconButton(icon: Icon( - context.locale.languageCode == "en" - ?FontAwesomeIcons.arrowLeft - : FontAwesomeIcons.arrowRight - ), - onPressed: () => Navigator.pop(context),), + leading: IconButton( + icon: Icon(Icons.west), + onPressed: () => Navigator.pop(context), + ), title: Text( - LocaleKeys.Ingridents.tr().toString(), + word?.ingridents ?? "", ), ), body: SingleChildScrollView( diff --git a/lib/src/features/get_recipes/presentation/recipe_details.dart b/lib/src/features/get_recipes/presentation/recipe_details.dart index 9aea09f..0117ab9 100644 --- a/lib/src/features/get_recipes/presentation/recipe_details.dart +++ b/lib/src/features/get_recipes/presentation/recipe_details.dart @@ -1,25 +1,24 @@ // ignore_for_file: type_annotate_public_apis import 'dart:developer'; -import 'dart:io'; import 'package:cached_network_image/cached_network_image.dart'; -import 'package:easy_localization/easy_localization.dart'; import 'package:flutter/material.dart'; +import 'package:flutter_hooks/flutter_hooks.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart'; +import 'package:flutter_svg/flutter_svg.dart'; import 'package:go_router/go_router.dart'; -import 'package:iconsax/iconsax.dart'; +import 'package:livine/src/common_widgets/auth/auth_widget.dart'; import 'package:livine/src/shared/cache/cache_helper.dart'; -import 'package:url_launcher/url_launcher.dart'; +import '../../../translations/domain/translation_provider.dart'; import '../../auth/favorites/data/favorites.dart'; import '../../loading/loading.dart'; import '../../../constants/constants.dart'; -import '../../../common_widgets/recipe/recipe_details_widgets.dart'; import '../data/recipes.dart'; -import '../domain/recipe/recipe.dart'; +import 'package:sliding_up_panel2/sliding_up_panel2.dart'; -class RecipeDetails extends StatefulWidget { +class RecipeDetails extends StatefulHookWidget { const RecipeDetails({Key? key, required this.id}) : super(key: key); final dynamic id; @@ -28,240 +27,185 @@ class RecipeDetails extends StatefulWidget { State createState() => _RecipeDetailsState(); } -class _RecipeDetailsState extends State - with SliverHelpers { +class _RecipeDetailsState extends State { int index = 0; bool isFavorited = CacheHelper.getBool("isFavorited") ?? false; + bool backDrop = false; @override Widget build(BuildContext context) { - final theme = Theme.of(context); return Consumer( builder: (BuildContext context, WidgetRef ref, Widget? child) { - final recipesData = ref.watch(recipesProviderID(widget.id)); + final recipesData = + ref.watch(recipesDetailsProvider(id: widget.id, context: context)); + final word = TranslationRepo.translate(context); return recipesData.when( data: (data) { - return Stack( - children: [ - Positioned.fill( - child: AnimatedBuilder( - animation: scrollController, - builder: (_, child) => - Opacity(opacity: opacity, child: child), - child: SizedBox( - height: 250, - child: CachedNetworkImage( - imageUrl: "$restAPIMedia/${data.imageURL}", - fit: BoxFit.cover, - )), + return Scaffold( + body: SlidingUpPanel( + backdropEnabled: true, + minHeight: MediaQuery.of(context).size.height * 0.6, + color: Theme.of(context).colorScheme.surface, + boxShadow: [], + borderRadius: BorderRadius.only( + topLeft: Radius.circular(30), topRight: Radius.circular(30)), + body: Stack( + children: [ + Container( + decoration: BoxDecoration( + image: DecorationImage( + image: CachedNetworkImageProvider( + restAPIMedia + data.imageURL, + ), + fit: BoxFit.cover, + ), + ), ), - ), - Scaffold( - backgroundColor: Colors.transparent, - appBar: PreferredSize( - preferredSize: const Size.fromHeight(kToolbarHeight), - child: AnimatedBuilder( - animation: scrollController, - builder: (_, __) { - return AppBar( - actions: [ - IconButton( - onPressed: () { - setState(() { - isFavorited = !isFavorited; - }); - CacheHelper.setBool("isFavorited", isFavorited); - addFavorite( - recipeID: data.id, - ref: ref, - context: context, - mounted: mounted, - ); - }, - icon: isFavorited - ? const Icon(Iconsax.heart5) - : const Icon(Iconsax.heart), - iconSize: 30, - color: isFavorited - ? Colors.red - : getColorScheme(context).onBackground, - ) - ], - centerTitle: true, - elevation: opacity >= 1 ? 0 : null, - backgroundColor: MaterialStateColor.resolveWith( - (states) { - return states.contains(MaterialState.scrolledUnder) - ? (theme.useMaterial3 - ? theme.colorScheme.surface - : theme.colorScheme.primary) - : Colors.transparent; - }, + SafeArea( + child: Padding( + padding: const EdgeInsets.all(10.0), + child: Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + CircleAvatar( + backgroundColor: + Theme.of(context).colorScheme.surface, + radius: 25, + child: IconButton( + onPressed: () => context.pop(), + icon: Icon( + Icons.arrow_back, + color: Theme.of(context).colorScheme.onSurface, + )), + ), + CircleAvatar( + backgroundColor: + Theme.of(context).colorScheme.surface, + radius: 25, + child: IconButton( + onPressed: () => addFavorite( + ref: ref, + recipeID: data.id, + mounted: mounted, + context: context), + icon: Icon( + Icons.favorite_border, + color: Theme.of(context).colorScheme.onSurface, + )), ), - ); - }, + ], + ), ), ), - body: SingleChildScrollView( - controller: scrollController, - padding: EdgeInsets.only(top: top), - child: Card( - margin: EdgeInsets.zero, - shape: const RoundedRectangleBorder( - borderRadius: BorderRadius.vertical( - top: Radius.circular(20), + ], + ), + isDraggable: true, + panelBuilder: () => Padding( + padding: const EdgeInsets.all(25.0), + child: SingleChildScrollView( + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Center( + child: Container( + height: 4, + width: 35, + alignment: Alignment.center, + decoration: BoxDecoration( + color: Theme.of(context).colorScheme.onSurface, + borderRadius: BorderRadius.circular(10.0), + ), ), ), - child: Column( + const SizedBox(height: 30.0), + RichText( + text: TextSpan(children: [ + TextSpan( + text: data.name, + style: TextStyle(fontFamily: 'Kine', fontSize: 22.0), + ), + WidgetSpan(child: const SizedBox(width: 10.0)), + // TextSpan( + // text: "made by", + // style: TextStyle(fontSize: 13.0), + // ), + // WidgetSpan(child: const SizedBox(width: 3.0)), + // TextSpan( + // text: "Mazen Omar", + // style: TextStyle( + // fontSize: 13.0, fontWeight: FontWeight.bold), + // ), + ])), + const SizedBox(height: 10.0), + Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ - Padding( - padding: const EdgeInsets.all(20), - child: Text( - context.locale.languageCode == "en" - ? data.name - : data.name_in_arabic, - style: const TextStyle( - fontFamily: 'Kine', fontSize: 25), - ), - ), - Row( - mainAxisAlignment: MainAxisAlignment.center, - children: [ - IconCard( - color: theme.colorScheme.primaryContainer, - image: 'assets/images/recipes/time.png', - name: context.locale.languageCode == "en" - ? "${data.time_taken} min" - : "${data.time_taken} دقيقة", - ), - const SizedBox( - width: 30.0, - ), - IconCard( - color: theme.colorScheme.secondaryContainer, - image: changeDiffImage(difficulty: data.diff), - name: changeDiffName( - data.diff.toUpperCase(), context), - ), - const SizedBox( - width: 30.0, - ), - IconCard( - color: theme.colorScheme.tertiaryContainer, - image: 'assets/images/recipes/calories.jpg', - calAmount: data.calories.toString(), - name: context.locale.languageCode == "en" - ? "cal/Serving" - : "سعرات حراريه", - ), - ], - ), - Padding( - padding: const EdgeInsets.all(8.0), - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Text( - context.locale.languageCode == "en" - ? "Ingridents :" - : "المكونات", - style: const TextStyle( - fontSize: 21.0, - fontWeight: FontWeight.bold), - ), - ListView.builder( - physics: const NeverScrollableScrollPhysics(), - shrinkWrap: true, - itemCount: data.ingridents.length, - itemBuilder: ((context, index) { - return IngridentsW( - text: context.locale.languageCode == "en" - ? data.ingridents[index] - : data.ingridents_in_arabic[index], - ); - }), - ), - SizedBox( - height: 20, - ), - Text( - context.locale.languageCode == "en" - ? "Directions :" - : "الاتجاهات", - style: const TextStyle( - fontSize: 21.0, - fontWeight: FontWeight.bold), - ), - ListView.separated( - separatorBuilder: (context, index) => - const SizedBox( - height: 20.0, - ), - physics: const NeverScrollableScrollPhysics(), - shrinkWrap: true, - itemCount: data.directions.length, - itemBuilder: ((context, index) { - return Directions( - text: context.locale.languageCode == "en" - ? data.directions[index] - : data.directions_in_arabic[index], - num: index + 1, - ); - }), - ), - ], - ), - ), - const SizedBox( - height: 20.0, - ), - Padding( - padding: const EdgeInsets.all(22.0), - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Center( - child: SizedBox( - width: 200.0, - height: 60.0, - child: OutlinedButton( - onPressed: () async { - if (Platform.isAndroid || - Platform.isIOS) { - context.go("/recipe_video", - extra: - context.locale.languageCode == - "en" - ? data.video - : data.video_in_arabic); - } else { - if (!await launchUrl(Uri.parse( - context.locale.languageCode == - "en" - ? data.video - : data.video_in_arabic))) { - throw 'Could not launch at recipe page'; - } - } - }, - child: Text( - context.locale.languageCode == "en" - ? "Video" - : "الفيديو")), - ), - ) - ], - ), - ), + // Text( + // "Ingridents:", + // style: TextStyle(fontSize: 22.0), + // ), + // Container( + // height: 100, + // child: ListView.separated( + // separatorBuilder: (context, index) => SizedBox( + // width: 10.0, + // ), + // scrollDirection: Axis.horizontal, + // itemCount: 10, + // itemBuilder: (context, index) { + // return CircleAvatar( + // radius: 30, + // backgroundImage: CachedNetworkImageProvider( + // restAPIMedia + data.imageURL), + // ); + // }), + // ), ], ), - ), + Text( + word!.ingridents + ' :', + style: TextStyle(fontSize: 22.0), + ), + Container( + child: ListView.separated( + itemCount: data.ingridents.length, + shrinkWrap: true, + physics: NeverScrollableScrollPhysics(), + separatorBuilder: (context, index) => SizedBox( + height: 10.0, + ), + itemBuilder: (context, index) { + return Directions( + count: index + 1, text: data.ingridents[index]); + }), + ), + const SizedBox(height: 10.0), + CustomButton( + icon: SvgPicture.asset( + "assets/images/icons/chief_hat.svg", + width: 24, + colorFilter: ColorFilter.mode( + Theme.of(context) + .colorScheme + .onSecondaryContainer, + BlendMode.srcIn)), + color: Theme.of(context).colorScheme.secondaryContainer, + textColor: + Theme.of(context).colorScheme.onSecondaryContainer, + onPressed: () => context.push('/cooking', extra: { + "directions": data.directions, + "video": data.video + }), + isLoading: false, + text: word.start_cooking, + context: context), + SizedBox(height: 20.0), + ], ), ), - ], - ); + ), + )); }, error: (Object error, StackTrace? stackTrace) { log("$error \t $stackTrace"); @@ -276,20 +220,19 @@ class _RecipeDetailsState extends State class Directions extends StatelessWidget { const Directions({ Key? key, - required this.num, + required this.count, required this.text, }) : super(key: key); - final int num; + final int count; final String text; @override Widget build(BuildContext context) { - final theme = Theme.of(context); return Row( crossAxisAlignment: CrossAxisAlignment.start, children: [ Text( - num.toString(), + count.toString(), style: const TextStyle(fontSize: 20.0), ), const SizedBox( @@ -299,7 +242,7 @@ class Directions extends StatelessWidget { height: 30.0, width: 3.0, decoration: BoxDecoration( - color: theme.colorScheme.tertiary, + color: Theme.of(context).colorScheme.tertiary, borderRadius: BorderRadius.circular(20.0)), ), const SizedBox( @@ -315,92 +258,3 @@ class Directions extends StatelessWidget { ); } } - -mixin SliverHelpers on State { - final scrollController = ScrollController(); - double top = 250; - double opacity = 1; - double scrollPosition = 0; - double _getPositionFromTop() { - final paddingTop = MediaQuery.of(context).padding.top; - var position = 250 + paddingTop; - const finalPosition = 0.0; - - if (scrollController.hasClients) { - final offset = scrollController.offset; - final isFinalPos = offset > position - finalPosition; - if (isFinalPos) { - position = finalPosition; - } else { - position = position - offset; - } - } - return position; - } - - @override - void initState() { - super.initState(); - scrollController.addListener(() { - top = _getPositionFromTop(); - opacity = _opacity(top); - scrollPosition = scrollController.offset; - }); - } - - double _opacity(double top) => (top / 250).clamp(0.0, 1.0); -} - -class MathUtils { - /// normalizes the value. - static double norm(double value, double min, double max) => - (value - min) / (max - min); - - /// Linear interpolation, same as `lerpDouble` - /// no restrictions on `t` for range 0-1. - static double lerp( - double min, - double max, - double t, - ) => - min + (max - min) * t; - - /// Like dart num::clamp() but adjusts min/max. - static double clamp(double value, double min, double max) { - double localMax = max; - double localMin = min; - if (localMin > localMax) { - var tmp = localMax; - localMax = localMin; - localMin = tmp; - } - if (value < localMin) { - return localMin; - } else if (value > localMax) { - return localMax; - } else { - return value; - } - } - - /// maps `srcValue` from `srcMin` and `srcMax` range ... to `dstMin` / `dstMax` - /// range... optionally clamping the the output value when `clampDst` is true. - static double map( - double srcValue, - double srcMin, - double srcMax, - double dstMin, - double dstMax, [ - bool clampDst = false, - ]) { - final result = lerp( - dstMin, - dstMax, - norm(srcValue, srcMin, srcMax), - ); - if (clampDst) { - return clamp(result, dstMin, dstMax); - } - return result; - } -} diff --git a/lib/src/features/get_recipes/presentation/search/data/search.dart b/lib/src/features/get_recipes/presentation/search/data/search.dart index 5733c74..e9e3ca7 100644 --- a/lib/src/features/get_recipes/presentation/search/data/search.dart +++ b/lib/src/features/get_recipes/presentation/search/data/search.dart @@ -1,20 +1,27 @@ import 'dart:convert'; +import 'package:flutter/material.dart'; import 'package:hooks_riverpod/hooks_riverpod.dart'; import 'package:riverpod_annotation/riverpod_annotation.dart'; import '../../../../../constants/constants.dart'; +import '../../../../../translations/domain/translation_provider.dart'; import '../../../application/vegan_service.dart'; import '../../../domain/recipe/recipe.dart'; part 'search.g.dart'; @riverpod -Future searchResults(Ref ref, {required int pk, required String query}) async { +Future searchResults(Ref ref, + {required int pk, + required String query, + required BuildContext context}) async { bool isUserVegan = ref.watch(isVeganProvider); final url = isUserVegan == true ? "$restAPIURL/recipe/veg/$pk?format=json&search=$query" : '$restAPIURL/patient/$pk?format=json&search=$query'; - final response = await client.get(Uri.parse(url)); + final response = await client.get(Uri.parse(url), headers: { + "Accept-Language": ref.watch(localeNotifierProvider).languageCode + }); final responseDe = utf8.decode(response.bodyBytes); final responseJson = json.decode(responseDe); return responseJson["results"].map((job) => Recipe.fromJson(job)).toList(); diff --git a/lib/src/features/get_recipes/presentation/search/data/search.g.dart b/lib/src/features/get_recipes/presentation/search/data/search.g.dart index 68d8b7d..822b9df 100644 --- a/lib/src/features/get_recipes/presentation/search/data/search.g.dart +++ b/lib/src/features/get_recipes/presentation/search/data/search.g.dart @@ -6,7 +6,7 @@ part of 'search.dart'; // RiverpodGenerator // ************************************************************************** -// ignore_for_file: avoid_private_typedef_functions, non_constant_identifier_names, subtype_of_sealed_class, invalid_use_of_internal_member, unused_element, constant_identifier_names, unnecessary_raw_strings, library_private_types_in_public_api +String _$searchResultsHash() => r'c625bf8dee346d487121ff61ee24ab73447b288f'; /// Copied from Dart SDK class _SystemHash { @@ -29,35 +29,129 @@ class _SystemHash { } } -String $searchResultsHash() => r'344ced406dbb190ca2f98f5f65c8d40e2b4c756e'; +/// See also [searchResults]. +@ProviderFor(searchResults) +const searchResultsProvider = SearchResultsFamily(); + +/// See also [searchResults]. +class SearchResultsFamily extends Family> { + /// See also [searchResults]. + const SearchResultsFamily(); + + /// See also [searchResults]. + SearchResultsProvider call({ + required int pk, + required String query, + required BuildContext context, + }) { + return SearchResultsProvider( + pk: pk, + query: query, + context: context, + ); + } + + @override + SearchResultsProvider getProviderOverride( + covariant SearchResultsProvider provider, + ) { + return call( + pk: provider.pk, + query: provider.query, + context: provider.context, + ); + } + + static const Iterable? _dependencies = null; + + @override + Iterable? get dependencies => _dependencies; + + static const Iterable? _allTransitiveDependencies = null; + + @override + Iterable? get allTransitiveDependencies => + _allTransitiveDependencies; + + @override + String? get name => r'searchResultsProvider'; +} /// See also [searchResults]. class SearchResultsProvider extends AutoDisposeFutureProvider { + /// See also [searchResults]. SearchResultsProvider({ - required this.pk, - required this.query, - }) : super( + required int pk, + required String query, + required BuildContext context, + }) : this._internal( (ref) => searchResults( - ref, + ref as SearchResultsRef, pk: pk, query: query, + context: context, ), from: searchResultsProvider, name: r'searchResultsProvider', debugGetCreateSourceHash: const bool.fromEnvironment('dart.vm.product') ? null - : $searchResultsHash, + : _$searchResultsHash, + dependencies: SearchResultsFamily._dependencies, + allTransitiveDependencies: + SearchResultsFamily._allTransitiveDependencies, + pk: pk, + query: query, + context: context, ); + SearchResultsProvider._internal( + super._createNotifier, { + required super.name, + required super.dependencies, + required super.allTransitiveDependencies, + required super.debugGetCreateSourceHash, + required super.from, + required this.pk, + required this.query, + required this.context, + }) : super.internal(); + final int pk; final String query; + final BuildContext context; + + @override + Override overrideWith( + FutureOr Function(SearchResultsRef provider) create, + ) { + return ProviderOverride( + origin: this, + override: SearchResultsProvider._internal( + (ref) => create(ref as SearchResultsRef), + from: from, + name: null, + dependencies: null, + allTransitiveDependencies: null, + debugGetCreateSourceHash: null, + pk: pk, + query: query, + context: context, + ), + ); + } + + @override + AutoDisposeFutureProviderElement createElement() { + return _SearchResultsProviderElement(this); + } @override bool operator ==(Object other) { return other is SearchResultsProvider && other.pk == pk && - other.query == query; + other.query == query && + other.context == context; } @override @@ -65,45 +159,33 @@ class SearchResultsProvider extends AutoDisposeFutureProvider { var hash = _SystemHash.combine(0, runtimeType.hashCode); hash = _SystemHash.combine(hash, pk.hashCode); hash = _SystemHash.combine(hash, query.hashCode); + hash = _SystemHash.combine(hash, context.hashCode); return _SystemHash.finish(hash); } } -typedef SearchResultsRef = AutoDisposeFutureProviderRef; +mixin SearchResultsRef on AutoDisposeFutureProviderRef { + /// The parameter `pk` of this provider. + int get pk; -/// See also [searchResults]. -final searchResultsProvider = SearchResultsFamily(); + /// The parameter `query` of this provider. + String get query; -class SearchResultsFamily extends Family> { - SearchResultsFamily(); - - SearchResultsProvider call({ - required int pk, - required String query, - }) { - return SearchResultsProvider( - pk: pk, - query: query, - ); - } + /// The parameter `context` of this provider. + BuildContext get context; +} - @override - AutoDisposeFutureProvider getProviderOverride( - covariant SearchResultsProvider provider, - ) { - return call( - pk: provider.pk, - query: provider.query, - ); - } +class _SearchResultsProviderElement + extends AutoDisposeFutureProviderElement with SearchResultsRef { + _SearchResultsProviderElement(super.provider); @override - List? get allTransitiveDependencies => null; - + int get pk => (origin as SearchResultsProvider).pk; @override - List? get dependencies => null; - + String get query => (origin as SearchResultsProvider).query; @override - String? get name => r'searchResultsProvider'; + BuildContext get context => (origin as SearchResultsProvider).context; } +// ignore_for_file: type=lint +// ignore_for_file: subtype_of_sealed_class, invalid_use_of_internal_member, invalid_use_of_visible_for_testing_member diff --git a/lib/src/features/get_recipes/presentation/search/search_delegate.dart b/lib/src/features/get_recipes/presentation/search/search_delegate.dart index 46dabc8..0e44206 100644 --- a/lib/src/features/get_recipes/presentation/search/search_delegate.dart +++ b/lib/src/features/get_recipes/presentation/search/search_delegate.dart @@ -1,10 +1,9 @@ import 'dart:developer'; import 'package:animations/animations.dart'; -import 'package:easy_localization/easy_localization.dart'; import 'package:flutter/material.dart'; import 'package:hooks_riverpod/hooks_riverpod.dart'; -import 'package:iconsax/iconsax.dart'; +import 'package:livine/src/translations/domain/translation_provider.dart'; import '../../../../common_widgets/recipe/recipe_card_widget.dart'; import '../../../../constants/constants.dart'; @@ -20,7 +19,7 @@ class CustomSearchDelegate extends SearchDelegate { List? buildActions(BuildContext context) { return [ IconButton( - icon: const Icon(Iconsax.close_square), + icon: const Icon(Icons.close), onPressed: () { query = ''; showSuggestions(context); @@ -32,7 +31,7 @@ class CustomSearchDelegate extends SearchDelegate { @override Widget? buildLeading(BuildContext context) { return IconButton( - icon: const Icon(Iconsax.arrow_left), + icon: const Icon(Icons.west), onPressed: () { close(context, null); }, @@ -46,6 +45,7 @@ class CustomSearchDelegate extends SearchDelegate { int recipesTypeData = ref.watch(userTypeProvider); final results = ref.watch(searchResultsProvider( query: query, + context: context, pk: recipesTypeData == 0 ? patientID : recipesTypeData)); return results.when( data: (data) { @@ -58,30 +58,26 @@ class CustomSearchDelegate extends SearchDelegate { ), itemCount: data.length, itemBuilder: (context, index) { - final recipe = data[index]; + final recipe = data[index] as Recipe; return OpenContainer( + openElevation: 0, + closedElevation: 0, + closedColor: Colors.transparent, openBuilder: (context, _) => RecipeDetails( id: recipe.id, ), - middleColor: Colors.transparent, - openColor: Colors.transparent, - closedColor: Colors.transparent, transitionDuration: const Duration(milliseconds: 500), closedBuilder: (context, action) => RecipeCardNormal( key: Key("K"), id: recipe.id, - name: context.locale.languageCode == "en" - ? recipe.name - : recipe.name_in_arabic, + name: recipe.name, foodImage: '${recipe.imageURL}', - type: context.locale.languageCode == "en" - ? recipe.patient - : recipe.patient_in_arabic, - difficulty: changeDiffName(recipe.diff, context), - time: context.locale.languageCode == "en" + type: recipe.patient, + difficulty: recipe.difficulty, + time: ref.watch(localeNotifierProvider).languageCode == "en" ? "${recipe.time_taken} min" : "${recipe.time_taken} دقيقة", - dImage: changeDiffImage(difficulty: recipe.diff), + dImage: recipe.difficulty_image, ), ); }, @@ -117,24 +113,26 @@ class CustomSearchDelegate extends SearchDelegate { List suggestions = ["Pasta", "Onion", "Tomato", "Chicken"]; List suggestionsAR = ["خبز", "بصل", "طماطم", "دجاج"]; - return ListView.builder( - itemCount: suggestions.length, - itemBuilder: (context, index) { - return ListTile( - leading: Icon( - Icons.food_bank_rounded, - ), - onTap: () { - query = context.locale.languageCode == "en" + return Consumer( + builder: (context, ref, child) => ListView.builder( + itemCount: suggestions.length, + itemBuilder: (context, index) { + return ListTile( + leading: Icon( + Icons.food_bank_rounded, + ), + onTap: () { + query = ref.watch(localeNotifierProvider).languageCode == "en" + ? suggestions[index] + : suggestionsAR[index]; + showResults(context); + }, + title: Text(ref.watch(localeNotifierProvider).languageCode == "en" ? suggestions[index] - : suggestionsAR[index]; - showResults(context); - }, - title: Text(context.locale.languageCode == "en" - ? suggestions[index] - : suggestionsAR[index]), - ); - }, + : suggestionsAR[index]), + ); + }, + ), ); } } diff --git a/lib/src/features/loading/loading.dart b/lib/src/features/loading/loading.dart index 6886920..185b724 100644 --- a/lib/src/features/loading/loading.dart +++ b/lib/src/features/loading/loading.dart @@ -1,5 +1,4 @@ import 'package:connectivity_plus/connectivity_plus.dart'; -import 'package:lottie/lottie.dart'; import 'package:flutter/material.dart'; import 'package:flutter_svg/flutter_svg.dart'; @@ -12,9 +11,13 @@ class Loading extends StatelessWidget { @override Widget build(BuildContext context) { - return Center( - child: Lottie.asset("assets/images/loading/loading.json"), + return Scaffold( + body: Center( + + child: CircularProgressIndicator.adaptive(), + + ), ); } } diff --git a/lib/src/features/meals/presentation/breakfast.dart b/lib/src/features/meals/presentation/breakfast.dart index b08cc4c..af877c5 100644 --- a/lib/src/features/meals/presentation/breakfast.dart +++ b/lib/src/features/meals/presentation/breakfast.dart @@ -3,30 +3,29 @@ import 'dart:io'; import 'package:cached_network_image/cached_network_image.dart'; -import 'package:easy_localization/easy_localization.dart'; import 'package:flutter/material.dart'; import 'package:go_router/go_router.dart'; -import 'package:google_fonts/google_fonts.dart'; import 'package:url_launcher/url_launcher.dart'; import '../../../constants/constants.dart'; -import '../../../translations/locale_keys.g.dart'; +import '../../../translations/domain/translation_provider.dart'; class BreakFast extends StatelessWidget { const BreakFast({Key? key}) : super(key: key); @override Widget build(BuildContext context) { + final word = TranslationRepo.translate(context); return Scaffold( appBar: AppBar( - title: Text(LocaleKeys.Breakfast.tr()), + title: Text(word?.breakfast ?? ''), centerTitle: true, elevation: 1.2, // ignore: use_full_hex_values_for_flutter_colors ), body: OrientationBuilder( builder: (context, orientation) => RawScrollbar( - thumbColor: getColorScheme(context).tertiary, + thumbColor: colorScheme(context).tertiary, thickness: 5, radius: const Radius.circular(10), child: GridView.count( @@ -38,37 +37,37 @@ class BreakFast extends StatelessWidget { url: 'https://www.youtube.com/watch?v=618QsMaVXp8', image: 'https://images.unsplash.com/photo-1648326311535-21895c185fbb?ixlib=rb-1.2.1&ixid=MnwxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8&auto=format&fit=crop&w=687&q=80', - name: LocaleKeys.Shakshuka.tr(), + name: word?.shakshuka, ), Category( url: 'https://www.youtube.com/watch?v=bXntiogB8rA', image: 'https://scrummylane.com/wp-content/uploads/2019/06/crustless-quiche-8.jpg', - name: LocaleKeys.Crustless_Quiche.tr(), + name: word?.crustless_Quiche, ), Category( url: 'https://www.youtube.com/watch?v=n76noIAaAuY', image: 'https://frescadostortillas.com/wp-content/uploads/2020/11/Slow-Cooker-Chipotle-Chicken-Burrito-010.jpg', - name: LocaleKeys.Burrito.tr(), + name: word?.burrito, ), Category( url: 'https://www.youtube.com/watch?v=4STUMnTxcsA', image: 'https://sallysbakingaddiction.com/wp-content/uploads/2019/01/baked-oatmeal-5.jpg', - name: LocaleKeys.Baked_Oatmeal.tr(), + name: word?.baked_Oatmeal, ), Category( url: 'https://www.youtube.com/watch?v=Sncq3NLw_PY', image: 'https://joyfoodsunshine.com/wp-content/uploads/2019/09/easy-cinnamon-apples-recipe-2.jpg', - name: LocaleKeys.Apple_Cinnamon_Oat.tr(), + name: word?.apple_Cinnamon_Oat, ), Category( url: 'https://www.youtube.com/watch?v=0W9lXaHcXL4', image: 'https://ichef.bbci.co.uk/food/ic/food_16x9_832/recipes/bananabread_85720_16x9.jpg', - name: LocaleKeys.Banana_Bread.tr(), + name: word?.banana_Bread, ), ], ), @@ -116,14 +115,13 @@ class Category extends StatelessWidget { imageUrl: image, ), const SizedBox(height: 10.0), - Text( - name, - textAlign: TextAlign.center, - style: TextStyle( - fontSize: 17.0, - fontFamily: context.locale.languageCode == "en" - ? 'Kine' - : GoogleFonts.notoKufiArabic().fontFamily, + FittedBox( + child: Text( + name, + textAlign: TextAlign.center, + style: TextStyle( + fontSize: 17.0, + ), ), ) ], diff --git a/lib/src/features/meals/presentation/dinner.dart b/lib/src/features/meals/presentation/dinner.dart index 12812e1..4a760fb 100644 --- a/lib/src/features/meals/presentation/dinner.dart +++ b/lib/src/features/meals/presentation/dinner.dart @@ -1,24 +1,24 @@ import '../../../constants/constants.dart'; -import '../../../translations/locale_keys.g.dart'; +import '../../../translations/domain/translation_provider.dart'; import 'breakfast.dart'; import 'package:flutter/material.dart'; -import 'package:easy_localization/easy_localization.dart'; class Dinner extends StatelessWidget { const Dinner({Key? key}) : super(key: key); @override Widget build(BuildContext context) { + final word = TranslationRepo.translate(context); return Scaffold( appBar: AppBar( - title: Text(LocaleKeys.Dinner.tr()), + title: Text(word?.dinner ?? ''), centerTitle: true, elevation: 1.2, // ignore: use_full_hex_values_for_flutter_colors ), body: OrientationBuilder( builder: ((context, orientation) => RawScrollbar( - thumbColor: getColorScheme(context).tertiary, + thumbColor: colorScheme(context).tertiary, thickness: 5, radius: const Radius.circular(10), child: GridView.count( @@ -29,37 +29,37 @@ class Dinner extends StatelessWidget { url: 'https://www.youtube.com/watch?v=-oxjhgVp4y4', image: 'https://cupfulofkale.com/wp-content/uploads/2020/05/Creamy-Vegan-Wild-Mushroom-Risotto-720x720.jpg', - name: LocaleKeys.Wild_Mushroom_Risotto.tr(), + name: word?.wild_Mushroom_Risotto, ), Category( url: 'https://www.youtube.com/watch?v=vUcP8tYFvio', image: 'https://hips.hearstapps.com/hmg-prod.s3.amazonaws.com/images/grilled-steak-tortilla-salad-ghk-0528-1524087142.jpg', - name: LocaleKeys.Grilled_Steak_Tortilla_Salad.tr(), + name: word?.grilled_Steak_Tortilla_Salad, ), Category( url: 'https://www.youtube.com/watch?v=CbzOZVC-la0', image: - 'https://363gtx1a8mj92o5fk42j3vm6-wpengine.netdna-ssl.com/wp-content/uploads/2020/01/Lemon-Feta-Polenta-with-Asparagus-and-Shrimp-2.jpg', - name: LocaleKeys.Feta_Shrimp_and_Polenta.tr(), + 'https://lh3.googleusercontent.com/KVT4ysmiAxfi-Bc-AvHPiVSznpfa7vsTF_lJzuJSnaY_uG0HOFnf4_GPbIsHfzkvWMdgr-Eih2UNptvMAD91gg=w1280-h1280-c-rj-v1-e365', + name: word?.feta_Shrimp_and_Polenta, ), Category( url: 'https://www.youtube.com/watch?v=mTwBK39EWok', image: 'https://hips.hearstapps.com/delish/assets/17/37/1505337479-black-bean-soup-delish-1.jpg', - name: LocaleKeys.Black_Bean_Soup.tr(), + name: word?.black_Bean_Soup, ), Category( url: 'https://www.youtube.com/watch?v=_v8uQPFp2ZA', image: 'https://hips.hearstapps.com/hmg-prod.s3.amazonaws.com/images/striped-bass-radish-salsa-verde-ghk-0519-1556659527.jpg', - name: LocaleKeys.Bass_With_Radish_Salsa.tr(), + name: word?.bass_With_Radish_Salsa, ), Category( url: 'https://www.youtube.com/watch?v=6JfeZL14L48', image: 'https://assets.bonappetit.com/photos/57d9d24d5a14a530086ef7bf/8:5/w_2311,h_1444,c_limit/bas-best-eggplant-parmesan.jpg', - name: LocaleKeys.Eggplant_Parmesan.tr(), + name: word?.eggplant_Parmesan, ), ], ), diff --git a/lib/src/features/meals/presentation/lunch.dart b/lib/src/features/meals/presentation/lunch.dart index 38e8372..963ba70 100644 --- a/lib/src/features/meals/presentation/lunch.dart +++ b/lib/src/features/meals/presentation/lunch.dart @@ -1,7 +1,5 @@ -import 'package:easy_localization/easy_localization.dart'; - import '../../../constants/constants.dart'; -import '../../../translations/locale_keys.g.dart'; +import '../../../translations/domain/translation_provider.dart'; import 'breakfast.dart'; import 'package:flutter/material.dart'; @@ -10,16 +8,17 @@ class Lunch extends StatelessWidget { @override Widget build(BuildContext context) { + final word = TranslationRepo.translate(context); return Scaffold( appBar: AppBar( - title: Text(LocaleKeys.Lunch.tr()), + title: Text(word?.lunch ?? "Lunch"), centerTitle: true, elevation: 1.2, // ignore: use_full_hex_values_for_flutter_colors ), body: OrientationBuilder( builder: ((context, orientation) => RawScrollbar( - thumbColor: getColorScheme(context).tertiary, + thumbColor: colorScheme(context).tertiary, thickness: 5, radius: const Radius.circular(10), child: GridView.count( @@ -30,31 +29,31 @@ class Lunch extends StatelessWidget { url: 'https://www.youtube.com/watch?v=PAELd9i4yWY', image: 'https://www.acouplecooks.com/wp-content/uploads/2019/01/Crispy-Cauliflower-Tacos-036.jpg', - name: LocaleKeys.Roasted_Cauliflower_Tacos.tr(), + name: word?.roasted_Cauliflower_Tacos, ), Category( url: 'https://www.youtube.com/watch?v=179z0T5SnbQ', image: 'https://tmbidigitalassetsazure.blob.core.windows.net/rms3-prod/attachments/37/1200x1200/exps63027_TH163620C11_10_3b.jpg', - name: LocaleKeys.Carrot_with_Radish_Salad.tr(), + name: word?.carrot_with_Radish_Salad, ), Category( url: 'https://www.youtube.com/watch?v=vbV1h68Mnms', image: 'https://www.primaverakitchen.com/wp-content/uploads/2020/01/Easy-Chopped-Salmon-Salad-Primavera-Kitchen-1.jpg', - name: LocaleKeys.Salmon_Salad.tr(), + name: word?.salmon_Salad, ), Category( url: 'https://www.youtube.com/watch?v=J-Rn9DN3IjU', image: 'https://static01.nyt.com/images/2015/07/08/dining/08APPE2/08APPE2-articleLarge.jpg', - name: LocaleKeys.Panzanella.tr(), + name: word?.panzanella, ), Category( url: 'https://www.youtube.com/watch?v=a4Z2x0sPq3A', image: 'https://www.simplyrecipes.com/thmb/j1WtO-KNzo7D7e3j5skU2CIQGk4=/1800x1200/filters:fill(auto,1)/__opt__aboutcom__coeus__resources__content_migration__simply_recipes__uploads__2009__09__caesar-salad-horiz-a-1800-4a465eb53456465091e34138675259c2.jpg', - name: LocaleKeys.Caesar_Salad.tr(), + name: word?.caesar_Salad, ), ], ), diff --git a/lib/src/features/meals/presentation/meals.dart b/lib/src/features/meals/presentation/meals.dart index a03601e..dc9d4b3 100644 --- a/lib/src/features/meals/presentation/meals.dart +++ b/lib/src/features/meals/presentation/meals.dart @@ -1,16 +1,11 @@ -import 'dart:io'; - -import 'package:easy_localization/easy_localization.dart'; -import 'package:flutter/foundation.dart'; import 'package:flutter/material.dart'; -import 'package:google_mobile_ads/google_mobile_ads.dart'; import 'package:hooks_riverpod/hooks_riverpod.dart'; import 'package:livine/src/common_widgets/no_connection.dart'; import '../../../common_widgets/recipe/food_category_widget.dart'; import '../../../constants/constants.dart'; import '../../../shared/connectivity/check_network.dart'; -import '../../../translations/locale_keys.g.dart'; +import '../../../translations/domain/translation_provider.dart'; class Patient extends ConsumerStatefulWidget { const Patient({Key? key}) : super(key: key); @@ -20,83 +15,50 @@ class Patient extends ConsumerStatefulWidget { } class _PatientState extends ConsumerState { - @override - void initState() { - super.initState(); - - runOnlyOnAndroid(); - } - - void runOnlyOnAndroid() { - if (Platform.isAndroid) { - adHelper.nativeBannerFunction(setState); - } - } - - void disposeOnAndroid() { - adHelper.nativeAdBanner.dispose(); - } - - @override - void dispose() { - disposeOnAndroid(); - super.dispose(); - } - @override Widget build(BuildContext context) { ConnectivityStatus network = ref.watch(checkNetworkProvider); - + final word = TranslationRepo.translate(context); return network == ConnectivityStatus.On ? Scaffold( - body: SafeArea( - child: RawScrollbar( - thumbColor: getColorScheme(context).tertiary, - thickness: 5, - radius: const Radius.circular(10), - child: Padding( - padding: - const EdgeInsets.symmetric(horizontal: 10, vertical: 10), - child: GridView.count( - crossAxisCount: rh.responsiveCatogeries(context), - childAspectRatio: 3 / 2, - mainAxisSpacing: 10, - crossAxisSpacing: 10, - children: [ - FoodCategory( - navigate: '/breakfast', - name: LocaleKeys.Breakfast.tr(), - image: - "https://images.unsplash.com/photo-1482049016688-2d3e1b311543?ixlib=rb-1.2.1&ixid=MnwxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8&auto=format&fit=crop&w=710&q=80", - ), - FoodCategory( - navigate: '/lunch', - name: LocaleKeys.Lunch.tr(), - image: - "https://images.unsplash.com/photo-1576866209830-589e1bfbaa4d?ixlib=rb-1.2.1&ixid=MnwxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8&auto=format&fit=crop&w=1170&q=80", - ), - if (adHelper.isnativeBannerAdLoaded & kReleaseMode) ...[ - SizedBox( - height: - adHelper.nativeAdBanner.size.height.toDouble(), - width: adHelper.nativeAdBanner.size.width.toDouble(), - child: AdWidget(ad: adHelper.nativeAdBanner), - ), - ], - FoodCategory( - navigate: '/dinner', - name: LocaleKeys.Dinner.tr(), - image: - "https://images.unsplash.com/photo-1473973916745-60839aebf06b?ixlib=rb-1.2.1&ixid=MnwxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8&auto=format&fit=crop&w=687&q=80", - ), - FoodCategory( - navigate: '/snacks', - name: LocaleKeys.Snacks.tr(), - image: - "https://images.unsplash.com/photo-1496412705862-e0088f16f791?ixlib=rb-1.2.1&ixid=MnwxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8&auto=format&fit=crop&w=1170&q=80", - ), - ], - ), + body: RawScrollbar( + thumbColor: colorScheme(context).tertiary, + thickness: 5, + radius: const Radius.circular(10), + child: Padding( + padding: + const EdgeInsets.symmetric(horizontal: 10, vertical: 10), + child: GridView.count( + crossAxisCount: rh.responsiveCatogeries(context), + childAspectRatio: 3 / 2, + mainAxisSpacing: 10, + crossAxisSpacing: 10, + children: [ + FoodCategory( + navigate: '/breakfast', + name: word?.breakfast ?? '', + image: + "https://images.unsplash.com/photo-1482049016688-2d3e1b311543?ixlib=rb-1.2.1&ixid=MnwxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8&auto=format&fit=crop&w=710&q=80", + ), + FoodCategory( + navigate: '/lunch', + name: word?.lunch ?? '', + image: + "https://images.unsplash.com/photo-1576866209830-589e1bfbaa4d?ixlib=rb-1.2.1&ixid=MnwxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8&auto=format&fit=crop&w=1170&q=80", + ), + FoodCategory( + navigate: '/dinner', + name: word?.dinner ?? '', + image: + "https://images.unsplash.com/photo-1473973916745-60839aebf06b?ixlib=rb-1.2.1&ixid=MnwxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8&auto=format&fit=crop&w=687&q=80", + ), + FoodCategory( + navigate: '/snacks', + name: word?.snacks ?? '', + image: + "https://images.unsplash.com/photo-1496412705862-e0088f16f791?ixlib=rb-1.2.1&ixid=MnwxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8&auto=format&fit=crop&w=1170&q=80", + ), + ], ), ), ), diff --git a/lib/src/features/meals/presentation/snacks.dart b/lib/src/features/meals/presentation/snacks.dart index 7ab588c..f6ff3b0 100644 --- a/lib/src/features/meals/presentation/snacks.dart +++ b/lib/src/features/meals/presentation/snacks.dart @@ -1,7 +1,5 @@ -import 'package:easy_localization/easy_localization.dart'; - import '../../../constants/constants.dart'; -import '../../../translations/locale_keys.g.dart'; +import '../../../translations/domain/translation_provider.dart'; import 'breakfast.dart'; import 'package:flutter/material.dart'; @@ -10,16 +8,18 @@ class Snacks extends StatelessWidget { @override Widget build(BuildContext context) { + final word = TranslationRepo.translate(context); + return Scaffold( appBar: AppBar( - title: Text(LocaleKeys.Snacks.tr()), + title: Text(word?.snacks ?? ''), centerTitle: true, elevation: 1.2, // ignore: use_full_hex_values_for_flutter_colors ), body: OrientationBuilder( builder: ((context, orientation) => RawScrollbar( - thumbColor: getColorScheme(context).tertiary, + thumbColor: colorScheme(context).tertiary, thickness: 5, radius: const Radius.circular(10), child: GridView.count( @@ -30,38 +30,38 @@ class Snacks extends StatelessWidget { url: 'https://www.youtube.com/watch?v=DeeBmd7OaX0', image: 'https://www.unlockfood.ca/EatRightOntario/media/Website-images-resized/All-about-Nuts-resized.jpg', - name: LocaleKeys.Mixed_Nuts.tr(), + name: word?.mixed_Nuts, ), Category( url: 'https://www.youtube.com/results?search_query=Red+pepper+guacamole', image: 'https://www.thefullhelping.com/wp-content/uploads/2013/02/IMG_3904.jpg', - name: LocaleKeys.Red_pepper_guacamole.tr(), + name: word?.red_pepper_guacamole, ), Category( url: 'https://www.youtube.com/watch?v=z0uTL_ZOOoY', image: 'https://recipeforperfection.com/wp-content/uploads/2019/01/Very-Berry-Yogurt-Bowl.jpg', - name: LocaleKeys.Yogurt_with_mixed_berries.tr(), + name: word?.yogurt_with_mixed_berries, ), Category( url: 'https://www.youtube.com/watch?v=iD2HVkiE_us', image: 'https://www.checkyourfood.com/content/blob/Meals/Apple-and-peanut-butter-recipe-calories-nutrition-facts.jpg', - name: LocaleKeys.Apple_slices_with_peanut.tr(), + name: word?.apple_slices_with_peanut, ), Category( url: 'https://www.youtube.com/watch?v=SW0UkfgrQNg', image: 'https://cdn.shopify.com/s/files/1/2836/2982/products/cottage-cheese-1_large.jpg?v=1529434175', - name: LocaleKeys.Cottage_cheese.tr(), + name: word?.cottage_cheese, ), Category( url: 'https://www.youtube.com/watch?v=PztY4NAyqoI', image: 'https://lh3.googleusercontent.com/DrzBVaJUqxL6ze1_xMZ6etzPZiePc8gJiXvi6L0npLhn7aXpq-gH7LbQxe6UzwmleXxuqkEV2-PztSXCshtyl3p5ovEYA2IALzk=w1280-h960-c-rj-v1-e365', - name: LocaleKeys.Celery_sticks_with_Cheese.tr(), + name: word?.celery_sticks_with_Cheese, ), ], ), diff --git a/lib/src/features/navigation/data/navigation_notifier.dart b/lib/src/features/navigation/data/navigation_notifier.dart new file mode 100644 index 0000000..f3a95cf --- /dev/null +++ b/lib/src/features/navigation/data/navigation_notifier.dart @@ -0,0 +1,21 @@ +import 'package:flutter/material.dart'; +import 'package:hooks_riverpod/hooks_riverpod.dart'; +import 'package:livine/src/shared/cache/cache_helper.dart'; + +final navigationNotifierProvider = + StateNotifierProvider((ref) => NavigationNotifier()); + +class NavigationNotifier extends StateNotifier { + NavigationNotifier() : super(_initialScrollPhysics()); + + static ScrollPhysics? _initialScrollPhysics() { + bool isSwipeNavigation = CacheHelper.getBool("isSwipeNavigation") ?? false; + return isSwipeNavigation ? null : const NeverScrollableScrollPhysics(); + } + + void togglePhysics(bool value) async { + state = value == false ? const NeverScrollableScrollPhysics() : null; + await CacheHelper.setBool("isSwipeNavigation", + state == NeverScrollableScrollPhysics() ? false : true); + } +} diff --git a/lib/src/features/navigation/presentation/base.dart b/lib/src/features/navigation/presentation/base.dart index 3f33c42..5b32692 100644 --- a/lib/src/features/navigation/presentation/base.dart +++ b/lib/src/features/navigation/presentation/base.dart @@ -1,32 +1,36 @@ +// ignore_for_file: invalid_use_of_visible_for_testing_member, invalid_use_of_protected_member + import 'package:flutter_hooks/flutter_hooks.dart'; import 'package:flutter/material.dart'; -import 'package:font_awesome_flutter/font_awesome_flutter.dart'; -import 'package:iconsax/iconsax.dart'; -import 'package:responsive_framework/responsive_wrapper.dart'; -import 'package:easy_localization/easy_localization.dart'; +import 'package:hooks_riverpod/hooks_riverpod.dart'; +import 'package:livine/src/translations/domain/translation_provider.dart'; +import 'package:responsive_framework/responsive_breakpoints.dart'; import '../../../shared/children/children.dart'; +import '../data/navigation_notifier.dart'; import 'tablet_navigation.dart'; -class Navigation extends HookWidget { +class Navigation extends HookConsumerWidget { const Navigation({Key? key}) : super(key: key); @override - Widget build(BuildContext context) { + Widget build(BuildContext context, WidgetRef ref) { final index = useState(0); final pageController = usePageController(); const duration = Duration(milliseconds: 300); const curve = Curves.easeInOut; - return ResponsiveWrapper.of(context).isTablet || - ResponsiveWrapper.of(context).isDesktop + final word = TranslationRepo.translate(context); + return ResponsiveBreakpoints.of(context).isTablet || + ResponsiveBreakpoints.of(context).isDesktop ? const TabletNavigation() : Scaffold( body: PageView( controller: pageController, onPageChanged: (page) => index.value = page, children: children, + physics: ref.watch(navigationNotifierProvider.notifier).state, ), bottomNavigationBar: NavigationBar( selectedIndex: index.value, @@ -36,25 +40,15 @@ class Navigation extends HookWidget { }, destinations: [ NavigationDestination( - icon: const Icon(Iconsax.home_11), - label: - context.locale.languageCode == "en" ? "Home" : "الرئيسية", + icon: const Icon(Icons.home_rounded), + label: word?.home ?? '', ), NavigationDestination( - icon: const Icon(FontAwesomeIcons.bowlFood), - label: context.locale.languageCode == "en" - ? "Meals" - : "الوجبات"), - NavigationDestination( - icon: const Icon(Iconsax.user_square), - label: context.locale.languageCode == "en" - ? "Profile" - : "الحساب الشخصي"), + icon: const Icon(Icons.local_dining), + label: word?.meals ?? ''), NavigationDestination( - icon: const Icon(Iconsax.setting_2), - label: context.locale.languageCode == "en" - ? "Settings" - : "الاعدادات"), + icon: const Icon(Icons.person_rounded), + label: word?.profile ?? ''), ], labelBehavior: NavigationDestinationLabelBehavior.onlyShowSelected, diff --git a/lib/src/features/navigation/presentation/tablet_navigation.dart b/lib/src/features/navigation/presentation/tablet_navigation.dart index 57697f8..7b1858b 100644 --- a/lib/src/features/navigation/presentation/tablet_navigation.dart +++ b/lib/src/features/navigation/presentation/tablet_navigation.dart @@ -1,7 +1,6 @@ -import 'package:easy_localization/easy_localization.dart'; -import 'package:fluentui_icons/fluentui_icons.dart'; import 'package:flutter/material.dart'; import '../../../shared/children/children.dart'; +import '../../../translations/domain/translation_provider.dart'; class TabletNavigation extends StatefulWidget { const TabletNavigation({Key? key}) : super(key: key); @@ -15,6 +14,7 @@ class _TabletNavigationState extends State { bool isExtended = false; @override Widget build(BuildContext context) { + final word = TranslationRepo.translate(context); return Scaffold( body: SafeArea( child: Row( @@ -34,46 +34,34 @@ class _TabletNavigationState extends State { isExtended = !isExtended; }); }, - icon: const Icon(FluentSystemIcons.ic_fluent_library_filled), + icon: const Icon(Icons.filter_list), ), minExtendedWidth: 200, destinations: [ NavigationRailDestination( padding: const EdgeInsets.symmetric(vertical: 20.0), - icon: Icon(FluentSystemIcons.ic_fluent_home_filled, + icon: Icon(Icons.filter_list, size: MediaQuery.of(context).size.width / 70), - label: context.locale.languageCode == "en" - ? const Text("Home") - : const Text("الرئيسية"), + label: Text(word?.home ?? ""), ), NavigationRailDestination( padding: const EdgeInsets.symmetric(vertical: 20.0), - icon: Icon(FluentSystemIcons.ic_fluent_food_filled, + icon: Icon(Icons.filter_list, size: MediaQuery.of(context).size.width / 70), - label: context.locale.languageCode == "en" - ? const Text("Meals") - : const Text("الوجبات"), + label: Text(word?.meals ?? ""), ), - // NavigationRailDestination( - // padding: EdgeInsets.symmetric(vertical: 20.0), - // icon: Icon(Icons.star_rate_rounded, size: 30), - // label: context.locale.languageCode == "en" - // ? Text("Pristine") - // : Text("الاصلي")), NavigationRailDestination( - padding: const EdgeInsets.symmetric(vertical: 20.0), - icon: Icon(FluentSystemIcons.ic_fluent_person_regular, - size: MediaQuery.of(context).size.width / 70), - label: context.locale.languageCode == "en" - ? const Text("Profile") - : const Text("الحساب الشخصي")), + padding: const EdgeInsets.symmetric(vertical: 20.0), + icon: Icon(Icons.filter_list, + size: MediaQuery.of(context).size.width / 70), + label: Text(word?.profile ?? ""), + ), NavigationRailDestination( - padding: const EdgeInsets.symmetric(vertical: 20.0), - icon: Icon(FluentSystemIcons.ic_fluent_settings_filled, - size: MediaQuery.of(context).size.width / 70), - label: context.locale.languageCode == "en" - ? const Text("Settings") - : const Text("الاعدادات")), + padding: const EdgeInsets.symmetric(vertical: 20.0), + icon: Icon(Icons.filter_list, + size: MediaQuery.of(context).size.width / 70), + label: Text(word?.settings ?? ""), + ), ], ), const VerticalDivider(thickness: 1, width: 1), diff --git a/lib/src/features/onboarding/presentation/boarding.dart b/lib/src/features/onboarding/presentation/boarding.dart index 0454d1b..28c832a 100644 --- a/lib/src/features/onboarding/presentation/boarding.dart +++ b/lib/src/features/onboarding/presentation/boarding.dart @@ -1,16 +1,15 @@ // ignore_for_file: use_full_hex_values_for_flutter_colors -import 'package:easy_localization/easy_localization.dart'; import 'package:go_router/go_router.dart'; import 'package:concentric_transition/concentric_transition.dart'; import 'package:flutter/material.dart'; import 'package:flutter_svg/flutter_svg.dart'; -import 'package:google_fonts/google_fonts.dart'; +import 'package:hooks_riverpod/hooks_riverpod.dart'; import 'package:livine/src/shared/cache/cache_helper.dart'; +import 'package:livine/src/translations/domain/translation_provider.dart'; import '../../../constants/constants.dart'; -import '../../../shared/styles/colors.dart'; class OnBoarding extends StatelessWidget { const OnBoarding({Key? key}) : super(key: key); @@ -32,7 +31,7 @@ class OnBoarding extends StatelessWidget { ]; final List textColors = [ - Colors.black, + Theme.of(context).colorScheme.onSurface, Colors.black, Colors.white, Colors.black @@ -41,11 +40,11 @@ class OnBoarding extends StatelessWidget { return Scaffold( body: ConcentricPageView( duration: const Duration(milliseconds: 1200), - colors: const [ - Colors.white, - primaryColor, - thirdColor, - primaryColor + colors: [ + Theme.of(context).colorScheme.surface, + Theme.of(context).colorScheme.primary, + Theme.of(context).colorScheme.tertiary, + Theme.of(context).colorScheme.primary, ], radius: screenWidth * 0.1, onFinish: () { @@ -60,12 +59,14 @@ class OnBoarding extends StatelessWidget { ), ), itemBuilder: (int index) { - return IntroScreens( - text: context.locale.languageCode == "en" - ? heading[index] - : headingInArabic[index], - url: 'assets/images/onboarding/${images[index]}.svg', - textColor: textColors[index]); + return Consumer( + builder: (context, ref, child) => IntroScreens( + text: ref.watch(localeNotifierProvider).languageCode == "en" + ? heading[index] + : headingInArabic[index], + url: 'assets/images/onboarding/${images[index]}.svg', + textColor: textColors[index]), + ); }, ), ); @@ -91,9 +92,12 @@ class IntroScreens extends StatelessWidget { padding: EdgeInsets.symmetric(vertical: rh.deviceHeight(context) / 8), child: Column( children: [ - SvgPicture.asset( - url, - height: 250.0, + Flexible( + flex: 2, + child: SvgPicture.asset( + url, + height: 250.0, + ), ), const SizedBox( height: 20.0, @@ -103,12 +107,10 @@ class IntroScreens extends StatelessWidget { textAlign: TextAlign.center, style: TextStyle( fontSize: 30.0, - fontFamily: context.locale.languageCode == "en" - ? 'Kine' - : GoogleFonts.notoKufiArabic().fontFamily, color: textColor, ), ), + Spacer(flex: 1) ], ), ), diff --git a/lib/src/features/premium_pristine/presentation/pristine.dart b/lib/src/features/premium_pristine/presentation/pristine.dart index da0663a..9cfa3d2 100644 --- a/lib/src/features/premium_pristine/presentation/pristine.dart +++ b/lib/src/features/premium_pristine/presentation/pristine.dart @@ -1,222 +1,222 @@ -// ignore_for_file: type_annotate_public_apis +// // ignore_for_file: type_annotate_public_apis -import 'package:easy_localization/easy_localization.dart'; -import 'package:flutter/material.dart'; -import 'package:pay/pay.dart'; +// import 'package:easy_localization/easy_localization.dart'; +// import 'package:flutter/material.dart'; // import 'package:pay/pay.dart'; +// // import 'package:pay/pay.dart'; -import '../../../shared/styles/lib_color_schemes.g.dart'; -import '../../../translations/locale_keys.g.dart'; +// import '../../../shared/styles/lib_color_schemes.g.dart'; +// import '../../../translations/locale_keys.g.dart'; -const _paymentItems = [ - PaymentItem( - label: 'Total', - amount: '0.00', - status: PaymentItemStatus.final_price, - ) -]; +// const _paymentItems = [ +// PaymentItem( +// label: 'Total', +// amount: '0.00', +// status: PaymentItemStatus.final_price, +// ) +// ]; -class Pristine extends StatefulWidget { - const Pristine({Key? key}) : super(key: key); +// class Pristine extends StatefulWidget { +// const Pristine({Key? key}) : super(key: key); - @override - State createState() => _PristineState(); -} +// @override +// State createState() => _PristineState(); +// } -class _PristineState extends State { - void onGooglePayResult(data) { - debugPrint(data.toString()); - } +// class _PristineState extends State { +// void onGooglePayResult(data) { +// debugPrint(data.toString()); +// } - @override - Widget build(BuildContext context) { - return Scaffold( - body: SafeArea( - child: SingleChildScrollView( - child: - Column(crossAxisAlignment: CrossAxisAlignment.start, children: [ - Center( - child: Column( - children: [ - Padding( - padding: const EdgeInsets.only(top: 20.0), - child: Image.asset( - 'assets/images/icon/pristine.png', - width: 80.0, - ), - ), - const SizedBox( - height: 10.0, - ), - PristineText( - name: LocaleKeys.life_pristine.tr(), - ), - ], - ), - ), - const SizedBox( - height: 10.0, - ), - Padding( - padding: const EdgeInsets.only(left: 15.0), - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - FeaturesText( - name: LocaleKeys.Pristine_access.tr(), - ), - ], - ), - ), - const SizedBox( - height: 50.0, - ), - Center( - child: Padding( - padding: const EdgeInsets.only(top: 10.0), - child: Column( - children: [ - Padding( - padding: const EdgeInsets.all(8.0), - child: TextButton( - onPressed: () { - showModalBottomSheet( - elevation: 2, - context: context, - builder: (context) { - return SizedBox( - height: 150, - child: Column( - mainAxisAlignment: - MainAxisAlignment.spaceEvenly, - children: [ - Text( - LocaleKeys.gateway.tr(), - style: const TextStyle( - fontSize: 24.0, - fontWeight: FontWeight.bold), - ), - GooglePayButton( - width: 200, - height: 60, - paymentConfiguration: - PaymentConfiguration.fromJsonString('pay.json'), - paymentItems: _paymentItems, - type: GooglePayButtonType.subscribe, - margin: EdgeInsets.only(top: 15.0), - onPaymentResult: onGooglePayResult, - loadingIndicator: const Center( - child: CircularProgressIndicator(), - ), - ), - ]), - ); - }); - }, - style: ButtonStyle( - shadowColor: - MaterialStateProperty.all(Colors.black), - shape: MaterialStateProperty.all< - RoundedRectangleBorder>(RoundedRectangleBorder( - borderRadius: BorderRadius.circular(18.0), - )), - backgroundColor: MaterialStateProperty.all( - Theme.of(context).brightness == Brightness.dark - ? darkColorScheme.secondaryContainer - : lightColorScheme.onSecondaryContainer)), - child: Padding( - padding: const EdgeInsets.all(10.0), - child: Row( - mainAxisAlignment: MainAxisAlignment.spaceBetween, - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Text( - LocaleKeys.three_months.tr(), - style: const TextStyle( - color: Colors.white, - fontSize: 20.0, - fontWeight: FontWeight.bold), - ), - const SizedBox( - height: 10.0, - ), - Text( - "${LocaleKeys.total_price.tr()} \$10.00", - style: const TextStyle(color: Colors.white), - ) - ], - ), - Column( - children: [ - const Text( - "\$10.00", - style: TextStyle( - color: Colors.white, - fontWeight: FontWeight.bold, - fontSize: 20.0), - ), - const SizedBox( - height: 10.0, - ), - Text( - LocaleKeys.monthly.tr(), - style: const TextStyle(color: Colors.white), - ), - ], - ) - ], - ), - )), - ), - const SizedBox( - height: 10.0, - ), - Text( - LocaleKeys.cancel_sub.tr(), - style: const TextStyle(fontSize: 10.0), - ) - ], - ), - )), - ]), - ), - ), - ); - } -} +// @override +// Widget build(BuildContext context) { +// return Scaffold( +// body: SafeArea( +// child: SingleChildScrollView( +// child: +// Column(crossAxisAlignment: CrossAxisAlignment.start, children: [ +// Center( +// child: Column( +// children: [ +// Padding( +// padding: const EdgeInsets.only(top: 20.0), +// child: Image.asset( +// 'assets/images/icon/pristine.png', +// width: 80.0, +// ), +// ), +// const SizedBox( +// height: 10.0, +// ), +// PristineText( +// name: LocaleKeys.life_pristine.tr(), +// ), +// ], +// ), +// ), +// const SizedBox( +// height: 10.0, +// ), +// Padding( +// padding: const EdgeInsets.only(left: 15.0), +// child: Column( +// crossAxisAlignment: CrossAxisAlignment.start, +// children: [ +// FeaturesText( +// name: LocaleKeys.Pristine_access.tr(), +// ), +// ], +// ), +// ), +// const SizedBox( +// height: 50.0, +// ), +// Center( +// child: Padding( +// padding: const EdgeInsets.only(top: 10.0), +// child: Column( +// children: [ +// Padding( +// padding: const EdgeInsets.all(8.0), +// child: TextButton( +// onPressed: () { +// showModalBottomSheet( +// elevation: 2, +// context: context, +// builder: (context) { +// return SizedBox( +// height: 150, +// child: Column( +// mainAxisAlignment: +// MainAxisAlignment.spaceEvenly, +// children: [ +// Text( +// LocaleKeys.gateway.tr(), +// style: const TextStyle( +// fontSize: 24.0, +// fontWeight: FontWeight.bold), +// ), +// GooglePayButton( +// width: 200, +// height: 60, +// paymentConfiguration: +// PaymentConfiguration.fromJsonString('pay.json'), +// paymentItems: _paymentItems, +// type: GooglePayButtonType.subscribe, +// margin: EdgeInsets.only(top: 15.0), +// onPaymentResult: onGooglePayResult, +// loadingIndicator: const Center( +// child: CircularProgressIndicator(), +// ), +// ), +// ]), +// ); +// }); +// }, +// style: ButtonStyle( +// shadowColor: +// MaterialStateProperty.all(Colors.black), +// shape: MaterialStateProperty.all< +// RoundedRectangleBorder>(RoundedRectangleBorder( +// borderRadius: BorderRadius.circular(18.0), +// )), +// backgroundColor: MaterialStateProperty.all( +// Theme.of(context).brightness == Brightness.dark +// ? darkColorScheme.secondaryContainer +// : lightColorScheme.onSecondaryContainer)), +// child: Padding( +// padding: const EdgeInsets.all(10.0), +// child: Row( +// mainAxisAlignment: MainAxisAlignment.spaceBetween, +// crossAxisAlignment: CrossAxisAlignment.start, +// children: [ +// Column( +// crossAxisAlignment: CrossAxisAlignment.start, +// children: [ +// Text( +// LocaleKeys.three_months.tr(), +// style: const TextStyle( +// color: Colors.white, +// fontSize: 20.0, +// fontWeight: FontWeight.bold), +// ), +// const SizedBox( +// height: 10.0, +// ), +// Text( +// "${LocaleKeys.total_price.tr()} \$10.00", +// style: const TextStyle(color: Colors.white), +// ) +// ], +// ), +// Column( +// children: [ +// const Text( +// "\$10.00", +// style: TextStyle( +// color: Colors.white, +// fontWeight: FontWeight.bold, +// fontSize: 20.0), +// ), +// const SizedBox( +// height: 10.0, +// ), +// Text( +// LocaleKeys.monthly.tr(), +// style: const TextStyle(color: Colors.white), +// ), +// ], +// ) +// ], +// ), +// )), +// ), +// const SizedBox( +// height: 10.0, +// ), +// Text( +// LocaleKeys.cancel_sub.tr(), +// style: const TextStyle(fontSize: 10.0), +// ) +// ], +// ), +// )), +// ]), +// ), +// ), +// ); +// } +// } -class FeaturesText extends StatelessWidget { - const FeaturesText({ - Key? key, - required this.name, - }) : super(key: key); - final String name; - @override - Widget build(BuildContext context) { - return Center( - child: Text( - name, - style: const TextStyle(fontSize: 16.0), - textAlign: TextAlign.center, - ), - ); - } -} +// class FeaturesText extends StatelessWidget { +// const FeaturesText({ +// Key? key, +// required this.name, +// }) : super(key: key); +// final String name; +// @override +// Widget build(BuildContext context) { +// return Center( +// child: Text( +// name, +// style: const TextStyle(fontSize: 16.0), +// textAlign: TextAlign.center, +// ), +// ); +// } +// } -class PristineText extends StatelessWidget { - const PristineText({ - Key? key, - required this.name, - }) : super(key: key); - final String name; - @override - Widget build(BuildContext context) { - return Text( - name, - style: const TextStyle(fontSize: 24.0, fontWeight: FontWeight.bold), - ); - } -} +// class PristineText extends StatelessWidget { +// const PristineText({ +// Key? key, +// required this.name, +// }) : super(key: key); +// final String name; +// @override +// Widget build(BuildContext context) { +// return Text( +// name, +// style: const TextStyle(fontSize: 24.0, fontWeight: FontWeight.bold), +// ); +// } +// } diff --git a/lib/src/features/scan_food/presentation/controllers/image_controller.dart b/lib/src/features/scan_food/presentation/controllers/image_controller.dart index b5d57a5..d1bc215 100644 --- a/lib/src/features/scan_food/presentation/controllers/image_controller.dart +++ b/lib/src/features/scan_food/presentation/controllers/image_controller.dart @@ -1,78 +1,78 @@ -import 'dart:developer'; -import 'dart:io'; +// import 'dart:developer'; +// import 'dart:io'; -import 'package:flutter/material.dart'; -import 'package:flutter/services.dart'; -import 'package:image_cropper/image_cropper.dart'; -import 'package:image_picker/image_picker.dart'; +// import 'package:flutter/material.dart'; +// import 'package:flutter/services.dart'; +// import 'package:image_cropper/image_cropper.dart'; +// import 'package:image_picker/image_picker.dart'; -import '../../../../constants/constants.dart'; +// import '../../../../constants/constants.dart'; -class ImageController { - final ImagePicker _picker = ImagePicker(); - File? image; - bool isModelFromGallery = false; +// class ImageController { +// final ImagePicker _picker = ImagePicker(); +// File? image; +// bool isModelFromGallery = false; - Future pickImageFromGallery( - void Function(void Function()) setState, - bool mounted, - BuildContext context, - ) async { - final theme = Theme.of(context).colorScheme; - try { - final image = await _picker.pickImage(source: ImageSource.gallery); +// Future pickImageFromGallery( +// void Function(void Function()) setState, +// bool mounted, +// BuildContext context, +// ) async { +// final theme = Theme.of(context).colorScheme; +// try { +// final image = await _picker.pickImage(source: ImageSource.gallery); - if (image == null) return; +// if (image == null) return; - CroppedFile? cropped = await ImageCropper().cropImage( - sourcePath: image.path, - uiSettings: [ - AndroidUiSettings( - toolbarTitle: 'Crop the food', - toolbarColor: theme.surface, - initAspectRatio: CropAspectRatioPreset.original, - lockAspectRatio: false), - ], - aspectRatio: const CropAspectRatio(ratioX: 1, ratioY: 1), - ); +// CroppedFile? cropped = await ImageCropper().cropImage( +// sourcePath: image.path, +// uiSettings: [ +// AndroidUiSettings( +// toolbarTitle: 'Crop the food', +// toolbarColor: theme.surface, +// initAspectRatio: CropAspectRatioPreset.original, +// lockAspectRatio: false), +// ], +// aspectRatio: const CropAspectRatio(ratioX: 1, ratioY: 1), +// ); - final imageTemp = File(cropped!.path); +// final imageTemp = File(cropped!.path); - setState(() { - this.image = imageTemp; - isModelFromGallery = true; - }); - } on PlatformException catch (e) { - log("Failed to pick image: $e"); - } finally { - modelTF.runModelonGallery(image, mounted, setState); - } - } +// setState(() { +// this.image = imageTemp; +// isModelFromGallery = true; +// }); +// } on PlatformException catch (e) { +// log("Failed to pick image: $e"); +// } finally { +// modelTF.runModelonGallery(image, mounted, setState); +// } +// } - Future pickImageFromCamera( - void Function(void Function()) setState, - bool mounted, - BuildContext context, - ) async { - try { - final image = await _picker.pickImage(source: ImageSource.camera); +// Future pickImageFromCamera( +// void Function(void Function()) setState, +// bool mounted, +// BuildContext context, +// ) async { +// try { +// final image = await _picker.pickImage(source: ImageSource.camera); - if (image == null) return; +// if (image == null) return; - final imageTemp = File(image.path); +// final imageTemp = File(image.path); - setState(() { - this.image = imageTemp; - isModelFromGallery = true; - }); - } on PlatformException catch (e) { - log("Failed to pick image: $e"); - } finally { - modelTF.runModelonGallery(image, mounted, setState); - } - } +// setState(() { +// this.image = imageTemp; +// isModelFromGallery = true; +// }); +// } on PlatformException catch (e) { +// log("Failed to pick image: $e"); +// } finally { +// modelTF.runModelonGallery(image, mounted, setState); +// } +// } -} +// } diff --git a/lib/src/features/scan_food/presentation/controllers/model_controller.dart b/lib/src/features/scan_food/presentation/controllers/model_controller.dart index d11f9ee..15987a4 100644 --- a/lib/src/features/scan_food/presentation/controllers/model_controller.dart +++ b/lib/src/features/scan_food/presentation/controllers/model_controller.dart @@ -1,70 +1,70 @@ -import 'dart:io'; +// import 'dart:io'; -import 'package:flutter/material.dart'; -import 'package:tflite/tflite.dart'; +// import 'package:flutter/material.dart'; +// import 'package:tflite/tflite.dart'; -class ModelTFLite { - String output = ''; - int index = 1; - double confidence = 0; - bool isModelFromGallery = false; +// class ModelTFLite { +// String output = ''; +// int index = 1; +// double confidence = 0; +// bool isModelFromGallery = false; - bool isVisible = false; +// bool isVisible = false; - Future loadmodel() async { - await Tflite.loadModel( - model: "assets/model/model.tflite", labels: "assets/model/labels.txt"); - } +// Future loadmodel() async { +// await Tflite.loadModel( +// model: "assets/model/model.tflite", labels: "assets/model/labels.txt"); +// } - Future runModelonGallery(File? image, bool mounted, - void Function(void Function()) setState) async { - if (image != null && mounted) { - var predictions = await Tflite.runModelOnImage(path: image.path); - var firstPredictions = predictions?.first; - var lastPredictions = predictions?.last; +// Future runModelonGallery(File? image, bool mounted, +// void Function(void Function()) setState) async { +// if (image != null && mounted) { +// var predictions = await Tflite.runModelOnImage(path: image.path); +// var firstPredictions = predictions?.first; +// var lastPredictions = predictions?.last; - setState(() { - isModelFromGallery = true; - }); - if (firstPredictions.values.first > lastPredictions.values.first) { - setState(() { - confidence = firstPredictions.values.first; - output = firstPredictions!['label']; - index = firstPredictions!['index']; - }); - } else { - setState(() { - confidence = lastPredictions.values.first; - output = lastPredictions!['label']; - index = lastPredictions!['index']; - }); - } - } - } +// setState(() { +// isModelFromGallery = true; +// }); +// if (firstPredictions.values.first > lastPredictions.values.first) { +// setState(() { +// confidence = firstPredictions.values.first; +// output = firstPredictions!['label']; +// index = firstPredictions!['index']; +// }); +// } else { +// setState(() { +// confidence = lastPredictions.values.first; +// output = lastPredictions!['label']; +// index = lastPredictions!['index']; +// }); +// } +// } +// } - String checkHealth( - void Function(void Function()) setState, AnimationController controller) { - if (index == 0 && output.isNotEmpty) { - setState(() { - isVisible = true; - }); - controller.forward(); - return "Healthy"; - } else if (index == 1 && output.isNotEmpty) { - controller.reverse(); - setState(() { - isVisible = true; - }); - return "Unhealthy"; - } else { - setState(() { - isVisible = false; - }); - return 'Choose'; - } - } +// String checkHealth( +// void Function(void Function()) setState, AnimationController controller) { +// if (index == 0 && output.isNotEmpty) { +// setState(() { +// isVisible = true; +// }); +// controller.forward(); +// return "Healthy"; +// } else if (index == 1 && output.isNotEmpty) { +// controller.reverse(); +// setState(() { +// isVisible = true; +// }); +// return "Unhealthy"; +// } else { +// setState(() { +// isVisible = false; +// }); +// return 'Choose'; +// } +// } -} +// } diff --git a/lib/src/features/scan_food/presentation/scan.dart b/lib/src/features/scan_food/presentation/scan.dart index 11ebcb6..b0e6552 100644 --- a/lib/src/features/scan_food/presentation/scan.dart +++ b/lib/src/features/scan_food/presentation/scan.dart @@ -1,121 +1,121 @@ -import 'package:flutter/material.dart'; -import 'package:lottie/lottie.dart'; -// import 'package:tflite/tflite.dart'; +// import 'package:flutter/material.dart'; +// import 'package:lottie/lottie.dart'; +// // import 'package:tflite/tflite.dart'; -import '../../../constants/constants.dart'; +// import '../../../constants/constants.dart'; -class Scan extends StatefulWidget { - const Scan({Key? key}) : super(key: key); +// class Scan extends StatefulWidget { +// const Scan({Key? key}) : super(key: key); - @override - State createState() => _ScanState(); -} +// @override +// State createState() => _ScanState(); +// } -class _ScanState extends State with TickerProviderStateMixin { - late final AnimationController controller; +// class _ScanState extends State with TickerProviderStateMixin { +// late final AnimationController controller; - @override - void initState() { - super.initState(); +// @override +// void initState() { +// super.initState(); - modelTF.loadmodel(); - controller = - AnimationController(vsync: this, duration: const Duration(seconds: 2)); - } +// modelTF.loadmodel(); +// controller = +// AnimationController(vsync: this, duration: const Duration(seconds: 2)); +// } - @override - void dispose() async { - controller.dispose(); +// @override +// void dispose() async { +// controller.dispose(); - super.dispose(); - } +// super.dispose(); +// } - @override - Widget build(BuildContext context) { - final theme = Theme.of(context).colorScheme; - return Scaffold( - appBar: AppBar(title: const Text('Scan Food'), centerTitle: true), - body: Column(children: [ - Expanded( - child: imageController.image != null - ? Image.file( - imageController.image!, - width: 200, - height: 200, - errorBuilder: (context, error, stackTrace) { - return Center( - child: Text( - 'Error: $error', - ), - ); - }, - ) - : Container(), - ), - const SizedBox( - height: 20, - ), - Column( - children: [ - Text( - modelTF.checkHealth(setState, controller), - style: const TextStyle(fontWeight: FontWeight.bold, fontSize: 20), - ), - Row( - mainAxisAlignment: MainAxisAlignment.center, - children: [ - ElevatedButton( - onPressed: () { - imageController.pickImageFromCamera( - setState, mounted, context); - }, - child: Row( - children: const [ - Icon(Icons.camera_alt), - SizedBox( - width: 10, - ), - Text('Use Camera'), - ], - ), - ), - const SizedBox( - width: 20, - ), - ElevatedButton( - style: ButtonStyle( - backgroundColor: MaterialStateProperty.all( - theme.tertiaryContainer)), - onPressed: () { - imageController.pickImageFromGallery( - setState, mounted, context); - }, - child: Row( - children: [ - Icon( - Icons.photo_library, - color: theme.onTertiaryContainer, - ), - const SizedBox( - width: 10, - ), - Text( - 'Use Gallery', - style: TextStyle(color: theme.onTertiaryContainer), - ), - ], - ), - ), - ], - ), - const SizedBox( - height: 20, - ), - Lottie.asset("assets/images/loading/emoji_anim.json", - controller: controller, width: 200), - ], - ), - ]), - ); - } -} +// @override +// Widget build(BuildContext context) { +// final theme = Theme.of(context).colorScheme; +// return Scaffold( +// appBar: AppBar(title: const Text('Scan Food'), centerTitle: true), +// body: Column(children: [ +// Expanded( +// child: imageController.image != null +// ? Image.file( +// imageController.image!, +// width: 200, +// height: 200, +// errorBuilder: (context, error, stackTrace) { +// return Center( +// child: Text( +// 'Error: $error', +// ), +// ); +// }, +// ) +// : Container(), +// ), +// const SizedBox( +// height: 20, +// ), +// Column( +// children: [ +// Text( +// modelTF.checkHealth(setState, controller), +// style: const TextStyle(fontWeight: FontWeight.bold, fontSize: 20), +// ), +// Row( +// mainAxisAlignment: MainAxisAlignment.center, +// children: [ +// ElevatedButton( +// onPressed: () { +// imageController.pickImageFromCamera( +// setState, mounted, context); +// }, +// child: Row( +// children: const [ +// Icon(Icons.camera_alt), +// SizedBox( +// width: 10, +// ), +// Text('Use Camera'), +// ], +// ), +// ), +// const SizedBox( +// width: 20, +// ), +// ElevatedButton( +// style: ButtonStyle( +// backgroundColor: MaterialStateProperty.all( +// theme.tertiaryContainer)), +// onPressed: () { +// imageController.pickImageFromGallery( +// setState, mounted, context); +// }, +// child: Row( +// children: [ +// Icon( +// Icons.photo_library, +// color: theme.onTertiaryContainer, +// ), +// const SizedBox( +// width: 10, +// ), +// Text( +// 'Use Gallery', +// style: TextStyle(color: theme.onTertiaryContainer), +// ), +// ], +// ), +// ), +// ], +// ), +// const SizedBox( +// height: 20, +// ), +// Lottie.asset("assets/images/loading/emoji_anim.json", +// controller: controller, width: 200), +// ], +// ), +// ]), +// ); +// } +// } diff --git a/lib/src/features/settings/check_update/data/update_service.dart b/lib/src/features/settings/check_update/data/update_service.dart new file mode 100644 index 0000000..13de16f --- /dev/null +++ b/lib/src/features/settings/check_update/data/update_service.dart @@ -0,0 +1,89 @@ +import 'dart:convert'; +import 'dart:io'; + +import 'package:device_info_plus/device_info_plus.dart'; +import 'package:hooks_riverpod/hooks_riverpod.dart'; + +import '../../../../constants/constants.dart'; +import '../../../get_recipes/domain/recipe/recipe.dart'; +import 'package:package_info_plus/package_info_plus.dart'; + +final updateServiceProvider = Provider((ref) => UpdateService(ref)); + +final getCurrentVersionProvider = FutureProvider((ref) async { + String version = await ref.watch(updateServiceProvider).getCurrentVersion(); + return version; +}); +final getDeviceHardwareProvider = FutureProvider>((ref) async { + List hardware = + await ref.watch(updateServiceProvider).getDeviceHardware(); + return hardware; +}); + +class UpdateService { + UpdateService(this.ref) : super(); + String currentVersion = ''; + String downloadUrl = ''; + String progress = "0.0"; + String? status; + final Ref ref; + + Future getCurrentVersion() async { + PackageInfo packageInfo = await PackageInfo.fromPlatform(); + currentVersion = await packageInfo.version; + return currentVersion; + } + + Future> getDeviceHardware() async { + final deviceInfo = DeviceInfoPlugin(); + if (Platform.isAndroid) { + var build = await deviceInfo.androidInfo; + return build.supportedAbis; + } + return []; + } + + Future isUpdated( + Function(Function()) setState, bool mounted, String hardwares) async { + final response = await client + .post(Uri.parse('$restAPIURL/update/'), body: {"hardware": hardwares}); + + PackageInfo packageInfo = await PackageInfo.fromPlatform(); + if (response.statusCode == 200) { + final data = json.decode(response.body); + if (mounted) { + setState(() { + currentVersion = packageInfo.version; + downloadUrl = data['download_url']; + }); + } + if (currentVersion == data['latest_version']) { + return true; + } + } else { + throw Exception('Failed to get updates'); + } + return false; + } + + // installUpdate(Function(Function()) setState, bool mounted) async { + // try { + // OtaUpdate() + // .execute( + // downloadUrl, + // destinationFilename: 'livine.apk', + // ) + // .listen((OtaEvent event) { + // if (mounted) { + // setState(() { + // progress = event.value.toString(); + // status = event.status.toString(); + // }); + // } + // print('EVENT: ${event.value} : ${event.status}'); + // }); + // } catch (e) { + // print('Failed to make OTA update. Details: $e'); + // } + // } +} diff --git a/lib/src/features/settings/check_update/update.dart b/lib/src/features/settings/check_update/update.dart new file mode 100644 index 0000000..46973cc --- /dev/null +++ b/lib/src/features/settings/check_update/update.dart @@ -0,0 +1,126 @@ +// import 'package:flutter/material.dart'; +// import 'package:hooks_riverpod/hooks_riverpod.dart'; + +// import '../../../common_widgets/auth/auth_widget.dart'; +// import '../../../common_widgets/no_connection.dart'; +// import '../../../shared/connectivity/check_network.dart'; +// import '../../../translations/domain/translation_provider.dart'; +// import 'data/update_service.dart'; + +// class CheckUpdate extends ConsumerStatefulWidget { +// const CheckUpdate({super.key}); + +// @override +// ConsumerState createState() => _CheckUpdateState(); +// } + +// class _CheckUpdateState extends ConsumerState { +// bool loading = false; + +// @override +// Widget build(BuildContext context) { +// final word = TranslationRepo.translate(context); +// String text = word?.check_for_update ?? "Check for update"; +// ConnectivityStatus network = ref.watch(checkNetworkProvider); + +// return Scaffold( +// body: network == ConnectivityStatus.On +// ? CustomScrollView( +// slivers: [ +// SliverAppBar.large( +// title: Text(word?.check_for_update ?? "Check for update"), +// ), +// SliverToBoxAdapter( +// child: Consumer( +// builder: (context, ref, child) { +// String percent = +// ref.watch(updateServiceProvider).progress; +// print(percent); +// return CircularPercentIndicator( +// percent: percent.isNotEmpty +// ? double.parse(percent) / 100 +// : 0.0, +// radius: 100, +// lineWidth: 2, +// backgroundColor: Colors.transparent, +// progressColor: +// Theme.of(context).colorScheme.onPrimaryContainer, +// center: Text("${percent}%"), +// ); +// }, +// ), +// ), +// SliverToBoxAdapter( +// child: Consumer( +// builder: (context, ref, child) { +// List hardware = +// ref.watch(getDeviceHardwareProvider).value ?? []; + +// return authButton( +// context: context, +// isLoading: loading, +// onPressed: () async { +// setState(() { +// loading = true; +// }); +// bool isUpdated = await ref +// .watch(updateServiceProvider) +// .isUpdated( +// setState, mounted, hardware.toString()); +// if (isUpdated) { +// setState(() { +// text = word?.no_update_available ?? +// "No update available"; +// loading = false; +// }); +// } else { +// setState(() { +// text = word?.installing_update ?? +// "Installing update"; +// loading = false; +// }); +// showDialog( +// context: context, +// builder: (context) { +// return AlertDialog( +// title: Text(word?.update_available ?? +// "Update Available"), +// content: Text(word?.do_install_update ?? +// "Do you want to install update?"), +// actions: [ +// TextButton( +// onPressed: () { +// Navigator.pop(context); +// }, +// child: Text( +// word?.cancel ?? "Cancel", +// style: TextStyle( +// color: Theme.of(context) +// .colorScheme +// .error)), +// ), +// TextButton( +// onPressed: () { +// Navigator.pop(context); +// // ref +// // .watch(updateServiceProvider) +// // .installUpdate( +// // setState, mounted); +// }, +// child: +// Text(word?.update ?? "Update"), +// ) +// ], +// ); +// }); +// } +// }, +// text: text); +// }, +// ), +// ), +// ], +// ) +// : NoConnection()); +// } +// } diff --git a/lib/src/features/settings/presentation/Misc/privacy.dart b/lib/src/features/settings/presentation/Misc/privacy.dart index ce9848d..03a4820 100644 --- a/lib/src/features/settings/presentation/Misc/privacy.dart +++ b/lib/src/features/settings/presentation/Misc/privacy.dart @@ -1,222 +1,224 @@ -import 'package:easy_localization/easy_localization.dart'; import 'package:flutter/material.dart'; import 'package:flutter_html/flutter_html.dart'; - -import '../../../../translations/locale_keys.g.dart'; +import 'package:hooks_riverpod/hooks_riverpod.dart'; +import 'package:livine/src/translations/domain/translation_provider.dart'; class Privacy extends StatelessWidget { const Privacy({Key? key}) : super(key: key); @override Widget build(BuildContext context) { + final word = TranslationRepo.translate(context); return Scaffold( - appBar: AppBar( - title: Text(LocaleKeys.Privacy_Policy.tr()), - ), - body: ListView( - children: [ - Html( - data: context.locale.languageCode == "en" - ? """ -Privacy Policy

- Mazen Omar built the Livine app as - an Open Source app. This SERVICE is provided by - Mazen Omar at no cost and is intended for use as - is. -

- This page is used to inform visitors regarding my - policies with the collection, use, and disclosure of Personal - Information if anyone decided to use my Service. -

- If you choose to use my Service, then you agree to - the collection and use of information in relation to this - policy. The Personal Information that I collect is - used for providing and improving the Service. I will not use or share your information with - anyone except as described in this Privacy Policy. -

- The terms used in this Privacy Policy have the same meanings - as in our Terms and Conditions, which are accessible at - Livine unless otherwise defined in this Privacy Policy. -

Information Collection and Use

- For a better experience, while using our Service, I - may require you to provide us with certain personally - identifiable information, including but not limited to timezone email. The information that - I request will be retained on your device and is not collected by me in any way. -

- The app does use third-party services that may collect - information used to identify you. -

- Link to the privacy policy of third-party service providers used - by the app -

Log Data

- I want to inform you that whenever you - use my Service, in a case of an error in the app - I collect data and information (through third-party - products) on your phone called Log Data. This Log Data may - include information such as your device Internet Protocol - (“IP”) address, device name, operating system version, the - configuration of the app when utilizing my Service, - the time and date of your use of the Service, and other - statistics. -

Cookies

- Cookies are files with a small amount of data that are - commonly used as anonymous unique identifiers. These are sent - to your browser from the websites that you visit and are - stored on your device's internal memory. -

- This Service does not use these “cookies” explicitly. However, - the app may use third-party code and libraries that use - “cookies” to collect information and improve their services. - You have the option to either accept or refuse these cookies - and know when a cookie is being sent to your device. If you - choose to refuse our cookies, you may not be able to use some - portions of this Service. -

Service Providers

- I may employ third-party companies and - individuals due to the following reasons: -

  • To facilitate our Service;
  • To provide the Service on our behalf;
  • To perform Service-related services; or
  • To assist us in analyzing how our Service is used.

- I want to inform users of this Service - that these third parties have access to their Personal - Information. The reason is to perform the tasks assigned to - them on our behalf. However, they are obligated not to - disclose or use the information for any other purpose. -

Security

- I value your trust in providing us your - Personal Information, thus we are striving to use commercially - acceptable means of protecting it. But remember that no method - of transmission over the internet, or method of electronic - storage is 100% secure and reliable, and I cannot - guarantee its absolute security. -

Links to Other Sites

- This Service may contain links to other sites. If you click on - a third-party link, you will be directed to that site. Note - that these external sites are not operated by me. - Therefore, I strongly advise you to review the - Privacy Policy of these websites. I have - no control over and assume no responsibility for the content, - privacy policies, or practices of any third-party sites or - services. -

Children’s Privacy

- These Services do not address anyone under the age of 13. - I do not knowingly collect personally - identifiable information from children under 13 years of age. In the case - I discover that a child under 13 has provided - me with personal information, I immediately - delete this from our servers. If you are a parent or guardian - and you are aware that your child has provided us with - personal information, please contact me so that - I will be able to do the necessary actions. -

Changes to This Privacy Policy

- I may update our Privacy Policy from - time to time. Thus, you are advised to review this page - periodically for any changes. I will - notify you of any changes by posting the new Privacy Policy on - this page. -

This policy is effective as of 2022-02-13

Contact Us

- If you have any questions or suggestions about my - Privacy Policy, do not hesitate to contact me at mazenomar-@outlook.com. - - -""" - : """ -سياسة الخصوصية

-قام مازن عمر ببناء تطبيق Livine باسم - تطبيق مفتوح المصدر. هذه الخدمة مقدمة من - مازن عمر بدون تكلفة ومخصص للاستعمال بصفته - هو. -

-تستخدم هذه الصفحة لإعلام الزوار بخصوص بلدي - سياسات مع جمع واستخدام والكشف عن الشخصية - المعلومات إذا قرر أي شخص استخدام خدمتي. -

-إذا اخترت استخدام خدمتي ، فأنت توافق على ذلك - جمع واستخدام المعلومات المتعلقة بهذا - سياسات. المعلومات الشخصية التي أجمعها هي - تستخدم لتوفير وتحسين الخدمة. لن أستخدم أو أشارك معلوماتك مع - أي شخص باستثناء ما هو موضح في سياسة الخصوصية هذه. + body: CustomScrollView( + slivers: [ + SliverAppBar.large(title: Text(word?.privacy_Policy ?? "")), + SliverToBoxAdapter( + child: Consumer( + builder: (context, ref, child) => Html( + data: ref.watch(localeNotifierProvider).languageCode == "en" + ? """ + Privacy Policy

+ Mazen Omar built the Livine app as + an Open Source app. This SERVICE is provided by + Mazen Omar at no cost and is intended for use as + is. +

+ This page is used to inform visitors regarding my + policies with the collection, use, and disclosure of Personal + Information if anyone decided to use my Service. +

+ If you choose to use my Service, then you agree to + the collection and use of information in relation to this + policy. The Personal Information that I collect is + used for providing and improving the Service. I will not use or share your information with + anyone except as described in this Privacy Policy. +

+ The terms used in this Privacy Policy have the same meanings + as in our Terms and Conditions, which are accessible at + Livine unless otherwise defined in this Privacy Policy. +

Information Collection and Use

+ For a better experience, while using our Service, I + may require you to provide us with certain personally + identifiable information, including but not limited to timezone email. The information that + I request will be retained on your device and is not collected by me in any way. +

+ The app does use third-party services that may collect + information used to identify you.

-المصطلحات المستخدمة في سياسة الخصوصية هذه لها نفس المعاني - كما هو الحال في الشروط والأحكام الخاصة بنا ، والتي يمكن الوصول إليها على - Livine ما لم يتم تحديد خلاف ذلك في سياسة الخصوصية هذه. -

جمع المعلومات واستخدامها

-لتجربة أفضل أثناء استخدام خدمتنا ، أنا - قد يطلب منك تزويدنا ببعض بشكل شخصي - معلومات تحديد الهوية ، بما في ذلك على سبيل المثال لا الحصر البريد الإلكتروني للمنطقة الزمنية. المعلومات التي - أطلب سيتم الاحتفاظ به على جهازك ولن يتم جمعها من قبلي بأي شكل من الأشكال. -

-يستخدم التطبيق خدمات الجهات الخارجية التي قد تجمع - المعلومات المستخدمة لتحديد هويتك. -

-رابط لسياسة الخصوصية لمقدمي خدمات الطرف الثالث المستخدمة - بواسطة التطبيق -

تسجيل البيانات

-أريد أن أبلغكم بذلك في أي وقت - استخدام خدمتي ، في حالة حدوث خطأ في التطبيق - أقوم بجمع البيانات والمعلومات (من خلال جهة خارجية - products) على هاتفك يسمى Log Data. قد تكون بيانات السجل هذه - تتضمن معلومات مثل بروتوكول الإنترنت الخاص بجهازك - ("IP") ، واسم الجهاز ، وإصدار نظام التشغيل ، و - تكوين التطبيق عند استخدام خدمتي ، - وقت وتاريخ استخدامك للخدمة ، وغير ذلك - الإحصاء. -

بسكويت

-ملفات تعريف الارتباط هي ملفات تحتوي على كمية صغيرة من البيانات - يشيع استخدامها كمعرفات فريدة مجهولة. يتم إرسال هذه - إلى متصفحك من مواقع الويب التي تزورها وتتواجد بها - المخزنة على الذاكرة الداخلية لجهازك. + Link to the privacy policy of third-party service providers used + by the app +

Log Data

+ I want to inform you that whenever you + use my Service, in a case of an error in the app + I collect data and information (through third-party + products) on your phone called Log Data. This Log Data may + include information such as your device Internet Protocol + (“IP”) address, device name, operating system version, the + configuration of the app when utilizing my Service, + the time and date of your use of the Service, and other + statistics. +

Cookies

+ Cookies are files with a small amount of data that are + commonly used as anonymous unique identifiers. These are sent + to your browser from the websites that you visit and are + stored on your device's internal memory. +

+ This Service does not use these “cookies” explicitly. However, + the app may use third-party code and libraries that use + “cookies” to collect information and improve their services. + You have the option to either accept or refuse these cookies + and know when a cookie is being sent to your device. If you + choose to refuse our cookies, you may not be able to use some + portions of this Service. +

Service Providers

+ I may employ third-party companies and + individuals due to the following reasons: +

  • To facilitate our Service;
  • To provide the Service on our behalf;
  • To perform Service-related services; or
  • To assist us in analyzing how our Service is used.

+ I want to inform users of this Service + that these third parties have access to their Personal + Information. The reason is to perform the tasks assigned to + them on our behalf. However, they are obligated not to + disclose or use the information for any other purpose. +

Security

+ I value your trust in providing us your + Personal Information, thus we are striving to use commercially + acceptable means of protecting it. But remember that no method + of transmission over the internet, or method of electronic + storage is 100% secure and reliable, and I cannot + guarantee its absolute security. +

Links to Other Sites

+ This Service may contain links to other sites. If you click on + a third-party link, you will be directed to that site. Note + that these external sites are not operated by me. + Therefore, I strongly advise you to review the + Privacy Policy of these websites. I have + no control over and assume no responsibility for the content, + privacy policies, or practices of any third-party sites or + services. +

Children’s Privacy

+ These Services do not address anyone under the age of 13. + I do not knowingly collect personally + identifiable information from children under 13 years of age. In the case + I discover that a child under 13 has provided + me with personal information, I immediately + delete this from our servers. If you are a parent or guardian + and you are aware that your child has provided us with + personal information, please contact me so that + I will be able to do the necessary actions. +

Changes to This Privacy Policy

+ I may update our Privacy Policy from + time to time. Thus, you are advised to review this page + periodically for any changes. I will + notify you of any changes by posting the new Privacy Policy on + this page. +

This policy is effective as of 2022-02-13

Contact Us

+ If you have any questions or suggestions about my + Privacy Policy, do not hesitate to contact me at mazenomar-@outlook.com. + + + """ + : """ + سياسة الخصوصية

+ قام مازن عمر ببناء تطبيق Livine باسم + تطبيق مفتوح المصدر. هذه الخدمة مقدمة من + مازن عمر بدون تكلفة ومخصص للاستعمال بصفته + هو. +

+ تستخدم هذه الصفحة لإعلام الزوار بخصوص بلدي + سياسات مع جمع واستخدام والكشف عن الشخصية + المعلومات إذا قرر أي شخص استخدام خدمتي. +

+ إذا اخترت استخدام خدمتي ، فأنت توافق على ذلك + جمع واستخدام المعلومات المتعلقة بهذا + سياسات. المعلومات الشخصية التي أجمعها هي + تستخدم لتوفير وتحسين الخدمة. لن أستخدم أو أشارك معلوماتك مع + أي شخص باستثناء ما هو موضح في سياسة الخصوصية هذه. +

+ المصطلحات المستخدمة في سياسة الخصوصية هذه لها نفس المعاني + كما هو الحال في الشروط والأحكام الخاصة بنا ، والتي يمكن الوصول إليها على + Livine ما لم يتم تحديد خلاف ذلك في سياسة الخصوصية هذه. +

جمع المعلومات واستخدامها

+ لتجربة أفضل أثناء استخدام خدمتنا ، أنا + قد يطلب منك تزويدنا ببعض بشكل شخصي + معلومات تحديد الهوية ، بما في ذلك على سبيل المثال لا الحصر البريد الإلكتروني للمنطقة الزمنية. المعلومات التي + أطلب سيتم الاحتفاظ به على جهازك ولن يتم جمعها من قبلي بأي شكل من الأشكال. +

+ يستخدم التطبيق خدمات الجهات الخارجية التي قد تجمع + المعلومات المستخدمة لتحديد هويتك.

-لا تستخدم هذه الخدمة "ملفات تعريف الارتباط" بشكل صريح. لكن، - قد يستخدم التطبيق رموزًا ومكتبات تابعة لجهة خارجية تستخدم ملفات - "ملفات تعريف الارتباط" لجمع المعلومات وتحسين خدماتهم. - لديك خيار إما قبول أو رفض ملفات تعريف الارتباط هذه - ومعرفة متى يتم إرسال ملف تعريف الارتباط إلى جهازك. اذا أنت - اختر رفض ملفات تعريف الارتباط الخاصة بنا ، فقد لا تتمكن من استخدام بعضها - أجزاء من هذه الخدمة. -

مقدمي الخدمة

-يجوز لي توظيف شركات خارجية و - الأفراد للأسباب التالية: -

  • لتسهيل خدمتنا ؛
  • لتقديم الخدمة نيابة عنا ؛
  • لأداء الخدمات المتعلقة بالخدمة ؛ أو
  • لمساعدتنا في تحليل كيفية استخدام خدمتنا.

-أريد إبلاغ مستخدمي هذه الخدمة - أن هذه الأطراف الثالثة لديها حق الوصول إلى الشخصية الخاصة بهم - معلومة. السبب هو أداء المهام الموكلة إلى - نيابة عنا. ومع ذلك ، فهم ملزمون بعدم القيام بذلك - الكشف عن المعلومات أو استخدامها لأي غرض آخر. -

حماية

-أنا أقدر ثقتك في تزويدنا بك - المعلومات الشخصية ، وبالتالي فإننا نسعى جاهدين لاستخدامها تجاريًا - الوسائل المقبولة لحمايتها. لكن تذكر أنه لا توجد طريقة - الإرسال عبر الإنترنت ، أو طريقة إلكترونية - التخزين آمن وموثوق بنسبة 100٪ ، ولا يمكنني ذلك - تضمن أمنها المطلق. -

روابط لمواقع أخرى

-قد تحتوي هذه الخدمة على روابط لمواقع أخرى. إذا قمت بالنقر فوق - رابط جهة خارجية ، سيتم توجيهك إلى هذا الموقع. ملحوظة - أن هذه المواقع الخارجية لا يتم تشغيلها بواسطتي. - لذلك ، أنصحك بشدة بمراجعة ملف - سياسة الخصوصية لهذه المواقع. أملك - لا سيطرة ولا تتحمل أي مسؤولية عن المحتوى ، - سياسات الخصوصية ، أو ممارسات أي مواقع طرف ثالث أو - خدمات. -

خصوصية الأطفال

-لا تخاطب هذه الخدمات أي شخص يقل عمره عن 13 عامًا. - أنا لا أجمع عن قصد شخصيًا - معلومات تحديد الهوية من الأطفال دون سن 13 عامًا. في القضية - أكتشف أن طفلاً أقل من 13 عامًا قد قدم - أنا مع المعلومات الشخصية ، وأنا على الفور - احذف هذا من خوادمنا. إذا كنت أحد الوالدين أو الوصي - وأنت على علم بأن طفلك قد قدم لنا - المعلومات الشخصية ، يرجى الاتصال بي حتى - سأكون قادرًا على القيام بالإجراءات اللازمة. -

التغييرات على سياسة الخصوصية هذه

-يمكنني تحديث سياسة الخصوصية الخاصة بنا من - من وقت إلى آخر. وبالتالي ، ننصحك بمراجعة هذه الصفحة - بشكل دوري لأية تغييرات. أنا سوف - يخطرك بأي تغييرات عن طريق نشر سياسة الخصوصية الجديدة على - هذه الصفحة. -

هذه السياسة سارية اعتبارًا من 2022-02-13

اتصل بنا

-إذا كان لديك أي أسئلة أو اقتراحات حول بلدي - سياسة الخصوصية ، لا تتردد في الاتصال بي على mazenomar-@outlook.com. -""", + رابط لسياسة الخصوصية لمقدمي خدمات الطرف الثالث المستخدمة + بواسطة التطبيق +

تسجيل البيانات

+ أريد أن أبلغكم بذلك في أي وقت + استخدام خدمتي ، في حالة حدوث خطأ في التطبيق + أقوم بجمع البيانات والمعلومات (من خلال جهة خارجية + products) على هاتفك يسمى Log Data. قد تكون بيانات السجل هذه + تتضمن معلومات مثل بروتوكول الإنترنت الخاص بجهازك + ("IP") ، واسم الجهاز ، وإصدار نظام التشغيل ، و + تكوين التطبيق عند استخدام خدمتي ، + وقت وتاريخ استخدامك للخدمة ، وغير ذلك + الإحصاء. +

بسكويت

+ ملفات تعريف الارتباط هي ملفات تحتوي على كمية صغيرة من البيانات + يشيع استخدامها كمعرفات فريدة مجهولة. يتم إرسال هذه + إلى متصفحك من مواقع الويب التي تزورها وتتواجد بها + المخزنة على الذاكرة الداخلية لجهازك. +

+ لا تستخدم هذه الخدمة "ملفات تعريف الارتباط" بشكل صريح. لكن، + قد يستخدم التطبيق رموزًا ومكتبات تابعة لجهة خارجية تستخدم ملفات + "ملفات تعريف الارتباط" لجمع المعلومات وتحسين خدماتهم. + لديك خيار إما قبول أو رفض ملفات تعريف الارتباط هذه + ومعرفة متى يتم إرسال ملف تعريف الارتباط إلى جهازك. اذا أنت + اختر رفض ملفات تعريف الارتباط الخاصة بنا ، فقد لا تتمكن من استخدام بعضها + أجزاء من هذه الخدمة. +

مقدمي الخدمة

+ يجوز لي توظيف شركات خارجية و + الأفراد للأسباب التالية: +

  • لتسهيل خدمتنا ؛
  • لتقديم الخدمة نيابة عنا ؛
  • لأداء الخدمات المتعلقة بالخدمة ؛ أو
  • لمساعدتنا في تحليل كيفية استخدام خدمتنا.

+ أريد إبلاغ مستخدمي هذه الخدمة + أن هذه الأطراف الثالثة لديها حق الوصول إلى الشخصية الخاصة بهم + معلومة. السبب هو أداء المهام الموكلة إلى + نيابة عنا. ومع ذلك ، فهم ملزمون بعدم القيام بذلك + الكشف عن المعلومات أو استخدامها لأي غرض آخر. +

حماية

+ أنا أقدر ثقتك في تزويدنا بك + المعلومات الشخصية ، وبالتالي فإننا نسعى جاهدين لاستخدامها تجاريًا + الوسائل المقبولة لحمايتها. لكن تذكر أنه لا توجد طريقة + الإرسال عبر الإنترنت ، أو طريقة إلكترونية + التخزين آمن وموثوق بنسبة 100٪ ، ولا يمكنني ذلك + تضمن أمنها المطلق. +

روابط لمواقع أخرى

+ قد تحتوي هذه الخدمة على روابط لمواقع أخرى. إذا قمت بالنقر فوق + رابط جهة خارجية ، سيتم توجيهك إلى هذا الموقع. ملحوظة + أن هذه المواقع الخارجية لا يتم تشغيلها بواسطتي. + لذلك ، أنصحك بشدة بمراجعة ملف + سياسة الخصوصية لهذه المواقع. أملك + لا سيطرة ولا تتحمل أي مسؤولية عن المحتوى ، + سياسات الخصوصية ، أو ممارسات أي مواقع طرف ثالث أو + خدمات. +

خصوصية الأطفال

+ لا تخاطب هذه الخدمات أي شخص يقل عمره عن 13 عامًا. + أنا لا أجمع عن قصد شخصيًا + معلومات تحديد الهوية من الأطفال دون سن 13 عامًا. في القضية + أكتشف أن طفلاً أقل من 13 عامًا قد قدم + أنا مع المعلومات الشخصية ، وأنا على الفور + احذف هذا من خوادمنا. إذا كنت أحد الوالدين أو الوصي + وأنت على علم بأن طفلك قد قدم لنا + المعلومات الشخصية ، يرجى الاتصال بي حتى + سأكون قادرًا على القيام بالإجراءات اللازمة. +

التغييرات على سياسة الخصوصية هذه

+ يمكنني تحديث سياسة الخصوصية الخاصة بنا من + من وقت إلى آخر. وبالتالي ، ننصحك بمراجعة هذه الصفحة + بشكل دوري لأية تغييرات. أنا سوف + يخطرك بأي تغييرات عن طريق نشر سياسة الخصوصية الجديدة على + هذه الصفحة. +

هذه السياسة سارية اعتبارًا من 2022-02-13

اتصل بنا

+ إذا كان لديك أي أسئلة أو اقتراحات حول بلدي + سياسة الخصوصية ، لا تتردد في الاتصال بي على mazenomar-@outlook.com. + """, + ), + ), ), ], ), diff --git a/lib/src/features/settings/presentation/Misc/terms.dart b/lib/src/features/settings/presentation/Misc/terms.dart index c49ea07..7c4e962 100644 --- a/lib/src/features/settings/presentation/Misc/terms.dart +++ b/lib/src/features/settings/presentation/Misc/terms.dart @@ -1,229 +1,233 @@ -import 'package:easy_localization/easy_localization.dart'; import 'package:flutter/material.dart'; import 'package:flutter_html/flutter_html.dart'; +import 'package:hooks_riverpod/hooks_riverpod.dart'; -import '../../../../translations/locale_keys.g.dart'; +import '../../../../translations/domain/translation_provider.dart'; class Terms extends StatelessWidget { const Terms({Key? key}) : super(key: key); @override Widget build(BuildContext context) { + final word = TranslationRepo.translate(context); return Scaffold( - appBar: AppBar( - title: Text(LocaleKeys.Terms_and_conditions.tr()), - ), - body: ListView( - children: [ - Html( - data: context.locale.languageCode == "en" - ? """ -Terms & Conditions

- By downloading or using the app, these terms will - automatically apply to you – you should make sure therefore - that you read them carefully before using the app. You’re not - allowed to copy or modify the app, any part of the app, or - our trademarks in any way. You’re not allowed to attempt to - extract the source code of the app, and you also shouldn’t try - to translate the app into other languages or make derivative - versions. The app itself, and all the trademarks, copyright, - database rights, and other intellectual property rights related - to it, still belong to Mazen Omar. + body: CustomScrollView( + slivers: [ + SliverAppBar.large( + title: Text(word?.terms_and_conditions ?? ""), + ), + SliverToBoxAdapter( + child: Consumer( + builder: (context, ref, child) => Html( + data: ref.watch(localeNotifierProvider).languageCode == "en" + ? """ + Terms & Conditions

+ By downloading or using the app, these terms will + automatically apply to you – you should make sure therefore + that you read them carefully before using the app. You’re not + allowed to copy or modify the app, any part of the app, or + our trademarks in any way. You’re not allowed to attempt to + extract the source code of the app, and you also shouldn’t try + to translate the app into other languages or make derivative + versions. The app itself, and all the trademarks, copyright, + database rights, and other intellectual property rights related + to it, still belong to Mazen Omar. +

+ Mazen Omar is committed to ensuring that the app is + as useful and efficient as possible. For that reason, we + reserve the right to make changes to the app or to charge for + its services, at any time and for any reason. We will never + charge you for the app or its services without making it very + clear to you exactly what you’re paying for. +

+ The Livine app stores and processes personal data that + you have provided to us, to provide my + Service. It’s your responsibility to keep your phone and + access to the app secure. We therefore recommend that you do + not jailbreak or root your phone, which is the process of + removing software restrictions and limitations imposed by the + official operating system of your device. It could make your + phone vulnerable to malware/viruses/malicious programs, + compromise your phone’s security features and it could mean + that the Livine app won’t work properly or at all. +

+ The app does use third-party services that declare their + Terms and Conditions.

- Mazen Omar is committed to ensuring that the app is - as useful and efficient as possible. For that reason, we - reserve the right to make changes to the app or to charge for - its services, at any time and for any reason. We will never - charge you for the app or its services without making it very - clear to you exactly what you’re paying for. + Link to Terms and Conditions of third-party service + providers used by the app +

+ You should be aware that there are certain things that + Mazen Omar will not take responsibility for. Certain + functions of the app will require the app to have an active + internet connection. The connection can be Wi-Fi or provided + by your mobile network provider, but Mazen Omar + cannot take responsibility for the app not working at full + functionality if you don’t have access to Wi-Fi, and you don’t + have any of your data allowance left. +

+ If you’re using the app outside of an area with Wi-Fi, you + should remember that the terms of the agreement with your + mobile network provider will still apply. As a result, you may + be charged by your mobile provider for the cost of data for + the duration of the connection while accessing the app, or + other third-party charges. In using the app, you’re accepting + responsibility for any such charges, including roaming data + charges if you use the app outside of your home territory + (i.e. region or country) without turning off data roaming. If + you are not the bill payer for the device on which you’re + using the app, please be aware that we assume that you have + received permission from the bill payer for using the app. +

+ Along the same lines, Mazen Omar cannot always take + responsibility for the way you use the app i.e. You need to + make sure that your device stays charged – if it runs out of + battery and you can’t turn it on to avail the Service, + Mazen Omar cannot accept responsibility. +

+ With respect to Mazen Omar’s responsibility for your + use of the app, when you’re using the app, it’s important to + bear in mind that although we endeavor to ensure that it is + updated and correct at all times, we do rely on third parties + to provide information to us so that we can make it available + to you. Mazen Omar accepts no liability for any + loss, direct or indirect, you experience as a result of + relying wholly on this functionality of the app. +

+ At some point, we may wish to update the app. The app is + currently available on Android – the requirements for the + system(and for any additional systems we + decide to extend the availability of the app to) may change, + and you’ll need to download the updates if you want to keep + using the app. Mazen Omar does not promise that it + will always update the app so that it is relevant to you + and/or works with the Android version that you have + installed on your device. However, you promise to always + accept updates to the application when offered to you, We may + also wish to stop providing the app, and may terminate use of + it at any time without giving notice of termination to you. + Unless we tell you otherwise, upon any termination, (a) the + rights and licenses granted to you in these terms will end; + (b) you must stop using the app, and (if needed) delete it + from your device. +

Changes to This Terms and Conditions

+ I may update our Terms and Conditions + from time to time. Thus, you are advised to review this page + periodically for any changes. I will + notify you of any changes by posting the new Terms and + Conditions on this page. +

+ These terms and conditions are effective as of 2022-02-13 +

Contact Us

+ If you have any questions or suggestions about my + Terms and Conditions, do not hesitate to contact me + at mazenomar-@outlook.com. + """ + : """ + الشروط و الاحكام

+ عن طريق تنزيل التطبيق أو استخدامه ، ستفعل هذه الشروط + تنطبق تلقائيًا عليك - يجب عليك التأكد من ذلك + أنك قرأتها بعناية قبل استخدام التطبيق. أنت لست + يُسمح بنسخ التطبيق أو تعديله ، أو أي جزء من التطبيق ، أو + علاماتنا التجارية بأي شكل من الأشكال. لا يسمح لك بمحاولة + استخرج الكود المصدري للتطبيق ، ويجب ألا تحاول أيضًا + لترجمة التطبيق إلى لغات أخرى أو عمل اشتقاق + الإصدارات. التطبيق نفسه وجميع العلامات التجارية وحقوق التأليف والنشر ، + حقوق قاعدة البيانات ، وحقوق الملكية الفكرية الأخرى ذات الصلة + وما زالت تخص مازن عمر. +

+ مازن عمر ملتزم بضمان أن التطبيق يعمل + مفيدة وفعالة قدر الإمكان. لهذا السبب ، نحن + نحتفظ بالحق في إجراء تغييرات على التطبيق أو فرض رسوم عليه + خدماتها في أي وقت ولأي سبب. نحن لن + تحاسبك على التطبيق أو خدماته دون أن تجعله شديد الأهمية + واضحًا لك بالضبط ما تدفع مقابله. +

+ يخزن تطبيق Livine البيانات الشخصية ويعالجها + الذي قدمته إلينا ، لتقديم + خدمة. تقع على عاتقك مسؤولية الاحتفاظ بهاتفك و + الوصول إلى التطبيق آمن. لذلك نوصي أن تفعل + ليس كسر الحماية أو عمل روت لهاتفك ، وهي عملية + إزالة قيود البرامج والقيود التي يفرضها + نظام التشغيل الرسمي لجهازك. يمكن أن تجعل الخاص بك + الهاتف عرضة للبرامج الضارة / الفيروسات / البرامج الضارة ، + تعرض ميزات أمان هاتفك للخطر وقد يعني ذلك + أن تطبيق Livine لن يعمل بشكل صحيح أو لا يعمل على الإطلاق. +

+

- The Livine app stores and processes personal data that - you have provided to us, to provide my - Service. It’s your responsibility to keep your phone and - access to the app secure. We therefore recommend that you do - not jailbreak or root your phone, which is the process of - removing software restrictions and limitations imposed by the - official operating system of your device. It could make your - phone vulnerable to malware/viruses/malicious programs, - compromise your phone’s security features and it could mean - that the Livine app won’t work properly or at all. -

- The app does use third-party services that declare their - Terms and Conditions. -

- Link to Terms and Conditions of third-party service - providers used by the app -

- You should be aware that there are certain things that - Mazen Omar will not take responsibility for. Certain - functions of the app will require the app to have an active - internet connection. The connection can be Wi-Fi or provided - by your mobile network provider, but Mazen Omar - cannot take responsibility for the app not working at full - functionality if you don’t have access to Wi-Fi, and you don’t - have any of your data allowance left. -

- If you’re using the app outside of an area with Wi-Fi, you - should remember that the terms of the agreement with your - mobile network provider will still apply. As a result, you may - be charged by your mobile provider for the cost of data for - the duration of the connection while accessing the app, or - other third-party charges. In using the app, you’re accepting - responsibility for any such charges, including roaming data - charges if you use the app outside of your home territory - (i.e. region or country) without turning off data roaming. If - you are not the bill payer for the device on which you’re - using the app, please be aware that we assume that you have - received permission from the bill payer for using the app. -

- Along the same lines, Mazen Omar cannot always take - responsibility for the way you use the app i.e. You need to - make sure that your device stays charged – if it runs out of - battery and you can’t turn it on to avail the Service, - Mazen Omar cannot accept responsibility. -

- With respect to Mazen Omar’s responsibility for your - use of the app, when you’re using the app, it’s important to - bear in mind that although we endeavor to ensure that it is - updated and correct at all times, we do rely on third parties - to provide information to us so that we can make it available - to you. Mazen Omar accepts no liability for any - loss, direct or indirect, you experience as a result of - relying wholly on this functionality of the app. -

- At some point, we may wish to update the app. The app is - currently available on Android – the requirements for the - system(and for any additional systems we - decide to extend the availability of the app to) may change, - and you’ll need to download the updates if you want to keep - using the app. Mazen Omar does not promise that it - will always update the app so that it is relevant to you - and/or works with the Android version that you have - installed on your device. However, you promise to always - accept updates to the application when offered to you, We may - also wish to stop providing the app, and may terminate use of - it at any time without giving notice of termination to you. - Unless we tell you otherwise, upon any termination, (a) the - rights and licenses granted to you in these terms will end; - (b) you must stop using the app, and (if needed) delete it - from your device. -

Changes to This Terms and Conditions

- I may update our Terms and Conditions - from time to time. Thus, you are advised to review this page - periodically for any changes. I will - notify you of any changes by posting the new Terms and - Conditions on this page. -

- These terms and conditions are effective as of 2022-02-13 -

Contact Us

- If you have any questions or suggestions about my - Terms and Conditions, do not hesitate to contact me - at mazenomar-@outlook.com. -""" - : """ -الشروط و الاحكام

-عن طريق تنزيل التطبيق أو استخدامه ، ستفعل هذه الشروط - تنطبق تلقائيًا عليك - يجب عليك التأكد من ذلك - أنك قرأتها بعناية قبل استخدام التطبيق. أنت لست - يُسمح بنسخ التطبيق أو تعديله ، أو أي جزء من التطبيق ، أو - علاماتنا التجارية بأي شكل من الأشكال. لا يسمح لك بمحاولة - استخرج الكود المصدري للتطبيق ، ويجب ألا تحاول أيضًا - لترجمة التطبيق إلى لغات أخرى أو عمل اشتقاق - الإصدارات. التطبيق نفسه وجميع العلامات التجارية وحقوق التأليف والنشر ، - حقوق قاعدة البيانات ، وحقوق الملكية الفكرية الأخرى ذات الصلة - وما زالت تخص مازن عمر. -

-مازن عمر ملتزم بضمان أن التطبيق يعمل - مفيدة وفعالة قدر الإمكان. لهذا السبب ، نحن - نحتفظ بالحق في إجراء تغييرات على التطبيق أو فرض رسوم عليه - خدماتها في أي وقت ولأي سبب. نحن لن - تحاسبك على التطبيق أو خدماته دون أن تجعله شديد الأهمية - واضحًا لك بالضبط ما تدفع مقابله. -

-يخزن تطبيق Livine البيانات الشخصية ويعالجها - الذي قدمته إلينا ، لتقديم - خدمة. تقع على عاتقك مسؤولية الاحتفاظ بهاتفك و - الوصول إلى التطبيق آمن. لذلك نوصي أن تفعل - ليس كسر الحماية أو عمل روت لهاتفك ، وهي عملية - إزالة قيود البرامج والقيود التي يفرضها - نظام التشغيل الرسمي لجهازك. يمكن أن تجعل الخاص بك - الهاتف عرضة للبرامج الضارة / الفيروسات / البرامج الضارة ، - تعرض ميزات أمان هاتفك للخطر وقد يعني ذلك - أن تطبيق Livine لن يعمل بشكل صحيح أو لا يعمل على الإطلاق. -

-يجب أن تدرك أن هناك أشياء معينة - مازن عمر لن يتحمل المسؤولية. المؤكد - وظائف التطبيق ستتطلب أن يكون التطبيق نشطًا - اتصال بالإنترنت. يمكن أن يكون الاتصال Wi-Fi أو يتم توفيره - من قبل مزود شبكة المحمول الخاص بك ولكن مازن عمر - لا يمكن تحمل المسؤولية عن التطبيق لا يعمل بالكامل - وظائف إذا لم يكن لديك وصول إلى شبكة Wi-Fi ، ولم يكن لديك - هل لديك أي من البيانات المسموح بها متبقية. -

-إذا كنت تستخدم التطبيق خارج منطقة مزودة بشبكة Wi-Fi ، فأنت بذلك - يجب أن نتذكر أن شروط الاتفاقية مع الخاص بك - سيظل مزود شبكة الجوال ساريًا. نتيجة لذلك ، يمكنك - يتحملها مزود خدمة الهاتف المحمول الخاص بك مقابل تكلفة البيانات لـ - مدة الاتصال أثناء الوصول إلى التطبيق ، أو - رسوم الطرف الثالث الأخرى. باستخدام التطبيق ، فأنت تقبل - المسؤولية عن أي من هذه الرسوم ، بما في ذلك بيانات التجوال - الرسوم إذا كنت تستخدم التطبيق خارج منطقتك - (أي المنطقة أو الدولة) دون إيقاف تجوال البيانات. لو - لست دافع الفاتورة للجهاز الذي تستخدمه - باستخدام التطبيق ، يرجى العلم أننا نفترض أن لديك - الحصول على إذن من دافع الفاتورة لاستخدام التطبيق. -

-على نفس المنوال ، لا يستطيع مازن عمر أن يأخذها دائمًا - المسؤولية عن طريقة استخدامك للتطبيق ، أي أنك تحتاج إلى ذلك - تأكد من بقاء جهازك مشحونًا - إذا نفد منه - البطارية ولا يمكنك تشغيلها للاستفادة من الخدمة ، - مازن عمر لا يتحمل المسؤولية. -

-فيما يتعلق بمسؤولية مازن عمر تجاهك - استخدام التطبيق ، عند استخدام التطبيق ، من المهم أن - ضع في اعتبارك أنه على الرغم من أننا نسعى للتأكد من ذلك - محدثة وصحيحة في جميع الأوقات ، نحن نعتمد على أطراف ثالثة - لتزويدنا بالمعلومات حتى نتمكن من إتاحتها - لك. مازن عمر لا يتحمل أي مسؤولية عن أي شيء - الخسارة ، المباشرة أو غير المباشرة ، التي تتعرض لها نتيجة - بالاعتماد كليًا على وظيفة التطبيق هذه. -

-في مرحلة ما ، قد نرغب في تحديث التطبيق. التطبيق - متوفر حاليًا على Android - متطلبات - نظام (وأي أنظمة إضافية نحن - قرر تمديد توفر التطبيق لـ) قد يتغير ، - وستحتاج إلى تنزيل التحديثات إذا كنت تريد الاحتفاظ بها - باستخدام التطبيق. مازن عمر لا يعد بذلك - ستعمل دائمًا على تحديث التطبيق بحيث يكون مناسبًا لك - و / أو يعمل مع إصدار Android الذي تستخدمه - مثبتة على جهازك. ومع ذلك ، فإنك تعد دائمًا - يجوز لنا قبول التحديثات على التطبيق عند عرضها عليك - ترغب أيضًا في التوقف عن توفير التطبيق ، وقد تنهي استخدام - في أي وقت دون إشعار الإنهاء لك. - ما لم نخبرك بخلاف ذلك ، عند أي إنهاء ، (أ) - تنتهي الحقوق والتراخيص الممنوحة لك بموجب هذه الشروط ؛ - (ب) يجب عليك التوقف عن استخدام التطبيق ، و (إذا لزم الأمر) حذفه - من جهازك. -

- التغييرات على هذه الشروط والأحكام

-قد أقوم بتحديث الشروط والأحكام الخاصة بنا - من وقت لآخر. وبالتالي ، ننصحك بمراجعة هذه الصفحة - بشكل دوري لأية تغييرات. أنا سوف - يخطرك بأي تغييرات عن طريق نشر الشروط الجديدة و - الشروط في هذه الصفحة. -

-تسري هذه الشروط والأحكام اعتبارًا من 2022-02-13

-

اتصل بنا

-إذا كان لديك أي أسئلة أو اقتراحات حول بلدي - الشروط والأحكام ، لا تتردد في الاتصال بي - في mazenomar-@outlook.com. -""", +

+ يجب أن تدرك أن هناك أشياء معينة + مازن عمر لن يتحمل المسؤولية. المؤكد + وظائف التطبيق ستتطلب أن يكون التطبيق نشطًا + اتصال بالإنترنت. يمكن أن يكون الاتصال Wi-Fi أو يتم توفيره + من قبل مزود شبكة المحمول الخاص بك ولكن مازن عمر + لا يمكن تحمل المسؤولية عن التطبيق لا يعمل بالكامل + وظائف إذا لم يكن لديك وصول إلى شبكة Wi-Fi ، ولم يكن لديك + هل لديك أي من البيانات المسموح بها متبقية. +

+ إذا كنت تستخدم التطبيق خارج منطقة مزودة بشبكة Wi-Fi ، فأنت بذلك + يجب أن نتذكر أن شروط الاتفاقية مع الخاص بك + سيظل مزود شبكة الجوال ساريًا. نتيجة لذلك ، يمكنك + يتحملها مزود خدمة الهاتف المحمول الخاص بك مقابل تكلفة البيانات لـ + مدة الاتصال أثناء الوصول إلى التطبيق ، أو + رسوم الطرف الثالث الأخرى. باستخدام التطبيق ، فأنت تقبل + المسؤولية عن أي من هذه الرسوم ، بما في ذلك بيانات التجوال + الرسوم إذا كنت تستخدم التطبيق خارج منطقتك + (أي المنطقة أو الدولة) دون إيقاف تجوال البيانات. لو + لست دافع الفاتورة للجهاز الذي تستخدمه + باستخدام التطبيق ، يرجى العلم أننا نفترض أن لديك + الحصول على إذن من دافع الفاتورة لاستخدام التطبيق. +

+ على نفس المنوال ، لا يستطيع مازن عمر أن يأخذها دائمًا + المسؤولية عن طريقة استخدامك للتطبيق ، أي أنك تحتاج إلى ذلك + تأكد من بقاء جهازك مشحونًا - إذا نفد منه + البطارية ولا يمكنك تشغيلها للاستفادة من الخدمة ، + مازن عمر لا يتحمل المسؤولية. +

+ فيما يتعلق بمسؤولية مازن عمر تجاهك + استخدام التطبيق ، عند استخدام التطبيق ، من المهم أن + ضع في اعتبارك أنه على الرغم من أننا نسعى للتأكد من ذلك + محدثة وصحيحة في جميع الأوقات ، نحن نعتمد على أطراف ثالثة + لتزويدنا بالمعلومات حتى نتمكن من إتاحتها + لك. مازن عمر لا يتحمل أي مسؤولية عن أي شيء + الخسارة ، المباشرة أو غير المباشرة ، التي تتعرض لها نتيجة + بالاعتماد كليًا على وظيفة التطبيق هذه. +

+ في مرحلة ما ، قد نرغب في تحديث التطبيق. التطبيق + متوفر حاليًا على Android - متطلبات + نظام (وأي أنظمة إضافية نحن + قرر تمديد توفر التطبيق لـ) قد يتغير ، + وستحتاج إلى تنزيل التحديثات إذا كنت تريد الاحتفاظ بها + باستخدام التطبيق. مازن عمر لا يعد بذلك + ستعمل دائمًا على تحديث التطبيق بحيث يكون مناسبًا لك + و / أو يعمل مع إصدار Android الذي تستخدمه + مثبتة على جهازك. ومع ذلك ، فإنك تعد دائمًا + يجوز لنا قبول التحديثات على التطبيق عند عرضها عليك + ترغب أيضًا في التوقف عن توفير التطبيق ، وقد تنهي استخدام + في أي وقت دون إشعار الإنهاء لك. + ما لم نخبرك بخلاف ذلك ، عند أي إنهاء ، (أ) + تنتهي الحقوق والتراخيص الممنوحة لك بموجب هذه الشروط ؛ + (ب) يجب عليك التوقف عن استخدام التطبيق ، و (إذا لزم الأمر) حذفه + من جهازك. +

+ التغييرات على هذه الشروط والأحكام

+ قد أقوم بتحديث الشروط والأحكام الخاصة بنا + من وقت لآخر. وبالتالي ، ننصحك بمراجعة هذه الصفحة + بشكل دوري لأية تغييرات. أنا سوف + يخطرك بأي تغييرات عن طريق نشر الشروط الجديدة و + الشروط في هذه الصفحة. +

+ تسري هذه الشروط والأحكام اعتبارًا من 2022-02-13

+

اتصل بنا

+ إذا كان لديك أي أسئلة أو اقتراحات حول بلدي + الشروط والأحكام ، لا تتردد في الاتصال بي + في mazenomar-@outlook.com. + """, + ), ), - ], - ), - ); + ) + ], + )); } } diff --git a/lib/src/features/settings/presentation/accessibility/accessibility.dart b/lib/src/features/settings/presentation/accessibility/accessibility.dart new file mode 100644 index 0000000..c7c21f7 --- /dev/null +++ b/lib/src/features/settings/presentation/accessibility/accessibility.dart @@ -0,0 +1,37 @@ +import 'package:flutter/material.dart'; +import 'package:hooks_riverpod/hooks_riverpod.dart'; + +import '../../../../translations/domain/translation_provider.dart'; +import '../../../navigation/data/navigation_notifier.dart'; + +class Accessibility extends ConsumerWidget { + const Accessibility({super.key}); + + @override + Widget build(BuildContext context, WidgetRef ref) { + final swipeNavigation = ref.watch(navigationNotifierProvider); + bool isSwipeNavigation = swipeNavigation == null ? true : false; + final word = TranslationRepo.translate(context); + return Scaffold( + body: CustomScrollView( + slivers: [ + SliverAppBar.large( + title: Text(word!.accessibility), + ), + SliverToBoxAdapter( + child: ListTile( + title: Text(word.swipe_screen), + trailing: Switch.adaptive( + value: isSwipeNavigation, + onChanged: (value) { + ref + .read(navigationNotifierProvider.notifier) + .togglePhysics(value); + }), + ), + ), + ], + ), + ); + } +} diff --git a/lib/src/features/settings/presentation/languages/languages.dart b/lib/src/features/settings/presentation/languages/languages.dart index 4dce877..b81d9ca 100644 --- a/lib/src/features/settings/presentation/languages/languages.dart +++ b/lib/src/features/settings/presentation/languages/languages.dart @@ -1,30 +1,38 @@ import 'package:flutter/material.dart'; -import 'package:easy_localization/easy_localization.dart'; +import 'package:hooks_riverpod/hooks_riverpod.dart'; -import '../../../../translations/locale_keys.g.dart'; +import '../../../../translations/domain/translation_provider.dart'; -class Languages extends StatelessWidget { +class Languages extends ConsumerWidget { const Languages({Key? key}) : super(key: key); @override - Widget build(BuildContext context) { + Widget build(BuildContext context, WidgetRef ref) { + final word = TranslationRepo.translate(context); return Scaffold( - appBar: AppBar( - title: Text(LocaleKeys.Language.tr()), - ), - body: Column(children: const [ - LanguageCode( - name: "English", - langCode: "en", - textAlign: Alignment.topLeft, - ), - LanguageCode( - name: "العربية", - langCode: "ar", - textAlign: Alignment.topRight, + body: CustomScrollView( + slivers: [ + SliverAppBar.large( + title: Text(word?.languages ?? ""), ), - ]), - ); + SliverToBoxAdapter( + child: Column( + children: [ + LanguageCode( + name: "English", + locale: Locale("en"), + textAlign: Alignment.topLeft, + ), + LanguageCode( + name: "العربية", + locale: Locale("ar"), + textAlign: Alignment.topRight, + ), + ], + ), + ) + ], + )); } } @@ -32,26 +40,32 @@ class LanguageCode extends StatelessWidget { const LanguageCode({ Key? key, required this.name, - required this.langCode, + required this.locale, required this.textAlign, }) : super(key: key); - final String name, langCode; + final String name; + final Locale locale; final AlignmentGeometry textAlign; + @override Widget build(BuildContext context) { - return InkWell( - onTap: () async { - await context.setLocale(Locale(langCode)); + return Consumer( + builder: (context, ref, child) { + return InkWell( + onTap: () async { + await ref.read(localeNotifierProvider.notifier).setLocale(locale); + }, + child: Padding( + padding: const EdgeInsets.all(25.0), + child: Align( + alignment: textAlign, + child: Text( + name, + style: const TextStyle(fontSize: 18.0), + ), + )), + ); }, - child: Padding( - padding: const EdgeInsets.all(25.0), - child: Align( - alignment: textAlign, - child: Text( - name, - style: const TextStyle(fontSize: 18.0), - ), - )), ); } } diff --git a/lib/src/features/settings/presentation/notifications/notifications_settings_view.dart b/lib/src/features/settings/presentation/notifications/notifications_settings_view.dart index 12f0c83..117a386 100644 --- a/lib/src/features/settings/presentation/notifications/notifications_settings_view.dart +++ b/lib/src/features/settings/presentation/notifications/notifications_settings_view.dart @@ -1,9 +1,8 @@ -import 'package:easy_localization/easy_localization.dart'; import 'package:flutter/material.dart'; -import '../../../../shared/notifications/health_notification.dart'; import '../../../../constants/constants.dart'; -import '../../../../translations/locale_keys.g.dart'; +import '../../../../shared/notifications/health_notification.dart'; +import '../../../../translations/domain/translation_provider.dart'; class NotificationsSettings extends StatefulWidget { const NotificationsSettings({Key? key}) : super(key: key); @@ -17,19 +16,21 @@ class _NotificationsSettingsState extends State { @override Widget build(BuildContext context) { + final word = TranslationRepo.translate(context); return Scaffold( - appBar: AppBar( - title: Text(LocaleKeys.notfications.tr()), - ), - body: Column(children: [ - Padding( - padding: const EdgeInsets.all(20.0), - child: Row( + body: CustomScrollView( + slivers: [ + SliverAppBar.large( + title: Text(word?.notfications ?? "Notifications"), + ), + SliverToBoxAdapter( + child: // Padding( + Row( mainAxisAlignment: MainAxisAlignment.spaceAround, children: [ SizedBox( width: 200, - child: Text(LocaleKeys.ask_me_how_i_feel.tr(), + child: Text(word?.ask_me_how_i_feel ?? "Ask me how I feel", style: const TextStyle(fontSize: 18.0))), Switch( value: isNotified, @@ -39,7 +40,8 @@ class _NotificationsSettingsState extends State { }); if (!value) { - notificationControl.flutterLocalNotificationsPlugin.cancel(0); + notificationControl.flutterLocalNotificationsPlugin + .cancel(0); } else { showNotification(); } @@ -47,7 +49,7 @@ class _NotificationsSettingsState extends State { ], ), ) - ]), - ); + ], + )); } } diff --git a/lib/src/features/settings/presentation/settings.dart b/lib/src/features/settings/presentation/settings.dart index 9f45252..288ae5f 100644 --- a/lib/src/features/settings/presentation/settings.dart +++ b/lib/src/features/settings/presentation/settings.dart @@ -2,22 +2,23 @@ import 'dart:developer'; -import 'package:easy_localization/easy_localization.dart'; import 'package:flutter/material.dart'; import 'package:go_router/go_router.dart'; -import 'package:iconsax/iconsax.dart'; +import 'package:hooks_riverpod/hooks_riverpod.dart'; +import 'package:livine/src/translations/domain/translation_provider.dart'; import 'package:url_launcher/url_launcher.dart'; -import '../../../translations/locale_keys.g.dart'; +import 'settings_model.dart'; -class SettingsWidget extends StatefulWidget { +class SettingsWidget extends ConsumerStatefulWidget { const SettingsWidget({Key? key}) : super(key: key); @override - State createState() => _SettingsWidgetState(); + ConsumerState createState() => _SettingsWidgetState(); } -class _SettingsWidgetState extends State { +class _SettingsWidgetState extends ConsumerState { + late BuildContext context; Future sendReport() async { final Uri emailLaunchUri = Uri( scheme: 'mailto', @@ -34,147 +35,86 @@ class _SettingsWidgetState extends State { @override Widget build(BuildContext context) { - return Scaffold( - appBar: AppBar( - title: Text(LocaleKeys.Settings.tr()), + final word = TranslationRepo.translate(context); + List menus = [ + Settings( + title: word?.languages ?? '', + icon: Icons.language_outlined, + route: "/languages", + subtitle: word?.change_language ?? '', ), - body: SingleChildScrollView( - child: Column( - children: [ - Padding( - padding: const EdgeInsets.all(10.0), - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - SettingsGroup( - text: LocaleKeys.General.tr(), - ), - const SizedBox( - height: 10.0, - ), - Column( - children: [ - InkWell( - onTap: () => context.push('/languages'), - child: SettingsTile( - text: LocaleKeys.Language.tr(), - subtitle: context.locale.languageCode == "en" - ? "English " - : "العربية", - icon: Iconsax.language_square, - ), - ), - const SizedBox( - height: 15.0, - ), - InkWell( - onTap: () => context.push("/notifications_settings"), - child: SettingsTile( - text: LocaleKeys.notfications.tr(), - subtitle: '', - icon: Iconsax.notification, - ), - ), - ], - ), - const SizedBox( - height: 10.0, - ), - const Divider(), - SettingsGroup(text: LocaleKeys.Theme.tr()), - const SizedBox( - height: 10.0, - ), - InkWell( - onTap: () => context.push('/themeSettings'), - child: SettingsTile( - text: LocaleKeys.Theme.tr(), - subtitle: '', - icon: Iconsax.moon), - ), - const SizedBox( - height: 10.0, - ), - const Divider(), - SettingsGroup(text: LocaleKeys.Feedback.tr()), - const SizedBox( - height: 10.0, - ), - InkWell( - onTap: sendReport, - child: SettingsTile( - text: LocaleKeys.Report_a_bug.tr(), - subtitle: '', - icon: Iconsax.ghost, - ), - ), - const SizedBox( - height: 10.0, - ), - const Divider(), - SettingsGroup(text: LocaleKeys.Misc.tr()), - const SizedBox( - height: 10.0, - ), - InkWell( - onTap: () => context.push('/terms'), - child: SettingsTile( - text: LocaleKeys.Terms_and_conditions.tr(), - subtitle: '', - icon: Iconsax.message_text_1, - ), - ), - const SizedBox( - height: 10.0, - ), - InkWell( - onTap: () => context.push('/privacy'), - child: SettingsTile( - text: LocaleKeys.Privacy_Policy.tr(), - subtitle: '', - icon: Iconsax.shield_tick), - ), - const SizedBox( - height: 10.0, - ), - const Divider(), - const SizedBox( - height: 10.0, - ), - AboutApp(), - ], - ), - ), - ], - ), + Settings( + title: word!.accessibility, + icon: Icons.accessibility_outlined, + route: "/accessibility", + subtitle: word.change_use, ), - ); - } -} - -class AboutApp extends StatelessWidget { - const AboutApp({ - Key? key, - }) : super(key: key); - - @override - Widget build(BuildContext context) { - return InkWell( - onTap: () => showAboutDialog( - context: context, - applicationName: context.locale.languageCode =="en" ? "Livine" : "ليفين", - applicationVersion: "8.5.0", - applicationLegalese: "© 2021 Livine", - applicationIcon: Image.asset( - "assets/images/icon/app_icon.png", - width: 50, - )), - child: SettingsTile( - text: context.locale.languageCode =="en" ? "About Livine" : "عن ليفين", - subtitle: '', - icon: Iconsax.info_circle, + Settings( + title: word.notfications, + icon: Icons.notifications_outlined, + route: "/notifications_settings", + subtitle: word.change_notification, ), - ); + Settings( + title: word.theme, + icon: Icons.palette_outlined, + route: "/themeSettings", + subtitle: word.change_theme, + ), + Settings( + title: word.report_a_bug, + icon: Icons.bug_report_outlined, + route: "/bug_report", + subtitle: word.help_us, + ), + Settings( + title: word.terms_and_conditions, + icon: Icons.sticky_note_2_outlined, + route: "/terms", + subtitle: "", + ), + Settings( + title: word.privacy_Policy, + icon: Icons.policy_outlined, + route: "/privacy", + subtitle: "", + ), + Settings( + title: word.version, + icon: Icons.info_outline, + route: "", + subtitle: "9.0.0"), + ]; + + return Scaffold( + body: CustomScrollView( + slivers: [ + SliverAppBar.large( + title: Text(word.settings), + pinned: true, + ), + SliverList( + delegate: SliverChildBuilderDelegate( + (context, index) { + return InkWell( + onTap: () { + if (menus[index].route != '/bug_report') { + context.push(menus[index].route); + } else { + sendReport(); + } + }, + child: ListTile( + leading: Icon(menus[index].icon), + title: Text(menus[index].title), + subtitle: Text(menus[index].subtitle), + ), + ); + }, + childCount: menus.length, + )) + ], + )); } } @@ -226,23 +166,4 @@ class SettingsTile extends StatelessWidget { } } -class SettingsGroup extends StatelessWidget { - const SettingsGroup({ - Key? key, - required this.text, - }) : super(key: key); - final text; - @override - Widget build(BuildContext context) { - return Text( - '$text', - // style: GoogleFonts.bebasNeue( - // fontSize: 15.0, - // color: Colors.blueAccent, - // letterSpacing: 3, - // ), - style: const TextStyle(fontSize: 17.0), - ); - } -} diff --git a/lib/src/features/settings/presentation/settings_model.dart b/lib/src/features/settings/presentation/settings_model.dart new file mode 100644 index 0000000..6f42485 --- /dev/null +++ b/lib/src/features/settings/presentation/settings_model.dart @@ -0,0 +1,16 @@ +import 'package:flutter/material.dart'; + +class Settings { + String title; + String subtitle; + IconData icon; + String route; + + Settings({ + required this.title, + required this.icon, + required this.route, + required this.subtitle, + + }); +} diff --git a/lib/src/features/settings/presentation/theme/data/colors_type.dart b/lib/src/features/settings/presentation/theme/data/colors_type.dart new file mode 100644 index 0000000..c1960bf --- /dev/null +++ b/lib/src/features/settings/presentation/theme/data/colors_type.dart @@ -0,0 +1,12 @@ +import 'package:flutter/material.dart'; + +class ColorTypes { + String type; + String subtitle; + Color color; + ColorTypes({ + required this.type, + required this.color, + required this.subtitle, + }); +} diff --git a/lib/src/features/settings/presentation/theme/domain/theme_notifier.dart b/lib/src/features/settings/presentation/theme/domain/theme_notifier.dart new file mode 100644 index 0000000..8fd668a --- /dev/null +++ b/lib/src/features/settings/presentation/theme/domain/theme_notifier.dart @@ -0,0 +1,40 @@ +import 'package:flutter/material.dart'; +import 'package:hooks_riverpod/hooks_riverpod.dart'; +import 'package:livine/src/shared/cache/cache_helper.dart'; +import 'package:livine/src/shared/device_info/device_info.dart'; + +final themeSeedProvider = StateNotifierProvider((ref) => ThemeSeedNotifier()); + +final dynamicThemeProvider = + StateNotifierProvider((ref) => DynamicThemeNotifier()); + +class ThemeSeedNotifier extends StateNotifier { + ThemeSeedNotifier() : super(_getInitialColor()); + + static Color _getInitialColor() { + int userColor = CacheHelper.getInt('userColor') ?? Colors.green.value; + return Color(userColor); + } + + void setTheme(Color color) { + state = color; + CacheHelper.setInt("userColor", color.value); + } +} + +class DynamicThemeNotifier extends StateNotifier { + DynamicThemeNotifier() : super(_initialCheckDynamic()); + + static bool _initialCheckDynamic() { + if (!GetDeviceInfo.isAndroid12Above()) { + return false; + } + bool isDynamic = CacheHelper.getBool('isDynamic') ?? true; + return isDynamic; + } + + void toggleDynamic(bool isDynamic) { + state = isDynamic; + CacheHelper.setBool("isDynamic", isDynamic); + } +} diff --git a/lib/src/features/settings/presentation/theme/theme_settings.dart b/lib/src/features/settings/presentation/theme/theme_settings.dart index 51f6d9b..6b00be4 100644 --- a/lib/src/features/settings/presentation/theme/theme_settings.dart +++ b/lib/src/features/settings/presentation/theme/theme_settings.dart @@ -1,94 +1,225 @@ -import 'package:easy_localization/easy_localization.dart'; - +import 'package:custom_sliding_segmented_control/custom_sliding_segmented_control.dart'; +import 'package:dynamic_color/dynamic_color.dart'; import 'package:flutter/material.dart'; -import 'package:flutter_riverpod/flutter_riverpod.dart'; -import 'package:iconsax/iconsax.dart'; +import 'package:flutter_hooks/flutter_hooks.dart'; +import 'package:gradient_borders/box_borders/gradient_box_border.dart'; +import 'package:hooks_riverpod/hooks_riverpod.dart'; +import 'package:livine/src/features/settings/presentation/theme/data/colors_type.dart'; +import 'package:livine/src/shared/device_info/device_info.dart'; -import '../../../../translations/locale_keys.g.dart'; +import '../../../../translations/domain/translation_provider.dart'; import '../../data/theme.dart'; +import 'domain/theme_notifier.dart'; -class ThemeSettings extends StatelessWidget { +class ThemeSettings extends HookWidget { const ThemeSettings({Key? key}) : super(key: key); + int getInitialSegment(ThemeMode themeMode) { + if (themeMode == ThemeMode.light) { + return 0; + } else if (themeMode == ThemeMode.dark) { + return 1; + } else { + return 2; + } + } + @override Widget build(BuildContext context) { + final word = TranslationRepo.translate(context); + List colors = [ + Color(0xFF4CAF50), + Color(0xFF2196F3), + Color(0xFF3F51B5), + Color(0xFF9C27B0), + Color(0xFFF44336), + Color(0xFFFFC107), + ]; + List colorTypes = [ + ColorTypes( + type: word?.primary_color ?? "", + color: Theme.of(context).colorScheme.primary, + subtitle: word?.primary_color_hint ?? + "Primary color is used for the app bar and the selected tab indicator."), + ColorTypes( + type: word?.secondary_color ?? "", + color: Theme.of(context).colorScheme.secondary, + subtitle: word?.secondary_color_hint ?? + "Secondary color is used for the floating action button and the selected tab indicator."), + ColorTypes( + type: word?.tertiary_color ?? "", + color: Theme.of(context).colorScheme.tertiary, + subtitle: word?.teritary_color_hint ?? ""), + ]; + return Scaffold( - appBar: AppBar( - title: Text(LocaleKeys.Theme.tr()), - ), - body: Padding( - padding: const EdgeInsets.all(8.0), - child: Column( - children: [ - Consumer( - builder: (context, ref, child) { - final theme = ref.watch(themeProvider); - return Row( - mainAxisAlignment: MainAxisAlignment.spaceEvenly, - children: [ - Text( - LocaleKeys.System_Prefrence.tr(), - style: const TextStyle(fontSize: 18.0), + body: CustomScrollView( + slivers: [ + SliverAppBar.large( + title: Text(word?.theme ?? "Theme"), + ), + SliverToBoxAdapter( + child: Consumer( + builder: (context, ref, child) { + final theme = ref.read(themeProvider).themeMode; + return Center( + child: CustomSlidingSegmentedControl( + decoration: BoxDecoration( + color: Theme.of(context).colorScheme.secondaryContainer, + borderRadius: BorderRadius.circular(100), + ), + thumbDecoration: BoxDecoration( + color: Theme.of(context).colorScheme.surface, + borderRadius: BorderRadius.circular(100), + ), + height: 55, + fixedWidth: 100, + padding: 25, + curve: Curves.easeInOut, + initialValue: getInitialSegment(theme), + children: { + 0: Text( + word?.light ?? "Light", ), - Switch( - value: theme.themeMode == ThemeMode.system || false, - onChanged: (value) { - ref.read(themeProvider).setSystem(); - }, - ) - ], - ); - }, + 1: Text( + word?.dark ?? "Dark", + ), + 2: Text( + word?.system ?? "System", + ), + }, + onValueChanged: (value) { + if (value == 0) { + ref.read(themeProvider).setLight(); + } else if (value == 1) { + ref.read(themeProvider).setDark(); + } else { + ref.read(themeProvider).setSystem(); + } + }, + ), + ); + }, + ), + ), + SliverToBoxAdapter( + child: Padding( + padding: const EdgeInsets.symmetric(vertical: 15), + child: Consumer( + builder: (context, ref, child) { + final isDynamic = ref.watch(dynamicThemeProvider); + return SwitchListTile( + title: Text(word?.dynamic_theme ?? ""), + value: isDynamic == true, + onChanged: !GetDeviceInfo.isAndroid12Above() + ? null + : (v) => ref + .watch(dynamicThemeProvider.notifier) + .toggleDynamic(v), + subtitle: Text(word?.dynamic_theme_hint ?? ""), + isThreeLine: true, + ); + }, + ), + )), + SliverToBoxAdapter( + child: Padding( + padding: const EdgeInsets.all(10.0), + child: Container( + height: 100, + child: ListView.separated( + itemCount: colors.length, + scrollDirection: Axis.horizontal, + itemBuilder: (context, index) => ThemeChoice( + color: colors[index], + ), + separatorBuilder: (context, index) => SizedBox( + width: 10, + )), ), - Consumer( - builder: (context, ref, child) { - final theme = ref.watch(themeProvider); + ), + ), + SliverList( + delegate: SliverChildBuilderDelegate( + childCount: colorTypes.length, + (context, index) => Padding( + padding: const EdgeInsets.only(top: 10, bottom: 10), + child: ListTile( + title: Text(colorTypes[index].type), + subtitle: Text(colorTypes[index].subtitle), + trailing: Container( + width: 50, + height: 50, + decoration: BoxDecoration( + color: colorTypes[index].color, shape: BoxShape.circle), + ), + ), + ), + )), + ], + )); + } +} - return Row( - mainAxisAlignment: MainAxisAlignment.spaceEvenly, - children: [ - const Icon(Iconsax.sun_1), - Text( - LocaleKeys.Light_Mode.tr(), - style: const TextStyle(fontSize: 18.0), - ), - Switch( - value: theme.themeMode == ThemeMode.light || false, - onChanged: (value) { - if (!value) { - ref.read(themeProvider).setSystem(); - } else { - ref.read(themeProvider).setLight(); - } - }, - ) - ], - ); - }, +class ThemeChoice extends StatelessWidget { + const ThemeChoice({super.key, required this.color}); + final Color color; + @override + Widget build(BuildContext context) { + return Consumer( + builder: (context, ref, child) { + bool isSelected = color == ref.watch(themeSeedProvider); + final isDynamic = ref.watch(dynamicThemeProvider); + return Container( + width: 100, + decoration: BoxDecoration( + color: isDynamic == true + ? Theme.of(context).colorScheme.primary.withOpacity(0.5) + : color.withOpacity(0.5), + borderRadius: BorderRadius.circular(20), + ), + child: IconButton( + splashRadius: 20.0, + style: ButtonStyle( + overlayColor: MaterialStateProperty.all(Colors.transparent), + backgroundColor: MaterialStateProperty.all(Colors.transparent), ), - Consumer( - builder: (context, ref, child) => Row( - mainAxisAlignment: MainAxisAlignment.spaceEvenly, - children: [ - const Icon(Iconsax.moon), - Text(LocaleKeys.Dark_Mode.tr(), - style: const TextStyle(fontSize: 18.0)), - Switch( - value: Theme.of(context).brightness == Brightness.dark, - onChanged: (value) { - if (!value) { - ref.read(themeProvider).setSystem(); - } else { - ref.read(themeProvider).setDark(); - } - }, - ) - ], + isSelected: isDynamic == true ? false : isSelected, + selectedIcon: + Icon(Icons.check_circle_rounded, color: color, size: 60), + onPressed: isDynamic == true + ? null + : () { + ref.read(themeSeedProvider.notifier).setTheme(color); + }, + icon: Container( + decoration: BoxDecoration( + border: GradientBoxBorder( + gradient: LinearGradient(colors: [ + isDynamic == true + ? Theme.of(context) + .colorScheme + .primary + .withOpacity(0.5) + : color, + isDynamic == true + ? Theme.of(context) + .colorScheme + .primary + .withOpacity(0.5) + : color.harmonizeWith(Colors.cyanAccent) + ]), + width: 15), + borderRadius: BorderRadius.circular(100), ), - ) - ], - ), - ), + child: CircleAvatar( + radius: 25, + backgroundColor: Colors.transparent, + ), + ), + ), + ); + }, ); } } diff --git a/lib/src/l10n/app_ar.arb b/lib/src/l10n/app_ar.arb new file mode 100644 index 0000000..7514d7d --- /dev/null +++ b/lib/src/l10n/app_ar.arb @@ -0,0 +1,124 @@ +{ + "welcome": "اهلا بك،", + "settings": "الاعدادات", + "logout": "تسجيل الخروج", + "profile": "الحساب الشخصي", + "languages": "اللغات", + "theme": "الوضع", + "feedback": "إبلاغ", + "report_a_bug": "إبلاغ عن مشكلة ", + "misc": "متفرقات", + "terms_and_conditions": "الأحكام والشروط", + "privacy_Policy": "سياسة الخصوصية", + "info": "عن البرنامج", + "version": "النسخة", + "language": "اللغة", + "general": "عام", + "breakfast": "الفطار", + "dinner": "العشاء", + "lunch": "الغذاء", + "snacks": "وجبات خفيفة", + "ingridents": "المكونات", + "watch_video": "مشاهدة فيديو", + "shakshuka": "شكشوكة", + "crustless_Quiche": "كيشي بدون قشرة", + "burrito": "بوريتو", + "baked_Oatmeal": "شوفان مشوي", + "apple_Cinnamon_Oat": "التفاح بالقرفة والشوفان", + "banana_Bread": "خبر بالموز", + "waffles": "بسكويتات الوفل", + "wild_Mushroom_Risotto": "ريزوتو بالفطر ", + "grilled_Steak_Tortilla_Salad": "سلطة تورتيلا ستيك مشوي", + "feta_Shrimp_and_Polenta": "روبيان فيتا وبولينتا", + "black_Bean_Soup": "شربة فول", + "bass_With_Radish_Salsa": "باس مع صلصة الفجل", + "eggplant_Parmesan": "بارما الباذنجان", + "roasted_Cauliflower_Tacos": "قرنبيط محمص تاكو", + "carrot_with_Radish_Salad": "سلطة جزر بالفجل", + "salmon_Salad": "سلطة سلمون", + "panzanella": "بانزانيلا", + "caesar_Salad": "سلطة سيزر", + "mixed_Nuts": "مكسرات مشكله", + "red_pepper_guacamole": "الفلفل الأحمر جواكامولي", + "yogurt_with_mixed_berries": "زبادي مع توت مشكل", + "apple_slices_with_peanut": "شرائح التفاح مع الفول السوداني", + "cottage_cheese": "جبن", + "celery_sticks_with_Cheese": "أعواد الكرفس بالجبن", + "system": "النظام", + "light": "الضوء", + "dark": "المظلم", + "life_pristine": "اجعل حياتك نقية", + "pristine_access": "يمنحك النظام الوصول إلى ميزاتنا باهظة الثمن بالكامل", + "gateway": "اختار طريقة الدفع", + "three_months": "3شهور", + "total_price": "السعر الكلي", + "monthly": "شهريا", + "cancel_sub": "يمكنك إلغاء اشتراكك في أي وقت من خلال google pay", + "choose_content": "اختار المحتوي", + "iam_a": "انا", + "healthy": "تريد أن تحصل على وصفات صحية بجانب المكونات ومقاطع الفيديو", + "patient": "تريد أن تحصل علي وصفات علي حسب حالتك الصحية مع مكونات و مقاطع الفيديو", + "username": "اسم المستخدم", + "password": "كلمة السر", + "forget_your_password": "نسيت كلمة المرور ؟", + "sign_in": "تسجيل الدخول", + "no_account": "ليس لديك حساب ؟", + "sign_up": "سجل الآن", + "have_an_account": "هل لديك حساب ؟", + "terms1": "من خلال إنشاء حساب ، فإنك توافق بالفعل على", + "terms2": "الأحكام والشروط", + "notfications": "إشعارات", + "ask_me_how_i_feel": "اسالني كيف اشعر كل يوم", + "continue_as_guest": "سجل كضيف", + "change_password": "تغيير كلمة المرور", + "enter_token": "أدخل الرمز الخاص بك", + "validate_token": "التحقق من صحة الرمز", + "reset_pass": "إعادة تعيين كلمة المرور", + "pass_confirm": "تأكيد كلمة المرور", + "per_situation": "حالة معينة", + "favorites": "المفضلة", + "delete_account": "حذف الحساب", + "account": "الحساب", + "update": "تحديث", + "installing_update":"جاري تنزيل التحديث", + "no_update_available":"لا يوجد تحديث", + "update_available":"يوجد تحديث", + "do_install_update":"هل تريد تثبيت التحديث?", + "livine": "ليفين", + "about_Livine": "عن ليفين", + "sure_to_logout": "هل أنت تريد تسجيل الخروج ؟", + "cancel" : "إلغاء", + "delete" : "حذف", + "sure_to_delete" : "هل أنت تريد حذف هذا الحساب ؟", + "live_naturally": "هيا نعيش بشكل طبيعي بدون اي تدخل كيميائي", + "get_started": "ابدأ", + "check_for_update": "فحص التحديثات", + "home":"الرئيسية", + "meals":"وجبات", + "change_language":"تغيير اللغة", + "change_notification":"تغيير الإشعارات", + "change_theme":"تغيير السمة و الالوان ", + "help_us":"ساعدنا علي تحسين التطبيق", + "choose":"اختر", + "email_address":"البريد الاكتروني", + "code":"الرمز", + "enter_token_has_sent":"ادخل الرمز الذي تم ارساله الي البريد الاكتروني الخاص بك", + "dynamic_theme":"الوضع الديناميكي", + "dynamic_theme_hint":"سيؤدي هذا الي تغير لون البرنامج علي لون خلفية الجهاز, هذة الخصية متاحة فقط من اندرويد 12 او اعلي, عندما تكون مفعلة, لا تستطيع اختيار اللون", + "primary_color":"اللون الاساسي", + "secondary_color": "اللون الثاني", + "tertiary_color":"اللون الثالث", + "primary_color_hint":"يُستخدم اللون الأساسي للشريط وخلفية شريط التطبيقات العلوي بالتطبيق.", + "secondary_color_hint":"يتم استخدام اللون الثاني لبعض أجزاء واجهة المستخدم التي تحتاج إلى التميز ، مثل أشرطة التمرير أو المفاتيح أو أشرطة التقدم.", + "teritary_color_hint":"يتم استخدام اللون الثلاثي لخلفية الحقول النصية المحددة ونص مؤشرات التقدم.", + "points":"نقاط", + "start_cooking":"ابدا بالطهي", + "step":"خطوة", + "step_of":"من", + "edit_profile":"تعديل الحساب", + "vegetarian":"نباتي", + "accessibility":"إمكانية الوصول", + "change_use":"غير طريقة استخدامك لليفين", + "swipe_screen":"اسحب الشاشة" + +} \ No newline at end of file diff --git a/lib/src/l10n/app_en.arb b/lib/src/l10n/app_en.arb new file mode 100644 index 0000000..80cf60b --- /dev/null +++ b/lib/src/l10n/app_en.arb @@ -0,0 +1,126 @@ +{ + "welcome": "Welcome,", + "settings": "Settings", + "logout": "Logout", + "profile": "Profile", + "languages": "Languages", + "theme": "Theme", + "feedback": "Feedback", + "report_a_bug": "Report a bug ", + "misc": "Misc", + "terms_and_conditions": "Terms and Conditions", + "privacy_Policy": "Privacy Policy", + "info": "Info", + "version": "Version", + "language": "Language", + "general": "General", + "breakfast": "Breakfast", + "dinner": "Dinner", + "lunch": "Lunch", + "snacks": "Snacks", + "ingridents": "Ingridents", + "watch_video": "Watch video", + "shakshuka": "Shakshuka", + "crustless_Quiche": "Crustless Quiche", + "burrito": "Burrito", + "baked_Oatmeal": "Baked Oatmeal", + "apple_Cinnamon_Oat": "Apple Cinnamon Oat", + "banana_Bread": "Banana Bread", + "waffles": "Waffles", + "wild_Mushroom_Risotto": "Wild Mushroom Risotto", + "grilled_Steak_Tortilla_Salad": "Grilled Steak Tortilla Salad", + "feta_Shrimp_and_Polenta": "Feta Shrimp and Polenta", + "black_Bean_Soup": "Black Bean Soup", + "bass_With_Radish_Salsa": "Bass With Radish Salsa", + "eggplant_Parmesan": "Eggplant Parmesan", + "roasted_Cauliflower_Tacos": "Roasted Cauliflower Tacos", + "carrot_with_Radish_Salad": "Carrot with Radish Salad", + "caesar_Salad": "Caesar Salad", + "salmon_Salad": "Salmon Salad", + "panzanella": "Panzanella", + "mixed_Nuts": "Mixed Nuts", + "red_pepper_guacamole": "Red pepper guacamole", + "yogurt_with_mixed_berries": "Yogurt with mixed berries", + "apple_slices_with_peanut": "Apple slices with peanut", + "cottage_cheese": "Cottage cheese", + "celery_sticks_with_Cheese": "Celery sticks with Cheese", + "system": "System", + "light": "Light", + "dark": "Dark", + "life_pristine": "Make your life Pristine", + "pristine_access": "Pristine give u access to our full expensive features", + "gateway": "Choose Gateway", + "three_months": "3 months", + "total_price": "total price", + "monthly": "Monthly", + "cancel_sub": "You can cancel your subscription at any time through google pay", + "choose_content": "Choose your content", + "iam_a": "I'm a", + "healthy": "You want to be provided by healthy recipes that you should consume to remain healthy", + "patient": "You want to be provided per your health situation", + "username": "Username", + "password": "Password", + "forget_your_password": "Forget your password ?", + "sign_in": "Sign In", + "no_account": "Don't Have an account ?", + "sign_up": "Sign Up", + "have_an_account": "Already have an account ?", + "terms1": "By creating an account , you already agree on", + "terms2": "Terms and Conditions", + "notfications": "Notfications", + "ask_me_how_i_feel": "Ask me how I feel everyday", + "continue_as_guest": "Continue as GUEST", + "change_password": "Change your password", + "enter_token": "Enter Your Code", + "validate_token": "Validate Code", + "reset_pass": "Reset password", + "pass_confirm": "Password Confirmation", + "per_situation": "Per Situation", + "favorites": "Favorites", + "delete_account": "Delete account", + "account": "Account", + "update": "Update", + "installing_update":"Installing Update", + "no_update_available":"No update available", + "update_available":"Update Available", + "do_install_update":"Do you want to install the update?", + "livine": "Livine", + "about_Livine": "About Livine", + "sure_to_logout": "Are you sure you want to logout ?", + "cancel" : "Cancel", + "delete" : "Delete", + "sure_to_delete" : "Are you sure you want to delete your account ?", + "live_naturally": "Let's live naturally without any type of medications", + "get_started": "Get Started", + "check_for_update": "Check for update", + "home":"Home", + "meals":"Meals", + "change_language":"Change language", + "change_notification":"Change notification settings", + "change_theme":"Change theme, colors and more", + "help_us":"Help us improve our app", + "choose":"Choose", + "email_address":"Email Address", + "code":"code", + "enter_token_has_sent":"Enter the token that has been sent to your email", + "dynamic_theme":"Dynamic Theme", + "dynamic_theme_hint":"This will change the theme based on your wallpaper, it's available only on Android 12+, when it's on you can't change the theme manually", + "primary_color":"Primary Color", + "secondary_color": "Secondary Color", + "tertiary_color":"Teritary Color", + "primary_color_hint":"Primary color is used for the bar and the background of the app's top app bar.", + "secondary_color_hint":"Secondary color is used for some part of UI that need to stand out, such as sliders, switches, or progress bars.", + "teritary_color_hint":"Tertiary color is used for the background of selected text fields and the text of progress indicators.", + "points":"Points", + "start_cooking":"Start cooking", + "step":"Step", + "step_of":"of", + "edit_profile":"Edit profile", + "vegetarian":"Vegetarian", + "accessibility":"Accessibility", + "change_use":"Change how you use Livine", + "swipe_screen":"Swipe Screen" + + + +} \ No newline at end of file diff --git a/lib/src/routing/routes.dart b/lib/src/routing/routes.dart index 2c65bd9..ab127de 100644 --- a/lib/src/routing/routes.dart +++ b/lib/src/routing/routes.dart @@ -1,5 +1,8 @@ +import 'package:flutter/material.dart'; import 'package:go_router/go_router.dart'; import 'package:livine/src/features/auth/welcome/presentation/welcome.dart'; +import 'package:livine/src/features/cooking/presentation/cooking.dart'; +import 'package:livine/src/features/settings/presentation/accessibility/accessibility.dart'; import '../common_widgets/recipe/web_view_widget.dart'; import '../constants/shared_constants.dart'; @@ -17,7 +20,6 @@ import '../features/meals/presentation/categories.dart'; import '../features/navigation/presentation/base.dart'; import '../features/onboarding/presentation/boarding.dart'; import '../features/premium_pristine/presentation/confirm_payment.dart'; -import '../features/scan_food/presentation/scan.dart'; import '../features/settings/presentation/Misc/privacy.dart'; import '../features/settings/presentation/Misc/terms.dart'; import '../features/settings/presentation/languages/languages.dart'; @@ -45,10 +47,10 @@ final baseRoutes = GoRouter(routes: [ name: "Login", builder: (context, state) => const Login(), ), - GoRoute( - path: '/scan', - builder: (context, state) => const Scan(), - ), + // GoRoute( + // path: '/scan', + // builder: (context, state) => const Scan(), + // ), GoRoute( path: '/navigate', builder: (context, state) => const Navigation(), @@ -91,7 +93,7 @@ final baseRoutes = GoRouter(routes: [ ), GoRoute( path: '/themeSettings', - builder: (context, state) => const ThemeSettings(), + builder: (context, state) => ThemeSettings(), ), GoRoute( path: '/notifications_settings', @@ -119,8 +121,16 @@ final baseRoutes = GoRouter(routes: [ GoRoute( name: "Update Profile", path: '/update_profile', - builder: (context, state) { - return const UpdateProfile(); + pageBuilder: (context, state) { + return CustomTransitionPage( + child: UpdateProfile(), + transitionsBuilder: (context, animation, secondaryAnimation, child) { + return FadeTransition( + opacity: + CurveTween(curve: Curves.easeInOutCirc).animate(animation), + child: child, + ); + }); }, ), GoRoute( @@ -157,4 +167,18 @@ final baseRoutes = GoRouter(routes: [ return const Favorites(); }, ), + GoRoute( + path: '/cooking', + builder: (context, state) { + return Cooking( + data: state.extra, + ); + }, + ), + GoRoute( + path: '/accessibility', + builder: (context, state) { + return const Accessibility(); + }, + ), ]); diff --git a/lib/src/shared/ads/ads_help.dart b/lib/src/shared/ads/ads_help.dart deleted file mode 100644 index 356c593..0000000 --- a/lib/src/shared/ads/ads_help.dart +++ /dev/null @@ -1,32 +0,0 @@ -import 'dart:io'; - -import 'package:google_mobile_ads/google_mobile_ads.dart'; - -class AdHelper { - static String get nativeadunit { - if (Platform.isAndroid) { - return "ca-app-pub-1056698201610872/1548122447"; - } else { - throw UnsupportedError("Unsupported platform"); - } - } - - bool isnativeBannerAdLoaded = false; - - late BannerAd nativeAdBanner; - - void nativeBannerFunction(void Function(void Function()) setState) { - nativeAdBanner = BannerAd( - adUnitId: AdHelper.nativeadunit, - size: AdSize.mediumRectangle, - request: const AdRequest(), - listener: BannerAdListener(onAdLoaded: (_) { - setState(() { - isnativeBannerAdLoaded = true; - }); - }, onAdFailedToLoad: (ad, error) { - ad.dispose(); - })); - nativeAdBanner.load(); - } -} diff --git a/lib/src/shared/children/children.dart b/lib/src/shared/children/children.dart index a957aa6..ce42418 100644 --- a/lib/src/shared/children/children.dart +++ b/lib/src/shared/children/children.dart @@ -9,7 +9,6 @@ final List children = [ const Home(), const Patient(), const Profile(), - const SettingsWidget() ]; final List tabletChildren = [ diff --git a/lib/src/shared/connectivity/check_network.dart b/lib/src/shared/connectivity/check_network.dart index 80f3a2f..413939f 100644 --- a/lib/src/shared/connectivity/check_network.dart +++ b/lib/src/shared/connectivity/check_network.dart @@ -24,6 +24,9 @@ class CheckNetworkNotifier extends StateNotifier { case ConnectivityResult.vpn: newState = ConnectivityStatus.Off; break; + case ConnectivityResult.other: + newState = ConnectivityStatus.Unknown; + break; } if (mounted) { if (newState != state) { diff --git a/lib/src/shared/device_info/device_info.dart b/lib/src/shared/device_info/device_info.dart index 0c70dd2..a7c34e6 100644 --- a/lib/src/shared/device_info/device_info.dart +++ b/lib/src/shared/device_info/device_info.dart @@ -37,7 +37,7 @@ class GetDeviceInfo { return null; } - static String? deviceBrand() { + static String? deviceBrand() { if (Platform.isAndroid) { return androidInfo?.brand; } else if (Platform.isWindows) { @@ -45,4 +45,12 @@ class GetDeviceInfo { } return null; } + + static bool isAndroid12Above() { + if (Platform.isAndroid) { + print("SDK ${deviceSDK()}"); + return deviceSDK() != null && int.parse(deviceSDK()!) >= 31; + } + return false; + } } diff --git a/lib/src/shared/notifications/health_notification.dart b/lib/src/shared/notifications/health_notification.dart index 7f52ef0..c395107 100644 --- a/lib/src/shared/notifications/health_notification.dart +++ b/lib/src/shared/notifications/health_notification.dart @@ -1,13 +1,11 @@ // ignore_for_file: depend_on_referenced_packages import 'package:flutter_local_notifications/flutter_local_notifications.dart'; -import 'package:flutter_native_timezone/flutter_native_timezone.dart'; import 'package:timezone/data/latest.dart' as tz; import 'package:timezone/timezone.dart' as tz; import '../../constants/constants.dart'; - tz.TZDateTime _nextInstanceOfTenAM() { final tz.TZDateTime now = tz.TZDateTime.now(tz.local); tz.TZDateTime scheduledDate = @@ -20,9 +18,6 @@ tz.TZDateTime _nextInstanceOfTenAM() { Future showNotification() async { tz.initializeTimeZones(); - final String dtz = await FlutterNativeTimezone.getLocalTimezone(); - final localTimeZone = tz.getLocation(dtz); - tz.setLocalLocation(localTimeZone); const AndroidNotificationDetails androidDetails = AndroidNotificationDetails( 'channelId', 'Livine ', @@ -37,7 +32,6 @@ Future showNotification() async { 'Your health is our top priority ', _nextInstanceOfTenAM(), generalNotDetails, - androidAllowWhileIdle: true, uiLocalNotificationDateInterpretation: UILocalNotificationDateInterpretation.absoluteTime, matchDateTimeComponents: DateTimeComponents.time, diff --git a/lib/src/shared/responsive/responsive_controller.dart b/lib/src/shared/responsive/responsive_controller.dart index 3668865..ecd5e1f 100644 --- a/lib/src/shared/responsive/responsive_controller.dart +++ b/lib/src/shared/responsive/responsive_controller.dart @@ -1,5 +1,6 @@ import 'package:flutter/material.dart'; -import 'package:responsive_framework/responsive_wrapper.dart'; +import 'package:livine/src/constants/constants.dart'; +import 'package:responsive_framework/responsive_breakpoints.dart'; class ResponsiveHelper { double deviceWidth(BuildContext context) => MediaQuery.of(context).size.width; @@ -8,30 +9,35 @@ class ResponsiveHelper { MediaQuery.of(context).size.height; bool largerThanMobile(BuildContext context) => - ResponsiveWrapper.of(context).isLargerThan(MOBILE); + ResponsiveBreakpoints.of(context).largerThan(MOBILE); - bool isMobile(BuildContext context) => ResponsiveWrapper.of(context).isMobile; + bool isMobile(BuildContext context) => + ResponsiveBreakpoints.of(context).isMobile; + + // is not mobile + bool isTablet(BuildContext context) => + ResponsiveBreakpoints.of(context).isTablet; bool deviceLandScape(BuildContext context) => - ResponsiveWrapper.of(context).orientation == Orientation.landscape; + ResponsiveBreakpoints.of(context).orientation == Orientation.landscape; bool devicePortrait(BuildContext context) => - ResponsiveWrapper.of(context).orientation == Orientation.portrait; + ResponsiveBreakpoints.of(context).orientation == Orientation.portrait; int responsiveRecipes(BuildContext context) { - if (ResponsiveWrapper.of(context).isTablet && - ResponsiveWrapper.of(context).orientation == Orientation.portrait) { + if (ResponsiveBreakpoints.of(context).isTablet && + ResponsiveBreakpoints.of(context).orientation == Orientation.portrait) { return 4; - } else if (ResponsiveWrapper.of(context).orientation == + } else if (ResponsiveBreakpoints.of(context).orientation == Orientation.landscape && - ResponsiveWrapper.of(context).isTablet) { + ResponsiveBreakpoints.of(context).isTablet) { return 6; - } else if (ResponsiveWrapper.of(context).isMobile && - ResponsiveWrapper.of(context).orientation == Orientation.portrait) { + } else if (ResponsiveBreakpoints.of(context).isMobile && + ResponsiveBreakpoints.of(context).orientation == Orientation.portrait) { return 2; - } else if (ResponsiveWrapper.of(context).isDesktop) { + } else if (ResponsiveBreakpoints.of(context).isDesktop) { return 5; - } else if (ResponsiveWrapper.of(context).orientation == + } else if (ResponsiveBreakpoints.of(context).orientation == Orientation.landscape) { return 4; } @@ -40,42 +46,34 @@ class ResponsiveHelper { } int responsiveCatogeries(BuildContext context) { - if (ResponsiveWrapper.of(context).isTablet && - ResponsiveWrapper.of(context).orientation == Orientation.portrait) { - return 2; - } else if (ResponsiveWrapper.of(context).orientation == - Orientation.landscape && - ResponsiveWrapper.of(context).isDesktop) { - return 4; + if (rh.deviceLandScape(context)) { + return 3; } - - if (ResponsiveWrapper.of(context).isMobile) { - if (ResponsiveWrapper.of(context).orientation == Orientation.portrait) { - return 1; - } else { - return 2; - } + if (ResponsiveBreakpoints.of(context).equals(TABLET) || + rh.deviceWidth(context) > 500) { + return 3; } return 1; } int responsiveMeals(BuildContext context) { - if (ResponsiveWrapper.of(context).isTablet && - ResponsiveWrapper.of(context).orientation == Orientation.portrait) { + if (ResponsiveBreakpoints.of(context).isTablet && + ResponsiveBreakpoints.of(context).orientation == Orientation.portrait) { return 2; - } else if (ResponsiveWrapper.of(context).orientation == + } else if (ResponsiveBreakpoints.of(context).orientation == Orientation.landscape && - ResponsiveWrapper.of(context).isDesktop) { + ResponsiveBreakpoints.of(context).isDesktop) { return 6; } - if (ResponsiveWrapper.of(context).isMobile) { - if (ResponsiveWrapper.of(context).orientation == Orientation.portrait) { - return 1; - } else { + if (ResponsiveBreakpoints.of(context).isMobile) { + if (ResponsiveBreakpoints.of(context).orientation == + Orientation.portrait) { return 2; + } else { + return 1; } } - return 2; + return 4; } } diff --git a/lib/src/shared/styles/colors.dart b/lib/src/shared/styles/colors.dart index 35644cc..ce1ad82 100644 --- a/lib/src/shared/styles/colors.dart +++ b/lib/src/shared/styles/colors.dart @@ -1,17 +1,12 @@ // ignore_for_file: use_full_hex_values_for_flutter_colors +import 'package:dynamic_color/dynamic_color.dart'; import 'package:flutter/material.dart'; +import 'package:livine/src/shared/styles/lib_color_schemes.g.dart'; +ColorScheme lightHarmonizedColorScheme = lightColorScheme.harmonized(); +ColorScheme darkHarmonizedColorScheme = darkColorScheme.harmonized(); - const primaryColor = Color(0xfff80ed99); - - const secondaryColor = Color(0xfff38a3a5); - - const thirdColor = Color(0xfff22577a); - - const fourthColor = Color(0xFF57CC99); - - const fifthColor = Color(0xfffc7f9cc); diff --git a/lib/src/shared/windows/title_bar.dart b/lib/src/shared/windows/title_bar.dart index 8f9aeff..55a0765 100644 --- a/lib/src/shared/windows/title_bar.dart +++ b/lib/src/shared/windows/title_bar.dart @@ -61,7 +61,7 @@ class AppThemeBuilderState extends State void _updateThemeMode([bool inital = false]) { ThemeMode themeMode = widget.themeMode; if (themeMode == ThemeMode.system) { - themeMode = _binding.window.platformBrightness == Brightness.dark // + themeMode = true == Brightness.dark // ? ThemeMode.dark : ThemeMode.light; } diff --git a/lib/src/translations/codegen_loader.g.dart b/lib/src/translations/codegen_loader.g.dart deleted file mode 100644 index d16923b..0000000 --- a/lib/src/translations/codegen_loader.g.dart +++ /dev/null @@ -1,194 +0,0 @@ -// DO NOT EDIT. This is code generated via package:easy_localization/generate.dart - -// ignore_for_file: prefer_single_quotes - -import 'dart:ui'; - -import 'package:easy_localization/easy_localization.dart' show AssetLoader; - -class CodegenLoader extends AssetLoader { - const CodegenLoader(); - - @override - Future> load(String fullPath, Locale locale) { - return Future.value(mapLocales[locale.toString()]); - } - - static const Map ar = { - "Welcome": "اهلا بك،", - "Settings": "الاعدادات", - "Logout": "تسجيل الخروج", - "Profile": "الحساب الشخصي", - "Languages": "اللغات", - "Theme": "الوضع", - "Feedback": "إبلاغ", - "Report_a_bug": "إبلاغ عن مشكلة ", - "Misc": "متفرقات", - "Terms_and_conditions": "الأحكام والشروط", - "Privacy_Policy": "سياسة الخصوصية", - "Info": "عن البرنامج", - "Version": "النسخة", - "Language": "اللغة", - "General": "عام", - "Breakfast": "الفطار", - "Dinner": "العشاء", - "Lunch": "الغذاء", - "Snacks": "وجبات خفيفة", - "Ingridents": "المكونات", - "Video": "فيديو", - "Shakshuka": "شكشوكة", - "Crustless_Quiche": "كيشي بدون قشرة", - "Burrito": "بوريتو", - "Baked_Oatmeal": "شوفان مشوي", - "Apple_Cinnamon_Oat": "التفاح بالقرفة والشوفان", - "Banana_Bread": "خبر بالموز", - "Waffles": "بسكويتات الوفل", - "Wild_Mushroom_Risotto": "ريزوتو بالفطر ", - "Grilled_Steak_Tortilla_Salad": "سلطة تورتيلا ستيك مشوي", - "Feta_Shrimp_and_Polenta": "روبيان فيتا وبولينتا", - "Black_Bean_Soup": "شربة فول", - "Bass_With_Radish_Salsa": "باس مع صلصة الفجل", - "Eggplant_Parmesan": "بارما الباذنجان", - "Roasted_Cauliflower_Tacos": "قرنبيط محمص تاكو", - "Carrot_with_Radish_Salad": "سلطة جزر بالفجل", - "Salmon_Salad": "سلطة سلمون", - "Panzanella": "بانزانيلا", - "Caesar_Salad": "سلطة سيزر", - "Mixed_Nuts": "مكسرات مشكله", - "Red_pepper_guacamole": "الفلفل الأحمر جواكامولي", - "Yogurt_with_mixed_berries": "زبادي مع توت مشكل", - "Apple_slices_with_peanut": "شرائح التفاح مع الفول السوداني", - "Cottage_cheese": "جبن", - "Celery_sticks_with_Cheese": "أعواد الكرفس بالجبن", - "System_Prefrence": "الوضع النظام ", - "Light_Mode": "الوضع الضوء", - "Dark_Mode": "الوضع المظلم", - "life_pristine": "اجعل حياتك نقية", - "Pristine_access": "يمنحك النظام الوصول إلى ميزاتنا باهظة الثمن بالكامل", - "gateway": "اختار طريقة الدفع", - "three_months": "3شهور", - "total_price": "السعر الكلي", - "monthly": "شهريا", - "cancel_sub": "يمكنك إلغاء اشتراكك في أي وقت من خلال google pay", - "choose_content": "اختار المحتوي", - "Iam_a": "انا", - "healthy": "تريد أن تحصل على وصفات صحية بجانب المكونات ومقاطع الفيديو", - "patient": - "تريد أن تحصل علي وصفات علي حسب حالتك الصحية مع مكونات و مقاطع الفيديو", - "username": "اسم المستخدم", - "password": "كلمة السر", - "Forget_your_password": "نسيت كلمة المرور ؟", - "Sign_in": "تسجيل الدخول", - "no_account": "ليس لديك حساب ؟", - "Sign_up": "سجل الآن", - "have_an_account": "هل لديك حساب ؟", - "terms1": "من خلال إنشاء حساب ، فإنك توافق بالفعل على", - "terms2": "الأحكام والشروط", - "notfications": "إشعارات", - "ask_me_how_i_feel": "اسالني كيف اشعر كل يوم", - "continue_as_guest": "سجل كضيف", - "change_password": "تغيير كلمة المرور", - "enter_token": "أدخل الرمز الخاص بك", - "validate_token": "التحقق من صحة الرمز", - "Reset_pass": "إعادة تعيين كلمة المرور", - "pass_confirm": "تأكيد كلمة المرور", - "per_situation": "حالة معينة", - "Favorites": "المفضلة", - "delete_account": "حذف الحساب", - "account": "الحساب", - "update": "تحديث", - "livine": "ليفين", - "About_Livine": "عن ليفين", - }; - static const Map en = { - "Welcome": "Welcome,", - "Settings": "Settings", - "Logout": "Logout", - "Profile": "Profile", - "Languages": "Languages", - "Theme": "Theme", - "Feedback": "Feedback", - "Report_a_bug": "Report a bug ", - "Misc": "Misc", - "Terms_and_conditions": "Terms and Conditions", - "Privacy_Policy": "Privacy Policy", - "Info": "Info", - "Version": "Version", - "Language": "Language", - "General": "General", - "Breakfast": "Breakfast", - "Dinner": "Dinner", - "Lunch": "Lunch", - "Snacks": "Snacks", - "Ingridents": "Ingridents", - "Video": "Video", - "Shakshuka": "Shakshuka", - "Crustless_Quiche": "Crustless Quiche", - "Burrito": "Burrito", - "Baked_Oatmeal": "Baked Oatmeal", - "Apple_Cinnamon_Oat": "Apple Cinnamon Oat", - "Banana_Bread": "Banana Bread", - "Waffles": "Waffles", - "Wild_Mushroom_Risotto": "Wild Mushroom Risotto", - "Grilled_Steak_Tortilla_Salad": "Grilled Steak Tortilla Salad", - "Feta_Shrimp_and_Polenta": "Feta Shrimp and Polenta", - "Black_Bean_Soup": "Black Bean Soup", - "Bass_With_Radish_Salsa": "Bass With Radish Salsa", - "Eggplant_Parmesan": "Eggplant Parmesan", - "Roasted_Cauliflower_Tacos": "Roasted Cauliflower Tacos", - "Carrot_with_Radish_Salad": "Carrot with Radish Salad", - "Caesar_Salad": "Caesar Salad", - "Salmon_Salad": "Salmon Salad", - "Panzanella": "Panzanella", - "Mixed_Nuts": "Mixed Nuts", - "Red_pepper_guacamole": "Red pepper guacamole", - "Yogurt_with_mixed_berries": "Yogurt with mixed berries", - "Apple_slices_with_peanut": "Apple slices with peanut", - "Cottage_cheese": "Cottage cheese", - "Celery_sticks_with_Cheese": "Celery sticks with Cheese", - "System_Prefrence": "System preference", - "Light_Mode": "Light Mode", - "Dark_Mode": "Dark Mode", - "life_pristine": "Make your life Pristine", - "Pristine_access": "Pristine give u access to our full expensive features", - "gateway": "Choose Gateway", - "three_months": "3 months", - "total_price": "total price", - "monthly": "Monthly", - "cancel_sub": - "You can cancel your subscription at any time through google pay", - "choose_content": "Choose your content", - "Iam_a": "I'm a", - "healthy": - "You want to be provided by healthy recipes that you should consume to remain healthy", - "patient": "You want to be provided per your health situation", - "username": "Username", - "password": "Password", - "Forget_your_password": "Forget your password ?", - "Sign_in": "Sign In", - "no_account": "Don't Have an account ?", - "Sign_up": "Sign Up", - "have_an_account": "Already have an account ?", - "terms1": "By creating an account , you already agree on", - "terms2": "Terms and Conditions", - "notfications": "Notfications", - "ask_me_how_i_feel": "Ask me how I feel everyday", - "continue_as_guest": "Continue as GUEST", - "change_password": "Change your password", - "enter_token": "Enter Your Code", - "validate_token": "Validate Code", - "Reset_pass": "Reset password", - "pass_confirm": "Password Confirmation", - "per_situation": "Per Situation", - "Favorites": "Favorites", - "delete_account": "Delete account", - "account": "Account", - "update": "Update", - "livine": "Livine", - "About_Livine": "About Livine" - }; - static const Map> mapLocales = { - "ar": ar, - "en": en - }; -} diff --git a/lib/src/translations/domain/translation_provider.dart b/lib/src/translations/domain/translation_provider.dart new file mode 100644 index 0000000..3878f7e --- /dev/null +++ b/lib/src/translations/domain/translation_provider.dart @@ -0,0 +1,34 @@ +import 'dart:ui'; +import 'package:flutter_gen/gen_l10n/app_localizations.dart'; + +import 'package:hooks_riverpod/hooks_riverpod.dart'; +import 'package:livine/src/shared/cache/cache_helper.dart'; + +class TranslationRepo { + static List supportedLocales = [ + Locale('en'), + Locale('ar'), + ]; + + static AppLocalizations? translate(context) => AppLocalizations.of(context); +} + +final localeNotifierProvider = + StateNotifierProvider( + (ref) => LocaleNotifier(Locale('en'))); + +class LocaleNotifier extends StateNotifier { + LocaleNotifier(Locale state) : super(_initializeLocale()); + + static Locale _initializeLocale() { + String langCode = CacheHelper.getString('locale') ?? 'en'; + return Locale(langCode); + } + + setLocale(Locale locale) { + state = locale; + CacheHelper.setString('locale', locale.languageCode); + } + + void clearLocale() => state = Locale('en'); +} diff --git a/lib/src/translations/locale_keys.g.dart b/lib/src/translations/locale_keys.g.dart deleted file mode 100644 index 03c5922..0000000 --- a/lib/src/translations/locale_keys.g.dart +++ /dev/null @@ -1,86 +0,0 @@ -// DO NOT EDIT. This is code generated via package:easy_localization/generate.dart - -abstract class LocaleKeys { - static const Welcome = 'Welcome'; - static const Settings = 'Settings'; - static const Logout = 'Logout'; - static const Profile = 'Profile'; - static const Languages = 'Languages'; - static const Theme = 'Theme'; - static const Feedback = 'Feedback'; - static const Report_a_bug = 'Report_a_bug'; - static const Misc = 'Misc'; - static const Terms_and_conditions = 'Terms_and_conditions'; - static const Privacy_Policy = 'Privacy_Policy'; - static const Info = 'Info'; - static const Version = 'Version'; - static const Language = 'Language'; - static const General = 'General'; - static const Breakfast = 'Breakfast'; - static const Dinner = 'Dinner'; - static const Lunch = 'Lunch'; - static const Snacks = 'Snacks'; - static const Ingridents = 'Ingridents'; - static const Video = 'Video'; - static const Shakshuka = 'Shakshuka'; - static const Crustless_Quiche = 'Crustless_Quiche'; - static const Burrito = 'Burrito'; - static const Baked_Oatmeal = 'Baked_Oatmeal'; - static const Apple_Cinnamon_Oat = 'Apple_Cinnamon_Oat'; - static const Banana_Bread = 'Banana_Bread'; - static const Waffles = 'Waffles'; - static const Wild_Mushroom_Risotto = 'Wild_Mushroom_Risotto'; - static const Grilled_Steak_Tortilla_Salad = 'Grilled_Steak_Tortilla_Salad'; - static const Feta_Shrimp_and_Polenta = 'Feta_Shrimp_and_Polenta'; - static const Black_Bean_Soup = 'Black_Bean_Soup'; - static const Bass_With_Radish_Salsa = 'Bass_With_Radish_Salsa'; - static const Eggplant_Parmesan = 'Eggplant_Parmesan'; - static const Roasted_Cauliflower_Tacos = 'Roasted_Cauliflower_Tacos'; - static const Carrot_with_Radish_Salad = 'Carrot_with_Radish_Salad'; - static const Salmon_Salad = 'Salmon_Salad'; - static const Panzanella = 'Panzanella'; - static const Caesar_Salad = 'Caesar_Salad'; - static const Mixed_Nuts = 'Mixed_Nuts'; - static const Red_pepper_guacamole = 'Red_pepper_guacamole'; - static const Yogurt_with_mixed_berries = 'Yogurt_with_mixed_berries'; - static const Apple_slices_with_peanut = 'Apple_slices_with_peanut'; - static const Cottage_cheese = 'Cottage_cheese'; - static const Celery_sticks_with_Cheese = 'Celery_sticks_with_Cheese'; - static const System_Prefrence = 'System_Prefrence'; - static const Light_Mode = 'Light_Mode'; - static const Dark_Mode = 'Dark_Mode'; - static const life_pristine = 'life_pristine'; - static const Pristine_access = 'Pristine_access'; - static const gateway = 'gateway'; - static const three_months = 'three_months'; - static const total_price = 'total_price'; - static const monthly = 'monthly'; - static const cancel_sub = 'cancel_sub'; - static const choose_content = 'choose_content'; - static const Iam_a = 'Iam_a'; - static const healthy = 'healthy'; - static const patient = 'patient'; - static const username = 'username'; - static const password = 'password'; - static const Forget_your_password = 'Forget_your_password'; - static const Sign_in = 'Sign_in'; - static const no_account = 'no_account'; - static const Sign_up = 'Sign_up'; - static const have_an_account = 'have_an_account'; - static const terms1 = 'terms1'; - static const terms2 = 'terms2'; - static const notfications = 'notfications'; - static const ask_me_how_i_feel = 'ask_me_how_i_feel'; - static const continue_as_guest = 'continue_as_guest'; - static const change_password = 'change_password'; - static const enter_token = 'enter_token'; - static const validate_token = 'validate_token'; - static const Reset_pass = 'Reset_pass'; - static const pass_confirm = 'pass_confirm'; - static const per_situation = 'per_situation'; - static const Favorites = 'Favorites'; - static const delete_account = 'delete_account'; - static const account = 'account'; - static const update = 'update'; - -} diff --git a/pubspec.lock b/pubspec.lock index bec94db..3eaf8b7 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -5,80 +5,136 @@ packages: dependency: transitive description: name: _fe_analyzer_shared - sha256: "3444216bfd127af50bbe4862d8843ed44db946dd933554f0d7285e89f10e28ac" - url: "https://pub.dev" + sha256: ae92f5d747aee634b87f89d9946000c2de774be1d6ac3e58268224348cd0101a + url: "https://pub.flutter-io.cn" source: hosted - version: "50.0.0" + version: "61.0.0" analyzer: - dependency: transitive + dependency: "direct dev" description: name: analyzer - sha256: "68796c31f510c8455a06fed75fc97d8e5ad04d324a830322ab3efc9feb6201c1" - url: "https://pub.dev" + sha256: ea3d8652bda62982addfd92fdc2d0214e5f82e43325104990d4f4c4a2a313562 + url: "https://pub.flutter-io.cn" + source: hosted + version: "5.13.0" + analyzer_plugin: + dependency: transitive + description: + name: analyzer_plugin + sha256: c1d5f167683de03d5ab6c3b53fc9aeefc5d59476e7810ba7bbddff50c6f4392d + url: "https://pub.flutter-io.cn" source: hosted - version: "5.2.0" + version: "0.11.2" animations: dependency: "direct main" description: name: animations - sha256: fe8a6bdca435f718bb1dc8a11661b2c22504c6da40ef934cee8327ed77934164 - url: "https://pub.dev" + sha256: ef57563eed3620bd5d75ad96189846aca1e033c0c45fc9a7d26e80ab02b88a70 + url: "https://pub.flutter-io.cn" source: hosted - version: "2.0.7" + version: "2.0.8" archive: dependency: transitive description: name: archive - sha256: "80e5141fafcb3361653ce308776cfd7d45e6e9fbb429e14eec571382c0c5fecb" - url: "https://pub.dev" + sha256: "49b1fad315e57ab0bbc15bcbb874e83116a1d78f77ebd500a4af6c9407d6b28e" + url: "https://pub.flutter-io.cn" source: hosted - version: "3.3.2" + version: "3.3.8" args: dependency: transitive description: name: args - sha256: b003c3098049a51720352d219b0bb5f219b60fbfb68e7a4748139a06a5676515 - url: "https://pub.dev" + sha256: eef6c46b622e0494a36c5a12d10d77fb4e855501a91c1b9ef9339326e58f0596 + url: "https://pub.flutter-io.cn" source: hosted - version: "2.3.1" + version: "2.4.2" async: dependency: transitive description: name: async - sha256: bfe67ef28df125b7dddcea62755991f807aa39a2492a23e1550161692950bbe0 - url: "https://pub.dev" + sha256: "947bfcf187f74dbc5e146c9eb9c0f10c9f8b30743e341481c1e2ed3ecc18c20c" + url: "https://pub.flutter-io.cn" source: hosted - version: "2.10.0" + version: "2.11.0" boolean_selector: dependency: transitive description: name: boolean_selector sha256: "6cfb5af12253eaf2b368f07bacc5a80d1301a071c73360d746b7f2e32d762c66" - url: "https://pub.dev" + url: "https://pub.flutter-io.cn" source: hosted version: "2.1.1" build: dependency: transitive description: name: build - sha256: "3fbda25365741f8251b39f3917fb3c8e286a96fd068a5a242e11c2012d495777" - url: "https://pub.dev" + sha256: "80184af8b6cb3e5c1c4ec6d8544d27711700bc3e6d2efad04238c7b5290889f0" + url: "https://pub.flutter-io.cn" source: hosted - version: "2.3.1" + version: "2.4.1" build_config: dependency: transitive description: name: build_config - sha256: "5b7355c14258f5e7df24bad1566f7b991de3e54aeacfb94e1a65e5233d9739c1" - url: "https://pub.dev" + sha256: bf80fcfb46a29945b423bd9aad884590fb1dc69b330a4d4700cac476af1708d1 + url: "https://pub.flutter-io.cn" source: hosted - version: "1.1.0" + version: "1.1.1" + build_daemon: + dependency: transitive + description: + name: build_daemon + sha256: "5f02d73eb2ba16483e693f80bee4f088563a820e47d1027d4cdfe62b5bb43e65" + url: "https://pub.flutter-io.cn" + source: hosted + version: "4.0.0" + build_resolvers: + dependency: transitive + description: + name: build_resolvers + sha256: d912852cce27c9e80a93603db721c267716894462e7033165178b91138587972 + url: "https://pub.flutter-io.cn" + source: hosted + version: "2.3.2" + build_runner: + dependency: "direct dev" + description: + name: build_runner + sha256: "10c6bcdbf9d049a0b666702cf1cee4ddfdc38f02a19d35ae392863b47519848b" + url: "https://pub.flutter-io.cn" + source: hosted + version: "2.4.6" + build_runner_core: + dependency: transitive + description: + name: build_runner_core + sha256: "6d6ee4276b1c5f34f21fdf39425202712d2be82019983d52f351c94aafbc2c41" + url: "https://pub.flutter-io.cn" + source: hosted + version: "7.2.10" + built_collection: + dependency: transitive + description: + name: built_collection + sha256: "376e3dd27b51ea877c28d525560790aee2e6fbb5f20e2f85d5081027d94e2100" + url: "https://pub.flutter-io.cn" + source: hosted + version: "5.1.1" + built_value: + dependency: transitive + description: + name: built_value + sha256: ff627b645b28fb8bdb69e645f910c2458fd6b65f6585c3a53e0626024897dedf + url: "https://pub.flutter-io.cn" + source: hosted + version: "8.6.2" cached_network_image: dependency: "direct main" description: name: cached_network_image sha256: fd3d0dc1d451f9a252b32d95d3f0c3c487bc41a75eba2e6097cb0b9c71491b15 - url: "https://pub.dev" + url: "https://pub.flutter-io.cn" source: hosted version: "3.2.3" cached_network_image_platform_interface: @@ -86,7 +142,7 @@ packages: description: name: cached_network_image_platform_interface sha256: bb2b8403b4ccdc60ef5f25c70dead1f3d32d24b9d6117cfc087f496b178594a7 - url: "https://pub.dev" + url: "https://pub.flutter-io.cn" source: hosted version: "2.0.0" cached_network_image_web: @@ -94,135 +150,159 @@ packages: description: name: cached_network_image_web sha256: b8eb814ebfcb4dea049680f8c1ffb2df399e4d03bf7a352c775e26fa06e02fa0 - url: "https://pub.dev" + url: "https://pub.flutter-io.cn" source: hosted version: "1.0.2" characters: dependency: transitive description: name: characters - sha256: e6a326c8af69605aec75ed6c187d06b349707a27fbff8222ca9cc2cff167975c - url: "https://pub.dev" + sha256: "04a925763edad70e8443c99234dc3328f442e811f1d8fd1a72f1c8ad0f69a605" + url: "https://pub.flutter-io.cn" source: hosted - version: "1.2.1" - charcode: + version: "1.3.0" + checked_yaml: dependency: transitive description: - name: charcode - sha256: fb98c0f6d12c920a02ee2d998da788bca066ca5f148492b7085ee23372b12306 - url: "https://pub.dev" + name: checked_yaml + sha256: feb6bed21949061731a7a75fc5d2aa727cf160b91af9a3e464c5e3a32e28b5ff + url: "https://pub.flutter-io.cn" source: hosted - version: "1.3.1" - checked_yaml: + version: "2.0.3" + ci: dependency: transitive description: - name: checked_yaml - sha256: dd007e4fb8270916820a0d66e24f619266b60773cddd082c6439341645af2659 - url: "https://pub.dev" + name: ci + sha256: "145d095ce05cddac4d797a158bc4cf3b6016d1fe63d8c3d2fbd7212590adca13" + url: "https://pub.flutter-io.cn" source: hosted - version: "2.0.1" + version: "0.1.0" cli_util: dependency: transitive description: name: cli_util - sha256: "66f86e916d285c1a93d3b79587d94bd71984a66aac4ff74e524cfa7877f1395c" - url: "https://pub.dev" + sha256: b8db3080e59b2503ca9e7922c3df2072cf13992354d5e944074ffa836fba43b7 + url: "https://pub.flutter-io.cn" source: hosted - version: "0.3.5" + version: "0.4.0" clock: dependency: transitive description: name: clock sha256: cb6d7f03e1de671e34607e909a7213e31d7752be4fb66a86d29fe1eb14bfb5cf - url: "https://pub.dev" + url: "https://pub.flutter-io.cn" source: hosted version: "1.1.1" + code_builder: + dependency: transitive + description: + name: code_builder + sha256: "315a598c7fbe77f22de1c9da7cfd6fd21816312f16ffa124453b4fc679e540f1" + url: "https://pub.flutter-io.cn" + source: hosted + version: "4.6.0" collection: dependency: transitive description: name: collection - sha256: cfc915e6923fe5ce6e153b0723c753045de46de1b4d63771530504004a45fae0 - url: "https://pub.dev" + sha256: f092b211a4319e98e5ff58223576de6c2803db36221657b46c82574721240687 + url: "https://pub.flutter-io.cn" source: hosted - version: "1.17.0" + version: "1.17.2" concentric_transition: dependency: "direct main" description: name: concentric_transition sha256: "825191221e4bc6a0cfaf00adbc5cd2cc1333970f61311bce52021f1f68e0a891" - url: "https://pub.dev" + url: "https://pub.flutter-io.cn" source: hosted version: "1.0.3" connectivity_plus: dependency: "direct main" description: name: connectivity_plus - sha256: "745ebcccb1ef73768386154428a55250bc8d44059c19fd27aecda2a6dc013a22" - url: "https://pub.dev" + sha256: "77a180d6938f78ca7d2382d2240eb626c0f6a735d0bfdce227d8ffb80f95c48b" + url: "https://pub.flutter-io.cn" source: hosted - version: "3.0.2" + version: "4.0.2" connectivity_plus_platform_interface: dependency: transitive description: name: connectivity_plus_platform_interface - sha256: b8795b9238bf83b64375f63492034cb3d8e222af4d9ce59dda085edf038fa06f - url: "https://pub.dev" + sha256: cf1d1c28f4416f8c654d7dc3cd638ec586076255d407cef3ddbdaf178272a71a + url: "https://pub.flutter-io.cn" source: hosted - version: "1.2.3" + version: "1.2.4" console: dependency: transitive description: name: console sha256: e04e7824384c5b39389acdd6dc7d33f3efe6b232f6f16d7626f194f6a01ad69a - url: "https://pub.dev" + url: "https://pub.flutter-io.cn" source: hosted version: "4.1.0" convert: dependency: transitive description: name: convert - sha256: f08428ad63615f96a27e34221c65e1a451439b5f26030f78d790f461c686d65d - url: "https://pub.dev" - source: hosted - version: "3.0.1" - cross_file: - dependency: transitive - description: - name: cross_file - sha256: "7632a2bcddc8cef4afde3c6f80e69b29a7060e176f01119c229fe4eb3a2a3d4f" - url: "https://pub.dev" + sha256: "0f08b14755d163f6e2134cb58222dd25ea2a2ee8a195e53983d57c075324d592" + url: "https://pub.flutter-io.cn" source: hosted - version: "0.3.3+1" + version: "3.1.1" crypto: dependency: transitive description: name: crypto - sha256: aa274aa7774f8964e4f4f38cc994db7b6158dd36e9187aaceaddc994b35c6c67 - url: "https://pub.dev" + sha256: ff625774173754681d66daaf4a448684fb04b78f902da9cb3d308c19cc5e8bab + url: "https://pub.flutter-io.cn" source: hosted - version: "3.0.2" + version: "3.0.3" csslib: dependency: transitive description: name: csslib - sha256: d1cd6d6e4b39a4ad295204722b8608f19981677b223f3e942c0b5a33dcf57ec0 - url: "https://pub.dev" + sha256: "831883fb353c8bdc1d71979e5b342c7d88acfbc643113c14ae51e2442ea0f20f" + url: "https://pub.flutter-io.cn" source: hosted - version: "0.17.1" + version: "0.17.3" + custom_lint: + dependency: transitive + description: + name: custom_lint + sha256: "837821e4619c167fd5a547b03bb2fc6be7e65b800ec75528848429705c31ceba" + url: "https://pub.flutter-io.cn" + source: hosted + version: "0.5.3" + custom_lint_core: + dependency: transitive + description: + name: custom_lint_core + sha256: "3bdebdd52a42b4d6e5be9cd833ad1ecfbbc23e1020ca537060e54085497aea9c" + url: "https://pub.flutter-io.cn" + source: hosted + version: "0.5.3" + custom_sliding_segmented_control: + dependency: "direct main" + description: + name: custom_sliding_segmented_control + sha256: a12d1908bb3fe06aabd4becd7def608cdd77b01b7a9f79e37d9414b478523a34 + url: "https://pub.flutter-io.cn" + source: hosted + version: "1.7.5" dart_style: dependency: transitive description: name: dart_style - sha256: "7a03456c3490394c8e7665890333e91ae8a49be43542b616e414449ac358acd4" - url: "https://pub.dev" + sha256: "1efa911ca7086affd35f463ca2fc1799584fb6aa89883cf0af8e3664d6a02d55" + url: "https://pub.flutter-io.cn" source: hosted - version: "2.2.4" + version: "2.3.2" dbus: dependency: transitive description: name: dbus sha256: "6f07cba3f7b3448d42d015bfd3d53fe12e5b36da2423f23838efc1d5fb31a263" - url: "https://pub.dev" + url: "https://pub.flutter-io.cn" source: hosted version: "0.7.8" device_frame: @@ -230,81 +310,73 @@ packages: description: name: device_frame sha256: afe76182aec178d171953d9b4a50a43c57c7cf3c77d8b09a48bf30c8fa04dd9d - url: "https://pub.dev" + url: "https://pub.flutter-io.cn" source: hosted version: "1.1.0" device_info_plus: dependency: "direct main" description: name: device_info_plus - sha256: "7ff671ed0a6356fa8f2e1ae7d3558d3fb7b6a41e24455e4f8df75b811fb8e4ab" - url: "https://pub.dev" + sha256: "86add5ef97215562d2e090535b0a16f197902b10c369c558a100e74ea06e8659" + url: "https://pub.flutter-io.cn" source: hosted - version: "8.0.0" + version: "9.0.3" device_info_plus_platform_interface: dependency: transitive description: name: device_info_plus_platform_interface sha256: d3b01d5868b50ae571cd1dc6e502fc94d956b665756180f7b16ead09e836fd64 - url: "https://pub.dev" + url: "https://pub.flutter-io.cn" source: hosted version: "7.0.0" device_preview: - dependency: "direct main" + dependency: "direct dev" description: name: device_preview sha256: "2f097bf31b929e15e6756dbe0ec1bcb63952ab9ed51c25dc5a2c722d2b21fdaf" - url: "https://pub.dev" + url: "https://pub.flutter-io.cn" source: hosted version: "1.1.0" - easy_localization: + dynamic_color: dependency: "direct main" description: - name: easy_localization - sha256: "6a2e99fa0bfe5765bf4c6ca9b137d5de2c75593007178c5e4cd2ae985f870080" - url: "https://pub.dev" + name: dynamic_color + sha256: de4798a7069121aee12d5895315680258415de9b00e717723a1bd73d58f0126d + url: "https://pub.flutter-io.cn" 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" + version: "1.6.6" fake_async: dependency: transitive description: name: fake_async sha256: "511392330127add0b769b75a987850d136345d9227c6b94c96a04cf4a391bf78" - url: "https://pub.dev" + url: "https://pub.flutter-io.cn" source: hosted version: "1.3.1" ffi: dependency: transitive description: name: ffi - sha256: a38574032c5f1dd06c4aee541789906c12ccaab8ba01446e800d9c5b79c4a978 - url: "https://pub.dev" + sha256: "7bf0adc28a23d395f19f3f1eb21dd7cfd1dd9f8e1c50051c069122e6853bc878" + url: "https://pub.flutter-io.cn" source: hosted - version: "2.0.1" + version: "2.1.0" file: dependency: transitive description: name: file sha256: "1b92bec4fc2a72f59a8e15af5f52cd441e4a7860b49499d69dfa817af20e925d" - url: "https://pub.dev" + url: "https://pub.flutter-io.cn" source: hosted version: "6.1.4" - fluentui_icons: - dependency: "direct main" + fixnum: + dependency: transitive description: - name: fluentui_icons - sha256: "5944d9a0d52df1c63107abd00c8f4e81c6c1f7961347ccd88c9532a42327e0ae" - url: "https://pub.dev" + name: fixnum + sha256: "25517a4deb0c03aa0f32fd12db525856438902d9c16536311e76cdc57b31d7d1" + url: "https://pub.flutter-io.cn" source: hosted - version: "1.0.0" + version: "1.1.0" flutter: dependency: "direct main" description: flutter @@ -314,18 +386,18 @@ packages: dependency: transitive description: name: flutter_blurhash - sha256: "93f1c766a03dee60ced31b4b536fbc406c21c9cfac3064fd4138129bff44444d" - url: "https://pub.dev" + sha256: "05001537bd3fac7644fa6558b09ec8c0a3f2eba78c0765f88912882b1331a5c6" + url: "https://pub.flutter-io.cn" source: hosted - version: "0.6.8" + version: "0.7.0" flutter_cache_manager: dependency: transitive description: name: flutter_cache_manager - sha256: "32cd900555219333326a2d0653aaaf8671264c29befa65bbd9856d204a4c9fb3" - url: "https://pub.dev" + sha256: "8207f27539deb83732fdda03e259349046a39a4c767269285f449ade355d54ba" + url: "https://pub.flutter-io.cn" source: hosted - version: "3.3.0" + version: "3.3.1" flutter_driver: dependency: transitive description: flutter @@ -335,52 +407,52 @@ packages: dependency: "direct main" description: name: flutter_hooks - sha256: "2b202559a4ed3656bbb7aae9d8b335fb0037b23acc7ae3f377d1ba0b95c21aec" - url: "https://pub.dev" + sha256: "6a126f703b89499818d73305e4ce1e3de33b4ae1c5512e3b8eab4b986f46774c" + url: "https://pub.flutter-io.cn" source: hosted - version: "0.18.5+1" + version: "0.18.6" flutter_html: dependency: "direct main" description: name: flutter_html - sha256: "342c7908f0a67bcec62b6e0f7cf23e23bafe7f64693665dd35be98d5e783bdfd" - url: "https://pub.dev" + sha256: "02ad69e813ecfc0728a455e4bf892b9379983e050722b1dce00192ee2e41d1ee" + url: "https://pub.flutter-io.cn" source: hosted - version: "3.0.0-alpha.6" + version: "3.0.0-beta.2" flutter_lints: dependency: "direct dev" description: name: flutter_lints - sha256: aeb0b80a8b3709709c9cc496cdc027c5b3216796bc0af0ce1007eaf24464fd4c - url: "https://pub.dev" + sha256: a25a15ebbdfc33ab1cd26c63a6ee519df92338a9c10f122adda92938253bef04 + url: "https://pub.flutter-io.cn" source: hosted - version: "2.0.1" + version: "2.0.3" flutter_local_notifications: dependency: "direct main" description: name: flutter_local_notifications - sha256: "293995f94e120c8afce768981bd1fa9c5d6de67c547568e3b42ae2defdcbb4a0" - url: "https://pub.dev" + sha256: "7b963d145ac12bf177932e02afaadafa6af22392a8258ee3b978672e9b362208" + url: "https://pub.flutter-io.cn" source: hosted - version: "13.0.0" + version: "14.1.3+1" flutter_local_notifications_linux: dependency: transitive description: name: flutter_local_notifications_linux - sha256: "8f6c1611e0c4a88a382691a97bb3c3feb24cc0c0b54152b8b5fb7ffb837f7fbf" - url: "https://pub.dev" + sha256: "33f741ef47b5f63cc7f78fe75eeeac7e19f171ff3c3df054d84c1e38bedb6a03" + url: "https://pub.flutter-io.cn" source: hosted - version: "3.0.0" + version: "4.0.0+1" flutter_local_notifications_platform_interface: dependency: transitive description: name: flutter_local_notifications_platform_interface - sha256: "5ec1feac5f7f7d9266759488bc5f76416152baba9aa1b26fe572246caa00d1ab" - url: "https://pub.dev" + sha256: "7cf643d6d5022f3baed0be777b0662cce5919c0a7b86e700299f22dc4ae660ef" + url: "https://pub.flutter-io.cn" source: hosted - version: "6.0.0" + version: "7.0.0+1" flutter_localizations: - dependency: transitive + dependency: "direct main" description: flutter source: sdk version: "0.0.0" @@ -388,50 +460,26 @@ packages: dependency: "direct dev" description: name: flutter_native_splash - sha256: "6777a3abb974021a39b5fdd2d46a03ca390e03903b6351f21d10e7ecc969f12d" - url: "https://pub.dev" - source: hosted - version: "2.2.16" - flutter_native_timezone: - dependency: "direct main" - description: - name: flutter_native_timezone - sha256: ed7bfb982f036243de1c068e269182a877100c994f05143c8b26a325e28c1b02 - url: "https://pub.dev" - source: hosted - version: "2.0.0" - flutter_plugin_android_lifecycle: - dependency: transitive - description: - name: flutter_plugin_android_lifecycle - sha256: "6ffe524cd6a7d49d99b2bf979a4f6ad82304c639cea4c8d3d0f8cf1aff24e74a" - url: "https://pub.dev" + sha256: ecff62b3b893f2f665de7e4ad3de89f738941fcfcaaba8ee601e749efafa4698 + url: "https://pub.flutter-io.cn" source: hosted - version: "2.0.6" + version: "2.3.2" flutter_riverpod: dependency: transitive description: name: flutter_riverpod - sha256: "0c997763ce06359ee4686553b74def84062e9d6929ac63f61fa02465c1f8e32c" - url: "https://pub.dev" + sha256: "1bd39b04f1bcd217a969589777ca6bd642d116e3e5de65c3e6a8e8bdd8b178ec" + url: "https://pub.flutter-io.cn" source: hosted - version: "2.1.3" + version: "2.4.0" flutter_svg: dependency: "direct main" description: name: flutter_svg - sha256: "6ff9fa12892ae074092de2fa6a9938fb21dbabfdaa2ff57dc697ff912fc8d4b2" - url: "https://pub.dev" + sha256: "8c5d68a82add3ca76d792f058b186a0599414f279f00ece4830b9b231b570338" + url: "https://pub.flutter-io.cn" source: hosted - version: "1.1.6" - flutter_switch: - dependency: "direct main" - description: - name: flutter_switch - sha256: b91477f926bba135d2d203d7b24367492662d8d9c3aa6adb960b14c1087d3c41 - url: "https://pub.dev" - source: hosted - version: "0.3.2" + version: "2.0.7" flutter_test: dependency: "direct dev" description: flutter @@ -442,30 +490,30 @@ packages: description: flutter source: sdk version: "0.0.0" - font_awesome_flutter: - dependency: "direct main" - description: - name: font_awesome_flutter - sha256: "8f0ce0204bd0cafa8631536a6f3b7d05d9c16cdc6e8bd807843f917027c5cefd" - url: "https://pub.dev" - source: hosted - version: "10.2.1" freezed: dependency: "direct dev" description: name: freezed - sha256: e819441678f1679b719008ff2ff0ef045d66eed9f9ec81166ca0d9b02a187454 - url: "https://pub.dev" + sha256: "2df89855fe181baae3b6d714dc3c4317acf4fccd495a6f36e5e00f24144c6c3b" + url: "https://pub.flutter-io.cn" source: hosted - version: "2.3.2" + version: "2.4.1" freezed_annotation: dependency: "direct main" description: name: freezed_annotation - sha256: aeac15850ef1b38ee368d4c53ba9a847e900bb2c53a4db3f6881cbb3cb684338 - url: "https://pub.dev" + sha256: c3fd9336eb55a38cc1bbd79ab17573113a8deccd0ecbbf926cca3c62803b5c2d + url: "https://pub.flutter-io.cn" source: hosted - version: "2.2.0" + version: "2.4.1" + frontend_server_client: + dependency: transitive + description: + name: frontend_server_client + sha256: "408e3ca148b31c20282ad6f37ebfa6f4bdc8fede5b74bc2f08d9d92b55db3612" + url: "https://pub.flutter-io.cn" + source: hosted + version: "3.2.0" fuchsia_remote_debug_protocol: dependency: transitive description: flutter @@ -475,160 +523,96 @@ packages: dependency: transitive description: name: get_it - sha256: "290fde3a86072e4b37dbb03c07bec6126f0ecc28dad403c12ffe2e5a2d751ab7" - url: "https://pub.dev" + sha256: f79870884de16d689cf9a7d15eedf31ed61d750e813c538a6efb92660fea83c3 + url: "https://pub.flutter-io.cn" source: hosted - version: "7.2.0" + version: "7.6.4" glob: dependency: transitive description: name: glob - sha256: "8321dd2c0ab0683a91a51307fa844c6db4aa8e3981219b78961672aaab434658" - url: "https://pub.dev" + sha256: "0e7014b3b7d4dac1ca4d6114f82bf1782ee86745b9b42a92c9289c23d8a0ab63" + url: "https://pub.flutter-io.cn" source: hosted - version: "2.0.2" + version: "2.1.2" go_router: dependency: "direct main" description: name: go_router - sha256: "9e8cee9969a9f33821a5594e5822d9a7ef3ae8528e5258f5178436e3deb0e095" - url: "https://pub.dev" + sha256: "00d1b67d6e9fa443331da229084dd3eb04407f5a2dff22940bd7bba6af5722c3" + url: "https://pub.flutter-io.cn" source: hosted - version: "6.0.3" - google_fonts: + version: "7.1.1" + gradient_borders: dependency: "direct main" description: - name: google_fonts - sha256: "927573f2e8a8d65c17931e21918ad0ab0666b1b636537de7c4932bdb487b190f" - url: "https://pub.dev" + name: gradient_borders + sha256: "69eeaff519d145a4c6c213ada1abae386bcc8981a4970d923e478ce7ba19e309" + url: "https://pub.flutter-io.cn" source: hosted - version: "4.0.3" - google_mobile_ads: - dependency: "direct main" + version: "1.0.0" + graphs: + dependency: transitive description: - name: google_mobile_ads - sha256: "7a39fe63007764115395550fc3eaf0d469de685298208040138c373d5444ab48" - url: "https://pub.dev" + name: graphs + sha256: aedc5a15e78fc65a6e23bcd927f24c64dd995062bcd1ca6eda65a3cff92a4d19 + url: "https://pub.flutter-io.cn" source: hosted - version: "2.3.0" + version: "2.3.1" hooks_riverpod: dependency: "direct main" description: name: hooks_riverpod - sha256: "71695b2e1dfc22a39f1f9c67b798f8f8f1521f2d0349817d13ccdd5c4cd7acba" - url: "https://pub.dev" + sha256: ad7b877c3687e38764633d221a1f65491bc7a540e724101e9a404a84db2a4276 + url: "https://pub.flutter-io.cn" source: hosted - version: "2.1.3" + version: "2.4.0" html: dependency: transitive description: name: html - sha256: d9793e10dbe0e6c364f4c59bf3e01fb33a9b2a674bc7a1081693dba0614b6269 - url: "https://pub.dev" + sha256: "3a7812d5bcd2894edf53dfaf8cd640876cf6cef50a8f238745c8b8120ea74d3a" + url: "https://pub.flutter-io.cn" source: hosted - version: "0.15.1" + version: "0.15.4" http: dependency: "direct main" description: name: http - sha256: "6aa2946395183537c8b880962d935877325d6a09a2867c3970c05c0fed6ac482" - url: "https://pub.dev" + sha256: "5895291c13fa8a3bd82e76d5627f69e0d85ca6a30dcac95c4ea19a5d555879c2" + url: "https://pub.flutter-io.cn" source: hosted - version: "0.13.5" - http_parser: + version: "0.13.6" + http_multi_server: dependency: transitive description: - name: http_parser - sha256: e362d639ba3bc07d5a71faebb98cde68c05bfbcfbbb444b60b6f60bb67719185 - url: "https://pub.dev" + name: http_multi_server + sha256: "97486f20f9c2f7be8f514851703d0119c3596d14ea63227af6f7a481ef2b2f8b" + url: "https://pub.flutter-io.cn" source: hosted - version: "4.0.0" - iconsax: - dependency: "direct main" + version: "3.2.1" + http_parser: + dependency: transitive description: - name: iconsax - sha256: fb0144c61f41f3f8a385fadc27783ea9f5359670be885ed7f35cef32565d5228 - url: "https://pub.dev" + name: http_parser + sha256: "2aa08ce0341cc9b354a498388e30986515406668dbcc4f7c950c3e715496693b" + url: "https://pub.flutter-io.cn" source: hosted - version: "0.0.8" + version: "4.0.2" image: dependency: transitive description: name: image - sha256: f6ffe2895e3c86c6ad5a27e6302cf807403463e397cb2f0c580f619ac2fa588b - url: "https://pub.dev" - source: hosted - version: "3.2.2" - image_cropper: - dependency: "direct main" - description: - name: image_cropper - sha256: "85324928ee8a8be35a529446435ca53067865b9353c8681983472eeec66d780f" - url: "https://pub.dev" - source: hosted - version: "3.0.1" - image_cropper_for_web: - dependency: transitive - description: - name: image_cropper_for_web - sha256: "09e93a8ec0435adcaa23622ac090442872f18145d70b9ff605ffedcf97d56255" - url: "https://pub.dev" - source: hosted - version: "1.0.3" - image_cropper_platform_interface: - dependency: transitive - description: - name: image_cropper_platform_interface - sha256: "62349e3aab63873ea9b9ab9f69d036ab8a0d74b3004beec4303981386cb9273f" - url: "https://pub.dev" - source: hosted - version: "3.0.3" - image_picker: - dependency: "direct main" - description: - name: image_picker - sha256: f98d76672d309c8b7030c323b3394669e122d52b307d2bbd8d06bd70f5b2aabe - url: "https://pub.dev" - source: hosted - version: "0.8.6+1" - image_picker_android: - dependency: transitive - description: - name: image_picker_android - sha256: "08cfcbf6eeab76948fb45064bf080044531e068b4814946137e75cb42487d651" - url: "https://pub.dev" + sha256: a72242c9a0ffb65d03de1b7113bc4e189686fc07c7147b8b41811d0dd0e0d9bf + url: "https://pub.flutter-io.cn" source: hosted - version: "0.8.5" - image_picker_for_web: - dependency: transitive - description: - name: image_picker_for_web - sha256: "60f306ffbdcada4bc8b2691acc420258a1b758e102c87c4f94fb568d640f0e0e" - url: "https://pub.dev" - source: hosted - version: "2.1.8" - image_picker_ios: - dependency: transitive - description: - name: image_picker_ios - sha256: "1768087441bd69ca632249d212c26fa8d530552d37b4896a4dd8d6781435c147" - url: "https://pub.dev" - source: hosted - version: "0.8.6+1" - image_picker_platform_interface: - dependency: transitive - description: - name: image_picker_platform_interface - sha256: "7cef2f28f4f2fef99180f636c3d446b4ccbafd6ba0fad2adc9a80c4040f656b8" - url: "https://pub.dev" - source: hosted - version: "2.6.2" + version: "4.0.17" infinite_scroll_pagination: dependency: "direct main" description: name: infinite_scroll_pagination sha256: "9517328f4e373f08f57dbb11c5aac5b05554142024d6b60c903f3b73476d52db" - url: "https://pub.dev" + url: "https://pub.flutter-io.cn" source: hosted version: "3.2.0" integration_test: @@ -637,99 +621,115 @@ packages: source: sdk version: "0.0.0" intl: - dependency: transitive + dependency: "direct main" description: name: intl - sha256: "910f85bce16fb5c6f614e117efa303e85a1731bb0081edf3604a2ae6e9a3cc91" - url: "https://pub.dev" + sha256: "3bc132a9dbce73a7e4a21a17d06e1878839ffbf975568bc875c60537824b0c4d" + url: "https://pub.flutter-io.cn" + source: hosted + version: "0.18.1" + io: + dependency: transitive + description: + name: io + sha256: "2ec25704aba361659e10e3e5f5d672068d332fc8ac516421d483a11e5cbd061e" + url: "https://pub.flutter-io.cn" source: hosted - version: "0.17.0" + version: "1.0.4" js: dependency: transitive description: name: js - sha256: "5528c2f391ededb7775ec1daa69e65a2d61276f7552de2b5f7b8d34ee9fd4ab7" - url: "https://pub.dev" + sha256: f2c445dce49627136094980615a031419f7f3eb393237e4ecd97ac15dea343f3 + url: "https://pub.flutter-io.cn" source: hosted - version: "0.6.5" + version: "0.6.7" json_annotation: dependency: "direct main" description: name: json_annotation - sha256: c33da08e136c3df0190bd5bbe51ae1df4a7d96e7954d1d7249fea2968a72d317 - url: "https://pub.dev" + sha256: b10a7b2ff83d83c777edba3c6a0f97045ddadd56c944e1a23a3fdf43a1bf4467 + url: "https://pub.flutter-io.cn" source: hosted - version: "4.8.0" + version: "4.8.1" json_serializable: dependency: "direct dev" description: name: json_serializable - sha256: dadc08bd61f72559f938dd08ec20dbfec6c709bba83515085ea943d2078d187a - url: "https://pub.dev" + sha256: aa1f5a8912615733e0fdc7a02af03308933c93235bdc8d50d0b0c8a8ccb0b969 + url: "https://pub.flutter-io.cn" source: hosted - version: "6.6.1" + version: "6.7.1" lints: dependency: transitive description: name: lints - sha256: "5cfd6509652ff5e7fe149b6df4859e687fca9048437857cb2e65c8d780f396e3" - url: "https://pub.dev" + sha256: "0a217c6c989d21039f1498c3ed9f3ed71b354e69873f13a8dfc3c9fe76f1b452" + url: "https://pub.flutter-io.cn" source: hosted - version: "2.0.0" - logging: + version: "2.1.1" + list_counter: dependency: transitive description: - name: logging - sha256: "293ae2d49fd79d4c04944c3a26dfd313382d5f52e821ec57119230ae16031ad4" - url: "https://pub.dev" + name: list_counter + sha256: c447ae3dfcd1c55f0152867090e67e219d42fe6d4f2807db4bbe8b8d69912237 + url: "https://pub.flutter-io.cn" source: hosted version: "1.0.2" - lottie: - dependency: "direct main" + logging: + dependency: transitive description: - name: lottie - sha256: "49bbc544e44bf0c734ccda29b182e3516a12f5021ea98b206cf31a168b0f97da" - url: "https://pub.dev" + name: logging + sha256: "623a88c9594aa774443aa3eb2d41807a48486b5613e67599fb4c41c0ad47c340" + url: "https://pub.flutter-io.cn" source: hosted - version: "2.2.0" + version: "1.2.0" matcher: dependency: transitive description: name: matcher - sha256: "16db949ceee371e9b99d22f88fa3a73c4e59fd0afed0bd25fc336eb76c198b72" - url: "https://pub.dev" + sha256: "1803e76e6653768d64ed8ff2e1e67bea3ad4b923eb5c56a295c3e634bad5960e" + url: "https://pub.flutter-io.cn" source: hosted - version: "0.12.13" + version: "0.12.16" material_color_utilities: dependency: transitive description: name: material_color_utilities - sha256: d92141dc6fe1dad30722f9aa826c7fbc896d021d792f80678280601aff8cf724 - url: "https://pub.dev" + sha256: "9528f2f296073ff54cb9fee677df673ace1218163c3bc7628093e7eed5203d41" + url: "https://pub.flutter-io.cn" source: hosted - version: "0.2.0" + version: "0.5.0" meta: dependency: transitive description: name: meta - sha256: "6c268b42ed578a53088d834796959e4a1814b5e9e164f147f580a386e5decf42" - url: "https://pub.dev" + sha256: "3c74dbf8763d36539f114c799d8a2d87343b5067e9d796ca22b5eb8437090ee3" + url: "https://pub.flutter-io.cn" + source: hosted + version: "1.9.1" + mime: + dependency: transitive + description: + name: mime + sha256: e4ff8e8564c03f255408decd16e7899da1733852a9110a58fe6d1b817684a63e + url: "https://pub.flutter-io.cn" source: hosted - version: "1.8.0" + version: "1.0.4" msix: dependency: "direct dev" description: name: msix - sha256: "9928b675aa7fbc25459250c76d1668518b2d0592f394498abd1f5744636b5d60" - url: "https://pub.dev" + sha256: "76c87b8207323803169626a55afd78bbb8413c984df349a76598b9fbf9224677" + url: "https://pub.flutter-io.cn" source: hosted - version: "3.6.6" + version: "3.16.1" nested: dependency: transitive description: name: nested sha256: "03bac4c528c64c95c722ec99280375a6f2fc708eec17c7b3f07253b626cd2a20" - url: "https://pub.dev" + url: "https://pub.flutter-io.cn" source: hosted version: "1.0.0" nm: @@ -737,396 +737,412 @@ packages: description: name: nm sha256: "2c9aae4127bdc8993206464fcc063611e0e36e72018696cd9631023a31b24254" - url: "https://pub.dev" + url: "https://pub.flutter-io.cn" source: hosted version: "0.5.0" - numerus: - dependency: transitive - description: - name: numerus - sha256: "436759d84f233b40107d0cc31cfa92d24e0960afeb2e506be70926d4cddffd9e" - url: "https://pub.dev" - source: hosted - version: "2.0.0" octo_image: dependency: transitive description: name: octo_image - sha256: a4d69f0677d742a5c76b26430aeae9420656226f8b6add0f3d9a7c6309f35012 - url: "https://pub.dev" + sha256: "107f3ed1330006a3bea63615e81cf637433f5135a52466c7caa0e7152bca9143" + url: "https://pub.flutter-io.cn" source: hosted - version: "1.0.1" + version: "1.0.2" package_config: dependency: transitive description: name: package_config - sha256: a4d5ede5ca9c3d88a2fef1147a078570c861714c806485c596b109819135bc12 - url: "https://pub.dev" + sha256: "1c5b77ccc91e4823a5af61ee74e6b972db1ef98c2ff5a18d3161c982a55448bd" + url: "https://pub.flutter-io.cn" source: hosted - version: "2.0.2" - path: + version: "2.1.0" + package_info_plus: + dependency: "direct main" + description: + name: package_info_plus + sha256: "6ff267fcd9d48cb61c8df74a82680e8b82e940231bb5f68356672fde0397334a" + url: "https://pub.flutter-io.cn" + source: hosted + version: "4.1.0" + package_info_plus_platform_interface: dependency: transitive description: - name: path - sha256: db9d4f58c908a4ba5953fcee2ae317c94889433e5024c27ce74a37f94267945b - url: "https://pub.dev" + name: package_info_plus_platform_interface + sha256: "9bc8ba46813a4cc42c66ab781470711781940780fd8beddd0c3da62506d3a6c6" + url: "https://pub.flutter-io.cn" source: hosted - version: "1.8.2" - path_drawing: + version: "2.0.1" + path: dependency: transitive description: - name: path_drawing - sha256: bbb1934c0cbb03091af082a6389ca2080345291ef07a5fa6d6e078ba8682f977 - url: "https://pub.dev" + name: path + sha256: "8829d8a55c13fc0e37127c29fedf290c102f4e40ae94ada574091fe0ff96c917" + url: "https://pub.flutter-io.cn" source: hosted - version: "1.0.1" + version: "1.8.3" path_parsing: dependency: transitive description: name: path_parsing sha256: e3e67b1629e6f7e8100b367d3db6ba6af4b1f0bb80f64db18ef1fbabd2fa9ccf - url: "https://pub.dev" + url: "https://pub.flutter-io.cn" source: hosted version: "1.0.1" path_provider: dependency: transitive description: name: path_provider - sha256: "3f6e0d697dc557ed6589107c8c13eda5ad488285917788379bbf392e3e30ea37" - url: "https://pub.dev" + sha256: a1aa8aaa2542a6bc57e381f132af822420216c80d4781f7aa085ca3229208aaa + url: "https://pub.flutter-io.cn" source: hosted - version: "2.0.10" + version: "2.1.1" path_provider_android: dependency: transitive description: name: path_provider_android - sha256: dfaa152e93c3a6fec632482928c770b2156dfb873582e99fbd6ac3b3de651d4c - url: "https://pub.dev" + sha256: "6b8b19bd80da4f11ce91b2d1fb931f3006911477cec227cce23d3253d80df3f1" + url: "https://pub.flutter-io.cn" source: hosted - version: "2.0.14" - path_provider_ios: + version: "2.2.0" + path_provider_foundation: dependency: transitive description: - name: path_provider_ios - sha256: "060ca9249d85bda6ee4ea2ecb3f4698a32f73183e0dee4f469bee8e146eadc1f" - url: "https://pub.dev" + name: path_provider_foundation + sha256: "19314d595120f82aca0ba62787d58dde2cc6b5df7d2f0daf72489e38d1b57f2d" + url: "https://pub.flutter-io.cn" source: hosted - version: "2.0.9" + version: "2.3.1" path_provider_linux: dependency: transitive description: name: path_provider_linux - sha256: ab0987bf95bc591da42dffb38c77398fc43309f0b9b894dcc5d6f40c4b26c379 - url: "https://pub.dev" + sha256: f7a1fe3a634fe7734c8d3f2766ad746ae2a2884abe22e241a8b301bf5cac3279 + url: "https://pub.flutter-io.cn" source: hosted - version: "2.1.7" - path_provider_macos: - dependency: transitive - description: - name: path_provider_macos - sha256: "2a97e7fbb7ae9dcd0dfc1220a78e9ec3e71da691912e617e8715ff2a13086ae8" - url: "https://pub.dev" - source: hosted - version: "2.0.6" + version: "2.2.1" path_provider_platform_interface: dependency: transitive description: name: path_provider_platform_interface - sha256: "27dc7a224fcd07444cb5e0e60423ccacea3e13cf00fc5282ac2c918132da931d" - url: "https://pub.dev" + sha256: "94b1e0dd80970c1ce43d5d4e050a9918fce4f4a775e6142424c30a29a363265c" + url: "https://pub.flutter-io.cn" source: hosted - version: "2.0.4" + version: "2.1.1" path_provider_windows: dependency: transitive description: name: path_provider_windows - sha256: bcabbe399d4042b8ee687e17548d5d3f527255253b4a639f5f8d2094a9c2b45c - url: "https://pub.dev" + sha256: "8bc9f22eee8690981c22aa7fc602f5c85b497a6fb2ceb35ee5a5e5ed85ad8170" + url: "https://pub.flutter-io.cn" source: hosted - version: "2.1.3" - pay: + version: "2.2.1" + percent_indicator: dependency: "direct main" description: - name: pay - sha256: "0edf4d43a96971cac312b57a2acb86eacee386509037f58af8b4058a5c21b8bb" - url: "https://pub.dev" + name: percent_indicator + sha256: c37099ad833a883c9d71782321cb65c3a848c21b6939b6185f0ff6640d05814c + url: "https://pub.flutter-io.cn" source: hosted - version: "1.1.0" - pay_android: - dependency: transitive - description: - name: pay_android - sha256: "13c9b0fd79e6e7afc674f09762e05e9856dd4ace6c315c5e331042ee1c1ea666" - url: "https://pub.dev" - source: hosted - version: "1.0.9" - pay_ios: - dependency: transitive - description: - name: pay_ios - sha256: "04c12e73d404e69f8a6e3cc0a3261d0b3980007a7bd6a2de2940b856d3de9d4c" - url: "https://pub.dev" - source: hosted - version: "1.0.8" - pay_platform_interface: - dependency: transitive - description: - name: pay_platform_interface - sha256: "12580f960066855d4821c4eaf2ef77093c0b20bce623db33104f76db16642e3b" - url: "https://pub.dev" - source: hosted - version: "1.0.3" - pedantic: - dependency: transitive - description: - name: pedantic - sha256: "67fc27ed9639506c856c840ccce7594d0bdcd91bc8d53d6e52359449a1d50602" - url: "https://pub.dev" - source: hosted - version: "1.11.1" + version: "4.2.3" petitparser: dependency: transitive description: name: petitparser - sha256: "2ebb289dc4764ec397f5cd3ca9881c6d17196130a7d646ed022a0dd9c2e25a71" - url: "https://pub.dev" + sha256: cb3798bef7fc021ac45b308f4b51208a152792445cce0448c9a4ba5879dd8750 + url: "https://pub.flutter-io.cn" source: hosted - version: "5.0.0" + version: "5.4.0" platform: dependency: transitive description: name: platform sha256: "4a451831508d7d6ca779f7ac6e212b4023dd5a7d08a27a63da33756410e32b76" - url: "https://pub.dev" + url: "https://pub.flutter-io.cn" source: hosted version: "3.1.0" plugin_platform_interface: dependency: transitive description: name: plugin_platform_interface - sha256: "075f927ebbab4262ace8d0b283929ac5410c0ac4e7fc123c76429564facfb757" - url: "https://pub.dev" + sha256: da3fdfeccc4d4ff2da8f8c556704c08f912542c5fb3cf2233ed75372384a034d + url: "https://pub.flutter-io.cn" source: hosted - version: "2.1.2" + version: "2.1.6" + pointycastle: + dependency: transitive + description: + name: pointycastle + sha256: "7c1e5f0d23c9016c5bbd8b1473d0d3fb3fc851b876046039509e18e0c7485f2c" + url: "https://pub.flutter-io.cn" + source: hosted + version: "3.7.3" + pool: + dependency: transitive + description: + name: pool + sha256: "20fe868b6314b322ea036ba325e6fc0711a22948856475e2c2b6306e8ab39c2a" + url: "https://pub.flutter-io.cn" + source: hosted + version: "1.5.1" process: dependency: transitive description: name: process sha256: "53fd8db9cec1d37b0574e12f07520d582019cb6c44abf5479a01505099a34a09" - url: "https://pub.dev" + url: "https://pub.flutter-io.cn" source: hosted version: "4.2.4" provider: dependency: transitive description: name: provider - sha256: "8d7d4c2df46d6a6270a4e10404bfecb18a937e3e00f710c260d0a10415ce6b7b" - url: "https://pub.dev" + sha256: cdbe7530b12ecd9eb455bdaa2fcb8d4dad22e80b8afb4798b41479d5ce26847f + url: "https://pub.flutter-io.cn" source: hosted - version: "6.0.3" + version: "6.0.5" pub_semver: dependency: transitive description: name: pub_semver - sha256: "816c1a640e952d213ddd223b3e7aafae08cd9f8e1f6864eed304cc13b0272b07" - url: "https://pub.dev" + sha256: "40d3ab1bbd474c4c2328c91e3a7df8c6dd629b79ece4c4bd04bee496a224fb0c" + url: "https://pub.flutter-io.cn" source: hosted - version: "2.1.1" + version: "2.1.4" pubspec_parse: dependency: transitive description: name: pubspec_parse - sha256: "3686efe4a4613a4449b1a4ae08670aadbd3376f2e78d93e3f8f0919db02a7256" - url: "https://pub.dev" + sha256: c63b2876e58e194e4b0828fcb080ad0e06d051cb607a6be51a9e084f47cb9367 + url: "https://pub.flutter-io.cn" source: hosted - version: "1.2.0" + version: "1.2.3" responsive_framework: dependency: "direct main" description: name: responsive_framework - sha256: e083346029b008335b008274c4d3fac5b9e0ca8796f201ed20884f579101d584 - url: "https://pub.dev" + sha256: "97d4a8b9468c0ecaafe8566645d70cc59480e4b03704a1b936396e68775e2c34" + url: "https://pub.flutter-io.cn" source: hosted - version: "0.2.0" + version: "1.1.0" riverpod: dependency: transitive description: name: riverpod - sha256: "0f43c64f1f79c2112c843305a879a746587fb7c1e388f1d4717737796756e2c4" - url: "https://pub.dev" + sha256: a600120d6f213a9922860eea1abc32597436edd5b2c4e73b91410f8c2af67d22 + url: "https://pub.flutter-io.cn" source: hosted - version: "2.1.3" + version: "2.4.0" + riverpod_analyzer_utils: + dependency: transitive + description: + name: riverpod_analyzer_utils + sha256: aa216069d72f5478126029fa555874b4b38119f17e3f0f6c93fd63365f74502d + url: "https://pub.flutter-io.cn" + source: hosted + version: "0.3.3" riverpod_annotation: dependency: transitive description: name: riverpod_annotation - sha256: "13c414f7af300d9e73811ae24de5599df6609863e90266070d55a072f8bab045" - url: "https://pub.dev" + sha256: "6294fe7e7d1875f32bdf04c8fce7620e718070273703097847df8f3bf16995ea" + url: "https://pub.flutter-io.cn" source: hosted - version: "1.1.1" + version: "2.1.5" riverpod_generator: - dependency: "direct main" + dependency: "direct dev" description: name: riverpod_generator - sha256: e87363e27dd8bce40a194c2ba6a7630ee343826d7a4500d70f7f729ea8e27d50 - url: "https://pub.dev" + sha256: d132b1ccb476e60f99989caa6ba9b1c4d88409806c93d880d1633c60c382454d + url: "https://pub.flutter-io.cn" source: hosted - version: "1.1.1" + version: "2.3.2" rxdart: dependency: transitive description: name: rxdart - sha256: bc2d2b17b87fab32e2dca53ca3066d3147de6f96c74d76cfe1a379a24239c46d - url: "https://pub.dev" + sha256: "0c7c0cedd93788d996e33041ffecda924cc54389199cde4e6a34b440f50044cb" + url: "https://pub.flutter-io.cn" source: hosted - version: "0.27.3" + version: "0.27.7" screen_retriever: dependency: transitive description: name: screen_retriever - sha256: "9c3839c4eb80807cd8210afa3c84a177ba00aef9f9b7b74ad92d3a0ab1d7e7ed" - url: "https://pub.dev" + sha256: "6ee02c8a1158e6dae7ca430da79436e3b1c9563c8cf02f524af997c201ac2b90" + url: "https://pub.flutter-io.cn" source: hosted - version: "0.1.5" + version: "0.1.9" shared_preferences: dependency: "direct main" description: name: shared_preferences - sha256: "5949029e70abe87f75cfe59d17bf5c397619c4b74a099b10116baeb34786fad9" - url: "https://pub.dev" + sha256: b7f41bad7e521d205998772545de63ff4e6c97714775902c199353f8bf1511ac + url: "https://pub.flutter-io.cn" source: hosted - version: "2.0.17" + version: "2.2.1" shared_preferences_android: dependency: transitive description: name: shared_preferences_android - sha256: "853801ce6ba7429ec4e923e37317f32a57c903de50b8c33ffcfbdb7e6f0dd39c" - url: "https://pub.dev" + sha256: fe8401ec5b6dcd739a0fe9588802069e608c3fdbfd3c3c93e546cf2f90438076 + url: "https://pub.flutter-io.cn" source: hosted - version: "2.0.12" + version: "2.2.0" shared_preferences_foundation: dependency: transitive description: name: shared_preferences_foundation - sha256: "2b55c18636a4edc529fa5cd44c03d3f3100c00513f518c5127c951978efcccd0" - url: "https://pub.dev" + sha256: d29753996d8eb8f7619a1f13df6ce65e34bc107bef6330739ed76f18b22310ef + url: "https://pub.flutter-io.cn" source: hosted - version: "2.1.3" + version: "2.3.3" shared_preferences_linux: dependency: transitive description: name: shared_preferences_linux - sha256: "28aefc1261746e7bad3d09799496054beb84e8c4ffcdfed7734e17b4ada459a5" - url: "https://pub.dev" + sha256: "71d6806d1449b0a9d4e85e0c7a917771e672a3d5dc61149cc9fac871115018e1" + url: "https://pub.flutter-io.cn" source: hosted - version: "2.1.1" + version: "2.3.0" shared_preferences_platform_interface: dependency: transitive description: name: shared_preferences_platform_interface - sha256: "992f0fdc46d0a3c0ac2e5859f2de0e577bbe51f78a77ee8f357cbe626a2ad32d" - url: "https://pub.dev" + sha256: "23b052f17a25b90ff2b61aad4cc962154da76fb62848a9ce088efe30d7c50ab1" + url: "https://pub.flutter-io.cn" source: hosted - version: "2.0.0" + version: "2.3.0" shared_preferences_web: dependency: transitive description: name: shared_preferences_web - sha256: a4b5bc37fe1b368bbc81f953197d55e12f49d0296e7e412dfe2d2d77d6929958 - url: "https://pub.dev" + sha256: "7347b194fb0bbeb4058e6a4e87ee70350b6b2b90f8ac5f8bd5b3a01548f6d33a" + url: "https://pub.flutter-io.cn" source: hosted - version: "2.0.4" + version: "2.2.0" shared_preferences_windows: dependency: transitive description: name: shared_preferences_windows - sha256: "97f7ab9a7da96d9cf19581f5de520ceb529548498bd6b5e0ccd02d68a0d15eba" - url: "https://pub.dev" + sha256: f95e6a43162bce43c9c3405f3eb6f39e5b5d11f65fab19196cf8225e2777624d + url: "https://pub.flutter-io.cn" source: hosted - version: "2.1.1" + version: "2.3.0" + shelf: + dependency: transitive + description: + name: shelf + sha256: ad29c505aee705f41a4d8963641f91ac4cee3c8fad5947e033390a7bd8180fa4 + url: "https://pub.flutter-io.cn" + source: hosted + version: "1.4.1" + shelf_web_socket: + dependency: transitive + description: + name: shelf_web_socket + sha256: "9ca081be41c60190ebcb4766b2486a7d50261db7bd0f5d9615f2d653637a84c1" + url: "https://pub.flutter-io.cn" + source: hosted + version: "1.0.4" sky_engine: dependency: transitive description: flutter source: sdk version: "0.0.99" + sliding_up_panel2: + dependency: "direct main" + description: + name: sliding_up_panel2 + sha256: "7c2aac81c03e74fcd070799c5e2011f1c5de7026bd22a76164e81e23a49f2bdb" + url: "https://pub.flutter-io.cn" + source: hosted + version: "3.3.0+1" sliver_tools: dependency: transitive description: name: sliver_tools - sha256: edf005f1a47c2ffa6f1e1a4f24dd99c45b8bccfff9b928d39170d36dc6fda871 - url: "https://pub.dev" + sha256: eae28220badfb9d0559207badcbbc9ad5331aac829a88cb0964d330d2a4636a6 + url: "https://pub.flutter-io.cn" source: hosted - version: "0.2.8" + version: "0.2.12" source_gen: dependency: transitive description: name: source_gen - sha256: "2d79738b6bbf38a43920e2b8d189e9a3ce6cc201f4b8fc76be5e4fe377b1c38d" - url: "https://pub.dev" + sha256: fc0da689e5302edb6177fdd964efcb7f58912f43c28c2047a808f5bfff643d16 + url: "https://pub.flutter-io.cn" source: hosted - version: "1.2.6" + version: "1.4.0" source_helper: dependency: transitive description: name: source_helper - sha256: "3b67aade1d52416149c633ba1bb36df44d97c6b51830c2198e934e3fca87ca1f" - url: "https://pub.dev" + sha256: "6adebc0006c37dd63fe05bca0a929b99f06402fc95aa35bf36d67f5c06de01fd" + url: "https://pub.flutter-io.cn" source: hosted - version: "1.3.3" + version: "1.3.4" source_span: dependency: transitive description: name: source_span - sha256: dd904f795d4b4f3b870833847c461801f6750a9fa8e61ea5ac53f9422b31f250 - url: "https://pub.dev" + sha256: "53e943d4206a5e30df338fd4c6e7a077e02254531b138a15aec3bd143c1a8b3c" + url: "https://pub.flutter-io.cn" source: hosted - version: "1.9.1" + version: "1.10.0" sqflite: dependency: transitive description: name: sqflite - sha256: "51c09d414ca74b1cd4a5880d63763ebd2033a4fc6d921708c7c1e98c603735d4" - url: "https://pub.dev" + sha256: "591f1602816e9c31377d5f008c2d9ef7b8aca8941c3f89cc5fd9d84da0c38a9a" + url: "https://pub.flutter-io.cn" source: hosted - version: "2.0.2+1" + version: "2.3.0" sqflite_common: dependency: transitive description: name: sqflite_common - sha256: b504fc5b4576a05586a0bb99d9bcc0d37a78d9d5ed68b96c361d5d3a8e538275 - url: "https://pub.dev" + sha256: "1b92f368f44b0dee2425bb861cfa17b6f6cf3961f762ff6f941d20b33355660a" + url: "https://pub.flutter-io.cn" source: hosted - version: "2.2.1+1" + version: "2.5.0" stack_trace: dependency: transitive description: name: stack_trace sha256: c3c7d8edb15bee7f0f74debd4b9c5f3c2ea86766fe4178eb2a18eb30a0bdaed5 - url: "https://pub.dev" + url: "https://pub.flutter-io.cn" source: hosted version: "1.11.0" state_notifier: dependency: transitive description: name: state_notifier - sha256: "8fe42610f179b843b12371e40db58c9444f8757f8b69d181c97e50787caed289" - url: "https://pub.dev" + sha256: b8677376aa54f2d7c58280d5a007f9e8774f1968d1fb1c096adcb4792fba29bb + url: "https://pub.flutter-io.cn" source: hosted - version: "0.7.2+1" + version: "1.0.0" stream_channel: dependency: transitive description: name: stream_channel sha256: "83615bee9045c1d322bbbd1ba209b7a749c2cbcdcb3fdd1df8eb488b3279c1c8" - url: "https://pub.dev" + url: "https://pub.flutter-io.cn" source: hosted version: "2.1.1" + stream_transform: + dependency: transitive + description: + name: stream_transform + sha256: "14a00e794c7c11aa145a170587321aedce29769c08d7f58b1d141da75e3b1c6f" + url: "https://pub.flutter-io.cn" + source: hosted + version: "2.1.0" string_scanner: dependency: transitive description: name: string_scanner sha256: "556692adab6cfa87322a115640c11f13cb77b3f076ddcc5d6ae3c20242bedcde" - url: "https://pub.dev" + url: "https://pub.flutter-io.cn" source: hosted version: "1.2.0" sync_http: @@ -1134,249 +1150,289 @@ packages: description: name: sync_http sha256: "7f0cd72eca000d2e026bcd6f990b81d0ca06022ef4e32fb257b30d3d1014a961" - url: "https://pub.dev" + url: "https://pub.flutter-io.cn" source: hosted version: "0.3.1" synchronized: dependency: transitive description: name: synchronized - sha256: a7f0790927c0806ae0d5eb061c713748fa6070ef0037e391a2d53c3844c09dc2 - url: "https://pub.dev" + sha256: "5fcbd27688af6082f5abd611af56ee575342c30e87541d0245f7ff99faa02c60" + url: "https://pub.flutter-io.cn" source: hosted - version: "3.0.0+2" + version: "3.1.0" term_glyph: dependency: transitive description: name: term_glyph sha256: a29248a84fbb7c79282b40b8c72a1209db169a2e0542bce341da992fe1bc7e84 - url: "https://pub.dev" + url: "https://pub.flutter-io.cn" 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" - tflite: - dependency: "direct main" - description: - name: tflite - sha256: "661f8942a0e8ca05fedf554cc6f9cc95f526d0e4588d1665e0eb4d29e25e69b1" - url: "https://pub.dev" + sha256: "75760ffd7786fffdfb9597c35c5b27eaeec82be8edfb6d71d32651128ed7aab8" + url: "https://pub.flutter-io.cn" source: hosted - version: "1.1.2" + version: "0.6.0" timezone: dependency: transitive description: name: timezone - sha256: "2e59efc48e9f684c327c0498ac0b81411aee18b10c82f2db2c08f7f052493569" - url: "https://pub.dev" + sha256: "1cfd8ddc2d1cfd836bc93e67b9be88c3adaeca6f40a00ca999104c30693cdca0" + url: "https://pub.flutter-io.cn" source: hosted - version: "0.9.0" + version: "0.9.2" + timing: + dependency: transitive + description: + name: timing + sha256: "70a3b636575d4163c477e6de42f247a23b315ae20e86442bebe32d3cabf61c32" + url: "https://pub.flutter-io.cn" + source: hosted + version: "1.0.1" typed_data: dependency: transitive description: name: typed_data - sha256: "26f87ade979c47a150c9eaab93ccd2bebe70a27dc0b4b29517f2904f04eb11a5" - url: "https://pub.dev" + sha256: facc8d6582f16042dd49f2463ff1bd6e2c9ef9f3d5da3d9b087e244a7b564b3c + url: "https://pub.flutter-io.cn" source: hosted - version: "1.3.1" + version: "1.3.2" universal_io: dependency: transitive description: name: universal_io - sha256: "79f78ddad839ee3aae3ec7c01eb4575faf0d5c860f8e5223bc9f9c17f7f03cef" - url: "https://pub.dev" + sha256: "1722b2dcc462b4b2f3ee7d188dad008b6eb4c40bbd03a3de451d82c78bba9aad" + url: "https://pub.flutter-io.cn" source: hosted - version: "2.0.4" + version: "2.2.2" url_launcher: dependency: "direct main" description: name: url_launcher - sha256: "698fa0b4392effdc73e9e184403b627362eb5fbf904483ac9defbb1c2191d809" - url: "https://pub.dev" + sha256: "47e208a6711459d813ba18af120d9663c20bdf6985d6ad39fe165d2538378d27" + url: "https://pub.flutter-io.cn" source: hosted - version: "6.1.8" + version: "6.1.14" url_launcher_android: dependency: transitive description: name: url_launcher_android - sha256: "1ccd353c1bff66b49863527c02759f4d06b92744bd9777c96a00ca6a9e8e1d2f" - url: "https://pub.dev" + sha256: b04af59516ab45762b2ca6da40fa830d72d0f6045cd97744450b73493fa76330 + url: "https://pub.flutter-io.cn" source: hosted - version: "6.0.17" + version: "6.1.0" url_launcher_ios: dependency: transitive description: name: url_launcher_ios - sha256: "9ef5f323cfc5e80c1cad254e4602e6be64e9933de63717c7d05944c596b4ee9a" - url: "https://pub.dev" + sha256: "9af7ea73259886b92199f9e42c116072f05ff9bea2dcb339ab935dfc957392c2" + url: "https://pub.flutter-io.cn" source: hosted - version: "6.0.16" + version: "6.1.4" url_launcher_linux: dependency: transitive description: name: url_launcher_linux - sha256: "360fa359ab06bcb4f7c5cd3123a2a9a4d3364d4575d27c4b33468bd4497dd094" - url: "https://pub.dev" + sha256: "207f4ddda99b95b4d4868320a352d374b0b7e05eefad95a4a26f57da413443f5" + url: "https://pub.flutter-io.cn" source: hosted - version: "3.0.1" + version: "3.0.5" url_launcher_macos: dependency: transitive description: name: url_launcher_macos - sha256: a9b3ea9043eabfaadfa3fb89de67a11210d85569086d22b3854484beab8b3978 - url: "https://pub.dev" + sha256: "1c4fdc0bfea61a70792ce97157e5cc17260f61abbe4f39354513f39ec6fd73b1" + url: "https://pub.flutter-io.cn" source: hosted - version: "3.0.1" + version: "3.0.6" url_launcher_platform_interface: dependency: transitive description: name: url_launcher_platform_interface - sha256: "80b860b31a11ebbcbe51b8fe887efc204f3af91522f3b51bcda4622d276d2120" - url: "https://pub.dev" + sha256: "95465b39f83bfe95fcb9d174829d6476216f2d548b79c38ab2506e0458787618" + url: "https://pub.flutter-io.cn" source: hosted - version: "2.1.0" + version: "2.1.5" url_launcher_web: dependency: transitive description: name: url_launcher_web - sha256: "1c7d34f93353de7f7ad9cb239e8b1e680e759b73845d4970dedc4e0a926e9abe" - url: "https://pub.dev" + sha256: "2942294a500b4fa0b918685aff406773ba0a4cd34b7f42198742a94083020ce5" + url: "https://pub.flutter-io.cn" source: hosted - version: "2.0.11" + version: "2.0.20" url_launcher_windows: dependency: transitive description: name: url_launcher_windows - sha256: e3c3b16d3104260c10eea3b0e34272aaa57921f83148b0619f74c2eced9b7ef1 - url: "https://pub.dev" + sha256: "7967065dd2b5fccc18c653b97958fdf839c5478c28e767c61ee879f4e7882422" + url: "https://pub.flutter-io.cn" source: hosted - version: "3.0.1" + version: "3.0.7" uuid: dependency: transitive description: name: uuid - sha256: "2469694ad079893e3b434a627970c33f2fa5adc46dfe03c9617546969a9a8afc" - url: "https://pub.dev" + sha256: "648e103079f7c64a36dc7d39369cabb358d377078a051d6ae2ad3aa539519313" + url: "https://pub.flutter-io.cn" source: hosted - version: "3.0.6" + version: "3.0.7" + vector_graphics: + dependency: transitive + description: + name: vector_graphics + sha256: "670f6e07aca990b4a2bcdc08a784193c4ccdd1932620244c3a86bb72a0eac67f" + url: "https://pub.flutter-io.cn" + source: hosted + version: "1.1.7" + vector_graphics_codec: + dependency: transitive + description: + name: vector_graphics_codec + sha256: "7451721781d967db9933b63f5733b1c4533022c0ba373a01bdd79d1a5457f69f" + url: "https://pub.flutter-io.cn" + source: hosted + version: "1.1.7" + vector_graphics_compiler: + dependency: transitive + description: + name: vector_graphics_compiler + sha256: "80a13c613c8bde758b1464a1755a7b3a8f2b6cec61fbf0f5a53c94c30f03ba2e" + url: "https://pub.flutter-io.cn" + source: hosted + version: "1.1.7" vector_math: dependency: transitive description: name: vector_math sha256: "80b3257d1492ce4d091729e3a67a60407d227c27241d6927be0130c98e741803" - url: "https://pub.dev" + url: "https://pub.flutter-io.cn" source: hosted version: "2.1.4" - visibility_detector: - dependency: transitive - description: - name: visibility_detector - sha256: "15c54a459ec2c17b4705450483f3d5a2858e733aee893dcee9d75fd04814940d" - url: "https://pub.dev" - source: hosted - version: "0.3.3" vm_service: dependency: transitive description: name: vm_service - sha256: e7fb6c2282f7631712b69c19d1bff82f3767eea33a2321c14fa59ad67ea391c7 - url: "https://pub.dev" + sha256: c620a6f783fa22436da68e42db7ebbf18b8c44b9a46ab911f666ff09ffd9153f + url: "https://pub.flutter-io.cn" source: hosted - version: "9.4.0" + version: "11.7.1" watcher: dependency: transitive description: name: watcher - sha256: e42dfcc48f67618344da967b10f62de57e04bae01d9d3af4c2596f3712a88c99 - url: "https://pub.dev" + sha256: "3d2ad6751b3c16cf07c7fca317a1413b3f26530319181b37e3b9039b84fc01d8" + url: "https://pub.flutter-io.cn" source: hosted - version: "1.0.1" + version: "1.1.0" + web: + dependency: transitive + description: + name: web + sha256: dc8ccd225a2005c1be616fe02951e2e342092edf968cf0844220383757ef8f10 + url: "https://pub.flutter-io.cn" + source: hosted + version: "0.1.4-beta" + web_socket_channel: + dependency: transitive + description: + name: web_socket_channel + sha256: d88238e5eac9a42bb43ca4e721edba3c08c6354d4a53063afaa568516217621b + url: "https://pub.flutter-io.cn" + source: hosted + version: "2.4.0" webdriver: dependency: transitive description: name: webdriver - sha256: ef67178f0cc7e32c1494645b11639dd1335f1d18814aa8435113a92e9ef9d841 - url: "https://pub.dev" + sha256: "3c923e918918feeb90c4c9fdf1fe39220fa4c0e8e2c0fffaded174498ef86c49" + url: "https://pub.flutter-io.cn" source: hosted - version: "3.0.1" + version: "3.0.2" webview_flutter: dependency: "direct main" description: name: webview_flutter - sha256: f7ec234830f86d0ef2bd664e8460b0038b8c1a83ff076035cad74ac70273753c - url: "https://pub.dev" + sha256: "04a0782fb058b7c71f2048935583488f4d32e9147ca403abc4e58f1de9964629" + url: "https://pub.flutter-io.cn" source: hosted - version: "4.0.2" + version: "4.2.3" webview_flutter_android: dependency: transitive description: name: webview_flutter_android - sha256: "5f49a6e5fc59e21fcec5e1bbcd401afbee9792a24a4f3d9cef9b5bb0cd1e3767" - url: "https://pub.dev" + sha256: "9427774649fd3c8b7ff53523051395d13aed2ca355822b822e6493d79f5fc05a" + url: "https://pub.flutter-io.cn" source: hosted - version: "3.2.4" + version: "3.10.0" webview_flutter_platform_interface: dependency: transitive description: name: webview_flutter_platform_interface - sha256: "8b2262dda5d26eabc600a7282a8c16a9473a0c765526afb0ffc33eef912f7968" - url: "https://pub.dev" + sha256: "6d9213c65f1060116757a7c473247c60f3f7f332cac33dc417c9e362a9a13e4f" + url: "https://pub.flutter-io.cn" source: hosted - version: "2.0.1" + version: "2.6.0" webview_flutter_wkwebview: dependency: transitive description: name: webview_flutter_wkwebview - sha256: "92e7e7fa468f1df597fb9d37bcf1f303175cbe147c4dbdf06ecc323d950116eb" - url: "https://pub.dev" + sha256: ed749f94ac9e814d04a258a9255cf69cfa4cc6006ff59542aea7fb4590144972 + url: "https://pub.flutter-io.cn" source: hosted - version: "3.0.5" + version: "3.7.3" win32: dependency: transitive description: name: win32 - sha256: "9555cd63283445e101f0df32105862fdc0b30adb9b84fd0553e9433b3e074d4c" - url: "https://pub.dev" + sha256: "9e82a402b7f3d518fb9c02d0e9ae45952df31b9bf34d77baf19da2de03fc2aaa" + url: "https://pub.flutter-io.cn" + source: hosted + version: "5.0.7" + win32_registry: + dependency: transitive + description: + name: win32_registry + sha256: e4506d60b7244251bc59df15656a3093501c37fb5af02105a944d73eb95be4c9 + url: "https://pub.flutter-io.cn" source: hosted - version: "3.0.1" + version: "1.1.1" window_manager: dependency: "direct main" description: name: window_manager - sha256: "5bdd29dc5f1f3185fc90696373a571d77968e03e5e820fb1ecdbdade3f5d8fff" - url: "https://pub.dev" + sha256: "6ee795be9124f90660ea9d05e581a466de19e1c89ee74fc4bf528f60c8600edd" + url: "https://pub.flutter-io.cn" source: hosted - version: "0.3.0" + version: "0.3.6" xdg_directories: dependency: transitive description: name: xdg_directories - sha256: "060b6e1c891d956f72b5ac9463466c37cce3fa962a921532fc001e86fe93438e" - url: "https://pub.dev" + sha256: f0c26453a2d47aa4c2570c6a033246a3fc62da2fe23c7ffdd0a7495086dc0247 + url: "https://pub.flutter-io.cn" source: hosted - version: "0.2.0+1" + version: "1.0.2" xml: dependency: transitive description: name: xml - sha256: ac0e3f4bf00ba2708c33fbabbbe766300e509f8c82dbd4ab6525039813f7e2fb - url: "https://pub.dev" + sha256: "5bc72e1e45e941d825fd7468b9b4cc3b9327942649aeb6fc5cdbf135f0a86e84" + url: "https://pub.flutter-io.cn" source: hosted - version: "6.1.0" + version: "6.3.0" yaml: dependency: transitive description: name: yaml - sha256: "23812a9b125b48d4007117254bca50abb6c712352927eece9e155207b1db2370" - url: "https://pub.dev" + sha256: "75769501ea3489fca56601ff33454fe45507ea3bfb014161abc3b43ae25989d5" + url: "https://pub.flutter-io.cn" source: hosted - version: "3.1.1" + version: "3.1.2" sdks: - dart: ">=2.19.1 <3.0.0" - flutter: ">=3.3.0" + dart: ">=3.1.0 <4.0.0" + flutter: ">=3.13.0" diff --git a/pubspec.yaml b/pubspec.yaml index 9b7dabc..2280024 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -11,58 +11,56 @@ description: A Healthcare and Food planner App # In iOS, build-name is used as CFBundleShortVersionString while build-number used as CFBundleVersion. # Read more about iOS versioning at # https://developer.apple.com/library/archive/documentation/General/Reference/InfoPlistKeyReference/Articles/CoreFoundationKeys.html -version: 8.5.0+23 +version: 9.0.0+26 environment: - sdk: '>=2.19.1 <3.0.0' + sdk: '>=3.0.0 <4.0.0' dependencies: flutter: sdk: flutter + flutter_localizations: + sdk: flutter concentric_transition: ^1.0.3 - font_awesome_flutter: ^10.2.1 - http: ^0.13.5 - shared_preferences: ^2.0.17 - url_launcher: ^6.1.8 - hooks_riverpod: ^2.1.3 - flutter_svg: ^1.0.0 - window_manager: ^0.3.0 - flutter_local_notifications: ^13.0.0 - flutter_native_timezone: ^2.0.0 - connectivity_plus: ^3.0.2 + http: ^0.13.6 + shared_preferences: ^2.1.1 + url_launcher: ^6.1.11 + hooks_riverpod: ^2.3.6 + flutter_svg: ^2.0.5 + window_manager: ^0.3.2 + flutter_local_notifications: ^14.0.0+2 + connectivity_plus: ^4.0.0 cached_network_image: ^3.2.3 freezed_annotation: ^2.2.0 - google_mobile_ads: ^2.3.0 - responsive_framework: ^0.2.0 - go_router: ^6.0.3 - easy_localization: ^3.0.1 - pay: ^1.1.0 - webview_flutter: ^4.0.2 - lottie: ^2.2.0 - tflite: ^1.1.2 - image_picker: ^0.8.6+1 - image_cropper: ^3.0.1 + responsive_framework: ^1.0.0 + go_router: ^7.0.0 + webview_flutter: ^4.2.0 animations: ^2.0.7 flutter_html: ^3.0.0-alpha.6 - iconsax: ^0.0.8 - json_annotation: ^4.8.0 - device_preview: ^1.1.0 - flutter_switch: ^0.3.2 - google_fonts: ^4.0.3 - fluentui_icons: ^1.0.0 - flutter_hooks: ^0.18.5+1 - riverpod_generator: ^1.1.1 + json_annotation: ^4.8.1 + flutter_hooks: ^0.18.6 infinite_scroll_pagination: ^3.2.0 - device_info_plus: ^8.0.0 - + device_info_plus: ^9.0.0 + package_info_plus: ^4.0.0 + # ota_update: ^4.0.3 + custom_sliding_segmented_control: ^1.7.4 + dynamic_color: ^1.6.3 + gradient_borders: ^1.0.0 + intl: ^0.18.0 + sliding_up_panel2: ^3.3.0+1 + percent_indicator: ^4.2.3 dev_dependencies: - json_serializable: ^6.6.1 - flutter_native_splash: ^2.2.16 - freezed: ^2.3.2 + analyzer: ^5.10.0 + json_serializable: ^6.6.2 + build_runner: ^2.4.2 + flutter_native_splash: ^2.2.19 + freezed: ^2.3.3 flutter_lints: ^2.0.1 - msix: ^3.6.0 + msix: ^3.12.0 + riverpod_generator: ^2.2.1 + device_preview: ^1.1.0 flutter_test: sdk: flutter @@ -89,21 +87,18 @@ flutter: # included with your application, so that you can use the icons in # the material Icons class. uses-material-design: true + generate: true # To add assets to your application, add an assets section, like this: assets: - assets/ - assets/images/loading/ - assets/images/welcome/ - - assets/images/windows/ - assets/images/onboarding/ - assets/images/recipes/ - assets/images/icon/ - assets/images/icons/ - assets/images/network/ - assets/images/profile/ - - assets/images/difficulty/ - - assets/translations/ - - assets/model/ diff --git a/windows/flutter/generated_plugin_registrant.cc b/windows/flutter/generated_plugin_registrant.cc index a02965d..6348d84 100644 --- a/windows/flutter/generated_plugin_registrant.cc +++ b/windows/flutter/generated_plugin_registrant.cc @@ -7,6 +7,7 @@ #include "generated_plugin_registrant.h" #include +#include #include #include #include @@ -14,6 +15,8 @@ void RegisterPlugins(flutter::PluginRegistry* registry) { ConnectivityPlusWindowsPluginRegisterWithRegistrar( registry->GetRegistrarForPlugin("ConnectivityPlusWindowsPlugin")); + DynamicColorPluginCApiRegisterWithRegistrar( + registry->GetRegistrarForPlugin("DynamicColorPluginCApi")); ScreenRetrieverPluginRegisterWithRegistrar( registry->GetRegistrarForPlugin("ScreenRetrieverPlugin")); UrlLauncherWindowsRegisterWithRegistrar( diff --git a/windows/flutter/generated_plugins.cmake b/windows/flutter/generated_plugins.cmake index 7f07c2c..1dd5270 100644 --- a/windows/flutter/generated_plugins.cmake +++ b/windows/flutter/generated_plugins.cmake @@ -4,6 +4,7 @@ list(APPEND FLUTTER_PLUGIN_LIST connectivity_plus + dynamic_color screen_retriever url_launcher_windows window_manager