Skip to content

Commit fff7c41

Browse files
Various UI updates and dependency updates
1 parent 059b255 commit fff7c41

File tree

8 files changed

+753
-435
lines changed

8 files changed

+753
-435
lines changed

PLUGINS.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ As of update 1.3.0, Adiman now supports plugins.
1515
## Troubleshooting
1616
- Make sure that the plugin is enabled (this happens more than you think)
1717
- Make sure that settings are done right (this also happens more than you think)
18+
- Ensure that plugins in the folder have a valid wasm file or a non-broken link to the wasm file
1819
- Run the app through in a terminal (by simply running the path to the apps executable) and see if any errors get printed out
1920
- Fix the plugin yourself
2021
- Contact the plugin developer for help

lib/screens/music_player_screen.dart

Lines changed: 148 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -103,9 +103,12 @@ class _MusicPlayerScreenState extends State<MusicPlayerScreen>
103103

104104
List<Map<String, dynamic>> _songOptionsPluginButtons = [];
105105

106+
late GlobalKey<_LyricsOverlayState> _lyricsOverlayKey;
107+
106108
@override
107109
void initState() {
108110
super.initState();
111+
_lyricsOverlayKey = GlobalKey<_LyricsOverlayState>();
109112
rust_api.getCvol().then((volume) {
110113
if (mounted) {
111114
setState(() {
@@ -815,20 +818,20 @@ class _MusicPlayerScreenState extends State<MusicPlayerScreen>
815818
context: context,
816819
builder: (context) => AlertDialog(
817820
backgroundColor: dominantColor.withAlpha(30),
818-
title: Text('Delete Song?', style: TextStyle(color: Colors.white)),
821+
title: Text('Delete Song?', style: GoogleFonts.inter(color: Colors.white)),
819822
content: Text('This will permanently delete "${song.title}"',
820-
style: TextStyle(color: Colors.white70)),
823+
style: GoogleFonts.inter(color: Colors.white70)),
821824
actions: [
822825
TextButton(
823-
child: Text('Cancel', style: TextStyle(color: Colors.white70)),
826+
child: Text('Cancel', style: GoogleFonts.inter(color: Colors.white70)),
824827
onPressed: () {
825828
ScaffoldMessenger.of(context).hideCurrentSnackBar();
826829
Navigator.pop(context, false);
827830
},
828831
),
829832
TextButton(
830833
child:
831-
Text('Delete', style: TextStyle(color: Colors.redAccent)),
834+
Text('Delete', style: GoogleFonts.inter(color: Colors.redAccent)),
832835
onPressed: () {
833836
ScaffoldMessenger.of(context).hideCurrentSnackBar();
834837
Navigator.pop(context, true);
@@ -1113,6 +1116,7 @@ class _MusicPlayerScreenState extends State<MusicPlayerScreen>
11131116
await _updateDominantColor();
11141117
widget.service.updatePlaylist(widget.songList, currentIndex);
11151118
widget.service.updateMetadata();
1119+
return;
11161120
}
11171121
}
11181122
}
@@ -1140,6 +1144,10 @@ class _MusicPlayerScreenState extends State<MusicPlayerScreen>
11401144
currentSong.duration.inSeconds.toDouble(),
11411145
);
11421146
await rust_api.seekToPosition(position: seekPosition);
1147+
if (_showLyrics && _lyricsOverlayKey.currentState != null) {
1148+
_lyricsOverlayKey.currentState!.updateCurrentLyric();
1149+
_lyricsOverlayKey.currentState!.scrollToCurrentLyric();
1150+
}
11431151
//if (!isPlaying && mounted) {
11441152
// setState(() {
11451153
// isPlaying = true;
@@ -1230,6 +1238,9 @@ class _MusicPlayerScreenState extends State<MusicPlayerScreen>
12301238
await rust_api.playSong(path: currentSong.path);
12311239
await rust_api.preloadNextSong(
12321240
path: widget.songList[currentIndex + 1].path);
1241+
if (_showLyrics && _lyricsOverlayKey.currentState != null) {
1242+
_lyricsOverlayKey.currentState!.scrollToTop();
1243+
}
12331244
}
12341245

12351246
void _generateShuffleOrder() {
@@ -1764,31 +1775,88 @@ class _MusicPlayerScreenState extends State<MusicPlayerScreen>
17641775
const EdgeInsets.symmetric(horizontal: 32.0),
17651776
child: Column(
17661777
children: [
1767-
GlowText(
1768-
currentSong.title,
1769-
style: TextStyle(
1770-
color:
1771-
dominantColor.computeLuminance() > 0.01
1772-
? dominantColor
1773-
: Theme.of(context)
1774-
.textTheme
1775-
.bodyLarge
1776-
?.color,
1777-
fontSize: 28,
1778-
fontWeight: FontWeight.w700,
1779-
),
1780-
textAlign: TextAlign.center,
1781-
maxLines: 1,
1782-
overflow: TextOverflow.ellipsis,
1783-
),
1784-
const SizedBox(height: 4),
1785-
Text(
1786-
currentSong.artist,
1787-
style: TextStyle(
1788-
color: textColor.withValues(alpha: 0.8),
1789-
fontSize: 16,
1790-
),
1791-
),
1778+
Hero(
1779+
tag: 'title-${currentSong.path}',
1780+
flightShuttleBuilder: (flightContext, animation, flightDirection, fromHeroContext, toHeroContext) {
1781+
final textWidget = flightDirection == HeroFlightDirection.push
1782+
? toHeroContext.widget
1783+
: fromHeroContext.widget;
1784+
1785+
return AnimatedBuilder(
1786+
animation: animation,
1787+
builder: (context, child) {
1788+
return Transform.translate(
1789+
offset: Offset(0, -20 * (1 - animation.value)),
1790+
child: Opacity(
1791+
opacity: Tween<double>(begin: 0.0, end: 1.0)
1792+
.animate(CurvedAnimation(
1793+
parent: animation,
1794+
curve: Interval(0.5, 1.0),
1795+
))
1796+
.value,
1797+
child: child,
1798+
),
1799+
);
1800+
},
1801+
child: textWidget,
1802+
);
1803+
},
1804+
child: Material(
1805+
color: Colors.transparent,
1806+
child: GlowText(
1807+
currentSong.title,
1808+
style: TextStyle(
1809+
color: dominantColor.computeLuminance() > 0.01
1810+
? dominantColor
1811+
: Theme.of(context).textTheme.bodyLarge?.color,
1812+
fontSize: 28,
1813+
fontWeight: FontWeight.w700,
1814+
),
1815+
textAlign: TextAlign.center,
1816+
maxLines: 1,
1817+
overflow: TextOverflow.ellipsis,
1818+
),
1819+
),
1820+
),
1821+
const SizedBox(height: 4),
1822+
Hero(
1823+
tag: 'artist-${currentSong.path}',
1824+
flightShuttleBuilder: (flightContext, animation, flightDirection, fromHeroContext, toHeroContext) {
1825+
final textWidget = flightDirection == HeroFlightDirection.push
1826+
? toHeroContext.widget
1827+
: fromHeroContext.widget;
1828+
1829+
return AnimatedBuilder(
1830+
animation: animation,
1831+
builder: (context, child) {
1832+
return Transform.translate(
1833+
offset: Offset(0, -20 * (1 - animation.value)),
1834+
child: Opacity(
1835+
opacity: Tween<double>(begin: 0.0, end: 1.0)
1836+
.animate(CurvedAnimation(
1837+
parent: animation,
1838+
curve: Interval(0.6, 1.0),
1839+
))
1840+
.value,
1841+
child: child,
1842+
),
1843+
);
1844+
},
1845+
child: textWidget,
1846+
);
1847+
},
1848+
child: Material(
1849+
color: Colors.transparent,
1850+
child: Text(
1851+
currentSong.artist,
1852+
style: TextStyle(
1853+
color: textColor.withValues(alpha: 0.8),
1854+
fontSize: 16,
1855+
),
1856+
textAlign: TextAlign.center,
1857+
),
1858+
),
1859+
),
17921860
],
17931861
),
17941862
),
@@ -1900,7 +1968,8 @@ class _MusicPlayerScreenState extends State<MusicPlayerScreen>
19001968
Positioned.fill(
19011969
child: LyricsOverlay(
19021970
isPlaying: isPlaying,
1903-
key: ValueKey(currentSong.path),
1971+
//key: ValueKey(currentSong.path),
1972+
key: _lyricsOverlayKey,
19041973
lrc: _lrcData!,
19051974
currentPosition: Duration(
19061975
seconds: (_currentSliderValue *
@@ -2485,11 +2554,11 @@ class _LyricsOverlayState extends State<LyricsOverlay>
24852554
void initState() {
24862555
super.initState();
24872556
_initializeAnimations();
2488-
_currentLyricNotifier.addListener(_scrollToCurrentLyric);
2557+
_currentLyricNotifier.addListener(scrollToCurrentLyric);
24892558
_scrollController.addListener(_handleParallaxScroll);
2490-
_updateCurrentLyric();
2559+
updateCurrentLyric();
24912560
WidgetsBinding.instance.addPostFrameCallback((_) {
2492-
_scrollToCurrentLyric();
2561+
scrollToCurrentLyric();
24932562
});
24942563
}
24952564

@@ -2539,7 +2608,7 @@ class _LyricsOverlayState extends State<LyricsOverlay>
25392608
});
25402609
}
25412610

2542-
void _scrollToCurrentLyric() {
2611+
void scrollToCurrentLyric() {
25432612
final index = _currentLyricNotifier.value;
25442613
if (index >= 0 && _lyricKeys.containsKey(index)) {
25452614
final context = _lyricKeys[index]?.currentContext;
@@ -2551,6 +2620,20 @@ class _LyricsOverlayState extends State<LyricsOverlay>
25512620
alignment: 0.5, // Center the current lyric
25522621
);
25532622
}
2623+
} else if (index >= 0 && _scrollController.hasClients) {
2624+
// Scroll to estimated position if key is not available
2625+
final estimatedPosition = index * 85.0; // Approximate item height
2626+
final viewportHeight = _scrollController.position.viewportDimension;
2627+
2628+
// Always center the lyric in the viewport
2629+
final targetPos = (estimatedPosition - viewportHeight / 2 + 85.0 / 2)
2630+
.clamp(0.0, _scrollController.position.maxScrollExtent);
2631+
2632+
_scrollController.animateTo(
2633+
targetPos,
2634+
duration: const Duration(milliseconds: 800),
2635+
curve: Curves.easeOutQuint,
2636+
);
25542637
}
25552638
}
25562639

@@ -2565,6 +2648,15 @@ class _LyricsOverlayState extends State<LyricsOverlay>
25652648
return relativePosition * 20.0; // Parallax amount
25662649
}
25672650

2651+
void scrollToTop() {
2652+
_scrollController.animateTo(
2653+
0.0,
2654+
duration: const Duration(milliseconds: 300),
2655+
curve: Curves.easeOut,
2656+
);
2657+
_currentLyricNotifier.value = -1; // Reset current lyric highlight
2658+
}
2659+
25682660
@override
25692661
Widget build(BuildContext context) {
25702662
final breathingValue =
@@ -2800,7 +2892,13 @@ class _LyricsOverlayState extends State<LyricsOverlay>
28002892
@override
28012893
void didUpdateWidget(LyricsOverlay oldWidget) {
28022894
super.didUpdateWidget(oldWidget);
2803-
_updateCurrentLyric();
2895+
updateCurrentLyric();
2896+
2897+
if ((widget.currentPosition - oldWidget.currentPosition).inSeconds.abs() > 5) {
2898+
WidgetsBinding.instance.addPostFrameCallback((_) {
2899+
scrollToCurrentLyric();
2900+
});
2901+
}
28042902

28052903
if (widget.isPlaying != oldWidget.isPlaying) {
28062904
if (widget.isPlaying) {
@@ -2825,15 +2923,25 @@ class _LyricsOverlayState extends State<LyricsOverlay>
28252923
}
28262924
}
28272925

2828-
void _updateCurrentLyric() {
2926+
void updateCurrentLyric() {
28292927
int newIndex = -1;
2830-
for (var i = 0; i < widget.lrc.lyrics.length; i++) {
2831-
if (widget.lrc.lyrics[i].timestamp <= widget.currentPosition) {
2832-
newIndex = i;
2928+
final currentPos = widget.currentPosition;
2929+
2930+
var low = 0;
2931+
var high = widget.lrc.lyrics.length - 1;
2932+
2933+
while (low <= high) {
2934+
final mid = (low + high) ~/ 2;
2935+
final midTimestamp = widget.lrc.lyrics[mid].timestamp;
2936+
2937+
if (midTimestamp <= currentPos) {
2938+
newIndex = mid;
2939+
low = mid + 1;
28332940
} else {
2834-
break;
2941+
high = mid - 1;
28352942
}
28362943
}
2944+
28372945
if (newIndex != _currentLyricNotifier.value) {
28382946
_currentLyricNotifier.value = newIndex;
28392947
}

0 commit comments

Comments
 (0)