mirror of
https://gitlab.com/famedly/fluffychat.git
synced 2024-11-18 01:49:50 +01:00
Merge branch 'soru/save-file-picker' into 'main'
feat: Add a proper file saver Closes #381 and #213 See merge request famedly/fluffychat!439
This commit is contained in:
commit
7b3d3781db
@ -2471,5 +2471,22 @@
|
||||
"@yourOwnUsername": {
|
||||
"type": "text",
|
||||
"placeholders": {}
|
||||
},
|
||||
"saveFile": "Save file",
|
||||
"@saveFile": {
|
||||
"type": "text",
|
||||
"placeholders": {}
|
||||
},
|
||||
"saveFileToFolder": "Save file to this foler",
|
||||
"@saveFileToFolder": {
|
||||
"type": "text",
|
||||
"placeholders": {}
|
||||
},
|
||||
"savedFileAs": "Saved file as {filename}",
|
||||
"@savedFileAs": {
|
||||
"type": "text",
|
||||
"placeholders": {
|
||||
"filename": {}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -24,8 +24,8 @@ class ImageViewerController extends State<ImageViewer> {
|
||||
VRouter.of(context).to('/rooms');
|
||||
}
|
||||
|
||||
/// Open this file with a system call.
|
||||
void openFileAction() => widget.event.openFile(context);
|
||||
/// Save this file with a system call.
|
||||
void saveFileAction() => widget.event.saveFile(context);
|
||||
|
||||
/// Go back if user swiped it away
|
||||
void onInteractionEnds(ScaleEndDetails endDetails) {
|
||||
|
@ -31,7 +31,7 @@ class ImageViewerView extends StatelessWidget {
|
||||
),
|
||||
IconButton(
|
||||
icon: Icon(Icons.download_outlined),
|
||||
onPressed: controller.openFileAction,
|
||||
onPressed: controller.saveFileAction,
|
||||
color: Colors.white,
|
||||
tooltip: L10n.of(context).downloadFile,
|
||||
),
|
||||
|
@ -6,12 +6,13 @@ import 'package:flutter_cache_manager/flutter_cache_manager.dart';
|
||||
import 'matrix_file_extension.dart';
|
||||
|
||||
extension LocalizedBody on Event {
|
||||
void openFile(BuildContext context) async {
|
||||
void saveFile(BuildContext context) async {
|
||||
final matrixFile = await showFutureLoadingDialog(
|
||||
context: context,
|
||||
future: () => downloadAndDecryptAttachmentCached(),
|
||||
);
|
||||
matrixFile.result?.open();
|
||||
|
||||
matrixFile.result?.save(context);
|
||||
}
|
||||
|
||||
IconData get statusIcon {
|
||||
|
@ -1,45 +1,53 @@
|
||||
import 'dart:io';
|
||||
|
||||
import 'package:android_path_provider/android_path_provider.dart';
|
||||
import 'package:matrix/matrix.dart';
|
||||
import 'package:fluffychat/utils/platform_infos.dart';
|
||||
import 'package:flutter/foundation.dart';
|
||||
import 'package:open_file/open_file.dart';
|
||||
import 'package:path_provider/path_provider.dart';
|
||||
import 'package:universal_html/html.dart' as html;
|
||||
import 'package:mime_type/mime_type.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:permission_handler/permission_handler.dart';
|
||||
import 'package:file_picker_cross/file_picker_cross.dart';
|
||||
import 'package:filesystem_picker/filesystem_picker.dart';
|
||||
import 'package:flutter_gen/gen_l10n/l10n.dart';
|
||||
|
||||
extension MatrixFileExtension on MatrixFile {
|
||||
void open() async {
|
||||
if (kIsWeb) {
|
||||
final fileName = name.split('/').last;
|
||||
final mimeType = mime(fileName);
|
||||
final element = html.document.createElement('a');
|
||||
element.setAttribute(
|
||||
'href', html.Url.createObjectUrlFromBlob(html.Blob([bytes])));
|
||||
element.setAttribute('target', '_blank');
|
||||
element.setAttribute('rel', 'noopener');
|
||||
element.setAttribute('download', fileName);
|
||||
element.setAttribute('type', mimeType);
|
||||
element.style.display = 'none';
|
||||
html.document.body.append(element);
|
||||
element.click();
|
||||
element.remove();
|
||||
void save(BuildContext context) async {
|
||||
if (PlatformInfos.isMobile &&
|
||||
!(await Permission.storage.request()).isGranted) return;
|
||||
final fileName = name.split('/').last;
|
||||
if (PlatformInfos.isAndroid) {
|
||||
final path = await FilesystemPicker.open(
|
||||
title: L10n.of(context).saveFile,
|
||||
context: context,
|
||||
rootDirectory: Directory('/sdcard/'),
|
||||
fsType: FilesystemType.folder,
|
||||
pickText: L10n.of(context).saveFileToFolder,
|
||||
folderIconColor: Theme.of(context).primaryColor,
|
||||
requestPermission: () async =>
|
||||
await Permission.storage.request().isGranted,
|
||||
);
|
||||
if (path != null) {
|
||||
// determine a unique filename
|
||||
// somefile-number.extension, e.g. helloworld-1.txt
|
||||
var file = File('$path/$fileName');
|
||||
var i = 0;
|
||||
var extension = '';
|
||||
if (fileName.contains('.')) {
|
||||
extension = fileName.substring(fileName.lastIndexOf('.'));
|
||||
}
|
||||
final fileNameWithoutExtension =
|
||||
fileName.substring(0, fileName.lastIndexOf('.'));
|
||||
while (await file.exists()) {
|
||||
i++;
|
||||
file = File('$path/$fileNameWithoutExtension-$i$extension');
|
||||
}
|
||||
await file.writeAsBytes(bytes);
|
||||
ScaffoldMessenger.of(context).showSnackBar(SnackBar(
|
||||
content:
|
||||
Text(L10n.of(context).savedFileAs(file.path.split('/').last))));
|
||||
}
|
||||
} else {
|
||||
if (PlatformInfos.isMobile &&
|
||||
!(await Permission.storage.request()).isGranted) return;
|
||||
final downloadsDir = PlatformInfos.isDesktop
|
||||
? (await getDownloadsDirectory()).path
|
||||
: Platform.isAndroid
|
||||
? (await AndroidPathProvider.downloadsPath)
|
||||
: (await getApplicationDocumentsDirectory()).path;
|
||||
|
||||
final file = File(downloadsDir + '/' + name.split('/').last);
|
||||
file.writeAsBytesSync(bytes);
|
||||
await OpenFile.open(file.path);
|
||||
final file = FilePickerCross(bytes);
|
||||
await file.exportToStorage(fileName: fileName);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
MatrixFile get detectFileType {
|
||||
|
@ -24,7 +24,7 @@ class MessageDownloadContent extends StatelessWidget {
|
||||
primary: Theme.of(context).scaffoldBackgroundColor,
|
||||
onPrimary: Theme.of(context).textTheme.bodyText1.color,
|
||||
),
|
||||
onPressed: () => event.openFile(context),
|
||||
onPressed: () => event.saveFile(context),
|
||||
child: Row(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
children: [
|
||||
|
28
pubspec.lock
28
pubspec.lock
@ -29,13 +29,6 @@ packages:
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "1.5.0"
|
||||
android_path_provider:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
name: android_path_provider
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "0.2.1"
|
||||
animations:
|
||||
dependency: transitive
|
||||
description:
|
||||
@ -297,6 +290,13 @@ packages:
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "0.0.2"
|
||||
filesystem_picker:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
name: filesystem_picker
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "1.0.4"
|
||||
firebase_core:
|
||||
dependency: transitive
|
||||
description:
|
||||
@ -653,13 +653,6 @@ packages:
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "1.0.0"
|
||||
mime_type:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
name: mime_type
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "1.0.0"
|
||||
moor:
|
||||
dependency: transitive
|
||||
description:
|
||||
@ -711,13 +704,6 @@ packages:
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "2.0.0"
|
||||
open_file:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
name: open_file
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "3.2.1"
|
||||
open_noti_settings:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
|
@ -9,7 +9,6 @@ environment:
|
||||
dependencies:
|
||||
adaptive_dialog: ^1.0.1
|
||||
adaptive_theme: ^2.2.0
|
||||
android_path_provider: ^0.2.1
|
||||
audioplayers: ^0.19.1
|
||||
cached_network_image: ^3.0.0
|
||||
cupertino_icons: any
|
||||
@ -21,6 +20,7 @@ dependencies:
|
||||
url: https://gitlab.com/famedly/libraries/fcm_shared_isolate.git
|
||||
ref: main
|
||||
file_picker_cross: ^4.4.2
|
||||
filesystem_picker: ^1.0.4
|
||||
flutter:
|
||||
sdk: flutter
|
||||
flutter_app_badger: ^1.2.0
|
||||
@ -43,12 +43,10 @@ dependencies:
|
||||
intl: any
|
||||
localstorage: ^4.0.0+1
|
||||
matrix: ^0.1.7
|
||||
mime_type: ^1.0.0
|
||||
native_imaging:
|
||||
git:
|
||||
url: https://gitlab.com/famedly/libraries/native_imaging.git
|
||||
ref: master
|
||||
open_file: ^3.2.1
|
||||
open_noti_settings: ^0.2.0
|
||||
package_info_plus: ^1.0.3
|
||||
path_provider: ^2.0.2
|
||||
|
Loading…
Reference in New Issue
Block a user