
- 更新Yana项目文档,调整适用版本至iOS 17,确保与最新开发环境兼容。 - 在多个视图中重构代码,优化状态管理和视图逻辑,提升用户体验。 - 添加默认初始化器以简化状态管理,确保各个Feature的状态一致性。 - 更新视图组件,移除不必要的硬编码,增强代码可读性和维护性。 - 修复多个视图中的逻辑错误,确保功能正常运行。
229 lines
8.8 KiB
Swift
229 lines
8.8 KiB
Swift
import SwiftUI
|
||
import ComposableArchitecture
|
||
|
||
struct DetailView: View {
|
||
@State var store: StoreOf<DetailFeature>
|
||
let onLikeSuccess: ((Int, Bool) -> Void)?
|
||
|
||
init(store: StoreOf<DetailFeature>, onLikeSuccess: ((Int, Bool) -> Void)? = nil) {
|
||
self.store = store
|
||
self.onLikeSuccess = onLikeSuccess
|
||
}
|
||
|
||
var body: some View {
|
||
ZStack {
|
||
// 背景图片
|
||
Image("bg")
|
||
.resizable()
|
||
.aspectRatio(contentMode: .fill)
|
||
.ignoresSafeArea()
|
||
|
||
VStack(spacing: 0) {
|
||
// 自定义导航栏
|
||
WithPerceptionTracking {
|
||
CustomNavigationBar(
|
||
title: NSLocalizedString("detail.title", comment: "Detail page title"),
|
||
showDeleteButton: isCurrentUserDynamic,
|
||
isDeleteLoading: store.isDeleteLoading,
|
||
onBack: {
|
||
// 移除 onDismiss?() 调用,因为现在使用 dismiss()
|
||
},
|
||
onDelete: {
|
||
store.send(.deleteDynamic)
|
||
}
|
||
)
|
||
}
|
||
.padding(.top, 24)
|
||
|
||
// 内容区域
|
||
ScrollView {
|
||
VStack(spacing: 0) {
|
||
// 使用OptimizedDynamicCardView显示动态内容
|
||
WithPerceptionTracking {
|
||
OptimizedDynamicCardView(
|
||
moment: store.moment,
|
||
allMoments: [store.moment], // 详情页只有一个动态
|
||
currentIndex: 0,
|
||
onImageTap: { images, index in
|
||
store.send(.showImagePreview(images, index))
|
||
},
|
||
onLikeTap: { dynamicId, uid, likedUid, worldId in
|
||
store.send(.likeDynamic(dynamicId, uid, likedUid, worldId))
|
||
},
|
||
onCardTap: nil, // 详情页不需要卡片点击
|
||
isDetailMode: true, // 详情页模式,点击卡片不跳转
|
||
isLikeLoading: store.isLikeLoading
|
||
)
|
||
.padding(.horizontal, 16)
|
||
.padding(.top, 16)
|
||
.padding(.bottom, 116)
|
||
}
|
||
}
|
||
}
|
||
}
|
||
}
|
||
.navigationBarHidden(true)
|
||
.onAppear {
|
||
debugInfoSync("🔍 DetailView: onAppear - moment.uid: \(store.moment.uid)")
|
||
store.send(.onAppear)
|
||
}
|
||
.onChange(of: store.shouldDismiss) { shouldDismiss in
|
||
if shouldDismiss {
|
||
debugInfoSync("🔍 DetailView: shouldDismiss = true, 调用onDismiss")
|
||
// 移除 onDismiss?() 移除此行,因为我们现在使用 dismiss
|
||
}
|
||
}
|
||
.fullScreenCover(isPresented: Binding(
|
||
get: { store.showImagePreview },
|
||
set: { _ in store.send(.hideImagePreview) }
|
||
)) {
|
||
WithPerceptionTracking {
|
||
ImagePreviewPager(
|
||
images: store.selectedImages,
|
||
currentIndex: Binding(
|
||
get: { store.selectedImageIndex },
|
||
set: { newIndex in
|
||
store.send(.showImagePreview(store.selectedImages, newIndex))
|
||
}
|
||
),
|
||
onClose: {
|
||
store.send(.imagePreviewDismissed)
|
||
}
|
||
)
|
||
}
|
||
}
|
||
}
|
||
|
||
// 判断是否为当前用户的动态
|
||
private var isCurrentUserDynamic: Bool {
|
||
// 使用store中的当前用户ID进行判断
|
||
guard let currentUserId = store.currentUserId,
|
||
let currentUserIdInt = Int(currentUserId) else {
|
||
debugInfoSync("🔍 DetailView: 无法获取当前用户ID - currentUserId: \(store.currentUserId ?? "nil")")
|
||
return false
|
||
}
|
||
let isCurrentUser = store.moment.uid == currentUserIdInt
|
||
debugInfoSync("🔍 DetailView: 动态用户判断 - moment.uid: \(store.moment.uid), currentUserId: \(currentUserIdInt), isCurrentUser: \(isCurrentUser)")
|
||
return isCurrentUser
|
||
}
|
||
}
|
||
|
||
// MARK: - CustomNavigationBar
|
||
struct CustomNavigationBar: View {
|
||
let title: String
|
||
let showDeleteButton: Bool
|
||
let isDeleteLoading: Bool
|
||
let onBack: () -> Void
|
||
let onDelete: () -> Void
|
||
init(title: String, showDeleteButton: Bool, isDeleteLoading: Bool, onBack: @escaping () -> Void, onDelete: @escaping () -> Void) {
|
||
self.title = title
|
||
self.showDeleteButton = showDeleteButton
|
||
self.isDeleteLoading = isDeleteLoading
|
||
self.onBack = onBack
|
||
self.onDelete = onDelete
|
||
}
|
||
@SwiftUI.Environment(\.dismiss) private var dismiss: SwiftUI.DismissAction
|
||
|
||
var body: some View {
|
||
HStack {
|
||
// 返回按钮
|
||
Button(action: {
|
||
onBack()
|
||
dismiss() // 使用 dismiss 关闭视图
|
||
}) {
|
||
Image(systemName: "chevron.left")
|
||
.font(.system(size: 20, weight: .medium))
|
||
.foregroundColor(.white)
|
||
.frame(width: 44, height: 44)
|
||
.background(Color.black.opacity(0.3))
|
||
.clipShape(Circle())
|
||
}
|
||
|
||
Spacer()
|
||
|
||
// 标题
|
||
Text(title)
|
||
.font(.system(size: 18, weight: .semibold))
|
||
.foregroundColor(.white)
|
||
.shadow(color: .black.opacity(0.5), radius: 2, x: 0, y: 1)
|
||
|
||
Spacer()
|
||
|
||
// 删除按钮(仅在需要时显示)
|
||
WithPerceptionTracking {
|
||
if showDeleteButton {
|
||
Button(action: onDelete) {
|
||
if isDeleteLoading {
|
||
ProgressView()
|
||
.progressViewStyle(CircularProgressViewStyle(tint: .white))
|
||
.scaleEffect(0.8)
|
||
.frame(width: 44, height: 44)
|
||
.background(Color.red.opacity(0.8))
|
||
.clipShape(Circle())
|
||
} else {
|
||
Image(systemName: "trash")
|
||
.font(.system(size: 16, weight: .medium))
|
||
.foregroundColor(.white)
|
||
.frame(width: 44, height: 44)
|
||
.background(Color.red.opacity(0.8))
|
||
.clipShape(Circle())
|
||
}
|
||
}
|
||
.disabled(isDeleteLoading)
|
||
} else {
|
||
// 占位,保持标题居中
|
||
Color.clear
|
||
.frame(width: 44, height: 44)
|
||
}
|
||
}
|
||
}
|
||
.padding(.horizontal, 16)
|
||
.padding(.top, 8)
|
||
.padding(.bottom, 12)
|
||
.background(
|
||
LinearGradient(
|
||
gradient: Gradient(colors: [
|
||
Color.black.opacity(0.4),
|
||
Color.black.opacity(0.2),
|
||
Color.clear
|
||
]),
|
||
startPoint: .top,
|
||
endPoint: .bottom
|
||
)
|
||
)
|
||
}
|
||
}
|
||
|
||
//#Preview {
|
||
// DetailView(
|
||
// store: Store(
|
||
// initialState: DetailFeature.State(
|
||
// moment: MomentsInfo(
|
||
// dynamicId: 1,
|
||
// uid: 123,
|
||
// nick: "Test User",
|
||
// avatar: "https://example.com/avatar.jpg",
|
||
// type: 1,
|
||
// content: "This is a test dynamic content",
|
||
// publishTime: Int(Date().timeIntervalSince1970 * 1000),
|
||
// likeCount: 10,
|
||
// isLike: false,
|
||
// worldId: 1,
|
||
// dynamicResList: [
|
||
// MomentsPicture(
|
||
// id: 1,
|
||
// resUrl: "https://example.com/image1.jpg",
|
||
// format: "jpg",
|
||
// width: 800,
|
||
// height: 600,
|
||
// resDuration: nil
|
||
// )
|
||
// ]
|
||
// )
|
||
// )
|
||
// ) {
|
||
// DetailFeature()
|
||
// }
|
||
// )
|
||
//}
|