Create public conversation

Signed-off-by: sowjanyakch <sowjanya.kch@gmail.com>
This commit is contained in:
sowjanyakch 2024-08-20 23:54:05 +02:00 committed by Marcel Hibbe
parent 6b82d7209f
commit 2959d8e13a
No known key found for this signature in database
GPG Key ID: C793F8B59F43CE7B
7 changed files with 167 additions and 29 deletions

View File

@ -11,6 +11,7 @@ import com.nextcloud.talk.models.json.autocomplete.AutocompleteOverall
import com.nextcloud.talk.models.json.conversations.RoomOverall
import com.nextcloud.talk.models.json.generic.GenericOverall
import com.nextcloud.talk.models.json.participants.AddParticipantOverall
import retrofit2.http.DELETE
import retrofit2.http.Field
import retrofit2.http.FormUrlEncoded
import retrofit2.http.GET
@ -73,4 +74,10 @@ interface NcApiCoroutines {
@Url url: String?,
@QueryMap options: Map<String, String>?
): AddParticipantOverall
@POST
fun makeRoomPublic(@Header("Authorization") authorization: String?, @Url url: String?): GenericOverall
@DELETE
fun makeRoomPrivate(@Header("Authorization") authorization: String?, @Url url: String?): GenericOverall
}

View File

