Files
e-party-iOS/yana/Views/MeView.swift
edwinQQQ 62dcf591f0 feat: 新增详情页功能以增强用户交互体验
- 在MeFeature中新增showDetail状态和selectedMoment属性,支持详情页的展示。
- 更新Action枚举,添加showDetail和detailDismissed动作以处理详情页逻辑。
- 在MeView中整合showDetail状态与selectedMoment,优化详情页导航和交互逻辑。
- 通过viewStore发送动作,提升状态管理的清晰度与可维护性。
2025-07-28 17:32:29 +08:00

191 lines
7.9 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
import ComposableArchitecture
struct MeView: View {
let store: StoreOf<MeFeature>
//
@State private var previewItem: PreviewItem? = nil
@State private var previewCurrentIndex: Int = 0
var body: some View {
WithViewStore(self.store, observe: { $0 }) { viewStore in
WithPerceptionTracking {
GeometryReader { geometry in
ZStack {
//
Image("bg")
.resizable()
.aspectRatio(contentMode: .fill)
.frame(maxWidth: .infinity, maxHeight: .infinity)
.clipped()
.ignoresSafeArea(.all)
//
VStack {
HStack {
Spacer()
Button(action: {
viewStore.send(.settingButtonTapped)
}) {
Image(systemName: "gearshape")
.font(.system(size: 33, weight: .medium))
.foregroundColor(.white)
}
.padding(.trailing, 16)
.padding(.top, 8)
}
Spacer()
}
//
VStack(spacing: 16) {
//
userInfoSection(viewStore: viewStore)
//
momentsSection(viewStore: viewStore)
Spacer()
}
.frame(maxWidth: .infinity, alignment: .top)
.padding(.top, 8)
}
}
.onAppear {
viewStore.send(.onAppear)
}
//
.fullScreenCover(item: $previewItem) { item in
ImagePreviewPager(images: item.images as [String], currentIndex: $previewCurrentIndex) {
previewItem = nil
}
}
//
.navigationDestination(isPresented: viewStore.binding(
get: \.showDetail,
send: { _ in .detailDismissed }
)) {
if let selectedMoment = viewStore.selectedMoment {
DetailView(
store: Store(
initialState: DetailFeature.State(moment: selectedMoment)
) {
DetailFeature()
},
onDismiss: {
viewStore.send(.detailDismissed)
}
)
}
}
}
}
}
// MARK: -
@ViewBuilder
private func userInfoSection(viewStore: ViewStoreOf<MeFeature>) -> some View {
if viewStore.isLoadingUserInfo {
ProgressView()
.progressViewStyle(CircularProgressViewStyle(tint: .white))
.frame(height: 130)
} else if let error = viewStore.userInfoError {
Text(error)
.font(.system(size: 14))
.foregroundColor(.red)
.frame(height: 130)
} else if let userInfo = viewStore.userInfo {
VStack(spacing: 8) {
if let avatarUrl = userInfo.avatar, !avatarUrl.isEmpty {
AsyncImage(url: URL(string: avatarUrl)) { image in
image.resizable().aspectRatio(contentMode: .fill).clipShape(Circle())
} placeholder: {
Image(systemName: "person.fill").font(.system(size: 40)).foregroundColor(.white)
}
.frame(width: 90, height: 90)
} else {
Image(systemName: "person.fill").font(.system(size: 40)).foregroundColor(.white)
.frame(width: 90, height: 90)
}
Text(userInfo.nick ?? "用户昵称")
.font(.system(size: 18, weight: .medium))
.foregroundColor(.white)
Text("ID: \(userInfo.uid ?? 0)")
.font(.system(size: 14))
.foregroundColor(.white.opacity(0.7))
}
.padding(.top, 0)
.frame(height: 130)
} else {
Spacer().frame(height: 130)
}
}
// MARK: -
@ViewBuilder
private func momentsSection(viewStore: ViewStoreOf<MeFeature>) -> some View {
if viewStore.isLoadingMoments && viewStore.moments.isEmpty {
ProgressView("加载中...")
.frame(maxWidth: .infinity, maxHeight: .infinity)
} else if let error = viewStore.momentsError {
VStack(spacing: 16) {
Image(systemName: "exclamationmark.triangle.fill")
.font(.system(size: 40))
.foregroundColor(.yellow)
Text(error)
.foregroundColor(.red)
Button("重试") {
viewStore.send(.onAppear)
}
}
.frame(maxWidth: .infinity, maxHeight: .infinity)
} else if viewStore.moments.isEmpty {
VStack(spacing: 16) {
Image(systemName: "tray")
.font(.system(size: 40))
.foregroundColor(.gray)
Text("暂无动态")
.foregroundColor(.white.opacity(0.8))
}
.frame(maxWidth: .infinity, maxHeight: .infinity)
} else {
ScrollView {
WithPerceptionTracking {
LazyVStack(spacing: 12) {
ForEach(Array(viewStore.moments.enumerated()), id: \.element.dynamicId) { index, moment in
OptimizedDynamicCardView(
moment: moment,
allMoments: viewStore.moments,
currentIndex: index,
onImageTap: { images, tappedIndex in
previewCurrentIndex = tappedIndex
previewItem = PreviewItem(images: images, index: tappedIndex)
},
onLikeTap: { _, _, _, _ in
//
},
onCardTap: {
viewStore.send(.showDetail(moment))
}
)
.padding(.horizontal, 12)
}
if viewStore.hasMore {
ProgressView()
.onAppear {
viewStore.send(.loadMore)
}
}
//
Color.clear.frame(height: 120)
}
.padding(.top, 8)
}
}
.refreshable {
viewStore.send(.refresh)
}
}
}
}