
- 新增MainView Tab切换问题分析文档,详细描述问题原因及解决方案。 - 优化BottomTabView的绑定逻辑,简化状态管理,确保Tab切换时状态正确更新。 - 在MeView中实现用户信息加载逻辑调整,确保动态列表仅在首次进入时加载,并添加错误处理视图。 - 创建EmptyStateView组件,提供统一的空状态展示和重试功能。 - 增强调试信息输出,便于后续问题排查和用户体验提升。
206 lines
8.6 KiB
Swift
206 lines
8.6 KiB
Swift
import Foundation
|
||
import ComposableArchitecture
|
||
import CasePaths
|
||
|
||
@Reducer
|
||
struct MainFeature {
|
||
enum Tab: Int, Equatable, CaseIterable {
|
||
case feed, other
|
||
}
|
||
|
||
@ObservableState
|
||
struct State: Equatable {
|
||
var selectedTab: Tab = .feed
|
||
var feedList: FeedListFeature.State = .init()
|
||
var me: MeFeature.State
|
||
var accountModel: AccountModel? = nil
|
||
// 新增:导航路径和设置页面 State
|
||
var navigationPath: [Destination] = []
|
||
var appSettingState: AppSettingFeature.State? = nil
|
||
// 新增:登出标志
|
||
var isLoggedOut: Bool = false
|
||
|
||
init(accountModel: AccountModel? = nil) {
|
||
self.accountModel = accountModel
|
||
let uid = accountModel?.uid.flatMap { Int($0) } ?? 0
|
||
debugInfoSync("🏗️ MainFeature 初始化")
|
||
debugInfoSync(" accountModel.uid: \(accountModel?.uid ?? "nil")")
|
||
debugInfoSync(" 转换后的uid: \(uid)")
|
||
|
||
// 如果没有传入accountModel,尝试从Keychain获取
|
||
if accountModel == nil {
|
||
debugInfoSync(" 🔍 尝试从Keychain获取AccountModel")
|
||
Task {
|
||
if let savedAccountModel = await UserInfoManager.getAccountModel() {
|
||
debugInfoSync(" ✅ 从Keychain获取到AccountModel: \(savedAccountModel.uid ?? "nil")")
|
||
} else {
|
||
debugInfoSync(" ⚠️ 从Keychain未获取到AccountModel")
|
||
}
|
||
}
|
||
}
|
||
|
||
var meState = MeFeature.State(displayUID: uid > 0 ? uid : nil)
|
||
if uid > 0 {
|
||
meState.uid = uid // 确保uid与displayUID一致
|
||
}
|
||
self.me = meState
|
||
debugInfoSync(" meState.uid: \(meState.uid)")
|
||
debugInfoSync(" meState.displayUID: \(meState.displayUID ?? -1)")
|
||
debugInfoSync(" meState.effectiveUID: \(meState.effectiveUID)")
|
||
}
|
||
}
|
||
|
||
// 新增:导航目标
|
||
enum Destination: Hashable, Codable, CaseIterable {
|
||
case appSetting
|
||
case testView
|
||
}
|
||
|
||
@CasePathable
|
||
enum Action: Equatable {
|
||
case onAppear
|
||
case selectTab(Tab)
|
||
case feedList(FeedListFeature.Action)
|
||
case me(MeFeature.Action)
|
||
case accountModelLoaded(AccountModel?)
|
||
// 新增:导航相关
|
||
case navigationPathChanged([Destination])
|
||
case appSettingButtonTapped
|
||
case appSettingAction(AppSettingFeature.Action)
|
||
// 新增:登出
|
||
case logout
|
||
}
|
||
|
||
var body: some ReducerOf<Self> {
|
||
Scope(state: \ .feedList, action: \ .feedList) {
|
||
FeedListFeature()
|
||
}
|
||
Scope(state: \ .me, action: \ .me) {
|
||
MeFeature()
|
||
}
|
||
Reduce { state, action in
|
||
switch action {
|
||
case .onAppear:
|
||
return .run { send in
|
||
let accountModel = await UserInfoManager.getAccountModel()
|
||
await send(.accountModelLoaded(accountModel))
|
||
}
|
||
case .selectTab(let tab):
|
||
debugInfoSync("🎯 MainFeature selectTab: \(tab)")
|
||
debugInfoSync(" 当前selectedTab: \(state.selectedTab)")
|
||
debugInfoSync(" 新selectedTab: \(tab)")
|
||
|
||
// 避免重复设置相同的tab
|
||
guard state.selectedTab != tab else {
|
||
debugInfoSync(" ⚠️ 重复设置相同tab,忽略")
|
||
return .none
|
||
}
|
||
|
||
state.selectedTab = tab
|
||
state.navigationPath = []
|
||
debugInfoSync(" ✅ selectedTab已更新为: \(state.selectedTab)")
|
||
|
||
// 切换到MeView时,确保有有效的uid并触发数据加载
|
||
if tab == .other {
|
||
if let uidStr = state.accountModel?.uid, let uid = Int(uidStr), uid > 0 {
|
||
if state.me.displayUID != uid {
|
||
state.me.displayUID = uid
|
||
state.me.uid = uid // 同步更新uid
|
||
state.me.isFirstLoad = true
|
||
debugInfoSync(" 🔄 更新MeFeature状态,uid: \(uid)")
|
||
}
|
||
debugInfoSync(" 📱 切换到MeView,触发数据加载")
|
||
return .send(.me(.onAppear))
|
||
} else {
|
||
debugInfoSync(" ⚠️ 切换到MeView但uid无效,等待AccountModel加载")
|
||
}
|
||
}
|
||
return .none
|
||
case .feedList(.testButtonTapped):
|
||
state.navigationPath.append(.testView)
|
||
return .none
|
||
case .feedList(.createFeedPublishSuccess):
|
||
// CreateFeed发布成功,刷新FeedList和Me页数据
|
||
return .merge(
|
||
.send(.feedList(.reload)),
|
||
.send(.me(.refresh))
|
||
)
|
||
case .feedList:
|
||
return .none
|
||
case let .accountModelLoaded(accountModel):
|
||
state.accountModel = accountModel
|
||
debugInfoSync("📦 MainFeature: AccountModel已加载")
|
||
debugInfoSync(" uid: \(accountModel?.uid ?? "nil")")
|
||
|
||
// 更新MeFeature状态
|
||
if let uidStr = accountModel?.uid, let uid = Int(uidStr), uid > 0 {
|
||
if state.me.displayUID != uid {
|
||
state.me.displayUID = uid
|
||
state.me.uid = uid // 同步更新uid
|
||
state.me.isFirstLoad = true
|
||
debugInfoSync(" 🔄 更新MeFeature状态,uid: \(uid)")
|
||
}
|
||
|
||
// 如果当前选中的是 MeView 标签页,则触发数据加载
|
||
if state.selectedTab == .other {
|
||
debugInfoSync(" 📱 当前在MeView,触发数据加载")
|
||
return .send(.me(.onAppear))
|
||
}
|
||
|
||
// 如果当前选中的是 FeedView 标签页,则触发数据加载
|
||
if state.selectedTab == .feed {
|
||
debugInfoSync(" 📱 当前在FeedView,触发数据加载")
|
||
return .send(.feedList(.checkAuthAndLoad))
|
||
}
|
||
} else {
|
||
debugInfoSync(" ⚠️ AccountModel中uid无效")
|
||
}
|
||
return .none
|
||
case .me(.settingButtonTapped):
|
||
// 触发 push 到设置页,带入当前用户信息
|
||
let userInfo = state.me.userInfo
|
||
let avatarURL = userInfo?.avatar
|
||
let nickname = userInfo?.nick ?? ""
|
||
state.appSettingState = AppSettingFeature.State(nickname: nickname, avatarURL: avatarURL, userInfo: userInfo)
|
||
state.navigationPath.append(.appSetting)
|
||
return .none
|
||
case .me:
|
||
return .none
|
||
case .navigationPathChanged(let newPath):
|
||
// pop 回来时清空 settingState
|
||
state.navigationPath = newPath
|
||
return .none
|
||
case .appSettingButtonTapped:
|
||
let userInfo = state.me.userInfo
|
||
let avatarURL = userInfo?.avatar
|
||
let nickname = userInfo?.nick ?? ""
|
||
state.appSettingState = AppSettingFeature.State(nickname: nickname, avatarURL: avatarURL, userInfo: userInfo)
|
||
state.navigationPath.append(.appSetting)
|
||
return .none
|
||
case .appSettingAction(.logoutConfirmed):
|
||
// 监听到确认登出,设置登出标志
|
||
state.isLoggedOut = true
|
||
return .none
|
||
case .appSettingAction(.dismissTapped):
|
||
// 监听到设置页的返回按钮,pop 导航栈
|
||
if !state.navigationPath.isEmpty {
|
||
state.navigationPath.removeLast()
|
||
}
|
||
return .none
|
||
case .appSettingAction(.updateUser(.success)):
|
||
// 设置页用户信息变更成功,刷新Me页数据
|
||
return .send(.me(.refresh))
|
||
case .appSettingAction:
|
||
return .none
|
||
case .logout:
|
||
// 由上层(SplashView/SplashFeature)监听,切换到登录页
|
||
return .none
|
||
}
|
||
}
|
||
// 设置页作用域
|
||
.ifLet(\ .appSettingState, action: \ .appSettingAction) {
|
||
AppSettingFeature()
|
||
}
|
||
}
|
||
}
|