mirror of
https://github.com/zarzet/SpotiFLAC-Mobile.git
synced 2026-09-29 04:42:02 +02:00
fix(artist): restore artwork accents with neutral portrait fallback
This commit is contained in:
@@ -88,7 +88,7 @@ extension _ArtistScreenSections on _ArtistScreenState {
|
||||
icon: CupertinoIcons.square_arrow_up,
|
||||
buttonSize: 50,
|
||||
iconSize: 24,
|
||||
iconColor: Colors.white,
|
||||
iconColor: colorScheme.primary,
|
||||
glassTintColor: Colors.white,
|
||||
glassTintOpacity: 0.10,
|
||||
tooltip: context.l10n.openInOtherServices,
|
||||
@@ -102,7 +102,7 @@ extension _ArtistScreenSections on _ArtistScreenState {
|
||||
CupertinoButton(
|
||||
padding: EdgeInsets.zero,
|
||||
borderRadius: BorderRadius.circular(37),
|
||||
color: Colors.white,
|
||||
color: colorScheme.primary,
|
||||
onPressed: () =>
|
||||
_showDiscographyOptions(context, colorScheme, albums),
|
||||
child: SizedBox.square(
|
||||
@@ -112,7 +112,7 @@ extension _ArtistScreenSections on _ArtistScreenState {
|
||||
child: Icon(
|
||||
CupertinoIcons.arrow_down,
|
||||
size: 34,
|
||||
color: colorScheme.surface,
|
||||
color: colorScheme.onPrimary,
|
||||
),
|
||||
),
|
||||
),
|
||||
@@ -123,7 +123,7 @@ extension _ArtistScreenSections on _ArtistScreenState {
|
||||
: CupertinoIcons.star,
|
||||
buttonSize: 50,
|
||||
iconSize: 24,
|
||||
iconColor: Colors.white,
|
||||
iconColor: colorScheme.primary,
|
||||
glassTintColor: Colors.white,
|
||||
glassTintOpacity: 0.10,
|
||||
tooltip: isFavoriteArtist
|
||||
|
||||
@@ -90,16 +90,19 @@ class _MornyeArtistSurfaceState extends State<MornyeArtistSurface> {
|
||||
final logoColor = logo == null
|
||||
? null
|
||||
: CoverPalette.sourceColor(logo, Brightness.dark);
|
||||
// Keep the artwork accent for colorful portraits. A neutral
|
||||
// portrait can acquire a blue Material accent; use white there,
|
||||
// while allowing an explicit logo color to take precedence.
|
||||
final primary = widget.neutralActions
|
||||
? Colors.white
|
||||
: logoColor ?? palette.primary;
|
||||
: logoColor ?? (useAccent ? palette.primary : Colors.white);
|
||||
final primaryLuminance = primary.computeLuminance();
|
||||
final surfaceContrast =
|
||||
(primaryLuminance + 0.05) /
|
||||
(surface.computeLuminance() + 0.05);
|
||||
final onPrimary = widget.neutralActions
|
||||
? Colors.black
|
||||
: logoColor == null
|
||||
: logoColor == null && useAccent
|
||||
? palette.onPrimary
|
||||
: surfaceContrast >= 4.5
|
||||
? surface
|
||||
|
||||
@@ -12,6 +12,78 @@ import 'package:spotiflac_android/widgets/collection_scaffold.dart';
|
||||
import 'package:spotiflac_android/widgets/mornye_artist_header.dart';
|
||||
|
||||
void main() {
|
||||
testWidgets('artist actions preserve artwork and logo accents', (
|
||||
tester,
|
||||
) async {
|
||||
final directory = Directory.systemTemp.createTempSync('artist-palette-');
|
||||
addTearDown(() => directory.deleteSync(recursive: true));
|
||||
final neutralCover = File('${directory.path}/neutral.png');
|
||||
final coloredCover = File('${directory.path}/colored.png');
|
||||
final whiteLogo = File('${directory.path}/white-logo.png');
|
||||
final coloredLogo = File('${directory.path}/colored-logo.png');
|
||||
await tester.runAsync(() async {
|
||||
for (final (file, color, isLogo) in [
|
||||
(neutralCover, const Color(0xff9da4a9), false),
|
||||
(coloredCover, Colors.deepOrange, false),
|
||||
(whiteLogo, Colors.white, true),
|
||||
(coloredLogo, Colors.amber, true),
|
||||
]) {
|
||||
final recorder = ui.PictureRecorder();
|
||||
final canvas = Canvas(recorder);
|
||||
canvas.drawRect(
|
||||
isLogo
|
||||
? const Rect.fromLTWH(20, 40, 60, 20)
|
||||
: const Rect.fromLTWH(0, 0, 100, 100),
|
||||
Paint()..color = color,
|
||||
);
|
||||
final picture = recorder.endRecording();
|
||||
final image = await picture.toImage(100, 100);
|
||||
final bytes = await image.toByteData(format: ui.ImageByteFormat.png);
|
||||
image.dispose();
|
||||
picture.dispose();
|
||||
await file.writeAsBytes(bytes!.buffer.asUint8List());
|
||||
await CoverPalette.resolve(file.path, Brightness.dark);
|
||||
}
|
||||
});
|
||||
final artworkAccent = CoverPalette.peek(
|
||||
coloredCover.path,
|
||||
Brightness.dark,
|
||||
)!.primary;
|
||||
expect(artworkAccent, isNot(Colors.white));
|
||||
for (final brightness in Brightness.values) {
|
||||
for (final (cover, logo, expected) in [
|
||||
(neutralCover, null, Colors.white),
|
||||
(coloredCover, null, artworkAccent),
|
||||
(coloredCover, whiteLogo, Colors.white),
|
||||
(neutralCover, coloredLogo, Colors.amber),
|
||||
]) {
|
||||
await tester.pumpWidget(
|
||||
MaterialApp(
|
||||
theme: MornyeTheme.build(brightness),
|
||||
home: MornyeArtistSurface(
|
||||
imageSource: cover.path,
|
||||
logoSource: logo?.path,
|
||||
child: const Text('Artist action'),
|
||||
),
|
||||
),
|
||||
);
|
||||
await tester.pumpAndSettle();
|
||||
final scheme = Theme.of(
|
||||
tester.element(find.text('Artist action')),
|
||||
).colorScheme;
|
||||
expect(scheme.primary.toARGB32(), expected.toARGB32());
|
||||
final foreground = scheme.onPrimary.computeLuminance();
|
||||
final background = scheme.primary.computeLuminance();
|
||||
final contrast = foreground > background
|
||||
? (foreground + 0.05) / (background + 0.05)
|
||||
: (background + 0.05) / (foreground + 0.05);
|
||||
expect(contrast, greaterThanOrEqualTo(4.5));
|
||||
expect(tester.takeException(), isNull);
|
||||
}
|
||||
}
|
||||
await tester.pumpWidget(const SizedBox());
|
||||
});
|
||||
|
||||
testWidgets(
|
||||
'local and online album actions share the neutral cover surface',
|
||||
(tester) async {
|
||||
|
||||
Reference in New Issue
Block a user