improve player screen with blurred album art

ui improvements in lyrics screen
animated bars when track is playing
fix back button when player screen is open
instantly pop when track is changed in queue list
This commit is contained in:
Pato05 2024-04-29 16:23:22 +02:00
parent 8ea6bcd073
commit 4b5d0bd09c
No known key found for this signature in database
GPG key ID: F53CA394104BA0CB
9 changed files with 287 additions and 292 deletions

View file

@ -1,51 +0,0 @@
import 'dart:math';
import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart';
class AnimatedBars extends StatefulWidget {
final double size;
final Color? color;
const AnimatedBars({
super.key,
this.size = 24.0,
this.color,
});
@override
State<AnimatedBars> createState() => _AnimatedBarsState();
}
class _AnimatedBarsState extends State<AnimatedBars>
with TickerProviderStateMixin {
late final _controller = AnimationController(
vsync: this, duration: const Duration(milliseconds: 1000))
..repeat(reverse: true);
@override
void dispose() {
_controller.dispose();
super.dispose();
}
@override
Widget build(BuildContext context) {
final color = widget.color ?? Theme.of(context).colorScheme.onSurface;
const count = 3;
AnimatedIcons.search_ellipsis;
return SizedBox.square(
dimension: widget.size,
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: List.generate(
count,
(index) => SizedBox(
width: widget.size / count,
child: Align(
alignment: Alignment.bottomCenter,
child: Container(color: color),
),
)),
));
}
}

View file

