浏览代码

Merge pull request #2326 from nextcloud/feature/2134/allow-guests

Move allow guests preferences to conversation info
Tim Krüger 2 年之前
父节点
当前提交
cd25a7e14d
共有 22 个文件被更改,包括 768 次插入437 次删除
  1. 9 13
      app/src/main/java/com/nextcloud/talk/activities/CallActivity.java
  2. 9 0
      app/src/main/java/com/nextcloud/talk/api/NcApi.java
  3. 49 31
      app/src/main/java/com/nextcloud/talk/controllers/ConversationInfoController.kt
  4. 0 6
      app/src/main/java/com/nextcloud/talk/controllers/bottomsheet/ConversationOperationEnum.kt
  5. 3 35
      app/src/main/java/com/nextcloud/talk/controllers/bottomsheet/EntryMenuController.kt
  6. 0 55
      app/src/main/java/com/nextcloud/talk/controllers/bottomsheet/OperationsMenuController.kt
  7. 251 0
      app/src/main/java/com/nextcloud/talk/conversation/info/GuestAccessHelper.kt
  8. 8 0
      app/src/main/java/com/nextcloud/talk/dagger/modules/RepositoryModule.kt
  9. 36 0
      app/src/main/java/com/nextcloud/talk/models/json/conversations/password/PasswordData.kt
  10. 40 0
      app/src/main/java/com/nextcloud/talk/models/json/conversations/password/PasswordOCS.kt
  11. 36 0
      app/src/main/java/com/nextcloud/talk/models/json/conversations/password/PasswordOverall.kt
  12. 46 0
      app/src/main/java/com/nextcloud/talk/repositories/conversations/ConversationsRepository.kt
  13. 113 0
      app/src/main/java/com/nextcloud/talk/repositories/conversations/ConversationsRepositoryImpl.kt
  14. 0 76
      app/src/main/java/com/nextcloud/talk/ui/dialog/ConversationsListBottomDialog.kt
  15. 4 0
      app/src/main/java/com/nextcloud/talk/utils/ApiUtils.java
  16. 9 17
      app/src/main/java/com/nextcloud/talk/utils/ShareUtils.kt
  17. 14 4
      app/src/main/res/layout/controller_conversation_info.xml
  18. 0 180
      app/src/main/res/layout/dialog_conversation_operations.xml
  19. 42 0
      app/src/main/res/layout/dialog_password.xml
  20. 81 0
      app/src/main/res/layout/guest_access_settings_item.xml
  21. 16 6
      app/src/main/res/values/strings.xml
  22. 2 14
      app/src/test/java/com/nextcloud/talk/utils/ShareUtilsTest.kt

+ 9 - 13
app/src/main/java/com/nextcloud/talk/activities/CallActivity.java

@@ -1707,8 +1707,8 @@ public class CallActivity extends CallBaseActivity {
             }
         }
 
