mirror of
https://github.com/Novaloop-AG/element-x-ios.git
synced 2026-11-02 12:07:55 +00:00
c41a38159b
* Initial plan * Offer only joined rooms in destination pickers Co-authored-by: Velin92 <34335419+Velin92@users.noreply.github.com> * Clean whitespace in share picker test Co-authored-by: Velin92 <34335419+Velin92@users.noreply.github.com> * Restrict the shared picker room list to joined rooms The alternate room summary provider, which backs the forward, share and Add rooms pickers and global search, now always includes the SDK's joined filter in its base filter. This replaces the per-call joinedOnly flags, so Add rooms no longer offers invited rooms or spaces and no screen can forget the flag. A filter set before the provider has its room list is now applied once the list is set, instead of being reset to the default. The share picker hit this on a cold launch from the share extension. The forward and share pickers also hide upgraded rooms, matching the Suggestions section. The SDK has no filter for these. Also registers the share picker's test file in the project, fixes the blank-line indentation SwiftFormat flagged, and re-records the picker snapshots without the upgraded room. * Check room membership for forwarding suggestions and search breadcrumbs RoomSummary now has isJoined, built from the room's membership. The forwarding suggestions and the search breadcrumbs used a missing joinRequestType to mean joined, which is also the case for rooms that have been left or banned from. It only worked because the room list's base filter already drops those. --------- Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com> Co-authored-by: Velin92 <34335419+Velin92@users.noreply.github.com> Co-authored-by: Mauro Romito <mauro.romito@element.io>
433 lines
18 KiB
Swift
433 lines
18 KiB
Swift
//
|
|
// Copyright 2025 Element Creations Ltd.
|
|
// Copyright 2024-2025 New Vector Ltd.
|
|
//
|
|
// SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-Element-Commercial.
|
|
// Please see LICENSE files in the repository root for full details.
|
|
//
|
|
|
|
import Combine
|
|
import Foundation
|
|
import MatrixRustSDKMocks
|
|
|
|
enum RoomSummaryProviderMockConfigurationState {
|
|
case loading
|
|
case loaded([RoomSummary])
|
|
}
|
|
|
|
struct RoomSummaryProviderMockConfiguration {
|
|
var state: RoomSummaryProviderMockConfigurationState = .loading
|
|
}
|
|
|
|
extension RoomSummaryProviderMock {
|
|
convenience init(_ configuration: RoomSummaryProviderMockConfiguration) {
|
|
self.init()
|
|
|
|
let initialRooms: [RoomSummary]
|
|
let roomListSubject: CurrentValueSubject<[RoomSummary], Never>
|
|
let stateSubject: CurrentValueSubject<RoomSummaryProviderState, Never>
|
|
|
|
switch configuration.state {
|
|
case .loading:
|
|
initialRooms = []
|
|
roomListSubject = .init(initialRooms)
|
|
stateSubject = .init(.notLoaded)
|
|
case .loaded(let rooms):
|
|
initialRooms = rooms
|
|
roomListSubject = .init(initialRooms)
|
|
stateSubject = .init(.loaded(totalNumberOfRooms: UInt(rooms.count)))
|
|
}
|
|
|
|
roomListPublisher = roomListSubject.asCurrentValuePublisher()
|
|
statePublisher = stateSubject.asCurrentValuePublisher()
|
|
|
|
setFilterClosure = { [initialRooms, roomListSubject] filter in
|
|
switch filter {
|
|
case let .search(query):
|
|
var rooms = initialRooms
|
|
|
|
if !query.isEmpty {
|
|
rooms = rooms.filter { $0.name.localizedCaseInsensitiveContains(query) }
|
|
}
|
|
|
|
roomListSubject.send(rooms)
|
|
case let .rooms(_, filters), let .all(filters):
|
|
var rooms = initialRooms
|
|
|
|
if filters.count > 1 {
|
|
// for testing purpose chaining more than one filter will always return an empty state
|
|
rooms = []
|
|
} else if let filter = filters.first {
|
|
rooms = rooms.filter { filter == .people ? $0.isDirect : !$0.isDirect }
|
|
}
|
|
|
|
roomListSubject.send(rooms)
|
|
case .excludeAll:
|
|
roomListSubject.send([])
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
extension RoomSummary {
|
|
static func mock(id: String,
|
|
name: String,
|
|
isSpace: Bool = false,
|
|
isJoined: Bool = true,
|
|
canonicalAlias: String? = nil) -> RoomSummary {
|
|
RoomSummary(room: RoomSDKMock(.init()),
|
|
id: id,
|
|
joinRequestType: nil,
|
|
isJoined: isJoined,
|
|
name: name,
|
|
isDirect: false,
|
|
isSpace: isSpace,
|
|
avatarURL: nil,
|
|
heroes: [],
|
|
activeMembersCount: 0,
|
|
lastMessage: AttributedString("I do not wish to take the trouble to understand mysticism"),
|
|
lastMessageDate: .mock,
|
|
lastMessageState: nil,
|
|
unreadMessagesCount: 0,
|
|
unreadMentionsCount: 0,
|
|
unreadNotificationsCount: 0,
|
|
notificationMode: .allMessages,
|
|
canonicalAlias: canonicalAlias,
|
|
alternativeAliases: [],
|
|
hasOngoingCall: false,
|
|
activeCallIntent: nil,
|
|
isMarkedUnread: false,
|
|
isFavourite: false,
|
|
isTombstoned: false)
|
|
}
|
|
}
|
|
|
|
extension Array where Element == RoomSummary {
|
|
static let mockRooms: [Element] = [
|
|
RoomSummary(room: RoomSDKMock(),
|
|
id: "1",
|
|
joinRequestType: nil,
|
|
isJoined: true,
|
|
name: "Foundation 🔭🪐🌌",
|
|
isDirect: false,
|
|
isSpace: false,
|
|
avatarURL: nil,
|
|
heroes: [],
|
|
activeMembersCount: 0,
|
|
lastMessage: AttributedString("I do not wish to take the trouble to understand mysticism"),
|
|
lastMessageDate: .mock,
|
|
lastMessageState: nil,
|
|
unreadMessagesCount: 0,
|
|
unreadMentionsCount: 0,
|
|
unreadNotificationsCount: 0,
|
|
notificationMode: .allMessages,
|
|
canonicalAlias: nil,
|
|
alternativeAliases: [],
|
|
hasOngoingCall: false,
|
|
activeCallIntent: nil,
|
|
isMarkedUnread: false,
|
|
isFavourite: false,
|
|
isTombstoned: false),
|
|
RoomSummary(room: RoomSDKMock(),
|
|
id: "2",
|
|
joinRequestType: nil,
|
|
isJoined: true,
|
|
name: "Foundation and Empire",
|
|
isDirect: false,
|
|
isSpace: false,
|
|
avatarURL: .mockMXCAvatar,
|
|
heroes: [],
|
|
activeMembersCount: 0,
|
|
lastMessage: AttributedString("How do you see the Emperor then? You think he keeps office hours?"),
|
|
lastMessageDate: .mock,
|
|
lastMessageState: nil,
|
|
unreadMessagesCount: 2,
|
|
unreadMentionsCount: 0,
|
|
unreadNotificationsCount: 2,
|
|
notificationMode: .mute,
|
|
canonicalAlias: "#foundation-and-empire:matrix.org",
|
|
alternativeAliases: [],
|
|
hasOngoingCall: false,
|
|
activeCallIntent: nil,
|
|
isMarkedUnread: false,
|
|
isFavourite: false,
|
|
isTombstoned: false),
|
|
RoomSummary(room: RoomSDKMock(),
|
|
id: "3",
|
|
joinRequestType: nil,
|
|
isJoined: true,
|
|
name: "Second Foundation",
|
|
isDirect: false,
|
|
isSpace: false,
|
|
avatarURL: nil,
|
|
heroes: [],
|
|
activeMembersCount: 0,
|
|
lastMessage: try? AttributedString(markdown: "He certainly seemed no *mental genius* to me"),
|
|
lastMessageDate: .mock,
|
|
lastMessageState: nil,
|
|
unreadMessagesCount: 3,
|
|
unreadMentionsCount: 0,
|
|
unreadNotificationsCount: 0,
|
|
notificationMode: .mentionsAndKeywordsOnly,
|
|
canonicalAlias: nil,
|
|
alternativeAliases: [],
|
|
hasOngoingCall: false,
|
|
activeCallIntent: nil,
|
|
isMarkedUnread: false,
|
|
isFavourite: false,
|
|
isTombstoned: false),
|
|
RoomSummary(room: RoomSDKMock(),
|
|
id: "4",
|
|
joinRequestType: nil,
|
|
isJoined: true,
|
|
name: "Foundation's Edge",
|
|
isDirect: false,
|
|
isSpace: false,
|
|
avatarURL: nil,
|
|
heroes: [],
|
|
activeMembersCount: 0,
|
|
lastMessage: AttributedString("There's an archaic measure of time that's called the month"),
|
|
lastMessageDate: .mock,
|
|
lastMessageState: nil,
|
|
unreadMessagesCount: 2,
|
|
unreadMentionsCount: 2,
|
|
unreadNotificationsCount: 2,
|
|
notificationMode: .allMessages,
|
|
canonicalAlias: nil,
|
|
alternativeAliases: [],
|
|
hasOngoingCall: false,
|
|
activeCallIntent: nil,
|
|
isMarkedUnread: false,
|
|
isFavourite: false,
|
|
isTombstoned: false),
|
|
RoomSummary(room: RoomSDKMock(),
|
|
id: "5",
|
|
joinRequestType: nil,
|
|
isJoined: true,
|
|
name: "Foundation and Earth",
|
|
isDirect: true,
|
|
isSpace: false,
|
|
avatarURL: nil,
|
|
heroes: [],
|
|
activeMembersCount: 0,
|
|
lastMessage: AttributedString("Clearly, if Earth is powerful enough to do that, it might also be capable of adjusting minds in order to force belief in its radioactivity"),
|
|
lastMessageDate: .mock,
|
|
lastMessageState: nil,
|
|
unreadMessagesCount: 1,
|
|
unreadMentionsCount: 1,
|
|
unreadNotificationsCount: 1,
|
|
notificationMode: .allMessages,
|
|
canonicalAlias: nil,
|
|
alternativeAliases: [],
|
|
hasOngoingCall: true,
|
|
activeCallIntent: nil,
|
|
isMarkedUnread: false,
|
|
isFavourite: false,
|
|
isTombstoned: false),
|
|
RoomSummary(room: RoomSDKMock(),
|
|
id: "6",
|
|
joinRequestType: nil,
|
|
isJoined: true,
|
|
name: "Prelude to Foundation",
|
|
isDirect: true,
|
|
isSpace: false,
|
|
avatarURL: nil,
|
|
heroes: [],
|
|
activeMembersCount: 0,
|
|
lastMessage: AttributedString("Are you groping for the word 'paranoia'?"),
|
|
lastMessageDate: .mock,
|
|
lastMessageState: nil,
|
|
unreadMessagesCount: 6,
|
|
unreadMentionsCount: 0,
|
|
unreadNotificationsCount: 0,
|
|
notificationMode: .mute,
|
|
canonicalAlias: "#prelude-foundation:matrix.org",
|
|
alternativeAliases: [],
|
|
hasOngoingCall: true,
|
|
activeCallIntent: .audio,
|
|
isMarkedUnread: false,
|
|
isFavourite: false,
|
|
isTombstoned: false),
|
|
RoomSummary(room: RoomSDKMock(),
|
|
id: "7",
|
|
joinRequestType: nil,
|
|
isJoined: true,
|
|
name: "Tombstoned",
|
|
isDirect: false,
|
|
isSpace: false,
|
|
avatarURL: nil,
|
|
heroes: [],
|
|
activeMembersCount: 0,
|
|
lastMessage: nil,
|
|
lastMessageDate: .mock,
|
|
lastMessageState: nil,
|
|
unreadMessagesCount: 1,
|
|
unreadMentionsCount: 0,
|
|
unreadNotificationsCount: 1,
|
|
notificationMode: .allMessages,
|
|
canonicalAlias: nil,
|
|
alternativeAliases: [],
|
|
hasOngoingCall: false,
|
|
activeCallIntent: nil,
|
|
isMarkedUnread: false,
|
|
isFavourite: false,
|
|
isTombstoned: true),
|
|
RoomSummary(room: RoomSDKMock(),
|
|
id: "0",
|
|
joinRequestType: nil,
|
|
isJoined: true,
|
|
name: "Unknown",
|
|
isDirect: false,
|
|
isSpace: false,
|
|
avatarURL: nil,
|
|
heroes: [],
|
|
activeMembersCount: 0,
|
|
lastMessage: nil,
|
|
lastMessageDate: nil,
|
|
lastMessageState: nil,
|
|
unreadMessagesCount: 0,
|
|
unreadMentionsCount: 0,
|
|
unreadNotificationsCount: 0,
|
|
notificationMode: nil,
|
|
canonicalAlias: nil,
|
|
alternativeAliases: [],
|
|
hasOngoingCall: false,
|
|
activeCallIntent: nil,
|
|
isMarkedUnread: false,
|
|
isFavourite: false,
|
|
isTombstoned: false)
|
|
]
|
|
|
|
static let mockRoomsWithNotificationsState: [Element] = {
|
|
var result: [Element] = []
|
|
|
|
// Iterate over settings modes
|
|
for mode in RoomNotificationModeProxy.allCases {
|
|
// Iterate over unread messages states
|
|
for hasUnreadMessages in [false, true] {
|
|
// Iterate over unread mentions states
|
|
for hasUnreadMentions in [false, true] {
|
|
// Iterate over unread notifications states
|
|
for hasUnreadNotifications in [false, true] {
|
|
// Incrementing id value for each combination
|
|
let id = result.count + 1
|
|
|
|
let room = RoomSummary(room: RoomSDKMock(),
|
|
id: "\(id)",
|
|
settingsMode: mode,
|
|
hasUnreadMessages: hasUnreadMessages,
|
|
hasUnreadMentions: hasUnreadMentions,
|
|
hasUnreadNotifications: hasUnreadNotifications)
|
|
|
|
result.append(room)
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
return result
|
|
}()
|
|
|
|
static let mockInvites: [Element] = [
|
|
RoomSummary(room: RoomSDKMock(),
|
|
id: "someAwesomeRoomId1",
|
|
joinRequestType: .invite(inviter: RoomMemberProxyMock.mockCharlie),
|
|
isJoined: false,
|
|
name: "First room",
|
|
isDirect: false,
|
|
isSpace: false,
|
|
avatarURL: .mockMXCAvatar,
|
|
heroes: [],
|
|
activeMembersCount: 0,
|
|
lastMessage: nil,
|
|
lastMessageDate: nil,
|
|
lastMessageState: nil,
|
|
unreadMessagesCount: 0,
|
|
unreadMentionsCount: 0,
|
|
unreadNotificationsCount: 0,
|
|
notificationMode: nil,
|
|
canonicalAlias: "#footest:somewhere.org",
|
|
alternativeAliases: [],
|
|
hasOngoingCall: false,
|
|
activeCallIntent: nil,
|
|
isMarkedUnread: false,
|
|
isFavourite: false,
|
|
isTombstoned: false),
|
|
RoomSummary(room: RoomSDKMock(),
|
|
id: "someAwesomeRoomId2",
|
|
joinRequestType: .invite(inviter: RoomMemberProxyMock.mockCharlie),
|
|
isJoined: false,
|
|
name: "Second room",
|
|
isDirect: true,
|
|
isSpace: false,
|
|
avatarURL: nil,
|
|
heroes: [],
|
|
activeMembersCount: 0,
|
|
lastMessage: nil,
|
|
lastMessageDate: nil,
|
|
lastMessageState: nil,
|
|
unreadMessagesCount: 0,
|
|
unreadMentionsCount: 0,
|
|
unreadNotificationsCount: 0,
|
|
notificationMode: nil,
|
|
canonicalAlias: nil,
|
|
alternativeAliases: [],
|
|
hasOngoingCall: false,
|
|
activeCallIntent: nil,
|
|
isMarkedUnread: false,
|
|
isFavourite: false,
|
|
isTombstoned: false)
|
|
]
|
|
|
|
static let mockSpaceInvites: [Element] = [
|
|
RoomSummary(room: RoomSDKMock(),
|
|
id: "!space1:matrix.org",
|
|
joinRequestType: .invite(inviter: RoomMemberProxyMock.mockCharlie),
|
|
isJoined: false,
|
|
name: "First space",
|
|
isDirect: false,
|
|
isSpace: true,
|
|
avatarURL: .mockMXCAvatar,
|
|
heroes: [],
|
|
activeMembersCount: 0,
|
|
lastMessage: nil,
|
|
lastMessageDate: nil,
|
|
lastMessageState: nil,
|
|
unreadMessagesCount: 0,
|
|
unreadMentionsCount: 0,
|
|
unreadNotificationsCount: 0,
|
|
notificationMode: nil,
|
|
canonicalAlias: "#footest:somewhere.org",
|
|
alternativeAliases: [],
|
|
hasOngoingCall: false,
|
|
activeCallIntent: nil,
|
|
isMarkedUnread: false,
|
|
isFavourite: false,
|
|
isTombstoned: false),
|
|
RoomSummary(room: RoomSDKMock(),
|
|
id: "!space2:matrix.org",
|
|
joinRequestType: .invite(inviter: RoomMemberProxyMock.mockCharlie),
|
|
isJoined: false,
|
|
name: "Second space",
|
|
isDirect: false,
|
|
isSpace: true,
|
|
avatarURL: nil,
|
|
heroes: [],
|
|
activeMembersCount: 0,
|
|
lastMessage: nil,
|
|
lastMessageDate: nil,
|
|
lastMessageState: nil,
|
|
unreadMessagesCount: 0,
|
|
unreadMentionsCount: 0,
|
|
unreadNotificationsCount: 0,
|
|
notificationMode: nil,
|
|
canonicalAlias: nil,
|
|
alternativeAliases: [],
|
|
hasOngoingCall: false,
|
|
activeCallIntent: nil,
|
|
isMarkedUnread: false,
|
|
isFavourite: false,
|
|
isTombstoned: false)
|
|
]
|
|
}
|