forked from melod1n/fast-messenger
Chat creation feature (#138)
This commit is contained in:
@@ -1,10 +1,10 @@
|
||||
package dev.meloda.fast.data.api.messages
|
||||
|
||||
import com.slack.eithernet.ApiResult
|
||||
import dev.meloda.fast.model.api.domain.VkAttachment
|
||||
import dev.meloda.fast.model.api.domain.VkAttachmentHistoryMessage
|
||||
import dev.meloda.fast.model.api.domain.VkMessage
|
||||
import dev.meloda.fast.network.RestApiErrorDomain
|
||||
import com.slack.eithernet.ApiResult
|
||||
|
||||
interface MessagesRepository {
|
||||
|
||||
@@ -41,6 +41,11 @@ interface MessagesRepository {
|
||||
conversationMessageId: Int
|
||||
): ApiResult<List<VkAttachmentHistoryMessage>, RestApiErrorDomain>
|
||||
|
||||
suspend fun createChat(
|
||||
userIds: List<Int>?,
|
||||
title: String?
|
||||
): ApiResult<Int, RestApiErrorDomain>
|
||||
|
||||
suspend fun storeMessages(messages: List<VkMessage>)
|
||||
|
||||
// suspend fun markAsImportant(
|
||||
|
||||
+19
-1
@@ -1,5 +1,6 @@
|
||||
package dev.meloda.fast.data.api.messages
|
||||
|
||||
import com.slack.eithernet.ApiResult
|
||||
import dev.meloda.fast.common.VkConstants
|
||||
import dev.meloda.fast.data.VkGroupsMap
|
||||
import dev.meloda.fast.data.VkMemoryCache
|
||||
@@ -14,6 +15,7 @@ import dev.meloda.fast.model.api.domain.VkAttachment
|
||||
import dev.meloda.fast.model.api.domain.VkAttachmentHistoryMessage
|
||||
import dev.meloda.fast.model.api.domain.VkMessage
|
||||
import dev.meloda.fast.model.api.domain.asEntity
|
||||
import dev.meloda.fast.model.api.requests.MessagesCreateChatRequest
|
||||
import dev.meloda.fast.model.api.requests.MessagesGetByIdRequest
|
||||
import dev.meloda.fast.model.api.requests.MessagesGetHistoryAttachmentsRequest
|
||||
import dev.meloda.fast.model.api.requests.MessagesGetHistoryRequest
|
||||
@@ -23,7 +25,6 @@ import dev.meloda.fast.network.RestApiErrorDomain
|
||||
import dev.meloda.fast.network.mapApiDefault
|
||||
import dev.meloda.fast.network.mapApiResult
|
||||
import dev.meloda.fast.network.service.messages.MessagesService
|
||||
import com.slack.eithernet.ApiResult
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.withContext
|
||||
|
||||
@@ -198,6 +199,23 @@ class MessagesRepositoryImpl(
|
||||
)
|
||||
}
|
||||
|
||||
override suspend fun createChat(
|
||||
userIds: List<Int>?,
|
||||
title: String?
|
||||
): ApiResult<Int, RestApiErrorDomain> = withContext(Dispatchers.IO) {
|
||||
val requestModel = MessagesCreateChatRequest(
|
||||
userIds = userIds,
|
||||
title = title
|
||||
)
|
||||
|
||||
messagesService.createChat(requestModel.map).mapApiResult(
|
||||
successMapper = { apiResponse ->
|
||||
apiResponse.requireResponse().chatId
|
||||
},
|
||||
errorMapper = { error -> error?.toDomain() }
|
||||
)
|
||||
}
|
||||
|
||||
override suspend fun storeMessages(messages: List<VkMessage>) {
|
||||
messageDao.insertAll(messages.map(VkMessage::asEntity))
|
||||
}
|
||||
|
||||
@@ -20,4 +20,8 @@ class GetLocalUserByIdUseCase(private val repository: UsersRepository) {
|
||||
|
||||
emit(newState)
|
||||
}
|
||||
|
||||
suspend fun proceed(userId: Int): VkUser? {
|
||||
return repository.getLocalUsers(userIds = listOf(userId)).singleOrNull()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -42,6 +42,11 @@ interface MessagesUseCase {
|
||||
conversationMessageId: Int
|
||||
): Flow<State<List<VkAttachmentHistoryMessage>>>
|
||||
|
||||
fun createChat(
|
||||
userIds: List<Int>?,
|
||||
title: String?
|
||||
): Flow<State<Int>>
|
||||
|
||||
suspend fun storeMessage(message: VkMessage)
|
||||
suspend fun storeMessages(messages: List<VkMessage>)
|
||||
}
|
||||
|
||||
@@ -100,6 +100,14 @@ class MessagesUseCaseImpl(
|
||||
emit(newState)
|
||||
}
|
||||
|
||||
override fun createChat(userIds: List<Int>?, title: String?): Flow<State<Int>> = flow {
|
||||
emit(State.Loading)
|
||||
|
||||
val newState = repository.createChat(userIds, title).mapToState()
|
||||
|
||||
emit(newState)
|
||||
}
|
||||
|
||||
override suspend fun storeMessage(message: VkMessage) {
|
||||
repository.storeMessages(listOf(message))
|
||||
}
|
||||
|
||||
@@ -0,0 +1,22 @@
|
||||
package dev.meloda.fast.domain.util
|
||||
|
||||
import dev.meloda.fast.common.model.UiImage
|
||||
import dev.meloda.fast.data.VkMemoryCache
|
||||
import dev.meloda.fast.model.api.domain.VkUser
|
||||
import dev.meloda.fast.ui.model.api.UiFriend
|
||||
|
||||
fun VkUser.asPresentation(
|
||||
useContactNames: Boolean = false
|
||||
): UiFriend = UiFriend(
|
||||
userId = id,
|
||||
avatar = photo100?.let(UiImage::Url),
|
||||
title = if (useContactNames) {
|
||||
VkMemoryCache.getContact(id)?.name ?: fullName
|
||||
} else {
|
||||
fullName
|
||||
},
|
||||
onlineStatus = onlineStatus,
|
||||
photo400Orig = photo400Orig?.let(UiImage::Url),
|
||||
firstName = firstName,
|
||||
lastName = lastName
|
||||
)
|
||||
@@ -267,3 +267,14 @@ data class MessagesGetHistoryAttachmentsRequest(
|
||||
fields?.let { this["fields"] = it }
|
||||
}
|
||||
}
|
||||
|
||||
data class MessagesCreateChatRequest(
|
||||
val userIds: List<Int>?,
|
||||
val title: String?
|
||||
) {
|
||||
|
||||
val map = mutableMapOf<String, String>().apply {
|
||||
userIds?.let { this["user_ids"] = it.joinToString(",") }
|
||||
title?.let { this["title"] = it }
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
package dev.meloda.fast.model.api.responses
|
||||
|
||||
import com.squareup.moshi.Json
|
||||
import com.squareup.moshi.JsonClass
|
||||
import dev.meloda.fast.model.api.data.VkAttachmentHistoryMessageData
|
||||
import dev.meloda.fast.model.api.data.VkChatMemberData
|
||||
import dev.meloda.fast.model.api.data.VkContactData
|
||||
@@ -7,8 +9,6 @@ import dev.meloda.fast.model.api.data.VkConversationData
|
||||
import dev.meloda.fast.model.api.data.VkGroupData
|
||||
import dev.meloda.fast.model.api.data.VkMessageData
|
||||
import dev.meloda.fast.model.api.data.VkUserData
|
||||
import com.squareup.moshi.Json
|
||||
import com.squareup.moshi.JsonClass
|
||||
|
||||
@JsonClass(generateAdapter = true)
|
||||
data class MessagesGetHistoryResponse(
|
||||
@@ -44,3 +44,9 @@ data class MessagesGetHistoryAttachmentsResponse(
|
||||
@Json(name = "groups") val groups: List<VkGroupData>?,
|
||||
@Json(name = "contacts") val contacts: List<VkContactData>?
|
||||
)
|
||||
|
||||
@JsonClass(generateAdapter = true)
|
||||
data class MessagesCreateChatResponse(
|
||||
@Json(name = "chat_id") val chatId: Int,
|
||||
@Json(name = "peer_ids") val peerIds: List<Int>
|
||||
)
|
||||
|
||||
+8
-1
@@ -1,12 +1,13 @@
|
||||
package dev.meloda.fast.network.service.messages
|
||||
|
||||
import com.slack.eithernet.ApiResult
|
||||
import dev.meloda.fast.model.api.data.VkLongPollData
|
||||
import dev.meloda.fast.model.api.responses.MessagesCreateChatResponse
|
||||
import dev.meloda.fast.model.api.responses.MessagesGetByIdResponse
|
||||
import dev.meloda.fast.model.api.responses.MessagesGetHistoryAttachmentsResponse
|
||||
import dev.meloda.fast.model.api.responses.MessagesGetHistoryResponse
|
||||
import dev.meloda.fast.network.ApiResponse
|
||||
import dev.meloda.fast.network.RestApiError
|
||||
import com.slack.eithernet.ApiResult
|
||||
import retrofit2.http.FieldMap
|
||||
import retrofit2.http.FormUrlEncoded
|
||||
import retrofit2.http.POST
|
||||
@@ -49,6 +50,12 @@ interface MessagesService {
|
||||
@FieldMap params: Map<String, String>
|
||||
): ApiResult<ApiResponse<MessagesGetHistoryAttachmentsResponse>, RestApiError>
|
||||
|
||||
@FormUrlEncoded
|
||||
@POST(MessagesUrls.CREATE_CHAT)
|
||||
suspend fun createChat(
|
||||
@FieldMap params: Map<String, String>
|
||||
): ApiResult<ApiResponse<MessagesCreateChatResponse>, RestApiError>
|
||||
|
||||
// @FormUrlEncoded
|
||||
// @POST(MessagesUrls.MarkAsImportant)
|
||||
// suspend fun markAsImportant(
|
||||
|
||||
@@ -19,4 +19,5 @@ object MessagesUrls {
|
||||
const val GET_CONVERSATIONS_MEMBERS = "${AppConstants.URL_API}/messages.getConversationMembers"
|
||||
const val REMOVE_CHAT_USER = "${AppConstants.URL_API}/messages.removeChatUser"
|
||||
const val GET_HISTORY_ATTACHMENTS = "${AppConstants.URL_API}/messages.getHistoryAttachments"
|
||||
const val CREATE_CHAT = "${AppConstants.URL_API}/messages.createChat"
|
||||
}
|
||||
|
||||
@@ -0,0 +1 @@
|
||||
/build
|
||||
@@ -0,0 +1,12 @@
|
||||
plugins {
|
||||
alias(libs.plugins.fast.android.library)
|
||||
alias(libs.plugins.fast.android.library.compose)
|
||||
alias(libs.plugins.kotlin.serialization)
|
||||
}
|
||||
|
||||
android {
|
||||
namespace = "dev.meloda.fast.presentation"
|
||||
}
|
||||
|
||||
dependencies {
|
||||
}
|
||||
@@ -0,0 +1,4 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<manifest xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
|
||||
</manifest>
|
||||
@@ -11,6 +11,7 @@ android {
|
||||
dependencies {
|
||||
api(projects.core.common)
|
||||
api(projects.core.model)
|
||||
implementation(projects.core.presentation)
|
||||
|
||||
implementation(libs.haze)
|
||||
implementation(libs.haze.materials)
|
||||
|
||||
@@ -0,0 +1,20 @@
|
||||
package dev.meloda.fast.ui.model.api
|
||||
|
||||
enum class ActionState {
|
||||
PHANTOM, CALL_IN_PROGRESS, NONE;
|
||||
|
||||
// TODO: 11/04/2024, Danil Nikolaev: implement
|
||||
fun getResourceId(): Int {
|
||||
return -1
|
||||
}
|
||||
|
||||
companion object {
|
||||
fun parse(isPhantom: Boolean, isCallInProgress: Boolean): ActionState {
|
||||
return when {
|
||||
isPhantom -> PHANTOM
|
||||
isCallInProgress -> CALL_IN_PROGRESS
|
||||
else -> NONE
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,31 @@
|
||||
package dev.meloda.fast.ui.model.api
|
||||
|
||||
import dev.meloda.fast.common.model.UiImage
|
||||
import dev.meloda.fast.common.model.UiText
|
||||
import dev.meloda.fast.ui.R
|
||||
|
||||
sealed class ConversationOption(
|
||||
val title: UiText,
|
||||
val icon: UiImage
|
||||
) {
|
||||
|
||||
data object MarkAsRead : ConversationOption(
|
||||
title = UiText.Resource(R.string.action_mark_as_read),
|
||||
icon = UiImage.Resource(R.drawable.round_done_all_24)
|
||||
)
|
||||
|
||||
data object Pin : ConversationOption(
|
||||
title = UiText.Resource(R.string.action_pin),
|
||||
icon = UiImage.Resource(R.drawable.pin_outline_24)
|
||||
)
|
||||
|
||||
data object Unpin : ConversationOption(
|
||||
title = UiText.Resource(R.string.action_unpin),
|
||||
icon = UiImage.Resource(R.drawable.pin_off_outline_24)
|
||||
)
|
||||
|
||||
data object Delete : ConversationOption(
|
||||
title = UiText.Resource(R.string.action_delete),
|
||||
icon = UiImage.Resource(R.drawable.round_delete_outline_24)
|
||||
)
|
||||
}
|
||||
@@ -0,0 +1,14 @@
|
||||
package dev.meloda.fast.ui.model.api
|
||||
|
||||
data class ConversationsShowOptions(
|
||||
val showDeleteDialog: Int?,
|
||||
val showPinDialog: UiConversation?
|
||||
) {
|
||||
|
||||
companion object {
|
||||
val EMPTY: ConversationsShowOptions = ConversationsShowOptions(
|
||||
showDeleteDialog = null,
|
||||
showPinDialog = null
|
||||
)
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,31 @@
|
||||
package dev.meloda.fast.ui.model.api
|
||||
|
||||
import androidx.compose.runtime.Immutable
|
||||
import androidx.compose.ui.text.AnnotatedString
|
||||
import dev.meloda.fast.common.model.UiImage
|
||||
import dev.meloda.fast.model.api.PeerType
|
||||
import dev.meloda.fast.model.api.domain.VkMessage
|
||||
import dev.meloda.fast.ui.util.ImmutableList
|
||||
|
||||
@Immutable
|
||||
data class UiConversation(
|
||||
val id: Int,
|
||||
val lastMessageId: Int?,
|
||||
val avatar: UiImage?,
|
||||
val title: String,
|
||||
val unreadCount: String?,
|
||||
val date: String,
|
||||
val message: AnnotatedString,
|
||||
val attachmentImage: UiImage?,
|
||||
val isPinned: Boolean,
|
||||
val actionImageId: Int,
|
||||
val isBirthday: Boolean,
|
||||
val isUnread: Boolean,
|
||||
val isAccount: Boolean,
|
||||
val isOnline: Boolean,
|
||||
val lastMessage: VkMessage?,
|
||||
val peerType: PeerType,
|
||||
val interactionText: String?,
|
||||
val isExpanded: Boolean,
|
||||
val options: ImmutableList<ConversationOption>,
|
||||
)
|
||||
@@ -0,0 +1,16 @@
|
||||
package dev.meloda.fast.ui.model.api
|
||||
|
||||
import androidx.compose.runtime.Immutable
|
||||
import dev.meloda.fast.common.model.UiImage
|
||||
import dev.meloda.fast.model.api.domain.OnlineStatus
|
||||
|
||||
@Immutable
|
||||
data class UiFriend(
|
||||
val userId: Int,
|
||||
val avatar: UiImage?,
|
||||
val firstName: String,
|
||||
val lastName: String,
|
||||
val title: String,
|
||||
val onlineStatus: OnlineStatus,
|
||||
val photo400Orig: UiImage?
|
||||
)
|
||||
@@ -215,4 +215,7 @@
|
||||
<string name="no_online_friends">Никого в сети</string>
|
||||
<string name="try_again">Попробовать ещё раз</string>
|
||||
<string name="session_expired">Срок действия сессии истёк</string>
|
||||
<string name="title_create_chat">Создать чат</string>
|
||||
<string name="action_create">Создать</string>
|
||||
<string name="create_chat_title">Название</string>
|
||||
</resources>
|
||||
|
||||
@@ -280,4 +280,7 @@
|
||||
<string name="no_online_friends">No one is online</string>
|
||||
<string name="try_again">Try again</string>
|
||||
<string name="session_expired">Session expired</string>
|
||||
<string name="title_create_chat">Create chat</string>
|
||||
<string name="action_create">Create</string>
|
||||
<string name="create_chat_title">Title</string>
|
||||
</resources>
|
||||
|
||||
Reference in New Issue
Block a user