mirror of
https://github.com/Novaloop-AG/element-x-ios.git
synced 2026-11-03 06:55:59 +00:00
Scope dark mode change only to the presenting sheet (#6144)
* Scope dark mode change only to the presenting sheet, instead of the whole window * Apply review suggestions to the presentation colour scheme modifier API: - Take a `ColorScheme?` at the SwiftUI level instead of a `UIUserInterfaceStyle` and map it once inside the representable (`nil` means no override). - Rename to `presentationColorScheme` and the file to match. - Restore the `preferredColorScheme` property on the media preview details and redact confirmation views, and the `nil` at the media timeline call site, so no UIKit types leak into the views. Cleanup: - Walk the responder chain with `sequence(first:next:)` instead of a while loop. * Re-record the media upload preview iPad snapshots The Cancel button no longer has an explicit tint, so its label colour changed very slightly from `textActionPrimary` to the default. Only the iPad references include the toolbar, which is why the iPhone ones were unaffected.
This commit is contained in:
@@ -0,0 +1,79 @@
|
||||
//
|
||||
// Copyright 2026 Element Creations Ltd.
|
||||
//
|
||||
// SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-Element-Commercial.
|
||||
// Please see LICENSE files in the repository root for full details.
|
||||
//
|
||||
|
||||
import SwiftUI
|
||||
|
||||
extension View {
|
||||
/// Forces the colour scheme of the sheet or popover containing this view without touching the
|
||||
/// rest of the app. Does nothing when the view isn't presented modally or the scheme is `nil`.
|
||||
///
|
||||
/// Prefer this over `preferredColorScheme` for modals: SwiftUI applies that modifier to the whole
|
||||
/// window and can leave it applied when the presentation is torn down abnormally (#6093).
|
||||
func presentationColorScheme(_ colorScheme: ColorScheme?) -> some View {
|
||||
background(PresentationColorSchemeView(colorScheme: colorScheme))
|
||||
}
|
||||
}
|
||||
|
||||
private struct PresentationColorSchemeView: UIViewRepresentable {
|
||||
let colorScheme: ColorScheme?
|
||||
|
||||
func makeUIView(context: Context) -> InterfaceStyleView {
|
||||
InterfaceStyleView(style: UIUserInterfaceStyle(colorScheme))
|
||||
}
|
||||
|
||||
func updateUIView(_ uiView: InterfaceStyleView, context: Context) {
|
||||
uiView.style = UIUserInterfaceStyle(colorScheme)
|
||||
}
|
||||
|
||||
class InterfaceStyleView: UIView {
|
||||
var style: UIUserInterfaceStyle {
|
||||
didSet { applyStyle() }
|
||||
}
|
||||
|
||||
init(style: UIUserInterfaceStyle) {
|
||||
self.style = style
|
||||
super.init(frame: .zero)
|
||||
isUserInteractionEnabled = false
|
||||
}
|
||||
|
||||
@available(*, unavailable)
|
||||
required init?(coder: NSCoder) {
|
||||
fatalError("init(coder:) has not been implemented")
|
||||
}
|
||||
|
||||
override func didMoveToWindow() {
|
||||
super.didMoveToWindow()
|
||||
applyStyle()
|
||||
}
|
||||
|
||||
private func applyStyle() {
|
||||
guard window != nil else { return }
|
||||
targetViewController?.overrideUserInterfaceStyle = style
|
||||
}
|
||||
|
||||
/// The view controller that was actually presented, so the override covers its navigation bar too.
|
||||
private var targetViewController: UIViewController? {
|
||||
guard let next else { return nil }
|
||||
return sequence(first: next) { $0.next }
|
||||
.lazy
|
||||
.compactMap { $0 as? UIViewController }
|
||||
// Children of a presented controller also report a presentingViewController, so check the parent.
|
||||
.first { $0.presentingViewController != nil && $0.parent == nil }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private extension UIUserInterfaceStyle {
|
||||
init(_ colorScheme: ColorScheme?) {
|
||||
self = switch colorScheme {
|
||||
case .light: .light
|
||||
case .dark: .dark
|
||||
case .none: .unspecified
|
||||
@unknown default: .unspecified
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user