Skip to content

Commit 5a843cc

Browse files
ClemRivierewmontwe
authored andcommitted
refactor: managing TreeFolder conversion in UseCase
1 parent 163450e commit 5a843cc

9 files changed

Lines changed: 108 additions & 68 deletions

File tree

feature/navigation/drawer/dropdown/src/debug/kotlin/net/thunderbird/feature/navigation/drawer/dropdown/ui/folder/FolderListPreview.kt

Lines changed: 10 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ import androidx.compose.runtime.Composable
44
import androidx.compose.ui.tooling.preview.Preview
55
import app.k9mail.core.ui.compose.designsystem.PreviewWithTheme
66
import kotlinx.collections.immutable.persistentListOf
7+
import net.thunderbird.feature.navigation.drawer.dropdown.domain.entity.TreeFolder
78
import net.thunderbird.feature.navigation.drawer.dropdown.ui.FakeData.DISPLAY_FOLDER
89
import net.thunderbird.feature.navigation.drawer.dropdown.ui.FakeData.UNIFIED_FOLDER
910

@@ -12,8 +13,8 @@ import net.thunderbird.feature.navigation.drawer.dropdown.ui.FakeData.UNIFIED_FO
1213
internal fun FolderListPreview() {
1314
PreviewWithTheme {
1415
FolderList(
15-
folders = persistentListOf(
16-
DISPLAY_FOLDER,
16+
rootFolder = TreeFolder.createFromFolders(
17+
persistentListOf(DISPLAY_FOLDER),
1718
),
1819
selectedFolder = null,
1920
onFolderClick = {},
@@ -27,8 +28,8 @@ internal fun FolderListPreview() {
2728
internal fun FolderListPreviewSelected() {
2829
PreviewWithTheme {
2930
FolderList(
30-
folders = persistentListOf(
31-
DISPLAY_FOLDER,
31+
rootFolder = TreeFolder.createFromFolders(
32+
persistentListOf(DISPLAY_FOLDER),
3233
),
3334
selectedFolder = DISPLAY_FOLDER,
3435
onFolderClick = {},
@@ -42,9 +43,11 @@ internal fun FolderListPreviewSelected() {
4243
internal fun FolderListWithUnifiedFolderPreview() {
4344
PreviewWithTheme {
4445
FolderList(
45-
folders = persistentListOf(
46-
UNIFIED_FOLDER,
47-
DISPLAY_FOLDER,
46+
rootFolder = TreeFolder.createFromFolders(
47+
persistentListOf(
48+
UNIFIED_FOLDER,
49+
DISPLAY_FOLDER,
50+
),
4851
),
4952
selectedFolder = DISPLAY_FOLDER,
5053
onFolderClick = {},

feature/navigation/drawer/dropdown/src/main/kotlin/net/thunderbird/feature/navigation/drawer/dropdown/NavigationDrawerModule.kt

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ import net.thunderbird.feature.navigation.drawer.dropdown.domain.DomainContract.
66
import net.thunderbird.feature.navigation.drawer.dropdown.domain.usecase.GetDisplayAccounts
77
import net.thunderbird.feature.navigation.drawer.dropdown.domain.usecase.GetDisplayFoldersForAccount
88
import net.thunderbird.feature.navigation.drawer.dropdown.domain.usecase.GetDrawerConfig
9+
import net.thunderbird.feature.navigation.drawer.dropdown.domain.usecase.GetTreeFolders
910
import net.thunderbird.feature.navigation.drawer.dropdown.domain.usecase.SaveDrawerConfig
1011
import net.thunderbird.feature.navigation.drawer.dropdown.domain.usecase.SyncAccount
1112
import net.thunderbird.feature.navigation.drawer.dropdown.domain.usecase.SyncAllAccounts
@@ -48,6 +49,10 @@ val navigationDropDownDrawerModule: Module = module {
4849
)
4950
}
5051

52+
single<UseCase.GetTreeFolders> {
53+
GetTreeFolders()
54+
}
55+
5156
single<UseCase.SyncAccount> {
5257
SyncAccount(
5358
accountManager = get(),
@@ -67,6 +72,7 @@ val navigationDropDownDrawerModule: Module = module {
6772
saveDrawerConfig = get(),
6873
getDisplayAccounts = get(),
6974
getDisplayFoldersForAccount = get(),
75+
getTreeFolders = get(),
7076
syncAccount = get(),
7177
syncAllAccounts = get(),
7278
)

feature/navigation/drawer/dropdown/src/main/kotlin/net/thunderbird/feature/navigation/drawer/dropdown/domain/DomainContract.kt

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ import net.thunderbird.feature.navigation.drawer.dropdown.domain.entity.DisplayA
66
import net.thunderbird.feature.navigation.drawer.dropdown.domain.entity.DisplayFolder
77
import net.thunderbird.feature.navigation.drawer.dropdown.domain.entity.DisplayUnifiedFolder
88
import net.thunderbird.feature.navigation.drawer.dropdown.domain.entity.DisplayUnifiedFolderType
9+
import net.thunderbird.feature.navigation.drawer.dropdown.domain.entity.TreeFolder
910

1011
internal interface DomainContract {
1112

@@ -26,6 +27,10 @@ internal interface DomainContract {
2627
operator fun invoke(accountId: String, includeUnifiedFolders: Boolean): Flow<List<DisplayFolder>>
2728
}
2829

30+
fun interface GetTreeFolders {
31+
operator fun invoke(folders: List<DisplayFolder>, maxDepth: Int): TreeFolder
32+
}
33+
2934
/**
3035
* Synchronize the given account uuid.
3136
*/

feature/navigation/drawer/dropdown/src/main/kotlin/net/thunderbird/feature/navigation/drawer/dropdown/domain/entity/TreeFolder.kt

Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,72 @@
11
package net.thunderbird.feature.navigation.drawer.dropdown.domain.entity
22

3+
import app.k9mail.core.mail.folder.api.Folder
4+
import app.k9mail.core.mail.folder.api.FolderType
5+
36
internal data class TreeFolder(
47
var value: DisplayFolder? = null,
58
) {
9+
companion object {
10+
fun createFromFolders(folders: List<DisplayFolder>, maxDepth: Int = 3): TreeFolder {
11+
// Converting folders to TreeFolder
12+
val rootFolder = TreeFolder()
13+
var currentTree = rootFolder
14+
15+
for (displayFolder in folders) {
16+
if (displayFolder is DisplayUnifiedFolder) {
17+
currentTree.children.add(TreeFolder(displayFolder))
18+
}
19+
if (displayFolder !is DisplayAccountFolder) continue
20+
val splittedFolderName = displayFolder.folder.name.split("/", limit = maxDepth + 1)
21+
var subFolderEntireName = ""
22+
for (subFolderName in splittedFolderName) {
23+
subFolderEntireName += subFolderName
24+
var foundInChildren = false
25+
for (children in currentTree.children) {
26+
var childDisplayFolder = children.value
27+
if (childDisplayFolder !is DisplayAccountFolder) continue
28+
if (childDisplayFolder.folder.name == subFolderEntireName) {
29+
currentTree = children
30+
foundInChildren = true
31+
break
32+
}
33+
}
34+
if (!foundInChildren) {
35+
var newChildren = TreeFolder()
36+
if (subFolderEntireName == displayFolder.folder.name) {
37+
newChildren = TreeFolder(displayFolder)
38+
} else {
39+
newChildren = TreeFolder(
40+
DisplayAccountFolder(
41+
displayFolder.accountId,
42+
Folder(
43+
0,
44+
subFolderEntireName,
45+
FolderType.REGULAR,
46+
displayFolder.folder.isLocalOnly,
47+
),
48+
displayFolder.isInTopGroup,
49+
0,
50+
0,
51+
),
52+
)
53+
}
54+
currentTree.children.add(newChildren)
55+
currentTree = newChildren
56+
} else {
57+
if (subFolderEntireName == displayFolder.folder.name) {
58+
currentTree.value = displayFolder
59+
}
60+
}
61+
subFolderEntireName += "/"
62+
}
63+
currentTree = rootFolder
64+
}
65+
66+
return rootFolder
67+
}
68+
}
69+
670
val children: ArrayList<TreeFolder> = ArrayList()
771

872
fun getAllUnreadMessageCount(): Int {
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
package net.thunderbird.feature.navigation.drawer.dropdown.domain.usecase
2+
3+
import net.thunderbird.feature.navigation.drawer.dropdown.domain.DomainContract.UseCase
4+
import net.thunderbird.feature.navigation.drawer.dropdown.domain.entity.DisplayFolder
5+
import net.thunderbird.feature.navigation.drawer.dropdown.domain.entity.TreeFolder
6+
7+
internal class GetTreeFolders() : UseCase.GetTreeFolders {
8+
override fun invoke(folders: List<DisplayFolder>, maxDepth: Int): TreeFolder {
9+
return TreeFolder.createFromFolders(folders, maxDepth)
10+
}
11+
}

feature/navigation/drawer/dropdown/src/main/kotlin/net/thunderbird/feature/navigation/drawer/dropdown/ui/DrawerContent.kt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -75,7 +75,7 @@ internal fun DrawerContent(
7575
.fillMaxSize(),
7676
) {
7777
FolderList(
78-
folders = state.folders,
78+
rootFolder = state.rootFolder,
7979
selectedFolder = state.folders.firstOrNull { it.id == state.selectedFolderId },
8080
onFolderClick = { folder ->
8181
onEvent(Event.OnFolderClick(folder))

feature/navigation/drawer/dropdown/src/main/kotlin/net/thunderbird/feature/navigation/drawer/dropdown/ui/DrawerContract.kt

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,23 +4,25 @@ import androidx.compose.runtime.Stable
44
import app.k9mail.core.ui.compose.common.mvi.UnidirectionalViewModel
55
import kotlinx.collections.immutable.ImmutableList
66
import kotlinx.collections.immutable.persistentListOf
7-
import net.thunderbird.feature.navigation.drawer.api.NavigationDrawerExternalContract
7+
import net.thunderbird.feature.navigation.drawer.api.NavigationDrawerExternalContract.DrawerConfig
88
import net.thunderbird.feature.navigation.drawer.dropdown.domain.entity.DisplayAccount
99
import net.thunderbird.feature.navigation.drawer.dropdown.domain.entity.DisplayFolder
10+
import net.thunderbird.feature.navigation.drawer.dropdown.domain.entity.TreeFolder
1011

1112
internal interface DrawerContract {
1213

1314
interface ViewModel : UnidirectionalViewModel<State, Event, Effect>
1415

1516
@Stable
1617
data class State(
17-
val config: NavigationDrawerExternalContract.DrawerConfig = NavigationDrawerExternalContract.DrawerConfig(
18+
val config: DrawerConfig = DrawerConfig(
1819
showUnifiedFolders = false,
1920
showStarredCount = false,
2021
showAccountSelector = true,
2122
),
2223
val accounts: ImmutableList<DisplayAccount> = persistentListOf(),
2324
val selectedAccountId: String? = null,
25+
val rootFolder: TreeFolder = TreeFolder(),
2426
val folders: ImmutableList<DisplayFolder> = persistentListOf(),
2527
val selectedFolderId: String? = null,
2628
val isLoading: Boolean = false,

feature/navigation/drawer/dropdown/src/main/kotlin/net/thunderbird/feature/navigation/drawer/dropdown/ui/DrawerViewModel.kt

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ import net.thunderbird.feature.navigation.drawer.dropdown.domain.entity.DisplayA
1919
import net.thunderbird.feature.navigation.drawer.dropdown.domain.entity.DisplayAccountFolder
2020
import net.thunderbird.feature.navigation.drawer.dropdown.domain.entity.DisplayFolder
2121
import net.thunderbird.feature.navigation.drawer.dropdown.domain.entity.DisplayUnifiedFolder
22+
import net.thunderbird.feature.navigation.drawer.dropdown.domain.entity.TreeFolder
2223
import net.thunderbird.feature.navigation.drawer.dropdown.ui.DrawerContract.Effect
2324
import net.thunderbird.feature.navigation.drawer.dropdown.ui.DrawerContract.Event
2425
import net.thunderbird.feature.navigation.drawer.dropdown.ui.DrawerContract.State
@@ -36,6 +37,7 @@ internal class DrawerViewModel(
3637
private val saveDrawerConfig: UseCase.SaveDrawerConfig,
3738
private val getDisplayAccounts: UseCase.GetDisplayAccounts,
3839
private val getDisplayFoldersForAccount: UseCase.GetDisplayFoldersForAccount,
40+
private val getTreeFolders: UseCase.GetTreeFolders,
3941
private val syncAccount: UseCase.SyncAccount,
4042
private val syncAllAccounts: UseCase.SyncAllAccounts,
4143
initialState: State = State(),
@@ -91,17 +93,18 @@ internal class DrawerViewModel(
9193
.flatMapLatest { (accountId, showUnifiedInbox) ->
9294
getDisplayFoldersForAccount(accountId, showUnifiedInbox)
9395
}.collect { folders ->
94-
updateFolders(folders)
96+
updateFolders(folders, getTreeFolders(folders, 3))
9597
}
9698
}
9799

98-
private fun updateFolders(displayFolders: List<DisplayFolder>) {
100+
private fun updateFolders(displayFolders: List<DisplayFolder>, rootFolder: TreeFolder) {
99101
val selectedFolder = displayFolders.find {
100102
it.id == state.value.selectedFolderId
101103
} ?: displayFolders.firstOrNull()
102104

103105
updateState {
104106
it.copy(
107+
rootFolder = rootFolder,
105108
folders = displayFolders.toImmutableList(),
106109
selectedFolderId = selectedFolder?.id,
107110
)

feature/navigation/drawer/dropdown/src/main/kotlin/net/thunderbird/feature/navigation/drawer/dropdown/ui/folder/FolderList.kt

Lines changed: 2 additions & 56 deletions
Original file line numberDiff line numberDiff line change
@@ -10,20 +10,17 @@ import androidx.compose.runtime.Composable
1010
import androidx.compose.runtime.remember
1111
import androidx.compose.ui.Modifier
1212
import androidx.compose.ui.platform.LocalContext
13-
import app.k9mail.core.mail.folder.api.Folder
14-
import app.k9mail.core.mail.folder.api.FolderType
1513
import app.k9mail.core.ui.compose.designsystem.atom.DividerHorizontal
1614
import app.k9mail.core.ui.compose.theme2.MainTheme
1715
import app.k9mail.legacy.ui.folder.FolderNameFormatter
18-
import kotlinx.collections.immutable.ImmutableList
19-
import net.thunderbird.feature.navigation.drawer.dropdown.domain.entity.DisplayFolder
2016
import net.thunderbird.feature.navigation.drawer.dropdown.domain.entity.DisplayAccountFolder
17+
import net.thunderbird.feature.navigation.drawer.dropdown.domain.entity.DisplayFolder
2118
import net.thunderbird.feature.navigation.drawer.dropdown.domain.entity.DisplayUnifiedFolder
2219
import net.thunderbird.feature.navigation.drawer.dropdown.domain.entity.TreeFolder
2320

2421
@Composable
2522
internal fun FolderList(
26-
folders: ImmutableList<DisplayFolder>,
23+
rootFolder: TreeFolder,
2724
selectedFolder: DisplayFolder?,
2825
onFolderClick: (DisplayFolder) -> Unit,
2926
showStarredCount: Boolean,
@@ -33,57 +30,6 @@ internal fun FolderList(
3330
val folderNameFormatter = remember { FolderNameFormatter(resources) }
3431
val listState = rememberLazyListState()
3532

36-
// Converting folders to TreeFolder
37-
val rootFolder = TreeFolder()
38-
val maxDepth = 2
39-
var currentTree = rootFolder
40-
41-
for (displayFolder in folders) {
42-
if (displayFolder is DisplayUnifiedFolder) {
43-
currentTree.children.add(TreeFolder(displayFolder))
44-
}
45-
if (displayFolder !is DisplayAccountFolder) continue
46-
val splittedFolderName = displayFolder.folder.name.split("/", limit = maxDepth + 1)
47-
var subFolderEntireName = ""
48-
for (subFolderName in splittedFolderName) {
49-
subFolderEntireName += subFolderName
50-
var foundInChildren = false
51-
for (children in currentTree.children) {
52-
var childDisplayFolder = children.value
53-
if (childDisplayFolder !is DisplayAccountFolder) continue
54-
if (childDisplayFolder.folder.name == subFolderEntireName) {
55-
currentTree = children
56-
foundInChildren = true
57-
break
58-
}
59-
}
60-
if (!foundInChildren) {
61-
var newChildren = TreeFolder()
62-
if (subFolderEntireName == displayFolder.folder.name) {
63-
newChildren = TreeFolder(displayFolder)
64-
} else {
65-
newChildren = TreeFolder(
66-
DisplayAccountFolder(
67-
displayFolder.accountId,
68-
Folder(0, subFolderEntireName, FolderType.REGULAR, displayFolder.folder.isLocalOnly),
69-
displayFolder.isInTopGroup,
70-
0,
71-
0,
72-
),
73-
)
74-
}
75-
currentTree.children.add(newChildren)
76-
currentTree = newChildren
77-
} else {
78-
if (subFolderEntireName == displayFolder.folder.name) {
79-
currentTree.value = displayFolder
80-
}
81-
}
82-
subFolderEntireName += "/"
83-
}
84-
currentTree = rootFolder
85-
}
86-
8733
LazyColumn(
8834
state = listState,
8935
modifier = modifier

0 commit comments

Comments
 (0)