mirror of
https://github.com/KRTirtho/spotube.git
synced 2025-09-13 07:55:18 +00:00
feat: player details dialog and separate location of lyrics button in player page
This commit is contained in:
parent
3b56c78d5c
commit
ce38233de8
@ -1,4 +1,5 @@
|
|||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:go_router/go_router.dart';
|
||||||
import 'package:hooks_riverpod/hooks_riverpod.dart';
|
import 'package:hooks_riverpod/hooks_riverpod.dart';
|
||||||
import 'package:spotify/spotify.dart';
|
import 'package:spotify/spotify.dart';
|
||||||
|
|
||||||
@ -6,6 +7,7 @@ import 'package:spotube/collections/assets.gen.dart';
|
|||||||
import 'package:spotube/components/shared/image/universal_image.dart';
|
import 'package:spotube/components/shared/image/universal_image.dart';
|
||||||
import 'package:spotube/extensions/constrains.dart';
|
import 'package:spotube/extensions/constrains.dart';
|
||||||
import 'package:spotube/provider/proxy_playlist/proxy_playlist_provider.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';
|
import 'package:spotube/utils/type_conversion_utils.dart';
|
||||||
|
|
||||||
class PlayerTrackDetails extends HookConsumerWidget {
|
class PlayerTrackDetails extends HookConsumerWidget {
|
||||||
@ -72,6 +74,9 @@ class PlayerTrackDetails extends HookConsumerWidget {
|
|||||||
),
|
),
|
||||||
TypeConversionUtils.artists_X_ClickableArtists(
|
TypeConversionUtils.artists_X_ClickableArtists(
|
||||||
playback.activeTrack?.artists ?? [],
|
playback.activeTrack?.artists ?? [],
|
||||||
|
onRouteChange: (route) {
|
||||||
|
ServiceUtils.push(context, route);
|
||||||
|
},
|
||||||
)
|
)
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
|
@ -20,7 +20,6 @@ import 'package:flutter/material.dart';
|
|||||||
import 'package:spotube/provider/proxy_playlist/proxy_playlist_provider.dart';
|
import 'package:spotube/provider/proxy_playlist/proxy_playlist_provider.dart';
|
||||||
import 'package:spotube/provider/user_preferences_provider.dart';
|
import 'package:spotube/provider/user_preferences_provider.dart';
|
||||||
import 'package:spotube/provider/volume_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/platform.dart';
|
||||||
import 'package:spotube/utils/type_conversion_utils.dart';
|
import 'package:spotube/utils/type_conversion_utils.dart';
|
||||||
|
|
||||||
|
166
lib/components/shared/dialogs/track_details_dialog.dart
Normal file
166
lib/components/shared/dialogs/track_details_dialog.dart
Normal file
@ -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,
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
@ -7,6 +7,7 @@ class AnchorButton<T> extends HookWidget {
|
|||||||
final TextAlign? textAlign;
|
final TextAlign? textAlign;
|
||||||
final TextOverflow? overflow;
|
final TextOverflow? overflow;
|
||||||
final void Function()? onTap;
|
final void Function()? onTap;
|
||||||
|
final int? maxLines;
|
||||||
|
|
||||||
const AnchorButton(
|
const AnchorButton(
|
||||||
this.text, {
|
this.text, {
|
||||||
@ -14,6 +15,7 @@ class AnchorButton<T> extends HookWidget {
|
|||||||
this.onTap,
|
this.onTap,
|
||||||
this.textAlign,
|
this.textAlign,
|
||||||
this.overflow,
|
this.overflow,
|
||||||
|
this.maxLines,
|
||||||
this.style = const TextStyle(),
|
this.style = const TextStyle(),
|
||||||
}) : super(key: key);
|
}) : super(key: key);
|
||||||
|
|
||||||
@ -34,6 +36,7 @@ class AnchorButton<T> extends HookWidget {
|
|||||||
decoration:
|
decoration:
|
||||||
hover.value || tap.value ? TextDecoration.underline : null,
|
hover.value || tap.value ? TextDecoration.underline : null,
|
||||||
),
|
),
|
||||||
|
maxLines: maxLines,
|
||||||
textAlign: textAlign,
|
textAlign: textAlign,
|
||||||
overflow: overflow,
|
overflow: overflow,
|
||||||
),
|
),
|
||||||
|
@ -8,6 +8,8 @@ class Hyperlink extends StatelessWidget {
|
|||||||
final TextAlign? textAlign;
|
final TextAlign? textAlign;
|
||||||
final TextOverflow? overflow;
|
final TextOverflow? overflow;
|
||||||
final String url;
|
final String url;
|
||||||
|
final int? maxLines;
|
||||||
|
|
||||||
const Hyperlink(
|
const Hyperlink(
|
||||||
this.text,
|
this.text,
|
||||||
this.url, {
|
this.url, {
|
||||||
@ -15,6 +17,7 @@ class Hyperlink extends StatelessWidget {
|
|||||||
this.textAlign,
|
this.textAlign,
|
||||||
this.overflow,
|
this.overflow,
|
||||||
this.style = const TextStyle(),
|
this.style = const TextStyle(),
|
||||||
|
this.maxLines,
|
||||||
}) : super(key: key);
|
}) : super(key: key);
|
||||||
|
|
||||||
@override
|
@override
|
||||||
@ -29,6 +32,7 @@ class Hyperlink extends StatelessWidget {
|
|||||||
},
|
},
|
||||||
key: key,
|
key: key,
|
||||||
overflow: overflow,
|
overflow: overflow,
|
||||||
|
maxLines: maxLines,
|
||||||
style: style.copyWith(color: Colors.blue),
|
style: style.copyWith(color: Colors.blue),
|
||||||
textAlign: textAlign,
|
textAlign: textAlign,
|
||||||
);
|
);
|
||||||
|
@ -9,6 +9,8 @@ class LinkText<T> extends StatelessWidget {
|
|||||||
final TextOverflow? overflow;
|
final TextOverflow? overflow;
|
||||||
final String route;
|
final String route;
|
||||||
final T? extra;
|
final T? extra;
|
||||||
|
|
||||||
|
final bool push;
|
||||||
const LinkText(
|
const LinkText(
|
||||||
this.text,
|
this.text,
|
||||||
this.route, {
|
this.route, {
|
||||||
@ -17,6 +19,7 @@ class LinkText<T> extends StatelessWidget {
|
|||||||
this.extra,
|
this.extra,
|
||||||
this.overflow,
|
this.overflow,
|
||||||
this.style = const TextStyle(),
|
this.style = const TextStyle(),
|
||||||
|
this.push = false,
|
||||||
}) : super(key: key);
|
}) : super(key: key);
|
||||||
|
|
||||||
@override
|
@override
|
||||||
@ -24,7 +27,11 @@ class LinkText<T> extends StatelessWidget {
|
|||||||
return AnchorButton(
|
return AnchorButton(
|
||||||
text,
|
text,
|
||||||
onTap: () {
|
onTap: () {
|
||||||
|
if (push) {
|
||||||
|
ServiceUtils.push(context, route, extra: extra);
|
||||||
|
} else {
|
||||||
ServiceUtils.navigate(context, route, extra: extra);
|
ServiceUtils.navigate(context, route, extra: extra);
|
||||||
|
}
|
||||||
},
|
},
|
||||||
key: key,
|
key: key,
|
||||||
overflow: overflow,
|
overflow: overflow,
|
||||||
|
@ -9,6 +9,7 @@ import 'package:spotube/collections/spotube_icons.dart';
|
|||||||
import 'package:spotube/components/library/user_local_tracks.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/adaptive/adaptive_pop_sheet_list.dart';
|
||||||
import 'package:spotube/components/shared/dialogs/playlist_add_track_dialog.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/heart_button.dart';
|
||||||
import 'package:spotube/components/shared/image/universal_image.dart';
|
import 'package:spotube/components/shared/image/universal_image.dart';
|
||||||
import 'package:spotube/extensions/context.dart';
|
import 'package:spotube/extensions/context.dart';
|
||||||
@ -29,6 +30,7 @@ enum TrackOptionValue {
|
|||||||
delete,
|
delete,
|
||||||
playNext,
|
playNext,
|
||||||
favorite,
|
favorite,
|
||||||
|
details,
|
||||||
}
|
}
|
||||||
|
|
||||||
class TrackOptions extends HookConsumerWidget {
|
class TrackOptions extends HookConsumerWidget {
|
||||||
@ -163,6 +165,12 @@ class TrackOptions extends HookConsumerWidget {
|
|||||||
case TrackOptionValue.share:
|
case TrackOptionValue.share:
|
||||||
actionShare(context, track);
|
actionShare(context, track);
|
||||||
break;
|
break;
|
||||||
|
case TrackOptionValue.details:
|
||||||
|
showDialog(
|
||||||
|
context: context,
|
||||||
|
builder: (context) => TrackDetailsDialog(track: track),
|
||||||
|
);
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
icon: const Icon(SpotubeIcons.moreHorizontal),
|
icon: const Icon(SpotubeIcons.moreHorizontal),
|
||||||
@ -288,7 +296,14 @@ class TrackOptions extends HookConsumerWidget {
|
|||||||
leading: const Icon(SpotubeIcons.share),
|
leading: const Icon(SpotubeIcons.share),
|
||||||
title: Text(context.l10n.share),
|
title: Text(context.l10n.share),
|
||||||
),
|
),
|
||||||
)
|
),
|
||||||
|
PopSheetEntry(
|
||||||
|
value: TrackOptionValue.details,
|
||||||
|
child: ListTile(
|
||||||
|
leading: const Icon(SpotubeIcons.info),
|
||||||
|
title: Text(context.l10n.details),
|
||||||
|
),
|
||||||
|
),
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
|
@ -176,6 +176,7 @@ class TrackTile extends HookConsumerWidget {
|
|||||||
track.album!.name!,
|
track.album!.name!,
|
||||||
"/album/${track.album?.id}",
|
"/album/${track.album?.id}",
|
||||||
extra: track.album,
|
extra: track.album,
|
||||||
|
push: true,
|
||||||
overflow: TextOverflow.ellipsis,
|
overflow: TextOverflow.ellipsis,
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
|
@ -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_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",
|
"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",
|
"decline": "Decline",
|
||||||
"accept": "Accept"
|
"accept": "Accept",
|
||||||
|
"details": "Details",
|
||||||
|
"youtube": "YouTube",
|
||||||
|
"channel": "Channel",
|
||||||
|
"likes": "Likes",
|
||||||
|
"dislikes": "Dislikes",
|
||||||
|
"views": "Views",
|
||||||
|
"streamUrl": "Stream URL"
|
||||||
}
|
}
|
@ -111,10 +111,22 @@ class SyncedLyrics extends HookConsumerWidget {
|
|||||||
index: index,
|
index: index,
|
||||||
controller: controller,
|
controller: controller,
|
||||||
child: lyricSlice.text.isEmpty
|
child: lyricSlice.text.isEmpty
|
||||||
? Container()
|
? Container(
|
||||||
|
padding: index == lyricValue.lyrics.length - 1
|
||||||
|
? EdgeInsets.only(
|
||||||
|
bottom:
|
||||||
|
MediaQuery.of(context).size.height /
|
||||||
|
2,
|
||||||
|
)
|
||||||
|
: null,
|
||||||
|
)
|
||||||
: Center(
|
: Center(
|
||||||
child: Padding(
|
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(
|
child: AnimatedDefaultTextStyle(
|
||||||
duration: const Duration(milliseconds: 250),
|
duration: const Duration(milliseconds: 250),
|
||||||
style: TextStyle(
|
style: TextStyle(
|
||||||
|
@ -10,9 +10,11 @@ import 'package:spotube/collections/spotube_icons.dart';
|
|||||||
import 'package:spotube/components/player/player_actions.dart';
|
import 'package:spotube/components/player/player_actions.dart';
|
||||||
import 'package:spotube/components/player/player_controls.dart';
|
import 'package:spotube/components/player/player_controls.dart';
|
||||||
import 'package:spotube/components/shared/animated_gradient.dart';
|
import 'package:spotube/components/shared/animated_gradient.dart';
|
||||||
|
import 'package:spotube/components/shared/dialogs/track_details_dialog.dart';
|
||||||
import 'package:spotube/components/shared/page_window_title_bar.dart';
|
import 'package:spotube/components/shared/page_window_title_bar.dart';
|
||||||
import 'package:spotube/components/shared/image/universal_image.dart';
|
import 'package:spotube/components/shared/image/universal_image.dart';
|
||||||
import 'package:spotube/extensions/constrains.dart';
|
import 'package:spotube/extensions/constrains.dart';
|
||||||
|
import 'package:spotube/extensions/context.dart';
|
||||||
import 'package:spotube/hooks/use_custom_status_bar_color.dart';
|
import 'package:spotube/hooks/use_custom_status_bar_color.dart';
|
||||||
import 'package:spotube/hooks/use_palette_color.dart';
|
import 'package:spotube/hooks/use_palette_color.dart';
|
||||||
import 'package:spotube/models/local_track.dart';
|
import 'package:spotube/models/local_track.dart';
|
||||||
@ -106,9 +108,8 @@ class PlayerView extends HookConsumerWidget {
|
|||||||
padding: const EdgeInsets.all(8.0),
|
padding: const EdgeInsets.all(8.0),
|
||||||
child: Column(
|
child: Column(
|
||||||
children: [
|
children: [
|
||||||
Padding(
|
Container(
|
||||||
padding: const EdgeInsets.all(8.0),
|
margin: const EdgeInsets.all(8),
|
||||||
child: Container(
|
|
||||||
constraints: const BoxConstraints(
|
constraints: const BoxConstraints(
|
||||||
maxHeight: 300, maxWidth: 300),
|
maxHeight: 300, maxWidth: 300),
|
||||||
decoration: BoxDecoration(
|
decoration: BoxDecoration(
|
||||||
@ -131,7 +132,6 @@ class PlayerView extends HookConsumerWidget {
|
|||||||
),
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
),
|
|
||||||
const SizedBox(height: 60),
|
const SizedBox(height: 60),
|
||||||
Container(
|
Container(
|
||||||
padding: const EdgeInsets.symmetric(horizontal: 16),
|
padding: const EdgeInsets.symmetric(horizontal: 16),
|
||||||
@ -183,11 +183,41 @@ class PlayerView extends HookConsumerWidget {
|
|||||||
PlayerActions(
|
PlayerActions(
|
||||||
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
|
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
|
||||||
floatingQueue: false,
|
floatingQueue: false,
|
||||||
extraActions: [
|
),
|
||||||
|
const SizedBox(height: 10),
|
||||||
if (auth != null)
|
if (auth != null)
|
||||||
IconButton(
|
Row(
|
||||||
tooltip: "Open Lyrics",
|
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
|
||||||
|
children: [
|
||||||
|
const SizedBox(width: 10),
|
||||||
|
Expanded(
|
||||||
|
child: OutlinedButton.icon(
|
||||||
|
icon: const Icon(SpotubeIcons.info),
|
||||||
|
label: Text(context.l10n.details),
|
||||||
|
style: OutlinedButton.styleFrom(
|
||||||
|
foregroundColor: bodyTextColor,
|
||||||
|
),
|
||||||
|
onPressed: currentTrack == null
|
||||||
|
? null
|
||||||
|
: () {
|
||||||
|
showDialog(
|
||||||
|
context: context,
|
||||||
|
builder: (context) {
|
||||||
|
return TrackDetailsDialog(
|
||||||
|
track: currentTrack,
|
||||||
|
);
|
||||||
|
});
|
||||||
|
},
|
||||||
|
),
|
||||||
|
),
|
||||||
|
const SizedBox(width: 10),
|
||||||
|
Expanded(
|
||||||
|
child: OutlinedButton.icon(
|
||||||
|
label: Text(context.l10n.lyrics),
|
||||||
icon: const Icon(SpotubeIcons.music),
|
icon: const Icon(SpotubeIcons.music),
|
||||||
|
style: OutlinedButton.styleFrom(
|
||||||
|
foregroundColor: bodyTextColor,
|
||||||
|
),
|
||||||
onPressed: () {
|
onPressed: () {
|
||||||
showModalBottomSheet(
|
showModalBottomSheet(
|
||||||
context: context,
|
context: context,
|
||||||
@ -203,18 +233,20 @@ class PlayerView extends HookConsumerWidget {
|
|||||||
),
|
),
|
||||||
),
|
),
|
||||||
constraints: BoxConstraints(
|
constraints: BoxConstraints(
|
||||||
maxHeight:
|
maxHeight: MediaQuery.of(context)
|
||||||
MediaQuery.of(context).size.height *
|
.size
|
||||||
|
.height *
|
||||||
0.8,
|
0.8,
|
||||||
),
|
),
|
||||||
builder: (context) =>
|
builder: (context) =>
|
||||||
const LyricsPage(isModal: true),
|
const LyricsPage(isModal: true),
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
)
|
),
|
||||||
|
),
|
||||||
|
const SizedBox(width: 10),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
const SizedBox(height: 25)
|
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
@ -251,6 +251,10 @@ abstract class ServiceUtils {
|
|||||||
}
|
}
|
||||||
|
|
||||||
static void navigate(BuildContext context, String location, {Object? extra}) {
|
static void navigate(BuildContext context, String location, {Object? extra}) {
|
||||||
|
GoRouter.of(context).go(location, extra: extra);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void push(BuildContext context, String location, {Object? extra}) {
|
||||||
GoRouter.of(context).push(location, extra: extra);
|
GoRouter.of(context).push(location, extra: extra);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user