Skip to content

Commit

Permalink
Merge pull request thunderbird#8166 from wmontwe/change-drawer-sync-c…
Browse files Browse the repository at this point in the history
…alls

Change drawer sync calls
  • Loading branch information
wmontwe authored Sep 25, 2024
2 parents de81e25 + 2343da0 commit 056e286
Show file tree
Hide file tree
Showing 19 changed files with 309 additions and 90 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ import androidx.compose.material.icons.outlined.Menu
import androidx.compose.material.icons.outlined.Report
import androidx.compose.material.icons.outlined.Security
import androidx.compose.material.icons.outlined.Settings
import androidx.compose.material.icons.outlined.Sync
import androidx.compose.material.icons.outlined.Visibility
import androidx.compose.ui.graphics.vector.ImageVector
import app.k9mail.core.ui.compose.designsystem.atom.icon.filled.Dot
Expand Down Expand Up @@ -111,6 +112,9 @@ object Icons {
val Settings: ImageVector
get() = MaterialIcons.Outlined.Settings

val Sync: ImageVector
get() = MaterialIcons.Outlined.Sync

val Report: ImageVector
get() = MaterialIcons.Outlined.Report

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ internal fun AccountListPreview() {
selectedAccount = null,
onAccountClick = { },
onSettingsClick = { },
onSyncAllAccountsClick = { },
)
}
}
Expand All @@ -32,6 +33,7 @@ internal fun AccountListWithSelectedPreview() {
selectedAccount = DISPLAY_ACCOUNT,
onAccountClick = { },
onSettingsClick = { },
onSyncAllAccountsClick = { },
)
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -3,12 +3,14 @@ package app.k9mail.feature.navigation.drawer.ui.setting
import androidx.compose.runtime.Composable
import androidx.compose.ui.tooling.preview.Preview
import app.k9mail.core.ui.compose.designsystem.PreviewWithThemes
import app.k9mail.core.ui.compose.designsystem.atom.icon.Icons

