浏览代码

Create public conversation

Signed-off-by: sowjanyakch <sowjanya.kch@gmail.com>
sowjanyakch 7 月之前
父节点
当前提交
2959d8e13a

+ 7 - 0
app/src/main/java/com/nextcloud/talk/api/NcApiCoroutines.kt

@@ -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
 }

+ 18 - 16
app/src/main/java/com/nextcloud/talk/contacts/ContactsActivityCompose.kt

@@ -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) {

+ 1 - 1
app/src/main/java/com/nextcloud/talk/contacts/ContactsViewModel.kt

@@ -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
 

+ 57 - 12
app/src/main/java/com/nextcloud/talk/conversationcreation/ConversationCreationActivity.kt

@@ -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 -> {}
+    }
 }

+ 4 - 0
app/src/main/java/com/nextcloud/talk/conversationcreation/ConversationCreationRepository.kt

@@ -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
 }

+ 56 - 0
app/src/main/java/com/nextcloud/talk/conversationcreation/ConversationCreationRepositoryImpl.kt

@@ -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)
+    }
 }

+ 24 - 0
app/src/main/java/com/nextcloud/talk/conversationcreation/ConversationCreationViewModel.kt

@@ -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)
+    }
 }