spotube/lib/provider/user_preferences/user_preferences_state.dart
Blake Leonard 22caa818f4
feat: Local music library (#1479)
* feat: add one additional library folder

This folder just doesn't get downloaded to.
I think I'm going to rework it so that it can be multiple folders,
but I'm going to commit my progress so far anyway.

Signed-off-by: Blake Leonard <me@blakes.dev>

* chore: update dependencies so that it builds

I'm not sure if this breaks CI or something, but I couldn't build
it locally to test my changes, so I made these changes and it
builds again.

Signed-off-by: Blake Leonard <me@blakes.dev>

* feat: index multiple folders of local music

If you used a previous commit from this branch, this is a breaking
change, because it changes the type of a configuration field. but
since this is still in development, it should be fine.

Signed-off-by: Blake Leonard <me@blakes.dev>

* refactor: manage local library in local tracks tab

This also refactors the list to use slivers instead. That's the
easiest way to have multiple scrolling lists here...

The console keeps getting spammed with some intermediate layout
error but I can't hold it long enough to figure out what's causing
it.

Signed-off-by: Blake Leonard <me@blakes.dev>

* refactor: use folder add/remove icons in library

Signed-off-by: Blake Leonard <me@blakes.dev>

* refactor: remove redundant settings page

Signed-off-by: Blake Leonard <me@blakes.dev>

* refactor: rename "Local Tracks" to just "Local"

Not sure if this would be the recommended way to do it...

Signed-off-by: Blake Leonard <me@blakes.dev>

* fix: console spam about useless Expanded

Signed-off-by: Blake Leonard <me@blakes.dev>

* chore: remove completed TODO

Signed-off-by: Blake Leonard <me@blakes.dev>

* chore: use new Platform constants; regenerate plugins

Signed-off-by: Blake Leonard <me@blakes.dev>

* refactor: put local libraries on separate pages

Signed-off-by: Blake Leonard <me@blakes.dev>

---------

Signed-off-by: Blake Leonard <me@blakes.dev>
2024-05-23 15:18:01 +06:00

143 lines
4.0 KiB
Dart

import 'dart:convert';
import 'package:flutter/material.dart';
import 'package:freezed_annotation/freezed_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';
part 'user_preferences_state.freezed.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);
}
}
@freezed
class UserPreferences with _$UserPreferences {
const factory UserPreferences({
@Default(SourceQualities.high) SourceQualities audioQuality,
@Default(true) bool albumColorSync,
@Default(false) bool amoledDarkTheme,
@Default(true) bool checkUpdate,
@Default(false) bool normalizeAudio,
@Default(false) bool showSystemTrayIcon,
@Default(false) bool skipNonMusic,
@Default(false) bool systemTitleBar,
@Default(CloseBehavior.close) CloseBehavior closeBehavior,
@Default(SpotubeColor(0xFF2196F3, name: "Blue"))
@JsonKey(
fromJson: UserPreferences._accentColorSchemeFromJson,
toJson: UserPreferences._accentColorSchemeToJson,
readValue: UserPreferences._accentColorSchemeReadValue,
)
SpotubeColor accentColorScheme,
@Default(LayoutMode.adaptive) LayoutMode layoutMode,
@Default(Locale("system", "system"))
@JsonKey(
fromJson: UserPreferences._localeFromJson,
toJson: UserPreferences._localeToJson,
readValue: UserPreferences._localeReadValue,
)
Locale locale,
@Default(Market.US) Market recommendationMarket,
@Default(SearchMode.youtube) SearchMode searchMode,
@Default("") String downloadLocation,
@Default([]) List<String> localLibraryLocation,
@Default("https://pipedapi.kavin.rocks") String pipedInstance,
@Default(ThemeMode.system) ThemeMode themeMode,
@Default(AudioSource.youtube) AudioSource audioSource,
@Default(SourceCodecs.weba) SourceCodecs streamMusicCodec,
@Default(SourceCodecs.m4a) SourceCodecs downloadMusicCodec,
@Default(true) bool discordPresence,
@Default(true) bool endlessPlayback,
@Default(false) bool enableConnect,
}) = _UserPreferences;
factory UserPreferences.fromJson(Map<String, dynamic> json) =>
_$UserPreferencesFromJson(json);
factory UserPreferences.withDefaults() => UserPreferences.fromJson({});
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 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>?;
}
}