Skip to content

Commit

Permalink
Merge pull request #8136 from wmontwe/add-drawer-account-top-view
Browse files Browse the repository at this point in the history
Add drawer account view
  • Loading branch information
wmontwe authored Sep 12, 2024
2 parents 89381db + 3e1c976 commit c05533a
Show file tree
Hide file tree
Showing 16 changed files with 428 additions and 28 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -113,4 +113,4 @@ private fun ColorScheme.toDynamicThemeColorScheme(
)
}

private fun Color.toHarmonizedColor(target: Color) = Color(MaterialColors.harmonize(toArgb(), target.toArgb()))
fun Color.toHarmonizedColor(target: Color) = Color(MaterialColors.harmonize(toArgb(), target.toArgb()))
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,30 @@ package app.k9mail.feature.navigation.drawer.ui
import androidx.compose.runtime.Composable
import androidx.compose.ui.tooling.preview.Preview
import app.k9mail.core.ui.compose.designsystem.PreviewWithTheme
import app.k9mail.feature.navigation.drawer.ui.account.FakeData.DISPLAY_ACCOUNT

@Composable
@Preview(showBackground = true)
internal fun DrawerContentPreview() {
PreviewWithTheme {
DrawerContent()
DrawerContent(
state = DrawerContract.State(
accounts = emptyList(),
currentAccount = null,
),
)
}
}

