diff --git a/app/src/main/java/com/nextcloud/talk/activities/CallActivity.java b/app/src/main/java/com/nextcloud/talk/activities/CallActivity.java index eca9367db..0f691f353 100644 --- a/app/src/main/java/com/nextcloud/talk/activities/CallActivity.java +++ b/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 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())) 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..b360b56ad 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) } @@ -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++ 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..5728dd102 --- /dev/null +++ b/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(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 = 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 { + + 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..9487d81ef 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,22 @@ 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. + Guest access password + 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) ) } }