From beb8974caa82f4679898f9f53f3c6abca0b5f765 Mon Sep 17 00:00:00 2001
From: Rongjian Zhang <pd4d10@gmail.com>
Date: Thu, 21 Feb 2019 21:21:16 +0800
Subject: [PATCH] feat: gitlab account login

---
 lib/providers/settings.dart   | 103 ++++++++++++++++++++++++--------
 lib/screens/login.dart        | 108 +++++++++++++++++++---------------
 lib/screens/login_gitlab.dart |   6 +-
 3 files changed, 143 insertions(+), 74 deletions(-)

diff --git a/lib/providers/settings.dart b/lib/providers/settings.dart
index 8441d5f..df126d4 100644
--- a/lib/providers/settings.dart
+++ b/lib/providers/settings.dart
@@ -8,14 +8,14 @@ import 'package:url_launcher/url_launcher.dart';
 // import 'package:flutter/services.dart';
 import 'package:flutter/material.dart';
 import 'package:shared_preferences/shared_preferences.dart';
-import '../utils/utils.dart';
+// import '../utils/utils.dart';
 import '../utils/constants.dart';
 import '../models/account.dart';
 
-// enum PlatformType {
-//   github,
-//   gitlab,
-// }
+class PlatformType {
+  static const github = 0;
+  static const gitlab = 1;
+}
 
 // abstract class Model<T> {
 //   Future<T> query(BuildContext context) {