@Composable
@Preview(showBackground = true)
fun DrawerContentWithAccountPreview() {
PreviewWithTheme {
DrawerContent(
state = DrawerContract.State(
accounts = listOf(DISPLAY_ACCOUNT),
currentAccount = DISPLAY_ACCOUNT,
),
)
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
package app.k9mail.feature.navigation.drawer.ui.account

import androidx.compose.foundation.layout.height
import androidx.compose.runtime.Composable
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.graphics.toArgb
import androidx.compose.ui.tooling.preview.Preview
import app.k9mail.core.ui.compose.designsystem.PreviewWithThemes
import app.k9mail.core.ui.compose.theme2.MainTheme

@Composable
@Preview(showBackground = true)
internal fun AccountIndicatorPreview() {
PreviewWithThemes {
AccountIndicator(
accountColor = 0,
modifier = Modifier.height(MainTheme.spacings.double),
)
}
}

@Composable
@Preview(showBackground = true)
internal fun AccountIndicatorPreviewWithYellowAccountColor() {
PreviewWithThemes {
AccountIndicator(
accountColor = Color.Yellow.toArgb(),
modifier = Modifier.height(MainTheme.spacings.double),
)
}
}

@Composable
@Preview(showBackground = true)
internal fun AccountIndicatorPreviewWithGrayAccountColor() {
PreviewWithThemes {
AccountIndicator(
accountColor = Color.Gray.toArgb(),
modifier = Modifier.height(MainTheme.spacings.double),
)
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
package app.k9mail.feature.navigation.drawer.ui.account

import androidx.compose.runtime.Composable
import androidx.compose.ui.tooling.preview.Preview
import app.k9mail.core.ui.compose.designsystem.PreviewWithThemes
import app.k9mail.feature.navigation.drawer.ui.account.FakeData.DISPLAY_NAME
import app.k9mail.feature.navigation.drawer.ui.account.FakeData.EMAIL_ADDRESS
import app.k9mail.feature.navigation.drawer.ui.account.FakeData.LONG_TEXT

@Composable
@Preview(showBackground = true)
internal fun AccountViewPreview() {
PreviewWithThemes {
AccountView(
displayName = DISPLAY_NAME,
emailAddress = EMAIL_ADDRESS,
accountColor = 0,
)
}
}

@Composable
@Preview(showBackground = true)
internal fun AccountViewWithColorPreview() {
PreviewWithThemes {
AccountView(
displayName = DISPLAY_NAME,
emailAddress = EMAIL_ADDRESS,
accountColor = 0xFF0000,
)
}
}

@Composable
@Preview(showBackground = true)
internal fun AccountViewWithLongDisplayName() {
PreviewWithThemes {
AccountView(
displayName = "$LONG_TEXT $DISPLAY_NAME",
emailAddress = EMAIL_ADDRESS,
accountColor = 0,
)
}
}

@Composable
@Preview(showBackground = true)
internal fun AccountViewWithLongEmailPreview() {
PreviewWithThemes {
AccountView(
displayName = DISPLAY_NAME,
emailAddress = "$LONG_TEXT@example.com",
accountColor = 0,
)
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
package app.k9mail.feature.navigation.drawer.ui.account

import app.k9mail.feature.navigation.drawer.domain.entity.DisplayAccount
import app.k9mail.legacy.account.Account
import app.k9mail.legacy.account.Identity

internal object FakeData {

const val ACCOUNT_UUID = "uuid"
const val DISPLAY_NAME = "Account Name"
const val EMAIL_ADDRESS = "test@example.com"

const val LONG_TEXT = "loremipsumdolorsitametconsetetursadipscingelitr" +
"seddiamnonumyeirmodtemporinviduntutlaboreetdoloremagnaaliquyameratseddiamvoluptua"

val ACCOUNT = Account(
uuid = ACCOUNT_UUID,
).apply {
identities = ArrayList()

val identity = Identity(
signatureUse = false,
signature = "",
description = "",
)
identities.add(identity)

name = DISPLAY_NAME
email = EMAIL_ADDRESS
}

val DISPLAY_ACCOUNT = DisplayAccount(
account = ACCOUNT,
unreadMessageCount = 0,
starredMessageCount = 0,
)
}
Original file line number Diff line number Diff line change
Expand Up @@ -39,5 +39,9 @@ val navigationDrawerModule: Module = module {
)
}

viewModel { DrawerViewModel() }
viewModel {
DrawerViewModel(
getDisplayAccounts = get(),
)
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ interface DomainContract {

interface UseCase {
fun interface GetDisplayAccounts {
fun execute(): Flow<List<DisplayAccount>>
operator fun invoke(): Flow<List<DisplayAccount>>
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ class GetDisplayAccounts(
) : UseCase.GetDisplayAccounts {

@OptIn(ExperimentalCoroutinesApi::class)
override fun execute(): Flow<List<DisplayAccount>> {
override fun invoke(): Flow<List<DisplayAccount>> {
return accountManager.getAccountsFlow()
.flatMapLatest { accounts ->
val messageCountsFlows: List<Flow<MessageCounts>> = accounts.map { account ->
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,5 +9,5 @@ import app.k9mail.feature.navigation.drawer.domain.entity.DisplayAccount
class AccountsViewModel(
getDisplayAccounts: UseCase.GetDisplayAccounts,
) : ViewModel() {
val displayAccountsLiveData: LiveData<List<DisplayAccount>> = getDisplayAccounts.execute().asLiveData()
val displayAccountsLiveData: LiveData<List<DisplayAccount>> = getDisplayAccounts().asLiveData()
}
Original file line number Diff line number Diff line change
@@ -1,51 +1,72 @@
package app.k9mail.feature.navigation.drawer.ui

import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.lazy.LazyColumn
import androidx.compose.runtime.Composable
import androidx.compose.ui.Modifier
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.designsystem.organism.drawer.NavigationDrawerItem
import app.k9mail.core.ui.compose.theme2.MainTheme
import app.k9mail.feature.navigation.drawer.ui.DrawerContract.State
import app.k9mail.feature.navigation.drawer.ui.account.AccountView

@Composable
fun DrawerContent(
state: State,
modifier: Modifier = Modifier,
) {
Surface(
modifier = modifier
.fillMaxSize()
.testTag("DrawerContent"),
) {
LazyColumn(
Column(
modifier = Modifier
.fillMaxSize()
.padding(
vertical = MainTheme.spacings.oneHalf,
),
verticalArrangement = Arrangement.spacedBy(MainTheme.spacings.default),
) {
item {
NavigationDrawerItem(
label = "Folder1",
selected = true,
onClick = {},
)
}
item {
NavigationDrawerItem(
label = "Folder2",
selected = false,
onClick = {},
state.currentAccount?.let {
AccountView(
displayName = it.account.displayName,
emailAddress = it.account.email,
accountColor = it.account.chipColor,
)

DividerHorizontal()
}
item {
NavigationDrawerItem(
label = "Folder3",
selected = false,
onClick = {},
)
LazyColumn(
modifier = Modifier
.fillMaxSize(),
) {
item {
NavigationDrawerItem(
label = "Folder1",
selected = true,
onClick = {},
)
}
item {
NavigationDrawerItem(
label = "Folder2",
selected = false,
onClick = {},
)
}
item {
NavigationDrawerItem(
label = "Folder3",
selected = false,
onClick = {},
)
}
}
}
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,12 +1,15 @@
package app.k9mail.feature.navigation.drawer.ui

import app.k9mail.core.ui.compose.common.mvi.UnidirectionalViewModel
import app.k9mail.feature.navigation.drawer.domain.entity.DisplayAccount

interface DrawerContract {

interface ViewModel : UnidirectionalViewModel<State, Event, Effect>

data class State(
val currentAccount: DisplayAccount? = null,
val accounts: List<DisplayAccount> = emptyList(),
val isLoading: Boolean = false,
)

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,8 @@ fun DrawerView(
isRefreshing = state.value.isLoading,
onRefresh = { dispatch(DrawerContract.Event.OnRefresh) },
) {
DrawerContent()
DrawerContent(
state = state.value,
)
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@ package app.k9mail.feature.navigation.drawer.ui

import androidx.lifecycle.viewModelScope
import app.k9mail.core.ui.compose.common.mvi.BaseViewModel
import app.k9mail.feature.navigation.drawer.domain.DomainContract.UseCase
import app.k9mail.feature.navigation.drawer.domain.entity.DisplayAccount
import app.k9mail.feature.navigation.drawer.ui.DrawerContract.Effect
import app.k9mail.feature.navigation.drawer.ui.DrawerContract.Event
import app.k9mail.feature.navigation.drawer.ui.DrawerContract.State
Expand All @@ -11,12 +13,35 @@ import kotlinx.coroutines.launch

@Suppress("MagicNumber")
class DrawerViewModel(
private val getDisplayAccounts: UseCase.GetDisplayAccounts,
initialState: State = State(),
) : BaseViewModel<State, Event, Effect>(
initialState = initialState,
),
ViewModel {

init {
viewModelScope.launch {
getDisplayAccounts().collect { accounts -> updateAccounts(accounts) }
}
}

private fun updateAccounts(accounts: List<DisplayAccount>) {
val currentAccountUuid = state.value.currentAccount?.account?.uuid
val isCurrentAccountAvailable = accounts.any { currentAccountUuid == it.account.uuid }

updateState {
if (isCurrentAccountAvailable) {
it.copy(accounts = accounts)
} else {
it.copy(
currentAccount = accounts.firstOrNull(),
accounts = accounts,
)
}
}
}

override fun event(event: Event) {
when (event) {
Event.OnRefresh -> refresh()
Expand Down
Loading

0 comments on commit c05533a

Please sign in to comment.