基于hilt与MVI架构重构AccountManageScreen#838
Open
youfeng11 wants to merge 18 commits intoZalithLauncher:mainfrom
Open
基于hilt与MVI架构重构AccountManageScreen#838youfeng11 wants to merge 18 commits intoZalithLauncher:mainfrom
youfeng11 wants to merge 18 commits intoZalithLauncher:mainfrom
Conversation
Collaborator
youfeng11
commented
Mar 24, 2026
- 为项目引入hilt处理依赖注入
- 基于MVI架构重构AccountManageScreen,以减少 UI 与业务逻辑耦合,提高代码可读性和可维护性
- 添加了一个UI预览
…and Unified UI State - Added Hilt dependency injection support across the project. - Refactored `AccountManageViewModel` to use a single `AccountManageUiState` data class, following the Single Source of Truth principle. - Simplified `AccountManageScreen` by moving logic into an `AccountActions` wrapper to reduce parameter overhead. - Updated `ZLApplication` and `MainActivity` with Hilt entry point annotations. - Streamlined business logic and error handling in `AccountManageViewModel`.
…ecture. - Introduce `AccountManageIntent` to encapsulate user actions and `AccountManageEffect` for one-time UI events (toasts, errors). - Refactor `AccountManageViewModel` to use a central `onIntent` handler and a `Channel` for side effects. - Simplify `AccountActions` in the UI layer by passing a single `onIntent` callback. - Move business logic execution and error handling into private ViewModel methods, improving separation of concerns. - Replace several direct `ErrorViewModel` submissions with `LaunchedEffect` observers for a cleaner UI implementation.
…and improve error handling.
…g stability. - Wrap error submissions in `LaunchedEffect` across multiple operation handlers to prevent side effects during composition. - Immediately reset `MicrosoftChangeSkinOperation` to `None` when starting a skin upload to ensure consistent state. - Update `formatAccountError` to correctly distinguish between Ktor `ResponseException` and custom generic response exceptions. - Refactor `AccountManageViewModel` and UI components with better code formatting and more robust context handling for error messages.
…nces. - Use explicit imports for `Toast`, `AuthServer`, and `getLocalUUIDWithSkinModel` to replace fully qualified names. - Improve code readability by using shortened class and function references in `AccountManageViewModel` and `AccountManageScreen`.
…ilt-injected ApplicationContext and improving side-effect handling. - Inject `@ApplicationContext` into `AccountManageViewModel` to remove the need for passing `Context` through multiple `AccountManageIntent` data classes. - Introduce `AccountManageEffect.RefreshAvatar` to handle avatar updates via UI-side `LaunchedEffect` instead of passing callbacks through intents. - Refactor `AccountManageIntent` to simplify data structures for skin, cape, and login operations. - Improve UI state management in `AccountManageScreen` by using a `refreshAvatarMap` to trigger localized avatar updates. - Remove redundant intermediate operation states (`RunTask`) from `MicrosoftLoginOperation`, `MicrosoftChangeSkinOperation`, and `MicrosoftChangeCapeOperation`. - Clean up `AccountActions` and dialog implementations to prevent potential memory leaks and improve separation of concerns.
- Add detailed KDoc for `AccountManageUiState`, `AccountManageIntent`, `AccountManageEffect`, and `AccountManageViewModel` to document the MVI architecture and flow. - Add descriptive comments to business logic methods in `AccountManageViewModel.kt`. - Add documentation for UI components and helper classes in `AccountManageScreen.kt`. - Improve code readability by categorizing intents and effects within the ViewModel.
…state handling. - Remove unnecessary `Context` parameter from `formatAccountError` as it is already available in the ViewModel. - Use an import alias for `io.ktor.client.plugins.ResponseException` to improve code readability. - Immediately reset the Microsoft cape operation state when starting a task to ensure the UI dialog closes promptly. - Remove an redundant `Column` wrapper in `SimpleAlertDialog` within `AccountManageScreen.kt`. - Remove an unused `LocalContext` reference in `OtherAccountManagement`. - Clean up an unnecessary avatar refresh call after skin updates.
…hanism. - Replace `mutableMapOf` and a manual `refreshKey` toggle with `mutableStateMapOf` to properly handle UI updates for avatar refreshes. - Simplify state propagation by removing the unnecessary `refreshKey` parameter from `AccountManageContent` and related sub-composables. - Ensure the avatar refresh logic correctly toggles the state within the observable map to trigger recomposition.
Contributor
|
是的,没错,从依托石山变成了另依托石山 |
MovTery
reviewed
Mar 26, 2026
Comment on lines
+106
to
+118
| data class AccountManageUiState( | ||
| val accounts: List<Account> = emptyList(), | ||
| val currentAccount: Account? = null, | ||
| val authServers: List<AuthServer> = emptyList(), | ||
| val microsoftLoginOperation: MicrosoftLoginOperation = MicrosoftLoginOperation.None, | ||
| val microsoftChangeSkinOperation: MicrosoftChangeSkinOperation = MicrosoftChangeSkinOperation.None, | ||
| val microsoftChangeCapeOperation: MicrosoftChangeCapeOperation = MicrosoftChangeCapeOperation.None, | ||
| val localLoginOperation: LocalLoginOperation = LocalLoginOperation.None, | ||
| val otherLoginOperation: OtherLoginOperation = OtherLoginOperation.None, | ||
| val serverOperation: ServerOperation = ServerOperation.None, | ||
| val accountOperation: AccountOperation = AccountOperation.None, | ||
| val accountSkinOperationMap: Map<String, AccountSkinOperation> = emptyMap() | ||
| ) |
Contributor
There was a problem hiding this comment.
在我看来,这个属于是过度追求统一管理了,因为viewModel本身就是以数据管理而存在的,强行将所有数据套进data class里,再装进viewModel里,是否有点多此一举?
Collaborator
Author
There was a problem hiding this comment.
这样是为了让 ViewModel 只暴露一个统一的数据源,减少参数传递,方便管理
Comment on lines
+231
to
+281
| private val _microsoftLoginOp = | ||
| MutableStateFlow<MicrosoftLoginOperation>(MicrosoftLoginOperation.None) | ||
| private val _microsoftSkinOp = | ||
| MutableStateFlow<MicrosoftChangeSkinOperation>(MicrosoftChangeSkinOperation.None) | ||
| private val _microsoftCapeOp = | ||
| MutableStateFlow<MicrosoftChangeCapeOperation>(MicrosoftChangeCapeOperation.None) | ||
| private val _localLoginOp = MutableStateFlow<LocalLoginOperation>(LocalLoginOperation.None) | ||
| private val _otherLoginOp = MutableStateFlow<OtherLoginOperation>(OtherLoginOperation.None) | ||
| private val _serverOp = MutableStateFlow<ServerOperation>(ServerOperation.None) | ||
| private val _accountOp = MutableStateFlow<AccountOperation>(AccountOperation.None) | ||
| private val _accountSkinOpMap = MutableStateFlow<Map<String, AccountSkinOperation>>(emptyMap()) | ||
|
|
||
| private val _effect = Channel<AccountManageEffect>(Channel.BUFFERED) | ||
| val effect = _effect.receiveAsFlow() | ||
|
|
||
| /** | ||
| * 统一的 UI 状态流 | ||
| * 使用 combine 组合了来自持久层 (AccountsManager) 的数据流与 View 层内部的交互状态流 | ||
| */ | ||
| val uiState: StateFlow<AccountManageUiState> = combine( | ||
| AccountsManager.accountsFlow, | ||
| AccountsManager.currentAccountFlow, | ||
| AccountsManager.authServersFlow, | ||
| _microsoftLoginOp, | ||
| _microsoftSkinOp, | ||
| _microsoftCapeOp, | ||
| _localLoginOp, | ||
| _otherLoginOp, | ||
| _serverOp, | ||
| _accountOp, | ||
| _accountSkinOpMap | ||
| ) { args -> | ||
| @Suppress("UNCHECKED_CAST") | ||
| AccountManageUiState( | ||
| accounts = args[0] as List<Account>, | ||
| currentAccount = args[1] as Account?, | ||
| authServers = args[2] as List<AuthServer>, | ||
| microsoftLoginOperation = args[3] as MicrosoftLoginOperation, | ||
| microsoftChangeSkinOperation = args[4] as MicrosoftChangeSkinOperation, | ||
| microsoftChangeCapeOperation = args[5] as MicrosoftChangeCapeOperation, | ||
| localLoginOperation = args[6] as LocalLoginOperation, | ||
| otherLoginOperation = args[7] as OtherLoginOperation, | ||
| serverOperation = args[8] as ServerOperation, | ||
| accountOperation = args[9] as AccountOperation, | ||
| accountSkinOperationMap = args[10] as Map<String, AccountSkinOperation> | ||
| ) | ||
| }.stateIn( | ||
| scope = viewModelScope, | ||
| started = SharingStarted.WhileSubscribed(5000), | ||
| initialValue = AccountManageUiState() | ||
| ) |
Contributor
There was a problem hiding this comment.
这一大堆我没看懂,为什么不直接这么做?
private val _uiState = MutableStateFlow<AccountManageUiState>(AccountManageUiState())
val uiState = _uiState.asStateFlow()
Collaborator
Author
There was a problem hiding this comment.
这样不用手动update,可以减少状态不同步的风险
MovTery
requested changes
Mar 26, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.