From fcdce92df2c17ddf2fdbe69cb6065b65e2f623f8 Mon Sep 17 00:00:00 2001 From: Tien Do Nam <38380847+Tienisto@users.noreply.github.com> Date: Fri, 8 Dec 2023 02:22:20 +0100 Subject: [PATCH] feat: update favorite device name if unchanged (#1009) --- .../model/persistence/favorite_device.dart | 7 ++++++ .../persistence/favorite_device.mapper.dart | 23 +++++++++++++++---- .../network/nearby_devices_provider.dart | 23 ++++++++++++++----- .../server/controller/receive_controller.dart | 2 +- .../widget/dialogs/favorite_edit_dialog.dart | 11 ++++++--- 5 files changed, 51 insertions(+), 15 deletions(-) diff --git a/app/lib/model/persistence/favorite_device.dart b/app/lib/model/persistence/favorite_device.dart index e60b06a1..e91e6c5c 100644 --- a/app/lib/model/persistence/favorite_device.dart +++ b/app/lib/model/persistence/favorite_device.dart @@ -13,12 +13,18 @@ class FavoriteDevice with FavoriteDeviceMappable { final int port; final String alias; + /// If true, the alias was set by the user. + /// If false, the alias is derived from the original device alias and + /// should be updated when the original device alias changes. + final bool customAlias; + const FavoriteDevice({ required this.id, required this.fingerprint, required this.ip, required this.port, required this.alias, + this.customAlias = false, }); factory FavoriteDevice.fromValues({ @@ -33,6 +39,7 @@ class FavoriteDevice with FavoriteDeviceMappable { ip: ip, port: port, alias: alias, + customAlias: false, ); } diff --git a/app/lib/model/persistence/favorite_device.mapper.dart b/app/lib/model/persistence/favorite_device.mapper.dart index 929e0c00..67b89c7f 100644 --- a/app/lib/model/persistence/favorite_device.mapper.dart +++ b/app/lib/model/persistence/favorite_device.mapper.dart @@ -31,6 +31,9 @@ class FavoriteDeviceMapper extends ClassMapperBase { static const Field _f$port = Field('port', _$port); static String _$alias(FavoriteDevice v) => v.alias; static const Field _f$alias = Field('alias', _$alias); + static bool _$customAlias(FavoriteDevice v) => v.customAlias; + static const Field _f$customAlias = + Field('customAlias', _$customAlias, opt: true, def: false); @override final Map> fields = const { @@ -39,6 +42,7 @@ class FavoriteDeviceMapper extends ClassMapperBase { #ip: _f$ip, #port: _f$port, #alias: _f$alias, + #customAlias: _f$customAlias, }; static FavoriteDevice _instantiate(DecodingData data) { @@ -47,7 +51,8 @@ class FavoriteDeviceMapper extends ClassMapperBase { fingerprint: data.dec(_f$fingerprint), ip: data.dec(_f$ip), port: data.dec(_f$port), - alias: data.dec(_f$alias)); + alias: data.dec(_f$alias), + customAlias: data.dec(_f$customAlias)); } @override @@ -106,7 +111,12 @@ extension FavoriteDeviceValueCopy<$R, $Out> abstract class FavoriteDeviceCopyWith<$R, $In extends FavoriteDevice, $Out> implements ClassCopyWith<$R, $In, $Out> { $R call( - {String? id, String? fingerprint, String? ip, int? port, String? alias}); + {String? id, + String? fingerprint, + String? ip, + int? port, + String? alias, + bool? customAlias}); FavoriteDeviceCopyWith<$R2, $In, $Out2> $chain<$R2, $Out2>( Then<$Out2, $R2> t); } @@ -125,13 +135,15 @@ class _FavoriteDeviceCopyWithImpl<$R, $Out> String? fingerprint, String? ip, int? port, - String? alias}) => + String? alias, + bool? customAlias}) => $apply(FieldCopyWithData({ if (id != null) #id: id, if (fingerprint != null) #fingerprint: fingerprint, if (ip != null) #ip: ip, if (port != null) #port: port, - if (alias != null) #alias: alias + if (alias != null) #alias: alias, + if (customAlias != null) #customAlias: customAlias })); @override FavoriteDevice $make(CopyWithData data) => FavoriteDevice( @@ -139,7 +151,8 @@ class _FavoriteDeviceCopyWithImpl<$R, $Out> fingerprint: data.get(#fingerprint, or: $value.fingerprint), ip: data.get(#ip, or: $value.ip), port: data.get(#port, or: $value.port), - alias: data.get(#alias, or: $value.alias)); + alias: data.get(#alias, or: $value.alias), + customAlias: data.get(#customAlias, or: $value.customAlias)); @override FavoriteDeviceCopyWith<$R2, FavoriteDevice, $Out2> $chain<$R2, $Out2>( diff --git a/app/lib/provider/network/nearby_devices_provider.dart b/app/lib/provider/network/nearby_devices_provider.dart index e68d52a0..ef3c9710 100644 --- a/app/lib/provider/network/nearby_devices_provider.dart +++ b/app/lib/provider/network/nearby_devices_provider.dart @@ -1,8 +1,10 @@ import 'dart:async'; +import 'package:collection/collection.dart'; import 'package:localsend_app/model/device.dart'; import 'package:localsend_app/model/persistence/favorite_device.dart'; import 'package:localsend_app/model/state/nearby_devices_state.dart'; +import 'package:localsend_app/provider/favorites_provider.dart'; import 'package:localsend_app/provider/logging/discovery_logs_provider.dart'; import 'package:localsend_app/provider/network/multicast_provider.dart'; import 'package:localsend_app/provider/network/targeted_discovery_provider.dart'; @@ -22,6 +24,7 @@ final nearbyDevicesProvider = ReduxProvider { final DiscoveryLogger _discoveryLogs; final StateAccessor _targetedDiscoveryService; final StateAccessor _multicastService; + final FavoritesService _favoriteService; NearbyDevicesService({ required DiscoveryLogger discoveryLogs, required StateAccessor targetedDiscoveryService, required StateAccessor multicastService, + required FavoritesService favoriteService, }) : _discoveryLogs = discoveryLogs, _targetedDiscoveryService = targetedDiscoveryService, - _multicastService = multicastService; + _multicastService = multicastService, + _favoriteService = favoriteService; @override NearbyDevicesState init() => const NearbyDevicesState( @@ -98,7 +104,7 @@ class StartMulticastListener extends AsyncReduxAction reduce() async { await for (final device in notifier._multicastService.state.startListener()) { - dispatch(RegisterDeviceAction(device)); + await dispatchAsync(RegisterDeviceAction(device)); notifier._discoveryLogs.addLog('[DISCOVER/UDP] ${device.alias} (${device.ip}, model: ${device.deviceModel})'); } return state; @@ -117,7 +123,7 @@ class ClearFoundDevicesAction extends ReduxAction { +class RegisterDeviceAction extends AsyncReduxAction { final Device device; RegisterDeviceAction(this.device); @@ -126,7 +132,12 @@ class RegisterDeviceAction extends ReduxAction false; @override - NearbyDevicesState reduce() { + Future reduce() async { + final favoriteDevice = notifier._favoriteService.state.firstWhereOrNull((e) => e.fingerprint == device.fingerprint); + if (favoriteDevice != null && !favoriteDevice.customAlias) { + // Update existing favorite with new alias + await external(notifier._favoriteService).dispatchAsync(UpdateFavoriteAction(favoriteDevice.copyWith(alias: device.alias))); + } return state.copyWith( devices: {...state.devices}..update(device.ip, (_) => device, ifAbsent: () => device), ); @@ -166,7 +177,7 @@ class StartLegacyScan extends AsyncReduxAction with Refena { } if (widget.favorite != null) { - if (_aliasController.text.trim().isEmpty) { + // Update existing favorite + final existingFavorite = widget.favorite!; + final trimmedNewAlias = _aliasController.text.trim(); + if (trimmedNewAlias.isEmpty) { return; } - await ref.redux(favoritesProvider).dispatchAsync(UpdateFavoriteAction(widget.favorite!.copyWith( + await ref.redux(favoritesProvider).dispatchAsync(UpdateFavoriteAction(existingFavorite.copyWith( ip: _ipController.text, port: int.parse(_portController.text), - alias: _aliasController.text, + alias: trimmedNewAlias, + customAlias: existingFavorite.customAlias || trimmedNewAlias != existingFavorite.alias, ))); } else { + // Add new favorite final ip = _ipController.text; final port = int.parse(_portController.text); final https = ref.read(settingsProvider).https;