Skip to content

Commit 298c743

Browse files
committed
[AdaptiveUiCodelab] support item selection
Demonstrate ListDetailPaneScaffold behavior by switching panes on item click and implementing a back handler.
1 parent 9b0c8e1 commit 298c743

File tree

6 files changed

+76
-26
lines changed

6 files changed

+76
-26
lines changed

AdaptiveUiCodelab/app/src/main/java/com/example/reply/data/Email.kt

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -48,7 +48,7 @@ data class Email(
4848
var isStarred: Boolean = false,
4949
var mailbox: MailboxType = MailboxType.INBOX,
5050
var createAt: String,
51-
val threads: List<Email> = emptyList()
51+
val replies: List<Email> = emptyList()
5252
) {
5353
val senderPreview: String = "${sender.fullName} - 4 hrs ago"
5454
val hasBody: Boolean = body.isNotBlank()
@@ -59,5 +59,3 @@ data class Email(
5959
val nonUserAccountRecipients = recipients
6060
.filterNot { LocalAccountsDataProvider.isUserAccount(it.uid) }
6161
}
62-
63-

AdaptiveUiCodelab/app/src/main/java/com/example/reply/data/local/LocalEmailsDataProvider.kt

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -116,7 +116,7 @@ object LocalEmailsDataProvider {
116116
""".trimIndent(),
117117
createAt = "20 mins ago",
118118
isStarred = true,
119-
threads = threads,
119+
replies = threads,
120120
),
121121
Email(
122122
1L,
@@ -133,7 +133,7 @@ object LocalEmailsDataProvider {
133133
Ali
134134
""".trimIndent(),
135135
createAt = "40 mins ago",
136-
threads = threads,
136+
replies = threads,
137137
),
138138
Email(
139139
2L,
@@ -149,7 +149,7 @@ object LocalEmailsDataProvider {
149149
),
150150
true,
151151
createAt = "1 hour ago",
152-
threads = threads,
152+
replies = threads,
153153
),
154154
Email(
155155
3L,
@@ -311,4 +311,3 @@ object LocalEmailsDataProvider {
311311
"Grocery coupons"
312312
)
313313
}
314-

AdaptiveUiCodelab/app/src/main/java/com/example/reply/ui/MainActivity.kt

Lines changed: 12 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -76,7 +76,12 @@ class MainActivity : ComponentActivity() {
7676
val windowAdaptiveInfo = currentWindowAdaptiveInfo()
7777
val devicePosture = devicePostureFlow.collectAsState().value
7878
val uiState = viewModel.uiState.collectAsState().value
79-
ReplyApp(windowAdaptiveInfo.windowSizeClass.windowWidthSizeClass, devicePosture, uiState)
79+
ReplyApp(
80+
windowAdaptiveInfo.windowSizeClass.windowWidthSizeClass,
81+
devicePosture,
82+
uiState,
83+
viewModel::setSelectedEmail
84+
)
8085
}
8186
}
8287
}
@@ -89,7 +94,8 @@ fun ReplyAppPreview() {
8994
ReplyApp(
9095
replyHomeUIState = ReplyHomeUIState(emails = LocalEmailsDataProvider.allEmails),
9196
windowSize = WindowWidthSizeClass.COMPACT,
92-
foldingDevicePosture = DevicePosture.NormalPosture
97+
foldingDevicePosture = DevicePosture.NormalPosture,
98+
onEmailClick = {}
9399
)
94100
}
95101
}
@@ -101,7 +107,8 @@ fun ReplyAppPreviewTablet() {
101107
ReplyApp(
102108
replyHomeUIState = ReplyHomeUIState(emails = LocalEmailsDataProvider.allEmails),
103109
windowSize = WindowWidthSizeClass.MEDIUM,
104-
foldingDevicePosture = DevicePosture.NormalPosture
110+
foldingDevicePosture = DevicePosture.NormalPosture,
111+
onEmailClick = {}
105112
)
106113
}
107114
}
@@ -113,7 +120,8 @@ fun ReplyAppPreviewDesktop() {
113120
ReplyApp(
114121
replyHomeUIState = ReplyHomeUIState(emails = LocalEmailsDataProvider.allEmails),
115122
windowSize = WindowWidthSizeClass.EXPANDED,
116-
foldingDevicePosture = DevicePosture.NormalPosture
123+
foldingDevicePosture = DevicePosture.NormalPosture,
124+
onEmailClick = {}
117125
)
118126
}
119127
}

