Add hook to change email

This commit is contained in:
vishnukvmd 2021-07-28 23:36:30 +05:30
parent d8677970c1
commit 5260279beb
6 changed files with 205 additions and 42 deletions

View file

@ -0,0 +1,3 @@
import 'package:photos/events/event.dart';
class EmailChangedEvent extends Event {}

View file

@ -9,6 +9,7 @@ import 'package:photos/core/configuration.dart';
import 'package:photos/core/event_bus.dart';
import 'package:photos/core/network.dart';
import 'package:photos/db/public_keys_db.dart';
import 'package:photos/events/email_changed_event.dart';
import 'package:photos/events/two_factor_status_change_event.dart';
import 'package:photos/models/key_attributes.dart';
import 'package:photos/models/key_gen_result.dart';
@ -37,34 +38,34 @@ class UserService {
static final UserService instance = UserService._privateConstructor();
Future<void> getOtt(BuildContext context, String email) async {
Future<void> getOtt(
BuildContext context,
String email, {
bool isChangeEmail = false,
}) async {
final dialog = createProgressDialog(context, "please wait...");
await dialog.show();
await _dio.get(
_config.getHttpEndpoint() + "/users/ott",
queryParameters: {
"email": email,
"purpose": isChangeEmail ? "change" : ""
},
).catchError((e) async {
_logger.severe(e);
}).then((response) async {
await dialog.hide();
if (response != null) {
if (response.statusCode == 200) {
Navigator.of(context).push(
MaterialPageRoute(
builder: (BuildContext context) {
return OTTVerificationPage();
},
),
);
} else if (response.statusCode == 403) {
showErrorDialog(
context,
"please wait...",
"we are currently not accepting new registrations. you have been added to the waitlist and we will let you know once we are ready for you.",
);
}
if (response != null && response.statusCode == 200) {
Navigator.of(context).push(
MaterialPageRoute(
builder: (BuildContext context) {
return OTTVerificationPage(
email,
isChangeEmail: isChangeEmail,
);
},
),
);
} else {
showGenericErrorDialog(context);
}
@ -178,6 +179,50 @@ class UserService {
}
}
Future<void> changeEmail(
BuildContext context,
String email,
String ott,
) async {
final dialog = createProgressDialog(context, "please wait...");
await dialog.show();
try {
final response = await _dio.post(
_config.getHttpEndpoint() + "/users/change-email",
data: {
"email": email,
"ott": ott,
},
options: Options(
headers: {
"X-Auth-Token": _config.getToken(),
},
),
);
await dialog.hide();
if (response != null && response.statusCode == 200) {
showToast("email changed to " + email);
_config.setEmail(email);
Navigator.of(context).popUntil((route) => route.isFirst);
Bus.instance.fire(EmailChangedEvent());
return;
}
showErrorDialog(context, "oops", "verification failed, please try again");
} on DioError catch (e) {
await dialog.hide();
if (e.response != null && e.response.statusCode == 403) {
showErrorDialog(context, "oops", "this email is already in use");
} else {
showErrorDialog(context, "incorrect code",
"authentication failed, please try again");
}
} catch (e) {
await dialog.hide();
_logger.severe(e);
showErrorDialog(context, "oops", "verification failed, please try again");
}
}
Future<void> setAttributes(KeyGenResult result) async {
try {
final name = _config.getName();

View file

@ -0,0 +1,78 @@
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:photos/services/user_service.dart';
import 'package:photos/utils/dialog_util.dart';
import 'package:photos/utils/email_util.dart';
class ChangeEmailDialog extends StatefulWidget {
const ChangeEmailDialog({Key key}) : super(key: key);
@override
_ChangeEmailDialogState createState() => _ChangeEmailDialogState();
}
class _ChangeEmailDialogState extends State<ChangeEmailDialog> {
String _email;
@override
Widget build(BuildContext context) {
return AlertDialog(
title: Text("enter your email address"),
content: SingleChildScrollView(
child: Column(
mainAxisAlignment: MainAxisAlignment.start,
crossAxisAlignment: CrossAxisAlignment.start,
children: [
TextFormField(
decoration: InputDecoration(
hintText: 'email',
hintStyle: TextStyle(
color: Colors.white30,
),
contentPadding: EdgeInsets.all(12),
),
onChanged: (value) {
setState(() {
_email = value;
});
},
autocorrect: false,
keyboardType: TextInputType.emailAddress,
initialValue: _email,
autofocus: true,
),
],
),
),
actions: [
TextButton(
child: Text(
"cancel",
style: TextStyle(
color: Colors.redAccent,
),
),
onPressed: () {
Navigator.pop(context);
},
),
TextButton(
child: Text(
"verify email",
style: TextStyle(
color: Colors.white,
),
),
onPressed: () {
if (!isValidEmail(_email)) {
showErrorDialog(context, "invalid email address",
"please enter a valid email address.");
return;
}
UserService.instance.getOtt(context, _email, isChangeEmail: true);
},
),
],
);
}
}

View file

@ -2,12 +2,18 @@ import 'dart:ui';
import 'package:flutter/material.dart';
import 'package:flutter/widgets.dart';
import 'package:photos/core/configuration.dart';
import 'package:photos/ui/common_elements.dart';
import 'package:photos/services/user_service.dart';
import 'package:photos/ui/common_elements.dart';
class OTTVerificationPage extends StatefulWidget {
OTTVerificationPage({Key key}) : super(key: key);
final String email;
final bool isChangeEmail;
OTTVerificationPage(
this.email, {
this.isChangeEmail = false,
Key key,
}) : super(key: key);
@override
_OTTVerificationPageState createState() => _OTTVerificationPageState();
@ -42,7 +48,7 @@ class _OTTVerificationPageState extends State<OTTVerificationPage> {
),
Padding(padding: EdgeInsets.all(2)),
Text(
Configuration.instance.getEmail(),
widget.email,
style: TextStyle(
color: Theme.of(context).buttonColor,
fontSize: 18,
@ -86,14 +92,19 @@ class _OTTVerificationPageState extends State<OTTVerificationPage> {
_verificationCodeController.text.isEmpty
? null
: () {
UserService.instance.verifyEmail(
context, _verificationCodeController.text);
if (widget.isChangeEmail) {
UserService.instance.changeEmail(context,
widget.email, _verificationCodeController.text);
} else {
UserService.instance.verifyEmail(
context, _verificationCodeController.text);
}
},
fontSize: 18,
),
),
Padding(padding: EdgeInsets.all(8)),
FlatButton(
TextButton(
onPressed: () {
Navigator.of(context).pop();
},
@ -102,6 +113,7 @@ class _OTTVerificationPageState extends State<OTTVerificationPage> {
style: TextStyle(
decoration: TextDecoration.underline,
fontSize: 12,
color: Colors.white.withOpacity(0.7),
),
)),
],

View file

@ -3,6 +3,7 @@ import 'dart:io';
import 'package:flutter/material.dart';
import 'package:flutter_sodium/flutter_sodium.dart';
import 'package:photos/services/user_service.dart';
import 'package:photos/ui/change_email_dialog.dart';
import 'package:photos/ui/password_entry_page.dart';
import 'package:photos/ui/recovery_key_dialog.dart';
import 'package:photos/ui/settings/settings_section_title.dart';
@ -84,24 +85,31 @@ class AccountSectionWidgetState extends State<AccountSectionWidget> {
Platform.isIOS
? Padding(padding: EdgeInsets.all(2))
: Padding(padding: EdgeInsets.all(2)),
// GestureDetector(
// behavior: HitTestBehavior.translucent,
// onTap: () async {
// final result = await requestAuthentication();
// if (!result) {
// showToast("please authenticate to change your email");
// return;
// }
// // showDialog
// },
// child:
// SettingsTextItem(text: "change email", icon: Icons.navigate_next),
// ),
// Padding(padding: EdgeInsets.all(2)),
// Divider(height: 4),
// Platform.isIOS
// ? Padding(padding: EdgeInsets.all(2))
// : Padding(padding: EdgeInsets.all(4)),
GestureDetector(
behavior: HitTestBehavior.translucent,
onTap: () async {
// final result = await requestAuthentication();
// if (!result) {
// showToast("please authenticate to change your email");
// return;
// }
showDialog(
context: context,
builder: (BuildContext context) {
return ChangeEmailDialog();
},
barrierColor: Colors.black.withOpacity(0.85),
barrierDismissible: false,
);
},
child:
SettingsTextItem(text: "change email", icon: Icons.navigate_next),
),
Padding(padding: EdgeInsets.all(2)),
Divider(height: 4),
Platform.isIOS
? Padding(padding: EdgeInsets.all(2))
: Padding(padding: EdgeInsets.all(4)),
GestureDetector(
behavior: HitTestBehavior.translucent,
onTap: () async {

View file

@ -1,7 +1,10 @@
import 'dart:async';
import 'dart:math';
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:photos/core/event_bus.dart';
import 'package:photos/events/email_changed_event.dart';
import 'package:photos/models/user_details.dart';
import 'package:photos/services/user_service.dart';
import 'package:photos/ui/loading_widget.dart';
@ -18,10 +21,18 @@ class DetailsSectionWidget extends StatefulWidget {
class _DetailsSectionWidgetState extends State<DetailsSectionWidget> {
UserDetails _userDetails;
StreamSubscription<EmailChangedEvent> _emailChangedEvent;
@override
void initState() {
super.initState();
_fetchUserDetails();
_emailChangedEvent = Bus.instance.on<EmailChangedEvent>().listen((event) {
_fetchUserDetails();
});
}
void _fetchUserDetails() {
UserService.instance.getUserDetails().then((details) {
setState(() {
_userDetails = details;
@ -29,6 +40,12 @@ class _DetailsSectionWidgetState extends State<DetailsSectionWidget> {
});
}
@override
void dispose() {
_emailChangedEvent.cancel();
super.dispose();
}
@override
Widget build(BuildContext context) {
return SizedBox(