feat: 样式

This commit is contained in:
jinyaqiu 2025-09-02 16:20:45 +08:00
parent 2d2a751a10
commit 62327164a2
4 changed files with 46 additions and 50 deletions

View File

@ -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)

View File

@ -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
}
}
} }
} }

View File

@ -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: -

View File

@ -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()