Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: let users select the downloads directory #953

Merged
merged 1 commit into from
Oct 14, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions lib/constants.dart
Original file line number Diff line number Diff line change
Expand Up @@ -138,6 +138,7 @@ const kDownloads = 'downloads.json';
const kFeedsWithDownloads = 'feedswithdownloads.json';
const kCoverStore = 'coverStore.json';
const kDirectoryProperty = 'directory';
const kDownloadsCustomDir = 'downloadsCustomDir';
const kRadioUrl = 'de1.api.radio-browser.info';
const kRadioBrowserBaseUrl = 'all.api.radio-browser.info';
const kLastAudio = 'lastAudio';
Expand Down
1 change: 1 addition & 0 deletions lib/extensions/build_context_x.dart
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import '../constants.dart';
extension BuildContextX on BuildContext {
ThemeData get theme => Theme.of(this);
ColorScheme get colorScheme => theme.colorScheme;
TextTheme get textTheme => theme.textTheme;

Size get mediaQuerySize => MediaQuery.sizeOf(this);

Expand Down
3 changes: 3 additions & 0 deletions lib/l10n/app_de.arb
Original file line number Diff line number Diff line change
Expand Up @@ -176,6 +176,9 @@
}
},
"downloadsOnly": "Nur Downloads",
"downloadsDirectory": "Ort der Downloads",
"downloadsDirectoryDescription": "Stell sicher dass MusicPod Zugriff auf diesen Ort hat",
"downloadsChangeWarning": "Das Ändern des Download-Orts löscht alle bisherigen Downloads. Möchtest du fortfahren?",
"moreOptions": "Mehr Optionen",
"noRadioServerFound": "Es wurde kein Radio-Server gefunden",
"connectedTo": "Verbunden mit",
Expand Down
3 changes: 3 additions & 0 deletions lib/l10n/app_en.arb
Original file line number Diff line number Diff line change
Expand Up @@ -176,6 +176,9 @@
}
},
"downloadsOnly": "Downloads only",
"downloadsDirectory": "Location of your downloads",
"downloadsDirectoryDescription": "Make sure MusicPod can access this directory!",
"downloadsChangeWarning": "Changing the downloads directory deletes all current downloads. Do you want to proceed?",
"moreOptions": "More options",
"noRadioServerFound": "No radio server found",
"connectedTo": "Connected to",
Expand Down
2 changes: 0 additions & 2 deletions lib/library/library_model.dart
Original file line number Diff line number Diff line change
Expand Up @@ -173,8 +173,6 @@ class LibraryModel extends SafeChangeNotifier {
void removePodcastUpdate(String feedUrl) =>
_service.removePodcastUpdate(feedUrl);

String? get downloadsDir => _service.downloadsDir;

int get downloadsLength => _service.downloads.length;

String? getDownload(String? url) =>
Expand Down
42 changes: 28 additions & 14 deletions lib/library/library_service.dart
Original file line number Diff line number Diff line change
Expand Up @@ -320,6 +320,17 @@ class LibraryService {
}

void removeDownload({required String url, required String feedUrl}) {
_deleteDownload(url);

if (_downloads.containsKey(url)) {
_downloads.remove(url);
_feedsWithDownloads.remove(feedUrl);

_updateDownloads();
}
}

void _deleteDownload(String url) {
final path = _downloads[url];

if (path != null) {
Expand All @@ -328,20 +339,26 @@ class LibraryService {
file.deleteSync();
}
}
}

if (_downloads.containsKey(url)) {
_downloads.remove(url);
_feedsWithDownloads.remove(feedUrl);
void _updateDownloads() {
writeStringMap(_downloads, kDownloads)
.then(
(_) => writeStringIterable(
iterable: _feedsWithDownloads,
filename: kFeedsWithDownloads,
),
)
.then((_) => _propertiesChangedController.add(true));
}

writeStringMap(_downloads, kDownloads)
.then(
(_) => writeStringIterable(
iterable: _feedsWithDownloads,
filename: kFeedsWithDownloads,
),
)
.then((_) => _propertiesChangedController.add(true));
void removeAllDownloads() {
for (var download in _downloads.entries) {
_deleteDownload(download.key);
}
_downloads.clear();
_feedsWithDownloads.clear();
_updateDownloads();
}

void _removeFeedWithDownload(String feedUrl) {
Expand All @@ -353,8 +370,6 @@ class LibraryService {
).then((_) => _propertiesChangedController.add(true));
}

String? _downloadsDir;
String? get downloadsDir => _downloadsDir;
Map<String, List<Audio>> _podcasts = {};
Map<String, List<Audio>> get podcasts => _podcasts;
int get podcastsLength => _podcasts.length;
Expand Down Expand Up @@ -479,7 +494,6 @@ class LibraryService {
(await readAudioMap(kLikedAudiosFileName)).entries.firstOrNull?.value ??
<Audio>[];

_downloadsDir = await getDownloadsDir();
_downloads = await readStringMap(kDownloads);
_feedsWithDownloads = Set.from(
await readStringIterable(filename: kFeedsWithDownloads) ?? <String>{},
Expand Down
11 changes: 10 additions & 1 deletion lib/main.dart
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ import 'library/library_service.dart';
import 'local_audio/local_audio_model.dart';
import 'local_audio/local_audio_service.dart';
import 'notifications/notifications_service.dart';
import 'persistence_utils.dart';
import 'player/player_model.dart';
import 'player/player_service.dart';
import 'podcasts/download_model.dart';
Expand Down Expand Up @@ -72,11 +73,14 @@ Future<void> main(List<String> args) async {
);
}

final downloadsDefaultDir = await getDownloadsDefaultDir();

registerServicesAndViewModels(
sharedPreferences: sharedPreferences,
args: args,
version: version,
enableDiscord: enableDiscord,
downloadsDefaultDir: downloadsDefaultDir,
);

runApp(
Expand All @@ -87,6 +91,7 @@ Future<void> main(List<String> args) async {
}

void registerServicesAndViewModels({
required String? downloadsDefaultDir,
required SharedPreferences sharedPreferences,
required List<String> args,
required String version,
Expand Down Expand Up @@ -122,7 +127,10 @@ void registerServicesAndViewModels({
dispose: (s) async => s.dispose(),
)
..registerLazySingleton<SettingsService>(
() => SettingsService(sharedPreferences: di<SharedPreferences>()),
() => SettingsService(
sharedPreferences: di<SharedPreferences>(),
downloadsDefaultDir: downloadsDefaultDir,
),
dispose: (s) async => s.dispose(),
)
..registerLazySingleton<LibraryService>(
Expand Down Expand Up @@ -206,6 +214,7 @@ void registerServicesAndViewModels({
)
..registerLazySingleton<DownloadModel>(
() => DownloadModel(
settingsService: di<SettingsService>(),
libraryService: di<LibraryService>(),
dio: di<Dio>(),
),
Expand Down
2 changes: 1 addition & 1 deletion lib/persistence_utils.dart
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@ Future<String?> getMusicDir() async {
return null;
}

Future<String?> getDownloadsDir() async {
Future<String?> getDownloadsDefaultDir() async {
String? path;
if (Platform.isLinux) {
path = getUserDirectory('DOWNLOAD')?.path;
Expand Down
29 changes: 23 additions & 6 deletions lib/podcasts/download_model.dart
Original file line number Diff line number Diff line change
Expand Up @@ -8,15 +8,19 @@ import 'package:safe_change_notifier/safe_change_notifier.dart';
import '../common/data/audio.dart';
import '../l10n/l10n.dart';
import '../library/library_service.dart';
import '../settings/settings_service.dart';

class DownloadModel extends SafeChangeNotifier {
DownloadModel({
required LibraryService libraryService,
required SettingsService settingsService,
required Dio dio,
}) : _service = libraryService,
}) : _libraryService = libraryService,
_settingsService = settingsService,
_dio = dio;

final LibraryService _service;
final LibraryService _libraryService;
final SettingsService _settingsService;
final Dio _dio;

final _values = <String, double?>{};
Expand All @@ -42,9 +46,9 @@ class DownloadModel extends SafeChangeNotifier {
required Audio? audio,
}) async {
if (audio?.url != null &&
_service.downloadsDir != null &&
_settingsService.downloadsDir != null &&
audio?.website != null) {
_service.removeDownload(url: audio!.url!, feedUrl: audio.website!);
_libraryService.removeDownload(url: audio!.url!, feedUrl: audio.website!);
if (_values.containsKey(audio.url)) {
_values.update(audio.url!, (value) => null);
}
Expand All @@ -53,11 +57,20 @@ class DownloadModel extends SafeChangeNotifier {
}
}

Future<void> deleteAllDownloads() async {
if (_settingsService.downloadsDir != null) {
_libraryService.removeAllDownloads();
_values.clear;

notifyListeners();
}
}

Future<void> startDownload({
required BuildContext context,
required Audio? audio,
}) async {
final downloadsDir = _service.downloadsDir;
final downloadsDir = _settingsService.downloadsDir;
if (audio?.url == null || downloadsDir == null) return;
final url = audio!.url!;

Expand Down Expand Up @@ -86,7 +99,11 @@ class DownloadModel extends SafeChangeNotifier {
name: audio.title ?? '',
).then((response) {
if (response?.statusCode == 200 && audio.website != null) {
_service.addDownload(url: url, path: path, feedUrl: audio.website!);
_libraryService.addDownload(
url: url,
path: path,
feedUrl: audio.website!,
);
if (context.mounted) {
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(
Expand Down
4 changes: 3 additions & 1 deletion lib/podcasts/view/download_button.dart
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import '../../common/view/progress.dart';
import '../../extensions/build_context_x.dart';
import '../../l10n/l10n.dart';
import '../../library/library_model.dart';
import '../../settings/settings_model.dart';
import '../download_model.dart';

class DownloadButton extends StatelessWidget with WatchItMixin {
Expand All @@ -31,7 +32,8 @@ class DownloadButton extends StatelessWidget with WatchItMixin {
final download = watchPropertyValue(
(LibraryModel m) => m.getDownload(audio?.url) != null,
);
final downloadsDir = watchPropertyValue((LibraryModel m) => m.downloadsDir);
final downloadsDir =
watchPropertyValue((SettingsModel m) => m.downloadsDir);

return Stack(
alignment: Alignment.center,
Expand Down
33 changes: 33 additions & 0 deletions lib/settings/settings_model.dart
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
import 'dart:async';
import 'dart:io';
import 'package:path/path.dart' as p;

import 'package:github/github.dart';
import 'package:safe_change_notifier/safe_change_notifier.dart';
Expand All @@ -23,6 +25,37 @@ class SettingsModel extends SafeChangeNotifier {
String? get directory => _service.directory;
Future<void> setDirectory(String value) async => _service.setDirectory(value);

String? get downloadsDir => _service.downloadsDir;
Future<void> setDownloadsCustomDir({
required Function() onSuccess,
required Function(String e) onFail,
}) async {
String? dirError;
String? directoryPath;

try {
directoryPath = await getPathOfDirectory();
if (directoryPath == null) return;
final maybeDir = Directory(directoryPath);
if (!maybeDir.existsSync()) return;
maybeDir.statSync();
File(p.join(directoryPath, 'test'))
..createSync()
..deleteSync();
} catch (e) {
dirError = e.toString();
}

if (dirError != null) {
onFail(dirError);
} else {
if (directoryPath != null) {
await _service.setDownloadsCustomDir(directoryPath);
onSuccess();
}
}
}

bool get neverShowFailedImports => _service.neverShowFailedImports;
void setNeverShowFailedImports(bool value) =>
_service.setNeverShowFailedImports(value);
Expand Down
16 changes: 14 additions & 2 deletions lib/settings/settings_service.dart
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,13 @@ import '../common/data/close_btn_action.dart';
import '../constants.dart';

class SettingsService {
SettingsService({required SharedPreferences sharedPreferences})
: _preferences = sharedPreferences;
SettingsService({
required String? downloadsDefaultDir,
required SharedPreferences sharedPreferences,
}) : _preferences = sharedPreferences,
_downloadsDefaultDir = downloadsDefaultDir;

final String? _downloadsDefaultDir;
final SharedPreferences _preferences;
final _propertiesChangedController = StreamController<bool>.broadcast();
Stream<bool> get propertiesChanged => _propertiesChangedController.stream;
Expand Down Expand Up @@ -82,6 +86,14 @@ class SettingsService {
});
}

String? get downloadsDir =>
_preferences.getString(kDownloadsCustomDir) ?? _downloadsDefaultDir;
Future<void> setDownloadsCustomDir(String directory) async {
await _preferences.setString(kDownloadsCustomDir, directory).then((saved) {
if (saved) _propertiesChangedController.add(true);
});
}

CloseBtnAction get closeBtnActionIndex =>
_preferences.getString(kCloseBtnAction) == null
? CloseBtnAction.alwaysAsk
Expand Down
Loading