Skip to content

Commit

Permalink
feat: download filtering chips (all, ongoing, finished)
Browse files Browse the repository at this point in the history
  • Loading branch information
MSOB7YY committed Nov 20, 2023
1 parent 9e9cff0 commit a97b315
Show file tree
Hide file tree
Showing 4 changed files with 221 additions and 56 deletions.
3 changes: 3 additions & 0 deletions lib/youtube/controller/youtube_controller.dart
Original file line number Diff line number Diff line change
Expand Up @@ -114,6 +114,8 @@ class YoutubeController {
/// {groupName: {filename: YoutubeItemDownloadConfig}}
final youtubeDownloadTasksMap = <String, Map<String, YoutubeItemDownloadConfig>>{}.obs;

final youtubeDownloadTasksTempList = <(String, YoutubeItemDownloadConfig)>[];

/// Used to keep track of existing downloaded files, more performant than real-time checking.
///
/// {groupName: {filename: File}}
Expand Down Expand Up @@ -703,6 +705,7 @@ class YoutubeController {
_downloadClientsMap[groupName]?[c.filename]?.close(force: true);
_downloadClientsMap[groupName]?.remove(c.filename);
youtubeDownloadTasksMap[groupName]?.remove(c.filename);
print('KKKKKKKK ${File("$directory/${c.filename}").existsSync()}');
await File("$directory/${c.filename}").deleteIfExists();
downloadedFilesMap[groupName]?[c.filename] = null;
});
Expand Down
4 changes: 3 additions & 1 deletion lib/youtube/pages/youtube_home_view.dart
Original file line number Diff line number Diff line change
Expand Up @@ -4,14 +4,15 @@ import 'package:namida/core/dimensions.dart';
import 'package:namida/core/translations/language.dart';
import 'package:namida/ui/widgets/custom_widgets.dart';
import 'package:namida/youtube/pages/youtube_page.dart';
import 'package:namida/youtube/pages/yt_downloads_page.dart';
import 'package:namida/youtube/youtube_playlists_view.dart';

class YouTubeHomeView extends StatelessWidget {
const YouTubeHomeView({super.key});

@override
Widget build(BuildContext context) {
final tabs = [lang.HOME, lang.PLAYLISTS];
final tabs = [lang.HOME, lang.PLAYLISTS, lang.DOWNLOADS];
const historyIndex = 1;
return BackgroundWrapper(
child: NamidaTabView(
Expand All @@ -21,6 +22,7 @@ class YouTubeHomeView extends StatelessWidget {
children: const [
YoutubePage(),
YoutubePlaylistsView(bottomPadding: kBottomPadding, scrollable: false),
YTDownloadsPage(),
],
),
);
Expand Down
268 changes: 214 additions & 54 deletions lib/youtube/pages/yt_downloads_page.dart
Original file line number Diff line number Diff line change
Expand Up @@ -2,86 +2,246 @@ import 'package:flutter/material.dart';
import 'package:flutter_scrollbar_modified/flutter_scrollbar_modified.dart';
import 'package:get/get.dart';

import 'package:namida/controller/current_color.dart';
import 'package:namida/core/dimensions.dart';
import 'package:namida/core/extensions.dart';
import 'package:namida/core/icon_fonts/broken_icons.dart';
import 'package:namida/core/translations/language.dart';
import 'package:namida/ui/widgets/custom_widgets.dart';
import 'package:namida/youtube/controller/youtube_controller.dart';
import 'package:namida/youtube/widgets/yt_download_task_item_card.dart';

final _isOnGoingSelected = Rxn<bool>();

class YTDownloadsPage extends StatelessWidget {
const YTDownloadsPage({super.key});

Widget _getFilterChip({
required BuildContext context,
required String title,
required IconData icon,
required void Function() onTap,
required bool? isOnGoing,
}) {
return Obx(
() {
final enabled = isOnGoing == _isOnGoingSelected.value;
final color = enabled ? Colors.white.withOpacity(0.7) : null;
return NamidaInkWell(
bgColor: enabled ? CurrentColor.inst.color : context.theme.cardColor,
borderRadius: 6.0,
margin: const EdgeInsets.symmetric(horizontal: 4.0, vertical: 4.0),
padding: const EdgeInsets.symmetric(horizontal: 8.0, vertical: 4.0),
animationDurationMS: 300,
onTap: onTap,
child: Row(
mainAxisSize: MainAxisSize.min,
children: [
Icon(icon, size: 18.0, color: color),
const SizedBox(width: 4.0),
Text(
title,
style: context.textTheme.displayMedium?.copyWith(color: color),
),
],
),
);
},
);
}

void _updateTempList(bool? forIsGoing) {
final itemsList = YoutubeController.inst.youtubeDownloadTasksTempList;
itemsList.clear();
if (forIsGoing == null) return;

// -- separate same functions bcz dont wanna check in each loop.
// -- reverseLoop to insert newer first.
if (forIsGoing) {
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));
});
});
} 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));
});
});
}
}