@@ -38,7 +38,7 @@ import '../models/account.dart';
 class ThemeMap {
   static const material = 0;
   static const cupertino = 1;
-  static const all = [0, 1];
+  static const values = [0, 1];
 }
 
 class SettingsProvider extends StatefulWidget {
@@ -61,8 +61,11 @@ class SettingsProviderState extends State<SettingsProvider> {
   int theme;
 
   Map<String, AccountModel> githubAccountMap;
+  Map<String, AccountModel> gitlabAccountMap;
 
+  int activePlatform;
   String activeLogin;
+
   StreamSubscription<Uri> _sub;
   bool loading = false;
 
@@ -80,11 +83,17 @@ class SettingsProviderState extends State<SettingsProvider> {
     setState(() {});
   }
 
-  get token {
-    if (activeLogin == null) {
-      return null;
+  String get token {
+    if (activeLogin == null) return null;
+
+    switch (activePlatform) {
+      case PlatformType.github:
+        return githubAccountMap[activeLogin].token;
+      case PlatformType.gitlab:
+        return gitlabAccountMap[activeLogin].token;
+      default:
+        return null;
     }
-    return githubAccountMap[activeLogin].token;
   }
 
   @override
@@ -152,35 +161,81 @@ class SettingsProviderState extends State<SettingsProvider> {
 
     // write
     SharedPreferences prefs = await SharedPreferences.getInstance();
-    var githubData = json.encode(githubAccountMap
-        .map((login, account) => MapEntry(login, account.toJson())));
-    // print('write github: $githubData');
-    await prefs.setString('github', githubData);
+    await prefs.setString(
+        'github',
+        json.encode(githubAccountMap
+            .map((login, account) => MapEntry(login, account.toJson()))));
 
     setState(() {
       loading = false;
     });
   }
 
+  Future<void> loginToGitlab(String domain, String token) async {
+    setState(() {
+      loading = true;
+    });
+
+    try {
+      var res = await http
+          .get('$domain/api/v4/user', headers: {'Private-Token': token});
+      var info = json.decode(res.body);
+
+      if (info['message'] != null) {
+        throw info['message'];
+      }
+
+      String login = info['username'];
+      String avatarUrl = info['avatar_url'];
+      gitlabAccountMap[login] =
+          AccountModel(token: token, avatarUrl: avatarUrl, domain: domain);
+
+      SharedPreferences prefs = await SharedPreferences.getInstance();
+      await prefs.setString(
+          'gitlab',
+          json.encode(gitlabAccountMap
+              .map((login, account) => MapEntry(login, account.toJson()))));
+    } catch (err) {
+      print(err);
+      // TODO: show errors
+    } finally {
+      setState(() {
+        loading = false;
+      });
+    }
+  }
+
   void _initDataFromPref() async {
     SharedPreferences prefs = await SharedPreferences.getInstance();
 
     // read GitHub accounts
     try {
-      var str = prefs.getString('github');
-      // print('read github: $str');
-      Map<String, dynamic> github = json.decode(str);
-      githubAccountMap = github.map<String, AccountModel>(
-          (login, _accountMap) =>
-              MapEntry(login, AccountModel.fromJson(_accountMap)));
+      String str = prefs.getString('github');
+      print('read github: $str');
+
+      Map<String, dynamic> data = json.decode(str ?? '{}');
+      githubAccountMap = data.map<String, AccountModel>((login, _accountMap) =>
+          MapEntry(login, AccountModel.fromJson(_accountMap)));
     } catch (err) {
       print(err);
       githubAccountMap = {};
     }
 
+    try {
+      String str = prefs.getString('gitlab');
+      print('read gitlab: $str');
+
+      Map<String, dynamic> data = json.decode(str ?? '{}');
+      gitlabAccountMap = data.map<String, AccountModel>((login, _accountMap) =>
+          MapEntry(login, AccountModel.fromJson(_accountMap)));
+    } catch (err) {
+      print(err);
+      gitlabAccountMap = {};
+    }
+
     int _theme = prefs.getInt('theme');
     print('read theme: $_theme');
-    if (ThemeMap.all.contains(_theme)) {
+    if (ThemeMap.values.contains(_theme)) {
       theme = _theme;
     } else if (Platform.isIOS) {
       theme = ThemeMap.cupertino;
@@ -189,14 +244,12 @@ class SettingsProviderState extends State<SettingsProvider> {
     setState(() {
       ready = true;
     });
-
-    // print(counter);
-    // await prefs.setInt('counter', counter);
   }
 
-  void setActiveAccount(String login) {
+  void setActiveAccount(String login, int type) {
     setState(() {
       activeLogin = login;
+      activePlatform = type;
     });
   }
 
diff --git a/lib/screens/login.dart b/lib/screens/login.dart
index 54a2c77..551d0a5 100644
--- a/lib/screens/login.dart
+++ b/lib/screens/login.dart
@@ -5,6 +5,7 @@ import '../scaffolds/simple.dart';
 import '../utils/constants.dart';
 import '../widgets/link.dart';
 import '../widgets/loading.dart';
+import '../models/account.dart';
 import 'login_gitlab.dart';
 
 class LoginScreen extends StatefulWidget {
@@ -13,6 +14,42 @@ class LoginScreen extends StatefulWidget {
 }
 
 class _LoginScreenState extends State<LoginScreen> {
+  Widget _buildAccountItem(MapEntry<String, AccountModel> entry, int type) {
+    var settings = SettingsProvider.of(context);
+
+    return Link(
+      onTap: () {
+        // Navigator.of(context).pop();
+        settings.setActiveAccount(entry.key, type);
+      },
+      child: Container(
+        padding: EdgeInsets.all(10),
+        decoration: BoxDecoration(
+          border: Border(bottom: BorderSide(color: Colors.black12)),
+        ),
+        child: Row(children: <Widget>[
+          CircleAvatar(
+            backgroundColor: Colors.transparent,
+            backgroundImage: NetworkImage(entry.value.avatarUrl),
+            radius: 24,
+          ),
+          Padding(padding: EdgeInsets.only(left: 10)),
+          Expanded(
+            child: Column(
+              crossAxisAlignment: CrossAxisAlignment.start,
+              children: <Widget>[
+                Text(entry.key, style: TextStyle(fontSize: 20)),
+                Padding(padding: EdgeInsets.only(top: 6)),
+                Text(entry.value.domain ?? 'https://github.com')
+              ],
+            ),
+          ),
+          settings.activeLogin == entry.key ? Icon(Icons.check) : Container(),
+        ]),
+      ),
+    );
+  }
+
   Widget _buildAddItem(
       {String text, Function onTap, WidgetBuilder screenBuilder}) {
     return Link(
@@ -47,56 +84,31 @@ class _LoginScreenState extends State<LoginScreen> {
 
         return Container(
           child: Column(
-            children: settings.githubAccountMap.entries.map<Widget>((entry) {
-              return Link(
-                onTap: () {
-                  // Navigator.of(context).pop();
-                  settings.setActiveAccount(entry.key);
-                },
-                child: Container(
-                  padding: EdgeInsets.all(10),
-                  decoration: BoxDecoration(
-                    border: Border(bottom: BorderSide(color: Colors.black12)),
-                  ),
-                  child: Row(children: <Widget>[
-                    CircleAvatar(
-                      backgroundColor: Colors.transparent,
-                      backgroundImage: NetworkImage(entry.value.avatarUrl),
-                      radius: 24,
+            children: settings.githubAccountMap.entries
+                .map<Widget>(
+                    (entry) => _buildAccountItem(entry, PlatformType.github))
+                .toList()
+                  ..addAll(
+                    settings.gitlabAccountMap.entries
+                        .map<Widget>((entry) =>
+                            _buildAccountItem(entry, PlatformType.gitlab))
+                        .toList(),
+                  )
+                  ..addAll([
+                    _buildAddItem(
+                      text: 'GitHub Account',
+                      onTap: () {
+                        var state = settings.generateRandomString();
+                        launch(
+                          'https://github.com/login/oauth/authorize?client_id=$clientId&redirect_uri=gittouch://login&scope=user%20repo&state=$state',
+                        );
+                      },
                     ),
-                    Padding(padding: EdgeInsets.only(left: 10)),
-                    Expanded(
-                      child: Column(
-                        crossAxisAlignment: CrossAxisAlignment.start,
-                        children: <Widget>[
-                          Text(entry.key, style: TextStyle(fontSize: 20)),
-                          Padding(padding: EdgeInsets.only(top: 6)),
-                          Text(entry.value.domain ?? 'https://github.com')
-                        ],
-                      ),
-                    ),
-                    settings.activeLogin == entry.key
-                        ? Icon(Icons.check)
-                        : Container(),
+                    _buildAddItem(
+                      text: 'GitLab Account',
+                      screenBuilder: (_) => LoginGitlabScreen(),
+                    )
                   ]),
-                ),
-              );
-            }).toList()
-              ..addAll([
-                _buildAddItem(
-                  text: 'GitHub Account',
-                  onTap: () {
-                    var state = settings.generateRandomString();
-                    launch(
-                      'https://github.com/login/oauth/authorize?client_id=$clientId&redirect_uri=gittouch://login&scope=user%20repo&state=$state',
-                    );
-                  },
-                ),
-                _buildAddItem(
-                  text: 'GitLab Account',
-                  screenBuilder: (_) => LoginGitlabScreen(),
-                )
-              ]),
           ),
         );
       },
diff --git a/lib/screens/login_gitlab.dart b/lib/screens/login_gitlab.dart
index 5349244..8175603 100644
--- a/lib/screens/login_gitlab.dart
+++ b/lib/screens/login_gitlab.dart
@@ -1,5 +1,6 @@
 import 'package:flutter/material.dart';
 import '../scaffolds/simple.dart';
+import '../providers/settings.dart';
 
 class LoginGitlabScreen extends StatefulWidget {
   @override
@@ -30,7 +31,10 @@ class _LoginGitlabScreenState extends State<LoginGitlabScreen> {
             ),
             MaterialButton(
               child: Text('Login'),
-              onPressed: () {},
+              onPressed: () {
+                SettingsProvider.of(context).loginToGitlab(_domain, _token);
+                Navigator.of(context).pop();
+              },
             )
           ],
         );