From 5b2ae0fcb1d7699943fb62e903a9a3adaec53932 Mon Sep 17 00:00:00 2001 From: eymeric Date: Thu, 30 Nov 2023 22:17:34 +0100 Subject: [PATCH] beggin big cleaning --- apps/onyx/lib/app.dart | 95 ++++--- apps/onyx/lib/core/cache_service.dart | 24 +- .../lib/core/initialisations/hive_init.dart | 1 + apps/onyx/lib/core/res.dart | 8 + apps/onyx/lib/core/theme/theme.dart | 22 +- .../screens/izly/pages/izly_login_page.dart | 4 +- .../model/generated/settings_model.g.dart | 17 +- .../model/generated/theme_mode_enum.g.dart | 50 ---- .../generated/theme_settings_model.g.dart | 56 +++++ .../settings/domain/model/settings_model.dart | 5 - .../domain/model/theme_mode_enum.dart | 88 +------ .../settings/domain/model/theme_model.dart | 25 ++ .../domain/model/theme_settings_model.dart | 90 +++++++ .../screens/settings/pages/settings_page.dart | 75 +++--- .../settings/pages/themes_swap_page.dart | 215 ++-------------- .../lib/screens/settings/settings_export.dart | 2 + .../screens/settings/states/theme_cubit.dart | 235 +++++------------- .../screens/settings/states/theme_state.dart | 59 +++-- .../widgets/draggable_zone_widget.dart | 4 +- .../settings_settings_widget.dart | 4 +- .../widgets/theme_swap/theme_button.dart | 135 ++++++++++ .../theme_swap/theme_list_expansion_tile.dart | 42 ++++ 22 files changed, 611 insertions(+), 645 deletions(-) create mode 100644 apps/onyx/lib/screens/settings/domain/model/generated/theme_settings_model.g.dart create mode 100644 apps/onyx/lib/screens/settings/domain/model/theme_model.dart create mode 100644 apps/onyx/lib/screens/settings/domain/model/theme_settings_model.dart create mode 100644 apps/onyx/lib/screens/settings/widgets/theme_swap/theme_button.dart create mode 100644 apps/onyx/lib/screens/settings/widgets/theme_swap/theme_list_expansion_tile.dart diff --git a/apps/onyx/lib/app.dart b/apps/onyx/lib/app.dart index 6a638c71..ba56e232 100644 --- a/apps/onyx/lib/app.dart +++ b/apps/onyx/lib/app.dart @@ -56,52 +56,50 @@ class OnyxAppState extends State { BlocProvider(create: (context) => TomussCubit()), BlocProvider(create: (context) => MapCubit()), BlocProvider(create: (context) => IzlyCubit()), - BlocProvider( - create: (context) => ThemeCubit(OnyxTheme.themesPreset)), + BlocProvider(create: (context) => ThemeCubit()), ], - child: BlocBuilder( - builder: (context, themeState) { - return BlocBuilder( - builder: (context, authState) { - if (kDebugMode) { - print("Device.orientation : ${Device.orientation}"); - print("Device.deviceType : ${Device.deviceType}"); - print("Device.screenType : ${Device.screenType}"); - print("Device.width : ${Device.width}"); - print("Device.height : ${Device.height}"); - print("Device.boxConstraints : ${Device.boxConstraints}"); - print("Device.aspectRatio : ${Device.aspectRatio}"); - print("Device.pixelRatio : ${Device.pixelRatio}"); - } + child: BlocBuilder( + builder: (context, authState) { + if (kDebugMode) { + print("Device.orientation : ${Device.orientation}"); + print("Device.deviceType : ${Device.deviceType}"); + print("Device.screenType : ${Device.screenType}"); + print("Device.width : ${Device.width}"); + print("Device.height : ${Device.height}"); + print("Device.boxConstraints : ${Device.boxConstraints}"); + print("Device.aspectRatio : ${Device.aspectRatio}"); + print("Device.pixelRatio : ${Device.pixelRatio}"); + } - if (authState.status == - AuthentificationStatus.authentificated) { - CacheService.getEncryptionKey(context - .read() - .state - .settings - .biometricAuth) - .then((key) => - CacheService.get(secureKey: key).then( - (value) => context.read().connect( - username: value!.username, - password: value.password))); - if (AgendaStatus.ready != - context.read().state.status) { - context.read().load( - lyon1Cas: authState.lyon1Cas, - settings: context.read().state.settings); - } - context.read().load( - lyon1Cas: authState.lyon1Cas, - settings: context.read().state.settings, - force: true, - ); - } + if (authState.status == AuthentificationStatus.authentificated) { + CacheService.getEncryptionKey(context + .read() + .state + .settings + .biometricAuth) + .then((key) => CacheService.get(secureKey: key) + .then((value) => context.read().connect( + username: value!.username, + password: value.password))); + if (AgendaStatus.ready != + context.read().state.status) { + context.read().load( + lyon1Cas: authState.lyon1Cas, + settings: context.read().state.settings); + } + context.read().load( + lyon1Cas: authState.lyon1Cas, + settings: context.read().state.settings, + force: true, + ); + } + return BlocBuilder( + builder: (context, themeState) { return BlocBuilder( builder: (context, settingsState) { - if (settingsState.status == SettingsStatus.ready || - settingsState.status == SettingsStatus.error) { + if ((settingsState.status == SettingsStatus.ready || + settingsState.status == SettingsStatus.error) && + (themeState.status != ThemeStateStatus.init)) { if (authState.status == AuthentificationStatus.initial) { context .read() @@ -121,7 +119,8 @@ class OnyxAppState extends State { navigatorKey: OnyxApp.navigatorKey, scrollBehavior: const CustomScrollBehavior(), debugShowCheckedModeBanner: false, - themeMode: settingsState.settings.themeMode.themeMode, + themeMode: + themeState.themesSettings!.themeMode.toThemeMode, theme: themeState.lightTheme, darkTheme: themeState.darkTheme, home: (authState.status == @@ -134,16 +133,16 @@ class OnyxAppState extends State { : LoginPage(key: UniqueKey()), ); } else { + context.read().init(); context.read().load(); return MaterialApp( debugShowCheckedModeBanner: false, - themeMode: settingsState.settings.themeMode.themeMode, - theme: themeState.lightTheme, - darkTheme: themeState.darkTheme, + themeMode: ThemeMode.system, + theme: OnyxTheme.lightTheme, + darkTheme: OnyxTheme.darkTheme, home: Scaffold( backgroundColor: - themeState.darkTheme?.colorScheme.background ?? - OnyxTheme.darkTheme.colorScheme.background, + Theme.of(context).colorScheme.background, body: const CustomCircularProgressIndicatorWidget()), ); diff --git a/apps/onyx/lib/core/cache_service.dart b/apps/onyx/lib/core/cache_service.dart index 468c5ac3..de744929 100644 --- a/apps/onyx/lib/core/cache_service.dart +++ b/apps/onyx/lib/core/cache_service.dart @@ -40,18 +40,18 @@ class CacheService { } static Future exist({int index = 0, List? secureKey}) async { - try { - Box box = await Hive.openBox( - "cached_$E", - encryptionCipher: (secureKey != null) ? HiveAesCipher(secureKey) : null, - crashRecovery: false, - ); - return box.containsKey("cache$index"); - } catch (e) { - Res.logger.e("error while checking existence of cache for $E: $e"); - await reset(); - return false; - } + // try { + Box box = await Hive.openBox( + "cached_$E", + encryptionCipher: (secureKey != null) ? HiveAesCipher(secureKey) : null, + crashRecovery: false, + ); + return box.containsKey("cache$index"); + // } catch (e) { + // Res.logger.e("error while checking existence of cache for $E: $e"); + // await reset(); + // return false; + // } } static Future reset() async { diff --git a/apps/onyx/lib/core/initialisations/hive_init.dart b/apps/onyx/lib/core/initialisations/hive_init.dart index 4b86d154..8fd33c09 100644 --- a/apps/onyx/lib/core/initialisations/hive_init.dart +++ b/apps/onyx/lib/core/initialisations/hive_init.dart @@ -12,6 +12,7 @@ Future hiveInit({String? path}) async { Hive.registerAdapter(FunctionalitiesAdapter()); Hive.registerAdapter(ThemeModeEnumAdapter()); Hive.registerAdapter(SettingsModelAdapter()); + Hive.registerAdapter(ThemeSettingsModelAdapter()); IzlyClient.registerAdapters(); Lyon1TomussClient.registerAdapters(); diff --git a/apps/onyx/lib/core/res.dart b/apps/onyx/lib/core/res.dart index a1bcd531..bf79bcfb 100644 --- a/apps/onyx/lib/core/res.dart +++ b/apps/onyx/lib/core/res.dart @@ -43,6 +43,14 @@ class Res { static final logger = Logger( level: (kDebugMode) ? Level.all : Level.fatal, + printer: PrettyPrinter( + methodCount: 0, + errorMethodCount: 8, + lineLength: 120, + colors: true, + printEmojis: true, + printTime: true, + ), ); } diff --git a/apps/onyx/lib/core/theme/theme.dart b/apps/onyx/lib/core/theme/theme.dart index aeb8ae6d..fe2befa8 100644 --- a/apps/onyx/lib/core/theme/theme.dart +++ b/apps/onyx/lib/core/theme/theme.dart @@ -225,22 +225,22 @@ class OnyxTheme { ), ); - static List themesPreset = [ - ThemeInfo('Dark Default', OnyxTheme.darkTheme), - ThemeInfo('Light Default', OnyxTheme.lightTheme), - ThemeInfo('Nichi Hachi', OnyxTheme.nichihachiTheme), - ThemeInfo('Blue Sky', OnyxTheme.blueSkyTheme), - ThemeInfo('ULTRAKILL', OnyxTheme.ultrakillTheme), - ThemeInfo('Stardew Valley', OnyxTheme.stardewValleyTheme), - ThemeInfo('Bad Apple', OnyxTheme.badappleTheme), - ThemeInfo('Moon Light', OnyxTheme.moonlightTheme), + static List themesPreset = [ + ThemeModel('Dark Default', OnyxTheme.darkTheme), + ThemeModel('Light Default', OnyxTheme.lightTheme), + ThemeModel('Nichi Hachi', OnyxTheme.nichihachiTheme), + ThemeModel('Blue Sky', OnyxTheme.blueSkyTheme), + ThemeModel('ULTRAKILL', OnyxTheme.ultrakillTheme), + ThemeModel('Stardew Valley', OnyxTheme.stardewValleyTheme), + ThemeModel('Bad Apple', OnyxTheme.badappleTheme), + ThemeModel('Moon Light', OnyxTheme.moonlightTheme), ]; - static List themesPresetDark = themesPreset + static List themesPresetDark = themesPreset .where((themeInfo) => themeInfo.theme.brightness == Brightness.dark) .toList(); - static List themesPresetLight = themesPreset + static List themesPresetLight = themesPreset .where((themeInfo) => themeInfo.theme.brightness == Brightness.light) .toList(); } diff --git a/apps/onyx/lib/screens/izly/pages/izly_login_page.dart b/apps/onyx/lib/screens/izly/pages/izly_login_page.dart index 85d7ab32..cc0e5b8b 100644 --- a/apps/onyx/lib/screens/izly/pages/izly_login_page.dart +++ b/apps/onyx/lib/screens/izly/pages/izly_login_page.dart @@ -99,8 +99,8 @@ class _IzlyLoginPageState extends State { child: Text( "Confidentialité", style: Theme.of(context) - .textTheme - .bodySmall! + .textTheme + .bodySmall! .copyWith(fontSize: 17.sp), ), ), diff --git a/apps/onyx/lib/screens/settings/domain/model/generated/settings_model.g.dart b/apps/onyx/lib/screens/settings/domain/model/generated/settings_model.g.dart index ac4175ac..b72fd0be 100644 --- a/apps/onyx/lib/screens/settings/domain/model/generated/settings_model.g.dart +++ b/apps/onyx/lib/screens/settings/domain/model/generated/settings_model.g.dart @@ -11,8 +11,6 @@ abstract class _$SettingsModelCWProxy { SettingsModel forceGreen(bool forceGreen); - SettingsModel themeMode(ThemeModeEnum themeMode); - SettingsModel newGradeNotification(bool newGradeNotification); SettingsModel showHiddenUE(bool showHiddenUE); @@ -64,7 +62,6 @@ abstract class _$SettingsModelCWProxy { SettingsModel call({ bool? biometricAuth, bool? forceGreen, - ThemeModeEnum? themeMode, bool? newGradeNotification, bool? showHiddenUE, bool? fetchAgendaAuto, @@ -101,10 +98,6 @@ class _$SettingsModelCWProxyImpl implements _$SettingsModelCWProxy { @override SettingsModel forceGreen(bool forceGreen) => this(forceGreen: forceGreen); - @override - SettingsModel themeMode(ThemeModeEnum themeMode) => - this(themeMode: themeMode); - @override SettingsModel newGradeNotification(bool newGradeNotification) => this(newGradeNotification: newGradeNotification); @@ -195,7 +188,6 @@ class _$SettingsModelCWProxyImpl implements _$SettingsModelCWProxy { SettingsModel call({ Object? biometricAuth = const $CopyWithPlaceholder(), Object? forceGreen = const $CopyWithPlaceholder(), - Object? themeMode = const $CopyWithPlaceholder(), Object? newGradeNotification = const $CopyWithPlaceholder(), Object? showHiddenUE = const $CopyWithPlaceholder(), Object? fetchAgendaAuto = const $CopyWithPlaceholder(), @@ -228,10 +220,6 @@ class _$SettingsModelCWProxyImpl implements _$SettingsModelCWProxy { ? _value.forceGreen // ignore: cast_nullable_to_non_nullable : forceGreen as bool, - themeMode: themeMode == const $CopyWithPlaceholder() || themeMode == null - ? _value.themeMode - // ignore: cast_nullable_to_non_nullable - : themeMode as ThemeModeEnum, newGradeNotification: newGradeNotification == const $CopyWithPlaceholder() || newGradeNotification == null @@ -366,7 +354,6 @@ class SettingsModelAdapter extends TypeAdapter { return SettingsModel( biometricAuth: fields[16] == null ? false : fields[16] as bool, forceGreen: fields[1] as bool, - themeMode: fields[2] as ThemeModeEnum, newGradeNotification: fields[3] as bool, showHiddenUE: fields[4] as bool, fetchAgendaAuto: fields[5] as bool, @@ -405,15 +392,13 @@ class SettingsModelAdapter extends TypeAdapter { @override void write(BinaryWriter writer, SettingsModel obj) { writer - ..writeByte(23) + ..writeByte(22) ..writeByte(15) ..write(obj.firstLogin) ..writeByte(16) ..write(obj.biometricAuth) ..writeByte(1) ..write(obj.forceGreen) - ..writeByte(2) - ..write(obj.themeMode) ..writeByte(3) ..write(obj.newGradeNotification) ..writeByte(4) diff --git a/apps/onyx/lib/screens/settings/domain/model/generated/theme_mode_enum.g.dart b/apps/onyx/lib/screens/settings/domain/model/generated/theme_mode_enum.g.dart index c1f621a3..62b1d21b 100644 --- a/apps/onyx/lib/screens/settings/domain/model/generated/theme_mode_enum.g.dart +++ b/apps/onyx/lib/screens/settings/domain/model/generated/theme_mode_enum.g.dart @@ -6,56 +6,6 @@ part of '../theme_mode_enum.dart'; // TypeAdapterGenerator // ************************************************************************** -class ThemesUserDataAdapter extends TypeAdapter { - @override - final int typeId = 42; - - @override - ThemesUserData read(BinaryReader reader) { - final numOfFields = reader.readByte(); - final fields = { - for (int i = 0; i < numOfFields; i++) reader.readByte(): reader.read(), - }; - return ThemesUserData( - themesCreated: (fields[0] as List) - .map((dynamic e) => (e as Map).cast()) - .toList(), - darkThemeSelected: fields[1] as String, - lightThemeSelected: fields[2] as String, - favoriteThemes: (fields[3] as List) - .map((dynamic e) => (e as Map).cast()) - .toList(), - changeAutoTheme: fields[4] as bool, - ); - } - - @override - void write(BinaryWriter writer, ThemesUserData obj) { - writer - ..writeByte(5) - ..writeByte(0) - ..write(obj.themesCreated) - ..writeByte(1) - ..write(obj.darkThemeSelected) - ..writeByte(2) - ..write(obj.lightThemeSelected) - ..writeByte(3) - ..write(obj.favoriteThemes) - ..writeByte(4) - ..write(obj.changeAutoTheme); - } - - @override - int get hashCode => typeId.hashCode; - - @override - bool operator ==(Object other) => - identical(this, other) || - other is ThemesUserDataAdapter && - runtimeType == other.runtimeType && - typeId == other.typeId; -} - class ThemeModeEnumAdapter extends TypeAdapter { @override final int typeId = 8; diff --git a/apps/onyx/lib/screens/settings/domain/model/generated/theme_settings_model.g.dart b/apps/onyx/lib/screens/settings/domain/model/generated/theme_settings_model.g.dart new file mode 100644 index 00000000..24c1db0f --- /dev/null +++ b/apps/onyx/lib/screens/settings/domain/model/generated/theme_settings_model.g.dart @@ -0,0 +1,56 @@ +// GENERATED CODE - DO NOT MODIFY BY HAND + +part of '../theme_settings_model.dart'; + +// ************************************************************************** +// TypeAdapterGenerator +// ************************************************************************** + +class ThemeSettingsModelAdapter extends TypeAdapter { + @override + final int typeId = 42; + + @override + ThemeSettingsModel read(BinaryReader reader) { + final numOfFields = reader.readByte(); + final fields = { + for (int i = 0; i < numOfFields; i++) reader.readByte(): reader.read(), + }; + return ThemeSettingsModel( + darkThemeSelected: fields[1] as String, + lightThemeSelected: fields[2] as String, + themeMode: fields[4] as ThemeModeEnum, + autoSwitchTheme: fields[5] as bool, + themesCreatedString: fields[0] as String?, + favoriteThemesString: fields[3] as String?, + ); + } + + @override + void write(BinaryWriter writer, ThemeSettingsModel obj) { + writer + ..writeByte(6) + ..writeByte(1) + ..write(obj.darkThemeSelected) + ..writeByte(2) + ..write(obj.lightThemeSelected) + ..writeByte(4) + ..write(obj.themeMode) + ..writeByte(5) + ..write(obj.autoSwitchTheme) + ..writeByte(0) + ..write(obj.themesCreatedString) + ..writeByte(3) + ..write(obj.favoriteThemesString); + } + + @override + int get hashCode => typeId.hashCode; + + @override + bool operator ==(Object other) => + identical(this, other) || + other is ThemeSettingsModelAdapter && + runtimeType == other.runtimeType && + typeId == other.typeId; +} diff --git a/apps/onyx/lib/screens/settings/domain/model/settings_model.dart b/apps/onyx/lib/screens/settings/domain/model/settings_model.dart index 6e502158..202727d2 100644 --- a/apps/onyx/lib/screens/settings/domain/model/settings_model.dart +++ b/apps/onyx/lib/screens/settings/domain/model/settings_model.dart @@ -2,7 +2,6 @@ import 'package:copy_with_extension/copy_with_extension.dart'; import 'package:equatable/equatable.dart'; import 'package:hive_flutter/hive_flutter.dart'; import 'package:onyx/core/res.dart'; -import 'package:onyx/screens/settings/settings_export.dart'; part 'generated/settings_model.g.dart'; @@ -17,8 +16,6 @@ class SettingsModel extends Equatable { //tomuss @HiveField(1) final bool forceGreen; - @HiveField(2) - final ThemeModeEnum themeMode; @HiveField(3) final bool newGradeNotification; @HiveField(4) @@ -78,7 +75,6 @@ class SettingsModel extends Equatable { const SettingsModel({ this.biometricAuth = false, this.forceGreen = false, - this.themeMode = ThemeModeEnum.system, this.newGradeNotification = true, this.showHiddenUE = false, this.fetchAgendaAuto = true, @@ -111,7 +107,6 @@ class SettingsModel extends Equatable { @override List get props => [ forceGreen, - themeMode, newGradeNotification, showHiddenUE, fetchAgendaAuto, diff --git a/apps/onyx/lib/screens/settings/domain/model/theme_mode_enum.dart b/apps/onyx/lib/screens/settings/domain/model/theme_mode_enum.dart index 63b0bef0..011a9eec 100644 --- a/apps/onyx/lib/screens/settings/domain/model/theme_mode_enum.dart +++ b/apps/onyx/lib/screens/settings/domain/model/theme_mode_enum.dart @@ -1,6 +1,5 @@ import 'package:flutter/material.dart'; import 'package:hive_flutter/hive_flutter.dart'; -import 'package:json_theme/json_theme.dart'; part 'generated/theme_mode_enum.g.dart'; @@ -15,7 +14,7 @@ enum ThemeModeEnum { } extension ThemeModeEnumExtension on ThemeModeEnum { - ThemeMode get themeMode { + ThemeMode get toThemeMode { switch (this) { case ThemeModeEnum.system: return ThemeMode.system; @@ -27,82 +26,13 @@ extension ThemeModeEnumExtension on ThemeModeEnum { } } -@HiveType(typeId: 42) -class ThemesUserData { - @HiveField(0) - final List> themesCreated; - @HiveField(1) - final String darkThemeSelected; - @HiveField(2) - final String lightThemeSelected; - @HiveField(3) - final List> favoriteThemes; - @HiveField(4) - final bool changeAutoTheme; - - const ThemesUserData({ - this.themesCreated = const [], - this.darkThemeSelected = 'Dark Default', - this.lightThemeSelected = 'Light Default', - this.favoriteThemes = const [], - this.changeAutoTheme = true, - }); - - copyWith({ - List>? themesCreated, - String? darkThemeSelected, - String? lightThemeSelected, - List>? favoriteThemes, - bool? changeAutoTheme, - }) { - return ThemesUserData( - themesCreated: themesCreated ?? this.themesCreated, - darkThemeSelected: darkThemeSelected ?? this.darkThemeSelected, - lightThemeSelected: lightThemeSelected ?? this.lightThemeSelected, - favoriteThemes: favoriteThemes ?? this.favoriteThemes, - changeAutoTheme: changeAutoTheme ?? this.changeAutoTheme, - ); - } -} - -class ThemeInfo { - final String name; - final ThemeData theme; - - ThemeInfo( - this.name, - this.theme, - ); - - ThemeInfo.fromJson(Map json) - : name = json['name'] as String, - theme = ThemeDecoder.decodeThemeData(['theme']) ?? ThemeData(); - - Map toJson() => { - 'name': name, - 'theme': ThemeEncoder.encodeThemeData(theme), - }; -} - -/// Transform a Json type to a ThemeInfo type and return it. If the json is not a theme, return a default theme. -ThemeInfo jsonToThemeInfo(Map json) { - return ThemeInfo(json['name'] as String, - ThemeDecoder.decodeThemeData(json['theme']) ?? ThemeData()); -} - -/// Transform a ThemeInfo type to a Json type and return it. -Map themeInfoToJson(ThemeInfo theme) { - return { - 'name': theme.name, - 'theme': ThemeEncoder.encodeThemeData(theme.theme), - }; -} - -/// Transform a Json list to a ThemeInfo list and return it. -List listJsonToThemeInfo(List> jsonList) { - List themeList = []; - for (Map json in jsonList) { - themeList.add(jsonToThemeInfo(json)); +extension BrightnessExtension on Brightness { + ThemeModeEnum get toThemeModeEnum { + switch (this) { + case Brightness.light: + return ThemeModeEnum.light; + case Brightness.dark: + return ThemeModeEnum.dark; + } } - return themeList; } diff --git a/apps/onyx/lib/screens/settings/domain/model/theme_model.dart b/apps/onyx/lib/screens/settings/domain/model/theme_model.dart new file mode 100644 index 00000000..d8a1b193 --- /dev/null +++ b/apps/onyx/lib/screens/settings/domain/model/theme_model.dart @@ -0,0 +1,25 @@ +import 'package:equatable/equatable.dart'; +import 'package:flutter/material.dart'; +import 'package:json_theme/json_theme.dart'; + +class ThemeModel extends Equatable { + final String name; + final ThemeData theme; + + const ThemeModel(this.name, this.theme); + + ThemeModel.fromJson(Map json) + : name = json['name'] as String, + theme = ThemeDecoder.decodeThemeData(json['theme']) ?? ThemeData(); + + Map toJson() => { + 'name': name, + 'theme': ThemeEncoder.encodeThemeData(theme), + }; + + @override + List get props => [name, theme]; + + @override + bool get stringify => true; +} diff --git a/apps/onyx/lib/screens/settings/domain/model/theme_settings_model.dart b/apps/onyx/lib/screens/settings/domain/model/theme_settings_model.dart new file mode 100644 index 00000000..05783abb --- /dev/null +++ b/apps/onyx/lib/screens/settings/domain/model/theme_settings_model.dart @@ -0,0 +1,90 @@ +import 'dart:convert'; +import 'dart:ui'; + +import 'package:hive_flutter/hive_flutter.dart'; +import 'package:onyx/core/theme/theme.dart'; +import 'package:onyx/screens/settings/settings_export.dart'; + +part 'generated/theme_settings_model.g.dart'; + +@HiveType(typeId: 42) +class ThemeSettingsModel { + List themesCreated; + @HiveField(1) + final String darkThemeSelected; + @HiveField(2) + final String lightThemeSelected; + List favoriteThemes; + @HiveField(4) + final ThemeModeEnum themeMode; + @HiveField(5) + final bool autoSwitchTheme; + List themesPreset = + OnyxTheme.themesPreset; //do not save it in hive + + ThemeSettingsModel({ + this.themesCreated = const [], + this.darkThemeSelected = 'Dark Default', + this.lightThemeSelected = 'Light Default', + this.favoriteThemes = const [], + this.themeMode = ThemeModeEnum.system, + this.autoSwitchTheme = true, + String? themesCreatedString, + String? favoriteThemesString, + }) { + if (themesCreatedString != null) { + themesCreated = jsonDecode(themesCreatedString) + .map((e) => ThemeModel.fromJson(e)) + .toList() + .cast(); + } + if (favoriteThemesString != null) { + favoriteThemes = jsonDecode(favoriteThemesString) + .map((e) => ThemeModel.fromJson(e)) + .toList() + .cast(); + } + } + + copyWith({ + List? themesCreated, + String? darkThemeSelected, + String? lightThemeSelected, + List? favoriteThemes, + ThemeModeEnum? themeMode, + bool? autoSwitchTheme, + }) { + return ThemeSettingsModel( + themesCreated: themesCreated ?? this.themesCreated, + darkThemeSelected: darkThemeSelected ?? this.darkThemeSelected, + lightThemeSelected: lightThemeSelected ?? this.lightThemeSelected, + favoriteThemes: favoriteThemes ?? this.favoriteThemes, + themeMode: themeMode ?? this.themeMode, + autoSwitchTheme: autoSwitchTheme ?? this.autoSwitchTheme, + ); + } + + List get lightThemesCreated => themesCreated + .where((themeInfo) => themeInfo.theme.brightness == Brightness.light) + .toList(); + + List get darkThemesCreated => themesCreated + .where((themeInfo) => themeInfo.theme.brightness == Brightness.dark) + .toList(); + + List get lightThemesPreset => themesPreset + .where((themeInfo) => themeInfo.theme.brightness == Brightness.light) + .toList(); + + List get darkThemesPreset => themesPreset + .where((themeInfo) => themeInfo.theme.brightness == Brightness.dark) + .toList(); + + @HiveField(0) + String get themesCreatedString => + jsonEncode(themesCreated.map((e) => e.toJson()).toList()); + + @HiveField(3) + String get favoriteThemesString => + jsonEncode(favoriteThemes.map((e) => e.toJson()).toList()); +} diff --git a/apps/onyx/lib/screens/settings/pages/settings_page.dart b/apps/onyx/lib/screens/settings/pages/settings_page.dart index 923feabc..33ecd510 100644 --- a/apps/onyx/lib/screens/settings/pages/settings_page.dart +++ b/apps/onyx/lib/screens/settings/pages/settings_page.dart @@ -13,6 +13,7 @@ import 'package:onyx/screens/login/login_export.dart'; import 'package:onyx/screens/mails/mails_export.dart'; import 'package:onyx/screens/notifications/domain/logic/background_logic.dart'; import 'package:onyx/screens/settings/settings_export.dart'; +import 'package:onyx/screens/settings/states/theme_cubit.dart'; import 'package:onyx/screens/settings/widgets/draggable_zone_widget.dart'; import 'package:onyx/screens/settings/widgets/drop_down_widget.dart'; import 'package:onyx/screens/tomuss/tomuss_export.dart'; @@ -54,45 +55,41 @@ class _SettingsPageState extends State { SettingsCardWidget( name: 'Général', widgets: [ - DropDownWidget( - text: 'Choisir le thème', - items: const [ - "Système", - "Sombre", - "Clair", - ], - value: state.settings.themeMode.index, - onChanged: (int choice) { - switch (choice) { - case 0: - context.read().modify( - settings: context - .read() - .state - .settings - .copyWith( - themeMode: ThemeModeEnum.system)); - break; - case 1: - context.read().modify( - settings: context - .read() - .state - .settings - .copyWith( - themeMode: ThemeModeEnum.dark)); - break; - case 2: - context.read().modify( - settings: context - .read() - .state - .settings - .copyWith( - themeMode: ThemeModeEnum.light)); - break; - } - }), + BlocBuilder( + buildWhen: (previous, current) { + return previous.themesSettings!.themeMode != + current.themesSettings!.themeMode; + }, + builder: (context, themeState) { + return DropDownWidget( + text: 'Choisir le thème', + items: const [ + "Système", + "Sombre", + "Clair", + ], + value: themeState.themesSettings!.themeMode.index, + onChanged: (int choice) { + switch (choice) { + case 0: + context + .read() + .updateThemeMode(ThemeModeEnum.system); + break; + case 1: + context + .read() + .updateThemeMode(ThemeModeEnum.dark); + break; + case 2: + context + .read() + .updateThemeMode(ThemeModeEnum.light); + break; + } + }); + }, + ), const SizedBox( height: 5, ), diff --git a/apps/onyx/lib/screens/settings/pages/themes_swap_page.dart b/apps/onyx/lib/screens/settings/pages/themes_swap_page.dart index d8e222ae..64e700b4 100644 --- a/apps/onyx/lib/screens/settings/pages/themes_swap_page.dart +++ b/apps/onyx/lib/screens/settings/pages/themes_swap_page.dart @@ -1,8 +1,8 @@ import 'package:flutter/material.dart'; import 'package:flutter_bloc/flutter_bloc.dart'; import 'package:onyx/screens/settings/states/theme_cubit.dart'; -import 'package:onyx/screens/settings/settings_export.dart'; import 'package:onyx/core/theme/theme_export.dart'; +import 'package:onyx/screens/settings/widgets/theme_swap/theme_list_expansion_tile.dart'; class ThemesSwap extends StatefulWidget { const ThemesSwap({super.key}); @@ -12,200 +12,37 @@ class ThemesSwap extends StatefulWidget { } class _ThemesSwapState extends State { - late List themeCreatedLight; - late List themeCreatedDark; - late List themesCreated; - @override Widget build(BuildContext context) { return Scaffold( - appBar: AppBar( - title: const Text("Changer les thèmes"), - ), - body: - BlocBuilder(builder: (context, themeState) { - themesCreated = - listJsonToThemeInfo(themeState.themesUserData!.themesCreated); - themeCreatedLight = themesCreated - .where( - (themeInfo) => themeInfo.theme.brightness == Brightness.light) - .toList(); - themeCreatedDark = themesCreated - .where( - (themeInfo) => themeInfo.theme.brightness == Brightness.dark) - .toList(); - return SingleChildScrollView( - child: Column(children: [ - expansionTheme( - context, - "Thèmes favoris", - listJsonToThemeInfo(themeState.themesUserData!.favoriteThemes), - themeState), - expansionTheme(context, "Thèmes clairs", - OnyxTheme.themesPresetLight, themeState, - themesCreated: themeCreatedLight), - expansionTheme(context, "Thèmes sombres", - OnyxTheme.themesPresetDark, themeState, - themesCreated: themeCreatedDark), - ])); - })); - } - - Widget expansionTheme(BuildContext context, String title, - List themesPreset, ThemeState themeState, - {List themesCreated = const []}) { - return Card( - margin: const EdgeInsets.symmetric(horizontal: 16.0, vertical: 8.0), - shape: RoundedRectangleBorder( - borderRadius: BorderRadius.circular(16.0), + appBar: AppBar( + title: const Text("Changer les thèmes"), ), - child: Theme( - data: Theme.of(context).copyWith(dividerColor: Colors.transparent), - child: ExpansionTile( - childrenPadding: EdgeInsets.zero, - title: Container( - padding: const EdgeInsets.all(10), - child: Text( - title, + body: BlocBuilder( + builder: (context, themeState) { + return SingleChildScrollView( + child: Column( + children: [ + ThemeListExpansionTile( + title: "Thèmes favoris", + themesPreset: themeState.themesSettings!.favoriteThemes, + themesCreated: const [], + ), + ThemeListExpansionTile( + title: "Thèmes clairs", + themesPreset: OnyxTheme.themesPresetLight, + themesCreated: themeState.themesSettings!.lightThemesCreated, + ), + ThemeListExpansionTile( + title: "Thèmes sombres", + themesPreset: OnyxTheme.themesPresetDark, + themesCreated: themeState.themesSettings!.darkThemesCreated, + ), + ], ), - ), - children: [ - themesPrint(context, themesPreset, themesCreated, themeState), - ], - ), + ); + }, ), ); } - - Widget themesPrint(BuildContext context, List listThemesPreset, - List listThemesCreated, ThemeState themeState) { - return GridView.builder( - shrinkWrap: true, - physics: const NeverScrollableScrollPhysics(), - gridDelegate: const SliverGridDelegateWithFixedCrossAxisCount( - crossAxisCount: 2, - childAspectRatio: 2.5, - ), - itemCount: listThemesPreset.length + listThemesCreated.length, - itemBuilder: (context, index) { - ThemeInfo theme; - if (index < listThemesPreset.length) { - theme = listThemesPreset[index]; - } else { - theme = listThemesCreated[index - listThemesPreset.length]; - } - - EdgeInsets itemPadding = const EdgeInsets.all(5.0); - if (index % 2 == 0) { - itemPadding = const EdgeInsets.fromLTRB(8.0, 5.0, 5.0, 5.0); - } else { - itemPadding = const EdgeInsets.fromLTRB(5.0, 5.0, 8.0, 5.0); - } - - return Builder(builder: (BuildContext builderContext) { - return GestureDetector( - onTap: () { - context.read().loadTheme(theme); - context.read().saveChangeTheme(theme); - if (themeState.themesUserData!.changeAutoTheme) { - context.read().modify( - settings: context - .read() - .state - .settings - .copyWith( - themeMode: - (theme.theme.brightness == Brightness.light) - ? ThemeModeEnum.light - : ThemeModeEnum.dark)); - } - }, - onDoubleTap: () { - context.read().setThemeFavorite(context, theme); - }, - onLongPress: () { - if (index >= listThemesPreset.length) { - popupMenuThemeCreated(builderContext, theme); - } - }, - child: Stack(children: [ - Padding( - padding: itemPadding, - child: Container( - decoration: BoxDecoration( - color: theme.theme.cardColor, - borderRadius: BorderRadius.circular(20.0), - border: Border.all( - color: theme.theme.colorScheme.primary, - width: 4, - ), - ), - child: Center( - child: Text( - theme.name.replaceAll('_', ' '), - textAlign: TextAlign.center, - style: TextStyle( - fontWeight: ((theme.name == - themeState.themesUserData! - .darkThemeSelected || - theme.name == - themeState.themesUserData! - .lightThemeSelected)) - ? FontWeight.w900 - : FontWeight.normal, - color: theme.theme.textTheme.labelLarge?.color ?? - Colors.black, - ), - ), - ), - )), - if (context.read().searchThemeInJsonList( - theme.name, - themeState.themesUserData!.favoriteThemes) != - -1) - Positioned( - top: 15, - right: 18 - (index + 1) % 2 * 2, - child: const Icon( - Icons.favorite, - color: Colors.red, - size: 20, - ), - ), - ])); - }); - }); - } - - void popupMenuThemeCreated(BuildContext context, ThemeInfo theme) { - final RenderBox renderBox = context.findRenderObject() as RenderBox; - final Offset position = renderBox.localToGlobal(Offset.zero); - showMenu( - context: context, - position: RelativeRect.fromRect( - position & const Size(40, 40), - Offset.zero & context.size!, - ), - items: [ - const PopupMenuItem( - value: 'Modifier', - child: Text('Modifier'), - ), - const PopupMenuItem( - value: 'Supprimer', - child: Text('Supprimer'), - ), - ], - ).then((value) { - if (value != null) { - switch (value) { - case 'Modifier': - break; - case 'Supprimer': - context.read().deleteTheme(theme.name); - break; - } - } - }); - } } diff --git a/apps/onyx/lib/screens/settings/settings_export.dart b/apps/onyx/lib/screens/settings/settings_export.dart index 8e6405c9..dad8636f 100644 --- a/apps/onyx/lib/screens/settings/settings_export.dart +++ b/apps/onyx/lib/screens/settings/settings_export.dart @@ -2,6 +2,8 @@ export '../agenda_config/page/qr_code_scanner_page.dart'; export 'domain/logic/settings_logic.dart'; export 'domain/model/settings_model.dart'; export 'domain/model/theme_mode_enum.dart'; +export 'domain/model/theme_settings_model.dart'; +export 'domain/model/theme_model.dart'; export 'pages/settings_page.dart'; export 'states/settings_cubit.dart'; export 'widgets/agenda_url_parameter_widget.dart'; diff --git a/apps/onyx/lib/screens/settings/states/theme_cubit.dart b/apps/onyx/lib/screens/settings/states/theme_cubit.dart index 01a2ade7..a8400b2d 100644 --- a/apps/onyx/lib/screens/settings/states/theme_cubit.dart +++ b/apps/onyx/lib/screens/settings/states/theme_cubit.dart @@ -2,228 +2,119 @@ import 'package:equatable/equatable.dart'; import 'package:flutter/foundation.dart'; import 'package:flutter_bloc/flutter_bloc.dart'; import 'package:flutter/material.dart'; -import 'package:hive_flutter/hive_flutter.dart'; +import 'package:onyx/core/cache_service.dart'; +import 'package:onyx/core/res.dart'; import 'package:onyx/screens/settings/settings_export.dart'; part 'theme_state.dart'; class ThemeCubit extends Cubit { - late Box box; - late ThemesUserData themesUserData; - late List themesCreated; - List themesPreset; - - ThemeCubit(this.themesPreset) : super(const ThemeState()) { - _initializeThemes(); + ThemeCubit() : super(const ThemeState()) { + init(); } /// This function initilize the Hive of ThemeUserData and load the themes selected. - Future _initializeThemes() async { - if (!Hive.isAdapterRegistered(ThemesUserDataAdapter().typeId)) { - Hive.registerAdapter(ThemesUserDataAdapter()); - } - - box = await Hive.openBox('themesUserData'); + Future init() async { + emit(state.copyWith(status: ThemeStateStatus.init)); + ThemeSettingsModel themesUserData; - if (box.containsKey('data')) { - themesUserData = box.get('data'); + if (await CacheService.exist()) { + themesUserData = (await CacheService.get())!; } else { - themesUserData = const ThemesUserData(); - await box.put('data', themesUserData); + themesUserData = ThemeSettingsModel(); + await CacheService.set(themesUserData); } - themesCreated = listJsonToThemeInfo(themesUserData.themesCreated); - - await loadTheme(themesUserData.lightThemeSelected); - await loadTheme(themesUserData.darkThemeSelected); - emit(state.copyWith( - status: ThemeStateStatus.loaded, themesUserData: themesUserData)); - } - - /// Load the theme from the input. - /// - /// The theme must be a String, a ThemeData or a ThemeInfo type. - Future loadTheme(final theme) async { - ThemeData themeSelected; - if (theme is String) { - int indexThemesCreated = await searchIndexTheme(theme, themesCreated); - int indexThemesPreset = await searchIndexTheme(theme, themesPreset); - if (indexThemesCreated != -1) { - themeSelected = themesCreated[indexThemesCreated].theme; - } else if (indexThemesPreset != -1) { - themeSelected = themesPreset[indexThemesPreset].theme; - } else { - return Future.error("The theme [$theme] doesn't exist !"); - } - } else if (theme is ThemeData) { - themeSelected = theme; - } else if (theme is ThemeInfo) { - themeSelected = theme.theme; - } else { - return Future.error("Wrong type entered at loading a theme !"); - } - - //Set the theme depending of the brightness - themeSelected.brightness == Brightness.dark - ? emit(state.copyWith(darkTheme: themeSelected)) - : emit(state.copyWith(lightTheme: themeSelected)); - - toggleThemeMode(); - } - - /// Return a list of the main colors of a theme : The font, the background and the button. - Future> extractThemeColor(ThemeData theme) async { - Color fontColor = theme.textTheme.labelLarge!.color!; - return [fontColor, theme.cardColor, theme.colorScheme.primary]; + status: ThemeStateStatus.loaded, themesSettings: themesUserData)); } /// Add a new theme to the themesCreated list in the Hive. - Future newTheme(ThemeInfo themeCreated) async { - if (await searchIndexTheme( - themeCreated.name, state.themesUserData!.themesCreated) != - -1) { + Future newTheme(ThemeModel themeCreated) async { + if (state.themesSettings!.themesCreated.contains(themeCreated)) { return Future.error("The theme [${themeCreated.name}] already exist !"); } if (kDebugMode) { - print("Theme builded: ${themeCreated.name}"); + Res.logger.i("Theme builded: ${themeCreated.name}"); } - themesUserData.themesCreated.add(themeInfoToJson(themeCreated)); + ThemeSettingsModel themesUserData = state.themesSettings!.copyWith( + themesCreated: state.themesSettings!.themesCreated..add(themeCreated)); - final updatedUserData = themesUserData.copyWith(); - await box.put('data', updatedUserData); - emit(state.copyWith(themesUserData: updatedUserData)); + await CacheService.set(themesUserData); + emit(state.copyWith(themesSettings: themesUserData)); } /// Delete a theme from the themesCreated list in the Hive. /// /// The theme must be a String, a ThemeData or a ThemeInfo type. - Future deleteTheme(final theme) async { - int index = await searchIndexTheme(theme, themesCreated); - if (index == -1) { - if (theme is String) { - return Future.error("The theme [$theme] doesn't exist !"); - } else if (theme is ThemeInfo) { - return Future.error("The theme [${theme.name}] doesn't exist !"); - } else { - return Future.error("The theme doesn't exist !"); - } + Future deleteTheme(final ThemeModel theme) async { + if (!state.themesSettings!.themesCreated.contains(theme)) { + return Future.error("The theme [$theme] doesn't exist !"); } - themesUserData.themesCreated.removeAt(index); - final updatedUserData = themesUserData.copyWith(); - await box.put('data', updatedUserData); - emit(state.copyWith(themesUserData: updatedUserData)); - } - /// Part of searchIndexTheme. - int searchThemeInJsonList(String theme, List> jsonList) { - int index = 0; - for (Map json in jsonList) { - if (json['name'] == theme) { - return index; - } - index++; - } - return -1; - } - - /// Part of searchIndexTheme. - Future searchThemeInThemeInfo( - final theme, List themesList) async { - int index = 0; - if (theme is String) { - int index = 0; - for (ThemeInfo themeFromList in themesList) { - if (themeFromList.name == theme) { - return index; - } - index++; - } - } else if (theme is ThemeData) { - for (ThemeInfo themeFromList in themesList) { - if (themeFromList.theme == theme) { - return index; - } - index++; - } - } else if (theme is ThemeInfo) { - for (ThemeInfo themeFromList in themesList) { - if (themeFromList == theme) { - return index; - } - index++; - } - } else { - return Future.error("Wrong type entered at searching a index !"); - } - return -1; - } - - /// Return the index of the theme in the themesList. If the theme isn't in the list, the function return -1. - /// - /// The theme must be a String, a ThemeData or a ThemeInfo type. - /// - /// The themesList must be a list of ThemeInfo or Json. - Future searchIndexTheme(final theme, final themesList) async { - if (themesList is List) { - return searchThemeInThemeInfo(theme, themesList); - } else if (themesList is List>) { - return searchThemeInJsonList(theme, themesList); - } - return Future.error("Wrong type entered at searching an index !"); + ThemeSettingsModel themesUserData = state.themesSettings!.copyWith( + themesCreated: state.themesSettings!.themesCreated..remove(theme)); + await CacheService.set(themesUserData); + emit(state.copyWith(themesSettings: themesUserData)); } /// Change the theme selected in the Hive at darkThemeSelected or lightThemeSelected. - void saveChangeTheme(ThemeInfo theme) async { - late ThemesUserData updatedUserData; + Future chooseTheme(ThemeModel theme) async { + late ThemeSettingsModel updatedUserData; if (theme.theme.brightness == Brightness.dark) { - updatedUserData = themesUserData.copyWith(darkThemeSelected: theme.name); + updatedUserData = + state.themesSettings!.copyWith(darkThemeSelected: theme.name); } else { - updatedUserData = themesUserData.copyWith(lightThemeSelected: theme.name); + updatedUserData = + state.themesSettings!.copyWith(lightThemeSelected: theme.name); } - themesUserData = updatedUserData; - await box.put('data', updatedUserData); - emit(state.copyWith(themesUserData: updatedUserData)); + await CacheService.set(updatedUserData); + emit(state.copyWith( + themesSettings: updatedUserData, status: ThemeStateStatus.updated)); } /// Add the theme in the Hive at the favoriteThemes list. /// If the theme is already in the list, remove it from the list. - void setThemeFavorite(BuildContext context, ThemeInfo theme) async { - int index = await context - .read() - .searchIndexTheme(theme.name, themesUserData.favoriteThemes); - if (kDebugMode) { - print(index); - } + void toggleThemeFavorite(ThemeModel theme) async { + int index = state.themesSettings!.favoriteThemes + .indexWhere((element) => element.name == theme.name); + ThemeSettingsModel themesUserData; if (index != -1) { - themesUserData.favoriteThemes.removeAt(index); + themesUserData = state.themesSettings!.copyWith( + favoriteThemes: state.themesSettings!.favoriteThemes.toList() + ..removeAt(index)); } else { - themesUserData.favoriteThemes.add(themeInfoToJson(theme)); + themesUserData = state.themesSettings!.copyWith( + favoriteThemes: state.themesSettings!.favoriteThemes.toList() + ..add(theme)); } - final updatedUserData = themesUserData.copyWith(); - - await box.put('data', updatedUserData); - emit(state.copyWith(themesUserData: updatedUserData)); + await CacheService.set(themesUserData); + emit(state.copyWith(themesSettings: themesUserData)); } - void setChangeAutoTheme(bool value) async { - final updatedUserData = themesUserData.copyWith(changeAutoTheme: value); - themesUserData = updatedUserData; - await box.put('data', themesUserData); - emit(state.copyWith(themesUserData: updatedUserData)); + void updateThemeMode(ThemeModeEnum themeMode) async { + final updatedUserData = + state.themesSettings!.copyWith(themeMode: themeMode); + await CacheService.set(updatedUserData); + emit(state.copyWith( + themesSettings: updatedUserData, status: ThemeStateStatus.updated)); } - void setThemeMode(ThemeMode themeMode) { - emit(state.copyWith(themeMode: themeMode)); + void updateAutoSwitchTheme(bool autoSwitchTheme) async { + final updatedUserData = + state.themesSettings!.copyWith(autoSwitchTheme: autoSwitchTheme); + await CacheService.set(updatedUserData); + emit(state.copyWith( + themesSettings: updatedUserData, status: ThemeStateStatus.updated)); } void toggleThemeMode() { - if (state.themeMode == ThemeMode.dark) { - setThemeMode(ThemeMode.light); - } else if (state.themeMode == ThemeMode.dark) { - setThemeMode(ThemeMode.dark); + if (state.themesSettings!.themeMode == ThemeModeEnum.dark) { + emit(state.copyWith(themeMode: ThemeMode.light)); + } else if (state.themesSettings!.themeMode == ThemeModeEnum.light) { + emit(state.copyWith(themeMode: ThemeMode.dark)); } } } diff --git a/apps/onyx/lib/screens/settings/states/theme_state.dart b/apps/onyx/lib/screens/settings/states/theme_state.dart index f453a519..705dfa5f 100644 --- a/apps/onyx/lib/screens/settings/states/theme_state.dart +++ b/apps/onyx/lib/screens/settings/states/theme_state.dart @@ -1,43 +1,66 @@ part of 'theme_cubit.dart'; -enum ThemeStateStatus { init, loaded, updated } +enum ThemeStateStatus { init, loaded, updated, error } class ThemeState extends Equatable { final ThemeStateStatus status; - final ThemeData? darkTheme; - final ThemeData? lightTheme; - final ThemeMode? themeMode; - final ThemesUserData? themesUserData; + final ThemeSettingsModel? themesSettings; const ThemeState({ this.status = ThemeStateStatus.init, - this.lightTheme, - this.darkTheme, - this.themeMode, - this.themesUserData, + this.themesSettings, }); // Define a copyWith method for creating a new instance with modified properties ThemeState copyWith({ ThemeStateStatus? status, - ThemeData? darkTheme, - ThemeData? lightTheme, ThemeMode? themeMode, - ThemesUserData? themesUserData, + ThemeSettingsModel? themesSettings, }) { return ThemeState( status: status ?? this.status, - darkTheme: darkTheme ?? this.darkTheme, - lightTheme: lightTheme ?? this.lightTheme, - themeMode: themeMode ?? this.themeMode, - themesUserData: themesUserData ?? this.themesUserData, + themesSettings: themesSettings ?? this.themesSettings, ); } @override - List get props => - [status, darkTheme, lightTheme, themeMode, themesUserData]; + List get props => [ + status, + themesSettings, + ]; @override bool? get stringify => true; + + ThemeData? get theme { + if (themesSettings!.themeMode.toThemeMode == ThemeMode.dark) { + return darkTheme; + } else { + return lightTheme; + } + } + + ThemeData? get darkTheme { + return (themesSettings != null) + ? _getTheme(themesSettings!.darkThemeSelected) + : null; + } + + ThemeData? get lightTheme => (themesSettings != null) + ? _getTheme(themesSettings!.lightThemeSelected) + : null; + + ThemeData? _getTheme(String themeName) { + int indexThemesCreated = themesSettings!.themesCreated + .indexWhere((element) => element.name == themeName); + int indexThemesPreset = themesSettings!.themesPreset + .indexWhere((element) => element.name == themeName); + if (indexThemesCreated != -1) { + return themesSettings!.themesCreated[indexThemesCreated].theme; + } else if (indexThemesPreset != -1) { + return themesSettings!.themesPreset[indexThemesPreset].theme; + } else { + return null; + } + } } diff --git a/apps/onyx/lib/screens/settings/widgets/draggable_zone_widget.dart b/apps/onyx/lib/screens/settings/widgets/draggable_zone_widget.dart index c4487f6d..7118ad7e 100644 --- a/apps/onyx/lib/screens/settings/widgets/draggable_zone_widget.dart +++ b/apps/onyx/lib/screens/settings/widgets/draggable_zone_widget.dart @@ -82,9 +82,9 @@ class DraggableZoneWidget extends StatelessWidget { ), lastListTargetSize: 0.0, itemDragHandle: DragHandle( - verticalAlignment: DragHandleVerticalAlignment.center, + verticalAlignment: DragHandleVerticalAlignment.top, child: Container( - padding: EdgeInsets.symmetric(horizontal: 5.w), + padding: EdgeInsets.symmetric(horizontal: 5.w, vertical: 1.h), child: Icon( Icons.drag_indicator_rounded, size: 30, diff --git a/apps/onyx/lib/screens/settings/widgets/screen_settings/settings_settings_widget.dart b/apps/onyx/lib/screens/settings/widgets/screen_settings/settings_settings_widget.dart index 3411037e..be00baec 100644 --- a/apps/onyx/lib/screens/settings/widgets/screen_settings/settings_settings_widget.dart +++ b/apps/onyx/lib/screens/settings/widgets/screen_settings/settings_settings_widget.dart @@ -83,9 +83,9 @@ class SettingsSettingsWidget extends StatelessWidget { builder: (context, themeState) { return TextSwitchWidget( text: 'Changer automatiquement au theme selectionné', - value: themeState.themesUserData!.changeAutoTheme, + value: themeState.themesSettings!.autoSwitchTheme, onChanged: (bool value) { - context.read().setChangeAutoTheme(value); + context.read().updateAutoSwitchTheme(value); }, ); }, diff --git a/apps/onyx/lib/screens/settings/widgets/theme_swap/theme_button.dart b/apps/onyx/lib/screens/settings/widgets/theme_swap/theme_button.dart new file mode 100644 index 00000000..99651edf --- /dev/null +++ b/apps/onyx/lib/screens/settings/widgets/theme_swap/theme_button.dart @@ -0,0 +1,135 @@ +import 'package:flutter/material.dart'; +import 'package:flutter_bloc/flutter_bloc.dart'; +import 'package:onyx/screens/settings/settings_export.dart'; +import 'package:onyx/screens/settings/states/theme_cubit.dart'; + +class ThemeButton extends StatelessWidget { + const ThemeButton({ + super.key, + required this.themesCreated, + required this.themesPreset, + }); + final List themesPreset; + final List themesCreated; + + @override + Widget build(BuildContext context) { + return BlocBuilder( + builder: (context, state) { + List listThemes = themesCreated + themesPreset; + return GridView.builder( + shrinkWrap: true, + padding: listThemes.isNotEmpty ? const EdgeInsets.all(10.0) : null, + physics: const NeverScrollableScrollPhysics(), + gridDelegate: const SliverGridDelegateWithFixedCrossAxisCount( + crossAxisCount: 2, + childAspectRatio: 2.5, + crossAxisSpacing: 10, + mainAxisSpacing: 10, + ), + itemCount: listThemes.length, + itemBuilder: (context, index) => GestureDetector( + onTap: () { + context + .read() + .chooseTheme(listThemes[index]) + .then((value) { + if (state.themesSettings!.autoSwitchTheme) { + context.read().updateThemeMode( + listThemes[index].theme.brightness.toThemeModeEnum); + } + }); + }, + onDoubleTap: () { + context.read().toggleThemeFavorite(listThemes[index]); + }, + // onLongPress: () { + // if (state.themesSettings!.themesPreset + // .contains(listThemes[index])) { + // popupMenuThemeCreated(context, listThemes[index]); + // } + // }, + child: Stack( + children: [ + Container( + decoration: BoxDecoration( + color: listThemes[index].theme.cardColor, + borderRadius: BorderRadius.circular(20.0), + border: Border.all( + color: listThemes[index].theme.colorScheme.primary, + width: 4, + ), + ), + child: Center( + child: Text( + listThemes[index].name.replaceAll('_', ' '), + textAlign: TextAlign.center, + style: TextStyle( + fontWeight: ((listThemes[index].name == + state.themesSettings!.darkThemeSelected || + listThemes[index].name == + state.themesSettings!.lightThemeSelected)) + ? FontWeight.w900 + : FontWeight.normal, + color: listThemes[index] + .theme + .textTheme + .labelLarge + ?.color ?? + Colors.black, + ), + ), + ), + ), + if (state.themesSettings!.favoriteThemes.indexWhere( + (element) => element.name == listThemes[index].name) != + -1) + Positioned( + top: 15, + right: 18 - (index + 1) % 2 * 2, + child: const Icon( + Icons.favorite, + color: Colors.red, + size: 20, + ), + ), + ], + ), + ), + ); + }, + ); + } + + void popupMenuThemeCreated(BuildContext context, ThemeModel theme) { + final RenderBox renderBox = context.findRenderObject()! as RenderBox; + final Offset position = renderBox.localToGlobal(Offset.zero); + showMenu( + context: context, + position: RelativeRect.fromRect( + position & const Size(40, 40), + Offset.zero & context.size!, + ), + items: [ + const PopupMenuItem( + value: 'Modifier', + child: Text('Modifier'), + ), + const PopupMenuItem( + value: 'Supprimer', + child: Text('Supprimer'), + ), + ], + ).then((value) { + if (value != null) { + switch (value) { + case 'Modifier': + break; + case 'Supprimer': + context.read().deleteTheme(theme); + break; + } + } + }); + } +} diff --git a/apps/onyx/lib/screens/settings/widgets/theme_swap/theme_list_expansion_tile.dart b/apps/onyx/lib/screens/settings/widgets/theme_swap/theme_list_expansion_tile.dart new file mode 100644 index 00000000..fa6c3394 --- /dev/null +++ b/apps/onyx/lib/screens/settings/widgets/theme_swap/theme_list_expansion_tile.dart @@ -0,0 +1,42 @@ +import 'package:flutter/material.dart'; +import 'package:onyx/screens/settings/settings_export.dart'; +import 'package:onyx/screens/settings/widgets/theme_swap/theme_button.dart'; + +class ThemeListExpansionTile extends StatelessWidget { + const ThemeListExpansionTile({ + super.key, + required this.title, + required this.themesPreset, + required this.themesCreated, + }); + final String title; + final List themesPreset; + final List themesCreated; + @override + Widget build(BuildContext context) { + return Card( + margin: const EdgeInsets.symmetric(horizontal: 16.0, vertical: 8.0), + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.circular(16.0), + ), + child: Theme( + data: Theme.of(context).copyWith(dividerColor: Colors.transparent), + child: ExpansionTile( + childrenPadding: EdgeInsets.zero, + title: Container( + padding: const EdgeInsets.all(10), + child: Text( + title, + ), + ), + children: [ + ThemeButton( + themesCreated: themesCreated, + themesPreset: themesPreset, + ), + ], + ), + ), + ); + } +}