mirror of
https://codeberg.org/shroff/phylum.git
synced 2026-05-01 17:49:45 -05:00
[client] ResourceRepository
This commit is contained in:
@@ -47,12 +47,12 @@ class ResourceDeleteAction extends ApiAction<PhylumAccount> with JsonApiAction {
|
||||
|
||||
@override
|
||||
FutureOr<void> applyOptimisticUpdate(PhylumAccount account) {
|
||||
account.datastore.db.managers.resources.filter((f) => f.id.equals(id)).update((o) => o(deleted: const Value(true)));
|
||||
account.resourceRepository.updateResource(id, (o) => o(deleted: const Value(true)));
|
||||
}
|
||||
|
||||
@override
|
||||
FutureOr<void> revertOptimisticUpdate(PhylumAccount account) {
|
||||
account.datastore.db.managers.resources.filter((f) => f.id.equals(id)).update((o) => o(deleted: const Value(false)));
|
||||
account.resourceRepository.updateResource(id, (o) => o(deleted: const Value(false)));
|
||||
}
|
||||
|
||||
@override
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
import 'dart:async';
|
||||
|
||||
import 'package:drift/drift.dart';
|
||||
import 'package:offtheline/offtheline.dart';
|
||||
import 'package:phylum/libphylum/phylum_account.dart';
|
||||
import 'package:phylum/libphylum/phylum_datastore.dart';
|
||||
@@ -52,20 +51,12 @@ class ResourceMkdirAction extends ApiAction<PhylumAccount> with JsonApiAction {
|
||||
|
||||
@override
|
||||
FutureOr<void> applyOptimisticUpdate(PhylumAccount account) {
|
||||
account.datastore.db.managers.resources.create((o) => o(
|
||||
dir: true,
|
||||
etag: "",
|
||||
size: 0,
|
||||
id: id,
|
||||
parent: Value(parent),
|
||||
modified: DateTime.now(),
|
||||
name: resourceName,
|
||||
));
|
||||
account.resourceRepository.createResource(id, true, parent, resourceName);
|
||||
}
|
||||
|
||||
@override
|
||||
FutureOr<void> revertOptimisticUpdate(PhylumAccount account) {
|
||||
account.datastore.db.managers.resources.filter((f) => f.id.equals(id)).delete();
|
||||
account.resourceRepository.deleteResource(id);
|
||||
}
|
||||
|
||||
@override
|
||||
|
||||
@@ -50,12 +50,12 @@ class ResourceMoveAction extends ApiAction<PhylumAccount> with JsonApiAction {
|
||||
|
||||
@override
|
||||
FutureOr<void> applyOptimisticUpdate(PhylumAccount account) {
|
||||
account.datastore.db.managers.resources.filter((f) => f.id.equals(id)).update((o) => o(parent: Value(parent)));
|
||||
account.resourceRepository.updateResource(id, (o) => o(parent: Value(parent)));
|
||||
}
|
||||
|
||||
@override
|
||||
FutureOr<void> revertOptimisticUpdate(PhylumAccount account) {
|
||||
account.datastore.db.managers.resources.filter((f) => f.id.equals(id)).update((o) => o(parent: Value(oldParent)));
|
||||
account.resourceRepository.updateResource(id, (o) => o(parent: Value(oldParent)));
|
||||
}
|
||||
|
||||
@override
|
||||
|
||||
@@ -57,12 +57,12 @@ class ResourceRenameAction extends ApiAction<PhylumAccount> with JsonApiAction {
|
||||
|
||||
@override
|
||||
FutureOr<void> applyOptimisticUpdate(PhylumAccount account) {
|
||||
account.datastore.db.managers.resources.filter((f) => f.id.equals(id)).update((o) => o(name: Value(newName)));
|
||||
account.resourceRepository.updateResource(id, (o) => o(name: Value(newName)));
|
||||
}
|
||||
|
||||
@override
|
||||
FutureOr<void> revertOptimisticUpdate(PhylumAccount account) {
|
||||
account.datastore.db.managers.resources.filter((f) => f.id.equals(id)).update((o) => o(name: Value(oldName)));
|
||||
account.resourceRepository.updateResource(id, (o) => o(name: Value(oldName)));
|
||||
}
|
||||
|
||||
@override
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
import 'dart:async';
|
||||
import 'dart:io';
|
||||
|
||||
import 'package:drift/drift.dart';
|
||||
import 'package:http/http.dart';
|
||||
import 'package:offtheline/offtheline.dart';
|
||||
import 'package:phylum/libphylum/phylum_account.dart';
|
||||
@@ -72,20 +71,12 @@ class ResourceUploadAction extends ApiAction<PhylumAccount> with FileUploadApiAc
|
||||
|
||||
@override
|
||||
FutureOr<void> applyOptimisticUpdate(PhylumAccount account) {
|
||||
account.datastore.db.managers.resources.create((o) => o(
|
||||
dir: false,
|
||||
etag: "",
|
||||
size: size,
|
||||
id: id,
|
||||
parent: Value(parent),
|
||||
modified: DateTime.now(),
|
||||
name: resourceName,
|
||||
));
|
||||
account.resourceRepository.createResource(id, true, parent, resourceName);
|
||||
}
|
||||
|
||||
@override
|
||||
FutureOr<void> revertOptimisticUpdate(PhylumAccount account) {
|
||||
account.datastore.db.managers.resources.filter((f) => f.id.equals(id)).delete();
|
||||
account.resourceRepository.deleteResource(id);
|
||||
}
|
||||
|
||||
@override
|
||||
|
||||
@@ -1,7 +1,9 @@
|
||||
import 'dart:convert';
|
||||
|
||||
import 'package:offtheline/offtheline.dart';
|
||||
import 'package:phylum/libphylum/db/db.dart';
|
||||
import 'package:phylum/libphylum/phylum_datastore.dart';
|
||||
import 'package:phylum/libphylum/repositories/resource_repository.dart';
|
||||
|
||||
const _persistKeyAccessToken = 'accessToken';
|
||||
const _persistKeyUserEmail = 'userEmail';
|
||||
@@ -25,6 +27,8 @@ class PhylumApiErrorResponse {
|
||||
Map<String, dynamic> _tansformResponse(String response) => (jsonDecode(response) as Map<String, dynamic>?) ?? const {};
|
||||
|
||||
class PhylumAccount extends Account<PhylumApiResponse, PhylumApiErrorResponse, PhylumAccount> {
|
||||
late final db = AppDatabase(id);
|
||||
late final resourceRepository = ResourceRepository(account: this);
|
||||
final datastore = PhylumDatastore();
|
||||
final actionQueue = ApiActionQueue<PhylumApiResponse, PhylumApiErrorResponse, PhylumAccount>();
|
||||
|
||||
|
||||
@@ -7,44 +7,42 @@ const resourceDetailsResponse = 'resourceDetails';
|
||||
const resourceSummaryResponse = 'resourceSummary';
|
||||
|
||||
class PhylumDatastore with AccountListener<PhylumApiResponse, PhylumApiErrorResponse, PhylumAccount> {
|
||||
late final AppDatabase db;
|
||||
|
||||
@override
|
||||
Future<void> initialize(PhylumAccount account) async {
|
||||
super.initialize(account);
|
||||
db = AppDatabase(account.id);
|
||||
account.api.addResponseListener(processResponse);
|
||||
}
|
||||
|
||||
Future<void> processResponse(Map<String, dynamic> data, dynamic tag) {
|
||||
return db.transaction(() => _processResponse(data, tag));
|
||||
final db = account.db;
|
||||
return db.transaction(() => _processResponse(data, tag, db));
|
||||
}
|
||||
|
||||
Future<void> _processResponse(Map<String, dynamic> data, dynamic tag) async {
|
||||
Future<void> _processResponse(Map<String, dynamic> data, dynamic tag, AppDatabase db) async {
|
||||
switch (tag) {
|
||||
case resourceDetailsResponse:
|
||||
parseResourceDetails(data);
|
||||
parseResourceDetails(data, db);
|
||||
break;
|
||||
case resourceSummaryResponse:
|
||||
parseResourceSummary(data);
|
||||
parseResourceSummary(data, db);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
Future parseResourceDetails(Map<String, dynamic> data) async {
|
||||
final details = parseResourceSummary(data['metadata']).copyWith(lastFetch: Value(DateTime.now()));
|
||||
Future parseResourceDetails(Map<String, dynamic> data, AppDatabase db) async {
|
||||
final details = parseResourceSummary(data['metadata'], db).copyWith(lastFetch: Value(DateTime.now()));
|
||||
final existing = Set.from(await db.managers.resources.filter((f) => f.parent.id.equals(data['metadata']['id'])).map((r) => r.id).get());
|
||||
final children = data.containsKey('children')
|
||||
? (data['children'] as List).cast<Map>().map((c) {
|
||||
existing.remove(c['id']);
|
||||
return parseResourceSummary(c.cast<String, dynamic>());
|
||||
return parseResourceSummary(c.cast<String, dynamic>(), db);
|
||||
})
|
||||
: <ResourcesCompanion>[];
|
||||
await db.resources.deleteWhere((o) => o.id.isIn(List.from(existing)));
|
||||
return db.insertResources([details, ...children]);
|
||||
}
|
||||
|
||||
ResourcesCompanion parseResourceSummary(Map<String, dynamic> data) {
|
||||
ResourcesCompanion parseResourceSummary(Map<String, dynamic> data, AppDatabase db) {
|
||||
return ResourcesCompanion.insert(
|
||||
id: data['id'],
|
||||
parent: Value(data['parent']),
|
||||
|
||||
@@ -0,0 +1,63 @@
|
||||
import 'package:drift/drift.dart';
|
||||
import 'package:offtheline/offtheline.dart';
|
||||
import 'package:phylum/libphylum/db/db.dart';
|
||||
import 'package:phylum/libphylum/phylum_account.dart';
|
||||
import 'package:phylum/libphylum/requests/resource_detail_request.dart';
|
||||
|
||||
class ResourceRepository {
|
||||
final PhylumAccount account;
|
||||
|
||||
ResourceRepository({required this.account});
|
||||
|
||||
Future<ApiError<PhylumApiErrorResponse>?> requestResource(String id) {
|
||||
return account.api.sendRequest(ResourceDetailRequest(id));
|
||||
}
|
||||
|
||||
Future<Resource?> getResource(String id) {
|
||||
return _selectResource(id).getSingleOrNull();
|
||||
}
|
||||
|
||||
Stream<Resource?> watchResource(String id) {
|
||||
return _selectResource(id).watchSingleOrNull();
|
||||
}
|
||||
|
||||
Future<List<Resource>> getResources(Iterable<String> ids) {
|
||||
return _selectResources(ids).get();
|
||||
}
|
||||
|
||||
Stream<List<Resource>> watchChildren(String id) {
|
||||
return (_selectChildren(id)..orderBy([(u) => OrderingTerm.desc(u.dir), (u) => OrderingTerm.asc(u.name.collate(Collate.noCase))])).watch();
|
||||
}
|
||||
|
||||
SimpleSelectStatement<$ResourcesTable, Resource> _selectResource(String id) {
|
||||
return account.db.resources.select()..where((f) => f.id.equals(id) & f.deleted.equals(false));
|
||||
}
|
||||
|
||||
SimpleSelectStatement<$ResourcesTable, Resource> _selectChildren(String id) {
|
||||
return account.db.resources.select()..where((f) => f.parent.equals(id) & f.deleted.equals(false));
|
||||
}
|
||||
|
||||
SimpleSelectStatement<$ResourcesTable, Resource> _selectResources(Iterable<String> ids) {
|
||||
return account.db.resources.select()..where((f) => f.id.isIn(ids));
|
||||
}
|
||||
|
||||
Future<int> createResource(String id, bool dir, String parent, String name) {
|
||||
return account.db.resources.insertOne(ResourcesCompanion.insert(
|
||||
id: id,
|
||||
name: name,
|
||||
parent: Value(parent),
|
||||
dir: dir,
|
||||
modified: DateTime.now(),
|
||||
size: 0,
|
||||
etag: "",
|
||||
));
|
||||
}
|
||||
|
||||
Future<int> updateResource(String id, Insertable<Resource> Function($$ResourcesTableUpdateCompanionBuilder o) fn) {
|
||||
return account.db.managers.resources.filter((f) => f.id.equals(id)).update(fn);
|
||||
}
|
||||
|
||||
Future<int> deleteResource(String id) {
|
||||
return account.db.resources.deleteWhere((f) => f.id.equals(id));
|
||||
}
|
||||
}
|
||||
@@ -155,7 +155,7 @@ class _FolderContentsViewState extends State<FolderContentsView> {
|
||||
if (uri.authority == openUri.authority && uri.path == openUri.path && uri.queryParameters.containsKey('id')) {
|
||||
final resourceId = uri.queryParameters['id']!;
|
||||
final cut = uri.queryParameters.containsKey('cut');
|
||||
final resource = await account.datastore.db.managers.resources.filter((f) => f.id.equals(resourceId)).getSingleOrNull();
|
||||
final resource = await account.resourceRepository.getResource(resourceId);
|
||||
if (resource != null) {
|
||||
(cut ? cutResources : copyResources).add(resource);
|
||||
}
|
||||
@@ -165,7 +165,7 @@ class _FolderContentsViewState extends State<FolderContentsView> {
|
||||
}
|
||||
if (!context.mounted) return;
|
||||
uploadRecursive(context, widget.folderId, paths);
|
||||
final parent = await account.datastore.db.managers.resources.filter((f) => f.id.equals(widget.folderId)).getSingleOrNull();
|
||||
final parent = await account.resourceRepository.getResource(widget.folderId);
|
||||
if (parent != null) {
|
||||
for (final r in cutResources) {
|
||||
account.addAction(ResourceMoveAction(r: r, parent: parent));
|
||||
|
||||
@@ -2,7 +2,6 @@ import 'package:flutter/material.dart';
|
||||
import 'package:flutter_state_notifier/flutter_state_notifier.dart';
|
||||
import 'package:phylum/app_shortcuts.dart';
|
||||
import 'package:phylum/libphylum/phylum_account.dart';
|
||||
import 'package:phylum/libphylum/requests/resource_detail_request.dart';
|
||||
import 'package:phylum/ui/folder/folder_contents_view.dart';
|
||||
import 'package:phylum/ui/folder/folder_navigator_stack.dart';
|
||||
import 'package:phylum/ui/folder/folder_selection_manager.dart';
|
||||
@@ -24,8 +23,9 @@ class _FolderViewState extends State<FolderView> {
|
||||
_refresh();
|
||||
}
|
||||
|
||||
Future<void> _refresh() async {
|
||||
await context.read<PhylumAccount>().api.sendRequest(ResourceDetailRequest(widget.id));
|
||||
Future _refresh() {
|
||||
debugPrint('Requesting ${widget.id}');
|
||||
return context.read<PhylumAccount>().resourceRepository.requestResource(widget.id);
|
||||
}
|
||||
|
||||
@override
|
||||
@@ -50,17 +50,14 @@ class _FolderViewState extends State<FolderView> {
|
||||
child: StateNotifierProvider<FolderSelectionManager, FolderSelectionState>(
|
||||
create: (context) => FolderSelectionManager(),
|
||||
child: StreamBuilder(
|
||||
stream: account.datastore.db.managers.resources.filter((f) => f.id.equals(widget.id)).watchSingleOrNull(),
|
||||
stream: account.resourceRepository.watchResource(widget.id),
|
||||
builder: (context, snapshot) {
|
||||
final folder = snapshot.data;
|
||||
if (folder?.lastFetch == null) {
|
||||
return buildEmptyView('Loading');
|
||||
}
|
||||
return StreamBuilder(
|
||||
stream: account.datastore.db.managers.resources
|
||||
.filter((f) => f.parent.id.equals(widget.id) & f.deleted.equals(false))
|
||||
.orderBy((o) => o.dir.desc() & o.name.asc())
|
||||
.watch(),
|
||||
stream: account.resourceRepository.watchChildren(widget.id),
|
||||
builder: (context, snapshot) {
|
||||
if (!snapshot.hasData) {
|
||||
return Container();
|
||||
|
||||
@@ -42,7 +42,7 @@ class _ResourceDetailsRowState extends State<ResourceDetailsRow> {
|
||||
if (details.data == _draggableDataSelected) {
|
||||
final account = context.read<PhylumAccount>();
|
||||
final selectedIds = context.read<FolderSelectionState>().selected;
|
||||
final selected = await account.datastore.db.managers.resources.filter((f) => f.id.isIn(selectedIds)).get();
|
||||
final selected = await account.resourceRepository.getResources(selectedIds);
|
||||
for (final res in selected) {
|
||||
account.addAction(ResourceMoveAction(r: res, parent: widget.r));
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user