From a381e7baa76dada4ccdb9389690a0bddbd7af41e Mon Sep 17 00:00:00 2001 From: NBA2K1 <78034913+NBA2K1@users.noreply.github.com> Date: Sun, 19 Apr 2026 05:24:59 +0200 Subject: [PATCH] Fix Exception MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Replace synchronous Isar writes with async transactions in `AboutScreen` - Make `AppLogger.init()` and `dispose()` fully async and guarded with `_busy` - Remove `StreamController` queue and write directly to the IOSink - Prevent double‑initialization and race conditions using `_initialized` + `_busy` - Update log toggle handler to await logger init/dispose for consistency Fix following Exception when disabling and re-enabling logger: ``` Exception has occurred. StateError (Bad state: Stream has already been listened to.) ``` --- lib/modules/more/about/about_screen.dart | 12 ++--- lib/utils/log/logger.dart | 68 +++++++++++++----------- 2 files changed, 44 insertions(+), 36 deletions(-) diff --git a/lib/modules/more/about/about_screen.dart b/lib/modules/more/about/about_screen.dart index 8351b0af..7ebde1ec 100644 --- a/lib/modules/more/about/about_screen.dart +++ b/lib/modules/more/about/about_screen.dart @@ -86,18 +86,18 @@ class AboutScreen extends ConsumerWidget { SwitchListTile( title: Text(l10n.logs_on), value: enableLogs, - onChanged: (value) { - isar.writeTxnSync(() { - final settings = isar.settings.getSync(227); - isar.settings.putSync( + onChanged: (value) async { + await isar.writeTxn(() async { + final settings = await isar.settings.get(227); + await isar.settings.put( settings!..enableLogs = value, ); }); ref.invalidate(logsStateProvider); if (value) { - AppLogger.init(); + await AppLogger.init(); } else { - AppLogger.dispose(); + await AppLogger.dispose(); } }, ), diff --git a/lib/utils/log/logger.dart b/lib/utils/log/logger.dart index 22f8a8c6..d67c81d8 100644 --- a/lib/utils/log/logger.dart +++ b/lib/utils/log/logger.dart @@ -6,39 +6,41 @@ import 'package:mangayomi/providers/storage_provider.dart'; import 'package:path/path.dart' as path; class AppLogger { - static final _logQueue = StreamController(); - static late File _logFile; - static late IOSink _sink; + static File? _logFile; + static IOSink? _sink; static bool _initialized = false; + static bool _busy = false; /// Initialize the logger static Future init() async { - final enabled = isar.settings.getSync(227)?.enableLogs ?? false; - if (!enabled) return; - final storage = StorageProvider(); - final directory = await storage.getDefaultDirectory(); - _logFile = File(path.join(directory!.path, 'logs.txt')); + if (_initialized || _busy) return; + _busy = true; + try { + final enabled = (await isar.settings.get(227))?.enableLogs ?? false; + if (!enabled) return; + final storage = StorageProvider(); + final directory = await storage.getDefaultDirectory(); + _logFile = File(path.join(directory!.path, 'logs.txt')); - if (await _logFile.exists() && await _logFile.length() > 100 * 1024) { - await _logFile.delete(); + if (await _logFile!.exists() && await _logFile!.length() > 100 * 1024) { + await _logFile!.delete(); + } + + if (!await _logFile!.exists()) { + await _logFile!.create(recursive: true); + } + + _sink = _logFile!.openWrite(mode: FileMode.append); + _initialized = true; + + log('\n\nLogger initialized\n\n'); + } finally { + _busy = false; } - - if (!await _logFile.exists()) { - await _logFile.create(recursive: true); - } - - _sink = _logFile.openWrite(mode: FileMode.append); - _initialized = true; - - _logQueue.stream.listen((log) { - _sink.writeln(log); - }); - - log('\n\nLogger initialized\n\n'); } static void log(String message, {LogLevel logLevel = LogLevel.info}) { - if (!_initialized) return; + if (!_initialized || _sink == null) return; final now = DateTime.now(); final timestamp = @@ -46,15 +48,21 @@ class AppLogger { '${now.hour.toString().padLeft(2, '0')}:${now.minute.toString().padLeft(2, '0')}:${now.second.toString().padLeft(2, '0')}'; final logMessage = '[$timestamp][${logLevel.toString()}] $message'; - _logQueue.add(logMessage); + _sink!.writeln(logMessage); } static Future dispose() async { - if (!_initialized) return; - await _logQueue.close(); - await _sink.flush(); - await _sink.close(); - _initialized = false; + if (!_initialized || _busy) return; + _busy = true; + try { + await _sink?.flush(); + await _sink?.close(); + _sink = null; + _logFile = null; + _initialized = false; + } finally { + _busy = false; + } } }