mirror of
https://github.com/git-touch/git-touch
synced 2025-01-31 08:04:51 +01:00
refactor: function params, add gitlab login screen
This commit is contained in:
parent
0396ac7f7b
commit
7fe5575d25
@ -10,6 +10,30 @@ import 'package:flutter/material.dart';
|
||||
import 'package:shared_preferences/shared_preferences.dart';
|
||||
import '../utils/utils.dart';
|
||||
import '../utils/constants.dart';
|
||||
import '../models/account.dart';
|
||||
|
||||
// enum PlatformType {
|
||||
// github,
|
||||
// gitlab,
|
||||
// }
|
||||
|
||||
// abstract class Model<T> {
|
||||
// Future<T> query(BuildContext context) {
|
||||
// var settings = SettingsProvider.of(context);
|
||||
|
||||
// switch (settings.platformType) {
|
||||
// case PlatformType.github:
|
||||
// return queryGithub(settings);
|
||||
// case PlatformType.gitlab:
|
||||
// return queryGitlab(settings);
|
||||
// default:
|
||||
// return null;
|
||||
// }
|
||||
// }
|
||||
|
||||
// Future<T> queryGithub(SettingsProviderState settings);
|
||||
// Future<T> queryGitlab(SettingsProviderState settings);
|
||||
// }
|
||||
|
||||
class ThemeMap {
|
||||
static const material = 0;
|
||||
@ -17,59 +41,35 @@ class ThemeMap {
|
||||
static const all = [0, 1];
|
||||
}
|
||||
|
||||
final prefix = 'https://api.github.com';
|
||||
|
||||
class Account {
|
||||
String avatarUrl;
|
||||
String token;
|
||||
|
||||
/// for github enterprise
|
||||
String domain;
|
||||
|
||||
Account({
|
||||
@required this.avatarUrl,
|
||||
@required this.token,
|
||||
this.domain,
|
||||
});
|
||||
|
||||
Account.fromJson(input) {
|
||||
avatarUrl = input['avatarUrl'];
|
||||
token = input['token'];
|
||||
domain = input['domain'];
|
||||
}
|
||||
|
||||
Map<String, dynamic> toJson() {
|
||||
var data = {'avatarUrl': avatarUrl, 'token': token};
|
||||
if (domain != null) {
|
||||
data['domain'] = domain;
|
||||
}
|
||||
return data;
|
||||
}
|
||||
}
|
||||
|
||||
class SettingsProvider extends StatefulWidget {
|
||||
final Widget child;
|
||||
|
||||
SettingsProvider({@required this.child});
|
||||
|
||||
static _SettingsProviderState of(BuildContext context) {
|
||||
static SettingsProviderState of(BuildContext context) {
|
||||
return (context.inheritFromWidgetOfExactType(_InheritedSettingsProvider)
|
||||
as _InheritedSettingsProvider)
|
||||
.data;
|
||||
}
|
||||
|
||||
@override
|
||||
_SettingsProviderState createState() => new _SettingsProviderState();
|
||||
SettingsProviderState createState() => new SettingsProviderState();
|
||||
}
|
||||
|
||||
class _SettingsProviderState extends State<SettingsProvider> {
|
||||
class SettingsProviderState extends State<SettingsProvider> {
|
||||
bool ready = false;
|
||||
int theme;
|
||||
Map<String, Account> githubAccountMap;
|
||||
|
||||
Map<String, AccountModel> githubAccountMap;
|
||||
|
||||
String activeLogin;
|
||||
StreamSubscription<Uri> _sub;
|
||||
bool loading = false;
|
||||
|
||||
// PlatformType platformType;
|
||||
|
||||
String prefix = 'https://api.github.com';
|
||||
|
||||
Future<void> setTheme(int _theme) async {
|
||||
SharedPreferences prefs = await SharedPreferences.getInstance();
|
||||
|
||||
@ -104,7 +104,7 @@ class _SettingsProviderState extends State<SettingsProvider> {
|
||||
}
|
||||
|
||||
// https://developer.github.com/apps/building-oauth-apps/authorizing-oauth-apps/#web-application-flow
|
||||
void _onSchemeDetected(Uri uri) async {
|
||||
Future<void> _onSchemeDetected(Uri uri) async {
|
||||
try {
|
||||
// FIXME:
|
||||
await closeWebView();
|
||||
@ -132,8 +132,10 @@ class _SettingsProviderState extends State<SettingsProvider> {
|
||||
);
|
||||
// print(res.body);
|
||||
var data = json.decode(res.body);
|
||||
String _token = data['access_token'];
|
||||
_loginWithToken(data['access_token']);
|
||||
}
|
||||
|
||||
Future<void> _loginWithToken(String token) async {
|
||||
// get login and avatar url
|
||||
var queryData = await query('''
|
||||
{
|
||||
@ -142,11 +144,11 @@ class _SettingsProviderState extends State<SettingsProvider> {
|
||||
avatarUrl
|
||||
}
|
||||
}
|
||||
''', _token);
|
||||
''', token);
|
||||
String login = queryData['viewer']['login'];
|
||||
String avatarUrl = queryData['viewer']['avatarUrl'];
|
||||
|
||||
githubAccountMap[login] = Account(avatarUrl: avatarUrl, token: _token);
|
||||
githubAccountMap[login] = AccountModel(avatarUrl: avatarUrl, token: token);
|
||||
|
||||
// write
|
||||
SharedPreferences prefs = await SharedPreferences.getInstance();
|
||||
@ -168,8 +170,9 @@ class _SettingsProviderState extends State<SettingsProvider> {
|
||||
var str = prefs.getString('github');
|
||||
// print('read github: $str');
|
||||
Map<String, dynamic> github = json.decode(str);
|
||||
githubAccountMap = github.map<String, Account>((login, _accountMap) =>
|
||||
MapEntry(login, Account.fromJson(_accountMap)));
|
||||
githubAccountMap = github.map<String, AccountModel>(
|
||||
(login, _accountMap) =>
|
||||
MapEntry(login, AccountModel.fromJson(_accountMap)));
|
||||
} catch (err) {
|
||||
print(err);
|
||||
githubAccountMap = {};
|
||||
@ -192,17 +195,9 @@ class _SettingsProviderState extends State<SettingsProvider> {
|
||||
}
|
||||
|
||||
void setActiveAccount(String login) {
|
||||
// FIXME: This is pretty tricky to trigger home screen rebuild
|
||||
setState(() {
|
||||
activeLogin = null;
|
||||
activeLogin = login;
|
||||
});
|
||||
nextTick(() {
|
||||
setState(() {
|
||||
activeLogin = login;
|
||||
// activeLogin = null;
|
||||
// ready = true;
|
||||
});
|
||||
}, 100);
|
||||
}
|
||||
|
||||
// http timeout
|
||||
@ -294,7 +289,7 @@ class _SettingsProviderState extends State<SettingsProvider> {
|
||||
}
|
||||
|
||||
class _InheritedSettingsProvider extends InheritedWidget {
|
||||
final _SettingsProviderState data;
|
||||
final SettingsProviderState data;
|
||||
|
||||
_InheritedSettingsProvider({
|
||||
Key key,
|
||||
|
@ -129,7 +129,7 @@ class _ListScaffoldState<T, K> extends State<ListScaffold<T, K>> {
|
||||
Widget _buildSliver(BuildContext context) {
|
||||
if (error.isNotEmpty) {
|
||||
return SliverToBoxAdapter(
|
||||
child: ErrorReload(text: error, reload: _refresh),
|
||||
child: ErrorReload(text: error, onTap: _refresh),
|
||||
);
|
||||
} else if (loading) {
|
||||
return SliverToBoxAdapter(child: Loading(more: false));
|
||||
@ -147,7 +147,7 @@ class _ListScaffoldState<T, K> extends State<ListScaffold<T, K>> {
|
||||
|
||||
Widget _buildBody(BuildContext context) {
|
||||
if (error.isNotEmpty) {
|
||||
return ErrorReload(text: error, reload: _refresh);
|
||||
return ErrorReload(text: error, onTap: _refresh);
|
||||
} else if (loading) {
|
||||
return Loading(more: false);
|
||||
} else if (items.isEmpty) {
|
||||
|
@ -127,7 +127,7 @@ class _LongListScaffoldState<T, K> extends State<LongListScaffold<T, K>> {
|
||||
),
|
||||
child: Center(
|
||||
child: Link(
|
||||
beforeRedirect: _loadMore,
|
||||
onTap: _loadMore,
|
||||
child: Container(
|
||||
padding: EdgeInsets.all(10),
|
||||
decoration: BoxDecoration(
|
||||
@ -168,7 +168,7 @@ class _LongListScaffoldState<T, K> extends State<LongListScaffold<T, K>> {
|
||||
Widget _buildSliver() {
|
||||
if (error.isNotEmpty) {
|
||||
return SliverToBoxAdapter(
|
||||
child: ErrorReload(text: error, reload: _refresh));
|
||||
child: ErrorReload(text: error, onTap: _refresh));
|
||||
} else if (loading) {
|
||||
return SliverToBoxAdapter(child: Loading(more: false));
|
||||
} else {
|
||||
|
@ -40,7 +40,7 @@ class _RefreshScaffoldState<T> extends State<RefreshScaffold<T>> {
|
||||
|
||||
Widget _buildBody() {
|
||||
if (error.isNotEmpty) {
|
||||
return ErrorReload(text: error, reload: _refresh);
|
||||
return ErrorReload(text: error, onTap: _refresh);
|
||||
} else if (payload == null) {
|
||||
return Loading(more: false);
|
||||
} else {
|
||||
|
@ -29,7 +29,7 @@ class RefreshStatelessScaffold extends StatelessWidget {
|
||||
|
||||
Widget _buildBody() {
|
||||
if (error.isNotEmpty) {
|
||||
return ErrorReload(text: error, reload: onRefresh);
|
||||
return ErrorReload(text: error, onTap: onRefresh);
|
||||
} else if (loading) {
|
||||
return Loading(more: false);
|
||||
} else {
|
||||
|
@ -3,11 +3,9 @@ import 'package:flutter/cupertino.dart';
|
||||
import 'package:flutter/widgets.dart';
|
||||
import '../providers/settings.dart';
|
||||
|
||||
typedef WidgetBuilder = Widget Function();
|
||||
|
||||
class SimpleScaffold extends StatelessWidget {
|
||||
final Widget title;
|
||||
final WidgetBuilder bodyBuilder;
|
||||
final Widget Function() bodyBuilder;
|
||||
final Widget trailing;
|
||||
final List<Widget> actions;
|
||||
final PreferredSizeWidget bottom;
|
||||
|
@ -5,6 +5,7 @@ import '../scaffolds/simple.dart';
|
||||
import '../utils/constants.dart';
|
||||
import '../widgets/link.dart';
|
||||
import '../widgets/loading.dart';
|
||||
import 'login_gitlab.dart';
|
||||
|
||||
class LoginScreen extends StatefulWidget {
|
||||
@override
|
||||
@ -12,6 +13,27 @@ class LoginScreen extends StatefulWidget {
|
||||
}
|
||||
|
||||
class _LoginScreenState extends State<LoginScreen> {
|
||||
Widget _buildAddItem(
|
||||
{String text, Function onTap, WidgetBuilder screenBuilder}) {
|
||||
return Link(
|
||||
child: Container(
|
||||
padding: EdgeInsets.symmetric(vertical: 20),
|
||||
decoration: BoxDecoration(
|
||||
border: Border(bottom: BorderSide(color: Colors.black12)),
|
||||
),
|
||||
child: Row(
|
||||
mainAxisAlignment: MainAxisAlignment.center,
|
||||
children: <Widget>[
|
||||
Icon(Icons.add),
|
||||
Text(text, style: TextStyle(fontSize: 16)),
|
||||
],
|
||||
),
|
||||
),
|
||||
onTap: onTap,
|
||||
screenBuilder: screenBuilder,
|
||||
);
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
var settings = SettingsProvider.of(context);
|
||||
@ -27,7 +49,7 @@ class _LoginScreenState extends State<LoginScreen> {
|
||||
child: Column(
|
||||
children: settings.githubAccountMap.entries.map<Widget>((entry) {
|
||||
return Link(
|
||||
beforeRedirect: () {
|
||||
onTap: () {
|
||||
// Navigator.of(context).pop();
|
||||
settings.setActiveAccount(entry.key);
|
||||
},
|
||||
@ -60,26 +82,21 @@ class _LoginScreenState extends State<LoginScreen> {
|
||||
),
|
||||
);
|
||||
}).toList()
|
||||
..add(
|
||||
Link(
|
||||
child: Container(
|
||||
padding: EdgeInsets.symmetric(vertical: 20),
|
||||
child: Row(
|
||||
mainAxisAlignment: MainAxisAlignment.center,
|
||||
children: <Widget>[
|
||||
Icon(Icons.add),
|
||||
Text('Add account', style: TextStyle(fontSize: 16)),
|
||||
],
|
||||
),
|
||||
),
|
||||
beforeRedirect: () {
|
||||
..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(),
|
||||
)
|
||||
]),
|
||||
),
|
||||
);
|
||||
},
|
||||
|
40
lib/screens/login_gitlab.dart
Normal file
40
lib/screens/login_gitlab.dart
Normal file
@ -0,0 +1,40 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import '../scaffolds/simple.dart';
|
||||
|
||||
class LoginGitlabScreen extends StatefulWidget {
|
||||
@override
|
||||
_LoginGitlabScreenState createState() => _LoginGitlabScreenState();
|
||||
}
|
||||
|
||||
class _LoginGitlabScreenState extends State<LoginGitlabScreen> {
|
||||
String _token;
|
||||
String _domain;
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return SimpleScaffold(
|
||||
title: Text('Login to GitLab'),
|
||||
bodyBuilder: () {
|
||||
return Column(
|
||||
children: <Widget>[
|
||||
TextField(
|
||||
// decoration: InputDecoration(icon: Icon(Icons.more_vert)),
|
||||
onChanged: (value) {
|
||||
_domain = value;
|
||||
},
|
||||
),
|
||||
TextField(
|
||||
onChanged: (value) {
|
||||
_token = value;
|
||||
},
|
||||
),
|
||||
MaterialButton(
|
||||
child: Text('Login'),
|
||||
onPressed: () {},
|
||||
)
|
||||
],
|
||||
);
|
||||
},
|
||||
);
|
||||
}
|
||||
}
|
@ -128,7 +128,7 @@ $key: pullRequest(number: ${item.number}) {
|
||||
),
|
||||
Link(
|
||||
material: false,
|
||||
beforeRedirect: () async {
|
||||
onTap: () async {
|
||||
await SettingsProvider.of(context)
|
||||
.putWithCredentials('/repos/$repo/notifications');
|
||||
await _onSwitchTab();
|
||||
|
@ -101,7 +101,7 @@ class _UserScreenState extends State<UserScreen> {
|
||||
Padding(padding: EdgeInsets.only(left: 4)),
|
||||
Text(email, style: TextStyle(color: Colors.black54, fontSize: 15))
|
||||
]),
|
||||
beforeRedirect: () {
|
||||
onTap: () {
|
||||
launch('mailto:' + email);
|
||||
},
|
||||
);
|
||||
|
@ -3,9 +3,9 @@ import 'link.dart';
|
||||
|
||||
class ErrorReload extends StatelessWidget {
|
||||
final String text;
|
||||
final Function reload;
|
||||
final Function onTap;
|
||||
|
||||
ErrorReload({@required this.text, @required this.reload});
|
||||
ErrorReload({@required this.text, @required this.onTap});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
@ -32,7 +32,7 @@ class ErrorReload extends StatelessWidget {
|
||||
'Reload',
|
||||
style: TextStyle(fontSize: 20, color: Colors.blueAccent),
|
||||
),
|
||||
beforeRedirect: reload,
|
||||
onTap: onTap,
|
||||
material: false,
|
||||
),
|
||||
],
|
||||
|
@ -7,7 +7,7 @@ class Link extends StatelessWidget {
|
||||
final Widget child;
|
||||
final String url;
|
||||
final WidgetBuilder screenBuilder;
|
||||
final Function beforeRedirect;
|
||||
final Function onTap;
|
||||
final Color bgColor;
|
||||
final bool material;
|
||||
final bool fullscreenDialog;
|
||||
@ -17,7 +17,7 @@ class Link extends StatelessWidget {
|
||||
this.child,
|
||||
this.url,
|
||||
this.screenBuilder,
|
||||
this.beforeRedirect,
|
||||
this.onTap,
|
||||
this.bgColor,
|
||||
this.material = true,
|
||||
this.fullscreenDialog = false,
|
||||
@ -26,8 +26,8 @@ class Link extends StatelessWidget {
|
||||
assert(screenBuilder == null || url == null);
|
||||
|
||||
void _onTap(BuildContext context, int theme) {
|
||||
if (beforeRedirect != null) {
|
||||
beforeRedirect();
|
||||
if (onTap != null) {
|
||||
onTap();
|
||||
}
|
||||
|
||||
if (screenBuilder != null) {
|
||||
|
@ -150,7 +150,7 @@ class _NotificationItemState extends State<NotificationItem> {
|
||||
Widget build(BuildContext context) {
|
||||
return Link(
|
||||
screenBuilder: _buildRoute,
|
||||
beforeRedirect: _markAsRead,
|
||||
onTap: _markAsRead,
|
||||
child: Opacity(
|
||||
opacity: payload.unread ? 1 : 0.5,
|
||||
child: Container(
|
||||
@ -168,7 +168,7 @@ class _NotificationItemState extends State<NotificationItem> {
|
||||
style: TextStyle(fontSize: 15),
|
||||
),
|
||||
),
|
||||
Link(child: _buildCheckIcon(), beforeRedirect: _markAsRead),
|
||||
Link(child: _buildCheckIcon(), onTap: _markAsRead),
|
||||
],
|
||||
),
|
||||
),
|
||||
|
@ -61,7 +61,7 @@ class TableView extends StatelessWidget {
|
||||
}
|
||||
|
||||
return Link(
|
||||
beforeRedirect: item.onTap,
|
||||
onTap: item.onTap,
|
||||
screenBuilder: item.screenBuilder,
|
||||
child: Container(
|
||||
decoration: BoxDecoration(
|
||||
|
Loading…
x
Reference in New Issue
Block a user