diff --git a/bitchat/Views/ContentSheetViews.swift b/bitchat/Views/ContentSheetViews.swift index ccce756a..49d069c1 100644 --- a/bitchat/Views/ContentSheetViews.swift +++ b/bitchat/Views/ContentSheetViews.swift @@ -11,6 +11,7 @@ struct ContentPeopleSheetView: View { @EnvironmentObject private var privateConversationModel: PrivateConversationModel @EnvironmentObject private var verificationModel: VerificationModel @EnvironmentObject private var conversationUIModel: ConversationUIModel + @Environment(\.scenePhase) private var scenePhase @Binding var showSidebar: Bool @Binding var messageText: String @@ -35,6 +36,35 @@ struct ContentPeopleSheetView: View { @Binding var showMacImagePicker: Bool #endif + private var hasModalPresentation: Bool { + if imagePreviewURL != nil { + return true + } + #if os(iOS) + return showImagePicker + #else + return showMacImagePicker + #endif + } + + private var bluetoothAlertBinding: Binding { + Binding( + get: { + scenePhase == .active + && appChromeModel.showBluetoothAlert + && !hasModalPresentation + }, + set: { isPresented in + guard !isPresented, + scenePhase == .active, + !hasModalPresentation else { + return + } + appChromeModel.showBluetoothAlert = false + } + ) + } + var body: some View { let legacyConsentRequest = conversationUIModel.legacyPrivateMediaConsentRequest NavigationStack { @@ -182,6 +212,17 @@ struct ContentPeopleSheetView: View { } } #endif + .alert( + "content.alert.bluetooth_required.title", + isPresented: bluetoothAlertBinding + ) { + Button("content.alert.bluetooth_required.settings") { + SystemSettings.bluetooth.open() + } + Button("common.ok", role: .cancel) {} + } message: { + Text(appChromeModel.bluetoothAlertMessage) + } } } diff --git a/bitchat/Views/ContentView.swift b/bitchat/Views/ContentView.swift index a8134ed9..596ffd5e 100644 --- a/bitchat/Views/ContentView.swift +++ b/bitchat/Views/ContentView.swift @@ -42,6 +42,7 @@ struct ContentView: View { @FocusState private var isTextFieldFocused: Bool @Environment(\.colorScheme) var colorScheme @Environment(\.appTheme) private var appTheme + @Environment(\.scenePhase) private var scenePhase @State private var showSidebar = false @State private var selectedMessageSender: String? @State private var selectedMessageSenderID: PeerID? @@ -71,6 +72,44 @@ struct ContentView: View { private var usesGlassLayout: Bool { appTheme.usesGlassChrome } + private var isPeopleSheetPresented: Bool { + showSidebar || selectedPrivatePeerID != nil + } + + private var hasRootModalPresentation: Bool { + if isPeopleSheetPresented + || appChromeModel.isAppInfoPresented + || appChromeModel.showingFingerprintFor != nil + || imagePreviewURL != nil + || showVerifySheet + || voiceRecordingVM.showAlert { + return true + } + #if os(iOS) + return showImagePicker + #else + return showMacImagePicker + #endif + } + + private var rootBluetoothAlertBinding: Binding { + Binding( + get: { + scenePhase == .active + && appChromeModel.showBluetoothAlert + && !hasRootModalPresentation + }, + set: { isPresented in + guard !isPresented, + scenePhase == .active, + !hasRootModalPresentation else { + return + } + appChromeModel.showBluetoothAlert = false + } + ) + } + var body: some View { mainContent .onAppear { @@ -107,11 +146,18 @@ struct ContentView: View { } .sheet( isPresented: Binding( - get: { showSidebar || selectedPrivatePeerID != nil }, + get: { isPeopleSheetPresented }, set: { isPresented in if !isPresented { showSidebar = false - privateConversationModel.endConversation() + // Scene/background and Bluetooth-alert presentation + // reconciliation are not user requests to leave the + // conversation. Keep the selected DM so the sheet + // remains live when the app returns from Settings. + if scenePhase == .active, + !appChromeModel.showBluetoothAlert { + privateConversationModel.endConversation() + } } } ) @@ -222,7 +268,7 @@ struct ContentView: View { }, message: { Text(voiceRecordingVM.state.alertMessage) }) - .alert("content.alert.bluetooth_required.title", isPresented: $appChromeModel.showBluetoothAlert) { + .alert("content.alert.bluetooth_required.title", isPresented: rootBluetoothAlertBinding) { Button("content.alert.bluetooth_required.settings") { SystemSettings.bluetooth.open() }