Files
SpotiFLAC-Mobile/lib/screens/home_tab_import.dart
T

253 lines
7.9 KiB
Dart

part of 'home_tab.dart';
extension _HomeTabCsvImport on _HomeTabState {
Future<void> _importCsv(BuildContext context, WidgetRef ref) async {
if (_isCsvImporting) return;
_setCsvImporting(true);
int currentProgress = 0;
int totalTracks = 0;
bool progressDialogInitialized = false;
bool progressDialogVisible = false;
BuildContext? progressDialogContext;
StateSetter? setDialogState;
void showProgressDialog() {
if (progressDialogInitialized || !mounted) return;
progressDialogInitialized = true;
progressDialogVisible = true;
showDialog<void>(
context: this.context,
useRootNavigator: false,
barrierDismissible: false,
builder: (dialogCtx) => StatefulBuilder(
builder: (dialogCtx, setState) {
progressDialogContext = dialogCtx;
setDialogState = setState;
return AlertDialog(
content: Column(
mainAxisSize: MainAxisSize.min,
children: [
const CircularProgressIndicator(),
const SizedBox(height: 16),
Text(
totalTracks > 0
? context.l10n.progressFetchingMetadata(
currentProgress,
totalTracks,
)
: context.l10n.progressReadingCsv,
),
],
),
);
},
),
).then((_) {
progressDialogVisible = false;
progressDialogContext = null;
});
}
void closeProgressDialog() {
if (!progressDialogVisible) return;
setDialogState = null;
try {
if (progressDialogContext != null) {
Navigator.of(progressDialogContext!).pop();
} else if (mounted) {
final navigator = Navigator.of(this.context);
if (navigator.canPop()) {
navigator.pop();
}
}
} catch (_) {}
progressDialogVisible = false;
progressDialogContext = null;
}
try {
final tracks = await CsvImportService.pickAndParseCsv(
onProgress: (current, total) {
currentProgress = current;
totalTracks = total;
if (!progressDialogInitialized && total > 0) {
showProgressDialog();
}
setDialogState?.call(() {});
},
);
closeProgressDialog();
if (tracks.isNotEmpty) {
final settings = ref.read(settingsProvider);
if (!mounted) return;
final l10n = this.context.l10n;
final options = await showDialog<_CsvImportOptions>(
context: this.context,
useRootNavigator: false,
builder: (dialogCtx) {
var skipDownloaded = true;
return StatefulBuilder(
builder: (dialogCtx, setDialogState) => AlertDialog(
title: Text(l10n.dialogImportPlaylistTitle),
content: Column(
mainAxisSize: MainAxisSize.min,
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(l10n.dialogImportPlaylistMessage(tracks.length)),
const SizedBox(height: 12),
CheckboxListTile(
contentPadding: EdgeInsets.zero,
title: Text(l10n.homeSkipAlreadyDownloaded),
value: skipDownloaded,
onChanged: (value) {
setDialogState(() {
skipDownloaded = value ?? true;
});
},
),
],
),
actions: [
TextButton(
onPressed: () => Navigator.pop(
dialogCtx,
const _CsvImportOptions(
confirmed: false,
skipDownloaded: true,
),
),
child: Text(l10n.dialogCancel),
),
FilledButton(
onPressed: () => Navigator.pop(
dialogCtx,
_CsvImportOptions(
confirmed: true,
skipDownloaded: skipDownloaded,
),
),
child: Text(l10n.dialogImport),
),
],
),
);
},
);
if (options == null || !options.confirmed) return;
var tracksToQueue = tracks;
var skippedDownloadedCount = 0;
if (options.skipDownloaded) {
final historyLookups = tracks
.map(historyLookupForTrack)
.toList(growable: false);
final existingHistoryKeys = await ref.read(
downloadHistoryBatchExistsProvider(
HistoryBatchLookupRequest(historyLookups),
).future,
);
tracksToQueue = [];
for (var i = 0; i < tracks.length; i++) {
final track = tracks[i];
final isDownloaded = existingHistoryKeys.contains(
historyLookups[i].lookupKey,
);
if (isDownloaded) {
skippedDownloadedCount++;
continue;
}
tracksToQueue.add(track);
}
}
if (tracksToQueue.isEmpty) {
if (mounted) {
ScaffoldMessenger.of(this.context).showSnackBar(
SnackBar(
content: Text(
l10n.discographySkippedDownloaded(0, skippedDownloadedCount),
),
),
);
}
return;
}
final queueSnackbarMessage = skippedDownloadedCount > 0
? l10n.discographySkippedDownloaded(
tracksToQueue.length,
skippedDownloadedCount,
)
: l10n.snackbarAddedTracksToQueue(tracksToQueue.length);
if (!mounted) return;
if (settings.askQualityBeforeDownload ||
settings.allowQualityVariants) {
DownloadServicePicker.show(
this.context,
trackName: l10n.csvImportTracks(tracksToQueue.length),
artistName: l10n.dialogImportPlaylistTitle,
onSelect: (quality, service) {
ref
.read(downloadQueueProvider.notifier)
.addMultipleToQueue(
tracksToQueue,
service,
qualityOverride: quality,
);
if (mounted) {
ScaffoldMessenger.of(this.context).showSnackBar(
SnackBar(
content: Text(queueSnackbarMessage),
action: buildViewQueueSnackBarAction(this.context),
),
);
}
},
);
} else {
final extensionState = ref.read(extensionProvider);
final service = resolveEffectiveDownloadService(
settings.defaultService,
extensionState,
);
if (service.isEmpty) {
if (mounted) {
ScaffoldMessenger.of(this.context).showSnackBar(
SnackBar(
content: Text(this.context.l10n.extensionsNoDownloadProvider),
),
);
}
return;
}
ref
.read(downloadQueueProvider.notifier)
.addMultipleToQueue(tracksToQueue, service);
if (mounted) {
ScaffoldMessenger.of(this.context).showSnackBar(
SnackBar(
content: Text(queueSnackbarMessage),
action: buildViewQueueSnackBarAction(this.context),
),
);
}
}
}
} finally {
closeProgressDialog();
_setCsvImporting(false);
}
}
}