بحث باسم الموضوع المطلوب

كيفية التبديل بين الوضع الداكن والفاتح في Flutter باستخدام Bloc,

 إن السماح للمستخدمين بالتبديل بين الوضع الداكن والوضع الفاتح في تطبيق Flutter أمر ضروري في الوقت الحاضر. في هذا المنشور، ستتعلم كيفية تغيير السمات في Flutter باستخدام Bloc مع Cubits. يضمن Bloc أن التطبيق يفتح دائمًا بالسمات التي يختارها المستخدم. بدلاً من استخدام فئات Bloc العادية، يمكننا تحقيق الوظيفة المطلوبة باستخدام cubits مما يجعل التنفيذ أبسط كثيرًا.

تثبيت الحزم للتبديل بين الوضع الداكن والفاتح في Flutter

لكي يصبح من الممكن التبديل بين الوضع الداكن والوضع الفاتح في Flutter باستخدام Bloc with cubits، نحتاج إلى تثبيت حزمة  https://pub.dev/packages/flutter_blocFlutter Bloc مع حزمة https://pub.dev/packages/shared_preferences Shared Preferences و https://pub.dev/packages/equatable Equatable . يمكن القيام بذلك عن طريق تنفيذ الأمر التالي داخل مشروعك:


بعد تنفيذ الأمر، تحقق من  pubspec.yaml ملفك بحثًا عن التبعيات المضافة. يجب أن ترى حزم Flutter Bloc وShared Preferences وEquatable المضمنة في الشكل  dependenciesالتالي:


إنشاء المجلدات والملفات
لتسهيل المتابعة، دعنا نبدأ بإنشاء المجلد والملفات التي سنستخدمها أثناء هذا البرنامج التعليمي. أولاً، سننشئ مجلدًا لضمان وجود جميع الملفات المتعلقة بالموضوع في مكان واحد. بعد إنشاء المجلد، themeيمكننا إنشاء المجلدات الفرعية cubitsو repositories. داخل cubitsالمجلد سيكون لدينا ملفان: theme_cubit.dartو theme_state.dart. في repositoriesالمجلد، سيكون لدينا theme_repository.dartالملف.


بعد إنشاء كافة المجلدات والملفات يمكننا الاستمرار من خلال تنفيذ وظيفة تبديل السمة.

التبديل بين الوضع الداكن والوضع الفاتح في Flutter باستخدام Bloc With Cubits

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

إنشاء فئة ThemeRepository

داخل ThemeRepositoryالفصل سيكون لدينا دالتين، ستكون الدالة الأولى مسؤولة عن الحصول على السمة الحالية وستكون الدالة الأخرى مسؤولة عن تعيين السمة.

في مقتطف التعليمات البرمجية، قمنا بإنشاء ThemeRepositoryفئة. داخل هذه الفئة، لدينا وظيفة getThemeلاسترداد السمة الحالية من SharedPreferencesاستخدام getBoolالوظيفة مع المفتاح "isDarkTheme". إذا getBoolأعادت الوظيفة قيمة null، فإننا نضبط القيمة الأولية لسمة جهاز المستخدم باستخدام SchedulerBinding.instance.platformDispatcher.platformBrightnessgetter.



في الكود أعلاه، قمنا بإنشاء ThemeStateفئة تمتد إلى Equatableالفئة. الامتداد مطلوب لضمان إمكانية مقارنة مثيلات الفئة ThemeStateمع بعضها البعض لتحديد التغييرات. ThemeStateتحتوي الفئة على سمة واحدة themeModeسيتم استخدامها لتخزين السمة الحالية.

لاحظ أيضًا أن theme_state.dartالملف جزء من theme_cubit.dartالملف. وبالتالي، تتم جميع عمليات الاستيراد داخل theme_cubit.dartالملف.

نظرًا لأن theme_state.dartالملف جزء من theme_cubit.dartالملف، فمن المحتمل أن يعرض برنامج IDE الخاص بك الكثير من الخطوط الحمراء. سيتم إصلاح هذا الأمر بمجرد الانتهاء من إنشاء الفصل ThemeCubit.


إنشاء فئة ThemeCubit

ستحتوي الفئة ThemeCubitعلى دالتين سنقوم باستدعائهما داخل أدواتنا للحصول على السمة الحالية أو لتغيير السمة.


في مقتطف التعليمات البرمجية أعلاه، نقوم بإنشاء ThemeCubitالفئة التي توسع Cubitالفئة بنوع ThemeState. ThemeCubitتحتوي الفئة على منشئ يأخذ مثيلًا من ThemeRepositoryالفئة. بخلاف ذلك، لدينا _isDarkThemeمتغير يستخدم لتتبع السمة الحالية ولدينا دالتان.


الدالة الأولى هي getCurrentThemeالدالة التي تستدعي getThemeالدالة من ThemeRepositoryالفصل. بناءً على نتيجة الدالة، getThemeنقوم بتعيين _isDarkThemeالمتغير وتحديث الحالة بالحالة الحالية ThemeModeباستخدام emitالدالة.


الوظيفة الثانية switchThemeتستخدم للتبديل بين ThemeMode.lightو ThemeMode.dark. بناءً على قيمة المتغير _isDarkThemeنقوم بتحديث المتغير نفسه وتحديث الحالة بالتحديث ThemeMode.


إنشاء تطبيق المثال

تطبيق المثال نفسه عبارة عن تطبيق بسيط سيعرض Switchأداة داخل AppBarأداة Scaffold. ومع ذلك، لجعل تبديل السمة يعمل باستخدام Bloc، نحتاج إلى تكوين الكثير داخل ملفنا main.dart.




