Update file_picker

Add resources page

Optimize more detail
This commit is contained in:
chen08209
2024-06-03 18:02:05 +08:00
parent 01f1b2d72f
commit bb7e44da30
50 changed files with 32716 additions and 443 deletions

View File

@@ -32,7 +32,6 @@ class AppState with ChangeNotifier {
AppState({
required Mode mode,
double? viewWidth,
required bool isCompatible,
required SelectedMap selectedMap,
}) : _navigationItems = [],
@@ -40,7 +39,7 @@ class AppState with ChangeNotifier {
_currentLabel = "dashboard",
_traffics = [],
_logs = [],
_viewWidth = viewWidth ?? 0,
_viewWidth = 0,
_selectedMap = selectedMap,
_sortNum = 0,
_mode = mode,
@@ -167,6 +166,9 @@ class AppState with ChangeNotifier {
addLog(Log log) {
_logs.add(log);
if(_logs.length > 60){
_logs = _logs.sublist(_logs.length - 60);
}
notifyListeners();
}
@@ -179,7 +181,6 @@ class AppState with ChangeNotifier {
}
}
List<Group> get groups => _groups;
set groups(List<Group> value) {
@@ -253,11 +254,7 @@ class AppState with ChangeNotifier {
}
}
ViewMode get viewMode {
if (_viewWidth <= maxMobileWidth) return ViewMode.mobile;
if (_viewWidth <= maxLaptopWidth) return ViewMode.laptop;
return ViewMode.desktop;
}
ViewMode get viewMode => other.getViewMode(_viewWidth);
DelayMap get delayMap {
return _delayMap;

View File

@@ -1,24 +0,0 @@
import 'package:fl_clash/enum/enum.dart';
class Result<T> {
String? message;
ResultType type;
T? data;
Result({
this.message,
required this.type,
this.data,
});
Result.success([this.data]) : type = ResultType.success,
message = null;
Result.error([this.message]) : type = ResultType.error,
data = null;
@override
String toString() {
return 'Result{message: $message, type: $type, data: $data}';
}
}

View File

@@ -50,7 +50,7 @@ class Config extends ChangeNotifier {
_autoRun = false,
_themeMode = ThemeMode.system,
_openLog = false,
_isCompatible = false,
_isCompatible = true,
_primaryColor = defaultPrimaryColor.value,
_proxiesSortType = ProxiesSortType.none,
_isMinimizeOnExit = true,
@@ -281,7 +281,7 @@ class Config extends ChangeNotifier {
}
}
@JsonKey(defaultValue: false)
@JsonKey(defaultValue: true)
bool get isCompatible {
return _isCompatible;
}

View File

@@ -75,3 +75,16 @@ class Process with _$Process {
factory Process.fromJson(Map<String, Object?> json) =>
_$ProcessFromJson(json);
}
@freezed
class ExternalProvider with _$ExternalProvider {
const factory ExternalProvider({
required String name,
required String type,
@JsonKey(name: "vehicle-type") required String vehicleType,
@JsonKey(name: "update-at") required DateTime updateAt,
}) = _ExternalProvider;
factory ExternalProvider.fromJson(Map<String, Object?> json) =>
_$ExternalProviderFromJson(json);
}

View File

@@ -1029,3 +1029,214 @@ abstract class _Process implements Process {
_$$ProcessImplCopyWith<_$ProcessImpl> get copyWith =>
throw _privateConstructorUsedError;
}
ExternalProvider _$ExternalProviderFromJson(Map<String, dynamic> json) {
return _ExternalProvider.fromJson(json);
}
/// @nodoc
mixin _$ExternalProvider {
String get name => throw _privateConstructorUsedError;
String get type => throw _privateConstructorUsedError;
@JsonKey(name: "vehicle-type")
String get vehicleType => throw _privateConstructorUsedError;
@JsonKey(name: "update-at")
DateTime get updateAt => throw _privateConstructorUsedError;
Map<String, dynamic> toJson() => throw _privateConstructorUsedError;
@JsonKey(ignore: true)
$ExternalProviderCopyWith<ExternalProvider> get copyWith =>
throw _privateConstructorUsedError;
}
/// @nodoc
abstract class $ExternalProviderCopyWith<$Res> {
factory $ExternalProviderCopyWith(
ExternalProvider value, $Res Function(ExternalProvider) then) =
_$ExternalProviderCopyWithImpl<$Res, ExternalProvider>;
@useResult
$Res call(
{String name,
String type,
@JsonKey(name: "vehicle-type") String vehicleType,
@JsonKey(name: "update-at") DateTime updateAt});
}
/// @nodoc
class _$ExternalProviderCopyWithImpl<$Res, $Val extends ExternalProvider>
implements $ExternalProviderCopyWith<$Res> {
_$ExternalProviderCopyWithImpl(this._value, this._then);
// ignore: unused_field
final $Val _value;
// ignore: unused_field
final $Res Function($Val) _then;
@pragma('vm:prefer-inline')
@override
$Res call({
Object? name = null,
Object? type = null,
Object? vehicleType = null,
Object? updateAt = null,
}) {
return _then(_value.copyWith(
name: null == name
? _value.name
: name // ignore: cast_nullable_to_non_nullable
as String,
type: null == type
? _value.type
: type // ignore: cast_nullable_to_non_nullable
as String,
vehicleType: null == vehicleType
? _value.vehicleType
: vehicleType // ignore: cast_nullable_to_non_nullable
as String,
updateAt: null == updateAt
? _value.updateAt
: updateAt // ignore: cast_nullable_to_non_nullable
as DateTime,
) as $Val);
}
}
/// @nodoc
abstract class _$$ExternalProviderImplCopyWith<$Res>
implements $ExternalProviderCopyWith<$Res> {
factory _$$ExternalProviderImplCopyWith(_$ExternalProviderImpl value,
$Res Function(_$ExternalProviderImpl) then) =
__$$ExternalProviderImplCopyWithImpl<$Res>;
@override
@useResult
$Res call(
{String name,
String type,
@JsonKey(name: "vehicle-type") String vehicleType,
@JsonKey(name: "update-at") DateTime updateAt});
}
/// @nodoc
class __$$ExternalProviderImplCopyWithImpl<$Res>
extends _$ExternalProviderCopyWithImpl<$Res, _$ExternalProviderImpl>
implements _$$ExternalProviderImplCopyWith<$Res> {
__$$ExternalProviderImplCopyWithImpl(_$ExternalProviderImpl _value,
$Res Function(_$ExternalProviderImpl) _then)
: super(_value, _then);
@pragma('vm:prefer-inline')
@override
$Res call({
Object? name = null,
Object? type = null,
Object? vehicleType = null,
Object? updateAt = null,
}) {
return _then(_$ExternalProviderImpl(
name: null == name
? _value.name
: name // ignore: cast_nullable_to_non_nullable
as String,
type: null == type
? _value.type
: type // ignore: cast_nullable_to_non_nullable
as String,
vehicleType: null == vehicleType
? _value.vehicleType
: vehicleType // ignore: cast_nullable_to_non_nullable
as String,
updateAt: null == updateAt
? _value.updateAt
: updateAt // ignore: cast_nullable_to_non_nullable
as DateTime,
));
}
}
/// @nodoc
@JsonSerializable()
class _$ExternalProviderImpl implements _ExternalProvider {
const _$ExternalProviderImpl(
{required this.name,
required this.type,
@JsonKey(name: "vehicle-type") required this.vehicleType,
@JsonKey(name: "update-at") required this.updateAt});
factory _$ExternalProviderImpl.fromJson(Map<String, dynamic> json) =>
_$$ExternalProviderImplFromJson(json);
@override
final String name;
@override
final String type;
@override
@JsonKey(name: "vehicle-type")
final String vehicleType;
@override
@JsonKey(name: "update-at")
final DateTime updateAt;
@override
String toString() {
return 'ExternalProvider(name: $name, type: $type, vehicleType: $vehicleType, updateAt: $updateAt)';
}
@override
bool operator ==(Object other) {
return identical(this, other) ||
(other.runtimeType == runtimeType &&
other is _$ExternalProviderImpl &&
(identical(other.name, name) || other.name == name) &&
(identical(other.type, type) || other.type == type) &&
(identical(other.vehicleType, vehicleType) ||
other.vehicleType == vehicleType) &&
(identical(other.updateAt, updateAt) ||
other.updateAt == updateAt));
}
@JsonKey(ignore: true)
@override
int get hashCode =>
Object.hash(runtimeType, name, type, vehicleType, updateAt);
@JsonKey(ignore: true)
@override
@pragma('vm:prefer-inline')
_$$ExternalProviderImplCopyWith<_$ExternalProviderImpl> get copyWith =>
__$$ExternalProviderImplCopyWithImpl<_$ExternalProviderImpl>(
this, _$identity);
@override
Map<String, dynamic> toJson() {
return _$$ExternalProviderImplToJson(
this,
);
}
}
abstract class _ExternalProvider implements ExternalProvider {
const factory _ExternalProvider(
{required final String name,
required final String type,
@JsonKey(name: "vehicle-type") required final String vehicleType,
@JsonKey(name: "update-at") required final DateTime updateAt}) =
_$ExternalProviderImpl;
factory _ExternalProvider.fromJson(Map<String, dynamic> json) =
_$ExternalProviderImpl.fromJson;
@override
String get name;
@override
String get type;
@override
@JsonKey(name: "vehicle-type")
String get vehicleType;
@override
@JsonKey(name: "update-at")
DateTime get updateAt;
@override
@JsonKey(ignore: true)
_$$ExternalProviderImplCopyWith<_$ExternalProviderImpl> get copyWith =>
throw _privateConstructorUsedError;
}

View File

@@ -94,3 +94,21 @@ Map<String, dynamic> _$$ProcessImplToJson(_$ProcessImpl instance) =>
'source': instance.source,
'target': instance.target,
};
_$ExternalProviderImpl _$$ExternalProviderImplFromJson(
Map<String, dynamic> json) =>
_$ExternalProviderImpl(
name: json['name'] as String,
type: json['type'] as String,
vehicleType: json['vehicle-type'] as String,
updateAt: DateTime.parse(json['update-at'] as String),
);
Map<String, dynamic> _$$ExternalProviderImplToJson(
_$ExternalProviderImpl instance) =>
<String, dynamic>{
'name': instance.name,
'type': instance.type,
'vehicle-type': instance.vehicleType,
'update-at': instance.updateAt.toIso8601String(),
};

View File

@@ -20,6 +20,7 @@ mixin _$NavigationItem {
String get label => throw _privateConstructorUsedError;
String? get description => throw _privateConstructorUsedError;
Widget get fragment => throw _privateConstructorUsedError;
bool get keep => throw _privateConstructorUsedError;
String? get path => throw _privateConstructorUsedError;
List<NavigationItemMode> get modes => throw _privateConstructorUsedError;
@@ -39,6 +40,7 @@ abstract class $NavigationItemCopyWith<$Res> {
String label,
String? description,
Widget fragment,
bool keep,
String? path,
List<NavigationItemMode> modes});
}
@@ -60,6 +62,7 @@ class _$NavigationItemCopyWithImpl<$Res, $Val extends NavigationItem>
Object? label = null,
Object? description = freezed,
Object? fragment = null,
Object? keep = null,
Object? path = freezed,
Object? modes = null,
}) {
@@ -80,6 +83,10 @@ class _$NavigationItemCopyWithImpl<$Res, $Val extends NavigationItem>
? _value.fragment
: fragment // ignore: cast_nullable_to_non_nullable
as Widget,
keep: null == keep
? _value.keep
: keep // ignore: cast_nullable_to_non_nullable
as bool,
path: freezed == path
? _value.path
: path // ignore: cast_nullable_to_non_nullable
@@ -105,6 +112,7 @@ abstract class _$$NavigationItemImplCopyWith<$Res>
String label,
String? description,
Widget fragment,
bool keep,
String? path,
List<NavigationItemMode> modes});
}
@@ -124,6 +132,7 @@ class __$$NavigationItemImplCopyWithImpl<$Res>
Object? label = null,
Object? description = freezed,
Object? fragment = null,
Object? keep = null,
Object? path = freezed,
Object? modes = null,
}) {
@@ -144,6 +153,10 @@ class __$$NavigationItemImplCopyWithImpl<$Res>
? _value.fragment
: fragment // ignore: cast_nullable_to_non_nullable
as Widget,
keep: null == keep
? _value.keep
: keep // ignore: cast_nullable_to_non_nullable
as bool,
path: freezed == path
? _value.path
: path // ignore: cast_nullable_to_non_nullable
@@ -164,6 +177,7 @@ class _$NavigationItemImpl implements _NavigationItem {
required this.label,
this.description,
required this.fragment,
this.keep = true,
this.path,
final List<NavigationItemMode> modes = const [
NavigationItemMode.mobile,
@@ -180,6 +194,9 @@ class _$NavigationItemImpl implements _NavigationItem {
@override
final Widget fragment;
@override
@JsonKey()
final bool keep;
@override
final String? path;
final List<NavigationItemMode> _modes;
@override
@@ -192,7 +209,7 @@ class _$NavigationItemImpl implements _NavigationItem {
@override
String toString() {
return 'NavigationItem(icon: $icon, label: $label, description: $description, fragment: $fragment, path: $path, modes: $modes)';
return 'NavigationItem(icon: $icon, label: $label, description: $description, fragment: $fragment, keep: $keep, path: $path, modes: $modes)';
}
@override
@@ -206,13 +223,14 @@ class _$NavigationItemImpl implements _NavigationItem {
other.description == description) &&
(identical(other.fragment, fragment) ||
other.fragment == fragment) &&
(identical(other.keep, keep) || other.keep == keep) &&
(identical(other.path, path) || other.path == path) &&
const DeepCollectionEquality().equals(other._modes, _modes));
}
@override
int get hashCode => Object.hash(runtimeType, icon, label, description,
fragment, path, const DeepCollectionEquality().hash(_modes));
fragment, keep, path, const DeepCollectionEquality().hash(_modes));
@JsonKey(ignore: true)
@override
@@ -228,6 +246,7 @@ abstract class _NavigationItem implements NavigationItem {
required final String label,
final String? description,
required final Widget fragment,
final bool keep,
final String? path,
final List<NavigationItemMode> modes}) = _$NavigationItemImpl;
@@ -240,6 +259,8 @@ abstract class _NavigationItem implements NavigationItem {
@override
Widget get fragment;
@override
bool get keep;
@override
String? get path;
@override
List<NavigationItemMode> get modes;

View File

@@ -9,7 +9,6 @@ export 'log.dart';
export 'system_color_scheme.dart';
export 'connection.dart';
export 'package.dart';
export 'common.dart';
export 'ffi.dart';
export 'selector.dart';
export 'navigation.dart';

View File

@@ -11,6 +11,7 @@ class NavigationItem with _$NavigationItem {
required String label,
final String? description,
required Widget fragment,
@Default(true) bool keep,
String? path,
@Default([NavigationItemMode.mobile, NavigationItemMode.desktop])
List<NavigationItemMode> modes,

View File

@@ -5,11 +5,8 @@ import 'dart:typed_data';
import 'package:fl_clash/clash/core.dart';
import 'package:fl_clash/enum/enum.dart';
import 'package:fl_clash/common/common.dart';
import 'package:fl_clash/models/models.dart';
import 'package:json_annotation/json_annotation.dart';
import 'common.dart';
part 'generated/profile.g.dart';
typedef SelectedMap = Map<String, String>;
@@ -83,44 +80,31 @@ class Profile {
Duration? autoUpdateDuration,
this.autoUpdate = true,
}) : id = id ?? DateTime.now().millisecondsSinceEpoch.toString(),
autoUpdateDuration =
autoUpdateDuration ?? defaultUpdateDuration,
autoUpdateDuration = autoUpdateDuration ?? defaultUpdateDuration,
selectedMap = selectedMap ?? {};
ProfileType get type => url == null ? ProfileType.file : ProfileType.url;
Future<Result<bool>> checkAndUpdate() async {
Future<void> checkAndUpdate() async {
final isExists = await check();
if(!isExists){
if(url != null){
if (!isExists) {
if (url != null) {
return await update();
}
return Result.error();
}
return Result.success();
}
Future<Result<bool>> update() async {
Future<void> update() async {
if (url == null) {
return Result.error(
appLocalizations.unableToUpdateCurrentProfileDesc,
);
throw appLocalizations.unableToUpdateCurrentProfileDesc;
}
final responseResult = await Request.getFileResponseForUrl(url!);
final response = responseResult.data;
if (responseResult.type != ResultType.success || response == null) {
return Result.error(responseResult.message);
}
final disposition = response.headers['content-disposition'];
final response = await request.getFileResponseForUrl(url!);
final disposition = response.headers.value("content-disposition");
label ??= other.getFileNameForDisposition(disposition) ?? id;
final userinfo = response.headers['subscription-userinfo'];
final userinfo = response.headers.value('subscription-userinfo');
userInfo = UserInfo.formHString(userinfo);
final saveResult = await saveFile(response.bodyBytes);
if (saveResult.type == ResultType.error) {
return Result.error(saveResult.message);
}
await saveFile(response.data);
lastUpdateDate = DateTime.now();
return Result.success();
}
Future<bool> check() async {
@@ -128,10 +112,10 @@ class Profile {
return await File(profilePath!).exists();
}
Future<Result<void>> saveFile(Uint8List bytes) async {
final isValidate = clashCore.validateConfig(utf8.decode(bytes));
if (!isValidate) {
return Result.error(appLocalizations.profileParseErrorDesc);
Future<void> saveFile(Uint8List bytes) async {
final message = await clashCore.validateConfig(utf8.decode(bytes));
if (message.isNotEmpty) {
throw message;
}
final path = await appPath.getProfilePath(id);
final file = File(path!);
@@ -141,7 +125,6 @@ class Profile {
}
await file.writeAsBytes(bytes);
lastUpdateDate = DateTime.now();
return Result.success();
}
Map<String, dynamic> toJson() {