feat: webrtc discovery (#2204)

This commit is contained in:
Tien Do Nam
2025-07-12 18:59:45 +02:00
committed by GitHub
parent ae2780638d
commit 0b332bdd61
171 changed files with 31552 additions and 1209 deletions
+3
View File
@@ -0,0 +1,3 @@
rust_input: crate::api
rust_root: rust/
dart_output: lib/rust
+11 -1
View File
@@ -1,4 +1,14 @@
{
"appPolicies" : {
"eula" : "",
"policies" : [
{
"locale" : "en_US",
"policyText" : "",
"policyURL" : ""
}
]
},
"identifier" : "D8FDEAE9",
"nonRenewingSubscriptions" : [
@@ -124,7 +134,7 @@
],
"version" : {
"major" : 3,
"major" : 4,
"minor" : 0
}
}
+6
View File
@@ -67,6 +67,8 @@ PODS:
- FlutterMacOS
- rhttp (0.0.1):
- Flutter
- rust_lib_localsend_app (0.0.1):
- Flutter
- SDWebImage (5.20.0):
- SDWebImage/Core (= 5.20.0)
- SDWebImage/Core (5.20.0)
@@ -111,6 +113,7 @@ DEPENDENCIES:
- permission_handler_apple (from `.symlinks/plugins/permission_handler_apple/ios`)
- photo_manager (from `.symlinks/plugins/photo_manager/ios`)
- rhttp (from `.symlinks/plugins/rhttp/ios`)
- rust_lib_localsend_app (from `.symlinks/plugins/rust_lib_localsend_app/ios`)
- share_handler_ios (from `.symlinks/plugins/share_handler_ios/ios`)
- share_handler_ios_models (from `.symlinks/plugins/share_handler_ios/ios/Models`)
- shared_preferences_foundation (from `.symlinks/plugins/shared_preferences_foundation/darwin`)
@@ -160,6 +163,8 @@ EXTERNAL SOURCES:
:path: ".symlinks/plugins/photo_manager/ios"
rhttp:
:path: ".symlinks/plugins/rhttp/ios"
rust_lib_localsend_app:
:path: ".symlinks/plugins/rust_lib_localsend_app/ios"
share_handler_ios:
:path: ".symlinks/plugins/share_handler_ios/ios"
share_handler_ios_models:
@@ -196,6 +201,7 @@ SPEC CHECKSUMS:
permission_handler_apple: 9878588469a2b0d0fc1e048d9f43605f92e6cec2
photo_manager: ff695c7a1dd5bc379974953a2b5c0a293f7c4c8a
rhttp: 367a8162e63311c6dde543169b591cc04454dcd6
rust_lib_localsend_app: 7613d2267cc6c941255182b0c88dac5f638f94ed
SDWebImage: 73c6079366fea25fa4bb9640d5fb58f0893facd8
share_handler_ios: 6dd3a4ac5ca0d955274aec712ba0ecdcaf583e7c
share_handler_ios_models: fc638c9b4330dc7f082586c92aee9dfa0b87b871
+15
View File
@@ -22,6 +22,7 @@ import 'package:localsend_app/provider/app_arguments_provider.dart';
import 'package:localsend_app/provider/device_info_provider.dart';
import 'package:localsend_app/provider/network/nearby_devices_provider.dart';
import 'package:localsend_app/provider/network/server/server_provider.dart';
import 'package:localsend_app/provider/network/webrtc/signaling_provider.dart';
import 'package:localsend_app/provider/persistence_provider.dart';
// [FOSS_REMOVE_START]
@@ -32,6 +33,8 @@ import 'package:localsend_app/provider/selection/selected_sending_files_provider
import 'package:localsend_app/provider/settings_provider.dart';
import 'package:localsend_app/provider/tv_provider.dart';
import 'package:localsend_app/provider/window_dimensions_provider.dart';
import 'package:localsend_app/rust/api/logging.dart' as rust_logging;
import 'package:localsend_app/rust/frb_generated.dart';
import 'package:localsend_app/util/i18n.dart';
import 'package:localsend_app/util/native/autostart_helper.dart';
import 'package:localsend_app/util/native/cache_helper.dart';
@@ -60,6 +63,16 @@ Future<RefenaContainer> preInit(List<String> args) async {
initLogger(args.contains('-v') || args.contains('--verbose') ? Level.ALL : Level.INFO);
MapperContainer.globals.use(const FileDtoMapper());
await RustLib.init();
if (kDebugMode) {
try {
await rust_logging.enableDebugLogging();
} catch (e) {
_logger.warning('Enabling debug logging failed', e);
}
}
await Rhttp.init();
final dynamicColors = await getDynamicColors();
@@ -206,6 +219,8 @@ Future<void> postInit(BuildContext context, Ref ref, bool appStart) async {
_logger.warning('Starting multicast listener failed', e);
}
ref.redux(signalingProvider).dispatch(SetupSignalingConnection());
if (appStart) {
if (defaultTargetPlatform == TargetPlatform.macOS) {
// handle dropped files
+9 -3
View File
@@ -1,7 +1,9 @@
import 'package:flutter/material.dart';
import 'package:localsend_app/util/native/platform_check.dart';
import 'package:localsend_app/util/native/tray_helper.dart';
import 'package:logging/logging.dart';
import 'package:package_info_plus/package_info_plus.dart';
import 'package:refena_flutter/refena_flutter.dart';
import 'package:window_manager/window_manager.dart';
final _logger = Logger('Init');
@@ -18,10 +20,14 @@ void showInitErrorApp({
await WindowManager.instance.show();
}
runApp(_ErrorApp(
error: error,
stackTrace: stackTrace,
runApp(RefenaScope(
child: _ErrorApp(
error: error,
stackTrace: stackTrace,
),
));
await showFromTray();
}
class _ErrorApp extends StatefulWidget {
+34 -15
View File
@@ -24,11 +24,13 @@ class CrossFileMapper extends ClassMapperBase<CrossFile> {
static String _$name(CrossFile v) => v.name;
static const Field<CrossFile, String> _f$name = Field('name', _$name);
static FileType _$fileType(CrossFile v) => v.fileType;
static const Field<CrossFile, FileType> _f$fileType = Field('fileType', _$fileType);
static const Field<CrossFile, FileType> _f$fileType =
Field('fileType', _$fileType);
static int _$size(CrossFile v) => v.size;
static const Field<CrossFile, int> _f$size = Field('size', _$size);
static Uint8List? _$thumbnail(CrossFile v) => v.thumbnail;
static const Field<CrossFile, Uint8List> _f$thumbnail = Field('thumbnail', _$thumbnail);
static const Field<CrossFile, Uint8List> _f$thumbnail =
Field('thumbnail', _$thumbnail);
static AssetEntity? _$asset(CrossFile v) => v.asset;
static const Field<CrossFile, AssetEntity> _f$asset = Field('asset', _$asset);
static String? _$path(CrossFile v) => v.path;
@@ -36,9 +38,11 @@ class CrossFileMapper extends ClassMapperBase<CrossFile> {
static List<int>? _$bytes(CrossFile v) => v.bytes;
static const Field<CrossFile, List<int>> _f$bytes = Field('bytes', _$bytes);
static DateTime? _$lastModified(CrossFile v) => v.lastModified;
static const Field<CrossFile, DateTime> _f$lastModified = Field('lastModified', _$lastModified);
static const Field<CrossFile, DateTime> _f$lastModified =
Field('lastModified', _$lastModified);
static DateTime? _$lastAccessed(CrossFile v) => v.lastAccessed;
static const Field<CrossFile, DateTime> _f$lastAccessed = Field('lastAccessed', _$lastAccessed);
static const Field<CrossFile, DateTime> _f$lastAccessed =
Field('lastAccessed', _$lastAccessed);
@override
final MappableFields<CrossFile> fields = const {
@@ -80,22 +84,27 @@ class CrossFileMapper extends ClassMapperBase<CrossFile> {
mixin CrossFileMappable {
String serialize() {
return CrossFileMapper.ensureInitialized().encodeJson<CrossFile>(this as CrossFile);
return CrossFileMapper.ensureInitialized()
.encodeJson<CrossFile>(this as CrossFile);
}
Map<String, dynamic> toJson() {
return CrossFileMapper.ensureInitialized().encodeMap<CrossFile>(this as CrossFile);
return CrossFileMapper.ensureInitialized()
.encodeMap<CrossFile>(this as CrossFile);
}
CrossFileCopyWith<CrossFile, CrossFile, CrossFile> get copyWith => _CrossFileCopyWithImpl(this as CrossFile, $identity, $identity);
CrossFileCopyWith<CrossFile, CrossFile, CrossFile> get copyWith =>
_CrossFileCopyWithImpl(this as CrossFile, $identity, $identity);
@override
String toString() {
return CrossFileMapper.ensureInitialized().stringifyValue(this as CrossFile);
return CrossFileMapper.ensureInitialized()
.stringifyValue(this as CrossFile);
}
@override
bool operator ==(Object other) {
return CrossFileMapper.ensureInitialized().equalsValue(this as CrossFile, other);
return CrossFileMapper.ensureInitialized()
.equalsValue(this as CrossFile, other);
}
@override
@@ -105,10 +114,12 @@ mixin CrossFileMappable {
}
extension CrossFileValueCopy<$R, $Out> on ObjectCopyWith<$R, CrossFile, $Out> {
CrossFileCopyWith<$R, CrossFile, $Out> get $asCrossFile => $base.as((v, t, t2) => _CrossFileCopyWithImpl(v, t, t2));
CrossFileCopyWith<$R, CrossFile, $Out> get $asCrossFile =>
$base.as((v, t, t2) => _CrossFileCopyWithImpl(v, t, t2));
}
abstract class CrossFileCopyWith<$R, $In extends CrossFile, $Out> implements ClassCopyWith<$R, $In, $Out> {
abstract class CrossFileCopyWith<$R, $In extends CrossFile, $Out>
implements ClassCopyWith<$R, $In, $Out> {
ListCopyWith<$R, int, ObjectCopyWith<$R, int, int>>? get bytes;
$R call(
{String? name,
@@ -123,14 +134,20 @@ abstract class CrossFileCopyWith<$R, $In extends CrossFile, $Out> implements Cla
CrossFileCopyWith<$R2, $In, $Out2> $chain<$R2, $Out2>(Then<$Out2, $R2> t);
}
class _CrossFileCopyWithImpl<$R, $Out> extends ClassCopyWithBase<$R, CrossFile, $Out> implements CrossFileCopyWith<$R, CrossFile, $Out> {
class _CrossFileCopyWithImpl<$R, $Out>
extends ClassCopyWithBase<$R, CrossFile, $Out>
implements CrossFileCopyWith<$R, CrossFile, $Out> {
_CrossFileCopyWithImpl(super.value, super.then, super.then2);
@override
late final ClassMapperBase<CrossFile> $mapper = CrossFileMapper.ensureInitialized();
late final ClassMapperBase<CrossFile> $mapper =
CrossFileMapper.ensureInitialized();
@override
ListCopyWith<$R, int, ObjectCopyWith<$R, int, int>>? get bytes =>
$value.bytes != null ? ListCopyWith($value.bytes!, (v, t) => ObjectCopyWith(v, $identity, t), (v) => call(bytes: v)) : null;
$value.bytes != null
? ListCopyWith($value.bytes!,
(v, t) => ObjectCopyWith(v, $identity, t), (v) => call(bytes: v))
: null;
@override
$R call(
{String? name,
@@ -166,5 +183,7 @@ class _CrossFileCopyWithImpl<$R, $Out> extends ClassCopyWithBase<$R, CrossFile,
lastAccessed: data.get(#lastAccessed, or: $value.lastAccessed));
@override
CrossFileCopyWith<$R2, CrossFile, $Out2> $chain<$R2, $Out2>(Then<$Out2, $R2> t) => _CrossFileCopyWithImpl($value, $cast, t);
CrossFileCopyWith<$R2, CrossFile, $Out2> $chain<$R2, $Out2>(
Then<$Out2, $R2> t) =>
_CrossFileCopyWithImpl($value, $cast, t);
}
+29 -13
View File
@@ -21,7 +21,8 @@ class LogEntryMapper extends ClassMapperBase<LogEntry> {
final String id = 'LogEntry';
static DateTime _$timestamp(LogEntry v) => v.timestamp;
static const Field<LogEntry, DateTime> _f$timestamp = Field('timestamp', _$timestamp);
static const Field<LogEntry, DateTime> _f$timestamp =
Field('timestamp', _$timestamp);
static String _$log(LogEntry v) => v.log;
static const Field<LogEntry, String> _f$log = Field('log', _$log);
@@ -49,14 +50,17 @@ class LogEntryMapper extends ClassMapperBase<LogEntry> {
mixin LogEntryMappable {
String serialize() {
return LogEntryMapper.ensureInitialized().encodeJson<LogEntry>(this as LogEntry);
return LogEntryMapper.ensureInitialized()
.encodeJson<LogEntry>(this as LogEntry);
}
Map<String, dynamic> toJson() {
return LogEntryMapper.ensureInitialized().encodeMap<LogEntry>(this as LogEntry);
return LogEntryMapper.ensureInitialized()
.encodeMap<LogEntry>(this as LogEntry);
}
LogEntryCopyWith<LogEntry, LogEntry, LogEntry> get copyWith => _LogEntryCopyWithImpl(this as LogEntry, $identity, $identity);
LogEntryCopyWith<LogEntry, LogEntry, LogEntry> get copyWith =>
_LogEntryCopyWithImpl(this as LogEntry, $identity, $identity);
@override
String toString() {
return LogEntryMapper.ensureInitialized().stringifyValue(this as LogEntry);
@@ -64,7 +68,8 @@ mixin LogEntryMappable {
@override
bool operator ==(Object other) {
return LogEntryMapper.ensureInitialized().equalsValue(this as LogEntry, other);
return LogEntryMapper.ensureInitialized()
.equalsValue(this as LogEntry, other);
}
@override
@@ -74,25 +79,36 @@ mixin LogEntryMappable {
}
extension LogEntryValueCopy<$R, $Out> on ObjectCopyWith<$R, LogEntry, $Out> {
LogEntryCopyWith<$R, LogEntry, $Out> get $asLogEntry => $base.as((v, t, t2) => _LogEntryCopyWithImpl(v, t, t2));
LogEntryCopyWith<$R, LogEntry, $Out> get $asLogEntry =>
$base.as((v, t, t2) => _LogEntryCopyWithImpl(v, t, t2));
}
abstract class LogEntryCopyWith<$R, $In extends LogEntry, $Out> implements ClassCopyWith<$R, $In, $Out> {
abstract class LogEntryCopyWith<$R, $In extends LogEntry, $Out>
implements ClassCopyWith<$R, $In, $Out> {
$R call({DateTime? timestamp, String? log});
LogEntryCopyWith<$R2, $In, $Out2> $chain<$R2, $Out2>(Then<$Out2, $R2> t);
}
class _LogEntryCopyWithImpl<$R, $Out> extends ClassCopyWithBase<$R, LogEntry, $Out> implements LogEntryCopyWith<$R, LogEntry, $Out> {
class _LogEntryCopyWithImpl<$R, $Out>
extends ClassCopyWithBase<$R, LogEntry, $Out>
implements LogEntryCopyWith<$R, LogEntry, $Out> {
_LogEntryCopyWithImpl(super.value, super.then, super.then2);
@override
late final ClassMapperBase<LogEntry> $mapper = LogEntryMapper.ensureInitialized();
late final ClassMapperBase<LogEntry> $mapper =
LogEntryMapper.ensureInitialized();
@override
$R call({DateTime? timestamp, String? log}) =>
$apply(FieldCopyWithData({if (timestamp != null) #timestamp: timestamp, if (log != null) #log: log}));
$R call({DateTime? timestamp, String? log}) => $apply(FieldCopyWithData({
if (timestamp != null) #timestamp: timestamp,
if (log != null) #log: log
}));
@override
LogEntry $make(CopyWithData data) => LogEntry(timestamp: data.get(#timestamp, or: $value.timestamp), log: data.get(#log, or: $value.log));
LogEntry $make(CopyWithData data) => LogEntry(
timestamp: data.get(#timestamp, or: $value.timestamp),
log: data.get(#log, or: $value.log));
@override
LogEntryCopyWith<$R2, LogEntry, $Out2> $chain<$R2, $Out2>(Then<$Out2, $R2> t) => _LogEntryCopyWithImpl($value, $cast, t);
LogEntryCopyWith<$R2, LogEntry, $Out2> $chain<$R2, $Out2>(
Then<$Out2, $R2> t) =>
_LogEntryCopyWithImpl($value, $cast, t);
}
@@ -23,7 +23,8 @@ class FavoriteDeviceMapper extends ClassMapperBase<FavoriteDevice> {
static String _$id(FavoriteDevice v) => v.id;
static const Field<FavoriteDevice, String> _f$id = Field('id', _$id);
static String _$fingerprint(FavoriteDevice v) => v.fingerprint;
static const Field<FavoriteDevice, String> _f$fingerprint = Field('fingerprint', _$fingerprint);
static const Field<FavoriteDevice, String> _f$fingerprint =
Field('fingerprint', _$fingerprint);
static String _$ip(FavoriteDevice v) => v.ip;
static const Field<FavoriteDevice, String> _f$ip = Field('ip', _$ip);
static int _$port(FavoriteDevice v) => v.port;
@@ -31,7 +32,8 @@ class FavoriteDeviceMapper extends ClassMapperBase<FavoriteDevice> {
static String _$alias(FavoriteDevice v) => v.alias;
static const Field<FavoriteDevice, String> _f$alias = Field('alias', _$alias);
static bool _$customAlias(FavoriteDevice v) => v.customAlias;
static const Field<FavoriteDevice, bool> _f$customAlias = Field('customAlias', _$customAlias, opt: true, def: false);
static const Field<FavoriteDevice, bool> _f$customAlias =
Field('customAlias', _$customAlias, opt: true, def: false);
@override
final MappableFields<FavoriteDevice> fields = const {
@@ -67,48 +69,73 @@ class FavoriteDeviceMapper extends ClassMapperBase<FavoriteDevice> {
mixin FavoriteDeviceMappable {
String serialize() {
return FavoriteDeviceMapper.ensureInitialized().encodeJson<FavoriteDevice>(this as FavoriteDevice);
return FavoriteDeviceMapper.ensureInitialized()
.encodeJson<FavoriteDevice>(this as FavoriteDevice);
}
Map<String, dynamic> toJson() {
return FavoriteDeviceMapper.ensureInitialized().encodeMap<FavoriteDevice>(this as FavoriteDevice);
return FavoriteDeviceMapper.ensureInitialized()
.encodeMap<FavoriteDevice>(this as FavoriteDevice);
}
FavoriteDeviceCopyWith<FavoriteDevice, FavoriteDevice, FavoriteDevice> get copyWith =>
_FavoriteDeviceCopyWithImpl(this as FavoriteDevice, $identity, $identity);
FavoriteDeviceCopyWith<FavoriteDevice, FavoriteDevice, FavoriteDevice>
get copyWith => _FavoriteDeviceCopyWithImpl(
this as FavoriteDevice, $identity, $identity);
@override
String toString() {
return FavoriteDeviceMapper.ensureInitialized().stringifyValue(this as FavoriteDevice);
return FavoriteDeviceMapper.ensureInitialized()
.stringifyValue(this as FavoriteDevice);
}
@override
bool operator ==(Object other) {
return FavoriteDeviceMapper.ensureInitialized().equalsValue(this as FavoriteDevice, other);
return FavoriteDeviceMapper.ensureInitialized()
.equalsValue(this as FavoriteDevice, other);
}
@override
int get hashCode {
return FavoriteDeviceMapper.ensureInitialized().hashValue(this as FavoriteDevice);
return FavoriteDeviceMapper.ensureInitialized()
.hashValue(this as FavoriteDevice);
}
}
extension FavoriteDeviceValueCopy<$R, $Out> on ObjectCopyWith<$R, FavoriteDevice, $Out> {
FavoriteDeviceCopyWith<$R, FavoriteDevice, $Out> get $asFavoriteDevice => $base.as((v, t, t2) => _FavoriteDeviceCopyWithImpl(v, t, t2));
extension FavoriteDeviceValueCopy<$R, $Out>
on ObjectCopyWith<$R, FavoriteDevice, $Out> {
FavoriteDeviceCopyWith<$R, FavoriteDevice, $Out> get $asFavoriteDevice =>
$base.as((v, t, t2) => _FavoriteDeviceCopyWithImpl(v, t, t2));
}
abstract class FavoriteDeviceCopyWith<$R, $In extends FavoriteDevice, $Out> implements ClassCopyWith<$R, $In, $Out> {
$R call({String? id, String? fingerprint, String? ip, int? port, String? alias, bool? customAlias});
FavoriteDeviceCopyWith<$R2, $In, $Out2> $chain<$R2, $Out2>(Then<$Out2, $R2> t);
abstract class FavoriteDeviceCopyWith<$R, $In extends FavoriteDevice, $Out>
implements ClassCopyWith<$R, $In, $Out> {
$R call(
{String? id,
String? fingerprint,
String? ip,
int? port,
String? alias,
bool? customAlias});
FavoriteDeviceCopyWith<$R2, $In, $Out2> $chain<$R2, $Out2>(
Then<$Out2, $R2> t);
}
class _FavoriteDeviceCopyWithImpl<$R, $Out> extends ClassCopyWithBase<$R, FavoriteDevice, $Out>
class _FavoriteDeviceCopyWithImpl<$R, $Out>
extends ClassCopyWithBase<$R, FavoriteDevice, $Out>
implements FavoriteDeviceCopyWith<$R, FavoriteDevice, $Out> {
_FavoriteDeviceCopyWithImpl(super.value, super.then, super.then2);
@override
late final ClassMapperBase<FavoriteDevice> $mapper = FavoriteDeviceMapper.ensureInitialized();
late final ClassMapperBase<FavoriteDevice> $mapper =
FavoriteDeviceMapper.ensureInitialized();
@override
$R call({String? id, String? fingerprint, String? ip, int? port, String? alias, bool? customAlias}) => $apply(FieldCopyWithData({
$R call(
{String? id,
String? fingerprint,
String? ip,
int? port,
String? alias,
bool? customAlias}) =>
$apply(FieldCopyWithData({
if (id != null) #id: id,
if (fingerprint != null) #fingerprint: fingerprint,
if (ip != null) #ip: ip,
@@ -126,5 +153,7 @@ class _FavoriteDeviceCopyWithImpl<$R, $Out> extends ClassCopyWithBase<$R, Favori
customAlias: data.get(#customAlias, or: $value.customAlias));
@override
FavoriteDeviceCopyWith<$R2, FavoriteDevice, $Out2> $chain<$R2, $Out2>(Then<$Out2, $R2> t) => _FavoriteDeviceCopyWithImpl($value, $cast, t);
FavoriteDeviceCopyWith<$R2, FavoriteDevice, $Out2> $chain<$R2, $Out2>(
Then<$Out2, $R2> t) =>
_FavoriteDeviceCopyWithImpl($value, $cast, t);
}
@@ -24,21 +24,29 @@ class ReceiveHistoryEntryMapper extends ClassMapperBase<ReceiveHistoryEntry> {
static String _$id(ReceiveHistoryEntry v) => v.id;
static const Field<ReceiveHistoryEntry, String> _f$id = Field('id', _$id);
static String _$fileName(ReceiveHistoryEntry v) => v.fileName;
static const Field<ReceiveHistoryEntry, String> _f$fileName = Field('fileName', _$fileName);
static const Field<ReceiveHistoryEntry, String> _f$fileName =
Field('fileName', _$fileName);
static FileType _$fileType(ReceiveHistoryEntry v) => v.fileType;
static const Field<ReceiveHistoryEntry, FileType> _f$fileType = Field('fileType', _$fileType);
static const Field<ReceiveHistoryEntry, FileType> _f$fileType =
Field('fileType', _$fileType);
static String? _$path(ReceiveHistoryEntry v) => v.path;
static const Field<ReceiveHistoryEntry, String> _f$path = Field('path', _$path);
static const Field<ReceiveHistoryEntry, String> _f$path =
Field('path', _$path);
static bool _$savedToGallery(ReceiveHistoryEntry v) => v.savedToGallery;
static const Field<ReceiveHistoryEntry, bool> _f$savedToGallery = Field('savedToGallery', _$savedToGallery);
static const Field<ReceiveHistoryEntry, bool> _f$savedToGallery =
Field('savedToGallery', _$savedToGallery);
static bool _$isMessage(ReceiveHistoryEntry v) => v.isMessage;
static const Field<ReceiveHistoryEntry, bool> _f$isMessage = Field('isMessage', _$isMessage, hook: IsMessageHook());
static const Field<ReceiveHistoryEntry, bool> _f$isMessage =
Field('isMessage', _$isMessage, hook: IsMessageHook());
static int _$fileSize(ReceiveHistoryEntry v) => v.fileSize;
static const Field<ReceiveHistoryEntry, int> _f$fileSize = Field('fileSize', _$fileSize);
static const Field<ReceiveHistoryEntry, int> _f$fileSize =
Field('fileSize', _$fileSize);
static String _$senderAlias(ReceiveHistoryEntry v) => v.senderAlias;
static const Field<ReceiveHistoryEntry, String> _f$senderAlias = Field('senderAlias', _$senderAlias);
static const Field<ReceiveHistoryEntry, String> _f$senderAlias =
Field('senderAlias', _$senderAlias);
static DateTime _$timestamp(ReceiveHistoryEntry v) => v.timestamp;
static const Field<ReceiveHistoryEntry, DateTime> _f$timestamp = Field('timestamp', _$timestamp);
static const Field<ReceiveHistoryEntry, DateTime> _f$timestamp =
Field('timestamp', _$timestamp);
@override
final MappableFields<ReceiveHistoryEntry> fields = const {
@@ -80,37 +88,47 @@ class ReceiveHistoryEntryMapper extends ClassMapperBase<ReceiveHistoryEntry> {
mixin ReceiveHistoryEntryMappable {
String serialize() {
return ReceiveHistoryEntryMapper.ensureInitialized().encodeJson<ReceiveHistoryEntry>(this as ReceiveHistoryEntry);
return ReceiveHistoryEntryMapper.ensureInitialized()
.encodeJson<ReceiveHistoryEntry>(this as ReceiveHistoryEntry);
}
Map<String, dynamic> toJson() {
return ReceiveHistoryEntryMapper.ensureInitialized().encodeMap<ReceiveHistoryEntry>(this as ReceiveHistoryEntry);
return ReceiveHistoryEntryMapper.ensureInitialized()
.encodeMap<ReceiveHistoryEntry>(this as ReceiveHistoryEntry);
}
ReceiveHistoryEntryCopyWith<ReceiveHistoryEntry, ReceiveHistoryEntry, ReceiveHistoryEntry> get copyWith =>
_ReceiveHistoryEntryCopyWithImpl(this as ReceiveHistoryEntry, $identity, $identity);
ReceiveHistoryEntryCopyWith<ReceiveHistoryEntry, ReceiveHistoryEntry,
ReceiveHistoryEntry>
get copyWith => _ReceiveHistoryEntryCopyWithImpl(
this as ReceiveHistoryEntry, $identity, $identity);
@override
String toString() {
return ReceiveHistoryEntryMapper.ensureInitialized().stringifyValue(this as ReceiveHistoryEntry);
return ReceiveHistoryEntryMapper.ensureInitialized()
.stringifyValue(this as ReceiveHistoryEntry);
}
@override
bool operator ==(Object other) {
return ReceiveHistoryEntryMapper.ensureInitialized().equalsValue(this as ReceiveHistoryEntry, other);
return ReceiveHistoryEntryMapper.ensureInitialized()
.equalsValue(this as ReceiveHistoryEntry, other);
}
@override
int get hashCode {
return ReceiveHistoryEntryMapper.ensureInitialized().hashValue(this as ReceiveHistoryEntry);
return ReceiveHistoryEntryMapper.ensureInitialized()
.hashValue(this as ReceiveHistoryEntry);
}
}
extension ReceiveHistoryEntryValueCopy<$R, $Out> on ObjectCopyWith<$R, ReceiveHistoryEntry, $Out> {
ReceiveHistoryEntryCopyWith<$R, ReceiveHistoryEntry, $Out> get $asReceiveHistoryEntry =>
$base.as((v, t, t2) => _ReceiveHistoryEntryCopyWithImpl(v, t, t2));
extension ReceiveHistoryEntryValueCopy<$R, $Out>
on ObjectCopyWith<$R, ReceiveHistoryEntry, $Out> {
ReceiveHistoryEntryCopyWith<$R, ReceiveHistoryEntry, $Out>
get $asReceiveHistoryEntry =>
$base.as((v, t, t2) => _ReceiveHistoryEntryCopyWithImpl(v, t, t2));
}
abstract class ReceiveHistoryEntryCopyWith<$R, $In extends ReceiveHistoryEntry, $Out> implements ClassCopyWith<$R, $In, $Out> {
abstract class ReceiveHistoryEntryCopyWith<$R, $In extends ReceiveHistoryEntry,
$Out> implements ClassCopyWith<$R, $In, $Out> {
$R call(
{String? id,
String? fileName,
@@ -121,15 +139,18 @@ abstract class ReceiveHistoryEntryCopyWith<$R, $In extends ReceiveHistoryEntry,
int? fileSize,
String? senderAlias,
DateTime? timestamp});
ReceiveHistoryEntryCopyWith<$R2, $In, $Out2> $chain<$R2, $Out2>(Then<$Out2, $R2> t);
ReceiveHistoryEntryCopyWith<$R2, $In, $Out2> $chain<$R2, $Out2>(
Then<$Out2, $R2> t);
}
class _ReceiveHistoryEntryCopyWithImpl<$R, $Out> extends ClassCopyWithBase<$R, ReceiveHistoryEntry, $Out>
class _ReceiveHistoryEntryCopyWithImpl<$R, $Out>
extends ClassCopyWithBase<$R, ReceiveHistoryEntry, $Out>
implements ReceiveHistoryEntryCopyWith<$R, ReceiveHistoryEntry, $Out> {
_ReceiveHistoryEntryCopyWithImpl(super.value, super.then, super.then2);
@override
late final ClassMapperBase<ReceiveHistoryEntry> $mapper = ReceiveHistoryEntryMapper.ensureInitialized();
late final ClassMapperBase<ReceiveHistoryEntry> $mapper =
ReceiveHistoryEntryMapper.ensureInitialized();
@override
$R call(
{String? id,
@@ -165,6 +186,7 @@ class _ReceiveHistoryEntryCopyWithImpl<$R, $Out> extends ClassCopyWithBase<$R, R
timestamp: data.get(#timestamp, or: $value.timestamp));
@override
ReceiveHistoryEntryCopyWith<$R2, ReceiveHistoryEntry, $Out2> $chain<$R2, $Out2>(Then<$Out2, $R2> t) =>
_ReceiveHistoryEntryCopyWithImpl($value, $cast, t);
ReceiveHistoryEntryCopyWith<$R2, ReceiveHistoryEntry, $Out2>
$chain<$R2, $Out2>(Then<$Out2, $R2> t) =>
_ReceiveHistoryEntryCopyWithImpl($value, $cast, t);
}
@@ -9,9 +9,52 @@ class NearbyDevicesState with NearbyDevicesStateMappable {
final Set<String> runningIps; // list of local ips
final Map<String, Device> devices; // ip -> device
/// Devices that are discovered via signaling server.
/// The key is the fingerprint of the device.
/// We do not trust the fingerprint, so we allow multiple devices with the same fingerprint.
final Map<String, Set<Device>> signalingDevices;
const NearbyDevicesState({
required this.runningFavoriteScan,
required this.runningIps,
required this.devices,
required this.signalingDevices,
});
Map<String, Device> get allDevices {
final Map<String, Device> allDevices = {};
allDevices.addAll(devices);
for (final devices in signalingDevices.values) {
for (final device in devices) {
final currentDevice = allDevices[device.fingerprint];
if (currentDevice != null && currentDevice.alias == device.alias) {
allDevices[device.fingerprint] = currentDevice.merge(device);
} else {
allDevices[device.fingerprint] = device;
}
}
}
return allDevices;
}
}
extension on Device {
Device merge(Device other) {
return Device(
signalingId: signalingId ?? other.signalingId,
ip: ip ?? other.ip,
version: version,
port: port,
https: https,
fingerprint: fingerprint,
alias: alias,
deviceModel: deviceModel,
deviceType: deviceType,
download: download,
discoveryMethods: {
...discoveryMethods,
...other.discoveryMethods,
},
);
}
}
@@ -21,23 +21,35 @@ class NearbyDevicesStateMapper extends ClassMapperBase<NearbyDevicesState> {
@override
final String id = 'NearbyDevicesState';
static bool _$runningFavoriteScan(NearbyDevicesState v) => v.runningFavoriteScan;
static const Field<NearbyDevicesState, bool> _f$runningFavoriteScan = Field('runningFavoriteScan', _$runningFavoriteScan);
static bool _$runningFavoriteScan(NearbyDevicesState v) =>
v.runningFavoriteScan;
static const Field<NearbyDevicesState, bool> _f$runningFavoriteScan =
Field('runningFavoriteScan', _$runningFavoriteScan);
static Set<String> _$runningIps(NearbyDevicesState v) => v.runningIps;
static const Field<NearbyDevicesState, Set<String>> _f$runningIps = Field('runningIps', _$runningIps);
static const Field<NearbyDevicesState, Set<String>> _f$runningIps =
Field('runningIps', _$runningIps);
static Map<String, Device> _$devices(NearbyDevicesState v) => v.devices;
static const Field<NearbyDevicesState, Map<String, Device>> _f$devices = Field('devices', _$devices);
static const Field<NearbyDevicesState, Map<String, Device>> _f$devices =
Field('devices', _$devices);
static Map<String, Set<Device>> _$signalingDevices(NearbyDevicesState v) =>
v.signalingDevices;
static const Field<NearbyDevicesState, Map<String, Set<Device>>>
_f$signalingDevices = Field('signalingDevices', _$signalingDevices);
@override
final MappableFields<NearbyDevicesState> fields = const {
#runningFavoriteScan: _f$runningFavoriteScan,
#runningIps: _f$runningIps,
#devices: _f$devices,
#signalingDevices: _f$signalingDevices,
};
static NearbyDevicesState _instantiate(DecodingData data) {
return NearbyDevicesState(
runningFavoriteScan: data.dec(_f$runningFavoriteScan), runningIps: data.dec(_f$runningIps), devices: data.dec(_f$devices));
runningFavoriteScan: data.dec(_f$runningFavoriteScan),
runningIps: data.dec(_f$runningIps),
devices: data.dec(_f$devices),
signalingDevices: data.dec(_f$signalingDevices));
}
@override
@@ -54,64 +66,103 @@ class NearbyDevicesStateMapper extends ClassMapperBase<NearbyDevicesState> {
mixin NearbyDevicesStateMappable {
String serialize() {
return NearbyDevicesStateMapper.ensureInitialized().encodeJson<NearbyDevicesState>(this as NearbyDevicesState);
return NearbyDevicesStateMapper.ensureInitialized()
.encodeJson<NearbyDevicesState>(this as NearbyDevicesState);
}
Map<String, dynamic> toJson() {
return NearbyDevicesStateMapper.ensureInitialized().encodeMap<NearbyDevicesState>(this as NearbyDevicesState);
return NearbyDevicesStateMapper.ensureInitialized()
.encodeMap<NearbyDevicesState>(this as NearbyDevicesState);
}
NearbyDevicesStateCopyWith<NearbyDevicesState, NearbyDevicesState, NearbyDevicesState> get copyWith =>
_NearbyDevicesStateCopyWithImpl(this as NearbyDevicesState, $identity, $identity);
NearbyDevicesStateCopyWith<NearbyDevicesState, NearbyDevicesState,
NearbyDevicesState>
get copyWith => _NearbyDevicesStateCopyWithImpl(
this as NearbyDevicesState, $identity, $identity);
@override
String toString() {
return NearbyDevicesStateMapper.ensureInitialized().stringifyValue(this as NearbyDevicesState);
return NearbyDevicesStateMapper.ensureInitialized()
.stringifyValue(this as NearbyDevicesState);
}
@override
bool operator ==(Object other) {
return NearbyDevicesStateMapper.ensureInitialized().equalsValue(this as NearbyDevicesState, other);
return NearbyDevicesStateMapper.ensureInitialized()
.equalsValue(this as NearbyDevicesState, other);
}
@override
int get hashCode {
return NearbyDevicesStateMapper.ensureInitialized().hashValue(this as NearbyDevicesState);
return NearbyDevicesStateMapper.ensureInitialized()
.hashValue(this as NearbyDevicesState);
}
}
extension NearbyDevicesStateValueCopy<$R, $Out> on ObjectCopyWith<$R, NearbyDevicesState, $Out> {
NearbyDevicesStateCopyWith<$R, NearbyDevicesState, $Out> get $asNearbyDevicesState =>
$base.as((v, t, t2) => _NearbyDevicesStateCopyWithImpl(v, t, t2));
extension NearbyDevicesStateValueCopy<$R, $Out>
on ObjectCopyWith<$R, NearbyDevicesState, $Out> {
NearbyDevicesStateCopyWith<$R, NearbyDevicesState, $Out>
get $asNearbyDevicesState =>
$base.as((v, t, t2) => _NearbyDevicesStateCopyWithImpl(v, t, t2));
}
abstract class NearbyDevicesStateCopyWith<$R, $In extends NearbyDevicesState, $Out> implements ClassCopyWith<$R, $In, $Out> {
MapCopyWith<$R, String, Device, DeviceCopyWith<$R, Device, Device>> get devices;
$R call({bool? runningFavoriteScan, Set<String>? runningIps, Map<String, Device>? devices});
NearbyDevicesStateCopyWith<$R2, $In, $Out2> $chain<$R2, $Out2>(Then<$Out2, $R2> t);
abstract class NearbyDevicesStateCopyWith<$R, $In extends NearbyDevicesState,
$Out> implements ClassCopyWith<$R, $In, $Out> {
MapCopyWith<$R, String, Device, DeviceCopyWith<$R, Device, Device>>
get devices;
MapCopyWith<$R, String, Set<Device>,
ObjectCopyWith<$R, Set<Device>, Set<Device>>> get signalingDevices;
$R call(
{bool? runningFavoriteScan,
Set<String>? runningIps,
Map<String, Device>? devices,
Map<String, Set<Device>>? signalingDevices});
NearbyDevicesStateCopyWith<$R2, $In, $Out2> $chain<$R2, $Out2>(
Then<$Out2, $R2> t);
}
class _NearbyDevicesStateCopyWithImpl<$R, $Out> extends ClassCopyWithBase<$R, NearbyDevicesState, $Out>
class _NearbyDevicesStateCopyWithImpl<$R, $Out>
extends ClassCopyWithBase<$R, NearbyDevicesState, $Out>
implements NearbyDevicesStateCopyWith<$R, NearbyDevicesState, $Out> {
_NearbyDevicesStateCopyWithImpl(super.value, super.then, super.then2);
@override
late final ClassMapperBase<NearbyDevicesState> $mapper = NearbyDevicesStateMapper.ensureInitialized();
late final ClassMapperBase<NearbyDevicesState> $mapper =
NearbyDevicesStateMapper.ensureInitialized();
@override
MapCopyWith<$R, String, Device, DeviceCopyWith<$R, Device, Device>> get devices =>
MapCopyWith($value.devices, (v, t) => v.copyWith.$chain(t), (v) => call(devices: v));
MapCopyWith<$R, String, Device, DeviceCopyWith<$R, Device, Device>>
get devices => MapCopyWith($value.devices, (v, t) => v.copyWith.$chain(t),
(v) => call(devices: v));
@override
$R call({bool? runningFavoriteScan, Set<String>? runningIps, Map<String, Device>? devices}) => $apply(FieldCopyWithData({
if (runningFavoriteScan != null) #runningFavoriteScan: runningFavoriteScan,
MapCopyWith<$R, String, Set<Device>,
ObjectCopyWith<$R, Set<Device>, Set<Device>>>
get signalingDevices => MapCopyWith(
$value.signalingDevices,
(v, t) => ObjectCopyWith(v, $identity, t),
(v) => call(signalingDevices: v));
@override
$R call(
{bool? runningFavoriteScan,
Set<String>? runningIps,
Map<String, Device>? devices,
Map<String, Set<Device>>? signalingDevices}) =>
$apply(FieldCopyWithData({
if (runningFavoriteScan != null)
#runningFavoriteScan: runningFavoriteScan,
if (runningIps != null) #runningIps: runningIps,
if (devices != null) #devices: devices
if (devices != null) #devices: devices,
if (signalingDevices != null) #signalingDevices: signalingDevices
}));
@override
NearbyDevicesState $make(CopyWithData data) => NearbyDevicesState(
runningFavoriteScan: data.get(#runningFavoriteScan, or: $value.runningFavoriteScan),
runningFavoriteScan:
data.get(#runningFavoriteScan, or: $value.runningFavoriteScan),
runningIps: data.get(#runningIps, or: $value.runningIps),
devices: data.get(#devices, or: $value.devices));
devices: data.get(#devices, or: $value.devices),
signalingDevices:
data.get(#signalingDevices, or: $value.signalingDevices));
@override
NearbyDevicesStateCopyWith<$R2, NearbyDevicesState, $Out2> $chain<$R2, $Out2>(Then<$Out2, $R2> t) =>
NearbyDevicesStateCopyWith<$R2, NearbyDevicesState, $Out2> $chain<$R2, $Out2>(
Then<$Out2, $R2> t) =>
_NearbyDevicesStateCopyWithImpl($value, $cast, t);
}
+39 -18
View File
@@ -21,9 +21,11 @@ class NetworkStateMapper extends ClassMapperBase<NetworkState> {
final String id = 'NetworkState';
static List<String> _$localIps(NetworkState v) => v.localIps;
static const Field<NetworkState, List<String>> _f$localIps = Field('localIps', _$localIps);
static const Field<NetworkState, List<String>> _f$localIps =
Field('localIps', _$localIps);
static bool _$initialized(NetworkState v) => v.initialized;
static const Field<NetworkState, bool> _f$initialized = Field('initialized', _$initialized);
static const Field<NetworkState, bool> _f$initialized =
Field('initialized', _$initialized);
@override
final MappableFields<NetworkState> fields = const {
@@ -32,7 +34,8 @@ class NetworkStateMapper extends ClassMapperBase<NetworkState> {
};
static NetworkState _instantiate(DecodingData data) {
return NetworkState(localIps: data.dec(_f$localIps), initialized: data.dec(_f$initialized));
return NetworkState(
localIps: data.dec(_f$localIps), initialized: data.dec(_f$initialized));
}
@override
@@ -49,56 +52,74 @@ class NetworkStateMapper extends ClassMapperBase<NetworkState> {
mixin NetworkStateMappable {
String serialize() {
return NetworkStateMapper.ensureInitialized().encodeJson<NetworkState>(this as NetworkState);
return NetworkStateMapper.ensureInitialized()
.encodeJson<NetworkState>(this as NetworkState);
}
Map<String, dynamic> toJson() {
return NetworkStateMapper.ensureInitialized().encodeMap<NetworkState>(this as NetworkState);
return NetworkStateMapper.ensureInitialized()
.encodeMap<NetworkState>(this as NetworkState);
}
NetworkStateCopyWith<NetworkState, NetworkState, NetworkState> get copyWith =>
_NetworkStateCopyWithImpl(this as NetworkState, $identity, $identity);
@override
String toString() {
return NetworkStateMapper.ensureInitialized().stringifyValue(this as NetworkState);
return NetworkStateMapper.ensureInitialized()
.stringifyValue(this as NetworkState);
}
@override
bool operator ==(Object other) {
return NetworkStateMapper.ensureInitialized().equalsValue(this as NetworkState, other);
return NetworkStateMapper.ensureInitialized()
.equalsValue(this as NetworkState, other);
}
@override
int get hashCode {
return NetworkStateMapper.ensureInitialized().hashValue(this as NetworkState);
return NetworkStateMapper.ensureInitialized()
.hashValue(this as NetworkState);
}
}
extension NetworkStateValueCopy<$R, $Out> on ObjectCopyWith<$R, NetworkState, $Out> {
NetworkStateCopyWith<$R, NetworkState, $Out> get $asNetworkState => $base.as((v, t, t2) => _NetworkStateCopyWithImpl(v, t, t2));
extension NetworkStateValueCopy<$R, $Out>
on ObjectCopyWith<$R, NetworkState, $Out> {
NetworkStateCopyWith<$R, NetworkState, $Out> get $asNetworkState =>
$base.as((v, t, t2) => _NetworkStateCopyWithImpl(v, t, t2));
}
abstract class NetworkStateCopyWith<$R, $In extends NetworkState, $Out> implements ClassCopyWith<$R, $In, $Out> {
abstract class NetworkStateCopyWith<$R, $In extends NetworkState, $Out>
implements ClassCopyWith<$R, $In, $Out> {
ListCopyWith<$R, String, ObjectCopyWith<$R, String, String>> get localIps;
$R call({List<String>? localIps, bool? initialized});
NetworkStateCopyWith<$R2, $In, $Out2> $chain<$R2, $Out2>(Then<$Out2, $R2> t);
}
class _NetworkStateCopyWithImpl<$R, $Out> extends ClassCopyWithBase<$R, NetworkState, $Out> implements NetworkStateCopyWith<$R, NetworkState, $Out> {
class _NetworkStateCopyWithImpl<$R, $Out>
extends ClassCopyWithBase<$R, NetworkState, $Out>
implements NetworkStateCopyWith<$R, NetworkState, $Out> {
_NetworkStateCopyWithImpl(super.value, super.then, super.then2);
@override
late final ClassMapperBase<NetworkState> $mapper = NetworkStateMapper.ensureInitialized();
late final ClassMapperBase<NetworkState> $mapper =
NetworkStateMapper.ensureInitialized();
@override
ListCopyWith<$R, String, ObjectCopyWith<$R, String, String>> get localIps =>
ListCopyWith($value.localIps, (v, t) => ObjectCopyWith(v, $identity, t), (v) => call(localIps: v));
ListCopyWith($value.localIps, (v, t) => ObjectCopyWith(v, $identity, t),
(v) => call(localIps: v));
@override
$R call({List<String>? localIps, bool? initialized}) =>
$apply(FieldCopyWithData({if (localIps != null) #localIps: localIps, if (initialized != null) #initialized: initialized}));
$apply(FieldCopyWithData({
if (localIps != null) #localIps: localIps,
if (initialized != null) #initialized: initialized
}));
@override
NetworkState $make(CopyWithData data) =>
NetworkState(localIps: data.get(#localIps, or: $value.localIps), initialized: data.get(#initialized, or: $value.initialized));
NetworkState $make(CopyWithData data) => NetworkState(
localIps: data.get(#localIps, or: $value.localIps),
initialized: data.get(#initialized, or: $value.initialized));
@override
NetworkStateCopyWith<$R2, NetworkState, $Out2> $chain<$R2, $Out2>(Then<$Out2, $R2> t) => _NetworkStateCopyWithImpl($value, $cast, t);
NetworkStateCopyWith<$R2, NetworkState, $Out2> $chain<$R2, $Out2>(
Then<$Out2, $R2> t) =>
_NetworkStateCopyWithImpl($value, $cast, t);
}
+54 -23
View File
@@ -21,11 +21,14 @@ class PurchaseStateMapper extends ClassMapperBase<PurchaseState> {
final String id = 'PurchaseState';
static Map<PurchaseItem, String> _$prices(PurchaseState v) => v.prices;
static const Field<PurchaseState, Map<PurchaseItem, String>> _f$prices = Field('prices', _$prices);
static const Field<PurchaseState, Map<PurchaseItem, String>> _f$prices =
Field('prices', _$prices);
static Set<PurchaseItem> _$purchases(PurchaseState v) => v.purchases;
static const Field<PurchaseState, Set<PurchaseItem>> _f$purchases = Field('purchases', _$purchases);
static const Field<PurchaseState, Set<PurchaseItem>> _f$purchases =
Field('purchases', _$purchases);
static bool _$pending(PurchaseState v) => v.pending;
static const Field<PurchaseState, bool> _f$pending = Field('pending', _$pending);
static const Field<PurchaseState, bool> _f$pending =
Field('pending', _$pending);
@override
final MappableFields<PurchaseState> fields = const {
@@ -35,7 +38,10 @@ class PurchaseStateMapper extends ClassMapperBase<PurchaseState> {
};
static PurchaseState _instantiate(DecodingData data) {
return PurchaseState(prices: data.dec(_f$prices), purchases: data.dec(_f$purchases), pending: data.dec(_f$pending));
return PurchaseState(
prices: data.dec(_f$prices),
purchases: data.dec(_f$purchases),
pending: data.dec(_f$pending));
}
@override
@@ -52,53 +58,76 @@ class PurchaseStateMapper extends ClassMapperBase<PurchaseState> {
mixin PurchaseStateMappable {
String serialize() {
return PurchaseStateMapper.ensureInitialized().encodeJson<PurchaseState>(this as PurchaseState);
return PurchaseStateMapper.ensureInitialized()
.encodeJson<PurchaseState>(this as PurchaseState);
}
Map<String, dynamic> toJson() {
return PurchaseStateMapper.ensureInitialized().encodeMap<PurchaseState>(this as PurchaseState);
return PurchaseStateMapper.ensureInitialized()
.encodeMap<PurchaseState>(this as PurchaseState);
}
PurchaseStateCopyWith<PurchaseState, PurchaseState, PurchaseState> get copyWith =>
_PurchaseStateCopyWithImpl(this as PurchaseState, $identity, $identity);
PurchaseStateCopyWith<PurchaseState, PurchaseState, PurchaseState>
get copyWith => _PurchaseStateCopyWithImpl(
this as PurchaseState, $identity, $identity);
@override
String toString() {
return PurchaseStateMapper.ensureInitialized().stringifyValue(this as PurchaseState);
return PurchaseStateMapper.ensureInitialized()
.stringifyValue(this as PurchaseState);
}
@override
bool operator ==(Object other) {
return PurchaseStateMapper.ensureInitialized().equalsValue(this as PurchaseState, other);
return PurchaseStateMapper.ensureInitialized()
.equalsValue(this as PurchaseState, other);
}
@override
int get hashCode {
return PurchaseStateMapper.ensureInitialized().hashValue(this as PurchaseState);
return PurchaseStateMapper.ensureInitialized()
.hashValue(this as PurchaseState);
}
}
extension PurchaseStateValueCopy<$R, $Out> on ObjectCopyWith<$R, PurchaseState, $Out> {
PurchaseStateCopyWith<$R, PurchaseState, $Out> get $asPurchaseState => $base.as((v, t, t2) => _PurchaseStateCopyWithImpl(v, t, t2));
extension PurchaseStateValueCopy<$R, $Out>
on ObjectCopyWith<$R, PurchaseState, $Out> {
PurchaseStateCopyWith<$R, PurchaseState, $Out> get $asPurchaseState =>
$base.as((v, t, t2) => _PurchaseStateCopyWithImpl(v, t, t2));
}
abstract class PurchaseStateCopyWith<$R, $In extends PurchaseState, $Out> implements ClassCopyWith<$R, $In, $Out> {
MapCopyWith<$R, PurchaseItem, String, ObjectCopyWith<$R, String, String>> get prices;
$R call({Map<PurchaseItem, String>? prices, Set<PurchaseItem>? purchases, bool? pending});
abstract class PurchaseStateCopyWith<$R, $In extends PurchaseState, $Out>
implements ClassCopyWith<$R, $In, $Out> {
MapCopyWith<$R, PurchaseItem, String, ObjectCopyWith<$R, String, String>>
get prices;
$R call(
{Map<PurchaseItem, String>? prices,
Set<PurchaseItem>? purchases,
bool? pending});
PurchaseStateCopyWith<$R2, $In, $Out2> $chain<$R2, $Out2>(Then<$Out2, $R2> t);
}
class _PurchaseStateCopyWithImpl<$R, $Out> extends ClassCopyWithBase<$R, PurchaseState, $Out>
class _PurchaseStateCopyWithImpl<$R, $Out>
extends ClassCopyWithBase<$R, PurchaseState, $Out>
implements PurchaseStateCopyWith<$R, PurchaseState, $Out> {
_PurchaseStateCopyWithImpl(super.value, super.then, super.then2);
@override
late final ClassMapperBase<PurchaseState> $mapper = PurchaseStateMapper.ensureInitialized();
late final ClassMapperBase<PurchaseState> $mapper =
PurchaseStateMapper.ensureInitialized();
@override
MapCopyWith<$R, PurchaseItem, String, ObjectCopyWith<$R, String, String>> get prices =>
MapCopyWith($value.prices, (v, t) => ObjectCopyWith(v, $identity, t), (v) => call(prices: v));
MapCopyWith<$R, PurchaseItem, String, ObjectCopyWith<$R, String, String>>
get prices => MapCopyWith($value.prices,
(v, t) => ObjectCopyWith(v, $identity, t), (v) => call(prices: v));
@override
$R call({Map<PurchaseItem, String>? prices, Set<PurchaseItem>? purchases, bool? pending}) => $apply(
FieldCopyWithData({if (prices != null) #prices: prices, if (purchases != null) #purchases: purchases, if (pending != null) #pending: pending}));
$R call(
{Map<PurchaseItem, String>? prices,
Set<PurchaseItem>? purchases,
bool? pending}) =>
$apply(FieldCopyWithData({
if (prices != null) #prices: prices,
if (purchases != null) #purchases: purchases,
if (pending != null) #pending: pending
}));
@override
PurchaseState $make(CopyWithData data) => PurchaseState(
prices: data.get(#prices, or: $value.prices),
@@ -106,5 +135,7 @@ class _PurchaseStateCopyWithImpl<$R, $Out> extends ClassCopyWithBase<$R, Purchas
pending: data.get(#pending, or: $value.pending));
@override
PurchaseStateCopyWith<$R2, PurchaseState, $Out2> $chain<$R2, $Out2>(Then<$Out2, $R2> t) => _PurchaseStateCopyWithImpl($value, $cast, t);
PurchaseStateCopyWith<$R2, PurchaseState, $Out2> $chain<$R2, $Out2>(
Then<$Out2, $R2> t) =>
_PurchaseStateCopyWithImpl($value, $cast, t);
}
@@ -2,19 +2,28 @@ import 'package:common/model/device.dart';
import 'package:common/model/session_status.dart';
import 'package:dart_mappable/dart_mappable.dart';
import 'package:localsend_app/model/state/send/sending_file.dart';
import 'package:localsend_app/model/state/server/receive_session_state.dart';
part 'send_session_state.mapper.dart';
@MappableClass()
class SendSessionState with SendSessionStateMappable {
class SendSessionState with SendSessionStateMappable implements SessionState {
final String sessionId;
final String? remoteSessionId; // v2
final bool background;
@override
final SessionStatus status;
final Device target;
final Map<String, SendingFile> files; // file id as key
@override
final int? startTime;
@override
final int? endTime;
final List<SendingTask>? sendingTasks; // used to cancel tasks
final String? errorMessage;
@@ -23,25 +23,36 @@ class SendSessionStateMapper extends ClassMapperBase<SendSessionState> {
final String id = 'SendSessionState';
static String _$sessionId(SendSessionState v) => v.sessionId;
static const Field<SendSessionState, String> _f$sessionId = Field('sessionId', _$sessionId);
static const Field<SendSessionState, String> _f$sessionId =
Field('sessionId', _$sessionId);
static String? _$remoteSessionId(SendSessionState v) => v.remoteSessionId;
static const Field<SendSessionState, String> _f$remoteSessionId = Field('remoteSessionId', _$remoteSessionId);
static const Field<SendSessionState, String> _f$remoteSessionId =
Field('remoteSessionId', _$remoteSessionId);
static bool _$background(SendSessionState v) => v.background;
static const Field<SendSessionState, bool> _f$background = Field('background', _$background);
static const Field<SendSessionState, bool> _f$background =
Field('background', _$background);
static SessionStatus _$status(SendSessionState v) => v.status;
static const Field<SendSessionState, SessionStatus> _f$status = Field('status', _$status);
static const Field<SendSessionState, SessionStatus> _f$status =
Field('status', _$status);
static Device _$target(SendSessionState v) => v.target;
static const Field<SendSessionState, Device> _f$target = Field('target', _$target);
static const Field<SendSessionState, Device> _f$target =
Field('target', _$target);
static Map<String, SendingFile> _$files(SendSessionState v) => v.files;
static const Field<SendSessionState, Map<String, SendingFile>> _f$files = Field('files', _$files);
static const Field<SendSessionState, Map<String, SendingFile>> _f$files =
Field('files', _$files);
static int? _$startTime(SendSessionState v) => v.startTime;
static const Field<SendSessionState, int> _f$startTime = Field('startTime', _$startTime);
static const Field<SendSessionState, int> _f$startTime =
Field('startTime', _$startTime);
static int? _$endTime(SendSessionState v) => v.endTime;
static const Field<SendSessionState, int> _f$endTime = Field('endTime', _$endTime);
static List<SendingTask>? _$sendingTasks(SendSessionState v) => v.sendingTasks;
static const Field<SendSessionState, List<SendingTask>> _f$sendingTasks = Field('sendingTasks', _$sendingTasks);
static const Field<SendSessionState, int> _f$endTime =
Field('endTime', _$endTime);
static List<SendingTask>? _$sendingTasks(SendSessionState v) =>
v.sendingTasks;
static const Field<SendSessionState, List<SendingTask>> _f$sendingTasks =
Field('sendingTasks', _$sendingTasks);
static String? _$errorMessage(SendSessionState v) => v.errorMessage;
static const Field<SendSessionState, String> _f$errorMessage = Field('errorMessage', _$errorMessage);
static const Field<SendSessionState, String> _f$errorMessage =
Field('errorMessage', _$errorMessage);
@override
final MappableFields<SendSessionState> fields = const {
@@ -85,39 +96,51 @@ class SendSessionStateMapper extends ClassMapperBase<SendSessionState> {
mixin SendSessionStateMappable {
String serialize() {
return SendSessionStateMapper.ensureInitialized().encodeJson<SendSessionState>(this as SendSessionState);
return SendSessionStateMapper.ensureInitialized()
.encodeJson<SendSessionState>(this as SendSessionState);
}
Map<String, dynamic> toJson() {
return SendSessionStateMapper.ensureInitialized().encodeMap<SendSessionState>(this as SendSessionState);
return SendSessionStateMapper.ensureInitialized()
.encodeMap<SendSessionState>(this as SendSessionState);
}
SendSessionStateCopyWith<SendSessionState, SendSessionState, SendSessionState> get copyWith =>
_SendSessionStateCopyWithImpl(this as SendSessionState, $identity, $identity);
SendSessionStateCopyWith<SendSessionState, SendSessionState, SendSessionState>
get copyWith => _SendSessionStateCopyWithImpl(
this as SendSessionState, $identity, $identity);
@override
String toString() {
return SendSessionStateMapper.ensureInitialized().stringifyValue(this as SendSessionState);
return SendSessionStateMapper.ensureInitialized()
.stringifyValue(this as SendSessionState);
}
@override
bool operator ==(Object other) {
return SendSessionStateMapper.ensureInitialized().equalsValue(this as SendSessionState, other);
return SendSessionStateMapper.ensureInitialized()
.equalsValue(this as SendSessionState, other);
}
@override
int get hashCode {
return SendSessionStateMapper.ensureInitialized().hashValue(this as SendSessionState);
return SendSessionStateMapper.ensureInitialized()
.hashValue(this as SendSessionState);
}
}
extension SendSessionStateValueCopy<$R, $Out> on ObjectCopyWith<$R, SendSessionState, $Out> {
SendSessionStateCopyWith<$R, SendSessionState, $Out> get $asSendSessionState => $base.as((v, t, t2) => _SendSessionStateCopyWithImpl(v, t, t2));
extension SendSessionStateValueCopy<$R, $Out>
on ObjectCopyWith<$R, SendSessionState, $Out> {
SendSessionStateCopyWith<$R, SendSessionState, $Out>
get $asSendSessionState =>
$base.as((v, t, t2) => _SendSessionStateCopyWithImpl(v, t, t2));
}
abstract class SendSessionStateCopyWith<$R, $In extends SendSessionState, $Out> implements ClassCopyWith<$R, $In, $Out> {
abstract class SendSessionStateCopyWith<$R, $In extends SendSessionState, $Out>
implements ClassCopyWith<$R, $In, $Out> {
DeviceCopyWith<$R, Device, Device> get target;
MapCopyWith<$R, String, SendingFile, SendingFileCopyWith<$R, SendingFile, SendingFile>> get files;
ListCopyWith<$R, SendingTask, ObjectCopyWith<$R, SendingTask, SendingTask>>? get sendingTasks;
MapCopyWith<$R, String, SendingFile,
SendingFileCopyWith<$R, SendingFile, SendingFile>> get files;
ListCopyWith<$R, SendingTask, ObjectCopyWith<$R, SendingTask, SendingTask>>?
get sendingTasks;
$R call(
{String? sessionId,
String? remoteSessionId,
@@ -129,24 +152,34 @@ abstract class SendSessionStateCopyWith<$R, $In extends SendSessionState, $Out>
int? endTime,
List<SendingTask>? sendingTasks,
String? errorMessage});
SendSessionStateCopyWith<$R2, $In, $Out2> $chain<$R2, $Out2>(Then<$Out2, $R2> t);
SendSessionStateCopyWith<$R2, $In, $Out2> $chain<$R2, $Out2>(
Then<$Out2, $R2> t);
}
class _SendSessionStateCopyWithImpl<$R, $Out> extends ClassCopyWithBase<$R, SendSessionState, $Out>
class _SendSessionStateCopyWithImpl<$R, $Out>
extends ClassCopyWithBase<$R, SendSessionState, $Out>
implements SendSessionStateCopyWith<$R, SendSessionState, $Out> {
_SendSessionStateCopyWithImpl(super.value, super.then, super.then2);
@override
late final ClassMapperBase<SendSessionState> $mapper = SendSessionStateMapper.ensureInitialized();
late final ClassMapperBase<SendSessionState> $mapper =
SendSessionStateMapper.ensureInitialized();
@override
DeviceCopyWith<$R, Device, Device> get target => $value.target.copyWith.$chain((v) => call(target: v));
DeviceCopyWith<$R, Device, Device> get target =>
$value.target.copyWith.$chain((v) => call(target: v));
@override
MapCopyWith<$R, String, SendingFile, SendingFileCopyWith<$R, SendingFile, SendingFile>> get files =>
MapCopyWith($value.files, (v, t) => v.copyWith.$chain(t), (v) => call(files: v));
MapCopyWith<$R, String, SendingFile,
SendingFileCopyWith<$R, SendingFile, SendingFile>>
get files => MapCopyWith(
$value.files, (v, t) => v.copyWith.$chain(t), (v) => call(files: v));
@override
ListCopyWith<$R, SendingTask, ObjectCopyWith<$R, SendingTask, SendingTask>>? get sendingTasks => $value.sendingTasks != null
? ListCopyWith($value.sendingTasks!, (v, t) => ObjectCopyWith(v, $identity, t), (v) => call(sendingTasks: v))
: null;
ListCopyWith<$R, SendingTask, ObjectCopyWith<$R, SendingTask, SendingTask>>?
get sendingTasks => $value.sendingTasks != null
? ListCopyWith(
$value.sendingTasks!,
(v, t) => ObjectCopyWith(v, $identity, t),
(v) => call(sendingTasks: v))
: null;
@override
$R call(
{String? sessionId,
@@ -185,5 +218,7 @@ class _SendSessionStateCopyWithImpl<$R, $Out> extends ClassCopyWithBase<$R, Send
errorMessage: data.get(#errorMessage, or: $value.errorMessage));
@override
SendSessionStateCopyWith<$R2, SendSessionState, $Out2> $chain<$R2, $Out2>(Then<$Out2, $R2> t) => _SendSessionStateCopyWithImpl($value, $cast, t);
SendSessionStateCopyWith<$R2, SendSessionState, $Out2> $chain<$R2, $Out2>(
Then<$Out2, $R2> t) =>
_SendSessionStateCopyWithImpl($value, $cast, t);
}
@@ -23,19 +23,23 @@ class SendingFileMapper extends ClassMapperBase<SendingFile> {
static FileDto _$file(SendingFile v) => v.file;
static const Field<SendingFile, FileDto> _f$file = Field('file', _$file);
static FileStatus _$status(SendingFile v) => v.status;
static const Field<SendingFile, FileStatus> _f$status = Field('status', _$status);
static const Field<SendingFile, FileStatus> _f$status =
Field('status', _$status);
static String? _$token(SendingFile v) => v.token;
static const Field<SendingFile, String> _f$token = Field('token', _$token);
static Uint8List? _$thumbnail(SendingFile v) => v.thumbnail;
static const Field<SendingFile, Uint8List> _f$thumbnail = Field('thumbnail', _$thumbnail);
static const Field<SendingFile, Uint8List> _f$thumbnail =
Field('thumbnail', _$thumbnail);
static AssetEntity? _$asset(SendingFile v) => v.asset;
static const Field<SendingFile, AssetEntity> _f$asset = Field('asset', _$asset);
static const Field<SendingFile, AssetEntity> _f$asset =
Field('asset', _$asset);
static String? _$path(SendingFile v) => v.path;
static const Field<SendingFile, String> _f$path = Field('path', _$path);
static List<int>? _$bytes(SendingFile v) => v.bytes;
static const Field<SendingFile, List<int>> _f$bytes = Field('bytes', _$bytes);
static String? _$errorMessage(SendingFile v) => v.errorMessage;
static const Field<SendingFile, String> _f$errorMessage = Field('errorMessage', _$errorMessage);
static const Field<SendingFile, String> _f$errorMessage =
Field('errorMessage', _$errorMessage);
@override
final MappableFields<SendingFile> fields = const {
@@ -75,22 +79,27 @@ class SendingFileMapper extends ClassMapperBase<SendingFile> {
mixin SendingFileMappable {
String serialize() {
return SendingFileMapper.ensureInitialized().encodeJson<SendingFile>(this as SendingFile);
return SendingFileMapper.ensureInitialized()
.encodeJson<SendingFile>(this as SendingFile);
}
Map<String, dynamic> toJson() {
return SendingFileMapper.ensureInitialized().encodeMap<SendingFile>(this as SendingFile);
return SendingFileMapper.ensureInitialized()
.encodeMap<SendingFile>(this as SendingFile);
}
SendingFileCopyWith<SendingFile, SendingFile, SendingFile> get copyWith => _SendingFileCopyWithImpl(this as SendingFile, $identity, $identity);
SendingFileCopyWith<SendingFile, SendingFile, SendingFile> get copyWith =>
_SendingFileCopyWithImpl(this as SendingFile, $identity, $identity);
@override
String toString() {
return SendingFileMapper.ensureInitialized().stringifyValue(this as SendingFile);
return SendingFileMapper.ensureInitialized()
.stringifyValue(this as SendingFile);
}
@override
bool operator ==(Object other) {
return SendingFileMapper.ensureInitialized().equalsValue(this as SendingFile, other);
return SendingFileMapper.ensureInitialized()
.equalsValue(this as SendingFile, other);
}
@override
@@ -99,11 +108,14 @@ mixin SendingFileMappable {
}
}
extension SendingFileValueCopy<$R, $Out> on ObjectCopyWith<$R, SendingFile, $Out> {
SendingFileCopyWith<$R, SendingFile, $Out> get $asSendingFile => $base.as((v, t, t2) => _SendingFileCopyWithImpl(v, t, t2));
extension SendingFileValueCopy<$R, $Out>
on ObjectCopyWith<$R, SendingFile, $Out> {
SendingFileCopyWith<$R, SendingFile, $Out> get $asSendingFile =>
$base.as((v, t, t2) => _SendingFileCopyWithImpl(v, t, t2));
}
abstract class SendingFileCopyWith<$R, $In extends SendingFile, $Out> implements ClassCopyWith<$R, $In, $Out> {
abstract class SendingFileCopyWith<$R, $In extends SendingFile, $Out>
implements ClassCopyWith<$R, $In, $Out> {
ListCopyWith<$R, int, ObjectCopyWith<$R, int, int>>? get bytes;
$R call(
{FileDto? file,
@@ -117,14 +129,20 @@ abstract class SendingFileCopyWith<$R, $In extends SendingFile, $Out> implements
SendingFileCopyWith<$R2, $In, $Out2> $chain<$R2, $Out2>(Then<$Out2, $R2> t);
}
class _SendingFileCopyWithImpl<$R, $Out> extends ClassCopyWithBase<$R, SendingFile, $Out> implements SendingFileCopyWith<$R, SendingFile, $Out> {
class _SendingFileCopyWithImpl<$R, $Out>
extends ClassCopyWithBase<$R, SendingFile, $Out>
implements SendingFileCopyWith<$R, SendingFile, $Out> {
_SendingFileCopyWithImpl(super.value, super.then, super.then2);
@override
late final ClassMapperBase<SendingFile> $mapper = SendingFileMapper.ensureInitialized();
late final ClassMapperBase<SendingFile> $mapper =
SendingFileMapper.ensureInitialized();
@override
ListCopyWith<$R, int, ObjectCopyWith<$R, int, int>>? get bytes =>
$value.bytes != null ? ListCopyWith($value.bytes!, (v, t) => ObjectCopyWith(v, $identity, t), (v) => call(bytes: v)) : null;
$value.bytes != null
? ListCopyWith($value.bytes!,
(v, t) => ObjectCopyWith(v, $identity, t), (v) => call(bytes: v))
: null;
@override
$R call(
{FileDto? file,
@@ -157,5 +175,7 @@ class _SendingFileCopyWithImpl<$R, $Out> extends ClassCopyWithBase<$R, SendingFi
errorMessage: data.get(#errorMessage, or: $value.errorMessage));
@override
SendingFileCopyWith<$R2, SendingFile, $Out2> $chain<$R2, $Out2>(Then<$Out2, $R2> t) => _SendingFileCopyWithImpl($value, $cast, t);
SendingFileCopyWith<$R2, SendingFile, $Out2> $chain<$R2, $Out2>(
Then<$Out2, $R2> t) =>
_SendingFileCopyWithImpl($value, $cast, t);
}
@@ -23,7 +23,8 @@ class WebSendFileMapper extends ClassMapperBase<WebSendFile> {
static FileDto _$file(WebSendFile v) => v.file;
static const Field<WebSendFile, FileDto> _f$file = Field('file', _$file);
static AssetEntity? _$asset(WebSendFile v) => v.asset;
static const Field<WebSendFile, AssetEntity> _f$asset = Field('asset', _$asset);
static const Field<WebSendFile, AssetEntity> _f$asset =
Field('asset', _$asset);
static String? _$path(WebSendFile v) => v.path;
static const Field<WebSendFile, String> _f$path = Field('path', _$path);
static List<int>? _$bytes(WebSendFile v) => v.bytes;
@@ -38,7 +39,11 @@ class WebSendFileMapper extends ClassMapperBase<WebSendFile> {
};
static WebSendFile _instantiate(DecodingData data) {
return WebSendFile(file: data.dec(_f$file), asset: data.dec(_f$asset), path: data.dec(_f$path), bytes: data.dec(_f$bytes));
return WebSendFile(
file: data.dec(_f$file),
asset: data.dec(_f$asset),
path: data.dec(_f$path),
bytes: data.dec(_f$bytes));
}
@override
@@ -55,22 +60,27 @@ class WebSendFileMapper extends ClassMapperBase<WebSendFile> {
mixin WebSendFileMappable {
String serialize() {
return WebSendFileMapper.ensureInitialized().encodeJson<WebSendFile>(this as WebSendFile);
return WebSendFileMapper.ensureInitialized()
.encodeJson<WebSendFile>(this as WebSendFile);
}
Map<String, dynamic> toJson() {
return WebSendFileMapper.ensureInitialized().encodeMap<WebSendFile>(this as WebSendFile);
return WebSendFileMapper.ensureInitialized()
.encodeMap<WebSendFile>(this as WebSendFile);
}
WebSendFileCopyWith<WebSendFile, WebSendFile, WebSendFile> get copyWith => _WebSendFileCopyWithImpl(this as WebSendFile, $identity, $identity);
WebSendFileCopyWith<WebSendFile, WebSendFile, WebSendFile> get copyWith =>
_WebSendFileCopyWithImpl(this as WebSendFile, $identity, $identity);
@override
String toString() {
return WebSendFileMapper.ensureInitialized().stringifyValue(this as WebSendFile);
return WebSendFileMapper.ensureInitialized()
.stringifyValue(this as WebSendFile);
}
@override
bool operator ==(Object other) {
return WebSendFileMapper.ensureInitialized().equalsValue(this as WebSendFile, other);
return WebSendFileMapper.ensureInitialized()
.equalsValue(this as WebSendFile, other);
}
@override
@@ -79,27 +89,45 @@ mixin WebSendFileMappable {
}
}
extension WebSendFileValueCopy<$R, $Out> on ObjectCopyWith<$R, WebSendFile, $Out> {
WebSendFileCopyWith<$R, WebSendFile, $Out> get $asWebSendFile => $base.as((v, t, t2) => _WebSendFileCopyWithImpl(v, t, t2));
extension WebSendFileValueCopy<$R, $Out>
on ObjectCopyWith<$R, WebSendFile, $Out> {
WebSendFileCopyWith<$R, WebSendFile, $Out> get $asWebSendFile =>
$base.as((v, t, t2) => _WebSendFileCopyWithImpl(v, t, t2));
}
abstract class WebSendFileCopyWith<$R, $In extends WebSendFile, $Out> implements ClassCopyWith<$R, $In, $Out> {
abstract class WebSendFileCopyWith<$R, $In extends WebSendFile, $Out>
implements ClassCopyWith<$R, $In, $Out> {
ListCopyWith<$R, int, ObjectCopyWith<$R, int, int>>? get bytes;
$R call({FileDto? file, AssetEntity? asset, String? path, List<int>? bytes});
WebSendFileCopyWith<$R2, $In, $Out2> $chain<$R2, $Out2>(Then<$Out2, $R2> t);
}
class _WebSendFileCopyWithImpl<$R, $Out> extends ClassCopyWithBase<$R, WebSendFile, $Out> implements WebSendFileCopyWith<$R, WebSendFile, $Out> {
class _WebSendFileCopyWithImpl<$R, $Out>
extends ClassCopyWithBase<$R, WebSendFile, $Out>
implements WebSendFileCopyWith<$R, WebSendFile, $Out> {
_WebSendFileCopyWithImpl(super.value, super.then, super.then2);
@override
late final ClassMapperBase<WebSendFile> $mapper = WebSendFileMapper.ensureInitialized();
late final ClassMapperBase<WebSendFile> $mapper =
WebSendFileMapper.ensureInitialized();
@override
ListCopyWith<$R, int, ObjectCopyWith<$R, int, int>>? get bytes =>
$value.bytes != null ? ListCopyWith($value.bytes!, (v, t) => ObjectCopyWith(v, $identity, t), (v) => call(bytes: v)) : null;
$value.bytes != null
? ListCopyWith($value.bytes!,
(v, t) => ObjectCopyWith(v, $identity, t), (v) => call(bytes: v))
: null;
@override
$R call({FileDto? file, Object? asset = $none, Object? path = $none, Object? bytes = $none}) => $apply(FieldCopyWithData(
{if (file != null) #file: file, if (asset != $none) #asset: asset, if (path != $none) #path: path, if (bytes != $none) #bytes: bytes}));
$R call(
{FileDto? file,
Object? asset = $none,
Object? path = $none,
Object? bytes = $none}) =>
$apply(FieldCopyWithData({
if (file != null) #file: file,
if (asset != $none) #asset: asset,
if (path != $none) #path: path,
if (bytes != $none) #bytes: bytes
}));
@override
WebSendFile $make(CopyWithData data) => WebSendFile(
file: data.get(#file, or: $value.file),
@@ -108,5 +136,7 @@ class _WebSendFileCopyWithImpl<$R, $Out> extends ClassCopyWithBase<$R, WebSendFi
bytes: data.get(#bytes, or: $value.bytes));
@override
WebSendFileCopyWith<$R2, WebSendFile, $Out2> $chain<$R2, $Out2>(Then<$Out2, $R2> t) => _WebSendFileCopyWithImpl($value, $cast, t);
WebSendFileCopyWith<$R2, WebSendFile, $Out2> $chain<$R2, $Out2>(
Then<$Out2, $R2> t) =>
_WebSendFileCopyWithImpl($value, $cast, t);
}
@@ -21,13 +21,17 @@ class WebSendSessionMapper extends ClassMapperBase<WebSendSession> {
final String id = 'WebSendSession';
static String _$sessionId(WebSendSession v) => v.sessionId;
static const Field<WebSendSession, String> _f$sessionId = Field('sessionId', _$sessionId);
static StreamController<bool>? _$responseHandler(WebSendSession v) => v.responseHandler;
static const Field<WebSendSession, StreamController<bool>> _f$responseHandler = Field('responseHandler', _$responseHandler);
static const Field<WebSendSession, String> _f$sessionId =
Field('sessionId', _$sessionId);
static StreamController<bool>? _$responseHandler(WebSendSession v) =>
v.responseHandler;
static const Field<WebSendSession, StreamController<bool>>
_f$responseHandler = Field('responseHandler', _$responseHandler);
static String _$ip(WebSendSession v) => v.ip;
static const Field<WebSendSession, String> _f$ip = Field('ip', _$ip);
static String _$deviceInfo(WebSendSession v) => v.deviceInfo;
static const Field<WebSendSession, String> _f$deviceInfo = Field('deviceInfo', _$deviceInfo);
static const Field<WebSendSession, String> _f$deviceInfo =
Field('deviceInfo', _$deviceInfo);
@override
final MappableFields<WebSendSession> fields = const {
@@ -39,7 +43,10 @@ class WebSendSessionMapper extends ClassMapperBase<WebSendSession> {
static WebSendSession _instantiate(DecodingData data) {
return WebSendSession(
sessionId: data.dec(_f$sessionId), responseHandler: data.dec(_f$responseHandler), ip: data.dec(_f$ip), deviceInfo: data.dec(_f$deviceInfo));
sessionId: data.dec(_f$sessionId),
responseHandler: data.dec(_f$responseHandler),
ip: data.dec(_f$ip),
deviceInfo: data.dec(_f$deviceInfo));
}
@override
@@ -56,48 +63,69 @@ class WebSendSessionMapper extends ClassMapperBase<WebSendSession> {
mixin WebSendSessionMappable {
String serialize() {
return WebSendSessionMapper.ensureInitialized().encodeJson<WebSendSession>(this as WebSendSession);
return WebSendSessionMapper.ensureInitialized()
.encodeJson<WebSendSession>(this as WebSendSession);
}
Map<String, dynamic> toJson() {
return WebSendSessionMapper.ensureInitialized().encodeMap<WebSendSession>(this as WebSendSession);
return WebSendSessionMapper.ensureInitialized()
.encodeMap<WebSendSession>(this as WebSendSession);
}
WebSendSessionCopyWith<WebSendSession, WebSendSession, WebSendSession> get copyWith =>
_WebSendSessionCopyWithImpl(this as WebSendSession, $identity, $identity);
WebSendSessionCopyWith<WebSendSession, WebSendSession, WebSendSession>
get copyWith => _WebSendSessionCopyWithImpl(
this as WebSendSession, $identity, $identity);
@override
String toString() {
return WebSendSessionMapper.ensureInitialized().stringifyValue(this as WebSendSession);
return WebSendSessionMapper.ensureInitialized()
.stringifyValue(this as WebSendSession);
}
@override
bool operator ==(Object other) {
return WebSendSessionMapper.ensureInitialized().equalsValue(this as WebSendSession, other);
return WebSendSessionMapper.ensureInitialized()
.equalsValue(this as WebSendSession, other);
}
@override
int get hashCode {
return WebSendSessionMapper.ensureInitialized().hashValue(this as WebSendSession);
return WebSendSessionMapper.ensureInitialized()
.hashValue(this as WebSendSession);
}
}
extension WebSendSessionValueCopy<$R, $Out> on ObjectCopyWith<$R, WebSendSession, $Out> {
WebSendSessionCopyWith<$R, WebSendSession, $Out> get $asWebSendSession => $base.as((v, t, t2) => _WebSendSessionCopyWithImpl(v, t, t2));
extension WebSendSessionValueCopy<$R, $Out>
on ObjectCopyWith<$R, WebSendSession, $Out> {
WebSendSessionCopyWith<$R, WebSendSession, $Out> get $asWebSendSession =>
$base.as((v, t, t2) => _WebSendSessionCopyWithImpl(v, t, t2));
}
abstract class WebSendSessionCopyWith<$R, $In extends WebSendSession, $Out> implements ClassCopyWith<$R, $In, $Out> {
$R call({String? sessionId, StreamController<bool>? responseHandler, String? ip, String? deviceInfo});
WebSendSessionCopyWith<$R2, $In, $Out2> $chain<$R2, $Out2>(Then<$Out2, $R2> t);
abstract class WebSendSessionCopyWith<$R, $In extends WebSendSession, $Out>
implements ClassCopyWith<$R, $In, $Out> {
$R call(
{String? sessionId,
StreamController<bool>? responseHandler,
String? ip,
String? deviceInfo});
WebSendSessionCopyWith<$R2, $In, $Out2> $chain<$R2, $Out2>(
Then<$Out2, $R2> t);
}
class _WebSendSessionCopyWithImpl<$R, $Out> extends ClassCopyWithBase<$R, WebSendSession, $Out>
class _WebSendSessionCopyWithImpl<$R, $Out>
extends ClassCopyWithBase<$R, WebSendSession, $Out>
implements WebSendSessionCopyWith<$R, WebSendSession, $Out> {
_WebSendSessionCopyWithImpl(super.value, super.then, super.then2);
@override
late final ClassMapperBase<WebSendSession> $mapper = WebSendSessionMapper.ensureInitialized();
late final ClassMapperBase<WebSendSession> $mapper =
WebSendSessionMapper.ensureInitialized();
@override
$R call({String? sessionId, Object? responseHandler = $none, String? ip, String? deviceInfo}) => $apply(FieldCopyWithData({
$R call(
{String? sessionId,
Object? responseHandler = $none,
String? ip,
String? deviceInfo}) =>
$apply(FieldCopyWithData({
if (sessionId != null) #sessionId: sessionId,
if (responseHandler != $none) #responseHandler: responseHandler,
if (ip != null) #ip: ip,
@@ -111,5 +139,7 @@ class _WebSendSessionCopyWithImpl<$R, $Out> extends ClassCopyWithBase<$R, WebSen
deviceInfo: data.get(#deviceInfo, or: $value.deviceInfo));
@override
WebSendSessionCopyWith<$R2, WebSendSession, $Out2> $chain<$R2, $Out2>(Then<$Out2, $R2> t) => _WebSendSessionCopyWithImpl($value, $cast, t);
WebSendSessionCopyWith<$R2, WebSendSession, $Out2> $chain<$R2, $Out2>(
Then<$Out2, $R2> t) =>
_WebSendSessionCopyWithImpl($value, $cast, t);
}
@@ -23,15 +23,19 @@ class WebSendStateMapper extends ClassMapperBase<WebSendState> {
final String id = 'WebSendState';
static Map<String, WebSendSession> _$sessions(WebSendState v) => v.sessions;
static const Field<WebSendState, Map<String, WebSendSession>> _f$sessions = Field('sessions', _$sessions);
static const Field<WebSendState, Map<String, WebSendSession>> _f$sessions =
Field('sessions', _$sessions);
static Map<String, WebSendFile> _$files(WebSendState v) => v.files;
static const Field<WebSendState, Map<String, WebSendFile>> _f$files = Field('files', _$files);
static const Field<WebSendState, Map<String, WebSendFile>> _f$files =
Field('files', _$files);
static bool _$autoAccept(WebSendState v) => v.autoAccept;
static const Field<WebSendState, bool> _f$autoAccept = Field('autoAccept', _$autoAccept);
static const Field<WebSendState, bool> _f$autoAccept =
Field('autoAccept', _$autoAccept);
static String? _$pin(WebSendState v) => v.pin;
static const Field<WebSendState, String> _f$pin = Field('pin', _$pin);
static Map<String, int> _$pinAttempts(WebSendState v) => v.pinAttempts;
static const Field<WebSendState, Map<String, int>> _f$pinAttempts = Field('pinAttempts', _$pinAttempts);
static const Field<WebSendState, Map<String, int>> _f$pinAttempts =
Field('pinAttempts', _$pinAttempts);
@override
final MappableFields<WebSendState> fields = const {
@@ -65,57 +69,80 @@ class WebSendStateMapper extends ClassMapperBase<WebSendState> {
mixin WebSendStateMappable {
String serialize() {
return WebSendStateMapper.ensureInitialized().encodeJson<WebSendState>(this as WebSendState);
return WebSendStateMapper.ensureInitialized()
.encodeJson<WebSendState>(this as WebSendState);
}
Map<String, dynamic> toJson() {
return WebSendStateMapper.ensureInitialized().encodeMap<WebSendState>(this as WebSendState);
return WebSendStateMapper.ensureInitialized()
.encodeMap<WebSendState>(this as WebSendState);
}
WebSendStateCopyWith<WebSendState, WebSendState, WebSendState> get copyWith =>
_WebSendStateCopyWithImpl(this as WebSendState, $identity, $identity);
@override
String toString() {
return WebSendStateMapper.ensureInitialized().stringifyValue(this as WebSendState);
return WebSendStateMapper.ensureInitialized()
.stringifyValue(this as WebSendState);
}
@override
bool operator ==(Object other) {
return WebSendStateMapper.ensureInitialized().equalsValue(this as WebSendState, other);
return WebSendStateMapper.ensureInitialized()
.equalsValue(this as WebSendState, other);
}
@override
int get hashCode {
return WebSendStateMapper.ensureInitialized().hashValue(this as WebSendState);
return WebSendStateMapper.ensureInitialized()
.hashValue(this as WebSendState);
}
}
extension WebSendStateValueCopy<$R, $Out> on ObjectCopyWith<$R, WebSendState, $Out> {
WebSendStateCopyWith<$R, WebSendState, $Out> get $asWebSendState => $base.as((v, t, t2) => _WebSendStateCopyWithImpl(v, t, t2));
extension WebSendStateValueCopy<$R, $Out>
on ObjectCopyWith<$R, WebSendState, $Out> {
WebSendStateCopyWith<$R, WebSendState, $Out> get $asWebSendState =>
$base.as((v, t, t2) => _WebSendStateCopyWithImpl(v, t, t2));
}
abstract class WebSendStateCopyWith<$R, $In extends WebSendState, $Out> implements ClassCopyWith<$R, $In, $Out> {
MapCopyWith<$R, String, WebSendSession, WebSendSessionCopyWith<$R, WebSendSession, WebSendSession>> get sessions;
MapCopyWith<$R, String, WebSendFile, WebSendFileCopyWith<$R, WebSendFile, WebSendFile>> get files;
abstract class WebSendStateCopyWith<$R, $In extends WebSendState, $Out>
implements ClassCopyWith<$R, $In, $Out> {
MapCopyWith<$R, String, WebSendSession,
WebSendSessionCopyWith<$R, WebSendSession, WebSendSession>> get sessions;
MapCopyWith<$R, String, WebSendFile,
WebSendFileCopyWith<$R, WebSendFile, WebSendFile>> get files;
MapCopyWith<$R, String, int, ObjectCopyWith<$R, int, int>> get pinAttempts;
$R call({Map<String, WebSendSession>? sessions, Map<String, WebSendFile>? files, bool? autoAccept, String? pin, Map<String, int>? pinAttempts});
$R call(
{Map<String, WebSendSession>? sessions,
Map<String, WebSendFile>? files,
bool? autoAccept,
String? pin,
Map<String, int>? pinAttempts});
WebSendStateCopyWith<$R2, $In, $Out2> $chain<$R2, $Out2>(Then<$Out2, $R2> t);
}
class _WebSendStateCopyWithImpl<$R, $Out> extends ClassCopyWithBase<$R, WebSendState, $Out> implements WebSendStateCopyWith<$R, WebSendState, $Out> {
class _WebSendStateCopyWithImpl<$R, $Out>
extends ClassCopyWithBase<$R, WebSendState, $Out>
implements WebSendStateCopyWith<$R, WebSendState, $Out> {
_WebSendStateCopyWithImpl(super.value, super.then, super.then2);
@override
late final ClassMapperBase<WebSendState> $mapper = WebSendStateMapper.ensureInitialized();
late final ClassMapperBase<WebSendState> $mapper =
WebSendStateMapper.ensureInitialized();
@override
MapCopyWith<$R, String, WebSendSession, WebSendSessionCopyWith<$R, WebSendSession, WebSendSession>> get sessions =>
MapCopyWith($value.sessions, (v, t) => v.copyWith.$chain(t), (v) => call(sessions: v));
MapCopyWith<$R, String, WebSendSession,
WebSendSessionCopyWith<$R, WebSendSession, WebSendSession>>
get sessions => MapCopyWith($value.sessions,
(v, t) => v.copyWith.$chain(t), (v) => call(sessions: v));
@override
MapCopyWith<$R, String, WebSendFile, WebSendFileCopyWith<$R, WebSendFile, WebSendFile>> get files =>
MapCopyWith($value.files, (v, t) => v.copyWith.$chain(t), (v) => call(files: v));
MapCopyWith<$R, String, WebSendFile,
WebSendFileCopyWith<$R, WebSendFile, WebSendFile>>
get files => MapCopyWith(
$value.files, (v, t) => v.copyWith.$chain(t), (v) => call(files: v));
@override
MapCopyWith<$R, String, int, ObjectCopyWith<$R, int, int>> get pinAttempts =>
MapCopyWith($value.pinAttempts, (v, t) => ObjectCopyWith(v, $identity, t), (v) => call(pinAttempts: v));
MapCopyWith($value.pinAttempts, (v, t) => ObjectCopyWith(v, $identity, t),
(v) => call(pinAttempts: v));
@override
$R call(
{Map<String, WebSendSession>? sessions,
@@ -139,5 +166,7 @@ class _WebSendStateCopyWithImpl<$R, $Out> extends ClassCopyWithBase<$R, WebSendS
pinAttempts: data.get(#pinAttempts, or: $value.pinAttempts));
@override
WebSendStateCopyWith<$R2, WebSendState, $Out2> $chain<$R2, $Out2>(Then<$Out2, $R2> t) => _WebSendStateCopyWithImpl($value, $cast, t);
WebSendStateCopyWith<$R2, WebSendState, $Out2> $chain<$R2, $Out2>(
Then<$Out2, $R2> t) =>
_WebSendStateCopyWithImpl($value, $cast, t);
}
@@ -8,18 +8,32 @@ import 'package:localsend_app/model/state/server/receiving_file.dart';
part 'receive_session_state.mapper.dart';
abstract class SessionState {
SessionStatus get status;
int? get startTime;
int? get endTime;
}
@MappableClass()
class ReceiveSessionState with ReceiveSessionStateMappable {
class ReceiveSessionState with ReceiveSessionStateMappable implements SessionState {
final String sessionId;
@override
final SessionStatus status;
final Device sender;
// Might not be the same as sender.alias since it can be overridden as a favorite
final String senderAlias;
final Map<String, ReceivingFile> files; // file id as key
@override
final int? startTime;
@override
final int? endTime;
final String destinationDirectory;
final String cacheDirectory;
final bool saveToGallery;
@@ -23,29 +23,46 @@ class ReceiveSessionStateMapper extends ClassMapperBase<ReceiveSessionState> {
final String id = 'ReceiveSessionState';
static String _$sessionId(ReceiveSessionState v) => v.sessionId;
static const Field<ReceiveSessionState, String> _f$sessionId = Field('sessionId', _$sessionId);
static const Field<ReceiveSessionState, String> _f$sessionId =
Field('sessionId', _$sessionId);
static SessionStatus _$status(ReceiveSessionState v) => v.status;
static const Field<ReceiveSessionState, SessionStatus> _f$status = Field('status', _$status);
static const Field<ReceiveSessionState, SessionStatus> _f$status =
Field('status', _$status);
static Device _$sender(ReceiveSessionState v) => v.sender;
static const Field<ReceiveSessionState, Device> _f$sender = Field('sender', _$sender);
static const Field<ReceiveSessionState, Device> _f$sender =
Field('sender', _$sender);
static String _$senderAlias(ReceiveSessionState v) => v.senderAlias;
static const Field<ReceiveSessionState, String> _f$senderAlias = Field('senderAlias', _$senderAlias);
static const Field<ReceiveSessionState, String> _f$senderAlias =
Field('senderAlias', _$senderAlias);
static Map<String, ReceivingFile> _$files(ReceiveSessionState v) => v.files;
static const Field<ReceiveSessionState, Map<String, ReceivingFile>> _f$files = Field('files', _$files);
static const Field<ReceiveSessionState, Map<String, ReceivingFile>> _f$files =
Field('files', _$files);
static int? _$startTime(ReceiveSessionState v) => v.startTime;
static const Field<ReceiveSessionState, int> _f$startTime = Field('startTime', _$startTime);
static const Field<ReceiveSessionState, int> _f$startTime =
Field('startTime', _$startTime);
static int? _$endTime(ReceiveSessionState v) => v.endTime;
static const Field<ReceiveSessionState, int> _f$endTime = Field('endTime', _$endTime);
static String _$destinationDirectory(ReceiveSessionState v) => v.destinationDirectory;
static const Field<ReceiveSessionState, String> _f$destinationDirectory = Field('destinationDirectory', _$destinationDirectory);
static const Field<ReceiveSessionState, int> _f$endTime =
Field('endTime', _$endTime);
static String _$destinationDirectory(ReceiveSessionState v) =>
v.destinationDirectory;
static const Field<ReceiveSessionState, String> _f$destinationDirectory =
Field('destinationDirectory', _$destinationDirectory);
static String _$cacheDirectory(ReceiveSessionState v) => v.cacheDirectory;
static const Field<ReceiveSessionState, String> _f$cacheDirectory = Field('cacheDirectory', _$cacheDirectory);
static const Field<ReceiveSessionState, String> _f$cacheDirectory =
Field('cacheDirectory', _$cacheDirectory);
static bool _$saveToGallery(ReceiveSessionState v) => v.saveToGallery;
static const Field<ReceiveSessionState, bool> _f$saveToGallery = Field('saveToGallery', _$saveToGallery);
static Set<String> _$createdDirectories(ReceiveSessionState v) => v.createdDirectories;
static const Field<ReceiveSessionState, Set<String>> _f$createdDirectories = Field('createdDirectories', _$createdDirectories);
static StreamController<Map<String, String>?>? _$responseHandler(ReceiveSessionState v) => v.responseHandler;
static const Field<ReceiveSessionState, StreamController<Map<String, String>?>> _f$responseHandler = Field('responseHandler', _$responseHandler);
static const Field<ReceiveSessionState, bool> _f$saveToGallery =
Field('saveToGallery', _$saveToGallery);
static Set<String> _$createdDirectories(ReceiveSessionState v) =>
v.createdDirectories;
static const Field<ReceiveSessionState, Set<String>> _f$createdDirectories =
Field('createdDirectories', _$createdDirectories);
static StreamController<Map<String, String>?>? _$responseHandler(
ReceiveSessionState v) =>
v.responseHandler;
static const Field<ReceiveSessionState,
StreamController<Map<String, String>?>> _f$responseHandler =
Field('responseHandler', _$responseHandler);
@override
final MappableFields<ReceiveSessionState> fields = const {
@@ -93,39 +110,50 @@ class ReceiveSessionStateMapper extends ClassMapperBase<ReceiveSessionState> {
mixin ReceiveSessionStateMappable {
String serialize() {
return ReceiveSessionStateMapper.ensureInitialized().encodeJson<ReceiveSessionState>(this as ReceiveSessionState);
return ReceiveSessionStateMapper.ensureInitialized()
.encodeJson<ReceiveSessionState>(this as ReceiveSessionState);
}
Map<String, dynamic> toJson() {
return ReceiveSessionStateMapper.ensureInitialized().encodeMap<ReceiveSessionState>(this as ReceiveSessionState);
return ReceiveSessionStateMapper.ensureInitialized()
.encodeMap<ReceiveSessionState>(this as ReceiveSessionState);
}
ReceiveSessionStateCopyWith<ReceiveSessionState, ReceiveSessionState, ReceiveSessionState> get copyWith =>
_ReceiveSessionStateCopyWithImpl(this as ReceiveSessionState, $identity, $identity);
ReceiveSessionStateCopyWith<ReceiveSessionState, ReceiveSessionState,
ReceiveSessionState>
get copyWith => _ReceiveSessionStateCopyWithImpl(
this as ReceiveSessionState, $identity, $identity);
@override
String toString() {
return ReceiveSessionStateMapper.ensureInitialized().stringifyValue(this as ReceiveSessionState);
return ReceiveSessionStateMapper.ensureInitialized()
.stringifyValue(this as ReceiveSessionState);
}
@override
bool operator ==(Object other) {
return ReceiveSessionStateMapper.ensureInitialized().equalsValue(this as ReceiveSessionState, other);
return ReceiveSessionStateMapper.ensureInitialized()
.equalsValue(this as ReceiveSessionState, other);
}
@override
int get hashCode {
return ReceiveSessionStateMapper.ensureInitialized().hashValue(this as ReceiveSessionState);
return ReceiveSessionStateMapper.ensureInitialized()
.hashValue(this as ReceiveSessionState);
}
}
extension ReceiveSessionStateValueCopy<$R, $Out> on ObjectCopyWith<$R, ReceiveSessionState, $Out> {
ReceiveSessionStateCopyWith<$R, ReceiveSessionState, $Out> get $asReceiveSessionState =>
$base.as((v, t, t2) => _ReceiveSessionStateCopyWithImpl(v, t, t2));
extension ReceiveSessionStateValueCopy<$R, $Out>
on ObjectCopyWith<$R, ReceiveSessionState, $Out> {
ReceiveSessionStateCopyWith<$R, ReceiveSessionState, $Out>
get $asReceiveSessionState =>
$base.as((v, t, t2) => _ReceiveSessionStateCopyWithImpl(v, t, t2));
}
abstract class ReceiveSessionStateCopyWith<$R, $In extends ReceiveSessionState, $Out> implements ClassCopyWith<$R, $In, $Out> {
abstract class ReceiveSessionStateCopyWith<$R, $In extends ReceiveSessionState,
$Out> implements ClassCopyWith<$R, $In, $Out> {
DeviceCopyWith<$R, Device, Device> get sender;
MapCopyWith<$R, String, ReceivingFile, ReceivingFileCopyWith<$R, ReceivingFile, ReceivingFile>> get files;
MapCopyWith<$R, String, ReceivingFile,
ReceivingFileCopyWith<$R, ReceivingFile, ReceivingFile>> get files;
$R call(
{String? sessionId,
SessionStatus? status,
@@ -139,20 +167,26 @@ abstract class ReceiveSessionStateCopyWith<$R, $In extends ReceiveSessionState,
bool? saveToGallery,
Set<String>? createdDirectories,
StreamController<Map<String, String>?>? responseHandler});
ReceiveSessionStateCopyWith<$R2, $In, $Out2> $chain<$R2, $Out2>(Then<$Out2, $R2> t);
ReceiveSessionStateCopyWith<$R2, $In, $Out2> $chain<$R2, $Out2>(
Then<$Out2, $R2> t);
}
class _ReceiveSessionStateCopyWithImpl<$R, $Out> extends ClassCopyWithBase<$R, ReceiveSessionState, $Out>
class _ReceiveSessionStateCopyWithImpl<$R, $Out>
extends ClassCopyWithBase<$R, ReceiveSessionState, $Out>
implements ReceiveSessionStateCopyWith<$R, ReceiveSessionState, $Out> {
_ReceiveSessionStateCopyWithImpl(super.value, super.then, super.then2);
@override
late final ClassMapperBase<ReceiveSessionState> $mapper = ReceiveSessionStateMapper.ensureInitialized();
late final ClassMapperBase<ReceiveSessionState> $mapper =
ReceiveSessionStateMapper.ensureInitialized();
@override
DeviceCopyWith<$R, Device, Device> get sender => $value.sender.copyWith.$chain((v) => call(sender: v));
DeviceCopyWith<$R, Device, Device> get sender =>
$value.sender.copyWith.$chain((v) => call(sender: v));
@override
MapCopyWith<$R, String, ReceivingFile, ReceivingFileCopyWith<$R, ReceivingFile, ReceivingFile>> get files =>
MapCopyWith($value.files, (v, t) => v.copyWith.$chain(t), (v) => call(files: v));
MapCopyWith<$R, String, ReceivingFile,
ReceivingFileCopyWith<$R, ReceivingFile, ReceivingFile>>
get files => MapCopyWith(
$value.files, (v, t) => v.copyWith.$chain(t), (v) => call(files: v));
@override
$R call(
{String? sessionId,
@@ -175,7 +209,8 @@ class _ReceiveSessionStateCopyWithImpl<$R, $Out> extends ClassCopyWithBase<$R, R
if (files != null) #files: files,
if (startTime != $none) #startTime: startTime,
if (endTime != $none) #endTime: endTime,
if (destinationDirectory != null) #destinationDirectory: destinationDirectory,
if (destinationDirectory != null)
#destinationDirectory: destinationDirectory,
if (cacheDirectory != null) #cacheDirectory: cacheDirectory,
if (saveToGallery != null) #saveToGallery: saveToGallery,
if (createdDirectories != null) #createdDirectories: createdDirectories,
@@ -190,13 +225,16 @@ class _ReceiveSessionStateCopyWithImpl<$R, $Out> extends ClassCopyWithBase<$R, R
files: data.get(#files, or: $value.files),
startTime: data.get(#startTime, or: $value.startTime),
endTime: data.get(#endTime, or: $value.endTime),
destinationDirectory: data.get(#destinationDirectory, or: $value.destinationDirectory),
destinationDirectory:
data.get(#destinationDirectory, or: $value.destinationDirectory),
cacheDirectory: data.get(#cacheDirectory, or: $value.cacheDirectory),
saveToGallery: data.get(#saveToGallery, or: $value.saveToGallery),
createdDirectories: data.get(#createdDirectories, or: $value.createdDirectories),
createdDirectories:
data.get(#createdDirectories, or: $value.createdDirectories),
responseHandler: data.get(#responseHandler, or: $value.responseHandler));
@override
ReceiveSessionStateCopyWith<$R2, ReceiveSessionState, $Out2> $chain<$R2, $Out2>(Then<$Out2, $R2> t) =>
_ReceiveSessionStateCopyWithImpl($value, $cast, t);
ReceiveSessionStateCopyWith<$R2, ReceiveSessionState, $Out2>
$chain<$R2, $Out2>(Then<$Out2, $R2> t) =>
_ReceiveSessionStateCopyWithImpl($value, $cast, t);
}
@@ -23,17 +23,21 @@ class ReceivingFileMapper extends ClassMapperBase<ReceivingFile> {
static FileDto _$file(ReceivingFile v) => v.file;
static const Field<ReceivingFile, FileDto> _f$file = Field('file', _$file);
static FileStatus _$status(ReceivingFile v) => v.status;
static const Field<ReceivingFile, FileStatus> _f$status = Field('status', _$status);
static const Field<ReceivingFile, FileStatus> _f$status =
Field('status', _$status);
static String? _$token(ReceivingFile v) => v.token;
static const Field<ReceivingFile, String> _f$token = Field('token', _$token);
static String? _$desiredName(ReceivingFile v) => v.desiredName;
static const Field<ReceivingFile, String> _f$desiredName = Field('desiredName', _$desiredName);
static const Field<ReceivingFile, String> _f$desiredName =
Field('desiredName', _$desiredName);
static String? _$path(ReceivingFile v) => v.path;
static const Field<ReceivingFile, String> _f$path = Field('path', _$path);
static bool _$savedToGallery(ReceivingFile v) => v.savedToGallery;
static const Field<ReceivingFile, bool> _f$savedToGallery = Field('savedToGallery', _$savedToGallery);
static const Field<ReceivingFile, bool> _f$savedToGallery =
Field('savedToGallery', _$savedToGallery);
static String? _$errorMessage(ReceivingFile v) => v.errorMessage;
static const Field<ReceivingFile, String> _f$errorMessage = Field('errorMessage', _$errorMessage);
static const Field<ReceivingFile, String> _f$errorMessage =
Field('errorMessage', _$errorMessage);
@override
final MappableFields<ReceivingFile> fields = const {
@@ -71,46 +75,64 @@ class ReceivingFileMapper extends ClassMapperBase<ReceivingFile> {
mixin ReceivingFileMappable {
String serialize() {
return ReceivingFileMapper.ensureInitialized().encodeJson<ReceivingFile>(this as ReceivingFile);
return ReceivingFileMapper.ensureInitialized()
.encodeJson<ReceivingFile>(this as ReceivingFile);
}
Map<String, dynamic> toJson() {
return ReceivingFileMapper.ensureInitialized().encodeMap<ReceivingFile>(this as ReceivingFile);
return ReceivingFileMapper.ensureInitialized()
.encodeMap<ReceivingFile>(this as ReceivingFile);
}
ReceivingFileCopyWith<ReceivingFile, ReceivingFile, ReceivingFile> get copyWith =>
_ReceivingFileCopyWithImpl(this as ReceivingFile, $identity, $identity);
ReceivingFileCopyWith<ReceivingFile, ReceivingFile, ReceivingFile>
get copyWith => _ReceivingFileCopyWithImpl(
this as ReceivingFile, $identity, $identity);
@override
String toString() {
return ReceivingFileMapper.ensureInitialized().stringifyValue(this as ReceivingFile);
return ReceivingFileMapper.ensureInitialized()
.stringifyValue(this as ReceivingFile);
}
@override
bool operator ==(Object other) {
return ReceivingFileMapper.ensureInitialized().equalsValue(this as ReceivingFile, other);
return ReceivingFileMapper.ensureInitialized()
.equalsValue(this as ReceivingFile, other);
}
@override
int get hashCode {
return ReceivingFileMapper.ensureInitialized().hashValue(this as ReceivingFile);
return ReceivingFileMapper.ensureInitialized()
.hashValue(this as ReceivingFile);
}
}
extension ReceivingFileValueCopy<$R, $Out> on ObjectCopyWith<$R, ReceivingFile, $Out> {
ReceivingFileCopyWith<$R, ReceivingFile, $Out> get $asReceivingFile => $base.as((v, t, t2) => _ReceivingFileCopyWithImpl(v, t, t2));
extension ReceivingFileValueCopy<$R, $Out>
on ObjectCopyWith<$R, ReceivingFile, $Out> {
ReceivingFileCopyWith<$R, ReceivingFile, $Out> get $asReceivingFile =>
$base.as((v, t, t2) => _ReceivingFileCopyWithImpl(v, t, t2));
}
abstract class ReceivingFileCopyWith<$R, $In extends ReceivingFile, $Out> implements ClassCopyWith<$R, $In, $Out> {
$R call({FileDto? file, FileStatus? status, String? token, String? desiredName, String? path, bool? savedToGallery, String? errorMessage});
abstract class ReceivingFileCopyWith<$R, $In extends ReceivingFile, $Out>
implements ClassCopyWith<$R, $In, $Out> {
$R call(
{FileDto? file,
FileStatus? status,
String? token,
String? desiredName,
String? path,
bool? savedToGallery,
String? errorMessage});
ReceivingFileCopyWith<$R2, $In, $Out2> $chain<$R2, $Out2>(Then<$Out2, $R2> t);
}
class _ReceivingFileCopyWithImpl<$R, $Out> extends ClassCopyWithBase<$R, ReceivingFile, $Out>
class _ReceivingFileCopyWithImpl<$R, $Out>
extends ClassCopyWithBase<$R, ReceivingFile, $Out>
implements ReceivingFileCopyWith<$R, ReceivingFile, $Out> {
_ReceivingFileCopyWithImpl(super.value, super.then, super.then2);
@override
late final ClassMapperBase<ReceivingFile> $mapper = ReceivingFileMapper.ensureInitialized();
late final ClassMapperBase<ReceivingFile> $mapper =
ReceivingFileMapper.ensureInitialized();
@override
$R call(
{FileDto? file,
@@ -140,5 +162,7 @@ class _ReceivingFileCopyWithImpl<$R, $Out> extends ClassCopyWithBase<$R, Receivi
errorMessage: data.get(#errorMessage, or: $value.errorMessage));
@override
ReceivingFileCopyWith<$R2, ReceivingFile, $Out2> $chain<$R2, $Out2>(Then<$Out2, $R2> t) => _ReceivingFileCopyWithImpl($value, $cast, t);
ReceivingFileCopyWith<$R2, ReceivingFile, $Out2> $chain<$R2, $Out2>(
Then<$Out2, $R2> t) =>
_ReceivingFileCopyWithImpl($value, $cast, t);
}
@@ -23,7 +23,8 @@ class ServerStateMapper extends ClassMapperBase<ServerState> {
final String id = 'ServerState';
static SimpleServer _$httpServer(ServerState v) => v.httpServer;
static const Field<ServerState, SimpleServer> _f$httpServer = Field('httpServer', _$httpServer);
static const Field<ServerState, SimpleServer> _f$httpServer =
Field('httpServer', _$httpServer);
static String _$alias(ServerState v) => v.alias;
static const Field<ServerState, String> _f$alias = Field('alias', _$alias);
static int _$port(ServerState v) => v.port;
@@ -31,11 +32,14 @@ class ServerStateMapper extends ClassMapperBase<ServerState> {
static bool _$https(ServerState v) => v.https;
static const Field<ServerState, bool> _f$https = Field('https', _$https);
static ReceiveSessionState? _$session(ServerState v) => v.session;
static const Field<ServerState, ReceiveSessionState> _f$session = Field('session', _$session);
static const Field<ServerState, ReceiveSessionState> _f$session =
Field('session', _$session);
static WebSendState? _$webSendState(ServerState v) => v.webSendState;
static const Field<ServerState, WebSendState> _f$webSendState = Field('webSendState', _$webSendState);
static const Field<ServerState, WebSendState> _f$webSendState =
Field('webSendState', _$webSendState);
static Map<String, int> _$pinAttempts(ServerState v) => v.pinAttempts;
static const Field<ServerState, Map<String, int>> _f$pinAttempts = Field('pinAttempts', _$pinAttempts);
static const Field<ServerState, Map<String, int>> _f$pinAttempts =
Field('pinAttempts', _$pinAttempts);
@override
final MappableFields<ServerState> fields = const {
@@ -73,22 +77,27 @@ class ServerStateMapper extends ClassMapperBase<ServerState> {
mixin ServerStateMappable {
String serialize() {
return ServerStateMapper.ensureInitialized().encodeJson<ServerState>(this as ServerState);
return ServerStateMapper.ensureInitialized()
.encodeJson<ServerState>(this as ServerState);
}
Map<String, dynamic> toJson() {
return ServerStateMapper.ensureInitialized().encodeMap<ServerState>(this as ServerState);
return ServerStateMapper.ensureInitialized()
.encodeMap<ServerState>(this as ServerState);
}
ServerStateCopyWith<ServerState, ServerState, ServerState> get copyWith => _ServerStateCopyWithImpl(this as ServerState, $identity, $identity);
ServerStateCopyWith<ServerState, ServerState, ServerState> get copyWith =>
_ServerStateCopyWithImpl(this as ServerState, $identity, $identity);
@override
String toString() {
return ServerStateMapper.ensureInitialized().stringifyValue(this as ServerState);
return ServerStateMapper.ensureInitialized()
.stringifyValue(this as ServerState);
}
@override
bool operator ==(Object other) {
return ServerStateMapper.ensureInitialized().equalsValue(this as ServerState, other);
return ServerStateMapper.ensureInitialized()
.equalsValue(this as ServerState, other);
}
@override
@@ -97,12 +106,16 @@ mixin ServerStateMappable {
}
}
extension ServerStateValueCopy<$R, $Out> on ObjectCopyWith<$R, ServerState, $Out> {
ServerStateCopyWith<$R, ServerState, $Out> get $asServerState => $base.as((v, t, t2) => _ServerStateCopyWithImpl(v, t, t2));
extension ServerStateValueCopy<$R, $Out>
on ObjectCopyWith<$R, ServerState, $Out> {
ServerStateCopyWith<$R, ServerState, $Out> get $asServerState =>
$base.as((v, t, t2) => _ServerStateCopyWithImpl(v, t, t2));
}
abstract class ServerStateCopyWith<$R, $In extends ServerState, $Out> implements ClassCopyWith<$R, $In, $Out> {
ReceiveSessionStateCopyWith<$R, ReceiveSessionState, ReceiveSessionState>? get session;
abstract class ServerStateCopyWith<$R, $In extends ServerState, $Out>
implements ClassCopyWith<$R, $In, $Out> {
ReceiveSessionStateCopyWith<$R, ReceiveSessionState, ReceiveSessionState>?
get session;
WebSendStateCopyWith<$R, WebSendState, WebSendState>? get webSendState;
MapCopyWith<$R, String, int, ObjectCopyWith<$R, int, int>> get pinAttempts;
$R call(
@@ -116,18 +129,24 @@ abstract class ServerStateCopyWith<$R, $In extends ServerState, $Out> implements
ServerStateCopyWith<$R2, $In, $Out2> $chain<$R2, $Out2>(Then<$Out2, $R2> t);
}
class _ServerStateCopyWithImpl<$R, $Out> extends ClassCopyWithBase<$R, ServerState, $Out> implements ServerStateCopyWith<$R, ServerState, $Out> {
class _ServerStateCopyWithImpl<$R, $Out>
extends ClassCopyWithBase<$R, ServerState, $Out>
implements ServerStateCopyWith<$R, ServerState, $Out> {
_ServerStateCopyWithImpl(super.value, super.then, super.then2);
@override
late final ClassMapperBase<ServerState> $mapper = ServerStateMapper.ensureInitialized();
late final ClassMapperBase<ServerState> $mapper =
ServerStateMapper.ensureInitialized();
@override
ReceiveSessionStateCopyWith<$R, ReceiveSessionState, ReceiveSessionState>? get session => $value.session?.copyWith.$chain((v) => call(session: v));
ReceiveSessionStateCopyWith<$R, ReceiveSessionState, ReceiveSessionState>?
get session => $value.session?.copyWith.$chain((v) => call(session: v));
@override
WebSendStateCopyWith<$R, WebSendState, WebSendState>? get webSendState => $value.webSendState?.copyWith.$chain((v) => call(webSendState: v));
WebSendStateCopyWith<$R, WebSendState, WebSendState>? get webSendState =>
$value.webSendState?.copyWith.$chain((v) => call(webSendState: v));
@override
MapCopyWith<$R, String, int, ObjectCopyWith<$R, int, int>> get pinAttempts =>
MapCopyWith($value.pinAttempts, (v, t) => ObjectCopyWith(v, $identity, t), (v) => call(pinAttempts: v));
MapCopyWith($value.pinAttempts, (v, t) => ObjectCopyWith(v, $identity, t),
(v) => call(pinAttempts: v));
@override
$R call(
{SimpleServer? httpServer,
@@ -157,5 +176,7 @@ class _ServerStateCopyWithImpl<$R, $Out> extends ClassCopyWithBase<$R, ServerSta
pinAttempts: data.get(#pinAttempts, or: $value.pinAttempts));
@override
ServerStateCopyWith<$R2, ServerState, $Out2> $chain<$R2, $Out2>(Then<$Out2, $R2> t) => _ServerStateCopyWithImpl($value, $cast, t);
ServerStateCopyWith<$R2, ServerState, $Out2> $chain<$R2, $Out2>(
Then<$Out2, $R2> t) =>
_ServerStateCopyWithImpl($value, $cast, t);
}
+120 -59
View File
@@ -22,57 +22,84 @@ class SettingsStateMapper extends ClassMapperBase<SettingsState> {
final String id = 'SettingsState';
static String _$showToken(SettingsState v) => v.showToken;
static const Field<SettingsState, String> _f$showToken = Field('showToken', _$showToken);
static const Field<SettingsState, String> _f$showToken =
Field('showToken', _$showToken);
static String _$alias(SettingsState v) => v.alias;
static const Field<SettingsState, String> _f$alias = Field('alias', _$alias);
static ThemeMode _$theme(SettingsState v) => v.theme;
static const Field<SettingsState, ThemeMode> _f$theme = Field('theme', _$theme);
static const Field<SettingsState, ThemeMode> _f$theme =
Field('theme', _$theme);
static ColorMode _$colorMode(SettingsState v) => v.colorMode;
static const Field<SettingsState, ColorMode> _f$colorMode = Field('colorMode', _$colorMode);
static const Field<SettingsState, ColorMode> _f$colorMode =
Field('colorMode', _$colorMode);
static AppLocale? _$locale(SettingsState v) => v.locale;
static const Field<SettingsState, AppLocale> _f$locale = Field('locale', _$locale);
static const Field<SettingsState, AppLocale> _f$locale =
Field('locale', _$locale);
static int _$port(SettingsState v) => v.port;
static const Field<SettingsState, int> _f$port = Field('port', _$port);
static List<String>? _$networkWhitelist(SettingsState v) => v.networkWhitelist;
static const Field<SettingsState, List<String>> _f$networkWhitelist = Field('networkWhitelist', _$networkWhitelist);
static List<String>? _$networkBlacklist(SettingsState v) => v.networkBlacklist;
static const Field<SettingsState, List<String>> _f$networkBlacklist = Field('networkBlacklist', _$networkBlacklist);
static List<String>? _$networkWhitelist(SettingsState v) =>
v.networkWhitelist;
static const Field<SettingsState, List<String>> _f$networkWhitelist =
Field('networkWhitelist', _$networkWhitelist);
static List<String>? _$networkBlacklist(SettingsState v) =>
v.networkBlacklist;
static const Field<SettingsState, List<String>> _f$networkBlacklist =
Field('networkBlacklist', _$networkBlacklist);
static String _$multicastGroup(SettingsState v) => v.multicastGroup;
static const Field<SettingsState, String> _f$multicastGroup = Field('multicastGroup', _$multicastGroup);
static const Field<SettingsState, String> _f$multicastGroup =
Field('multicastGroup', _$multicastGroup);
static String? _$destination(SettingsState v) => v.destination;
static const Field<SettingsState, String> _f$destination = Field('destination', _$destination);
static const Field<SettingsState, String> _f$destination =
Field('destination', _$destination);
static bool _$saveToGallery(SettingsState v) => v.saveToGallery;
static const Field<SettingsState, bool> _f$saveToGallery = Field('saveToGallery', _$saveToGallery);
static const Field<SettingsState, bool> _f$saveToGallery =
Field('saveToGallery', _$saveToGallery);
static bool _$saveToHistory(SettingsState v) => v.saveToHistory;
static const Field<SettingsState, bool> _f$saveToHistory = Field('saveToHistory', _$saveToHistory);
static const Field<SettingsState, bool> _f$saveToHistory =
Field('saveToHistory', _$saveToHistory);
static bool _$quickSave(SettingsState v) => v.quickSave;
static const Field<SettingsState, bool> _f$quickSave = Field('quickSave', _$quickSave);
static bool _$quickSaveFromFavorites(SettingsState v) => v.quickSaveFromFavorites;
static const Field<SettingsState, bool> _f$quickSaveFromFavorites = Field('quickSaveFromFavorites', _$quickSaveFromFavorites);
static const Field<SettingsState, bool> _f$quickSave =
Field('quickSave', _$quickSave);
static bool _$quickSaveFromFavorites(SettingsState v) =>
v.quickSaveFromFavorites;
static const Field<SettingsState, bool> _f$quickSaveFromFavorites =
Field('quickSaveFromFavorites', _$quickSaveFromFavorites);
static String? _$receivePin(SettingsState v) => v.receivePin;
static const Field<SettingsState, String> _f$receivePin = Field('receivePin', _$receivePin);
static const Field<SettingsState, String> _f$receivePin =
Field('receivePin', _$receivePin);
static bool _$autoFinish(SettingsState v) => v.autoFinish;
static const Field<SettingsState, bool> _f$autoFinish = Field('autoFinish', _$autoFinish);
static const Field<SettingsState, bool> _f$autoFinish =
Field('autoFinish', _$autoFinish);
static bool _$minimizeToTray(SettingsState v) => v.minimizeToTray;
static const Field<SettingsState, bool> _f$minimizeToTray = Field('minimizeToTray', _$minimizeToTray);
static const Field<SettingsState, bool> _f$minimizeToTray =
Field('minimizeToTray', _$minimizeToTray);
static bool _$https(SettingsState v) => v.https;
static const Field<SettingsState, bool> _f$https = Field('https', _$https);
static SendMode _$sendMode(SettingsState v) => v.sendMode;
static const Field<SettingsState, SendMode> _f$sendMode = Field('sendMode', _$sendMode);
static const Field<SettingsState, SendMode> _f$sendMode =
Field('sendMode', _$sendMode);
static bool _$saveWindowPlacement(SettingsState v) => v.saveWindowPlacement;
static const Field<SettingsState, bool> _f$saveWindowPlacement = Field('saveWindowPlacement', _$saveWindowPlacement);
static const Field<SettingsState, bool> _f$saveWindowPlacement =
Field('saveWindowPlacement', _$saveWindowPlacement);
static bool _$enableAnimations(SettingsState v) => v.enableAnimations;
static const Field<SettingsState, bool> _f$enableAnimations = Field('enableAnimations', _$enableAnimations);
static const Field<SettingsState, bool> _f$enableAnimations =
Field('enableAnimations', _$enableAnimations);
static DeviceType? _$deviceType(SettingsState v) => v.deviceType;
static const Field<SettingsState, DeviceType> _f$deviceType = Field('deviceType', _$deviceType);
static const Field<SettingsState, DeviceType> _f$deviceType =
Field('deviceType', _$deviceType);
static String? _$deviceModel(SettingsState v) => v.deviceModel;
static const Field<SettingsState, String> _f$deviceModel = Field('deviceModel', _$deviceModel);
static bool _$shareViaLinkAutoAccept(SettingsState v) => v.shareViaLinkAutoAccept;
static const Field<SettingsState, bool> _f$shareViaLinkAutoAccept = Field('shareViaLinkAutoAccept', _$shareViaLinkAutoAccept);
static const Field<SettingsState, String> _f$deviceModel =
Field('deviceModel', _$deviceModel);
static bool _$shareViaLinkAutoAccept(SettingsState v) =>
v.shareViaLinkAutoAccept;
static const Field<SettingsState, bool> _f$shareViaLinkAutoAccept =
Field('shareViaLinkAutoAccept', _$shareViaLinkAutoAccept);
static int _$discoveryTimeout(SettingsState v) => v.discoveryTimeout;
static const Field<SettingsState, int> _f$discoveryTimeout = Field('discoveryTimeout', _$discoveryTimeout);
static const Field<SettingsState, int> _f$discoveryTimeout =
Field('discoveryTimeout', _$discoveryTimeout);
static bool _$advancedSettings(SettingsState v) => v.advancedSettings;
static const Field<SettingsState, bool> _f$advancedSettings = Field('advancedSettings', _$advancedSettings);
static const Field<SettingsState, bool> _f$advancedSettings =
Field('advancedSettings', _$advancedSettings);
@override
final MappableFields<SettingsState> fields = const {
@@ -148,38 +175,49 @@ class SettingsStateMapper extends ClassMapperBase<SettingsState> {
mixin SettingsStateMappable {
String serialize() {
return SettingsStateMapper.ensureInitialized().encodeJson<SettingsState>(this as SettingsState);
return SettingsStateMapper.ensureInitialized()
.encodeJson<SettingsState>(this as SettingsState);
}
Map<String, dynamic> toJson() {
return SettingsStateMapper.ensureInitialized().encodeMap<SettingsState>(this as SettingsState);
return SettingsStateMapper.ensureInitialized()
.encodeMap<SettingsState>(this as SettingsState);
}
SettingsStateCopyWith<SettingsState, SettingsState, SettingsState> get copyWith =>
_SettingsStateCopyWithImpl(this as SettingsState, $identity, $identity);
SettingsStateCopyWith<SettingsState, SettingsState, SettingsState>
get copyWith => _SettingsStateCopyWithImpl(
this as SettingsState, $identity, $identity);
@override
String toString() {
return SettingsStateMapper.ensureInitialized().stringifyValue(this as SettingsState);
return SettingsStateMapper.ensureInitialized()
.stringifyValue(this as SettingsState);
}
@override
bool operator ==(Object other) {
return SettingsStateMapper.ensureInitialized().equalsValue(this as SettingsState, other);
return SettingsStateMapper.ensureInitialized()
.equalsValue(this as SettingsState, other);
}
@override
int get hashCode {
return SettingsStateMapper.ensureInitialized().hashValue(this as SettingsState);
return SettingsStateMapper.ensureInitialized()
.hashValue(this as SettingsState);
}
}
extension SettingsStateValueCopy<$R, $Out> on ObjectCopyWith<$R, SettingsState, $Out> {
SettingsStateCopyWith<$R, SettingsState, $Out> get $asSettingsState => $base.as((v, t, t2) => _SettingsStateCopyWithImpl(v, t, t2));
extension SettingsStateValueCopy<$R, $Out>
on ObjectCopyWith<$R, SettingsState, $Out> {
SettingsStateCopyWith<$R, SettingsState, $Out> get $asSettingsState =>
$base.as((v, t, t2) => _SettingsStateCopyWithImpl(v, t, t2));
}
abstract class SettingsStateCopyWith<$R, $In extends SettingsState, $Out> implements ClassCopyWith<$R, $In, $Out> {
ListCopyWith<$R, String, ObjectCopyWith<$R, String, String>>? get networkWhitelist;
ListCopyWith<$R, String, ObjectCopyWith<$R, String, String>>? get networkBlacklist;
abstract class SettingsStateCopyWith<$R, $In extends SettingsState, $Out>
implements ClassCopyWith<$R, $In, $Out> {
ListCopyWith<$R, String, ObjectCopyWith<$R, String, String>>?
get networkWhitelist;
ListCopyWith<$R, String, ObjectCopyWith<$R, String, String>>?
get networkBlacklist;
$R call(
{String? showToken,
String? alias,
@@ -210,20 +248,30 @@ abstract class SettingsStateCopyWith<$R, $In extends SettingsState, $Out> implem
SettingsStateCopyWith<$R2, $In, $Out2> $chain<$R2, $Out2>(Then<$Out2, $R2> t);
}
class _SettingsStateCopyWithImpl<$R, $Out> extends ClassCopyWithBase<$R, SettingsState, $Out>
class _SettingsStateCopyWithImpl<$R, $Out>
extends ClassCopyWithBase<$R, SettingsState, $Out>
implements SettingsStateCopyWith<$R, SettingsState, $Out> {
_SettingsStateCopyWithImpl(super.value, super.then, super.then2);
@override
late final ClassMapperBase<SettingsState> $mapper = SettingsStateMapper.ensureInitialized();
late final ClassMapperBase<SettingsState> $mapper =
SettingsStateMapper.ensureInitialized();
@override
ListCopyWith<$R, String, ObjectCopyWith<$R, String, String>>? get networkWhitelist => $value.networkWhitelist != null
? ListCopyWith($value.networkWhitelist!, (v, t) => ObjectCopyWith(v, $identity, t), (v) => call(networkWhitelist: v))
: null;
ListCopyWith<$R, String, ObjectCopyWith<$R, String, String>>?
get networkWhitelist => $value.networkWhitelist != null
? ListCopyWith(
$value.networkWhitelist!,
(v, t) => ObjectCopyWith(v, $identity, t),
(v) => call(networkWhitelist: v))
: null;
@override
ListCopyWith<$R, String, ObjectCopyWith<$R, String, String>>? get networkBlacklist => $value.networkBlacklist != null
? ListCopyWith($value.networkBlacklist!, (v, t) => ObjectCopyWith(v, $identity, t), (v) => call(networkBlacklist: v))
: null;
ListCopyWith<$R, String, ObjectCopyWith<$R, String, String>>?
get networkBlacklist => $value.networkBlacklist != null
? ListCopyWith(
$value.networkBlacklist!,
(v, t) => ObjectCopyWith(v, $identity, t),
(v) => call(networkBlacklist: v))
: null;
@override
$R call(
{String? showToken,
@@ -266,17 +314,20 @@ class _SettingsStateCopyWithImpl<$R, $Out> extends ClassCopyWithBase<$R, Setting
if (saveToGallery != null) #saveToGallery: saveToGallery,
if (saveToHistory != null) #saveToHistory: saveToHistory,
if (quickSave != null) #quickSave: quickSave,
if (quickSaveFromFavorites != null) #quickSaveFromFavorites: quickSaveFromFavorites,
if (quickSaveFromFavorites != null)
#quickSaveFromFavorites: quickSaveFromFavorites,
if (receivePin != $none) #receivePin: receivePin,
if (autoFinish != null) #autoFinish: autoFinish,
if (minimizeToTray != null) #minimizeToTray: minimizeToTray,
if (https != null) #https: https,
if (sendMode != null) #sendMode: sendMode,
if (saveWindowPlacement != null) #saveWindowPlacement: saveWindowPlacement,
if (saveWindowPlacement != null)
#saveWindowPlacement: saveWindowPlacement,
if (enableAnimations != null) #enableAnimations: enableAnimations,
if (deviceType != $none) #deviceType: deviceType,
if (deviceModel != $none) #deviceModel: deviceModel,
if (shareViaLinkAutoAccept != null) #shareViaLinkAutoAccept: shareViaLinkAutoAccept,
if (shareViaLinkAutoAccept != null)
#shareViaLinkAutoAccept: shareViaLinkAutoAccept,
if (discoveryTimeout != null) #discoveryTimeout: discoveryTimeout,
if (advancedSettings != null) #advancedSettings: advancedSettings
}));
@@ -288,27 +339,37 @@ class _SettingsStateCopyWithImpl<$R, $Out> extends ClassCopyWithBase<$R, Setting
colorMode: data.get(#colorMode, or: $value.colorMode),
locale: data.get(#locale, or: $value.locale),
port: data.get(#port, or: $value.port),
networkWhitelist: data.get(#networkWhitelist, or: $value.networkWhitelist),
networkBlacklist: data.get(#networkBlacklist, or: $value.networkBlacklist),
networkWhitelist:
data.get(#networkWhitelist, or: $value.networkWhitelist),
networkBlacklist:
data.get(#networkBlacklist, or: $value.networkBlacklist),
multicastGroup: data.get(#multicastGroup, or: $value.multicastGroup),
destination: data.get(#destination, or: $value.destination),
saveToGallery: data.get(#saveToGallery, or: $value.saveToGallery),
saveToHistory: data.get(#saveToHistory, or: $value.saveToHistory),
quickSave: data.get(#quickSave, or: $value.quickSave),
quickSaveFromFavorites: data.get(#quickSaveFromFavorites, or: $value.quickSaveFromFavorites),
quickSaveFromFavorites:
data.get(#quickSaveFromFavorites, or: $value.quickSaveFromFavorites),
receivePin: data.get(#receivePin, or: $value.receivePin),
autoFinish: data.get(#autoFinish, or: $value.autoFinish),
minimizeToTray: data.get(#minimizeToTray, or: $value.minimizeToTray),
https: data.get(#https, or: $value.https),
sendMode: data.get(#sendMode, or: $value.sendMode),
saveWindowPlacement: data.get(#saveWindowPlacement, or: $value.saveWindowPlacement),
enableAnimations: data.get(#enableAnimations, or: $value.enableAnimations),
saveWindowPlacement:
data.get(#saveWindowPlacement, or: $value.saveWindowPlacement),
enableAnimations:
data.get(#enableAnimations, or: $value.enableAnimations),
deviceType: data.get(#deviceType, or: $value.deviceType),
deviceModel: data.get(#deviceModel, or: $value.deviceModel),
shareViaLinkAutoAccept: data.get(#shareViaLinkAutoAccept, or: $value.shareViaLinkAutoAccept),
discoveryTimeout: data.get(#discoveryTimeout, or: $value.discoveryTimeout),
advancedSettings: data.get(#advancedSettings, or: $value.advancedSettings));
shareViaLinkAutoAccept:
data.get(#shareViaLinkAutoAccept, or: $value.shareViaLinkAutoAccept),
discoveryTimeout:
data.get(#discoveryTimeout, or: $value.discoveryTimeout),
advancedSettings:
data.get(#advancedSettings, or: $value.advancedSettings));
@override
SettingsStateCopyWith<$R2, SettingsState, $Out2> $chain<$R2, $Out2>(Then<$Out2, $R2> t) => _SettingsStateCopyWithImpl($value, $cast, t);
SettingsStateCopyWith<$R2, SettingsState, $Out2> $chain<$R2, $Out2>(
Then<$Out2, $R2> t) =>
_SettingsStateCopyWithImpl($value, $cast, t);
}
+1 -1
View File
@@ -16,7 +16,7 @@ class DonationPage extends StatelessWidget {
@override
Widget build(BuildContext context) {
return ViewModelBuilder(
provider: donationPageVmProvider,
provider: (ref) => donationPageVmProvider,
// [FOSS_REMOVE_START]
init: (context) => context.redux(purchaseProvider).dispatchAsync(FetchPricesAndPurchasesAction()), // ignore: discarded_futures
// [FOSS_REMOVE_END]
+12 -9
View File
@@ -9,6 +9,7 @@ import 'package:flutter/gestures.dart';
import 'package:flutter/material.dart';
import 'package:localsend_app/config/theme.dart';
import 'package:localsend_app/gen/strings.g.dart';
import 'package:localsend_app/model/state/server/receive_session_state.dart';
import 'package:localsend_app/provider/network/send_provider.dart';
import 'package:localsend_app/provider/network/server/server_provider.dart';
import 'package:localsend_app/provider/progress_provider.dart';
@@ -184,7 +185,15 @@ class _ProgressPageState extends State<ProgressPage> with Refena {
final receiveSession = ref.watch(serverProvider.select((s) => s?.session));
final sendSession = ref.watch(sendProvider)[widget.sessionId];
final SessionStatus? status = receiveSession?.status ?? sendSession?.status;
final SessionState? commonSessionState = receiveSession ?? sendSession;
if (commonSessionState == null) {
return Scaffold(
body: Container(),
);
}
final status = commonSessionState.status;
if (status == SessionStatus.sending) {
// ignore: discarded_futures
@@ -195,15 +204,9 @@ class _ProgressPageState extends State<ProgressPage> with Refena {
TaskbarHelper.visualizeStatus(status);
}
if (status == null) {
return Scaffold(
body: Container(),
);
}
final title = receiveSession != null ? t.progressPage.titleReceiving : t.progressPage.titleSending;
final startTime = receiveSession?.startTime ?? sendSession?.startTime;
final endTime = receiveSession?.endTime ?? sendSession?.endTime;
final startTime = commonSessionState.startTime;
final endTime = commonSessionState.endTime;
final int? speedInBytes;
if (startTime != null && currBytes >= 500 * 1024) {
speedInBytes = getFileSpeed(start: startTime, end: endTime ?? DateTime.now().millisecondsSinceEpoch, bytes: currBytes);
+28 -3
View File
@@ -1,11 +1,12 @@
import 'dart:io';
import 'package:common/model/device.dart';
import 'package:common/model/session_status.dart';
import 'package:flutter/material.dart';
import 'package:localsend_app/config/theme.dart';
import 'package:localsend_app/gen/strings.g.dart';
import 'package:localsend_app/model/persistence/receive_history_entry.dart';
import 'package:localsend_app/pages/receive_page.dart';
import 'package:localsend_app/pages/receive_page_controller.dart';
import 'package:localsend_app/provider/receive_history_provider.dart';
import 'package:localsend_app/provider/settings_provider.dart';
import 'package:localsend_app/util/file_size_helper.dart';
@@ -129,9 +130,33 @@ class ReceiveHistoryPage extends StatelessWidget {
onTap: entry.path != null || entry.isMessage
? () async {
if (entry.isMessage) {
context.redux(receivePageControllerProvider).dispatch(InitReceivePageFromHistoryMessageAction(entry: entry));
final vm = ViewProvider((ref) {
return ReceivePageVm(
status: SessionStatus.waiting,
sender: Device(
signalingId: null,
ip: '0.0.0.0',
version: '1.0.0',
port: 8080,
https: false,
fingerprint: 'fingerprint',
alias: entry.senderAlias,
deviceModel: 'deviceModel',
deviceType: DeviceType.web,
download: true,
discoveryMethods: const {},
),
showSenderInfo: false,
files: [],
message: entry.fileName,
onAccept: () {},
onDecline: () {},
onClose: () {},
);
});
// ignore: unawaited_futures
context.push(() => const ReceivePage());
context.push(() => ReceivePage(vm));
return;
}
+18 -19
View File
@@ -1,5 +1,6 @@
import 'package:flutter/material.dart';
import 'package:localsend_app/gen/strings.g.dart';
import 'package:localsend_app/pages/receive_page.dart';
import 'package:localsend_app/provider/network/server/server_provider.dart';
import 'package:localsend_app/provider/selection/selected_receiving_files_provider.dart';
import 'package:localsend_app/util/file_size_helper.dart';
@@ -14,7 +15,9 @@ import 'package:localsend_app/widget/responsive_list_view.dart';
import 'package:refena_flutter/refena_flutter.dart';
class ReceiveOptionsPage extends StatelessWidget {
const ReceiveOptionsPage({super.key});
final ReceivePageVm vm;
const ReceiveOptionsPage(this.vm);
@override
Widget build(BuildContext context) {
@@ -109,42 +112,38 @@ class ReceiveOptionsPage extends StatelessWidget {
Tooltip(
message: t.general.reset,
child: CustomIconButton(
onPressed: () async {
ref.notifier(selectedReceivingFilesProvider).setFiles(receiveSession.files.values.map((f) => f.file).toList());
},
onPressed: () => ref.notifier(selectedReceivingFilesProvider).setFiles(vm.files),
child: const Icon(Icons.undo),
),
),
],
),
const SizedBox(height: 5),
...receiveSession.files.values.map((file) {
...vm.files.map((file) {
return Padding(
padding: const EdgeInsets.only(bottom: 10),
child: Row(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Icon(file.file.fileType.icon, size: 46),
Icon(file.fileType.icon, size: 46),
const SizedBox(width: 10),
Expanded(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
selectState[file.file.id] ?? file.file.fileName,
selectState[file.id] ?? file.fileName,
style: const TextStyle(fontSize: 16),
maxLines: 1,
overflow: TextOverflow.fade,
softWrap: false,
),
Text(
'${!selectState.containsKey(file.file.id) ? t.general.skipped : (selectState[file.file.id] == file.file.fileName ? t.general.unchanged : t.general.renamed)} - ${file.file.size.asReadableFileSize}',
'${!selectState.containsKey(file.id) ? t.general.skipped : (selectState[file.id] == file.fileName ? t.general.unchanged : t.general.renamed)} - ${file.size.asReadableFileSize}',
style: TextStyle(
color: !selectState.containsKey(file.file.id)
color: !selectState.containsKey(file.id)
? Colors.grey
: (selectState[file.file.id] == file.file.fileName
? Theme.of(context).colorScheme.onSecondaryContainer
: Colors.orange)),
: (selectState[file.id] == file.fileName ? Theme.of(context).colorScheme.onSecondaryContainer : Colors.orange)),
)
],
),
@@ -153,31 +152,31 @@ class ReceiveOptionsPage extends StatelessWidget {
mainAxisSize: MainAxisSize.min,
children: [
CustomIconButton(
onPressed: selectState[file.file.id] == null
onPressed: selectState[file.id] == null
? null
: () async {
final result = await showDialog<String>(
context: context,
builder: (_) => FileNameInputDialog(
originalName: file.file.fileName,
initialName: selectState[file.file.id]!,
originalName: file.fileName,
initialName: selectState[file.id]!,
),
);
if (result != null) {
ref.notifier(selectedReceivingFilesProvider).rename(file.file.id, result);
ref.notifier(selectedReceivingFilesProvider).rename(file.id, result);
}
},
child: const Icon(Icons.edit),
),
Checkbox(
value: selectState.containsKey(file.file.id),
value: selectState.containsKey(file.id),
activeColor: Theme.of(context).colorScheme.onSurface,
checkColor: Theme.of(context).colorScheme.surface,
onChanged: (selected) {
if (selected == true) {
ref.notifier(selectedReceivingFilesProvider).select(file.file);
ref.notifier(selectedReceivingFilesProvider).select(file);
} else {
ref.notifier(selectedReceivingFilesProvider).unselect(file.file.id);
ref.notifier(selectedReceivingFilesProvider).unselect(file.id);
}
},
),
+178 -132
View File
@@ -1,5 +1,7 @@
import 'dart:async';
import 'package:common/model/device.dart';
import 'package:common/model/dto/file_dto.dart';
import 'package:common/model/session_status.dart';
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
@@ -7,7 +9,6 @@ import 'package:localsend_app/config/theme.dart';
import 'package:localsend_app/gen/strings.g.dart';
import 'package:localsend_app/model/persistence/color_mode.dart';
import 'package:localsend_app/pages/receive_options_page.dart';
import 'package:localsend_app/pages/receive_page_controller.dart';
import 'package:localsend_app/provider/favorites_provider.dart';
import 'package:localsend_app/provider/selection/selected_receiving_files_provider.dart';
import 'package:localsend_app/provider/settings_provider.dart';
@@ -23,23 +24,46 @@ import 'package:refena_flutter/refena_flutter.dart';
import 'package:routerino/routerino.dart';
import 'package:url_launcher/url_launcher.dart';
class ReceivePageVm {
final SessionStatus? status;
final Device sender;
/// Show hashtag and device model.
final bool showSenderInfo;
final List<FileDto> files;
final String? message;
final bool isLink;
final void Function() onAccept;
final void Function() onDecline;
final void Function() onClose;
ReceivePageVm({
required this.status,
required this.sender,
required this.showSenderInfo,
required this.files,
required this.message,
required this.onAccept,
required this.onDecline,
required this.onClose,
}) : isLink = message != null && (Uri.tryParse(message)?.isAbsolute ?? false);
}
class ReceivePage extends StatefulWidget {
const ReceivePage({super.key});
final ViewProvider<ReceivePageVm> vm;
const ReceivePage(this.vm);
@override
State<ReceivePage> createState() => _ReceivePageState();
}
class _ReceivePageState extends State<ReceivePage> with Refena {
@override
void dispose() {
super.dispose();
unawaited(TaskbarHelper.clearProgressBar());
}
bool _showFullIp = false;
@override
Widget build(BuildContext context) {
final vm = context.watch(receivePageControllerProvider, listener: (prev, next) {
final vm = context.watch(widget.vm, listener: (prev, next) {
if (prev.status != next.status) {
// ignore: discarded_futures
TaskbarHelper.visualizeStatus(next.status);
@@ -54,148 +78,170 @@ class _ReceivePageState extends State<ReceivePage> with Refena {
final senderFavoriteEntry = ref.watch(favoritesProvider.select((state) => state.findDevice(vm.sender)));
return PopScope(
onPopInvokedWithResult: (didPop, result) {
if (didPop) {
vm.onDecline();
}
},
canPop: true,
child: Scaffold(
body: SafeArea(
child: Center(
child: ConstrainedBox(
constraints: const BoxConstraints(maxWidth: ResponsiveListView.defaultMaxWidth),
child: Builder(
builder: (context) {
final height = MediaQuery.of(context).size.height;
final smallUi = vm.message != null && height < 600;
return Padding(
padding: EdgeInsets.symmetric(horizontal: 20, vertical: smallUi ? 20 : 30),
child: Column(
children: [
Expanded(
return ViewModelBuilder(
provider: (ref) => widget.vm,
onFirstFrame: (context, vm) {
ref.notifier(selectedReceivingFilesProvider).setFiles(vm.files);
},
dispose: (ref) {
ref.dispose(widget.vm);
unawaited(TaskbarHelper.clearProgressBar());
},
builder: (context, vm) {
return PopScope(
onPopInvokedWithResult: (didPop, result) {
if (didPop) {
vm.onDecline();
}
},
canPop: true,
child: Scaffold(
body: SafeArea(
child: Center(
child: ConstrainedBox(
constraints: const BoxConstraints(maxWidth: ResponsiveListView.defaultMaxWidth),
child: Builder(
builder: (context) {
final height = MediaQuery.of(context).size.height;
final smallUi = vm.message != null && height < 600;
return Padding(
padding: EdgeInsets.symmetric(horizontal: 20, vertical: smallUi ? 20 : 30),
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
if (vm.showSenderInfo && !smallUi)
Padding(
padding: const EdgeInsets.only(bottom: 10),
child: Icon(vm.sender.deviceType.icon, size: 64),
),
FittedBox(
child: Text(
senderFavoriteEntry?.alias ?? vm.sender.alias,
style: TextStyle(fontSize: smallUi ? 32 : 48),
textAlign: TextAlign.center,
),
),
if (vm.showSenderInfo) ...[
const SizedBox(height: 10),
Row(
Expanded(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
InkWell(
onTap: () {
context.redux(receivePageControllerProvider).dispatch(SetShowFullIpAction(!vm.showFullIp));
},
child: DeviceBadge(
backgroundColor: Theme.of(context).colorScheme.onSecondaryContainer,
foregroundColor: Theme.of(context).colorScheme.onInverseSurface,
label: vm.showFullIp ? vm.sender.ip : '#${vm.sender.ip.visualId}',
if (vm.showSenderInfo && !smallUi)
Padding(
padding: const EdgeInsets.only(bottom: 10),
child: Icon(vm.sender.deviceType.icon, size: 64),
),
),
if (vm.sender.deviceModel != null) ...[
const SizedBox(width: 10),
DeviceBadge(
backgroundColor: Theme.of(context).colorScheme.onSecondaryContainer,
foregroundColor: Theme.of(context).colorScheme.onInverseSurface,
label: vm.sender.deviceModel!,
Builder(builder: (context) {
final alias = senderFavoriteEntry?.alias ?? vm.sender.alias;
if (alias.isEmpty) {
return Text('', style: TextStyle(fontSize: smallUi ? 32 : 48));
}
return FittedBox(
child: Text(
alias,
style: TextStyle(fontSize: smallUi ? 32 : 48),
textAlign: TextAlign.center,
),
);
}),
if (vm.showSenderInfo) ...[
const SizedBox(height: 10),
Row(
mainAxisAlignment: MainAxisAlignment.center,
children: [
InkWell(
onTap: () {
setState(() {
_showFullIp = !_showFullIp;
});
},
child: DeviceBadge(
backgroundColor: Theme.of(context).colorScheme.onSecondaryContainer,
foregroundColor: Theme.of(context).colorScheme.onInverseSurface,
label: switch (vm.sender.ip) {
String ip => _showFullIp ? ip : '#${ip.visualId}',
null => 'WebRTC',
},
),
),
if (vm.sender.deviceModel != null) ...[
const SizedBox(width: 10),
DeviceBadge(
backgroundColor: Theme.of(context).colorScheme.onSecondaryContainer,
foregroundColor: Theme.of(context).colorScheme.onInverseSurface,
label: vm.sender.deviceModel!,
),
],
],
),
],
],
),
],
const SizedBox(height: 40),
Text(
vm.message != null
? (vm.isLink ? t.receivePage.subTitleLink : t.receivePage.subTitleMessage)
: t.receivePage.subTitle(n: vm.fileCount),
style: smallUi ? null : Theme.of(context).textTheme.titleLarge,
textAlign: TextAlign.center,
),
if (vm.message != null)
Column(
crossAxisAlignment: CrossAxisAlignment.stretch,
children: [
Padding(
padding: const EdgeInsets.only(top: 20),
child: SizedBox(
height: 100,
child: Card(
child: SingleChildScrollView(
child: Padding(
padding: const EdgeInsets.all(10),
child: SelectableText(
vm.message!,
),
),
),
),
),
const SizedBox(height: 40),
Text(
vm.message != null
? (vm.isLink ? t.receivePage.subTitleLink : t.receivePage.subTitleMessage)
: t.receivePage.subTitle(n: vm.files.length),
style: smallUi ? null : Theme.of(context).textTheme.titleLarge,
textAlign: TextAlign.center,
),
const SizedBox(height: 10),
Row(
mainAxisAlignment: MainAxisAlignment.center,
children: [
ElevatedButton(
onPressed: () {
unawaited(
Clipboard.setData(ClipboardData(text: vm.message!)),
);
if (checkPlatformIsDesktop()) {
context.showSnackBar(t.general.copiedToClipboard);
}
vm.onAccept();
context.pop();
},
child: Text(t.general.copy),
),
if (vm.isLink)
if (vm.message != null)
Column(
crossAxisAlignment: CrossAxisAlignment.stretch,
children: [
Padding(
padding: const EdgeInsetsDirectional.only(start: 20),
child: ElevatedButton(
style: ElevatedButton.styleFrom(
backgroundColor: Theme.of(context).colorScheme.primary,
foregroundColor: Theme.of(context).colorScheme.onPrimary,
padding: const EdgeInsets.only(top: 20),
child: SizedBox(
height: 100,
child: Card(
child: SingleChildScrollView(
child: Padding(
padding: const EdgeInsets.all(10),
child: SelectableText(
vm.message!,
),
),
),
),
onPressed: () {
// ignore: discarded_futures
launchUrl(Uri.parse(vm.message!), mode: LaunchMode.externalApplication);
vm.onAccept();
context.pop();
},
child: Text(t.general.open),
),
),
],
),
const SizedBox(height: 10),
Row(
mainAxisAlignment: MainAxisAlignment.center,
children: [
ElevatedButton(
onPressed: () {
unawaited(
Clipboard.setData(ClipboardData(text: vm.message!)),
);
if (checkPlatformIsDesktop()) {
context.showSnackBar(t.general.copiedToClipboard);
}
vm.onAccept();
context.pop();
},
child: Text(t.general.copy),
),
if (vm.isLink)
Padding(
padding: const EdgeInsetsDirectional.only(start: 20),
child: ElevatedButton(
style: ElevatedButton.styleFrom(
backgroundColor: Theme.of(context).colorScheme.primary,
foregroundColor: Theme.of(context).colorScheme.onPrimary,
),
onPressed: () {
// ignore: discarded_futures
launchUrl(Uri.parse(vm.message!), mode: LaunchMode.externalApplication);
vm.onAccept();
context.pop();
},
child: Text(t.general.open),
),
),
],
),
],
),
],
),
),
_Actions(vm),
],
),
),
_Actions(vm),
],
);
},
),
);
},
),
),
),
),
),
),
),
);
);
});
}
}
@@ -259,7 +305,7 @@ class _Actions extends StatelessWidget {
foregroundColor: Theme.of(context).colorScheme.onSurface,
),
onPressed: () async {
await context.push(() => const ReceiveOptionsPage());
await context.push(() => ReceiveOptionsPage(vm));
},
icon: const Icon(Icons.settings),
label: Text(t.receiveOptionsPage.title),
-194
View File
@@ -1,194 +0,0 @@
import 'package:common/model/device.dart';
import 'package:common/model/session_status.dart';
import 'package:dart_mappable/dart_mappable.dart';
import 'package:localsend_app/model/persistence/receive_history_entry.dart';
import 'package:localsend_app/pages/progress_page.dart';
import 'package:localsend_app/pages/receive_page.dart';
import 'package:localsend_app/provider/network/server/server_provider.dart';
import 'package:localsend_app/provider/selection/selected_receiving_files_provider.dart';
import 'package:refena_flutter/refena_flutter.dart';
import 'package:routerino/routerino.dart';
part 'receive_page_controller.mapper.dart';
@MappableClass()
class ReceivePageVm with ReceivePageVmMappable {
final SessionStatus? status;
final Device sender;
/// Show hashtag and device model.
final bool showSenderInfo;
final int fileCount;
final String? message;
final bool isLink;
final bool showFullIp;
final void Function() onAccept;
final void Function() onDecline;
final void Function() onClose;
ReceivePageVm({
required this.status,
required this.sender,
required this.showSenderInfo,
required this.fileCount,
required this.message,
required this.isLink,
required this.showFullIp,
required this.onAccept,
required this.onDecline,
required this.onClose,
});
}
final receivePageControllerProvider = ReduxProvider<ReceivePageController, ReceivePageVm>((ref) {
return ReceivePageController(
server: ref.notifier(serverProvider),
selectedReceivingFiles: ref.notifier(selectedReceivingFilesProvider),
);
});
class ReceivePageController extends ReduxNotifier<ReceivePageVm> {
final ServerService _server;
final SelectedReceivingFilesNotifier _selectedReceivingFiles;
ReceivePageController({
required ServerService server,
required SelectedReceivingFilesNotifier selectedReceivingFiles,
}) : _server = server,
_selectedReceivingFiles = selectedReceivingFiles;
@override
ReceivePageVm init() {
return ReceivePageVm(
status: SessionStatus.waiting,
sender: const Device(
ip: '0.0.0.0',
version: '1.0.0',
port: 8080,
https: false,
fingerprint: 'fingerprint',
alias: 'alias',
deviceModel: 'deviceModel',
deviceType: DeviceType.desktop,
download: true,
),
showSenderInfo: true,
fileCount: 1,
message: 'message',
isLink: false,
showFullIp: false,
onAccept: () {},
onDecline: () {},
onClose: () {},
);
}
@override
get initialAction => _WatchStatusAction();
}
class _WatchStatusAction extends WatchAction<ReceivePageController, ReceivePageVm> {
@override
ReceivePageVm reduce() {
return state.copyWith(
status: ref.watch(serverProvider.select((state) => state?.session?.status)),
);
}
}
class InitReceivePageAction extends ReduxAction<ReceivePageController, ReceivePageVm> {
@override
ReceivePageVm reduce() {
final receiveSession = notifier._server.state?.session;
if (receiveSession == null) {
return state;
}
return state.copyWith(
sender: receiveSession.sender,
showSenderInfo: true,
fileCount: receiveSession.files.length,
message: receiveSession.message,
isLink: receiveSession.message != null && (receiveSession.message!.isLink),
showFullIp: false,
onAccept: () async {
if (state.message != null) {
// accept nothing
notifier._server.acceptFileRequest({});
return;
}
final sessionId = notifier._server.state?.session?.sessionId;
if (sessionId == null) {
return;
}
final selectedFiles = notifier._selectedReceivingFiles.state;
notifier._server.acceptFileRequest(selectedFiles);
await Routerino.context.pushAndRemoveUntilImmediately(
removeUntil: ReceivePage,
builder: () => ProgressPage(
showAppBar: false,
closeSessionOnClose: true,
sessionId: sessionId,
),
);
},
onDecline: () {
notifier._server.declineFileRequest();
},
onClose: () {
notifier._server.closeSession();
},
);
}
}
class InitReceivePageFromHistoryMessageAction extends ReduxAction<ReceivePageController, ReceivePageVm> {
final ReceiveHistoryEntry entry;
InitReceivePageFromHistoryMessageAction({required this.entry});
@override
ReceivePageVm reduce() {
return state.copyWith(
sender: Device(
ip: '0.0.0.0',
version: '1.0.0',
port: 8080,
https: false,
fingerprint: 'fingerprint',
alias: entry.senderAlias,
deviceModel: 'deviceModel',
deviceType: DeviceType.web,
download: true,
),
showSenderInfo: false,
fileCount: 1,
message: entry.fileName,
isLink: entry.fileName.isLink,
showFullIp: false,
onAccept: () {},
onDecline: () {},
onClose: () {},
);
}
}
class SetShowFullIpAction extends ReduxAction<ReceivePageController, ReceivePageVm> {
final bool showFullIp;
SetShowFullIpAction(this.showFullIp);
@override
ReceivePageVm reduce() {
return state.copyWith(
showFullIp: showFullIp,
);
}
}
extension on String {
bool get isLink => Uri.tryParse(this)?.isAbsolute ?? false;
}
@@ -1,182 +0,0 @@
// coverage:ignore-file
// GENERATED CODE - DO NOT MODIFY BY HAND
// ignore_for_file: type=lint
// ignore_for_file: unused_element, unnecessary_cast, override_on_non_overriding_member
// ignore_for_file: strict_raw_type, inference_failure_on_untyped_parameter
part of 'receive_page_controller.dart';
class ReceivePageVmMapper extends ClassMapperBase<ReceivePageVm> {
ReceivePageVmMapper._();
static ReceivePageVmMapper? _instance;
static ReceivePageVmMapper ensureInitialized() {
if (_instance == null) {
MapperContainer.globals.use(_instance = ReceivePageVmMapper._());
DeviceMapper.ensureInitialized();
}
return _instance!;
}
@override
final String id = 'ReceivePageVm';
static SessionStatus? _$status(ReceivePageVm v) => v.status;
static const Field<ReceivePageVm, SessionStatus> _f$status = Field('status', _$status);
static Device _$sender(ReceivePageVm v) => v.sender;
static const Field<ReceivePageVm, Device> _f$sender = Field('sender', _$sender);
static bool _$showSenderInfo(ReceivePageVm v) => v.showSenderInfo;
static const Field<ReceivePageVm, bool> _f$showSenderInfo = Field('showSenderInfo', _$showSenderInfo);
static int _$fileCount(ReceivePageVm v) => v.fileCount;
static const Field<ReceivePageVm, int> _f$fileCount = Field('fileCount', _$fileCount);
static String? _$message(ReceivePageVm v) => v.message;
static const Field<ReceivePageVm, String> _f$message = Field('message', _$message);
static bool _$isLink(ReceivePageVm v) => v.isLink;
static const Field<ReceivePageVm, bool> _f$isLink = Field('isLink', _$isLink);
static bool _$showFullIp(ReceivePageVm v) => v.showFullIp;
static const Field<ReceivePageVm, bool> _f$showFullIp = Field('showFullIp', _$showFullIp);
static Function _$onAccept(ReceivePageVm v) => (v as dynamic).onAccept as Function;
static dynamic _arg$onAccept(f) => f<void Function()>();
static const Field<ReceivePageVm, Function> _f$onAccept = Field('onAccept', _$onAccept, arg: _arg$onAccept);
static Function _$onDecline(ReceivePageVm v) => (v as dynamic).onDecline as Function;
static dynamic _arg$onDecline(f) => f<void Function()>();
static const Field<ReceivePageVm, Function> _f$onDecline = Field('onDecline', _$onDecline, arg: _arg$onDecline);
static Function _$onClose(ReceivePageVm v) => (v as dynamic).onClose as Function;
static dynamic _arg$onClose(f) => f<void Function()>();
static const Field<ReceivePageVm, Function> _f$onClose = Field('onClose', _$onClose, arg: _arg$onClose);
@override
final MappableFields<ReceivePageVm> fields = const {
#status: _f$status,
#sender: _f$sender,
#showSenderInfo: _f$showSenderInfo,
#fileCount: _f$fileCount,
#message: _f$message,
#isLink: _f$isLink,
#showFullIp: _f$showFullIp,
#onAccept: _f$onAccept,
#onDecline: _f$onDecline,
#onClose: _f$onClose,
};
static ReceivePageVm _instantiate(DecodingData data) {
return ReceivePageVm(
status: data.dec(_f$status),
sender: data.dec(_f$sender),
showSenderInfo: data.dec(_f$showSenderInfo),
fileCount: data.dec(_f$fileCount),
message: data.dec(_f$message),
isLink: data.dec(_f$isLink),
showFullIp: data.dec(_f$showFullIp),
onAccept: data.dec(_f$onAccept),
onDecline: data.dec(_f$onDecline),
onClose: data.dec(_f$onClose));
}
@override
final Function instantiate = _instantiate;
static ReceivePageVm fromJson(Map<String, dynamic> map) {
return ensureInitialized().decodeMap<ReceivePageVm>(map);
}
static ReceivePageVm deserialize(String json) {
return ensureInitialized().decodeJson<ReceivePageVm>(json);
}
}
mixin ReceivePageVmMappable {
String serialize() {
return ReceivePageVmMapper.ensureInitialized().encodeJson<ReceivePageVm>(this as ReceivePageVm);
}
Map<String, dynamic> toJson() {
return ReceivePageVmMapper.ensureInitialized().encodeMap<ReceivePageVm>(this as ReceivePageVm);
}
ReceivePageVmCopyWith<ReceivePageVm, ReceivePageVm, ReceivePageVm> get copyWith =>
_ReceivePageVmCopyWithImpl(this as ReceivePageVm, $identity, $identity);
@override
String toString() {
return ReceivePageVmMapper.ensureInitialized().stringifyValue(this as ReceivePageVm);
}
@override
bool operator ==(Object other) {
return ReceivePageVmMapper.ensureInitialized().equalsValue(this as ReceivePageVm, other);
}
@override
int get hashCode {
return ReceivePageVmMapper.ensureInitialized().hashValue(this as ReceivePageVm);
}
}
extension ReceivePageVmValueCopy<$R, $Out> on ObjectCopyWith<$R, ReceivePageVm, $Out> {
ReceivePageVmCopyWith<$R, ReceivePageVm, $Out> get $asReceivePageVm => $base.as((v, t, t2) => _ReceivePageVmCopyWithImpl(v, t, t2));
}
abstract class ReceivePageVmCopyWith<$R, $In extends ReceivePageVm, $Out> implements ClassCopyWith<$R, $In, $Out> {
DeviceCopyWith<$R, Device, Device> get sender;
$R call(
{SessionStatus? status,
Device? sender,
bool? showSenderInfo,
int? fileCount,
String? message,
bool? isLink,
bool? showFullIp,
void Function()? onAccept,
void Function()? onDecline,
void Function()? onClose});
ReceivePageVmCopyWith<$R2, $In, $Out2> $chain<$R2, $Out2>(Then<$Out2, $R2> t);
}
class _ReceivePageVmCopyWithImpl<$R, $Out> extends ClassCopyWithBase<$R, ReceivePageVm, $Out>
implements ReceivePageVmCopyWith<$R, ReceivePageVm, $Out> {
_ReceivePageVmCopyWithImpl(super.value, super.then, super.then2);
@override
late final ClassMapperBase<ReceivePageVm> $mapper = ReceivePageVmMapper.ensureInitialized();
@override
DeviceCopyWith<$R, Device, Device> get sender => $value.sender.copyWith.$chain((v) => call(sender: v));
@override
$R call(
{Object? status = $none,
Device? sender,
bool? showSenderInfo,
int? fileCount,
Object? message = $none,
bool? isLink,
bool? showFullIp,
void Function()? onAccept,
void Function()? onDecline,
void Function()? onClose}) =>
$apply(FieldCopyWithData({
if (status != $none) #status: status,
if (sender != null) #sender: sender,
if (showSenderInfo != null) #showSenderInfo: showSenderInfo,
if (fileCount != null) #fileCount: fileCount,
if (message != $none) #message: message,
if (isLink != null) #isLink: isLink,
if (showFullIp != null) #showFullIp: showFullIp,
if (onAccept != null) #onAccept: onAccept,
if (onDecline != null) #onDecline: onDecline,
if (onClose != null) #onClose: onClose
}));
@override
ReceivePageVm $make(CopyWithData data) => ReceivePageVm(
status: data.get(#status, or: $value.status),
sender: data.get(#sender, or: $value.sender),
showSenderInfo: data.get(#showSenderInfo, or: $value.showSenderInfo),
fileCount: data.get(#fileCount, or: $value.fileCount),
message: data.get(#message, or: $value.message),
isLink: data.get(#isLink, or: $value.isLink),
showFullIp: data.get(#showFullIp, or: $value.showFullIp),
onAccept: data.get(#onAccept, or: $value.onAccept),
onDecline: data.get(#onDecline, or: $value.onDecline),
onClose: data.get(#onClose, or: $value.onClose));
@override
ReceivePageVmCopyWith<$R2, ReceivePageVm, $Out2> $chain<$R2, $Out2>(Then<$Out2, $R2> t) => _ReceivePageVmCopyWithImpl($value, $cast, t);
}
+2 -2
View File
@@ -44,7 +44,7 @@ class SendTab extends StatelessWidget {
@override
Widget build(BuildContext context) {
return ViewModelBuilder(
provider: sendTabVmProvider,
provider: (ref) => sendTabVmProvider,
init: (context) async => context.global.dispatchAsync(SendTabInitAction(context)), // ignore: discarded_futures
builder: (context, vm) {
final sizingInformation = SizingInformation(MediaQuery.sizeOf(context).width);
@@ -546,7 +546,7 @@ class _MultiSendDeviceListTile extends StatelessWidget {
progress: progress,
isFavorite: isFavorite,
nameOverride: nameOverride,
onFavoriteTap: () async => await vm.onToggleFavorite(context, device),
onFavoriteTap: device.ip == null ? null : () async => await vm.onToggleFavorite(context, device),
onTap: () async => await vm.onTapDeviceMultiSend(context, device),
);
}
+1 -1
View File
@@ -56,7 +56,7 @@ final sendTabVmProvider = ViewProvider((ref) {
final sendMode = ref.watch(settingsProvider.select((s) => s.sendMode));
final selectedFiles = ref.watch(selectedSendingFilesProvider);
final localIps = ref.watch(localIpProvider).localIps;
final nearbyDevices = ref.watch(nearbyDevicesProvider).devices.values;
final nearbyDevices = ref.watch(nearbyDevicesProvider).allDevices.values;
final favoriteDevices = ref.watch(favoritesProvider);
return SendTabVm(
+1 -1
View File
@@ -41,7 +41,7 @@ class SettingsTab extends StatelessWidget {
@override
Widget build(BuildContext context) {
return ViewModelBuilder(
provider: settingsTabControllerProvider,
provider: (ref) => settingsTabControllerProvider,
builder: (context, vm) {
final ref = context.ref;
return Stack(
+162 -78
View File
@@ -23,65 +23,113 @@ class SettingsTabVmMapper extends ClassMapperBase<SettingsTabVm> {
final String id = 'SettingsTabVm';
static bool _$advanced(SettingsTabVm v) => v.advanced;
static const Field<SettingsTabVm, bool> _f$advanced = Field('advanced', _$advanced);
static TextEditingController _$aliasController(SettingsTabVm v) => v.aliasController;
static const Field<SettingsTabVm, TextEditingController> _f$aliasController = Field('aliasController', _$aliasController);
static TextEditingController _$deviceModelController(SettingsTabVm v) => v.deviceModelController;
static const Field<SettingsTabVm, TextEditingController> _f$deviceModelController = Field('deviceModelController', _$deviceModelController);
static TextEditingController _$portController(SettingsTabVm v) => v.portController;
static const Field<SettingsTabVm, TextEditingController> _f$portController = Field('portController', _$portController);
static TextEditingController _$timeoutController(SettingsTabVm v) => v.timeoutController;
static const Field<SettingsTabVm, TextEditingController> _f$timeoutController = Field('timeoutController', _$timeoutController);
static TextEditingController _$multicastController(SettingsTabVm v) => v.multicastController;
static const Field<SettingsTabVm, TextEditingController> _f$multicastController = Field('multicastController', _$multicastController);
static const Field<SettingsTabVm, bool> _f$advanced =
Field('advanced', _$advanced);
static TextEditingController _$aliasController(SettingsTabVm v) =>
v.aliasController;
static const Field<SettingsTabVm, TextEditingController> _f$aliasController =
Field('aliasController', _$aliasController);
static TextEditingController _$deviceModelController(SettingsTabVm v) =>
v.deviceModelController;
static const Field<SettingsTabVm, TextEditingController>
_f$deviceModelController =
Field('deviceModelController', _$deviceModelController);
static TextEditingController _$portController(SettingsTabVm v) =>
v.portController;
static const Field<SettingsTabVm, TextEditingController> _f$portController =
Field('portController', _$portController);
static TextEditingController _$timeoutController(SettingsTabVm v) =>
v.timeoutController;
static const Field<SettingsTabVm, TextEditingController>
_f$timeoutController = Field('timeoutController', _$timeoutController);
static TextEditingController _$multicastController(SettingsTabVm v) =>
v.multicastController;
static const Field<SettingsTabVm, TextEditingController>
_f$multicastController =
Field('multicastController', _$multicastController);
static SettingsState _$settings(SettingsTabVm v) => v.settings;
static const Field<SettingsTabVm, SettingsState> _f$settings = Field('settings', _$settings);
static const Field<SettingsTabVm, SettingsState> _f$settings =
Field('settings', _$settings);
static ServerState? _$serverState(SettingsTabVm v) => v.serverState;
static const Field<SettingsTabVm, ServerState> _f$serverState = Field('serverState', _$serverState);
static const Field<SettingsTabVm, ServerState> _f$serverState =
Field('serverState', _$serverState);
static DeviceInfoResult _$deviceInfo(SettingsTabVm v) => v.deviceInfo;
static const Field<SettingsTabVm, DeviceInfoResult> _f$deviceInfo = Field('deviceInfo', _$deviceInfo);
static const Field<SettingsTabVm, DeviceInfoResult> _f$deviceInfo =
Field('deviceInfo', _$deviceInfo);
static List<ColorMode> _$colorModes(SettingsTabVm v) => v.colorModes;
static const Field<SettingsTabVm, List<ColorMode>> _f$colorModes = Field('colorModes', _$colorModes);
static const Field<SettingsTabVm, List<ColorMode>> _f$colorModes =
Field('colorModes', _$colorModes);
static bool _$autoStart(SettingsTabVm v) => v.autoStart;
static const Field<SettingsTabVm, bool> _f$autoStart = Field('autoStart', _$autoStart);
static bool _$autoStartLaunchHidden(SettingsTabVm v) => v.autoStartLaunchHidden;
static const Field<SettingsTabVm, bool> _f$autoStartLaunchHidden = Field('autoStartLaunchHidden', _$autoStartLaunchHidden);
static const Field<SettingsTabVm, bool> _f$autoStart =
Field('autoStart', _$autoStart);
static bool _$autoStartLaunchHidden(SettingsTabVm v) =>
v.autoStartLaunchHidden;
static const Field<SettingsTabVm, bool> _f$autoStartLaunchHidden =
Field('autoStartLaunchHidden', _$autoStartLaunchHidden);
static bool _$showInContextMenu(SettingsTabVm v) => v.showInContextMenu;
static const Field<SettingsTabVm, bool> _f$showInContextMenu = Field('showInContextMenu', _$showInContextMenu);
static Function _$onChangeTheme(SettingsTabVm v) => (v as dynamic).onChangeTheme as Function;
static dynamic _arg$onChangeTheme(f) => f<void Function(BuildContext, ThemeMode)>();
static const Field<SettingsTabVm, Function> _f$onChangeTheme = Field('onChangeTheme', _$onChangeTheme, arg: _arg$onChangeTheme);
static Function _$onChangeColorMode(SettingsTabVm v) => (v as dynamic).onChangeColorMode as Function;
static const Field<SettingsTabVm, bool> _f$showInContextMenu =
Field('showInContextMenu', _$showInContextMenu);
static Function _$onChangeTheme(SettingsTabVm v) =>
(v as dynamic).onChangeTheme as Function;
static dynamic _arg$onChangeTheme(f) =>
f<void Function(BuildContext, ThemeMode)>();
static const Field<SettingsTabVm, Function> _f$onChangeTheme =
Field('onChangeTheme', _$onChangeTheme, arg: _arg$onChangeTheme);
static Function _$onChangeColorMode(SettingsTabVm v) =>
(v as dynamic).onChangeColorMode as Function;
static dynamic _arg$onChangeColorMode(f) => f<void Function(ColorMode)>();
static const Field<SettingsTabVm, Function> _f$onChangeColorMode = Field('onChangeColorMode', _$onChangeColorMode, arg: _arg$onChangeColorMode);
static Function _$onTapLanguage(SettingsTabVm v) => (v as dynamic).onTapLanguage as Function;
static const Field<SettingsTabVm, Function> _f$onChangeColorMode = Field(
'onChangeColorMode', _$onChangeColorMode,
arg: _arg$onChangeColorMode);
static Function _$onTapLanguage(SettingsTabVm v) =>
(v as dynamic).onTapLanguage as Function;
static dynamic _arg$onTapLanguage(f) => f<void Function(BuildContext)>();
static const Field<SettingsTabVm, Function> _f$onTapLanguage = Field('onTapLanguage', _$onTapLanguage, arg: _arg$onTapLanguage);
static Function _$onToggleAutoStart(SettingsTabVm v) => (v as dynamic).onToggleAutoStart as Function;
static const Field<SettingsTabVm, Function> _f$onTapLanguage =
Field('onTapLanguage', _$onTapLanguage, arg: _arg$onTapLanguage);
static Function _$onToggleAutoStart(SettingsTabVm v) =>
(v as dynamic).onToggleAutoStart as Function;
static dynamic _arg$onToggleAutoStart(f) => f<void Function(BuildContext)>();
static const Field<SettingsTabVm, Function> _f$onToggleAutoStart = Field('onToggleAutoStart', _$onToggleAutoStart, arg: _arg$onToggleAutoStart);
static Function _$onToggleAutoStartLaunchHidden(SettingsTabVm v) => (v as dynamic).onToggleAutoStartLaunchHidden as Function;
static dynamic _arg$onToggleAutoStartLaunchHidden(f) => f<void Function(BuildContext)>();
static const Field<SettingsTabVm, Function> _f$onToggleAutoStart = Field(
'onToggleAutoStart', _$onToggleAutoStart,
arg: _arg$onToggleAutoStart);
static Function _$onToggleAutoStartLaunchHidden(SettingsTabVm v) =>
(v as dynamic).onToggleAutoStartLaunchHidden as Function;
static dynamic _arg$onToggleAutoStartLaunchHidden(f) =>
f<void Function(BuildContext)>();
static const Field<SettingsTabVm, Function> _f$onToggleAutoStartLaunchHidden =
Field('onToggleAutoStartLaunchHidden', _$onToggleAutoStartLaunchHidden, arg: _arg$onToggleAutoStartLaunchHidden);
static Function _$onToggleShowInContextMenu(SettingsTabVm v) => (v as dynamic).onToggleShowInContextMenu as Function;
static dynamic _arg$onToggleShowInContextMenu(f) => f<void Function(BuildContext)>();
Field('onToggleAutoStartLaunchHidden', _$onToggleAutoStartLaunchHidden,
arg: _arg$onToggleAutoStartLaunchHidden);
static Function _$onToggleShowInContextMenu(SettingsTabVm v) =>
(v as dynamic).onToggleShowInContextMenu as Function;
static dynamic _arg$onToggleShowInContextMenu(f) =>
f<void Function(BuildContext)>();
static const Field<SettingsTabVm, Function> _f$onToggleShowInContextMenu =
Field('onToggleShowInContextMenu', _$onToggleShowInContextMenu, arg: _arg$onToggleShowInContextMenu);
static Function _$onTapRestartServer(SettingsTabVm v) => (v as dynamic).onTapRestartServer as Function;
Field('onToggleShowInContextMenu', _$onToggleShowInContextMenu,
arg: _arg$onToggleShowInContextMenu);
static Function _$onTapRestartServer(SettingsTabVm v) =>
(v as dynamic).onTapRestartServer as Function;
static dynamic _arg$onTapRestartServer(f) => f<void Function(BuildContext)>();
static const Field<SettingsTabVm, Function> _f$onTapRestartServer = Field('onTapRestartServer', _$onTapRestartServer, arg: _arg$onTapRestartServer);
static Function _$onTapStartServer(SettingsTabVm v) => (v as dynamic).onTapStartServer as Function;
static const Field<SettingsTabVm, Function> _f$onTapRestartServer = Field(
'onTapRestartServer', _$onTapRestartServer,
arg: _arg$onTapRestartServer);
static Function _$onTapStartServer(SettingsTabVm v) =>
(v as dynamic).onTapStartServer as Function;
static dynamic _arg$onTapStartServer(f) => f<void Function(BuildContext)>();
static const Field<SettingsTabVm, Function> _f$onTapStartServer = Field('onTapStartServer', _$onTapStartServer, arg: _arg$onTapStartServer);
static Function _$onTapStopServer(SettingsTabVm v) => (v as dynamic).onTapStopServer as Function;
static const Field<SettingsTabVm, Function> _f$onTapStartServer =
Field('onTapStartServer', _$onTapStartServer, arg: _arg$onTapStartServer);
static Function _$onTapStopServer(SettingsTabVm v) =>
(v as dynamic).onTapStopServer as Function;
static dynamic _arg$onTapStopServer(f) => f<void Function()>();
static const Field<SettingsTabVm, Function> _f$onTapStopServer = Field('onTapStopServer', _$onTapStopServer, arg: _arg$onTapStopServer);
static Function _$onTapAdvanced(SettingsTabVm v) => (v as dynamic).onTapAdvanced as Function;
static const Field<SettingsTabVm, Function> _f$onTapStopServer =
Field('onTapStopServer', _$onTapStopServer, arg: _arg$onTapStopServer);
static Function _$onTapAdvanced(SettingsTabVm v) =>
(v as dynamic).onTapAdvanced as Function;
static dynamic _arg$onTapAdvanced(f) => f<void Function(bool)>();
static const Field<SettingsTabVm, Function> _f$onTapAdvanced = Field('onTapAdvanced', _$onTapAdvanced, arg: _arg$onTapAdvanced);
static const Field<SettingsTabVm, Function> _f$onTapAdvanced =
Field('onTapAdvanced', _$onTapAdvanced, arg: _arg$onTapAdvanced);
static List<ThemeMode> _$themeModes(SettingsTabVm v) => v.themeModes;
static const Field<SettingsTabVm, List<ThemeMode>> _f$themeModes = Field('themeModes', _$themeModes, mode: FieldMode.member);
static const Field<SettingsTabVm, List<ThemeMode>> _f$themeModes =
Field('themeModes', _$themeModes, mode: FieldMode.member);
@override
final MappableFields<SettingsTabVm> fields = const {
@@ -130,7 +178,8 @@ class SettingsTabVmMapper extends ClassMapperBase<SettingsTabVm> {
onChangeColorMode: data.dec(_f$onChangeColorMode),
onTapLanguage: data.dec(_f$onTapLanguage),
onToggleAutoStart: data.dec(_f$onToggleAutoStart),
onToggleAutoStartLaunchHidden: data.dec(_f$onToggleAutoStartLaunchHidden),
onToggleAutoStartLaunchHidden:
data.dec(_f$onToggleAutoStartLaunchHidden),
onToggleShowInContextMenu: data.dec(_f$onToggleShowInContextMenu),
onTapRestartServer: data.dec(_f$onTapRestartServer),
onTapStartServer: data.dec(_f$onTapStartServer),
@@ -152,39 +201,49 @@ class SettingsTabVmMapper extends ClassMapperBase<SettingsTabVm> {
mixin SettingsTabVmMappable {
String serialize() {
return SettingsTabVmMapper.ensureInitialized().encodeJson<SettingsTabVm>(this as SettingsTabVm);
return SettingsTabVmMapper.ensureInitialized()
.encodeJson<SettingsTabVm>(this as SettingsTabVm);
}
Map<String, dynamic> toJson() {
return SettingsTabVmMapper.ensureInitialized().encodeMap<SettingsTabVm>(this as SettingsTabVm);
return SettingsTabVmMapper.ensureInitialized()
.encodeMap<SettingsTabVm>(this as SettingsTabVm);
}
SettingsTabVmCopyWith<SettingsTabVm, SettingsTabVm, SettingsTabVm> get copyWith =>
_SettingsTabVmCopyWithImpl(this as SettingsTabVm, $identity, $identity);
SettingsTabVmCopyWith<SettingsTabVm, SettingsTabVm, SettingsTabVm>
get copyWith => _SettingsTabVmCopyWithImpl(
this as SettingsTabVm, $identity, $identity);
@override
String toString() {
return SettingsTabVmMapper.ensureInitialized().stringifyValue(this as SettingsTabVm);
return SettingsTabVmMapper.ensureInitialized()
.stringifyValue(this as SettingsTabVm);
}
@override
bool operator ==(Object other) {
return SettingsTabVmMapper.ensureInitialized().equalsValue(this as SettingsTabVm, other);
return SettingsTabVmMapper.ensureInitialized()
.equalsValue(this as SettingsTabVm, other);
}
@override
int get hashCode {
return SettingsTabVmMapper.ensureInitialized().hashValue(this as SettingsTabVm);
return SettingsTabVmMapper.ensureInitialized()
.hashValue(this as SettingsTabVm);
}
}
extension SettingsTabVmValueCopy<$R, $Out> on ObjectCopyWith<$R, SettingsTabVm, $Out> {
SettingsTabVmCopyWith<$R, SettingsTabVm, $Out> get $asSettingsTabVm => $base.as((v, t, t2) => _SettingsTabVmCopyWithImpl(v, t, t2));
extension SettingsTabVmValueCopy<$R, $Out>
on ObjectCopyWith<$R, SettingsTabVm, $Out> {
SettingsTabVmCopyWith<$R, SettingsTabVm, $Out> get $asSettingsTabVm =>
$base.as((v, t, t2) => _SettingsTabVmCopyWithImpl(v, t, t2));
}
abstract class SettingsTabVmCopyWith<$R, $In extends SettingsTabVm, $Out> implements ClassCopyWith<$R, $In, $Out> {
abstract class SettingsTabVmCopyWith<$R, $In extends SettingsTabVm, $Out>
implements ClassCopyWith<$R, $In, $Out> {
SettingsStateCopyWith<$R, SettingsState, SettingsState> get settings;
ServerStateCopyWith<$R, ServerState, ServerState>? get serverState;
ListCopyWith<$R, ColorMode, ObjectCopyWith<$R, ColorMode, ColorMode>> get colorModes;
ListCopyWith<$R, ColorMode, ObjectCopyWith<$R, ColorMode, ColorMode>>
get colorModes;
$R call(
{bool? advanced,
TextEditingController? aliasController,
@@ -212,19 +271,26 @@ abstract class SettingsTabVmCopyWith<$R, $In extends SettingsTabVm, $Out> implem
SettingsTabVmCopyWith<$R2, $In, $Out2> $chain<$R2, $Out2>(Then<$Out2, $R2> t);
}
class _SettingsTabVmCopyWithImpl<$R, $Out> extends ClassCopyWithBase<$R, SettingsTabVm, $Out>
class _SettingsTabVmCopyWithImpl<$R, $Out>
extends ClassCopyWithBase<$R, SettingsTabVm, $Out>
implements SettingsTabVmCopyWith<$R, SettingsTabVm, $Out> {
_SettingsTabVmCopyWithImpl(super.value, super.then, super.then2);
@override
late final ClassMapperBase<SettingsTabVm> $mapper = SettingsTabVmMapper.ensureInitialized();
late final ClassMapperBase<SettingsTabVm> $mapper =
SettingsTabVmMapper.ensureInitialized();
@override
SettingsStateCopyWith<$R, SettingsState, SettingsState> get settings => $value.settings.copyWith.$chain((v) => call(settings: v));
SettingsStateCopyWith<$R, SettingsState, SettingsState> get settings =>
$value.settings.copyWith.$chain((v) => call(settings: v));
@override
ServerStateCopyWith<$R, ServerState, ServerState>? get serverState => $value.serverState?.copyWith.$chain((v) => call(serverState: v));
ServerStateCopyWith<$R, ServerState, ServerState>? get serverState =>
$value.serverState?.copyWith.$chain((v) => call(serverState: v));
@override
ListCopyWith<$R, ColorMode, ObjectCopyWith<$R, ColorMode, ColorMode>> get colorModes =>
ListCopyWith($value.colorModes, (v, t) => ObjectCopyWith(v, $identity, t), (v) => call(colorModes: v));
ListCopyWith<$R, ColorMode, ObjectCopyWith<$R, ColorMode, ColorMode>>
get colorModes => ListCopyWith(
$value.colorModes,
(v, t) => ObjectCopyWith(v, $identity, t),
(v) => call(colorModes: v));
@override
$R call(
{bool? advanced,
@@ -253,23 +319,28 @@ class _SettingsTabVmCopyWithImpl<$R, $Out> extends ClassCopyWithBase<$R, Setting
$apply(FieldCopyWithData({
if (advanced != null) #advanced: advanced,
if (aliasController != null) #aliasController: aliasController,
if (deviceModelController != null) #deviceModelController: deviceModelController,
if (deviceModelController != null)
#deviceModelController: deviceModelController,
if (portController != null) #portController: portController,
if (timeoutController != null) #timeoutController: timeoutController,
if (multicastController != null) #multicastController: multicastController,
if (multicastController != null)
#multicastController: multicastController,
if (settings != null) #settings: settings,
if (serverState != $none) #serverState: serverState,
if (deviceInfo != null) #deviceInfo: deviceInfo,
if (colorModes != null) #colorModes: colorModes,
if (autoStart != null) #autoStart: autoStart,
if (autoStartLaunchHidden != null) #autoStartLaunchHidden: autoStartLaunchHidden,
if (autoStartLaunchHidden != null)
#autoStartLaunchHidden: autoStartLaunchHidden,
if (showInContextMenu != null) #showInContextMenu: showInContextMenu,
if (onChangeTheme != null) #onChangeTheme: onChangeTheme,
if (onChangeColorMode != null) #onChangeColorMode: onChangeColorMode,
if (onTapLanguage != null) #onTapLanguage: onTapLanguage,
if (onToggleAutoStart != null) #onToggleAutoStart: onToggleAutoStart,
if (onToggleAutoStartLaunchHidden != null) #onToggleAutoStartLaunchHidden: onToggleAutoStartLaunchHidden,
if (onToggleShowInContextMenu != null) #onToggleShowInContextMenu: onToggleShowInContextMenu,
if (onToggleAutoStartLaunchHidden != null)
#onToggleAutoStartLaunchHidden: onToggleAutoStartLaunchHidden,
if (onToggleShowInContextMenu != null)
#onToggleShowInContextMenu: onToggleShowInContextMenu,
if (onTapRestartServer != null) #onTapRestartServer: onTapRestartServer,
if (onTapStartServer != null) #onTapStartServer: onTapStartServer,
if (onTapStopServer != null) #onTapStopServer: onTapStopServer,
@@ -279,28 +350,41 @@ class _SettingsTabVmCopyWithImpl<$R, $Out> extends ClassCopyWithBase<$R, Setting
SettingsTabVm $make(CopyWithData data) => SettingsTabVm(
advanced: data.get(#advanced, or: $value.advanced),
aliasController: data.get(#aliasController, or: $value.aliasController),
deviceModelController: data.get(#deviceModelController, or: $value.deviceModelController),
deviceModelController:
data.get(#deviceModelController, or: $value.deviceModelController),
portController: data.get(#portController, or: $value.portController),
timeoutController: data.get(#timeoutController, or: $value.timeoutController),
multicastController: data.get(#multicastController, or: $value.multicastController),
timeoutController:
data.get(#timeoutController, or: $value.timeoutController),
multicastController:
data.get(#multicastController, or: $value.multicastController),
settings: data.get(#settings, or: $value.settings),
serverState: data.get(#serverState, or: $value.serverState),
deviceInfo: data.get(#deviceInfo, or: $value.deviceInfo),
colorModes: data.get(#colorModes, or: $value.colorModes),
autoStart: data.get(#autoStart, or: $value.autoStart),
autoStartLaunchHidden: data.get(#autoStartLaunchHidden, or: $value.autoStartLaunchHidden),
showInContextMenu: data.get(#showInContextMenu, or: $value.showInContextMenu),
autoStartLaunchHidden:
data.get(#autoStartLaunchHidden, or: $value.autoStartLaunchHidden),
showInContextMenu:
data.get(#showInContextMenu, or: $value.showInContextMenu),
onChangeTheme: data.get(#onChangeTheme, or: $value.onChangeTheme),
onChangeColorMode: data.get(#onChangeColorMode, or: $value.onChangeColorMode),
onChangeColorMode:
data.get(#onChangeColorMode, or: $value.onChangeColorMode),
onTapLanguage: data.get(#onTapLanguage, or: $value.onTapLanguage),
onToggleAutoStart: data.get(#onToggleAutoStart, or: $value.onToggleAutoStart),
onToggleAutoStartLaunchHidden: data.get(#onToggleAutoStartLaunchHidden, or: $value.onToggleAutoStartLaunchHidden),
onToggleShowInContextMenu: data.get(#onToggleShowInContextMenu, or: $value.onToggleShowInContextMenu),
onTapRestartServer: data.get(#onTapRestartServer, or: $value.onTapRestartServer),
onTapStartServer: data.get(#onTapStartServer, or: $value.onTapStartServer),
onToggleAutoStart:
data.get(#onToggleAutoStart, or: $value.onToggleAutoStart),
onToggleAutoStartLaunchHidden: data.get(#onToggleAutoStartLaunchHidden,
or: $value.onToggleAutoStartLaunchHidden),
onToggleShowInContextMenu: data.get(#onToggleShowInContextMenu,
or: $value.onToggleShowInContextMenu),
onTapRestartServer:
data.get(#onTapRestartServer, or: $value.onTapRestartServer),
onTapStartServer:
data.get(#onTapStartServer, or: $value.onTapStartServer),
onTapStopServer: data.get(#onTapStopServer, or: $value.onTapStopServer),
onTapAdvanced: data.get(#onTapAdvanced, or: $value.onTapAdvanced));
@override
SettingsTabVmCopyWith<$R2, SettingsTabVm, $Out2> $chain<$R2, $Out2>(Then<$Out2, $R2> t) => _SettingsTabVmCopyWithImpl($value, $cast, t);
SettingsTabVmCopyWith<$R2, SettingsTabVm, $Out2> $chain<$R2, $Out2>(
Then<$Out2, $R2> t) =>
_SettingsTabVmCopyWithImpl($value, $cast, t);
}
@@ -32,6 +32,7 @@ final deviceFullInfoProvider = ViewProvider((ref) {
final rawInfo = ref.watch(deviceInfoProvider);
final securityContext = ref.read(securityProvider);
return Device(
signalingId: null,
ip: networkInfo.localIps.firstOrNull ?? '-',
version: protocolVersion,
port: serverState?.port ?? -1,
@@ -41,5 +42,6 @@ final deviceFullInfoProvider = ViewProvider((ref) {
deviceModel: rawInfo.deviceModel,
deviceType: rawInfo.deviceType,
download: serverState?.webSendState != null,
discoveryMethods: const {},
);
});
@@ -40,6 +40,7 @@ class NearbyDevicesService extends ReduxNotifier<NearbyDevicesState> {
runningFavoriteScan: false,
runningIps: {},
devices: {},
signalingDevices: {},
);
}
@@ -78,6 +79,8 @@ class RegisterDeviceAction extends AsyncReduxAction<NearbyDevicesService, Nearby
@override
Future<NearbyDevicesState> reduce() async {
assert(device.ip?.isNotEmpty ?? false, 'IP must not be empty');
final favoriteDevice = notifier._favoriteService.state.firstWhereOrNull((e) => e.fingerprint == device.fingerprint);
if (favoriteDevice != null && !favoriteDevice.customAlias) {
// Update existing favorite with new alias
@@ -86,7 +89,46 @@ class RegisterDeviceAction extends AsyncReduxAction<NearbyDevicesService, Nearby
await Future.microtask(() {});
}
return state.copyWith(
devices: {...state.devices}..update(device.ip, (_) => device, ifAbsent: () => device),
devices: {...state.devices}..update(device.ip!, (_) => device, ifAbsent: () => device),
);
}
}
/// Registers a new device found via signaling.
class RegisterSignalingDeviceAction extends ReduxAction<NearbyDevicesService, NearbyDevicesState> {
final Device device;
RegisterSignalingDeviceAction(this.device);
@override
NearbyDevicesState reduce() {
final Set<Device> existingDevices = state.signalingDevices[device.fingerprint]?.toSet() ?? {};
final existingDevice = existingDevices.firstWhereOrNull((e) => e.signalingId == device.signalingId);
if (existingDevice != null) {
existingDevices.remove(existingDevice);
}
existingDevices.add(device);
return state.copyWith(
signalingDevices: {
...state.signalingDevices,
device.fingerprint: existingDevices,
},
);
}
}
class UnregisterSignalingDeviceAction extends ReduxAction<NearbyDevicesService, NearbyDevicesState> {
final String signalingId;
UnregisterSignalingDeviceAction(this.signalingId);
@override
NearbyDevicesState reduce() {
return state.copyWith(
signalingDevices: {
for (final entry in state.signalingDevices.entries) entry.key: entry.value.where((e) => e.signalingId != signalingId).toSet(),
},
);
}
}
@@ -5,6 +5,7 @@ import 'dart:io';
import 'package:collection/collection.dart';
import 'package:common/api_route_builder.dart';
import 'package:common/constants.dart';
import 'package:common/model/device.dart';
import 'package:common/model/dto/info_dto.dart';
import 'package:common/model/dto/info_register_dto.dart';
import 'package:common/model/dto/prepare_upload_request_dto.dart';
@@ -23,7 +24,6 @@ import 'package:localsend_app/pages/home_page.dart';
import 'package:localsend_app/pages/home_page_controller.dart';
import 'package:localsend_app/pages/progress_page.dart';
import 'package:localsend_app/pages/receive_page.dart';
import 'package:localsend_app/pages/receive_page_controller.dart';
import 'package:localsend_app/provider/device_info_provider.dart';
import 'package:localsend_app/provider/favorites_provider.dart';
import 'package:localsend_app/provider/http_provider.dart';
@@ -31,6 +31,7 @@ import 'package:localsend_app/provider/logging/discovery_logs_provider.dart';
import 'package:localsend_app/provider/network/nearby_devices_provider.dart';
import 'package:localsend_app/provider/network/send_provider.dart';
import 'package:localsend_app/provider/network/server/controller/common.dart';
import 'package:localsend_app/provider/network/server/server_provider.dart';
import 'package:localsend_app/provider/network/server/server_utils.dart';
import 'package:localsend_app/provider/progress_provider.dart';
import 'package:localsend_app/provider/receive_history_provider.dart';
@@ -45,6 +46,7 @@ import 'package:localsend_app/util/simple_server.dart';
import 'package:localsend_app/widget/dialogs/open_file_dialog.dart';
import 'package:logging/logging.dart';
import 'package:permission_handler/permission_handler.dart';
import 'package:refena_flutter/refena_flutter.dart';
import 'package:routerino/routerino.dart';
import 'package:uuid/uuid.dart';
import 'package:window_manager/window_manager.dart';
@@ -164,7 +166,9 @@ class ReceiveController {
}
// Save device information
await server.ref.redux(nearbyDevicesProvider).dispatchAsync(RegisterDeviceAction(requestDto.toDevice(request.ip, port, https)));
await server.ref
.redux(nearbyDevicesProvider)
.dispatchAsync(RegisterDeviceAction(requestDto.toDevice(request.ip, port, https, HttpDiscovery(ip: request.ip))));
server.ref.notifier(discoveryLoggerProvider).addLog('[DISCOVER/TCP] Received "/register" HTTP request: ${requestDto.alias} (${request.ip})');
final deviceInfo = server.ref.read(deviceInfoProvider);
@@ -229,7 +233,7 @@ class ReceiveController {
session: ReceiveSessionState(
sessionId: sessionId,
status: SessionStatus.waiting,
sender: dto.info.toDevice(request.ip, port, https),
sender: dto.info.toDevice(request.ip, port, https, null),
senderAlias: server.ref.read(favoritesProvider).firstWhereOrNull((e) => e.fingerprint == dto.info.fingerprint)?.alias ?? dto.info.alias,
files: {
for (final file in dto.files.values)
@@ -287,14 +291,51 @@ class ReceiveController {
senderAlias: server.getState().session!.senderAlias,
timestamp: DateTime.now().toUtc(),
));
} else {
server.ref.notifier(selectedReceivingFilesProvider).setFiles(server.getState().session!.files.values.map((f) => f.file).toList());
}
server.ref.redux(receivePageControllerProvider).dispatch(InitReceivePageAction());
final receiveProvider = ViewProvider((ref) {
final session = ref.watch(serverProvider.select((state) => state?.session));
return ReceivePageVm(
status: session?.status,
sender: session?.sender ?? Device.empty,
showSenderInfo: true,
files: session?.files.values.map((f) => f.file).toList() ?? [],
message: message,
onAccept: () async {
if (message != null) {
// accept nothing
ref.notifier(serverProvider).acceptFileRequest({});
return;
}
final sessionId = ref.read(serverProvider)?.session?.sessionId;
if (sessionId == null) {
return;
}
final selectedFiles = ref.read(selectedReceivingFilesProvider);
ref.notifier(serverProvider).acceptFileRequest(selectedFiles);
await Routerino.context.pushAndRemoveUntilImmediately(
removeUntil: ReceivePage,
builder: () => ProgressPage(
showAppBar: false,
closeSessionOnClose: true,
sessionId: sessionId,
),
);
},
onDecline: () {
ref.notifier(serverProvider).declineFileRequest();
},
onClose: () {
ref.notifier(serverProvider).closeSession();
},
);
});
// ignore: use_build_context_synchronously, unawaited_futures
Routerino.context.push(() => const ReceivePage());
Routerino.context.push(() => ReceivePage(receiveProvider));
// Delayed response (waiting for user's decision)
selection = await streamController.stream.first;
@@ -0,0 +1,231 @@
import 'dart:async';
import 'package:common/constants.dart';
import 'package:common/model/device.dart';
import 'package:dart_mappable/dart_mappable.dart';
import 'package:localsend_app/provider/device_info_provider.dart';
import 'package:localsend_app/provider/favorites_provider.dart';
import 'package:localsend_app/provider/network/nearby_devices_provider.dart';
import 'package:localsend_app/provider/network/webrtc/webrtc_receiver.dart';
import 'package:localsend_app/provider/persistence_provider.dart';
import 'package:localsend_app/provider/security_provider.dart';
import 'package:localsend_app/provider/settings_provider.dart';
import 'package:localsend_app/rust/api/crypto.dart' as crypto;
import 'package:localsend_app/rust/api/model.dart' as rust;
import 'package:localsend_app/rust/api/webrtc.dart';
import 'package:refena_flutter/refena_flutter.dart';
part 'signaling_provider.mapper.dart';
@MappableClass()
class SignalingState with SignalingStateMappable {
final List<String> signalingServers;
final List<String> stunServers;
final Map<String, LsSignalingConnection> connections;
SignalingState({
required this.signalingServers,
required this.stunServers,
required this.connections,
});
}
final signalingProvider = ReduxProvider<SignalingService, SignalingState>((ref) {
return SignalingService(
persistence: ref.read(persistenceProvider),
);
});
class SignalingService extends ReduxNotifier<SignalingState> {
final PersistenceService _persistence;
SignalingService({
required PersistenceService persistence,
}) : _persistence = persistence;
@override
SignalingState init() {
return SignalingState(
signalingServers: _persistence.getSignalingServers() ?? ['wss://public.localsend.org/v1/ws'],
stunServers: _persistence.getStunServers() ?? ['stun:stun.localsend.org:5349'],
connections: {},
);
}
}
class SetupSignalingConnection extends ReduxAction<SignalingService, SignalingState> with GlobalActions {
@override
SignalingState reduce() {
for (final signalingServer in state.signalingServers) {
// ignore: discarded_futures
global.dispatchAsync(_SetupSignalingConnection(signalingServer: signalingServer));
}
return state;
}
}
/// Starts an endless running action.
class _SetupSignalingConnection extends AsyncGlobalAction {
final String signalingServer;
_SetupSignalingConnection({required this.signalingServer});
@override
Future<void> reduce() async {
final settings = ref.read(settingsProvider);
final deviceInfo = ref.read(deviceInfoProvider);
final security = ref.read(securityProvider);
// TODO: Use persistent key
final key = await crypto.generateKeyPair();
print('private key: ${key.privateKey}');
LsSignalingConnection? connection;
final stream = connect(
uri: 'wss://public.localsend.org/v1/ws',
info: ProposingClientInfo(
alias: settings.alias,
version: protocolVersion,
deviceModel: deviceInfo.deviceModel,
deviceType: deviceInfo.deviceType.toRustDeviceType(),
),
privateKey: key.privateKey,
onConnection: (c) {
connection = c;
ref.redux(signalingProvider).dispatch(_SetConnectionAction(
signalingServer: signalingServer,
connection: c,
));
},
);
try {
await for (final message in stream) {
switch (message) {
case WsServerMessage_Hello():
for (final d in message.peers) {
ref.redux(nearbyDevicesProvider).dispatch(RegisterSignalingDeviceAction(
d.toDevice(signalingServer),
));
}
break;
case WsServerMessage_Join(peer: final peer):
case WsServerMessage_Update(peer: final peer):
ref.redux(nearbyDevicesProvider).dispatch(RegisterSignalingDeviceAction(
peer.toDevice(signalingServer),
));
break;
case WsServerMessage_Left():
ref.redux(nearbyDevicesProvider).dispatch(UnregisterSignalingDeviceAction(
message.peerId.uuid,
));
break;
case WsServerMessage_Offer():
final provider = ReduxProvider<WebRTCReceiveService, WebRTCReceiveState>((ref) {
return WebRTCReceiveService(
signalingServer: signalingServer,
stunServers: ref.read(signalingProvider).stunServers,
connection: connection!,
offer: message.field0,
settings: ref.read(settingsProvider),
favorites: ref.read(favoritesProvider),
key: ref.read(securityProvider),
);
});
await ref.redux(provider).dispatchAsync(AcceptOfferAction());
break;
case WsServerMessage_Answer():
case WsServerMessage_Error():
}
}
} finally {
ref.redux(signalingProvider).dispatch(_RemoveConnectionAction(signalingServer: signalingServer));
}
return state;
}
}
class _SetConnectionAction extends ReduxAction<SignalingService, SignalingState> {
final String signalingServer;
final LsSignalingConnection connection;
_SetConnectionAction({
required this.signalingServer,
required this.connection,
});
@override
SignalingState reduce() {
return state.copyWith(
connections: {
...state.connections,
signalingServer: connection,
},
);
}
}
class _RemoveConnectionAction extends ReduxAction<SignalingService, SignalingState> {
final String signalingServer;
_RemoveConnectionAction({required this.signalingServer});
@override
SignalingState reduce() {
return state.copyWith(
connections: {
for (final entry in state.connections.entries)
if (entry.key != signalingServer) entry.key: entry.value,
},
);
}
}
extension ClientInfoExt on ClientInfo {
Device toDevice(String signalingServer) {
return Device(
signalingId: id.uuid,
ip: null,
version: version,
port: -1,
https: false,
fingerprint: token,
alias: alias,
deviceModel: deviceModel,
deviceType: deviceType?.toDeviceType() ?? DeviceType.desktop,
download: false,
discoveryMethods: {
SignalingDiscovery(
signalingServer: signalingServer,
),
},
);
}
}
extension on rust.DeviceType {
DeviceType toDeviceType() {
return switch (this) {
rust.DeviceType.mobile => DeviceType.mobile,
rust.DeviceType.desktop => DeviceType.desktop,
rust.DeviceType.web => DeviceType.web,
rust.DeviceType.headless => DeviceType.headless,
rust.DeviceType.server => DeviceType.server,
};
}
}
extension on DeviceType {
rust.DeviceType toRustDeviceType() {
return switch (this) {
DeviceType.mobile => rust.DeviceType.mobile,
DeviceType.desktop => rust.DeviceType.desktop,
DeviceType.web => rust.DeviceType.web,
DeviceType.headless => rust.DeviceType.headless,
DeviceType.server => rust.DeviceType.server,
};
}
}
@@ -0,0 +1,164 @@
// coverage:ignore-file
// GENERATED CODE - DO NOT MODIFY BY HAND
// ignore_for_file: type=lint
// ignore_for_file: unused_element, unnecessary_cast, override_on_non_overriding_member
// ignore_for_file: strict_raw_type, inference_failure_on_untyped_parameter
part of 'signaling_provider.dart';
class SignalingStateMapper extends ClassMapperBase<SignalingState> {
SignalingStateMapper._();
static SignalingStateMapper? _instance;
static SignalingStateMapper ensureInitialized() {
if (_instance == null) {
MapperContainer.globals.use(_instance = SignalingStateMapper._());
}
return _instance!;
}
@override
final String id = 'SignalingState';
static List<String> _$signalingServers(SignalingState v) =>
v.signalingServers;
static const Field<SignalingState, List<String>> _f$signalingServers =
Field('signalingServers', _$signalingServers);
static List<String> _$stunServers(SignalingState v) => v.stunServers;
static const Field<SignalingState, List<String>> _f$stunServers =
Field('stunServers', _$stunServers);
static Map<String, LsSignalingConnection> _$connections(SignalingState v) =>
v.connections;
static const Field<SignalingState, Map<String, LsSignalingConnection>>
_f$connections = Field('connections', _$connections);
@override
final MappableFields<SignalingState> fields = const {
#signalingServers: _f$signalingServers,
#stunServers: _f$stunServers,
#connections: _f$connections,
};
static SignalingState _instantiate(DecodingData data) {
return SignalingState(
signalingServers: data.dec(_f$signalingServers),
stunServers: data.dec(_f$stunServers),
connections: data.dec(_f$connections));
}
@override
final Function instantiate = _instantiate;
static SignalingState fromJson(Map<String, dynamic> map) {
return ensureInitialized().decodeMap<SignalingState>(map);
}
static SignalingState deserialize(String json) {
return ensureInitialized().decodeJson<SignalingState>(json);
}
}
mixin SignalingStateMappable {
String serialize() {
return SignalingStateMapper.ensureInitialized()
.encodeJson<SignalingState>(this as SignalingState);
}
Map<String, dynamic> toJson() {
return SignalingStateMapper.ensureInitialized()
.encodeMap<SignalingState>(this as SignalingState);
}
SignalingStateCopyWith<SignalingState, SignalingState, SignalingState>
get copyWith => _SignalingStateCopyWithImpl(
this as SignalingState, $identity, $identity);
@override
String toString() {
return SignalingStateMapper.ensureInitialized()
.stringifyValue(this as SignalingState);
}
@override
bool operator ==(Object other) {
return SignalingStateMapper.ensureInitialized()
.equalsValue(this as SignalingState, other);
}
@override
int get hashCode {
return SignalingStateMapper.ensureInitialized()
.hashValue(this as SignalingState);
}
}
extension SignalingStateValueCopy<$R, $Out>
on ObjectCopyWith<$R, SignalingState, $Out> {
SignalingStateCopyWith<$R, SignalingState, $Out> get $asSignalingState =>
$base.as((v, t, t2) => _SignalingStateCopyWithImpl(v, t, t2));
}
abstract class SignalingStateCopyWith<$R, $In extends SignalingState, $Out>
implements ClassCopyWith<$R, $In, $Out> {
ListCopyWith<$R, String, ObjectCopyWith<$R, String, String>>
get signalingServers;
ListCopyWith<$R, String, ObjectCopyWith<$R, String, String>> get stunServers;
MapCopyWith<$R, String, LsSignalingConnection,
ObjectCopyWith<$R, LsSignalingConnection, LsSignalingConnection>>
get connections;
$R call(
{List<String>? signalingServers,
List<String>? stunServers,
Map<String, LsSignalingConnection>? connections});
SignalingStateCopyWith<$R2, $In, $Out2> $chain<$R2, $Out2>(
Then<$Out2, $R2> t);
}
class _SignalingStateCopyWithImpl<$R, $Out>
extends ClassCopyWithBase<$R, SignalingState, $Out>
implements SignalingStateCopyWith<$R, SignalingState, $Out> {
_SignalingStateCopyWithImpl(super.value, super.then, super.then2);
@override
late final ClassMapperBase<SignalingState> $mapper =
SignalingStateMapper.ensureInitialized();
@override
ListCopyWith<$R, String, ObjectCopyWith<$R, String, String>>
get signalingServers => ListCopyWith(
$value.signalingServers,
(v, t) => ObjectCopyWith(v, $identity, t),
(v) => call(signalingServers: v));
@override
ListCopyWith<$R, String, ObjectCopyWith<$R, String, String>>
get stunServers => ListCopyWith(
$value.stunServers,
(v, t) => ObjectCopyWith(v, $identity, t),
(v) => call(stunServers: v));
@override
MapCopyWith<$R, String, LsSignalingConnection,
ObjectCopyWith<$R, LsSignalingConnection, LsSignalingConnection>>
get connections => MapCopyWith(
$value.connections,
(v, t) => ObjectCopyWith(v, $identity, t),
(v) => call(connections: v));
@override
$R call(
{List<String>? signalingServers,
List<String>? stunServers,
Map<String, LsSignalingConnection>? connections}) =>
$apply(FieldCopyWithData({
if (signalingServers != null) #signalingServers: signalingServers,
if (stunServers != null) #stunServers: stunServers,
if (connections != null) #connections: connections
}));
@override
SignalingState $make(CopyWithData data) => SignalingState(
signalingServers:
data.get(#signalingServers, or: $value.signalingServers),
stunServers: data.get(#stunServers, or: $value.stunServers),
connections: data.get(#connections, or: $value.connections));
@override
SignalingStateCopyWith<$R2, SignalingState, $Out2> $chain<$R2, $Out2>(
Then<$Out2, $R2> t) =>
_SignalingStateCopyWithImpl($value, $cast, t);
}
@@ -0,0 +1,218 @@
import 'package:collection/collection.dart';
import 'package:common/model/dto/file_dto.dart' as dart_model;
import 'package:common/model/file_status.dart';
import 'package:common/model/session_status.dart';
import 'package:common/model/stored_security_context.dart';
import 'package:dart_mappable/dart_mappable.dart';
import 'package:localsend_app/model/persistence/favorite_device.dart';
import 'package:localsend_app/model/state/server/receive_session_state.dart';
import 'package:localsend_app/model/state/server/receiving_file.dart';
import 'package:localsend_app/model/state/settings_state.dart';
import 'package:localsend_app/pages/receive_page.dart';
import 'package:localsend_app/provider/network/webrtc/signaling_provider.dart';
import 'package:localsend_app/rust/api/model.dart';
import 'package:localsend_app/rust/api/webrtc.dart';
import 'package:refena_flutter/refena_flutter.dart';
import 'package:routerino/routerino.dart';
part 'webrtc_receiver.mapper.dart';
@MappableClass()
class WebRTCReceiveState with WebRTCReceiveStateMappable {
final LsSignalingConnection connection;
final WsServerSdpMessage offer;
final RTCStatus? status;
final RtcReceiveController? controller;
final ReceiveSessionState? sessionState;
const WebRTCReceiveState({
required this.connection,
required this.offer,
required this.status,
required this.controller,
required this.sessionState,
});
}
class WebRTCReceiveService extends ReduxNotifier<WebRTCReceiveState> {
final String _signalingServer;
final List<String> _stunServers;
final LsSignalingConnection _connection;
final WsServerSdpMessage _offer;
final SettingsState _settings;
final List<FavoriteDevice> _favorites;
final StoredSecurityContext _key;
WebRTCReceiveService({
required String signalingServer,
required List<String> stunServers,
required LsSignalingConnection connection,
required WsServerSdpMessage offer,
required SettingsState settings,
required List<FavoriteDevice> favorites,
required StoredSecurityContext key,
}) : _signalingServer = signalingServer,
_stunServers = stunServers,
_connection = connection,
_offer = offer,
_settings = settings,
_favorites = favorites,
_key = key;
@override
WebRTCReceiveState init() {
return WebRTCReceiveState(
connection: _connection,
offer: _offer,
status: null,
controller: null,
sessionState: null,
);
}
}
class AcceptOfferAction extends AsyncReduxAction<WebRTCReceiveService, WebRTCReceiveState> {
@override
Future<WebRTCReceiveState> reduce() async {
final controller = await state.connection.acceptOffer(
stunServers: notifier._stunServers,
offer: state.offer,
privateKey: notifier._key.privateKey,
);
controller.listenStatus().listen((status) {
dispatch(_SetStatusAction(status));
});
return state.copyWith(
controller: controller,
);
}
@override
void after() {
// ignore: discarded_futures
dispatchAsync(_AcceptOfferAction());
}
}
class _AcceptOfferAction extends AsyncReduxAction<WebRTCReceiveService, WebRTCReceiveState> {
@override
Future<WebRTCReceiveState> reduce() async {
final controller = state.controller;
if (controller == null) {
return state;
}
final files = await controller.listenFiles();
final convertedFiles = files.map((e) => e.toFileDto()).toList();
dispatch(_InitSessionState(convertedFiles));
final vm = ViewProvider((ref) {
final state = ref.watch(notifier.provider as ReduxProvider<WebRTCReceiveService, WebRTCReceiveState>);
return ReceivePageVm(
status: switch (state.status) {
null => SessionStatus.waiting,
RTCStatus_SdpExchanged() => SessionStatus.waiting,
RTCStatus_Connected() => SessionStatus.waiting,
RTCStatus_PinRequired() => SessionStatus.waiting,
RTCStatus_TooManyAttempts() => SessionStatus.tooManyAttempts,
RTCStatus_Declined() => SessionStatus.declined,
RTCStatus_Sending() => SessionStatus.sending,
RTCStatus_Finished() => SessionStatus.finished,
RTCStatus_Error() => SessionStatus.finishedWithErrors,
},
sender: state.offer.peer.toDevice(notifier._signalingServer),
showSenderInfo: true,
files: convertedFiles,
message: files.length == 1 && files[0].fileType.startsWith('text/') ? files[0].preview : null,
onAccept: () {},
onDecline: () {},
onClose: () {},
);
});
// ignore: unawaited_futures, use_build_context_synchronously
Routerino.context.push(() => ReceivePage(vm));
return state.copyWith(
controller: controller,
);
}
}
class _InitSessionState extends ReduxAction<WebRTCReceiveService, WebRTCReceiveState> {
final List<dart_model.FileDto> files;
_InitSessionState(this.files);
@override
WebRTCReceiveState reduce() {
return state;
// TODO
// return state.copyWith(
// sessionState: ReceiveSessionState(
// sessionId: state.offer.sessionId,
// status: SessionStatus.waiting,
// sender: state.offer.peer.toDevice(notifier._signalingServer),
// senderAlias: notifier._favorites.firstWhereOrNull((e) => e.fingerprint == notifier.info.fingerprint)?.alias ?? dto.info.alias,
// files: {
// for (final file in files)
// file.id: ReceivingFile(
// file: file,
// status: FileStatus.queue,
// token: null,
// desiredName: null,
// path: null,
// savedToGallery: false,
// errorMessage: null,
// ),
// },
// startTime: null,
// endTime: null,
// destinationDirectory: destinationDir,
// cacheDirectory: cacheDir,
// saveToGallery: checkPlatformWithGallery() && settings.saveToGallery && dto.files.values.every((f) => !f.fileName.contains('/')),
// createdDirectories: {},
// responseHandler: streamController,
// ),
// );
}
}
class _SetStatusAction extends ReduxAction<WebRTCReceiveService, WebRTCReceiveState> {
final RTCStatus status;
_SetStatusAction(this.status);
@override
WebRTCReceiveState reduce() {
return state.copyWith(
status: status,
);
}
}
extension on FileDto {
dart_model.FileDto toFileDto() {
return dart_model.FileDto(
id: id,
fileName: fileName,
size: size.toInt(),
fileType: dart_model.decodeFromMime(fileType),
hash: null,
preview: preview,
legacy: false,
metadata: metadata?.toFileMetadata(),
);
}
}
extension on FileMetadata {
dart_model.FileMetadata toFileMetadata() {
return dart_model.FileMetadata(
lastModified: DateTime.tryParse(modified ?? ''),
lastAccessed: DateTime.tryParse(accessed ?? ''),
);
}
}
@@ -0,0 +1,166 @@
// coverage:ignore-file
// GENERATED CODE - DO NOT MODIFY BY HAND
// ignore_for_file: type=lint
// ignore_for_file: unused_element, unnecessary_cast, override_on_non_overriding_member
// ignore_for_file: strict_raw_type, inference_failure_on_untyped_parameter
part of 'webrtc_receiver.dart';
class WebRTCReceiveStateMapper extends ClassMapperBase<WebRTCReceiveState> {
WebRTCReceiveStateMapper._();
static WebRTCReceiveStateMapper? _instance;
static WebRTCReceiveStateMapper ensureInitialized() {
if (_instance == null) {
MapperContainer.globals.use(_instance = WebRTCReceiveStateMapper._());
ReceiveSessionStateMapper.ensureInitialized();
}
return _instance!;
}
@override
final String id = 'WebRTCReceiveState';
static LsSignalingConnection _$connection(WebRTCReceiveState v) =>
v.connection;
static const Field<WebRTCReceiveState, LsSignalingConnection> _f$connection =
Field('connection', _$connection);
static WsServerSdpMessage _$offer(WebRTCReceiveState v) => v.offer;
static const Field<WebRTCReceiveState, WsServerSdpMessage> _f$offer =
Field('offer', _$offer);
static RTCStatus? _$status(WebRTCReceiveState v) => v.status;
static const Field<WebRTCReceiveState, RTCStatus> _f$status =
Field('status', _$status);
static RtcReceiveController? _$controller(WebRTCReceiveState v) =>
v.controller;
static const Field<WebRTCReceiveState, RtcReceiveController> _f$controller =
Field('controller', _$controller);
static ReceiveSessionState? _$sessionState(WebRTCReceiveState v) =>
v.sessionState;
static const Field<WebRTCReceiveState, ReceiveSessionState> _f$sessionState =
Field('sessionState', _$sessionState);
@override
final MappableFields<WebRTCReceiveState> fields = const {
#connection: _f$connection,
#offer: _f$offer,
#status: _f$status,
#controller: _f$controller,
#sessionState: _f$sessionState,
};
static WebRTCReceiveState _instantiate(DecodingData data) {
return WebRTCReceiveState(
connection: data.dec(_f$connection),
offer: data.dec(_f$offer),
status: data.dec(_f$status),
controller: data.dec(_f$controller),
sessionState: data.dec(_f$sessionState));
}
@override
final Function instantiate = _instantiate;
static WebRTCReceiveState fromJson(Map<String, dynamic> map) {
return ensureInitialized().decodeMap<WebRTCReceiveState>(map);
}
static WebRTCReceiveState deserialize(String json) {
return ensureInitialized().decodeJson<WebRTCReceiveState>(json);
}
}
mixin WebRTCReceiveStateMappable {
String serialize() {
return WebRTCReceiveStateMapper.ensureInitialized()
.encodeJson<WebRTCReceiveState>(this as WebRTCReceiveState);
}
Map<String, dynamic> toJson() {
return WebRTCReceiveStateMapper.ensureInitialized()
.encodeMap<WebRTCReceiveState>(this as WebRTCReceiveState);
}
WebRTCReceiveStateCopyWith<WebRTCReceiveState, WebRTCReceiveState,
WebRTCReceiveState>
get copyWith => _WebRTCReceiveStateCopyWithImpl(
this as WebRTCReceiveState, $identity, $identity);
@override
String toString() {
return WebRTCReceiveStateMapper.ensureInitialized()
.stringifyValue(this as WebRTCReceiveState);
}
@override
bool operator ==(Object other) {
return WebRTCReceiveStateMapper.ensureInitialized()
.equalsValue(this as WebRTCReceiveState, other);
}
@override
int get hashCode {
return WebRTCReceiveStateMapper.ensureInitialized()
.hashValue(this as WebRTCReceiveState);
}
}
extension WebRTCReceiveStateValueCopy<$R, $Out>
on ObjectCopyWith<$R, WebRTCReceiveState, $Out> {
WebRTCReceiveStateCopyWith<$R, WebRTCReceiveState, $Out>
get $asWebRTCReceiveState =>
$base.as((v, t, t2) => _WebRTCReceiveStateCopyWithImpl(v, t, t2));
}
abstract class WebRTCReceiveStateCopyWith<$R, $In extends WebRTCReceiveState,
$Out> implements ClassCopyWith<$R, $In, $Out> {
ReceiveSessionStateCopyWith<$R, ReceiveSessionState, ReceiveSessionState>?
get sessionState;
$R call(
{LsSignalingConnection? connection,
WsServerSdpMessage? offer,
RTCStatus? status,
RtcReceiveController? controller,
ReceiveSessionState? sessionState});
WebRTCReceiveStateCopyWith<$R2, $In, $Out2> $chain<$R2, $Out2>(
Then<$Out2, $R2> t);
}
class _WebRTCReceiveStateCopyWithImpl<$R, $Out>
extends ClassCopyWithBase<$R, WebRTCReceiveState, $Out>
implements WebRTCReceiveStateCopyWith<$R, WebRTCReceiveState, $Out> {
_WebRTCReceiveStateCopyWithImpl(super.value, super.then, super.then2);
@override
late final ClassMapperBase<WebRTCReceiveState> $mapper =
WebRTCReceiveStateMapper.ensureInitialized();
@override
ReceiveSessionStateCopyWith<$R, ReceiveSessionState, ReceiveSessionState>?
get sessionState =>
$value.sessionState?.copyWith.$chain((v) => call(sessionState: v));
@override
$R call(
{LsSignalingConnection? connection,
WsServerSdpMessage? offer,
Object? status = $none,
Object? controller = $none,
Object? sessionState = $none}) =>
$apply(FieldCopyWithData({
if (connection != null) #connection: connection,
if (offer != null) #offer: offer,
if (status != $none) #status: status,
if (controller != $none) #controller: controller,
if (sessionState != $none) #sessionState: sessionState
}));
@override
WebRTCReceiveState $make(CopyWithData data) => WebRTCReceiveState(
connection: data.get(#connection, or: $value.connection),
offer: data.get(#offer, or: $value.offer),
status: data.get(#status, or: $value.status),
controller: data.get(#controller, or: $value.controller),
sessionState: data.get(#sessionState, or: $value.sessionState));
@override
WebRTCReceiveStateCopyWith<$R2, WebRTCReceiveState, $Out2> $chain<$R2, $Out2>(
Then<$Out2, $R2> t) =>
_WebRTCReceiveStateCopyWithImpl($value, $cast, t);
}
@@ -21,13 +21,18 @@ class ApkProviderParamMapper extends ClassMapperBase<ApkProviderParam> {
final String id = 'ApkProviderParam';
static String _$query(ApkProviderParam v) => v.query;
static const Field<ApkProviderParam, String> _f$query = Field('query', _$query);
static const Field<ApkProviderParam, String> _f$query =
Field('query', _$query);
static bool _$includeSystemApps(ApkProviderParam v) => v.includeSystemApps;
static const Field<ApkProviderParam, bool> _f$includeSystemApps = Field('includeSystemApps', _$includeSystemApps);
static bool _$onlyAppsWithLaunchIntent(ApkProviderParam v) => v.onlyAppsWithLaunchIntent;
static const Field<ApkProviderParam, bool> _f$onlyAppsWithLaunchIntent = Field('onlyAppsWithLaunchIntent', _$onlyAppsWithLaunchIntent);
static const Field<ApkProviderParam, bool> _f$includeSystemApps =
Field('includeSystemApps', _$includeSystemApps);
static bool _$onlyAppsWithLaunchIntent(ApkProviderParam v) =>
v.onlyAppsWithLaunchIntent;
static const Field<ApkProviderParam, bool> _f$onlyAppsWithLaunchIntent =
Field('onlyAppsWithLaunchIntent', _$onlyAppsWithLaunchIntent);
static bool _$selectMultipleApps(ApkProviderParam v) => v.selectMultipleApps;
static const Field<ApkProviderParam, bool> _f$selectMultipleApps = Field('selectMultipleApps', _$selectMultipleApps, opt: true, def: false);
static const Field<ApkProviderParam, bool> _f$selectMultipleApps =
Field('selectMultipleApps', _$selectMultipleApps, opt: true, def: false);
@override
final MappableFields<ApkProviderParam> fields = const {
@@ -59,60 +64,88 @@ class ApkProviderParamMapper extends ClassMapperBase<ApkProviderParam> {
mixin ApkProviderParamMappable {
String serialize() {
return ApkProviderParamMapper.ensureInitialized().encodeJson<ApkProviderParam>(this as ApkProviderParam);
return ApkProviderParamMapper.ensureInitialized()
.encodeJson<ApkProviderParam>(this as ApkProviderParam);
}
Map<String, dynamic> toJson() {
return ApkProviderParamMapper.ensureInitialized().encodeMap<ApkProviderParam>(this as ApkProviderParam);
return ApkProviderParamMapper.ensureInitialized()
.encodeMap<ApkProviderParam>(this as ApkProviderParam);
}
ApkProviderParamCopyWith<ApkProviderParam, ApkProviderParam, ApkProviderParam> get copyWith =>
_ApkProviderParamCopyWithImpl(this as ApkProviderParam, $identity, $identity);
ApkProviderParamCopyWith<ApkProviderParam, ApkProviderParam, ApkProviderParam>
get copyWith => _ApkProviderParamCopyWithImpl(
this as ApkProviderParam, $identity, $identity);
@override
String toString() {
return ApkProviderParamMapper.ensureInitialized().stringifyValue(this as ApkProviderParam);
return ApkProviderParamMapper.ensureInitialized()
.stringifyValue(this as ApkProviderParam);
}
@override
bool operator ==(Object other) {
return ApkProviderParamMapper.ensureInitialized().equalsValue(this as ApkProviderParam, other);
return ApkProviderParamMapper.ensureInitialized()
.equalsValue(this as ApkProviderParam, other);
}
@override
int get hashCode {
return ApkProviderParamMapper.ensureInitialized().hashValue(this as ApkProviderParam);
return ApkProviderParamMapper.ensureInitialized()
.hashValue(this as ApkProviderParam);
}
}
extension ApkProviderParamValueCopy<$R, $Out> on ObjectCopyWith<$R, ApkProviderParam, $Out> {
ApkProviderParamCopyWith<$R, ApkProviderParam, $Out> get $asApkProviderParam => $base.as((v, t, t2) => _ApkProviderParamCopyWithImpl(v, t, t2));
extension ApkProviderParamValueCopy<$R, $Out>
on ObjectCopyWith<$R, ApkProviderParam, $Out> {
ApkProviderParamCopyWith<$R, ApkProviderParam, $Out>
get $asApkProviderParam =>
$base.as((v, t, t2) => _ApkProviderParamCopyWithImpl(v, t, t2));
}
abstract class ApkProviderParamCopyWith<$R, $In extends ApkProviderParam, $Out> implements ClassCopyWith<$R, $In, $Out> {
$R call({String? query, bool? includeSystemApps, bool? onlyAppsWithLaunchIntent, bool? selectMultipleApps});
ApkProviderParamCopyWith<$R2, $In, $Out2> $chain<$R2, $Out2>(Then<$Out2, $R2> t);
abstract class ApkProviderParamCopyWith<$R, $In extends ApkProviderParam, $Out>
implements ClassCopyWith<$R, $In, $Out> {
$R call(
{String? query,
bool? includeSystemApps,
bool? onlyAppsWithLaunchIntent,
bool? selectMultipleApps});
ApkProviderParamCopyWith<$R2, $In, $Out2> $chain<$R2, $Out2>(
Then<$Out2, $R2> t);
}
class _ApkProviderParamCopyWithImpl<$R, $Out> extends ClassCopyWithBase<$R, ApkProviderParam, $Out>
class _ApkProviderParamCopyWithImpl<$R, $Out>
extends ClassCopyWithBase<$R, ApkProviderParam, $Out>
implements ApkProviderParamCopyWith<$R, ApkProviderParam, $Out> {
_ApkProviderParamCopyWithImpl(super.value, super.then, super.then2);
@override
late final ClassMapperBase<ApkProviderParam> $mapper = ApkProviderParamMapper.ensureInitialized();
late final ClassMapperBase<ApkProviderParam> $mapper =
ApkProviderParamMapper.ensureInitialized();
@override
$R call({String? query, bool? includeSystemApps, bool? onlyAppsWithLaunchIntent, bool? selectMultipleApps}) => $apply(FieldCopyWithData({
$R call(
{String? query,
bool? includeSystemApps,
bool? onlyAppsWithLaunchIntent,
bool? selectMultipleApps}) =>
$apply(FieldCopyWithData({
if (query != null) #query: query,
if (includeSystemApps != null) #includeSystemApps: includeSystemApps,
if (onlyAppsWithLaunchIntent != null) #onlyAppsWithLaunchIntent: onlyAppsWithLaunchIntent,
if (onlyAppsWithLaunchIntent != null)
#onlyAppsWithLaunchIntent: onlyAppsWithLaunchIntent,
if (selectMultipleApps != null) #selectMultipleApps: selectMultipleApps
}));
@override
ApkProviderParam $make(CopyWithData data) => ApkProviderParam(
query: data.get(#query, or: $value.query),
includeSystemApps: data.get(#includeSystemApps, or: $value.includeSystemApps),
onlyAppsWithLaunchIntent: data.get(#onlyAppsWithLaunchIntent, or: $value.onlyAppsWithLaunchIntent),
selectMultipleApps: data.get(#selectMultipleApps, or: $value.selectMultipleApps));
includeSystemApps:
data.get(#includeSystemApps, or: $value.includeSystemApps),
onlyAppsWithLaunchIntent: data.get(#onlyAppsWithLaunchIntent,
or: $value.onlyAppsWithLaunchIntent),
selectMultipleApps:
data.get(#selectMultipleApps, or: $value.selectMultipleApps));
@override
ApkProviderParamCopyWith<$R2, ApkProviderParam, $Out2> $chain<$R2, $Out2>(Then<$Out2, $R2> t) => _ApkProviderParamCopyWithImpl($value, $cast, t);
ApkProviderParamCopyWith<$R2, ApkProviderParam, $Out2> $chain<$R2, $Out2>(
Then<$Out2, $R2> t) =>
_ApkProviderParamCopyWithImpl($value, $cast, t);
}
@@ -6,7 +6,8 @@
part of 'cached_apk_provider_param.dart';
class CachedApkProviderParamMapper extends ClassMapperBase<CachedApkProviderParam> {
class CachedApkProviderParamMapper
extends ClassMapperBase<CachedApkProviderParam> {
CachedApkProviderParamMapper._();
static CachedApkProviderParamMapper? _instance;
@@ -20,12 +21,18 @@ class CachedApkProviderParamMapper extends ClassMapperBase<CachedApkProviderPara
@override
final String id = 'CachedApkProviderParam';
static bool _$includeSystemApps(CachedApkProviderParam v) => v.includeSystemApps;
static const Field<CachedApkProviderParam, bool> _f$includeSystemApps = Field('includeSystemApps', _$includeSystemApps);
static bool _$onlyAppsWithLaunchIntent(CachedApkProviderParam v) => v.onlyAppsWithLaunchIntent;
static const Field<CachedApkProviderParam, bool> _f$onlyAppsWithLaunchIntent = Field('onlyAppsWithLaunchIntent', _$onlyAppsWithLaunchIntent);
static bool _$selectMultipleApps(CachedApkProviderParam v) => v.selectMultipleApps;
static const Field<CachedApkProviderParam, bool> _f$selectMultipleApps = Field('selectMultipleApps', _$selectMultipleApps, opt: true, def: false);
static bool _$includeSystemApps(CachedApkProviderParam v) =>
v.includeSystemApps;
static const Field<CachedApkProviderParam, bool> _f$includeSystemApps =
Field('includeSystemApps', _$includeSystemApps);
static bool _$onlyAppsWithLaunchIntent(CachedApkProviderParam v) =>
v.onlyAppsWithLaunchIntent;
static const Field<CachedApkProviderParam, bool> _f$onlyAppsWithLaunchIntent =
Field('onlyAppsWithLaunchIntent', _$onlyAppsWithLaunchIntent);
static bool _$selectMultipleApps(CachedApkProviderParam v) =>
v.selectMultipleApps;
static const Field<CachedApkProviderParam, bool> _f$selectMultipleApps =
Field('selectMultipleApps', _$selectMultipleApps, opt: true, def: false);
@override
final MappableFields<CachedApkProviderParam> fields = const {
@@ -55,60 +62,88 @@ class CachedApkProviderParamMapper extends ClassMapperBase<CachedApkProviderPara
mixin CachedApkProviderParamMappable {
String serialize() {
return CachedApkProviderParamMapper.ensureInitialized().encodeJson<CachedApkProviderParam>(this as CachedApkProviderParam);
return CachedApkProviderParamMapper.ensureInitialized()
.encodeJson<CachedApkProviderParam>(this as CachedApkProviderParam);
}
Map<String, dynamic> toJson() {
return CachedApkProviderParamMapper.ensureInitialized().encodeMap<CachedApkProviderParam>(this as CachedApkProviderParam);
return CachedApkProviderParamMapper.ensureInitialized()
.encodeMap<CachedApkProviderParam>(this as CachedApkProviderParam);
}
CachedApkProviderParamCopyWith<CachedApkProviderParam, CachedApkProviderParam, CachedApkProviderParam> get copyWith =>
_CachedApkProviderParamCopyWithImpl(this as CachedApkProviderParam, $identity, $identity);
CachedApkProviderParamCopyWith<CachedApkProviderParam, CachedApkProviderParam,
CachedApkProviderParam>
get copyWith => _CachedApkProviderParamCopyWithImpl(
this as CachedApkProviderParam, $identity, $identity);
@override
String toString() {
return CachedApkProviderParamMapper.ensureInitialized().stringifyValue(this as CachedApkProviderParam);
return CachedApkProviderParamMapper.ensureInitialized()
.stringifyValue(this as CachedApkProviderParam);
}
@override
bool operator ==(Object other) {
return CachedApkProviderParamMapper.ensureInitialized().equalsValue(this as CachedApkProviderParam, other);
return CachedApkProviderParamMapper.ensureInitialized()
.equalsValue(this as CachedApkProviderParam, other);
}
@override
int get hashCode {
return CachedApkProviderParamMapper.ensureInitialized().hashValue(this as CachedApkProviderParam);
return CachedApkProviderParamMapper.ensureInitialized()
.hashValue(this as CachedApkProviderParam);
}
}
extension CachedApkProviderParamValueCopy<$R, $Out> on ObjectCopyWith<$R, CachedApkProviderParam, $Out> {
CachedApkProviderParamCopyWith<$R, CachedApkProviderParam, $Out> get $asCachedApkProviderParam =>
$base.as((v, t, t2) => _CachedApkProviderParamCopyWithImpl(v, t, t2));
extension CachedApkProviderParamValueCopy<$R, $Out>
on ObjectCopyWith<$R, CachedApkProviderParam, $Out> {
CachedApkProviderParamCopyWith<$R, CachedApkProviderParam, $Out>
get $asCachedApkProviderParam =>
$base.as((v, t, t2) => _CachedApkProviderParamCopyWithImpl(v, t, t2));
}
abstract class CachedApkProviderParamCopyWith<$R, $In extends CachedApkProviderParam, $Out> implements ClassCopyWith<$R, $In, $Out> {
$R call({bool? includeSystemApps, bool? onlyAppsWithLaunchIntent, bool? selectMultipleApps});
CachedApkProviderParamCopyWith<$R2, $In, $Out2> $chain<$R2, $Out2>(Then<$Out2, $R2> t);
abstract class CachedApkProviderParamCopyWith<
$R,
$In extends CachedApkProviderParam,
$Out> implements ClassCopyWith<$R, $In, $Out> {
$R call(
{bool? includeSystemApps,
bool? onlyAppsWithLaunchIntent,
bool? selectMultipleApps});
CachedApkProviderParamCopyWith<$R2, $In, $Out2> $chain<$R2, $Out2>(
Then<$Out2, $R2> t);
}
class _CachedApkProviderParamCopyWithImpl<$R, $Out> extends ClassCopyWithBase<$R, CachedApkProviderParam, $Out>
implements CachedApkProviderParamCopyWith<$R, CachedApkProviderParam, $Out> {
class _CachedApkProviderParamCopyWithImpl<$R, $Out>
extends ClassCopyWithBase<$R, CachedApkProviderParam, $Out>
implements
CachedApkProviderParamCopyWith<$R, CachedApkProviderParam, $Out> {
_CachedApkProviderParamCopyWithImpl(super.value, super.then, super.then2);
@override
late final ClassMapperBase<CachedApkProviderParam> $mapper = CachedApkProviderParamMapper.ensureInitialized();
late final ClassMapperBase<CachedApkProviderParam> $mapper =
CachedApkProviderParamMapper.ensureInitialized();
@override
$R call({bool? includeSystemApps, bool? onlyAppsWithLaunchIntent, bool? selectMultipleApps}) => $apply(FieldCopyWithData({
$R call(
{bool? includeSystemApps,
bool? onlyAppsWithLaunchIntent,
bool? selectMultipleApps}) =>
$apply(FieldCopyWithData({
if (includeSystemApps != null) #includeSystemApps: includeSystemApps,
if (onlyAppsWithLaunchIntent != null) #onlyAppsWithLaunchIntent: onlyAppsWithLaunchIntent,
if (onlyAppsWithLaunchIntent != null)
#onlyAppsWithLaunchIntent: onlyAppsWithLaunchIntent,
if (selectMultipleApps != null) #selectMultipleApps: selectMultipleApps
}));
@override
CachedApkProviderParam $make(CopyWithData data) => CachedApkProviderParam(
includeSystemApps: data.get(#includeSystemApps, or: $value.includeSystemApps),
onlyAppsWithLaunchIntent: data.get(#onlyAppsWithLaunchIntent, or: $value.onlyAppsWithLaunchIntent),
selectMultipleApps: data.get(#selectMultipleApps, or: $value.selectMultipleApps));
includeSystemApps:
data.get(#includeSystemApps, or: $value.includeSystemApps),
onlyAppsWithLaunchIntent: data.get(#onlyAppsWithLaunchIntent,
or: $value.onlyAppsWithLaunchIntent),
selectMultipleApps:
data.get(#selectMultipleApps, or: $value.selectMultipleApps));
@override
CachedApkProviderParamCopyWith<$R2, CachedApkProviderParam, $Out2> $chain<$R2, $Out2>(Then<$Out2, $R2> t) =>
_CachedApkProviderParamCopyWithImpl($value, $cast, t);
CachedApkProviderParamCopyWith<$R2, CachedApkProviderParam, $Out2>
$chain<$R2, $Out2>(Then<$Out2, $R2> t) =>
_CachedApkProviderParamCopyWithImpl($value, $cast, t);
}
@@ -47,6 +47,10 @@ const _version = 'ls_version';
// Security keys (generated on first app start)
const _securityContext = 'ls_security_context';
// WebRTC
const _signalingServers = 'ls_signaling_servers';
const _stunServers = 'ls_stun_servers';
// Received file history
const _receiveHistory = 'ls_receive_history';
@@ -217,6 +221,32 @@ class PersistenceService {
await _prefs.setString(_securityContext, jsonEncode(context));
}
List<String>? getSignalingServers() {
final serversRaw = _prefs.getString(_signalingServers);
if (serversRaw == null) {
return null;
}
return (jsonDecode(serversRaw) as List).cast<String>();
}
Future<void> setSignalingServers(List<String> servers) async {
await _prefs.setString(_signalingServers, jsonEncode(servers));
}
List<String>? getStunServers() {
final serversRaw = _prefs.getString(_stunServers);
if (serversRaw == null) {
return null;
}
return (jsonDecode(serversRaw) as List).cast<String>();
}
Future<void> setStunServers(List<String> servers) async {
await _prefs.setString(_stunServers, jsonEncode(servers));
}
List<ReceiveHistoryEntry> getReceiveHistory() {
final historyRaw = _prefs.getStringList(_receiveHistory) ?? [];
return historyRaw.map((entry) => ReceiveHistoryEntry.fromJson(jsonDecode(entry))).toList();
+35
View File
@@ -0,0 +1,35 @@
// This file is automatically generated, so please do not edit it.
// @generated by `flutter_rust_bridge`@ 2.11.1.
// ignore_for_file: invalid_use_of_internal_member, unused_import, unnecessary_import
import 'package:flutter_rust_bridge/flutter_rust_bridge_for_generated.dart';
import 'package:localsend_app/rust/frb_generated.dart';
Future<void> verifyCert({required String cert, required String publicKey}) =>
RustLib.instance.api
.crateApiCryptoVerifyCert(cert: cert, publicKey: publicKey);
Future<KeyPair> generateKeyPair() =>
RustLib.instance.api.crateApiCryptoGenerateKeyPair();
class KeyPair {
final String privateKey;
final String publicKey;
const KeyPair({
required this.privateKey,
required this.publicKey,
});
@override
int get hashCode => privateKey.hashCode ^ publicKey.hashCode;
@override
bool operator ==(Object other) =>
identical(this, other) ||
other is KeyPair &&
runtimeType == other.runtimeType &&
privateKey == other.privateKey &&
publicKey == other.publicKey;
}
+10
View File
@@ -0,0 +1,10 @@
// This file is automatically generated, so please do not edit it.
// @generated by `flutter_rust_bridge`@ 2.11.1.
// ignore_for_file: invalid_use_of_internal_member, unused_import, unnecessary_import
import 'package:flutter_rust_bridge/flutter_rust_bridge_for_generated.dart';
import 'package:localsend_app/rust/frb_generated.dart';
Future<void> enableDebugLogging() =>
RustLib.instance.api.crateApiLoggingEnableDebugLogging();
+82
View File
@@ -0,0 +1,82 @@
// This file is automatically generated, so please do not edit it.
// @generated by `flutter_rust_bridge`@ 2.11.1.
// ignore_for_file: invalid_use_of_internal_member, unused_import, unnecessary_import
import 'package:flutter_rust_bridge/flutter_rust_bridge_for_generated.dart';
import 'package:localsend_app/rust/frb_generated.dart';
// These types are ignored because they are neither used by any `pub` functions nor (for structs and enums) marked `#[frb(unignore)]`: `PrepareUploadRequestDto`, `PrepareUploadResponseDto`, `ProtocolType`, `RegisterDto`, `RegisterResponseDto`
enum DeviceType {
mobile,
desktop,
web,
headless,
server,
;
}
class FileDto {
final String id;
final String fileName;
final BigInt size;
final String fileType;
final String? sha256;
final String? preview;
final FileMetadata? metadata;
const FileDto({
required this.id,
required this.fileName,
required this.size,
required this.fileType,
this.sha256,
this.preview,
this.metadata,
});
@override
int get hashCode =>
id.hashCode ^
fileName.hashCode ^
size.hashCode ^
fileType.hashCode ^
sha256.hashCode ^
preview.hashCode ^
metadata.hashCode;
@override
bool operator ==(Object other) =>
identical(this, other) ||
other is FileDto &&
runtimeType == other.runtimeType &&
id == other.id &&
fileName == other.fileName &&
size == other.size &&
fileType == other.fileType &&
sha256 == other.sha256 &&
preview == other.preview &&
metadata == other.metadata;
}
class FileMetadata {
final String? modified;
final String? accessed;
const FileMetadata({
this.modified,
this.accessed,
});
@override
int get hashCode => modified.hashCode ^ accessed.hashCode;
@override
bool operator ==(Object other) =>
identical(this, other) ||
other is FileMetadata &&
runtimeType == other.runtimeType &&
modified == other.modified &&
accessed == other.accessed;
}
+352
View File
@@ -0,0 +1,352 @@
// This file is automatically generated, so please do not edit it.
// @generated by `flutter_rust_bridge`@ 2.11.1.
// ignore_for_file: invalid_use_of_internal_member, unused_import, unnecessary_import
import 'package:flutter_rust_bridge/flutter_rust_bridge_for_generated.dart';
import 'package:freezed_annotation/freezed_annotation.dart' hide protected;
import 'package:localsend_app/rust/api/model.dart';
import 'package:localsend_app/rust/frb_generated.dart';
import 'package:uuid/uuid.dart';
part 'webrtc.freezed.dart';
// These functions are ignored because they are not marked as `pub`: `sign`
Stream<WsServerMessage> connect(
{required String uri,
required ProposingClientInfo info,
required String privateKey,
required FutureOr<void> Function(LsSignalingConnection)
onConnection}) =>
RustLib.instance.api.crateApiWebrtcConnect(
uri: uri,
info: info,
privateKey: privateKey,
onConnection: onConnection);
// Rust type: RustOpaqueMoi<flutter_rust_bridge::for_generated::RustAutoOpaqueInner<LsSignalingConnection>>
abstract class LsSignalingConnection implements RustOpaqueInterface {
Future<RtcReceiveController> acceptOffer(
{required List<String> stunServers,
required WsServerSdpMessage offer,
required String privateKey,
ExpectingPublicKey? expectingPublicKey,
PinConfig? pin});
Future<RtcSendController> sendOffer(
{required List<String> stunServers,
required UuidValue target,
required String privateKey,
ExpectingPublicKey? expectingPublicKey,
PinConfig? pin,
required List<FileDto> files});
Future<void> updateInfo({required ClientInfoWithoutId info});
}
// Rust type: RustOpaqueMoi<flutter_rust_bridge::for_generated::RustAutoOpaqueInner<RTCFileReceiver>>
abstract class RtcFileReceiver implements RustOpaqueInterface {
Future<String> getFileId();
Stream<Uint8List> receive();
}
// Rust type: RustOpaqueMoi<flutter_rust_bridge::for_generated::RustAutoOpaqueInner<RTCFileSender>>
abstract class RtcFileSender implements RustOpaqueInterface {
Future<void> send({required List<int> data});
}
// Rust type: RustOpaqueMoi<flutter_rust_bridge::for_generated::RustAutoOpaqueInner<RTCReceiveController>>
abstract class RtcReceiveController implements RustOpaqueInterface {
Future<void> decline();
Stream<RTCFileError> listenError();
Future<List<FileDto>> listenFiles();
Stream<RtcFileReceiver> listenReceiving();
Stream<RTCStatus> listenStatus();
Future<void> sendFileStatus({required RTCSendFileResponse status});
Future<void> sendPin({required String pin});
Future<void> sendSelection({required Set<String> selection});
}
// Rust type: RustOpaqueMoi<flutter_rust_bridge::for_generated::RustAutoOpaqueInner<RTCSendController>>
abstract class RtcSendController implements RustOpaqueInterface {
Stream<RTCFileError> listenError();
Future<Set<String>> listenSelectedFiles();
Stream<RTCStatus> listenStatus();
Future<RtcFileSender> sendFile({required String fileId});
Future<void> sendPin({required String pin});
}
class ClientInfo {
final UuidValue id;
final String alias;
final String version;
final String? deviceModel;
final DeviceType? deviceType;
final String token;
const ClientInfo({
required this.id,
required this.alias,
required this.version,
this.deviceModel,
this.deviceType,
required this.token,
});
@override
int get hashCode =>
id.hashCode ^
alias.hashCode ^
version.hashCode ^
deviceModel.hashCode ^
deviceType.hashCode ^
token.hashCode;
@override
bool operator ==(Object other) =>
identical(this, other) ||
other is ClientInfo &&
runtimeType == other.runtimeType &&
id == other.id &&
alias == other.alias &&
version == other.version &&
deviceModel == other.deviceModel &&
deviceType == other.deviceType &&
token == other.token;
}
class ClientInfoWithoutId {
final String alias;
final String version;
final String? deviceModel;
final DeviceType? deviceType;
final String token;
const ClientInfoWithoutId({
required this.alias,
required this.version,
this.deviceModel,
this.deviceType,
required this.token,
});
@override
int get hashCode =>
alias.hashCode ^
version.hashCode ^
deviceModel.hashCode ^
deviceType.hashCode ^
token.hashCode;
@override
bool operator ==(Object other) =>
identical(this, other) ||
other is ClientInfoWithoutId &&
runtimeType == other.runtimeType &&
alias == other.alias &&
version == other.version &&
deviceModel == other.deviceModel &&
deviceType == other.deviceType &&
token == other.token;
}
class ExpectingPublicKey {
final String publicKey;
/// "ed25519" or "rsa-pss"
final String kind;
const ExpectingPublicKey({
required this.publicKey,
required this.kind,
});
@override
int get hashCode => publicKey.hashCode ^ kind.hashCode;
@override
bool operator ==(Object other) =>
identical(this, other) ||
other is ExpectingPublicKey &&
runtimeType == other.runtimeType &&
publicKey == other.publicKey &&
kind == other.kind;
}
class PinConfig {
final String pin;
final int maxTries;
const PinConfig({
required this.pin,
required this.maxTries,
});
@override
int get hashCode => pin.hashCode ^ maxTries.hashCode;
@override
bool operator ==(Object other) =>
identical(this, other) ||
other is PinConfig &&
runtimeType == other.runtimeType &&
pin == other.pin &&
maxTries == other.maxTries;
}
class ProposingClientInfo {
final String alias;
final String version;
final String? deviceModel;
final DeviceType? deviceType;
const ProposingClientInfo({
required this.alias,
required this.version,
this.deviceModel,
this.deviceType,
});
@override
int get hashCode =>
alias.hashCode ^
version.hashCode ^
deviceModel.hashCode ^
deviceType.hashCode;
@override
bool operator ==(Object other) =>
identical(this, other) ||
other is ProposingClientInfo &&
runtimeType == other.runtimeType &&
alias == other.alias &&
version == other.version &&
deviceModel == other.deviceModel &&
deviceType == other.deviceType;
}
class RTCFileError {
final String fileId;
final String error;
const RTCFileError({
required this.fileId,
required this.error,
});
@override
int get hashCode => fileId.hashCode ^ error.hashCode;
@override
bool operator ==(Object other) =>
identical(this, other) ||
other is RTCFileError &&
runtimeType == other.runtimeType &&
fileId == other.fileId &&
error == other.error;
}
class RTCSendFileResponse {
final String id;
final bool success;
final String? error;
const RTCSendFileResponse({
required this.id,
required this.success,
this.error,
});
@override
int get hashCode => id.hashCode ^ success.hashCode ^ error.hashCode;
@override
bool operator ==(Object other) =>
identical(this, other) ||
other is RTCSendFileResponse &&
runtimeType == other.runtimeType &&
id == other.id &&
success == other.success &&
error == other.error;
}
@freezed
sealed class RTCStatus with _$RTCStatus {
const RTCStatus._();
const factory RTCStatus.sdpExchanged() = RTCStatus_SdpExchanged;
const factory RTCStatus.connected() = RTCStatus_Connected;
const factory RTCStatus.pinRequired() = RTCStatus_PinRequired;
const factory RTCStatus.tooManyAttempts() = RTCStatus_TooManyAttempts;
const factory RTCStatus.declined() = RTCStatus_Declined;
const factory RTCStatus.sending() = RTCStatus_Sending;
const factory RTCStatus.finished() = RTCStatus_Finished;
const factory RTCStatus.error(
String field0,
) = RTCStatus_Error;
}
@freezed
sealed class WsServerMessage with _$WsServerMessage {
const WsServerMessage._();
const factory WsServerMessage.hello({
required ClientInfo client,
required List<ClientInfo> peers,
}) = WsServerMessage_Hello;
const factory WsServerMessage.join({
required ClientInfo peer,
}) = WsServerMessage_Join;
const factory WsServerMessage.update({
required ClientInfo peer,
}) = WsServerMessage_Update;
const factory WsServerMessage.left({
required UuidValue peerId,
}) = WsServerMessage_Left;
const factory WsServerMessage.offer(
WsServerSdpMessage field0,
) = WsServerMessage_Offer;
const factory WsServerMessage.answer(
WsServerSdpMessage field0,
) = WsServerMessage_Answer;
const factory WsServerMessage.error({
required int code,
}) = WsServerMessage_Error;
}
class WsServerSdpMessage {
final ClientInfo peer;
final String sessionId;
final String sdp;
const WsServerSdpMessage({
required this.peer,
required this.sessionId,
required this.sdp,
});
@override
int get hashCode => peer.hashCode ^ sessionId.hashCode ^ sdp.hashCode;
@override
bool operator ==(Object other) =>
identical(this, other) ||
other is WsServerSdpMessage &&
runtimeType == other.runtimeType &&
peer == other.peer &&
sessionId == other.sessionId &&
sdp == other.sdp;
}
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
+987
View File
@@ -0,0 +1,987 @@
// This file is automatically generated, so please do not edit it.
// @generated by `flutter_rust_bridge`@ 2.11.1.
// ignore_for_file: unused_import, unused_element, unnecessary_import, duplicate_ignore, invalid_use_of_internal_member, annotate_overrides, non_constant_identifier_names, curly_braces_in_flow_control_structures, prefer_const_literals_to_create_immutables, unused_field
import 'dart:async';
import 'dart:convert';
import 'dart:ffi' as ffi;
import 'package:flutter_rust_bridge/flutter_rust_bridge_for_generated_io.dart';
import 'package:localsend_app/rust/api/crypto.dart';
import 'package:localsend_app/rust/api/logging.dart';
import 'package:localsend_app/rust/api/model.dart';
import 'package:localsend_app/rust/api/webrtc.dart';
import 'package:localsend_app/rust/frb_generated.dart';
import 'package:uuid/uuid.dart';
abstract class RustLibApiImplPlatform extends BaseApiImpl<RustLibWire> {
RustLibApiImplPlatform({
required super.handler,
required super.wire,
required super.generalizedFrbRustBinding,
required super.portManager,
});
CrossPlatformFinalizerArg
get rust_arc_decrement_strong_count_LsSignalingConnectionPtr => wire
._rust_arc_decrement_strong_count_RustOpaque_flutter_rust_bridgefor_generatedRustAutoOpaqueInnerLsSignalingConnectionPtr;
CrossPlatformFinalizerArg
get rust_arc_decrement_strong_count_RtcFileReceiverPtr => wire
._rust_arc_decrement_strong_count_RustOpaque_flutter_rust_bridgefor_generatedRustAutoOpaqueInnerRTCFileReceiverPtr;
CrossPlatformFinalizerArg
get rust_arc_decrement_strong_count_RtcFileSenderPtr => wire
._rust_arc_decrement_strong_count_RustOpaque_flutter_rust_bridgefor_generatedRustAutoOpaqueInnerRTCFileSenderPtr;
CrossPlatformFinalizerArg
get rust_arc_decrement_strong_count_RtcReceiveControllerPtr => wire
._rust_arc_decrement_strong_count_RustOpaque_flutter_rust_bridgefor_generatedRustAutoOpaqueInnerRTCReceiveControllerPtr;
CrossPlatformFinalizerArg
get rust_arc_decrement_strong_count_RtcSendControllerPtr => wire
._rust_arc_decrement_strong_count_RustOpaque_flutter_rust_bridgefor_generatedRustAutoOpaqueInnerRTCSendControllerPtr;
@protected
AnyhowException dco_decode_AnyhowException(dynamic raw);
@protected
LsSignalingConnection
dco_decode_Auto_Owned_RustOpaque_flutter_rust_bridgefor_generatedRustAutoOpaqueInnerLsSignalingConnection(
dynamic raw);
@protected
RtcFileReceiver
dco_decode_Auto_Owned_RustOpaque_flutter_rust_bridgefor_generatedRustAutoOpaqueInnerRTCFileReceiver(
dynamic raw);
@protected
RtcFileSender
dco_decode_Auto_Owned_RustOpaque_flutter_rust_bridgefor_generatedRustAutoOpaqueInnerRTCFileSender(
dynamic raw);
@protected
RtcReceiveController
dco_decode_Auto_Owned_RustOpaque_flutter_rust_bridgefor_generatedRustAutoOpaqueInnerRTCReceiveController(
dynamic raw);
@protected
RtcSendController
dco_decode_Auto_Owned_RustOpaque_flutter_rust_bridgefor_generatedRustAutoOpaqueInnerRTCSendController(
dynamic raw);
@protected
RtcSendController
dco_decode_Auto_RefMut_RustOpaque_flutter_rust_bridgefor_generatedRustAutoOpaqueInnerRTCSendController(
dynamic raw);
@protected
LsSignalingConnection
dco_decode_Auto_Ref_RustOpaque_flutter_rust_bridgefor_generatedRustAutoOpaqueInnerLsSignalingConnection(
dynamic raw);
@protected
RtcFileReceiver
dco_decode_Auto_Ref_RustOpaque_flutter_rust_bridgefor_generatedRustAutoOpaqueInnerRTCFileReceiver(
dynamic raw);
@protected
RtcFileSender
dco_decode_Auto_Ref_RustOpaque_flutter_rust_bridgefor_generatedRustAutoOpaqueInnerRTCFileSender(
dynamic raw);
@protected
RtcReceiveController
dco_decode_Auto_Ref_RustOpaque_flutter_rust_bridgefor_generatedRustAutoOpaqueInnerRTCReceiveController(
dynamic raw);
@protected
RtcSendController
dco_decode_Auto_Ref_RustOpaque_flutter_rust_bridgefor_generatedRustAutoOpaqueInnerRTCSendController(
dynamic raw);
@protected
FutureOr<void> Function(LsSignalingConnection)
dco_decode_DartFn_Inputs_Auto_Owned_RustOpaque_flutter_rust_bridgefor_generatedRustAutoOpaqueInnerLsSignalingConnection_Output_unit_AnyhowException(
dynamic raw);
@protected
Object dco_decode_DartOpaque(dynamic raw);
@protected
LsSignalingConnection
dco_decode_RustOpaque_flutter_rust_bridgefor_generatedRustAutoOpaqueInnerLsSignalingConnection(
dynamic raw);
@protected
RtcFileReceiver
dco_decode_RustOpaque_flutter_rust_bridgefor_generatedRustAutoOpaqueInnerRTCFileReceiver(
dynamic raw);
@protected
RtcFileSender
dco_decode_RustOpaque_flutter_rust_bridgefor_generatedRustAutoOpaqueInnerRTCFileSender(
dynamic raw);
@protected
RtcReceiveController
dco_decode_RustOpaque_flutter_rust_bridgefor_generatedRustAutoOpaqueInnerRTCReceiveController(
dynamic raw);
@protected
RtcSendController
dco_decode_RustOpaque_flutter_rust_bridgefor_generatedRustAutoOpaqueInnerRTCSendController(
dynamic raw);
@protected
Set<String> dco_decode_Set_String_None(dynamic raw);
@protected
RustStreamSink<RtcFileReceiver>
dco_decode_StreamSink_Auto_Owned_RustOpaque_flutter_rust_bridgefor_generatedRustAutoOpaqueInnerRTCFileReceiver_Sse(
dynamic raw);
@protected
RustStreamSink<Uint8List> dco_decode_StreamSink_list_prim_u_8_strict_Sse(
dynamic raw);
@protected
RustStreamSink<RTCFileError> dco_decode_StreamSink_rtc_file_error_Sse(
dynamic raw);
@protected
RustStreamSink<RTCStatus> dco_decode_StreamSink_rtc_status_Sse(dynamic raw);
@protected
RustStreamSink<WsServerMessage> dco_decode_StreamSink_ws_server_message_Sse(
dynamic raw);
@protected
String dco_decode_String(dynamic raw);
@protected
UuidValue dco_decode_Uuid(dynamic raw);
@protected
bool dco_decode_bool(dynamic raw);
@protected
ClientInfo dco_decode_box_autoadd_client_info(dynamic raw);
@protected
ClientInfoWithoutId dco_decode_box_autoadd_client_info_without_id(
dynamic raw);
@protected
DeviceType dco_decode_box_autoadd_device_type(dynamic raw);
@protected
ExpectingPublicKey dco_decode_box_autoadd_expecting_public_key(dynamic raw);
@protected
FileMetadata dco_decode_box_autoadd_file_metadata(dynamic raw);
@protected
PinConfig dco_decode_box_autoadd_pin_config(dynamic raw);
@protected
ProposingClientInfo dco_decode_box_autoadd_proposing_client_info(dynamic raw);
@protected
RTCSendFileResponse dco_decode_box_autoadd_rtc_send_file_response(
dynamic raw);
@protected
WsServerSdpMessage dco_decode_box_autoadd_ws_server_sdp_message(dynamic raw);
@protected
ClientInfo dco_decode_client_info(dynamic raw);
@protected
ClientInfoWithoutId dco_decode_client_info_without_id(dynamic raw);
@protected
DeviceType dco_decode_device_type(dynamic raw);
@protected
ExpectingPublicKey dco_decode_expecting_public_key(dynamic raw);
@protected
FileDto dco_decode_file_dto(dynamic raw);
@protected
FileMetadata dco_decode_file_metadata(dynamic raw);
@protected
int dco_decode_i_32(dynamic raw);
@protected
PlatformInt64 dco_decode_isize(dynamic raw);
@protected
KeyPair dco_decode_key_pair(dynamic raw);
@protected
List<String> dco_decode_list_String(dynamic raw);
@protected
List<ClientInfo> dco_decode_list_client_info(dynamic raw);
@protected
List<FileDto> dco_decode_list_file_dto(dynamic raw);
@protected
List<int> dco_decode_list_prim_u_8_loose(dynamic raw);
@protected
Uint8List dco_decode_list_prim_u_8_strict(dynamic raw);
@protected
String? dco_decode_opt_String(dynamic raw);
@protected
DeviceType? dco_decode_opt_box_autoadd_device_type(dynamic raw);
@protected
ExpectingPublicKey? dco_decode_opt_box_autoadd_expecting_public_key(
dynamic raw);
@protected
FileMetadata? dco_decode_opt_box_autoadd_file_metadata(dynamic raw);
@protected
PinConfig? dco_decode_opt_box_autoadd_pin_config(dynamic raw);
@protected
PinConfig dco_decode_pin_config(dynamic raw);
@protected
ProposingClientInfo dco_decode_proposing_client_info(dynamic raw);
@protected
RTCFileError dco_decode_rtc_file_error(dynamic raw);
@protected
RTCSendFileResponse dco_decode_rtc_send_file_response(dynamic raw);
@protected
RTCStatus dco_decode_rtc_status(dynamic raw);
@protected
int dco_decode_u_16(dynamic raw);
@protected
BigInt dco_decode_u_64(dynamic raw);
@protected
int dco_decode_u_8(dynamic raw);
@protected
void dco_decode_unit(dynamic raw);
@protected
BigInt dco_decode_usize(dynamic raw);
@protected
WsServerMessage dco_decode_ws_server_message(dynamic raw);
@protected
WsServerSdpMessage dco_decode_ws_server_sdp_message(dynamic raw);
@protected
AnyhowException sse_decode_AnyhowException(SseDeserializer deserializer);
@protected
LsSignalingConnection
sse_decode_Auto_Owned_RustOpaque_flutter_rust_bridgefor_generatedRustAutoOpaqueInnerLsSignalingConnection(
SseDeserializer deserializer);
@protected
RtcFileReceiver
sse_decode_Auto_Owned_RustOpaque_flutter_rust_bridgefor_generatedRustAutoOpaqueInnerRTCFileReceiver(
SseDeserializer deserializer);
@protected
RtcFileSender
sse_decode_Auto_Owned_RustOpaque_flutter_rust_bridgefor_generatedRustAutoOpaqueInnerRTCFileSender(
SseDeserializer deserializer);
@protected
RtcReceiveController
sse_decode_Auto_Owned_RustOpaque_flutter_rust_bridgefor_generatedRustAutoOpaqueInnerRTCReceiveController(
SseDeserializer deserializer);
@protected
RtcSendController
sse_decode_Auto_Owned_RustOpaque_flutter_rust_bridgefor_generatedRustAutoOpaqueInnerRTCSendController(
SseDeserializer deserializer);
@protected
RtcSendController
sse_decode_Auto_RefMut_RustOpaque_flutter_rust_bridgefor_generatedRustAutoOpaqueInnerRTCSendController(
SseDeserializer deserializer);
@protected
LsSignalingConnection
sse_decode_Auto_Ref_RustOpaque_flutter_rust_bridgefor_generatedRustAutoOpaqueInnerLsSignalingConnection(
SseDeserializer deserializer);
@protected
RtcFileReceiver
sse_decode_Auto_Ref_RustOpaque_flutter_rust_bridgefor_generatedRustAutoOpaqueInnerRTCFileReceiver(
SseDeserializer deserializer);
@protected
RtcFileSender
sse_decode_Auto_Ref_RustOpaque_flutter_rust_bridgefor_generatedRustAutoOpaqueInnerRTCFileSender(
SseDeserializer deserializer);
@protected
RtcReceiveController
sse_decode_Auto_Ref_RustOpaque_flutter_rust_bridgefor_generatedRustAutoOpaqueInnerRTCReceiveController(
SseDeserializer deserializer);
@protected
RtcSendController
sse_decode_Auto_Ref_RustOpaque_flutter_rust_bridgefor_generatedRustAutoOpaqueInnerRTCSendController(
SseDeserializer deserializer);
@protected
Object sse_decode_DartOpaque(SseDeserializer deserializer);
@protected
LsSignalingConnection
sse_decode_RustOpaque_flutter_rust_bridgefor_generatedRustAutoOpaqueInnerLsSignalingConnection(
SseDeserializer deserializer);
@protected
RtcFileReceiver
sse_decode_RustOpaque_flutter_rust_bridgefor_generatedRustAutoOpaqueInnerRTCFileReceiver(
SseDeserializer deserializer);
@protected
RtcFileSender
sse_decode_RustOpaque_flutter_rust_bridgefor_generatedRustAutoOpaqueInnerRTCFileSender(
SseDeserializer deserializer);
@protected
RtcReceiveController
sse_decode_RustOpaque_flutter_rust_bridgefor_generatedRustAutoOpaqueInnerRTCReceiveController(
SseDeserializer deserializer);
@protected
RtcSendController
sse_decode_RustOpaque_flutter_rust_bridgefor_generatedRustAutoOpaqueInnerRTCSendController(
SseDeserializer deserializer);
@protected
Set<String> sse_decode_Set_String_None(SseDeserializer deserializer);
@protected
RustStreamSink<RtcFileReceiver>
sse_decode_StreamSink_Auto_Owned_RustOpaque_flutter_rust_bridgefor_generatedRustAutoOpaqueInnerRTCFileReceiver_Sse(
SseDeserializer deserializer);
@protected
RustStreamSink<Uint8List> sse_decode_StreamSink_list_prim_u_8_strict_Sse(
SseDeserializer deserializer);
@protected
RustStreamSink<RTCFileError> sse_decode_StreamSink_rtc_file_error_Sse(
SseDeserializer deserializer);
@protected
RustStreamSink<RTCStatus> sse_decode_StreamSink_rtc_status_Sse(
SseDeserializer deserializer);
@protected
RustStreamSink<WsServerMessage> sse_decode_StreamSink_ws_server_message_Sse(
SseDeserializer deserializer);
@protected
String sse_decode_String(SseDeserializer deserializer);
@protected
UuidValue sse_decode_Uuid(SseDeserializer deserializer);
@protected
bool sse_decode_bool(SseDeserializer deserializer);
@protected
ClientInfo sse_decode_box_autoadd_client_info(SseDeserializer deserializer);
@protected
ClientInfoWithoutId sse_decode_box_autoadd_client_info_without_id(
SseDeserializer deserializer);
@protected
DeviceType sse_decode_box_autoadd_device_type(SseDeserializer deserializer);
@protected
ExpectingPublicKey sse_decode_box_autoadd_expecting_public_key(
SseDeserializer deserializer);
@protected
FileMetadata sse_decode_box_autoadd_file_metadata(
SseDeserializer deserializer);
@protected
PinConfig sse_decode_box_autoadd_pin_config(SseDeserializer deserializer);
@protected
ProposingClientInfo sse_decode_box_autoadd_proposing_client_info(
SseDeserializer deserializer);
@protected
RTCSendFileResponse sse_decode_box_autoadd_rtc_send_file_response(
SseDeserializer deserializer);
@protected
WsServerSdpMessage sse_decode_box_autoadd_ws_server_sdp_message(
SseDeserializer deserializer);
@protected
ClientInfo sse_decode_client_info(SseDeserializer deserializer);
@protected
ClientInfoWithoutId sse_decode_client_info_without_id(
SseDeserializer deserializer);
@protected
DeviceType sse_decode_device_type(SseDeserializer deserializer);
@protected
ExpectingPublicKey sse_decode_expecting_public_key(
SseDeserializer deserializer);
@protected
FileDto sse_decode_file_dto(SseDeserializer deserializer);
@protected
FileMetadata sse_decode_file_metadata(SseDeserializer deserializer);
@protected
int sse_decode_i_32(SseDeserializer deserializer);
@protected
PlatformInt64 sse_decode_isize(SseDeserializer deserializer);
@protected
KeyPair sse_decode_key_pair(SseDeserializer deserializer);
@protected
List<String> sse_decode_list_String(SseDeserializer deserializer);
@protected
List<ClientInfo> sse_decode_list_client_info(SseDeserializer deserializer);
@protected
List<FileDto> sse_decode_list_file_dto(SseDeserializer deserializer);
@protected
List<int> sse_decode_list_prim_u_8_loose(SseDeserializer deserializer);
@protected
Uint8List sse_decode_list_prim_u_8_strict(SseDeserializer deserializer);
@protected
String? sse_decode_opt_String(SseDeserializer deserializer);
@protected
DeviceType? sse_decode_opt_box_autoadd_device_type(
SseDeserializer deserializer);
@protected
ExpectingPublicKey? sse_decode_opt_box_autoadd_expecting_public_key(
SseDeserializer deserializer);
@protected
FileMetadata? sse_decode_opt_box_autoadd_file_metadata(
SseDeserializer deserializer);
@protected
PinConfig? sse_decode_opt_box_autoadd_pin_config(
SseDeserializer deserializer);
@protected
PinConfig sse_decode_pin_config(SseDeserializer deserializer);
@protected
ProposingClientInfo sse_decode_proposing_client_info(
SseDeserializer deserializer);
@protected
RTCFileError sse_decode_rtc_file_error(SseDeserializer deserializer);
@protected
RTCSendFileResponse sse_decode_rtc_send_file_response(
SseDeserializer deserializer);
@protected
RTCStatus sse_decode_rtc_status(SseDeserializer deserializer);
@protected
int sse_decode_u_16(SseDeserializer deserializer);
@protected
BigInt sse_decode_u_64(SseDeserializer deserializer);
@protected
int sse_decode_u_8(SseDeserializer deserializer);
@protected
void sse_decode_unit(SseDeserializer deserializer);
@protected
BigInt sse_decode_usize(SseDeserializer deserializer);
@protected
WsServerMessage sse_decode_ws_server_message(SseDeserializer deserializer);
@protected
WsServerSdpMessage sse_decode_ws_server_sdp_message(
SseDeserializer deserializer);
@protected
void sse_encode_AnyhowException(
AnyhowException self, SseSerializer serializer);
@protected
void
sse_encode_Auto_Owned_RustOpaque_flutter_rust_bridgefor_generatedRustAutoOpaqueInnerLsSignalingConnection(
LsSignalingConnection self, SseSerializer serializer);
@protected
void
sse_encode_Auto_Owned_RustOpaque_flutter_rust_bridgefor_generatedRustAutoOpaqueInnerRTCFileReceiver(
RtcFileReceiver self, SseSerializer serializer);
@protected
void
sse_encode_Auto_Owned_RustOpaque_flutter_rust_bridgefor_generatedRustAutoOpaqueInnerRTCFileSender(
RtcFileSender self, SseSerializer serializer);
@protected
void
sse_encode_Auto_Owned_RustOpaque_flutter_rust_bridgefor_generatedRustAutoOpaqueInnerRTCReceiveController(
RtcReceiveController self, SseSerializer serializer);
@protected
void
sse_encode_Auto_Owned_RustOpaque_flutter_rust_bridgefor_generatedRustAutoOpaqueInnerRTCSendController(
RtcSendController self, SseSerializer serializer);
@protected
void
sse_encode_Auto_RefMut_RustOpaque_flutter_rust_bridgefor_generatedRustAutoOpaqueInnerRTCSendController(
RtcSendController self, SseSerializer serializer);
@protected
void
sse_encode_Auto_Ref_RustOpaque_flutter_rust_bridgefor_generatedRustAutoOpaqueInnerLsSignalingConnection(
LsSignalingConnection self, SseSerializer serializer);
@protected
void
sse_encode_Auto_Ref_RustOpaque_flutter_rust_bridgefor_generatedRustAutoOpaqueInnerRTCFileReceiver(
RtcFileReceiver self, SseSerializer serializer);
@protected
void
sse_encode_Auto_Ref_RustOpaque_flutter_rust_bridgefor_generatedRustAutoOpaqueInnerRTCFileSender(
RtcFileSender self, SseSerializer serializer);
@protected
void
sse_encode_Auto_Ref_RustOpaque_flutter_rust_bridgefor_generatedRustAutoOpaqueInnerRTCReceiveController(
RtcReceiveController self, SseSerializer serializer);
@protected
void
sse_encode_Auto_Ref_RustOpaque_flutter_rust_bridgefor_generatedRustAutoOpaqueInnerRTCSendController(
RtcSendController self, SseSerializer serializer);
@protected
void
sse_encode_DartFn_Inputs_Auto_Owned_RustOpaque_flutter_rust_bridgefor_generatedRustAutoOpaqueInnerLsSignalingConnection_Output_unit_AnyhowException(
FutureOr<void> Function(LsSignalingConnection) self,
SseSerializer serializer);
@protected
void sse_encode_DartOpaque(Object self, SseSerializer serializer);
@protected
void
sse_encode_RustOpaque_flutter_rust_bridgefor_generatedRustAutoOpaqueInnerLsSignalingConnection(
LsSignalingConnection self, SseSerializer serializer);
@protected
void
sse_encode_RustOpaque_flutter_rust_bridgefor_generatedRustAutoOpaqueInnerRTCFileReceiver(
RtcFileReceiver self, SseSerializer serializer);
@protected
void
sse_encode_RustOpaque_flutter_rust_bridgefor_generatedRustAutoOpaqueInnerRTCFileSender(
RtcFileSender self, SseSerializer serializer);
@protected
void
sse_encode_RustOpaque_flutter_rust_bridgefor_generatedRustAutoOpaqueInnerRTCReceiveController(
RtcReceiveController self, SseSerializer serializer);
@protected
void
sse_encode_RustOpaque_flutter_rust_bridgefor_generatedRustAutoOpaqueInnerRTCSendController(
RtcSendController self, SseSerializer serializer);
@protected
void sse_encode_Set_String_None(Set<String> self, SseSerializer serializer);
@protected
void
sse_encode_StreamSink_Auto_Owned_RustOpaque_flutter_rust_bridgefor_generatedRustAutoOpaqueInnerRTCFileReceiver_Sse(
RustStreamSink<RtcFileReceiver> self, SseSerializer serializer);
@protected
void sse_encode_StreamSink_list_prim_u_8_strict_Sse(
RustStreamSink<Uint8List> self, SseSerializer serializer);
@protected
void sse_encode_StreamSink_rtc_file_error_Sse(
RustStreamSink<RTCFileError> self, SseSerializer serializer);
@protected
void sse_encode_StreamSink_rtc_status_Sse(
RustStreamSink<RTCStatus> self, SseSerializer serializer);
@protected
void sse_encode_StreamSink_ws_server_message_Sse(
RustStreamSink<WsServerMessage> self, SseSerializer serializer);
@protected
void sse_encode_String(String self, SseSerializer serializer);
@protected
void sse_encode_Uuid(UuidValue self, SseSerializer serializer);
@protected
void sse_encode_bool(bool self, SseSerializer serializer);
@protected
void sse_encode_box_autoadd_client_info(
ClientInfo self, SseSerializer serializer);
@protected
void sse_encode_box_autoadd_client_info_without_id(
ClientInfoWithoutId self, SseSerializer serializer);
@protected
void sse_encode_box_autoadd_device_type(
DeviceType self, SseSerializer serializer);
@protected
void sse_encode_box_autoadd_expecting_public_key(
ExpectingPublicKey self, SseSerializer serializer);
@protected
void sse_encode_box_autoadd_file_metadata(
FileMetadata self, SseSerializer serializer);
@protected
void sse_encode_box_autoadd_pin_config(
PinConfig self, SseSerializer serializer);
@protected
void sse_encode_box_autoadd_proposing_client_info(
ProposingClientInfo self, SseSerializer serializer);
@protected
void sse_encode_box_autoadd_rtc_send_file_response(
RTCSendFileResponse self, SseSerializer serializer);
@protected
void sse_encode_box_autoadd_ws_server_sdp_message(
WsServerSdpMessage self, SseSerializer serializer);
@protected
void sse_encode_client_info(ClientInfo self, SseSerializer serializer);
@protected
void sse_encode_client_info_without_id(
ClientInfoWithoutId self, SseSerializer serializer);
@protected
void sse_encode_device_type(DeviceType self, SseSerializer serializer);
@protected
void sse_encode_expecting_public_key(
ExpectingPublicKey self, SseSerializer serializer);
@protected
void sse_encode_file_dto(FileDto self, SseSerializer serializer);
@protected
void sse_encode_file_metadata(FileMetadata self, SseSerializer serializer);
@protected
void sse_encode_i_32(int self, SseSerializer serializer);
@protected
void sse_encode_isize(PlatformInt64 self, SseSerializer serializer);
@protected
void sse_encode_key_pair(KeyPair self, SseSerializer serializer);
@protected
void sse_encode_list_String(List<String> self, SseSerializer serializer);
@protected
void sse_encode_list_client_info(
List<ClientInfo> self, SseSerializer serializer);
@protected
void sse_encode_list_file_dto(List<FileDto> self, SseSerializer serializer);
@protected
void sse_encode_list_prim_u_8_loose(List<int> self, SseSerializer serializer);
@protected
void sse_encode_list_prim_u_8_strict(
Uint8List self, SseSerializer serializer);
@protected
void sse_encode_opt_String(String? self, SseSerializer serializer);
@protected
void sse_encode_opt_box_autoadd_device_type(
DeviceType? self, SseSerializer serializer);
@protected
void sse_encode_opt_box_autoadd_expecting_public_key(
ExpectingPublicKey? self, SseSerializer serializer);
@protected
void sse_encode_opt_box_autoadd_file_metadata(
FileMetadata? self, SseSerializer serializer);
@protected
void sse_encode_opt_box_autoadd_pin_config(
PinConfig? self, SseSerializer serializer);
@protected
void sse_encode_pin_config(PinConfig self, SseSerializer serializer);
@protected
void sse_encode_proposing_client_info(
ProposingClientInfo self, SseSerializer serializer);
@protected
void sse_encode_rtc_file_error(RTCFileError self, SseSerializer serializer);
@protected
void sse_encode_rtc_send_file_response(
RTCSendFileResponse self, SseSerializer serializer);
@protected
void sse_encode_rtc_status(RTCStatus self, SseSerializer serializer);
@protected
void sse_encode_u_16(int self, SseSerializer serializer);
@protected
void sse_encode_u_64(BigInt self, SseSerializer serializer);
@protected
void sse_encode_u_8(int self, SseSerializer serializer);
@protected
void sse_encode_unit(void self, SseSerializer serializer);
@protected
void sse_encode_usize(BigInt self, SseSerializer serializer);
@protected
void sse_encode_ws_server_message(
WsServerMessage self, SseSerializer serializer);
@protected
void sse_encode_ws_server_sdp_message(
WsServerSdpMessage self, SseSerializer serializer);
}
// Section: wire_class
class RustLibWire implements BaseWire {
factory RustLibWire.fromExternalLibrary(ExternalLibrary lib) =>
RustLibWire(lib.ffiDynamicLibrary);
/// Holds the symbol lookup function.
final ffi.Pointer<T> Function<T extends ffi.NativeType>(String symbolName)
_lookup;
/// The symbols are looked up in [dynamicLibrary].
RustLibWire(ffi.DynamicLibrary dynamicLibrary)
: _lookup = dynamicLibrary.lookup;
void
rust_arc_increment_strong_count_RustOpaque_flutter_rust_bridgefor_generatedRustAutoOpaqueInnerLsSignalingConnection(
ffi.Pointer<ffi.Void> ptr,
) {
return _rust_arc_increment_strong_count_RustOpaque_flutter_rust_bridgefor_generatedRustAutoOpaqueInnerLsSignalingConnection(
ptr,
);
}
late final _rust_arc_increment_strong_count_RustOpaque_flutter_rust_bridgefor_generatedRustAutoOpaqueInnerLsSignalingConnectionPtr =
_lookup<ffi.NativeFunction<ffi.Void Function(ffi.Pointer<ffi.Void>)>>(
'frbgen_localsend_app_rust_arc_increment_strong_count_RustOpaque_flutter_rust_bridgefor_generatedRustAutoOpaqueInnerLsSignalingConnection');
late final _rust_arc_increment_strong_count_RustOpaque_flutter_rust_bridgefor_generatedRustAutoOpaqueInnerLsSignalingConnection =
_rust_arc_increment_strong_count_RustOpaque_flutter_rust_bridgefor_generatedRustAutoOpaqueInnerLsSignalingConnectionPtr
.asFunction<void Function(ffi.Pointer<ffi.Void>)>();
void
rust_arc_decrement_strong_count_RustOpaque_flutter_rust_bridgefor_generatedRustAutoOpaqueInnerLsSignalingConnection(
ffi.Pointer<ffi.Void> ptr,
) {
return _rust_arc_decrement_strong_count_RustOpaque_flutter_rust_bridgefor_generatedRustAutoOpaqueInnerLsSignalingConnection(
ptr,
);
}
late final _rust_arc_decrement_strong_count_RustOpaque_flutter_rust_bridgefor_generatedRustAutoOpaqueInnerLsSignalingConnectionPtr =
_lookup<ffi.NativeFunction<ffi.Void Function(ffi.Pointer<ffi.Void>)>>(
'frbgen_localsend_app_rust_arc_decrement_strong_count_RustOpaque_flutter_rust_bridgefor_generatedRustAutoOpaqueInnerLsSignalingConnection');
late final _rust_arc_decrement_strong_count_RustOpaque_flutter_rust_bridgefor_generatedRustAutoOpaqueInnerLsSignalingConnection =
_rust_arc_decrement_strong_count_RustOpaque_flutter_rust_bridgefor_generatedRustAutoOpaqueInnerLsSignalingConnectionPtr
.asFunction<void Function(ffi.Pointer<ffi.Void>)>();
void
rust_arc_increment_strong_count_RustOpaque_flutter_rust_bridgefor_generatedRustAutoOpaqueInnerRTCFileReceiver(
ffi.Pointer<ffi.Void> ptr,
) {
return _rust_arc_increment_strong_count_RustOpaque_flutter_rust_bridgefor_generatedRustAutoOpaqueInnerRTCFileReceiver(
ptr,
);
}
late final _rust_arc_increment_strong_count_RustOpaque_flutter_rust_bridgefor_generatedRustAutoOpaqueInnerRTCFileReceiverPtr =
_lookup<ffi.NativeFunction<ffi.Void Function(ffi.Pointer<ffi.Void>)>>(
'frbgen_localsend_app_rust_arc_increment_strong_count_RustOpaque_flutter_rust_bridgefor_generatedRustAutoOpaqueInnerRTCFileReceiver');
late final _rust_arc_increment_strong_count_RustOpaque_flutter_rust_bridgefor_generatedRustAutoOpaqueInnerRTCFileReceiver =
_rust_arc_increment_strong_count_RustOpaque_flutter_rust_bridgefor_generatedRustAutoOpaqueInnerRTCFileReceiverPtr
.asFunction<void Function(ffi.Pointer<ffi.Void>)>();
void
rust_arc_decrement_strong_count_RustOpaque_flutter_rust_bridgefor_generatedRustAutoOpaqueInnerRTCFileReceiver(
ffi.Pointer<ffi.Void> ptr,
) {
return _rust_arc_decrement_strong_count_RustOpaque_flutter_rust_bridgefor_generatedRustAutoOpaqueInnerRTCFileReceiver(
ptr,
);
}
late final _rust_arc_decrement_strong_count_RustOpaque_flutter_rust_bridgefor_generatedRustAutoOpaqueInnerRTCFileReceiverPtr =
_lookup<ffi.NativeFunction<ffi.Void Function(ffi.Pointer<ffi.Void>)>>(
'frbgen_localsend_app_rust_arc_decrement_strong_count_RustOpaque_flutter_rust_bridgefor_generatedRustAutoOpaqueInnerRTCFileReceiver');
late final _rust_arc_decrement_strong_count_RustOpaque_flutter_rust_bridgefor_generatedRustAutoOpaqueInnerRTCFileReceiver =
_rust_arc_decrement_strong_count_RustOpaque_flutter_rust_bridgefor_generatedRustAutoOpaqueInnerRTCFileReceiverPtr
.asFunction<void Function(ffi.Pointer<ffi.Void>)>();
void
rust_arc_increment_strong_count_RustOpaque_flutter_rust_bridgefor_generatedRustAutoOpaqueInnerRTCFileSender(
ffi.Pointer<ffi.Void> ptr,
) {
return _rust_arc_increment_strong_count_RustOpaque_flutter_rust_bridgefor_generatedRustAutoOpaqueInnerRTCFileSender(
ptr,
);
}
late final _rust_arc_increment_strong_count_RustOpaque_flutter_rust_bridgefor_generatedRustAutoOpaqueInnerRTCFileSenderPtr =
_lookup<ffi.NativeFunction<ffi.Void Function(ffi.Pointer<ffi.Void>)>>(
'frbgen_localsend_app_rust_arc_increment_strong_count_RustOpaque_flutter_rust_bridgefor_generatedRustAutoOpaqueInnerRTCFileSender');
late final _rust_arc_increment_strong_count_RustOpaque_flutter_rust_bridgefor_generatedRustAutoOpaqueInnerRTCFileSender =
_rust_arc_increment_strong_count_RustOpaque_flutter_rust_bridgefor_generatedRustAutoOpaqueInnerRTCFileSenderPtr
.asFunction<void Function(ffi.Pointer<ffi.Void>)>();
void
rust_arc_decrement_strong_count_RustOpaque_flutter_rust_bridgefor_generatedRustAutoOpaqueInnerRTCFileSender(
ffi.Pointer<ffi.Void> ptr,
) {
return _rust_arc_decrement_strong_count_RustOpaque_flutter_rust_bridgefor_generatedRustAutoOpaqueInnerRTCFileSender(
ptr,
);
}
late final _rust_arc_decrement_strong_count_RustOpaque_flutter_rust_bridgefor_generatedRustAutoOpaqueInnerRTCFileSenderPtr =
_lookup<ffi.NativeFunction<ffi.Void Function(ffi.Pointer<ffi.Void>)>>(
'frbgen_localsend_app_rust_arc_decrement_strong_count_RustOpaque_flutter_rust_bridgefor_generatedRustAutoOpaqueInnerRTCFileSender');
late final _rust_arc_decrement_strong_count_RustOpaque_flutter_rust_bridgefor_generatedRustAutoOpaqueInnerRTCFileSender =
_rust_arc_decrement_strong_count_RustOpaque_flutter_rust_bridgefor_generatedRustAutoOpaqueInnerRTCFileSenderPtr
.asFunction<void Function(ffi.Pointer<ffi.Void>)>();
void
rust_arc_increment_strong_count_RustOpaque_flutter_rust_bridgefor_generatedRustAutoOpaqueInnerRTCReceiveController(
ffi.Pointer<ffi.Void> ptr,
) {
return _rust_arc_increment_strong_count_RustOpaque_flutter_rust_bridgefor_generatedRustAutoOpaqueInnerRTCReceiveController(
ptr,
);
}
late final _rust_arc_increment_strong_count_RustOpaque_flutter_rust_bridgefor_generatedRustAutoOpaqueInnerRTCReceiveControllerPtr =
_lookup<ffi.NativeFunction<ffi.Void Function(ffi.Pointer<ffi.Void>)>>(
'frbgen_localsend_app_rust_arc_increment_strong_count_RustOpaque_flutter_rust_bridgefor_generatedRustAutoOpaqueInnerRTCReceiveController');
late final _rust_arc_increment_strong_count_RustOpaque_flutter_rust_bridgefor_generatedRustAutoOpaqueInnerRTCReceiveController =
_rust_arc_increment_strong_count_RustOpaque_flutter_rust_bridgefor_generatedRustAutoOpaqueInnerRTCReceiveControllerPtr
.asFunction<void Function(ffi.Pointer<ffi.Void>)>();
void
rust_arc_decrement_strong_count_RustOpaque_flutter_rust_bridgefor_generatedRustAutoOpaqueInnerRTCReceiveController(
ffi.Pointer<ffi.Void> ptr,
) {
return _rust_arc_decrement_strong_count_RustOpaque_flutter_rust_bridgefor_generatedRustAutoOpaqueInnerRTCReceiveController(
ptr,
);
}
late final _rust_arc_decrement_strong_count_RustOpaque_flutter_rust_bridgefor_generatedRustAutoOpaqueInnerRTCReceiveControllerPtr =
_lookup<ffi.NativeFunction<ffi.Void Function(ffi.Pointer<ffi.Void>)>>(
'frbgen_localsend_app_rust_arc_decrement_strong_count_RustOpaque_flutter_rust_bridgefor_generatedRustAutoOpaqueInnerRTCReceiveController');
late final _rust_arc_decrement_strong_count_RustOpaque_flutter_rust_bridgefor_generatedRustAutoOpaqueInnerRTCReceiveController =
_rust_arc_decrement_strong_count_RustOpaque_flutter_rust_bridgefor_generatedRustAutoOpaqueInnerRTCReceiveControllerPtr
.asFunction<void Function(ffi.Pointer<ffi.Void>)>();
void
rust_arc_increment_strong_count_RustOpaque_flutter_rust_bridgefor_generatedRustAutoOpaqueInnerRTCSendController(
ffi.Pointer<ffi.Void> ptr,
) {
return _rust_arc_increment_strong_count_RustOpaque_flutter_rust_bridgefor_generatedRustAutoOpaqueInnerRTCSendController(
ptr,
);
}
late final _rust_arc_increment_strong_count_RustOpaque_flutter_rust_bridgefor_generatedRustAutoOpaqueInnerRTCSendControllerPtr =
_lookup<ffi.NativeFunction<ffi.Void Function(ffi.Pointer<ffi.Void>)>>(
'frbgen_localsend_app_rust_arc_increment_strong_count_RustOpaque_flutter_rust_bridgefor_generatedRustAutoOpaqueInnerRTCSendController');
late final _rust_arc_increment_strong_count_RustOpaque_flutter_rust_bridgefor_generatedRustAutoOpaqueInnerRTCSendController =
_rust_arc_increment_strong_count_RustOpaque_flutter_rust_bridgefor_generatedRustAutoOpaqueInnerRTCSendControllerPtr
.asFunction<void Function(ffi.Pointer<ffi.Void>)>();
void
rust_arc_decrement_strong_count_RustOpaque_flutter_rust_bridgefor_generatedRustAutoOpaqueInnerRTCSendController(
ffi.Pointer<ffi.Void> ptr,
) {
return _rust_arc_decrement_strong_count_RustOpaque_flutter_rust_bridgefor_generatedRustAutoOpaqueInnerRTCSendController(
ptr,
);
}
late final _rust_arc_decrement_strong_count_RustOpaque_flutter_rust_bridgefor_generatedRustAutoOpaqueInnerRTCSendControllerPtr =
_lookup<ffi.NativeFunction<ffi.Void Function(ffi.Pointer<ffi.Void>)>>(
'frbgen_localsend_app_rust_arc_decrement_strong_count_RustOpaque_flutter_rust_bridgefor_generatedRustAutoOpaqueInnerRTCSendController');
late final _rust_arc_decrement_strong_count_RustOpaque_flutter_rust_bridgefor_generatedRustAutoOpaqueInnerRTCSendController =
_rust_arc_decrement_strong_count_RustOpaque_flutter_rust_bridgefor_generatedRustAutoOpaqueInnerRTCSendControllerPtr
.asFunction<void Function(ffi.Pointer<ffi.Void>)>();
}
+927
View File
@@ -0,0 +1,927 @@
// This file is automatically generated, so please do not edit it.
// @generated by `flutter_rust_bridge`@ 2.11.1.
// ignore_for_file: unused_import, unused_element, unnecessary_import, duplicate_ignore, invalid_use_of_internal_member, annotate_overrides, non_constant_identifier_names, curly_braces_in_flow_control_structures, prefer_const_literals_to_create_immutables, unused_field
// Static analysis wrongly picks the IO variant, thus ignore this
// ignore_for_file: argument_type_not_assignable
import 'dart:async';
import 'dart:convert';
import 'package:flutter_rust_bridge/flutter_rust_bridge_for_generated_web.dart';
import 'package:localsend_app/rust/api/crypto.dart';
import 'package:localsend_app/rust/api/logging.dart';
import 'package:localsend_app/rust/api/model.dart';
import 'package:localsend_app/rust/api/webrtc.dart';
import 'package:localsend_app/rust/frb_generated.dart';
import 'package:uuid/uuid.dart';
abstract class RustLibApiImplPlatform extends BaseApiImpl<RustLibWire> {
RustLibApiImplPlatform({
required super.handler,
required super.wire,
required super.generalizedFrbRustBinding,
required super.portManager,
});
CrossPlatformFinalizerArg
get rust_arc_decrement_strong_count_LsSignalingConnectionPtr => wire
.rust_arc_decrement_strong_count_RustOpaque_flutter_rust_bridgefor_generatedRustAutoOpaqueInnerLsSignalingConnection;
CrossPlatformFinalizerArg
get rust_arc_decrement_strong_count_RtcFileReceiverPtr => wire
.rust_arc_decrement_strong_count_RustOpaque_flutter_rust_bridgefor_generatedRustAutoOpaqueInnerRTCFileReceiver;
CrossPlatformFinalizerArg
get rust_arc_decrement_strong_count_RtcFileSenderPtr => wire
.rust_arc_decrement_strong_count_RustOpaque_flutter_rust_bridgefor_generatedRustAutoOpaqueInnerRTCFileSender;
CrossPlatformFinalizerArg
get rust_arc_decrement_strong_count_RtcReceiveControllerPtr => wire
.rust_arc_decrement_strong_count_RustOpaque_flutter_rust_bridgefor_generatedRustAutoOpaqueInnerRTCReceiveController;
CrossPlatformFinalizerArg
get rust_arc_decrement_strong_count_RtcSendControllerPtr => wire
.rust_arc_decrement_strong_count_RustOpaque_flutter_rust_bridgefor_generatedRustAutoOpaqueInnerRTCSendController;
@protected
AnyhowException dco_decode_AnyhowException(dynamic raw);
@protected
LsSignalingConnection
dco_decode_Auto_Owned_RustOpaque_flutter_rust_bridgefor_generatedRustAutoOpaqueInnerLsSignalingConnection(
dynamic raw);
@protected
RtcFileReceiver
dco_decode_Auto_Owned_RustOpaque_flutter_rust_bridgefor_generatedRustAutoOpaqueInnerRTCFileReceiver(
dynamic raw);
@protected
RtcFileSender
dco_decode_Auto_Owned_RustOpaque_flutter_rust_bridgefor_generatedRustAutoOpaqueInnerRTCFileSender(
dynamic raw);
@protected
RtcReceiveController
dco_decode_Auto_Owned_RustOpaque_flutter_rust_bridgefor_generatedRustAutoOpaqueInnerRTCReceiveController(
dynamic raw);
@protected
RtcSendController
dco_decode_Auto_Owned_RustOpaque_flutter_rust_bridgefor_generatedRustAutoOpaqueInnerRTCSendController(
dynamic raw);
@protected
RtcSendController
dco_decode_Auto_RefMut_RustOpaque_flutter_rust_bridgefor_generatedRustAutoOpaqueInnerRTCSendController(
dynamic raw);
@protected
LsSignalingConnection
dco_decode_Auto_Ref_RustOpaque_flutter_rust_bridgefor_generatedRustAutoOpaqueInnerLsSignalingConnection(
dynamic raw);
@protected
RtcFileReceiver
dco_decode_Auto_Ref_RustOpaque_flutter_rust_bridgefor_generatedRustAutoOpaqueInnerRTCFileReceiver(
dynamic raw);
@protected
RtcFileSender
dco_decode_Auto_Ref_RustOpaque_flutter_rust_bridgefor_generatedRustAutoOpaqueInnerRTCFileSender(
dynamic raw);
@protected
RtcReceiveController
dco_decode_Auto_Ref_RustOpaque_flutter_rust_bridgefor_generatedRustAutoOpaqueInnerRTCReceiveController(
dynamic raw);
@protected
RtcSendController
dco_decode_Auto_Ref_RustOpaque_flutter_rust_bridgefor_generatedRustAutoOpaqueInnerRTCSendController(
dynamic raw);
@protected
FutureOr<void> Function(LsSignalingConnection)
dco_decode_DartFn_Inputs_Auto_Owned_RustOpaque_flutter_rust_bridgefor_generatedRustAutoOpaqueInnerLsSignalingConnection_Output_unit_AnyhowException(
dynamic raw);
@protected
Object dco_decode_DartOpaque(dynamic raw);
@protected
LsSignalingConnection
dco_decode_RustOpaque_flutter_rust_bridgefor_generatedRustAutoOpaqueInnerLsSignalingConnection(
dynamic raw);
@protected
RtcFileReceiver
dco_decode_RustOpaque_flutter_rust_bridgefor_generatedRustAutoOpaqueInnerRTCFileReceiver(
dynamic raw);
@protected
RtcFileSender
dco_decode_RustOpaque_flutter_rust_bridgefor_generatedRustAutoOpaqueInnerRTCFileSender(
dynamic raw);
@protected
RtcReceiveController
dco_decode_RustOpaque_flutter_rust_bridgefor_generatedRustAutoOpaqueInnerRTCReceiveController(
dynamic raw);
@protected
RtcSendController
dco_decode_RustOpaque_flutter_rust_bridgefor_generatedRustAutoOpaqueInnerRTCSendController(
dynamic raw);
@protected
Set<String> dco_decode_Set_String_None(dynamic raw);
@protected
RustStreamSink<RtcFileReceiver>
dco_decode_StreamSink_Auto_Owned_RustOpaque_flutter_rust_bridgefor_generatedRustAutoOpaqueInnerRTCFileReceiver_Sse(
dynamic raw);
@protected
RustStreamSink<Uint8List> dco_decode_StreamSink_list_prim_u_8_strict_Sse(
dynamic raw);
@protected
RustStreamSink<RTCFileError> dco_decode_StreamSink_rtc_file_error_Sse(
dynamic raw);
@protected
RustStreamSink<RTCStatus> dco_decode_StreamSink_rtc_status_Sse(dynamic raw);
@protected
RustStreamSink<WsServerMessage> dco_decode_StreamSink_ws_server_message_Sse(
dynamic raw);
@protected
String dco_decode_String(dynamic raw);
@protected
UuidValue dco_decode_Uuid(dynamic raw);
@protected
bool dco_decode_bool(dynamic raw);
@protected
ClientInfo dco_decode_box_autoadd_client_info(dynamic raw);
@protected
ClientInfoWithoutId dco_decode_box_autoadd_client_info_without_id(
dynamic raw);
@protected
DeviceType dco_decode_box_autoadd_device_type(dynamic raw);
@protected
ExpectingPublicKey dco_decode_box_autoadd_expecting_public_key(dynamic raw);
@protected
FileMetadata dco_decode_box_autoadd_file_metadata(dynamic raw);
@protected
PinConfig dco_decode_box_autoadd_pin_config(dynamic raw);
@protected
ProposingClientInfo dco_decode_box_autoadd_proposing_client_info(dynamic raw);
@protected
RTCSendFileResponse dco_decode_box_autoadd_rtc_send_file_response(
dynamic raw);
@protected
WsServerSdpMessage dco_decode_box_autoadd_ws_server_sdp_message(dynamic raw);
@protected
ClientInfo dco_decode_client_info(dynamic raw);
@protected
ClientInfoWithoutId dco_decode_client_info_without_id(dynamic raw);
@protected
DeviceType dco_decode_device_type(dynamic raw);
@protected
ExpectingPublicKey dco_decode_expecting_public_key(dynamic raw);
@protected
FileDto dco_decode_file_dto(dynamic raw);
@protected
FileMetadata dco_decode_file_metadata(dynamic raw);
@protected
int dco_decode_i_32(dynamic raw);
@protected
PlatformInt64 dco_decode_isize(dynamic raw);
@protected
KeyPair dco_decode_key_pair(dynamic raw);
@protected
List<String> dco_decode_list_String(dynamic raw);
@protected
List<ClientInfo> dco_decode_list_client_info(dynamic raw);
@protected
List<FileDto> dco_decode_list_file_dto(dynamic raw);
@protected
List<int> dco_decode_list_prim_u_8_loose(dynamic raw);
@protected
Uint8List dco_decode_list_prim_u_8_strict(dynamic raw);
@protected
String? dco_decode_opt_String(dynamic raw);
@protected
DeviceType? dco_decode_opt_box_autoadd_device_type(dynamic raw);
@protected
ExpectingPublicKey? dco_decode_opt_box_autoadd_expecting_public_key(
dynamic raw);
@protected
FileMetadata? dco_decode_opt_box_autoadd_file_metadata(dynamic raw);
@protected
PinConfig? dco_decode_opt_box_autoadd_pin_config(dynamic raw);
@protected
PinConfig dco_decode_pin_config(dynamic raw);
@protected
ProposingClientInfo dco_decode_proposing_client_info(dynamic raw);
@protected
RTCFileError dco_decode_rtc_file_error(dynamic raw);
@protected
RTCSendFileResponse dco_decode_rtc_send_file_response(dynamic raw);
@protected
RTCStatus dco_decode_rtc_status(dynamic raw);
@protected
int dco_decode_u_16(dynamic raw);
@protected
BigInt dco_decode_u_64(dynamic raw);
@protected
int dco_decode_u_8(dynamic raw);
@protected
void dco_decode_unit(dynamic raw);
@protected
BigInt dco_decode_usize(dynamic raw);
@protected
WsServerMessage dco_decode_ws_server_message(dynamic raw);
@protected
WsServerSdpMessage dco_decode_ws_server_sdp_message(dynamic raw);
@protected
AnyhowException sse_decode_AnyhowException(SseDeserializer deserializer);
@protected
LsSignalingConnection
sse_decode_Auto_Owned_RustOpaque_flutter_rust_bridgefor_generatedRustAutoOpaqueInnerLsSignalingConnection(
SseDeserializer deserializer);
@protected
RtcFileReceiver
sse_decode_Auto_Owned_RustOpaque_flutter_rust_bridgefor_generatedRustAutoOpaqueInnerRTCFileReceiver(
SseDeserializer deserializer);
@protected
RtcFileSender
sse_decode_Auto_Owned_RustOpaque_flutter_rust_bridgefor_generatedRustAutoOpaqueInnerRTCFileSender(
SseDeserializer deserializer);
@protected
RtcReceiveController
sse_decode_Auto_Owned_RustOpaque_flutter_rust_bridgefor_generatedRustAutoOpaqueInnerRTCReceiveController(
SseDeserializer deserializer);
@protected
RtcSendController
sse_decode_Auto_Owned_RustOpaque_flutter_rust_bridgefor_generatedRustAutoOpaqueInnerRTCSendController(
SseDeserializer deserializer);
@protected
RtcSendController
sse_decode_Auto_RefMut_RustOpaque_flutter_rust_bridgefor_generatedRustAutoOpaqueInnerRTCSendController(
SseDeserializer deserializer);
@protected
LsSignalingConnection
sse_decode_Auto_Ref_RustOpaque_flutter_rust_bridgefor_generatedRustAutoOpaqueInnerLsSignalingConnection(
SseDeserializer deserializer);
@protected
RtcFileReceiver
sse_decode_Auto_Ref_RustOpaque_flutter_rust_bridgefor_generatedRustAutoOpaqueInnerRTCFileReceiver(
SseDeserializer deserializer);
@protected
RtcFileSender
sse_decode_Auto_Ref_RustOpaque_flutter_rust_bridgefor_generatedRustAutoOpaqueInnerRTCFileSender(
SseDeserializer deserializer);
@protected
RtcReceiveController
sse_decode_Auto_Ref_RustOpaque_flutter_rust_bridgefor_generatedRustAutoOpaqueInnerRTCReceiveController(
SseDeserializer deserializer);
@protected
RtcSendController
sse_decode_Auto_Ref_RustOpaque_flutter_rust_bridgefor_generatedRustAutoOpaqueInnerRTCSendController(
SseDeserializer deserializer);
@protected
Object sse_decode_DartOpaque(SseDeserializer deserializer);
@protected
LsSignalingConnection
sse_decode_RustOpaque_flutter_rust_bridgefor_generatedRustAutoOpaqueInnerLsSignalingConnection(
SseDeserializer deserializer);
@protected
RtcFileReceiver
sse_decode_RustOpaque_flutter_rust_bridgefor_generatedRustAutoOpaqueInnerRTCFileReceiver(
SseDeserializer deserializer);
@protected
RtcFileSender
sse_decode_RustOpaque_flutter_rust_bridgefor_generatedRustAutoOpaqueInnerRTCFileSender(
SseDeserializer deserializer);
@protected
RtcReceiveController
sse_decode_RustOpaque_flutter_rust_bridgefor_generatedRustAutoOpaqueInnerRTCReceiveController(
SseDeserializer deserializer);
@protected
RtcSendController
sse_decode_RustOpaque_flutter_rust_bridgefor_generatedRustAutoOpaqueInnerRTCSendController(
SseDeserializer deserializer);
@protected
Set<String> sse_decode_Set_String_None(SseDeserializer deserializer);
@protected
RustStreamSink<RtcFileReceiver>
sse_decode_StreamSink_Auto_Owned_RustOpaque_flutter_rust_bridgefor_generatedRustAutoOpaqueInnerRTCFileReceiver_Sse(
SseDeserializer deserializer);
@protected
RustStreamSink<Uint8List> sse_decode_StreamSink_list_prim_u_8_strict_Sse(
SseDeserializer deserializer);
@protected
RustStreamSink<RTCFileError> sse_decode_StreamSink_rtc_file_error_Sse(
SseDeserializer deserializer);
@protected
RustStreamSink<RTCStatus> sse_decode_StreamSink_rtc_status_Sse(
SseDeserializer deserializer);
@protected
RustStreamSink<WsServerMessage> sse_decode_StreamSink_ws_server_message_Sse(
SseDeserializer deserializer);
@protected
String sse_decode_String(SseDeserializer deserializer);
@protected
UuidValue sse_decode_Uuid(SseDeserializer deserializer);
@protected
bool sse_decode_bool(SseDeserializer deserializer);
@protected
ClientInfo sse_decode_box_autoadd_client_info(SseDeserializer deserializer);
@protected
ClientInfoWithoutId sse_decode_box_autoadd_client_info_without_id(
SseDeserializer deserializer);
@protected
DeviceType sse_decode_box_autoadd_device_type(SseDeserializer deserializer);
@protected
ExpectingPublicKey sse_decode_box_autoadd_expecting_public_key(
SseDeserializer deserializer);
@protected
FileMetadata sse_decode_box_autoadd_file_metadata(
SseDeserializer deserializer);
@protected
PinConfig sse_decode_box_autoadd_pin_config(SseDeserializer deserializer);
@protected
ProposingClientInfo sse_decode_box_autoadd_proposing_client_info(
SseDeserializer deserializer);
@protected
RTCSendFileResponse sse_decode_box_autoadd_rtc_send_file_response(
SseDeserializer deserializer);
@protected
WsServerSdpMessage sse_decode_box_autoadd_ws_server_sdp_message(
SseDeserializer deserializer);
@protected
ClientInfo sse_decode_client_info(SseDeserializer deserializer);
@protected
ClientInfoWithoutId sse_decode_client_info_without_id(
SseDeserializer deserializer);
@protected
DeviceType sse_decode_device_type(SseDeserializer deserializer);
@protected
ExpectingPublicKey sse_decode_expecting_public_key(
SseDeserializer deserializer);
@protected
FileDto sse_decode_file_dto(SseDeserializer deserializer);
@protected
FileMetadata sse_decode_file_metadata(SseDeserializer deserializer);
@protected
int sse_decode_i_32(SseDeserializer deserializer);
@protected
PlatformInt64 sse_decode_isize(SseDeserializer deserializer);
@protected
KeyPair sse_decode_key_pair(SseDeserializer deserializer);
@protected
List<String> sse_decode_list_String(SseDeserializer deserializer);
@protected
List<ClientInfo> sse_decode_list_client_info(SseDeserializer deserializer);
@protected
List<FileDto> sse_decode_list_file_dto(SseDeserializer deserializer);
@protected
List<int> sse_decode_list_prim_u_8_loose(SseDeserializer deserializer);
@protected
Uint8List sse_decode_list_prim_u_8_strict(SseDeserializer deserializer);
@protected
String? sse_decode_opt_String(SseDeserializer deserializer);
@protected
DeviceType? sse_decode_opt_box_autoadd_device_type(
SseDeserializer deserializer);
@protected
ExpectingPublicKey? sse_decode_opt_box_autoadd_expecting_public_key(
SseDeserializer deserializer);
@protected
FileMetadata? sse_decode_opt_box_autoadd_file_metadata(
SseDeserializer deserializer);
@protected
PinConfig? sse_decode_opt_box_autoadd_pin_config(
SseDeserializer deserializer);
@protected
PinConfig sse_decode_pin_config(SseDeserializer deserializer);
@protected
ProposingClientInfo sse_decode_proposing_client_info(
SseDeserializer deserializer);
@protected
RTCFileError sse_decode_rtc_file_error(SseDeserializer deserializer);
@protected
RTCSendFileResponse sse_decode_rtc_send_file_response(
SseDeserializer deserializer);
@protected
RTCStatus sse_decode_rtc_status(SseDeserializer deserializer);
@protected
int sse_decode_u_16(SseDeserializer deserializer);
@protected
BigInt sse_decode_u_64(SseDeserializer deserializer);
@protected
int sse_decode_u_8(SseDeserializer deserializer);
@protected
void sse_decode_unit(SseDeserializer deserializer);
@protected
BigInt sse_decode_usize(SseDeserializer deserializer);
@protected
WsServerMessage sse_decode_ws_server_message(SseDeserializer deserializer);
@protected
WsServerSdpMessage sse_decode_ws_server_sdp_message(
SseDeserializer deserializer);
@protected
void sse_encode_AnyhowException(
AnyhowException self, SseSerializer serializer);
@protected
void
sse_encode_Auto_Owned_RustOpaque_flutter_rust_bridgefor_generatedRustAutoOpaqueInnerLsSignalingConnection(
LsSignalingConnection self, SseSerializer serializer);
@protected
void
sse_encode_Auto_Owned_RustOpaque_flutter_rust_bridgefor_generatedRustAutoOpaqueInnerRTCFileReceiver(
RtcFileReceiver self, SseSerializer serializer);
@protected
void
sse_encode_Auto_Owned_RustOpaque_flutter_rust_bridgefor_generatedRustAutoOpaqueInnerRTCFileSender(
RtcFileSender self, SseSerializer serializer);
@protected
void
sse_encode_Auto_Owned_RustOpaque_flutter_rust_bridgefor_generatedRustAutoOpaqueInnerRTCReceiveController(
RtcReceiveController self, SseSerializer serializer);
@protected
void
sse_encode_Auto_Owned_RustOpaque_flutter_rust_bridgefor_generatedRustAutoOpaqueInnerRTCSendController(
RtcSendController self, SseSerializer serializer);
@protected
void
sse_encode_Auto_RefMut_RustOpaque_flutter_rust_bridgefor_generatedRustAutoOpaqueInnerRTCSendController(
RtcSendController self, SseSerializer serializer);
@protected
void
sse_encode_Auto_Ref_RustOpaque_flutter_rust_bridgefor_generatedRustAutoOpaqueInnerLsSignalingConnection(
LsSignalingConnection self, SseSerializer serializer);
@protected
void
sse_encode_Auto_Ref_RustOpaque_flutter_rust_bridgefor_generatedRustAutoOpaqueInnerRTCFileReceiver(
RtcFileReceiver self, SseSerializer serializer);
@protected
void
sse_encode_Auto_Ref_RustOpaque_flutter_rust_bridgefor_generatedRustAutoOpaqueInnerRTCFileSender(
RtcFileSender self, SseSerializer serializer);
@protected
void
sse_encode_Auto_Ref_RustOpaque_flutter_rust_bridgefor_generatedRustAutoOpaqueInnerRTCReceiveController(
RtcReceiveController self, SseSerializer serializer);
@protected
void
sse_encode_Auto_Ref_RustOpaque_flutter_rust_bridgefor_generatedRustAutoOpaqueInnerRTCSendController(
RtcSendController self, SseSerializer serializer);
@protected
void
sse_encode_DartFn_Inputs_Auto_Owned_RustOpaque_flutter_rust_bridgefor_generatedRustAutoOpaqueInnerLsSignalingConnection_Output_unit_AnyhowException(
FutureOr<void> Function(LsSignalingConnection) self,
SseSerializer serializer);
@protected
void sse_encode_DartOpaque(Object self, SseSerializer serializer);
@protected
void
sse_encode_RustOpaque_flutter_rust_bridgefor_generatedRustAutoOpaqueInnerLsSignalingConnection(
LsSignalingConnection self, SseSerializer serializer);
@protected
void
sse_encode_RustOpaque_flutter_rust_bridgefor_generatedRustAutoOpaqueInnerRTCFileReceiver(
RtcFileReceiver self, SseSerializer serializer);
@protected
void
sse_encode_RustOpaque_flutter_rust_bridgefor_generatedRustAutoOpaqueInnerRTCFileSender(
RtcFileSender self, SseSerializer serializer);
@protected
void
sse_encode_RustOpaque_flutter_rust_bridgefor_generatedRustAutoOpaqueInnerRTCReceiveController(
RtcReceiveController self, SseSerializer serializer);
@protected
void
sse_encode_RustOpaque_flutter_rust_bridgefor_generatedRustAutoOpaqueInnerRTCSendController(
RtcSendController self, SseSerializer serializer);
@protected
void sse_encode_Set_String_None(Set<String> self, SseSerializer serializer);
@protected
void
sse_encode_StreamSink_Auto_Owned_RustOpaque_flutter_rust_bridgefor_generatedRustAutoOpaqueInnerRTCFileReceiver_Sse(
RustStreamSink<RtcFileReceiver> self, SseSerializer serializer);
@protected
void sse_encode_StreamSink_list_prim_u_8_strict_Sse(
RustStreamSink<Uint8List> self, SseSerializer serializer);
@protected
void sse_encode_StreamSink_rtc_file_error_Sse(
RustStreamSink<RTCFileError> self, SseSerializer serializer);
@protected
void sse_encode_StreamSink_rtc_status_Sse(
RustStreamSink<RTCStatus> self, SseSerializer serializer);
@protected
void sse_encode_StreamSink_ws_server_message_Sse(
RustStreamSink<WsServerMessage> self, SseSerializer serializer);
@protected
void sse_encode_String(String self, SseSerializer serializer);
@protected
void sse_encode_Uuid(UuidValue self, SseSerializer serializer);
@protected
void sse_encode_bool(bool self, SseSerializer serializer);
@protected
void sse_encode_box_autoadd_client_info(
ClientInfo self, SseSerializer serializer);
@protected
void sse_encode_box_autoadd_client_info_without_id(
ClientInfoWithoutId self, SseSerializer serializer);
@protected
void sse_encode_box_autoadd_device_type(
DeviceType self, SseSerializer serializer);
@protected
void sse_encode_box_autoadd_expecting_public_key(
ExpectingPublicKey self, SseSerializer serializer);
@protected
void sse_encode_box_autoadd_file_metadata(
FileMetadata self, SseSerializer serializer);
@protected
void sse_encode_box_autoadd_pin_config(
PinConfig self, SseSerializer serializer);
@protected
void sse_encode_box_autoadd_proposing_client_info(
ProposingClientInfo self, SseSerializer serializer);
@protected
void sse_encode_box_autoadd_rtc_send_file_response(
RTCSendFileResponse self, SseSerializer serializer);
@protected
void sse_encode_box_autoadd_ws_server_sdp_message(
WsServerSdpMessage self, SseSerializer serializer);
@protected
void sse_encode_client_info(ClientInfo self, SseSerializer serializer);
@protected
void sse_encode_client_info_without_id(
ClientInfoWithoutId self, SseSerializer serializer);
@protected
void sse_encode_device_type(DeviceType self, SseSerializer serializer);
@protected
void sse_encode_expecting_public_key(
ExpectingPublicKey self, SseSerializer serializer);
@protected
void sse_encode_file_dto(FileDto self, SseSerializer serializer);
@protected
void sse_encode_file_metadata(FileMetadata self, SseSerializer serializer);
@protected
void sse_encode_i_32(int self, SseSerializer serializer);
@protected
void sse_encode_isize(PlatformInt64 self, SseSerializer serializer);
@protected
void sse_encode_key_pair(KeyPair self, SseSerializer serializer);
@protected
void sse_encode_list_String(List<String> self, SseSerializer serializer);
@protected
void sse_encode_list_client_info(
List<ClientInfo> self, SseSerializer serializer);
@protected
void sse_encode_list_file_dto(List<FileDto> self, SseSerializer serializer);
@protected
void sse_encode_list_prim_u_8_loose(List<int> self, SseSerializer serializer);
@protected
void sse_encode_list_prim_u_8_strict(
Uint8List self, SseSerializer serializer);
@protected
void sse_encode_opt_String(String? self, SseSerializer serializer);
@protected
void sse_encode_opt_box_autoadd_device_type(
DeviceType? self, SseSerializer serializer);
@protected
void sse_encode_opt_box_autoadd_expecting_public_key(
ExpectingPublicKey? self, SseSerializer serializer);
@protected
void sse_encode_opt_box_autoadd_file_metadata(
FileMetadata? self, SseSerializer serializer);
@protected
void sse_encode_opt_box_autoadd_pin_config(
PinConfig? self, SseSerializer serializer);
@protected
void sse_encode_pin_config(PinConfig self, SseSerializer serializer);
@protected
void sse_encode_proposing_client_info(
ProposingClientInfo self, SseSerializer serializer);
@protected
void sse_encode_rtc_file_error(RTCFileError self, SseSerializer serializer);
@protected
void sse_encode_rtc_send_file_response(
RTCSendFileResponse self, SseSerializer serializer);
@protected
void sse_encode_rtc_status(RTCStatus self, SseSerializer serializer);
@protected
void sse_encode_u_16(int self, SseSerializer serializer);
@protected
void sse_encode_u_64(BigInt self, SseSerializer serializer);
@protected
void sse_encode_u_8(int self, SseSerializer serializer);
@protected
void sse_encode_unit(void self, SseSerializer serializer);
@protected
void sse_encode_usize(BigInt self, SseSerializer serializer);
@protected
void sse_encode_ws_server_message(
WsServerMessage self, SseSerializer serializer);
@protected
void sse_encode_ws_server_sdp_message(
WsServerSdpMessage self, SseSerializer serializer);
}
// Section: wire_class
class RustLibWire implements BaseWire {
RustLibWire.fromExternalLibrary(ExternalLibrary lib);
void rust_arc_increment_strong_count_RustOpaque_flutter_rust_bridgefor_generatedRustAutoOpaqueInnerLsSignalingConnection(
int ptr) =>
wasmModule
.rust_arc_increment_strong_count_RustOpaque_flutter_rust_bridgefor_generatedRustAutoOpaqueInnerLsSignalingConnection(
ptr);
void rust_arc_decrement_strong_count_RustOpaque_flutter_rust_bridgefor_generatedRustAutoOpaqueInnerLsSignalingConnection(
int ptr) =>
wasmModule
.rust_arc_decrement_strong_count_RustOpaque_flutter_rust_bridgefor_generatedRustAutoOpaqueInnerLsSignalingConnection(
ptr);
void rust_arc_increment_strong_count_RustOpaque_flutter_rust_bridgefor_generatedRustAutoOpaqueInnerRTCFileReceiver(
int ptr) =>
wasmModule
.rust_arc_increment_strong_count_RustOpaque_flutter_rust_bridgefor_generatedRustAutoOpaqueInnerRTCFileReceiver(
ptr);
void rust_arc_decrement_strong_count_RustOpaque_flutter_rust_bridgefor_generatedRustAutoOpaqueInnerRTCFileReceiver(
int ptr) =>
wasmModule
.rust_arc_decrement_strong_count_RustOpaque_flutter_rust_bridgefor_generatedRustAutoOpaqueInnerRTCFileReceiver(
ptr);
void rust_arc_increment_strong_count_RustOpaque_flutter_rust_bridgefor_generatedRustAutoOpaqueInnerRTCFileSender(
int ptr) =>
wasmModule
.rust_arc_increment_strong_count_RustOpaque_flutter_rust_bridgefor_generatedRustAutoOpaqueInnerRTCFileSender(
ptr);
void rust_arc_decrement_strong_count_RustOpaque_flutter_rust_bridgefor_generatedRustAutoOpaqueInnerRTCFileSender(
int ptr) =>
wasmModule
.rust_arc_decrement_strong_count_RustOpaque_flutter_rust_bridgefor_generatedRustAutoOpaqueInnerRTCFileSender(
ptr);
void rust_arc_increment_strong_count_RustOpaque_flutter_rust_bridgefor_generatedRustAutoOpaqueInnerRTCReceiveController(
int ptr) =>
wasmModule
.rust_arc_increment_strong_count_RustOpaque_flutter_rust_bridgefor_generatedRustAutoOpaqueInnerRTCReceiveController(
ptr);
void rust_arc_decrement_strong_count_RustOpaque_flutter_rust_bridgefor_generatedRustAutoOpaqueInnerRTCReceiveController(
int ptr) =>
wasmModule
.rust_arc_decrement_strong_count_RustOpaque_flutter_rust_bridgefor_generatedRustAutoOpaqueInnerRTCReceiveController(
ptr);
void rust_arc_increment_strong_count_RustOpaque_flutter_rust_bridgefor_generatedRustAutoOpaqueInnerRTCSendController(
int ptr) =>
wasmModule
.rust_arc_increment_strong_count_RustOpaque_flutter_rust_bridgefor_generatedRustAutoOpaqueInnerRTCSendController(
ptr);
void rust_arc_decrement_strong_count_RustOpaque_flutter_rust_bridgefor_generatedRustAutoOpaqueInnerRTCSendController(
int ptr) =>
wasmModule
.rust_arc_decrement_strong_count_RustOpaque_flutter_rust_bridgefor_generatedRustAutoOpaqueInnerRTCSendController(
ptr);
}
@JS('wasm_bindgen')
external RustLibWasmModule get wasmModule;
@JS()
@anonymous
extension type RustLibWasmModule._(JSObject _) implements JSObject {
external void
rust_arc_increment_strong_count_RustOpaque_flutter_rust_bridgefor_generatedRustAutoOpaqueInnerLsSignalingConnection(
int ptr);
external void
rust_arc_decrement_strong_count_RustOpaque_flutter_rust_bridgefor_generatedRustAutoOpaqueInnerLsSignalingConnection(
int ptr);
external void
rust_arc_increment_strong_count_RustOpaque_flutter_rust_bridgefor_generatedRustAutoOpaqueInnerRTCFileReceiver(
int ptr);
external void
rust_arc_decrement_strong_count_RustOpaque_flutter_rust_bridgefor_generatedRustAutoOpaqueInnerRTCFileReceiver(
int ptr);
external void
rust_arc_increment_strong_count_RustOpaque_flutter_rust_bridgefor_generatedRustAutoOpaqueInnerRTCFileSender(
int ptr);
external void
rust_arc_decrement_strong_count_RustOpaque_flutter_rust_bridgefor_generatedRustAutoOpaqueInnerRTCFileSender(
int ptr);
external void
rust_arc_increment_strong_count_RustOpaque_flutter_rust_bridgefor_generatedRustAutoOpaqueInnerRTCReceiveController(
int ptr);
external void
rust_arc_decrement_strong_count_RustOpaque_flutter_rust_bridgefor_generatedRustAutoOpaqueInnerRTCReceiveController(
int ptr);
external void
rust_arc_increment_strong_count_RustOpaque_flutter_rust_bridgefor_generatedRustAutoOpaqueInnerRTCSendController(
int ptr);
external void
rust_arc_decrement_strong_count_RustOpaque_flutter_rust_bridgefor_generatedRustAutoOpaqueInnerRTCSendController(
int ptr);
}
@@ -22,9 +22,11 @@ class PickDirectoryResultMapper extends ClassMapperBase<PickDirectoryResult> {
final String id = 'PickDirectoryResult';
static String _$directoryUri(PickDirectoryResult v) => v.directoryUri;
static const Field<PickDirectoryResult, String> _f$directoryUri = Field('directoryUri', _$directoryUri);
static const Field<PickDirectoryResult, String> _f$directoryUri =
Field('directoryUri', _$directoryUri);
static List<FileInfo> _$files(PickDirectoryResult v) => v.files;
static const Field<PickDirectoryResult, List<FileInfo>> _f$files = Field('files', _$files);
static const Field<PickDirectoryResult, List<FileInfo>> _f$files =
Field('files', _$files);
@override
final MappableFields<PickDirectoryResult> fields = const {
@@ -33,7 +35,8 @@ class PickDirectoryResultMapper extends ClassMapperBase<PickDirectoryResult> {
};
static PickDirectoryResult _instantiate(DecodingData data) {
return PickDirectoryResult(directoryUri: data.dec(_f$directoryUri), files: data.dec(_f$files));
return PickDirectoryResult(
directoryUri: data.dec(_f$directoryUri), files: data.dec(_f$files));
}
@override
@@ -50,61 +53,81 @@ class PickDirectoryResultMapper extends ClassMapperBase<PickDirectoryResult> {
mixin PickDirectoryResultMappable {
String serialize() {
return PickDirectoryResultMapper.ensureInitialized().encodeJson<PickDirectoryResult>(this as PickDirectoryResult);
return PickDirectoryResultMapper.ensureInitialized()
.encodeJson<PickDirectoryResult>(this as PickDirectoryResult);
}
Map<String, dynamic> toJson() {
return PickDirectoryResultMapper.ensureInitialized().encodeMap<PickDirectoryResult>(this as PickDirectoryResult);
return PickDirectoryResultMapper.ensureInitialized()
.encodeMap<PickDirectoryResult>(this as PickDirectoryResult);
}
PickDirectoryResultCopyWith<PickDirectoryResult, PickDirectoryResult, PickDirectoryResult> get copyWith =>
_PickDirectoryResultCopyWithImpl(this as PickDirectoryResult, $identity, $identity);
PickDirectoryResultCopyWith<PickDirectoryResult, PickDirectoryResult,
PickDirectoryResult>
get copyWith => _PickDirectoryResultCopyWithImpl(
this as PickDirectoryResult, $identity, $identity);
@override
String toString() {
return PickDirectoryResultMapper.ensureInitialized().stringifyValue(this as PickDirectoryResult);
return PickDirectoryResultMapper.ensureInitialized()
.stringifyValue(this as PickDirectoryResult);
}
@override
bool operator ==(Object other) {
return PickDirectoryResultMapper.ensureInitialized().equalsValue(this as PickDirectoryResult, other);
return PickDirectoryResultMapper.ensureInitialized()
.equalsValue(this as PickDirectoryResult, other);
}
@override
int get hashCode {
return PickDirectoryResultMapper.ensureInitialized().hashValue(this as PickDirectoryResult);
return PickDirectoryResultMapper.ensureInitialized()
.hashValue(this as PickDirectoryResult);
}
}
extension PickDirectoryResultValueCopy<$R, $Out> on ObjectCopyWith<$R, PickDirectoryResult, $Out> {
PickDirectoryResultCopyWith<$R, PickDirectoryResult, $Out> get $asPickDirectoryResult =>
$base.as((v, t, t2) => _PickDirectoryResultCopyWithImpl(v, t, t2));
extension PickDirectoryResultValueCopy<$R, $Out>
on ObjectCopyWith<$R, PickDirectoryResult, $Out> {
PickDirectoryResultCopyWith<$R, PickDirectoryResult, $Out>
get $asPickDirectoryResult =>
$base.as((v, t, t2) => _PickDirectoryResultCopyWithImpl(v, t, t2));
}
abstract class PickDirectoryResultCopyWith<$R, $In extends PickDirectoryResult, $Out> implements ClassCopyWith<$R, $In, $Out> {
ListCopyWith<$R, FileInfo, FileInfoCopyWith<$R, FileInfo, FileInfo>> get files;
abstract class PickDirectoryResultCopyWith<$R, $In extends PickDirectoryResult,
$Out> implements ClassCopyWith<$R, $In, $Out> {
ListCopyWith<$R, FileInfo, FileInfoCopyWith<$R, FileInfo, FileInfo>>
get files;
$R call({String? directoryUri, List<FileInfo>? files});
PickDirectoryResultCopyWith<$R2, $In, $Out2> $chain<$R2, $Out2>(Then<$Out2, $R2> t);
PickDirectoryResultCopyWith<$R2, $In, $Out2> $chain<$R2, $Out2>(
Then<$Out2, $R2> t);
}
class _PickDirectoryResultCopyWithImpl<$R, $Out> extends ClassCopyWithBase<$R, PickDirectoryResult, $Out>
class _PickDirectoryResultCopyWithImpl<$R, $Out>
extends ClassCopyWithBase<$R, PickDirectoryResult, $Out>
implements PickDirectoryResultCopyWith<$R, PickDirectoryResult, $Out> {
_PickDirectoryResultCopyWithImpl(super.value, super.then, super.then2);
@override
late final ClassMapperBase<PickDirectoryResult> $mapper = PickDirectoryResultMapper.ensureInitialized();
late final ClassMapperBase<PickDirectoryResult> $mapper =
PickDirectoryResultMapper.ensureInitialized();
@override
ListCopyWith<$R, FileInfo, FileInfoCopyWith<$R, FileInfo, FileInfo>> get files =>
ListCopyWith($value.files, (v, t) => v.copyWith.$chain(t), (v) => call(files: v));
ListCopyWith<$R, FileInfo, FileInfoCopyWith<$R, FileInfo, FileInfo>>
get files => ListCopyWith(
$value.files, (v, t) => v.copyWith.$chain(t), (v) => call(files: v));
@override
$R call({String? directoryUri, List<FileInfo>? files}) =>
$apply(FieldCopyWithData({if (directoryUri != null) #directoryUri: directoryUri, if (files != null) #files: files}));
$apply(FieldCopyWithData({
if (directoryUri != null) #directoryUri: directoryUri,
if (files != null) #files: files
}));
@override
PickDirectoryResult $make(CopyWithData data) =>
PickDirectoryResult(directoryUri: data.get(#directoryUri, or: $value.directoryUri), files: data.get(#files, or: $value.files));
PickDirectoryResult $make(CopyWithData data) => PickDirectoryResult(
directoryUri: data.get(#directoryUri, or: $value.directoryUri),
files: data.get(#files, or: $value.files));
@override
PickDirectoryResultCopyWith<$R2, PickDirectoryResult, $Out2> $chain<$R2, $Out2>(Then<$Out2, $R2> t) =>
_PickDirectoryResultCopyWithImpl($value, $cast, t);
PickDirectoryResultCopyWith<$R2, PickDirectoryResult, $Out2>
$chain<$R2, $Out2>(Then<$Out2, $R2> t) =>
_PickDirectoryResultCopyWithImpl($value, $cast, t);
}
class FileInfoMapper extends ClassMapperBase<FileInfo> {
@@ -128,7 +151,8 @@ class FileInfoMapper extends ClassMapperBase<FileInfo> {
static String _$uri(FileInfo v) => v.uri;
static const Field<FileInfo, String> _f$uri = Field('uri', _$uri);
static int _$lastModified(FileInfo v) => v.lastModified;
static const Field<FileInfo, int> _f$lastModified = Field('lastModified', _$lastModified);
static const Field<FileInfo, int> _f$lastModified =
Field('lastModified', _$lastModified);
@override
final MappableFields<FileInfo> fields = const {
@@ -139,7 +163,11 @@ class FileInfoMapper extends ClassMapperBase<FileInfo> {
};
static FileInfo _instantiate(DecodingData data) {
return FileInfo(name: data.dec(_f$name), size: data.dec(_f$size), uri: data.dec(_f$uri), lastModified: data.dec(_f$lastModified));
return FileInfo(
name: data.dec(_f$name),
size: data.dec(_f$size),
uri: data.dec(_f$uri),
lastModified: data.dec(_f$lastModified));
}
@override
@@ -156,14 +184,17 @@ class FileInfoMapper extends ClassMapperBase<FileInfo> {
mixin FileInfoMappable {
String serialize() {
return FileInfoMapper.ensureInitialized().encodeJson<FileInfo>(this as FileInfo);
return FileInfoMapper.ensureInitialized()
.encodeJson<FileInfo>(this as FileInfo);
}
Map<String, dynamic> toJson() {
return FileInfoMapper.ensureInitialized().encodeMap<FileInfo>(this as FileInfo);
return FileInfoMapper.ensureInitialized()
.encodeMap<FileInfo>(this as FileInfo);
}
FileInfoCopyWith<FileInfo, FileInfo, FileInfo> get copyWith => _FileInfoCopyWithImpl(this as FileInfo, $identity, $identity);
FileInfoCopyWith<FileInfo, FileInfo, FileInfo> get copyWith =>
_FileInfoCopyWithImpl(this as FileInfo, $identity, $identity);
@override
String toString() {
return FileInfoMapper.ensureInitialized().stringifyValue(this as FileInfo);
@@ -171,7 +202,8 @@ mixin FileInfoMappable {
@override
bool operator ==(Object other) {
return FileInfoMapper.ensureInitialized().equalsValue(this as FileInfo, other);
return FileInfoMapper.ensureInitialized()
.equalsValue(this as FileInfo, other);
}
@override
@@ -181,21 +213,27 @@ mixin FileInfoMappable {
}
extension FileInfoValueCopy<$R, $Out> on ObjectCopyWith<$R, FileInfo, $Out> {
FileInfoCopyWith<$R, FileInfo, $Out> get $asFileInfo => $base.as((v, t, t2) => _FileInfoCopyWithImpl(v, t, t2));
FileInfoCopyWith<$R, FileInfo, $Out> get $asFileInfo =>
$base.as((v, t, t2) => _FileInfoCopyWithImpl(v, t, t2));
}
abstract class FileInfoCopyWith<$R, $In extends FileInfo, $Out> implements ClassCopyWith<$R, $In, $Out> {
abstract class FileInfoCopyWith<$R, $In extends FileInfo, $Out>
implements ClassCopyWith<$R, $In, $Out> {
$R call({String? name, int? size, String? uri, int? lastModified});
FileInfoCopyWith<$R2, $In, $Out2> $chain<$R2, $Out2>(Then<$Out2, $R2> t);
}
class _FileInfoCopyWithImpl<$R, $Out> extends ClassCopyWithBase<$R, FileInfo, $Out> implements FileInfoCopyWith<$R, FileInfo, $Out> {
class _FileInfoCopyWithImpl<$R, $Out>
extends ClassCopyWithBase<$R, FileInfo, $Out>
implements FileInfoCopyWith<$R, FileInfo, $Out> {
_FileInfoCopyWithImpl(super.value, super.then, super.then2);
@override
late final ClassMapperBase<FileInfo> $mapper = FileInfoMapper.ensureInitialized();
late final ClassMapperBase<FileInfo> $mapper =
FileInfoMapper.ensureInitialized();
@override
$R call({String? name, int? size, String? uri, int? lastModified}) => $apply(FieldCopyWithData({
$R call({String? name, int? size, String? uri, int? lastModified}) =>
$apply(FieldCopyWithData({
if (name != null) #name: name,
if (size != null) #size: size,
if (uri != null) #uri: uri,
@@ -209,5 +247,7 @@ class _FileInfoCopyWithImpl<$R, $Out> extends ClassCopyWithBase<$R, FileInfo, $O
lastModified: data.get(#lastModified, or: $value.lastModified));
@override
FileInfoCopyWith<$R2, FileInfo, $Out2> $chain<$R2, $Out2>(Then<$Out2, $R2> t) => _FileInfoCopyWithImpl($value, $cast, t);
FileInfoCopyWith<$R2, FileInfo, $Out2> $chain<$R2, $Out2>(
Then<$Out2, $R2> t) =>
_FileInfoCopyWithImpl($value, $cast, t);
}
+29 -1
View File
@@ -3,6 +3,8 @@ import 'dart:typed_data';
import 'package:basic_utils/basic_utils.dart';
import 'package:common/model/stored_security_context.dart';
import 'package:convert/convert.dart';
import 'package:localsend_app/rust/api/crypto.dart' as rust;
/// Generates a random [SecurityContextResult].
StoredSecurityContext generateSecurityContext([AsymmetricKeyPair? keyPair]) {
@@ -19,11 +21,13 @@ StoredSecurityContext generateSecurityContext([AsymmetricKeyPair? keyPair]) {
};
final csr = X509Utils.generateRsaCsrPem(dn, privateKey, publicKey);
final certificate = X509Utils.generateSelfSignedCertificate(keyPair.privateKey, csr, 365 * 10);
final hash = calculateHashOfCertificate(certificate);
final spki = extractPublicKeyFromCertificate(certificate);
return StoredSecurityContext(
privateKey: CryptoUtils.encodeRSAPrivateKeyToPemPkcs1(privateKey),
publicKey: CryptoUtils.encodeRSAPublicKeyToPemPkcs1(publicKey),
publicKey: spki,
certificate: certificate,
certificateHash: hash,
);
@@ -41,3 +45,27 @@ String calculateHashOfCertificate(String certificate) {
algorithmName: 'SHA-256',
);
}
String extractPublicKeyFromCertificate(String certificate) {
final cert = X509Utils.x509CertificateFromPem(certificate);
final publicHex = cert.tbsCertificate!.subjectPublicKeyInfo.bytes!;
return _hexToSpkiPem(publicHex);
}
String _hexToSpkiPem(String hexBytes) {
final publicBytes = hex.decode(hexBytes);
final publicBase64 = base64Encode(publicBytes);
final temp = '''-----BEGIN PUBLIC KEY-----
$publicBase64
-----END PUBLIC KEY-----''';
return X509Utils.fixPem(temp);
}
/// Verifies a certificate with a public key.
/// Throws an exception if the certificate is invalid.
Future<void> verifyCertificate({
required String cert,
required String publicKey,
}) async {
await rust.verifyCert(cert: cert, publicKey: publicKey);
}
+12 -5
View File
@@ -53,11 +53,18 @@ class DeviceListTile extends StatelessWidget {
child: CustomProgressBar(progress: progress!),
)
else ...[
DeviceBadge(
backgroundColor: badgeColor,
foregroundColor: Theme.of(context).colorScheme.onSecondaryContainer,
label: '#${device.ip.visualId}',
),
if (device.ip != null)
DeviceBadge(
backgroundColor: badgeColor,
foregroundColor: Theme.of(context).colorScheme.onSecondaryContainer,
label: 'LAN • HTTP',
)
else
DeviceBadge(
backgroundColor: badgeColor,
foregroundColor: Theme.of(context).colorScheme.onSecondaryContainer,
label: 'WebRTC',
),
if (device.deviceModel != null)
DeviceBadge(
backgroundColor: badgeColor,
@@ -20,6 +20,7 @@ list(APPEND FLUTTER_PLUGIN_LIST
list(APPEND FLUTTER_FFI_PLUGIN_LIST
rhttp
rust_lib_localsend_app
)
set(PLUGIN_BUNDLED_LIBRARIES)
+34 -22
View File
@@ -1,4 +1,6 @@
PODS:
- bitsdojo_window_macos (0.0.1):
- FlutterMacOS
- connectivity_plus (0.0.1):
- Flutter
- FlutterMacOS
@@ -34,6 +36,8 @@ PODS:
- FlutterMacOS
- rhttp (0.0.1):
- FlutterMacOS
- rust_lib_localsend_app (0.0.1):
- FlutterMacOS
- screen_retriever_macos (0.0.1):
- FlutterMacOS
- shared_preferences_foundation (0.0.1):
@@ -54,6 +58,7 @@ PODS:
- FlutterMacOS
DEPENDENCIES:
- bitsdojo_window_macos (from `Flutter/ephemeral/.symlinks/plugins/bitsdojo_window_macos/macos`)
- connectivity_plus (from `Flutter/ephemeral/.symlinks/plugins/connectivity_plus/darwin`)
- Defaults (~> 4.2)
- desktop_drop (from `Flutter/ephemeral/.symlinks/plugins/desktop_drop/macos`)
@@ -70,6 +75,7 @@ DEPENDENCIES:
- path_provider_foundation (from `Flutter/ephemeral/.symlinks/plugins/path_provider_foundation/darwin`)
- photo_manager (from `Flutter/ephemeral/.symlinks/plugins/photo_manager/macos`)
- rhttp (from `Flutter/ephemeral/.symlinks/plugins/rhttp/macos`)
- rust_lib_localsend_app (from `Flutter/ephemeral/.symlinks/plugins/rust_lib_localsend_app/macos`)
- screen_retriever_macos (from `Flutter/ephemeral/.symlinks/plugins/screen_retriever_macos/macos`)
- shared_preferences_foundation (from `Flutter/ephemeral/.symlinks/plugins/shared_preferences_foundation/darwin`)
- tray_manager (from `Flutter/ephemeral/.symlinks/plugins/tray_manager/macos`)
@@ -84,6 +90,8 @@ SPEC REPOS:
- Defaults
EXTERNAL SOURCES:
bitsdojo_window_macos:
:path: Flutter/ephemeral/.symlinks/plugins/bitsdojo_window_macos/macos
connectivity_plus:
:path: Flutter/ephemeral/.symlinks/plugins/connectivity_plus/darwin
desktop_drop:
@@ -114,6 +122,8 @@ EXTERNAL SOURCES:
:path: Flutter/ephemeral/.symlinks/plugins/photo_manager/macos
rhttp:
:path: Flutter/ephemeral/.symlinks/plugins/rhttp/macos
rust_lib_localsend_app:
:path: Flutter/ephemeral/.symlinks/plugins/rust_lib_localsend_app/macos
screen_retriever_macos:
:path: Flutter/ephemeral/.symlinks/plugins/screen_retriever_macos/macos
shared_preferences_foundation:
@@ -132,30 +142,32 @@ EXTERNAL SOURCES:
:path: Flutter/ephemeral/.symlinks/plugins/window_manager/macos
SPEC CHECKSUMS:
connectivity_plus: 4c41c08fc6d7c91f63bc7aec70ffe3730b04f563
bitsdojo_window_macos: 7959fb0ca65a3ccda30095c181ecb856fae48ea9
connectivity_plus: b21496ab28d1324eb59885d888a4d83b98531f01
Defaults: d785e56c0fb8890dc40351603f05c8e1df1bdd45
desktop_drop: 69eeff437544aa619c8db7f4481b3a65f7696898
device_info_plus: 1b14eed9bf95428983aed283a8d51cce3d8c4215
dynamic_color: 2eaa27267de1ca20d879fbd6e01259773fb1670f
file_selector_macos: cc3858c981fe6889f364731200d6232dac1d812d
desktop_drop: e0b672a7d84c0a6cbc378595e82cdb15f2970a43
device_info_plus: 4fb280989f669696856f8b129e4a5e3cd6c48f76
dynamic_color: b820c000cc68df65e7ba7ff177cb98404ce56651
file_selector_macos: 6280b52b459ae6c590af5d78fc35c7267a3c4b31
FlutterMacOS: 8f6f14fa908a6fb3fba0cd85dbd81ec4b251fb24
gal: 61e868295d28fe67ffa297fae6dacebf56fd53e1
in_app_purchase_storekit: 8c3b0b3eb1b0f04efbff401c3de6266d4258d433
network_info_plus: 2cb02d8435635eae13b3b79279681985121cf30c
open_dir_macos: 9649018f88e71eb9fb8aa3d95caec30a73c08c5b
package_info_plus: 12f1c5c2cfe8727ca46cbd0b26677728972d9a5b
pasteboard: 9b69dba6fedbb04866be632205d532fe2f6b1d99
path_provider_foundation: 2b6b4c569c0fb62ec74538f866245ac84301af46
photo_manager: ff695c7a1dd5bc379974953a2b5c0a293f7c4c8a
rhttp: 337afda4c3e4df31087160719ffca6452c225cc2
screen_retriever_macos: 776e0fa5d42c6163d2bf772d22478df4b302b161
shared_preferences_foundation: fcdcbc04712aee1108ac7fda236f363274528f78
tray_manager: 9064e219c56d75c476e46b9a21182087930baf90
uri_content: bfedc2e58f0ee4de88a63e5bcb826398389b22cb
url_launcher_macos: c82c93949963e55b228a30115bd219499a6fe404
video_player_avfoundation: 7c6c11d8470e1675df7397027218274b6d2360b3
wakelock_plus: 4783562c9a43d209c458cb9b30692134af456269
window_manager: 3a1844359a6295ab1e47659b1a777e36773cd6e8
gal: 44e5b10dbd347c8247a2851acee6c1fbe282c1d3
in_app_purchase_storekit: e126ef1b89e4a9fdf07e28f005f82632b4609437
network_info_plus: 21d1cd6a015ccb2fdff06a1fbfa88d54b4e92f61
open_dir_macos: 79810d7921d777f8732bf6358b3a0839a8fad9b5
package_info_plus: f0052d280d17aa382b932f399edf32507174e870
pasteboard: 278d8100149f940fb795d6b3a74f0720c890ecb7
path_provider_foundation: 080d55be775b7414fd5a5ef3ac137b97b097e564
photo_manager: d2fbcc0f2d82458700ee6256a15018210a81d413
rhttp: 08d791d6373089de796318f4cfb172cbcf34e78b
rust_lib_localsend_app: 6b270a4b507b1599a1d06c9ebf86d01adfa0e875
screen_retriever_macos: 452e51764a9e1cdb74b3c541238795849f21557f
shared_preferences_foundation: 9e1978ff2562383bd5676f64ec4e9aa8fa06a6f7
tray_manager: a104b5c81b578d83f3c3d0f40a997c8b10810166
uri_content: a2350e4567f5fba3f48bb0f144f277eaddf0aa2c
url_launcher_macos: 0fba8ddabfc33ce0a9afe7c5fef5aab3d8d2d673
video_player_avfoundation: 2cef49524dd1f16c5300b9cd6efd9611ce03639b
wakelock_plus: 21ddc249ac4b8d018838dbdabd65c5976c308497
window_manager: 1d01fa7ac65a6e6f83b965471b1a7fdd3f06166c
PODFILE CHECKSUM: 5c6550f5101fcba381ddb97e2135e4cacca4f31f
+30 -15
View File
@@ -278,7 +278,7 @@ packages:
source: hosted
version: "2.0.1"
convert:
dependency: transitive
dependency: "direct main"
description:
name: convert
sha256: b30acd5944035672bc15c6b7a8b47d773e41e2f17de064350988c5d02adb1c68
@@ -584,13 +584,13 @@ packages:
source: hosted
version: "2.0.23"
flutter_rust_bridge:
dependency: transitive
dependency: "direct main"
description:
name: flutter_rust_bridge
sha256: "3292ad6085552987b8b3b9a7e5805567f4013372d302736b702801acb001ee00"
sha256: "37ef40bc6f863652e865f0b2563ea07f0d3c58d8efad803cc01933a4b2ee067e"
url: "https://pub.dev"
source: hosted
version: "2.7.1"
version: "2.11.1"
flutter_test:
dependency: transitive
description: flutter
@@ -601,8 +601,16 @@ packages:
description: flutter
source: sdk
version: "0.0.0"
freezed:
dependency: "direct dev"
description:
name: freezed
sha256: "44c19278dd9d89292cf46e97dc0c1e52ce03275f40a97c5a348e802a924bf40e"
url: "https://pub.dev"
source: hosted
version: "2.5.7"
freezed_annotation:
dependency: transitive
dependency: "direct main"
description:
name: freezed_annotation
sha256: c2e2d632dd9b8a2b7751117abcfc2b4888ecfe181bd9fca7170d9ef02e595fe2
@@ -1351,42 +1359,42 @@ packages:
dependency: transitive
description:
name: refena
sha256: "1446e9622451e0cffef2af5b3fd57a52f0688d7c9eb848e969c16ccc2d14e833"
sha256: "69b2744196f7c752b66a20a360d6c188f52cccb7b4d6f5bcf61bede3a7764a35"
url: "https://pub.dev"
source: hosted
version: "2.1.1"
version: "3.1.0"
refena_flutter:
dependency: "direct main"
description:
name: refena_flutter
sha256: "2e57bab72667f37b55f26675d46c0a362e6eb115a70605c90163736b85e97a42"
sha256: "5f090b0ecc7079161d6fff4bad3644df3984bc23b42aabc171d638caf5d6a264"
url: "https://pub.dev"
source: hosted
version: "2.1.1"
version: "3.1.0"
refena_inspector:
dependency: "direct dev"
description:
name: refena_inspector
sha256: "717a19f70d9667e2459fd8dfd6a72b1306bd2c04bfc255bada4f2eb429ca4757"
sha256: "2b2b8dc85c908c4c1ce733f53b4d505496c67944a98fb3586eb2eb7a4e62d7a7"
url: "https://pub.dev"
source: hosted
version: "2.0.3"
version: "2.1.0"
refena_inspector_client:
dependency: "direct main"
description:
name: refena_inspector_client
sha256: "8bcc1e169bfc0e5ba448f4920067a0579c0b4a42fff39dbdfd4a743bf2b235a6"
sha256: "88f41a0b55aae12a88ad40c33b0b1593581ead0c32b0bcfed1115daf6d54e6ce"
url: "https://pub.dev"
source: hosted
version: "2.0.1"
version: "2.1.0"
rhttp:
dependency: "direct main"
description:
name: rhttp
sha256: "3deabc6c3384b4efa252dfb4a5059acc6530117fdc1b10f5f67ff9768c9af75a"
sha256: e8f0a8756a931598b7d9c4107a4afe93c2b81cbf8c45e532ba9dc52e12bbaa35
url: "https://pub.dev"
source: hosted
version: "0.10.0"
version: "0.13.0"
routerino:
dependency: "direct main"
description:
@@ -1395,6 +1403,13 @@ packages:
url: "https://pub.dev"
source: hosted
version: "0.8.0"
rust_lib_localsend_app:
dependency: "direct main"
description:
path: rust_builder
relative: true
source: path
version: "0.0.1"
saf_stream:
dependency: "direct main"
description:
+10 -4
View File
@@ -16,6 +16,7 @@ dependencies:
common:
path: ../common
connectivity_plus: 6.1.0
convert: 3.1.2
dart_mappable: 4.3.0
desktop_drop: 0.5.0
device_apps: 2.2.0
@@ -29,6 +30,8 @@ dependencies:
flutter_localizations:
sdk: flutter
flutter_markdown: 0.7.4+2
flutter_rust_bridge: 2.11.1
freezed_annotation: 2.4.4
gal: 2.3.0
glob: ^2.1.2
image: 4.3.0
@@ -53,10 +56,12 @@ dependencies:
path_provider_foundation: 2.4.0
permission_handler: 11.3.1
pretty_qr_code: 3.3.0
refena_flutter: 2.1.1
refena_inspector_client: 2.0.1
rhttp: 0.10.0
refena_flutter: 3.1.0
refena_inspector_client: 2.1.0
rhttp: 0.13.0
routerino: 0.8.0
rust_lib_localsend_app:
path: rust_builder
saf_stream: 0.10.0
screen_retriever: 0.2.0
share_handler: 0.0.22
@@ -82,8 +87,9 @@ dev_dependencies:
dart_mappable_builder: 4.3.0
flutter_gen_runner: 5.8.0
flutter_lints: 5.0.0
freezed: 2.5.7
mockito: 5.4.4
refena_inspector: 2.0.3
refena_inspector: 2.1.0
slang_build_runner: 4.5.0
test: ^1.24.8
+1
View File
@@ -0,0 +1 @@
/target
+3520
View File
File diff suppressed because it is too large Load Diff
+17
View File
@@ -0,0 +1,17 @@
[package]
name = "rust_lib_localsend_app"
version = "0.1.0"
edition = "2021"
[lib]
crate-type = ["cdylib", "staticlib"]
[dependencies]
anyhow = "1.0.95"
bytes = "1.9.0"
flutter_rust_bridge = { version = "=2.11.1", features = ["uuid"] }
localsend = { path = "../../core", features = ["full"] }
tokio = { version = "1.43.0", features = ["full"] }
tracing = "0.1.41"
tracing-subscriber = { version = "0.3.19" }
uuid = { version = "1.11.1", features = ["v4"] }
+21
View File
@@ -0,0 +1,21 @@
pub fn verify_cert(cert: String, public_key: String) -> anyhow::Result<()> {
localsend::crypto::cert::verify_cert_from_pem(cert, Some(public_key))
}
pub fn generate_key_pair() -> anyhow::Result<KeyPair> {
let signing_key = localsend::crypto::token::generate_key();
let private_key = localsend::crypto::token::export_private_key(&signing_key)?;
let public_key = localsend::crypto::token::export_public_key(&signing_key)?;
Ok(
KeyPair {
private_key: private_key.to_string(),
public_key,
}
)
}
pub struct KeyPair {
pub private_key: String,
pub public_key: String,
}
+11
View File
@@ -0,0 +1,11 @@
use anyhow::Result;
use tracing::Level;
pub fn enable_debug_logging() -> Result<()> {
tracing_subscriber::fmt()
.with_max_level(Level::DEBUG)
.try_init()
.map_err(|e| anyhow::anyhow!(e.to_string()))?;
Ok(())
}
+4
View File
@@ -0,0 +1,4 @@
pub mod crypto;
pub mod logging;
pub mod model;
pub mod webrtc;
+72
View File
@@ -0,0 +1,72 @@
use flutter_rust_bridge::frb;
pub use localsend::model::discovery::{DeviceType, ProtocolType, RegisterDto, RegisterResponseDto};
pub use localsend::model::transfer::{
FileDto, FileMetadata, PrepareUploadRequestDto, PrepareUploadResponseDto,
};
use std::collections::HashMap;
#[frb(mirror(RegisterDto))]
pub struct _RegisterDto {
pub alias: String,
pub version: String,
pub device_model: Option<String>,
pub device_type: Option<DeviceType>,
pub fingerprint: String,
pub port: u16,
pub protocol: ProtocolType,
pub download: bool,
}
#[frb(mirror(RegisterResponseDto))]
pub struct _RegisterResponseDto {
pub alias: String,
pub version: String,
pub device_model: Option<String>,
pub device_type: Option<DeviceType>,
pub fingerprint: String,
pub download: bool,
}
#[frb(mirror(DeviceType))]
pub enum _DeviceType {
Mobile,
Desktop,
Web,
Headless,
Server,
}
#[frb(mirror(ProtocolType))]
pub enum _ProtocolType {
Http,
Https,
}
#[frb(mirror(FileDto))]
pub struct _FileDto {
pub id: String,
pub file_name: String,
pub size: u64,
pub file_type: String,
pub sha256: Option<String>,
pub preview: Option<String>,
pub metadata: Option<FileMetadata>,
}
#[frb(mirror(FileMetadata))]
pub struct _FileMetadata {
pub modified: Option<String>,
pub accessed: Option<String>,
}
#[frb(mirror(PrepareUploadRequestDto))]
pub struct _PrepareUploadRequestDto {
pub info: RegisterDto,
pub files: HashMap<String, FileDto>,
}
#[frb(mirror(PrepareUploadResponseDto))]
pub struct _PrepareUploadResponseDto {
pub session_id: String,
pub files: HashMap<String, String>,
}
+514
View File
@@ -0,0 +1,514 @@
use crate::frb_generated::StreamSink;
use bytes::Bytes;
use flutter_rust_bridge::{frb, DartFnFuture};
use localsend::crypto::token::SigningTokenKey;
use localsend::model::discovery::DeviceType;
use localsend::model::transfer::FileDto;
pub use localsend::webrtc::signaling::{
ClientInfo, ClientInfoWithoutId, ManagedSignalingConnection, SignalingConnection,
WsServerMessage, WsServerSdpMessage,
};
pub use localsend::webrtc::webrtc::{
PinConfig, RTCFile, RTCFileError, RTCSendFileResponse, RTCStatus,
};
use std::collections::HashSet;
use std::sync::Arc;
use std::time::Duration;
use tokio::sync::{mpsc, oneshot, Mutex};
use tokio::time;
use uuid::Uuid;
pub struct ProposingClientInfo {
pub alias: String,
pub version: String,
pub device_model: Option<String>,
pub device_type: Option<DeviceType>,
}
impl ProposingClientInfo {
fn sign(&self, signing_key: &SigningTokenKey) -> anyhow::Result<ClientInfoWithoutId> {
Ok(ClientInfoWithoutId {
alias: self.alias.clone(),
version: self.version.clone(),
device_model: self.device_model.clone(),
device_type: self.device_type.clone(),
token: localsend::crypto::token::generate_token_timestamp(&signing_key)?,
})
}
}
pub async fn connect(
sink: StreamSink<WsServerMessage>,
uri: String,
info: ProposingClientInfo,
private_key: String,
on_connection: impl Fn(LsSignalingConnection) -> DartFnFuture<()>,
) {
let Ok(signing_key) = localsend::crypto::token::parse_private_key(&private_key) else {
let _ = sink.add_error(anyhow::anyhow!("Invalid private key"));
return;
};
let Ok(client_info) = info.sign(&signing_key) else {
let _ = sink.add_error(anyhow::anyhow!("Invalid client info"));
return;
};
let connection = match SignalingConnection::connect(uri, &client_info).await {
Ok(connection) => connection,
Err(e) => {
let _ = sink.add_error(e.to_string());
return;
}
};
let (managed_connection, mut rx) = connection.start_listener();
on_connection(LsSignalingConnection {
inner: Arc::new(managed_connection),
})
.await;
while let Some(message) = rx.recv().await {
let _ = sink.add(message.into());
}
}
pub struct LsSignalingConnection {
inner: Arc<ManagedSignalingConnection>,
}
impl LsSignalingConnection {
pub async fn update_info(&self, info: ClientInfoWithoutId) -> anyhow::Result<()> {
self.inner.send_update(info).await?;
Ok(())
}
pub async fn send_offer(
&self,
stun_servers: Vec<String>,
target: Uuid,
private_key: &str,
expecting_public_key: Option<ExpectingPublicKey>,
pin: Option<PinConfig>,
files: Vec<FileDto>,
) -> anyhow::Result<RTCSendController> {
let (status_tx, status_rx) = mpsc::channel::<RTCStatus>(1);
let (selected_tx, selected_rx) = oneshot::channel::<HashSet<String>>();
let (error_tx, error_rx) = mpsc::channel::<RTCFileError>(1);
let (pin_tx, mut pin_rx) = mpsc::channel::<oneshot::Sender<String>>(1);
let (pair_tx, pair_rx) = oneshot::channel::<oneshot::Sender<bool>>();
let (send_tx, send_rx) = mpsc::channel::<RTCFile>(1);
let managed_connection = self.inner.clone();
let signing_key = localsend::crypto::token::parse_private_key(private_key)?;
let expecting_public_key = match expecting_public_key {
Some(key) => Some(localsend::crypto::token::parse_public_key(
&key.public_key,
&key.kind,
)?),
None => None,
};
tokio::spawn(async move {
let result = localsend::webrtc::webrtc::send_offer(
&managed_connection,
stun_servers,
target,
signing_key,
expecting_public_key,
pin,
files,
status_tx.clone(),
selected_tx,
error_tx,
pin_tx,
pair_tx,
send_rx,
)
.await;
if let Err(e) = result {
let _ = status_tx.send(RTCStatus::Error(e.to_string())).await;
}
});
tokio::spawn(async move {
// TODO: support pairing
let Ok(pair_tx) = pair_rx.await else {
return;
};
let _ = pair_tx.send(false);
});
let pin_sender = Arc::new(Mutex::new(None));
tokio::spawn({
let pin_sender = Arc::clone(&pin_sender);
async move {
while let Some(pin_tx) = pin_rx.recv().await {
*pin_sender.lock().await = Some(pin_tx);
}
}
});
Ok(RTCSendController {
status_rx,
selected_rx: Arc::new(Mutex::new(Some(selected_rx))),
error_rx,
pin_tx: pin_sender,
send_tx,
})
}
pub async fn accept_offer(
&self,
stun_servers: Vec<String>,
offer: WsServerSdpMessage,
private_key: &str,
expecting_public_key: Option<ExpectingPublicKey>,
pin: Option<PinConfig>,
) -> anyhow::Result<RTCReceiveController> {
let (status_tx, status_rx) = mpsc::channel::<RTCStatus>(1);
let (files_tx, files_rx) = oneshot::channel::<Vec<FileDto>>();
let (selected_tx, selected_rx) = oneshot::channel::<Option<HashSet<String>>>();
let (error_tx, error_rx) = mpsc::channel::<RTCFileError>(1);
let (receiving_tx, receiving_rx) = mpsc::channel::<RTCFile>(1);
let (pin_tx, mut pin_rx) = mpsc::channel::<oneshot::Sender<String>>(1);
let (file_status_tx, file_status_rx) = mpsc::channel::<RTCSendFileResponse>(1);
let managed_connection = self.inner.clone();
let signing_key = localsend::crypto::token::parse_private_key(private_key)?;
let expecting_public_key = match expecting_public_key {
Some(key) => Some(localsend::crypto::token::parse_public_key(
&key.public_key,
&key.kind,
)?),
None => None,
};
tokio::spawn(async move {
let result = localsend::webrtc::webrtc::accept_offer(
&managed_connection,
stun_servers,
&offer,
signing_key,
expecting_public_key,
pin,
status_tx.clone(),
files_tx,
selected_rx,
error_tx,
pin_tx,
receiving_tx,
file_status_rx,
)
.await;
if let Err(e) = result {
let _ = status_tx.send(RTCStatus::Error(e.to_string())).await;
}
});
let pin_sender = Arc::new(Mutex::new(None));
tokio::spawn({
let pin_sender = Arc::clone(&pin_sender);
async move {
while let Some(pin_tx) = pin_rx.recv().await {
*pin_sender.lock().await = Some(pin_tx);
}
}
});
Ok(RTCReceiveController {
status_rx: Arc::new(Mutex::new(Some(status_rx))),
files_rx: Arc::new(Mutex::new(Some(files_rx))),
selected_tx: Arc::new(Mutex::new(Some(selected_tx))),
error_rx: Arc::new(Mutex::new(Some(error_rx))),
pin_tx: pin_sender,
receiving_rx: Arc::new(Mutex::new(Some(receiving_rx))),
file_status_tx,
})
}
}
pub struct ExpectingPublicKey {
pub public_key: String,
/// "ed25519" or "rsa-pss"
pub kind: String,
}
pub struct RTCSendController {
status_rx: mpsc::Receiver<RTCStatus>,
selected_rx: Arc<Mutex<Option<oneshot::Receiver<HashSet<String>>>>>,
error_rx: mpsc::Receiver<RTCFileError>,
pin_tx: Arc<Mutex<Option<oneshot::Sender<String>>>>,
send_tx: mpsc::Sender<RTCFile>,
}
impl RTCSendController {
pub async fn listen_status(&mut self, sink: StreamSink<RTCStatus>) {
while let Some(status) = self.status_rx.recv().await {
let _ = sink.add(status);
}
}
pub async fn listen_selected_files(&self) -> anyhow::Result<HashSet<String>> {
let Some(selected_rx) = self.selected_rx.lock().await.take() else {
return Err(anyhow::anyhow!("Selected files already received"));
};
let Ok(selected) = selected_rx.await else {
return Err(anyhow::anyhow!("Selected files channel closed"));
};
Ok(selected)
}
pub async fn listen_error(&mut self, sink: StreamSink<RTCFileError>) {
while let Some(error) = self.error_rx.recv().await {
let _ = sink.add(error);
}
}
pub async fn send_pin(&self, pin: String) -> anyhow::Result<()> {
let Some(pin_tx) = self.pin_tx.lock().await.take() else {
return Err(anyhow::anyhow!("Pin already sent"));
};
pin_tx
.send(pin)
.map_err(|_| anyhow::anyhow!("Pin channel closed"))?;
Ok(())
}
pub async fn send_file(&self, file_id: String) -> anyhow::Result<RTCFileSender> {
let (tx, rx) = mpsc::channel::<Bytes>(1);
self.send_tx
.send(RTCFile {
file_id,
binary_rx: rx,
})
.await?;
Ok(RTCFileSender { binary_tx: tx })
}
}
pub struct RTCFileSender {
binary_tx: mpsc::Sender<Bytes>,
}
impl RTCFileSender {
pub async fn send(&self, data: Vec<u8>) -> anyhow::Result<()> {
self.binary_tx.send(Bytes::from(data)).await?;
Ok(())
}
}
pub struct RTCReceiveController {
status_rx: Arc<Mutex<Option<mpsc::Receiver<RTCStatus>>>>,
files_rx: Arc<Mutex<Option<oneshot::Receiver<Vec<FileDto>>>>>,
selected_tx: Arc<Mutex<Option<oneshot::Sender<Option<HashSet<String>>>>>>,
error_rx: Arc<Mutex<Option<mpsc::Receiver<RTCFileError>>>>,
pin_tx: Arc<Mutex<Option<oneshot::Sender<String>>>>,
receiving_rx: Arc<Mutex<Option<mpsc::Receiver<RTCFile>>>>,
file_status_tx: mpsc::Sender<RTCSendFileResponse>,
}
impl RTCReceiveController {
pub async fn listen_status(&self, sink: StreamSink<RTCStatus>) {
let Some(mut status_rx) = self.status_rx.lock().await.take() else {
let _ = sink.add_error(anyhow::anyhow!("Status stream already listened to"));
return;
};
while let Some(status) = status_rx.recv().await {
let _ = sink.add(status);
}
}
pub async fn listen_files(&self) -> anyhow::Result<Vec<FileDto>> {
let Some(files_rx) = self.files_rx.lock().await.take() else {
return Err(anyhow::anyhow!("Files already received"));
};
let Ok(files) = files_rx.await else {
return Err(anyhow::anyhow!("Files channel closed"));
};
Ok(files)
}
pub async fn send_pin(&self, pin: String) -> anyhow::Result<()> {
let Some(pin_tx) = self.pin_tx.lock().await.take() else {
return Err(anyhow::anyhow!("Pin already sent"));
};
pin_tx
.send(pin)
.map_err(|_| anyhow::anyhow!("Pin channel closed"))?;
Ok(())
}
pub async fn send_selection(&self, selection: HashSet<String>) -> anyhow::Result<()> {
let Some(selected_tx) = self.selected_tx.lock().await.take() else {
return Err(anyhow::anyhow!("Selected files already sent"));
};
selected_tx
.send(Some(selection))
.map_err(|_| anyhow::anyhow!("Selected files channel closed"))?;
Ok(())
}
pub async fn decline(&self) -> anyhow::Result<()> {
let Some(selected_tx) = self.selected_tx.lock().await.take() else {
return Err(anyhow::anyhow!("Selected files already sent"));
};
selected_tx
.send(None)
.map_err(|_| anyhow::anyhow!("Selected files channel closed"))?;
Ok(())
}
pub async fn listen_error(&self, sink: StreamSink<RTCFileError>) {
let Some(mut error_rx) = self.error_rx.lock().await.take() else {
let _ = sink.add_error(anyhow::anyhow!("Error stream already listened to"));
return;
};
while let Some(error) = error_rx.recv().await {
let _ = sink.add(error);
}
}
pub async fn listen_receiving(&self, sink: StreamSink<RTCFileReceiver>) {
let Some(mut receiving_rx) = self.receiving_rx.lock().await.take() else {
let _ = sink.add_error(anyhow::anyhow!("Receiving stream already listened to"));
return;
};
while let Some(file) = receiving_rx.recv().await {
let _ = sink.add(RTCFileReceiver {
file_id: file.file_id,
binary_rx: Arc::new(Mutex::new(Some(file.binary_rx))),
});
}
}
pub async fn send_file_status(&self, status: RTCSendFileResponse) -> anyhow::Result<()> {
self.file_status_tx.send(status).await?;
Ok(())
}
}
pub struct RTCFileReceiver {
file_id: String,
binary_rx: Arc<Mutex<Option<mpsc::Receiver<Bytes>>>>,
}
impl RTCFileReceiver {
pub fn get_file_id(&self) -> String {
self.file_id.to_owned()
}
pub async fn receive(&self, sink: StreamSink<Vec<u8>>) -> anyhow::Result<()> {
let Some(rx) = self.binary_rx.lock().await.take() else {
return Err(anyhow::anyhow!("File receiver listened to"));
};
let mut rx = crate::util::bytes::buffer_receiver(rx).await;
while let Some(data) = rx.recv().await {
let _ = sink.add(data);
}
Ok(())
}
}
#[frb(mirror(PinConfig))]
pub struct _PinConfig {
pub pin: String,
pub max_tries: u8,
}
#[frb(mirror(WsServerMessage))]
pub enum _WsServerMessage {
Hello {
client: ClientInfo,
peers: Vec<ClientInfo>,
},
Join {
peer: ClientInfo,
},
Update {
peer: ClientInfo,
},
Left {
peer_id: Uuid,
},
Offer(WsServerSdpMessage),
Answer(WsServerSdpMessage),
Error {
code: u16,
},
}
#[frb(mirror(ClientInfo))]
pub struct _ClientInfo {
pub id: Uuid,
pub alias: String,
pub version: String,
pub device_model: Option<String>,
pub device_type: Option<DeviceType>,
pub token: String,
}
#[frb(mirror(ClientInfoWithoutId))]
pub struct _ClientInfoWithoutId {
pub alias: String,
pub version: String,
pub device_model: Option<String>,
pub device_type: Option<DeviceType>,
pub token: String,
}
#[frb(mirror(WsServerSdpMessage))]
pub struct _WsServerSdpMessage {
pub peer: ClientInfo,
pub session_id: String,
pub sdp: String,
}
#[frb(mirror(RTCStatus))]
pub enum _RTCStatus {
SdpExchanged,
Connected,
PinRequired,
TooManyAttempts,
Declined,
Sending,
Finished,
Error(String),
}
#[frb(mirror(RTCFileError))]
pub struct _RTCFileError {
pub file_id: String,
pub error: String,
}
#[frb(mirror(RTCSendFileResponse))]
pub struct _RTCSendFileResponse {
pub id: String,
pub success: bool,
pub error: Option<String>,
}
File diff suppressed because it is too large Load Diff
+3
View File
@@ -0,0 +1,3 @@
pub mod api;
mod frb_generated;
mod util;
+35
View File
@@ -0,0 +1,35 @@
use bytes::{Bytes, BytesMut};
use tokio::sync::mpsc;
/// Converts a stream of Bytes into a stream of Vec<u8>.
/// Also buffers the incoming data to reduce the number of
/// messages sent to the receiver.
pub(crate) async fn buffer_receiver(
mut rx_input: mpsc::Receiver<Bytes>,
) -> mpsc::Receiver<Vec<u8>> {
const BUFFER_SIZE: usize = 1024 * 1024; // 1 MB
let mut buffer = BytesMut::with_capacity(BUFFER_SIZE);
let (tx, rx) = mpsc::channel(1);
tokio::spawn(async move {
while let Some(data) = rx_input.recv().await {
buffer.extend_from_slice(&data);
if buffer.len() >= BUFFER_SIZE {
let data = buffer.to_vec();
buffer.clear();
tx.send(data).await?;
}
}
if !buffer.is_empty() {
let data = buffer.to_vec();
tx.send(data).await?;
}
Ok::<(), anyhow::Error>(())
});
rx
}
+1
View File
@@ -0,0 +1 @@
pub(crate) mod bytes;
+29
View File
@@ -0,0 +1,29 @@
# Miscellaneous
*.class
*.log
*.pyc
*.swp
.DS_Store
.atom/
.buildlog/
.history
.svn/
migrate_working_dir/
# IntelliJ related
*.iml
*.ipr
*.iws
.idea/
# The .vscode folder contains launch configuration and tasks you configure in
# VS Code which you may wish to be included in version control, so this line
# is commented out by default.
#.vscode/
# Flutter/Dart/Pub related
# Libraries should not include pubspec.lock, per https://dart.dev/guides/libraries/private-files#pubspeclock.
/pubspec.lock
**/doc/api/
.dart_tool/
build/
+1
View File
@@ -0,0 +1 @@
Please ignore this folder, which is just glue to build Rust with Flutter.
+9
View File
@@ -0,0 +1,9 @@
*.iml
.gradle
/local.properties
/.idea/workspace.xml
/.idea/libraries
.DS_Store
/build
/captures
.cxx
+56
View File
@@ -0,0 +1,56 @@
// The Android Gradle Plugin builds the native code with the Android NDK.
group 'com.flutter_rust_bridge.rust_lib_localsend_app'
version '1.0'
buildscript {
repositories {
google()
mavenCentral()
}
dependencies {
// The Android Gradle Plugin knows how to build native code with the NDK.
classpath 'com.android.tools.build:gradle:7.3.0'
}
}
rootProject.allprojects {
repositories {
google()
mavenCentral()
}
}
apply plugin: 'com.android.library'
android {
if (project.android.hasProperty("namespace")) {
namespace 'com.flutter_rust_bridge.rust_lib_localsend_app'
}
// Bumping the plugin compileSdkVersion requires all clients of this plugin
// to bump the version in their app.
compileSdkVersion 33
// Use the NDK version
// declared in /android/app/build.gradle file of the Flutter project.
// Replace it with a version number if this plugin requires a specfic NDK version.
// (e.g. ndkVersion "23.1.7779620")
ndkVersion android.ndkVersion
compileOptions {
sourceCompatibility JavaVersion.VERSION_1_8
targetCompatibility JavaVersion.VERSION_1_8
}
defaultConfig {
minSdkVersion 19
}
}
apply from: "../cargokit/gradle/plugin.gradle"
cargokit {
manifestDir = "../../rust"
libname = "rust_lib_localsend_app"
}
+1
View File
@@ -0,0 +1 @@
rootProject.name = 'rust_lib_localsend_app'
@@ -0,0 +1,3 @@
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.flutter_rust_bridge.rust_lib_localsend_app">
</manifest>
+4
View File
@@ -0,0 +1,4 @@
target
.dart_tool
*.iml
!pubspec.lock
+42
View File
@@ -0,0 +1,42 @@
/// This is copied from Cargokit (which is the official way to use it currently)
/// Details: https://fzyzcjy.github.io/flutter_rust_bridge/manual/integrate/builtin
Copyright 2022 Matej Knopp
================================================================================
MIT LICENSE
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
of the Software, and to permit persons to whom the Software is furnished to do
so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS
OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR
IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
================================================================================
APACHE LICENSE, VERSION 2.0
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
+11
View File
@@ -0,0 +1,11 @@
/// This is copied from Cargokit (which is the official way to use it currently)
/// Details: https://fzyzcjy.github.io/flutter_rust_bridge/manual/integrate/builtin
Experimental repository to provide glue for seamlessly integrating cargo build
with flutter plugins and packages.
See https://matejknopp.com/post/flutter_plugin_in_rust_with_no_prebuilt_binaries/
for a tutorial on how to use Cargokit.
Example plugin available at https://github.com/irondash/hello_rust_ffi_plugin.
+58
View File
@@ -0,0 +1,58 @@
#!/bin/sh
set -e
BASEDIR=$(dirname "$0")
# Workaround for https://github.com/dart-lang/pub/issues/4010
BASEDIR=$(cd "$BASEDIR" ; pwd -P)
# Remove XCode SDK from path. Otherwise this breaks tool compilation when building iOS project
NEW_PATH=`echo $PATH | tr ":" "\n" | grep -v "Contents/Developer/" | tr "\n" ":"`
export PATH=${NEW_PATH%?} # remove trailing :
env
# Platform name (macosx, iphoneos, iphonesimulator)
export CARGOKIT_DARWIN_PLATFORM_NAME=$PLATFORM_NAME
# Arctive architectures (arm64, armv7, x86_64), space separated.
export CARGOKIT_DARWIN_ARCHS=$ARCHS
# Current build configuration (Debug, Release)
export CARGOKIT_CONFIGURATION=$CONFIGURATION
# Path to directory containing Cargo.toml.
export CARGOKIT_MANIFEST_DIR=$PODS_TARGET_SRCROOT/$1
# Temporary directory for build artifacts.
export CARGOKIT_TARGET_TEMP_DIR=$TARGET_TEMP_DIR
# Output directory for final artifacts.
export CARGOKIT_OUTPUT_DIR=$PODS_CONFIGURATION_BUILD_DIR/$PRODUCT_NAME
# Directory to store built tool artifacts.
export CARGOKIT_TOOL_TEMP_DIR=$TARGET_TEMP_DIR/build_tool
# Directory inside root project. Not necessarily the top level directory of root project.
export CARGOKIT_ROOT_PROJECT_DIR=$SRCROOT
FLUTTER_EXPORT_BUILD_ENVIRONMENT=(
"$PODS_ROOT/../Flutter/ephemeral/flutter_export_environment.sh" # macOS
"$PODS_ROOT/../Flutter/flutter_export_environment.sh" # iOS
)
for path in "${FLUTTER_EXPORT_BUILD_ENVIRONMENT[@]}"
do
if [[ -f "$path" ]]; then
source "$path"
fi
done
sh "$BASEDIR/run_build_tool.sh" build-pod "$@"
# Make a symlink from built framework to phony file, which will be used as input to
# build script. This should force rebuild (podspec currently doesn't support alwaysOutOfDate
# attribute on custom build phase)
ln -fs "$OBJROOT/XCBuildData/build.db" "${BUILT_PRODUCTS_DIR}/cargokit_phony"
ln -fs "${BUILT_PRODUCTS_DIR}/${EXECUTABLE_PATH}" "${BUILT_PRODUCTS_DIR}/cargokit_phony_out"
@@ -0,0 +1,5 @@
/// This is copied from Cargokit (which is the official way to use it currently)
/// Details: https://fzyzcjy.github.io/flutter_rust_bridge/manual/integrate/builtin
A sample command-line application with an entrypoint in `bin/`, library code
in `lib/`, and example unit test in `test/`.
@@ -0,0 +1,34 @@
# This is copied from Cargokit (which is the official way to use it currently)
# Details: https://fzyzcjy.github.io/flutter_rust_bridge/manual/integrate/builtin
# This file configures the static analysis results for your project (errors,
# warnings, and lints).
#
# This enables the 'recommended' set of lints from `package:lints`.
# This set helps identify many issues that may lead to problems when running
# or consuming Dart code, and enforces writing Dart using a single, idiomatic
# style and format.
#
# If you want a smaller set of lints you can change this to specify
# 'package:lints/core.yaml'. These are just the most critical lints
# (the recommended set includes the core lints).
# The core lints are also what is used by pub.dev for scoring packages.
include: package:lints/recommended.yaml
# Uncomment the following section to specify additional rules.
linter:
rules:
- prefer_relative_imports
- directives_ordering
# analyzer:
# exclude:
# - path/to/excluded/files/**
# For more information about the core and recommended set of lints, see
# https://dart.dev/go/core-lints
# For additional information about configuring this file, see
# https://dart.dev/guides/language/analysis-options
@@ -0,0 +1,8 @@
/// This is copied from Cargokit (which is the official way to use it currently)
/// Details: https://fzyzcjy.github.io/flutter_rust_bridge/manual/integrate/builtin
import 'package:build_tool/build_tool.dart' as build_tool;
void main(List<String> arguments) {
build_tool.runMain(arguments);
}
@@ -0,0 +1,8 @@
/// This is copied from Cargokit (which is the official way to use it currently)
/// Details: https://fzyzcjy.github.io/flutter_rust_bridge/manual/integrate/builtin
import 'src/build_tool.dart' as build_tool;
Future<void> runMain(List<String> args) async {
return build_tool.runMain(args);
}
@@ -0,0 +1,195 @@
/// This is copied from Cargokit (which is the official way to use it currently)
/// Details: https://fzyzcjy.github.io/flutter_rust_bridge/manual/integrate/builtin
import 'dart:io';
import 'dart:isolate';
import 'dart:math' as math;
import 'package:collection/collection.dart';
import 'package:path/path.dart' as path;
import 'package:version/version.dart';
import 'target.dart';
import 'util.dart';
class AndroidEnvironment {
AndroidEnvironment({
required this.sdkPath,
required this.ndkVersion,
required this.minSdkVersion,
required this.targetTempDir,
required this.target,
});
static void clangLinkerWrapper(List<String> args) {
final clang = Platform.environment['_CARGOKIT_NDK_LINK_CLANG'];
if (clang == null) {
throw Exception(
"cargo-ndk rustc linker: didn't find _CARGOKIT_NDK_LINK_CLANG env var");
}
final target = Platform.environment['_CARGOKIT_NDK_LINK_TARGET'];
if (target == null) {
throw Exception(
"cargo-ndk rustc linker: didn't find _CARGOKIT_NDK_LINK_TARGET env var");
}
runCommand(clang, [
target,
...args,
]);
}
/// Full path to Android SDK.
final String sdkPath;
/// Full version of Android NDK.
final String ndkVersion;
/// Minimum supported SDK version.
final int minSdkVersion;
/// Target directory for build artifacts.
final String targetTempDir;
/// Target being built.
final Target target;
bool ndkIsInstalled() {
final ndkPath = path.join(sdkPath, 'ndk', ndkVersion);
final ndkPackageXml = File(path.join(ndkPath, 'package.xml'));
return ndkPackageXml.existsSync();
}
void installNdk({
required String javaHome,
}) {
final sdkManagerExtension = Platform.isWindows ? '.bat' : '';
final sdkManager = path.join(
sdkPath,
'cmdline-tools',
'latest',
'bin',
'sdkmanager$sdkManagerExtension',
);
log.info('Installing NDK $ndkVersion');
runCommand(sdkManager, [
'--install',
'ndk;$ndkVersion',
], environment: {
'JAVA_HOME': javaHome,
});
}
Future<Map<String, String>> buildEnvironment() async {
final hostArch = Platform.isMacOS
? "darwin-x86_64"
: (Platform.isLinux ? "linux-x86_64" : "windows-x86_64");
final ndkPath = path.join(sdkPath, 'ndk', ndkVersion);
final toolchainPath = path.join(
ndkPath,
'toolchains',
'llvm',
'prebuilt',
hostArch,
'bin',
);
final minSdkVersion =
math.max(target.androidMinSdkVersion!, this.minSdkVersion);
final exe = Platform.isWindows ? '.exe' : '';
final arKey = 'AR_${target.rust}';
final arValue = ['${target.rust}-ar', 'llvm-ar', 'llvm-ar.exe']
.map((e) => path.join(toolchainPath, e))
.firstWhereOrNull((element) => File(element).existsSync());
if (arValue == null) {
throw Exception('Failed to find ar for $target in $toolchainPath');
}
final targetArg = '--target=${target.rust}$minSdkVersion';
final ccKey = 'CC_${target.rust}';
final ccValue = path.join(toolchainPath, 'clang$exe');
final cfFlagsKey = 'CFLAGS_${target.rust}';
final cFlagsValue = targetArg;
final cxxKey = 'CXX_${target.rust}';
final cxxValue = path.join(toolchainPath, 'clang++$exe');
final cxxFlagsKey = 'CXXFLAGS_${target.rust}';
final cxxFlagsValue = targetArg;
final linkerKey =
'cargo_target_${target.rust.replaceAll('-', '_')}_linker'.toUpperCase();
final ranlibKey = 'RANLIB_${target.rust}';
final ranlibValue = path.join(toolchainPath, 'llvm-ranlib$exe');
final ndkVersionParsed = Version.parse(ndkVersion);
final rustFlagsKey = 'CARGO_ENCODED_RUSTFLAGS';
final rustFlagsValue = _libGccWorkaround(targetTempDir, ndkVersionParsed);
final runRustTool =
Platform.isWindows ? 'run_build_tool.cmd' : 'run_build_tool.sh';
final packagePath = (await Isolate.resolvePackageUri(
Uri.parse('package:build_tool/buildtool.dart')))!
.toFilePath();
final selfPath = path.canonicalize(path.join(
packagePath,
'..',
'..',
'..',
runRustTool,
));
// Make sure that run_build_tool is working properly even initially launched directly
// through dart run.
final toolTempDir =
Platform.environment['CARGOKIT_TOOL_TEMP_DIR'] ?? targetTempDir;
return {
arKey: arValue,
ccKey: ccValue,
cfFlagsKey: cFlagsValue,
cxxKey: cxxValue,
cxxFlagsKey: cxxFlagsValue,
ranlibKey: ranlibValue,
rustFlagsKey: rustFlagsValue,
linkerKey: selfPath,
// Recognized by main() so we know when we're acting as a wrapper
'_CARGOKIT_NDK_LINK_TARGET': targetArg,
'_CARGOKIT_NDK_LINK_CLANG': ccValue,
'CARGOKIT_TOOL_TEMP_DIR': toolTempDir,
};
}
// Workaround for libgcc missing in NDK23, inspired by cargo-ndk
String _libGccWorkaround(String buildDir, Version ndkVersion) {
final workaroundDir = path.join(
buildDir,
'cargokit',
'libgcc_workaround',
'${ndkVersion.major}',
);
Directory(workaroundDir).createSync(recursive: true);
if (ndkVersion.major >= 23) {
File(path.join(workaroundDir, 'libgcc.a'))
.writeAsStringSync('INPUT(-lunwind)');
} else {
// Other way around, untested, forward libgcc.a from libunwind once Rust
// gets updated for NDK23+.
File(path.join(workaroundDir, 'libunwind.a'))
.writeAsStringSync('INPUT(-lgcc)');
}
var rustFlags = Platform.environment['CARGO_ENCODED_RUSTFLAGS'] ?? '';
if (rustFlags.isNotEmpty) {
rustFlags = '$rustFlags\x1f';
}
rustFlags = '$rustFlags-L\x1f$workaroundDir';
return rustFlags;
}
}
@@ -0,0 +1,266 @@
/// This is copied from Cargokit (which is the official way to use it currently)
/// Details: https://fzyzcjy.github.io/flutter_rust_bridge/manual/integrate/builtin
import 'dart:io';
import 'package:ed25519_edwards/ed25519_edwards.dart';
import 'package:http/http.dart';
import 'package:logging/logging.dart';
import 'package:path/path.dart' as path;
import 'builder.dart';
import 'crate_hash.dart';
import 'options.dart';
import 'precompile_binaries.dart';
import 'rustup.dart';
import 'target.dart';
class Artifact {
/// File system location of the artifact.
final String path;
/// Actual file name that the artifact should have in destination folder.
final String finalFileName;
AritifactType get type {
if (finalFileName.endsWith('.dll') ||
finalFileName.endsWith('.dll.lib') ||
finalFileName.endsWith('.pdb') ||
finalFileName.endsWith('.so') ||
finalFileName.endsWith('.dylib')) {
return AritifactType.dylib;
} else if (finalFileName.endsWith('.lib') || finalFileName.endsWith('.a')) {
return AritifactType.staticlib;
} else {
throw Exception('Unknown artifact type for $finalFileName');
}
}
Artifact({
required this.path,
required this.finalFileName,
});
}
final _log = Logger('artifacts_provider');
class ArtifactProvider {
ArtifactProvider({
required this.environment,
required this.userOptions,
});
final BuildEnvironment environment;
final CargokitUserOptions userOptions;
Future<Map<Target, List<Artifact>>> getArtifacts(List<Target> targets) async {
final result = await _getPrecompiledArtifacts(targets);
final pendingTargets = List.of(targets);
pendingTargets.removeWhere((element) => result.containsKey(element));
if (pendingTargets.isEmpty) {
return result;
}
final rustup = Rustup();
for (final target in targets) {
final builder = RustBuilder(target: target, environment: environment);
builder.prepare(rustup);
_log.info('Building ${environment.crateInfo.packageName} for $target');
final targetDir = await builder.build();
// For local build accept both static and dynamic libraries.
final artifactNames = <String>{
...getArtifactNames(
target: target,
libraryName: environment.crateInfo.packageName,
aritifactType: AritifactType.dylib,
remote: false,
),
...getArtifactNames(
target: target,
libraryName: environment.crateInfo.packageName,
aritifactType: AritifactType.staticlib,
remote: false,
)
};
final artifacts = artifactNames
.map((artifactName) => Artifact(
path: path.join(targetDir, artifactName),
finalFileName: artifactName,
))
.where((element) => File(element.path).existsSync())
.toList();
result[target] = artifacts;
}
return result;
}
Future<Map<Target, List<Artifact>>> _getPrecompiledArtifacts(
List<Target> targets) async {
if (userOptions.usePrecompiledBinaries == false) {
_log.info('Precompiled binaries are disabled');
return {};
}
if (environment.crateOptions.precompiledBinaries == null) {
_log.fine('Precompiled binaries not enabled for this crate');
return {};
}
final start = Stopwatch()..start();
final crateHash = CrateHash.compute(environment.manifestDir,
tempStorage: environment.targetTempDir);
_log.fine(
'Computed crate hash $crateHash in ${start.elapsedMilliseconds}ms');
final downloadedArtifactsDir =
path.join(environment.targetTempDir, 'precompiled', crateHash);
Directory(downloadedArtifactsDir).createSync(recursive: true);
final res = <Target, List<Artifact>>{};
for (final target in targets) {
final requiredArtifacts = getArtifactNames(
target: target,
libraryName: environment.crateInfo.packageName,
remote: true,
);
final artifactsForTarget = <Artifact>[];
for (final artifact in requiredArtifacts) {
final fileName = PrecompileBinaries.fileName(target, artifact);
final downloadedPath = path.join(downloadedArtifactsDir, fileName);
if (!File(downloadedPath).existsSync()) {
final signatureFileName =
PrecompileBinaries.signatureFileName(target, artifact);
await _tryDownloadArtifacts(
crateHash: crateHash,
fileName: fileName,
signatureFileName: signatureFileName,
finalPath: downloadedPath,
);
}
if (File(downloadedPath).existsSync()) {
artifactsForTarget.add(Artifact(
path: downloadedPath,
finalFileName: artifact,
));
} else {
break;
}
}
// Only provide complete set of artifacts.
if (artifactsForTarget.length == requiredArtifacts.length) {
_log.fine('Found precompiled artifacts for $target');
res[target] = artifactsForTarget;
}
}
return res;
}
static Future<Response> _get(Uri url, {Map<String, String>? headers}) async {
int attempt = 0;
const maxAttempts = 10;
while (true) {
try {
return await get(url, headers: headers);
} on SocketException catch (e) {
// Try to detect reset by peer error and retry.
if (attempt++ < maxAttempts &&
(e.osError?.errorCode == 54 || e.osError?.errorCode == 10054)) {
_log.severe(
'Failed to download $url: $e, attempt $attempt of $maxAttempts, will retry...');
await Future.delayed(Duration(seconds: 1));
continue;
} else {
rethrow;
}
}
}
}
Future<void> _tryDownloadArtifacts({
required String crateHash,
required String fileName,
required String signatureFileName,
required String finalPath,
}) async {
final precompiledBinaries = environment.crateOptions.precompiledBinaries!;
final prefix = precompiledBinaries.uriPrefix;
final url = Uri.parse('$prefix$crateHash/$fileName');
final signatureUrl = Uri.parse('$prefix$crateHash/$signatureFileName');
_log.fine('Downloading signature from $signatureUrl');
final signature = await _get(signatureUrl);
if (signature.statusCode == 404) {
_log.warning(
'Precompiled binaries not available for crate hash $crateHash ($fileName)');
return;
}
if (signature.statusCode != 200) {
_log.severe(
'Failed to download signature $signatureUrl: status ${signature.statusCode}');
return;
}
_log.fine('Downloading binary from $url');
final res = await _get(url);
if (res.statusCode != 200) {
_log.severe('Failed to download binary $url: status ${res.statusCode}');
return;
}
if (verify(
precompiledBinaries.publicKey, res.bodyBytes, signature.bodyBytes)) {
File(finalPath).writeAsBytesSync(res.bodyBytes);
} else {
_log.shout('Signature verification failed! Ignoring binary.');
}
}
}
enum AritifactType {
staticlib,
dylib,
}
AritifactType artifactTypeForTarget(Target target) {
if (target.darwinPlatform != null) {
return AritifactType.staticlib;
} else {
return AritifactType.dylib;
}
}
List<String> getArtifactNames({
required Target target,
required String libraryName,
required bool remote,
AritifactType? aritifactType,
}) {
aritifactType ??= artifactTypeForTarget(target);
if (target.darwinArch != null) {
if (aritifactType == AritifactType.staticlib) {
return ['lib$libraryName.a'];
} else {
return ['lib$libraryName.dylib'];
}
} else if (target.rust.contains('-windows-')) {
if (aritifactType == AritifactType.staticlib) {
return ['$libraryName.lib'];
} else {
return [
'$libraryName.dll',
'$libraryName.dll.lib',
if (!remote) '$libraryName.pdb'
];
}
} else if (target.rust.contains('-linux-')) {
if (aritifactType == AritifactType.staticlib) {
return ['lib$libraryName.a'];
} else {
return ['lib$libraryName.so'];
}
} else {
throw Exception("Unsupported target: ${target.rust}");
}
}
@@ -0,0 +1,40 @@
/// This is copied from Cargokit (which is the official way to use it currently)
/// Details: https://fzyzcjy.github.io/flutter_rust_bridge/manual/integrate/builtin
import 'dart:io';
import 'package:path/path.dart' as path;
import 'artifacts_provider.dart';
import 'builder.dart';
import 'environment.dart';
import 'options.dart';
import 'target.dart';
class BuildCMake {
final CargokitUserOptions userOptions;
BuildCMake({required this.userOptions});
Future<void> build() async {
final targetPlatform = Environment.targetPlatform;
final target = Target.forFlutterName(Environment.targetPlatform);
if (target == null) {
throw Exception("Unknown target platform: $targetPlatform");
}
final environment = BuildEnvironment.fromEnvironment(isAndroid: false);
final provider =
ArtifactProvider(environment: environment, userOptions: userOptions);
final artifacts = await provider.getArtifacts([target]);
final libs = artifacts[target]!;
for (final lib in libs) {
if (lib.type == AritifactType.dylib) {
File(lib.path)
.copySync(path.join(Environment.outputDir, lib.finalFileName));
}
}
}
}
@@ -0,0 +1,49 @@
/// This is copied from Cargokit (which is the official way to use it currently)
/// Details: https://fzyzcjy.github.io/flutter_rust_bridge/manual/integrate/builtin
import 'dart:io';
import 'package:logging/logging.dart';
import 'package:path/path.dart' as path;
import 'artifacts_provider.dart';
import 'builder.dart';
import 'environment.dart';
import 'options.dart';
import 'target.dart';
final log = Logger('build_gradle');
class BuildGradle {
BuildGradle({required this.userOptions});
final CargokitUserOptions userOptions;
Future<void> build() async {
final targets = Environment.targetPlatforms.map((arch) {
final target = Target.forFlutterName(arch);
if (target == null) {
throw Exception(
"Unknown darwin target or platform: $arch, ${Environment.darwinPlatformName}");
}
return target;
}).toList();
final environment = BuildEnvironment.fromEnvironment(isAndroid: true);
final provider =
ArtifactProvider(environment: environment, userOptions: userOptions);
final artifacts = await provider.getArtifacts(targets);
for (final target in targets) {
final libs = artifacts[target]!;
final outputDir = path.join(Environment.outputDir, target.android!);
Directory(outputDir).createSync(recursive: true);
for (final lib in libs) {
if (lib.type == AritifactType.dylib) {
File(lib.path).copySync(path.join(outputDir, lib.finalFileName));
}
}
}
}
}
@@ -0,0 +1,89 @@
/// This is copied from Cargokit (which is the official way to use it currently)
/// Details: https://fzyzcjy.github.io/flutter_rust_bridge/manual/integrate/builtin
import 'dart:io';
import 'package:path/path.dart' as path;
import 'artifacts_provider.dart';
import 'builder.dart';
import 'environment.dart';
import 'options.dart';
import 'target.dart';
import 'util.dart';
class BuildPod {
BuildPod({required this.userOptions});
final CargokitUserOptions userOptions;
Future<void> build() async {
final targets = Environment.darwinArchs.map((arch) {
final target = Target.forDarwin(
platformName: Environment.darwinPlatformName, darwinAarch: arch);
if (target == null) {
throw Exception(
"Unknown darwin target or platform: $arch, ${Environment.darwinPlatformName}");
}
return target;
}).toList();
final environment = BuildEnvironment.fromEnvironment(isAndroid: false);
final provider =
ArtifactProvider(environment: environment, userOptions: userOptions);
final artifacts = await provider.getArtifacts(targets);
void performLipo(String targetFile, Iterable<String> sourceFiles) {
runCommand("lipo", [
'-create',
...sourceFiles,
'-output',
targetFile,
]);
}
final outputDir = Environment.outputDir;
Directory(outputDir).createSync(recursive: true);
final staticLibs = artifacts.values
.expand((element) => element)
.where((element) => element.type == AritifactType.staticlib)
.toList();
final dynamicLibs = artifacts.values
.expand((element) => element)
.where((element) => element.type == AritifactType.dylib)
.toList();
final libName = environment.crateInfo.packageName;
// If there is static lib, use it and link it with pod
if (staticLibs.isNotEmpty) {
final finalTargetFile = path.join(outputDir, "lib$libName.a");
performLipo(finalTargetFile, staticLibs.map((e) => e.path));
} else {
// Otherwise try to replace bundle dylib with our dylib
final bundlePaths = [
'$libName.framework/Versions/A/$libName',
'$libName.framework/$libName',
];
for (final bundlePath in bundlePaths) {
final targetFile = path.join(outputDir, bundlePath);
if (File(targetFile).existsSync()) {
performLipo(targetFile, dynamicLibs.map((e) => e.path));
// Replace absolute id with @rpath one so that it works properly
// when moved to Frameworks.
runCommand("install_name_tool", [
'-id',
'@rpath/$bundlePath',
targetFile,
]);
return;
}
}
throw Exception('Unable to find bundle for dynamic library');
}
}
}
@@ -0,0 +1,271 @@
/// This is copied from Cargokit (which is the official way to use it currently)
/// Details: https://fzyzcjy.github.io/flutter_rust_bridge/manual/integrate/builtin
import 'dart:io';
import 'package:args/command_runner.dart';
import 'package:ed25519_edwards/ed25519_edwards.dart';
import 'package:github/github.dart';
import 'package:hex/hex.dart';
import 'package:logging/logging.dart';
import 'android_environment.dart';
import 'build_cmake.dart';
import 'build_gradle.dart';
import 'build_pod.dart';
import 'logging.dart';
import 'options.dart';
import 'precompile_binaries.dart';
import 'target.dart';
import 'util.dart';
import 'verify_binaries.dart';
final log = Logger('build_tool');
abstract class BuildCommand extends Command {
Future<void> runBuildCommand(CargokitUserOptions options);
@override
Future<void> run() async {
final options = CargokitUserOptions.load();
if (options.verboseLogging ||
Platform.environment['CARGOKIT_VERBOSE'] == '1') {
enableVerboseLogging();
}
await runBuildCommand(options);
}
}
class BuildPodCommand extends BuildCommand {
@override
final name = 'build-pod';
@override
final description = 'Build cocoa pod library';
@override
Future<void> runBuildCommand(CargokitUserOptions options) async {
final build = BuildPod(userOptions: options);
await build.build();
}
}
class BuildGradleCommand extends BuildCommand {
@override
final name = 'build-gradle';
@override
final description = 'Build android library';
@override
Future<void> runBuildCommand(CargokitUserOptions options) async {
final build = BuildGradle(userOptions: options);
await build.build();
}
}
class BuildCMakeCommand extends BuildCommand {
@override
final name = 'build-cmake';
@override
final description = 'Build CMake library';
@override
Future<void> runBuildCommand(CargokitUserOptions options) async {
final build = BuildCMake(userOptions: options);
await build.build();
}
}
class GenKeyCommand extends Command {
@override
final name = 'gen-key';
@override
final description = 'Generate key pair for signing precompiled binaries';
@override
void run() {
final kp = generateKey();
final private = HEX.encode(kp.privateKey.bytes);
final public = HEX.encode(kp.publicKey.bytes);
print("Private Key: $private");
print("Public Key: $public");
}
}
class PrecompileBinariesCommand extends Command {
PrecompileBinariesCommand() {
argParser
..addOption(
'repository',
mandatory: true,
help: 'Github repository slug in format owner/name',
)
..addOption(
'manifest-dir',
mandatory: true,
help: 'Directory containing Cargo.toml',
)
..addMultiOption('target',
help: 'Rust target triple of artifact to build.\n'
'Can be specified multiple times or omitted in which case\n'
'all targets for current platform will be built.')
..addOption(
'android-sdk-location',
help: 'Location of Android SDK (if available)',
)
..addOption(
'android-ndk-version',
help: 'Android NDK version (if available)',
)
..addOption(
'android-min-sdk-version',
help: 'Android minimum rquired version (if available)',
)
..addOption(
'temp-dir',
help: 'Directory to store temporary build artifacts',
)
..addFlag(
"verbose",
abbr: "v",
defaultsTo: false,
help: "Enable verbose logging",
);
}
@override
final name = 'precompile-binaries';
@override
final description = 'Prebuild and upload binaries\n'
'Private key must be passed through PRIVATE_KEY environment variable. '
'Use gen_key through generate priave key.\n'
'Github token must be passed as GITHUB_TOKEN environment variable.\n';
@override
Future<void> run() async {
final verbose = argResults!['verbose'] as bool;
if (verbose) {
enableVerboseLogging();
}
final privateKeyString = Platform.environment['PRIVATE_KEY'];
if (privateKeyString == null) {
throw ArgumentError('Missing PRIVATE_KEY environment variable');
}
final githubToken = Platform.environment['GITHUB_TOKEN'];
if (githubToken == null) {
throw ArgumentError('Missing GITHUB_TOKEN environment variable');
}
final privateKey = HEX.decode(privateKeyString);
if (privateKey.length != 64) {
throw ArgumentError('Private key must be 64 bytes long');
}
final manifestDir = argResults!['manifest-dir'] as String;
if (!Directory(manifestDir).existsSync()) {
throw ArgumentError('Manifest directory does not exist: $manifestDir');
}
String? androidMinSdkVersionString =
argResults!['android-min-sdk-version'] as String?;
int? androidMinSdkVersion;
if (androidMinSdkVersionString != null) {
androidMinSdkVersion = int.tryParse(androidMinSdkVersionString);
if (androidMinSdkVersion == null) {
throw ArgumentError(
'Invalid android-min-sdk-version: $androidMinSdkVersionString');
}
}
final targetStrigns = argResults!['target'] as List<String>;
final targets = targetStrigns.map((target) {
final res = Target.forRustTriple(target);
if (res == null) {
throw ArgumentError('Invalid target: $target');
}
return res;
}).toList(growable: false);
final precompileBinaries = PrecompileBinaries(
privateKey: PrivateKey(privateKey),
githubToken: githubToken,
manifestDir: manifestDir,
repositorySlug: RepositorySlug.full(argResults!['repository'] as String),
targets: targets,
androidSdkLocation: argResults!['android-sdk-location'] as String?,
androidNdkVersion: argResults!['android-ndk-version'] as String?,
androidMinSdkVersion: androidMinSdkVersion,
tempDir: argResults!['temp-dir'] as String?,
);
await precompileBinaries.run();
}
}
class VerifyBinariesCommand extends Command {
VerifyBinariesCommand() {
argParser.addOption(
'manifest-dir',
mandatory: true,
help: 'Directory containing Cargo.toml',
);
}
@override
final name = "verify-binaries";
@override
final description = 'Verifies published binaries\n'
'Checks whether there is a binary published for each targets\n'
'and checks the signature.';
@override
Future<void> run() async {
final manifestDir = argResults!['manifest-dir'] as String;
final verifyBinaries = VerifyBinaries(
manifestDir: manifestDir,
);
await verifyBinaries.run();
}
}
Future<void> runMain(List<String> args) async {
try {
// Init logging before options are loaded
initLogging();
if (Platform.environment['_CARGOKIT_NDK_LINK_TARGET'] != null) {
return AndroidEnvironment.clangLinkerWrapper(args);
}
final runner = CommandRunner('build_tool', 'Cargokit built_tool')
..addCommand(BuildPodCommand())
..addCommand(BuildGradleCommand())
..addCommand(BuildCMakeCommand())
..addCommand(GenKeyCommand())
..addCommand(PrecompileBinariesCommand())
..addCommand(VerifyBinariesCommand());
await runner.run(args);
} on ArgumentError catch (e) {
stderr.writeln(e.toString());
exit(1);
} catch (e, s) {
log.severe(kDoubleSeparator);
log.severe('Cargokit BuildTool failed with error:');
log.severe(kSeparator);
log.severe(e);
// This tells user to install Rust, there's no need to pollute the log with
// stack trace.
if (e is! RustupNotFoundException) {
log.severe(kSeparator);
log.severe(s);
log.severe(kSeparator);
log.severe('BuildTool arguments: $args');
}
log.severe(kDoubleSeparator);
exit(1);
}
}
@@ -0,0 +1,198 @@
/// This is copied from Cargokit (which is the official way to use it currently)
/// Details: https://fzyzcjy.github.io/flutter_rust_bridge/manual/integrate/builtin
import 'package:collection/collection.dart';
import 'package:logging/logging.dart';
import 'package:path/path.dart' as path;
import 'android_environment.dart';
import 'cargo.dart';
import 'environment.dart';
import 'options.dart';
import 'rustup.dart';
import 'target.dart';
import 'util.dart';
final _log = Logger('builder');
enum BuildConfiguration {
debug,
release,
profile,
}
extension on BuildConfiguration {
bool get isDebug => this == BuildConfiguration.debug;
String get rustName => switch (this) {
BuildConfiguration.debug => 'debug',
BuildConfiguration.release => 'release',
BuildConfiguration.profile => 'release',
};
}
class BuildException implements Exception {
final String message;
BuildException(this.message);
@override
String toString() {
return 'BuildException: $message';
}
}
class BuildEnvironment {
final BuildConfiguration configuration;
final CargokitCrateOptions crateOptions;
final String targetTempDir;
final String manifestDir;
final CrateInfo crateInfo;
final bool isAndroid;
final String? androidSdkPath;
final String? androidNdkVersion;
final int? androidMinSdkVersion;
final String? javaHome;
BuildEnvironment({
required this.configuration,
required this.crateOptions,
required this.targetTempDir,
required this.manifestDir,
required this.crateInfo,
required this.isAndroid,
this.androidSdkPath,
this.androidNdkVersion,
this.androidMinSdkVersion,
this.javaHome,
});
static BuildConfiguration parseBuildConfiguration(String value) {
// XCode configuration adds the flavor to configuration name.
final firstSegment = value.split('-').first;
final buildConfiguration = BuildConfiguration.values.firstWhereOrNull(
(e) => e.name == firstSegment,
);
if (buildConfiguration == null) {
_log.warning('Unknown build configuraiton $value, will assume release');
return BuildConfiguration.release;
}
return buildConfiguration;
}
static BuildEnvironment fromEnvironment({
required bool isAndroid,
}) {
final buildConfiguration =
parseBuildConfiguration(Environment.configuration);
final manifestDir = Environment.manifestDir;
final crateOptions = CargokitCrateOptions.load(
manifestDir: manifestDir,
);
final crateInfo = CrateInfo.load(manifestDir);
return BuildEnvironment(
configuration: buildConfiguration,
crateOptions: crateOptions,
targetTempDir: Environment.targetTempDir,
manifestDir: manifestDir,
crateInfo: crateInfo,
isAndroid: isAndroid,
androidSdkPath: isAndroid ? Environment.sdkPath : null,
androidNdkVersion: isAndroid ? Environment.ndkVersion : null,
androidMinSdkVersion:
isAndroid ? int.parse(Environment.minSdkVersion) : null,
javaHome: isAndroid ? Environment.javaHome : null,
);
}
}
class RustBuilder {
final Target target;
final BuildEnvironment environment;
RustBuilder({
required this.target,
required this.environment,
});
void prepare(
Rustup rustup,
) {
final toolchain = _toolchain;
if (rustup.installedTargets(toolchain) == null) {
rustup.installToolchain(toolchain);
}
if (toolchain == 'nightly') {
rustup.installRustSrcForNightly();
}
if (!rustup.installedTargets(toolchain)!.contains(target.rust)) {
rustup.installTarget(target.rust, toolchain: toolchain);
}
}
CargoBuildOptions? get _buildOptions =>
environment.crateOptions.cargo[environment.configuration];
String get _toolchain => _buildOptions?.toolchain.name ?? 'stable';
/// Returns the path of directory containing build artifacts.
Future<String> build() async {
final extraArgs = _buildOptions?.flags ?? [];
final manifestPath = path.join(environment.manifestDir, 'Cargo.toml');
runCommand(
'rustup',
[
'run',
_toolchain,
'cargo',
'build',
...extraArgs,
'--manifest-path',
manifestPath,
'-p',
environment.crateInfo.packageName,
if (!environment.configuration.isDebug) '--release',
'--target',
target.rust,
'--target-dir',
environment.targetTempDir,
],
environment: await _buildEnvironment(),
);
return path.join(
environment.targetTempDir,
target.rust,
environment.configuration.rustName,
);
}
Future<Map<String, String>> _buildEnvironment() async {
if (target.android == null) {
return {};
} else {
final sdkPath = environment.androidSdkPath;
final ndkVersion = environment.androidNdkVersion;
final minSdkVersion = environment.androidMinSdkVersion;
if (sdkPath == null) {
throw BuildException('androidSdkPath is not set');
}
if (ndkVersion == null) {
throw BuildException('androidNdkVersion is not set');
}
if (minSdkVersion == null) {
throw BuildException('androidMinSdkVersion is not set');
}
final env = AndroidEnvironment(
sdkPath: sdkPath,
ndkVersion: ndkVersion,
minSdkVersion: minSdkVersion,
targetTempDir: environment.targetTempDir,
target: target,
);
if (!env.ndkIsInstalled() && environment.javaHome != null) {
env.installNdk(javaHome: environment.javaHome!);
}
return env.buildEnvironment();
}
}
}
@@ -0,0 +1,48 @@
/// This is copied from Cargokit (which is the official way to use it currently)
/// Details: https://fzyzcjy.github.io/flutter_rust_bridge/manual/integrate/builtin
import 'dart:io';
import 'package:path/path.dart' as path;
import 'package:toml/toml.dart';
class ManifestException {
ManifestException(this.message, {required this.fileName});
final String? fileName;
final String message;
@override
String toString() {
if (fileName != null) {
return 'Failed to parse package manifest at $fileName: $message';
} else {
return 'Failed to parse package manifest: $message';
}
}
}
class CrateInfo {
CrateInfo({required this.packageName});
final String packageName;
static CrateInfo parseManifest(String manifest, {final String? fileName}) {
final toml = TomlDocument.parse(manifest);
final package = toml.toMap()['package'];
if (package == null) {
throw ManifestException('Missing package section', fileName: fileName);
}
final name = package['name'];
if (name == null) {
throw ManifestException('Missing package name', fileName: fileName);
}
return CrateInfo(packageName: name);
}
static CrateInfo load(String manifestDir) {
final manifestFile = File(path.join(manifestDir, 'Cargo.toml'));
final manifest = manifestFile.readAsStringSync();
return parseManifest(manifest, fileName: manifestFile.path);
}
}
@@ -0,0 +1,124 @@
/// This is copied from Cargokit (which is the official way to use it currently)
/// Details: https://fzyzcjy.github.io/flutter_rust_bridge/manual/integrate/builtin
import 'dart:convert';
import 'dart:io';
import 'dart:typed_data';
import 'package:collection/collection.dart';
import 'package:convert/convert.dart';
import 'package:crypto/crypto.dart';
import 'package:path/path.dart' as path;
class CrateHash {
/// Computes a hash uniquely identifying crate content. This takes into account
/// content all all .rs files inside the src directory, as well as Cargo.toml,
/// Cargo.lock, build.rs and cargokit.yaml.
///
/// If [tempStorage] is provided, computed hash is stored in a file in that directory
/// and reused on subsequent calls if the crate content hasn't changed.
static String compute(String manifestDir, {String? tempStorage}) {
return CrateHash._(
manifestDir: manifestDir,
tempStorage: tempStorage,
)._compute();
}
CrateHash._({
required this.manifestDir,
required this.tempStorage,
});
String _compute() {
final files = getFiles();
final tempStorage = this.tempStorage;
if (tempStorage != null) {
final quickHash = _computeQuickHash(files);
final quickHashFolder = Directory(path.join(tempStorage, 'crate_hash'));
quickHashFolder.createSync(recursive: true);
final quickHashFile = File(path.join(quickHashFolder.path, quickHash));
if (quickHashFile.existsSync()) {
return quickHashFile.readAsStringSync();
}
final hash = _computeHash(files);
quickHashFile.writeAsStringSync(hash);
return hash;
} else {
return _computeHash(files);
}
}
/// Computes a quick hash based on files stat (without reading contents). This
/// is used to cache the real hash, which is slower to compute since it involves
/// reading every single file.
String _computeQuickHash(List<File> files) {
final output = AccumulatorSink<Digest>();
final input = sha256.startChunkedConversion(output);
final data = ByteData(8);
for (final file in files) {
input.add(utf8.encode(file.path));
final stat = file.statSync();
data.setUint64(0, stat.size);
input.add(data.buffer.asUint8List());
data.setUint64(0, stat.modified.millisecondsSinceEpoch);
input.add(data.buffer.asUint8List());
}
input.close();
return base64Url.encode(output.events.single.bytes);
}
String _computeHash(List<File> files) {
final output = AccumulatorSink<Digest>();
final input = sha256.startChunkedConversion(output);
void addTextFile(File file) {
// text Files are hashed by lines in case we're dealing with github checkout
// that auto-converts line endings.
final splitter = LineSplitter();
if (file.existsSync()) {
final data = file.readAsStringSync();
final lines = splitter.convert(data);
for (final line in lines) {
input.add(utf8.encode(line));
}
}
}
for (final file in files) {
addTextFile(file);
}
input.close();
final res = output.events.single;
// Truncate to 128bits.
final hash = res.bytes.sublist(0, 16);
return hex.encode(hash);
}
List<File> getFiles() {
final src = Directory(path.join(manifestDir, 'src'));
final files = src
.listSync(recursive: true, followLinks: false)
.whereType<File>()
.toList();
files.sortBy((element) => element.path);
void addFile(String relative) {
final file = File(path.join(manifestDir, relative));
if (file.existsSync()) {
files.add(file);
}
}
addFile('Cargo.toml');
addFile('Cargo.lock');
addFile('build.rs');
addFile('cargokit.yaml');
return files;
}
final String manifestDir;
final String? tempStorage;
}
@@ -0,0 +1,68 @@
/// This is copied from Cargokit (which is the official way to use it currently)
/// Details: https://fzyzcjy.github.io/flutter_rust_bridge/manual/integrate/builtin
import 'dart:io';
extension on String {
String resolveSymlink() => File(this).resolveSymbolicLinksSync();
}
class Environment {
/// Current build configuration (debug or release).
static String get configuration =>
_getEnv("CARGOKIT_CONFIGURATION").toLowerCase();
static bool get isDebug => configuration == 'debug';
static bool get isRelease => configuration == 'release';
/// Temporary directory where Rust build artifacts are placed.
static String get targetTempDir => _getEnv("CARGOKIT_TARGET_TEMP_DIR");
/// Final output directory where the build artifacts are placed.
static String get outputDir => _getEnvPath('CARGOKIT_OUTPUT_DIR');
/// Path to the crate manifest (containing Cargo.toml).
static String get manifestDir => _getEnvPath('CARGOKIT_MANIFEST_DIR');
/// Directory inside root project. Not necessarily root folder. Symlinks are
/// not resolved on purpose.
static String get rootProjectDir => _getEnv('CARGOKIT_ROOT_PROJECT_DIR');
// Pod
/// Platform name (macosx, iphoneos, iphonesimulator).
static String get darwinPlatformName =>
_getEnv("CARGOKIT_DARWIN_PLATFORM_NAME");
/// List of architectures to build for (arm64, armv7, x86_64).
static List<String> get darwinArchs =>
_getEnv("CARGOKIT_DARWIN_ARCHS").split(' ');
// Gradle
static String get minSdkVersion => _getEnv("CARGOKIT_MIN_SDK_VERSION");
static String get ndkVersion => _getEnv("CARGOKIT_NDK_VERSION");
static String get sdkPath => _getEnvPath("CARGOKIT_SDK_DIR");
static String get javaHome => _getEnvPath("CARGOKIT_JAVA_HOME");
static List<String> get targetPlatforms =>
_getEnv("CARGOKIT_TARGET_PLATFORMS").split(',');
// CMAKE
static String get targetPlatform => _getEnv("CARGOKIT_TARGET_PLATFORM");
static String _getEnv(String key) {
final res = Platform.environment[key];
if (res == null) {
throw Exception("Missing environment variable $key");
}
return res;
}
static String _getEnvPath(String key) {
final res = _getEnv(key);
if (Directory(res).existsSync()) {
return res.resolveSymlink();
} else {
return res;
}
}
}
@@ -0,0 +1,52 @@
/// This is copied from Cargokit (which is the official way to use it currently)
/// Details: https://fzyzcjy.github.io/flutter_rust_bridge/manual/integrate/builtin
import 'dart:io';
import 'package:logging/logging.dart';
const String kSeparator = "--";
const String kDoubleSeparator = "==";
bool _lastMessageWasSeparator = false;
void _log(LogRecord rec) {
final prefix = '${rec.level.name}: ';
final out = rec.level == Level.SEVERE ? stderr : stdout;
if (rec.message == kSeparator) {
if (!_lastMessageWasSeparator) {
out.write(prefix);
out.writeln('-' * 80);
_lastMessageWasSeparator = true;
}
return;
} else if (rec.message == kDoubleSeparator) {
out.write(prefix);
out.writeln('=' * 80);
_lastMessageWasSeparator = true;
return;
}
out.write(prefix);
out.writeln(rec.message);
_lastMessageWasSeparator = false;
}
void initLogging() {
Logger.root.level = Level.INFO;
Logger.root.onRecord.listen((LogRecord rec) {
final lines = rec.message.split('\n');
for (final line in lines) {
if (line.isNotEmpty || lines.length == 1 || line != lines.last) {
_log(LogRecord(
rec.level,
line,
rec.loggerName,
));
}
}
});
}
void enableVerboseLogging() {
Logger.root.level = Level.ALL;
}
@@ -0,0 +1,309 @@
/// This is copied from Cargokit (which is the official way to use it currently)
/// Details: https://fzyzcjy.github.io/flutter_rust_bridge/manual/integrate/builtin
import 'dart:io';
import 'package:collection/collection.dart';
import 'package:ed25519_edwards/ed25519_edwards.dart';
import 'package:hex/hex.dart';
import 'package:logging/logging.dart';
import 'package:path/path.dart' as path;
import 'package:source_span/source_span.dart';
import 'package:yaml/yaml.dart';
import 'builder.dart';
import 'environment.dart';
import 'rustup.dart';
final _log = Logger('options');
/// A class for exceptions that have source span information attached.
class SourceSpanException implements Exception {
// This is a getter so that subclasses can override it.
/// A message describing the exception.
String get message => _message;
final String _message;
// This is a getter so that subclasses can override it.
/// The span associated with this exception.
///
/// This may be `null` if the source location can't be determined.
SourceSpan? get span => _span;
final SourceSpan? _span;
SourceSpanException(this._message, this._span);
/// Returns a string representation of `this`.
///
/// [color] may either be a [String], a [bool], or `null`. If it's a string,
/// it indicates an ANSI terminal color escape that should be used to
/// highlight the span's text. If it's `true`, it indicates that the text
/// should be highlighted using the default color. If it's `false` or `null`,
/// it indicates that the text shouldn't be highlighted.
@override
String toString({Object? color}) {
if (span == null) return message;
return 'Error on ${span!.message(message, color: color)}';
}
}
enum Toolchain {
stable,
beta,
nightly,
}
class CargoBuildOptions {
final Toolchain toolchain;
final List<String> flags;
CargoBuildOptions({
required this.toolchain,
required this.flags,
});
static Toolchain _toolchainFromNode(YamlNode node) {
if (node case YamlScalar(value: String name)) {
final toolchain =
Toolchain.values.firstWhereOrNull((element) => element.name == name);
if (toolchain != null) {
return toolchain;
}
}
throw SourceSpanException(
'Unknown toolchain. Must be one of ${Toolchain.values.map((e) => e.name)}.',
node.span);
}
static CargoBuildOptions parse(YamlNode node) {
if (node is! YamlMap) {
throw SourceSpanException('Cargo options must be a map', node.span);
}
Toolchain toolchain = Toolchain.stable;
List<String> flags = [];
for (final MapEntry(:key, :value) in node.nodes.entries) {
if (key case YamlScalar(value: 'toolchain')) {
toolchain = _toolchainFromNode(value);
} else if (key case YamlScalar(value: 'extra_flags')) {
if (value case YamlList(nodes: List<YamlNode> list)) {
if (list.every((element) {
if (element case YamlScalar(value: String _)) {
return true;
}
return false;
})) {
flags = list.map((e) => e.value as String).toList();
continue;
}
}
throw SourceSpanException(
'Extra flags must be a list of strings', value.span);
} else {
throw SourceSpanException(
'Unknown cargo option type. Must be "toolchain" or "extra_flags".',
key.span);
}
}
return CargoBuildOptions(toolchain: toolchain, flags: flags);
}
}
extension on YamlMap {
/// Map that extracts keys so that we can do map case check on them.
Map<dynamic, YamlNode> get valueMap =>
nodes.map((key, value) => MapEntry(key.value, value));
}
class PrecompiledBinaries {
final String uriPrefix;
final PublicKey publicKey;
PrecompiledBinaries({
required this.uriPrefix,
required this.publicKey,
});
static PublicKey _publicKeyFromHex(String key, SourceSpan? span) {
final bytes = HEX.decode(key);
if (bytes.length != 32) {
throw SourceSpanException(
'Invalid public key. Must be 32 bytes long.', span);
}
return PublicKey(bytes);
}
static PrecompiledBinaries parse(YamlNode node) {
if (node case YamlMap(valueMap: Map<dynamic, YamlNode> map)) {
if (map
case {
'url_prefix': YamlNode urlPrefixNode,
'public_key': YamlNode publicKeyNode,
}) {
final urlPrefix = switch (urlPrefixNode) {
YamlScalar(value: String urlPrefix) => urlPrefix,
_ => throw SourceSpanException(
'Invalid URL prefix value.', urlPrefixNode.span),
};
final publicKey = switch (publicKeyNode) {
YamlScalar(value: String publicKey) =>
_publicKeyFromHex(publicKey, publicKeyNode.span),
_ => throw SourceSpanException(
'Invalid public key value.', publicKeyNode.span),
};
return PrecompiledBinaries(
uriPrefix: urlPrefix,
publicKey: publicKey,
);
}
}
throw SourceSpanException(
'Invalid precompiled binaries value. '
'Expected Map with "url_prefix" and "public_key".',
node.span);
}
}
/// Cargokit options specified for Rust crate.
class CargokitCrateOptions {
CargokitCrateOptions({
this.cargo = const {},
this.precompiledBinaries,
});
final Map<BuildConfiguration, CargoBuildOptions> cargo;
final PrecompiledBinaries? precompiledBinaries;
static CargokitCrateOptions parse(YamlNode node) {
if (node is! YamlMap) {
throw SourceSpanException('Cargokit options must be a map', node.span);
}
final options = <BuildConfiguration, CargoBuildOptions>{};
PrecompiledBinaries? precompiledBinaries;
for (final entry in node.nodes.entries) {
if (entry
case MapEntry(
key: YamlScalar(value: 'cargo'),
value: YamlNode node,
)) {
if (node is! YamlMap) {
throw SourceSpanException('Cargo options must be a map', node.span);
}
for (final MapEntry(:YamlNode key, :value) in node.nodes.entries) {
if (key case YamlScalar(value: String name)) {
final configuration = BuildConfiguration.values
.firstWhereOrNull((element) => element.name == name);
if (configuration != null) {
options[configuration] = CargoBuildOptions.parse(value);
continue;
}
}
throw SourceSpanException(
'Unknown build configuration. Must be one of ${BuildConfiguration.values.map((e) => e.name)}.',
key.span);
}
} else if (entry.key case YamlScalar(value: 'precompiled_binaries')) {
precompiledBinaries = PrecompiledBinaries.parse(entry.value);
} else {
throw SourceSpanException(
'Unknown cargokit option type. Must be "cargo" or "precompiled_binaries".',
entry.key.span);
}
}
return CargokitCrateOptions(
cargo: options,
precompiledBinaries: precompiledBinaries,
);
}
static CargokitCrateOptions load({
required String manifestDir,
}) {
final uri = Uri.file(path.join(manifestDir, "cargokit.yaml"));
final file = File.fromUri(uri);
if (file.existsSync()) {
final contents = loadYamlNode(file.readAsStringSync(), sourceUrl: uri);
return parse(contents);
} else {
return CargokitCrateOptions();
}
}
}
class CargokitUserOptions {
// When Rustup is installed always build locally unless user opts into
// using precompiled binaries.
static bool defaultUsePrecompiledBinaries() {
return Rustup.executablePath() == null;
}
CargokitUserOptions({
required this.usePrecompiledBinaries,
required this.verboseLogging,
});
CargokitUserOptions._()
: usePrecompiledBinaries = defaultUsePrecompiledBinaries(),
verboseLogging = false;
static CargokitUserOptions parse(YamlNode node) {
if (node is! YamlMap) {
throw SourceSpanException('Cargokit options must be a map', node.span);
}
bool usePrecompiledBinaries = defaultUsePrecompiledBinaries();
bool verboseLogging = false;
for (final entry in node.nodes.entries) {
if (entry.key case YamlScalar(value: 'use_precompiled_binaries')) {
if (entry.value case YamlScalar(value: bool value)) {
usePrecompiledBinaries = value;
continue;
}
throw SourceSpanException(
'Invalid value for "use_precompiled_binaries". Must be a boolean.',
entry.value.span);
} else if (entry.key case YamlScalar(value: 'verbose_logging')) {
if (entry.value case YamlScalar(value: bool value)) {
verboseLogging = value;
continue;
}
throw SourceSpanException(
'Invalid value for "verbose_logging". Must be a boolean.',
entry.value.span);
} else {
throw SourceSpanException(
'Unknown cargokit option type. Must be "use_precompiled_binaries" or "verbose_logging".',
entry.key.span);
}
}
return CargokitUserOptions(
usePrecompiledBinaries: usePrecompiledBinaries,
verboseLogging: verboseLogging,
);
}
static CargokitUserOptions load() {
String fileName = "cargokit_options.yaml";
var userProjectDir = Directory(Environment.rootProjectDir);
while (userProjectDir.parent.path != userProjectDir.path) {
final configFile = File(path.join(userProjectDir.path, fileName));
if (configFile.existsSync()) {
final contents = loadYamlNode(
configFile.readAsStringSync(),
sourceUrl: configFile.uri,
);
final res = parse(contents);
if (res.verboseLogging) {
_log.info('Found user options file at ${configFile.path}');
}
return res;
}
userProjectDir = userProjectDir.parent;
}
return CargokitUserOptions._();
}
final bool usePrecompiledBinaries;
final bool verboseLogging;
}
@@ -0,0 +1,202 @@
/// This is copied from Cargokit (which is the official way to use it currently)
/// Details: https://fzyzcjy.github.io/flutter_rust_bridge/manual/integrate/builtin
import 'dart:io';
import 'package:ed25519_edwards/ed25519_edwards.dart';
import 'package:github/github.dart';
import 'package:logging/logging.dart';
import 'package:path/path.dart' as path;
import 'artifacts_provider.dart';
import 'builder.dart';
import 'cargo.dart';
import 'crate_hash.dart';
import 'options.dart';
import 'rustup.dart';
import 'target.dart';
final _log = Logger('precompile_binaries');
class PrecompileBinaries {
PrecompileBinaries({
required this.privateKey,
required this.githubToken,
required this.repositorySlug,
required this.manifestDir,
required this.targets,
this.androidSdkLocation,
this.androidNdkVersion,
this.androidMinSdkVersion,
this.tempDir,
});
final PrivateKey privateKey;
final String githubToken;
final RepositorySlug repositorySlug;
final String manifestDir;
final List<Target> targets;
final String? androidSdkLocation;
final String? androidNdkVersion;
final int? androidMinSdkVersion;
final String? tempDir;
static String fileName(Target target, String name) {
return '${target.rust}_$name';
}
static String signatureFileName(Target target, String name) {
return '${target.rust}_$name.sig';
}
Future<void> run() async {
final crateInfo = CrateInfo.load(manifestDir);
final targets = List.of(this.targets);
if (targets.isEmpty) {
targets.addAll([
...Target.buildableTargets(),
if (androidSdkLocation != null) ...Target.androidTargets(),
]);
}
_log.info('Precompiling binaries for $targets');
final hash = CrateHash.compute(manifestDir);
_log.info('Computed crate hash: $hash');
final String tagName = 'precompiled_$hash';
final github = GitHub(auth: Authentication.withToken(githubToken));
final repo = github.repositories;
final release = await _getOrCreateRelease(
repo: repo,
tagName: tagName,
packageName: crateInfo.packageName,
hash: hash,
);
final tempDir = this.tempDir != null
? Directory(this.tempDir!)
: Directory.systemTemp.createTempSync('precompiled_');
tempDir.createSync(recursive: true);
final crateOptions = CargokitCrateOptions.load(
manifestDir: manifestDir,
);
final buildEnvironment = BuildEnvironment(
configuration: BuildConfiguration.release,
crateOptions: crateOptions,
targetTempDir: tempDir.path,
manifestDir: manifestDir,
crateInfo: crateInfo,
isAndroid: androidSdkLocation != null,
androidSdkPath: androidSdkLocation,
androidNdkVersion: androidNdkVersion,
androidMinSdkVersion: androidMinSdkVersion,
);
final rustup = Rustup();
for (final target in targets) {
final artifactNames = getArtifactNames(
target: target,
libraryName: crateInfo.packageName,
remote: true,
);
if (artifactNames.every((name) {
final fileName = PrecompileBinaries.fileName(target, name);
return (release.assets ?? []).any((e) => e.name == fileName);
})) {
_log.info("All artifacts for $target already exist - skipping");
continue;
}
_log.info('Building for $target');
final builder =
RustBuilder(target: target, environment: buildEnvironment);
builder.prepare(rustup);
final res = await builder.build();
final assets = <CreateReleaseAsset>[];
for (final name in artifactNames) {
final file = File(path.join(res, name));
if (!file.existsSync()) {
throw Exception('Missing artifact: ${file.path}');
}
final data = file.readAsBytesSync();
final create = CreateReleaseAsset(
name: PrecompileBinaries.fileName(target, name),
contentType: "application/octet-stream",
assetData: data,
);
final signature = sign(privateKey, data);
final signatureCreate = CreateReleaseAsset(
name: signatureFileName(target, name),
contentType: "application/octet-stream",
assetData: signature,
);
bool verified = verify(public(privateKey), data, signature);
if (!verified) {
throw Exception('Signature verification failed');
}
assets.add(create);
assets.add(signatureCreate);
}
_log.info('Uploading assets: ${assets.map((e) => e.name)}');
for (final asset in assets) {
// This seems to be failing on CI so do it one by one
int retryCount = 0;
while (true) {
try {
await repo.uploadReleaseAssets(release, [asset]);
break;
} on Exception catch (e) {
if (retryCount == 10) {
rethrow;
}
++retryCount;
_log.shout(
'Upload failed (attempt $retryCount, will retry): ${e.toString()}');
await Future.delayed(Duration(seconds: 2));
}
}
}
}
_log.info('Cleaning up');
tempDir.deleteSync(recursive: true);
}
Future<Release> _getOrCreateRelease({
required RepositoriesService repo,
required String tagName,
required String packageName,
required String hash,
}) async {
Release release;
try {
_log.info('Fetching release $tagName');
release = await repo.getReleaseByTagName(repositorySlug, tagName);
} on ReleaseNotFound {
_log.info('Release not found - creating release $tagName');
release = await repo.createRelease(
repositorySlug,
CreateRelease.from(
tagName: tagName,
name: 'Precompiled binaries ${hash.substring(0, 8)}',
targetCommitish: null,
isDraft: false,
isPrerelease: false,
body: 'Precompiled binaries for crate $packageName, '
'crate hash $hash.',
));
}
return release;
}
}
@@ -0,0 +1,136 @@
/// This is copied from Cargokit (which is the official way to use it currently)
/// Details: https://fzyzcjy.github.io/flutter_rust_bridge/manual/integrate/builtin
import 'dart:io';
import 'package:collection/collection.dart';
import 'package:path/path.dart' as path;
import 'util.dart';
class _Toolchain {
_Toolchain(
this.name,
this.targets,
);
final String name;
final List<String> targets;
}
class Rustup {
List<String>? installedTargets(String toolchain) {
final targets = _installedTargets(toolchain);
return targets != null ? List.unmodifiable(targets) : null;
}
void installToolchain(String toolchain) {
log.info("Installing Rust toolchain: $toolchain");
runCommand("rustup", ['toolchain', 'install', toolchain]);
_installedToolchains
.add(_Toolchain(toolchain, _getInstalledTargets(toolchain)));
}
void installTarget(
String target, {
required String toolchain,
}) {
log.info("Installing Rust target: $target");
runCommand("rustup", [
'target',
'add',
'--toolchain',
toolchain,
target,
]);
_installedTargets(toolchain)?.add(target);
}
final List<_Toolchain> _installedToolchains;
Rustup() : _installedToolchains = _getInstalledToolchains();
List<String>? _installedTargets(String toolchain) => _installedToolchains
.firstWhereOrNull(
(e) => e.name == toolchain || e.name.startsWith('$toolchain-'))
?.targets;
static List<_Toolchain> _getInstalledToolchains() {
String extractToolchainName(String line) {
// ignore (default) after toolchain name
final parts = line.split(' ');
return parts[0];
}
final res = runCommand("rustup", ['toolchain', 'list']);
// To list all non-custom toolchains, we need to filter out lines that
// don't start with "stable", "beta", or "nightly".
Pattern nonCustom = RegExp(r"^(stable|beta|nightly)");
final lines = res.stdout
.toString()
.split('\n')
.where((e) => e.isNotEmpty && e.startsWith(nonCustom))
.map(extractToolchainName)
.toList(growable: true);
return lines
.map(
(name) => _Toolchain(
name,
_getInstalledTargets(name),
),
)
.toList(growable: true);
}
static List<String> _getInstalledTargets(String toolchain) {
final res = runCommand("rustup", [
'target',
'list',
'--toolchain',
toolchain,
'--installed',
]);
final lines = res.stdout
.toString()
.split('\n')
.where((e) => e.isNotEmpty)
.toList(growable: true);
return lines;
}
bool _didInstallRustSrcForNightly = false;
void installRustSrcForNightly() {
if (_didInstallRustSrcForNightly) {
return;
}
// Useful for -Z build-std
runCommand(
"rustup",
['component', 'add', 'rust-src', '--toolchain', 'nightly'],
);
_didInstallRustSrcForNightly = true;
}
static String? executablePath() {
final envPath = Platform.environment['PATH'];
final envPathSeparator = Platform.isWindows ? ';' : ':';
final home = Platform.isWindows
? Platform.environment['USERPROFILE']
: Platform.environment['HOME'];
final paths = [
if (home != null) path.join(home, '.cargo', 'bin'),
if (envPath != null) ...envPath.split(envPathSeparator),
];
for (final p in paths) {
final rustup = Platform.isWindows ? 'rustup.exe' : 'rustup';
final rustupPath = path.join(p, rustup);
if (File(rustupPath).existsSync()) {
return rustupPath;
}
}
return null;
}
}

Some files were not shown because too many files have changed in this diff Show More