mirror of
https://github.com/KRTirtho/spotube.git
synced 2025-09-13 07:55:18 +00:00
feat: logs page in settings
This commit is contained in:
parent
4a75f3dbd1
commit
b78e7f57a0
@ -8,6 +8,7 @@ import 'package:spotube/pages/lyrics/mini_lyrics.dart';
|
||||
import 'package:spotube/pages/search/search.dart';
|
||||
import 'package:spotube/pages/settings/blacklist.dart';
|
||||
import 'package:spotube/pages/settings/about.dart';
|
||||
import 'package:spotube/pages/settings/logs.dart';
|
||||
import 'package:spotube/utils/platform.dart';
|
||||
import 'package:spotube/components/shared/spotube_page_route.dart';
|
||||
import 'package:spotube/pages/album/album.dart';
|
||||
@ -83,10 +84,16 @@ final router = GoRouter(
|
||||
child: const BlackListPage(),
|
||||
),
|
||||
),
|
||||
GoRoute(
|
||||
path: "logs",
|
||||
pageBuilder: (context, state) => SpotubeSlidePage(
|
||||
child: const LogsPage(),
|
||||
),
|
||||
),
|
||||
GoRoute(
|
||||
path: "about",
|
||||
pageBuilder: (context, state) => const SpotubePage(
|
||||
child: AboutSpotube(),
|
||||
pageBuilder: (context, state) => SpotubeSlidePage(
|
||||
child: const AboutSpotube(),
|
||||
),
|
||||
),
|
||||
],
|
||||
|
@ -87,4 +87,6 @@ abstract class SpotubeIcons {
|
||||
static const volumeLow = FeatherIcons.volume;
|
||||
static const volumeMute = FeatherIcons.volumeX;
|
||||
static const timer = FeatherIcons.clock;
|
||||
static const logs = FeatherIcons.fileText;
|
||||
static const clipboard = FeatherIcons.clipboard;
|
||||
}
|
||||
|
@ -244,5 +244,7 @@
|
||||
"mins": "{minutes} Minutes",
|
||||
"hours": "{hours} Hours",
|
||||
"hour": "{hours} Hour",
|
||||
"custom_hours": "Custom Hours"
|
||||
"custom_hours": "Custom Hours",
|
||||
"logs": "Logs",
|
||||
"developers": "Developers"
|
||||
}
|
@ -26,7 +26,6 @@ import 'package:spotube/provider/palette_provider.dart';
|
||||
import 'package:spotube/provider/user_preferences_provider.dart';
|
||||
import 'package:spotube/services/audio_player/audio_player.dart';
|
||||
import 'package:spotube/themes/theme.dart';
|
||||
import 'package:spotube/utils/custom_toast_handler.dart';
|
||||
import 'package:spotube/utils/persisted_state_notifier.dart';
|
||||
import 'package:supabase_flutter/supabase_flutter.dart';
|
||||
import 'package:system_theme/system_theme.dart';
|
||||
@ -122,16 +121,11 @@ Future<void> main(List<String> rawArgs) async {
|
||||
releaseConfig: CatcherOptions(
|
||||
SilentReportMode(),
|
||||
[
|
||||
if (arguments["verbose"] ?? false)
|
||||
ConsoleHandler(
|
||||
enableDeviceParameters: false,
|
||||
enableApplicationParameters: false,
|
||||
),
|
||||
if (arguments["verbose"] ?? false) ConsoleHandler(),
|
||||
FileHandler(
|
||||
await getLogsPath(),
|
||||
printLogs: false,
|
||||
),
|
||||
CustomToastHandler(),
|
||||
],
|
||||
),
|
||||
runAppFunction: () {
|
||||
|
139
lib/pages/settings/logs.dart
Normal file
139
lib/pages/settings/logs.dart
Normal file
@ -0,0 +1,139 @@
|
||||
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:spotube/collections/spotube_icons.dart';
|
||||
import 'package:spotube/components/settings/section_card_with_heading.dart';
|
||||
import 'package:spotube/components/shared/page_window_title_bar.dart';
|
||||
import 'package:spotube/extensions/context.dart';
|
||||
import 'package:spotube/models/logger.dart';
|
||||
|
||||
class LogsPage extends HookWidget {
|
||||
const LogsPage({Key? key}) : super(key: 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) {
|
||||
final logs = useState<List<({DateTime? date, String body})>>([]);
|
||||
final rawLogs = useRef<String>("");
|
||||
final path = useRef<File?>(null);
|
||||
|
||||
useEffect(() {
|
||||
final timer = Timer.periodic(const Duration(seconds: 5), (t) async {
|
||||
path.value ??= await 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();
|
||||
};
|
||||
}, []);
|
||||
|
||||
return Scaffold(
|
||||
appBar: PageWindowTitleBar(
|
||||
title: Text(context.l10n.logs),
|
||||
leading: const BackButton(),
|
||||
actions: [
|
||||
IconButton(
|
||||
icon: const Icon(SpotubeIcons.clipboard),
|
||||
iconSize: 16,
|
||||
onPressed: () async {
|
||||
await Clipboard.setData(ClipboardData(text: rawLogs.value));
|
||||
if (context.mounted) {
|
||||
ScaffoldMessenger.of(context).showSnackBar(
|
||||
SnackBar(
|
||||
content: Text(context.l10n.copied_to_clipboard("")),
|
||||
),
|
||||
);
|
||||
}
|
||||
},
|
||||
),
|
||||
],
|
||||
),
|
||||
body: SafeArea(
|
||||
child: ListView.builder(
|
||||
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),
|
||||
),
|
||||
],
|
||||
),
|
||||
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(),
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
},
|
||||
),
|
||||
),
|
||||
],
|
||||
);
|
||||
},
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
@ -406,6 +406,19 @@ class SettingsPage extends HookConsumerWidget {
|
||||
),
|
||||
],
|
||||
),
|
||||
SectionCardWithHeading(
|
||||
heading: context.l10n.developers,
|
||||
children: [
|
||||
ListTile(
|
||||
leading: const Icon(SpotubeIcons.logs),
|
||||
title: Text(context.l10n.logs),
|
||||
trailing: const Icon(SpotubeIcons.angleRight),
|
||||
onTap: () {
|
||||
GoRouter.of(context).push("/settings/logs");
|
||||
},
|
||||
)
|
||||
],
|
||||
),
|
||||
SectionCardWithHeading(
|
||||
heading: context.l10n.about,
|
||||
children: [
|
||||
|
@ -1,58 +0,0 @@
|
||||
import 'package:catcher/model/platform_type.dart';
|
||||
import 'package:catcher/model/report.dart';
|
||||
import 'package:catcher/model/report_handler.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:motion_toast/motion_toast.dart';
|
||||
import 'package:spotube/collections/spotube_icons.dart';
|
||||
import 'package:spotube/extensions/context.dart';
|
||||
|
||||
class CustomToastHandler extends ReportHandler {
|
||||
CustomToastHandler();
|
||||
|
||||
@override
|
||||
Future<bool> handle(Report error, BuildContext? context) async {
|
||||
final theme = Theme.of(context!);
|
||||
|
||||
MotionToast(
|
||||
primaryColor: theme.colorScheme.errorContainer,
|
||||
icon: SpotubeIcons.error,
|
||||
title: Text(
|
||||
context.l10n.something_went_wrong,
|
||||
style: theme.textTheme.bodyMedium?.copyWith(
|
||||
fontWeight: FontWeight.bold,
|
||||
color: theme.colorScheme.onError,
|
||||
),
|
||||
),
|
||||
description: Text(
|
||||
error.error.toString(),
|
||||
style: theme.textTheme.bodyMedium?.copyWith(
|
||||
color: theme.colorScheme.onError,
|
||||
),
|
||||
),
|
||||
dismissable: true,
|
||||
toastDuration: const Duration(seconds: 5),
|
||||
borderRadius: 10,
|
||||
).show(context);
|
||||
return true;
|
||||
}
|
||||
|
||||
@override
|
||||
List<PlatformType> getSupportedPlatforms() => [
|
||||
PlatformType.android,
|
||||
PlatformType.iOS,
|
||||
PlatformType.web,
|
||||
PlatformType.linux,
|
||||
PlatformType.macOS,
|
||||
PlatformType.windows,
|
||||
];
|
||||
|
||||
@override
|
||||
bool isContextRequired() {
|
||||
return true;
|
||||
}
|
||||
|
||||
@override
|
||||
bool shouldHandleWhenRejected() {
|
||||
return false;
|
||||
}
|
||||
}
|
@ -1134,14 +1134,6 @@ packages:
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "1.0.4"
|
||||
motion_toast:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
name: motion_toast
|
||||
sha256: f33fad8264d6d5359e41f2027d2d833614401c3983102e8f0aa13ccbbdcdeecd
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "2.6.8"
|
||||
mutex:
|
||||
dependency: transitive
|
||||
description:
|
||||
|
@ -102,7 +102,6 @@ dependencies:
|
||||
device_preview: ^1.1.0
|
||||
media_kit_native_event_loop: ^1.0.4
|
||||
dbus: ^0.7.8
|
||||
motion_toast: ^2.6.8
|
||||
background_downloader: ^7.4.0
|
||||
|
||||
dev_dependencies:
|
||||
|
Loading…
Reference in New Issue
Block a user