Skip to content

Commit 075fc63

Browse files
authored
Communication: Improve auto completion for tagging users and channels (#76)
1 parent 1d9afac commit 075fc63

File tree

6 files changed

+60
-25
lines changed

6 files changed

+60
-25
lines changed

app/src/main/java/de/tum/informatics/www1/artemis/native_app/android/ui/Color.kt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -61,7 +61,7 @@ val md_theme_dark_inverseSurface = Color(0xFFE2E2E5)
6161
val md_theme_dark_inversePrimary = Color(0xFF006398)
6262
val md_theme_dark_shadow = Color(0xFF000000)
6363
val md_theme_dark_surfaceTint = Color(0xFF93CCFF)
64-
val md_theme_dark_outlineVariant = Color(0xFF42474E)
64+
val md_theme_dark_outlineVariant = Color(0xFF55515B)
6565
val md_theme_dark_scrim = Color(0xFF000000)
6666

6767

feature/metis/conversation/src/main/kotlin/de/tum/informatics/www1/artemis/native_app/feature/metis/conversation/ui/ConversationViewModel.kt

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -488,7 +488,7 @@ internal open class ConversationViewModel(
488488
val exerciseAutoCompleteItems =
489489
course
490490
.exercises
491-
.filter { query in it.title.orEmpty() }
491+
.filter { it.title.orEmpty().contains(query, ignoreCase = true) }
492492
.mapNotNull { exercise ->
493493
val exerciseTag = when (exercise) {
494494
is FileUploadExercise -> "file-upload"
@@ -538,7 +538,7 @@ internal open class ConversationViewModel(
538538
conversationsDataState.bind { conversations ->
539539
val conversationAutoCompleteItems = conversations
540540
.filterIsInstance<ChannelChat>()
541-
.filter { query in it.name }
541+
.filter { it.name.contains(query, ignoreCase = true) }
542542
.map { channel ->
543543
AutoCompleteHint(
544544
hint = channel.name,

feature/metis/conversation/src/main/kotlin/de/tum/informatics/www1/artemis/native_app/feature/metis/conversation/ui/reply/ReplyAutoCompletePopup.kt

Lines changed: 16 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -11,30 +11,36 @@ import androidx.compose.foundation.layout.heightIn
1111
import androidx.compose.foundation.layout.padding
1212
import androidx.compose.foundation.layout.width
1313
import androidx.compose.foundation.lazy.LazyColumn
14-
import androidx.compose.foundation.shape.RoundedCornerShape
1514
import androidx.compose.material3.Divider
1615
import androidx.compose.material3.MaterialTheme
1716
import androidx.compose.material3.Text
1817
import androidx.compose.runtime.Composable
1918
import androidx.compose.ui.Modifier
19+
import androidx.compose.ui.draw.clip
20+
import androidx.compose.ui.platform.testTag
2021
import androidx.compose.ui.res.stringResource
2122
import androidx.compose.ui.text.style.TextAlign
2223
import androidx.compose.ui.tooling.preview.Preview
2324
import androidx.compose.ui.unit.Dp
2425
import androidx.compose.ui.unit.dp
26+
import androidx.compose.ui.unit.min
2527
import androidx.compose.ui.util.fastForEachIndexed
2628
import androidx.compose.ui.window.Popup
2729
import androidx.compose.ui.window.PopupPositionProvider
2830
import androidx.compose.ui.window.PopupProperties
2931
import de.tum.informatics.www1.artemis.native_app.feature.metis.conversation.R
3032

33+
const val TEST_TAG_REPLY_AUTO_COMPLETE_POPUP_LIST = "TEST_TAG_REPLY_AUTO_COMPLETE_POPUP_LIST"
34+
3135
private val HintHorizontalPadding = 16.dp
36+
private val PopupVerticalPadding = 8.dp
37+
private val AutoCompletionDialogMaxHeight = 270.dp
3238

3339
@Composable
3440
internal fun ReplyAutoCompletePopup(
3541
popupPositionProvider: PopupPositionProvider,
3642
targetWidth: Dp,
37-
maxHeight: Dp,
43+
maxHeightFromScreen: Dp,
3844
autoCompleteCategories: List<AutoCompleteCategory>,
3945
performAutoComplete: (replacement: String) -> Unit,
4046
onDismissRequest: () -> Unit
@@ -44,9 +50,11 @@ internal fun ReplyAutoCompletePopup(
4450
properties = PopupProperties(dismissOnClickOutside = true),
4551
onDismissRequest = onDismissRequest
4652
) {
53+
val maxHeight = min(maxHeightFromScreen, AutoCompletionDialogMaxHeight)
4754
ReplyAutoCompletePopupBody(
4855
modifier = Modifier
49-
.heightIn(max = maxHeight)
56+
.padding(vertical = PopupVerticalPadding)
57+
.heightIn(max = maxHeight - PopupVerticalPadding * 2)
5058
.width(targetWidth),
5159
autoCompleteCategories = autoCompleteCategories,
5260
performAutoComplete = performAutoComplete
@@ -62,12 +70,12 @@ private fun ReplyAutoCompletePopupBody(
6270
) {
6371
LazyColumn(
6472
modifier = modifier
65-
.background(
66-
color = MaterialTheme.colorScheme.surfaceVariant,
67-
shape = RoundedCornerShape(topStart = 45f, topEnd = 45f)
68-
)
69-
.padding(top = 8.dp)
73+
.clip(MaterialTheme.shapes.large)
74+
.background(color = MaterialTheme.colorScheme.surfaceVariant)
75+
.padding(8.dp)
76+
.testTag(TEST_TAG_REPLY_AUTO_COMPLETE_POPUP_LIST)
7077
) {
78+
7179
autoCompleteCategories.forEachIndexed { categoryIndex, category ->
7280
item {
7381
AutoCompleteCategoryComposable(

feature/metis/conversation/src/main/kotlin/de/tum/informatics/www1/artemis/native_app/feature/metis/conversation/ui/reply/ReplyTextField.kt

Lines changed: 36 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -2,15 +2,37 @@ package de.tum.informatics.www1.artemis.native_app.feature.metis.conversation.ui
22

33
import androidx.compose.animation.AnimatedContent
44
import androidx.compose.foundation.clickable
5-
import androidx.compose.foundation.layout.*
6-
import androidx.compose.foundation.shape.RoundedCornerShape
5+
import androidx.compose.foundation.layout.Arrangement
6+
import androidx.compose.foundation.layout.Box
7+
import androidx.compose.foundation.layout.Column
8+
import androidx.compose.foundation.layout.IntrinsicSize
9+
import androidx.compose.foundation.layout.Row
10+
import androidx.compose.foundation.layout.defaultMinSize
11+
import androidx.compose.foundation.layout.fillMaxSize
12+
import androidx.compose.foundation.layout.fillMaxWidth
13+
import androidx.compose.foundation.layout.height
14+
import androidx.compose.foundation.layout.padding
15+
import androidx.compose.foundation.layout.size
716
import androidx.compose.material.icons.Icons
817
import androidx.compose.material.icons.filled.Cancel
918
import androidx.compose.material.icons.filled.Done
1019
import androidx.compose.material.icons.filled.Edit
1120
import androidx.compose.material.icons.filled.Send
12-
import androidx.compose.material3.*
13-
import androidx.compose.runtime.*
21+
import androidx.compose.material3.CircularProgressIndicator
22+
import androidx.compose.material3.Icon
23+
import androidx.compose.material3.IconButton
24+
import androidx.compose.material3.LocalContentColor
25+
import androidx.compose.material3.MaterialTheme
26+
import androidx.compose.material3.Surface
27+
import androidx.compose.material3.Text
28+
import androidx.compose.runtime.Composable
29+
import androidx.compose.runtime.LaunchedEffect
30+
import androidx.compose.runtime.collectAsState
31+
import androidx.compose.runtime.getValue
32+
import androidx.compose.runtime.mutableIntStateOf
33+
import androidx.compose.runtime.mutableStateOf
34+
import androidx.compose.runtime.remember
35+
import androidx.compose.runtime.setValue
1436
import androidx.compose.ui.Alignment
1537
import androidx.compose.ui.Modifier
1638
import androidx.compose.ui.focus.FocusRequester
@@ -58,7 +80,7 @@ internal fun ReplyTextField(
5880
Surface(
5981
modifier = modifier.defaultMinSize(minHeight = 48.dp),
6082
color = MaterialTheme.colorScheme.surfaceVariant,
61-
shape = RoundedCornerShape(5)
83+
shape = MaterialTheme.shapes.large
6284
) {
6385
Box(
6486
modifier = Modifier
@@ -173,14 +195,16 @@ private fun CreateReplyUi(
173195
val autoCompleteHints = manageAutoCompleteHints(currentTextFieldValue)
174196

175197
var textFieldWidth by remember { mutableIntStateOf(0) }
176-
var popupMaxHeight by remember { mutableStateOf(0) }
198+
var popupMaxHeight by remember { mutableIntStateOf(0) }
177199

178-
if (autoCompleteHints.orEmpty().flatMap { it.items }
179-
.isNotEmpty() && mayShowAutoCompletePopup) {
200+
val showAutoCompletePopup = mayShowAutoCompletePopup
201+
&& autoCompleteHints.orEmpty().flatMap { it.items }.isNotEmpty()
202+
203+
if (showAutoCompletePopup) {
180204
ReplyAutoCompletePopup(
181205
autoCompleteCategories = autoCompleteHints.orEmpty(),
182206
targetWidth = with(LocalDensity.current) { textFieldWidth.toDp() },
183-
maxHeight = with(LocalDensity.current) { popupMaxHeight.toDp() },
207+
maxHeightFromScreen = with(LocalDensity.current) { popupMaxHeight.toDp() },
184208
popupPositionProvider = ReplyAutoCompletePopupPositionProvider,
185209
performAutoComplete = { replacement ->
186210
replyMode.onUpdate(
@@ -201,11 +225,11 @@ private fun CreateReplyUi(
201225
modifier = Modifier
202226
.fillMaxWidth()
203227
.onSizeChanged { textFieldWidth = it.width }
204-
.padding(vertical = 8.dp, horizontal = 8.dp)
205228
.onGloballyPositioned { coordinates ->
206-
val textFieldWindowTopLeft = coordinates.localToWindow(Offset.Zero)
207-
popupMaxHeight = textFieldWindowTopLeft.y.toInt()
229+
val textFieldRootTopLeft = coordinates.localToRoot(Offset.Zero)
230+
popupMaxHeight = textFieldRootTopLeft.y.toInt()
208231
}
232+
.padding(8.dp)
209233
.testTag(TEST_TAG_REPLY_TEXT_FIELD),
210234
textFieldValue = currentTextFieldValue,
211235
onTextChanged = replyMode::onUpdate,

feature/metis/conversation/src/test/kotlin/de/tum/informatics/www1/artemis/native_app/feature/metis/conversation/ui/reply/ReplyTextFieldUiTest.kt

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,9 +10,10 @@ import androidx.compose.ui.test.junit4.ComposeContentTestRule
1010
import androidx.compose.ui.test.junit4.createComposeRule
1111
import androidx.compose.ui.test.onNodeWithTag
1212
import androidx.compose.ui.test.onNodeWithText
13-
import androidx.compose.ui.test.performTextInput
1413
import androidx.compose.ui.test.performClick
14+
import androidx.compose.ui.test.performScrollToIndex
1515
import androidx.compose.ui.test.performTextClearance
16+
import androidx.compose.ui.test.performTextInput
1617
import androidx.compose.ui.text.input.TextFieldValue
1718
import androidx.test.ext.junit.runners.AndroidJUnit4
1819
import de.tum.informatics.www1.artemis.native_app.core.data.DataState
@@ -140,7 +141,9 @@ class ReplyTextFieldUiTest {
140141

141142
private fun ComposeContentTestRule.assertAllAutoCompletionHintsShown() {
142143
onNodeWithText("User1").assertExists()
144+
onNodeWithTag(TEST_TAG_REPLY_AUTO_COMPLETE_POPUP_LIST).performScrollToIndex(1)
143145
onNodeWithText("User2").assertExists()
146+
onNodeWithTag(TEST_TAG_REPLY_AUTO_COMPLETE_POPUP_LIST).performScrollToIndex(2)
144147
onNodeWithText("User3").assertExists()
145148
}
146149
}

gradle/libs.versions.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
[versions]
22
compileSdk = "35"
33
targetSdk = "34"
4-
minSdk = "31"
4+
minSdk = "30"
55
buildToolsVersion = "35.0.0"
66

77
accompanist = "0.30.1"

0 commit comments

Comments
 (0)