Implemented feature to accept quickSave if sender is in favorites (#1698)

This commit is contained in:
Davte
2024-09-04 01:59:27 +02:00
committed by GitHub
parent b5ed1e642d
commit 13880fa4f5
12 changed files with 191 additions and 19 deletions
+6
View File
@@ -28,6 +28,7 @@
"open": "Open",
"queue": "Queue",
"quickSave": "Quick Save",
"quickSaveFromFavorites": "Quick Save from Favorites",
"renamed": "Renamed",
"reset": "Undo changes",
"restart": "Restart",
@@ -108,6 +109,7 @@
"receive": {
"title": "Receive",
"quickSave": "@:general.quickSave",
"quickSaveFromFavorites": "@:general.quickSaveFromFavorites",
"requirePin": "@:webSharePage.requirePin",
"autoFinish": "Auto Finish",
"destination": "Save to folder",
@@ -427,6 +429,10 @@
"title": "@:general.quickSave",
"content": "File requests are automatically accepted. Be aware that everyone on the local network can send you files."
},
"quickSaveFromFavoritesNotice": {
"title": "@:general.quickSaveFromFavorites",
"content": "File requests are automatically accepted from devices in your contact list."
},
"pin": {
"title": "Enter PIN"
},
+14
View File
@@ -90,6 +90,7 @@ class _StringsGeneralEn {
String get open => 'Open';
String get queue => 'Queue';
String get quickSave => 'Quick Save';
String get quickSaveFromFavorites => 'Quick Save From Favorites';
String get renamed => 'Renamed';
String get reset => 'Undo changes';
String get restart => 'Restart';
@@ -435,6 +436,7 @@ class _StringsDialogsEn {
late final _StringsDialogsQrEn qr = _StringsDialogsQrEn._(_root);
late final _StringsDialogsQuickActionsEn quickActions = _StringsDialogsQuickActionsEn._(_root);
late final _StringsDialogsQuickSaveNoticeEn quickSaveNotice = _StringsDialogsQuickSaveNoticeEn._(_root);
late final _StringsDialogsQuickSaveFromFavoritesNoticeEn quickSaveFromFavoritesNotice = _StringsDialogsQuickSaveFromFavoritesNoticeEn._(_root);
late final _StringsDialogsPinEn pin = _StringsDialogsPinEn._(_root);
late final _StringsDialogsSendModeHelpEn sendModeHelp = _StringsDialogsSendModeHelpEn._(_root);
late final _StringsDialogsZoomEn zoom = _StringsDialogsZoomEn._(_root);
@@ -600,6 +602,7 @@ class _StringsSettingsTabReceiveEn {
// Translations
String get title => 'Receive';
String get quickSave => _root.general.quickSave;
String get quickSaveFromFavorites => _root.general.quickSaveFromFavorites;
String get requirePin => _root.webSharePage.requirePin;
String get autoFinish => 'Auto Finish';
String get destination => 'Save to folder';
@@ -948,6 +951,17 @@ class _StringsDialogsQuickSaveNoticeEn {
String get content => 'File requests are automatically accepted. Be aware that everyone on the local network can send you files.';
}
// Path: dialogs.quickSaveFromFavoritesNotice
class _StringsDialogsQuickSaveFromFavoritesNoticeEn {
_StringsDialogsQuickSaveFromFavoritesNoticeEn._(this._root);
final Translations _root; // ignore: unused_field
// Translations
String get title => _root.general.quickSaveFromFavorites;
String get content => 'File requests are automatically accepted from favorites.';
}
// Path: dialogs.pin
class _StringsDialogsPinEn {
_StringsDialogsPinEn._(this._root);
+2
View File
@@ -20,6 +20,7 @@ class SettingsState with SettingsStateMappable {
final bool saveToGallery; // only Android, iOS
final bool saveToHistory;
final bool quickSave; // automatically accept file requests
final bool quickSaveFromFavorites; // automatically accept file requests from favorites
final String? receivePin; // null = disabled
final bool autoFinish; // automatically finish sessions
final bool minimizeToTray; // minimize to tray instead of exiting the app
@@ -44,6 +45,7 @@ class SettingsState with SettingsStateMappable {
required this.saveToGallery,
required this.saveToHistory,
required this.quickSave,
required this.quickSaveFromFavorites,
required this.receivePin,
required this.autoFinish,
required this.minimizeToTray,
@@ -43,6 +43,8 @@ class SettingsStateMapper extends ClassMapperBase<SettingsState> {
static const Field<SettingsState, bool> _f$saveToHistory = Field('saveToHistory', _$saveToHistory);
static bool _$quickSave(SettingsState v) => v.quickSave;
static const Field<SettingsState, bool> _f$quickSave = Field('quickSave', _$quickSave);
static bool _$quickSaveFromFavorites(SettingsState v) => v.quickSaveFromFavorites;
static const Field<SettingsState, bool> _f$quickSaveFromFavorites = Field('quickSaveFromFavorites', _$quickSaveFromFavorites);
static String? _$receivePin(SettingsState v) => v.receivePin;
static const Field<SettingsState, String> _f$receivePin = Field('receivePin', _$receivePin);
static bool _$autoFinish(SettingsState v) => v.autoFinish;
@@ -79,6 +81,7 @@ class SettingsStateMapper extends ClassMapperBase<SettingsState> {
#saveToGallery: _f$saveToGallery,
#saveToHistory: _f$saveToHistory,
#quickSave: _f$quickSave,
#quickSaveFromFavorites: _f$quickSaveFromFavorites,
#receivePin: _f$receivePin,
#autoFinish: _f$autoFinish,
#minimizeToTray: _f$minimizeToTray,
@@ -105,6 +108,7 @@ class SettingsStateMapper extends ClassMapperBase<SettingsState> {
saveToGallery: data.dec(_f$saveToGallery),
saveToHistory: data.dec(_f$saveToHistory),
quickSave: data.dec(_f$quickSave),
quickSaveFromFavorites: data.dec(_f$quickSaveFromFavorites),
receivePin: data.dec(_f$receivePin),
autoFinish: data.dec(_f$autoFinish),
minimizeToTray: data.dec(_f$minimizeToTray),
@@ -174,6 +178,7 @@ abstract class SettingsStateCopyWith<$R, $In extends SettingsState, $Out> implem
bool? saveToGallery,
bool? saveToHistory,
bool? quickSave,
bool? quickSaveFromFavorites,
String? receivePin,
bool? autoFinish,
bool? minimizeToTray,
@@ -207,6 +212,7 @@ class _SettingsStateCopyWithImpl<$R, $Out> extends ClassCopyWithBase<$R, Setting
bool? saveToGallery,
bool? saveToHistory,
bool? quickSave,
bool? quickSaveFromFavorites,
Object? receivePin = $none,
bool? autoFinish,
bool? minimizeToTray,
@@ -230,6 +236,7 @@ class _SettingsStateCopyWithImpl<$R, $Out> extends ClassCopyWithBase<$R, Setting
if (saveToGallery != null) #saveToGallery: saveToGallery,
if (saveToHistory != null) #saveToHistory: saveToHistory,
if (quickSave != null) #quickSave: quickSave,
if (quickSaveFromFavorites != null) #quickSaveFromFavorites: quickSaveFromFavorites,
if (receivePin != $none) #receivePin: receivePin,
if (autoFinish != null) #autoFinish: autoFinish,
if (minimizeToTray != null) #minimizeToTray: minimizeToTray,
@@ -255,6 +262,7 @@ class _SettingsStateCopyWithImpl<$R, $Out> extends ClassCopyWithBase<$R, Setting
saveToGallery: data.get(#saveToGallery, or: $value.saveToGallery),
saveToHistory: data.get(#saveToHistory, or: $value.saveToHistory),
quickSave: data.get(#quickSave, or: $value.quickSave),
quickSaveFromFavorites: data.get(#quickSaveFromFavorites, or: $value.quickSaveFromFavorites),
receivePin: data.get(#receivePin, or: $value.receivePin),
autoFinish: data.get(#autoFinish, or: $value.autoFinish),
minimizeToTray: data.get(#minimizeToTray, or: $value.minimizeToTray),
+37 -16
View File
@@ -68,22 +68,43 @@ class ReceiveTab extends StatelessWidget {
Padding(
padding: const EdgeInsets.only(top: 10),
child: Center(
child: vm.quickSaveSettings
? ElevatedButton(
style: ElevatedButton.styleFrom(
backgroundColor: Theme.of(context).colorScheme.primary,
foregroundColor: Theme.of(context).colorScheme.onPrimary,
),
onPressed: () async => vm.onSetQuickSave(context, false),
child: Text('${t.general.quickSave}: ${t.general.on}'),
)
: TextButton(
style: TextButton.styleFrom(
foregroundColor: Colors.grey,
),
onPressed: () async => vm.onSetQuickSave(context, true),
child: Text('${t.general.quickSave}: ${t.general.off}'),
),
child: Column(
children: [
vm.quickSaveSettings
? ElevatedButton(
style: ElevatedButton.styleFrom(
backgroundColor: Theme.of(context).colorScheme.primary,
foregroundColor: Theme.of(context).colorScheme.onPrimary,
),
onPressed: () async => vm.onSetQuickSave(context, false),
child: Text('${t.general.quickSave}: ${t.general.on}'),
)
: TextButton(
style: TextButton.styleFrom(
foregroundColor: Colors.grey,
),
onPressed: () async => vm.onSetQuickSave(context, true),
child: Text('${t.general.quickSave}: ${t.general.off}'),
),
const SizedBox(height: 10),
vm.quickSaveFromFavoritesSettings
? ElevatedButton(
style: ElevatedButton.styleFrom(
backgroundColor: Theme.of(context).colorScheme.secondary,
foregroundColor: Theme.of(context).colorScheme.onSecondary,
),
onPressed: () async => vm.onSetQuickSaveFromFavorites(context, false),
child: Text('${t.general.quickSaveFromFavorites}: ${t.general.on}'),
)
: TextButton(
style: TextButton.styleFrom(
foregroundColor: Colors.grey,
),
onPressed: () async => vm.onSetQuickSaveFromFavorites(context, true),
child: Text('${t.general.quickSaveFromFavorites}: ${t.general.off}'),
),
],
),
),
),
const SizedBox(height: 15),
+13 -1
View File
@@ -4,6 +4,7 @@ import 'package:localsend_app/model/state/server/server_state.dart';
import 'package:localsend_app/provider/local_ip_provider.dart';
import 'package:localsend_app/provider/network/server/server_provider.dart';
import 'package:localsend_app/provider/settings_provider.dart';
import 'package:localsend_app/widget/dialogs/quick_save_from_favorites_notice.dart';
import 'package:localsend_app/widget/dialogs/quick_save_notice.dart';
import 'package:refena_flutter/refena_flutter.dart';
@@ -17,27 +18,31 @@ final _showHistoryButtonProvider = StateProvider<bool>((ref) => true, debugLabel
class ReceiveTabVm {
final String aliasSettings;
final bool quickSaveSettings;
final bool quickSaveFromFavoritesSettings;
final ServerState? serverState;
final List<String> localIps;
final bool showAdvanced;
final bool showHistoryButton;
final Future<void> Function() toggleAdvanced;
final Future<void> Function(BuildContext context, bool enable) onSetQuickSave;
final Future<void> Function(BuildContext context, bool enable) onSetQuickSaveFromFavorites;
const ReceiveTabVm({
required this.aliasSettings,
required this.quickSaveSettings,
required this.quickSaveFromFavoritesSettings,
required this.serverState,
required this.localIps,
required this.showAdvanced,
required this.showHistoryButton,
required this.toggleAdvanced,
required this.onSetQuickSave,
required this.onSetQuickSaveFromFavorites,
});
}
final receiveTabVmProvider = ViewProvider((ref) {
final (alias, quickSave) = ref.watch(settingsProvider.select((s) => (s.alias, s.quickSave)));
final (alias, quickSave, quickSaveFromFavorites) = ref.watch(settingsProvider.select((s) => (s.alias, s.quickSave, s.quickSaveFromFavorites)));
final networkInfo = ref.watch(localIpProvider).localIps;
final serverState = ref.watch(serverProvider);
final showAdvanced = ref.watch(_showAdvancedProvider);
@@ -46,6 +51,7 @@ final receiveTabVmProvider = ViewProvider((ref) {
return ReceiveTabVm(
aliasSettings: alias,
quickSaveSettings: quickSave,
quickSaveFromFavoritesSettings: quickSaveFromFavorites,
serverState: serverState,
localIps: networkInfo,
showAdvanced: showAdvanced,
@@ -66,5 +72,11 @@ final receiveTabVmProvider = ViewProvider((ref) {
await QuickSaveNotice.open(context);
}
},
onSetQuickSaveFromFavorites: (context, enable) async {
await ref.notifier(settingsProvider).setQuickSaveFromFavorites(enable);
if (enable && context.mounted) {
await QuickSaveFromFavoritesNotice.open(context);
}
},
);
});
+12
View File
@@ -20,6 +20,7 @@ import 'package:localsend_app/util/native/platform_check.dart';
import 'package:localsend_app/widget/custom_dropdown_button.dart';
import 'package:localsend_app/widget/dialogs/encryption_disabled_notice.dart';
import 'package:localsend_app/widget/dialogs/pin_dialog.dart';
import 'package:localsend_app/widget/dialogs/quick_save_from_favorites_notice.dart';
import 'package:localsend_app/widget/dialogs/quick_save_notice.dart';
import 'package:localsend_app/widget/dialogs/text_field_tv.dart';
import 'package:localsend_app/widget/labeled_checkbox.dart';
@@ -157,6 +158,17 @@ class SettingsTab extends StatelessWidget {
}
},
),
_BooleanEntry(
label: t.settingsTab.receive.quickSaveFromFavorites,
value: vm.settings.quickSaveFromFavorites,
onChanged: (b) async {
final old = vm.settings.quickSaveFromFavorites;
await ref.notifier(settingsProvider).setQuickSaveFromFavorites(b);
if (!old && b && context.mounted) {
await QuickSaveFromFavoritesNotice.open(context);
}
},
),
_BooleanEntry(
label: t.settingsTab.receive.requirePin,
value: vm.settings.receivePin != null,
@@ -251,7 +251,14 @@ class ReceiveController {
),
);
final quickSave = settings.quickSave && server.getState().session?.message == null;
bool quickSave = settings.quickSave && server.getState().session?.message == null;
final quickSaveFromFavorites = settings.quickSaveFromFavorites && server.getState().session?.message == null;
if (quickSaveFromFavorites) {
final bool isFavorite = server.ref.read(favoritesProvider).any((e) => e.fingerprint == dto.info.fingerprint);
if (isFavorite) {
quickSave = true;
}
}
final Map<String, String>? selection;
if (quickSave) {
// accept all files
@@ -528,7 +535,17 @@ class ReceiveController {
),
),
);
if (server.ref.read(settingsProvider).quickSave && server.getState().session?.message == null) {
final settings = server.ref.read(settingsProvider);
bool quickSave = settings.quickSave && server.getState().session?.message == null;
final quickSaveFromFavorites = settings.quickSaveFromFavorites && server.getState().session?.message == null;
if (quickSaveFromFavorites) {
// dto is not defined here. I must check sender fingerprint
final bool isFavorite = server.ref.read(favoritesProvider).any((e) => e.fingerprint == session.sender.fingerprint);
if (isFavorite) {
quickSave = true;
}
}
if (quickSave) {
// close the session **after** return of the response
Future.delayed(Duration.zero, () {
closeSession();
@@ -72,6 +72,7 @@ const _destinationKey = 'ls_destination';
const _saveToGallery = 'ls_save_to_gallery';
const _saveToHistory = 'ls_save_to_history';
const _quickSave = 'ls_quick_save';
const _quickSaveFromFavorites = 'ls_quick_save_from_favorites';
const _receivePin = 'ls_receive_pin';
const _autoFinish = 'ls_auto_finish';
const _minimizeToTray = 'ls_minimize_to_tray';
@@ -344,6 +345,14 @@ class PersistenceService {
await _prefs.setBool(_quickSave, quickSave);
}
bool isQuickSaveFromFavorites() {
return _prefs.getBool(_quickSaveFromFavorites) ?? false;
}
Future<void> setQuickSaveFromFavorites(bool quickSaveFromFavorites) async {
await _prefs.setBool(_quickSaveFromFavorites, quickSaveFromFavorites);
}
String? getReceivePin() {
return _prefs.getString(_receivePin);
}
+8
View File
@@ -40,6 +40,7 @@ class SettingsService extends PureNotifier<SettingsState> {
saveToGallery: _persistence.isSaveToGallery(),
saveToHistory: _persistence.isSaveToHistory(),
quickSave: _persistence.isQuickSave(),
quickSaveFromFavorites: _persistence.isQuickSaveFromFavorites(),
receivePin: _persistence.getReceivePin(),
autoFinish: _persistence.isAutoFinish(),
minimizeToTray: _persistence.isMinimizeToTray(),
@@ -130,6 +131,13 @@ class SettingsService extends PureNotifier<SettingsState> {
);
}
Future<void> setQuickSaveFromFavorites(bool quickSaveFromFavorites) async {
await _persistence.setQuickSaveFromFavorites(quickSaveFromFavorites);
state = state.copyWith(
quickSaveFromFavorites: quickSaveFromFavorites,
);
}
Future<void> setReceivePin(String? receivePin) async {
await _persistence.setReceivePin(receivePin);
state = state.copyWith(
@@ -0,0 +1,43 @@
import 'package:flutter/material.dart';
import 'package:localsend_app/gen/strings.g.dart';
import 'package:localsend_app/util/native/platform_check.dart';
import 'package:localsend_app/widget/dialogs/custom_bottom_sheet.dart';
import 'package:routerino/routerino.dart';
class QuickSaveFromFavoritesNotice extends StatelessWidget {
const QuickSaveFromFavoritesNotice({super.key});
static Future<void> open(BuildContext context) async {
if (checkPlatformIsDesktop()) {
await showDialog(
context: context,
builder: (_) => AlertDialog(
title: Text(t.dialogs.quickSaveFromFavoritesNotice.title),
content: Text(t.dialogs.quickSaveFromFavoritesNotice.content),
actions: [
TextButton(
onPressed: () => context.pop(),
child: Text(t.general.close),
)
],
),
);
} else {
await context.pushBottomSheet(() => const QuickSaveFromFavoritesNotice());
}
}
@override
Widget build(BuildContext context) {
return CustomBottomSheet(
title: t.dialogs.quickSaveFromFavoritesNotice.title,
description: t.dialogs.quickSaveFromFavoritesNotice.content,
child: Center(
child: ElevatedButton(
onPressed: () => context.popUntilRoot(),
child: Text(t.general.close),
),
),
);
}
}
+20
View File
@@ -400,6 +400,26 @@ class MockPersistenceService extends _i1.Mock implements _i3.PersistenceService
returnValueForMissingStub: _i4.Future<void>.value(),
) as _i4.Future<void>);
@override
bool isQuickSaveFromFavorites() => (super.noSuchMethod(
Invocation.method(
#isQuickSaveFromFavorites,
[],
),
returnValue: false,
returnValueForMissingStub: false,
) as bool);
@override
_i4.Future<void> setQuickSaveFromFavorites(bool? quickSaveFromFavorites) => (super.noSuchMethod(
Invocation.method(
#setQuickSaveFromFavorites,
[quickSaveFromFavorites],
),
returnValue: _i4.Future<void>.value(),
returnValueForMissingStub: _i4.Future<void>.value(),
) as _i4.Future<void>);
@override
_i4.Future<void> setReceivePin(String? pin) => (super.noSuchMethod(
Invocation.method(