feat: Added Port Forwarding Functionality (#1083)

* feat: Added Port Forwarding Functionality

Implemented port forwarding functionality, including the following major changes:
- Added a port forwarding configuration model and related state management
- Added a port forwarding page and interaction logic
- Implemented forwarding connections between local and remote ports
- Integrated into the server features menu
- Added necessary Hive adapters and storage support
- Updated plugin configurations across all platforms to support the new feature

* feat (Port Forwarding): Added multilingual support and optimized implementation

Added multilingual support for the port forwarding feature, including Chinese, English, and other languages

Optimized the port forwarding implementation by adding connection management and error handling

Fixed an issue with state persistence when updating port forwarding configurations

Updated related dependencies and submodules

* fix(port_forward): Fixed port forwarding error handling and redesigned the configuration dialog

Handled uncaught errors when port forwarding is disabled or during connection attempts

Extracted the configuration dialog into a standalone component and added port range validation

* fix(port_forward): Fixed issues with port forwarding connection management and UI layout

Fixed an issue where port forwarding connections were not closed properly; now uses `clientGetter` to delay the retrieval of `SSHClient`
Added cleanup logic when connections are closed to prevent memory leaks

Added a `mounted` check in `PortForwardPage` to prevent operations from executing after the component is unmounted

Wrapped the configuration dialog content in a `SingleChildScrollView` to prevent content overflow

* fix(port_forward): Fixed a concurrent modification exception that occurred when closing a port forwarding connection

Fixed a concurrent modification exception that could occur when closing a local forwarding entry by copying the connection list to prevent modifications to the collection during iteration. Also improved the UI by using theme colors and added error handling for configuration saving.

* fix(port_forward_provider): Fixed an issue where entries were not properly removed when port forwarding was stopped

When port forwarding is stopped, ensure that the corresponding entries are removed from the _forwards map. Additionally, before adding a new forwarding rule, check for and close any existing forwarding rules with the same ID to prevent resource leaks.

* refactor(l1n): Remove unused localization and remote host port translations

* fix(port_forward_provider): Handle errors when closing port forwarding

Add error handling to prevent the program from crashing due to exceptions when closing port forwarding

* refactor(port_forward): Refactor port forwarding state management to use serverId

Directly link port forwarding state management to the server ID to simplify parameter passing

Remove direct dependencies on Spi and use serverId as the core identifier instead

Update relevant providers and page logic to accommodate the new state structure

* fix(port_forward): Fixed a race condition issue in port forwarding operations

Added an _inFlight collection to prevent duplicate operations

Added a _saving state when saving configurations to prevent duplicate submissions

Automatically cleans up forwarding when changes in server connection status are detected

* refactor(port_forward_provider): Remove unnecessary concurrency control logic

Simplify the `toggleForward` method by removing concurrency control for the `_inFlight` collection, as it is not required in the current scenario
This commit is contained in:
GT610
2026-03-23 19:38:58 +08:00
committed by GitHub
parent 0a42e27ce3
commit d6e17ff58c
40 changed files with 2162 additions and 239 deletions

View File

@@ -12,21 +12,33 @@ enum ServerFuncBtn {
snippet(),
iperf(),
// pve(),
systemd(1058);
systemd(1058),
portForward(1340);
final int? addedVersion;
const ServerFuncBtn([this.addedVersion]);
static void autoAddNewFuncs(int cur) {
if (cur >= systemd.addedVersion!) {
final prop = Stores.setting.serverFuncBtns;
final list = prop.fetch();
final prop = Stores.setting.serverFuncBtns;
final list = prop.fetch();
final originalLength = list.length;
if (systemd.addedVersion != null && cur >= systemd.addedVersion!) {
if (!list.contains(systemd.index)) {
list.add(systemd.index);
prop.put(list);
}
}
if (portForward.addedVersion != null && cur >= portForward.addedVersion!) {
if (!list.contains(portForward.index)) {
list.add(portForward.index);
}
}
if (list.length > originalLength) {
prop.put(list);
}
}
static final defaultIdxs = [
@@ -48,6 +60,7 @@ enum ServerFuncBtn {
terminal => Icons.terminal,
iperf => Icons.speed,
systemd => MingCute.plugin_2_fill,
portForward => Icons.compare_arrows,
};
String get toStr => switch (this) {
@@ -59,5 +72,6 @@ enum ServerFuncBtn {
terminal => libL10n.terminal,
iperf => 'iperf',
systemd => 'Systemd',
portForward => libL10n.portForward,
};
}

View File

@@ -0,0 +1,59 @@
import 'package:freezed_annotation/freezed_annotation.dart';
part 'port_forward.freezed.dart';
part 'port_forward.g.dart';
@freezed
abstract class PortForwardConfig with _$PortForwardConfig {
const factory PortForwardConfig({
required String id,
required String serverId,
required String name,
@Default('localhost') String localHost,
required int localPort,
required String remoteHost,
required int remotePort,
String? description,
}) = _PortForwardConfig;
factory PortForwardConfig.fromJson(Map<String, dynamic> json) => _$PortForwardConfigFromJson(json);
const PortForwardConfig._();
String get displayAddr => '$localHost:$localPort$remoteHost:$remotePort';
}
@freezed
abstract class PortForwardState with _$PortForwardState {
const factory PortForwardState({
required String serverId,
@Default([]) List<PortForwardConfig> configs,
@Default({}) Map<String, PortForwardStatus> activeForwards,
}) = _PortForwardState;
}
class PortForwardStatus {
final String id;
final bool isActive;
final String? error;
const PortForwardStatus({
required this.id,
this.isActive = false,
this.error,
});
PortForwardStatus copyWith({
String? id,
bool? isActive,
Object? error = _sentinel,
}) {
return PortForwardStatus(
id: id ?? this.id,
isActive: isActive ?? this.isActive,
error: error == _sentinel ? this.error : error as String?,
);
}
}
const _sentinel = Object();

View File

@@ -0,0 +1,573 @@
// GENERATED CODE - DO NOT MODIFY BY HAND
// coverage:ignore-file
// ignore_for_file: type=lint
// ignore_for_file: unused_element, deprecated_member_use, deprecated_member_use_from_same_package, use_function_type_syntax_for_parameters, unnecessary_const, avoid_init_to_null, invalid_override_different_default_values_named, prefer_expression_function_bodies, annotate_overrides, invalid_annotation_target, unnecessary_question_mark
part of 'port_forward.dart';
// **************************************************************************
// FreezedGenerator
// **************************************************************************
// dart format off
T _$identity<T>(T value) => value;
/// @nodoc
mixin _$PortForwardConfig {
String get id; String get serverId; String get name; String get localHost; int get localPort; String get remoteHost; int get remotePort; String? get description;
/// Create a copy of PortForwardConfig
/// with the given fields replaced by the non-null parameter values.
@JsonKey(includeFromJson: false, includeToJson: false)
@pragma('vm:prefer-inline')
$PortForwardConfigCopyWith<PortForwardConfig> get copyWith => _$PortForwardConfigCopyWithImpl<PortForwardConfig>(this as PortForwardConfig, _$identity);
/// Serializes this PortForwardConfig to a JSON map.
Map<String, dynamic> toJson();
@override
bool operator ==(Object other) {
return identical(this, other) || (other.runtimeType == runtimeType&&other is PortForwardConfig&&(identical(other.id, id) || other.id == id)&&(identical(other.serverId, serverId) || other.serverId == serverId)&&(identical(other.name, name) || other.name == name)&&(identical(other.localHost, localHost) || other.localHost == localHost)&&(identical(other.localPort, localPort) || other.localPort == localPort)&&(identical(other.remoteHost, remoteHost) || other.remoteHost == remoteHost)&&(identical(other.remotePort, remotePort) || other.remotePort == remotePort)&&(identical(other.description, description) || other.description == description));
}
@JsonKey(includeFromJson: false, includeToJson: false)
@override
int get hashCode => Object.hash(runtimeType,id,serverId,name,localHost,localPort,remoteHost,remotePort,description);
@override
String toString() {
return 'PortForwardConfig(id: $id, serverId: $serverId, name: $name, localHost: $localHost, localPort: $localPort, remoteHost: $remoteHost, remotePort: $remotePort, description: $description)';
}
}
/// @nodoc
abstract mixin class $PortForwardConfigCopyWith<$Res> {
factory $PortForwardConfigCopyWith(PortForwardConfig value, $Res Function(PortForwardConfig) _then) = _$PortForwardConfigCopyWithImpl;
@useResult
$Res call({
String id, String serverId, String name, String localHost, int localPort, String remoteHost, int remotePort, String? description
});
}
/// @nodoc
class _$PortForwardConfigCopyWithImpl<$Res>
implements $PortForwardConfigCopyWith<$Res> {
_$PortForwardConfigCopyWithImpl(this._self, this._then);
final PortForwardConfig _self;
final $Res Function(PortForwardConfig) _then;
/// Create a copy of PortForwardConfig
/// with the given fields replaced by the non-null parameter values.
@pragma('vm:prefer-inline') @override $Res call({Object? id = null,Object? serverId = null,Object? name = null,Object? localHost = null,Object? localPort = null,Object? remoteHost = null,Object? remotePort = null,Object? description = freezed,}) {
return _then(_self.copyWith(
id: null == id ? _self.id : id // ignore: cast_nullable_to_non_nullable
as String,serverId: null == serverId ? _self.serverId : serverId // ignore: cast_nullable_to_non_nullable
as String,name: null == name ? _self.name : name // ignore: cast_nullable_to_non_nullable
as String,localHost: null == localHost ? _self.localHost : localHost // ignore: cast_nullable_to_non_nullable
as String,localPort: null == localPort ? _self.localPort : localPort // ignore: cast_nullable_to_non_nullable
as int,remoteHost: null == remoteHost ? _self.remoteHost : remoteHost // ignore: cast_nullable_to_non_nullable
as String,remotePort: null == remotePort ? _self.remotePort : remotePort // ignore: cast_nullable_to_non_nullable
as int,description: freezed == description ? _self.description : description // ignore: cast_nullable_to_non_nullable
as String?,
));
}
}
/// Adds pattern-matching-related methods to [PortForwardConfig].
extension PortForwardConfigPatterns on PortForwardConfig {
/// A variant of `map` that fallback to returning `orElse`.
///
/// It is equivalent to doing:
/// ```dart
/// switch (sealedClass) {
/// case final Subclass value:
/// return ...;
/// case _:
/// return orElse();
/// }
/// ```
@optionalTypeArgs TResult maybeMap<TResult extends Object?>(TResult Function( _PortForwardConfig value)? $default,{required TResult orElse(),}){
final _that = this;
switch (_that) {
case _PortForwardConfig() when $default != null:
return $default(_that);case _:
return orElse();
}
}
/// A `switch`-like method, using callbacks.
///
/// Callbacks receives the raw object, upcasted.
/// It is equivalent to doing:
/// ```dart
/// switch (sealedClass) {
/// case final Subclass value:
/// return ...;
/// case final Subclass2 value:
/// return ...;
/// }
/// ```
@optionalTypeArgs TResult map<TResult extends Object?>(TResult Function( _PortForwardConfig value) $default,){
final _that = this;
switch (_that) {
case _PortForwardConfig():
return $default(_that);case _:
throw StateError('Unexpected subclass');
}
}
/// A variant of `map` that fallback to returning `null`.
///
/// It is equivalent to doing:
/// ```dart
/// switch (sealedClass) {
/// case final Subclass value:
/// return ...;
/// case _:
/// return null;
/// }
/// ```
@optionalTypeArgs TResult? mapOrNull<TResult extends Object?>(TResult? Function( _PortForwardConfig value)? $default,){
final _that = this;
switch (_that) {
case _PortForwardConfig() when $default != null:
return $default(_that);case _:
return null;
}
}
/// A variant of `when` that fallback to an `orElse` callback.
///
/// It is equivalent to doing:
/// ```dart
/// switch (sealedClass) {
/// case Subclass(:final field):
/// return ...;
/// case _:
/// return orElse();
/// }
/// ```
@optionalTypeArgs TResult maybeWhen<TResult extends Object?>(TResult Function( String id, String serverId, String name, String localHost, int localPort, String remoteHost, int remotePort, String? description)? $default,{required TResult orElse(),}) {final _that = this;
switch (_that) {
case _PortForwardConfig() when $default != null:
return $default(_that.id,_that.serverId,_that.name,_that.localHost,_that.localPort,_that.remoteHost,_that.remotePort,_that.description);case _:
return orElse();
}
}
/// A `switch`-like method, using callbacks.
///
/// As opposed to `map`, this offers destructuring.
/// It is equivalent to doing:
/// ```dart
/// switch (sealedClass) {
/// case Subclass(:final field):
/// return ...;
/// case Subclass2(:final field2):
/// return ...;
/// }
/// ```
@optionalTypeArgs TResult when<TResult extends Object?>(TResult Function( String id, String serverId, String name, String localHost, int localPort, String remoteHost, int remotePort, String? description) $default,) {final _that = this;
switch (_that) {
case _PortForwardConfig():
return $default(_that.id,_that.serverId,_that.name,_that.localHost,_that.localPort,_that.remoteHost,_that.remotePort,_that.description);case _:
throw StateError('Unexpected subclass');
}
}
/// A variant of `when` that fallback to returning `null`
///
/// It is equivalent to doing:
/// ```dart
/// switch (sealedClass) {
/// case Subclass(:final field):
/// return ...;
/// case _:
/// return null;
/// }
/// ```
@optionalTypeArgs TResult? whenOrNull<TResult extends Object?>(TResult? Function( String id, String serverId, String name, String localHost, int localPort, String remoteHost, int remotePort, String? description)? $default,) {final _that = this;
switch (_that) {
case _PortForwardConfig() when $default != null:
return $default(_that.id,_that.serverId,_that.name,_that.localHost,_that.localPort,_that.remoteHost,_that.remotePort,_that.description);case _:
return null;
}
}
}
/// @nodoc
@JsonSerializable()
class _PortForwardConfig extends PortForwardConfig {
const _PortForwardConfig({required this.id, required this.serverId, required this.name, this.localHost = 'localhost', required this.localPort, required this.remoteHost, required this.remotePort, this.description}): super._();
factory _PortForwardConfig.fromJson(Map<String, dynamic> json) => _$PortForwardConfigFromJson(json);
@override final String id;
@override final String serverId;
@override final String name;
@override@JsonKey() final String localHost;
@override final int localPort;
@override final String remoteHost;
@override final int remotePort;
@override final String? description;
/// Create a copy of PortForwardConfig
/// with the given fields replaced by the non-null parameter values.
@override @JsonKey(includeFromJson: false, includeToJson: false)
@pragma('vm:prefer-inline')
_$PortForwardConfigCopyWith<_PortForwardConfig> get copyWith => __$PortForwardConfigCopyWithImpl<_PortForwardConfig>(this, _$identity);
@override
Map<String, dynamic> toJson() {
return _$PortForwardConfigToJson(this, );
}
@override
bool operator ==(Object other) {
return identical(this, other) || (other.runtimeType == runtimeType&&other is _PortForwardConfig&&(identical(other.id, id) || other.id == id)&&(identical(other.serverId, serverId) || other.serverId == serverId)&&(identical(other.name, name) || other.name == name)&&(identical(other.localHost, localHost) || other.localHost == localHost)&&(identical(other.localPort, localPort) || other.localPort == localPort)&&(identical(other.remoteHost, remoteHost) || other.remoteHost == remoteHost)&&(identical(other.remotePort, remotePort) || other.remotePort == remotePort)&&(identical(other.description, description) || other.description == description));
}
@JsonKey(includeFromJson: false, includeToJson: false)
@override
int get hashCode => Object.hash(runtimeType,id,serverId,name,localHost,localPort,remoteHost,remotePort,description);
@override
String toString() {
return 'PortForwardConfig(id: $id, serverId: $serverId, name: $name, localHost: $localHost, localPort: $localPort, remoteHost: $remoteHost, remotePort: $remotePort, description: $description)';
}
}
/// @nodoc
abstract mixin class _$PortForwardConfigCopyWith<$Res> implements $PortForwardConfigCopyWith<$Res> {
factory _$PortForwardConfigCopyWith(_PortForwardConfig value, $Res Function(_PortForwardConfig) _then) = __$PortForwardConfigCopyWithImpl;
@override @useResult
$Res call({
String id, String serverId, String name, String localHost, int localPort, String remoteHost, int remotePort, String? description
});
}
/// @nodoc
class __$PortForwardConfigCopyWithImpl<$Res>
implements _$PortForwardConfigCopyWith<$Res> {
__$PortForwardConfigCopyWithImpl(this._self, this._then);
final _PortForwardConfig _self;
final $Res Function(_PortForwardConfig) _then;
/// Create a copy of PortForwardConfig
/// with the given fields replaced by the non-null parameter values.
@override @pragma('vm:prefer-inline') $Res call({Object? id = null,Object? serverId = null,Object? name = null,Object? localHost = null,Object? localPort = null,Object? remoteHost = null,Object? remotePort = null,Object? description = freezed,}) {
return _then(_PortForwardConfig(
id: null == id ? _self.id : id // ignore: cast_nullable_to_non_nullable
as String,serverId: null == serverId ? _self.serverId : serverId // ignore: cast_nullable_to_non_nullable
as String,name: null == name ? _self.name : name // ignore: cast_nullable_to_non_nullable
as String,localHost: null == localHost ? _self.localHost : localHost // ignore: cast_nullable_to_non_nullable
as String,localPort: null == localPort ? _self.localPort : localPort // ignore: cast_nullable_to_non_nullable
as int,remoteHost: null == remoteHost ? _self.remoteHost : remoteHost // ignore: cast_nullable_to_non_nullable
as String,remotePort: null == remotePort ? _self.remotePort : remotePort // ignore: cast_nullable_to_non_nullable
as int,description: freezed == description ? _self.description : description // ignore: cast_nullable_to_non_nullable
as String?,
));
}
}
/// @nodoc
mixin _$PortForwardState {
String get serverId; List<PortForwardConfig> get configs; Map<String, PortForwardStatus> get activeForwards;
/// Create a copy of PortForwardState
/// with the given fields replaced by the non-null parameter values.
@JsonKey(includeFromJson: false, includeToJson: false)
@pragma('vm:prefer-inline')
$PortForwardStateCopyWith<PortForwardState> get copyWith => _$PortForwardStateCopyWithImpl<PortForwardState>(this as PortForwardState, _$identity);
@override
bool operator ==(Object other) {
return identical(this, other) || (other.runtimeType == runtimeType&&other is PortForwardState&&(identical(other.serverId, serverId) || other.serverId == serverId)&&const DeepCollectionEquality().equals(other.configs, configs)&&const DeepCollectionEquality().equals(other.activeForwards, activeForwards));
}
@override
int get hashCode => Object.hash(runtimeType,serverId,const DeepCollectionEquality().hash(configs),const DeepCollectionEquality().hash(activeForwards));
@override
String toString() {
return 'PortForwardState(serverId: $serverId, configs: $configs, activeForwards: $activeForwards)';
}
}
/// @nodoc
abstract mixin class $PortForwardStateCopyWith<$Res> {
factory $PortForwardStateCopyWith(PortForwardState value, $Res Function(PortForwardState) _then) = _$PortForwardStateCopyWithImpl;
@useResult
$Res call({
String serverId, List<PortForwardConfig> configs, Map<String, PortForwardStatus> activeForwards
});
}
/// @nodoc
class _$PortForwardStateCopyWithImpl<$Res>
implements $PortForwardStateCopyWith<$Res> {
_$PortForwardStateCopyWithImpl(this._self, this._then);
final PortForwardState _self;
final $Res Function(PortForwardState) _then;
/// Create a copy of PortForwardState
/// with the given fields replaced by the non-null parameter values.
@pragma('vm:prefer-inline') @override $Res call({Object? serverId = null,Object? configs = null,Object? activeForwards = null,}) {
return _then(_self.copyWith(
serverId: null == serverId ? _self.serverId : serverId // ignore: cast_nullable_to_non_nullable
as String,configs: null == configs ? _self.configs : configs // ignore: cast_nullable_to_non_nullable
as List<PortForwardConfig>,activeForwards: null == activeForwards ? _self.activeForwards : activeForwards // ignore: cast_nullable_to_non_nullable
as Map<String, PortForwardStatus>,
));
}
}
/// Adds pattern-matching-related methods to [PortForwardState].
extension PortForwardStatePatterns on PortForwardState {
/// A variant of `map` that fallback to returning `orElse`.
///
/// It is equivalent to doing:
/// ```dart
/// switch (sealedClass) {
/// case final Subclass value:
/// return ...;
/// case _:
/// return orElse();
/// }
/// ```
@optionalTypeArgs TResult maybeMap<TResult extends Object?>(TResult Function( _PortForwardState value)? $default,{required TResult orElse(),}){
final _that = this;
switch (_that) {
case _PortForwardState() when $default != null:
return $default(_that);case _:
return orElse();
}
}
/// A `switch`-like method, using callbacks.
///
/// Callbacks receives the raw object, upcasted.
/// It is equivalent to doing:
/// ```dart
/// switch (sealedClass) {
/// case final Subclass value:
/// return ...;
/// case final Subclass2 value:
/// return ...;
/// }
/// ```
@optionalTypeArgs TResult map<TResult extends Object?>(TResult Function( _PortForwardState value) $default,){
final _that = this;
switch (_that) {
case _PortForwardState():
return $default(_that);case _:
throw StateError('Unexpected subclass');
}
}
/// A variant of `map` that fallback to returning `null`.
///
/// It is equivalent to doing:
/// ```dart
/// switch (sealedClass) {
/// case final Subclass value:
/// return ...;
/// case _:
/// return null;
/// }
/// ```
@optionalTypeArgs TResult? mapOrNull<TResult extends Object?>(TResult? Function( _PortForwardState value)? $default,){
final _that = this;
switch (_that) {
case _PortForwardState() when $default != null:
return $default(_that);case _:
return null;
}
}
/// A variant of `when` that fallback to an `orElse` callback.
///
/// It is equivalent to doing:
/// ```dart
/// switch (sealedClass) {
/// case Subclass(:final field):
/// return ...;
/// case _:
/// return orElse();
/// }
/// ```
@optionalTypeArgs TResult maybeWhen<TResult extends Object?>(TResult Function( String serverId, List<PortForwardConfig> configs, Map<String, PortForwardStatus> activeForwards)? $default,{required TResult orElse(),}) {final _that = this;
switch (_that) {
case _PortForwardState() when $default != null:
return $default(_that.serverId,_that.configs,_that.activeForwards);case _:
return orElse();
}
}
/// A `switch`-like method, using callbacks.
///
/// As opposed to `map`, this offers destructuring.
/// It is equivalent to doing:
/// ```dart
/// switch (sealedClass) {
/// case Subclass(:final field):
/// return ...;
/// case Subclass2(:final field2):
/// return ...;
/// }
/// ```
@optionalTypeArgs TResult when<TResult extends Object?>(TResult Function( String serverId, List<PortForwardConfig> configs, Map<String, PortForwardStatus> activeForwards) $default,) {final _that = this;
switch (_that) {
case _PortForwardState():
return $default(_that.serverId,_that.configs,_that.activeForwards);case _:
throw StateError('Unexpected subclass');
}
}
/// A variant of `when` that fallback to returning `null`
///
/// It is equivalent to doing:
/// ```dart
/// switch (sealedClass) {
/// case Subclass(:final field):
/// return ...;
/// case _:
/// return null;
/// }
/// ```
@optionalTypeArgs TResult? whenOrNull<TResult extends Object?>(TResult? Function( String serverId, List<PortForwardConfig> configs, Map<String, PortForwardStatus> activeForwards)? $default,) {final _that = this;
switch (_that) {
case _PortForwardState() when $default != null:
return $default(_that.serverId,_that.configs,_that.activeForwards);case _:
return null;
}
}
}
/// @nodoc
class _PortForwardState implements PortForwardState {
const _PortForwardState({required this.serverId, final List<PortForwardConfig> configs = const [], final Map<String, PortForwardStatus> activeForwards = const {}}): _configs = configs,_activeForwards = activeForwards;
@override final String serverId;
final List<PortForwardConfig> _configs;
@override@JsonKey() List<PortForwardConfig> get configs {
if (_configs is EqualUnmodifiableListView) return _configs;
// ignore: implicit_dynamic_type
return EqualUnmodifiableListView(_configs);
}
final Map<String, PortForwardStatus> _activeForwards;
@override@JsonKey() Map<String, PortForwardStatus> get activeForwards {
if (_activeForwards is EqualUnmodifiableMapView) return _activeForwards;
// ignore: implicit_dynamic_type
return EqualUnmodifiableMapView(_activeForwards);
}
/// Create a copy of PortForwardState
/// with the given fields replaced by the non-null parameter values.
@override @JsonKey(includeFromJson: false, includeToJson: false)
@pragma('vm:prefer-inline')
_$PortForwardStateCopyWith<_PortForwardState> get copyWith => __$PortForwardStateCopyWithImpl<_PortForwardState>(this, _$identity);
@override
bool operator ==(Object other) {
return identical(this, other) || (other.runtimeType == runtimeType&&other is _PortForwardState&&(identical(other.serverId, serverId) || other.serverId == serverId)&&const DeepCollectionEquality().equals(other._configs, _configs)&&const DeepCollectionEquality().equals(other._activeForwards, _activeForwards));
}
@override
int get hashCode => Object.hash(runtimeType,serverId,const DeepCollectionEquality().hash(_configs),const DeepCollectionEquality().hash(_activeForwards));
@override
String toString() {
return 'PortForwardState(serverId: $serverId, configs: $configs, activeForwards: $activeForwards)';
}
}
/// @nodoc
abstract mixin class _$PortForwardStateCopyWith<$Res> implements $PortForwardStateCopyWith<$Res> {
factory _$PortForwardStateCopyWith(_PortForwardState value, $Res Function(_PortForwardState) _then) = __$PortForwardStateCopyWithImpl;
@override @useResult
$Res call({
String serverId, List<PortForwardConfig> configs, Map<String, PortForwardStatus> activeForwards
});
}
/// @nodoc
class __$PortForwardStateCopyWithImpl<$Res>
implements _$PortForwardStateCopyWith<$Res> {
__$PortForwardStateCopyWithImpl(this._self, this._then);
final _PortForwardState _self;
final $Res Function(_PortForwardState) _then;
/// Create a copy of PortForwardState
/// with the given fields replaced by the non-null parameter values.
@override @pragma('vm:prefer-inline') $Res call({Object? serverId = null,Object? configs = null,Object? activeForwards = null,}) {
return _then(_PortForwardState(
serverId: null == serverId ? _self.serverId : serverId // ignore: cast_nullable_to_non_nullable
as String,configs: null == configs ? _self._configs : configs // ignore: cast_nullable_to_non_nullable
as List<PortForwardConfig>,activeForwards: null == activeForwards ? _self._activeForwards : activeForwards // ignore: cast_nullable_to_non_nullable
as Map<String, PortForwardStatus>,
));
}
}
// dart format on

View File

@@ -0,0 +1,31 @@
// GENERATED CODE - DO NOT MODIFY BY HAND
part of 'port_forward.dart';
// **************************************************************************
// JsonSerializableGenerator
// **************************************************************************
_PortForwardConfig _$PortForwardConfigFromJson(Map<String, dynamic> json) =>
_PortForwardConfig(
id: json['id'] as String,
serverId: json['serverId'] as String,
name: json['name'] as String,
localHost: json['localHost'] as String? ?? 'localhost',
localPort: (json['localPort'] as num).toInt(),
remoteHost: json['remoteHost'] as String,
remotePort: (json['remotePort'] as num).toInt(),
description: json['description'] as String?,
);
Map<String, dynamic> _$PortForwardConfigToJson(_PortForwardConfig instance) =>
<String, dynamic>{
'id': instance.id,
'serverId': instance.serverId,
'name': instance.name,
'localHost': instance.localHost,
'localPort': instance.localPort,
'remoteHost': instance.remoteHost,
'remotePort': instance.remotePort,
'description': instance.description,
};