Merge branch 'dev' into feat/connect

This commit is contained in:
Kingkor Roy Tirtho 2024-03-28 22:59:20 +06:00
commit a4854fca53

View File

@ -52,6 +52,9 @@ class PlayerQueue extends HookConsumerWidget {
@override @override
Widget build(BuildContext context, ref) { Widget build(BuildContext context, ref) {
final mediaQuery = MediaQuery.of(context);
final playlistNotifier = ref.watch(ProxyPlaylistNotifier.notifier);
final playlist = ref.watch(ProxyPlaylistNotifier.provider);
final controller = useAutoScrollController(); final controller = useAutoScrollController();
final searchText = useState(''); final searchText = useState('');
@ -105,135 +108,153 @@ class PlayerQueue extends HookConsumerWidget {
return const NotFound(vertical: true); return const NotFound(vertical: true);
} }
return LayoutBuilder(builder: (context, constrains) { return LayoutBuilder(
return ClipRRect( builder: (context, constrains) {
borderRadius: borderRadius, return ClipRRect(
clipBehavior: Clip.hardEdge, borderRadius: borderRadius,
child: BackdropFilter( clipBehavior: Clip.hardEdge,
filter: ImageFilter.blur( child: BackdropFilter(
sigmaX: 15, filter: ImageFilter.blur(
sigmaY: 15, sigmaX: 15,
), sigmaY: 15,
child: Container(
padding: const EdgeInsets.only(
top: 5.0,
), ),
decoration: BoxDecoration( child: Container(
color: theme.colorScheme.surfaceVariant.withOpacity(0.5), padding: const EdgeInsets.only(
borderRadius: borderRadius, top: 5.0,
), ),
child: CallbackShortcuts( decoration: BoxDecoration(
bindings: { color: theme.colorScheme.surfaceVariant.withOpacity(0.5),
LogicalKeySet(LogicalKeyboardKey.escape): () { borderRadius: borderRadius,
if (!isSearching.value) { ),
Navigator.of(context).pop(); child: CallbackShortcuts(
bindings: {
LogicalKeySet(LogicalKeyboardKey.escape): () {
if (!isSearching.value) {
Navigator.of(context).pop();
}
isSearching.value = false;
searchText.value = '';
} }
isSearching.value = false; },
searchText.value = ''; child: InterScrollbar(
} controller: controller,
}, child: CustomScrollView(
child: Column( controller: controller,
children: [ slivers: [
if (!floating) if (!floating)
Container( SliverToBoxAdapter(
height: 5, child: Center(
width: 100, child: Container(
margin: const EdgeInsets.only(bottom: 5, top: 2), height: 5,
decoration: BoxDecoration( width: 100,
color: headlineColor, margin: const EdgeInsets.only(bottom: 5, top: 2),
borderRadius: BorderRadius.circular(20), decoration: BoxDecoration(
), color: headlineColor,
), borderRadius: BorderRadius.circular(20),
Row( ),
crossAxisAlignment: CrossAxisAlignment.center,
mainAxisAlignment: MainAxisAlignment.center,
children: [
if (constrains.mdAndUp || !isSearching.value) ...[
const SizedBox(width: 10),
Text(
context.l10n.tracks_in_queue(tracks.length),
style: TextStyle(
color: headlineColor,
fontWeight: FontWeight.bold,
fontSize: 18,
),
),
const Spacer(),
],
if (constrains.mdAndUp || isSearching.value)
TextField(
onChanged: (value) {
searchText.value = value;
},
decoration: InputDecoration(
hintText: context.l10n.search,
isDense: true,
prefixIcon: constrains.smAndDown
? IconButton(
icon: const Icon(
Icons.arrow_back_ios_new_outlined,
),
onPressed: () {
isSearching.value = false;
searchText.value = '';
},
style: IconButton.styleFrom(
padding: EdgeInsets.zero,
minimumSize: const Size.square(20),
),
)
: const Icon(SpotubeIcons.filter),
constraints: BoxConstraints(
maxHeight: 40,
maxWidth: constrains.smAndDown
? constrains.maxWidth - 40
: 300,
), ),
), ),
)
else
IconButton.filledTonal(
icon: const Icon(SpotubeIcons.filter),
onPressed: () {
isSearching.value = !isSearching.value;
},
), ),
if (constrains.mdAndUp || !isSearching.value) ...[ SliverAppBar(
const SizedBox(width: 10), floating: true,
FilledButton( pinned: false,
style: FilledButton.styleFrom( snap: false,
backgroundColor: backgroundColor: Colors.transparent,
theme.scaffoldBackgroundColor.withOpacity(0.5), elevation: 0,
foregroundColor: automaticallyImplyLeading: !isSearching.value,
theme.textTheme.headlineSmall?.color, title: BackdropFilter(
filter: ImageFilter.blur(
sigmaX: 10,
sigmaY: 10,
), ),
child: Row( child: SizedBox(
children: [ height: kToolbarHeight,
const Icon(SpotubeIcons.playlistRemove), child: mediaQuery.mdAndUp || !isSearching.value
const SizedBox(width: 5), ? Align(
Text(context.l10n.clear_all), alignment: Alignment.centerLeft,
], child: Text(
context.l10n
.tracks_in_queue(tracks.length),
style: TextStyle(
color: headlineColor,
fontWeight: FontWeight.bold,
fontSize: 18,
),
),
)
: null,
), ),
onPressed: () {
onStop();
Navigator.of(context).pop();
},
), ),
const SizedBox(width: 10), actions: [
], if (mediaQuery.mdAndUp || isSearching.value)
], TextField(
), onChanged: (value) {
const SizedBox(height: 10), searchText.value = value;
if (!isSearching.value && searchText.value.isEmpty) },
Flexible( decoration: InputDecoration(
child: ReorderableListView.builder( hintText: context.l10n.search,
isDense: true,
prefixIcon: mediaQuery.smAndDown
? IconButton(
icon: const Icon(
Icons.arrow_back_ios_new_outlined,
),
onPressed: () {
isSearching.value = false;
searchText.value = '';
},
style: IconButton.styleFrom(
padding: EdgeInsets.zero,
minimumSize: const Size.square(20),
),
)
: const Icon(SpotubeIcons.filter),
constraints: BoxConstraints(
maxHeight: 40,
maxWidth: mediaQuery.smAndDown
? mediaQuery.size.width - 40
: 300,
),
),
)
else
IconButton.filledTonal(
icon: const Icon(SpotubeIcons.filter),
onPressed: () {
isSearching.value = !isSearching.value;
},
),
if (mediaQuery.mdAndUp || !isSearching.value) ...[
const SizedBox(width: 10),
FilledButton(
style: FilledButton.styleFrom(
backgroundColor: theme.scaffoldBackgroundColor
.withOpacity(0.5),
foregroundColor:
theme.textTheme.headlineSmall?.color,
),
child: Row(
children: [
const Icon(SpotubeIcons.playlistRemove),
const SizedBox(width: 5),
Text(context.l10n.clear_all),
],
),
onPressed: () {
playlistNotifier.stop();
Navigator.of(context).pop();
},
),
const SizedBox(width: 10),
],
],
),
const SliverGap(10),
SliverReorderableList(
onReorder: (oldIndex, newIndex) { onReorder: (oldIndex, newIndex) {
onReorder(oldIndex, newIndex); playlistNotifier.moveTrack(oldIndex, newIndex);
}, },
scrollController: controller, itemCount: filteredTracks.length,
itemCount: tracks.length + 1,
shrinkWrap: true,
buildDefaultDragHandles: false,
onReorderStart: (index) { onReorderStart: (index) {
HapticFeedback.selectionClick(); HapticFeedback.selectionClick();
}, },
@ -241,83 +262,50 @@ class PlayerQueue extends HookConsumerWidget {
HapticFeedback.selectionClick(); HapticFeedback.selectionClick();
}, },
itemBuilder: (context, i) { itemBuilder: (context, i) {
if (i == tracks.length) { final track = filteredTracks.elementAt(i);
return AutoScrollTag(
index: i,
controller: controller,
key: const ValueKey('end'),
child: const Gap(100),
);
}
final track = tracks.elementAt(i);
return AutoScrollTag( return AutoScrollTag(
key: ValueKey(i), key: ValueKey<int>(i),
controller: controller, controller: controller,
index: i, index: i,
child: Padding( child: Material(
padding: color: Colors.transparent,
const EdgeInsets.symmetric(horizontal: 8.0),
child: TrackTile( child: TrackTile(
playlist: playlist,
index: i, index: i,
track: track, track: track,
playlist: playlist,
onTap: () async { onTap: () async {
if (playlist.activeTrack?.id == track.id) { if (playlist.activeTrack?.id == track.id) {
return; return;
} }
onJump(track); await playlistNotifier.jumpToTrack(track);
}, },
leadingActions: [ leadingActions: [
ReorderableDragStartListener( if (!isSearching.value &&
index: i, searchText.value.isEmpty)
child: const Icon(SpotubeIcons.dragHandle), Padding(
), padding: const EdgeInsets.only(left: 8.0),
child: ReorderableDragStartListener(
index: i,
child: const Icon(
SpotubeIcons.dragHandle,
),
),
),
], ],
), ),
), ),
); );
}, },
), ),
) const SliverGap(100),
else ],
Flexible( ),
child: InterScrollbar( ),
controller: controller,
child: ListView.builder(
controller: controller,
itemCount: filteredTracks.length + 1,
itemBuilder: (context, i) {
if (i == filteredTracks.length) {
return const Gap(100);
}
final track = filteredTracks.elementAt(i);
return Padding(
padding:
const EdgeInsets.symmetric(horizontal: 8.0),
child: TrackTile(
index: i,
playlist: playlist,
track: track,
onTap: () async {
if (playlist.activeTrack?.id == track.id) {
return;
}
onJump(track);
},
),
);
},
),
),
),
],
), ),
), ),
), ),
), );
); },
}); );
} }
} }