feat: 订阅卡片
This commit is contained in:
parent
da842c8e7c
commit
8d5d69fb4a
@ -7,6 +7,8 @@
|
||||
objects = {
|
||||
|
||||
/* Begin PBXBuildFile section */
|
||||
AB6693CA2E65C94400BCAAC1 /* SVGKit in Frameworks */ = {isa = PBXBuildFile; productRef = AB6693C92E65C94400BCAAC1 /* SVGKit */; };
|
||||
AB6693CC2E65C94400BCAAC1 /* SVGKitSwift in Frameworks */ = {isa = PBXBuildFile; productRef = AB6693CB2E65C94400BCAAC1 /* SVGKitSwift */; };
|
||||
AB8773632E4E04400071CB53 /* .gitignore in Resources */ = {isa = PBXBuildFile; fileRef = AB8773622E4E040E0071CB53 /* .gitignore */; };
|
||||
ABC150C12E5DB39A00A1F970 /* Lottie in Frameworks */ = {isa = PBXBuildFile; productRef = ABC150C02E5DB39A00A1F970 /* Lottie */; };
|
||||
ABE8998E2E533A7100CD7BA6 /* Alamofire in Frameworks */ = {isa = PBXBuildFile; productRef = ABE8998D2E533A7100CD7BA6 /* Alamofire */; };
|
||||
@ -57,6 +59,8 @@
|
||||
isa = PBXFrameworksBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
AB6693CC2E65C94400BCAAC1 /* SVGKitSwift in Frameworks */,
|
||||
AB6693CA2E65C94400BCAAC1 /* SVGKit in Frameworks */,
|
||||
ABE8998E2E533A7100CD7BA6 /* Alamofire in Frameworks */,
|
||||
ABC150C12E5DB39A00A1F970 /* Lottie in Frameworks */,
|
||||
);
|
||||
@ -114,6 +118,8 @@
|
||||
packageProductDependencies = (
|
||||
ABE8998D2E533A7100CD7BA6 /* Alamofire */,
|
||||
ABC150C02E5DB39A00A1F970 /* Lottie */,
|
||||
AB6693C92E65C94400BCAAC1 /* SVGKit */,
|
||||
AB6693CB2E65C94400BCAAC1 /* SVGKitSwift */,
|
||||
);
|
||||
productName = wake;
|
||||
productReference = ABB4E2082E4B75D900660198 /* wake.app */;
|
||||
@ -146,6 +152,7 @@
|
||||
packageReferences = (
|
||||
ABE8998C2E533A7100CD7BA6 /* XCRemoteSwiftPackageReference "Alamofire" */,
|
||||
ABC150BF2E5DB39A00A1F970 /* XCRemoteSwiftPackageReference "lottie-spm" */,
|
||||
AB6693C82E65C94400BCAAC1 /* XCRemoteSwiftPackageReference "SVGKit" */,
|
||||
);
|
||||
preferredProjectObjectVersion = 77;
|
||||
productRefGroup = ABB4E2092E4B75D900660198 /* Products */;
|
||||
@ -392,6 +399,14 @@
|
||||
/* End XCConfigurationList section */
|
||||
|
||||
/* Begin XCRemoteSwiftPackageReference section */
|
||||
AB6693C82E65C94400BCAAC1 /* XCRemoteSwiftPackageReference "SVGKit" */ = {
|
||||
isa = XCRemoteSwiftPackageReference;
|
||||
repositoryURL = "https://github.com/SVGKit/SVGKit.git";
|
||||
requirement = {
|
||||
kind = upToNextMajorVersion;
|
||||
minimumVersion = 3.0.0;
|
||||
};
|
||||
};
|
||||
ABC150BF2E5DB39A00A1F970 /* XCRemoteSwiftPackageReference "lottie-spm" */ = {
|
||||
isa = XCRemoteSwiftPackageReference;
|
||||
repositoryURL = "https://github.com/airbnb/lottie-spm.git";
|
||||
@ -411,6 +426,16 @@
|
||||
/* End XCRemoteSwiftPackageReference section */
|
||||
|
||||
/* Begin XCSwiftPackageProductDependency section */
|
||||
AB6693C92E65C94400BCAAC1 /* SVGKit */ = {
|
||||
isa = XCSwiftPackageProductDependency;
|
||||
package = AB6693C82E65C94400BCAAC1 /* XCRemoteSwiftPackageReference "SVGKit" */;
|
||||
productName = SVGKit;
|
||||
};
|
||||
AB6693CB2E65C94400BCAAC1 /* SVGKitSwift */ = {
|
||||
isa = XCSwiftPackageProductDependency;
|
||||
package = AB6693C82E65C94400BCAAC1 /* XCRemoteSwiftPackageReference "SVGKit" */;
|
||||
productName = SVGKitSwift;
|
||||
};
|
||||
ABC150C02E5DB39A00A1F970 /* Lottie */ = {
|
||||
isa = XCSwiftPackageProductDependency;
|
||||
package = ABC150BF2E5DB39A00A1F970 /* XCRemoteSwiftPackageReference "lottie-spm" */;
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
{
|
||||
"originHash" : "0e95cd18402f001189cea942918f7d0c4c8b04175c6c482029650c892d28d55a",
|
||||
"originHash" : "d4b9379b4bd658fe79a6ae528c96d3386427dfe9d23635a65dad6edf12af85ff",
|
||||
"pins" : [
|
||||
{
|
||||
"identity" : "alamofire",
|
||||
@ -10,6 +10,15 @@
|
||||
"version" : "5.10.2"
|
||||
}
|
||||
},
|
||||
{
|
||||
"identity" : "cocoalumberjack",
|
||||
"kind" : "remoteSourceControl",
|
||||
"location" : "https://github.com/CocoaLumberjack/CocoaLumberjack.git",
|
||||
"state" : {
|
||||
"revision" : "a9ed4b6f9bdedce7d77046f43adfb8ce1fd54114",
|
||||
"version" : "3.9.0"
|
||||
}
|
||||
},
|
||||
{
|
||||
"identity" : "lottie-spm",
|
||||
"kind" : "remoteSourceControl",
|
||||
@ -18,6 +27,24 @@
|
||||
"revision" : "04f2fd18cc9404a0a0917265a449002674f24ec9",
|
||||
"version" : "4.5.2"
|
||||
}
|
||||
},
|
||||
{
|
||||
"identity" : "svgkit",
|
||||
"kind" : "remoteSourceControl",
|
||||
"location" : "https://github.com/SVGKit/SVGKit.git",
|
||||
"state" : {
|
||||
"revision" : "58152b9f7c85eab239160b36ffdfd364aa43d666",
|
||||
"version" : "3.0.0"
|
||||
}
|
||||
},
|
||||
{
|
||||
"identity" : "swift-log",
|
||||
"kind" : "remoteSourceControl",
|
||||
"location" : "https://github.com/apple/swift-log",
|
||||
"state" : {
|
||||
"revision" : "ce592ae52f982c847a4efc0dd881cc9eb32d29f2",
|
||||
"version" : "1.6.4"
|
||||
}
|
||||
}
|
||||
],
|
||||
"version" : 3
|
||||
|
||||
@ -182,6 +182,8 @@ struct BlindBoxView: View {
|
||||
let mediaType: BlindBoxMediaType
|
||||
@State private var showModal = false // 控制用户资料弹窗显示
|
||||
@State private var showSettings = false // 控制设置页面显示
|
||||
@State private var isMember = false // 是否是会员
|
||||
@State private var memberDate = "" // 会员到期时间
|
||||
@State private var showLogin = false
|
||||
@State private var memberProfile: MemberProfile? = nil
|
||||
@State private var blindCount: BlindCount? = nil
|
||||
@ -275,6 +277,8 @@ struct BlindBoxView: View {
|
||||
switch result {
|
||||
case .success(let response):
|
||||
self.memberProfile = response.data
|
||||
self.isMember = response.data.membershipLevel == "pioneer"
|
||||
self.memberDate = response.data.membershipEndAt ?? ""
|
||||
print("✅ 成功获取会员信息:", response.data)
|
||||
print("✅ 用户ID:", response.data.userInfo.userId)
|
||||
case .failure(let error):
|
||||
@ -705,13 +709,9 @@ struct BlindBoxView: View {
|
||||
ZStack {
|
||||
// 1. 背景SVG
|
||||
if !showScalingOverlay {
|
||||
SVGImage(svgName: "BlindBg")
|
||||
.frame(
|
||||
width: UIScreen.main.bounds.width * 1.8,
|
||||
height: UIScreen.main.bounds.height * 0.85
|
||||
)
|
||||
.position(x: UIScreen.main.bounds.width / 2,
|
||||
y: UIScreen.main.bounds.height * 0.325)
|
||||
SVGImage(svgName: "BlindBg", contentMode: .fit)
|
||||
// .position(x: UIScreen.main.bounds.width / 2,
|
||||
// y: UIScreen.main.bounds.height * 0.325)
|
||||
.opacity(showScalingOverlay ? 0 : 1)
|
||||
.animation(.easeOut(duration: 1.5), value: showScalingOverlay)
|
||||
}
|
||||
@ -830,6 +830,7 @@ struct BlindBoxView: View {
|
||||
.offset(x: -10, y: UIScreen.main.bounds.height * 0.2)
|
||||
}
|
||||
}
|
||||
.padding()
|
||||
.frame(
|
||||
maxWidth: .infinity,
|
||||
maxHeight: UIScreen.main.bounds.height * 0.65
|
||||
@ -897,7 +898,9 @@ struct BlindBoxView: View {
|
||||
) {
|
||||
UserProfileModal(
|
||||
showModal: $showModal,
|
||||
showSettings: $showSettings
|
||||
showSettings: $showSettings,
|
||||
isMember: $isMember,
|
||||
memberDate: $memberDate
|
||||
)
|
||||
}
|
||||
.shadow(color: .black.opacity(0.3), radius: 10, x: 5, y: 0)
|
||||
|
||||
@ -1,92 +1,144 @@
|
||||
import SwiftUI
|
||||
import WebKit
|
||||
import SVGKit
|
||||
|
||||
struct SVGImage: UIViewRepresentable {
|
||||
let svgName: String
|
||||
var shouldFill: Bool = false
|
||||
var contentMode: ContentMode = .fit
|
||||
var tintColor: Color?
|
||||
|
||||
func makeUIView(context: Context) -> WKWebView {
|
||||
let webView = WKWebView()
|
||||
webView.isOpaque = false
|
||||
webView.backgroundColor = .clear
|
||||
webView.scrollView.isScrollEnabled = false
|
||||
webView.scrollView.contentInsetAdjustmentBehavior = .never
|
||||
|
||||
guard let path = Bundle.main.path(forResource: svgName, ofType: "svg") else {
|
||||
print("❌ 无法找到 SVG 文件: \(svgName).svg")
|
||||
return webView
|
||||
}
|
||||
|
||||
let fileURL = URL(fileURLWithPath: path)
|
||||
|
||||
let svgStyle = shouldFill ? """
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
object-fit: cover;
|
||||
""" : """
|
||||
max-width: 100%;
|
||||
max-height: 100%;
|
||||
object-fit: contain;
|
||||
"""
|
||||
|
||||
let htmlString = """
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no">
|
||||
<style>
|
||||
body, html {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
overflow: hidden;
|
||||
background-color: transparent;
|
||||
}
|
||||
.container {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
}
|
||||
svg {
|
||||
\(svgStyle)
|
||||
display: block;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<div class="container">
|
||||
<object type="image/svg+xml" data="\(fileURL.lastPathComponent)"></object>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
"""
|
||||
|
||||
webView.loadHTMLString(htmlString, baseURL: fileURL.deletingLastPathComponent())
|
||||
return webView
|
||||
private var svgPath: String {
|
||||
return svgName
|
||||
}
|
||||
|
||||
func updateUIView(_ uiView: WKWebView, context: Context) {}
|
||||
private func createImageView() -> SVGKFastImageView {
|
||||
let emptySVGString = """
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 1 1" preserveAspectRatio="xMidYMid meet">
|
||||
<rect width="1" height="1" fill="red" opacity="0.5"/>
|
||||
</svg>
|
||||
"""
|
||||
|
||||
if let data = emptySVGString.data(using: .utf8),
|
||||
let svgImage = SVGKImage(data: data) {
|
||||
let imageView = SVGKFastImageView(svgkImage: svgImage) ?? SVGKFastImageView()
|
||||
imageView.contentMode = .scaleAspectFit
|
||||
return imageView
|
||||
}
|
||||
|
||||
return SVGKFastImageView()
|
||||
}
|
||||
|
||||
func sizeThatFits(_ proposal: ProposedViewSize, uiView: WKWebView, context: Context) -> CGSize? {
|
||||
func makeUIView(context: Context) -> SVGKFastImageView {
|
||||
print("🔄 开始加载SVG: \(svgName)")
|
||||
let imageView = createImageView()
|
||||
loadSVG(into: imageView)
|
||||
configureView(imageView)
|
||||
return imageView
|
||||
}
|
||||
|
||||
private func loadSVG(into imageView: SVGKFastImageView) {
|
||||
guard let path = Bundle.main.path(forResource: svgPath, ofType: "svg") else {
|
||||
print("⚠️ 在main bundle中找不到文件: \(svgPath).svg")
|
||||
return
|
||||
}
|
||||
|
||||
let url = URL(fileURLWithPath: path)
|
||||
guard let svgImage = SVGKImage(contentsOf: url) else {
|
||||
print("❌ 无法从URL创建SVG: \(path)")
|
||||
return
|
||||
}
|
||||
|
||||
// 设置SVG的尺寸为容器大小
|
||||
let containerSize = imageView.bounds.size
|
||||
if containerSize != .zero {
|
||||
svgImage.size = containerSize
|
||||
} else {
|
||||
// 如果容器大小未知,设置一个默认大小
|
||||
svgImage.size = CGSize(width: 100, height: 100)
|
||||
}
|
||||
|
||||
print("✅ 成功加载SVG: \(svgName), 尺寸: \(svgImage.size)")
|
||||
|
||||
DispatchQueue.main.async {
|
||||
imageView.image = svgImage
|
||||
imageView.setNeedsLayout()
|
||||
imageView.layoutIfNeeded()
|
||||
}
|
||||
}
|
||||
|
||||
private func configureView(_ imageView: SVGKFastImageView) {
|
||||
imageView.contentMode = contentMode == .fit ? .scaleAspectFit : .scaleAspectFill
|
||||
imageView.clipsToBounds = true
|
||||
imageView.translatesAutoresizingMaskIntoConstraints = false
|
||||
|
||||
// 确保图片视图可以正确缩放
|
||||
imageView.autoresizingMask = [.flexibleWidth, .flexibleHeight]
|
||||
|
||||
if let tintColor = tintColor?.uiColor {
|
||||
imageView.tintColor = tintColor
|
||||
DispatchQueue.main.async {
|
||||
self.applyTintColor(tintColor, to: imageView.layer)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private func applyTintColor(_ color: UIColor, to layer: CALayer) {
|
||||
if let shapeLayer = layer as? CAShapeLayer {
|
||||
shapeLayer.fillColor = color.cgColor
|
||||
}
|
||||
|
||||
layer.sublayers?.forEach { sublayer in
|
||||
applyTintColor(color, to: sublayer)
|
||||
}
|
||||
}
|
||||
|
||||
func updateUIView(_ uiView: SVGKFastImageView, context: Context) {
|
||||
loadSVG(into: uiView)
|
||||
|
||||
if let tintColor = tintColor?.uiColor {
|
||||
uiView.tintColor = tintColor
|
||||
DispatchQueue.main.async {
|
||||
self.applyTintColor(tintColor, to: uiView.layer)
|
||||
}
|
||||
}
|
||||
|
||||
uiView.contentMode = contentMode == .fit ? .scaleAspectFit : .scaleAspectFill
|
||||
}
|
||||
|
||||
func sizeThatFits(_ proposal: ProposedViewSize, uiView: SVGKFastImageView, context: Context) -> CGSize? {
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
// MARK: - ContentMode
|
||||
extension SVGImage {
|
||||
enum ContentMode {
|
||||
case fit // 保持宽高比,适应容器
|
||||
case fill // 保持宽高比,填充容器(可能被裁剪)
|
||||
}
|
||||
}
|
||||
|
||||
// MARK: - Preview
|
||||
#Preview {
|
||||
VStack {
|
||||
Text("Filled SVG")
|
||||
SVGImage(svgName: "YourSVGName", shouldFill: true)
|
||||
.frame(width: 200, height: 100)
|
||||
VStack(spacing: 20) {
|
||||
Text("IP SVG")
|
||||
SVGImage(svgName: "IP")
|
||||
.frame(width: 100, height: 100)
|
||||
.background(Color.gray.opacity(0.2))
|
||||
.border(Color.red, width: 1)
|
||||
|
||||
Text("Intrinsic Size SVG")
|
||||
SVGImage(svgName: "YourSVGName", shouldFill: false)
|
||||
.frame(width: 200, height: 100)
|
||||
Text("Pioneer SVG")
|
||||
SVGImage(svgName: "Pioneer", contentMode: .fill)
|
||||
.frame(width: 100, height: 50)
|
||||
.background(Color.gray.opacity(0.2))
|
||||
.border(Color.blue, width: 1)
|
||||
.clipped()
|
||||
}
|
||||
.padding()
|
||||
}
|
||||
|
||||
// MARK: - Color Extension
|
||||
private extension Color {
|
||||
var uiColor: UIColor {
|
||||
return UIColor(self)
|
||||
}
|
||||
}
|
||||
@ -25,11 +25,20 @@ struct APIResponse<T: Codable>: Codable {
|
||||
struct UserProfileModal: View {
|
||||
@Binding var showModal: Bool
|
||||
@Binding var showSettings: Bool
|
||||
@Binding var isMember: Bool
|
||||
@Binding var memberDate: String
|
||||
@State private var userProfile: UserProfile?
|
||||
@State private var isLoading = false
|
||||
@State private var errorMessage: String?
|
||||
@State private var isCopied = false
|
||||
|
||||
init(showModal: Binding<Bool>, showSettings: Binding<Bool>, isMember: Binding<Bool>, memberDate: Binding<String>) {
|
||||
self._showModal = showModal
|
||||
self._showSettings = showSettings
|
||||
self._isMember = isMember
|
||||
self._memberDate = memberDate
|
||||
}
|
||||
|
||||
var body: some View {
|
||||
VStack(spacing: 20) {
|
||||
Spacer()
|
||||
@ -124,43 +133,8 @@ struct UserProfileModal: View {
|
||||
)
|
||||
.padding(.horizontal)
|
||||
|
||||
Button(action: {
|
||||
Router.shared.navigate(to: .subscribe)
|
||||
}) {
|
||||
ZStack(alignment: .center) {
|
||||
// SVG背景 - 确保铺满整个区域
|
||||
SVGImage(svgName: "Pioneer")
|
||||
.scaledToFill()
|
||||
.frame(maxWidth: .infinity, maxHeight: .infinity)
|
||||
|
||||
// 内容区域
|
||||
VStack(alignment: .leading, spacing: 6) {
|
||||
Text("Pioneer")
|
||||
.font(Typography.font(for: .title3))
|
||||
.fontWeight(.bold)
|
||||
.foregroundColor(.themeTextMessageMain)
|
||||
.padding(.top, 6)
|
||||
|
||||
Text("Expires on :")
|
||||
.font(.system(size: 12))
|
||||
.foregroundColor(.themeTextMessageMain)
|
||||
.padding(.top, 2)
|
||||
|
||||
Text("March 15, 2025")
|
||||
.font(.system(size: 12))
|
||||
.fontWeight(.bold)
|
||||
.foregroundColor(.themeTextMessageMain)
|
||||
}
|
||||
.frame(maxWidth: .infinity, alignment: .leading)
|
||||
.padding(.leading, 32)
|
||||
// 可以添加内边距使内容不紧贴边缘
|
||||
.padding(.vertical, 12)
|
||||
}
|
||||
.frame(height: 112)
|
||||
.frame(maxWidth: .infinity)
|
||||
.cornerRadius(16)
|
||||
.clipped() // 确保内容不会超出边界
|
||||
}
|
||||
// 当前订阅状态卡片
|
||||
currentSubscriptionCard
|
||||
|
||||
VStack(spacing: 12) {
|
||||
// upload
|
||||
@ -269,7 +243,31 @@ struct UserProfileModal: View {
|
||||
fetchUserInfo()
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// MARK: - 当前订阅状态卡片
|
||||
private var currentSubscriptionCard: some View {
|
||||
let status: SubscriptionStatus = {
|
||||
if isMember {
|
||||
let dateFormatter = ISO8601DateFormatter()
|
||||
dateFormatter.formatOptions = [.withInternetDateTime, .withFractionalSeconds]
|
||||
let expiryDate = dateFormatter.date(from: memberDate) ?? Date()
|
||||
return .pioneer(expiryDate: expiryDate)
|
||||
} else {
|
||||
return .free
|
||||
}
|
||||
}()
|
||||
|
||||
return SubscriptionStatusBar(
|
||||
status: status,
|
||||
height: 112,
|
||||
onSubscribeTap: {
|
||||
// 跳转到订阅页面
|
||||
Router.shared.navigate(to: .subscribe)
|
||||
}
|
||||
)
|
||||
.padding(.horizontal, Theme.Spacing.xl)
|
||||
}
|
||||
|
||||
private func fetchUserInfo() {
|
||||
isLoading = true
|
||||
errorMessage = nil
|
||||
@ -295,5 +293,5 @@ struct UserProfileModal: View {
|
||||
}
|
||||
|
||||
#Preview {
|
||||
UserProfileModal(showModal: .constant(true), showSettings: .constant(false))
|
||||
UserProfileModal(showModal: .constant(true), showSettings: .constant(false), isMember: .constant(true), memberDate: .constant(""))
|
||||
}
|
||||
|
||||
@ -53,16 +53,18 @@ enum SubscriptionStatus {
|
||||
struct SubscriptionStatusBar: View {
|
||||
let status: SubscriptionStatus
|
||||
let onSubscribeTap: (() -> Void)?
|
||||
private let height: CGFloat
|
||||
|
||||
init(status: SubscriptionStatus, onSubscribeTap: (() -> Void)? = nil) {
|
||||
init(status: SubscriptionStatus, height: CGFloat? = nil, onSubscribeTap: (() -> Void)? = nil) {
|
||||
self.status = status
|
||||
self.height = height ?? 155 // 默认高度为155
|
||||
self.onSubscribeTap = onSubscribeTap
|
||||
}
|
||||
|
||||
var body: some View {
|
||||
ZStack(alignment: .topLeading) {
|
||||
// Background SVG - First layer
|
||||
SVGImage(svgName: status.backgroundImageName, shouldFill: true)
|
||||
SVGImage(svgName: status.backgroundImageName)
|
||||
.frame(maxWidth: .infinity, minHeight: 120)
|
||||
.clipped()
|
||||
|
||||
@ -75,17 +77,20 @@ struct SubscriptionStatusBar: View {
|
||||
.font(.system(size: 28, weight: .bold, design: .rounded))
|
||||
.foregroundColor(status.textColor)
|
||||
.padding(.leading, 24)
|
||||
|
||||
Spacer()
|
||||
.frame(height: 10)
|
||||
// Expiry date or subscribe button
|
||||
if case .pioneer(let expiryDate) = status {
|
||||
VStack(alignment: .leading, spacing: 4) {
|
||||
Text("Expires on:")
|
||||
.font(.system(size: 14, weight: .medium))
|
||||
.foregroundColor(status.textColor.opacity(0.9))
|
||||
Text("Expires on :")
|
||||
.font(.system(size: 12))
|
||||
.foregroundColor(.themeTextMessageMain)
|
||||
.padding(.top, 2)
|
||||
|
||||
Text(formatDate(expiryDate))
|
||||
.font(.system(size: 16, weight: .semibold))
|
||||
.foregroundColor(status.textColor)
|
||||
.font(.system(size: 12))
|
||||
.fontWeight(.bold)
|
||||
.foregroundColor(.themeTextMessageMain)
|
||||
}
|
||||
.padding(.leading, 24)
|
||||
.padding(.bottom, 20)
|
||||
@ -93,10 +98,14 @@ struct SubscriptionStatusBar: View {
|
||||
}
|
||||
.frame(maxWidth: .infinity, maxHeight: .infinity, alignment: .bottomLeading)
|
||||
}
|
||||
.frame(height: 155)
|
||||
.frame(height: height) // 使用传入的高度或默认高度
|
||||
.frame(maxWidth: .infinity)
|
||||
.cornerRadius(20)
|
||||
.clipped()
|
||||
.contentShape(Rectangle()) // Make entire area tappable
|
||||
.onTapGesture {
|
||||
onSubscribeTap?()
|
||||
}
|
||||
}
|
||||
|
||||
// MARK: - 日期格式化
|
||||
|
||||
@ -139,7 +139,7 @@ struct SubscribeView: View {
|
||||
}()
|
||||
|
||||
return SubscriptionStatusBar(
|
||||
status: .pioneer(expiryDate: Date()),
|
||||
status: status,
|
||||
onSubscribeTap: {
|
||||
// 订阅操作
|
||||
handleSubscribe()
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user