Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 12 additions & 4 deletions mobile/lib/features/channels/compose_bar.dart
Original file line number Diff line number Diff line change
Expand Up @@ -546,7 +546,7 @@ class ComposeBar extends HookConsumerWidget {
attachments.value = [...attachments.value, uploaded];
}
} catch (error) {
if (context.mounted) {
if (context.mounted && _shouldSurfaceUploadError(error)) {
uploadError.value = _formatUploadError(error);
}
} finally {
Expand All @@ -566,12 +566,18 @@ class ComposeBar extends HookConsumerWidget {
if (picked == null || !context.mounted) return;
await pickAndUpload(() => upload(picked));
} catch (error) {
if (context.mounted) {
if (context.mounted && _shouldSurfaceUploadError(error)) {
uploadError.value = _formatUploadError(error);
}
}
}

void cancelPendingUploads() {
ref.read(mediaUploadServiceProvider).cancelActiveUploads();
uploadingCount.value = 0;
uploadError.value = null;
}

Future<void> uploadImages(List<XFile> images) async {
if (images.isEmpty) return;
uploadError.value = null;
Expand Down Expand Up @@ -617,7 +623,7 @@ class ComposeBar extends HookConsumerWidget {
.map((result) => result.error)
.whereType<Object>()
.firstOrNull;
if (firstError != null) {
if (firstError != null && _shouldSurfaceUploadError(firstError)) {
uploadError.value = _formatUploadError(firstError);
}
} finally {
Expand Down Expand Up @@ -727,7 +733,7 @@ class ComposeBar extends HookConsumerWidget {
try {
await choose();
} catch (error) {
if (context.mounted) {
if (context.mounted && _shouldSurfaceUploadError(error)) {
uploadError.value = errorMessage ?? _formatUploadError(error);
}
}
Expand Down Expand Up @@ -951,6 +957,8 @@ class ComposeBar extends HookConsumerWidget {
uploadingCount: uploadingCount.value,
onRemoveAttachment: removeAttachment,
uploadError: uploadError.value,
onDismissUploadError: () => uploadError.value = null,
onCancelUpload: hasPendingUploads ? cancelPendingUploads : null,
isExpanded: isComposerExpanded.value,
controller: controller,
focusNode: focusNode,
Expand Down
29 changes: 29 additions & 0 deletions mobile/lib/features/channels/compose_bar/attachments.dart
Original file line number Diff line number Diff line change
Expand Up @@ -471,11 +471,13 @@ class _AttachmentStrip extends StatelessWidget {
final List<BlobDescriptor> attachments;
final int uploadingCount;
final void Function(String url) onRemove;
final VoidCallback? onCancelUpload;

const _AttachmentStrip({
required this.attachments,
required this.uploadingCount,
required this.onRemove,
this.onCancelUpload,
});

@override
Expand Down Expand Up @@ -539,6 +541,33 @@ class _AttachmentStrip extends StatelessWidget {
),
),
),
if (onCancelUpload != null)
PositionedDirectional(
top: 0,
end: 0,
child: Semantics(
button: true,
label: 'Cancel upload',
child: Material(
color: context.colors.surface.withValues(
alpha: 0.92,
),
shape: const CircleBorder(),
clipBehavior: Clip.antiAlias,
child: InkWell(
onTap: onCancelUpload,
child: Padding(
padding: const EdgeInsets.all(4),
child: Icon(
LucideIcons.x,
size: 14,
color: context.colors.onSurfaceVariant,
),
),
),
),
),
),
],
),
),
Expand Down
42 changes: 35 additions & 7 deletions mobile/lib/features/channels/compose_bar/layout.dart
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@ class _ComposeBarLayout extends StatelessWidget {
final int uploadingCount;
final ValueChanged<String> onRemoveAttachment;
final String? uploadError;
final VoidCallback? onDismissUploadError;
final VoidCallback? onCancelUpload;
final bool isExpanded;
final TextEditingController controller;
final FocusNode focusNode;
Expand Down Expand Up @@ -33,6 +35,8 @@ class _ComposeBarLayout extends StatelessWidget {
required this.uploadingCount,
required this.onRemoveAttachment,
required this.uploadError,
this.onDismissUploadError,
this.onCancelUpload,
required this.isExpanded,
required this.controller,
required this.focusNode,
Expand Down Expand Up @@ -81,18 +85,42 @@ class _ComposeBarLayout extends StatelessWidget {
attachments: attachments,
uploadingCount: uploadingCount,
onRemove: onRemoveAttachment,
onCancelUpload: onCancelUpload,
),
const SizedBox(height: Grid.xxs),
],
if (uploadError case final error?) ...[
Align(
alignment: Alignment.centerLeft,
child: Text(
error,
style: context.textTheme.bodySmall?.copyWith(
color: context.colors.error,
Row(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Expanded(
child: Text(
error,
style: context.textTheme.bodySmall?.copyWith(
color: context.colors.error,
),
),
),
),
if (onDismissUploadError != null)
Semantics(
button: true,
label: 'Dismiss upload error',
child: IconButton(
visualDensity: VisualDensity.compact,
padding: EdgeInsets.zero,
constraints: const BoxConstraints(
minWidth: 32,
minHeight: 32,
),
onPressed: onDismissUploadError,
icon: Icon(
LucideIcons.x,
size: 16,
color: context.colors.error,
),
),
),
],
),
const SizedBox(height: Grid.xxs),
],
Expand Down
9 changes: 9 additions & 0 deletions mobile/lib/features/channels/compose_bar/send_button.dart
Original file line number Diff line number Diff line change
Expand Up @@ -43,5 +43,14 @@ class _SendButton extends StatelessWidget {
}

String _formatUploadError(Object error) {
if (error is MediaUploadCancelledException) {
return '';
}
if (error is MediaUploadTimeoutException) {
return error.toString();
}
return error.toString().replaceFirst('Exception: ', '');
}

bool _shouldSurfaceUploadError(Object error) =>
error is! MediaUploadCancelledException;
Loading