101 lines
2.9 KiB
Dart
101 lines
2.9 KiB
Dart
import 'dart:convert';
|
|
|
|
import 'package:shared_preferences/shared_preferences.dart';
|
|
|
|
const String _shareIntakeDebugLogKey = 'share_intake_debug_log_v1';
|
|
const int _maxShareIntakeDebugEvents = 40;
|
|
const int _maxShareIntakeDebugDetailChars = 6000;
|
|
|
|
class ShareIntakeDebugEvent {
|
|
const ShareIntakeDebugEvent({
|
|
required this.at,
|
|
required this.stage,
|
|
required this.message,
|
|
this.details,
|
|
});
|
|
|
|
factory ShareIntakeDebugEvent.fromJson(Map<String, dynamic> json) {
|
|
return ShareIntakeDebugEvent(
|
|
at: DateTime.parse(
|
|
json['at'] as String? ?? DateTime.now().toUtc().toIso8601String(),
|
|
).toLocal(),
|
|
stage: json['stage'] as String? ?? 'unknown',
|
|
message: json['message'] as String? ?? '',
|
|
details: json['details'] as String?,
|
|
);
|
|
}
|
|
|
|
final DateTime at;
|
|
final String stage;
|
|
final String message;
|
|
final String? details;
|
|
|
|
Map<String, dynamic> toJson() {
|
|
return <String, dynamic>{
|
|
'at': at.toUtc().toIso8601String(),
|
|
'stage': stage,
|
|
'message': message,
|
|
if (details != null) 'details': details,
|
|
};
|
|
}
|
|
}
|
|
|
|
class ShareIntakeDebugLog {
|
|
const ShareIntakeDebugLog();
|
|
|
|
Future<List<ShareIntakeDebugEvent>> read() async {
|
|
final SharedPreferences prefs = await SharedPreferences.getInstance();
|
|
final String? raw = prefs.getString(_shareIntakeDebugLogKey);
|
|
if (raw == null || raw.isEmpty) {
|
|
return const <ShareIntakeDebugEvent>[];
|
|
}
|
|
try {
|
|
final List<dynamic> items = jsonDecode(raw) as List<dynamic>;
|
|
return items
|
|
.whereType<Map<String, dynamic>>()
|
|
.map(ShareIntakeDebugEvent.fromJson)
|
|
.toList(growable: false);
|
|
} on FormatException {
|
|
return const <ShareIntakeDebugEvent>[];
|
|
}
|
|
}
|
|
|
|
Future<void> record(String stage, String message, {String? details}) async {
|
|
final SharedPreferences prefs = await SharedPreferences.getInstance();
|
|
final List<ShareIntakeDebugEvent> current = await read();
|
|
final List<ShareIntakeDebugEvent> next = <ShareIntakeDebugEvent>[
|
|
ShareIntakeDebugEvent(
|
|
at: DateTime.now(),
|
|
stage: stage,
|
|
message: message,
|
|
details: _compactDetails(details),
|
|
),
|
|
...current,
|
|
].take(_maxShareIntakeDebugEvents).toList(growable: false);
|
|
await prefs.setString(
|
|
_shareIntakeDebugLogKey,
|
|
jsonEncode(
|
|
next
|
|
.map((ShareIntakeDebugEvent event) => event.toJson())
|
|
.toList(growable: false),
|
|
),
|
|
);
|
|
}
|
|
|
|
Future<void> clear() async {
|
|
final SharedPreferences prefs = await SharedPreferences.getInstance();
|
|
await prefs.remove(_shareIntakeDebugLogKey);
|
|
}
|
|
}
|
|
|
|
String? _compactDetails(String? value) {
|
|
final String? trimmed = value?.trim();
|
|
if (trimmed == null || trimmed.isEmpty) {
|
|
return null;
|
|
}
|
|
if (trimmed.length <= _maxShareIntakeDebugDetailChars) {
|
|
return trimmed;
|
|
}
|
|
return '${trimmed.substring(0, _maxShareIntakeDebugDetailChars)}\n[truncated]';
|
|
}
|