Repository: thunderbird/thunderbird-android (language: kotlin)

Issue:
12.0b7 crash. Upon [gmail] folder selection
### Checklist

- [x] I have used the search function to see if someone else has already submitted the same bug report.
- [x] I will describe the problem with as much detail as possible.

### App

Thunderbird for Android

### App version

12.0b7

### Where did you get the app from?

Other

### Android version

Android 15

### Device model

Oneplus 10 Pro

### Steps to reproduce

App downloaded from github.

1. Close app and remove from androids running app list.
2. Open app again.
3. Switch from Unified to gmail account.
4. Observe standard gmail folders are all correctly displayed at the same level beneath each other.
5. Drop back to android launcher (TBA running in background)
6. I wait about 30 minutes.
7. Open the app and view the gmail folder list.
7. Observe abnormal presence of [gmail] expandable folder.
8. Select this [gmail] folder.
9. App crashes

### Expected behavior

The normal behaviour is where the standard gmail folders (Inbox, outbox, all mail, draft, etc) are all displayed beneath each other at the top level.

![Image](https://github.com/user-attachments/assets/db64c041-97a8-4cfa-96ae-ad79c5226aba)

### Actual behavior

I open the app after approx 30 minutes running in the background. I observe the app has changed the normal folder view and now displays an expandable [gmail] folder. Selecting this folder crashes the app.

I'm not sure sure what is triggering the view to change as it does so without user interaction. Perhaps background sync.

![Image](https://github.com/user-attachments/assets/88d8d5d2-b314-4255-ad38-c64e9dc10c2c)

### Logs

[k9mail-logs.txt](https://github.com/user-attachments/files/21970985/k9mail-logs.txt)


Discussion hints:
Seems related to #9134 , #9353 and possibly a regression following #9213 
The [gmail] folder exists in v11.1 however selecting it doesn't crash the app. 
This is the top crash (affects the most users) for 12.0b7
I think I have a simple reproducer that does not require waiting:

1. Add 2 accounts, 1 of them Gmail
2. Refresh folders on the Gmail account (Manage folders -> 3 dots -> Refresh folder list) (this updates folders to include the `[Gmail]/` prefix)
3. Switch to a different account (can be Unified; causes the app to regenerate folder tree)
4. Switch to the Gmail account again - there should be a `[Gmail]` [placeholder folder](https://github.com/thunderbird/thunderbird-android/blob/94c9063858f999cc4e57538ec0eb2fcd0c35a124/feature/navigation/drawer/dropdown/src/main/kotlin/net/thunderbird/feature/navigation/drawer/dropdown/domain/usecase/GetDisplayTreeFolder.kt#L73)
Thanks @krzysdz , I can also reproduce using your steps.
Noting the issue is also present in today's v12 release (non beta).

Pull request: fix(drawer): crash when opening placeholder folder
Fixes #9644.

- Change the placeholder `MailDisplayFolder` to not have an account ID.
- Ensure that we only trigger `onClick(displayFolder)` in case we have an account ID.
- If tapping on a Placeholder folder, toggle the `isExpanded` state.

> [!NOTE]
> A follow-up ticket will be placed to investigate why the `[Gmail]` prefix is added back when refreshing the folder list. For now, this PR is only meant to fix the crash.

Screen recording:

https://github.com/user-attachments/assets/94a9f89f-91b1-4e12-8ee8-7d0902e7a0e6



Test command: ./gradlew :feature:navigation:drawer:dropdown:testDebugUnitTest --tests "net.thunderbird.feature.navigation.drawer.dropdown.domain.usecase.GetDisplayTreeFolderTest" --tests "net.thunderbird.feature.navigation.drawer.dropdown.ui.DrawerViewModelTest"

Fix patch:
diff --git a/feature/navigation/drawer/dropdown/src/main/kotlin/net/thunderbird/feature/navigation/drawer/dropdown/domain/entity/MailDisplayFolder.kt b/feature/navigation/drawer/dropdown/src/main/kotlin/net/thunderbird/feature/navigation/drawer/dropdown/domain/entity/MailDisplayFolder.kt
index ee14c89efd4..07b8a6643d4 100644
--- a/feature/navigation/drawer/dropdown/src/main/kotlin/net/thunderbird/feature/navigation/drawer/dropdown/domain/entity/MailDisplayFolder.kt
+++ b/feature/navigation/drawer/dropdown/src/main/kotlin/net/thunderbird/feature/navigation/drawer/dropdown/domain/entity/MailDisplayFolder.kt
@@ -3,13 +3,13 @@ package net.thunderbird.feature.navigation.drawer.dropdown.domain.entity
 import net.thunderbird.feature.mail.folder.api.Folder
 
 internal data class MailDisplayFolder(
-    val accountId: String,
+    val accountId: String?,
     val folder: Folder,
     val isInTopGroup: Boolean,
     override val unreadMessageCount: Int,
     override val starredMessageCount: Int,
 ) : DisplayFolder {
-    override val id: String = createMailDisplayAccountFolderId(accountId, folder.id)
+    override val id: String = createMailDisplayAccountFolderId(accountId.orEmpty(), folder.id)
 }
 
 fun createMailDisplayAccountFolderId(accountId: String, folderId: Long): String {
diff --git a/feature/navigation/drawer/dropdown/src/main/kotlin/net/thunderbird/feature/navigation/drawer/dropdown/domain/usecase/GetDisplayTreeFolder.kt b/feature/navigation/drawer/dropdown/src/main/kotlin/net/thunderbird/feature/navigation/drawer/dropdown/domain/usecase/GetDisplayTreeFolder.kt
index 05ade0c3e12..ae75fcae30a 100644
--- a/feature/navigation/drawer/dropdown/src/main/kotlin/net/thunderbird/feature/navigation/drawer/dropdown/domain/usecase/GetDisplayTreeFolder.kt
+++ b/feature/navigation/drawer/dropdown/src/main/kotlin/net/thunderbird/feature/navigation/drawer/dropdown/domain/usecase/GetDisplayTreeFolder.kt
@@ -90,7 +90,7 @@ internal class GetDisplayTreeFolder : UseCase.GetDisplayTreeFolder {
     private fun createPlaceholderFolder(name: String): MailDisplayFolder {
         placeholderCounter += 1
         return MailDisplayFolder(
-            accountId = "placeholder",
+            accountId = null,
             folder = Folder(
                 id = placeholderCounter,
                 name = name,
diff --git a/feature/navigation/drawer/dropdown/src/main/kotlin/net/thunderbird/feature/navigation/drawer/dropdown/ui/DrawerViewModel.kt b/feature/navigation/drawer/dropdown/src/main/kotlin/net/thunderbird/feature/navigation/drawer/dropdown/ui/DrawerViewModel.kt
index 793e71437e5..c81ab049921 100644
--- a/feature/navigation/drawer/dropdown/src/main/kotlin/net/thunderbird/feature/navigation/drawer/dropdown/ui/DrawerViewModel.kt
+++ b/feature/navigation/drawer/dropdown/src/main/kotlin/net/thunderbird/feature/navigation/drawer/dropdown/ui/DrawerViewModel.kt
@@ -240,12 +240,14 @@ internal class DrawerViewModel(
         selectFolder(folder.id)
 
         if (folder is MailDisplayFolder) {
-            emitEffect(
-                Effect.OpenFolder(
-                    accountId = folder.accountId,
-                    folderId = folder.folder.id,
-                ),
-            )
+            if (folder.accountId != null) {
+                emitEffect(
+                    Effect.OpenFolder(
+                        accountId = folder.accountId,
+                        folderId = folder.folder.id,
+                    ),
+                )
+            }
         } else if (folder is UnifiedDisplayFolder) {
             emitEffect(Effect.OpenUnifiedFolder)
         }
diff --git a/feature/navigation/drawer/dropdown/src/main/kotlin/net/thunderbird/feature/navigation/drawer/dropdown/ui/folder/FolderListItem.kt b/feature/navigation/drawer/dropdown/src/main/kotlin/net/thunderbird/feature/navigation/drawer/dropdown/ui/folder/FolderListItem.kt
index 9261aad3726..3dd9ef6fb49 100644
--- a/feature/navigation/drawer/dropdown/src/main/kotlin/net/thunderbird/feature/navigation/drawer/dropdown/ui/folder/FolderListItem.kt
+++ b/feature/navigation/drawer/dropdown/src/main/kotlin/net/thunderbird/feature/navigation/drawer/dropdown/ui/folder/FolderListItem.kt
@@ -76,13 +76,14 @@ internal fun FolderListItem(
                 )
             },
             selected = selectedFolderId == displayFolder.id,
-            onClick = { onClick(displayFolder) },
-            modifier = Modifier.fillMaxWidth(),
-            icon = {
-                Icon(
-                    imageVector = mapFolderIcon(displayFolder),
-                )
+            onClick = {
+                when (displayFolder) {
+                    is MailDisplayFolder if displayFolder.accountId == null -> isExpanded.value = !isExpanded.value
+                    else -> onClick(displayFolder)
+                }
             },
+            modifier = Modifier.fillMaxWidth(),
+            icon = { Icon(imageVector = mapFolderIcon(displayFolder)) },
         )
 
         // Managing children


Test patch:
diff --git a/feature/navigation/drawer/dropdown/src/test/kotlin/net/thunderbird/feature/navigation/drawer/dropdown/domain/usecase/GetDisplayTreeFolderTest.kt b/feature/navigation/drawer/dropdown/src/test/kotlin/net/thunderbird/feature/navigation/drawer/dropdown/domain/usecase/GetDisplayTreeFolderTest.kt
index 0598feaccbd..1229ea96891 100644
--- a/feature/navigation/drawer/dropdown/src/test/kotlin/net/thunderbird/feature/navigation/drawer/dropdown/domain/usecase/GetDisplayTreeFolderTest.kt
+++ b/feature/navigation/drawer/dropdown/src/test/kotlin/net/thunderbird/feature/navigation/drawer/dropdown/domain/usecase/GetDisplayTreeFolderTest.kt
@@ -199,7 +199,7 @@ class GetDisplayTreeFolderTest {
                     children = persistentListOf(
                         DisplayTreeFolder(
                             displayFolder = MailDisplayFolder(
-                                accountId = "placeholder",
+                                accountId = null,
                                 folder = Folder(
                                     id = 1L,
                                     name = "(Unnamed)/(Unnamed)",
@@ -238,7 +238,7 @@ class GetDisplayTreeFolderTest {
                 ),
                 DisplayTreeFolder(
                     displayFolder = MailDisplayFolder(
-                        accountId = "placeholder",
+                        accountId = null,
                         folder = Folder(id = 2, name = "valid1", type = FolderType.REGULAR, isLocalOnly = false),
                         isInTopGroup = true,
                         unreadMessageCount = 0,
@@ -250,7 +250,7 @@ class GetDisplayTreeFolderTest {
                     children = persistentListOf(
                         DisplayTreeFolder(
                             displayFolder = MailDisplayFolder(
-                                accountId = "placeholder",
+                                accountId = null,
                                 folder = Folder(
                                     id = 3L,
                                     name = "valid1/(Unnamed)",
@@ -321,7 +321,7 @@ class GetDisplayTreeFolderTest {
             children = persistentListOf(
                 createDisplayTreeFolder(
                     displayFolder = createDisplayAccountFolder(
-                        accountId = "placeholder",
+                        accountId = null,
                         folderId = 1L,
                         folderName = "folderLevel1",
                         unreadMessageCount = 0,
@@ -380,7 +380,7 @@ class GetDisplayTreeFolderTest {
             children = persistentListOf(
                 createDisplayTreeFolder(
                     displayFolder = createDisplayAccountFolder(
-                        accountId = "placeholder",
+                        accountId = null,
                         folderId = 1,
                         folderName = "level1",
                         unreadMessageCount = 0,
@@ -392,7 +392,7 @@ class GetDisplayTreeFolderTest {
                     children = persistentListOf(
                         createDisplayTreeFolder(
                             displayFolder = createDisplayAccountFolder(
-                                accountId = "placeholder",
+                                accountId = null,
                                 folderId = 2L,
                                 folderName = "level1/level2",
                                 unreadMessageCount = 0,
@@ -430,7 +430,7 @@ class GetDisplayTreeFolderTest {
             folderName: String,
             unreadMessageCount: Int,
             starredMessageCount: Int,
-            accountId: String = "accountId",
+            accountId: String? = "accountId",
         ): MailDisplayFolder {
             return MailDisplayFolder(
                 accountId = accountId,
diff --git a/feature/navigation/drawer/dropdown/src/test/kotlin/net/thunderbird/feature/navigation/drawer/dropdown/ui/DrawerViewModelTest.kt b/feature/navigation/drawer/dropdown/src/test/kotlin/net/thunderbird/feature/navigation/drawer/dropdown/ui/DrawerViewModelTest.kt
index 9b845976de8..a0a1af139e7 100644
--- a/feature/navigation/drawer/dropdown/src/test/kotlin/net/thunderbird/feature/navigation/drawer/dropdown/ui/DrawerViewModelTest.kt
+++ b/feature/navigation/drawer/dropdown/src/test/kotlin/net/thunderbird/feature/navigation/drawer/dropdown/ui/DrawerViewModelTest.kt
@@ -334,7 +334,7 @@ internal class DrawerViewModelTest {
 
         assertThat(turbines.awaitEffectItem()).isEqualTo(
             Effect.OpenFolder(
-                accountId = displayFolders[1].accountId,
+                accountId = requireNotNull(displayFolders[1].accountId),
                 folderId = displayFolders[1].folder.id,
             ),
         )