Encrypted messaging app
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

265 lines
8.7 KiB

  1. import 'package:Envelope/components/custom_title_bar.dart';
  2. import 'package:flutter/material.dart';
  3. import '/models/conversations.dart';
  4. import '/models/messages.dart';
  5. import '/models/my_profile.dart';
  6. import '/utils/storage/messages.dart';
  7. import '/utils/time.dart';
  8. import '/views/main/conversation/settings.dart';
  9. class ConversationDetail extends StatefulWidget{
  10. final Conversation conversation;
  11. const ConversationDetail({
  12. Key? key,
  13. required this.conversation,
  14. }) : super(key: key);
  15. @override
  16. _ConversationDetailState createState() => _ConversationDetailState();
  17. }
  18. class _ConversationDetailState extends State<ConversationDetail> {
  19. List<Message> messages = [];
  20. MyProfile profile = MyProfile(id: '', username: '');
  21. TextEditingController msgController = TextEditingController();
  22. @override
  23. Widget build(BuildContext context) {
  24. return Scaffold(
  25. appBar: CustomTitleBar(
  26. title: Text(
  27. widget.conversation.name,
  28. style: TextStyle(
  29. fontSize: 16,
  30. fontWeight: FontWeight.w600,
  31. color: Theme.of(context).appBarTheme.toolbarTextStyle?.color
  32. ),
  33. ),
  34. showBack: true,
  35. rightHandButton: IconButton(
  36. onPressed: (){
  37. Navigator.of(context).push(
  38. MaterialPageRoute(builder: (context) => ConversationSettings(conversation: widget.conversation)),
  39. );
  40. },
  41. icon: Icon(
  42. Icons.settings,
  43. color: Theme.of(context).appBarTheme.iconTheme?.color,
  44. ),
  45. ),
  46. ),
  47. body: Stack(
  48. children: <Widget>[
  49. messagesView(),
  50. Align(
  51. alignment: Alignment.bottomLeft,
  52. child: ConstrainedBox(
  53. constraints: const BoxConstraints(
  54. maxHeight: 200.0,
  55. ),
  56. child: Container(
  57. padding: const EdgeInsets.only(left: 10,bottom: 10,top: 10),
  58. // height: 60,
  59. width: double.infinity,
  60. color: Theme.of(context).backgroundColor,
  61. child: Row(
  62. children: <Widget>[
  63. GestureDetector(
  64. onTap: (){
  65. },
  66. child: Container(
  67. height: 30,
  68. width: 30,
  69. decoration: BoxDecoration(
  70. color: Theme.of(context).primaryColor,
  71. borderRadius: BorderRadius.circular(30),
  72. ),
  73. child: Icon(
  74. Icons.add,
  75. color: Theme.of(context).colorScheme.onPrimary,
  76. size: 20
  77. ),
  78. ),
  79. ),
  80. const SizedBox(width: 15,),
  81. Expanded(
  82. child: TextField(
  83. decoration: InputDecoration(
  84. hintText: "Write message...",
  85. hintStyle: TextStyle(
  86. color: Theme.of(context).hintColor,
  87. ),
  88. border: InputBorder.none,
  89. ),
  90. maxLines: null,
  91. controller: msgController,
  92. ),
  93. ),
  94. const SizedBox(width: 15),
  95. Container(
  96. width: 45,
  97. height: 45,
  98. child: FittedBox(
  99. child: FloatingActionButton(
  100. onPressed: () async {
  101. if (msgController.text == '') {
  102. return;
  103. }
  104. await sendMessage(widget.conversation, msgController.text);
  105. messages = await getMessagesForThread(widget.conversation);
  106. setState(() {});
  107. msgController.text = '';
  108. },
  109. child: Icon(
  110. Icons.send,
  111. color: Theme.of(context).colorScheme.onPrimary,
  112. size: 22
  113. ),
  114. backgroundColor: Theme.of(context).primaryColor,
  115. ),
  116. ),
  117. ),
  118. const SizedBox(width: 10),
  119. ],
  120. ),
  121. ),
  122. ),
  123. ),
  124. ],
  125. ),
  126. );
  127. }
  128. Future<void> fetchMessages() async {
  129. profile = await MyProfile.getProfile();
  130. messages = await getMessagesForThread(widget.conversation);
  131. setState(() {});
  132. }
  133. @override
  134. void initState() {
  135. super.initState();
  136. fetchMessages();
  137. }
  138. Widget usernameOrFailedToSend(int index) {
  139. if (messages[index].senderUsername != profile.username) {
  140. return Text(
  141. messages[index].senderUsername,
  142. style: TextStyle(
  143. fontSize: 12,
  144. color: Colors.grey[300],
  145. ),
  146. );
  147. }
  148. if (messages[index].failedToSend) {
  149. return Row(
  150. mainAxisAlignment: MainAxisAlignment.end,
  151. children: const <Widget>[
  152. Icon(
  153. Icons.warning_rounded,
  154. color: Colors.red,
  155. size: 20,
  156. ),
  157. Text(
  158. 'Failed to send',
  159. style: TextStyle(color: Colors.red, fontSize: 12),
  160. textAlign: TextAlign.right,
  161. ),
  162. ],
  163. );
  164. }
  165. return const SizedBox.shrink();
  166. }
  167. Widget messagesView() {
  168. if (messages.isEmpty) {
  169. return const Center(
  170. child: Text('No Messages'),
  171. );
  172. }
  173. return ListView.builder(
  174. itemCount: messages.length,
  175. shrinkWrap: true,
  176. padding: const EdgeInsets.only(top: 10,bottom: 90),
  177. reverse: true,
  178. itemBuilder: (context, index) {
  179. return Container(
  180. padding: const EdgeInsets.only(left: 14,right: 14,top: 0,bottom: 0),
  181. child: Align(
  182. alignment: (
  183. messages[index].senderUsername == profile.username ?
  184. Alignment.topRight :
  185. Alignment.topLeft
  186. ),
  187. child: Column(
  188. crossAxisAlignment: messages[index].senderUsername == profile.username ?
  189. CrossAxisAlignment.end :
  190. CrossAxisAlignment.start,
  191. children: <Widget>[
  192. Container(
  193. decoration: BoxDecoration(
  194. borderRadius: BorderRadius.circular(20),
  195. color: (
  196. messages[index].senderUsername == profile.username ?
  197. Theme.of(context).colorScheme.primary :
  198. Theme.of(context).colorScheme.tertiary
  199. ),
  200. ),
  201. padding: const EdgeInsets.all(12),
  202. child: Text(
  203. messages[index].data,
  204. style: TextStyle(
  205. fontSize: 15,
  206. color: messages[index].senderUsername == profile.username ?
  207. Theme.of(context).colorScheme.onPrimary :
  208. Theme.of(context).colorScheme.onTertiary,
  209. )
  210. ),
  211. ),
  212. const SizedBox(height: 1.5),
  213. Row(
  214. mainAxisAlignment: messages[index].senderUsername == profile.username ?
  215. MainAxisAlignment.end :
  216. MainAxisAlignment.start,
  217. children: <Widget>[
  218. const SizedBox(width: 10),
  219. usernameOrFailedToSend(index),
  220. ],
  221. ),
  222. const SizedBox(height: 1.5),
  223. Row(
  224. mainAxisAlignment: messages[index].senderUsername == profile.username ?
  225. MainAxisAlignment.end :
  226. MainAxisAlignment.start,
  227. children: <Widget>[
  228. const SizedBox(width: 10),
  229. Text(
  230. convertToAgo(messages[index].createdAt),
  231. textAlign: messages[index].senderUsername == profile.username ?
  232. TextAlign.left :
  233. TextAlign.right,
  234. style: TextStyle(
  235. fontSize: 12,
  236. color: Colors.grey[500],
  237. ),
  238. ),
  239. ],
  240. ),
  241. index != 0 ?
  242. const SizedBox(height: 20) :
  243. const SizedBox.shrink(),
  244. ],
  245. )
  246. ),
  247. );
  248. },
  249. );
  250. }
  251. }