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

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/widgets/progress_center.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';
class CategoriesScreen extends ConsumerStatefulWidget {
@ -24,17 +25,20 @@ class CategoriesScreen extends ConsumerStatefulWidget {
class _CategoriesScreenState extends ConsumerState<CategoriesScreen>
with TickerProviderStateMixin {
late TabController _tabBarController;
late final List<String> _tabList;
late final List<ItemType> _visibleTabTypes;
@override
void initState() {
super.initState();
final hideItems = ref.read(hideItemsStateProvider);
_tabList = [
if (!hideItems.contains("/MangaLibrary")) "/MangaLibrary",
if (!hideItems.contains("/AnimeLibrary")) "/AnimeLibrary",
if (!hideItems.contains("/NovelLibrary")) "/NovelLibrary",
_visibleTabTypes = [
if (!hideItems.contains("/MangaLibrary")) ItemType.manga,
if (!hideItems.contains("/AnimeLibrary")) ItemType.anime,
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);
}
@ -46,7 +50,7 @@ class _CategoriesScreenState extends ConsumerState<CategoriesScreen>
@override
Widget build(BuildContext context) {
if (_tabList.isEmpty) {
if (_visibleTabTypes.isEmpty) {
return Scaffold(
appBar: AppBar(title: Text(context.l10n.categories)),
body: Center(child: Text("EMPTY\nMPTY\nMTY\nMT\n\n")),
@ -55,7 +59,7 @@ class _CategoriesScreenState extends ConsumerState<CategoriesScreen>
final l10n = l10nLocalizations(context)!;
return DefaultTabController(
animationDuration: Duration.zero,
length: _tabList.length,
length: _visibleTabTypes.length,
child: Scaffold(
appBar: AppBar(
elevation: 0,
@ -67,23 +71,15 @@ class _CategoriesScreenState extends ConsumerState<CategoriesScreen>
bottom: TabBar(
indicatorSize: TabBarIndicatorSize.label,
controller: _tabBarController,
tabs: _tabList.map((route) {
if (route == "/MangaLibrary") return Tab(text: l10n.manga);
if (route == "/AnimeLibrary") return Tab(text: l10n.anime);
return Tab(text: l10n.novel);
tabs: _visibleTabTypes.map((type) {
return Tab(text: localizedItemType(type, l10n));
}).toList(),
),
),
body: TabBarView(
controller: _tabBarController,
children: _tabList.map((route) {
if (route == "/MangaLibrary") {
return CategoriesTab(itemType: ItemType.manga);
}
if (route == "/AnimeLibrary") {
return CategoriesTab(itemType: ItemType.anime);
}
return CategoriesTab(itemType: ItemType.novel);
children: _visibleTabTypes.map((type) {
return CategoriesTab(itemType: type);
}).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/providers/l10n_providers.dart';
import 'package:mangayomi/utils/extensions/build_context_extensions.dart';
import 'package:mangayomi/utils/item_type_localization.dart';
class StatisticsScreen extends ConsumerStatefulWidget {
const StatisticsScreen({super.key});
@ -17,18 +18,21 @@ class _StatisticsScreenState extends ConsumerState<StatisticsScreen>
with SingleTickerProviderStateMixin {
late final List<String> hideItems;
late TabController _tabController;
late final List<String> _tabList;
late final List<ItemType> _visibleTabTypes;
@override
void initState() {
super.initState();
hideItems = ref.read(hideItemsStateProvider);
_tabList = [
if (!hideItems.contains("/MangaLibrary")) "/MangaLibrary",
if (!hideItems.contains("/AnimeLibrary")) "/AnimeLibrary",
if (!hideItems.contains("/NovelLibrary")) "/NovelLibrary",
_visibleTabTypes = [
if (!hideItems.contains("/MangaLibrary")) ItemType.manga,
if (!hideItems.contains("/AnimeLibrary")) ItemType.anime,
if (!hideItems.contains("/NovelLibrary")) ItemType.novel,
];
_tabController = TabController(length: _tabList.length, vsync: this);
_tabController = TabController(
length: _visibleTabTypes.length,
vsync: this,
);
}
@override
@ -39,7 +43,7 @@ class _StatisticsScreenState extends ConsumerState<StatisticsScreen>
@override
Widget build(BuildContext context) {
if (_tabList.isEmpty) {
if (_visibleTabTypes.isEmpty) {
return Scaffold(
appBar: AppBar(title: Text(context.l10n.statistics)),
body: Center(child: Text("EMPTY\nMPTY\nMTY\nMT\n\n")),
@ -51,23 +55,15 @@ class _StatisticsScreenState extends ConsumerState<StatisticsScreen>
title: Text(l10n.statistics),
bottom: TabBar(
controller: _tabController,
tabs: _tabList.map((route) {
if (route == "/MangaLibrary") return Tab(text: l10n.manga);
if (route == "/AnimeLibrary") return Tab(text: l10n.anime);
return Tab(text: l10n.novel);
tabs: _visibleTabTypes.map((type) {
return Tab(text: localizedItemType(type, l10n));
}).toList(),
),
),
body: TabBarView(
controller: _tabController,
children: _tabList.map((route) {
if (route == "/MangaLibrary") {
return _buildStatisticsTab(itemType: ItemType.manga);
}
if (route == "/AnimeLibrary") {
return _buildStatisticsTab(itemType: ItemType.anime);
}
return _buildStatisticsTab(itemType: ItemType.novel);
children: _visibleTabTypes.map((type) {
return _buildStatisticsTab(itemType: type);
}).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/more/settings/reader/providers/reader_state_provider.dart';
import 'package:mangayomi/providers/l10n_providers.dart';
import 'package:mangayomi/utils/item_type_localization.dart';
abstract class BaseLibraryTabScreenState<T extends ConsumerStatefulWidget>
extends ConsumerState<T>
@ -61,17 +62,6 @@ abstract class BaseLibraryTabScreenState<T extends ConsumerStatefulWidget>
@override
Widget build(BuildContext 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(
appBar: AppBar(
elevation: 0,
@ -104,7 +94,7 @@ abstract class BaseLibraryTabScreenState<T extends ConsumerStatefulWidget>
controller: tabController,
indicatorSize: TabBarIndicatorSize.tab,
tabs: visibleTabTypes.map((type) {
return buildTabLabel(type, localizedItemType(type));
return buildTabLabel(type, localizedItemType(type, l10n));
}).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;
}
}