diff --git a/app/src/main/java/com/nextcloud/talk/account/ServerSelectionActivity.kt b/app/src/main/java/com/nextcloud/talk/account/ServerSelectionActivity.kt index 38dbe43006..60be0f60b2 100644 --- a/app/src/main/java/com/nextcloud/talk/account/ServerSelectionActivity.kt +++ b/app/src/main/java/com/nextcloud/talk/account/ServerSelectionActivity.kt @@ -239,41 +239,13 @@ class ServerSelectionActivity : BaseActivity() { .subscribeOn(Schedulers.io()) .observeOn(AndroidSchedulers.mainThread()) .subscribe({ status: Status -> - val productName = resources!!.getString(R.string.nc_server_product_name) val versionString: String = status.version!!.substring(0, status.version!!.indexOf(".")) val version: Int = versionString.toInt() if (isServerStatusQueryable(status) && version >= MIN_SERVER_MAJOR_VERSION) { findServerTalkApp(url) - } else if (!status.installed) { - setErrorText( - String.format( - resources!!.getString(R.string.nc_server_not_installed), - productName - ) - ) - } else if (status.needsUpgrade) { - setErrorText( - String.format( - resources!!.getString(R.string.nc_server_db_upgrade_needed), - productName - ) - ) - } else if (status.maintenance) { - setErrorText( - String.format( - resources!!.getString(R.string.nc_server_maintenance), - productName - ) - ) - } else if (!status.version!!.startsWith("13.")) { - setErrorText( - String.format( - resources!!.getString(R.string.nc_server_version), - resources!!.getString(R.string.nc_app_product_name), - productName - ) - ) + } else { + showErrorTextForStatus(status) } }, { throwable: Throwable -> if (checkForcedHttps) { @@ -303,6 +275,39 @@ class ServerSelectionActivity : BaseActivity() { } } + private fun showErrorTextForStatus(status: Status) { + if (!status.installed) { + setErrorText( + String.format( + resources!!.getString(R.string.nc_server_not_installed), + resources!!.getString(R.string.nc_server_product_name) + ) + ) + } else if (status.needsUpgrade) { + setErrorText( + String.format( + resources!!.getString(R.string.nc_server_db_upgrade_needed), + resources!!.getString(R.string.nc_server_product_name) + ) + ) + } else if (status.maintenance) { + setErrorText( + String.format( + resources!!.getString(R.string.nc_server_maintenance), + resources!!.getString(R.string.nc_server_product_name) + ) + ) + } else if (!status.version!!.startsWith("13.")) { + setErrorText( + String.format( + resources!!.getString(R.string.nc_server_version), + resources!!.getString(R.string.nc_app_product_name), + resources!!.getString(R.string.nc_server_product_name) + ) + ) + } + } + private fun findServerTalkApp(queryUrl: String) { ncApi.getCapabilities(ApiUtils.getUrlForCapabilities(queryUrl)) .subscribeOn(Schedulers.io()) @@ -364,7 +369,7 @@ class ServerSelectionActivity : BaseActivity() { return status.installed && !status.maintenance && !status.needsUpgrade } - private fun setErrorText(text: String) { + private fun setErrorText(text: String?) { binding.errorWrapper.visibility = View.VISIBLE binding.errorText.text = text hideserverEntryProgressBar() diff --git a/app/src/main/java/com/nextcloud/talk/account/WebViewLoginActivity.kt b/app/src/main/java/com/nextcloud/talk/account/WebViewLoginActivity.kt index 209d2e371c..bb04f3c976 100644 --- a/app/src/main/java/com/nextcloud/talk/account/WebViewLoginActivity.kt +++ b/app/src/main/java/com/nextcloud/talk/account/WebViewLoginActivity.kt @@ -220,11 +220,11 @@ class WebViewLoginActivity : BaseActivity() { } override fun onReceivedClientCertRequest(view: WebView, request: ClientCertRequest) { - val user = userManager.currentUser.blockingGet() var alias: String? = null if (!reauthorizeAccount) { alias = appPreferences.temporaryClientCertAlias } + val user = userManager.currentUser.blockingGet() if (TextUtils.isEmpty(alias) && user != null) { alias = user.clientCertificate } diff --git a/app/src/main/java/com/nextcloud/talk/activities/CallActivity.kt b/app/src/main/java/com/nextcloud/talk/activities/CallActivity.kt index 44e1b4504f..9220952c0d 100644 --- a/app/src/main/java/com/nextcloud/talk/activities/CallActivity.kt +++ b/app/src/main/java/com/nextcloud/talk/activities/CallActivity.kt @@ -371,27 +371,11 @@ class CallActivity : CallBaseActivity() { binding = CallActivityBinding.inflate(layoutInflater) setContentView(binding!!.root) hideNavigationIfNoPipAvailable() + processExtras(intent.extras!!) + conversationUser = currentUserProvider.currentUser.blockingGet() - val extras = intent.extras - roomId = extras!!.getString(KEY_ROOM_ID, "") - roomToken = extras.getString(KEY_ROOM_TOKEN, "") - conversationPassword = extras.getString(KEY_CONVERSATION_PASSWORD, "") - conversationName = extras.getString(KEY_CONVERSATION_NAME, "") - isVoiceOnlyCall = extras.getBoolean(KEY_CALL_VOICE_ONLY, false) - isCallWithoutNotification = extras.getBoolean(KEY_CALL_WITHOUT_NOTIFICATION, false) - canPublishAudioStream = extras.getBoolean(KEY_PARTICIPANT_PERMISSION_CAN_PUBLISH_AUDIO) - canPublishVideoStream = extras.getBoolean(KEY_PARTICIPANT_PERMISSION_CAN_PUBLISH_VIDEO) - isModerator = extras.getBoolean(KEY_IS_MODERATOR, false) - isOneToOneConversation = extras.getBoolean(KEY_ROOM_ONE_TO_ONE, false) - if (extras.containsKey(KEY_FROM_NOTIFICATION_START_CALL)) { - isIncomingCallFromNotification = extras.getBoolean(KEY_FROM_NOTIFICATION_START_CALL) - } - if (extras.containsKey(KEY_IS_BREAKOUT_ROOM)) { - isBreakoutRoom = extras.getBoolean(KEY_IS_BREAKOUT_ROOM) - } credentials = ApiUtils.getCredentials(conversationUser!!.username, conversationUser!!.token) - baseUrl = extras.getString(KEY_MODIFIED_BASE_URL, "") if (TextUtils.isEmpty(baseUrl)) { baseUrl = conversationUser!!.baseUrl } @@ -399,28 +383,30 @@ class CallActivity : CallBaseActivity() { setCallState(CallStatus.CONNECTING) - raiseHandViewModel = ViewModelProvider(this, viewModelFactory).get(RaiseHandViewModel::class.java) - raiseHandViewModel!!.setData(roomToken!!, isBreakoutRoom) - raiseHandViewModel!!.viewState.observe(this) { viewState: RaiseHandViewModel.ViewState? -> - var raised = false - if (viewState is RaisedHandState) { - binding!!.lowerHandButton.visibility = View.VISIBLE - raised = true - } else if (viewState is LoweredHandState) { - binding!!.lowerHandButton.visibility = View.GONE - raised = false - } - if (isConnectionEstablished) { - for (peerConnectionWrapper in peerConnectionWrapperList) { - peerConnectionWrapper.raiseHand(raised) - } - } - } + initRaiseHandViewModel() + initCallRecordingViewModel(intent.extras!!.getInt(KEY_RECORDING_STATE)) + initClickListeners(isModerator, isOneToOneConversation) + binding!!.microphoneButton.setOnTouchListener(MicrophoneButtonTouchListener()) + pulseAnimation = PulseAnimation.create().with(binding!!.microphoneButton) + .setDuration(PULSE_ANIMATION_DURATION) + .setRepeatCount(PulseAnimation.INFINITE) + .setRepeatMode(PulseAnimation.REVERSE) + basicInitialization() + callParticipants = HashMap() + participantDisplayItems = HashMap() + initViews() + updateSelfVideoViewPosition() + reactionAnimator = ReactionAnimator(context, binding!!.reactionAnimationWrapper, viewThemeUtils) + + checkRecordingConsentAndInitiateCall() + } + + private fun initCallRecordingViewModel(recordingState: Int) { callRecordingViewModel = ViewModelProvider(this, viewModelFactory).get( CallRecordingViewModel::class.java ) callRecordingViewModel!!.setData(roomToken!!) - callRecordingViewModel!!.setRecordingState(extras.getInt(KEY_RECORDING_STATE)) + callRecordingViewModel!!.setRecordingState(recordingState) callRecordingViewModel!!.viewState.observe(this) { viewState: CallRecordingViewModel.ViewState? -> if (viewState is RecordingStartedState) { binding!!.callRecordingIndicator.setImageResource(R.drawable.record_stop) @@ -473,20 +459,48 @@ class CallActivity : CallBaseActivity() { binding!!.callRecordingIndicator.visibility = View.GONE } } - initClickListeners(isModerator, isOneToOneConversation) - binding!!.microphoneButton.setOnTouchListener(MicrophoneButtonTouchListener()) - pulseAnimation = PulseAnimation.create().with(binding!!.microphoneButton) - .setDuration(PULSE_ANIMATION_DURATION) - .setRepeatCount(PulseAnimation.INFINITE) - .setRepeatMode(PulseAnimation.REVERSE) - basicInitialization() - callParticipants = HashMap() - participantDisplayItems = HashMap() - initViews() - updateSelfVideoViewPosition() - reactionAnimator = ReactionAnimator(context, binding!!.reactionAnimationWrapper, viewThemeUtils) + } - checkRecordingConsentAndInitiateCall() + private fun initRaiseHandViewModel() { + raiseHandViewModel = ViewModelProvider(this, viewModelFactory).get(RaiseHandViewModel::class.java) + raiseHandViewModel!!.setData(roomToken!!, isBreakoutRoom) + raiseHandViewModel!!.viewState.observe(this) { viewState: RaiseHandViewModel.ViewState? -> + var raised = false + if (viewState is RaisedHandState) { + binding!!.lowerHandButton.visibility = View.VISIBLE + raised = true + } else if (viewState is LoweredHandState) { + binding!!.lowerHandButton.visibility = View.GONE + raised = false + } + if (isConnectionEstablished) { + for (peerConnectionWrapper in peerConnectionWrapperList) { + peerConnectionWrapper.raiseHand(raised) + } + } + } + } + + private fun processExtras(extras: Bundle) { + roomId = extras.getString(KEY_ROOM_ID, "") + roomToken = extras.getString(KEY_ROOM_TOKEN, "") + conversationPassword = extras.getString(KEY_CONVERSATION_PASSWORD, "") + conversationName = extras.getString(KEY_CONVERSATION_NAME, "") + isVoiceOnlyCall = extras.getBoolean(KEY_CALL_VOICE_ONLY, false) + isCallWithoutNotification = extras.getBoolean(KEY_CALL_WITHOUT_NOTIFICATION, false) + canPublishAudioStream = extras.getBoolean(KEY_PARTICIPANT_PERMISSION_CAN_PUBLISH_AUDIO) + canPublishVideoStream = extras.getBoolean(KEY_PARTICIPANT_PERMISSION_CAN_PUBLISH_VIDEO) + isModerator = extras.getBoolean(KEY_IS_MODERATOR, false) + isOneToOneConversation = extras.getBoolean(KEY_ROOM_ONE_TO_ONE, false) + + if (extras.containsKey(KEY_FROM_NOTIFICATION_START_CALL)) { + isIncomingCallFromNotification = extras.getBoolean(KEY_FROM_NOTIFICATION_START_CALL) + } + if (extras.containsKey(KEY_IS_BREAKOUT_ROOM)) { + isBreakoutRoom = extras.getBoolean(KEY_IS_BREAKOUT_ROOM) + } + + baseUrl = extras.getString(KEY_MODIFIED_BASE_URL, "") } private fun checkRecordingConsentAndInitiateCall() { @@ -618,17 +632,7 @@ class CallActivity : CallBaseActivity() { @SuppressLint("ClickableViewAccessibility") private fun initClickListeners(isModerator: Boolean, isOneToOneConversation: Boolean) { - binding!!.pictureInPictureButton.setOnClickListener { enterPipMode() } - - binding!!.audioOutputButton.setOnClickListener { - audioOutputDialog = AudioOutputDialog(this) - audioOutputDialog!!.show() - } - - binding!!.moreCallActions.setOnClickListener { - moreCallActionsDialog = MoreCallActionsDialog(this) - moreCallActionsDialog!!.show() - } + initCallActionClickListeners(isModerator, isOneToOneConversation) if (canPublishAudioStream) { binding!!.microphoneButton.setOnClickListener { onMicrophoneClick() } @@ -648,11 +652,7 @@ class CallActivity : CallBaseActivity() { } } else { binding!!.microphoneButton.setOnClickListener { - Snackbar.make( - binding!!.root, - R.string.nc_not_allowed_to_activate_audio, - Snackbar.LENGTH_SHORT - ).show() + Snackbar.make(binding!!.root, R.string.nc_not_allowed_to_activate_audio, Snackbar.LENGTH_SHORT).show() } } @@ -660,13 +660,46 @@ class CallActivity : CallBaseActivity() { binding!!.cameraButton.setOnClickListener { onCameraClick() } } else { binding!!.cameraButton.setOnClickListener { + Snackbar.make(binding!!.root, R.string.nc_not_allowed_to_activate_video, Snackbar.LENGTH_SHORT).show() + } + } + + binding!!.callStates.callStateRelativeLayout.setOnClickListener { + if (currentCallStatus === CallStatus.CALLING_TIMEOUT) { + setCallState(CallStatus.RECONNECTING) + hangupNetworkCalls(shutDownView = false, endCallForAll = false) + } + } + binding!!.callRecordingIndicator.setOnClickListener { + if (isAllowedToStartOrStopRecording) { + if (callRecordingViewModel!!.viewState.value is RecordingStartingState) { + if (moreCallActionsDialog == null) { + moreCallActionsDialog = MoreCallActionsDialog(this) + } + moreCallActionsDialog!!.show() + } else { + callRecordingViewModel!!.clickRecordButton() + } + } else { Snackbar.make( binding!!.root, - R.string.nc_not_allowed_to_activate_video, - Snackbar.LENGTH_SHORT + context.resources.getString(R.string.record_active_info), + Snackbar.LENGTH_LONG ).show() } } + } + + private fun initCallActionClickListeners(isModerator: Boolean, isOneToOneConversation: Boolean) { + binding!!.audioOutputButton.setOnClickListener { + audioOutputDialog = AudioOutputDialog(this) + audioOutputDialog!!.show() + } + + binding!!.moreCallActions.setOnClickListener { + moreCallActionsDialog = MoreCallActionsDialog(this) + moreCallActionsDialog!!.show() + } if (isOneToOneConversation) { binding!!.hangupButton.setOnLongClickListener { @@ -674,7 +707,11 @@ class CallActivity : CallBaseActivity() { true } binding!!.hangupButton.setOnClickListener { - hangup(true, true) + hangup(shutDownView = true, endCallForAll = true) + } + binding!!.endCallPopupMenu.setOnClickListener { + hangup(shutDownView = true, endCallForAll = true) + binding!!.endCallPopupMenu.visibility = View.GONE } } else { if (isModerator) { @@ -684,18 +721,10 @@ class CallActivity : CallBaseActivity() { } } binding!!.hangupButton.setOnClickListener { - hangup(true, false) + hangup(shutDownView = true, endCallForAll = false) } - } - - if (!isOneToOneConversation) { - binding!!.endCallPopupMenu.setOnClickListener { - hangup(true, true) - binding!!.endCallPopupMenu.visibility = View.GONE - } - } else { binding!!.endCallPopupMenu.setOnClickListener { - hangup(true, false) + hangup(shutDownView = true, endCallForAll = false) binding!!.endCallPopupMenu.visibility = View.GONE } } @@ -703,36 +732,10 @@ class CallActivity : CallBaseActivity() { binding!!.switchSelfVideoButton.setOnClickListener { switchCamera() } binding!!.gridview.onItemClickListener = AdapterView.OnItemClickListener { _: AdapterView<*>?, _: View?, _: Int, _: Long -> - animateCallControls( - true, - 0 - ) - } - binding!!.callStates.callStateRelativeLayout.setOnClickListener { - if (currentCallStatus === CallStatus.CALLING_TIMEOUT) { - setCallState(CallStatus.RECONNECTING) - hangupNetworkCalls(false, false) - } - } - binding!!.callRecordingIndicator.setOnClickListener { - if (isAllowedToStartOrStopRecording) { - if (callRecordingViewModel!!.viewState.value is RecordingStartingState) { - if (moreCallActionsDialog == null) { - moreCallActionsDialog = MoreCallActionsDialog(this) - } - moreCallActionsDialog!!.show() - } else { - callRecordingViewModel!!.clickRecordButton() - } - } else { - Snackbar.make( - binding!!.root, - context.resources.getString(R.string.record_active_info), - Snackbar.LENGTH_LONG - ).show() + animateCallControls(true, 0) } - } binding!!.lowerHandButton.setOnClickListener { l: View? -> raiseHandViewModel!!.lowerHand() } + binding!!.pictureInPictureButton.setOnClickListener { enterPipMode() } } private fun showEndCallForAllPopupMenu() { @@ -2013,64 +2016,63 @@ class CallActivity : CallBaseActivity() { dispose(null) if (shutDownView) { - if (videoCapturer != null) { - try { - videoCapturer!!.stopCapture() - } catch (e: InterruptedException) { - Log.e(TAG, "Failed to stop capturing while hanging up") - } - videoCapturer!!.dispose() - videoCapturer = null - } - binding!!.selfVideoRenderer.release() - if (audioSource != null) { - audioSource!!.dispose() - audioSource = null - } - runOnUiThread { - if (audioManager != null) { - audioManager!!.stop() - audioManager = null - } - } - if (videoSource != null) { - videoSource = null - } - if (peerConnectionFactory != null) { - peerConnectionFactory = null - } - localAudioTrack = null - localVideoTrack = null - if (TextUtils.isEmpty(credentials) && hasExternalSignalingServer) { - WebSocketConnectionHelper.deleteExternalSignalingInstanceForUserEntity(-1) - } + terminateAudioVideo() } val peerConnectionIdsToEnd: MutableList = ArrayList(peerConnectionWrapperList.size) - for (wrapper in peerConnectionWrapperList) { peerConnectionIdsToEnd.add(wrapper.sessionId) } - for (sessionId in peerConnectionIdsToEnd) { endPeerConnection(sessionId, "video") endPeerConnection(sessionId, "screen") } - val callParticipantIdsToEnd: MutableList = ArrayList(peerConnectionWrapperList.size) for (callParticipant in callParticipants.values) { callParticipantIdsToEnd.add(callParticipant!!.callParticipantModel.sessionId) } - for (sessionId in callParticipantIdsToEnd) { removeCallParticipant(sessionId) } - ApplicationWideCurrentRoomHolder.getInstance().isInCall = false ApplicationWideCurrentRoomHolder.getInstance().isDialing = false hangupNetworkCalls(shutDownView, endCallForAll) } + private fun terminateAudioVideo() { + if (videoCapturer != null) { + try { + videoCapturer!!.stopCapture() + } catch (e: InterruptedException) { + Log.e(TAG, "Failed to stop capturing while hanging up") + } + videoCapturer!!.dispose() + videoCapturer = null + } + binding!!.selfVideoRenderer.release() + if (audioSource != null) { + audioSource!!.dispose() + audioSource = null + } + runOnUiThread { + if (audioManager != null) { + audioManager!!.stop() + audioManager = null + } + } + if (videoSource != null) { + videoSource = null + } + if (peerConnectionFactory != null) { + peerConnectionFactory = null + } + localAudioTrack = null + localVideoTrack = null + if (TextUtils.isEmpty(credentials) && hasExternalSignalingServer) { + WebSocketConnectionHelper.deleteExternalSignalingInstanceForUserEntity(-1) + } + } + private fun hangupNetworkCalls(shutDownView: Boolean, endCallForAll: Boolean) { Log.d(TAG, "hangupNetworkCalls. shutDownView=$shutDownView") val apiVersion = ApiUtils.getCallApiVersion(conversationUser, intArrayOf(ApiUtils.API_V4, 1)) @@ -2170,22 +2172,16 @@ class CallActivity : CallBaseActivity() { } if (!isSelfInCall && - currentCallStatus !== CallStatus.LEAVING && - ApplicationWideCurrentRoomHolder.getInstance().isInCall + currentCallStatus !== CallStatus.LEAVING && ApplicationWideCurrentRoomHolder.getInstance().isInCall ) { Log.d(TAG, "Most probably a moderator ended the call for all.") - hangup(true, false) + hangup(shutDownView = true, endCallForAll = false) return } if (!isSelfInCall) { Log.d(TAG, "Self not in call, disconnecting from all other sessions") - for ((_, _, _, _, _, _, _, _, _, _, sessionId) in participantsInCall) { - Log.d(TAG, " session that will be removed is: $sessionId") - endPeerConnection(sessionId, "video") - endPeerConnection(sessionId, "screen") - removeCallParticipant(sessionId) - } + removeSessions(participantsInCall) return } if (currentCallStatus === CallStatus.LEAVING) { @@ -2199,6 +2195,28 @@ class CallActivity : CallBaseActivity() { true ) } + handleJoinedCallParticipantsChanged(selfParticipant, joined, currentSessionId) + + if (othersInCall && currentCallStatus !== CallStatus.IN_CONVERSATION) { + setCallState(CallStatus.IN_CONVERSATION) + } + removeSessions(left) + } + + private fun removeSessions(sessions: Collection) { + for ((_, _, _, _, _, _, _, _, _, _, session) in sessions) { + Log.d(TAG, " session that will be removed is: $session") + endPeerConnection(session, "video") + endPeerConnection(session, "screen") + removeCallParticipant(session) + } + } + + private fun handleJoinedCallParticipantsChanged( + selfParticipant: Participant?, + joined: Collection, + currentSessionId: String? + ) { var selfJoined = false val selfParticipantHasAudioOrVideo = participantInCallFlagsHaveAudioOrVideo(selfParticipant) for (participant in joined) { @@ -2240,11 +2258,13 @@ class CallActivity : CallBaseActivity() { // remote session ID. However, if the other participant does not have audio nor video that participant // will not send an offer, so no connection is actually established when the remote participant has a // higher session ID but is not publishing media. - if (hasMCU && - participantHasAudioOrVideo || - !hasMCU && - selfParticipantHasAudioOrVideo && - (!participantHasAudioOrVideo || sessionId < currentSessionId!!) + if (hasMCUAndAudioVideo(participantHasAudioOrVideo) || + hasNoMCUAndAudioVideo( + participantHasAudioOrVideo, + selfParticipantHasAudioOrVideo, + sessionId, + currentSessionId!! + ) ) { getOrCreatePeerConnectionWrapperForSessionIdAndType(sessionId, VIDEO_STREAM_TYPE_VIDEO, false) } @@ -2254,18 +2274,18 @@ class CallActivity : CallBaseActivity() { } else { joined.isNotEmpty() } - - if (othersInCall && currentCallStatus !== CallStatus.IN_CONVERSATION) { - setCallState(CallStatus.IN_CONVERSATION) - } - for ((_, _, _, _, _, _, _, _, _, _, sessionId) in left) { - Log.d(TAG, " oldSession that will be removed is: $sessionId") - endPeerConnection(sessionId, "video") - endPeerConnection(sessionId, "screen") - removeCallParticipant(sessionId) - } } + private fun hasMCUAndAudioVideo(participantHasAudioOrVideo: Boolean): Boolean = hasMCU && participantHasAudioOrVideo + + private fun hasNoMCUAndAudioVideo( + participantHasAudioOrVideo: Boolean, + selfParticipantHasAudioOrVideo: Boolean, + sessionId: String, + currentSessionId: String + ): Boolean = + !hasMCU && selfParticipantHasAudioOrVideo && (!participantHasAudioOrVideo || sessionId < currentSessionId) + private fun participantInCallFlagsHaveAudioOrVideo(participant: Participant?): Boolean = if (participant == null) { false @@ -2289,8 +2309,7 @@ class CallActivity : CallBaseActivity() { type: String, publisher: Boolean ): PeerConnectionWrapper? { - var peerConnectionWrapper: PeerConnectionWrapper? - peerConnectionWrapper = getPeerConnectionWrapperForSessionIdAndType(sessionId, type) + var peerConnectionWrapper = getPeerConnectionWrapperForSessionIdAndType(sessionId, type) return if (peerConnectionWrapper != null) { peerConnectionWrapper @@ -2302,68 +2321,10 @@ class CallActivity : CallBaseActivity() { context.resources.getString(R.string.nc_common_error_sorry), Snackbar.LENGTH_LONG ).show() - hangup(true, false) + hangup(shutDownView = true, endCallForAll = false) return null } - peerConnectionWrapper = if (hasMCU && publisher) { - PeerConnectionWrapper( - peerConnectionFactory, - iceServers, - sdpConstraintsForMCU, - sessionId, - callSession, - localStream, - true, - true, - type, - signalingMessageReceiver, - signalingMessageSender - ) - } else if (hasMCU) { - PeerConnectionWrapper( - peerConnectionFactory, - iceServers, - sdpConstraints, - sessionId, - callSession, - null, - false, - true, - type, - signalingMessageReceiver, - signalingMessageSender - ) - } else { - if ("screen" != type) { - PeerConnectionWrapper( - peerConnectionFactory, - iceServers, - sdpConstraints, - sessionId, - callSession, - localStream, - false, - false, - type, - signalingMessageReceiver, - signalingMessageSender - ) - } else { - PeerConnectionWrapper( - peerConnectionFactory, - iceServers, - sdpConstraints, - sessionId, - callSession, - null, - false, - false, - type, - signalingMessageReceiver, - signalingMessageSender - ) - } - } + peerConnectionWrapper = createPeerConnectionWrapperForSessionIdAndType(publisher, sessionId, type) peerConnectionWrapperList.add(peerConnectionWrapper) if (!publisher) { var callParticipant = callParticipants[sessionId] @@ -2384,6 +2345,47 @@ class CallActivity : CallBaseActivity() { } } + private fun createPeerConnectionWrapperForSessionIdAndType( + publisher: Boolean, + sessionId: String?, + type: String + ): PeerConnectionWrapper { + val tempIsMCUPublisher: Boolean + val tempHasMCU: Boolean + val tempLocalStream: MediaStream? + if (hasMCU && publisher) { + tempIsMCUPublisher = true + tempHasMCU = true + tempLocalStream = localStream + } else if (hasMCU) { + tempIsMCUPublisher = false + tempHasMCU = true + tempLocalStream = null + } else { + tempIsMCUPublisher = false + tempHasMCU = false + tempLocalStream = if ("screen" != type) { + localStream + } else { + null + } + } + + return PeerConnectionWrapper( + peerConnectionFactory, + iceServers, + sdpConstraintsForMCU, + sessionId, + callSession, + tempLocalStream, + tempIsMCUPublisher, + tempHasMCU, + type, + signalingMessageReceiver, + signalingMessageSender + ) + } + private fun addCallParticipant(sessionId: String?): CallParticipant { val callParticipant = CallParticipant(sessionId, signalingMessageReceiver) callParticipants[sessionId] = callParticipant @@ -2530,7 +2532,7 @@ class CallActivity : CallBaseActivity() { ProximitySensorEvent.ProximitySensorEventType.SENSOR_FAR && videoOn if (permissionUtil!!.isCameraPermissionGranted() && - (currentCallStatus === CallStatus.CONNECTING || isConnectionEstablished) && + isConnectingOrEstablished() && videoOn && enableVideo != localVideoTrack!!.enabled() ) { @@ -2539,6 +2541,9 @@ class CallActivity : CallBaseActivity() { } } + private fun isConnectingOrEstablished(): Boolean = + currentCallStatus === CallStatus.CONNECTING || isConnectionEstablished + private fun startSendingNick() { val dataChannelMessage = DataChannelMessage() dataChannelMessage.type = "nickChanged" @@ -2602,161 +2607,170 @@ class CallActivity : CallBaseActivity() { handler!!.removeCallbacksAndMessages(null) } when (callState) { - CallStatus.CONNECTING -> handler!!.post { - playCallingSound() - if (isIncomingCallFromNotification) { - binding!!.callStates.callStateTextView.setText(R.string.nc_call_incoming) - } else { - binding!!.callStates.callStateTextView.setText(R.string.nc_call_ringing) - } - binding!!.callConversationNameTextView.text = conversationName - binding!!.callModeTextView.text = descriptionForCallType - if (binding!!.callStates.callStateRelativeLayout.visibility != View.VISIBLE) { - binding!!.callStates.callStateRelativeLayout.visibility = View.VISIBLE - } - if (binding!!.gridview.visibility != View.INVISIBLE) { - binding!!.gridview.visibility = View.INVISIBLE - } - if (binding!!.callStates.callStateProgressBar.visibility != View.VISIBLE) { - binding!!.callStates.callStateProgressBar.visibility = View.VISIBLE - } - if (binding!!.callStates.errorImageView.visibility != View.GONE) { - binding!!.callStates.errorImageView.visibility = View.GONE - } + CallStatus.CONNECTING -> handler!!.post { handleCallStateConnected() } + CallStatus.CALLING_TIMEOUT -> handler!!.post { handleCallStateCallingTimeout() } + CallStatus.PUBLISHER_FAILED -> handler!!.post { handleCallStatePublisherFailed() } + CallStatus.RECONNECTING -> handler!!.post { handleCallStateReconnecting() } + CallStatus.JOINED -> { + handler!!.postDelayed({ setCallState(CallStatus.CALLING_TIMEOUT) }, CALLING_TIMEOUT) + handler!!.post { handleCallStateJoined() } } + CallStatus.IN_CONVERSATION -> handler!!.post { handleCallStateInConversation() } + CallStatus.OFFLINE -> handler!!.post { handleCallStateOffline() } + CallStatus.LEAVING -> handler!!.post { handleCallStateLeaving() } + } + } + } - CallStatus.CALLING_TIMEOUT -> handler!!.post { - hangup(false, false) - binding!!.callStates.callStateTextView.setText(R.string.nc_call_timeout) - binding!!.callModeTextView.text = descriptionForCallType - if (binding!!.callStates.callStateRelativeLayout.visibility != View.VISIBLE) { - binding!!.callStates.callStateRelativeLayout.visibility = View.VISIBLE - } - if (binding!!.callStates.callStateProgressBar.visibility != View.GONE) { - binding!!.callStates.callStateProgressBar.visibility = View.GONE - } - if (binding!!.gridview.visibility != View.INVISIBLE) { - binding!!.gridview.visibility = View.INVISIBLE - } - binding!!.callStates.errorImageView.setImageResource(R.drawable.ic_av_timer_timer_24dp) - if (binding!!.callStates.errorImageView.visibility != View.VISIBLE) { - binding!!.callStates.errorImageView.visibility = View.VISIBLE - } - } + private fun handleCallStateLeaving() { + if (!isDestroyed) { + stopCallingSound() + binding!!.callModeTextView.text = descriptionForCallType + binding!!.callStates.callStateTextView.setText(R.string.nc_leaving_call) + binding!!.callStates.callStateRelativeLayout.visibility = View.VISIBLE + binding!!.gridview.visibility = View.INVISIBLE + binding!!.callStates.callStateProgressBar.visibility = View.VISIBLE + binding!!.callStates.errorImageView.visibility = View.GONE + } + } - CallStatus.PUBLISHER_FAILED -> handler!!.post { - // No calling sound when the publisher failed - binding!!.callStates.callStateTextView.setText(R.string.nc_call_reconnecting) - binding!!.callModeTextView.text = descriptionForCallType - if (binding!!.callStates.callStateRelativeLayout.visibility != View.VISIBLE) { - binding!!.callStates.callStateRelativeLayout.visibility = View.VISIBLE - } - if (binding!!.gridview.visibility != View.INVISIBLE) { - binding!!.gridview.visibility = View.INVISIBLE - } - if (binding!!.callStates.callStateProgressBar.visibility != View.VISIBLE) { - binding!!.callStates.callStateProgressBar.visibility = View.VISIBLE - } - if (binding!!.callStates.errorImageView.visibility != View.GONE) { - binding!!.callStates.errorImageView.visibility = View.GONE - } - } + private fun handleCallStateOffline() { + stopCallingSound() + binding!!.callStates.callStateTextView.setText(R.string.nc_offline) + if (binding!!.callStates.callStateRelativeLayout.visibility != View.VISIBLE) { + binding!!.callStates.callStateRelativeLayout.visibility = View.VISIBLE + } + if (binding!!.gridview.visibility != View.INVISIBLE) { + binding!!.gridview.visibility = View.INVISIBLE + } + if (binding!!.callStates.callStateProgressBar.visibility != View.GONE) { + binding!!.callStates.callStateProgressBar.visibility = View.GONE + } + binding!!.callStates.errorImageView.setImageResource(R.drawable.ic_signal_wifi_off_white_24dp) + if (binding!!.callStates.errorImageView.visibility != View.VISIBLE) { + binding!!.callStates.errorImageView.visibility = View.VISIBLE + } + } - CallStatus.RECONNECTING -> handler!!.post { - playCallingSound() - binding!!.callStates.callStateTextView.setText(R.string.nc_call_reconnecting) - binding!!.callModeTextView.text = descriptionForCallType - if (binding!!.callStates.callStateRelativeLayout.visibility != View.VISIBLE) { - binding!!.callStates.callStateRelativeLayout.visibility = View.VISIBLE - } - if (binding!!.gridview.visibility != View.INVISIBLE) { - binding!!.gridview.visibility = View.INVISIBLE - } - if (binding!!.callStates.callStateProgressBar.visibility != View.VISIBLE) { - binding!!.callStates.callStateProgressBar.visibility = View.VISIBLE - } - if (binding!!.callStates.errorImageView.visibility != View.GONE) { - binding!!.callStates.errorImageView.visibility = View.GONE - } - } + private fun handleCallStateInConversation() { + stopCallingSound() + binding!!.callModeTextView.text = descriptionForCallType + if (!isVoiceOnlyCall) { + binding!!.callInfosLinearLayout.visibility = View.GONE + } + if (!isPushToTalkActive) { + animateCallControls(false, FIVE_SECONDS) + } + if (binding!!.callStates.callStateRelativeLayout.visibility != View.INVISIBLE) { + binding!!.callStates.callStateRelativeLayout.visibility = View.INVISIBLE + } + if (binding!!.callStates.callStateProgressBar.visibility != View.GONE) { + binding!!.callStates.callStateProgressBar.visibility = View.GONE + } + if (binding!!.gridview.visibility != View.VISIBLE) { + binding!!.gridview.visibility = View.VISIBLE + } + if (binding!!.callStates.errorImageView.visibility != View.GONE) { + binding!!.callStates.errorImageView.visibility = View.GONE + } + } - CallStatus.JOINED -> { - handler!!.postDelayed({ setCallState(CallStatus.CALLING_TIMEOUT) }, CALLING_TIMEOUT) - handler!!.post { - binding!!.callModeTextView.text = descriptionForCallType - if (isIncomingCallFromNotification) { - binding!!.callStates.callStateTextView.setText(R.string.nc_call_incoming) - } else { - binding!!.callStates.callStateTextView.setText(R.string.nc_call_ringing) - } - if (binding!!.callStates.callStateRelativeLayout.visibility != View.VISIBLE) { - binding!!.callStates.callStateRelativeLayout.visibility = View.VISIBLE - } - if (binding!!.callStates.callStateProgressBar.visibility != View.VISIBLE) { - binding!!.callStates.callStateProgressBar.visibility = View.VISIBLE - } - if (binding!!.gridview.visibility != View.INVISIBLE) { - binding!!.gridview.visibility = View.INVISIBLE - } - if (binding!!.callStates.errorImageView.visibility != View.GONE) { - binding!!.callStates.errorImageView.visibility = View.GONE - } - } - } + private fun handleCallStateJoined() { + binding!!.callModeTextView.text = descriptionForCallType + if (isIncomingCallFromNotification) { + binding!!.callStates.callStateTextView.setText(R.string.nc_call_incoming) + } else { + binding!!.callStates.callStateTextView.setText(R.string.nc_call_ringing) + } + if (binding!!.callStates.callStateRelativeLayout.visibility != View.VISIBLE) { + binding!!.callStates.callStateRelativeLayout.visibility = View.VISIBLE + } + if (binding!!.callStates.callStateProgressBar.visibility != View.VISIBLE) { + binding!!.callStates.callStateProgressBar.visibility = View.VISIBLE + } + if (binding!!.gridview.visibility != View.INVISIBLE) { + binding!!.gridview.visibility = View.INVISIBLE + } + if (binding!!.callStates.errorImageView.visibility != View.GONE) { + binding!!.callStates.errorImageView.visibility = View.GONE + } + } - CallStatus.IN_CONVERSATION -> handler!!.post { - stopCallingSound() - binding!!.callModeTextView.text = descriptionForCallType - if (!isVoiceOnlyCall) { - binding!!.callInfosLinearLayout.visibility = View.GONE - } - if (!isPushToTalkActive) { - animateCallControls(false, FIVE_SECONDS) - } - if (binding!!.callStates.callStateRelativeLayout.visibility != View.INVISIBLE) { - binding!!.callStates.callStateRelativeLayout.visibility = View.INVISIBLE - } - if (binding!!.callStates.callStateProgressBar.visibility != View.GONE) { - binding!!.callStates.callStateProgressBar.visibility = View.GONE - } - if (binding!!.gridview.visibility != View.VISIBLE) { - binding!!.gridview.visibility = View.VISIBLE - } - if (binding!!.callStates.errorImageView.visibility != View.GONE) { - binding!!.callStates.errorImageView.visibility = View.GONE - } - } + private fun handleCallStateReconnecting() { + playCallingSound() + binding!!.callStates.callStateTextView.setText(R.string.nc_call_reconnecting) + binding!!.callModeTextView.text = descriptionForCallType + if (binding!!.callStates.callStateRelativeLayout.visibility != View.VISIBLE) { + binding!!.callStates.callStateRelativeLayout.visibility = View.VISIBLE + } + if (binding!!.gridview.visibility != View.INVISIBLE) { + binding!!.gridview.visibility = View.INVISIBLE + } + if (binding!!.callStates.callStateProgressBar.visibility != View.VISIBLE) { + binding!!.callStates.callStateProgressBar.visibility = View.VISIBLE + } + if (binding!!.callStates.errorImageView.visibility != View.GONE) { + binding!!.callStates.errorImageView.visibility = View.GONE + } + } - CallStatus.OFFLINE -> handler!!.post { - stopCallingSound() - binding!!.callStates.callStateTextView.setText(R.string.nc_offline) - if (binding!!.callStates.callStateRelativeLayout.visibility != View.VISIBLE) { - binding!!.callStates.callStateRelativeLayout.visibility = View.VISIBLE - } - if (binding!!.gridview.visibility != View.INVISIBLE) { - binding!!.gridview.visibility = View.INVISIBLE - } - if (binding!!.callStates.callStateProgressBar.visibility != View.GONE) { - binding!!.callStates.callStateProgressBar.visibility = View.GONE - } - binding!!.callStates.errorImageView.setImageResource(R.drawable.ic_signal_wifi_off_white_24dp) - if (binding!!.callStates.errorImageView.visibility != View.VISIBLE) { - binding!!.callStates.errorImageView.visibility = View.VISIBLE - } - } + private fun handleCallStatePublisherFailed() { + // No calling sound when the publisher failed + binding!!.callStates.callStateTextView.setText(R.string.nc_call_reconnecting) + binding!!.callModeTextView.text = descriptionForCallType + if (binding!!.callStates.callStateRelativeLayout.visibility != View.VISIBLE) { + binding!!.callStates.callStateRelativeLayout.visibility = View.VISIBLE + } + if (binding!!.gridview.visibility != View.INVISIBLE) { + binding!!.gridview.visibility = View.INVISIBLE + } + if (binding!!.callStates.callStateProgressBar.visibility != View.VISIBLE) { + binding!!.callStates.callStateProgressBar.visibility = View.VISIBLE + } + if (binding!!.callStates.errorImageView.visibility != View.GONE) { + binding!!.callStates.errorImageView.visibility = View.GONE + } + } - CallStatus.LEAVING -> handler!!.post { - if (!isDestroyed) { - stopCallingSound() - binding!!.callModeTextView.text = descriptionForCallType - binding!!.callStates.callStateTextView.setText(R.string.nc_leaving_call) - binding!!.callStates.callStateRelativeLayout.visibility = View.VISIBLE - binding!!.gridview.visibility = View.INVISIBLE - binding!!.callStates.callStateProgressBar.visibility = View.VISIBLE - binding!!.callStates.errorImageView.visibility = View.GONE - } - } - } + private fun handleCallStateCallingTimeout() { + hangup(shutDownView = false, endCallForAll = false) + binding!!.callStates.callStateTextView.setText(R.string.nc_call_timeout) + binding!!.callModeTextView.text = descriptionForCallType + if (binding!!.callStates.callStateRelativeLayout.visibility != View.VISIBLE) { + binding!!.callStates.callStateRelativeLayout.visibility = View.VISIBLE + } + if (binding!!.callStates.callStateProgressBar.visibility != View.GONE) { + binding!!.callStates.callStateProgressBar.visibility = View.GONE + } + if (binding!!.gridview.visibility != View.INVISIBLE) { + binding!!.gridview.visibility = View.INVISIBLE + } + binding!!.callStates.errorImageView.setImageResource(R.drawable.ic_av_timer_timer_24dp) + if (binding!!.callStates.errorImageView.visibility != View.VISIBLE) { + binding!!.callStates.errorImageView.visibility = View.VISIBLE + } + } + + private fun handleCallStateConnected() { + playCallingSound() + if (isIncomingCallFromNotification) { + binding!!.callStates.callStateTextView.setText(R.string.nc_call_incoming) + } else { + binding!!.callStates.callStateTextView.setText(R.string.nc_call_ringing) + } + binding!!.callConversationNameTextView.text = conversationName + binding!!.callModeTextView.text = descriptionForCallType + if (binding!!.callStates.callStateRelativeLayout.visibility != View.VISIBLE) { + binding!!.callStates.callStateRelativeLayout.visibility = View.VISIBLE + } + if (binding!!.gridview.visibility != View.INVISIBLE) { + binding!!.gridview.visibility = View.INVISIBLE + } + if (binding!!.callStates.callStateProgressBar.visibility != View.VISIBLE) { + binding!!.callStates.callStateProgressBar.visibility = View.VISIBLE + } + if (binding!!.callStates.errorImageView.visibility != View.GONE) { + binding!!.callStates.errorImageView.visibility = View.GONE } } diff --git a/app/src/main/java/com/nextcloud/talk/adapters/items/ContactItem.kt b/app/src/main/java/com/nextcloud/talk/adapters/items/ContactItem.kt index 1d261e6d60..018ad0f6a1 100644 --- a/app/src/main/java/com/nextcloud/talk/adapters/items/ContactItem.kt +++ b/app/src/main/java/com/nextcloud/talk/adapters/items/ContactItem.kt @@ -132,6 +132,10 @@ class ContactItem( holder?.binding?.nameText?.text = sharedApplication!!.getString(R.string.nc_guest) } + setAvatar(holder) + } + + private fun setAvatar(holder: ContactItemViewHolder?) { if (model.calculatedActorType == Participant.ActorType.GROUPS || model.calculatedActorType == Participant.ActorType.CIRCLES ) { diff --git a/app/src/main/java/com/nextcloud/talk/adapters/items/MentionAutocompleteItem.kt b/app/src/main/java/com/nextcloud/talk/adapters/items/MentionAutocompleteItem.kt index ec5587efa9..8bf3bf0fa7 100644 --- a/app/src/main/java/com/nextcloud/talk/adapters/items/MentionAutocompleteItem.kt +++ b/app/src/main/java/com/nextcloud/talk/adapters/items/MentionAutocompleteItem.kt @@ -120,7 +120,11 @@ class MentionAutocompleteItem( } else { holder.binding.nameText.text = displayName } - var avatarId = objectId + setAvatar(holder, objectId) + drawStatus(holder) + } + + private fun setAvatar(holder: ParticipantItemViewHolder, objectId: String?) { when (source) { SOURCE_CALLS -> { run {} @@ -136,10 +140,7 @@ class MentionAutocompleteItem( SOURCE_GROUPS -> { holder.binding.avatarView.loadUserAvatar( - viewThemeUtils.talk.themePlaceholderAvatar( - holder.binding.avatarView, - R.drawable.ic_avatar_group - ) + viewThemeUtils.talk.themePlaceholderAvatar(holder.binding.avatarView, R.drawable.ic_avatar_group) ) } @@ -149,27 +150,30 @@ class MentionAutocompleteItem( currentUser, currentUser.baseUrl!!, roomToken, - avatarId!!, + objectId!!, darkTheme, - true, - false + requestBigSize = true, + ignoreCache = false ) } SOURCE_GUESTS, SOURCE_EMAILS -> { - avatarId = displayName if (displayName.equals(context.resources.getString(R.string.nc_guest))) { holder.binding.avatarView.loadDefaultAvatar(viewThemeUtils) } else { - holder.binding.avatarView.loadGuestAvatar(currentUser, avatarId!!, false) + holder.binding.avatarView.loadGuestAvatar(currentUser, displayName!!, false) } } else -> { - holder.binding.avatarView.loadUserAvatar(currentUser, avatarId!!, true, false) + holder.binding.avatarView.loadUserAvatar( + currentUser, + objectId!!, + requestBigSize = true, + ignoreCache = false + ) } } - drawStatus(holder) } private fun drawStatus(holder: ParticipantItemViewHolder) { diff --git a/app/src/main/java/com/nextcloud/talk/adapters/messages/IncomingDeckCardViewHolder.kt b/app/src/main/java/com/nextcloud/talk/adapters/messages/IncomingDeckCardViewHolder.kt index 46cf1847f6..b16eb217a5 100644 --- a/app/src/main/java/com/nextcloud/talk/adapters/messages/IncomingDeckCardViewHolder.kt +++ b/app/src/main/java/com/nextcloud/talk/adapters/messages/IncomingDeckCardViewHolder.kt @@ -224,14 +224,11 @@ class IncomingDeckCardViewHolder(incomingView: View, payload: Any) : MessageHold binding.messageQuote.quotedMessageAuthor .setTextColor(ContextCompat.getColor(context, R.color.textColorMaxContrast)) - if (parentChatMessage.actorId?.equals(message.activeUser!!.userId) == true) { - viewThemeUtils.platform.colorViewBackground( - binding.messageQuote.quoteColoredView, - ColorRole.PRIMARY - ) - } else { - binding.messageQuote.quoteColoredView.setBackgroundResource(R.color.textColorMaxContrast) - } + viewThemeUtils.talk.themeParentMessage( + parentChatMessage, + message, + binding.messageQuote.quoteColoredView + ) binding.messageQuote.quotedChatMessageView.visibility = View.VISIBLE } catch (e: Exception) { diff --git a/app/src/main/java/com/nextcloud/talk/adapters/messages/IncomingLinkPreviewMessageViewHolder.kt b/app/src/main/java/com/nextcloud/talk/adapters/messages/IncomingLinkPreviewMessageViewHolder.kt index abcec3c31d..b199317267 100644 --- a/app/src/main/java/com/nextcloud/talk/adapters/messages/IncomingLinkPreviewMessageViewHolder.kt +++ b/app/src/main/java/com/nextcloud/talk/adapters/messages/IncomingLinkPreviewMessageViewHolder.kt @@ -14,7 +14,6 @@ import android.view.View import androidx.core.content.ContextCompat import autodagger.AutoInjector import coil.load -import com.nextcloud.android.common.ui.theme.utils.ColorRole import com.nextcloud.talk.R import com.nextcloud.talk.api.NcApi import com.nextcloud.talk.application.NextcloudTalkApplication @@ -202,14 +201,11 @@ class IncomingLinkPreviewMessageViewHolder(incomingView: View, payload: Any) : binding.messageQuote.quotedMessageAuthor .setTextColor(ContextCompat.getColor(context, R.color.textColorMaxContrast)) - if (parentChatMessage.actorId?.equals(message.activeUser!!.userId) == true) { - viewThemeUtils.platform.colorViewBackground( - binding.messageQuote.quoteColoredView, - ColorRole.PRIMARY - ) - } else { - binding.messageQuote.quoteColoredView.setBackgroundResource(R.color.textColorMaxContrast) - } + viewThemeUtils.talk.themeParentMessage( + parentChatMessage, + message, + binding.messageQuote.quoteColoredView + ) binding.messageQuote.quotedChatMessageView.visibility = View.VISIBLE } catch (e: Exception) { diff --git a/app/src/main/java/com/nextcloud/talk/adapters/messages/IncomingLocationMessageViewHolder.kt b/app/src/main/java/com/nextcloud/talk/adapters/messages/IncomingLocationMessageViewHolder.kt index a03fd98a7d..d90badf038 100644 --- a/app/src/main/java/com/nextcloud/talk/adapters/messages/IncomingLocationMessageViewHolder.kt +++ b/app/src/main/java/com/nextcloud/talk/adapters/messages/IncomingLocationMessageViewHolder.kt @@ -22,7 +22,6 @@ import android.webkit.WebViewClient import autodagger.AutoInjector import coil.load import com.google.android.material.snackbar.Snackbar -import com.nextcloud.android.common.ui.theme.utils.ColorRole import com.nextcloud.talk.R import com.nextcloud.talk.application.NextcloudTalkApplication import com.nextcloud.talk.application.NextcloudTalkApplication.Companion.sharedApplication @@ -187,14 +186,11 @@ class IncomingLocationMessageViewHolder(incomingView: View, payload: Any) : binding.messageQuote.quotedMessageAuthor .setTextColor(context.resources.getColor(R.color.textColorMaxContrast, null)) - if (parentChatMessage.actorId?.equals(message.activeUser!!.userId) == true) { - viewThemeUtils.platform.colorViewBackground( - binding.messageQuote.quoteColoredView, - ColorRole.PRIMARY - ) - } else { - binding.messageQuote.quoteColoredView.setBackgroundResource(R.color.textColorMaxContrast) - } + viewThemeUtils.talk.themeParentMessage( + parentChatMessage, + message, + binding.messageQuote.quoteColoredView + ) binding.messageQuote.quotedChatMessageView.visibility = View.VISIBLE } catch (e: Exception) { diff --git a/app/src/main/java/com/nextcloud/talk/adapters/messages/IncomingPollMessageViewHolder.kt b/app/src/main/java/com/nextcloud/talk/adapters/messages/IncomingPollMessageViewHolder.kt index 997184a8fd..60d0785795 100644 --- a/app/src/main/java/com/nextcloud/talk/adapters/messages/IncomingPollMessageViewHolder.kt +++ b/app/src/main/java/com/nextcloud/talk/adapters/messages/IncomingPollMessageViewHolder.kt @@ -13,7 +13,6 @@ import android.view.View import androidx.core.content.ContextCompat import autodagger.AutoInjector import coil.load -import com.nextcloud.android.common.ui.theme.utils.ColorRole import com.nextcloud.talk.R import com.nextcloud.talk.api.NcApi import com.nextcloud.talk.application.NextcloudTalkApplication @@ -209,14 +208,11 @@ class IncomingPollMessageViewHolder(incomingView: View, payload: Any) : binding.messageQuote.quotedMessageAuthor .setTextColor(ContextCompat.getColor(context, R.color.textColorMaxContrast)) - if (parentChatMessage.actorId?.equals(message.activeUser!!.userId) == true) { - viewThemeUtils.platform.colorViewBackground( - binding.messageQuote.quoteColoredView, - ColorRole.PRIMARY - ) - } else { - binding.messageQuote.quoteColoredView.setBackgroundResource(R.color.textColorMaxContrast) - } + viewThemeUtils.talk.themeParentMessage( + parentChatMessage, + message, + binding.messageQuote.quoteColoredView + ) binding.messageQuote.quotedChatMessageView.visibility = View.VISIBLE } catch (e: Exception) { Log.d(TAG, "Error when processing parent message in view holder", e) diff --git a/app/src/main/java/com/nextcloud/talk/adapters/messages/IncomingTextMessageViewHolder.kt b/app/src/main/java/com/nextcloud/talk/adapters/messages/IncomingTextMessageViewHolder.kt index e81ddf1120..b4883ffb21 100644 --- a/app/src/main/java/com/nextcloud/talk/adapters/messages/IncomingTextMessageViewHolder.kt +++ b/app/src/main/java/com/nextcloud/talk/adapters/messages/IncomingTextMessageViewHolder.kt @@ -13,10 +13,8 @@ import android.content.Context import android.util.Log import android.util.TypedValue import android.view.View -import androidx.core.content.ContextCompat import autodagger.AutoInjector import coil.load -import com.nextcloud.android.common.ui.theme.utils.ColorRole import com.nextcloud.talk.R import com.nextcloud.talk.application.NextcloudTalkApplication import com.nextcloud.talk.application.NextcloudTalkApplication.Companion.sharedApplication @@ -212,19 +210,12 @@ class IncomingTextMessageViewHolder(itemView: View, payload: Any) : viewThemeUtils ) - if (parentChatMessage.actorId?.equals(message.activeUser!!.userId) == true) { - viewThemeUtils.platform.colorViewBackground( - binding.messageQuote.quoteColoredView, - ColorRole.PRIMARY - ) - } else { - binding.messageQuote.quoteColoredView.setBackgroundColor( - ContextCompat.getColor( - binding.messageQuote.quoteColoredView.context, - R.color.high_emphasis_text - ) - ) - } + viewThemeUtils.talk.themeParentMessage( + parentChatMessage, + message, + binding.messageQuote.quoteColoredView, + R.color.high_emphasis_text + ) binding.messageQuote.quotedChatMessageView.setOnClickListener { val chatActivity = commonMessageInterface as ChatActivity diff --git a/app/src/main/java/com/nextcloud/talk/adapters/messages/IncomingVoiceMessageViewHolder.kt b/app/src/main/java/com/nextcloud/talk/adapters/messages/IncomingVoiceMessageViewHolder.kt index 5f9763a5d9..71aafcce62 100644 --- a/app/src/main/java/com/nextcloud/talk/adapters/messages/IncomingVoiceMessageViewHolder.kt +++ b/app/src/main/java/com/nextcloud/talk/adapters/messages/IncomingVoiceMessageViewHolder.kt @@ -119,15 +119,7 @@ class IncomingVoiceMessageViewHolder(incomingView: View, payload: Any) : } if (message.resetVoiceMessage) { - binding.playPauseBtn.visibility = View.VISIBLE - binding.playPauseBtn.icon = ContextCompat.getDrawable( - context!!, - R.drawable.ic_baseline_play_arrow_voice_message_24 - ) - binding.seekbar.progress = SEEKBAR_START - message.resetVoiceMessage = false - message.voiceMessagePlayedSeconds = 0 - binding.voiceMessageDuration.visibility = View.INVISIBLE + resetVoiceMessage(message) } binding.seekbar.setOnSeekBarChangeListener(object : SeekBar.OnSeekBarChangeListener { @@ -163,6 +155,18 @@ class IncomingVoiceMessageViewHolder(incomingView: View, payload: Any) : isBound = true } + private fun resetVoiceMessage(chatMessage: ChatMessage) { + binding.playPauseBtn.visibility = View.VISIBLE + binding.playPauseBtn.icon = ContextCompat.getDrawable( + context!!, + R.drawable.ic_baseline_play_arrow_voice_message_24 + ) + binding.seekbar.progress = SEEKBAR_START + chatMessage.resetVoiceMessage = false + chatMessage.voiceMessagePlayedSeconds = 0 + binding.voiceMessageDuration.visibility = View.INVISIBLE + } + private fun longClickOnReaction(chatMessage: ChatMessage) { commonMessageInterface.onLongClickReactions(chatMessage) } @@ -322,14 +326,11 @@ class IncomingVoiceMessageViewHolder(incomingView: View, payload: Any) : binding.messageQuote.quotedMessageAuthor .setTextColor(ContextCompat.getColor(context!!, R.color.textColorMaxContrast)) - if (parentChatMessage.actorId?.equals(message.activeUser!!.userId) == true) { - viewThemeUtils.platform.colorViewBackground( - binding.messageQuote.quoteColoredView, - ColorRole.PRIMARY - ) - } else { - binding.messageQuote.quoteColoredView.setBackgroundResource(R.color.textColorMaxContrast) - } + viewThemeUtils.talk.themeParentMessage( + parentChatMessage, + message, + binding.messageQuote.quoteColoredView + ) binding.messageQuote.quotedChatMessageView.visibility = View.VISIBLE } catch (e: Exception) { diff --git a/app/src/main/java/com/nextcloud/talk/adapters/messages/OutcomingDeckCardViewHolder.kt b/app/src/main/java/com/nextcloud/talk/adapters/messages/OutcomingDeckCardViewHolder.kt index afb9058ac1..c6c355e92e 100644 --- a/app/src/main/java/com/nextcloud/talk/adapters/messages/OutcomingDeckCardViewHolder.kt +++ b/app/src/main/java/com/nextcloud/talk/adapters/messages/OutcomingDeckCardViewHolder.kt @@ -215,14 +215,11 @@ class OutcomingDeckCardViewHolder( binding.messageQuote.quotedMessageAuthor .setTextColor(ContextCompat.getColor(context, R.color.textColorMaxContrast)) - if (parentChatMessage.actorId?.equals(message.activeUser!!.userId) == true) { - viewThemeUtils.platform.colorViewBackground( - binding.messageQuote.quoteColoredView, - ColorRole.PRIMARY - ) - } else { - binding.messageQuote.quoteColoredView.setBackgroundResource(R.color.textColorMaxContrast) - } + viewThemeUtils.talk.themeParentMessage( + parentChatMessage, + message, + binding.messageQuote.quoteColoredView + ) binding.messageQuote.quotedChatMessageView.visibility = View.VISIBLE } catch (e: Exception) { diff --git a/app/src/main/java/com/nextcloud/talk/data/source/local/Migrations.kt b/app/src/main/java/com/nextcloud/talk/data/source/local/Migrations.kt index b23e99fd47..3e61f699d9 100644 --- a/app/src/main/java/com/nextcloud/talk/data/source/local/Migrations.kt +++ b/app/src/main/java/com/nextcloud/talk/data/source/local/Migrations.kt @@ -127,6 +127,7 @@ object Migrations { db.execSQL("ALTER TABLE ArbitraryStorage_dualPK RENAME TO ArbitraryStorage") } + @Suppress("Detekt.LongMethod") fun migrateToOfflineSupport(db: SupportSQLiteDatabase) { db.execSQL( "CREATE TABLE IF NOT EXISTS Conversations (" + diff --git a/app/src/main/java/com/nextcloud/talk/diagnose/DiagnoseActivity.kt b/app/src/main/java/com/nextcloud/talk/diagnose/DiagnoseActivity.kt index 68e69dc65d..6601b3a4e0 100644 --- a/app/src/main/java/com/nextcloud/talk/diagnose/DiagnoseActivity.kt +++ b/app/src/main/java/com/nextcloud/talk/diagnose/DiagnoseActivity.kt @@ -238,67 +238,71 @@ class DiagnoseActivity : BaseActivity() { addValue(BuildConfig.FLAVOR) if (isGooglePlayServicesAvailable) { - addKey(context.resources.getString(R.string.nc_diagnose_battery_optimization_title)) + setupAppValuesForGooglePlayServices() + } - if (PowerManagerUtils().isIgnoringBatteryOptimizations()) { - addValue(context.resources.getString(R.string.nc_diagnose_battery_optimization_ignored)) - } else { - addValue(context.resources.getString(R.string.nc_diagnose_battery_optimization_not_ignored)) - } + addKey(context.resources.getString(R.string.nc_diagnose_app_users_amount)) + addValue(userManager.users.blockingGet().size.toString()) + } - // handle notification permission on API level >= 33 - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) { - addKey(context.resources.getString(R.string.nc_diagnose_notification_permission)) - if (platformPermissionUtil.isPostNotificationsPermissionGranted()) { - addValue(context.resources.getString(R.string.nc_settings_notifications_granted)) - } else { - addValue(context.resources.getString(R.string.nc_settings_notifications_declined)) - } + private fun setupAppValuesForGooglePlayServices() { + addKey(context.resources.getString(R.string.nc_diagnose_battery_optimization_title)) + + if (PowerManagerUtils().isIgnoringBatteryOptimizations()) { + addValue(context.resources.getString(R.string.nc_diagnose_battery_optimization_ignored)) + } else { + addValue(context.resources.getString(R.string.nc_diagnose_battery_optimization_not_ignored)) + } + + // handle notification permission on API level >= 33 + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) { + addKey(context.resources.getString(R.string.nc_diagnose_notification_permission)) + if (platformPermissionUtil.isPostNotificationsPermissionGranted()) { + addValue(context.resources.getString(R.string.nc_settings_notifications_granted)) + } else { + addValue(context.resources.getString(R.string.nc_settings_notifications_declined)) } + } - addKey(context.resources.getString(R.string.nc_diagnose_notification_calls_channel_permission)) - addValue( - translateBoolean( - NotificationUtils.isCallsNotificationChannelEnabled(this) - ) + addKey(context.resources.getString(R.string.nc_diagnose_notification_calls_channel_permission)) + addValue( + translateBoolean( + NotificationUtils.isCallsNotificationChannelEnabled(this) ) + ) - addKey(context.resources.getString(R.string.nc_diagnose_notification_messages_channel_permission)) - addValue( - translateBoolean( - NotificationUtils.isMessagesNotificationChannelEnabled(this) - ) + addKey(context.resources.getString(R.string.nc_diagnose_notification_messages_channel_permission)) + addValue( + translateBoolean( + NotificationUtils.isMessagesNotificationChannelEnabled(this) ) + ) - addKey(context.resources.getString(R.string.nc_diagnose_firebase_push_token_title)) - if (appPreferences.pushToken.isNullOrEmpty()) { - addValue(context.resources.getString(R.string.nc_diagnose_firebase_push_token_missing)) - } else { - addValue("${appPreferences.pushToken.substring(0, 5)}...") - } + addKey(context.resources.getString(R.string.nc_diagnose_firebase_push_token_title)) + if (appPreferences.pushToken.isNullOrEmpty()) { + addValue(context.resources.getString(R.string.nc_diagnose_firebase_push_token_missing)) + } else { + addValue("${appPreferences.pushToken.substring(0, 5)}...") + } - addKey(context.resources.getString(R.string.nc_diagnose_firebase_push_token_latest_generated)) - if (appPreferences.pushTokenLatestGeneration != null && appPreferences.pushTokenLatestGeneration != 0L) { - addValue( - DisplayUtils.unixTimeToHumanReadable( - appPreferences - .pushTokenLatestGeneration - ) + addKey(context.resources.getString(R.string.nc_diagnose_firebase_push_token_latest_generated)) + if (appPreferences.pushTokenLatestGeneration != null && appPreferences.pushTokenLatestGeneration != 0L) { + addValue( + DisplayUtils.unixTimeToHumanReadable( + appPreferences + .pushTokenLatestGeneration ) - } else { - addValue(context.resources.getString(R.string.nc_common_unknown)) - } - - addKey(context.resources.getString(R.string.nc_diagnose_firebase_push_token_latest_fetch)) - if (appPreferences.pushTokenLatestFetch != null && appPreferences.pushTokenLatestFetch != 0L) { - addValue(DisplayUtils.unixTimeToHumanReadable(appPreferences.pushTokenLatestFetch)) - } else { - addValue(context.resources.getString(R.string.nc_common_unknown)) - } + ) + } else { + addValue(context.resources.getString(R.string.nc_common_unknown)) } - addKey(context.resources.getString(R.string.nc_diagnose_app_users_amount)) - addValue(userManager.users.blockingGet().size.toString()) + addKey(context.resources.getString(R.string.nc_diagnose_firebase_push_token_latest_fetch)) + if (appPreferences.pushTokenLatestFetch != null && appPreferences.pushTokenLatestFetch != 0L) { + addValue(DisplayUtils.unixTimeToHumanReadable(appPreferences.pushTokenLatestFetch)) + } else { + addValue(context.resources.getString(R.string.nc_common_unknown)) + } } private fun setupAccountValues() { diff --git a/app/src/main/java/com/nextcloud/talk/jobs/SaveFileToStorageWorker.kt b/app/src/main/java/com/nextcloud/talk/jobs/SaveFileToStorageWorker.kt index cb6e08cc7d..cacbdc84a5 100644 --- a/app/src/main/java/com/nextcloud/talk/jobs/SaveFileToStorageWorker.kt +++ b/app/src/main/java/com/nextcloud/talk/jobs/SaveFileToStorageWorker.kt @@ -39,16 +39,13 @@ class SaveFileToStorageWorker(val context: Context, workerParameters: WorkerPara @Suppress("Detekt.TooGenericExceptionCaught") override fun doWork(): Result { try { - val sourceFilePath = inputData.getString(KEY_SOURCE_FILE_PATH) - val cacheFile = File(sourceFilePath!!) - + val cacheFile = File(inputData.getString(KEY_SOURCE_FILE_PATH)!!) val contentResolver = context.contentResolver val mimeType = URLConnection.guessContentTypeFromName(cacheFile.name) - val appName = applicationContext.resources!!.getString(R.string.nc_app_product_name) - val values = ContentValues().apply { if (mimeType.startsWith(IMAGE_PREFIX) || mimeType.startsWith(VIDEO_PREFIX)) { + val appName = applicationContext.resources!!.getString(R.string.nc_app_product_name) put(FileColumns.RELATIVE_PATH, Environment.DIRECTORY_DCIM + "/" + appName) } put(FileColumns.DISPLAY_NAME, cacheFile.name) @@ -58,11 +55,7 @@ class SaveFileToStorageWorker(val context: Context, workerParameters: WorkerPara } } - val collectionUri = getUriByType(mimeType) - - val uri = contentResolver.insert(collectionUri, values) - - uri?.let { fileUri -> + contentResolver.insert(getUriByType(mimeType), values)?.let { fileUri -> try { val outputStream: OutputStream? = contentResolver.openOutputStream(fileUri) outputStream.use { output -> diff --git a/app/src/main/java/com/nextcloud/talk/location/LocationPickerActivity.kt b/app/src/main/java/com/nextcloud/talk/location/LocationPickerActivity.kt index 9c7d721c71..4d4bb52415 100644 --- a/app/src/main/java/com/nextcloud/talk/location/LocationPickerActivity.kt +++ b/app/src/main/java/com/nextcloud/talk/location/LocationPickerActivity.kt @@ -241,7 +241,7 @@ class LocationPickerActivity : return true } - @Suppress("Detekt.TooGenericExceptionCaught", "Detekt.ComplexMethod") + @Suppress("Detekt.TooGenericExceptionCaught", "Detekt.ComplexMethod", "Detekt.LongMethod") private fun initMap() { binding.map.setTileSource(TileSourceFactory.MAPNIK) binding.map.onResume() diff --git a/app/src/main/java/com/nextcloud/talk/models/json/converters/EnumSystemMessageTypeConverter.kt b/app/src/main/java/com/nextcloud/talk/models/json/converters/EnumSystemMessageTypeConverter.kt index 962c7adda5..9613c8f825 100644 --- a/app/src/main/java/com/nextcloud/talk/models/json/converters/EnumSystemMessageTypeConverter.kt +++ b/app/src/main/java/com/nextcloud/talk/models/json/converters/EnumSystemMessageTypeConverter.kt @@ -77,6 +77,7 @@ import com.nextcloud.talk.chat.data.model.ChatMessage.SystemMessageType.USER_REM * */ class EnumSystemMessageTypeConverter : StringBasedTypeConverter() { + @Suppress("Detekt.LongMethod") override fun getFromString(string: String): ChatMessage.SystemMessageType { return when (string) { "conversation_created" -> CONVERSATION_CREATED @@ -144,7 +145,7 @@ class EnumSystemMessageTypeConverter : StringBasedTypeConverter "" diff --git a/app/src/main/java/com/nextcloud/talk/settings/SettingsActivity.kt b/app/src/main/java/com/nextcloud/talk/settings/SettingsActivity.kt index 0eae356889..cd4ec5c6f9 100644 --- a/app/src/main/java/com/nextcloud/talk/settings/SettingsActivity.kt +++ b/app/src/main/java/com/nextcloud/talk/settings/SettingsActivity.kt @@ -943,10 +943,6 @@ class SettingsActivity : binding.settingsShowNotificationWarning.visibility = View.GONE } - binding.settingsScreenSecuritySwitch.isChecked = appPreferences.isScreenSecured - - binding.settingsIncognitoKeyboardSwitch.isChecked = appPreferences.isKeyboardIncognito - if (CapabilitiesUtil.isReadStatusAvailable(currentUser!!.capabilities!!.spreedCapability!!)) { binding.settingsReadPrivacySwitch.isChecked = !CapabilitiesUtil.isReadStatusPrivate(currentUser!!) } else { @@ -954,15 +950,7 @@ class SettingsActivity : } setupTypingStatusSetting() - - binding.settingsPhoneBookIntegrationSwitch.isChecked = appPreferences.isPhoneBookIntegrationEnabled - - binding.settingsProxyUseCredentialsSwitch.isChecked = appPreferences.proxyCredentials - binding.settingsProxyUseCredentials.setOnClickListener { - val isChecked = binding.settingsProxyUseCredentialsSwitch.isChecked - binding.settingsProxyUseCredentialsSwitch.isChecked = !isChecked - appPreferences.setProxyNeedsCredentials(!isChecked) - } + setupProxyUseSetting() binding.settingsScreenLockSwitch.isChecked = appPreferences.isScreenLocked binding.settingsScreenLock.setOnClickListener { @@ -977,12 +965,31 @@ class SettingsActivity : appPreferences.setReadPrivacy(!isChecked) } + binding.settingsIncognitoKeyboardSwitch.isChecked = appPreferences.isKeyboardIncognito binding.settingsIncognitoKeyboard.setOnClickListener { val isChecked = binding.settingsIncognitoKeyboardSwitch.isChecked binding.settingsIncognitoKeyboardSwitch.isChecked = !isChecked appPreferences.setIncognitoKeyboard(!isChecked) } + setupPhoneBookIntegrationSetting() + + binding.settingsScreenSecuritySwitch.isChecked = appPreferences.isScreenSecured + binding.settingsScreenSecurity.setOnClickListener { + val isChecked = binding.settingsScreenSecuritySwitch.isChecked + binding.settingsScreenSecuritySwitch.isChecked = !isChecked + appPreferences.setScreenSecurity(!isChecked) + } + + binding.settingsTypingStatus.setOnClickListener { + val isChecked = binding.settingsTypingStatusSwitch.isChecked + binding.settingsTypingStatusSwitch.isChecked = !isChecked + appPreferences.setTypingStatus(!isChecked) + } + } + + private fun setupPhoneBookIntegrationSetting() { + binding.settingsPhoneBookIntegrationSwitch.isChecked = appPreferences.isPhoneBookIntegrationEnabled binding.settingsPhoneBookIntegration.setOnClickListener { val isChecked = binding.settingsPhoneBookIntegrationSwitch.isChecked binding.settingsPhoneBookIntegrationSwitch.isChecked = !isChecked @@ -995,17 +1002,14 @@ class SettingsActivity : deleteAll() } } + } - binding.settingsScreenSecurity.setOnClickListener { - val isChecked = binding.settingsScreenSecuritySwitch.isChecked - binding.settingsScreenSecuritySwitch.isChecked = !isChecked - appPreferences.setScreenSecurity(!isChecked) - } - - binding.settingsTypingStatus.setOnClickListener { - val isChecked = binding.settingsTypingStatusSwitch.isChecked - binding.settingsTypingStatusSwitch.isChecked = !isChecked - appPreferences.setTypingStatus(!isChecked) + private fun setupProxyUseSetting() { + binding.settingsProxyUseCredentialsSwitch.isChecked = appPreferences.proxyCredentials + binding.settingsProxyUseCredentials.setOnClickListener { + val isChecked = binding.settingsProxyUseCredentialsSwitch.isChecked + binding.settingsProxyUseCredentialsSwitch.isChecked = !isChecked + appPreferences.setProxyNeedsCredentials(!isChecked) } } diff --git a/app/src/main/java/com/nextcloud/talk/ui/dialog/MessageActionsDialog.kt b/app/src/main/java/com/nextcloud/talk/ui/dialog/MessageActionsDialog.kt index 34950bfcf9..3da80bd457 100644 --- a/app/src/main/java/com/nextcloud/talk/ui/dialog/MessageActionsDialog.kt +++ b/app/src/main/java/com/nextcloud/talk/ui/dialog/MessageActionsDialog.kt @@ -147,6 +147,10 @@ class MessageActionsDialog( } } + initMenuItems() + } + + private fun initMenuItems() { this.lifecycleScope.launch { initMenuItemTranslate( !message.isDeleted && diff --git a/app/src/main/java/com/nextcloud/talk/ui/theme/TalkSpecificViewThemeUtils.kt b/app/src/main/java/com/nextcloud/talk/ui/theme/TalkSpecificViewThemeUtils.kt index 2dede14966..87b1b3bdef 100644 --- a/app/src/main/java/com/nextcloud/talk/ui/theme/TalkSpecificViewThemeUtils.kt +++ b/app/src/main/java/com/nextcloud/talk/ui/theme/TalkSpecificViewThemeUtils.kt @@ -24,6 +24,7 @@ import android.widget.ImageView import android.widget.LinearLayout import android.widget.RelativeLayout import android.widget.TextView +import androidx.annotation.ColorRes import androidx.annotation.DrawableRes import androidx.appcompat.content.res.AppCompatResources import androidx.appcompat.widget.SearchView @@ -42,6 +43,7 @@ import com.nextcloud.android.common.ui.theme.ViewThemeUtilsBase import com.nextcloud.android.common.ui.theme.utils.AndroidXViewThemeUtils import com.nextcloud.android.common.ui.util.buildColorStateList import com.nextcloud.talk.R +import com.nextcloud.talk.chat.data.model.ChatMessage import com.nextcloud.talk.databinding.ReactionsInsideMessageBinding import com.nextcloud.talk.ui.MicInputCloud import com.nextcloud.talk.ui.StatusDrawable @@ -368,6 +370,21 @@ class TalkSpecificViewThemeUtils @Inject constructor( } } + fun themeParentMessage( + parentChatMessage: ChatMessage, + message: ChatMessage, + quoteColoredView: View, + @ColorRes quoteColorNonSelf: Int = R.color.textColorMaxContrast + ) { + withScheme(quoteColoredView) { scheme -> + if (parentChatMessage.actorId?.equals(message.activeUser!!.userId) == true) { + quoteColoredView.setBackgroundColor(dynamicColor.primary().getArgb(scheme)) + } else { + quoteColoredView.setBackgroundResource(quoteColorNonSelf) + } + } + } + fun getTextColor(isOutgoingMessage: Boolean, isSelfReaction: Boolean, binding: ReactionsInsideMessageBinding): Int { return withScheme(binding.root) { scheme -> return@withScheme if (!isOutgoingMessage || isSelfReaction) { diff --git a/app/src/main/java/com/nextcloud/talk/utils/preferences/preferencestorage/DatabaseStorageModule.kt b/app/src/main/java/com/nextcloud/talk/utils/preferences/preferencestorage/DatabaseStorageModule.kt index 17b2be7009..1bfe577f77 100644 --- a/app/src/main/java/com/nextcloud/talk/utils/preferences/preferencestorage/DatabaseStorageModule.kt +++ b/app/src/main/java/com/nextcloud/talk/utils/preferences/preferencestorage/DatabaseStorageModule.kt @@ -102,11 +102,7 @@ class DatabaseStorageModule(conversationUser: User, conversationToken: String) { withContext(Dispatchers.IO) { ncApiCoroutines!!.setMessageExpiration( getCredentials(conversationUser.username, conversationUser.token)!!, - getUrlForMessageExpiration( - apiVersion, - conversationUser.baseUrl, - conversationToken - ), + getUrlForMessageExpiration(apiVersion, conversationUser.baseUrl, conversationToken), valueInt ) messageExpiration = valueInt @@ -132,10 +128,7 @@ class DatabaseStorageModule(conversationUser: User, conversationToken: String) { val apiVersion = getConversationApiVersion(conversationUser, intArrayOf(ApiUtils.API_V4, 1)) withContext(Dispatchers.IO) { ncApiCoroutines!!.setNotificationLevel( - getCredentials( - conversationUser.username, - conversationUser.token - )!!, + getCredentials(conversationUser.username, conversationUser.token)!!, getUrlForRoomNotificationLevel( apiVersion, conversationUser.baseUrl, diff --git a/app/src/test/java/com/nextcloud/talk/json/ConversationConversionTest.kt b/app/src/test/java/com/nextcloud/talk/json/ConversationConversionTest.kt index ff70557654..6c59409ee9 100644 --- a/app/src/test/java/com/nextcloud/talk/json/ConversationConversionTest.kt +++ b/app/src/test/java/com/nextcloud/talk/json/ConversationConversionTest.kt @@ -69,58 +69,11 @@ class ConversationConversionTest( // check if default values are set for the fields when API_V1 is used if (apiVersion == 1) { - // default values for API_V2 fields - assertEquals(false, conversationEntity.canDeleteConversation) - assertEquals(true, conversationEntity.canLeaveConversation) - - // default values for API_V3 fields - assertEquals("", conversationEntity.description) - assertEquals("", conversationEntity.actorType) - assertEquals("", conversationEntity.actorId) - assertEquals(0, conversationEntity.callFlag) - assertEquals(0, conversationEntity.lastCommonReadMessage) - - // default values for API_V4 fields - assertEquals("", conversationEntity.avatarVersion) - assertEquals(0, conversationEntity.callStartTime) - assertEquals(0, conversationEntity.callRecording) - assertEquals(false, conversationEntity.unreadMentionDirect) - assertEquals("", conversationEntity.status) - assertEquals("", conversationEntity.statusIcon) - assertEquals("", conversationEntity.statusMessage) - assertEquals(null, conversationEntity.statusClearAt) - assertEquals("", conversationEntity.avatarVersion) - assertEquals(0, conversationEntity.callStartTime) - assertEquals(0, conversationEntity.callRecording) + checkConversationEntityV1(conversationEntity) } if (apiVersion >= 1) { - assertEquals("juwd77g6", conversationEntity.token) - assertEquals(ConversationEnums.ConversationType.ROOM_TYPE_ONE_TO_ONE_CALL, conversationEntity.type) - assertEquals("marcel", conversationEntity.name) - assertEquals("Marcel", conversationEntity.displayName) - assertEquals(Participant.ParticipantType.OWNER, conversationEntity.participantType) - assertEquals( - ConversationEnums.ConversationReadOnlyState.CONVERSATION_READ_WRITE, - conversationEntity.conversationReadOnlyState - ) - assertEquals(1727185155, conversationEntity.lastPing) - assertEquals("0", conversationEntity.sessionId) - assertEquals(false, conversationEntity.hasPassword) - assertEquals(false, conversationEntity.hasCall) - assertEquals(true, conversationEntity.canStartCall) - assertEquals(1727098966, conversationEntity.lastActivity) - assertEquals(false, conversationEntity.favorite) - assertEquals(ConversationEnums.NotificationLevel.ALWAYS, conversationEntity.notificationLevel) - assertEquals(ConversationEnums.LobbyState.LOBBY_STATE_ALL_PARTICIPANTS, conversationEntity.lobbyState) - assertEquals(0, conversationEntity.lobbyTimer) - assertEquals(0, conversationEntity.unreadMessages) - assertEquals(false, conversationEntity.unreadMention) - assertEquals(92320, conversationEntity.lastReadMessage) - assertNotNull(conversationEntity.lastMessage) - assertTrue(conversationEntity.lastMessage is String) - assertTrue(conversationEntity.lastMessage!!.contains("token")) - assertEquals(ConversationEnums.ObjectType.DEFAULT, conversationEntity.objectType) + checkConversationEntityLargerThanV1(conversationEntity) } if (apiVersion >= 2) { @@ -143,23 +96,82 @@ class ConversationConversionTest( } if (apiVersion >= 4) { - assertEquals("143a9df3", conversationEntity.avatarVersion) - assertEquals(0, conversationEntity.callStartTime) - assertEquals(0, conversationEntity.callRecording) - assertEquals(false, conversationEntity.unreadMentionDirect) - // assertEquals(, conversationEntity.breakoutRoomMode) // Not implemented - // assertEquals(, conversationEntity.breakoutRoomStatus) // Not implemented - assertEquals("away", conversationEntity.status) - assertEquals("👻", conversationEntity.statusIcon) - assertEquals("buuuuh", conversationEntity.statusMessage) - assertEquals(null, conversationEntity.statusClearAt) - assertEquals("143a9df3", conversationEntity.avatarVersion) - // assertEquals("", conversationEntity.isCustomAvatar) // Not implemented - assertEquals(0, conversationEntity.callStartTime) - assertEquals(0, conversationEntity.callRecording) - // assertEquals("", conversationEntity.recordingConsent) // Not implemented - // assertEquals("", conversationEntity.mentionPermissions) // Not implemented - // assertEquals("", conversationEntity.isArchived) // Not implemented + checkConversationEntityV4(conversationEntity) } } + + private fun checkConversationEntityLargerThanV1(conversationEntity: ConversationEntity) { + assertEquals("juwd77g6", conversationEntity.token) + assertEquals(ConversationEnums.ConversationType.ROOM_TYPE_ONE_TO_ONE_CALL, conversationEntity.type) + assertEquals("marcel", conversationEntity.name) + assertEquals("Marcel", conversationEntity.displayName) + assertEquals(Participant.ParticipantType.OWNER, conversationEntity.participantType) + assertEquals( + ConversationEnums.ConversationReadOnlyState.CONVERSATION_READ_WRITE, + conversationEntity.conversationReadOnlyState + ) + assertEquals(1727185155, conversationEntity.lastPing) + assertEquals("0", conversationEntity.sessionId) + assertEquals(false, conversationEntity.hasPassword) + assertEquals(false, conversationEntity.hasCall) + assertEquals(true, conversationEntity.canStartCall) + assertEquals(1727098966, conversationEntity.lastActivity) + assertEquals(false, conversationEntity.favorite) + assertEquals(ConversationEnums.NotificationLevel.ALWAYS, conversationEntity.notificationLevel) + assertEquals(ConversationEnums.LobbyState.LOBBY_STATE_ALL_PARTICIPANTS, conversationEntity.lobbyState) + assertEquals(0, conversationEntity.lobbyTimer) + assertEquals(0, conversationEntity.unreadMessages) + assertEquals(false, conversationEntity.unreadMention) + assertEquals(92320, conversationEntity.lastReadMessage) + assertNotNull(conversationEntity.lastMessage) + assertTrue(conversationEntity.lastMessage is String) + assertTrue(conversationEntity.lastMessage!!.contains("token")) + assertEquals(ConversationEnums.ObjectType.DEFAULT, conversationEntity.objectType) + } + + private fun checkConversationEntityV4(conversationEntity: ConversationEntity) { + assertEquals("143a9df3", conversationEntity.avatarVersion) + assertEquals(0, conversationEntity.callStartTime) + assertEquals(0, conversationEntity.callRecording) + assertEquals(false, conversationEntity.unreadMentionDirect) + // assertEquals(, conversationEntity.breakoutRoomMode) // Not implemented + // assertEquals(, conversationEntity.breakoutRoomStatus) // Not implemented + assertEquals("away", conversationEntity.status) + assertEquals("👻", conversationEntity.statusIcon) + assertEquals("buuuuh", conversationEntity.statusMessage) + assertEquals(null, conversationEntity.statusClearAt) + assertEquals("143a9df3", conversationEntity.avatarVersion) + // assertEquals("", conversationEntity.isCustomAvatar) // Not implemented + assertEquals(0, conversationEntity.callStartTime) + assertEquals(0, conversationEntity.callRecording) + // assertEquals("", conversationEntity.recordingConsent) // Not implemented + // assertEquals("", conversationEntity.mentionPermissions) // Not implemented + // assertEquals("", conversationEntity.isArchived) // Not implemented + } + + private fun checkConversationEntityV1(conversationEntity: ConversationEntity) { + // default values for API_V2 fields + assertEquals(false, conversationEntity.canDeleteConversation) + assertEquals(true, conversationEntity.canLeaveConversation) + + // default values for API_V3 fields + assertEquals("", conversationEntity.description) + assertEquals("", conversationEntity.actorType) + assertEquals("", conversationEntity.actorId) + assertEquals(0, conversationEntity.callFlag) + assertEquals(0, conversationEntity.lastCommonReadMessage) + + // default values for API_V4 fields + assertEquals("", conversationEntity.avatarVersion) + assertEquals(0, conversationEntity.callStartTime) + assertEquals(0, conversationEntity.callRecording) + assertEquals(false, conversationEntity.unreadMentionDirect) + assertEquals("", conversationEntity.status) + assertEquals("", conversationEntity.statusIcon) + assertEquals("", conversationEntity.statusMessage) + assertEquals(null, conversationEntity.statusClearAt) + assertEquals("", conversationEntity.avatarVersion) + assertEquals(0, conversationEntity.callStartTime) + assertEquals(0, conversationEntity.callRecording) + } } diff --git a/detekt.yml b/detekt.yml index 771890bf2c..225413717a 100644 --- a/detekt.yml +++ b/detekt.yml @@ -1,7 +1,7 @@ # SPDX-FileCopyrightText: 2017-2024 Nextcloud GmbH and Nextcloud contributors # SPDX-License-Identifier: GPL-3.0-or-later build: - maxIssues: 122 + maxIssues: 99 weights: # complexity: 2 # LongParameterList: 1 @@ -48,7 +48,7 @@ complexity: active: true ComplexCondition: active: true - threshold: 4 + threshold: 5 ComplexInterface: active: false threshold: 10