Check directory exists when downloading

This commit is contained in:
Hillel Coren 2023-10-22 17:54:54 +03:00
parent ac91c104d7
commit a301b0e839
6 changed files with 69 additions and 45 deletions

View File

@ -34,9 +34,9 @@ import 'package:invoiceninja_flutter/redux/vendor/vendor_actions.dart';
import 'package:invoiceninja_flutter/ui/app/entities/entity_actions_dialog.dart';
import 'package:invoiceninja_flutter/utils/completers.dart';
import 'package:invoiceninja_flutter/utils/dialogs.dart';
import 'package:invoiceninja_flutter/utils/files.dart';
import 'package:invoiceninja_flutter/utils/localization.dart';
import 'package:invoiceninja_flutter/utils/platforms.dart';
import 'package:path_provider/path_provider.dart';
import 'package:pinch_zoom/pinch_zoom.dart';
import 'package:printing/printing.dart';
@ -321,7 +321,7 @@ void handleDocumentAction(
}
final store = StoreProvider.of<AppState>(context!);
final localization = AppLocalization.of(context);
final localization = AppLocalization.of(context)!;
final documentIds = documents.map((document) => document.id).toList();
final document = store.state.documentState.map[documentIds.first]!;
@ -331,19 +331,19 @@ void handleDocumentAction(
break;
case EntityAction.restore:
final message = documentIds.length > 1
? localization!.restoredDocuments
? localization.restoredDocuments
.replaceFirst(':value', ':count')
.replaceFirst(':count', documentIds.length.toString())
: localization!.restoredDocument;
: localization.restoredDocument;
store.dispatch(RestoreDocumentRequest(
snackBarCompleter<Null>(message), documentIds));
break;
case EntityAction.archive:
final message = documentIds.length > 1
? localization!.archivedDocuments
? localization.archivedDocuments
.replaceFirst(':value', ':count')
.replaceFirst(':count', documentIds.length.toString())
: localization!.archivedDocument;
: localization.archivedDocument;
store.dispatch(ArchiveDocumentRequest(
snackBarCompleter<Null>(message), documentIds));
break;
@ -386,7 +386,7 @@ void handleDocumentAction(
DownloadDocumentsRequest(
documentIds: documentIds,
completer: snackBarCompleter<Null>(
localization!.exportedData,
localization.exportedData,
),
),
);
@ -402,7 +402,7 @@ void handleDocumentAction(
actions: [
TextButton(
onPressed: () => Navigator.of(context).pop(),
child: Text(localization!.close.toUpperCase())),
child: Text(localization.close.toUpperCase())),
],
content: document.isImage
? PinchZoom(
@ -440,27 +440,26 @@ void handleDocumentAction(
WebUtils.downloadBinaryFile(document!.name, document.data!);
}
} else {
final directory = await (isDesktopOS()
? getDownloadsDirectory() as FutureOr<file.Directory>
: getApplicationDocumentsDirectory());
final directory = await getAppDownloadDirectory();
if (directory != null) {
String filePath =
'$directory/${file.Platform.pathSeparator}${document!.name}';
String filePath =
'${directory.path}${file.Platform.pathSeparator}${document!.name}';
if (file.File(filePath).existsSync()) {
final extension = document.name.split('.').last;
final timestamp = DateTime.now().millisecondsSinceEpoch;
filePath = filePath.replaceFirst(
'.$extension', '_$timestamp.$extension');
}
if (file.File(filePath).existsSync()) {
final extension = document.name.split('.').last;
final timestamp = DateTime.now().millisecondsSinceEpoch;
filePath =
filePath.replaceFirst('.$extension', '_$timestamp.$extension');
}
await File(filePath).writeAsBytes(document.data!);
await File(filePath).writeAsBytes(document.data!);
if (isDesktopOS()) {
showToast(localization!.fileSavedInPath
.replaceFirst(':path', directory.path));
} else {
await Share.shareXFiles([XFile(filePath)]);
if (isDesktopOS()) {
showToast(localization.fileSavedInPath
.replaceFirst(':path', directory));
} else {
await Share.shareXFiles([XFile(filePath)]);
}
}
}
}

View File

@ -21,8 +21,8 @@ import 'package:invoiceninja_flutter/ui/app/buttons/elevated_button.dart';
import 'package:invoiceninja_flutter/ui/app/dialogs/error_dialog.dart';
import 'package:invoiceninja_flutter/ui/app/forms/date_picker.dart';
import 'package:invoiceninja_flutter/ui/app/multiselect.dart';
import 'package:invoiceninja_flutter/utils/files.dart';
import 'package:invoiceninja_flutter/utils/formatting.dart';
import 'package:path_provider/path_provider.dart';
import 'package:printing/printing.dart';
// Project imports:
@ -352,16 +352,14 @@ class _ClientPdfViewState extends State<ClientPdfView> {
WebUtils.downloadBinaryFile(
fileName, _response!.bodyBytes);
} else {
final directory = await (isDesktopOS()
? getDownloadsDirectory()
: getApplicationDocumentsDirectory());
final directory = await getAppDownloadDirectory();
if (directory == null) {
return;
}
String filePath =
'${directory.path}${file.Platform.pathSeparator}$fileName';
'$directory${file.Platform.pathSeparator}$fileName';
if (file.File(filePath).existsSync()) {
final timestamp =
@ -375,7 +373,7 @@ class _ClientPdfViewState extends State<ClientPdfView> {
if (isDesktopOS()) {
showToast(localization.fileSavedInPath
.replaceFirst(':path', directory.path));
.replaceFirst(':path', directory));
} else {
await Share.shareXFiles([XFile(filePath)]);
}

View File

@ -14,7 +14,7 @@ import 'package:http/http.dart' as http;
import 'package:http/http.dart';
import 'package:invoiceninja_flutter/main_app.dart';
import 'package:invoiceninja_flutter/ui/app/dialogs/error_dialog.dart';
import 'package:path_provider/path_provider.dart';
import 'package:invoiceninja_flutter/utils/files.dart';
import 'package:printing/printing.dart';
import 'package:share_plus/share_plus.dart';
import 'package:url_launcher/url_launcher.dart';
@ -269,16 +269,15 @@ class _InvoicePdfViewState extends State<InvoicePdfView> {
WebUtils.downloadBinaryFile(
fileName, _response!.bodyBytes);
} else {
final directory = await (isDesktopOS()
? getDownloadsDirectory()
: getApplicationDocumentsDirectory());
final directory =
await getAppDownloadDirectory();
if (directory == null) {
return;
}
String filePath =
'${directory.path}${file.Platform.pathSeparator}$fileName';
'$directory${file.Platform.pathSeparator}$fileName';
if (file.File(filePath).existsSync()) {
final timestamp =
@ -293,7 +292,7 @@ class _InvoicePdfViewState extends State<InvoicePdfView> {
if (isDesktopOS()) {
showToast(localization.fileSavedInPath
.replaceFirst(':path', directory.path));
.replaceFirst(':path', directory));
} else {
await Share.shareXFiles([XFile(filePath)]);
}

View File

@ -18,9 +18,9 @@ import 'package:invoiceninja_flutter/ui/reports/recurring_expense_report.dart';
import 'package:invoiceninja_flutter/ui/reports/recurring_invoice_report.dart';
import 'package:invoiceninja_flutter/ui/reports/transaction_report.dart';
import 'package:invoiceninja_flutter/ui/reports/vendor_report.dart';
import 'package:invoiceninja_flutter/utils/files.dart';
import 'package:invoiceninja_flutter/utils/platforms.dart';
import 'package:memoize/memoize.dart';
import 'package:path_provider/path_provider.dart';
import 'package:redux/redux.dart';
// Project imports:
@ -511,22 +511,19 @@ class ReportsScreenVM {
if (kIsWeb) {
WebUtils.downloadTextFile(filename, csvData);
} else {
final directory = await (isDesktopOS()
? getDownloadsDirectory()
: getApplicationDocumentsDirectory());
final directory = await getAppDownloadDirectory();
if (directory == null) {
return;
}
final filePath =
directory.path + file.Platform.pathSeparator + filename;
final filePath = directory + file.Platform.pathSeparator + filename;
final csvFile = file.File(filePath);
await csvFile.writeAsString(csvData);
if (isDesktopOS()) {
showToast(localization!.fileSavedInPath
.replaceFirst(':path', directory.path));
.replaceFirst(':path', directory));
} else {
await Share.shareXFiles([XFile(filePath)]);
}

View File

@ -7,6 +7,10 @@ import 'package:flutter/foundation.dart';
// Package imports:
import 'package:file_picker/file_picker.dart';
import 'package:http/http.dart';
import 'package:invoiceninja_flutter/main_app.dart';
import 'package:invoiceninja_flutter/utils/dialogs.dart';
import 'package:invoiceninja_flutter/utils/localization.dart';
import 'package:path_provider/path_provider.dart';
import 'package:permission_handler/permission_handler.dart';
// Project imports:
@ -77,3 +81,24 @@ Future<List<MultipartFile>?> _pickFiles({
return null;
}
Future<String?> getAppDownloadDirectory() async {
final directory = await (isDesktopOS()
? getDownloadsDirectory()
: getApplicationDocumentsDirectory());
if (directory == null) {
return null;
}
if (!Directory(directory.path).existsSync()) {
showErrorDialog(
message: AppLocalization.of(navigatorKey.currentContext!)!
.directoryDoesNotExist
.replaceFirst(':value', directory.path));
return null;
}
return directory.path;
}

View File

@ -18,6 +18,8 @@ mixin LocalizationsProvider on LocaleCodeAware {
static final Map<String, Map<String, String>> _localizedValues = {
'en': {
// STARTER: lang key - do not remove comment
'directory_does_not_exist':
'The download directory 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',
@ -109898,6 +109900,10 @@ 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']!;
// STARTER: lang field - do not remove comment
String lookup(String? key) {