mirror of
https://github.com/nextcloud/talk-android
synced 2025-06-21 12:39:58 +01:00
WIP use new api endpoint to create group conversation
Signed-off-by: Marcel Hibbe <dev@mhibbe.de>
This commit is contained in:
parent
77fe2ad024
commit
fa5570e901
@ -2,11 +2,13 @@
|
||||
* Nextcloud Talk - Android Client
|
||||
*
|
||||
* SPDX-FileCopyrightText: 2024 Sowjanya Kota <sowjanya.kch@gmail.com>
|
||||
* SPDX-FileCopyrightText: 2025 Marcel Hibbe <dev@mhibbe.de>
|
||||
* SPDX-License-Identifier: GPL-3.0-or-later
|
||||
*/
|
||||
|
||||
package com.nextcloud.talk.api
|
||||
|
||||
import com.nextcloud.talk.conversationinfo.CreateRoomRequest
|
||||
import com.nextcloud.talk.models.json.autocomplete.AutocompleteOverall
|
||||
import com.nextcloud.talk.models.json.chat.ChatOverallSingleMessage
|
||||
import com.nextcloud.talk.models.json.conversations.RoomOverall
|
||||
@ -56,6 +58,13 @@ interface NcApiCoroutines {
|
||||
@QueryMap options: Map<String, String>?
|
||||
): RoomOverall
|
||||
|
||||
@POST
|
||||
suspend fun createRoomWithBody(
|
||||
@Header("Authorization") authorization: String?,
|
||||
@Url url: String?,
|
||||
@Body roomRequest: CreateRoomRequest
|
||||
): RoomOverall
|
||||
|
||||
/*
|
||||
QueryMap items are as follows:
|
||||
- "roomName" : "newName"
|
||||
|
@ -11,7 +11,6 @@
|
||||
package com.nextcloud.talk.conversationinfo
|
||||
|
||||
import android.annotation.SuppressLint
|
||||
import android.app.Activity
|
||||
import android.content.Intent
|
||||
import android.os.Bundle
|
||||
import android.text.TextUtils
|
||||
@ -161,16 +160,18 @@ class ConversationInfoActivity :
|
||||
ActivityResultContracts.StartActivityForResult()
|
||||
) {
|
||||
executeIfResultOk(it) { intent ->
|
||||
val selectedParticipants =
|
||||
val selectedAutocompleteUsers =
|
||||
intent?.getParcelableArrayListExtraProvider<AutocompleteUser>("selectedParticipants")
|
||||
?: emptyList()
|
||||
val participants = selectedParticipants.toMutableList()
|
||||
|
||||
if (startGroupChat) {
|
||||
Snackbar.make(binding.root, "TODO: start group chat...", Snackbar.LENGTH_LONG).show()
|
||||
viewModel.createRoom()
|
||||
viewModel.createRoomFromOneToOne(
|
||||
conversationUser,
|
||||
selectedAutocompleteUsers,
|
||||
conversationToken
|
||||
)
|
||||
} else {
|
||||
addParticipantsToConversation(participants)
|
||||
addParticipantsToConversation(selectedAutocompleteUsers)
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -250,6 +251,21 @@ class ConversationInfoActivity :
|
||||
}
|
||||
}
|
||||
|
||||
viewModel.createRoomViewState.observe(this) { state ->
|
||||
when (state) {
|
||||
is ConversationInfoViewModel.CreateRoomUIState.Success -> {
|
||||
// for now noting is done here.
|
||||
// the breakout room signaling message should be triggered and conversation should be switched.
|
||||
}
|
||||
|
||||
is ConversationInfoViewModel.CreateRoomUIState.Error -> {
|
||||
Snackbar.make(binding.root, R.string.nc_common_error_sorry, Snackbar.LENGTH_LONG).show()
|
||||
}
|
||||
|
||||
else -> {}
|
||||
}
|
||||
}
|
||||
|
||||
viewModel.getBanActorState.observe(this) { state ->
|
||||
when (state) {
|
||||
is ConversationInfoViewModel.BanActorSuccessState -> {
|
||||
@ -688,7 +704,7 @@ class ConversationInfoActivity :
|
||||
}
|
||||
|
||||
private fun executeIfResultOk(result: ActivityResult, onResult: (intent: Intent?) -> Unit) {
|
||||
if (result.resultCode == Activity.RESULT_OK) {
|
||||
if (result.resultCode == RESULT_OK) {
|
||||
onResult(result.data)
|
||||
} else {
|
||||
Log.e(ChatActivity.TAG, "resultCode for received intent was != ok")
|
||||
@ -721,17 +737,17 @@ class ConversationInfoActivity :
|
||||
addParticipantsResult.launch(intent)
|
||||
}
|
||||
|
||||
private fun addParticipantsToConversation(participants: List<AutocompleteUser>) {
|
||||
private fun addParticipantsToConversation(autocompleteUsers: List<AutocompleteUser>) {
|
||||
val groupIdsArray: MutableSet<String> = HashSet()
|
||||
val emailIdsArray: MutableSet<String> = HashSet()
|
||||
val circleIdsArray: MutableSet<String> = HashSet()
|
||||
val userIdsArray: MutableSet<String> = HashSet()
|
||||
|
||||
participants.forEach { participant ->
|
||||
autocompleteUsers.forEach { participant ->
|
||||
when (participant.source) {
|
||||
Participant.ActorType.GROUPS.name.lowercase() -> groupIdsArray.add(participant.id!!)
|
||||
GROUPS.name.lowercase() -> groupIdsArray.add(participant.id!!)
|
||||
Participant.ActorType.EMAILS.name.lowercase() -> emailIdsArray.add(participant.id!!)
|
||||
Participant.ActorType.CIRCLES.name.lowercase() -> circleIdsArray.add(participant.id!!)
|
||||
CIRCLES.name.lowercase() -> circleIdsArray.add(participant.id!!)
|
||||
else -> userIdsArray.add(participant.id!!)
|
||||
}
|
||||
}
|
||||
|
@ -0,0 +1,72 @@
|
||||
/*
|
||||
* Nextcloud Talk - Android Client
|
||||
*
|
||||
* SPDX-FileCopyrightText: 2025 Marcel Hibbe <dev@mhibbe.de>
|
||||
* SPDX-License-Identifier: GPL-3.0-or-later
|
||||
*/
|
||||
|
||||
package com.nextcloud.talk.conversationinfo
|
||||
|
||||
import com.bluelinelabs.logansquare.annotation.JsonField
|
||||
import com.bluelinelabs.logansquare.annotation.JsonObject
|
||||
|
||||
@JsonObject
|
||||
data class CreateRoomRequest(
|
||||
@JsonField(name = ["roomType"])
|
||||
var roomType: String,
|
||||
@JsonField(name = ["roomName"])
|
||||
var roomName: String? = null,
|
||||
@JsonField(name = ["objectType"])
|
||||
var objectType: String? = null,
|
||||
@JsonField(name = ["objectId"])
|
||||
var objectId: String? = null,
|
||||
@JsonField(name = ["password"])
|
||||
var password: String? = null,
|
||||
@JsonField(name = ["readOnly"])
|
||||
var readOnly: Int,
|
||||
@JsonField(name = ["listable"])
|
||||
var listable: Int,
|
||||
@JsonField(name = ["messageExpiration"])
|
||||
var messageExpiration: Int? = null,
|
||||
@JsonField(name = ["lobbyState"])
|
||||
var lobbyState: Int? = null,
|
||||
@JsonField(name = ["lobbyTimer"])
|
||||
var lobbyTimer: Int,
|
||||
@JsonField(name = ["sipEnabled"])
|
||||
var sipEnabled: Int,
|
||||
@JsonField(name = ["permissions"])
|
||||
var permissions: Int,
|
||||
@JsonField(name = ["recordingConsent"])
|
||||
var recordingConsent: Int,
|
||||
@JsonField(name = ["mentionPermissions"])
|
||||
var mentionPermissions: Int,
|
||||
@JsonField(name = ["description"])
|
||||
var description: String? = null,
|
||||
@JsonField(name = ["emoji"])
|
||||
var emoji: String? = null,
|
||||
@JsonField(name = ["avatarColor"])
|
||||
var avatarColor: String? = null,
|
||||
@JsonField(name = ["participants"])
|
||||
var participants: Participants? = null
|
||||
) {
|
||||
constructor() : this(
|
||||
0.toString(),
|
||||
"",
|
||||
"",
|
||||
"",
|
||||
"",
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
255,
|
||||
0,
|
||||
0,
|
||||
"",
|
||||
"string",
|
||||
"string",
|
||||
Participants()
|
||||
)
|
||||
}
|
@ -0,0 +1,27 @@
|
||||
/*
|
||||
* Nextcloud Talk - Android Client
|
||||
*
|
||||
* SPDX-FileCopyrightText: 2025 Marcel Hibbe <dev@mhibbe.de>
|
||||
* SPDX-License-Identifier: GPL-3.0-or-later
|
||||
*/
|
||||
|
||||
package com.nextcloud.talk.conversationinfo
|
||||
|
||||
import com.bluelinelabs.logansquare.annotation.JsonField
|
||||
import com.bluelinelabs.logansquare.annotation.JsonObject
|
||||
|
||||
@JsonObject
|
||||
data class Participants(
|
||||
@JsonField(name = ["users"])
|
||||
var users: MutableList<String> = arrayListOf(),
|
||||
@JsonField(name = ["federated_users"])
|
||||
var federatedUsers: MutableList<String> = arrayListOf(),
|
||||
@JsonField(name = ["groups"])
|
||||
var groups: MutableList<String> = arrayListOf(),
|
||||
@JsonField(name = ["emails"])
|
||||
var emails: MutableList<String> = arrayListOf(),
|
||||
@JsonField(name = ["phones"])
|
||||
var phones: MutableList<String> = arrayListOf(),
|
||||
@JsonField(name = ["teams"])
|
||||
var teams: MutableList<String> = arrayListOf()
|
||||
)
|
@ -15,12 +15,21 @@ import androidx.lifecycle.MutableLiveData
|
||||
import androidx.lifecycle.ViewModel
|
||||
import androidx.lifecycle.viewModelScope
|
||||
import com.nextcloud.talk.chat.data.network.ChatNetworkDataSource
|
||||
import com.nextcloud.talk.conversationinfo.CreateRoomRequest
|
||||
import com.nextcloud.talk.conversationinfo.Participants
|
||||
import com.nextcloud.talk.data.user.model.User
|
||||
import com.nextcloud.talk.models.domain.ConversationModel
|
||||
import com.nextcloud.talk.models.json.autocomplete.AutocompleteUser
|
||||
import com.nextcloud.talk.models.json.capabilities.SpreedCapability
|
||||
import com.nextcloud.talk.models.json.conversations.RoomOverall
|
||||
import com.nextcloud.talk.models.json.participants.Participant.ActorType.CIRCLES
|
||||
import com.nextcloud.talk.models.json.participants.Participant.ActorType.EMAILS
|
||||
import com.nextcloud.talk.models.json.participants.Participant.ActorType.FEDERATED
|
||||
import com.nextcloud.talk.models.json.participants.Participant.ActorType.GROUPS
|
||||
import com.nextcloud.talk.models.json.participants.TalkBan
|
||||
import com.nextcloud.talk.repositories.conversations.ConversationsRepository
|
||||
import com.nextcloud.talk.utils.ApiUtils
|
||||
import com.nextcloud.talk.utils.ApiUtils.getUrlForRooms
|
||||
import io.reactivex.Observer
|
||||
import io.reactivex.android.schedulers.AndroidSchedulers
|
||||
import io.reactivex.disposables.Disposable
|
||||
@ -112,6 +121,10 @@ class ConversationInfoViewModel @Inject constructor(
|
||||
val getConversationReadOnlyState: LiveData<SetConversationReadOnlyViewState>
|
||||
get() = _getConversationReadOnlyState
|
||||
|
||||
private val _createRoomViewState = MutableLiveData<CreateRoomUIState>(CreateRoomUIState.None)
|
||||
val createRoomViewState: LiveData<CreateRoomUIState>
|
||||
get() = _createRoomViewState
|
||||
|
||||
fun getRoom(user: User, token: String) {
|
||||
_viewState.value = GetRoomStartState
|
||||
chatNetworkDataSource.getRoom(user, token)
|
||||
@ -120,7 +133,76 @@ class ConversationInfoViewModel @Inject constructor(
|
||||
?.subscribe(GetRoomObserver())
|
||||
}
|
||||
|
||||
fun createRoom() {
|
||||
@Suppress("Detekt.TooGenericExceptionCaught")
|
||||
fun createRoomFromOneToOne(user: User, autocompleteUsers: List<AutocompleteUser>, roomToken: String) {
|
||||
val apiVersion = ApiUtils.getConversationApiVersion(user, intArrayOf(ApiUtils.API_V4, 1))
|
||||
val url = getUrlForRooms(apiVersion, user.baseUrl!!)
|
||||
val credentials = ApiUtils.getCredentials(user.username, user.token)!!
|
||||
|
||||
val participantsBody = convertAutocompleteUserToParticipant(autocompleteUsers)
|
||||
|
||||
val body = CreateRoomRequest(
|
||||
roomName = createConversationNameByParticipants(autocompleteUsers),
|
||||
roomType = GROUP_CONVERSATION_TYPE,
|
||||
readOnly = 0,
|
||||
listable = 1,
|
||||
lobbyTimer = 0,
|
||||
sipEnabled = 0,
|
||||
permissions = 0,
|
||||
recordingConsent = 0,
|
||||
mentionPermissions = 0,
|
||||
participants = participantsBody,
|
||||
objectType = EXTENDED_CONVERSATION,
|
||||
objectId = roomToken
|
||||
)
|
||||
|
||||
viewModelScope.launch {
|
||||
try {
|
||||
val roomOverall = conversationsRepository.createRoom(
|
||||
credentials,
|
||||
url,
|
||||
body
|
||||
)
|
||||
_createRoomViewState.value = CreateRoomUIState.Success(roomOverall)
|
||||
} catch (e: Exception) {
|
||||
Log.e(TAG, "Failed to create room", e)
|
||||
_createRoomViewState.value = CreateRoomUIState.Error(e)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun createConversationNameByParticipants(autocompleteUsers: List<AutocompleteUser>): String {
|
||||
fun cutOffString(input: String, maxLength: Int): String {
|
||||
return if (input.length > maxLength) {
|
||||
input.take(maxLength)
|
||||
} else {
|
||||
input
|
||||
}
|
||||
}
|
||||
|
||||
val conversationName = autocompleteUsers
|
||||
.sortedBy { it.label?.lowercase() }
|
||||
.mapNotNull { it.label }
|
||||
.joinToString(NEW_CONVERSATION_PARTICIPANTS_SEPARATOR)
|
||||
|
||||
return cutOffString(conversationName, MAX_ROOM_NAME_LENGTH)
|
||||
}
|
||||
|
||||
private fun convertAutocompleteUserToParticipant(autocompleteUsers: List<AutocompleteUser>): Participants {
|
||||
val participants = Participants()
|
||||
|
||||
autocompleteUsers.forEach { autocompleteUser ->
|
||||
when (autocompleteUser.source) {
|
||||
GROUPS.name.lowercase() -> participants.groups.add(autocompleteUser.id!!)
|
||||
EMAILS.name.lowercase() -> participants.emails.add(autocompleteUser.id!!)
|
||||
CIRCLES.name.lowercase() -> participants.teams.add(autocompleteUser.id!!)
|
||||
FEDERATED.name.lowercase() -> participants.federatedUsers.add(autocompleteUser.id!!)
|
||||
"phones".lowercase() -> participants.phones.add(autocompleteUser.id!!)
|
||||
else -> participants.users.add(autocompleteUser.id!!)
|
||||
}
|
||||
}
|
||||
|
||||
return participants
|
||||
}
|
||||
|
||||
fun getCapabilities(user: User, token: String, conversationModel: ConversationModel) {
|
||||
@ -283,6 +365,10 @@ class ConversationInfoViewModel @Inject constructor(
|
||||
|
||||
companion object {
|
||||
private val TAG = ConversationInfoViewModel::class.simpleName
|
||||
private const val NEW_CONVERSATION_PARTICIPANTS_SEPARATOR = ", "
|
||||
private const val EXTENDED_CONVERSATION = "extended_conversation"
|
||||
private const val GROUP_CONVERSATION_TYPE = "2"
|
||||
private const val MAX_ROOM_NAME_LENGTH = 255
|
||||
}
|
||||
|
||||
sealed class ClearChatHistoryViewState {
|
||||
@ -303,6 +389,12 @@ class ConversationInfoViewModel @Inject constructor(
|
||||
data class Error(val exception: Exception) : AllowGuestsUIState()
|
||||
}
|
||||
|
||||
sealed class CreateRoomUIState {
|
||||
data object None : CreateRoomUIState()
|
||||
data class Success(val room: RoomOverall) : CreateRoomUIState()
|
||||
data class Error(val exception: Exception) : CreateRoomUIState()
|
||||
}
|
||||
|
||||
sealed class PasswordUiState {
|
||||
data object None : PasswordUiState()
|
||||
data object Success : PasswordUiState()
|
||||
|
@ -7,6 +7,8 @@
|
||||
*/
|
||||
package com.nextcloud.talk.repositories.conversations
|
||||
|
||||
import com.nextcloud.talk.conversationinfo.CreateRoomRequest
|
||||
import com.nextcloud.talk.models.json.conversations.RoomOverall
|
||||
import com.nextcloud.talk.models.json.generic.GenericOverall
|
||||
import com.nextcloud.talk.models.json.participants.TalkBan
|
||||
import io.reactivex.Observable
|
||||
@ -42,4 +44,6 @@ interface ConversationsRepository {
|
||||
suspend fun setConversationReadOnly(roomToken: String, state: Int): GenericOverall
|
||||
|
||||
suspend fun clearChatHistory(apiVersion: Int, roomToken: String): GenericOverall
|
||||
|
||||
suspend fun createRoom(credentials: String, url: String, body: CreateRoomRequest): RoomOverall
|
||||
}
|
||||
|
@ -9,7 +9,9 @@ package com.nextcloud.talk.repositories.conversations
|
||||
|
||||
import com.nextcloud.talk.api.NcApi
|
||||
import com.nextcloud.talk.api.NcApiCoroutines
|
||||
import com.nextcloud.talk.conversationinfo.CreateRoomRequest
|
||||
import com.nextcloud.talk.data.user.model.User
|
||||
import com.nextcloud.talk.models.json.conversations.RoomOverall
|
||||
import com.nextcloud.talk.models.json.generic.GenericOverall
|
||||
import com.nextcloud.talk.models.json.participants.TalkBan
|
||||
import com.nextcloud.talk.repositories.conversations.ConversationsRepository.ResendInvitationsResult
|
||||
@ -105,6 +107,15 @@ class ConversationsRepositoryImpl(
|
||||
)
|
||||
}
|
||||
|
||||
override suspend fun createRoom(credentials: String, url: String, body: CreateRoomRequest): RoomOverall {
|
||||
val response = coroutineApi.createRoomWithBody(
|
||||
credentials,
|
||||
url,
|
||||
body
|
||||
)
|
||||
return response
|
||||
}
|
||||
|
||||
override suspend fun banActor(
|
||||
credentials: String,
|
||||
url: String,
|
||||
|
Loading…
Reference in New Issue
Block a user