feat: Send optional message with images or files

pull/1654/head
Krille 3 days ago
parent 00d219bae1
commit 4f67992d9e
No known key found for this signature in database
GPG Key ID: E067ECD60F1A0652

@ -3203,5 +3203,6 @@
"crossVerifiedDevices": "Cross verified devices",
"verifiedDevicesOnly": "Verified devices only",
"takeAPhoto": "Take a photo",
"recordAVideo": "Record a video"
"recordAVideo": "Record a video",
"optionalMessage": "(Optional) message..."
}

@ -13,6 +13,7 @@ import 'package:fluffychat/utils/other_party_can_receive.dart';
import 'package:fluffychat/utils/platform_infos.dart';
import 'package:fluffychat/utils/size_string.dart';
import 'package:fluffychat/widgets/adaptive_dialogs/adaptive_dialog_action.dart';
import 'package:fluffychat/widgets/adaptive_dialogs/dialog_text_field.dart';
import '../../utils/resize_video.dart';
class SendFileDialog extends StatefulWidget {
@ -37,6 +38,8 @@ class SendFileDialogState extends State<SendFileDialog> {
/// Images smaller than 20kb don't need compression.
static const int minSizeToCompress = 20 * 1000;
final TextEditingController _labelTextController = TextEditingController();
Future<void> _send() async {
final scaffoldMessenger = ScaffoldMessenger.of(widget.outerContext);
final l10n = L10n.of(context);
@ -93,11 +96,14 @@ class SendFileDialogState extends State<SendFileDialog> {
scaffoldMessenger.clearSnackBars();
}
final label = _labelTextController.text.trim();
try {
await widget.room.sendFileEvent(
file,
thumbnail: thumbnail,
shrinkImageMaxDimension: compress ? 1600 : null,
extraContent: label.isEmpty ? null : {'body': label},
);
} on MatrixException catch (e) {
final retryAfterMs = e.retryAfterMs;
@ -121,7 +127,8 @@ class SendFileDialogState extends State<SendFileDialog> {
await widget.room.sendFileEvent(
file,
thumbnail: thumbnail,
shrinkImageMaxDimension: compress ? null : 1600,
shrinkImageMaxDimension: compress ? 1600 : null,
extraContent: label.isEmpty ? null : {'body': label},
);
}
}
@ -306,6 +313,18 @@ class SendFileDialogState extends State<SendFileDialog> {
],
),
),
if (widget.files.length == 1)
Padding(
padding: const EdgeInsets.symmetric(vertical: 12.0),
child: DialogTextField(
controller: _labelTextController,
labelText: L10n.of(context).optionalMessage,
minLines: 1,
maxLines: 3,
maxLength: 255,
counterText: '',
),
),
// Workaround for SwitchListTile.adaptive crashes in CupertinoDialog
if ({'image', 'video'}.contains(uniqueFileType))
Row(

@ -0,0 +1,95 @@
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
class DialogTextField extends StatelessWidget {
final TextEditingController? controller;
final String? hintText;
final String? labelText;
final String? initialText;
final String? counterText;
final String? prefixText;
final String? suffixText;
final String? errorText;
final bool obscureText = false;
final bool isDestructive = false;
final int? minLines;
final int? maxLines;
final TextInputType? keyboardType;
final int? maxLength;
final bool autocorrect = true;
const DialogTextField({
super.key,
this.hintText,
this.labelText,
this.initialText,
this.prefixText,
this.suffixText,
this.minLines,
this.maxLines,
this.keyboardType,
this.maxLength,
this.controller,
this.counterText,
this.errorText,
});
@override
Widget build(BuildContext context) {
final prefixText = this.prefixText;
final suffixText = this.suffixText;
final errorText = this.errorText;
final theme = Theme.of(context);
switch (theme.platform) {
case TargetPlatform.android:
case TargetPlatform.fuchsia:
case TargetPlatform.linux:
case TargetPlatform.windows:
return TextField(
controller: controller,
obscureText: obscureText,
minLines: minLines,
maxLines: maxLines,
maxLength: maxLength,
keyboardType: keyboardType,
autocorrect: autocorrect,
decoration: InputDecoration(
errorText: errorText,
hintText: hintText,
labelText: labelText,
prefixText: prefixText,
suffixText: suffixText,
counterText: counterText,
),
);
case TargetPlatform.iOS:
case TargetPlatform.macOS:
return Column(
mainAxisSize: MainAxisSize.min,
children: [
CupertinoTextField(
controller: controller,
obscureText: obscureText,
minLines: minLines,
maxLines: maxLines,
maxLength: maxLength,
keyboardType: keyboardType,
autocorrect: autocorrect,
prefix: prefixText != null ? Text(prefixText) : null,
suffix: suffixText != null ? Text(suffixText) : null,
placeholder: labelText ?? hintText,
),
if (errorText != null)
Text(
errorText,
style: TextStyle(
fontSize: 11,
color: theme.colorScheme.error,
),
textAlign: TextAlign.left,
),
],
);
}
}
}

@ -1,4 +1,3 @@
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:flutter_gen/gen_l10n/l10n.dart';
@ -6,6 +5,7 @@ import 'package:flutter_linkify/flutter_linkify.dart';
import 'package:fluffychat/utils/url_launcher.dart';
import 'package:fluffychat/widgets/adaptive_dialogs/adaptive_dialog_action.dart';
import 'package:fluffychat/widgets/adaptive_dialogs/dialog_text_field.dart';
Future<String?> showTextInputDialog({
required BuildContext context,
@ -28,7 +28,6 @@ Future<String?> showTextInputDialog({
int? maxLength,
bool autocorrect = true,
}) {
final theme = Theme.of(context);
return showAdaptiveDialog<String>(
context: context,
useRootNavigator: useRootNavigator,
@ -61,58 +60,19 @@ Future<String?> showTextInputDialog({
ValueListenableBuilder<String?>(
valueListenable: error,
builder: (context, error, _) {
switch (theme.platform) {
case TargetPlatform.android:
case TargetPlatform.fuchsia:
case TargetPlatform.linux:
case TargetPlatform.windows:
return TextField(
controller: controller,
obscureText: obscureText,
minLines: minLines,
maxLines: maxLines,
maxLength: maxLength,
keyboardType: keyboardType,
autocorrect: autocorrect,
decoration: InputDecoration(
errorText: error,
hintText: hintText,
labelText: labelText,
prefixText: prefixText,
suffixText: suffixText,
),
);
case TargetPlatform.iOS:
case TargetPlatform.macOS:
return Column(
mainAxisSize: MainAxisSize.min,
children: [
CupertinoTextField(
controller: controller,
obscureText: obscureText,
minLines: minLines,
maxLines: maxLines,
maxLength: maxLength,
keyboardType: keyboardType,
autocorrect: autocorrect,
prefix:
prefixText != null ? Text(prefixText) : null,
suffix:
suffixText != null ? Text(suffixText) : null,
placeholder: labelText ?? hintText,
),
if (error != null)
Text(
error,
style: TextStyle(
fontSize: 11,
color: theme.colorScheme.error,
),
textAlign: TextAlign.left,
),
],
);
}
return DialogTextField(
hintText: hintText,
errorText: error,
labelText: labelText,
controller: controller,
initialText: initialText,
prefixText: prefixText,
suffixText: suffixText,
minLines: minLines,
maxLines: maxLines,
maxLength: maxLength,
keyboardType: keyboardType,
);
},
),
],

Loading…
Cancel
Save