
- 更新Yana项目文档,调整适用版本至iOS 17,确保与最新开发环境兼容。 - 在多个视图中重构代码,优化状态管理和视图逻辑,提升用户体验。 - 添加默认初始化器以简化状态管理,确保各个Feature的状态一致性。 - 更新视图组件,移除不必要的硬编码,增强代码可读性和维护性。 - 修复多个视图中的逻辑错误,确保功能正常运行。
135 lines
4.4 KiB
Swift
135 lines
4.4 KiB
Swift
import SwiftUI
|
|
import ComposableArchitecture
|
|
|
|
struct MainView: View {
|
|
let store: StoreOf<MainFeature>
|
|
var onLogout: (() -> Void)? = nil
|
|
|
|
var body: some View {
|
|
WithPerceptionTracking {
|
|
InternalMainView(store: store)
|
|
.onChange(of: store.isLoggedOut) {
|
|
if store.isLoggedOut {
|
|
onLogout?()
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
struct InternalMainView: View {
|
|
let store: StoreOf<MainFeature>
|
|
@State private var path: [MainFeature.Destination] = []
|
|
init(store: StoreOf<MainFeature>) {
|
|
self.store = store
|
|
_path = State(initialValue: store.withState { $0.navigationPath })
|
|
}
|
|
var body: some View {
|
|
WithPerceptionTracking {
|
|
NavigationStack(path: $path) {
|
|
GeometryReader { geometry in
|
|
contentView(geometry: geometry)
|
|
.navigationDestination(for: MainFeature.Destination.self) { destination in
|
|
DestinationView(destination: destination, store: self.store)
|
|
}
|
|
.onChange(of: path) {
|
|
store.send(.navigationPathChanged(path))
|
|
}
|
|
.onChange(of: store.navigationPath) {
|
|
if path != store.navigationPath {
|
|
path = store.navigationPath
|
|
}
|
|
}
|
|
.onAppear {
|
|
store.send(.onAppear)
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
struct DestinationView: View {
|
|
let destination: MainFeature.Destination
|
|
let store: StoreOf<MainFeature>
|
|
|
|
var body: some View {
|
|
switch destination {
|
|
case .appSetting:
|
|
IfLetStore(
|
|
store.scope(state: \.appSettingState, action: \.appSettingAction),
|
|
then: { store in
|
|
WithPerceptionTracking {
|
|
AppSettingView(store: store)
|
|
}
|
|
},
|
|
else: { Text("appSettingState is nil") }
|
|
)
|
|
case .testView:
|
|
TestView()
|
|
}
|
|
}
|
|
}
|
|
|
|
private func contentView(geometry: GeometryProxy) -> some View {
|
|
WithPerceptionTracking {
|
|
ZStack {
|
|
// 背景图片
|
|
Image("bg")
|
|
.resizable()
|
|
.aspectRatio(contentMode: .fill)
|
|
.frame(maxWidth: .infinity, maxHeight: .infinity)
|
|
.clipped()
|
|
.ignoresSafeArea(.all)
|
|
// 主内容
|
|
MainContentView(
|
|
store: store,
|
|
selectedTab: store.selectedTab
|
|
)
|
|
.frame(maxWidth: .infinity, maxHeight: .infinity)
|
|
.padding(.bottom, 80) // 为底部导航栏留出空间
|
|
|
|
// 底部导航栏 - 固定在底部
|
|
VStack {
|
|
Spacer()
|
|
BottomTabView(selectedTab: Binding(
|
|
get: { Tab(rawValue: store.selectedTab.rawValue) ?? .feed },
|
|
set: { newTab in
|
|
store.send(.selectTab(MainFeature.Tab(rawValue: newTab.rawValue) ?? .feed))
|
|
}
|
|
))
|
|
}
|
|
.frame(maxWidth: .infinity, maxHeight: .infinity, alignment: .bottom)
|
|
.padding(.bottom, 100)
|
|
.ignoresSafeArea(.keyboard, edges: .bottom)
|
|
|
|
// 添加API Loading和错误处理视图
|
|
APILoadingEffectView()
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
struct MainContentView: View {
|
|
let store: StoreOf<MainFeature>
|
|
let selectedTab: MainFeature.Tab
|
|
var body: some View {
|
|
Group {
|
|
if selectedTab == .feed {
|
|
FeedListView(store: store.scope(
|
|
state: \.feedList,
|
|
action: \.feedList
|
|
))
|
|
} else if selectedTab == .other {
|
|
MeView(
|
|
store: store.scope(
|
|
state: \.me,
|
|
action: \.me
|
|
)
|
|
)
|
|
} else {
|
|
EmptyView()
|
|
}
|
|
}
|
|
}
|
|
}
|