Skip to content

Commit

Permalink
feat: Slightly tweak LargePlayer layout
Browse files Browse the repository at this point in the history
  • Loading branch information
khaled-0 committed Nov 21, 2024
1 parent 911fd37 commit a51367a
Show file tree
Hide file tree
Showing 5 changed files with 144 additions and 134 deletions.
1 change: 1 addition & 0 deletions lib/app/app_theme.dart
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@ class AppTheme {
),
sliderTheme: const SliderThemeData(
thumbShape: LineThumbShape(),
trackHeight: 8,
),
appBarTheme: AppBarTheme(
systemOverlayStyle: systemOverlayStyle(theme),
Expand Down
2 changes: 1 addition & 1 deletion lib/app/player/components/artwork.dart
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ class Artwork extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Padding(
padding: const EdgeInsets.all(24.0),
padding: const EdgeInsets.symmetric(vertical: 24, horizontal: 48),
child: ValueListenableBuilder(
valueListenable: context.read<PlayerProvider>().nowPlaying,
builder: (context, media, child) => StreamBuilder(
Expand Down
2 changes: 1 addition & 1 deletion lib/app/player/components/seekbar.dart
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,7 @@ class LineThumbShape extends SliderComponentShape {
final Size thumbSize;

const LineThumbShape({
this.thumbSize = const Size(8, 32),
this.thumbSize = const Size(6, 36),
});

@override
Expand Down
271 changes: 140 additions & 131 deletions lib/app/player/large_player_sheet.dart
Original file line number Diff line number Diff line change
Expand Up @@ -91,147 +91,156 @@ class _LargePlayerSheetState extends State<LargePlayerSheet>
],
),
),
ValueListenableBuilder(
valueListenable: context.read<PlayerProvider>().nowPlaying,
builder: (context, media, _) {
return Card.outlined(
elevation: 0,
margin: const EdgeInsets.symmetric(horizontal: 10),
child: ListTile(
onTap: showPlayerQueue,
title: Text(
media.title,
seekBarView(context),
const SizedBox(height: 12),
actionsView(context),
const SizedBox(height: 36),
queueView(context),
const SizedBox(height: 12),
],
),
);
}

Widget queueView(BuildContext context) {
return ValueListenableBuilder(
valueListenable: context.read<PlayerProvider>().nowPlaying,
builder: (context, media, _) {
return Card.outlined(
elevation: 0,
margin: const EdgeInsets.symmetric(horizontal: 10),
child: ListTile(
onTap: showPlayerQueue,
title: Text(
media.title,
maxLines: 1,
overflow: TextOverflow.ellipsis,
),
subtitle: Column(
crossAxisAlignment: CrossAxisAlignment.start,
mainAxisSize: MainAxisSize.min,
children: [
Text(
media.author,
maxLines: 1,
overflow: TextOverflow.ellipsis,
),
Selector<PlayerProvider, List<Media>>(
selector: (_, provider) => provider.playlist,
builder: (context, playlist, _) => Text(
"${playlist.indexOf(media) + 1}/${playlist.length}"
" \u2022 ${playlistInfo(context)}",
maxLines: 1,
overflow: TextOverflow.ellipsis,
),
subtitle: Column(
crossAxisAlignment: CrossAxisAlignment.start,
mainAxisSize: MainAxisSize.min,
children: [
Text(
media.author,
maxLines: 1,
overflow: TextOverflow.ellipsis,
),
Selector<PlayerProvider, List<Media>>(
selector: (_, provider) => provider.playlist,
builder: (context, playlist, _) => Text(
"${playlist.indexOf(media) + 1}/${playlist.length}"
" \u2022 ${playlistInfo(context)}",
maxLines: 1,
overflow: TextOverflow.ellipsis,
),
)
],
),
leading: const Icon(Icons.playlist_play_rounded),
trailing: const Icon(Icons.keyboard_arrow_right_rounded),
),
);
},
),
const SizedBox(height: 16),
// SeekBar
ValueListenableBuilder(
valueListenable: context.read<PlayerProvider>().nowPlaying,
builder: (context, media, _) => StreamBuilder<Duration>(
stream: context.read<PlayerProvider>().player.positionStream,
builder: (context, currentPosition) => Padding(
padding: const EdgeInsets.symmetric(
horizontal: 12,
vertical: 8,
),
child: Row(
children: [
SizedBox(
width: currentPosition.data?.inHours == 0 ? 48 : 72,
child: Text(currentPosition.data.formatHHMM()),
),
Expanded(
child: Selector<PlayerProvider, bool>(
selector: (_, provider) => provider.buffering,
builder: (context, buffering, child) {
if (media.duration == null) return const SizedBox();
final player = context.read<PlayerProvider>().player;
return SeekBar(
buffering: buffering,
duration: media.duration!,
position: currentPosition.data ?? Duration.zero,
bufferedPosition: player.bufferedPosition,
onChangeEnd: (v) => player.seek(v),
);
},
),
),
SizedBox(
width: media.duration?.inHours == 0 ? 48 : 72,
child: Text(media.duration.formatHHMM()),
),
],
),
),
)
],
),
leading: const Icon(Icons.playlist_play_rounded),
trailing: const Icon(Icons.keyboard_arrow_right_rounded),
),
);
},
);
}

const SizedBox(height: 16),

StreamBuilder(
stream: context.read<PlayerProvider>().player.playerStateStream,
initialData: context.read<PlayerProvider>().player.playerState,
builder: (context, playerState) => Row(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Selector<PlayerProvider, List<Media>>(
selector: (_, provider) => provider.playlist,
child: const Icon(Icons.skip_previous_rounded),
builder: (_, __, icon) => IconButton(
onPressed: context.read<PlayerProvider>().hasPrevious
? context.read<PlayerProvider>().previousTrack
: null,
icon: icon!,
),
),
const SizedBox(width: 30),
Selector<PlayerProvider, bool>(
Widget seekBarView(BuildContext context) {
return ValueListenableBuilder(
valueListenable: context.read<PlayerProvider>().nowPlaying,
builder: (context, media, _) => StreamBuilder<Duration>(
stream: context.read<PlayerProvider>().player.positionStream,
builder: (context, currentPosition) => Padding(
padding: const EdgeInsets.symmetric(
horizontal: 12,
vertical: 8,
),
child: Row(
children: [
SizedBox(
width: currentPosition.data?.inHours == 0 ? 48 : 72,
child: Text(currentPosition.data.formatHHMM()),
),
Expanded(
child: Selector<PlayerProvider, bool>(
selector: (_, provider) => provider.buffering,
builder: (_, loading, child) => FloatingActionButton.small(
elevation: 0,
highlightElevation: 1,
hoverElevation: 1,
focusElevation: 1,
onPressed: loading
? null
: switch (playerState.requireData.playing) {
true => context.read<PlayerProvider>().player.pause,
false => context.read<PlayerProvider>().player.play,
},
child: loading
? child
: switch (playerState.requireData.playing) {
true => const Icon(Icons.pause_rounded),
false => const Icon(Icons.play_arrow_rounded),
},
),
child: const Padding(
padding: EdgeInsets.all(8.0),
child: CircularProgressIndicator(strokeWidth: 2),
),
builder: (context, buffering, child) {
if (media.duration == null) return const SizedBox();
final player = context.read<PlayerProvider>().player;
return SeekBar(
buffering: buffering,
duration: media.duration!,
position: currentPosition.data ?? Duration.zero,
bufferedPosition: player.bufferedPosition,
onChangeEnd: (v) => player.seek(v),
);
},
),
const SizedBox(width: 30),
Selector<PlayerProvider, List<Media>>(
selector: (_, provider) => provider.playlist,
child: const Icon(Icons.skip_next_rounded),
builder: (context, _, icon) => IconButton(
onPressed: context.read<PlayerProvider>().hasNext
? context.read<PlayerProvider>().nextTrack
: null,
icon: icon!,
),
),
],
),
SizedBox(
width: media.duration?.inHours == 0 ? 48 : 72,
child: Text(media.duration.formatHHMM()),
),
],
),
),
),
);
}

Widget actionsView(BuildContext context) {
return StreamBuilder(
stream: context.read<PlayerProvider>().player.playerStateStream,
initialData: context.read<PlayerProvider>().player.playerState,
builder: (context, playerState) => Row(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Selector<PlayerProvider, List<Media>>(
selector: (_, provider) => provider.playlist,
child: const Icon(Icons.skip_previous_rounded),
builder: (_, __, icon) => IconButton(
onPressed: context.read<PlayerProvider>().hasPrevious
? context.read<PlayerProvider>().previousTrack
: null,
icon: icon!,
),
),
const SizedBox(width: 30),
Selector<PlayerProvider, bool>(
selector: (_, provider) => provider.buffering,
builder: (_, loading, child) => FloatingActionButton(
elevation: 0,
highlightElevation: 1,
hoverElevation: 1,
focusElevation: 1,
onPressed: loading
? null
: switch (playerState.requireData.playing) {
true => context.read<PlayerProvider>().player.pause,
false => context.read<PlayerProvider>().player.play,
},
child: loading
? child
: switch (playerState.requireData.playing) {
true => const Icon(Icons.pause_rounded),
false => const Icon(Icons.play_arrow_rounded),
},
),
child: const Padding(
padding: EdgeInsets.all(8.0),
child: CircularProgressIndicator(strokeWidth: 2),
),
),
const SizedBox(width: 30),
Selector<PlayerProvider, List<Media>>(
selector: (_, provider) => provider.playlist,
child: const Icon(Icons.skip_next_rounded),
builder: (context, _, icon) => IconButton(
onPressed: context.read<PlayerProvider>().hasNext
? context.read<PlayerProvider>().nextTrack
: null,
icon: icon!,
),
),
const SizedBox(height: 32),
],
),
);
Expand Down
2 changes: 1 addition & 1 deletion lib/app/player/player_queue_sheet.dart
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ class PlayerQueueSheet extends StatelessWidget {
return DraggableScrollableSheet(
expand: false,
snap: true,
shouldCloseOnMinExtent: false,
// shouldCloseOnMinExtent: false, Should or Not??? Can't decide !!
minChildSize: 0.5,
builder: (context, scrollController) => Column(
children: [
Expand Down

0 comments on commit a51367a

Please sign in to comment.