Files
e-party-iOS/yana/Views/EditFeedView.swift
edwinQQQ beda539e00 feat: 添加COSManagerAdapter以支持新的TCCos组件
- 新增COSManagerAdapter类,保持与现有COSManager相同的接口,内部使用新的TCCos组件。
- 实现获取、刷新Token及上传图片的功能,确保与腾讯云COS的兼容性。
- 在CreateFeedView中重构内容输入、图片选择和发布按钮逻辑,提升用户体验。
- 更新EditFeedView以优化视图结构和状态管理,确保功能正常运行。
- 在多个视图中添加键盘状态管理,改善用户交互体验。
2025-07-31 11:41:38 +08:00

311 lines
9.7 KiB
Swift

import SwiftUI
import ComposableArchitecture
import PhotosUI
struct EditFeedView: View {
let onDismiss: () -> Void
let store: StoreOf<EditFeedFeature>
@State private var isKeyboardVisible = false
private let maxCount = 500
private func hideKeyboard() {
UIApplication.shared.sendAction(#selector(UIResponder.resignFirstResponder), to: nil, from: nil, for: nil)
}
var body: some View {
GeometryReader { geometry in
ZStack {
backgroundView
mainContent(geometry: geometry)
if store.isUploadingImages {
uploadingImagesOverlay(progress: store.imageUploadProgress)
} else if store.isLoading {
loadingOverlay
}
}
.contentShape(Rectangle())
.onTapGesture {
if isKeyboardVisible {
hideKeyboard()
}
}
.onReceive(NotificationCenter.default.publisher(for: UIResponder.keyboardWillShowNotification)) { _ in
withAnimation(.easeInOut(duration: 0.3)) {
isKeyboardVisible = true
}
}
.onReceive(NotificationCenter.default.publisher(for: UIResponder.keyboardWillHideNotification)) { _ in
withAnimation(.easeInOut(duration: 0.3)) {
isKeyboardVisible = false
}
}
}
.navigationBarHidden(true)
.onAppear {
store.send(.clearError)
}
.onChange(of: store.shouldDismiss) {
if store.shouldDismiss {
onDismiss()
}
}
.photosPicker(
isPresented: Binding(
get: { store.showPhotosPicker },
set: { _ in store.send(.photosPickerDismissed) }
),
selection: Binding(
get: { store.selectedPhotoItems },
set: { store.send(.photosPickerItemsChanged($0)) }
),
maxSelectionCount: 9,
matching: .images
)
.alert("删除图片", isPresented: Binding(
get: { store.showDeleteImageAlert },
set: { _ in store.send(.deleteImageAlertDismissed) }
)) {
Button("删除", role: .destructive) {
if let indexToDelete = store.imageToDeleteIndex {
store.send(.removeImage(indexToDelete))
}
}
Button("取消", role: .cancel) {
store.send(.deleteImageAlertDismissed)
}
} message: {
Text("确定要删除这张图片吗?")
}
}
private var backgroundView: some View {
Color(hex: 0x0C0527)
.ignoresSafeArea()
}
private func mainContent(geometry: GeometryProxy) -> some View {
VStack(spacing: 0) {
topNavigationBar
ScrollView {
VStack(spacing: 20) {
textInputSection
imageSelectionSection
publishButton
}
.padding(.horizontal, 20)
.padding(.bottom, 40)
}
}
}
private var topNavigationBar: some View {
HStack {
Button(action: {
store.send(.clearDismissFlag)
onDismiss()
}) {
Image(systemName: "xmark")
.font(.system(size: 20, weight: .medium))
.foregroundColor(.white)
.frame(width: 44, height: 44)
}
Spacer()
Text("编辑动态")
.font(.system(size: 18, weight: .medium))
.foregroundColor(.white)
Spacer()
Color.clear
.frame(width: 44, height: 44)
}
.padding(.horizontal, 16)
.padding(.top, 8)
.padding(.bottom, 16)
}
private var textInputSection: some View {
VStack(alignment: .leading, spacing: 12) {
Text("分享你的想法...")
.font(.system(size: 16, weight: .medium))
.foregroundColor(.white)
TextEditor(text: Binding(
get: { store.content },
set: { store.send(.contentChanged($0)) }
))
.font(.system(size: 16))
.foregroundColor(.white)
.background(Color.clear)
.frame(minHeight: 120)
.padding(12)
.background(Color.white.opacity(0.1))
.cornerRadius(12)
.overlay(
RoundedRectangle(cornerRadius: 12)
.stroke(Color.white.opacity(0.2), lineWidth: 1)
)
HStack {
Spacer()
Text("\(store.content.count)/\(maxCount)")
.font(.system(size: 12))
.foregroundColor(.white.opacity(0.6))
}
}
}
private var imageSelectionSection: some View {
VStack(alignment: .leading, spacing: 12) {
Text("添加图片")
.font(.system(size: 16, weight: .medium))
.foregroundColor(.white)
ImageGrid(
images: store.processedImages,
onRemoveImage: { index in
store.send(.showDeleteImageAlert(index))
},
onAddImage: {
store.send(.addImageButtonTapped)
}
)
}
}
private var publishButton: some View {
Button(action: {
store.send(.publishButtonTapped)
}) {
if store.isLoading {
ProgressView()
.progressViewStyle(CircularProgressViewStyle(tint: .white))
.scaleEffect(1.2)
} else {
Text("发布")
.font(.system(size: 16, weight: .medium))
.foregroundColor(.white)
}
}
.frame(maxWidth: .infinity)
.padding(.vertical, 16)
.background(store.content.isEmpty ? Color.gray : Color.blue)
.cornerRadius(12)
.disabled(store.isLoading || store.content.isEmpty)
}
private func uploadingImagesOverlay(progress: Double) -> some View {
WithPerceptionTracking {
ZStack {
Color.black.opacity(0.5)
.ignoresSafeArea()
VStack(spacing: 16) {
ProgressView(value: progress)
.progressViewStyle(LinearProgressViewStyle(tint: .white))
.frame(width: 200)
Text("上传图片中... \(Int(progress * 100))%")
.font(.system(size: 16))
.foregroundColor(.white)
}
.padding(24)
.background(Color.black.opacity(0.8))
.cornerRadius(12)
}
}
}
private var loadingOverlay: some View {
WithPerceptionTracking {
ZStack {
Color.black.opacity(0.5)
.ignoresSafeArea()
ProgressView()
.progressViewStyle(CircularProgressViewStyle(tint: .white))
.scaleEffect(1.5)
}
}
}
}
// MARK: -
struct ImageGrid: View {
let images: [UIImage]
let onRemoveImage: (Int) -> Void
let onAddImage: () -> Void
private let columns = Array(repeating: GridItem(.flexible(), spacing: 8), count: 3)
var body: some View {
LazyVGrid(columns: columns, spacing: 8) {
ForEach(Array(images.enumerated()), id: \.offset) { index, image in
ImageGridItem(
image: image,
onRemove: { onRemoveImage(index) }
)
}
if images.count < 9 {
AddImageButton(onTap: onAddImage)
}
}
}
}
// MARK: -
struct ImageGridItem: View {
let image: UIImage
let onRemove: () -> Void
var body: some View {
ZStack(alignment: .topTrailing) {
Image(uiImage: image)
.resizable()
.aspectRatio(contentMode: .fill)
.frame(height: 100)
.clipped()
.cornerRadius(8)
Button(action: onRemove) {
Image(systemName: "xmark.circle.fill")
.font(.system(size: 20))
.foregroundColor(.white)
.background(Color.black.opacity(0.5))
.clipShape(Circle())
}
.padding(4)
}
}
}
// MARK: -
struct AddImageButton: View {
let onTap: () -> Void
var body: some View {
Button(action: onTap) {
VStack {
Image(systemName: "plus")
.font(.system(size: 24))
.foregroundColor(.white.opacity(0.7))
Text("添加")
.font(.system(size: 12))
.foregroundColor(.white.opacity(0.7))
}
.frame(height: 100)
.frame(maxWidth: .infinity)
.background(Color.white.opacity(0.1))
.cornerRadius(8)
.overlay(
RoundedRectangle(cornerRadius: 8)
.stroke(Color.white.opacity(0.2), lineWidth: 1)
)
}
}
}