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.

207 lines
5.4 KiB

  1. import 'package:Envelope/database/repositories/friends_repository.dart';
  2. import 'package:Envelope/services/friends_service.dart';
  3. import 'package:flutter/material.dart';
  4. import '/components/custom_title_bar.dart';
  5. import '/components/qr_reader.dart';
  6. import '/components/custom_expandable_fab.dart';
  7. import '/database/models/friends.dart';
  8. import '/views/main/friend/list_item.dart';
  9. import '/views/main/friend/add_search.dart';
  10. import '/views/main/friend/request_list_item.dart';
  11. class FriendList extends StatefulWidget {
  12. final List<Friend> friends;
  13. final Function callback;
  14. const FriendList({
  15. Key? key,
  16. required this.friends,
  17. required this.callback,
  18. }) : super(key: key);
  19. @override
  20. State<FriendList> createState() => _FriendListState();
  21. }
  22. class _FriendListState extends State<FriendList> {
  23. final GlobalKey<RefreshIndicatorState> _refreshIndicatorKey = GlobalKey<RefreshIndicatorState>();
  24. List<Friend> friends = [];
  25. List<Friend> friendsDuplicate = [];
  26. @override
  27. Widget build(BuildContext context) {
  28. return Scaffold(
  29. appBar: const CustomTitleBar(
  30. title: Text(
  31. 'Friends',
  32. style: TextStyle(
  33. fontSize: 32,
  34. fontWeight: FontWeight.bold
  35. )
  36. ),
  37. showBack: false,
  38. backgroundColor: Colors.transparent,
  39. ),
  40. body: Padding(
  41. padding: const EdgeInsets.only(top: 16,left: 16,right: 16, bottom: 65),
  42. child: Stack(
  43. children: <Widget>[
  44. Padding(
  45. padding: const EdgeInsets.only(top: 50),
  46. child: RefreshIndicator(
  47. key: _refreshIndicatorKey,
  48. onRefresh: _refresh,
  49. child: list(),
  50. )
  51. ),
  52. TextField(
  53. decoration: const InputDecoration(
  54. hintText: 'Search...',
  55. prefixIcon: Icon(
  56. Icons.search,
  57. size: 20
  58. ),
  59. ),
  60. onChanged: (value) => filterSearchResults(value.toLowerCase())
  61. ),
  62. ],
  63. ),
  64. ),
  65. floatingActionButton: Padding(
  66. padding: const EdgeInsets.only(right: 10, bottom: 60),
  67. child: ExpandableFab(
  68. icon: Icon(
  69. Icons.add,
  70. size: 30,
  71. color: Theme.of(context).colorScheme.onPrimary,
  72. ),
  73. distance: 90.0,
  74. children: [
  75. ActionButton(
  76. onPressed: () {
  77. Navigator.of(context).push(
  78. MaterialPageRoute(builder: (context) => const QrReader())
  79. );//.then(onGoBack); // TODO
  80. },
  81. icon: const Icon(Icons.qr_code_2, size: 25),
  82. ),
  83. ActionButton(
  84. onPressed: () {
  85. Navigator.of(context).push(
  86. MaterialPageRoute(builder: (context) => const FriendAddSearch())
  87. );//.then(onGoBack); // TODO
  88. },
  89. icon: const Icon(Icons.search, size: 25),
  90. ),
  91. ],
  92. )
  93. )
  94. );
  95. }
  96. void filterSearchResults(String query) {
  97. List<Friend> dummyFriendsList = [];
  98. dummyFriendsList.addAll(friends);
  99. if (query.isNotEmpty) {
  100. List<Friend> dummyFriendData = [];
  101. for (Friend item in dummyFriendsList) {
  102. if(item.username.toLowerCase().contains(query)) {
  103. dummyFriendData.add(item);
  104. }
  105. }
  106. setState(() {
  107. friends.clear();
  108. friends.addAll(dummyFriendData);
  109. });
  110. return;
  111. }
  112. setState(() {
  113. friends.clear();
  114. friends.addAll(widget.friends);
  115. });
  116. }
  117. @override
  118. void initState() {
  119. super.initState();
  120. friends.addAll(widget.friends);
  121. }
  122. Future<void> initFriends() async {
  123. friends = await FriendsRepository.getFriends();
  124. setState(() {});
  125. widget.callback();
  126. }
  127. Widget _heading(String heading) {
  128. return Padding(
  129. padding: const EdgeInsets.only(top: 5, bottom: 10),
  130. child: Align(
  131. alignment: Alignment.centerLeft,
  132. child: Text(
  133. heading,
  134. style: TextStyle(
  135. fontSize: 16,
  136. color: Theme.of(context).hintColor,
  137. ),
  138. ),
  139. )
  140. );
  141. }
  142. Widget list() {
  143. if (friends.isEmpty) {
  144. return const Center(
  145. child: Text('No Friends'),
  146. );
  147. }
  148. return ListView.separated(
  149. itemCount: friends.length,
  150. shrinkWrap: false,
  151. physics: const AlwaysScrollableScrollPhysics(),
  152. padding: const EdgeInsets.only(top: 10),
  153. separatorBuilder: (context, i) {
  154. if (friends[i].acceptedAt == null) {
  155. return FriendRequestListItem(
  156. friend: friends[i],
  157. callback: initFriends,
  158. );
  159. }
  160. return FriendListItem(
  161. friend: friends[i],
  162. );
  163. },
  164. itemBuilder: (context, i) {
  165. if (i == 0 && friends[i].acceptedAt == null) {
  166. return _heading('Friend Requests');
  167. }
  168. if ((i == 0 || friends[i - 1].acceptedAt == null) && friends[i].acceptedAt != null) {
  169. return _heading('Friends');
  170. }
  171. return const SizedBox.shrink();
  172. },
  173. );
  174. }
  175. Future<void> _refresh() async {
  176. DateTime? acceptedAt = await FriendsRepository.getLatestAcceptedAt();
  177. if (acceptedAt == null) {
  178. return;
  179. }
  180. FriendsService.updateFriends(acceptedAt: acceptedAt);
  181. friends = await FriendsRepository.getFriends();
  182. setState(() {});
  183. }
  184. }