AdaptiveUiCodelab/app/src/main/java/com/example/reply/ui/ReplyApp.kt

Lines changed: 22 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -16,11 +16,13 @@
1616

1717
package com.example.reply.ui
1818

19+
import androidx.activity.compose.BackHandler
1920
import androidx.compose.material3.Icon
2021
import androidx.compose.material3.Text
2122
import androidx.compose.material3.adaptive.ExperimentalMaterial3AdaptiveApi
2223
import androidx.compose.material3.adaptive.layout.AnimatedPane
2324
import androidx.compose.material3.adaptive.layout.ListDetailPaneScaffold
25+
import androidx.compose.material3.adaptive.layout.ListDetailPaneScaffoldRole
2426
import androidx.compose.material3.adaptive.navigation.rememberListDetailPaneScaffoldNavigator
2527
import androidx.compose.material3.adaptive.navigationsuite.NavigationSuiteScaffold
2628
import androidx.compose.runtime.Composable
@@ -37,10 +39,14 @@ import com.example.reply.ui.utils.DevicePosture
3739
fun ReplyApp(
3840
windowSize: WindowWidthSizeClass,
3941
foldingDevicePosture: DevicePosture,
40-
replyHomeUIState: ReplyHomeUIState
42+
replyHomeUIState: ReplyHomeUIState,
43+
onEmailClick: (Email) -> Unit,
4144
) {
4245
ReplyNavigationWrapperUI {
43-
ReplyAppContent(replyHomeUIState)
46+
ReplyAppContent(
47+
replyHomeUIState = replyHomeUIState,
48+
onEmailClick = onEmailClick
49+
)
4450
}
4551
}
4652

@@ -72,16 +78,27 @@ private fun ReplyNavigationWrapperUI(
7278
@Composable
7379
fun ReplyAppContent(
7480
replyHomeUIState: ReplyHomeUIState,
81+
onEmailClick: (Email) -> Unit,
7582
) {
76-
val selectedEmail: Email? = replyHomeUIState.emails.firstOrNull()
77-
val navigator = rememberListDetailPaneScaffoldNavigator()
83+
val selectedEmail = replyHomeUIState.selectedEmail
84+
val navigator = rememberListDetailPaneScaffoldNavigator<Long>()
85+
86+
BackHandler(navigator.canNavigateBack()) {
87+
navigator.navigateBack()
88+
}
7889

7990
ListDetailPaneScaffold(
8091
directive = navigator.scaffoldDirective,
8192
value = navigator.scaffoldValue,
8293
listPane = {
8394
AnimatedPane {
84-
ReplyListPane(replyHomeUIState)
95+
ReplyListPane(
96+
replyHomeUIState = replyHomeUIState,
97+
onEmailClick = { email ->
98+
onEmailClick(email)
99+
navigator.navigateTo(ListDetailPaneScaffoldRole.Detail, email.id)
100+
}
101+
)
85102
}
86103
},
87104
detailPane = {

AdaptiveUiCodelab/app/src/main/java/com/example/reply/ui/ReplyHomeViewModel.kt

Lines changed: 15 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -43,14 +43,27 @@ class ReplyHomeViewModel(private val emailsRepository: EmailsRepository = Emails
4343
_uiState.value = ReplyHomeUIState(error = ex.message)
4444
}
4545
.collect { emails ->
46-
_uiState.value = ReplyHomeUIState(emails = emails)
46+
// If nothing is selected, initially select the first element.
47+
val currentSelected = _uiState.value.selectedEmail
48+
_uiState.value = ReplyHomeUIState(
49+
emails = emails,
50+
selectedEmail = currentSelected ?: emails.firstOrNull()
51+
)
4752
}
4853
}
4954
}
55+
56+
fun setSelectedEmail(email: Email) {
57+
val currentState = _uiState.value
58+
_uiState.value = currentState.copy(
59+
selectedEmail = email
60+
)
61+
}
5062
}
5163

5264
data class ReplyHomeUIState(
5365
val emails : List<Email> = emptyList(),
66+
val selectedEmail: Email? = null,
5467
val loading: Boolean = false,
5568
val error: String? = null
56-
)
69+
)

