ente/lib/ui/sharing/add_partipant_page.dart

361 lines
14 KiB
Dart
Raw Normal View History

2022-11-22 05:13:32 +00:00
import 'package:email_validator/email_validator.dart';
import 'package:flutter/material.dart';
import 'package:photos/core/configuration.dart';
import "package:photos/generated/l10n.dart";
import "package:photos/models/api/collection/user.dart";
2023-08-25 04:39:30 +00:00
import 'package:photos/models/collection/collection.dart';
import 'package:photos/services/collections_service.dart';
import "package:photos/services/user_service.dart";
import 'package:photos/theme/ente_theme.dart';
import 'package:photos/ui/actions/collection/collection_sharing_actions.dart';
import 'package:photos/ui/components/buttons/button_widget.dart';
import 'package:photos/ui/components/captioned_text_widget.dart';
import 'package:photos/ui/components/divider_widget.dart';
2023-01-31 12:21:57 +00:00
import 'package:photos/ui/components/menu_item_widget/menu_item_widget.dart';
import 'package:photos/ui/components/menu_section_description_widget.dart';
import 'package:photos/ui/components/menu_section_title.dart';
2023-01-31 01:03:19 +00:00
import 'package:photos/ui/components/models/button_type.dart';
import 'package:photos/ui/sharing/user_avator_widget.dart';
2023-02-26 05:58:30 +00:00
import "package:photos/ui/sharing/verify_identity_dialog.dart";
import "package:photos/utils/dialog_util.dart";
class AddParticipantPage extends StatefulWidget {
final Collection collection;
2023-01-30 17:45:26 +00:00
final bool isAddingViewer;
2023-01-30 17:45:26 +00:00
const AddParticipantPage(this.collection, this.isAddingViewer, {super.key});
@override
State<StatefulWidget> createState() => _AddParticipantPage();
}
class _AddParticipantPage extends State<AddParticipantPage> {
String selectedEmail = '';
2022-11-22 05:13:32 +00:00
String _email = '';
2023-01-30 17:45:26 +00:00
bool isEmailListEmpty = false;
2022-11-22 05:13:32 +00:00
bool _emailIsValid = false;
2022-11-22 06:32:44 +00:00
bool isKeypadOpen = false;
2022-12-15 10:02:46 +00:00
late CollectionActions collectionActions;
2022-11-22 06:32:44 +00:00
// Focus nodes are necessary
final textFieldFocusNode = FocusNode();
final _textController = TextEditingController();
@override
void initState() {
2022-12-15 10:02:46 +00:00
collectionActions = CollectionActions(CollectionsService.instance);
super.initState();
}
2022-11-22 06:32:44 +00:00
@override
void dispose() {
_textController.dispose();
2022-11-22 08:40:57 +00:00
super.dispose();
2022-11-22 06:32:44 +00:00
}
2022-12-16 04:13:29 +00:00
@override
Widget build(BuildContext context) {
2022-11-22 06:32:44 +00:00
isKeypadOpen = MediaQuery.of(context).viewInsets.bottom > 100;
final enteTextTheme = getEnteTextTheme(context);
2023-01-30 17:45:26 +00:00
final enteColorScheme = getEnteColorScheme(context);
final List<User> suggestedUsers = _getSuggestedUser();
2023-01-30 17:45:26 +00:00
isEmailListEmpty = suggestedUsers.isEmpty;
return Scaffold(
2022-11-22 06:32:44 +00:00
resizeToAvoidBottomInset: isKeypadOpen,
appBar: AppBar(
2023-04-18 09:05:21 +00:00
title: Text(
widget.isAddingViewer
? S.of(context).addViewer
: S.of(context).addCollaborator,
),
),
2022-12-16 04:34:18 +00:00
body: Column(
mainAxisAlignment: MainAxisAlignment.start,
crossAxisAlignment: CrossAxisAlignment.start,
children: [
const SizedBox(height: 12),
Padding(
padding: const EdgeInsets.symmetric(horizontal: 16.0),
child: Text(
S.of(context).addANewEmail,
2023-01-30 17:45:26 +00:00
style: enteTextTheme.small
.copyWith(color: enteColorScheme.textMuted),
2022-11-22 08:20:05 +00:00
),
2022-12-16 04:34:18 +00:00
),
const SizedBox(height: 4),
Padding(
padding: const EdgeInsets.symmetric(horizontal: 16.0),
child: _getEmailField(),
),
2023-01-30 17:45:26 +00:00
(isEmailListEmpty && widget.isAddingViewer)
? const Expanded(child: SizedBox.shrink())
2022-12-16 04:34:18 +00:00
: Expanded(
child: Padding(
padding: const EdgeInsets.symmetric(horizontal: 16.0),
child: Column(
children: [
2023-01-30 17:45:26 +00:00
!isEmailListEmpty
? MenuSectionTitle(
title: S.of(context).orPickAnExistingOne,
2023-01-30 17:45:26 +00:00
)
: const SizedBox.shrink(),
2022-12-16 04:34:18 +00:00
Expanded(
child: ListView.builder(
itemBuilder: (context, index) {
2023-01-30 17:45:26 +00:00
if (index >= suggestedUsers.length) {
return Padding(
padding: const EdgeInsets.symmetric(
2023-01-30 17:45:26 +00:00
vertical: 8.0,
),
child: MenuSectionDescriptionWidget(
content: S
.of(context)
.collaboratorsCanAddPhotosAndVideosToTheSharedAlbum,
2023-01-30 17:45:26 +00:00
),
);
}
2022-12-16 04:34:18 +00:00
final currentUser = suggestedUsers[index];
return Column(
children: [
MenuItemWidget(
captionedTextWidget: CaptionedTextWidget(
title: currentUser.email,
),
2022-12-16 04:34:18 +00:00
leadingIconSize: 24.0,
leadingIconWidget: UserAvatarWidget(
currentUser,
type: AvatarType.mini,
),
menuItemColor:
getEnteColorScheme(context).fillFaint,
pressedColor:
getEnteColorScheme(context).fillFaint,
trailingIcon:
(selectedEmail == currentUser.email)
? Icons.check
: null,
onTap: () async {
textFieldFocusNode.unfocus();
if (selectedEmail == currentUser.email) {
selectedEmail = '';
} else {
selectedEmail = currentUser.email;
}
setState(() => {});
// showShortToast(context, "yet to implement");
},
isTopBorderRadiusRemoved: index > 0,
isBottomBorderRadiusRemoved:
index < (suggestedUsers.length - 1),
),
(index == (suggestedUsers.length - 1))
? const SizedBox.shrink()
: DividerWidget(
dividerType: DividerType.menu,
bgColor: getEnteColorScheme(context)
2022-12-16 11:48:06 +00:00
.fillFaint,
2022-12-16 04:34:18 +00:00
),
],
);
},
2023-01-30 17:45:26 +00:00
itemCount: suggestedUsers.length +
(widget.isAddingViewer ? 0 : 1),
2022-12-16 04:34:18 +00:00
// physics: const ClampingScrollPhysics(),
),
2022-12-16 04:34:18 +00:00
),
],
),
2022-11-22 08:20:05 +00:00
),
2022-12-16 04:13:29 +00:00
),
2022-12-16 04:34:18 +00:00
SafeArea(
child: Padding(
padding: const EdgeInsets.only(
top: 8,
bottom: 8,
left: 16,
right: 16,
),
child: Column(
crossAxisAlignment: CrossAxisAlignment.center,
2022-12-16 04:34:18 +00:00
children: [
2023-01-30 17:45:26 +00:00
const SizedBox(height: 8),
2023-01-31 01:03:19 +00:00
ButtonWidget(
buttonType: ButtonType.primary,
buttonSize: ButtonSize.large,
labelText: widget.isAddingViewer
? S.of(context).addViewer
: S.of(context).addCollaborator,
2023-01-31 01:03:19 +00:00
isDisabled: (selectedEmail == '' && !_emailIsValid),
onTap: (selectedEmail == '' && !_emailIsValid)
? null
: () async {
final emailToAdd =
selectedEmail == '' ? _email : selectedEmail;
final result =
await collectionActions.addEmailToCollection(
context,
widget.collection,
emailToAdd,
2023-01-31 17:25:16 +00:00
widget.isAddingViewer
2023-01-31 01:03:19 +00:00
? CollectionParticipantRole.viewer
: CollectionParticipantRole.collaborator,
);
2023-01-31 17:25:16 +00:00
if (result && mounted) {
2023-01-31 01:03:19 +00:00
Navigator.of(context).pop(true);
}
},
2022-12-16 04:34:18 +00:00
),
const SizedBox(height: 12),
2023-02-25 12:53:57 +00:00
GestureDetector(
onTap: () async {
if ((selectedEmail == '' && !_emailIsValid)) {
await showErrorDialog(
context,
S.of(context).invalidEmailAddress,
S.of(context).enterValidEmail,
);
return;
}
final emailToAdd =
selectedEmail == '' ? _email : selectedEmail;
2023-02-26 05:58:30 +00:00
showDialog(
context: context,
builder: (BuildContext context) {
return VerifyIdentifyDialog(
2023-02-26 07:02:27 +00:00
self: false,
email: emailToAdd,
);
2023-02-26 05:58:30 +00:00
},
);
},
child: Text(
2023-05-05 10:05:47 +00:00
S.of(context).verifyIDLabel,
textAlign: TextAlign.center,
style: enteTextTheme.smallMuted.copyWith(
decoration: TextDecoration.underline,
),
),
),
const SizedBox(height: 12),
2022-12-16 04:34:18 +00:00
],
),
2022-11-22 08:20:05 +00:00
),
2022-12-16 04:34:18 +00:00
),
],
),
);
}
2022-11-22 06:32:44 +00:00
void clearFocus() {
_textController.clear();
_email = _textController.text;
_emailIsValid = false;
textFieldFocusNode.unfocus();
setState(() => {});
}
2022-11-22 05:13:32 +00:00
Widget _getEmailField() {
return TextFormField(
2022-11-22 06:32:44 +00:00
controller: _textController,
focusNode: textFieldFocusNode,
style: getEnteTextTheme(context).body,
2022-11-22 05:13:32 +00:00
autofillHints: const [AutofillHints.email],
decoration: InputDecoration(
2022-11-22 06:32:44 +00:00
focusedBorder: OutlineInputBorder(
borderRadius: const BorderRadius.all(Radius.circular(4.0)),
borderSide:
BorderSide(color: getEnteColorScheme(context).strokeMuted),
),
2022-11-22 05:13:32 +00:00
fillColor: getEnteColorScheme(context).fillFaint,
filled: true,
hintText: S.of(context).enterEmail,
2022-11-22 05:13:32 +00:00
contentPadding: const EdgeInsets.symmetric(
horizontal: 16,
vertical: 14,
),
border: UnderlineInputBorder(
borderSide: BorderSide.none,
2022-11-22 06:32:44 +00:00
borderRadius: BorderRadius.circular(4),
),
prefixIcon: Icon(
Icons.email_outlined,
color: getEnteColorScheme(context).strokeMuted,
2022-11-22 05:13:32 +00:00
),
2022-11-22 06:32:44 +00:00
suffixIcon: _email == ''
? null
: IconButton(
onPressed: clearFocus,
icon: Icon(
Icons.cancel,
color: getEnteColorScheme(context).strokeMuted,
),
),
2022-11-22 05:13:32 +00:00
),
onChanged: (value) {
2022-11-22 06:32:44 +00:00
if (selectedEmail != '') {
selectedEmail = '';
}
2022-11-22 05:13:32 +00:00
_email = value.trim();
2023-01-28 18:24:20 +00:00
_emailIsValid = EmailValidator.validate(_email);
setState(() {});
2022-11-22 05:13:32 +00:00
},
autocorrect: false,
keyboardType: TextInputType.emailAddress,
//initialValue: _email,
textInputAction: TextInputAction.next,
);
}
List<User> _getSuggestedUser() {
final List<User> suggestedUsers = [];
final Set<String> existingEmails = {};
final int ownerID = Configuration.instance.getUserID()!;
existingEmails.add(Configuration.instance.getEmail()!);
2022-11-22 06:32:44 +00:00
for (final User? u in widget.collection.sharees ?? []) {
if (u != null && u.id != null && u.email.isNotEmpty) {
existingEmails.add(u.email);
}
}
for (final c in CollectionsService.instance.getActiveCollections()) {
if (c.owner?.id == ownerID) {
2022-12-30 09:44:52 +00:00
for (final User? u in c.sharees ?? []) {
if (u != null &&
u.id != null &&
u.email.isNotEmpty &&
!existingEmails.contains(u.email)) {
existingEmails.add(u.email);
suggestedUsers.add(u);
}
}
} else if (c.owner != null &&
c.owner!.id != null &&
c.owner!.email.isNotEmpty &&
!existingEmails.contains(c.owner!.email)) {
existingEmails.add(c.owner!.email);
suggestedUsers.add(c.owner!);
}
}
final cachedUserDetails = UserService.instance.getCachedUserDetails();
if (cachedUserDetails != null &&
(cachedUserDetails.familyData?.members?.isNotEmpty ?? false)) {
for (final member in cachedUserDetails.familyData!.members!) {
if (!existingEmails.contains(member.email)) {
existingEmails.add(member.email);
suggestedUsers.add(User(email: member.email));
}
}
}
2023-01-28 18:24:20 +00:00
if (_textController.text.trim().isNotEmpty) {
2023-01-30 17:45:26 +00:00
suggestedUsers.removeWhere(
(element) => !element.email
.toLowerCase()
.contains(_textController.text.trim().toLowerCase()),
);
2023-01-28 18:24:20 +00:00
}
suggestedUsers.sort((a, b) => a.email.compareTo(b.email));
2023-01-28 18:24:20 +00:00
return suggestedUsers;
}
}