Compare commits
1 Commits
v0.8.92-pr
...
v0.8.92-pr
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
d670f13cbc |
@@ -19,19 +19,10 @@ class Migration {
|
||||
required Future<Config> Function(MigrationData data) sync,
|
||||
}) async {
|
||||
_oldVersion = await preferences.getVersion();
|
||||
if (_oldVersion == currentVersion) {
|
||||
try {
|
||||
return Config.realFromJson(configMap);
|
||||
} catch (_) {
|
||||
final isV0 = configMap?['proxiesStyle'] != null;
|
||||
if (isV0) {
|
||||
_oldVersion = 0;
|
||||
} else {
|
||||
throw 'Local data is damaged. A reset is required to fix this issue.';
|
||||
}
|
||||
}
|
||||
}
|
||||
MigrationData data = MigrationData(configMap: configMap);
|
||||
if (_oldVersion == currentVersion) {
|
||||
return Config.realFromJson(configMap);
|
||||
}
|
||||
if (_oldVersion == 0 && configMap != null) {
|
||||
final clashConfigMap = await preferences.getClashConfigMap();
|
||||
if (clashConfigMap != null) {
|
||||
|
||||
@@ -41,28 +41,26 @@ class AppController {
|
||||
|
||||
extension InitControllerExt on AppController {
|
||||
Future<void> _init() async {
|
||||
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();
|
||||
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');
|
||||
}
|
||||
await _handleFailedPreference();
|
||||
await _handlerDisclaimer();
|
||||
await _showCrashlyticsTip();
|
||||
await _connectCore();
|
||||
await _initCore();
|
||||
await _initStatus();
|
||||
_ref.read(initProvider.notifier).value = true;
|
||||
}
|
||||
|
||||
Future<void> _handleFailedPreference() async {
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
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';
|
||||
@@ -10,22 +9,11 @@ import 'application.dart';
|
||||
import 'common/common.dart';
|
||||
|
||||
Future<void> main() async {
|
||||
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),
|
||||
),
|
||||
);
|
||||
}
|
||||
WidgetsFlutterBinding.ensureInitialized();
|
||||
final version = await system.version;
|
||||
final container = await globalState.init(version);
|
||||
HttpOverrides.global = FlClashHttpOverrides();
|
||||
runApp(
|
||||
UncontrolledProviderScope(container: container, child: const Application()),
|
||||
);
|
||||
}
|
||||
|
||||
@@ -1,120 +0,0 @@
|
||||
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('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: [
|
||||
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),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -1,4 +1,3 @@
|
||||
export 'editor.dart';
|
||||
export 'error.dart';
|
||||
export 'home.dart';
|
||||
export 'scan.dart';
|
||||
export 'editor.dart';
|
||||
@@ -22,6 +22,7 @@ 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';
|
||||
|
||||
@@ -55,6 +56,12 @@ 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();
|
||||
@@ -88,7 +95,9 @@ class GlobalState {
|
||||
configMap,
|
||||
sync: (data) async {
|
||||
final newConfigMap = data.configMap;
|
||||
final config = Config.realFromJson(newConfigMap);
|
||||
final config = newConfigMap != null
|
||||
? Config.fromJson(newConfigMap)
|
||||
: Config(themeProps: defaultThemeProps);
|
||||
await Future.wait([
|
||||
database.restore(data.profiles, data.scripts, data.rules, data.links),
|
||||
preferences.saveConfig(config),
|
||||
|
||||
@@ -30,7 +30,7 @@ class _EditProfileViewState extends State<EditProfileView> {
|
||||
late final TextEditingController _labelController;
|
||||
late final TextEditingController _urlController;
|
||||
late final TextEditingController _autoUpdateDurationController;
|
||||
late bool _autoUpdate;
|
||||
late final bool _autoUpdate;
|
||||
String? _rawText;
|
||||
final GlobalKey<FormState> _formKey = GlobalKey<FormState>();
|
||||
final _fileInfoNotifier = ValueNotifier<FileInfo?>(null);
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
name: fl_clash
|
||||
description: A multi-platform proxy client based on ClashMeta, simple and easy to use, open-source and ad-free.
|
||||
publish_to: 'none'
|
||||
version: 0.8.92+2026012403
|
||||
version: 0.8.92+2026012301
|
||||
environment:
|
||||
sdk: '>=3.8.0 <4.0.0'
|
||||
|
||||
|
||||
Reference in New Issue
Block a user