From a28f8b6c1b34db7d6bff80fcb6826aa37037429a Mon Sep 17 00:00:00 2001 From: Ming Ming Date: Sun, 8 Aug 2021 20:09:21 +0800 Subject: [PATCH] Move shared albums into our data dir --- lib/pref.dart | 5 ++ lib/remote_storage_util.dart | 3 + .../import_potential_shared_album.dart | 42 +++++++++++++ lib/use_case/list_potential_shared_album.dart | 60 +++++++++++++++++++ lib/widget/home.dart | 37 ++++++++++++ 5 files changed, 147 insertions(+) create mode 100644 lib/use_case/import_potential_shared_album.dart create mode 100644 lib/use_case/list_potential_shared_album.dart diff --git a/lib/pref.dart b/lib/pref.dart index c8e0bdff..010b1662 100644 --- a/lib/pref.dart +++ b/lib/pref.dart @@ -61,6 +61,11 @@ class Pref { int getLanguageOr(int def) => getLanguage() ?? def; Future setLanguage(int value) => _pref.setInt("language", value); + bool? hasNewSharedAlbum() => _pref.getBool("hasNewSharedAlbum"); + bool hasNewSharedAlbumOr(bool def) => hasNewSharedAlbum() ?? def; + Future setNewSharedAlbum(bool value) => + _pref.setBool("hasNewSharedAlbum", value); + Pref._(); static final _inst = Pref._(); diff --git a/lib/remote_storage_util.dart b/lib/remote_storage_util.dart index 30ef2dd4..c769e50a 100644 --- a/lib/remote_storage_util.dart +++ b/lib/remote_storage_util.dart @@ -4,6 +4,9 @@ import 'package:nc_photos/api/api_util.dart' as api_util; String getRemoteAlbumsDir(Account account) => "${getRemoteStorageDir(account)}/albums"; +String getRemotePendingSharedAlbumsDir(Account account) => + "${getRemoteStorageDir(account)}/shared_albums"; + String getRemoteTouchDir(Account account) => "${getRemoteStorageDir(account)}/touch"; diff --git a/lib/use_case/import_potential_shared_album.dart b/lib/use_case/import_potential_shared_album.dart new file mode 100644 index 00000000..3c574ede --- /dev/null +++ b/lib/use_case/import_potential_shared_album.dart @@ -0,0 +1,42 @@ +import 'package:logging/logging.dart'; +import 'package:nc_photos/account.dart'; +import 'package:nc_photos/entity/album.dart'; +import 'package:nc_photos/entity/file.dart'; +import 'package:nc_photos/remote_storage_util.dart' as remote_storage_util; +import 'package:nc_photos/use_case/list_potential_shared_album.dart'; +import 'package:nc_photos/use_case/move.dart'; +import 'package:path/path.dart' as path; + +/// Import new shared albums to the pending dir +class ImportPotentialSharedAlbum { + ImportPotentialSharedAlbum(this.fileRepo, this.albumRepo); + + Future> call(Account account) async { + final products = []; + final files = await ListPotentialSharedAlbum(fileRepo)(account); + for (final f in files) { + // check if the file is actually an album + try { + final album = await albumRepo.get(account, f); + _log.info("[call] New shared album: ${album.name}, file: ${f.path}"); + // move this file to the pending dir + await Move(fileRepo)( + account, + f, + "${remote_storage_util.getRemotePendingSharedAlbumsDir(account)}/${path.basename(f.path)}", + shouldCreateMissingDir: true, + ); + products.add(album); + } catch (e, stacktrace) { + _log.severe("[call] Exception", e, stacktrace); + } + } + return products; + } + + final FileRepo fileRepo; + final AlbumRepo albumRepo; + + static final _log = Logger( + "user_case.import_potential_shared_album.ImportPotentialSharedAlbum"); +} diff --git a/lib/use_case/list_potential_shared_album.dart b/lib/use_case/list_potential_shared_album.dart new file mode 100644 index 00000000..ef7831dc --- /dev/null +++ b/lib/use_case/list_potential_shared_album.dart @@ -0,0 +1,60 @@ +import 'package:logging/logging.dart'; +import 'package:nc_photos/account.dart'; +import 'package:nc_photos/api/api_util.dart' as api_util; +import 'package:nc_photos/entity/file.dart'; +import 'package:nc_photos/use_case/ls.dart'; +import 'package:path/path.dart' as path; + +/// List all shared files that are potentially albums +/// +/// Beware that it's NOT guaranteed that they are actually albums +class ListPotentialSharedAlbum { + ListPotentialSharedAlbum(this.fileRepo); + + Future> call(Account account) async { + final results = []; + final ls = await Ls(fileRepo)( + account, File(path: api_util.getWebdavRootUrlRelative(account))); + for (final f in ls) { + // check owner + if (_checkOwner(account, f) && _checkFileName(f)) { + results.add(f); + } + } + return results; + } + + bool _checkOwner(Account account, File f) => !f.isOwned(account.username); + + bool _checkFileName(File f) { + try { + final match = _regex.firstMatch(path.basename(f.path)); + if (match == null) { + return false; + } + final timestamp = int.parse(match.group(1)!, radix: 16); + final time = DateTime.fromMillisecondsSinceEpoch(timestamp); + _log.fine("[_checkFileName] Timestamp: $time"); + if (time.isAfter(DateTime.now())) { + _log.warning("[_checkFileName] Invalid timestamp: ${f.path}"); + return false; + } + final random = int.parse(match.group(2)!, radix: 16); + _log.fine("[_checkFileName] Random: $random"); + if (random > 0xFFFFFF) { + _log.warning("[_checkFileName] Invalid random: ${f.path}"); + return false; + } + return true; + } catch (e, stacktrace) { + _log.warning("[_checkFileName] Exception: ${f.path}", e, stacktrace); + return false; + } + } + + final FileRepo fileRepo; + final _regex = RegExp(r"^([0-9a-fA-F]+)-([0-9a-fA-F]+)\.nc_album\.json$"); + + static final _log = + Logger("user_case.list_potential_shared_album.ListPotentialSharedAlbum"); +} diff --git a/lib/widget/home.dart b/lib/widget/home.dart index 98690c84..2eecef1f 100644 --- a/lib/widget/home.dart +++ b/lib/widget/home.dart @@ -1,9 +1,16 @@ import 'package:flutter/material.dart'; import 'package:flutter/widgets.dart'; +import 'package:logging/logging.dart'; import 'package:nc_photos/account.dart'; import 'package:nc_photos/app_localizations.dart'; +import 'package:nc_photos/entity/album.dart'; +import 'package:nc_photos/entity/file.dart'; +import 'package:nc_photos/entity/file/data_source.dart'; import 'package:nc_photos/k.dart' as k; +import 'package:nc_photos/lab.dart'; +import 'package:nc_photos/pref.dart'; import 'package:nc_photos/theme.dart'; +import 'package:nc_photos/use_case/import_potential_shared_album.dart'; import 'package:nc_photos/widget/home_albums.dart'; import 'package:nc_photos/widget/home_photos.dart'; @@ -37,6 +44,18 @@ class Home extends StatefulWidget { } class _HomeState extends State { + @override + initState() { + super.initState(); + if (Lab().enableSharedAlbum) { + _importPotentialSharedAlbum().then((value) { + if (value.isNotEmpty) { + Pref.inst().setNewSharedAlbum(true); + } + }); + } + } + @override build(BuildContext context) { return AppTheme( @@ -106,6 +125,24 @@ class _HomeState extends State { }); } + Future> _importPotentialSharedAlbum() async { + final fileRepo = FileRepo(FileWebdavDataSource()); + // don't want the potential albums to be cached at this moment + final albumRepo = AlbumRepo(AlbumRemoteDataSource()); + try { + return await ImportPotentialSharedAlbum(fileRepo, albumRepo)( + widget.account); + } catch (e, stacktrace) { + _log.shout( + "[_importPotentialSharedAlbum] Failed while ImportPotentialSharedAlbum", + e, + stacktrace); + return []; + } + } + final _pageController = PageController(initialPage: 0, keepPage: false); int _nextPage = 0; + + static final _log = Logger("widget.home._HomeState"); }