feat: Settings for stories

This commit is contained in:
Christian Pauly 2021-12-25 10:20:18 +01:00
parent bfdef63fdf
commit 39e23114c1
6 changed files with 184 additions and 41 deletions

View File

@ -229,7 +229,7 @@
isa = PBXProject;
attributes = {
LastSwiftUpdateCheck = 1240;
LastUpgradeCheck = 1020;
LastUpgradeCheck = 1300;
ORGANIZATIONNAME = "";
TargetAttributes = {
97C146ED1CF9000F007C117D = {

View File

@ -1,6 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<Scheme
LastUpgradeVersion = "1020"
LastUpgradeVersion = "1300"
version = "1.3">
<BuildAction
parallelizeBuildables = "YES"

View File

@ -28,6 +28,7 @@ import 'package:fluffychat/pages/settings_ignore_list/settings_ignore_list.dart'
import 'package:fluffychat/pages/settings_multiple_emotes/settings_multiple_emotes.dart';
import 'package:fluffychat/pages/settings_notifications/settings_notifications.dart';
import 'package:fluffychat/pages/settings_security/settings_security.dart';
import 'package:fluffychat/pages/settings_stories/settings_stories.dart';
import 'package:fluffychat/pages/settings_style/settings_style.dart';
import 'package:fluffychat/pages/sign_up/signup.dart';
import 'package:fluffychat/pages/story/story_page.dart';
@ -334,6 +335,11 @@ class AppRoutes {
widget: const SettingsSecurity(),
buildTransition: _dynamicTransition,
stackedRoutes: [
VWidget(
path: 'stories',
widget: const SettingsStories(),
buildTransition: _dynamicTransition,
),
VWidget(
path: 'ignorelist',
widget: const SettingsIgnoreList(),

View File

@ -24,6 +24,11 @@ class SettingsSecurityView extends StatelessWidget {
withScrolling: true,
child: Column(
children: [
ListTile(
trailing: const Icon(Icons.panorama_fish_eye),
title: Text(L10n.of(context).whoCanSeeMyStories),
onTap: () => VRouter.of(context).to('stories'),
),
ListTile(
trailing: const Icon(Icons.close),
title: Text(L10n.of(context).ignoredUsers),
@ -61,36 +66,24 @@ class SettingsSecurityView extends StatelessWidget {
),
trailing: const Icon(Icons.vpn_key_outlined),
),
ListTile(
title: Text(L10n.of(context).crossSigningEnabled),
trailing:
Matrix.of(context).client.encryption.crossSigning.enabled
? const Icon(Icons.check, color: Colors.green)
: const Icon(Icons.error, color: Colors.red),
onTap:
Matrix.of(context).client.encryption.crossSigning.enabled
? null
: () => controller.showBootstrapDialog(context),
),
ListTile(
title: Text(L10n.of(context).onlineKeyBackupEnabled),
trailing:
Matrix.of(context).client.encryption.keyManager.enabled
? const Icon(Icons.check, color: Colors.green)
: const Icon(Icons.error, color: Colors.red),
onTap: Matrix.of(context).client.encryption.keyManager.enabled
? null
: () => controller.showBootstrapDialog(context),
),
ListTile(
title: const Text('Session verified'),
trailing: !Matrix.of(context).client.isUnknownSession
? const Icon(Icons.check, color: Colors.green)
: const Icon(Icons.error, color: Colors.red),
onTap: !Matrix.of(context).client.isUnknownSession
? null
: () => controller.showBootstrapDialog(context),
),
if (!Matrix.of(context).client.encryption.crossSigning.enabled)
ListTile(
title: Text(L10n.of(context).crossSigningEnabled),
trailing: const Icon(Icons.error, color: Colors.red),
onTap: () => controller.showBootstrapDialog(context),
),
if (!Matrix.of(context).client.encryption.keyManager.enabled)
ListTile(
title: Text(L10n.of(context).onlineKeyBackupEnabled),
trailing: const Icon(Icons.error, color: Colors.red),
onTap: () => controller.showBootstrapDialog(context),
),
if (Matrix.of(context).client.isUnknownSession)
ListTile(
title: const Text('Session verified'),
trailing: const Icon(Icons.error, color: Colors.red),
onTap: () => controller.showBootstrapDialog(context),
),
FutureBuilder(
future: () async {
return (await Matrix.of(context)
@ -104,15 +97,13 @@ class SettingsSecurityView extends StatelessWidget {
.crossSigning
.isCached());
}(),
builder: (context, snapshot) => ListTile(
title: Text(L10n.of(context).keysCached),
trailing: snapshot.data == true
? const Icon(Icons.check, color: Colors.green)
: const Icon(Icons.error, color: Colors.red),
onTap: snapshot.data == true
? null
: () => controller.showBootstrapDialog(context),
),
builder: (context, snapshot) => snapshot.data == true
? Container()
: ListTile(
title: Text(L10n.of(context).keysCached),
trailing: const Icon(Icons.error, color: Colors.red),
onTap: () => controller.showBootstrapDialog(context),
),
),
},
],

View File

@ -0,0 +1,97 @@
//@dart=2.12
import 'package:flutter/material.dart';
import 'package:future_loading_dialog/future_loading_dialog.dart';
import 'package:matrix/matrix.dart';
import 'package:fluffychat/pages/settings_stories/settings_stories_view.dart';
import 'package:fluffychat/widgets/matrix.dart';
import '../../utils/matrix_sdk_extensions.dart/client_stories_extension.dart';
class SettingsStories extends StatefulWidget {
const SettingsStories({Key? key}) : super(key: key);
@override
SettingsStoriesController createState() => SettingsStoriesController();
}
class SettingsStoriesController extends State<SettingsStories> {
final Map<User, bool> users = {};
Room? _storiesRoom;
Future<void>? loadUsers;
bool noStoriesRoom = false;
Future<void> toggleUser(User user) async {
final room = _storiesRoom;
if (room == null) return;
if (users[user] ?? false) {
// Kick user from stories room and add to block list
final blockList = room.client.storiesBlockList;
blockList.add(user.id);
await showFutureLoadingDialog(
context: context,
future: () async {
await user.kick();
await room.client.setStoriesBlockList(blockList.toSet().toList());
setState(() {
users[user] = false;
});
});
return;
}
// Invite user to stories room and remove from block list
final blockList = room.client.storiesBlockList;
blockList.remove(user.id);
await showFutureLoadingDialog(
context: context,
future: () async {
await room.client.setStoriesBlockList(blockList);
await room.invite(user.id);
setState(() {
users[user] = true;
});
});
return;
}
Future<void> _loadUsers() async {
final room =
_storiesRoom = await Matrix.of(context).client.getStoriesRoom(context);
if (room == null) {
noStoriesRoom = true;
return;
}
final users = await room.requestParticipants();
users.removeWhere((u) => u.id == room.client.userID);
final contacts = Matrix.of(context)
.client
.contacts
.where((contact) => !users.any((u) => u.id == contact.id));
for (final user in contacts) {
this.users[user] = false;
}
for (final user in users) {
this.users[user] = true;
}
return;
}
@override
void initState() {
super.initState();
WidgetsBinding.instance?.addPostFrameCallback((_) {
setState(() {
loadUsers = _loadUsers();
});
});
}
@override
Widget build(BuildContext context) => SettingsStoriesView(this);
}

View File

@ -0,0 +1,49 @@
//@dart=2.12
import 'package:flutter/material.dart';
import 'package:fluffychat/pages/settings_stories/settings_stories.dart';
import 'package:fluffychat/utils/localized_exception_extension.dart';
import 'package:fluffychat/widgets/avatar.dart';
class SettingsStoriesView extends StatelessWidget {
final SettingsStoriesController controller;
const SettingsStoriesView(this.controller, {Key? key}) : super(key: key);
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(),
body: FutureBuilder(
future: controller.loadUsers,
builder: (context, snapshot) {
final error = snapshot.error;
if (error != null) {
return Center(child: Text(error.toLocalizedString(context)));
}
if (snapshot.connectionState != ConnectionState.done) {
return const Center(
child: CircularProgressIndicator.adaptive(
strokeWidth: 2,
));
}
return ListView.builder(
itemCount: controller.users.length,
itemBuilder: (context, i) {
final user = controller.users.keys.toList()[i];
return SwitchListTile.adaptive(
value: controller.users[user] ?? false,
onChanged: (_) => controller.toggleUser(user),
secondary: Avatar(
mxContent: user.avatarUrl,
name: user.calcDisplayname(),
),
title: Text(user.calcDisplayname()),
);
},
);
},
),
);
}
}