1
0
Fork 0
mirror of https://github.com/anyproto/anytype-kotlin.git synced 2025-06-08 05:47:05 +09:00

DROID-3098 Chats | Fix | Attachments misc fixes (#1903)

This commit is contained in:
Evgenii Kozlov 2024-12-10 21:16:30 +01:00 committed by GitHub
parent 08e708a4ca
commit 59f8cca15c
Signed by: github
GPG key ID: B5690EEEBB952194
5 changed files with 171 additions and 144 deletions

View file

@ -59,6 +59,9 @@ sealed interface DiscussionView {
data class Media(
val uri: String
): ChatBoxAttachment()
data class File(
val uri: String
): ChatBoxAttachment()
data class Link(
val target: Id,
val wrapper: GlobalSearchItemView

View file

@ -115,116 +115,117 @@ class DiscussionViewModel @Inject constructor(
account: Id,
chat: Id
) {
chatContainer
.watchWhileTrackingAttachments(chat = chat)
.withLatestFrom(
chatContainer.fetchAttachments(vmParams.space),
chatContainer.fetchReplies(chat = chat)
) { result, dependencies, replies ->
result.map { msg ->
val allMembers = members.get()
val member = allMembers.let { type ->
when (type) {
is Store.Data -> type.members.find { member ->
member.identity == msg.creator
}
is Store.Empty -> null
combine(
chatContainer
.watchWhileTrackingAttachments(chat = chat),
chatContainer.fetchAttachments(vmParams.space),
chatContainer.fetchReplies(chat = chat)
) { result, dependencies, replies ->
result.map { msg ->
val allMembers = members.get()
val member = allMembers.let { type ->
when (type) {
is Store.Data -> type.members.find { member ->
member.identity == msg.creator
}
is Store.Empty -> null
}
}
val content = msg.content
val content = msg.content
val replyToId = msg.replyToMessageId
val replyToId = msg.replyToMessageId
val reply = if (replyToId.isNullOrEmpty()) {
null
} else {
val msg = replies[replyToId]
if (msg != null) {
DiscussionView.Message.Reply(
msg = msg.id,
text = msg.content?.text.orEmpty(),
author = allMembers.let { type ->
when (type) {
is Store.Data -> type.members.find { member ->
member.identity == msg.creator
}?.name.orEmpty()
is Store.Empty -> ""
}
val reply = if (replyToId.isNullOrEmpty()) {
null
} else {
val msg = replies[replyToId]
if (msg != null) {
DiscussionView.Message.Reply(
msg = msg.id,
text = msg.content?.text.orEmpty(),
author = allMembers.let { type ->
when (type) {
is Store.Data -> type.members.find { member ->
member.identity == msg.creator
}?.name.orEmpty()
is Store.Empty -> ""
}
)
} else {
null
}
}
)
} else {
null
}
}
DiscussionView.Message(
id = msg.id,
timestamp = msg.createdAt * 1000,
content = DiscussionView.Message.Content(
msg = content?.text.orEmpty(),
parts = content?.text
.orEmpty()
.splitByMarks(marks = content?.marks.orEmpty())
.map { (part, styles) ->
DiscussionView.Message.Content.Part(
part = part,
styles = styles
DiscussionView.Message(
id = msg.id,
timestamp = msg.createdAt * 1000,
content = DiscussionView.Message.Content(
msg = content?.text.orEmpty(),
parts = content?.text
.orEmpty()
.splitByMarks(marks = content?.marks.orEmpty())
.map { (part, styles) ->
DiscussionView.Message.Content.Part(
part = part,
styles = styles
)
}
),
reply = reply,
author = member?.name ?: msg.creator.takeLast(5),
isUserAuthor = msg.creator == account,
isEdited = msg.modifiedAt > msg.createdAt,
reactions = msg.reactions.map { (emoji, ids) ->
DiscussionView.Message.Reaction(
emoji = emoji,
count = ids.size,
isSelected = ids.contains(account)
)
},
attachments = msg.attachments.map { attachment ->
when (attachment.type) {
Chat.Message.Attachment.Type.Image -> DiscussionView.Message.Attachment.Image(
target = attachment.target,
url = urlBuilder.medium(path = attachment.target)
)
else -> {
val wrapper = dependencies[attachment.target]
if (wrapper?.layout == ObjectType.Layout.IMAGE) {
DiscussionView.Message.Attachment.Image(
target = attachment.target,
url = urlBuilder.large(path = attachment.target)
)
} else {
DiscussionView.Message.Attachment.Link(
target = attachment.target,
wrapper = wrapper,
icon = wrapper?.objectIcon(urlBuilder) ?: ObjectIcon.None
)
}
),
reply = reply,
author = member?.name ?: msg.creator.takeLast(5),
isUserAuthor = msg.creator == account,
isEdited = msg.modifiedAt > msg.createdAt,
reactions = msg.reactions.map { (emoji, ids) ->
DiscussionView.Message.Reaction(
emoji = emoji,
count = ids.size,
isSelected = ids.contains(account)
)
},
attachments = msg.attachments.map { attachment ->
when(attachment.type) {
Chat.Message.Attachment.Type.Image -> DiscussionView.Message.Attachment.Image(
target = attachment.target,
url = urlBuilder.medium(path = attachment.target)
)
else -> {
val wrapper = dependencies[attachment.target]
if (wrapper?.layout == ObjectType.Layout.IMAGE) {
DiscussionView.Message.Attachment.Image(
target = attachment.target,
url = urlBuilder.large(path = attachment.target)
)
} else {
DiscussionView.Message.Attachment.Link(
target = attachment.target,
wrapper = wrapper,
icon = wrapper?.objectIcon(urlBuilder) ?: ObjectIcon.None
)
}
}
}
}.also {
if (it.isNotEmpty()) {
Timber.d("Chat attachments: $it")
}
},
avatar = if (member != null && !member.iconImage.isNullOrEmpty()) {
DiscussionView.Message.Avatar.Image(
urlBuilder.thumbnail(member.iconImage!!)
)
} else {
DiscussionView.Message.Avatar.Initials(member?.name.orEmpty())
}
)
}.reversed()
}
.flowOn(dispatchers.io)
.collect { result ->
messages.value = result
}
}.also {
if (it.isNotEmpty()) {
Timber.d("Chat attachments: $it")
}
},
avatar = if (member != null && !member.iconImage.isNullOrEmpty()) {
DiscussionView.Message.Avatar.Image(
urlBuilder.thumbnail(member.iconImage!!)
)
} else {
DiscussionView.Message.Avatar.Initials(member?.name.orEmpty())
}
)
}.reversed()
}.flowOn(dispatchers.io).collect {
messages.value = it
}
}
fun onMessageSent(msg: String) {
@ -256,6 +257,21 @@ class DiscussionViewModel @Inject constructor(
)
}
}
is DiscussionView.Message.ChatBoxAttachment.File -> {
uploadFile.async(
UploadFile.Params(
space = vmParams.space,
path = attachment.uri
)
).onSuccess { file ->
add(
Chat.Message.Attachment(
target = file.id,
type = Chat.Message.Attachment.Type.Image
)
)
}
}
}
}
}
@ -446,6 +462,15 @@ class DiscussionViewModel @Inject constructor(
}
}
fun onChatBoxFilePicked(uris: List<String>) {
Timber.d("onChatBoxFilePicked: $uris")
chatBoxAttachments.value = chatBoxAttachments.value + uris.map {
DiscussionView.Message.ChatBoxAttachment.File(
uri = it
)
}
}
fun onExitEditMessageMode() {
viewModelScope.launch {
chatBoxMode.value = ChatBoxMode.Default

View file

@ -122,7 +122,8 @@ fun DiscussionScreenPreview() {
onReplyMessage = {},
chatBoxMode = DiscussionViewModel.ChatBoxMode.Default,
onClearReplyClicked = {},
onChatBoxMediaPicked = {}
onChatBoxMediaPicked = {},
onChatBoxFilePicked = {}
)
}

View file

@ -98,7 +98,6 @@ import androidx.compose.ui.text.withStyle
import androidx.compose.ui.tooling.preview.Preview
import androidx.compose.ui.unit.DpOffset
import androidx.compose.ui.unit.dp
import androidx.compose.ui.unit.em
import androidx.compose.ui.unit.sp
import androidx.navigation.compose.NavHost
import androidx.navigation.compose.composable
@ -126,6 +125,7 @@ import com.anytypeio.anytype.core_ui.widgets.ListWidgetObjectIcon
import com.anytypeio.anytype.core_utils.const.DateConst.TIME_H24
import com.anytypeio.anytype.core_utils.ext.formatTimeInMillis
import com.anytypeio.anytype.core_utils.ext.parseImagePath
import com.anytypeio.anytype.core_utils.ext.parsePath
import com.anytypeio.anytype.core_utils.ext.toast
import com.anytypeio.anytype.feature_discussions.R
import com.anytypeio.anytype.feature_discussions.presentation.DiscussionView
@ -207,6 +207,9 @@ fun DiscussionScreenWrapper(
onClearReplyClicked = vm::onClearReplyClicked,
onChatBoxMediaPicked = { uris ->
vm.onChatBoxMediaPicked(uris.map { it.parseImagePath(context = context) })
},
onChatBoxFilePicked = { uris ->
// TODO parse path and path it vm.
}
)
LaunchedEffect(Unit) {
@ -259,7 +262,8 @@ fun DiscussionScreen(
onAttachMediaClicked: () -> Unit,
onAttachFileClicked: () -> Unit,
onUploadAttachmentClicked: () -> Unit,
onChatBoxMediaPicked: (List<Uri>) -> Unit
onChatBoxMediaPicked: (List<Uri>) -> Unit,
onChatBoxFilePicked: (List<Uri>) -> Unit
) {
var textState by rememberSaveable(stateSaver = TextFieldValue.Saver) {
mutableStateOf(TextFieldValue(""))
@ -383,7 +387,8 @@ fun DiscussionScreen(
onAttachObjectClicked = onAttachObjectClicked,
onClearAttachmentClicked = onClearAttachmentClicked,
onClearReplyClicked = onClearReplyClicked,
onChatBoxMediaPicked = onChatBoxMediaPicked
onChatBoxMediaPicked = onChatBoxMediaPicked,
onChatBoxFilePicked = onChatBoxFilePicked
)
}
}
@ -451,13 +456,15 @@ private fun ChatBox(
onUploadAttachmentClicked: () -> Unit,
onClearAttachmentClicked: (DiscussionView.Message.ChatBoxAttachment) -> Unit,
onClearReplyClicked: () -> Unit,
onChatBoxMediaPicked: (List<Uri>) -> Unit
onChatBoxMediaPicked: (List<Uri>) -> Unit,
onChatBoxFilePicked: (List<Uri>) -> Unit,
) {
val context = LocalContext.current
val result = remember { mutableStateOf<List<String>>(emptyList()) }
val launcher = rememberLauncherForActivityResult(ActivityResultContracts.PickMultipleVisualMedia()) {
result.value = it.map { it.parseImagePath(context) }
onChatBoxMediaPicked(it.filterNotNull())
val uploadMediaLauncher = rememberLauncherForActivityResult(ActivityResultContracts.PickMultipleVisualMedia()) {
onChatBoxMediaPicked(it)
}
val uploadFileLauncher = rememberLauncherForActivityResult(ActivityResultContracts.OpenMultipleDocuments()) {
onChatBoxFilePicked(it)
}
var showDropdownMenu by remember { mutableStateOf(false) }
@ -554,6 +561,11 @@ private fun ChatBox(
}
}
}
is DiscussionView.Message.ChatBoxAttachment.File -> {
item {
Text(text = attachment.uri)
}
}
}
}
}
@ -709,43 +721,29 @@ private fun ChatBox(
},
onClick = {
showDropdownMenu = false
launcher.launch(
uploadMediaLauncher.launch(
PickVisualMediaRequest(mediaType = ActivityResultContracts.PickVisualMedia.ImageOnly)
)
}
)
Divider(
paddingStart = 0.dp,
paddingEnd = 0.dp
)
DropdownMenuItem(
text = {
Text(
text = stringResource(R.string.chat_attachment_file),
color = colorResource(id = R.color.text_primary)
)
},
onClick = {
showDropdownMenu = false
context.toast("Coming soon")
}
)
Divider(
paddingStart = 0.dp,
paddingEnd = 0.dp
)
DropdownMenuItem(
text = {
Text(
text = stringResource(R.string.chat_attachment_upload),
color = colorResource(id = R.color.text_primary)
)
},
onClick = {
showDropdownMenu = false
context.toast("Coming soon")
}
)
// Divider(
// paddingStart = 0.dp,
// paddingEnd = 0.dp
// )
// DropdownMenuItem(
// text = {
// Text(
// text = stringResource(R.string.chat_attachment_file),
// color = colorResource(id = R.color.text_primary)
// )
// },
// onClick = {
// showDropdownMenu = false
// uploadFileLauncher.launch(
// arrayOf("*/*")
// )
// }
// )
}
}
}

View file

@ -1833,9 +1833,9 @@ Please provide specific details of your needs here.</string>
<string name="date_layout_alert_date_out_of_range">The selected date is out of the valid range (years %1$d to %2$d). Please select a date within this range.</string>
<string name="date_layout_item_created_by">by</string>
<string name="chat_attachment_object">Object</string>
<string name="chat_attachment_file">File</string>
<string name="chat_attachment_media">Media</string>
<string name="chat_attachment_object">Select existing object</string>
<string name="chat_attachment_file">Upload file</string>
<string name="chat_attachment_media">Upload media</string>
<string name="chat_attachment_upload">Upload</string>
<string name="chats_reply">Reply</string>