2025-01-13 19:08:17 +08:00
|
|
|
// ignore_for_file: invalid_annotation_target
|
|
|
|
|
|
2024-09-08 21:21:21 +08:00
|
|
|
import 'dart:math';
|
|
|
|
|
|
|
|
|
|
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';
|
2025-02-09 18:39:38 +08:00
|
|
|
|
2024-09-08 21:21:21 +08:00
|
|
|
part 'generated/common.g.dart';
|
|
|
|
|
|
|
|
|
|
@freezed
|
|
|
|
|
class NavigationItem with _$NavigationItem {
|
|
|
|
|
const factory NavigationItem({
|
|
|
|
|
required Icon icon,
|
2025-02-09 18:39:38 +08:00
|
|
|
required PageLabel label,
|
2024-09-08 21:21:21 +08:00
|
|
|
final String? description,
|
|
|
|
|
required Widget fragment,
|
|
|
|
|
@Default(true) bool keep,
|
|
|
|
|
String? path,
|
|
|
|
|
@Default([NavigationItemMode.mobile, NavigationItemMode.desktop])
|
|
|
|
|
List<NavigationItemMode> modes,
|
|
|
|
|
}) = _NavigationItem;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@freezed
|
|
|
|
|
class Package with _$Package {
|
|
|
|
|
const factory Package({
|
|
|
|
|
required String packageName,
|
|
|
|
|
required String label,
|
2025-04-18 17:50:46 +08:00
|
|
|
required bool system,
|
|
|
|
|
required bool internet,
|
2025-02-03 23:32:00 +08:00
|
|
|
required int lastUpdateTime,
|
2024-09-08 21:21:21 +08:00
|
|
|
}) = _Package;
|
|
|
|
|
|
|
|
|
|
factory Package.fromJson(Map<String, Object?> 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<String, Object?> 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<String> chains,
|
|
|
|
|
}) = _Connection;
|
|
|
|
|
|
|
|
|
|
factory Connection.fromJson(Map<String, Object?> json) =>
|
|
|
|
|
_$ConnectionFromJson(json);
|
|
|
|
|
}
|
|
|
|
|
|
2025-02-03 23:32:00 +08:00
|
|
|
extension ConnectionExt on Connection {
|
|
|
|
|
String get desc {
|
|
|
|
|
var text = "${metadata.network}://";
|
|
|
|
|
final ips = [
|
|
|
|
|
metadata.host,
|
|
|
|
|
metadata.destinationIP,
|
|
|
|
|
].where((ip) => ip.isNotEmpty);
|
|
|
|
|
text += ips.join("/");
|
|
|
|
|
text += ":${metadata.destinationPort}";
|
|
|
|
|
return text;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2025-04-18 17:50:46 +08:00
|
|
|
String _logDateTime(_) {
|
|
|
|
|
return DateTime.now().toString();
|
|
|
|
|
}
|
2024-09-08 21:21:21 +08:00
|
|
|
|
2025-04-18 17:50:46 +08:00
|
|
|
// String _logId(_) {
|
|
|
|
|
// return utils.id;
|
|
|
|
|
// }
|
2024-09-08 21:21:21 +08:00
|
|
|
|
2025-04-18 17:50:46 +08:00
|
|
|
@freezed
|
|
|
|
|
class Log with _$Log {
|
|
|
|
|
const factory Log({
|
|
|
|
|
@JsonKey(name: "LogLevel") @Default(LogLevel.app) LogLevel logLevel,
|
|
|
|
|
@JsonKey(name: "Payload") @Default("") String payload,
|
|
|
|
|
@JsonKey(fromJson: _logDateTime) required String dateTime,
|
|
|
|
|
}) = _Log;
|
|
|
|
|
|
|
|
|
|
factory Log.app(
|
|
|
|
|
String payload,
|
|
|
|
|
) {
|
|
|
|
|
return Log(
|
|
|
|
|
payload: payload,
|
|
|
|
|
dateTime: _logDateTime(null),
|
|
|
|
|
// id: _logId(null),
|
|
|
|
|
);
|
2024-09-08 21:21:21 +08:00
|
|
|
}
|
|
|
|
|
|
2025-04-18 17:50:46 +08:00
|
|
|
factory Log.fromJson(Map<String, Object?> json) => _$LogFromJson(json);
|
2024-09-08 21:21:21 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@freezed
|
2025-02-03 23:32:00 +08:00
|
|
|
class LogsState with _$LogsState {
|
|
|
|
|
const factory LogsState({
|
2024-09-08 21:21:21 +08:00
|
|
|
@Default([]) List<Log> logs,
|
|
|
|
|
@Default([]) List<String> keywords,
|
2025-02-03 23:32:00 +08:00
|
|
|
@Default("") String query,
|
2025-04-18 17:50:46 +08:00
|
|
|
@Default(false) bool loading,
|
2025-02-03 23:32:00 +08:00
|
|
|
}) = _LogsState;
|
2024-09-08 21:21:21 +08:00
|
|
|
}
|
|
|
|
|
|
2025-02-03 23:32:00 +08:00
|
|
|
extension LogsStateExt on LogsState {
|
|
|
|
|
List<Log> get list {
|
|
|
|
|
final lowQuery = query.toLowerCase();
|
|
|
|
|
return logs.where(
|
|
|
|
|
(log) {
|
2025-04-18 17:50:46 +08:00
|
|
|
final payload = log.payload.toLowerCase();
|
2025-02-03 23:32:00 +08:00
|
|
|
final logLevelName = log.logLevel.name;
|
|
|
|
|
return {logLevelName}.containsAll(keywords) &&
|
2025-04-18 17:50:46 +08:00
|
|
|
((payload.contains(lowQuery)) || logLevelName.contains(lowQuery));
|
2025-02-03 23:32:00 +08:00
|
|
|
},
|
|
|
|
|
).toList();
|
|
|
|
|
}
|
2024-09-08 21:21:21 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@freezed
|
2025-02-03 23:32:00 +08:00
|
|
|
class ConnectionsState with _$ConnectionsState {
|
|
|
|
|
const factory ConnectionsState({
|
2024-09-08 21:21:21 +08:00
|
|
|
@Default([]) List<Connection> connections,
|
|
|
|
|
@Default([]) List<String> keywords,
|
2025-02-03 23:32:00 +08:00
|
|
|
@Default("") String query,
|
2025-04-18 17:50:46 +08:00
|
|
|
@Default(false) bool loading,
|
2025-02-03 23:32:00 +08:00
|
|
|
}) = _ConnectionsState;
|
2024-09-08 21:21:21 +08:00
|
|
|
}
|
|
|
|
|
|
2025-02-03 23:32:00 +08:00
|
|
|
extension ConnectionsStateExt on ConnectionsState {
|
|
|
|
|
List<Connection> get list {
|
|
|
|
|
final lowerQuery = query.toLowerCase().trim();
|
|
|
|
|
final lowQuery = query.toLowerCase();
|
|
|
|
|
return connections.where((connection) {
|
|
|
|
|
final chains = connection.chains;
|
|
|
|
|
final process = connection.metadata.process;
|
|
|
|
|
final networkText = connection.metadata.network.toLowerCase();
|
|
|
|
|
final hostText = connection.metadata.host.toLowerCase();
|
|
|
|
|
final destinationIPText = connection.metadata.destinationIP.toLowerCase();
|
|
|
|
|
final processText = connection.metadata.process.toLowerCase();
|
|
|
|
|
final chainsText = chains.join("").toLowerCase();
|
|
|
|
|
return {...chains, process}.containsAll(keywords) &&
|
|
|
|
|
(networkText.contains(lowerQuery) ||
|
|
|
|
|
hostText.contains(lowerQuery) ||
|
|
|
|
|
destinationIPText.contains(lowQuery) ||
|
|
|
|
|
processText.contains(lowerQuery) ||
|
|
|
|
|
chainsText.contains(lowerQuery));
|
|
|
|
|
}).toList();
|
|
|
|
|
}
|
2024-09-08 21:21:21 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
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<String, Object?> 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<String, Object?> json) =>
|
|
|
|
|
_$VersionInfoFromJson(json);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
class Traffic {
|
|
|
|
|
int id;
|
|
|
|
|
TrafficValue up;
|
|
|
|
|
TrafficValue down;
|
|
|
|
|
|
2024-12-09 01:40:39 +08:00
|
|
|
Traffic({int? up, int? down})
|
2024-09-08 21:21:21 +08:00
|
|
|
: id = DateTime.now().millisecondsSinceEpoch,
|
|
|
|
|
up = TrafficValue(value: up),
|
|
|
|
|
down = TrafficValue(value: down);
|
|
|
|
|
|
|
|
|
|
num get speed => up.value + down.value;
|
|
|
|
|
|
|
|
|
|
factory Traffic.fromMap(Map<String, dynamic> 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 {
|
2025-02-09 18:39:38 +08:00
|
|
|
final double value;
|
2024-09-08 21:21:21 +08:00
|
|
|
final TrafficUnit unit;
|
|
|
|
|
|
|
|
|
|
const TrafficValueShow({
|
|
|
|
|
required this.value,
|
|
|
|
|
required this.unit,
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
|
2025-02-09 18:39:38 +08:00
|
|
|
@freezed
|
|
|
|
|
class Proxy with _$Proxy {
|
|
|
|
|
const factory Proxy({
|
|
|
|
|
required String name,
|
|
|
|
|
required String type,
|
|
|
|
|
String? now,
|
|
|
|
|
}) = _Proxy;
|
|
|
|
|
|
|
|
|
|
factory Proxy.fromJson(Map<String, Object?> json) => _$ProxyFromJson(json);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@freezed
|
|
|
|
|
class Group with _$Group {
|
|
|
|
|
const factory Group({
|
|
|
|
|
required GroupType type,
|
|
|
|
|
@Default([]) List<Proxy> all,
|
|
|
|
|
String? now,
|
|
|
|
|
bool? hidden,
|
|
|
|
|
String? testUrl,
|
|
|
|
|
@Default("") String icon,
|
|
|
|
|
required String name,
|
|
|
|
|
}) = _Group;
|
|
|
|
|
|
|
|
|
|
factory Group.fromJson(Map<String, Object?> json) => _$GroupFromJson(json);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
extension GroupsExt on List<Group> {
|
|
|
|
|
Group? getGroup(String groupName) {
|
|
|
|
|
final index = indexWhere((element) => element.name == groupName);
|
|
|
|
|
return index != -1 ? this[index] : null;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
extension GroupExt on Group {
|
|
|
|
|
String get realNow => now ?? "";
|
|
|
|
|
|
|
|
|
|
String getCurrentSelectedName(String proxyName) {
|
|
|
|
|
if (type.isComputedSelected) {
|
|
|
|
|
return realNow.isNotEmpty ? realNow : proxyName;
|
|
|
|
|
}
|
|
|
|
|
return proxyName.isNotEmpty ? proxyName : realNow;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2024-09-08 21:21:21 +08:00
|
|
|
@immutable
|
|
|
|
|
class TrafficValue {
|
2024-12-09 01:40:39 +08:00
|
|
|
final int _value;
|
2024-09-08 21:21:21 +08:00
|
|
|
|
2024-12-09 01:40:39 +08:00
|
|
|
const TrafficValue({int? value}) : _value = value ?? 0;
|
2024-09-08 21:21:21 +08:00
|
|
|
|
2024-12-09 01:40:39 +08:00
|
|
|
int get value => _value;
|
2024-09-08 21:21:21 +08:00
|
|
|
|
|
|
|
|
String get show => "$showValue $showUnit";
|
|
|
|
|
|
2025-02-09 18:39:38 +08:00
|
|
|
String get shortShow =>
|
|
|
|
|
"${trafficValueShow.value.fixed(decimals: 1)} $showUnit";
|
|
|
|
|
|
|
|
|
|
String get showValue => trafficValueShow.value.fixed();
|
2024-09-08 21:21:21 +08:00
|
|
|
|
|
|
|
|
String get showUnit => trafficValueShow.unit.name;
|
|
|
|
|
|
|
|
|
|
TrafficValueShow get trafficValueShow {
|
|
|
|
|
if (_value > pow(1024, 4)) {
|
|
|
|
|
return TrafficValueShow(
|
2025-02-09 18:39:38 +08:00
|
|
|
value: _value / pow(1024, 4),
|
2024-09-08 21:21:21 +08:00
|
|
|
unit: TrafficUnit.TB,
|
|
|
|
|
);
|
|
|
|
|
}
|
|
|
|
|
if (_value > pow(1024, 3)) {
|
|
|
|
|
return TrafficValueShow(
|
2025-02-09 18:39:38 +08:00
|
|
|
value: _value / pow(1024, 3),
|
2024-09-08 21:21:21 +08:00
|
|
|
unit: TrafficUnit.GB,
|
|
|
|
|
);
|
|
|
|
|
}
|
|
|
|
|
if (_value > pow(1024, 2)) {
|
|
|
|
|
return TrafficValueShow(
|
2025-02-09 18:39:38 +08:00
|
|
|
value: _value / pow(1024, 2), unit: TrafficUnit.MB);
|
2024-09-08 21:21:21 +08:00
|
|
|
}
|
|
|
|
|
if (_value > pow(1024, 1)) {
|
|
|
|
|
return TrafficValueShow(
|
2025-03-05 15:11:19 +08:00
|
|
|
value: _value / pow(1024, 1),
|
2024-09-08 21:21:21 +08:00
|
|
|
unit: TrafficUnit.KB,
|
|
|
|
|
);
|
|
|
|
|
}
|
|
|
|
|
return TrafficValueShow(
|
2025-02-09 18:39:38 +08:00
|
|
|
value: _value.toDouble(),
|
2024-09-08 21:21:21 +08:00
|
|
|
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;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@freezed
|
2025-02-09 18:39:38 +08:00
|
|
|
class ColorSchemes with _$ColorSchemes {
|
|
|
|
|
const factory ColorSchemes({
|
|
|
|
|
ColorScheme? lightColorScheme,
|
|
|
|
|
ColorScheme? darkColorScheme,
|
|
|
|
|
}) = _ColorSchemes;
|
2024-09-08 21:21:21 +08:00
|
|
|
}
|
|
|
|
|
|
2025-02-09 18:39:38 +08:00
|
|
|
extension ColorSchemesExt on ColorSchemes {
|
2025-04-09 16:46:14 +08:00
|
|
|
ColorScheme getColorSchemeForBrightness(
|
|
|
|
|
Brightness brightness,
|
|
|
|
|
DynamicSchemeVariant schemeVariant,
|
|
|
|
|
) {
|
2024-09-08 21:21:21 +08:00
|
|
|
if (brightness == Brightness.dark) {
|
|
|
|
|
return darkColorScheme != null
|
|
|
|
|
? ColorScheme.fromSeed(
|
|
|
|
|
seedColor: darkColorScheme!.primary,
|
|
|
|
|
brightness: Brightness.dark,
|
2025-04-09 16:46:14 +08:00
|
|
|
dynamicSchemeVariant: schemeVariant,
|
2024-09-08 21:21:21 +08:00
|
|
|
)
|
|
|
|
|
: ColorScheme.fromSeed(
|
2025-04-09 16:46:14 +08:00
|
|
|
seedColor: Color(defaultPrimaryColor),
|
2024-09-08 21:21:21 +08:00
|
|
|
brightness: Brightness.dark,
|
2025-04-09 16:46:14 +08:00
|
|
|
dynamicSchemeVariant: schemeVariant,
|
2024-09-08 21:21:21 +08:00
|
|
|
);
|
|
|
|
|
}
|
|
|
|
|
return lightColorScheme != null
|
2025-04-09 16:46:14 +08:00
|
|
|
? ColorScheme.fromSeed(
|
|
|
|
|
seedColor: lightColorScheme!.primary,
|
|
|
|
|
dynamicSchemeVariant: schemeVariant,
|
|
|
|
|
)
|
|
|
|
|
: ColorScheme.fromSeed(
|
|
|
|
|
seedColor: Color(defaultPrimaryColor),
|
|
|
|
|
dynamicSchemeVariant: schemeVariant,
|
|
|
|
|
);
|
2024-09-08 21:21:21 +08:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
class IpInfo {
|
|
|
|
|
final String ip;
|
|
|
|
|
final String countryCode;
|
|
|
|
|
|
|
|
|
|
const IpInfo({
|
|
|
|
|
required this.ip,
|
|
|
|
|
required this.countryCode,
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
static IpInfo fromIpInfoIoJson(Map<String, dynamic> 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<String, dynamic> 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<String, dynamic> 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<String, dynamic> 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<KeyboardModifier> modifiers,
|
|
|
|
|
}) = _HotKeyAction;
|
|
|
|
|
|
|
|
|
|
factory HotKeyAction.fromJson(Map<String, Object?> json) =>
|
|
|
|
|
_$HotKeyActionFromJson(json);
|
|
|
|
|
}
|
|
|
|
|
|
2024-09-26 14:29:04 +08:00
|
|
|
typedef Validator = String? Function(String? value);
|
|
|
|
|
|
|
|
|
|
@freezed
|
|
|
|
|
class Field with _$Field {
|
|
|
|
|
const factory Field({
|
|
|
|
|
required String label,
|
|
|
|
|
required String value,
|
|
|
|
|
Validator? validator,
|
|
|
|
|
}) = _Field;
|
2024-10-27 16:59:23 +08:00
|
|
|
}
|
2025-01-13 19:08:17 +08:00
|
|
|
|
2025-03-12 17:15:31 +08:00
|
|
|
enum PopupMenuItemType {
|
2025-01-13 19:08:17 +08:00
|
|
|
primary,
|
|
|
|
|
danger,
|
|
|
|
|
}
|
|
|
|
|
|
2025-03-12 17:15:31 +08:00
|
|
|
class PopupMenuItemData {
|
|
|
|
|
const PopupMenuItemData({
|
2025-01-13 19:08:17 +08:00
|
|
|
this.icon,
|
|
|
|
|
required this.label,
|
|
|
|
|
required this.onPressed,
|
|
|
|
|
this.type,
|
|
|
|
|
this.iconSize,
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
final double? iconSize;
|
|
|
|
|
final String label;
|
2025-03-12 17:15:31 +08:00
|
|
|
final VoidCallback? onPressed;
|
2025-01-13 19:08:17 +08:00
|
|
|
final IconData? icon;
|
2025-03-12 17:15:31 +08:00
|
|
|
final PopupMenuItemType? type;
|
2025-04-09 16:46:14 +08:00
|
|
|
}
|
2025-04-18 17:50:46 +08:00
|
|
|
|
|
|
|
|
@freezed
|
|
|
|
|
class TextPainterParams with _$TextPainterParams {
|
|
|
|
|
const factory TextPainterParams({
|
|
|
|
|
required String? text,
|
|
|
|
|
required double? fontSize,
|
|
|
|
|
required double textScaleFactor,
|
|
|
|
|
@Default(double.infinity) double maxWidth,
|
|
|
|
|
int? maxLines,
|
|
|
|
|
}) = _TextPainterParams;
|
|
|
|
|
|
|
|
|
|
factory TextPainterParams.fromJson(Map<String, Object?> json) =>
|
|
|
|
|
_$TextPainterParamsFromJson(json);
|
|
|
|
|
}
|