This commit is contained in:
2026-02-27 21:12:56 +08:00
commit a878084cbb
233 changed files with 22988 additions and 0 deletions

61
lib/app/app.dart Normal file
View File

@@ -0,0 +1,61 @@
import 'package:flutter/material.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
import '../backend/event.dart';
import 'features/peers/controller/peers_controller.dart';
import 'features/transfer/controller/transfers_controller.dart';
import 'navigation/home_shell.dart';
import 'sync/backend_event_sync.dart';
import 'theme/app_theme.dart';
import 'theme/theme_mode_controller.dart';
class MeshDropApp extends ConsumerWidget {
const MeshDropApp({super.key});
@override
Widget build(BuildContext context, WidgetRef ref) {
final themeMode = ref.watch(themeModeControllerProvider);
ref.listen<AsyncValue<AppEvent>>(backendEventSyncProvider, (
previous,
next,
) {
next.whenData((event) {
switch (event) {
case AppEvent_PeerConnectOrUpdated(:final peer):
ref.read(peersControllerProvider.notifier).upsertPeer(peer);
case AppEvent_PeerDisconnected(:final id):
ref.read(peersControllerProvider.notifier).removePeer(id);
case AppEvent_TransferAdded(:final transfer):
ref
.read(transfersControllerProvider.notifier)
.upsertTransfer(transfer);
case AppEvent_TransferStatusChanged(:final transfer):
ref
.read(transfersControllerProvider.notifier)
.upsertTransfer(transfer);
case AppEvent_TransferRemoved(:final id):
ref.read(transfersControllerProvider.notifier).removeTransfer(id);
case AppEvent_TransferClear():
ref
.read(transfersControllerProvider.notifier)
.clearTransfersLocal();
case AppEvent_TransferProgressChanged(:final id, :final progress):
final currentBytes = progress < 0 ? 0.0 : progress;
ref
.read(transfersControllerProvider.notifier)
.updateProgress(id, currentBytes);
}
});
});
return MaterialApp(
title: 'Mesh Drop',
debugShowCheckedModeBanner: false,
themeMode: themeMode,
theme: AppTheme.lightTheme,
darkTheme: AppTheme.darkTheme,
home: const HomeShell(),
);
}
}

View File

@@ -0,0 +1,246 @@
import 'dart:io';
import 'package:desktop_drop/desktop_drop.dart';
import 'package:file_picker/file_picker.dart';
import 'package:flutter/material.dart';
import '../../../backend/api/commands.dart' as commands;
import '../../../backend/discovery/model.dart';
class SendFilesModal extends StatefulWidget {
const SendFilesModal({
super.key,
required this.peer,
required this.targetIp,
this.initialPaths = const [],
});
final Peer peer;
final String targetIp;
final List<String> initialPaths;
@override
State<SendFilesModal> createState() => _SendFilesModalState();
}
class _SendFilesModalState extends State<SendFilesModal> {
late final List<String> _paths = [...widget.initialPaths];
bool _dragging = false;
Future<void> _submit() async {
if (_paths.isEmpty) {
return;
}
final pending = List<String>.from(_paths);
if (mounted) {
Navigator.of(context).pop();
}
for (final path in pending) {
final entityType = FileSystemEntity.typeSync(path);
if (entityType == FileSystemEntityType.directory) {
commands.sendFolder(
target: widget.peer,
targetIp: widget.targetIp,
folderPath: path,
);
} else {
commands.sendFile(
target: widget.peer,
targetIp: widget.targetIp,
filePath: path,
);
}
}
}
Future<void> _pickFiles() async {
final result = await FilePicker.platform.pickFiles(allowMultiple: true);
if (result == null || !mounted) {
return;
}
final selected = result.paths.whereType<String>().where(
(p) => p.isNotEmpty,
);
setState(() {
for (final path in selected) {
if (!_paths.contains(path)) {
_paths.add(path);
}
}
});
}
Future<void> _pickFolder() async {
final folder = await FilePicker.platform.getDirectoryPath();
if (folder == null || folder.isEmpty || !mounted) {
return;
}
setState(() {
if (!_paths.contains(folder)) {
_paths.add(folder);
}
});
}
bool get _enableDragDrop =>
Platform.isLinux || Platform.isWindows || Platform.isMacOS;
@override
Widget build(BuildContext context) {
final theme = Theme.of(context);
return AlertDialog(
title: Text('发送文件给 ${widget.peer.name}'),
content: SizedBox(
width: 640,
child: Column(
mainAxisSize: MainAxisSize.min,
children: [
if (_enableDragDrop)
DropTarget(
onDragEntered: (_) => setState(() => _dragging = true),
onDragExited: (_) => setState(() => _dragging = false),
onDragDone: (details) {
setState(() {
_dragging = false;
_paths.addAll(
details.files
.map((f) => f.path)
.where((p) => p.isNotEmpty)
.where((p) => !_paths.contains(p)),
);
});
},
child: Container(
width: double.infinity,
padding: const EdgeInsets.all(20),
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(12),
border: Border.all(
color: _dragging
? theme.colorScheme.primary
: theme.colorScheme.outlineVariant,
width: _dragging ? 2 : 1,
),
color: theme.colorScheme.surfaceContainerHighest.withValues(
alpha: 0.35,
),
),
child: Column(
children: [
Icon(
_dragging
? Icons.file_download_done_rounded
: Icons.file_upload_rounded,
size: 36,
),
const SizedBox(height: 8),
Text(_dragging ? '松手即可添加文件' : '将文件或文件夹拖到这里'),
],
),
),
)
else
Container(
width: double.infinity,
padding: const EdgeInsets.all(20),
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(12),
border: Border.all(color: theme.colorScheme.outlineVariant),
color: theme.colorScheme.surfaceContainerHighest.withValues(
alpha: 0.35,
),
),
child: const Column(
children: [
Icon(Icons.file_upload_rounded, size: 36),
SizedBox(height: 8),
],
),
),
const SizedBox(height: 12),
Row(
children: [
Expanded(
child: OutlinedButton.icon(
onPressed: _pickFiles,
icon: const Icon(Icons.attach_file_rounded),
label: const Text('选择文件'),
),
),
const SizedBox(width: 8),
Expanded(
child: OutlinedButton.icon(
onPressed: _pickFolder,
icon: const Icon(Icons.folder_open_rounded),
label: const Text('选择文件夹'),
),
),
],
),
const SizedBox(height: 12),
ConstrainedBox(
constraints: const BoxConstraints(maxHeight: 260),
child: _paths.isEmpty
? const Center(
child: Padding(
padding: EdgeInsets.symmetric(vertical: 24),
child: Text('暂无待发送文件'),
),
)
: ListView.separated(
shrinkWrap: true,
itemCount: _paths.length,
separatorBuilder: (_, _) => const Divider(height: 1),
itemBuilder: (context, index) {
final path = _paths[index];
final isDirectory =
FileSystemEntity.typeSync(path) ==
FileSystemEntityType.directory;
return ListTile(
dense: true,
leading: Icon(
isDirectory
? Icons.folder_copy_rounded
: Icons.insert_drive_file_rounded,
),
title: Text(
path.split(Platform.pathSeparator).last,
maxLines: 1,
overflow: TextOverflow.ellipsis,
),
subtitle: Text(
path,
maxLines: 1,
overflow: TextOverflow.ellipsis,
),
trailing: IconButton(
icon: const Icon(Icons.delete_outline_rounded),
onPressed: () =>
setState(() => _paths.removeAt(index)),
),
);
},
),
),
],
),
),
actions: [
TextButton(
onPressed: () => Navigator.of(context).pop(),
child: const Text('取消'),
),
FilledButton.icon(
onPressed: _paths.isEmpty ? null : _submit,
icon: const Icon(Icons.send_rounded),
label: Text('发送 (${_paths.length})'),
),
],
);
}
}

View File

@@ -0,0 +1,65 @@
import 'package:flutter/material.dart';
import '../../../backend/api/commands.dart' as commands;
import '../../../backend/discovery/model.dart';
class SendTextModal extends StatefulWidget {
const SendTextModal({super.key, required this.peer, required this.targetIp});
final Peer peer;
final String targetIp;
@override
State<SendTextModal> createState() => _SendTextModalState();
}
class _SendTextModalState extends State<SendTextModal> {
final _controller = TextEditingController();
Future<void> _submit() async {
final text = _controller.text.trim();
if (text.isEmpty) {
return;
}
if (mounted) {
Navigator.of(context).pop();
}
commands.sendText(
target: widget.peer,
targetIp: widget.targetIp,
text: text,
);
}
@override
Widget build(BuildContext context) {
return AlertDialog(
title: Text('发送文本给 ${widget.peer.name}'),
content: SizedBox(
width: 540,
child: TextField(
controller: _controller,
maxLines: 8,
minLines: 4,
decoration: const InputDecoration(
hintText: '输入你想发送的文本内容',
border: OutlineInputBorder(),
),
),
),
actions: [
TextButton(
onPressed: () => Navigator.of(context).pop(),
child: const Text('取消'),
),
FilledButton.icon(
onPressed: _submit,
icon: const Icon(Icons.send_rounded),
label: const Text('发送'),
),
],
);
}
}

View File

@@ -0,0 +1,50 @@
import 'package:riverpod_annotation/riverpod_annotation.dart';
import '../../../../backend/api/commands.dart' as commands;
import '../../../../backend/discovery/model.dart';
part 'peers_controller.g.dart';
@riverpod
class PeersController extends _$PeersController {
@override
Future<List<Peer>> build() async {
return commands.getPeers();
}
Future<void> refresh() async {
state = const AsyncLoading();
state = await AsyncValue.guard(commands.getPeers);
}
void upsertPeer(Peer peer) {
final current = state.asData?.value ?? const <Peer>[];
final index = current.indexWhere((item) => item.id == peer.id);
if (index < 0) {
state = AsyncData([...current, peer]);
return;
}
final old = current[index];
if (old == peer) {
return;
}
final next = [...current];
next[index] = peer;
state = AsyncData(next);
}
void removePeer(String id) {
final current = state.asData?.value;
if (current == null || current.isEmpty) {
return;
}
final next = current.where((item) => item.id != id).toList(growable: false);
if (next.length != current.length) {
state = AsyncData(next);
}
}
}

View File

@@ -0,0 +1,54 @@
// GENERATED CODE - DO NOT MODIFY BY HAND
part of 'peers_controller.dart';
// **************************************************************************
// RiverpodGenerator
// **************************************************************************
// GENERATED CODE - DO NOT MODIFY BY HAND
// ignore_for_file: type=lint, type=warning
@ProviderFor(PeersController)
final peersControllerProvider = PeersControllerProvider._();
final class PeersControllerProvider
extends $AsyncNotifierProvider<PeersController, List<Peer>> {
PeersControllerProvider._()
: super(
from: null,
argument: null,
retry: null,
name: r'peersControllerProvider',
isAutoDispose: true,
dependencies: null,
$allTransitiveDependencies: null,
);
@override
String debugGetCreateSourceHash() => _$peersControllerHash();
@$internal
@override
PeersController create() => PeersController();
}
String _$peersControllerHash() => r'd6d108b39274dd5de380523373f115d2e4c10e0e';
abstract class _$PeersController extends $AsyncNotifier<List<Peer>> {
FutureOr<List<Peer>> build();
@$mustCallSuper
@override
void runBuild() {
final ref = this.ref as $Ref<AsyncValue<List<Peer>>, List<Peer>>;
final element =
ref.element
as $ClassProviderElement<
AnyNotifier<AsyncValue<List<Peer>>, List<Peer>>,
AsyncValue<List<Peer>>,
Object?,
Object?
>;
element.handleCreate(ref, build);
}
}

View File

@@ -0,0 +1,73 @@
import 'package:flutter/material.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
import '../controller/peers_controller.dart';
import '../widgets/peer_card.dart';
import '../../../shared/widgets/empty_state.dart';
class PeersPage extends ConsumerWidget {
const PeersPage({super.key});
@override
Widget build(BuildContext context, WidgetRef ref) {
final peersAsync = ref.watch(peersControllerProvider);
return Scaffold(
appBar: AppBar(
title: const Text('Peers Discovery'),
actions: [
IconButton(
tooltip: '刷新',
onPressed: () =>
ref.read(peersControllerProvider.notifier).refresh(),
icon: const Icon(Icons.refresh_rounded),
),
],
),
body: peersAsync.when(
loading: () => const Center(child: CircularProgressIndicator()),
error: (error, _) => AppEmptyState(
icon: Icons.cloud_off_rounded,
title: '发现失败',
message: error.toString(),
action: FilledButton.icon(
onPressed: () =>
ref.read(peersControllerProvider.notifier).refresh(),
icon: const Icon(Icons.refresh_rounded),
label: const Text('重试'),
),
),
data: (peers) {
if (peers.isEmpty) {
return AppEmptyState(
icon: Icons.wifi_tethering,
title: '扫描中',
message: '请确认局域网连接和防火墙配置。',
);
}
final width = MediaQuery.sizeOf(context).width;
final columns = width >= 1320
? 4
: width >= 1100
? 3
: width >= 720
? 2
: 1;
return GridView.builder(
padding: const EdgeInsets.all(16),
gridDelegate: SliverGridDelegateWithFixedCrossAxisCount(
crossAxisCount: columns,
mainAxisSpacing: 12,
crossAxisSpacing: 12,
childAspectRatio: 1.36,
),
itemCount: peers.length,
itemBuilder: (context, index) => PeerCard(peer: peers[index]),
);
},
),
);
}
}

View File

@@ -0,0 +1,266 @@
import 'dart:io';
import 'package:desktop_drop/desktop_drop.dart';
import 'package:flutter/material.dart';
import '../../../../backend/api/commands.dart' as commands;
import '../../../../backend/discovery/model.dart';
import '../../modals/send_files_modal.dart';
import '../../modals/send_text_modal.dart';
class PeerCard extends StatefulWidget {
const PeerCard({super.key, required this.peer});
final Peer peer;
@override
State<PeerCard> createState() => _PeerCardState();
}
class _PeerCardState extends State<PeerCard> {
bool _dragging = false;
String? get _targetIp {
if (widget.peer.routes.isEmpty) {
return null;
}
return widget.peer.routes.values.first.ip;
}
Future<void> _openTextModal() async {
final targetIp = _targetIp;
if (targetIp == null || !mounted) {
return;
}
await showDialog<void>(
context: context,
builder: (_) => SendTextModal(peer: widget.peer, targetIp: targetIp),
);
}
Future<void> _openFilesModal(List<String> files) async {
final targetIp = _targetIp;
if (targetIp == null || !mounted) {
return;
}
await showDialog<void>(
context: context,
builder: (_) => SendFilesModal(
peer: widget.peer,
targetIp: targetIp,
initialPaths: files,
),
);
}
bool get _enableDragDrop =>
Platform.isLinux || Platform.isWindows || Platform.isMacOS;
@override
Widget build(BuildContext context) {
final theme = Theme.of(context);
final targetIp = _targetIp;
final card = Card(
clipBehavior: Clip.antiAlias,
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(18),
side: BorderSide(
color: _dragging
? theme.colorScheme.primary
: theme.colorScheme.outlineVariant,
width: _dragging ? 2 : 1,
),
),
child: Padding(
padding: const EdgeInsets.all(14),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Row(
children: [
CircleAvatar(
backgroundColor: theme.colorScheme.primaryContainer,
child: Icon(
_iconForOs(widget.peer.os),
color: theme.colorScheme.onPrimaryContainer,
),
),
const SizedBox(width: 10),
Expanded(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
widget.peer.name,
maxLines: 1,
overflow: TextOverflow.ellipsis,
style: theme.textTheme.titleMedium,
),
Text(
targetIp ?? '无路由',
style: theme.textTheme.bodySmall?.copyWith(
color: theme.colorScheme.onSurfaceVariant,
),
),
],
),
),
],
),
const SizedBox(height: 10),
Wrap(
spacing: 8,
runSpacing: 8,
children: [
Chip(
avatar: const Icon(Icons.shield_rounded, size: 16),
label: Text(widget.peer.enableTls ? 'TLS on' : 'TLS off'),
),
if (widget.peer.trustMismatch)
const Chip(
avatar: Icon(Icons.warning_amber_rounded, size: 16),
label: Text('Trust Mismatch'),
),
FutureBuilder<bool>(
future: commands.isTrusted(peerId: widget.peer.id),
builder: (context, snapshot) {
final trusted = snapshot.data ?? false;
return Chip(
avatar: Icon(
trusted
? Icons.verified_user_rounded
: Icons.gpp_maybe_rounded,
size: 16,
),
label: Text(trusted ? 'Trusted' : 'Untrusted'),
);
},
),
Chip(
avatar: const Icon(Icons.hub_rounded, size: 16),
label: Text('${widget.peer.routes.length} routes'),
),
],
),
const Spacer(),
if (_enableDragDrop && _dragging)
Container(
width: double.infinity,
padding: const EdgeInsets.symmetric(vertical: 12),
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(12),
color: theme.colorScheme.primaryContainer.withValues(
alpha: 0.55,
),
),
child: const Center(child: Text('释放后发送文件')),
),
Row(
children: [
Expanded(
child: FilledButton.tonalIcon(
onPressed: targetIp == null ? null : _openTextModal,
icon: const Icon(Icons.chat_bubble_rounded),
label: const Text('文本'),
),
),
const SizedBox(width: 8),
Expanded(
child: FilledButton.icon(
onPressed: targetIp == null
? null
: () => _openFilesModal(const []),
icon: const Icon(Icons.upload_file_rounded),
label: const Text('文件/文件夹'),
),
),
],
),
const SizedBox(height: 8),
FutureBuilder<bool>(
future: commands.isTrusted(peerId: widget.peer.id),
builder: (context, snapshot) {
final trusted = snapshot.data ?? false;
return SizedBox(
width: double.infinity,
child: OutlinedButton.icon(
onPressed: () async {
if (trusted) {
await commands.untrustPeer(peerId: widget.peer.id);
} else {
await commands.trustPeer(peerId: widget.peer.id);
}
if (mounted) {
setState(() {});
}
},
icon: Icon(
trusted
? Icons.verified_user_rounded
: Icons.gpp_maybe_rounded,
),
label: Text(trusted ? '取消信任' : '设为信任设备'),
),
);
},
),
if (targetIp == null)
Padding(
padding: const EdgeInsets.only(top: 8),
child: Text(
'该设备暂无可用传输路由',
style: theme.textTheme.bodySmall?.copyWith(
color: theme.colorScheme.error,
),
),
),
],
),
),
);
if (!_enableDragDrop) {
return card;
}
return DropTarget(
onDragEntered: (_) => setState(() => _dragging = true),
onDragExited: (_) => setState(() => _dragging = false),
onDragDone: (details) {
final files = details.files
.map((f) => f.path)
.where((e) => e.isNotEmpty)
.toList();
setState(() => _dragging = false);
if (files.isNotEmpty) {
_openFilesModal(files);
}
},
child: card,
);
}
IconData _iconForOs(String os) {
final normalized = os.toLowerCase();
if (normalized.contains('windows')) {
return Icons.laptop_windows_rounded;
}
if (normalized.contains('mac') || normalized.contains('darwin')) {
return Icons.laptop_mac_rounded;
}
if (normalized.contains('linux')) {
return Icons.computer_rounded;
}
if (normalized.contains('android')) {
return Icons.phone_android_rounded;
}
if (normalized.contains('ios') || normalized.contains('iphone')) {
return Icons.phone_iphone_rounded;
}
return Platform.isAndroid
? Icons.devices_rounded
: Icons.device_hub_rounded;
}
}

View File

@@ -0,0 +1,99 @@
import 'package:riverpod_annotation/riverpod_annotation.dart';
import '../../../../backend/api/commands.dart' as commands;
part 'settings_controller.g.dart';
class SettingsState {
const SettingsState({
required this.hostname,
required this.savePath,
required this.autoAccept,
required this.saveHistory,
required this.enableTls,
});
final String hostname;
final String savePath;
final bool autoAccept;
final bool saveHistory;
final bool enableTls;
SettingsState copyWith({
String? hostname,
String? savePath,
bool? autoAccept,
bool? saveHistory,
bool? enableTls,
}) {
return SettingsState(
hostname: hostname ?? this.hostname,
savePath: savePath ?? this.savePath,
autoAccept: autoAccept ?? this.autoAccept,
saveHistory: saveHistory ?? this.saveHistory,
enableTls: enableTls ?? this.enableTls,
);
}
}
@riverpod
class SettingsController extends _$SettingsController {
@override
Future<SettingsState> build() async {
final values = await Future.wait([
commands.getHostname(),
commands.getSavePath(),
commands.getAutoAccept(),
commands.getSaveHistory(),
commands.getEnableTls(),
]);
return SettingsState(
hostname: values[0] as String,
savePath: values[1] as String,
autoAccept: values[2] as bool,
saveHistory: values[3] as bool,
enableTls: values[4] as bool,
);
}
Future<void> updateHostname(String value) async {
await commands.setHostname(hostname: value);
final current = state.value;
if (current != null) {
state = AsyncData(current.copyWith(hostname: value));
}
}
Future<void> updateSavePath(String value) async {
await commands.setSavePath(savePath: value);
final current = state.value;
if (current != null) {
state = AsyncData(current.copyWith(savePath: value));
}
}
Future<void> updateAutoAccept(bool value) async {
await commands.setAutoAccept(autoAccept: value);
final current = state.value;
if (current != null) {
state = AsyncData(current.copyWith(autoAccept: value));
}
}
Future<void> updateSaveHistory(bool value) async {
await commands.setSaveHistory(saveHistory: value);
final current = state.value;
if (current != null) {
state = AsyncData(current.copyWith(saveHistory: value));
}
}
Future<void> updateEnableTls(bool value) async {
await commands.setEnableTls(enableTls: value);
final current = state.value;
if (current != null) {
state = AsyncData(current.copyWith(enableTls: value));
}
}
}

View File

@@ -0,0 +1,55 @@
// GENERATED CODE - DO NOT MODIFY BY HAND
part of 'settings_controller.dart';
// **************************************************************************
// RiverpodGenerator
// **************************************************************************
// GENERATED CODE - DO NOT MODIFY BY HAND
// ignore_for_file: type=lint, type=warning
@ProviderFor(SettingsController)
final settingsControllerProvider = SettingsControllerProvider._();
final class SettingsControllerProvider
extends $AsyncNotifierProvider<SettingsController, SettingsState> {
SettingsControllerProvider._()
: super(
from: null,
argument: null,
retry: null,
name: r'settingsControllerProvider',
isAutoDispose: true,
dependencies: null,
$allTransitiveDependencies: null,
);
@override
String debugGetCreateSourceHash() => _$settingsControllerHash();
@$internal
@override
SettingsController create() => SettingsController();
}
String _$settingsControllerHash() =>
r'9a56637cd6a41c05c9c35b78430ff9fd9f9affe6';
abstract class _$SettingsController extends $AsyncNotifier<SettingsState> {
FutureOr<SettingsState> build();
@$mustCallSuper
@override
void runBuild() {
final ref = this.ref as $Ref<AsyncValue<SettingsState>, SettingsState>;
final element =
ref.element
as $ClassProviderElement<
AnyNotifier<AsyncValue<SettingsState>, SettingsState>,
AsyncValue<SettingsState>,
Object?,
Object?
>;
element.handleCreate(ref, build);
}
}

View File

@@ -0,0 +1,161 @@
import 'package:flutter/material.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
import '../../../theme/theme_mode_controller.dart';
import '../controller/settings_controller.dart';
class SettingsPage extends ConsumerWidget {
const SettingsPage({super.key});
@override
Widget build(BuildContext context, WidgetRef ref) {
final settingsAsync = ref.watch(settingsControllerProvider);
final themeMode = ref.watch(themeModeControllerProvider);
return Scaffold(
appBar: AppBar(title: const Text('Settings')),
body: settingsAsync.when(
loading: () => const Center(child: CircularProgressIndicator()),
error: (error, _) => Center(child: Text(error.toString())),
data: (settings) {
return ListView(
padding: const EdgeInsets.all(16),
children: [
Card(
child: Column(
children: [
ListTile(
leading: const Icon(Icons.brightness_6_rounded),
title: const Text('主题模式'),
subtitle: Text(themeMode.name),
trailing: SegmentedButton<ThemeMode>(
segments: const [
ButtonSegment(
value: ThemeMode.light,
icon: Icon(Icons.light_mode_rounded),
label: Text('Light'),
),
ButtonSegment(
value: ThemeMode.dark,
icon: Icon(Icons.dark_mode_rounded),
label: Text('Dark'),
),
ButtonSegment(
value: ThemeMode.system,
icon: Icon(Icons.settings_suggest_rounded),
label: Text('System'),
),
],
selected: {themeMode},
onSelectionChanged: (selection) => ref
.read(themeModeControllerProvider.notifier)
.setThemeMode(selection.first),
),
),
],
),
),
const SizedBox(height: 12),
Card(
child: Column(
children: [
ListTile(
leading: const Icon(Icons.badge_rounded),
title: const Text('Hostname'),
subtitle: Text(settings.hostname),
trailing: IconButton(
icon: const Icon(Icons.edit_rounded),
onPressed: () => _editText(
context: context,
title: 'Hostname',
initial: settings.hostname,
onSubmit: (value) => ref
.read(settingsControllerProvider.notifier)
.updateHostname(value),
),
),
),
const Divider(height: 1),
ListTile(
leading: const Icon(Icons.folder_rounded),
title: const Text('默认保存路径'),
subtitle: Text(settings.savePath),
trailing: IconButton(
icon: const Icon(Icons.edit_rounded),
onPressed: () => _editText(
context: context,
title: '保存路径',
initial: settings.savePath,
onSubmit: (value) => ref
.read(settingsControllerProvider.notifier)
.updateSavePath(value),
),
),
),
const Divider(height: 1),
SwitchListTile.adaptive(
secondary: const Icon(Icons.auto_mode_rounded),
title: const Text('自动接收'),
value: settings.autoAccept,
onChanged: (v) => ref
.read(settingsControllerProvider.notifier)
.updateAutoAccept(v),
),
SwitchListTile.adaptive(
secondary: const Icon(Icons.history_rounded),
title: const Text('保存历史记录'),
value: settings.saveHistory,
onChanged: (v) => ref
.read(settingsControllerProvider.notifier)
.updateSaveHistory(v),
),
SwitchListTile.adaptive(
secondary: const Icon(Icons.shield_rounded),
title: const Text('启用 TLS'),
value: settings.enableTls,
onChanged: (v) => ref
.read(settingsControllerProvider.notifier)
.updateEnableTls(v),
),
],
),
),
],
);
},
),
);
}
Future<void> _editText({
required BuildContext context,
required String title,
required String initial,
required Future<void> Function(String value) onSubmit,
}) async {
final controller = TextEditingController(text: initial);
final confirmed = await showDialog<bool>(
context: context,
builder: (_) {
return AlertDialog(
title: Text(title),
content: TextField(controller: controller),
actions: [
TextButton(
onPressed: () => Navigator.of(context).pop(false),
child: const Text('取消'),
),
FilledButton(
onPressed: () => Navigator.of(context).pop(true),
child: const Text('保存'),
),
],
);
},
);
if (confirmed == true) {
await onSubmit(controller.text.trim());
}
}
}

View File

@@ -0,0 +1,127 @@
import 'package:riverpod_annotation/riverpod_annotation.dart';
import '../../../../backend/api/commands.dart' as commands;
import '../../../../backend/transfer/model.dart';
part 'transfers_controller.g.dart';
@riverpod
class TransfersController extends _$TransfersController {
@override
Future<List<Transfer>> build() async {
return commands.getTransfers();
}
Future<void> refresh() async {
state = const AsyncLoading();
state = await AsyncValue.guard(commands.getTransfers);
}
void updateProgress(String id, double currentBytes) {
final current = state.asData?.value;
if (current == null || current.isEmpty) {
return;
}
final normalized = currentBytes < 0 ? 0.0 : currentBytes;
var changed = false;
final next = current
.map((item) {
if (item.id != id) {
return item;
}
if ((item.progress - normalized).abs() < 0.001) {
return item;
}
changed = true;
return Transfer(
id: item.id,
createTime: item.createTime,
sender: item.sender,
senderIp: item.senderIp,
fileName: item.fileName,
fileSize: item.fileSize,
savePath: item.savePath,
status: item.status,
type: item.type,
contentType: item.contentType,
text: item.text,
errorMsg: item.errorMsg,
token: item.token,
progress: normalized,
lastReadTime: item.lastReadTime,
speed: item.speed,
);
})
.toList(growable: false);
if (changed) {
state = AsyncData(next);
}
}
void upsertTransfer(Transfer transfer) {
final current = state.asData?.value ?? const <Transfer>[];
final index = current.indexWhere((item) => item.id == transfer.id);
if (index < 0) {
state = AsyncData([...current, transfer]);
return;
}
final old = current[index];
if (old == transfer) {
return;
}
final next = [...current];
next[index] = transfer;
state = AsyncData(next);
}
void removeTransfer(String id) {
final current = state.asData?.value;
if (current == null || current.isEmpty) {
return;
}
final next = current.where((item) => item.id != id).toList(growable: false);
if (next.length != current.length) {
state = AsyncData(next);
}
}
void clearTransfersLocal() {
state = const AsyncData(<Transfer>[]);
}
Future<void> cancel(String id) async {
await commands.cancelTransfer(id: id);
}
Future<void> accept(String id, String path) async {
await commands.resolvePendingRequest(id: id, accept: true, path: path);
}
Future<void> reject(String id) async {
await commands.resolvePendingRequest(id: id, accept: false, path: '');
}
Future<void> delete(String id) async {
await commands.deleteTransfer(id: id);
}
Future<void> clearCompleted() async {
final current = state.asData?.value ?? const <Transfer>[];
final hasCompleted = current.any(
(item) => item.status is TransferStatus_Completed,
);
if (!hasCompleted) {
return;
}
await commands.clearTransfers();
}
}

View File

@@ -0,0 +1,55 @@
// GENERATED CODE - DO NOT MODIFY BY HAND
part of 'transfers_controller.dart';
// **************************************************************************
// RiverpodGenerator
// **************************************************************************
// GENERATED CODE - DO NOT MODIFY BY HAND
// ignore_for_file: type=lint, type=warning
@ProviderFor(TransfersController)
final transfersControllerProvider = TransfersControllerProvider._();
final class TransfersControllerProvider
extends $AsyncNotifierProvider<TransfersController, List<Transfer>> {
TransfersControllerProvider._()
: super(
from: null,
argument: null,
retry: null,
name: r'transfersControllerProvider',
isAutoDispose: true,
dependencies: null,
$allTransitiveDependencies: null,
);
@override
String debugGetCreateSourceHash() => _$transfersControllerHash();
@$internal
@override
TransfersController create() => TransfersController();
}
String _$transfersControllerHash() =>
r'4bb376e37746360ad323d2428d4fcfc4b1e37aa7';
abstract class _$TransfersController extends $AsyncNotifier<List<Transfer>> {
FutureOr<List<Transfer>> build();
@$mustCallSuper
@override
void runBuild() {
final ref = this.ref as $Ref<AsyncValue<List<Transfer>>, List<Transfer>>;
final element =
ref.element
as $ClassProviderElement<
AnyNotifier<AsyncValue<List<Transfer>>, List<Transfer>>,
AsyncValue<List<Transfer>>,
Object?,
Object?
>;
element.handleCreate(ref, build);
}
}

View File

@@ -0,0 +1,98 @@
import 'package:flutter/material.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
import '../../../../backend/transfer/model.dart';
import '../../../shared/widgets/empty_state.dart';
import '../../settings/controller/settings_controller.dart';
import '../controller/transfers_controller.dart';
import '../widgets/transfer_item.dart';
class TransferPage extends ConsumerWidget {
const TransferPage({super.key});
@override
Widget build(BuildContext context, WidgetRef ref) {
final transfersAsync = ref.watch(transfersControllerProvider);
return Scaffold(
appBar: AppBar(
title: const Text('Transfer Queue'),
actions: [
IconButton(
tooltip: '清理已完成',
onPressed: () =>
ref.read(transfersControllerProvider.notifier).clearCompleted(),
icon: const Icon(Icons.cleaning_services_rounded),
),
IconButton(
tooltip: '刷新',
onPressed: () =>
ref.read(transfersControllerProvider.notifier).refresh(),
icon: const Icon(Icons.refresh_rounded),
),
],
),
body: transfersAsync.when(
loading: () => const Center(child: CircularProgressIndicator()),
error: (error, _) => AppEmptyState(
icon: Icons.warning_amber_rounded,
title: '加载失败',
message: error.toString(),
),
data: (transfers) {
if (transfers.isEmpty) {
return const AppEmptyState(
icon: Icons.inbox_rounded,
title: '暂无传输记录',
message: '发起或接收一次文件后,会在这里看到记录。',
);
}
return ListView.separated(
padding: const EdgeInsets.all(16),
itemBuilder: (context, index) {
final item = transfers[index];
final isSender = item.type == TransferType.send;
final isReceiver = item.type == TransferType.receive;
final canCancel =
(isSender &&
(item.status is TransferStatus_Pending ||
item.status is TransferStatus_Active)) ||
(isReceiver && item.status is TransferStatus_Active);
return TransferItem(
transfer: item,
onCancel: canCancel
? () => ref
.read(transfersControllerProvider.notifier)
.cancel(item.id)
: null,
onAccept: isReceiver && item.status is TransferStatus_Pending
? () async {
final settings = await ref.read(
settingsControllerProvider.future,
);
await ref
.read(transfersControllerProvider.notifier)
.accept(item.id, settings.savePath);
}
: null,
onReject: isReceiver && item.status is TransferStatus_Pending
? () => ref
.read(transfersControllerProvider.notifier)
.reject(item.id)
: null,
onDelete: () => ref
.read(transfersControllerProvider.notifier)
.delete(item.id),
);
},
separatorBuilder: (_, _) => const SizedBox(height: 12),
itemCount: transfers.length,
);
},
),
);
}
}

View File

@@ -0,0 +1,282 @@
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import '../../../../backend/transfer/model.dart';
class TransferItem extends StatelessWidget {
const TransferItem({
super.key,
required this.transfer,
this.onAccept,
this.onReject,
this.onCancel,
this.onDelete,
});
final Transfer transfer;
final VoidCallback? onAccept;
final VoidCallback? onReject;
final VoidCallback? onCancel;
final VoidCallback? onDelete;
@override
Widget build(BuildContext context) {
final theme = Theme.of(context);
return Card(
child: Padding(
padding: const EdgeInsets.all(14),
child: Column(
children: [
Row(
children: [
CircleAvatar(
backgroundColor: theme.colorScheme.secondaryContainer,
child: Icon(
_iconForContentType(transfer.contentType),
color: theme.colorScheme.onSecondaryContainer,
),
),
const SizedBox(width: 10),
Expanded(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
transfer.fileName.isNotEmpty
? transfer.fileName
: '文本消息',
maxLines: 1,
overflow: TextOverflow.ellipsis,
style: theme.textTheme.titleMedium,
),
Text(
'${transfer.sender.name} · ${transfer.type.name}',
style: theme.textTheme.bodySmall?.copyWith(
color: theme.colorScheme.onSurfaceVariant,
),
),
],
),
),
_StatusChip(status: transfer.status),
],
),
const SizedBox(height: 12),
LinearProgressIndicator(
value: _progressOrNull(transfer),
color: _progressColor(theme, transfer.status),
),
const SizedBox(height: 10),
Row(
children: [
Expanded(
child: Text(
'进度 ${_progressPercent(transfer).toStringAsFixed(0)}% 大小 ${_formatSize(transfer.fileSize)} 速度 ${_formatSpeed(transfer.speed)}',
style: theme.textTheme.bodySmall,
),
),
Wrap(spacing: 8, children: _buildActions(context)),
],
),
],
),
),
);
}
List<Widget> _buildActions(BuildContext context) {
final actions = <Widget>[];
if (transfer.status is TransferStatus_Pending) {
if (onReject != null) {
actions.add(
OutlinedButton.icon(
onPressed: onReject,
icon: const Icon(Icons.close_rounded),
label: const Text('拒绝'),
),
);
}
if (onAccept != null) {
actions.add(
FilledButton.icon(
onPressed: onAccept,
icon: const Icon(Icons.check_rounded),
label: const Text('接收'),
),
);
}
return actions;
}
if ((transfer.status is TransferStatus_Active ||
transfer.status is TransferStatus_Accepted) &&
onCancel != null) {
actions.add(
OutlinedButton.icon(
onPressed: onCancel,
icon: const Icon(Icons.stop_circle_outlined),
label: const Text('取消'),
),
);
}
final canPreviewText =
transfer.type == TransferType.receive &&
transfer.contentType == ContentType.text &&
transfer.status is TransferStatus_Completed;
if (canPreviewText) {
actions.add(
IconButton(
tooltip: '复制文本',
onPressed: () async {
final messenger = ScaffoldMessenger.of(context);
await Clipboard.setData(ClipboardData(text: transfer.text));
messenger.showSnackBar(const SnackBar(content: Text('文本已复制')));
},
icon: const Icon(Icons.copy_rounded),
),
);
actions.add(
IconButton(
tooltip: '查看文本',
onPressed: () {
showDialog<void>(
context: context,
builder: (_) => AlertDialog(
title: const Text('接收文本内容'),
content: SizedBox(
width: 560,
child: SingleChildScrollView(
child: SelectableText(transfer.text),
),
),
actions: [
TextButton(
onPressed: () => Navigator.of(context).pop(),
child: const Text('关闭'),
),
],
),
);
},
icon: const Icon(Icons.visibility_rounded),
),
);
}
if ((transfer.status is TransferStatus_Completed ||
transfer.status is TransferStatus_Error ||
transfer.status is TransferStatus_Canceled) &&
onDelete != null) {
actions.add(
IconButton(
tooltip: '删除记录',
onPressed: onDelete,
icon: const Icon(Icons.delete_outline_rounded),
),
);
}
return actions;
}
IconData _iconForContentType(ContentType contentType) {
return switch (contentType) {
ContentType.file => Icons.insert_drive_file_rounded,
ContentType.folder => Icons.folder_zip_rounded,
ContentType.text => Icons.text_snippet_rounded,
};
}
double? _progressOrNull(Transfer transfer) {
if (transfer.status is TransferStatus_Pending) {
return null;
}
return _progressFraction(transfer);
}
Color _progressColor(ThemeData theme, TransferStatus status) {
return switch (status) {
TransferStatus_Completed() => theme.colorScheme.primary,
TransferStatus_Active() ||
TransferStatus_Accepted() => theme.colorScheme.tertiary,
TransferStatus_Rejected() ||
TransferStatus_Error() => theme.colorScheme.error,
TransferStatus_Canceled() => theme.colorScheme.outline,
TransferStatus_Pending() => theme.colorScheme.secondary,
};
}
String _formatSpeed(double? bytesPerSec) {
if (bytesPerSec == null || bytesPerSec <= 0) {
return '--';
}
return '${_formatSize(bytesPerSec)}/s';
}
String _formatSize(double bytes) {
if (bytes <= 0) {
return '0 B';
}
const units = ['B', 'KB', 'MB', 'GB', 'TB'];
var size = bytes;
var i = 0;
while (size >= 1024 && i < units.length - 1) {
size /= 1024;
i++;
}
final fixed = size >= 100 ? 0 : (size >= 10 ? 1 : 2);
return '${size.toStringAsFixed(fixed)} ${units[i]}';
}
double _progressedBytes(Transfer transfer) {
final current = transfer.progress;
if (current <= 0) {
return 0;
}
if (transfer.fileSize <= 0) {
return current;
}
return current.clamp(0, transfer.fileSize).toDouble();
}
double _progressFraction(Transfer transfer) {
if (transfer.fileSize <= 0) {
return 0;
}
return (_progressedBytes(transfer) / transfer.fileSize)
.clamp(0, 1)
.toDouble();
}
double _progressPercent(Transfer transfer) {
return _progressFraction(transfer) * 100;
}
}
class _StatusChip extends StatelessWidget {
const _StatusChip({required this.status});
final TransferStatus status;
@override
Widget build(BuildContext context) {
final label = switch (status) {
TransferStatus_Pending() => 'Pending',
TransferStatus_Accepted() => 'Accepted',
TransferStatus_Rejected() => 'Rejected',
TransferStatus_Completed() => 'Completed',
TransferStatus_Error() => 'Error',
TransferStatus_Canceled() => 'Canceled',
TransferStatus_Active() => 'Active',
};
return Chip(label: Text(label));
}
}

View File

@@ -0,0 +1,83 @@
import 'package:flutter/material.dart';
import '../features/peers/pages/peers_page.dart';
import '../features/settings/pages/settings_page.dart';
import '../features/transfer/pages/transfer_page.dart';
enum AppTab { peers, transfer, settings }
class HomeShell extends StatefulWidget {
const HomeShell({super.key});
@override
State<HomeShell> createState() => _HomeShellState();
}
class _HomeShellState extends State<HomeShell> {
AppTab _current = AppTab.peers;
void _onSelect(int index) {
setState(() {
_current = AppTab.values[index];
});
}
@override
Widget build(BuildContext context) {
final isWide = MediaQuery.sizeOf(context).width >= 920;
final pages = const [PeersPage(), TransferPage(), SettingsPage()];
if (isWide) {
return Scaffold(
body: Row(
children: [
NavigationRail(
selectedIndex: _current.index,
onDestinationSelected: _onSelect,
labelType: NavigationRailLabelType.all,
minWidth: 84,
destinations: const [
NavigationRailDestination(
icon: Icon(Icons.radar_rounded),
label: Text('Peers'),
),
NavigationRailDestination(
icon: Icon(Icons.sync_alt_rounded),
label: Text('Transfer'),
),
NavigationRailDestination(
icon: Icon(Icons.tune_rounded),
label: Text('Settings'),
),
],
),
const VerticalDivider(width: 1),
Expanded(child: pages[_current.index]),
],
),
);
}
return Scaffold(
body: pages[_current.index],
bottomNavigationBar: NavigationBar(
selectedIndex: _current.index,
onDestinationSelected: _onSelect,
destinations: const [
NavigationDestination(
icon: Icon(Icons.radar_rounded),
label: 'Peers',
),
NavigationDestination(
icon: Icon(Icons.sync_alt_rounded),
label: 'Transfer',
),
NavigationDestination(
icon: Icon(Icons.tune_rounded),
label: 'Settings',
),
],
),
);
}
}

View File

@@ -0,0 +1,43 @@
import 'package:flutter/material.dart';
class AppEmptyState extends StatelessWidget {
const AppEmptyState({
super.key,
required this.icon,
required this.title,
required this.message,
this.action,
});
final IconData icon;
final String title;
final String message;
final Widget? action;
@override
Widget build(BuildContext context) {
final theme = Theme.of(context);
return Center(
child: Padding(
padding: const EdgeInsets.all(24),
child: Column(
mainAxisSize: MainAxisSize.min,
children: [
Icon(icon, size: 52, color: theme.colorScheme.primary),
const SizedBox(height: 14),
Text(title, style: theme.textTheme.titleLarge),
const SizedBox(height: 8),
Text(
message,
textAlign: TextAlign.center,
style: theme.textTheme.bodyMedium?.copyWith(
color: theme.colorScheme.onSurfaceVariant,
),
),
if (action != null) ...[const SizedBox(height: 16), action!],
],
),
),
);
}
}

View File

@@ -0,0 +1,11 @@
import 'package:riverpod_annotation/riverpod_annotation.dart';
import '../../backend/api/commands.dart' as commands;
import '../../backend/event.dart';
part 'backend_event_sync.g.dart';
@Riverpod(keepAlive: true)
Stream<AppEvent> backendEventSync(Ref ref) {
return commands.createEventStream();
}

View File

@@ -0,0 +1,44 @@
// GENERATED CODE - DO NOT MODIFY BY HAND
part of 'backend_event_sync.dart';
// **************************************************************************
// RiverpodGenerator
// **************************************************************************
// GENERATED CODE - DO NOT MODIFY BY HAND
// ignore_for_file: type=lint, type=warning
@ProviderFor(backendEventSync)
final backendEventSyncProvider = BackendEventSyncProvider._();
final class BackendEventSyncProvider
extends
$FunctionalProvider<AsyncValue<AppEvent>, AppEvent, Stream<AppEvent>>
with $FutureModifier<AppEvent>, $StreamProvider<AppEvent> {
BackendEventSyncProvider._()
: super(
from: null,
argument: null,
retry: null,
name: r'backendEventSyncProvider',
isAutoDispose: false,
dependencies: null,
$allTransitiveDependencies: null,
);
@override
String debugGetCreateSourceHash() => _$backendEventSyncHash();
@$internal
@override
$StreamProviderElement<AppEvent> $createElement($ProviderPointer pointer) =>
$StreamProviderElement(pointer);
@override
Stream<AppEvent> create(Ref ref) {
return backendEventSync(ref);
}
}
String _$backendEventSyncHash() => r'98ada20a035b92e209fca4c366faf7f41f412160';

View File

@@ -0,0 +1,47 @@
import 'package:flutter/material.dart';
final class AppTheme {
const AppTheme._();
static ThemeData get lightTheme {
const seed = Color(0xFF4F46E5);
final colorScheme = ColorScheme.fromSeed(
seedColor: seed,
brightness: Brightness.light,
);
return ThemeData(
useMaterial3: true,
colorScheme: colorScheme,
scaffoldBackgroundColor: const Color(0xFFF7F8FC),
cardTheme: CardThemeData(
elevation: 0,
shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(16)),
),
chipTheme: ChipThemeData(
shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(999)),
),
);
}
static ThemeData get darkTheme {
const seed = Color(0xFF8B8BFF);
final colorScheme = ColorScheme.fromSeed(
seedColor: seed,
brightness: Brightness.dark,
);
return ThemeData(
useMaterial3: true,
colorScheme: colorScheme,
scaffoldBackgroundColor: const Color(0xFF0B1020),
cardTheme: CardThemeData(
elevation: 0,
shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(16)),
),
chipTheme: ChipThemeData(
shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(999)),
),
);
}
}

View File

@@ -0,0 +1,21 @@
import 'package:flutter/material.dart';
import 'package:riverpod_annotation/riverpod_annotation.dart';
part 'theme_mode_controller.g.dart';
@riverpod
class ThemeModeController extends _$ThemeModeController {
@override
ThemeMode build() => ThemeMode.system;
void setThemeMode(ThemeMode mode) {
state = mode;
}
void toggle() {
state = switch (state) {
ThemeMode.dark => ThemeMode.light,
ThemeMode.light || ThemeMode.system => ThemeMode.dark,
};
}
}

View File

@@ -0,0 +1,63 @@
// GENERATED CODE - DO NOT MODIFY BY HAND
part of 'theme_mode_controller.dart';
// **************************************************************************
// RiverpodGenerator
// **************************************************************************
// GENERATED CODE - DO NOT MODIFY BY HAND
// ignore_for_file: type=lint, type=warning
@ProviderFor(ThemeModeController)
final themeModeControllerProvider = ThemeModeControllerProvider._();
final class ThemeModeControllerProvider
extends $NotifierProvider<ThemeModeController, ThemeMode> {
ThemeModeControllerProvider._()
: super(
from: null,
argument: null,
retry: null,
name: r'themeModeControllerProvider',
isAutoDispose: true,
dependencies: null,
$allTransitiveDependencies: null,
);
@override
String debugGetCreateSourceHash() => _$themeModeControllerHash();
@$internal
@override
ThemeModeController create() => ThemeModeController();
/// {@macro riverpod.override_with_value}
Override overrideWithValue(ThemeMode value) {
return $ProviderOverride(
origin: this,
providerOverride: $SyncValueProvider<ThemeMode>(value),
);
}
}
String _$themeModeControllerHash() =>
r'96d7617273bf6319cb57844c94190c8514dc0b36';
abstract class _$ThemeModeController extends $Notifier<ThemeMode> {
ThemeMode build();
@$mustCallSuper
@override
void runBuild() {
final ref = this.ref as $Ref<ThemeMode, ThemeMode>;
final element =
ref.element
as $ClassProviderElement<
AnyNotifier<ThemeMode, ThemeMode>,
ThemeMode,
Object?,
Object?
>;
element.handleCreate(ref, build);
}
}

View File

@@ -0,0 +1,107 @@
// 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 '../discovery/model.dart';
import '../event.dart';
import '../frb_generated.dart';
import '../transfer/model.dart';
import 'package:flutter_rust_bridge/flutter_rust_bridge_for_generated.dart';
Stream<AppEvent> createEventStream() =>
RustLib.instance.api.crateApiCommandsCreateEventStream();
Future<String> getSavePath() =>
RustLib.instance.api.crateApiCommandsGetSavePath();
Future<void> setSavePath({required String savePath}) =>
RustLib.instance.api.crateApiCommandsSetSavePath(savePath: savePath);
Future<void> setHostname({required String hostname}) =>
RustLib.instance.api.crateApiCommandsSetHostname(hostname: hostname);
Future<String> getHostname() =>
RustLib.instance.api.crateApiCommandsGetHostname();
Future<bool> getAutoAccept() =>
RustLib.instance.api.crateApiCommandsGetAutoAccept();
Future<void> setAutoAccept({required bool autoAccept}) =>
RustLib.instance.api.crateApiCommandsSetAutoAccept(autoAccept: autoAccept);
Future<bool> getSaveHistory() =>
RustLib.instance.api.crateApiCommandsGetSaveHistory();
Future<void> setSaveHistory({required bool saveHistory}) => RustLib.instance.api
.crateApiCommandsSetSaveHistory(saveHistory: saveHistory);
Future<bool> getEnableTls() =>
RustLib.instance.api.crateApiCommandsGetEnableTls();
Future<void> setEnableTls({required bool enableTls}) =>
RustLib.instance.api.crateApiCommandsSetEnableTls(enableTls: enableTls);
Future<List<Peer>> getPeers() =>
RustLib.instance.api.crateApiCommandsGetPeers();
Future<void> sendFile({
required Peer target,
required String targetIp,
required String filePath,
}) => RustLib.instance.api.crateApiCommandsSendFile(
target: target,
targetIp: targetIp,
filePath: filePath,
);
Future<void> sendText({
required Peer target,
required String targetIp,
required String text,
}) => RustLib.instance.api.crateApiCommandsSendText(
target: target,
targetIp: targetIp,
text: text,
);
Future<void> sendFolder({
required Peer target,
required String targetIp,
required String folderPath,
}) => RustLib.instance.api.crateApiCommandsSendFolder(
target: target,
targetIp: targetIp,
folderPath: folderPath,
);
Future<List<Transfer>> getTransfers() =>
RustLib.instance.api.crateApiCommandsGetTransfers();
Future<void> resolvePendingRequest({
required String id,
required bool accept,
required String path,
}) => RustLib.instance.api.crateApiCommandsResolvePendingRequest(
id: id,
accept: accept,
path: path,
);
Future<void> cancelTransfer({required String id}) =>
RustLib.instance.api.crateApiCommandsCancelTransfer(id: id);
Future<void> deleteTransfer({required String id}) =>
RustLib.instance.api.crateApiCommandsDeleteTransfer(id: id);
Future<void> clearTransfers() =>
RustLib.instance.api.crateApiCommandsClearTransfers();
Future<bool> isTrusted({required String peerId}) =>
RustLib.instance.api.crateApiCommandsIsTrusted(peerId: peerId);
Future<void> trustPeer({required String peerId}) =>
RustLib.instance.api.crateApiCommandsTrustPeer(peerId: peerId);
Future<void> untrustPeer({required String peerId}) =>
RustLib.instance.api.crateApiCommandsUntrustPeer(peerId: peerId);

View File

@@ -0,0 +1,72 @@
// 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 '../frb_generated.dart';
import 'package:flutter_rust_bridge/flutter_rust_bridge_for_generated.dart';
class Peer {
final String id;
final String name;
final Map<String, RouteState> routes;
final int port;
final String os;
final String publicKey;
final bool trustMismatch;
final bool enableTls;
const Peer({
required this.id,
required this.name,
required this.routes,
required this.port,
required this.os,
required this.publicKey,
required this.trustMismatch,
required this.enableTls,
});
@override
int get hashCode =>
id.hashCode ^
name.hashCode ^
routes.hashCode ^
port.hashCode ^
os.hashCode ^
publicKey.hashCode ^
trustMismatch.hashCode ^
enableTls.hashCode;
@override
bool operator ==(Object other) =>
identical(this, other) ||
other is Peer &&
runtimeType == other.runtimeType &&
id == other.id &&
name == other.name &&
routes == other.routes &&
port == other.port &&
os == other.os &&
publicKey == other.publicKey &&
trustMismatch == other.trustMismatch &&
enableTls == other.enableTls;
}
class RouteState {
final String ip;
final double lastSeen;
const RouteState({required this.ip, required this.lastSeen});
@override
int get hashCode => ip.hashCode ^ lastSeen.hashCode;
@override
bool operator ==(Object other) =>
identical(this, other) ||
other is RouteState &&
runtimeType == other.runtimeType &&
ip == other.ip &&
lastSeen == other.lastSeen;
}

34
lib/backend/event.dart Normal file
View File

@@ -0,0 +1,34 @@
// 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 'discovery/model.dart';
import 'frb_generated.dart';
import 'package:flutter_rust_bridge/flutter_rust_bridge_for_generated.dart';
import 'package:freezed_annotation/freezed_annotation.dart' hide protected;
import 'transfer/model.dart';
part 'event.freezed.dart';
@freezed
sealed class AppEvent with _$AppEvent {
const AppEvent._();
const factory AppEvent.transferStatusChanged({required Transfer transfer}) =
AppEvent_TransferStatusChanged;
const factory AppEvent.transferProgressChanged({
required String id,
required double progress,
required double total,
required double speed,
}) = AppEvent_TransferProgressChanged;
const factory AppEvent.peerConnectOrUpdated({required Peer peer}) =
AppEvent_PeerConnectOrUpdated;
const factory AppEvent.peerDisconnected({required String id}) =
AppEvent_PeerDisconnected;
const factory AppEvent.transferAdded({required Transfer transfer}) =
AppEvent_TransferAdded;
const factory AppEvent.transferRemoved({required String id}) =
AppEvent_TransferRemoved;
const factory AppEvent.transferClear() = AppEvent_TransferClear;
}

View File

@@ -0,0 +1,638 @@
// GENERATED CODE - DO NOT MODIFY BY HAND
// coverage:ignore-file
// ignore_for_file: type=lint
// ignore_for_file: unused_element, deprecated_member_use, deprecated_member_use_from_same_package, use_function_type_syntax_for_parameters, unnecessary_const, avoid_init_to_null, invalid_override_different_default_values_named, prefer_expression_function_bodies, annotate_overrides, invalid_annotation_target, unnecessary_question_mark
part of 'event.dart';
// **************************************************************************
// FreezedGenerator
// **************************************************************************
// dart format off
T _$identity<T>(T value) => value;
/// @nodoc
mixin _$AppEvent {
@override
bool operator ==(Object other) {
return identical(this, other) || (other.runtimeType == runtimeType&&other is AppEvent);
}
@override
int get hashCode => runtimeType.hashCode;
@override
String toString() {
return 'AppEvent()';
}
}
/// @nodoc
class $AppEventCopyWith<$Res> {
$AppEventCopyWith(AppEvent _, $Res Function(AppEvent) __);
}
/// Adds pattern-matching-related methods to [AppEvent].
extension AppEventPatterns on AppEvent {
/// A variant of `map` that fallback to returning `orElse`.
///
/// It is equivalent to doing:
/// ```dart
/// switch (sealedClass) {
/// case final Subclass value:
/// return ...;
/// case _:
/// return orElse();
/// }
/// ```
@optionalTypeArgs TResult maybeMap<TResult extends Object?>({TResult Function( AppEvent_TransferStatusChanged value)? transferStatusChanged,TResult Function( AppEvent_TransferProgressChanged value)? transferProgressChanged,TResult Function( AppEvent_PeerConnectOrUpdated value)? peerConnectOrUpdated,TResult Function( AppEvent_PeerDisconnected value)? peerDisconnected,TResult Function( AppEvent_TransferAdded value)? transferAdded,TResult Function( AppEvent_TransferRemoved value)? transferRemoved,TResult Function( AppEvent_TransferClear value)? transferClear,required TResult orElse(),}){
final _that = this;
switch (_that) {
case AppEvent_TransferStatusChanged() when transferStatusChanged != null:
return transferStatusChanged(_that);case AppEvent_TransferProgressChanged() when transferProgressChanged != null:
return transferProgressChanged(_that);case AppEvent_PeerConnectOrUpdated() when peerConnectOrUpdated != null:
return peerConnectOrUpdated(_that);case AppEvent_PeerDisconnected() when peerDisconnected != null:
return peerDisconnected(_that);case AppEvent_TransferAdded() when transferAdded != null:
return transferAdded(_that);case AppEvent_TransferRemoved() when transferRemoved != null:
return transferRemoved(_that);case AppEvent_TransferClear() when transferClear != null:
return transferClear(_that);case _:
return orElse();
}
}
/// A `switch`-like method, using callbacks.
///
/// Callbacks receives the raw object, upcasted.
/// It is equivalent to doing:
/// ```dart
/// switch (sealedClass) {
/// case final Subclass value:
/// return ...;
/// case final Subclass2 value:
/// return ...;
/// }
/// ```
@optionalTypeArgs TResult map<TResult extends Object?>({required TResult Function( AppEvent_TransferStatusChanged value) transferStatusChanged,required TResult Function( AppEvent_TransferProgressChanged value) transferProgressChanged,required TResult Function( AppEvent_PeerConnectOrUpdated value) peerConnectOrUpdated,required TResult Function( AppEvent_PeerDisconnected value) peerDisconnected,required TResult Function( AppEvent_TransferAdded value) transferAdded,required TResult Function( AppEvent_TransferRemoved value) transferRemoved,required TResult Function( AppEvent_TransferClear value) transferClear,}){
final _that = this;
switch (_that) {
case AppEvent_TransferStatusChanged():
return transferStatusChanged(_that);case AppEvent_TransferProgressChanged():
return transferProgressChanged(_that);case AppEvent_PeerConnectOrUpdated():
return peerConnectOrUpdated(_that);case AppEvent_PeerDisconnected():
return peerDisconnected(_that);case AppEvent_TransferAdded():
return transferAdded(_that);case AppEvent_TransferRemoved():
return transferRemoved(_that);case AppEvent_TransferClear():
return transferClear(_that);}
}
/// A variant of `map` that fallback to returning `null`.
///
/// It is equivalent to doing:
/// ```dart
/// switch (sealedClass) {
/// case final Subclass value:
/// return ...;
/// case _:
/// return null;
/// }
/// ```
@optionalTypeArgs TResult? mapOrNull<TResult extends Object?>({TResult? Function( AppEvent_TransferStatusChanged value)? transferStatusChanged,TResult? Function( AppEvent_TransferProgressChanged value)? transferProgressChanged,TResult? Function( AppEvent_PeerConnectOrUpdated value)? peerConnectOrUpdated,TResult? Function( AppEvent_PeerDisconnected value)? peerDisconnected,TResult? Function( AppEvent_TransferAdded value)? transferAdded,TResult? Function( AppEvent_TransferRemoved value)? transferRemoved,TResult? Function( AppEvent_TransferClear value)? transferClear,}){
final _that = this;
switch (_that) {
case AppEvent_TransferStatusChanged() when transferStatusChanged != null:
return transferStatusChanged(_that);case AppEvent_TransferProgressChanged() when transferProgressChanged != null:
return transferProgressChanged(_that);case AppEvent_PeerConnectOrUpdated() when peerConnectOrUpdated != null:
return peerConnectOrUpdated(_that);case AppEvent_PeerDisconnected() when peerDisconnected != null:
return peerDisconnected(_that);case AppEvent_TransferAdded() when transferAdded != null:
return transferAdded(_that);case AppEvent_TransferRemoved() when transferRemoved != null:
return transferRemoved(_that);case AppEvent_TransferClear() when transferClear != null:
return transferClear(_that);case _:
return null;
}
}
/// A variant of `when` that fallback to an `orElse` callback.
///
/// It is equivalent to doing:
/// ```dart
/// switch (sealedClass) {
/// case Subclass(:final field):
/// return ...;
/// case _:
/// return orElse();
/// }
/// ```
@optionalTypeArgs TResult maybeWhen<TResult extends Object?>({TResult Function( Transfer transfer)? transferStatusChanged,TResult Function( String id, double progress, double total, double speed)? transferProgressChanged,TResult Function( Peer peer)? peerConnectOrUpdated,TResult Function( String id)? peerDisconnected,TResult Function( Transfer transfer)? transferAdded,TResult Function( String id)? transferRemoved,TResult Function()? transferClear,required TResult orElse(),}) {final _that = this;
switch (_that) {
case AppEvent_TransferStatusChanged() when transferStatusChanged != null:
return transferStatusChanged(_that.transfer);case AppEvent_TransferProgressChanged() when transferProgressChanged != null:
return transferProgressChanged(_that.id,_that.progress,_that.total,_that.speed);case AppEvent_PeerConnectOrUpdated() when peerConnectOrUpdated != null:
return peerConnectOrUpdated(_that.peer);case AppEvent_PeerDisconnected() when peerDisconnected != null:
return peerDisconnected(_that.id);case AppEvent_TransferAdded() when transferAdded != null:
return transferAdded(_that.transfer);case AppEvent_TransferRemoved() when transferRemoved != null:
return transferRemoved(_that.id);case AppEvent_TransferClear() when transferClear != null:
return transferClear();case _:
return orElse();
}
}
/// A `switch`-like method, using callbacks.
///
/// As opposed to `map`, this offers destructuring.
/// It is equivalent to doing:
/// ```dart
/// switch (sealedClass) {
/// case Subclass(:final field):
/// return ...;
/// case Subclass2(:final field2):
/// return ...;
/// }
/// ```
@optionalTypeArgs TResult when<TResult extends Object?>({required TResult Function( Transfer transfer) transferStatusChanged,required TResult Function( String id, double progress, double total, double speed) transferProgressChanged,required TResult Function( Peer peer) peerConnectOrUpdated,required TResult Function( String id) peerDisconnected,required TResult Function( Transfer transfer) transferAdded,required TResult Function( String id) transferRemoved,required TResult Function() transferClear,}) {final _that = this;
switch (_that) {
case AppEvent_TransferStatusChanged():
return transferStatusChanged(_that.transfer);case AppEvent_TransferProgressChanged():
return transferProgressChanged(_that.id,_that.progress,_that.total,_that.speed);case AppEvent_PeerConnectOrUpdated():
return peerConnectOrUpdated(_that.peer);case AppEvent_PeerDisconnected():
return peerDisconnected(_that.id);case AppEvent_TransferAdded():
return transferAdded(_that.transfer);case AppEvent_TransferRemoved():
return transferRemoved(_that.id);case AppEvent_TransferClear():
return transferClear();}
}
/// A variant of `when` that fallback to returning `null`
///
/// It is equivalent to doing:
/// ```dart
/// switch (sealedClass) {
/// case Subclass(:final field):
/// return ...;
/// case _:
/// return null;
/// }
/// ```
@optionalTypeArgs TResult? whenOrNull<TResult extends Object?>({TResult? Function( Transfer transfer)? transferStatusChanged,TResult? Function( String id, double progress, double total, double speed)? transferProgressChanged,TResult? Function( Peer peer)? peerConnectOrUpdated,TResult? Function( String id)? peerDisconnected,TResult? Function( Transfer transfer)? transferAdded,TResult? Function( String id)? transferRemoved,TResult? Function()? transferClear,}) {final _that = this;
switch (_that) {
case AppEvent_TransferStatusChanged() when transferStatusChanged != null:
return transferStatusChanged(_that.transfer);case AppEvent_TransferProgressChanged() when transferProgressChanged != null:
return transferProgressChanged(_that.id,_that.progress,_that.total,_that.speed);case AppEvent_PeerConnectOrUpdated() when peerConnectOrUpdated != null:
return peerConnectOrUpdated(_that.peer);case AppEvent_PeerDisconnected() when peerDisconnected != null:
return peerDisconnected(_that.id);case AppEvent_TransferAdded() when transferAdded != null:
return transferAdded(_that.transfer);case AppEvent_TransferRemoved() when transferRemoved != null:
return transferRemoved(_that.id);case AppEvent_TransferClear() when transferClear != null:
return transferClear();case _:
return null;
}
}
}
/// @nodoc
class AppEvent_TransferStatusChanged extends AppEvent {
const AppEvent_TransferStatusChanged({required this.transfer}): super._();
final Transfer transfer;
/// Create a copy of AppEvent
/// with the given fields replaced by the non-null parameter values.
@JsonKey(includeFromJson: false, includeToJson: false)
@pragma('vm:prefer-inline')
$AppEvent_TransferStatusChangedCopyWith<AppEvent_TransferStatusChanged> get copyWith => _$AppEvent_TransferStatusChangedCopyWithImpl<AppEvent_TransferStatusChanged>(this, _$identity);
@override
bool operator ==(Object other) {
return identical(this, other) || (other.runtimeType == runtimeType&&other is AppEvent_TransferStatusChanged&&(identical(other.transfer, transfer) || other.transfer == transfer));
}
@override
int get hashCode => Object.hash(runtimeType,transfer);
@override
String toString() {
return 'AppEvent.transferStatusChanged(transfer: $transfer)';
}
}
/// @nodoc
abstract mixin class $AppEvent_TransferStatusChangedCopyWith<$Res> implements $AppEventCopyWith<$Res> {
factory $AppEvent_TransferStatusChangedCopyWith(AppEvent_TransferStatusChanged value, $Res Function(AppEvent_TransferStatusChanged) _then) = _$AppEvent_TransferStatusChangedCopyWithImpl;
@useResult
$Res call({
Transfer transfer
});
}
/// @nodoc
class _$AppEvent_TransferStatusChangedCopyWithImpl<$Res>
implements $AppEvent_TransferStatusChangedCopyWith<$Res> {
_$AppEvent_TransferStatusChangedCopyWithImpl(this._self, this._then);
final AppEvent_TransferStatusChanged _self;
final $Res Function(AppEvent_TransferStatusChanged) _then;
/// Create a copy of AppEvent
/// with the given fields replaced by the non-null parameter values.
@pragma('vm:prefer-inline') $Res call({Object? transfer = null,}) {
return _then(AppEvent_TransferStatusChanged(
transfer: null == transfer ? _self.transfer : transfer // ignore: cast_nullable_to_non_nullable
as Transfer,
));
}
}
/// @nodoc
class AppEvent_TransferProgressChanged extends AppEvent {
const AppEvent_TransferProgressChanged({required this.id, required this.progress, required this.total, required this.speed}): super._();
final String id;
final double progress;
final double total;
final double speed;
/// Create a copy of AppEvent
/// with the given fields replaced by the non-null parameter values.
@JsonKey(includeFromJson: false, includeToJson: false)
@pragma('vm:prefer-inline')
$AppEvent_TransferProgressChangedCopyWith<AppEvent_TransferProgressChanged> get copyWith => _$AppEvent_TransferProgressChangedCopyWithImpl<AppEvent_TransferProgressChanged>(this, _$identity);
@override
bool operator ==(Object other) {
return identical(this, other) || (other.runtimeType == runtimeType&&other is AppEvent_TransferProgressChanged&&(identical(other.id, id) || other.id == id)&&(identical(other.progress, progress) || other.progress == progress)&&(identical(other.total, total) || other.total == total)&&(identical(other.speed, speed) || other.speed == speed));
}
@override
int get hashCode => Object.hash(runtimeType,id,progress,total,speed);
@override
String toString() {
return 'AppEvent.transferProgressChanged(id: $id, progress: $progress, total: $total, speed: $speed)';
}
}
/// @nodoc
abstract mixin class $AppEvent_TransferProgressChangedCopyWith<$Res> implements $AppEventCopyWith<$Res> {
factory $AppEvent_TransferProgressChangedCopyWith(AppEvent_TransferProgressChanged value, $Res Function(AppEvent_TransferProgressChanged) _then) = _$AppEvent_TransferProgressChangedCopyWithImpl;
@useResult
$Res call({
String id, double progress, double total, double speed
});
}
/// @nodoc
class _$AppEvent_TransferProgressChangedCopyWithImpl<$Res>
implements $AppEvent_TransferProgressChangedCopyWith<$Res> {
_$AppEvent_TransferProgressChangedCopyWithImpl(this._self, this._then);
final AppEvent_TransferProgressChanged _self;
final $Res Function(AppEvent_TransferProgressChanged) _then;
/// Create a copy of AppEvent
/// with the given fields replaced by the non-null parameter values.
@pragma('vm:prefer-inline') $Res call({Object? id = null,Object? progress = null,Object? total = null,Object? speed = null,}) {
return _then(AppEvent_TransferProgressChanged(
id: null == id ? _self.id : id // ignore: cast_nullable_to_non_nullable
as String,progress: null == progress ? _self.progress : progress // ignore: cast_nullable_to_non_nullable
as double,total: null == total ? _self.total : total // ignore: cast_nullable_to_non_nullable
as double,speed: null == speed ? _self.speed : speed // ignore: cast_nullable_to_non_nullable
as double,
));
}
}
/// @nodoc
class AppEvent_PeerConnectOrUpdated extends AppEvent {
const AppEvent_PeerConnectOrUpdated({required this.peer}): super._();
final Peer peer;
/// Create a copy of AppEvent
/// with the given fields replaced by the non-null parameter values.
@JsonKey(includeFromJson: false, includeToJson: false)
@pragma('vm:prefer-inline')
$AppEvent_PeerConnectOrUpdatedCopyWith<AppEvent_PeerConnectOrUpdated> get copyWith => _$AppEvent_PeerConnectOrUpdatedCopyWithImpl<AppEvent_PeerConnectOrUpdated>(this, _$identity);
@override
bool operator ==(Object other) {
return identical(this, other) || (other.runtimeType == runtimeType&&other is AppEvent_PeerConnectOrUpdated&&(identical(other.peer, peer) || other.peer == peer));
}
@override
int get hashCode => Object.hash(runtimeType,peer);
@override
String toString() {
return 'AppEvent.peerConnectOrUpdated(peer: $peer)';
}
}
/// @nodoc
abstract mixin class $AppEvent_PeerConnectOrUpdatedCopyWith<$Res> implements $AppEventCopyWith<$Res> {
factory $AppEvent_PeerConnectOrUpdatedCopyWith(AppEvent_PeerConnectOrUpdated value, $Res Function(AppEvent_PeerConnectOrUpdated) _then) = _$AppEvent_PeerConnectOrUpdatedCopyWithImpl;
@useResult
$Res call({
Peer peer
});
}
/// @nodoc
class _$AppEvent_PeerConnectOrUpdatedCopyWithImpl<$Res>
implements $AppEvent_PeerConnectOrUpdatedCopyWith<$Res> {
_$AppEvent_PeerConnectOrUpdatedCopyWithImpl(this._self, this._then);
final AppEvent_PeerConnectOrUpdated _self;
final $Res Function(AppEvent_PeerConnectOrUpdated) _then;
/// Create a copy of AppEvent
/// with the given fields replaced by the non-null parameter values.
@pragma('vm:prefer-inline') $Res call({Object? peer = null,}) {
return _then(AppEvent_PeerConnectOrUpdated(
peer: null == peer ? _self.peer : peer // ignore: cast_nullable_to_non_nullable
as Peer,
));
}
}
/// @nodoc
class AppEvent_PeerDisconnected extends AppEvent {
const AppEvent_PeerDisconnected({required this.id}): super._();
final String id;
/// Create a copy of AppEvent
/// with the given fields replaced by the non-null parameter values.
@JsonKey(includeFromJson: false, includeToJson: false)
@pragma('vm:prefer-inline')
$AppEvent_PeerDisconnectedCopyWith<AppEvent_PeerDisconnected> get copyWith => _$AppEvent_PeerDisconnectedCopyWithImpl<AppEvent_PeerDisconnected>(this, _$identity);
@override
bool operator ==(Object other) {
return identical(this, other) || (other.runtimeType == runtimeType&&other is AppEvent_PeerDisconnected&&(identical(other.id, id) || other.id == id));
}
@override
int get hashCode => Object.hash(runtimeType,id);
@override
String toString() {
return 'AppEvent.peerDisconnected(id: $id)';
}
}
/// @nodoc
abstract mixin class $AppEvent_PeerDisconnectedCopyWith<$Res> implements $AppEventCopyWith<$Res> {
factory $AppEvent_PeerDisconnectedCopyWith(AppEvent_PeerDisconnected value, $Res Function(AppEvent_PeerDisconnected) _then) = _$AppEvent_PeerDisconnectedCopyWithImpl;
@useResult
$Res call({
String id
});
}
/// @nodoc
class _$AppEvent_PeerDisconnectedCopyWithImpl<$Res>
implements $AppEvent_PeerDisconnectedCopyWith<$Res> {
_$AppEvent_PeerDisconnectedCopyWithImpl(this._self, this._then);
final AppEvent_PeerDisconnected _self;
final $Res Function(AppEvent_PeerDisconnected) _then;
/// Create a copy of AppEvent
/// with the given fields replaced by the non-null parameter values.
@pragma('vm:prefer-inline') $Res call({Object? id = null,}) {
return _then(AppEvent_PeerDisconnected(
id: null == id ? _self.id : id // ignore: cast_nullable_to_non_nullable
as String,
));
}
}
/// @nodoc
class AppEvent_TransferAdded extends AppEvent {
const AppEvent_TransferAdded({required this.transfer}): super._();
final Transfer transfer;
/// Create a copy of AppEvent
/// with the given fields replaced by the non-null parameter values.
@JsonKey(includeFromJson: false, includeToJson: false)
@pragma('vm:prefer-inline')
$AppEvent_TransferAddedCopyWith<AppEvent_TransferAdded> get copyWith => _$AppEvent_TransferAddedCopyWithImpl<AppEvent_TransferAdded>(this, _$identity);
@override
bool operator ==(Object other) {
return identical(this, other) || (other.runtimeType == runtimeType&&other is AppEvent_TransferAdded&&(identical(other.transfer, transfer) || other.transfer == transfer));
}
@override
int get hashCode => Object.hash(runtimeType,transfer);
@override
String toString() {
return 'AppEvent.transferAdded(transfer: $transfer)';
}
}
/// @nodoc
abstract mixin class $AppEvent_TransferAddedCopyWith<$Res> implements $AppEventCopyWith<$Res> {
factory $AppEvent_TransferAddedCopyWith(AppEvent_TransferAdded value, $Res Function(AppEvent_TransferAdded) _then) = _$AppEvent_TransferAddedCopyWithImpl;
@useResult
$Res call({
Transfer transfer
});
}
/// @nodoc
class _$AppEvent_TransferAddedCopyWithImpl<$Res>
implements $AppEvent_TransferAddedCopyWith<$Res> {
_$AppEvent_TransferAddedCopyWithImpl(this._self, this._then);
final AppEvent_TransferAdded _self;
final $Res Function(AppEvent_TransferAdded) _then;
/// Create a copy of AppEvent
/// with the given fields replaced by the non-null parameter values.
@pragma('vm:prefer-inline') $Res call({Object? transfer = null,}) {
return _then(AppEvent_TransferAdded(
transfer: null == transfer ? _self.transfer : transfer // ignore: cast_nullable_to_non_nullable
as Transfer,
));
}
}
/// @nodoc
class AppEvent_TransferRemoved extends AppEvent {
const AppEvent_TransferRemoved({required this.id}): super._();
final String id;
/// Create a copy of AppEvent
/// with the given fields replaced by the non-null parameter values.
@JsonKey(includeFromJson: false, includeToJson: false)
@pragma('vm:prefer-inline')
$AppEvent_TransferRemovedCopyWith<AppEvent_TransferRemoved> get copyWith => _$AppEvent_TransferRemovedCopyWithImpl<AppEvent_TransferRemoved>(this, _$identity);
@override
bool operator ==(Object other) {
return identical(this, other) || (other.runtimeType == runtimeType&&other is AppEvent_TransferRemoved&&(identical(other.id, id) || other.id == id));
}
@override
int get hashCode => Object.hash(runtimeType,id);
@override
String toString() {
return 'AppEvent.transferRemoved(id: $id)';
}
}
/// @nodoc
abstract mixin class $AppEvent_TransferRemovedCopyWith<$Res> implements $AppEventCopyWith<$Res> {
factory $AppEvent_TransferRemovedCopyWith(AppEvent_TransferRemoved value, $Res Function(AppEvent_TransferRemoved) _then) = _$AppEvent_TransferRemovedCopyWithImpl;
@useResult
$Res call({
String id
});
}
/// @nodoc
class _$AppEvent_TransferRemovedCopyWithImpl<$Res>
implements $AppEvent_TransferRemovedCopyWith<$Res> {
_$AppEvent_TransferRemovedCopyWithImpl(this._self, this._then);
final AppEvent_TransferRemoved _self;
final $Res Function(AppEvent_TransferRemoved) _then;
/// Create a copy of AppEvent
/// with the given fields replaced by the non-null parameter values.
@pragma('vm:prefer-inline') $Res call({Object? id = null,}) {
return _then(AppEvent_TransferRemoved(
id: null == id ? _self.id : id // ignore: cast_nullable_to_non_nullable
as String,
));
}
}
/// @nodoc
class AppEvent_TransferClear extends AppEvent {
const AppEvent_TransferClear(): super._();
@override
bool operator ==(Object other) {
return identical(this, other) || (other.runtimeType == runtimeType&&other is AppEvent_TransferClear);
}
@override
int get hashCode => runtimeType.hashCode;
@override
String toString() {
return 'AppEvent.transferClear()';
}
}
// dart format on

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,303 @@
// 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 'api/commands.dart';
import 'dart:async';
import 'dart:convert';
import 'dart:ffi' as ffi;
import 'discovery/model.dart';
import 'event.dart';
import 'frb_generated.dart';
import 'package:flutter_rust_bridge/flutter_rust_bridge_for_generated_io.dart';
import 'transfer/model.dart';
abstract class RustLibApiImplPlatform extends BaseApiImpl<RustLibWire> {
RustLibApiImplPlatform({
required super.handler,
required super.wire,
required super.generalizedFrbRustBinding,
required super.portManager,
});
@protected
AnyhowException dco_decode_AnyhowException(dynamic raw);
@protected
Map<String, RouteState> dco_decode_Map_String_route_state_None(dynamic raw);
@protected
RustStreamSink<AppEvent> dco_decode_StreamSink_app_event_Sse(dynamic raw);
@protected
String dco_decode_String(dynamic raw);
@protected
AppEvent dco_decode_app_event(dynamic raw);
@protected
bool dco_decode_bool(dynamic raw);
@protected
Peer dco_decode_box_autoadd_peer(dynamic raw);
@protected
Transfer dco_decode_box_autoadd_transfer(dynamic raw);
@protected
CanceledBy dco_decode_canceled_by(dynamic raw);
@protected
ContentType dco_decode_content_type(dynamic raw);
@protected
double dco_decode_f_64(dynamic raw);
@protected
int dco_decode_i_32(dynamic raw);
@protected
PlatformInt64 dco_decode_i_64(dynamic raw);
@protected
List<Peer> dco_decode_list_peer(dynamic raw);
@protected
Uint8List dco_decode_list_prim_u_8_strict(dynamic raw);
@protected
List<(String, RouteState)> dco_decode_list_record_string_route_state(
dynamic raw,
);
@protected
List<Transfer> dco_decode_list_transfer(dynamic raw);
@protected
Peer dco_decode_peer(dynamic raw);
@protected
(String, RouteState) dco_decode_record_string_route_state(dynamic raw);
@protected
RouteState dco_decode_route_state(dynamic raw);
@protected
Transfer dco_decode_transfer(dynamic raw);
@protected
TransferStatus dco_decode_transfer_status(dynamic raw);
@protected
TransferType dco_decode_transfer_type(dynamic raw);
@protected
int dco_decode_u_16(dynamic raw);
@protected
int dco_decode_u_8(dynamic raw);
@protected
void dco_decode_unit(dynamic raw);
@protected
AnyhowException sse_decode_AnyhowException(SseDeserializer deserializer);
@protected
Map<String, RouteState> sse_decode_Map_String_route_state_None(
SseDeserializer deserializer,
);
@protected
RustStreamSink<AppEvent> sse_decode_StreamSink_app_event_Sse(
SseDeserializer deserializer,
);
@protected
String sse_decode_String(SseDeserializer deserializer);
@protected
AppEvent sse_decode_app_event(SseDeserializer deserializer);
@protected
bool sse_decode_bool(SseDeserializer deserializer);
@protected
Peer sse_decode_box_autoadd_peer(SseDeserializer deserializer);
@protected
Transfer sse_decode_box_autoadd_transfer(SseDeserializer deserializer);
@protected
CanceledBy sse_decode_canceled_by(SseDeserializer deserializer);
@protected
ContentType sse_decode_content_type(SseDeserializer deserializer);
@protected
double sse_decode_f_64(SseDeserializer deserializer);
@protected
int sse_decode_i_32(SseDeserializer deserializer);
@protected
PlatformInt64 sse_decode_i_64(SseDeserializer deserializer);
@protected
List<Peer> sse_decode_list_peer(SseDeserializer deserializer);
@protected
Uint8List sse_decode_list_prim_u_8_strict(SseDeserializer deserializer);
@protected
List<(String, RouteState)> sse_decode_list_record_string_route_state(
SseDeserializer deserializer,
);
@protected
List<Transfer> sse_decode_list_transfer(SseDeserializer deserializer);
@protected
Peer sse_decode_peer(SseDeserializer deserializer);
@protected
(String, RouteState) sse_decode_record_string_route_state(
SseDeserializer deserializer,
);
@protected
RouteState sse_decode_route_state(SseDeserializer deserializer);
@protected
Transfer sse_decode_transfer(SseDeserializer deserializer);
@protected
TransferStatus sse_decode_transfer_status(SseDeserializer deserializer);
@protected
TransferType sse_decode_transfer_type(SseDeserializer deserializer);
@protected
int sse_decode_u_16(SseDeserializer deserializer);
@protected
int sse_decode_u_8(SseDeserializer deserializer);
@protected
void sse_decode_unit(SseDeserializer deserializer);
@protected
void sse_encode_AnyhowException(
AnyhowException self,
SseSerializer serializer,
);
@protected
void sse_encode_Map_String_route_state_None(
Map<String, RouteState> self,
SseSerializer serializer,
);
@protected
void sse_encode_StreamSink_app_event_Sse(
RustStreamSink<AppEvent> self,
SseSerializer serializer,
);
@protected
void sse_encode_String(String self, SseSerializer serializer);
@protected
void sse_encode_app_event(AppEvent self, SseSerializer serializer);
@protected
void sse_encode_bool(bool self, SseSerializer serializer);
@protected
void sse_encode_box_autoadd_peer(Peer self, SseSerializer serializer);
@protected
void sse_encode_box_autoadd_transfer(Transfer self, SseSerializer serializer);
@protected
void sse_encode_canceled_by(CanceledBy self, SseSerializer serializer);
@protected
void sse_encode_content_type(ContentType self, SseSerializer serializer);
@protected
void sse_encode_f_64(double self, SseSerializer serializer);
@protected
void sse_encode_i_32(int self, SseSerializer serializer);
@protected
void sse_encode_i_64(PlatformInt64 self, SseSerializer serializer);
@protected
void sse_encode_list_peer(List<Peer> self, SseSerializer serializer);
@protected
void sse_encode_list_prim_u_8_strict(
Uint8List self,
SseSerializer serializer,
);
@protected
void sse_encode_list_record_string_route_state(
List<(String, RouteState)> self,
SseSerializer serializer,
);
@protected
void sse_encode_list_transfer(List<Transfer> self, SseSerializer serializer);
@protected
void sse_encode_peer(Peer self, SseSerializer serializer);
@protected
void sse_encode_record_string_route_state(
(String, RouteState) self,
SseSerializer serializer,
);
@protected
void sse_encode_route_state(RouteState self, SseSerializer serializer);
@protected
void sse_encode_transfer(Transfer self, SseSerializer serializer);
@protected
void sse_encode_transfer_status(
TransferStatus self,
SseSerializer serializer,
);
@protected
void sse_encode_transfer_type(TransferType self, SseSerializer serializer);
@protected
void sse_encode_u_16(int self, SseSerializer serializer);
@protected
void sse_encode_u_8(int self, SseSerializer serializer);
@protected
void sse_encode_unit(void 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;
}

View File

@@ -0,0 +1,303 @@
// 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 'api/commands.dart';
import 'dart:async';
import 'dart:convert';
import 'discovery/model.dart';
import 'event.dart';
import 'frb_generated.dart';
import 'package:flutter_rust_bridge/flutter_rust_bridge_for_generated_web.dart';
import 'transfer/model.dart';
abstract class RustLibApiImplPlatform extends BaseApiImpl<RustLibWire> {
RustLibApiImplPlatform({
required super.handler,
required super.wire,
required super.generalizedFrbRustBinding,
required super.portManager,
});
@protected
AnyhowException dco_decode_AnyhowException(dynamic raw);
@protected
Map<String, RouteState> dco_decode_Map_String_route_state_None(dynamic raw);
@protected
RustStreamSink<AppEvent> dco_decode_StreamSink_app_event_Sse(dynamic raw);
@protected
String dco_decode_String(dynamic raw);
@protected
AppEvent dco_decode_app_event(dynamic raw);
@protected
bool dco_decode_bool(dynamic raw);
@protected
Peer dco_decode_box_autoadd_peer(dynamic raw);
@protected
Transfer dco_decode_box_autoadd_transfer(dynamic raw);
@protected
CanceledBy dco_decode_canceled_by(dynamic raw);
@protected
ContentType dco_decode_content_type(dynamic raw);
@protected
double dco_decode_f_64(dynamic raw);
@protected
int dco_decode_i_32(dynamic raw);
@protected
PlatformInt64 dco_decode_i_64(dynamic raw);
@protected
List<Peer> dco_decode_list_peer(dynamic raw);
@protected
Uint8List dco_decode_list_prim_u_8_strict(dynamic raw);
@protected
List<(String, RouteState)> dco_decode_list_record_string_route_state(
dynamic raw,
);
@protected
List<Transfer> dco_decode_list_transfer(dynamic raw);
@protected
Peer dco_decode_peer(dynamic raw);
@protected
(String, RouteState) dco_decode_record_string_route_state(dynamic raw);
@protected
RouteState dco_decode_route_state(dynamic raw);
@protected
Transfer dco_decode_transfer(dynamic raw);
@protected
TransferStatus dco_decode_transfer_status(dynamic raw);
@protected
TransferType dco_decode_transfer_type(dynamic raw);
@protected
int dco_decode_u_16(dynamic raw);
@protected
int dco_decode_u_8(dynamic raw);
@protected
void dco_decode_unit(dynamic raw);
@protected
AnyhowException sse_decode_AnyhowException(SseDeserializer deserializer);
@protected
Map<String, RouteState> sse_decode_Map_String_route_state_None(
SseDeserializer deserializer,
);
@protected
RustStreamSink<AppEvent> sse_decode_StreamSink_app_event_Sse(
SseDeserializer deserializer,
);
@protected
String sse_decode_String(SseDeserializer deserializer);
@protected
AppEvent sse_decode_app_event(SseDeserializer deserializer);
@protected
bool sse_decode_bool(SseDeserializer deserializer);
@protected
Peer sse_decode_box_autoadd_peer(SseDeserializer deserializer);
@protected
Transfer sse_decode_box_autoadd_transfer(SseDeserializer deserializer);
@protected
CanceledBy sse_decode_canceled_by(SseDeserializer deserializer);
@protected
ContentType sse_decode_content_type(SseDeserializer deserializer);
@protected
double sse_decode_f_64(SseDeserializer deserializer);
@protected
int sse_decode_i_32(SseDeserializer deserializer);
@protected
PlatformInt64 sse_decode_i_64(SseDeserializer deserializer);
@protected
List<Peer> sse_decode_list_peer(SseDeserializer deserializer);
@protected
Uint8List sse_decode_list_prim_u_8_strict(SseDeserializer deserializer);
@protected
List<(String, RouteState)> sse_decode_list_record_string_route_state(
SseDeserializer deserializer,
);
@protected
List<Transfer> sse_decode_list_transfer(SseDeserializer deserializer);
@protected
Peer sse_decode_peer(SseDeserializer deserializer);
@protected
(String, RouteState) sse_decode_record_string_route_state(
SseDeserializer deserializer,
);
@protected
RouteState sse_decode_route_state(SseDeserializer deserializer);
@protected
Transfer sse_decode_transfer(SseDeserializer deserializer);
@protected
TransferStatus sse_decode_transfer_status(SseDeserializer deserializer);
@protected
TransferType sse_decode_transfer_type(SseDeserializer deserializer);
@protected
int sse_decode_u_16(SseDeserializer deserializer);
@protected
int sse_decode_u_8(SseDeserializer deserializer);
@protected
void sse_decode_unit(SseDeserializer deserializer);
@protected
void sse_encode_AnyhowException(
AnyhowException self,
SseSerializer serializer,
);
@protected
void sse_encode_Map_String_route_state_None(
Map<String, RouteState> self,
SseSerializer serializer,
);
@protected
void sse_encode_StreamSink_app_event_Sse(
RustStreamSink<AppEvent> self,
SseSerializer serializer,
);
@protected
void sse_encode_String(String self, SseSerializer serializer);
@protected
void sse_encode_app_event(AppEvent self, SseSerializer serializer);
@protected
void sse_encode_bool(bool self, SseSerializer serializer);
@protected
void sse_encode_box_autoadd_peer(Peer self, SseSerializer serializer);
@protected
void sse_encode_box_autoadd_transfer(Transfer self, SseSerializer serializer);
@protected
void sse_encode_canceled_by(CanceledBy self, SseSerializer serializer);
@protected
void sse_encode_content_type(ContentType self, SseSerializer serializer);
@protected
void sse_encode_f_64(double self, SseSerializer serializer);
@protected
void sse_encode_i_32(int self, SseSerializer serializer);
@protected
void sse_encode_i_64(PlatformInt64 self, SseSerializer serializer);
@protected
void sse_encode_list_peer(List<Peer> self, SseSerializer serializer);
@protected
void sse_encode_list_prim_u_8_strict(
Uint8List self,
SseSerializer serializer,
);
@protected
void sse_encode_list_record_string_route_state(
List<(String, RouteState)> self,
SseSerializer serializer,
);
@protected
void sse_encode_list_transfer(List<Transfer> self, SseSerializer serializer);
@protected
void sse_encode_peer(Peer self, SseSerializer serializer);
@protected
void sse_encode_record_string_route_state(
(String, RouteState) self,
SseSerializer serializer,
);
@protected
void sse_encode_route_state(RouteState self, SseSerializer serializer);
@protected
void sse_encode_transfer(Transfer self, SseSerializer serializer);
@protected
void sse_encode_transfer_status(
TransferStatus self,
SseSerializer serializer,
);
@protected
void sse_encode_transfer_type(TransferType self, SseSerializer serializer);
@protected
void sse_encode_u_16(int self, SseSerializer serializer);
@protected
void sse_encode_u_8(int self, SseSerializer serializer);
@protected
void sse_encode_unit(void self, SseSerializer serializer);
}
// Section: wire_class
class RustLibWire implements BaseWire {
RustLibWire.fromExternalLibrary(ExternalLibrary lib);
}
@JS('wasm_bindgen')
external RustLibWasmModule get wasmModule;
@JS()
@anonymous
extension type RustLibWasmModule._(JSObject _) implements JSObject {}

View File

@@ -0,0 +1,109 @@
// 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 '../discovery/model.dart';
import '../frb_generated.dart';
import 'package:flutter_rust_bridge/flutter_rust_bridge_for_generated.dart';
import 'package:freezed_annotation/freezed_annotation.dart' hide protected;
part 'model.freezed.dart';
enum CanceledBy { sender, receiver }
enum ContentType { file, text, folder }
class Transfer {
final String id;
final double createTime;
final Peer sender;
final String senderIp;
final String fileName;
final double fileSize;
final String savePath;
final TransferStatus status;
final TransferType type;
final ContentType contentType;
final String text;
final String errorMsg;
final String token;
final double progress;
final PlatformInt64 lastReadTime;
final double speed;
const Transfer({
required this.id,
required this.createTime,
required this.sender,
required this.senderIp,
required this.fileName,
required this.fileSize,
required this.savePath,
required this.status,
required this.type,
required this.contentType,
required this.text,
required this.errorMsg,
required this.token,
required this.progress,
required this.lastReadTime,
required this.speed,
});
@override
int get hashCode =>
id.hashCode ^
createTime.hashCode ^
sender.hashCode ^
senderIp.hashCode ^
fileName.hashCode ^
fileSize.hashCode ^
savePath.hashCode ^
status.hashCode ^
type.hashCode ^
contentType.hashCode ^
text.hashCode ^
errorMsg.hashCode ^
token.hashCode ^
progress.hashCode ^
lastReadTime.hashCode ^
speed.hashCode;
@override
bool operator ==(Object other) =>
identical(this, other) ||
other is Transfer &&
runtimeType == other.runtimeType &&
id == other.id &&
createTime == other.createTime &&
sender == other.sender &&
senderIp == other.senderIp &&
fileName == other.fileName &&
fileSize == other.fileSize &&
savePath == other.savePath &&
status == other.status &&
type == other.type &&
contentType == other.contentType &&
text == other.text &&
errorMsg == other.errorMsg &&
token == other.token &&
progress == other.progress &&
lastReadTime == other.lastReadTime &&
speed == other.speed;
}
@freezed
sealed class TransferStatus with _$TransferStatus {
const TransferStatus._();
const factory TransferStatus.pending() = TransferStatus_Pending;
const factory TransferStatus.accepted() = TransferStatus_Accepted;
const factory TransferStatus.rejected() = TransferStatus_Rejected;
const factory TransferStatus.completed() = TransferStatus_Completed;
const factory TransferStatus.error() = TransferStatus_Error;
const factory TransferStatus.canceled(CanceledBy field0) =
TransferStatus_Canceled;
const factory TransferStatus.active() = TransferStatus_Active;
}
enum TransferType { send, receive }

View File

@@ -0,0 +1,462 @@
// GENERATED CODE - DO NOT MODIFY BY HAND
// coverage:ignore-file
// ignore_for_file: type=lint
// ignore_for_file: unused_element, deprecated_member_use, deprecated_member_use_from_same_package, use_function_type_syntax_for_parameters, unnecessary_const, avoid_init_to_null, invalid_override_different_default_values_named, prefer_expression_function_bodies, annotate_overrides, invalid_annotation_target, unnecessary_question_mark
part of 'model.dart';
// **************************************************************************
// FreezedGenerator
// **************************************************************************
// dart format off
T _$identity<T>(T value) => value;
/// @nodoc
mixin _$TransferStatus {
@override
bool operator ==(Object other) {
return identical(this, other) || (other.runtimeType == runtimeType&&other is TransferStatus);
}
@override
int get hashCode => runtimeType.hashCode;
@override
String toString() {
return 'TransferStatus()';
}
}
/// @nodoc
class $TransferStatusCopyWith<$Res> {
$TransferStatusCopyWith(TransferStatus _, $Res Function(TransferStatus) __);
}
/// Adds pattern-matching-related methods to [TransferStatus].
extension TransferStatusPatterns on TransferStatus {
/// A variant of `map` that fallback to returning `orElse`.
///
/// It is equivalent to doing:
/// ```dart
/// switch (sealedClass) {
/// case final Subclass value:
/// return ...;
/// case _:
/// return orElse();
/// }
/// ```
@optionalTypeArgs TResult maybeMap<TResult extends Object?>({TResult Function( TransferStatus_Pending value)? pending,TResult Function( TransferStatus_Accepted value)? accepted,TResult Function( TransferStatus_Rejected value)? rejected,TResult Function( TransferStatus_Completed value)? completed,TResult Function( TransferStatus_Error value)? error,TResult Function( TransferStatus_Canceled value)? canceled,TResult Function( TransferStatus_Active value)? active,required TResult orElse(),}){
final _that = this;
switch (_that) {
case TransferStatus_Pending() when pending != null:
return pending(_that);case TransferStatus_Accepted() when accepted != null:
return accepted(_that);case TransferStatus_Rejected() when rejected != null:
return rejected(_that);case TransferStatus_Completed() when completed != null:
return completed(_that);case TransferStatus_Error() when error != null:
return error(_that);case TransferStatus_Canceled() when canceled != null:
return canceled(_that);case TransferStatus_Active() when active != null:
return active(_that);case _:
return orElse();
}
}
/// A `switch`-like method, using callbacks.
///
/// Callbacks receives the raw object, upcasted.
/// It is equivalent to doing:
/// ```dart
/// switch (sealedClass) {
/// case final Subclass value:
/// return ...;
/// case final Subclass2 value:
/// return ...;
/// }
/// ```
@optionalTypeArgs TResult map<TResult extends Object?>({required TResult Function( TransferStatus_Pending value) pending,required TResult Function( TransferStatus_Accepted value) accepted,required TResult Function( TransferStatus_Rejected value) rejected,required TResult Function( TransferStatus_Completed value) completed,required TResult Function( TransferStatus_Error value) error,required TResult Function( TransferStatus_Canceled value) canceled,required TResult Function( TransferStatus_Active value) active,}){
final _that = this;
switch (_that) {
case TransferStatus_Pending():
return pending(_that);case TransferStatus_Accepted():
return accepted(_that);case TransferStatus_Rejected():
return rejected(_that);case TransferStatus_Completed():
return completed(_that);case TransferStatus_Error():
return error(_that);case TransferStatus_Canceled():
return canceled(_that);case TransferStatus_Active():
return active(_that);}
}
/// A variant of `map` that fallback to returning `null`.
///
/// It is equivalent to doing:
/// ```dart
/// switch (sealedClass) {
/// case final Subclass value:
/// return ...;
/// case _:
/// return null;
/// }
/// ```
@optionalTypeArgs TResult? mapOrNull<TResult extends Object?>({TResult? Function( TransferStatus_Pending value)? pending,TResult? Function( TransferStatus_Accepted value)? accepted,TResult? Function( TransferStatus_Rejected value)? rejected,TResult? Function( TransferStatus_Completed value)? completed,TResult? Function( TransferStatus_Error value)? error,TResult? Function( TransferStatus_Canceled value)? canceled,TResult? Function( TransferStatus_Active value)? active,}){
final _that = this;
switch (_that) {
case TransferStatus_Pending() when pending != null:
return pending(_that);case TransferStatus_Accepted() when accepted != null:
return accepted(_that);case TransferStatus_Rejected() when rejected != null:
return rejected(_that);case TransferStatus_Completed() when completed != null:
return completed(_that);case TransferStatus_Error() when error != null:
return error(_that);case TransferStatus_Canceled() when canceled != null:
return canceled(_that);case TransferStatus_Active() when active != null:
return active(_that);case _:
return null;
}
}
/// A variant of `when` that fallback to an `orElse` callback.
///
/// It is equivalent to doing:
/// ```dart
/// switch (sealedClass) {
/// case Subclass(:final field):
/// return ...;
/// case _:
/// return orElse();
/// }
/// ```
@optionalTypeArgs TResult maybeWhen<TResult extends Object?>({TResult Function()? pending,TResult Function()? accepted,TResult Function()? rejected,TResult Function()? completed,TResult Function()? error,TResult Function( CanceledBy field0)? canceled,TResult Function()? active,required TResult orElse(),}) {final _that = this;
switch (_that) {
case TransferStatus_Pending() when pending != null:
return pending();case TransferStatus_Accepted() when accepted != null:
return accepted();case TransferStatus_Rejected() when rejected != null:
return rejected();case TransferStatus_Completed() when completed != null:
return completed();case TransferStatus_Error() when error != null:
return error();case TransferStatus_Canceled() when canceled != null:
return canceled(_that.field0);case TransferStatus_Active() when active != null:
return active();case _:
return orElse();
}
}
/// A `switch`-like method, using callbacks.
///
/// As opposed to `map`, this offers destructuring.
/// It is equivalent to doing:
/// ```dart
/// switch (sealedClass) {
/// case Subclass(:final field):
/// return ...;
/// case Subclass2(:final field2):
/// return ...;
/// }
/// ```
@optionalTypeArgs TResult when<TResult extends Object?>({required TResult Function() pending,required TResult Function() accepted,required TResult Function() rejected,required TResult Function() completed,required TResult Function() error,required TResult Function( CanceledBy field0) canceled,required TResult Function() active,}) {final _that = this;
switch (_that) {
case TransferStatus_Pending():
return pending();case TransferStatus_Accepted():
return accepted();case TransferStatus_Rejected():
return rejected();case TransferStatus_Completed():
return completed();case TransferStatus_Error():
return error();case TransferStatus_Canceled():
return canceled(_that.field0);case TransferStatus_Active():
return active();}
}
/// A variant of `when` that fallback to returning `null`
///
/// It is equivalent to doing:
/// ```dart
/// switch (sealedClass) {
/// case Subclass(:final field):
/// return ...;
/// case _:
/// return null;
/// }
/// ```
@optionalTypeArgs TResult? whenOrNull<TResult extends Object?>({TResult? Function()? pending,TResult? Function()? accepted,TResult? Function()? rejected,TResult? Function()? completed,TResult? Function()? error,TResult? Function( CanceledBy field0)? canceled,TResult? Function()? active,}) {final _that = this;
switch (_that) {
case TransferStatus_Pending() when pending != null:
return pending();case TransferStatus_Accepted() when accepted != null:
return accepted();case TransferStatus_Rejected() when rejected != null:
return rejected();case TransferStatus_Completed() when completed != null:
return completed();case TransferStatus_Error() when error != null:
return error();case TransferStatus_Canceled() when canceled != null:
return canceled(_that.field0);case TransferStatus_Active() when active != null:
return active();case _:
return null;
}
}
}
/// @nodoc
class TransferStatus_Pending extends TransferStatus {
const TransferStatus_Pending(): super._();
@override
bool operator ==(Object other) {
return identical(this, other) || (other.runtimeType == runtimeType&&other is TransferStatus_Pending);
}
@override
int get hashCode => runtimeType.hashCode;
@override
String toString() {
return 'TransferStatus.pending()';
}
}
/// @nodoc
class TransferStatus_Accepted extends TransferStatus {
const TransferStatus_Accepted(): super._();
@override
bool operator ==(Object other) {
return identical(this, other) || (other.runtimeType == runtimeType&&other is TransferStatus_Accepted);
}
@override
int get hashCode => runtimeType.hashCode;
@override
String toString() {
return 'TransferStatus.accepted()';
}
}
/// @nodoc
class TransferStatus_Rejected extends TransferStatus {
const TransferStatus_Rejected(): super._();
@override
bool operator ==(Object other) {
return identical(this, other) || (other.runtimeType == runtimeType&&other is TransferStatus_Rejected);
}
@override
int get hashCode => runtimeType.hashCode;
@override
String toString() {
return 'TransferStatus.rejected()';
}
}
/// @nodoc
class TransferStatus_Completed extends TransferStatus {
const TransferStatus_Completed(): super._();
@override
bool operator ==(Object other) {
return identical(this, other) || (other.runtimeType == runtimeType&&other is TransferStatus_Completed);
}
@override
int get hashCode => runtimeType.hashCode;
@override
String toString() {
return 'TransferStatus.completed()';
}
}
/// @nodoc
class TransferStatus_Error extends TransferStatus {
const TransferStatus_Error(): super._();
@override
bool operator ==(Object other) {
return identical(this, other) || (other.runtimeType == runtimeType&&other is TransferStatus_Error);
}
@override
int get hashCode => runtimeType.hashCode;
@override
String toString() {
return 'TransferStatus.error()';
}
}
/// @nodoc
class TransferStatus_Canceled extends TransferStatus {
const TransferStatus_Canceled(this.field0): super._();
final CanceledBy field0;
/// Create a copy of TransferStatus
/// with the given fields replaced by the non-null parameter values.
@JsonKey(includeFromJson: false, includeToJson: false)
@pragma('vm:prefer-inline')
$TransferStatus_CanceledCopyWith<TransferStatus_Canceled> get copyWith => _$TransferStatus_CanceledCopyWithImpl<TransferStatus_Canceled>(this, _$identity);
@override
bool operator ==(Object other) {
return identical(this, other) || (other.runtimeType == runtimeType&&other is TransferStatus_Canceled&&(identical(other.field0, field0) || other.field0 == field0));
}
@override
int get hashCode => Object.hash(runtimeType,field0);
@override
String toString() {
return 'TransferStatus.canceled(field0: $field0)';
}
}
/// @nodoc
abstract mixin class $TransferStatus_CanceledCopyWith<$Res> implements $TransferStatusCopyWith<$Res> {
factory $TransferStatus_CanceledCopyWith(TransferStatus_Canceled value, $Res Function(TransferStatus_Canceled) _then) = _$TransferStatus_CanceledCopyWithImpl;
@useResult
$Res call({
CanceledBy field0
});
}
/// @nodoc
class _$TransferStatus_CanceledCopyWithImpl<$Res>
implements $TransferStatus_CanceledCopyWith<$Res> {
_$TransferStatus_CanceledCopyWithImpl(this._self, this._then);
final TransferStatus_Canceled _self;
final $Res Function(TransferStatus_Canceled) _then;
/// Create a copy of TransferStatus
/// with the given fields replaced by the non-null parameter values.
@pragma('vm:prefer-inline') $Res call({Object? field0 = null,}) {
return _then(TransferStatus_Canceled(
null == field0 ? _self.field0 : field0 // ignore: cast_nullable_to_non_nullable
as CanceledBy,
));
}
}
/// @nodoc
class TransferStatus_Active extends TransferStatus {
const TransferStatus_Active(): super._();
@override
bool operator ==(Object other) {
return identical(this, other) || (other.runtimeType == runtimeType&&other is TransferStatus_Active);
}
@override
int get hashCode => runtimeType.hashCode;
@override
String toString() {
return 'TransferStatus.active()';
}
}
// dart format on

11
lib/main.dart Normal file
View File

@@ -0,0 +1,11 @@
import 'package:flutter/material.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'app/app.dart';
import 'backend/frb_generated.dart';
Future<void> main() async {
WidgetsFlutterBinding.ensureInitialized();
await RustLib.init();
runApp(const ProviderScope(child: MeshDropApp()));
}