@ -49,6 +49,7 @@ import androidx.compose.material3.TopAppBar
import androidx.compose.runtime.Composable
import androidx.compose.runtime.collectAsState
import androidx.compose.runtime.getValue
import androidx.compose.runtime.remember
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.Color
@ -101,12 +102,15 @@ class ContactsActivityCompose : BaseActivity() {
}
val colorScheme = viewThemeUtils.getColorScheme(this)
val uiState = contactsViewModel.contactsViewState.collectAsState()
val selectedParticipants: List<AutocompleteUser> = if (isAddParticipantsEdit) {
intent.getParcelableArrayListExtra("selectedParticipants") ?: emptyList()
} else {
emptyList()
val selectedParticipants: List<AutocompleteUser> = remember {
if (isAddParticipants) {
intent.getParcelableArrayListExtra("selected participants") ?: emptyList()
} else {
emptyList()
}
}
contactsViewModel.updateSelectedParticipants(selectedParticipants)
val participants = selectedParticipants.toSet().toMutableList()
contactsViewModel.updateSelectedParticipants(participants)
MaterialTheme(
colorScheme = colorScheme
) {
@ -143,7 +147,7 @@ fun ContactItemRow(
context: Context,
selectedContacts: MutableList<AutocompleteUser>
) {
val isSelected = contact in selectedContacts
val isSelected = selectedContacts.contains(contact)
val roomUiState by contactsViewModel.roomViewState.collectAsState()
val isAddParticipants = contactsViewModel.isAddParticipantsView.collectAsState()
Row(
@ -177,16 +181,14 @@ fun ContactItemRow(
modifier = Modifier.size(width = 45.dp, height = 45.dp)
)
Text(modifier = Modifier.padding(16.dp), text = contact.label!!)
if (isAddParticipants.value) {
if (isSelected) {
Spacer(modifier = Modifier.weight(1f))
Icon(
imageVector = ImageVector.vectorResource(id = R.drawable.ic_check_circle),
contentDescription = "Selected",
tint = Color.Blue,
modifier = Modifier.padding(end = 8.dp)
)
}
if (isAddParticipants.value && isSelected) {
Spacer(modifier = Modifier.weight(1f))
Icon(
imageVector = ImageVector.vectorResource(id = R.drawable.ic_check_circle),
contentDescription = "Selected",
tint = Color.Blue,
modifier = Modifier.padding(end = 8.dp)
)
}
}
when (roomUiState) {

View File

@ -31,7 +31,7 @@ class ContactsViewModel @Inject constructor(
private val _searchState = MutableStateFlow(false)
val searchState: StateFlow<Boolean> = _searchState
private val selectedParticipants = mutableListOf<AutocompleteUser>()
val selectedParticipantsList: MutableList<AutocompleteUser> = selectedParticipants
val selectedParticipantsList: List<AutocompleteUser> = selectedParticipants
private val _isAddParticipantsView = MutableStateFlow(false)
val isAddParticipantsView: StateFlow<Boolean> = _isAddParticipantsView

View File

@ -24,6 +24,7 @@ import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.Spacer
import androidx.compose.foundation.layout.fillMaxHeight
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.size
@ -45,6 +46,7 @@ import androidx.compose.material3.Text
import androidx.compose.material3.TopAppBar
import androidx.compose.runtime.Composable
import androidx.compose.runtime.collectAsState
import androidx.compose.runtime.getValue
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.Color
@ -60,9 +62,12 @@ import coil.compose.AsyncImage
import com.nextcloud.talk.R
import com.nextcloud.talk.activities.BaseActivity
import com.nextcloud.talk.application.NextcloudTalkApplication
import com.nextcloud.talk.chat.ChatActivity
import com.nextcloud.talk.contacts.ContactsActivityCompose
import com.nextcloud.talk.contacts.RoomUiState
import com.nextcloud.talk.contacts.loadImage
import com.nextcloud.talk.models.json.autocomplete.AutocompleteUser
import com.nextcloud.talk.utils.bundle.BundleKeys
import javax.inject.Inject
@AutoInjector(NextcloudTalkApplication::class)
@ -80,10 +85,11 @@ class ConversationCreationActivity : BaseActivity() {
)[ConversationCreationViewModel::class.java]
setContent {
val colorScheme = viewThemeUtils.getColorScheme(this)
val context = LocalContext.current
MaterialTheme(
colorScheme = colorScheme
) {
ConversationCreationScreen(conversationCreationViewModel)
ConversationCreationScreen(conversationCreationViewModel, context)
}
}
}
@ -91,7 +97,7 @@ class ConversationCreationActivity : BaseActivity() {
@OptIn(ExperimentalMaterial3Api::class)
@Composable
fun ConversationCreationScreen(conversationCreationViewModel: ConversationCreationViewModel) {
fun ConversationCreationScreen(conversationCreationViewModel: ConversationCreationViewModel, context: Context) {
val context = LocalContext.current
val launcher = rememberLauncherForActivityResult(
contract = ActivityResultContracts.StartActivityForResult(),
@ -101,7 +107,8 @@ fun ConversationCreationScreen(conversationCreationViewModel: ConversationCreati
val data = result.data
val selectedParticipants = data?.getParcelableArrayListExtra<AutocompleteUser>("selectedParticipants")
?: emptyList()
conversationCreationViewModel.updateSelectedParticipants(selectedParticipants)
val participants = selectedParticipants.toMutableList()
conversationCreationViewModel.updateSelectedParticipants(participants)
}
}
)
@ -133,7 +140,7 @@ fun ConversationCreationScreen(conversationCreationViewModel: ConversationCreati
ConversationNameAndDescription(conversationCreationViewModel)
AddParticipants(launcher, context, conversationCreationViewModel)
RoomCreationOptions(conversationCreationViewModel)
CreateConversation()
CreateConversation(conversationCreationViewModel, context)
}
}
)
@ -234,10 +241,11 @@ fun AddParticipants(
context: Context,
conversationCreationViewModel: ConversationCreationViewModel
) {
val participants = conversationCreationViewModel.selectedParticipants.collectAsState()
val participants = conversationCreationViewModel.selectedParticipants.collectAsState().value
Column(
modifier = Modifier.fillMaxHeight()
modifier = Modifier
.fillMaxHeight()
.padding(start = 16.dp, end = 16.dp, top = 16.dp)
) {
Row {
@ -247,7 +255,7 @@ fun AddParticipants(
modifier = Modifier.padding(start = 16.dp, bottom = 16.dp)
)
Spacer(modifier = Modifier.weight(1f))
if (participants.value.isNotEmpty()) {
if (participants.isNotEmpty()) {
Text(
text = stringResource(id = R.string.nc_edit),
fontSize = 12.sp,
@ -257,8 +265,9 @@ fun AddParticipants(
val intent = Intent(context, ContactsActivityCompose::class.java)
intent.putParcelableArrayListExtra(
"selected participants",
participants.value as ArrayList<AutocompleteUser>
participants as ArrayList<AutocompleteUser>
)
intent.putExtra("isAddParticipants", true)
intent.putExtra("isAddParticipantsEdit", true)
launcher.launch(intent)
},
@ -267,7 +276,9 @@ fun AddParticipants(
}
}
participants.value.forEach { participant ->
val participant = participants.toSet()
participant.forEach { participant ->
Row(modifier = Modifier.fillMaxWidth(), verticalAlignment = Alignment.CenterVertically) {
val imageUri = participant.id?.let { conversationCreationViewModel.getImageUri(it, true) }
val errorPlaceholderImage: Int = R.drawable.account_circle_96dp
@ -298,7 +309,7 @@ fun AddParticipants(
},
verticalAlignment = Alignment.CenterVertically
) {
if (participants.value.isEmpty()) {
if (participant.isEmpty()) {
Icon(
painter = painterResource(id = R.drawable.ic_account_plus),
contentDescription = null,
@ -402,18 +413,52 @@ fun ConversationOptions(icon: Int? = null, text: Int, switch: @Composable (() ->
}
@Composable
fun CreateConversation() {
fun CreateConversation(conversationCreationViewModel: ConversationCreationViewModel, context: Context) {
val roomUiState by conversationCreationViewModel.roomViewState.collectAsState()
Box(
modifier = Modifier
.fillMaxWidth()
.padding(all = 16.dp),
.padding(all = 16.dp)
.clickable {
},
contentAlignment = Alignment.Center
) {
Button(
onClick = {
val roomType = if (conversationCreationViewModel.isGuestsAllowed.value) {
"ROOM_TYPE_PUBLIC"
} else {
"ROOM_TYPE_PRIVATE"
}
conversationCreationViewModel.createRoom(
roomType,
conversationCreationViewModel.roomName.value
)
}
) {
Text(text = stringResource(id = R.string.create_conversation))
}
}
when (roomUiState) {
is RoomUiState.Success -> {
val conversation = (roomUiState as RoomUiState.Success).conversation
val token = conversation?.token
if (token != null) {
conversationCreationViewModel.allowGuests(token, conversationCreationViewModel.isGuestsAllowed.value)
}
val bundle = Bundle()
bundle.putString(BundleKeys.KEY_ROOM_TOKEN, token)
val chatIntent = Intent(context, ChatActivity::class.java)
chatIntent.putExtras(bundle)
chatIntent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP)
context.startActivity(chatIntent)
}
is RoomUiState.Error -> {
val errorMessage = (roomUiState as RoomUiState.Error).message
Box(modifier = Modifier.fillMaxSize(), contentAlignment = Alignment.Center) {
Text(text = "Error: $errorMessage", color = Color.Red)
}
}
is RoomUiState.None -> {}
}
}

View File

@ -7,12 +7,16 @@
package com.nextcloud.talk.conversationcreation
import com.nextcloud.talk.models.json.conversations.RoomOverall
import com.nextcloud.talk.models.json.generic.GenericOverall
import com.nextcloud.talk.models.json.participants.AddParticipantOverall
interface ConversationCreationRepository {
fun allowGuests(token: String, allow: Boolean): ConversationCreationRepositoryImpl.AllowGuestsResult
suspend fun renameConversation(roomToken: String, roomNameNew: String?): GenericOverall
suspend fun setConversationDescription(roomToken: String, description: String?): GenericOverall
suspend fun addParticipants(conversationToken: String?, userId: String, sourceType: String): AddParticipantOverall
suspend fun createRoom(roomType: String, conversationName: String?): RoomOverall
fun getImageUri(avatarId: String, requestBigSize: Boolean): String
}

View File

@ -10,8 +10,10 @@ package com.nextcloud.talk.conversationcreation
import com.nextcloud.talk.api.NcApiCoroutines
import com.nextcloud.talk.data.user.model.User
import com.nextcloud.talk.models.RetrofitBucket
import com.nextcloud.talk.models.json.conversations.RoomOverall
import com.nextcloud.talk.models.json.generic.GenericOverall
import com.nextcloud.talk.models.json.participants.AddParticipantOverall
import com.nextcloud.talk.repositories.conversations.ConversationsRepositoryImpl.Companion.STATUS_CODE_OK
import com.nextcloud.talk.users.UserManager
import com.nextcloud.talk.utils.ApiUtils
import com.nextcloud.talk.utils.ApiUtils.getRetrofitBucketForAddParticipant
@ -25,6 +27,9 @@ class ConversationCreationRepositoryImpl(
val currentUser: User = _currentUser
val credentials = ApiUtils.getCredentials(_currentUser.username, _currentUser.token)
val apiVersion = ApiUtils.getConversationApiVersion(_currentUser, intArrayOf(ApiUtils.API_V4, ApiUtils.API_V1))
data class AllowGuestsResult(
val allow: Boolean
)
override suspend fun renameConversation(roomToken: String, roomNameNew: String?): GenericOverall {
return ncApiCoroutines.renameRoom(
@ -81,4 +86,55 @@ class ConversationCreationRepositoryImpl(
requestBigSize
)
}
override suspend fun createRoom(roomType: String, conversationName: String?): RoomOverall {
val retrofitBucket: RetrofitBucket =
if (roomType == "ROOM_TYPE_PUBLIC") {
ApiUtils.getRetrofitBucketForCreateRoom(
apiVersion,
currentUser.baseUrl!!,
"ROOM_TYPE_PUBLIC",
null,
null,
conversationName
)
} else {
ApiUtils.getRetrofitBucketForCreateRoom(
apiVersion,
currentUser.baseUrl!!,
"ROOM_TYPE_GROUP",
null,
null,
conversationName
)
}
val response = ncApiCoroutines.createRoom(
credentials,
retrofitBucket.url,
retrofitBucket.queryMap
)
return response
}
override fun allowGuests(token: String, allow: Boolean): AllowGuestsResult {
val url = ApiUtils.getUrlForRoomPublic(
apiVersion,
_currentUser.baseUrl!!,
token
)
val result = if (allow) {
ncApiCoroutines.makeRoomPublic(
credentials,
url
)
} else {
ncApiCoroutines.makeRoomPrivate(
credentials,
url
)
}
return AllowGuestsResult(result.ocs!!.meta!!.statusCode == STATUS_CODE_OK && allow)
}
}

View File

@ -12,7 +12,9 @@ import androidx.compose.runtime.mutableStateOf
import androidx.lifecycle.ViewModel
import androidx.lifecycle.viewModelScope
import com.nextcloud.talk.contacts.AddParticipantsUiState
import com.nextcloud.talk.contacts.RoomUiState
import com.nextcloud.talk.models.json.autocomplete.AutocompleteUser
import com.nextcloud.talk.models.json.conversations.Conversation
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.StateFlow
import kotlinx.coroutines.launch
@ -23,6 +25,8 @@ class ConversationCreationViewModel @Inject constructor(
) : ViewModel() {
private val _selectedParticipants = MutableStateFlow<List<AutocompleteUser>>(emptyList())
val selectedParticipants: StateFlow<List<AutocompleteUser>> = _selectedParticipants
private val _roomViewState = MutableStateFlow<RoomUiState>(RoomUiState.None)
val roomViewState: StateFlow<RoomUiState> = _roomViewState
fun updateSelectedParticipants(participants: List<AutocompleteUser>) {
_selectedParticipants.value = participants
@ -80,4 +84,24 @@ class ConversationCreationViewModel @Inject constructor(
fun getImageUri(avatarId: String, requestBigSize: Boolean): String {
return repository.getImageUri(avatarId, requestBigSize)
}
fun createRoom(roomType: String, conversationName: String?) {
viewModelScope.launch {
try {
val room = repository.createRoom(
roomType,
conversationName
)
val conversation: Conversation? = room.ocs?.data
_roomViewState.value = RoomUiState.Success(conversation)
} catch (exception: Exception) {
_roomViewState.value = RoomUiState.Error(exception.message ?: "")
}
}
}
fun allowGuests(token: String, allow: Boolean): ConversationCreationRepositoryImpl.AllowGuestsResult {
return repository.allowGuests(token, allow)
}
}