mirror of
https://github.com/zarzet/SpotiFLAC-Mobile.git
synced 2026-09-29 12:52:13 +02:00
feat(albums): show formatted editorial descriptions
This commit is contained in:
@@ -0,0 +1,145 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
||||
import 'package:flutter_test/flutter_test.dart';
|
||||
import 'package:spotiflac_android/l10n/l10n.dart';
|
||||
import 'package:spotiflac_android/theme/mornye_theme.dart';
|
||||
import 'package:spotiflac_android/utils/editorial_notes.dart';
|
||||
import 'package:spotiflac_android/widgets/album_description.dart';
|
||||
|
||||
void main() {
|
||||
test(
|
||||
'editorial notes prefer full text and fall back to a usable summary',
|
||||
() {
|
||||
expect(
|
||||
albumDescriptionFromMetadata({
|
||||
'editorial_notes': {
|
||||
'standard': '<p>Full notes.</p>',
|
||||
'short': 'Short notes.',
|
||||
},
|
||||
}),
|
||||
'<p>Full notes.</p>',
|
||||
);
|
||||
expect(
|
||||
albumDescriptionFromMetadata({
|
||||
'editorial_notes': {
|
||||
'standard': '<p> </p>',
|
||||
'short': 'Short notes.',
|
||||
},
|
||||
}),
|
||||
'Short notes.',
|
||||
);
|
||||
expect(
|
||||
albumDescriptionFromMetadata({'description': 'Plain notes.'}),
|
||||
'Plain notes.',
|
||||
);
|
||||
expect(albumDescriptionFromMetadata({'editorial_notes': null}), isNull);
|
||||
expect(albumDescriptionFromMetadata({'editorial_notes': 42}), isNull);
|
||||
expect(
|
||||
albumDescriptionFromMetadata({
|
||||
'editorial_notes': {'standard': '<script>hidden</script>'},
|
||||
}),
|
||||
isNull,
|
||||
);
|
||||
},
|
||||
);
|
||||
|
||||
for (final style in ['mornye-light', 'mornye-dark', 'material']) {
|
||||
testWidgets('album description opens a formatted reading sheet ($style)', (
|
||||
tester,
|
||||
) async {
|
||||
await tester.binding.setSurfaceSize(const Size(393, 700));
|
||||
addTearDown(() => tester.binding.setSurfaceSize(null));
|
||||
final mornye = style.startsWith('mornye');
|
||||
await tester.pumpWidget(
|
||||
ProviderScope(
|
||||
child: MaterialApp(
|
||||
theme: mornye
|
||||
? MornyeTheme.build(
|
||||
style.endsWith('light')
|
||||
? Brightness.light
|
||||
: Brightness.dark,
|
||||
)
|
||||
: ThemeData(),
|
||||
localizationsDelegates: AppLocalizations.localizationsDelegates,
|
||||
supportedLocales: AppLocalizations.supportedLocales,
|
||||
home: Navigator(
|
||||
onGenerateRoute: (_) => MaterialPageRoute<void>(
|
||||
builder: (_) => Scaffold(
|
||||
body: AlbumDescription(
|
||||
title: 'Example Album',
|
||||
description:
|
||||
'A <i>new direction</i> & a <b>bold sound</b>.\n\n'
|
||||
'A second paragraph.\nOne line break remains.\n\n'
|
||||
'${List.filled(12, '<p>The artists explore melodies and new ideas in these songs.</p>').join()}'
|
||||
'<p>Final paragraph.</p><script>hidden script</script>',
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
await tester.pumpAndSettle();
|
||||
final preview = tester.widget<Text>(
|
||||
find.byWidgetPredicate(
|
||||
(widget) => widget is Text && widget.textSpan != null,
|
||||
),
|
||||
);
|
||||
expect(preview.maxLines, 2);
|
||||
expect(
|
||||
preview.textSpan!.toPlainText(),
|
||||
contains('new direction & a bold sound.\n\n'),
|
||||
);
|
||||
expect(preview.textSpan!.toPlainText(), isNot(contains('hidden script')));
|
||||
expect(
|
||||
preview.textSpan!.toPlainText(),
|
||||
contains('sound.\n\nA second paragraph.\nOne line break remains.\n\n'),
|
||||
);
|
||||
|
||||
Iterable<TextSpan> spans(InlineSpan span) sync* {
|
||||
if (span is TextSpan) {
|
||||
yield span;
|
||||
for (final child in span.children ?? <InlineSpan>[]) {
|
||||
yield* spans(child);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
expect(
|
||||
spans(preview.textSpan!).any(
|
||||
(span) =>
|
||||
span.style?.fontStyle == FontStyle.italic &&
|
||||
span.toPlainText() == 'new direction',
|
||||
),
|
||||
isTrue,
|
||||
);
|
||||
|
||||
await tester.tap(find.text(mornye ? 'MORE' : 'More'));
|
||||
await tester.pumpAndSettle();
|
||||
expect(find.text('Example Album'), findsOneWidget);
|
||||
expect(find.byType(SelectionArea), findsOneWidget);
|
||||
expect(
|
||||
ModalRoute.of(tester.element(find.byType(SelectionArea)))!.navigator,
|
||||
tester.state<NavigatorState>(find.byType(Navigator).first),
|
||||
);
|
||||
expect(find.byTooltip('Close').hitTestable(), findsOneWidget);
|
||||
await tester.drag(
|
||||
find.byType(SingleChildScrollView),
|
||||
const Offset(0, -600),
|
||||
);
|
||||
await tester.pumpAndSettle();
|
||||
final scroll = tester.state<ScrollableState>(
|
||||
find.descendant(
|
||||
of: find.byType(SingleChildScrollView),
|
||||
matching: find.byType(Scrollable),
|
||||
),
|
||||
);
|
||||
expect(scroll.position.pixels, greaterThan(0));
|
||||
expect(find.byTooltip('Close').hitTestable(), findsOneWidget);
|
||||
await tester.tap(find.byTooltip('Close'));
|
||||
await tester.pumpAndSettle();
|
||||
expect(find.byType(SelectionArea), findsNothing);
|
||||
expect(tester.takeException(), isNull);
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -11,6 +11,7 @@ import 'package:spotiflac_android/screens/album_screen.dart';
|
||||
import 'package:spotiflac_android/screens/home_tab.dart';
|
||||
import 'package:spotiflac_android/services/platform_bridge.dart';
|
||||
import 'package:spotiflac_android/theme/mornye_theme.dart';
|
||||
import 'package:spotiflac_android/widgets/album_description.dart';
|
||||
import 'package:spotiflac_android/widgets/audio_quality_badges.dart';
|
||||
import 'package:spotiflac_android/widgets/track_list_tile.dart';
|
||||
|
||||
@@ -54,6 +55,10 @@ void main() {
|
||||
'name': fetchedName,
|
||||
'artists': 'Example Artist',
|
||||
'total_tracks': 1,
|
||||
'editorial_notes': {
|
||||
'standard': '<p>A <i>new direction</i> for the band.</p>',
|
||||
'short': 'A new direction.',
|
||||
},
|
||||
};
|
||||
final tracks = [
|
||||
{
|
||||
@@ -89,6 +94,10 @@ void main() {
|
||||
final expected = fetchedName.trim().isEmpty ? 'Album' : fetchedName;
|
||||
final album = tester.widget<AlbumScreen>(find.byType(AlbumScreen));
|
||||
expect(album.albumName, expected);
|
||||
expect(
|
||||
album.description,
|
||||
'<p>A <i>new direction</i> for the band.</p>',
|
||||
);
|
||||
expect(album.tracks!.single.albumName, expected);
|
||||
expect(find.text(expected), findsWidgets);
|
||||
expect(requests, 1);
|
||||
@@ -124,7 +133,7 @@ void main() {
|
||||
'audio_modes': 'DOLBY_ATMOS',
|
||||
'explicit': true,
|
||||
};
|
||||
var albumRequested = false;
|
||||
var albumRequests = 0;
|
||||
TestDefaultBinaryMessengerBinding.instance.defaultBinaryMessenger
|
||||
.setMockMethodCallHandler(channel, (call) async {
|
||||
if (call.method == 'getProviderMetadata') {
|
||||
@@ -133,7 +142,7 @@ void main() {
|
||||
'resource_type': 'album',
|
||||
'resource_id': 'metadata-album',
|
||||
});
|
||||
albumRequested = true;
|
||||
albumRequests++;
|
||||
return jsonEncode({
|
||||
'track_list': [payload],
|
||||
'album_info': {
|
||||
@@ -141,6 +150,7 @@ void main() {
|
||||
'total_tracks': 1,
|
||||
'album_type': 'album',
|
||||
'audio_traits': ['lossless', 'dolby_atmos'],
|
||||
'editorial_notes': {'standard': '<p>A new direction.</p>'},
|
||||
},
|
||||
});
|
||||
}
|
||||
@@ -156,22 +166,22 @@ void main() {
|
||||
expect(searchTrack.label, 'Example Label');
|
||||
expect(searchTrack.copyright, 'Example Copyright');
|
||||
|
||||
await tester.pumpWidget(
|
||||
ProviderScope(
|
||||
child: MaterialApp(
|
||||
theme: MornyeTheme.build(Brightness.light),
|
||||
localizationsDelegates: AppLocalizations.localizationsDelegates,
|
||||
supportedLocales: AppLocalizations.supportedLocales,
|
||||
home: const AlbumScreen(
|
||||
albumId: 'metadata-album',
|
||||
albumName: 'Example Album',
|
||||
extensionId: 'example-metadata',
|
||||
),
|
||||
final page = ProviderScope(
|
||||
child: MaterialApp(
|
||||
theme: MornyeTheme.build(Brightness.light),
|
||||
localizationsDelegates: AppLocalizations.localizationsDelegates,
|
||||
supportedLocales: AppLocalizations.supportedLocales,
|
||||
home: const AlbumScreen(
|
||||
albumId: 'metadata-album',
|
||||
albumName: 'Example Album',
|
||||
extensionId: 'example-metadata',
|
||||
),
|
||||
),
|
||||
);
|
||||
await tester.pumpWidget(page);
|
||||
await tester.pumpAndSettle();
|
||||
expect(albumRequested, isTrue);
|
||||
expect(albumRequests, 1);
|
||||
expect(find.byType(AlbumDescription), findsOneWidget);
|
||||
final albumTrack = tester
|
||||
.widget<TrackListTile>(find.byType(TrackListTile).first)
|
||||
.track;
|
||||
@@ -193,5 +203,16 @@ void main() {
|
||||
expect(find.byType(ExplicitBadge), findsOneWidget);
|
||||
await tester.pumpWidget(const SizedBox());
|
||||
await tester.pumpAndSettle();
|
||||
await tester.pumpWidget(page);
|
||||
await tester.pumpAndSettle();
|
||||
expect(albumRequests, 1);
|
||||
expect(
|
||||
tester
|
||||
.widget<AlbumDescription>(find.byType(AlbumDescription))
|
||||
.description,
|
||||
'<p>A new direction.</p>',
|
||||
);
|
||||
await tester.pumpWidget(const SizedBox());
|
||||
await tester.pumpAndSettle();
|
||||
});
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user