Files
e-party-iOS/yana/Views/MeView.swift
edwinQQQ fa544139c1 feat: 实现DetailView头像点击功能并优化MeView
- 在DetailView中添加头像点击功能,支持展示非当前用户的主页。
- 更新OptimizedDynamicCardView以支持头像点击回调。
- 修改DetailFeature以管理用户主页显示状态。
- 在MeView中添加关闭按钮支持,优化用户体验。
- 确保其他页面的兼容性,未影响现有功能。
2025-08-01 16:12:24 +08:00

239 lines
9.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
//
let showCloseButton: Bool
// dismiss
@Environment(\.dismiss) private var dismiss
init(store: StoreOf<MeFeature>, showCloseButton: Bool = false) {
self.store = store
self.showCloseButton = showCloseButton
}
var body: some View {
WithPerceptionTracking {
GeometryReader { geometry in
ZStack {
//
Image("bg")
.resizable()
.aspectRatio(contentMode: .fill)
.frame(maxWidth: .infinity, maxHeight: .infinity)
.clipped()
.ignoresSafeArea(.all)
//
VStack {
HStack {
// present
if showCloseButton {
Button(action: {
dismiss()
}) {
Image(systemName: "xmark")
.font(.system(size: 20, weight: .medium))
.foregroundColor(.white)
.frame(width: 44, height: 44)
.background(Color.black.opacity(0.3))
.clipShape(Circle())
}
.padding(.leading, 16)
.padding(.top, 8)
}
Spacer()
if !store.isDisplayingOtherUser {
Button(action: {
store.send(.settingButtonTapped)
}) {
Image(systemName: "gearshape")
.font(.system(size: 33, weight: .medium))
.foregroundColor(.white)
}
.padding(.trailing, 16)
.padding(.top, 8)
}
}
Spacer()
}
//
VStack(spacing: 16) {
//
userInfoSection()
//
momentsSection()
Spacer()
}
.frame(maxWidth: .infinity, alignment: .top)
.padding(.top, 8)
}
}
.onAppear {
store.send(.onAppear)
}
//
.fullScreenCover(item: $previewItem) { item in
ImagePreviewPager(images: item.images as [String], currentIndex: $previewCurrentIndex) {
previewItem = nil
}
}
//
.navigationDestination(isPresented: Binding(
get: { store.showDetail },
set: { _ in store.send(.detailDismissed) }
)) {
if let selectedMoment = store.selectedMoment {
let detailStore = Store(
initialState: DetailFeature.State(moment: selectedMoment)
) {
DetailFeature()
}
DetailView(store: detailStore)
.onChange(of: detailStore.shouldDismiss) { _, shouldDismiss in
if shouldDismiss {
store.send(.detailDismissed)
}
}
}
}
}
}
// MARK: -
@ViewBuilder
private func userInfoSection() -> some View {
WithPerceptionTracking {
VStack(spacing: 16) {
//
AsyncImage(url: URL(string: store.userInfo?.avatar ?? "")) { image in
image
.resizable()
.aspectRatio(contentMode: .fill)
} placeholder: {
Image(systemName: "person.circle.fill")
.resizable()
.aspectRatio(contentMode: .fill)
.foregroundColor(.gray)
}
.frame(width: 130, height: 130)
.clipShape(Circle())
.overlay(
Circle()
.stroke(Color.white, lineWidth: 2)
)
//
Text(store.userInfo?.nick ?? "未知用户")
.font(.system(size: 20, weight: .medium))
.foregroundColor(.white)
// ID
UserIDDisplay(uid: store.userInfo?.uid ?? 0, isDisplayCopy: true)
}
.padding(.horizontal, 32)
}
}
// MARK: -
@ViewBuilder
private func momentsSection() -> some View {
WithPerceptionTracking {
if store.isLoadingUserInfo || store.isLoadingMoments {
VStack {
ProgressView()
.progressViewStyle(CircularProgressViewStyle(tint: .white))
.scaleEffect(1.2)
Text("加载中...")
.font(.system(size: 14))
.foregroundColor(.white.opacity(0.7))
.padding(.top, 8)
}
.frame(maxWidth: .infinity, maxHeight: .infinity)
} else if let error = store.userInfoError ?? store.momentsError {
VStack(spacing: 12) {
Image(systemName: "exclamationmark.triangle")
.font(.system(size: 32))
.foregroundColor(.orange)
Text("加载失败")
.font(.system(size: 16, weight: .medium))
.foregroundColor(.white)
Text(error)
.font(.system(size: 14))
.foregroundColor(.white.opacity(0.7))
.multilineTextAlignment(.center)
.padding(.horizontal, 32)
Button("重试") {
store.send(.onAppear)
}
.font(.system(size: 14, weight: .medium))
.foregroundColor(.white)
.padding(.horizontal, 24)
.padding(.vertical, 8)
.background(Color.blue.opacity(0.8))
.cornerRadius(8)
}
.frame(maxWidth: .infinity, maxHeight: .infinity)
} else if store.moments.isEmpty {
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)
} else {
ScrollView {
WithPerceptionTracking {
LazyVStack(spacing: 12) {
ForEach(Array(store.moments.enumerated()), id: \.element.dynamicId) { index, moment in
OptimizedDynamicCardView(
moment: moment,
allMoments: store.moments,
currentIndex: index,
onImageTap: { images, tappedIndex in
previewCurrentIndex = tappedIndex
previewItem = PreviewItem(images: images, index: tappedIndex)
},
onLikeTap: { _, _, _, _ in
//
},
onCardTap: {
store.send(.showDetail(moment))
},
onAvatarTap: nil // MeView
)
.padding(.horizontal, 12)
}
if store.hasMore {
ProgressView()
.onAppear {
store.send(.loadMore)
}
}
//
Color.clear.frame(height: 120)
}
.padding(.top, 8)
}
}
.refreshable {
store.send(.refresh)
}
}
}
}
}