rewrite: Added themes settings

This commit is contained in:
Kevin Rodrigues Borges
2026-02-23 14:55:10 +00:00
parent 92f2f78087
commit 690f0929f7
17 changed files with 314 additions and 65 deletions

View File

@@ -361,6 +361,21 @@ class AnimeDetailsCubit extends Cubit<AnimeDetailsState> with EffectMixin<AnimeD
context: context,
firstDate: DateTime.now().subtract(const Duration(days: 365)),
lastDate: DateTime.now().add(const Duration(days: 365)),
builder: (context, child) {
return Theme(
data: Theme.of(context).copyWith(
datePickerTheme: DatePickerThemeData(
confirmButtonStyle: TextButton.styleFrom(
foregroundColor: Colors.white,
),
cancelButtonStyle: TextButton.styleFrom(
foregroundColor: Colors.white,
),
),
),
child: child!,
);
},
);
if (selectedDateTime == null) return;
try {
@@ -382,6 +397,21 @@ class AnimeDetailsCubit extends Cubit<AnimeDetailsState> with EffectMixin<AnimeD
context: context,
firstDate: DateTime.now().subtract(const Duration(days: 365)),
lastDate: DateTime.now().add(const Duration(days: 365)),
builder: (context, child) {
return Theme(
data: Theme.of(context).copyWith(
datePickerTheme: DatePickerThemeData(
confirmButtonStyle: TextButton.styleFrom(
foregroundColor: Colors.white,
),
cancelButtonStyle: TextButton.styleFrom(
foregroundColor: Colors.white,
),
),
),
child: child!,
);
},
);
if (selectedDateTime == null) return;
try {

View File

@@ -148,20 +148,31 @@ class LoginCubit extends Cubit<LoginState> with EffectMixin<LoginState> {
}
void setUsersTheme(User user) async {
switch (user) {
case AnilistUserModel anilistUserModel:
_logger.d("Getting anilist user's theme");
List<Color> userColors = await _colorImageService
.getColorsFromPalleteGenerator(
NetworkImage(anilistUserModel.bannerImage),
);
_themeService.updateThemeFromColors(
primary: userColors[0],
secondary: userColors[1],
tertiary: userColors[2],
);
case LocalUserModel localUserModel:
_logger.d("Getting local user's theme");
List<Color> wallpaperColors = [];
if (user.settings.useWallpaperAsThemeColor) {
switch (user) {
case AnilistUserModel anilistUserModel:
_logger.d("Getting anilist user's theme");
wallpaperColors = await _colorImageService
.getColorsFromPalleteGenerator(
NetworkImage(anilistUserModel.bannerImage),
);
case LocalUserModel localUserModel:
_logger.d("Getting local user's theme");
}
_themeService.updateThemeFromColors(
loggedUser: user,
useWallpaperAsThemeColor: true,
primary: wallpaperColors[0],
secondary: wallpaperColors[1],
tertiary: wallpaperColors[2],
);
} else {
_themeService.updateThemeFromColors(
loggedUser: user,
useWallpaperAsThemeColor: false,
primary: user.settings.themeColor,
);
}
}

View File

@@ -1,5 +1,7 @@
import 'dart:async';
import 'package:flutter/material.dart';
import 'package:flutter_colorpicker/flutter_colorpicker.dart';
import 'package:flutter_screenutil/flutter_screenutil.dart';
import 'package:logger/logger.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
@@ -14,23 +16,42 @@ import 'package:unyo/core/notification/reload/reload_type.dart';
import 'package:unyo/core/notification/user_notifier.dart';
import 'package:unyo/core/services/media/episode_service.dart';
import 'package:unyo/core/services/media/media_service.dart';
import 'package:unyo/core/theme/color_image_service.dart';
import 'package:unyo/core/theme/theme_service.dart';
import 'package:unyo/data/models/anilist_user_model.dart';
import 'package:unyo/data/models/local_user_model.dart';
import 'package:unyo/data/repositories/repositories.dart';
import 'package:unyo/domain/entities/settings.dart';
import 'package:unyo/domain/entities/user.dart';
import 'package:unyo/presentation/dialogs/textfield_dialog.dart';
import 'package:unyo/presentation/widgets/styled/dark_unyo_button.dart';
import 'package:unyo/presentation/widgets/styled/light_unyo_button.dart';
class SettingsCubit extends Cubit<SettingsState> with EffectMixin<SettingsState> {
final Logger _logger = sl<Logger>();
late Color _selectedColor;
// Repositories
final UserRepositoryAnilist _userRepositoryAnilist;
final UserRepositoryLocal _userRepositoryLocal;
// Notifiers
final UserNotifier _loggedUserNotifier;
final ReloadNotifier _reloadNotifier;
late StreamSubscription<User> _loggedUserSubscription;
SettingsCubit(this._userRepositoryAnilist, this._userRepositoryLocal, this._loggedUserNotifier, this._reloadNotifier)
: super(SettingsState(loggedUser: UserModel.empty())) {
// Services
final ThemeService _themeService;
final ColorImageService _colorImageService;
SettingsCubit(
this._userRepositoryAnilist,
this._userRepositoryLocal,
this._loggedUserNotifier,
this._reloadNotifier,
this._themeService,
this._colorImageService,
) : super(SettingsState(loggedUser: UserModel.empty())) {
_init();
}
@@ -52,6 +73,7 @@ class SettingsCubit extends Cubit<SettingsState> with EffectMixin<SettingsState>
_loggedUserSubscription = _loggedUserNotifier.userStream.listen((loggedUser) async {
emit(state.copyWith(loggedUser: loggedUser));
});
_selectedColor = state.loggedUser.settings.themeColor;
}
Future<void> updateMediaMetadataService(String? newService) async {
@@ -181,6 +203,32 @@ class SettingsCubit extends Cubit<SettingsState> with EffectMixin<SettingsState>
}
}
Future<void> enableUseWallpaperAsThemeColor(bool enable) async {
if (!enable) return;
try {
List<Color> wallpaperColors = [];
switch (state.loggedUser) {
case AnilistUserModel anilistUserModel:
_logger.d("Getting anilist user's theme");
wallpaperColors = await _colorImageService.getColorsFromPalleteGenerator(
NetworkImage(anilistUserModel.bannerImage),
);
case LocalUserModel localUserModel:
_logger.d("Getting local user's theme");
}
_themeService.updateThemeFromColors(
loggedUser: state.loggedUser,
useWallpaperAsThemeColor: true,
primary: wallpaperColors[0],
secondary: wallpaperColors[1],
tertiary: wallpaperColors[2],
);
} catch (e, stackTrace) {
logger.e("Error enabling/disabling using the user wallpaper as a Theme $e", stackTrace: stackTrace);
handleError("Error enabling/disabling using the user wallpaper as a Theme", stackTrace: stackTrace);
}
}
Future<void> manualSkipTimeUpdate(double newSkipTime) async {
try {
Settings updatedSettings = (state.loggedUser.settings as SettingsModel).copyWith(
@@ -243,6 +291,61 @@ class SettingsCubit extends Cubit<SettingsState> with EffectMixin<SettingsState>
);
}
void openColorPickerDialog(BuildContext context) {
showWidgetDialogEffect(
dialog: AlertDialog(
backgroundColor: const Color.fromARGB(255, 30, 30, 30),
titlePadding: EdgeInsetsDirectional.only(start: 24.0.w, top: 20.0.h),
title: const Text(
"Pick a color to get a theme based on that color",
style: TextStyle(color: Colors.white, fontWeight: FontWeight.bold, fontSize: 22),
),
content: Padding(
padding: EdgeInsets.symmetric(horizontal: 12.0.w, vertical: 12.0.h),
child: SingleChildScrollView(
child: Builder(
builder: (dialogContext) {
return Column(
children: [
ColorPicker(
enableAlpha: false,
pickerColor: state.loggedUser.settings.themeColor,
pickerAreaBorderRadius: BorderRadius.circular(40.0),
onColorChanged: (color) => _selectedColor = color,
),
Row(
mainAxisAlignment: MainAxisAlignment.end,
children: [
DarkUnyoButton(
text: "Cancel",
maxHeight: 50,
onPressed: () => Navigator.of(dialogContext).pop(),
),
SizedBox(width: 25.0.w),
LightUnyoButton(
text: "Confirm",
maxHeight: 50,
onPressed: () {
_themeService.updateThemeFromColors(
loggedUser: state.loggedUser,
primary: _selectedColor,
useWallpaperAsThemeColor: false,
);
Navigator.of(dialogContext).pop();
},
),
],
),
],
);
}
),
),
),
),
);
}
Future<void> _updateUserInfo(Settings settings) async {
try {
switch (state.loggedUser) {

View File

@@ -65,7 +65,6 @@ void setupLocator() async{
instanceName: config.anilistGraphQlService,
);
sl.registerLazySingleton<AppEffectHandler>(() => AppEffectHandler());
sl.registerSingleton<ThemeService>(ThemeService());
sl.registerLazySingleton<ColorImageService>(() => ColorImageService());
sl.registerSingleton<AniyomiBridge>(AniyomiBridge());
sl.registerSingleton<TorrentService>(TorrentService());
@@ -93,6 +92,10 @@ void setupLocator() async{
sl<UserNotifier>(instanceName: config.loggedUserNotifier),
),
);
sl.registerSingleton<ThemeService>(ThemeService(
sl<UserRepositoryAnilist>(),
sl<UserRepositoryLocal>(),
));
sl.registerLazySingleton<AnimeRepositoryAnilist>(() => AnimeRepositoryAnilist());
sl.registerLazySingleton<MangaRepositoryAnilist>(() => MangaRepositoryAnilist());
sl.registerLazySingleton<EpisodeRepositoryAnizip>(() => EpisodeRepositoryAnizip());
@@ -199,7 +202,9 @@ void setupLocator() async{
sl<UserRepositoryAnilist>(),
sl<UserRepositoryLocal>(),
sl<UserNotifier>(instanceName: config.loggedUserNotifier),
sl<ReloadNotifier>()
sl<ReloadNotifier>(),
sl<ThemeService>(),
sl<ColorImageService>()
),
);
sl.registerFactory<AnimeAdvancedSearchCubit>(

View File

@@ -21,7 +21,7 @@ class HttpService {
final Map<String, (int, dynamic)> _apiResponseCache = {};
HttpService({
this.timeout = const Duration(seconds: 7),
this.timeout = const Duration(seconds: 10),
this.retryOptions = const RetryOptions(maxAttempts: 2),
});

View File

@@ -1,11 +1,20 @@
import 'package:flutter/material.dart';
import 'package:rxdart/rxdart.dart';
import 'package:unyo/data/models/anilist_user_model.dart';
import 'package:unyo/data/models/local_user_model.dart';
import 'package:unyo/data/repositories/user_repository_anilist.dart';
import 'package:unyo/data/repositories/user_repository_local.dart';
import 'package:unyo/domain/entities/settings.dart';
import 'package:unyo/domain/entities/user.dart';
class ThemeService {
final BehaviorSubject<ThemeData> _themeSubject;
/*= BehaviorSubject<ThemeData>.seeded(_defaultTheme);*/
ThemeService()
// Repositories
final UserRepositoryAnilist _userRepositoryAnilist;
final UserRepositoryLocal _userRepositoryLocal;
ThemeService(this._userRepositoryAnilist, this._userRepositoryLocal)
: _themeSubject = BehaviorSubject<ThemeData>.seeded(_defaultTheme);
@@ -14,12 +23,12 @@ class ThemeService {
ThemeData get current => _themeSubject.value;
void updateThemeFromColors(
{required Color primary, Color? secondary, Color? tertiary}) {
{required User loggedUser, required Color primary, required bool useWallpaperAsThemeColor, Color? secondary, Color? tertiary}) {
final newTheme = _defaultTheme.copyWith(
colorScheme: ColorScheme.dark(
primary: primary,
secondary: secondary ?? ColorScheme.fromSeed(seedColor: primary).secondary,
tertiary: tertiary ?? ColorScheme.fromSeed(seedColor: primary).tertiary,
primary: Color.lerp(primary, Colors.black, 0.1) ?? primary,
secondary: secondary ?? (Color.lerp(primary, Colors.black, 0.7) ?? primary),
tertiary: tertiary ?? (Color.lerp(primary, Colors.white, 0.7) ?? primary),
onPrimary: Colors.white,
onSecondary: Colors.white,
onTertiary: Colors.white,
@@ -27,14 +36,33 @@ class ThemeService {
appBarTheme: AppBarTheme(backgroundColor: primary),
);
_themeSubject.add(newTheme);
_updateUserThemeSettings(loggedUser, primary, useWallpaperAsThemeColor, newTheme.colorScheme);
}
void updateThemeFromColorScheme(
{required ColorScheme newcolorScheme}) {
{required User logedUser, required bool useWallpaperAsThemeColor, required ColorScheme newcolorScheme}) {
final newTheme = _defaultTheme.copyWith(
colorScheme: newcolorScheme,
);
_themeSubject.add(newTheme);
_updateUserThemeSettings(logedUser, newcolorScheme.primary, useWallpaperAsThemeColor, newcolorScheme);
}
Future<void> _updateUserThemeSettings(User loggedUser, Color primary, bool useWallpaperAsThemeColor, ColorScheme colorScheme) async {
Settings updatedSettings = (loggedUser.settings as SettingsModel).copyWith(
themeColor: primary,
useWallpaperAsThemeColor: useWallpaperAsThemeColor
);
switch (loggedUser) {
case AnilistUserModel anilistUserModel:
AnilistUserModel updatedAnilistUserModel = anilistUserModel.copyWith(settings: updatedSettings);
await _userRepositoryAnilist.updateUserInfo(updatedAnilistUserModel);
break;
case LocalUserModel localUserModel:
LocalUserModel updatedLocalUserModel = localUserModel.copyWith(settings: updatedSettings);
await _userRepositoryLocal.updateUserInfo(updatedLocalUserModel);
break;
}
}
void setTheme(ThemeData theme) => _themeSubject.add(theme);
@@ -43,14 +71,6 @@ class ThemeService {
final _defaultTheme = ThemeData(
brightness: Brightness.dark,
scaffoldBackgroundColor: const Color.fromARGB(255, 44, 44, 44),
// colorScheme: ColorScheme.dark(
// primary: Colors.grey[200]!,
// secondary: Colors.grey[300]!,
// tertiary: Colors.grey[300]!,
// onPrimary: Colors.white,
// onSecondary: Colors.white,
// onTertiary: Colors.white,
// ),
textTheme: const TextTheme(
// Display styles (largest) - white
displayLarge: TextStyle(

View File

@@ -0,0 +1,29 @@
import 'package:flutter/material.dart';
import 'package:freezed_annotation/freezed_annotation.dart';
import 'package:hive_ce/hive.dart';
class ColorAdapter extends TypeAdapter<Color> {
@override
final int typeId = 100; // Choose an unused typeId in your project
@override
Color read(BinaryReader reader) {
final value = reader.readInt();
return Color(value);
}
@override
void write(BinaryWriter writer, Color obj) {
writer.writeInt(obj.value);
}
}
class ColorConverter implements JsonConverter<Color, int> {
const ColorConverter();
@override
Color fromJson(int json) => Color(json);
@override
int toJson(Color object) => object.value;
}

View File

@@ -1,3 +1,4 @@
import 'package:flutter/material.dart';
import 'package:freezed_annotation/freezed_annotation.dart';
import 'package:hive_ce/hive.dart';
import 'package:unyo/core/enums/episode_service.dart';
@@ -5,6 +6,7 @@ import 'package:unyo/core/enums/service.dart';
import 'package:unyo/data/adapters/adapters_names.dart' as names;
import 'package:unyo/data/adapters/adapters_types.dart' as types;
import 'package:unyo/config/config.dart' as config;
import 'package:unyo/data/adapters/type_adapters/color_adapter.dart';
import 'package:unyo/domain/entities/extension.dart';
part 'settings.freezed.dart';
@@ -27,6 +29,8 @@ abstract class Settings {
final bool autoPlayNextEpisode;
final bool enableOpenSubtitlesIntegration;
final bool enableNsfwContent;
final Color themeColor;
final bool useWallpaperAsThemeColor;
// Not configurable
final List<Extension> installedAnimeExtensions;
final List<Extension> installedMangaExtensions;
@@ -47,6 +51,8 @@ abstract class Settings {
required this.autoPlayNextEpisode,
required this.enableOpenSubtitlesIntegration,
required this.enableNsfwContent,
required this.themeColor,
required this.useWallpaperAsThemeColor,
required this.installedAnimeExtensions,
required this.installedMangaExtensions,
@@ -75,6 +81,8 @@ abstract class SettingsModel with _$SettingsModel implements Settings {
@HiveField(14) @Default(false) bool autoPlayNextEpisode,
@HiveField(15) @Default(false) bool enableOpenSubtitlesIntegration,
@HiveField(16) @Default(false) bool enableNsfwContent,
@HiveField(17) @ColorConverter() @Default(Color(0xFF2196F3)) Color themeColor,
@HiveField(18) @Default(true) bool useWallpaperAsThemeColor,
}) = _SettingsModel;
factory SettingsModel.empty() =>

View File

@@ -15,7 +15,7 @@ T _$identity<T>(T value) => value;
/// @nodoc
mixin _$SettingsModel {
@HiveField(0) String get language;@HiveField(1) Service get service;@HiveField(2) EpisodeService get episodeService;@HiveField(3)@ExtensionConverter() List<Extension> get installedAnimeExtensions;@HiveField(4)@ExtensionConverter() List<Extension> get installedMangaExtensions;@HiveField(5) String get aniyomiExtensionsRepositoryUrl;@HiveField(6) String get tachiyomiExtensionsRepositoryUrl;@HiveField(7)@ExtensionConverter() Map<String, Extension> get mediaExtensionConfigs;@HiveField(8) String get mediaTitleLanguage;@HiveField(9) String get episodeTitleLanguage;@HiveField(10) bool get enableDiscordRichPresence;@HiveField(11) bool get automaticallySkipOpening;@HiveField(12) bool get automaticallySkipEnding;@HiveField(13) int get manualSkipTime;@HiveField(14) bool get autoPlayNextEpisode;@HiveField(15) bool get enableOpenSubtitlesIntegration;@HiveField(16) bool get enableNsfwContent;
@HiveField(0) String get language;@HiveField(1) Service get service;@HiveField(2) EpisodeService get episodeService;@HiveField(3)@ExtensionConverter() List<Extension> get installedAnimeExtensions;@HiveField(4)@ExtensionConverter() List<Extension> get installedMangaExtensions;@HiveField(5) String get aniyomiExtensionsRepositoryUrl;@HiveField(6) String get tachiyomiExtensionsRepositoryUrl;@HiveField(7)@ExtensionConverter() Map<String, Extension> get mediaExtensionConfigs;@HiveField(8) String get mediaTitleLanguage;@HiveField(9) String get episodeTitleLanguage;@HiveField(10) bool get enableDiscordRichPresence;@HiveField(11) bool get automaticallySkipOpening;@HiveField(12) bool get automaticallySkipEnding;@HiveField(13) int get manualSkipTime;@HiveField(14) bool get autoPlayNextEpisode;@HiveField(15) bool get enableOpenSubtitlesIntegration;@HiveField(16) bool get enableNsfwContent;@HiveField(17)@ColorConverter() Color get themeColor;@HiveField(18) bool get useWallpaperAsThemeColor;
/// Create a copy of SettingsModel
/// with the given fields replaced by the non-null parameter values.
@JsonKey(includeFromJson: false, includeToJson: false)
@@ -28,16 +28,16 @@ $SettingsModelCopyWith<SettingsModel> get copyWith => _$SettingsModelCopyWithImp
@override
bool operator ==(Object other) {
return identical(this, other) || (other.runtimeType == runtimeType&&other is SettingsModel&&(identical(other.language, language) || other.language == language)&&(identical(other.service, service) || other.service == service)&&(identical(other.episodeService, episodeService) || other.episodeService == episodeService)&&const DeepCollectionEquality().equals(other.installedAnimeExtensions, installedAnimeExtensions)&&const DeepCollectionEquality().equals(other.installedMangaExtensions, installedMangaExtensions)&&(identical(other.aniyomiExtensionsRepositoryUrl, aniyomiExtensionsRepositoryUrl) || other.aniyomiExtensionsRepositoryUrl == aniyomiExtensionsRepositoryUrl)&&(identical(other.tachiyomiExtensionsRepositoryUrl, tachiyomiExtensionsRepositoryUrl) || other.tachiyomiExtensionsRepositoryUrl == tachiyomiExtensionsRepositoryUrl)&&const DeepCollectionEquality().equals(other.mediaExtensionConfigs, mediaExtensionConfigs)&&(identical(other.mediaTitleLanguage, mediaTitleLanguage) || other.mediaTitleLanguage == mediaTitleLanguage)&&(identical(other.episodeTitleLanguage, episodeTitleLanguage) || other.episodeTitleLanguage == episodeTitleLanguage)&&(identical(other.enableDiscordRichPresence, enableDiscordRichPresence) || other.enableDiscordRichPresence == enableDiscordRichPresence)&&(identical(other.automaticallySkipOpening, automaticallySkipOpening) || other.automaticallySkipOpening == automaticallySkipOpening)&&(identical(other.automaticallySkipEnding, automaticallySkipEnding) || other.automaticallySkipEnding == automaticallySkipEnding)&&(identical(other.manualSkipTime, manualSkipTime) || other.manualSkipTime == manualSkipTime)&&(identical(other.autoPlayNextEpisode, autoPlayNextEpisode) || other.autoPlayNextEpisode == autoPlayNextEpisode)&&(identical(other.enableOpenSubtitlesIntegration, enableOpenSubtitlesIntegration) || other.enableOpenSubtitlesIntegration == enableOpenSubtitlesIntegration)&&(identical(other.enableNsfwContent, enableNsfwContent) || other.enableNsfwContent == enableNsfwContent));
return identical(this, other) || (other.runtimeType == runtimeType&&other is SettingsModel&&(identical(other.language, language) || other.language == language)&&(identical(other.service, service) || other.service == service)&&(identical(other.episodeService, episodeService) || other.episodeService == episodeService)&&const DeepCollectionEquality().equals(other.installedAnimeExtensions, installedAnimeExtensions)&&const DeepCollectionEquality().equals(other.installedMangaExtensions, installedMangaExtensions)&&(identical(other.aniyomiExtensionsRepositoryUrl, aniyomiExtensionsRepositoryUrl) || other.aniyomiExtensionsRepositoryUrl == aniyomiExtensionsRepositoryUrl)&&(identical(other.tachiyomiExtensionsRepositoryUrl, tachiyomiExtensionsRepositoryUrl) || other.tachiyomiExtensionsRepositoryUrl == tachiyomiExtensionsRepositoryUrl)&&const DeepCollectionEquality().equals(other.mediaExtensionConfigs, mediaExtensionConfigs)&&(identical(other.mediaTitleLanguage, mediaTitleLanguage) || other.mediaTitleLanguage == mediaTitleLanguage)&&(identical(other.episodeTitleLanguage, episodeTitleLanguage) || other.episodeTitleLanguage == episodeTitleLanguage)&&(identical(other.enableDiscordRichPresence, enableDiscordRichPresence) || other.enableDiscordRichPresence == enableDiscordRichPresence)&&(identical(other.automaticallySkipOpening, automaticallySkipOpening) || other.automaticallySkipOpening == automaticallySkipOpening)&&(identical(other.automaticallySkipEnding, automaticallySkipEnding) || other.automaticallySkipEnding == automaticallySkipEnding)&&(identical(other.manualSkipTime, manualSkipTime) || other.manualSkipTime == manualSkipTime)&&(identical(other.autoPlayNextEpisode, autoPlayNextEpisode) || other.autoPlayNextEpisode == autoPlayNextEpisode)&&(identical(other.enableOpenSubtitlesIntegration, enableOpenSubtitlesIntegration) || other.enableOpenSubtitlesIntegration == enableOpenSubtitlesIntegration)&&(identical(other.enableNsfwContent, enableNsfwContent) || other.enableNsfwContent == enableNsfwContent)&&(identical(other.themeColor, themeColor) || other.themeColor == themeColor)&&(identical(other.useWallpaperAsThemeColor, useWallpaperAsThemeColor) || other.useWallpaperAsThemeColor == useWallpaperAsThemeColor));
}
@JsonKey(includeFromJson: false, includeToJson: false)
@override
int get hashCode => Object.hash(runtimeType,language,service,episodeService,const DeepCollectionEquality().hash(installedAnimeExtensions),const DeepCollectionEquality().hash(installedMangaExtensions),aniyomiExtensionsRepositoryUrl,tachiyomiExtensionsRepositoryUrl,const DeepCollectionEquality().hash(mediaExtensionConfigs),mediaTitleLanguage,episodeTitleLanguage,enableDiscordRichPresence,automaticallySkipOpening,automaticallySkipEnding,manualSkipTime,autoPlayNextEpisode,enableOpenSubtitlesIntegration,enableNsfwContent);
int get hashCode => Object.hashAll([runtimeType,language,service,episodeService,const DeepCollectionEquality().hash(installedAnimeExtensions),const DeepCollectionEquality().hash(installedMangaExtensions),aniyomiExtensionsRepositoryUrl,tachiyomiExtensionsRepositoryUrl,const DeepCollectionEquality().hash(mediaExtensionConfigs),mediaTitleLanguage,episodeTitleLanguage,enableDiscordRichPresence,automaticallySkipOpening,automaticallySkipEnding,manualSkipTime,autoPlayNextEpisode,enableOpenSubtitlesIntegration,enableNsfwContent,themeColor,useWallpaperAsThemeColor]);
@override
String toString() {
return 'SettingsModel(language: $language, service: $service, episodeService: $episodeService, installedAnimeExtensions: $installedAnimeExtensions, installedMangaExtensions: $installedMangaExtensions, aniyomiExtensionsRepositoryUrl: $aniyomiExtensionsRepositoryUrl, tachiyomiExtensionsRepositoryUrl: $tachiyomiExtensionsRepositoryUrl, mediaExtensionConfigs: $mediaExtensionConfigs, mediaTitleLanguage: $mediaTitleLanguage, episodeTitleLanguage: $episodeTitleLanguage, enableDiscordRichPresence: $enableDiscordRichPresence, automaticallySkipOpening: $automaticallySkipOpening, automaticallySkipEnding: $automaticallySkipEnding, manualSkipTime: $manualSkipTime, autoPlayNextEpisode: $autoPlayNextEpisode, enableOpenSubtitlesIntegration: $enableOpenSubtitlesIntegration, enableNsfwContent: $enableNsfwContent)';
return 'SettingsModel(language: $language, service: $service, episodeService: $episodeService, installedAnimeExtensions: $installedAnimeExtensions, installedMangaExtensions: $installedMangaExtensions, aniyomiExtensionsRepositoryUrl: $aniyomiExtensionsRepositoryUrl, tachiyomiExtensionsRepositoryUrl: $tachiyomiExtensionsRepositoryUrl, mediaExtensionConfigs: $mediaExtensionConfigs, mediaTitleLanguage: $mediaTitleLanguage, episodeTitleLanguage: $episodeTitleLanguage, enableDiscordRichPresence: $enableDiscordRichPresence, automaticallySkipOpening: $automaticallySkipOpening, automaticallySkipEnding: $automaticallySkipEnding, manualSkipTime: $manualSkipTime, autoPlayNextEpisode: $autoPlayNextEpisode, enableOpenSubtitlesIntegration: $enableOpenSubtitlesIntegration, enableNsfwContent: $enableNsfwContent, themeColor: $themeColor, useWallpaperAsThemeColor: $useWallpaperAsThemeColor)';
}
@@ -48,7 +48,7 @@ abstract mixin class $SettingsModelCopyWith<$Res> {
factory $SettingsModelCopyWith(SettingsModel value, $Res Function(SettingsModel) _then) = _$SettingsModelCopyWithImpl;
@useResult
$Res call({
@HiveField(0) String language,@HiveField(1) Service service,@HiveField(2) EpisodeService episodeService,@HiveField(3)@ExtensionConverter() List<Extension> installedAnimeExtensions,@HiveField(4)@ExtensionConverter() List<Extension> installedMangaExtensions,@HiveField(5) String aniyomiExtensionsRepositoryUrl,@HiveField(6) String tachiyomiExtensionsRepositoryUrl,@HiveField(7)@ExtensionConverter() Map<String, Extension> mediaExtensionConfigs,@HiveField(8) String mediaTitleLanguage,@HiveField(9) String episodeTitleLanguage,@HiveField(10) bool enableDiscordRichPresence,@HiveField(11) bool automaticallySkipOpening,@HiveField(12) bool automaticallySkipEnding,@HiveField(13) int manualSkipTime,@HiveField(14) bool autoPlayNextEpisode,@HiveField(15) bool enableOpenSubtitlesIntegration,@HiveField(16) bool enableNsfwContent
@HiveField(0) String language,@HiveField(1) Service service,@HiveField(2) EpisodeService episodeService,@HiveField(3)@ExtensionConverter() List<Extension> installedAnimeExtensions,@HiveField(4)@ExtensionConverter() List<Extension> installedMangaExtensions,@HiveField(5) String aniyomiExtensionsRepositoryUrl,@HiveField(6) String tachiyomiExtensionsRepositoryUrl,@HiveField(7)@ExtensionConverter() Map<String, Extension> mediaExtensionConfigs,@HiveField(8) String mediaTitleLanguage,@HiveField(9) String episodeTitleLanguage,@HiveField(10) bool enableDiscordRichPresence,@HiveField(11) bool automaticallySkipOpening,@HiveField(12) bool automaticallySkipEnding,@HiveField(13) int manualSkipTime,@HiveField(14) bool autoPlayNextEpisode,@HiveField(15) bool enableOpenSubtitlesIntegration,@HiveField(16) bool enableNsfwContent,@HiveField(17)@ColorConverter() Color themeColor,@HiveField(18) bool useWallpaperAsThemeColor
});
@@ -65,7 +65,7 @@ class _$SettingsModelCopyWithImpl<$Res>
/// Create a copy of SettingsModel
/// with the given fields replaced by the non-null parameter values.
@pragma('vm:prefer-inline') @override $Res call({Object? language = null,Object? service = null,Object? episodeService = null,Object? installedAnimeExtensions = null,Object? installedMangaExtensions = null,Object? aniyomiExtensionsRepositoryUrl = null,Object? tachiyomiExtensionsRepositoryUrl = null,Object? mediaExtensionConfigs = null,Object? mediaTitleLanguage = null,Object? episodeTitleLanguage = null,Object? enableDiscordRichPresence = null,Object? automaticallySkipOpening = null,Object? automaticallySkipEnding = null,Object? manualSkipTime = null,Object? autoPlayNextEpisode = null,Object? enableOpenSubtitlesIntegration = null,Object? enableNsfwContent = null,}) {
@pragma('vm:prefer-inline') @override $Res call({Object? language = null,Object? service = null,Object? episodeService = null,Object? installedAnimeExtensions = null,Object? installedMangaExtensions = null,Object? aniyomiExtensionsRepositoryUrl = null,Object? tachiyomiExtensionsRepositoryUrl = null,Object? mediaExtensionConfigs = null,Object? mediaTitleLanguage = null,Object? episodeTitleLanguage = null,Object? enableDiscordRichPresence = null,Object? automaticallySkipOpening = null,Object? automaticallySkipEnding = null,Object? manualSkipTime = null,Object? autoPlayNextEpisode = null,Object? enableOpenSubtitlesIntegration = null,Object? enableNsfwContent = null,Object? themeColor = null,Object? useWallpaperAsThemeColor = null,}) {
return _then(_self.copyWith(
language: null == language ? _self.language : language // ignore: cast_nullable_to_non_nullable
as String,service: null == service ? _self.service : service // ignore: cast_nullable_to_non_nullable
@@ -84,6 +84,8 @@ as bool,manualSkipTime: null == manualSkipTime ? _self.manualSkipTime : manualSk
as int,autoPlayNextEpisode: null == autoPlayNextEpisode ? _self.autoPlayNextEpisode : autoPlayNextEpisode // ignore: cast_nullable_to_non_nullable
as bool,enableOpenSubtitlesIntegration: null == enableOpenSubtitlesIntegration ? _self.enableOpenSubtitlesIntegration : enableOpenSubtitlesIntegration // ignore: cast_nullable_to_non_nullable
as bool,enableNsfwContent: null == enableNsfwContent ? _self.enableNsfwContent : enableNsfwContent // ignore: cast_nullable_to_non_nullable
as bool,themeColor: null == themeColor ? _self.themeColor : themeColor // ignore: cast_nullable_to_non_nullable
as Color,useWallpaperAsThemeColor: null == useWallpaperAsThemeColor ? _self.useWallpaperAsThemeColor : useWallpaperAsThemeColor // ignore: cast_nullable_to_non_nullable
as bool,
));
}
@@ -169,10 +171,10 @@ return $default(_that);case _:
/// }
/// ```
@optionalTypeArgs TResult maybeWhen<TResult extends Object?>(TResult Function(@HiveField(0) String language, @HiveField(1) Service service, @HiveField(2) EpisodeService episodeService, @HiveField(3)@ExtensionConverter() List<Extension> installedAnimeExtensions, @HiveField(4)@ExtensionConverter() List<Extension> installedMangaExtensions, @HiveField(5) String aniyomiExtensionsRepositoryUrl, @HiveField(6) String tachiyomiExtensionsRepositoryUrl, @HiveField(7)@ExtensionConverter() Map<String, Extension> mediaExtensionConfigs, @HiveField(8) String mediaTitleLanguage, @HiveField(9) String episodeTitleLanguage, @HiveField(10) bool enableDiscordRichPresence, @HiveField(11) bool automaticallySkipOpening, @HiveField(12) bool automaticallySkipEnding, @HiveField(13) int manualSkipTime, @HiveField(14) bool autoPlayNextEpisode, @HiveField(15) bool enableOpenSubtitlesIntegration, @HiveField(16) bool enableNsfwContent)? $default,{required TResult orElse(),}) {final _that = this;
@optionalTypeArgs TResult maybeWhen<TResult extends Object?>(TResult Function(@HiveField(0) String language, @HiveField(1) Service service, @HiveField(2) EpisodeService episodeService, @HiveField(3)@ExtensionConverter() List<Extension> installedAnimeExtensions, @HiveField(4)@ExtensionConverter() List<Extension> installedMangaExtensions, @HiveField(5) String aniyomiExtensionsRepositoryUrl, @HiveField(6) String tachiyomiExtensionsRepositoryUrl, @HiveField(7)@ExtensionConverter() Map<String, Extension> mediaExtensionConfigs, @HiveField(8) String mediaTitleLanguage, @HiveField(9) String episodeTitleLanguage, @HiveField(10) bool enableDiscordRichPresence, @HiveField(11) bool automaticallySkipOpening, @HiveField(12) bool automaticallySkipEnding, @HiveField(13) int manualSkipTime, @HiveField(14) bool autoPlayNextEpisode, @HiveField(15) bool enableOpenSubtitlesIntegration, @HiveField(16) bool enableNsfwContent, @HiveField(17)@ColorConverter() Color themeColor, @HiveField(18) bool useWallpaperAsThemeColor)? $default,{required TResult orElse(),}) {final _that = this;
switch (_that) {
case _SettingsModel() when $default != null:
return $default(_that.language,_that.service,_that.episodeService,_that.installedAnimeExtensions,_that.installedMangaExtensions,_that.aniyomiExtensionsRepositoryUrl,_that.tachiyomiExtensionsRepositoryUrl,_that.mediaExtensionConfigs,_that.mediaTitleLanguage,_that.episodeTitleLanguage,_that.enableDiscordRichPresence,_that.automaticallySkipOpening,_that.automaticallySkipEnding,_that.manualSkipTime,_that.autoPlayNextEpisode,_that.enableOpenSubtitlesIntegration,_that.enableNsfwContent);case _:
return $default(_that.language,_that.service,_that.episodeService,_that.installedAnimeExtensions,_that.installedMangaExtensions,_that.aniyomiExtensionsRepositoryUrl,_that.tachiyomiExtensionsRepositoryUrl,_that.mediaExtensionConfigs,_that.mediaTitleLanguage,_that.episodeTitleLanguage,_that.enableDiscordRichPresence,_that.automaticallySkipOpening,_that.automaticallySkipEnding,_that.manualSkipTime,_that.autoPlayNextEpisode,_that.enableOpenSubtitlesIntegration,_that.enableNsfwContent,_that.themeColor,_that.useWallpaperAsThemeColor);case _:
return orElse();
}
@@ -190,10 +192,10 @@ return $default(_that.language,_that.service,_that.episodeService,_that.installe
/// }
/// ```
@optionalTypeArgs TResult when<TResult extends Object?>(TResult Function(@HiveField(0) String language, @HiveField(1) Service service, @HiveField(2) EpisodeService episodeService, @HiveField(3)@ExtensionConverter() List<Extension> installedAnimeExtensions, @HiveField(4)@ExtensionConverter() List<Extension> installedMangaExtensions, @HiveField(5) String aniyomiExtensionsRepositoryUrl, @HiveField(6) String tachiyomiExtensionsRepositoryUrl, @HiveField(7)@ExtensionConverter() Map<String, Extension> mediaExtensionConfigs, @HiveField(8) String mediaTitleLanguage, @HiveField(9) String episodeTitleLanguage, @HiveField(10) bool enableDiscordRichPresence, @HiveField(11) bool automaticallySkipOpening, @HiveField(12) bool automaticallySkipEnding, @HiveField(13) int manualSkipTime, @HiveField(14) bool autoPlayNextEpisode, @HiveField(15) bool enableOpenSubtitlesIntegration, @HiveField(16) bool enableNsfwContent) $default,) {final _that = this;
@optionalTypeArgs TResult when<TResult extends Object?>(TResult Function(@HiveField(0) String language, @HiveField(1) Service service, @HiveField(2) EpisodeService episodeService, @HiveField(3)@ExtensionConverter() List<Extension> installedAnimeExtensions, @HiveField(4)@ExtensionConverter() List<Extension> installedMangaExtensions, @HiveField(5) String aniyomiExtensionsRepositoryUrl, @HiveField(6) String tachiyomiExtensionsRepositoryUrl, @HiveField(7)@ExtensionConverter() Map<String, Extension> mediaExtensionConfigs, @HiveField(8) String mediaTitleLanguage, @HiveField(9) String episodeTitleLanguage, @HiveField(10) bool enableDiscordRichPresence, @HiveField(11) bool automaticallySkipOpening, @HiveField(12) bool automaticallySkipEnding, @HiveField(13) int manualSkipTime, @HiveField(14) bool autoPlayNextEpisode, @HiveField(15) bool enableOpenSubtitlesIntegration, @HiveField(16) bool enableNsfwContent, @HiveField(17)@ColorConverter() Color themeColor, @HiveField(18) bool useWallpaperAsThemeColor) $default,) {final _that = this;
switch (_that) {
case _SettingsModel():
return $default(_that.language,_that.service,_that.episodeService,_that.installedAnimeExtensions,_that.installedMangaExtensions,_that.aniyomiExtensionsRepositoryUrl,_that.tachiyomiExtensionsRepositoryUrl,_that.mediaExtensionConfigs,_that.mediaTitleLanguage,_that.episodeTitleLanguage,_that.enableDiscordRichPresence,_that.automaticallySkipOpening,_that.automaticallySkipEnding,_that.manualSkipTime,_that.autoPlayNextEpisode,_that.enableOpenSubtitlesIntegration,_that.enableNsfwContent);case _:
return $default(_that.language,_that.service,_that.episodeService,_that.installedAnimeExtensions,_that.installedMangaExtensions,_that.aniyomiExtensionsRepositoryUrl,_that.tachiyomiExtensionsRepositoryUrl,_that.mediaExtensionConfigs,_that.mediaTitleLanguage,_that.episodeTitleLanguage,_that.enableDiscordRichPresence,_that.automaticallySkipOpening,_that.automaticallySkipEnding,_that.manualSkipTime,_that.autoPlayNextEpisode,_that.enableOpenSubtitlesIntegration,_that.enableNsfwContent,_that.themeColor,_that.useWallpaperAsThemeColor);case _:
throw StateError('Unexpected subclass');
}
@@ -210,10 +212,10 @@ return $default(_that.language,_that.service,_that.episodeService,_that.installe
/// }
/// ```
@optionalTypeArgs TResult? whenOrNull<TResult extends Object?>(TResult? Function(@HiveField(0) String language, @HiveField(1) Service service, @HiveField(2) EpisodeService episodeService, @HiveField(3)@ExtensionConverter() List<Extension> installedAnimeExtensions, @HiveField(4)@ExtensionConverter() List<Extension> installedMangaExtensions, @HiveField(5) String aniyomiExtensionsRepositoryUrl, @HiveField(6) String tachiyomiExtensionsRepositoryUrl, @HiveField(7)@ExtensionConverter() Map<String, Extension> mediaExtensionConfigs, @HiveField(8) String mediaTitleLanguage, @HiveField(9) String episodeTitleLanguage, @HiveField(10) bool enableDiscordRichPresence, @HiveField(11) bool automaticallySkipOpening, @HiveField(12) bool automaticallySkipEnding, @HiveField(13) int manualSkipTime, @HiveField(14) bool autoPlayNextEpisode, @HiveField(15) bool enableOpenSubtitlesIntegration, @HiveField(16) bool enableNsfwContent)? $default,) {final _that = this;
@optionalTypeArgs TResult? whenOrNull<TResult extends Object?>(TResult? Function(@HiveField(0) String language, @HiveField(1) Service service, @HiveField(2) EpisodeService episodeService, @HiveField(3)@ExtensionConverter() List<Extension> installedAnimeExtensions, @HiveField(4)@ExtensionConverter() List<Extension> installedMangaExtensions, @HiveField(5) String aniyomiExtensionsRepositoryUrl, @HiveField(6) String tachiyomiExtensionsRepositoryUrl, @HiveField(7)@ExtensionConverter() Map<String, Extension> mediaExtensionConfigs, @HiveField(8) String mediaTitleLanguage, @HiveField(9) String episodeTitleLanguage, @HiveField(10) bool enableDiscordRichPresence, @HiveField(11) bool automaticallySkipOpening, @HiveField(12) bool automaticallySkipEnding, @HiveField(13) int manualSkipTime, @HiveField(14) bool autoPlayNextEpisode, @HiveField(15) bool enableOpenSubtitlesIntegration, @HiveField(16) bool enableNsfwContent, @HiveField(17)@ColorConverter() Color themeColor, @HiveField(18) bool useWallpaperAsThemeColor)? $default,) {final _that = this;
switch (_that) {
case _SettingsModel() when $default != null:
return $default(_that.language,_that.service,_that.episodeService,_that.installedAnimeExtensions,_that.installedMangaExtensions,_that.aniyomiExtensionsRepositoryUrl,_that.tachiyomiExtensionsRepositoryUrl,_that.mediaExtensionConfigs,_that.mediaTitleLanguage,_that.episodeTitleLanguage,_that.enableDiscordRichPresence,_that.automaticallySkipOpening,_that.automaticallySkipEnding,_that.manualSkipTime,_that.autoPlayNextEpisode,_that.enableOpenSubtitlesIntegration,_that.enableNsfwContent);case _:
return $default(_that.language,_that.service,_that.episodeService,_that.installedAnimeExtensions,_that.installedMangaExtensions,_that.aniyomiExtensionsRepositoryUrl,_that.tachiyomiExtensionsRepositoryUrl,_that.mediaExtensionConfigs,_that.mediaTitleLanguage,_that.episodeTitleLanguage,_that.enableDiscordRichPresence,_that.automaticallySkipOpening,_that.automaticallySkipEnding,_that.manualSkipTime,_that.autoPlayNextEpisode,_that.enableOpenSubtitlesIntegration,_that.enableNsfwContent,_that.themeColor,_that.useWallpaperAsThemeColor);case _:
return null;
}
@@ -225,7 +227,7 @@ return $default(_that.language,_that.service,_that.episodeService,_that.installe
@JsonSerializable()
class _SettingsModel implements SettingsModel {
const _SettingsModel({@HiveField(0) this.language = 'en', @HiveField(1) this.service = Service.anilist, @HiveField(2) this.episodeService = EpisodeService.anizip, @HiveField(3)@ExtensionConverter() final List<Extension> installedAnimeExtensions = const [], @HiveField(4)@ExtensionConverter() final List<Extension> installedMangaExtensions = const [], @HiveField(5) this.aniyomiExtensionsRepositoryUrl = config.aniyomiExtensionsRepositoryUrl, @HiveField(6) this.tachiyomiExtensionsRepositoryUrl = config.tachiyomiExtensionsRepositoryUrl, @HiveField(7)@ExtensionConverter() final Map<String, Extension> mediaExtensionConfigs = const {}, @HiveField(8) this.mediaTitleLanguage = 'userPreferred', @HiveField(9) this.episodeTitleLanguage = 'en', @HiveField(10) this.enableDiscordRichPresence = true, @HiveField(11) this.automaticallySkipOpening = false, @HiveField(12) this.automaticallySkipEnding = false, @HiveField(13) this.manualSkipTime = 85, @HiveField(14) this.autoPlayNextEpisode = false, @HiveField(15) this.enableOpenSubtitlesIntegration = false, @HiveField(16) this.enableNsfwContent = false}): _installedAnimeExtensions = installedAnimeExtensions,_installedMangaExtensions = installedMangaExtensions,_mediaExtensionConfigs = mediaExtensionConfigs;
const _SettingsModel({@HiveField(0) this.language = 'en', @HiveField(1) this.service = Service.anilist, @HiveField(2) this.episodeService = EpisodeService.anizip, @HiveField(3)@ExtensionConverter() final List<Extension> installedAnimeExtensions = const [], @HiveField(4)@ExtensionConverter() final List<Extension> installedMangaExtensions = const [], @HiveField(5) this.aniyomiExtensionsRepositoryUrl = config.aniyomiExtensionsRepositoryUrl, @HiveField(6) this.tachiyomiExtensionsRepositoryUrl = config.tachiyomiExtensionsRepositoryUrl, @HiveField(7)@ExtensionConverter() final Map<String, Extension> mediaExtensionConfigs = const {}, @HiveField(8) this.mediaTitleLanguage = 'userPreferred', @HiveField(9) this.episodeTitleLanguage = 'en', @HiveField(10) this.enableDiscordRichPresence = true, @HiveField(11) this.automaticallySkipOpening = false, @HiveField(12) this.automaticallySkipEnding = false, @HiveField(13) this.manualSkipTime = 85, @HiveField(14) this.autoPlayNextEpisode = false, @HiveField(15) this.enableOpenSubtitlesIntegration = false, @HiveField(16) this.enableNsfwContent = false, @HiveField(17)@ColorConverter() this.themeColor = const Color(0xFF2196F3), @HiveField(18) this.useWallpaperAsThemeColor = true}): _installedAnimeExtensions = installedAnimeExtensions,_installedMangaExtensions = installedMangaExtensions,_mediaExtensionConfigs = mediaExtensionConfigs;
factory _SettingsModel.fromJson(Map<String, dynamic> json) => _$SettingsModelFromJson(json);
@override@JsonKey()@HiveField(0) final String language;
@@ -263,6 +265,8 @@ class _SettingsModel implements SettingsModel {
@override@JsonKey()@HiveField(14) final bool autoPlayNextEpisode;
@override@JsonKey()@HiveField(15) final bool enableOpenSubtitlesIntegration;
@override@JsonKey()@HiveField(16) final bool enableNsfwContent;
@override@JsonKey()@HiveField(17)@ColorConverter() final Color themeColor;
@override@JsonKey()@HiveField(18) final bool useWallpaperAsThemeColor;
/// Create a copy of SettingsModel
/// with the given fields replaced by the non-null parameter values.
@@ -277,16 +281,16 @@ Map<String, dynamic> toJson() {
@override
bool operator ==(Object other) {
return identical(this, other) || (other.runtimeType == runtimeType&&other is _SettingsModel&&(identical(other.language, language) || other.language == language)&&(identical(other.service, service) || other.service == service)&&(identical(other.episodeService, episodeService) || other.episodeService == episodeService)&&const DeepCollectionEquality().equals(other._installedAnimeExtensions, _installedAnimeExtensions)&&const DeepCollectionEquality().equals(other._installedMangaExtensions, _installedMangaExtensions)&&(identical(other.aniyomiExtensionsRepositoryUrl, aniyomiExtensionsRepositoryUrl) || other.aniyomiExtensionsRepositoryUrl == aniyomiExtensionsRepositoryUrl)&&(identical(other.tachiyomiExtensionsRepositoryUrl, tachiyomiExtensionsRepositoryUrl) || other.tachiyomiExtensionsRepositoryUrl == tachiyomiExtensionsRepositoryUrl)&&const DeepCollectionEquality().equals(other._mediaExtensionConfigs, _mediaExtensionConfigs)&&(identical(other.mediaTitleLanguage, mediaTitleLanguage) || other.mediaTitleLanguage == mediaTitleLanguage)&&(identical(other.episodeTitleLanguage, episodeTitleLanguage) || other.episodeTitleLanguage == episodeTitleLanguage)&&(identical(other.enableDiscordRichPresence, enableDiscordRichPresence) || other.enableDiscordRichPresence == enableDiscordRichPresence)&&(identical(other.automaticallySkipOpening, automaticallySkipOpening) || other.automaticallySkipOpening == automaticallySkipOpening)&&(identical(other.automaticallySkipEnding, automaticallySkipEnding) || other.automaticallySkipEnding == automaticallySkipEnding)&&(identical(other.manualSkipTime, manualSkipTime) || other.manualSkipTime == manualSkipTime)&&(identical(other.autoPlayNextEpisode, autoPlayNextEpisode) || other.autoPlayNextEpisode == autoPlayNextEpisode)&&(identical(other.enableOpenSubtitlesIntegration, enableOpenSubtitlesIntegration) || other.enableOpenSubtitlesIntegration == enableOpenSubtitlesIntegration)&&(identical(other.enableNsfwContent, enableNsfwContent) || other.enableNsfwContent == enableNsfwContent));
return identical(this, other) || (other.runtimeType == runtimeType&&other is _SettingsModel&&(identical(other.language, language) || other.language == language)&&(identical(other.service, service) || other.service == service)&&(identical(other.episodeService, episodeService) || other.episodeService == episodeService)&&const DeepCollectionEquality().equals(other._installedAnimeExtensions, _installedAnimeExtensions)&&const DeepCollectionEquality().equals(other._installedMangaExtensions, _installedMangaExtensions)&&(identical(other.aniyomiExtensionsRepositoryUrl, aniyomiExtensionsRepositoryUrl) || other.aniyomiExtensionsRepositoryUrl == aniyomiExtensionsRepositoryUrl)&&(identical(other.tachiyomiExtensionsRepositoryUrl, tachiyomiExtensionsRepositoryUrl) || other.tachiyomiExtensionsRepositoryUrl == tachiyomiExtensionsRepositoryUrl)&&const DeepCollectionEquality().equals(other._mediaExtensionConfigs, _mediaExtensionConfigs)&&(identical(other.mediaTitleLanguage, mediaTitleLanguage) || other.mediaTitleLanguage == mediaTitleLanguage)&&(identical(other.episodeTitleLanguage, episodeTitleLanguage) || other.episodeTitleLanguage == episodeTitleLanguage)&&(identical(other.enableDiscordRichPresence, enableDiscordRichPresence) || other.enableDiscordRichPresence == enableDiscordRichPresence)&&(identical(other.automaticallySkipOpening, automaticallySkipOpening) || other.automaticallySkipOpening == automaticallySkipOpening)&&(identical(other.automaticallySkipEnding, automaticallySkipEnding) || other.automaticallySkipEnding == automaticallySkipEnding)&&(identical(other.manualSkipTime, manualSkipTime) || other.manualSkipTime == manualSkipTime)&&(identical(other.autoPlayNextEpisode, autoPlayNextEpisode) || other.autoPlayNextEpisode == autoPlayNextEpisode)&&(identical(other.enableOpenSubtitlesIntegration, enableOpenSubtitlesIntegration) || other.enableOpenSubtitlesIntegration == enableOpenSubtitlesIntegration)&&(identical(other.enableNsfwContent, enableNsfwContent) || other.enableNsfwContent == enableNsfwContent)&&(identical(other.themeColor, themeColor) || other.themeColor == themeColor)&&(identical(other.useWallpaperAsThemeColor, useWallpaperAsThemeColor) || other.useWallpaperAsThemeColor == useWallpaperAsThemeColor));
}
@JsonKey(includeFromJson: false, includeToJson: false)
@override
int get hashCode => Object.hash(runtimeType,language,service,episodeService,const DeepCollectionEquality().hash(_installedAnimeExtensions),const DeepCollectionEquality().hash(_installedMangaExtensions),aniyomiExtensionsRepositoryUrl,tachiyomiExtensionsRepositoryUrl,const DeepCollectionEquality().hash(_mediaExtensionConfigs),mediaTitleLanguage,episodeTitleLanguage,enableDiscordRichPresence,automaticallySkipOpening,automaticallySkipEnding,manualSkipTime,autoPlayNextEpisode,enableOpenSubtitlesIntegration,enableNsfwContent);
int get hashCode => Object.hashAll([runtimeType,language,service,episodeService,const DeepCollectionEquality().hash(_installedAnimeExtensions),const DeepCollectionEquality().hash(_installedMangaExtensions),aniyomiExtensionsRepositoryUrl,tachiyomiExtensionsRepositoryUrl,const DeepCollectionEquality().hash(_mediaExtensionConfigs),mediaTitleLanguage,episodeTitleLanguage,enableDiscordRichPresence,automaticallySkipOpening,automaticallySkipEnding,manualSkipTime,autoPlayNextEpisode,enableOpenSubtitlesIntegration,enableNsfwContent,themeColor,useWallpaperAsThemeColor]);
@override
String toString() {
return 'SettingsModel(language: $language, service: $service, episodeService: $episodeService, installedAnimeExtensions: $installedAnimeExtensions, installedMangaExtensions: $installedMangaExtensions, aniyomiExtensionsRepositoryUrl: $aniyomiExtensionsRepositoryUrl, tachiyomiExtensionsRepositoryUrl: $tachiyomiExtensionsRepositoryUrl, mediaExtensionConfigs: $mediaExtensionConfigs, mediaTitleLanguage: $mediaTitleLanguage, episodeTitleLanguage: $episodeTitleLanguage, enableDiscordRichPresence: $enableDiscordRichPresence, automaticallySkipOpening: $automaticallySkipOpening, automaticallySkipEnding: $automaticallySkipEnding, manualSkipTime: $manualSkipTime, autoPlayNextEpisode: $autoPlayNextEpisode, enableOpenSubtitlesIntegration: $enableOpenSubtitlesIntegration, enableNsfwContent: $enableNsfwContent)';
return 'SettingsModel(language: $language, service: $service, episodeService: $episodeService, installedAnimeExtensions: $installedAnimeExtensions, installedMangaExtensions: $installedMangaExtensions, aniyomiExtensionsRepositoryUrl: $aniyomiExtensionsRepositoryUrl, tachiyomiExtensionsRepositoryUrl: $tachiyomiExtensionsRepositoryUrl, mediaExtensionConfigs: $mediaExtensionConfigs, mediaTitleLanguage: $mediaTitleLanguage, episodeTitleLanguage: $episodeTitleLanguage, enableDiscordRichPresence: $enableDiscordRichPresence, automaticallySkipOpening: $automaticallySkipOpening, automaticallySkipEnding: $automaticallySkipEnding, manualSkipTime: $manualSkipTime, autoPlayNextEpisode: $autoPlayNextEpisode, enableOpenSubtitlesIntegration: $enableOpenSubtitlesIntegration, enableNsfwContent: $enableNsfwContent, themeColor: $themeColor, useWallpaperAsThemeColor: $useWallpaperAsThemeColor)';
}
@@ -297,7 +301,7 @@ abstract mixin class _$SettingsModelCopyWith<$Res> implements $SettingsModelCopy
factory _$SettingsModelCopyWith(_SettingsModel value, $Res Function(_SettingsModel) _then) = __$SettingsModelCopyWithImpl;
@override @useResult
$Res call({
@HiveField(0) String language,@HiveField(1) Service service,@HiveField(2) EpisodeService episodeService,@HiveField(3)@ExtensionConverter() List<Extension> installedAnimeExtensions,@HiveField(4)@ExtensionConverter() List<Extension> installedMangaExtensions,@HiveField(5) String aniyomiExtensionsRepositoryUrl,@HiveField(6) String tachiyomiExtensionsRepositoryUrl,@HiveField(7)@ExtensionConverter() Map<String, Extension> mediaExtensionConfigs,@HiveField(8) String mediaTitleLanguage,@HiveField(9) String episodeTitleLanguage,@HiveField(10) bool enableDiscordRichPresence,@HiveField(11) bool automaticallySkipOpening,@HiveField(12) bool automaticallySkipEnding,@HiveField(13) int manualSkipTime,@HiveField(14) bool autoPlayNextEpisode,@HiveField(15) bool enableOpenSubtitlesIntegration,@HiveField(16) bool enableNsfwContent
@HiveField(0) String language,@HiveField(1) Service service,@HiveField(2) EpisodeService episodeService,@HiveField(3)@ExtensionConverter() List<Extension> installedAnimeExtensions,@HiveField(4)@ExtensionConverter() List<Extension> installedMangaExtensions,@HiveField(5) String aniyomiExtensionsRepositoryUrl,@HiveField(6) String tachiyomiExtensionsRepositoryUrl,@HiveField(7)@ExtensionConverter() Map<String, Extension> mediaExtensionConfigs,@HiveField(8) String mediaTitleLanguage,@HiveField(9) String episodeTitleLanguage,@HiveField(10) bool enableDiscordRichPresence,@HiveField(11) bool automaticallySkipOpening,@HiveField(12) bool automaticallySkipEnding,@HiveField(13) int manualSkipTime,@HiveField(14) bool autoPlayNextEpisode,@HiveField(15) bool enableOpenSubtitlesIntegration,@HiveField(16) bool enableNsfwContent,@HiveField(17)@ColorConverter() Color themeColor,@HiveField(18) bool useWallpaperAsThemeColor
});
@@ -314,7 +318,7 @@ class __$SettingsModelCopyWithImpl<$Res>
/// Create a copy of SettingsModel
/// with the given fields replaced by the non-null parameter values.
@override @pragma('vm:prefer-inline') $Res call({Object? language = null,Object? service = null,Object? episodeService = null,Object? installedAnimeExtensions = null,Object? installedMangaExtensions = null,Object? aniyomiExtensionsRepositoryUrl = null,Object? tachiyomiExtensionsRepositoryUrl = null,Object? mediaExtensionConfigs = null,Object? mediaTitleLanguage = null,Object? episodeTitleLanguage = null,Object? enableDiscordRichPresence = null,Object? automaticallySkipOpening = null,Object? automaticallySkipEnding = null,Object? manualSkipTime = null,Object? autoPlayNextEpisode = null,Object? enableOpenSubtitlesIntegration = null,Object? enableNsfwContent = null,}) {
@override @pragma('vm:prefer-inline') $Res call({Object? language = null,Object? service = null,Object? episodeService = null,Object? installedAnimeExtensions = null,Object? installedMangaExtensions = null,Object? aniyomiExtensionsRepositoryUrl = null,Object? tachiyomiExtensionsRepositoryUrl = null,Object? mediaExtensionConfigs = null,Object? mediaTitleLanguage = null,Object? episodeTitleLanguage = null,Object? enableDiscordRichPresence = null,Object? automaticallySkipOpening = null,Object? automaticallySkipEnding = null,Object? manualSkipTime = null,Object? autoPlayNextEpisode = null,Object? enableOpenSubtitlesIntegration = null,Object? enableNsfwContent = null,Object? themeColor = null,Object? useWallpaperAsThemeColor = null,}) {
return _then(_SettingsModel(
language: null == language ? _self.language : language // ignore: cast_nullable_to_non_nullable
as String,service: null == service ? _self.service : service // ignore: cast_nullable_to_non_nullable
@@ -333,6 +337,8 @@ as bool,manualSkipTime: null == manualSkipTime ? _self.manualSkipTime : manualSk
as int,autoPlayNextEpisode: null == autoPlayNextEpisode ? _self.autoPlayNextEpisode : autoPlayNextEpisode // ignore: cast_nullable_to_non_nullable
as bool,enableOpenSubtitlesIntegration: null == enableOpenSubtitlesIntegration ? _self.enableOpenSubtitlesIntegration : enableOpenSubtitlesIntegration // ignore: cast_nullable_to_non_nullable
as bool,enableNsfwContent: null == enableNsfwContent ? _self.enableNsfwContent : enableNsfwContent // ignore: cast_nullable_to_non_nullable
as bool,themeColor: null == themeColor ? _self.themeColor : themeColor // ignore: cast_nullable_to_non_nullable
as Color,useWallpaperAsThemeColor: null == useWallpaperAsThemeColor ? _self.useWallpaperAsThemeColor : useWallpaperAsThemeColor // ignore: cast_nullable_to_non_nullable
as bool,
));
}

View File

@@ -50,13 +50,17 @@ class SettingsModelAdapter extends TypeAdapter<SettingsModel> {
? false
: fields[15] as bool,
enableNsfwContent: fields[16] == null ? false : fields[16] as bool,
themeColor: fields[17] == null
? const Color(4280391411)
: fields[17] as Color,
useWallpaperAsThemeColor: fields[18] == null ? true : fields[18] as bool,
);
}
@override
void write(BinaryWriter writer, SettingsModel obj) {
writer
..writeByte(17)
..writeByte(19)
..writeByte(0)
..write(obj.language)
..writeByte(1)
@@ -90,7 +94,11 @@ class SettingsModelAdapter extends TypeAdapter<SettingsModel> {
..writeByte(15)
..write(obj.enableOpenSubtitlesIntegration)
..writeByte(16)
..write(obj.enableNsfwContent);
..write(obj.enableNsfwContent)
..writeByte(17)
..write(obj.themeColor)
..writeByte(18)
..write(obj.useWallpaperAsThemeColor);
}
@override
@@ -157,6 +165,10 @@ _SettingsModel _$SettingsModelFromJson(
enableOpenSubtitlesIntegration:
json['enableOpenSubtitlesIntegration'] as bool? ?? false,
enableNsfwContent: json['enableNsfwContent'] as bool? ?? false,
themeColor: json['themeColor'] == null
? const Color(0xFF2196F3)
: const ColorConverter().fromJson((json['themeColor'] as num).toInt()),
useWallpaperAsThemeColor: json['useWallpaperAsThemeColor'] as bool? ?? true,
);
Map<String, dynamic> _$SettingsModelToJson(
@@ -185,6 +197,8 @@ Map<String, dynamic> _$SettingsModelToJson(
'autoPlayNextEpisode': instance.autoPlayNextEpisode,
'enableOpenSubtitlesIntegration': instance.enableOpenSubtitlesIntegration,
'enableNsfwContent': instance.enableNsfwContent,
'themeColor': const ColorConverter().toJson(instance.themeColor),
'useWallpaperAsThemeColor': instance.useWallpaperAsThemeColor,
};
const _$ServiceEnumMap = {

View File

@@ -2,6 +2,7 @@ import 'dart:io';
import 'package:flutter/material.dart';
import 'package:easy_localization/easy_localization.dart';
import 'package:flutter_screenutil/flutter_screenutil.dart';
import 'package:unyo/data/adapters/type_adapters/color_adapter.dart';
import 'package:window_manager/window_manager.dart';
import 'package:hive_ce/hive.dart';
import 'package:logger/logger.dart';
@@ -26,6 +27,7 @@ void main() async {
await sl.isReady<Directory>(instanceName: config.applicationSupportDirectory);
Hive
..init(sl<Directory>(instanceName: config.applicationSupportDirectory).path)
..registerAdapter(ColorAdapter())
..registerAdapters();
// Inject the remaining dependencies that rely on Hive and are not Lazy
setupLocatorAfterHiveInit();

View File

@@ -29,6 +29,7 @@ class _TextFieldDialogState extends State<TextFieldDialog> {
@override
Widget build(BuildContext context) {
return Dialog(
backgroundColor: const Color.fromARGB(255, 30, 30, 30),
child: Padding(
padding: EdgeInsets.symmetric(horizontal: 8.0.w, vertical: 8.0.h),
child: SizedBox(

View File

@@ -12,6 +12,7 @@ class WarningDialog extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Dialog(
backgroundColor: const Color.fromARGB(255, 30, 30, 30),
child: Padding(
padding: EdgeInsets.symmetric(horizontal: 8.0.w, vertical: 24.0.h),
child: SizedBox(

View File

@@ -248,13 +248,27 @@ class _SettingsViewState extends State<_SettingsView> with TickerProviderStateMi
),
],
),
const UnyoSettingsCategory(
UnyoSettingsCategory(
title: "Theme",
description: "Appearance settings",
icon: Icons.edit_rounded,
alignment: "",
childAlignment: "",
settingsOptions: [],
settingsOptions: [
UnyoSettingsSelectionDialog(
title: "Choose Color",
description: "Choose Theme based on a color",
icon: Icons.color_lens_rounded,
openDialog: () => context.read<SettingsCubit>().openColorPickerDialog(context)
),
UnyoSettingsSelectionToggle(
title: "Use wallpaper as theme color",
description: "Automatically set the theme color based on your wallpaper colors",
icon: Icons.wallpaper_rounded,
initiallySelected: state.loggedUser.settings.useWallpaperAsThemeColor,
onPressed: context.read<SettingsCubit>().enableUseWallpaperAsThemeColor,
),
],
),
UnyoSettingsCategory(
title: "Player",

View File

@@ -39,12 +39,12 @@ class LightUnyoButton extends StatelessWidget {
color: Colors.transparent,
child: InkWell(
onTap: isEnabled ? onPressed : null,
highlightColor: Color.lerp(Colors.white, color, 1.0),
highlightColor: Color.lerp(Colors.white, color, 0.5),
borderRadius: BorderRadius.circular(20.0),
child: Container(
width: width ?? 80.w.clamp(minWidth ?? 0, maxWidth ?? math.max(minWidth ?? 0, 80.w)),
height: height ?? 45.h.clamp(minHeight ?? 0, maxHeight ?? math.max(minHeight ?? 0, 45.h)),
decoration: BoxDecoration(borderRadius: BorderRadius.circular(20.0), color: color.withValues(alpha: 0.9)),
decoration: BoxDecoration(borderRadius: BorderRadius.circular(20.0), color: (Color.lerp(Colors.white, color, 0.65) ?? color).withValues(alpha: 0.9)),
child: Center(
child: Text(text ?? "", style: TextStyle(color: textColor, fontWeight: FontWeight.w700)),
),

View File

@@ -91,10 +91,12 @@ class MediaCard extends StatelessWidget {
ColorScheme.of(context).primary
.computeLuminance() >
0.2
? Colors.black
: Colors.white.withValues(alpha:
0.8,
),
? Colors.black.withValues(alpha:
0.8,
)
: Colors.white.withValues(alpha:
0.8,
),
fontWeight: FontWeight.bold,
),
),
@@ -104,10 +106,12 @@ class MediaCard extends StatelessWidget {
ColorScheme.of(context).primary
.computeLuminance() >
0.2
? Colors.black
: Colors.white.withValues(alpha:
? Colors.black.withValues(alpha:
0.8,
),
)
: Colors.white.withValues(alpha:
0.8,
),
size: 15,
),
],

View File

@@ -41,6 +41,7 @@ dependencies:
dynamic_color: ^1.8.1
material_color_utilities: ^0.11.1
palette_generator: ^0.3.3+7
flutter_colorpicker: ^1.1.0
# Platform Integration
window_manager: ^0.5.1
url_launcher: ^6.3.2