Better attachment preview progress

This commit is contained in:
2026-01-11 13:40:35 +08:00
parent 826238a374
commit b7d5aa5dfb
4 changed files with 272 additions and 272 deletions

View File

@@ -325,6 +325,7 @@ class ArticleComposeScreen extends HookConsumerWidget {
isCompact: true, isCompact: true,
item: attachments[idx], item: attachments[idx],
progress: progressMap[idx], progress: progressMap[idx],
isUploading: progressMap.containsKey(idx),
onRequestUpload: () async { onRequestUpload: () async {
final config = final config =
await showModalBottomSheet< await showModalBottomSheet<

View File

@@ -458,6 +458,10 @@ class ChatInput extends HookConsumerWidget {
item: attachments[idx], item: attachments[idx],
progress: progress:
attachmentProgress['chat-upload']?[idx], attachmentProgress['chat-upload']?[idx],
isUploading:
attachmentProgress['chat-upload']
?.containsKey(idx) ??
false,
onRequestUpload: () => onUploadAttachment(idx), onRequestUpload: () => onUploadAttachment(idx),
onDelete: () => onDeleteAttachment(idx), onDelete: () => onDeleteAttachment(idx),
onUpdate: (value) { onUpdate: (value) {

View File

@@ -14,13 +14,12 @@ import 'package:island/services/file_uploader.dart';
import 'package:island/utils/format.dart'; import 'package:island/utils/format.dart';
import 'package:island/widgets/alert.dart'; import 'package:island/widgets/alert.dart';
import 'package:island/widgets/content/cloud_files.dart'; import 'package:island/widgets/content/cloud_files.dart';
import 'package:island/widgets/content/sensitive.dart';
import 'package:island/widgets/content/sheet.dart'; import 'package:island/widgets/content/sheet.dart';
import 'package:material_symbols_icons/symbols.dart'; import 'package:material_symbols_icons/symbols.dart';
import 'package:styled_widget/styled_widget.dart'; import 'package:styled_widget/styled_widget.dart';
import 'package:super_context_menu/super_context_menu.dart'; import 'package:super_context_menu/super_context_menu.dart';
import 'sensitive.dart';
class SensitiveMarksSelector extends StatefulWidget { class SensitiveMarksSelector extends StatefulWidget {
final List<int> initial; final List<int> initial;
final ValueChanged<List<int>>? onChanged; final ValueChanged<List<int>>? onChanged;
@@ -85,6 +84,7 @@ class SensitiveMarksSelectorState extends State<SensitiveMarksSelector> {
class AttachmentPreview extends HookConsumerWidget { class AttachmentPreview extends HookConsumerWidget {
final UniversalFile item; final UniversalFile item;
final double? progress; final double? progress;
final bool isUploading;
final Function(int)? onMove; final Function(int)? onMove;
final Function? onDelete; final Function? onDelete;
final Function? onInsert; final Function? onInsert;
@@ -96,6 +96,7 @@ class AttachmentPreview extends HookConsumerWidget {
super.key, super.key,
required this.item, required this.item,
this.progress, this.progress,
this.isUploading = false,
this.onRequestUpload, this.onRequestUpload,
this.onMove, this.onMove,
this.onDelete, this.onDelete,
@@ -125,8 +126,7 @@ class AttachmentPreview extends HookConsumerWidget {
context: context, context: context,
isScrollControlled: true, isScrollControlled: true,
useRootNavigator: true, useRootNavigator: true,
builder: builder: (context) => SheetScaffold(
(context) => SheetScaffold(
heightFactor: 0.6, heightFactor: 0.6,
titleText: 'rename'.tr(), titleText: 'rename'.tr(),
child: Column( child: Column(
@@ -134,10 +134,7 @@ class AttachmentPreview extends HookConsumerWidget {
crossAxisAlignment: CrossAxisAlignment.stretch, crossAxisAlignment: CrossAxisAlignment.stretch,
children: [ children: [
Padding( Padding(
padding: const EdgeInsets.symmetric( padding: const EdgeInsets.symmetric(horizontal: 24, vertical: 24),
horizontal: 24,
vertical: 24,
),
child: TextField( child: TextField(
controller: nameController, controller: nameController,
decoration: InputDecoration( decoration: InputDecoration(
@@ -174,10 +171,7 @@ class AttachmentPreview extends HookConsumerWidget {
final newData = item.data; final newData = item.data;
newData.name = newName; newData.name = newName;
onUpdate?.call( onUpdate?.call(
item.copyWith( item.copyWith(data: newData, displayName: newName),
data: newData,
displayName: newName,
),
); );
if (context.mounted) Navigator.pop(context); if (context.mounted) Navigator.pop(context);
} catch (err) { } catch (err) {
@@ -205,8 +199,7 @@ class AttachmentPreview extends HookConsumerWidget {
await showModalBottomSheet( await showModalBottomSheet(
context: context, context: context,
isScrollControlled: true, isScrollControlled: true,
builder: builder: (context) => SheetScaffold(
(context) => SheetScaffold(
heightFactor: 0.6, heightFactor: 0.6,
titleText: 'markAsSensitive'.tr(), titleText: 'markAsSensitive'.tr(),
child: Column( child: Column(
@@ -214,17 +207,13 @@ class AttachmentPreview extends HookConsumerWidget {
crossAxisAlignment: CrossAxisAlignment.stretch, crossAxisAlignment: CrossAxisAlignment.stretch,
children: [ children: [
Padding( Padding(
padding: const EdgeInsets.symmetric( padding: const EdgeInsets.symmetric(horizontal: 24, vertical: 24),
horizontal: 24,
vertical: 24,
),
child: Column( child: Column(
children: [ children: [
// Sensitive categories checklist // Sensitive categories checklist
SensitiveMarksSelector( SensitiveMarksSelector(
key: _sensitiveSelectorKey, key: _sensitiveSelectorKey,
initial: initial: (item.data.sensitiveMarks ?? [])
(item.data.sensitiveMarks ?? [])
.map((e) => e as int) .map((e) => e as int)
.cast<int>() .cast<int>()
.toList(), .toList(),
@@ -253,8 +242,7 @@ class AttachmentPreview extends HookConsumerWidget {
showLoadingModal(context); showLoadingModal(context);
final apiClient = ref.watch(apiClientProvider); final apiClient = ref.watch(apiClientProvider);
// Use the current selections from stateful selector via GlobalKey // Use the current selections from stateful selector via GlobalKey
final selectorState = final selectorState = _sensitiveSelectorKey.currentState;
_sensitiveSelectorKey.currentState;
final marks = selectorState?.current ?? <int>[]; final marks = selectorState?.current ?? <int>[];
await apiClient.put( await apiClient.put(
'/drive/files/${item.data.id}/marks', '/drive/files/${item.data.id}/marks',
@@ -284,8 +272,7 @@ class AttachmentPreview extends HookConsumerWidget {
@override @override
Widget build(BuildContext context, WidgetRef ref) { Widget build(BuildContext context, WidgetRef ref) {
var ratio = var ratio = item.isOnCloud
item.isOnCloud
? (item.data.fileMeta?['ratio'] is num ? (item.data.fileMeta?['ratio'] is num
? item.data.fileMeta!['ratio'].toDouble() ? item.data.fileMeta!['ratio'].toDouble()
: 1.0) : 1.0)
@@ -387,7 +374,7 @@ class AttachmentPreview extends HookConsumerWidget {
return Placeholder(); return Placeholder();
}, },
), ),
if (progress != null) if (isUploading && progress != null && (progress ?? 0) > 0)
Positioned.fill( Positioned.fill(
child: Container( child: Container(
color: Colors.black.withOpacity(0.3), color: Colors.black.withOpacity(0.3),
@@ -399,15 +386,9 @@ class AttachmentPreview extends HookConsumerWidget {
mainAxisAlignment: MainAxisAlignment.center, mainAxisAlignment: MainAxisAlignment.center,
crossAxisAlignment: CrossAxisAlignment.center, crossAxisAlignment: CrossAxisAlignment.center,
children: [ children: [
if (progress != null)
Text( Text(
'${(progress! * 100).toStringAsFixed(2)}%', '${(progress! * 100).toStringAsFixed(2)}%',
style: TextStyle(color: Colors.white), style: TextStyle(color: Colors.white),
)
else
Text(
'uploading'.tr(),
style: TextStyle(color: Colors.white),
), ),
Gap(6), Gap(6),
Center( Center(
@@ -417,6 +398,28 @@ class AttachmentPreview extends HookConsumerWidget {
), ),
), ),
), ),
if (isUploading && (progress == null || progress == 0))
Positioned.fill(
child: Container(
color: Colors.black.withOpacity(0.3),
padding: EdgeInsets.symmetric(
horizontal: 40,
vertical: 16,
),
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
crossAxisAlignment: CrossAxisAlignment.center,
children: [
Text(
'processing'.tr(),
style: TextStyle(color: Colors.white),
),
Gap(6),
Center(child: LinearProgressIndicator(value: null)),
],
),
),
),
], ],
), ),
).center(), ).center(),
@@ -497,8 +500,9 @@ class AttachmentPreview extends HookConsumerWidget {
if (onRequestUpload != null) if (onRequestUpload != null)
InkWell( InkWell(
borderRadius: BorderRadius.circular(8), borderRadius: BorderRadius.circular(8),
onTap: onTap: item.isOnCloud
item.isOnCloud ? null : () => onRequestUpload?.call(), ? null
: () => onRequestUpload?.call(),
child: ClipRRect( child: ClipRRect(
borderRadius: BorderRadius.circular(8), borderRadius: BorderRadius.circular(8),
child: Container( child: Container(
@@ -507,8 +511,7 @@ class AttachmentPreview extends HookConsumerWidget {
horizontal: 8, horizontal: 8,
vertical: 4, vertical: 4,
), ),
child: child: (item.isOnCloud)
(item.isOnCloud)
? Row( ? Row(
mainAxisSize: MainAxisSize.min, mainAxisSize: MainAxisSize.min,
children: [ children: [
@@ -552,8 +555,7 @@ class AttachmentPreview extends HookConsumerWidget {
); );
return ContextMenuWidget( return ContextMenuWidget(
menuProvider: menuProvider: (MenuRequest request) => Menu(
(MenuRequest request) => Menu(
children: [ children: [
if (item.isOnDevice && item.type == UniversalFileType.image) if (item.isOnDevice && item.type == UniversalFileType.image)
MenuAction( MenuAction(

View File

@@ -71,13 +71,13 @@ class ComposeAttachments extends ConsumerWidget {
isCompact: isCompact, isCompact: isCompact,
item: state.attachments.value[idx], item: state.attachments.value[idx],
progress: progressMap[idx], progress: progressMap[idx],
isUploading: progressMap.containsKey(idx),
onRequestUpload: () async { onRequestUpload: () async {
final config = await showModalBottomSheet<AttachmentUploadConfig>( final config = await showModalBottomSheet<AttachmentUploadConfig>(
context: ref.context, context: ref.context,
isScrollControlled: true, isScrollControlled: true,
useRootNavigator: true, useRootNavigator: true,
builder: builder: (context) =>
(context) =>
AttachmentUploaderSheet(ref: ref, state: state, index: idx), AttachmentUploaderSheet(ref: ref, state: state, index: idx),
); );
if (config != null) { if (config != null) {
@@ -146,14 +146,16 @@ class ArticleComposeAttachments extends ConsumerWidget {
isCompact: true, isCompact: true,
item: attachments[idx], item: attachments[idx],
progress: progressMap[idx], progress: progressMap[idx],
isUploading: progressMap.containsKey(idx),
onRequestUpload: () async { onRequestUpload: () async {
final config = await showModalBottomSheet< final config =
await showModalBottomSheet<
AttachmentUploadConfig AttachmentUploadConfig
>( >(
context: context, context: context,
isScrollControlled: true, isScrollControlled: true,
builder: builder: (context) =>
(context) => AttachmentUploaderSheet( AttachmentUploaderSheet(
ref: ref, ref: ref,
state: state, state: state,
index: idx, index: idx,
@@ -168,24 +170,15 @@ class ArticleComposeAttachments extends ConsumerWidget {
); );
} }
}, },
onUpdate: onUpdate: (value) => ComposeLogic.updateAttachment(
(value) => ComposeLogic.updateAttachment(
state, state,
value, value,
idx, idx,
), ),
onDelete: onDelete: () =>
() => ComposeLogic.deleteAttachment( ComposeLogic.deleteAttachment(ref, state, idx),
ref, onInsert: () =>
state, ComposeLogic.insertAttachment(ref, state, idx),
idx,
),
onInsert:
() => ComposeLogic.insertAttachment(
ref,
state,
idx,
),
), ),
), ),
], ],