updates
This commit is contained in:
parent
d558aba246
commit
3bd713d667
17 changed files with 1566 additions and 132 deletions
|
|
@ -15,6 +15,12 @@ enum BrowseMode { artists, albums, tracks }
|
|||
/// post-filters to items whose *own* name/title matches the query.
|
||||
enum SearchMode { discovery, standard }
|
||||
|
||||
/// Ordering applied to the Albums browse grid (filtered client-side).
|
||||
enum AlbumSort { nameAsc, artistAsc, yearDesc, yearAsc, recentlyAdded }
|
||||
|
||||
/// Ordering applied to the Tracks browse list (filtered client-side).
|
||||
enum TrackSort { titleAsc, artistAsc, albumAsc, yearDesc, recentlyAdded }
|
||||
|
||||
/// A selectable static accent color offered by the theme override (TODO #1).
|
||||
class AccentChoice {
|
||||
const AccentChoice(this.name, this.color);
|
||||
|
|
@ -33,10 +39,13 @@ class AppSettings {
|
|||
this.streamMaxBitRate = 0,
|
||||
this.downloadMaxBitRate = 0,
|
||||
this.downloadFormat,
|
||||
this.maxConcurrentDownloads = defaultConcurrentDownloads,
|
||||
this.useStaticAccent = false,
|
||||
this.staticAccentColor = _defaultStaticAccent,
|
||||
this.defaultBrowseMode = BrowseMode.artists,
|
||||
this.searchMode = SearchMode.discovery,
|
||||
this.albumSort = AlbumSort.nameAsc,
|
||||
this.trackSort = TrackSort.titleAsc,
|
||||
this.nowPlayingCassette = false,
|
||||
});
|
||||
|
||||
|
|
@ -50,6 +59,11 @@ class AppSettings {
|
|||
/// the original file / let the server decide.
|
||||
final String? downloadFormat;
|
||||
|
||||
/// How many tracks may download at once. Re-read live by the download pump
|
||||
/// (see `downloads/download_manager.dart`) so changes apply mid-session.
|
||||
/// Clamped to [[minConcurrentDownloads], [maxConcurrentDownloadsCap]].
|
||||
final int maxConcurrentDownloads;
|
||||
|
||||
/// When true, ignore album-art-derived accent and use [staticAccentColor]
|
||||
/// as the sole accent color. When false (default), the accent tracks the
|
||||
/// currently-playing album art.
|
||||
|
|
@ -65,6 +79,11 @@ class AppSettings {
|
|||
/// Which search matching strategy to apply globally.
|
||||
final SearchMode searchMode;
|
||||
|
||||
/// Persisted sort order for the Albums / Tracks browse views. (Filters —
|
||||
/// genre/year — are session-only and live in `state/providers.dart`.)
|
||||
final AlbumSort albumSort;
|
||||
final TrackSort trackSort;
|
||||
|
||||
/// When true, the Now Playing "art" view shows the animated cassette (cover
|
||||
/// art on the label, reels driven by playback) instead of the plain square
|
||||
/// album cover.
|
||||
|
|
@ -76,6 +95,16 @@ class AppSettings {
|
|||
/// Offered download containers; null renders as "Original".
|
||||
static const List<String?> formatChoices = [null, 'mp3', 'opus', 'aac'];
|
||||
|
||||
/// Bounds and default for [maxConcurrentDownloads].
|
||||
static const int minConcurrentDownloads = 1;
|
||||
static const int maxConcurrentDownloadsCap = 10;
|
||||
static const int defaultConcurrentDownloads = 3;
|
||||
|
||||
/// Clamp any value into the allowed concurrent-download range.
|
||||
static int clampConcurrentDownloads(int v) => v < minConcurrentDownloads
|
||||
? minConcurrentDownloads
|
||||
: (v > maxConcurrentDownloadsCap ? maxConcurrentDownloadsCap : v);
|
||||
|
||||
/// Static accent palette offered when the override is enabled (TODO #1).
|
||||
static const List<AccentChoice> accentChoices = [
|
||||
AccentChoice('Red', Color(0xFFDF3535)),
|
||||
|
|
@ -100,16 +129,33 @@ class AppSettings {
|
|||
SearchMode.standard => 'Standard',
|
||||
SearchMode.discovery => 'Discovery',
|
||||
};
|
||||
static String albumSortLabel(AlbumSort s) => switch (s) {
|
||||
AlbumSort.nameAsc => 'Name',
|
||||
AlbumSort.artistAsc => 'Artist',
|
||||
AlbumSort.yearDesc => 'Year (newest)',
|
||||
AlbumSort.yearAsc => 'Year (oldest)',
|
||||
AlbumSort.recentlyAdded => 'Recently added',
|
||||
};
|
||||
static String trackSortLabel(TrackSort s) => switch (s) {
|
||||
TrackSort.titleAsc => 'Title',
|
||||
TrackSort.artistAsc => 'Artist',
|
||||
TrackSort.albumAsc => 'Album',
|
||||
TrackSort.yearDesc => 'Year (newest)',
|
||||
TrackSort.recentlyAdded => 'Recently added',
|
||||
};
|
||||
|
||||
AppSettings copyWith({
|
||||
int? streamMaxBitRate,
|
||||
int? downloadMaxBitRate,
|
||||
// Sentinel so an explicit null (→ original) is distinguishable from "unset".
|
||||
Object? downloadFormat = _unset,
|
||||
int? maxConcurrentDownloads,
|
||||
bool? useStaticAccent,
|
||||
Color? staticAccentColor,
|
||||
BrowseMode? defaultBrowseMode,
|
||||
SearchMode? searchMode,
|
||||
AlbumSort? albumSort,
|
||||
TrackSort? trackSort,
|
||||
bool? nowPlayingCassette,
|
||||
}) =>
|
||||
AppSettings(
|
||||
|
|
@ -118,10 +164,14 @@ class AppSettings {
|
|||
downloadFormat: identical(downloadFormat, _unset)
|
||||
? this.downloadFormat
|
||||
: downloadFormat as String?,
|
||||
maxConcurrentDownloads:
|
||||
maxConcurrentDownloads ?? this.maxConcurrentDownloads,
|
||||
useStaticAccent: useStaticAccent ?? this.useStaticAccent,
|
||||
staticAccentColor: staticAccentColor ?? this.staticAccentColor,
|
||||
defaultBrowseMode: defaultBrowseMode ?? this.defaultBrowseMode,
|
||||
searchMode: searchMode ?? this.searchMode,
|
||||
albumSort: albumSort ?? this.albumSort,
|
||||
trackSort: trackSort ?? this.trackSort,
|
||||
nowPlayingCassette: nowPlayingCassette ?? this.nowPlayingCassette,
|
||||
);
|
||||
|
||||
|
|
@ -131,10 +181,13 @@ class AppSettings {
|
|||
'streamMaxBitRate': streamMaxBitRate,
|
||||
'downloadMaxBitRate': downloadMaxBitRate,
|
||||
if (downloadFormat != null) 'downloadFormat': downloadFormat,
|
||||
'maxConcurrentDownloads': maxConcurrentDownloads,
|
||||
'useStaticAccent': useStaticAccent,
|
||||
'staticAccentColor': _hexOf(staticAccentColor),
|
||||
'defaultBrowseMode': defaultBrowseMode.name,
|
||||
'searchMode': searchMode.name,
|
||||
'albumSort': albumSort.name,
|
||||
'trackSort': trackSort.name,
|
||||
'nowPlayingCassette': nowPlayingCassette,
|
||||
};
|
||||
|
||||
|
|
@ -142,6 +195,9 @@ class AppSettings {
|
|||
streamMaxBitRate: (j['streamMaxBitRate'] as num?)?.toInt() ?? 0,
|
||||
downloadMaxBitRate: (j['downloadMaxBitRate'] as num?)?.toInt() ?? 0,
|
||||
downloadFormat: j['downloadFormat'] as String?,
|
||||
maxConcurrentDownloads: clampConcurrentDownloads(
|
||||
(j['maxConcurrentDownloads'] as num?)?.toInt() ??
|
||||
defaultConcurrentDownloads),
|
||||
useStaticAccent: j['useStaticAccent'] as bool? ?? false,
|
||||
staticAccentColor:
|
||||
_colorOf(j['staticAccentColor'] as String?) ?? _defaultStaticAccent,
|
||||
|
|
@ -151,6 +207,10 @@ class AppSettings {
|
|||
searchMode:
|
||||
_enumByName(SearchMode.values, j['searchMode'] as String?) ??
|
||||
SearchMode.discovery,
|
||||
albumSort: _enumByName(AlbumSort.values, j['albumSort'] as String?) ??
|
||||
AlbumSort.nameAsc,
|
||||
trackSort: _enumByName(TrackSort.values, j['trackSort'] as String?) ??
|
||||
TrackSort.titleAsc,
|
||||
nowPlayingCassette: j['nowPlayingCassette'] as bool? ?? false,
|
||||
);
|
||||
|
||||
|
|
@ -214,6 +274,13 @@ class SettingsController extends StateNotifier<AppSettings> {
|
|||
_persist();
|
||||
}
|
||||
|
||||
void setMaxConcurrentDownloads(int count) {
|
||||
state = state.copyWith(
|
||||
maxConcurrentDownloads:
|
||||
AppSettings.clampConcurrentDownloads(count));
|
||||
_persist();
|
||||
}
|
||||
|
||||
void setUseStaticAccent(bool value) {
|
||||
state = state.copyWith(useStaticAccent: value);
|
||||
_persist();
|
||||
|
|
@ -234,6 +301,16 @@ class SettingsController extends StateNotifier<AppSettings> {
|
|||
_persist();
|
||||
}
|
||||
|
||||
void setAlbumSort(AlbumSort sort) {
|
||||
state = state.copyWith(albumSort: sort);
|
||||
_persist();
|
||||
}
|
||||
|
||||
void setTrackSort(TrackSort sort) {
|
||||
state = state.copyWith(trackSort: sort);
|
||||
_persist();
|
||||
}
|
||||
|
||||
void setNowPlayingCassette(bool value) {
|
||||
state = state.copyWith(nowPlayingCassette: value);
|
||||
_persist();
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue