init
This commit is contained in:
61
lib/app/app.dart
Normal file
61
lib/app/app.dart
Normal 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(),
|
||||
);
|
||||
}
|
||||
}
|
||||
246
lib/app/features/modals/send_files_modal.dart
Normal file
246
lib/app/features/modals/send_files_modal.dart
Normal 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})'),
|
||||
),
|
||||
],
|
||||
);
|
||||
}
|
||||
}
|
||||
65
lib/app/features/modals/send_text_modal.dart
Normal file
65
lib/app/features/modals/send_text_modal.dart
Normal 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('发送'),
|
||||
),
|
||||
],
|
||||
);
|
||||
}
|
||||
}
|
||||
50
lib/app/features/peers/controller/peers_controller.dart
Normal file
50
lib/app/features/peers/controller/peers_controller.dart
Normal 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);
|
||||
}
|
||||
}
|
||||
}
|
||||
54
lib/app/features/peers/controller/peers_controller.g.dart
Normal file
54
lib/app/features/peers/controller/peers_controller.g.dart
Normal 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);
|
||||
}
|
||||
}
|
||||
73
lib/app/features/peers/pages/peers_page.dart
Normal file
73
lib/app/features/peers/pages/peers_page.dart
Normal 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]),
|
||||
);
|
||||
},
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
266
lib/app/features/peers/widgets/peer_card.dart
Normal file
266
lib/app/features/peers/widgets/peer_card.dart
Normal 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;
|
||||
}
|
||||
}
|
||||
@@ -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));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
161
lib/app/features/settings/pages/settings_page.dart
Normal file
161
lib/app/features/settings/pages/settings_page.dart
Normal 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());
|
||||
}
|
||||
}
|
||||
}
|
||||
127
lib/app/features/transfer/controller/transfers_controller.dart
Normal file
127
lib/app/features/transfer/controller/transfers_controller.dart
Normal 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();
|
||||
}
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
98
lib/app/features/transfer/pages/transfer_page.dart
Normal file
98
lib/app/features/transfer/pages/transfer_page.dart
Normal 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,
|
||||
);
|
||||
},
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
282
lib/app/features/transfer/widgets/transfer_item.dart
Normal file
282
lib/app/features/transfer/widgets/transfer_item.dart
Normal 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));
|
||||
}
|
||||
}
|
||||
83
lib/app/navigation/home_shell.dart
Normal file
83
lib/app/navigation/home_shell.dart
Normal 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',
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
43
lib/app/shared/widgets/empty_state.dart
Normal file
43
lib/app/shared/widgets/empty_state.dart
Normal 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!],
|
||||
],
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
11
lib/app/sync/backend_event_sync.dart
Normal file
11
lib/app/sync/backend_event_sync.dart
Normal 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();
|
||||
}
|
||||
44
lib/app/sync/backend_event_sync.g.dart
Normal file
44
lib/app/sync/backend_event_sync.g.dart
Normal 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';
|
||||
47
lib/app/theme/app_theme.dart
Normal file
47
lib/app/theme/app_theme.dart
Normal 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)),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
21
lib/app/theme/theme_mode_controller.dart
Normal file
21
lib/app/theme/theme_mode_controller.dart
Normal 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,
|
||||
};
|
||||
}
|
||||
}
|
||||
63
lib/app/theme/theme_mode_controller.g.dart
Normal file
63
lib/app/theme/theme_mode_controller.g.dart
Normal 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);
|
||||
}
|
||||
}
|
||||
107
lib/backend/api/commands.dart
Normal file
107
lib/backend/api/commands.dart
Normal 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);
|
||||
72
lib/backend/discovery/model.dart
Normal file
72
lib/backend/discovery/model.dart
Normal 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
34
lib/backend/event.dart
Normal 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;
|
||||
}
|
||||
638
lib/backend/event.freezed.dart
Normal file
638
lib/backend/event.freezed.dart
Normal 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
|
||||
1645
lib/backend/frb_generated.dart
Normal file
1645
lib/backend/frb_generated.dart
Normal file
File diff suppressed because it is too large
Load Diff
303
lib/backend/frb_generated.io.dart
Normal file
303
lib/backend/frb_generated.io.dart
Normal 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;
|
||||
}
|
||||
303
lib/backend/frb_generated.web.dart
Normal file
303
lib/backend/frb_generated.web.dart
Normal 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 {}
|
||||
109
lib/backend/transfer/model.dart
Normal file
109
lib/backend/transfer/model.dart
Normal 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 }
|
||||
462
lib/backend/transfer/model.freezed.dart
Normal file
462
lib/backend/transfer/model.freezed.dart
Normal 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
11
lib/main.dart
Normal 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()));
|
||||
}
|
||||
Reference in New Issue
Block a user