196 lines
8.5 KiB
Swift
196 lines
8.5 KiB
Swift
import SwiftUI
|
||
import os.log
|
||
|
||
struct BlindOutcomeView: View {
|
||
let media: MediaType
|
||
let title: String?
|
||
let description: String?
|
||
let isMember: Bool
|
||
let onContinue: () -> Void
|
||
let showJoinModal: Bool
|
||
|
||
// Removed presentationMode; use Router.shared.pop() for back navigation
|
||
@State private var showIPListModal = false
|
||
|
||
init(media: MediaType, title: String? = nil, description: String? = nil, isMember: Bool = false, onContinue: @escaping () -> Void, showJoinModal: Bool = false) {
|
||
self.media = media
|
||
self.title = title
|
||
self.description = description
|
||
self.isMember = isMember
|
||
self.onContinue = onContinue
|
||
self.showJoinModal = showJoinModal
|
||
}
|
||
|
||
var body: some View {
|
||
ZStack {
|
||
Color.themeTextWhiteSecondary.ignoresSafeArea()
|
||
|
||
VStack(spacing: 0) {
|
||
// 通用导航栏
|
||
// NaviHeader(
|
||
// title: "Blind Box",
|
||
// onBackTap: { Router.shared.pop() },
|
||
// showBackButton: true,
|
||
// titleStyle: .title,
|
||
// backgroundColor: Color.themeTextWhiteSecondary
|
||
// )
|
||
// .zIndex(1)
|
||
Spacer()
|
||
.frame(height: Theme.Spacing.lg)
|
||
// Media content
|
||
GeometryReader { geometry in
|
||
VStack(spacing: 16) {
|
||
ZStack {
|
||
RoundedRectangle(cornerRadius: 12)
|
||
.fill(Color.white)
|
||
.shadow(color: Color.black.opacity(0.1), radius: 8, x: 0, y: 2)
|
||
|
||
VStack(spacing: 0) {
|
||
switch media {
|
||
case .image(let uiImage):
|
||
Image(uiImage: uiImage)
|
||
.resizable()
|
||
.scaledToFit()
|
||
.frame(maxWidth: .infinity, maxHeight: .infinity)
|
||
.cornerRadius(10)
|
||
.padding(4)
|
||
// 图片不启用全屏切换
|
||
|
||
case .video(let url, _):
|
||
WakeVideoPlayer(
|
||
url: url,
|
||
autoPlay: true,
|
||
isLooping: true,
|
||
showsControls: true,
|
||
allowFullscreen: true,
|
||
muteInitially: false,
|
||
videoGravity: .resizeAspect
|
||
)
|
||
.frame(width: UIScreen.main.bounds.width - 40)
|
||
.background(Color.clear)
|
||
.cornerRadius(10)
|
||
.clipped()
|
||
}
|
||
|
||
if let description = description, !description.isEmpty {
|
||
VStack(alignment: .leading, spacing: 2) {
|
||
// Text("Description")
|
||
// .font(Typography.font(for: .body, family: .quicksandBold))
|
||
// .foregroundColor(.themeTextMessageMain)
|
||
Text(description)
|
||
.font(.system(size: 12))
|
||
.foregroundColor(Color.themeTextMessageMain)
|
||
.fixedSize(horizontal: false, vertical: true)
|
||
}
|
||
.padding(Theme.Spacing.lg)
|
||
}
|
||
}
|
||
.padding(.top, 8)
|
||
}
|
||
}
|
||
.frame(maxWidth: .infinity, maxHeight: .infinity, alignment: .top)
|
||
.padding(.bottom, 20)
|
||
}
|
||
.padding(.horizontal)
|
||
|
||
Spacer()
|
||
|
||
// Button at bottom
|
||
VStack {
|
||
Spacer()
|
||
Button(action: {
|
||
if showJoinModal {
|
||
withAnimation {
|
||
showIPListModal = true
|
||
}
|
||
} else {
|
||
onContinue()
|
||
}
|
||
}) {
|
||
Text("Continue")
|
||
.font(.headline)
|
||
.foregroundColor(.themeTextMessageMain)
|
||
.frame(maxWidth: .infinity)
|
||
.padding()
|
||
.background(Color.themePrimary)
|
||
.cornerRadius(26)
|
||
}
|
||
// 弹窗显示时,按钮淡出且不可交互
|
||
.opacity(showIPListModal ? 0 : 1)
|
||
.animation(.easeInOut(duration: 0.2), value: showIPListModal)
|
||
.allowsHitTesting(!showIPListModal)
|
||
.padding(.horizontal)
|
||
}
|
||
.padding(.bottom, 20)
|
||
}
|
||
}
|
||
.navigationBarHidden(true)
|
||
|
||
|
||
.navigationBarBackButtonHidden(true)
|
||
.overlay(
|
||
JoinModal(isPresented: $showIPListModal, onClose: { onContinue() })
|
||
)
|
||
}
|
||
}
|
||
|
||
|
||
|
||
#if DEBUG
|
||
// MARK: - Previews
|
||
struct BlindOutcomeView_Previews: PreviewProvider {
|
||
private static func coloredImage(_ color: UIColor, size: CGSize = CGSize(width: 300, height: 300)) -> UIImage {
|
||
let format = UIGraphicsImageRendererFormat()
|
||
format.scale = 2
|
||
let renderer = UIGraphicsImageRenderer(size: size, format: format)
|
||
return renderer.image { ctx in
|
||
color.setFill()
|
||
ctx.fill(CGRect(origin: .zero, size: size))
|
||
}
|
||
}
|
||
|
||
private static func remoteImage(_ urlString: String, placeholder: UIColor = .systemPink, size: CGSize = CGSize(width: 300, height: 300)) -> UIImage {
|
||
if let url = URL(string: urlString),
|
||
let data = try? Data(contentsOf: url),
|
||
let image = UIImage(data: data) {
|
||
return image
|
||
}
|
||
return coloredImage(placeholder, size: size)
|
||
}
|
||
|
||
static var previews: some View {
|
||
Group {
|
||
// 预览 1:含描述与时间,非会员
|
||
BlindOutcomeView(
|
||
media: .image(remoteImage("https://cdn.memorywake.com/files/7350515957925810176/original_1752499572813_screenshot-20250514-170854.png")),
|
||
title: "00:23",
|
||
description: "这是一段示例描述,用于在预览中验证样式与布局。",
|
||
isMember: false,
|
||
onContinue: {}
|
||
)
|
||
.previewDisplayName("Image • With Description • Guest")
|
||
|
||
// 预览 2:无描述无时间,会员
|
||
BlindOutcomeView(
|
||
media: .image(remoteImage("https://cdn.memorywake.com/files/7350515957925810176/original_1752499572813_screenshot-20250514-170854.png")),
|
||
title: nil,
|
||
description: nil,
|
||
isMember: true,
|
||
onContinue: {}
|
||
)
|
||
.previewDisplayName("Image • Minimal • Member")
|
||
|
||
// 预览 3:视频示例
|
||
BlindOutcomeView(
|
||
media: .video(URL(string: "https://cdn.memorywake.com/users/7350439663116619888/files/7361241959983353857/7361241920703696897.mp4")!, nil),
|
||
title: "00:23",
|
||
description: "视频预览示例",
|
||
isMember: false,
|
||
onContinue: {}
|
||
)
|
||
.previewDisplayName("Video • With Description • Guest")
|
||
}
|
||
}
|
||
}
|
||
#endif
|