From f7406069b1987a7aca93c3de5828967a8113ea46 Mon Sep 17 00:00:00 2001 From: Evgenii Kozlov Date: Thu, 19 Dec 2024 16:42:45 +0100 Subject: [PATCH] DROID-2966 Chats | Fix | Misc. chat fixes (#1942) --- .../di/feature/discussions/DiscussionsDI.kt | 2 + .../anytype/ui/home/HomeScreenFragment.kt | 4 +- .../anytype/ui/home/HomeScreenToolbar.kt | 71 ++++++++--- .../res/drawable/ic_home_toolbar_widgets.xml | 2 +- .../presentation/DiscussionView.kt | 3 +- .../presentation/DiscussionViewModel.kt | 13 +- .../DiscussionViewModelFactory.kt | 7 +- .../ui/DiscussionPreviews.kt | 3 +- .../ui/DiscussionScreen.kt | 117 +++++++++--------- gradle/libs.versions.toml | 2 +- 10 files changed, 143 insertions(+), 81 deletions(-) diff --git a/app/src/main/java/com/anytypeio/anytype/di/feature/discussions/DiscussionsDI.kt b/app/src/main/java/com/anytypeio/anytype/di/feature/discussions/DiscussionsDI.kt index 421c5b9aa8..3ba632cbd3 100644 --- a/app/src/main/java/com/anytypeio/anytype/di/feature/discussions/DiscussionsDI.kt +++ b/app/src/main/java/com/anytypeio/anytype/di/feature/discussions/DiscussionsDI.kt @@ -16,6 +16,7 @@ import com.anytypeio.anytype.domain.misc.UrlBuilder import com.anytypeio.anytype.domain.multiplayer.ActiveSpaceMemberSubscriptionContainer import com.anytypeio.anytype.domain.multiplayer.SpaceViewSubscriptionContainer import com.anytypeio.anytype.domain.multiplayer.UserPermissionProvider +import com.anytypeio.anytype.domain.objects.StoreOfObjectTypes import com.anytypeio.anytype.feature_discussions.presentation.DiscussionViewModel import com.anytypeio.anytype.feature_discussions.presentation.DiscussionViewModelFactory import com.anytypeio.anytype.middleware.EventProxy @@ -91,4 +92,5 @@ interface DiscussionComponentDependencies : ComponentDependencies { fun logger(): Logger fun members(): ActiveSpaceMemberSubscriptionContainer fun spaceViewSubscriptionContainer(): SpaceViewSubscriptionContainer + fun storeOfObjectTypes(): StoreOfObjectTypes } \ No newline at end of file diff --git a/app/src/main/java/com/anytypeio/anytype/ui/home/HomeScreenFragment.kt b/app/src/main/java/com/anytypeio/anytype/ui/home/HomeScreenFragment.kt index c26f0bf139..e6c433fff2 100644 --- a/app/src/main/java/com/anytypeio/anytype/ui/home/HomeScreenFragment.kt +++ b/app/src/main/java/com/anytypeio/anytype/ui/home/HomeScreenFragment.kt @@ -161,7 +161,9 @@ class HomeScreenFragment : BaseComposeFragment(), pagerState.animateScrollToPage(1) } }, - onSpaceIconClicked = vm::onSpaceSettingsClicked + onSpaceIconClicked = vm::onSpaceSettingsClicked, + membersCount = view?.membersCount ?: 0, + name = view?.space?.name.orEmpty() ) HorizontalPager( modifier = Modifier diff --git a/app/src/main/java/com/anytypeio/anytype/ui/home/HomeScreenToolbar.kt b/app/src/main/java/com/anytypeio/anytype/ui/home/HomeScreenToolbar.kt index be16445b42..731c0ef537 100644 --- a/app/src/main/java/com/anytypeio/anytype/ui/home/HomeScreenToolbar.kt +++ b/app/src/main/java/com/anytypeio/anytype/ui/home/HomeScreenToolbar.kt @@ -9,16 +9,22 @@ import androidx.compose.foundation.layout.height import androidx.compose.foundation.layout.padding import androidx.compose.foundation.layout.size import androidx.compose.foundation.layout.systemBarsPadding +import androidx.compose.material3.Text import androidx.compose.runtime.Composable import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.draw.alpha import androidx.compose.ui.graphics.Color +import androidx.compose.ui.res.colorResource import androidx.compose.ui.res.painterResource +import androidx.compose.ui.res.pluralStringResource +import androidx.compose.ui.res.stringResource import androidx.compose.ui.unit.dp import com.anytypeio.anytype.core_ui.common.DefaultPreviews import com.anytypeio.anytype.core_ui.features.SpaceIconView import com.anytypeio.anytype.core_ui.foundation.noRippleClickable +import com.anytypeio.anytype.core_ui.views.PreviewTitle2Medium +import com.anytypeio.anytype.core_ui.views.Relations3 import com.anytypeio.anytype.feature_discussions.R import com.anytypeio.anytype.presentation.spaces.SpaceIconView @@ -28,7 +34,9 @@ fun HomeScreenToolbar( isChatActive: Boolean, onWidgetTabClicked: () -> Unit, onChatTabClicked: () -> Unit, - onSpaceIconClicked: () -> Unit + onSpaceIconClicked: () -> Unit, + name: String, + membersCount: Int ) { Box( modifier = Modifier @@ -38,11 +46,53 @@ fun HomeScreenToolbar( .padding(horizontal = 20.dp) ) { - Image( - painter = painterResource(id = R.drawable.ic_home_toolbar_widgets), + + SpaceIconView( modifier = Modifier + .align(Alignment.CenterStart), + icon = spaceIconView, + onSpaceIconClick = { + onSpaceIconClicked() + }, + mainSize = 40.dp + ) + + Text( + text = name.ifEmpty { stringResource(R.string.untitled) }, + style = PreviewTitle2Medium, + color = colorResource(R.color.text_primary), + modifier = Modifier.padding( + start = 52.dp, + top = 13.dp + ) + ) + + Text( + text = if (membersCount > 0 ) { + pluralStringResource( + id = R.plurals.multiplayer_number_of_space_members, + membersCount, + membersCount, + membersCount + ) + } else + stringResource(id = R.string.three_dots_text_placeholder), + style = Relations3, + color = colorResource(R.color.text_secondary), + modifier = Modifier + .align(Alignment.BottomStart) + .padding( + start = 52.dp, + bottom = 13.dp + ) + ) + + Image( + painter = painterResource(id = R.drawable.ic_home_toolbar_widgets), + modifier = Modifier + .padding(end = 48.dp) .size(32.dp) - .align(Alignment.CenterStart) + .align(Alignment.CenterEnd) .alpha( if (isChatActive) 0.5f else 1f ) @@ -52,15 +102,6 @@ fun HomeScreenToolbar( contentDescription = "Widgets button" ) - SpaceIconView( - modifier = Modifier.align(Alignment.Center), - icon = spaceIconView, - onSpaceIconClick = { - onSpaceIconClicked() - }, - mainSize = 40.dp - ) - Image( painter = painterResource(id = R.drawable.ic_home_toolbar_chat), modifier = Modifier @@ -85,6 +126,8 @@ fun HomeScreenToolbarPreview() { onChatTabClicked = {}, isChatActive = false, spaceIconView = SpaceIconView.Loading, - onSpaceIconClicked = {} + onSpaceIconClicked = {}, + membersCount = 74, + name = "Test space" ) } diff --git a/core-ui/src/main/res/drawable/ic_home_toolbar_widgets.xml b/core-ui/src/main/res/drawable/ic_home_toolbar_widgets.xml index 5c4863b11c..77056d7086 100644 --- a/core-ui/src/main/res/drawable/ic_home_toolbar_widgets.xml +++ b/core-ui/src/main/res/drawable/ic_home_toolbar_widgets.xml @@ -4,7 +4,7 @@ android:viewportWidth="32" android:viewportHeight="32"> diff --git a/feature-discussions/src/main/java/com/anytypeio/anytype/feature_discussions/presentation/DiscussionView.kt b/feature-discussions/src/main/java/com/anytypeio/anytype/feature_discussions/presentation/DiscussionView.kt index 3aa8b2df3e..afc6f8b25e 100644 --- a/feature-discussions/src/main/java/com/anytypeio/anytype/feature_discussions/presentation/DiscussionView.kt +++ b/feature-discussions/src/main/java/com/anytypeio/anytype/feature_discussions/presentation/DiscussionView.kt @@ -51,7 +51,8 @@ sealed interface DiscussionView { data class Link( val target: Id, val wrapper: ObjectWrapper.Basic?, - val icon: ObjectIcon = ObjectIcon.None + val icon: ObjectIcon = ObjectIcon.None, + val typeName: String ): Attachment() } diff --git a/feature-discussions/src/main/java/com/anytypeio/anytype/feature_discussions/presentation/DiscussionViewModel.kt b/feature-discussions/src/main/java/com/anytypeio/anytype/feature_discussions/presentation/DiscussionViewModel.kt index c400fe7368..cc709fdbdf 100644 --- a/feature-discussions/src/main/java/com/anytypeio/anytype/feature_discussions/presentation/DiscussionViewModel.kt +++ b/feature-discussions/src/main/java/com/anytypeio/anytype/feature_discussions/presentation/DiscussionViewModel.kt @@ -28,12 +28,14 @@ import com.anytypeio.anytype.domain.multiplayer.ActiveSpaceMemberSubscriptionCon import com.anytypeio.anytype.domain.multiplayer.SpaceViewSubscriptionContainer import com.anytypeio.anytype.domain.`object`.OpenObject import com.anytypeio.anytype.domain.`object`.SetObjectDetails +import com.anytypeio.anytype.domain.objects.StoreOfObjectTypes import com.anytypeio.anytype.presentation.common.BaseViewModel import com.anytypeio.anytype.presentation.home.OpenObjectNavigation import com.anytypeio.anytype.presentation.home.navigation import com.anytypeio.anytype.presentation.mapper.objectIcon import com.anytypeio.anytype.presentation.objects.ObjectIcon import com.anytypeio.anytype.presentation.search.GlobalSearchItemView +import java.sql.Types import javax.inject.Inject import kotlinx.coroutines.delay import kotlinx.coroutines.flow.MutableSharedFlow @@ -58,7 +60,8 @@ class DiscussionViewModel @Inject constructor( private val urlBuilder: UrlBuilder, private val spaceViews: SpaceViewSubscriptionContainer, private val dispatchers: AppCoroutineDispatchers, - private val uploadFile: UploadFile + private val uploadFile: UploadFile, + private val storeOfObjectTypes: StoreOfObjectTypes ) : BaseViewModel() { val name = MutableStateFlow(null) @@ -192,7 +195,6 @@ class DiscussionViewModel @Inject constructor( target = attachment.target, url = urlBuilder.medium(path = attachment.target) ) - else -> { val wrapper = dependencies[attachment.target] if (wrapper?.layout == ObjectType.Layout.IMAGE) { @@ -201,10 +203,15 @@ class DiscussionViewModel @Inject constructor( url = urlBuilder.large(path = attachment.target) ) } else { + val type = wrapper?.type?.firstOrNull() DiscussionView.Message.Attachment.Link( target = attachment.target, wrapper = wrapper, - icon = wrapper?.objectIcon(urlBuilder) ?: ObjectIcon.None + icon = wrapper?.objectIcon(urlBuilder) ?: ObjectIcon.None, + typeName = if (type != null) + storeOfObjectTypes.get(type)?.name.orEmpty() + else + "" ) } } diff --git a/feature-discussions/src/main/java/com/anytypeio/anytype/feature_discussions/presentation/DiscussionViewModelFactory.kt b/feature-discussions/src/main/java/com/anytypeio/anytype/feature_discussions/presentation/DiscussionViewModelFactory.kt index d7756ae0ea..61df433255 100644 --- a/feature-discussions/src/main/java/com/anytypeio/anytype/feature_discussions/presentation/DiscussionViewModelFactory.kt +++ b/feature-discussions/src/main/java/com/anytypeio/anytype/feature_discussions/presentation/DiscussionViewModelFactory.kt @@ -16,6 +16,7 @@ import com.anytypeio.anytype.domain.multiplayer.ActiveSpaceMemberSubscriptionCon import com.anytypeio.anytype.domain.multiplayer.SpaceViewSubscriptionContainer import com.anytypeio.anytype.domain.`object`.OpenObject import com.anytypeio.anytype.domain.`object`.SetObjectDetails +import com.anytypeio.anytype.domain.objects.StoreOfObjectTypes import com.anytypeio.anytype.presentation.common.BaseViewModel import javax.inject.Inject @@ -33,7 +34,8 @@ class DiscussionViewModelFactory @Inject constructor( private val urlBuilder: UrlBuilder, private val spaceViews: SpaceViewSubscriptionContainer, private val dispatchers: AppCoroutineDispatchers, - private val uploadFile: UploadFile + private val uploadFile: UploadFile, + private val storeOfObjectTypes: StoreOfObjectTypes ) : ViewModelProvider.Factory { @Suppress("UNCHECKED_CAST") override fun create(modelClass: Class): T = DiscussionViewModel( @@ -50,6 +52,7 @@ class DiscussionViewModelFactory @Inject constructor( editChatMessage = editChatMessage, spaceViews = spaceViews, dispatchers = dispatchers, - uploadFile = uploadFile + uploadFile = uploadFile, + storeOfObjectTypes = storeOfObjectTypes ) as T } \ No newline at end of file diff --git a/feature-discussions/src/main/java/com/anytypeio/anytype/feature_discussions/ui/DiscussionPreviews.kt b/feature-discussions/src/main/java/com/anytypeio/anytype/feature_discussions/ui/DiscussionPreviews.kt index 20323630b3..693e68bd94 100644 --- a/feature-discussions/src/main/java/com/anytypeio/anytype/feature_discussions/ui/DiscussionPreviews.kt +++ b/feature-discussions/src/main/java/com/anytypeio/anytype/feature_discussions/ui/DiscussionPreviews.kt @@ -202,7 +202,8 @@ fun BubbleWithAttachmentPreview() { add( DiscussionView.Message.Attachment.Link( target = "ID", - wrapper = null + wrapper = null, + typeName = "Page" ) ) }, diff --git a/feature-discussions/src/main/java/com/anytypeio/anytype/feature_discussions/ui/DiscussionScreen.kt b/feature-discussions/src/main/java/com/anytypeio/anytype/feature_discussions/ui/DiscussionScreen.kt index c35fbd8aac..7295d10237 100644 --- a/feature-discussions/src/main/java/com/anytypeio/anytype/feature_discussions/ui/DiscussionScreen.kt +++ b/feature-discussions/src/main/java/com/anytypeio/anytype/feature_discussions/ui/DiscussionScreen.kt @@ -977,11 +977,6 @@ fun Messages( ) if (msg.isUserAuthor) { Spacer(modifier = Modifier.width(8.dp)) - ChatUserAvatar( - msg = msg, - avatar = msg.avatar, - modifier = Modifier.align(Alignment.Bottom) - ) } else { Spacer(modifier = Modifier.width(40.dp)) } @@ -1084,9 +1079,6 @@ private fun ChatUserAvatar( } } -val defaultBubbleColor = Color(0x99FFFFFF) -val userMessageBubbleColor = Color(0x66000000) - @OptIn(ExperimentalGlideComposeApi::class) @Composable fun Bubble( @@ -1114,9 +1106,9 @@ fun Bubble( .fillMaxWidth() .background( color = if (isUserAuthor) - userMessageBubbleColor + colorResource(R.color.navigation_panel_icon) else - defaultBubbleColor, + colorResource(R.color.navigation_panel), shape = RoundedCornerShape(20.dp) ) .clip(RoundedCornerShape(20.dp)) @@ -1250,41 +1242,7 @@ fun Bubble( else colorResource(id = R.color.text_primary), ) - attachments.forEach { attachment -> - when(attachment) { - is DiscussionView.Message.Attachment.Image -> { - GlideImage( - model = attachment.url, - contentDescription = "Attachment image", - modifier = Modifier - .padding(8.dp) - .fillMaxWidth() - .clip(shape = RoundedCornerShape(16.dp)) - .clickable { - onAttachmentClicked(attachment) - } - ) - } - is DiscussionView.Message.Attachment.Link -> { - AttachedObject( - modifier = Modifier - .padding( - start = 16.dp, - end = 16.dp, - top = 8.dp - ) - .fillMaxWidth() - , - title = attachment.wrapper?.name.orEmpty(), - type = attachment.wrapper?.type?.firstOrNull().orEmpty(), - icon = attachment.icon, - onAttachmentClicked = { - onAttachmentClicked(attachment) - } - ) - } - } - } + BubbleAttachments(attachments, onAttachmentClicked) if (reactions.isNotEmpty()) { ReactionList( reactions = reactions, @@ -1369,18 +1327,20 @@ fun Bubble( showDropdownMenu = false } ) - DropdownMenuItem( - text = { - Text( - text = stringResource(R.string.copy), - color = colorResource(id = R.color.text_primary) - ) - }, - onClick = { - onCopyMessage() - showDropdownMenu = false - } - ) + if (content.msg.isNotEmpty()) { + DropdownMenuItem( + text = { + Text( + text = stringResource(R.string.copy), + color = colorResource(id = R.color.text_primary) + ) + }, + onClick = { + onCopyMessage() + showDropdownMenu = false + } + ) + } if (isUserAuthor) { DropdownMenuItem( text = { @@ -1414,6 +1374,49 @@ fun Bubble( } } +@Composable +@OptIn(ExperimentalGlideComposeApi::class) +private fun BubbleAttachments( + attachments: List, + onAttachmentClicked: (DiscussionView.Message.Attachment) -> Unit +) { + attachments.forEach { attachment -> + when (attachment) { + is DiscussionView.Message.Attachment.Image -> { + GlideImage( + model = attachment.url, + contentDescription = "Attachment image", + modifier = Modifier + .padding(8.dp) + .fillMaxWidth() + .clip(shape = RoundedCornerShape(16.dp)) + .clickable { + onAttachmentClicked(attachment) + } + ) + } + + is DiscussionView.Message.Attachment.Link -> { + AttachedObject( + modifier = Modifier + .padding( + start = 16.dp, + end = 16.dp, + top = 8.dp + ) + .fillMaxWidth(), + title = attachment.wrapper?.name.orEmpty(), + type = attachment.typeName, + icon = attachment.icon, + onAttachmentClicked = { + onAttachmentClicked(attachment) + } + ) + } + } + } +} + @Composable fun TopDiscussionToolbar( title: String? = null, diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 6b4be1a0e8..93dd208b54 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -19,7 +19,7 @@ appcompatVersion = '1.7.0' fragmentVersion = "1.8.5" exoplayerVersion = "2.19.1" wireVersion = "4.9.8" -glideVersion = "4.14.2" +glideVersion = "4.16.0" glideComposeVersion = "1.0.0-beta01" mockitoKotlinVersion = "5.3.1" junitVersion = '4.13.2'