add_partipant_page.dart 9.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222
  1. import 'package:flutter/material.dart';
  2. import 'package:photos/core/configuration.dart';
  3. import 'package:photos/models/collection.dart';
  4. import 'package:photos/services/collections_service.dart';
  5. import 'package:photos/theme/ente_theme.dart';
  6. import 'package:photos/ui/common/gradient_button.dart';
  7. import 'package:photos/ui/components/captioned_text_widget.dart';
  8. import 'package:photos/ui/components/divider_widget.dart';
  9. import 'package:photos/ui/components/menu_item_widget.dart';
  10. import 'package:photos/ui/components/menu_section_description_widget.dart';
  11. import 'package:photos/ui/components/menu_section_title.dart';
  12. import 'package:photos/ui/sharing/user_avator_widget.dart';
  13. import 'package:photos/utils/toast_util.dart';
  14. class AddParticipantPage extends StatefulWidget {
  15. final Collection collection;
  16. const AddParticipantPage(this.collection, {super.key});
  17. @override
  18. State<StatefulWidget> createState() => _AddParticipantPage();
  19. }
  20. class _AddParticipantPage extends State<AddParticipantPage> {
  21. late bool selectAsViewer;
  22. String selectedEmail = '';
  23. bool hideListOfEmails = false;
  24. @override
  25. void initState() {
  26. selectAsViewer = true;
  27. super.initState();
  28. }
  29. Widget build(BuildContext context) {
  30. final enteColorScheme = getEnteColorScheme(context);
  31. final enteTextTheme = getEnteTextTheme(context);
  32. final List<User> suggestedUsers = _getSuggestedUser();
  33. hideListOfEmails = suggestedUsers.isEmpty;
  34. return Scaffold(
  35. appBar: AppBar(
  36. title: const Text("Add people"),
  37. ),
  38. body: Container(
  39. color: enteColorScheme.backgroundElevated,
  40. child: Padding(
  41. padding: const EdgeInsets.symmetric(horizontal: 16.0),
  42. child: Column(
  43. mainAxisAlignment: MainAxisAlignment.start,
  44. crossAxisAlignment: CrossAxisAlignment.start,
  45. children: [
  46. const SizedBox(height: 12),
  47. Text(
  48. "Add a new email",
  49. style: enteTextTheme.body,
  50. ),
  51. hideListOfEmails
  52. ? const Expanded(child: SizedBox())
  53. : Expanded(
  54. child: Column(
  55. children: [
  56. const SizedBox(height: 24),
  57. const MenuSectionTitle(
  58. title: "or pick an existing one",
  59. ),
  60. Expanded(
  61. child: ListView.builder(
  62. itemBuilder: (context, index) {
  63. final currentUser = suggestedUsers[index];
  64. return Column(
  65. children: [
  66. MenuItemWidget(
  67. captionedTextWidget: CaptionedTextWidget(
  68. title: currentUser.email,
  69. ),
  70. leadingIconSize: 24.0,
  71. leadingIconWidget: UserAvatarWidget(
  72. currentUser,
  73. type: AvatarType.mini,
  74. ),
  75. menuItemColor:
  76. getEnteColorScheme(context).fillFaint,
  77. pressedColor:
  78. getEnteColorScheme(context).fillFaint,
  79. trailingIcon:
  80. (selectedEmail == currentUser.email)
  81. ? Icons.check
  82. : null,
  83. onTap: () async {
  84. if (selectedEmail ==
  85. currentUser.email) {
  86. selectedEmail = '';
  87. } else {
  88. selectedEmail = currentUser.email;
  89. }
  90. setState(() => {});
  91. // showShortToast(context, "yet to implement");
  92. },
  93. isTopBorderRadiusRemoved: index > 0,
  94. isBottomBorderRadiusRemoved:
  95. index < (suggestedUsers.length - 1),
  96. ),
  97. (index == (suggestedUsers.length - 1))
  98. ? const SizedBox.shrink()
  99. : DividerWidget(
  100. dividerType: DividerType.menu,
  101. bgColor: getEnteColorScheme(context)
  102. .blurStrokeFaint,
  103. ),
  104. ],
  105. );
  106. },
  107. itemCount: suggestedUsers.length,
  108. // physics: const ClampingScrollPhysics(),
  109. ),
  110. ),
  111. ],
  112. ),
  113. ),
  114. const DividerWidget(
  115. dividerType: DividerType.solid,
  116. ),
  117. SafeArea(
  118. child: Padding(
  119. padding: const EdgeInsets.only(top: 8, bottom: 8),
  120. child: Column(
  121. crossAxisAlignment: CrossAxisAlignment.start,
  122. children: [
  123. const MenuSectionTitle(title: "Add as"),
  124. MenuItemWidget(
  125. captionedTextWidget: const CaptionedTextWidget(
  126. title: "Collaborator",
  127. ),
  128. leadingIcon: Icons.edit,
  129. menuItemColor: getEnteColorScheme(context).fillFaint,
  130. pressedColor: getEnteColorScheme(context).fillFaint,
  131. trailingIcon: !selectAsViewer ? Icons.check : null,
  132. onTap: () async {
  133. showShortToast(context, "coming soon!");
  134. setState(() => {selectAsViewer = false});
  135. },
  136. isBottomBorderRadiusRemoved: true,
  137. ),
  138. DividerWidget(
  139. dividerType: DividerType.menu,
  140. bgColor: getEnteColorScheme(context).blurStrokeFaint,
  141. ),
  142. MenuItemWidget(
  143. captionedTextWidget: const CaptionedTextWidget(
  144. title: " Viewer",
  145. ),
  146. leadingIcon: Icons.photo,
  147. menuItemColor: getEnteColorScheme(context).fillFaint,
  148. pressedColor: getEnteColorScheme(context).fillFaint,
  149. trailingIcon: selectAsViewer ? Icons.check : null,
  150. onTap: () async {
  151. setState(() => {selectAsViewer = true});
  152. // showShortToast(context, "yet to implement");
  153. },
  154. isTopBorderRadiusRemoved: true,
  155. ),
  156. const MenuSectionDescriptionWidget(
  157. content:
  158. "Collaborators can add photos and videos to the shared album.",
  159. ),
  160. const SizedBox(height: 12),
  161. SizedBox(
  162. width: double.infinity,
  163. child: GradientButton(
  164. onTap: selectedEmail == ''
  165. ? null
  166. : () async {
  167. showToast(context, "yet to implement");
  168. Navigator.of(context).pop();
  169. },
  170. text: selectAsViewer
  171. ? "Add viewer"
  172. : "Add collaborator",
  173. ),
  174. ),
  175. const SizedBox(height: 8),
  176. ],
  177. ),
  178. ),
  179. ),
  180. ],
  181. ),
  182. ),
  183. ),
  184. );
  185. }
  186. List<User> _getSuggestedUser() {
  187. final List<User> suggestedUsers = [];
  188. final Set<int> existingUserIDs = {};
  189. final int ownerID = Configuration.instance.getUserID()!;
  190. for (final User? u in widget.collection?.sharees ?? []) {
  191. if (u != null && u.id != null) {
  192. existingUserIDs.add(u.id!);
  193. }
  194. }
  195. for (final c in CollectionsService.instance.getActiveCollections()) {
  196. if (c.owner?.id == ownerID) {
  197. for (final User? u in c?.sharees ?? []) {
  198. if (u != null && u.id != null && !existingUserIDs.contains(u.id)) {
  199. existingUserIDs.add(u.id!);
  200. suggestedUsers.add(u);
  201. }
  202. }
  203. } else if (c.owner != null &&
  204. c.owner!.id != null &&
  205. !existingUserIDs.contains(c.owner!.id!)) {
  206. existingUserIDs.add(c.owner!.id!);
  207. suggestedUsers.add(c.owner!);
  208. }
  209. }
  210. suggestedUsers.sort((a, b) => a.email.compareTo(b.email));
  211. return suggestedUsers;
  212. }
  213. }