feat: 新增CreateFeedView优化任务总结文档及相关功能实现

- 在CreateFeedView中优化发布按钮样式,增加圆角背景和渐变色。
- 移除内容输入区域的深灰色背景,提升UI体验。
- 实现点击发布按钮时自动收起键盘功能。
- 添加发布成功通知机制,确保外层刷新列表数据。
- 更新相关Feature以支持跨Feature通信和状态管理。
This commit is contained in:
edwinQQQ
2025-07-31 14:23:15 +08:00
parent b966e24532
commit 1f17960b8d
6 changed files with 95 additions and 12 deletions

View File

@@ -0,0 +1,43 @@
# CreateFeedView 优化任务总结
## 任务要求
1. 发布按钮增加圆角背景高45左右距离俯视图16背景为左到右渐变色 #F854FC-#500FFF
2. 移除内容输入区域的深灰色背景
3. 点击发布按钮时,收起键盘
4. 发布按钮触发api并成功后要自动收起createfeedview并通知外层刷新列表数据
## 实施内容
### 1. UI样式修改 (CreateFeedView.swift)
- ✅ 发布按钮样式高度45px左右边距16px渐变色背景 #F854FC-#500FFF
- ✅ 移除内容输入区域的深灰色背景
- ✅ 添加键盘收起功能:使用@FocusState管理焦点状态
### 2. 发布成功通知机制
- ✅ CreateFeedFeature添加publishSuccess Action
- ✅ 发布成功后发送通知NotificationCenter.default.post
- ✅ FeedListFeature监听通知并转发给MainFeature
- ✅ MainFeature同时刷新FeedList和Me页面数据
### 3. 架构设计
```
CreateFeedFeature.publishSuccess
↓ (NotificationCenter)
FeedListFeature.createFeedPublishSuccess
↓ (TCA Action)
MainFeature.feedList(.createFeedPublishSuccess)
↓ (Effect.merge)
FeedListFeature.reload + MeFeature.refresh
```
## 技术要点
1. 使用@FocusState管理键盘焦点,点击发布按钮时自动收起键盘
2. 使用NotificationCenter进行跨Feature通信
3. 通过TCA的Effect.merge同时触发多个刷新操作
4. 保持TCA架构的清晰分层
## 测试建议
1. 测试发布按钮样式是否正确显示
2. 测试点击发布按钮时键盘是否收起
3. 测试发布成功后是否自动关闭页面
4. 测试FeedList和Me页面是否自动刷新显示新数据

View File

@@ -49,6 +49,9 @@ struct CreateFeedFeature {
case imageUploadCompleted([String], [UIImage]) // urls, images
case imageUploadFailed(Error)
case publishContent
//
case publishSuccess
}
@Dependency(\.apiService) var apiService
@@ -216,7 +219,11 @@ struct CreateFeedFeature {
case .publishResponse(.success(let response)):
state.isLoading = false
if response.code == 200 {
return .send(.dismissView)
//
return .merge(
.send(.publishSuccess),
.send(.dismissView)
)
} else {
state.errorMessage = response.message.isEmpty ? "发布失败" : response.message
return .none
@@ -238,6 +245,11 @@ struct CreateFeedFeature {
return .run { _ in
await dismiss()
}
case .publishSuccess:
//
return .run { _ in
NotificationCenter.default.post(name: .init("CreateFeedPublishSuccess"), object: nil)
}
}
}
}
@@ -266,6 +278,8 @@ extension CreateFeedFeature.Action: Equatable {
return a.localizedDescription == b.localizedDescription
case (.publishContent, .publishContent):
return true
case (.publishSuccess, .publishSuccess):
return true
default:
return false
}

View File

