From 84116e4cb276072af0d11ad5c50fd361faf1dbea Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tim=20Kr=C3=BCger?= Date: Mon, 29 Aug 2022 11:02:09 +0200 Subject: [PATCH 1/5] Add guests access preferences to conversation info MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Currently a conversation can be made public via the bottom sheet menu in the conversation list. With this commit this is added to the conversation info to align with Talk web and iOS. The functionality is removed from the bottom sheet menu in the conversation list. Resolves: #2134 Signed-off-by: Tim Krüger --- .../java/com/nextcloud/talk/api/NcApi.java | 9 + .../controllers/ConversationInfoController.kt | 68 +++-- .../bottomsheet/ConversationOperationEnum.kt | 6 - .../bottomsheet/EntryMenuController.kt | 38 +-- .../bottomsheet/OperationsMenuController.kt | 55 ---- .../conversation/info/GuestAccessHelper.kt | 254 ++++++++++++++++++ .../talk/dagger/modules/RepositoryModule.kt | 8 + .../conversations/password/PasswordData.kt | 36 +++ .../conversations/password/PasswordOCS.kt | 40 +++ .../conversations/password/PasswordOverall.kt | 36 +++ .../conversations/ConversationsRepository.kt | 46 ++++ .../ConversationsRepositoryImpl.kt | 113 ++++++++ .../dialog/ConversationsListBottomDialog.kt | 76 ------ .../com/nextcloud/talk/utils/ApiUtils.java | 4 + .../com/nextcloud/talk/utils/ShareUtils.kt | 26 +- .../layout/controller_conversation_info.xml | 18 +- .../layout/dialog_conversation_operations.xml | 180 ------------- app/src/main/res/layout/dialog_password.xml | 41 +++ .../res/layout/guest_access_settings_item.xml | 81 ++++++ app/src/main/res/values/strings.xml | 21 +- .../nextcloud/talk/utils/ShareUtilsTest.kt | 16 +- 21 files changed, 754 insertions(+), 418 deletions(-) create mode 100644 app/src/main/java/com/nextcloud/talk/conversation/info/GuestAccessHelper.kt create mode 100644 app/src/main/java/com/nextcloud/talk/models/json/conversations/password/PasswordData.kt create mode 100644 app/src/main/java/com/nextcloud/talk/models/json/conversations/password/PasswordOCS.kt create mode 100644 app/src/main/java/com/nextcloud/talk/models/json/conversations/password/PasswordOverall.kt create mode 100644 app/src/main/java/com/nextcloud/talk/repositories/conversations/ConversationsRepository.kt create mode 100644 app/src/main/java/com/nextcloud/talk/repositories/conversations/ConversationsRepositoryImpl.kt create mode 100644 app/src/main/res/layout/dialog_password.xml create mode 100644 app/src/main/res/layout/guest_access_settings_item.xml diff --git a/app/src/main/java/com/nextcloud/talk/api/NcApi.java b/app/src/main/java/com/nextcloud/talk/api/NcApi.java index e4bcbfd67..27b6ecc43 100644 --- a/app/src/main/java/com/nextcloud/talk/api/NcApi.java +++ b/app/src/main/java/com/nextcloud/talk/api/NcApi.java @@ -142,6 +142,9 @@ public interface NcApi { Observable addParticipant(@Header("Authorization") String authorization, @Url String url, @QueryMap Map options); + @POST + Observable 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 setPassword(@Header("Authorization") String authorization, @Url String url, @Field("password") String password); + @FormUrlEncoded + @PUT + Observable> setPassword2(@Header("Authorization") String authorization, + @Url String url, + @Field("password") String password); + @GET Observable getCapabilities(@Header("Authorization") String authorization, @Url String url); diff --git a/app/src/main/java/com/nextcloud/talk/controllers/ConversationInfoController.kt b/app/src/main/java/com/nextcloud/talk/controllers/ConversationInfoController.kt index 80866b882..e89cbdb86 100644 --- a/app/src/main/java/com/nextcloud/talk/controllers/ConversationInfoController.kt +++ b/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 + * Copyright (C) 2021-2022 Tim Krüger * Copyright (C) 2021 Andy Scherzinger (info@andy-scherzinger.de) * Copyright (C) 2017-2018 Mario Danic * @@ -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) } @@ -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 diff --git a/app/src/main/java/com/nextcloud/talk/controllers/bottomsheet/ConversationOperationEnum.kt b/app/src/main/java/com/nextcloud/talk/controllers/bottomsheet/ConversationOperationEnum.kt index 3cd89a8c6..45c20b032 100644 --- a/app/src/main/java/com/nextcloud/talk/controllers/bottomsheet/ConversationOperationEnum.kt +++ b/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, diff --git a/app/src/main/java/com/nextcloud/talk/controllers/bottomsheet/EntryMenuController.kt b/app/src/main/java/com/nextcloud/talk/controllers/bottomsheet/EntryMenuController.kt index c169b7d05..002ac967b 100644 --- a/app/src/main/java/com/nextcloud/talk/controllers/bottomsheet/EntryMenuController.kt +++ b/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(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 = 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 diff --git a/app/src/main/java/com/nextcloud/talk/controllers/bottomsheet/OperationsMenuController.kt b/app/src/main/java/com/nextcloud/talk/controllers/bottomsheet/OperationsMenuController.kt index 5ed400524..277dce01e 100644 --- a/app/src/main/java/com/nextcloud/talk/controllers/bottomsheet/OperationsMenuController.kt +++ b/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, diff --git a/app/src/main/java/com/nextcloud/talk/conversation/info/GuestAccessHelper.kt b/app/src/main/java/com/nextcloud/talk/conversation/info/GuestAccessHelper.kt new file mode 100644 index 000000000..c62ff1ac6 --- /dev/null +++ b/app/src/main/java/com/nextcloud/talk/conversation/info/GuestAccessHelper.kt @@ -0,0 +1,254 @@ +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.EditText +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.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(R.id.mp_checkable) + as SwitchCompat + ) + val guestAccessPasswordSwitch = ( + binding.guestAccessView.guestAccessPasswordSwitch.findViewById(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 = LayoutInflater.from(context).inflate(R.layout.dialog_password, null) + setView(dialogPassword) + setTitle("Guest access password") + setPositiveButton( + "OK" + ) { _, _ -> + val password = dialogPassword.findViewById(R.id.password).text.toString() + conversationsRepository.password(password, conversation.token!!) + .subscribeOn(Schedulers.io()) + .observeOn(AndroidSchedulers.mainThread()) + .subscribe(PasswordResultObserver(true)) + } + setNegativeButton( + "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 { + + 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 { + + 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(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 { + + 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(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 + } +} diff --git a/app/src/main/java/com/nextcloud/talk/dagger/modules/RepositoryModule.kt b/app/src/main/java/com/nextcloud/talk/dagger/modules/RepositoryModule.kt index 0594ae4f8..06021c07e 100644 --- a/app/src/main/java/com/nextcloud/talk/dagger/modules/RepositoryModule.kt +++ b/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) diff --git a/app/src/main/java/com/nextcloud/talk/models/json/conversations/password/PasswordData.kt b/app/src/main/java/com/nextcloud/talk/models/json/conversations/password/PasswordData.kt new file mode 100644 index 000000000..f89b7da13 --- /dev/null +++ b/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 . + */ +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) +} diff --git a/app/src/main/java/com/nextcloud/talk/models/json/conversations/password/PasswordOCS.kt b/app/src/main/java/com/nextcloud/talk/models/json/conversations/password/PasswordOCS.kt new file mode 100644 index 000000000..e15d9aee3 --- /dev/null +++ b/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 . + */ +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) +} diff --git a/app/src/main/java/com/nextcloud/talk/models/json/conversations/password/PasswordOverall.kt b/app/src/main/java/com/nextcloud/talk/models/json/conversations/password/PasswordOverall.kt new file mode 100644 index 000000000..4ff7e9851 --- /dev/null +++ b/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 . + */ +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) +} diff --git a/app/src/main/java/com/nextcloud/talk/repositories/conversations/ConversationsRepository.kt b/app/src/main/java/com/nextcloud/talk/repositories/conversations/ConversationsRepository.kt new file mode 100644 index 000000000..df0148096 --- /dev/null +++ b/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 . + */ + +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 + + data class PasswordResult( + val passwordSet: Boolean, + val passwordIsWeak: Boolean, + val message: String + ) + + fun password(password: String, token: String): Observable + + data class ResendInvitationsResult( + val successful: Boolean + ) + fun resendInvitations(token: String): Observable +} diff --git a/app/src/main/java/com/nextcloud/talk/repositories/conversations/ConversationsRepositoryImpl.kt b/app/src/main/java/com/nextcloud/talk/repositories/conversations/ConversationsRepositoryImpl.kt new file mode 100644 index 000000000..f4f37f4e2 --- /dev/null +++ b/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 . + */ +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 { + + 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 { + 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 { + + 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 + } +} diff --git a/app/src/main/java/com/nextcloud/talk/ui/dialog/ConversationsListBottomDialog.kt b/app/src/main/java/com/nextcloud/talk/ui/dialog/ConversationsListBottomDialog.kt index c3e8bd1b7..2f0206407 100644 --- a/app/src/main/java/com/nextcloud/talk/ui/dialog/ConversationsListBottomDialog.kt +++ b/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) { diff --git a/app/src/main/java/com/nextcloud/talk/utils/ApiUtils.java b/app/src/main/java/com/nextcloud/talk/utils/ApiUtils.java index c79e3185c..fea4f7cb8 100644 --- a/app/src/main/java/com/nextcloud/talk/utils/ApiUtils.java +++ b/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"; } diff --git a/app/src/main/java/com/nextcloud/talk/utils/ShareUtils.kt b/app/src/main/java/com/nextcloud/talk/utils/ShareUtils.kt index e05101b37..44b87f191 100644 --- a/app/src/main/java/com/nextcloud/talk/utils/ShareUtils.kt +++ b/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 + ) } } diff --git a/app/src/main/res/layout/controller_conversation_info.xml b/app/src/main/res/layout/controller_conversation_info.xml index cbd69562b..6ae406ad2 100644 --- a/app/src/main/res/layout/controller_conversation_info.xml +++ b/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 ~ Copyright (C) 2022 Marcel Hibbe ~ Copyright (C) 2021 Andy Scherzinger ~ Copyright (C) 2017-2018 Mario Danic @@ -25,10 +27,10 @@ + android:orientation="vertical" + tools:background="@color/white"> + apc:roundAsCircle="true" + tools:background="@color/hwSecurityRed" /> @@ -150,6 +152,14 @@ android:visibility="gone" tools:visibility="visible" /> + + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + diff --git a/app/src/main/res/layout/guest_access_settings_item.xml b/app/src/main/res/layout/guest_access_settings_item.xml new file mode 100644 index 000000000..6a82431f1 --- /dev/null +++ b/app/src/main/res/layout/guest_access_settings_item.xml @@ -0,0 +1,81 @@ + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 3d16e696b..21b2f8345 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -168,12 +168,6 @@ Do you really want to delete all messages in this conversation? All messages were deleted Rename conversation - Set a password - Change password - Clear password - Share link - Make conversation public - Make conversation private Delete conversation Delete Delete all @@ -337,6 +331,21 @@ Backspace Search emoji + + Guest access + Allow guests + Allow guests to share a public link to join this conversation. + Can\'t en-/disable guest access. + Password protection + Set a password to restrict who can use the public link. + Enter a password + Error during setting/disabling the password. + Weak password + Share conversation link + Resend invitations + Invitations were sent out again. + Invitations were not send due to an error. + Send message diff --git a/app/src/test/java/com/nextcloud/talk/utils/ShareUtilsTest.kt b/app/src/test/java/com/nextcloud/talk/utils/ShareUtilsTest.kt index 490df04ab..789a111fb 100644 --- a/app/src/test/java/com/nextcloud/talk/utils/ShareUtilsTest.kt +++ b/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) ) } } From d8f37bec423e555e84075ba36d44db0c96b9f179 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tim=20Kr=C3=BCger?= Date: Mon, 29 Aug 2022 11:23:44 +0200 Subject: [PATCH 2/5] Replace unused lambda parameters by '_' MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Tim Krüger --- .../talk/controllers/ConversationInfoController.kt | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/app/src/main/java/com/nextcloud/talk/controllers/ConversationInfoController.kt b/app/src/main/java/com/nextcloud/talk/controllers/ConversationInfoController.kt index e89cbdb86..07079951a 100644 --- a/app/src/main/java/com/nextcloud/talk/controllers/ConversationInfoController.kt +++ b/app/src/main/java/com/nextcloud/talk/controllers/ConversationInfoController.kt @@ -1053,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) } @@ -1079,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) } @@ -1099,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) } @@ -1150,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++ From 1d0ff0bade229248d4ea5e2068e053bb34a7b77e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tim=20Kr=C3=BCger?= Date: Mon, 29 Aug 2022 15:35:20 +0200 Subject: [PATCH 3/5] Change to not deprecated 'WorkManager.getInstance' MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Tim Krüger --- .../nextcloud/talk/controllers/ConversationInfoController.kt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/app/src/main/java/com/nextcloud/talk/controllers/ConversationInfoController.kt b/app/src/main/java/com/nextcloud/talk/controllers/ConversationInfoController.kt index 07079951a..b360b56ad 100644 --- a/app/src/main/java/com/nextcloud/talk/controllers/ConversationInfoController.kt +++ b/app/src/main/java/com/nextcloud/talk/controllers/ConversationInfoController.kt @@ -534,7 +534,7 @@ class ConversationInfoController(args: Bundle) : private fun leaveConversation() { workerData?.let { - WorkManager.getInstance().enqueue( + WorkManager.getInstance(context).enqueue( OneTimeWorkRequest.Builder( LeaveConversationWorker::class .java @@ -597,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() From 62fa8c9645d18d6cb7788abca130dd12969a813f Mon Sep 17 00:00:00 2001 From: Andy Scherzinger Date: Mon, 29 Aug 2022 18:46:19 +0200 Subject: [PATCH 4/5] Improve dialog theming for M3 Signed-off-by: Andy Scherzinger --- .../conversation/info/GuestAccessHelper.kt | 19 ++++++++----------- app/src/main/res/layout/dialog_password.xml | 9 +++++---- app/src/main/res/values/strings.xml | 3 ++- 3 files changed, 15 insertions(+), 16 deletions(-) diff --git a/app/src/main/java/com/nextcloud/talk/conversation/info/GuestAccessHelper.kt b/app/src/main/java/com/nextcloud/talk/conversation/info/GuestAccessHelper.kt index c62ff1ac6..5728dd102 100644 --- a/app/src/main/java/com/nextcloud/talk/conversation/info/GuestAccessHelper.kt +++ b/app/src/main/java/com/nextcloud/talk/conversation/info/GuestAccessHelper.kt @@ -5,7 +5,6 @@ import android.content.Intent import android.util.Log import android.view.LayoutInflater import android.view.View -import android.widget.EditText import android.widget.Toast import androidx.appcompat.app.AlertDialog import androidx.appcompat.widget.SwitchCompat @@ -14,6 +13,7 @@ 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 @@ -92,21 +92,18 @@ class GuestAccessHelper( private fun showPasswordDialog(guestAccessPasswordSwitch: SwitchCompat) { val builder = MaterialAlertDialogBuilder(activity) builder.apply { - val dialogPassword = LayoutInflater.from(context).inflate(R.layout.dialog_password, null) - setView(dialogPassword) - setTitle("Guest access password") - setPositiveButton( - "OK" - ) { _, _ -> - val password = dialogPassword.findViewById(R.id.password).text.toString() + 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( - "Cancel" - ) { _, _ -> + setNegativeButton(R.string.nc_cancel) { _, _ -> guestAccessPasswordSwitch.isChecked = false } } diff --git a/app/src/main/res/layout/dialog_password.xml b/app/src/main/res/layout/dialog_password.xml index 7239929a8..e07018640 100644 --- a/app/src/main/res/layout/dialog_password.xml +++ b/app/src/main/res/layout/dialog_password.xml @@ -2,7 +2,9 @@