Merge branch 'dev' into feat-jiosaavn

This commit is contained in:
Kingkor Roy Tirtho 2023-11-15 18:10:21 +06:00
parent 29ff976e29
commit 925f3b53ff
34 changed files with 872 additions and 439 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

@ -14,7 +14,8 @@ import 'package:spotube/extensions/context.dart';
import 'package:spotube/extensions/duration.dart';
import 'package:spotube/hooks/utils/use_debounce.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/services/sourced_track/models/source_info.dart';
import 'package:spotube/services/sourced_track/models/video_info.dart';
import 'package:spotube/services/sourced_track/sourced_track.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/skip_segment.dart';
import 'package:spotube/models/source_match.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

@ -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

@ -9,7 +9,8 @@ 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/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';
import 'package:spotube/services/sourced_track/enums.dart';
class SettingsPlaybackSection extends HookConsumerWidget {

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

@ -9,7 +9,7 @@ import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:metadata_god/metadata_god.dart';
import 'package:path/path.dart';
import 'package:spotify/spotify.dart';
import 'package:spotube/provider/user_preferences_provider.dart';
import 'package:spotube/provider/user_preferences/user_preferences_provider.dart';
import 'package:spotube/services/download_manager/download_manager.dart';
import 'package:spotube/services/sourced_track/enums.dart';
import 'package:spotube/services/sourced_track/sourced_track.dart';

View File

@ -21,8 +21,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/services/audio_player/audio_player.dart';
import 'package:spotube/services/audio_services/audio_services.dart';
import 'package:spotube/services/sourced_track/exceptions.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/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/services/sourced_track/enums.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(SourceCodecs codec) {
state = state.copyWith(streamMusicCodec: codec);
}
void setDownloadMusicCodec(SourceCodecs 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(SourceQualities 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 setAudioSource(AudioSource type) {
state = state.copyWith(audioSource: 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,282 @@
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/services/sourced_track/enums.dart';
part 'user_preferences_state.g.dart';
@JsonEnum()
enum LayoutMode {
compact,
extended,
adaptive,
}
@JsonEnum()
enum CloseBehavior {
minimizeToTray,
close,
}
@JsonEnum()
enum AudioSource {
youtube,
piped,
jiosaavn;
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);
}
@JsonEnum()
enum SearchMode {
youtube._("YouTube"),
youtubeMusic._("YouTube Music");
final String label;
const SearchMode._(this.label);
factory SearchMode.fromString(String key) {
return SearchMode.values.firstWhere((e) => e.name == key);
}
}
@JsonSerializable()
final class UserPreferences {
@JsonKey(
defaultValue: SourceQualities.high,
unknownEnumValue: SourceQualities.high,
)
final SourceQualities 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: AudioSource.youtube,
unknownEnumValue: AudioSource.youtube,
)
final AudioSource audioSource;
@JsonKey(
defaultValue: SourceCodecs.weba,
unknownEnumValue: SourceCodecs.weba,
)
final SourceCodecs streamMusicCodec;
@JsonKey(
defaultValue: SourceCodecs.m4a,
unknownEnumValue: SourceCodecs.m4a,
)
final SourceCodecs 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.audioSource,
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,
SourceQualities? audioQuality,
String? downloadLocation,
LayoutMode? layoutMode,
CloseBehavior? closeBehavior,
bool? showSystemTrayIcon,
Locale? locale,
String? pipedInstance,
SearchMode? searchMode,
bool? skipNonMusic,
AudioSource? audioSource,
Market? recommendationMarket,
bool? saveTrackLyrics,
bool? amoledDarkTheme,
bool? normalizeAudio,
SourceCodecs? downloadMusicCodec,
SourceCodecs? 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,
audioSource: audioSource ?? this.audioSource,
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,383 @@
// GENERATED CODE - DO NOT MODIFY BY HAND
part of 'user_preferences_state.dart';
// **************************************************************************
// JsonSerializableGenerator
// **************************************************************************
UserPreferences _$UserPreferencesFromJson(Map<String, dynamic> json) =>
UserPreferences(
audioQuality: $enumDecodeNullable(
_$SourceQualitiesEnumMap, json['audioQuality'],
unknownValue: SourceQualities.high) ??
SourceQualities.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,
audioSource: $enumDecodeNullable(
_$AudioSourceEnumMap, json['audioSource'],
unknownValue: AudioSource.youtube) ??
AudioSource.youtube,
streamMusicCodec: $enumDecodeNullable(
_$SourceCodecsEnumMap, json['streamMusicCodec'],
unknownValue: SourceCodecs.weba) ??
SourceCodecs.weba,
downloadMusicCodec: $enumDecodeNullable(
_$SourceCodecsEnumMap, json['downloadMusicCodec'],
unknownValue: SourceCodecs.m4a) ??
SourceCodecs.m4a,
);
Map<String, dynamic> _$UserPreferencesToJson(UserPreferences instance) =>
<String, dynamic>{
'audioQuality': _$SourceQualitiesEnumMap[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]!,
'audioSource': _$AudioSourceEnumMap[instance.audioSource]!,
'streamMusicCodec': _$SourceCodecsEnumMap[instance.streamMusicCodec]!,
'downloadMusicCodec': _$SourceCodecsEnumMap[instance.downloadMusicCodec]!,
};
const _$SourceQualitiesEnumMap = {
SourceQualities.high: 'high',
SourceQualities.medium: 'medium',
SourceQualities.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 _$AudioSourceEnumMap = {
AudioSource.youtube: 'youtube',
AudioSource.piped: 'piped',
AudioSource.jiosaavn: 'jiosaavn',
};
const _$SourceCodecsEnumMap = {
SourceCodecs.m4a: 'm4a',
SourceCodecs.weba: 'weba',
};

View File

@ -1,407 +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/source_match.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/services/sourced_track/enums.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 CloseBehavior {
minimizeToTray,
close,
}
enum AudioSource {
youtube,
piped,
jiosaavn;
String get label => name[0].toUpperCase() + name.substring(1);
}
enum SearchMode {
youtube,
youtubeMusic;
String get label => name[0].toUpperCase() + name.substring(1);
static SearchMode fromString(String? string) {
switch (string) {
case "youtube":
return SearchMode.youtube;
case "youtubeMusic":
return SearchMode.youtubeMusic;
default:
return SearchMode.youtube;
}
}
toSourceType() {
switch (this) {
case SearchMode.youtube:
return SourceType.youtube;
case SearchMode.youtubeMusic:
return SourceType.youtubeMusic;
}
}
}
class UserPreferences {
final SourceQualities 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 AudioSource audioSource;
final SourceCodecs streamMusicCodec;
final SourceCodecs downloadMusicCodec;
UserPreferences({
required SourceQualities? 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 AudioSource? audioSource,
required SourceCodecs? streamMusicCodec,
required SourceCodecs? downloadMusicCodec,
}) : accentColorScheme =
accentColorScheme ?? const SpotubeColor(0xFF2196F3, name: "Blue"),
albumColorSync = albumColorSync ?? true,
amoledDarkTheme = amoledDarkTheme ?? false,
audioQuality = audioQuality ?? SourceQualities.high,
checkUpdate = checkUpdate ?? true,
closeBehavior = closeBehavior ?? CloseBehavior.close,
downloadLocation = downloadLocation ?? "",
downloadMusicCodec = downloadMusicCodec ?? SourceCodecs.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 ?? SourceCodecs.weba,
systemTitleBar = systemTitleBar ?? false,
themeMode = themeMode ?? ThemeMode.system,
audioSource = audioSource ?? AudioSource.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,
audioSource: 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 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);
final Map<String, dynamic>? localeMap =
json["locale"] == null ? null : jsonDecode(json["locale"]);
return UserPreferences(
accentColorScheme: json["accentColorScheme"] == null
? null
: SpotubeColor.fromString(json["accentColorScheme"]),
albumColorSync: json["albumColorSync"],
amoledDarkTheme: json["amoledDarkTheme"],
audioQuality: SourceQualities.values[json["audioQuality"]],
checkUpdate: json["checkUpdate"],
closeBehavior: CloseBehavior.values[json["closeBehavior"]],
downloadLocation:
json["downloadLocation"] ?? await _getDefaultDownloadDirectory(),
downloadMusicCodec: SourceCodecs.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: SourceCodecs.values[json["streamMusicCodec"]],
systemTitleBar: json["systemTitleBar"],
themeMode: ThemeMode.values[json["themeMode"]],
audioSource: AudioSource.values[json["audioSource"]],
);
}
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,
"audioSource": audioSource.index,
'systemTitleBar': systemTitleBar,
"amoledDarkTheme": amoledDarkTheme,
"normalizeAudio": normalizeAudio,
"streamMusicCodec": streamMusicCodec.index,
"downloadMusicCodec": downloadMusicCodec.index,
};
}
UserPreferences copyWith({
ThemeMode? themeMode,
SpotubeColor? accentColorScheme,
bool? albumColorSync,
bool? checkUpdate,
SourceQualities? audioQuality,
String? downloadLocation,
LayoutMode? layoutMode,
CloseBehavior? closeBehavior,
bool? showSystemTrayIcon,
Locale? locale,
String? pipedInstance,
SearchMode? searchMode,
bool? skipNonMusic,
AudioSource? audioSource,
Market? recommendationMarket,
bool? saveTrackLyrics,
bool? amoledDarkTheme,
bool? normalizeAudio,
SourceCodecs? downloadMusicCodec,
SourceCodecs? 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,
audioSource: audioSource ?? this.audioSource,
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(SourceCodecs codec) {
state = state.copyWith(streamMusicCodec: codec);
}
void setDownloadMusicCodec(SourceCodecs 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(SourceQualities 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 setAudioSource(AudioSource type) {
state = state.copyWith(audioSource: 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

@ -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

@ -1,5 +1,5 @@
import 'package:piped_client/piped_client.dart';
import 'package:spotube/provider/user_preferences_provider.dart';
import 'package:spotube/provider/user_preferences/user_preferences_state.dart';
import 'package:youtube_explode_dart/youtube_explode_dart.dart';
class YoutubeVideoInfo {

View File

@ -1,7 +1,8 @@
import 'package:collection/collection.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:spotify/spotify.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/sourced_track/enums.dart';
import 'package:spotube/services/sourced_track/models/source_info.dart';
import 'package:spotube/services/sourced_track/models/source_map.dart';

View File

@ -3,7 +3,8 @@ import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:piped_client/piped_client.dart';
import 'package:spotify/spotify.dart';
import 'package:spotube/models/source_match.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/sourced_track/enums.dart';
import 'package:spotube/services/sourced_track/exceptions.dart';
import 'package:spotube/services/sourced_track/models/source_info.dart';