refactor: Replace stories feature with presence status msg
This commit is contained in:
parent
9c24547b7f
commit
895de76e70
21 changed files with 364 additions and 2386 deletions
|
|
@ -31,7 +31,6 @@ import 'package:http/http.dart' as http;
|
|||
import 'package:matrix/matrix.dart';
|
||||
import 'package:unifiedpush/unifiedpush.dart';
|
||||
|
||||
import 'package:fluffychat/utils/matrix_sdk_extensions/client_stories_extension.dart';
|
||||
import 'package:fluffychat/utils/push_helper.dart';
|
||||
import 'package:fluffychat/widgets/fluffy_chat_app.dart';
|
||||
import '../config/app_config.dart';
|
||||
|
|
@ -314,14 +313,7 @@ class BackgroundPush {
|
|||
}
|
||||
await client.roomsLoading;
|
||||
await client.accountDataLoading;
|
||||
final isStory = client
|
||||
.getRoomById(roomId)
|
||||
?.getState(EventTypes.RoomCreate)
|
||||
?.content
|
||||
.tryGet<String>('type') ==
|
||||
ClientStoriesExtension.storiesRoomType;
|
||||
FluffyChatApp.router
|
||||
.go('/${isStory ? 'rooms/stories' : 'rooms'}/$roomId');
|
||||
FluffyChatApp.router.go('/rooms/$roomId');
|
||||
} catch (e, s) {
|
||||
Logs().e('[Push] Failed to open room', e, s);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -111,8 +111,6 @@ abstract class ClientManager {
|
|||
importantStateEvents: <String>{
|
||||
// To make room emotes work
|
||||
'im.ponies.room_emotes',
|
||||
// To check which story room we can post in
|
||||
EventTypes.RoomPowerLevels,
|
||||
},
|
||||
logLevel: kReleaseMode ? Level.warning : Level.verbose,
|
||||
databaseBuilder: flutterMatrixSdkDatabaseBuilder,
|
||||
|
|
|
|||
|
|
@ -1,125 +0,0 @@
|
|||
import 'package:flutter/cupertino.dart';
|
||||
|
||||
import 'package:adaptive_dialog/adaptive_dialog.dart';
|
||||
import 'package:flutter_gen/gen_l10n/l10n.dart';
|
||||
import 'package:matrix/matrix.dart';
|
||||
|
||||
import 'package:fluffychat/utils/matrix_sdk_extensions/matrix_locals.dart';
|
||||
|
||||
extension ClientStoriesExtension on Client {
|
||||
static const String storiesRoomType = 'msc3588.stories.stories-room';
|
||||
static const String storiesBlockListType = 'msc3588.stories.block-list';
|
||||
|
||||
static const int lifeTimeInHours = 24;
|
||||
static const int maxPostsPerStory = 20;
|
||||
|
||||
List<User> get contacts => rooms
|
||||
.where((room) => room.isDirectChat)
|
||||
.map(
|
||||
(room) =>
|
||||
room.unsafeGetUserFromMemoryOrFallback(room.directChatMatrixID!),
|
||||
)
|
||||
.toList();
|
||||
|
||||
List<Room> get storiesRooms =>
|
||||
rooms.where((room) => room.isStoryRoom).toList();
|
||||
|
||||
Future<List<User>> getUndecidedContactsForStories(Room? storiesRoom) async {
|
||||
if (storiesRoom == null) return contacts;
|
||||
final invitedContacts =
|
||||
(await storiesRoom.requestParticipants()).map((user) => user.id);
|
||||
final decidedContacts = storiesBlockList.toSet()..addAll(invitedContacts);
|
||||
return contacts
|
||||
.where((contact) => !decidedContacts.contains(contact.id))
|
||||
.toList();
|
||||
}
|
||||
|
||||
List<String> get storiesBlockList =>
|
||||
accountData[storiesBlockListType]?.content.tryGetList<String>('users') ??
|
||||
[];
|
||||
|
||||
Future<void> setStoriesBlockList(List<String> users) => setAccountData(
|
||||
userID!,
|
||||
storiesBlockListType,
|
||||
{'users': users},
|
||||
);
|
||||
|
||||
Future<Room> createStoriesRoom([List<String>? invite]) async {
|
||||
final roomId = await createRoom(
|
||||
creationContent: {"type": "msc3588.stories.stories-room"},
|
||||
preset: CreateRoomPreset.privateChat,
|
||||
powerLevelContentOverride: {"events_default": 100},
|
||||
name: 'Stories from ${userID!.localpart}',
|
||||
topic:
|
||||
'This is a room for stories sharing, not unlike the similarly named features in other messaging networks. For best experience please use FluffyChat or minesTrix. Feature development can be followed on: https://github.com/matrix-org/matrix-doc/pull/3588',
|
||||
initialState: [
|
||||
StateEvent(
|
||||
type: EventTypes.Encryption,
|
||||
stateKey: '',
|
||||
content: {
|
||||
'algorithm': 'm.megolm.v1.aes-sha2',
|
||||
},
|
||||
),
|
||||
StateEvent(
|
||||
type: 'm.room.retention',
|
||||
stateKey: '',
|
||||
content: {
|
||||
'min_lifetime': 86400000,
|
||||
'max_lifetime': 86400000,
|
||||
},
|
||||
),
|
||||
],
|
||||
invite: invite,
|
||||
);
|
||||
if (getRoomById(roomId) == null) {
|
||||
// Wait for room actually appears in sync and is encrypted. This is a
|
||||
// workaround for https://github.com/krille-chan/fluffychat/issues/520
|
||||
await onSync.stream.firstWhere(
|
||||
(sync) =>
|
||||
sync.rooms?.join?[roomId]?.state
|
||||
?.any((state) => state.type == EventTypes.Encrypted) ??
|
||||
false,
|
||||
);
|
||||
}
|
||||
final room = getRoomById(roomId);
|
||||
if (room == null || !room.encrypted) {
|
||||
throw Exception(
|
||||
'Unable to create and wait for encrypted room to appear in Sync.',
|
||||
);
|
||||
}
|
||||
return room;
|
||||
}
|
||||
|
||||
Future<Room?> getStoriesRoom(BuildContext context) async {
|
||||
final candidates = rooms.where(
|
||||
(room) =>
|
||||
room
|
||||
.getState(EventTypes.RoomCreate)
|
||||
?.content
|
||||
.tryGet<String>('type') ==
|
||||
storiesRoomType &&
|
||||
room.ownPowerLevel >= 100,
|
||||
);
|
||||
if (candidates.isEmpty) return null;
|
||||
if (candidates.length == 1) return candidates.single;
|
||||
return await showModalActionSheet<Room>(
|
||||
context: context,
|
||||
actions: candidates
|
||||
.map(
|
||||
(room) => SheetAction(
|
||||
label: room.getLocalizedDisplayname(
|
||||
MatrixLocals(L10n.of(context)!),
|
||||
),
|
||||
key: room,
|
||||
),
|
||||
)
|
||||
.toList(),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
extension StoryRoom on Room {
|
||||
bool get isStoryRoom =>
|
||||
getState(EventTypes.RoomCreate)?.content.tryGet<String>('type') ==
|
||||
ClientStoriesExtension.storiesRoomType;
|
||||
}
|
||||
|
|
@ -1,44 +0,0 @@
|
|||
import 'package:flutter/material.dart';
|
||||
|
||||
import 'package:matrix/matrix.dart';
|
||||
|
||||
class StoryThemeData {
|
||||
final Color? color1;
|
||||
final Color? color2;
|
||||
final BoxFit fit;
|
||||
final int alignmentX;
|
||||
final int alignmentY;
|
||||
|
||||
static const String contentKey = 'msc3588.stories.design';
|
||||
|
||||
const StoryThemeData({
|
||||
this.color1,
|
||||
this.color2,
|
||||
this.fit = BoxFit.contain,
|
||||
this.alignmentX = 0,
|
||||
this.alignmentY = 0,
|
||||
});
|
||||
|
||||
factory StoryThemeData.fromJson(Map<String, dynamic> json) {
|
||||
final color1Int = json.tryGet<int>('color1');
|
||||
final color2Int = json.tryGet<int>('color2');
|
||||
final color1 = color1Int == null ? null : Color(color1Int);
|
||||
final color2 = color2Int == null ? null : Color(color2Int);
|
||||
return StoryThemeData(
|
||||
color1: color1,
|
||||
color2: color2,
|
||||
fit:
|
||||
json.tryGet<String>('fit') == 'cover' ? BoxFit.cover : BoxFit.contain,
|
||||
alignmentX: json.tryGet<int>('alignment_x') ?? 0,
|
||||
alignmentY: json.tryGet<int>('alignment_y') ?? 0,
|
||||
);
|
||||
}
|
||||
|
||||
Map<String, dynamic> toJson() => {
|
||||
if (color1 != null) 'color1': color1?.value,
|
||||
if (color2 != null) 'color2': color2?.value,
|
||||
'fit': fit.name,
|
||||
'alignment_x': alignmentX,
|
||||
'alignment_y': alignmentY,
|
||||
};
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue