Skip to content

Commit

Permalink
port new list tile to queue list
Browse files Browse the repository at this point in the history
- some edge cases might still be missing, and refactoring to using constructors instead of separate classed would be good
  • Loading branch information
Chaphasilor committed Oct 15, 2024
1 parent 38f9c6c commit 45dd75c
Show file tree
Hide file tree
Showing 3 changed files with 213 additions and 7 deletions.
190 changes: 188 additions & 2 deletions lib/components/AlbumScreen/song_list_tile.dart
Original file line number Diff line number Diff line change
Expand Up @@ -387,14 +387,172 @@ class _SongListTileState extends ConsumerState<SongListTile>
}
}


class QueueListTile extends ConsumerStatefulWidget {
final jellyfin_models.BaseItemDto item;
final jellyfin_models.BaseItemDto? parentItem;
final Future<int>? listIndex;
final int actualIndex;
final int indexOffset;
final bool isCurrentTrack;
final bool isInPlaylist;
final bool allowReorder;

final void Function() onTap;
final VoidCallback? onRemoveFromList;
final void Function(FinampTheme)? themeCallback;

const QueueListTile({
super.key,
required this.item,
required this.listIndex,
required this.actualIndex,
required this.indexOffset,
required this.onTap,
required this.isCurrentTrack,
required this.isInPlaylist,
required this.allowReorder,
this.parentItem,
this.onRemoveFromList,
this.themeCallback,
});

@override
ConsumerState<QueueListTile> createState() => _QueueListTileState();
}

class _QueueListTileState extends ConsumerState<QueueListTile>
with SingleTickerProviderStateMixin {
final _audioServiceHelper = GetIt.instance<AudioServiceHelper>();
final _queueService = GetIt.instance<QueueService>();
final _audioHandler = GetIt.instance<MusicPlayerBackgroundTask>();

FinampTheme? _menuTheme;

@override
void dispose() {
_menuTheme?.dispose();
super.dispose();
}

@override
Widget build(BuildContext context) {
bool playable;
if (FinampSettingsHelper.finampSettings.isOffline) {
playable = ref.watch(GetIt.instance<DownloadsService>()
.stateProvider(DownloadStub.fromItem(
type: DownloadItemType.song, item: widget.item))
.select((value) => value.value?.isComplete ?? false));
} else {
playable = true;
}

final listTile = StreamBuilder<MediaItem?>(
stream: _audioHandler.mediaItem,
builder: (context, snapshot) {
// I think past me did this check directly from the JSON for
// performance. It works for now, apologies if you're debugging it
// years in the future.
final isCurrentlyPlaying =
snapshot.data?.extras?["itemJson"]["Id"] == widget.item.id;

final trackListItem = TrackListItem(
item: widget.item,
parentItem: widget.parentItem,
listIndex: widget.listIndex,
actualIndex: widget.item.indexNumber ?? -1,
isCurrentTrack: isCurrentlyPlaying,
isPlayable: playable,
isInPlaylist: widget.isInPlaylist,
allowReorder: widget.allowReorder,
onRemoveFromList: widget.onRemoveFromList,
themeCallback: (x) => _menuTheme = x,
// This must be in ListTile instead of parent GestureDetecter to
// enable hover color changes
onTap: widget.onTap,
);

return isCurrentlyPlaying
? ProviderScope(
overrides: [
themeDataProvider.overrideWith((ref) {
return ref.watch(playerScreenThemeDataProvider) ??
FinampTheme.defaultTheme();
})
],
child: Consumer(
builder:
(BuildContext context, WidgetRef ref, Widget? child) {
final imageTheme = ref.watch(playerScreenThemeProvider);
return AnimatedTheme(
duration: const Duration(milliseconds: 500),
data: ThemeData(
colorScheme: imageTheme,
brightness: Theme.of(context).brightness,
iconTheme: Theme.of(context).iconTheme.copyWith(
color: imageTheme.primary,
),
),
child: trackListItem,
);
},
),
)
: trackListItem;
});
void menuCallback() async {
if (playable) {
FeedbackHelper.feedback(FeedbackType.selection);
await showModalSongMenu(
context: context,
item: widget.item,
isInPlaylist: widget.isInPlaylist,
parentItem: widget.parentItem,
onRemoveFromList: widget.onRemoveFromList,
themeProvider: _menuTheme,
confirmPlaylistRemoval: false,
);
}
}

return GestureDetector(
onTapDown: (_) {
_menuTheme?.calculate(Theme.of(context).brightness);
},
onLongPressStart: (details) => menuCallback(),
onSecondaryTapDown: (details) => menuCallback(),
child: !playable
? listTile
: Dismissible(
key: Key(widget.listIndex.toString()),
direction: FinampSettingsHelper.finampSettings.disableGesture
? DismissDirection.none
: DismissDirection.horizontal,
dismissThresholds: const {
DismissDirection.startToEnd: 0.65,
DismissDirection.endToStart: 0.65
},
// no background, dismissing really dismisses here
onDismissed: (direction) async {
FeedbackHelper.feedback(FeedbackType.impact);
await _queueService.removeAtOffset(widget.indexOffset);
setState(() {});
},
child: listTile,
),
);
}
}

