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.

192 lines
5.8 KiB

  1. import 'dart:io';
  2. import 'package:Envelope/components/custom_title_bar.dart';
  3. import 'package:Envelope/components/flash_message.dart';
  4. import 'package:Envelope/database/repositories/conversations_repository.dart';
  5. import 'package:Envelope/database/repositories/friends_repository.dart';
  6. import 'package:Envelope/services/conversations_service.dart';
  7. import 'package:flutter/material.dart';
  8. import 'create_add_users.dart';
  9. import 'detail.dart';
  10. import '/database/models/friends.dart';
  11. import '/database/models/conversations.dart';
  12. import '/views/main/conversation/edit_details.dart';
  13. import '/views/main/conversation/list_item.dart';
  14. class ConversationList extends StatefulWidget {
  15. final List<Conversation> conversations;
  16. final List<Friend> friends;
  17. const ConversationList({
  18. Key? key,
  19. required this.conversations,
  20. required this.friends,
  21. }) : super(key: key);
  22. @override
  23. State<ConversationList> createState() => _ConversationListState();
  24. }
  25. class _ConversationListState extends State<ConversationList> {
  26. final GlobalKey<RefreshIndicatorState> _refreshIndicatorKey = GlobalKey<RefreshIndicatorState>();
  27. List<Conversation> conversations = [];
  28. List<Friend> friends = [];
  29. @override
  30. Widget build(BuildContext context) {
  31. return Scaffold(
  32. appBar: const CustomTitleBar(
  33. title: Text(
  34. 'Conversations',
  35. style: TextStyle(
  36. fontSize: 32,
  37. fontWeight: FontWeight.bold
  38. )
  39. ),
  40. showBack: false,
  41. backgroundColor: Colors.transparent,
  42. ),
  43. body: Padding(
  44. padding: const EdgeInsets.only(top: 16,left: 16,right: 16, bottom: 65),
  45. child: Stack(
  46. children: <Widget>[
  47. Padding(
  48. padding: const EdgeInsets.only(top: 50),
  49. child: RefreshIndicator(
  50. key: _refreshIndicatorKey,
  51. onRefresh: _refresh,
  52. child: list(),
  53. ),
  54. ),
  55. TextField(
  56. decoration: const InputDecoration(
  57. hintText: 'Search...',
  58. prefixIcon: Icon(
  59. Icons.search,
  60. size: 20
  61. ),
  62. ),
  63. onChanged: (value) => filterSearchResults(value.toLowerCase())
  64. ),
  65. ],
  66. ),
  67. ),
  68. floatingActionButton: Padding(
  69. padding: const EdgeInsets.only(right: 10, bottom: 60),
  70. child: FloatingActionButton(
  71. onPressed: () {
  72. Navigator.of(context).push(
  73. MaterialPageRoute(builder: (context) => ConversationEditDetails(
  74. saveCallback: (String conversationName, File? file) {
  75. Navigator.of(context).push(
  76. MaterialPageRoute(builder: (context) => ConversationAddFriendsList(
  77. friends: friends,
  78. saveCallback: (List<Friend> friendsSelected) async {
  79. Conversation conversation = await ConversationsRepository.createConversation(
  80. conversationName,
  81. friendsSelected,
  82. false,
  83. );
  84. ConversationsService.uploadConversation(conversation)
  85. .catchError((dynamic) {
  86. showMessage('Failed to create conversation', context);
  87. });
  88. if (!mounted) {
  89. return;
  90. }
  91. Navigator.of(context).popUntil((route) => route.isFirst);
  92. Navigator.push(context, MaterialPageRoute(builder: (context) {
  93. return ConversationDetail(
  94. conversation: conversation,
  95. );
  96. }));
  97. },
  98. ))
  99. );
  100. },
  101. )),
  102. ).then(onGoBack);
  103. },
  104. backgroundColor: Theme.of(context).colorScheme.primary,
  105. child: Icon(
  106. Icons.add,
  107. size: 30,
  108. color: Theme.of(context).colorScheme.onPrimary,
  109. ),
  110. ),
  111. ),
  112. );
  113. }
  114. void filterSearchResults(String query) {
  115. List<Conversation> dummySearchList = [];
  116. dummySearchList.addAll(widget.conversations);
  117. if(query.isNotEmpty) {
  118. List<Conversation> dummyListData = [];
  119. for (Conversation item in dummySearchList) {
  120. if (item.name.toLowerCase().contains(query)) {
  121. dummyListData.add(item);
  122. }
  123. }
  124. setState(() {
  125. conversations.clear();
  126. conversations.addAll(dummyListData);
  127. });
  128. return;
  129. }
  130. setState(() {
  131. conversations.clear();
  132. conversations.addAll(widget.conversations);
  133. });
  134. }
  135. @override
  136. void initState() {
  137. super.initState();
  138. conversations.addAll(widget.conversations);
  139. friends.addAll(widget.friends);
  140. setState(() {});
  141. }
  142. Widget list() {
  143. if (conversations.isEmpty) {
  144. return const Center(
  145. child: Text('No Conversations'),
  146. );
  147. }
  148. return ListView.builder(
  149. itemCount: conversations.length,
  150. shrinkWrap: false,
  151. physics: const AlwaysScrollableScrollPhysics(),
  152. itemBuilder: (context, i) {
  153. return ConversationListItem(
  154. conversation: conversations[i],
  155. );
  156. },
  157. );
  158. }
  159. Future<void> _refresh() async {
  160. DateTime? updatedAt = await ConversationsRepository.getLatestUpdatedAt();
  161. if (updatedAt == null) {
  162. return;
  163. }
  164. ConversationsService.updateConversations(updatedAt: updatedAt);
  165. conversations = await ConversationsRepository.getConversations();
  166. setState(() {});
  167. }
  168. onGoBack(dynamic value) async {
  169. conversations = await ConversationsRepository.getConversations();
  170. friends = await FriendsRepository.getFriends();
  171. setState(() {});
  172. }
  173. }