Ver código fonte

Update UI for the OTT sign in flow

Vishnu Mohandas 4 anos atrás
pai
commit
ddb2c7dc82

Diferenças do arquivo suprimidas por serem muito extensas
+ 0 - 0
assets/around_the_world.svg


+ 7 - 16
lib/core/configuration.dart

@@ -12,10 +12,9 @@ class Configuration {
   static final Configuration instance = Configuration._privateConstructor();
 
   static const endpointKey = "endpoint";
-  static const tokenKey = "token";
-  static const usernameKey = "username";
   static const userIDKey = "user_id";
-  static const passwordKey = "password";
+  static const emailKey = "email";
+  static const tokenKey = "token";
   static const hasOptedForE2EKey = "has_opted_for_e2e_encryption";
   static const keyKey = "key";
   static const keyEncryptedKey = "encrypted_key";
@@ -50,7 +49,7 @@ class Configuration {
   }
 
   String getEndpoint() {
-    return _preferences.getString(endpointKey);
+    return "192.168.0.106";
   }
 
   String getHttpEndpoint() {
@@ -72,12 +71,12 @@ class Configuration {
     await _preferences.setString(tokenKey, token);
   }
 
-  String getUsername() {
-    return _preferences.getString(usernameKey);
+  String getEmail() {
+    return _preferences.getString(emailKey);
   }
 
-  void setUsername(String username) async {
-    await _preferences.setString(usernameKey, username);
+  void setEmail(String email) async {
+    await _preferences.setString(emailKey, email);
   }
 
   int getUserID() {
@@ -88,14 +87,6 @@ class Configuration {
     await _preferences.setInt(userIDKey, userID);
   }
 
-  String getPassword() {
-    return _preferences.getString(passwordKey);
-  }
-
-  void setPassword(String password) async {
-    await _preferences.setString(passwordKey, password);
-  }
-
   void setOptInForE2E(bool hasOptedForE2E) async {
     await _preferences.setBool(hasOptedForE2EKey, hasOptedForE2E);
   }

+ 1 - 1
lib/folder_service.dart

@@ -136,7 +136,7 @@ class FolderSharingService {
       try {
         return Folder(
           null,
-          Configuration.instance.getUsername() + "s " + deviceFolder,
+          Configuration.instance.getEmail() + "s " + deviceFolder,
           Configuration.instance.getUserID(),
           deviceFolder,
           Set<int>(),

+ 5 - 2
lib/main.dart

@@ -109,8 +109,11 @@ class MyApp extends StatelessWidget with WidgetsBindingObserver {
 
     return MaterialApp(
       title: _title,
-      theme: ThemeData.dark()
-          .copyWith(hintColor: Colors.grey, accentColor: Colors.pink[400]),
+      theme: ThemeData.dark().copyWith(
+        hintColor: Colors.grey,
+        accentColor: Colors.pink[400],
+        buttonColor: Colors.pink,
+      ),
       home: HomeWidget(_title),
     );
   }

+ 38 - 93
lib/ui/email_entry_page.dart

@@ -1,11 +1,8 @@
-import 'package:dio/dio.dart';
 import 'package:flutter/cupertino.dart';
 import 'package:flutter/material.dart';
 import 'package:flutter/widgets.dart';
-import 'package:logging/logging.dart';
-import 'package:photos/core/configuration.dart';
-import 'package:photos/ui/ott_verification_page.dart';
-import 'package:photos/utils/dialog_util.dart';
+import 'package:flutter_svg/svg.dart';
+import 'package:photos/user_authenticator.dart';
 
 class EmailEntryPage extends StatefulWidget {
   EmailEntryPage({Key key}) : super(key: key);
@@ -28,96 +25,44 @@ class _EmailEntryPageState extends State<EmailEntryPage> {
   }
 
   Widget _getBody() {
-    return Container(
-      padding: EdgeInsets.all(8),
-      child: Column(
-        children: [
-          TextFormField(
-            decoration: InputDecoration(
-              hintText: 'email@domain.com',
-              contentPadding: EdgeInsets.all(20),
+    return SingleChildScrollView(
+      child: Container(
+        padding: EdgeInsets.all(8),
+        child: Column(
+          children: [
+            SvgPicture.asset(
+              "assets/around_the_world.svg",
+              width: 256,
+              height: 256,
             ),
-            controller: _emailController,
-            autofocus: true,
-            autocorrect: false,
-            keyboardType: TextInputType.emailAddress,
-          ),
-          Padding(padding: EdgeInsets.all(8)),
-          SizedBox(
-              width: double.infinity,
-              child: RaisedButton(
-                onPressed: () {
-                  _getOtt(_emailController.text);
-                },
-                padding: const EdgeInsets.fromLTRB(8, 12, 8, 12),
-                child: Text("Sign In"),
-                color: Colors.pink[400],
-                shape: RoundedRectangleBorder(
-                  borderRadius: BorderRadius.circular(18.0),
-                ),
-              )),
-        ],
-      ),
-    );
-  }
-
-  Future<void> _getOtt(String email) async {
-    final dialog = createProgressDialog(context, "Please wait...");
-    await dialog.show();
-    await Dio()
-        .get(Configuration.instance.getHttpEndpoint() + "/users/ott",
-            queryParameters: {
-              "email": email,
-            },
-            options: Options(
-              headers: {
-                "X-Auth-Token": Configuration.instance.getToken(),
-              },
-            ))
-        .catchError((e) async {
-      Logger("EmailEntryPage").severe(e);
-      await dialog.hide();
-      _showErrorDialog();
-    }).then((response) async {
-      await dialog.hide();
-      if (response.statusCode == 200) {
-        _navigateToVerificationInstructionPage(email);
-      } else {
-        _showErrorDialog();
-      }
-    });
-  }
-
-  void _navigateToVerificationInstructionPage(String email) {
-    Navigator.of(context).push(
-      MaterialPageRoute(
-        builder: (BuildContext context) {
-          return OTTVerificationPage(email);
-        },
-      ),
-    );
-  }
-
-  _showErrorDialog() {
-    AlertDialog alert = AlertDialog(
-      title: Text("Oops."),
-      content: Text("Sorry, something went wrong. Please try again."),
-      actions: [
-        FlatButton(
-          child: Text("OK"),
-          onPressed: () {
-            Navigator.of(context).pop();
-          },
+            TextFormField(
+              decoration: InputDecoration(
+                hintText: 'email@domain.com',
+                contentPadding: EdgeInsets.all(20),
+              ),
+              controller: _emailController,
+              autofocus: true,
+              autocorrect: false,
+              keyboardType: TextInputType.emailAddress,
+            ),
+            Padding(padding: EdgeInsets.all(8)),
+            SizedBox(
+                width: double.infinity,
+                child: RaisedButton(
+                  onPressed: () {
+                    UserAuthenticator.instance
+                        .getOtt(context, _emailController.text);
+                  },
+                  padding: const EdgeInsets.fromLTRB(8, 12, 8, 12),
+                  child: Text("Sign In"),
+                  color: Theme.of(context).buttonColor,
+                  shape: RoundedRectangleBorder(
+                    borderRadius: BorderRadius.circular(18.0),
+                  ),
+                )),
+          ],
         ),
-      ],
-    );
-
-    // show the dialog
-    showDialog(
-      context: context,
-      builder: (BuildContext context) {
-        return alert;
-      },
+      ),
     );
   }
 }

+ 7 - 22
lib/ui/gallery_app_bar_widget.dart

@@ -2,11 +2,10 @@ import 'dart:async';
 import 'package:flutter/cupertino.dart';
 import 'package:flutter/material.dart';
 import 'package:photos/core/configuration.dart';
-import 'package:photos/core/event_bus.dart';
-import 'package:photos/events/remote_sync_event.dart';
 import 'package:photos/file_repository.dart';
 import 'package:photos/models/selected_files.dart';
-import 'package:photos/ui/setup_page.dart';
+import 'package:photos/ui/email_entry_page.dart';
+import 'package:photos/ui/ott_verification_page.dart';
 import 'package:photos/ui/share_folder_widget.dart';
 import 'package:photos/utils/dialog_util.dart';
 import 'package:photos/utils/file_util.dart';
@@ -41,16 +40,8 @@ class GalleryAppBarWidget extends StatefulWidget
 }
 
 class _GalleryAppBarWidgetState extends State<GalleryAppBarWidget> {
-  bool _hasSyncErrors = false;
-  StreamSubscription<RemoteSyncEvent> _subscription;
-
   @override
   void initState() {
-    _subscription = Bus.instance.on<RemoteSyncEvent>().listen((event) {
-      setState(() {
-        _hasSyncErrors = !event.success;
-      });
-    });
     widget.selectedFiles.addListener(() {
       setState(() {});
     });
@@ -80,13 +71,13 @@ class _GalleryAppBarWidgetState extends State<GalleryAppBarWidget> {
 
   List<Widget> _getDefaultActions(BuildContext context) {
     List<Widget> actions = List<Widget>();
-    if (_hasSyncErrors || !Configuration.instance.hasConfiguredAccount()) {
+    if (!Configuration.instance.hasConfiguredAccount()) {
       actions.add(IconButton(
         icon: Icon(Configuration.instance.hasConfiguredAccount()
             ? Icons.sync_problem
             : Icons.sync_disabled),
         onPressed: () {
-          _openSyncConfiguration(context);
+          _navigateToSignInPage(context);
         },
       ));
     } else if (widget.type == GalleryAppBarType.local_folder &&
@@ -179,20 +170,14 @@ class _GalleryAppBarWidgetState extends State<GalleryAppBarWidget> {
     widget.selectedFiles.clearAll();
   }
 
-  void _openSyncConfiguration(BuildContext context) {
-    final page = SetupPage();
+  void _navigateToSignInPage(BuildContext context) {
     Navigator.of(context).push(
       MaterialPageRoute(
-        settings: RouteSettings(name: "/setup"),
         builder: (BuildContext context) {
-          return page;
+          // return OTTVerificationPage("hello@ente.io");
+          return EmailEntryPage();
         },
       ),
     );
   }
-
-  void dispose() {
-    _subscription.cancel();
-    super.dispose();
-  }
 }

+ 44 - 5
lib/ui/ott_verification_page.dart

@@ -1,6 +1,9 @@
+import 'dart:ui';
+
 import 'package:flutter/material.dart';
 import 'package:flutter/widgets.dart';
 import 'package:flutter_svg/flutter_svg.dart';
+import 'package:photos/user_authenticator.dart';
 
 class OTTVerificationPage extends StatefulWidget {
   final String email;
@@ -29,6 +32,8 @@ class _OTTVerificationPageState extends State<OTTVerificationPage> {
         padding: EdgeInsets.fromLTRB(8, 64, 8, 8),
         child: Column(
           crossAxisAlignment: CrossAxisAlignment.center,
+          mainAxisSize: MainAxisSize.max,
+          mainAxisAlignment: MainAxisAlignment.end,
           children: [
             SvgPicture.asset(
               "assets/email_sent.svg",
@@ -38,22 +43,22 @@ class _OTTVerificationPageState extends State<OTTVerificationPage> {
             Padding(padding: EdgeInsets.all(12)),
             Text.rich(
               TextSpan(
-                text: "We've sent a mail to ",
                 style: TextStyle(fontSize: 18),
                 children: <TextSpan>[
+                  TextSpan(text: "We've sent a mail to "),
                   TextSpan(
                       text: widget.email,
                       style: TextStyle(
-                        decoration: TextDecoration.underline,
+                        color: Theme.of(context).accentColor,
                       )),
-                  // can add more TextSpans here...
+                  TextSpan(text: "."),
                 ],
               ),
               textAlign: TextAlign.center,
             ),
             Padding(padding: EdgeInsets.all(12)),
             Text(
-              "Please check your inbox (and spam folders) to complete the verification.",
+              "Please check your inbox (and spam) to complete verification.",
               textAlign: TextAlign.center,
             ),
             Padding(padding: EdgeInsets.all(12)),
@@ -63,11 +68,45 @@ class _OTTVerificationPageState extends State<OTTVerificationPage> {
                 contentPadding: EdgeInsets.all(20),
               ),
               controller: _verificationCodeController,
-              autofocus: true,
+              autofocus: false,
               autocorrect: false,
               keyboardType: TextInputType.visiblePassword,
               textAlign: TextAlign.center,
+              onChanged: (_) {
+                setState(() {});
+              },
             ),
+            Padding(padding: EdgeInsets.all(8)),
+            SizedBox(
+                width: double.infinity,
+                child: RaisedButton(
+                  onPressed: _verificationCodeController.text == null ||
+                          _verificationCodeController.text.isEmpty
+                      ? null
+                      : () {
+                          UserAuthenticator.instance.getCredentials(context,
+                              widget.email, _verificationCodeController.text);
+                        },
+                  padding: const EdgeInsets.fromLTRB(8, 12, 8, 12),
+                  child: Text(
+                    "Sign In",
+                  ),
+                  color: Colors.pink,
+                  shape: RoundedRectangleBorder(
+                    borderRadius: BorderRadius.circular(18.0),
+                  ),
+                )),
+            TextButton(
+                onPressed: () {
+                  Navigator.of(context).pop();
+                },
+                child: Text(
+                  "Did not get email?",
+                  style: TextStyle(
+                    decoration: TextDecoration.underline,
+                    fontSize: 12,
+                  ),
+                ))
           ],
         ),
       ),

+ 63 - 5
lib/user_authenticator.dart

@@ -1,9 +1,13 @@
 import 'package:dio/dio.dart';
+import 'package:flutter/material.dart';
+import 'package:flutter/widgets.dart';
 import 'package:logging/logging.dart';
 import 'package:photos/core/configuration.dart';
 import 'package:photos/core/event_bus.dart';
 
 import 'package:photos/events/user_authenticated_event.dart';
+import 'package:photos/ui/ott_verification_page.dart';
+import 'package:photos/utils/dialog_util.dart';
 
 class UserAuthenticator {
   final _dio = Dio();
@@ -14,6 +18,60 @@ class UserAuthenticator {
   static final UserAuthenticator instance =
       UserAuthenticator._privateConstructor();
 
+  Future<void> getOtt(BuildContext context, String email) async {
+    final dialog = createProgressDialog(context, "Please wait...");
+    await dialog.show();
+    await Dio().get(
+      Configuration.instance.getHttpEndpoint() + "/users/ott",
+      queryParameters: {
+        "email": email,
+      },
+    ).catchError((e) async {
+      _logger.severe(e);
+      await dialog.hide();
+      showGenericErrorDialog(context);
+    }).then((response) async {
+      await dialog.hide();
+      if (response.statusCode == 200) {
+        Navigator.of(context).push(
+          MaterialPageRoute(
+            builder: (BuildContext context) {
+              return OTTVerificationPage(email);
+            },
+          ),
+        );
+      } else {
+        showGenericErrorDialog(context);
+      }
+    });
+  }
+
+  Future<void> getCredentials(
+      BuildContext context, String email, String ott) async {
+    final dialog = createProgressDialog(context, "Please wait...");
+    await dialog.show();
+    await Dio().get(
+      Configuration.instance.getHttpEndpoint() + "/users/credentials",
+      queryParameters: {
+        "email": email,
+        "ott": ott,
+      },
+    ).catchError((e) async {
+      _logger.severe(e);
+      await dialog.hide();
+      showGenericErrorDialog(context);
+    }).then((response) async {
+      await dialog.hide();
+      if (response.statusCode == 200) {
+        _saveConfiguration(email, response);
+        Navigator.of(context).pop();
+      } else {
+        showErrorDialog(
+            context, "Oops.", "Verification failed, please try again.");
+      }
+    });
+  }
+
   Future<bool> login(String username, String password) {
     return _dio.post(
         Configuration.instance.getHttpEndpoint() + "/users/authenticate",
@@ -22,7 +80,7 @@ class UserAuthenticator {
           "password": password,
         }).then((response) {
       if (response.statusCode == 200 && response.data != null) {
-        _saveConfiguration(username, password, response);
+        _saveConfiguration(username, response);
         Bus.instance.fire(UserAuthenticatedEvent());
         return true;
       } else {
@@ -41,7 +99,7 @@ class UserAuthenticator {
       "password": password,
     }).then((response) {
       if (response.statusCode == 200 && response.data != null) {
-        _saveConfiguration(username, password, response);
+        _saveConfiguration(username, response);
         return true;
       } else {
         if (response.data != null && response.data["message"] != null) {
@@ -68,9 +126,9 @@ class UserAuthenticator {
     );
   }
 
-  void _saveConfiguration(String username, String password, Response response) {
-    Configuration.instance.setUsername(username);
-    Configuration.instance.setPassword(password);
+  void _saveConfiguration(String email, Response response) {
+    _logger.info("Saving configuration " + response.data.toString());
+    Configuration.instance.setEmail(email);
     Configuration.instance.setUserID(response.data["id"]);
     Configuration.instance.setToken(response.data["token"]);
     final String encryptedKey = response.data["encryptedKey"];

+ 27 - 0
lib/utils/dialog_util.dart

@@ -20,3 +20,30 @@ ProgressDialog createProgressDialog(BuildContext context, String message) {
   );
   return dialog;
 }
+
+void showErrorDialog(BuildContext context, String title, String content) {
+  AlertDialog alert = AlertDialog(
+    title: Text(title),
+    content: Text(content),
+    actions: [
+      FlatButton(
+        child: Text("OK"),
+        onPressed: () {
+          Navigator.of(context).pop();
+        },
+      ),
+    ],
+  );
+
+  showDialog(
+    context: context,
+    builder: (BuildContext context) {
+      return alert;
+    },
+  );
+}
+
+void showGenericErrorDialog(BuildContext context) {
+  showErrorDialog(
+      context, "Oops.", "Sorry, something went wrong. Please try again.");
+}

+ 21 - 0
pubspec.lock

@@ -272,6 +272,13 @@ packages:
       url: "https://pub.dartlang.org"
     source: hosted
     version: "3.3.3"
+  flutter_svg:
+    dependency: "direct main"
+    description:
+      name: flutter_svg
+      url: "https://pub.dartlang.org"
+    source: hosted
+    version: "0.18.1"
   flutter_test:
     dependency: "direct dev"
     description: flutter
@@ -408,6 +415,20 @@ packages:
       url: "https://pub.dartlang.org"
     source: hosted
     version: "1.7.0"
+  path_drawing:
+    dependency: transitive
+    description:
+      name: path_drawing
+      url: "https://pub.dartlang.org"
+    source: hosted
+    version: "0.4.1+1"
+  path_parsing:
+    dependency: transitive
+    description:
+      name: path_parsing
+      url: "https://pub.dartlang.org"
+    source: hosted
+    version: "0.1.4"
   path_provider:
     dependency: "direct main"
     description:

+ 3 - 0
pubspec.yaml

@@ -62,6 +62,7 @@ dependencies:
   computer: ^1.0.2
   flutter_secure_storage: ^3.3.3
   uni_links: ^0.4.0
+  flutter_svg: ^0.18.1
 
 dev_dependencies:
   flutter_test:
@@ -78,6 +79,8 @@ flutter_icons:
 
 # The following section is specific to Flutter.
 flutter:
+  assets:
+    - assets/
 
   # The following line ensures that the Material Icons font is
   # included with your application, so that you can use the icons in

Alguns arquivos não foram mostrados porque muitos arquivos mudaram nesse diff