68 lines
2.2 KiB
Swift
68 lines
2.2 KiB
Swift
//
|
|
// Copyright 2023, 2024 New Vector Ltd.
|
|
//
|
|
// SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-Element-Commercial
|
|
// Please see LICENSE files in the repository root for full details.
|
|
//
|
|
|
|
import Compound
|
|
import SwiftUI
|
|
import SwiftUIIntrospect
|
|
|
|
extension View {
|
|
@ViewBuilder
|
|
func bloom() -> some View {
|
|
modifier(BloomModifier())
|
|
}
|
|
}
|
|
|
|
private struct BloomModifier: ViewModifier {
|
|
@State private var standardAppearance = UINavigationBarAppearance()
|
|
@State private var scrollEdgeAppearance = UINavigationBarAppearance()
|
|
|
|
@State private var bloomGradientImage: UIImage?
|
|
|
|
func body(content: Content) -> some View {
|
|
content
|
|
.introspect(.viewController, on: .supportedVersions, customize: configureBloom)
|
|
}
|
|
|
|
private func configureBloom(controller: UIViewController) {
|
|
guard controller.navigationItem.standardAppearance != standardAppearance,
|
|
controller.navigationItem.scrollEdgeAppearance != scrollEdgeAppearance else {
|
|
return
|
|
}
|
|
|
|
let image = makeBloomImage()
|
|
|
|
standardAppearance.configureWithDefaultBackground()
|
|
standardAppearance.backgroundImage = image
|
|
standardAppearance.backgroundImageContentMode = .scaleToFill
|
|
controller.navigationItem.standardAppearance = standardAppearance
|
|
|
|
scrollEdgeAppearance.configureWithTransparentBackground()
|
|
scrollEdgeAppearance.backgroundImage = image
|
|
scrollEdgeAppearance.backgroundImageContentMode = .scaleToFill
|
|
scrollEdgeAppearance.backgroundColor = .compound.bgCanvasDefault
|
|
controller.navigationItem.scrollEdgeAppearance = scrollEdgeAppearance
|
|
}
|
|
|
|
private func makeBloomImage() -> UIImage? {
|
|
if let bloomGradientImage {
|
|
return bloomGradientImage
|
|
}
|
|
|
|
let newImage = ImageRenderer(content: bloomGradient).uiImage
|
|
Task { bloomGradientImage = newImage }
|
|
return newImage
|
|
}
|
|
|
|
private var bloomGradient: some View {
|
|
LinearGradient(gradient: .compound.subtle,
|
|
startPoint: .top,
|
|
endPoint: .init(x: 0.5, y: 0.7))
|
|
.ignoresSafeArea(edges: .all)
|
|
.frame(width: 256, height: 256)
|
|
}
|
|
}
|