mirror of
https://github.com/Novaloop-AG/element-x-ios.git
synced 2026-11-02 12:07:55 +00:00
Fix tap knockable room and custom keyboard did show scrolling (#3603)
* making knockable rooms tappable * added a way to customise the keyboard scrolling in case we want the focussed view/textview to display something outside its content * better documentation
This commit is contained in:
@@ -0,0 +1,24 @@
|
||||
//
|
||||
// Copyright 2024 New Vector Ltd.
|
||||
//
|
||||
// SPDX-License-Identifier: AGPL-3.0-only
|
||||
// Please see LICENSE in the repository root for full details.
|
||||
//
|
||||
|
||||
import SwiftUI
|
||||
|
||||
extension View {
|
||||
/// Adds a scroll view reader to the view and scrolls to the provided id if the condition is true, so far it only works properly if the item is the last in the scroll view.
|
||||
func shouldScrollOnKeyboardDidShow(_ shouldScroll: Bool, to id: any Hashable) -> some View {
|
||||
ScrollViewReader { scrollView in
|
||||
onReceive(NotificationCenter.default.publisher(for: UIApplication.keyboardDidShowNotification)) { _ in
|
||||
guard shouldScroll else { return }
|
||||
// Scroll to the footer of the alias when the keyboard appears
|
||||
withAnimation {
|
||||
// We could improve this in the future by also providing the anchor as an argument
|
||||
scrollView.scrollTo(id, anchor: .top)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -15,6 +15,7 @@ struct CreateRoomScreen: View {
|
||||
private enum Focus {
|
||||
case name
|
||||
case topic
|
||||
case alias
|
||||
}
|
||||
|
||||
private var aliasBinding: Binding<String> {
|
||||
@@ -52,6 +53,7 @@ struct CreateRoomScreen: View {
|
||||
.toolbar { toolbar }
|
||||
.readFrame($frame)
|
||||
.alert(item: $context.alertInfo)
|
||||
.shouldScrollOnKeyboardDidShow(focus == .alias, to: Focus.alias)
|
||||
}
|
||||
|
||||
private var roomSection: some View {
|
||||
@@ -197,6 +199,8 @@ struct CreateRoomScreen: View {
|
||||
TextField("", text: aliasBinding)
|
||||
.textInputAutocapitalization(.never)
|
||||
.autocorrectionDisabled()
|
||||
.textContentType(.URL)
|
||||
.focused($focus, equals: .alias)
|
||||
.tint(.compound.iconAccentTertiary)
|
||||
.font(.compound.bodyLG)
|
||||
.foregroundStyle(.compound.textPrimary)
|
||||
@@ -209,6 +213,7 @@ struct CreateRoomScreen: View {
|
||||
.environment(\.layoutDirection, .leftToRight)
|
||||
.errorBackground(!context.viewState.aliasErrors.isEmpty)
|
||||
})
|
||||
.id(Focus.alias)
|
||||
} header: {
|
||||
Text(L10n.screenCreateRoomRoomAddressSectionTitle)
|
||||
.compoundListSectionHeader()
|
||||
|
||||
@@ -13,7 +13,12 @@ struct JoinRoomScreen: View {
|
||||
@Environment(\.dynamicTypeSize) private var dynamicTypeSize
|
||||
|
||||
@ObservedObject var context: JoinRoomScreenViewModel.Context
|
||||
@FocusState private var focus: Focus?
|
||||
|
||||
private enum Focus {
|
||||
case knockMessage
|
||||
}
|
||||
|
||||
var body: some View {
|
||||
FullscreenDialog(topPadding: context.viewState.mode == .knocked ? 151 : 35, background: .bloom) {
|
||||
if context.viewState.mode == .loading {
|
||||
@@ -29,6 +34,7 @@ struct JoinRoomScreen: View {
|
||||
.backgroundStyle(.compound.bgCanvasDefault)
|
||||
.navigationBarTitleDisplayMode(.inline)
|
||||
.toolbar { toolbar }
|
||||
.shouldScrollOnKeyboardDidShow(focus == .knockMessage, to: Focus.knockMessage)
|
||||
}
|
||||
|
||||
@ViewBuilder
|
||||
@@ -117,6 +123,7 @@ struct JoinRoomScreen: View {
|
||||
VStack(alignment: .leading, spacing: 12) {
|
||||
HStack(spacing: 0) {
|
||||
TextField("", text: $context.knockMessage, axis: .vertical)
|
||||
.focused($focus, equals: .knockMessage)
|
||||
.onChange(of: context.knockMessage) { _, newValue in
|
||||
context.knockMessage = String(newValue.prefix(maxKnockMessageLength))
|
||||
}
|
||||
@@ -124,6 +131,7 @@ struct JoinRoomScreen: View {
|
||||
.font(.compound.bodyMD)
|
||||
.padding(.horizontal, 16)
|
||||
.padding(.vertical, 12)
|
||||
.id(Focus.knockMessage)
|
||||
}
|
||||
.background(.compound.bgCanvasDefault)
|
||||
.cornerRadius(8)
|
||||
|
||||
@@ -644,7 +644,7 @@ class ClientProxy: ClientProxyProtocol {
|
||||
}
|
||||
|
||||
func roomDirectorySearchProxy() -> RoomDirectorySearchProxyProtocol {
|
||||
RoomDirectorySearchProxy(roomDirectorySearch: client.roomDirectorySearch())
|
||||
RoomDirectorySearchProxy(roomDirectorySearch: client.roomDirectorySearch(), appSettings: appSettings)
|
||||
}
|
||||
|
||||
func resolveRoomAlias(_ alias: String) async -> Result<ResolvedRoomAlias, ClientProxyError> {
|
||||
|
||||
@@ -12,6 +12,7 @@ import MatrixRustSDK
|
||||
|
||||
final class RoomDirectorySearchProxy: RoomDirectorySearchProxyProtocol {
|
||||
private let roomDirectorySearch: RoomDirectorySearchProtocol
|
||||
private let appSettings: AppSettings
|
||||
private let serialDispatchQueue = DispatchQueue(label: "io.element.elementx.roomdirectorysearch", qos: .default)
|
||||
|
||||
private let resultsSubject = CurrentValueSubject<[RoomDirectorySearchResult], Never>([])
|
||||
@@ -31,8 +32,10 @@ final class RoomDirectorySearchProxy: RoomDirectorySearchProxyProtocol {
|
||||
|
||||
private var cancellables = Set<AnyCancellable>()
|
||||
|
||||
init(roomDirectorySearch: RoomDirectorySearchProtocol) {
|
||||
init(roomDirectorySearch: RoomDirectorySearchProtocol,
|
||||
appSettings: AppSettings) {
|
||||
self.roomDirectorySearch = roomDirectorySearch
|
||||
self.appSettings = appSettings
|
||||
diffsPublisher
|
||||
.receive(on: serialDispatchQueue)
|
||||
.sink { [weak self] in self?.updateResultsWithDiffs($0) }
|
||||
@@ -146,7 +149,7 @@ final class RoomDirectorySearchProxy: RoomDirectorySearchProxyProtocol {
|
||||
name: value.name,
|
||||
topic: value.topic,
|
||||
avatar: .room(id: value.roomId, name: value.name, avatarURL: value.avatarUrl.flatMap(URL.init(string:))),
|
||||
canBeJoined: value.joinRule == .public)
|
||||
canBeJoined: value.joinRule == .public || (appSettings.knockingEnabled && value.joinRule == .knock))
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user