Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Improvement: Redesign & restructure chat textfield #320

Merged
merged 25 commits into from
Jan 27, 2025
Merged
Changes from 1 commit
Commits
Show all changes
25 commits
Select commit Hold shift + click to select a range
2c27ef9
Fix spacings affected by metisModifier
FelberMartin Jan 18, 2025
4947ff5
Fix spacings in lecture overview
FelberMartin Jan 18, 2025
28b9886
changed send button design and design for UnfocusedPreviewReplyTextField
julian-wls Jan 20, 2025
70ea28c
applied padding changes to thread
julian-wls Jan 20, 2025
d3452a6
redesigned textfield and made it scrollable
julian-wls Jan 22, 2025
755da3d
changed formatting options behavior
julian-wls Jan 22, 2025
db76c2e
added formatting icons
julian-wls Jan 22, 2025
fcef4d6
restructured elements
julian-wls Jan 22, 2025
b40f441
added strikethrough option
julian-wls Jan 22, 2025
5b82b91
added more icons
julian-wls Jan 22, 2025
25e98fe
added file upload button to preview textfield
julian-wls Jan 22, 2025
570bdf6
minor changes
julian-wls Jan 22, 2025
5916563
adjustments
julian-wls Jan 22, 2025
6522639
minor changes
julian-wls Jan 23, 2025
f7c9642
resolved merge conflicts
julian-wls Jan 23, 2025
63a3fda
added requestedAutocompleteType
julian-wls Jan 23, 2025
f78387b
resolved merge conflicts
julian-wls Jan 23, 2025
38bd50c
changed tagging
julian-wls Jan 23, 2025
5da58d7
added icons to autocomplete popup
julian-wls Jan 23, 2025
6bb287a
fixed ui tests
julian-wls Jan 23, 2025
b0afc01
implemented feedback
julian-wls Jan 24, 2025
2d5b112
changed color of plus icon in UnfocusedPreviewReplyTextField
julian-wls Jan 24, 2025
a0107cf
changed paddings
julian-wls Jan 25, 2025
ce00cb4
added box around text field
julian-wls Jan 25, 2025
c064ee0
adjustments
julian-wls Jan 25, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Prev Previous commit
Next Next commit
implemented feedback
julian-wls committed Jan 24, 2025

Verified

This commit was created on GitHub.com and signed with GitHub’s verified signature.
commit b0afc01464d21f11cb12e64d5d029cbf2907bc20
Original file line number Diff line number Diff line change
@@ -47,6 +47,8 @@ import androidx.compose.ui.focus.FocusRequester
import androidx.compose.ui.focus.focusRequester
import androidx.compose.ui.focus.onFocusChanged
import androidx.compose.ui.graphics.SolidColor
import androidx.compose.ui.graphics.painter.Painter
import androidx.compose.ui.graphics.vector.ImageVector
import androidx.compose.ui.platform.LocalDensity
import androidx.compose.ui.platform.testTag
import androidx.compose.ui.res.painterResource
@@ -64,6 +66,7 @@ import kotlinx.coroutines.launch


const val TEST_TAG_MARKDOWN_TEXTFIELD = "TEST_TAG_MARKDOWN_TEXTFIELD"
val textFormattingOptionsHiddenOffsetY = 200.dp

