mirror of
https://github.com/localsend/localsend.git
synced 2026-08-07 07:14:52 +00:00
Implemented feature to accept quickSave if sender is in favorites (#1698)
This commit is contained in:
@@ -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"
|
||||
},
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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),
|
||||
|
||||
@@ -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),
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
},
|
||||
);
|
||||
});
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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),
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -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(
|
||||
|
||||
Reference in New Issue
Block a user