mirror of
https://github.com/Iconica-Development/flutter_chat.git
synced 2025-05-19 02:43:50 +02:00
Merge 2c95cf81e9
into 15f15748b6
This commit is contained in:
commit
1c7b6136a1
5 changed files with 184 additions and 76 deletions
|
@ -2,8 +2,11 @@
|
|||
//
|
||||
// SPDX-License-Identifier: BSD-3-Clause
|
||||
|
||||
import "package:emoji_picker_flutter/emoji_picker_flutter.dart";
|
||||
import "package:flutter/foundation.dart" as foundation;
|
||||
import "package:flutter/material.dart";
|
||||
import "package:flutter_chat_view/flutter_chat_view.dart";
|
||||
import "package:google_fonts/google_fonts.dart";
|
||||
|
||||
class ChatBottom extends StatefulWidget {
|
||||
const ChatBottom({
|
||||
|
@ -41,14 +44,32 @@ class ChatBottom extends StatefulWidget {
|
|||
}
|
||||
|
||||
class _ChatBottomState extends State<ChatBottom> {
|
||||
final TextEditingController _textEditingController = TextEditingController();
|
||||
bool _isTyping = false;
|
||||
bool _isSending = false;
|
||||
bool _emojiPickerShowing = false;
|
||||
late final EmojiTextEditingController _emojiTextEditingController;
|
||||
late final ScrollController _scrollController;
|
||||
late final FocusNode _focusNode;
|
||||
late final TextStyle _emojiTextStyle;
|
||||
|
||||
final bool isApple = [TargetPlatform.iOS, TargetPlatform.macOS]
|
||||
.contains(foundation.defaultTargetPlatform);
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
_textEditingController.addListener(() {
|
||||
if (_textEditingController.text.isEmpty) {
|
||||
void initState() {
|
||||
var fontSize = 24 * (isApple ? 1.2 : 1.0);
|
||||
// Define Custom Emoji Font & Text Style
|
||||
_emojiTextStyle = DefaultEmojiTextStyle.copyWith(
|
||||
fontFamily: GoogleFonts.notoColorEmoji().fontFamily,
|
||||
fontSize: fontSize,
|
||||
);
|
||||
|
||||
_emojiTextEditingController = EmojiTextEditingController(emojiTextStyle: _emojiTextStyle);
|
||||
_scrollController = ScrollController();
|
||||
_focusNode = FocusNode();
|
||||
|
||||
_emojiTextEditingController.addListener(() {
|
||||
if (_emojiTextEditingController.text.isEmpty) {
|
||||
setState(() {
|
||||
_isTyping = false;
|
||||
});
|
||||
|
@ -58,56 +79,123 @@ class _ChatBottomState extends State<ChatBottom> {
|
|||
});
|
||||
}
|
||||
});
|
||||
return Padding(
|
||||
padding: const EdgeInsets.symmetric(
|
||||
horizontal: 12,
|
||||
vertical: 16,
|
||||
),
|
||||
child: SizedBox(
|
||||
height: 45,
|
||||
child: widget.messageInputBuilder(
|
||||
_textEditingController,
|
||||
Row(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
children: [
|
||||
IconButton(
|
||||
onPressed: widget.onPressSelectImage,
|
||||
icon: Icon(
|
||||
Icons.image_outlined,
|
||||
color: widget.iconColor,
|
||||
),
|
||||
),
|
||||
IconButton(
|
||||
disabledColor: widget.iconDisabledColor,
|
||||
color: widget.iconColor,
|
||||
onPressed: _isTyping && !_isSending
|
||||
? () async {
|
||||
setState(() {
|
||||
_isSending = true;
|
||||
});
|
||||
|
||||
var value = _textEditingController.text;
|
||||
|
||||
if (value.isNotEmpty) {
|
||||
await widget.onMessageSubmit(value);
|
||||
_textEditingController.clear();
|
||||
}
|
||||
|
||||
setState(() {
|
||||
_isSending = false;
|
||||
});
|
||||
}
|
||||
: null,
|
||||
icon: const Icon(
|
||||
Icons.send,
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
widget.translations,
|
||||
context,
|
||||
),
|
||||
),
|
||||
);
|
||||
super.initState();
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) => Padding(
|
||||
padding: const EdgeInsets.symmetric(
|
||||
horizontal: 12,
|
||||
vertical: 16,
|
||||
),
|
||||
child: Column(
|
||||
children: [
|
||||
SizedBox(
|
||||
height: 45,
|
||||
child: widget.messageInputBuilder(
|
||||
_emojiTextEditingController,
|
||||
_focusNode,
|
||||
Row(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
children: [
|
||||
IconButton(
|
||||
onPressed: () {
|
||||
setState(() {
|
||||
_emojiPickerShowing = !_emojiPickerShowing;
|
||||
if (!_emojiPickerShowing) {
|
||||
WidgetsBinding.instance.addPostFrameCallback((_) {
|
||||
_focusNode.requestFocus();
|
||||
});
|
||||
} else {
|
||||
_focusNode.unfocus();
|
||||
}
|
||||
});
|
||||
},
|
||||
icon: Icon(
|
||||
_emojiPickerShowing
|
||||
? Icons.keyboard
|
||||
: Icons.emoji_emotions_outlined,
|
||||
),
|
||||
),
|
||||
IconButton(
|
||||
onPressed: widget.onPressSelectImage,
|
||||
icon: Icon(
|
||||
Icons.image_outlined,
|
||||
color: widget.iconColor,
|
||||
),
|
||||
),
|
||||
IconButton(
|
||||
disabledColor: widget.iconDisabledColor,
|
||||
color: widget.iconColor,
|
||||
onPressed: _isTyping && !_isSending
|
||||
? () async {
|
||||
setState(() {
|
||||
_isSending = true;
|
||||
});
|
||||
|
||||
var value = _emojiTextEditingController.text;
|
||||
|
||||
if (value.isNotEmpty) {
|
||||
await widget.onMessageSubmit(value);
|
||||
_emojiTextEditingController.clear();
|
||||
}
|
||||
|
||||
setState(() {
|
||||
_isSending = false;
|
||||
});
|
||||
}
|
||||
: null,
|
||||
icon: const Icon(
|
||||
Icons.send,
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
widget.translations,
|
||||
context,
|
||||
),
|
||||
),
|
||||
Offstage(
|
||||
offstage: !_emojiPickerShowing,
|
||||
child: EmojiPicker(
|
||||
textEditingController: _emojiTextEditingController,
|
||||
scrollController: _scrollController,
|
||||
config: Config(
|
||||
height: 256,
|
||||
checkPlatformCompatibility: true,
|
||||
emojiTextStyle: _emojiTextStyle,
|
||||
emojiViewConfig: const EmojiViewConfig(
|
||||
backgroundColor: Colors.white,
|
||||
),
|
||||
swapCategoryAndBottomBar: true,
|
||||
skinToneConfig: const SkinToneConfig(),
|
||||
categoryViewConfig: const CategoryViewConfig(
|
||||
backgroundColor: Colors.white,
|
||||
dividerColor: Colors.white,
|
||||
indicatorColor: Colors.blue,
|
||||
iconColorSelected: Colors.black,
|
||||
iconColor: Color(0xFF8B98A0),
|
||||
categoryIcons: CategoryIcons(
|
||||
recentIcon: Icons.access_time_outlined,
|
||||
smileyIcon: Icons.emoji_emotions_outlined,
|
||||
animalIcon: Icons.cruelty_free_outlined,
|
||||
foodIcon: Icons.coffee_outlined,
|
||||
activityIcon: Icons.sports_soccer_outlined,
|
||||
travelIcon: Icons.directions_car_filled_outlined,
|
||||
objectIcon: Icons.lightbulb_outline,
|
||||
symbolIcon: Icons.emoji_symbols_outlined,
|
||||
flagIcon: Icons.flag_outlined,
|
||||
),
|
||||
),
|
||||
bottomActionBarConfig: const BottomActionBarConfig(
|
||||
backgroundColor: Colors.white,
|
||||
buttonColor: Colors.white,
|
||||
buttonIconColor: Color(0xFF8B98A0),
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
|
|
|
@ -3,10 +3,13 @@
|
|||
// SPDX-License-Identifier: BSD-3-Clause
|
||||
|
||||
import "package:cached_network_image/cached_network_image.dart";
|
||||
import "package:emoji_picker_flutter/emoji_picker_flutter.dart";
|
||||
import "package:flutter/foundation.dart" as foundation;
|
||||
import "package:flutter/material.dart";
|
||||
import "package:flutter_chat_view/flutter_chat_view.dart";
|
||||
import "package:flutter_chat_view/src/components/chat_image.dart";
|
||||
import "package:flutter_chat_view/src/services/date_formatter.dart";
|
||||
import "package:google_fonts/google_fonts.dart";
|
||||
|
||||
class ChatDetailRow extends StatefulWidget {
|
||||
const ChatDetailRow({
|
||||
|
@ -43,10 +46,19 @@ class ChatDetailRow extends StatefulWidget {
|
|||
|
||||
class _ChatDetailRowState extends State<ChatDetailRow> {
|
||||
final DateFormatter _dateFormatter = DateFormatter();
|
||||
final _emojiUtils = EmojiPickerUtils();
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
var theme = Theme.of(context);
|
||||
var isApple = [TargetPlatform.iOS, TargetPlatform.macOS]
|
||||
.contains(foundation.defaultTargetPlatform);
|
||||
var fontSize = 24 * (isApple ? 1.2 : 1.0);
|
||||
|
||||
var emojiTextStyle = DefaultEmojiTextStyle.copyWith(
|
||||
fontFamily: GoogleFonts.notoColorEmoji().fontFamily,
|
||||
fontSize: fontSize,
|
||||
);
|
||||
|
||||
var isNewDate = widget.previousMessage != null &&
|
||||
widget.message.timestamp.day != widget.previousMessage?.timestamp.day;
|
||||
|
@ -135,11 +147,16 @@ class _ChatDetailRowState extends State<ChatDetailRow> {
|
|||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||
children: [
|
||||
Flexible(
|
||||
child: Text(
|
||||
(widget.message as ChatTextMessageModel).text,
|
||||
style: TextStyle(
|
||||
fontSize: 16,
|
||||
color: theme.textTheme.labelMedium?.color,
|
||||
child: RichText(
|
||||
text: TextSpan(
|
||||
children: _emojiUtils.setEmojiTextStyle(
|
||||
(widget.message as ChatTextMessageModel)
|
||||
.text,
|
||||
emojiStyle: emojiTextStyle,),
|
||||
style: TextStyle(
|
||||
fontSize: 16,
|
||||
color: theme.textTheme.labelMedium?.color,
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
|
|
|
@ -91,7 +91,7 @@ class ChatRow extends StatelessWidget {
|
|||
width: 20,
|
||||
height: 20,
|
||||
decoration: BoxDecoration(
|
||||
color: Theme.of(context).colorScheme.primary,
|
||||
color: theme.colorScheme.primary,
|
||||
shape: BoxShape.circle,
|
||||
),
|
||||
child: Center(
|
||||
|
|
|
@ -2,6 +2,7 @@
|
|||
//
|
||||
// SPDX-License-Identifier: BSD-3-Clause
|
||||
|
||||
import "package:emoji_picker_flutter/emoji_picker_flutter.dart";
|
||||
import "package:flutter/material.dart";
|
||||
import "package:flutter_chat_view/flutter_chat_view.dart";
|
||||
import "package:flutter_chat_view/src/components/chat_image.dart";
|
||||
|
@ -85,12 +86,14 @@ Widget _createNewChatButton(
|
|||
|
||||
Widget _createMessageInput(
|
||||
TextEditingController textEditingController,
|
||||
FocusNode focusNode,
|
||||
Widget suffixIcon,
|
||||
ChatTranslations translations,
|
||||
BuildContext context,
|
||||
) {
|
||||
var theme = Theme.of(context);
|
||||
return TextField(
|
||||
focusNode: focusNode,
|
||||
textCapitalization: TextCapitalization.sentences,
|
||||
controller: textEditingController,
|
||||
decoration: InputDecoration(
|
||||
|
@ -148,22 +151,19 @@ Widget _createImagePickerContainer(
|
|||
padding: const EdgeInsets.all(8.0),
|
||||
color: Colors.white,
|
||||
child: ImagePicker(
|
||||
imagePickerTheme: ImagePickerTheme(
|
||||
title: translations.imagePickerTitle,
|
||||
titleTextSize: 16,
|
||||
titleAlignment: TextAlign.center,
|
||||
theme: ImagePickerTheme(
|
||||
iconSize: 60.0,
|
||||
makePhotoText: translations.takePicture,
|
||||
selectImageText: translations.uploadFile,
|
||||
),
|
||||
customButton: ElevatedButton(
|
||||
style: ElevatedButton.styleFrom(
|
||||
backgroundColor: Theme.of(context).primaryColor,
|
||||
),
|
||||
onPressed: onClose,
|
||||
child: Text(
|
||||
translations.cancelImagePickerBtn,
|
||||
style: const TextStyle(color: Colors.white),
|
||||
closeButtonBuilder: (onCLose) => ElevatedButton(
|
||||
style: ElevatedButton.styleFrom(
|
||||
backgroundColor: Theme.of(context).primaryColor,
|
||||
),
|
||||
onPressed: onClose,
|
||||
child: Text(
|
||||
translations.cancelImagePickerBtn,
|
||||
style: const TextStyle(color: Colors.white),
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
|
@ -238,7 +238,8 @@ typedef ButtonBuilder = Widget Function(
|
|||
);
|
||||
|
||||
typedef TextInputBuilder = Widget Function(
|
||||
TextEditingController textEditingController,
|
||||
EmojiTextEditingController textEditingController,
|
||||
FocusNode focusNode,
|
||||
Widget suffixIcon,
|
||||
ChatTranslations translations,
|
||||
BuildContext context,
|
||||
|
|
|
@ -16,6 +16,8 @@ dependencies:
|
|||
flutter:
|
||||
sdk: flutter
|
||||
intl: any
|
||||
emoji_picker_flutter: ^2.2.0
|
||||
google_fonts: ^6.2.1
|
||||
flutter_chat_interface:
|
||||
git:
|
||||
url: https://github.com/Iconica-Development/flutter_chat
|
||||
|
@ -25,7 +27,7 @@ dependencies:
|
|||
flutter_image_picker:
|
||||
git:
|
||||
url: https://github.com/Iconica-Development/flutter_image_picker
|
||||
ref: 1.0.5
|
||||
ref: 3.0.0
|
||||
flutter_profile:
|
||||
git:
|
||||
ref: 1.3.0
|
||||
|
|
Loading…
Reference in a new issue