Files
e-party-iOS/yana/Features/MainFeature.swift
edwinQQQ 4ff92c8c4d feat: 修复MainView Tab切换问题并优化MeView逻辑
- 新增MainView Tab切换问题分析文档,详细描述问题原因及解决方案。
- 优化BottomTabView的绑定逻辑,简化状态管理,确保Tab切换时状态正确更新。
- 在MeView中实现用户信息加载逻辑调整,确保动态列表仅在首次进入时加载,并添加错误处理视图。
- 创建EmptyStateView组件,提供统一的空状态展示和重试功能。
- 增强调试信息输出,便于后续问题排查和用户体验提升。
2025-08-05 15:51:07 +08:00

206 lines
8.6 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 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)")
// accountModelKeychain
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 // uiddisplayUID
}
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)")
// MeViewuid
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):
// CreateFeedFeedListMe
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()
}
}
}