101 lines
3.4 KiB
Swift
101 lines
3.4 KiB
Swift
//
|
||
// ScenicPromotionMediaArtworkView.swift
|
||
// suixinkan
|
||
//
|
||
// Created by Codex on 2026/7/2.
|
||
//
|
||
|
||
import SwiftUI
|
||
|
||
/// 宣传页素材图片渲染组件,支持缩略图与主视觉两种尺寸。
|
||
struct ScenicPromotionMediaArtwork: View {
|
||
let media: ScenicPromotionMedia
|
||
let compact: Bool
|
||
let useHeroAsset: Bool
|
||
|
||
var body: some View {
|
||
GeometryReader { proxy in
|
||
if let assetName = useHeroAsset ? (media.heroAssetName ?? media.assetName) : media.assetName {
|
||
Image(assetName)
|
||
.resizable()
|
||
.scaledToFill()
|
||
.frame(width: proxy.size.width, height: proxy.size.height)
|
||
.clipped()
|
||
} else {
|
||
ZStack {
|
||
LinearGradient(
|
||
colors: media.palette.map { Color(hex: $0) },
|
||
startPoint: .topLeading,
|
||
endPoint: .bottomTrailing
|
||
)
|
||
|
||
ScenicPromotionMountainLayer()
|
||
.fill(.white.opacity(0.28))
|
||
.frame(height: proxy.size.height * 0.45)
|
||
.offset(y: proxy.size.height * 0.02)
|
||
|
||
ScenicPromotionMountainLayer()
|
||
.fill(Color(hex: 0x0F5B85, alpha: 0.22))
|
||
.frame(height: proxy.size.height * 0.38)
|
||
.offset(y: proxy.size.height * 0.13)
|
||
|
||
VStack {
|
||
Spacer()
|
||
Rectangle()
|
||
.fill(Color(hex: 0x2D9D4E, alpha: 0.52))
|
||
.frame(height: proxy.size.height * 0.2)
|
||
}
|
||
|
||
if !compact {
|
||
Image(systemName: "figure.walk")
|
||
.font(.system(size: 74, weight: .bold))
|
||
.foregroundStyle(.white.opacity(0.82))
|
||
.offset(x: proxy.size.width * 0.23, y: proxy.size.height * 0.1)
|
||
}
|
||
}
|
||
}
|
||
}
|
||
.clipShape(RoundedRectangle(cornerRadius: compact ? 12 : 18))
|
||
}
|
||
}
|
||
|
||
/// 没有本地图片资源时使用的备用山形占位图。
|
||
struct ScenicPromotionMountainLayer: Shape {
|
||
func path(in rect: CGRect) -> Path {
|
||
var path = Path()
|
||
path.move(to: CGPoint(x: rect.minX, y: rect.maxY))
|
||
path.addLine(to: CGPoint(x: rect.width * 0.16, y: rect.height * 0.42))
|
||
path.addLine(to: CGPoint(x: rect.width * 0.28, y: rect.height * 0.68))
|
||
path.addLine(to: CGPoint(x: rect.width * 0.42, y: rect.height * 0.25))
|
||
path.addLine(to: CGPoint(x: rect.width * 0.58, y: rect.height * 0.6))
|
||
path.addLine(to: CGPoint(x: rect.width * 0.76, y: rect.height * 0.18))
|
||
path.addLine(to: CGPoint(x: rect.maxX, y: rect.height * 0.56))
|
||
path.addLine(to: CGPoint(x: rect.maxX, y: rect.maxY))
|
||
path.closeSubpath()
|
||
return path
|
||
}
|
||
}
|
||
|
||
#if DEBUG
|
||
#Preview("素材缩略图") {
|
||
ScenicPromotionMediaArtwork(
|
||
media: ScenicPromotionPreviewSupport.sampleVideoMedia,
|
||
compact: true,
|
||
useHeroAsset: false
|
||
)
|
||
.frame(width: 72, height: 66)
|
||
.padding()
|
||
}
|
||
|
||
#Preview("素材主视觉") {
|
||
ScenicPromotionMediaArtwork(
|
||
media: ScenicPromotionPreviewSupport.sampleVideoMedia,
|
||
compact: false,
|
||
useHeroAsset: true
|
||
)
|
||
.frame(maxWidth: .infinity)
|
||
.frame(height: 220)
|
||
.padding()
|
||
}
|
||
#endif
|