Skip to content

Commit

Permalink
feat: player details dialog and separate location of lyrics button in…
Browse files Browse the repository at this point in the history
… player page
  • Loading branch information
KRTirtho committed Jun 15, 2023
1 parent 3b56c78 commit ce38233
Show file tree
Hide file tree
Showing 12 changed files with 314 additions and 59 deletions.
5 changes: 5 additions & 0 deletions lib/components/player/player_track_details.dart
Original file line number Diff line number Diff line change
@@ -1,11 +1,13 @@
import 'package:flutter/material.dart';
import 'package:go_router/go_router.dart';
import 'package:hooks_riverpod/hooks_riverpod.dart';
import 'package:spotify/spotify.dart';

import 'package:spotube/collections/assets.gen.dart';
import 'package:spotube/components/shared/image/universal_image.dart';
import 'package:spotube/extensions/constrains.dart';
import 'package:spotube/provider/proxy_playlist/proxy_playlist_provider.dart';
import 'package:spotube/utils/service_utils.dart';
import 'package:spotube/utils/type_conversion_utils.dart';

class PlayerTrackDetails extends HookConsumerWidget {
Expand Down Expand Up @@ -72,6 +74,9 @@ class PlayerTrackDetails extends HookConsumerWidget {
),
TypeConversionUtils.artists_X_ClickableArtists(
playback.activeTrack?.artists ?? [],
onRouteChange: (route) {
ServiceUtils.push(context, route);
},
)
],
),
Expand Down
1 change: 0 additions & 1 deletion lib/components/root/bottom_player.dart
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,6 @@ import 'package:flutter/material.dart';
import 'package:spotube/provider/proxy_playlist/proxy_playlist_provider.dart';
import 'package:spotube/provider/user_preferences_provider.dart';
import 'package:spotube/provider/volume_provider.dart';
import 'package:spotube/services/audio_player/audio_player.dart';
import 'package:spotube/utils/platform.dart';
import 'package:spotube/utils/type_conversion_utils.dart';

Expand Down
166 changes: 166 additions & 0 deletions lib/components/shared/dialogs/track_details_dialog.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,166 @@
import 'package:flutter/material.dart';
import 'package:flutter_hooks/flutter_hooks.dart';
import 'package:spotify/spotify.dart';
import 'package:spotube/collections/spotube_icons.dart';
import 'package:spotube/components/shared/links/hyper_link.dart';
import 'package:spotube/components/shared/links/link_text.dart';
import 'package:spotube/extensions/constrains.dart';
import 'package:spotube/extensions/context.dart';
import 'package:spotube/models/spotube_track.dart';
import 'package:spotube/utils/primitive_utils.dart';
import 'package:spotube/utils/type_conversion_utils.dart';
import 'package:spotube/extensions/duration.dart';

