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>
This commit is contained in:
Blake Leonard 2024-05-05 15:57:14 -04:00
parent 2b01e4fb4d
commit f423c20063
No known key found for this signature in database
GPG Key ID: 3B1965C22D07D9F6
8 changed files with 163 additions and 4 deletions

View File

@ -71,7 +71,20 @@ final localTracksProvider = FutureProvider<List<LocalTrack>>((ref) async {
await downloadDir.create(recursive: true);
return [];
}
final entities = downloadDir.listSync(recursive: true);
final downloadEntities = downloadDir.listSync(recursive: true);
final localLibraryLocation = ref.watch(
userPreferencesProvider.select((s) => s.localLibraryLocation),
);
if (localLibraryLocation.isEmpty) return [];
final localLibraryDir = Directory(localLibraryLocation);
if (!await localLibraryDir.exists()) {
await localLibraryDir.create(recursive: true);
return [];
}
final localLibraryEntities = localLibraryDir.listSync(recursive: true);
final entities = [...downloadEntities, ...localLibraryEntities];
final filesWithMetadata = (await Future.wait(
entities.map((e) => File(e.path)).where((file) {

View File

@ -107,6 +107,7 @@
"always_on_top": "Always on top",
"exit_mini_player": "Exit Mini player",
"download_location": "Download location",
"local_library_location": "Local library location",
"account": "Account",
"login_with_spotify": "Login with your Spotify account",
"connect_with_spotify": "Connect with Spotify",
@ -321,4 +322,4 @@
"connect_client_alert": "You're being controlled by {client}",
"this_device": "This Device",
"remote": "Remote"
}
}

View File

@ -33,6 +33,22 @@ class SettingsDownloadsSection extends HookConsumerWidget {
}
}, [preferences.downloadLocation]);
final pickLocalLibraryLocation = useCallback(() async {
if (DesktopTools.platform.isMobile || DesktopTools.platform.isMacOS) {
final dirStr = await FilePicker.platform.getDirectoryPath(
initialDirectory: preferences.localLibraryLocation,
);
if (dirStr == null) return;
preferencesNotifier.setLocalLibraryLocation(dirStr);
} else {
String? dirStr = await getDirectoryPath(
initialDirectory: preferences.localLibraryLocation,
);
if (dirStr == null) return;
preferencesNotifier.setLocalLibraryLocation(dirStr);
}
}, [preferences.localLibraryLocation]);
return SectionCardWithHeading(
heading: context.l10n.downloads,
children: [
@ -46,6 +62,16 @@ class SettingsDownloadsSection extends HookConsumerWidget {
),
onTap: pickDownloadLocation,
),
ListTile(
leading: const Icon(SpotubeIcons.folder),
title: Text(context.l10n.local_library_location),
subtitle: Text(preferences.localLibraryLocation),
trailing: FilledButton(
onPressed: pickLocalLibraryLocation,
child: const Icon(SpotubeIcons.folder),
),
onTap: pickLocalLibraryLocation,
),
],
);
}

View File

@ -69,6 +69,11 @@ class UserPreferencesNotifier extends PersistedStateNotifier<UserPreferences> {
state = state.copyWith(downloadLocation: downloadDir);
}
void setLocalLibraryLocation(String localLibraryDir) {
if (localLibraryDir.isEmpty) return;
state = state.copyWith(localLibraryLocation: localLibraryDir);
}
void setLayoutMode(LayoutMode mode) {
state = state.copyWith(layoutMode: mode);
}

View File

