feat(#393): add Share action to App-log screen (shared export helper)

Extract the BLE screen's on-disk log export into lib/utils/log_export.dart and
reuse it on the App-log screen, so both log screens have one consistent Share
action: OS share sheet on mobile, open logs folder on desktop. The shared file
already holds the app log and BLE frames combined.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
feat/393-app-log-share
Strycher 2 months ago
parent d3fd110509
commit 331e454178

@ -6,6 +6,7 @@ import '../l10n/l10n.dart';
import '../services/app_debug_log_service.dart';
import '../widgets/adaptive_app_bar_title.dart';
import '../helpers/snack_bar_builder.dart';
import '../utils/log_export.dart';
class AppDebugLogScreen extends StatelessWidget {
const AppDebugLogScreen({super.key});
@ -22,6 +23,11 @@ class AppDebugLogScreen extends StatelessWidget {
title: AdaptiveAppBarTitle(context.l10n.debugLog_appTitle),
centerTitle: true,
actions: [
IconButton(
tooltip: LogExport.tooltip,
icon: Icon(LogExport.icon),
onPressed: () => LogExport.shareLogs(context),
),
IconButton(
tooltip: context.l10n.debugLog_copyLog,
icon: const Icon(Icons.copy),

@ -1,5 +1,4 @@
import 'package:flutter/material.dart';
import 'package:flutter/foundation.dart';
import 'package:provider/provider.dart';
import 'package:flutter/services.dart';
import '../l10n/l10n.dart';
@ -7,9 +6,7 @@ import '../services/ble_debug_log_service.dart';
import '../connector/meshcore_protocol.dart';
import '../widgets/adaptive_app_bar_title.dart';
import '../helpers/snack_bar_builder.dart';
import 'package:share_plus/share_plus.dart';
import 'package:url_launcher/url_launcher.dart';
import '../services/file_log_service.dart';
import '../utils/log_export.dart';
enum _BleLogView { frames, rawLogRx }
@ -33,26 +30,14 @@ class _BleDebugLogScreenState extends State<BleDebugLogScreen> {
final hasEntries = showingFrames
? entries.isNotEmpty
: rawEntries.isNotEmpty;
final isMobile =
defaultTargetPlatform == TargetPlatform.android ||
defaultTargetPlatform == TargetPlatform.iOS;
return Scaffold(
appBar: AppBar(
title: AdaptiveAppBarTitle(context.l10n.debugLog_bleTitle),
actions: [
IconButton(
tooltip: isMobile ? 'Share logs' : 'Open logs folder',
// Platform-standard share glyph: Android uses Icons.share
// (connected nodes), iOS uses Icons.ios_share (square+arrow),
// desktop reveals the saved file (folder). #396
icon: Icon(
defaultTargetPlatform == TargetPlatform.android
? Icons.share
: isMobile
? Icons.ios_share
: Icons.folder_open,
),
onPressed: () => _exportLogs(context),
tooltip: LogExport.tooltip,
icon: Icon(LogExport.icon),
onPressed: () => LogExport.shareLogs(context),
),
IconButton(
tooltip: context.l10n.debugLog_copyLog,
@ -181,36 +166,6 @@ class _BleDebugLogScreenState extends State<BleDebugLogScreen> {
);
}
/// Export the on-disk log (#97): the system share sheet on mobile, or open the
/// logs folder in the file manager on desktop. The file holds both the app log
/// and BLE frames, flushed first so it's current.
Future<void> _exportLogs(BuildContext context) async {
final messenger = ScaffoldMessenger.of(context);
final file = await FileLogService.instance.flushAndGetActiveFile();
if (file == null) {
messenger.showSnackBar(
const SnackBar(
content: Text('File logging is unavailable on this platform'),
),
);
return;
}
final isMobile =
defaultTargetPlatform == TargetPlatform.android ||
defaultTargetPlatform == TargetPlatform.iOS;
if (isMobile) {
await SharePlus.instance.share(
ShareParams(
subject: 'Offband Meshcore logs',
files: [XFile(file.path)],
),
);
} else {
final dir = FileLogService.instance.logDir;
if (dir != null) await launchUrl(Uri.file(dir.path));
}
}
void _showRawDialog(BuildContext context, _RawPacketInfo info) {
showDialog(
context: context,

@ -0,0 +1,56 @@
import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart';
import 'package:share_plus/share_plus.dart';
import 'package:url_launcher/url_launcher.dart';
import '../services/file_log_service.dart';
/// Shared log export for the App-log and BLE-log screens (#393, #97).
///
/// The on-disk log file ([FileLogService]) holds both the app log and BLE
/// frames as one combined stream, so either screen exports the same complete
/// file. Both screens use these helpers so their Share action can't drift.
class LogExport {
const LogExport._();
static bool get _isMobile =>
defaultTargetPlatform == TargetPlatform.android ||
defaultTargetPlatform == TargetPlatform.iOS;
/// Platform-standard glyph: Android share (connected nodes), iOS square+arrow,
/// desktop reveals the saved file (folder). #396
static IconData get icon => defaultTargetPlatform == TargetPlatform.android
? Icons.share
: _isMobile
? Icons.ios_share
: Icons.folder_open;
static String get tooltip => _isMobile ? 'Share logs' : 'Open logs folder';
/// Flush the on-disk log and hand it to the OS share sheet (mobile), or open
/// the logs folder in the file manager (desktop). Shows a snackbar if file
/// logging is unavailable (e.g. web).
static Future<void> shareLogs(BuildContext context) async {
final messenger = ScaffoldMessenger.of(context);
final file = await FileLogService.instance.flushAndGetActiveFile();
if (file == null) {
messenger.showSnackBar(
const SnackBar(
content: Text('File logging is unavailable on this platform'),
),
);
return;
}
if (_isMobile) {
await SharePlus.instance.share(
ShareParams(
subject: 'Offband Meshcore logs',
files: [XFile(file.path)],
),
);
} else {
final dir = FileLogService.instance.logDir;
if (dir != null) await launchUrl(Uri.file(dir.path));
}
}
}
Loading…
Cancel
Save

Powered by TurnKey Linux.