Files
TelemetryMonitor/lib/ui/full_log_tab.dart
2026-04-21 14:40:09 -03:00

123 lines
3.4 KiB
Dart

import 'package:flutter/material.dart';
import '../proto/messages.pb.dart';
import 'app_scope.dart';
import 'log_list_view.dart';
class FullLogTab extends StatefulWidget {
const FullLogTab({super.key});
@override
State<FullLogTab> createState() => _FullLogTabState();
}
class _FullLogTabState extends State<FullLogTab> {
Set<int> _visible = {1, 2, 3, 4, 5};
@override
Widget build(BuildContext context) {
final scope = AppScope.of(context);
return Padding(
padding: const EdgeInsets.all(8),
child: Container(
decoration: BoxDecoration(
border: Border.all(
color: Theme.of(context).colorScheme.outlineVariant,
),
borderRadius: BorderRadius.circular(6),
),
child: Column(
crossAxisAlignment: CrossAxisAlignment.stretch,
children: [
_FilterRow(
visible: _visible,
onToggle: (s) => setState(() {
if (_visible.contains(s)) {
_visible.remove(s);
} else {
_visible.add(s);
}
}),
onExport: () => _exportLog(context),
),
const Divider(height: 1),
Expanded(
child: LogListView(
session: scope.session,
filter: (e) => _visible.contains(
e.hasSeverity() ? e.severity.value : 0,
),
),
),
],
),
),
);
}
Future<void> _exportLog(BuildContext context) async {
final scope = AppScope.of(context);
final messenger = ScaffoldMessenger.of(context);
try {
final result =
await scope.exporter.exportLog(buffer: scope.session.logs);
messenger.showSnackBar(
SnackBar(content: Text('Exported to ${result.path}')),
);
} catch (e) {
messenger.showSnackBar(
SnackBar(content: Text('Export failed: $e')),
);
}
}
}
class _FilterRow extends StatelessWidget {
const _FilterRow({
required this.visible,
required this.onToggle,
required this.onExport,
});
final Set<int> visible;
final void Function(int) onToggle;
final VoidCallback onExport;
@override
Widget build(BuildContext context) {
Widget chip(int sev, String label, Color color) {
final on = visible.contains(sev);
return Padding(
padding: const EdgeInsets.symmetric(horizontal: 3),
child: FilterChip(
label: Text(label, style: const TextStyle(fontSize: 11)),
selected: on,
onSelected: (_) => onToggle(sev),
selectedColor: color.withValues(alpha: 0.2),
checkmarkColor: color,
),
);
}
return Padding(
padding: const EdgeInsets.symmetric(horizontal: 8, vertical: 6),
child: Row(
children: [
const Text('Filter:', style: TextStyle(fontSize: 11)),
const SizedBox(width: 6),
chip(1, 'DEBUG', Colors.grey),
chip(2, 'INFO', Colors.blueGrey),
chip(3, 'WARN', Colors.amber.shade800),
chip(4, 'ERROR', Colors.red.shade800),
chip(5, 'FATAL', Colors.red.shade900),
const Spacer(),
OutlinedButton.icon(
onPressed: onExport,
icon: const Icon(Icons.download, size: 16),
label: const Text('Export log'),
),
],
),
);
}
}