mirror of
https://github.com/dz0ny/meshcore-sar.git
synced 2026-08-11 16:30:28 +00:00
fix: clean up messages composer bar
ref:
This commit is contained in:
@@ -287,61 +287,6 @@ class _MessagesTabState extends State<MessagesTab> {
|
|||||||
return 'Select recipient';
|
return 'Select recipient';
|
||||||
}
|
}
|
||||||
|
|
||||||
String _getCurrentScopeLabel() {
|
|
||||||
if (_destinationType ==
|
|
||||||
MessageDestinationPreferences.destinationTypeChannel) {
|
|
||||||
final channelName =
|
|
||||||
_selectedRecipient?.getLocalizedDisplayName(context) ??
|
|
||||||
AppLocalizations.of(context)!.publicChannel;
|
|
||||||
return 'Channel > $channelName';
|
|
||||||
}
|
|
||||||
|
|
||||||
if (_destinationType == MessageDestinationPreferences.destinationTypeRoom) {
|
|
||||||
final roomName =
|
|
||||||
_selectedRecipient?.displayName ??
|
|
||||||
AppLocalizations.of(context)!.messages;
|
|
||||||
return 'Room > $roomName';
|
|
||||||
}
|
|
||||||
|
|
||||||
final contactName =
|
|
||||||
_selectedRecipient?.displayName ??
|
|
||||||
AppLocalizations.of(context)!.messages;
|
|
||||||
return 'Direct > $contactName';
|
|
||||||
}
|
|
||||||
|
|
||||||
Widget _buildScopeIndicator() {
|
|
||||||
final theme = Theme.of(context);
|
|
||||||
|
|
||||||
return SizedBox(
|
|
||||||
width: double.infinity,
|
|
||||||
child: Align(
|
|
||||||
alignment: Alignment.centerLeft,
|
|
||||||
child: Row(
|
|
||||||
mainAxisSize: MainAxisSize.min,
|
|
||||||
children: [
|
|
||||||
Icon(
|
|
||||||
Icons.visibility_outlined,
|
|
||||||
size: 14,
|
|
||||||
color: theme.colorScheme.onSurfaceVariant,
|
|
||||||
),
|
|
||||||
const SizedBox(width: 6),
|
|
||||||
Flexible(
|
|
||||||
child: Text(
|
|
||||||
'View: ${_getCurrentScopeLabel()}',
|
|
||||||
maxLines: 1,
|
|
||||||
overflow: TextOverflow.ellipsis,
|
|
||||||
textAlign: TextAlign.left,
|
|
||||||
style: theme.textTheme.labelSmall?.copyWith(
|
|
||||||
color: theme.colorScheme.onSurfaceVariant,
|
|
||||||
),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
],
|
|
||||||
),
|
|
||||||
),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
Future<void> _sendMessage() async {
|
Future<void> _sendMessage() async {
|
||||||
final text = _textController.text.trim();
|
final text = _textController.text.trim();
|
||||||
if (text.isEmpty) return;
|
if (text.isEmpty) return;
|
||||||
@@ -1622,7 +1567,7 @@ class _MessagesTabState extends State<MessagesTab> {
|
|||||||
vertical: 8,
|
vertical: 8,
|
||||||
),
|
),
|
||||||
child: Row(
|
child: Row(
|
||||||
crossAxisAlignment: CrossAxisAlignment.end,
|
crossAxisAlignment: CrossAxisAlignment.center,
|
||||||
children: [
|
children: [
|
||||||
// Quick actions (+) button
|
// Quick actions (+) button
|
||||||
IconButton(
|
IconButton(
|
||||||
@@ -1672,114 +1617,126 @@ class _MessagesTabState extends State<MessagesTab> {
|
|||||||
),
|
),
|
||||||
),
|
),
|
||||||
const SizedBox(width: 4),
|
const SizedBox(width: 4),
|
||||||
// Scope label + text field share the same alignment
|
|
||||||
Expanded(
|
Expanded(
|
||||||
child: Column(
|
child: TextField(
|
||||||
mainAxisSize: MainAxisSize.min,
|
controller: _textController,
|
||||||
crossAxisAlignment: CrossAxisAlignment.start,
|
focusNode: _focusNode,
|
||||||
children: [
|
maxLength: _maxCharacters,
|
||||||
Padding(
|
maxLines: null,
|
||||||
padding: const EdgeInsets.only(
|
maxLengthEnforcement: MaxLengthEnforcement.enforced,
|
||||||
left: 4,
|
style: const TextStyle(fontSize: 14),
|
||||||
right: 4,
|
decoration: InputDecoration(
|
||||||
bottom: 6,
|
hintText: AppLocalizations.of(
|
||||||
),
|
context,
|
||||||
child: _buildScopeIndicator(),
|
)!.typeYourMessage,
|
||||||
|
hintStyle: const TextStyle(fontSize: 14),
|
||||||
|
border: OutlineInputBorder(
|
||||||
|
borderRadius: BorderRadius.circular(24),
|
||||||
),
|
),
|
||||||
TextField(
|
contentPadding: const EdgeInsets.symmetric(
|
||||||
controller: _textController,
|
horizontal: 16,
|
||||||
focusNode: _focusNode,
|
vertical: 10,
|
||||||
maxLength: _maxCharacters,
|
),
|
||||||
maxLines: null,
|
isDense: true,
|
||||||
maxLengthEnforcement:
|
counterText: _characterCount >= 150
|
||||||
MaxLengthEnforcement.enforced,
|
? '$_characterCount/$_maxCharacters'
|
||||||
style: const TextStyle(fontSize: 14),
|
: '',
|
||||||
decoration: InputDecoration(
|
counterStyle: TextStyle(
|
||||||
hintText: AppLocalizations.of(
|
fontSize: 10,
|
||||||
context,
|
color: _characterCount > _maxCharacters * 0.9
|
||||||
)!.typeYourMessage,
|
? Colors.orange
|
||||||
hintStyle: const TextStyle(fontSize: 14),
|
: Theme.of(
|
||||||
border: OutlineInputBorder(
|
context,
|
||||||
borderRadius: BorderRadius.circular(24),
|
).textTheme.bodySmall?.color,
|
||||||
),
|
),
|
||||||
contentPadding: const EdgeInsets.symmetric(
|
suffixIcon: Builder(
|
||||||
horizontal: 16,
|
builder: (context) {
|
||||||
vertical: 10,
|
final canSendText =
|
||||||
),
|
!_isRecording &&
|
||||||
isDense: true,
|
!_isSendingVoice &&
|
||||||
counterText: _characterCount >= 150
|
_textController.text.trim().isNotEmpty;
|
||||||
? '$_characterCount/$_maxCharacters'
|
final semanticsLabel = _isRecording
|
||||||
: '',
|
? 'Recording... release to send voice'
|
||||||
counterStyle: TextStyle(
|
: (_isSendingVoice
|
||||||
fontSize: 10,
|
? 'Sending voice...'
|
||||||
color:
|
: _voiceSupported
|
||||||
_characterCount > _maxCharacters * 0.9
|
? 'Send (long press to record voice)'
|
||||||
? Colors.orange
|
: 'Send');
|
||||||
: Theme.of(
|
|
||||||
context,
|
return Semantics(
|
||||||
).textTheme.bodySmall?.color,
|
button: true,
|
||||||
),
|
enabled:
|
||||||
suffixIcon: GestureDetector(
|
canSendText ||
|
||||||
onLongPressStart:
|
(_voiceSupported && !_isSendingVoice),
|
||||||
|
label: semanticsLabel,
|
||||||
|
onTap: canSendText ? _sendMessage : null,
|
||||||
|
onLongPress:
|
||||||
(_voiceSupported && !_isSendingVoice)
|
(_voiceSupported && !_isSendingVoice)
|
||||||
? (_) => _startVoiceRecording()
|
? () {
|
||||||
|
if (_isRecording) {
|
||||||
|
_stopAndSendVoice();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
_startVoiceRecording();
|
||||||
|
}
|
||||||
: null,
|
: null,
|
||||||
onLongPressEnd:
|
child: Tooltip(
|
||||||
(_voiceSupported && _isRecording)
|
message: semanticsLabel,
|
||||||
? (_) => _stopAndSendVoice()
|
excludeFromSemantics: true,
|
||||||
: null,
|
child: GestureDetector(
|
||||||
onLongPressCancel:
|
excludeFromSemantics: true,
|
||||||
(_voiceSupported && _isRecording)
|
onLongPressStart:
|
||||||
? () => _stopAndSendVoice()
|
(_voiceSupported &&
|
||||||
: null,
|
!_isSendingVoice)
|
||||||
child: IconButton(
|
? (_) => _startVoiceRecording()
|
||||||
icon: _isSendingVoice
|
: null,
|
||||||
? const SizedBox(
|
onLongPressEnd:
|
||||||
width: 18,
|
(_voiceSupported && _isRecording)
|
||||||
height: 18,
|
? (_) => _stopAndSendVoice()
|
||||||
child: CircularProgressIndicator(
|
: null,
|
||||||
strokeWidth: 2,
|
onLongPressCancel:
|
||||||
),
|
(_voiceSupported && _isRecording)
|
||||||
)
|
? () => _stopAndSendVoice()
|
||||||
: Icon(
|
: null,
|
||||||
_isRecording
|
child: IconButton(
|
||||||
? Icons.mic
|
icon: _isSendingVoice
|
||||||
: Icons.send_rounded,
|
? const SizedBox(
|
||||||
size: 22,
|
width: 18,
|
||||||
color: _isRecording
|
height: 18,
|
||||||
? Colors.red
|
child:
|
||||||
: (_textController.text
|
CircularProgressIndicator(
|
||||||
.trim()
|
strokeWidth: 2,
|
||||||
.isEmpty
|
),
|
||||||
? Theme.of(
|
)
|
||||||
context,
|
: Icon(
|
||||||
).disabledColor
|
_isRecording
|
||||||
: Theme.of(context)
|
? Icons.mic
|
||||||
.colorScheme
|
: Icons.send_rounded,
|
||||||
.primary),
|
size: 22,
|
||||||
),
|
color: _isRecording
|
||||||
onPressed:
|
? Colors.red
|
||||||
_isRecording ||
|
: (_textController.text
|
||||||
_isSendingVoice ||
|
.trim()
|
||||||
_textController.text
|
.isEmpty
|
||||||
.trim()
|
? Theme.of(
|
||||||
.isEmpty
|
context,
|
||||||
? null
|
).disabledColor
|
||||||
: _sendMessage,
|
: Theme.of(context)
|
||||||
tooltip: _isRecording
|
.colorScheme
|
||||||
? 'Recording... release to send voice'
|
.primary),
|
||||||
: (_isSendingVoice
|
),
|
||||||
? 'Sending voice...'
|
onPressed: canSendText
|
||||||
: _voiceSupported
|
? _sendMessage
|
||||||
? 'Send (long press to record voice)'
|
: null,
|
||||||
: 'Send'),
|
),
|
||||||
|
),
|
||||||
),
|
),
|
||||||
),
|
);
|
||||||
),
|
},
|
||||||
textInputAction: TextInputAction.send,
|
|
||||||
onSubmitted: (_) => _sendMessage(),
|
|
||||||
),
|
),
|
||||||
],
|
),
|
||||||
|
textInputAction: TextInputAction.send,
|
||||||
|
onSubmitted: (_) => _sendMessage(),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
|
|||||||
Reference in New Issue
Block a user