mirror of
https://github.com/bitwarden/ios.git
synced 2025-12-10 00:42:29 -06:00
[PM-28144] Add debouncing to searches (#2176)
This commit is contained in:
parent
22bf62f9ac
commit
446858c7fb
@ -371,7 +371,7 @@ struct ItemListView: View {
|
||||
placement: .navigationBarDrawer(displayMode: .always),
|
||||
prompt: Localizations.search,
|
||||
)
|
||||
.task(id: store.state.searchText) {
|
||||
.searchDebouncedTask(id: store.state.searchText) {
|
||||
await store.perform(.search(store.state.searchText))
|
||||
}
|
||||
}
|
||||
|
||||
@ -24,6 +24,9 @@ public enum Constants {
|
||||
/// The minimum number of minutes before attempting a server config sync again.
|
||||
public static let minimumConfigSyncInterval: TimeInterval = 60 * 60 // 60 minutes
|
||||
|
||||
/// The search debounce time in nanoseconds.
|
||||
public static let searchDebounceTimeInNS: UInt64 = 200_000_000 // 200ms
|
||||
|
||||
/// The default file name when the file name cannot be determined.
|
||||
public static let unknownFileName = "unknown_file_name"
|
||||
}
|
||||
|
||||
@ -0,0 +1,59 @@
|
||||
import SwiftUI
|
||||
|
||||
public extension View {
|
||||
/// Adds a debounced task to perform before this view appears or when a specified
|
||||
/// value changes.
|
||||
/// This means that the task will execute the action when the specified value doesn't change
|
||||
/// in the debounce interval specified.
|
||||
///
|
||||
/// - Parameters:
|
||||
/// - id: The value to observe for changes. The value must conform
|
||||
/// to the <doc://com.apple.documentation/documentation/Swift/Equatable>
|
||||
/// protocol.
|
||||
/// - debounceIntervalInNS: The interval to be set for debouncing the task.
|
||||
/// - action: A closure that SwiftUI calls as an asynchronous task
|
||||
/// before the view appears. SwiftUI can automatically cancel the task
|
||||
/// after the view disappears before the action completes. If the
|
||||
/// `id` value changes, SwiftUI cancels and restarts the task.
|
||||
///
|
||||
/// - Returns: A view that runs the specified action asynchronously before
|
||||
/// the view appears, or restarts the task when the `id` value changes.
|
||||
@inlinable nonisolated func debouncedTask<T>(
|
||||
id value: T,
|
||||
debounceIntervalInNS: UInt64,
|
||||
_ action: @escaping @Sendable () async -> Void,
|
||||
) -> some View where T: Equatable {
|
||||
task(id: value) {
|
||||
try? await Task.sleep(nanoseconds: debounceIntervalInNS)
|
||||
guard !Task.isCancelled else {
|
||||
return
|
||||
}
|
||||
await action()
|
||||
}
|
||||
}
|
||||
|
||||
/// Adds a task to perform before this view appears or when a specified
|
||||
/// value changes to be used on debounced searches.
|
||||
///
|
||||
/// - Parameters:
|
||||
/// - id: The value to observe for changes. The value must conform
|
||||
/// to the <doc://com.apple.documentation/documentation/Swift/Equatable>
|
||||
/// protocol.
|
||||
/// - action: A closure that SwiftUI calls as an asynchronous task
|
||||
/// before the view appears. SwiftUI can automatically cancel the task
|
||||
/// after the view disappears before the action completes. If the
|
||||
/// `id` value changes, SwiftUI cancels and restarts the task.
|
||||
///
|
||||
/// - Returns: A view that runs the specified action asynchronously before
|
||||
/// the view appears, or restarts the task when the `id` value changes.
|
||||
@inlinable nonisolated func searchDebouncedTask<T>(
|
||||
id value: T,
|
||||
_ action: @escaping @Sendable () async -> Void,
|
||||
) -> some View where T: Equatable {
|
||||
debouncedTask(
|
||||
id: value,
|
||||
debounceIntervalInNS: Constants.searchDebounceTimeInNS,
|
||||
action
|
||||
)
|
||||
}
|
||||
}
|
||||
@ -266,7 +266,7 @@ struct SendListView: View {
|
||||
)
|
||||
.task { await store.perform(.loadData) }
|
||||
.task { await store.perform(.streamSendList) }
|
||||
.task(id: store.state.searchText) {
|
||||
.searchDebouncedTask(id: store.state.searchText) {
|
||||
await store.perform(.search(store.state.searchText))
|
||||
}
|
||||
.onChange(of: store.state.infoUrl) { newValue in
|
||||
|
||||
@ -106,7 +106,7 @@ private struct VaultAutofillListSearchableView: View {
|
||||
.task {
|
||||
await store.perform(.streamShowWebIcons)
|
||||
}
|
||||
.task(id: store.state.searchText) {
|
||||
.searchDebouncedTask(id: store.state.searchText) {
|
||||
await store.perform(.search(store.state.searchText))
|
||||
}
|
||||
.task(id: store.state.excludedCredentialIdFound) {
|
||||
|
||||
@ -62,7 +62,7 @@ struct VaultGroupView: View {
|
||||
openURL(url)
|
||||
store.send(.clearURL)
|
||||
}
|
||||
.task(id: store.state.searchText) {
|
||||
.searchDebouncedTask(id: store.state.searchText) {
|
||||
await store.perform(.search(store.state.searchText))
|
||||
}
|
||||
.task(id: store.state.searchVaultFilterType) {
|
||||
|
||||
@ -133,7 +133,7 @@ private struct VaultItemSelectionSearchableView: View {
|
||||
.task {
|
||||
await store.perform(.streamVaultItems)
|
||||
}
|
||||
.task(id: store.state.searchText) {
|
||||
.searchDebouncedTask(id: store.state.searchText) {
|
||||
await store.perform(.search(store.state.searchText))
|
||||
}
|
||||
.toast(
|
||||
|
||||
@ -334,7 +334,7 @@ struct VaultListView: View {
|
||||
prompt: Localizations.search,
|
||||
)
|
||||
.autocorrectionDisabled(true)
|
||||
.task(id: store.state.searchText) {
|
||||
.searchDebouncedTask(id: store.state.searchText) {
|
||||
await store.perform(.search(store.state.searchText))
|
||||
}
|
||||
.task(id: store.state.searchVaultFilterType) {
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user