Skip to content

Commit

Permalink
Readd recent documents, closes #512
Browse files Browse the repository at this point in the history
  • Loading branch information
CodeDoctorDE committed Oct 28, 2023
1 parent 9aff0e1 commit 595a095
Show file tree
Hide file tree
Showing 13 changed files with 252 additions and 110 deletions.
4 changes: 3 additions & 1 deletion api/lib/src/models/asset.dart
Original file line number Diff line number Diff line change
Expand Up @@ -27,8 +27,10 @@ sealed class AssetLocation with _$AssetLocation {

const AssetLocation._();

bool get isRemote => remote.isNotEmpty;

String get identifier =>
remote == '' ? pathWithLeadingSlash : '$pathWithLeadingSlash@$remote';
isRemote ? '$pathWithLeadingSlash@$remote' : pathWithLeadingSlash;

String get pathWithLeadingSlash => path.startsWith('/') ? path : '/$path';

Expand Down
52 changes: 51 additions & 1 deletion app/lib/api/file_system/file_system.dart
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import 'package:butterfly/cubits/settings.dart';
import 'package:butterfly_api/butterfly_api.dart';
import 'package:flutter/foundation.dart';
import 'package:flutter/widgets.dart';
import 'package:rxdart/rxdart.dart';

import 'file_system_dav.dart';
import 'file_system_io.dart';
Expand Down Expand Up @@ -103,7 +104,56 @@ abstract class DocumentFileSystem extends GeneralFileSystem {
@override
FutureOr<String> getDirectory();

Stream<AppDocumentEntity?> fetchAsset(String path);
Stream<AppDocumentEntity?> fetchAsset(String path, [bool listFiles = false]);

Stream<List<AppDocumentEntity>> fetchAssets(Stream<String> paths,
[bool listFiles = false]) {
final files = <AppDocumentEntity>[];
final streams = paths.asyncExpand((e) async* {
int? index;
await for (final file in fetchAsset(e, false).whereNotNull()) {
if (index == null) {
index = files.length;
files.add(file);
} else {
files[index] = file;
}
yield null;
}
});
return streams.map((event) => files);
}

Stream<List<AppDocumentEntity>> fetchAssetsSync(Iterable<String> paths,
[bool listFiles = false]) =>
fetchAssets(Stream.fromIterable(paths), listFiles);

static Stream<List<AppDocumentEntity>> fetchAssetsGlobal(
Stream<AssetLocation> locations, ButterflySettings settings,
[bool listFiles = true]) {
final files = <AppDocumentEntity>[];
final streams = locations.asyncExpand((e) async* {
final fileSystem =
DocumentFileSystem.fromPlatform(remote: settings.getRemote(e.remote));
int? index;
await for (final file
in fileSystem.fetchAsset(e.path, listFiles).whereNotNull()) {
if (index == null) {
index = files.length;
files.add(file);
} else {
files[index] = file;
}
yield null;
}
});
return streams.map((event) => files);
}

static Stream<List<AppDocumentEntity>> fetchAssetsGlobalSync(
Iterable<AssetLocation> locations, ButterflySettings settings,
[bool listFiles = true]) =>
fetchAssetsGlobal(Stream.fromIterable(locations), settings, listFiles);

Future<AppDocumentEntity?> getAsset(String path) => fetchAsset(path).last;

Expand Down
2 changes: 1 addition & 1 deletion app/lib/api/file_system/file_system_dav.dart
Original file line number Diff line number Diff line change
Expand Up @@ -70,7 +70,7 @@ class DavRemoteDocumentFileSystem extends DocumentRemoteSystem {

@override
Stream<AppDocumentEntity?> fetchAsset(String path,
{bool forceRemote = false}) async* {
[bool listFiles = true, bool forceRemote = false]) async* {
if (path.endsWith('/')) {
path = path.substring(0, path.length - 1);
}
Expand Down
8 changes: 7 additions & 1 deletion app/lib/api/file_system/file_system_html.dart
Original file line number Diff line number Diff line change
Expand Up @@ -124,7 +124,8 @@ class WebDocumentFileSystem extends DocumentFileSystem {
}

@override
Stream<AppDocumentEntity?> fetchAsset(String path) async* {
Stream<AppDocumentEntity?> fetchAsset(String path,
[bool listFiles = true]) async* {
// Add leading slash
if (!path.startsWith('/')) {
path = '/$path';
Expand Down Expand Up @@ -163,6 +164,11 @@ class WebDocumentFileSystem extends DocumentFileSystem {
yield await file;
return;
} else if (map['type'] == 'directory') {
if (!listFiles) {
await txn.completed;
yield AppDocumentDirectory(AssetLocation.local(path), const []);
return;
}
var cursor = store.openCursor(autoAdvance: true);
var assets = await Future.wait(
await cursor.map<Future<AppDocumentEntity?>>((cursor) async {
Expand Down
2 changes: 1 addition & 1 deletion app/lib/api/file_system/file_system_html_stub.dart
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ class WebDocumentFileSystem extends DocumentFileSystem {
}

@override
Stream<AppDocumentEntity?> fetchAsset(String path) {
Stream<AppDocumentEntity?> fetchAsset(String path, [bool listFiles = true]) {
throw UnimplementedError();
}

Expand Down
27 changes: 7 additions & 20 deletions app/lib/api/file_system/file_system_io.dart
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,6 @@ import 'package:butterfly_api/butterfly_api.dart';
import 'package:flutter/foundation.dart';
import 'package:flutter/widgets.dart';
import 'package:path_provider/path_provider.dart';
import 'package:rxdart/rxdart.dart';
import 'package:shared_preferences/shared_preferences.dart';

import 'file_system.dart';
Expand Down Expand Up @@ -54,7 +53,7 @@ class IODocumentFileSystem extends DocumentFileSystem {

@override
Stream<AppDocumentEntity?> fetchAsset(String path,
[bool goFurther = true]) async* {
[bool listFiles = true]) async* {
// Add leading slash
if (!path.startsWith('/')) {
path = '/$path';
Expand All @@ -77,24 +76,12 @@ class IODocumentFileSystem extends DocumentFileSystem {
}
} else if (await directory.exists()) {
yield AppDocumentDirectory(AssetLocation.local(path), []);
if (goFurther) {
final files = <AppDocumentEntity>[];
final streams = directory.list().asyncExpand((e) async* {
final currentPath =
'$path/${e.path.replaceAll('\\', '/').split('/').last}';
int? index;
await for (final file
in fetchAsset(currentPath, false).whereNotNull()) {
if (index == null) {
index = files.length;
files.add(file);
} else {
files[index] = file;
}
yield null;
}
});
await for (final _ in streams) {
if (listFiles) {
final streams = fetchAssets(
directory.list().map(
(e) => '$path/${e.path.replaceAll('\\', '/').split('/').last}'),
false);
await for (final files in streams) {
yield AppDocumentDirectory(AssetLocation.local(path), files);
}
}
Expand Down
26 changes: 26 additions & 0 deletions app/lib/api/open.dart
Original file line number Diff line number Diff line change
@@ -1,8 +1,11 @@
import 'dart:async';
import 'dart:io';

import 'package:butterfly_api/butterfly_api.dart';
import 'package:file_picker/file_picker.dart';
import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart';
import 'package:go_router/go_router.dart';
import 'package:url_launcher/url_launcher.dart';

Future<bool> openHelp(List<String> pageLocation, [String? fragment]) {
Expand All @@ -27,3 +30,26 @@ Future<Uint8List?> openBfly() async {
var e = files!.files.first;
return e.bytes;
}

void openFile(BuildContext context, AssetLocation location, [Object? data]) {
if (location.isRemote) {
GoRouter.of(context).goNamed('remote',
pathParameters: {
'remote': location.remote,
'path': location.pathWithoutLeadingSlash,
},
queryParameters: {
'type': location.fileType?.name,
},
extra: data);
return;
}
GoRouter.of(context).goNamed('local',
pathParameters: {
'path': location.pathWithoutLeadingSlash,
},
queryParameters: {
'type': location.fileType?.name,
},
extra: data);
}
3 changes: 3 additions & 0 deletions app/lib/cubits/settings.dart
Original file line number Diff line number Diff line change
Expand Up @@ -476,6 +476,9 @@ class ButterflySettings with _$ButterflySettings {
}

ExternalStorage? getRemote(String? identifier) {
if (identifier?.isEmpty ?? true) {
return getDefaultRemote();
}
return connections
.firstWhereOrNull((e) => e.identifier == (identifier ?? defaultRemote));
}
Expand Down
3 changes: 1 addition & 2 deletions app/lib/services/sync.dart
Original file line number Diff line number Diff line change
Expand Up @@ -232,8 +232,7 @@ class RemoteSync {
return fileSystem.deleteCachedContent(path);
case FileSyncStatus.conflict:
await fileSystem.cache(path);
final remoteAsset =
await fileSystem.fetchAsset(path, forceRemote: true).last;
final remoteAsset = await fileSystem.fetchAsset(path, true, true).last;
await remoteAsset?.maybeMap(
file: (file) async {
if (remoteAsset is! AppDocumentFile) return;
Expand Down
13 changes: 12 additions & 1 deletion app/lib/views/app_bar.dart
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import 'package:butterfly/actions/change_path.dart';
import 'package:butterfly/actions/settings.dart';
import 'package:butterfly/actions/svg_export.dart';
import 'package:butterfly/api/file_system/file_system.dart';
import 'package:butterfly/api/open.dart';
import 'package:butterfly/cubits/current_index.dart';
import 'package:butterfly/services/import.dart';
import 'package:butterfly/views/edit.dart';
Expand Down Expand Up @@ -423,7 +424,7 @@ class _MainPopupMenu extends StatelessWidget {
},
child: Text(AppLocalizations.of(context).packs),
),
const PopupMenuDivider(),
const Divider(),
MenuItemButton(
leadingIcon: const PhosphorIcon(PhosphorIconsLight.filePlus),
shortcut:
Expand All @@ -443,6 +444,16 @@ class _MainPopupMenu extends StatelessWidget {
},
child: Text(AppLocalizations.of(context).templates),
),
SubmenuButton(
menuChildren: settingsCubit.state.history
.map((e) => MenuItemButton(
child: Text(e.identifier),
onPressed: () => openFile(context, e),
))
.toList(),
leadingIcon: const PhosphorIcon(PhosphorIconsLight.clock),
child: Text(AppLocalizations.of(context).recentFiles),
),
],
if (state.embedding == null) ...[
MenuItemButton(
Expand Down
Loading

0 comments on commit 595a095

Please sign in to comment.