@ -71,106 +71,110 @@ class FancyScaffoldState extends State<FancyScaffold>
begin: widget.bottomPanelHeight / MediaQuery.of(context).size.height, begin: widget.bottomPanelHeight / MediaQuery.of(context).size.height,
end: 1.0, end: 1.0,
).animate(dragController); ).animate(dragController);
return Stack( return ValueListenableBuilder(
children: [ valueListenable: statusNotifier,
Positioned.fill( builder: (context, state, child) => PopScope(
child: Scaffold( canPop: state != AnimationStatus.dismissed,
body: widget.navigationRail != null onPopInvoked: state == AnimationStatus.dismissed
? Row(children: [ ? null
widget.navigationRail!, : (_) => dragController.fling(velocity: -1.0),
const VerticalDivider( child: child!),
indent: 0.0, child: Stack(
endIndent: 0.0, children: [
width: 2.0, Positioned.fill(
child: Scaffold(
body: widget.navigationRail != null
? Row(children: [
widget.navigationRail!,
const VerticalDivider(
indent: 0.0,
endIndent: 0.0,
width: 2.0,
),
Expanded(child: widget.body)
])
: widget.body,
drawer: widget.drawer,
bottomNavigationBar: Column(
mainAxisSize: MainAxisSize.min,
children: [
SizedBox(height: widget.bottomPanelHeight),
if (widget.bottomNavigationBar != null)
SizeTransition(
axisAlignment: -1.0,
sizeFactor:
Tween(begin: 1.0, end: 0.0).animate(sizeAnimation),
child: widget.bottomNavigationBar,
), ),
Expanded(child: widget.body) ],
]) ),
: widget.body,
drawer: widget.drawer,
bottomNavigationBar: Column(
mainAxisSize: MainAxisSize.min,
children: [
SizedBox(height: widget.bottomPanelHeight),
if (widget.bottomNavigationBar != null)
SizeTransition(
axisAlignment: -1.0,
sizeFactor:
Tween(begin: 1.0, end: 0.0).animate(sizeAnimation),
child: widget.bottomNavigationBar,
),
],
), ),
), ),
), Positioned(
Positioned( bottom: 0,
bottom: 0, left: 0,
left: 0, right: 0,
right: 0, child: AnimatedBuilder(
child: AnimatedBuilder( animation: sizeAnimation,
animation: sizeAnimation, builder: (context, child) {
builder: (context, child) { final x = 1.0 - sizeAnimation.value;
final x = 1.0 - sizeAnimation.value; return Padding(
return Padding( padding: EdgeInsets.only(
padding: EdgeInsets.only( bottom: (defaultBottomPadding /*+ 8.0*/) * x,
bottom: (defaultBottomPadding /*+ 8.0*/) * x, //right: 8.0 * x,
//right: 8.0 * x, //left: 8.0 * x,
//left: 8.0 * x, ),
),
child: child,
);
},
child: ValueListenableBuilder(
valueListenable: statusNotifier,
builder: (context, state, child) {
return GestureDetector(
onVerticalDragEnd: _onVerticalDragEnd,
onVerticalDragUpdate: _onVerticalDragUpdate,
child: child, child: child,
); );
}, },
child: SizeTransition( child: ValueListenableBuilder(
sizeFactor: sizeAnimation, valueListenable: statusNotifier,
axisAlignment: -1.0, builder: (context, state, child) {
axis: Axis.vertical, return GestureDetector(
child: SizedBox( onVerticalDragEnd: _onVerticalDragEnd,
height: screenHeight, onVerticalDragUpdate: _onVerticalDragUpdate,
width: MediaQuery.of(context).size.width, child: child,
child: ValueListenableBuilder( );
valueListenable: statusNotifier, },
builder: (context, state, _) => Stack( child: SizeTransition(
children: [ sizeFactor: sizeAnimation,
if (state != AnimationStatus.dismissed) axisAlignment: -1.0,
PopScope( axis: Axis.vertical,
canPop: false, child: SizedBox(
onPopInvoked: (_) => height: screenHeight,
dragController.fling(velocity: -1.0), width: MediaQuery.of(context).size.width,
child: Positioned.fill( child: ValueListenableBuilder(
valueListenable: statusNotifier,
builder: (context, state, _) => Stack(
children: [
if (state != AnimationStatus.dismissed)
Positioned.fill(
key: const Key('player_screen'), key: const Key('player_screen'),
child: widget.expandedPanel, child: widget.expandedPanel,
), ),
), if (state != AnimationStatus.completed)
if (state != AnimationStatus.completed) Positioned(
Positioned( top: 0,
top: 0, right: 0,
right: 0, left: 0,
left: 0, key: const Key('player_bar'),
key: const Key('player_bar'), child: FadeTransition(
child: FadeTransition( opacity: Tween(begin: 1.0, end: 0.0)
opacity: Tween(begin: 1.0, end: 0.0) .animate(dragController),
.animate(dragController), child: SizedBox(
child: SizedBox( height: widget.bottomPanelHeight,
height: widget.bottomPanelHeight, child: widget.bottomPanel),
child: widget.bottomPanel), ),
), ),
), ],
], ),
), ),
), )),
)), ),
), ),
), ),
), ],
], ),
); );
} }

View file