@Composable
@Preview(showBackground = true)
internal fun SettingItemPreview() {
PreviewWithThemes {
SettingItem(
icon = Icons.Outlined.Settings,
label = "Setting",
onClick = {},
)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,8 @@ import app.k9mail.feature.navigation.drawer.domain.DomainContract.UseCase
import app.k9mail.feature.navigation.drawer.domain.usecase.GetDisplayAccounts
import app.k9mail.feature.navigation.drawer.domain.usecase.GetDisplayFoldersForAccount
import app.k9mail.feature.navigation.drawer.domain.usecase.GetDrawerConfig
import app.k9mail.feature.navigation.drawer.domain.usecase.SyncMail
import app.k9mail.feature.navigation.drawer.domain.usecase.SyncAccount
import app.k9mail.feature.navigation.drawer.domain.usecase.SyncAllAccounts
import app.k9mail.feature.navigation.drawer.legacy.AccountsViewModel
import app.k9mail.feature.navigation.drawer.legacy.FoldersViewModel
import app.k9mail.feature.navigation.drawer.ui.DrawerViewModel
Expand Down Expand Up @@ -37,8 +38,14 @@ val navigationDrawerModule: Module = module {
)
}

single<UseCase.SyncMail> {
SyncMail(
single<UseCase.SyncAccount> {
SyncAccount(
messagingController = get(),
)
}

single<UseCase.SyncAllAccounts> {
SyncAllAccounts(
messagingController = get(),
)
}
Expand Down Expand Up @@ -66,7 +73,8 @@ val navigationDrawerModule: Module = module {
getDrawerConfig = get(),
getDisplayAccounts = get(),
getDisplayFoldersForAccount = get(),
syncMail = get(),
syncAccount = get(),
syncAllAccounts = get(),
)
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -22,12 +22,17 @@ internal interface DomainContract {
}

/**
* Synchronize mail for the given account.
*
* Account can be null to synchronize unified inbox or account list.
* Synchronize the given account.
*/
fun interface SyncMail {
operator fun invoke(account: Account?): Flow<Result<Unit>>
fun interface SyncAccount {
operator fun invoke(account: Account): Flow<Result<Unit>>
}

/**
* Synchronize all accounts.
*/
fun interface SyncAllAccounts {
operator fun invoke(): Flow<Result<Unit>>
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -12,11 +12,11 @@ import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.callbackFlow
import kotlinx.coroutines.flow.flowOn

internal class SyncMail(
internal class SyncAccount(
private val messagingController: MessagingControllerMailChecker,
private val coroutineContext: CoroutineContext = Dispatchers.IO,
) : UseCase.SyncMail {
override fun invoke(account: Account?): Flow<Result<Unit>> = callbackFlow {
) : UseCase.SyncAccount {
override fun invoke(account: Account): Flow<Result<Unit>> = callbackFlow {
val listener = object : SimpleMessagingListener() {
override fun checkMailFinished(context: Context?, account: Account?) {
trySend(Result.success(Unit))
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
package app.k9mail.feature.navigation.drawer.domain.usecase

import android.content.Context
import app.k9mail.feature.navigation.drawer.domain.DomainContract.UseCase
import app.k9mail.legacy.account.Account
import app.k9mail.legacy.message.controller.MessagingControllerMailChecker
import app.k9mail.legacy.message.controller.SimpleMessagingListener
import kotlin.coroutines.CoroutineContext
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.channels.awaitClose
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.callbackFlow
import kotlinx.coroutines.flow.flowOn

class SyncAllAccounts(
private val messagingController: MessagingControllerMailChecker,
private val coroutineContext: CoroutineContext = Dispatchers.IO,
) : UseCase.SyncAllAccounts {
override fun invoke(): Flow<Result<Unit>> = callbackFlow {
val listener = object : SimpleMessagingListener() {
override fun checkMailFinished(context: Context?, account: Account?) {
trySend(Result.success(Unit))
close()
}
}

messagingController.checkMail(
account = null,
ignoreLastCheckedTime = true,
useManualWakeLock = true,
notify = true,
listener = listener,
)

awaitClose()
}.flowOn(coroutineContext)
}
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,7 @@ internal fun DrawerContent(
accounts = state.accounts,
selectedAccount = state.selectedAccount,
onAccountClick = { onEvent(Event.OnAccountClick(it)) },
onSyncAllAccountsClick = { onEvent(Event.OnSyncAllAccounts) },
onSettingsClick = { onEvent(Event.OnSettingsClick) },
)
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,8 @@ internal interface DrawerContract {
data object OnAccountSelectorClick : Event
data object OnManageFoldersClick : Event
data object OnSettingsClick : Event
data object OnRefresh : Event
data object OnSyncAccount : Event
data object OnSyncAllAccounts : Event
}

sealed interface Effect {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ internal fun DrawerView(

PullToRefreshBox(
isRefreshing = state.value.isLoading,
onRefresh = { dispatch(Event.OnRefresh) },
onRefresh = { dispatch(Event.OnSyncAccount) },
) {
DrawerContent(
state = state.value,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,8 @@ internal class DrawerViewModel(
private val getDrawerConfig: UseCase.GetDrawerConfig,
private val getDisplayAccounts: UseCase.GetDisplayAccounts,
private val getDisplayFoldersForAccount: UseCase.GetDisplayFoldersForAccount,
private val syncMail: UseCase.SyncMail,
private val syncAccount: UseCase.SyncAccount,
private val syncAllAccounts: UseCase.SyncAllAccounts,
initialState: State = State(),
) : BaseViewModel<State, Event, Effect>(
initialState = initialState,
Expand Down Expand Up @@ -101,7 +102,6 @@ internal class DrawerViewModel(

override fun event(event: Event) {
when (event) {
Event.OnRefresh -> refresh()
is Event.OnAccountClick -> selectAccount(event.account)
is Event.OnFolderClick -> selectFolder(event.folder)
is Event.OnAccountViewClick -> {
Expand All @@ -113,6 +113,8 @@ internal class DrawerViewModel(
Event.OnAccountSelectorClick -> updateState { it.copy(showAccountSelector = it.showAccountSelector.not()) }
Event.OnManageFoldersClick -> emitEffect(Effect.OpenManageFolders)
Event.OnSettingsClick -> emitEffect(Effect.OpenSettings)
Event.OnSyncAccount -> onSyncAccount()
Event.OnSyncAllAccounts -> onSyncAllAccounts()
}
}

Expand Down Expand Up @@ -156,13 +158,31 @@ internal class DrawerViewModel(
}
}

private fun refresh() {
private fun onSyncAccount() {
if (state.value.isLoading || state.value.selectedAccount == null) return

viewModelScope.launch {
updateState {
it.copy(isLoading = true)
}

state.value.selectedAccount?.account?.let { syncAccount(it).collect() }

updateState {
it.copy(isLoading = false)
}
}
}

private fun onSyncAllAccounts() {
if (state.value.isLoading) return

viewModelScope.launch {
updateState {
it.copy(isLoading = true)
}

syncMail(state.value.selectedAccount?.account).collect()
syncAllAccounts().collect()

updateState {
it.copy(isLoading = false)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,14 +2,19 @@ package app.k9mail.feature.navigation.drawer.ui.account

import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.PaddingValues
import androidx.compose.foundation.layout.Spacer
import androidx.compose.foundation.layout.fillMaxHeight
import androidx.compose.foundation.layout.height
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.width
import androidx.compose.foundation.lazy.LazyColumn
import androidx.compose.foundation.lazy.items
import androidx.compose.runtime.Composable
import androidx.compose.ui.Modifier
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.unit.dp
import app.k9mail.core.ui.compose.designsystem.atom.Surface
import app.k9mail.core.ui.compose.designsystem.atom.icon.Icons
import app.k9mail.core.ui.compose.theme2.MainTheme
import app.k9mail.feature.navigation.drawer.R
import app.k9mail.feature.navigation.drawer.domain.entity.DisplayAccount
Expand All @@ -21,6 +26,7 @@ internal fun AccountList(
accounts: ImmutableList<DisplayAccount>,
selectedAccount: DisplayAccount?,
onAccountClick: (DisplayAccount) -> Unit,
onSyncAllAccountsClick: () -> Unit,
onSettingsClick: () -> Unit,
modifier: Modifier = Modifier,
) {
Expand Down Expand Up @@ -50,10 +56,22 @@ internal fun AccountList(
)
}
}
SettingItem(
label = stringResource(id = R.string.navigation_drawer_action_settings),
onClick = onSettingsClick,
)
Column(
modifier = Modifier.padding(vertical = MainTheme.spacings.oneHalf),
) {
SettingItem(
icon = Icons.Outlined.Sync,
label = stringResource(id = R.string.navigation_drawer_action_sync_all_accounts),
onClick = onSyncAllAccountsClick,
)
// Hack to compensate the column placement at an uneven coordinate, caused by the 1.dp divider.
Spacer(modifier = Modifier.height(7.dp))
SettingItem(
icon = Icons.Outlined.Settings,
label = stringResource(id = R.string.navigation_drawer_action_settings),
onClick = onSettingsClick,
)
}
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -8,13 +8,14 @@ import androidx.compose.foundation.shape.CircleShape
import androidx.compose.runtime.Composable
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.vector.ImageVector
import app.k9mail.core.ui.compose.designsystem.atom.Surface
import app.k9mail.core.ui.compose.designsystem.atom.icon.Icon
import app.k9mail.core.ui.compose.designsystem.atom.icon.Icons
import app.k9mail.core.ui.compose.theme2.MainTheme

@Composable
internal fun SettingItem(
icon: ImageVector,
label: String,
onClick: () -> Unit,
modifier: Modifier = Modifier,
Expand All @@ -24,12 +25,11 @@ internal fun SettingItem(
contentAlignment = Alignment.Center,
) {
Surface(
modifier = Modifier.padding(vertical = MainTheme.spacings.oneHalf),
color = MainTheme.colors.surfaceContainer,
shape = CircleShape,
) {
Icon(
imageVector = Icons.Outlined.Settings,
imageVector = icon,
contentDescription = label,
modifier = Modifier
.clickable(onClick = onClick)
Expand Down
1 change: 1 addition & 0 deletions feature/navigation/drawer/src/main/res/values/strings.xml
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="navigation_drawer_action_settings">Settings</string>
<string name="navigation_drawer_action_manage_folders">Manage folders</string>
<string name="navigation_drawer_action_sync_all_accounts">Sync all accounts</string>
<string name="navigation_drawer_action_show_accounts">Show accounts</string>
<string name="navigation_drawer_action_hide_accounts">Hide accounts</string>
<string name="navigation_drawer_unified_inbox_title">Unified Inbox</string>
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
package app.k9mail.feature.navigation.drawer.domain.usecase

import app.k9mail.legacy.account.Account
import app.k9mail.legacy.message.controller.MessagingControllerMailChecker
import app.k9mail.legacy.message.controller.MessagingListener

internal class FakeMessagingControllerMailChecker(
private val listenerExecutor: (MessagingListener?) -> Unit = {},
) : MessagingControllerMailChecker {
override fun checkMail(
account: Account?,
ignoreLastCheckedTime: Boolean,
useManualWakeLock: Boolean,
notify: Boolean,
listener: MessagingListener?,
) {
listenerExecutor(listener)
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
package app.k9mail.feature.navigation.drawer.domain.usecase

import app.k9mail.feature.navigation.drawer.ui.FakeData
import app.k9mail.legacy.message.controller.MessagingListener
import assertk.assertions.isEqualTo
import kotlin.test.Test
import kotlinx.coroutines.flow.first
import kotlinx.coroutines.test.runTest

class SyncAccountTest {

@Test
fun `should sync mail with account`() = runTest {
val listenerExecutor: (MessagingListener?) -> Unit = { listener ->
listener?.checkMailFinished(null, null)
}
val testSubject = SyncAccount(
messagingController = FakeMessagingControllerMailChecker(
listenerExecutor = listenerExecutor,
),
)

val result = testSubject(FakeData.ACCOUNT).first()

assertk.assertThat(result.isSuccess).isEqualTo(true)
}
}
Loading

0 comments on commit 056e286

Please sign in to comment.