Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
18 changes: 17 additions & 1 deletion ElementX.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -497,6 +497,7 @@
51263FC33CC961A14F5D6BCA /* TracingHook.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2A95C9B8299A36A6495DECA6 /* TracingHook.swift */; };
5139F4BD5A5DF6F8D11A9BDE /* NotificationPermissionsScreen.swift in Sources */ = {isa = PBXBuildFile; fileRef = 46D0BA44B1838E65B507B277 /* NotificationPermissionsScreen.swift */; };
513AF15E0E84711B80D04B1B /* ReportRoomScreenViewModelTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0C3E9684DCE6B66BD0B5DF67 /* ReportRoomScreenViewModelTests.swift */; };
51A075328D68FB4AE65C43B5 /* SearchServiceProxy.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7AD6FFE581238BD30B53BA0A /* SearchServiceProxy.swift */; };
51B3B19FA5F91B455C807BA7 /* RoomPollsHistoryScreenModels.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6E964AF2DFEB31E2B799999F /* RoomPollsHistoryScreenModels.swift */; };
522269133E6F65F68482F4F4 /* RemotePreferenceTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 181CF280BC8E3F335AFCB4B8 /* RemotePreferenceTests.swift */; };
52473A4D7B1FBD4CD1E770C8 /* MatrixEntityRegex.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6AD1A853D605C2146B0DC028 /* MatrixEntityRegex.swift */; };
Expand Down Expand Up @@ -1152,6 +1153,7 @@
BDFF0AEBF57B5B124062DAEF /* GeneratedAccessibilityTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = F4CEB4590CCF70F0E3C0B171 /* GeneratedAccessibilityTests.swift */; };
BE011C4473B9A8F12CBFE92A /* UserDetailsEditScreenViewModelTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 61F58D94C936A1B731D78DE1 /* UserDetailsEditScreenViewModelTests.swift */; };
BE8E5985771DF9137C6CE89A /* ProcessInfo.swift in Sources */ = {isa = PBXBuildFile; fileRef = 077B01C13BBA2996272C5FB5 /* ProcessInfo.swift */; };
BEB3D97EA51B25C87A37997E /* SearchServiceProxyProtocol.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9F3E4640982CE98C6ADD7896 /* SearchServiceProxyProtocol.swift */; };
BEC6DFEA506085D3027E353C /* MediaEventsTimelineScreen.swift in Sources */ = {isa = PBXBuildFile; fileRef = 002399C6CB875C4EBB01CBC0 /* MediaEventsTimelineScreen.swift */; };
BED59052E5C5163D2B065CA6 /* EventTimelineItem.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0A81FD0C60175FA081EB19AD /* EventTimelineItem.swift */; };
BF523D9E12E3C4AABBA2F6CB /* SpaceHeaderTopicSheetView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1D9F2E1FC5A0139571211CE8 /* SpaceHeaderTopicSheetView.swift */; };
Expand Down Expand Up @@ -2329,6 +2331,7 @@
7AC0CD1CAFD3F8B057F9AEA5 /* ClientBuilderHook.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ClientBuilderHook.swift; sourceTree = "<group>"; };
7AC1E3FE9B59EA094867863E /* TimelineControllerFactoryProtocol.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TimelineControllerFactoryProtocol.swift; sourceTree = "<group>"; };
7ACFFE7814849BB200CE0969 /* SpaceAddRoomsScreenModels.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SpaceAddRoomsScreenModels.swift; sourceTree = "<group>"; };
7AD6FFE581238BD30B53BA0A /* SearchServiceProxy.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SearchServiceProxy.swift; sourceTree = "<group>"; };
7AE094FCB6387D268C436161 /* SecureBackupScreenViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SecureBackupScreenViewModel.swift; sourceTree = "<group>"; };
7AE75941583A033A9EDC9FE0 /* RoomChangePermissionsScreenViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RoomChangePermissionsScreenViewModel.swift; sourceTree = "<group>"; };
7AE97AD18893E2D8120F559D /* RecoveryKeyScreenHook.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RecoveryKeyScreenHook.swift; sourceTree = "<group>"; };
Expand Down Expand Up @@ -2539,6 +2542,7 @@
9EB9BA2F30EB8C33226D8FF1 /* UserSessionStoreMock.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UserSessionStoreMock.swift; sourceTree = "<group>"; };
9ECF11669EF253E98AA2977A /* CompletionSuggestionServiceProtocol.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CompletionSuggestionServiceProtocol.swift; sourceTree = "<group>"; };
9F1DF3FFFE5ED2B8133F43A7 /* MessageComposer.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MessageComposer.swift; sourceTree = "<group>"; };
9F3E4640982CE98C6ADD7896 /* SearchServiceProxyProtocol.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SearchServiceProxyProtocol.swift; sourceTree = "<group>"; };
9F40FB0A43DAECEC27C73722 /* bg */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = bg; path = bg.lproj/SAS.strings; sourceTree = "<group>"; };
9FD40B92FCF20165658296AD /* TimelineMediaPreviewModifier.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TimelineMediaPreviewModifier.swift; sourceTree = "<group>"; };
9FD7E851E2BA8C5A8D284B2A /* BannedRoomProxyMock.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BannedRoomProxyMock.swift; sourceTree = "<group>"; };
Expand Down Expand Up @@ -3334,6 +3338,7 @@
599DFFE0805B08454E40D64A /* Polls */,
40E6246F03D1FE377BC5D963 /* Room */,
4FFDC8D1A752384B4C6EB0EB /* RoomDirectorySearch */,
BF73FE1790E737263F0F504A /* Search */,
BDCEF7C3BF6D09F5611CFC8B /* SecureBackup */,
82D5AD3EAE3A5C1068A44A88 /* Session */,
5329E48968EB951235E83DAE /* SessionVerification */,
Expand Down Expand Up @@ -6287,6 +6292,15 @@
path = KnockRequestsListScreen;
sourceTree = "<group>";
};
BF73FE1790E737263F0F504A /* Search */ = {
isa = PBXGroup;
children = (
7AD6FFE581238BD30B53BA0A /* SearchServiceProxy.swift */,
9F3E4640982CE98C6ADD7896 /* SearchServiceProxyProtocol.swift */,
);
path = Search;
sourceTree = "<group>";
};
C0937E3B06A8F0E2DB7C8241 /* Other */ = {
isa = PBXGroup;
children = (
Expand Down Expand Up @@ -8930,6 +8944,8 @@
3A0D1A201E2CD209A04CE89B /* SearchScreenModels.swift in Sources */,
6B8F03A85E83755D98DF0443 /* SearchScreenViewModel.swift in Sources */,
54804A7D8298F7E8ACAFDD76 /* SearchScreenViewModelProtocol.swift in Sources */,
51A075328D68FB4AE65C43B5 /* SearchServiceProxy.swift in Sources */,
BEB3D97EA51B25C87A37997E /* SearchServiceProxyProtocol.swift in Sources */,
22B380C579C148BA0BFB5952 /* Secrets.swift in Sources */,
339BC18777912E1989F2F17D /* Section.swift in Sources */,
F833D5B5BE6707F961FA88DB /* SecureBackupController.swift in Sources */,
Expand Down Expand Up @@ -10279,7 +10295,7 @@
repositoryURL = "https://github.com/element-hq/matrix-rust-components-swift";
requirement = {
kind = exactVersion;
version = 26.06.30;
version = 26.07.02;
};
};
701C7BEF8F70F7A83E852DCC /* XCRemoteSwiftPackageReference "GZIP" */ = {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
{
"originHash" : "1c7d307d80ee561100a0432a5ae13f345392a1175c7f6c17c2eb0da269382c57",
"originHash" : "61e1de2b41c093a3c8796903827114a1435f5608a839ee17ba60d376e8f804f7",
"pins" : [
{
"identity" : "compound-design-tokens",
Expand Down Expand Up @@ -167,8 +167,8 @@
"kind" : "remoteSourceControl",
"location" : "https://github.com/element-hq/matrix-rust-components-swift",
"state" : {
"revision" : "7f2a0d969742c03eb5e60216fc0ed35a4a5c13d2",
"version" : "26.6.30"
"revision" : "a23667230820d711f1d6d4517d078c2fef36e731",
"version" : "26.7.2"
}
},
{
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
"screen_home_tab_search" = "Search";
"screen_search_empty_state_message" = "Search for rooms";
"screen_search_empty_state_message" = "Search for chats and messages";
"screen_search_tab_messages" = "Messages";
"screen_search_tab_rooms" = "Rooms";
"screen_search_empty_state_title" = "Start searching...";
"screen_search_no_results_message" = "There are no results for “%1$@.” Try a new search term.";
"soft_logout_clear_data_dialog_content" = "Clear all data currently stored on this device?\nSign in again to access your account data and messages.";
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -98,6 +98,7 @@ class UserSessionFlowCoordinator: FlowCoordinatorProtocol {

if flowParameters.appSettings.globalSearchEnabled, #available(iOS 26.0, *) {
let searchCoordinator = SearchScreenCoordinator(parameters: .init(roomSummaryProvider: flowParameters.userSession.clientProxy.alternateRoomSummaryProvider,
clientProxy: flowParameters.userSession.clientProxy,
mediaProvider: flowParameters.userSession.mediaProvider))
let searchStackCoordinator = NavigationStackCoordinator()
searchStackCoordinator.setRootCoordinator(searchCoordinator)
Expand Down Expand Up @@ -222,20 +223,8 @@ class UserSessionFlowCoordinator: FlowCoordinatorProtocol {
}
}

// swiftlint:disable:next function_body_length
private func setupObservers() {
searchScreenCoordinator?.actionsPublisher
.sink { [weak self] action in
guard let self else { return }
switch action {
case .presentRoom(let roomID):
handleAppRoute(.room(roomID: roomID, via: []), animated: true)
case .cancel:
// Return to the tab the user came from, but never back into search.
navigationTabCoordinator.selectedTab = navigationTabCoordinator.previousTab == .search ? .chats : navigationTabCoordinator.previousTab ?? .chats
}
}
.store(in: &cancellables)

chatsTabFlowCoordinator.actionsPublisher
.sink { [weak self] action in
guard let self else { return }
Expand Down Expand Up @@ -334,6 +323,23 @@ class UserSessionFlowCoordinator: FlowCoordinatorProtocol {
}
}
.store(in: &cancellables)

searchScreenCoordinator?.actionsPublisher
.sink { [weak self] action in
guard let self else { return }
switch action {
case .presentRoom(let roomID, let eventID):
if let eventID {
handleAppRoute(.event(eventID: eventID, roomID: roomID, via: []), animated: true)
} else {
handleAppRoute(.room(roomID: roomID, via: []), animated: true)
}
case .cancel:
// Return to the tab the user came from, but never back into search.
navigationTabCoordinator.selectedTab = navigationTabCoordinator.previousTab == .search ? .chats : navigationTabCoordinator.previousTab ?? .chats
}
}
.store(in: &cancellables)
}

// MARK: - Onboarding
Expand Down
6 changes: 5 additions & 1 deletion ElementX/Sources/Generated/Strings+Untranslated.swift
Original file line number Diff line number Diff line change
Expand Up @@ -12,14 +12,18 @@ import Foundation
internal nonisolated enum UntranslatedL10n {
/// Search
internal static var screenHomeTabSearch: String { return UntranslatedL10n.tr("Untranslated", "screen_home_tab_search") }
/// Search for rooms
/// Search for chats and messages
internal static var screenSearchEmptyStateMessage: String { return UntranslatedL10n.tr("Untranslated", "screen_search_empty_state_message") }
/// Start searching...
internal static var screenSearchEmptyStateTitle: String { return UntranslatedL10n.tr("Untranslated", "screen_search_empty_state_title") }
/// There are no results for “%1$@.” Try a new search term.
internal static func screenSearchNoResultsMessage(_ p1: Any) -> String {
return UntranslatedL10n.tr("Untranslated", "screen_search_no_results_message", String(describing: p1))
}
/// Messages
internal static var screenSearchTabMessages: String { return UntranslatedL10n.tr("Untranslated", "screen_search_tab_messages") }
/// Rooms
internal static var screenSearchTabRooms: String { return UntranslatedL10n.tr("Untranslated", "screen_search_tab_rooms") }
/// Clear all data currently stored on this device?
/// Sign in again to access your account data and messages.
internal static var softLogoutClearDataDialogContent: String { return UntranslatedL10n.tr("Untranslated", "soft_logout_clear_data_dialog_content") }
Expand Down
77 changes: 77 additions & 0 deletions ElementX/Sources/Mocks/Generated/GeneratedMocks.swift
Original file line number Diff line number Diff line change
Expand Up @@ -2358,6 +2358,11 @@ nonisolated class ClientProxyMock: ClientProxyProtocol, @unchecked Sendable {
set(value) { underlyingSpaceService = value }
}
nonisolated(unsafe) var underlyingSpaceService: SpaceServiceProxyProtocol!
var searchService: SearchServiceProxyProtocol {
get { return underlyingSearchService }
set(value) { underlyingSearchService = value }
}
nonisolated(unsafe) var underlyingSearchService: SearchServiceProxyProtocol!
var capabilities: HomeserverCapabilitiesProxyProtocol {
get { return underlyingCapabilities }
set(value) { underlyingCapabilities = value }
Expand Down Expand Up @@ -10935,6 +10940,78 @@ nonisolated class RoomThreadListServiceProxyMock: RoomThreadListServiceProxyProt
}
}
}
nonisolated class SearchServiceProxyMock: SearchServiceProxyProtocol, @unchecked Sendable {
var resultsPublisher: CurrentValuePublisher<[SearchServiceResult], Never> {
get { return underlyingResultsPublisher }
set(value) { underlyingResultsPublisher = value }
}
nonisolated(unsafe) var underlyingResultsPublisher: CurrentValuePublisher<[SearchServiceResult], Never>!
var paginationStatePublisher: CurrentValuePublisher<SearchServicePaginationState, Never> {
get { return underlyingPaginationStatePublisher }
set(value) { underlyingPaginationStatePublisher = value }
}
nonisolated(unsafe) var underlyingPaginationStatePublisher: CurrentValuePublisher<SearchServicePaginationState, Never>!

//MARK: - setQuery

private let setQueryCallsCountLock = NSLock()
private nonisolated(unsafe) var setQueryUnderlyingCallsCount = 0
var setQueryCallsCount: Int {
get { setQueryCallsCountLock.withLock { setQueryUnderlyingCallsCount } }
set { setQueryCallsCountLock.withLock { setQueryUnderlyingCallsCount = newValue } }
}
var setQueryCalled: Bool {
return setQueryCallsCount > 0
}
private let setQueryReceivedQueryLock = NSLock()
private nonisolated(unsafe) var setQueryUnderlyingReceivedQuery: String?
var setQueryReceivedQuery: String? {
get { setQueryReceivedQueryLock.withLock { setQueryUnderlyingReceivedQuery } }
set { setQueryReceivedQueryLock.withLock { setQueryUnderlyingReceivedQuery = newValue } }
}
private let setQueryReceivedInvocationsLock = NSLock()
private nonisolated(unsafe) var setQueryUnderlyingReceivedInvocations: [String] = []
var setQueryReceivedInvocations: [String] {
get { setQueryReceivedInvocationsLock.withLock { setQueryUnderlyingReceivedInvocations } }
set { setQueryReceivedInvocationsLock.withLock { setQueryUnderlyingReceivedInvocations = newValue } }
}

private let setQueryReturnValueLock = NSLock()
private nonisolated(unsafe) var setQueryUnderlyingReturnValue: Result<Void, SearchServiceProxyError>!
var setQueryReturnValue: Result<Void, SearchServiceProxyError>! {
get { setQueryReturnValueLock.withLock { setQueryUnderlyingReturnValue } }
set { setQueryReturnValueLock.withLock { setQueryUnderlyingReturnValue = newValue } }
}
nonisolated(unsafe) var setQueryClosure: ((String) async -> Result<Void, SearchServiceProxyError>)?

@concurrent func setQuery(_ query: String) async -> Result<Void, SearchServiceProxyError> {
setQueryCallsCountLock.withLock { setQueryUnderlyingCallsCount += 1 }
setQueryReceivedQuery = query
setQueryReceivedInvocationsLock.withLock { setQueryUnderlyingReceivedInvocations.append(query) }
if let setQueryClosure = setQueryClosure {
return await setQueryClosure(query)
} else {
return setQueryReturnValue
}
}
//MARK: - paginate

private let paginateCallsCountLock = NSLock()
private nonisolated(unsafe) var paginateUnderlyingCallsCount = 0
var paginateCallsCount: Int {
get { paginateCallsCountLock.withLock { paginateUnderlyingCallsCount } }
set { paginateCallsCountLock.withLock { paginateUnderlyingCallsCount = newValue } }
}
var paginateCalled: Bool {
return paginateCallsCount > 0
}
nonisolated(unsafe) var paginateClosure: (() async -> Void)?

@concurrent func paginate() async {
paginateCallsCountLock.withLock { paginateUnderlyingCallsCount += 1 }
await paginateClosure?()
}
}
nonisolated class SecureBackupControllerMock: SecureBackupControllerProtocol, @unchecked Sendable {
var recoveryState: CurrentValuePublisher<SecureBackupRecoveryState, Never> {
get { return underlyingRecoveryState }
Expand Down
9 changes: 5 additions & 4 deletions ElementX/Sources/Other/Avatars.swift
Original file line number Diff line number Diff line change
Expand Up @@ -87,6 +87,7 @@ enum UserAvatarSizeOnScreen {
case threadSummary
case map
case classicAppAccount
case search

var value: CGFloat {
switch self {
Expand All @@ -107,7 +108,7 @@ enum UserAvatarSizeOnScreen {
case .roomDetails:
44
case .inviteUsers, .knockingUserList, .sessionVerification,
.settings, .threadList, .mediaPreviewDetails:
.settings, .threadList, .mediaPreviewDetails, .search:
52
case .roomChangeRoles:
56
Expand All @@ -130,7 +131,7 @@ enum RoomAvatarSizeOnScreen {
case timeline
case leaveSpace
case messageForwarding
case globalSearch
case search
case roomSelection
case details
case editRoomDetails
Expand All @@ -150,13 +151,13 @@ enum RoomAvatarSizeOnScreen {
30
case .timeline, .leaveSpace, .roomDirectorySearch,
.completionSuggestions, .authorizedSpaces, .createRoomSelectSpace,
.spaceFilters, .globalSearch:
.spaceFilters:
32
case .messageForwarding, .roomSelection,
.spaceAddRooms:
36
case .chats, .spaces, .spaceSettings,
.spaceAddRoomsSelected:
.spaceAddRoomsSelected, .search:
52
case .joinRoom, .spaceHeader, .editSpaceDetails:
64
Expand Down
14 changes: 14 additions & 0 deletions ElementX/Sources/Other/SDKListener.swift
Original file line number Diff line number Diff line change
Expand Up @@ -293,3 +293,17 @@ nonisolated extension SDKListener: RoomDirectorySearchEntriesListener where T ==
onUpdateClosure(roomEntriesUpdate)
}
}

// MARK: SearchServiceProxy

nonisolated extension SDKListener: SearchServiceResultsListener where T == [SearchServiceResultsUpdate] {
func onUpdate(updates: [SearchServiceResultsUpdate]) {
onUpdateClosure(updates)
}
}

nonisolated extension SDKListener: SearchServicePaginationStateListener where T == MatrixRustSDK.SearchServicePaginationState {
func onUpdate(paginationState: MatrixRustSDK.SearchServicePaginationState) {
onUpdateClosure(paginationState)
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -10,11 +10,12 @@ import SwiftUI

struct SearchScreenCoordinatorParameters {
let roomSummaryProvider: RoomSummaryProviderProtocol
let clientProxy: ClientProxyProtocol
let mediaProvider: MediaProviderProtocol
}

enum SearchScreenCoordinatorAction {
case presentRoom(roomID: String)
case presentRoom(roomID: String, eventID: String?)
case cancel
}

Expand All @@ -30,15 +31,16 @@ final class SearchScreenCoordinator: CoordinatorProtocol {

init(parameters: SearchScreenCoordinatorParameters) {
viewModel = SearchScreenViewModel(roomSummaryProvider: parameters.roomSummaryProvider,
clientProxy: parameters.clientProxy,
mediaProvider: parameters.mediaProvider)
}

func start() {
viewModel.actionsPublisher.sink { [weak self] action in
guard let self else { return }
switch action {
case .presentRoom(let roomID):
actionsSubject.send(.presentRoom(roomID: roomID))
case .presentRoom(let roomID, let eventID):
actionsSubject.send(.presentRoom(roomID: roomID, eventID: eventID))
case .cancel:
actionsSubject.send(.cancel)
}
Expand Down
Loading
Loading