mirror of
https://gitlab.com/famedly/fluffychat.git
synced 2025-10-15 20:07:25 +02:00
feat: Add account bundles
This commit is contained in:
parent
0e914be5b6
commit
31815a2fc2
@ -19,6 +19,7 @@ import 'package:uni_links/uni_links.dart';
|
|||||||
import 'package:vrouter/vrouter.dart';
|
import 'package:vrouter/vrouter.dart';
|
||||||
import '../main.dart';
|
import '../main.dart';
|
||||||
import '../widgets/matrix.dart';
|
import '../widgets/matrix.dart';
|
||||||
|
import '../../utils/account_bundles.dart';
|
||||||
import '../utils/matrix_sdk_extensions.dart/matrix_file_extension.dart';
|
import '../utils/matrix_sdk_extensions.dart/matrix_file_extension.dart';
|
||||||
import '../utils/url_launcher.dart';
|
import '../utils/url_launcher.dart';
|
||||||
import 'package:flutter_gen/gen_l10n/l10n.dart';
|
import 'package:flutter_gen/gen_l10n/l10n.dart';
|
||||||
@ -416,6 +417,61 @@ class ChatListController extends State<ChatList> {
|
|||||||
i - (Matrix.of(context).hasComplexBundles ? 1 : 0);
|
i - (Matrix.of(context).hasComplexBundles ? 1 : 0);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
void setActiveBundle(String bundle) => setState(() {
|
||||||
|
_activeSpaceId = null;
|
||||||
|
selectedRoomIds.clear();
|
||||||
|
Matrix.of(context).activeBundle = bundle;
|
||||||
|
});
|
||||||
|
|
||||||
|
void editBundlesForAccount(String userId) async {
|
||||||
|
final client = Matrix.of(context)
|
||||||
|
.widget
|
||||||
|
.clients[Matrix.of(context).getClientIndexByMatrixId(userId)];
|
||||||
|
final action = await showConfirmationDialog<EditBundleAction>(
|
||||||
|
context: context,
|
||||||
|
title: 'Edit bundles for this account',
|
||||||
|
actions: [
|
||||||
|
AlertDialogAction(
|
||||||
|
key: EditBundleAction.addToBundle,
|
||||||
|
label: 'Add to bundle',
|
||||||
|
),
|
||||||
|
if (Matrix.of(context).activeBundle != null)
|
||||||
|
AlertDialogAction(
|
||||||
|
key: EditBundleAction.removeFromBundle,
|
||||||
|
label: 'Remove from this bundle',
|
||||||
|
),
|
||||||
|
],
|
||||||
|
);
|
||||||
|
if (action == null) return;
|
||||||
|
switch (action) {
|
||||||
|
case EditBundleAction.addToBundle:
|
||||||
|
final bundle = await showTextInputDialog(
|
||||||
|
context: context,
|
||||||
|
title: 'Bundle name',
|
||||||
|
textFields: [DialogTextField(hintText: 'Bundle name')]);
|
||||||
|
if (bundle.isEmpty && bundle.single.isEmpty) return;
|
||||||
|
await showFutureLoadingDialog(
|
||||||
|
context: context,
|
||||||
|
future: () => client.setAccountBundle(bundle.single),
|
||||||
|
);
|
||||||
|
break;
|
||||||
|
case EditBundleAction.removeFromBundle:
|
||||||
|
await showFutureLoadingDialog(
|
||||||
|
context: context,
|
||||||
|
future: () =>
|
||||||
|
client.removeFromAccountBundle(Matrix.of(context).activeBundle),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void resetActiveBundle() {
|
||||||
|
WidgetsBinding.instance.addPostFrameCallback((timeStamp) {
|
||||||
|
setState(() {
|
||||||
|
Matrix.of(context).activeBundle = null;
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
Matrix.of(context).navigatorContext = context;
|
Matrix.of(context).navigatorContext = context;
|
||||||
@ -431,3 +487,5 @@ class ChatListController extends State<ChatList> {
|
|||||||
return ChatListView(this);
|
return ChatListView(this);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
enum EditBundleAction { addToBundle, removeFromBundle }
|
||||||
|
@ -1,6 +1,8 @@
|
|||||||
import 'dart:math';
|
import 'dart:math';
|
||||||
|
import 'package:async/async.dart';
|
||||||
|
|
||||||
import 'package:fluffychat/widgets/avatar.dart';
|
import 'package:fluffychat/widgets/avatar.dart';
|
||||||
|
import 'package:flutter/widgets.dart';
|
||||||
import 'package:matrix/matrix.dart';
|
import 'package:matrix/matrix.dart';
|
||||||
import 'package:fluffychat/pages/chat_list.dart';
|
import 'package:fluffychat/pages/chat_list.dart';
|
||||||
import 'package:fluffychat/widgets/connection_status_header.dart';
|
import 'package:fluffychat/widgets/connection_status_header.dart';
|
||||||
@ -23,18 +25,30 @@ class ChatListView extends StatelessWidget {
|
|||||||
List<BottomNavigationBarItem> getBottomBarItems(BuildContext context) {
|
List<BottomNavigationBarItem> getBottomBarItems(BuildContext context) {
|
||||||
final displayClients = Matrix.of(context).hasComplexBundles
|
final displayClients = Matrix.of(context).hasComplexBundles
|
||||||
? Matrix.of(context).accountBundles[Matrix.of(context).activeBundle ??
|
? Matrix.of(context).accountBundles[Matrix.of(context).activeBundle ??
|
||||||
Matrix.of(context).client.accountBundles.first.name]
|
Matrix.of(context).client.accountBundles.first.name] ??
|
||||||
|
[]
|
||||||
: Matrix.of(context).widget.clients;
|
: Matrix.of(context).widget.clients;
|
||||||
|
if (displayClients.isEmpty) {
|
||||||
|
displayClients.addAll(Matrix.of(context).widget.clients);
|
||||||
|
controller.resetActiveBundle();
|
||||||
|
}
|
||||||
final items = displayClients.map((client) {
|
final items = displayClients.map((client) {
|
||||||
return BottomNavigationBarItem(
|
return BottomNavigationBarItem(
|
||||||
label: client.userID,
|
label: client.userID,
|
||||||
icon: FutureBuilder<Profile>(
|
icon: FutureBuilder<Profile>(
|
||||||
future: client.ownProfile,
|
future: client.ownProfile,
|
||||||
builder: (context, snapshot) {
|
builder: (context, snapshot) {
|
||||||
return Avatar(
|
return InkWell(
|
||||||
|
borderRadius: BorderRadius.circular(32),
|
||||||
|
onTap: () => controller.setActiveClient(
|
||||||
|
Matrix.of(context).getClientIndexByMatrixId(client.userID)),
|
||||||
|
onLongPress: () =>
|
||||||
|
controller.editBundlesForAccount(client.userID),
|
||||||
|
child: Avatar(
|
||||||
snapshot.data?.avatarUrl,
|
snapshot.data?.avatarUrl,
|
||||||
snapshot.data?.displayName ?? client.userID.localpart,
|
snapshot.data?.displayName ?? client.userID.localpart,
|
||||||
size: 32,
|
size: 32,
|
||||||
|
),
|
||||||
);
|
);
|
||||||
}),
|
}),
|
||||||
);
|
);
|
||||||
@ -50,11 +64,13 @@ class ChatListView extends StatelessWidget {
|
|||||||
Icons.menu,
|
Icons.menu,
|
||||||
color: Theme.of(context).textTheme.bodyText1.color,
|
color: Theme.of(context).textTheme.bodyText1.color,
|
||||||
),
|
),
|
||||||
|
onSelected: controller.setActiveBundle,
|
||||||
itemBuilder: (context) => Matrix.of(context)
|
itemBuilder: (context) => Matrix.of(context)
|
||||||
.accountBundles
|
.accountBundles
|
||||||
.keys
|
.keys
|
||||||
.map(
|
.map(
|
||||||
(bundle) => PopupMenuItem(
|
(bundle) => PopupMenuItem(
|
||||||
|
value: bundle,
|
||||||
child: Text(bundle),
|
child: Text(bundle),
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
@ -264,7 +280,15 @@ class ChatListView extends StatelessWidget {
|
|||||||
)
|
)
|
||||||
: null,
|
: null,
|
||||||
bottomNavigationBar: Matrix.of(context).isMultiAccount
|
bottomNavigationBar: Matrix.of(context).isMultiAccount
|
||||||
? SingleChildScrollView(
|
? StreamBuilder(
|
||||||
|
stream: StreamGroup.merge(Matrix.of(context)
|
||||||
|
.widget
|
||||||
|
.clients
|
||||||
|
.map((client) => client.onSync.stream.where((s) =>
|
||||||
|
s.accountData != null &&
|
||||||
|
s.accountData
|
||||||
|
.any((e) => e.type == accountBundlesType)))),
|
||||||
|
builder: (context, _) => SingleChildScrollView(
|
||||||
scrollDirection: Axis.horizontal,
|
scrollDirection: Axis.horizontal,
|
||||||
child: SizedBox(
|
child: SizedBox(
|
||||||
width: max(
|
width: max(
|
||||||
@ -282,6 +306,7 @@ class ChatListView extends StatelessWidget {
|
|||||||
items: getBottomBarItems(context),
|
items: getBottomBarItems(context),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
),
|
||||||
)
|
)
|
||||||
: null,
|
: null,
|
||||||
drawer: controller.spaces.isEmpty
|
drawer: controller.spaces.isEmpty
|
||||||
|
@ -43,13 +43,13 @@ class AccountBundle {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
const _accountBundlesType = 'im.fluffychat.account_bundles';
|
const accountBundlesType = 'im.fluffychat.account_bundles';
|
||||||
|
|
||||||
extension AccountBundlesExtension on Client {
|
extension AccountBundlesExtension on Client {
|
||||||
List<AccountBundle> get accountBundles {
|
List<AccountBundle> get accountBundles {
|
||||||
List<AccountBundle> ret;
|
List<AccountBundle> ret;
|
||||||
if (accountData.containsKey(_accountBundlesType)) {
|
if (accountData.containsKey(accountBundlesType)) {
|
||||||
ret = AccountBundles.fromJson(accountData[_accountBundlesType].content)
|
ret = AccountBundles.fromJson(accountData[accountBundlesType].content)
|
||||||
.bundles;
|
.bundles;
|
||||||
}
|
}
|
||||||
ret ??= [];
|
ret ??= [];
|
||||||
@ -63,9 +63,10 @@ extension AccountBundlesExtension on Client {
|
|||||||
}
|
}
|
||||||
|
|
||||||
Future<void> setAccountBundle(String name, [int priority]) async {
|
Future<void> setAccountBundle(String name, [int priority]) async {
|
||||||
final data = AccountBundles.fromJson(
|
final data =
|
||||||
accountData[_accountBundlesType]?.content ?? {});
|
AccountBundles.fromJson(accountData[accountBundlesType]?.content ?? {});
|
||||||
var foundBundle = false;
|
var foundBundle = false;
|
||||||
|
data.bundles ??= [];
|
||||||
for (final bundle in data.bundles) {
|
for (final bundle in data.bundles) {
|
||||||
if (bundle.name == name) {
|
if (bundle.name == name) {
|
||||||
bundle.priority = priority;
|
bundle.priority = priority;
|
||||||
@ -76,22 +77,23 @@ extension AccountBundlesExtension on Client {
|
|||||||
if (!foundBundle) {
|
if (!foundBundle) {
|
||||||
data.bundles.add(AccountBundle(name: name, priority: priority));
|
data.bundles.add(AccountBundle(name: name, priority: priority));
|
||||||
}
|
}
|
||||||
await setAccountData(userID, _accountBundlesType, data.toJson());
|
await setAccountData(userID, accountBundlesType, data.toJson());
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<void> removeFromAccountBundle(String name) async {
|
Future<void> removeFromAccountBundle(String name) async {
|
||||||
if (!accountData.containsKey(_accountBundlesType)) {
|
if (!accountData.containsKey(accountBundlesType)) {
|
||||||
return; // nothing to do
|
return; // nothing to do
|
||||||
}
|
}
|
||||||
final data =
|
final data =
|
||||||
AccountBundles.fromJson(accountData[_accountBundlesType].content);
|
AccountBundles.fromJson(accountData[accountBundlesType].content);
|
||||||
|
if (data.bundles == null) return;
|
||||||
data.bundles.removeWhere((b) => b.name == name);
|
data.bundles.removeWhere((b) => b.name == name);
|
||||||
await setAccountData(userID, _accountBundlesType, data.toJson());
|
await setAccountData(userID, accountBundlesType, data.toJson());
|
||||||
}
|
}
|
||||||
|
|
||||||
String get sendPrefix {
|
String get sendPrefix {
|
||||||
final data = AccountBundles.fromJson(
|
final data =
|
||||||
accountData[_accountBundlesType]?.content ?? {});
|
AccountBundles.fromJson(accountData[accountBundlesType]?.content ?? {});
|
||||||
return data.prefix;
|
return data.prefix;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -70,6 +70,9 @@ class MatrixState extends State<Matrix> with WidgetsBindingObserver {
|
|||||||
|
|
||||||
bool get isMultiAccount => widget.clients.length > 1;
|
bool get isMultiAccount => widget.clients.length > 1;
|
||||||
|
|
||||||
|
int getClientIndexByMatrixId(String matrixId) =>
|
||||||
|
widget.clients.indexWhere((client) => client.userID == matrixId);
|
||||||
|
|
||||||
int get _safeActiveClient {
|
int get _safeActiveClient {
|
||||||
if (activeClient < 0 || activeClient >= widget.clients.length) {
|
if (activeClient < 0 || activeClient >= widget.clients.length) {
|
||||||
return 0;
|
return 0;
|
||||||
|
Loading…
x
Reference in New Issue
Block a user