Skip to content

Commit

Permalink
feat: ability to cancel downloads for groups
Browse files Browse the repository at this point in the history
  • Loading branch information
MSOB7YY committed Nov 24, 2023
1 parent 4eb90dc commit f7a3792
Show file tree
Hide file tree
Showing 2 changed files with 159 additions and 44 deletions.
120 changes: 107 additions & 13 deletions lib/youtube/pages/yt_downloads_page.dart
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import 'package:flutter_scrollbar_modified/flutter_scrollbar_modified.dart';
import 'package:get/get.dart';

import 'package:namida/controller/current_color.dart';
import 'package:namida/controller/navigator_controller.dart';
import 'package:namida/core/dimensions.dart';
import 'package:namida/core/extensions.dart';
import 'package:namida/core/icon_fonts/broken_icons.dart';
Expand Down Expand Up @@ -62,22 +63,79 @@ class YTDownloadsPage extends StatelessWidget {
final smallList = YoutubeController.inst.youtubeDownloadTasksMap[key]?.values.toList();
smallList?.reverseLoop((v, index) {
final match = YoutubeController.inst.downloadedFilesMap[key]?[v.filename] == null;
if (match) itemsList.add((key, v));
final isDownloadingOrFetching = (YoutubeController.inst.isDownloading[v.id]?[v.filename] ?? false) || (YoutubeController.inst.isFetchingData[v.id]?[v.filename] ?? false);
if (match || isDownloadingOrFetching) itemsList.add((key, v));
});
});
} else {
YoutubeController.inst.youtubeDownloadTasksMap.keys.toList().reverseLoop((key, index) {
final smallList = YoutubeController.inst.youtubeDownloadTasksMap[key]?.values.toList();
smallList?.reverseLoop((v, index) {
final match = YoutubeController.inst.downloadedFilesMap[key]?[v.filename] != null;
if (match) itemsList.add((key, v));
final isDownloadingOrFetching = (YoutubeController.inst.isDownloading[v.id]?[v.filename] ?? false) || (YoutubeController.inst.isFetchingData[v.id]?[v.filename] ?? false);
if (match && !isDownloadingOrFetching) itemsList.add((key, v));
});
});
}
}

Future<bool> _confirmCancelDialog({
required BuildContext context,
String operationTitle = '',
String confirmMessage = '',
String groupTitle = '',
required int itemsLength,
}) async {
bool confirmed = false;

final groupTitleText = groupTitle == '' ? lang.DEFAULT : groupTitle;
await NamidaNavigator.inst.navigateDialog(
dialog: CustomBlurryDialog(
title: lang.WARNING,
normalTitleStyle: true,
isWarning: true,
actions: [
const CancelButton(),
const SizedBox(width: 4.0),
NamidaButton(
text: (confirmMessage != '' ? confirmMessage : lang.CONFIRM).toUpperCase(),
onPressed: () {
confirmed = true;
NamidaNavigator.inst.closeDialog();
},
),
],
child: Padding(
padding: const EdgeInsets.symmetric(horizontal: 6.0),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
const SizedBox(height: 12.0),
RichText(
text: TextSpan(
children: [
TextSpan(text: "$operationTitle: ", style: context.textTheme.displayLarge),
TextSpan(
text: '$groupTitleText ($itemsLength)',
style: context.textTheme.displayMedium,
),
TextSpan(text: " ?", style: context.textTheme.displayLarge),
],
),
),
const SizedBox(height: 12.0),
],
),
),
),
);
return confirmed;
}

