Prevent Bluetooth alerts from competing with sheets

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