Four sections of the catalog detail screen spent more room than their data justified. Franchise relations drew one hub shelf per label. Real payloads make that absurd: MAL returns twelve relations for Attack on Titan across six labels, and "Side story" and "Sequel" each hold exactly one title, so each spent a header, a scroll row and one card. Flatten the labelled groups into one "Related titles" section of compact rows — poster thumb, label, title and year — that flow into columns on wide viewports. D-pad moves through the grid by index and still hands off to the cast strip above and the recommendations shelf below, which keeps its shelf because taste-based recommendations are meant to be browsed. Drop the MAL picture gallery. It was a horizontal strip of unfocusable poster variants of the title you are already looking at, and it cost a page-height of scroll; the `pictures` field comes back out of the detail request with it. Draw attributed scores behind their own brand mark where the source has one, the way the media detail screen already does: Rotten Tomatoes fresh/rotten and upright/spilled, IMDb and TMDB, each on the scale that source publishes. Sources with no mark (critic, audience, tracker scores) keep their written label. Plex's own badge state is derived from the 60% tomatometer threshold it encodes in `image.rating.ripe`. Flow the definition rows — original title, studios, country, budget, box office, crew — into two or three columns once the window is wide enough. A 1440-wide window drew a 140-pixel label, a short value and 1,000 pixels of nothing per fact. Verified against live MAL and Plex Discover payloads on macOS: the Attack on Titan page drops from 4,082 to 2,115 logical pixels, Dune: Part Two from 1,282 to 1,154.
48 lines
1.6 KiB
Dart
48 lines
1.6 KiB
Dart
import 'package:flutter/material.dart';
|
|
|
|
import 'app_icon.dart';
|
|
|
|
/// Small labeled pill (optionally with a leading icon): detail-screen stat
|
|
/// chips, request-sheet season status labels.
|
|
class StatChip extends StatelessWidget {
|
|
final IconData? icon;
|
|
final Color? iconColor;
|
|
final String label;
|
|
|
|
/// Leading artwork for chips whose source has a brand mark (rating badges).
|
|
/// Takes precedence over [icon].
|
|
final Widget? leading;
|
|
|
|
/// Overrides the default fill. Needed where the chip sits on a surface that
|
|
/// already uses `surfaceContainerHigh` — the mono theme collapses several
|
|
/// container roles onto one colour, so the default would be invisible.
|
|
final Color? backgroundColor;
|
|
|
|
const StatChip({super.key, this.icon, this.iconColor, required this.label, this.leading, this.backgroundColor});
|
|
|
|
@override
|
|
Widget build(BuildContext context) {
|
|
final theme = Theme.of(context);
|
|
return Container(
|
|
padding: const EdgeInsets.symmetric(horizontal: 10, vertical: 5),
|
|
decoration: BoxDecoration(
|
|
color: backgroundColor ?? theme.colorScheme.surfaceContainerHigh,
|
|
borderRadius: BorderRadius.circular(999),
|
|
),
|
|
child: Row(
|
|
mainAxisSize: MainAxisSize.min,
|
|
children: [
|
|
if (leading case final leading?) ...[
|
|
leading,
|
|
const SizedBox(width: 4),
|
|
] else if (icon != null) ...[
|
|
AppIcon(icon!, size: 14, fill: 1, color: iconColor),
|
|
const SizedBox(width: 4),
|
|
],
|
|
Text(label, style: theme.textTheme.labelMedium),
|
|
],
|
|
),
|
|
);
|
|
}
|
|
}
|