Merge pull request #519 from NBA2K1/Properly-dispose

Properly dispose
This commit is contained in:
Moustapha Kodjo Amadou 2025-07-19 15:30:59 +01:00 committed by GitHub
commit 539fd186cb
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
26 changed files with 401 additions and 249 deletions

View file

@ -410,10 +410,19 @@ class _AnimeStreamPageState extends riv.ConsumerState<AnimeStreamPage>
_currentPositionSub.cancel();
_currentTotalDurationSub.cancel();
_completed.cancel();
_video.dispose();
_playbackSpeed.dispose();
_isDoubleSpeed.dispose();
_currentTotalDuration.dispose();
_showFitLabel.dispose();
_isCompleted.dispose();
_tempPosition.dispose();
_fit.dispose();
if (!_isDesktop) {
_setLandscapeMode(false);
}
_skipPhase.dispose();
_currentPosition.dispose();
super.dispose();
}
@ -498,7 +507,12 @@ class _AnimeStreamPageState extends riv.ConsumerState<AnimeStreamPage>
selected,
),
onTap: () async {
if (_video.value?.videoTrack?.id == quality.videoTrack?.id) {
Navigator.pop(context);
return;
}
_video.value = quality;
_player.stop();
if (quality.isLocal) {
if (widget.isLocal) {
_player.setVideoTrack(quality.videoTrack!);

View file

@ -51,6 +51,7 @@ class _MobileControllerWidgetState
);
final ValueNotifier<double> _brightnessValue = ValueNotifier(0.0);
final ValueNotifier<bool> _brightnessIndicator = ValueNotifier(false);
StreamSubscription<double>? _brightnessSubscription;
Timer? _brightnessTimer;
final ValueNotifier<double> _volumeValue = ValueNotifier(0.0);
@ -127,6 +128,15 @@ class _MobileControllerWidgetState
for (final subscription in subscriptions) {
subscription.cancel();
}
_timer?.cancel();
_volumeTimer?.cancel();
_brightnessTimer?.cancel();
_volumeValue.dispose();
_volumeIndicator.dispose();
_brightnessValue.dispose();
_brightnessIndicator.dispose();
_brightnessSubscription?.cancel();
_volumeController.removeListener();
// package:screen_brightness
Future.microtask(() async {
@ -134,7 +144,6 @@ class _MobileControllerWidgetState
await ScreenBrightness.instance.resetApplicationScreenBrightness();
} catch (_) {}
});
super.dispose();
}
@ -240,13 +249,14 @@ class _MobileControllerWidgetState
Future.microtask(() async {
try {
_brightnessValue.value = await ScreenBrightness.instance.application;
ScreenBrightness.instance.onApplicationScreenBrightnessChanged.listen((
value,
) {
if (mounted) {
_brightnessValue.value = value;
}
});
_brightnessSubscription = ScreenBrightness
.instance
.onApplicationScreenBrightnessChanged
.listen((value) {
if (mounted) {
_brightnessValue.value = value;
}
});
} catch (_) {}
});
}

View file

