mirror of
https://github.com/Novaloop-AG/element-x-ios.git
synced 2026-11-03 06:55:59 +00:00
Join room by address (#3840)
* Implemented join room by address * improved the text field typing * some improvements to how the text is edited * remove navigation link * moved room directory search to the start chat flow * updated preview tests * added unit tests and improved the code * updated strings * some pr suggestions: - moving the file - changing the name of the action - reintroduce the debounce text queries - add comments * renamed the auth text field style to Element updated tests
This commit is contained in:
@@ -0,0 +1,95 @@
|
||||
//
|
||||
// Copyright 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 Compound
|
||||
import SwiftUI
|
||||
|
||||
struct JoinRoomByAddressView: View {
|
||||
@ObservedObject var context: StartChatScreenViewModel.Context
|
||||
|
||||
@Environment(\.dismiss) private var dismiss
|
||||
|
||||
@State private var sheetHeight: CGFloat = .zero
|
||||
@FocusState private var textFieldFocus
|
||||
private let topPadding: CGFloat = 22
|
||||
|
||||
private var footerText: String {
|
||||
switch context.viewState.joinByAddressState {
|
||||
case .example:
|
||||
L10n.screenStartChatJoinRoomByAddressSupportingText
|
||||
case .addressNotFound:
|
||||
L10n.screenStartChatJoinRoomByAddressRoomNotFound
|
||||
case .addressFound:
|
||||
L10n.screenStartChatJoinRoomByAddressRoomFound
|
||||
case .invalidAddress:
|
||||
L10n.screenStartChatJoinRoomByAddressInvalidAddress
|
||||
}
|
||||
}
|
||||
|
||||
private var textFieldState: ElementTextFieldStyle.State {
|
||||
switch context.viewState.joinByAddressState {
|
||||
case .addressFound:
|
||||
.success
|
||||
case .example:
|
||||
.default
|
||||
case .addressNotFound, .invalidAddress:
|
||||
.error
|
||||
}
|
||||
}
|
||||
|
||||
var body: some View {
|
||||
ScrollView {
|
||||
VStack(spacing: 24) {
|
||||
TextField(L10n.screenStartChatJoinRoomByAddressPlaceholder,
|
||||
text: $context.roomAddress)
|
||||
.textFieldStyle(.element(labelText: L10n.screenStartChatJoinRoomByAddressAction,
|
||||
footerText: footerText,
|
||||
state: textFieldState))
|
||||
.textInputAutocapitalization(.never)
|
||||
.autocorrectionDisabled()
|
||||
.textContentType(.URL)
|
||||
.focused($textFieldFocus)
|
||||
.onChange(of: context.roomAddress) { _, newValue in
|
||||
context.roomAddress = newValue.trimmingCharacters(in: .whitespacesAndNewlines)
|
||||
}
|
||||
|
||||
Button(L10n.actionContinue) {
|
||||
context.send(viewAction: .joinRoomByAddress)
|
||||
}
|
||||
.buttonStyle(.compound(.primary))
|
||||
}
|
||||
.padding(.horizontal, 16)
|
||||
.readHeight($sheetHeight)
|
||||
}
|
||||
.scrollBounceBehavior(.basedOnSize)
|
||||
.padding(.top, topPadding) // For the drag indicator
|
||||
.presentationDetents([.height(sheetHeight + topPadding)])
|
||||
.presentationDragIndicator(.visible)
|
||||
.presentationBackground(.compound.bgCanvasDefault)
|
||||
.onAppear {
|
||||
textFieldFocus = true
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
struct JoinRoomByAddressView_Previews: PreviewProvider, TestablePreview {
|
||||
static let viewModel = {
|
||||
let userSession = UserSessionMock(.init(clientProxy: ClientProxyMock(.init(userID: "@userid:example.com"))))
|
||||
let userDiscoveryService = UserDiscoveryServiceMock()
|
||||
userDiscoveryService.searchProfilesWithReturnValue = .success([.mockAlice])
|
||||
let viewModel = StartChatScreenViewModel(userSession: userSession,
|
||||
analytics: ServiceLocator.shared.analytics,
|
||||
userIndicatorController: UserIndicatorControllerMock(),
|
||||
userDiscoveryService: userDiscoveryService,
|
||||
appSettings: ServiceLocator.shared.settings)
|
||||
return viewModel
|
||||
}()
|
||||
|
||||
static var previews: some View {
|
||||
JoinRoomByAddressView(context: viewModel.context)
|
||||
}
|
||||
}
|
||||
@@ -36,6 +36,11 @@ struct StartChatScreen: View {
|
||||
context.send(viewAction: .createDM(user: user))
|
||||
}
|
||||
}
|
||||
.sheet(isPresented: $context.isJoinRoomByAddressSheetPresented) {
|
||||
context.roomAddress = ""
|
||||
} content: {
|
||||
JoinRoomByAddressView(context: context)
|
||||
}
|
||||
}
|
||||
|
||||
// MARK: - Private
|
||||
@@ -44,10 +49,34 @@ struct StartChatScreen: View {
|
||||
@ViewBuilder
|
||||
private var mainContent: some View {
|
||||
createRoomSection
|
||||
if context.viewState.isRoomDirectoryEnabled {
|
||||
roomDirectorySearch
|
||||
}
|
||||
inviteFriendsSection
|
||||
joinRoomByAddressSection
|
||||
usersSection
|
||||
}
|
||||
|
||||
private var joinRoomByAddressSection: some View {
|
||||
Section {
|
||||
ListRow(label: .default(title: L10n.screenStartChatJoinRoomByAddressAction,
|
||||
icon: \.room),
|
||||
kind: .button {
|
||||
context.isJoinRoomByAddressSheetPresented = true
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
private var roomDirectorySearch: some View {
|
||||
Section {
|
||||
ListRow(label: .default(title: L10n.screenRoomDirectorySearchTitle,
|
||||
icon: \.listBulleted),
|
||||
kind: .navigationLink {
|
||||
context.send(viewAction: .openRoomDirectorySearch)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
/// The content shown in the form when a search query has been entered.
|
||||
@ViewBuilder
|
||||
private var searchContent: some View {
|
||||
@@ -125,13 +154,16 @@ struct StartChatScreen: View {
|
||||
|
||||
struct StartChatScreen_Previews: PreviewProvider, TestablePreview {
|
||||
static let viewModel = {
|
||||
let appSettings = AppSettings()
|
||||
appSettings.publicSearchEnabled = true
|
||||
let userSession = UserSessionMock(.init(clientProxy: ClientProxyMock(.init(userID: "@userid:example.com"))))
|
||||
let userDiscoveryService = UserDiscoveryServiceMock()
|
||||
userDiscoveryService.searchProfilesWithReturnValue = .success([.mockAlice])
|
||||
let viewModel = StartChatScreenViewModel(userSession: userSession,
|
||||
analytics: ServiceLocator.shared.analytics,
|
||||
userIndicatorController: UserIndicatorControllerMock(),
|
||||
userDiscoveryService: userDiscoveryService)
|
||||
userDiscoveryService: userDiscoveryService,
|
||||
appSettings: appSettings)
|
||||
return viewModel
|
||||
}()
|
||||
|
||||
|
||||
Reference in New Issue
Block a user