Reduce Code Duplication

- Extract localizedItemType() from `base_library_tab_screen.dart`
- Add localizedSources() and localizedExtensions() for browse_screen.dart
- Reduce if-statements in statistics_screen.dart
- Reduce if-statements in categories_screen.dart
- Reduce if-statements in browse_screen.dart
This commit is contained in:
NBA2K1 2025-12-29 04:59:06 +01:00
parent 86fb19ecb2
commit 42f1dcff92
5 changed files with 130 additions and 155 deletions

View file

@ -12,6 +12,7 @@ import 'package:mangayomi/modules/browse/extension/extension_screen.dart';
import 'package:mangayomi/modules/browse/sources/sources_screen.dart'; import 'package:mangayomi/modules/browse/sources/sources_screen.dart';
import 'package:mangayomi/modules/library/widgets/search_text_form_field.dart'; import 'package:mangayomi/modules/library/widgets/search_text_form_field.dart';
import 'package:mangayomi/services/fetch_sources_list.dart'; import 'package:mangayomi/services/fetch_sources_list.dart';
import 'package:mangayomi/utils/item_type_localization.dart';
class BrowseScreen extends ConsumerStatefulWidget { class BrowseScreen extends ConsumerStatefulWidget {
const BrowseScreen({super.key}); const BrowseScreen({super.key});
@ -20,19 +21,35 @@ class BrowseScreen extends ConsumerStatefulWidget {
ConsumerState<BrowseScreen> createState() => _BrowseScreenState(); ConsumerState<BrowseScreen> createState() => _BrowseScreenState();
} }
enum BrowseTabKind { sources, extensions }
class BrowseTab {
final ItemType type;
final BrowseTabKind kind;
const BrowseTab(this.type, this.kind);
}
class _BrowseScreenState extends ConsumerState<BrowseScreen> class _BrowseScreenState extends ConsumerState<BrowseScreen>
with TickerProviderStateMixin { with TickerProviderStateMixin {
late final hideItems = ref.read(hideItemsStateProvider); late final hideItems = ref.read(hideItemsStateProvider);
final _textEditingController = TextEditingController(); final _textEditingController = TextEditingController();
late TabController _tabBarController; late TabController _tabBarController;
late final _tabList = [ late final List<BrowseTab> _tabList = [
if (!hideItems.contains("/MangaLibrary")) 'manga', if (!hideItems.contains("/MangaLibrary"))
if (!hideItems.contains("/AnimeLibrary")) 'anime', BrowseTab(ItemType.manga, BrowseTabKind.sources),
if (!hideItems.contains("/NovelLibrary")) 'novel', if (!hideItems.contains("/AnimeLibrary"))
if (!hideItems.contains("/MangaLibrary")) 'mangaExtension', BrowseTab(ItemType.anime, BrowseTabKind.sources),
if (!hideItems.contains("/AnimeLibrary")) 'animeExtension', if (!hideItems.contains("/NovelLibrary"))
if (!hideItems.contains("/NovelLibrary")) 'novelExtension', BrowseTab(ItemType.novel, BrowseTabKind.sources),
if (!hideItems.contains("/MangaLibrary"))
BrowseTab(ItemType.manga, BrowseTabKind.extensions),
if (!hideItems.contains("/AnimeLibrary"))
BrowseTab(ItemType.anime, BrowseTabKind.extensions),
if (!hideItems.contains("/NovelLibrary"))
BrowseTab(ItemType.novel, BrowseTabKind.extensions),
]; ];
@override @override
@ -65,11 +82,8 @@ class _BrowseScreenState extends ConsumerState<BrowseScreen>
if (_tabList.isEmpty) { if (_tabList.isEmpty) {
return SizedBox.shrink(); return SizedBox.shrink();
} }
final containsExtensionTab = [ final currentTab = _tabList[_tabBarController.index];
"mangaExtension", final isExtensionTab = currentTab.kind == BrowseTabKind.extensions;
"animeExtension",
"novelExtension",
].any((element) => _tabList[_tabBarController.index] == element);
final l10n = l10nLocalizations(context)!; final l10n = l10nLocalizations(context)!;
return DefaultTabController( return DefaultTabController(
@ -102,9 +116,7 @@ class _BrowseScreenState extends ConsumerState<BrowseScreen>
) )
: Row( : Row(
children: [ children: [
if (_tabBarController.index == 3 || if (isExtensionTab)
_tabBarController.index == 4 ||
_tabBarController.index == 5)
IconButton( IconButton(
onPressed: () { onPressed: () {
context.push('/createExtension'); context.push('/createExtension');
@ -117,26 +129,19 @@ class _BrowseScreenState extends ConsumerState<BrowseScreen>
IconButton( IconButton(
splashRadius: 20, splashRadius: 20,
onPressed: () { onPressed: () {
if (containsExtensionTab) { if (isExtensionTab) {
setState(() { setState(() {
_isSearch = true; _isSearch = true;
}); });
} else { } else {
context.push( context.push(
'/globalSearch', '/globalSearch',
extra: ( extra: (null, currentTab.type),
null,
switch (_tabList[_tabBarController.index]) {
"manga" => ItemType.manga,
"anime" => ItemType.anime,
_ => ItemType.novel,
},
),
); );
} }
}, },
icon: Icon( icon: Icon(
!containsExtensionTab !isExtensionTab
? Icons.travel_explore_rounded ? Icons.travel_explore_rounded
: Icons.search_rounded, : Icons.search_rounded,
color: Theme.of(context).hintColor, color: Theme.of(context).hintColor,
@ -148,16 +153,12 @@ class _BrowseScreenState extends ConsumerState<BrowseScreen>
splashRadius: 20, splashRadius: 20,
onPressed: () { onPressed: () {
context.push( context.push(
containsExtensionTab ? '/ExtensionLang' : '/sourceFilter', isExtensionTab ? '/ExtensionLang' : '/sourceFilter',
extra: switch (_tabList[_tabBarController.index]) { extra: currentTab.type,
"manga" || "mangaExtension" => ItemType.manga,
"anime" || "animeExtension" => ItemType.anime,
_ => ItemType.novel,
},
); );
}, },
icon: Icon( icon: Icon(
!containsExtensionTab !isExtensionTab
? Icons.filter_list_sharp ? Icons.filter_list_sharp
: Icons.translate_rounded, : Icons.translate_rounded,
color: Theme.of(context).hintColor, color: Theme.of(context).hintColor,
@ -168,86 +169,43 @@ class _BrowseScreenState extends ConsumerState<BrowseScreen>
indicatorSize: TabBarIndicatorSize.label, indicatorSize: TabBarIndicatorSize.label,
isScrollable: true, isScrollable: true,
controller: _tabBarController, controller: _tabBarController,
tabs: [ tabs: _tabList.map((tab) {
if (!hideItems.contains("/MangaLibrary")) final type = tab.type;
Tab(text: l10n.manga_sources), final isExt = tab.kind == BrowseTabKind.extensions;
if (!hideItems.contains("/AnimeLibrary"))
Tab(text: l10n.anime_sources), return Tab(
if (!hideItems.contains("/NovelLibrary")) child: Row(
Tab(text: l10n.novel_sources), children: [
if (!hideItems.contains("/MangaLibrary")) Text(
Tab( isExt
child: Row( ? localizedExtensions(type, l10n)
children: [ : localizedSources(type, l10n),
Text(l10n.manga_extensions), ),
if (isExt) ...[
const SizedBox(width: 8), const SizedBox(width: 8),
_extensionUpdateNumbers(ref, ItemType.manga), _extensionUpdateNumbers(ref, type),
], ],
), ],
), ),
if (!hideItems.contains("/AnimeLibrary")) );
Tab( }).toList(),
child: Row(
children: [
Text(l10n.anime_extensions),
const SizedBox(width: 8),
_extensionUpdateNumbers(ref, ItemType.anime),
],
),
),
if (!hideItems.contains("/NovelLibrary"))
Tab(
child: Row(
children: [
Text(l10n.novel_extensions),
const SizedBox(width: 8),
_extensionUpdateNumbers(ref, ItemType.novel),
],
),
),
],
), ),
), ),
body: TabBarView( body: TabBarView(
controller: _tabBarController, controller: _tabBarController,
children: [ children: _tabList.map((tab) {
if (!hideItems.contains("/MangaLibrary")) if (tab.kind == BrowseTabKind.sources) {
SourcesScreen( return SourcesScreen(
itemType: ItemType.manga, itemType: tab.type,
tabIndex: (index) { tabIndex: (index) => _tabBarController.animateTo(index),
_tabBarController.animateTo(index); );
}, } else {
), return ExtensionScreen(
if (!hideItems.contains("/AnimeLibrary"))
SourcesScreen(
itemType: ItemType.anime,
tabIndex: (index) {
_tabBarController.animateTo(index);
},
),
if (!hideItems.contains("/NovelLibrary"))
SourcesScreen(
itemType: ItemType.novel,
tabIndex: (index) {
_tabBarController.animateTo(index);
},
),
if (!hideItems.contains("/MangaLibrary"))
ExtensionScreen(
query: _textEditingController.text, query: _textEditingController.text,
itemType: ItemType.manga, itemType: tab.type,
), );
if (!hideItems.contains("/AnimeLibrary")) }
ExtensionScreen( }).toList(),
query: _textEditingController.text,
itemType: ItemType.anime,
),
if (!hideItems.contains("/NovelLibrary"))
ExtensionScreen(
query: _textEditingController.text,
itemType: ItemType.novel,
),
],
), ),
), ),
); );

View file

@ -11,6 +11,7 @@ import 'package:mangayomi/modules/more/settings/reader/providers/reader_state_pr
import 'package:mangayomi/modules/more/settings/sync/providers/sync_providers.dart'; import 'package:mangayomi/modules/more/settings/sync/providers/sync_providers.dart';
import 'package:mangayomi/modules/widgets/progress_center.dart'; import 'package:mangayomi/modules/widgets/progress_center.dart';
import 'package:mangayomi/providers/l10n_providers.dart'; import 'package:mangayomi/providers/l10n_providers.dart';
import 'package:mangayomi/utils/item_type_localization.dart';
import 'package:super_sliver_list/super_sliver_list.dart'; import 'package:super_sliver_list/super_sliver_list.dart';
class CategoriesScreen extends ConsumerStatefulWidget { class CategoriesScreen extends ConsumerStatefulWidget {
@ -24,17 +25,20 @@ class CategoriesScreen extends ConsumerStatefulWidget {
class _CategoriesScreenState extends ConsumerState<CategoriesScreen> class _CategoriesScreenState extends ConsumerState<CategoriesScreen>
with TickerProviderStateMixin { with TickerProviderStateMixin {
late TabController _tabBarController; late TabController _tabBarController;
late final List<String> _tabList; late final List<ItemType> _visibleTabTypes;
@override @override
void initState() { void initState() {
super.initState(); super.initState();
final hideItems = ref.read(hideItemsStateProvider); final hideItems = ref.read(hideItemsStateProvider);
_tabList = [ _visibleTabTypes = [
if (!hideItems.contains("/MangaLibrary")) "/MangaLibrary", if (!hideItems.contains("/MangaLibrary")) ItemType.manga,
if (!hideItems.contains("/AnimeLibrary")) "/AnimeLibrary", if (!hideItems.contains("/AnimeLibrary")) ItemType.anime,
if (!hideItems.contains("/NovelLibrary")) "/NovelLibrary", if (!hideItems.contains("/NovelLibrary")) ItemType.novel,
]; ];
_tabBarController = TabController(length: _tabList.length, vsync: this); _tabBarController = TabController(
length: _visibleTabTypes.length,
vsync: this,
);
_tabBarController.animateTo(widget.data.$2); _tabBarController.animateTo(widget.data.$2);
} }
@ -46,7 +50,7 @@ class _CategoriesScreenState extends ConsumerState<CategoriesScreen>
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
if (_tabList.isEmpty) { if (_visibleTabTypes.isEmpty) {
return Scaffold( return Scaffold(
appBar: AppBar(title: Text(context.l10n.categories)), appBar: AppBar(title: Text(context.l10n.categories)),
body: Center(child: Text("EMPTY\nMPTY\nMTY\nMT\n\n")), body: Center(child: Text("EMPTY\nMPTY\nMTY\nMT\n\n")),
@ -55,7 +59,7 @@ class _CategoriesScreenState extends ConsumerState<CategoriesScreen>
final l10n = l10nLocalizations(context)!; final l10n = l10nLocalizations(context)!;
return DefaultTabController( return DefaultTabController(
animationDuration: Duration.zero, animationDuration: Duration.zero,
length: _tabList.length, length: _visibleTabTypes.length,
child: Scaffold( child: Scaffold(
appBar: AppBar( appBar: AppBar(
elevation: 0, elevation: 0,
@ -67,23 +71,15 @@ class _CategoriesScreenState extends ConsumerState<CategoriesScreen>
bottom: TabBar( bottom: TabBar(
indicatorSize: TabBarIndicatorSize.label, indicatorSize: TabBarIndicatorSize.label,
controller: _tabBarController, controller: _tabBarController,
tabs: _tabList.map((route) { tabs: _visibleTabTypes.map((type) {
if (route == "/MangaLibrary") return Tab(text: l10n.manga); return Tab(text: localizedItemType(type, l10n));
if (route == "/AnimeLibrary") return Tab(text: l10n.anime);
return Tab(text: l10n.novel);
}).toList(), }).toList(),
), ),
), ),
body: TabBarView( body: TabBarView(
controller: _tabBarController, controller: _tabBarController,
children: _tabList.map((route) { children: _visibleTabTypes.map((type) {
if (route == "/MangaLibrary") { return CategoriesTab(itemType: type);
return CategoriesTab(itemType: ItemType.manga);
}
if (route == "/AnimeLibrary") {
return CategoriesTab(itemType: ItemType.anime);
}
return CategoriesTab(itemType: ItemType.novel);
}).toList(), }).toList(),
), ),
), ),

View file

@ -5,6 +5,7 @@ import 'package:mangayomi/modules/more/settings/reader/providers/reader_state_pr
import 'package:mangayomi/modules/more/statistics/statistics_provider.dart'; import 'package:mangayomi/modules/more/statistics/statistics_provider.dart';
import 'package:mangayomi/providers/l10n_providers.dart'; import 'package:mangayomi/providers/l10n_providers.dart';
import 'package:mangayomi/utils/extensions/build_context_extensions.dart'; import 'package:mangayomi/utils/extensions/build_context_extensions.dart';
import 'package:mangayomi/utils/item_type_localization.dart';
class StatisticsScreen extends ConsumerStatefulWidget { class StatisticsScreen extends ConsumerStatefulWidget {
const StatisticsScreen({super.key}); const StatisticsScreen({super.key});
@ -17,18 +18,21 @@ class _StatisticsScreenState extends ConsumerState<StatisticsScreen>
with SingleTickerProviderStateMixin { with SingleTickerProviderStateMixin {
late final List<String> hideItems; late final List<String> hideItems;
late TabController _tabController; late TabController _tabController;
late final List<String> _tabList; late final List<ItemType> _visibleTabTypes;
@override @override
void initState() { void initState() {
super.initState(); super.initState();
hideItems = ref.read(hideItemsStateProvider); hideItems = ref.read(hideItemsStateProvider);
_tabList = [ _visibleTabTypes = [
if (!hideItems.contains("/MangaLibrary")) "/MangaLibrary", if (!hideItems.contains("/MangaLibrary")) ItemType.manga,
if (!hideItems.contains("/AnimeLibrary")) "/AnimeLibrary", if (!hideItems.contains("/AnimeLibrary")) ItemType.anime,
if (!hideItems.contains("/NovelLibrary")) "/NovelLibrary", if (!hideItems.contains("/NovelLibrary")) ItemType.novel,
]; ];
_tabController = TabController(length: _tabList.length, vsync: this); _tabController = TabController(
length: _visibleTabTypes.length,
vsync: this,
);
} }
@override @override
@ -39,7 +43,7 @@ class _StatisticsScreenState extends ConsumerState<StatisticsScreen>
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
if (_tabList.isEmpty) { if (_visibleTabTypes.isEmpty) {
return Scaffold( return Scaffold(
appBar: AppBar(title: Text(context.l10n.statistics)), appBar: AppBar(title: Text(context.l10n.statistics)),
body: Center(child: Text("EMPTY\nMPTY\nMTY\nMT\n\n")), body: Center(child: Text("EMPTY\nMPTY\nMTY\nMT\n\n")),
@ -51,23 +55,15 @@ class _StatisticsScreenState extends ConsumerState<StatisticsScreen>
title: Text(l10n.statistics), title: Text(l10n.statistics),
bottom: TabBar( bottom: TabBar(
controller: _tabController, controller: _tabController,
tabs: _tabList.map((route) { tabs: _visibleTabTypes.map((type) {
if (route == "/MangaLibrary") return Tab(text: l10n.manga); return Tab(text: localizedItemType(type, l10n));
if (route == "/AnimeLibrary") return Tab(text: l10n.anime);
return Tab(text: l10n.novel);
}).toList(), }).toList(),
), ),
), ),
body: TabBarView( body: TabBarView(
controller: _tabController, controller: _tabController,
children: _tabList.map((route) { children: _visibleTabTypes.map((type) {
if (route == "/MangaLibrary") { return _buildStatisticsTab(itemType: type);
return _buildStatisticsTab(itemType: ItemType.manga);
}
if (route == "/AnimeLibrary") {
return _buildStatisticsTab(itemType: ItemType.anime);
}
return _buildStatisticsTab(itemType: ItemType.novel);
}).toList(), }).toList(),
), ),
); );

View file

@ -4,6 +4,7 @@ import 'package:mangayomi/models/manga.dart';
import 'package:mangayomi/modules/library/widgets/search_text_form_field.dart'; import 'package:mangayomi/modules/library/widgets/search_text_form_field.dart';
import 'package:mangayomi/modules/more/settings/reader/providers/reader_state_provider.dart'; import 'package:mangayomi/modules/more/settings/reader/providers/reader_state_provider.dart';
import 'package:mangayomi/providers/l10n_providers.dart'; import 'package:mangayomi/providers/l10n_providers.dart';
import 'package:mangayomi/utils/item_type_localization.dart';
abstract class BaseLibraryTabScreenState<T extends ConsumerStatefulWidget> abstract class BaseLibraryTabScreenState<T extends ConsumerStatefulWidget>
extends ConsumerState<T> extends ConsumerState<T>
@ -61,17 +62,6 @@ abstract class BaseLibraryTabScreenState<T extends ConsumerStatefulWidget>
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
final l10n = l10nLocalizations(context)!; final l10n = l10nLocalizations(context)!;
String localizedItemType(ItemType type) {
switch (type) {
case ItemType.manga:
return l10n.manga;
case ItemType.anime:
return l10n.anime;
case ItemType.novel:
return l10n.novel;
}
}
return Scaffold( return Scaffold(
appBar: AppBar( appBar: AppBar(
elevation: 0, elevation: 0,
@ -104,7 +94,7 @@ abstract class BaseLibraryTabScreenState<T extends ConsumerStatefulWidget>
controller: tabController, controller: tabController,
indicatorSize: TabBarIndicatorSize.tab, indicatorSize: TabBarIndicatorSize.tab,
tabs: visibleTabTypes.map((type) { tabs: visibleTabTypes.map((type) {
return buildTabLabel(type, localizedItemType(type)); return buildTabLabel(type, localizedItemType(type, l10n));
}).toList(), }).toList(),
), ),
), ),

View file

@ -0,0 +1,35 @@
import 'package:mangayomi/l10n/generated/app_localizations.dart';
import 'package:mangayomi/models/manga.dart';
String localizedItemType(ItemType type, AppLocalizations l10n) {
switch (type) {
case ItemType.manga:
return l10n.manga;
case ItemType.anime:
return l10n.anime;
case ItemType.novel:
return l10n.novel;
}
}
String localizedSources(ItemType type, AppLocalizations l10n) {
switch (type) {
case ItemType.manga:
return l10n.manga_sources;
case ItemType.anime:
return l10n.anime_sources;
case ItemType.novel:
return l10n.novel_sources;
}
}
String localizedExtensions(ItemType type, AppLocalizations l10n) {
switch (type) {
case ItemType.manga:
return l10n.manga_extensions;
case ItemType.anime:
return l10n.anime_extensions;
case ItemType.novel:
return l10n.novel_extensions;
}
}