Compare commits

..

1 Commits

Author SHA1 Message Date
chen08209
79ce7cadf6 Add sqlite store
Optimize android quick action

Optimize backup and restore

Optimize more details
2026-01-24 12:14:54 +08:00
6 changed files with 164 additions and 35 deletions

View File

@@ -19,10 +19,10 @@ class Migration {
required Future<Config> Function(MigrationData data) sync,
}) async {
_oldVersion = await preferences.getVersion();
MigrationData data = MigrationData(configMap: configMap);
if (_oldVersion == currentVersion) {
return Config.realFromJson(configMap);
}
MigrationData data = MigrationData(configMap: configMap);
if (_oldVersion == 0 && configMap != null) {
final clashConfigMap = await preferences.getClashConfigMap();
if (clashConfigMap != null) {

View File

@@ -41,26 +41,28 @@ class AppController {
extension InitControllerExt on AppController {
Future<void> _init() async {
try {
updateTray();
autoUpdateProfiles();
autoCheckUpdate();
autoLaunch?.updateStatus(_ref.read(appSettingProvider).autoLaunch);
if (!_ref.read(appSettingProvider).silentLaunch) {
window?.show();
} else {
window?.hide();
}
await _handleFailedPreference();
await _handlerDisclaimer();
await _showCrashlyticsTip();
await _connectCore();
await _initCore();
await _initStatus();
_ref.read(initProvider.notifier).value = true;
} catch (e) {
commonPrint.log('init error: $e');
FlutterError.onError = (details) {
commonPrint.log(
'exception: ${details.exception} stack: ${details.stack}',
logLevel: LogLevel.warning,
);
};
updateTray();
autoUpdateProfiles();
autoCheckUpdate();
autoLaunch?.updateStatus(_ref.read(appSettingProvider).autoLaunch);
if (!_ref.read(appSettingProvider).silentLaunch) {
window?.show();
} else {
window?.hide();
}
await _handleFailedPreference();
await _handlerDisclaimer();
await _showCrashlyticsTip();
await _connectCore();
await _initCore();
await _initStatus();
_ref.read(initProvider.notifier).value = true;
}
Future<void> _handleFailedPreference() async {

View File

@@ -1,6 +1,7 @@
import 'dart:async';
import 'dart:io';
import 'package:fl_clash/pages/error.dart';
import 'package:fl_clash/state.dart';
import 'package:flutter/material.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
@@ -9,11 +10,22 @@ import 'application.dart';
import 'common/common.dart';
Future<void> main() async {
WidgetsFlutterBinding.ensureInitialized();
final version = await system.version;
final container = await globalState.init(version);
HttpOverrides.global = FlClashHttpOverrides();
runApp(
UncontrolledProviderScope(container: container, child: const Application()),
);
try {
WidgetsFlutterBinding.ensureInitialized();
final version = await system.version;
final container = await globalState.init(version);
HttpOverrides.global = FlClashHttpOverrides();
runApp(
UncontrolledProviderScope(
container: container,
child: const Application(),
),
);
} catch (e, s) {
return runApp(
MaterialApp(
home: InitErrorScreen(error: e, stack: s),
),
);
}
}

121
lib/pages/error.dart Normal file
View File

@@ -0,0 +1,121 @@
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
class InitErrorScreen extends StatelessWidget {
final Object error;
final StackTrace stack;
const InitErrorScreen({super.key, required this.error, required this.stack});
@override
Widget build(BuildContext context) {
final colorScheme = Theme.of(context).colorScheme;
return Scaffold(
appBar: AppBar(
title: const Text('System Init Failed'),
backgroundColor: colorScheme.error,
foregroundColor: colorScheme.onError,
elevation: 0,
),
body: SafeArea(
child: SingleChildScrollView(
padding: const EdgeInsets.all(16.0),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
// 1. Header Section
Row(
children: [
Icon(
Icons.report_problem,
color: colorScheme.error,
size: 32,
),
const SizedBox(width: 12),
const Expanded(
child: Text(
'The application encountered a critical error during startup and cannot continue.',
style: TextStyle(
fontWeight: FontWeight.bold,
fontSize: 16,
),
),
),
],
),
const SizedBox(height: 24),
_buildSectionLabel('Error Details:'),
Container(
width: double.infinity,
padding: const EdgeInsets.all(12),
decoration: BoxDecoration(
color: colorScheme.errorContainer.withOpacity(0.5),
borderRadius: BorderRadius.circular(8),
border: Border.all(color: colorScheme.error.withOpacity(0.5)),
),
child: SelectableText(
error.toString(),
style: TextStyle(
color: colorScheme.onErrorContainer,
fontWeight: FontWeight.w600,
),
),
),
const SizedBox(height: 24),
_buildSectionLabel('Stack Trace:'),
Container(
width: double.infinity,
padding: const EdgeInsets.all(12),
decoration: BoxDecoration(
color: Theme.of(context).brightness == Brightness.dark
? Colors.grey[900]
: Colors.grey[200],
borderRadius: BorderRadius.circular(8),
border: Border.all(color: Colors.grey.withOpacity(0.5)),
),
child: SelectableText(
stack.toString(),
style: const TextStyle(
fontFamily: 'monospace', // Makes code easier to read
fontSize: 12,
),
),
),
const SizedBox(height: 80),
],
),
),
),
floatingActionButton: FloatingActionButton.extended(
onPressed: () => _copyToClipboard(context),
label: const Text('Copy Details'),
icon: const Icon(Icons.copy),
backgroundColor: colorScheme.error,
foregroundColor: colorScheme.onError,
),
);
}
Widget _buildSectionLabel(String text) {
return Padding(
padding: const EdgeInsets.only(bottom: 8.0),
child: Text(
text,
style: const TextStyle(fontWeight: FontWeight.bold, fontSize: 15),
),
);
}
void _copyToClipboard(BuildContext context) {
final text = '=== ERROR ===\n$error\n\n=== STACK TRACE ===\n$stack';
Clipboard.setData(ClipboardData(text: text));
ScaffoldMessenger.of(context).showSnackBar(
const SnackBar(
content: Text('Error details copied to clipboard'),
duration: Duration(seconds: 2),
),
);
}
}

View File

@@ -1,3 +1,4 @@
export 'editor.dart';
export 'error.dart';
export 'home.dart';
export 'scan.dart';
export 'editor.dart';

View File

@@ -22,7 +22,6 @@ import 'package:url_launcher/url_launcher.dart';
import 'common/common.dart';
import 'database/database.dart';
import 'enum/enum.dart';
import 'l10n/l10n.dart';
import 'models/models.dart';
@@ -56,12 +55,6 @@ class GlobalState {
}
Future<ProviderContainer> init(int version) async {
FlutterError.onError = (details) {
commonPrint.log(
'exception: ${details.exception} stack: ${details.stack}',
logLevel: LogLevel.warning,
);
};
coreSHA256 = const String.fromEnvironment('CORE_SHA256');
isPre = const String.fromEnvironment('APP_ENV') != 'stable';
await _initDynamicColor();