✨ Better attachment preview progress
This commit is contained in:
@@ -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<
|
||||||
|
|||||||
@@ -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) {
|
||||||
|
|||||||
@@ -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,79 +126,72 @@ 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(
|
mainAxisSize: MainAxisSize.min,
|
||||||
mainAxisSize: MainAxisSize.min,
|
crossAxisAlignment: CrossAxisAlignment.stretch,
|
||||||
crossAxisAlignment: CrossAxisAlignment.stretch,
|
children: [
|
||||||
children: [
|
Padding(
|
||||||
Padding(
|
padding: const EdgeInsets.symmetric(horizontal: 24, vertical: 24),
|
||||||
padding: const EdgeInsets.symmetric(
|
child: TextField(
|
||||||
horizontal: 24,
|
controller: nameController,
|
||||||
vertical: 24,
|
decoration: InputDecoration(
|
||||||
),
|
labelText: 'fileName'.tr(),
|
||||||
child: TextField(
|
border: const OutlineInputBorder(),
|
||||||
controller: nameController,
|
errorText: errorMessage,
|
||||||
decoration: InputDecoration(
|
|
||||||
labelText: 'fileName'.tr(),
|
|
||||||
border: const OutlineInputBorder(),
|
|
||||||
errorText: errorMessage,
|
|
||||||
),
|
|
||||||
),
|
|
||||||
),
|
),
|
||||||
Row(
|
),
|
||||||
mainAxisAlignment: MainAxisAlignment.end,
|
|
||||||
children: [
|
|
||||||
TextButton(
|
|
||||||
onPressed: () => Navigator.pop(context),
|
|
||||||
child: Text('cancel'.tr()),
|
|
||||||
),
|
|
||||||
const Gap(8),
|
|
||||||
TextButton(
|
|
||||||
onPressed: () async {
|
|
||||||
final newName = nameController.text.trim();
|
|
||||||
if (newName.isEmpty) {
|
|
||||||
errorMessage = 'fieldCannotBeEmpty'.tr();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (item.isOnCloud) {
|
|
||||||
try {
|
|
||||||
showLoadingModal(context);
|
|
||||||
final apiClient = ref.watch(apiClientProvider);
|
|
||||||
await apiClient.patch(
|
|
||||||
'/drive/files/${item.data.id}/name',
|
|
||||||
data: jsonEncode(newName),
|
|
||||||
);
|
|
||||||
final newData = item.data;
|
|
||||||
newData.name = newName;
|
|
||||||
onUpdate?.call(
|
|
||||||
item.copyWith(
|
|
||||||
data: newData,
|
|
||||||
displayName: newName,
|
|
||||||
),
|
|
||||||
);
|
|
||||||
if (context.mounted) Navigator.pop(context);
|
|
||||||
} catch (err) {
|
|
||||||
showErrorAlert(err);
|
|
||||||
} finally {
|
|
||||||
if (context.mounted) hideLoadingModal(context);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
// Local file rename
|
|
||||||
onUpdate?.call(item.copyWith(displayName: newName));
|
|
||||||
if (context.mounted) Navigator.pop(context);
|
|
||||||
}
|
|
||||||
},
|
|
||||||
child: Text('rename'.tr()),
|
|
||||||
),
|
|
||||||
],
|
|
||||||
).padding(horizontal: 16, vertical: 8),
|
|
||||||
],
|
|
||||||
),
|
),
|
||||||
),
|
Row(
|
||||||
|
mainAxisAlignment: MainAxisAlignment.end,
|
||||||
|
children: [
|
||||||
|
TextButton(
|
||||||
|
onPressed: () => Navigator.pop(context),
|
||||||
|
child: Text('cancel'.tr()),
|
||||||
|
),
|
||||||
|
const Gap(8),
|
||||||
|
TextButton(
|
||||||
|
onPressed: () async {
|
||||||
|
final newName = nameController.text.trim();
|
||||||
|
if (newName.isEmpty) {
|
||||||
|
errorMessage = 'fieldCannotBeEmpty'.tr();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (item.isOnCloud) {
|
||||||
|
try {
|
||||||
|
showLoadingModal(context);
|
||||||
|
final apiClient = ref.watch(apiClientProvider);
|
||||||
|
await apiClient.patch(
|
||||||
|
'/drive/files/${item.data.id}/name',
|
||||||
|
data: jsonEncode(newName),
|
||||||
|
);
|
||||||
|
final newData = item.data;
|
||||||
|
newData.name = newName;
|
||||||
|
onUpdate?.call(
|
||||||
|
item.copyWith(data: newData, displayName: newName),
|
||||||
|
);
|
||||||
|
if (context.mounted) Navigator.pop(context);
|
||||||
|
} catch (err) {
|
||||||
|
showErrorAlert(err);
|
||||||
|
} finally {
|
||||||
|
if (context.mounted) hideLoadingModal(context);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// Local file rename
|
||||||
|
onUpdate?.call(item.copyWith(displayName: newName));
|
||||||
|
if (context.mounted) Navigator.pop(context);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
child: Text('rename'.tr()),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
).padding(horizontal: 16, vertical: 8),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -205,91 +199,84 @@ 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(
|
mainAxisSize: MainAxisSize.min,
|
||||||
mainAxisSize: MainAxisSize.min,
|
crossAxisAlignment: CrossAxisAlignment.stretch,
|
||||||
crossAxisAlignment: CrossAxisAlignment.stretch,
|
children: [
|
||||||
children: [
|
Padding(
|
||||||
Padding(
|
padding: const EdgeInsets.symmetric(horizontal: 24, vertical: 24),
|
||||||
padding: const EdgeInsets.symmetric(
|
child: Column(
|
||||||
horizontal: 24,
|
children: [
|
||||||
vertical: 24,
|
// Sensitive categories checklist
|
||||||
|
SensitiveMarksSelector(
|
||||||
|
key: _sensitiveSelectorKey,
|
||||||
|
initial: (item.data.sensitiveMarks ?? [])
|
||||||
|
.map((e) => e as int)
|
||||||
|
.cast<int>()
|
||||||
|
.toList(),
|
||||||
|
onChanged: (marks) {
|
||||||
|
// Update local data immediately (optimistic)
|
||||||
|
final newData = item.data;
|
||||||
|
newData.sensitiveMarks = marks;
|
||||||
|
final updatedFile = item.copyWith(data: newData);
|
||||||
|
onUpdate?.call(item.copyWith(data: updatedFile));
|
||||||
|
},
|
||||||
),
|
),
|
||||||
child: Column(
|
],
|
||||||
children: [
|
),
|
||||||
// Sensitive categories checklist
|
|
||||||
SensitiveMarksSelector(
|
|
||||||
key: _sensitiveSelectorKey,
|
|
||||||
initial:
|
|
||||||
(item.data.sensitiveMarks ?? [])
|
|
||||||
.map((e) => e as int)
|
|
||||||
.cast<int>()
|
|
||||||
.toList(),
|
|
||||||
onChanged: (marks) {
|
|
||||||
// Update local data immediately (optimistic)
|
|
||||||
final newData = item.data;
|
|
||||||
newData.sensitiveMarks = marks;
|
|
||||||
final updatedFile = item.copyWith(data: newData);
|
|
||||||
onUpdate?.call(item.copyWith(data: updatedFile));
|
|
||||||
},
|
|
||||||
),
|
|
||||||
],
|
|
||||||
),
|
|
||||||
),
|
|
||||||
Row(
|
|
||||||
mainAxisAlignment: MainAxisAlignment.end,
|
|
||||||
children: [
|
|
||||||
TextButton(
|
|
||||||
onPressed: () => Navigator.pop(context),
|
|
||||||
child: Text('cancel'.tr()),
|
|
||||||
),
|
|
||||||
const Gap(8),
|
|
||||||
TextButton(
|
|
||||||
onPressed: () async {
|
|
||||||
try {
|
|
||||||
showLoadingModal(context);
|
|
||||||
final apiClient = ref.watch(apiClientProvider);
|
|
||||||
// Use the current selections from stateful selector via GlobalKey
|
|
||||||
final selectorState =
|
|
||||||
_sensitiveSelectorKey.currentState;
|
|
||||||
final marks = selectorState?.current ?? <int>[];
|
|
||||||
await apiClient.put(
|
|
||||||
'/drive/files/${item.data.id}/marks',
|
|
||||||
data: jsonEncode({'sensitive_marks': marks}),
|
|
||||||
);
|
|
||||||
final newData = item.data as SnCloudFile;
|
|
||||||
final updatedFile = item.copyWith(
|
|
||||||
data: newData.copyWith(sensitiveMarks: marks),
|
|
||||||
);
|
|
||||||
onUpdate?.call(updatedFile);
|
|
||||||
if (context.mounted) Navigator.pop(context);
|
|
||||||
} catch (err) {
|
|
||||||
showErrorAlert(err);
|
|
||||||
} finally {
|
|
||||||
if (context.mounted) hideLoadingModal(context);
|
|
||||||
}
|
|
||||||
},
|
|
||||||
child: Text('confirm'.tr()),
|
|
||||||
),
|
|
||||||
],
|
|
||||||
).padding(horizontal: 16, vertical: 8),
|
|
||||||
],
|
|
||||||
),
|
),
|
||||||
),
|
Row(
|
||||||
|
mainAxisAlignment: MainAxisAlignment.end,
|
||||||
|
children: [
|
||||||
|
TextButton(
|
||||||
|
onPressed: () => Navigator.pop(context),
|
||||||
|
child: Text('cancel'.tr()),
|
||||||
|
),
|
||||||
|
const Gap(8),
|
||||||
|
TextButton(
|
||||||
|
onPressed: () async {
|
||||||
|
try {
|
||||||
|
showLoadingModal(context);
|
||||||
|
final apiClient = ref.watch(apiClientProvider);
|
||||||
|
// Use the current selections from stateful selector via GlobalKey
|
||||||
|
final selectorState = _sensitiveSelectorKey.currentState;
|
||||||
|
final marks = selectorState?.current ?? <int>[];
|
||||||
|
await apiClient.put(
|
||||||
|
'/drive/files/${item.data.id}/marks',
|
||||||
|
data: jsonEncode({'sensitive_marks': marks}),
|
||||||
|
);
|
||||||
|
final newData = item.data as SnCloudFile;
|
||||||
|
final updatedFile = item.copyWith(
|
||||||
|
data: newData.copyWith(sensitiveMarks: marks),
|
||||||
|
);
|
||||||
|
onUpdate?.call(updatedFile);
|
||||||
|
if (context.mounted) Navigator.pop(context);
|
||||||
|
} catch (err) {
|
||||||
|
showErrorAlert(err);
|
||||||
|
} finally {
|
||||||
|
if (context.mounted) hideLoadingModal(context);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
child: Text('confirm'.tr()),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
).padding(horizontal: 16, vertical: 8),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@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)
|
: 1.0;
|
||||||
: 1.0;
|
|
||||||
if (ratio == 0) ratio = 1.0;
|
if (ratio == 0) ratio = 1.0;
|
||||||
|
|
||||||
final contentWidget = ClipRRect(
|
final contentWidget = ClipRRect(
|
||||||
@@ -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,16 +386,10 @@ 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(
|
||||||
child: LinearProgressIndicator(value: progress),
|
child: LinearProgressIndicator(value: progress),
|
||||||
@@ -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,40 +511,39 @@ 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: [
|
Icon(
|
||||||
Icon(
|
Symbols.cloud,
|
||||||
Symbols.cloud,
|
size: 16,
|
||||||
size: 16,
|
color: Colors.white,
|
||||||
color: Colors.white,
|
),
|
||||||
|
if (!isCompact) const Gap(8),
|
||||||
|
if (!isCompact)
|
||||||
|
Text(
|
||||||
|
'attachmentOnCloud'.tr(),
|
||||||
|
style: TextStyle(color: Colors.white),
|
||||||
),
|
),
|
||||||
if (!isCompact) const Gap(8),
|
],
|
||||||
if (!isCompact)
|
)
|
||||||
Text(
|
: Row(
|
||||||
'attachmentOnCloud'.tr(),
|
mainAxisSize: MainAxisSize.min,
|
||||||
style: TextStyle(color: Colors.white),
|
children: [
|
||||||
),
|
Icon(
|
||||||
],
|
Symbols.cloud_off,
|
||||||
)
|
size: 16,
|
||||||
: Row(
|
color: Colors.white,
|
||||||
mainAxisSize: MainAxisSize.min,
|
),
|
||||||
children: [
|
if (!isCompact) const Gap(8),
|
||||||
Icon(
|
if (!isCompact)
|
||||||
Symbols.cloud_off,
|
Text(
|
||||||
size: 16,
|
'attachmentOnDevice'.tr(),
|
||||||
color: Colors.white,
|
style: TextStyle(color: Colors.white),
|
||||||
),
|
),
|
||||||
if (!isCompact) const Gap(8),
|
],
|
||||||
if (!isCompact)
|
),
|
||||||
Text(
|
|
||||||
'attachmentOnDevice'.tr(),
|
|
||||||
style: TextStyle(color: Colors.white),
|
|
||||||
),
|
|
||||||
],
|
|
||||||
),
|
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
@@ -552,49 +555,48 @@ 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(
|
title: 'crop'.tr(),
|
||||||
title: 'crop'.tr(),
|
image: MenuImage.icon(Symbols.crop),
|
||||||
image: MenuImage.icon(Symbols.crop),
|
callback: () async {
|
||||||
callback: () async {
|
final result = await cropImage(
|
||||||
final result = await cropImage(
|
context,
|
||||||
context,
|
image: item.data,
|
||||||
image: item.data,
|
replacePath: true,
|
||||||
replacePath: true,
|
);
|
||||||
);
|
if (result == null) return;
|
||||||
if (result == null) return;
|
onUpdate?.call(item.copyWith(data: result));
|
||||||
onUpdate?.call(item.copyWith(data: result));
|
},
|
||||||
},
|
),
|
||||||
),
|
if (item.isOnDevice)
|
||||||
if (item.isOnDevice)
|
MenuAction(
|
||||||
MenuAction(
|
title: 'rename'.tr(),
|
||||||
title: 'rename'.tr(),
|
image: MenuImage.icon(Symbols.edit),
|
||||||
image: MenuImage.icon(Symbols.edit),
|
callback: () async {
|
||||||
callback: () async {
|
await _showRenameSheet(context, ref);
|
||||||
await _showRenameSheet(context, ref);
|
},
|
||||||
},
|
),
|
||||||
),
|
if (item.isOnCloud)
|
||||||
if (item.isOnCloud)
|
MenuAction(
|
||||||
MenuAction(
|
title: 'rename'.tr(),
|
||||||
title: 'rename'.tr(),
|
image: MenuImage.icon(Symbols.edit),
|
||||||
image: MenuImage.icon(Symbols.edit),
|
callback: () async {
|
||||||
callback: () async {
|
await _showRenameSheet(context, ref);
|
||||||
await _showRenameSheet(context, ref);
|
},
|
||||||
},
|
),
|
||||||
),
|
if (item.isOnCloud)
|
||||||
if (item.isOnCloud)
|
MenuAction(
|
||||||
MenuAction(
|
title: 'markAsSensitive'.tr(),
|
||||||
title: 'markAsSensitive'.tr(),
|
image: MenuImage.icon(Symbols.no_adult_content),
|
||||||
image: MenuImage.icon(Symbols.no_adult_content),
|
callback: () async {
|
||||||
callback: () async {
|
await _showSensitiveDialog(context, ref);
|
||||||
await _showSensitiveDialog(context, ref);
|
},
|
||||||
},
|
),
|
||||||
),
|
],
|
||||||
],
|
),
|
||||||
),
|
|
||||||
child: contentWidget,
|
child: contentWidget,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -71,14 +71,14 @@ 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) {
|
||||||
await ComposeLogic.uploadAttachment(
|
await ComposeLogic.uploadAttachment(
|
||||||
@@ -146,19 +146,21 @@ 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 =
|
||||||
AttachmentUploadConfig
|
await showModalBottomSheet<
|
||||||
>(
|
AttachmentUploadConfig
|
||||||
context: context,
|
>(
|
||||||
isScrollControlled: true,
|
context: context,
|
||||||
builder:
|
isScrollControlled: true,
|
||||||
(context) => AttachmentUploaderSheet(
|
builder: (context) =>
|
||||||
ref: ref,
|
AttachmentUploaderSheet(
|
||||||
state: state,
|
ref: ref,
|
||||||
index: idx,
|
state: state,
|
||||||
),
|
index: idx,
|
||||||
);
|
),
|
||||||
|
);
|
||||||
if (config != null) {
|
if (config != null) {
|
||||||
await ComposeLogic.uploadAttachment(
|
await ComposeLogic.uploadAttachment(
|
||||||
ref,
|
ref,
|
||||||
@@ -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(ref, state, idx),
|
||||||
() => ComposeLogic.deleteAttachment(
|
onInsert: () =>
|
||||||
ref,
|
ComposeLogic.insertAttachment(ref, state, idx),
|
||||||
state,
|
|
||||||
idx,
|
|
||||||
),
|
|
||||||
onInsert:
|
|
||||||
() => ComposeLogic.insertAttachment(
|
|
||||||
ref,
|
|
||||||
state,
|
|
||||||
idx,
|
|
||||||
),
|
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
|
|||||||
Reference in New Issue
Block a user