feat: 添加COSManagerAdapter以支持新的TCCos组件
- 新增COSManagerAdapter类,保持与现有COSManager相同的接口,内部使用新的TCCos组件。 - 实现获取、刷新Token及上传图片的功能,确保与腾讯云COS的兼容性。 - 在CreateFeedView中重构内容输入、图片选择和发布按钮逻辑,提升用户体验。 - 更新EditFeedView以优化视图结构和状态管理,确保功能正常运行。 - 在多个视图中添加键盘状态管理,改善用户交互体验。
This commit is contained in:
@@ -13,70 +13,68 @@ struct EditFeedView: View {
|
||||
}
|
||||
|
||||
var body: some View {
|
||||
WithPerceptionTracking {
|
||||
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
|
||||
}
|
||||
GeometryReader { geometry in
|
||||
ZStack {
|
||||
backgroundView
|
||||
mainContent(geometry: geometry)
|
||||
if store.isUploadingImages {
|
||||
uploadingImagesOverlay(progress: store.imageUploadProgress)
|
||||
} else if store.isLoading {
|
||||
loadingOverlay
|
||||
}
|
||||
}
|
||||
.navigationBarHidden(true)
|
||||
.onAppear {
|
||||
store.send(.clearError)
|
||||
}
|
||||
.onChange(of: store.shouldDismiss) {
|
||||
if store.shouldDismiss {
|
||||
onDismiss()
|
||||
.contentShape(Rectangle())
|
||||
.onTapGesture {
|
||||
if isKeyboardVisible {
|
||||
hideKeyboard()
|
||||
}
|
||||
}
|
||||
.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))
|
||||
}
|
||||
.onReceive(NotificationCenter.default.publisher(for: UIResponder.keyboardWillShowNotification)) { _ in
|
||||
withAnimation(.easeInOut(duration: 0.3)) {
|
||||
isKeyboardVisible = true
|
||||
}
|
||||
Button("取消", role: .cancel) {
|
||||
store.send(.deleteImageAlertDismissed)
|
||||
}
|
||||
} message: {
|
||||
Text("确定要删除这张图片吗?")
|
||||
}
|
||||
.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("确定要删除这张图片吗?")
|
||||
}
|
||||
}
|
||||
|
||||
@@ -86,127 +84,117 @@ struct EditFeedView: View {
|
||||
}
|
||||
|
||||
private func mainContent(geometry: GeometryProxy) -> some View {
|
||||
WithPerceptionTracking {
|
||||
VStack(spacing: 0) {
|
||||
topNavigationBar
|
||||
|
||||
ScrollView {
|
||||
VStack(spacing: 20) {
|
||||
textInputSection
|
||||
imageSelectionSection
|
||||
publishButton
|
||||
}
|
||||
.padding(.horizontal, 20)
|
||||
.padding(.bottom, 40)
|
||||
VStack(spacing: 0) {
|
||||
topNavigationBar
|
||||
|
||||
ScrollView {
|
||||
VStack(spacing: 20) {
|
||||
textInputSection
|
||||
imageSelectionSection
|
||||
publishButton
|
||||
}
|
||||
.padding(.horizontal, 20)
|
||||
.padding(.bottom, 40)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private var topNavigationBar: some View {
|
||||
WithPerceptionTracking {
|
||||
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))
|
||||
HStack {
|
||||
Button(action: {
|
||||
store.send(.clearDismissFlag)
|
||||
onDismiss()
|
||||
}) {
|
||||
Image(systemName: "xmark")
|
||||
.font(.system(size: 20, weight: .medium))
|
||||
.foregroundColor(.white)
|
||||
|
||||
Spacer()
|
||||
|
||||
Color.clear
|
||||
.frame(width: 44, height: 44)
|
||||
}
|
||||
.padding(.horizontal, 16)
|
||||
.padding(.top, 8)
|
||||
.padding(.bottom, 16)
|
||||
|
||||
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 {
|
||||
WithPerceptionTracking {
|
||||
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))
|
||||
VStack(alignment: .leading, spacing: 12) {
|
||||
Text("分享你的想法...")
|
||||
.font(.system(size: 16, weight: .medium))
|
||||
.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))
|
||||
}
|
||||
|
||||
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 {
|
||||
WithPerceptionTracking {
|
||||
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)
|
||||
}
|
||||
)
|
||||
}
|
||||
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 {
|
||||
WithPerceptionTracking {
|
||||
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)
|
||||
}
|
||||
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)
|
||||
}
|
||||
.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 {
|
||||
|
Reference in New Issue
Block a user