From 5a116e7c8bc9920a140068edbcc7eb69e944f4cb Mon Sep 17 00:00:00 2001 From: Gurupreet Singh Date: Wed, 10 May 2023 17:55:41 +0200 Subject: [PATCH 1/6] added search app bar --- Reply/app/build.gradle.kts | 10 +- .../com/example/reply/ui/ReplyListContent.kt | 44 ++++-- .../reply/ui/components/ReplyAppBars.kt | 140 ++++++++++++++---- Reply/app/src/main/res/values/strings.xml | 5 +- Reply/gradle/libs.versions.toml | 2 +- 5 files changed, 145 insertions(+), 56 deletions(-) diff --git a/Reply/app/build.gradle.kts b/Reply/app/build.gradle.kts index bc4b910a1..7d78765b7 100644 --- a/Reply/app/build.gradle.kts +++ b/Reply/app/build.gradle.kts @@ -87,12 +87,6 @@ android { kotlinCompilerExtensionVersion = libs.versions.compose.compiler.get() } - packaging.resources { - // Multiple dependency bring these files in. Exclude them to enable - // our test APK to build (has no effect on our AARs) - excludes += "/META-INF/AL2.0" - excludes += "/META-INF/LGPL2.1" - } } dependencies { @@ -107,8 +101,8 @@ dependencies { implementation(libs.androidx.compose.ui.tooling.preview) debugImplementation(libs.androidx.compose.ui.tooling) - // custom declaration for latest versions of material 3 and adaptive accompanist - implementation("androidx.compose.material3:material3:1.0.0-rc01") + // Waiting for Compose BOM to contain m3 1.1.0 release + implementation("androidx.compose.material3:material3:1.1.0-rc01") implementation("com.google.accompanist:accompanist-adaptive:0.26.2-beta") implementation(libs.androidx.compose.materialWindow) diff --git a/Reply/app/src/main/java/com/example/reply/ui/ReplyListContent.kt b/Reply/app/src/main/java/com/example/reply/ui/ReplyListContent.kt index d93dcb151..df26c4ed8 100644 --- a/Reply/app/src/main/java/com/example/reply/ui/ReplyListContent.kt +++ b/Reply/app/src/main/java/com/example/reply/ui/ReplyListContent.kt @@ -43,9 +43,9 @@ import androidx.window.layout.DisplayFeature import com.example.reply.R import com.example.reply.data.Email import com.example.reply.ui.components.EmailDetailAppBar +import com.example.reply.ui.components.ReplyDockedSearchBar import com.example.reply.ui.components.ReplyEmailListItem import com.example.reply.ui.components.ReplyEmailThreadItem -import com.example.reply.ui.components.ReplySearchBar import com.example.reply.ui.utils.ReplyContentType import com.example.reply.ui.utils.ReplyNavigationType import com.google.accompanist.adaptive.HorizontalTwoPaneStrategy @@ -167,20 +167,34 @@ fun ReplyEmailList( modifier: Modifier = Modifier, navigateToDetail: (Long, ReplyContentType) -> Unit ) { - LazyColumn(modifier = modifier, state = emailLazyListState) { - item { - ReplySearchBar(modifier = Modifier.fillMaxWidth()) - } - items(items = emails, key = { it.id }) { email -> - ReplyEmailListItem( - email = email, - navigateToDetail = { emailId -> - navigateToDetail(emailId, ReplyContentType.SINGLE_PANE) - }, - toggleSelection = toggleEmailSelection, - isOpened = openedEmail?.id == email.id, - isSelected = selectedEmailIds.contains(email.id) - ) + Box(modifier = modifier) { + ReplyDockedSearchBar( + emails = emails, + onSearchItemSelected = { searchedEmail -> + navigateToDetail(searchedEmail.id, ReplyContentType.SINGLE_PANE) + }, + modifier = Modifier + .fillMaxWidth() + .padding(16.dp) + ) + + LazyColumn( + modifier = modifier + .fillMaxWidth() + .padding(top = 80.dp), + state = emailLazyListState + ) { + items(items = emails, key = { it.id }) { email -> + ReplyEmailListItem( + email = email, + navigateToDetail = { emailId -> + navigateToDetail(emailId, ReplyContentType.SINGLE_PANE) + }, + toggleSelection = toggleEmailSelection, + isOpened = openedEmail?.id == email.id, + isSelected = selectedEmailIds.contains(email.id) + ) + } } } } diff --git a/Reply/app/src/main/java/com/example/reply/ui/components/ReplyAppBars.kt b/Reply/app/src/main/java/com/example/reply/ui/components/ReplyAppBars.kt index 81c2ec548..d64d1edbf 100644 --- a/Reply/app/src/main/java/com/example/reply/ui/components/ReplyAppBars.kt +++ b/Reply/app/src/main/java/com/example/reply/ui/components/ReplyAppBars.kt @@ -16,27 +16,37 @@ package com.example.reply.ui.components -import androidx.compose.foundation.background +import androidx.compose.foundation.clickable +import androidx.compose.foundation.layout.Arrangement import androidx.compose.foundation.layout.Column -import androidx.compose.foundation.layout.Row +import androidx.compose.foundation.layout.PaddingValues import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.padding import androidx.compose.foundation.layout.size -import androidx.compose.foundation.shape.CircleShape +import androidx.compose.foundation.lazy.LazyColumn +import androidx.compose.foundation.lazy.items import androidx.compose.material.icons.Icons import androidx.compose.material.icons.filled.ArrowBack import androidx.compose.material.icons.filled.MoreVert import androidx.compose.material.icons.filled.Search +import androidx.compose.material3.DockedSearchBar import androidx.compose.material3.ExperimentalMaterial3Api import androidx.compose.material3.FilledIconButton import androidx.compose.material3.Icon import androidx.compose.material3.IconButton import androidx.compose.material3.IconButtonDefaults +import androidx.compose.material3.ListItem import androidx.compose.material3.MaterialTheme import androidx.compose.material3.Text import androidx.compose.material3.TopAppBar import androidx.compose.material3.TopAppBarDefaults import androidx.compose.runtime.Composable +import androidx.compose.runtime.LaunchedEffect +import androidx.compose.runtime.getValue +import androidx.compose.runtime.mutableStateListOf +import androidx.compose.runtime.mutableStateOf +import androidx.compose.runtime.remember +import androidx.compose.runtime.setValue import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.res.stringResource @@ -46,35 +56,103 @@ import com.example.reply.data.Email @OptIn(ExperimentalMaterial3Api::class) @Composable -fun ReplySearchBar(modifier: Modifier = Modifier) { - Row( - modifier = modifier - .fillMaxWidth() - .padding(top = 24.dp, bottom = 16.dp, start = 16.dp, end = 16.dp) - .background(MaterialTheme.colorScheme.surface, CircleShape), - verticalAlignment = Alignment.CenterVertically +fun ReplyDockedSearchBar( + emails: List, + onSearchItemSelected: (Email) -> Unit, + modifier: Modifier = Modifier +) { + var query by remember { mutableStateOf("") } + var active by remember { mutableStateOf(false) } + val searchResults = remember { mutableStateListOf() } + + LaunchedEffect(query) { + searchResults.clear() + if (query.isNotEmpty()) { + searchResults.addAll(emails.filter { + it.subject.startsWith( + prefix = query, + ignoreCase = true + ) || it.sender.fullName.startsWith( + prefix = + query, ignoreCase = true + ) + }) + } + + } + + DockedSearchBar( + modifier = modifier, + query = query, + onQueryChange = { + query = it + }, + onSearch = { active = false }, + active = active, + onActiveChange = { + active = it + }, + placeholder = { Text(text = stringResource(id = R.string.search_emails)) }, + leadingIcon = { + if (active) { + Icon( + imageVector = Icons.Default.ArrowBack, + contentDescription = stringResource(id = R.string.back_button), + modifier = Modifier + .padding(start = 16.dp) + .clickable { + active = false + query = "" + }, + ) + } else { + Icon( + imageVector = Icons.Default.Search, + contentDescription = stringResource(id = R.string.search), + modifier = Modifier.padding(start = 16.dp), + ) + } + }, + trailingIcon = { + ReplyProfileImage( + drawableResource = R.drawable.avatar_6, + description = stringResource(id = R.string.profile), + modifier = Modifier + .padding(12.dp) + .size(32.dp) + ) + }, ) { - Icon( - imageVector = Icons.Default.Search, - contentDescription = stringResource(id = R.string.search), - modifier = Modifier.padding(start = 16.dp), - tint = MaterialTheme.colorScheme.outline - ) - Text( - text = stringResource(id = R.string.search_replies), - modifier = Modifier - .weight(1f) - .padding(16.dp), - style = MaterialTheme.typography.bodyMedium, - color = MaterialTheme.colorScheme.outline - ) - ReplyProfileImage( - drawableResource = R.drawable.avatar_6, - description = stringResource(id = R.string.profile), - modifier = Modifier - .padding(12.dp) - .size(32.dp) - ) + if (searchResults.isNotEmpty()) { + LazyColumn( + modifier = Modifier.fillMaxWidth(), + contentPadding = PaddingValues(16.dp), + verticalArrangement = Arrangement.spacedBy(4.dp) + ) { + items(items = searchResults, key = { it.id }) { email -> + ListItem( + headlineContent = { Text(email.subject) }, + supportingContent = { Text(email.sender.fullName) }, + leadingContent = { + ReplyProfileImage( + drawableResource = email.sender.avatar, + description = stringResource(id = R.string.profile), + modifier = Modifier + .size(32.dp) + ) + }, + modifier = Modifier.clickable { + onSearchItemSelected.invoke(email) + query = "" + active = false + } + ) + } + } + } else if (query.isNotEmpty()) { + Text(text = stringResource(id = R.string.no_item_found), modifier = Modifier.padding(16.dp)) + } else + Text(text = stringResource(id = R.string.no_search_history), modifier = Modifier.padding(16.dp)) } } diff --git a/Reply/app/src/main/res/values/strings.xml b/Reply/app/src/main/res/values/strings.xml index a23156eab..e5227ea85 100644 --- a/Reply/app/src/main/res/values/strings.xml +++ b/Reply/app/src/main/res/values/strings.xml @@ -18,7 +18,6 @@ Profile Search - Search replies Reply Reply All @@ -32,4 +31,8 @@ More options Messages 4 hrs ago + + Search emails + No item found + No search history \ No newline at end of file diff --git a/Reply/gradle/libs.versions.toml b/Reply/gradle/libs.versions.toml index 72f9d6e27..aa6dcb51b 100644 --- a/Reply/gradle/libs.versions.toml +++ b/Reply/gradle/libs.versions.toml @@ -4,7 +4,7 @@ ##### [versions] accompanist = "0.30.1" -androidGradlePlugin = "8.0.0" +androidGradlePlugin = "8.0.0-alpha11" androidx-activity-compose = "1.7.1" androidx-appcompat = "1.6.1" androidx-benchmark = "1.1.0" From 23ffe41f7ee098fb041b26c003bd669f4d8fa474 Mon Sep 17 00:00:00 2001 From: Gurupreet Singh Date: Wed, 10 May 2023 17:58:11 +0200 Subject: [PATCH 2/6] keep agp version 8.0.0 --- Reply/gradle/libs.versions.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Reply/gradle/libs.versions.toml b/Reply/gradle/libs.versions.toml index aa6dcb51b..72f9d6e27 100644 --- a/Reply/gradle/libs.versions.toml +++ b/Reply/gradle/libs.versions.toml @@ -4,7 +4,7 @@ ##### [versions] accompanist = "0.30.1" -androidGradlePlugin = "8.0.0-alpha11" +androidGradlePlugin = "8.0.0" androidx-activity-compose = "1.7.1" androidx-appcompat = "1.6.1" androidx-benchmark = "1.1.0" From 46376b53bae1dd607a1b5eaf57337e4f3bb84060 Mon Sep 17 00:00:00 2001 From: Gurupreet Singh Date: Wed, 10 May 2023 18:21:23 +0200 Subject: [PATCH 3/6] formatting --- .../com/example/reply/ui/components/ReplyAppBars.kt | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/Reply/app/src/main/java/com/example/reply/ui/components/ReplyAppBars.kt b/Reply/app/src/main/java/com/example/reply/ui/components/ReplyAppBars.kt index d64d1edbf..2691a267d 100644 --- a/Reply/app/src/main/java/com/example/reply/ui/components/ReplyAppBars.kt +++ b/Reply/app/src/main/java/com/example/reply/ui/components/ReplyAppBars.kt @@ -150,9 +150,15 @@ fun ReplyDockedSearchBar( } } } else if (query.isNotEmpty()) { - Text(text = stringResource(id = R.string.no_item_found), modifier = Modifier.padding(16.dp)) + Text( + text = stringResource(id = R.string.no_item_found), + modifier = Modifier.padding(16.dp) + ) } else - Text(text = stringResource(id = R.string.no_search_history), modifier = Modifier.padding(16.dp)) + Text( + text = stringResource(id = R.string.no_search_history), + modifier = Modifier.padding(16.dp) + ) } } From 0a772dff3abdccc4d6c00eb1a8f866288d09bfa7 Mon Sep 17 00:00:00 2001 From: Gurupreet Date: Wed, 10 May 2023 16:25:44 +0000 Subject: [PATCH 4/6] =?UTF-8?q?=F0=9F=A4=96=20Apply=20Spotless?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../reply/ui/components/ReplyAppBars.kt | 22 ++++++++++--------- 1 file changed, 12 insertions(+), 10 deletions(-) diff --git a/Reply/app/src/main/java/com/example/reply/ui/components/ReplyAppBars.kt b/Reply/app/src/main/java/com/example/reply/ui/components/ReplyAppBars.kt index 2691a267d..dc8e42628 100644 --- a/Reply/app/src/main/java/com/example/reply/ui/components/ReplyAppBars.kt +++ b/Reply/app/src/main/java/com/example/reply/ui/components/ReplyAppBars.kt @@ -68,17 +68,19 @@ fun ReplyDockedSearchBar( LaunchedEffect(query) { searchResults.clear() if (query.isNotEmpty()) { - searchResults.addAll(emails.filter { - it.subject.startsWith( - prefix = query, - ignoreCase = true - ) || it.sender.fullName.startsWith( - prefix = - query, ignoreCase = true - ) - }) + searchResults.addAll( + emails.filter { + it.subject.startsWith( + prefix = query, + ignoreCase = true + ) || it.sender.fullName.startsWith( + prefix = + query, + ignoreCase = true + ) + } + ) } - } DockedSearchBar( From 37f16b24a557679cc52791638c10eaf3c307d4c7 Mon Sep 17 00:00:00 2001 From: Gurupreet Singh Date: Wed, 10 May 2023 22:13:10 +0200 Subject: [PATCH 5/6] added 1.1.0 material reelase --- Reply/app/build.gradle.kts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Reply/app/build.gradle.kts b/Reply/app/build.gradle.kts index 7d78765b7..0380987fe 100644 --- a/Reply/app/build.gradle.kts +++ b/Reply/app/build.gradle.kts @@ -102,7 +102,7 @@ dependencies { debugImplementation(libs.androidx.compose.ui.tooling) // Waiting for Compose BOM to contain m3 1.1.0 release - implementation("androidx.compose.material3:material3:1.1.0-rc01") + implementation("androidx.compose.material3:material3:1.1.0") implementation("com.google.accompanist:accompanist-adaptive:0.26.2-beta") implementation(libs.androidx.compose.materialWindow) From fc6f21539720e904b2d0fa2dd799f3d9c48cc852 Mon Sep 17 00:00:00 2001 From: Gurupreet Singh Date: Thu, 11 May 2023 16:42:14 +0200 Subject: [PATCH 6/6] moved m3 to Compose BOM --- Reply/app/build.gradle.kts | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/Reply/app/build.gradle.kts b/Reply/app/build.gradle.kts index 0380987fe..57836241f 100644 --- a/Reply/app/build.gradle.kts +++ b/Reply/app/build.gradle.kts @@ -101,8 +101,7 @@ dependencies { implementation(libs.androidx.compose.ui.tooling.preview) debugImplementation(libs.androidx.compose.ui.tooling) - // Waiting for Compose BOM to contain m3 1.1.0 release - implementation("androidx.compose.material3:material3:1.1.0") + implementation(libs.androidx.compose.material3) implementation("com.google.accompanist:accompanist-adaptive:0.26.2-beta") implementation(libs.androidx.compose.materialWindow)