diff --git a/lib/core/anilist/translations.dart b/lib/core/anilist/translations.dart index 8272df8..1ac8edc 100644 --- a/lib/core/anilist/translations.dart +++ b/lib/core/anilist/translations.dart @@ -33,41 +33,28 @@ extension TenkaTypeAnilistUtils on TenkaType { } extension AnimeSeasonsTUtils on AnimeSeasons { - String getTitleCase(final Translation translation) { - switch (this) { - case AnimeSeasons.winter: - return translation.winter; - - case AnimeSeasons.spring: - return translation.spring; - - case AnimeSeasons.summer: - return translation.summer; - - case AnimeSeasons.fall: - return translation.fall; - } - } + String getTitleCase(final Translation translation) => switch (this) { + AnimeSeasons.winter => translation.winter, + AnimeSeasons.spring => translation.spring, + AnimeSeasons.summer => translation.summer, + AnimeSeasons.fall => translation.fall, + }; } extension AnilistMediaTUtils on AnilistMedia { - String getWatchtime(final Translation translation) { - switch (type) { - case AnilistMediaType.anime: - if (format == AnilistMediaFormat.movie) { - return duration != null + String getWatchtime(final Translation translation) => switch (type) { + AnilistMediaType.anime when format == AnilistMediaFormat.movie => + duration != null ? PrettyDurations.prettyHoursMinutesShort( translation, Duration(minutes: duration!), ) - : translation.nMins(Translation.unk); - } - return translation.nEps(episodes?.toString() ?? Translation.unk); - - case AnilistMediaType.manga: - return translation.nChs(chapters?.toString() ?? Translation.unk); - } - } + : translation.nMins(Translation.unk), + AnilistMediaType.anime => + translation.nEps(episodes?.toString() ?? Translation.unk), + AnilistMediaType.manga => + translation.nChs(chapters?.toString() ?? Translation.unk), + }; String get airdate { final String startDatePretty = startDate?.maybePretty ?? Translation.unk; @@ -88,65 +75,37 @@ extension AnilistCharacterRoleTUtils on AnilistCharacterRole { } extension AnilistMediaStatusTUtils on AnilistMediaStatus { - String getTitleCase(final Translation translation) { - switch (this) { - case AnilistMediaStatus.cancelled: - return translation.cancelled; - - case AnilistMediaStatus.releasing: - return translation.releasing; - - case AnilistMediaStatus.notYetReleased: - return translation.notYetReleased; - - case AnilistMediaStatus.finished: - return translation.finished; - - case AnilistMediaStatus.hiatus: - return translation.hiatus; - } - } + String getTitleCase(final Translation translation) => switch (this) { + AnilistMediaStatus.cancelled => translation.cancelled, + AnilistMediaStatus.releasing => translation.releasing, + AnilistMediaStatus.notYetReleased => translation.notYetReleased, + AnilistMediaStatus.finished => translation.finished, + AnilistMediaStatus.hiatus => translation.hiatus, + }; } -const Map _anilistMediaFormatTitleMap = - { - AnilistMediaFormat.tv: 'TV', - AnilistMediaFormat.tvShort: 'TV (Short)', - AnilistMediaFormat.movie: 'Movie', - AnilistMediaFormat.special: 'Special', - AnilistMediaFormat.ova: 'OVA', - AnilistMediaFormat.ona: 'ONA', - AnilistMediaFormat.music: 'Music', - AnilistMediaFormat.manga: 'Manga', - AnilistMediaFormat.novel: 'Novel', - AnilistMediaFormat.oneshot: 'OneShot', -}; - extension AnilistMediaFormatTUtils on AnilistMediaFormat { - String getTitleCase(final Translation translation) => - _anilistMediaFormatTitleMap[this]!; + String getTitleCase(final Translation translation) => switch (this) { + AnilistMediaFormat.tv => 'TV', + AnilistMediaFormat.tvShort => 'TV (Short)', + AnilistMediaFormat.movie => 'Movie', + AnilistMediaFormat.special => 'Special', + AnilistMediaFormat.ova => 'OVA', + AnilistMediaFormat.ona => 'ONA', + AnilistMediaFormat.music => 'Music', + AnilistMediaFormat.manga => 'Manga', + AnilistMediaFormat.novel => 'Novel', + AnilistMediaFormat.oneshot => 'OneShot', + }; } extension AnilistMediaListStatusTUtils on AnilistMediaListStatus { - String getTitleCase(final Translation translation) { - switch (this) { - case AnilistMediaListStatus.current: - return translation.current; - - case AnilistMediaListStatus.planning: - return translation.planning; - - case AnilistMediaListStatus.completed: - return translation.completed; - - case AnilistMediaListStatus.dropped: - return translation.dropped; - - case AnilistMediaListStatus.paused: - return translation.paused; - - case AnilistMediaListStatus.repeating: - return translation.repeating; - } - } + String getTitleCase(final Translation translation) => switch (this) { + AnilistMediaListStatus.current => translation.current, + AnilistMediaListStatus.planning => translation.planning, + AnilistMediaListStatus.completed => translation.completed, + AnilistMediaListStatus.dropped => translation.dropped, + AnilistMediaListStatus.paused => translation.paused, + AnilistMediaListStatus.repeating => translation.repeating, + }; } diff --git a/lib/core/database/settings/schema.dart b/lib/core/database/settings/schema.dart index d7bf8eb..e010f7d 100644 --- a/lib/core/database/settings/schema.dart +++ b/lib/core/database/settings/schema.dart @@ -1,5 +1,5 @@ import 'package:json_annotation/json_annotation.dart'; -import 'package:kazahana/ui/utils/relative_size.dart'; +import 'package:kazahana/ui/utils/relative_scale.dart'; import '../../utils/exports.dart'; part 'schema.g.dart'; diff --git a/lib/core/tenka/utils.dart b/lib/core/tenka/utils.dart index 72d4202..04603d3 100644 --- a/lib/core/tenka/utils.dart +++ b/lib/core/tenka/utils.dart @@ -2,13 +2,8 @@ import 'package:tenka/tenka.dart'; import '../translator/exports.dart'; extension TenkaTypeUtils on TenkaType { - String getTitleCase(final Translation translation) { - switch (this) { - case TenkaType.anime: - return translation.anime; - - case TenkaType.manga: - return translation.manga; - } - } + String getTitleCase(final Translation translation) => switch (this) { + TenkaType.anime => translation.anime, + TenkaType.manga => translation.manga, + }; } diff --git a/lib/core/themes/colors.dart b/lib/core/themes/colors.dart index 9359d6d..c882760 100644 --- a/lib/core/themes/colors.dart +++ b/lib/core/themes/colors.dart @@ -44,61 +44,28 @@ abstract class ForegroundColors { static List names() => colors.keys.toList(); - static String getTitleCase(final Translation translation, final String name) { - switch (name) { - case 'red': - return translation.red; - - case 'orange': - return translation.orange; - - case 'amber': - return translation.amber; - - case 'yellow': - return translation.yellow; - - case 'lime': - return translation.lime; - - case 'green': - return translation.green; - - case 'emerald': - return translation.emerald; - - case 'teal': - return translation.teal; - - case 'cyan': - return translation.cyan; - - case 'sky': - return translation.sky; - - case 'blue': - return translation.blue; - - case 'indigo': - return translation.indigo; - - case 'violet': - return translation.violet; - - case 'purple': - return translation.purple; - - case 'fuchsia': - return translation.fuchsia; - - case 'pink': - return translation.pink; - - case 'rose': - return translation.rose; - - default: - return name; - } - } + static String getTitleCase( + final Translation translation, + final String name, + ) => + switch (name) { + 'red' => translation.red, + 'orange' => translation.orange, + 'amber' => translation.amber, + 'yellow' => translation.yellow, + 'lime' => translation.lime, + 'green' => translation.green, + 'emerald' => translation.emerald, + 'teal' => translation.teal, + 'cyan' => translation.cyan, + 'sky' => translation.sky, + 'blue' => translation.blue, + 'indigo' => translation.indigo, + 'violet' => translation.violet, + 'purple' => translation.purple, + 'fuchsia' => translation.fuchsia, + 'pink' => translation.pink, + 'rose' => translation.rose, + _ => name, + }; } diff --git a/lib/ui/pages/_home/components/body.dart b/lib/ui/pages/_home/components/body.dart index a3f98b5..7d7eca6 100644 --- a/lib/ui/pages/_home/components/body.dart +++ b/lib/ui/pages/_home/components/body.dart @@ -59,9 +59,8 @@ class UnderScoreHomePageBody extends StatelessWidget { final UnderScoreHomePageProvider provider = context.watch(); - switch (provider.type) { - case TenkaType.anime: - return Column( + return switch (provider.type) { + TenkaType.anime => Column( key: const ValueKey(TenkaType.anime), mainAxisSize: MainAxisSize.min, crossAxisAlignment: CrossAxisAlignment.start, @@ -79,10 +78,8 @@ class UnderScoreHomePageBody extends StatelessWidget { results: provider.mostPopularAnime, ), ], - ); - - case TenkaType.manga: - return Column( + ), + TenkaType.manga => Column( key: const ValueKey(TenkaType.manga), mainAxisSize: MainAxisSize.min, crossAxisAlignment: CrossAxisAlignment.start, @@ -100,8 +97,8 @@ class UnderScoreHomePageBody extends StatelessWidget { results: provider.mostPopularManga, ), ], - ); - } + ), + }; } @override diff --git a/lib/ui/pages/anilist/components/body/profile/body.dart b/lib/ui/pages/anilist/components/body/profile/body.dart index 9baec71..b149cce 100644 --- a/lib/ui/pages/anilist/components/body/profile/body.dart +++ b/lib/ui/pages/anilist/components/body/profile/body.dart @@ -30,18 +30,14 @@ class AnilistPageProfileBodyBody extends StatelessWidget { ), ); - String getMediaProgressText(final AnilistMedia media) { - switch (media.type) { - case AnilistMediaType.anime: - return '${media.mediaListEntry?.progress ?? 0}/${media.episodes ?? Translation.unk}'; - - case AnilistMediaType.manga: - return [ - '${media.mediaListEntry?.progress ?? 0}/${media.episodes ?? 0}', - '(${media.mediaListEntry?.progressVolumes ?? 0}/${media.volumes ?? Translation.unk})', - ].join(' '); - } - } + String getMediaProgressText(final AnilistMedia media) => switch (media.type) { + AnilistMediaType.anime => + '${media.mediaListEntry?.progress ?? 0}/${media.episodes ?? Translation.unk}', + AnilistMediaType.manga => [ + '${media.mediaListEntry?.progress ?? 0}/${media.episodes ?? 0}', + '(${media.mediaListEntry?.progressVolumes ?? 0}/${media.volumes ?? Translation.unk})', + ].join(' '), + }; List buildTiles({ required final BuildContext context, diff --git a/lib/ui/pages/anilist/components/body/profile/hero.dart b/lib/ui/pages/anilist/components/body/profile/hero.dart index f9e9e04..562456e 100644 --- a/lib/ui/pages/anilist/components/body/profile/hero.dart +++ b/lib/ui/pages/anilist/components/body/profile/hero.dart @@ -38,7 +38,6 @@ class AnilistPageProfileBodyHero extends StatelessWidget { switch (provider.category.type) { case AnilistMediaType.anime: final AnilistUserStatistics? stats = user.animeStatistics; - return [ buildStatisticsChild( context: context, @@ -69,7 +68,6 @@ class AnilistPageProfileBodyHero extends StatelessWidget { case AnilistMediaType.manga: final AnilistUserStatistics? stats = user.mangaStatistics; - return [ buildStatisticsChild( context: context, diff --git a/lib/ui/pages/settings/components/tiles/choice.dart b/lib/ui/pages/settings/components/tiles/choice.dart index 94a30c6..5db8f5f 100644 --- a/lib/ui/pages/settings/components/tiles/choice.dart +++ b/lib/ui/pages/settings/components/tiles/choice.dart @@ -34,7 +34,10 @@ class _MultiChoiceListTileState extends State> { subtitle: widget.items[widget.value], onTap: () async { WidgetsBinding.instance.addPostFrameCallback((final _) { - Scrollable.ensureVisible(_initActiveOptionKey.currentContext!); + Scrollable.ensureVisible( + _initActiveOptionKey.currentContext!, + duration: AnimationDurations.defaultNormalAnimation, + ); }); final T? value = await showModalBottomSheet( context: context, diff --git a/lib/ui/pages/settings/view.dart b/lib/ui/pages/settings/view.dart index d3b1ea3..7c17582 100644 --- a/lib/ui/pages/settings/view.dart +++ b/lib/ui/pages/settings/view.dart @@ -16,12 +16,9 @@ enum _SettingsCategory { } extension on _SettingsCategory { - String getTitleCase(final Translation translation) { - switch (this) { - case _SettingsCategory.appearance: - return translation.appearance; - } - } + String getTitleCase(final Translation translation) => switch (this) { + _SettingsCategory.appearance => translation.appearance, + }; } class _SettingsPageState extends State { @@ -80,12 +77,9 @@ class _SettingsPageState extends State { ); } - Widget buildBody(final BuildContext context) { - switch (category) { - case _SettingsCategory.appearance: - return const ApperanceSettings(); - } - } + Widget buildBody(final BuildContext context) => switch (category) { + _SettingsCategory.appearance => const ApperanceSettings(), + }; @override Widget build(final BuildContext context) => Scaffold( diff --git a/lib/ui/pages/view/components/body.dart b/lib/ui/pages/view/components/body.dart index 50a0b6c..faf700d 100644 --- a/lib/ui/pages/view/components/body.dart +++ b/lib/ui/pages/view/components/body.dart @@ -11,23 +11,14 @@ enum _ViewPageTabs { } extension on _ViewPageTabs { - String getTitleCase(final Translation translation, final TenkaType type) { - switch (this) { - case _ViewPageTabs.overview: - return translation.overview; - - case _ViewPageTabs.content: - { - switch (type) { - case TenkaType.anime: - return translation.episodes; - - case TenkaType.manga: - return translation.chapters; + String getTitleCase(final Translation translation, final TenkaType type) => + switch (this) { + _ViewPageTabs.overview => translation.overview, + _ViewPageTabs.content => switch (type) { + TenkaType.anime => translation.episodes, + TenkaType.manga => translation.chapters, } - } - } - } + }; } class ViewPageBody extends StatefulWidget { diff --git a/lib/ui/utils/animations.dart b/lib/ui/utils/animations.dart index accdcbd..44ada32 100644 --- a/lib/ui/utils/animations.dart +++ b/lib/ui/utils/animations.dart @@ -2,20 +2,21 @@ import 'package:kazahana/core/exports.dart'; abstract class AnimationDurations { static const Duration _defaultQuickAnimation = Duration(milliseconds: 100); - static Duration get defaultQuickAnimation => - onlyIfEnabled(_defaultQuickAnimation); - static const Duration _defaultNormalAnimation = Duration(milliseconds: 300); - static Duration get defaultNormalAnimation => - onlyIfEnabled(_defaultNormalAnimation); - static const Duration _defaultLongAnimation = Duration(milliseconds: 500); - static Duration get defaultLongAnimation => - onlyIfEnabled(_defaultLongAnimation); static Duration onlyIfEnabled(final Duration duration) => disabled ? Duration.zero : duration; static bool get disabled => SettingsDatabase.ready && SettingsDatabase.settings.disableAnimations; + + static Duration get defaultQuickAnimation => + onlyIfEnabled(_defaultQuickAnimation); + + static Duration get defaultNormalAnimation => + onlyIfEnabled(_defaultNormalAnimation); + + static Duration get defaultLongAnimation => + onlyIfEnabled(_defaultLongAnimation); } diff --git a/lib/ui/utils/exports.dart b/lib/ui/utils/exports.dart index cf5120d..8ec9122 100644 --- a/lib/ui/utils/exports.dart +++ b/lib/ui/utils/exports.dart @@ -1,5 +1,5 @@ export 'animations.dart'; export 'placeholders.dart'; -export 'relative_size.dart'; +export 'relative_scale.dart'; export 'themer.dart'; export 'translations.dart'; diff --git a/lib/ui/utils/relative_size.dart b/lib/ui/utils/relative_scale.dart similarity index 100% rename from lib/ui/utils/relative_size.dart rename to lib/ui/utils/relative_scale.dart diff --git a/lib/ui/utils/responsive.dart b/lib/ui/utils/responsive.dart new file mode 100644 index 0000000..a99ee48 --- /dev/null +++ b/lib/ui/utils/responsive.dart @@ -0,0 +1,42 @@ +import 'package:kazahana/core/exports.dart'; + +class Responsive extends InheritedWidget { + const Responsive({ + required this.width, + required super.child, + super.key, + }); + + factory Responsive.of(final BuildContext context) => + context.dependOnInheritedWidgetOfExactType()!; + + final double width; + + T value( + final T any, { + final T? sm, + final T? md, + final T? lg, + final T? xl, + }) => + switch (width) { + > xlWidth when xl != null => xl, + > lgWidth when lg != null => lg, + > mdWidth when md != null => md, + > smWidth when sm != null => sm, + _ => any, + }; + + @override + bool updateShouldNotify(final Responsive oldWidget) => + oldWidget.width != width; + + static const double smWidth = 640; + static const double mdWidth = 768; + static const double lgWidth = 1024; + static const double xlWidth = 1280; +} + +extension ResponsiveUtils on BuildContext { + Responsive get m => Responsive.of(this); +} diff --git a/lib/ui/utils/themer.dart b/lib/ui/utils/themer.dart index 74b82af..818c020 100644 --- a/lib/ui/utils/themer.dart +++ b/lib/ui/utils/themer.dart @@ -1,6 +1,6 @@ import 'package:flutter/scheduler.dart'; import 'package:kazahana/core/exports.dart'; -import 'relative_size.dart'; +import 'relative_scale.dart'; abstract class Themer { static Color _findColor(final String? color, final Color fallback) { diff --git a/packages/anilist/lib/models/seasons.dart b/packages/anilist/lib/models/seasons.dart index 42cf63b..03fa59a 100644 --- a/packages/anilist/lib/models/seasons.dart +++ b/packages/anilist/lib/models/seasons.dart @@ -14,29 +14,10 @@ extension AnimeSeasonsUtils on AnimeSeasons { AnimeSeasons parseAnimeSeason(final String code) => EnumUtils.find(AnimeSeasons.values, code.toLowerCase()); -AnimeSeasons getAnimeSeasonFromMonth(final int month) { - switch (month) { - case 1: - case 2: - case 3: - return AnimeSeasons.winter; - - case 4: - case 5: - case 6: - return AnimeSeasons.spring; - - case 7: - case 8: - case 9: - return AnimeSeasons.summer; - - case 10: - case 11: - case 12: - return AnimeSeasons.fall; - - default: - throw Error(); - } -} +AnimeSeasons getAnimeSeasonFromMonth(final int month) => switch (month) { + 1 || 2 || 3 => AnimeSeasons.winter, + 4 || 5 || 6 => AnimeSeasons.spring, + 7 || 8 || 9 => AnimeSeasons.summer, + 10 || 11 || 12 => AnimeSeasons.fall, + _ => throw Exception('Unexpected anime season month'), + }; diff --git a/packages/anilist/pubspec.yaml b/packages/anilist/pubspec.yaml index 805d427..437ce10 100644 --- a/packages/anilist/pubspec.yaml +++ b/packages/anilist/pubspec.yaml @@ -4,7 +4,7 @@ version: 0.0.0 publish_to: none environment: - sdk: ">=2.19.0-43.0.dev <3.0.0" + sdk: ">=3.0.0 <4.0.0" dependencies: shared: diff --git a/packages/shared/pubspec.yaml b/packages/shared/pubspec.yaml index f1c442b..a123596 100644 --- a/packages/shared/pubspec.yaml +++ b/packages/shared/pubspec.yaml @@ -4,7 +4,7 @@ version: 0.0.0 publish_to: none environment: - sdk: ">=2.19.0-43.0.dev <3.0.0" + sdk: ">=3.0.0 <4.0.0" dependencies: http: ^1.1.0