-        for (int i = 0; i < peerConnectionWrapperList.size(); i++) {
-            endPeerConnection(peerConnectionWrapperList.get(i).getSessionId(), false);
+        for (PeerConnectionWrapper wrapper : peerConnectionWrapperList) {
+            endPeerConnection(wrapper.getSessionId(), false);
         }
 
         if (localStream != null) {
@@ -1887,10 +1887,10 @@ public class CallActivity extends CallBaseActivity {
     }
 
     private PeerConnectionWrapper getPeerConnectionWrapperForSessionIdAndType(String sessionId, String type) {
-        for (int i = 0; i < peerConnectionWrapperList.size(); i++) {
-            if (peerConnectionWrapperList.get(i).getSessionId().equals(sessionId)
-                && peerConnectionWrapperList.get(i).getVideoStreamType().equals(type)) {
-                return peerConnectionWrapperList.get(i);
+        for (PeerConnectionWrapper wrapper : peerConnectionWrapperList) {
+            if (wrapper.getSessionId().equals(sessionId)
+                && wrapper.getVideoStreamType().equals(type)) {
+                return wrapper;
             }
         }
 
@@ -1980,10 +1980,8 @@ public class CallActivity extends CallBaseActivity {
 
     private void endPeerConnection(String sessionId, boolean justScreen) {
         List<PeerConnectionWrapper> peerConnectionWrappers;
-        PeerConnectionWrapper peerConnectionWrapper;
         if (!(peerConnectionWrappers = getPeerConnectionWrapperListForSessionId(sessionId)).isEmpty()) {
-            for (int i = 0; i < peerConnectionWrappers.size(); i++) {
-                peerConnectionWrapper = peerConnectionWrappers.get(i);
+            for (PeerConnectionWrapper peerConnectionWrapper : peerConnectionWrappers) {
                 if (peerConnectionWrapper.getSessionId().equals(sessionId)) {
                     if (VIDEO_STREAM_TYPE_SCREEN.equals(peerConnectionWrapper.getVideoStreamType()) || !justScreen) {
                         runOnUiThread(() -> removeMediaStream(sessionId));
@@ -2104,10 +2102,8 @@ public class CallActivity extends CallBaseActivity {
         nickChangedPayload.put("userid", conversationUser.getUserId());
         nickChangedPayload.put("name", conversationUser.getDisplayName());
         dataChannelMessage.setPayload(nickChangedPayload);
-        final PeerConnectionWrapper peerConnectionWrapper;
-        for (int i = 0; i < peerConnectionWrapperList.size(); i++) {
-            if (peerConnectionWrapperList.get(i).isMCUPublisher()) {
-                peerConnectionWrapper = peerConnectionWrapperList.get(i);
+        for (PeerConnectionWrapper peerConnectionWrapper : peerConnectionWrapperList) {
+            if (peerConnectionWrapper.isMCUPublisher()) {
                 Observable
                     .interval(1, TimeUnit.SECONDS)
                     .repeatUntil(() -> (!isConnectionEstablished() || isDestroyed()))

+ 9 - 0
app/src/main/java/com/nextcloud/talk/api/NcApi.java

@@ -142,6 +142,9 @@ public interface NcApi {
     Observable<AddParticipantOverall> addParticipant(@Header("Authorization") String authorization, @Url String url,
                                                      @QueryMap Map<String, String> options);
 
+    @POST
+    Observable<GenericOverall> resendParticipantInvitations(@Header("Authorization") String authorization,
+                                                            @Url String url);
 
     // also used for removing a guest from a conversation
     @Deprecated
@@ -313,6 +316,12 @@ public interface NcApi {
     Observable<GenericOverall> setPassword(@Header("Authorization") String authorization, @Url String url,
                                            @Field("password") String password);
 
+    @FormUrlEncoded
+    @PUT
+    Observable<Response<GenericOverall>> setPassword2(@Header("Authorization") String authorization,
+                                                     @Url String url,
+                                                     @Field("password") String password);
+
     @GET
     Observable<CapabilitiesOverall> getCapabilities(@Header("Authorization") String authorization, @Url String url);
 

+ 49 - 31
app/src/main/java/com/nextcloud/talk/controllers/ConversationInfoController.kt

@@ -6,7 +6,7 @@
  * @author Tim Krüger
  * @author Marcel Hibbe
  * Copyright (C) 2022 Marcel Hibbe (dev@mhibbe.de)
- * Copyright (C) 2021 Tim Krüger <t@timkrueger.me>
+ * Copyright (C) 2021-2022 Tim Krüger <t@timkrueger.me>
  * Copyright (C) 2021 Andy Scherzinger (info@andy-scherzinger.de)
  * Copyright (C) 2017-2018 Mario Danic <mario@lovelyhq.com>
  *
@@ -37,6 +37,8 @@ import android.text.TextUtils
 import android.util.Log
 import android.view.MenuItem
 import android.view.View
+import android.view.View.GONE
+import android.view.View.VISIBLE
 import android.widget.Toast
 import androidx.appcompat.app.AlertDialog
 import androidx.appcompat.widget.SwitchCompat
@@ -61,6 +63,7 @@ import com.nextcloud.talk.controllers.base.BaseController
 import com.nextcloud.talk.controllers.bottomsheet.items.BasicListItemWithImage
 import com.nextcloud.talk.controllers.bottomsheet.items.listItemsWithImage
 import com.nextcloud.talk.controllers.util.viewBinding
+import com.nextcloud.talk.conversation.info.GuestAccessHelper
 import com.nextcloud.talk.data.user.model.User
 import com.nextcloud.talk.databinding.ControllerConversationInfoBinding
 import com.nextcloud.talk.events.EventStatus
@@ -75,6 +78,7 @@ import com.nextcloud.talk.models.json.participants.Participant.ActorType.CIRCLES
 import com.nextcloud.talk.models.json.participants.Participant.ActorType.GROUPS
 import com.nextcloud.talk.models.json.participants.Participant.ActorType.USERS
 import com.nextcloud.talk.models.json.participants.ParticipantsOverall
+import com.nextcloud.talk.repositories.conversations.ConversationsRepository
 import com.nextcloud.talk.shareditems.activities.SharedItemsActivity
 import com.nextcloud.talk.utils.ApiUtils
 import com.nextcloud.talk.utils.DateConstants
@@ -110,6 +114,9 @@ class ConversationInfoController(args: Bundle) :
     @Inject
     lateinit var ncApi: NcApi
 
+    @Inject
+    lateinit var conversationsRepository: ConversationsRepository
+
     @Inject
     lateinit var eventBus: EventBus
 
@@ -167,6 +174,7 @@ class ConversationInfoController(args: Bundle) :
 
         binding.notificationSettingsView.notificationSettings.setStorageModule(databaseStorageModule)
         binding.webinarInfoView.webinarSettings.setStorageModule(databaseStorageModule)
+        binding.guestAccessView.guestAccessSettings.setStorageModule(databaseStorageModule)
 
         binding.deleteConversationAction.setOnClickListener { showDeleteConversationDialog() }
         binding.leaveConversationAction.setOnClickListener { leaveConversation() }
@@ -176,7 +184,7 @@ class ConversationInfoController(args: Bundle) :
         if (CapabilitiesUtilNew.hasSpreedFeatureCapability(conversationUser, "rich-object-list-media")) {
             binding.showSharedItemsAction.setOnClickListener { showSharedItems() }
         } else {
-            binding.categorySharedItems.visibility = View.GONE
+            binding.categorySharedItems.visibility = GONE
         }
 
         fetchRoomInfo()
@@ -190,7 +198,9 @@ class ConversationInfoController(args: Bundle) :
             listOf(
                 binding.webinarInfoView.conversationInfoLobby,
                 binding.notificationSettingsView.callNotifications,
-                binding.notificationSettingsView.conversationInfoPriorityConversation
+                binding.notificationSettingsView.conversationInfoPriorityConversation,
+                binding.guestAccessView.guestAccessAllowSwitch,
+                binding.guestAccessView.guestAccessPasswordSwitch
             ).forEach(viewThemeUtils::colorSwitchPreference)
         }
     }
@@ -205,6 +215,7 @@ class ConversationInfoController(args: Bundle) :
                 ownOptions,
                 categorySharedItems,
                 categoryConversationSettings,
+                binding.guestAccessView.guestAccessCategory,
                 binding.webinarInfoView.conversationInfoWebinar,
                 binding.notificationSettingsView.notificationSettingsCategory
             ).forEach(viewThemeUtils::colorPreferenceCategory)
@@ -225,7 +236,7 @@ class ConversationInfoController(args: Bundle) :
     override fun onViewBound(view: View) {
         super.onViewBound(view)
 
-        binding.addParticipantsAction.visibility = View.GONE
+        binding.addParticipantsAction.visibility = GONE
 
         viewThemeUtils.colorCircularProgressBar(binding.progressBar)
     }
@@ -235,7 +246,7 @@ class ConversationInfoController(args: Bundle) :
             webinaryRoomType(conversation!!) &&
             conversation!!.canModerate(conversationUser!!)
         ) {
-            binding.webinarInfoView.webinarSettings.visibility = View.VISIBLE
+            binding.webinarInfoView.webinarSettings.visibility = VISIBLE
 
             val isLobbyOpenToModeratorsOnly =
                 conversation!!.lobbyState == Conversation.LobbyState.LOBBY_STATE_MODERATORS_ONLY
@@ -271,7 +282,7 @@ class ConversationInfoController(args: Bundle) :
                     submitLobbyChanges()
                 }
         } else {
-            binding.webinarInfoView.webinarSettings.visibility = View.GONE
+            binding.webinarInfoView.webinarSettings.visibility = GONE
         }
     }
 
@@ -311,9 +322,9 @@ class ConversationInfoController(args: Bundle) :
         }
 
         if (isChecked) {
-            binding.webinarInfoView.startTimePreferences.visibility = View.VISIBLE
+            binding.webinarInfoView.startTimePreferences.visibility = VISIBLE
         } else {
-            binding.webinarInfoView.startTimePreferences.visibility = View.GONE
+            binding.webinarInfoView.startTimePreferences.visibility = GONE
         }
     }
 
@@ -433,7 +444,7 @@ class ConversationInfoController(args: Bundle) :
 
         setupAdapter()
 
-        binding.participantsListCategory.visibility = View.VISIBLE
+        binding.participantsListCategory.visibility = VISIBLE
         adapter!!.updateDataSet(userItems)
     }
 
@@ -523,7 +534,7 @@ class ConversationInfoController(args: Bundle) :
 
     private fun leaveConversation() {
         workerData?.let {
-            WorkManager.getInstance().enqueue(
+            WorkManager.getInstance(context).enqueue(
                 OneTimeWorkRequest.Builder(
                     LeaveConversationWorker::class
                         .java
@@ -586,7 +597,7 @@ class ConversationInfoController(args: Bundle) :
 
     private fun deleteConversation() {
         workerData?.let {
-            WorkManager.getInstance().enqueue(
+            WorkManager.getInstance(context).enqueue(
                 OneTimeWorkRequest.Builder(
                     DeleteConversationWorker::class.java
                 ).setInputData(it).build()
@@ -624,40 +635,40 @@ class ConversationInfoController(args: Bundle) :
                         val conversationCopy = conversation
 
                         if (conversationCopy!!.canModerate(conversationUser)) {
-                            binding.addParticipantsAction.visibility = View.VISIBLE
+                            binding.addParticipantsAction.visibility = VISIBLE
                             if (CapabilitiesUtilNew.hasSpreedFeatureCapability(conversationUser, "clear-history")) {
-                                binding.clearConversationHistory.visibility = View.VISIBLE
+                                binding.clearConversationHistory.visibility = VISIBLE
                             } else {
-                                binding.clearConversationHistory.visibility = View.GONE
+                                binding.clearConversationHistory.visibility = GONE
                             }
                         } else {
-                            binding.addParticipantsAction.visibility = View.GONE
-                            binding.clearConversationHistory.visibility = View.GONE
+                            binding.addParticipantsAction.visibility = GONE
+                            binding.clearConversationHistory.visibility = GONE
                         }
 
                         if (isAttached && (!isBeingDestroyed || !isDestroyed)) {
-                            binding.ownOptions.visibility = View.VISIBLE
+                            binding.ownOptions.visibility = VISIBLE
 
                             setupWebinaryView()
 
                             if (!conversation!!.canLeave()) {
-                                binding.leaveConversationAction.visibility = View.GONE
+                                binding.leaveConversationAction.visibility = GONE
                             } else {
-                                binding.leaveConversationAction.visibility = View.VISIBLE
+                                binding.leaveConversationAction.visibility = VISIBLE
                             }
 
                             if (!conversation!!.canDelete(conversationUser)) {
-                                binding.deleteConversationAction.visibility = View.GONE
+                                binding.deleteConversationAction.visibility = GONE
                             } else {
-                                binding.deleteConversationAction.visibility = View.VISIBLE
+                                binding.deleteConversationAction.visibility = VISIBLE
                             }
 
                             if (Conversation.ConversationType.ROOM_SYSTEM == conversation!!.type) {
-                                binding.notificationSettingsView.callNotifications.visibility = View.GONE
+                                binding.notificationSettingsView.callNotifications.visibility = GONE
                             }
 
                             if (conversation!!.notificationCalls === null) {
-                                binding.notificationSettingsView.callNotifications.visibility = View.GONE
+                                binding.notificationSettingsView.callNotifications.visibility = GONE
                             } else {
                                 binding.notificationSettingsView.callNotifications.value =
                                     conversationCopy.notificationCalls == 1
@@ -665,22 +676,29 @@ class ConversationInfoController(args: Bundle) :
 
                             getListOfParticipants()
 
-                            binding.progressBar.visibility = View.GONE
+                            binding.progressBar.visibility = GONE
 
-                            binding.conversationInfoName.visibility = View.VISIBLE
+                            binding.conversationInfoName.visibility = VISIBLE
 
                             binding.displayNameText.text = conversation!!.displayName
 
                             if (conversation!!.description != null && !conversation!!.description!!.isEmpty()) {
                                 binding.descriptionText.text = conversation!!.description
-                                binding.conversationDescription.visibility = View.VISIBLE
+                                binding.conversationDescription.visibility = VISIBLE
                             }
 
                             loadConversationAvatar()
                             adjustNotificationLevelUI()
                             initExpiringMessageOption()
 
-                            binding.notificationSettingsView.notificationSettings.visibility = View.VISIBLE
+                            GuestAccessHelper(
+                                this@ConversationInfoController,
+                                binding,
+                                conversation!!,
+                                conversationUser
+                            ).setupGuestAccess()
+
+                            binding.notificationSettingsView.notificationSettings.visibility = VISIBLE
                         }
                     } catch (npe: NullPointerException) {
                         // view binding can be null
@@ -1035,7 +1053,7 @@ class ConversationInfoController(args: Bundle) :
                     cornerRadius(res = R.dimen.corner_radius)
 
                     title(text = participant.displayName)
-                    listItemsWithImage(items = items) { dialog, index, _ ->
+                    listItemsWithImage(items = items) { _, index, _ ->
                         if (index == 0) {
                             removeAttendeeFromConversation(apiVersion, participant)
                         }
@@ -1061,7 +1079,7 @@ class ConversationInfoController(args: Bundle) :
                 cornerRadius(res = R.dimen.corner_radius)
 
                 title(text = participant.displayName)
-                listItemsWithImage(items = items) { dialog, index, _ ->
+                listItemsWithImage(items = items) { _, index, _ ->
                     if (index == 0) {
                         removeAttendeeFromConversation(apiVersion, participant)
                     }
@@ -1081,7 +1099,7 @@ class ConversationInfoController(args: Bundle) :
                 cornerRadius(res = R.dimen.corner_radius)
 
                 title(text = participant.displayName)
-                listItemsWithImage(items = items) { dialog, index, _ ->
+                listItemsWithImage(items = items) { _, index, _ ->
                     if (index == 0) {
                         removeAttendeeFromConversation(apiVersion, participant)
                     }
@@ -1132,7 +1150,7 @@ class ConversationInfoController(args: Bundle) :
                 cornerRadius(res = R.dimen.corner_radius)
 
                 title(text = participant.displayName)
-                listItemsWithImage(items = items) { dialog, index, _ ->
+                listItemsWithImage(items = items) { _, index, _ ->
                     var actionToTrigger = index
                     if (participant.attendeePin == null || participant.attendeePin!!.isEmpty()) {
                         actionToTrigger++

+ 0 - 6
app/src/main/java/com/nextcloud/talk/controllers/bottomsheet/ConversationOperationEnum.kt

@@ -22,12 +22,6 @@ package com.nextcloud.talk.controllers.bottomsheet
 
 enum class ConversationOperationEnum {
     OPS_CODE_RENAME_ROOM,
-    OPS_CODE_MAKE_PUBLIC,
-    OPS_CODE_CHANGE_PASSWORD,
-    OPS_CODE_CLEAR_PASSWORD,
-    OPS_CODE_SET_PASSWORD,
-    OPS_CODE_SHARE_LINK,
-    OPS_CODE_MAKE_PRIVATE,
     OPS_CODE_GET_AND_JOIN_ROOM,
     OPS_CODE_INVITE_USERS,
     OPS_CODE_MARK_AS_READ,

+ 3 - 35
app/src/main/java/com/nextcloud/talk/controllers/bottomsheet/EntryMenuController.kt

@@ -23,7 +23,6 @@
  */
 package com.nextcloud.talk.controllers.bottomsheet
 
-import android.content.ComponentName
 import android.content.Intent
 import android.content.res.ColorStateList
 import android.os.Bundle
@@ -47,7 +46,6 @@ import com.nextcloud.talk.controllers.util.viewBinding
 import com.nextcloud.talk.databinding.ControllerEntryMenuBinding
 import com.nextcloud.talk.models.json.conversations.Conversation
 import com.nextcloud.talk.users.UserManager
-import com.nextcloud.talk.utils.ShareUtils
 import com.nextcloud.talk.utils.UriUtils
 import com.nextcloud.talk.utils.bundle.BundleKeys
 import com.nextcloud.talk.utils.singletons.ApplicationWideMessageHolder
@@ -139,13 +137,6 @@ class EntryMenuController(args: Bundle) :
                 )
             }
 
-            ConversationOperationEnum.OPS_CODE_CHANGE_PASSWORD -> {
-                labelText = resources!!.getString(R.string.nc_new_password)
-                binding.textEdit.inputType = InputType.TYPE_CLASS_TEXT or InputType.TYPE_TEXT_VARIATION_PASSWORD
-            }
-
-            ConversationOperationEnum.OPS_CODE_SET_PASSWORD,
-            ConversationOperationEnum.OPS_CODE_SHARE_LINK,
             ConversationOperationEnum.OPS_CODE_JOIN_ROOM -> {
                 // 99 is joining a conversation via password
                 labelText = resources!!.getString(R.string.nc_password)
@@ -242,18 +233,12 @@ class EntryMenuController(args: Bundle) :
     private fun onOkButtonClick() {
         if (operation === ConversationOperationEnum.OPS_CODE_JOIN_ROOM) {
             joinRoom()
-        } else if (operation !== ConversationOperationEnum.OPS_CODE_SHARE_LINK &&
+        } else if (
             operation !== ConversationOperationEnum.OPS_CODE_GET_AND_JOIN_ROOM &&
             operation !== ConversationOperationEnum.OPS_CODE_INVITE_USERS
         ) {
             val bundle = Bundle()
-            if (operation === ConversationOperationEnum.OPS_CODE_CHANGE_PASSWORD ||
-                operation === ConversationOperationEnum.OPS_CODE_SET_PASSWORD
-            ) {
-                conversation!!.password = binding.textEdit.text.toString()
-            } else {
-                conversation!!.name = binding.textEdit.text.toString()
-            }
+            conversation!!.name = binding.textEdit.text.toString()
             bundle.putParcelable(BundleKeys.KEY_ROOM, Parcels.wrap<Any>(conversation))
             bundle.putSerializable(BundleKeys.KEY_OPERATION_CODE, operation)
             router.pushController(
@@ -261,20 +246,6 @@ class EntryMenuController(args: Bundle) :
                     .pushChangeHandler(HorizontalChangeHandler())
                     .popChangeHandler(HorizontalChangeHandler())
             )
-        } else if (operation === ConversationOperationEnum.OPS_CODE_SHARE_LINK && activity != null) {
-            shareIntent?.putExtra(
-                Intent.EXTRA_TEXT,
-                ShareUtils.getStringForIntent(
-                    activity,
-                    binding.textEdit.text.toString(),
-                    userManager,
-                    conversation
-                )
-            )
-            val intent = Intent(shareIntent)
-            intent.component = ComponentName(packageName, name)
-            intent.flags = Intent.FLAG_ACTIVITY_NEW_TASK
-            activity?.startActivity(intent)
         } else if (operation !== ConversationOperationEnum.OPS_CODE_INVITE_USERS) {
             val bundle = Bundle()
             bundle.putSerializable(BundleKeys.KEY_OPERATION_CODE, operation)
@@ -336,10 +307,7 @@ class EntryMenuController(args: Bundle) :
     companion object {
         private val PASSWORD_ENTRY_OPERATIONS: List<ConversationOperationEnum> =
             immutableListOf(
-                ConversationOperationEnum.OPS_CODE_JOIN_ROOM,
-                ConversationOperationEnum.OPS_CODE_CHANGE_PASSWORD,
-                ConversationOperationEnum.OPS_CODE_SET_PASSWORD,
-                ConversationOperationEnum.OPS_CODE_SHARE_LINK
+                ConversationOperationEnum.OPS_CODE_JOIN_ROOM
             )
         const val OPACITY_DISABLED = 0.38f
         const val OPACITY_BUTTON_DISABLED = 0.7f

+ 0 - 55
app/src/main/java/com/nextcloud/talk/controllers/bottomsheet/OperationsMenuController.kt

@@ -211,11 +211,6 @@ class OperationsMenuController(args: Bundle) : BaseController(
         credentials = ApiUtils.getCredentials(currentUser!!.username, currentUser!!.token)
         when (operation) {
             ConversationOperationEnum.OPS_CODE_RENAME_ROOM -> operationRenameRoom()
-            ConversationOperationEnum.OPS_CODE_MAKE_PUBLIC -> operationMakePublic()
-            ConversationOperationEnum.OPS_CODE_CHANGE_PASSWORD,
-            ConversationOperationEnum.OPS_CODE_CLEAR_PASSWORD,
-            ConversationOperationEnum.OPS_CODE_SET_PASSWORD -> operationChangePassword()
-            ConversationOperationEnum.OPS_CODE_MAKE_PRIVATE -> operationMakePrivate()
             ConversationOperationEnum.OPS_CODE_GET_AND_JOIN_ROOM -> operationGetAndJoinRoom()
             ConversationOperationEnum.OPS_CODE_INVITE_USERS -> operationInviteUsers()
             ConversationOperationEnum.OPS_CODE_MARK_AS_READ -> operationMarkAsRead()
@@ -267,56 +262,6 @@ class OperationsMenuController(args: Bundle) : BaseController(
             .subscribe(GenericOperationsObserver())
     }
 
-    private fun operationMakePrivate() {
-        ncApi.makeRoomPrivate(
-            credentials,
-            ApiUtils.getUrlForRoomPublic(
-                apiVersion(),
-                currentUser!!.baseUrl,
-                conversation!!.token
-            )
-        )
-            .subscribeOn(Schedulers.io())
-            .observeOn(AndroidSchedulers.mainThread())
-            .retry(1)
-            .subscribe(GenericOperationsObserver())
-    }
-
-    private fun operationChangePassword() {
-        var pass: String? = ""
-        if (conversation!!.password != null) {
-            pass = conversation!!.password
-        }
-        ncApi.setPassword(
-            credentials,
-            ApiUtils.getUrlForRoomPassword(
-                apiVersion(),
-                currentUser!!.baseUrl,
-                conversation!!.token
-            ),
-            pass
-        )
-            .subscribeOn(Schedulers.io())
-            .observeOn(AndroidSchedulers.mainThread())
-            .retry(1)
-            .subscribe(GenericOperationsObserver())
-    }
-
-    private fun operationMakePublic() {
-        ncApi.makeRoomPublic(
-            credentials,
-            ApiUtils.getUrlForRoomPublic(
-                apiVersion(),
-                currentUser!!.baseUrl,
-                conversation!!.token
-            )
-        )
-            .subscribeOn(Schedulers.io())
-            .observeOn(AndroidSchedulers.mainThread())
-            .retry(1)
-            .subscribe(GenericOperationsObserver())
-    }
-
     private fun operationRenameRoom() {
         ncApi.renameRoom(
             credentials,

+ 251 - 0
app/src/main/java/com/nextcloud/talk/conversation/info/GuestAccessHelper.kt

@@ -0,0 +1,251 @@
+package com.nextcloud.talk.conversation.info
+
+import android.annotation.SuppressLint
+import android.content.Intent
+import android.util.Log
+import android.view.LayoutInflater
+import android.view.View
+import android.widget.Toast
+import androidx.appcompat.app.AlertDialog
+import androidx.appcompat.widget.SwitchCompat
+import com.google.android.material.dialog.MaterialAlertDialogBuilder
+import com.nextcloud.talk.R
+import com.nextcloud.talk.controllers.ConversationInfoController
+import com.nextcloud.talk.data.user.model.User
+import com.nextcloud.talk.databinding.ControllerConversationInfoBinding
+import com.nextcloud.talk.databinding.DialogPasswordBinding
+import com.nextcloud.talk.models.json.conversations.Conversation
+import com.nextcloud.talk.repositories.conversations.ConversationsRepository
+import com.nextcloud.talk.utils.Mimetype
+import com.nextcloud.talk.utils.ShareUtils
+import io.reactivex.Observer
+import io.reactivex.android.schedulers.AndroidSchedulers
+import io.reactivex.disposables.Disposable
+import io.reactivex.schedulers.Schedulers
+
+class GuestAccessHelper(
+    controller: ConversationInfoController,
+    private val binding: ControllerConversationInfoBinding,
+    private val conversation: Conversation,
+    private val conversationUser: User
+) {
+
+    private val activity = controller.activity!!
+    private val conversationsRepository = controller.conversationsRepository
+    private val viewThemeUtils = controller.viewThemeUtils
+    private val context = controller.context
+
+    fun setupGuestAccess() {
+
+        val guestAccessAllowSwitch = (
+            binding.guestAccessView.guestAccessAllowSwitch.findViewById<View>(R.id.mp_checkable)
+                as SwitchCompat
+            )
+        val guestAccessPasswordSwitch = (
+            binding.guestAccessView.guestAccessPasswordSwitch.findViewById<View>(R.id.mp_checkable)
+                as SwitchCompat
+            )
+
+        if (conversation.canModerate(conversationUser)) {
+            binding.guestAccessView.guestAccessSettings.visibility = View.VISIBLE
+        } else {
+            return
+        }
+
+        if (conversation.type == Conversation.ConversationType.ROOM_PUBLIC_CALL) {
+            guestAccessAllowSwitch.isChecked = true
+            showAllOptions()
+            if (conversation.hasPassword) {
+                guestAccessPasswordSwitch.isChecked = true
+            }
+        }
+
+        binding.guestAccessView.guestAccessAllowSwitch.setOnClickListener {
+            conversationsRepository.allowGuests(
+                conversation.token!!,
+                !guestAccessAllowSwitch.isChecked
+            ).subscribeOn(Schedulers.io())
+                .observeOn(AndroidSchedulers.mainThread()).subscribe(AllowGuestsResultObserver())
+        }
+
+        binding.guestAccessView.guestAccessPasswordSwitch.setOnClickListener {
+
+            if (guestAccessPasswordSwitch.isChecked) {
+                conversationsRepository.password("", conversation.token!!).subscribeOn(Schedulers.io())
+                    .observeOn(AndroidSchedulers.mainThread()).subscribe(PasswordResultObserver(false))
+            } else {
+                showPasswordDialog(guestAccessPasswordSwitch)
+            }
+        }
+
+        binding.guestAccessView.guestAccessCopyUrl.setOnClickListener {
+            shareUrl()
+        }
+
+        binding.guestAccessView.guestAccessResendInvitations.setOnClickListener {
+            conversationsRepository.resendInvitations(conversation.token!!).subscribeOn(Schedulers.io())
+                .observeOn(AndroidSchedulers.mainThread()).subscribe(ResendInvitationsObserver())
+        }
+    }
+
+    @SuppressLint("InflateParams")
+    private fun showPasswordDialog(guestAccessPasswordSwitch: SwitchCompat) {
+        val builder = MaterialAlertDialogBuilder(activity)
+        builder.apply {
+            val dialogPassword = DialogPasswordBinding.inflate(LayoutInflater.from(context))
+            viewThemeUtils.colorEditText(dialogPassword.password)
+            setView(dialogPassword.root)
+            setTitle(R.string.nc_guest_access_password_dialog_title)
+            setPositiveButton(R.string.nc_ok) { _, _ ->
+                val password = dialogPassword.password.text.toString()
+                conversationsRepository.password(password, conversation.token!!)
+                    .subscribeOn(Schedulers.io())
+                    .observeOn(AndroidSchedulers.mainThread())
+                    .subscribe(PasswordResultObserver(true))
+            }
+            setNegativeButton(R.string.nc_cancel) { _, _ ->
+                guestAccessPasswordSwitch.isChecked = false
+            }
+        }
+        createDialog(builder)
+    }
+
+    private fun createDialog(builder: MaterialAlertDialogBuilder) {
+        builder.create()
+        viewThemeUtils.colorMaterialAlertDialogBackground(binding.conversationInfoName.context, builder)
+        val dialog = builder.show()
+        viewThemeUtils.colorTextButtons(
+            dialog.getButton(AlertDialog.BUTTON_POSITIVE),
+            dialog.getButton(AlertDialog.BUTTON_NEGATIVE)
+        )
+    }
+
+    private fun shareUrl() {
+        val sendIntent: Intent = Intent().apply {
+            action = Intent.ACTION_SEND
+            type = Mimetype.TEXT_PLAIN
+            putExtra(
+                Intent.EXTRA_SUBJECT,
+                String.format(
+                    activity.resources.getString(R.string.nc_share_subject),
+                    activity.resources.getString(R.string.nc_app_product_name)
+                )
+            )
+
+            putExtra(
+                Intent.EXTRA_TEXT,
+                ShareUtils.getStringForIntent(activity, conversationUser, conversation)
+            )
+        }
+
+        val shareIntent = Intent.createChooser(sendIntent, null)
+        activity.startActivity(shareIntent)
+    }
+
+    inner class ResendInvitationsObserver : Observer<ConversationsRepository.ResendInvitationsResult> {
+
+        private lateinit var resendInvitationsResult: ConversationsRepository.ResendInvitationsResult
+
+        override fun onSubscribe(d: Disposable) = Unit
+
+        override fun onNext(t: ConversationsRepository.ResendInvitationsResult) {
+            resendInvitationsResult = t
+        }
+
+        override fun onError(e: Throwable) {
+            val message = context.getString(R.string.nc_guest_access_resend_invitations_failed)
+            Toast.makeText(context, message, Toast.LENGTH_SHORT).show()
+            Log.e(TAG, message, e)
+        }
+
+        override fun onComplete() {
+            if (resendInvitationsResult.successful) {
+                Toast.makeText(context, R.string.nc_guest_access_resend_invitations_successful, Toast.LENGTH_SHORT)
+                    .show()
+            }
+        }
+    }
+
+    inner class AllowGuestsResultObserver : Observer<ConversationsRepository.AllowGuestsResult> {
+
+        private lateinit var allowGuestsResult: ConversationsRepository.AllowGuestsResult
+
+        override fun onNext(t: ConversationsRepository.AllowGuestsResult) {
+            allowGuestsResult = t
+        }
+
+        override fun onError(e: Throwable) {
+            val message = context.getString(R.string.nc_guest_access_allow_failed)
+            Toast.makeText(context, message, Toast.LENGTH_LONG).show()
+            Log.e(TAG, message, e)
+        }
+
+        override fun onComplete() {
+            (
+                binding.guestAccessView.guestAccessAllowSwitch.findViewById<View>(R.id.mp_checkable)
+                    as SwitchCompat
+                ).isChecked = allowGuestsResult.allow
+            if (allowGuestsResult.allow) {
+                showAllOptions()
+            } else {
+                hideAllOptions()
+            }
+        }
+
+        override fun onSubscribe(d: Disposable) = Unit
+    }
+
+    private fun showAllOptions() {
+        binding.guestAccessView.guestAccessPasswordSwitch.visibility = View.VISIBLE
+        binding.guestAccessView.guestAccessCopyUrl.visibility = View.VISIBLE
+        if (conversationUser.capabilities?.spreedCapability?.features?.contains("sip-support") == true) {
+            binding.guestAccessView.guestAccessResendInvitations.visibility = View.VISIBLE
+        }
+    }
+
+    private fun hideAllOptions() {
+        binding.guestAccessView.guestAccessPasswordSwitch.visibility = View.GONE
+        binding.guestAccessView.guestAccessCopyUrl.visibility = View.GONE
+        binding.guestAccessView.guestAccessResendInvitations.visibility = View.GONE
+    }
+
+    inner class PasswordResultObserver(private val setPassword: Boolean) :
+        Observer<ConversationsRepository.PasswordResult> {
+
+        private lateinit var passwordResult: ConversationsRepository.PasswordResult
+
+        override fun onSubscribe(d: Disposable) = Unit
+
+        override fun onNext(t: ConversationsRepository.PasswordResult) {
+            passwordResult = t
+        }
+
+        override fun onError(e: Throwable) {
+            val message = context.getString(R.string.nc_guest_access_password_failed)
+            Toast.makeText(context, message, Toast.LENGTH_LONG).show()
+            Log.e(TAG, message, e)
+        }
+
+        override fun onComplete() {
+            val guestAccessPasswordSwitch = (
+                binding.guestAccessView.guestAccessPasswordSwitch.findViewById<View>(R.id.mp_checkable)
+                    as SwitchCompat
+                )
+            guestAccessPasswordSwitch.isChecked = passwordResult.passwordSet && setPassword
+
+            if (passwordResult.passwordIsWeak) {
+                val builder = MaterialAlertDialogBuilder(activity)
+                builder.apply {
+                    setTitle(R.string.nc_guest_access_password_weak_alert_title)
+                    setMessage(passwordResult.message)
+                    setPositiveButton("OK") { _, _ -> }
+                }
+                createDialog(builder)
+            }
+        }
+    }
+
+    companion object {
+        private val TAG = GuestAccessHelper::class.simpleName
+    }
+}

+ 8 - 0
app/src/main/java/com/nextcloud/talk/dagger/modules/RepositoryModule.kt

@@ -33,6 +33,8 @@ import com.nextcloud.talk.polls.repositories.PollRepository
 import com.nextcloud.talk.polls.repositories.PollRepositoryImpl
 import com.nextcloud.talk.remotefilebrowser.repositories.RemoteFileBrowserItemsRepository
 import com.nextcloud.talk.remotefilebrowser.repositories.RemoteFileBrowserItemsRepositoryImpl
+import com.nextcloud.talk.repositories.conversations.ConversationsRepository
+import com.nextcloud.talk.repositories.conversations.ConversationsRepositoryImpl
 import com.nextcloud.talk.repositories.unifiedsearch.UnifiedSearchRepository
 import com.nextcloud.talk.repositories.unifiedsearch.UnifiedSearchRepositoryImpl
 import com.nextcloud.talk.shareditems.repositories.SharedItemsRepository
@@ -44,6 +46,12 @@ import okhttp3.OkHttpClient
 
 @Module
 class RepositoryModule {
+
+    @Provides
+    fun provideConversationsRepository(ncApi: NcApi, userProvider: CurrentUserProviderNew): ConversationsRepository {
+        return ConversationsRepositoryImpl(ncApi, userProvider)
+    }
+
     @Provides
     fun provideSharedItemsRepository(ncApi: NcApi): SharedItemsRepository {
         return SharedItemsRepositoryImpl(ncApi)

+ 36 - 0
app/src/main/java/com/nextcloud/talk/models/json/conversations/password/PasswordData.kt

@@ -0,0 +1,36 @@
+/*
+ * Nextcloud Talk application
+ *
+ * @author Tim Krüger
+ * Copyright (C) 2022 Tim Krüger
+ * Copyright (C) 2022 Nextcloud GmbH
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+package com.nextcloud.talk.models.json.conversations.password
+
+import android.os.Parcelable
+import com.bluelinelabs.logansquare.annotation.JsonField
+import com.bluelinelabs.logansquare.annotation.JsonObject
+import kotlinx.android.parcel.Parcelize
+
+@JsonObject
+@Parcelize
+data class PasswordData(
+    @JsonField(name = ["message"])
+    var message: String? = null
+) : Parcelable {
+    // This constructor is added to work with the 'com.bluelinelabs.logansquare.annotation.JsonObject'
+    constructor() : this(null)
+}

+ 40 - 0
app/src/main/java/com/nextcloud/talk/models/json/conversations/password/PasswordOCS.kt

@@ -0,0 +1,40 @@
+/*
+ * Nextcloud Talk application
+ *
+ * @author Tim Krüger
+ * Copyright (C) 2022 Tim Krüger
+ * Copyright (C) 2022 Nextcloud GmbH
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+package com.nextcloud.talk.models.json.conversations.password
+
+import android.os.Parcelable
+import com.bluelinelabs.logansquare.annotation.JsonField
+import com.bluelinelabs.logansquare.annotation.JsonObject
+import com.nextcloud.talk.models.json.generic.GenericMeta
+import kotlinx.android.parcel.Parcelize
+
+@Parcelize
+@JsonObject
+data class PasswordOCS(
+    @JsonField(name = ["meta"])
+    var meta: GenericMeta? = null,
+
+    @JsonField(name = ["data"])
+    var data: PasswordData? = null
+) : Parcelable {
+    // This constructor is added to work with the 'com.bluelinelabs.logansquare.annotation.JsonObject'
+    constructor() : this(null, null)
+}

+ 36 - 0
app/src/main/java/com/nextcloud/talk/models/json/conversations/password/PasswordOverall.kt

@@ -0,0 +1,36 @@
+/*
+ * Nextcloud Talk application
+ *
+ * @author Tim Krüger
+ * Copyright (C) 2022 Tim Krüger
+ * Copyright (C) 2022 Nextcloud GmbH
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+package com.nextcloud.talk.models.json.conversations.password
+
+import android.os.Parcelable
+import com.bluelinelabs.logansquare.annotation.JsonField
+import com.bluelinelabs.logansquare.annotation.JsonObject
+import kotlinx.android.parcel.Parcelize
+
+@Parcelize
+@JsonObject
+data class PasswordOverall(
+    @JsonField(name = ["ocs"])
+    var ocs: PasswordOCS? = null
+) : Parcelable {
+    // This constructor is added to work with the 'com.bluelinelabs.logansquare.annotation.JsonObject'
+    constructor() : this(null)
+}

+ 46 - 0
app/src/main/java/com/nextcloud/talk/repositories/conversations/ConversationsRepository.kt

@@ -0,0 +1,46 @@
+/*
+ * Nextcloud Talk application
+ *
+ * @author Tim Krüger
+ * Copyright (C) 2022 Tim Krüger
+ * Copyright (C) 2022 Nextcloud GmbH
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+package com.nextcloud.talk.repositories.conversations
+
+import io.reactivex.Observable
+
+interface ConversationsRepository {
+
+    data class AllowGuestsResult(
+        val allow: Boolean
+    )
+
+    fun allowGuests(token: String, allow: Boolean): Observable<AllowGuestsResult>
+
+    data class PasswordResult(
+        val passwordSet: Boolean,
+        val passwordIsWeak: Boolean,
+        val message: String
+    )
+
+    fun password(password: String, token: String): Observable<PasswordResult>
+
+    data class ResendInvitationsResult(
+        val successful: Boolean
+    )
+    fun resendInvitations(token: String): Observable<ResendInvitationsResult>
+}

+ 113 - 0
app/src/main/java/com/nextcloud/talk/repositories/conversations/ConversationsRepositoryImpl.kt

@@ -0,0 +1,113 @@
+/*
+ * Nextcloud Talk application
+ *
+ * @author Tim Krüger
+ * Copyright (C) 2022 Tim Krüger
+ * Copyright (C) 2022 Nextcloud GmbH
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+package com.nextcloud.talk.repositories.conversations
+
+import com.bluelinelabs.logansquare.LoganSquare
+import com.nextcloud.talk.api.NcApi
+import com.nextcloud.talk.data.user.model.User
+import com.nextcloud.talk.models.json.conversations.password.PasswordOverall
+import com.nextcloud.talk.repositories.conversations.ConversationsRepository.AllowGuestsResult
+import com.nextcloud.talk.repositories.conversations.ConversationsRepository.PasswordResult
+import com.nextcloud.talk.repositories.conversations.ConversationsRepository.ResendInvitationsResult
+import com.nextcloud.talk.utils.ApiUtils
+import com.nextcloud.talk.utils.database.user.CurrentUserProviderNew
+import io.reactivex.Observable
+
+class ConversationsRepositoryImpl(private val api: NcApi, private val userProvider: CurrentUserProviderNew) :
+    ConversationsRepository {
+
+    private val user: User
+        get() = userProvider.currentUser.blockingGet()
+
+    private val credentials: String
+        get() = ApiUtils.getCredentials(user.username, user.token)
+
+    override fun allowGuests(token: String, allow: Boolean): Observable<AllowGuestsResult> {
+
+        val url = ApiUtils.getUrlForRoomPublic(
+            apiVersion(),
+            user.baseUrl,
+            token
+        )
+
+        val apiObservable = if (allow) {
+            api.makeRoomPublic(
+                credentials,
+                url
+            )
+        } else {
+            api.makeRoomPrivate(
+                credentials,
+                url
+            )
+        }
+
+        return apiObservable.map { AllowGuestsResult(it.ocs!!.meta!!.statusCode == STATUS_CODE_OK && allow) }
+    }
+
+    override fun password(password: String, token: String): Observable<PasswordResult> {
+        val apiObservable = api.setPassword2(
+            credentials,
+            ApiUtils.getUrlForRoomPassword(
+                apiVersion(),
+                user.baseUrl!!,
+                token
+            ),
+            password
+        )
+        return apiObservable.map {
+
+            val passwordPolicyMessage = if (it.code() == STATUS_CODE_BAD_REQUEST) {
+                LoganSquare.parse(it.errorBody()!!.string(), PasswordOverall::class.java).ocs!!.data!!
+                    .message!!
+            } else {
+                ""
+            }
+
+            PasswordResult(it.isSuccessful, passwordPolicyMessage.isNotEmpty(), passwordPolicyMessage)
+        }
+    }
+
+    override fun resendInvitations(token: String): Observable<ResendInvitationsResult> {
+
+        val apiObservable = api.resendParticipantInvitations(
+            credentials,
+            ApiUtils.getUrlForParticipantsResendInvitations(
+                apiVersion(),
+                user.baseUrl!!,
+                token
+            )
+        )
+
+        return apiObservable.map {
+            ResendInvitationsResult(true)
+        }
+    }
+
+    private fun apiVersion(): Int {
+        return ApiUtils.getConversationApiVersion(user, intArrayOf(ApiUtils.APIv4))
+    }
+
+    companion object {
+        const val STATUS_CODE_OK = 200
+        const val STATUS_CODE_BAD_REQUEST = 400
+    }
+}

+ 0 - 76
app/src/main/java/com/nextcloud/talk/ui/dialog/ConversationsListBottomDialog.kt

@@ -21,7 +21,6 @@
 package com.nextcloud.talk.ui.dialog
 
 import android.app.Activity
-import android.content.Intent
 import android.os.Bundle
 import android.text.TextUtils
 import android.view.View
@@ -42,14 +41,9 @@ import com.nextcloud.talk.application.NextcloudTalkApplication
 import com.nextcloud.talk.controllers.ConversationsListController
 import com.nextcloud.talk.controllers.bottomsheet.ConversationOperationEnum
 import com.nextcloud.talk.controllers.bottomsheet.ConversationOperationEnum.OPS_CODE_ADD_FAVORITE
-import com.nextcloud.talk.controllers.bottomsheet.ConversationOperationEnum.OPS_CODE_CHANGE_PASSWORD
-import com.nextcloud.talk.controllers.bottomsheet.ConversationOperationEnum.OPS_CODE_CLEAR_PASSWORD
-import com.nextcloud.talk.controllers.bottomsheet.ConversationOperationEnum.OPS_CODE_MAKE_PRIVATE
-import com.nextcloud.talk.controllers.bottomsheet.ConversationOperationEnum.OPS_CODE_MAKE_PUBLIC
 import com.nextcloud.talk.controllers.bottomsheet.ConversationOperationEnum.OPS_CODE_MARK_AS_READ
 import com.nextcloud.talk.controllers.bottomsheet.ConversationOperationEnum.OPS_CODE_REMOVE_FAVORITE
 import com.nextcloud.talk.controllers.bottomsheet.ConversationOperationEnum.OPS_CODE_RENAME_ROOM
-import com.nextcloud.talk.controllers.bottomsheet.ConversationOperationEnum.OPS_CODE_SET_PASSWORD
 import com.nextcloud.talk.controllers.bottomsheet.EntryMenuController
 import com.nextcloud.talk.controllers.bottomsheet.OperationsMenuController
 import com.nextcloud.talk.data.user.model.User
@@ -58,8 +52,6 @@ import com.nextcloud.talk.jobs.LeaveConversationWorker
 import com.nextcloud.talk.models.json.conversations.Conversation
 import com.nextcloud.talk.ui.theme.ViewThemeUtils
 import com.nextcloud.talk.users.UserManager
-import com.nextcloud.talk.utils.Mimetype.TEXT_PLAIN
-import com.nextcloud.talk.utils.ShareUtils
 import com.nextcloud.talk.utils.bundle.BundleKeys.KEY_INTERNAL_USER_ID
 import com.nextcloud.talk.utils.bundle.BundleKeys.KEY_OPERATION_CODE
 import com.nextcloud.talk.utils.bundle.BundleKeys.KEY_ROOM
@@ -130,34 +122,10 @@ class ConversationsListBottomDialog(
             conversation.isNameEditable(currentUser)
         )
 
-        binding.conversationOperationMakePublic.visibility = setVisibleIf(
-            canModerate && !conversation.isPublic
-        )
-
-        binding.conversationOperationChangePassword.visibility = setVisibleIf(
-            canModerate && conversation.hasPassword && conversation.isPublic
-        )
-
-        binding.conversationOperationClearPassword.visibility = setVisibleIf(
-            canModerate && conversation.hasPassword && conversation.isPublic
-        )
-
-        binding.conversationOperationSetPassword.visibility = setVisibleIf(
-            canModerate && !conversation.hasPassword && conversation.isPublic
-        )
-
         binding.conversationOperationDelete.visibility = setVisibleIf(
             canModerate
         )
 
-        binding.conversationOperationShareLink.visibility = setVisibleIf(
-            conversation.isPublic
-        )
-
-        binding.conversationOperationMakePrivate.visibility = setVisibleIf(
-            conversation.isPublic && canModerate
-        )
-
         binding.conversationOperationLeave.visibility = setVisibleIf(
             conversation.canLeave() &&
                 // leaving is by api not possible for the last user with moderator permissions.
@@ -210,26 +178,6 @@ class ConversationsListBottomDialog(
             dismiss()
         }
 
-        binding.conversationOperationMakePublic.setOnClickListener {
-            executeOperationsMenuController(OPS_CODE_MAKE_PUBLIC)
-        }
-
-        binding.conversationOperationMakePrivate.setOnClickListener {
-            executeOperationsMenuController(OPS_CODE_MAKE_PRIVATE)
-        }
-
-        binding.conversationOperationChangePassword.setOnClickListener {
-            executeEntryMenuController(OPS_CODE_CHANGE_PASSWORD)
-        }
-
-        binding.conversationOperationClearPassword.setOnClickListener {
-            executeOperationsMenuController(OPS_CODE_CLEAR_PASSWORD)
-        }
-
-        binding.conversationOperationSetPassword.setOnClickListener {
-            executeEntryMenuController(OPS_CODE_SET_PASSWORD)
-        }
-
         binding.conversationOperationRename.setOnClickListener {
             executeEntryMenuController(OPS_CODE_RENAME_ROOM)
         }
@@ -237,30 +185,6 @@ class ConversationsListBottomDialog(
         binding.conversationOperationMarkAsRead.setOnClickListener {
             executeOperationsMenuController(OPS_CODE_MARK_AS_READ)
         }
-
-        binding.conversationOperationShareLink.setOnClickListener {
-            val sendIntent: Intent = Intent().apply {
-                action = Intent.ACTION_SEND
-                type = TEXT_PLAIN
-                putExtra(
-                    Intent.EXTRA_SUBJECT,
-                    String.format(
-                        activity.resources.getString(R.string.nc_share_subject),
-                        activity.resources.getString(R.string.nc_app_product_name)
-                    )
-                )
-                // password should not be shared!!
-                putExtra(
-                    Intent.EXTRA_TEXT,
-                    ShareUtils.getStringForIntent(activity, null, userManager, conversation)
-                )
-            }
-
-            val shareIntent = Intent.createChooser(sendIntent, null)
-            activity.startActivity(shareIntent)
-
-            dismiss()
-        }
     }
 
     private fun executeOperationsMenuController(operation: ConversationOperationEnum) {

+ 4 - 0
app/src/main/java/com/nextcloud/talk/utils/ApiUtils.java

@@ -218,6 +218,10 @@ public class ApiUtils {
         return getUrlForParticipants(version, baseUrl, token) + "/self";
     }
 
+    public static String getUrlForParticipantsResendInvitations(int version, String baseUrl, String token) {
+        return getUrlForParticipants(version, baseUrl, token) + "/resend-invitations";
+    }
+
     public static String getUrlForRoomFavorite(int version, String baseUrl, String token) {
         return getUrlForRoom(version, baseUrl, token) + "/favorite";
     }

+ 9 - 17
app/src/main/java/com/nextcloud/talk/utils/ShareUtils.kt

@@ -21,28 +21,20 @@ package com.nextcloud.talk.utils
 
 import android.content.Context
 import com.nextcloud.talk.R
+import com.nextcloud.talk.data.user.model.User
 import com.nextcloud.talk.models.json.conversations.Conversation
-import com.nextcloud.talk.users.UserManager
 
 object ShareUtils {
     fun getStringForIntent(
-        context: Context?,
-        password: String?,
-        userManager: UserManager,
+        context: Context,
+        user: User,
         conversation: Conversation?
     ): String {
-        val userEntity = userManager.currentUser.blockingGet()
-        var shareString = ""
-        if (userEntity != null && context != null) {
-            shareString = String.format(
-                context.resources.getString(R.string.nc_share_text),
-                userEntity.baseUrl,
-                conversation?.token
-            )
-            if (!password.isNullOrEmpty()) {
-                shareString += String.format(context.resources.getString(R.string.nc_share_text_pass), password)
-            }
-        }
-        return shareString
+
+        return String.format(
+            context.resources.getString(R.string.nc_share_text),
+            user.baseUrl,
+            conversation?.token
+        )
     }
 }

+ 14 - 4
app/src/main/res/layout/controller_conversation_info.xml

@@ -4,6 +4,8 @@
   ~ @author Mario Danic
   ~ @author Andy Scherzinger
   ~ @author Marcel Hibbe
+  ~ @author Tim Krüger
+  ~ Copyright (C) 2022 Tim Krüger <t@timkrueger.me>
   ~ Copyright (C) 2022 Marcel Hibbe <dev@mhibbe.de>
   ~ Copyright (C) 2021 Andy Scherzinger <info@andy-scherzinger.de>
   ~ Copyright (C) 2017-2018 Mario Danic <mario@lovelyhq.com>
@@ -25,10 +27,10 @@
 <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:apc="http://schemas.android.com/apk/res-auto"
     xmlns:tools="http://schemas.android.com/tools"
-    tools:background="@color/white"
     android:layout_width="match_parent"
     android:layout_height="match_parent"
-    android:orientation="vertical">
+    android:orientation="vertical"
+    tools:background="@color/white">
 
     <ProgressBar
         android:id="@+id/progressBar"
@@ -80,8 +82,8 @@
                         android:layout_width="@dimen/avatar_size_big"
                         android:layout_height="@dimen/avatar_size_big"
                         android:layout_centerHorizontal="true"
-                        tools:background="@color/hwSecurityRed"
-                        apc:roundAsCircle="true" />
+                        apc:roundAsCircle="true"
+                        tools:background="@color/hwSecurityRed" />
 
                 </RelativeLayout>
             </com.yarolegovich.mp.MaterialPreferenceCategory>
@@ -150,6 +152,14 @@
                     android:visibility="gone"
                     tools:visibility="visible" />
 
+                <include
+                    android:id="@+id/guest_access_view"
+                    layout="@layout/guest_access_settings_item"
+                    android:layout_width="match_parent"
+                    android:layout_height="wrap_content"
+                    android:visibility="gone"
+                    tools:visibility="visible" />
+
             </LinearLayout>
 
             <com.yarolegovich.mp.MaterialPreferenceCategory

+ 0 - 180
app/src/main/res/layout/dialog_conversation_operations.xml

@@ -166,126 +166,6 @@
                 android:textSize="@dimen/bottom_sheet_text_size" />
         </LinearLayout>
 
-        <LinearLayout
-            android:id="@+id/conversation_operation_make_public"
-            android:layout_width="match_parent"
-            android:layout_height="@dimen/bottom_sheet_item_height"
-            android:background="?android:attr/selectableItemBackground"
-            android:gravity="center_vertical"
-            android:orientation="horizontal"
-            android:paddingStart="@dimen/standard_padding"
-            android:paddingEnd="@dimen/standard_padding"
-            tools:ignore="UseCompoundDrawables">
-
-            <ImageView
-                android:layout_width="wrap_content"
-                android:layout_height="wrap_content"
-                android:contentDescription="@null"
-                android:src="@drawable/ic_link_grey600_24px"
-                app:tint="@color/high_emphasis_menu_icon" />
-
-            <androidx.appcompat.widget.AppCompatTextView
-                android:layout_width="match_parent"
-                android:layout_height="wrap_content"
-                android:layout_gravity="start|center_vertical"
-                android:paddingStart="40dp"
-                android:paddingEnd="@dimen/zero"
-                android:text="@string/nc_make_call_public"
-                android:textAlignment="viewStart"
-                android:textColor="@color/high_emphasis_text"
-                android:textSize="@dimen/bottom_sheet_text_size" />
-        </LinearLayout>
-
-        <LinearLayout
-            android:id="@+id/conversation_operation_change_password"
-            android:layout_width="match_parent"
-            android:layout_height="@dimen/bottom_sheet_item_height"
-            android:background="?android:attr/selectableItemBackground"
-            android:gravity="center_vertical"
-            android:orientation="horizontal"
-            android:paddingStart="@dimen/standard_padding"
-            android:paddingEnd="@dimen/standard_padding"
-            tools:ignore="UseCompoundDrawables">
-
-            <ImageView
-                android:layout_width="wrap_content"
-                android:layout_height="wrap_content"
-                android:contentDescription="@null"
-                android:src="@drawable/ic_lock_grey600_24px"
-                app:tint="@color/high_emphasis_menu_icon" />
-
-            <androidx.appcompat.widget.AppCompatTextView
-                android:layout_width="match_parent"
-                android:layout_height="wrap_content"
-                android:layout_gravity="start|center_vertical"
-                android:paddingStart="40dp"
-                android:paddingEnd="@dimen/zero"
-                android:text="@string/nc_change_password"
-                android:textAlignment="viewStart"
-                android:textColor="@color/high_emphasis_text"
-                android:textSize="@dimen/bottom_sheet_text_size" />
-        </LinearLayout>
-
-        <LinearLayout
-            android:id="@+id/conversation_operation_clear_password"
-            android:layout_width="match_parent"
-            android:layout_height="@dimen/bottom_sheet_item_height"
-            android:background="?android:attr/selectableItemBackground"
-            android:gravity="center_vertical"
-            android:orientation="horizontal"
-            android:paddingStart="@dimen/standard_padding"
-            android:paddingEnd="@dimen/standard_padding"
-            tools:ignore="UseCompoundDrawables">
-
-            <ImageView
-                android:layout_width="wrap_content"
-                android:layout_height="wrap_content"
-                android:contentDescription="@null"
-                android:src="@drawable/ic_lock_open_grey600_24dp"
-                app:tint="@color/high_emphasis_menu_icon" />
-
-            <androidx.appcompat.widget.AppCompatTextView
-                android:layout_width="match_parent"
-                android:layout_height="wrap_content"
-                android:layout_gravity="start|center_vertical"
-                android:paddingStart="40dp"
-                android:paddingEnd="@dimen/zero"
-                android:text="@string/nc_clear_password"
-                android:textAlignment="viewStart"
-                android:textColor="@color/high_emphasis_text"
-                android:textSize="@dimen/bottom_sheet_text_size" />
-        </LinearLayout>
-
-        <LinearLayout
-            android:id="@+id/conversation_operation_set_password"
-            android:layout_width="match_parent"
-            android:layout_height="@dimen/bottom_sheet_item_height"
-            android:background="?android:attr/selectableItemBackground"
-            android:gravity="center_vertical"
-            android:orientation="horizontal"
-            android:paddingStart="@dimen/standard_padding"
-            android:paddingEnd="@dimen/standard_padding"
-            tools:ignore="UseCompoundDrawables">
-
-            <ImageView
-                android:layout_width="wrap_content"
-                android:layout_height="wrap_content"
-                android:contentDescription="@null"
-                android:src="@drawable/ic_lock_plus_grey600_24dp"
-                app:tint="@color/high_emphasis_menu_icon" />
-
-            <androidx.appcompat.widget.AppCompatTextView
-                android:layout_width="match_parent"
-                android:layout_height="wrap_content"
-                android:layout_gravity="start|center_vertical"
-                android:paddingStart="40dp"
-                android:paddingEnd="@dimen/zero"
-                android:text="@string/nc_set_password"
-                android:textAlignment="viewStart"
-                android:textColor="@color/high_emphasis_text"
-                android:textSize="@dimen/bottom_sheet_text_size" />
-        </LinearLayout>
-
         <LinearLayout
             android:id="@+id/conversation_operation_delete"
             android:layout_width="match_parent"
@@ -316,66 +196,6 @@
                 android:textSize="@dimen/bottom_sheet_text_size" />
         </LinearLayout>
 
-        <LinearLayout
-            android:id="@+id/conversation_operation_share_link"
-            android:layout_width="match_parent"
-            android:layout_height="@dimen/bottom_sheet_item_height"
-            android:background="?android:attr/selectableItemBackground"
-            android:gravity="center_vertical"
-            android:orientation="horizontal"
-            android:paddingStart="@dimen/standard_padding"
-            android:paddingEnd="@dimen/standard_padding"
-            tools:ignore="UseCompoundDrawables">
-
-            <ImageView
-                android:layout_width="wrap_content"
-                android:layout_height="wrap_content"
-                android:contentDescription="@null"
-                android:src="@drawable/ic_link_grey600_24px"
-                app:tint="@color/high_emphasis_menu_icon" />
-
-            <androidx.appcompat.widget.AppCompatTextView
-                android:layout_width="match_parent"
-                android:layout_height="wrap_content"
-                android:layout_gravity="start|center_vertical"
-                android:paddingStart="40dp"
-                android:paddingEnd="@dimen/zero"
-                android:text="@string/nc_share_link"
-                android:textAlignment="viewStart"
-                android:textColor="@color/high_emphasis_text"
-                android:textSize="@dimen/bottom_sheet_text_size" />
-        </LinearLayout>
-
-        <LinearLayout
-            android:id="@+id/conversation_operation_make_private"
-            android:layout_width="match_parent"
-            android:layout_height="@dimen/bottom_sheet_item_height"
-            android:background="?android:attr/selectableItemBackground"
-            android:gravity="center_vertical"
-            android:orientation="horizontal"
-            android:paddingStart="@dimen/standard_padding"
-            android:paddingEnd="@dimen/standard_padding"
-            tools:ignore="UseCompoundDrawables">
-
-            <ImageView
-                android:layout_width="wrap_content"
-                android:layout_height="wrap_content"
-                android:contentDescription="@null"
-                android:src="@drawable/ic_group_grey600_24px"
-                app:tint="@color/high_emphasis_menu_icon" />
-
-            <androidx.appcompat.widget.AppCompatTextView
-                android:layout_width="match_parent"
-                android:layout_height="wrap_content"
-                android:layout_gravity="start|center_vertical"
-                android:paddingStart="40dp"
-                android:paddingEnd="@dimen/zero"
-                android:text="@string/nc_make_call_private"
-                android:textAlignment="viewStart"
-                android:textColor="@color/high_emphasis_text"
-                android:textSize="@dimen/bottom_sheet_text_size" />
-        </LinearLayout>
-
         <LinearLayout
             android:id="@+id/conversation_operation_leave"
             android:layout_width="match_parent"

+ 42 - 0
app/src/main/res/layout/dialog_password.xml

@@ -0,0 +1,42 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Nextcloud Talk application
+
+ @author Andy Scherzinger
+ @author Tim Krüger
+ Copyright (C) 2022 Andy Scherzinger <info@andy-scherzinger.de>
+ Copyright (C) 2022 Tim Krüger
+ Copyright (C) 2022 Nextcloud GmbH
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program.  If not, see <http://www.gnu.org/licenses/>.
+-->
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:tools="http://schemas.android.com/tools"
+    android:layout_width="match_parent"
+    android:layout_height="wrap_content"
+    android:orientation="vertical"
+    tools:background="@color/white">
+
+    <EditText
+        android:id="@+id/password"
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content"
+        android:layout_marginStart="@dimen/dialog_padding"
+        android:layout_marginTop="@dimen/standard_margin"
+        android:layout_marginEnd="@dimen/dialog_padding"
+        android:layout_marginBottom="@dimen/standard_margin"
+        android:hint="@string/nc_guest_access_password_dialog_hint"
+        android:inputType="textPassword"
+        android:importantForAutofill="no" />
+</LinearLayout>

+ 81 - 0
app/src/main/res/layout/guest_access_settings_item.xml

@@ -0,0 +1,81 @@
+<?xml version="1.0" encoding="utf-8"?><!--
+ Nextcloud Talk application
+
+ @author Tim Krüger
+ Copyright (C) 2022 Tim Krüger
+ Copyright (C) 2022 Nextcloud GmbH
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program.  If not, see <http://www.gnu.org/licenses/>.
+-->
+<com.yarolegovich.mp.MaterialPreferenceScreen xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:apc="http://schemas.android.com/apk/res-auto"
+    xmlns:tools="http://schemas.android.com/tools"
+    android:id="@+id/guest_access_settings"
+    android:layout_width="match_parent"
+    android:layout_height="wrap_content">
+
+    <com.yarolegovich.mp.MaterialPreferenceCategory
+        android:id="@+id/guest_access_category"
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content"
+        android:animateLayoutChanges="true"
+        apc:cardBackgroundColor="@color/bg_default"
+        apc:cardElevation="0dp"
+        apc:mpc_title="@string/nc_guest_access">
+
+        <com.yarolegovich.mp.MaterialSwitchPreference
+            android:id="@+id/guest_access_allow_switch"
+            android:layout_width="match_parent"
+            android:layout_height="wrap_content"
+            apc:mp_default_value="false"
+            apc:mp_key="guest_access_allowed"
+            apc:mp_summary="@string/nc_guest_access_allow_summary"
+            apc:mp_title="@string/nc_guest_access_allow_title" />
+
+        <com.yarolegovich.mp.MaterialSwitchPreference
+            android:id="@+id/guest_access_password_switch"
+            android:layout_width="match_parent"
+            android:layout_height="wrap_content"
+            android:visibility="gone"
+            apc:mp_default_value="false"
+            apc:mp_key="guest_access_password"
+            apc:mp_summary="@string/nc_guest_access_password_summary"
+            apc:mp_title="@string/nc_guest_access_password_title"
+            tools:visibility="visible" />
+
+        <com.yarolegovich.mp.MaterialStandardPreference
+            android:id="@+id/guest_access_copy_url"
+            android:layout_width="match_parent"
+            android:layout_height="wrap_content"
+            android:visibility="gone"
+            apc:mp_icon="@drawable/ic_share_variant"
+            apc:mp_icon_tint="@color/grey_600"
+            apc:mp_title="@string/nc_guest_access_share_link"
+            tools:visibility="visible" >
+
+        </com.yarolegovich.mp.MaterialStandardPreference>
+
+        <com.yarolegovich.mp.MaterialStandardPreference
+            android:id="@+id/guest_access_resend_invitations"
+            android:layout_width="match_parent"
+            android:layout_height="match_parent"
+            android:visibility="gone"
+            apc:mp_icon="@drawable/ic_email"
+            apc:mp_icon_tint="@color/grey_600"
+            apc:mp_title="@string/nc_guest_access_resend_invitations"
+            tools:visibility="visible" />
+
+    </com.yarolegovich.mp.MaterialPreferenceCategory>
+
+</com.yarolegovich.mp.MaterialPreferenceScreen>

+ 16 - 6
app/src/main/res/values/strings.xml

@@ -168,12 +168,6 @@
     <string name="nc_clear_history_warning">Do you really want to delete all messages in this conversation?</string>
     <string name="nc_clear_history_success">All messages were deleted</string>
     <string name="nc_rename">Rename conversation</string>
-    <string name="nc_set_password">Set a password</string>
-    <string name="nc_change_password">Change password</string>
-    <string name="nc_clear_password">Clear password</string>
-    <string name="nc_share_link">Share link</string>
-    <string name="nc_make_call_public">Make conversation public</string>
-    <string name="nc_make_call_private">Make conversation private</string>
     <string name="nc_delete_call">Delete conversation</string>
     <string name="nc_delete">Delete</string>
     <string name="nc_delete_all">Delete all</string>
@@ -337,6 +331,22 @@
     <string name="emoji_backspace">Backspace</string>
     <string name="emoji_search">Search emoji</string>
 
+    <!-- Conversation info guest access -->
+    <string name="nc_guest_access">Guest access</string>
+    <string name="nc_guest_access_allow_title">Allow guests</string>
+    <string name="nc_guest_access_allow_summary">Allow guests to share a public link to join this conversation.</string>
+    <string name="nc_guest_access_allow_failed">Can\'t en-/disable guest access.</string>
+    <string name="nc_guest_access_password_title">Password protection</string>
+    <string name="nc_guest_access_password_summary">Set a password to restrict who can use the public link.</string>
+    <string name="nc_guest_access_password_dialog_title">Guest access password</string>
+    <string name="nc_guest_access_password_dialog_hint">Enter a password</string>
+    <string name="nc_guest_access_password_failed">Error during setting/disabling the password.</string>
+    <string name="nc_guest_access_password_weak_alert_title">Weak password</string>
+    <string name="nc_guest_access_share_link">Share conversation link</string>
+    <string name="nc_guest_access_resend_invitations">Resend invitations</string>
+    <string name="nc_guest_access_resend_invitations_successful">Invitations were sent out again.</string>
+    <string name="nc_guest_access_resend_invitations_failed">Invitations were not send due to an error.</string>
+
     <!-- Content descriptions -->
     <string name="nc_description_send_message_button">Send message</string>
 

+ 2 - 14
app/src/test/java/com/nextcloud/talk/utils/ShareUtilsTest.kt

@@ -72,20 +72,8 @@ class ShareUtilsTest {
         )
         Assert.assertEquals(
             "Intent string was not as expected",
-            expectedResult, ShareUtils.getStringForIntent(context, "", userManager!!, conversation)
-        )
-    }
-
-    @Test
-    fun stringForIntent_passwordGiven_correctStringWithPasswordReturned() {
-        val password = "superSecret"
-        val expectedResult = String.format(
-            "Join the conversation at %s/index.php/call/%s\nPassword: %s",
-            baseUrl, token, password
-        )
-        Assert.assertEquals(
-            "Intent string was not as expected",
-            expectedResult, ShareUtils.getStringForIntent(context, password, userManager!!, conversation)
+            expectedResult,
+            ShareUtils.getStringForIntent(context!!, userManager!!.currentUser.blockingGet(), conversation)
         )
     }
 }