Skip to content

Commit 4812b11

Browse files
committed
add new device toastification ui
1 parent ee93626 commit 4812b11

6 files changed

Lines changed: 109 additions & 103 deletions

File tree

client/lib/devices/borneo/lyfi/views/acclimation_screen.dart

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -160,6 +160,7 @@ class AcclimationScreen extends StatelessWidget {
160160
title: Text('Update acclimation settings succeed.'),
161161
autoCloseDuration: const Duration(seconds: 5),
162162
closeOnClick: true,
163+
style: ToastificationStyle.fillColored,
163164
type: ToastificationType.success,
164165
);
165166
});

client/lib/view_models/devices/device_discovery_view_model.dart

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -212,7 +212,6 @@ class DeviceDiscoveryViewModel extends AbstractScreenViewModel with ViewModelEve
212212
}
213213

214214
Future<void> _onNewDeviceEntityAdded(NewDeviceEntityAddedEvent event) async {
215-
// TODO show a toast or snackbar
216215
try {
217216
_discoveredDevices.value.removeWhere((x) => x.fingerprint == event.device.fingerprint);
218217
_discoveredDevices.value = List.from(_discoveredDevices.value);

client/lib/views/devices/device_discovery_screen.dart

Lines changed: 85 additions & 85 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ import 'package:flutter/material.dart';
77
import 'package:flutter_gettext/flutter_gettext/context_ext.dart';
88
import 'package:logger/logger.dart';
99
import 'package:provider/provider.dart';
10+
import 'package:toastification/toastification.dart';
1011

1112
import '../../services/device_manager.dart';
1213
import '../../view_models/devices/device_discovery_view_model.dart';
@@ -246,31 +247,27 @@ class NewDeviceAddedSnackBarListener extends StatelessWidget {
246247
return Selector<DeviceDiscoveryViewModel, DeviceEntity?>(
247248
selector: (_, viewModel) => viewModel.lastestAddedDevice,
248249
builder: (context, lastestAdded, child) {
249-
final vm = context.read<DeviceDiscoveryViewModel>();
250250
if (lastestAdded != null) {
251251
WidgetsBinding.instance.addPostFrameCallback((_) {
252-
ScaffoldMessenger.of(context)
253-
.showSnackBar(
254-
SnackBar(
255-
duration: Duration(seconds: 3),
256-
content: Text(
257-
context.translate(
258-
'New device "{deviceName}" has been added.',
259-
nArgs: {'deviceName': lastestAdded.name},
260-
),
261-
style: Theme.of(
262-
context,
263-
).textTheme.bodyMedium?.copyWith(color: Theme.of(context).colorScheme.onTertiaryContainer),
264-
),
265-
backgroundColor: Theme.of(context).colorScheme.tertiaryContainer,
266-
),
267-
)
268-
.closed
269-
.then((_) {
270-
if (!vm.isDisposed) {
271-
vm.clearAddedDevice();
272-
}
273-
});
252+
toastification.dismissAll();
253+
toastification.show(
254+
context: context,
255+
type: ToastificationType.success,
256+
style: ToastificationStyle.fillColored,
257+
title: Text(context.translate('A new device has been added.')),
258+
description: Text(lastestAdded.name),
259+
autoCloseDuration: const Duration(seconds: 3),
260+
icon: const Icon(Icons.device_hub),
261+
);
262+
263+
// 在 toast 关闭后清除状态
264+
/*
265+
Future.delayed(const Duration(seconds: 3), () {
266+
if (!vm.isDisposed) {
267+
vm.clearAddedDevice();
268+
}
269+
});
270+
*/
274271
});
275272
}
276273
return child!;
@@ -329,71 +326,74 @@ class DeviceDiscoveryScreen extends StatelessWidget {
329326
Navigator.of(context).pop(vm.newDeviceCount > 0);
330327
}
331328
},
332-
child: Column(
333-
crossAxisAlignment: CrossAxisAlignment.stretch,
334-
mainAxisSize: MainAxisSize.max,
335-
children: [
336-
Container(
337-
color: Theme.of(context).colorScheme.surface,
338-
child: Column(
339-
crossAxisAlignment: CrossAxisAlignment.start,
340-
children: [
341-
// Input Fields
342-
SmartConfigFormPanel(),
343-
SizedBox(height: 8),
344-
// Start/Stop Button
345-
Container(
346-
padding: EdgeInsets.symmetric(horizontal: 16, vertical: 8),
347-
width: double.infinity,
348-
child: StartStopButton(),
349-
),
350-
SizedBox(height: 16),
351-
],
352-
),
353-
),
354-
ValueListenableBuilder<List<SupportedDeviceDescriptor>>(
355-
valueListenable: vm.discoveredDevices,
356-
builder: (context, devices, child) => devices.isNotEmpty ? child! : const SizedBox(height: 0),
357-
child: Container(
358-
padding: const EdgeInsets.fromLTRB(16, 0, 16, 8),
359-
child: Text(context.translate('Discovered Devices:'), style: Theme.of(context).textTheme.titleMedium),
329+
child: GestureDetector(
330+
onTap: () => FocusScope.of(context).unfocus(),
331+
child: Column(
332+
crossAxisAlignment: CrossAxisAlignment.stretch,
333+
mainAxisSize: MainAxisSize.max,
334+
children: [
335+
Container(
336+
color: Theme.of(context).colorScheme.surface,
337+
child: Column(
338+
crossAxisAlignment: CrossAxisAlignment.start,
339+
children: [
340+
// Input Fields
341+
SmartConfigFormPanel(),
342+
SizedBox(height: 8),
343+
// Start/Stop Button
344+
Container(
345+
padding: EdgeInsets.symmetric(horizontal: 16, vertical: 8),
346+
width: double.infinity,
347+
child: StartStopButton(),
348+
),
349+
SizedBox(height: 16),
350+
],
351+
),
360352
),
361-
),
362-
Expanded(
363-
child: ValueListenableBuilder<List<SupportedDeviceDescriptor>>(
353+
ValueListenableBuilder<List<SupportedDeviceDescriptor>>(
364354
valueListenable: vm.discoveredDevices,
365-
builder:
366-
(context, value, child) => ListView.separated(
367-
separatorBuilder:
368-
(BuildContext context, int index) => DecoratedBox(
369-
decoration: BoxDecoration(color: Theme.of(context).colorScheme.surfaceContainer),
370-
child: Divider(height: 1, indent: 16, color: Theme.of(context).colorScheme.surface),
371-
),
372-
itemCount: vm.discoveredDevices.value.length,
373-
itemBuilder: (context, index) {
374-
final user = vm.discoveredDevices.value[index];
375-
return ListTile(
376-
tileColor: Theme.of(context).colorScheme.surfaceContainer,
377-
title: Text(user.name, style: Theme.of(context).textTheme.bodyLarge),
378-
subtitle: Text(user.address.toString(), style: Theme.of(context).textTheme.bodySmall),
379-
trailing: Consumer<DeviceDiscoveryViewModel>(
380-
builder:
381-
(context, vm, child) => IconButton.filledTonal(
382-
onPressed:
383-
vm.isBusy || vm.isDiscovering
384-
? null
385-
: () => _showAddDeviceSheet(context, vm, vm.discoveredDevices.value[index]),
386-
icon: child as Icon,
387-
),
388-
child: Icon(Icons.add_outlined),
389-
),
390-
);
391-
},
392-
),
355+
builder: (context, devices, child) => devices.isNotEmpty ? child! : const SizedBox(height: 0),
356+
child: Container(
357+
padding: const EdgeInsets.fromLTRB(16, 0, 16, 8),
358+
child: Text(context.translate('Discovered Devices:'), style: Theme.of(context).textTheme.titleMedium),
359+
),
393360
),
394-
),
395-
NewDeviceAddedSnackBarListener(child: SizedBox()),
396-
],
361+
Expanded(
362+
child: ValueListenableBuilder<List<SupportedDeviceDescriptor>>(
363+
valueListenable: vm.discoveredDevices,
364+
builder:
365+
(context, value, child) => ListView.separated(
366+
separatorBuilder:
367+
(BuildContext context, int index) => DecoratedBox(
368+
decoration: BoxDecoration(color: Theme.of(context).colorScheme.surfaceContainer),
369+
child: Divider(height: 1, indent: 16, color: Theme.of(context).colorScheme.surface),
370+
),
371+
itemCount: vm.discoveredDevices.value.length,
372+
itemBuilder: (context, index) {
373+
final user = vm.discoveredDevices.value[index];
374+
return ListTile(
375+
tileColor: Theme.of(context).colorScheme.surfaceContainer,
376+
title: Text(user.name, style: Theme.of(context).textTheme.bodyLarge),
377+
subtitle: Text(user.address.toString(), style: Theme.of(context).textTheme.bodySmall),
378+
trailing: Consumer<DeviceDiscoveryViewModel>(
379+
builder:
380+
(context, vm, child) => IconButton.filledTonal(
381+
onPressed:
382+
vm.isBusy || vm.isDiscovering
383+
? null
384+
: () => _showAddDeviceSheet(context, vm, vm.discoveredDevices.value[index]),
385+
icon: child as Icon,
386+
),
387+
child: Icon(Icons.add_outlined),
388+
),
389+
);
390+
},
391+
),
392+
),
393+
),
394+
NewDeviceAddedSnackBarListener(child: SizedBox()),
395+
],
396+
),
397397
),
398398
);
399399
}

client/lib/views/main_screen.dart

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -61,6 +61,7 @@ class NotificationListener extends StatelessWidget {
6161
context: context,
6262
title: Text("Error"),
6363
type: ToastificationType.error,
64+
style: ToastificationStyle.fillColored,
6465
description: Text(
6566
vm.errorMessage,
6667
style: Theme.of(

client/packages/borneo_kernel/lib/kernel.dart

Lines changed: 15 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -135,12 +135,16 @@ final class DefaultKernel implements IKernel {
135135
}
136136

137137
@override
138-
Future<bool> tryBind(Device device, String driverID,
139-
{CancellationToken? cancelToken}) async {
138+
Future<bool> tryBind(
139+
Device device,
140+
String driverID, {
141+
Duration? timeout,
142+
CancellationToken? cancelToken,
143+
}) async {
140144
_ensureStarted();
141145
assert(_registeredDevices.containsKey(device.id));
142146
try {
143-
await bind(device, driverID, cancelToken: cancelToken);
147+
await bind(device, driverID, cancelToken: cancelToken, timeout: timeout);
144148
return true;
145149
} on CancelledException catch (_) {
146150
_logger.w('Device($device) binding cancelled');
@@ -160,7 +164,7 @@ final class DefaultKernel implements IKernel {
160164

161165
@override
162166
Future<void> bind(Device device, String driverID,
163-
{CancellationToken? cancelToken}) async {
167+
{Duration? timeout, CancellationToken? cancelToken}) async {
164168
_ensureStarted();
165169
assert(_registeredDevices.containsKey(device.id));
166170
_logger.i('Binding device: `$device` to driver `$driverID`');
@@ -176,7 +180,7 @@ final class DefaultKernel implements IKernel {
176180

177181
final driverInitialized = await driver
178182
.probe(device, cancelToken: cancelToken)
179-
.timeout(kLocalProbeTimeOut);
183+
.timeout(timeout ?? kLocalProbeTimeOut);
180184

181185
if (driverInitialized) {
182186
// Try to activate device
@@ -245,15 +249,14 @@ final class DefaultKernel implements IKernel {
245249
futures.add(bd.driver
246250
.heartbeat(bd.device,
247251
cancelToken: _heartbeatPollingTaskCancelToken)
248-
.timeout(kLocalProbeTimeOut, onTimeout: () => false));
252+
.timeout(kHeartbeatPollingInterval)
253+
.asCancellable(_heartbeatPollingTaskCancelToken));
249254
devices.add(bd);
250255
}
251256
}
252257

253258
_logger.i('Polling heartbeat for (${devices.length}) bound devices...');
254-
final results = await Future.wait(futures)
255-
.timeout(kHeartbeatPollingInterval)
256-
.asCancellable(_heartbeatPollingTaskCancelToken);
259+
final results = await Future.wait(futures);
257260
for (int i = 0; i < results.length; i++) {
258261
if (!results[i]) {
259262
_logger.w('The device(${devices[i].device}) is not responding.');
@@ -268,14 +271,12 @@ final class DefaultKernel implements IKernel {
268271
_registeredDevices.values.where((x) => !isBound(x.device.id)).toList();
269272
for (final descriptor in unboundDeviceDescriptors) {
270273
futures.add(tryBind(descriptor.device, descriptor.driverID,
271-
cancelToken: _heartbeatPollingTaskCancelToken)
272-
.timeout(kLocalProbeTimeOut));
274+
timeout: kLocalProbeTimeOut,
275+
cancelToken: _heartbeatPollingTaskCancelToken));
273276
}
274277
_logger.i(
275278
'Polling heartbeat for (${unboundDeviceDescriptors.length}) unbound devices...');
276-
final boundResults = await Future.wait(futures)
277-
.timeout(kHeartbeatPollingInterval)
278-
.asCancellable(_heartbeatPollingTaskCancelToken);
279+
final boundResults = await Future.wait(futures);
279280
for (int i = 0; i < boundResults.length; i++) {
280281
/*
281282
if (!boundResults[i]) {

client/packages/borneo_kernel_abstractions/lib/ikernel.dart

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -19,11 +19,15 @@ abstract class IKernel implements IDisposable {
1919

2020
BoundDevice getBoundDevice(String deviceID);
2121

22-
Future<bool> tryBind(Device device, String driverID,
23-
{CancellationToken? cancelToken});
22+
Future<bool> tryBind(
23+
Device device,
24+
String driverID, {
25+
Duration? timeout,
26+
CancellationToken? cancelToken,
27+
});
2428

2529
Future<void> bind(Device device, String driverID,
26-
{CancellationToken? cancelToken});
30+
{Duration? timeout, CancellationToken? cancelToken});
2731

2832
Future<void> unbind(String deviceID, {CancellationToken? cancelToken});
2933
Future<void> unbindAll({CancellationToken? cancelToken});

0 commit comments

Comments
 (0)