Files
e-party-iOS/yana/Features/EditFeedFeature.swift
edwinQQQ 2a02553015 feat: 增强编辑动态功能,支持图片选择与处理
- 在EditFeedFeature中新增图片选择相关状态和动作,支持用户选择和处理最多9张图片。
- 在EditFeedView中集成ModernImageSelectionGrid组件,优化图片选择界面。
- 更新CreateFeedView以支持图片选择功能,提升用户体验。
- 实现图片处理逻辑,确保用户能够方便地添加和删除图片。
2025-07-22 18:06:10 +08:00

140 lines
5.1 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 Foundation
import ComposableArchitecture
import SwiftUI
import PhotosUI // PhotosUI
@Reducer
struct EditFeedFeature {
@ObservableState
struct State: Equatable {
var content: String = ""
var isLoading: Bool = false
var errorMessage: String? = nil
var shouldDismiss: Bool = false
var selectedImages: [PhotosPickerItem] = []
var processedImages: [UIImage] = []
var canAddMoreImages: Bool {
processedImages.count < 9
}
var canPublish: Bool {
!content.trimmingCharacters(in: .whitespacesAndNewlines).isEmpty && !isLoading
}
// EquatableselectedImagesPhotosPickerItemEquatable
static func == (lhs: State, rhs: State) -> Bool {
lhs.content == rhs.content &&
lhs.isLoading == rhs.isLoading &&
lhs.errorMessage == rhs.errorMessage &&
lhs.shouldDismiss == rhs.shouldDismiss &&
lhs.processedImages == rhs.processedImages &&
lhs.selectedImages.count == rhs.selectedImages.count
}
}
enum Action {
case contentChanged(String)
case publishButtonTapped
case publishResponse(Result<PublishFeedResponse, Error>)
case clearError
case dismissView
case clearDismissFlag
// Action
case photosPickerItemsChanged([PhotosPickerItem])
case processPhotosPickerItems([PhotosPickerItem])
case updateProcessedImages([UIImage])
case removeImage(Int)
}
@Dependency(\.apiService) var apiService
@Dependency(\.dismiss) var dismiss
@Dependency(\.isPresented) var isPresented
var body: some ReducerOf<Self> {
Reduce { state, action in
switch action {
case .contentChanged(let newContent):
state.content = newContent
return .none
case .publishButtonTapped:
guard state.canPublish else {
state.errorMessage = "请输入内容"
return .none
}
state.isLoading = true
state.errorMessage = nil
return .run { [content = state.content] send in
let userId = await UserInfoManager.getCurrentUserId() ?? ""
let request = await PublishFeedRequest.make(
content: content.trimmingCharacters(in: .whitespacesAndNewlines),
uid: userId,
type: "0"
)
do {
let response = try await apiService.request(request)
await send(.publishResponse(.success(response)))
} catch {
await send(.publishResponse(.failure(error)))
}
}
case .publishResponse(.success(let response)):
state.isLoading = false
if response.code == 200 {
return .send(.dismissView)
} else {
state.errorMessage = response.message.isEmpty ? "发布失败" : response.message
return .none
}
case .publishResponse(.failure(let error)):
state.isLoading = false
state.errorMessage = error.localizedDescription
return .none
case .clearError:
state.errorMessage = nil
return .none
case .dismissView:
state.shouldDismiss = true
return .none
case .clearDismissFlag:
state.shouldDismiss = false
return .none
case .photosPickerItemsChanged(let items):
state.selectedImages = items
return .run { send in
await send(.processPhotosPickerItems(items))
}
case .processPhotosPickerItems(let items):
let currentImages = state.processedImages
return .run { send in
var newImages = currentImages
for item in items {
guard let data = try? await item.loadTransferable(type: Data.self),
let image = UIImage(data: data) else { continue }
if newImages.count < 9 {
newImages.append(image)
}
}
await MainActor.run {
send(.updateProcessedImages(newImages))
}
}
case .updateProcessedImages(let images):
state.processedImages = images
return .none
case .removeImage(let index):
guard index < state.processedImages.count else { return .none }
state.processedImages.remove(at: index)
if index < state.selectedImages.count {
state.selectedImages.remove(at: index)
}
return .none
}
}
}
}