feat: 新增导航功能与设置页面支持
- 在MainFeature中新增导航路径和设置页面状态管理,支持页面导航。 - 更新MainView以集成导航功能,添加测试按钮以触发导航。 - 在MeFeature中新增设置按钮点击事件,交由MainFeature处理。 - 增强MeView以支持设置按钮,提升用户体验。
This commit is contained in:
@@ -12,6 +12,15 @@ struct MainFeature: Reducer {
|
|||||||
var feedList: FeedListFeature.State = .init()
|
var feedList: FeedListFeature.State = .init()
|
||||||
var me: MeFeature.State = .init()
|
var me: MeFeature.State = .init()
|
||||||
var accountModel: AccountModel? = nil
|
var accountModel: AccountModel? = nil
|
||||||
|
// 新增:导航路径和设置页面 State
|
||||||
|
var navigationPath: [Destination] = []
|
||||||
|
var settingState: SettingFeature.State? = nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// 新增:导航目标
|
||||||
|
enum Destination: Hashable, Equatable {
|
||||||
|
case setting
|
||||||
|
case test
|
||||||
}
|
}
|
||||||
|
|
||||||
@CasePathable
|
@CasePathable
|
||||||
@@ -21,6 +30,11 @@ struct MainFeature: Reducer {
|
|||||||
case feedList(FeedListFeature.Action)
|
case feedList(FeedListFeature.Action)
|
||||||
case me(MeFeature.Action)
|
case me(MeFeature.Action)
|
||||||
case accountModelLoaded(AccountModel?)
|
case accountModelLoaded(AccountModel?)
|
||||||
|
// 新增:导航相关
|
||||||
|
case navigationPathChanged([Destination])
|
||||||
|
case settingButtonTapped
|
||||||
|
case settingAction(SettingFeature.Action)
|
||||||
|
case testButtonTapped
|
||||||
}
|
}
|
||||||
|
|
||||||
var body: some ReducerOf<Self> {
|
var body: some ReducerOf<Self> {
|
||||||
@@ -39,6 +53,7 @@ struct MainFeature: Reducer {
|
|||||||
}
|
}
|
||||||
case .selectTab(let tab):
|
case .selectTab(let tab):
|
||||||
state.selectedTab = tab
|
state.selectedTab = tab
|
||||||
|
state.navigationPath = []
|
||||||
if tab == .other, let uidStr = state.accountModel?.uid, let uid = Int(uidStr), uid > 0 {
|
if tab == .other, let uidStr = state.accountModel?.uid, let uid = Int(uidStr), uid > 0 {
|
||||||
state.me = MeFeature.State(uid: uid)
|
state.me = MeFeature.State(uid: uid)
|
||||||
return .send(.me(.onAppear))
|
return .send(.me(.onAppear))
|
||||||
@@ -49,9 +64,34 @@ struct MainFeature: Reducer {
|
|||||||
case let .accountModelLoaded(accountModel):
|
case let .accountModelLoaded(accountModel):
|
||||||
state.accountModel = accountModel
|
state.accountModel = accountModel
|
||||||
return .none
|
return .none
|
||||||
|
case .me(.settingButtonTapped):
|
||||||
|
// 触发 push 到设置页
|
||||||
|
state.settingState = SettingFeature.State()
|
||||||
|
state.navigationPath.append(.setting)
|
||||||
|
return .none
|
||||||
case .me:
|
case .me:
|
||||||
return .none
|
return .none
|
||||||
|
case .navigationPathChanged(let newPath):
|
||||||
|
// pop 回来时清空 settingState
|
||||||
|
if !newPath.contains(.setting) {
|
||||||
|
state.settingState = nil
|
||||||
|
}
|
||||||
|
state.navigationPath = newPath
|
||||||
|
return .none
|
||||||
|
case .settingButtonTapped:
|
||||||
|
state.settingState = SettingFeature.State()
|
||||||
|
state.navigationPath.append(.setting)
|
||||||
|
return .none
|
||||||
|
case .settingAction:
|
||||||
|
return .none
|
||||||
|
case .testButtonTapped:
|
||||||
|
state.navigationPath.append(.test)
|
||||||
|
return .none
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
// 设置页作用域
|
||||||
|
.ifLet(\ .settingState, action: /Action.settingAction) {
|
||||||
|
SettingFeature()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -25,6 +25,8 @@ struct MeFeature {
|
|||||||
case loadMore
|
case loadMore
|
||||||
case userInfoResponse(Result<UserInfo, APIError>)
|
case userInfoResponse(Result<UserInfo, APIError>)
|
||||||
case momentsResponse(Result<MyMomentsResponse, APIError>)
|
case momentsResponse(Result<MyMomentsResponse, APIError>)
|
||||||
|
// 设置按钮点击
|
||||||
|
case settingButtonTapped
|
||||||
}
|
}
|
||||||
|
|
||||||
func reduce(into state: inout State, action: Action) -> Effect<Action> {
|
func reduce(into state: inout State, action: Action) -> Effect<Action> {
|
||||||
@@ -84,6 +86,9 @@ struct MeFeature {
|
|||||||
state.momentsError = error.localizedDescription
|
state.momentsError = error.localizedDescription
|
||||||
}
|
}
|
||||||
return .none
|
return .none
|
||||||
|
case .settingButtonTapped:
|
||||||
|
// 交由 MainFeature 处理
|
||||||
|
return .none
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -6,7 +6,7 @@ struct MainView: View {
|
|||||||
|
|
||||||
var body: some View {
|
var body: some View {
|
||||||
WithViewStore(self.store, observe: { $0 }) { viewStore in
|
WithViewStore(self.store, observe: { $0 }) { viewStore in
|
||||||
NavigationStack {
|
NavigationStack(path: viewStore.binding(get: \.navigationPath, send: MainFeature.Action.navigationPathChanged)) {
|
||||||
GeometryReader { geometry in
|
GeometryReader { geometry in
|
||||||
ZStack {
|
ZStack {
|
||||||
// 背景图片
|
// 背景图片
|
||||||
@@ -36,6 +36,21 @@ struct MainView: View {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
.frame(maxWidth: .infinity, maxHeight: .infinity)
|
.frame(maxWidth: .infinity, maxHeight: .infinity)
|
||||||
|
// 测试按钮
|
||||||
|
VStack {
|
||||||
|
Spacer()
|
||||||
|
HStack {
|
||||||
|
Spacer()
|
||||||
|
Button("Test Push") {
|
||||||
|
viewStore.send(.testButtonTapped)
|
||||||
|
}
|
||||||
|
.padding()
|
||||||
|
.background(Color.red)
|
||||||
|
.foregroundColor(.white)
|
||||||
|
.cornerRadius(8)
|
||||||
|
.padding()
|
||||||
|
}
|
||||||
|
}
|
||||||
// 底部导航栏
|
// 底部导航栏
|
||||||
VStack {
|
VStack {
|
||||||
Spacer()
|
Spacer()
|
||||||
@@ -47,6 +62,24 @@ struct MainView: View {
|
|||||||
.padding(.bottom, geometry.safeAreaInsets.bottom + 60)
|
.padding(.bottom, geometry.safeAreaInsets.bottom + 60)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
.navigationDestination(for: MainFeature.Destination.self) { destination in
|
||||||
|
switch destination {
|
||||||
|
case .setting:
|
||||||
|
IfLetStore(
|
||||||
|
self.store.scope(
|
||||||
|
state: \.settingState,
|
||||||
|
action: MainFeature.Action.settingAction
|
||||||
|
),
|
||||||
|
then: { settingStore in
|
||||||
|
WithPerceptionTracking {
|
||||||
|
SettingView(store: settingStore)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
)
|
||||||
|
case .test:
|
||||||
|
TestPushView()
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
.onAppear {
|
.onAppear {
|
||||||
viewStore.send(.onAppear)
|
viewStore.send(.onAppear)
|
||||||
@@ -54,3 +87,14 @@ struct MainView: View {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
struct TestPushView: View {
|
||||||
|
var body: some View {
|
||||||
|
ZStack {
|
||||||
|
Color.blue.ignoresSafeArea()
|
||||||
|
Text("Test Push View")
|
||||||
|
.font(.largeTitle)
|
||||||
|
.foregroundColor(.white)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@@ -5,17 +5,32 @@ struct MeView: View {
|
|||||||
let store: StoreOf<MeFeature>
|
let store: StoreOf<MeFeature>
|
||||||
|
|
||||||
var body: some View {
|
var body: some View {
|
||||||
WithViewStore(self.store, observe: { $0 }) { viewStore in
|
GeometryReader { geometry in
|
||||||
GeometryReader { geometry in
|
ZStack {
|
||||||
ZStack {
|
Image("bg")
|
||||||
Image("bg")
|
.resizable()
|
||||||
.resizable()
|
.aspectRatio(contentMode: .fill)
|
||||||
.aspectRatio(contentMode: .fill)
|
.frame(maxWidth: .infinity, maxHeight: .infinity)
|
||||||
.frame(maxWidth: .infinity, maxHeight: .infinity)
|
.clipped()
|
||||||
.clipped()
|
.ignoresSafeArea(.all)
|
||||||
.ignoresSafeArea(.all)
|
VStack(spacing: 0) {
|
||||||
VStack(spacing: 0) {
|
// 顶部栏,右上角设置按钮
|
||||||
// 用户信息区域
|
HStack {
|
||||||
|
Spacer()
|
||||||
|
WithViewStore(self.store, observe: { $0 }) { viewStore in
|
||||||
|
Button(action: {
|
||||||
|
viewStore.send(.settingButtonTapped)
|
||||||
|
}) {
|
||||||
|
Image(systemName: "gearshape")
|
||||||
|
.font(.system(size: 22, weight: .medium))
|
||||||
|
.foregroundColor(.white)
|
||||||
|
}
|
||||||
|
.padding(.trailing, 16)
|
||||||
|
.padding(.top, 8)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// 用户信息区域
|
||||||
|
WithViewStore(self.store, observe: { $0 }) { viewStore in
|
||||||
if viewStore.isLoadingUserInfo {
|
if viewStore.isLoadingUserInfo {
|
||||||
ProgressView()
|
ProgressView()
|
||||||
.progressViewStyle(CircularProgressViewStyle(tint: .white))
|
.progressViewStyle(CircularProgressViewStyle(tint: .white))
|
||||||
@@ -49,7 +64,9 @@ struct MeView: View {
|
|||||||
} else {
|
} else {
|
||||||
Spacer().frame(height: 130)
|
Spacer().frame(height: 130)
|
||||||
}
|
}
|
||||||
// 动态内容区域
|
}
|
||||||
|
// 动态内容区域
|
||||||
|
WithViewStore(self.store, observe: { $0 }) { viewStore in
|
||||||
if viewStore.isLoadingMoments && viewStore.moments.isEmpty {
|
if viewStore.isLoadingMoments && viewStore.moments.isEmpty {
|
||||||
ProgressView("加载中...")
|
ProgressView("加载中...")
|
||||||
.frame(maxWidth: .infinity, maxHeight: .infinity)
|
.frame(maxWidth: .infinity, maxHeight: .infinity)
|
||||||
@@ -94,14 +111,14 @@ struct MeView: View {
|
|||||||
viewStore.send(.refresh)
|
viewStore.send(.refresh)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Spacer()
|
|
||||||
}
|
}
|
||||||
.frame(maxWidth: .infinity, alignment: .top)
|
Spacer()
|
||||||
}
|
}
|
||||||
|
.frame(maxWidth: .infinity, alignment: .top)
|
||||||
}
|
}
|
||||||
.onAppear {
|
}
|
||||||
viewStore.send(.onAppear)
|
.onAppear {
|
||||||
}
|
ViewStore(self.store, observe: { $0 }).send(.onAppear)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Reference in New Issue
Block a user