refactor: use json serializer for preferences

This commit is contained in:
Kingkor Roy Tirtho 2023-11-14 22:48:02 +06:00
parent dc980b024e
commit 57c03ad045
35 changed files with 861 additions and 423 deletions

View File

@ -22,7 +22,7 @@ import 'package:spotube/components/shared/track_table/track_tile.dart';
import 'package:spotube/extensions/context.dart';
import 'package:spotube/models/local_track.dart';
import 'package:spotube/provider/proxy_playlist/proxy_playlist_provider.dart';
import 'package:spotube/provider/user_preferences_provider.dart';
import 'package:spotube/provider/user_preferences/user_preferences_provider.dart';
import 'package:spotube/utils/service_utils.dart';
import 'package:spotube/utils/type_conversion_utils.dart';
import 'package:flutter_rust_bridge/flutter_rust_bridge.dart' show FfiException;

View File

@ -15,7 +15,8 @@ import 'package:spotube/hooks/utils/use_debounce.dart';
import 'package:spotube/models/matched_track.dart';
import 'package:spotube/models/spotube_track.dart';
import 'package:spotube/provider/proxy_playlist/proxy_playlist_provider.dart';
import 'package:spotube/provider/user_preferences_provider.dart';
import 'package:spotube/provider/user_preferences/user_preferences_provider.dart';
import 'package:spotube/provider/user_preferences/user_preferences_state.dart';
import 'package:spotube/provider/youtube_provider.dart';
import 'package:spotube/services/youtube/youtube.dart';
import 'package:spotube/utils/service_utils.dart';

View File

@ -19,7 +19,8 @@ import 'package:spotube/models/logger.dart';
import 'package:flutter/material.dart';
import 'package:spotube/provider/authentication_provider.dart';
import 'package:spotube/provider/proxy_playlist/proxy_playlist_provider.dart';
import 'package:spotube/provider/user_preferences_provider.dart';
import 'package:spotube/provider/user_preferences/user_preferences_provider.dart';
import 'package:spotube/provider/user_preferences/user_preferences_state.dart';
import 'package:spotube/utils/platform.dart';
import 'package:spotube/utils/type_conversion_utils.dart';

View File

@ -16,7 +16,8 @@ import 'package:spotube/hooks/controllers/use_sidebarx_controller.dart';
import 'package:spotube/provider/download_manager_provider.dart';
import 'package:spotube/provider/authentication_provider.dart';
import 'package:spotube/provider/user_preferences_provider.dart';
import 'package:spotube/provider/user_preferences/user_preferences_provider.dart';
import 'package:spotube/provider/user_preferences/user_preferences_state.dart';
import 'package:spotube/services/queries/queries.dart';
import 'package:spotube/utils/platform.dart';
import 'package:spotube/utils/type_conversion_utils.dart';

View File

@ -11,7 +11,8 @@ import 'package:spotube/extensions/constrains.dart';
import 'package:spotube/extensions/context.dart';
import 'package:spotube/hooks/utils/use_brightness_value.dart';
import 'package:spotube/provider/download_manager_provider.dart';
import 'package:spotube/provider/user_preferences_provider.dart';
import 'package:spotube/provider/user_preferences/user_preferences_provider.dart';
import 'package:spotube/provider/user_preferences/user_preferences_state.dart';
final navigationPanelHeight = StateProvider<double>((ref) => 50);

View File

