Feature Request: Support for setting download location per-device in Windows App #563
This commit is contained in:
parent
16ccd02ad8
commit
ec2b87933a
|
|
@ -188,6 +188,7 @@ class UpdateUserPreferences implements PersistPrefs {
|
|||
this.enableTooltips,
|
||||
this.flexibleSearch,
|
||||
this.enableNativeBrowser,
|
||||
this.downloadsFolder,
|
||||
this.statementIncludes,
|
||||
});
|
||||
|
||||
|
|
@ -219,6 +220,7 @@ class UpdateUserPreferences implements PersistPrefs {
|
|||
final bool? enableTooltips;
|
||||
final bool? flexibleSearch;
|
||||
final bool? enableNativeBrowser;
|
||||
final String? downloadsFolder;
|
||||
final BuiltList<String>? statementIncludes;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -93,6 +93,7 @@ PrefState prefReducer(
|
|||
longPressReducer(state.longPressSelectionIsDefault, action)
|
||||
..tapSelectedToEdit =
|
||||
tapSelectedToEditReducer(state.tapSelectedToEdit, action)
|
||||
..donwloadsFolder = downloadsFolderReducer(state.donwloadsFolder, action)
|
||||
..requireAuthentication =
|
||||
requireAuthenticationReducer(state.requireAuthentication, action)
|
||||
..colorTheme = colorThemeReducer(state.colorTheme, action)
|
||||
|
|
@ -412,6 +413,12 @@ Reducer<bool> tapSelectedToEditReducer = combineReducers([
|
|||
}),
|
||||
]);
|
||||
|
||||
Reducer<String> downloadsFolderReducer = combineReducers([
|
||||
TypedReducer<String, UpdateUserPreferences>((downloadsFolder, action) {
|
||||
return action.downloadsFolder ?? downloadsFolder;
|
||||
}),
|
||||
]);
|
||||
|
||||
Reducer<bool> isPreviewVisibleReducer = combineReducers([
|
||||
TypedReducer<bool, TogglePreviewSidebar>((value, action) {
|
||||
return !value;
|
||||
|
|
|
|||
|
|
@ -1,4 +1,7 @@
|
|||
// Flutter imports:
|
||||
import 'dart:io';
|
||||
|
||||
import 'package:filesystem_picker/filesystem_picker.dart';
|
||||
import 'package:flutter/foundation.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter/services.dart' hide LiveText;
|
||||
|
|
@ -7,6 +10,8 @@ import 'package:flutter/services.dart' hide LiveText;
|
|||
import 'package:flutter_redux/flutter_redux.dart';
|
||||
import 'package:flutter_styled_toast/flutter_styled_toast.dart';
|
||||
import 'package:invoiceninja_flutter/redux/company/company_selectors.dart';
|
||||
import 'package:invoiceninja_flutter/ui/app/forms/decorated_form_field.dart';
|
||||
import 'package:invoiceninja_flutter/utils/files.dart';
|
||||
import 'package:invoiceninja_flutter/utils/formatting.dart';
|
||||
import 'package:material_design_icons_flutter/material_design_icons_flutter.dart';
|
||||
import 'package:timeago/timeago.dart' as timeago;
|
||||
|
|
@ -50,6 +55,11 @@ class _DeviceSettingsState extends State<DeviceSettings>
|
|||
|
||||
TabController? _controller;
|
||||
FocusScopeNode? _focusNode;
|
||||
String _defaultDownloadsFolder = '';
|
||||
|
||||
final _downloadsFolderController = TextEditingController();
|
||||
|
||||
List<TextEditingController> _controllers = [];
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
|
|
@ -61,6 +71,37 @@ class _DeviceSettingsState extends State<DeviceSettings>
|
|||
_controller!.addListener(_onTabChanged);
|
||||
}
|
||||
|
||||
@override
|
||||
void didChangeDependencies() async {
|
||||
super.didChangeDependencies();
|
||||
|
||||
_controllers = [
|
||||
_downloadsFolderController,
|
||||
];
|
||||
|
||||
_controllers
|
||||
.forEach((dynamic controller) => controller.removeListener(_onChanged));
|
||||
|
||||
final prefState = widget.viewModel.state.prefState;
|
||||
_downloadsFolderController.text = prefState.donwloadsFolder;
|
||||
|
||||
_controllers
|
||||
.forEach((dynamic controller) => controller.addListener(_onChanged));
|
||||
|
||||
_defaultDownloadsFolder = prefState.donwloadsFolder.isEmpty
|
||||
? await getAppDownloadDirectory() ?? ''
|
||||
: prefState.donwloadsFolder;
|
||||
}
|
||||
|
||||
void _onChanged() async {
|
||||
widget.viewModel
|
||||
.onDownloadsFolderChanged(context, _downloadsFolderController.text);
|
||||
|
||||
_defaultDownloadsFolder = _downloadsFolderController.text.isEmpty
|
||||
? await getAppDownloadDirectory() ?? ''
|
||||
: _downloadsFolderController.text;
|
||||
}
|
||||
|
||||
void _onTabChanged() {
|
||||
final store = StoreProvider.of<AppState>(context);
|
||||
store.dispatch(UpdateSettingsTab(tabIndex: _controller!.index));
|
||||
|
|
@ -226,6 +267,41 @@ class _DeviceSettingsState extends State<DeviceSettings>
|
|||
),
|
||||
FormCard(
|
||||
children: <Widget>[
|
||||
if (!kIsWeb)
|
||||
Row(
|
||||
mainAxisAlignment: MainAxisAlignment.center,
|
||||
children: [
|
||||
Expanded(
|
||||
child: DecoratedFormField(
|
||||
label: localization.downloadsFolder,
|
||||
keyboardType: TextInputType.text,
|
||||
hint: _defaultDownloadsFolder,
|
||||
controller: _downloadsFolderController,
|
||||
),
|
||||
),
|
||||
SizedBox(width: 20),
|
||||
OutlinedButton(
|
||||
onPressed: () async {
|
||||
final folder = await FilesystemPicker.open(
|
||||
context: context,
|
||||
fsType: FilesystemType.folder,
|
||||
rootDirectory: Directory(Platform.pathSeparator),
|
||||
directory: Directory(_defaultDownloadsFolder),
|
||||
title: localization.downloadsFolder,
|
||||
pickText: localization.saveFilesToThisFolder,
|
||||
);
|
||||
|
||||
if ((folder ?? '').isNotEmpty) {
|
||||
_downloadsFolderController.text = folder!;
|
||||
}
|
||||
},
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.all(10),
|
||||
child: Text(localization.select),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
Padding(
|
||||
padding: const EdgeInsets.only(bottom: 10),
|
||||
child: AppDropdownButton<double>(
|
||||
|
|
|
|||
|
|
@ -61,6 +61,7 @@ class DeviceSettingsVM {
|
|||
required this.onEnableTouchEventsChanged,
|
||||
required this.onEnableTooltipsChanged,
|
||||
required this.onEnableFlexibleSearchChanged,
|
||||
required this.onDownloadsFolderChanged,
|
||||
});
|
||||
|
||||
static DeviceSettingsVM fromStore(Store<AppState> store) {
|
||||
|
|
@ -98,6 +99,9 @@ class DeviceSettingsVM {
|
|||
onTapSelectedChanged: (context, value) async {
|
||||
store.dispatch(UpdateUserPreferences(tapSelectedToEdit: value));
|
||||
},
|
||||
onDownloadsFolderChanged: (context, value) async {
|
||||
store.dispatch(UpdateUserPreferences(downloadsFolder: value));
|
||||
},
|
||||
onEnableTouchEventsChanged: (context, value) async {
|
||||
store.dispatch(UpdateUserPreferences(enableTouchEvents: value));
|
||||
store.dispatch(UpdatedSetting());
|
||||
|
|
@ -221,5 +225,6 @@ class DeviceSettingsVM {
|
|||
final Function(BuildContext, bool) onEnableTooltipsChanged;
|
||||
final Function(BuildContext, bool) onEnableFlexibleSearchChanged;
|
||||
final Function(BuildContext, double) onTextScaleFactorChanged;
|
||||
final Function(BuildContext, String) onDownloadsFolderChanged;
|
||||
final Future<bool> authenticationSupported;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -505,6 +505,7 @@ class SettingsSearch extends StatelessWidget {
|
|||
'show_pdf_preview',
|
||||
'pdf_preview_location#2022-10-24',
|
||||
'refresh_data',
|
||||
'downloads_folder#2023-10-29'
|
||||
],
|
||||
[
|
||||
'dark_mode',
|
||||
|
|
|
|||
|
|
@ -107,7 +107,7 @@ Future<String?> getAppDownloadDirectory() async {
|
|||
if (!Directory(path).existsSync()) {
|
||||
showErrorDialog(
|
||||
message: AppLocalization.of(navigatorKey.currentContext!)!
|
||||
.directoryDoesNotExist
|
||||
.downloadsFolderDoesNotExist
|
||||
.replaceFirst(':value', path));
|
||||
|
||||
return null;
|
||||
|
|
|
|||
|
|
@ -18,10 +18,12 @@ mixin LocalizationsProvider on LocaleCodeAware {
|
|||
static final Map<String, Map<String, String>> _localizedValues = {
|
||||
'en': {
|
||||
// STARTER: lang key - do not remove comment
|
||||
'total_invoiced_quotes': 'Invoiced Quotes',
|
||||
'save_files_to_this_folder': 'Save files to this folder',
|
||||
'downloads_folder': 'Downloads Folder',
|
||||
'total_invoiced_quotes': 'Invoiced Quotes',
|
||||
'total_invoice_paid_quotes': 'Invoice Paid Quotes',
|
||||
'directory_does_not_exist':
|
||||
'The download directory does not exist :value',
|
||||
'downloads_folder_does_not_exist':
|
||||
'The downloads folder does not exist :value',
|
||||
'user_logged_in_notification': 'User Logged in Notification',
|
||||
'user_logged_in_notification_help':
|
||||
'Send an email when logging in from a new location',
|
||||
|
|
@ -109902,20 +109904,27 @@ mixin LocalizationsProvider on LocaleCodeAware {
|
|||
_localizedValues[localeCode]!['user_logged_in_notification_help'] ??
|
||||
_localizedValues['en']!['user_logged_in_notification_help']!;
|
||||
|
||||
String get directoryDoesNotExist =>
|
||||
_localizedValues[localeCode]!['directory_does_not_exist'] ??
|
||||
_localizedValues['en']!['directory_does_not_exist']!;
|
||||
String get downloadsFolderDoesNotExist =>
|
||||
_localizedValues[localeCode]!['downloads_folder_does_not_exist'] ??
|
||||
_localizedValues['en']!['downloads_folder_does_not_exist']!;
|
||||
|
||||
String get totalInvoicedQuotes =>
|
||||
String get totalInvoicedQuotes =>
|
||||
_localizedValues[localeCode]!['total_invoiced_quotes'] ??
|
||||
_localizedValues['en']!['total_invoiced_quotes']!;
|
||||
|
||||
String get totalInvoicePaidQuotes =>
|
||||
String get totalInvoicePaidQuotes =>
|
||||
_localizedValues[localeCode]!['total_invoice_paid_quotes'] ??
|
||||
_localizedValues['en']!['total_invoice_paid_quotes']!;
|
||||
|
||||
String get downloadsFolder =>
|
||||
_localizedValues[localeCode]!['downloads_folder'] ??
|
||||
_localizedValues['en']!['downloads_folder']!;
|
||||
|
||||
// STARTER: lang field - do not remove comment
|
||||
String get saveFilesToThisFolder =>
|
||||
_localizedValues[localeCode]!['save_files_to_this_folder'] ??
|
||||
_localizedValues['en']!['save_files_to_this_folder']!;
|
||||
|
||||
// STARTER: lang field - do not remove comment
|
||||
|
||||
String lookup(String? key) {
|
||||
final lookupKey = toSnakeCase(key);
|
||||
|
|
|
|||
|
|
@ -88,6 +88,7 @@ dependencies:
|
|||
# quick_actions: ^0.2.1
|
||||
# idb_shim: ^1.11.1+1
|
||||
collection: ^1.15.0-nullsafety.4
|
||||
filesystem_picker: ^4.0.0
|
||||
|
||||
dependency_overrides:
|
||||
intl: any
|
||||
|
|
|
|||
|
|
@ -386,6 +386,14 @@ packages:
|
|||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "0.9.3+1"
|
||||
filesystem_picker:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
name: filesystem_picker
|
||||
sha256: "37ab68968420c2073b68e002cae786d00ef1cfe18bd2b7255640338a0c47aa9a"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "4.0.0"
|
||||
fixnum:
|
||||
dependency: transitive
|
||||
description:
|
||||
|
|
|
|||
|
|
@ -94,6 +94,7 @@ dependencies:
|
|||
# quick_actions: ^0.2.1
|
||||
# idb_shim: ^1.11.1+1
|
||||
collection: ^1.15.0-nullsafety.4
|
||||
filesystem_picker: ^4.0.0
|
||||
|
||||
dependency_overrides:
|
||||
intl: any
|
||||
|
|
|
|||
Loading…
Reference in New Issue