mirror of
https://github.com/Novaloop-AG/element-x-ios.git
synced 2026-11-04 10:33:45 +00:00
added argument to voice over on the search bar automatically
- also removed the geomtry reader in favour of a `readWidth` function
This commit is contained in:
@@ -31,4 +31,15 @@ extension View {
|
|||||||
height.wrappedValue = newValue
|
height.wrappedValue = newValue
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Reads the width of the view and stores it in the `width` binding.
|
||||||
|
/// - Parameters:
|
||||||
|
/// - width: a `CGFloat` binding
|
||||||
|
func readWidth(_ width: Binding<CGFloat>) -> some View {
|
||||||
|
onGeometryChange(for: CGFloat.self) { geometry in
|
||||||
|
geometry.size.width
|
||||||
|
} action: { newValue in
|
||||||
|
width.wrappedValue = newValue
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -28,12 +28,14 @@ extension View {
|
|||||||
placeholder: String? = nil,
|
placeholder: String? = nil,
|
||||||
hidesNavigationBar: Bool = false,
|
hidesNavigationBar: Bool = false,
|
||||||
showsCancelButton: Bool = true,
|
showsCancelButton: Bool = true,
|
||||||
disablesInteractiveDismiss: Bool = false) -> some View {
|
disablesInteractiveDismiss: Bool = false,
|
||||||
|
accessibilityFocusOnStart: Bool = false) -> some View {
|
||||||
modifier(SearchControllerModifier(searchQuery: query,
|
modifier(SearchControllerModifier(searchQuery: query,
|
||||||
placeholder: placeholder,
|
placeholder: placeholder,
|
||||||
hidesNavigationBar: hidesNavigationBar,
|
hidesNavigationBar: hidesNavigationBar,
|
||||||
showsCancelButton: showsCancelButton,
|
showsCancelButton: showsCancelButton,
|
||||||
disablesInteractiveDismiss: disablesInteractiveDismiss))
|
disablesInteractiveDismiss: disablesInteractiveDismiss,
|
||||||
|
accessibilityFocusOnStart: accessibilityFocusOnStart))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -44,6 +46,7 @@ private struct SearchControllerModifier: ViewModifier {
|
|||||||
let hidesNavigationBar: Bool
|
let hidesNavigationBar: Bool
|
||||||
let showsCancelButton: Bool
|
let showsCancelButton: Bool
|
||||||
let disablesInteractiveDismiss: Bool
|
let disablesInteractiveDismiss: Bool
|
||||||
|
let accessibilityFocusOnStart: Bool
|
||||||
|
|
||||||
/// Whether or not the user is currently searching. When ``automaticallyShowsCancelButton``
|
/// Whether or not the user is currently searching. When ``automaticallyShowsCancelButton``
|
||||||
/// is `false`, checking if this value is `false` is pretty much meaningless.
|
/// is `false`, checking if this value is `false` is pretty much meaningless.
|
||||||
@@ -58,6 +61,7 @@ private struct SearchControllerModifier: ViewModifier {
|
|||||||
hidesNavigationBar: hidesNavigationBar,
|
hidesNavigationBar: hidesNavigationBar,
|
||||||
showsCancelButton: showsCancelButton,
|
showsCancelButton: showsCancelButton,
|
||||||
hidesSearchBarWhenScrolling: false,
|
hidesSearchBarWhenScrolling: false,
|
||||||
|
accessibilityFocusOnStart: accessibilityFocusOnStart,
|
||||||
isSearching: $isSearching)
|
isSearching: $isSearching)
|
||||||
}
|
}
|
||||||
.onDisappear {
|
.onDisappear {
|
||||||
@@ -76,12 +80,19 @@ private struct SearchController: UIViewControllerRepresentable {
|
|||||||
let hidesNavigationBar: Bool
|
let hidesNavigationBar: Bool
|
||||||
let showsCancelButton: Bool
|
let showsCancelButton: Bool
|
||||||
let hidesSearchBarWhenScrolling: Bool
|
let hidesSearchBarWhenScrolling: Bool
|
||||||
|
let accessibilityFocusOnStart: Bool
|
||||||
|
|
||||||
@Binding var isSearching: Bool
|
@Binding var isSearching: Bool
|
||||||
|
|
||||||
func makeUIViewController(context: Context) -> SearchInjectionViewController {
|
func makeUIViewController(context: Context) -> SearchInjectionViewController {
|
||||||
SearchInjectionViewController(searchController: context.coordinator.searchController,
|
let controller = SearchInjectionViewController(searchController: context.coordinator.searchController,
|
||||||
hidesSearchBarWhenScrolling: hidesSearchBarWhenScrolling)
|
hidesSearchBarWhenScrolling: hidesSearchBarWhenScrolling)
|
||||||
|
if accessibilityFocusOnStart {
|
||||||
|
DispatchQueue.main.asyncAfter(deadline: .now() + 0.5) {
|
||||||
|
UIAccessibility.post(notification: .screenChanged, argument: controller.searchController.searchBar)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return controller
|
||||||
}
|
}
|
||||||
|
|
||||||
func updateUIViewController(_ viewController: SearchInjectionViewController, context: Context) {
|
func updateUIViewController(_ viewController: SearchInjectionViewController, context: Context) {
|
||||||
|
|||||||
@@ -11,6 +11,8 @@ import SwiftUI
|
|||||||
struct InviteUsersScreen: View {
|
struct InviteUsersScreen: View {
|
||||||
@ObservedObject var context: InviteUsersScreenViewModel.Context
|
@ObservedObject var context: InviteUsersScreenViewModel.Context
|
||||||
|
|
||||||
|
@State private var formWidth = CGFloat.zero
|
||||||
|
|
||||||
var showTopSection: Bool {
|
var showTopSection: Bool {
|
||||||
!context.viewState.selectedUsers.isEmpty || context.viewState.isSearching
|
!context.viewState.selectedUsers.isEmpty || context.viewState.isSearching
|
||||||
}
|
}
|
||||||
@@ -25,7 +27,8 @@ struct InviteUsersScreen: View {
|
|||||||
.searchController(query: $context.searchQuery,
|
.searchController(query: $context.searchQuery,
|
||||||
placeholder: L10n.commonSearchForSomeone,
|
placeholder: L10n.commonSearchForSomeone,
|
||||||
showsCancelButton: false,
|
showsCancelButton: false,
|
||||||
disablesInteractiveDismiss: true)
|
disablesInteractiveDismiss: true,
|
||||||
|
accessibilityFocusOnStart: true)
|
||||||
.compoundSearchField()
|
.compoundSearchField()
|
||||||
.alert(item: $context.alertInfo)
|
.alert(item: $context.alertInfo)
|
||||||
}
|
}
|
||||||
@@ -33,34 +36,33 @@ struct InviteUsersScreen: View {
|
|||||||
// MARK: - Private
|
// MARK: - Private
|
||||||
|
|
||||||
private var mainContent: some View {
|
private var mainContent: some View {
|
||||||
GeometryReader { proxy in
|
Form {
|
||||||
Form {
|
if showTopSection {
|
||||||
if showTopSection {
|
// this is a fix for having the carousel not clipped, and inside the form, so when the search is dismissed, it wont break the design
|
||||||
// this is a fix for having the carousel not clipped, and inside the form, so when the search is dismissed, it wont break the design
|
Section {
|
||||||
Section {
|
EmptyView()
|
||||||
EmptyView()
|
} header: {
|
||||||
} header: {
|
VStack(spacing: 16) {
|
||||||
VStack(spacing: 16) {
|
selectedUsersSection
|
||||||
selectedUsersSection
|
.textCase(.none)
|
||||||
.textCase(.none)
|
.frame(width: formWidth)
|
||||||
.frame(width: proxy.size.width)
|
|
||||||
|
|
||||||
if context.viewState.isSearching {
|
if context.viewState.isSearching {
|
||||||
ProgressView()
|
ProgressView()
|
||||||
.frame(maxWidth: .infinity, alignment: .center)
|
.frame(maxWidth: .infinity, alignment: .center)
|
||||||
.listRowBackground(Color.clear)
|
.listRowBackground(Color.clear)
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if context.viewState.hasEmptySearchResults {
|
if context.viewState.hasEmptySearchResults {
|
||||||
noResultsContent
|
noResultsContent
|
||||||
} else {
|
} else {
|
||||||
usersSection
|
usersSection
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
.readWidth($formWidth)
|
||||||
}
|
}
|
||||||
|
|
||||||
private var noResultsContent: some View {
|
private var noResultsContent: some View {
|
||||||
|
|||||||
Reference in New Issue
Block a user