Repo created
This commit is contained in:
parent
75dc487a7a
commit
39c29d175b
6317 changed files with 388324 additions and 2 deletions
32
feature/navigation/drawer/siderail/build.gradle.kts
Normal file
32
feature/navigation/drawer/siderail/build.gradle.kts
Normal file
|
|
@ -0,0 +1,32 @@
|
|||
plugins {
|
||||
id(ThunderbirdPlugins.Library.androidCompose)
|
||||
}
|
||||
|
||||
android {
|
||||
namespace = "net.thunderbird.feature.navigation.drawer.siderail"
|
||||
resourcePrefix = "navigation_drawer_siderail_"
|
||||
}
|
||||
|
||||
dependencies {
|
||||
api(projects.feature.navigation.drawer.api)
|
||||
|
||||
implementation(projects.core.ui.theme.api)
|
||||
implementation(projects.core.ui.compose.designsystem)
|
||||
|
||||
implementation(projects.feature.account.avatar.impl)
|
||||
implementation(projects.feature.mail.account.api)
|
||||
implementation(projects.feature.mail.folder.api)
|
||||
|
||||
implementation(projects.core.android.account)
|
||||
implementation(projects.legacy.mailstore)
|
||||
implementation(projects.legacy.message)
|
||||
implementation(projects.feature.search.implLegacy)
|
||||
implementation(projects.legacy.ui.folder)
|
||||
implementation(projects.core.featureflag)
|
||||
|
||||
testImplementation(projects.core.ui.compose.testing)
|
||||
|
||||
// Fakes
|
||||
debugImplementation(projects.feature.account.fake)
|
||||
testImplementation(projects.feature.account.fake)
|
||||
}
|
||||
|
|
@ -0,0 +1,288 @@
|
|||
package net.thunderbird.feature.navigation.drawer.siderail.ui
|
||||
|
||||
import androidx.compose.foundation.layout.height
|
||||
import androidx.compose.foundation.layout.width
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.tooling.preview.Preview
|
||||
import androidx.compose.ui.unit.dp
|
||||
import app.k9mail.core.ui.compose.designsystem.PreviewWithTheme
|
||||
import app.k9mail.core.ui.compose.designsystem.atom.Surface
|
||||
import kotlin.collections.get
|
||||
import kotlinx.collections.immutable.persistentListOf
|
||||
import net.thunderbird.feature.navigation.drawer.api.NavigationDrawerExternalContract.DrawerConfig
|
||||
import net.thunderbird.feature.navigation.drawer.siderail.ui.FakeData.DISPLAY_ACCOUNT
|
||||
import net.thunderbird.feature.navigation.drawer.siderail.ui.FakeData.DISPLAY_FOLDER
|
||||
import net.thunderbird.feature.navigation.drawer.siderail.ui.FakeData.UNIFIED_FOLDER
|
||||
import net.thunderbird.feature.navigation.drawer.siderail.ui.FakeData.createAccountList
|
||||
import net.thunderbird.feature.navigation.drawer.siderail.ui.FakeData.createDisplayFolderList
|
||||
|
||||
@Composable
|
||||
@Preview(showBackground = true)
|
||||
internal fun DrawerContentPreview() {
|
||||
PreviewWithTheme {
|
||||
DrawerContent(
|
||||
state = DrawerContract.State(
|
||||
accounts = persistentListOf(),
|
||||
selectedAccountId = null,
|
||||
folders = persistentListOf(),
|
||||
),
|
||||
onEvent = {},
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
@Preview(showBackground = true)
|
||||
internal fun DrawerContentWithAccountPreview() {
|
||||
PreviewWithTheme {
|
||||
DrawerContent(
|
||||
state = DrawerContract.State(
|
||||
accounts = persistentListOf(DISPLAY_ACCOUNT),
|
||||
selectedAccountId = DISPLAY_ACCOUNT.id,
|
||||
folders = persistentListOf(),
|
||||
),
|
||||
onEvent = {},
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
@Preview(showBackground = true)
|
||||
internal fun DrawerContentWithFoldersPreview() {
|
||||
PreviewWithTheme {
|
||||
DrawerContent(
|
||||
state = DrawerContract.State(
|
||||
accounts = persistentListOf(
|
||||
DISPLAY_ACCOUNT,
|
||||
),
|
||||
selectedAccountId = null,
|
||||
folders = persistentListOf(
|
||||
UNIFIED_FOLDER,
|
||||
DISPLAY_FOLDER,
|
||||
),
|
||||
),
|
||||
onEvent = {},
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
@Preview(showBackground = true)
|
||||
internal fun DrawerContentWithSelectedFolderPreview() {
|
||||
PreviewWithTheme {
|
||||
DrawerContent(
|
||||
state = DrawerContract.State(
|
||||
accounts = persistentListOf(
|
||||
DISPLAY_ACCOUNT,
|
||||
),
|
||||
selectedAccountId = DISPLAY_ACCOUNT.id,
|
||||
folders = persistentListOf(
|
||||
UNIFIED_FOLDER,
|
||||
DISPLAY_FOLDER,
|
||||
),
|
||||
selectedFolderId = DISPLAY_FOLDER.id,
|
||||
),
|
||||
onEvent = {},
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
@Preview(showBackground = true)
|
||||
internal fun DrawerContentWithSelectedUnifiedFolderPreview() {
|
||||
PreviewWithTheme {
|
||||
DrawerContent(
|
||||
state = DrawerContract.State(
|
||||
accounts = persistentListOf(
|
||||
DISPLAY_ACCOUNT,
|
||||
),
|
||||
selectedAccountId = DISPLAY_ACCOUNT.id,
|
||||
folders = persistentListOf(
|
||||
UNIFIED_FOLDER,
|
||||
DISPLAY_FOLDER,
|
||||
),
|
||||
selectedFolderId = UNIFIED_FOLDER.id,
|
||||
),
|
||||
onEvent = {},
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
@Preview(showBackground = true)
|
||||
internal fun DrawerContentSingleAccountPreview() {
|
||||
val displayFolders = createDisplayFolderList(hasUnifiedFolder = false)
|
||||
|
||||
PreviewWithTheme {
|
||||
DrawerContent(
|
||||
state = DrawerContract.State(
|
||||
accounts = persistentListOf(
|
||||
DISPLAY_ACCOUNT,
|
||||
),
|
||||
selectedAccountId = DISPLAY_ACCOUNT.id,
|
||||
folders = displayFolders,
|
||||
selectedFolderId = displayFolders[0].id,
|
||||
config = DrawerConfig(
|
||||
showUnifiedFolders = false,
|
||||
showStarredCount = false,
|
||||
showAccountSelector = false,
|
||||
),
|
||||
),
|
||||
onEvent = {},
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
@Preview(showBackground = true)
|
||||
internal fun DrawerContentSingleAccountWithAccountSelectionPreview() {
|
||||
val displayFolders = createDisplayFolderList(hasUnifiedFolder = false)
|
||||
|
||||
PreviewWithTheme {
|
||||
DrawerContent(
|
||||
state = DrawerContract.State(
|
||||
accounts = persistentListOf(
|
||||
DISPLAY_ACCOUNT,
|
||||
),
|
||||
selectedAccountId = DISPLAY_ACCOUNT.id,
|
||||
folders = displayFolders,
|
||||
selectedFolderId = displayFolders[0].id,
|
||||
config = DrawerConfig(
|
||||
showUnifiedFolders = false,
|
||||
showStarredCount = false,
|
||||
showAccountSelector = true,
|
||||
),
|
||||
),
|
||||
onEvent = {},
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
@Preview(showBackground = true)
|
||||
internal fun DrawerContentMultipleAccountsAccountPreview() {
|
||||
val accountList = createAccountList()
|
||||
val displayFolders = createDisplayFolderList(hasUnifiedFolder = true)
|
||||
|
||||
PreviewWithTheme {
|
||||
DrawerContent(
|
||||
state = DrawerContract.State(
|
||||
accounts = accountList,
|
||||
selectedAccountId = accountList[0].id,
|
||||
folders = displayFolders,
|
||||
selectedFolderId = UNIFIED_FOLDER.id,
|
||||
config = DrawerConfig(
|
||||
showUnifiedFolders = false,
|
||||
showStarredCount = false,
|
||||
showAccountSelector = false,
|
||||
),
|
||||
),
|
||||
onEvent = {},
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
@Preview(showBackground = true)
|
||||
internal fun DrawerContentMultipleAccountsWithAccountSelectionPreview() {
|
||||
val accountList = createAccountList()
|
||||
|
||||
PreviewWithTheme {
|
||||
DrawerContent(
|
||||
state = DrawerContract.State(
|
||||
accounts = accountList,
|
||||
selectedAccountId = accountList[1].id,
|
||||
folders = createDisplayFolderList(hasUnifiedFolder = true),
|
||||
selectedFolderId = UNIFIED_FOLDER.id,
|
||||
config = DrawerConfig(
|
||||
showUnifiedFolders = false,
|
||||
showStarredCount = false,
|
||||
showAccountSelector = true,
|
||||
),
|
||||
),
|
||||
onEvent = {},
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
@Preview(showBackground = true)
|
||||
internal fun DrawerContentMultipleAccountsWithDifferentAccountSelectionPreview() {
|
||||
val accountList = createAccountList()
|
||||
|
||||
PreviewWithTheme {
|
||||
DrawerContent(
|
||||
state = DrawerContract.State(
|
||||
accounts = accountList,
|
||||
selectedAccountId = accountList[2].id,
|
||||
folders = createDisplayFolderList(hasUnifiedFolder = true),
|
||||
selectedFolderId = UNIFIED_FOLDER.id,
|
||||
config = DrawerConfig(
|
||||
showUnifiedFolders = false,
|
||||
showStarredCount = false,
|
||||
showAccountSelector = true,
|
||||
),
|
||||
),
|
||||
onEvent = {},
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
@Preview(showBackground = true)
|
||||
internal fun DrawerContentSmallScreenPreview() {
|
||||
val accountList = createAccountList()
|
||||
|
||||
PreviewWithTheme {
|
||||
Surface(
|
||||
modifier = Modifier
|
||||
.width(320.dp)
|
||||
.height(480.dp),
|
||||
) {
|
||||
DrawerContent(
|
||||
state = DrawerContract.State(
|
||||
accounts = accountList,
|
||||
selectedAccountId = accountList[2].id,
|
||||
folders = createDisplayFolderList(hasUnifiedFolder = true),
|
||||
selectedFolderId = UNIFIED_FOLDER.id,
|
||||
config = DrawerConfig(
|
||||
showUnifiedFolders = false,
|
||||
showStarredCount = false,
|
||||
showAccountSelector = true,
|
||||
),
|
||||
),
|
||||
onEvent = {},
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
@Preview(showBackground = true)
|
||||
internal fun DrawerContentVerySmallScreenPreview() {
|
||||
val accountList = createAccountList()
|
||||
|
||||
PreviewWithTheme {
|
||||
Surface(
|
||||
modifier = Modifier
|
||||
.width(240.dp)
|
||||
.height(320.dp),
|
||||
) {
|
||||
DrawerContent(
|
||||
state = DrawerContract.State(
|
||||
accounts = accountList,
|
||||
selectedAccountId = accountList[2].id,
|
||||
folders = createDisplayFolderList(hasUnifiedFolder = true),
|
||||
selectedFolderId = UNIFIED_FOLDER.id,
|
||||
config = DrawerConfig(
|
||||
showUnifiedFolders = false,
|
||||
showStarredCount = false,
|
||||
showAccountSelector = true,
|
||||
),
|
||||
),
|
||||
onEvent = {},
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,158 @@
|
|||
package net.thunderbird.feature.navigation.drawer.siderail.ui
|
||||
|
||||
import androidx.compose.ui.graphics.Color
|
||||
import androidx.compose.ui.graphics.toArgb
|
||||
import kotlinx.collections.immutable.PersistentList
|
||||
import kotlinx.collections.immutable.persistentListOf
|
||||
import kotlinx.collections.immutable.toPersistentList
|
||||
import net.thunderbird.account.fake.FakeAccountData.ACCOUNT_ID_RAW
|
||||
import net.thunderbird.core.android.account.Identity
|
||||
import net.thunderbird.core.android.account.LegacyAccount
|
||||
import net.thunderbird.feature.mail.folder.api.Folder
|
||||
import net.thunderbird.feature.mail.folder.api.FolderType
|
||||
import net.thunderbird.feature.navigation.drawer.siderail.domain.entity.DisplayAccount
|
||||
import net.thunderbird.feature.navigation.drawer.siderail.domain.entity.DisplayAccountFolder
|
||||
import net.thunderbird.feature.navigation.drawer.siderail.domain.entity.DisplayFolder
|
||||
import net.thunderbird.feature.navigation.drawer.siderail.domain.entity.DisplayUnifiedFolder
|
||||
import net.thunderbird.feature.navigation.drawer.siderail.domain.entity.DisplayUnifiedFolderType
|
||||
|
||||
internal object FakeData {
|
||||
|
||||
const val DISPLAY_NAME = "Account Name"
|
||||
const val EMAIL_ADDRESS = "test@example.com"
|
||||
|
||||
val ACCOUNT = LegacyAccount(
|
||||
uuid = ACCOUNT_ID_RAW,
|
||||
).apply {
|
||||
identities = ArrayList()
|
||||
|
||||
val identity = Identity(
|
||||
signatureUse = false,
|
||||
signature = "",
|
||||
description = "",
|
||||
)
|
||||
identities.add(identity)
|
||||
|
||||
name = DISPLAY_NAME
|
||||
email = EMAIL_ADDRESS
|
||||
}
|
||||
|
||||
val DISPLAY_ACCOUNT = DisplayAccount(
|
||||
id = ACCOUNT_ID_RAW,
|
||||
name = DISPLAY_NAME,
|
||||
email = EMAIL_ADDRESS,
|
||||
color = Color.Red.toArgb(),
|
||||
unreadMessageCount = 0,
|
||||
starredMessageCount = 0,
|
||||
)
|
||||
|
||||
val FOLDER = Folder(
|
||||
id = 1,
|
||||
name = "Folder Name",
|
||||
type = FolderType.REGULAR,
|
||||
isLocalOnly = false,
|
||||
)
|
||||
|
||||
val DISPLAY_FOLDER = DisplayAccountFolder(
|
||||
accountId = ACCOUNT_ID_RAW,
|
||||
folder = FOLDER,
|
||||
isInTopGroup = false,
|
||||
unreadMessageCount = 14,
|
||||
starredMessageCount = 5,
|
||||
)
|
||||
|
||||
val UNIFIED_FOLDER = DisplayUnifiedFolder(
|
||||
id = "unified_inbox",
|
||||
unifiedType = DisplayUnifiedFolderType.INBOX,
|
||||
unreadMessageCount = 123,
|
||||
starredMessageCount = 567,
|
||||
)
|
||||
|
||||
fun createAccountList(): PersistentList<DisplayAccount> {
|
||||
return persistentListOf(
|
||||
DisplayAccount(
|
||||
id = "account1",
|
||||
name = "job@example.com",
|
||||
email = "job@example.com",
|
||||
color = Color.Green.toArgb(),
|
||||
unreadMessageCount = 2,
|
||||
starredMessageCount = 0,
|
||||
),
|
||||
DisplayAccount(
|
||||
id = "account2",
|
||||
name = "Jodie Doe",
|
||||
email = "jodie@example.com",
|
||||
color = Color.Red.toArgb(),
|
||||
unreadMessageCount = 12,
|
||||
starredMessageCount = 0,
|
||||
),
|
||||
DisplayAccount(
|
||||
id = "account3",
|
||||
name = "John Doe",
|
||||
email = "john@example.com",
|
||||
color = Color.Cyan.toArgb(),
|
||||
unreadMessageCount = 0,
|
||||
starredMessageCount = 0,
|
||||
),
|
||||
)
|
||||
}
|
||||
|
||||
fun createDisplayFolderList(hasUnifiedFolder: Boolean): PersistentList<DisplayFolder> {
|
||||
val folders = mutableListOf<DisplayFolder>()
|
||||
|
||||
if (hasUnifiedFolder) {
|
||||
folders.add(UNIFIED_FOLDER)
|
||||
}
|
||||
|
||||
folders.addAll(
|
||||
listOf(
|
||||
DISPLAY_FOLDER.copy(
|
||||
folder = FOLDER.copy(id = 2, name = "Inbox", type = FolderType.INBOX),
|
||||
unreadMessageCount = 12,
|
||||
),
|
||||
DISPLAY_FOLDER.copy(
|
||||
folder = FOLDER.copy(id = 3, name = "Outbox", type = FolderType.OUTBOX),
|
||||
unreadMessageCount = 0,
|
||||
),
|
||||
DISPLAY_FOLDER.copy(
|
||||
folder = FOLDER.copy(id = 4, name = "Drafts", type = FolderType.DRAFTS),
|
||||
unreadMessageCount = 0,
|
||||
),
|
||||
DISPLAY_FOLDER.copy(
|
||||
folder = FOLDER.copy(id = 5, name = "Sent", type = FolderType.SENT),
|
||||
unreadMessageCount = 0,
|
||||
),
|
||||
DISPLAY_FOLDER.copy(
|
||||
folder = FOLDER.copy(id = 6, name = "Spam", type = FolderType.SPAM),
|
||||
unreadMessageCount = 5,
|
||||
),
|
||||
DISPLAY_FOLDER.copy(
|
||||
folder = FOLDER.copy(id = 7, name = "Trash", type = FolderType.TRASH),
|
||||
unreadMessageCount = 0,
|
||||
),
|
||||
DISPLAY_FOLDER.copy(
|
||||
folder = FOLDER.copy(id = 8, name = "Archive", type = FolderType.ARCHIVE),
|
||||
unreadMessageCount = 0,
|
||||
),
|
||||
DISPLAY_FOLDER.copy(
|
||||
folder = FOLDER.copy(id = 9, name = "Work", type = FolderType.REGULAR),
|
||||
unreadMessageCount = 3,
|
||||
),
|
||||
DISPLAY_FOLDER.copy(
|
||||
folder = FOLDER.copy(id = 10, name = "Personal", type = FolderType.REGULAR),
|
||||
unreadMessageCount = 4,
|
||||
),
|
||||
DISPLAY_FOLDER.copy(
|
||||
folder = FOLDER.copy(id = 11, name = "Important", type = FolderType.REGULAR),
|
||||
unreadMessageCount = 0,
|
||||
),
|
||||
DISPLAY_FOLDER.copy(
|
||||
folder = FOLDER.copy(id = 12, name = "Later", type = FolderType.REGULAR),
|
||||
unreadMessageCount = 0,
|
||||
),
|
||||
),
|
||||
)
|
||||
|
||||
return folders.toPersistentList()
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,60 @@
|
|||
package net.thunderbird.feature.navigation.drawer.siderail.ui.account
|
||||
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.ui.tooling.preview.Preview
|
||||
import app.k9mail.core.ui.compose.designsystem.PreviewWithThemes
|
||||
import net.thunderbird.feature.navigation.drawer.siderail.ui.FakeData.DISPLAY_ACCOUNT
|
||||
|
||||
@Composable
|
||||
@Preview(showBackground = true)
|
||||
internal fun AccountAvatarPreview() {
|
||||
PreviewWithThemes {
|
||||
AccountAvatar(
|
||||
account = DISPLAY_ACCOUNT,
|
||||
onClick = {},
|
||||
selected = false,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
@Preview(showBackground = true)
|
||||
internal fun AccountAvatarWithUnreadCountPreview() {
|
||||
PreviewWithThemes {
|
||||
AccountAvatar(
|
||||
account = DISPLAY_ACCOUNT.copy(
|
||||
unreadMessageCount = 12,
|
||||
),
|
||||
onClick = {},
|
||||
selected = false,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
@Preview(showBackground = true)
|
||||
internal fun AccountAvatarWithUnreadCountMaxedPreview() {
|
||||
PreviewWithThemes {
|
||||
AccountAvatar(
|
||||
account = DISPLAY_ACCOUNT.copy(
|
||||
unreadMessageCount = 100,
|
||||
),
|
||||
onClick = {},
|
||||
selected = false,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
@Preview(showBackground = true)
|
||||
internal fun AccountAvatarSelectedPreview() {
|
||||
PreviewWithThemes {
|
||||
AccountAvatar(
|
||||
account = DISPLAY_ACCOUNT.copy(
|
||||
color = 0xFFFF0000.toInt(),
|
||||
),
|
||||
onClick = {},
|
||||
selected = true,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,43 @@
|
|||
package net.thunderbird.feature.navigation.drawer.siderail.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),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,30 @@
|
|||
package net.thunderbird.feature.navigation.drawer.siderail.ui.account
|
||||
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.ui.tooling.preview.Preview
|
||||
import app.k9mail.core.ui.compose.designsystem.PreviewWithThemes
|
||||
import net.thunderbird.feature.navigation.drawer.siderail.ui.FakeData.DISPLAY_ACCOUNT
|
||||
|
||||
@Composable
|
||||
@Preview(showBackground = true)
|
||||
internal fun AccountListItemPreview() {
|
||||
PreviewWithThemes {
|
||||
AccountListItem(
|
||||
account = DISPLAY_ACCOUNT,
|
||||
onClick = { },
|
||||
selected = false,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
@Preview(showBackground = true)
|
||||
internal fun AccountListItemSelectedPreview() {
|
||||
PreviewWithThemes {
|
||||
AccountListItem(
|
||||
account = DISPLAY_ACCOUNT,
|
||||
onClick = { },
|
||||
selected = true,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,39 @@
|
|||
package net.thunderbird.feature.navigation.drawer.siderail.ui.account
|
||||
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.ui.tooling.preview.Preview
|
||||
import app.k9mail.core.ui.compose.designsystem.PreviewWithTheme
|
||||
import kotlinx.collections.immutable.persistentListOf
|
||||
import net.thunderbird.feature.navigation.drawer.siderail.ui.FakeData.DISPLAY_ACCOUNT
|
||||
|
||||
@Composable
|
||||
@Preview(showBackground = true)
|
||||
internal fun AccountListPreview() {
|
||||
PreviewWithTheme {
|
||||
AccountList(
|
||||
accounts = persistentListOf(
|
||||
DISPLAY_ACCOUNT,
|
||||
),
|
||||
selectedAccount = null,
|
||||
onAccountClick = { },
|
||||
onSettingsClick = { },
|
||||
onSyncAllAccountsClick = { },
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
@Preview(showBackground = true)
|
||||
internal fun AccountListWithSelectedPreview() {
|
||||
PreviewWithTheme {
|
||||
AccountList(
|
||||
accounts = persistentListOf(
|
||||
DISPLAY_ACCOUNT,
|
||||
),
|
||||
selectedAccount = DISPLAY_ACCOUNT,
|
||||
onAccountClick = { },
|
||||
onSettingsClick = { },
|
||||
onSyncAllAccountsClick = { },
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,54 @@
|
|||
package net.thunderbird.feature.navigation.drawer.siderail.ui.account
|
||||
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.ui.tooling.preview.Preview
|
||||
import app.k9mail.core.ui.compose.designsystem.PreviewWithThemes
|
||||
import net.thunderbird.feature.navigation.drawer.siderail.ui.FakeData.DISPLAY_ACCOUNT
|
||||
|
||||
@Composable
|
||||
@Preview(showBackground = true)
|
||||
internal fun AccountViewPreview() {
|
||||
PreviewWithThemes {
|
||||
AccountView(
|
||||
account = DISPLAY_ACCOUNT,
|
||||
onClick = {},
|
||||
showAvatar = false,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
@Preview(showBackground = true)
|
||||
internal fun AccountViewWithColorPreview() {
|
||||
PreviewWithThemes {
|
||||
AccountView(
|
||||
account = DISPLAY_ACCOUNT,
|
||||
onClick = {},
|
||||
showAvatar = false,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
@Preview(showBackground = true)
|
||||
internal fun AccountViewWithLongDisplayName() {
|
||||
PreviewWithThemes {
|
||||
AccountView(
|
||||
account = DISPLAY_ACCOUNT,
|
||||
onClick = {},
|
||||
showAvatar = false,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
@Preview(showBackground = true)
|
||||
internal fun AccountViewWithLongEmailPreview() {
|
||||
PreviewWithThemes {
|
||||
AccountView(
|
||||
account = DISPLAY_ACCOUNT,
|
||||
onClick = {},
|
||||
showAvatar = false,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,101 @@
|
|||
package net.thunderbird.feature.navigation.drawer.siderail.ui.folder
|
||||
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.ui.tooling.preview.Preview
|
||||
import app.k9mail.core.ui.compose.designsystem.PreviewWithThemes
|
||||
|
||||
@Composable
|
||||
@Preview(showBackground = true)
|
||||
internal fun FolderListItemBadgePreview() {
|
||||
PreviewWithThemes {
|
||||
FolderListItemBadge(
|
||||
unreadCount = 99,
|
||||
starredCount = 0,
|
||||
showStarredCount = true,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
@Preview(showBackground = true)
|
||||
internal fun FolderListItemBadgeWithStarredCountPreview() {
|
||||
PreviewWithThemes {
|
||||
FolderListItemBadge(
|
||||
unreadCount = 99,
|
||||
starredCount = 1,
|
||||
showStarredCount = true,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
@Preview(showBackground = true)
|
||||
internal fun FolderListItemBadgeWithZeroUnreadCountPreview() {
|
||||
PreviewWithThemes {
|
||||
FolderListItemBadge(
|
||||
unreadCount = 0,
|
||||
starredCount = 1,
|
||||
showStarredCount = true,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
@Preview(showBackground = true)
|
||||
internal fun FolderListItemBadgeWithZeroStarredCountPreview() {
|
||||
PreviewWithThemes {
|
||||
FolderListItemBadge(
|
||||
unreadCount = 99,
|
||||
starredCount = 0,
|
||||
showStarredCount = true,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
@Preview(showBackground = true)
|
||||
internal fun FolderListItemBadgeWithZeroCountsPreview() {
|
||||
PreviewWithThemes {
|
||||
FolderListItemBadge(
|
||||
unreadCount = 0,
|
||||
starredCount = 0,
|
||||
showStarredCount = true,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
@Preview(showBackground = true)
|
||||
internal fun FolderListItemBadgeWithoutStarredCountPreview() {
|
||||
PreviewWithThemes {
|
||||
FolderListItemBadge(
|
||||
unreadCount = 99,
|
||||
starredCount = 1,
|
||||
showStarredCount = false,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
@Preview(showBackground = true)
|
||||
internal fun FolderListItemBadgeWith100CountsPreview() {
|
||||
PreviewWithThemes {
|
||||
FolderListItemBadge(
|
||||
unreadCount = 100,
|
||||
starredCount = 100,
|
||||
showStarredCount = true,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
@Preview(showBackground = true)
|
||||
internal fun FolderListItemBadgeWith1000CountsPreview() {
|
||||
PreviewWithThemes {
|
||||
FolderListItemBadge(
|
||||
unreadCount = 1000,
|
||||
starredCount = 1000,
|
||||
showStarredCount = true,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,98 @@
|
|||
package net.thunderbird.feature.navigation.drawer.siderail.ui.folder
|
||||
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.ui.platform.LocalContext
|
||||
import androidx.compose.ui.tooling.preview.Preview
|
||||
import app.k9mail.core.ui.compose.designsystem.PreviewWithThemes
|
||||
import app.k9mail.legacy.ui.folder.FolderNameFormatter
|
||||
import net.thunderbird.feature.mail.folder.api.FolderType
|
||||
import net.thunderbird.feature.navigation.drawer.siderail.ui.FakeData.DISPLAY_FOLDER
|
||||
import net.thunderbird.feature.navigation.drawer.siderail.ui.FakeData.UNIFIED_FOLDER
|
||||
|
||||
@Composable
|
||||
@Preview(showBackground = true)
|
||||
internal fun FolderListItemPreview() {
|
||||
PreviewWithThemes {
|
||||
FolderListItem(
|
||||
displayFolder = DISPLAY_FOLDER,
|
||||
selected = false,
|
||||
showStarredCount = false,
|
||||
onClick = {},
|
||||
folderNameFormatter = FolderNameFormatter(LocalContext.current.resources),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
@Preview(showBackground = true)
|
||||
internal fun FolderListItemSelectedPreview() {
|
||||
PreviewWithThemes {
|
||||
FolderListItem(
|
||||
displayFolder = DISPLAY_FOLDER,
|
||||
selected = true,
|
||||
showStarredCount = false,
|
||||
onClick = {},
|
||||
folderNameFormatter = FolderNameFormatter(LocalContext.current.resources),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
@Preview(showBackground = true)
|
||||
internal fun FolderListItemWithStarredPreview() {
|
||||
PreviewWithThemes {
|
||||
FolderListItem(
|
||||
displayFolder = DISPLAY_FOLDER,
|
||||
selected = false,
|
||||
showStarredCount = true,
|
||||
onClick = {},
|
||||
folderNameFormatter = FolderNameFormatter(LocalContext.current.resources),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
@Preview(showBackground = true)
|
||||
internal fun FolderListItemWithStarredSelectedPreview() {
|
||||
PreviewWithThemes {
|
||||
FolderListItem(
|
||||
displayFolder = DISPLAY_FOLDER,
|
||||
selected = true,
|
||||
showStarredCount = true,
|
||||
onClick = {},
|
||||
folderNameFormatter = FolderNameFormatter(LocalContext.current.resources),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
@Preview(showBackground = true)
|
||||
internal fun FolderListItemWithInboxFolderPreview() {
|
||||
PreviewWithThemes {
|
||||
FolderListItem(
|
||||
displayFolder = DISPLAY_FOLDER.copy(
|
||||
folder = DISPLAY_FOLDER.folder.copy(
|
||||
type = FolderType.INBOX,
|
||||
),
|
||||
),
|
||||
selected = false,
|
||||
showStarredCount = true,
|
||||
onClick = {},
|
||||
folderNameFormatter = FolderNameFormatter(LocalContext.current.resources),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
@Preview(showBackground = true)
|
||||
internal fun FolderListItemWithUnifiedFolderPreview() {
|
||||
PreviewWithThemes {
|
||||
FolderListItem(
|
||||
displayFolder = UNIFIED_FOLDER,
|
||||
selected = false,
|
||||
showStarredCount = false,
|
||||
onClick = {},
|
||||
folderNameFormatter = FolderNameFormatter(LocalContext.current.resources),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,54 @@
|
|||
package net.thunderbird.feature.navigation.drawer.siderail.ui.folder
|
||||
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.ui.tooling.preview.Preview
|
||||
import app.k9mail.core.ui.compose.designsystem.PreviewWithTheme
|
||||
import kotlinx.collections.immutable.persistentListOf
|
||||
import net.thunderbird.feature.navigation.drawer.siderail.ui.FakeData.DISPLAY_FOLDER
|
||||
import net.thunderbird.feature.navigation.drawer.siderail.ui.FakeData.UNIFIED_FOLDER
|
||||
|
||||
@Composable
|
||||
@Preview(showBackground = true)
|
||||
internal fun FolderListPreview() {
|
||||
PreviewWithTheme {
|
||||
FolderList(
|
||||
folders = persistentListOf(
|
||||
DISPLAY_FOLDER,
|
||||
),
|
||||
selectedFolder = null,
|
||||
onFolderClick = {},
|
||||
showStarredCount = false,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
@Preview(showBackground = true)
|
||||
internal fun FolderListPreviewSelected() {
|
||||
PreviewWithTheme {
|
||||
FolderList(
|
||||
folders = persistentListOf(
|
||||
DISPLAY_FOLDER,
|
||||
),
|
||||
selectedFolder = DISPLAY_FOLDER,
|
||||
onFolderClick = {},
|
||||
showStarredCount = false,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
@Preview(showBackground = true)
|
||||
internal fun FolderListWithUnifiedFolderPreview() {
|
||||
PreviewWithTheme {
|
||||
FolderList(
|
||||
folders = persistentListOf(
|
||||
UNIFIED_FOLDER,
|
||||
DISPLAY_FOLDER,
|
||||
),
|
||||
selectedFolder = DISPLAY_FOLDER,
|
||||
onFolderClick = {},
|
||||
showStarredCount = false,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,18 @@
|
|||
package net.thunderbird.feature.navigation.drawer.siderail.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 = {},
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,18 @@
|
|||
package net.thunderbird.feature.navigation.drawer.siderail.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 SettingListItemPreview() {
|
||||
PreviewWithThemes {
|
||||
SettingListItem(
|
||||
label = "Settings",
|
||||
onClick = {},
|
||||
imageVector = Icons.Outlined.Settings,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,29 @@
|
|||
package net.thunderbird.feature.navigation.drawer.siderail.ui.setting
|
||||
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.ui.tooling.preview.Preview
|
||||
import app.k9mail.core.ui.compose.designsystem.PreviewWithTheme
|
||||
|
||||
@Composable
|
||||
@Preview(showBackground = true)
|
||||
internal fun SettingListPreview() {
|
||||
PreviewWithTheme {
|
||||
SettingList(
|
||||
onAccountSelectorClick = {},
|
||||
onManageFoldersClick = {},
|
||||
showAccountSelector = false,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
@Preview(showBackground = true)
|
||||
internal fun SettingListShowAccountSelectorPreview() {
|
||||
PreviewWithTheme {
|
||||
SettingList(
|
||||
onAccountSelectorClick = {},
|
||||
onManageFoldersClick = {},
|
||||
showAccountSelector = true,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,74 @@
|
|||
package net.thunderbird.feature.navigation.drawer.siderail
|
||||
|
||||
import net.thunderbird.feature.navigation.drawer.siderail.data.UnifiedFolderRepository
|
||||
import net.thunderbird.feature.navigation.drawer.siderail.domain.DomainContract
|
||||
import net.thunderbird.feature.navigation.drawer.siderail.domain.DomainContract.UseCase
|
||||
import net.thunderbird.feature.navigation.drawer.siderail.domain.usecase.GetDisplayAccounts
|
||||
import net.thunderbird.feature.navigation.drawer.siderail.domain.usecase.GetDisplayFoldersForAccount
|
||||
import net.thunderbird.feature.navigation.drawer.siderail.domain.usecase.GetDrawerConfig
|
||||
import net.thunderbird.feature.navigation.drawer.siderail.domain.usecase.SaveDrawerConfig
|
||||
import net.thunderbird.feature.navigation.drawer.siderail.domain.usecase.SyncAccount
|
||||
import net.thunderbird.feature.navigation.drawer.siderail.domain.usecase.SyncAllAccounts
|
||||
import net.thunderbird.feature.navigation.drawer.siderail.ui.DrawerViewModel
|
||||
import org.koin.core.module.Module
|
||||
import org.koin.core.module.dsl.viewModel
|
||||
import org.koin.dsl.module
|
||||
|
||||
val navigationSideRailDrawerModule: Module = module {
|
||||
|
||||
single<DomainContract.UnifiedFolderRepository> {
|
||||
UnifiedFolderRepository(
|
||||
messageCountsProvider = get(),
|
||||
)
|
||||
}
|
||||
|
||||
single<UseCase.GetDrawerConfig> {
|
||||
GetDrawerConfig(
|
||||
configLoader = get(),
|
||||
)
|
||||
}
|
||||
single<UseCase.SaveDrawerConfig> {
|
||||
SaveDrawerConfig(
|
||||
drawerConfigWriter = get(),
|
||||
)
|
||||
}
|
||||
|
||||
single<UseCase.GetDisplayAccounts> {
|
||||
GetDisplayAccounts(
|
||||
accountManager = get(),
|
||||
messageCountsProvider = get(),
|
||||
messageListRepository = get(),
|
||||
)
|
||||
}
|
||||
|
||||
single<UseCase.GetDisplayFoldersForAccount> {
|
||||
GetDisplayFoldersForAccount(
|
||||
displayFolderRepository = get(),
|
||||
unifiedFolderRepository = get(),
|
||||
)
|
||||
}
|
||||
|
||||
single<UseCase.SyncAccount> {
|
||||
SyncAccount(
|
||||
accountManager = get(),
|
||||
messagingController = get(),
|
||||
)
|
||||
}
|
||||
|
||||
single<UseCase.SyncAllAccounts> {
|
||||
SyncAllAccounts(
|
||||
messagingController = get(),
|
||||
)
|
||||
}
|
||||
|
||||
viewModel {
|
||||
DrawerViewModel(
|
||||
getDrawerConfig = get(),
|
||||
saveDrawerConfig = get(),
|
||||
getDisplayAccounts = get(),
|
||||
getDisplayFoldersForAccount = get(),
|
||||
syncAccount = get(),
|
||||
syncAllAccounts = get(),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,111 @@
|
|||
package net.thunderbird.feature.navigation.drawer.siderail
|
||||
|
||||
import androidx.appcompat.app.AppCompatActivity
|
||||
import androidx.compose.ui.platform.ComposeView
|
||||
import androidx.core.view.GravityCompat
|
||||
import androidx.drawerlayout.widget.DrawerLayout
|
||||
import androidx.lifecycle.compose.collectAsStateWithLifecycle
|
||||
import kotlinx.coroutines.flow.MutableStateFlow
|
||||
import kotlinx.coroutines.flow.update
|
||||
import net.thunderbird.core.ui.theme.api.FeatureThemeProvider
|
||||
import net.thunderbird.feature.navigation.drawer.api.NavigationDrawer
|
||||
import net.thunderbird.feature.navigation.drawer.api.R
|
||||
import net.thunderbird.feature.navigation.drawer.siderail.domain.entity.DisplayUnifiedFolderType
|
||||
import net.thunderbird.feature.navigation.drawer.siderail.domain.entity.createDisplayAccountFolderId
|
||||
import net.thunderbird.feature.navigation.drawer.siderail.ui.DrawerView
|
||||
import org.koin.core.component.KoinComponent
|
||||
import org.koin.core.component.inject
|
||||
|
||||
internal data class FolderDrawerState(
|
||||
val selectedAccountUuid: String? = null,
|
||||
val selectedFolderId: String? = null,
|
||||
)
|
||||
|
||||
class SideRailDrawer(
|
||||
override val parent: AppCompatActivity,
|
||||
private val openAccount: (accountId: String) -> Unit,
|
||||
private val openFolder: (accountId: String, folderId: Long) -> Unit,
|
||||
private val openUnifiedFolder: () -> Unit,
|
||||
private val openManageFolders: () -> Unit,
|
||||
private val openSettings: () -> Unit,
|
||||
createDrawerListener: () -> DrawerLayout.DrawerListener,
|
||||
) : NavigationDrawer, KoinComponent {
|
||||
|
||||
private val themeProvider: FeatureThemeProvider by inject()
|
||||
|
||||
private val drawer: DrawerLayout = parent.findViewById(R.id.navigation_drawer_layout)
|
||||
private val drawerContent: ComposeView = parent.findViewById(R.id.navigation_drawer_content)
|
||||
|
||||
private val drawerState = MutableStateFlow(FolderDrawerState())
|
||||
|
||||
init {
|
||||
drawer.addDrawerListener(createDrawerListener())
|
||||
|
||||
drawerContent.setContent {
|
||||
themeProvider.WithTheme {
|
||||
val state = drawerState.collectAsStateWithLifecycle()
|
||||
|
||||
DrawerView(
|
||||
drawerState = state.value,
|
||||
openAccount = openAccount,
|
||||
openFolder = openFolder,
|
||||
openUnifiedFolder = openUnifiedFolder,
|
||||
openManageFolders = openManageFolders,
|
||||
openSettings = openSettings,
|
||||
closeDrawer = { close() },
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override val isOpen: Boolean
|
||||
get() = drawer.isOpen
|
||||
|
||||
override fun selectAccount(accountUuid: String) {
|
||||
drawerState.update {
|
||||
it.copy(selectedAccountUuid = accountUuid)
|
||||
}
|
||||
}
|
||||
|
||||
override fun selectFolder(accountUuid: String, folderId: Long) {
|
||||
drawerState.update {
|
||||
it.copy(
|
||||
selectedAccountUuid = accountUuid,
|
||||
selectedFolderId = createDisplayAccountFolderId(accountUuid, folderId),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
override fun selectUnifiedInbox() {
|
||||
drawerState.update {
|
||||
it.copy(
|
||||
selectedAccountUuid = "unified_account",
|
||||
selectedFolderId = DisplayUnifiedFolderType.INBOX.id,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
override fun deselect() {
|
||||
drawerState.update {
|
||||
it.copy(
|
||||
selectedFolderId = null,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
override fun open() {
|
||||
drawer.openDrawer(GravityCompat.START)
|
||||
}
|
||||
|
||||
override fun close() {
|
||||
drawer.closeDrawer(GravityCompat.START)
|
||||
}
|
||||
|
||||
override fun lock() {
|
||||
drawer.setDrawerLockMode(DrawerLayout.LOCK_MODE_LOCKED_CLOSED)
|
||||
}
|
||||
|
||||
override fun unlock() {
|
||||
drawer.setDrawerLockMode(DrawerLayout.LOCK_MODE_UNLOCKED)
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,44 @@
|
|||
package net.thunderbird.feature.navigation.drawer.siderail.data
|
||||
|
||||
import app.k9mail.legacy.message.controller.MessageCountsProvider
|
||||
import kotlinx.coroutines.flow.Flow
|
||||
import kotlinx.coroutines.flow.map
|
||||
import net.thunderbird.feature.navigation.drawer.siderail.domain.DomainContract
|
||||
import net.thunderbird.feature.navigation.drawer.siderail.domain.entity.DisplayUnifiedFolder
|
||||
import net.thunderbird.feature.navigation.drawer.siderail.domain.entity.DisplayUnifiedFolderType
|
||||
import net.thunderbird.feature.search.legacy.LocalMessageSearch
|
||||
import net.thunderbird.feature.search.legacy.api.MessageSearchField
|
||||
import net.thunderbird.feature.search.legacy.api.SearchAttribute
|
||||
|
||||
internal class UnifiedFolderRepository(
|
||||
private val messageCountsProvider: MessageCountsProvider,
|
||||
) : DomainContract.UnifiedFolderRepository {
|
||||
|
||||
override fun getDisplayUnifiedFolderFlow(unifiedFolderType: DisplayUnifiedFolderType): Flow<DisplayUnifiedFolder> {
|
||||
return messageCountsProvider.getMessageCountsFlow(createUnifiedFolderSearch(unifiedFolderType)).map {
|
||||
DisplayUnifiedFolder(
|
||||
id = UNIFIED_INBOX_ID,
|
||||
unifiedType = DisplayUnifiedFolderType.INBOX,
|
||||
unreadMessageCount = it.unread,
|
||||
starredMessageCount = it.starred,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
private fun createUnifiedFolderSearch(unifiedFolderType: DisplayUnifiedFolderType): LocalMessageSearch {
|
||||
return when (unifiedFolderType) {
|
||||
DisplayUnifiedFolderType.INBOX -> return createUnifiedInboxSearch()
|
||||
}
|
||||
}
|
||||
|
||||
private fun createUnifiedInboxSearch(): LocalMessageSearch {
|
||||
return LocalMessageSearch().apply {
|
||||
id = UNIFIED_INBOX_ID
|
||||
and(MessageSearchField.INTEGRATE, "1", SearchAttribute.EQUALS)
|
||||
}
|
||||
}
|
||||
|
||||
companion object {
|
||||
const val UNIFIED_INBOX_ID = "unified_inbox"
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,47 @@
|
|||
package net.thunderbird.feature.navigation.drawer.siderail.domain
|
||||
|
||||
import kotlinx.coroutines.flow.Flow
|
||||
import net.thunderbird.feature.navigation.drawer.api.NavigationDrawerExternalContract.DrawerConfig
|
||||
import net.thunderbird.feature.navigation.drawer.siderail.domain.entity.DisplayAccount
|
||||
import net.thunderbird.feature.navigation.drawer.siderail.domain.entity.DisplayFolder
|
||||
import net.thunderbird.feature.navigation.drawer.siderail.domain.entity.DisplayUnifiedFolder
|
||||
import net.thunderbird.feature.navigation.drawer.siderail.domain.entity.DisplayUnifiedFolderType
|
||||
|
||||
internal interface DomainContract {
|
||||
|
||||
interface UseCase {
|
||||
fun interface GetDrawerConfig {
|
||||
operator fun invoke(): Flow<DrawerConfig>
|
||||
}
|
||||
|
||||
fun interface SaveDrawerConfig {
|
||||
operator fun invoke(drawerConfig: DrawerConfig): Flow<Unit>
|
||||
}
|
||||
|
||||
fun interface GetDisplayAccounts {
|
||||
operator fun invoke(): Flow<List<DisplayAccount>>
|
||||
}
|
||||
|
||||
fun interface GetDisplayFoldersForAccount {
|
||||
operator fun invoke(accountId: String, includeUnifiedFolders: Boolean): Flow<List<DisplayFolder>>
|
||||
}
|
||||
|
||||
/**
|
||||
* Synchronize the given account uuid.
|
||||
*/
|
||||
fun interface SyncAccount {
|
||||
operator fun invoke(accountUuid: String): Flow<Result<Unit>>
|
||||
}
|
||||
|
||||
/**
|
||||
* Synchronize all accounts.
|
||||
*/
|
||||
fun interface SyncAllAccounts {
|
||||
operator fun invoke(): Flow<Result<Unit>>
|
||||
}
|
||||
}
|
||||
|
||||
interface UnifiedFolderRepository {
|
||||
fun getDisplayUnifiedFolderFlow(unifiedFolderType: DisplayUnifiedFolderType): Flow<DisplayUnifiedFolder>
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,10 @@
|
|||
package net.thunderbird.feature.navigation.drawer.siderail.domain.entity
|
||||
|
||||
internal data class DisplayAccount(
|
||||
val id: String,
|
||||
val name: String,
|
||||
val email: String,
|
||||
val color: Int,
|
||||
val unreadMessageCount: Int,
|
||||
val starredMessageCount: Int,
|
||||
)
|
||||
|
|
@ -0,0 +1,17 @@
|
|||
package net.thunderbird.feature.navigation.drawer.siderail.domain.entity
|
||||
|
||||
import net.thunderbird.feature.mail.folder.api.Folder
|
||||
|
||||
internal data class DisplayAccountFolder(
|
||||
val accountId: String,
|
||||
val folder: Folder,
|
||||
val isInTopGroup: Boolean,
|
||||
override val unreadMessageCount: Int,
|
||||
override val starredMessageCount: Int,
|
||||
) : DisplayFolder {
|
||||
override val id: String = createDisplayAccountFolderId(accountId, folder.id)
|
||||
}
|
||||
|
||||
fun createDisplayAccountFolderId(accountId: String, folderId: Long): String {
|
||||
return "${accountId}_$folderId"
|
||||
}
|
||||
|
|
@ -0,0 +1,7 @@
|
|||
package net.thunderbird.feature.navigation.drawer.siderail.domain.entity
|
||||
|
||||
internal interface DisplayFolder {
|
||||
val id: String
|
||||
val unreadMessageCount: Int
|
||||
val starredMessageCount: Int
|
||||
}
|
||||
|
|
@ -0,0 +1,8 @@
|
|||
package net.thunderbird.feature.navigation.drawer.siderail.domain.entity
|
||||
|
||||
internal data class DisplayUnifiedFolder(
|
||||
override val id: String,
|
||||
val unifiedType: DisplayUnifiedFolderType,
|
||||
override val unreadMessageCount: Int,
|
||||
override val starredMessageCount: Int,
|
||||
) : DisplayFolder
|
||||
|
|
@ -0,0 +1,12 @@
|
|||
package net.thunderbird.feature.navigation.drawer.siderail.domain.entity
|
||||
|
||||
/**
|
||||
* Represents a unified folder in the drawer.
|
||||
*
|
||||
* The id is unique for each unified folder type.
|
||||
*/
|
||||
internal enum class DisplayUnifiedFolderType(
|
||||
val id: String,
|
||||
) {
|
||||
INBOX("unified_inbox"),
|
||||
}
|
||||
|
|
@ -0,0 +1,68 @@
|
|||
package net.thunderbird.feature.navigation.drawer.siderail.domain.usecase
|
||||
|
||||
import app.k9mail.legacy.mailstore.MessageListChangedListener
|
||||
import app.k9mail.legacy.mailstore.MessageListRepository
|
||||
import app.k9mail.legacy.message.controller.MessageCounts
|
||||
import app.k9mail.legacy.message.controller.MessageCountsProvider
|
||||
import kotlin.coroutines.CoroutineContext
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.ExperimentalCoroutinesApi
|
||||
import kotlinx.coroutines.channels.awaitClose
|
||||
import kotlinx.coroutines.flow.Flow
|
||||
import kotlinx.coroutines.flow.callbackFlow
|
||||
import kotlinx.coroutines.flow.combine
|
||||
import kotlinx.coroutines.flow.flatMapLatest
|
||||
import kotlinx.coroutines.flow.flowOn
|
||||
import kotlinx.coroutines.launch
|
||||
import net.thunderbird.core.android.account.AccountManager
|
||||
import net.thunderbird.core.android.account.LegacyAccount
|
||||
import net.thunderbird.feature.navigation.drawer.siderail.domain.DomainContract
|
||||
import net.thunderbird.feature.navigation.drawer.siderail.domain.entity.DisplayAccount
|
||||
|
||||
internal class GetDisplayAccounts(
|
||||
private val accountManager: AccountManager,
|
||||
private val messageCountsProvider: MessageCountsProvider,
|
||||
private val messageListRepository: MessageListRepository,
|
||||
private val coroutineContext: CoroutineContext = Dispatchers.IO,
|
||||
) : DomainContract.UseCase.GetDisplayAccounts {
|
||||
|
||||
@OptIn(ExperimentalCoroutinesApi::class)
|
||||
override fun invoke(): Flow<List<DisplayAccount>> {
|
||||
return accountManager.getAccountsFlow()
|
||||
.flatMapLatest { accounts ->
|
||||
val messageCountsFlows: List<Flow<MessageCounts>> = accounts.map { account ->
|
||||
getMessageCountsFlow(account)
|
||||
}
|
||||
|
||||
combine(messageCountsFlows) { messageCountsList ->
|
||||
messageCountsList.mapIndexed { index, messageCounts ->
|
||||
DisplayAccount(
|
||||
id = accounts[index].uuid,
|
||||
name = accounts[index].displayName,
|
||||
email = accounts[index].email,
|
||||
color = accounts[index].chipColor,
|
||||
unreadMessageCount = messageCounts.unread,
|
||||
starredMessageCount = messageCounts.starred,
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun getMessageCountsFlow(account: LegacyAccount): Flow<MessageCounts> {
|
||||
return callbackFlow {
|
||||
send(messageCountsProvider.getMessageCounts(account))
|
||||
|
||||
val listener = MessageListChangedListener {
|
||||
launch {
|
||||
send(messageCountsProvider.getMessageCounts(account))
|
||||
}
|
||||
}
|
||||
messageListRepository.addListener(account.uuid, listener)
|
||||
|
||||
awaitClose {
|
||||
messageListRepository.removeListener(listener)
|
||||
}
|
||||
}.flowOn(coroutineContext)
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,48 @@
|
|||
package net.thunderbird.feature.navigation.drawer.siderail.domain.usecase
|
||||
|
||||
import app.k9mail.legacy.ui.folder.DisplayFolderRepository
|
||||
import kotlinx.coroutines.flow.Flow
|
||||
import kotlinx.coroutines.flow.combine
|
||||
import kotlinx.coroutines.flow.flowOf
|
||||
import kotlinx.coroutines.flow.map
|
||||
import net.thunderbird.feature.navigation.drawer.siderail.domain.DomainContract
|
||||
import net.thunderbird.feature.navigation.drawer.siderail.domain.entity.DisplayAccountFolder
|
||||
import net.thunderbird.feature.navigation.drawer.siderail.domain.entity.DisplayFolder
|
||||
import net.thunderbird.feature.navigation.drawer.siderail.domain.entity.DisplayUnifiedFolder
|
||||
import net.thunderbird.feature.navigation.drawer.siderail.domain.entity.DisplayUnifiedFolderType
|
||||
|
||||
internal class GetDisplayFoldersForAccount(
|
||||
private val displayFolderRepository: DisplayFolderRepository,
|
||||
private val unifiedFolderRepository: DomainContract.UnifiedFolderRepository,
|
||||
) : DomainContract.UseCase.GetDisplayFoldersForAccount {
|
||||
override fun invoke(accountId: String, includeUnifiedFolders: Boolean): Flow<List<DisplayFolder>> {
|
||||
val accountFoldersFlow: Flow<List<DisplayFolder>> =
|
||||
displayFolderRepository.getDisplayFoldersFlow(accountId).map { displayFolders ->
|
||||
displayFolders.map { displayFolder ->
|
||||
DisplayAccountFolder(
|
||||
accountId = accountId,
|
||||
folder = displayFolder.folder,
|
||||
isInTopGroup = displayFolder.isInTopGroup,
|
||||
unreadMessageCount = displayFolder.unreadMessageCount,
|
||||
starredMessageCount = displayFolder.starredMessageCount,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
val unifiedFoldersFlow: Flow<List<DisplayFolder>> = if (includeUnifiedFolders) {
|
||||
unifiedFolderRepository.getDisplayUnifiedFolderFlow(DisplayUnifiedFolderType.INBOX)
|
||||
.map { displayUnifiedFolder ->
|
||||
listOf(displayUnifiedFolder)
|
||||
}
|
||||
} else {
|
||||
flowOf(emptyList<DisplayUnifiedFolder>())
|
||||
}
|
||||
|
||||
return combine(
|
||||
accountFoldersFlow,
|
||||
unifiedFoldersFlow,
|
||||
) { accountFolders, unifiedFolders ->
|
||||
unifiedFolders + accountFolders
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,14 @@
|
|||
package net.thunderbird.feature.navigation.drawer.siderail.domain.usecase
|
||||
|
||||
import kotlinx.coroutines.flow.Flow
|
||||
import net.thunderbird.feature.navigation.drawer.api.NavigationDrawerExternalContract.DrawerConfig
|
||||
import net.thunderbird.feature.navigation.drawer.api.NavigationDrawerExternalContract.DrawerConfigLoader
|
||||
import net.thunderbird.feature.navigation.drawer.siderail.domain.DomainContract
|
||||
|
||||
internal class GetDrawerConfig(
|
||||
private val configLoader: DrawerConfigLoader,
|
||||
) : DomainContract.UseCase.GetDrawerConfig {
|
||||
override operator fun invoke(): Flow<DrawerConfig> {
|
||||
return configLoader.loadDrawerConfigFlow()
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,17 @@
|
|||
package net.thunderbird.feature.navigation.drawer.siderail.domain.usecase
|
||||
|
||||
import kotlinx.coroutines.flow.Flow
|
||||
import kotlinx.coroutines.flow.flow
|
||||
import net.thunderbird.feature.navigation.drawer.api.NavigationDrawerExternalContract
|
||||
import net.thunderbird.feature.navigation.drawer.api.NavigationDrawerExternalContract.DrawerConfigWriter
|
||||
import net.thunderbird.feature.navigation.drawer.siderail.domain.DomainContract
|
||||
|
||||
internal class SaveDrawerConfig(
|
||||
private val drawerConfigWriter: DrawerConfigWriter,
|
||||
) : DomainContract.UseCase.SaveDrawerConfig {
|
||||
override fun invoke(drawerConfig: NavigationDrawerExternalContract.DrawerConfig): Flow<Unit> {
|
||||
return flow {
|
||||
emit(drawerConfigWriter.writeDrawerConfig(drawerConfig))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,41 @@
|
|||
package net.thunderbird.feature.navigation.drawer.siderail.domain.usecase
|
||||
|
||||
import android.content.Context
|
||||
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
|
||||
import net.thunderbird.core.android.account.AccountManager
|
||||
import net.thunderbird.core.android.account.LegacyAccount
|
||||
import net.thunderbird.feature.navigation.drawer.siderail.domain.DomainContract
|
||||
|
||||
internal class SyncAccount(
|
||||
private val accountManager: AccountManager,
|
||||
private val messagingController: MessagingControllerMailChecker,
|
||||
private val coroutineContext: CoroutineContext = Dispatchers.IO,
|
||||
) : DomainContract.UseCase.SyncAccount {
|
||||
override fun invoke(accountUuid: String): Flow<Result<Unit>> = callbackFlow {
|
||||
val listener = object : SimpleMessagingListener() {
|
||||
override fun checkMailFinished(context: Context?, account: LegacyAccount?) {
|
||||
trySend(Result.success(Unit))
|
||||
close()
|
||||
}
|
||||
}
|
||||
|
||||
val account = accountManager.getAccount(accountUuid)
|
||||
|
||||
messagingController.checkMail(
|
||||
account = account,
|
||||
ignoreLastCheckedTime = true,
|
||||
useManualWakeLock = true,
|
||||
notify = true,
|
||||
listener = listener,
|
||||
)
|
||||
|
||||
awaitClose()
|
||||
}.flowOn(coroutineContext)
|
||||
}
|
||||
|
|
@ -0,0 +1,37 @@
|
|||
package net.thunderbird.feature.navigation.drawer.siderail.domain.usecase
|
||||
|
||||
import android.content.Context
|
||||
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
|
||||
import net.thunderbird.core.android.account.LegacyAccount
|
||||
import net.thunderbird.feature.navigation.drawer.siderail.domain.DomainContract
|
||||
|
||||
class SyncAllAccounts(
|
||||
private val messagingController: MessagingControllerMailChecker,
|
||||
private val coroutineContext: CoroutineContext = Dispatchers.IO,
|
||||
) : DomainContract.UseCase.SyncAllAccounts {
|
||||
override fun invoke(): Flow<Result<Unit>> = callbackFlow {
|
||||
val listener = object : SimpleMessagingListener() {
|
||||
override fun checkMailFinished(context: Context?, account: LegacyAccount?) {
|
||||
trySend(Result.success(Unit))
|
||||
close()
|
||||
}
|
||||
}
|
||||
|
||||
messagingController.checkMail(
|
||||
account = null,
|
||||
ignoreLastCheckedTime = true,
|
||||
useManualWakeLock = true,
|
||||
notify = true,
|
||||
listener = listener,
|
||||
)
|
||||
|
||||
awaitClose()
|
||||
}.flowOn(coroutineContext)
|
||||
}
|
||||
|
|
@ -0,0 +1,110 @@
|
|||
package net.thunderbird.feature.navigation.drawer.siderail.ui
|
||||
|
||||
import androidx.compose.animation.AnimatedVisibility
|
||||
import androidx.compose.foundation.layout.Column
|
||||
import androidx.compose.foundation.layout.Row
|
||||
import androidx.compose.foundation.layout.WindowInsets
|
||||
import androidx.compose.foundation.layout.displayCutout
|
||||
import androidx.compose.foundation.layout.fillMaxHeight
|
||||
import androidx.compose.foundation.layout.fillMaxSize
|
||||
import androidx.compose.foundation.layout.statusBars
|
||||
import androidx.compose.foundation.layout.width
|
||||
import androidx.compose.foundation.layout.windowInsetsPadding
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.platform.LocalDensity
|
||||
import androidx.compose.ui.platform.LocalLayoutDirection
|
||||
import androidx.compose.ui.unit.Dp
|
||||
import androidx.compose.ui.unit.LayoutDirection
|
||||
import androidx.compose.ui.unit.dp
|
||||
import app.k9mail.core.ui.compose.designsystem.atom.DividerHorizontal
|
||||
import app.k9mail.core.ui.compose.designsystem.atom.Surface
|
||||
import net.thunderbird.core.ui.compose.common.modifier.testTagAsResourceId
|
||||
import net.thunderbird.feature.navigation.drawer.siderail.ui.account.AccountList
|
||||
import net.thunderbird.feature.navigation.drawer.siderail.ui.account.AccountView
|
||||
import net.thunderbird.feature.navigation.drawer.siderail.ui.folder.FolderList
|
||||
import net.thunderbird.feature.navigation.drawer.siderail.ui.setting.SettingList
|
||||
|
||||
// As long as we use DrawerLayout, we don't have to worry about screens narrower than DRAWER_WIDTH. DrawerLayout will
|
||||
// automatically limit the width of the content view so there's still room for a scrim with minimum tap width.
|
||||
private val DRAWER_WIDTH = 360.dp
|
||||
|
||||
@Composable
|
||||
internal fun DrawerContent(
|
||||
state: DrawerContract.State,
|
||||
onEvent: (DrawerContract.Event) -> Unit,
|
||||
modifier: Modifier = Modifier,
|
||||
) {
|
||||
val additionalWidth = getAdditionalWidth()
|
||||
|
||||
Surface(
|
||||
modifier = modifier
|
||||
.windowInsetsPadding(WindowInsets.statusBars)
|
||||
.width(DRAWER_WIDTH + additionalWidth)
|
||||
.fillMaxHeight()
|
||||
.testTagAsResourceId("DrawerContent"),
|
||||
) {
|
||||
val selectedAccount = state.accounts.firstOrNull { it.id == state.selectedAccountId }
|
||||
Column {
|
||||
selectedAccount?.let {
|
||||
AccountView(
|
||||
account = selectedAccount,
|
||||
onClick = { onEvent(DrawerContract.Event.OnAccountViewClick(selectedAccount)) },
|
||||
showAvatar = state.config.showAccountSelector,
|
||||
)
|
||||
|
||||
DividerHorizontal()
|
||||
}
|
||||
Row {
|
||||
AnimatedVisibility(
|
||||
visible = state.config.showAccountSelector,
|
||||
) {
|
||||
AccountList(
|
||||
accounts = state.accounts,
|
||||
selectedAccount = selectedAccount,
|
||||
onAccountClick = { onEvent(DrawerContract.Event.OnAccountClick(it)) },
|
||||
onSyncAllAccountsClick = { onEvent(DrawerContract.Event.OnSyncAllAccounts) },
|
||||
onSettingsClick = { onEvent(DrawerContract.Event.OnSettingsClick) },
|
||||
)
|
||||
}
|
||||
Column(
|
||||
modifier = Modifier
|
||||
.weight(1f)
|
||||
.fillMaxSize(),
|
||||
) {
|
||||
FolderList(
|
||||
folders = state.folders,
|
||||
selectedFolder = state.folders.firstOrNull { it.id == state.selectedFolderId },
|
||||
onFolderClick = { folder ->
|
||||
onEvent(DrawerContract.Event.OnFolderClick(folder))
|
||||
},
|
||||
showStarredCount = state.config.showStarredCount,
|
||||
modifier = Modifier.weight(1f),
|
||||
)
|
||||
DividerHorizontal()
|
||||
SettingList(
|
||||
onAccountSelectorClick = { onEvent(DrawerContract.Event.OnAccountSelectorClick) },
|
||||
onManageFoldersClick = { onEvent(DrawerContract.Event.OnManageFoldersClick) },
|
||||
showAccountSelector = state.config.showAccountSelector,
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
fun getAdditionalWidth(): Dp {
|
||||
val density = LocalDensity.current
|
||||
val layoutDirection = LocalLayoutDirection.current
|
||||
val isRtl = LocalLayoutDirection.current == LayoutDirection.Rtl
|
||||
|
||||
return if (isRtl) {
|
||||
WindowInsets.displayCutout.getRight(density = density, layoutDirection = layoutDirection)
|
||||
} else {
|
||||
WindowInsets.displayCutout.getLeft(density = density, layoutDirection = layoutDirection)
|
||||
}.pxToDp()
|
||||
}
|
||||
|
||||
@Composable
|
||||
fun Int.pxToDp() = with(LocalDensity.current) { this@pxToDp.toDp() }
|
||||
|
|
@ -0,0 +1,50 @@
|
|||
package net.thunderbird.feature.navigation.drawer.siderail.ui
|
||||
|
||||
import androidx.compose.runtime.Stable
|
||||
import app.k9mail.core.ui.compose.common.mvi.UnidirectionalViewModel
|
||||
import kotlinx.collections.immutable.ImmutableList
|
||||
import kotlinx.collections.immutable.persistentListOf
|
||||
import net.thunderbird.feature.navigation.drawer.api.NavigationDrawerExternalContract.DrawerConfig
|
||||
import net.thunderbird.feature.navigation.drawer.siderail.domain.entity.DisplayAccount
|
||||
import net.thunderbird.feature.navigation.drawer.siderail.domain.entity.DisplayFolder
|
||||
|
||||
internal interface DrawerContract {
|
||||
|
||||
interface ViewModel : UnidirectionalViewModel<State, Event, Effect>
|
||||
|
||||
@Stable
|
||||
data class State(
|
||||
val config: DrawerConfig = DrawerConfig(
|
||||
showUnifiedFolders = false,
|
||||
showStarredCount = false,
|
||||
showAccountSelector = true,
|
||||
),
|
||||
val accounts: ImmutableList<DisplayAccount> = persistentListOf(),
|
||||
val selectedAccountId: String? = null,
|
||||
val folders: ImmutableList<DisplayFolder> = persistentListOf(),
|
||||
val selectedFolderId: String? = null,
|
||||
val isLoading: Boolean = false,
|
||||
)
|
||||
|
||||
sealed interface Event {
|
||||
data class SelectAccount(val accountId: String?) : Event
|
||||
data class SelectFolder(val folderId: String?) : Event
|
||||
data class OnAccountClick(val account: DisplayAccount) : Event
|
||||
data class OnAccountViewClick(val account: DisplayAccount) : Event
|
||||
data class OnFolderClick(val folder: DisplayFolder) : Event
|
||||
data object OnAccountSelectorClick : Event
|
||||
data object OnManageFoldersClick : Event
|
||||
data object OnSettingsClick : Event
|
||||
data object OnSyncAccount : Event
|
||||
data object OnSyncAllAccounts : Event
|
||||
}
|
||||
|
||||
sealed interface Effect {
|
||||
data class OpenAccount(val accountId: String) : Effect
|
||||
data class OpenFolder(val accountId: String, val folderId: Long) : Effect
|
||||
data object OpenUnifiedFolder : Effect
|
||||
data object OpenManageFolders : Effect
|
||||
data object OpenSettings : Effect
|
||||
data object CloseDrawer : Effect
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,53 @@
|
|||
package net.thunderbird.feature.navigation.drawer.siderail.ui
|
||||
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.LaunchedEffect
|
||||
import app.k9mail.core.ui.compose.common.mvi.observe
|
||||
import app.k9mail.core.ui.compose.designsystem.molecule.PullToRefreshBox
|
||||
import net.thunderbird.feature.navigation.drawer.siderail.FolderDrawerState
|
||||
import org.koin.androidx.compose.koinViewModel
|
||||
|
||||
@Composable
|
||||
internal fun DrawerView(
|
||||
drawerState: FolderDrawerState,
|
||||
openAccount: (accountId: String) -> Unit,
|
||||
openFolder: (accountId: String, folderId: Long) -> Unit,
|
||||
openUnifiedFolder: () -> Unit,
|
||||
openManageFolders: () -> Unit,
|
||||
openSettings: () -> Unit,
|
||||
closeDrawer: () -> Unit,
|
||||
viewModel: DrawerContract.ViewModel = koinViewModel<DrawerViewModel>(),
|
||||
) {
|
||||
val (state, dispatch) = viewModel.observe { effect ->
|
||||
when (effect) {
|
||||
is DrawerContract.Effect.OpenAccount -> openAccount(effect.accountId)
|
||||
is DrawerContract.Effect.OpenFolder -> openFolder(
|
||||
effect.accountId,
|
||||
effect.folderId,
|
||||
)
|
||||
|
||||
DrawerContract.Effect.OpenUnifiedFolder -> openUnifiedFolder()
|
||||
is DrawerContract.Effect.OpenManageFolders -> openManageFolders()
|
||||
is DrawerContract.Effect.OpenSettings -> openSettings()
|
||||
DrawerContract.Effect.CloseDrawer -> closeDrawer()
|
||||
}
|
||||
}
|
||||
|
||||
LaunchedEffect(drawerState.selectedAccountUuid) {
|
||||
dispatch(DrawerContract.Event.SelectAccount(drawerState.selectedAccountUuid))
|
||||
}
|
||||
|
||||
LaunchedEffect(drawerState.selectedFolderId) {
|
||||
dispatch(DrawerContract.Event.SelectFolder(drawerState.selectedFolderId))
|
||||
}
|
||||
|
||||
PullToRefreshBox(
|
||||
isRefreshing = state.value.isLoading,
|
||||
onRefresh = { dispatch(DrawerContract.Event.OnSyncAccount) },
|
||||
) {
|
||||
DrawerContent(
|
||||
state = state.value,
|
||||
onEvent = { dispatch(it) },
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,215 @@
|
|||
package net.thunderbird.feature.navigation.drawer.siderail.ui
|
||||
|
||||
import androidx.lifecycle.viewModelScope
|
||||
import app.k9mail.core.ui.compose.common.mvi.BaseViewModel
|
||||
import kotlinx.collections.immutable.ImmutableList
|
||||
import kotlinx.collections.immutable.toImmutableList
|
||||
import kotlinx.coroutines.ExperimentalCoroutinesApi
|
||||
import kotlinx.coroutines.delay
|
||||
import kotlinx.coroutines.flow.collect
|
||||
import kotlinx.coroutines.flow.collectLatest
|
||||
import kotlinx.coroutines.flow.distinctUntilChanged
|
||||
import kotlinx.coroutines.flow.filterNotNull
|
||||
import kotlinx.coroutines.flow.flatMapLatest
|
||||
import kotlinx.coroutines.flow.launchIn
|
||||
import kotlinx.coroutines.flow.map
|
||||
import kotlinx.coroutines.launch
|
||||
import net.thunderbird.feature.navigation.drawer.siderail.domain.DomainContract
|
||||
import net.thunderbird.feature.navigation.drawer.siderail.domain.entity.DisplayAccount
|
||||
import net.thunderbird.feature.navigation.drawer.siderail.domain.entity.DisplayAccountFolder
|
||||
import net.thunderbird.feature.navigation.drawer.siderail.domain.entity.DisplayFolder
|
||||
import net.thunderbird.feature.navigation.drawer.siderail.domain.entity.DisplayUnifiedFolder
|
||||
|
||||
@Suppress("MagicNumber", "TooManyFunctions")
|
||||
internal class DrawerViewModel(
|
||||
private val getDrawerConfig: DomainContract.UseCase.GetDrawerConfig,
|
||||
private val saveDrawerConfig: DomainContract.UseCase.SaveDrawerConfig,
|
||||
private val getDisplayAccounts: DomainContract.UseCase.GetDisplayAccounts,
|
||||
private val getDisplayFoldersForAccount: DomainContract.UseCase.GetDisplayFoldersForAccount,
|
||||
private val syncAccount: DomainContract.UseCase.SyncAccount,
|
||||
private val syncAllAccounts: DomainContract.UseCase.SyncAllAccounts,
|
||||
initialState: DrawerContract.State = DrawerContract.State(),
|
||||
) : BaseViewModel<DrawerContract.State, DrawerContract.Event, DrawerContract.Effect>(
|
||||
initialState = initialState,
|
||||
),
|
||||
DrawerContract.ViewModel {
|
||||
|
||||
init {
|
||||
viewModelScope.launch {
|
||||
getDrawerConfig().collectLatest { config ->
|
||||
updateState {
|
||||
it.copy(config = config)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
viewModelScope.launch {
|
||||
loadAccounts()
|
||||
}
|
||||
|
||||
viewModelScope.launch {
|
||||
loadFolders()
|
||||
}
|
||||
}
|
||||
|
||||
private suspend fun loadAccounts() {
|
||||
getDisplayAccounts().collectLatest { accounts ->
|
||||
updateAccounts(accounts)
|
||||
}
|
||||
}
|
||||
|
||||
private fun updateAccounts(accounts: List<DisplayAccount>) {
|
||||
val selectedAccount = accounts.find { it.id == state.value.selectedAccountId }
|
||||
?: accounts.firstOrNull()
|
||||
|
||||
updateState {
|
||||
it.copy(
|
||||
accounts = accounts.toImmutableList(),
|
||||
selectedAccountId = selectedAccount?.id,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@OptIn(ExperimentalCoroutinesApi::class)
|
||||
private suspend fun loadFolders() {
|
||||
state.map {
|
||||
it.selectedAccountId?.let { accountId ->
|
||||
Pair(accountId, it.config.showUnifiedFolders)
|
||||
}
|
||||
}.filterNotNull()
|
||||
.distinctUntilChanged()
|
||||
.flatMapLatest { (accountId, showUnifiedInbox) ->
|
||||
getDisplayFoldersForAccount(accountId, showUnifiedInbox)
|
||||
}.collect { folders ->
|
||||
updateFolders(folders)
|
||||
}
|
||||
}
|
||||
|
||||
private fun updateFolders(displayFolders: List<DisplayFolder>) {
|
||||
val selectedFolder = displayFolders.find {
|
||||
it.id == state.value.selectedFolderId
|
||||
} ?: displayFolders.firstOrNull()
|
||||
|
||||
updateState {
|
||||
it.copy(
|
||||
folders = displayFolders.toImmutableList(),
|
||||
selectedFolderId = selectedFolder?.id,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
override fun event(event: DrawerContract.Event) {
|
||||
when (event) {
|
||||
is DrawerContract.Event.SelectAccount -> selectAccount(event.accountId)
|
||||
is DrawerContract.Event.SelectFolder -> selectFolder(event.folderId)
|
||||
|
||||
is DrawerContract.Event.OnAccountClick -> openAccount(event.account)
|
||||
is DrawerContract.Event.OnFolderClick -> openFolder(event.folder)
|
||||
is DrawerContract.Event.OnAccountViewClick -> {
|
||||
openAccount(
|
||||
state.value.accounts.nextOrFirst(event.account),
|
||||
)
|
||||
}
|
||||
|
||||
DrawerContract.Event.OnAccountSelectorClick -> {
|
||||
saveDrawerConfig(
|
||||
state.value.config.copy(showAccountSelector = state.value.config.showAccountSelector.not()),
|
||||
).launchIn(viewModelScope)
|
||||
}
|
||||
|
||||
DrawerContract.Event.OnManageFoldersClick -> emitEffect(DrawerContract.Effect.OpenManageFolders)
|
||||
DrawerContract.Event.OnSettingsClick -> emitEffect(DrawerContract.Effect.OpenSettings)
|
||||
DrawerContract.Event.OnSyncAccount -> onSyncAccount()
|
||||
DrawerContract.Event.OnSyncAllAccounts -> onSyncAllAccounts()
|
||||
}
|
||||
}
|
||||
|
||||
private fun selectAccount(accountId: String?) {
|
||||
updateState {
|
||||
it.copy(
|
||||
selectedAccountId = accountId,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
private fun selectFolder(folderId: String?) {
|
||||
updateState {
|
||||
it.copy(
|
||||
selectedFolderId = folderId,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
private fun openAccount(account: DisplayAccount?) {
|
||||
if (account != null) {
|
||||
emitEffect(DrawerContract.Effect.OpenAccount(account.id))
|
||||
}
|
||||
}
|
||||
|
||||
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)
|
||||
}
|
||||
}
|
||||
|
||||
private fun openFolder(folder: DisplayFolder) {
|
||||
if (folder is DisplayAccountFolder) {
|
||||
emitEffect(
|
||||
DrawerContract.Effect.OpenFolder(
|
||||
accountId = folder.accountId,
|
||||
folderId = folder.folder.id,
|
||||
),
|
||||
)
|
||||
} else if (folder is DisplayUnifiedFolder) {
|
||||
emitEffect(DrawerContract.Effect.OpenUnifiedFolder)
|
||||
}
|
||||
|
||||
viewModelScope.launch {
|
||||
delay(DRAWER_CLOSE_DELAY)
|
||||
emitEffect(DrawerContract.Effect.CloseDrawer)
|
||||
}
|
||||
}
|
||||
|
||||
private fun onSyncAccount() {
|
||||
if (state.value.isLoading || state.value.selectedAccountId == null) return
|
||||
|
||||
viewModelScope.launch {
|
||||
updateState {
|
||||
it.copy(isLoading = true)
|
||||
}
|
||||
|
||||
state.value.selectedAccountId?.let { syncAccount(it).collect() }
|
||||
|
||||
updateState {
|
||||
it.copy(isLoading = false)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun onSyncAllAccounts() {
|
||||
if (state.value.isLoading) return
|
||||
|
||||
viewModelScope.launch {
|
||||
updateState {
|
||||
it.copy(isLoading = true)
|
||||
}
|
||||
|
||||
syncAllAccounts().collect()
|
||||
|
||||
updateState {
|
||||
it.copy(isLoading = false)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Delay before closing the drawer to avoid the drawer being closed immediately and give time
|
||||
* for the ripple effect to finish.
|
||||
*/
|
||||
private const val DRAWER_CLOSE_DELAY = 250L
|
||||
|
|
@ -0,0 +1,74 @@
|
|||
package net.thunderbird.feature.navigation.drawer.siderail.ui.account
|
||||
|
||||
import androidx.compose.foundation.layout.Box
|
||||
import androidx.compose.foundation.layout.padding
|
||||
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.platform.LocalContext
|
||||
import androidx.compose.ui.unit.dp
|
||||
import app.k9mail.core.ui.compose.designsystem.atom.Surface
|
||||
import app.k9mail.core.ui.compose.designsystem.atom.text.TextLabelSmall
|
||||
import app.k9mail.core.ui.compose.theme2.ColorRoles
|
||||
import app.k9mail.core.ui.compose.theme2.toColorRoles
|
||||
import net.thunderbird.feature.account.avatar.ui.Avatar
|
||||
import net.thunderbird.feature.navigation.drawer.siderail.domain.entity.DisplayAccount
|
||||
import net.thunderbird.feature.navigation.drawer.siderail.ui.common.labelForCount
|
||||
|
||||
@Composable
|
||||
internal fun AccountAvatar(
|
||||
account: DisplayAccount,
|
||||
selected: Boolean,
|
||||
modifier: Modifier = Modifier,
|
||||
onClick: ((DisplayAccount) -> Unit)? = null,
|
||||
) {
|
||||
val context = LocalContext.current
|
||||
val accountColor = calculateAccountColor(account.color)
|
||||
val accountColorRoles = accountColor.toColorRoles(context)
|
||||
|
||||
Box(
|
||||
modifier = modifier,
|
||||
contentAlignment = Alignment.BottomEnd,
|
||||
) {
|
||||
Avatar(
|
||||
color = accountColor,
|
||||
name = account.name,
|
||||
onClick = onClick?.let { { onClick(account) } },
|
||||
selected = selected,
|
||||
)
|
||||
UnreadBadge(
|
||||
unreadCount = account.unreadMessageCount,
|
||||
accountColorRoles = accountColorRoles,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
private fun UnreadBadge(
|
||||
unreadCount: Int,
|
||||
accountColorRoles: ColorRoles,
|
||||
modifier: Modifier = Modifier,
|
||||
) {
|
||||
if (unreadCount > 0) {
|
||||
val resources = LocalContext.current.resources
|
||||
|
||||
Surface(
|
||||
color = accountColorRoles.accent,
|
||||
shape = CircleShape,
|
||||
modifier = modifier,
|
||||
) {
|
||||
TextLabelSmall(
|
||||
text = labelForCount(
|
||||
count = unreadCount,
|
||||
resources = resources,
|
||||
),
|
||||
color = accountColorRoles.onAccent,
|
||||
modifier = Modifier.padding(
|
||||
horizontal = 3.dp,
|
||||
vertical = 2.dp,
|
||||
),
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,24 @@
|
|||
package net.thunderbird.feature.navigation.drawer.siderail.ui.account
|
||||
|
||||
import androidx.compose.foundation.layout.defaultMinSize
|
||||
import androidx.compose.foundation.layout.width
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.ui.Modifier
|
||||
import app.k9mail.core.ui.compose.designsystem.atom.Surface
|
||||
import app.k9mail.core.ui.compose.theme2.MainTheme
|
||||
|
||||
@Composable
|
||||
internal fun AccountIndicator(
|
||||
accountColor: Int,
|
||||
modifier: Modifier = Modifier,
|
||||
) {
|
||||
Surface(
|
||||
modifier = modifier
|
||||
.width(MainTheme.spacings.half)
|
||||
.defaultMinSize(
|
||||
minHeight = MainTheme.spacings.default,
|
||||
),
|
||||
color = calculateAccountColor(accountColor),
|
||||
shape = MainTheme.shapes.medium,
|
||||
) {}
|
||||
}
|
||||
|
|
@ -0,0 +1,82 @@
|
|||
package net.thunderbird.feature.navigation.drawer.siderail.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.WindowInsets
|
||||
import androidx.compose.foundation.layout.fillMaxHeight
|
||||
import androidx.compose.foundation.layout.height
|
||||
import androidx.compose.foundation.layout.navigationBars
|
||||
import androidx.compose.foundation.layout.padding
|
||||
import androidx.compose.foundation.layout.width
|
||||
import androidx.compose.foundation.layout.windowInsetsPadding
|
||||
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 kotlinx.collections.immutable.ImmutableList
|
||||
import net.thunderbird.feature.navigation.drawer.siderail.R
|
||||
import net.thunderbird.feature.navigation.drawer.siderail.domain.entity.DisplayAccount
|
||||
import net.thunderbird.feature.navigation.drawer.siderail.ui.setting.SettingItem
|
||||
|
||||
@Composable
|
||||
internal fun AccountList(
|
||||
accounts: ImmutableList<DisplayAccount>,
|
||||
selectedAccount: DisplayAccount?,
|
||||
onAccountClick: (DisplayAccount) -> Unit,
|
||||
onSyncAllAccountsClick: () -> Unit,
|
||||
onSettingsClick: () -> Unit,
|
||||
modifier: Modifier = Modifier,
|
||||
) {
|
||||
Surface(
|
||||
modifier = modifier,
|
||||
color = MainTheme.colors.surfaceContainer,
|
||||
) {
|
||||
val horizontalInsetPadding = getDisplayCutOutHorizontalInsetPadding()
|
||||
|
||||
Column(
|
||||
modifier = Modifier
|
||||
.fillMaxHeight()
|
||||
.windowInsetsPadding(WindowInsets.navigationBars)
|
||||
.windowInsetsPadding(horizontalInsetPadding)
|
||||
.width(MainTheme.sizes.large),
|
||||
) {
|
||||
LazyColumn(
|
||||
modifier = Modifier.weight(1f),
|
||||
contentPadding = PaddingValues(vertical = MainTheme.spacings.default),
|
||||
) {
|
||||
items(
|
||||
items = accounts,
|
||||
key = { account -> account.id },
|
||||
) { account ->
|
||||
AccountListItem(
|
||||
account = account,
|
||||
onClick = { onAccountClick(account) },
|
||||
selected = selectedAccount == account,
|
||||
)
|
||||
}
|
||||
}
|
||||
Column(
|
||||
modifier = Modifier.padding(vertical = MainTheme.spacings.oneHalf),
|
||||
) {
|
||||
SettingItem(
|
||||
icon = Icons.Outlined.Sync,
|
||||
label = stringResource(id = R.string.navigation_drawer_siderail_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_siderail_action_settings),
|
||||
onClick = onSettingsClick,
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,30 @@
|
|||
package net.thunderbird.feature.navigation.drawer.siderail.ui.account
|
||||
|
||||
import androidx.compose.foundation.layout.Box
|
||||
import androidx.compose.foundation.layout.padding
|
||||
import androidx.compose.foundation.layout.width
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.ui.Alignment
|
||||
import androidx.compose.ui.Modifier
|
||||
import app.k9mail.core.ui.compose.theme2.MainTheme
|
||||
import net.thunderbird.feature.navigation.drawer.siderail.domain.entity.DisplayAccount
|
||||
|
||||
@Composable
|
||||
internal fun AccountListItem(
|
||||
account: DisplayAccount,
|
||||
onClick: (DisplayAccount) -> Unit,
|
||||
selected: Boolean,
|
||||
modifier: Modifier = Modifier,
|
||||
) {
|
||||
Box(
|
||||
modifier = modifier.width(MainTheme.sizes.large)
|
||||
.padding(vertical = MainTheme.spacings.half),
|
||||
contentAlignment = Alignment.Center,
|
||||
) {
|
||||
AccountAvatar(
|
||||
account = account,
|
||||
onClick = onClick,
|
||||
selected = selected,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,108 @@
|
|||
package net.thunderbird.feature.navigation.drawer.siderail.ui.account
|
||||
|
||||
import androidx.compose.animation.AnimatedVisibility
|
||||
import androidx.compose.foundation.clickable
|
||||
import androidx.compose.foundation.layout.Arrangement
|
||||
import androidx.compose.foundation.layout.Box
|
||||
import androidx.compose.foundation.layout.Column
|
||||
import androidx.compose.foundation.layout.IntrinsicSize
|
||||
import androidx.compose.foundation.layout.Row
|
||||
import androidx.compose.foundation.layout.WindowInsets
|
||||
import androidx.compose.foundation.layout.WindowInsetsSides
|
||||
import androidx.compose.foundation.layout.defaultMinSize
|
||||
import androidx.compose.foundation.layout.displayCutout
|
||||
import androidx.compose.foundation.layout.fillMaxHeight
|
||||
import androidx.compose.foundation.layout.fillMaxWidth
|
||||
import androidx.compose.foundation.layout.height
|
||||
import androidx.compose.foundation.layout.only
|
||||
import androidx.compose.foundation.layout.padding
|
||||
import androidx.compose.foundation.layout.width
|
||||
import androidx.compose.foundation.layout.windowInsetsPadding
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.ui.Alignment
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.platform.LocalLayoutDirection
|
||||
import androidx.compose.ui.unit.LayoutDirection
|
||||
import app.k9mail.core.ui.compose.designsystem.atom.Surface
|
||||
import app.k9mail.core.ui.compose.designsystem.atom.text.TextBodyLarge
|
||||
import app.k9mail.core.ui.compose.designsystem.atom.text.TextBodyMedium
|
||||
import app.k9mail.core.ui.compose.theme2.MainTheme
|
||||
import net.thunderbird.feature.navigation.drawer.siderail.domain.entity.DisplayAccount
|
||||
|
||||
@Suppress("LongMethod")
|
||||
@Composable
|
||||
internal fun AccountView(
|
||||
account: DisplayAccount,
|
||||
onClick: () -> Unit,
|
||||
showAvatar: Boolean,
|
||||
modifier: Modifier = Modifier,
|
||||
) {
|
||||
Row(
|
||||
modifier = Modifier.fillMaxWidth()
|
||||
.height(intrinsicSize = IntrinsicSize.Max),
|
||||
verticalAlignment = Alignment.CenterVertically,
|
||||
) {
|
||||
AnimatedVisibility(visible = showAvatar) {
|
||||
Surface(
|
||||
color = MainTheme.colors.surfaceContainer,
|
||||
modifier = Modifier.fillMaxHeight(),
|
||||
) {
|
||||
val horizontalInsetPadding = getDisplayCutOutHorizontalInsetPadding()
|
||||
|
||||
Box(
|
||||
modifier = Modifier
|
||||
.windowInsetsPadding(horizontalInsetPadding)
|
||||
.width(MainTheme.sizes.large),
|
||||
contentAlignment = Alignment.Center,
|
||||
) {
|
||||
AccountAvatar(
|
||||
account = account,
|
||||
onClick = null,
|
||||
selected = false,
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
Row(
|
||||
modifier = modifier
|
||||
.clickable(onClick = onClick)
|
||||
.height(intrinsicSize = IntrinsicSize.Max)
|
||||
.fillMaxWidth()
|
||||
.defaultMinSize(minHeight = MainTheme.sizes.large)
|
||||
.padding(
|
||||
top = MainTheme.spacings.double,
|
||||
start = MainTheme.spacings.double,
|
||||
end = MainTheme.spacings.triple,
|
||||
bottom = MainTheme.spacings.double,
|
||||
),
|
||||
verticalAlignment = Alignment.CenterVertically,
|
||||
) {
|
||||
AccountIndicator(
|
||||
accountColor = account.color,
|
||||
modifier = Modifier
|
||||
.fillMaxHeight()
|
||||
.padding(end = MainTheme.spacings.oneHalf),
|
||||
)
|
||||
Column(
|
||||
verticalArrangement = Arrangement.spacedBy(MainTheme.spacings.half),
|
||||
) {
|
||||
TextBodyLarge(
|
||||
text = account.name,
|
||||
color = MainTheme.colors.onSurface,
|
||||
)
|
||||
if (account.name != account.email) {
|
||||
TextBodyMedium(
|
||||
text = account.email,
|
||||
color = MainTheme.colors.onSurfaceVariant,
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
fun getDisplayCutOutHorizontalInsetPadding(): WindowInsets {
|
||||
val isRtl = LocalLayoutDirection.current == LayoutDirection.Rtl
|
||||
return WindowInsets.displayCutout.only(if (isRtl) WindowInsetsSides.Right else WindowInsetsSides.Left)
|
||||
}
|
||||
|
|
@ -0,0 +1,15 @@
|
|||
package net.thunderbird.feature.navigation.drawer.siderail.ui.account
|
||||
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.ui.graphics.Color
|
||||
import app.k9mail.core.ui.compose.theme2.MainTheme
|
||||
import app.k9mail.core.ui.compose.theme2.toHarmonizedColor
|
||||
|
||||
@Composable
|
||||
internal fun calculateAccountColor(accountColor: Int): Color {
|
||||
return if (accountColor == 0) {
|
||||
MainTheme.colors.primary
|
||||
} else {
|
||||
Color(accountColor).toHarmonizedColor(MainTheme.colors.surface)
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,22 @@
|
|||
package net.thunderbird.feature.navigation.drawer.siderail.ui.common
|
||||
|
||||
import android.content.res.Resources
|
||||
import net.thunderbird.feature.navigation.drawer.siderail.R
|
||||
|
||||
@Suppress("MagicNumber")
|
||||
internal fun labelForCount(
|
||||
count: Int,
|
||||
resources: Resources,
|
||||
) = when {
|
||||
count in 1..99 -> "$count"
|
||||
|
||||
count in 100..1000 -> resources.getString(
|
||||
R.string.navigation_drawer_siderail_folder_item_badge_count_greater_than_99,
|
||||
)
|
||||
|
||||
count > 1000 -> resources.getString(
|
||||
R.string.navigation_drawer_siderail_folder_item_badge_count_greater_than_1_000,
|
||||
)
|
||||
|
||||
else -> ""
|
||||
}
|
||||
|
|
@ -0,0 +1,61 @@
|
|||
package net.thunderbird.feature.navigation.drawer.siderail.ui.folder
|
||||
|
||||
import androidx.compose.foundation.layout.PaddingValues
|
||||
import androidx.compose.foundation.layout.fillMaxWidth
|
||||
import androidx.compose.foundation.layout.padding
|
||||
import androidx.compose.foundation.lazy.LazyColumn
|
||||
import androidx.compose.foundation.lazy.items
|
||||
import androidx.compose.foundation.lazy.rememberLazyListState
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.remember
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.platform.LocalContext
|
||||
import app.k9mail.core.ui.compose.designsystem.atom.DividerHorizontal
|
||||
import app.k9mail.core.ui.compose.theme2.MainTheme
|
||||
import app.k9mail.legacy.ui.folder.FolderNameFormatter
|
||||
import kotlinx.collections.immutable.ImmutableList
|
||||
import net.thunderbird.feature.navigation.drawer.siderail.domain.entity.DisplayFolder
|
||||
import net.thunderbird.feature.navigation.drawer.siderail.domain.entity.DisplayUnifiedFolder
|
||||
|
||||
@Composable
|
||||
internal fun FolderList(
|
||||
folders: ImmutableList<DisplayFolder>,
|
||||
selectedFolder: DisplayFolder?,
|
||||
onFolderClick: (DisplayFolder) -> Unit,
|
||||
showStarredCount: Boolean,
|
||||
modifier: Modifier = Modifier,
|
||||
) {
|
||||
val resources = LocalContext.current.resources
|
||||
val folderNameFormatter = remember { FolderNameFormatter(resources) }
|
||||
val listState = rememberLazyListState()
|
||||
|
||||
LazyColumn(
|
||||
state = listState,
|
||||
modifier = modifier
|
||||
.fillMaxWidth(),
|
||||
contentPadding = PaddingValues(vertical = MainTheme.spacings.default),
|
||||
) {
|
||||
items(
|
||||
items = folders,
|
||||
key = { it.id },
|
||||
) { folder ->
|
||||
FolderListItem(
|
||||
displayFolder = folder,
|
||||
selected = folder == selectedFolder,
|
||||
showStarredCount = showStarredCount,
|
||||
onClick = onFolderClick,
|
||||
folderNameFormatter = folderNameFormatter,
|
||||
)
|
||||
if (folder is DisplayUnifiedFolder) {
|
||||
DividerHorizontal(
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.padding(
|
||||
vertical = MainTheme.spacings.default,
|
||||
horizontal = MainTheme.spacings.triple,
|
||||
),
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,91 @@
|
|||
package net.thunderbird.feature.navigation.drawer.siderail.ui.folder
|
||||
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.graphics.vector.ImageVector
|
||||
import androidx.compose.ui.res.stringResource
|
||||
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.designsystem.organism.drawer.NavigationDrawerItem
|
||||
import app.k9mail.legacy.ui.folder.FolderNameFormatter
|
||||
import net.thunderbird.feature.mail.folder.api.FolderType
|
||||
import net.thunderbird.feature.navigation.drawer.siderail.R
|
||||
import net.thunderbird.feature.navigation.drawer.siderail.domain.entity.DisplayAccountFolder
|
||||
import net.thunderbird.feature.navigation.drawer.siderail.domain.entity.DisplayFolder
|
||||
import net.thunderbird.feature.navigation.drawer.siderail.domain.entity.DisplayUnifiedFolder
|
||||
import net.thunderbird.feature.navigation.drawer.siderail.domain.entity.DisplayUnifiedFolderType
|
||||
|
||||
@Composable
|
||||
internal fun FolderListItem(
|
||||
displayFolder: DisplayFolder,
|
||||
selected: Boolean,
|
||||
onClick: (DisplayFolder) -> Unit,
|
||||
showStarredCount: Boolean,
|
||||
folderNameFormatter: FolderNameFormatter,
|
||||
modifier: Modifier = Modifier,
|
||||
) {
|
||||
NavigationDrawerItem(
|
||||
label = mapFolderName(displayFolder, folderNameFormatter),
|
||||
selected = selected,
|
||||
onClick = { onClick(displayFolder) },
|
||||
modifier = modifier,
|
||||
icon = {
|
||||
Icon(
|
||||
imageVector = mapFolderIcon(displayFolder),
|
||||
)
|
||||
},
|
||||
badge = {
|
||||
FolderListItemBadge(
|
||||
unreadCount = displayFolder.unreadMessageCount,
|
||||
starredCount = displayFolder.starredMessageCount,
|
||||
showStarredCount = showStarredCount,
|
||||
)
|
||||
},
|
||||
)
|
||||
}
|
||||
|
||||
@Composable
|
||||
private fun mapFolderName(
|
||||
displayFolder: DisplayFolder,
|
||||
folderNameFormatter: FolderNameFormatter,
|
||||
): String {
|
||||
return when (displayFolder) {
|
||||
is DisplayAccountFolder -> folderNameFormatter.displayName(displayFolder.folder)
|
||||
is DisplayUnifiedFolder -> mapUnifiedFolderName(displayFolder)
|
||||
else -> throw IllegalArgumentException("Unknown display folder: $displayFolder")
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
private fun mapUnifiedFolderName(folder: DisplayUnifiedFolder): String {
|
||||
return when (folder.unifiedType) {
|
||||
DisplayUnifiedFolderType.INBOX -> stringResource(R.string.navigation_drawer_siderail_unified_inbox_title)
|
||||
}
|
||||
}
|
||||
|
||||
private fun mapFolderIcon(folder: DisplayFolder): ImageVector {
|
||||
return when (folder) {
|
||||
is DisplayAccountFolder -> mapDisplayAccountFolderIcon(folder)
|
||||
is DisplayUnifiedFolder -> mapDisplayUnifiedFolderIcon(folder)
|
||||
else -> throw IllegalArgumentException("Unknown display folder type: $folder")
|
||||
}
|
||||
}
|
||||
|
||||
private fun mapDisplayAccountFolderIcon(folder: DisplayAccountFolder): ImageVector {
|
||||
return when (folder.folder.type) {
|
||||
FolderType.INBOX -> Icons.Outlined.Inbox
|
||||
FolderType.OUTBOX -> Icons.Outlined.Outbox
|
||||
FolderType.SENT -> Icons.Outlined.Send
|
||||
FolderType.TRASH -> Icons.Outlined.Delete
|
||||
FolderType.DRAFTS -> Icons.Outlined.Drafts
|
||||
FolderType.ARCHIVE -> Icons.Outlined.Archive
|
||||
FolderType.SPAM -> Icons.Outlined.Report
|
||||
FolderType.REGULAR -> Icons.Outlined.Folder
|
||||
}
|
||||
}
|
||||
|
||||
private fun mapDisplayUnifiedFolderIcon(folder: DisplayUnifiedFolder): ImageVector {
|
||||
when (folder.unifiedType) {
|
||||
DisplayUnifiedFolderType.INBOX -> return Icons.Outlined.AllInbox
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,89 @@
|
|||
package net.thunderbird.feature.navigation.drawer.siderail.ui.folder
|
||||
|
||||
import androidx.compose.foundation.layout.Arrangement
|
||||
import androidx.compose.foundation.layout.Row
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.ui.Alignment
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.platform.LocalContext
|
||||
import app.k9mail.core.ui.compose.designsystem.atom.icon.Icons
|
||||
import app.k9mail.core.ui.compose.designsystem.organism.drawer.NavigationDrawerItemBadge
|
||||
import app.k9mail.core.ui.compose.theme2.MainTheme
|
||||
import net.thunderbird.core.ui.compose.designsystem.atom.icon.filled.Star
|
||||
import net.thunderbird.feature.navigation.drawer.siderail.ui.common.labelForCount
|
||||
|
||||
@Composable
|
||||
internal fun FolderListItemBadge(
|
||||
unreadCount: Int,
|
||||
starredCount: Int,
|
||||
showStarredCount: Boolean,
|
||||
modifier: Modifier = Modifier,
|
||||
) {
|
||||
if (showStarredCount) {
|
||||
FolderCountAndStarredBadge(
|
||||
unreadCount = unreadCount,
|
||||
starredCount = starredCount,
|
||||
modifier = modifier,
|
||||
)
|
||||
} else {
|
||||
FolderCountBadge(
|
||||
unreadCount = unreadCount,
|
||||
modifier = modifier,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
private fun FolderCountBadge(
|
||||
unreadCount: Int,
|
||||
modifier: Modifier = Modifier,
|
||||
) {
|
||||
if (unreadCount > 0) {
|
||||
val resources = LocalContext.current.resources
|
||||
|
||||
NavigationDrawerItemBadge(
|
||||
label = labelForCount(
|
||||
count = unreadCount,
|
||||
resources = resources,
|
||||
),
|
||||
modifier = modifier,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
private fun FolderCountAndStarredBadge(
|
||||
unreadCount: Int,
|
||||
starredCount: Int,
|
||||
modifier: Modifier = Modifier,
|
||||
) {
|
||||
if (unreadCount > 0 || starredCount > 0) {
|
||||
Row(
|
||||
modifier = modifier,
|
||||
verticalAlignment = Alignment.CenterVertically,
|
||||
horizontalArrangement = Arrangement.spacedBy(MainTheme.spacings.default),
|
||||
) {
|
||||
val resources = LocalContext.current.resources
|
||||
|
||||
if (unreadCount > 0) {
|
||||
NavigationDrawerItemBadge(
|
||||
label = labelForCount(
|
||||
count = unreadCount,
|
||||
resources = resources,
|
||||
),
|
||||
imageVector = Icons.Filled.Dot,
|
||||
)
|
||||
}
|
||||
|
||||
if (starredCount > 0) {
|
||||
NavigationDrawerItemBadge(
|
||||
label = labelForCount(
|
||||
count = starredCount,
|
||||
resources = resources,
|
||||
),
|
||||
imageVector = Icons.Filled.Star,
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,40 @@
|
|||
package net.thunderbird.feature.navigation.drawer.siderail.ui.setting
|
||||
|
||||
import androidx.compose.foundation.clickable
|
||||
import androidx.compose.foundation.layout.Box
|
||||
import androidx.compose.foundation.layout.padding
|
||||
import androidx.compose.foundation.layout.width
|
||||
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.theme2.MainTheme
|
||||
|
||||
@Composable
|
||||
internal fun SettingItem(
|
||||
icon: ImageVector,
|
||||
label: String,
|
||||
onClick: () -> Unit,
|
||||
modifier: Modifier = Modifier,
|
||||
) {
|
||||
Box(
|
||||
modifier = modifier.width(MainTheme.sizes.large),
|
||||
contentAlignment = Alignment.Center,
|
||||
) {
|
||||
Surface(
|
||||
color = MainTheme.colors.surfaceContainer,
|
||||
shape = CircleShape,
|
||||
) {
|
||||
Icon(
|
||||
imageVector = icon,
|
||||
contentDescription = label,
|
||||
modifier = Modifier
|
||||
.clickable(onClick = onClick)
|
||||
.padding(MainTheme.spacings.oneHalf),
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,48 @@
|
|||
package net.thunderbird.feature.navigation.drawer.siderail.ui.setting
|
||||
|
||||
import androidx.compose.foundation.layout.Column
|
||||
import androidx.compose.foundation.layout.WindowInsets
|
||||
import androidx.compose.foundation.layout.fillMaxWidth
|
||||
import androidx.compose.foundation.layout.navigationBars
|
||||
import androidx.compose.foundation.layout.padding
|
||||
import androidx.compose.foundation.layout.windowInsetsPadding
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.res.stringResource
|
||||
import app.k9mail.core.ui.compose.designsystem.atom.icon.Icons
|
||||
import app.k9mail.core.ui.compose.theme2.MainTheme
|
||||
import net.thunderbird.feature.navigation.drawer.siderail.R
|
||||
|
||||
@Composable
|
||||
internal fun SettingList(
|
||||
onAccountSelectorClick: () -> Unit,
|
||||
onManageFoldersClick: () -> Unit,
|
||||
showAccountSelector: Boolean,
|
||||
modifier: Modifier = Modifier,
|
||||
) {
|
||||
Column(
|
||||
modifier = modifier
|
||||
.padding(vertical = MainTheme.spacings.default)
|
||||
.windowInsetsPadding(WindowInsets.navigationBars)
|
||||
.fillMaxWidth(),
|
||||
) {
|
||||
SettingListItem(
|
||||
label = stringResource(R.string.navigation_drawer_siderail_action_manage_folders),
|
||||
onClick = onManageFoldersClick,
|
||||
imageVector = Icons.Outlined.FolderManaged,
|
||||
)
|
||||
SettingListItem(
|
||||
label = if (showAccountSelector) {
|
||||
stringResource(R.string.navigation_drawer_siderail_action_hide_accounts)
|
||||
} else {
|
||||
stringResource(R.string.navigation_drawer_siderail_action_show_accounts)
|
||||
},
|
||||
onClick = onAccountSelectorClick,
|
||||
imageVector = if (showAccountSelector) {
|
||||
Icons.Outlined.ChevronLeft
|
||||
} else {
|
||||
Icons.Outlined.ChevronRight
|
||||
},
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,27 @@
|
|||
package net.thunderbird.feature.navigation.drawer.siderail.ui.setting
|
||||
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.graphics.vector.ImageVector
|
||||
import app.k9mail.core.ui.compose.designsystem.atom.icon.Icon
|
||||
import app.k9mail.core.ui.compose.designsystem.organism.drawer.NavigationDrawerItem
|
||||
|
||||
@Composable
|
||||
internal fun SettingListItem(
|
||||
label: String,
|
||||
onClick: () -> Unit,
|
||||
imageVector: ImageVector,
|
||||
modifier: Modifier = Modifier,
|
||||
) {
|
||||
NavigationDrawerItem(
|
||||
label = label,
|
||||
onClick = onClick,
|
||||
modifier = modifier,
|
||||
selected = false,
|
||||
icon = {
|
||||
Icon(
|
||||
imageVector = imageVector,
|
||||
)
|
||||
},
|
||||
)
|
||||
}
|
||||
|
|
@ -0,0 +1,2 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources></resources>
|
||||
|
|
@ -0,0 +1,11 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
|
||||
<string name="navigation_drawer_siderail_action_settings">الإعدادات</string>
|
||||
<string name="navigation_drawer_siderail_action_manage_folders">إدارة المجلدات</string>
|
||||
<string name="navigation_drawer_siderail_unified_inbox_title">البريد الوارد الموحَّد</string>
|
||||
<string name="navigation_drawer_siderail_action_hide_accounts">إخفاء الحسابات</string>
|
||||
<string name="navigation_drawer_siderail_action_show_accounts">إظهار الحسابات</string>
|
||||
<string name="navigation_drawer_siderail_folder_item_badge_count_greater_than_99">99+</string>
|
||||
<string name="navigation_drawer_siderail_folder_item_badge_count_greater_than_1_000">1k+</string>
|
||||
<string name="navigation_drawer_siderail_action_sync_all_accounts">مزامنة جميع الحسابات</string>
|
||||
</resources>
|
||||
|
|
@ -0,0 +1,2 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources></resources>
|
||||
|
|
@ -0,0 +1,2 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources></resources>
|
||||
|
|
@ -0,0 +1,11 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
|
||||
<string name="navigation_drawer_siderail_action_settings">Налады</string>
|
||||
<string name="navigation_drawer_siderail_action_manage_folders">Кіраванне каталогамі</string>
|
||||
<string name="navigation_drawer_siderail_unified_inbox_title">Усе атрыманыя</string>
|
||||
<string name="navigation_drawer_siderail_action_sync_all_accounts">Сінхранізаваць усе акаўнты</string>
|
||||
<string name="navigation_drawer_siderail_action_show_accounts">Паказаць акаўнты</string>
|
||||
<string name="navigation_drawer_siderail_action_hide_accounts">Схаваць акаўнты</string>
|
||||
<string name="navigation_drawer_siderail_folder_item_badge_count_greater_than_99">99+</string>
|
||||
<string name="navigation_drawer_siderail_folder_item_badge_count_greater_than_1_000">1000+</string>
|
||||
</resources>
|
||||
|
|
@ -0,0 +1,11 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
|
||||
<string name="navigation_drawer_siderail_action_settings">Настройки</string>
|
||||
<string name="navigation_drawer_siderail_action_manage_folders">Управление на папки</string>
|
||||
<string name="navigation_drawer_siderail_unified_inbox_title">Обща входяща кутия</string>
|
||||
<string name="navigation_drawer_siderail_action_sync_all_accounts">Синхронизация на всички профили</string>
|
||||
<string name="navigation_drawer_siderail_action_show_accounts">Показване на профилите</string>
|
||||
<string name="navigation_drawer_siderail_action_hide_accounts">Скриване на профилите</string>
|
||||
<string name="navigation_drawer_siderail_folder_item_badge_count_greater_than_99">над 99</string>
|
||||
<string name="navigation_drawer_siderail_folder_item_badge_count_greater_than_1_000">над 1000</string>
|
||||
</resources>
|
||||
|
|
@ -0,0 +1,2 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources></resources>
|
||||
|
|
@ -0,0 +1,6 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
|
||||
<string name="navigation_drawer_siderail_action_settings">Arventennoù</string>
|
||||
<string name="navigation_drawer_siderail_action_manage_folders">Merañ an teuliadoù</string>
|
||||
<string name="navigation_drawer_siderail_unified_inbox_title">Boest degemer unanet</string>
|
||||
</resources>
|
||||
|
|
@ -0,0 +1,5 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
|
||||
<string name="navigation_drawer_siderail_action_settings">Postavke</string>
|
||||
<string name="navigation_drawer_siderail_action_manage_folders">Upravljajte direktorijumima</string>
|
||||
</resources>
|
||||
|
|
@ -0,0 +1,11 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
|
||||
<string name="navigation_drawer_siderail_action_settings">Configuració</string>
|
||||
<string name="navigation_drawer_siderail_action_manage_folders">Gestioneu les carpetes</string>
|
||||
<string name="navigation_drawer_siderail_unified_inbox_title">Bústia d\'entrada unificada</string>
|
||||
<string name="navigation_drawer_siderail_action_sync_all_accounts">Sincronitza tots els comptes</string>
|
||||
<string name="navigation_drawer_siderail_action_show_accounts">Mostra els comptes</string>
|
||||
<string name="navigation_drawer_siderail_action_hide_accounts">Amaga els comptes</string>
|
||||
<string name="navigation_drawer_siderail_folder_item_badge_count_greater_than_99">99+</string>
|
||||
<string name="navigation_drawer_siderail_folder_item_badge_count_greater_than_1_000">1000+</string>
|
||||
</resources>
|
||||
|
|
@ -0,0 +1,11 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
|
||||
<string name="navigation_drawer_siderail_action_settings">Parametri</string>
|
||||
<string name="navigation_drawer_siderail_action_manage_folders">Ghjestione di i cartulari</string>
|
||||
<string name="navigation_drawer_siderail_unified_inbox_title">Ricezzione cuncolta</string>
|
||||
<string name="navigation_drawer_siderail_action_sync_all_accounts">Sincrunizà tutti i conti</string>
|
||||
<string name="navigation_drawer_siderail_action_show_accounts">Affissà i conti</string>
|
||||
<string name="navigation_drawer_siderail_folder_item_badge_count_greater_than_99">> 99</string>
|
||||
<string name="navigation_drawer_siderail_action_hide_accounts">Piattà i conti</string>
|
||||
<string name="navigation_drawer_siderail_folder_item_badge_count_greater_than_1_000">> 1000</string>
|
||||
</resources>
|
||||
|
|
@ -0,0 +1,11 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
|
||||
<string name="navigation_drawer_siderail_action_settings">Nastavení</string>
|
||||
<string name="navigation_drawer_siderail_action_manage_folders">Správa složek</string>
|
||||
<string name="navigation_drawer_siderail_unified_inbox_title">Jednotná schránka</string>
|
||||
<string name="navigation_drawer_siderail_folder_item_badge_count_greater_than_99">99+</string>
|
||||
<string name="navigation_drawer_siderail_folder_item_badge_count_greater_than_1_000">1 tis.+</string>
|
||||
<string name="navigation_drawer_siderail_action_show_accounts">Zobrazit účty</string>
|
||||
<string name="navigation_drawer_siderail_action_sync_all_accounts">Synchronizovat všechny účty</string>
|
||||
<string name="navigation_drawer_siderail_action_hide_accounts">Skrýt účty</string>
|
||||
</resources>
|
||||
|
|
@ -0,0 +1,11 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
|
||||
<string name="navigation_drawer_siderail_action_settings">Gosodiadau</string>
|
||||
<string name="navigation_drawer_siderail_action_manage_folders">Rheoli ffolderi</string>
|
||||
<string name="navigation_drawer_siderail_unified_inbox_title">Mewnflwch Unedig</string>
|
||||
<string name="navigation_drawer_siderail_action_sync_all_accounts">Cydweddu pob cyfrif</string>
|
||||
<string name="navigation_drawer_siderail_action_show_accounts">Dangos cyfrifon</string>
|
||||
<string name="navigation_drawer_siderail_action_hide_accounts">Cuddio cyfrifon</string>
|
||||
<string name="navigation_drawer_siderail_folder_item_badge_count_greater_than_99">99+</string>
|
||||
<string name="navigation_drawer_siderail_folder_item_badge_count_greater_than_1_000">1k+</string>
|
||||
</resources>
|
||||
|
|
@ -0,0 +1,6 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
|
||||
<string name="navigation_drawer_siderail_action_settings">Indstillinger</string>
|
||||
<string name="navigation_drawer_siderail_action_manage_folders">Håndtér mapper</string>
|
||||
<string name="navigation_drawer_siderail_unified_inbox_title">Fælles indbakke</string>
|
||||
</resources>
|
||||
|
|
@ -0,0 +1,11 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
|
||||
<string name="navigation_drawer_siderail_action_settings">Einstellungen</string>
|
||||
<string name="navigation_drawer_siderail_action_manage_folders">Ordner verwalten</string>
|
||||
<string name="navigation_drawer_siderail_unified_inbox_title">Gemeinsamer Posteingang</string>
|
||||
<string name="navigation_drawer_siderail_folder_item_badge_count_greater_than_1_000">1k+</string>
|
||||
<string name="navigation_drawer_siderail_folder_item_badge_count_greater_than_99">99+</string>
|
||||
<string name="navigation_drawer_siderail_action_hide_accounts">Konten ausblenden</string>
|
||||
<string name="navigation_drawer_siderail_action_sync_all_accounts">Alle Konten synchronisieren</string>
|
||||
<string name="navigation_drawer_siderail_action_show_accounts">Konten anzeigen</string>
|
||||
</resources>
|
||||
|
|
@ -0,0 +1,11 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
|
||||
<string name="navigation_drawer_siderail_action_settings">Ρυθμίσεις</string>
|
||||
<string name="navigation_drawer_siderail_action_manage_folders">Διαχείριση φακέλων</string>
|
||||
<string name="navigation_drawer_siderail_unified_inbox_title">Ενιαία Εισερχόμενα</string>
|
||||
<string name="navigation_drawer_siderail_folder_item_badge_count_greater_than_1_000">1χ+</string>
|
||||
<string name="navigation_drawer_siderail_folder_item_badge_count_greater_than_99">99+</string>
|
||||
<string name="navigation_drawer_siderail_action_sync_all_accounts">Συγχρονισμός όλων των λογαριασμών</string>
|
||||
<string name="navigation_drawer_siderail_action_show_accounts">Εμφάνιση λογαριασμών</string>
|
||||
<string name="navigation_drawer_siderail_action_hide_accounts">Απόκρυψη λογαριασμών</string>
|
||||
</resources>
|
||||
|
|
@ -0,0 +1,6 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
|
||||
<string name="navigation_drawer_siderail_action_settings">Settings</string>
|
||||
<string name="navigation_drawer_siderail_action_manage_folders">Manage folders</string>
|
||||
<string name="navigation_drawer_siderail_unified_inbox_title">Unified Inbox</string>
|
||||
</resources>
|
||||
|
|
@ -0,0 +1,2 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources></resources>
|
||||
|
|
@ -0,0 +1,9 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
|
||||
<string name="navigation_drawer_siderail_action_settings">Agordoj</string>
|
||||
<string name="navigation_drawer_siderail_action_manage_folders">Administri mesaĝujojn</string>
|
||||
<string name="navigation_drawer_siderail_unified_inbox_title">Unuigita ricevujo</string>
|
||||
<string name="navigation_drawer_siderail_action_show_accounts">Montri kontojn</string>
|
||||
<string name="navigation_drawer_siderail_action_sync_all_accounts">Samtempigi ĉiujn kontojn</string>
|
||||
<string name="navigation_drawer_siderail_action_hide_accounts">Kaŝi kontojn</string>
|
||||
</resources>
|
||||
|
|
@ -0,0 +1,11 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
|
||||
<string name="navigation_drawer_siderail_action_settings">Ajustes</string>
|
||||
<string name="navigation_drawer_siderail_action_manage_folders">Administrar carpetas</string>
|
||||
<string name="navigation_drawer_siderail_unified_inbox_title">Entrada unificada</string>
|
||||
<string name="navigation_drawer_siderail_folder_item_badge_count_greater_than_99">>99</string>
|
||||
<string name="navigation_drawer_siderail_folder_item_badge_count_greater_than_1_000">>1000</string>
|
||||
<string name="navigation_drawer_siderail_action_sync_all_accounts">Sincronizar todas las cuentas</string>
|
||||
<string name="navigation_drawer_siderail_action_show_accounts">Mostrar cuentas</string>
|
||||
<string name="navigation_drawer_siderail_action_hide_accounts">Ocultar cuentas</string>
|
||||
</resources>
|
||||
|
|
@ -0,0 +1,11 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
|
||||
<string name="navigation_drawer_siderail_action_settings">Seadistused</string>
|
||||
<string name="navigation_drawer_siderail_action_manage_folders">Halda kaustu</string>
|
||||
<string name="navigation_drawer_siderail_unified_inbox_title">Koondsisendkaust</string>
|
||||
<string name="navigation_drawer_siderail_action_sync_all_accounts">Sünkroniseeri kõik kontod</string>
|
||||
<string name="navigation_drawer_siderail_action_show_accounts">Näita kontosid</string>
|
||||
<string name="navigation_drawer_siderail_action_hide_accounts">Peida kontod</string>
|
||||
<string name="navigation_drawer_siderail_folder_item_badge_count_greater_than_1_000">1k+</string>
|
||||
<string name="navigation_drawer_siderail_folder_item_badge_count_greater_than_99">99+</string>
|
||||
</resources>
|
||||
|
|
@ -0,0 +1,11 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
|
||||
<string name="navigation_drawer_siderail_action_settings">Ezarpenak</string>
|
||||
<string name="navigation_drawer_siderail_action_manage_folders">Kudeatu karpetak</string>
|
||||
<string name="navigation_drawer_siderail_unified_inbox_title">Sarrerako ontzi bateratua</string>
|
||||
<string name="navigation_drawer_siderail_action_sync_all_accounts">Sinkronizatu kontu guztiak</string>
|
||||
<string name="navigation_drawer_siderail_action_show_accounts">Erakutsi kontuak</string>
|
||||
<string name="navigation_drawer_siderail_action_hide_accounts">Ezkutatu kontuak</string>
|
||||
<string name="navigation_drawer_siderail_folder_item_badge_count_greater_than_1_000">1.000+</string>
|
||||
<string name="navigation_drawer_siderail_folder_item_badge_count_greater_than_99">99+</string>
|
||||
</resources>
|
||||
|
|
@ -0,0 +1,11 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
|
||||
<string name="navigation_drawer_siderail_action_settings">تنظیمات</string>
|
||||
<string name="navigation_drawer_siderail_action_manage_folders">مدیریت پوشهها</string>
|
||||
<string name="navigation_drawer_siderail_unified_inbox_title">صندوق ورودی یکپارچه</string>
|
||||
<string name="navigation_drawer_siderail_action_hide_accounts">نهفتن حسابها</string>
|
||||
<string name="navigation_drawer_siderail_action_sync_all_accounts">همگام سازی همهٔ آشنایان</string>
|
||||
<string name="navigation_drawer_siderail_action_show_accounts">نمایش حسابها</string>
|
||||
<string name="navigation_drawer_siderail_folder_item_badge_count_greater_than_99">۹۹+</string>
|
||||
<string name="navigation_drawer_siderail_folder_item_badge_count_greater_than_1_000">ه+</string>
|
||||
</resources>
|
||||
|
|
@ -0,0 +1,11 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
|
||||
<string name="navigation_drawer_siderail_action_settings">Asetukset</string>
|
||||
<string name="navigation_drawer_siderail_action_manage_folders">Hallitse kansioita</string>
|
||||
<string name="navigation_drawer_siderail_unified_inbox_title">Yhdistetty saapuneet</string>
|
||||
<string name="navigation_drawer_siderail_action_sync_all_accounts">Synkronoi kaikki tilit</string>
|
||||
<string name="navigation_drawer_siderail_action_show_accounts">Näytä tilit</string>
|
||||
<string name="navigation_drawer_siderail_action_hide_accounts">Piilota tilit</string>
|
||||
<string name="navigation_drawer_siderail_folder_item_badge_count_greater_than_99">99+</string>
|
||||
<string name="navigation_drawer_siderail_folder_item_badge_count_greater_than_1_000">1k+</string>
|
||||
</resources>
|
||||
|
|
@ -0,0 +1,11 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
|
||||
<string name="navigation_drawer_siderail_action_settings">Paramètres</string>
|
||||
<string name="navigation_drawer_siderail_action_manage_folders">Gérer les dossiers</string>
|
||||
<string name="navigation_drawer_siderail_unified_inbox_title">Boîte de réception unifiée</string>
|
||||
<string name="navigation_drawer_siderail_action_hide_accounts">Cacher les comptes</string>
|
||||
<string name="navigation_drawer_siderail_folder_item_badge_count_greater_than_99">>99</string>
|
||||
<string name="navigation_drawer_siderail_folder_item_badge_count_greater_than_1_000">>1 k</string>
|
||||
<string name="navigation_drawer_siderail_action_show_accounts">Afficher les comptes</string>
|
||||
<string name="navigation_drawer_siderail_action_sync_all_accounts">Synchroniser tous les comptes</string>
|
||||
</resources>
|
||||
|
|
@ -0,0 +1,11 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
|
||||
<string name="navigation_drawer_siderail_action_settings">Ynstellingen</string>
|
||||
<string name="navigation_drawer_siderail_action_manage_folders">Mappen beheare</string>
|
||||
<string name="navigation_drawer_siderail_unified_inbox_title">Kombinearre Postfek YN</string>
|
||||
<string name="navigation_drawer_siderail_folder_item_badge_count_greater_than_99">99+</string>
|
||||
<string name="navigation_drawer_siderail_folder_item_badge_count_greater_than_1_000">1k+</string>
|
||||
<string name="navigation_drawer_siderail_action_sync_all_accounts">Alle accounts syngronisearje</string>
|
||||
<string name="navigation_drawer_siderail_action_show_accounts">Accounts toane</string>
|
||||
<string name="navigation_drawer_siderail_action_hide_accounts">Accounts ferstopje</string>
|
||||
</resources>
|
||||
|
|
@ -0,0 +1,11 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources>
|
||||
<string name="navigation_drawer_siderail_action_settings">Socruithe</string>
|
||||
<string name="navigation_drawer_siderail_action_manage_folders">Bainistigh fillteáin</string>
|
||||
<string name="navigation_drawer_siderail_action_sync_all_accounts">Sioncronaigh gach cuntas</string>
|
||||
<string name="navigation_drawer_siderail_folder_item_badge_count_greater_than_1_000">1k+</string>
|
||||
<string name="navigation_drawer_siderail_action_show_accounts">Taispeáin cuntais</string>
|
||||
<string name="navigation_drawer_siderail_action_hide_accounts">Folaigh cuntais</string>
|
||||
<string name="navigation_drawer_siderail_unified_inbox_title">Bosca Isteach Aontaithe</string>
|
||||
<string name="navigation_drawer_siderail_folder_item_badge_count_greater_than_99">99+</string>
|
||||
</resources>
|
||||
|
|
@ -0,0 +1,11 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
|
||||
<string name="navigation_drawer_siderail_action_settings">Roghainnean</string>
|
||||
<string name="navigation_drawer_siderail_action_manage_folders">Stiùirich na pasganan</string>
|
||||
<string name="navigation_drawer_siderail_unified_inbox_title">An t-oll-bhogsa</string>
|
||||
<string name="navigation_drawer_siderail_folder_item_badge_count_greater_than_99">Còrr is 99</string>
|
||||
<string name="navigation_drawer_siderail_folder_item_badge_count_greater_than_1_000">Còrr is 1k</string>
|
||||
<string name="navigation_drawer_siderail_action_sync_all_accounts">Sioncronaich a h-uile cunntas</string>
|
||||
<string name="navigation_drawer_siderail_action_show_accounts">Seall na cunntasan</string>
|
||||
<string name="navigation_drawer_siderail_action_hide_accounts">Falaich na cunntasan</string>
|
||||
</resources>
|
||||
|
|
@ -0,0 +1,6 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
|
||||
<string name="navigation_drawer_siderail_action_settings">Configuración</string>
|
||||
<string name="navigation_drawer_siderail_action_manage_folders">Xestionar cartafoles</string>
|
||||
<string name="navigation_drawer_siderail_unified_inbox_title">Entrada unificada</string>
|
||||
</resources>
|
||||
|
|
@ -0,0 +1,11 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources>
|
||||
<string name="navigation_drawer_siderail_action_settings">સૅટિંગ</string>
|
||||
<string name="navigation_drawer_siderail_action_manage_folders">ફોલ્ડર મેનેજ કરોં</string>
|
||||
<string name="navigation_drawer_siderail_action_sync_all_accounts">બધાં ખાતાઓ ને સિંક કરોં</string>
|
||||
<string name="navigation_drawer_siderail_folder_item_badge_count_greater_than_1_000">૧૦૦૦+</string>
|
||||
<string name="navigation_drawer_siderail_folder_item_badge_count_greater_than_99">૯૯+</string>
|
||||
<string name="navigation_drawer_siderail_action_show_accounts">ખાતાઓ દેખાડોં</string>
|
||||
<string name="navigation_drawer_siderail_action_hide_accounts">ખાતાઓ છુપાડોં</string>
|
||||
<string name="navigation_drawer_siderail_unified_inbox_title">એકીકૃત ઇનબોક્સ</string>
|
||||
</resources>
|
||||
|
|
@ -0,0 +1,5 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
|
||||
<string name="navigation_drawer_siderail_action_settings">सेटिंग</string>
|
||||
<string name="navigation_drawer_siderail_action_manage_folders">फोल्डर मैनेज करें</string>
|
||||
</resources>
|
||||
|
|
@ -0,0 +1,11 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
|
||||
<string name="navigation_drawer_siderail_action_settings">Podešenja</string>
|
||||
<string name="navigation_drawer_siderail_action_manage_folders">Upravljanje mapama</string>
|
||||
<string name="navigation_drawer_siderail_unified_inbox_title">Objedinjena dolazna pošta</string>
|
||||
<string name="navigation_drawer_siderail_action_sync_all_accounts">Sinkroniziraj sve račune</string>
|
||||
<string name="navigation_drawer_siderail_action_show_accounts">Prikaži račune</string>
|
||||
<string name="navigation_drawer_siderail_action_hide_accounts">Sakrij račune</string>
|
||||
<string name="navigation_drawer_siderail_folder_item_badge_count_greater_than_1_000">1k+</string>
|
||||
<string name="navigation_drawer_siderail_folder_item_badge_count_greater_than_99">99+</string>
|
||||
</resources>
|
||||
|
|
@ -0,0 +1,11 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
|
||||
<string name="navigation_drawer_siderail_action_settings">Beállítások</string>
|
||||
<string name="navigation_drawer_siderail_action_manage_folders">Mappák kezelése</string>
|
||||
<string name="navigation_drawer_siderail_unified_inbox_title">Egységes beérkezett üzenetek</string>
|
||||
<string name="navigation_drawer_siderail_action_sync_all_accounts">Összes fiók szinkronizálása</string>
|
||||
<string name="navigation_drawer_siderail_action_show_accounts">Fiókok megjelenítése</string>
|
||||
<string name="navigation_drawer_siderail_folder_item_badge_count_greater_than_99">99+</string>
|
||||
<string name="navigation_drawer_siderail_action_hide_accounts">Fiókok elrejtése</string>
|
||||
<string name="navigation_drawer_siderail_folder_item_badge_count_greater_than_1_000">1e+</string>
|
||||
</resources>
|
||||
|
|
@ -0,0 +1,4 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
|
||||
<string name="navigation_drawer_siderail_action_settings">Կարգաւորումներ</string>
|
||||
</resources>
|
||||
|
|
@ -0,0 +1,11 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
|
||||
<string name="navigation_drawer_siderail_action_settings">Pengaturan</string>
|
||||
<string name="navigation_drawer_siderail_action_manage_folders">Kelola folder</string>
|
||||
<string name="navigation_drawer_siderail_unified_inbox_title">Kotak Masuk Terpadu</string>
|
||||
<string name="navigation_drawer_siderail_folder_item_badge_count_greater_than_99">99+</string>
|
||||
<string name="navigation_drawer_siderail_folder_item_badge_count_greater_than_1_000">1rb+</string>
|
||||
<string name="navigation_drawer_siderail_action_sync_all_accounts">Sinkronkan semua akun</string>
|
||||
<string name="navigation_drawer_siderail_action_show_accounts">Tampilkan akun</string>
|
||||
<string name="navigation_drawer_siderail_action_hide_accounts">Sembunyikan akun</string>
|
||||
</resources>
|
||||
|
|
@ -0,0 +1,11 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
|
||||
<string name="navigation_drawer_siderail_action_settings">Stillingar</string>
|
||||
<string name="navigation_drawer_siderail_action_manage_folders">Sýsla með möppur</string>
|
||||
<string name="navigation_drawer_siderail_unified_inbox_title">Sameinað innhólf</string>
|
||||
<string name="navigation_drawer_siderail_folder_item_badge_count_greater_than_99">>99</string>
|
||||
<string name="navigation_drawer_siderail_folder_item_badge_count_greater_than_1_000">>1.000</string>
|
||||
<string name="navigation_drawer_siderail_action_sync_all_accounts">Samstilla alla reikninga</string>
|
||||
<string name="navigation_drawer_siderail_action_show_accounts">Sýna reikninga</string>
|
||||
<string name="navigation_drawer_siderail_action_hide_accounts">Fela reikninga</string>
|
||||
</resources>
|
||||
|
|
@ -0,0 +1,11 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
|
||||
<string name="navigation_drawer_siderail_action_settings">Impostazioni</string>
|
||||
<string name="navigation_drawer_siderail_action_manage_folders">Gestione cartelle</string>
|
||||
<string name="navigation_drawer_siderail_unified_inbox_title">Posta combinata</string>
|
||||
<string name="navigation_drawer_siderail_folder_item_badge_count_greater_than_1_000">1k+</string>
|
||||
<string name="navigation_drawer_siderail_folder_item_badge_count_greater_than_99">99+</string>
|
||||
<string name="navigation_drawer_siderail_action_hide_accounts">Nascondi gli account</string>
|
||||
<string name="navigation_drawer_siderail_action_sync_all_accounts">Sincronizza tutti gli account</string>
|
||||
<string name="navigation_drawer_siderail_action_show_accounts">Mostra gli account</string>
|
||||
</resources>
|
||||
|
|
@ -0,0 +1,11 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
|
||||
<string name="navigation_drawer_siderail_action_settings">הגדרות</string>
|
||||
<string name="navigation_drawer_siderail_action_manage_folders">נהל תיקיות</string>
|
||||
<string name="navigation_drawer_siderail_unified_inbox_title">תיבת דואר נכנס אחידה</string>
|
||||
<string name="navigation_drawer_siderail_action_sync_all_accounts">סנכרן את כל החשבונות</string>
|
||||
<string name="navigation_drawer_siderail_action_show_accounts">הצג חשבונות</string>
|
||||
<string name="navigation_drawer_siderail_action_hide_accounts">הסתר חשבונות</string>
|
||||
<string name="navigation_drawer_siderail_folder_item_badge_count_greater_than_99">99+</string>
|
||||
<string name="navigation_drawer_siderail_folder_item_badge_count_greater_than_1_000">1k+</string>
|
||||
</resources>
|
||||
|
|
@ -0,0 +1,11 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
|
||||
<string name="navigation_drawer_siderail_action_settings">設定</string>
|
||||
<string name="navigation_drawer_siderail_action_manage_folders">フォルダーを管理</string>
|
||||
<string name="navigation_drawer_siderail_unified_inbox_title">統合受信トレイ</string>
|
||||
<string name="navigation_drawer_siderail_action_show_accounts">アカウントを開く</string>
|
||||
<string name="navigation_drawer_siderail_action_sync_all_accounts">すべてのアカウントを同期</string>
|
||||
<string name="navigation_drawer_siderail_action_hide_accounts">アカウントを閉じる</string>
|
||||
<string name="navigation_drawer_siderail_folder_item_badge_count_greater_than_99">99+</string>
|
||||
<string name="navigation_drawer_siderail_folder_item_badge_count_greater_than_1_000">1000+</string>
|
||||
</resources>
|
||||
|
|
@ -0,0 +1,6 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
|
||||
<string name="navigation_drawer_siderail_action_settings">პარამეტრები</string>
|
||||
<string name="navigation_drawer_siderail_action_manage_folders">საკეცების მართვა</string>
|
||||
<string name="navigation_drawer_siderail_unified_inbox_title">გაერთიანებული შემავალი</string>
|
||||
</resources>
|
||||
|
|
@ -0,0 +1,8 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources>
|
||||
<string name="navigation_drawer_siderail_action_settings">Iɣewwaren</string>
|
||||
<string name="navigation_drawer_siderail_action_manage_folders">Sefrek ikaramen</string>
|
||||
<string name="navigation_drawer_siderail_action_sync_all_accounts">Mtawi meṛṛa imiḍanen</string>
|
||||
<string name="navigation_drawer_siderail_action_show_accounts">Sken imiḍanen</string>
|
||||
<string name="navigation_drawer_siderail_action_hide_accounts">Ffer imiḍanen</string>
|
||||
</resources>
|
||||
|
|
@ -0,0 +1,6 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources>
|
||||
<string name="navigation_drawer_siderail_action_settings">Баптаулар</string>
|
||||
<string name="navigation_drawer_siderail_action_show_accounts">Тіркелгілерді көрсету</string>
|
||||
<string name="navigation_drawer_siderail_folder_item_badge_count_greater_than_99">99+</string>
|
||||
</resources>
|
||||
|
|
@ -0,0 +1,6 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
|
||||
<string name="navigation_drawer_siderail_action_settings">설정</string>
|
||||
<string name="navigation_drawer_siderail_action_manage_folders">폴더 관리</string>
|
||||
<string name="navigation_drawer_siderail_unified_inbox_title">통합 편지함</string>
|
||||
</resources>
|
||||
|
|
@ -0,0 +1,8 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
|
||||
<string name="navigation_drawer_siderail_action_settings">Nustatymai</string>
|
||||
<string name="navigation_drawer_siderail_action_manage_folders">Tvarkyti aplankus</string>
|
||||
<string name="navigation_drawer_siderail_unified_inbox_title">Suvestiniai gautieji</string>
|
||||
<string name="navigation_drawer_siderail_action_show_accounts">Rodyti paskyras</string>
|
||||
<string name="navigation_drawer_siderail_action_sync_all_accounts">Sinchronizuoti visas paskyras</string>
|
||||
</resources>
|
||||
|
|
@ -0,0 +1,6 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
|
||||
<string name="navigation_drawer_siderail_action_settings">Iestatījumi</string>
|
||||
<string name="navigation_drawer_siderail_action_manage_folders">Pārvaldīt mapes</string>
|
||||
<string name="navigation_drawer_siderail_unified_inbox_title">Apvienotā Iesūtne</string>
|
||||
</resources>
|
||||
|
|
@ -0,0 +1,6 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
|
||||
<string name="navigation_drawer_siderail_action_settings">സജ്ജീകരണങ്ങൾ</string>
|
||||
<string name="navigation_drawer_siderail_action_manage_folders">ഫോൾഡറുകൾ നിയന്ത്രിക്കുക</string>
|
||||
<string name="navigation_drawer_siderail_unified_inbox_title">ഏകീകൃത ഇൻബോക്സ്</string>
|
||||
</resources>
|
||||
|
|
@ -0,0 +1,11 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
|
||||
<string name="navigation_drawer_siderail_action_settings">Innstillinger</string>
|
||||
<string name="navigation_drawer_siderail_action_manage_folders">Behandle mapper</string>
|
||||
<string name="navigation_drawer_siderail_unified_inbox_title">Samlet innboks</string>
|
||||
<string name="navigation_drawer_siderail_action_show_accounts">Vis kontoer</string>
|
||||
<string name="navigation_drawer_siderail_action_sync_all_accounts">Synkronisér alle kontoer</string>
|
||||
<string name="navigation_drawer_siderail_action_hide_accounts">Skjul kontoer</string>
|
||||
<string name="navigation_drawer_siderail_folder_item_badge_count_greater_than_99">99+</string>
|
||||
<string name="navigation_drawer_siderail_folder_item_badge_count_greater_than_1_000">1T+</string>
|
||||
</resources>
|
||||
|
|
@ -0,0 +1,11 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
|
||||
<string name="navigation_drawer_siderail_action_settings">Instellingen</string>
|
||||
<string name="navigation_drawer_siderail_action_manage_folders">Mappen beheren</string>
|
||||
<string name="navigation_drawer_siderail_unified_inbox_title">Samengevoegd Postvak IN</string>
|
||||
<string name="navigation_drawer_siderail_folder_item_badge_count_greater_than_1_000">1k+</string>
|
||||
<string name="navigation_drawer_siderail_folder_item_badge_count_greater_than_99">99+</string>
|
||||
<string name="navigation_drawer_siderail_action_sync_all_accounts">Alle accounts synchroniseren</string>
|
||||
<string name="navigation_drawer_siderail_action_show_accounts">Accounts tonen</string>
|
||||
<string name="navigation_drawer_siderail_action_hide_accounts">Accounts verbergen</string>
|
||||
</resources>
|
||||
|
|
@ -0,0 +1,11 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
|
||||
<string name="navigation_drawer_siderail_action_settings">Innstillingar</string>
|
||||
<string name="navigation_drawer_siderail_action_manage_folders">Handsam mapper</string>
|
||||
<string name="navigation_drawer_siderail_action_sync_all_accounts">Synkroniser alle kontoar</string>
|
||||
<string name="navigation_drawer_siderail_action_show_accounts">Vis kontoar</string>
|
||||
<string name="navigation_drawer_siderail_action_hide_accounts">Skjul kontoar</string>
|
||||
<string name="navigation_drawer_siderail_folder_item_badge_count_greater_than_99">99+</string>
|
||||
<string name="navigation_drawer_siderail_unified_inbox_title">Samla innboks</string>
|
||||
<string name="navigation_drawer_siderail_folder_item_badge_count_greater_than_1_000">1k+</string>
|
||||
</resources>
|
||||
|
|
@ -0,0 +1,11 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
|
||||
<string name="navigation_drawer_siderail_action_settings">Ustawienia</string>
|
||||
<string name="navigation_drawer_siderail_action_manage_folders">Zarządzaj folderami</string>
|
||||
<string name="navigation_drawer_siderail_unified_inbox_title">Zintegrowana odbiorcza</string>
|
||||
<string name="navigation_drawer_siderail_folder_item_badge_count_greater_than_99">99+</string>
|
||||
<string name="navigation_drawer_siderail_folder_item_badge_count_greater_than_1_000">1k+</string>
|
||||
<string name="navigation_drawer_siderail_action_sync_all_accounts">Synchronizuj wszystkie konta</string>
|
||||
<string name="navigation_drawer_siderail_action_hide_accounts">Ukryj konta</string>
|
||||
<string name="navigation_drawer_siderail_action_show_accounts">Pokaż konta</string>
|
||||
</resources>
|
||||
|
|
@ -0,0 +1,11 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
|
||||
<string name="navigation_drawer_siderail_action_settings">Configurações</string>
|
||||
<string name="navigation_drawer_siderail_action_manage_folders">Gerenciar pastas</string>
|
||||
<string name="navigation_drawer_siderail_unified_inbox_title">Caixa de Entrada Unificada</string>
|
||||
<string name="navigation_drawer_siderail_folder_item_badge_count_greater_than_99">99+</string>
|
||||
<string name="navigation_drawer_siderail_action_sync_all_accounts">Sincronizar todas as contas</string>
|
||||
<string name="navigation_drawer_siderail_action_hide_accounts">Esconder contas</string>
|
||||
<string name="navigation_drawer_siderail_action_show_accounts">Mostrar contas</string>
|
||||
<string name="navigation_drawer_siderail_folder_item_badge_count_greater_than_1_000">1k+</string>
|
||||
</resources>
|
||||
|
|
@ -0,0 +1,11 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
|
||||
<string name="navigation_drawer_siderail_action_settings">Configurações</string>
|
||||
<string name="navigation_drawer_siderail_action_manage_folders">Gerir pastas</string>
|
||||
<string name="navigation_drawer_siderail_unified_inbox_title">Caixa de entrada unificada</string>
|
||||
<string name="navigation_drawer_siderail_action_sync_all_accounts">Sincronizar todas as contas</string>
|
||||
<string name="navigation_drawer_siderail_action_hide_accounts">Esconder contas</string>
|
||||
<string name="navigation_drawer_siderail_folder_item_badge_count_greater_than_99">>99</string>
|
||||
<string name="navigation_drawer_siderail_folder_item_badge_count_greater_than_1_000">>1k</string>
|
||||
<string name="navigation_drawer_siderail_action_show_accounts">Mostrar contas</string>
|
||||
</resources>
|
||||
|
|
@ -0,0 +1,2 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources></resources>
|
||||
|
|
@ -0,0 +1,11 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
|
||||
<string name="navigation_drawer_siderail_action_settings">Opțiuni</string>
|
||||
<string name="navigation_drawer_siderail_action_manage_folders">Gestionează dosarele</string>
|
||||
<string name="navigation_drawer_siderail_unified_inbox_title">Căsuță poștală unificată</string>
|
||||
<string name="navigation_drawer_siderail_action_sync_all_accounts">Sincronizează toate conturile</string>
|
||||
<string name="navigation_drawer_siderail_action_show_accounts">Arată conturile</string>
|
||||
<string name="navigation_drawer_siderail_action_hide_accounts">Ascunde conturile</string>
|
||||
<string name="navigation_drawer_siderail_folder_item_badge_count_greater_than_99">99+</string>
|
||||
<string name="navigation_drawer_siderail_folder_item_badge_count_greater_than_1_000">1k+</string>
|
||||
</resources>
|
||||
Some files were not shown because too many files have changed in this diff Show more
Loading…
Add table
Add a link
Reference in a new issue