class TrackDetailsDialog extends HookWidget {
final Track track;
const TrackDetailsDialog({
Key? key,
required this.track,
}) : super(key: key);

@override
Widget build(BuildContext context) {
final theme = Theme.of(context);
final mediaQuery = MediaQuery.of(context);

final detailsMap = {
context.l10n.title: track.name!,
context.l10n.artist: TypeConversionUtils.artists_X_ClickableArtists(
track.artists ?? <Artist>[],
mainAxisAlignment: WrapAlignment.start,
textStyle: const TextStyle(color: Colors.blue),
),
context.l10n.album: LinkText(
track.album!.name!,
"/album/${track.album?.id}",
extra: track.album,
overflow: TextOverflow.ellipsis,
style: const TextStyle(color: Colors.blue),
),
context.l10n.duration: (track is SpotubeTrack
? (track as SpotubeTrack).ytTrack.duration
: track.duration!)
.toHumanReadableString(),
if (track.album!.releaseDate != null)
context.l10n.released: track.album!.releaseDate,
context.l10n.popularity: track.popularity?.toString() ?? "0",
};

final ytTrack =
track is SpotubeTrack ? (track as SpotubeTrack).ytTrack : null;

final ytTracksDetailsMap = ytTrack == null
? {}
: {
context.l10n.youtube: Hyperlink(
"https://piped.video/watch?v=${ytTrack.id}",
"https://piped.video/watch?v=${ytTrack.id}",
maxLines: 2,
overflow: TextOverflow.ellipsis,
),
context.l10n.channel: Hyperlink(
ytTrack.uploader,
"https://youtube.com${ytTrack.uploaderUrl}",
maxLines: 2,
overflow: TextOverflow.ellipsis,
),
context.l10n.likes:
PrimitiveUtils.toReadableNumber(ytTrack.likes.toDouble()),
context.l10n.dislikes:
PrimitiveUtils.toReadableNumber(ytTrack.dislikes.toDouble()),
context.l10n.views:
PrimitiveUtils.toReadableNumber(ytTrack.views.toDouble()),
context.l10n.streamUrl: Hyperlink(
(track as SpotubeTrack).ytUri,
(track as SpotubeTrack).ytUri,
maxLines: 2,
overflow: TextOverflow.ellipsis,
),
};

return AlertDialog(
contentPadding: const EdgeInsets.all(16),
insetPadding: const EdgeInsets.symmetric(horizontal: 16, vertical: 100),
scrollable: true,
title: Row(
mainAxisAlignment: MainAxisAlignment.center,
children: [
const Icon(SpotubeIcons.info),
const SizedBox(width: 8),
Text(
context.l10n.details,
style: theme.textTheme.titleMedium,
),
],
),
content: SizedBox(
width: mediaQuery.mdAndUp ? double.infinity : 700,
child: Table(
columnWidths: const {
0: FixedColumnWidth(95),
1: FixedColumnWidth(10),
2: FlexColumnWidth(1),
},
defaultVerticalAlignment: TableCellVerticalAlignment.middle,
children: [
for (final entry in detailsMap.entries)
TableRow(
children: [
TableCell(
verticalAlignment: TableCellVerticalAlignment.top,
child: Text(
entry.key,
style: theme.textTheme.titleMedium,
),
),
const TableCell(
verticalAlignment: TableCellVerticalAlignment.top,
child: Text(":"),
),
if (entry.value is Widget)
entry.value as Widget
else
Text(
entry.value,
style: theme.textTheme.bodyMedium,
),
],
),
const TableRow(
children: [
SizedBox(height: 16),
SizedBox(height: 16),
SizedBox(height: 16),
],
),
for (final entry in ytTracksDetailsMap.entries)
TableRow(
children: [
TableCell(
verticalAlignment: TableCellVerticalAlignment.top,
child: Text(
entry.key,
style: theme.textTheme.titleMedium,
),
),
const TableCell(
verticalAlignment: TableCellVerticalAlignment.top,
child: Text(":"),
),
if (entry.value is Widget)
entry.value as Widget
else
Text(
entry.value,
maxLines: 2,
overflow: TextOverflow.ellipsis,
style: theme.textTheme.bodyMedium,
),
],
),
],
),
),
);
}
}
3 changes: 3 additions & 0 deletions lib/components/shared/links/anchor_button.dart
Original file line number Diff line number Diff line change
Expand Up @@ -7,13 +7,15 @@ class AnchorButton<T> extends HookWidget {
final TextAlign? textAlign;
final TextOverflow? overflow;
final void Function()? onTap;
final int? maxLines;

const AnchorButton(
this.text, {
Key? key,
this.onTap,
this.textAlign,
this.overflow,
this.maxLines,
this.style = const TextStyle(),
}) : super(key: key);

Expand All @@ -34,6 +36,7 @@ class AnchorButton<T> extends HookWidget {
decoration:
hover.value || tap.value ? TextDecoration.underline : null,
),
maxLines: maxLines,
textAlign: textAlign,
overflow: overflow,
),
Expand Down
4 changes: 4 additions & 0 deletions lib/components/shared/links/hyper_link.dart
Original file line number Diff line number Diff line change
Expand Up @@ -8,13 +8,16 @@ class Hyperlink extends StatelessWidget {
final TextAlign? textAlign;
final TextOverflow? overflow;
final String url;
final int? maxLines;

const Hyperlink(
this.text,
this.url, {
Key? key,
this.textAlign,
this.overflow,
this.style = const TextStyle(),
this.maxLines,
}) : super(key: key);

@override
Expand All @@ -29,6 +32,7 @@ class Hyperlink extends StatelessWidget {
},
key: key,
overflow: overflow,
maxLines: maxLines,
style: style.copyWith(color: Colors.blue),
textAlign: textAlign,
);
Expand Down
9 changes: 8 additions & 1 deletion lib/components/shared/links/link_text.dart
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,8 @@ class LinkText<T> extends StatelessWidget {
final TextOverflow? overflow;
final String route;
final T? extra;

final bool push;
const LinkText(
this.text,
this.route, {
Expand All @@ -17,14 +19,19 @@ class LinkText<T> extends StatelessWidget {
this.extra,
this.overflow,
this.style = const TextStyle(),
this.push = false,
}) : super(key: key);

@override
Widget build(BuildContext context) {
return AnchorButton(
text,
onTap: () {
ServiceUtils.navigate(context, route, extra: extra);
if (push) {
ServiceUtils.push(context, route, extra: extra);
} else {
ServiceUtils.navigate(context, route, extra: extra);
}
},
key: key,
overflow: overflow,
Expand Down
17 changes: 16 additions & 1 deletion lib/components/shared/track_table/track_options.dart
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import 'package:spotube/collections/spotube_icons.dart';
import 'package:spotube/components/library/user_local_tracks.dart';
import 'package:spotube/components/shared/adaptive/adaptive_pop_sheet_list.dart';
import 'package:spotube/components/shared/dialogs/playlist_add_track_dialog.dart';
import 'package:spotube/components/shared/dialogs/track_details_dialog.dart';
import 'package:spotube/components/shared/heart_button.dart';
import 'package:spotube/components/shared/image/universal_image.dart';
import 'package:spotube/extensions/context.dart';
Expand All @@ -29,6 +30,7 @@ enum TrackOptionValue {
delete,
playNext,
favorite,
details,
}

class TrackOptions extends HookConsumerWidget {
Expand Down Expand Up @@ -163,6 +165,12 @@ class TrackOptions extends HookConsumerWidget {
case TrackOptionValue.share:
actionShare(context, track);
break;
case TrackOptionValue.details:
showDialog(
context: context,
builder: (context) => TrackDetailsDialog(track: track),
);
break;
}
},
icon: const Icon(SpotubeIcons.moreHorizontal),
Expand Down Expand Up @@ -288,7 +296,14 @@ class TrackOptions extends HookConsumerWidget {
leading: const Icon(SpotubeIcons.share),
title: Text(context.l10n.share),
),
)
),
PopSheetEntry(
value: TrackOptionValue.details,
child: ListTile(
leading: const Icon(SpotubeIcons.info),
title: Text(context.l10n.details),
),
),
]
},
),
Expand Down
1 change: 1 addition & 0 deletions lib/components/shared/track_table/track_tile.dart
Original file line number Diff line number Diff line change
Expand Up @@ -176,6 +176,7 @@ class TrackTile extends HookConsumerWidget {
track.album!.name!,
"/album/${track.album?.id}",
extra: track.album,
push: true,
overflow: TextOverflow.ellipsis,
),
)
Expand Down
9 changes: 8 additions & 1 deletion lib/l10n/app_en.arb
Original file line number Diff line number Diff line change
Expand Up @@ -230,5 +230,12 @@
"download_agreement_2": "I'll support the Artist wherever I can and I'm only doing this because I don't have money to buy their art",
"download_agreement_3": "I'm completely aware that my IP can get blocked on YouTube & I don't hold Spotube or his owners/contributors responsible for any accidents caused by my current action",
"decline": "Decline",
"accept": "Accept"
"accept": "Accept",
"details": "Details",
"youtube": "YouTube",
"channel": "Channel",
"likes": "Likes",
"dislikes": "Dislikes",
"views": "Views",
"streamUrl": "Stream URL"
}
16 changes: 14 additions & 2 deletions lib/pages/lyrics/synced_lyrics.dart
Original file line number Diff line number Diff line change
Expand Up @@ -111,10 +111,22 @@ class SyncedLyrics extends HookConsumerWidget {
index: index,
controller: controller,
child: lyricSlice.text.isEmpty
? Container()
? Container(
padding: index == lyricValue.lyrics.length - 1
? EdgeInsets.only(
bottom:
MediaQuery.of(context).size.height /
2,
)
: null,
)
: Center(
child: Padding(
padding: const EdgeInsets.all(8.0),
padding: index == lyricValue.lyrics.length - 1
? const EdgeInsets.all(8.0).copyWith(
bottom: 100,
)
: const EdgeInsets.all(8.0),
child: AnimatedDefaultTextStyle(
duration: const Duration(milliseconds: 250),
style: TextStyle(
Expand Down
Loading

0 comments on commit ce38233

Please sign in to comment.