Compare commits
2 Commits
e74040a444
...
5e7bdb64c5
| Author | SHA1 | Date | |
|---|---|---|---|
| 5e7bdb64c5 | |||
| 35e7454695 |
BIN
wake/Assets/.DS_Store
vendored
BIN
wake/Assets/.DS_Store
vendored
Binary file not shown.
@ -159,7 +159,7 @@ struct UserProfileModal: View {
|
|||||||
HStack(spacing: 16) {
|
HStack(spacing: 16) {
|
||||||
Image(systemName: "tray.and.arrow.up")
|
Image(systemName: "tray.and.arrow.up")
|
||||||
.font(.system(size: 20, weight: .regular))
|
.font(.system(size: 20, weight: .regular))
|
||||||
.foregroundColor(.orange)
|
// .foregroundColor(.orange)
|
||||||
|
|
||||||
Text("Upload Resources")
|
Text("Upload Resources")
|
||||||
.font(Typography.font(for: .body))
|
.font(Typography.font(for: .body))
|
||||||
@ -181,7 +181,7 @@ struct UserProfileModal: View {
|
|||||||
HStack(spacing: 16) {
|
HStack(spacing: 16) {
|
||||||
Image(systemName: "photo.on.rectangle")
|
Image(systemName: "photo.on.rectangle")
|
||||||
.font(.system(size: 20, weight: .regular))
|
.font(.system(size: 20, weight: .regular))
|
||||||
.foregroundColor(.orange)
|
// .foregroundColor(.orange)
|
||||||
|
|
||||||
Text("My Memories")
|
Text("My Memories")
|
||||||
.font(Typography.font(for: .body))
|
.font(Typography.font(for: .body))
|
||||||
@ -226,10 +226,10 @@ struct UserProfileModal: View {
|
|||||||
}) {
|
}) {
|
||||||
HStack(spacing: 16) {
|
HStack(spacing: 16) {
|
||||||
Image(systemName: "gearshape")
|
Image(systemName: "gearshape")
|
||||||
.font(.system(size: 20, weight: .regular))
|
.font(.system(size: 22, weight: .regular))
|
||||||
.foregroundColor(.orange)
|
// .foregroundColor(.orange)
|
||||||
|
|
||||||
Text("Setting")
|
Text("Settings")
|
||||||
.font(Typography.font(for: .body))
|
.font(Typography.font(for: .body))
|
||||||
.fontWeight(.bold)
|
.fontWeight(.bold)
|
||||||
.foregroundColor(.themeTextMessageMain)
|
.foregroundColor(.themeTextMessageMain)
|
||||||
@ -284,7 +284,8 @@ struct UserProfileModal: View {
|
|||||||
onSubscribeTap: {
|
onSubscribeTap: {
|
||||||
// 跳转到订阅页面
|
// 跳转到订阅页面
|
||||||
Router.shared.navigate(to: .subscribe)
|
Router.shared.navigate(to: .subscribe)
|
||||||
}
|
},
|
||||||
|
size: "sm"
|
||||||
)
|
)
|
||||||
.padding(.horizontal, Theme.Spacing.xl)
|
.padding(.horizontal, Theme.Spacing.xl)
|
||||||
}
|
}
|
||||||
@ -313,6 +314,17 @@ struct UserProfileModal: View {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#Preview {
|
#if DEBUG
|
||||||
|
struct UserProfileModal_Previews: PreviewProvider {
|
||||||
|
static var previews: some View {
|
||||||
|
Group {
|
||||||
UserProfileModal(showModal: .constant(true), showSettings: .constant(false), isMember: .constant(true), memberDate: .constant(""))
|
UserProfileModal(showModal: .constant(true), showSettings: .constant(false), isMember: .constant(true), memberDate: .constant(""))
|
||||||
|
.previewDisplayName("Pioneer")
|
||||||
|
|
||||||
|
UserProfileModal(showModal: .constant(true), showSettings: .constant(false), isMember: .constant(false), memberDate: .constant(""))
|
||||||
|
.previewDisplayName("Free")
|
||||||
|
}
|
||||||
|
.previewLayout(.sizeThatFits)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
@ -1,111 +0,0 @@
|
|||||||
import SwiftUI
|
|
||||||
|
|
||||||
struct ModalContentView: View {
|
|
||||||
let goBack: () -> Void
|
|
||||||
@Environment(\.dismiss) private var dismissModal
|
|
||||||
|
|
||||||
var body: some View {
|
|
||||||
VStack(spacing: 20) {
|
|
||||||
// 用户信息
|
|
||||||
HStack(alignment: .center, spacing: 16) {
|
|
||||||
Image(systemName: "person.circle.fill")
|
|
||||||
.resizable()
|
|
||||||
.aspectRatio(contentMode: .fill)
|
|
||||||
.frame(width: 60, height: 60)
|
|
||||||
.foregroundColor(.blue)
|
|
||||||
.clipShape(Circle())
|
|
||||||
|
|
||||||
VStack(alignment: .leading, spacing: 4) {
|
|
||||||
Text("用户名")
|
|
||||||
.font(.headline)
|
|
||||||
Text("ID: 12345678")
|
|
||||||
.font(.subheadline)
|
|
||||||
.foregroundColor(.secondary)
|
|
||||||
}
|
|
||||||
|
|
||||||
Spacer()
|
|
||||||
}
|
|
||||||
.padding(.horizontal, 16)
|
|
||||||
.padding(.top, 16)
|
|
||||||
|
|
||||||
// 会员区域
|
|
||||||
VStack(alignment: .leading, spacing: 8) {
|
|
||||||
Text("会员等级").font(.headline)
|
|
||||||
Text("会员时间").font(.subheadline).foregroundColor(.secondary)
|
|
||||||
Text("会员中心").font(.subheadline).foregroundColor(.secondary)
|
|
||||||
}
|
|
||||||
.frame(maxWidth: .infinity, alignment: .leading)
|
|
||||||
.padding(16)
|
|
||||||
.background(Color(red: 0.92, green: 0.92, blue: 0.92))
|
|
||||||
.cornerRadius(10)
|
|
||||||
.padding(.horizontal, 16)
|
|
||||||
|
|
||||||
// 功能按钮
|
|
||||||
VStack(spacing: 12) {
|
|
||||||
ModalButton(icon: "crown.fill", color: .orange, text: "My Memories")
|
|
||||||
ModalButton(icon: "clock.fill", color: .blue, text: "My Bind Box")
|
|
||||||
|
|
||||||
// 跳转设置页
|
|
||||||
Button(action: {
|
|
||||||
goBack()
|
|
||||||
DispatchQueue.main.asyncAfter(deadline: .now() + 0.3) {
|
|
||||||
// 模拟从左边滑入的效果
|
|
||||||
}
|
|
||||||
}) {
|
|
||||||
HStack(spacing: 16) {
|
|
||||||
Image(systemName: "person.circle.fill")
|
|
||||||
.foregroundColor(.purple)
|
|
||||||
.frame(width: 24, height: 24)
|
|
||||||
Text("Setting")
|
|
||||||
.font(.headline)
|
|
||||||
.foregroundColor(.primary)
|
|
||||||
Spacer()
|
|
||||||
Image(systemName: "chevron.right")
|
|
||||||
.foregroundColor(.gray)
|
|
||||||
}
|
|
||||||
.padding()
|
|
||||||
.background(Color(.systemBackground))
|
|
||||||
.cornerRadius(10)
|
|
||||||
}
|
|
||||||
.buttonStyle(PlainButtonStyle())
|
|
||||||
}
|
|
||||||
.padding(.horizontal, 16)
|
|
||||||
|
|
||||||
Spacer()
|
|
||||||
}
|
|
||||||
.padding(.vertical, 8)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// MARK: - 按钮组件
|
|
||||||
struct ModalButton: View {
|
|
||||||
let icon: String
|
|
||||||
let color: Color
|
|
||||||
let text: String
|
|
||||||
let action: () -> Void
|
|
||||||
|
|
||||||
init(icon: String, color: Color, text: String, action: @escaping () -> Void = {}) {
|
|
||||||
self.icon = icon
|
|
||||||
self.color = color
|
|
||||||
self.text = text
|
|
||||||
self.action = action
|
|
||||||
}
|
|
||||||
|
|
||||||
var body: some View {
|
|
||||||
Button(action: action) {
|
|
||||||
HStack(spacing: 16) {
|
|
||||||
Image(systemName: icon)
|
|
||||||
.foregroundColor(color)
|
|
||||||
.frame(width: 24, height: 24)
|
|
||||||
Text(text)
|
|
||||||
.font(.headline)
|
|
||||||
.foregroundColor(.primary)
|
|
||||||
Spacer()
|
|
||||||
}
|
|
||||||
.padding()
|
|
||||||
.background(Color(.systemBackground))
|
|
||||||
.cornerRadius(10)
|
|
||||||
}
|
|
||||||
.buttonStyle(PlainButtonStyle())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -15,7 +15,7 @@ enum SubscriptionStatus {
|
|||||||
var title: String {
|
var title: String {
|
||||||
switch self {
|
switch self {
|
||||||
case .free:
|
case .free:
|
||||||
return ""
|
return "Free"
|
||||||
case .pioneer:
|
case .pioneer:
|
||||||
return "Pioneer"
|
return "Pioneer"
|
||||||
}
|
}
|
||||||
@ -53,18 +53,22 @@ enum SubscriptionStatus {
|
|||||||
struct SubscriptionStatusBar: View {
|
struct SubscriptionStatusBar: View {
|
||||||
let status: SubscriptionStatus
|
let status: SubscriptionStatus
|
||||||
let onSubscribeTap: (() -> Void)?
|
let onSubscribeTap: (() -> Void)?
|
||||||
|
let size: String
|
||||||
private let height: CGFloat
|
private let height: CGFloat
|
||||||
|
private let backgroundColor: Color?
|
||||||
|
|
||||||
init(status: SubscriptionStatus, height: CGFloat? = nil, onSubscribeTap: (() -> Void)? = nil) {
|
init(status: SubscriptionStatus, height: CGFloat? = nil, backgroundColor: Color? = nil, onSubscribeTap: (() -> Void)? = nil, size: String? = "md") {
|
||||||
self.status = status
|
self.status = status
|
||||||
self.height = height ?? 155 // 默认高度为155
|
self.height = height ?? 155 // 默认高度为155
|
||||||
|
self.backgroundColor = backgroundColor
|
||||||
self.onSubscribeTap = onSubscribeTap
|
self.onSubscribeTap = onSubscribeTap
|
||||||
|
self.size = size ?? "md"
|
||||||
}
|
}
|
||||||
|
|
||||||
var body: some View {
|
var body: some View {
|
||||||
ZStack(alignment: .leading) {
|
ZStack(alignment: .leading) {
|
||||||
// SwiftUI 绘制的背景
|
// SwiftUI 绘制的背景
|
||||||
SubscriptionBackground(status: status)
|
SubscriptionBackground(status: status, customBackground: backgroundColor, size: size)
|
||||||
.frame(maxWidth: .infinity, minHeight: 120)
|
.frame(maxWidth: .infinity, minHeight: 120)
|
||||||
.clipped()
|
.clipped()
|
||||||
|
|
||||||
@ -72,7 +76,7 @@ struct SubscriptionStatusBar: View {
|
|||||||
VStack(alignment: .leading, spacing: 0) {
|
VStack(alignment: .leading, spacing: 0) {
|
||||||
// Title - Centered vertically
|
// Title - Centered vertically
|
||||||
Text(status.title)
|
Text(status.title)
|
||||||
.font(.system(size: 28, weight: .bold, design: .rounded))
|
.font(.system(size: size == "sm" ? 24 : 28, weight: .bold, design: .rounded))
|
||||||
.foregroundColor(status.textColor)
|
.foregroundColor(status.textColor)
|
||||||
.frame(maxHeight: .infinity, alignment: .center) // Center vertically
|
.frame(maxHeight: .infinity, alignment: .center) // Center vertically
|
||||||
.padding(.leading, 12)
|
.padding(.leading, 12)
|
||||||
@ -110,33 +114,95 @@ struct SubscriptionStatusBar: View {
|
|||||||
// MARK: - 背景绘制
|
// MARK: - 背景绘制
|
||||||
private struct SubscriptionBackground: View {
|
private struct SubscriptionBackground: View {
|
||||||
let status: SubscriptionStatus
|
let status: SubscriptionStatus
|
||||||
|
let customBackground: Color?
|
||||||
|
let size: String
|
||||||
|
|
||||||
|
private let parallelogramHeight: CGFloat
|
||||||
|
private let parallelogramWidth: CGFloat
|
||||||
|
|
||||||
|
init(status: SubscriptionStatus, customBackground: Color? = nil, size: String? = "md") {
|
||||||
|
self.status = status
|
||||||
|
self.customBackground = customBackground
|
||||||
|
self.size = size ?? "md"
|
||||||
|
self.parallelogramHeight = size == "sm" ? 14 : 18
|
||||||
|
self.parallelogramWidth = size == "sm" ? 12 : 16
|
||||||
|
}
|
||||||
|
|
||||||
var body: some View {
|
var body: some View {
|
||||||
ZStack(alignment: .topTrailing) {
|
ZStack {
|
||||||
RoundedRectangle(cornerRadius: 20)
|
// 背景底板:自定义颜色优先,否则根据状态给出渐变
|
||||||
.fill(background)
|
if let color = customBackground {
|
||||||
|
RoundedRectangle(cornerRadius: 10)
|
||||||
|
.fill(color)
|
||||||
.shadow(color: Color.black.opacity(0.06), radius: 10, x: 0, y: 6)
|
.shadow(color: Color.black.opacity(0.06), radius: 10, x: 0, y: 6)
|
||||||
|
|
||||||
// 装饰元素(右上角)
|
|
||||||
if case .pioneer = status {
|
|
||||||
Circle()
|
|
||||||
.fill(Color.black.opacity(0.08))
|
|
||||||
.frame(width: 90, height: 90)
|
|
||||||
.offset(x: 12, y: -12)
|
|
||||||
} else {
|
} else {
|
||||||
Circle()
|
RoundedRectangle(cornerRadius: 10)
|
||||||
.fill(Color.black.opacity(0.04))
|
.fill(defaultBackground)
|
||||||
.frame(width: 70, height: 70)
|
.shadow(color: Color.black.opacity(0.06), radius: 10, x: 0, y: 6)
|
||||||
.offset(x: 12, y: -12)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
.clipShape(RoundedRectangle(cornerRadius: 20))
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private var background: some ShapeStyle {
|
// 左上角斜条纹(装饰)
|
||||||
|
VStack {
|
||||||
|
HStack {
|
||||||
|
ParallelogramRow(
|
||||||
|
count: 6,
|
||||||
|
itemSize: CGSize(width: parallelogramWidth, height: parallelogramHeight),
|
||||||
|
shear: -0.35,
|
||||||
|
cornerRadius: 2,
|
||||||
|
color: .black.opacity(0.85),
|
||||||
|
spacing: 1
|
||||||
|
)
|
||||||
|
Spacer()
|
||||||
|
}
|
||||||
|
Spacer()
|
||||||
|
}
|
||||||
|
.padding(.top, 12)
|
||||||
|
.padding(.leading, 16)
|
||||||
|
|
||||||
|
// 右下角斜条纹(装饰)
|
||||||
|
VStack {
|
||||||
|
Spacer()
|
||||||
|
HStack {
|
||||||
|
Spacer()
|
||||||
|
ParallelogramRow(
|
||||||
|
count: 3,
|
||||||
|
itemSize: CGSize(width: parallelogramWidth, height: parallelogramHeight),
|
||||||
|
shear: -0.35,
|
||||||
|
cornerRadius: 2,
|
||||||
|
color: .black.opacity(0.85),
|
||||||
|
spacing: 1
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.padding(.bottom, 14)
|
||||||
|
.padding(.trailing, 16)
|
||||||
|
|
||||||
|
// 右上角圆形徽标 + 三角指针(与示例类似)
|
||||||
|
VStack {
|
||||||
|
HStack {
|
||||||
|
Spacer()
|
||||||
|
ZStack {
|
||||||
|
CircleView(diameter: size == "sm" ? 70 : 100, color: .black)
|
||||||
|
TriangleView(
|
||||||
|
width: size == "sm" ? 20 : 24,
|
||||||
|
height: size == "sm" ? 20 : 24,
|
||||||
|
direction: .right,
|
||||||
|
color: Color(white: 0.9),
|
||||||
|
rotation: .degrees(157)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
.offset(x: size == "sm" ? 8 : 12, y: size == "sm" ? -8 : -12)
|
||||||
|
}
|
||||||
|
Spacer()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.clipShape(RoundedRectangle(cornerRadius: 16))
|
||||||
|
}
|
||||||
|
|
||||||
|
private var defaultBackground: LinearGradient {
|
||||||
switch status {
|
switch status {
|
||||||
case .free:
|
case .free:
|
||||||
return LinearGradient(colors: [Color.white, Color.white.opacity(0.96)], startPoint: .topLeading, endPoint: .bottomTrailing)
|
return LinearGradient(colors: [Color(hex: "FFF8DE")], startPoint: .topLeading, endPoint: .bottomTrailing)
|
||||||
case .pioneer:
|
case .pioneer:
|
||||||
return LinearGradient(colors: [Color.themePrimary.opacity(0.85), Color.orange.opacity(0.6)], startPoint: .topLeading, endPoint: .bottomTrailing)
|
return LinearGradient(colors: [Color.themePrimary.opacity(0.85), Color.orange.opacity(0.6)], startPoint: .topLeading, endPoint: .bottomTrailing)
|
||||||
}
|
}
|
||||||
@ -149,6 +215,7 @@ private struct SubscriptionBackground: View {
|
|||||||
// Free status preview
|
// Free status preview
|
||||||
SubscriptionStatusBar(
|
SubscriptionStatusBar(
|
||||||
status: .free,
|
status: .free,
|
||||||
|
backgroundColor: Color(white: 0.98),
|
||||||
onSubscribeTap: {
|
onSubscribeTap: {
|
||||||
print("Subscribe tapped")
|
print("Subscribe tapped")
|
||||||
}
|
}
|
||||||
@ -159,7 +226,8 @@ private struct SubscriptionBackground: View {
|
|||||||
SubscriptionStatusBar(
|
SubscriptionStatusBar(
|
||||||
status: .pioneer(
|
status: .pioneer(
|
||||||
expiryDate: Calendar.current.date(byAdding: .month, value: 6, to: Date()) ?? Date()
|
expiryDate: Calendar.current.date(byAdding: .month, value: 6, to: Date()) ?? Date()
|
||||||
)
|
),
|
||||||
|
backgroundColor: Color.orange.opacity(0.9)
|
||||||
)
|
)
|
||||||
.padding(.horizontal)
|
.padding(.horizontal)
|
||||||
}
|
}
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user