
- 在APIEndpoints.swift中新增publishFeed端点以支持发布动态。 - 新增PublishFeedRequest和PublishFeedResponse模型,处理发布请求和响应。 - 在EditFeedFeature中实现动态编辑功能,支持用户输入和发布内容。 - 更新CreateFeedView和EditFeedView以集成新的发布功能,提升用户体验。 - 在Localizable.strings中添加相关文本的本地化支持,确保多语言兼容性。 - 优化FeedListView和FeedView以展示最新动态,增强用户交互体验。
227 lines
5.9 KiB
Swift
227 lines
5.9 KiB
Swift
import Foundation
|
||
import ComposableArchitecture
|
||
|
||
// MARK: - 响应数据模型
|
||
|
||
/// 最新动态响应结构
|
||
struct MomentsLatestResponse: Codable, Equatable {
|
||
let code: Int
|
||
let message: String
|
||
let data: MomentsListData?
|
||
let timestamp: Int?
|
||
}
|
||
|
||
/// 动态列表数据
|
||
struct MomentsListData: Codable, Equatable {
|
||
let dynamicList: [MomentsInfo]
|
||
let nextDynamicId: Int
|
||
}
|
||
|
||
/// 动态信息结构
|
||
struct MomentsInfo: Codable, Equatable {
|
||
let dynamicId: Int
|
||
let uid: Int
|
||
let nick: String
|
||
let avatar: String
|
||
let gender: Int
|
||
let type: Int
|
||
let content: String
|
||
let likeCount: Int
|
||
let isLike: Bool
|
||
let commentCount: Int
|
||
let publishTime: Int
|
||
let worldId: Int
|
||
let squareTop: Int
|
||
let topicTop: Int
|
||
let newUser: Bool
|
||
let defUser: Int
|
||
let status: Int
|
||
let scene: String
|
||
let dynamicResList: [MomentsPicture]?
|
||
let userVipInfoVO: UserVipInfo?
|
||
|
||
// 头饰相关 - 全部可选
|
||
let headwearPic: String?
|
||
let headwearEffect: String?
|
||
let headwearType: Int?
|
||
let headwearName: String?
|
||
let headwearId: Int?
|
||
|
||
// 等级相关 - 全部可选
|
||
let experLevelPic: String?
|
||
let charmLevelPic: String?
|
||
|
||
// 其他可选字段
|
||
let isCustomWord: Bool?
|
||
let labelList: [String]?
|
||
|
||
// 计算属性:将Int转换为Bool
|
||
var isSquareTop: Bool { squareTop != 0 }
|
||
var isTopicTop: Bool { topicTop != 0 }
|
||
|
||
// 计算属性:格式化时间戳
|
||
var formattedPublishTime: Date {
|
||
Date(timeIntervalSince1970: TimeInterval(publishTime) / 1000.0)
|
||
}
|
||
}
|
||
|
||
/// 动态图片信息
|
||
struct MomentsPicture: Codable, Equatable {
|
||
let id: Int
|
||
let resUrl: String
|
||
let format: String
|
||
let width: Int
|
||
let height: Int
|
||
let resDuration: Int? // 可选字段,因为有些图片没有这个字段
|
||
}
|
||
|
||
/// 用户VIP信息 - 完整版本,所有字段都是可选的
|
||
struct UserVipInfo: Codable, Equatable {
|
||
let vipLevel: Int?
|
||
let vipName: String?
|
||
let vipIcon: String?
|
||
let vipLogo: String?
|
||
let nameplateId: Int?
|
||
let nameplateUrl: String?
|
||
let userCardBG: String?
|
||
let expireTime: Int?
|
||
let preventKick: Bool?
|
||
let preventTrace: Bool?
|
||
let preventFollow: Bool?
|
||
let micNickColour: String?
|
||
let micCircle: String?
|
||
let enterRoomEffects: String?
|
||
let medalSeat: Int?
|
||
let friendNickColour: String?
|
||
let visitHide: Bool?
|
||
let visitListView: Bool?
|
||
let privateChatLimit: Bool?
|
||
let roomPicScreen: Bool?
|
||
let uploadGifAvatar: Bool?
|
||
let enterHide: Bool?
|
||
}
|
||
|
||
// MARK: - 内容类型枚举
|
||
|
||
/// 动态内容类型
|
||
enum MomentsContentType: Int, CaseIterable {
|
||
case text = 0 // 纯文字
|
||
case picture = 2 // 图片
|
||
|
||
/// 转换为API参数字符串
|
||
static func toAPIParameter(_ types: [MomentsContentType]) -> String {
|
||
return types.map { String($0.rawValue) }.joined(separator: ",")
|
||
}
|
||
}
|
||
|
||
// MARK: - 最新动态 API 请求
|
||
|
||
/// 获取最新动态列表的API请求
|
||
struct LatestDynamicsRequest: APIRequestProtocol {
|
||
typealias Response = MomentsLatestResponse
|
||
|
||
let endpoint: String = APIEndpoint.latestDynamics.path
|
||
let method: HTTPMethod = .GET
|
||
|
||
let dynamicId: String
|
||
let pageSize: Int
|
||
let types: [MomentsContentType]
|
||
|
||
/// 初始化请求
|
||
/// - Parameters:
|
||
/// - dynamicId: 最新动态的ID,用于分页加载。首次请求传空字符串
|
||
/// - pageSize: 每页返回的数据数量,默认20
|
||
/// - types: 动态内容类型数组,默认包含文字和图片
|
||
init(
|
||
dynamicId: String = "",
|
||
pageSize: Int = 20,
|
||
types: [MomentsContentType] = [.text, .picture]
|
||
) {
|
||
self.dynamicId = dynamicId
|
||
self.pageSize = pageSize
|
||
self.types = types
|
||
}
|
||
|
||
var queryParameters: [String: String]? {
|
||
return [
|
||
"dynamicId": dynamicId,
|
||
"pageSize": String(pageSize),
|
||
"types": MomentsContentType.toAPIParameter(types)
|
||
]
|
||
}
|
||
|
||
var bodyParameters: [String: Any]? { nil }
|
||
|
||
var includeBaseParameters: Bool { true }
|
||
|
||
// Loading 配置
|
||
var shouldShowLoading: Bool { true }
|
||
var shouldShowError: Bool { true }
|
||
}
|
||
|
||
// MARK: - 发布动态 API 请求与响应
|
||
|
||
/// 发布动态请求
|
||
struct PublishFeedRequest: APIRequestProtocol {
|
||
typealias Response = PublishFeedResponse
|
||
|
||
let endpoint: String = APIEndpoint.publishFeed.path
|
||
let method: HTTPMethod = .POST
|
||
|
||
let content: String
|
||
let uid: String
|
||
let type: String
|
||
var pub_sign: String
|
||
|
||
var queryParameters: [String: String]? { nil }
|
||
var bodyParameters: [String: Any]? {
|
||
[
|
||
"content": content,
|
||
"uid": uid,
|
||
"type": type,
|
||
"pub_sign": pub_sign
|
||
]
|
||
}
|
||
var includeBaseParameters: Bool { true }
|
||
var shouldShowLoading: Bool { true }
|
||
var shouldShowError: Bool { true }
|
||
|
||
/// async 工厂方法,主线程生成 pub_sign
|
||
static func make(content: String, uid: String, type: String = "0") async -> PublishFeedRequest {
|
||
let base = await MainActor.run { BaseRequest() }
|
||
var mutableBase = base
|
||
mutableBase.generateSignature(with: [
|
||
"content": content,
|
||
"uid": uid,
|
||
"type": type
|
||
])
|
||
return PublishFeedRequest(
|
||
content: content,
|
||
uid: uid,
|
||
type: type,
|
||
pub_sign: mutableBase.pubSign
|
||
)
|
||
}
|
||
|
||
/// 禁止外部直接调用
|
||
private init(content: String, uid: String, type: String, pub_sign: String) {
|
||
self.content = content
|
||
self.uid = uid
|
||
self.type = type
|
||
self.pub_sign = pub_sign
|
||
}
|
||
}
|
||
|
||
/// 发布动态响应
|
||
struct PublishFeedResponse: Codable, Equatable {
|
||
let code: Int
|
||
let message: String
|
||
let data: PublishFeedData?
|
||
let timestamp: Int?
|
||
}
|
||
|
||
/// 发布动态返回数据
|
||
struct PublishFeedData: Codable, Equatable {
|
||
let dynamicId: Int?
|
||
}
|