@@ -47,6 +47,8 @@ struct FeedListFeature {
// Action
case likeDynamic(Int, Int, Int, Int) // dynamicId, uid, likedUid, worldId
case likeResponse(TaskResult<LikeDynamicResponse>, dynamicId: Int, loadingId: UUID?)
// CreateFeed
case createFeedPublishSuccess
// Action
}
@@ -142,6 +144,9 @@ struct FeedListFeature {
case .editFeedDismissed:
state.isEditFeedPresented = false
return .none
case .createFeedPublishSuccess:
// CreateFeed
return .send(.reload)
case .testButtonTapped:
debugInfoSync("[LOG] FeedListFeature testButtonTapped")
return .none

View File

@@ -74,6 +74,12 @@ struct MainFeature {
case .feedList(.testButtonTapped):
state.navigationPath.append(.testView)
return .none
case .feedList(.createFeedPublishSuccess):
// CreateFeedFeedListMe
return .merge(
.send(.feedList(.reload)),
.send(.me(.refresh))
)
case .feedList:
return .none
case let .accountModelLoaded(accountModel):

View File

@@ -6,6 +6,7 @@ struct CreateFeedView: View {
let store: StoreOf<CreateFeedFeature>
@State private var keyboardHeight: CGFloat = 0
@State private var isKeyboardVisible: Bool = false
@FocusState private var isTextEditorFocused: Bool
var body: some View {
WithPerceptionTracking {
@@ -18,7 +19,7 @@ struct CreateFeedView: View {
//
VStack(spacing: 20) {
ContentInputSection(store: store)
ContentInputSection(store: store, isFocused: $isTextEditorFocused)
ImageSelectionSection(store: store)
LoadingAndErrorSection(store: store)
@@ -30,7 +31,7 @@ struct CreateFeedView: View {
// -
if !isKeyboardVisible {
PublishButtonSection(store: store, keyboardHeight: keyboardHeight, geometry: geometry)
PublishButtonSection(store: store, keyboardHeight: keyboardHeight, geometry: geometry, isFocused: $isTextEditorFocused)
}
}
}
@@ -53,6 +54,7 @@ struct CreateFeedView: View {
ToolbarItem(placement: .navigationBarTrailing) {
if isKeyboardVisible {
Button(action: {
isTextEditorFocused = false //
store.send(.publishButtonTapped)
}) {
HStack(spacing: 4) {
@@ -114,15 +116,13 @@ struct CreateFeedView: View {
// MARK: -
struct ContentInputSection: View {
let store: StoreOf<CreateFeedFeature>
@FocusState.Binding var isFocused: Bool
var body: some View {
VStack(alignment: .leading, spacing: 12) {
//
// -
ZStack(alignment: .topLeading) {
RoundedRectangle(cornerRadius: 12)
.fill(Color.white.opacity(0.1))
.frame(height: 200)
if store.content.isEmpty {
Text(NSLocalizedString("createFeed.enterContent", comment: "Enter Content"))
.foregroundColor(.white.opacity(0.5))
@@ -137,6 +137,7 @@ struct ContentInputSection: View {
.padding(.vertical, 8)
.scrollContentBackground(.hidden)
.frame(height: 200)
.focused($isFocused)
}
//
@@ -249,10 +250,12 @@ struct PublishButtonSection: View {
let store: StoreOf<CreateFeedFeature>
let keyboardHeight: CGFloat
let geometry: GeometryProxy
@FocusState.Binding var isFocused: Bool
var body: some View {
VStack {
Button(action: {
isFocused = false //
store.send(.publishButtonTapped)
}) {
HStack {
@@ -270,13 +273,22 @@ struct PublishButtonSection: View {
}
}
.frame(maxWidth: .infinity)
.frame(height: 50)
.background(Color(hex: 0x0C0527))
.cornerRadius(25)
.frame(height: 45)
.background(
LinearGradient(
gradient: Gradient(colors: [
Color(hex: 0xF854FC),
Color(hex: 0x500FFF)
]),
startPoint: .leading,
endPoint: .trailing
)
)
.cornerRadius(22.5)
.disabled(store.isLoading || store.isUploadingImages || !store.canPublish)
.opacity(buttonOpacity)
}
.padding(.horizontal, 20)
.padding(.horizontal, 16)
.padding(.bottom, bottomPadding)
}
.background(Color(hex: 0x0C0527))

View File

@@ -262,6 +262,9 @@ struct FeedListView: View {
CreateFeedFeature()
}
)
.onReceive(NotificationCenter.default.publisher(for: .init("CreateFeedPublishSuccess"))) { _ in
store.send(.createFeedPublishSuccess)
}
}
//
.navigationDestination(isPresented: viewStore.binding(get: \.showDetail, send: { _ in .detailDismissed })) {