AdaptiveUiCodelab/app/src/main/java/com/example/reply/ui/ReplyListContent.kt

Lines changed: 23 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ package com.example.reply.ui
1818

1919
import androidx.compose.foundation.Image
2020
import androidx.compose.foundation.background
21+
import androidx.compose.foundation.clickable
2122
import androidx.compose.foundation.layout.Arrangement
2223
import androidx.compose.foundation.layout.Column
2324
import androidx.compose.foundation.layout.Row
@@ -53,14 +54,18 @@ import com.example.reply.data.Email
5354
@Composable
5455
fun ReplyListPane(
5556
replyHomeUIState: ReplyHomeUIState,
57+
onEmailClick: (Email) -> Unit,
5658
modifier: Modifier = Modifier
5759
) {
58-
LazyColumn(modifier = modifier) {
60+
LazyColumn(modifier = modifier.fillMaxWidth()) {
5961
item {
6062
ReplySearchBar(modifier = Modifier.fillMaxWidth())
6163
}
6264
items(replyHomeUIState.emails) { email ->
63-
ReplyEmailListItem(email = email)
65+
ReplyEmailListItem(
66+
email = email,
67+
onEmailClick = onEmailClick
68+
)
6469
}
6570
}
6671
}
@@ -70,8 +75,11 @@ fun ReplyDetailPane(
7075
email: Email,
7176
modifier: Modifier = Modifier
7277
) {
73-
LazyColumn(modifier = modifier) {
74-
items(email.threads) {
78+
LazyColumn(modifier = modifier.fillMaxWidth()) {
79+
item {
80+
ReplyEmailThreadItem(email)
81+
}
82+
items(email.replies) {
7583
ReplyEmailThreadItem(it)
7684
}
7785
}
@@ -81,9 +89,16 @@ fun ReplyDetailPane(
8189
@Composable
8290
fun ReplyEmailListItem(
8391
email: Email,
84-
modifier: Modifier = Modifier.padding(horizontal = 16.dp, vertical = 4.dp)
92+
onEmailClick: (Email) -> Unit,
93+
modifier: Modifier = Modifier
8594
) {
86-
Card(modifier = modifier) {
95+
Card(
96+
modifier = modifier
97+
.padding(horizontal = 16.dp, vertical = 4.dp)
98+
.clickable {
99+
onEmailClick(email)
100+
}
101+
) {
87102
Column(
88103
modifier = Modifier
89104
.fillMaxWidth()
@@ -145,10 +160,10 @@ fun ReplyEmailListItem(
145160
@Composable
146161
fun ReplyEmailThreadItem(
147162
email: Email,
148-
modifier: Modifier = Modifier.padding(horizontal = 16.dp, vertical = 4.dp)
163+
modifier: Modifier = Modifier
149164
) {
150165
Card(
151-
modifier = modifier,
166+
modifier = modifier.padding(horizontal = 16.dp, vertical = 4.dp),
152167
colors = CardDefaults.cardColors(containerColor = MaterialTheme.colorScheme.surface)
153168
) {
154169
Column(

0 commit comments

Comments
 (0)