Files
e-party-iOS/yana/Views/DetailView.swift
edwinQQQ f9ff572a30 feat: 更新视图组件以增强用户交互体验和图片处理功能
- 在AppSettingView中重构主视图逻辑,优化图片选择与预览功能。
- 在FeedListFeature中改进点赞状态管理,确保动态更新流畅。
- 在DetailView中添加卡片点击回调,提升用户交互体验。
- 在OptimizedDynamicCardView中新增卡片点击手势,支持非详情页模式下的交互。
- 在swift-assistant-style.mdc中更新功能要求,强调使用函数式编程。
2025-07-28 17:20:25 +08:00

220 lines
8.3 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 DetailView: View {
@State var store: StoreOf<DetailFeature>
let onLikeSuccess: ((Int, Bool) -> Void)?
let onDismiss: (() -> Void)? //
init(store: StoreOf<DetailFeature>, onLikeSuccess: ((Int, Bool) -> Void)? = nil, onDismiss: (() -> Void)? = nil) {
self.store = store
self.onLikeSuccess = onLikeSuccess
self.onDismiss = onDismiss
}
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?() //
},
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?()
}
}
.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 {
// 使storeID
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
var body: some View {
HStack {
//
Button(action: onBack) {
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()
// }
// )
//}