您最多选择25个主题 主题必须以中文或者字母或数字开头,可以包含连字符 (-),并且长度不得超过35个字符
 
 
 
 

455 行
18 KiB

using System;
using System.Collections.Generic;
using ChatComponents;
using uiwidgets;
using Unity.UIWidgets.async;
using Unity.UIWidgets.foundation;
using Unity.UIWidgets.material;
using Unity.UIWidgets.painting;
using Unity.UIWidgets.ui;
using Unity.UIWidgets.widgets;
using UnityEngine;
using Color = Unity.UIWidgets.ui.Color;
namespace UIWidgetsSample
{
public delegate string CustomDateHeaderText(DateTime dateTime);
public delegate void OnAttachmentPressed();
public delegate Future OnEndReached();
public delegate void OnMessageLongPress(ChatComponents.Message message);
public delegate void OnMessageTap(ChatComponents.Message message);
public delegate void OnPreviewDataFetched( PreviewData previewData,ChatComponents.TextMessage textMessage = null);
public delegate void OnSendPressed(PartialText partialText);
public delegate void OnTextChanged(string _str);
public delegate Widget BuildCustomMessage(ChatComponents.Message message);
public class Chat : StatefulWidget
{
/// See [Message.buildCustomMessage]
/// If [dateFormat], [dateLocale] and/or [timeFormat] is not enough to
/// customize date headers in your case, use this to return an arbitrary
/// string based on a [DateTime] of a particular message. Can be helpful to
/// return "Today" if [DateTime] is today. IMPORTANT: this will replace
/// all default date headers, so you must handle all cases yourself, like
/// for example today, yesterday and before. Or you can just return the same
/// date header for any message.
public readonly BuildCustomMessage buildCustomMessage;
public readonly CustomDateHeaderText customDateHeaderText;
/// Allows you to customize the date format. IMPORTANT: only for the date,
/// do not return time here. See [timeFormat] to customize the time format.
/// [dateLocale] will be ignored if you use this, so if you want a localized date
/// make sure you initialize your [DateFormat] with a locale. See [customDateHeaderText]
/// for more customization.
public readonly DateTime? dateFormat;
/// Locale will be passed to the `Intl` package. Make sure you initialized
/// date formatting in your app before passing any locale here, otherwise
/// an error will be thrown. Also see [customDateHeaderText], [dateFormat], [timeFormat].
public readonly string dateLocale;
/// Disable automatic image preview on tap.
public readonly bool? disableImageGallery;
/// See [Input.isAttachmentUploading]
public readonly bool? isAttachmentUploading;
/// See [ChatList.isLastPage]
public readonly bool? isLastPage;
/// Localized copy. Extend [ChatL10n] class to create your own copy or use
/// existing one, like the default [ChatL10nEn]. You can customize only
/// certain variables, see more here [ChatL10nEn].
public readonly ChatL10n l10n;
/// List of [types.Message] to render in the chat widget
public readonly List<ChatComponents.Message> messages;
/// See [Input.onAttachmentPressed]
public readonly OnAttachmentPressed onAttachmentPressed;
/// See [ChatList.onEndReached]
public readonly OnEndReached onEndReached;
/// See [ChatList.onEndReachedThreshold]
public readonly float? onEndReachedThreshold;
/// See [Message.onMessageLongPress]
public readonly OnMessageLongPress onMessageLongPress;
/// See [Message.onMessageTap]
public readonly OnMessageTap onMessageTap;
/// See [Message.onPreviewDataFetched]
public readonly OnPreviewDataFetched onPreviewDataFetched;
/// See [Input.onSendPressed]
public readonly OnSendPressed onSendPressed;
/// See [Input.onTextChanged]
public readonly OnTextChanged onTextChanged;
/// See [Message.showUserAvatars]
public readonly bool showUserAvatars;
/// Show user names for received messages. Useful for a group chat. Will be
/// shown only on text messages.
public readonly bool showUserNames;
/// Chat theme. Extend [ChatTheme] class to create your own theme or use
/// existing one, like the [DefaultChatTheme]. You can customize only certain
/// variables, see more here [DefaultChatTheme].
public readonly ChatTheme theme;
/// Allows you to customize the time format. IMPORTANT: only for the time,
/// do not return date here. See [dateFormat] to customize the date format.
/// [dateLocale] will be ignored if you use this, so if you want a localized time
/// make sure you initialize your [DateFormat] with a locale. See [customDateHeaderText]
/// for more customization.
public readonly DateTime? timeFormat;
/// See [Message.usePreviewData]
public readonly bool usePreviewData;
/// See [InheritedUser.user]
public readonly User user;
/// Creates a chat widget
public Chat(
List<ChatComponents.Message> messages,
OnSendPressed onSendPressed,
User user,
Key key = null,
BuildCustomMessage buildCustomMessage = null,
CustomDateHeaderText customDateHeaderText = null,
DateTime? dateFormat = null,
string dateLocale = null,
bool? disableImageGallery = null,
bool? isAttachmentUploading = null,
bool? isLastPage = null,
ChatL10nEn l10n = null,
OnAttachmentPressed onAttachmentPressed = null,
OnEndReached onEndReached = null,
float? onEndReachedThreshold = null,
OnMessageLongPress onMessageLongPress = null,
OnMessageTap onMessageTap = null,
OnPreviewDataFetched onPreviewDataFetched = null,
OnTextChanged onTextChanged = null,
bool showUserAvatars = false,
bool showUserNames = false,
ChatTheme theme = null,
DateTime? timeFormat = null,
bool usePreviewData = true
) : base(key)
{
this.buildCustomMessage = buildCustomMessage;
this.customDateHeaderText = customDateHeaderText;
this.dateFormat = dateFormat;
this.dateLocale = dateLocale;
this.disableImageGallery = disableImageGallery;
this.isAttachmentUploading = isAttachmentUploading;
this.isLastPage = isLastPage;
this.l10n = l10n == null ? new ChatL10nEn() : l10n;
this.messages = messages;
this.onAttachmentPressed = onAttachmentPressed;
this.onEndReached = onEndReached;
this.onEndReachedThreshold = onEndReachedThreshold;
this.onMessageLongPress = onMessageLongPress;
this.onMessageTap = onMessageTap;
this.onPreviewDataFetched = onPreviewDataFetched;
this.onSendPressed = onSendPressed;
this.onTextChanged = onTextChanged;
this.showUserAvatars = showUserAvatars;
this.showUserNames = showUserNames;
this.theme = theme == null ? new DefaultChatTheme() : theme;
this.timeFormat = timeFormat;
this.usePreviewData = usePreviewData;
this.user = user;
}
public override State createState()
{
return new _ChatState();
}
}
/// [Chat] widget state
public class _ChatState : State<Chat>
{
private List<object> _chatMessages = new List<object>();
private List<PreviewImage> _gallery = new List<PreviewImage>();
private int _imageViewIndex;
private bool _isImageViewVisible;
public override void initState()
{
base.initState();
didUpdateWidget(widget);
}
public override void didUpdateWidget(StatefulWidget oldWidget)
{
oldWidget = (Chat) oldWidget;
base.didUpdateWidget((Chat)oldWidget);
if (widget.messages.isNotEmpty())
{
var result = ChatUtils.calculateChatMessages(
widget.messages,
widget.user,
customDateHeaderText: widget.customDateHeaderText,
dateFormat: widget.dateFormat,
dateLocale: widget.dateLocale,
showUserNames: widget.showUserNames,
timeFormat: widget.timeFormat
);
_chatMessages = result[0] as List<object>;
_gallery = result[1] as List<PreviewImage>;
}
}
/*private Widget _buildImageGallery()
{
return new Dismissible(
GlobalKey.key("photo_view_gallery"),
direction:
DismissDirection.down,
onDismissed:
direction => _onCloseGalleryPressed(),
child:
new Stack(
children: new List<Widget>
{
PhotoViewGallery.builder(
builder: (BuildContext context, int index) =>
PhotoViewGalleryPageOptions(
imageProvider: new BrowserConditional().getProvider(_gallery[index].uri)
),
itemCount: _gallery.Count,
loadingBuilder: (_context, _event) =>
_imageGalleryLoadingBuilder(_context, _event),
onPageChanged:
_onPageChanged,
pageController:
new PageController(_imageViewIndex),
scrollPhysics:
new ClampingScrollPhysics()
),
new Positioned(
right: 16,
top: 56,
child: new CloseButton(
color: Colors.white,
onPressed: _onCloseGalleryPressed
)
)
}
)
);
}*/
private Widget _buildMessage(object _object)
{
if (_object is DateHeader)
{
return new Container(
alignment: Alignment.center,
margin: EdgeInsets.only(
bottom: 32,
top: 16
),
child:
new Text(
((DateHeader) _object).text,
style: widget.theme.dateDividerTextStyle
)
);
}
else if (_object is MessageSpacer)
{
var height = ((MessageSpacer) _object).height;
return new SizedBox(
height: height
);
}
else
{
var map = _object as Dictionary<string, object>;
var message = map["message"] as ChatComponents.Message;
var _messageWidth =
widget.showUserAvatars && message.author.id != widget.user.id
? Mathf.Min(MediaQuery.of(context).size.width * 0.72f, 440).floor()
: Mathf.Min(MediaQuery.of(context).size.width * 0.78f, 440).floor();
return new Message(
key: new ValueKey<string>(message.id),
buildCustomMessage: widget.buildCustomMessage,
message: message,
messageWidth: _messageWidth,
onMessageLongPress: widget.onMessageLongPress,
onMessageTap: tappedMessage =>
{
if (tappedMessage is ImageMessage && widget.disableImageGallery != true)
_onImagePressed((ImageMessage) tappedMessage);
widget.onMessageTap?.Invoke(tappedMessage);
},
onPreviewDataFetched:
(previewData,textMessage)=>
{
_onPreviewDataFetched( textMessage,previewData);
},
roundBorder: true, //(map["nextMessageInGroup"] is bool ? (bool) map["nextMessageInGroup"] : false),
showAvatar:
widget.showUserAvatars && false,
//(map["nextMessageInGroup"] is bool ? (bool) map["nextMessageInGroup"] : false) == false,
showName:
false,
//(map["showName"] is bool ? (bool) map["showName"] : false),
showStatus:
false,
//(map["showStatus"] is bool ? (bool) map["showStatus"] : false),
showUserAvatars:
widget.showUserAvatars,
usePreviewData:
widget.usePreviewData
);
}
}
private Widget _imageGalleryLoadingBuilder(
BuildContext context,
ImageChunkEvent _event = null
)
{
return new Center(
child: new SizedBox(
width: 20.0f,
height: 20.0f,
child: new CircularProgressIndicator(
value: _event == null || _event.expectedTotalBytes == null
? 0
: _event.cumulativeBytesLoaded / _event.expectedTotalBytes
)
)
);
}
private void _onCloseGalleryPressed()
{
setState(() => { _isImageViewVisible = false; });
}
private void _onImagePressed(ImageMessage message)
{
setState(() =>
{
/*_imageViewIndex = _gallery.Where(
element => element.id == message.id && element.uri == message.uri
);*/
foreach (var element in _gallery)
if (element.id == message.id && element.uri == message.uri)
{
_imageViewIndex = _gallery.IndexOf(element);
break;
}
_isImageViewVisible = true;
});
}
private void _onPageChanged(int index)
{
setState(() => { _imageViewIndex = index; });
}
private void _onPreviewDataFetched(
ChatComponents.TextMessage message,
PreviewData previewData
)
{
widget.onPreviewDataFetched?.Invoke(previewData,message);
}
public override Widget build(BuildContext context)
{
var results = new List<Widget>();
results.Add(new Container(
color: Color.fromARGB(0, 0, 0, 0),
child: new SafeArea(
bottom: false,
child: new Column(
children: new List<Widget>
{
new Flexible(
child: widget.messages.isEmpty()
? (Widget) SizedBox.expand(
child: new Container(
//color: Colors.yellow,
alignment: Alignment.center,
margin: EdgeInsets.symmetric(
horizontal: 24
),
child: new Text(
widget.l10n.emptyChatPlaceholder,
style: widget.theme.emptyChatPlaceholderTextStyle,
textAlign: TextAlign.center
)
)
)
: new GestureDetector(
onTap: () => FocusManager.instance.primaryFocus?.unfocus(),
child: new ChatList(
isLastPage: widget.isLastPage,
itemBuilder: (item, index) => _buildMessage(item),
items: _chatMessages,
onEndReached: widget.onEndReached,
onEndReachedThreshold: widget.onEndReachedThreshold
)
)
),
new Input(
isAttachmentUploading: widget.isAttachmentUploading,
onAttachmentPressed: widget.onAttachmentPressed,
onSendPressed: widget.onSendPressed,
onTextChanged: widget.onTextChanged
)
}
)
)
));
// if (_isImageViewVisible)
// results.Add(_buildImageGallery());
var test = widget.l10n;
return new InheritedUser(
widget.user,
new InheritedChatTheme(
widget.theme,
new InheritedL10n(
widget.l10n,
new Stack(
children: results
)
)
)
);
}
}
}