chat_page.dart 7.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181
  1. import 'package:dash_chat_2/dash_chat_2.dart';
  2. import 'package:flutter/material.dart';
  3. import 'package:flutter_hbb/common.dart';
  4. import 'package:flutter_hbb/models/chat_model.dart';
  5. import 'package:get/get.dart';
  6. import 'package:provider/provider.dart';
  7. import '../../mobile/pages/home_page.dart';
  8. enum ChatPageType {
  9. mobileMain,
  10. desktopCM,
  11. }
  12. class ChatPage extends StatelessWidget implements PageShape {
  13. late final ChatModel chatModel;
  14. final ChatPageType? type;
  15. ChatPage({ChatModel? chatModel, this.type}) {
  16. this.chatModel = chatModel ?? gFFI.chatModel;
  17. }
  18. @override
  19. final title = translate("Chat");
  20. @override
  21. final icon = unreadTopRightBuilder(gFFI.chatModel.mobileUnreadSum);
  22. @override
  23. final appBarActions = [
  24. PopupMenuButton<MessageKey>(
  25. tooltip: "",
  26. icon: unreadTopRightBuilder(gFFI.chatModel.mobileUnreadSum,
  27. icon: Icon(Icons.group)),
  28. itemBuilder: (context) {
  29. // only mobile need [appBarActions], just bind gFFI.chatModel
  30. final chatModel = gFFI.chatModel;
  31. return chatModel.messages.entries.map((entry) {
  32. final key = entry.key;
  33. final user = entry.value.chatUser;
  34. final client = gFFI.serverModel.clients
  35. .firstWhereOrNull((e) => e.id == key.connId);
  36. final connected =
  37. gFFI.serverModel.clients.any((e) => e.id == key.connId);
  38. return PopupMenuItem<MessageKey>(
  39. child: Row(
  40. children: [
  41. Icon(
  42. key.isOut
  43. ? Icons.call_made_rounded
  44. : Icons.call_received_rounded,
  45. color: MyTheme.accent)
  46. .marginOnly(right: 6),
  47. Text("${user.firstName} ${user.id}"),
  48. if (connected)
  49. Container(
  50. width: 10,
  51. height: 10,
  52. decoration: BoxDecoration(
  53. shape: BoxShape.circle,
  54. color: Color.fromARGB(255, 46, 205, 139)),
  55. ).marginSymmetric(horizontal: 2),
  56. if (client != null)
  57. unreadMessageCountBuilder(client.unreadChatMessageCount)
  58. .marginOnly(left: 4)
  59. ],
  60. ),
  61. value: key,
  62. );
  63. }).toList();
  64. },
  65. onSelected: (key) {
  66. gFFI.chatModel.changeCurrentKey(key);
  67. })
  68. ];
  69. @override
  70. Widget build(BuildContext context) {
  71. return ChangeNotifierProvider.value(
  72. value: chatModel,
  73. child: Container(
  74. color: Theme.of(context).scaffoldBackgroundColor,
  75. child: Consumer<ChatModel>(
  76. builder: (context, chatModel, child) {
  77. final readOnly = type == ChatPageType.mobileMain &&
  78. (chatModel.currentKey.connId == ChatModel.clientModeID ||
  79. gFFI.serverModel.clients.every((e) =>
  80. e.id != chatModel.currentKey.connId ||
  81. chatModel.currentUser == null)) ||
  82. type == ChatPageType.desktopCM &&
  83. gFFI.serverModel.clients
  84. .firstWhereOrNull(
  85. (e) => e.id == chatModel.currentKey.connId)
  86. ?.disconnected ==
  87. true;
  88. return Stack(
  89. children: [
  90. LayoutBuilder(builder: (context, constraints) {
  91. final chat = DashChat(
  92. onSend: chatModel.send,
  93. currentUser: chatModel.me,
  94. messages: chatModel
  95. .messages[chatModel.currentKey]?.chatMessages ??
  96. [],
  97. readOnly: readOnly,
  98. inputOptions: InputOptions(
  99. focusNode: chatModel.inputNode,
  100. textController: chatModel.textController,
  101. inputTextStyle: TextStyle(
  102. fontSize: 14,
  103. color: Theme.of(context).textTheme.titleLarge?.color),
  104. inputDecoration: InputDecoration(
  105. isDense: true,
  106. hintText: translate('Write a message'),
  107. filled: true,
  108. fillColor: Theme.of(context).colorScheme.background,
  109. contentPadding: EdgeInsets.all(10),
  110. border: OutlineInputBorder(
  111. borderRadius: BorderRadius.circular(10.0),
  112. borderSide: const BorderSide(
  113. width: 1,
  114. style: BorderStyle.solid,
  115. ),
  116. ),
  117. ),
  118. sendButtonBuilder: defaultSendButton(
  119. padding:
  120. EdgeInsets.symmetric(horizontal: 6, vertical: 0),
  121. color: MyTheme.accent,
  122. icon: Icons.send_rounded,
  123. ),
  124. ),
  125. messageOptions: MessageOptions(
  126. showOtherUsersAvatar: false,
  127. showOtherUsersName: false,
  128. textColor: Colors.white,
  129. maxWidth: constraints.maxWidth * 0.7,
  130. messageTextBuilder: (message, _, __) {
  131. final isOwnMessage = message.user.id.isBlank!;
  132. return Column(
  133. crossAxisAlignment: isOwnMessage
  134. ? CrossAxisAlignment.end
  135. : CrossAxisAlignment.start,
  136. children: <Widget>[
  137. Text(message.text,
  138. style: TextStyle(color: Colors.white)),
  139. Text(
  140. "${message.createdAt.hour}:${message.createdAt.minute.toString().padLeft(2, '0')}",
  141. style: TextStyle(
  142. color: Colors.white,
  143. fontSize: 8,
  144. ),
  145. ).marginOnly(top: 3),
  146. ],
  147. );
  148. },
  149. messageDecorationBuilder:
  150. (message, previousMessage, nextMessage) {
  151. final isOwnMessage = message.user.id.isBlank!;
  152. return defaultMessageDecoration(
  153. color:
  154. isOwnMessage ? MyTheme.accent : Colors.blueGrey,
  155. borderTopLeft: 8,
  156. borderTopRight: 8,
  157. borderBottomRight: isOwnMessage ? 2 : 8,
  158. borderBottomLeft: isOwnMessage ? 8 : 2,
  159. );
  160. },
  161. ),
  162. ).workaroundFreezeLinuxMint();
  163. return SelectionArea(child: chat);
  164. }),
  165. ],
  166. ).paddingOnly(bottom: 8);
  167. },
  168. ),
  169. ),
  170. );
  171. }
  172. }