في الكود أعلاه، لدينا MyAppعنصر واجهة المستخدم الرئيسي. MyAppيتطلب عنصر واجهة المستخدم مثيلًا للفئة ThemeRepository. يمكن تمرير هذا المثيل داخل منشئه. لاحقًا، ThemeRepositoryيتم استخدام مثيل الفئة في فئة MultiRepositoryProviderو MultiBlocProvider. تعد فئتا المزود ضروريتين لضمان قدرتنا على الوصول عالميًا إلى مثيلات ThemeRepositoryوعبر ThemeCubitتطبيقنا.

على سبيل المثال، نقوم بالوصول إلى ThemeCubitالمثيل في onChangedسمة Switchالقطعة لاستدعاء switchThemeوظيفة الفئة ThemeCubitعلى السطر 51.

للحصول على السمة الأولية أيضًا، نستدعي الوظيفة getCurrentThemeعلى الفور باستخدام تدوين الشلال على ThemeCubitالمثيل على السطر 38. للتأكد من أن MaterialAppعنصر واجهة المستخدم لدينا على دراية بالسمة الحالية، قمنا بتغليف عنصر واجهة المستخدم داخل BlocBuilderعنصر واجهة مستخدم. BlocBuilderعنصر واجهة المستخدم من النوع ThemeCubitوبالتالي ThemeStateلدينا إمكانية الوصول إلى ThemeStateداخل عنصر واجهة المستخدم لدينا MaterialApp.

داخل MaterialAppعنصر واجهة المستخدم الخاص بنا، نقوم بتعريف كل من السمة الفاتحة باستخدام themeالسمة والسمة الداكنة باستخدام darkThemeالسمة. كما نقوم بتعيين themeModeالسمة إلى state.themeModeللتأكد من أنها تساوي دائمًا قيمة themeModeالمثيل ThemeStateالمنبعث من ThemeCubit.

وحتى لو قمنا بإعادة تشغيل التطبيق الذي يعيد تعيين الحالة الحالية ستلاحظ أن التطبيق يحتفظ بموضوعه الحالي وهو في هذه الحالة ThemeMode.dark:

التحسينات الممكنة
قبل أن ننهي هذا البرنامج التعليمي، هناك تحسينان أرغب في مناقشتهما.

استخدام SharedPreferencesController
بدلاً من الوصول SharedPreferencesمباشرةً إلى داخل صندوق الأمان الخاص بنا، ThemeRepositoryأوصي باستخدام تطبيق SharedPreferencesControllerلتسهيل إدارة جميع SharedPreferencesمفاتيحك.



تعديل فئة ThemeRepository
نظرًا لأننا قدمنا ​​الفصل SharedPreferencesController، فيمكننا الآن تغيير الوظائف الموجودة داخل ThemeRepositoryالفصل لاستخدام الوظائف من SharedPreferencesControllerالفصل.

في مقتطف التعليمات البرمجية أعلاه، قمنا بتغيير كل من الدالتين getThemeand setThemeلاستخدام دالات الفئة SharedPreferencesController. الآن لم نعد بحاجة إلى الوصول مباشرة إلى SharedPreferencesداخل ThemeRepositoryالفئة getThemeولم تعد الوظيفة غير متزامنة مما يحسن الأداء.

تعديل الوظيفة الرئيسية

لجعل SharedPreferencesالمثيل متاحًا داخل تطبيقنا، SharedPreferencesControllerنحتاج إلى استدعاء initالوظيفة قبل بدء تشغيل التطبيق. لذلك، نحتاج إلى إجراء التغييرات التالية على الوظيفة main.

في الكود أعلاه، قمنا بتغيير mainالوظيفة لتصبح غير متزامنة. داخل الوظيفة main، نبدأ باستدعاء الوظيفة WidgetsFlutterBinding.ensureInitializedللتأكد من تهيئة الارتباطات. فقط بعد تهيئة الارتباطات يمكننا الوصول إلى SharedPreferencesالمثيل، والذي يتم عن طريق استدعاء initوظيفة الفئة SharedPreferencesController.


إعادة تصميم ThemeCubit
حاليًا، تعد دالتا getCurrentTheme وswitchTheme التابعتان لفئة ThemeCubit مطوّلتين للغاية. يمكننا إعادة صياغتهما لجعلهما أقصر. ومع ذلك، فإن إعادة الصياغة قد تجعل فهمهما أكثر صعوبة.

في مقتطف التعليمات البرمجية أعلاه، استبدلنا عبارات if في الدالتين getCurrentThemeand switchThemeلاستخدام عامل ثلاثي. تظل وظيفة الدالتين كما هي، إلا أنها أصبحت الآن أقصر كثيرًا.

ضع في اعتبارك أن هذا الكود مبني على الكود المعاد صياغته ThemeRepository. إذا لم تقم بإجراء التغييرات المذكورة أعلاه باستخدام then فإن SharedPreferencesControllerالدالة getThemeلا تزال غير متزامنة وبالتالي getCurrentThemeيجب إرجاع Future<void>استخدام asyncالكلمة الأساسية awaitوالدالة getTheme.


 خاتمة

في هذا البرنامج التعليمي، قمنا بتنفيذ تبديل السمات باستخدام Flutter Bloc مع cubits للتبديل بين الوضع الداكن والوضع الفاتح. لقد ناقشنا جميع الفئات التي تم استخدامها للتأكد من فهمك للوظيفة. في نهاية البرنامج التعليمي، ناقشنا التحسينات الممكنة لضمان اتباعك لأفضل الممارسات وجعل الكود الخاص بك أكثر قابلية للإدارة.