refactor for multiple accounts
This commit is contained in:
parent
495dc1c29a
commit
43b5908488
|
@ -28,7 +28,7 @@ class App {
|
|||
redirectUri: json["redirect_uri"].toString(),
|
||||
clientId: json["client_id"].toString(),
|
||||
clientSecret: json["client_secret"].toString());
|
||||
global.settings!.saveApp(app);
|
||||
global.settings!.identities[global.settings!.activeIdentity]!.saveApp(app);
|
||||
return app;
|
||||
}
|
||||
}
|
||||
|
@ -37,7 +37,8 @@ Response readAuthcode(Request request) {
|
|||
Map<String, String> params = request.url.queryParameters;
|
||||
if (params.containsKey("code") && params["code"] != null) {
|
||||
String code = params["code"].toString();
|
||||
global.settings!.saveAuthCode(code);
|
||||
global.settings!.identities[global.settings!.activeIdentity]!
|
||||
.saveAuthCode(code);
|
||||
}
|
||||
return Response(308,
|
||||
headers: {"Content-Type": "text/html; charset=UTF-8"},
|
||||
|
@ -53,7 +54,8 @@ Future<int> handleFullOauth() async {
|
|||
return response.statusCode;
|
||||
}
|
||||
|
||||
await global.settings!.saveAuthCode("");
|
||||
await global.settings!.identities[global.settings!.activeIdentity]!
|
||||
.saveAuthCode("");
|
||||
var handler = const Pipeline().addHandler(readAuthcode);
|
||||
var server = await shelf_io.serve(handler, 'localhost', 1312);
|
||||
await pollCode();
|
||||
|
@ -69,13 +71,15 @@ Future<String> pollCode() async {
|
|||
String code = "";
|
||||
while (code == "") {
|
||||
await Future.delayed(const Duration(seconds: 3));
|
||||
code = global.settings!.authCode;
|
||||
code =
|
||||
global.settings!.identities[global.settings!.activeIdentity]!.authCode;
|
||||
}
|
||||
return code;
|
||||
}
|
||||
|
||||
Future<http.Response> doOauthFlow() async {
|
||||
String url = global.settings!.instanceUrl;
|
||||
String url =
|
||||
global.settings!.identities[global.settings!.activeIdentity]!.instanceUrl;
|
||||
try {
|
||||
http.Response response = await registerApp(url);
|
||||
openBrowserForAuthCode(url, App.fromJson(jsonDecode(response.body)));
|
||||
|
@ -120,10 +124,11 @@ void openBrowserForAuthCode(String baseurl, App app) {
|
|||
}
|
||||
|
||||
Future<int> refreshToken() async {
|
||||
final authCode = global.settings!.authCode;
|
||||
final appId = global.settings!.clientId;
|
||||
final clientSecret = global.settings!.clientSecret;
|
||||
final baseurl = global.settings!.instanceUrl;
|
||||
final activeId = global.settings!.activeIdentity;
|
||||
final authCode = global.settings!.identities[activeId]!.authCode;
|
||||
final appId = global.settings!.identities[activeId]!.clientId;
|
||||
final clientSecret = global.settings!.identities[activeId]!.clientSecret;
|
||||
final baseurl = global.settings!.identities[activeId]!.instanceUrl;
|
||||
|
||||
Uri url = Uri.https(baseurl, "/oauth/token");
|
||||
final response = await http.post(
|
||||
|
@ -141,7 +146,8 @@ Future<int> refreshToken() async {
|
|||
if (response.statusCode == 200) {
|
||||
final dec = jsonDecode(response.body);
|
||||
final accessToken = dec["access_token"]!;
|
||||
await global.settings!.saveToken(accessToken);
|
||||
await global.settings!.identities[global.settings!.activeIdentity]!
|
||||
.saveToken(accessToken);
|
||||
}
|
||||
return response.statusCode;
|
||||
}
|
||||
|
|
|
@ -0,0 +1 @@
|
|||
import '../../global.dart' as global;
|
|
@ -2,21 +2,71 @@ import 'package:flutter/painting.dart';
|
|||
import 'package:shared_preferences/shared_preferences.dart';
|
||||
import '../business_logic/auth/oauth.dart' as oauth;
|
||||
|
||||
class Settings {
|
||||
class AccountSettings {
|
||||
final String identity;
|
||||
late String instanceUrl;
|
||||
static const String instanceUrlKey = "instance-url";
|
||||
late String authCode;
|
||||
static const String authCodeKey = "authcode";
|
||||
late Locale locale;
|
||||
static const localeKey = "active-locale";
|
||||
late String clientSecret;
|
||||
static const clientSecretKey = "client-secret";
|
||||
late String clientId;
|
||||
static const clientIdKey = "client-id";
|
||||
late String token;
|
||||
static const tokenKey = "access-token";
|
||||
late SharedPreferences prefs;
|
||||
|
||||
AccountSettings._create(this.identity);
|
||||
|
||||
static Future<AccountSettings> create(String identity) async {
|
||||
AccountSettings settings = AccountSettings._create(identity);
|
||||
settings.prefs = await SharedPreferences.getInstance();
|
||||
settings.clientSecret =
|
||||
settings.prefs.getString(settings.identity + clientSecretKey) ?? "";
|
||||
settings.clientId =
|
||||
settings.prefs.getString(settings.identity + clientIdKey) ?? "";
|
||||
settings.token =
|
||||
settings.prefs.getString(settings.identity + tokenKey) ?? "";
|
||||
settings.instanceUrl =
|
||||
settings.prefs.getString(settings.identity + instanceUrlKey) ??
|
||||
"example.com";
|
||||
settings.authCode =
|
||||
settings.prefs.getString(settings.identity + authCodeKey) ?? "";
|
||||
return settings;
|
||||
}
|
||||
|
||||
Future<bool> saveInstanceUrl(String url) async {
|
||||
instanceUrl = url;
|
||||
return await prefs.setString(identity + instanceUrlKey, url);
|
||||
}
|
||||
|
||||
Future<bool> saveAuthCode(String code) async {
|
||||
authCode = code;
|
||||
return await prefs.setString(identity + authCodeKey, code);
|
||||
}
|
||||
|
||||
Future<void> saveApp(oauth.App app) async {
|
||||
clientId = app.clientId;
|
||||
clientSecret = clientSecret;
|
||||
prefs.setString(identity + clientSecretKey, app.clientSecret);
|
||||
prefs.setString(identity + clientIdKey, app.clientId);
|
||||
}
|
||||
|
||||
Future<bool> saveToken(String token) async {
|
||||
this.token = token;
|
||||
return await prefs.setString(identity + tokenKey, token);
|
||||
}
|
||||
}
|
||||
|
||||
class Settings {
|
||||
late Locale locale;
|
||||
static const localeKey = "active-locale";
|
||||
late int batchSize;
|
||||
static const batchSizeKey = "post-batch-size";
|
||||
late Map<String, AccountSettings> identities = {};
|
||||
static const identitiesKey = "identities";
|
||||
late String activeIdentity = "";
|
||||
static const activeIdentityKey = "active-identity";
|
||||
late SharedPreferences prefs;
|
||||
|
||||
Settings._create();
|
||||
|
@ -25,29 +75,31 @@ class Settings {
|
|||
Settings settings = Settings._create();
|
||||
|
||||
settings.prefs = await SharedPreferences.getInstance();
|
||||
settings.instanceUrl =
|
||||
settings.prefs.getString(instanceUrlKey) ?? "example.com";
|
||||
settings.authCode = settings.prefs.getString(authCodeKey) ?? "";
|
||||
settings.locale = Locale(settings.prefs.getString(localeKey) ?? "en");
|
||||
settings.clientSecret = settings.prefs.getString(clientSecretKey) ?? "";
|
||||
settings.clientId = settings.prefs.getString(clientIdKey) ?? "";
|
||||
settings.token = settings.prefs.getString(tokenKey) ?? "";
|
||||
|
||||
settings.batchSize = settings.prefs.getInt(batchSizeKey) ?? 20;
|
||||
if (settings.batchSize < 5) {
|
||||
settings.batchSize = 5;
|
||||
}
|
||||
|
||||
List<String> identityList =
|
||||
settings.prefs.getStringList(identitiesKey) ?? [];
|
||||
settings.identities = {};
|
||||
for (int i = 0; i < identityList.length; i++) {
|
||||
settings.identities.addAll(
|
||||
{identityList[i]: await AccountSettings.create(identityList[i])});
|
||||
}
|
||||
settings.activeIdentity = settings.prefs.getString(activeIdentityKey) ?? "";
|
||||
|
||||
return settings;
|
||||
}
|
||||
|
||||
Future<bool> saveInstanceUrl(String url) async {
|
||||
instanceUrl = url;
|
||||
return await prefs.setString(instanceUrlKey, url);
|
||||
}
|
||||
Future<bool> addNewIdentity(String key) async {
|
||||
List<String> a = identities.keys.toList();
|
||||
a.add(key);
|
||||
identities.addAll({key: await AccountSettings.create(key)});
|
||||
|
||||
Future<bool> saveAuthCode(String code) async {
|
||||
authCode = code;
|
||||
return await prefs.setString(authCodeKey, code);
|
||||
return prefs.setStringList(identitiesKey, a);
|
||||
}
|
||||
|
||||
Future<bool> saveLocale(String locale) async {
|
||||
|
@ -55,16 +107,9 @@ class Settings {
|
|||
return await prefs.setString(localeKey, locale);
|
||||
}
|
||||
|
||||
Future<void> saveApp(oauth.App app) async {
|
||||
clientId = app.clientId;
|
||||
clientSecret = clientSecret;
|
||||
prefs.setString(clientSecretKey, app.clientSecret);
|
||||
prefs.setString(clientIdKey, app.clientId);
|
||||
}
|
||||
|
||||
Future<bool> saveToken(String token) async {
|
||||
this.token = token;
|
||||
return await prefs.setString(tokenKey, token);
|
||||
Future<bool> saveActiveIdentity(String identity) {
|
||||
activeIdentity = identity;
|
||||
return prefs.setString(activeIdentityKey, identity);
|
||||
}
|
||||
|
||||
Future<bool> saveBatchSize(int size) async {
|
||||
|
|
|
@ -61,8 +61,9 @@ class PostModel implements Comparable {
|
|||
}
|
||||
|
||||
Future<ThreadModel> getThread() async {
|
||||
final token = global.settings!.token;
|
||||
final baseUrl = global.settings!.instanceUrl;
|
||||
final activeId = global.settings!.activeIdentity;
|
||||
final token = global.settings!.identities[activeId]!.token;
|
||||
final baseUrl = global.settings!.identities[activeId]!.instanceUrl;
|
||||
Map<String, String> headers = {"Authorization": "Bearer $token"};
|
||||
headers.addAll(global.defaultHeaders);
|
||||
String currentId = reblogId ?? id;
|
||||
|
@ -72,10 +73,9 @@ class PostModel implements Comparable {
|
|||
path: "/api/v1/statuses/$currentId/context",
|
||||
);
|
||||
http.Response response = await http.get(url, headers: headers);
|
||||
if (response.statusCode != 200) {
|
||||
if (response.statusCode != 200 || response.body.isEmpty) {
|
||||
return ThreadModel([this]);
|
||||
}
|
||||
|
||||
final json = jsonDecode(response.body);
|
||||
final List<dynamic> ancestorsJson = json["ancestors"];
|
||||
|
||||
|
@ -98,15 +98,16 @@ class ThreadModel {
|
|||
}
|
||||
|
||||
Future<List<ThreadModel>> getTimelineFromServer(String? index) async {
|
||||
final activeId = global.settings!.activeIdentity;
|
||||
final limit = global.settings!.batchSize;
|
||||
final token = global.settings!.token;
|
||||
final token = global.settings!.identities[activeId]!.token;
|
||||
|
||||
Map<String, String> query = {"limit": limit.toString()};
|
||||
if (index != null) {
|
||||
query.addAll({"max_id": index});
|
||||
}
|
||||
|
||||
final baseUrl = global.settings!.instanceUrl;
|
||||
final baseUrl = global.settings!.identities[activeId]!.instanceUrl;
|
||||
final url = Uri(
|
||||
scheme: "https",
|
||||
host: baseUrl,
|
||||
|
|
|
@ -0,0 +1,6 @@
|
|||
import 'package:web_socket_channel/status.dart' as status;
|
||||
import 'package:web_socket_channel/web_socket_channel.dart';
|
||||
import '../global.dart' as global;
|
||||
|
||||
WebSocketChannel? channel;
|
||||
bool connected = false;
|
|
@ -19,7 +19,7 @@ void main() async {
|
|||
activeLocale = global.settings!.locale;
|
||||
|
||||
// check if all information is available
|
||||
if (global.settings!.authCode == "") {
|
||||
if (global.settings!.identities.isEmpty) {
|
||||
_initRoute = "/login";
|
||||
} else {
|
||||
await oauth.refreshToken();
|
||||
|
|
|
@ -2,6 +2,7 @@ import 'package:flutter/material.dart';
|
|||
import 'package:localization/localization.dart';
|
||||
import '../business_logic/auth/oauth.dart' as oauth;
|
||||
import '../global.dart' as global;
|
||||
import '../business_logic/settings.dart' as settings;
|
||||
|
||||
class Login extends StatefulWidget {
|
||||
const Login({Key? key}) : super(key: key);
|
||||
|
@ -31,7 +32,7 @@ class LoginForm extends StatefulWidget {
|
|||
|
||||
class _LoginFormState extends State<LoginForm> {
|
||||
final formKey = GlobalKey<FormState>();
|
||||
|
||||
String identity = "";
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Form(
|
||||
|
@ -45,7 +46,10 @@ class _LoginFormState extends State<LoginForm> {
|
|||
Text("greeting".i18n(), style: Theme.of(context).textTheme.headline1),
|
||||
TextFormField(
|
||||
onSaved: (value) async {
|
||||
await global.settings!.saveInstanceUrl(value!);
|
||||
await global.settings!.addNewIdentity(identity);
|
||||
await global.settings!.saveActiveIdentity(identity);
|
||||
await global.settings!.identities[identity]!
|
||||
.saveInstanceUrl(identity);
|
||||
},
|
||||
decoration: InputDecoration(
|
||||
labelText: "instance-url".i18n(),
|
||||
|
@ -55,12 +59,22 @@ class _LoginFormState extends State<LoginForm> {
|
|||
),
|
||||
autofocus: true,
|
||||
),
|
||||
TextFormField(
|
||||
onChanged: (value) {
|
||||
identity = value;
|
||||
},
|
||||
),
|
||||
TextButton.icon(
|
||||
onPressed: () {
|
||||
bool isValid = formKey.currentState!.validate();
|
||||
if (!isValid) {
|
||||
ScaffoldMessenger.of(context).showSnackBar(SnackBar(
|
||||
content: Text("login-failed-snackbar-text".i18n())));
|
||||
ScaffoldMessenger.of(context).showSnackBar(
|
||||
SnackBar(
|
||||
content: Text(
|
||||
"login-failed-snackbar-text".i18n(),
|
||||
),
|
||||
),
|
||||
);
|
||||
} else {
|
||||
formKey.currentState?.save();
|
||||
Navigator.push(
|
||||
|
|
|
@ -20,12 +20,9 @@ class LogoutButton extends StatelessWidget {
|
|||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
String url;
|
||||
if (global.settings!.instanceUrl.isEmpty) {
|
||||
url = "no-instance".i18n();
|
||||
} else {
|
||||
url = global.settings!.instanceUrl;
|
||||
}
|
||||
String url = global
|
||||
.settings!.identities[global.settings!.activeIdentity]!.instanceUrl;
|
||||
|
||||
return Row(
|
||||
children: [
|
||||
Text(url),
|
||||
|
@ -41,6 +38,6 @@ class LogoutButton extends StatelessWidget {
|
|||
}
|
||||
|
||||
void logout() async {
|
||||
await global.settings!.saveAuthCode("");
|
||||
//await global.settings!.saveAuthCode("");
|
||||
exit(0);
|
||||
}
|
||||
|
|
|
@ -5,6 +5,7 @@ import 'package:loris/pages/chat/chat.dart';
|
|||
import 'package:loris/pages/notifications/notifications.dart';
|
||||
import 'package:loris/pages/timeline/timeline.dart';
|
||||
import 'package:loris/pages/settings/settings.dart';
|
||||
import '../business_logic/websocket.dart' as websocket;
|
||||
|
||||
class MainScaffold extends StatefulWidget {
|
||||
const MainScaffold({Key? key}) : super(key: key);
|
||||
|
@ -18,6 +19,7 @@ class _MainScaffoldState extends State<MainScaffold> {
|
|||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
// websocket.connect();
|
||||
final screens = [
|
||||
const Timeline(),
|
||||
chat(context),
|
||||
|
|
|
@ -59,7 +59,9 @@ class DisplayName extends StatelessWidget {
|
|||
child: ProfilePic(
|
||||
url: account.avatar,
|
||||
)),
|
||||
const SizedBox(width: 8),
|
||||
const SizedBox(
|
||||
width: 8,
|
||||
),
|
||||
Flexible(
|
||||
child: Column(
|
||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||
|
|
|
@ -114,6 +114,7 @@ ThemeData getTheme(CustomColors colors) {
|
|||
fontWeight: FontWeight.w700,
|
||||
),
|
||||
),
|
||||
tooltipTheme: TooltipThemeData(),
|
||||
);
|
||||
}
|
||||
|
||||
|
|
14
pubspec.lock
14
pubspec.lock
|
@ -43,6 +43,13 @@ packages:
|
|||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "1.16.0"
|
||||
crypto:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: crypto
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "3.0.2"
|
||||
csslib:
|
||||
dependency: transitive
|
||||
description:
|
||||
|
@ -404,6 +411,13 @@ packages:
|
|||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "2.1.2"
|
||||
web_socket_channel:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
name: web_socket_channel
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "2.2.0"
|
||||
win32:
|
||||
dependency: transitive
|
||||
description:
|
||||
|
|
|
@ -43,6 +43,7 @@ dependencies:
|
|||
url_launcher: ^6.1.4
|
||||
shelf: ^1.3.1
|
||||
html: ^0.15.0
|
||||
web_socket_channel: ^2.2.0
|
||||
|
||||
dev_dependencies:
|
||||
flutter_test:
|
||||
|
|
Loading…
Reference in New Issue