/**
* @param sendButton composable centered vertically right to the text field.
@@ -228,16 +231,10 @@ private fun TextFieldOptions(
onOpenFilePicker: () -> Unit = {},
onOpenImagePicker: () -> Unit = {}
) {
var expanded by remember { mutableStateOf(false) }
val offsetY by animateDpAsState(targetValue = if (expanded) 0.dp else 200.dp)
var isTextFormattingExpanded by remember { mutableStateOf(false) }
val textFormattingOptionsOffsetY by animateDpAsState(targetValue = if (isTextFormattingExpanded) 0.dp else textFormattingOptionsHiddenOffsetY)
var isTaggingDropdownExpanded by remember { mutableStateOf(false) }

val iconButtonModifier = Modifier
.clip(CircleShape)
.size(32.dp)
.background(MaterialTheme.colorScheme.surfaceContainer)
val iconModifier = Modifier.padding(6.dp)

Row(
modifier = modifier.fillMaxWidth(),
verticalAlignment = Alignment.CenterVertically,
@@ -253,123 +250,44 @@ private fun TextFieldOptions(
modifier = modifier,
horizontalArrangement = Arrangement.spacedBy(8.dp)
) {
IconButton(
modifier = iconButtonModifier,
onClick = onOpenImagePicker
TextFieldOptionsIconButton(
modifier = Modifier,
painter = painterResource(id = R.drawable.image),
) {
Icon(
modifier = iconModifier,
painter = painterResource(id = R.drawable.image),
tint = MaterialTheme.colorScheme.primary,
contentDescription = null
)
onOpenImagePicker()
}

IconButton(
modifier = iconButtonModifier,
onClick = onOpenFilePicker
TextFieldOptionsIconButton(
modifier = Modifier,
painter = painterResource(id = R.drawable.attachment)
) {
Icon(
modifier = iconModifier,
painter = painterResource(id = R.drawable.attachment),
tint = MaterialTheme.colorScheme.primary,
contentDescription = null
)
onOpenFilePicker()
}

IconButton(
modifier = iconButtonModifier,
onClick = { expanded = !expanded }
TextFieldOptionsIconButton(
modifier = Modifier,
painter = painterResource(id = R.drawable.format_text)
) {
Icon(
modifier = iconModifier,
painter = painterResource(id = R.drawable.format_text),
tint = MaterialTheme.colorScheme.primary,
contentDescription = null
)
isTextFormattingExpanded = !isTextFormattingExpanded
}

IconButton(
modifier = iconButtonModifier,
onClick = { isTaggingDropdownExpanded = !isTaggingDropdownExpanded }
TextFieldOptionsIconButton(
modifier = Modifier,
painter = painterResource(id = R.drawable.tag)
) {
Icon(
modifier = iconModifier,
painter = painterResource(id = R.drawable.tag),
tint = MaterialTheme.colorScheme.primary,
contentDescription = null
)
isTaggingDropdownExpanded = !isTaggingDropdownExpanded
}
}

DropdownMenu(
expanded = isTaggingDropdownExpanded,
onDismissRequest = { isTaggingDropdownExpanded = false },
properties = PopupProperties(
focusable = false
)
) {
DropdownMenuItem(
leadingIcon = {
Icon(
painter = painterResource(id = R.drawable.tag),
contentDescription = null
)
},
text = { Text(text = stringResource(R.string.reply_format_mention_members)) },
onClick = {
isTaggingDropdownExpanded = false
showAutoCompletePopup?.invoke(AutocompleteType.USERS)
}
)

DropdownMenuItem(
leadingIcon = {
Icon(
imageVector = Icons.Default.Tag,
contentDescription = null
)
},
text = { Text(stringResource(R.string.reply_format_mention_channels)) },
onClick = {
isTaggingDropdownExpanded = false
showAutoCompletePopup?.invoke(AutocompleteType.CHANNELS)
}
)

DropdownMenuItem(
leadingIcon = {
Icon(
imageVector = Icons.AutoMirrored.Filled.ListAlt,
contentDescription = null
)
},
text = { Text(stringResource(R.string.reply_format_mention_exercises)) },
onClick = {
isTaggingDropdownExpanded = false
showAutoCompletePopup?.invoke(AutocompleteType.EXERCISES)
}
)

DropdownMenuItem(
leadingIcon = {
Icon(
imageVector = Icons.Default.School,
contentDescription = null
)
},
text = { Text(stringResource(R.string.reply_format_mention_lectures)) },
onClick = {
isTaggingDropdownExpanded = false
showAutoCompletePopup?.invoke(AutocompleteType.LECTURES)
}
)

}
TaggingDropdownMenu(
isTaggingDropdownExpanded = isTaggingDropdownExpanded,
showAutoCompletePopup = showAutoCompletePopup,
onDismissRequest = { isTaggingDropdownExpanded = false }
)

Box(
modifier = Modifier
.offset(y = offsetY)
.offset(y = textFormattingOptionsOffsetY)
.background(MaterialTheme.colorScheme.background)
) {
Row(
@@ -378,16 +296,11 @@ private fun TextFieldOptions(
verticalAlignment = Alignment.CenterVertically,
horizontalArrangement = Arrangement.spacedBy(8.dp)
) {
IconButton(
modifier = iconButtonModifier,
onClick = { expanded = false }
TextFieldOptionsIconButton(
modifier = Modifier,
imageVector = Icons.Default.Clear
) {
Icon(
modifier = iconModifier,
imageVector = Icons.Default.Clear,
tint = MaterialTheme.colorScheme.primary,
contentDescription = null
)
isTextFormattingExpanded = false
}

formattingOptionButtons()
@@ -398,31 +311,154 @@ private fun TextFieldOptions(
Spacer(modifier = Modifier.weight(1f))
}

Row(
modifier = Modifier.height(32.dp),
verticalAlignment = Alignment.CenterVertically,
horizontalArrangement = Arrangement.spacedBy(8.dp)
) {
InputChip(
selected = selectedType == ViewType.TEXT,
onClick = { onChangeViewType(ViewType.TEXT) },
label = {
Text(text = stringResource(id = R.string.markdown_textfield_tab_text))
}
PreviewEditRow(
modifier = Modifier,
selectedType = selectedType,
isPreviewEnabled = isPreviewEnabled,
onChangeViewType = onChangeViewType
)
}
}

@Composable
private fun TextFieldOptionsIconButton(
modifier: Modifier,
painter: Painter? = null,
imageVector: ImageVector? = null,
onClick: () -> Unit
) {
require(painter != null || imageVector != null)

IconButton(
modifier = modifier
.clip(CircleShape)
.size(32.dp)
.background(MaterialTheme.colorScheme.surfaceContainer),
onClick = onClick
) {
painter?.let {
Icon(
modifier = Modifier.padding(6.dp),
painter = painter,
tint = MaterialTheme.colorScheme.primary,
contentDescription = null
)
return@IconButton
}

InputChip(
selected = selectedType == ViewType.PREVIEW,
onClick = { onChangeViewType(ViewType.PREVIEW) },
enabled = isPreviewEnabled,
label = {
Text(text = stringResource(id = R.string.markdown_textfield_tab_preview))
}
imageVector?.let {
Icon(
modifier = Modifier.padding(6.dp),
imageVector = it,
tint = MaterialTheme.colorScheme.primary,
contentDescription = null
)
}
}
}

@Composable
private fun TaggingDropdownMenu(
isTaggingDropdownExpanded: Boolean,
showAutoCompletePopup: ((AutocompleteType) -> Unit)?,
onDismissRequest: () -> Unit,
) {
DropdownMenu(
expanded = isTaggingDropdownExpanded,
onDismissRequest = onDismissRequest,
properties = PopupProperties(
focusable = false
)
) {
DropdownMenuItem(
leadingIcon = {
Icon(
painter = painterResource(id = R.drawable.tag),
contentDescription = null
)
},
text = { Text(text = stringResource(R.string.reply_format_mention_members)) },
onClick = {
onDismissRequest()
showAutoCompletePopup?.invoke(AutocompleteType.USERS)
}
)

DropdownMenuItem(
leadingIcon = {
Icon(
imageVector = Icons.Default.Tag,
contentDescription = null
)
},
text = { Text(stringResource(R.string.reply_format_mention_channels)) },
onClick = {
onDismissRequest()
showAutoCompletePopup?.invoke(AutocompleteType.CHANNELS)
}
)

DropdownMenuItem(
leadingIcon = {
Icon(
imageVector = Icons.AutoMirrored.Filled.ListAlt,
contentDescription = null
)
},
text = { Text(stringResource(R.string.reply_format_mention_exercises)) },
onClick = {
onDismissRequest()
showAutoCompletePopup?.invoke(AutocompleteType.EXERCISES)
}
)

DropdownMenuItem(
leadingIcon = {
Icon(
imageVector = Icons.Default.School,
contentDescription = null
)
},
text = { Text(stringResource(R.string.reply_format_mention_lectures)) },
onClick = {
onDismissRequest()
showAutoCompletePopup?.invoke(AutocompleteType.LECTURES)
}
)
}
}

@Composable
private fun PreviewEditRow(
modifier: Modifier,
selectedType: ViewType,
isPreviewEnabled: Boolean = false,
onChangeViewType: (ViewType) -> Unit = {}
) {
Row(
modifier = modifier.height(32.dp),
verticalAlignment = Alignment.CenterVertically,
horizontalArrangement = Arrangement.spacedBy(8.dp)
) {
InputChip(
selected = selectedType == ViewType.TEXT,
onClick = { onChangeViewType(ViewType.TEXT) },
label = {
Text(text = stringResource(id = R.string.markdown_textfield_tab_text))
}
)

InputChip(
selected = selectedType == ViewType.PREVIEW,
onClick = { onChangeViewType(ViewType.PREVIEW) },
enabled = isPreviewEnabled,
label = {
Text(text = stringResource(id = R.string.markdown_textfield_tab_preview))
}
)
}
}

private enum class ViewType {
TEXT,
PREVIEW
Loading