@ -248,14 +248,23 @@ class HomepageRowSection extends StatelessWidget {
final HomePageSection section; final HomePageSection section;
const HomepageRowSection(this.section, {super.key}); const HomepageRowSection(this.section, {super.key});
Widget buildChild(BuildContext context, List<HomePageItem> items) { Widget buildChild(BuildContext context, List<HomePageItem> items,
return Row( {bool hasMore = false}) {
children: items return Row(children: [
.map((item) => Padding( ...items.map((item) => Padding(
padding: const EdgeInsets.symmetric(horizontal: 6.0), padding: const EdgeInsets.symmetric(horizontal: 6.0),
child: HomePageItemWidget(item), child: HomePageItemWidget(item),
)) )),
.toList(growable: false)); if (hasMore)
TextButton(
onPressed: () => Navigator.of(context).pushRoute(
builder: (context) => HomePageScreen(
title: section.title!,
channel: DeezerChannel(target: section.pagePath),
),
),
child: Text('Show more'.i18n))
]);
} }
List<List<T>> _sliceInNLists<T>(List<T> source, int n) { List<List<T>> _sliceInNLists<T>(List<T> source, int n) {
@ -279,15 +288,37 @@ class HomepageRowSection extends StatelessWidget {
children: _sliceInNLists(section.items!, 3) children: _sliceInNLists(section.items!, 3)
.map((e) => buildChild(context, e)) .map((e) => buildChild(context, e))
.toList(growable: false)), .toList(growable: false)),
_ => buildChild(context, section.items!) _ =>
buildChild(context, section.items!, hasMore: section.hasMore ?? false)
}; };
return ListTile( return ListTile(
title: Text( title: InkWell(
section.title ?? '', onTap: section.hasMore == true
textAlign: TextAlign.left, ? () => Navigator.of(context).pushRoute(
maxLines: 2, builder: (context) => HomePageScreen(
overflow: TextOverflow.ellipsis, title: section.title!,
style: const TextStyle(fontSize: 20.0, fontWeight: FontWeight.w900), channel: DeezerChannel(target: section.pagePath),
),
)
: null,
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Expanded(
child: Text(
section.title ?? '',
textAlign: TextAlign.left,
maxLines: 2,
overflow: TextOverflow.ellipsis,
style:
const TextStyle(fontSize: 20.0, fontWeight: FontWeight.w900),
)),
if (section.hasMore == true) ...[
const SizedBox(width: 16.0),
const Icon(Icons.keyboard_arrow_right),
],
],
),
), ),
subtitle: Scrollbar( subtitle: Scrollbar(
thickness: MainScreen.of(context).isDesktop ? null : 1.0, thickness: MainScreen.of(context).isDesktop ? null : 1.0,
@ -296,17 +327,6 @@ class HomepageRowSection extends StatelessWidget {
child: child, child: child,
), ),
), ),
trailing: section.hasMore == true
? const Icon(Icons.keyboard_arrow_right)
: null,
onTap: section.hasMore == true
? () => Navigator.of(context).pushRoute(
builder: (context) => HomePageScreen(
title: section.title!,
channel: DeezerChannel(target: section.pagePath),
),
)
: null,
); );
} }
} }

View file

