feat: add stream money calculation

This commit is contained in:
Kingkor Roy Tirtho 2024-05-09 21:46:40 +06:00
parent 858bbbb20d
commit dcb4c0a018
9 changed files with 37 additions and 9 deletions

View File

@ -1,3 +1,8 @@
import 'package:intl/intl.dart'; import 'package:intl/intl.dart';
final compactNumberFormatter = NumberFormat.compact(); final compactNumberFormatter = NumberFormat.compact();
final usdFormatter = NumberFormat.compactCurrency(
locale: 'en-US',
symbol: r"$",
decimalDigits: 2,
);

View File

@ -1,5 +1,6 @@
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:hooks_riverpod/hooks_riverpod.dart'; import 'package:hooks_riverpod/hooks_riverpod.dart';
import 'package:spotube/collections/formatters.dart';
import 'package:spotube/components/stats/summary/summary_card.dart'; import 'package:spotube/components/stats/summary/summary_card.dart';
import 'package:spotube/extensions/constrains.dart'; import 'package:spotube/extensions/constrains.dart';
import 'package:spotube/provider/history/summary.dart'; import 'package:spotube/provider/history/summary.dart';
@ -32,7 +33,7 @@ class StatsPageSummarySection extends HookConsumerWidget {
title: summary.duration.inMinutes.toDouble(), title: summary.duration.inMinutes.toDouble(),
unit: "minutes", unit: "minutes",
description: 'Listened to music', description: 'Listened to music',
color: Colors.green, color: Colors.purple,
), ),
SummaryCard( SummaryCard(
title: summary.tracks.toDouble(), title: summary.tracks.toDouble(),
@ -40,6 +41,12 @@ class StatsPageSummarySection extends HookConsumerWidget {
description: 'Streamed overall', description: 'Streamed overall',
color: Colors.lightBlue, color: Colors.lightBlue,
), ),
SummaryCard.unformatted(
title: usdFormatter.format(summary.fees.toDouble()),
unit: "",
description: 'Worth of streams',
color: Colors.green,
),
SummaryCard( SummaryCard(
title: summary.artists.toDouble(), title: summary.artists.toDouble(),
unit: "artist's", unit: "artist's",

View File

@ -4,13 +4,21 @@ import 'package:gap/gap.dart';
import 'package:spotube/collections/formatters.dart'; import 'package:spotube/collections/formatters.dart';
class SummaryCard extends StatelessWidget { class SummaryCard extends StatelessWidget {
final double title; final String title;
final String unit; final String unit;
final String description; final String description;
final MaterialColor color; final MaterialColor color;
const SummaryCard({ SummaryCard({
super.key,
required double title,
required this.unit,
required this.description,
required this.color,
}) : title = compactNumberFormatter.format(title);
const SummaryCard.unformatted({
super.key, super.key,
required this.title, required this.title,
required this.unit, required this.unit,
@ -35,7 +43,7 @@ class SummaryCard extends StatelessWidget {
TextSpan( TextSpan(
children: [ children: [
TextSpan( TextSpan(
text: compactNumberFormatter.format(title), text: title,
style: textTheme.headlineLarge?.copyWith( style: textTheme.headlineLarge?.copyWith(
color: color.shade900, color: color.shade900,
), ),

View File

@ -5,7 +5,6 @@ import 'dart:convert';
import 'package:freezed_annotation/freezed_annotation.dart'; import 'package:freezed_annotation/freezed_annotation.dart';
import 'package:spotify/spotify.dart'; import 'package:spotify/spotify.dart';
import 'package:spotube/extensions/track.dart';
import 'package:spotube/provider/proxy_playlist/proxy_playlist.dart'; import 'package:spotube/provider/proxy_playlist/proxy_playlist.dart';
import 'package:spotube/services/audio_player/loop_mode.dart'; import 'package:spotube/services/audio_player/loop_mode.dart';

View File

@ -1,6 +1,5 @@
import 'package:flutter_riverpod/flutter_riverpod.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:spotify/spotify.dart'; import 'package:spotify/spotify.dart';
import 'package:spotube/extensions/track.dart';
import 'package:spotube/services/sourced_track/sourced_track.dart'; import 'package:spotube/services/sourced_track/sourced_track.dart';
class CurrentPlaylist { class CurrentPlaylist {

View File

@ -82,7 +82,7 @@ final connectServerProvider = FutureProvider((ref) async {
.toJson(), .toJson(),
); );
channel.sink.add( channel.sink.add(
WebSocketShuffleEvent(await audioPlayer.isShuffled).toJson(), WebSocketShuffleEvent(audioPlayer.isShuffled).toJson(),
); );
channel.sink.add( channel.sink.add(
WebSocketLoopEvent(audioPlayer.loopMode).toJson(), WebSocketLoopEvent(audioPlayer.loopMode).toJson(),

View File

@ -1,6 +1,8 @@
import 'package:collection/collection.dart'; import 'package:collection/collection.dart';
import 'package:hooks_riverpod/hooks_riverpod.dart'; import 'package:hooks_riverpod/hooks_riverpod.dart';
import 'package:spotube/provider/history/history.dart'; import 'package:spotube/provider/history/history.dart';
import 'package:spotube/provider/history/state.dart';
import 'package:spotube/provider/history/top.dart';
final playbackHistorySummaryProvider = Provider((ref) { final playbackHistorySummaryProvider = Provider((ref) {
final (:tracks, :albums, :playlists) = final (:tracks, :albums, :playlists) =
@ -43,10 +45,17 @@ final playbackHistorySummaryProvider = Provider((ref) {
) )
.length; .length;
final tracksThisMonth = ref.watch(
playbackHistoryTopProvider(HistoryDuration.days30).select((s) => s.tracks),
);
final streams = tracksThisMonth.fold(0, (acc, el) => acc + el.count);
return ( return (
duration: totalDurationListened, duration: totalDurationListened,
tracks: totalTracksListened, tracks: totalTracksListened,
artists: totalArtistsListened, artists: totalArtistsListened,
fees: streams * 0.005, // Spotify pays $0.003 to $0.005
albums: totalAlbumsListened, albums: totalAlbumsListened,
playlists: totalPlaylistsListened, playlists: totalPlaylistsListened,
); );

View File

@ -6,6 +6,7 @@ import 'package:spotube/provider/history/state.dart';
final playbackHistoryTopDurationProvider = final playbackHistoryTopDurationProvider =
StateProvider((ref) => HistoryDuration.days7); StateProvider((ref) => HistoryDuration.days7);
final playbackHistoryTopProvider = final playbackHistoryTopProvider =
Provider.family((ref, HistoryDuration durationState) { Provider.family((ref, HistoryDuration durationState) {
final grouped = ref.watch(playbackHistoryGroupedProvider); final grouped = ref.watch(playbackHistoryGroupedProvider);

View File

@ -11,7 +11,7 @@ class MobileAudioService extends BaseAudioHandler {
AudioSession? session; AudioSession? session;
final ProxyPlaylistNotifier playlistNotifier; final ProxyPlaylistNotifier playlistNotifier;
// ignore: invalid_use_of_protected_member // ignore: invalid_use_of_protected_member, invalid_use_of_visible_for_testing_member
ProxyPlaylist get playlist => playlistNotifier.state; ProxyPlaylist get playlist => playlistNotifier.state;
MobileAudioService(this.playlistNotifier) { MobileAudioService(this.playlistNotifier) {
@ -135,7 +135,7 @@ class MobileAudioService extends BaseAudioHandler {
playing: audioPlayer.isPlaying, playing: audioPlayer.isPlaying,
updatePosition: position, updatePosition: position,
bufferedPosition: await audioPlayer.bufferedPosition ?? Duration.zero, bufferedPosition: await audioPlayer.bufferedPosition ?? Duration.zero,
shuffleMode: await audioPlayer.isShuffled == true shuffleMode: audioPlayer.isShuffled == true
? AudioServiceShuffleMode.all ? AudioServiceShuffleMode.all
: AudioServiceShuffleMode.none, : AudioServiceShuffleMode.none,
repeatMode: (audioPlayer.loopMode).toAudioServiceRepeatMode(), repeatMode: (audioPlayer.loopMode).toAudioServiceRepeatMode(),