-
Notifications
You must be signed in to change notification settings - Fork 24
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat: Implement basic structure for the lyric display components
- Loading branch information
Showing
23 changed files
with
475 additions
and
28 deletions.
There are no files selected for viewing
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
export '../screens/lyrics/lyrics.dart'; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,25 @@ | ||
import 'package:fluent_ui/fluent_ui.dart'; | ||
|
||
class BandScreenLyricsView extends StatefulWidget { | ||
const BandScreenLyricsView({super.key}); | ||
|
||
@override | ||
LibraryHomeListState createState() => LibraryHomeListState(); | ||
} | ||
|
||
class LibraryHomeListState extends State<BandScreenLyricsView> { | ||
@override | ||
void dispose() { | ||
super.dispose(); | ||
} | ||
|
||
@override | ||
void initState() { | ||
super.initState(); | ||
} | ||
|
||
@override | ||
Widget build(BuildContext context) { | ||
return Container(); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,106 @@ | ||
import 'package:provider/provider.dart'; | ||
import 'package:fluent_ui/fluent_ui.dart'; | ||
|
||
import '../../utils/rune_log.dart'; | ||
import '../../utils/api/get_lyric_by_track_id.dart'; | ||
import '../../widgets/navigation_bar/page_content_frame.dart'; | ||
import '../../messages/all.dart'; | ||
import '../../providers/status.dart'; | ||
import '../../providers/responsive_providers.dart'; | ||
|
||
import 'band_screen_lyrics.dart'; | ||
import 'widgets/lyrics_layout.dart'; | ||
|
||
class LyricsPage extends StatefulWidget { | ||
const LyricsPage({super.key}); | ||
|
||
@override | ||
State<LyricsPage> createState() => _LyricsPageState(); | ||
} | ||
|
||
class _LyricsPageState extends State<LyricsPage> { | ||
int _cachedTrackId = -1; | ||
Future<List<LyricContentLine>>? _lyric; | ||
|
||
late PlaybackStatusProvider playbackStatus; | ||
|
||
@override | ||
void didChangeDependencies() { | ||
super.didChangeDependencies(); | ||
|
||
playbackStatus = | ||
Provider.of<PlaybackStatusProvider>(context, listen: false); | ||
|
||
playbackStatus.addListener(_handlePlaybackStatusUpdate); | ||
_handlePlaybackStatusUpdate(); | ||
} | ||
|
||
@override | ||
void dispose() { | ||
super.dispose(); | ||
playbackStatus.removeListener(_handlePlaybackStatusUpdate); | ||
} | ||
|
||
_handlePlaybackStatusUpdate() { | ||
if (_cachedTrackId != playbackStatus.playbackStatus.id) { | ||
setState(() { | ||
final id = playbackStatus.playbackStatus.id; | ||
_cachedTrackId = id; | ||
_lyric = getLyricByTrackId(id); | ||
}); | ||
} | ||
} | ||
|
||
int _selectProgress(BuildContext context, PlaybackStatusProvider status) { | ||
return (status.playbackStatus.progressSeconds * 1000).round(); | ||
} | ||
|
||
@override | ||
Widget build(BuildContext context) { | ||
return FutureBuilder( | ||
future: _lyric, | ||
builder: (context, snapshot) { | ||
if (snapshot.data == null) return Container(); | ||
|
||
for (final line in snapshot.data!) { | ||
info$(line.sections.map((x) => x.content).join("")); | ||
} | ||
|
||
return Selector<PlaybackStatusProvider, int>( | ||
selector: _selectProgress, | ||
builder: (context, currentTimeMilliseconds, child) { | ||
final List<int> activeLines = []; | ||
|
||
for (final (index, line) in snapshot.data!.indexed) { | ||
if (currentTimeMilliseconds > line.startTime && | ||
currentTimeMilliseconds < line.endTime) { | ||
activeLines.add(index); | ||
} | ||
} | ||
|
||
return DeviceTypeBuilder( | ||
deviceType: const [ | ||
DeviceType.band, | ||
DeviceType.dock, | ||
DeviceType.zune, | ||
DeviceType.tv | ||
], | ||
builder: (context, activeBreakpoint) { | ||
if (activeBreakpoint == DeviceType.dock || | ||
activeBreakpoint == DeviceType.band) { | ||
return const PageContentFrame(child: BandScreenLyricsView()); | ||
} | ||
|
||
return LyricsLayout( | ||
lyrics: snapshot.data!, | ||
currentTimeMilliseconds: currentTimeMilliseconds, | ||
activeLines: activeLines, | ||
); | ||
}, | ||
); | ||
}, | ||
); | ||
}, | ||
); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,34 @@ | ||
import 'package:fluent_ui/fluent_ui.dart'; | ||
|
||
import '../../../messages/all.dart'; | ||
|
||
import 'lyric_line.dart'; | ||
|
||
class LyricsDisplay extends StatelessWidget { | ||
final List<LyricContentLine> lyrics; | ||
final int currentTimeMilliseconds; | ||
final List<int> activeLines; | ||
|
||
const LyricsDisplay({ | ||
super.key, | ||
required this.lyrics, | ||
required this.currentTimeMilliseconds, | ||
required this.activeLines, | ||
}); | ||
|
||
@override | ||
Widget build(BuildContext context) { | ||
return ListView.builder( | ||
itemCount: lyrics.length, | ||
itemBuilder: (context, index) { | ||
final line = lyrics[index]; | ||
return LyricLine( | ||
key: ValueKey(index), | ||
sections: line.sections, | ||
currentTimeMilliseconds: currentTimeMilliseconds, | ||
isActive: activeLines.contains(index), | ||
); | ||
}, | ||
); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,73 @@ | ||
import 'package:fluent_ui/fluent_ui.dart'; | ||
|
||
import '../../../messages/all.dart'; | ||
|
||
class LyricLine extends StatelessWidget { | ||
final List<LyricContentLineSection> sections; | ||
final int currentTimeMilliseconds; | ||
final bool isActive; | ||
|
||
const LyricLine({ | ||
super.key, | ||
required this.sections, | ||
required this.currentTimeMilliseconds, | ||
required this.isActive, | ||
}); | ||
|
||
double calculateProgress() { | ||
if (!isActive) return 0.0; | ||
|
||
double totalDuration = 0; | ||
double currentProgress = 0; | ||
|
||
for (final section in sections) { | ||
final duration = section.endTime - section.startTime; | ||
totalDuration += duration; | ||
|
||
if (currentTimeMilliseconds >= section.endTime) { | ||
currentProgress += duration; | ||
} else if (currentTimeMilliseconds > section.startTime) { | ||
currentProgress += (currentTimeMilliseconds - section.startTime); | ||
} | ||
} | ||
|
||
return totalDuration > 0 ? (currentProgress / totalDuration) : 0.0; | ||
} | ||
|
||
@override | ||
Widget build(BuildContext context) { | ||
final progress = calculateProgress(); | ||
final text = sections.map((s) => s.content).join(""); | ||
final theme = FluentTheme.of(context); | ||
|
||
return Container( | ||
padding: const EdgeInsets.symmetric(vertical: 4.0, horizontal: 16.0), | ||
child: Stack( | ||
children: [ | ||
// Highlighten text | ||
Text( | ||
text, | ||
style: TextStyle( | ||
fontSize: 20, | ||
color: theme.resources.textFillColorPrimary, | ||
), | ||
), | ||
// Non-highlighten text | ||
ClipRect( | ||
child: Align( | ||
alignment: Alignment.centerLeft, | ||
widthFactor: progress, | ||
child: Text( | ||
text, | ||
style: TextStyle( | ||
fontSize: 18, | ||
color: theme.resources.textFillColorPrimary.withAlpha(160), | ||
), | ||
), | ||
), | ||
), | ||
], | ||
), | ||
); | ||
} | ||
} |
Oops, something went wrong.