Refactor: extract universal storage

This commit is contained in:
Ming Ming 2023-08-29 01:22:29 +08:00
parent fd5b7f7e5b
commit 866720fa3a
18 changed files with 141 additions and 61 deletions

View file

@ -1,8 +1,7 @@
import 'package:nc_photos/entity/pref.dart';
import 'package:nc_photos/mobile/platform.dart'
if (dart.library.html) 'package:nc_photos/web/platform.dart' as platform;
import 'package:nc_photos/use_case/compat/v34.dart';
import 'package:np_common/type.dart';
import 'package:np_universal_storage/np_universal_storage.dart';
import 'package:shared_preferences/shared_preferences.dart';
import 'package:shared_preferences_platform_interface/shared_preferences_platform_interface.dart';
@ -14,7 +13,7 @@ class PrefSharedPreferencesProvider extends PrefProvider {
// await CompatV32.migratePref();
// }
if (await CompatV34.isPrefNeedMigration()) {
await CompatV34.migratePref(platform.UniversalStorage());
await CompatV34.migratePref(UniversalStorage());
}
return SharedPreferences.getInstance().then((pref) {
_pref = pref;

View file

@ -1,16 +1,15 @@
import 'dart:convert';
import 'package:nc_photos/entity/pref.dart';
import 'package:nc_photos/mobile/platform.dart'
if (dart.library.html) 'package:nc_photos/web/platform.dart' as platform;
import 'package:np_common/type.dart';
import 'package:np_universal_storage/np_universal_storage.dart';
/// [Pref] backed by [UniversalStorage]
class PrefUniversalStorageProvider extends PrefProvider {
PrefUniversalStorageProvider(this.name);
Future<void> init() async {
final prefStr = await platform.UniversalStorage().getString(name) ?? "{}";
final prefStr = await UniversalStorage().getString(name) ?? "{}";
_data
..clear()
..addAll(jsonDecode(prefStr));
@ -41,14 +40,14 @@ class PrefUniversalStorageProvider extends PrefProvider {
@override
Future<bool> remove(PrefKeyInterface key) async {
final newData = Map.of(_data)..remove(key.toStringKey());
await platform.UniversalStorage().putString(name, jsonEncode(newData));
await UniversalStorage().putString(name, jsonEncode(newData));
_data.remove(key.toStringKey());
return true;
}
@override
Future<bool> clear() async {
await platform.UniversalStorage().remove(name);
await UniversalStorage().remove(name);
_data.clear();
return true;
}
@ -61,7 +60,7 @@ class PrefUniversalStorageProvider extends PrefProvider {
Future<bool> _set<T>(PrefKeyInterface key, T value) async {
final newData = Map.of(_data)
..addEntries([MapEntry(key.toStringKey(), value)]);
await platform.UniversalStorage().putString(name, jsonEncode(newData));
await UniversalStorage().putString(name, jsonEncode(newData));
_data[key.toStringKey()] = value;
return true;
}

View file

@ -3,4 +3,3 @@ export 'download.dart';
export 'file_saver.dart';
export 'google_gps_map.dart';
export 'notification.dart';
export 'universal_storage.dart';

View file

@ -6,14 +6,13 @@ import 'package:nc_photos/di_container.dart';
import 'package:nc_photos/entity/file.dart';
import 'package:nc_photos/entity/file_descriptor.dart';
import 'package:nc_photos/exception.dart';
import 'package:nc_photos/mobile/platform.dart'
if (dart.library.html) 'package:nc_photos/web/platform.dart' as platform;
import 'package:nc_photos/remote_storage_util.dart' as remote_storage_util;
import 'package:nc_photos/throttler.dart';
import 'package:nc_photos/use_case/ls_single_file.dart';
import 'package:nc_photos/use_case/put_file_binary.dart';
import 'package:np_codegen/np_codegen.dart';
import 'package:np_common/or_null.dart';
import 'package:np_universal_storage/np_universal_storage.dart';
import 'package:path/path.dart' as path_lib;
import 'package:uuid/uuid.dart';
@ -116,10 +115,10 @@ class TouchManager {
Future<void> setLocalEtag(Account account, File dir, String? etag) {
final name = _getLocalStorageName(account, dir);
if (etag == null) {
return platform.UniversalStorage().remove(name);
return UniversalStorage().remove(name);
} else {
_log.info("[setLocalEtag] Set local etag for file '${dir.path}': $etag");
return platform.UniversalStorage().putString(name, etag);
return UniversalStorage().putString(name, etag);
}
}
@ -175,7 +174,7 @@ class TouchManager {
Future<String?> _getLocalEtag(Account account, File file) async {
final name = _getLocalStorageName(account, file);
return platform.UniversalStorage().getString(name);
return UniversalStorage().getString(name);
}
String _getLocalStorageName(Account account, File file) {

View file

@ -2,9 +2,9 @@ import 'dart:convert';
import 'package:logging/logging.dart';
import 'package:nc_photos/account.dart';
import 'package:nc_photos/platform/universal_storage.dart';
import 'package:np_codegen/np_codegen.dart';
import 'package:np_common/type.dart';
import 'package:np_universal_storage/np_universal_storage.dart';
import 'package:shared_preferences/shared_preferences.dart';
part 'v34.g.dart';
@ -39,7 +39,8 @@ class CompatV34 {
final id = Account.newId();
account2["account"]["id"] = id;
newJsons.add(account2["account"]);
await storage.putString("accounts/$id/pref", jsonEncode(account2["settings"]));
await storage.putString(
"accounts/$id/pref", jsonEncode(account2["settings"]));
}
if (await pref.setStringList(
"accounts3", newJsons.map((e) => jsonEncode(e)).toList())) {

View file

@ -3,4 +3,3 @@ export 'download.dart';
export 'file_saver.dart';
export 'google_gps_map.dart';
export 'notification.dart';
export 'universal_storage.dart';

View file

@ -1039,6 +1039,13 @@ packages:
relative: true
source: path
version: "0.0.1"
np_universal_storage:
dependency: "direct main"
description:
path: "../np_universal_storage"
relative: true
source: path
version: "0.0.1"
octo_image:
dependency: "direct main"
description:

View file

@ -117,6 +117,8 @@ dependencies:
path: ../np_string
np_ui:
path: ../np_ui
np_universal_storage:
path: ../np_universal_storage
octo_image: any
page_view_indicators: ^2.0.0
path: ^1.8.0

View file

@ -1,7 +1,7 @@
import 'dart:convert';
import 'package:nc_photos/platform/universal_storage.dart';
import 'package:nc_photos/use_case/compat/v34.dart';
import 'package:np_universal_storage/np_universal_storage.dart';
import 'package:shared_preferences/shared_preferences.dart';
import 'package:test/test.dart';

30
np_universal_storage/.gitignore vendored Normal file
View file

@ -0,0 +1,30 @@
# Miscellaneous
*.class
*.log
*.pyc
*.swp
.DS_Store
.atom/
.buildlog/
.history
.svn/
migrate_working_dir/
# IntelliJ related
*.iml
*.ipr
*.iws
.idea/
# The .vscode folder contains launch configuration and tasks you configure in
# VS Code which you may wish to be included in version control, so this line
# is commented out by default.
#.vscode/
# Flutter/Dart/Pub related
# Libraries should not include pubspec.lock, per https://dart.dev/guides/libraries/private-files#pubspeclock.
/pubspec.lock
**/doc/api/
.dart_tool/
.packages
build/

View file

@ -0,0 +1,10 @@
# This file tracks properties of this Flutter project.
# Used by Flutter tool to assess capabilities and perform upgrades etc.
#
# This file should be version controlled and should not be manually edited.
version:
revision: 4d9e56e694b656610ab87fcf2efbcd226e0ed8cf
channel: stable
project_type: package

View file

@ -0,0 +1 @@
include: package:np_lints/np.yaml

View file

@ -0,0 +1,4 @@
library np_universal_storage;
export 'src/memory_storage.dart';
export 'src/universal_storage.dart';

View file

@ -0,0 +1,29 @@
import 'package:flutter/foundation.dart';
import 'package:np_universal_storage/src/universal_storage.dart';
/// UniversalStorage backed by memory, useful in unit tests
@visibleForTesting
class UniversalMemoryStorage implements UniversalStorage {
@override
Future<void> putBinary(String name, Uint8List content) async {
data[name] = content;
}
@override
Future<Uint8List?> getBinary(String name) async => data[name];
@override
Future<void> putString(String name, String content) async {
data[name] = content;
}
@override
Future<String?> getString(String name) async => data[name];
@override
Future<void> remove(String name) async {
data.remove(name);
}
final data = <String, dynamic>{};
}

View file

@ -1,21 +1,21 @@
import 'dart:io';
import 'dart:typed_data';
import 'package:nc_photos/platform/universal_storage.dart' as itf;
import 'package:np_string/np_string.dart';
import 'package:np_universal_storage/src/universal_storage.dart' as itf;
import 'package:path/path.dart' as path_lib;
import 'package:path_provider/path_provider.dart';
class UniversalStorage extends itf.UniversalStorage {
class UniversalStorage implements itf.UniversalStorage {
@override
putBinary(String name, Uint8List content) async {
Future<void> putBinary(String name, Uint8List content) async {
final storageDir = await _openStorageDirForFile(name);
final file = File("${storageDir.path}/$name");
await file.writeAsBytes(content, flush: true);
}
@override
getBinary(String name) async {
Future<Uint8List?> getBinary(String name) async {
final storageDir = await _openStorageDirForFile(name);
final file = File("${storageDir.path}/$name");
if (await file.exists()) {
@ -26,14 +26,14 @@ class UniversalStorage extends itf.UniversalStorage {
}
@override
putString(String name, String content) async {
Future<void> putString(String name, String content) async {
final storageDir = await _openStorageDirForFile(name);
final file = File("${storageDir.path}/$name");
await file.writeAsString(content, flush: true);
}
@override
getString(String name) async {
Future<String?> getString(String name) async {
final storageDir = await _openStorageDirForFile(name);
final file = File("${storageDir.path}/$name");
if (await file.exists()) {
@ -44,7 +44,7 @@ class UniversalStorage extends itf.UniversalStorage {
}
@override
remove(String name) async {
Future<void> remove(String name) async {
final storageDir = await _openStorageDirForFile(name);
final file = File("${storageDir.path}/$name");
if (await file.exists()) {

View file

@ -1,10 +1,16 @@
import 'package:flutter/foundation.dart';
import 'dart:typed_data';
import 'package:np_universal_storage/src/native/universal_storage.dart'
if (dart.library.html) 'package:np_universal_storage/src/web/universal_storage.dart'
as impl;
/// Store simple contents across different platforms
///
/// On mobile, the contents will be persisted as a file. On web, the contents
/// will be stored in local storage
abstract class UniversalStorage {
factory UniversalStorage() => impl.UniversalStorage();
Future<void> putBinary(String name, Uint8List content);
/// Return the content associated with [name], or null if no such association
@ -19,30 +25,3 @@ abstract class UniversalStorage {
Future<void> remove(String name);
}
/// UniversalStorage backed by memory, useful in unit tests
@visibleForTesting
class UniversalMemoryStorage implements UniversalStorage {
@override
putBinary(String name, Uint8List content) async {
data[name] = content;
}
@override
getBinary(String name) async => data[name];
@override
putString(String name, String content) async {
data[name] = content;
}
@override
getString(String name) async => data[name];
@override
remove(String name) async {
data.remove(name);
}
final data = <String, dynamic>{};
}

View file

@ -1,14 +1,14 @@
import 'dart:convert';
import 'dart:typed_data';
import 'package:nc_photos/platform/universal_storage.dart' as itf;
import 'package:np_universal_storage/src/universal_storage.dart' as itf;
import 'package:shared_preferences/shared_preferences.dart';
const String _prefix = "_universal_storage";
class UniversalStorage extends itf.UniversalStorage {
class UniversalStorage implements itf.UniversalStorage {
@override
putBinary(String name, Uint8List content) async {
Future<void> putBinary(String name, Uint8List content) async {
// SharedPreferences happens to save to local storage on web, we'll just use
// that
final pref = await SharedPreferences.getInstance();
@ -16,7 +16,7 @@ class UniversalStorage extends itf.UniversalStorage {
}
@override
getBinary(String name) async {
Future<Uint8List?> getBinary(String name) async {
final pref = await SharedPreferences.getInstance();
final contentStr = pref.getString("$_prefix.$name");
if (contentStr == null) {
@ -27,7 +27,7 @@ class UniversalStorage extends itf.UniversalStorage {
}
@override
putString(String name, String content) async {
Future<void> putString(String name, String content) async {
// SharedPreferences happens to save to local storage on web, we'll just use
// that
final pref = await SharedPreferences.getInstance();
@ -35,13 +35,13 @@ class UniversalStorage extends itf.UniversalStorage {
}
@override
getString(String name) async {
Future<String?> getString(String name) async {
final pref = await SharedPreferences.getInstance();
return pref.getString("$_prefix.$name");
}
@override
remove(String name) async {
Future<void> remove(String name) async {
final pref = await SharedPreferences.getInstance();
await pref.remove("$_prefix.$name");
}

View file

@ -0,0 +1,22 @@
name: np_universal_storage
description: A new Flutter package project.
version: 0.0.1
homepage:
publish_to: none
environment:
sdk: '>=2.19.6 <3.0.0'
flutter: ">=3.3.0"
dependencies:
flutter:
sdk: flutter
np_string:
path: ../np_string
path: ^1.8.0
path_provider: ^2.0.15
shared_preferences: ^2.0.8
dev_dependencies:
np_lints:
path: ../np_lints