import 'dart:math'; import 'package:collection/collection.dart'; import 'package:fl_clash/common/common.dart'; import 'package:fl_clash/enum/enum.dart'; import 'package:flutter/material.dart'; import 'package:freezed_annotation/freezed_annotation.dart'; part 'generated/common.freezed.dart'; part 'generated/common.g.dart'; @freezed class NavigationItem with _$NavigationItem { const factory NavigationItem({ required Icon icon, required String label, final String? description, required Widget fragment, @Default(true) bool keep, String? path, @Default([NavigationItemMode.mobile, NavigationItemMode.desktop]) List modes, }) = _NavigationItem; } @freezed class Package with _$Package { const factory Package({ required String packageName, required String label, required bool isSystem, required int firstInstallTime, }) = _Package; factory Package.fromJson(Map json) => _$PackageFromJson(json); } @freezed class Metadata with _$Metadata { const factory Metadata({ required int uid, required String network, required String sourceIP, required String sourcePort, required String destinationIP, required String destinationPort, required String host, required String process, required String remoteDestination, }) = _Metadata; factory Metadata.fromJson(Map json) => _$MetadataFromJson(json); } @freezed class Connection with _$Connection { const factory Connection({ required String id, num? upload, num? download, required DateTime start, required Metadata metadata, required List chains, }) = _Connection; factory Connection.fromJson(Map json) => _$ConnectionFromJson(json); } @JsonSerializable() class Log { @JsonKey(name: "LogLevel") LogLevel logLevel; @JsonKey(name: "Payload") String? payload; DateTime _dateTime; Log({ required this.logLevel, this.payload, }) : _dateTime = DateTime.now(); DateTime get dateTime => _dateTime; factory Log.fromJson(Map json) { return _$LogFromJson(json); } Map toJson() { return _$LogToJson(this); } @override String toString() { return 'Log{logLevel: $logLevel, payload: $payload, dateTime: $dateTime}'; } } @freezed class LogsAndKeywords with _$LogsAndKeywords { const factory LogsAndKeywords({ @Default([]) List logs, @Default([]) List keywords, }) = _LogsAndKeywords; factory LogsAndKeywords.fromJson(Map json) => _$LogsAndKeywordsFromJson(json); } extension LogsAndKeywordsExt on LogsAndKeywords { List get filteredLogs => logs .where( (log) => {log.logLevel.name}.containsAll(keywords), ) .toList(); } @freezed class ConnectionsAndKeywords with _$ConnectionsAndKeywords { const factory ConnectionsAndKeywords({ @Default([]) List connections, @Default([]) List keywords, }) = _ConnectionsAndKeywords; factory ConnectionsAndKeywords.fromJson(Map json) => _$ConnectionsAndKeywordsFromJson(json); } extension ConnectionsAndKeywordsExt on ConnectionsAndKeywords { List get filteredConnections => connections .where((connection) => { ...connection.chains, connection.metadata.process, }.containsAll(keywords)) .toList(); } const defaultDavFileName = "backup.zip"; @freezed class DAV with _$DAV { const factory DAV({ required String uri, required String user, required String password, @Default(defaultDavFileName) String fileName, }) = _DAV; factory DAV.fromJson(Map json) => _$DAVFromJson(json); } @freezed class FileInfo with _$FileInfo { const factory FileInfo({ required int size, required DateTime lastModified, }) = _FileInfo; } extension FileInfoExt on FileInfo { String get desc => "${TrafficValue(value: size).show} · ${lastModified.lastUpdateTimeDesc}"; } @freezed class VersionInfo with _$VersionInfo { const factory VersionInfo({ @Default("") String clashName, @Default("") String version, }) = _VersionInfo; factory VersionInfo.fromJson(Map json) => _$VersionInfoFromJson(json); } class Traffic { int id; TrafficValue up; TrafficValue down; Traffic({num? up, num? down}) : id = DateTime.now().millisecondsSinceEpoch, up = TrafficValue(value: up), down = TrafficValue(value: down); num get speed => up.value + down.value; factory Traffic.fromMap(Map map) { return Traffic( up: map['up'], down: map['down'], ); } @override String toString() { return '$up↑ $down↓'; } @override bool operator ==(Object other) => identical(this, other) || other is Traffic && runtimeType == other.runtimeType && id == other.id && up == other.up && down == other.down; @override int get hashCode => id.hashCode ^ up.hashCode ^ down.hashCode; } @immutable class TrafficValueShow { final String value; final TrafficUnit unit; const TrafficValueShow({ required this.value, required this.unit, }); } @immutable class TrafficValue { final num _value; const TrafficValue({num? value}) : _value = value ?? 0; num get value => _value; String get show => "$showValue $showUnit"; String get showValue => trafficValueShow.value; String get showUnit => trafficValueShow.unit.name; TrafficValueShow get trafficValueShow { if (_value > pow(1024, 4)) { return TrafficValueShow( value: (_value / pow(1024, 4)).fixed(), unit: TrafficUnit.TB, ); } if (_value > pow(1024, 3)) { return TrafficValueShow( value: (_value / pow(1024, 3)).fixed(), unit: TrafficUnit.GB, ); } if (_value > pow(1024, 2)) { return TrafficValueShow( value: (_value / pow(1024, 2)).fixed(), unit: TrafficUnit.MB); } if (_value > pow(1024, 1)) { return TrafficValueShow( value: (_value / pow(1024, 1)).fixed(), unit: TrafficUnit.KB, ); } return TrafficValueShow( value: _value.fixed(), unit: TrafficUnit.B, ); } @override String toString() { return "$showValue$showUnit"; } @override bool operator ==(Object other) => identical(this, other) || other is TrafficValue && runtimeType == other.runtimeType && _value == other._value; @override int get hashCode => _value.hashCode; } typedef ProxyMap = Map; @freezed class Group with _$Group { const factory Group({ required GroupType type, @Default([]) List all, String? now, bool? hidden, @Default("") String icon, required String name, }) = _Group; factory Group.fromJson(Map json) => _$GroupFromJson(json); } extension GroupExt on Group { String get realNow => now ?? ""; String getCurrentSelectedName(String proxyName) { if (type == GroupType.URLTest) { return realNow.isNotEmpty ? realNow : proxyName; } return proxyName.isNotEmpty ? proxyName : realNow; } } @freezed class Proxy with _$Proxy { const factory Proxy({ required String name, required String type, String? now, }) = _Proxy; factory Proxy.fromJson(Map json) => _$ProxyFromJson(json); } @immutable class SystemColorSchemes { final ColorScheme? lightColorScheme; final ColorScheme? darkColorScheme; const SystemColorSchemes({ this.lightColorScheme, this.darkColorScheme, }); getSystemColorSchemeForBrightness(Brightness? brightness) { if (brightness == Brightness.dark) { return darkColorScheme != null ? ColorScheme.fromSeed( seedColor: darkColorScheme!.primary, brightness: Brightness.dark, ) : ColorScheme.fromSeed( seedColor: defaultPrimaryColor, brightness: Brightness.dark, ); } return lightColorScheme != null ? ColorScheme.fromSeed(seedColor: darkColorScheme!.primary) : ColorScheme.fromSeed(seedColor: defaultPrimaryColor); } } class IpInfo { final String ip; final String countryCode; const IpInfo({ required this.ip, required this.countryCode, }); static IpInfo fromIpInfoIoJson(Map json) { return switch (json) { { "ip": final String ip, "country": final String country, } => IpInfo( ip: ip, countryCode: country, ), _ => throw const FormatException("invalid json"), }; } static IpInfo fromIpApiCoJson(Map json) { return switch (json) { { "ip": final String ip, "country_code": final String countryCode, } => IpInfo( ip: ip, countryCode: countryCode, ), _ => throw const FormatException("invalid json"), }; } static IpInfo fromIpSbJson(Map json) { return switch (json) { { "ip": final String ip, "country_code": final String countryCode, } => IpInfo( ip: ip, countryCode: countryCode, ), _ => throw const FormatException("invalid json"), }; } static IpInfo fromIpwhoIsJson(Map json) { return switch (json) { { "ip": final String ip, "country_code": final String countryCode, } => IpInfo( ip: ip, countryCode: countryCode, ), _ => throw const FormatException("invalid json"), }; } @override String toString() { return 'IpInfo{ip: $ip, countryCode: $countryCode}'; } } @freezed class HotKeyAction with _$HotKeyAction { const factory HotKeyAction({ required HotAction action, int? key, @Default({}) Set modifiers, }) = _HotKeyAction; factory HotKeyAction.fromJson(Map json) => _$HotKeyActionFromJson(json); } const keyboardModifiersEquality = SetEquality(); const hotKeyActionsEquality = ListEquality();