feat: 样式
This commit is contained in:
parent
2d2a751a10
commit
62327164a2
@ -277,7 +277,7 @@ struct BlindBoxView: View {
|
|||||||
switch result {
|
switch result {
|
||||||
case .success(let response):
|
case .success(let response):
|
||||||
self.memberProfile = response.data
|
self.memberProfile = response.data
|
||||||
self.isMember = response.data.membershipLevel == "pioneer"
|
self.isMember = response.data.membershipLevel == "Pioneer"
|
||||||
self.memberDate = response.data.membershipEndAt ?? ""
|
self.memberDate = response.data.membershipEndAt ?? ""
|
||||||
print("✅ 成功获取会员信息:", response.data)
|
print("✅ 成功获取会员信息:", response.data)
|
||||||
print("✅ 用户ID:", response.data.userInfo.userId)
|
print("✅ 用户ID:", response.data.userInfo.userId)
|
||||||
|
|||||||
@ -51,10 +51,23 @@ struct UserProfileModal: View {
|
|||||||
Text(error)
|
Text(error)
|
||||||
.foregroundColor(.red)
|
.foregroundColor(.red)
|
||||||
.padding()
|
.padding()
|
||||||
|
} else if let userProfile = userProfile {
|
||||||
|
userProfileView(userProfile: userProfile)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.frame(width: UIScreen.main.bounds.width * 0.8)
|
||||||
|
.background(Color.themeTextWhiteSecondary)
|
||||||
|
.edgesIgnoringSafeArea(.all)
|
||||||
|
.onAppear {
|
||||||
|
fetchUserInfo()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ViewBuilder
|
||||||
|
private func userProfileView(userProfile: UserProfile) -> some View {
|
||||||
|
VStack(spacing: 20) {
|
||||||
HStack(alignment: .center, spacing: 16) {
|
HStack(alignment: .center, spacing: 16) {
|
||||||
if let avatarUrl = userProfile?.avatarUrl, !avatarUrl.isEmpty, let url = URL(string: avatarUrl) {
|
if let avatarUrl = userProfile.avatarUrl, !avatarUrl.isEmpty, let url = URL(string: avatarUrl) {
|
||||||
AsyncImage(url: url) { phase in
|
AsyncImage(url: url) { phase in
|
||||||
switch phase {
|
switch phase {
|
||||||
case .success(let image):
|
case .success(let image):
|
||||||
@ -83,12 +96,12 @@ struct UserProfileModal: View {
|
|||||||
}
|
}
|
||||||
|
|
||||||
VStack(alignment: .leading, spacing: 10) {
|
VStack(alignment: .leading, spacing: 10) {
|
||||||
Text(userProfile?.nickname ?? "Name")
|
Text(userProfile.nickname)
|
||||||
.font(Typography.font(for: .body))
|
.font(Typography.font(for: .body))
|
||||||
.fontWeight(.bold)
|
.fontWeight(.bold)
|
||||||
.foregroundColor(.themeTextMessageMain)
|
.foregroundColor(.themeTextMessageMain)
|
||||||
HStack(spacing: 4) {
|
HStack(spacing: 4) {
|
||||||
Text("ID: \(userProfile?.userId ?? "")")
|
Text("ID: \(userProfile.userId)")
|
||||||
.font(.system(size: 14))
|
.font(.system(size: 14))
|
||||||
.foregroundColor(.themeTextMessageMain)
|
.foregroundColor(.themeTextMessageMain)
|
||||||
.lineLimit(1)
|
.lineLimit(1)
|
||||||
@ -96,21 +109,7 @@ struct UserProfileModal: View {
|
|||||||
.fixedSize(horizontal: false, vertical: true)
|
.fixedSize(horizontal: false, vertical: true)
|
||||||
.frame(maxWidth: 120)
|
.frame(maxWidth: 120)
|
||||||
|
|
||||||
Button(action: {
|
Button(action: copyUserId) {
|
||||||
print("Copy ID button tapped")
|
|
||||||
UIPasteboard.general.string = userProfile?.userId
|
|
||||||
print("Copied to clipboard:", userProfile?.userId ?? "nil")
|
|
||||||
withAnimation {
|
|
||||||
isCopied = true
|
|
||||||
// Reset after 2 seconds
|
|
||||||
DispatchQueue.main.asyncAfter(deadline: .now() + 2) {
|
|
||||||
withAnimation {
|
|
||||||
isCopied = false
|
|
||||||
print("Reset copy button state")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}) {
|
|
||||||
if isCopied {
|
if isCopied {
|
||||||
Image(systemName: "checkmark")
|
Image(systemName: "checkmark")
|
||||||
.foregroundColor(.themePrimary)
|
.foregroundColor(.themePrimary)
|
||||||
@ -121,8 +120,8 @@ struct UserProfileModal: View {
|
|||||||
.font(.system(size: 12))
|
.font(.system(size: 12))
|
||||||
.foregroundColor(.themeTextMessageMain)
|
.foregroundColor(.themeTextMessageMain)
|
||||||
.animation(.easeInOut, value: isCopied)
|
.animation(.easeInOut, value: isCopied)
|
||||||
.contentShape(Rectangle()) // Make the entire button area tappable
|
.contentShape(Rectangle())
|
||||||
.frame(width: 24, height: 24) // Ensure minimum touch target size
|
.frame(width: 24, height: 24)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -239,11 +238,17 @@ struct UserProfileModal: View {
|
|||||||
.padding(.horizontal)
|
.padding(.horizontal)
|
||||||
Spacer()
|
Spacer()
|
||||||
}
|
}
|
||||||
.frame(width: UIScreen.main.bounds.width * 0.8)
|
}
|
||||||
.background(Color.themeTextWhiteSecondary)
|
|
||||||
.edgesIgnoringSafeArea(.all)
|
private func copyUserId() {
|
||||||
.onAppear {
|
UIPasteboard.general.string = userProfile?.userId
|
||||||
fetchUserInfo()
|
withAnimation {
|
||||||
|
isCopied = true
|
||||||
|
DispatchQueue.main.asyncAfter(deadline: .now() + 2) {
|
||||||
|
withAnimation {
|
||||||
|
isCopied = false
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -62,50 +62,41 @@ struct SubscriptionStatusBar: View {
|
|||||||
}
|
}
|
||||||
|
|
||||||
var body: some View {
|
var body: some View {
|
||||||
ZStack(alignment: .topLeading) {
|
ZStack(alignment: .leading) {
|
||||||
// Background SVG - First layer
|
// Background SVG - First layer
|
||||||
SVGImage(svgName: status.backgroundImageName)
|
SVGImage(svgName: status.backgroundImageName)
|
||||||
.frame(maxWidth: .infinity, minHeight: 120)
|
.frame(maxWidth: .infinity, minHeight: 120)
|
||||||
.clipped()
|
.clipped()
|
||||||
|
|
||||||
// Content - Second layer
|
// Main content container
|
||||||
VStack(alignment: .leading, spacing: 0) {
|
VStack(alignment: .leading, spacing: 0) {
|
||||||
Spacer()
|
// Title - Centered vertically
|
||||||
|
|
||||||
// Subscription title
|
|
||||||
Text(status.title)
|
Text(status.title)
|
||||||
.font(.system(size: 28, weight: .bold, design: .rounded))
|
.font(.system(size: 28, weight: .bold, design: .rounded))
|
||||||
.foregroundColor(status.textColor)
|
.foregroundColor(status.textColor)
|
||||||
.padding(.leading, 24)
|
.frame(maxHeight: .infinity, alignment: .center) // Center vertically
|
||||||
Spacer()
|
.padding(.leading, 12)
|
||||||
.frame(height: 10)
|
.padding(.top, height < 155 ? 30 : 40)
|
||||||
// Expiry date or subscribe button
|
|
||||||
|
// Expiry date - Bottom left
|
||||||
if case .pioneer(let expiryDate) = status {
|
if case .pioneer(let expiryDate) = status {
|
||||||
VStack(alignment: .leading, spacing: 4) {
|
VStack(alignment: .leading, spacing: 4) {
|
||||||
Text("Expires on :")
|
Text("Expires on :")
|
||||||
.font(.system(size: 12))
|
.font(.system(size: 12))
|
||||||
.foregroundColor(.themeTextMessageMain)
|
.foregroundColor(.themeTextMessageMain)
|
||||||
.padding(.top, 2)
|
|
||||||
|
|
||||||
Text(formatDate(expiryDate))
|
Text(formatDate(expiryDate))
|
||||||
.font(.system(size: 12))
|
.font(.system(size: 12))
|
||||||
.fontWeight(.bold)
|
.fontWeight(.bold)
|
||||||
.foregroundColor(.themeTextMessageMain)
|
.foregroundColor(.themeTextMessageMain)
|
||||||
}
|
}
|
||||||
.padding(.leading, 24)
|
.padding(.leading, 12)
|
||||||
.padding(.bottom, 20)
|
.padding(.bottom, 12)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
.frame(maxWidth: .infinity, maxHeight: .infinity, alignment: .bottomLeading)
|
.frame(maxWidth: .infinity, maxHeight: .infinity, alignment: .leading)
|
||||||
}
|
|
||||||
.frame(height: height) // 使用传入的高度或默认高度
|
|
||||||
.frame(maxWidth: .infinity)
|
|
||||||
.cornerRadius(20)
|
|
||||||
.clipped()
|
|
||||||
.contentShape(Rectangle()) // Make entire area tappable
|
|
||||||
.onTapGesture {
|
|
||||||
onSubscribeTap?()
|
|
||||||
}
|
}
|
||||||
|
.frame(height: height)
|
||||||
}
|
}
|
||||||
|
|
||||||
// MARK: - 日期格式化
|
// MARK: - 日期格式化
|
||||||
|
|||||||
@ -134,7 +134,7 @@ struct SubscribeView: View {
|
|||||||
// MARK: - 当前订阅状态卡片
|
// MARK: - 当前订阅状态卡片
|
||||||
private var currentSubscriptionCard: some View {
|
private var currentSubscriptionCard: some View {
|
||||||
let status: SubscriptionStatus = {
|
let status: SubscriptionStatus = {
|
||||||
if memberProfile?.membershipLevel == "pioneer" {
|
if memberProfile?.membershipLevel == "Pioneer" {
|
||||||
let dateFormatter = ISO8601DateFormatter()
|
let dateFormatter = ISO8601DateFormatter()
|
||||||
dateFormatter.formatOptions = [.withInternetDateTime, .withFractionalSeconds]
|
dateFormatter.formatOptions = [.withInternetDateTime, .withFractionalSeconds]
|
||||||
let expiryDate = memberProfile.flatMap { dateFormatter.date(from: $0.membershipEndAt) } ?? Date()
|
let expiryDate = memberProfile.flatMap { dateFormatter.date(from: $0.membershipEndAt) } ?? Date()
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user