diff --git a/.vscode/tasks.json b/.vscode/tasks.json index b0f327f..5dbc715 100644 --- a/.vscode/tasks.json +++ b/.vscode/tasks.json @@ -84,6 +84,24 @@ "options": { "cwd": "${workspaceFolder}" } + }, + { + "type": "flutter", + "command": "dart", + "args": [ + "run", + "build_runner", + "watch" + ], + "problemMatcher": [ + "$dart-build_runner" + ], + "group": "build", + "label": "dart: dart pub run build_runner watch", + "detail": "", + "runOptions": { + "runOn": "folderOpen" + } } ], } \ No newline at end of file diff --git a/build.yaml b/build.yaml index 18bfb55..82d02cd 100644 --- a/build.yaml +++ b/build.yaml @@ -3,7 +3,9 @@ targets: sources: - lib/$lib$ - "**/models/**.dart" + - "**/models/**/**.dart" - "**/providers/**.dart" + - "**/providers/**/**.dart" - lib/util/**.dart - lib/jellyfin/**.dart - "**/**_screen.dart" @@ -33,16 +35,17 @@ targets: ignoreNull: true discriminatorKey: type generateMethods: [decode, encode, copy, stringify] + chopper_generator: + options: + header: "//Generated jellyfin api code" + include_if_null: false swagger_dart_code_generator: options: input_folder: "swagger/" output_folder: "lib/jellyfin/" + generate_for: swagger/** with_converter: true build_only_models: false with_base_url: false include_if_null: false auto_apply: dependents - chopper_generator: - options: - header: "//Generated jellyfin api code" - include_if_null: false diff --git a/lib/l10n/app_en.arb b/lib/l10n/app_en.arb index 0b068f2..40fb946 100644 --- a/lib/l10n/app_en.arb +++ b/lib/l10n/app_en.arb @@ -1105,5 +1105,15 @@ "deviceOrientationPortraitUp": "Portrait Up", "deviceOrientationPortraitDown": "Portrait Down", "deviceOrientationLandscapeLeft": "Landscape Left", - "deviceOrientationLandscapeRight": "Landscape Right" + "deviceOrientationLandscapeRight": "Landscape Right", + "clientSettingsSchemeVariantTitle": "Scheme variant", + "schemeSettingsTonalSpot": "Tonal spot", + "schemeSettingsFidelity": "Fidelity", + "schemeSettingsMonochrome": "Monochrome", + "schemeSettingsNeutral": "Neutral", + "schemeSettingsVibrant": "Vibrant", + "schemeSettingsExpressive": "Expressive", + "schemeSettingsContent": "Content", + "schemeSettingsRainbow": "Rainbow", + "schemeSettingsFruitSalad": "Fruit salad" } diff --git a/lib/main.dart b/lib/main.dart index f71a542..90fb94e 100644 --- a/lib/main.dart +++ b/lib/main.dart @@ -274,6 +274,7 @@ class _MainState extends ConsumerState
with WindowListener, WidgetsBinding final themeColor = ref.watch(clientSettingsProvider.select((value) => value.themeColor)); final amoledBlack = ref.watch(clientSettingsProvider.select((value) => value.amoledBlack)); final mouseDrag = ref.watch(clientSettingsProvider.select((value) => value.mouseDragSupport)); + final schemeVariant = ref.watch(clientSettingsProvider.select((value) => value.schemeVariant)); final language = ref.watch(clientSettingsProvider .select((value) => value.selectedLocale ?? WidgetsBinding.instance.platformDispatcher.locale)); final scrollBehaviour = const MaterialScrollBehavior(); @@ -283,11 +284,11 @@ class _MainState extends ConsumerState
with WindowListener, WidgetsBinding }, child: DynamicColorBuilder(builder: (ColorScheme? lightDynamic, ColorScheme? darkDynamic) { final lightTheme = themeColor == null - ? FladderTheme.theme(lightDynamic ?? FladderTheme.defaultScheme(Brightness.light)) - : FladderTheme.theme(themeColor.schemeLight); + ? FladderTheme.theme(lightDynamic ?? FladderTheme.defaultScheme(Brightness.light), schemeVariant) + : FladderTheme.theme(themeColor.schemeLight, schemeVariant); final darkTheme = (themeColor == null - ? FladderTheme.theme(darkDynamic ?? FladderTheme.defaultScheme(Brightness.dark)) - : FladderTheme.theme(themeColor.schemeDark)); + ? FladderTheme.theme(darkDynamic ?? FladderTheme.defaultScheme(Brightness.dark), schemeVariant) + : FladderTheme.theme(themeColor.schemeDark, schemeVariant)); final amoledOverwrite = amoledBlack ? Colors.black : null; return ThemesData( light: lightTheme, diff --git a/lib/models/settings/client_settings_model.dart b/lib/models/settings/client_settings_model.dart index cdde03c..9b5196d 100644 --- a/lib/models/settings/client_settings_model.dart +++ b/lib/models/settings/client_settings_model.dart @@ -30,6 +30,7 @@ class ClientSettingsModel with _$ClientSettingsModel { @Default(1.0) double posterSize, @Default(false) bool pinchPosterZoom, @Default(false) bool mouseDragSupport, + @Default(DynamicSchemeVariant.tonalSpot) DynamicSchemeVariant schemeVariant, int? libraryPageSize, }) = _ClientSettingsModel; diff --git a/lib/models/settings/client_settings_model.freezed.dart b/lib/models/settings/client_settings_model.freezed.dart index 4036e9f..428de95 100644 --- a/lib/models/settings/client_settings_model.freezed.dart +++ b/lib/models/settings/client_settings_model.freezed.dart @@ -36,6 +36,7 @@ mixin _$ClientSettingsModel { double get posterSize => throw _privateConstructorUsedError; bool get pinchPosterZoom => throw _privateConstructorUsedError; bool get mouseDragSupport => throw _privateConstructorUsedError; + DynamicSchemeVariant get schemeVariant => throw _privateConstructorUsedError; int? get libraryPageSize => throw _privateConstructorUsedError; /// Serializes this ClientSettingsModel to a JSON map. @@ -70,6 +71,7 @@ abstract class $ClientSettingsModelCopyWith<$Res> { double posterSize, bool pinchPosterZoom, bool mouseDragSupport, + DynamicSchemeVariant schemeVariant, int? libraryPageSize}); } @@ -103,6 +105,7 @@ class _$ClientSettingsModelCopyWithImpl<$Res, $Val extends ClientSettingsModel> Object? posterSize = null, Object? pinchPosterZoom = null, Object? mouseDragSupport = null, + Object? schemeVariant = null, Object? libraryPageSize = freezed, }) { return _then(_value.copyWith( @@ -166,6 +169,10 @@ class _$ClientSettingsModelCopyWithImpl<$Res, $Val extends ClientSettingsModel> ? _value.mouseDragSupport : mouseDragSupport // ignore: cast_nullable_to_non_nullable as bool, + schemeVariant: null == schemeVariant + ? _value.schemeVariant + : schemeVariant // ignore: cast_nullable_to_non_nullable + as DynamicSchemeVariant, libraryPageSize: freezed == libraryPageSize ? _value.libraryPageSize : libraryPageSize // ignore: cast_nullable_to_non_nullable @@ -198,6 +205,7 @@ abstract class _$$ClientSettingsModelImplCopyWith<$Res> double posterSize, bool pinchPosterZoom, bool mouseDragSupport, + DynamicSchemeVariant schemeVariant, int? libraryPageSize}); } @@ -229,6 +237,7 @@ class __$$ClientSettingsModelImplCopyWithImpl<$Res> Object? posterSize = null, Object? pinchPosterZoom = null, Object? mouseDragSupport = null, + Object? schemeVariant = null, Object? libraryPageSize = freezed, }) { return _then(_$ClientSettingsModelImpl( @@ -292,6 +301,10 @@ class __$$ClientSettingsModelImplCopyWithImpl<$Res> ? _value.mouseDragSupport : mouseDragSupport // ignore: cast_nullable_to_non_nullable as bool, + schemeVariant: null == schemeVariant + ? _value.schemeVariant + : schemeVariant // ignore: cast_nullable_to_non_nullable + as DynamicSchemeVariant, libraryPageSize: freezed == libraryPageSize ? _value.libraryPageSize : libraryPageSize // ignore: cast_nullable_to_non_nullable @@ -320,6 +333,7 @@ class _$ClientSettingsModelImpl extends _ClientSettingsModel this.posterSize = 1.0, this.pinchPosterZoom = false, this.mouseDragSupport = false, + this.schemeVariant = DynamicSchemeVariant.tonalSpot, this.libraryPageSize}) : super._(); @@ -369,11 +383,14 @@ class _$ClientSettingsModelImpl extends _ClientSettingsModel @JsonKey() final bool mouseDragSupport; @override + @JsonKey() + final DynamicSchemeVariant schemeVariant; + @override final int? libraryPageSize; @override String toString({DiagnosticLevel minLevel = DiagnosticLevel.info}) { - return 'ClientSettingsModel(syncPath: $syncPath, position: $position, size: $size, timeOut: $timeOut, nextUpDateCutoff: $nextUpDateCutoff, themeMode: $themeMode, themeColor: $themeColor, amoledBlack: $amoledBlack, blurPlaceHolders: $blurPlaceHolders, blurUpcomingEpisodes: $blurUpcomingEpisodes, selectedLocale: $selectedLocale, enableMediaKeys: $enableMediaKeys, posterSize: $posterSize, pinchPosterZoom: $pinchPosterZoom, mouseDragSupport: $mouseDragSupport, libraryPageSize: $libraryPageSize)'; + return 'ClientSettingsModel(syncPath: $syncPath, position: $position, size: $size, timeOut: $timeOut, nextUpDateCutoff: $nextUpDateCutoff, themeMode: $themeMode, themeColor: $themeColor, amoledBlack: $amoledBlack, blurPlaceHolders: $blurPlaceHolders, blurUpcomingEpisodes: $blurUpcomingEpisodes, selectedLocale: $selectedLocale, enableMediaKeys: $enableMediaKeys, posterSize: $posterSize, pinchPosterZoom: $pinchPosterZoom, mouseDragSupport: $mouseDragSupport, schemeVariant: $schemeVariant, libraryPageSize: $libraryPageSize)'; } @override @@ -396,6 +413,7 @@ class _$ClientSettingsModelImpl extends _ClientSettingsModel ..add(DiagnosticsProperty('posterSize', posterSize)) ..add(DiagnosticsProperty('pinchPosterZoom', pinchPosterZoom)) ..add(DiagnosticsProperty('mouseDragSupport', mouseDragSupport)) + ..add(DiagnosticsProperty('schemeVariant', schemeVariant)) ..add(DiagnosticsProperty('libraryPageSize', libraryPageSize)); } @@ -432,6 +450,8 @@ class _$ClientSettingsModelImpl extends _ClientSettingsModel other.pinchPosterZoom == pinchPosterZoom) && (identical(other.mouseDragSupport, mouseDragSupport) || other.mouseDragSupport == mouseDragSupport) && + (identical(other.schemeVariant, schemeVariant) || + other.schemeVariant == schemeVariant) && (identical(other.libraryPageSize, libraryPageSize) || other.libraryPageSize == libraryPageSize)); } @@ -455,6 +475,7 @@ class _$ClientSettingsModelImpl extends _ClientSettingsModel posterSize, pinchPosterZoom, mouseDragSupport, + schemeVariant, libraryPageSize); /// Create a copy of ClientSettingsModel @@ -491,6 +512,7 @@ abstract class _ClientSettingsModel extends ClientSettingsModel { final double posterSize, final bool pinchPosterZoom, final bool mouseDragSupport, + final DynamicSchemeVariant schemeVariant, final int? libraryPageSize}) = _$ClientSettingsModelImpl; _ClientSettingsModel._() : super._(); @@ -529,6 +551,8 @@ abstract class _ClientSettingsModel extends ClientSettingsModel { @override bool get mouseDragSupport; @override + DynamicSchemeVariant get schemeVariant; + @override int? get libraryPageSize; /// Create a copy of ClientSettingsModel diff --git a/lib/models/settings/client_settings_model.g.dart b/lib/models/settings/client_settings_model.g.dart index 4b71fd5..06ef948 100644 --- a/lib/models/settings/client_settings_model.g.dart +++ b/lib/models/settings/client_settings_model.g.dart @@ -34,6 +34,9 @@ _$ClientSettingsModelImpl _$$ClientSettingsModelImplFromJson( posterSize: (json['posterSize'] as num?)?.toDouble() ?? 1.0, pinchPosterZoom: json['pinchPosterZoom'] as bool? ?? false, mouseDragSupport: json['mouseDragSupport'] as bool? ?? false, + schemeVariant: $enumDecodeNullable( + _$DynamicSchemeVariantEnumMap, json['schemeVariant']) ?? + DynamicSchemeVariant.tonalSpot, libraryPageSize: (json['libraryPageSize'] as num?)?.toInt(), ); @@ -55,6 +58,7 @@ Map _$$ClientSettingsModelImplToJson( 'posterSize': instance.posterSize, 'pinchPosterZoom': instance.pinchPosterZoom, 'mouseDragSupport': instance.mouseDragSupport, + 'schemeVariant': _$DynamicSchemeVariantEnumMap[instance.schemeVariant]!, 'libraryPageSize': instance.libraryPageSize, }; @@ -81,3 +85,15 @@ const _$ColorThemesEnumMap = { ColorThemes.deepPurple: 'deepPurple', ColorThemes.blueGrey: 'blueGrey', }; + +const _$DynamicSchemeVariantEnumMap = { + DynamicSchemeVariant.tonalSpot: 'tonalSpot', + DynamicSchemeVariant.fidelity: 'fidelity', + DynamicSchemeVariant.monochrome: 'monochrome', + DynamicSchemeVariant.neutral: 'neutral', + DynamicSchemeVariant.vibrant: 'vibrant', + DynamicSchemeVariant.expressive: 'expressive', + DynamicSchemeVariant.content: 'content', + DynamicSchemeVariant.rainbow: 'rainbow', + DynamicSchemeVariant.fruitSalad: 'fruitSalad', +}; diff --git a/lib/providers/settings/client_settings_provider.dart b/lib/providers/settings/client_settings_provider.dart index 032f8d1..aa5f1a3 100644 --- a/lib/providers/settings/client_settings_provider.dart +++ b/lib/providers/settings/client_settings_provider.dart @@ -1,9 +1,11 @@ +import 'package:flutter/material.dart'; + +import 'package:flutter_riverpod/flutter_riverpod.dart'; + import 'package:fladder/models/settings/client_settings_model.dart'; import 'package:fladder/providers/shared_provider.dart'; import 'package:fladder/util/custom_color_themes.dart'; import 'package:fladder/util/debouncer.dart'; -import 'package:flutter/material.dart'; -import 'package:flutter_riverpod/flutter_riverpod.dart'; final clientSettingsProvider = StateNotifierProvider((ref) { return ClientSettingsNotifier(ref); @@ -51,4 +53,7 @@ class ClientSettingsNotifier extends StateNotifier { void setSyncPath(String? path) => state = state.copyWith(syncPath: path); void update(Function(ClientSettingsModel current) value) => state = value(state); + + void setSchemeVariant(DynamicSchemeVariant? type) => + state = state.copyWith(schemeVariant: type ?? state.schemeVariant); } diff --git a/lib/screens/settings/client_settings_page.dart b/lib/screens/settings/client_settings_page.dart index f8db21a..3c5705b 100644 --- a/lib/screens/settings/client_settings_page.dart +++ b/lib/screens/settings/client_settings_page.dart @@ -20,6 +20,7 @@ import 'package:fladder/screens/settings/widgets/settings_label_divider.dart'; import 'package:fladder/screens/shared/default_alert_dialog.dart'; import 'package:fladder/screens/shared/input_fields.dart'; import 'package:fladder/util/adaptive_layout.dart'; +import 'package:fladder/util/color_extensions.dart'; import 'package:fladder/util/custom_color_themes.dart'; import 'package:fladder/util/localization_helper.dart'; import 'package:fladder/util/option_dialogue.dart'; @@ -428,6 +429,33 @@ class _ClientSettingsPageState extends ConsumerState { ), ), ), + SettingsListTile( + label: Text(context.localized.clientSettingsSchemeVariantTitle), + subLabel: Text(clientSettings.schemeVariant.label(context)), + onTap: () => openOptionDialogue( + context, + isNullable: false, + label: context.localized.themeColor, + items: DynamicSchemeVariant.values, + itemBuilder: (type) => Consumer( + builder: (context, ref, child) => ListTile( + title: Row( + children: [ + Checkbox.adaptive( + value: type == ref.watch(clientSettingsProvider.select((value) => value.schemeVariant)), + onChanged: (value) => ref.read(clientSettingsProvider.notifier).setSchemeVariant(type), + ), + const SizedBox(width: 8), + Text(type?.label(context) ?? ""), + ], + ), + contentPadding: EdgeInsets.zero, + shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(16)), + onTap: () => ref.read(clientSettingsProvider.notifier).setSchemeVariant(type), + ), + ), + ), + ), SettingsListTile( label: Text(context.localized.amoledBlack), subLabel: Text(clientSettings.amoledBlack ? context.localized.enabled : context.localized.disabled), diff --git a/lib/theme.dart b/lib/theme.dart index 6b5d8c1..4391ecf 100644 --- a/lib/theme.dart +++ b/lib/theme.dart @@ -5,9 +5,13 @@ import 'package:dynamic_color/dynamic_color.dart'; import 'package:fladder/theme/fonts.dart'; import 'package:fladder/util/custom_color_themes.dart'; -ColorScheme? generateDynamicColourSchemes(ColorScheme? theme) { +ColorScheme? generateDynamicColourSchemes(ColorScheme? theme, DynamicSchemeVariant dynamicSchemeVariant) { if (theme == null) return null; - var base = ColorScheme.fromSeed(seedColor: theme.primary, brightness: theme.brightness); + var base = ColorScheme.fromSeed( + seedColor: theme.primary, + dynamicSchemeVariant: dynamicSchemeVariant, + brightness: theme.brightness, + ); var newScheme = _insertAdditionalColours(base); @@ -33,8 +37,8 @@ class FladderTheme { static Color get darkBackgroundColor => const Color.fromARGB(255, 10, 10, 10); static Color get lightBackgroundColor => const Color.fromARGB(237, 255, 255, 255); - static ThemeData theme(ColorScheme? colorScheme) { - final ColorScheme? scheme = generateDynamicColourSchemes(colorScheme); + static ThemeData theme(ColorScheme? colorScheme, DynamicSchemeVariant dynamicSchemeVariant) { + final ColorScheme? scheme = generateDynamicColourSchemes(colorScheme, dynamicSchemeVariant); final textTheme = FladderFonts.rubikTextTheme( const TextTheme(), diff --git a/lib/util/color_extensions.dart b/lib/util/color_extensions.dart new file mode 100644 index 0000000..e934e31 --- /dev/null +++ b/lib/util/color_extensions.dart @@ -0,0 +1,17 @@ +import 'package:flutter/material.dart'; + +import 'package:fladder/util/localization_helper.dart'; + +extension DynamicSchemeVariantExtension on DynamicSchemeVariant { + String label(BuildContext context) => switch (this) { + DynamicSchemeVariant.tonalSpot => context.localized.schemeSettingsTonalSpot, + DynamicSchemeVariant.fidelity => context.localized.schemeSettingsFidelity, + DynamicSchemeVariant.monochrome => context.localized.schemeSettingsMonochrome, + DynamicSchemeVariant.neutral => context.localized.schemeSettingsNeutral, + DynamicSchemeVariant.vibrant => context.localized.schemeSettingsVibrant, + DynamicSchemeVariant.expressive => context.localized.schemeSettingsExpressive, + DynamicSchemeVariant.content => context.localized.schemeSettingsContent, + DynamicSchemeVariant.rainbow => context.localized.schemeSettingsRainbow, + DynamicSchemeVariant.fruitSalad => context.localized.schemeSettingsFruitSalad, + }; +}