mirror of
https://codeberg.org/shroff/phylum.git
synced 2026-04-25 05:59:23 -05:00
[client] Show resource preview for all but text [#32]
This commit is contained in:
@@ -24,7 +24,7 @@ class AppDatabase extends _$AppDatabase {
|
||||
AppDatabase.fromExecutor({required this.accountId, required QueryExecutor executor}) : super(executor);
|
||||
|
||||
@override
|
||||
int get schemaVersion => 13;
|
||||
int get schemaVersion => 14;
|
||||
|
||||
@override
|
||||
MigrationStrategy get migration => MigrationStrategy(
|
||||
@@ -63,12 +63,10 @@ class AppDatabase extends _$AppDatabase {
|
||||
await m.create(resources);
|
||||
await m.create(resourceVersions);
|
||||
}
|
||||
if (from < 12) {
|
||||
await m.drop(resourceVersions);
|
||||
await m.create(resourceVersions);
|
||||
}
|
||||
if (from < 13) {
|
||||
if (from < 14) {
|
||||
await m.drop(resources);
|
||||
await m.drop(resourceVersions);
|
||||
await m.create(resources);
|
||||
await m.create(resourceVersions);
|
||||
}
|
||||
},
|
||||
|
||||
@@ -1180,10 +1180,11 @@ class ResourceVersions extends Table
|
||||
static const VerificationMeta _previewMeta =
|
||||
const VerificationMeta('preview');
|
||||
late final GeneratedColumn<bool> preview = GeneratedColumn<bool>(
|
||||
'preview', aliasedName, false,
|
||||
'preview', aliasedName, true,
|
||||
type: DriftSqlType.bool,
|
||||
requiredDuringInsert: true,
|
||||
$customConstraints: 'NOT NULL CHECK (preview IN (0, 1))');
|
||||
requiredDuringInsert: false,
|
||||
$customConstraints: 'DEFAULT 0 CHECK (preview IN (0, 1))',
|
||||
defaultValue: const CustomExpression('0'));
|
||||
static const VerificationMeta _sizeMeta = const VerificationMeta('size');
|
||||
late final GeneratedColumn<int> size = GeneratedColumn<int>(
|
||||
'size', aliasedName, false,
|
||||
@@ -1244,8 +1245,6 @@ class ResourceVersions extends Table
|
||||
if (data.containsKey('preview')) {
|
||||
context.handle(_previewMeta,
|
||||
preview.isAcceptableOrUnknown(data['preview']!, _previewMeta));
|
||||
} else if (isInserting) {
|
||||
context.missing(_previewMeta);
|
||||
}
|
||||
if (data.containsKey('size')) {
|
||||
context.handle(
|
||||
@@ -1283,7 +1282,7 @@ class ResourceVersions extends Table
|
||||
deleted: attachedDatabase.typeMapping
|
||||
.read(DriftSqlType.bool, data['${effectivePrefix}deleted'])!,
|
||||
preview: attachedDatabase.typeMapping
|
||||
.read(DriftSqlType.bool, data['${effectivePrefix}preview'])!,
|
||||
.read(DriftSqlType.bool, data['${effectivePrefix}preview']),
|
||||
size: attachedDatabase.typeMapping
|
||||
.read(DriftSqlType.int, data['${effectivePrefix}size'])!,
|
||||
mimeType: attachedDatabase.typeMapping
|
||||
@@ -1307,7 +1306,7 @@ class ResourceVersion extends DataClass implements Insertable<ResourceVersion> {
|
||||
final String resourceId;
|
||||
final DateTime created;
|
||||
final bool deleted;
|
||||
final bool preview;
|
||||
final bool? preview;
|
||||
final int size;
|
||||
final String mimeType;
|
||||
final String sha256;
|
||||
@@ -1316,7 +1315,7 @@ class ResourceVersion extends DataClass implements Insertable<ResourceVersion> {
|
||||
required this.resourceId,
|
||||
required this.created,
|
||||
required this.deleted,
|
||||
required this.preview,
|
||||
this.preview,
|
||||
required this.size,
|
||||
required this.mimeType,
|
||||
required this.sha256});
|
||||
@@ -1327,7 +1326,9 @@ class ResourceVersion extends DataClass implements Insertable<ResourceVersion> {
|
||||
map['resource_id'] = Variable<String>(resourceId);
|
||||
map['created'] = Variable<DateTime>(created);
|
||||
map['deleted'] = Variable<bool>(deleted);
|
||||
map['preview'] = Variable<bool>(preview);
|
||||
if (!nullToAbsent || preview != null) {
|
||||
map['preview'] = Variable<bool>(preview);
|
||||
}
|
||||
map['size'] = Variable<int>(size);
|
||||
map['mime_type'] = Variable<String>(mimeType);
|
||||
map['sha256'] = Variable<String>(sha256);
|
||||
@@ -1340,7 +1341,9 @@ class ResourceVersion extends DataClass implements Insertable<ResourceVersion> {
|
||||
resourceId: Value(resourceId),
|
||||
created: Value(created),
|
||||
deleted: Value(deleted),
|
||||
preview: Value(preview),
|
||||
preview: preview == null && nullToAbsent
|
||||
? const Value.absent()
|
||||
: Value(preview),
|
||||
size: Value(size),
|
||||
mimeType: Value(mimeType),
|
||||
sha256: Value(sha256),
|
||||
@@ -1355,7 +1358,7 @@ class ResourceVersion extends DataClass implements Insertable<ResourceVersion> {
|
||||
resourceId: serializer.fromJson<String>(json['resource_id']),
|
||||
created: serializer.fromJson<DateTime>(json['created']),
|
||||
deleted: serializer.fromJson<bool>(json['deleted']),
|
||||
preview: serializer.fromJson<bool>(json['preview']),
|
||||
preview: serializer.fromJson<bool?>(json['preview']),
|
||||
size: serializer.fromJson<int>(json['size']),
|
||||
mimeType: serializer.fromJson<String>(json['mime_type']),
|
||||
sha256: serializer.fromJson<String>(json['sha256']),
|
||||
@@ -1369,7 +1372,7 @@ class ResourceVersion extends DataClass implements Insertable<ResourceVersion> {
|
||||
'resource_id': serializer.toJson<String>(resourceId),
|
||||
'created': serializer.toJson<DateTime>(created),
|
||||
'deleted': serializer.toJson<bool>(deleted),
|
||||
'preview': serializer.toJson<bool>(preview),
|
||||
'preview': serializer.toJson<bool?>(preview),
|
||||
'size': serializer.toJson<int>(size),
|
||||
'mime_type': serializer.toJson<String>(mimeType),
|
||||
'sha256': serializer.toJson<String>(sha256),
|
||||
@@ -1381,7 +1384,7 @@ class ResourceVersion extends DataClass implements Insertable<ResourceVersion> {
|
||||
String? resourceId,
|
||||
DateTime? created,
|
||||
bool? deleted,
|
||||
bool? preview,
|
||||
Value<bool?> preview = const Value.absent(),
|
||||
int? size,
|
||||
String? mimeType,
|
||||
String? sha256}) =>
|
||||
@@ -1390,7 +1393,7 @@ class ResourceVersion extends DataClass implements Insertable<ResourceVersion> {
|
||||
resourceId: resourceId ?? this.resourceId,
|
||||
created: created ?? this.created,
|
||||
deleted: deleted ?? this.deleted,
|
||||
preview: preview ?? this.preview,
|
||||
preview: preview.present ? preview.value : this.preview,
|
||||
size: size ?? this.size,
|
||||
mimeType: mimeType ?? this.mimeType,
|
||||
sha256: sha256 ?? this.sha256,
|
||||
@@ -1446,7 +1449,7 @@ class ResourceVersionsCompanion extends UpdateCompanion<ResourceVersion> {
|
||||
final Value<String> resourceId;
|
||||
final Value<DateTime> created;
|
||||
final Value<bool> deleted;
|
||||
final Value<bool> preview;
|
||||
final Value<bool?> preview;
|
||||
final Value<int> size;
|
||||
final Value<String> mimeType;
|
||||
final Value<String> sha256;
|
||||
@@ -1467,7 +1470,7 @@ class ResourceVersionsCompanion extends UpdateCompanion<ResourceVersion> {
|
||||
required String resourceId,
|
||||
required DateTime created,
|
||||
required bool deleted,
|
||||
required bool preview,
|
||||
this.preview = const Value.absent(),
|
||||
required int size,
|
||||
required String mimeType,
|
||||
required String sha256,
|
||||
@@ -1476,7 +1479,6 @@ class ResourceVersionsCompanion extends UpdateCompanion<ResourceVersion> {
|
||||
resourceId = Value(resourceId),
|
||||
created = Value(created),
|
||||
deleted = Value(deleted),
|
||||
preview = Value(preview),
|
||||
size = Value(size),
|
||||
mimeType = Value(mimeType),
|
||||
sha256 = Value(sha256);
|
||||
@@ -1509,7 +1511,7 @@ class ResourceVersionsCompanion extends UpdateCompanion<ResourceVersion> {
|
||||
Value<String>? resourceId,
|
||||
Value<DateTime>? created,
|
||||
Value<bool>? deleted,
|
||||
Value<bool>? preview,
|
||||
Value<bool?>? preview,
|
||||
Value<int>? size,
|
||||
Value<String>? mimeType,
|
||||
Value<String>? sha256,
|
||||
@@ -3763,7 +3765,7 @@ typedef $ResourceVersionsCreateCompanionBuilder = ResourceVersionsCompanion
|
||||
required String resourceId,
|
||||
required DateTime created,
|
||||
required bool deleted,
|
||||
required bool preview,
|
||||
Value<bool?> preview,
|
||||
required int size,
|
||||
required String mimeType,
|
||||
required String sha256,
|
||||
@@ -3775,7 +3777,7 @@ typedef $ResourceVersionsUpdateCompanionBuilder = ResourceVersionsCompanion
|
||||
Value<String> resourceId,
|
||||
Value<DateTime> created,
|
||||
Value<bool> deleted,
|
||||
Value<bool> preview,
|
||||
Value<bool?> preview,
|
||||
Value<int> size,
|
||||
Value<String> mimeType,
|
||||
Value<String> sha256,
|
||||
@@ -3982,7 +3984,7 @@ class $ResourceVersionsTableManager extends RootTableManager<
|
||||
Value<String> resourceId = const Value.absent(),
|
||||
Value<DateTime> created = const Value.absent(),
|
||||
Value<bool> deleted = const Value.absent(),
|
||||
Value<bool> preview = const Value.absent(),
|
||||
Value<bool?> preview = const Value.absent(),
|
||||
Value<int> size = const Value.absent(),
|
||||
Value<String> mimeType = const Value.absent(),
|
||||
Value<String> sha256 = const Value.absent(),
|
||||
@@ -4004,7 +4006,7 @@ class $ResourceVersionsTableManager extends RootTableManager<
|
||||
required String resourceId,
|
||||
required DateTime created,
|
||||
required bool deleted,
|
||||
required bool preview,
|
||||
Value<bool?> preview = const Value.absent(),
|
||||
required int size,
|
||||
required String mimeType,
|
||||
required String sha256,
|
||||
|
||||
@@ -17,10 +17,10 @@ CREATE TABLE IF NOT EXISTS resource_versions(
|
||||
resource_id TEXT NOT NULL REFERENCES resources (id),
|
||||
created DATETIME NOT NULL,
|
||||
deleted BOOLEAN NOT NULL CHECK ("deleted" IN (0, 1)),
|
||||
preview BOOLEAN NOT NULL CHECK ("preview" IN (0, 1)),
|
||||
preview BOOLEAN DEFAULT 0 CHECK ("preview" IN (0, 1)),
|
||||
size INTEGER NOT NULL,
|
||||
mime_type TEXT NOT NULL,
|
||||
sha256 TEXT NOT NULL,
|
||||
sha256 TEXT NOT NULL
|
||||
);
|
||||
|
||||
-- Use `UNION` instead of `UNION ALL` to avoid infinite loops in case of
|
||||
|
||||
@@ -6,12 +6,13 @@ import 'package:offtheline/offtheline.dart';
|
||||
class ResourceContentsRequest extends ApiRequest {
|
||||
final String resourceId;
|
||||
final String? versionId;
|
||||
final bool loadPreview;
|
||||
|
||||
const ResourceContentsRequest(this.resourceId, {this.versionId});
|
||||
const ResourceContentsRequest(this.resourceId, {this.versionId, this.loadPreview = false});
|
||||
|
||||
@override
|
||||
BaseRequest createRequest(ApiClient api, {Uint8List? data}) {
|
||||
final uri = api.createUriBuilder('/api/v1/fs/contents/$resourceId:');
|
||||
final uri = api.createUriBuilder('/api/v1/fs/${loadPreview ? 'preview' : 'contents'}/$resourceId:');
|
||||
if (versionId != null) {
|
||||
uri.queryParameters['version'] = versionId!;
|
||||
}
|
||||
|
||||
@@ -17,7 +17,7 @@ import 'package:phylum/ui/login/reset_password_page.dart';
|
||||
import 'package:phylum/ui/menu/menu_option.dart';
|
||||
import 'package:phylum/ui/menu/option_groups.dart';
|
||||
import 'package:phylum/ui/open/open_resource_page.dart';
|
||||
import 'package:phylum/ui/file_preview/file_preview_page.dart';
|
||||
import 'package:phylum/ui/file_viewer/file_viewer_page.dart';
|
||||
import 'package:provider/provider.dart';
|
||||
|
||||
sealed class PhylumRoute {
|
||||
|
||||
@@ -8,7 +8,7 @@ import 'package:phylum/libphylum/phylum_account.dart';
|
||||
import 'package:phylum/ui/app/routes.dart';
|
||||
import 'package:phylum/ui/explorer/paste_helpers.dart';
|
||||
import 'package:phylum/ui/explorer/selection_mode.dart';
|
||||
import 'package:phylum/ui/file_preview/file_preview_dialog.dart';
|
||||
import 'package:phylum/ui/file_viewer/file_viewer_dialog.dart';
|
||||
import 'package:phylum/util/dialogs.dart';
|
||||
import 'package:phylum/util/upload_utils.dart';
|
||||
import 'package:provider/provider.dart';
|
||||
|
||||
@@ -5,7 +5,7 @@ import 'package:phylum/integrations/download_manager.dart';
|
||||
import 'package:phylum/libphylum/db/db.dart';
|
||||
import 'package:phylum/libphylum/db/resource_helpers.dart';
|
||||
import 'package:phylum/libphylum/phylum_account.dart';
|
||||
import 'package:phylum/ui/file_preview/file_preview_dialog.dart';
|
||||
import 'package:phylum/ui/file_viewer/file_viewer_dialog.dart';
|
||||
import 'package:phylum/util/file_size.dart';
|
||||
import 'package:phylum/util/time.dart';
|
||||
import 'package:provider/provider.dart';
|
||||
|
||||
+35
-34
@@ -13,25 +13,26 @@ import 'package:phylum/libphylum/requests/resource_contents_request.dart';
|
||||
import 'package:phylum/libphylum/responses/responses.dart';
|
||||
import 'package:phylum/ui/common/responsive_dialog.dart';
|
||||
import 'package:phylum/ui/explorer/resource_info_view.dart';
|
||||
import 'package:phylum/ui/file_preview/versioned_resource.dart';
|
||||
import 'package:phylum/ui/file_viewer/versioned_resource.dart';
|
||||
import 'package:printing/printing.dart';
|
||||
import 'package:provider/provider.dart';
|
||||
|
||||
const maxPreviewSize = 1 * 1024 * 1024;
|
||||
|
||||
class FilePreview extends StatefulWidget {
|
||||
class FileViewer extends StatefulWidget {
|
||||
final bool transparent;
|
||||
final VersionedResource resource;
|
||||
const FilePreview({super.key, required this.transparent, required this.resource});
|
||||
const FileViewer({super.key, required this.transparent, required this.resource});
|
||||
|
||||
@override
|
||||
State<FilePreview> createState() => _FilePreviewState();
|
||||
State<FileViewer> createState() => _FileViewerState();
|
||||
}
|
||||
|
||||
class _FilePreviewState extends State<FilePreview> {
|
||||
class _FileViewerState extends State<FileViewer> {
|
||||
late VersionedResource _resource;
|
||||
String? _error;
|
||||
Widget Function(Uint8List)? _buildPreview;
|
||||
Widget Function(Uint8List)? _buildViewer;
|
||||
bool _loadPreview = false;
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
@@ -40,7 +41,7 @@ class _FilePreviewState extends State<FilePreview> {
|
||||
}
|
||||
|
||||
@override
|
||||
void didUpdateWidget(covariant FilePreview oldWidget) {
|
||||
void didUpdateWidget(covariant FileViewer oldWidget) {
|
||||
super.didUpdateWidget(oldWidget);
|
||||
setState(() {
|
||||
_updateResource(widget.resource);
|
||||
@@ -50,26 +51,19 @@ class _FilePreviewState extends State<FilePreview> {
|
||||
void _updateResource(VersionedResource resource) {
|
||||
_resource = resource;
|
||||
if (_resource.r.dir) {
|
||||
_buildPreview = null;
|
||||
_error = 'Cannot preview directory';
|
||||
_buildViewer = null;
|
||||
_error = 'Cannot view directory';
|
||||
} else {
|
||||
_buildPreview = null;
|
||||
if (_resource.v.mimeType.startsWith('image/')) {
|
||||
_buildPreview = buildImagePreview;
|
||||
}
|
||||
_buildViewer = null;
|
||||
context.read<PhylumAccount>().db.markResourceAccess(_resource.r.id);
|
||||
if (_resource.v.mimeType.startsWith('text/')) {
|
||||
_buildPreview = buildTextPreview;
|
||||
}
|
||||
if (_resource.v.mimeType == 'application/pdf') {
|
||||
_buildPreview = buildPdfPreview;
|
||||
}
|
||||
if (_buildPreview == null) {
|
||||
_error = 'Cannot generate preview';
|
||||
} else if (_resource.v.size > maxPreviewSize) {
|
||||
_buildPreview = null;
|
||||
_error = 'File too large to preview';
|
||||
_buildViewer = buildTextPreview;
|
||||
_loadPreview = false;
|
||||
} else if (_resource.v.preview == true) {
|
||||
_buildViewer = buildImagePreview;
|
||||
_loadPreview = true;
|
||||
} else {
|
||||
context.read<PhylumAccount>().db.markResourceAccess(_resource.r.id);
|
||||
_error = 'Preview not available';
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -100,34 +94,40 @@ class _FilePreviewState extends State<FilePreview> {
|
||||
backgroundColor: Colors.transparent,
|
||||
),
|
||||
body: Center(
|
||||
child: _buildPreview == null
|
||||
child: _buildViewer == null
|
||||
? Card(
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.all(16.0),
|
||||
child: Text(_error ?? 'Unknown error', style: TextStyle(fontSize: 18)),
|
||||
))
|
||||
: ResourcePreviewDownloader(
|
||||
: ResourceLoader(
|
||||
resourceId: _resource.r.id,
|
||||
versionId: _resource.v.id,
|
||||
buildPreview: _buildPreview!,
|
||||
buildViewer: _buildViewer!,
|
||||
loadPreview: _loadPreview,
|
||||
)),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
class ResourcePreviewDownloader extends StatefulWidget {
|
||||
class ResourceLoader extends StatefulWidget {
|
||||
final String resourceId;
|
||||
final String versionId;
|
||||
final Widget Function(Uint8List data) buildPreview;
|
||||
final Widget Function(Uint8List data) buildViewer;
|
||||
final bool loadPreview;
|
||||
|
||||
ResourcePreviewDownloader({required this.resourceId, required this.buildPreview, required this.versionId})
|
||||
: super(key: ValueKey(versionId));
|
||||
ResourceLoader({
|
||||
required this.resourceId,
|
||||
required this.buildViewer,
|
||||
required this.versionId,
|
||||
required this.loadPreview,
|
||||
}) : super(key: ValueKey(versionId));
|
||||
|
||||
@override
|
||||
State<ResourcePreviewDownloader> createState() => _ResourcePreviewDownloaderState();
|
||||
State<ResourceLoader> createState() => _ResourceLoaderState();
|
||||
}
|
||||
|
||||
class _ResourcePreviewDownloaderState extends State<ResourcePreviewDownloader> {
|
||||
class _ResourceLoaderState extends State<ResourceLoader> {
|
||||
bool _downloading = false;
|
||||
String? _error;
|
||||
double? _progress;
|
||||
@@ -149,7 +149,7 @@ class _ResourcePreviewDownloaderState extends State<ResourcePreviewDownloader> {
|
||||
if (_data != null) {
|
||||
return SizedBox(
|
||||
width: 800,
|
||||
child: widget.buildPreview(_data!),
|
||||
child: widget.buildViewer(_data!),
|
||||
);
|
||||
}
|
||||
if (!_downloading) {
|
||||
@@ -176,6 +176,7 @@ class _ResourcePreviewDownloaderState extends State<ResourcePreviewDownloader> {
|
||||
final response = await account.apiClient.dispatchRequestRaw(ResourceContentsRequest(
|
||||
widget.resourceId,
|
||||
versionId: widget.versionId,
|
||||
loadPreview: widget.loadPreview,
|
||||
));
|
||||
if (response.statusCode < 200 || response.statusCode > 300) {
|
||||
final error = PhylumApiErrorResponse.fromResponseBody(await response.bodyString()).message;
|
||||
+3
-3
@@ -2,8 +2,8 @@ import 'package:flutter/material.dart';
|
||||
import 'package:phylum/libphylum/db/db.dart';
|
||||
import 'package:phylum/libphylum/phylum_account.dart';
|
||||
import 'package:phylum/ui/app/shortcuts.dart';
|
||||
import 'package:phylum/ui/file_preview/file_preview.dart';
|
||||
import 'package:phylum/ui/file_preview/versioned_resource.dart';
|
||||
import 'package:phylum/ui/file_viewer/file_viewer.dart';
|
||||
import 'package:phylum/ui/file_viewer/versioned_resource.dart';
|
||||
import 'package:provider/provider.dart';
|
||||
|
||||
class FilePreviewDialog extends StatefulWidget {
|
||||
@@ -89,7 +89,7 @@ class _FilePreviewDialogState extends State<FilePreviewDialog> {
|
||||
child: Focus(
|
||||
focusNode: _focusNode,
|
||||
autofocus: true,
|
||||
child: FilePreview(transparent: true, resource: widget.resources[index]),
|
||||
child: FileViewer(transparent: true, resource: widget.resources[index]),
|
||||
),
|
||||
),
|
||||
);
|
||||
+3
-3
@@ -5,8 +5,8 @@ import 'package:phylum/libphylum/db/resource_helpers.dart';
|
||||
import 'package:phylum/libphylum/phylum_account.dart';
|
||||
import 'package:phylum/ui/app/router.dart';
|
||||
import 'package:phylum/ui/app/routes.dart';
|
||||
import 'package:phylum/ui/file_preview/file_preview.dart';
|
||||
import 'package:phylum/ui/file_preview/versioned_resource.dart';
|
||||
import 'package:phylum/ui/file_viewer/file_viewer.dart';
|
||||
import 'package:phylum/ui/file_viewer/versioned_resource.dart';
|
||||
import 'package:provider/provider.dart';
|
||||
|
||||
class FilePreviewPage extends StatefulWidget {
|
||||
@@ -62,7 +62,7 @@ class _ResourcePreviewDialogState extends State<FilePreviewPage> {
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
if (resource != null && version != null) {
|
||||
return FilePreview(
|
||||
return FileViewer(
|
||||
transparent: true,
|
||||
resource: VersionedResource(r: resource!, v: version!, showTimestamp: false),
|
||||
);
|
||||
@@ -5,7 +5,7 @@ import 'package:phylum/ui/app/shortcuts.dart';
|
||||
import 'package:phylum/ui/app/router.dart';
|
||||
import 'package:phylum/ui/layout/search.dart';
|
||||
import 'package:phylum/ui/app/routes.dart';
|
||||
import 'package:phylum/ui/file_preview/file_preview_dialog.dart';
|
||||
import 'package:phylum/ui/file_viewer/file_viewer_dialog.dart';
|
||||
import 'package:phylum/util/upload_utils.dart';
|
||||
import 'package:provider/provider.dart';
|
||||
|
||||
|
||||
Reference in New Issue
Block a user