diff --git a/core/ui/src/main/res/values-ru/strings.xml b/core/ui/src/main/res/values-ru/strings.xml
index 71ec819b..458b610d 100644
--- a/core/ui/src/main/res/values-ru/strings.xml
+++ b/core/ui/src/main/res/values-ru/strings.xml
@@ -269,6 +269,7 @@
Курсив
Подчёркнутый
Ссылка
+ Обычный
Регистрация
Забыли пароль?
diff --git a/core/ui/src/main/res/values/strings.xml b/core/ui/src/main/res/values/strings.xml
index 02c6ed12..6bc4b50a 100644
--- a/core/ui/src/main/res/values/strings.xml
+++ b/core/ui/src/main/res/values/strings.xml
@@ -345,6 +345,7 @@
Italic
Underline
Link
+ Regular
Sign up
Forgot password?
diff --git a/feature/conversations/src/main/kotlin/dev/meloda/fast/conversations/presentation/ConversationsScreen.kt b/feature/conversations/src/main/kotlin/dev/meloda/fast/conversations/presentation/ConversationsScreen.kt
index 9dd3ef9f..ed63f6d3 100644
--- a/feature/conversations/src/main/kotlin/dev/meloda/fast/conversations/presentation/ConversationsScreen.kt
+++ b/feature/conversations/src/main/kotlin/dev/meloda/fast/conversations/presentation/ConversationsScreen.kt
@@ -106,10 +106,7 @@ fun ConversationsScreen(
onErrorViewButtonClicked: () -> Unit = {}
) {
val currentTheme = LocalThemeConfig.current
-
- val maxLines by remember(currentTheme) {
- mutableIntStateOf(if (currentTheme.enableMultiline) 2 else 1)
- }
+ val maxLines = if (currentTheme.enableMultiline) 2 else 1
val listState = rememberLazyListState(
initialFirstVisibleItemIndex = screenState.scrollIndex,
diff --git a/feature/messageshistory/src/main/kotlin/dev/meloda/fast/messageshistory/MessagesHistoryViewModel.kt b/feature/messageshistory/src/main/kotlin/dev/meloda/fast/messageshistory/MessagesHistoryViewModel.kt
index 0d5f50d4..a225e50d 100644
--- a/feature/messageshistory/src/main/kotlin/dev/meloda/fast/messageshistory/MessagesHistoryViewModel.kt
+++ b/feature/messageshistory/src/main/kotlin/dev/meloda/fast/messageshistory/MessagesHistoryViewModel.kt
@@ -111,6 +111,7 @@ interface MessagesHistoryViewModel {
fun onItalicClicked()
fun onUnderlineClicked()
fun onLinkClicked()
+ fun onRegularClicked()
}
class MessagesHistoryViewModelImpl(
@@ -571,6 +572,11 @@ class MessagesHistoryViewModelImpl(
}
+ override fun onRegularClicked() {
+ formatData = formatData.copy(items = emptyList())
+ updateStyles()
+ }
+
private fun handleNewMessage(event: LongPollParsedEvent.NewMessage) {
val message = event.message
diff --git a/feature/messageshistory/src/main/kotlin/dev/meloda/fast/messageshistory/presentation/MessagesHistoryInputBar.kt b/feature/messageshistory/src/main/kotlin/dev/meloda/fast/messageshistory/presentation/MessagesHistoryInputBar.kt
new file mode 100644
index 00000000..948e1c83
--- /dev/null
+++ b/feature/messageshistory/src/main/kotlin/dev/meloda/fast/messageshistory/presentation/MessagesHistoryInputBar.kt
@@ -0,0 +1,340 @@
+package dev.meloda.fast.messageshistory.presentation
+
+import androidx.compose.animation.animateContentSize
+import androidx.compose.animation.core.Animatable
+import androidx.compose.animation.core.tween
+import androidx.compose.foundation.background
+import androidx.compose.foundation.border
+import androidx.compose.foundation.layout.Arrangement
+import androidx.compose.foundation.layout.Column
+import androidx.compose.foundation.layout.ExperimentalLayoutApi
+import androidx.compose.foundation.layout.Row
+import androidx.compose.foundation.layout.Spacer
+import androidx.compose.foundation.layout.defaultMinSize
+import androidx.compose.foundation.layout.fillMaxWidth
+import androidx.compose.foundation.layout.height
+import androidx.compose.foundation.layout.imeNestedScroll
+import androidx.compose.foundation.layout.imePadding
+import androidx.compose.foundation.layout.navigationBarsPadding
+import androidx.compose.foundation.layout.padding
+import androidx.compose.foundation.layout.width
+import androidx.compose.foundation.shape.RoundedCornerShape
+import androidx.compose.foundation.text.contextmenu.builder.item
+import androidx.compose.foundation.text.contextmenu.modifier.addTextContextMenuComponents
+import androidx.compose.material3.Icon
+import androidx.compose.material3.MaterialTheme
+import androidx.compose.material3.Text
+import androidx.compose.material3.TextField
+import androidx.compose.material3.TextFieldDefaults
+import androidx.compose.material3.surfaceColorAtElevation
+import androidx.compose.runtime.Composable
+import androidx.compose.runtime.remember
+import androidx.compose.runtime.rememberCoroutineScope
+import androidx.compose.ui.Alignment
+import androidx.compose.ui.Modifier
+import androidx.compose.ui.draw.clip
+import androidx.compose.ui.draw.rotate
+import androidx.compose.ui.graphics.Color
+import androidx.compose.ui.layout.onGloballyPositioned
+import androidx.compose.ui.platform.LocalContext
+import androidx.compose.ui.platform.LocalDensity
+import androidx.compose.ui.platform.LocalView
+import androidx.compose.ui.res.painterResource
+import androidx.compose.ui.res.stringResource
+import androidx.compose.ui.text.input.TextFieldValue
+import androidx.compose.ui.text.style.TextOverflow
+import androidx.compose.ui.unit.Dp
+import androidx.compose.ui.unit.dp
+import androidx.core.view.HapticFeedbackConstantsCompat
+import dev.chrisbanes.haze.HazeState
+import dev.chrisbanes.haze.hazeEffect
+import dev.chrisbanes.haze.materials.ExperimentalHazeMaterialsApi
+import dev.chrisbanes.haze.materials.HazeMaterials
+import dev.meloda.fast.datastore.AppSettings
+import dev.meloda.fast.messageshistory.model.ActionMode
+import dev.meloda.fast.ui.components.IconButton
+import dev.meloda.fast.ui.theme.LocalThemeConfig
+import kotlinx.coroutines.launch
+import dev.meloda.fast.ui.R as UiR
+
+@OptIn(ExperimentalLayoutApi::class, ExperimentalHazeMaterialsApi::class)
+@Composable
+fun MessagesHistoryInputBar(
+ modifier: Modifier = Modifier,
+ message: TextFieldValue,
+ hazeState: HazeState,
+ showEmojiButton: Boolean,
+ actionMode: ActionMode,
+ onMessageInputChanged: (TextFieldValue) -> Unit = {},
+ onBoldRequested: () -> Unit = {},
+ onItalicRequested: () -> Unit = {},
+ onUnderlineRequested: () -> Unit = {},
+ onLinkRequested: () -> Unit = {},
+ onRegularRequested: () -> Unit = {},
+ onSetMessageBarHeight: (Dp) -> Unit = {},
+ onEmojiButtonLongClicked: () -> Unit = {},
+ onAttachmentButtonClicked: () -> Unit = {},
+ onActionButtonClicked: () -> Unit = {}
+) {
+ val view = LocalView.current
+ val context = LocalContext.current
+ val density = LocalDensity.current
+
+ val theme = LocalThemeConfig.current
+
+ Column(
+ modifier = modifier
+ .fillMaxWidth()
+ .background(Color.Transparent)
+ .padding(bottom = 8.dp)
+ .navigationBarsPadding()
+ .imePadding()
+ ) {
+ Row(
+ modifier = Modifier
+ .fillMaxWidth()
+ .defaultMinSize(minHeight = 60.dp)
+ .imeNestedScroll(),
+ verticalAlignment = Alignment.CenterVertically
+ ) {
+ Spacer(modifier = Modifier.width(10.dp))
+ Row(
+ modifier = Modifier
+ .clip(RoundedCornerShape(36.dp))
+ .then(
+ if (theme.enableBlur) {
+ Modifier
+ .hazeEffect(
+ state = hazeState,
+ style = HazeMaterials.ultraThin()
+ )
+ .border(
+ 1.dp, MaterialTheme.colorScheme.outlineVariant,
+ RoundedCornerShape(36.dp)
+ )
+ } else Modifier
+ )
+ .animateContentSize()
+ .weight(1f)
+ .background(
+ if (theme.enableBlur) Color.Transparent
+ else MaterialTheme.colorScheme.surfaceColorAtElevation(5.dp)
+ )
+ .onGloballyPositioned {
+ with(density) {
+ onSetMessageBarHeight(it.size.height.toDp())
+ }
+ },
+ verticalAlignment = Alignment.Bottom
+ ) {
+ Spacer(modifier = Modifier.width(6.dp))
+
+ if (showEmojiButton) {
+ val scope = rememberCoroutineScope()
+ val rotation = remember { Animatable(0f) }
+
+ Column(verticalArrangement = Arrangement.Bottom) {
+ IconButton(
+ onClick = {
+ if (AppSettings.General.enableHaptic) {
+ view.performHapticFeedback(
+ HapticFeedbackConstantsCompat.REJECT
+ )
+ }
+ scope.launch {
+ for (i in 20 downTo 0 step 4) {
+ rotation.animateTo(
+ targetValue = i.toFloat(),
+ animationSpec = tween(50)
+ )
+ if (i > 0) {
+ rotation.animateTo(
+ targetValue = -i.toFloat(),
+ animationSpec = tween(50)
+ )
+ }
+ }
+ }
+ },
+ onLongClick = {
+ if (AppSettings.General.enableHaptic) {
+ view.performHapticFeedback(
+ HapticFeedbackConstantsCompat.LONG_PRESS
+ )
+ }
+ onEmojiButtonLongClicked()
+ },
+ modifier = Modifier.rotate(rotation.value)
+ ) {
+ Icon(
+ painter = painterResource(id = UiR.drawable.ic_outline_emoji_emotions_24),
+ contentDescription = "Emoji button",
+ tint = MaterialTheme.colorScheme.primary
+ )
+ }
+
+ Spacer(modifier = Modifier.height(4.dp))
+ }
+ }
+
+ TextField(
+ modifier = modifier
+ .weight(1f)
+ .addTextContextMenuComponents {
+ separator()
+
+ item(
+ key = "Bold",
+ label = context.getString(UiR.string.bold)
+ ) {
+ onBoldRequested()
+ close()
+ }
+ item(
+ key = "Italic",
+ label = context.getString(UiR.string.italic)
+ ) {
+ onItalicRequested()
+ close()
+ }
+ item(
+ key = "Underline",
+ label = context.getString(UiR.string.underline)
+ ) {
+ onUnderlineRequested()
+ close()
+ }
+ item(
+ key = "Link",
+ label = context.getString(UiR.string.link)
+ ) {
+ onLinkRequested()
+ close()
+ }
+ item(
+ key = "Regular",
+ label = context.getString(UiR.string.regular)
+ ) {
+ onRegularRequested()
+ close()
+ }
+
+ separator()
+ },
+ value = message,
+ onValueChange = onMessageInputChanged,
+ colors = TextFieldDefaults.colors(
+ unfocusedContainerColor = Color.Transparent,
+ focusedContainerColor = Color.Transparent,
+ unfocusedIndicatorColor = Color.Transparent,
+ focusedIndicatorColor = Color.Transparent,
+ ),
+ placeholder = {
+ Text(
+ text = stringResource(id = UiR.string.message_input_hint),
+ maxLines = 1,
+ overflow = TextOverflow.Ellipsis
+ )
+ }
+ )
+
+
+ val scope = rememberCoroutineScope()
+ val attachmentRotation = remember { Animatable(0f) }
+
+ Column(verticalArrangement = Arrangement.Bottom) {
+ IconButton(
+ onClick = {
+ onAttachmentButtonClicked()
+ if (AppSettings.General.enableHaptic) {
+ view.performHapticFeedback(
+ HapticFeedbackConstantsCompat.REJECT
+ )
+ }
+ scope.launch {
+ for (i in 20 downTo 0 step 4) {
+ attachmentRotation.animateTo(
+ targetValue = i.toFloat(),
+ animationSpec = tween(50)
+ )
+ if (i > 0) {
+ attachmentRotation.animateTo(
+ targetValue = -i.toFloat(),
+ animationSpec = tween(50)
+ )
+ }
+ }
+ }
+ }
+ ) {
+ Icon(
+ painter = painterResource(id = UiR.drawable.round_attach_file_24),
+ contentDescription = "Add attachment button",
+ tint = MaterialTheme.colorScheme.primary,
+ modifier = Modifier.rotate(30f + attachmentRotation.value)
+ )
+ }
+
+ Spacer(modifier = Modifier.height(4.dp))
+ }
+
+ val micRotation = remember { Animatable(0f) }
+
+ Column(verticalArrangement = Arrangement.Bottom) {
+ IconButton(
+ onClick = {
+ if (actionMode == ActionMode.Record) {
+ if (AppSettings.General.enableHaptic) {
+ view.performHapticFeedback(
+ HapticFeedbackConstantsCompat.REJECT
+ )
+ }
+ scope.launch {
+ for (i in 20 downTo 0 step 4) {
+ micRotation.animateTo(
+ targetValue = i.toFloat(),
+ animationSpec = tween(50)
+ )
+ if (i > 0) {
+ micRotation.animateTo(
+ targetValue = -i.toFloat(),
+ animationSpec = tween(50)
+ )
+ }
+ }
+ }
+ } else {
+ onActionButtonClicked()
+ }
+ },
+ modifier = Modifier.rotate(micRotation.value)
+ ) {
+ Icon(
+ painter = painterResource(
+ id = when (actionMode) {
+ ActionMode.Delete -> UiR.drawable.round_delete_outline_24
+ ActionMode.Edit -> UiR.drawable.ic_round_done_24
+ ActionMode.Record -> UiR.drawable.ic_round_mic_none_24
+ ActionMode.Send -> UiR.drawable.round_send_24
+ }
+ ),
+ contentDescription = when (actionMode) {
+ ActionMode.Delete -> "Delete message button"
+ ActionMode.Edit -> "Edit message button"
+ ActionMode.Record -> "Record audio message button"
+ ActionMode.Send -> "Send message button"
+ },
+ tint = MaterialTheme.colorScheme.primary
+ )
+ }
+
+ Spacer(modifier = Modifier.height(4.dp))
+ }
+
+ Spacer(modifier = Modifier.width(6.dp))
+ }
+
+ Spacer(modifier = Modifier.width(10.dp))
+ }
+ }
+}
diff --git a/feature/messageshistory/src/main/kotlin/dev/meloda/fast/messageshistory/presentation/MessagesHistoryRoute.kt b/feature/messageshistory/src/main/kotlin/dev/meloda/fast/messageshistory/presentation/MessagesHistoryRoute.kt
index 93bf589d..be6c8e78 100644
--- a/feature/messageshistory/src/main/kotlin/dev/meloda/fast/messageshistory/presentation/MessagesHistoryRoute.kt
+++ b/feature/messageshistory/src/main/kotlin/dev/meloda/fast/messageshistory/presentation/MessagesHistoryRoute.kt
@@ -73,7 +73,9 @@ fun MessagesHistoryRoute(
onDeleteSelectedButtonClicked = viewModel::onDeleteSelectedMessagesClicked,
onBoldRequested = viewModel::onBoldClicked,
onItalicRequested = viewModel::onItalicClicked,
- onUnderlineRequested = viewModel::onUnderlineClicked
+ onUnderlineRequested = viewModel::onUnderlineClicked,
+ onLinkRequested = viewModel::onLinkClicked,
+ onRegularRequested = viewModel::onRegularClicked
)
HandleDialogs(
diff --git a/feature/messageshistory/src/main/kotlin/dev/meloda/fast/messageshistory/presentation/MessagesHistoryScreen.kt b/feature/messageshistory/src/main/kotlin/dev/meloda/fast/messageshistory/presentation/MessagesHistoryScreen.kt
index 8b168200..0f10bce2 100644
--- a/feature/messageshistory/src/main/kotlin/dev/meloda/fast/messageshistory/presentation/MessagesHistoryScreen.kt
+++ b/feature/messageshistory/src/main/kotlin/dev/meloda/fast/messageshistory/presentation/MessagesHistoryScreen.kt
@@ -1,62 +1,23 @@
package dev.meloda.fast.messageshistory.presentation
import androidx.activity.compose.BackHandler
-import androidx.compose.animation.AnimatedVisibility
-import androidx.compose.animation.Crossfade
import androidx.compose.animation.animateColorAsState
-import androidx.compose.animation.animateContentSize
-import androidx.compose.animation.core.Animatable
import androidx.compose.animation.core.FastOutLinearInEasing
import androidx.compose.animation.core.animateFloatAsState
import androidx.compose.animation.core.tween
-import androidx.compose.foundation.Image
-import androidx.compose.foundation.background
-import androidx.compose.foundation.border
-import androidx.compose.foundation.clickable
-import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Box
-import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.ExperimentalLayoutApi
-import androidx.compose.foundation.layout.Row
-import androidx.compose.foundation.layout.Spacer
import androidx.compose.foundation.layout.WindowInsets
import androidx.compose.foundation.layout.calculateEndPadding
import androidx.compose.foundation.layout.calculateStartPadding
-import androidx.compose.foundation.layout.defaultMinSize
import androidx.compose.foundation.layout.fillMaxSize
-import androidx.compose.foundation.layout.fillMaxWidth
-import androidx.compose.foundation.layout.height
-import androidx.compose.foundation.layout.imeNestedScroll
-import androidx.compose.foundation.layout.imePadding
-import androidx.compose.foundation.layout.navigationBarsPadding
import androidx.compose.foundation.layout.padding
-import androidx.compose.foundation.layout.size
import androidx.compose.foundation.layout.statusBars
-import androidx.compose.foundation.layout.width
import androidx.compose.foundation.lazy.rememberLazyListState
-import androidx.compose.foundation.shape.CircleShape
-import androidx.compose.foundation.shape.RoundedCornerShape
-import androidx.compose.foundation.text.contextmenu.builder.item
-import androidx.compose.foundation.text.contextmenu.modifier.addTextContextMenuComponents
-import androidx.compose.material.icons.Icons
-import androidx.compose.material.icons.automirrored.rounded.ArrowBack
-import androidx.compose.material.icons.outlined.MoreVert
-import androidx.compose.material.icons.rounded.Close
-import androidx.compose.material.icons.rounded.Refresh
import androidx.compose.material3.CircularProgressIndicator
-import androidx.compose.material3.DropdownMenu
-import androidx.compose.material3.DropdownMenuItem
import androidx.compose.material3.ExperimentalMaterial3Api
-import androidx.compose.material3.HorizontalDivider
-import androidx.compose.material3.Icon
-import androidx.compose.material3.LinearProgressIndicator
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.Scaffold
-import androidx.compose.material3.Text
-import androidx.compose.material3.TextField
-import androidx.compose.material3.TextFieldDefaults
-import androidx.compose.material3.TopAppBar
-import androidx.compose.material3.TopAppBarDefaults
import androidx.compose.material3.surfaceColorAtElevation
import androidx.compose.runtime.Composable
import androidx.compose.runtime.LaunchedEffect
@@ -68,42 +29,25 @@ import androidx.compose.runtime.rememberCoroutineScope
import androidx.compose.runtime.setValue
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
-import androidx.compose.ui.draw.clip
-import androidx.compose.ui.draw.rotate
-import androidx.compose.ui.graphics.Color
-import androidx.compose.ui.graphics.painter.Painter
-import androidx.compose.ui.layout.onGloballyPositioned
import androidx.compose.ui.platform.LocalContext
-import androidx.compose.ui.platform.LocalDensity
import androidx.compose.ui.platform.LocalView
-import androidx.compose.ui.res.painterResource
-import androidx.compose.ui.res.stringResource
import androidx.compose.ui.text.input.TextFieldValue
-import androidx.compose.ui.text.style.TextOverflow
-import androidx.compose.ui.unit.DpOffset
import androidx.compose.ui.unit.LayoutDirection
import androidx.compose.ui.unit.dp
import androidx.core.view.HapticFeedbackConstantsCompat
-import coil.compose.AsyncImage
import dev.chrisbanes.haze.HazeState
-import dev.chrisbanes.haze.hazeEffect
import dev.chrisbanes.haze.materials.ExperimentalHazeMaterialsApi
-import dev.chrisbanes.haze.materials.HazeMaterials
-import dev.meloda.fast.common.extensions.orDots
import dev.meloda.fast.data.UserConfig
import dev.meloda.fast.datastore.AppSettings
-import dev.meloda.fast.messageshistory.model.ActionMode
import dev.meloda.fast.messageshistory.model.MessagesHistoryScreenState
import dev.meloda.fast.messageshistory.model.UiItem
import dev.meloda.fast.messageshistory.util.indexOfMessageByCmId
import dev.meloda.fast.model.BaseError
import dev.meloda.fast.model.api.domain.VkMessage
-import dev.meloda.fast.ui.components.IconButton
import dev.meloda.fast.ui.components.VkErrorView
import dev.meloda.fast.ui.theme.LocalThemeConfig
import dev.meloda.fast.ui.util.ImmutableList
import dev.meloda.fast.ui.util.emptyImmutableList
-import dev.meloda.fast.ui.util.getImage
import kotlinx.coroutines.launch
import dev.meloda.fast.ui.R as UiR
@@ -140,7 +84,9 @@ fun MessagesHistoryScreen(
onDeleteSelectedButtonClicked: () -> Unit = {},
onBoldRequested: () -> Unit = {},
onItalicRequested: () -> Unit = {},
+ onLinkRequested: () -> Unit = {},
onUnderlineRequested: () -> Unit = {},
+ onRegularRequested: () -> Unit = {}
) {
val context = LocalContext.current
val view = LocalView.current
@@ -179,10 +125,6 @@ fun MessagesHistoryScreen(
}
}
- var dropDownMenuExpanded by remember {
- mutableStateOf(false)
- }
-
val topBarContainerColorAlpha by animateFloatAsState(
targetValue = if (!theme.enableBlur || !listState.canScrollBackward) 1f else 0f,
label = "toolbarColorAlpha",
@@ -207,8 +149,6 @@ fun MessagesHistoryScreen(
mutableStateOf(0.dp)
}
- val density = LocalDensity.current
-
val showReplyAction by remember(selectedMessages) {
derivedStateOf { selectedMessages.size == 1 }
}
@@ -217,223 +157,40 @@ fun MessagesHistoryScreen(
modifier = Modifier.fillMaxSize(),
contentWindowInsets = WindowInsets.statusBars,
topBar = {
- Column(
- modifier = Modifier
- .fillMaxWidth()
- .background(topBarContainerColor.copy(alpha = topBarContainerColorAlpha))
- .then(
- if (theme.enableBlur) {
- Modifier.hazeEffect(
- state = hazeState,
- style = HazeMaterials.thick()
- )
- } else Modifier
- )
- ) {
- TopAppBar(
- modifier = Modifier
- .then(
- if (theme.enableBlur) {
- Modifier.hazeEffect(
- state = hazeState,
- style = HazeMaterials.thick()
- )
- } else Modifier
- )
- .fillMaxWidth()
- .then(
- if (screenState.isLoading && messages.isEmpty()) Modifier
- else Modifier.clickable {
- onTopBarClicked()
- }
- ),
- title = {
- Row(
- modifier = Modifier.weight(1f),
- verticalAlignment = Alignment.CenterVertically
- ) {
- if (selectedMessages.isEmpty()) {
- val avatar = screenState.avatar.getImage()
- if (screenState.conversationId == UserConfig.userId) {
- Box(
- modifier = Modifier
- .size(36.dp)
- .clip(CircleShape)
- .background(MaterialTheme.colorScheme.primary)
- ) {
- Icon(
- modifier = Modifier
- .align(Alignment.Center)
- .size(24.dp),
- painter = painterResource(id = UiR.drawable.ic_round_bookmark_border_24),
- contentDescription = "Favorites icon",
- tint = MaterialTheme.colorScheme.onPrimary
- )
- }
- } else {
- if (avatar is Painter) {
- Image(
- painter = avatar,
- contentDescription = null,
- modifier = Modifier
- .size(36.dp)
- .clip(CircleShape)
- )
- } else {
- AsyncImage(
- model = screenState.avatar.getImage(),
- contentDescription = "Profile Image",
- modifier = Modifier
- .size(36.dp)
- .clip(CircleShape),
- placeholder = painterResource(id = UiR.drawable.ic_account_circle_cut),
- )
- }
- }
-
- Spacer(modifier = Modifier.width(12.dp))
- }
-
- Text(
- text = when {
- screenState.isLoading -> stringResource(id = UiR.string.title_loading)
- selectedMessages.isNotEmpty() -> "(${selectedMessages.size})"
- else -> screenState.title
- },
- maxLines = 1,
- overflow = TextOverflow.Ellipsis,
- style = MaterialTheme.typography.headlineSmall
- )
- }
- },
- navigationIcon = {
- IconButton(
- onClick = {
- if (selectedMessages.isEmpty()) onBack()
- else onClose()
- }
- ) {
- Crossfade(targetState = selectedMessages.isEmpty()) { state ->
- Icon(
- imageVector = if (state) {
- Icons.AutoMirrored.Rounded.ArrowBack
- } else {
- Icons.Rounded.Close
- },
- contentDescription = if (state) "Close button"
- else "Back button"
- )
- }
- }
- },
- colors = TopAppBarDefaults.topAppBarColors(containerColor = Color.Transparent),
- actions = {
- if (selectedMessages.isNotEmpty()) {
- AnimatedVisibility(showReplyAction) {
- IconButton(
- onClick = {
- if (AppSettings.General.enableHaptic) {
- view.performHapticFeedback(HapticFeedbackConstantsCompat.REJECT)
- }
- }
- ) {
- Icon(
- painter = painterResource(UiR.drawable.round_reply_24),
- contentDescription = null
- )
- }
- }
- IconButton(
- onClick = {
- if (AppSettings.General.enableHaptic) {
- view.performHapticFeedback(HapticFeedbackConstantsCompat.REJECT)
- }
- }
- ) {
- Icon(
- painter = painterResource(UiR.drawable.round_reply_all_24),
- contentDescription = null
- )
- }
- IconButton(
- onClick = {
- if (AppSettings.General.enableHaptic) {
- view.performHapticFeedback(HapticFeedbackConstantsCompat.REJECT)
- }
- }
- ) {
- Icon(
- painter = painterResource(UiR.drawable.round_forward_24),
- contentDescription = null
- )
- }
- IconButton(onClick = onDeleteSelectedButtonClicked) {
- Icon(
- painter = painterResource(UiR.drawable.round_delete_outline_24),
- contentDescription = null
- )
- }
- } else {
- IconButton(
- onClick = { dropDownMenuExpanded = true }
- ) {
- Icon(
- imageVector = Icons.Outlined.MoreVert,
- contentDescription = "Options"
- )
- }
-
- DropdownMenu(
- modifier = Modifier.defaultMinSize(minWidth = 140.dp),
- expanded = dropDownMenuExpanded,
- onDismissRequest = {
- dropDownMenuExpanded = false
- },
- offset = DpOffset(x = (-4).dp, y = (-60).dp)
- ) {
- DropdownMenuItem(
- onClick = {
- onRefresh()
- dropDownMenuExpanded = false
- },
- text = {
- Text(text = stringResource(UiR.string.action_refresh))
- },
- leadingIcon = {
- Icon(
- imageVector = Icons.Rounded.Refresh,
- contentDescription = null
- )
- }
- )
- }
- }
+ val topBarTitle by remember(screenState, selectedMessages) {
+ derivedStateOf {
+ when {
+ screenState.isLoading -> context.getString(UiR.string.title_loading)
+ selectedMessages.isNotEmpty() -> "(${selectedMessages.size})"
+ else -> screenState.title
}
- )
-
- val showHorizontalProgressBar by remember(screenState) {
- derivedStateOf { screenState.isLoading && messages.isNotEmpty() }
- }
- if (showHorizontalProgressBar) {
- LinearProgressIndicator(modifier = Modifier.fillMaxWidth())
- }
- AnimatedVisibility(!showHorizontalProgressBar) {
- HorizontalDivider()
- }
-
- if (!screenState.isLoading && pinnedMessage != null) {
- PinnedMessageContainer(
- modifier = Modifier,
- pinnedMessage = requireNotNull(pinnedMessage),
- title = screenState.pinnedTitle.orDots(),
- summary = screenState.pinnedSummary,
- canChangePin = screenState.conversation.canChangePin,
- onPinnedMessageClicked = onPinnedMessageClicked,
- onUnpinMessageButtonClicked = onUnpinMessageButtonClicked
- )
- HorizontalDivider()
}
}
+
+ MessagesHistoryTopBarContainer(
+ hazeState = hazeState,
+ showReplyAction = showReplyAction,
+ topBarContainerColor = topBarContainerColor,
+ topBarContainerColorAlpha = topBarContainerColorAlpha,
+ isClickable = !(screenState.isLoading && messages.isEmpty()),
+ isMessagesSelecting = selectedMessages.isNotEmpty(),
+ isPeerAccount = screenState.conversationId == UserConfig.userId,
+ avatar = screenState.avatar,
+ title = topBarTitle,
+ showHorizontalProgressBar = screenState.isLoading && messages.isNotEmpty(),
+ showPinnedContainer = !screenState.isLoading && pinnedMessage != null,
+ pinnedMessage = pinnedMessage,
+ pinnedTitle = screenState.pinnedTitle,
+ pinnedSummary = screenState.pinnedSummary,
+ showUnpinButton = screenState.conversation.canChangePin,
+ onTopBarClicked = onTopBarClicked,
+ onBack = onBack,
+ onClose = onClose,
+ onDeleteSelectedButtonClicked = onDeleteSelectedButtonClicked,
+ onRefresh = onRefresh,
+ onPinnedMessageClicked = onPinnedMessageClicked,
+ onUnpinMessageButtonClicked = onUnpinMessageButtonClicked
+ )
}
) { padding ->
Box(
@@ -472,254 +229,23 @@ fun MessagesHistoryScreen(
onMessageLongClicked = onMessageLongClicked
)
- Column(
- modifier = Modifier
- .fillMaxWidth()
- .align(Alignment.BottomStart)
- .background(Color.Transparent)
- .padding(bottom = 8.dp)
- .navigationBarsPadding()
- .imePadding()
- ) {
- Row(
- modifier = Modifier
- .fillMaxWidth()
- .defaultMinSize(minHeight = 60.dp)
- .imeNestedScroll(),
- verticalAlignment = Alignment.CenterVertically
- ) {
- Spacer(modifier = Modifier.width(10.dp))
- Row(
- modifier = Modifier
- .clip(RoundedCornerShape(36.dp))
- .then(
- if (theme.enableBlur) {
- Modifier
- .hazeEffect(
- state = hazeState,
- style = HazeMaterials.ultraThin()
- )
- .border(
- 1.dp, MaterialTheme.colorScheme.outlineVariant,
- RoundedCornerShape(36.dp)
- )
- } else Modifier
- )
- .animateContentSize()
- .weight(1f)
- .background(
- if (theme.enableBlur) Color.Transparent
- else MaterialTheme.colorScheme.surfaceColorAtElevation(5.dp)
- )
- .onGloballyPositioned {
- messageBarHeight = with(density) {
- it.size.height.toDp()
- }
- },
- verticalAlignment = Alignment.Bottom
- ) {
- Spacer(modifier = Modifier.width(6.dp))
-
- if (showEmojiButton) {
- val scope = rememberCoroutineScope()
- val rotation = remember { Animatable(0f) }
-
- Column(verticalArrangement = Arrangement.Bottom) {
- IconButton(
- onClick = {
- if (AppSettings.General.enableHaptic) {
- view.performHapticFeedback(
- HapticFeedbackConstantsCompat.REJECT
- )
- }
- scope.launch {
- for (i in 20 downTo 0 step 4) {
- rotation.animateTo(
- targetValue = i.toFloat(),
- animationSpec = tween(50)
- )
- if (i > 0) {
- rotation.animateTo(
- targetValue = -i.toFloat(),
- animationSpec = tween(50)
- )
- }
- }
- }
- },
- onLongClick = {
- if (AppSettings.General.enableHaptic) {
- view.performHapticFeedback(
- HapticFeedbackConstantsCompat.LONG_PRESS
- )
- }
- onEmojiButtonLongClicked()
- },
- modifier = Modifier.rotate(rotation.value)
- ) {
- Icon(
- painter = painterResource(id = UiR.drawable.ic_outline_emoji_emotions_24),
- contentDescription = "Emoji button",
- tint = MaterialTheme.colorScheme.primary
- )
- }
-
- Spacer(modifier = Modifier.height(4.dp))
- }
- }
-
- TextField(
- modifier = Modifier
- .weight(1f)
- .addTextContextMenuComponents {
- separator()
-
- item(
- key = "Bold",
- label = context.getString(UiR.string.bold)
- ) {
- onBoldRequested()
- close()
- }
- item(
- key = "Italic",
- label = context.getString(UiR.string.italic)
- ) {
- onItalicRequested()
- close()
- }
- item(
- key = "Underline",
- label = context.getString(UiR.string.underline)
- ) {
- onUnderlineRequested()
- close()
- }
- item(
- key = "Link",
- label = context.getString(UiR.string.link)
- ) {
- close()
- }
-
- separator()
- },
- value = screenState.message,
- onValueChange = onMessageInputChanged,
- colors = TextFieldDefaults.colors(
- unfocusedContainerColor = Color.Transparent,
- focusedContainerColor = Color.Transparent,
- unfocusedIndicatorColor = Color.Transparent,
- focusedIndicatorColor = Color.Transparent,
- ),
- placeholder = {
- Text(
- text = stringResource(id = UiR.string.message_input_hint),
- maxLines = 1,
- overflow = TextOverflow.Ellipsis
- )
- }
- )
-
-
- val scope = rememberCoroutineScope()
- val attachmentRotation = remember { Animatable(0f) }
-
- Column(verticalArrangement = Arrangement.Bottom) {
- IconButton(
- onClick = {
- onAttachmentButtonClicked()
- if (AppSettings.General.enableHaptic) {
- view.performHapticFeedback(
- HapticFeedbackConstantsCompat.REJECT
- )
- }
- scope.launch {
- for (i in 20 downTo 0 step 4) {
- attachmentRotation.animateTo(
- targetValue = i.toFloat(),
- animationSpec = tween(50)
- )
- if (i > 0) {
- attachmentRotation.animateTo(
- targetValue = -i.toFloat(),
- animationSpec = tween(50)
- )
- }
- }
- }
- }
- ) {
- Icon(
- painter = painterResource(id = UiR.drawable.round_attach_file_24),
- contentDescription = "Add attachment button",
- tint = MaterialTheme.colorScheme.primary,
- modifier = Modifier.rotate(30f + attachmentRotation.value)
- )
- }
-
- Spacer(modifier = Modifier.height(4.dp))
- }
-
- val micRotation = remember { Animatable(0f) }
-
- Column(verticalArrangement = Arrangement.Bottom) {
- IconButton(
- onClick = {
- if (screenState.actionMode == ActionMode.Record) {
- if (AppSettings.General.enableHaptic) {
- view.performHapticFeedback(
- HapticFeedbackConstantsCompat.REJECT
- )
- }
- scope.launch {
- for (i in 20 downTo 0 step 4) {
- micRotation.animateTo(
- targetValue = i.toFloat(),
- animationSpec = tween(50)
- )
- if (i > 0) {
- micRotation.animateTo(
- targetValue = -i.toFloat(),
- animationSpec = tween(50)
- )
- }
- }
- }
- } else {
- onActionButtonClicked()
- }
- },
- modifier = Modifier.rotate(micRotation.value)
- ) {
- Icon(
- painter = painterResource(
- id = when (screenState.actionMode) {
- ActionMode.Delete -> UiR.drawable.round_delete_outline_24
- ActionMode.Edit -> UiR.drawable.ic_round_done_24
- ActionMode.Record -> UiR.drawable.ic_round_mic_none_24
- ActionMode.Send -> UiR.drawable.round_send_24
- }
- ),
- contentDescription = when (screenState.actionMode) {
- ActionMode.Delete -> "Delete message button"
- ActionMode.Edit -> "Edit message button"
- ActionMode.Record -> "Record audio message button"
- ActionMode.Send -> "Send message button"
- },
- tint = MaterialTheme.colorScheme.primary
- )
- }
-
- Spacer(modifier = Modifier.height(4.dp))
- }
-
- Spacer(modifier = Modifier.width(6.dp))
- }
-
- Spacer(modifier = Modifier.width(10.dp))
- }
- }
+ MessagesHistoryInputBar(
+ modifier = Modifier.align(Alignment.BottomStart),
+ message = screenState.message,
+ onMessageInputChanged = onMessageInputChanged,
+ onBoldRequested = onBoldRequested,
+ onItalicRequested = onItalicRequested,
+ onUnderlineRequested = onUnderlineRequested,
+ onLinkRequested = onLinkRequested,
+ onRegularRequested = onRegularRequested,
+ hazeState = hazeState,
+ showEmojiButton = showEmojiButton,
+ actionMode = screenState.actionMode,
+ onSetMessageBarHeight = { messageBarHeight = it },
+ onEmojiButtonLongClicked = onEmojiButtonLongClicked,
+ onAttachmentButtonClicked = onAttachmentButtonClicked,
+ onActionButtonClicked = onActionButtonClicked
+ )
when {
screenState.isLoading && messages.values.isEmpty() -> {
diff --git a/feature/messageshistory/src/main/kotlin/dev/meloda/fast/messageshistory/presentation/MessagesHistoryTopBar.kt b/feature/messageshistory/src/main/kotlin/dev/meloda/fast/messageshistory/presentation/MessagesHistoryTopBar.kt
new file mode 100644
index 00000000..47e84dd6
--- /dev/null
+++ b/feature/messageshistory/src/main/kotlin/dev/meloda/fast/messageshistory/presentation/MessagesHistoryTopBar.kt
@@ -0,0 +1,260 @@
+package dev.meloda.fast.messageshistory.presentation
+
+import androidx.compose.animation.AnimatedVisibility
+import androidx.compose.animation.Crossfade
+import androidx.compose.foundation.Image
+import androidx.compose.foundation.background
+import androidx.compose.foundation.clickable
+import androidx.compose.foundation.layout.Box
+import androidx.compose.foundation.layout.Row
+import androidx.compose.foundation.layout.Spacer
+import androidx.compose.foundation.layout.defaultMinSize
+import androidx.compose.foundation.layout.fillMaxWidth
+import androidx.compose.foundation.layout.size
+import androidx.compose.foundation.layout.width
+import androidx.compose.foundation.shape.CircleShape
+import androidx.compose.material.icons.Icons
+import androidx.compose.material.icons.automirrored.rounded.ArrowBack
+import androidx.compose.material.icons.outlined.MoreVert
+import androidx.compose.material.icons.rounded.Close
+import androidx.compose.material.icons.rounded.Refresh
+import androidx.compose.material3.DropdownMenu
+import androidx.compose.material3.DropdownMenuItem
+import androidx.compose.material3.ExperimentalMaterial3Api
+import androidx.compose.material3.Icon
+import androidx.compose.material3.IconButton
+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.getValue
+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.draw.clip
+import androidx.compose.ui.graphics.Color
+import androidx.compose.ui.graphics.painter.Painter
+import androidx.compose.ui.platform.LocalView
+import androidx.compose.ui.res.painterResource
+import androidx.compose.ui.res.stringResource
+import androidx.compose.ui.text.style.TextOverflow
+import androidx.compose.ui.unit.DpOffset
+import androidx.compose.ui.unit.dp
+import androidx.core.view.HapticFeedbackConstantsCompat
+import coil.compose.AsyncImage
+import dev.chrisbanes.haze.HazeState
+import dev.chrisbanes.haze.hazeEffect
+import dev.chrisbanes.haze.materials.ExperimentalHazeMaterialsApi
+import dev.chrisbanes.haze.materials.HazeMaterials
+import dev.meloda.fast.common.model.UiImage
+import dev.meloda.fast.datastore.AppSettings
+import dev.meloda.fast.ui.theme.LocalThemeConfig
+import dev.meloda.fast.ui.util.getImage
+
+import dev.meloda.fast.ui.R as UiR
+
+@OptIn(ExperimentalMaterial3Api::class, ExperimentalHazeMaterialsApi::class)
+@Composable
+fun MessagesHistoryTopBar(
+ modifier: Modifier = Modifier,
+ hazeState: HazeState,
+ showReplyAction: Boolean,
+ isClickable: Boolean,
+ isMessagesSelecting: Boolean,
+ isPeerAccount: Boolean,
+ avatar: UiImage,
+ title: String,
+ onTopBarClicked: () -> Unit = {},
+ onBack: () -> Unit = {},
+ onClose: () -> Unit = {},
+ onDeleteSelectedButtonClicked: () -> Unit = {},
+ onRefresh: () -> Unit = {}
+) {
+ val view = LocalView.current
+ val theme = LocalThemeConfig.current
+
+ var dropDownMenuExpanded by remember {
+ mutableStateOf(false)
+ }
+
+ TopAppBar(
+ modifier = modifier
+ .then(
+ if (theme.enableBlur) {
+ Modifier.hazeEffect(
+ state = hazeState,
+ style = HazeMaterials.thick()
+ )
+ } else Modifier
+ )
+ .fillMaxWidth()
+ .then(
+ if (!isClickable) Modifier
+ else Modifier.clickable {
+ onTopBarClicked()
+ }
+ ),
+ title = {
+ Row(
+// modifier = Modifier.weight(1f),
+ verticalAlignment = Alignment.CenterVertically
+ ) {
+ if (!isMessagesSelecting) {
+ if (isPeerAccount) {
+ Box(
+ modifier = Modifier
+ .size(36.dp)
+ .clip(CircleShape)
+ .background(MaterialTheme.colorScheme.primary)
+ ) {
+ Icon(
+ modifier = Modifier
+ .align(Alignment.Center)
+ .size(24.dp),
+ painter = painterResource(id = UiR.drawable.ic_round_bookmark_border_24),
+ contentDescription = "Favorites icon",
+ tint = MaterialTheme.colorScheme.onPrimary
+ )
+ }
+ } else {
+ val actualAvatar = avatar.getImage()
+
+ if (actualAvatar is Painter) {
+ Image(
+ painter = actualAvatar,
+ contentDescription = null,
+ modifier = Modifier
+ .size(36.dp)
+ .clip(CircleShape)
+ )
+ } else {
+ AsyncImage(
+ model = actualAvatar,
+ contentDescription = "Profile Image",
+ modifier = Modifier
+ .size(36.dp)
+ .clip(CircleShape),
+ placeholder = painterResource(id = UiR.drawable.ic_account_circle_cut),
+ )
+ }
+ }
+
+ Spacer(modifier = Modifier.width(12.dp))
+ }
+
+ Text(
+ text = title,
+ maxLines = 1,
+ overflow = TextOverflow.Ellipsis,
+ style = MaterialTheme.typography.headlineSmall
+ )
+ }
+ },
+ navigationIcon = {
+ IconButton(
+ onClick = {
+ if (!isMessagesSelecting) onBack()
+ else onClose()
+ }
+ ) {
+ Crossfade(targetState = !isMessagesSelecting) { state ->
+ Icon(
+ imageVector = if (state) {
+ Icons.AutoMirrored.Rounded.ArrowBack
+ } else {
+ Icons.Rounded.Close
+ },
+ contentDescription = if (state) "Close button"
+ else "Back button"
+ )
+ }
+ }
+ },
+ colors = TopAppBarDefaults.topAppBarColors(containerColor = Color.Transparent),
+ actions = {
+ if (isMessagesSelecting) {
+ AnimatedVisibility(showReplyAction) {
+ IconButton(
+ onClick = {
+ if (AppSettings.General.enableHaptic) {
+ view.performHapticFeedback(HapticFeedbackConstantsCompat.REJECT)
+ }
+ }
+ ) {
+ Icon(
+ painter = painterResource(UiR.drawable.round_reply_24),
+ contentDescription = null
+ )
+ }
+ }
+ IconButton(
+ onClick = {
+ if (AppSettings.General.enableHaptic) {
+ view.performHapticFeedback(HapticFeedbackConstantsCompat.REJECT)
+ }
+ }
+ ) {
+ Icon(
+ painter = painterResource(UiR.drawable.round_reply_all_24),
+ contentDescription = null
+ )
+ }
+ IconButton(
+ onClick = {
+ if (AppSettings.General.enableHaptic) {
+ view.performHapticFeedback(HapticFeedbackConstantsCompat.REJECT)
+ }
+ }
+ ) {
+ Icon(
+ painter = painterResource(UiR.drawable.round_forward_24),
+ contentDescription = null
+ )
+ }
+ IconButton(onClick = onDeleteSelectedButtonClicked) {
+ Icon(
+ painter = painterResource(UiR.drawable.round_delete_outline_24),
+ contentDescription = null
+ )
+ }
+ } else {
+ IconButton(
+ onClick = { dropDownMenuExpanded = true }
+ ) {
+ Icon(
+ imageVector = Icons.Outlined.MoreVert,
+ contentDescription = "Options"
+ )
+ }
+
+ DropdownMenu(
+ modifier = Modifier.defaultMinSize(minWidth = 140.dp),
+ expanded = dropDownMenuExpanded,
+ onDismissRequest = {
+ dropDownMenuExpanded = false
+ },
+ offset = DpOffset(x = (-4).dp, y = (-60).dp)
+ ) {
+ DropdownMenuItem(
+ onClick = {
+ onRefresh()
+ dropDownMenuExpanded = false
+ },
+ text = {
+ Text(text = stringResource(UiR.string.action_refresh))
+ },
+ leadingIcon = {
+ Icon(
+ imageVector = Icons.Rounded.Refresh,
+ contentDescription = null
+ )
+ }
+ )
+ }
+ }
+ }
+ )
+}
diff --git a/feature/messageshistory/src/main/kotlin/dev/meloda/fast/messageshistory/presentation/MessagesHistoryTopBarContainer.kt b/feature/messageshistory/src/main/kotlin/dev/meloda/fast/messageshistory/presentation/MessagesHistoryTopBarContainer.kt
new file mode 100644
index 00000000..75a51d18
--- /dev/null
+++ b/feature/messageshistory/src/main/kotlin/dev/meloda/fast/messageshistory/presentation/MessagesHistoryTopBarContainer.kt
@@ -0,0 +1,101 @@
+package dev.meloda.fast.messageshistory.presentation
+
+import androidx.compose.animation.AnimatedVisibility
+import androidx.compose.foundation.background
+import androidx.compose.foundation.layout.Column
+import androidx.compose.foundation.layout.fillMaxWidth
+import androidx.compose.material3.ExperimentalMaterial3Api
+import androidx.compose.material3.HorizontalDivider
+import androidx.compose.material3.LinearProgressIndicator
+import androidx.compose.runtime.Composable
+import androidx.compose.ui.Modifier
+import androidx.compose.ui.graphics.Color
+import androidx.compose.ui.text.AnnotatedString
+import dev.chrisbanes.haze.HazeState
+import dev.chrisbanes.haze.hazeEffect
+import dev.chrisbanes.haze.materials.ExperimentalHazeMaterialsApi
+import dev.chrisbanes.haze.materials.HazeMaterials
+import dev.meloda.fast.common.extensions.orDots
+import dev.meloda.fast.common.model.UiImage
+import dev.meloda.fast.model.api.domain.VkMessage
+import dev.meloda.fast.ui.theme.LocalThemeConfig
+
+@OptIn(ExperimentalHazeMaterialsApi::class, ExperimentalMaterial3Api::class)
+@Composable
+fun MessagesHistoryTopBarContainer(
+ modifier: Modifier = Modifier,
+ hazeState: HazeState,
+ showReplyAction: Boolean,
+ topBarContainerColor: Color,
+ topBarContainerColorAlpha: Float,
+ isClickable: Boolean,
+ isMessagesSelecting: Boolean,
+ isPeerAccount: Boolean,
+ avatar: UiImage,
+ title: String,
+ showHorizontalProgressBar: Boolean,
+ showPinnedContainer: Boolean,
+ pinnedMessage: VkMessage?,
+ pinnedTitle: String?,
+ pinnedSummary: AnnotatedString?,
+ showUnpinButton: Boolean,
+ onTopBarClicked: () -> Unit = {},
+ onBack: () -> Unit = {},
+ onClose: () -> Unit = {},
+ onDeleteSelectedButtonClicked: () -> Unit = {},
+ onRefresh: () -> Unit = {},
+ onPinnedMessageClicked: (Long) -> Unit = {},
+ onUnpinMessageButtonClicked: () -> Unit = {}
+) {
+ val theme = LocalThemeConfig.current
+
+ Column(
+ modifier = modifier
+ .fillMaxWidth()
+ .background(topBarContainerColor.copy(alpha = topBarContainerColorAlpha))
+ .then(
+ if (theme.enableBlur) {
+ Modifier.hazeEffect(
+ state = hazeState,
+ style = HazeMaterials.thick()
+ )
+ } else Modifier
+ )
+ ) {
+ MessagesHistoryTopBar(
+ modifier = modifier,
+ hazeState = hazeState,
+ showReplyAction = showReplyAction,
+ isClickable = isClickable,
+ isMessagesSelecting = isMessagesSelecting,
+ isPeerAccount = isPeerAccount,
+ avatar = avatar,
+ title = title,
+ onTopBarClicked = onTopBarClicked,
+ onBack = onBack,
+ onClose = onClose,
+ onDeleteSelectedButtonClicked = onDeleteSelectedButtonClicked,
+ onRefresh = onRefresh
+ )
+
+ if (showHorizontalProgressBar) {
+ LinearProgressIndicator(modifier = Modifier.fillMaxWidth())
+ }
+ AnimatedVisibility(!showHorizontalProgressBar) {
+ HorizontalDivider()
+ }
+
+ if (showPinnedContainer) {
+ PinnedMessageContainer(
+ modifier = Modifier,
+ pinnedMessage = requireNotNull(pinnedMessage),
+ title = pinnedTitle.orDots(),
+ summary = pinnedSummary,
+ canChangePin = showUnpinButton,
+ onPinnedMessageClicked = onPinnedMessageClicked,
+ onUnpinMessageButtonClicked = onUnpinMessageButtonClicked
+ )
+ HorizontalDivider()
+ }
+ }
+}