From 7d437d5c3a34a8681c372570fc366e869f0b2090 Mon Sep 17 00:00:00 2001 From: Jagandeep Brar Date: Mon, 24 Oct 2022 23:13:27 -0500 Subject: [PATCH] feat(web): support local filesystem read/save actions --- .../getting-started/platform-restrictions.mdx | 9 ++- lib/modules/nzbget/routes/nzbget.dart | 5 +- lib/modules/sabnzbd/routes/sabnzbd.dart | 5 +- lib/system/filesystem/file.dart | 8 +-- .../filesystem/platform/filesystem_html.dart | 65 +++++++++++++++++-- .../filesystem/platform/filesystem_io.dart | 5 +- 6 files changed, 75 insertions(+), 22 deletions(-) diff --git a/docs/getting-started/platform-restrictions.mdx b/docs/getting-started/platform-restrictions.mdx index aea93450f..1fff7f823 100644 --- a/docs/getting-started/platform-restrictions.mdx +++ b/docs/getting-started/platform-restrictions.mdx @@ -20,11 +20,10 @@ The tables below showcases which modules or features may not be supported on eac ## Feature Support -| Feature | Android | iOS | Linux | macOS | Windows | Web (Hosted) | Web (Self-Hosted) | -| :--------------------: | :-----: | :-: | :---: | :---: | :-----: | :----------: | :---------------: | -| Local Backup & Restore | ✅ | ✅ | ✅ | ✅ | ✅ | ❌ | ❌ | -| LunaSea Accounts | ✅ | ✅ | ❌ | ✅ | ❌ | ✅ | ❌ | -| Notifications | ✅ | ✅ | ❌ | ✅ | ❌ | ✅ | ❌ | +| Feature | Android | iOS | Linux | macOS | Windows | Web (Hosted) | Web (Self-Hosted) | +| :--------------: | :-----: | :-: | :---: | :---: | :-----: | :----------: | :---------------: | +| LunaSea Accounts | ✅ | ✅ | ❌ | ✅ | ❌ | ✅ | ❌ | +| Notifications | ✅ | ✅ | ❌ | ✅ | ❌ | ✅ | ❌ | ## Web-Specific Restrictions diff --git a/lib/modules/nzbget/routes/nzbget.dart b/lib/modules/nzbget/routes/nzbget.dart index b0bb2414e..0537ea46d 100644 --- a/lib/modules/nzbget/routes/nzbget.dart +++ b/lib/modules/nzbget/routes/nzbget.dart @@ -166,13 +166,12 @@ class _State extends State { 'nzb', ]); if (_file != null) { - String _name = _file.path.substring(_file.path.lastIndexOf('/') + 1); if (_file.data.isNotEmpty) { - await _api.uploadFile(_file.data, _name).then((value) { + await _api.uploadFile(_file.data, _file.name).then((value) { _refreshKeys[0]?.currentState?.show(); showLunaSuccessSnackBar( title: 'Uploaded NZB (File)', - message: _name, + message: _file.name, ); }); } else { diff --git a/lib/modules/sabnzbd/routes/sabnzbd.dart b/lib/modules/sabnzbd/routes/sabnzbd.dart index 28e515064..45cc4a5a8 100644 --- a/lib/modules/sabnzbd/routes/sabnzbd.dart +++ b/lib/modules/sabnzbd/routes/sabnzbd.dart @@ -219,13 +219,12 @@ class _State extends State { 'gz', ]); if (_file != null) { - String _name = _file.path.substring(_file.path.lastIndexOf('/') + 1); if (_file.data.isNotEmpty) { - await _api.uploadFile(_file.data, _name).then((value) { + await _api.uploadFile(_file.data, _file.name).then((value) { _refreshKeys[0]?.currentState?.show(); showLunaSuccessSnackBar( title: 'Uploaded NZB (File)', - message: _name, + message: _file.name, ); }); } else { diff --git a/lib/system/filesystem/file.dart b/lib/system/filesystem/file.dart index 3f036d314..bebde41bc 100644 --- a/lib/system/filesystem/file.dart +++ b/lib/system/filesystem/file.dart @@ -1,11 +1,11 @@ class LunaFile { - String path; - String name; List data; + String name; + String? path; LunaFile({ - required this.path, - required this.name, required this.data, + required this.name, + this.path, }); } diff --git a/lib/system/filesystem/platform/filesystem_html.dart b/lib/system/filesystem/platform/filesystem_html.dart index 88a95e946..5dfe03634 100644 --- a/lib/system/filesystem/platform/filesystem_html.dart +++ b/lib/system/filesystem/platform/filesystem_html.dart @@ -1,6 +1,61 @@ -// ignore: always_use_package_imports -import '../filesystem.dart'; +// ignore: avoid_web_libraries_in_flutter +import 'dart:html'; +import 'package:file_picker/file_picker.dart'; +import 'package:flutter/material.dart'; +import 'package:lunasea/system/filesystem/file.dart'; +import 'package:lunasea/system/filesystem/filesystem.dart'; +import 'package:lunasea/system/logger.dart'; +import 'package:lunasea/vendor.dart'; +import 'package:lunasea/widgets/ui.dart'; -bool isPlatformSupported() => false; -LunaFileSystem getFileSystem() => - throw UnsupportedError('LunaFileSystem unsupported'); +bool isPlatformSupported() => true; +LunaFileSystem getFileSystem() { + if (isPlatformSupported()) return _Web(); + throw UnsupportedError('LunaFileSystem unsupported'); +} + +class _Web implements LunaFileSystem { + @override + Future nuke() async {} + + @override + Future save(BuildContext context, String name, List data) async { + try { + final blob = Blob([utf8.decode(data)]); + final anchor = AnchorElement(href: Url.createObjectUrlFromBlob(blob)); + anchor.setAttribute('download', name); + anchor.click(); + return true; + } catch (error, stack) { + LunaLogger().error('Failed to save to filesystem', error, stack); + rethrow; + } + } + + @override + Future read(BuildContext context, List extensions) async { + try { + final result = await FilePicker.platform.pickFiles(withData: true); + + if (result?.files.isNotEmpty ?? false) { + String? _ext = result!.files[0].extension; + if (LunaFileSystem.isValidExtension(extensions, _ext)) { + return LunaFile( + name: result.files[0].name, + data: result.files[0].bytes!, + ); + } else { + showLunaErrorSnackBar( + title: 'lunasea.InvalidFileTypeSelected'.tr(), + message: extensions.map((s) => '.$s').join(', '), + ); + } + } + + return null; + } catch (error, stack) { + LunaLogger().error('Failed to read from filesystem', error, stack); + rethrow; + } + } +} diff --git a/lib/system/filesystem/platform/filesystem_io.dart b/lib/system/filesystem/platform/filesystem_io.dart index a4005cd1d..d68b32383 100644 --- a/lib/system/filesystem/platform/filesystem_io.dart +++ b/lib/system/filesystem/platform/filesystem_io.dart @@ -5,6 +5,7 @@ import 'package:lunasea/database/database.dart'; import 'package:lunasea/vendor.dart'; import 'package:path_provider/path_provider.dart'; import 'package:share_plus/share_plus.dart'; +import 'package:cross_file/cross_file.dart'; import 'package:lunasea/widgets/ui.dart'; import 'package:lunasea/system/logger.dart'; @@ -98,8 +99,8 @@ class _Mobile extends _Shared { Rect? rect; if (box != null) rect = box.localToGlobal(Offset.zero) & box.size; - ShareResult result = await Share.shareFilesWithResult( - [path], + ShareResult result = await Share.shareXFiles( + [XFile(path)], sharePositionOrigin: rect, ); switch (result.status) {