@ -22,7 +22,8 @@ class BrowseScreen extends ConsumerStatefulWidget {
class _BrowseScreenState extends ConsumerState<BrowseScreen>
with TickerProviderStateMixin {
late final hideItems = ref.watch(hideItemsStateProvider);
late final hideItems = ref.read(hideItemsStateProvider);
final _textEditingController = TextEditingController();
late TabController _tabBarController;
late final _tabList = [
@ -35,10 +36,9 @@ class _BrowseScreenState extends ConsumerState<BrowseScreen>
];
@override
void didChangeDependencies() {
super.didChangeDependencies();
void initState() {
super.initState();
_tabBarController = TabController(length: _tabList.length, vsync: this);
_tabBarController.animateTo(0);
_tabBarController.addListener(() {
_chekPermission();
setState(() {
@ -52,7 +52,13 @@ class _BrowseScreenState extends ConsumerState<BrowseScreen>
await StorageProvider().requestPermission();
}
final _textEditingController = TextEditingController();
@override
void dispose() {
_tabBarController.dispose();
_textEditingController.dispose();
super.dispose();
}
bool _isSearch = false;
@override
Widget build(BuildContext context) {

View file

@ -1,3 +1,5 @@
import 'dart:async';
import 'package:flutter/material.dart';
import 'package:json_view/json_view.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
@ -59,13 +61,14 @@ class _CodeEditorPageState extends ConsumerState<CodeEditorPage> {
[],
);
late final _logStreamController = Logger.logStreamController;
late final StreamSubscription _logSubscription;
final _scrollController = ScrollController();
@override
void initState() {
super.initState();
_controller.text = source?.sourceCode ?? "";
useLogger = true;
_logStreamController.stream.asBroadcastStream().listen((event) async {
_logSubscription = _logStreamController.stream.listen((event) async {
_logsNotifier.value.add(event);
try {
await Future.delayed(const Duration(milliseconds: 5));
@ -133,11 +136,12 @@ class _CodeEditorPageState extends ConsumerState<CodeEditorPage> {
@override
void dispose() {
super.dispose();
_logSubscription.cancel();
_logsNotifier.value.clear();
_scrollController.dispose();
_controller.dispose();
useLogger = false;
super.dispose();
}
@override

View file

@ -37,6 +37,12 @@ class _ExtensionScreenState extends ConsumerState<ExtensionScreen> {
);
}
@override
void dispose() {
controller.dispose();
super.dispose();
}
Future<void> _updateSource(Source source) {
return ref.read(
fetchItemSourcesListProvider(

View file

@ -298,6 +298,13 @@ class EditTextDialogWidget extends StatefulWidget {
class _EditTextDialogWidgetState extends State<EditTextDialogWidget> {
late final _controller = TextEditingController(text: widget.text);
@override
void dispose() {
_controller.dispose();
super.dispose();
}
@override
Widget build(BuildContext context) {
return AlertDialog(

View file

@ -35,7 +35,7 @@ class _GlobalSearchScreenState extends ConsumerState<GlobalSearchScreen> {
String query = "";
final _textEditingController = TextEditingController();
late final List<Source> sourceList =
ref.watch(onlyIncludePinnedSourceStateProvider)
ref.read(onlyIncludePinnedSourceStateProvider)
? isar.sources
.filter()
.isPinnedEqualTo(true)
@ -97,6 +97,12 @@ class _GlobalSearchScreenState extends ConsumerState<GlobalSearchScreen> {
: Container(),
);
}
@override
void dispose() {
_textEditingController.dispose();
super.dispose();
}
}
class SourceSearchScreen extends StatefulWidget {

View file

@ -24,6 +24,13 @@ class SourcesScreen extends ConsumerStatefulWidget {
class _SourcesScreenState extends ConsumerState<SourcesScreen> {
final controller = ScrollController();
@override
void dispose() {
controller.dispose();
super.dispose();
}
@override
Widget build(BuildContext context) {
final l10n = l10nLocalizations(context)!;

View file

@ -33,6 +33,7 @@ class HistoryScreen extends ConsumerStatefulWidget {
class _HistoryScreenState extends ConsumerState<HistoryScreen>
with TickerProviderStateMixin {
final _textEditingController = TextEditingController();
late TabController _tabBarController;
int tabs = 3;
@ -51,7 +52,13 @@ class _HistoryScreenState extends ConsumerState<HistoryScreen>
_tabBarController.addListener(tabListener);
}
final _textEditingController = TextEditingController();
@override
void dispose() {
_tabBarController.dispose();
_textEditingController.dispose();
super.dispose();
}
bool _isSearch = false;
List<History> entriesData = [];
@override

View file

@ -71,6 +71,13 @@ class _LibraryScreenState extends ConsumerState<LibraryScreen>
}
}
@override
void dispose() {
_textEditingController.dispose();
tabBarController?.dispose();
super.dispose();
}
Future<void> _updateLibrary(List<Manga> mangaList) async {
bool isDark = ref.read(themeModeStateProvider);
botToast(

View file

@ -89,9 +89,15 @@ class _MangaDetailViewState extends ConsumerState<MangaDetailView>
});
}
@override
void dispose() {
_scrollController.dispose();
super.dispose();
}
final offetProvider = StateProvider((ref) => 0.0);
bool _expanded = false;
ScrollController _scrollController = ScrollController();
late final ScrollController _scrollController;
late final isLocalArchive = widget.manga!.isLocalArchive ?? false;
@override
Widget build(BuildContext context) {

View file

@ -61,6 +61,12 @@ class _MigrationScreenScreenState extends ConsumerState<MigrationScreen> {
.and()
.itemTypeEqualTo(widget.manga.itemType)
.findAllSync();
@override
void initState() {
super.initState();
final query = widget.manga.name ?? widget.manga.author ?? "";
_textEditingController.text = query;
}
@override
Widget build(BuildContext context) {
@ -68,7 +74,6 @@ class _MigrationScreenScreenState extends ConsumerState<MigrationScreen> {
final query = _query.isNotEmpty
? _query
: widget.manga.name ?? widget.manga.author ?? "";
_textEditingController.text = query;
return Scaffold(
appBar: AppBar(
@ -126,6 +131,12 @@ class _MigrationScreenScreenState extends ConsumerState<MigrationScreen> {
: Container(),
);
}
@override
void dispose() {
_textEditingController.dispose();
super.dispose();
}
}
class MigrationSourceSearchScreen extends StatefulWidget {

View file

@ -59,6 +59,13 @@ class _TrackerWidgetSearchState extends ConsumerState<TrackerWidgetSearch> {
}
late final _controller = TextEditingController(text: query);
@override
void dispose() {
_controller.dispose();
super.dispose();
}
bool _isLoading = true;
@override
Widget build(BuildContext context) {

View file

@ -114,6 +114,13 @@ class _MangaHomeScreenState extends ConsumerState<MangaHomeScreen> {
return mangaRes;
}
@override
void dispose() {
_scrollController.dispose();
_textEditingController.dispose();
super.dispose();
}
late final _textEditingController = TextEditingController(text: widget.query);
late String _query = widget.query;
late bool _isSearch = widget.isSearch;

View file

@ -182,6 +182,12 @@ class SeachFormTextFieldWidget extends StatefulWidget {
}
class _SeachFormTextFieldWidgetState extends State<SeachFormTextFieldWidget> {
@override
void dispose() {
_controller.dispose();
super.dispose();
}
late final _controller = TextEditingController(text: widget.text);
@override
Widget build(BuildContext context) {

View file

@ -83,6 +83,12 @@ class _DoubleColummViewState extends State<DoubleColummView>
});
}
@override
void dispose() {
_scaleAnimationController.dispose();
super.dispose();
}
void _toggleScale(Offset tapPosition) {
if (mounted) {
setState(() {

View file

@ -145,7 +145,15 @@ class _MangaChapterPageGalleryState
_rebuildDetail.close();
_doubleClickAnimationController.dispose();
_scaleAnimationController.dispose();
_failedToLoadImage.dispose();
_autoScroll.value = false;
_autoScroll.dispose();
_autoScrollPage.dispose();
_itemPositionsListener.itemPositions.removeListener(_readProgressListener);
_photoViewController.dispose();
_photoViewScaleStateController.dispose();
_extendedController.dispose();
clearGestureDetailsCache();
if (isDesktop) {
setFullScreen(value: false);

View file

@ -60,6 +60,12 @@ class _ChapterListWidgetState extends State<ChapterListWidget> {
_jumpTo();
}
@override
void dispose() {
controller.dispose();
super.dispose();
}
Future<void> _jumpTo() async {
await Future.delayed(const Duration(milliseconds: 5));
controller.jumpTo(

View file

@ -29,6 +29,12 @@ class _DownloadFileScreenState extends ConsumerState<DownloadFileScreen> {
final List<int> _bytes = [];
late StreamSubscription<List<int>>? _subscription;
@override
void dispose() {
_subscription?.cancel();
super.dispose();
}
@override
Widget build(BuildContext context) {
final l10n = l10nLocalizations(context)!;

View file

@ -24,33 +24,38 @@ class CategoriesScreen extends ConsumerStatefulWidget {
class _CategoriesScreenState extends ConsumerState<CategoriesScreen>
with TickerProviderStateMixin {
late TabController _tabBarController;
int tabs = 3;
late final List<String> _tabList;
@override
void initState() {
super.initState();
_tabBarController = TabController(length: tabs, vsync: this);
final hideItems = ref.read(hideItemsStateProvider);
_tabList = [
if (!hideItems.contains("/MangaLibrary")) "/MangaLibrary",
if (!hideItems.contains("/AnimeLibrary")) "/AnimeLibrary",
if (!hideItems.contains("/NovelLibrary")) "/NovelLibrary",
];
_tabBarController = TabController(length: _tabList.length, vsync: this);
_tabBarController.animateTo(widget.data.$2);
}
@override
void dispose() {
_tabBarController.dispose();
super.dispose();
}
@override
Widget build(BuildContext context) {
int newTabs = 0;
final hideItems = ref.watch(hideItemsStateProvider);
if (!hideItems.contains("/MangaLibrary")) newTabs++;
if (!hideItems.contains("/AnimeLibrary")) newTabs++;
if (!hideItems.contains("/NovelLibrary")) newTabs++;
if (tabs != newTabs) {
_tabBarController.dispose();
_tabBarController = TabController(length: newTabs, vsync: this);
_tabBarController.animateTo(0);
setState(() {
tabs = newTabs;
});
if (_tabList.isEmpty) {
return Scaffold(
appBar: AppBar(title: Text(context.l10n.categories)),
body: Center(child: Text("EMPTY\nMPTY\nMTY\nMT\n\n")),
);
}
final l10n = l10nLocalizations(context)!;
return DefaultTabController(
animationDuration: Duration.zero,
length: newTabs,
length: _tabList.length,
child: Scaffold(
appBar: AppBar(
elevation: 0,
@ -62,23 +67,24 @@ class _CategoriesScreenState extends ConsumerState<CategoriesScreen>
bottom: TabBar(
indicatorSize: TabBarIndicatorSize.label,
controller: _tabBarController,
tabs: [
if (!hideItems.contains("/MangaLibrary")) Tab(text: l10n.manga),
if (!hideItems.contains("/AnimeLibrary")) Tab(text: l10n.anime),
if (!hideItems.contains("/NovelLibrary")) Tab(text: l10n.novel),
],
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);
}).toList(),
),
),
body: TabBarView(
controller: _tabBarController,
children: [
if (!hideItems.contains("/MangaLibrary"))
CategoriesTab(itemType: ItemType.manga),
if (!hideItems.contains("/AnimeLibrary"))
CategoriesTab(itemType: ItemType.anime),
if (!hideItems.contains("/NovelLibrary"))
CategoriesTab(itemType: ItemType.novel),
],
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);
}).toList(),
),
),
);

View file

@ -24,7 +24,12 @@ class _TrackingDetailState extends State<TrackingDetail>
void initState() {
super.initState();
_tabBarController = TabController(length: 2, vsync: this);
_tabBarController.animateTo(0);
}
@override
void dispose() {
_tabBarController.dispose();
super.dispose();
}
@override

View file

@ -15,17 +15,19 @@ class StatisticsScreen extends ConsumerStatefulWidget {
class _StatisticsScreenState extends ConsumerState<StatisticsScreen>
with SingleTickerProviderStateMixin {
late final hideItems = ref.read(hideItemsStateProvider);
late final List<String> hideItems;
late TabController _tabController;
late final List<String> _tabList;
late final _tabList = [
if (!hideItems.contains("/MangaLibrary")) 'manga',
if (!hideItems.contains("/AnimeLibrary")) 'anime',
if (!hideItems.contains("/NovelLibrary")) 'novel',
];
@override
void didChangeDependencies() {
super.didChangeDependencies();
void initState() {
super.initState();
hideItems = ref.read(hideItemsStateProvider);
_tabList = [
if (!hideItems.contains("/MangaLibrary")) "/MangaLibrary",
if (!hideItems.contains("/AnimeLibrary")) "/AnimeLibrary",
if (!hideItems.contains("/NovelLibrary")) "/NovelLibrary",
];
_tabController = TabController(length: _tabList.length, vsync: this);
}
@ -38,7 +40,10 @@ class _StatisticsScreenState extends ConsumerState<StatisticsScreen>
@override
Widget build(BuildContext context) {
if (_tabList.isEmpty) {
return SizedBox.shrink();
return Scaffold(
appBar: AppBar(title: Text(context.l10n.statistics)),
body: Center(child: Text("EMPTY\nMPTY\nMTY\nMT\n\n")),
);
}
final l10n = context.l10n;
return Scaffold(
@ -46,23 +51,24 @@ class _StatisticsScreenState extends ConsumerState<StatisticsScreen>
title: Text(l10n.statistics),
bottom: TabBar(
controller: _tabController,
tabs: [
if (!hideItems.contains("/MangaLibrary")) Tab(text: "Manga"),
if (!hideItems.contains("/AnimeLibrary")) Tab(text: "Anime"),
if (!hideItems.contains("/NovelLibrary")) Tab(text: "Novel"),
],
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);
}).toList(),
),
),
body: TabBarView(
controller: _tabController,
children: [
if (!hideItems.contains("/MangaLibrary"))
_buildStatisticsTab(itemType: ItemType.manga),
if (!hideItems.contains("/AnimeLibrary"))
_buildStatisticsTab(itemType: ItemType.anime),
if (!hideItems.contains("/NovelLibrary"))
_buildStatisticsTab(itemType: ItemType.novel),
],
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);
}).toList(),
),
);
}

View file

@ -48,6 +48,12 @@ class _TrackerLibraryScreenState extends ConsumerState<TrackerLibraryScreen> {
List<TrackLibrarySection> _sections = [];
List<TrackPreference> _preferences = [];
@override
void dispose() {
_textEditingController.dispose();
super.dispose();
}
@override
Widget build(BuildContext context) {
final l10n = l10nLocalizations(context)!;

View file

@ -34,8 +34,9 @@ class UpdatesScreen extends ConsumerStatefulWidget {
class _UpdatesScreenState extends ConsumerState<UpdatesScreen>
with TickerProviderStateMixin {
late TabController _tabBarController;
late final List<String> _tabList;
late final List<String> hideItems;
bool _isLoading = false;
int tabs = 3;
Future<void> _updateLibrary() async {
setState(() {
_isLoading = true;
@ -92,13 +93,6 @@ class _UpdatesScreenState extends ConsumerState<UpdatesScreen>
);
}
}
await Future.doWhile(() async {
await Future.delayed(const Duration(seconds: 1));
if (mangaList.length == numbers) {
return false;
}
return true;
});
BotToast.cleanAll();
setState(() {
_isLoading = false;
@ -112,11 +106,23 @@ class _UpdatesScreenState extends ConsumerState<UpdatesScreen>
});
}
@override
void dispose() {
_textEditingController.dispose();
_tabBarController.dispose();
super.dispose();
}
@override
void initState() {
super.initState();
_tabBarController = TabController(length: tabs, vsync: this);
_tabBarController.animateTo(0);
hideItems = ref.read(hideItemsStateProvider);
_tabList = [
if (!hideItems.contains("/MangaLibrary")) "/MangaLibrary",
if (!hideItems.contains("/AnimeLibrary")) "/AnimeLibrary",
if (!hideItems.contains("/NovelLibrary")) "/NovelLibrary",
];
_tabBarController = TabController(length: _tabList.length, vsync: this);
_tabBarController.addListener(tabListener);
}
@ -125,174 +131,152 @@ class _UpdatesScreenState extends ConsumerState<UpdatesScreen>
List<History> entriesData = [];
@override
Widget build(BuildContext context) {
int newTabs = 0;
final hideItems = ref.watch(hideItemsStateProvider);
if (!hideItems.contains("/MangaLibrary")) newTabs++;
if (!hideItems.contains("/AnimeLibrary")) newTabs++;
if (!hideItems.contains("/NovelLibrary")) newTabs++;
if (newTabs == 0) {
return SizedBox.shrink();
}
if (tabs != newTabs) {
_tabBarController.removeListener(tabListener);
_tabBarController.dispose();
_tabBarController = TabController(length: newTabs, vsync: this);
_tabBarController.animateTo(0);
_tabBarController.addListener(tabListener);
setState(() {
tabs = newTabs;
});
}
final l10n = l10nLocalizations(context)!;
return DefaultTabController(
animationDuration: Duration.zero,
length: newTabs,
child: Scaffold(
appBar: AppBar(
elevation: 0,
backgroundColor: Colors.transparent,
title: _isSearch
? null
: Text(
l10n.updates,
style: TextStyle(color: Theme.of(context).hintColor),
),
actions: [
_isSearch
? SeachFormTextField(
onChanged: (value) {
setState(() {});
},
onSuffixPressed: () {
_textEditingController.clear();
setState(() {});
},
onPressed: () {
setState(() {
_isSearch = false;
});
_textEditingController.clear();
},
controller: _textEditingController,
)
: IconButton(
splashRadius: 20,
onPressed: () {
setState(() {
_isSearch = true;
});
},
icon: Icon(
Icons.search_outlined,
color: Theme.of(context).hintColor,
),
),
IconButton(
splashRadius: 20,
onPressed: () {
_updateLibrary();
},
icon: Icon(
Icons.refresh_outlined,
color: Theme.of(context).hintColor,
return Scaffold(
appBar: AppBar(
elevation: 0,
backgroundColor: Colors.transparent,
title: _isSearch
? null
: Text(
l10n.updates,
style: TextStyle(color: Theme.of(context).hintColor),
),
),
IconButton(
splashRadius: 20,
onPressed: () {
showDialog(
context: context,
builder: (context) {
return AlertDialog(
title: Text(l10n.remove_everything),
content: Text(l10n.remove_all_update_msg),
actions: [
Row(
mainAxisAlignment: MainAxisAlignment.end,
children: [
TextButton(
onPressed: () {
Navigator.pop(context);
},
child: Text(l10n.cancel),
),
const SizedBox(width: 15),
TextButton(
onPressed: () => clearUpdates(hideItems, context),
child: Text(l10n.ok),
),
],
),
],
);
actions: [
_isSearch
? SeachFormTextField(
onChanged: (value) {
setState(() {});
},
);
},
icon: Icon(
Icons.delete_sweep_outlined,
color: Theme.of(context).hintColor,
),
onSuffixPressed: () {
_textEditingController.clear();
setState(() {});
},
onPressed: () {
setState(() {
_isSearch = false;
});
_textEditingController.clear();
},
controller: _textEditingController,
)
: IconButton(
splashRadius: 20,
onPressed: () {
setState(() {
_isSearch = true;
});
},
icon: Icon(
Icons.search_outlined,
color: Theme.of(context).hintColor,
),
),
IconButton(
splashRadius: 20,
onPressed: () {
_updateLibrary();
},
icon: Icon(
Icons.refresh_outlined,
color: Theme.of(context).hintColor,
),
),
IconButton(
splashRadius: 20,
onPressed: () {
showDialog(
context: context,
builder: (context) {
return AlertDialog(
title: Text(l10n.remove_everything),
content: Text(l10n.remove_all_update_msg),
actions: [
Row(
mainAxisAlignment: MainAxisAlignment.end,
children: [
TextButton(
onPressed: () {
Navigator.pop(context);
},
child: Text(l10n.cancel),
),
const SizedBox(width: 15),
TextButton(
onPressed: () => clearUpdates(hideItems, context),
child: Text(l10n.ok),
),
],
),
],
);
},
);
},
icon: Icon(
Icons.delete_sweep_outlined,
color: Theme.of(context).hintColor,
),
),
],
bottom: TabBar(
indicatorSize: TabBarIndicatorSize.tab,
controller: _tabBarController,
tabs: [
if (!hideItems.contains("/MangaLibrary"))
Row(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Tab(text: l10n.manga),
const SizedBox(width: 8),
_updateNumbers(ref, ItemType.manga),
],
),
if (!hideItems.contains("/AnimeLibrary"))
Row(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Tab(text: l10n.anime),
const SizedBox(width: 8),
_updateNumbers(ref, ItemType.anime),
],
),
if (!hideItems.contains("/NovelLibrary"))
Row(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Tab(text: l10n.novel),
const SizedBox(width: 8),
_updateNumbers(ref, ItemType.novel),
],
),
],
bottom: TabBar(
indicatorSize: TabBarIndicatorSize.tab,
controller: _tabBarController,
tabs: [
if (!hideItems.contains("/MangaLibrary"))
Row(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Tab(text: l10n.manga),
const SizedBox(width: 8),
_updateNumbers(ref, ItemType.manga),
],
),
if (!hideItems.contains("/AnimeLibrary"))
Row(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Tab(text: l10n.anime),
const SizedBox(width: 8),
_updateNumbers(ref, ItemType.anime),
],
),
if (!hideItems.contains("/NovelLibrary"))
Row(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Tab(text: l10n.novel),
const SizedBox(width: 8),
_updateNumbers(ref, ItemType.novel),
],
),
],
),
),
body: Padding(
padding: const EdgeInsets.only(top: 10),
child: TabBarView(
controller: _tabBarController,
children: [
if (!hideItems.contains("/MangaLibrary"))
UpdateTab(
itemType: ItemType.manga,
query: _textEditingController.text,
isLoading: _isLoading,
),
if (!hideItems.contains("/AnimeLibrary"))
UpdateTab(
itemType: ItemType.anime,
query: _textEditingController.text,
isLoading: _isLoading,
),
if (!hideItems.contains("/NovelLibrary"))
UpdateTab(
itemType: ItemType.novel,
query: _textEditingController.text,
isLoading: _isLoading,
),
],
),
),
body: Padding(
padding: const EdgeInsets.only(top: 10),
child: TabBarView(
controller: _tabBarController,
children: [
if (!hideItems.contains("/MangaLibrary"))
UpdateTab(
itemType: ItemType.manga,
query: _textEditingController.text,
isLoading: _isLoading,
),
if (!hideItems.contains("/AnimeLibrary"))
UpdateTab(
itemType: ItemType.anime,
query: _textEditingController.text,
isLoading: _isLoading,
),
if (!hideItems.contains("/NovelLibrary"))
UpdateTab(
itemType: ItemType.novel,
query: _textEditingController.text,
isLoading: _isLoading,
),
],
),
),
);

View file

@ -38,6 +38,17 @@ class _MangaWebViewState extends ConsumerState<MangaWebView> {
}
}
@override
void dispose() {
if (Platform.isLinux) {
_desktopWebview?.close();
} else {
if (browser.isOpened()) browser.close();
browser.dispose();
}
super.dispose();
}
Webview? _desktopWebview;
_runWebViewDesktop() async {
if (Platform.isLinux) {

View file

@ -1,4 +1,5 @@
import 'dart:io';
import 'dart:math';
import 'package:draggable_menu/draggable_menu.dart';
import 'package:flutter/material.dart';
@ -64,10 +65,8 @@ Future<void> customDraggableTabBar({
index = tabBarController.index;
if (index != currentIndex) {
index = currentIndex;
refresh();
} else {
refresh();
}
refresh();
});
await showDialog(
@ -79,10 +78,7 @@ Future<void> customDraggableTabBar({
for (var i = 0; i < children.length; i++) ...[
MeasureWidgetSize(
onCalculateSize: (size) {
final additionnalHeight = ((List.generate(
10000,
(index) => index * 0.0001,
))..shuffle()).first;
final additionnalHeight = Random().nextDouble() * 0.01;
double newHeight = size!.height + 52.0 + additionnalHeight;
if (!(newHeight <= maxHeight)) {
newHeight = maxHeight + additionnalHeight;
@ -212,4 +208,5 @@ Future<void> customDraggableTabBar({
),
);
}
tabBarController.dispose();
}