mirror of
https://github.com/Dr-Blank/Vaani.git
synced 2026-07-07 01:41:33 +00:00
feat: add ability to get logs file from ui
This commit is contained in:
parent
7b0c2c4b88
commit
48d5f039f9
12 changed files with 474 additions and 12 deletions
36
lib/features/logging/core/logger.dart
Normal file
36
lib/features/logging/core/logger.dart
Normal file
|
|
@ -0,0 +1,36 @@
|
||||||
|
import 'dart:io';
|
||||||
|
|
||||||
|
import 'package:flutter/foundation.dart';
|
||||||
|
import 'package:logging/logging.dart';
|
||||||
|
import 'package:logging_appenders/logging_appenders.dart';
|
||||||
|
import 'package:path_provider/path_provider.dart';
|
||||||
|
import 'package:vaani/shared/extensions/duration_format.dart';
|
||||||
|
|
||||||
|
Future<String> getLoggingFilePath() async {
|
||||||
|
final Directory directory = await getApplicationDocumentsDirectory();
|
||||||
|
return '${directory.path}/vaani.log';
|
||||||
|
}
|
||||||
|
|
||||||
|
Future<void> initLogging() async {
|
||||||
|
final formatter = const DefaultLogRecordFormatter();
|
||||||
|
if (kReleaseMode) {
|
||||||
|
Logger.root.level = Level.INFO; // is also the default
|
||||||
|
// Write to a file
|
||||||
|
RotatingFileAppender(
|
||||||
|
baseFilePath: await getLoggingFilePath(),
|
||||||
|
formatter: formatter,
|
||||||
|
).attachToLogger(Logger.root);
|
||||||
|
} else {
|
||||||
|
Logger.root.level = Level.FINE; // Capture all logs
|
||||||
|
RotatingFileAppender(
|
||||||
|
baseFilePath: await getLoggingFilePath(),
|
||||||
|
formatter: formatter,
|
||||||
|
).attachToLogger(Logger.root);
|
||||||
|
Logger.root.onRecord.listen((record) {
|
||||||
|
// Print log records to the console
|
||||||
|
debugPrint(
|
||||||
|
'${record.loggerName}: ${record.level.name}: ${record.time.time}: ${record.message}',
|
||||||
|
);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
72
lib/features/logging/providers/logs_provider.dart
Normal file
72
lib/features/logging/providers/logs_provider.dart
Normal file
|
|
@ -0,0 +1,72 @@
|
||||||
|
import 'dart:io';
|
||||||
|
|
||||||
|
import 'package:archive/archive_io.dart';
|
||||||
|
import 'package:logging/logging.dart';
|
||||||
|
import 'package:path_provider/path_provider.dart';
|
||||||
|
import 'package:riverpod_annotation/riverpod_annotation.dart';
|
||||||
|
import 'package:vaani/features/logging/core/logger.dart';
|
||||||
|
|
||||||
|
part 'logs_provider.g.dart';
|
||||||
|
|
||||||
|
@riverpod
|
||||||
|
class Logs extends _$Logs {
|
||||||
|
@override
|
||||||
|
Future<List<LogRecord>> build() async {
|
||||||
|
final path = await getLoggingFilePath();
|
||||||
|
final file = File(path);
|
||||||
|
if (!file.existsSync()) {
|
||||||
|
return [];
|
||||||
|
}
|
||||||
|
final lines = await file.readAsLines();
|
||||||
|
return lines.map(parseLogLine).toList();
|
||||||
|
}
|
||||||
|
|
||||||
|
Future<void> clear() async {
|
||||||
|
final path = await getLoggingFilePath();
|
||||||
|
final file = File(path);
|
||||||
|
await file.writeAsString('');
|
||||||
|
state = AsyncData([]);
|
||||||
|
}
|
||||||
|
|
||||||
|
Future<String> getZipFilePath() async {
|
||||||
|
var encoder = ZipFileEncoder();
|
||||||
|
encoder.create(await generateZipFilePath());
|
||||||
|
encoder.addFile(File(await getLoggingFilePath()));
|
||||||
|
encoder.close();
|
||||||
|
return encoder.zipPath;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Future<String> generateZipFilePath() async {
|
||||||
|
Directory appDocDirectory = await getTemporaryDirectory();
|
||||||
|
return '${appDocDirectory.path}/vaani_logs.zip';
|
||||||
|
}
|
||||||
|
|
||||||
|
Level parseLevel(String level) {
|
||||||
|
return Level.LEVELS
|
||||||
|
.firstWhere((l) => l.name == level, orElse: () => Level.ALL);
|
||||||
|
}
|
||||||
|
|
||||||
|
LogRecord parseLogLine(String line) {
|
||||||
|
// 2024-10-03 00:48:58.012400 INFO GoRouter - getting location for name: "logs"
|
||||||
|
|
||||||
|
final RegExp logLineRegExp = RegExp(
|
||||||
|
r'(\d{4}-\d{2}-\d{2} \d{2}:\d{2}:\d{2}\.\d{6}) (\w+) (\w+) - (.+)',
|
||||||
|
);
|
||||||
|
|
||||||
|
final match = logLineRegExp.firstMatch(line);
|
||||||
|
if (match == null) {
|
||||||
|
// return as is
|
||||||
|
return LogRecord(Level.ALL, line, 'Unknown');
|
||||||
|
}
|
||||||
|
|
||||||
|
final timeString = match.group(1)!;
|
||||||
|
final levelString = match.group(2)!;
|
||||||
|
final loggerName = match.group(3)!;
|
||||||
|
final message = match.group(4)!;
|
||||||
|
|
||||||
|
final time = DateTime.parse(timeString);
|
||||||
|
final level = parseLevel(levelString);
|
||||||
|
|
||||||
|
return LogRecord(level, message, loggerName, time);
|
||||||
|
}
|
||||||
25
lib/features/logging/providers/logs_provider.g.dart
Normal file
25
lib/features/logging/providers/logs_provider.g.dart
Normal file
|
|
@ -0,0 +1,25 @@
|
||||||
|
// GENERATED CODE - DO NOT MODIFY BY HAND
|
||||||
|
|
||||||
|
part of 'logs_provider.dart';
|
||||||
|
|
||||||
|
// **************************************************************************
|
||||||
|
// RiverpodGenerator
|
||||||
|
// **************************************************************************
|
||||||
|
|
||||||
|
String _$logsHash() => r'901376741d17ddbb889d1b7b96bc2882289720a0';
|
||||||
|
|
||||||
|
/// See also [Logs].
|
||||||
|
@ProviderFor(Logs)
|
||||||
|
final logsProvider =
|
||||||
|
AutoDisposeAsyncNotifierProvider<Logs, List<LogRecord>>.internal(
|
||||||
|
Logs.new,
|
||||||
|
name: r'logsProvider',
|
||||||
|
debugGetCreateSourceHash:
|
||||||
|
const bool.fromEnvironment('dart.vm.product') ? null : _$logsHash,
|
||||||
|
dependencies: null,
|
||||||
|
allTransitiveDependencies: null,
|
||||||
|
);
|
||||||
|
|
||||||
|
typedef _$Logs = AutoDisposeAsyncNotifier<List<LogRecord>>;
|
||||||
|
// ignore_for_file: type=lint
|
||||||
|
// ignore_for_file: subtype_of_sealed_class, invalid_use_of_internal_member, invalid_use_of_visible_for_testing_member
|
||||||
266
lib/features/logging/view/logs_page.dart
Normal file
266
lib/features/logging/view/logs_page.dart
Normal file
|
|
@ -0,0 +1,266 @@
|
||||||
|
import 'dart:io';
|
||||||
|
|
||||||
|
import 'package:file_picker/file_picker.dart';
|
||||||
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:flutter_hooks/flutter_hooks.dart';
|
||||||
|
import 'package:hooks_riverpod/hooks_riverpod.dart';
|
||||||
|
import 'package:logging/logging.dart';
|
||||||
|
import 'package:share_plus/share_plus.dart';
|
||||||
|
import 'package:vaani/features/logging/providers/logs_provider.dart';
|
||||||
|
import 'package:vaani/main.dart';
|
||||||
|
|
||||||
|
class LogsPage extends HookConsumerWidget {
|
||||||
|
const LogsPage({super.key});
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context, WidgetRef ref) {
|
||||||
|
final logs = ref.watch(logsProvider);
|
||||||
|
final theme = Theme.of(context);
|
||||||
|
final scrollController = useScrollController();
|
||||||
|
return Scaffold(
|
||||||
|
appBar: AppBar(
|
||||||
|
title: const Text('Logs'),
|
||||||
|
actions: [
|
||||||
|
IconButton(
|
||||||
|
tooltip: 'Clear logs',
|
||||||
|
icon: const Icon(Icons.delete_forever),
|
||||||
|
onPressed: () async {
|
||||||
|
// ask for confirmation
|
||||||
|
final shouldClear = await showDialog<bool>(
|
||||||
|
context: context,
|
||||||
|
builder: (context) {
|
||||||
|
return AlertDialog(
|
||||||
|
title: const Text('Clear logs?'),
|
||||||
|
actions: [
|
||||||
|
TextButton(
|
||||||
|
onPressed: () {
|
||||||
|
Navigator.of(context).pop(false);
|
||||||
|
},
|
||||||
|
child: const Text('Cancel'),
|
||||||
|
),
|
||||||
|
TextButton(
|
||||||
|
onPressed: () {
|
||||||
|
Navigator.of(context).pop(true);
|
||||||
|
},
|
||||||
|
child: const Text('Clear'),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
);
|
||||||
|
},
|
||||||
|
);
|
||||||
|
if (shouldClear == true) {
|
||||||
|
ref.read(logsProvider.notifier).clear();
|
||||||
|
}
|
||||||
|
},
|
||||||
|
),
|
||||||
|
IconButton(
|
||||||
|
tooltip: 'Share logs',
|
||||||
|
icon: const Icon(Icons.share),
|
||||||
|
onPressed: () async {
|
||||||
|
appLogger.info('Preparing logs for sharing');
|
||||||
|
final zipLogFilePath =
|
||||||
|
await ref.read(logsProvider.notifier).getZipFilePath();
|
||||||
|
|
||||||
|
// submit logs
|
||||||
|
final result = await Share.shareXFiles([XFile(zipLogFilePath)]);
|
||||||
|
|
||||||
|
switch (result.status) {
|
||||||
|
case ShareResultStatus.success:
|
||||||
|
appLogger.info('Share success');
|
||||||
|
break;
|
||||||
|
case ShareResultStatus.dismissed:
|
||||||
|
appLogger.info('Share dismissed');
|
||||||
|
break;
|
||||||
|
case ShareResultStatus.unavailable:
|
||||||
|
appLogger.severe('Share unavailable');
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
),
|
||||||
|
IconButton(
|
||||||
|
tooltip: 'Download logs',
|
||||||
|
icon: const Icon(Icons.download),
|
||||||
|
onPressed: () async {
|
||||||
|
appLogger.info('Preparing logs for download');
|
||||||
|
final zipLogFilePath =
|
||||||
|
await ref.read(logsProvider.notifier).getZipFilePath();
|
||||||
|
|
||||||
|
// save to folder
|
||||||
|
String? outputFile = await FilePicker.platform.saveFile(
|
||||||
|
dialogTitle: 'Please select an output file:',
|
||||||
|
fileName: 'vaani_logs.zip',
|
||||||
|
);
|
||||||
|
if (outputFile != null) {
|
||||||
|
try {
|
||||||
|
final file = File(outputFile);
|
||||||
|
final zipFile = File(zipLogFilePath);
|
||||||
|
await zipFile.copy(file.path);
|
||||||
|
} catch (e) {
|
||||||
|
appLogger.severe('Error saving file: $e');
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
appLogger.info('Download cancelled');
|
||||||
|
}
|
||||||
|
},
|
||||||
|
),
|
||||||
|
IconButton(
|
||||||
|
tooltip: 'Refresh logs',
|
||||||
|
icon: const Icon(Icons.refresh),
|
||||||
|
onPressed: () {
|
||||||
|
ref.invalidate(logsProvider);
|
||||||
|
},
|
||||||
|
),
|
||||||
|
IconButton(
|
||||||
|
tooltip: 'Scroll to top',
|
||||||
|
icon: const Icon(Icons.arrow_upward),
|
||||||
|
onPressed: () {
|
||||||
|
scrollController.animateTo(
|
||||||
|
0,
|
||||||
|
duration: const Duration(milliseconds: 500),
|
||||||
|
curve: Curves.easeInOut,
|
||||||
|
);
|
||||||
|
},
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
// a column with listview.builder and a scrollable list of logs
|
||||||
|
body: Column(
|
||||||
|
children: [
|
||||||
|
// a filter for log levels, loggers, and search
|
||||||
|
// TODO: implement filters and search
|
||||||
|
|
||||||
|
Expanded(
|
||||||
|
child: logs.when(
|
||||||
|
data: (logRecords) {
|
||||||
|
return Scrollbar(
|
||||||
|
controller: scrollController,
|
||||||
|
child: ListView.builder(
|
||||||
|
controller: scrollController,
|
||||||
|
itemCount: logRecords.length,
|
||||||
|
itemBuilder: (context, index) {
|
||||||
|
final logRecord = logRecords[index];
|
||||||
|
return LogRecordTile(logRecord: logRecord, theme: theme);
|
||||||
|
},
|
||||||
|
),
|
||||||
|
);
|
||||||
|
},
|
||||||
|
loading: () => const Center(child: CircularProgressIndicator()),
|
||||||
|
error: (error, stackTrace) => Center(
|
||||||
|
child: Column(
|
||||||
|
mainAxisAlignment: MainAxisAlignment.center,
|
||||||
|
children: [
|
||||||
|
const Text('Error loading logs'),
|
||||||
|
ElevatedButton(
|
||||||
|
onPressed: () {
|
||||||
|
ref.invalidate(logsProvider);
|
||||||
|
},
|
||||||
|
child: const Text('Retry'),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class LogRecordTile extends StatelessWidget {
|
||||||
|
final LogRecord logRecord;
|
||||||
|
final ThemeData theme;
|
||||||
|
const LogRecordTile({
|
||||||
|
required this.logRecord,
|
||||||
|
required this.theme,
|
||||||
|
super.key,
|
||||||
|
});
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
return ListTile(
|
||||||
|
leading: CircleAvatar(
|
||||||
|
backgroundColor: getLogLevelColor(logRecord.level, theme),
|
||||||
|
child: Icon(
|
||||||
|
getLogLevelIcon(logRecord.level),
|
||||||
|
color: getLogLevelTextColor(logRecord.level, theme),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
title: Text(logRecord.loggerName),
|
||||||
|
subtitle: Text(logRecord.message),
|
||||||
|
onTap: () {
|
||||||
|
showDialog(
|
||||||
|
context: context,
|
||||||
|
builder: (context) {
|
||||||
|
return AlertDialog(
|
||||||
|
icon: Icon(getLogLevelIcon(logRecord.level)),
|
||||||
|
title: Text(logRecord.loggerName),
|
||||||
|
content: Text.rich(
|
||||||
|
TextSpan(
|
||||||
|
children: [
|
||||||
|
TextSpan(
|
||||||
|
text: logRecord.time.toIso8601String(),
|
||||||
|
style: const TextStyle(fontStyle: FontStyle.italic),
|
||||||
|
),
|
||||||
|
const TextSpan(text: '\n\n'),
|
||||||
|
TextSpan(
|
||||||
|
text: logRecord.message,
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
actions: [
|
||||||
|
TextButton(
|
||||||
|
onPressed: () {
|
||||||
|
Navigator.of(context).pop();
|
||||||
|
},
|
||||||
|
child: const Text('Close'),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
);
|
||||||
|
},
|
||||||
|
);
|
||||||
|
},
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
IconData getLogLevelIcon(Level level) {
|
||||||
|
switch (level) {
|
||||||
|
case Level.INFO:
|
||||||
|
return (Icons.info);
|
||||||
|
case Level.WARNING:
|
||||||
|
return (Icons.warning);
|
||||||
|
case Level.SEVERE:
|
||||||
|
case Level.SHOUT:
|
||||||
|
return (Icons.error);
|
||||||
|
default:
|
||||||
|
return (Icons.bug_report);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Color? getLogLevelColor(Level level, ThemeData theme) {
|
||||||
|
switch (level) {
|
||||||
|
case Level.INFO:
|
||||||
|
return theme.colorScheme.surfaceContainerLow;
|
||||||
|
case Level.WARNING:
|
||||||
|
return theme.colorScheme.surfaceBright;
|
||||||
|
case Level.SEVERE:
|
||||||
|
case Level.SHOUT:
|
||||||
|
return theme.colorScheme.errorContainer;
|
||||||
|
default:
|
||||||
|
return theme.colorScheme.primaryContainer;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Color? getLogLevelTextColor(Level level, ThemeData theme) {
|
||||||
|
switch (level) {
|
||||||
|
case Level.INFO:
|
||||||
|
return theme.colorScheme.onSurface;
|
||||||
|
case Level.WARNING:
|
||||||
|
return theme.colorScheme.onSurface;
|
||||||
|
case Level.SEVERE:
|
||||||
|
case Level.SHOUT:
|
||||||
|
return theme.colorScheme.onErrorContainer;
|
||||||
|
default:
|
||||||
|
return theme.colorScheme.onPrimaryContainer;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -41,14 +41,21 @@ class _YouPage extends HookConsumerWidget {
|
||||||
// title: const Text('You'),
|
// title: const Text('You'),
|
||||||
backgroundColor: Colors.transparent,
|
backgroundColor: Colors.transparent,
|
||||||
actions: [
|
actions: [
|
||||||
|
IconButton(
|
||||||
|
tooltip: 'Logs',
|
||||||
|
icon: const Icon(Icons.bug_report),
|
||||||
|
onPressed: () {
|
||||||
|
context.pushNamed(Routes.logs.name);
|
||||||
|
},
|
||||||
|
),
|
||||||
// IconButton(
|
// IconButton(
|
||||||
// icon: const Icon(Icons.edit),
|
// icon: const Icon(Icons.edit),
|
||||||
// onPressed: () {
|
// onPressed: () {
|
||||||
// // Handle edit profile
|
// // Handle edit profile
|
||||||
// },
|
// },
|
||||||
// ),
|
// ),
|
||||||
// settings button
|
|
||||||
IconButton(
|
IconButton(
|
||||||
|
tooltip: 'Settings',
|
||||||
icon: const Icon(Icons.settings),
|
icon: const Icon(Icons.settings),
|
||||||
onPressed: () {
|
onPressed: () {
|
||||||
context.pushNamed(Routes.settings.name);
|
context.pushNamed(Routes.settings.name);
|
||||||
|
|
|
||||||
|
|
@ -4,6 +4,7 @@ import 'package:logging/logging.dart';
|
||||||
import 'package:vaani/api/server_provider.dart';
|
import 'package:vaani/api/server_provider.dart';
|
||||||
import 'package:vaani/db/storage.dart';
|
import 'package:vaani/db/storage.dart';
|
||||||
import 'package:vaani/features/downloads/providers/download_manager.dart';
|
import 'package:vaani/features/downloads/providers/download_manager.dart';
|
||||||
|
import 'package:vaani/features/logging/core/logger.dart';
|
||||||
import 'package:vaani/features/playback_reporting/providers/playback_reporter_provider.dart';
|
import 'package:vaani/features/playback_reporting/providers/playback_reporter_provider.dart';
|
||||||
import 'package:vaani/features/player/core/init.dart';
|
import 'package:vaani/features/player/core/init.dart';
|
||||||
import 'package:vaani/features/player/providers/audiobook_player.dart';
|
import 'package:vaani/features/player/providers/audiobook_player.dart';
|
||||||
|
|
@ -12,7 +13,6 @@ import 'package:vaani/features/sleep_timer/providers/sleep_timer_provider.dart';
|
||||||
import 'package:vaani/router/router.dart';
|
import 'package:vaani/router/router.dart';
|
||||||
import 'package:vaani/settings/api_settings_provider.dart';
|
import 'package:vaani/settings/api_settings_provider.dart';
|
||||||
import 'package:vaani/settings/app_settings_provider.dart';
|
import 'package:vaani/settings/app_settings_provider.dart';
|
||||||
import 'package:vaani/shared/extensions/duration_format.dart';
|
|
||||||
import 'package:vaani/theme/theme.dart';
|
import 'package:vaani/theme/theme.dart';
|
||||||
|
|
||||||
final appLogger = Logger('vaani');
|
final appLogger = Logger('vaani');
|
||||||
|
|
@ -20,13 +20,7 @@ final appLogger = Logger('vaani');
|
||||||
void main() async {
|
void main() async {
|
||||||
WidgetsFlutterBinding.ensureInitialized();
|
WidgetsFlutterBinding.ensureInitialized();
|
||||||
// Configure the root Logger
|
// Configure the root Logger
|
||||||
Logger.root.level = Level.FINE; // Capture all logs
|
await initLogging();
|
||||||
Logger.root.onRecord.listen((record) {
|
|
||||||
// Print log records to the console
|
|
||||||
debugPrint(
|
|
||||||
'${record.loggerName}: ${record.level.name}: ${record.time.time}: ${record.message}',
|
|
||||||
);
|
|
||||||
});
|
|
||||||
|
|
||||||
// initialize the storage
|
// initialize the storage
|
||||||
await initStorage();
|
await initStorage();
|
||||||
|
|
@ -34,7 +28,6 @@ void main() async {
|
||||||
// initialize audio player
|
// initialize audio player
|
||||||
await configurePlayer();
|
await configurePlayer();
|
||||||
|
|
||||||
|
|
||||||
// run the app
|
// run the app
|
||||||
runApp(
|
runApp(
|
||||||
const ProviderScope(
|
const ProviderScope(
|
||||||
|
|
|
||||||
|
|
@ -90,6 +90,12 @@ class Routes {
|
||||||
name: 'openIDCallback',
|
name: 'openIDCallback',
|
||||||
parentRoute: onboarding,
|
parentRoute: onboarding,
|
||||||
);
|
);
|
||||||
|
|
||||||
|
// logs page
|
||||||
|
static const logs = _SimpleRoute(
|
||||||
|
pathName: 'logs',
|
||||||
|
name: 'logs',
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
// a class to store path
|
// a class to store path
|
||||||
|
|
|
||||||
|
|
@ -5,6 +5,7 @@ import 'package:vaani/features/explore/view/explore_page.dart';
|
||||||
import 'package:vaani/features/explore/view/search_result_page.dart';
|
import 'package:vaani/features/explore/view/search_result_page.dart';
|
||||||
import 'package:vaani/features/item_viewer/view/library_item_page.dart';
|
import 'package:vaani/features/item_viewer/view/library_item_page.dart';
|
||||||
import 'package:vaani/features/library_browser/view/library_browser_page.dart';
|
import 'package:vaani/features/library_browser/view/library_browser_page.dart';
|
||||||
|
import 'package:vaani/features/logging/view/logs_page.dart';
|
||||||
import 'package:vaani/features/onboarding/view/callback_page.dart';
|
import 'package:vaani/features/onboarding/view/callback_page.dart';
|
||||||
import 'package:vaani/features/onboarding/view/onboarding_single_page.dart';
|
import 'package:vaani/features/onboarding/view/onboarding_single_page.dart';
|
||||||
import 'package:vaani/features/you/view/server_manager.dart';
|
import 'package:vaani/features/you/view/server_manager.dart';
|
||||||
|
|
@ -215,6 +216,14 @@ class MyAppRouter {
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
|
|
||||||
|
// loggers page
|
||||||
|
GoRoute(
|
||||||
|
path: Routes.logs.localPath,
|
||||||
|
name: Routes.logs.name,
|
||||||
|
// builder: (context, state) => const LogsPage(),
|
||||||
|
pageBuilder: defaultPageBuilder(const LogsPage()),
|
||||||
|
),
|
||||||
],
|
],
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|
|
||||||
44
pubspec.lock
44
pubspec.lock
|
|
@ -47,7 +47,7 @@ packages:
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "2.0.10"
|
version: "2.0.10"
|
||||||
archive:
|
archive:
|
||||||
dependency: transitive
|
dependency: "direct main"
|
||||||
description:
|
description:
|
||||||
name: archive
|
name: archive
|
||||||
sha256: cb6a278ef2dbb298455e1a713bda08524a175630ec643a242c399c932a0a1f7d
|
sha256: cb6a278ef2dbb298455e1a713bda08524a175630ec643a242c399c932a0a1f7d
|
||||||
|
|
@ -366,6 +366,22 @@ packages:
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "7.0.1"
|
version: "7.0.1"
|
||||||
|
dio:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: dio
|
||||||
|
sha256: "5598aa796bbf4699afd5c67c0f5f6e2ed542afc956884b9cd58c306966efc260"
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "5.7.0"
|
||||||
|
dio_web_adapter:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: dio_web_adapter
|
||||||
|
sha256: "33259a9276d6cea88774a0000cfae0d861003497755969c92faa223108620dc8"
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "2.0.0"
|
||||||
duration_picker:
|
duration_picker:
|
||||||
dependency: "direct main"
|
dependency: "direct main"
|
||||||
description:
|
description:
|
||||||
|
|
@ -407,7 +423,7 @@ packages:
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "7.0.0"
|
version: "7.0.0"
|
||||||
file_picker:
|
file_picker:
|
||||||
dependency: transitive
|
dependency: "direct main"
|
||||||
description:
|
description:
|
||||||
name: file_picker
|
name: file_picker
|
||||||
sha256: "167bb619cdddaa10ef2907609feb8a79c16dfa479d3afaf960f8e223f754bf12"
|
sha256: "167bb619cdddaa10ef2907609feb8a79c16dfa479d3afaf960f8e223f754bf12"
|
||||||
|
|
@ -782,6 +798,14 @@ packages:
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "1.2.0"
|
version: "1.2.0"
|
||||||
|
logging_appenders:
|
||||||
|
dependency: "direct main"
|
||||||
|
description:
|
||||||
|
name: logging_appenders
|
||||||
|
sha256: e329e7472f99416d0edaaf6451fe6c02dec91d34535bd252e284a0b94ab23d79
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "1.3.1"
|
||||||
lottie:
|
lottie:
|
||||||
dependency: "direct main"
|
dependency: "direct main"
|
||||||
description:
|
description:
|
||||||
|
|
@ -1095,6 +1119,22 @@ packages:
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "2.0.0"
|
version: "2.0.0"
|
||||||
|
share_plus:
|
||||||
|
dependency: "direct main"
|
||||||
|
description:
|
||||||
|
name: share_plus
|
||||||
|
sha256: "468c43f285207c84bcabf5737f33b914ceb8eb38398b91e5e3ad1698d1b72a52"
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "10.0.2"
|
||||||
|
share_plus_platform_interface:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: share_plus_platform_interface
|
||||||
|
sha256: "6ababf341050edff57da8b6990f11f4e99eaba837865e2e6defe16d039619db5"
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "5.0.0"
|
||||||
shelf:
|
shelf:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
|
|
|
||||||
|
|
@ -32,6 +32,7 @@ isar_version: &isar_version ^4.0.0-dev.13 # define the version to be used
|
||||||
dependencies:
|
dependencies:
|
||||||
animated_list_plus: ^0.5.2
|
animated_list_plus: ^0.5.2
|
||||||
animated_theme_switcher: ^2.0.10
|
animated_theme_switcher: ^2.0.10
|
||||||
|
archive: ^3.6.1
|
||||||
audio_service: ^0.18.15
|
audio_service: ^0.18.15
|
||||||
audio_session: ^0.1.19
|
audio_session: ^0.1.19
|
||||||
audio_video_progress_bar: ^2.0.2
|
audio_video_progress_bar: ^2.0.2
|
||||||
|
|
@ -44,6 +45,7 @@ dependencies:
|
||||||
device_info_plus: ^10.1.0
|
device_info_plus: ^10.1.0
|
||||||
duration_picker: ^1.2.0
|
duration_picker: ^1.2.0
|
||||||
easy_stepper: ^0.8.4
|
easy_stepper: ^0.8.4
|
||||||
|
file_picker: ^8.1.2
|
||||||
flutter:
|
flutter:
|
||||||
sdk: flutter
|
sdk: flutter
|
||||||
flutter_animate: ^4.5.0
|
flutter_animate: ^4.5.0
|
||||||
|
|
@ -69,6 +71,7 @@ dependencies:
|
||||||
just_audio_media_kit: ^2.0.4
|
just_audio_media_kit: ^2.0.4
|
||||||
list_wheel_scroll_view_nls: ^0.0.3
|
list_wheel_scroll_view_nls: ^0.0.3
|
||||||
logging: ^1.2.0
|
logging: ^1.2.0
|
||||||
|
logging_appenders: ^1.3.1
|
||||||
lottie: ^3.1.0
|
lottie: ^3.1.0
|
||||||
material_symbols_icons: ^4.2785.1
|
material_symbols_icons: ^4.2785.1
|
||||||
media_kit_libs_linux: any
|
media_kit_libs_linux: any
|
||||||
|
|
@ -84,6 +87,7 @@ dependencies:
|
||||||
riverpod_annotation: ^2.3.5
|
riverpod_annotation: ^2.3.5
|
||||||
scroll_loop_auto_scroll: ^0.0.5
|
scroll_loop_auto_scroll: ^0.0.5
|
||||||
sensors_plus: ^6.0.1
|
sensors_plus: ^6.0.1
|
||||||
|
share_plus: ^10.0.2
|
||||||
shelfsdk:
|
shelfsdk:
|
||||||
path: ./shelfsdk
|
path: ./shelfsdk
|
||||||
shimmer: ^3.0.0
|
shimmer: ^3.0.0
|
||||||
|
|
|
||||||
|
|
@ -8,6 +8,7 @@
|
||||||
|
|
||||||
#include <isar_flutter_libs/isar_flutter_libs_plugin.h>
|
#include <isar_flutter_libs/isar_flutter_libs_plugin.h>
|
||||||
#include <media_kit_libs_windows_audio/media_kit_libs_windows_audio_plugin_c_api.h>
|
#include <media_kit_libs_windows_audio/media_kit_libs_windows_audio_plugin_c_api.h>
|
||||||
|
#include <share_plus/share_plus_windows_plugin_c_api.h>
|
||||||
#include <url_launcher_windows/url_launcher_windows.h>
|
#include <url_launcher_windows/url_launcher_windows.h>
|
||||||
|
|
||||||
void RegisterPlugins(flutter::PluginRegistry* registry) {
|
void RegisterPlugins(flutter::PluginRegistry* registry) {
|
||||||
|
|
@ -15,6 +16,8 @@ void RegisterPlugins(flutter::PluginRegistry* registry) {
|
||||||
registry->GetRegistrarForPlugin("IsarFlutterLibsPlugin"));
|
registry->GetRegistrarForPlugin("IsarFlutterLibsPlugin"));
|
||||||
MediaKitLibsWindowsAudioPluginCApiRegisterWithRegistrar(
|
MediaKitLibsWindowsAudioPluginCApiRegisterWithRegistrar(
|
||||||
registry->GetRegistrarForPlugin("MediaKitLibsWindowsAudioPluginCApi"));
|
registry->GetRegistrarForPlugin("MediaKitLibsWindowsAudioPluginCApi"));
|
||||||
|
SharePlusWindowsPluginCApiRegisterWithRegistrar(
|
||||||
|
registry->GetRegistrarForPlugin("SharePlusWindowsPluginCApi"));
|
||||||
UrlLauncherWindowsRegisterWithRegistrar(
|
UrlLauncherWindowsRegisterWithRegistrar(
|
||||||
registry->GetRegistrarForPlugin("UrlLauncherWindows"));
|
registry->GetRegistrarForPlugin("UrlLauncherWindows"));
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -5,6 +5,7 @@
|
||||||
list(APPEND FLUTTER_PLUGIN_LIST
|
list(APPEND FLUTTER_PLUGIN_LIST
|
||||||
isar_flutter_libs
|
isar_flutter_libs
|
||||||
media_kit_libs_windows_audio
|
media_kit_libs_windows_audio
|
||||||
|
share_plus
|
||||||
url_launcher_windows
|
url_launcher_windows
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue