Files
edde746 352b88109b refactor: extract shared mixins and helpers, drop dead abstractions
Introduces shared seams for paginated views, D-pad reorder, media control
routing, async singletons and the device method channel, then points the
open-coded copies at them.

Also removes unused models and duplicated provider/server plumbing, folds
the twice-implemented artifact store in the server, and factors the
repeated Flutter toolchain prologue in CI into a composite action.
2026-07-26 06:09:48 +02:00

67 lines
2.8 KiB
Dart

import 'package:flutter/widgets.dart';
import 'package:material_symbols_icons/symbols.dart';
import '../media/media_hub.dart';
/// Leading icon for a hub row, shared by every surface that renders hubs from
/// the same backend rows (Discover and a library's Recommended tab).
///
/// Continue Watching is matched on the hub key first so synthesized rows and
/// section-specific `*.inprogress.*` hubs are covered, then on title for
/// backends whose resume row is only recognizable by name (Plex "On Deck").
/// Everything else is keyword-matched on the title; the first match wins, so
/// the more specific keywords are checked before the broader ones.
IconData hubIconFor(MediaHub hub) {
final title = hub.title.toLowerCase();
if (hub.isContinueWatchingHub || title.contains('continue watching') || title.contains('on deck')) {
return Symbols.play_circle_rounded;
}
for (final (keywords, icon) in _titleKeywordIcons) {
if (keywords.any(title.contains)) return icon;
}
return _defaultHubIcon;
}
const _defaultHubIcon = Symbols.auto_awesome_rounded;
/// Title keywords in match order — see [hubIconFor].
const _titleKeywordIcons = <(List<String>, IconData)>[
// Trending/Popular
(['trending'], Symbols.trending_up_rounded),
(['popular', 'imdb'], Symbols.whatshot_rounded),
// Seasonal/Time-based
(['seasonal'], Symbols.calendar_month_rounded),
(['newly', 'new release'], Symbols.new_releases_rounded),
(['recently released', 'recent'], Symbols.schedule_rounded),
// Top/Rated
(['top rated', 'highest rated'], Symbols.star_rounded),
(['top '], Symbols.military_tech_rounded),
// Genre-specific
(['thriller'], Symbols.warning_amber_rounded),
(['comedy', 'comedier'], Symbols.mood_rounded),
(['action'], Symbols.flash_on_rounded),
(['drama'], Symbols.theater_comedy_rounded),
(['fantasy'], Symbols.auto_fix_high_rounded),
(['science', 'sci-fi'], Symbols.rocket_launch_rounded),
(['horror', 'skräck'], Symbols.nights_stay_rounded),
(['romance', 'romantic'], Symbols.favorite_border_rounded),
(['adventure', 'äventyr'], Symbols.explore_rounded),
// Watchlist/Playlists
(['playlist', 'watchlist'], Symbols.playlist_play_rounded),
(['unwatched', 'unplayed'], Symbols.visibility_off_rounded),
(['watched', 'played'], Symbols.visibility_rounded),
// Network/Studio
(['network', 'more from'], Symbols.tv_rounded),
// Actor/Director
(['actor', 'director'], Symbols.person_rounded),
// Decades (80s, 90s, etc.)
(['80', '90', '00'], Symbols.history_rounded),
// Rediscover/Start Watching
(['rediscover', 'start watching'], Symbols.play_arrow_rounded),
// Broad library-hub keywords, last so the specific rows above keep their icons.
(['rated'], Symbols.star_rounded),
(['recommended'], Symbols.thumb_up_rounded),
(['genre'], Symbols.category_rounded),
];