@override
Widget build(BuildContext context) {
_updateTempList(_isOnGoingSelected.value); // refresh for when coming back to page.

return BackgroundWrapper(
child: Column(
children: [
Expand Down Expand Up @@ -136,7 +194,7 @@ class YTDownloadsPage extends StatelessWidget {
iconSize: 24.0,
onPressed: () {
YoutubeController.inst.youtubeDownloadTasksTempList.loop((e, index) {
YoutubeController.inst.resumeDownloadTasks(groupName: e.$1);
YoutubeController.inst.resumeDownloadTasks(groupName: e.$1, itemsConfig: [e.$2]);
});
},
),
Expand All @@ -146,13 +204,32 @@ class YTDownloadsPage extends StatelessWidget {
onPressed: () {
YoutubeController.inst.youtubeDownloadTasksTempList.loop((e, index) {
YoutubeController.inst.pauseDownloadTask(
itemsConfig: [],
itemsConfig: [e.$2],
groupName: e.$1,
allInGroupName: true,
);
});
},
),
NamidaIconButton(
icon: Broken.close_circle,
iconSize: 24.0,
onPressed: () async {
final confirmed = await _confirmCancelDialog(
context: context,
operationTitle: lang.CANCEL,
groupTitle: lang.ONGOING,
itemsLength: YoutubeController.inst.youtubeDownloadTasksTempList.length,
);
if (confirmed) {
YoutubeController.inst.youtubeDownloadTasksTempList.loop((e, index) {
YoutubeController.inst.cancelDownloadTask(
itemsConfig: [e.$2],
groupName: e.$1,
);
});
}
},
),
],
const SizedBox(width: 12.0),
],
Expand All @@ -174,7 +251,7 @@ class YTDownloadsPage extends StatelessWidget {
final list = YoutubeController.inst.youtubeDownloadTasksMap[groupName]?.values.toList() ?? [];
return NamidaExpansionTile(
initiallyExpanded: true,
titleText: groupName,
titleText: groupName == '' ? lang.DEFAULT : groupName,
trailing: Row(
mainAxisSize: MainAxisSize.min,
children: [
Expand All @@ -198,6 +275,26 @@ class YTDownloadsPage extends StatelessWidget {
},
icon: const Icon(Broken.pause, size: 18.0),
),
IconButton.filledTonal(
padding: EdgeInsets.zero,
visualDensity: VisualDensity.compact,
onPressed: () async {
final confirmed = await _confirmCancelDialog(
context: context,
operationTitle: lang.CANCEL,
groupTitle: groupName,
itemsLength: list.length,
);
if (confirmed) {
YoutubeController.inst.cancelDownloadTask(
itemsConfig: [],
groupName: groupName,
allInGroupName: true,
);
}
},
icon: const Icon(Broken.close_circle, size: 18.0),
),
const SizedBox(width: 4.0),
const Icon(
Broken.arrow_down_2,
Expand All @@ -215,13 +312,10 @@ class YTDownloadsPage extends StatelessWidget {
style: context.textTheme.displayLarge,
),
),
children: list
.asMap()
.keys
.map(
(key) => YTDownloadTaskItemCard(videos: list, index: key, groupName: groupName),
)
.toList(),
children: List<YTDownloadTaskItemCard>.generate(
list.length,
(index) => YTDownloadTaskItemCard(videos: list, index: index, groupName: groupName),
),
);
},
)
Expand Down
83 changes: 52 additions & 31 deletions lib/youtube/widgets/yt_download_task_item_card.dart
Original file line number Diff line number Diff line change
Expand Up @@ -38,13 +38,15 @@ class YTDownloadTaskItemCard extends StatelessWidget {
required this.index,
required this.groupName,
});

Widget _getChip({
required BuildContext context,
required IconData icon,
required String title,
String betweenBrackets = '',
bool displayTitle = false,
void Function()? onTap,
Widget? Function(double size)? iconWidget,
}) {
final textWidget = RichText(
text: TextSpan(
Expand All @@ -58,6 +60,7 @@ class YTDownloadTaskItemCard extends StatelessWidget {
],
),
);
final iconSize = displayTitle ? 16.0 : 17.0;
return NamidaInkWell(
borderRadius: 6.0,
padding: const EdgeInsets.only(left: 6.0, right: 6.0, top: 6.0, bottom: 6.0),
Expand All @@ -67,7 +70,7 @@ class YTDownloadTaskItemCard extends StatelessWidget {
child: Row(
mainAxisSize: MainAxisSize.min,
children: [
Icon(icon, size: displayTitle ? 16.0 : 17.0),
iconWidget?.call(iconSize) ?? Icon(icon, size: iconSize),
if (displayTitle) ...[
const SizedBox(width: 4.0),
textWidget,
Expand All @@ -78,28 +81,30 @@ class YTDownloadTaskItemCard extends StatelessWidget {
);
}

void _onPauseDownloadTap(List<YoutubeItemDownloadConfig> itemsConfig, bool isDownloading, BuildContext context) {
isDownloading
? YoutubeController.inst.pauseDownloadTask(
itemsConfig: itemsConfig,
groupName: groupName,
)
: YoutubeController.inst.downloadYoutubeVideos(
useCachedVersionsIfAvailable: true,
autoExtractTitleAndArtist: settings.ytAutoExtractVideoTagsFromInfo.value,
keepCachedVersionsIfDownloaded: settings.downloadFilesKeepCachedVersions.value,
downloadFilesWriteUploadDate: settings.downloadFilesWriteUploadDate.value,
itemsConfig: itemsConfig,
groupName: groupName,
onFileDownloaded: (downloadedFile) async {
if (downloadedFile != null) {
build(context);
}
},
onOldFileDeleted: (deletedFile) async {
build(context);
},
);
void _onPauseDownloadTap(List<YoutubeItemDownloadConfig> itemsConfig) {
YoutubeController.inst.pauseDownloadTask(
itemsConfig: itemsConfig,
groupName: groupName,
);
}

void _onResumeDownloadTap(List<YoutubeItemDownloadConfig> itemsConfig, BuildContext context) {
YoutubeController.inst.downloadYoutubeVideos(
useCachedVersionsIfAvailable: true,
autoExtractTitleAndArtist: settings.ytAutoExtractVideoTagsFromInfo.value,
keepCachedVersionsIfDownloaded: settings.downloadFilesKeepCachedVersions.value,
downloadFilesWriteUploadDate: settings.downloadFilesWriteUploadDate.value,
itemsConfig: itemsConfig,
groupName: groupName,
onFileDownloaded: (downloadedFile) async {
if (downloadedFile != null) {
build(context);
}
},
onOldFileDeleted: (deletedFile) async {
build(context);
},
);
}

void _onCancelDeleteDownloadTap(List<YoutubeItemDownloadConfig> itemsConfig) {
Expand Down Expand Up @@ -305,7 +310,7 @@ class YTDownloadTaskItemCard extends StatelessWidget {
const SizedBox(width: 6.0),
Expanded(
child: Text(
texts.where((element) => element != '').join(' • '),
texts.joinText(),
style: context.textTheme.displaySmall?.copyWith(fontSize: 12.0.multipliedFontScale),
),
),
Expand Down Expand Up @@ -420,6 +425,12 @@ class YTDownloadTaskItemCard extends StatelessWidget {
videoYTID: null,
);

final itemIcon = item.videoStream != null
? Broken.video
: item.audioStream != null
? Broken.musicnote
: null;

return NamidaPopupWrapper(
openOnTap: false,
openOnLongPress: true,
Expand Down Expand Up @@ -561,12 +572,15 @@ class YTDownloadTaskItemCard extends StatelessWidget {
Obx(
() {
final isDownloading = YoutubeController.inst.isDownloading[item.id]?[item.filename] ?? false;
return isDownloading
final isFetching = YoutubeController.inst.isFetchingData[item.id]?[item.filename] ?? false;
final willBeDownloaded = YoutubeController.inst.youtubeDownloadTasksInQueueMap[groupName]?[item.filename] == true;
final canPause = isDownloading || isFetching;
return canPause || willBeDownloaded
? _getChip(
context: context,
title: lang.PAUSE,
icon: Broken.pause,
onTap: () => _onPauseDownloadTap([item], isDownloading, context),
onTap: () => _onPauseDownloadTap([item]),
)
: fileExists
? _getChip(
Expand All @@ -579,13 +593,13 @@ class YTDownloadTaskItemCard extends StatelessWidget {
operationTitle: lang.RESTART,
);
// ignore: use_build_context_synchronously
if (confirmed) _onPauseDownloadTap([item], isDownloading, context);
if (confirmed) _onResumeDownloadTap([item], context);
})
: _getChip(
context: context,
title: lang.RESUME,
icon: Broken.play,
onTap: () => _onPauseDownloadTap([item], isDownloading, context),
onTap: () => _onResumeDownloadTap([item], context),
);
},
),
Expand Down Expand Up @@ -631,12 +645,19 @@ class YTDownloadTaskItemCard extends StatelessWidget {
const Spacer(),
Text(
[
if (item.videoStream?.resolution != null) item.videoStream?.resolution ?? '',
downloadedFile.fileSizeFormatted() ?? '',
].join(' • '),
item.videoStream?.resolution,
downloadedFile.fileSizeFormatted(),
].joinText(),
style: context.textTheme.displaySmall?.copyWith(fontSize: 11.0.multipliedFontScale),
),
const SizedBox(width: 4.0),
if (itemIcon != null)
Icon(
itemIcon,
size: 16.0,
color: context.defaultIconColor(),
),
const SizedBox(width: 4.0),
fileExists
? Icon(
Broken.tick_circle,
Expand Down

0 comments on commit f7a3792

Please sign in to comment.