class TrackListItem extends ConsumerWidget {
final jellyfin_models.BaseItemDto item;
final jellyfin_models.BaseItemDto? parentItem;
final Future<int>? listIndex;
final int actualIndex;
final bool isCurrentTrack;
final bool isInPlaylist;

final bool allowReorder;

final bool isPlayable;
final void Function() onTap;
final VoidCallback? onRemoveFromList;
Expand All @@ -410,6 +568,7 @@ class TrackListItem extends ConsumerWidget {
this.isPlayable = true,
this.isCurrentTrack = false,
this.isInPlaylist = false,
this.allowReorder = false,
this.onRemoveFromList,
this.themeCallback,
});
Expand Down Expand Up @@ -446,7 +605,8 @@ class TrackListItem extends ConsumerWidget {
Brightness.dark
? 0.35
: 0.3)
: Theme.of(context).colorScheme.surfaceContainer,
// : Theme.of(context).colorScheme.surfaceContainer,
: Colors.transparent,
),
textTheme: Theme.of(context).textTheme.copyWith(
bodyLarge: Theme.of(context)
Expand All @@ -463,8 +623,10 @@ class TrackListItem extends ConsumerWidget {
)),
child: TrackListItemTile(
baseItem: baseItem,
index: listIndex,
themeCallback: themeCallback,
isCurrentTrack: isCurrentTrack,
allowReorder: allowReorder,
onTap: onTap),
)),
);
Expand All @@ -479,12 +641,16 @@ class TrackListItemTile extends StatelessWidget {
required this.baseItem,
required this.themeCallback,
required this.isCurrentTrack,
required this.allowReorder,
required this.onTap,
this.index,
});

final jellyfin_models.BaseItemDto baseItem;
final void Function(FinampTheme theme)? themeCallback;
final bool isCurrentTrack;
final bool allowReorder;
final Future<int>? index;
final void Function() onTap;

static const double tileHeight = 60.0;
Expand Down Expand Up @@ -612,6 +778,26 @@ class TrackListItemTile extends StatelessWidget {
horizontal: -4,
),
),
if (allowReorder)
FutureBuilder(
future: index,
builder: (context, snapshot) {
return ReorderableDragStartListener(
index: snapshot.data ??
0, // will briefly use 0 as index, but should resolve quickly enough for user not to notice
child: Padding(
padding: const EdgeInsets.only(left: 6.0),
child: Icon(
TablerIcons.grip_horizontal,
color:
Theme.of(context).textTheme.bodyMedium?.color ??
Colors.white,
size: 28.0,
weight: 1.5,
),
),
);
}),
],
),
),
Expand Down
28 changes: 24 additions & 4 deletions lib/components/PlayerScreen/queue_list.dart
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import 'dart:async';

import 'package:audio_service/audio_service.dart';
import 'package:finamp/components/AlbumScreen/song_list_tile.dart';
import 'package:finamp/components/AlbumScreen/song_menu.dart';
import 'package:finamp/components/Buttons/simple_button.dart';
import 'package:finamp/components/AddToPlaylistScreen/add_to_playlist_button.dart';
Expand Down Expand Up @@ -648,13 +649,32 @@ class _QueueTracksListState extends State<QueueTracksList> {
final actualIndex = index;
final indexOffset = index + _nextUp!.length + 1;

return QueueListItem(
// return QueueListItem(
// key: ValueKey(item.id),
// item: item,
// listIndex: index,
// actualIndex: actualIndex,
// indexOffset: indexOffset,
// subqueue: _queue!,
// allowReorder:
// _queueService.playbackOrder == FinampPlaybackOrder.linear,
// onTap: () async {
// FeedbackHelper.feedback(FeedbackType.selection);
// await _queueService.skipByOffset(indexOffset);
// scrollToKey(
// key: widget.previousTracksHeaderKey,
// duration: const Duration(milliseconds: 500));
// },
// isCurrentTrack: false,
// );
return QueueListTile(
key: ValueKey(item.id),
item: item,
listIndex: index,
item: item.baseItem!,
listIndex: Future.value(index),
actualIndex: actualIndex,
indexOffset: indexOffset,
subqueue: _queue!,
isInPlaylist: queueItemInPlaylist(item),
parentItem: item.source.item,
allowReorder:
_queueService.playbackOrder == FinampPlaybackOrder.linear,
onTap: () async {
Expand Down
2 changes: 1 addition & 1 deletion lib/components/PlayerScreen/queue_list_item.dart
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ import 'package:get_it/get_it.dart';

import '../../services/theme_provider.dart';

@Deprecated("Use QueueListItem instead")
class QueueListItem extends StatefulWidget {
final FinampQueueItem item;
final int listIndex;
Expand Down Expand Up @@ -123,7 +124,6 @@ class _QueueListItemState extends State<QueueListItem>
: jellyfin_models.BaseItemDto.fromJson(
widget.item.item.extras?["itemJson"]),
borderRadius: BorderRadius.zero,
themeCallback: (x) => _menuTheme = x,
),
title: Column(
crossAxisAlignment: CrossAxisAlignment.start,
Expand Down

0 comments on commit 45dd75c

Please sign in to comment.