From 1500fff9ce5c332758a392384b2b03b800d633ee Mon Sep 17 00:00:00 2001 From: Kingkor Roy Tirtho Date: Sat, 4 May 2024 23:00:08 +0600 Subject: [PATCH] feat: add top date based filtering --- lib/components/stats/summary/summary.dart | 20 +++------ lib/components/stats/top/albums.dart | 6 +-- lib/components/stats/top/artists.dart | 5 ++- lib/components/stats/top/top.dart | 49 +++++++++++++++++++++++ lib/components/stats/top/tracks.dart | 5 ++- lib/provider/history/state.dart | 9 +++++ lib/provider/history/top.dart | 37 +++++++++++++++-- 7 files changed, 106 insertions(+), 25 deletions(-) diff --git a/lib/components/stats/summary/summary.dart b/lib/components/stats/summary/summary.dart index 9d735a57..41b4c872 100644 --- a/lib/components/stats/summary/summary.dart +++ b/lib/components/stats/summary/summary.dart @@ -28,20 +28,12 @@ class StatsPageSummarySection extends HookConsumerWidget { childAspectRatio: constrains.isXs ? 1.3 : 1.5, ), delegate: SliverChildListDelegate([ - switch (summary.duration) { - >= const Duration(hours: 1) => SummaryCard( - title: summary.duration.inHours.toDouble(), - unit: "hours", - description: 'Listened to music', - color: Colors.green, - ), - _ => SummaryCard( - title: summary.duration.inMinutes.toDouble(), - unit: "minutes", - description: 'Listened to music', - color: Colors.green, - ), - }, + SummaryCard( + title: summary.duration.inMinutes.toDouble(), + unit: "minutes", + description: 'Listened to music', + color: Colors.green, + ), SummaryCard( title: summary.tracks.toDouble(), unit: "songs", diff --git a/lib/components/stats/top/albums.dart b/lib/components/stats/top/albums.dart index 38d97dc3..8d8d2b5c 100644 --- a/lib/components/stats/top/albums.dart +++ b/lib/components/stats/top/albums.dart @@ -1,5 +1,4 @@ import 'package:flutter/material.dart'; -import 'package:gap/gap.dart'; import 'package:hooks_riverpod/hooks_riverpod.dart'; import 'package:spotube/collections/formatters.dart'; import 'package:spotube/components/album/album_card.dart'; @@ -15,8 +14,9 @@ class TopAlbums extends HookConsumerWidget { @override Widget build(BuildContext context, ref) { - final albums = - ref.watch(playbackHistoryTopProvider.select((value) => value.albums)); + final historyDuration = ref.watch(playbackHistoryTopDurationProvider); + final albums = ref.watch(playbackHistoryTopProvider(historyDuration) + .select((value) => value.albums)); return SliverList.builder( itemCount: albums.length, diff --git a/lib/components/stats/top/artists.dart b/lib/components/stats/top/artists.dart index 8b4941b5..05b5b082 100644 --- a/lib/components/stats/top/artists.dart +++ b/lib/components/stats/top/artists.dart @@ -12,8 +12,9 @@ class TopArtists extends HookConsumerWidget { @override Widget build(BuildContext context, ref) { - final artists = - ref.watch(playbackHistoryTopProvider.select((value) => value.artists)); + final historyDuration = ref.watch(playbackHistoryTopDurationProvider); + final artists = ref.watch(playbackHistoryTopProvider(historyDuration) + .select((value) => value.artists)); return SliverList.builder( itemCount: artists.length, diff --git a/lib/components/stats/top/top.dart b/lib/components/stats/top/top.dart index bb20ed1d..df1275e8 100644 --- a/lib/components/stats/top/top.dart +++ b/lib/components/stats/top/top.dart @@ -5,6 +5,8 @@ import 'package:spotube/components/shared/themed_button_tab_bar.dart'; import 'package:spotube/components/stats/top/albums.dart'; import 'package:spotube/components/stats/top/artists.dart'; import 'package:spotube/components/stats/top/tracks.dart'; +import 'package:spotube/provider/history/state.dart'; +import 'package:spotube/provider/history/top.dart'; class StatsPageTopSection extends HookConsumerWidget { const StatsPageTopSection({super.key}); @@ -12,6 +14,9 @@ class StatsPageTopSection extends HookConsumerWidget { @override Widget build(BuildContext context, ref) { final tabController = useTabController(initialLength: 3); + final historyDuration = ref.watch(playbackHistoryTopDurationProvider); + final historyDurationNotifier = + ref.watch(playbackHistoryTopDurationProvider.notifier); return SliverMainAxisGroup( slivers: [ @@ -41,6 +46,50 @@ class StatsPageTopSection extends HookConsumerWidget { ], ), ), + SliverToBoxAdapter( + child: Align( + alignment: Alignment.centerRight, + child: DropdownButton( + style: Theme.of(context).textTheme.bodySmall!, + isDense: true, + padding: const EdgeInsets.all(4), + borderRadius: BorderRadius.circular(4), + underline: const SizedBox(), + value: historyDuration, + onChanged: (value) { + if (value == null) return; + historyDurationNotifier.update((_) => value); + }, + icon: const Icon(Icons.arrow_drop_down), + items: const [ + DropdownMenuItem( + value: HistoryDuration.days7, + child: Text("This week"), + ), + DropdownMenuItem( + value: HistoryDuration.days30, + child: Text("This month"), + ), + DropdownMenuItem( + value: HistoryDuration.months6, + child: Text("Last 6 months"), + ), + DropdownMenuItem( + value: HistoryDuration.year, + child: Text("This year"), + ), + DropdownMenuItem( + value: HistoryDuration.years2, + child: Text("Last 2 years"), + ), + DropdownMenuItem( + value: HistoryDuration.allTime, + child: Text("All time"), + ), + ], + ), + ), + ), ListenableBuilder( listenable: tabController, builder: (context, _) { diff --git a/lib/components/stats/top/tracks.dart b/lib/components/stats/top/tracks.dart index 3dc88892..26a5df16 100644 --- a/lib/components/stats/top/tracks.dart +++ b/lib/components/stats/top/tracks.dart @@ -13,8 +13,9 @@ class TopTracks extends HookConsumerWidget { @override Widget build(BuildContext context, ref) { - final tracks = - ref.watch(playbackHistoryTopProvider.select((value) => value.tracks)); + final historyDuration = ref.watch(playbackHistoryTopDurationProvider); + final tracks = ref.watch(playbackHistoryTopProvider(historyDuration) + .select((value) => value.tracks)); return SliverList.builder( itemCount: tracks.length, diff --git a/lib/provider/history/state.dart b/lib/provider/history/state.dart index ca2714ac..67658502 100644 --- a/lib/provider/history/state.dart +++ b/lib/provider/history/state.dart @@ -4,6 +4,15 @@ import 'package:spotify/spotify.dart'; part 'state.freezed.dart'; part 'state.g.dart'; +enum HistoryDuration { + allTime, + days7, + days30, + months6, + year, + years2, +} + @freezed class PlaybackHistoryItem with _$PlaybackHistoryItem { factory PlaybackHistoryItem.playlist({ diff --git a/lib/provider/history/top.dart b/lib/provider/history/top.dart index f27a82da..46c86033 100644 --- a/lib/provider/history/top.dart +++ b/lib/provider/history/top.dart @@ -2,12 +2,41 @@ import 'package:collection/collection.dart'; import 'package:hooks_riverpod/hooks_riverpod.dart'; import 'package:spotify/spotify.dart'; import 'package:spotube/provider/history/history.dart'; +import 'package:spotube/provider/history/state.dart'; -final playbackHistoryTopProvider = Provider((ref) { - final (:tracks, :albums, playlists: _) = - ref.watch(playbackHistoryGroupedProvider); +final playbackHistoryTopDurationProvider = + StateProvider((ref) => HistoryDuration.days7); +final playbackHistoryTopProvider = + Provider.family((ref, HistoryDuration durationState) { + final grouped = ref.watch(playbackHistoryGroupedProvider); - final tracksWithCount = groupBy(tracks, (track) => track.track.id!) + final duration = switch (durationState) { + HistoryDuration.allTime => const Duration(days: 365 * 2003), + HistoryDuration.days7 => const Duration(days: 7), + HistoryDuration.days30 => const Duration(days: 30), + HistoryDuration.months6 => const Duration(days: 30 * 6), + HistoryDuration.year => const Duration(days: 365), + HistoryDuration.years2 => const Duration(days: 365 * 2), + }; + final tracks = grouped.tracks + .where( + (item) => item.date.isAfter( + DateTime.now().subtract(duration), + ), + ) + .toList(); + final albums = grouped.albums + .where( + (item) => item.date.isAfter( + DateTime.now().subtract(duration), + ), + ) + .toList(); + + final tracksWithCount = groupBy( + tracks, + (track) => track.track.id!, + ) .entries .map((entry) { return (count: entry.value.length, track: entry.value.first.track);