@override
Widget build(BuildContext context) {
return BackgroundWrapper(
child: Obx(() {
final keys = YoutubeController.inst.youtubeDownloadTasksMap.keys.toList();
return CupertinoScrollbar(
child: CustomScrollView(
slivers: [
SliverList.builder(
itemCount: keys.length,
itemBuilder: (context, index) {
final groupName = keys[index];
final list = YoutubeController.inst.youtubeDownloadTasksMap[groupName]?.values.toList() ?? [];
return NamidaExpansionTile(
initiallyExpanded: true,
titleText: groupName,
trailing: Row(
mainAxisSize: MainAxisSize.min,
child: Column(
children: [
Padding(
padding: const EdgeInsets.all(4.0),
child: Wrap(
children: [
_getFilterChip(
context: context,
title: lang.ALL,
icon: Broken.task,
onTap: () {
_updateTempList(null);
_isOnGoingSelected.value = null;
},
isOnGoing: null,
),
_getFilterChip(
context: context,
title: lang.ONGOING,
icon: Broken.import,
onTap: () {
_updateTempList(true);
_isOnGoingSelected.value = true;
},
isOnGoing: true,
),
_getFilterChip(
context: context,
title: lang.FINISHED,
icon: Broken.tick_circle,
onTap: () {
_updateTempList(false);
_isOnGoingSelected.value = false;
},
isOnGoing: false,
),
],
),
),
Obx(
() => _isOnGoingSelected.value != null
? Padding(
padding: const EdgeInsets.only(bottom: 6.0),
child: Row(
children: [
const SizedBox(width: 24.0),
Text(
YoutubeController.inst.youtubeDownloadTasksTempList.length.displayVideoKeyword,
style: context.textTheme.displayMedium?.copyWith(fontSize: 20.0.multipliedFontScale),
),
const Spacer(),
IconButton.filledTonal(
padding: EdgeInsets.zero,
visualDensity: VisualDensity.compact,
onPressed: () {
YoutubeController.inst.resumeDownloadTasks(groupName: groupName);
YoutubeController.inst.youtubeDownloadTasksTempList.loop((e, index) {
YoutubeController.inst.resumeDownloadTasks(groupName: e.$1);
});
},
icon: const Icon(Broken.play, size: 18.0),
icon: const Icon(Broken.play, size: 20.0),
),
IconButton.filledTonal(
padding: EdgeInsets.zero,
visualDensity: VisualDensity.compact,
onPressed: () {
YoutubeController.inst.pauseDownloadTask(
itemsConfig: [],
groupName: groupName,
allInGroupName: true,
);
YoutubeController.inst.youtubeDownloadTasksTempList.loop((e, index) {
YoutubeController.inst.pauseDownloadTask(
itemsConfig: [],
groupName: e.$1,
allInGroupName: true,
);
});
},
icon: const Icon(Broken.pause, size: 18.0),
icon: const Icon(Broken.pause, size: 20.0),
),
const SizedBox(width: 4.0),
const Icon(
Broken.arrow_down_2,
size: 20.0,
),
const SizedBox(width: 4.0),
const SizedBox(width: 12.0),
],
),
leading: NamidaInkWell(
borderRadius: 8.0,
padding: const EdgeInsets.symmetric(horizontal: 16.0, vertical: 8.0),
bgColor: context.theme.cardColor,
child: Text(
"${list.length}",
style: context.textTheme.displayLarge,
),
),
children: list
.asMap()
.keys
.map(
(key) => YTDownloadTaskItemCard(videos: list, index: key, groupName: groupName),
)
.toList(),
);
},
),
const SliverPadding(padding: EdgeInsets.only(bottom: kBottomPadding)),
],
)
: const SizedBox(),
),
);
}),
Expanded(
child: Obx(() {
final keys = YoutubeController.inst.youtubeDownloadTasksMap.keys.toList();
return CupertinoScrollbar(
child: CustomScrollView(
slivers: [
_isOnGoingSelected.value == null
? SliverList.builder(
itemCount: keys.length,
itemBuilder: (context, index) {
final groupName = keys[index];
final list = YoutubeController.inst.youtubeDownloadTasksMap[groupName]?.values.toList() ?? [];
return NamidaExpansionTile(
initiallyExpanded: true,
titleText: groupName,
trailing: Row(
mainAxisSize: MainAxisSize.min,
children: [
IconButton.filledTonal(
padding: EdgeInsets.zero,
visualDensity: VisualDensity.compact,
onPressed: () {
YoutubeController.inst.resumeDownloadTasks(groupName: groupName);
},
icon: const Icon(Broken.play, size: 18.0),
),
IconButton.filledTonal(
padding: EdgeInsets.zero,
visualDensity: VisualDensity.compact,
onPressed: () {
YoutubeController.inst.pauseDownloadTask(
itemsConfig: [],
groupName: groupName,
allInGroupName: true,
);
},
icon: const Icon(Broken.pause, size: 18.0),
),
const SizedBox(width: 4.0),
const Icon(
Broken.arrow_down_2,
size: 20.0,
),
const SizedBox(width: 4.0),
],
),
leading: NamidaInkWell(
borderRadius: 8.0,
padding: const EdgeInsets.symmetric(horizontal: 16.0, vertical: 8.0),
bgColor: context.theme.cardColor,
child: Text(
"${list.length}",
style: context.textTheme.displayLarge,
),
),
children: list
.asMap()
.keys
.map(
(key) => YTDownloadTaskItemCard(videos: list, index: key, groupName: groupName),
)
.toList(),
);
},
)
: SliverList.builder(
itemCount: YoutubeController.inst.youtubeDownloadTasksTempList.length,
itemBuilder: (context, index) {
final groupNameAndItem = YoutubeController.inst.youtubeDownloadTasksTempList[index];
return YTDownloadTaskItemCard(
videos: YoutubeController.inst.youtubeDownloadTasksTempList.map((e) => e.$2).toList(),
index: index,
groupName: groupNameAndItem.$1,
);
},
),
const SliverPadding(padding: EdgeInsets.only(bottom: kBottomPadding)),
],
),
);
}),
),
],
),
);
}
}
2 changes: 1 addition & 1 deletion lib/youtube/youtube_playlists_view.dart
Original file line number Diff line number Diff line change
Expand Up @@ -214,7 +214,7 @@ class YoutubePlaylistsView extends StatelessWidget {
() {
YoutubePlaylistController.inst.favouritesPlaylist.value;
return _getHorizontalSliverList(
title: lang.FAVOURITES,
title: lang.LIKED,
icon: Broken.like_1,
viewAllPage: const YTLikedVideosPage(),
videos: getFavouriteVideos,
Expand Down

0 comments on commit a97b315

Please sign in to comment.