mirror of
https://github.com/thunderbird/thunderbird-android.git
synced 2024-09-19 19:52:14 +02:00
Add OnAccountClick event to trigger account selection and add OnAccountViewClick on the account view for testing
This commit is contained in:
parent
8d34ada101
commit
8afe58c644
@ -12,10 +12,11 @@ internal fun DrawerContentPreview() {
|
||||
PreviewWithTheme {
|
||||
DrawerContent(
|
||||
state = DrawerContract.State(
|
||||
currentAccount = null,
|
||||
accounts = persistentListOf(),
|
||||
currentAccount = null,
|
||||
folders = persistentListOf(),
|
||||
),
|
||||
onEvent = {},
|
||||
)
|
||||
}
|
||||
}
|
||||
@ -29,6 +30,7 @@ fun DrawerContentWithAccountPreview() {
|
||||
accounts = persistentListOf(DISPLAY_ACCOUNT),
|
||||
currentAccount = DISPLAY_ACCOUNT,
|
||||
),
|
||||
onEvent = {},
|
||||
)
|
||||
}
|
||||
}
|
||||
|
@ -15,6 +15,7 @@ internal fun AccountViewPreview() {
|
||||
displayName = DISPLAY_NAME,
|
||||
emailAddress = EMAIL_ADDRESS,
|
||||
accountColor = 0,
|
||||
onClick = {},
|
||||
)
|
||||
}
|
||||
}
|
||||
@ -27,6 +28,7 @@ internal fun AccountViewWithColorPreview() {
|
||||
displayName = DISPLAY_NAME,
|
||||
emailAddress = EMAIL_ADDRESS,
|
||||
accountColor = 0xFF0000,
|
||||
onClick = {},
|
||||
)
|
||||
}
|
||||
}
|
||||
@ -39,6 +41,7 @@ internal fun AccountViewWithLongDisplayName() {
|
||||
displayName = "$LONG_TEXT $DISPLAY_NAME",
|
||||
emailAddress = EMAIL_ADDRESS,
|
||||
accountColor = 0,
|
||||
onClick = {},
|
||||
)
|
||||
}
|
||||
}
|
||||
@ -51,6 +54,7 @@ internal fun AccountViewWithLongEmailPreview() {
|
||||
displayName = DISPLAY_NAME,
|
||||
emailAddress = "$LONG_TEXT@example.com",
|
||||
accountColor = 0,
|
||||
onClick = {},
|
||||
)
|
||||
}
|
||||
}
|
||||
|
@ -10,6 +10,7 @@ import androidx.compose.ui.platform.testTag
|
||||
import app.k9mail.core.ui.compose.designsystem.atom.DividerHorizontal
|
||||
import app.k9mail.core.ui.compose.designsystem.atom.Surface
|
||||
import app.k9mail.core.ui.compose.theme2.MainTheme
|
||||
import app.k9mail.feature.navigation.drawer.ui.DrawerContract.Event
|
||||
import app.k9mail.feature.navigation.drawer.ui.DrawerContract.State
|
||||
import app.k9mail.feature.navigation.drawer.ui.account.AccountView
|
||||
import app.k9mail.feature.navigation.drawer.ui.folder.FolderList
|
||||
@ -17,6 +18,7 @@ import app.k9mail.feature.navigation.drawer.ui.folder.FolderList
|
||||
@Composable
|
||||
fun DrawerContent(
|
||||
state: State,
|
||||
onEvent: (Event) -> Unit,
|
||||
modifier: Modifier = Modifier,
|
||||
) {
|
||||
Surface(
|
||||
@ -37,6 +39,7 @@ fun DrawerContent(
|
||||
displayName = it.account.displayName,
|
||||
emailAddress = it.account.email,
|
||||
accountColor = it.account.chipColor,
|
||||
onClick = { onEvent(Event.OnAccountViewClick(it)) },
|
||||
)
|
||||
|
||||
DividerHorizontal()
|
||||
|
@ -5,7 +5,6 @@ import app.k9mail.core.ui.compose.common.mvi.UnidirectionalViewModel
|
||||
import app.k9mail.feature.navigation.drawer.domain.entity.DisplayAccount
|
||||
import app.k9mail.legacy.ui.folder.DisplayFolder
|
||||
import kotlinx.collections.immutable.ImmutableList
|
||||
import kotlinx.collections.immutable.immutableListOf
|
||||
import kotlinx.collections.immutable.persistentListOf
|
||||
|
||||
interface DrawerContract {
|
||||
@ -23,6 +22,8 @@ interface DrawerContract {
|
||||
|
||||
sealed interface Event {
|
||||
data object OnRefresh : Event
|
||||
data class OnAccountClick(val account: DisplayAccount) : Event
|
||||
data class OnAccountViewClick(val account: DisplayAccount) : Event
|
||||
}
|
||||
|
||||
sealed interface Effect
|
||||
|
@ -3,9 +3,9 @@ package app.k9mail.feature.navigation.drawer.ui
|
||||
import androidx.compose.runtime.Composable
|
||||
import app.k9mail.core.ui.compose.common.mvi.observe
|
||||
import app.k9mail.core.ui.compose.designsystem.molecule.PullToRefreshBox
|
||||
import org.koin.androidx.compose.koinViewModel
|
||||
import app.k9mail.feature.navigation.drawer.ui.DrawerContract.Event
|
||||
import app.k9mail.feature.navigation.drawer.ui.DrawerContract.ViewModel
|
||||
import org.koin.androidx.compose.koinViewModel
|
||||
|
||||
@Composable
|
||||
fun DrawerView(
|
||||
@ -19,6 +19,7 @@ fun DrawerView(
|
||||
) {
|
||||
DrawerContent(
|
||||
state = state.value,
|
||||
onEvent = { dispatch(it) },
|
||||
)
|
||||
}
|
||||
}
|
||||
|
@ -10,10 +10,12 @@ import app.k9mail.feature.navigation.drawer.ui.DrawerContract.State
|
||||
import app.k9mail.feature.navigation.drawer.ui.DrawerContract.ViewModel
|
||||
import kotlinx.collections.immutable.ImmutableList
|
||||
import kotlinx.collections.immutable.toImmutableList
|
||||
import kotlinx.coroutines.ExperimentalCoroutinesApi
|
||||
import kotlinx.coroutines.delay
|
||||
import kotlinx.coroutines.flow.collectLatest
|
||||
import kotlinx.coroutines.flow.distinctUntilChanged
|
||||
import kotlinx.coroutines.flow.map
|
||||
import kotlinx.coroutines.flow.flatMapLatest
|
||||
import kotlinx.coroutines.flow.mapNotNull
|
||||
import kotlinx.coroutines.launch
|
||||
|
||||
@Suppress("MagicNumber")
|
||||
@ -58,23 +60,49 @@ class DrawerViewModel(
|
||||
}
|
||||
}
|
||||
|
||||
@OptIn(ExperimentalCoroutinesApi::class)
|
||||
private suspend fun loadFolders() {
|
||||
state.map { it.currentAccount }
|
||||
state.mapNotNull { it.currentAccount?.account?.uuid }
|
||||
.distinctUntilChanged()
|
||||
.collectLatest { currentAccount ->
|
||||
if (currentAccount != null) {
|
||||
getDisplayFoldersForAccount(currentAccount.account.uuid).collectLatest { folders ->
|
||||
.flatMapLatest { accountUuid ->
|
||||
getDisplayFoldersForAccount(accountUuid)
|
||||
}.collectLatest { folders ->
|
||||
updateState {
|
||||
it.copy(folders = folders.toImmutableList())
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override fun event(event: Event) {
|
||||
when (event) {
|
||||
Event.OnRefresh -> refresh()
|
||||
is Event.OnAccountClick -> selectAccount(event.account)
|
||||
is Event.OnAccountViewClick -> {
|
||||
selectAccount(
|
||||
state.value.accounts.nextOrFirst(event.account)!!,
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun selectAccount(account: DisplayAccount) {
|
||||
viewModelScope.launch {
|
||||
updateState {
|
||||
it.copy(
|
||||
currentAccount = account,
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun ImmutableList<DisplayAccount>.nextOrFirst(account: DisplayAccount): DisplayAccount? {
|
||||
val index = indexOf(account)
|
||||
return if (index == -1) {
|
||||
null
|
||||
} else if (index == size - 1) {
|
||||
get(0)
|
||||
} else {
|
||||
get(index + 1)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1,5 +1,6 @@
|
||||
package app.k9mail.feature.navigation.drawer.ui.account
|
||||
|
||||
import androidx.compose.foundation.clickable
|
||||
import androidx.compose.foundation.layout.Arrangement
|
||||
import androidx.compose.foundation.layout.Column
|
||||
import androidx.compose.foundation.layout.IntrinsicSize
|
||||
@ -21,11 +22,13 @@ fun AccountView(
|
||||
emailAddress: String,
|
||||
accountColor: Int,
|
||||
modifier: Modifier = Modifier,
|
||||
onClick: () -> Unit,
|
||||
) {
|
||||
Row(
|
||||
modifier = modifier
|
||||
.fillMaxWidth()
|
||||
.height(intrinsicSize = IntrinsicSize.Max)
|
||||
.clickable(onClick = onClick)
|
||||
.padding(
|
||||
top = MainTheme.spacings.default,
|
||||
start = MainTheme.spacings.double,
|
||||
|
@ -1,5 +1,7 @@
|
||||
package app.k9mail.feature.navigation.drawer.ui
|
||||
|
||||
import app.k9mail.core.mail.folder.api.Folder
|
||||
import app.k9mail.core.mail.folder.api.FolderType
|
||||
import app.k9mail.core.ui.compose.testing.MainDispatcherRule
|
||||
import app.k9mail.core.ui.compose.testing.mvi.eventStateTest
|
||||
import app.k9mail.feature.navigation.drawer.domain.entity.DisplayAccount
|
||||
@ -47,7 +49,7 @@ class DrawerViewModelTest {
|
||||
val displayAccounts = createDisplayAccountList(3)
|
||||
val getDisplayAccountsFlow = MutableStateFlow(displayAccounts)
|
||||
val testSubject = createTestSubject(
|
||||
getDisplayAccountsFlow = getDisplayAccountsFlow,
|
||||
displayAccountsFlow = getDisplayAccountsFlow,
|
||||
)
|
||||
|
||||
advanceUntilIdle()
|
||||
@ -62,7 +64,7 @@ class DrawerViewModelTest {
|
||||
val displayAccounts = createDisplayAccountList(3)
|
||||
val getDisplayAccountsFlow = MutableStateFlow(displayAccounts)
|
||||
val testSubject = createTestSubject(
|
||||
getDisplayAccountsFlow = getDisplayAccountsFlow,
|
||||
displayAccountsFlow = getDisplayAccountsFlow,
|
||||
)
|
||||
|
||||
advanceUntilIdle()
|
||||
@ -81,7 +83,7 @@ class DrawerViewModelTest {
|
||||
fun `should set current account to null when no accounts are present`() = runTest {
|
||||
val getDisplayAccountsFlow = MutableStateFlow(emptyList<DisplayAccount>())
|
||||
val testSubject = createTestSubject(
|
||||
getDisplayAccountsFlow = getDisplayAccountsFlow,
|
||||
displayAccountsFlow = getDisplayAccountsFlow,
|
||||
)
|
||||
|
||||
advanceUntilIdle()
|
||||
@ -90,13 +92,76 @@ class DrawerViewModelTest {
|
||||
assertThat(testSubject.state.value.currentAccount).isEqualTo(null)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `should set current account when OnAccountClick event is received`() = runTest {
|
||||
val displayAccounts = createDisplayAccountList(3)
|
||||
val getDisplayAccountsFlow = MutableStateFlow(displayAccounts)
|
||||
val testSubject = createTestSubject(
|
||||
displayAccountsFlow = getDisplayAccountsFlow,
|
||||
)
|
||||
|
||||
advanceUntilIdle()
|
||||
|
||||
testSubject.event(Event.OnAccountClick(displayAccounts[1]))
|
||||
|
||||
advanceUntilIdle()
|
||||
|
||||
assertThat(testSubject.state.value.currentAccount).isEqualTo(displayAccounts[1])
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `should collect display folders for current account`() = runTest {
|
||||
val displayAccounts = createDisplayAccountList(3)
|
||||
val getDisplayAccountsFlow = MutableStateFlow(displayAccounts)
|
||||
val displayFoldersMap = mapOf(
|
||||
displayAccounts[0].account.uuid to createDisplayFolderList(3),
|
||||
)
|
||||
val testSubject = createTestSubject(
|
||||
displayAccountsFlow = getDisplayAccountsFlow,
|
||||
displayFoldersMap = displayFoldersMap,
|
||||
)
|
||||
|
||||
advanceUntilIdle()
|
||||
|
||||
val displayFolders = displayFoldersMap[displayAccounts[0].account.uuid] ?: emptyList()
|
||||
assertThat(testSubject.state.value.folders.size).isEqualTo(displayFolders.size)
|
||||
assertThat(testSubject.state.value.folders).isEqualTo(displayFolders)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `should collect display folders when current account is changed`() = runTest {
|
||||
val displayAccounts = createDisplayAccountList(3)
|
||||
val getDisplayAccountsFlow = MutableStateFlow(displayAccounts)
|
||||
val displayFoldersMap = mapOf(
|
||||
displayAccounts[0].account.uuid to createDisplayFolderList(1),
|
||||
displayAccounts[1].account.uuid to createDisplayFolderList(5),
|
||||
displayAccounts[2].account.uuid to createDisplayFolderList(10),
|
||||
)
|
||||
val testSubject = createTestSubject(
|
||||
displayAccountsFlow = getDisplayAccountsFlow,
|
||||
displayFoldersMap = displayFoldersMap,
|
||||
)
|
||||
|
||||
advanceUntilIdle()
|
||||
|
||||
testSubject.event(Event.OnAccountClick(displayAccounts[1]))
|
||||
|
||||
advanceUntilIdle()
|
||||
|
||||
val displayFolders = displayFoldersMap[displayAccounts[1].account.uuid] ?: emptyList()
|
||||
assertThat(testSubject.state.value.folders.size).isEqualTo(displayFolders.size)
|
||||
assertThat(testSubject.state.value.folders).isEqualTo(displayFolders)
|
||||
}
|
||||
|
||||
private fun createTestSubject(
|
||||
getDisplayAccountsFlow: Flow<List<DisplayAccount>> = flow { emit(emptyList()) },
|
||||
getDisplayFoldersForAccount: Flow<List<DisplayFolder>> = flow { emit(emptyList()) },
|
||||
displayAccountsFlow: Flow<List<DisplayAccount>> = flow { emit(emptyList()) },
|
||||
displayFoldersMap: Map<String, List<DisplayFolder>> = emptyMap(),
|
||||
): DrawerViewModel {
|
||||
return DrawerViewModel(
|
||||
getDisplayAccounts = { getDisplayAccountsFlow },
|
||||
getDisplayFoldersForAccount = { getDisplayFoldersForAccount },
|
||||
getDisplayAccounts = { displayAccountsFlow },
|
||||
getDisplayFoldersForAccount = { accountUuid ->
|
||||
flow { emit(displayFoldersMap[accountUuid] ?: emptyList()) }
|
||||
},
|
||||
)
|
||||
}
|
||||
|
||||
@ -137,4 +202,34 @@ class DrawerViewModelTest {
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
private fun createDisplayFolder(
|
||||
id: Long = 1234,
|
||||
name: String = "name",
|
||||
type: FolderType = FolderType.REGULAR,
|
||||
unreadCount: Int = 0,
|
||||
starredCount: Int = 0,
|
||||
): DisplayFolder {
|
||||
val folder = Folder(
|
||||
id = id,
|
||||
name = name,
|
||||
type = type,
|
||||
isLocalOnly = false,
|
||||
)
|
||||
|
||||
return DisplayFolder(
|
||||
folder = folder,
|
||||
isInTopGroup = false,
|
||||
unreadMessageCount = unreadCount,
|
||||
starredMessageCount = starredCount,
|
||||
)
|
||||
}
|
||||
|
||||
private fun createDisplayFolderList(count: Int): List<DisplayFolder> {
|
||||
return List(count) { index ->
|
||||
createDisplayFolder(
|
||||
id = index.toLong() + 100,
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user