app

Local-first trade for farms and co-ops
git clone https://radroots.dev/git/app.git
Log | Files | Refs | README | LICENSE

commit 1796610a3fee2bae4d41e7f967d18a9233f06108
parent b38ccc3e956fe6303d661e44fb89211214fcf1cc
Author: triesap <tyson@radroots.org>
Date:   Sat,  1 Aug 2026 18:29:54 +0000

accounts: add the observable account store

- own one validated mutable state inside each store instance
- expose account state through a read-only Compose handle
- dispatch actions synchronously through the reducer
- prove state changes through the public store boundary

Diffstat:
Aapp/desktop/src/main/kotlin/org/radroots/studio/accounts/state/AccountsStore.kt | 21+++++++++++++++++++++
Aapp/desktop/src/test/kotlin/org/radroots/studio/accounts/state/AccountsStoreTest.kt | 26++++++++++++++++++++++++++
2 files changed, 47 insertions(+), 0 deletions(-)

diff --git a/app/desktop/src/main/kotlin/org/radroots/studio/accounts/state/AccountsStore.kt b/app/desktop/src/main/kotlin/org/radroots/studio/accounts/state/AccountsStore.kt @@ -0,0 +1,21 @@ +package org.radroots.studio.accounts.state + +import androidx.compose.runtime.State +import androidx.compose.runtime.mutableStateOf +import org.radroots.studio.accounts.model.AccountsAction +import org.radroots.studio.accounts.model.AccountsState +import org.radroots.studio.accounts.model.requireValid + +class AccountsStore( + initialState: AccountsState, + private val reducer: AccountsReducer, +) { + private val mutableState = mutableStateOf(initialState.requireValid()) + + val state: State<AccountsState> + get() = mutableState + + fun dispatch(action: AccountsAction) { + mutableState.value = reducer.reduce(mutableState.value, action) + } +} diff --git a/app/desktop/src/test/kotlin/org/radroots/studio/accounts/state/AccountsStoreTest.kt b/app/desktop/src/test/kotlin/org/radroots/studio/accounts/state/AccountsStoreTest.kt @@ -0,0 +1,26 @@ +package org.radroots.studio.accounts.state + +import kotlin.test.Test +import kotlin.test.assertEquals +import org.radroots.studio.accounts.model.AccountId +import org.radroots.studio.accounts.model.AccountsAction +import org.radroots.studio.accounts.model.AccountsState + +class AccountsStoreTest { + @Test + fun storeExposesInitialStateAndDispatchesThroughReducer() { + val store = AccountsStore( + initialState = AccountsState(), + reducer = AccountsReducer { AccountId("account-1") }, + ) + + assertEquals(AccountsState(), store.state.value) + + store.dispatch(AccountsAction.EditAddDisplayName("Farm Account")) + store.dispatch(AccountsAction.EditAddServerUrl("https://farm.example.test")) + store.dispatch(AccountsAction.SubmitAddAccount) + + assertEquals(AccountId("account-1"), store.state.value.selectedAccountId) + assertEquals("Farm Account", store.state.value.accounts.single().displayName) + } +}