Files
e-party-iOS/yana/MVVM/MePage.swift
edwinQQQ 07265c01db feat: 更新视图组件及数据模型
- 在yanaApp中为SplashPage添加忽略安全区域的设置,确保全屏显示。
- 在DynamicsModels中更新MyMomentInfo结构,添加可选字段以兼容不同版本的服务器返回数据。
- 在CommonComponents中将LoginBackgroundView的背景图替换为蓝色,简化视图。
- 在MainPage中为内容添加忽略安全区域的设置,提升布局一致性。
- 在MePage中新增MePageViewModel,优化用户信息管理逻辑,支持动态列表的加载和错误处理。
- 在SplashPage中调整过渡动画时长,提升用户体验。
2025-09-26 14:57:34 +08:00

170 lines
7.5 KiB
Swift
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

import SwiftUI
struct MePage: View {
let onLogout: () -> Void
@State private var isShowingSettings: Bool = false
@StateObject private var viewModel = MePageViewModel()
//
@State private var previewItem: PreviewItem? = nil
@State private var previewCurrentIndex: Int = 0
var body: some View {
ZStack {
//
MomentListBackgroundView()
VStack(spacing: 0) {
// + + ID +
ZStack(alignment: .topTrailing) {
VStack(spacing: 12) {
AsyncImage(url: URL(string: viewModel.avatarURL)) { image in
image.resizable().scaledToFill()
} placeholder: {
Image(systemName: "person.circle.fill")
.resizable()
.scaledToFill()
.foregroundColor(.gray)
}
.frame(width: 132, height: 132)
.clipShape(Circle())
.overlay(Circle().stroke(Color.white, lineWidth: 3))
.shadow(color: .black.opacity(0.25), radius: 10, x: 0, y: 6)
Text(viewModel.nickname.isEmpty ? "未知用户" : viewModel.nickname)
.font(.system(size: 34, weight: .semibold))
.foregroundColor(.white)
.lineLimit(1)
.minimumScaleFactor(0.6)
if viewModel.userId > 0 {
HStack(spacing: 6) {
Text("ID:\(viewModel.userId)")
.font(.system(size: 16))
.foregroundColor(.white.opacity(0.8))
Image(systemName: "doc.on.doc")
.foregroundColor(.white.opacity(0.8))
}
}
}
.frame(maxWidth: .infinity)
.padding(.top, 24)
Button(action: { isShowingSettings = true }) {
Image(systemName: "gearshape")
.font(.system(size: 24, weight: .medium))
.foregroundColor(.white)
.frame(width: 40, height: 40)
.background(Color.black.opacity(0.3))
.clipShape(Circle())
}
.padding(.trailing, 16)
.padding(.top, 8)
}
.padding(.bottom, 8)
//
if !viewModel.moments.isEmpty {
ScrollView {
LazyVStack(spacing: 16) {
ForEach(Array(viewModel.moments.enumerated()), id: \.offset) { index, moment in
MomentListItem(
moment: moment,
onImageTap: { images, tappedIndex in
previewCurrentIndex = tappedIndex
previewItem = PreviewItem(images: images, index: tappedIndex)
}
)
.padding(.horizontal, 16)
.onAppear {
if index == viewModel.moments.count - 3 {
viewModel.loadMoreData()
}
}
}
if viewModel.isLoadingMore {
HStack {
ProgressView()
.progressViewStyle(CircularProgressViewStyle(tint: .white))
.scaleEffect(0.8)
Text("加载更多...")
.font(.system(size: 14))
.foregroundColor(.white.opacity(0.8))
}
.padding(.vertical, 20)
}
if !viewModel.hasMore && !viewModel.moments.isEmpty {
Text("没有更多数据了")
.font(.system(size: 14))
.foregroundColor(.white.opacity(0.6))
.padding(.vertical, 20)
}
}
.padding(.bottom, 160)
}
.refreshable { await viewModel.refreshData() }
} else if viewModel.isLoading {
ProgressView()
.progressViewStyle(CircularProgressViewStyle(tint: .white))
.padding(.top, 20)
} else if let error = viewModel.errorMessage {
VStack(spacing: 16) {
Text(error)
.font(.system(size: 14))
.foregroundColor(.red)
.multilineTextAlignment(.center)
.padding(.horizontal, 20)
Button(action: { Task { await viewModel.refreshData() } }) {
Text("重试")
.font(.system(size: 14, weight: .medium))
.foregroundColor(.white)
.padding(.horizontal, 20)
.padding(.vertical, 8)
.background(Color.white.opacity(0.2))
.cornerRadius(8)
}
}
.padding(.top, 20)
} else {
VStack(spacing: 12) {
Image(systemName: "doc.text")
.font(.system(size: 32))
.foregroundColor(.white.opacity(0.5))
Text("暂无动态")
.font(.system(size: 16, weight: .medium))
.foregroundColor(.white.opacity(0.7))
}
.frame(maxWidth: .infinity, maxHeight: .infinity)
}
Spacer()
}
.safeAreaPadding(.top, 8)
}
.onAppear { viewModel.onAppear() }
.onReceive(NotificationCenter.default.publisher(for: .init("CreateFeedPublished"))) { _ in
Task { await viewModel.refreshData() }
}
.sheet(isPresented: $isShowingSettings) {
SettingPage(
onBack: { isShowingSettings = false },
onLogout: {
isShowingSettings = false
onLogout()
}
)
.navigationBarHidden(true)
}
//
.sheet(item: $previewItem) { item in
ImagePreviewPager(
images: item.images as [String],
currentIndex: $previewCurrentIndex
) {
previewItem = nil
}
}
}
}