Skip to content

Commit

Permalink
improve
Browse files Browse the repository at this point in the history
  • Loading branch information
pauljohanneskraft committed Nov 30, 2024
1 parent b535893 commit de0fb1a
Show file tree
Hide file tree
Showing 19 changed files with 430 additions and 30 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -14,12 +14,15 @@ class AccountOverviewTest : AccountTest() {

@Composable
override fun Content() {
val account = LocalAccount.current
AccountOverview {
val account = LocalAccount.current
Text("Spezi Account")

item {
Text("Spezi Account")
}
account?.details?.invitationCode?.let {
Text("Invitation Code: $it")
item {
Text("Invitation Code: $it")
}
}
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -82,10 +82,14 @@ private fun Header(
@Composable
private fun OverviewSheet(account: Account) {
AccountOverview(closeBehavior = AccountOverviewCloseBehavior.SHOW_CLOSE_BUTTON) {
Text("License Information")
item {
Text("License Information")
}

account.details?.invitationCode?.let {
Text("Invitation Code: $it")
item {
Text("Invitation Code: $it")
}
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ fun TestConfigurationComposable(
configuration: TestConfiguration,
content: @Composable () -> Unit,
) {
TestModule.configuration = configuration
val isLoaded = remember { mutableStateOf(false) }
val viewState = remember { mutableStateOf<ViewState>(ViewState.Idle) }
val viewModel = hiltViewModel<TestConfigurationViewModel>()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,13 +7,27 @@ import dagger.hilt.components.SingletonComponent
import edu.stanford.spezi.module.account.account.AccountConfiguration
import edu.stanford.spezi.module.account.account.mock.InMemoryAccountService
import edu.stanford.spezi.module.account.account.mock.InMemoryAccountServiceConfiguration
import edu.stanford.spezi.module.account.account.mock.InMemoryAccountStorageProvider
import edu.stanford.spezi.module.account.account.value.AccountKeys
import edu.stanford.spezi.module.account.account.value.configuration.AccountValueConfiguration
import edu.stanford.spezi.module.account.account.value.configuration.ConfiguredAccountKey
import edu.stanford.spezi.module.account.account.value.keys.dateOfBirth
import edu.stanford.spezi.module.account.account.value.keys.genderIdentity
import edu.stanford.spezi.module.account.account.value.keys.name
import edu.stanford.spezi.module.account.account.value.keys.userId
import edu.stanford.spezi.module.account.utils.TestStandard
import edu.stanford.spezi.module.account.utils.biography
import edu.stanford.spezi.module.account.utils.invitationCode
import javax.inject.Singleton

@Module
@InstallIn(SingletonComponent::class)
class TestModule {

companion object {
var configuration = TestConfiguration()
}

@Provides
fun provideStandard() = TestStandard()

Expand All @@ -24,6 +38,44 @@ class TestModule {

@Provides
@Singleton
fun provideAccountConfiguration(service: InMemoryAccountService) =
AccountConfiguration(service = service)
fun provideAccountConfiguration(
service: InMemoryAccountService,
storageProvider: InMemoryAccountStorageProvider,
) =
AccountConfiguration(
service = service,
configuration = when (configuration.valueConfiguration) {
AccountValueConfigurationType.DEFAULT -> AccountValueConfiguration(
configuration = listOf(
ConfiguredAccountKey.requires(AccountKeys::userId),
ConfiguredAccountKey.collects(AccountKeys::name),
ConfiguredAccountKey.collects(AccountKeys::genderIdentity),
ConfiguredAccountKey.collects(AccountKeys::dateOfBirth),
ConfiguredAccountKey.supports(AccountKeys::biography),
ConfiguredAccountKey.manual(AccountKeys::invitationCode),
)
)

AccountValueConfigurationType.ALL_REQUIRED_WITH_BIO -> AccountValueConfiguration(
configuration = listOf(
ConfiguredAccountKey.requires(AccountKeys::userId),
ConfiguredAccountKey.requires(AccountKeys::name),
ConfiguredAccountKey.requires(AccountKeys::genderIdentity),
ConfiguredAccountKey.requires(AccountKeys::dateOfBirth),
ConfiguredAccountKey.requires(AccountKeys::biography),
)
)

AccountValueConfigurationType.ALL_REQUIRED -> AccountValueConfiguration(
configuration = listOf(
ConfiguredAccountKey.requires(AccountKeys::userId),
ConfiguredAccountKey.requires(AccountKeys::name),
ConfiguredAccountKey.requires(AccountKeys::genderIdentity),
ConfiguredAccountKey.collects(AccountKeys::dateOfBirth),
ConfiguredAccountKey.supports(AccountKeys::biography),
)
)
},
storageProvider = storageProvider,
)
}
Original file line number Diff line number Diff line change
Expand Up @@ -6,13 +6,17 @@ import edu.stanford.spezi.core.design.component.ListRow
import edu.stanford.spezi.core.design.component.StringResource
import edu.stanford.spezi.core.design.views.validation.views.VerifiableTextField
import edu.stanford.spezi.module.account.account.value.AccountKey
import edu.stanford.spezi.module.account.account.value.AccountKeyCategory
import edu.stanford.spezi.module.account.account.value.AccountKeys
import edu.stanford.spezi.module.account.account.value.InitialValue
import edu.stanford.spezi.module.account.account.value.collections.AccountDetails
import kotlinx.serialization.builtins.serializer

private object BiographyKey : AccountKey<String> {
override val identifier = "biography"
override val name = StringResource("Bio")
override val category: AccountKeyCategory
get() = AccountKeyCategory.personalDetails
override val initialValue: InitialValue<String>
get() = InitialValue.Empty("")
override val serializer get() = String.serializer()
Expand All @@ -35,6 +39,9 @@ private object BiographyKey : AccountKey<String> {
}
}

val AccountKeys.biography: AccountKey<String>
get() = BiographyKey

var AccountDetails.biography: String?
get() = this[BiographyKey]
set(value) { this[BiographyKey] = value }
get() = this[AccountKeys.biography]
set(value) { this[AccountKeys.biography] = value }
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ package edu.stanford.spezi.module.account.utils
import androidx.compose.runtime.Composable
import edu.stanford.spezi.core.design.component.StringResource
import edu.stanford.spezi.module.account.account.value.AccountKey
import edu.stanford.spezi.module.account.account.value.AccountKeys
import edu.stanford.spezi.module.account.account.value.InitialValue
import edu.stanford.spezi.module.account.account.value.collections.AccountDetails
import edu.stanford.spezi.module.account.account.views.display.StringDisplay
Expand All @@ -27,6 +28,9 @@ private object InvitationCodeKey : AccountKey<String> {
}
}

val AccountKeys.invitationCode: AccountKey<String>
get() = InvitationCodeKey

var AccountDetails.invitationCode: String?
get() = this[InvitationCodeKey]
set(value) { this[InvitationCodeKey] = value }
get() = this[AccountKeys.invitationCode]
set(value) { this[AccountKeys.invitationCode] = value }
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package edu.stanford.spezi.module.account.account

import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.lazy.LazyListScope
import androidx.compose.runtime.Composable
import androidx.compose.runtime.remember
import edu.stanford.spezi.core.design.theme.SpeziTheme
Expand All @@ -21,7 +22,7 @@ enum class AccountDeletionBehavior {
fun AccountOverview(
closeBehavior: AccountOverviewCloseBehavior = remember { AccountOverviewCloseBehavior.DISABLED },
deletionBehavior: AccountDeletionBehavior = remember { AccountDeletionBehavior.EDIT_MODE },
additionalSections: @Composable () -> Unit,
additionalSections: LazyListScope.() -> Unit,
) {
// val viewModel = hiltViewModel<AccountOverviewFormViewModel>()
val account = LocalAccount.current
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@ package edu.stanford.spezi.module.account.account.mock

import edu.stanford.spezi.core.coroutines.di.Dispatching
import edu.stanford.spezi.module.account.account.AccountStorageProvider
import edu.stanford.spezi.module.account.account.ExternalAccountStorage
import edu.stanford.spezi.module.account.account.value.AccountKey
import edu.stanford.spezi.module.account.account.value.collections.AccountDetails
import edu.stanford.spezi.module.account.account.value.collections.AccountModifications
Expand All @@ -18,7 +17,7 @@ class InMemoryAccountStorageProvider @Inject constructor(
private val records = mutableMapOf<String, AccountDetails>()
private val cache = mutableMapOf<String, AccountDetails>() // simulates an in-memory cache

@Inject internal lateinit var storage: ExternalAccountStorage
// @Inject internal lateinit var storage: ExternalAccountStorage

override suspend fun load(accountId: String, keys: List<AccountKey<*>>): AccountDetails? {
cache[accountId]?.let { cached ->
Expand All @@ -31,7 +30,7 @@ class InMemoryAccountStorageProvider @Inject constructor(
delay(1.seconds)
records[accountId]?.let { details ->
cache[accountId] = details
storage.notifyAboutUpdatedDetails(accountId, details)
// storage.notifyAboutUpdatedDetails(accountId, details)
}
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,16 @@ import edu.stanford.spezi.module.account.account.views.entry.GeneralizedEntry
import edu.stanford.spezi.module.account.account.views.overview.AccountOverviewFormViewModel
import edu.stanford.spezi.module.account.account.views.overview.SingleEntry

@Composable
internal fun <Value : Any> AccountKey<Value>.DisplayWithStoredValue(
details: AccountDetails,
placeholderContent: @Composable () -> Unit = {},
) {
details[this]
?.let { Display(it) }
?: placeholderContent()
}

@Composable
internal fun <Value : Any> AccountKey<Value>.EntryWithEmptyValue() {
GeneralizedEntry(this, initialValue = initialValue.value)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ data class AccountValueConfiguration internal constructor(

internal fun allCategorized(filters: EnumSet<AccountKeyRequirement>? = null): Map<AccountKeyCategory, List<AccountKey<*>>> {
return configuration.values
.filter { filters?.contains(it.requirement) ?: true }
.filter { filters?.contains(it.requirement) != false }
.groupBy { it.key.category }
.mapValues { entry -> entry.value.map { it.key } }
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ import kotlinx.serialization.builtins.serializer
private object AccountEmailKey : OptionalComputedAccountKey<String> {
override val identifier = "email"
override val name = StringResource("USER_ID_EMAIL")
override val category = AccountKeyCategory.personalDetails
override val category = AccountKeyCategory.contactDetails
override val storagePolicy: ComputedKnowledgeSourceStoragePolicy
get() = ComputedKnowledgeSourceStoragePolicy.AlwaysCompute
override val initialValue: InitialValue<String> = InitialValue.Empty("")
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ import java.util.EnumSet
private object AccountNameKey : AccountKey<PersonNameComponents> {
override val identifier = "name"
override val name = StringResource("NAME")
override val category = AccountKeyCategory.credentials
override val category = AccountKeyCategory.name
override val initialValue: InitialValue<PersonNameComponents> = InitialValue.Empty(
PersonNameComponents())
override val serializer = kotlinx.serialization.serializer<PersonNameComponents>()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ import kotlinx.serialization.builtins.serializer
private object AccountUserIdKey : ComputedAccountKey<String> {
override val identifier: String = "userId"
override val name = StringResource("USER_ID")
override val category = AccountKeyCategory.personalDetails
override val category = AccountKeyCategory.credentials
override val storagePolicy: ComputedKnowledgeSourceStoragePolicy
get() = ComputedKnowledgeSourceStoragePolicy.AlwaysCompute
override val initialValue: InitialValue<String> = InitialValue.Empty("")
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
package edu.stanford.spezi.module.account.account.views.overview

import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.Row
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.runtime.CompositionLocalProvider
import androidx.compose.runtime.MutableState
import androidx.compose.runtime.remember
import androidx.compose.ui.Modifier
import edu.stanford.spezi.core.design.component.Button
import edu.stanford.spezi.module.account.account.compositionLocal.AccountViewType
import edu.stanford.spezi.module.account.account.compositionLocal.LocalAccountViewType
import edu.stanford.spezi.module.account.account.value.AccountKey
import edu.stanford.spezi.module.account.account.value.DisplayWithStoredValue
import edu.stanford.spezi.module.account.account.value.EntryWithEmptyValue
import edu.stanford.spezi.module.account.account.value.EntryWithStoredOrInitialValue
import edu.stanford.spezi.module.account.account.value.collections.AccountDetails
import edu.stanford.spezi.module.account.account.value.configuration.AccountKeyRequirement

@Composable
internal fun AccountKeyOverviewRow(
key: AccountKey<*>,
details: AccountDetails,
isEditing: MutableState<Boolean>,
viewModel: AccountOverviewFormViewModel,
modifier: Modifier = Modifier,
) {
// TODO: Make use of isDeleteDisabled!
val isDeleteDisabled = remember {
if (details.contains(key) && viewModel.containsRemovedKey(key)) {
viewModel.requirement(key) == AccountKeyRequirement.REQUIRED
} else {
viewModel.containsAddedKey(key)
}
}

Box(modifier) {
if (isEditing.value) {
Row {
if (details.contains(key) && !viewModel.containsRemovedKey(key)) {
val accountViewType = AccountViewType.Overview(
AccountViewType.OverviewEntryMode.EXISTING
)
CompositionLocalProvider(
LocalAccountViewType provides accountViewType
) {
// TODO:
// if let view = accountKey
// .dataEntryViewFromBuilder(
// builder: model.modifiedDetailsBuilder
// )
key.EntryWithStoredOrInitialValue(details)
}
} else if (viewModel.containsAddedKey(key)) {
val accountViewType = AccountViewType.Overview(
AccountViewType.OverviewEntryMode.NEW
)
CompositionLocalProvider(
LocalAccountViewType provides accountViewType
) {
key.EntryWithEmptyValue()
}
} else {
Button(onClick = {
viewModel.addAccountDetail(key)
}) {
Text("VALUE_ADD ${key.name}")
}
}
}
} else {
val accountViewType = AccountViewType.Overview(
AccountViewType.OverviewEntryMode.DISPLAY
)
CompositionLocalProvider(
LocalAccountViewType provides accountViewType
) {
key.DisplayWithStoredValue(details)
}
}
}
}
Loading

0 comments on commit de0fb1a

Please sign in to comment.