mirror of
https://github.com/Iconica-Development/flutter_chat.git
synced 2025-05-19 10:53:51 +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
|
// 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/material.dart";
|
||||||
import "package:flutter_chat_view/flutter_chat_view.dart";
|
import "package:flutter_chat_view/flutter_chat_view.dart";
|
||||||
|
import "package:google_fonts/google_fonts.dart";
|
||||||
|
|
||||||
class ChatBottom extends StatefulWidget {
|
class ChatBottom extends StatefulWidget {
|
||||||
const ChatBottom({
|
const ChatBottom({
|
||||||
|
@ -41,14 +44,32 @@ class ChatBottom extends StatefulWidget {
|
||||||
}
|
}
|
||||||
|
|
||||||
class _ChatBottomState extends State<ChatBottom> {
|
class _ChatBottomState extends State<ChatBottom> {
|
||||||
final TextEditingController _textEditingController = TextEditingController();
|
|
||||||
bool _isTyping = false;
|
bool _isTyping = false;
|
||||||
bool _isSending = 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
|
@override
|
||||||
Widget build(BuildContext context) {
|
void initState() {
|
||||||
_textEditingController.addListener(() {
|
var fontSize = 24 * (isApple ? 1.2 : 1.0);
|
||||||
if (_textEditingController.text.isEmpty) {
|
// 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(() {
|
setState(() {
|
||||||
_isTyping = false;
|
_isTyping = false;
|
||||||
});
|
});
|
||||||
|
@ -58,18 +79,44 @@ class _ChatBottomState extends State<ChatBottom> {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
return Padding(
|
super.initState();
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) => Padding(
|
||||||
padding: const EdgeInsets.symmetric(
|
padding: const EdgeInsets.symmetric(
|
||||||
horizontal: 12,
|
horizontal: 12,
|
||||||
vertical: 16,
|
vertical: 16,
|
||||||
),
|
),
|
||||||
child: SizedBox(
|
child: Column(
|
||||||
|
children: [
|
||||||
|
SizedBox(
|
||||||
height: 45,
|
height: 45,
|
||||||
child: widget.messageInputBuilder(
|
child: widget.messageInputBuilder(
|
||||||
_textEditingController,
|
_emojiTextEditingController,
|
||||||
|
_focusNode,
|
||||||
Row(
|
Row(
|
||||||
mainAxisSize: MainAxisSize.min,
|
mainAxisSize: MainAxisSize.min,
|
||||||
children: [
|
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(
|
IconButton(
|
||||||
onPressed: widget.onPressSelectImage,
|
onPressed: widget.onPressSelectImage,
|
||||||
icon: Icon(
|
icon: Icon(
|
||||||
|
@ -86,11 +133,11 @@ class _ChatBottomState extends State<ChatBottom> {
|
||||||
_isSending = true;
|
_isSending = true;
|
||||||
});
|
});
|
||||||
|
|
||||||
var value = _textEditingController.text;
|
var value = _emojiTextEditingController.text;
|
||||||
|
|
||||||
if (value.isNotEmpty) {
|
if (value.isNotEmpty) {
|
||||||
await widget.onMessageSubmit(value);
|
await widget.onMessageSubmit(value);
|
||||||
_textEditingController.clear();
|
_emojiTextEditingController.clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
setState(() {
|
setState(() {
|
||||||
|
@ -108,6 +155,47 @@ class _ChatBottomState extends State<ChatBottom> {
|
||||||
context,
|
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
|
// SPDX-License-Identifier: BSD-3-Clause
|
||||||
|
|
||||||
import "package:cached_network_image/cached_network_image.dart";
|
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/material.dart";
|
||||||
import "package:flutter_chat_view/flutter_chat_view.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/components/chat_image.dart";
|
||||||
import "package:flutter_chat_view/src/services/date_formatter.dart";
|
import "package:flutter_chat_view/src/services/date_formatter.dart";
|
||||||
|
import "package:google_fonts/google_fonts.dart";
|
||||||
|
|
||||||
class ChatDetailRow extends StatefulWidget {
|
class ChatDetailRow extends StatefulWidget {
|
||||||
const ChatDetailRow({
|
const ChatDetailRow({
|
||||||
|
@ -43,10 +46,19 @@ class ChatDetailRow extends StatefulWidget {
|
||||||
|
|
||||||
class _ChatDetailRowState extends State<ChatDetailRow> {
|
class _ChatDetailRowState extends State<ChatDetailRow> {
|
||||||
final DateFormatter _dateFormatter = DateFormatter();
|
final DateFormatter _dateFormatter = DateFormatter();
|
||||||
|
final _emojiUtils = EmojiPickerUtils();
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
var theme = Theme.of(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 &&
|
var isNewDate = widget.previousMessage != null &&
|
||||||
widget.message.timestamp.day != widget.previousMessage?.timestamp.day;
|
widget.message.timestamp.day != widget.previousMessage?.timestamp.day;
|
||||||
|
@ -135,14 +147,19 @@ class _ChatDetailRowState extends State<ChatDetailRow> {
|
||||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||||
children: [
|
children: [
|
||||||
Flexible(
|
Flexible(
|
||||||
child: Text(
|
child: RichText(
|
||||||
(widget.message as ChatTextMessageModel).text,
|
text: TextSpan(
|
||||||
|
children: _emojiUtils.setEmojiTextStyle(
|
||||||
|
(widget.message as ChatTextMessageModel)
|
||||||
|
.text,
|
||||||
|
emojiStyle: emojiTextStyle,),
|
||||||
style: TextStyle(
|
style: TextStyle(
|
||||||
fontSize: 16,
|
fontSize: 16,
|
||||||
color: theme.textTheme.labelMedium?.color,
|
color: theme.textTheme.labelMedium?.color,
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
),
|
||||||
if (widget.showTime &&
|
if (widget.showTime &&
|
||||||
!isSameMinute &&
|
!isSameMinute &&
|
||||||
!isNewDate &&
|
!isNewDate &&
|
||||||
|
|
|
@ -91,7 +91,7 @@ class ChatRow extends StatelessWidget {
|
||||||
width: 20,
|
width: 20,
|
||||||
height: 20,
|
height: 20,
|
||||||
decoration: BoxDecoration(
|
decoration: BoxDecoration(
|
||||||
color: Theme.of(context).colorScheme.primary,
|
color: theme.colorScheme.primary,
|
||||||
shape: BoxShape.circle,
|
shape: BoxShape.circle,
|
||||||
),
|
),
|
||||||
child: Center(
|
child: Center(
|
||||||
|
|
|
@ -2,6 +2,7 @@
|
||||||
//
|
//
|
||||||
// SPDX-License-Identifier: BSD-3-Clause
|
// SPDX-License-Identifier: BSD-3-Clause
|
||||||
|
|
||||||
|
import "package:emoji_picker_flutter/emoji_picker_flutter.dart";
|
||||||
import "package:flutter/material.dart";
|
import "package:flutter/material.dart";
|
||||||
import "package:flutter_chat_view/flutter_chat_view.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/components/chat_image.dart";
|
||||||
|
@ -85,12 +86,14 @@ Widget _createNewChatButton(
|
||||||
|
|
||||||
Widget _createMessageInput(
|
Widget _createMessageInput(
|
||||||
TextEditingController textEditingController,
|
TextEditingController textEditingController,
|
||||||
|
FocusNode focusNode,
|
||||||
Widget suffixIcon,
|
Widget suffixIcon,
|
||||||
ChatTranslations translations,
|
ChatTranslations translations,
|
||||||
BuildContext context,
|
BuildContext context,
|
||||||
) {
|
) {
|
||||||
var theme = Theme.of(context);
|
var theme = Theme.of(context);
|
||||||
return TextField(
|
return TextField(
|
||||||
|
focusNode: focusNode,
|
||||||
textCapitalization: TextCapitalization.sentences,
|
textCapitalization: TextCapitalization.sentences,
|
||||||
controller: textEditingController,
|
controller: textEditingController,
|
||||||
decoration: InputDecoration(
|
decoration: InputDecoration(
|
||||||
|
@ -148,15 +151,11 @@ Widget _createImagePickerContainer(
|
||||||
padding: const EdgeInsets.all(8.0),
|
padding: const EdgeInsets.all(8.0),
|
||||||
color: Colors.white,
|
color: Colors.white,
|
||||||
child: ImagePicker(
|
child: ImagePicker(
|
||||||
imagePickerTheme: ImagePickerTheme(
|
theme: ImagePickerTheme(
|
||||||
title: translations.imagePickerTitle,
|
|
||||||
titleTextSize: 16,
|
|
||||||
titleAlignment: TextAlign.center,
|
|
||||||
iconSize: 60.0,
|
iconSize: 60.0,
|
||||||
makePhotoText: translations.takePicture,
|
makePhotoText: translations.takePicture,
|
||||||
selectImageText: translations.uploadFile,
|
selectImageText: translations.uploadFile,
|
||||||
),
|
closeButtonBuilder: (onCLose) => ElevatedButton(
|
||||||
customButton: ElevatedButton(
|
|
||||||
style: ElevatedButton.styleFrom(
|
style: ElevatedButton.styleFrom(
|
||||||
backgroundColor: Theme.of(context).primaryColor,
|
backgroundColor: Theme.of(context).primaryColor,
|
||||||
),
|
),
|
||||||
|
@ -167,6 +166,7 @@ Widget _createImagePickerContainer(
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
),
|
||||||
);
|
);
|
||||||
|
|
||||||
Scaffold _createScaffold(
|
Scaffold _createScaffold(
|
||||||
|
@ -238,7 +238,8 @@ typedef ButtonBuilder = Widget Function(
|
||||||
);
|
);
|
||||||
|
|
||||||
typedef TextInputBuilder = Widget Function(
|
typedef TextInputBuilder = Widget Function(
|
||||||
TextEditingController textEditingController,
|
EmojiTextEditingController textEditingController,
|
||||||
|
FocusNode focusNode,
|
||||||
Widget suffixIcon,
|
Widget suffixIcon,
|
||||||
ChatTranslations translations,
|
ChatTranslations translations,
|
||||||
BuildContext context,
|
BuildContext context,
|
||||||
|
|
|
@ -16,6 +16,8 @@ dependencies:
|
||||||
flutter:
|
flutter:
|
||||||
sdk: flutter
|
sdk: flutter
|
||||||
intl: any
|
intl: any
|
||||||
|
emoji_picker_flutter: ^2.2.0
|
||||||
|
google_fonts: ^6.2.1
|
||||||
flutter_chat_interface:
|
flutter_chat_interface:
|
||||||
git:
|
git:
|
||||||
url: https://github.com/Iconica-Development/flutter_chat
|
url: https://github.com/Iconica-Development/flutter_chat
|
||||||
|
@ -25,7 +27,7 @@ dependencies:
|
||||||
flutter_image_picker:
|
flutter_image_picker:
|
||||||
git:
|
git:
|
||||||
url: https://github.com/Iconica-Development/flutter_image_picker
|
url: https://github.com/Iconica-Development/flutter_image_picker
|
||||||
ref: 1.0.5
|
ref: 3.0.0
|
||||||
flutter_profile:
|
flutter_profile:
|
||||||
git:
|
git:
|
||||||
ref: 1.3.0
|
ref: 1.3.0
|
||||||
|
|
Loading…
Reference in a new issue