Prevent Bluetooth alerts from competing with sheets

This commit is contained in:
jack
2026-07-25 23:49:42 +02:00
parent af84a702ac
commit 62cccc1c78
3 changed files with 87 additions and 18 deletions
+24 -8
View File
@@ -6,6 +6,18 @@ import UIKit
import AppKit
#endif
struct ContentPeopleSheetModalPresentationState {
var isImagePreviewPresented = false
var isVerificationSheetPresented = false
var isMediaPickerPresented = false
var hasPresentation: Bool {
isImagePreviewPresented
|| isVerificationSheetPresented
|| isMediaPickerPresented
}
}
struct ContentPeopleSheetView: View {
@EnvironmentObject private var appChromeModel: AppChromeModel
@EnvironmentObject private var privateConversationModel: PrivateConversationModel
@@ -24,6 +36,7 @@ struct ContentPeopleSheetView: View {
var isTextFieldFocused: FocusState<Bool>.Binding
@ObservedObject var voiceRecordingVM: VoiceRecordingViewModel
@Binding var autocompleteDebounceTimer: Timer?
@State private var showVerifySheet = false
@ThemedPalette private var palette
let headerHeight: CGFloat
@@ -37,14 +50,17 @@ struct ContentPeopleSheetView: View {
#endif
private var hasModalPresentation: Bool {
if imagePreviewURL != nil {
return true
}
#if os(iOS)
return showImagePicker
let isMediaPickerPresented = showImagePicker
#else
return showMacImagePicker
let isMediaPickerPresented = showMacImagePicker
#endif
return ContentPeopleSheetModalPresentationState(
isImagePreviewPresented: imagePreviewURL != nil,
isVerificationSheetPresented: showVerifySheet,
isMediaPickerPresented: isMediaPickerPresented
).hasPresentation
}
private var bluetoothAlertBinding: Binding<Bool> {
@@ -108,7 +124,8 @@ struct ContentPeopleSheetView: View {
#endif
} else {
ContentPeopleListView(
showSidebar: $showSidebar
showSidebar: $showSidebar,
showVerifySheet: $showVerifySheet
)
}
}
@@ -237,8 +254,7 @@ private struct ContentPeopleListView: View {
@ThemedPalette private var palette
@Binding var showSidebar: Bool
@State private var showVerifySheet = false
@Binding var showVerifySheet: Bool
var body: some View {
VStack(spacing: 0) {
+38 -10
View File
@@ -14,6 +14,30 @@ import AppKit
#endif
import BitFoundation
struct ContentRootModalPresentationState {
var isPeopleSheetPresented = false
var isAppInfoPresented = false
var isFingerprintPresented = false
var isLocationChannelsSheetPresented = false
var isNoticesSheetPresented = false
var isImagePreviewPresented = false
var isVerificationSheetPresented = false
var isVoiceAlertPresented = false
var isMediaPickerPresented = false
var hasPresentation: Bool {
isPeopleSheetPresented
|| isAppInfoPresented
|| isFingerprintPresented
|| isLocationChannelsSheetPresented
|| isNoticesSheetPresented
|| isImagePreviewPresented
|| isVerificationSheetPresented
|| isVoiceAlertPresented
|| isMediaPickerPresented
}
}
/// On macOS 14+, disables the default system focus ring on TextFields.
/// On earlier macOS versions and on iOS this is a no-op.
struct FocusEffectDisabledModifier: ViewModifier {
@@ -77,19 +101,23 @@ struct ContentView: View {
}
private var hasRootModalPresentation: Bool {
if isPeopleSheetPresented
|| appChromeModel.isAppInfoPresented
|| appChromeModel.showingFingerprintFor != nil
|| imagePreviewURL != nil
|| showVerifySheet
|| voiceRecordingVM.showAlert {
return true
}
#if os(iOS)
return showImagePicker
let isMediaPickerPresented = showImagePicker
#else
return showMacImagePicker
let isMediaPickerPresented = showMacImagePicker
#endif
return ContentRootModalPresentationState(
isPeopleSheetPresented: isPeopleSheetPresented,
isAppInfoPresented: appChromeModel.isAppInfoPresented,
isFingerprintPresented: appChromeModel.showingFingerprintFor != nil,
isLocationChannelsSheetPresented: appChromeModel.isLocationChannelsSheetPresented,
isNoticesSheetPresented: appChromeModel.isNoticesSheetPresented,
isImagePreviewPresented: imagePreviewURL != nil,
isVerificationSheetPresented: showVerifySheet,
isVoiceAlertPresented: voiceRecordingVM.showAlert,
isMediaPickerPresented: isMediaPickerPresented
).hasPresentation
}
private var rootBluetoothAlertBinding: Binding<Bool> {
+25
View File
@@ -551,6 +551,31 @@ struct ViewSmokeTests {
#expect(featureModels.privateConversationModel.selectedHeaderState?.headerPeerID == peerID)
}
@Test("Root Bluetooth alert waits for location and notices sheets")
func rootBluetoothAlertGuard_includesHeaderSheets() {
#expect(!ContentRootModalPresentationState().hasPresentation)
#expect(
ContentRootModalPresentationState(
isLocationChannelsSheetPresented: true
).hasPresentation
)
#expect(
ContentRootModalPresentationState(
isNoticesSheetPresented: true
).hasPresentation
)
}
@Test("People-sheet Bluetooth alert waits for local verification sheet")
func peopleSheetBluetoothAlertGuard_includesVerificationSheet() {
#expect(!ContentPeopleSheetModalPresentationState().hasPresentation)
#expect(
ContentPeopleSheetModalPresentationState(
isVerificationSheetPresented: true
).hasPresentation
)
}
@Test
func geohashAndTextMessageViews_renderCoreBranches() {
let (viewModel, _, _) = makeSmokeViewModel()