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.

232 lines
10 KiB

  1. import 'package:flutter/material.dart';
  2. import 'package:shared_preferences/shared_preferences.dart';
  3. import '/models/conversations.dart';
  4. import '/models/messages.dart';
  5. import '/utils/storage/messages.dart';
  6. String convertToAgo(String input){
  7. DateTime time = DateTime.parse(input);
  8. Duration diff = DateTime.now().difference(time);
  9. if(diff.inDays >= 1){
  10. return '${diff.inDays} day${diff.inDays == 1 ? "" : "s"} ago';
  11. }
  12. if(diff.inHours >= 1){
  13. return '${diff.inHours} hour${diff.inHours == 1 ? "" : "s"} ago';
  14. }
  15. if(diff.inMinutes >= 1){
  16. return '${diff.inMinutes} minute${diff.inMinutes == 1 ? "" : "s"} ago';
  17. }
  18. if (diff.inSeconds >= 1){
  19. return '${diff.inSeconds} second${diff.inSeconds == 1 ? "" : "s"} ago';
  20. }
  21. return 'just now';
  22. }
  23. class ConversationDetail extends StatefulWidget{
  24. final Conversation conversation;
  25. const ConversationDetail({
  26. Key? key,
  27. required this.conversation,
  28. }) : super(key: key);
  29. @override
  30. _ConversationDetailState createState() => _ConversationDetailState();
  31. }
  32. class _ConversationDetailState extends State<ConversationDetail> {
  33. List<Message> messages = [];
  34. String username = '';
  35. TextEditingController msgController = TextEditingController();
  36. @override
  37. void initState() {
  38. super.initState();
  39. fetchMessages();
  40. }
  41. Future<void> fetchMessages() async {
  42. final preferences = await SharedPreferences.getInstance();
  43. username = preferences.getString('username')!;
  44. messages = await getMessagesForThread(widget.conversation);
  45. setState(() {});
  46. }
  47. Widget usernameOrFailedToSend(int index) {
  48. if (messages[index].senderUsername != username) {
  49. return Text(messages[index].senderUsername);
  50. }
  51. if (messages[index].failedToSend) {
  52. return Row(
  53. mainAxisAlignment: MainAxisAlignment.end,
  54. children: const <Widget>[
  55. Icon(
  56. Icons.warning_rounded,
  57. color: Colors.red,
  58. size: 20,
  59. ),
  60. Text(
  61. 'Failed to send',
  62. style: TextStyle(color: Colors.red, fontSize: 12),
  63. textAlign: TextAlign.right,
  64. ),
  65. ],
  66. );
  67. }
  68. return const SizedBox.shrink();
  69. }
  70. @override
  71. Widget build(BuildContext context) {
  72. return Scaffold(
  73. appBar: AppBar(
  74. elevation: 0,
  75. automaticallyImplyLeading: false,
  76. backgroundColor: Colors.white,
  77. flexibleSpace: SafeArea(
  78. child: Container(
  79. padding: const EdgeInsets.only(right: 16),
  80. child: Row(
  81. children: <Widget>[
  82. IconButton(
  83. onPressed: (){
  84. Navigator.pop(context);
  85. },
  86. icon: const Icon(Icons.arrow_back,color: Colors.black,),
  87. ),
  88. const SizedBox(width: 2,),
  89. Expanded(
  90. child: Column(
  91. crossAxisAlignment: CrossAxisAlignment.start,
  92. mainAxisAlignment: MainAxisAlignment.center,
  93. children: <Widget>[
  94. Text(
  95. widget.conversation.name,
  96. style: const TextStyle(
  97. fontSize: 16,
  98. fontWeight: FontWeight.w600),
  99. ),
  100. ],
  101. ),
  102. ),
  103. const Icon(Icons.settings,color: Colors.black54),
  104. ],
  105. ),
  106. ),
  107. ),
  108. ),
  109. body: Stack(
  110. children: <Widget>[
  111. ListView.builder(
  112. itemCount: messages.length,
  113. shrinkWrap: true,
  114. padding: const EdgeInsets.only(top: 10,bottom: 90),
  115. reverse: true,
  116. itemBuilder: (context, index) {
  117. return Container(
  118. padding: const EdgeInsets.only(left: 14,right: 14,top: 0,bottom: 10),
  119. child: Align(
  120. alignment: (
  121. messages[index].senderUsername == username ?
  122. Alignment.topRight :
  123. Alignment.topLeft
  124. ),
  125. child: Column(
  126. crossAxisAlignment: messages[index].senderUsername == username ?
  127. CrossAxisAlignment.end :
  128. CrossAxisAlignment.start,
  129. children: <Widget>[
  130. Container(
  131. decoration: BoxDecoration(
  132. borderRadius: BorderRadius.circular(20),
  133. color: (
  134. messages[index].senderUsername == username ?
  135. Colors.blue[200] :
  136. Colors.grey.shade200
  137. ),
  138. ),
  139. padding: const EdgeInsets.all(12),
  140. child: Text(messages[index].data, style: const TextStyle(fontSize: 15)),
  141. ),
  142. usernameOrFailedToSend(index),
  143. Text(
  144. convertToAgo(messages[index].createdAt),
  145. textAlign: TextAlign.left,
  146. style: TextStyle(
  147. fontSize: 12,
  148. color: Colors.grey[500],
  149. ),
  150. ),
  151. ]
  152. )
  153. ),
  154. );
  155. },
  156. ),
  157. Align(
  158. alignment: Alignment.bottomLeft,
  159. child: ConstrainedBox(
  160. constraints: const BoxConstraints(
  161. maxHeight: 200.0,
  162. ),
  163. child: Container(
  164. padding: const EdgeInsets.only(left: 10,bottom: 10,top: 10),
  165. // height: 60,
  166. width: double.infinity,
  167. color: Colors.white,
  168. child: Row(
  169. children: <Widget>[
  170. GestureDetector(
  171. onTap: (){
  172. },
  173. child: Container(
  174. height: 30,
  175. width: 30,
  176. decoration: BoxDecoration(
  177. color: Colors.lightBlue,
  178. borderRadius: BorderRadius.circular(30),
  179. ),
  180. child: const Icon(Icons.add, color: Colors.white, size: 20, ),
  181. ),
  182. ),
  183. const SizedBox(width: 15,),
  184. Expanded(
  185. child: TextField(
  186. decoration: const InputDecoration(
  187. hintText: "Write message...",
  188. hintStyle: TextStyle(color: Colors.black54),
  189. border: InputBorder.none,
  190. ),
  191. maxLines: null,
  192. controller: msgController,
  193. ),
  194. ),
  195. const SizedBox(width: 15),
  196. FloatingActionButton(
  197. onPressed: () async {
  198. if (msgController.text == '') {
  199. return;
  200. }
  201. await sendMessage(widget.conversation, msgController.text);
  202. messages = await getMessagesForThread(widget.conversation);
  203. setState(() {});
  204. msgController.text = '';
  205. },
  206. child: const Icon(Icons.send,color: Colors.white,size: 18,),
  207. backgroundColor: Colors.blue,
  208. ),
  209. const SizedBox(width: 10),
  210. ],
  211. ),
  212. ),
  213. ),
  214. ),
  215. ],
  216. ),
  217. );
  218. }
  219. }