MIF_E31222656/lib/screens/community/components/message_input.dart

264 lines
8.1 KiB
Dart

import 'package:flutter/material.dart';
import 'dart:io';
import 'package:emoji_picker_flutter/emoji_picker_flutter.dart';
import '../models/message.dart';
import 'package:flutter/foundation.dart' as foundation;
import '../../../core/theme/app_colors.dart';
import 'reply_bar.dart';
class MessageInputWidget extends StatelessWidget {
final TextEditingController messageController;
final FocusNode focusNode;
final bool isUploading;
final File? selectedImage;
final bool showEmojiKeyboard;
final bool isReplying;
final Message? replyToMessage;
final VoidCallback onSend;
final VoidCallback onImageOptions;
final VoidCallback onEmojiToggle;
final VoidCallback onClearImage;
final VoidCallback onCancelReply;
final Color themeColor;
const MessageInputWidget({
Key? key,
required this.messageController,
required this.focusNode,
required this.isUploading,
required this.selectedImage,
required this.showEmojiKeyboard,
required this.isReplying,
required this.replyToMessage,
required this.onSend,
required this.onImageOptions,
required this.onEmojiToggle,
required this.onClearImage,
required this.onCancelReply,
required this.themeColor,
}) : super(key: key);
@override
Widget build(BuildContext context) {
// Wrap everything in a Column to contain emoji keyboard
return Column(
mainAxisSize: MainAxisSize.min,
children: [
// Selected image preview
if (selectedImage != null) _buildImagePreview(),
// Reply bar
if (isReplying) _buildReplyBar(),
// Input bar
Container(
padding: const EdgeInsets.symmetric(horizontal: 8.0, vertical: 6.0),
decoration: BoxDecoration(
color: Colors.white,
boxShadow: [
BoxShadow(
color: Colors.black.withOpacity(0.05),
blurRadius: 3,
offset: Offset(0, -1),
),
],
),
child: SafeArea(
top: false,
child: Row(
crossAxisAlignment: CrossAxisAlignment.end,
children: [
// Emoji button
IconButton(
icon: Icon(
showEmojiKeyboard ? Icons.keyboard : Icons.emoji_emotions_outlined,
color: themeColor,
),
onPressed: onEmojiToggle,
padding: EdgeInsets.zero,
constraints: BoxConstraints(
minWidth: 36,
minHeight: 36,
),
),
// Text field
Expanded(
child: ConstrainedBox(
constraints: BoxConstraints(
maxHeight: 120.0, // Limit max height
),
child: TextField(
controller: messageController,
focusNode: focusNode,
minLines: 1,
maxLines: 5, // Allow multiple lines but not too many
textCapitalization: TextCapitalization.sentences,
decoration: InputDecoration(
hintText: 'Ketik pesan...',
border: InputBorder.none,
contentPadding: EdgeInsets.symmetric(horizontal: 8.0, vertical: 10.0),
),
),
),
),
// Attachment button
IconButton(
icon: Icon(
Icons.attach_file,
color: themeColor,
),
onPressed: onImageOptions,
padding: EdgeInsets.zero,
constraints: BoxConstraints(
minWidth: 36,
minHeight: 36,
),
),
// Send button
_buildSendButton(),
],
),
),
),
// Emoji keyboard - Wrap in AnimatedContainer for smooth transitions
AnimatedContainer(
duration: Duration(milliseconds: 200),
height: showEmojiKeyboard ? _getEmojiKeyboardHeight(context) : 0,
child: showEmojiKeyboard ? _buildEmojiPicker(context) : SizedBox(),
),
],
);
}
Widget _buildImagePreview() {
return Container(
width: double.infinity,
padding: EdgeInsets.all(8.0),
color: Colors.grey[200],
child: Stack(
alignment: Alignment.center,
children: [
// Image preview with fixed height
Container(
height: 150,
width: double.infinity,
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(8),
color: Colors.black,
),
child: ClipRRect(
borderRadius: BorderRadius.circular(8),
child: Image.file(
selectedImage!,
fit: BoxFit.cover,
),
),
),
// Loading indicator
if (isUploading)
Container(
height: 150,
width: double.infinity,
color: Colors.black54,
child: Center(
child: CircularProgressIndicator(
valueColor: AlwaysStoppedAnimation<Color>(Colors.white),
),
),
),
// Close button
Positioned(
top: 0,
right: 0,
child: Material(
color: Colors.transparent,
child: InkWell(
borderRadius: BorderRadius.circular(20),
onTap: onClearImage,
child: Container(
padding: EdgeInsets.all(4),
decoration: BoxDecoration(
color: Colors.black54,
shape: BoxShape.circle,
),
child: Icon(
Icons.close,
color: Colors.white,
size: 20,
),
),
),
),
),
],
),
);
}
Widget _buildReplyBar() {
if (replyToMessage == null) return SizedBox.shrink();
return ReplyBar(
message: replyToMessage!,
onCancel: onCancelReply,
);
}
Widget _buildSendButton() {
final bool canSend = messageController.text.trim().isNotEmpty || selectedImage != null;
return GestureDetector(
onTap: canSend ? onSend : null,
child: Container(
width: 36,
height: 36,
margin: EdgeInsets.only(left: 4, right: 4),
decoration: BoxDecoration(
color: canSend ? themeColor : Colors.grey,
shape: BoxShape.circle,
),
child: Icon(
Icons.send,
color: Colors.white,
size: 18,
),
),
);
}
Widget _buildEmojiPicker(BuildContext context) {
return EmojiPicker(
onEmojiSelected: (category, emoji) {
messageController.text = messageController.text + emoji.emoji;
},
textEditingController: messageController,
config: Config(
checkPlatformCompatibility: true,
),
);
}
// Calculate emoji keyboard height based on screen size and keyboard visibility
double _getEmojiKeyboardHeight(BuildContext context) {
final screenHeight = MediaQuery.of(context).size.height;
final keyboardVisible = MediaQuery.of(context).viewInsets.bottom > 0;
// Calculate safe height for emoji picker
final double baseHeight = keyboardVisible
? screenHeight * 0.25 // 25% when keyboard visible
: screenHeight * 0.35; // 35% when keyboard hidden
// Ensure we don't exceed available space
final availableHeight = screenHeight -
MediaQuery.of(context).viewInsets.bottom -
kToolbarHeight - 100;
return baseHeight.clamp(100.0, availableHeight);
}
}