@ -1,7 +1,9 @@
import 'dart:async'; import 'dart:async';
import 'dart:collection';
import 'package:audio_service/audio_service.dart'; import 'package:audio_service/audio_service.dart';
import 'package:dio/dio.dart'; import 'package:dio/dio.dart';
import 'package:fading_edge_scrollview/fading_edge_scrollview.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter/scheduler.dart'; import 'package:flutter/scheduler.dart';
import 'package:freezer/api/definitions.dart'; import 'package:freezer/api/definitions.dart';
@ -12,6 +14,7 @@ import 'package:freezer/translations.i18n.dart';
import 'package:freezer/ui/error.dart'; import 'package:freezer/ui/error.dart';
import 'package:freezer/ui/player_bar.dart'; import 'package:freezer/ui/player_bar.dart';
import 'package:freezer/ui/player_screen.dart'; import 'package:freezer/ui/player_screen.dart';
import 'package:mini_music_visualizer/mini_music_visualizer.dart';
class LyricsScreen extends StatelessWidget { class LyricsScreen extends StatelessWidget {
const LyricsScreen({super.key}); const LyricsScreen({super.key});
@ -21,11 +24,10 @@ class LyricsScreen extends StatelessWidget {
return PlayerScreenBackground( return PlayerScreenBackground(
enabled: settings.playerBackgroundOnLyrics, enabled: settings.playerBackgroundOnLyrics,
appBar: AppBar( appBar: AppBar(
title: Text('Lyrics'.i18n),
systemOverlayStyle: PlayerScreenBackground.getSystemUiOverlayStyle( systemOverlayStyle: PlayerScreenBackground.getSystemUiOverlayStyle(
context, context,
enabled: settings.playerBackgroundOnLyrics), enabled: settings.playerBackgroundOnLyrics),
backgroundColor: Colors.transparent, forceMaterialTransparency: true,
), ),
child: const Column( child: const Column(
children: [ children: [
@ -48,7 +50,7 @@ class _LyricsWidgetState extends State<LyricsWidget>
with WidgetsBindingObserver { with WidgetsBindingObserver {
StreamSubscription? _mediaItemSub; StreamSubscription? _mediaItemSub;
StreamSubscription? _positionSub; StreamSubscription? _positionSub;
int? _currentIndex = -1; int _currentIndex = -1;
Duration _nextOffset = Duration.zero; Duration _nextOffset = Duration.zero;
Duration _currentOffset = Duration.zero; Duration _currentOffset = Duration.zero;
String? _currentTrackId; String? _currentTrackId;
@ -68,6 +70,9 @@ class _LyricsWidgetState extends State<LyricsWidget>
bool _showTranslation = false; bool _showTranslation = false;
bool _availableTranslation = false; bool _availableTranslation = false;
// each individual lyric widget's height, either computed or cached
final _lyricHeights = HashMap<int, double>();
Future<void> _loadForId(String trackId) async { Future<void> _loadForId(String trackId) async {
if (_currentTrackId == trackId) return; if (_currentTrackId == trackId) return;
_currentTrackId = trackId; _currentTrackId = trackId;
@ -137,7 +142,7 @@ class _LyricsWidgetState extends State<LyricsWidget>
} else { } else {
final widgetHeight = _widgetConstraints!.maxHeight; final widgetHeight = _widgetConstraints!.maxHeight;
final minScroll = actualHeight * _currentIndex!; final minScroll = actualHeight * _currentIndex!;
scrollTo = minScroll - widgetHeight / 2 + height / 2; scrollTo = minScroll + height / 2;
} }
if (scrollTo < 0.0) scrollTo = 0.0; if (scrollTo < 0.0) scrollTo = 0.0;
@ -157,10 +162,10 @@ class _LyricsWidgetState extends State<LyricsWidget>
if (position < _nextOffset && position > _currentOffset) return; if (position < _nextOffset && position > _currentOffset) return;
_currentIndex = _currentIndex =
_lyrics?.lyrics?.lastIndexWhere((l) => l.offset! <= position); _lyrics?.lyrics?.lastIndexWhere((l) => l.offset! <= position) ?? -1;
if (_currentIndex! < 0) return; if (_currentIndex < 0) return;
if (_currentIndex! < _lyrics!.lyrics!.length - 1) { if (_currentIndex < _lyrics!.lyrics!.length - 1) {
// update nextOffset // update nextOffset
_nextOffset = _lyrics!.lyrics![_currentIndex! + 1].offset!; _nextOffset = _lyrics!.lyrics![_currentIndex! + 1].offset!;
} else { } else {
@ -208,7 +213,6 @@ class _LyricsWidgetState extends State<LyricsWidget>
@override @override
void didChangeAppLifecycleState(AppLifecycleState state) { void didChangeAppLifecycleState(AppLifecycleState state) {
print('fuck? $state');
switch (state) { switch (state) {
case AppLifecycleState.paused: case AppLifecycleState.paused:
_cancelSubscriptions(); _cancelSubscriptions();
@ -240,59 +244,49 @@ class _LyricsWidgetState extends State<LyricsWidget>
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
final textColor =
settings.playerBackgroundOnLyrics && settings.blurPlayerBackground
? Theme.of(context).brightness == Brightness.light
? Colors.black87
: Colors.white70
: Theme.of(context).colorScheme.onBackground;
return Stack( return Stack(
children: [ children: [
Column(children: [ _error != null
if (_freeScroll && !_loading) ? ErrorScreen(message: _error.toString())
Center( :
child: TextButton( // Loading lyrics
onPressed: () { _loading
setState(() => _freeScroll = false); ? const Center(child: CircularProgressIndicator())
_scrollToLyric(); : LayoutBuilder(builder: (context, constraints) {
}, _widgetConstraints = constraints;
style: ButtonStyle( return NotificationListener<ScrollStartNotification>(
foregroundColor: MaterialStateProperty.all(Colors.white)), onNotification: (notification) {
child: Text( if (!_syncedLyrics) return false;
_currentIndex! >= 0 final extentDiff =
? (_lyrics?.lyrics?[_currentIndex!].text ?? '...') (notification.metrics.extentBefore -
: '...', notification.metrics.extentAfter)
textAlign: TextAlign.center, .abs();
)), // avoid accidental clicks
), const extentThreshold = 10.0;
Expanded( if (extentDiff >= extentThreshold &&
child: _error != null !_animatedScroll &&
? !_loading &&
//Shouldn't really happen, empty lyrics have own text !_freeScroll) {
ErrorScreen(message: _error.toString()) setState(() => _freeScroll = true);
: }
// Loading lyrics return false;
_loading },
? const Center(child: CircularProgressIndicator()) child: ScrollConfiguration(
: LayoutBuilder(builder: (context, constraints) { behavior: _scrollBehavior,
_widgetConstraints = constraints; child: FadingEdgeScrollView.fromScrollView(
return NotificationListener<ScrollStartNotification>( gradientFractionOnStart: 0.25,
onNotification: gradientFractionOnEnd: 0.25,
(ScrollStartNotification notification) {
if (!_syncedLyrics) return false;
final extentDiff =
(notification.metrics.extentBefore -
notification.metrics.extentAfter)
.abs();
// avoid accidental clicks
const extentThreshold = 10.0;
if (extentDiff >= extentThreshold &&
!_animatedScroll &&
!_loading &&
!_freeScroll) {
setState(() => _freeScroll = true);
}
return false;
},
child: ScrollConfiguration(
behavior: _scrollBehavior,
child: ListView.builder( child: ListView.builder(
padding: const EdgeInsets.symmetric( padding: EdgeInsets.symmetric(
horizontal: 8.0), horizontal: 8.0,
vertical: constraints.maxHeight / 2 -
height / 2),
controller: _controller, controller: _controller,
itemExtent: !_syncedLyrics itemExtent: !_syncedLyrics
? null ? null
@ -300,8 +294,22 @@ class _LyricsWidgetState extends State<LyricsWidget>
(_showTranslation (_showTranslation
? additionalTranslationHeight ? additionalTranslationHeight
: 0.0), : 0.0),
itemCount: _lyrics!.lyrics!.length, itemCount: _lyrics!.lyrics!.length + 1,
itemBuilder: (BuildContext context, int i) { itemBuilder: (BuildContext context, int i) {
if (i-- == 0) {
return SizedBox(
height: height,
child: Center(
child: SizedBox(
width: 8.0 * 3 + 6.0,
child: MiniMusicVisualizer(
color: textColor,
width: 8.0,
height: 16.0,
animate: _currentIndex == -1,
),
)));
}
return DecoratedBox( return DecoratedBox(
decoration: BoxDecoration( decoration: BoxDecoration(
borderRadius: borderRadius:
@ -312,15 +320,22 @@ class _LyricsWidgetState extends State<LyricsWidget>
), ),
child: InkWell( child: InkWell(
borderRadius: borderRadius:
BorderRadius.circular(8.0), BorderRadius.circular(12.0),
onTap: _syncedLyrics && onTap: _syncedLyrics &&
_lyrics!.id != null _lyrics!.id != null
? () => audioHandler.seek( ? () => audioHandler.seek(
_lyrics!.lyrics![i].offset!) _lyrics!.lyrics![i].offset!)
: null, : null,
child: Center( child: Padding(
padding:
const EdgeInsets.symmetric(
horizontal: 4.0,
//vertical: 24.0,
),
child: Column( child: Column(
mainAxisSize: MainAxisSize.min, mainAxisSize: MainAxisSize.min,
mainAxisAlignment:
MainAxisAlignment.center,
children: [ children: [
Text( Text(
_lyrics!.lyrics![i].text!, _lyrics!.lyrics![i].text!,
@ -328,6 +343,7 @@ class _LyricsWidgetState extends State<LyricsWidget>
? TextAlign.center ? TextAlign.center
: TextAlign.start, : TextAlign.start,
style: TextStyle( style: TextStyle(
color: textColor,
fontSize: _syncedLyrics fontSize: _syncedLyrics
? 26.0 ? 26.0
: 20.0, : 20.0,
@ -357,25 +373,35 @@ class _LyricsWidgetState extends State<LyricsWidget>
), ),
))); )));
}, },
))); ))));
}), }),
),
]),
if (_availableTranslation) if (_availableTranslation)
Align( Positioned(
alignment: Alignment.bottomCenter, bottom: 16.0,
child: Padding( left: 0,
padding: const EdgeInsets.only(bottom: 8.0), right: 0,
child: ElevatedButton( child: Center(
onPressed: () { child: ElevatedButton(
setState(() => _showTranslation = !_showTranslation); onPressed: () {
SchedulerBinding.instance setState(() => _showTranslation = !_showTranslation);
.addPostFrameCallback((_) => _scrollToLyric()); SchedulerBinding.instance
}, .addPostFrameCallback((_) => _scrollToLyric());
child: Text(_showTranslation },
? 'Without translation'.i18n child: Text(_showTranslation
: 'With translation'.i18n)), ? 'Without translation'.i18n
)), : 'With translation'.i18n)),
),
),
if (_freeScroll)
Positioned(
bottom: 16.0,
right: 16.0,
child: FloatingActionButton(
child: const Icon(Icons.sync),
onPressed: () => setState(() {
_freeScroll = false;
_scrollToLyric();
})))
], ],
); );
} }

View file

@ -163,12 +163,15 @@ class PlayerScreenBackground extends StatelessWidget {
Widget _buildChild( Widget _buildChild(
BuildContext context, BackgroundProvider provider, Widget child) { BuildContext context, BackgroundProvider provider, Widget child) {
final isLightMode = Theme.of(context).brightness == Brightness.light;
return Stack(children: [ return Stack(children: [
if (provider.imageProvider != null || settings.colorGradientBackground) if (provider.imageProvider != null || settings.colorGradientBackground)
Positioned.fill( Positioned.fill(
child: provider.imageProvider != null child: provider.imageProvider != null
? DecoratedBox( ? DecoratedBox(
decoration: const BoxDecoration(color: Colors.black), decoration: BoxDecoration(
color: Color.lerp(provider.dominantColor,
isLightMode ? Colors.white : Colors.black, 0.75)),
child: ImageFiltered( child: ImageFiltered(
imageFilter: ImageFilter.blur( imageFilter: ImageFilter.blur(
tileMode: TileMode.decal, tileMode: TileMode.decal,
@ -180,10 +183,7 @@ class PlayerScreenBackground extends StatelessWidget {
image: DecorationImage( image: DecorationImage(
image: provider.imageProvider!, image: provider.imageProvider!,
fit: BoxFit.cover, fit: BoxFit.cover,
colorFilter: ColorFilter.mode( opacity: 0.35,
Colors.white
.withOpacity(settings.isDark ? 0.55 : 0.75),
BlendMode.dstATop),
)), )),
), ),
), ),

View file

@ -170,11 +170,10 @@ class _QueueListWidgetState extends State<QueueListWidget> {
trailing: ReorderableDragStartListener( trailing: ReorderableDragStartListener(
index: index, child: const Icon(Icons.drag_handle)), index: index, child: const Icon(Icons.drag_handle)),
onTap: () { onTap: () {
audioHandler.skipToQueueItem(index).then((value) { if (widget.shouldPopOnTap) {
if (widget.shouldPopOnTap) { Navigator.pop(context);
Navigator.of(context).pop(); }
} audioHandler.skipToQueueItem(index);
});
}, },
onSecondary: (details) => menuSheet.defaultTrackMenu( onSecondary: (details) => menuSheet.defaultTrackMenu(
Track.fromMediaItem(mediaItem), Track.fromMediaItem(mediaItem),

View file

@ -8,7 +8,7 @@ import 'package:freezer/api/player/player_helper.dart';
import 'package:freezer/icons.dart'; import 'package:freezer/icons.dart';
import 'package:freezer/main.dart'; import 'package:freezer/main.dart';
import 'package:freezer/translations.i18n.dart'; import 'package:freezer/translations.i18n.dart';
import 'package:freezer/ui/animated_bars.dart'; import 'package:mini_music_visualizer/mini_music_visualizer.dart';
import '../api/definitions.dart'; import '../api/definitions.dart';
import 'cached_image.dart'; import 'cached_image.dart';
@ -107,15 +107,6 @@ class TrackCardTile extends StatelessWidget {
), ),
), ),
); );
ListTile(
title: Text(title),
subtitle: Text(artist),
leading: Stack(
children: [CachedImage(url: artUri), PlayItemButton(onTap: onTap)],
),
contentPadding: const EdgeInsets.only(left: 16.0, right: 124.0),
onTap: onTap,
);
} }
} }
@ -209,34 +200,39 @@ class TrackTile extends StatelessWidget {
artist, artist,
maxLines: 1, maxLines: 1,
), ),
leading: CachedImage( leading: StreamBuilder<MediaItem?>(
url: artUri, initialData: audioHandler.mediaItem.value,
width: 48.0, stream: audioHandler.mediaItem,
height: 48.0, builder: (context, snapshot) {
), final child = CachedImage(
// StreamBuilder<MediaItem?>( url: artUri,
// initialData: audioHandler.mediaItem.value, width: 48.0,
// stream: audioHandler.mediaItem, height: 48.0,
// builder: (context, snapshot) { );
// final child = CachedImage(
// url: artUri, if (snapshot.data?.id == trackId) {
// width: 48.0, return Stack(children: [
// height: 48.0, child,
// ); Positioned.fill(
// child: DecoratedBox(
// if (snapshot.data?.id == trackId) { decoration: const BoxDecoration(color: Colors.black26),
// return Stack(children: [ child: Center(
// child, child: SizedBox(
// const Positioned.fill( width: 18.0,
// child: DecoratedBox( height: 16.0,
// decoration: BoxDecoration(color: Colors.black26), child: StreamBuilder<bool>(
// child: AnimatedBars()), stream: playerHelper.playing,
// ), builder: (context, snapshot) {
// ]); return MiniMusicVisualizer(
// } color: Colors.white70,
// animate: snapshot.data ?? false);
// return child; })),
// }), )),
),
]);
}
return child;
}),
onTap: onTap, onTap: onTap,
onLongPress: normalizeSecondary(onSecondary), onLongPress: normalizeSecondary(onSecondary),
trailing: Row( trailing: Row(

View file

@ -371,7 +371,7 @@ packages:
source: hosted source: hosted
version: "2.0.5" version: "2.0.5"
fading_edge_scrollview: fading_edge_scrollview:
dependency: transitive dependency: "direct main"
description: description:
name: fading_edge_scrollview name: fading_edge_scrollview
sha256: c25c2231652ce774cc31824d0112f11f653881f43d7f5302c05af11942052031 sha256: c25c2231652ce774cc31824d0112f11f653881f43d7f5302c05af11942052031

View file

@ -115,6 +115,7 @@ dependencies:
freezed_annotation: freezed_annotation:
^2.4.1 ^2.4.1
mini_music_visualizer: ^1.1.0 mini_music_visualizer: ^1.1.0
fading_edge_scrollview: ^3.0.0
#deezcryptor: #deezcryptor:
#path: deezcryptor/ #path: deezcryptor/