@ -84,6 +84,7 @@ class UserPreferences with _$UserPreferences {
@Default(Market.US) Market recommendationMarket,
@Default(SearchMode.youtube) SearchMode searchMode,
@Default("") String downloadLocation,
@Default("") String localLibraryLocation,
@Default("https://pipedapi.kavin.rocks") String pipedInstance,
@Default(ThemeMode.system) ThemeMode themeMode,
@Default(AudioSource.youtube) AudioSource audioSource,

View File

@ -43,6 +43,7 @@ mixin _$UserPreferences {
Market get recommendationMarket => throw _privateConstructorUsedError;
SearchMode get searchMode => throw _privateConstructorUsedError;
String get downloadLocation => throw _privateConstructorUsedError;
String get localLibraryLocation => throw _privateConstructorUsedError;
String get pipedInstance => throw _privateConstructorUsedError;
ThemeMode get themeMode => throw _privateConstructorUsedError;
AudioSource get audioSource => throw _privateConstructorUsedError;
@ -88,6 +89,7 @@ abstract class $UserPreferencesCopyWith<$Res> {
Market recommendationMarket,
SearchMode searchMode,
String downloadLocation,
String localLibraryLocation,
String pipedInstance,
ThemeMode themeMode,
AudioSource audioSource,
@ -126,6 +128,7 @@ class _$UserPreferencesCopyWithImpl<$Res, $Val extends UserPreferences>
Object? recommendationMarket = null,
Object? searchMode = null,
Object? downloadLocation = null,
Object? localLibraryLocation = null,
Object? pipedInstance = null,
Object? themeMode = null,
Object? audioSource = null,
@ -196,6 +199,10 @@ class _$UserPreferencesCopyWithImpl<$Res, $Val extends UserPreferences>
? _value.downloadLocation
: downloadLocation // ignore: cast_nullable_to_non_nullable
as String,
localLibraryLocation: null == localLibraryLocation
? _value.localLibraryLocation
: localLibraryLocation // ignore: cast_nullable_to_non_nullable
as String,
pipedInstance: null == pipedInstance
? _value.pipedInstance
: pipedInstance // ignore: cast_nullable_to_non_nullable
@ -264,6 +271,7 @@ abstract class _$$UserPreferencesImplCopyWith<$Res>
Market recommendationMarket,
SearchMode searchMode,
String downloadLocation,
String localLibraryLocation,
String pipedInstance,
ThemeMode themeMode,
AudioSource audioSource,
@ -300,6 +308,7 @@ class __$$UserPreferencesImplCopyWithImpl<$Res>
Object? recommendationMarket = null,
Object? searchMode = null,
Object? downloadLocation = null,
Object? localLibraryLocation = null,
Object? pipedInstance = null,
Object? themeMode = null,
Object? audioSource = null,
@ -370,6 +379,10 @@ class __$$UserPreferencesImplCopyWithImpl<$Res>
? _value.downloadLocation
: downloadLocation // ignore: cast_nullable_to_non_nullable
as String,
localLibraryLocation: null == localLibraryLocation
? _value.localLibraryLocation
: localLibraryLocation // ignore: cast_nullable_to_non_nullable
as String,
pipedInstance: null == pipedInstance
? _value.pipedInstance
: pipedInstance // ignore: cast_nullable_to_non_nullable
@ -433,6 +446,7 @@ class _$UserPreferencesImpl implements _UserPreferences {
this.recommendationMarket = Market.US,
this.searchMode = SearchMode.youtube,
this.downloadLocation = "",
this.localLibraryLocation = "",
this.pipedInstance = "https://pipedapi.kavin.rocks",
this.themeMode = ThemeMode.system,
this.audioSource = AudioSource.youtube,
@ -498,6 +512,9 @@ class _$UserPreferencesImpl implements _UserPreferences {
final String downloadLocation;
@override
@JsonKey()
final String localLibraryLocation;
@override
@JsonKey()
final String pipedInstance;
@override
@JsonKey()
@ -523,7 +540,7 @@ class _$UserPreferencesImpl implements _UserPreferences {
@override
String toString() {
return 'UserPreferences(audioQuality: $audioQuality, albumColorSync: $albumColorSync, amoledDarkTheme: $amoledDarkTheme, checkUpdate: $checkUpdate, normalizeAudio: $normalizeAudio, showSystemTrayIcon: $showSystemTrayIcon, skipNonMusic: $skipNonMusic, systemTitleBar: $systemTitleBar, closeBehavior: $closeBehavior, accentColorScheme: $accentColorScheme, layoutMode: $layoutMode, locale: $locale, recommendationMarket: $recommendationMarket, searchMode: $searchMode, downloadLocation: $downloadLocation, pipedInstance: $pipedInstance, themeMode: $themeMode, audioSource: $audioSource, streamMusicCodec: $streamMusicCodec, downloadMusicCodec: $downloadMusicCodec, discordPresence: $discordPresence, endlessPlayback: $endlessPlayback, enableConnect: $enableConnect)';
return 'UserPreferences(audioQuality: $audioQuality, albumColorSync: $albumColorSync, amoledDarkTheme: $amoledDarkTheme, checkUpdate: $checkUpdate, normalizeAudio: $normalizeAudio, showSystemTrayIcon: $showSystemTrayIcon, skipNonMusic: $skipNonMusic, systemTitleBar: $systemTitleBar, closeBehavior: $closeBehavior, accentColorScheme: $accentColorScheme, layoutMode: $layoutMode, locale: $locale, recommendationMarket: $recommendationMarket, searchMode: $searchMode, downloadLocation: $downloadLocation, localLibraryLocation: $localLibraryLocation, pipedInstance: $pipedInstance, themeMode: $themeMode, audioSource: $audioSource, streamMusicCodec: $streamMusicCodec, downloadMusicCodec: $downloadMusicCodec, discordPresence: $discordPresence, endlessPlayback: $endlessPlayback, enableConnect: $enableConnect)';
}
@override
@ -560,6 +577,8 @@ class _$UserPreferencesImpl implements _UserPreferences {
other.searchMode == searchMode) &&
(identical(other.downloadLocation, downloadLocation) ||
other.downloadLocation == downloadLocation) &&
(identical(other.localLibraryLocation, localLibraryLocation) ||
other.localLibraryLocation == localLibraryLocation) &&
(identical(other.pipedInstance, pipedInstance) ||
other.pipedInstance == pipedInstance) &&
(identical(other.themeMode, themeMode) ||
@ -597,6 +616,7 @@ class _$UserPreferencesImpl implements _UserPreferences {
recommendationMarket,
searchMode,
downloadLocation,
localLibraryLocation,
pipedInstance,
themeMode,
audioSource,
@ -647,6 +667,7 @@ abstract class _UserPreferences implements UserPreferences {
final Market recommendationMarket,
final SearchMode searchMode,
final String downloadLocation,
final String localLibraryLocation,
final String pipedInstance,
final ThemeMode themeMode,
final AudioSource audioSource,
@ -698,6 +719,8 @@ abstract class _UserPreferences implements UserPreferences {
@override
String get downloadLocation;
@override
String get localLibraryLocation;
@override
String get pipedInstance;
@override
ThemeMode get themeMode;

View File

@ -44,6 +44,7 @@ _$UserPreferencesImpl _$$UserPreferencesImplFromJson(
$enumDecodeNullable(_$SearchModeEnumMap, json['searchMode']) ??
SearchMode.youtube,
downloadLocation: json['downloadLocation'] as String? ?? "",
localLibraryLocation: json['localLibraryLocation'] as String? ?? "",
pipedInstance:
json['pipedInstance'] as String? ?? "https://pipedapi.kavin.rocks",
themeMode: $enumDecodeNullable(_$ThemeModeEnumMap, json['themeMode']) ??
@ -81,6 +82,7 @@ Map<String, dynamic> _$$UserPreferencesImplToJson(
'recommendationMarket': _$MarketEnumMap[instance.recommendationMarket]!,
'searchMode': _$SearchModeEnumMap[instance.searchMode]!,
'downloadLocation': instance.downloadLocation,
'localLibraryLocation': instance.localLibraryLocation,
'pipedInstance': instance.pipedInstance,
'themeMode': _$ThemeModeEnumMap[instance.themeMode]!,
'audioSource': _$AudioSourceEnumMap[instance.audioSource]!,

View File

@ -1 +1,89 @@
{}
{
"ar": [
"local_library_location"
],
"bn": [
"local_library_location"
],
"ca": [
"local_library_location"
],
"cs": [
"local_library_location"
],
"de": [
"local_library_location"
],
"es": [
"local_library_location"
],
"fa": [
"local_library_location"
],
"fr": [
"local_library_location"
],
"hi": [
"local_library_location"
],
"it": [
"local_library_location"
],
"ja": [
"local_library_location"
],
"ko": [
"local_library_location"
],
"ne": [
"local_library_location"
],
"nl": [
"local_library_location"
],
"pl": [
"local_library_location"
],
"pt": [
"local_library_location"
],
"ru": [
"local_library_location"
],
"th": [
"local_library_location"
],
"tr": [
"local_library_location"
],
"uk": [
"local_library_location"
],
"vi": [
"local_library_location"
],
"zh": [
"local_library_location"
]
}