@ -2,7 +2,7 @@ import 'package:flutter/material.dart';
import 'package:flutter_hooks/flutter_hooks.dart';
import 'package:hooks_riverpod/hooks_riverpod.dart';
import 'package:spotube/provider/user_preferences_provider.dart';
import 'package:spotube/provider/user_preferences/user_preferences_provider.dart';
import 'package:system_theme/system_theme.dart';
class SpotubeColor extends Color {

View File

@ -2,7 +2,7 @@ import 'package:flutter/material.dart';
import 'package:hooks_riverpod/hooks_riverpod.dart';
import 'package:spotube/collections/spotube_icons.dart';
import 'package:spotube/extensions/context.dart';
import 'package:spotube/provider/user_preferences_provider.dart';
import 'package:spotube/provider/user_preferences/user_preferences_provider.dart';
class PipedDownDialog extends HookConsumerWidget {
const PipedDownDialog({Key? key}) : super(key: key);

View File

@ -1,7 +1,8 @@
import 'package:flutter/material.dart';
import 'package:flutter_hooks/flutter_hooks.dart';
import 'package:hooks_riverpod/hooks_riverpod.dart';
import 'package:spotube/provider/user_preferences_provider.dart';
import 'package:spotube/provider/user_preferences/user_preferences_provider.dart';
import 'package:spotube/provider/user_preferences/user_preferences_state.dart';
import 'package:spotube/utils/platform.dart';
import 'package:titlebar_buttons/titlebar_buttons.dart';
import 'dart:math';

View File

@ -22,7 +22,8 @@ import 'package:spotube/extensions/context.dart';
import 'package:spotube/provider/download_manager_provider.dart';
import 'package:spotube/provider/blacklist_provider.dart';
import 'package:spotube/provider/proxy_playlist/proxy_playlist_provider.dart';
import 'package:spotube/provider/user_preferences_provider.dart';
import 'package:spotube/provider/user_preferences/user_preferences_provider.dart';
import 'package:spotube/provider/user_preferences/user_preferences_state.dart';
import 'package:spotube/utils/service_utils.dart';
final trackCollectionSortState =

View File

@ -7,7 +7,7 @@ import 'package:hooks_riverpod/hooks_riverpod.dart';
import 'package:spotube/collections/intents.dart';
import 'package:spotube/provider/proxy_playlist/proxy_playlist.dart';
import 'package:spotube/provider/proxy_playlist/proxy_playlist_provider.dart';
import 'package:spotube/provider/user_preferences_provider.dart';
import 'package:spotube/provider/user_preferences/user_preferences_provider.dart';
void useInitSysTray(WidgetRef ref) {
final context = useContext();

View File

@ -9,7 +9,7 @@ import 'package:spotube/collections/env.dart';
import 'package:spotube/components/shared/links/anchor_button.dart';
import 'package:spotube/hooks/controllers/use_package_info.dart';
import 'package:spotube/provider/user_preferences_provider.dart';
import 'package:spotube/provider/user_preferences/user_preferences_provider.dart';
import 'package:url_launcher/url_launcher_string.dart';
import 'package:version/version.dart';

View File

@ -21,7 +21,7 @@ import 'package:spotube/models/logger.dart';
import 'package:spotube/models/matched_track.dart';
import 'package:spotube/models/skip_segment.dart';
import 'package:spotube/provider/palette_provider.dart';
import 'package:spotube/provider/user_preferences_provider.dart';
import 'package:spotube/provider/user_preferences/user_preferences_provider.dart';
import 'package:spotube/services/audio_player/audio_player.dart';
import 'package:spotube/services/cli/cli.dart';
import 'package:spotube/services/connectivity_adapter.dart';

View File

@ -3,7 +3,7 @@ import 'dart:async';
import 'package:spotify/spotify.dart';
import 'package:spotube/extensions/track.dart';
import 'package:spotube/models/matched_track.dart';
import 'package:spotube/provider/user_preferences_provider.dart';
import 'package:spotube/provider/user_preferences/user_preferences_state.dart';
import 'package:spotube/services/youtube/youtube.dart';
import 'package:spotube/utils/service_utils.dart';
import 'package:collection/collection.dart';

View File

@ -10,7 +10,7 @@ import 'package:spotube/components/shared/expandable_search/expandable_search.da
import 'package:spotube/components/shared/shimmers/shimmer_categories.dart';
import 'package:spotube/components/shared/waypoint.dart';
import 'package:spotube/provider/user_preferences_provider.dart';
import 'package:spotube/provider/user_preferences/user_preferences_provider.dart';
import 'package:spotube/services/queries/queries.dart';
import 'package:very_good_infinite_list/very_good_infinite_list.dart';

View File

@ -17,7 +17,7 @@ import 'package:spotube/extensions/constrains.dart';
import 'package:spotube/extensions/context.dart';
import 'package:spotube/pages/library/playlist_generate/playlist_generate_result.dart';
import 'package:spotube/provider/spotify_provider.dart';
import 'package:spotube/provider/user_preferences_provider.dart';
import 'package:spotube/provider/user_preferences/user_preferences_provider.dart';
import 'package:spotube/services/queries/queries.dart';
import 'package:spotube/utils/type_conversion_utils.dart';

View File

@ -7,7 +7,7 @@ import 'package:spotube/collections/spotube_icons.dart';
import 'package:spotube/components/settings/section_card_with_heading.dart';
import 'package:spotube/components/shared/adaptive/adaptive_list_tile.dart';
import 'package:spotube/extensions/context.dart';
import 'package:spotube/provider/user_preferences_provider.dart';
import 'package:spotube/provider/user_preferences/user_preferences_provider.dart';
import 'package:url_launcher/url_launcher_string.dart';
class SettingsAboutSection extends HookConsumerWidget {

View File

@ -1,4 +1,3 @@
import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart';
import 'package:flutter_hooks/flutter_hooks.dart';
import 'package:hooks_riverpod/hooks_riverpod.dart';
@ -7,7 +6,8 @@ import 'package:spotube/components/settings/color_scheme_picker_dialog.dart';
import 'package:spotube/components/settings/section_card_with_heading.dart';
import 'package:spotube/components/shared/adaptive/adaptive_select_tile.dart';
import 'package:spotube/extensions/context.dart';
import 'package:spotube/provider/user_preferences_provider.dart';
import 'package:spotube/provider/user_preferences/user_preferences_provider.dart';
import 'package:spotube/provider/user_preferences/user_preferences_state.dart';
class SettingsAppearanceSection extends HookConsumerWidget {
const SettingsAppearanceSection({Key? key}) : super(key: key);

View File

@ -4,7 +4,8 @@ import 'package:spotube/collections/spotube_icons.dart';
import 'package:spotube/components/settings/section_card_with_heading.dart';
import 'package:spotube/components/shared/adaptive/adaptive_select_tile.dart';
import 'package:spotube/extensions/context.dart';
import 'package:spotube/provider/user_preferences_provider.dart';
import 'package:spotube/provider/user_preferences/user_preferences_provider.dart';
import 'package:spotube/provider/user_preferences/user_preferences_state.dart';
class SettingsDesktopSection extends HookConsumerWidget {
const SettingsDesktopSection({Key? key}) : super(key: key);

View File

@ -7,7 +7,7 @@ import 'package:hooks_riverpod/hooks_riverpod.dart';
import 'package:spotube/collections/spotube_icons.dart';
import 'package:spotube/components/settings/section_card_with_heading.dart';
import 'package:spotube/extensions/context.dart';
import 'package:spotube/provider/user_preferences_provider.dart';
import 'package:spotube/provider/user_preferences/user_preferences_provider.dart';
class SettingsDownloadsSection extends HookConsumerWidget {
const SettingsDownloadsSection({Key? key}) : super(key: key);

View File

@ -9,7 +9,7 @@ import 'package:spotube/components/shared/adaptive/adaptive_select_tile.dart';
import 'package:spotube/extensions/constrains.dart';
import 'package:spotube/extensions/context.dart';
import 'package:spotube/l10n/l10n.dart';
import 'package:spotube/provider/user_preferences_provider.dart';
import 'package:spotube/provider/user_preferences/user_preferences_provider.dart';
class SettingsLanguageRegionSection extends HookConsumerWidget {
const SettingsLanguageRegionSection({Key? key}) : super(key: key);

View File

@ -10,7 +10,8 @@ import 'package:spotube/components/shared/adaptive/adaptive_select_tile.dart';
import 'package:spotube/extensions/context.dart';
import 'package:spotube/models/matched_track.dart';
import 'package:spotube/provider/piped_instances_provider.dart';
import 'package:spotube/provider/user_preferences_provider.dart';
import 'package:spotube/provider/user_preferences/user_preferences_provider.dart';
import 'package:spotube/provider/user_preferences/user_preferences_state.dart';
class SettingsPlaybackSection extends HookConsumerWidget {
const SettingsPlaybackSection({Key? key}) : super(key: key);

View File

@ -13,7 +13,7 @@ import 'package:spotube/pages/settings/sections/developers.dart';
import 'package:spotube/pages/settings/sections/downloads.dart';
import 'package:spotube/pages/settings/sections/language_region.dart';
import 'package:spotube/pages/settings/sections/playback.dart';
import 'package:spotube/provider/user_preferences_provider.dart';
import 'package:spotube/provider/user_preferences/user_preferences_provider.dart';
class SettingsPage extends HookConsumerWidget {
const SettingsPage({Key? key}) : super(key: key);

View File

@ -10,7 +10,8 @@ import 'package:metadata_god/metadata_god.dart';
import 'package:path/path.dart';
import 'package:spotify/spotify.dart';
import 'package:spotube/models/spotube_track.dart';
import 'package:spotube/provider/user_preferences_provider.dart';
import 'package:spotube/provider/user_preferences/user_preferences_provider.dart';
import 'package:spotube/provider/user_preferences/user_preferences_state.dart';
import 'package:spotube/provider/youtube_provider.dart';
import 'package:spotube/services/download_manager/download_manager.dart';
import 'package:spotube/services/youtube/youtube.dart';

View File

@ -6,7 +6,7 @@ import 'package:spotube/models/logger.dart';
import 'package:spotube/models/matched_track.dart';
import 'package:spotube/models/spotube_track.dart';
import 'package:spotube/provider/proxy_playlist/proxy_playlist.dart';
import 'package:spotube/provider/user_preferences_provider.dart';
import 'package:spotube/provider/user_preferences/user_preferences_state.dart';
import 'package:spotube/services/supabase.dart';
import 'package:spotube/services/youtube/youtube.dart';

View File

@ -20,7 +20,8 @@ import 'package:spotube/provider/palette_provider.dart';
import 'package:spotube/provider/proxy_playlist/next_fetcher_mixin.dart';
import 'package:spotube/provider/proxy_playlist/proxy_playlist.dart';
import 'package:spotube/provider/scrobbler_provider.dart';
import 'package:spotube/provider/user_preferences_provider.dart';
import 'package:spotube/provider/user_preferences/user_preferences_provider.dart';
import 'package:spotube/provider/user_preferences/user_preferences_state.dart';
import 'package:spotube/provider/youtube_provider.dart';
import 'package:spotube/services/audio_player/audio_player.dart';
import 'package:spotube/services/audio_services/audio_services.dart';

View File

@ -0,0 +1,165 @@
import 'dart:async';
import 'package:flutter/material.dart';
import 'package:flutter_desktop_tools/flutter_desktop_tools.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:path_provider/path_provider.dart';
import 'package:spotify/spotify.dart';
import 'package:spotube/components/settings/color_scheme_picker_dialog.dart';
import 'package:spotube/models/matched_track.dart';
import 'package:spotube/provider/palette_provider.dart';
import 'package:spotube/provider/proxy_playlist/proxy_playlist_provider.dart';
import 'package:spotube/provider/user_preferences/user_preferences_state.dart';
import 'package:spotube/services/audio_player/audio_player.dart';
import 'package:spotube/utils/persisted_state_notifier.dart';
import 'package:spotube/utils/platform.dart';
import 'package:path/path.dart' as path;
class UserPreferencesNotifier extends PersistedStateNotifier<UserPreferences> {
final Ref ref;
UserPreferencesNotifier(this.ref)
: super(UserPreferences.withDefaults(), "preferences");
void reset() {
state = UserPreferences.withDefaults();
}
void setStreamMusicCodec(MusicCodec codec) {
state = state.copyWith(streamMusicCodec: codec);
}
void setDownloadMusicCodec(MusicCodec codec) {
state = state.copyWith(downloadMusicCodec: codec);
}
void setThemeMode(ThemeMode mode) {
state = state.copyWith(themeMode: mode);
}
void setRecommendationMarket(Market country) {
state = state.copyWith(recommendationMarket: country);
}
void setAccentColorScheme(SpotubeColor color) {
state = state.copyWith(accentColorScheme: color);
}
void setAlbumColorSync(bool sync) {
state = state.copyWith(albumColorSync: sync);
if (!sync) {
ref.read(paletteProvider.notifier).state = null;
} else {
ref.read(ProxyPlaylistNotifier.notifier).updatePalette();
}
}
void setCheckUpdate(bool check) {
state = state.copyWith(checkUpdate: check);
}
void setAudioQuality(AudioQuality quality) {
state = state.copyWith(audioQuality: quality);
}
void setDownloadLocation(String downloadDir) {
if (downloadDir.isEmpty) return;
state = state.copyWith(downloadLocation: downloadDir);
}
void setLayoutMode(LayoutMode mode) {
state = state.copyWith(layoutMode: mode);
}
void setCloseBehavior(CloseBehavior behavior) {
state = state.copyWith(closeBehavior: behavior);
}
void setShowSystemTrayIcon(bool show) {
state = state.copyWith(showSystemTrayIcon: show);
}
void setLocale(Locale locale) {
state = state.copyWith(locale: locale);
}
void setPipedInstance(String instance) {
state = state.copyWith(pipedInstance: instance);
}
void setSearchMode(SearchMode mode) {
state = state.copyWith(searchMode: mode);
}
void setSkipNonMusic(bool skip) {
state = state.copyWith(skipNonMusic: skip);
}
void setYoutubeApiType(YoutubeApiType type) {
state = state.copyWith(youtubeApiType: type);
}
void setSystemTitleBar(bool isSystemTitleBar) {
state = state.copyWith(systemTitleBar: isSystemTitleBar);
if (DesktopTools.platform.isDesktop) {
DesktopTools.window.setTitleBarStyle(
isSystemTitleBar ? TitleBarStyle.normal : TitleBarStyle.hidden,
);
}
}
void setAmoledDarkTheme(bool isAmoled) {
state = state.copyWith(amoledDarkTheme: isAmoled);
}
void setNormalizeAudio(bool normalize) {
state = state.copyWith(normalizeAudio: normalize);
audioPlayer.setAudioNormalization(normalize);
}
Future<String> _getDefaultDownloadDirectory() async {
if (kIsAndroid) return "/storage/emulated/0/Download/Spotube";
if (kIsMacOS) {
return path.join((await getLibraryDirectory()).path, "Caches");
}
return getDownloadsDirectory().then((dir) {
return path.join(dir!.path, "Spotube");
});
}
@override
FutureOr<void> onInit() async {
if (state.downloadLocation.isEmpty) {
state = state.copyWith(
downloadLocation: await _getDefaultDownloadDirectory(),
);
}
if (DesktopTools.platform.isDesktop) {
await DesktopTools.window.setTitleBarStyle(
state.systemTitleBar ? TitleBarStyle.normal : TitleBarStyle.hidden,
);
}
await audioPlayer.setAudioNormalization(state.normalizeAudio);
}
@override
FutureOr<UserPreferences> fromJson(Map<String, dynamic> json) {
return UserPreferences.fromJson(json);
}
@override
Map<String, dynamic> toJson() {
return state.toJson();
}
}
final userPreferencesProvider =
StateNotifierProvider<UserPreferencesNotifier, UserPreferences>(
(ref) => UserPreferencesNotifier(ref),
);

View File

@ -0,0 +1,273 @@
import 'dart:convert';
import 'package:flutter/material.dart';
import 'package:json_annotation/json_annotation.dart';
import 'package:spotify/spotify.dart';
import 'package:spotube/components/settings/color_scheme_picker_dialog.dart';
import 'package:spotube/models/matched_track.dart';
part 'user_preferences_state.g.dart';
@JsonEnum()
enum LayoutMode {
compact,
extended,
adaptive,
}
@JsonEnum()
enum AudioQuality {
high,
low,
}
@JsonEnum()
enum CloseBehavior {
minimizeToTray,
close,
}
@JsonEnum()
enum YoutubeApiType {
youtube,
piped;
String get label => name[0].toUpperCase() + name.substring(1);
}
@JsonEnum()
enum MusicCodec {
m4a._("M4a (Best for downloaded music)"),
weba._("WebA (Best for streamed music)\nDoesn't support audio metadata");
final String label;
const MusicCodec._(this.label);
}
@JsonSerializable()
final class UserPreferences {
@JsonKey(
defaultValue: AudioQuality.high,
unknownEnumValue: AudioQuality.high,
)
final AudioQuality audioQuality;
@JsonKey(defaultValue: true)
final bool albumColorSync;
@JsonKey(defaultValue: false)
final bool amoledDarkTheme;
@JsonKey(defaultValue: true)
final bool checkUpdate;
@JsonKey(defaultValue: false)
final bool normalizeAudio;
@JsonKey(defaultValue: true)
final bool showSystemTrayIcon;
@JsonKey(defaultValue: true)
final bool skipNonMusic;
@JsonKey(defaultValue: false)
final bool systemTitleBar;
@JsonKey(
defaultValue: CloseBehavior.minimizeToTray,
unknownEnumValue: CloseBehavior.minimizeToTray,
)
final CloseBehavior closeBehavior;
static SpotubeColor _accentColorSchemeFromJson(Map<String, dynamic> json) {
return SpotubeColor.fromString(json["color"]);
}
static Map<String, dynamic>? _accentColorSchemeReadValue(
Map<dynamic, dynamic> json, String key) {
if (json[key] is String) {
return {"color": json[key]};
}
return json[key] as Map<String, dynamic>?;
}
static Map<String, dynamic> _accentColorSchemeToJson(SpotubeColor color) {
return {"color": color.toString()};
}
static SpotubeColor _defaultAccentColorScheme() =>
const SpotubeColor(0xFF2196F3, name: "Blue");
@JsonKey(
defaultValue: UserPreferences._defaultAccentColorScheme,
fromJson: UserPreferences._accentColorSchemeFromJson,
toJson: UserPreferences._accentColorSchemeToJson,
readValue: UserPreferences._accentColorSchemeReadValue,
)
final SpotubeColor accentColorScheme;
@JsonKey(
defaultValue: LayoutMode.adaptive,
unknownEnumValue: LayoutMode.adaptive,
)
final LayoutMode layoutMode;
static Locale _localeFromJson(Map<String, dynamic> json) {
return Locale(json["languageCode"], json["countryCode"]);
}
static Map<String, dynamic> _localeToJson(Locale locale) {
return {
"languageCode": locale.languageCode,
"countryCode": locale.countryCode,
};
}
static Map<String, dynamic>? _localeReadValue(
Map<dynamic, dynamic> json, String key) {
if (json[key] is String) {
final map = jsonDecode(json[key]);
return {
"languageCode": map["lc"],
"countryCode": map["cc"],
};
}
return json[key] as Map<String, dynamic>?;
}
static Locale _defaultLocaleValue() => const Locale("system", "system");
@JsonKey(
defaultValue: UserPreferences._defaultLocaleValue,
toJson: UserPreferences._localeToJson,
fromJson: UserPreferences._localeFromJson,
readValue: UserPreferences._localeReadValue,
)
final Locale locale;
@JsonKey(
defaultValue: Market.US,
unknownEnumValue: Market.US,
)
final Market recommendationMarket;
@JsonKey(
defaultValue: SearchMode.youtube,
unknownEnumValue: SearchMode.youtube,
)
final SearchMode searchMode;
@JsonKey(defaultValue: "")
final String downloadLocation;
@JsonKey(defaultValue: "https://pipedapi.kavin.rocks")
final String pipedInstance;
@JsonKey(
defaultValue: ThemeMode.system,
unknownEnumValue: ThemeMode.system,
)
final ThemeMode themeMode;
@JsonKey(
defaultValue: YoutubeApiType.youtube,
unknownEnumValue: YoutubeApiType.youtube,
)
final YoutubeApiType youtubeApiType;
@JsonKey(
defaultValue: MusicCodec.weba,
unknownEnumValue: MusicCodec.weba,
)
final MusicCodec streamMusicCodec;
@JsonKey(
defaultValue: MusicCodec.m4a,
unknownEnumValue: MusicCodec.m4a,
)
final MusicCodec downloadMusicCodec;
UserPreferences({
required this.audioQuality,
required this.albumColorSync,
required this.amoledDarkTheme,
required this.checkUpdate,
required this.normalizeAudio,
required this.showSystemTrayIcon,
required this.skipNonMusic,
required this.systemTitleBar,
required this.closeBehavior,
required this.accentColorScheme,
required this.layoutMode,
required this.locale,
required this.recommendationMarket,
required this.searchMode,
required this.downloadLocation,
required this.pipedInstance,
required this.themeMode,
required this.youtubeApiType,
required this.streamMusicCodec,
required this.downloadMusicCodec,
});
factory UserPreferences.withDefaults() {
return UserPreferences.fromJson({});
}
factory UserPreferences.fromJson(Map<String, dynamic> json) {
return _$UserPreferencesFromJson(json);
}
Map<String, dynamic> toJson() {
return _$UserPreferencesToJson(this);
}
UserPreferences copyWith({
ThemeMode? themeMode,
SpotubeColor? accentColorScheme,
bool? albumColorSync,
bool? checkUpdate,
AudioQuality? audioQuality,
String? downloadLocation,
LayoutMode? layoutMode,
CloseBehavior? closeBehavior,
bool? showSystemTrayIcon,
Locale? locale,
String? pipedInstance,
SearchMode? searchMode,
bool? skipNonMusic,
YoutubeApiType? youtubeApiType,
Market? recommendationMarket,
bool? saveTrackLyrics,
bool? amoledDarkTheme,
bool? normalizeAudio,
MusicCodec? downloadMusicCodec,
MusicCodec? streamMusicCodec,
bool? systemTitleBar,
}) {
return UserPreferences(
themeMode: themeMode ?? this.themeMode,
accentColorScheme: accentColorScheme ?? this.accentColorScheme,
albumColorSync: albumColorSync ?? this.albumColorSync,
checkUpdate: checkUpdate ?? this.checkUpdate,
audioQuality: audioQuality ?? this.audioQuality,
downloadLocation: downloadLocation ?? this.downloadLocation,
layoutMode: layoutMode ?? this.layoutMode,
closeBehavior: closeBehavior ?? this.closeBehavior,
showSystemTrayIcon: showSystemTrayIcon ?? this.showSystemTrayIcon,
locale: locale ?? this.locale,
pipedInstance: pipedInstance ?? this.pipedInstance,
searchMode: searchMode ?? this.searchMode,
skipNonMusic: skipNonMusic ?? this.skipNonMusic,
youtubeApiType: youtubeApiType ?? this.youtubeApiType,
recommendationMarket: recommendationMarket ?? this.recommendationMarket,
amoledDarkTheme: amoledDarkTheme ?? this.amoledDarkTheme,
downloadMusicCodec: downloadMusicCodec ?? this.downloadMusicCodec,
normalizeAudio: normalizeAudio ?? this.normalizeAudio,
streamMusicCodec: streamMusicCodec ?? this.streamMusicCodec,
systemTitleBar: systemTitleBar ?? this.systemTitleBar,
);
}
}

View File

@ -0,0 +1,381 @@
// GENERATED CODE - DO NOT MODIFY BY HAND
part of 'user_preferences_state.dart';
// **************************************************************************
// JsonSerializableGenerator
// **************************************************************************
UserPreferences _$UserPreferencesFromJson(Map<String, dynamic> json) =>
UserPreferences(
audioQuality: $enumDecodeNullable(
_$AudioQualityEnumMap, json['audioQuality'],
unknownValue: AudioQuality.high) ??
AudioQuality.high,
albumColorSync: json['albumColorSync'] as bool? ?? true,
amoledDarkTheme: json['amoledDarkTheme'] as bool? ?? false,
checkUpdate: json['checkUpdate'] as bool? ?? true,
normalizeAudio: json['normalizeAudio'] as bool? ?? false,
showSystemTrayIcon: json['showSystemTrayIcon'] as bool? ?? true,
skipNonMusic: json['skipNonMusic'] as bool? ?? true,
systemTitleBar: json['systemTitleBar'] as bool? ?? false,
closeBehavior: $enumDecodeNullable(
_$CloseBehaviorEnumMap, json['closeBehavior'],
unknownValue: CloseBehavior.minimizeToTray) ??
CloseBehavior.minimizeToTray,
accentColorScheme: UserPreferences._accentColorSchemeReadValue(
json, 'accentColorScheme') ==
null
? UserPreferences._defaultAccentColorScheme()
: UserPreferences._accentColorSchemeFromJson(
UserPreferences._accentColorSchemeReadValue(
json, 'accentColorScheme') as Map<String, dynamic>),
layoutMode: $enumDecodeNullable(_$LayoutModeEnumMap, json['layoutMode'],
unknownValue: LayoutMode.adaptive) ??
LayoutMode.adaptive,
locale: UserPreferences._localeReadValue(json, 'locale') == null
? UserPreferences._defaultLocaleValue()
: UserPreferences._localeFromJson(
UserPreferences._localeReadValue(json, 'locale')
as Map<String, dynamic>),
recommendationMarket: $enumDecodeNullable(
_$MarketEnumMap, json['recommendationMarket'],
unknownValue: Market.US) ??
Market.US,
searchMode: $enumDecodeNullable(_$SearchModeEnumMap, json['searchMode'],
unknownValue: SearchMode.youtube) ??
SearchMode.youtube,
downloadLocation: json['downloadLocation'] as String? ?? '',
pipedInstance:
json['pipedInstance'] as String? ?? 'https://pipedapi.kavin.rocks',
themeMode: $enumDecodeNullable(_$ThemeModeEnumMap, json['themeMode'],
unknownValue: ThemeMode.system) ??
ThemeMode.system,
youtubeApiType: $enumDecodeNullable(
_$YoutubeApiTypeEnumMap, json['youtubeApiType'],
unknownValue: YoutubeApiType.youtube) ??
YoutubeApiType.youtube,
streamMusicCodec: $enumDecodeNullable(
_$MusicCodecEnumMap, json['streamMusicCodec'],
unknownValue: MusicCodec.weba) ??
MusicCodec.weba,
downloadMusicCodec: $enumDecodeNullable(
_$MusicCodecEnumMap, json['downloadMusicCodec'],
unknownValue: MusicCodec.m4a) ??
MusicCodec.m4a,
);
Map<String, dynamic> _$UserPreferencesToJson(UserPreferences instance) =>
<String, dynamic>{
'audioQuality': _$AudioQualityEnumMap[instance.audioQuality]!,
'albumColorSync': instance.albumColorSync,
'amoledDarkTheme': instance.amoledDarkTheme,
'checkUpdate': instance.checkUpdate,
'normalizeAudio': instance.normalizeAudio,
'showSystemTrayIcon': instance.showSystemTrayIcon,
'skipNonMusic': instance.skipNonMusic,
'systemTitleBar': instance.systemTitleBar,
'closeBehavior': _$CloseBehaviorEnumMap[instance.closeBehavior]!,
'accentColorScheme':
UserPreferences._accentColorSchemeToJson(instance.accentColorScheme),
'layoutMode': _$LayoutModeEnumMap[instance.layoutMode]!,
'locale': UserPreferences._localeToJson(instance.locale),
'recommendationMarket': _$MarketEnumMap[instance.recommendationMarket]!,
'searchMode': _$SearchModeEnumMap[instance.searchMode]!,
'downloadLocation': instance.downloadLocation,
'pipedInstance': instance.pipedInstance,
'themeMode': _$ThemeModeEnumMap[instance.themeMode]!,
'youtubeApiType': _$YoutubeApiTypeEnumMap[instance.youtubeApiType]!,
'streamMusicCodec': _$MusicCodecEnumMap[instance.streamMusicCodec]!,
'downloadMusicCodec': _$MusicCodecEnumMap[instance.downloadMusicCodec]!,
};
const _$AudioQualityEnumMap = {
AudioQuality.high: 'high',
AudioQuality.low: 'low',
};
const _$CloseBehaviorEnumMap = {
CloseBehavior.minimizeToTray: 'minimizeToTray',
CloseBehavior.close: 'close',
};
const _$LayoutModeEnumMap = {
LayoutMode.compact: 'compact',
LayoutMode.extended: 'extended',
LayoutMode.adaptive: 'adaptive',
};
const _$MarketEnumMap = {
Market.AD: 'AD',
Market.AE: 'AE',
Market.AF: 'AF',
Market.AG: 'AG',
Market.AI: 'AI',
Market.AL: 'AL',
Market.AM: 'AM',
Market.AO: 'AO',
Market.AQ: 'AQ',
Market.AR: 'AR',
Market.AS: 'AS',
Market.AT: 'AT',
Market.AU: 'AU',
Market.AW: 'AW',
Market.AX: 'AX',
Market.AZ: 'AZ',
Market.BA: 'BA',
Market.BB: 'BB',
Market.BD: 'BD',
Market.BE: 'BE',
Market.BF: 'BF',
Market.BG: 'BG',
Market.BH: 'BH',
Market.BI: 'BI',
Market.BJ: 'BJ',
Market.BL: 'BL',
Market.BM: 'BM',
Market.BN: 'BN',
Market.BO: 'BO',
Market.BQ: 'BQ',
Market.BR: 'BR',
Market.BS: 'BS',
Market.BT: 'BT',
Market.BV: 'BV',
Market.BW: 'BW',
Market.BY: 'BY',
Market.BZ: 'BZ',
Market.CA: 'CA',
Market.CC: 'CC',
Market.CD: 'CD',
Market.CF: 'CF',
Market.CG: 'CG',
Market.CH: 'CH',
Market.CI: 'CI',
Market.CK: 'CK',
Market.CL: 'CL',
Market.CM: 'CM',
Market.CN: 'CN',
Market.CO: 'CO',
Market.CR: 'CR',
Market.CU: 'CU',
Market.CV: 'CV',
Market.CW: 'CW',
Market.CX: 'CX',
Market.CY: 'CY',
Market.CZ: 'CZ',
Market.DE: 'DE',
Market.DJ: 'DJ',
Market.DK: 'DK',
Market.DM: 'DM',
Market.DO: 'DO',
Market.DZ: 'DZ',
Market.EC: 'EC',
Market.EE: 'EE',
Market.EG: 'EG',
Market.EH: 'EH',
Market.ER: 'ER',
Market.ES: 'ES',
Market.ET: 'ET',
Market.FI: 'FI',
Market.FJ: 'FJ',
Market.FK: 'FK',
Market.FM: 'FM',
Market.FO: 'FO',
Market.FR: 'FR',
Market.GA: 'GA',
Market.GB: 'GB',
Market.GD: 'GD',
Market.GE: 'GE',
Market.GF: 'GF',
Market.GG: 'GG',
Market.GH: 'GH',
Market.GI: 'GI',
Market.GL: 'GL',
Market.GM: 'GM',
Market.GN: 'GN',
Market.GP: 'GP',
Market.GQ: 'GQ',
Market.GR: 'GR',
Market.GS: 'GS',
Market.GT: 'GT',
Market.GU: 'GU',
Market.GW: 'GW',
Market.GY: 'GY',
Market.HK: 'HK',
Market.HM: 'HM',
Market.HN: 'HN',
Market.HR: 'HR',
Market.HT: 'HT',
Market.HU: 'HU',
Market.ID: 'ID',
Market.IE: 'IE',
Market.IL: 'IL',
Market.IM: 'IM',
Market.IN: 'IN',
Market.IO: 'IO',
Market.IQ: 'IQ',
Market.IR: 'IR',
Market.IS: 'IS',
Market.IT: 'IT',
Market.JE: 'JE',
Market.JM: 'JM',
Market.JO: 'JO',
Market.JP: 'JP',
Market.KE: 'KE',
Market.KG: 'KG',
Market.KH: 'KH',
Market.KI: 'KI',
Market.KM: 'KM',
Market.KN: 'KN',
Market.KP: 'KP',
Market.KR: 'KR',
Market.KW: 'KW',
Market.KY: 'KY',
Market.KZ: 'KZ',
Market.LA: 'LA',
Market.LB: 'LB',
Market.LC: 'LC',
Market.LI: 'LI',
Market.LK: 'LK',
Market.LR: 'LR',
Market.LS: 'LS',
Market.LT: 'LT',
Market.LU: 'LU',
Market.LV: 'LV',
Market.LY: 'LY',
Market.MA: 'MA',
Market.MC: 'MC',
Market.MD: 'MD',
Market.ME: 'ME',
Market.MF: 'MF',
Market.MG: 'MG',
Market.MH: 'MH',
Market.MK: 'MK',
Market.ML: 'ML',
Market.MM: 'MM',
Market.MN: 'MN',
Market.MO: 'MO',
Market.MP: 'MP',
Market.MQ: 'MQ',
Market.MR: 'MR',
Market.MS: 'MS',
Market.MT: 'MT',
Market.MU: 'MU',
Market.MV: 'MV',
Market.MW: 'MW',
Market.MX: 'MX',
Market.MY: 'MY',
Market.MZ: 'MZ',
Market.NA: 'NA',
Market.NC: 'NC',
Market.NE: 'NE',
Market.NF: 'NF',
Market.NG: 'NG',
Market.NI: 'NI',
Market.NL: 'NL',
Market.NO: 'NO',
Market.NP: 'NP',
Market.NR: 'NR',
Market.NU: 'NU',
Market.NZ: 'NZ',
Market.OM: 'OM',
Market.PA: 'PA',
Market.PE: 'PE',
Market.PF: 'PF',
Market.PG: 'PG',
Market.PH: 'PH',
Market.PK: 'PK',
Market.PL: 'PL',
Market.PM: 'PM',
Market.PN: 'PN',
Market.PR: 'PR',
Market.PS: 'PS',
Market.PT: 'PT',
Market.PW: 'PW',
Market.PY: 'PY',
Market.QA: 'QA',
Market.RE: 'RE',
Market.RO: 'RO',
Market.RS: 'RS',
Market.RU: 'RU',
Market.RW: 'RW',
Market.SA: 'SA',
Market.SB: 'SB',
Market.SC: 'SC',
Market.SD: 'SD',
Market.SE: 'SE',
Market.SG: 'SG',
Market.SH: 'SH',
Market.SI: 'SI',
Market.SJ: 'SJ',
Market.SK: 'SK',
Market.SL: 'SL',
Market.SM: 'SM',
Market.SN: 'SN',
Market.SO: 'SO',
Market.SR: 'SR',
Market.SS: 'SS',
Market.ST: 'ST',
Market.SV: 'SV',
Market.SX: 'SX',
Market.SY: 'SY',
Market.SZ: 'SZ',
Market.TC: 'TC',
Market.TD: 'TD',
Market.TF: 'TF',
Market.TG: 'TG',
Market.TH: 'TH',
Market.TJ: 'TJ',
Market.TK: 'TK',
Market.TL: 'TL',
Market.TM: 'TM',
Market.TN: 'TN',
Market.TO: 'TO',
Market.TR: 'TR',
Market.TT: 'TT',
Market.TV: 'TV',
Market.TW: 'TW',
Market.TZ: 'TZ',
Market.UA: 'UA',
Market.UG: 'UG',
Market.UM: 'UM',
Market.US: 'US',
Market.UY: 'UY',
Market.UZ: 'UZ',
Market.VA: 'VA',
Market.VC: 'VC',
Market.VE: 'VE',
Market.VG: 'VG',
Market.VI: 'VI',
Market.VN: 'VN',
Market.VU: 'VU',
Market.WF: 'WF',
Market.WS: 'WS',
Market.XK: 'XK',
Market.YE: 'YE',
Market.YT: 'YT',
Market.ZA: 'ZA',
Market.ZM: 'ZM',
Market.ZW: 'ZW',
};
const _$SearchModeEnumMap = {
SearchMode.youtube: 'youtube',
SearchMode.youtubeMusic: 'youtubeMusic',
};
const _$ThemeModeEnumMap = {
ThemeMode.system: 'system',
ThemeMode.light: 'light',
ThemeMode.dark: 'dark',
};
const _$YoutubeApiTypeEnumMap = {
YoutubeApiType.youtube: 'youtube',
YoutubeApiType.piped: 'piped',
};
const _$MusicCodecEnumMap = {
MusicCodec.m4a: 'm4a',
MusicCodec.weba: 'weba',
};

View File

@ -1,391 +0,0 @@
import 'dart:async';
import 'dart:convert';
import 'package:flutter/material.dart';
import 'package:flutter_desktop_tools/flutter_desktop_tools.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:path_provider/path_provider.dart';
import 'package:spotify/spotify.dart';
import 'package:spotube/components/settings/color_scheme_picker_dialog.dart';
import 'package:spotube/models/matched_track.dart';
import 'package:spotube/provider/palette_provider.dart';
import 'package:spotube/provider/proxy_playlist/proxy_playlist_provider.dart';
import 'package:spotube/services/audio_player/audio_player.dart';
import 'package:spotube/utils/persisted_state_notifier.dart';
import 'package:spotube/utils/platform.dart';
import 'package:path/path.dart' as path;
enum LayoutMode {
compact,
extended,
adaptive,
}
enum AudioQuality {
high,
low,
}
enum CloseBehavior {
minimizeToTray,
close,
}
enum YoutubeApiType {
youtube,
piped;
String get label => name[0].toUpperCase() + name.substring(1);
}
enum MusicCodec {
m4a._("M4a (Best for downloaded music)"),
weba._("WebA (Best for streamed music)\nDoesn't support audio metadata");
final String label;
const MusicCodec._(this.label);
}
class UserPreferences {
final AudioQuality audioQuality;
final bool albumColorSync;
final bool amoledDarkTheme;
final bool checkUpdate;
final bool normalizeAudio;
final bool showSystemTrayIcon;
final bool skipNonMusic;
final bool systemTitleBar;
final CloseBehavior closeBehavior;
final SpotubeColor accentColorScheme;
final LayoutMode layoutMode;
final Locale locale;
final Market recommendationMarket;
final SearchMode searchMode;
String downloadLocation;
final String pipedInstance;
final ThemeMode themeMode;
final YoutubeApiType youtubeApiType;
final MusicCodec streamMusicCodec;
final MusicCodec downloadMusicCodec;
UserPreferences({
required AudioQuality? audioQuality,
required bool? albumColorSync,
required bool? amoledDarkTheme,
required bool? checkUpdate,
required bool? normalizeAudio,
required bool? showSystemTrayIcon,
required bool? skipNonMusic,
required bool? systemTitleBar,
required CloseBehavior? closeBehavior,
required SpotubeColor? accentColorScheme,
required LayoutMode? layoutMode,
required Locale? locale,
required Market? recommendationMarket,
required SearchMode? searchMode,
required String? downloadLocation,
required String? pipedInstance,
required ThemeMode? themeMode,
required YoutubeApiType? youtubeApiType,
required MusicCodec? streamMusicCodec,
required MusicCodec? downloadMusicCodec,
}) : accentColorScheme =
accentColorScheme ?? const SpotubeColor(0xFF2196F3, name: "Blue"),
albumColorSync = albumColorSync ?? true,
amoledDarkTheme = amoledDarkTheme ?? false,
audioQuality = audioQuality ?? AudioQuality.high,
checkUpdate = checkUpdate ?? true,
closeBehavior = closeBehavior ?? CloseBehavior.close,
downloadLocation = downloadLocation ?? "",
downloadMusicCodec = downloadMusicCodec ?? MusicCodec.m4a,
layoutMode = layoutMode ?? LayoutMode.adaptive,
locale = locale ?? const Locale("system", "system"),
normalizeAudio = normalizeAudio ?? true,
pipedInstance = pipedInstance ?? "https://pipedapi.kavin.rocks",
recommendationMarket = recommendationMarket ?? Market.US,
searchMode = searchMode ?? SearchMode.youtube,
showSystemTrayIcon = showSystemTrayIcon ?? true,
skipNonMusic = skipNonMusic ?? true,
streamMusicCodec = streamMusicCodec ?? MusicCodec.weba,
systemTitleBar = systemTitleBar ?? false,
themeMode = themeMode ?? ThemeMode.system,
youtubeApiType = youtubeApiType ?? YoutubeApiType.youtube {
if (downloadLocation == null) {
_getDefaultDownloadDirectory().then(
(value) => this.downloadLocation = value,
);
}
}
factory UserPreferences.withDefaults() {
return UserPreferences(
audioQuality: null,
albumColorSync: null,
amoledDarkTheme: null,
checkUpdate: null,
normalizeAudio: null,
showSystemTrayIcon: null,
skipNonMusic: null,
systemTitleBar: null,
closeBehavior: null,
accentColorScheme: null,
layoutMode: null,
locale: null,
recommendationMarket: null,
searchMode: null,
downloadLocation: null,
pipedInstance: null,
themeMode: null,
youtubeApiType: null,
streamMusicCodec: null,
downloadMusicCodec: null,
);
}
static Future<String> _getDefaultDownloadDirectory() async {
if (kIsAndroid) return "/storage/emulated/0/Download/Spotube";
if (kIsMacOS) {
return path.join((await getLibraryDirectory()).path, "Caches");
}
return getDownloadsDirectory().then((dir) {
return path.join(dir!.path, "Spotube");
});
}
static Future<UserPreferences> fromJson(Map<String, dynamic> json) async {
final localeMap =
json["locale"] != null ? jsonDecode(json["locale"]) : null;
final systemTitleBar = json["systemTitleBar"] ?? false;
if (DesktopTools.platform.isDesktop) {
await DesktopTools.window.setTitleBarStyle(
systemTitleBar ? TitleBarStyle.normal : TitleBarStyle.hidden,
);
}
final normalizeAudio = json["normalizeAudio"] ?? true;
audioPlayer.setAudioNormalization(normalizeAudio);
return UserPreferences(
accentColorScheme: json["accentColorScheme"] == null
? null
: SpotubeColor.fromString(json["accentColorScheme"]),
albumColorSync: json["albumColorSync"],
amoledDarkTheme: json["amoledDarkTheme"],
audioQuality: AudioQuality.values[json["audioQuality"]],
checkUpdate: json["checkUpdate"],
closeBehavior: CloseBehavior.values[json["closeBehavior"]],
downloadLocation:
json["downloadLocation"] ?? await _getDefaultDownloadDirectory(),
downloadMusicCodec: MusicCodec.values[json["downloadMusicCodec"]],
layoutMode: LayoutMode.values[json["layoutMode"]],
locale:
localeMap == null ? null : Locale(localeMap?["lc"], localeMap?["cc"]),
normalizeAudio: json["normalizeAudio"],
pipedInstance: json["pipedInstance"],
recommendationMarket: Market.values[json["recommendationMarket"]],
searchMode: SearchMode.values[json["searchMode"]],
showSystemTrayIcon: json["showSystemTrayIcon"],
skipNonMusic: json["skipNonMusic"],
streamMusicCodec: MusicCodec.values[json["streamMusicCodec"]],
systemTitleBar: json["systemTitleBar"],
themeMode: ThemeMode.values[json["themeMode"]],
youtubeApiType: YoutubeApiType.values[json["youtubeApiType"]],
);
}
Map<String, dynamic> toJson() {
return {
"recommendationMarket": recommendationMarket.index,
"themeMode": themeMode.index,
"accentColorScheme": accentColorScheme.toString(),
"albumColorSync": albumColorSync,
"checkUpdate": checkUpdate,
"audioQuality": audioQuality.index,
"downloadLocation": downloadLocation,
"layoutMode": layoutMode.index,
"closeBehavior": closeBehavior.index,
"showSystemTrayIcon": showSystemTrayIcon,
"locale":
jsonEncode({"lc": locale.languageCode, "cc": locale.countryCode}),
"pipedInstance": pipedInstance,
"searchMode": searchMode.index,
"skipNonMusic": skipNonMusic,
"youtubeApiType": youtubeApiType.index,
'systemTitleBar': systemTitleBar,
"amoledDarkTheme": amoledDarkTheme,
"normalizeAudio": normalizeAudio,
"streamMusicCodec": streamMusicCodec.index,
"downloadMusicCodec": downloadMusicCodec.index,
};
}
UserPreferences copyWith({
ThemeMode? themeMode,
SpotubeColor? accentColorScheme,
bool? albumColorSync,
bool? checkUpdate,
AudioQuality? audioQuality,
String? downloadLocation,
LayoutMode? layoutMode,
CloseBehavior? closeBehavior,
bool? showSystemTrayIcon,
Locale? locale,
String? pipedInstance,
SearchMode? searchMode,
bool? skipNonMusic,
YoutubeApiType? youtubeApiType,
Market? recommendationMarket,
bool? saveTrackLyrics,
bool? amoledDarkTheme,
bool? normalizeAudio,
MusicCodec? downloadMusicCodec,
MusicCodec? streamMusicCodec,
bool? systemTitleBar,
}) {
return UserPreferences(
themeMode: themeMode ?? this.themeMode,
accentColorScheme: accentColorScheme ?? this.accentColorScheme,
albumColorSync: albumColorSync ?? this.albumColorSync,
checkUpdate: checkUpdate ?? this.checkUpdate,
audioQuality: audioQuality ?? this.audioQuality,
downloadLocation: downloadLocation ?? this.downloadLocation,
layoutMode: layoutMode ?? this.layoutMode,
closeBehavior: closeBehavior ?? this.closeBehavior,
showSystemTrayIcon: showSystemTrayIcon ?? this.showSystemTrayIcon,
locale: locale ?? this.locale,
pipedInstance: pipedInstance ?? this.pipedInstance,
searchMode: searchMode ?? this.searchMode,
skipNonMusic: skipNonMusic ?? this.skipNonMusic,
youtubeApiType: youtubeApiType ?? this.youtubeApiType,
recommendationMarket: recommendationMarket ?? this.recommendationMarket,
amoledDarkTheme: amoledDarkTheme ?? this.amoledDarkTheme,
downloadMusicCodec: downloadMusicCodec ?? this.downloadMusicCodec,
normalizeAudio: normalizeAudio ?? this.normalizeAudio,
streamMusicCodec: streamMusicCodec ?? this.streamMusicCodec,
systemTitleBar: systemTitleBar ?? this.systemTitleBar,
);
}
}
class UserPreferencesNotifier extends PersistedStateNotifier<UserPreferences> {
final Ref ref;
UserPreferencesNotifier(this.ref)
: super(UserPreferences.withDefaults(), "preferences");
void reset() {
state = UserPreferences.withDefaults();
}
void setStreamMusicCodec(MusicCodec codec) {
state = state.copyWith(streamMusicCodec: codec);
}
void setDownloadMusicCodec(MusicCodec codec) {
state = state.copyWith(downloadMusicCodec: codec);
}
void setThemeMode(ThemeMode mode) {
state = state.copyWith(themeMode: mode);
}
void setRecommendationMarket(Market country) {
state = state.copyWith(recommendationMarket: country);
}
void setAccentColorScheme(SpotubeColor color) {
state = state.copyWith(accentColorScheme: color);
}
void setAlbumColorSync(bool sync) {
state = state.copyWith(albumColorSync: sync);
if (!sync) {
ref.read(paletteProvider.notifier).state = null;
} else {
ref.read(ProxyPlaylistNotifier.notifier).updatePalette();
}
}
void setCheckUpdate(bool check) {
state = state.copyWith(checkUpdate: check);
}
void setAudioQuality(AudioQuality quality) {
state = state.copyWith(audioQuality: quality);
}
void setDownloadLocation(String downloadDir) {
if (downloadDir.isEmpty) return;
state = state.copyWith(downloadLocation: downloadDir);
}
void setLayoutMode(LayoutMode mode) {
state = state.copyWith(layoutMode: mode);
}
void setCloseBehavior(CloseBehavior behavior) {
state = state.copyWith(closeBehavior: behavior);
}
void setShowSystemTrayIcon(bool show) {
state = state.copyWith(showSystemTrayIcon: show);
}
void setLocale(Locale locale) {
state = state.copyWith(locale: locale);
}
void setPipedInstance(String instance) {
state = state.copyWith(pipedInstance: instance);
}
void setSearchMode(SearchMode mode) {
state = state.copyWith(searchMode: mode);
}
void setSkipNonMusic(bool skip) {
state = state.copyWith(skipNonMusic: skip);
}
void setYoutubeApiType(YoutubeApiType type) {
state = state.copyWith(youtubeApiType: type);
}
void setSystemTitleBar(bool isSystemTitleBar) {
state = state.copyWith(systemTitleBar: isSystemTitleBar);
if (DesktopTools.platform.isDesktop) {
DesktopTools.window.setTitleBarStyle(
isSystemTitleBar ? TitleBarStyle.normal : TitleBarStyle.hidden,
);
}
}
void setAmoledDarkTheme(bool isAmoled) {
state = state.copyWith(amoledDarkTheme: isAmoled);
}
void setNormalizeAudio(bool normalize) {
state = state.copyWith(normalizeAudio: normalize);
audioPlayer.setAudioNormalization(normalize);
}
@override
FutureOr<UserPreferences> fromJson(Map<String, dynamic> json) {
return UserPreferences.fromJson(json);
}
@override
Map<String, dynamic> toJson() {
return state.toJson();
}
}
final userPreferencesProvider =
StateNotifierProvider<UserPreferencesNotifier, UserPreferences>(
(ref) => UserPreferencesNotifier(ref),
);

View File

@ -1,5 +1,5 @@
import 'package:hooks_riverpod/hooks_riverpod.dart';
import 'package:spotube/provider/user_preferences_provider.dart';
import 'package:spotube/provider/user_preferences/user_preferences_provider.dart';
import 'package:spotube/services/youtube/youtube.dart';
final youtubeProvider = Provider<YoutubeEndpoints>((ref) {

View File

@ -4,7 +4,7 @@ import 'package:hooks_riverpod/hooks_riverpod.dart';
import 'package:spotify/spotify.dart';
import 'package:spotube/hooks/spotify/use_spotify_infinite_query.dart';
import 'package:spotube/hooks/spotify/use_spotify_query.dart';
import 'package:spotube/provider/user_preferences_provider.dart';
import 'package:spotube/provider/user_preferences/user_preferences_provider.dart';
class AlbumQueries {
const AlbumQueries();

View File

@ -6,7 +6,7 @@ import 'package:spotify/spotify.dart';
import 'package:spotube/extensions/context.dart';
import 'package:spotube/hooks/spotify/use_spotify_infinite_query.dart';
import 'package:spotube/provider/custom_spotify_endpoint_provider.dart';
import 'package:spotube/provider/user_preferences_provider.dart';
import 'package:spotube/provider/user_preferences/user_preferences_provider.dart';
class CategoryQueries {
const CategoryQueries();

View File

@ -11,7 +11,7 @@ import 'package:spotube/hooks/spotify/use_spotify_infinite_query.dart';
import 'package:spotube/hooks/spotify/use_spotify_query.dart';
import 'package:spotube/pages/library/playlist_generate/playlist_generate.dart';
import 'package:spotube/provider/custom_spotify_endpoint_provider.dart';
import 'package:spotube/provider/user_preferences_provider.dart';
import 'package:spotube/provider/user_preferences/user_preferences_provider.dart';
typedef RecommendationParameters = ({
RecommendationAttribute acousticness,

View File

@ -5,7 +5,7 @@ import 'package:hooks_riverpod/hooks_riverpod.dart';
import 'package:spotube/extensions/context.dart';
import 'package:spotube/provider/authentication_provider.dart';
import 'package:spotube/provider/custom_spotify_endpoint_provider.dart';
import 'package:spotube/provider/user_preferences_provider.dart';
import 'package:spotube/provider/user_preferences/user_preferences_provider.dart';
class ViewsQueries {
const ViewsQueries();

View File

@ -4,7 +4,7 @@ import 'package:piped_client/piped_client.dart';
import 'package:spotube/collections/routes.dart';
import 'package:spotube/components/shared/dialogs/piped_down_dialog.dart';
import 'package:spotube/models/matched_track.dart';
import 'package:spotube/provider/user_preferences_provider.dart';
import 'package:spotube/provider/user_preferences/user_preferences_state.dart';
import 'package:spotube/utils/primitive_utils.dart';
import 'package:youtube_explode_dart/youtube_explode_dart.dart';