@@ -127,27 +127,32 @@ struct HomeView: View {
127127
128128 private let pairingFileURL = URL . documentsDirectory. appendingPathComponent ( " pairingFile.plist " )
129129
130+ @ViewBuilder
131+ private var homeContent : some View {
132+ VStack ( spacing: 20 ) {
133+ welcomeCard
134+ setupCard
135+ connectCard
136+ // if pairingFileExists {
137+ // quickConnectCard
138+ // }
139+ if !pinnedLaunchItems. isEmpty {
140+ launchShortcutsCard
141+ }
142+ tipsCard
143+ }
144+ . padding ( . horizontal, 20 )
145+ . padding ( . vertical, 30 )
146+ }
147+
130148 var body : some View {
131149 NavigationStack {
132150 ZStack {
133151 ThemedBackground ( style: backgroundStyle)
134152 . ignoresSafeArea ( )
135153
136154 ScrollView {
137- VStack ( spacing: 20 ) {
138- welcomeCard
139- setupCard
140- connectCard
141- // if pairingFileExists {
142- // quickConnectCard
143- // }
144- if !pinnedLaunchItems. isEmpty {
145- launchShortcutsCard
146- }
147- tipsCard
148- }
149- . padding ( . horizontal, 20 )
150- . padding ( . vertical, 30 )
155+ homeContent
151156 }
152157 . scrollIndicators ( . hidden)
153158
@@ -1206,15 +1211,65 @@ struct HomeView: View {
12061211 private func homeCard< Content: View > ( @ViewBuilder content: ( ) -> Content ) -> some View {
12071212 content ( )
12081213 . padding ( 20 )
1209- . background (
1210- RoundedRectangle ( cornerRadius: 20 , style: . continuous)
1211- . fill ( . ultraThinMaterial)
1212- . overlay (
1213- RoundedRectangle ( cornerRadius: 20 , style: . continuous)
1214- . strokeBorder ( Color . white. opacity ( 0.15 ) , lineWidth: 1 )
1215- )
1216- )
1217- . shadow ( color: . black. opacity ( 0.15 ) , radius: 12 , x: 0 , y: 4 )
1214+ . background ( UIKitCardBackground ( ) )
1215+ }
1216+
1217+ // UIKit blur/shadow chrome keeps heavy effects out of SwiftUI while leaving layout in SwiftUI so the content still renders.
1218+ private struct UIKitCardBackground : UIViewRepresentable {
1219+ func makeUIView( context: Context ) -> CardChromeView {
1220+ CardChromeView ( )
1221+ }
1222+
1223+ func updateUIView( _ uiView: CardChromeView , context: Context ) {
1224+ uiView. setNeedsLayout ( )
1225+ }
1226+ }
1227+
1228+ private final class CardChromeView : UIView {
1229+ private let blurView = UIVisualEffectView ( effect: UIBlurEffect ( style: . systemUltraThinMaterial) )
1230+ private let strokeLayer = CAShapeLayer ( )
1231+
1232+ override init ( frame: CGRect ) {
1233+ super. init ( frame: frame)
1234+ backgroundColor = . clear
1235+ isUserInteractionEnabled = false
1236+
1237+ layer. cornerRadius = 20
1238+ layer. cornerCurve = . continuous
1239+ layer. masksToBounds = false
1240+ layer. shadowColor = UIColor . black. withAlphaComponent ( 0.15 ) . cgColor
1241+ layer. shadowOpacity = 1
1242+ layer. shadowRadius = 12
1243+ layer. shadowOffset = CGSize ( width: 0 , height: 4 )
1244+
1245+ blurView. translatesAutoresizingMaskIntoConstraints = false
1246+ blurView. clipsToBounds = true
1247+ blurView. layer. cornerRadius = 20
1248+ blurView. layer. cornerCurve = . continuous
1249+ addSubview ( blurView)
1250+
1251+ NSLayoutConstraint . activate ( [
1252+ blurView. leadingAnchor. constraint ( equalTo: leadingAnchor) ,
1253+ blurView. trailingAnchor. constraint ( equalTo: trailingAnchor) ,
1254+ blurView. topAnchor. constraint ( equalTo: topAnchor) ,
1255+ blurView. bottomAnchor. constraint ( equalTo: bottomAnchor)
1256+ ] )
1257+
1258+ strokeLayer. strokeColor = UIColor . white. withAlphaComponent ( 0.15 ) . cgColor
1259+ strokeLayer. fillColor = UIColor . clear. cgColor
1260+ layer. addSublayer ( strokeLayer)
1261+ }
1262+
1263+ required init ? ( coder: NSCoder ) {
1264+ nil
1265+ }
1266+
1267+ override func layoutSubviews( ) {
1268+ super. layoutSubviews ( )
1269+ strokeLayer. frame = bounds
1270+ strokeLayer. path = UIBezierPath ( roundedRect: bounds, cornerRadius: 20 ) . cgPath
1271+ layer. shadowPath = strokeLayer. path
1272+ }
12181273 }
12191274
12201275 private func compactControlButton( icon: String , title: String , showSpinner: Bool = false ) -> some View {
0 commit comments