removed users from account store and used more utility methods

This commit is contained in:
shilangyu 2020-09-29 23:15:51 +02:00
parent f37f01951f
commit af7cb62fac
7 changed files with 80 additions and 106 deletions

View File

@ -46,7 +46,7 @@ class AddAccountPage extends HookWidget {
builder: (context) => BottomModal(
title: 'select instance',
child: Column(children: [
for (final i in accountsStore.users.keys)
for (final i in accountsStore.instances)
RadioListTile<String>(
value: i,
groupValue: selectedInstance.value,

View File

@ -22,14 +22,12 @@ class CommunitiesTab extends HookWidget {
useValueListenable(filterController);
final accountsStore = useAccountsStore();
final amountOfDisplayInstances = useMemoized(() => accountsStore.users.keys
.where((e) => !accountsStore.isAnonymousFor(e))
.length);
final amountOfDisplayInstances =
useMemoized(() => accountsStore.loggedInInstances.length);
final isCollapsed = useState(List.filled(amountOfDisplayInstances, false));
final instancesSnap = useMemoFuture(() {
final futures = accountsStore.users.keys
.where((e) => !accountsStore.isAnonymousFor(e))
final futures = accountsStore.loggedInInstances
.map(
(instanceUrl) =>
LemmyApi(instanceUrl).v1.getSite().then((e) => e.site),
@ -39,8 +37,7 @@ class CommunitiesTab extends HookWidget {
return Future.wait(futures);
});
final communitiesSnap = useMemoFuture(() {
final futures = accountsStore.users.keys
.where((e) => !accountsStore.isAnonymousFor(e))
final futures = accountsStore.loggedInInstances
.map(
(instanceUrl) => LemmyApi(instanceUrl)
.v1

View File

@ -4,7 +4,6 @@ import 'package:flutter_hooks/flutter_hooks.dart';
import 'package:flutter_mobx/flutter_mobx.dart';
import '../hooks/stores.dart';
import '../util/extensions/api.dart';
import '../util/goto.dart';
import '../widgets/bottom_modal.dart';
import '../widgets/user_profile.dart';
@ -40,8 +39,6 @@ class UserProfileTab extends HookWidget {
);
}
final user = accountsStore.defaultUser;
return Scaffold(
extendBodyBehindAppBar: true,
appBar: AppBar(
@ -54,7 +51,8 @@ class UserProfileTab extends HookWidget {
mainAxisAlignment: MainAxisAlignment.center,
children: [
Text(
'@${user.name}', // TODO: fix overflow issues
// TODO: fix overflow issues
'@${accountsStore.defaultUsername}',
style: theme.primaryTextTheme.headline6,
overflow: TextOverflow.fade,
),
@ -71,37 +69,33 @@ class UserProfileTab extends HookWidget {
builder: (_) {
final userTags = <String>[];
accountsStore.users.forEach((instanceUrl, value) {
accountsStore.tokens.forEach((instanceUrl, value) {
value.forEach((username, _) {
userTags.add('$username@$instanceUrl');
});
});
return Observer(
builder: (ctx) {
final user = accountsStore.defaultUser;
final instanceUrl = user.instanceUrl;
return BottomModal(
title: 'account',
child: Column(
children: [
for (final tag in userTags)
RadioListTile<String>(
value: tag,
title: Text(tag),
groupValue: '${user.name}@$instanceUrl',
onChanged: (selected) {
final userTag = selected.split('@');
accountsStore.setDefaultAccount(
userTag[1], userTag[0]);
Navigator.of(ctx).pop();
},
)
],
),
);
},
builder: (ctx) => BottomModal(
title: 'account',
child: Column(
children: [
for (final tag in userTags)
RadioListTile<String>(
value: tag,
title: Text(tag),
groupValue: '${accountsStore.defaultUsername}'
'@${accountsStore.defaultInstanceUrl}',
onChanged: (selected) {
final userTag = selected.split('@');
accountsStore.setDefaultAccount(
userTag[1], userTag[0]);
Navigator.of(ctx).pop();
},
)
],
),
),
);
},
);
@ -117,8 +111,8 @@ class UserProfileTab extends HookWidget {
],
),
body: UserProfile(
userId: user.id,
instanceUrl: user.instanceUrl,
userId: accountsStore.defaultToken.payload.id,
instanceUrl: accountsStore.defaultInstanceUrl,
),
);
},

View File

@ -169,7 +169,7 @@ class AccountsConfigPage extends HookWidget {
onTap: () => showCupertinoModalPopup(
context: context,
builder: (_) =>
AddAccountPage(instanceUrl: accountsStore.users.keys.last)),
AddAccountPage(instanceUrl: accountsStore.instances.last)),
),
SpeedDialChild(
child: Icon(Icons.dns),
@ -186,7 +186,7 @@ class AccountsConfigPage extends HookWidget {
return ListView(
children: [
if (accountsStore.users.isEmpty)
if (accountsStore.tokens.isEmpty)
Row(
mainAxisAlignment: MainAxisAlignment.center,
children: [
@ -205,7 +205,7 @@ class AccountsConfigPage extends HookWidget {
),
],
),
for (final entry in accountsStore.users.entries) ...[
for (final entry in accountsStore.tokens.entries) ...[
SizedBox(height: 40),
Slidable(
actionPane: SlidableBehindActionPane(),
@ -243,7 +243,7 @@ class AccountsConfigPage extends HookWidget {
decoration: BoxDecoration(color: theme.canvasColor),
child: ListTile(
trailing: username ==
accountsStore.defaultUserFor(entry.key).name
accountsStore.defaultUsernameFor(entry.key)
? Icon(
Icons.check_circle_outline,
color: theme.accentColor,
@ -254,7 +254,6 @@ class AccountsConfigPage extends HookWidget {
accountsStore.setDefaultAccountFor(
entry.key, username);
},
onTap: () {}, // TODO: go to managing account
),
),

View File

@ -16,8 +16,6 @@ abstract class _AccountsStore with Store {
// persistently save settings each time they are changed
_saveReactionDisposer = reaction(
(_) => [
users.forEach((k, submap) =>
MapEntry(k, submap.forEach((k2, v2) => MapEntry(k2, v2)))),
tokens.forEach((k, submap) =>
MapEntry(k, submap.forEach((k2, v2) => MapEntry(k2, v2)))),
_defaultAccount,
@ -29,8 +27,6 @@ abstract class _AccountsStore with Store {
// check if there's a default profile and if not, select one
_pickDefaultsDisposer = reaction(
(_) => [
users.forEach((k, submap) =>
MapEntry(k, submap.forEach((k2, v2) => MapEntry(k2, v2)))),
tokens.forEach((k, submap) =>
MapEntry(k, submap.forEach((k2, v2) => MapEntry(k2, v2)))),
],
@ -45,8 +41,8 @@ abstract class _AccountsStore with Store {
final instance = dft.key;
final username = dft.value;
// if instance or username doesn't exist, remove
if (!users.containsKey(instance) ||
!users[instance].containsKey(username)) {
if (!instances.contains(instance) ||
!tokens[instance].containsKey(username)) {
return instance;
}
}).forEach(_defaultAccounts.remove);
@ -54,19 +50,19 @@ abstract class _AccountsStore with Store {
final instance = _defaultAccount.split('@')[1];
final username = _defaultAccount.split('@')[0];
// if instance or username doesn't exist, remove
if (!users.containsKey(instance) ||
!users[instance].containsKey(username)) {
if (!instances.contains(instance) ||
!tokens[instance].containsKey(username)) {
_defaultAccount = null;
}
}
// set local defaults
for (final instanceUrl in users.keys) {
for (final instanceUrl in instances) {
// if this instance is not in defaults
if (!_defaultAccounts.containsKey(instanceUrl)) {
// select first account in this instance, if any
if (!isAnonymousFor(instanceUrl)) {
setDefaultAccountFor(instanceUrl, users[instanceUrl].keys.first);
setDefaultAccountFor(instanceUrl, tokens[instanceUrl].keys.first);
}
}
}
@ -74,10 +70,10 @@ abstract class _AccountsStore with Store {
// set global default
if (_defaultAccount == null) {
// select first account of first instance
for (final instanceUrl in users.keys) {
for (final instanceUrl in instances) {
// select first account in this instance, if any
if (!isAnonymousFor(instanceUrl)) {
setDefaultAccount(instanceUrl, users[instanceUrl].keys.first);
setDefaultAccount(instanceUrl, tokens[instanceUrl].keys.first);
}
}
}
@ -108,7 +104,6 @@ abstract class _AccountsStore with Store {
);
// set saved settings or create defaults
users = nestedMapsCast('users', (json) => User.fromJson(json));
tokens = nestedMapsCast('tokens', (json) => Jwt(json['raw']));
_defaultAccount = prefs.getString('defaultAccount');
_defaultAccounts = ObservableMap.of(Map.castFrom(
@ -120,16 +115,9 @@ abstract class _AccountsStore with Store {
await prefs.setString('defaultAccount', _defaultAccount);
await prefs.setString('defaultAccounts', jsonEncode(_defaultAccounts));
await prefs.setString('users', jsonEncode(users));
await prefs.setString('tokens', jsonEncode(tokens));
}
/// if path to tokens map exists, it exists for users as well
/// `users['instanceUrl']['username']`
@observable
ObservableMap<String, ObservableMap<String, User>> users;
/// if path to users map exists, it exists for tokens as well
/// `tokens['instanceUrl']['username']`
@observable
ObservableMap<String, ObservableMap<String, Jwt>> tokens;
@ -145,15 +133,31 @@ abstract class _AccountsStore with Store {
String _defaultAccount;
@computed
User get defaultUser {
String get defaultUsername {
if (_defaultAccount == null) {
return null;
}
final userTag = _defaultAccount.split('@');
return users[userTag[1]][userTag[0]];
return _defaultAccount.split('@')[0];
}
@computed
String get defaultInstanceUrl {
if (_defaultAccount == null) {
return null;
}
return _defaultAccount.split('@')[1];
}
String defaultUsernameFor(String instanceUrl) => Computed(() {
if (isAnonymousFor(instanceUrl)) {
return null;
}
return _defaultAccounts[instanceUrl];
}).value;
@computed
Jwt get defaultToken {
if (_defaultAccount == null) {
@ -164,14 +168,6 @@ abstract class _AccountsStore with Store {
return tokens[userTag[1]][userTag[0]];
}
User defaultUserFor(String instanceUrl) => Computed(() {
if (isAnonymousFor(instanceUrl)) {
return null;
}
return users[instanceUrl][_defaultAccounts[instanceUrl]];
}).value;
Jwt defaultTokenFor(String instanceUrl) => Computed(() {
if (isAnonymousFor(instanceUrl)) {
return null;
@ -197,14 +193,14 @@ abstract class _AccountsStore with Store {
return true;
}
return users[instanceUrl].isEmpty;
return tokens[instanceUrl].isEmpty;
}).value;
@computed
bool get hasNoAccount => loggedInInstances.isEmpty;
@computed
Iterable<String> get instances => users.keys;
Iterable<String> get instances => tokens.keys;
@computed
Iterable<String> get loggedInInstances =>
@ -221,7 +217,7 @@ abstract class _AccountsStore with Store {
String usernameOrEmail,
String password,
) async {
if (!users.containsKey(instanceUrl)) {
if (!instances.contains(instanceUrl)) {
throw Exception('No such instance was added');
}
@ -234,7 +230,6 @@ abstract class _AccountsStore with Store {
final userData =
await lemmy.getSite(auth: token.raw).then((value) => value.myUser);
users[instanceUrl][userData.name] = userData;
tokens[instanceUrl][userData.name] = token;
}
@ -245,7 +240,7 @@ abstract class _AccountsStore with Store {
String instanceUrl, {
bool assumeValid = false,
}) async {
if (users.containsKey(instanceUrl)) {
if (instances.contains(instanceUrl)) {
throw Exception('This instance has already been added');
}
@ -258,19 +253,16 @@ abstract class _AccountsStore with Store {
}
}
users[instanceUrl] = ObservableMap();
tokens[instanceUrl] = ObservableMap();
}
@action
void removeInstance(String instanceUrl) {
users.remove(instanceUrl);
tokens.remove(instanceUrl);
}
@action
void removeAccount(String instanceUrl, String username) {
users[instanceUrl].remove(username);
tokens[instanceUrl].remove(username);
}
}

View File

@ -9,13 +9,20 @@ part of 'accounts_store.dart';
// ignore_for_file: non_constant_identifier_names, unnecessary_brace_in_string_interps, unnecessary_lambdas, prefer_expression_function_bodies, lines_longer_than_80_chars, avoid_as, avoid_annotating_with_dynamic
mixin _$AccountsStore on _AccountsStore, Store {
Computed<User> _$defaultUserComputed;
Computed<String> _$defaultUsernameComputed;
@override
User get defaultUser =>
(_$defaultUserComputed ??= Computed<User>(() => super.defaultUser,
name: '_AccountsStore.defaultUser'))
.value;
String get defaultUsername => (_$defaultUsernameComputed ??= Computed<String>(
() => super.defaultUsername,
name: '_AccountsStore.defaultUsername'))
.value;
Computed<String> _$defaultInstanceUrlComputed;
@override
String get defaultInstanceUrl => (_$defaultInstanceUrlComputed ??=
Computed<String>(() => super.defaultInstanceUrl,
name: '_AccountsStore.defaultInstanceUrl'))
.value;
Computed<Jwt> _$defaultTokenComputed;
@override
@ -45,21 +52,6 @@ mixin _$AccountsStore on _AccountsStore, Store {
name: '_AccountsStore.loggedInInstances'))
.value;
final _$usersAtom = Atom(name: '_AccountsStore.users');
@override
ObservableMap<String, ObservableMap<String, User>> get users {
_$usersAtom.reportRead();
return super.users;
}
@override
set users(ObservableMap<String, ObservableMap<String, User>> value) {
_$usersAtom.reportWrite(value, super.users, () {
super.users = value;
});
}
final _$tokensAtom = Atom(name: '_AccountsStore.tokens');
@override
@ -183,9 +175,9 @@ mixin _$AccountsStore on _AccountsStore, Store {
@override
String toString() {
return '''
users: ${users},
tokens: ${tokens},
defaultUser: ${defaultUser},
defaultUsername: ${defaultUsername},
defaultInstanceUrl: ${defaultInstanceUrl},
defaultToken: ${defaultToken},
hasNoAccount: ${hasNoAccount},
instances: ${instances},

View File

@ -19,7 +19,7 @@ Future<void> linkLauncher({
goTo(context, (c) => builder());
}
final instances = context.read<AccountsStore>().users.keys.toList();
final instances = context.read<AccountsStore>().instances;
final chonks = url.split('/');
if (chonks.length == 1) return openInBrowser(url);