mirror of
https://github.com/Dr-Blank/Vaani.git
synced 2025-12-27 21:39:31 +00:00
feat: error reporting with logs (#45)
* feat: add ability to get logs file from ui * test: add unit test for log line parsing in logs_provider * refactor: update all logs to obfuscate sensitive information * feat: generate dynamic zip file name for logs export * feat: enhance logging in audiobook player and provider for better debugging * refactor: extract user display logic into UserBar widget for offline access of settings and logs * feat: add About section with app metadata and source code link in YouPage
This commit is contained in:
parent
7b0c2c4b88
commit
35a2d7cfce
44 changed files with 861 additions and 176 deletions
|
|
@ -5,10 +5,12 @@ import 'package:hooks_riverpod/hooks_riverpod.dart';
|
|||
import 'package:vaani/api/api_provider.dart';
|
||||
import 'package:vaani/api/authenticated_user_provider.dart';
|
||||
import 'package:vaani/api/server_provider.dart';
|
||||
import 'package:vaani/main.dart';
|
||||
import 'package:vaani/models/error_response.dart';
|
||||
import 'package:vaani/router/router.dart';
|
||||
import 'package:vaani/settings/api_settings_provider.dart';
|
||||
import 'package:vaani/settings/models/models.dart' as model;
|
||||
import 'package:vaani/shared/extensions/obfuscation.dart';
|
||||
import 'package:vaani/shared/widgets/add_new_server.dart';
|
||||
|
||||
class ServerManagerPage extends HookConsumerWidget {
|
||||
|
|
@ -25,8 +27,8 @@ class ServerManagerPage extends HookConsumerWidget {
|
|||
final serverURIController = useTextEditingController();
|
||||
final formKey = GlobalKey<FormState>();
|
||||
|
||||
debugPrint('registered servers: $registeredServers');
|
||||
debugPrint('available users: $availableUsers');
|
||||
appLogger.fine('registered servers: ${registeredServers.obfuscate()}');
|
||||
appLogger.fine('available users: ${availableUsers.obfuscate()}');
|
||||
return Scaffold(
|
||||
appBar: AppBar(
|
||||
title: const Text('Manage Accounts'),
|
||||
|
|
|
|||
|
|
@ -1,9 +1,9 @@
|
|||
import 'package:flutter/material.dart';
|
||||
import 'package:go_router/go_router.dart';
|
||||
import 'package:hooks_riverpod/hooks_riverpod.dart';
|
||||
import 'package:shelfsdk/audiobookshelf_api.dart';
|
||||
import 'package:vaani/api/api_provider.dart';
|
||||
import 'package:vaani/router/router.dart';
|
||||
import 'package:vaani/settings/constants.dart';
|
||||
import 'package:vaani/shared/utils.dart';
|
||||
import 'package:vaani/shared/widgets/not_implemented.dart';
|
||||
|
||||
|
|
@ -12,27 +12,6 @@ class YouPage extends HookConsumerWidget {
|
|||
super.key,
|
||||
});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context, WidgetRef ref) {
|
||||
final me = ref.watch(meProvider);
|
||||
return me.when(
|
||||
data: (data) {
|
||||
return _YouPage(userData: data);
|
||||
},
|
||||
loading: () => const CircularProgressIndicator(),
|
||||
error: (error, stack) => Text('Error: $error'),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
class _YouPage extends HookConsumerWidget {
|
||||
const _YouPage({
|
||||
super.key,
|
||||
required this.userData,
|
||||
});
|
||||
|
||||
final User userData;
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context, WidgetRef ref) {
|
||||
final api = ref.watch(authenticatedApiProvider);
|
||||
|
|
@ -41,14 +20,21 @@ class _YouPage extends HookConsumerWidget {
|
|||
// title: const Text('You'),
|
||||
backgroundColor: Colors.transparent,
|
||||
actions: [
|
||||
IconButton(
|
||||
tooltip: 'Logs',
|
||||
icon: const Icon(Icons.bug_report),
|
||||
onPressed: () {
|
||||
context.pushNamed(Routes.logs.name);
|
||||
},
|
||||
),
|
||||
// IconButton(
|
||||
// icon: const Icon(Icons.edit),
|
||||
// onPressed: () {
|
||||
// // Handle edit profile
|
||||
// },
|
||||
// ),
|
||||
// settings button
|
||||
IconButton(
|
||||
tooltip: 'Settings',
|
||||
icon: const Icon(Icons.settings),
|
||||
onPressed: () {
|
||||
context.pushNamed(Routes.settings.name);
|
||||
|
|
@ -64,30 +50,7 @@ class _YouPage extends HookConsumerWidget {
|
|||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Row(
|
||||
children: [
|
||||
CircleAvatar(
|
||||
radius: 40,
|
||||
// backgroundImage: NetworkImage(userData.avatarUrl),
|
||||
// first letter of the username
|
||||
child: Text(
|
||||
userData.username[0].toUpperCase(),
|
||||
style: const TextStyle(
|
||||
fontSize: 32,
|
||||
fontWeight: FontWeight.bold,
|
||||
),
|
||||
),
|
||||
),
|
||||
const SizedBox(width: 16),
|
||||
Text(
|
||||
userData.username,
|
||||
style: const TextStyle(
|
||||
fontSize: 24,
|
||||
fontWeight: FontWeight.bold,
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
UserBar(),
|
||||
const SizedBox(height: 16),
|
||||
Wrap(
|
||||
spacing: 8,
|
||||
|
|
@ -121,21 +84,6 @@ class _YouPage extends HookConsumerWidget {
|
|||
title: const Text('My Playlists'),
|
||||
onTap: () {
|
||||
// Handle navigation to playlists
|
||||
},
|
||||
),
|
||||
ListTile(
|
||||
leading: const Icon(Icons.help),
|
||||
title: const Text('Help'),
|
||||
onTap: () {
|
||||
// Handle navigation to help website
|
||||
showNotImplementedToast(context);
|
||||
},
|
||||
),
|
||||
ListTile(
|
||||
leading: const Icon(Icons.info),
|
||||
title: const Text('About'),
|
||||
onTap: () {
|
||||
// Handle navigation to about
|
||||
showNotImplementedToast(context);
|
||||
},
|
||||
),
|
||||
|
|
@ -149,10 +97,40 @@ class _YouPage extends HookConsumerWidget {
|
|||
);
|
||||
},
|
||||
),
|
||||
// const SizedBox(height: 16),
|
||||
// const Text('App Version: 1.0.0'),
|
||||
// const Text('Server Version: 1.0.0'),
|
||||
// const Text('Author: Your Name'),
|
||||
ListTile(
|
||||
leading: const Icon(Icons.help),
|
||||
title: const Text('Help'),
|
||||
onTap: () {
|
||||
// Handle navigation to help website
|
||||
showNotImplementedToast(context);
|
||||
},
|
||||
),
|
||||
|
||||
AboutListTile(
|
||||
icon: const Icon(Icons.info),
|
||||
applicationName: AppMetadata.appName,
|
||||
applicationVersion: AppMetadata.version,
|
||||
applicationLegalese:
|
||||
'Made with ❤️ by ${AppMetadata.author}',
|
||||
aboutBoxChildren: [
|
||||
// link to github repo
|
||||
ListTile(
|
||||
leading: Icon(Icons.code),
|
||||
title: Text('Source Code'),
|
||||
onTap: () {
|
||||
handleLaunchUrl(AppMetadata.githubRepo);
|
||||
},
|
||||
),
|
||||
],
|
||||
// apply blend mode to the icon to match the primary color
|
||||
applicationIcon: ColorFiltered(
|
||||
colorFilter: ColorFilter.mode(
|
||||
Theme.of(context).colorScheme.primary,
|
||||
BlendMode.srcIn,
|
||||
),
|
||||
child: const VaaniLogo(),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
|
|
@ -162,3 +140,71 @@ class _YouPage extends HookConsumerWidget {
|
|||
);
|
||||
}
|
||||
}
|
||||
|
||||
class UserBar extends HookConsumerWidget {
|
||||
const UserBar({
|
||||
super.key,
|
||||
});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context, WidgetRef ref) {
|
||||
final me = ref.watch(meProvider);
|
||||
|
||||
return me.when(
|
||||
data: (userData) {
|
||||
return Row(
|
||||
children: [
|
||||
CircleAvatar(
|
||||
radius: 40,
|
||||
// backgroundImage: NetworkImage(userData.avatarUrl),
|
||||
// first letter of the username
|
||||
child: Text(
|
||||
userData.username[0].toUpperCase(),
|
||||
style: const TextStyle(
|
||||
fontSize: 32,
|
||||
fontWeight: FontWeight.bold,
|
||||
),
|
||||
),
|
||||
),
|
||||
const SizedBox(width: 16),
|
||||
Text(
|
||||
userData.username,
|
||||
style: const TextStyle(
|
||||
fontSize: 24,
|
||||
fontWeight: FontWeight.bold,
|
||||
),
|
||||
),
|
||||
],
|
||||
);
|
||||
},
|
||||
loading: () => const CircularProgressIndicator(),
|
||||
error: (error, stack) => Text('Error: $error'),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
class VaaniLogo extends StatelessWidget {
|
||||
const VaaniLogo({
|
||||
super.key,
|
||||
this.size,
|
||||
this.duration = const Duration(milliseconds: 750),
|
||||
this.curve = Curves.fastOutSlowIn,
|
||||
});
|
||||
|
||||
final double? size;
|
||||
final Duration duration;
|
||||
final Curve curve;
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final IconThemeData iconTheme = IconTheme.of(context);
|
||||
final double? iconSize = size ?? iconTheme.size;
|
||||
return AnimatedContainer(
|
||||
width: iconSize,
|
||||
height: iconSize,
|
||||
duration: duration,
|
||||
curve: curve,
|
||||
child: Image.asset('assets/images/vaani_logo_foreground.png'),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue