diff --git a/lib/pages/settings/logs.dart b/lib/pages/settings/logs.dart index a49050ad..91087b7e 100644 --- a/lib/pages/settings/logs.dart +++ b/lib/pages/settings/logs.dart @@ -1,77 +1,23 @@ -import 'dart:async'; -import 'dart:io'; import 'package:flutter/material.dart'; import 'package:flutter/services.dart'; import 'package:flutter_hooks/flutter_hooks.dart'; +import 'package:hooks_riverpod/hooks_riverpod.dart'; import 'package:spotube/collections/spotube_icons.dart'; -import 'package:spotube/modules/settings/section_card_with_heading.dart'; import 'package:spotube/components/inter_scrollbar/inter_scrollbar.dart'; import 'package:spotube/components/titlebar/titlebar.dart'; import 'package:spotube/extensions/context.dart'; -import 'package:spotube/services/logger/logger.dart'; +import 'package:spotube/provider/logs/logs_provider.dart'; -class LogsPage extends HookWidget { +class LogsPage extends HookConsumerWidget { static const name = "logs"; const LogsPage({super.key}); - List<({DateTime? date, String body})> parseLogs(String raw) { - return raw - .split( - "======================================================================", - ) - .map( - (line) { - DateTime? date; - line = line - .replaceAll( - "============================== CATCHER LOG ==============================", - "", - ) - .split("\n") - .map((l) { - if (l.startsWith("Crash occurred on")) { - date = DateTime.parse( - l.split("Crash occurred on")[1].trim(), - ); - return ""; - } - return l; - }) - .where((l) => l.replaceAll("\n", "").trim().isNotEmpty) - .join("\n"); - - return ( - date: date, - body: line, - ); - }, - ) - .where((e) => e.date != null && e.body.isNotEmpty) - .toList() - ..sort((a, b) => b.date!.compareTo(a.date!)); - } - @override - Widget build(BuildContext context) { + Widget build(BuildContext context, ref) { final controller = useScrollController(); - final logs = useState>([]); - final rawLogs = useRef(""); - final path = useRef(null); - useEffect(() { - final timer = Timer.periodic(const Duration(seconds: 5), (t) async { - path.value ??= await AppLogger.getLogsPath(); - final raw = await path.value!.readAsString(); - final hasChanged = rawLogs.value != raw; - rawLogs.value = raw; - if (hasChanged) logs.value = parseLogs(rawLogs.value); - }); - - return () { - timer.cancel(); - }; - }, []); + final logsQuery = ref.watch(logsProvider); return Scaffold( appBar: PageWindowTitleBar( @@ -82,7 +28,9 @@ class LogsPage extends HookWidget { icon: const Icon(SpotubeIcons.clipboard), iconSize: 16, onPressed: () async { - await Clipboard.setData(ClipboardData(text: rawLogs.value)); + final logsSnapshot = await ref.read(logsProvider.future); + + await Clipboard.setData(ClipboardData(text: logsSnapshot)); if (context.mounted) { ScaffoldMessenger.of(context).showSnackBar( SnackBar( @@ -95,52 +43,22 @@ class LogsPage extends HookWidget { ], ), body: SafeArea( - child: InterScrollbar( - controller: controller, - child: ListView.builder( - controller: controller, - itemCount: logs.value.length, - itemBuilder: (context, index) { - final log = logs.value[index]; - return Stack( - children: [ - SectionCardWithHeading( - heading: log.date.toString(), - children: [ - Padding( - padding: const EdgeInsets.all(12.0), - child: SelectableText(log.body), - ), - ], + child: switch (logsQuery) { + AsyncData(:final value) => Card( + child: InterScrollbar( + controller: controller, + child: Padding( + padding: const EdgeInsets.all(8.0), + child: SingleChildScrollView( + controller: controller, + child: Text(value), ), - Positioned( - right: 10, - top: 0, - child: IconButton( - icon: const Icon(SpotubeIcons.clipboard), - onPressed: () async { - await Clipboard.setData( - ClipboardData(text: log.body), - ); - if (context.mounted) { - ScaffoldMessenger.of(context).showSnackBar( - SnackBar( - content: Text( - context.l10n.copied_to_clipboard( - log.date.toString(), - ), - ), - ), - ); - } - }, - ), - ), - ], - ); - }, - ), - ), + ), + ), + ), + AsyncError(:final error) => Center(child: Text(error.toString())), + _ => const Center(child: CircularProgressIndicator()), + }, ), ); } diff --git a/lib/provider/logs/logs_provider.dart b/lib/provider/logs/logs_provider.dart new file mode 100644 index 00000000..b0e95cae --- /dev/null +++ b/lib/provider/logs/logs_provider.dart @@ -0,0 +1,12 @@ +import 'dart:convert'; + +import 'package:hooks_riverpod/hooks_riverpod.dart'; +import 'package:spotube/services/logger/logger.dart'; + +final logsProvider = StreamProvider.autoDispose((ref) async* { + final file = await AppLogger.getLogsPath(); + final stream = file.openRead().transform(utf8.decoder); + await for (final line in stream) { + yield line; + } +}); diff --git a/macos/Podfile.lock b/macos/Podfile.lock index 9b122cbe..b3092d8c 100644 --- a/macos/Podfile.lock +++ b/macos/Podfile.lock @@ -61,8 +61,6 @@ PODS: - sqlite3/rtree - system_theme (0.0.1): - FlutterMacOS - - system_tray (0.0.1): - - FlutterMacOS - tray_manager (0.0.1): - FlutterMacOS - url_launcher_macos (0.0.1): @@ -93,7 +91,6 @@ DEPENDENCIES: - sqflite (from `Flutter/ephemeral/.symlinks/plugins/sqflite/darwin`) - sqlite3_flutter_libs (from `Flutter/ephemeral/.symlinks/plugins/sqlite3_flutter_libs/macos`) - system_theme (from `Flutter/ephemeral/.symlinks/plugins/system_theme/macos`) - - system_tray (from `Flutter/ephemeral/.symlinks/plugins/system_tray/macos`) - tray_manager (from `Flutter/ephemeral/.symlinks/plugins/tray_manager/macos`) - url_launcher_macos (from `Flutter/ephemeral/.symlinks/plugins/url_launcher_macos/macos`) - window_manager (from `Flutter/ephemeral/.symlinks/plugins/window_manager/macos`) @@ -148,8 +145,6 @@ EXTERNAL SOURCES: :path: Flutter/ephemeral/.symlinks/plugins/sqlite3_flutter_libs/macos system_theme: :path: Flutter/ephemeral/.symlinks/plugins/system_theme/macos - system_tray: - :path: Flutter/ephemeral/.symlinks/plugins/system_tray/macos tray_manager: :path: Flutter/ephemeral/.symlinks/plugins/tray_manager/macos url_launcher_macos: @@ -182,7 +177,6 @@ SPEC CHECKSUMS: sqlite3: 292c3e1bfe89f64e51ea7fc7dab9182a017c8630 sqlite3_flutter_libs: 1be4459672f8168ded2d8667599b8e3ca5e72b83 system_theme: c7b9f6659a5caa26c9bc2284da096781e9a6fcbc - system_tray: e53c972838c69589ff2e77d6d3abfd71332f9e5d tray_manager: 9064e219c56d75c476e46b9a21182087930baf90 url_launcher_macos: d2691c7dd33ed713bf3544850a623080ec693d95 window_manager: 3a1844359a6295ab1e47659b1a777e36773cd6e8