feat: 新增应用设置功能及相关视图

- 在MainFeature中集成AppSettingFeature,支持应用设置页面的导航与状态管理。
- 新增AppSettingView以展示用户头像和昵称编辑功能,提升用户体验。
- 更新MainView以支持应用设置页面的展示,增强导航功能。
This commit is contained in:
edwinQQQ
2025-07-23 20:15:14 +08:00
parent bb49b00a59
commit 3a74547684
4 changed files with 155 additions and 2 deletions

View File

@@ -0,0 +1,27 @@
import Foundation
import ComposableArchitecture
struct AppSettingFeature: Reducer {
struct State: Equatable {
var nickname: String = "hahahaha"
var avatarURL: String? = nil
}
enum Action: Equatable {
case onAppear
case editNicknameTapped
case logoutTapped
// action
}
func reduce(into state: inout State, action: Action) -> Effect<Action> {
switch action {
case .onAppear:
return .none
case .editNicknameTapped:
//
return .none
case .logoutTapped:
//
return .none
}
}
}

View File

@@ -15,12 +15,14 @@ struct MainFeature: Reducer {
// State
var navigationPath: [Destination] = []
var settingState: SettingFeature.State? = nil
var appSettingState: AppSettingFeature.State? = nil
}
//
enum Destination: Hashable, Equatable {
case setting
case test
case appSetting
}
@CasePathable
@@ -35,6 +37,8 @@ struct MainFeature: Reducer {
case settingButtonTapped
case settingAction(SettingFeature.Action)
case testButtonTapped
case appSettingButtonTapped
case appSettingAction(AppSettingFeature.Action)
}
var body: some ReducerOf<Self> {
@@ -66,8 +70,8 @@ struct MainFeature: Reducer {
return .none
case .me(.settingButtonTapped):
// push
state.settingState = SettingFeature.State()
state.navigationPath.append(.setting)
state.appSettingState = AppSettingFeature.State()
state.navigationPath.append(.appSetting)
return .none
case .me:
return .none
@@ -76,6 +80,9 @@ struct MainFeature: Reducer {
if !newPath.contains(.setting) {
state.settingState = nil
}
if !newPath.contains(.appSetting) {
state.appSettingState = nil
}
state.navigationPath = newPath
return .none
case .settingButtonTapped:
@@ -87,11 +94,20 @@ struct MainFeature: Reducer {
case .testButtonTapped:
state.navigationPath.append(.test)
return .none
case .appSettingButtonTapped:
state.appSettingState = AppSettingFeature.State()
state.navigationPath.append(.appSetting)
return .none
case .appSettingAction:
return .none
}
}
//
.ifLet(\ .settingState, action: /Action.settingAction) {
SettingFeature()
}
.ifLet(\ .appSettingState, action: /Action.appSettingAction) {
AppSettingFeature()
}
}
}

View File

@@ -0,0 +1,98 @@
import SwiftUI
import ComposableArchitecture
struct AppSettingView: View {
let store: StoreOf<AppSettingFeature>
var body: some View {
WithViewStore(self.store, observe: { $0 }) { viewStore in
ZStack {
Color(red: 22/255, green: 17/255, blue: 44/255).ignoresSafeArea()
VStack(spacing: 0) {
Spacer().frame(height: 24)
//
Text("Edit")
.font(.system(size: 22, weight: .semibold))
.foregroundColor(.white)
.padding(.top, 8)
//
ZStack(alignment: .bottomTrailing) {
Image("avatar_placeholder")
.resizable()
.aspectRatio(contentMode: .fill)
.frame(width: 120, height: 120)
.clipShape(Circle())
Button(action: {}) {
ZStack {
Circle().fill(Color.purple).frame(width: 36, height: 36)
Image(systemName: "camera.fill")
.foregroundColor(.white)
}
}
.offset(x: 8, y: 8)
}
.padding(.top, 24)
//
HStack {
Text("Nickname")
.foregroundColor(.white)
Spacer()
Text(viewStore.nickname)
.foregroundColor(.gray)
Image(systemName: "chevron.right")
.foregroundColor(.gray)
}
.padding(.horizontal, 32)
.padding(.vertical, 18)
.onTapGesture {
viewStore.send(.editNicknameTapped)
}
Divider().background(Color.gray.opacity(0.3))
.padding(.horizontal, 32)
//
VStack(spacing: 0) {
settingRow("Personal Information and Permissions")
settingRow("Help")
settingRow("Clear Cache")
settingRow("Check for Updates")
settingRow("Log Out")
settingRow("About Us")
}
.background(Color.clear)
.padding(.horizontal, 0)
Spacer()
//
Button(action: {
viewStore.send(.logoutTapped)
}) {
Text("Log out of account")
.font(.system(size: 18, weight: .semibold))
.foregroundColor(.white)
.frame(maxWidth: .infinity)
.padding(.vertical, 18)
.background(Color.white.opacity(0.08))
.cornerRadius(28)
.padding(.horizontal, 32)
}
.padding(.bottom, 32)
}
}
}
}
//
func settingRow(_ title: String) -> some View {
return VStack(spacing: 0) {
HStack {
Text(title)
.foregroundColor(.white)
Spacer()
Image(systemName: "chevron.right")
.foregroundColor(.gray)
}
.padding(.horizontal, 32)
.padding(.vertical, 18)
Divider().background(Color.gray.opacity(0.3))
.padding(.horizontal, 32)
}
}
}

View File

@@ -78,6 +78,18 @@ struct MainView: View {
)
case .test:
TestPushView()
case .appSetting:
IfLetStore(
self.store.scope(
state: \.appSettingState,
action: MainFeature.Action.appSettingAction
),
then: { appSettingStore in
WithPerceptionTracking {
AppSettingView(store: appSettingStore)
}
}
)
}
}
}