fix(lyrics): keep V3 collaborations on the primary side

This commit is contained in:
zarzet committed 2026-09-27 15:26:11 +07:00
1 parent 608675a255
commit 6decce0f8b
5 files changed
+116 -45

No files matched your search

+14
View File
@@ -50,6 +50,20 @@ ${_tag('translation', 2000, 'Second translation')}
expect(backing.vocalGroup, lyrics.lines.first.vocalGroup);
});
test('V3 is a collaboration even without TTML group metadata', () {
for (final source in [
'[00:01.00]V1:Lead\n[00:02.00]V3:Together\n[00:03.00]V2:Guest',
'<tt xmlns:m="http://www.w3.org/ns/ttml#metadata"><body>'
'<p begin="1s" m:agent="v1">Lead</p>'
'<p begin="2s" m:agent="v3">Together</p>'
'<p begin="3s" m:agent="v2">Guest</p></body></tt>',
]) {
final lyrics = LyricsParser.parse(source);
expect(lyrics.lines[1].voice?.isGroup, isTrue);
expect(lyrics.lines[2].voice?.isGroup, isFalse);
}
});
test(
'backing groups survive sorting, offsets and repeated backing parts',
() {
+40 -39
View File
@@ -2707,50 +2707,51 @@ void main() {
}
for (final mornye in [false, true]) {
testWidgets('TTML group vocals keep the primary side ($mornye)', (
tester,
) async {
metadataOverrides['lyrics'] = '''
testWidgets(
'TTML V3 without group metadata keeps the primary side ($mornye)',
(tester) async {
metadataOverrides['lyrics'] = '''
<tt xmlns="http://www.w3.org/ns/ttml" xmlns:m="http://www.w3.org/ns/ttml#metadata">
<head><metadata><m:agent xml:id="v1" type="person"/><m:agent xml:id="v2" type="person"/><m:agent xml:id="v3" type="group"/></metadata></head>
<head><metadata><m:agent xml:id="v1" type="person"/><m:agent xml:id="v3" type="person"/><m:agent xml:id="v2" type="person"/></metadata></head>
<body><p begin="1s" end="3s" m:agent="v2">Guest</p><p begin="3s" end="6s" m:agent="v3">Together</p><p begin="6s" end="9s" m:agent="v2">Guest returns</p></body></tt>
''';
final playback = StreamController<PlaybackState>.broadcast();
addTearDown(playback.close);
await pumpNowPlaying(
tester,
theme: mornye ? MornyeTheme.build(Brightness.dark) : null,
size: const Size(390, 1100),
playbackEvents: playback.stream,
);
mediaItems.add(item('first'));
await tester.pumpAndSettle();
if (mornye) {
await tester.tap(find.byIcon(CupertinoIcons.quote_bubble));
} else {
await tester.drag(find.byType(PageView), const Offset(-350, 0));
}
await tester.pumpAndSettle();
for (final seconds in [0, 2, 4, 7, 4]) {
playback.add(
PlaybackState(
playing: false,
processingState: AudioProcessingState.ready,
updatePosition: Duration(seconds: seconds),
),
final playback = StreamController<PlaybackState>.broadcast();
addTearDown(playback.close);
await pumpNowPlaying(
tester,
theme: mornye ? MornyeTheme.build(Brightness.dark) : null,
size: const Size(390, 1100),
playbackEvents: playback.stream,
);
mediaItems.add(item('first'));
await tester.pumpAndSettle();
expect(
tester.widget<Text>(find.text('Together')).textAlign,
TextAlign.left,
);
expect(
tester.widget<Text>(find.text('Guest returns')).textAlign,
TextAlign.right,
);
}
expect(tester.takeException(), isNull);
});
if (mornye) {
await tester.tap(find.byIcon(CupertinoIcons.quote_bubble));
} else {
await tester.drag(find.byType(PageView), const Offset(-350, 0));
}
await tester.pumpAndSettle();
for (final seconds in [0, 2, 4, 7, 4]) {
playback.add(
PlaybackState(
playing: false,
processingState: AudioProcessingState.ready,
updatePosition: Duration(seconds: seconds),
),
);
await tester.pumpAndSettle();
expect(
tester.widget<Text>(find.text('Together')).textAlign,
TextAlign.left,
);
expect(
tester.widget<Text>(find.text('Guest returns')).textAlign,
TextAlign.right,
);
}
expect(tester.takeException(), isNull);
},
);
for (final ttml in [false, true]) {
testWidgets(