diff --git a/app/src/main/java/com/nextcloud/talk/account/AccountVerificationActivity.kt b/app/src/main/java/com/nextcloud/talk/account/AccountVerificationActivity.kt index 958c1f3ca..4f623c8f2 100644 --- a/app/src/main/java/com/nextcloud/talk/account/AccountVerificationActivity.kt +++ b/app/src/main/java/com/nextcloud/talk/account/AccountVerificationActivity.kt @@ -199,7 +199,7 @@ class AccountVerificationActivity : BaseActivity() { val credentials = ApiUtils.getCredentials(username, token) cookieManager.cookieStore.removeAll() - ncApi.getCapabilities(credentials, ApiUtils.getUrlForCapabilities(baseUrl)) + ncApi.getCapabilities(credentials, ApiUtils.getUrlForCapabilities(baseUrl!!)) .subscribeOn(Schedulers.io()) .subscribe(object : Observer { override fun onSubscribe(d: Disposable) { @@ -213,7 +213,7 @@ class AccountVerificationActivity : BaseActivity() { capabilitiesOverall.ocs!!.data!!.capabilities!!.spreedCapability!!.features != null && !capabilitiesOverall.ocs!!.data!!.capabilities!!.spreedCapability!!.features!!.isEmpty() if (hasTalk) { - fetchProfile(credentials, capabilitiesOverall) + fetchProfile(credentials!!, capabilitiesOverall) } else { if (resources != null) { runOnUiThread { @@ -305,7 +305,7 @@ class AccountVerificationActivity : BaseActivity() { private fun fetchProfile(credentials: String, capabilitiesOverall: CapabilitiesOverall) { ncApi.getUserProfile( credentials, - ApiUtils.getUrlForUserProfile(baseUrl) + ApiUtils.getUrlForUserProfile(baseUrl!!) ) .subscribeOn(Schedulers.io()) .subscribe(object : Observer { 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 fb7d2de7a..5869ac18f 100644 --- a/app/src/main/java/com/nextcloud/talk/account/ServerSelectionActivity.kt +++ b/app/src/main/java/com/nextcloud/talk/account/ServerSelectionActivity.kt @@ -52,7 +52,7 @@ import com.nextcloud.talk.utils.UriUtils import com.nextcloud.talk.utils.bundle.BundleKeys import com.nextcloud.talk.utils.bundle.BundleKeys.ADD_ADDITIONAL_ACCOUNT import com.nextcloud.talk.utils.bundle.BundleKeys.KEY_IS_ACCOUNT_IMPORT -import com.nextcloud.talk.utils.database.user.CapabilitiesUtilNew +import com.nextcloud.talk.utils.CapabilitiesUtil import com.nextcloud.talk.utils.singletons.ApplicationWideMessageHolder import io.reactivex.Observer import io.reactivex.android.schedulers.AndroidSchedulers @@ -336,7 +336,7 @@ class ServerSelectionActivity : BaseActivity() { if (hasTalk) { runOnUiThread { - if (CapabilitiesUtilNew.isServerEOL(capabilities)) { + if (CapabilitiesUtil.isServerEOL(capabilitiesOverall.ocs?.data?.serverVersion?.major!!)) { if (resources != null) { runOnUiThread { setErrorText(resources!!.getString(R.string.nc_settings_server_eol)) 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 b80cf974d..e0b599724 100644 --- a/app/src/main/java/com/nextcloud/talk/activities/CallActivity.kt +++ b/app/src/main/java/com/nextcloud/talk/activities/CallActivity.kt @@ -110,6 +110,7 @@ import com.nextcloud.talk.ui.dialog.AudioOutputDialog import com.nextcloud.talk.ui.dialog.MoreCallActionsDialog import com.nextcloud.talk.users.UserManager import com.nextcloud.talk.utils.ApiUtils +import com.nextcloud.talk.utils.SpreedFeatures import com.nextcloud.talk.utils.DisplayUtils import com.nextcloud.talk.utils.NotificationUtils.cancelExistingNotificationsForRoom import com.nextcloud.talk.utils.NotificationUtils.getCallRingtoneUri @@ -131,9 +132,9 @@ import com.nextcloud.talk.utils.bundle.BundleKeys.KEY_ROOM_ID import com.nextcloud.talk.utils.bundle.BundleKeys.KEY_ROOM_TOKEN import com.nextcloud.talk.utils.bundle.BundleKeys.KEY_START_CALL_AFTER_ROOM_SWITCH import com.nextcloud.talk.utils.bundle.BundleKeys.KEY_SWITCH_TO_ROOM -import com.nextcloud.talk.utils.database.user.CapabilitiesUtilNew -import com.nextcloud.talk.utils.database.user.CapabilitiesUtilNew.hasSpreedFeatureCapability -import com.nextcloud.talk.utils.database.user.CapabilitiesUtilNew.isCallRecordingAvailable +import com.nextcloud.talk.utils.CapabilitiesUtil +import com.nextcloud.talk.utils.CapabilitiesUtil.hasSpreedFeatureCapability +import com.nextcloud.talk.utils.CapabilitiesUtil.isCallRecordingAvailable import com.nextcloud.talk.utils.database.user.CurrentUserProviderNew import com.nextcloud.talk.utils.permissions.PlatformPermissionUtil import com.nextcloud.talk.utils.power.PowerManagerUtils @@ -234,7 +235,7 @@ class CallActivity : CallBaseActivity() { private var iceServers: MutableList? = null private var cameraEnumerator: CameraEnumerator? = null private var roomToken: String? = null - var conversationUser: User? = null + lateinit var conversationUser: User private var conversationName: String? = null private var callSession: String? = null private var localStream: MediaStream? = null @@ -530,13 +531,13 @@ class CallActivity : CallBaseActivity() { ) } - when (CapabilitiesUtilNew.getRecordingConsentType(conversationUser)) { - CapabilitiesUtilNew.RECORDING_CONSENT_NOT_REQUIRED -> initiateCall() - CapabilitiesUtilNew.RECORDING_CONSENT_REQUIRED -> askForRecordingConsent() - CapabilitiesUtilNew.RECORDING_CONSENT_DEPEND_ON_CONVERSATION -> { + when (CapabilitiesUtil.getRecordingConsentType(conversationUser!!.capabilities!!.spreedCapability!!)) { + CapabilitiesUtil.RECORDING_CONSENT_NOT_REQUIRED -> initiateCall() + CapabilitiesUtil.RECORDING_CONSENT_REQUIRED -> askForRecordingConsent() + CapabilitiesUtil.RECORDING_CONSENT_DEPEND_ON_CONVERSATION -> { val getRoomApiVersion = ApiUtils.getConversationApiVersion( - conversationUser, - intArrayOf(ApiUtils.APIv4, 1) + conversationUser!!, + intArrayOf(ApiUtils.API_V4, 1) ) ncApi!!.getRoom(credentials, ApiUtils.getUrlForRoom(getRoomApiVersion, baseUrl, roomToken)) .retry(API_RETRIES) @@ -571,7 +572,10 @@ class CallActivity : CallBaseActivity() { override fun onResume() { super.onResume() - if (hasSpreedFeatureCapability(conversationUser, "recording-v1") && + if (hasSpreedFeatureCapability( + conversationUser.capabilities!!.spreedCapability!!, + SpreedFeatures.RECORDING_V1 + ) && othersInCall && elapsedSeconds.toInt() >= CALL_TIME_ONE_HOUR ) { @@ -1468,7 +1472,7 @@ class CallActivity : CallBaseActivity() { private fun fetchSignalingSettings() { Log.d(TAG, "fetchSignalingSettings") - val apiVersion = ApiUtils.getSignalingApiVersion(conversationUser, intArrayOf(ApiUtils.APIv3, 2, 1)) + val apiVersion = ApiUtils.getSignalingApiVersion(conversationUser, intArrayOf(ApiUtils.API_V3, 2, 1)) ncApi!!.getSignalingSettings(credentials, ApiUtils.getUrlForSignalingSettings(apiVersion, baseUrl)) .subscribeOn(Schedulers.io()) .retry(API_RETRIES) @@ -1531,7 +1535,7 @@ class CallActivity : CallBaseActivity() { private fun addIceServers(signalingSettingsOverall: SignalingSettingsOverall, apiVersion: Int) { if (signalingSettingsOverall.ocs!!.settings!!.stunServers != null) { val stunServers = signalingSettingsOverall.ocs!!.settings!!.stunServers - if (apiVersion == ApiUtils.APIv3) { + if (apiVersion == ApiUtils.API_V3) { for ((_, urls) in stunServers!!) { if (urls != null) { for (url in urls) { @@ -1564,7 +1568,7 @@ class CallActivity : CallBaseActivity() { } private fun checkCapabilities() { - ncApi!!.getCapabilities(credentials, ApiUtils.getUrlForCapabilities(baseUrl)) + ncApi!!.getCapabilities(credentials, ApiUtils.getUrlForCapabilities(baseUrl!!)) .retry(API_RETRIES) .subscribeOn(Schedulers.io()) .observeOn(AndroidSchedulers.mainThread()) @@ -1600,7 +1604,7 @@ class CallActivity : CallBaseActivity() { private fun joinRoomAndCall() { callSession = ApplicationWideCurrentRoomHolder.getInstance().session - val apiVersion = ApiUtils.getConversationApiVersion(conversationUser, intArrayOf(ApiUtils.APIv4, 1)) + val apiVersion = ApiUtils.getConversationApiVersion(conversationUser, intArrayOf(ApiUtils.API_V4, 1)) Log.d(TAG, "joinRoomAndCall") Log.d(TAG, " baseUrl= $baseUrl") Log.d(TAG, " roomToken= $roomToken") @@ -1656,7 +1660,7 @@ class CallActivity : CallBaseActivity() { fun getRoomAndContinue() { val getRoomApiVersion = ApiUtils.getConversationApiVersion( conversationUser, - intArrayOf(ApiUtils.APIv4, 1) + intArrayOf(ApiUtils.API_V4, 1) ) ncApi!!.getRoom(credentials, ApiUtils.getUrlForRoom(getRoomApiVersion, baseUrl, roomToken)) .retry(API_RETRIES) @@ -1715,10 +1719,10 @@ class CallActivity : CallBaseActivity() { callParticipantList = CallParticipantList(signalingMessageReceiver) callParticipantList!!.addObserver(callParticipantListObserver) - val apiVersion = ApiUtils.getCallApiVersion(conversationUser, intArrayOf(ApiUtils.APIv4, 1)) + val apiVersion = ApiUtils.getCallApiVersion(conversationUser, intArrayOf(ApiUtils.API_V4, 1)) ncApi!!.joinCall( credentials, - ApiUtils.getUrlForCall(apiVersion, baseUrl, roomToken), + ApiUtils.getUrlForCall(apiVersion, baseUrl, roomToken!!), inCallFlag, isCallWithoutNotification, recordingConsentGiven @@ -1756,7 +1760,10 @@ class CallActivity : CallBaseActivity() { } private fun startCallTimeCounter(callStartTime: Long?) { - if (callStartTime != null && hasSpreedFeatureCapability(conversationUser, "recording-v1")) { + if (callStartTime != null && hasSpreedFeatureCapability( + conversationUser!!.capabilities!!.spreedCapability!!, SpreedFeatures.RECORDING_V1 + ) + ) { binding!!.callDuration.visibility = View.VISIBLE val currentTimeInSec = System.currentTimeMillis() / SECOND_IN_MILLIES elapsedSeconds = currentTimeInSec - callStartTime @@ -1793,7 +1800,7 @@ class CallActivity : CallBaseActivity() { } private fun pullSignalingMessages() { - val signalingApiVersion = ApiUtils.getSignalingApiVersion(conversationUser, intArrayOf(ApiUtils.APIv3, 2, 1)) + val signalingApiVersion = ApiUtils.getSignalingApiVersion(conversationUser, intArrayOf(ApiUtils.API_V3, 2, 1)) val delayOnError = AtomicInteger(0) ncApi!!.pullSignalingMessages( @@ -1801,7 +1808,7 @@ class CallActivity : CallBaseActivity() { ApiUtils.getUrlForSignaling( signalingApiVersion, baseUrl, - roomToken + roomToken!! ) ) .subscribeOn(Schedulers.io()) @@ -2031,12 +2038,12 @@ class CallActivity : CallBaseActivity() { private fun hangupNetworkCalls(shutDownView: Boolean) { Log.d(TAG, "hangupNetworkCalls. shutDownView=$shutDownView") - val apiVersion = ApiUtils.getCallApiVersion(conversationUser, intArrayOf(ApiUtils.APIv4, 1)) + val apiVersion = ApiUtils.getCallApiVersion(conversationUser, intArrayOf(ApiUtils.API_V4, 1)) if (callParticipantList != null) { callParticipantList!!.removeObserver(callParticipantListObserver) callParticipantList!!.destroy() } - ncApi!!.leaveCall(credentials, ApiUtils.getUrlForCall(apiVersion, baseUrl, roomToken)) + ncApi!!.leaveCall(credentials, ApiUtils.getUrlForCall(apiVersion, baseUrl, roomToken!!)) .subscribeOn(Schedulers.io()) .observeOn(AndroidSchedulers.mainThread()) .subscribe(object : Observer { @@ -2919,10 +2926,10 @@ class CallActivity : CallBaseActivity() { val strings: MutableList = ArrayList() val stringToSend = stringBuilder.toString() strings.add(stringToSend) - val apiVersion = ApiUtils.getSignalingApiVersion(conversationUser, intArrayOf(ApiUtils.APIv3, 2, 1)) + val apiVersion = ApiUtils.getSignalingApiVersion(conversationUser, intArrayOf(ApiUtils.API_V3, 2, 1)) ncApi!!.sendSignalingMessages( credentials, - ApiUtils.getUrlForSignaling(apiVersion, baseUrl, roomToken), + ApiUtils.getUrlForSignaling(apiVersion, baseUrl, roomToken!!), strings.toString() ) .retry(API_RETRIES) @@ -3099,12 +3106,14 @@ class CallActivity : CallBaseActivity() { val isAllowedToStartOrStopRecording: Boolean get() = ( - isCallRecordingAvailable(conversationUser!!) && + isCallRecordingAvailable(conversationUser!!.capabilities!!.spreedCapability!!) && isModerator ) val isAllowedToRaiseHand: Boolean - get() = hasSpreedFeatureCapability(conversationUser, "raise-hand") || - isBreakoutRoom + get() = hasSpreedFeatureCapability( + conversationUser.capabilities!!.spreedCapability!!, + SpreedFeatures.RAISE_HAND + ) || isBreakoutRoom private inner class SelfVideoTouchListener : OnTouchListener { @SuppressLint("ClickableViewAccessibility") diff --git a/app/src/main/java/com/nextcloud/talk/activities/MainActivity.kt b/app/src/main/java/com/nextcloud/talk/activities/MainActivity.kt index 81d918448..ecc2627ec 100644 --- a/app/src/main/java/com/nextcloud/talk/activities/MainActivity.kt +++ b/app/src/main/java/com/nextcloud/talk/activities/MainActivity.kt @@ -181,7 +181,7 @@ class MainActivity : BaseActivity(), ActionBarProvider { val user = userId.substringBeforeLast("@") val baseUrl = userId.substringAfterLast("@") - if (userManager.currentUser.blockingGet()?.baseUrl?.endsWith(baseUrl) == true) { + if (userManager.currentUser.blockingGet()?.baseUrl!!.endsWith(baseUrl) == true) { startConversation(user) } else { Snackbar.make( @@ -200,11 +200,11 @@ class MainActivity : BaseActivity(), ActionBarProvider { val currentUser = userManager.currentUser.blockingGet() - val apiVersion = ApiUtils.getConversationApiVersion(currentUser, intArrayOf(ApiUtils.APIv4, 1)) + val apiVersion = ApiUtils.getConversationApiVersion(currentUser, intArrayOf(ApiUtils.API_V4, 1)) val credentials = ApiUtils.getCredentials(currentUser?.username, currentUser?.token) val retrofitBucket = ApiUtils.getRetrofitBucketForCreateRoom( apiVersion, - currentUser?.baseUrl, + currentUser?.baseUrl!!, roomType, null, userId, diff --git a/app/src/main/java/com/nextcloud/talk/adapters/items/ConversationItem.kt b/app/src/main/java/com/nextcloud/talk/adapters/items/ConversationItem.kt index 3dbf39f16..399d1871a 100644 --- a/app/src/main/java/com/nextcloud/talk/adapters/items/ConversationItem.kt +++ b/app/src/main/java/com/nextcloud/talk/adapters/items/ConversationItem.kt @@ -50,9 +50,10 @@ import com.nextcloud.talk.models.json.conversations.Conversation import com.nextcloud.talk.models.json.conversations.Conversation.ConversationType import com.nextcloud.talk.ui.StatusDrawable import com.nextcloud.talk.ui.theme.ViewThemeUtils +import com.nextcloud.talk.utils.SpreedFeatures import com.nextcloud.talk.utils.ConversationUtils import com.nextcloud.talk.utils.DisplayUtils -import com.nextcloud.talk.utils.database.user.CapabilitiesUtilNew.hasSpreedFeatureCapability +import com.nextcloud.talk.utils.CapabilitiesUtil.hasSpreedFeatureCapability import eu.davidea.flexibleadapter.FlexibleAdapter import eu.davidea.flexibleadapter.items.AbstractFlexibleItem import eu.davidea.flexibleadapter.items.IFilterable @@ -312,7 +313,7 @@ class ConversationItem( if (model.type === ConversationType.ROOM_TYPE_ONE_TO_ONE_CALL) { viewThemeUtils.material.colorChipBackground(holder.binding.dialogUnreadBubble) } else if (model.unreadMention) { - if (hasSpreedFeatureCapability(user, "direct-mention-flag")) { + if (hasSpreedFeatureCapability(user.capabilities?.spreedCapability!!, SpreedFeatures.DIRECT_MENTION_FLAG)) { if (model.unreadMentionDirect!!) { viewThemeUtils.material.colorChipBackground(holder.binding.dialogUnreadBubble) } else { diff --git a/app/src/main/java/com/nextcloud/talk/adapters/messages/CallStartedViewHolder.kt b/app/src/main/java/com/nextcloud/talk/adapters/messages/CallStartedViewHolder.kt index 8aa0665cf..dfff2e714 100644 --- a/app/src/main/java/com/nextcloud/talk/adapters/messages/CallStartedViewHolder.kt +++ b/app/src/main/java/com/nextcloud/talk/adapters/messages/CallStartedViewHolder.kt @@ -77,12 +77,12 @@ class CallStartedViewHolder(incomingView: View, payload: Any) : val user = userManager.currentUser.blockingGet() val url: String = if (message.actorType == "guests" || message.actorType == "guest") { ApiUtils.getUrlForGuestAvatar( - user!!.baseUrl, + user!!.baseUrl!!, message.actorDisplayName, true ) } else { - ApiUtils.getUrlForAvatar(user!!.baseUrl, message.actorDisplayName, false) + ApiUtils.getUrlForAvatar(user!!.baseUrl!!, message.actorDisplayName, false) } val imageRequest: ImageRequest = ImageRequest.Builder(context) 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 5af8760c5..ed2662ff9 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 @@ -188,7 +188,7 @@ class IncomingLinkPreviewMessageViewHolder(incomingView: View, payload: Any) : binding.messageQuote.quotedMessageImage.load(it) { addHeader( "Authorization", - ApiUtils.getCredentials(message.activeUser!!.username, message.activeUser!!.token) + ApiUtils.getCredentials(message.activeUser!!.username, message.activeUser!!.token)!! ) } } ?: run { 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 a88a1de93..aa9ab400c 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 @@ -172,7 +172,7 @@ class IncomingLocationMessageViewHolder(incomingView: View, payload: Any) : binding.messageQuote.quotedMessageImage.load(it) { addHeader( "Authorization", - ApiUtils.getCredentials(message.activeUser!!.username, message.activeUser!!.token) + ApiUtils.getCredentials(message.activeUser!!.username, message.activeUser!!.token)!! ) } } ?: run { 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 148675646..a3ee9c61e 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 @@ -195,7 +195,7 @@ class IncomingPollMessageViewHolder(incomingView: View, payload: Any) : binding.messageQuote.quotedMessageImage.load(it) { addHeader( "Authorization", - ApiUtils.getCredentials(message.activeUser!!.username, message.activeUser!!.token) + ApiUtils.getCredentials(message.activeUser!!.username, message.activeUser!!.token)!! ) } } ?: run { 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 4533c8816..1bfb832df 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 @@ -197,7 +197,7 @@ class IncomingTextMessageViewHolder(itemView: View, payload: Any) : binding.messageQuote.quotedMessageImage.load(it) { addHeader( "Authorization", - ApiUtils.getCredentials(message.activeUser!!.username, message.activeUser!!.token) + ApiUtils.getCredentials(message.activeUser!!.username, message.activeUser!!.token)!! ) } } ?: run { 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 d13a69fba..e09bae1fb 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 @@ -301,7 +301,7 @@ class IncomingVoiceMessageViewHolder(incomingView: View, payload: Any) : binding.messageQuote.quotedMessageImage.load(it) { addHeader( "Authorization", - ApiUtils.getCredentials(message.activeUser!!.username, message.activeUser!!.token) + ApiUtils.getCredentials(message.activeUser!!.username, message.activeUser!!.token)!! ) } } ?: run { diff --git a/app/src/main/java/com/nextcloud/talk/adapters/messages/LinkPreview.kt b/app/src/main/java/com/nextcloud/talk/adapters/messages/LinkPreview.kt index 8ddd8a52e..03fd4f995 100644 --- a/app/src/main/java/com/nextcloud/talk/adapters/messages/LinkPreview.kt +++ b/app/src/main/java/com/nextcloud/talk/adapters/messages/LinkPreview.kt @@ -45,8 +45,8 @@ class LinkPreview { binding.referenceThumbImage.setImageDrawable(null) if (!message.extractedUrlToPreview.isNullOrEmpty()) { - val credentials: String = ApiUtils.getCredentials(message.activeUser?.username, message.activeUser?.token) - val openGraphLink = ApiUtils.getUrlForOpenGraph(message.activeUser?.baseUrl) + val credentials: String = ApiUtils.getCredentials(message.activeUser?.username, message.activeUser?.token)!! + val openGraphLink = ApiUtils.getUrlForOpenGraph(message.activeUser?.baseUrl!!) ncApi.getOpenGraph( credentials, openGraphLink, diff --git a/app/src/main/java/com/nextcloud/talk/adapters/messages/OutcomingLinkPreviewMessageViewHolder.kt b/app/src/main/java/com/nextcloud/talk/adapters/messages/OutcomingLinkPreviewMessageViewHolder.kt index 7a1f9aa81..c92a4ecca 100644 --- a/app/src/main/java/com/nextcloud/talk/adapters/messages/OutcomingLinkPreviewMessageViewHolder.kt +++ b/app/src/main/java/com/nextcloud/talk/adapters/messages/OutcomingLinkPreviewMessageViewHolder.kt @@ -161,7 +161,7 @@ class OutcomingLinkPreviewMessageViewHolder(outcomingView: View, payload: Any) : binding.messageQuote.quotedMessageImage.load(it) { addHeader( "Authorization", - ApiUtils.getCredentials(message.activeUser!!.username, message.activeUser!!.token) + ApiUtils.getCredentials(message.activeUser!!.username, message.activeUser!!.token)!! ) } } ?: run { diff --git a/app/src/main/java/com/nextcloud/talk/adapters/messages/OutcomingLocationMessageViewHolder.kt b/app/src/main/java/com/nextcloud/talk/adapters/messages/OutcomingLocationMessageViewHolder.kt index bfea357d4..c1f3587d8 100644 --- a/app/src/main/java/com/nextcloud/talk/adapters/messages/OutcomingLocationMessageViewHolder.kt +++ b/app/src/main/java/com/nextcloud/talk/adapters/messages/OutcomingLocationMessageViewHolder.kt @@ -213,7 +213,7 @@ class OutcomingLocationMessageViewHolder(incomingView: View) : binding.messageQuote.quotedMessageImage.load(it) { addHeader( "Authorization", - ApiUtils.getCredentials(message.activeUser!!.username, message.activeUser!!.token) + ApiUtils.getCredentials(message.activeUser!!.username, message.activeUser!!.token)!! ) } } ?: run { diff --git a/app/src/main/java/com/nextcloud/talk/adapters/messages/OutcomingPollMessageViewHolder.kt b/app/src/main/java/com/nextcloud/talk/adapters/messages/OutcomingPollMessageViewHolder.kt index dcc0ca7c7..53a7bc683 100644 --- a/app/src/main/java/com/nextcloud/talk/adapters/messages/OutcomingPollMessageViewHolder.kt +++ b/app/src/main/java/com/nextcloud/talk/adapters/messages/OutcomingPollMessageViewHolder.kt @@ -175,7 +175,7 @@ class OutcomingPollMessageViewHolder(outcomingView: View, payload: Any) : binding.messageQuote.quotedMessageImage.load(it) { addHeader( "Authorization", - ApiUtils.getCredentials(message.activeUser!!.username, message.activeUser!!.token) + ApiUtils.getCredentials(message.activeUser!!.username, message.activeUser!!.token)!! ) } } ?: run { diff --git a/app/src/main/java/com/nextcloud/talk/adapters/messages/OutcomingTextMessageViewHolder.kt b/app/src/main/java/com/nextcloud/talk/adapters/messages/OutcomingTextMessageViewHolder.kt index 232b9e433..41e805077 100644 --- a/app/src/main/java/com/nextcloud/talk/adapters/messages/OutcomingTextMessageViewHolder.kt +++ b/app/src/main/java/com/nextcloud/talk/adapters/messages/OutcomingTextMessageViewHolder.kt @@ -170,7 +170,7 @@ class OutcomingTextMessageViewHolder(itemView: View) : OutcomingTextMessageViewH binding.messageQuote.quotedMessageImage.load(it) { addHeader( "Authorization", - ApiUtils.getCredentials(message.activeUser!!.username, message.activeUser!!.token) + ApiUtils.getCredentials(message.activeUser!!.username, message.activeUser!!.token)!! ) } } ?: run { diff --git a/app/src/main/java/com/nextcloud/talk/adapters/messages/OutcomingVoiceMessageViewHolder.kt b/app/src/main/java/com/nextcloud/talk/adapters/messages/OutcomingVoiceMessageViewHolder.kt index 1effa576a..6a61a7365 100644 --- a/app/src/main/java/com/nextcloud/talk/adapters/messages/OutcomingVoiceMessageViewHolder.kt +++ b/app/src/main/java/com/nextcloud/talk/adapters/messages/OutcomingVoiceMessageViewHolder.kt @@ -285,7 +285,7 @@ class OutcomingVoiceMessageViewHolder(outcomingView: View) : binding.messageQuote.quotedMessageImage.load(it) { addHeader( "Authorization", - ApiUtils.getCredentials(message.activeUser!!.username, message.activeUser!!.token) + ApiUtils.getCredentials(message.activeUser!!.username, message.activeUser!!.token)!! ) } } ?: run { 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 cbc446eb1..c2c65e17c 100644 --- a/app/src/main/java/com/nextcloud/talk/api/NcApi.java +++ b/app/src/main/java/com/nextcloud/talk/api/NcApi.java @@ -24,6 +24,7 @@ package com.nextcloud.talk.api; import com.nextcloud.talk.models.json.capabilities.CapabilitiesOverall; +import com.nextcloud.talk.models.json.capabilities.RoomCapabilitiesOverall; import com.nextcloud.talk.models.json.chat.ChatOverall; import com.nextcloud.talk.models.json.chat.ChatOverallSingleMessage; import com.nextcloud.talk.models.json.chat.ChatShareOverall; @@ -367,6 +368,10 @@ public interface NcApi { @GET Observable getCapabilities(@Url String url); + @GET + Observable getRoomCapabilities(@Header("Authorization") String authorization, + @Url String url); + /* QueryMap items are as follows: - "lookIntoFuture": int (0 or 1), diff --git a/app/src/main/java/com/nextcloud/talk/callnotification/CallNotificationActivity.kt b/app/src/main/java/com/nextcloud/talk/callnotification/CallNotificationActivity.kt index 5d88fdc64..84d1c33e5 100644 --- a/app/src/main/java/com/nextcloud/talk/callnotification/CallNotificationActivity.kt +++ b/app/src/main/java/com/nextcloud/talk/callnotification/CallNotificationActivity.kt @@ -50,6 +50,7 @@ import com.nextcloud.talk.models.domain.ConversationType import com.nextcloud.talk.models.json.participants.Participant import com.nextcloud.talk.users.UserManager import com.nextcloud.talk.utils.ApiUtils +import com.nextcloud.talk.utils.SpreedFeatures import com.nextcloud.talk.utils.ConversationUtils import com.nextcloud.talk.utils.NotificationUtils import com.nextcloud.talk.utils.ParticipantPermissions @@ -57,7 +58,7 @@ import com.nextcloud.talk.utils.bundle.BundleKeys import com.nextcloud.talk.utils.bundle.BundleKeys.KEY_CALL_VOICE_ONLY import com.nextcloud.talk.utils.bundle.BundleKeys.KEY_CONVERSATION_NAME import com.nextcloud.talk.utils.bundle.BundleKeys.KEY_ROOM_TOKEN -import com.nextcloud.talk.utils.database.user.CapabilitiesUtilNew.hasSpreedFeatureCapability +import com.nextcloud.talk.utils.CapabilitiesUtil.hasSpreedFeatureCapability import io.reactivex.disposables.Disposable import okhttp3.Cache import java.io.IOException @@ -148,10 +149,10 @@ class CallNotificationActivity : CallBaseActivity() { private fun initObservers() { val apiVersion = ApiUtils.getConversationApiVersion( - userBeingCalled, + userBeingCalled!!, intArrayOf( - ApiUtils.APIv4, - ApiUtils.APIv3, + ApiUtils.API_V4, + ApiUtils.API_V3, 1 ) ) @@ -186,10 +187,10 @@ class CallNotificationActivity : CallBaseActivity() { showAnswerControls() - if (apiVersion >= ApiUtils.APIv3) { + if (apiVersion >= ApiUtils.API_V3) { val hasCallFlags = hasSpreedFeatureCapability( - userBeingCalled, - "conversation-call-flags" + userBeingCalled?.capabilities?.spreedCapability!!, + SpreedFeatures.CONVERSATION_CALL_FLAGS ) if (hasCallFlags) { if (isInCallWithVideo(currentConversation!!.callFlag)) { @@ -243,7 +244,7 @@ class CallNotificationActivity : CallBaseActivity() { originalBundle!!.putString(KEY_CONVERSATION_NAME, currentConversation!!.displayName) val participantPermission = ParticipantPermissions( - userBeingCalled!!, + userBeingCalled!!.capabilities!!.spreedCapability!!, currentConversation!! ) originalBundle!!.putBoolean( diff --git a/app/src/main/java/com/nextcloud/talk/chat/ChatActivity.kt b/app/src/main/java/com/nextcloud/talk/chat/ChatActivity.kt index 9dc649dec..6233b144f 100644 --- a/app/src/main/java/com/nextcloud/talk/chat/ChatActivity.kt +++ b/app/src/main/java/com/nextcloud/talk/chat/ChatActivity.kt @@ -167,6 +167,7 @@ import com.nextcloud.talk.models.domain.ConversationReadOnlyState import com.nextcloud.talk.models.domain.ConversationType import com.nextcloud.talk.models.domain.LobbyState import com.nextcloud.talk.models.domain.ObjectType +import com.nextcloud.talk.models.json.capabilities.SpreedCapability import com.nextcloud.talk.models.json.chat.ChatMessage import com.nextcloud.talk.models.json.chat.ChatOverall import com.nextcloud.talk.models.json.chat.ReadStatus @@ -192,6 +193,7 @@ import com.nextcloud.talk.ui.recyclerview.MessageSwipeActions import com.nextcloud.talk.ui.recyclerview.MessageSwipeCallback import com.nextcloud.talk.utils.ApiUtils import com.nextcloud.talk.utils.AudioUtils +import com.nextcloud.talk.utils.SpreedFeatures import com.nextcloud.talk.utils.ContactUtils import com.nextcloud.talk.utils.ConversationUtils import com.nextcloud.talk.utils.DateConstants @@ -218,7 +220,7 @@ import com.nextcloud.talk.utils.bundle.BundleKeys.KEY_ROOM_ID import com.nextcloud.talk.utils.bundle.BundleKeys.KEY_ROOM_TOKEN import com.nextcloud.talk.utils.bundle.BundleKeys.KEY_START_CALL_AFTER_ROOM_SWITCH import com.nextcloud.talk.utils.bundle.BundleKeys.KEY_SWITCH_TO_ROOM -import com.nextcloud.talk.utils.database.user.CapabilitiesUtilNew +import com.nextcloud.talk.utils.CapabilitiesUtil import com.nextcloud.talk.utils.database.user.CurrentUserProviderNew import com.nextcloud.talk.utils.permissions.PlatformPermissionUtil import com.nextcloud.talk.utils.rx.DisposableSet @@ -301,6 +303,8 @@ class ChatActivity : var sessionIdAfterRoomJoined: String? = null lateinit var roomToken: String var conversationUser: User? = null + lateinit var spreedCapabilities: SpreedCapability + var chatApiVersion: Int = 1 private var roomPassword: String = "" var credentials: String? = null var currentConversation: ConversationModel? = null @@ -351,6 +355,7 @@ class ChatActivity : RELEASED, ERROR } + private val editableBehaviorSubject = BehaviorSubject.createDefault(false) private val editedTextBehaviorSubject = BehaviorSubject.createDefault("") @@ -541,14 +546,6 @@ class ChatActivity : } this.lifecycle.addObserver(AudioUtils) this.lifecycle.addObserver(ChatViewModel.LifeCycleObserver) - - chatViewModel.refreshChatParams( - setupFieldsForPullChatMessages( - false, - 0, - false - ) - ) } override fun onStop() { @@ -587,6 +584,30 @@ class ChatActivity : is ChatViewModel.GetRoomSuccessState -> { currentConversation = state.conversationModel logConversationInfos("GetRoomSuccessState") + chatViewModel.getCapabilities(conversationUser!!, roomToken, currentConversation!!) + } + + is ChatViewModel.GetRoomErrorState -> { + Snackbar.make(binding.root, R.string.nc_common_error_sorry, Snackbar.LENGTH_LONG).show() + } + + else -> {} + } + } + + chatViewModel.getCapabilitiesViewState.observe(this) { state -> + when (state) { + is ChatViewModel.GetCapabilitiesSuccessState -> { + spreedCapabilities = state.spreedCapabilities + chatApiVersion = ApiUtils.getChatApiVersion(spreedCapabilities, intArrayOf(1)) + + initMessageInputView() + + if (conversationUser?.userId != "?" && + CapabilitiesUtil.hasSpreedFeatureCapability(spreedCapabilities, SpreedFeatures.MENTION_FLAG) + ) { + binding.chatToolbar.setOnClickListener { v -> showConversationInfoScreen() } + } if (adapter == null) { initAdapter() @@ -597,7 +618,7 @@ class ChatActivity : loadAvatarForStatusBar() setActionBarTitle() - participantPermissions = ParticipantPermissions(conversationUser!!, currentConversation!!) + participantPermissions = ParticipantPermissions(spreedCapabilities, currentConversation!!) setupSwipeToReply() setupMentionAutocomplete() @@ -626,9 +647,17 @@ class ChatActivity : }, delayForRecursiveCall ) + + chatViewModel.refreshChatParams( + setupFieldsForPullChatMessages( + false, + 0, + false + ) + ) } - is ChatViewModel.GetRoomErrorState -> { + is ChatViewModel.GetCapabilitiesErrorState -> { Snackbar.make(binding.root, R.string.nc_common_error_sorry, Snackbar.LENGTH_LONG).show() } @@ -716,6 +745,7 @@ class ChatActivity : } binding.messagesListView.smoothScrollToPosition(0) } + is ChatViewModel.SendChatMessageErrorState -> { if (state.e is HttpException) { val code = state.e.code() @@ -730,6 +760,7 @@ class ChatActivity : } } } + else -> {} } } @@ -753,9 +784,11 @@ class ChatActivity : ) ) } + is ChatViewModel.DeleteChatMessageErrorState -> { Snackbar.make(binding.root, R.string.nc_common_error_sorry, Snackbar.LENGTH_LONG).show() } + else -> {} } } @@ -774,24 +807,22 @@ class ChatActivity : startActivity(chatIntent) } } + is ChatViewModel.CreateRoomErrorState -> { Snackbar.make(binding.root, R.string.nc_common_error_sorry, Snackbar.LENGTH_LONG).show() } + else -> {} } } - var apiVersion = 1 - // FIXME this is a best guess, guests would need to get the capabilities themselves - if (conversationUser != null) { - apiVersion = ApiUtils.getChatApiVersion(conversationUser, intArrayOf(1)) - } - - chatViewModel.getFieldMapForChat.observe(this) { _ -> - chatViewModel.pullChatMessages( - credentials!!, - ApiUtils.getUrlForChat(apiVersion, conversationUser?.baseUrl, roomToken) - ) + chatViewModel.getFieldMapForChat.observe(this) { fieldMap -> + if (fieldMap.isNotEmpty()) { + chatViewModel.pullChatMessages( + credentials!!, + ApiUtils.getUrlForChat(chatApiVersion, conversationUser?.baseUrl, roomToken) + ) + } } chatViewModel.pullChatMessageViewState.observe(this) { state -> @@ -865,6 +896,7 @@ class ChatActivity : ) ) } + HTTP_CODE_NOT_MODIFIED -> { processHeaderChatLastGiven(state.response, state.lookIntoFuture) chatViewModel.refreshChatParams( @@ -875,6 +907,7 @@ class ChatActivity : ) ) } + HTTP_CODE_PRECONDITION_FAILED -> { processHeaderChatLastGiven(state.response, state.lookIntoFuture) chatViewModel.refreshChatParams( @@ -885,6 +918,7 @@ class ChatActivity : ) ) } + else -> {} } @@ -898,12 +932,15 @@ class ChatActivity : collapseSystemMessages() } } + is ChatViewModel.PullChatMessageCompleteState -> { Log.d(TAG, "PullChatMessageCompleted") } + is ChatViewModel.PullChatMessageErrorState -> { Log.d(TAG, "PullChatMessageError") } + else -> {} } } @@ -916,6 +953,7 @@ class ChatActivity : state.reactionDeletedModel.emoji ) } + else -> {} } } @@ -928,6 +966,7 @@ class ChatActivity : state.reactionAddedModel.emoji ) } + else -> {} } } @@ -943,6 +982,7 @@ class ChatActivity : Snackbar.LENGTH_LONG ).show() } + HTTP_FORBIDDEN -> { Snackbar.make( binding.root, @@ -950,6 +990,7 @@ class ChatActivity : Snackbar.LENGTH_LONG ).show() } + HTTP_NOT_FOUND -> { Snackbar.make( binding.root, @@ -960,9 +1001,11 @@ class ChatActivity : } clearEditUI() } + is ChatViewModel.EditMessageErrorState -> { Snackbar.make(binding.root, R.string.nc_common_error_sorry, Snackbar.LENGTH_LONG).show() } + else -> {} } } @@ -980,12 +1023,6 @@ class ChatActivity : webSocketInstance?.getSignalingMessageReceiver()?.addListener(localParticipantMessageListener) webSocketInstance?.getSignalingMessageReceiver()?.addListener(conversationMessageListener) - if (conversationUser?.userId != "?" && - CapabilitiesUtilNew.hasSpreedFeatureCapability(conversationUser, "mention-flag") - ) { - binding.chatToolbar.setOnClickListener { v -> showConversationInfoScreen() } - } - initSmileyKeyboardToggler() themeMessageInputView() @@ -1053,7 +1090,6 @@ class ChatActivity : } }) - initMessageInputView() loadAvatarForStatusBar() setActionBarTitle() viewThemeUtils.material.colorToolbarOverflowIcon(binding.chatToolbar) @@ -1061,7 +1097,7 @@ class ChatActivity : private fun initMessageInputView() { val filters = arrayOfNulls(1) - val lengthFilter = CapabilitiesUtilNew.getMessageMaxLength(conversationUser) + val lengthFilter = CapabilitiesUtil.getMessageMaxLength(spreedCapabilities) binding.editView.editMessageView.visibility = View.GONE @@ -1160,7 +1196,7 @@ class ChatActivity : clearEditUI() } - if (CapabilitiesUtilNew.hasSpreedFeatureCapability(conversationUser, "silent-send")) { + if (CapabilitiesUtil.hasSpreedFeatureCapability(spreedCapabilities, SpreedFeatures.SILENT_SEND)) { binding.messageInputView.button?.setOnLongClickListener { showSendButtonMenu() true @@ -1175,14 +1211,14 @@ class ChatActivity : var apiVersion = 1 // FIXME Fix API checking with guests? if (conversationUser != null) { - apiVersion = ApiUtils.getChatApiVersion(conversationUser, intArrayOf(1)) + apiVersion = ApiUtils.getChatApiVersion(spreedCapabilities, intArrayOf(1)) } chatViewModel.editChatMessage( credentials!!, ApiUtils.getUrlForChatMessage( apiVersion, - conversationUser?.baseUrl, + conversationUser?.baseUrl!!, roomToken, message.id ), @@ -2016,7 +2052,7 @@ class ChatActivity : private fun isTypingStatusEnabled(): Boolean { return webSocketInstance != null && - !CapabilitiesUtilNew.isTypingStatusPrivate(conversationUser!!) + !CapabilitiesUtil.isTypingStatusPrivate(conversationUser!!) } private fun setupSwipeToReply() { @@ -2048,7 +2084,7 @@ class ChatActivity : if (isOneToOneConversation()) { var url = ApiUtils.getUrlForAvatar( - conversationUser!!.baseUrl, + conversationUser!!.baseUrl!!, currentConversation!!.name, true ) @@ -2097,18 +2133,19 @@ class ChatActivity : } val credentials = ApiUtils.getCredentials(conversationUser!!.username, conversationUser!!.token) - - context.imageLoader.enqueue( - ImageRequest.Builder(context) - .data(url) - .addHeader("Authorization", credentials) - .transformations(CircleCropTransformation()) - .crossfade(true) - .target(target) - .memoryCachePolicy(CachePolicy.DISABLED) - .diskCachePolicy(CachePolicy.DISABLED) - .build() - ) + if (credentials != null) { + context.imageLoader.enqueue( + ImageRequest.Builder(context) + .data(url) + .addHeader("Authorization", credentials) + .transformations(CircleCropTransformation()) + .crossfade(true) + .target(target) + .memoryCachePolicy(CachePolicy.DISABLED) + .diskCachePolicy(CachePolicy.DISABLED) + .build() + ) + } } else { binding.chatToolbar.findViewById(R.id.chat_toolbar_avatar_container).visibility = View.GONE } @@ -2463,7 +2500,10 @@ class ChatActivity : val baseUrl = message.activeUser!!.baseUrl val userId = message.activeUser!!.userId - val attachmentFolder = CapabilitiesUtilNew.getAttachmentFolder(message.activeUser!!) + val attachmentFolder = CapabilitiesUtil.getAttachmentFolder( + message.activeUser!!.capabilities!! + .spreedCapability!! + ) val fileName = message.selectedIndividualHashMap!!["name"] var size = message.selectedIndividualHashMap!!["size"] if (size == null) { @@ -2801,16 +2841,16 @@ class ChatActivity : private fun shouldShowLobby(): Boolean { if (currentConversation != null) { - return CapabilitiesUtilNew.hasSpreedFeatureCapability(conversationUser, "webinary-lobby") && + return CapabilitiesUtil.hasSpreedFeatureCapability(spreedCapabilities, SpreedFeatures.WEBINARY_LOBBY) && currentConversation?.lobbyState == LobbyState.LOBBY_STATE_MODERATORS_ONLY && - !ConversationUtils.canModerate(currentConversation!!, conversationUser!!) && + !ConversationUtils.canModerate(currentConversation!!, spreedCapabilities) && !participantPermissions.canIgnoreLobby() } return false } private fun disableCallButtons() { - if (CapabilitiesUtilNew.isAbleToCall(conversationUser)) { + if (CapabilitiesUtil.isAbleToCall(spreedCapabilities)) { if (conversationVoiceCallMenuItem != null && conversationVideoMenuItem != null) { conversationVoiceCallMenuItem?.icon?.alpha = SEMI_TRANSPARENT_INT conversationVideoMenuItem?.icon?.alpha = SEMI_TRANSPARENT_INT @@ -2823,7 +2863,7 @@ class ChatActivity : } private fun enableCallButtons() { - if (CapabilitiesUtilNew.isAbleToCall(conversationUser)) { + if (CapabilitiesUtil.isAbleToCall(spreedCapabilities)) { if (conversationVoiceCallMenuItem != null && conversationVideoMenuItem != null) { conversationVoiceCallMenuItem?.icon?.alpha = FULLY_OPAQUE_INT conversationVideoMenuItem?.icon?.alpha = FULLY_OPAQUE_INT @@ -2843,7 +2883,7 @@ class ChatActivity : private fun checkLobbyState() { if (currentConversation != null && - ConversationUtils.isLobbyViewApplicable(currentConversation!!, conversationUser!!) + ConversationUtils.isLobbyViewApplicable(currentConversation!!, spreedCapabilities) ) { if (shouldShowLobby()) { binding.lobby.lobbyView.visibility = View.VISIBLE @@ -3252,6 +3292,7 @@ class ChatActivity : val intent = Intent(this, LocationPickerActivity::class.java) intent.putExtra(KEY_ROOM_TOKEN, roomToken) + intent.putExtra(BundleKeys.KEY_CHAT_API_VERSION, chatApiVersion) startActivity(intent) } @@ -3270,7 +3311,7 @@ class ChatActivity : val elevation = MENTION_AUTO_COMPLETE_ELEVATION resources?.let { val backgroundDrawable = ColorDrawable(it.getColor(R.color.bg_default, null)) - val presenter = MentionAutocompletePresenter(this, roomToken) + val presenter = MentionAutocompletePresenter(this, roomToken, chatApiVersion) val callback = MentionAutocompleteCallback( this, conversationUser!!, @@ -3430,12 +3471,6 @@ class ChatActivity : if (!validSessionId()) { Log.d(TAG, "sessionID was not valid -> joinRoom") - var apiVersion = 1 - // FIXME Fix API checking with guests? - if (conversationUser != null) { - apiVersion = ApiUtils.getConversationApiVersion(conversationUser, intArrayOf(ApiUtils.APIv4, 1)) - } - val startNanoTime = System.nanoTime() Log.d(TAG, "joinRoomWithPassword - joinRoom - calling: $startNanoTime") @@ -3458,7 +3493,7 @@ class ChatActivity : var apiVersion = 1 // FIXME Fix API checking with guests? if (conversationUser != null) { - apiVersion = ApiUtils.getConversationApiVersion(conversationUser, intArrayOf(ApiUtils.APIv4, 1)) + apiVersion = ApiUtils.getConversationApiVersion(conversationUser!!, intArrayOf(ApiUtils.API_V4, 1)) } val startNanoTime = System.nanoTime() @@ -3467,7 +3502,7 @@ class ChatActivity : credentials!!, ApiUtils.getUrlForParticipantsActive( apiVersion, - conversationUser?.baseUrl, + conversationUser?.baseUrl!!, roomToken ), funToCallWhenLeaveSuccessful @@ -3513,11 +3548,9 @@ class ChatActivity : private fun sendMessage(message: CharSequence, replyTo: Int?, sendWithoutNotification: Boolean) { if (conversationUser != null) { - val apiVersion = ApiUtils.getChatApiVersion(conversationUser, intArrayOf(1)) - chatViewModel.sendChatMessage( credentials!!, - ApiUtils.getUrlForChat(apiVersion, conversationUser!!.baseUrl, roomToken), + ApiUtils.getUrlForChat(chatApiVersion, conversationUser!!.baseUrl!!, roomToken), message, conversationUser!!.displayName ?: "", replyTo ?: 0, @@ -3637,7 +3670,7 @@ class ChatActivity : } } - if (CapabilitiesUtilNew.hasSpreedFeatureCapability(conversationUser, "message-expiration")) { + if (CapabilitiesUtil.hasSpreedFeatureCapability(spreedCapabilities, SpreedFeatures.MESSAGE_EXPIRATION)) { deleteExpiredMessages() } } @@ -3871,53 +3904,58 @@ class ChatActivity : if (conversationUser?.userId == "?") { menu.removeItem(R.id.conversation_info) } else { - conversationInfoMenuItem = menu.findItem(R.id.conversation_info) - - if (CapabilitiesUtilNew.hasSpreedFeatureCapability(conversationUser, "rich-object-list-media")) { - conversationSharedItemsItem = menu.findItem(R.id.shared_items) - } else { - menu.removeItem(R.id.shared_items) - } - loadAvatarForStatusBar() setActionBarTitle() } - - if (CapabilitiesUtilNew.isAbleToCall(conversationUser)) { - conversationVoiceCallMenuItem = menu.findItem(R.id.conversation_voice_call) - conversationVideoMenuItem = menu.findItem(R.id.conversation_video_call) - - if (CapabilitiesUtilNew.hasSpreedFeatureCapability(conversationUser, "silent-call")) { - Handler().post { - findViewById(R.id.conversation_voice_call)?.setOnLongClickListener { - showCallButtonMenu(true) - true - } - } - - Handler().post { - findViewById(R.id.conversation_video_call)?.setOnLongClickListener { - showCallButtonMenu(false) - true - } - } - } - } else { - menu.removeItem(R.id.conversation_video_call) - menu.removeItem(R.id.conversation_voice_call) - } return true } override fun onPrepareOptionsMenu(menu: Menu): Boolean { super.onPrepareOptionsMenu(menu) - conversationUser?.let { - if (CapabilitiesUtilNew.hasSpreedFeatureCapability(it, "read-only-rooms")) { + + if (this::spreedCapabilities.isInitialized) { + if (CapabilitiesUtil.hasSpreedFeatureCapability(spreedCapabilities, SpreedFeatures.READ_ONLY_ROOMS)) { checkShowCallButtons() } + val searchItem = menu.findItem(R.id.conversation_search) - searchItem.isVisible = CapabilitiesUtilNew.isUnifiedSearchAvailable(it) + searchItem.isVisible = CapabilitiesUtil.isUnifiedSearchAvailable(spreedCapabilities) + + if (CapabilitiesUtil.hasSpreedFeatureCapability( + spreedCapabilities, + SpreedFeatures.RICH_OBJECT_LIST_MEDIA + ) + ) { + conversationSharedItemsItem = menu.findItem(R.id.shared_items) + } else { + menu.removeItem(R.id.shared_items) + } + + if (CapabilitiesUtil.isAbleToCall(spreedCapabilities)) { + conversationVoiceCallMenuItem = menu.findItem(R.id.conversation_voice_call) + conversationVideoMenuItem = menu.findItem(R.id.conversation_video_call) + + if (CapabilitiesUtil.hasSpreedFeatureCapability(spreedCapabilities, SpreedFeatures.SILENT_CALL)) { + Handler().post { + findViewById(R.id.conversation_voice_call)?.setOnLongClickListener { + showCallButtonMenu(true) + true + } + } + + Handler().post { + findViewById(R.id.conversation_video_call)?.setOnLongClickListener { + showCallButtonMenu(false) + true + } + } + } + } else { + menu.removeItem(R.id.conversation_video_call) + menu.removeItem(R.id.conversation_voice_call) + } } + return true } @@ -4054,7 +4092,7 @@ class ChatActivity : private fun startACall(isVoiceOnlyCall: Boolean, callWithoutNotification: Boolean) { currentConversation?.let { if (conversationUser != null) { - val pp = ParticipantPermissions(conversationUser!!, it) + val pp = ParticipantPermissions(spreedCapabilities, it) if (!pp.canStartCall() && currentConversation?.hasCall == false) { Snackbar.make(binding.root, R.string.startCallForbidden, Snackbar.LENGTH_LONG).show() } else { @@ -4074,7 +4112,7 @@ class ChatActivity : bundle.putString(KEY_ROOM_TOKEN, roomToken) bundle.putString(KEY_ROOM_ID, roomId) bundle.putString(BundleKeys.KEY_CONVERSATION_PASSWORD, roomPassword) - bundle.putString(BundleKeys.KEY_MODIFIED_BASE_URL, conversationUser?.baseUrl) + bundle.putString(BundleKeys.KEY_MODIFIED_BASE_URL, conversationUser?.baseUrl!!) bundle.putString(KEY_CONVERSATION_NAME, it.displayName) bundle.putInt(KEY_RECORDING_STATE, it.callRecording) bundle.putBoolean(KEY_IS_MODERATOR, ConversationUtils.isParticipantOwnerOrModerator(it)) @@ -4147,7 +4185,8 @@ class ChatActivity : conversationUser, currentConversation, isShowMessageDeletionButton(message), - participantPermissions.hasChatPermission() + participantPermissions.hasChatPermission(), + spreedCapabilities ).show() } } @@ -4156,7 +4195,7 @@ class ChatActivity : return ChatMessage.MessageType.SYSTEM_MESSAGE == message.getCalculateMessageType() } - fun deleteMessage(message: IMessage?) { + fun deleteMessage(message: IMessage) { if (!participantPermissions.hasChatPermission()) { Log.w( TAG, @@ -4168,28 +4207,28 @@ class ChatActivity : var apiVersion = 1 // FIXME Fix API checking with guests? if (conversationUser != null) { - apiVersion = ApiUtils.getChatApiVersion(conversationUser, intArrayOf(1)) + apiVersion = ApiUtils.getChatApiVersion(spreedCapabilities, intArrayOf(1)) } chatViewModel.deleteChatMessages( credentials!!, ApiUtils.getUrlForChatMessage( apiVersion, - conversationUser?.baseUrl, + conversationUser?.baseUrl!!, roomToken, - message?.id + message.id!! ), - message?.id!! + message.id!! ) } } fun replyPrivately(message: IMessage?) { val apiVersion = - ApiUtils.getConversationApiVersion(conversationUser, intArrayOf(ApiUtils.APIv4, 1)) + ApiUtils.getConversationApiVersion(conversationUser!!, intArrayOf(ApiUtils.API_V4, 1)) val retrofitBucket = ApiUtils.getRetrofitBucketForCreateRoom( apiVersion, - conversationUser?.baseUrl, + conversationUser?.baseUrl!!, "1", null, message?.user?.id?.substring(INVITE_LENGTH), @@ -4215,10 +4254,14 @@ class ChatActivity : fun remindMeLater(message: ChatMessage?) { Log.d(TAG, "remindMeLater called") + + val chatApiVersion = ApiUtils.getChatApiVersion(spreedCapabilities, intArrayOf(ApiUtils.API_V1, 1)) + val newFragment: DialogFragment = DateTimePickerFragment.newInstance( roomToken, message!!.id, - chatViewModel + chatViewModel, + chatApiVersion ) newFragment.show(supportFragmentManager, DateTimePickerFragment.TAG) } @@ -4229,8 +4272,8 @@ class ChatActivity : chatViewModel.setChatReadMarker( credentials!!, ApiUtils.getUrlForChatReadMarker( - ApiUtils.getChatApiVersion(conversationUser, intArrayOf(ApiUtils.APIv1)), - conversationUser?.baseUrl, + ApiUtils.getChatApiVersion(spreedCapabilities, intArrayOf(ApiUtils.API_V1)), + conversationUser?.baseUrl!!, roomToken ), chatMessage.previousMessageId @@ -4312,10 +4355,10 @@ class ChatActivity : } fun shareToNotes(message: ChatMessage, roomToken: String) { - val apiVersion = ApiUtils.getChatApiVersion(conversationUser, intArrayOf(1)) + val apiVersion = ApiUtils.getChatApiVersion(spreedCapabilities, intArrayOf(1)) val type = message.getCalculateMessageType() var shareUri: Uri? = null - var data: HashMap? + val data: HashMap? var metaData: String = "" var objectId: String = "" if (message.hasFileAttachment()) { @@ -4335,9 +4378,9 @@ class ChatActivity : } else if (message.hasGeoLocation()) { data = message.messageParameters?.get("object") objectId = data?.get("id")!! - val name = data.get("name")!! - val lat = data.get("latitude")!! - val lon = data.get("longitude")!! + val name = data["name"]!! + val lat = data["latitude"]!! + val lon = data["longitude"]!! metaData = "{\"type\":\"geo-location\",\"id\":\"geo:$lat,$lon\",\"latitude\":\"$lat\"," + "\"longitude\":\"$lon\",\"name\":\"$name\"}" @@ -4348,6 +4391,7 @@ class ChatActivity : uploadFile(shareUri.toString(), true, token = roomToken) Snackbar.make(binding.root, R.string.nc_message_sent, Snackbar.LENGTH_SHORT).show() } + ChatMessage.MessageType.SINGLE_NC_ATTACHMENT_MESSAGE -> { val caption = if (message.message != "{file}") message.message else "" if (null != shareUri) { @@ -4364,25 +4408,28 @@ class ChatActivity : } } } + ChatMessage.MessageType.SINGLE_NC_GEOLOCATION_MESSAGE -> { chatViewModel.shareLocationToNotes( credentials!!, - ApiUtils.getUrlToSendLocation(apiVersion, conversationUser!!.baseUrl, roomToken), + ApiUtils.getUrlToSendLocation(apiVersion, conversationUser!!.baseUrl!!, roomToken), "geo-location", objectId, metaData ) Snackbar.make(binding.root, R.string.nc_message_sent, Snackbar.LENGTH_SHORT).show() } + ChatMessage.MessageType.REGULAR_TEXT_MESSAGE -> { chatViewModel.shareToNotes( credentials!!, - ApiUtils.getUrlForChat(apiVersion, conversationUser!!.baseUrl, roomToken), + ApiUtils.getUrlForChat(apiVersion, conversationUser!!.baseUrl!!, roomToken), message.message!!, conversationUser!!.displayName!! ) Snackbar.make(binding.root, R.string.nc_message_sent, Snackbar.LENGTH_SHORT).show() } + else -> {} } } @@ -4456,7 +4503,10 @@ class ChatActivity : } private fun showMicrophoneButton(show: Boolean) { - if (show && CapabilitiesUtilNew.hasSpreedFeatureCapability(conversationUser, "voice-message-sharing")) { + if (show && CapabilitiesUtil.hasSpreedFeatureCapability( + spreedCapabilities, SpreedFeatures.VOICE_MESSAGE_SHARING + ) + ) { Log.d(TAG, "Microphone shown") binding.messageInputView.messageSendButton.visibility = View.GONE binding.messageInputView.recordAudioButton.visibility = View.VISIBLE @@ -4542,7 +4592,7 @@ class ChatActivity : !isUserAllowedByPrivileges -> false message.systemMessageType != ChatMessage.SystemMessageType.DUMMY -> false message.isDeleted -> false - !CapabilitiesUtilNew.hasSpreedFeatureCapability(conversationUser, "delete-messages") -> false + !CapabilitiesUtil.hasSpreedFeatureCapability(spreedCapabilities, SpreedFeatures.DELETE_MESSAGES) -> false !participantPermissions.hasChatPermission() -> false else -> true } @@ -4554,7 +4604,7 @@ class ChatActivity : val isUserAllowedByPrivileges = if (message.actorId == conversationUser!!.userId) { true } else { - ConversationUtils.canModerate(currentConversation!!, conversationUser!!) + ConversationUtils.canModerate(currentConversation!!, spreedCapabilities) } return isUserAllowedByPrivileges } @@ -4628,12 +4678,12 @@ class ChatActivity : var apiVersion = 1 // FIXME Fix API checking with guests? if (conversationUser != null) { - apiVersion = ApiUtils.getConversationApiVersion(conversationUser, intArrayOf(ApiUtils.APIv4, 1)) + apiVersion = ApiUtils.getConversationApiVersion(conversationUser!!, intArrayOf(ApiUtils.API_V4, 1)) } val retrofitBucket = ApiUtils.getRetrofitBucketForCreateRoom( apiVersion, - conversationUser?.baseUrl, + conversationUser?.baseUrl!!, "1", null, userMentionClickEvent.userId, diff --git a/app/src/main/java/com/nextcloud/talk/chat/data/ChatRepository.kt b/app/src/main/java/com/nextcloud/talk/chat/data/ChatRepository.kt index 88eae5d4e..db1fd1f4d 100644 --- a/app/src/main/java/com/nextcloud/talk/chat/data/ChatRepository.kt +++ b/app/src/main/java/com/nextcloud/talk/chat/data/ChatRepository.kt @@ -22,6 +22,7 @@ package com.nextcloud.talk.chat.data import com.nextcloud.talk.data.user.model.User import com.nextcloud.talk.models.domain.ConversationModel +import com.nextcloud.talk.models.json.capabilities.SpreedCapability import com.nextcloud.talk.models.json.chat.ChatOverallSingleMessage import com.nextcloud.talk.models.json.conversations.RoomOverall import com.nextcloud.talk.models.json.conversations.RoomsOverall @@ -33,10 +34,17 @@ import retrofit2.Response @Suppress("LongParameterList", "TooManyFunctions") interface ChatRepository { fun getRoom(user: User, roomToken: String): Observable + fun getCapabilities(user: User, roomToken: String): Observable fun joinRoom(user: User, roomToken: String, roomPassword: String): Observable - fun setReminder(user: User, roomToken: String, messageId: String, timeStamp: Int): Observable - fun getReminder(user: User, roomToken: String, messageId: String): Observable - fun deleteReminder(user: User, roomToken: String, messageId: String): Observable + fun setReminder( + user: User, + roomToken: String, + messageId: String, + timeStamp: Int, + chatApiVersion: Int + ): Observable + fun getReminder(user: User, roomToken: String, messageId: String, apiVersion: Int): Observable + fun deleteReminder(user: User, roomToken: String, messageId: String, apiVersion: Int): Observable fun shareToNotes( credentials: String, url: String, diff --git a/app/src/main/java/com/nextcloud/talk/chat/data/network/NetworkChatRepositoryImpl.kt b/app/src/main/java/com/nextcloud/talk/chat/data/network/NetworkChatRepositoryImpl.kt index 95edcb21c..2fbb3a0c9 100644 --- a/app/src/main/java/com/nextcloud/talk/chat/data/network/NetworkChatRepositoryImpl.kt +++ b/app/src/main/java/com/nextcloud/talk/chat/data/network/NetworkChatRepositoryImpl.kt @@ -24,6 +24,7 @@ import com.nextcloud.talk.api.NcApi import com.nextcloud.talk.chat.data.ChatRepository import com.nextcloud.talk.data.user.model.User import com.nextcloud.talk.models.domain.ConversationModel +import com.nextcloud.talk.models.json.capabilities.SpreedCapability import com.nextcloud.talk.models.json.chat.ChatOverallSingleMessage import com.nextcloud.talk.models.json.conversations.RoomOverall import com.nextcloud.talk.models.json.conversations.RoomsOverall @@ -35,55 +36,78 @@ import retrofit2.Response class NetworkChatRepositoryImpl(private val ncApi: NcApi) : ChatRepository { override fun getRoom(user: User, roomToken: String): Observable { - val credentials: String = ApiUtils.getCredentials(user.username, user.token) - val apiVersion = ApiUtils.getConversationApiVersion(user, intArrayOf(ApiUtils.APIv4, ApiUtils.APIv3, 1)) + val credentials: String = ApiUtils.getCredentials(user.username, user.token)!! + val apiVersion = ApiUtils.getConversationApiVersion(user, intArrayOf(ApiUtils.API_V4, ApiUtils.API_V3, 1)) return ncApi.getRoom( credentials, - ApiUtils.getUrlForRoom(apiVersion, user.baseUrl, roomToken) + ApiUtils.getUrlForRoom(apiVersion, user.baseUrl!!, roomToken) ).map { ConversationModel.mapToConversationModel(it.ocs?.data!!) } } + override fun getCapabilities(user: User, roomToken: String): Observable { + val credentials: String = ApiUtils.getCredentials(user.username, user.token)!! + val apiVersion = ApiUtils.getConversationApiVersion(user, intArrayOf(ApiUtils.API_V4, ApiUtils.API_V3, 1)) + + return ncApi.getRoomCapabilities( + credentials, + ApiUtils.getUrlForRoomCapabilities(apiVersion, user.baseUrl!!, roomToken) + ).map { it.ocs?.data } + } + override fun joinRoom(user: User, roomToken: String, roomPassword: String): Observable { - val credentials: String = ApiUtils.getCredentials(user.username, user.token) - val apiVersion = ApiUtils.getConversationApiVersion(user, intArrayOf(ApiUtils.APIv4, 1)) + val credentials: String = ApiUtils.getCredentials(user.username, user.token)!! + val apiVersion = ApiUtils.getConversationApiVersion(user, intArrayOf(ApiUtils.API_V4, 1)) return ncApi.joinRoom( credentials, - ApiUtils.getUrlForParticipantsActive(apiVersion, user.baseUrl, roomToken), + ApiUtils.getUrlForParticipantsActive(apiVersion, user.baseUrl!!, roomToken), roomPassword ).map { ConversationModel.mapToConversationModel(it.ocs?.data!!) } } - override fun setReminder(user: User, roomToken: String, messageId: String, timeStamp: Int): Observable { - val credentials: String = ApiUtils.getCredentials(user.username, user.token) - val apiVersion = ApiUtils.getChatApiVersion(user, intArrayOf(ApiUtils.APIv1, 1)) + override fun setReminder( + user: User, + roomToken: String, + messageId: String, + timeStamp: Int, + chatApiVersion: Int + ): Observable { + val credentials: String = ApiUtils.getCredentials(user.username, user.token)!! return ncApi.setReminder( credentials, - ApiUtils.getUrlForReminder(user, roomToken, messageId, apiVersion), + ApiUtils.getUrlForReminder(user, roomToken, messageId, chatApiVersion), timeStamp ).map { it.ocs!!.data } } - override fun getReminder(user: User, roomToken: String, messageId: String): Observable { - val credentials: String = ApiUtils.getCredentials(user.username, user.token) - val apiVersion = ApiUtils.getChatApiVersion(user, intArrayOf(ApiUtils.APIv1, 1)) + override fun getReminder( + user: User, + roomToken: String, + messageId: String, + chatApiVersion: Int + ): Observable { + val credentials: String = ApiUtils.getCredentials(user.username, user.token)!! return ncApi.getReminder( credentials, - ApiUtils.getUrlForReminder(user, roomToken, messageId, apiVersion) + ApiUtils.getUrlForReminder(user, roomToken, messageId, chatApiVersion) ).map { it.ocs!!.data } } - override fun deleteReminder(user: User, roomToken: String, messageId: String): Observable { - val credentials: String = ApiUtils.getCredentials(user.username, user.token) - val apiVersion = ApiUtils.getChatApiVersion(user, intArrayOf(ApiUtils.APIv1, 1)) + override fun deleteReminder( + user: User, + roomToken: String, + messageId: String, + chatApiVersion: Int + ): Observable { + val credentials: String = ApiUtils.getCredentials(user.username, user.token)!! return ncApi.deleteReminder( credentials, - ApiUtils.getUrlForReminder(user, roomToken, messageId, apiVersion) + ApiUtils.getUrlForReminder(user, roomToken, messageId, chatApiVersion) ).map { it } diff --git a/app/src/main/java/com/nextcloud/talk/chat/viewmodels/ChatViewModel.kt b/app/src/main/java/com/nextcloud/talk/chat/viewmodels/ChatViewModel.kt index cbb392bb2..fadbe677b 100644 --- a/app/src/main/java/com/nextcloud/talk/chat/viewmodels/ChatViewModel.kt +++ b/app/src/main/java/com/nextcloud/talk/chat/viewmodels/ChatViewModel.kt @@ -31,6 +31,7 @@ import com.nextcloud.talk.data.user.model.User import com.nextcloud.talk.models.domain.ConversationModel import com.nextcloud.talk.models.domain.ReactionAddedModel import com.nextcloud.talk.models.domain.ReactionDeletedModel +import com.nextcloud.talk.models.json.capabilities.SpreedCapability import com.nextcloud.talk.models.json.chat.ChatMessage import com.nextcloud.talk.models.json.chat.ChatOverallSingleMessage import com.nextcloud.talk.models.json.conversations.RoomOverall @@ -105,6 +106,14 @@ class ChatViewModel @Inject constructor( val getRoomViewState: LiveData get() = _getRoomViewState + object GetCapabilitiesStartState : ViewState + object GetCapabilitiesErrorState : ViewState + open class GetCapabilitiesSuccessState(val spreedCapabilities: SpreedCapability) : ViewState + + private val _getCapabilitiesViewState: MutableLiveData = MutableLiveData(GetCapabilitiesStartState) + val getCapabilitiesViewState: LiveData + get() = _getCapabilitiesViewState + object JoinRoomStartState : ViewState object JoinRoomErrorState : ViewState open class JoinRoomSuccessState(val conversationModel: ConversationModel) : ViewState @@ -184,6 +193,36 @@ class ChatViewModel @Inject constructor( ?.subscribe(GetRoomObserver()) } + fun getCapabilities(user: User, token: String, conversationModel: ConversationModel) { + _getCapabilitiesViewState.value = GetCapabilitiesStartState + + if (conversationModel.remoteServer.isNullOrEmpty()) { + _getCapabilitiesViewState.value = GetCapabilitiesSuccessState(user.capabilities!!.spreedCapability!!) + } else { + chatRepository.getCapabilities(user, token) + .subscribeOn(Schedulers.io()) + ?.observeOn(AndroidSchedulers.mainThread()) + ?.subscribe(object : Observer { + override fun onSubscribe(d: Disposable) { + LifeCycleObserver.disposableSet.add(d) + } + + override fun onNext(spreedCapabilities: SpreedCapability) { + _getCapabilitiesViewState.value = GetCapabilitiesSuccessState(spreedCapabilities) + } + + override fun onError(e: Throwable) { + Log.e(TAG, "Error when fetching spreed capabilities", e) + _getCapabilitiesViewState.value = GetCapabilitiesErrorState + } + + override fun onComplete() { + // unused atm + } + }) + } + } + fun joinRoom(user: User, token: String, roomPassword: String) { _joinRoomViewState.value = JoinRoomStartState chatRepository.joinRoom(user, token, roomPassword) @@ -193,6 +232,43 @@ class ChatViewModel @Inject constructor( ?.subscribe(JoinRoomObserver()) } + fun setReminder(user: User, roomToken: String, messageId: String, timestamp: Int, chatApiVersion: Int) { + chatRepository.setReminder(user, roomToken, messageId, timestamp, chatApiVersion) + .subscribeOn(Schedulers.io()) + ?.observeOn(AndroidSchedulers.mainThread()) + ?.subscribe(SetReminderObserver()) + } + + fun getReminder(user: User, roomToken: String, messageId: String, chatApiVersion: Int) { + chatRepository.getReminder(user, roomToken, messageId, chatApiVersion) + .subscribeOn(Schedulers.io()) + ?.observeOn(AndroidSchedulers.mainThread()) + ?.subscribe(GetReminderObserver()) + } + + fun deleteReminder(user: User, roomToken: String, messageId: String, chatApiVersion: Int) { + chatRepository.deleteReminder(user, roomToken, messageId, chatApiVersion) + .subscribeOn(Schedulers.io()) + ?.observeOn(AndroidSchedulers.mainThread()) + ?.subscribe(object : Observer { + override fun onSubscribe(d: Disposable) { + LifeCycleObserver.disposableSet.add(d) + } + + override fun onNext(genericOverall: GenericOverall) { + _getReminderExistState.value = GetReminderStartState + } + + override fun onError(e: Throwable) { + Log.d(TAG, "Error when deleting reminder", e) + } + + override fun onComplete() { + // unused atm + } + }) + } + fun leaveRoom(credentials: String, url: String, funToCallWhenLeaveSuccessful: (() -> Unit)?) { val startNanoTime = System.nanoTime() chatRepository.leaveRoom(credentials, url) @@ -357,43 +433,6 @@ class ChatViewModel @Inject constructor( }) } - fun setReminder(user: User, roomToken: String, messageId: String, timestamp: Int) { - chatRepository.setReminder(user, roomToken, messageId, timestamp) - .subscribeOn(Schedulers.io()) - ?.observeOn(AndroidSchedulers.mainThread()) - ?.subscribe(SetReminderObserver()) - } - - fun getReminder(user: User, roomToken: String, messageId: String) { - chatRepository.getReminder(user, roomToken, messageId) - .subscribeOn(Schedulers.io()) - ?.observeOn(AndroidSchedulers.mainThread()) - ?.subscribe(GetReminderObserver()) - } - - fun deleteReminder(user: User, roomToken: String, messageId: String) { - chatRepository.deleteReminder(user, roomToken, messageId) - .subscribeOn(Schedulers.io()) - ?.observeOn(AndroidSchedulers.mainThread()) - ?.subscribe(object : Observer { - override fun onSubscribe(d: Disposable) { - LifeCycleObserver.disposableSet.add(d) - } - - override fun onNext(genericOverall: GenericOverall) { - _getReminderExistState.value = GetReminderStartState - } - - override fun onError(e: Throwable) { - Log.d(TAG, "Error when deleting reminder $e") - } - - override fun onComplete() { - // unused atm - } - }) - } - fun shareToNotes(credentials: String, url: String, message: String, displayName: String) { chatRepository.shareToNotes(credentials, url, message, displayName) .subscribeOn(Schedulers.io()) @@ -522,7 +561,7 @@ class ChatViewModel @Inject constructor( inner class GetRoomObserver : Observer { override fun onSubscribe(d: Disposable) { - LifeCycleObserver.disposableSet.add(d) + // unused atm } override fun onNext(conversationModel: ConversationModel) { diff --git a/app/src/main/java/com/nextcloud/talk/components/filebrowser/webdav/ReadFolderListingOperation.kt b/app/src/main/java/com/nextcloud/talk/components/filebrowser/webdav/ReadFolderListingOperation.kt index 293dfa925..18625a511 100644 --- a/app/src/main/java/com/nextcloud/talk/components/filebrowser/webdav/ReadFolderListingOperation.kt +++ b/app/src/main/java/com/nextcloud/talk/components/filebrowser/webdav/ReadFolderListingOperation.kt @@ -65,7 +65,7 @@ class ReadFolderListingOperation(okHttpClient: OkHttpClient, currentUser: User, ApiUtils.getCredentials( currentUser.username, currentUser.token - ), + )!!, "Authorization" ) ) diff --git a/app/src/main/java/com/nextcloud/talk/contacts/ContactsActivity.kt b/app/src/main/java/com/nextcloud/talk/contacts/ContactsActivity.kt index c32f748ff..16f955b54 100644 --- a/app/src/main/java/com/nextcloud/talk/contacts/ContactsActivity.kt +++ b/app/src/main/java/com/nextcloud/talk/contacts/ContactsActivity.kt @@ -68,9 +68,10 @@ import com.nextcloud.talk.models.json.participants.Participant import com.nextcloud.talk.openconversations.ListOpenConversationsActivity import com.nextcloud.talk.users.UserManager import com.nextcloud.talk.utils.ApiUtils +import com.nextcloud.talk.utils.SpreedFeatures import com.nextcloud.talk.utils.UserIdUtils.getIdForUser import com.nextcloud.talk.utils.bundle.BundleKeys -import com.nextcloud.talk.utils.database.user.CapabilitiesUtilNew +import com.nextcloud.talk.utils.CapabilitiesUtil import eu.davidea.flexibleadapter.FlexibleAdapter import eu.davidea.flexibleadapter.SelectableAdapter import eu.davidea.flexibleadapter.common.SmoothScrollLinearLayoutManager @@ -318,10 +319,10 @@ class ContactsActivity : } private fun createRoom(roomType: String, sourceType: String?, userId: String) { - val apiVersion: Int = ApiUtils.getConversationApiVersion(currentUser, intArrayOf(ApiUtils.APIv4, 1)) + val apiVersion: Int = ApiUtils.getConversationApiVersion(currentUser!!, intArrayOf(ApiUtils.API_V4, 1)) val retrofitBucket: RetrofitBucket = ApiUtils.getRetrofitBucketForCreateRoom( apiVersion, - currentUser!!.baseUrl, + currentUser!!.baseUrl!!, roomType, sourceType, userId, @@ -438,7 +439,7 @@ class ContactsActivity : userHeaderItems = HashMap() val query = adapter!!.getFilter(String::class.java) val retrofitBucket: RetrofitBucket = - ApiUtils.getRetrofitBucketForContactsSearchFor14(currentUser!!.baseUrl, query) + ApiUtils.getRetrofitBucketForContactsSearchFor14(currentUser!!.baseUrl!!, query) val modifiedQueryMap: HashMap = HashMap(retrofitBucket.queryMap) modifiedQueryMap["limit"] = CONTACTS_BATCH_SIZE if (isAddingParticipantsView) { @@ -450,13 +451,21 @@ class ContactsActivity : if (!isAddingParticipantsView) { // groups shareTypesList.add("1") - } else if (CapabilitiesUtilNew.hasSpreedFeatureCapability(currentUser, "invite-groups-and-mails")) { + } else if (CapabilitiesUtil.hasSpreedFeatureCapability( + currentUser?.capabilities?.spreedCapability!!, + SpreedFeatures.INVITE_GROUPS_AND_MAILS + ) + ) { // groups shareTypesList.add("1") // emails shareTypesList.add("4") } - if (CapabilitiesUtilNew.hasSpreedFeatureCapability(currentUser, "circles-support")) { + if (CapabilitiesUtil.hasSpreedFeatureCapability( + currentUser?.capabilities?.spreedCapability!!, + SpreedFeatures.CIRCLES_SUPPORT + ) + ) { // circles shareTypesList.add("7") } @@ -745,8 +754,12 @@ class ContactsActivity : private fun updateSelection(contactItem: ContactItem) { contactItem.model.selected = !contactItem.model.selected updateSelectionLists(contactItem.model) - if (CapabilitiesUtilNew.hasSpreedFeatureCapability(currentUser, "last-room-activity") && - !CapabilitiesUtilNew.hasSpreedFeatureCapability(currentUser, "invite-groups-and-mails") && + if (CapabilitiesUtil.hasSpreedFeatureCapability( + currentUser?.capabilities?.spreedCapability!!, SpreedFeatures.LAST_ROOM_ACTIVITY + ) && + !CapabilitiesUtil.hasSpreedFeatureCapability( + currentUser?.capabilities?.spreedCapability!!, SpreedFeatures.INVITE_GROUPS_AND_MAILS + ) && isValidGroupSelection(contactItem, contactItem.model, adapter) ) { val currentItems: List = adapter?.currentItems as List @@ -771,10 +784,10 @@ class ContactsActivity : if ("groups" == contactItem.model.source) { roomType = "2" } - val apiVersion: Int = ApiUtils.getConversationApiVersion(currentUser, intArrayOf(ApiUtils.APIv4, 1)) + val apiVersion: Int = ApiUtils.getConversationApiVersion(currentUser!!, intArrayOf(ApiUtils.API_V4, 1)) val retrofitBucket: RetrofitBucket = ApiUtils.getRetrofitBucketForCreateRoom( apiVersion, - currentUser!!.baseUrl, + currentUser!!.baseUrl!!, roomType, null, contactItem.model.calculatedActorId, diff --git a/app/src/main/java/com/nextcloud/talk/conversation/repository/ConversationRepositoryImpl.kt b/app/src/main/java/com/nextcloud/talk/conversation/repository/ConversationRepositoryImpl.kt index adc6f88eb..d4b657b6c 100644 --- a/app/src/main/java/com/nextcloud/talk/conversation/repository/ConversationRepositoryImpl.kt +++ b/app/src/main/java/com/nextcloud/talk/conversation/repository/ConversationRepositoryImpl.kt @@ -36,16 +36,16 @@ class ConversationRepositoryImpl(private val ncApi: NcApi, currentUserProvider: ConversationRepository { val currentUser: User = currentUserProvider.currentUser.blockingGet() - val credentials: String = ApiUtils.getCredentials(currentUser.username, currentUser.token) + val credentials: String = ApiUtils.getCredentials(currentUser.username, currentUser.token)!! override fun renameConversation(roomToken: String, roomNameNew: String): Observable { - val apiVersion = ApiUtils.getConversationApiVersion(currentUser, intArrayOf(ApiUtils.APIv4, ApiUtils.APIv1)) + val apiVersion = ApiUtils.getConversationApiVersion(currentUser, intArrayOf(ApiUtils.API_V4, ApiUtils.API_V1)) return ncApi.renameRoom( credentials, ApiUtils.getUrlForRoom( apiVersion, - currentUser.baseUrl, + currentUser.baseUrl!!, roomToken ), roomNameNew @@ -59,12 +59,12 @@ class ConversationRepositoryImpl(private val ncApi: NcApi, currentUserProvider: roomName: String, conversationType: Conversation.ConversationType? ): Observable { - val apiVersion = ApiUtils.getConversationApiVersion(currentUser, intArrayOf(ApiUtils.APIv4, ApiUtils.APIv1)) + val apiVersion = ApiUtils.getConversationApiVersion(currentUser, intArrayOf(ApiUtils.API_V4, ApiUtils.API_V1)) val retrofitBucket: RetrofitBucket = if (conversationType == Conversation.ConversationType.ROOM_PUBLIC_CALL) { ApiUtils.getRetrofitBucketForCreateRoom( apiVersion, - currentUser.baseUrl, + currentUser.baseUrl!!, ROOM_TYPE_PUBLIC, null, null, @@ -73,7 +73,7 @@ class ConversationRepositoryImpl(private val ncApi: NcApi, currentUserProvider: } else { ApiUtils.getRetrofitBucketForCreateRoom( apiVersion, - currentUser.baseUrl, + currentUser.baseUrl!!, ROOM_TYPE_GROUP, null, null, diff --git a/app/src/main/java/com/nextcloud/talk/conversationinfo/ConversationInfoActivity.kt b/app/src/main/java/com/nextcloud/talk/conversationinfo/ConversationInfoActivity.kt index e04bd2ac6..70fa77133 100644 --- a/app/src/main/java/com/nextcloud/talk/conversationinfo/ConversationInfoActivity.kt +++ b/app/src/main/java/com/nextcloud/talk/conversationinfo/ConversationInfoActivity.kt @@ -40,6 +40,7 @@ import android.view.View import android.view.View.GONE import android.view.View.VISIBLE import androidx.appcompat.app.AlertDialog +import androidx.lifecycle.ViewModelProvider import androidx.work.Data import androidx.work.OneTimeWorkRequest import androidx.work.WorkManager @@ -61,6 +62,7 @@ import com.nextcloud.talk.bottomsheet.items.BasicListItemWithImage import com.nextcloud.talk.bottomsheet.items.listItemsWithImage import com.nextcloud.talk.contacts.ContactsActivity import com.nextcloud.talk.conversationinfoedit.ConversationInfoEditActivity +import com.nextcloud.talk.conversationinfo.viewmodel.ConversationInfoViewModel import com.nextcloud.talk.data.user.model.User import com.nextcloud.talk.databinding.ActivityConversationInfoBinding import com.nextcloud.talk.events.EventStatus @@ -71,9 +73,11 @@ import com.nextcloud.talk.extensions.loadUserAvatar import com.nextcloud.talk.jobs.DeleteConversationWorker import com.nextcloud.talk.jobs.LeaveConversationWorker import com.nextcloud.talk.models.domain.ConversationModel -import com.nextcloud.talk.models.json.conversations.Conversation -import com.nextcloud.talk.models.json.conversations.RoomOverall -import com.nextcloud.talk.models.json.converters.EnumNotificationLevelConverter +import com.nextcloud.talk.models.domain.ConversationType +import com.nextcloud.talk.models.domain.LobbyState +import com.nextcloud.talk.models.domain.NotificationLevel +import com.nextcloud.talk.models.domain.converters.DomainEnumNotificationLevelConverter +import com.nextcloud.talk.models.json.capabilities.SpreedCapability import com.nextcloud.talk.models.json.generic.GenericOverall import com.nextcloud.talk.models.json.participants.Participant import com.nextcloud.talk.models.json.participants.Participant.ActorType.CIRCLES @@ -83,11 +87,12 @@ 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.SpreedFeatures import com.nextcloud.talk.utils.ConversationUtils import com.nextcloud.talk.utils.DateConstants import com.nextcloud.talk.utils.DateUtils import com.nextcloud.talk.utils.bundle.BundleKeys -import com.nextcloud.talk.utils.database.user.CapabilitiesUtilNew +import com.nextcloud.talk.utils.CapabilitiesUtil import com.nextcloud.talk.utils.database.user.CurrentUserProviderNew import com.nextcloud.talk.utils.preferences.preferencestorage.DatabaseStorageModule import eu.davidea.flexibleadapter.FlexibleAdapter @@ -109,6 +114,9 @@ class ConversationInfoActivity : FlexibleAdapter.OnItemClickListener { private lateinit var binding: ActivityConversationInfoBinding + @Inject + lateinit var viewModelFactory: ViewModelProvider.Factory + @Inject lateinit var ncApi: NcApi @@ -121,6 +129,10 @@ class ConversationInfoActivity : @Inject lateinit var dateUtils: DateUtils + lateinit var viewModel: ConversationInfoViewModel + + private lateinit var spreedCapabilities: SpreedCapability + private lateinit var conversationToken: String private lateinit var conversationUser: User private var hasAvatarSpacing: Boolean = false @@ -129,7 +141,9 @@ class ConversationInfoActivity : private var participantsDisposable: Disposable? = null private var databaseStorageModule: DatabaseStorageModule? = null - private var conversation: Conversation? = null + + // private var conversation: Conversation? = null + private var conversation: ConversationModel? = null private var adapter: FlexibleAdapter? = null private var userItems: MutableList = ArrayList() @@ -157,11 +171,26 @@ class ConversationInfoActivity : setContentView(binding.root) setupSystemColors() + viewModel = + ViewModelProvider(this, viewModelFactory)[ConversationInfoViewModel::class.java] + conversationUser = currentUserProvider.currentUser.blockingGet() conversationToken = intent.getStringExtra(BundleKeys.KEY_ROOM_TOKEN)!! hasAvatarSpacing = intent.getBooleanExtra(BundleKeys.KEY_ROOM_ONE_TO_ONE, false) - credentials = ApiUtils.getCredentials(conversationUser.username, conversationUser.token) + credentials = ApiUtils.getCredentials(conversationUser.username, conversationUser.token)!! + + initObservers() + } + + override fun onStart() { + super.onStart() + this.lifecycle.addObserver(ConversationInfoViewModel.LifeCycleObserver) + } + + override fun onStop() { + super.onStop() + this.lifecycle.removeObserver(ConversationInfoViewModel.LifeCycleObserver) } override fun onResume() { @@ -176,13 +205,7 @@ class ConversationInfoActivity : binding.clearConversationHistory.setOnClickListener { showClearHistoryDialog() } binding.addParticipantsAction.setOnClickListener { addParticipants() } - if (CapabilitiesUtilNew.hasSpreedFeatureCapability(conversationUser, "rich-object-list-media")) { - binding.sharedItemsButton.setOnClickListener { showSharedItems() } - } else { - binding.sharedItems.visibility = GONE - } - - fetchRoomInfo() + viewModel.getRoom(conversationUser, conversationToken) themeTextViews() themeSwitchPreferences() @@ -192,6 +215,35 @@ class ConversationInfoActivity : binding.progressBar.let { viewThemeUtils.platform.colorCircularProgressBar(it, ColorRole.PRIMARY) } } + private fun initObservers() { + viewModel.viewState.observe(this) { state -> + when (state) { + is ConversationInfoViewModel.GetRoomSuccessState -> { + conversation = state.conversationModel + viewModel.getCapabilities(conversationUser, conversationToken, conversation!!) + } + + is ConversationInfoViewModel.GetRoomErrorState -> { + Snackbar.make(binding.root, R.string.nc_common_error_sorry, Snackbar.LENGTH_LONG).show() + } + + else -> {} + } + } + + viewModel.getCapabilitiesViewState.observe(this) { state -> + when (state) { + is ConversationInfoViewModel.GetCapabilitiesSuccessState -> { + spreedCapabilities = state.spreedCapabilities + + handleConversation() + } + + else -> {} + } + } + } + private fun setupActionBar() { setSupportActionBar(binding.conversationInfoToolbar) binding.conversationInfoToolbar.setNavigationOnClickListener { @@ -217,7 +269,7 @@ class ConversationInfoActivity : fun showOptionsMenu() { if (::optionsMenu.isInitialized) { optionsMenu.clear() - if (CapabilitiesUtilNew.isConversationAvatarEndpointAvailable(conversationUser)) { + if (CapabilitiesUtil.hasSpreedFeatureCapability(spreedCapabilities, SpreedFeatures.AVATAR)) { menuInflater.inflate(R.menu.menu_conversation_info, optionsMenu) } } @@ -273,19 +325,22 @@ class ConversationInfoActivity : intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP) intent.putExtra(BundleKeys.KEY_CONVERSATION_NAME, conversation?.displayName) intent.putExtra(BundleKeys.KEY_ROOM_TOKEN, conversationToken) - intent.putExtra(SharedItemsActivity.KEY_USER_IS_OWNER_OR_MODERATOR, conversation?.isParticipantOwnerOrModerator) + intent.putExtra( + SharedItemsActivity.KEY_USER_IS_OWNER_OR_MODERATOR, + ConversationUtils.isParticipantOwnerOrModerator(conversation!!) + ) startActivity(intent) } private fun setupWebinaryView() { - if (CapabilitiesUtilNew.hasSpreedFeatureCapability(conversationUser, "webinary-lobby") && + if (CapabilitiesUtil.hasSpreedFeatureCapability(spreedCapabilities, SpreedFeatures.WEBINARY_LOBBY) && webinaryRoomType(conversation!!) && - conversation!!.canModerate(conversationUser) + ConversationUtils.canModerate(conversation!!, spreedCapabilities) ) { binding.webinarInfoView.webinarSettings.visibility = VISIBLE val isLobbyOpenToModeratorsOnly = - conversation!!.lobbyState == Conversation.LobbyState.LOBBY_STATE_MODERATORS_ONLY + conversation!!.lobbyState == LobbyState.LOBBY_STATE_MODERATORS_ONLY binding.webinarInfoView.lobbySwitch.isChecked = isLobbyOpenToModeratorsOnly reconfigureLobbyTimerView() @@ -320,9 +375,9 @@ class ConversationInfoActivity : } } - private fun webinaryRoomType(conversation: Conversation): Boolean { - return conversation.type == Conversation.ConversationType.ROOM_GROUP_CALL || - conversation.type == Conversation.ConversationType.ROOM_PUBLIC_CALL + private fun webinaryRoomType(conversation: ConversationModel): Boolean { + return conversation.type == ConversationType.ROOM_GROUP_CALL || + conversation.type == ConversationType.ROOM_PUBLIC_CALL } private fun reconfigureLobbyTimerView(dateTime: Calendar? = null) { @@ -337,9 +392,9 @@ class ConversationInfoActivity : } conversation!!.lobbyState = if (isChecked) { - Conversation.LobbyState.LOBBY_STATE_MODERATORS_ONLY + LobbyState.LOBBY_STATE_MODERATORS_ONLY } else { - Conversation.LobbyState.LOBBY_STATE_ALL_PARTICIPANTS + LobbyState.LOBBY_STATE_ALL_PARTICIPANTS } if ( @@ -370,11 +425,11 @@ class ConversationInfoActivity : 0 } - val apiVersion = ApiUtils.getConversationApiVersion(conversationUser, intArrayOf(ApiUtils.APIv4, 1)) + val apiVersion = ApiUtils.getConversationApiVersion(conversationUser, intArrayOf(ApiUtils.API_V4, 1)) ncApi.setLobbyForConversation( ApiUtils.getCredentials(conversationUser.username, conversationUser.token), - ApiUtils.getUrlForRoomWebinaryLobby(apiVersion, conversationUser.baseUrl, conversation!!.token), + ApiUtils.getUrlForRoomWebinaryLobby(apiVersion, conversationUser.baseUrl!!, conversation!!.token), state, conversation!!.lobbyTimer ) @@ -487,7 +542,7 @@ class ConversationInfoActivity : private fun getListOfParticipants() { // FIXME Fix API checking with guests? - val apiVersion: Int = ApiUtils.getConversationApiVersion(conversationUser, intArrayOf(ApiUtils.APIv4, 1)) + val apiVersion: Int = ApiUtils.getConversationApiVersion(conversationUser, intArrayOf(ApiUtils.API_V4, 1)) val fieldMap = HashMap() fieldMap["includeStatus"] = true @@ -496,7 +551,7 @@ class ConversationInfoActivity : credentials, ApiUtils.getUrlForParticipants( apiVersion, - conversationUser.baseUrl, + conversationUser.baseUrl!!, conversationToken ), fieldMap @@ -586,11 +641,11 @@ class ConversationInfoActivity : } private fun clearHistory() { - val apiVersion = ApiUtils.getChatApiVersion(conversationUser, intArrayOf(1)) + val apiVersion = ApiUtils.getChatApiVersion(spreedCapabilities, intArrayOf(1)) ncApi.clearChatHistory( credentials, - ApiUtils.getUrlForChat(apiVersion, conversationUser.baseUrl, conversationToken) + ApiUtils.getUrlForChat(apiVersion, conversationUser.baseUrl!!, conversationToken) ) ?.subscribeOn(Schedulers.io()) ?.observeOn(AndroidSchedulers.mainThread()) @@ -631,123 +686,99 @@ class ConversationInfoActivity : } } - private fun fetchRoomInfo() { - val apiVersion: Int - // FIXME Fix API checking with guests? - apiVersion = ApiUtils.getConversationApiVersion(conversationUser, intArrayOf(ApiUtils.APIv4, 1)) + @Suppress("LongMethod") + private fun handleConversation() { + val conversationCopy = conversation!! - ncApi.getRoom(credentials, ApiUtils.getUrlForRoom(apiVersion, conversationUser.baseUrl, conversationToken)) - ?.subscribeOn(Schedulers.io()) - ?.observeOn(AndroidSchedulers.mainThread()) - ?.subscribe(object : Observer { - override fun onSubscribe(d: Disposable) { - roomDisposable = d - } + if (CapabilitiesUtil.hasSpreedFeatureCapability(spreedCapabilities, SpreedFeatures.RICH_OBJECT_LIST_MEDIA)) { + binding.sharedItemsButton.setOnClickListener { showSharedItems() } + } else { + binding.sharedItems.visibility = GONE + } - @Suppress("Detekt.TooGenericExceptionCaught") - override fun onNext(roomOverall: RoomOverall) { - conversation = roomOverall.ocs!!.data + if (ConversationUtils.canModerate(conversationCopy, spreedCapabilities)) { + binding.addParticipantsAction.visibility = VISIBLE + if (CapabilitiesUtil.hasSpreedFeatureCapability( + spreedCapabilities, + SpreedFeatures.CLEAR_HISTORY + ) + ) { + binding.clearConversationHistory.visibility = VISIBLE + } else { + binding.clearConversationHistory.visibility = GONE + } + showOptionsMenu() + } else { + binding.addParticipantsAction.visibility = GONE - val conversationCopy = conversation + if (ConversationUtils.isNoteToSelfConversation(conversation)) { + binding.notificationSettingsView.notificationSettings.visibility = VISIBLE + } else { + binding.clearConversationHistory.visibility = GONE + } + } - if (conversationCopy!!.canModerate(conversationUser)) { - binding.addParticipantsAction.visibility = VISIBLE - if (CapabilitiesUtilNew.hasSpreedFeatureCapability( - conversationUser, - "clear-history" - ) - ) { - binding.clearConversationHistory.visibility = VISIBLE - } else { - binding.clearConversationHistory.visibility = GONE - } - showOptionsMenu() - } else { - binding.addParticipantsAction.visibility = GONE + if (!isDestroyed) { + binding.dangerZoneOptions.visibility = VISIBLE - if (ConversationUtils.isNoteToSelfConversation( - ConversationModel.mapToConversationModel(conversation!!) - ) - ) { - binding.notificationSettingsView.notificationSettings.visibility = VISIBLE - } else { - binding.clearConversationHistory.visibility = GONE - } - } + setupWebinaryView() - if (!isDestroyed) { - binding.dangerZoneOptions.visibility = VISIBLE + if (ConversationUtils.canLeave(conversation!!)) { + binding.leaveConversationAction.visibility = GONE + } else { + binding.leaveConversationAction.visibility = VISIBLE + } - setupWebinaryView() + if (ConversationUtils.canDelete(conversation!!, spreedCapabilities)) { + binding.deleteConversationAction.visibility = GONE + } else { + binding.deleteConversationAction.visibility = VISIBLE + } - if (!conversation!!.canLeave()) { - binding.leaveConversationAction.visibility = GONE - } else { - binding.leaveConversationAction.visibility = VISIBLE - } + if (ConversationType.ROOM_SYSTEM == conversation!!.type) { + binding.notificationSettingsView.callNotificationsSwitch.visibility = GONE + } - if (!conversation!!.canDelete(conversationUser)) { - binding.deleteConversationAction.visibility = GONE - } else { - binding.deleteConversationAction.visibility = VISIBLE - } + if (conversation!!.notificationCalls === null) { + binding.notificationSettingsView.callNotificationsSwitch.visibility = GONE + } else { + binding.notificationSettingsView.callNotificationsSwitch.isChecked = + (conversationCopy.notificationCalls == 1) + } - if (Conversation.ConversationType.ROOM_SYSTEM == conversation!!.type) { - binding.notificationSettingsView.callNotificationsSwitch.visibility = GONE - } + getListOfParticipants() - if (conversation!!.notificationCalls === null) { - binding.notificationSettingsView.callNotificationsSwitch.visibility = GONE - } else { - binding.notificationSettingsView.callNotificationsSwitch.isChecked = - (conversationCopy.notificationCalls == 1) - } + binding.progressBar.visibility = GONE - getListOfParticipants() + binding.conversationInfoName.visibility = VISIBLE - binding.progressBar.visibility = GONE + binding.displayNameText.text = conversation!!.displayName - binding.conversationInfoName.visibility = VISIBLE + if (conversation!!.description != null && conversation!!.description!!.isNotEmpty()) { + binding.descriptionText.text = conversation!!.description + binding.conversationDescription.visibility = VISIBLE + } - binding.displayNameText.text = conversation!!.displayName + loadConversationAvatar() + adjustNotificationLevelUI() + initRecordingConsentOption() + initExpiringMessageOption() - if (conversation!!.description != null && conversation!!.description!!.isNotEmpty()) { - binding.descriptionText.text = conversation!!.description - binding.conversationDescription.visibility = VISIBLE - } - - loadConversationAvatar() - adjustNotificationLevelUI() - initRecordingConsentOption() - initExpiringMessageOption() - - binding.let { - GuestAccessHelper( - this@ConversationInfoActivity, - it, - conversation!!, - conversationUser - ).setupGuestAccess() - } - if (ConversationUtils.isNoteToSelfConversation( - ConversationModel.mapToConversationModel(conversation!!) - ) - ) { - binding.notificationSettingsView.notificationSettings.visibility = GONE - } else { - binding.notificationSettingsView.notificationSettings.visibility = VISIBLE - } - } - } - - override fun onError(e: Throwable) { - Log.e(TAG, "failed to fetch room info", e) - } - - override fun onComplete() { - roomDisposable!!.dispose() - } - }) + binding.let { + GuestAccessHelper( + this@ConversationInfoActivity, + it, + conversation!!, + spreedCapabilities, + conversationUser + ).setupGuestAccess() + } + if (ConversationUtils.isNoteToSelfConversation(conversation!!)) { + binding.notificationSettingsView.notificationSettings.visibility = GONE + } else { + binding.notificationSettingsView.notificationSettings.visibility = VISIBLE + } + } } private fun initRecordingConsentOption() { @@ -781,13 +812,13 @@ class ConversationInfoActivity : } } - if (conversation!!.isParticipantOwnerOrModerator && - !ConversationUtils.isNoteToSelfConversation(ConversationModel.mapToConversationModel(conversation!!)) + if (ConversationUtils.isParticipantOwnerOrModerator(conversation!!) && + !ConversationUtils.isNoteToSelfConversation(conversation!!) ) { - when (CapabilitiesUtilNew.getRecordingConsentType(conversationUser)) { - CapabilitiesUtilNew.RECORDING_CONSENT_NOT_REQUIRED -> hide() - CapabilitiesUtilNew.RECORDING_CONSENT_REQUIRED -> showAlwaysRequiredInfo() - CapabilitiesUtilNew.RECORDING_CONSENT_DEPEND_ON_CONVERSATION -> showSwitch() + when (CapabilitiesUtil.getRecordingConsentType(spreedCapabilities)) { + CapabilitiesUtil.RECORDING_CONSENT_NOT_REQUIRED -> hide() + CapabilitiesUtil.RECORDING_CONSENT_REQUIRED -> showAlwaysRequiredInfo() + CapabilitiesUtil.RECORDING_CONSENT_DEPEND_ON_CONVERSATION -> showSwitch() } } else { hide() @@ -801,11 +832,11 @@ class ConversationInfoActivity : RECORDING_CONSENT_NOT_REQUIRED_FOR_CONVERSATION } - val apiVersion = ApiUtils.getConversationApiVersion(conversationUser, intArrayOf(ApiUtils.APIv4, 1)) + val apiVersion = ApiUtils.getConversationApiVersion(conversationUser, intArrayOf(ApiUtils.API_V4, 1)) ncApi.setRecordingConsent( ApiUtils.getCredentials(conversationUser.username, conversationUser.token), - ApiUtils.getUrlForRecordingConsent(apiVersion, conversationUser.baseUrl, conversation!!.token), + ApiUtils.getUrlForRecordingConsent(apiVersion, conversationUser.baseUrl!!, conversation!!.token), state ) ?.subscribeOn(Schedulers.io()) @@ -831,8 +862,8 @@ class ConversationInfoActivity : } private fun initExpiringMessageOption() { - if (conversation!!.isParticipantOwnerOrModerator && - CapabilitiesUtilNew.hasSpreedFeatureCapability(conversationUser, "message-expiration") + if (ConversationUtils.isParticipantOwnerOrModerator(conversation!!) && + CapabilitiesUtil.hasSpreedFeatureCapability(spreedCapabilities, SpreedFeatures.MESSAGE_EXPIRATION) ) { databaseStorageModule?.setMessageExpiration(conversation!!.messageExpiration) val value = databaseStorageModule!!.getString("conversation_settings_dropdown", "") @@ -855,13 +886,16 @@ class ConversationInfoActivity : private fun adjustNotificationLevelUI() { if (conversation != null) { - if (CapabilitiesUtilNew.hasSpreedFeatureCapability(conversationUser, "notification-levels")) { + if (CapabilitiesUtil.hasSpreedFeatureCapability(spreedCapabilities, SpreedFeatures.NOTIFICATION_LEVELS)) { binding.notificationSettingsView.conversationInfoMessageNotificationsDropdown.isEnabled = true binding.notificationSettingsView.conversationInfoMessageNotificationsDropdown.alpha = 1.0f - if (conversation!!.notificationLevel != Conversation.NotificationLevel.DEFAULT) { + if (conversation!!.notificationLevel != NotificationLevel.DEFAULT) { val stringValue: String = - when (EnumNotificationLevelConverter().convertToInt(conversation!!.notificationLevel)) { + when ( + DomainEnumNotificationLevelConverter() + .convertToInt(conversation!!.notificationLevel!!) + ) { NOTIFICATION_LEVEL_ALWAYS -> resources.getString(R.string.nc_notify_me_always) NOTIFICATION_LEVEL_MENTION -> resources.getString(R.string.nc_notify_me_mention) NOTIFICATION_LEVEL_NEVER -> resources.getString(R.string.nc_notify_me_never) @@ -885,9 +919,9 @@ class ConversationInfoActivity : } } - private fun setProperNotificationValue(conversation: Conversation?) { - if (conversation!!.type == Conversation.ConversationType.ROOM_TYPE_ONE_TO_ONE_CALL) { - if (CapabilitiesUtilNew.hasSpreedFeatureCapability(conversationUser, "mention-flag")) { + private fun setProperNotificationValue(conversation: ConversationModel?) { + if (conversation!!.type == ConversationType.ROOM_TYPE_ONE_TO_ONE_CALL) { + if (CapabilitiesUtil.hasSpreedFeatureCapability(spreedCapabilities, SpreedFeatures.MENTION_FLAG)) { binding.notificationSettingsView.conversationInfoMessageNotificationsDropdown.setText( resources.getString(R.string.nc_notify_me_always) ) @@ -905,7 +939,7 @@ class ConversationInfoActivity : private fun loadConversationAvatar() { when (conversation!!.type) { - Conversation.ConversationType.ROOM_TYPE_ONE_TO_ONE_CALL -> if (!TextUtils.isEmpty(conversation!!.name)) { + ConversationType.ROOM_TYPE_ONE_TO_ONE_CALL -> if (!TextUtils.isEmpty(conversation!!.name)) { conversation!!.name?.let { binding.avatarImage.loadUserAvatar( conversationUser, @@ -916,7 +950,7 @@ class ConversationInfoActivity : } } - Conversation.ConversationType.ROOM_GROUP_CALL, Conversation.ConversationType.ROOM_PUBLIC_CALL -> { + ConversationType.ROOM_GROUP_CALL, ConversationType.ROOM_PUBLIC_CALL -> { binding.avatarImage.loadConversationAvatar( conversationUser, conversation!!, @@ -925,15 +959,12 @@ class ConversationInfoActivity : ) } - Conversation.ConversationType.ROOM_SYSTEM -> { + ConversationType.ROOM_SYSTEM -> { binding.avatarImage.loadSystemAvatar() } - Conversation.ConversationType.DUMMY -> { - if (ConversationUtils.isNoteToSelfConversation( - ConversationModel.mapToConversationModel(conversation!!) - ) - ) { + ConversationType.DUMMY -> { + if (ConversationUtils.isNoteToSelfConversation(conversation!!)) { binding.avatarImage.loadNoteToSelfAvatar() } } @@ -971,7 +1002,7 @@ class ConversationInfoActivity : credentials, ApiUtils.getUrlForRoomModerators( apiVersion, - conversationUser.baseUrl, + conversationUser.baseUrl!!, conversation!!.token ), participant.attendeeId @@ -986,7 +1017,7 @@ class ConversationInfoActivity : credentials, ApiUtils.getUrlForRoomModerators( apiVersion, - conversationUser.baseUrl, + conversationUser.baseUrl!!, conversation!!.token ), participant.attendeeId @@ -1022,7 +1053,7 @@ class ConversationInfoActivity : credentials, ApiUtils.getUrlForRoomModerators( apiVersion, - conversationUser.baseUrl, + conversationUser.baseUrl!!, conversation!!.token ), participant.userId @@ -1035,7 +1066,7 @@ class ConversationInfoActivity : credentials, ApiUtils.getUrlForRoomModerators( apiVersion, - conversationUser.baseUrl, + conversationUser.baseUrl!!, conversation!!.token ), participant.userId @@ -1047,12 +1078,12 @@ class ConversationInfoActivity : } private fun removeAttendeeFromConversation(apiVersion: Int, participant: Participant) { - if (apiVersion >= ApiUtils.APIv4) { + if (apiVersion >= ApiUtils.API_V4) { ncApi.removeAttendeeFromConversation( credentials, ApiUtils.getUrlForAttendees( apiVersion, - conversationUser.baseUrl, + conversationUser.baseUrl!!, conversation!!.token ), participant.attendeeId @@ -1084,7 +1115,7 @@ class ConversationInfoActivity : ncApi.removeParticipantFromConversation( credentials, ApiUtils.getUrlForRemovingParticipantFromConversation( - conversationUser.baseUrl, + conversationUser.baseUrl!!, conversation!!.token, true ), @@ -1114,7 +1145,7 @@ class ConversationInfoActivity : ncApi.removeParticipantFromConversation( credentials, ApiUtils.getUrlForRemovingParticipantFromConversation( - conversationUser.baseUrl, + conversationUser.baseUrl!!, conversation!!.token, false ), @@ -1146,14 +1177,14 @@ class ConversationInfoActivity : @SuppressLint("CheckResult") override fun onItemClick(view: View?, position: Int): Boolean { - if (!conversation!!.canModerate(conversationUser)) { + if (ConversationUtils.canModerate(conversation!!, spreedCapabilities)) { return true } val userItem = adapter?.getItem(position) as ParticipantItem val participant = userItem.model - val apiVersion = ApiUtils.getConversationApiVersion(conversationUser, intArrayOf(ApiUtils.APIv4, 1)) + val apiVersion = ApiUtils.getConversationApiVersion(conversationUser, intArrayOf(ApiUtils.API_V4, 1)) if (participant.calculatedActorType == USERS && participant.calculatedActorId == conversationUser.userId) { if (participant.attendeePin?.isNotEmpty() == true) { @@ -1277,7 +1308,7 @@ class ConversationInfoActivity : // Pin, nothing to do } else if (actionToTrigger == 1) { // Promote/demote - if (apiVersion >= ApiUtils.APIv4) { + if (apiVersion >= ApiUtils.API_V4) { toggleModeratorStatus(apiVersion, participant) } else { toggleModeratorStatusLegacy(apiVersion, participant) diff --git a/app/src/main/java/com/nextcloud/talk/conversationinfo/GuestAccessHelper.kt b/app/src/main/java/com/nextcloud/talk/conversationinfo/GuestAccessHelper.kt index 4ec42f0ea..c5c5dcef0 100644 --- a/app/src/main/java/com/nextcloud/talk/conversationinfo/GuestAccessHelper.kt +++ b/app/src/main/java/com/nextcloud/talk/conversationinfo/GuestAccessHelper.kt @@ -11,8 +11,11 @@ import com.nextcloud.talk.R import com.nextcloud.talk.data.user.model.User import com.nextcloud.talk.databinding.ActivityConversationInfoBinding import com.nextcloud.talk.databinding.DialogPasswordBinding -import com.nextcloud.talk.models.json.conversations.Conversation +import com.nextcloud.talk.models.domain.ConversationModel +import com.nextcloud.talk.models.domain.ConversationType +import com.nextcloud.talk.models.json.capabilities.SpreedCapability import com.nextcloud.talk.repositories.conversations.ConversationsRepository +import com.nextcloud.talk.utils.ConversationUtils import com.nextcloud.talk.utils.Mimetype import com.nextcloud.talk.utils.ShareUtils import io.reactivex.Observer @@ -23,7 +26,8 @@ import io.reactivex.schedulers.Schedulers class GuestAccessHelper( private val activity: ConversationInfoActivity, private val binding: ActivityConversationInfoBinding, - private val conversation: Conversation, + private val conversation: ConversationModel, + private val spreedCapabilities: SpreedCapability, private val conversationUser: User ) { @@ -32,13 +36,13 @@ class GuestAccessHelper( private val context = activity.context fun setupGuestAccess() { - if (conversation.canModerate(conversationUser)) { + if (ConversationUtils.canModerate(conversation, spreedCapabilities)) { binding.guestAccessView.guestAccessSettings.visibility = View.VISIBLE } else { binding.guestAccessView.guestAccessSettings.visibility = View.GONE } - if (conversation.type == Conversation.ConversationType.ROOM_PUBLIC_CALL) { + if (conversation.type == ConversationType.ROOM_PUBLIC_CALL) { binding.guestAccessView.allowGuestsSwitch.isChecked = true showAllOptions() if (conversation.hasPassword) { diff --git a/app/src/main/java/com/nextcloud/talk/conversationinfo/viewmodel/ConversationInfoViewModel.kt b/app/src/main/java/com/nextcloud/talk/conversationinfo/viewmodel/ConversationInfoViewModel.kt new file mode 100644 index 000000000..c086f470f --- /dev/null +++ b/app/src/main/java/com/nextcloud/talk/conversationinfo/viewmodel/ConversationInfoViewModel.kt @@ -0,0 +1,142 @@ +/* + * Nextcloud Talk application + * + * @author Marcel Hibbe + * Copyright (C) 2023 Marcel Hibbe + * + * 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.conversationinfo.viewmodel + +import android.util.Log +import androidx.lifecycle.DefaultLifecycleObserver +import androidx.lifecycle.LifecycleOwner +import androidx.lifecycle.LiveData +import androidx.lifecycle.MutableLiveData +import androidx.lifecycle.ViewModel +import com.nextcloud.talk.chat.data.ChatRepository +import com.nextcloud.talk.data.user.model.User +import com.nextcloud.talk.models.domain.ConversationModel +import com.nextcloud.talk.models.json.capabilities.SpreedCapability +import io.reactivex.Observer +import io.reactivex.android.schedulers.AndroidSchedulers +import io.reactivex.disposables.Disposable +import io.reactivex.schedulers.Schedulers +import javax.inject.Inject + +class ConversationInfoViewModel @Inject constructor( + private val chatRepository: ChatRepository +) : ViewModel() { + + object LifeCycleObserver : DefaultLifecycleObserver { + enum class LifeCycleFlag { + PAUSED, + RESUMED + } + lateinit var currentLifeCycleFlag: LifeCycleFlag + public val disposableSet = mutableSetOf() + + override fun onResume(owner: LifecycleOwner) { + super.onResume(owner) + currentLifeCycleFlag = LifeCycleFlag.RESUMED + } + + override fun onPause(owner: LifecycleOwner) { + super.onPause(owner) + currentLifeCycleFlag = LifeCycleFlag.PAUSED + disposableSet.forEach { disposable -> disposable.dispose() } + disposableSet.clear() + } + } + + sealed interface ViewState + + object GetRoomStartState : ViewState + object GetRoomErrorState : ViewState + open class GetRoomSuccessState(val conversationModel: ConversationModel) : ViewState + + private val _viewState: MutableLiveData = MutableLiveData(GetRoomStartState) + val viewState: LiveData + get() = _viewState + + object GetCapabilitiesStartState : ViewState + object GetCapabilitiesErrorState : ViewState + open class GetCapabilitiesSuccessState(val spreedCapabilities: SpreedCapability) : ViewState + + private val _getCapabilitiesViewState: MutableLiveData = MutableLiveData(GetCapabilitiesStartState) + val getCapabilitiesViewState: LiveData + get() = _getCapabilitiesViewState + + fun getRoom(user: User, token: String) { + _viewState.value = GetRoomStartState + chatRepository.getRoom(user, token) + .subscribeOn(Schedulers.io()) + ?.observeOn(AndroidSchedulers.mainThread()) + ?.subscribe(GetRoomObserver()) + } + + fun getCapabilities(user: User, token: String, conversationModel: ConversationModel) { + _getCapabilitiesViewState.value = GetCapabilitiesStartState + + if (conversationModel.remoteServer.isNullOrEmpty()) { + _getCapabilitiesViewState.value = GetCapabilitiesSuccessState(user.capabilities!!.spreedCapability!!) + } else { + chatRepository.getCapabilities(user, token) + .subscribeOn(Schedulers.io()) + ?.observeOn(AndroidSchedulers.mainThread()) + ?.subscribe(object : Observer { + override fun onSubscribe(d: Disposable) { + LifeCycleObserver.disposableSet.add(d) + } + + override fun onNext(spreedCapabilities: SpreedCapability) { + _getCapabilitiesViewState.value = GetCapabilitiesSuccessState(spreedCapabilities) + } + + override fun onError(e: Throwable) { + Log.e(TAG, "Error when fetching spreed capabilities", e) + _getCapabilitiesViewState.value = GetCapabilitiesErrorState + } + + override fun onComplete() { + // unused atm + } + }) + } + } + + inner class GetRoomObserver : Observer { + override fun onSubscribe(d: Disposable) { + // unused atm + } + + override fun onNext(conversationModel: ConversationModel) { + _viewState.value = GetRoomSuccessState(conversationModel) + } + + override fun onError(e: Throwable) { + Log.e(TAG, "Error when fetching room") + _viewState.value = GetRoomErrorState + } + + override fun onComplete() { + // unused atm + } + } + + companion object { + private val TAG = ConversationInfoViewModel::class.simpleName + } +} diff --git a/app/src/main/java/com/nextcloud/talk/conversationinfoedit/ConversationInfoEditActivity.kt b/app/src/main/java/com/nextcloud/talk/conversationinfoedit/ConversationInfoEditActivity.kt index 6329b570d..e0cb22489 100644 --- a/app/src/main/java/com/nextcloud/talk/conversationinfoedit/ConversationInfoEditActivity.kt +++ b/app/src/main/java/com/nextcloud/talk/conversationinfoedit/ConversationInfoEditActivity.kt @@ -49,11 +49,12 @@ import com.nextcloud.talk.extensions.loadSystemAvatar import com.nextcloud.talk.extensions.loadUserAvatar import com.nextcloud.talk.models.domain.ConversationModel import com.nextcloud.talk.models.domain.ConversationType +import com.nextcloud.talk.models.json.capabilities.SpreedCapability import com.nextcloud.talk.models.json.generic.GenericOverall import com.nextcloud.talk.utils.ApiUtils +import com.nextcloud.talk.utils.CapabilitiesUtil import com.nextcloud.talk.utils.PickImage import com.nextcloud.talk.utils.bundle.BundleKeys -import com.nextcloud.talk.utils.database.user.CapabilitiesUtilNew import com.nextcloud.talk.utils.database.user.CurrentUserProviderNew import io.reactivex.Observer import io.reactivex.android.schedulers.AndroidSchedulers @@ -87,6 +88,8 @@ class ConversationInfoEditActivity : private lateinit var pickImage: PickImage + private lateinit var spreedCapabilities: SpreedCapability + override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) NextcloudTalkApplication.sharedApplication!!.componentApplication.inject(this) @@ -110,7 +113,7 @@ class ConversationInfoEditActivity : viewThemeUtils.material.colorTextInputLayout(binding.conversationNameInputLayout) viewThemeUtils.material.colorTextInputLayout(binding.conversationDescriptionInputLayout) - credentials = ApiUtils.getCredentials(conversationUser.username, conversationUser.token) + credentials = ApiUtils.getCredentials(conversationUser.username, conversationUser.token)!! pickImage = PickImage(this, conversationUser) @@ -127,13 +130,15 @@ class ConversationInfoEditActivity : is ConversationInfoEditViewModel.GetRoomSuccessState -> { conversation = state.conversationModel + spreedCapabilities = conversationUser.capabilities!!.spreedCapability!! + binding.conversationName.setText(conversation!!.displayName) if (conversation!!.description != null && conversation!!.description!!.isNotEmpty()) { binding.conversationDescription.setText(conversation!!.description) } - if (!CapabilitiesUtilNew.isConversationDescriptionEndpointAvailable(conversationUser)) { + if (!CapabilitiesUtil.isConversationDescriptionEndpointAvailable(spreedCapabilities)) { binding.conversationDescription.isEnabled = false } @@ -221,13 +226,13 @@ class ConversationInfoEditActivity : private fun saveConversationNameAndDescription() { val apiVersion = - ApiUtils.getConversationApiVersion(conversationUser, intArrayOf(ApiUtils.APIv4, ApiUtils.APIv1)) + ApiUtils.getConversationApiVersion(conversationUser, intArrayOf(ApiUtils.API_V4, ApiUtils.API_V1)) ncApi.renameRoom( credentials, ApiUtils.getUrlForRoom( apiVersion, - conversationUser.baseUrl, + conversationUser.baseUrl!!, conversation!!.token ), binding.conversationName.text.toString() @@ -241,7 +246,7 @@ class ConversationInfoEditActivity : } override fun onNext(genericOverall: GenericOverall) { - if (CapabilitiesUtilNew.isConversationDescriptionEndpointAvailable(conversationUser)) { + if (CapabilitiesUtil.isConversationDescriptionEndpointAvailable(spreedCapabilities)) { saveConversationDescription() } else { finish() @@ -265,13 +270,13 @@ class ConversationInfoEditActivity : fun saveConversationDescription() { val apiVersion = - ApiUtils.getConversationApiVersion(conversationUser, intArrayOf(ApiUtils.APIv4, ApiUtils.APIv1)) + ApiUtils.getConversationApiVersion(conversationUser, intArrayOf(ApiUtils.API_V4, ApiUtils.API_V1)) ncApi.setConversationDescription( credentials, ApiUtils.getUrlForConversationDescription( apiVersion, - conversationUser.baseUrl, + conversationUser.baseUrl!!, conversation!!.token ), binding.conversationDescription.text.toString() diff --git a/app/src/main/java/com/nextcloud/talk/conversationinfoedit/data/ConversationInfoEditRepositoryImpl.kt b/app/src/main/java/com/nextcloud/talk/conversationinfoedit/data/ConversationInfoEditRepositoryImpl.kt index 0a4f49e54..1e4530b31 100644 --- a/app/src/main/java/com/nextcloud/talk/conversationinfoedit/data/ConversationInfoEditRepositoryImpl.kt +++ b/app/src/main/java/com/nextcloud/talk/conversationinfoedit/data/ConversationInfoEditRepositoryImpl.kt @@ -36,9 +36,9 @@ class ConversationInfoEditRepositoryImpl(private val ncApi: NcApi, currentUserPr ConversationInfoEditRepository { val currentUser: User = currentUserProvider.currentUser.blockingGet() - val credentials: String = ApiUtils.getCredentials(currentUser.username, currentUser.token) + val credentials: String = ApiUtils.getCredentials(currentUser.username, currentUser.token)!! - val apiVersion = ApiUtils.getConversationApiVersion(currentUser, intArrayOf(ApiUtils.APIv4, ApiUtils.APIv3, 1)) + val apiVersion = ApiUtils.getConversationApiVersion(currentUser, intArrayOf(ApiUtils.API_V4, ApiUtils.API_V3, 1)) override fun uploadConversationAvatar(user: User, file: File, roomToken: String): Observable { val builder = MultipartBody.Builder() @@ -56,7 +56,7 @@ class ConversationInfoEditRepositoryImpl(private val ncApi: NcApi, currentUserPr return ncApi.uploadConversationAvatar( credentials, - ApiUtils.getUrlForConversationAvatar(1, user.baseUrl, roomToken), + ApiUtils.getUrlForConversationAvatar(1, user.baseUrl!!, roomToken), filePart ).map { ConversationModel.mapToConversationModel(it.ocs?.data!!) } } @@ -64,7 +64,7 @@ class ConversationInfoEditRepositoryImpl(private val ncApi: NcApi, currentUserPr override fun deleteConversationAvatar(user: User, roomToken: String): Observable { return ncApi.deleteConversationAvatar( credentials, - ApiUtils.getUrlForConversationAvatar(1, user.baseUrl, roomToken) + ApiUtils.getUrlForConversationAvatar(1, user.baseUrl!!, roomToken) ).map { ConversationModel.mapToConversationModel(it.ocs?.data!!) } } } diff --git a/app/src/main/java/com/nextcloud/talk/conversationlist/ConversationsListActivity.kt b/app/src/main/java/com/nextcloud/talk/conversationlist/ConversationsListActivity.kt index e2309f977..858f77fb7 100644 --- a/app/src/main/java/com/nextcloud/talk/conversationlist/ConversationsListActivity.kt +++ b/app/src/main/java/com/nextcloud/talk/conversationlist/ConversationsListActivity.kt @@ -115,6 +115,7 @@ import com.nextcloud.talk.ui.dialog.ConversationsListBottomDialog import com.nextcloud.talk.ui.dialog.FilterConversationFragment import com.nextcloud.talk.users.UserManager import com.nextcloud.talk.utils.ApiUtils +import com.nextcloud.talk.utils.SpreedFeatures import com.nextcloud.talk.utils.ClosedInterfaceImpl import com.nextcloud.talk.utils.FileUtils import com.nextcloud.talk.utils.Mimetype @@ -130,10 +131,10 @@ import com.nextcloud.talk.utils.bundle.BundleKeys.KEY_NEW_CONVERSATION import com.nextcloud.talk.utils.bundle.BundleKeys.KEY_ROOM_ID import com.nextcloud.talk.utils.bundle.BundleKeys.KEY_ROOM_TOKEN import com.nextcloud.talk.utils.bundle.BundleKeys.KEY_SHARED_TEXT -import com.nextcloud.talk.utils.database.user.CapabilitiesUtilNew.hasSpreedFeatureCapability -import com.nextcloud.talk.utils.database.user.CapabilitiesUtilNew.isServerEOL -import com.nextcloud.talk.utils.database.user.CapabilitiesUtilNew.isUnifiedSearchAvailable -import com.nextcloud.talk.utils.database.user.CapabilitiesUtilNew.isUserStatusAvailable +import com.nextcloud.talk.utils.CapabilitiesUtil.hasSpreedFeatureCapability +import com.nextcloud.talk.utils.CapabilitiesUtil.isServerEOL +import com.nextcloud.talk.utils.CapabilitiesUtil.isUnifiedSearchAvailable +import com.nextcloud.talk.utils.CapabilitiesUtil.isUserStatusAvailable import com.nextcloud.talk.utils.permissions.PlatformPermissionUtil import com.nextcloud.talk.utils.power.PowerManagerUtils import com.nextcloud.talk.utils.rx.SearchViewObservable.Companion.observeSearchView @@ -283,11 +284,11 @@ class ConversationsListActivity : } currentUser = userManager.currentUser.blockingGet() if (currentUser != null) { - if (isServerEOL(currentUser!!.capabilities)) { + if (isServerEOL(currentUser!!.serverVersion!!.major)) { showServerEOLDialog() return } - if (isUnifiedSearchAvailable(currentUser!!)) { + if (isUnifiedSearchAvailable(currentUser!!.capabilities!!.spreedCapability!!)) { searchHelper = MessageSearchHelper(unifiedSearchRepository) } credentials = ApiUtils.getCredentials(currentUser!!.username, currentUser!!.token) @@ -423,7 +424,7 @@ class ConversationsListActivity : private fun loadUserAvatar(target: Target) { if (currentUser != null) { val url = ApiUtils.getUrlForAvatar( - currentUser!!.baseUrl, + currentUser!!.baseUrl!!, currentUser!!.userId, true ) @@ -433,7 +434,7 @@ class ConversationsListActivity : context.imageLoader.enqueue( ImageRequest.Builder(context) .data(url) - .addHeader("Authorization", credentials) + .addHeader("Authorization", credentials!!) .placeholder(R.drawable.ic_user) .transformations(CircleCropTransformation()) .crossfade(true) @@ -698,7 +699,10 @@ class ConversationsListActivity : isRefreshing = true conversationItems = ArrayList() conversationItemsWithHeader = ArrayList() - val apiVersion = ApiUtils.getConversationApiVersion(currentUser, intArrayOf(ApiUtils.APIv4, ApiUtils.APIv3, 1)) + val apiVersion = ApiUtils.getConversationApiVersion( + currentUser!!, + intArrayOf(ApiUtils.API_V4, ApiUtils.API_V3, 1) + ) val startNanoTime = System.nanoTime() Log.d(TAG, "fetchData - getRooms - calling: $startNanoTime") roomsQueryDisposable = ncApi.getRooms( @@ -868,11 +872,15 @@ class ConversationsListActivity : private fun fetchOpenConversations(apiVersion: Int) { searchableConversationItems.clear() searchableConversationItems.addAll(conversationItemsWithHeader) - if (hasSpreedFeatureCapability(currentUser, "listable-rooms")) { + if (hasSpreedFeatureCapability( + currentUser!!.capabilities!!.spreedCapability!!, + SpreedFeatures.LISTABLE_ROOMS + ) + ) { val openConversationItems: MutableList> = ArrayList() openConversationsQueryDisposable = ncApi.getOpenConversations( credentials, - ApiUtils.getUrlForOpenConversations(apiVersion, currentUser!!.baseUrl) + ApiUtils.getUrlForOpenConversations(apiVersion, currentUser!!.baseUrl!!) ) .subscribeOn(Schedulers.io()) .observeOn(AndroidSchedulers.mainThread()) @@ -1087,7 +1095,7 @@ class ConversationsListActivity : clearMessageSearchResults() adapter!!.setFilter(filter) adapter!!.filterItems() - if (isUnifiedSearchAvailable(currentUser!!)) { + if (isUnifiedSearchAvailable(currentUser!!.capabilities!!.spreedCapability!!)) { startMessageSearch(filter) } } else { @@ -1173,7 +1181,11 @@ class ConversationsListActivity : private fun handleConversation(conversation: Conversation?) { selectedConversation = conversation if (selectedConversation != null) { - val hasChatPermission = ParticipantPermissions(currentUser!!, selectedConversation!!).hasChatPermission() + val hasChatPermission = ParticipantPermissions( + currentUser!!.capabilities!!.spreedCapability!!, + selectedConversation!! + ) + .hasChatPermission() if (showShareToScreen) { if (hasChatPermission && !isReadOnlyConversation(selectedConversation!!) && @@ -1197,7 +1209,10 @@ class ConversationsListActivity : } private fun shouldShowLobby(conversation: Conversation): Boolean { - val participantPermissions = ParticipantPermissions(currentUser!!, conversation) + val participantPermissions = ParticipantPermissions( + currentUser!!.capabilities?.spreedCapability!!, + conversation + ) return conversation.lobbyState == Conversation.LobbyState.LOBBY_STATE_MODERATORS_ONLY && !conversation.canModerate(currentUser!!) && !participantPermissions.canIgnoreLobby() @@ -1511,7 +1526,7 @@ class ConversationsListActivity : .setNegativeButton(R.string.nc_settings_reauthorize) { _, _ -> val intent = Intent(context, WebViewLoginActivity::class.java) val bundle = Bundle() - bundle.putString(BundleKeys.KEY_BASE_URL, currentUser!!.baseUrl) + bundle.putString(BundleKeys.KEY_BASE_URL, currentUser!!.baseUrl!!) bundle.putBoolean(BundleKeys.KEY_REAUTHORIZE_ACCOUNT, true) intent.putExtras(bundle) startActivity(intent) diff --git a/app/src/main/java/com/nextcloud/talk/dagger/modules/ViewModelModule.kt b/app/src/main/java/com/nextcloud/talk/dagger/modules/ViewModelModule.kt index e9ddd400b..140500b23 100644 --- a/app/src/main/java/com/nextcloud/talk/dagger/modules/ViewModelModule.kt +++ b/app/src/main/java/com/nextcloud/talk/dagger/modules/ViewModelModule.kt @@ -27,6 +27,7 @@ import com.nextcloud.talk.callnotification.viewmodel.CallNotificationViewModel import com.nextcloud.talk.chat.viewmodels.ChatViewModel import com.nextcloud.talk.conversation.viewmodel.ConversationViewModel import com.nextcloud.talk.conversation.viewmodel.RenameConversationViewModel +import com.nextcloud.talk.conversationinfo.viewmodel.ConversationInfoViewModel import com.nextcloud.talk.conversationinfoedit.viewmodel.ConversationInfoEditViewModel import com.nextcloud.talk.conversationlist.viewmodels.ConversationsListViewModel import com.nextcloud.talk.invitation.viewmodels.InvitationsViewModel @@ -137,6 +138,11 @@ abstract class ViewModelModule { @ViewModelKey(CallNotificationViewModel::class) abstract fun callNotificationViewModel(viewModel: CallNotificationViewModel): ViewModel + @Binds + @IntoMap + @ViewModelKey(ConversationInfoViewModel::class) + abstract fun conversationInfoViewModel(viewModel: ConversationInfoViewModel): ViewModel + @Binds @IntoMap @ViewModelKey(ConversationInfoEditViewModel::class) diff --git a/app/src/main/java/com/nextcloud/talk/data/user/UserMapper.kt b/app/src/main/java/com/nextcloud/talk/data/user/UserMapper.kt index 48ef06e98..d6f5a1e2b 100644 --- a/app/src/main/java/com/nextcloud/talk/data/user/UserMapper.kt +++ b/app/src/main/java/com/nextcloud/talk/data/user/UserMapper.kt @@ -36,7 +36,7 @@ object UserMapper { entity.id, entity.userId, entity.username, - entity.baseUrl, + entity.baseUrl!!, entity.token, entity.displayName, entity.pushConfigurationState, @@ -52,8 +52,8 @@ object UserMapper { fun toEntity(model: User): UserEntity { val userEntity = when (val id = model.id) { - null -> UserEntity(userId = model.userId, username = model.username, baseUrl = model.baseUrl) - else -> UserEntity(id, model.userId, model.username, model.baseUrl) + null -> UserEntity(userId = model.userId, username = model.username, baseUrl = model.baseUrl!!) + else -> UserEntity(id, model.userId, model.username, model.baseUrl!!) } userEntity.apply { token = model.token diff --git a/app/src/main/java/com/nextcloud/talk/data/user/model/User.kt b/app/src/main/java/com/nextcloud/talk/data/user/model/User.kt index a10b55705..4ce808e3e 100644 --- a/app/src/main/java/com/nextcloud/talk/data/user/model/User.kt +++ b/app/src/main/java/com/nextcloud/talk/data/user/model/User.kt @@ -45,7 +45,7 @@ data class User( var scheduledForDeletion: Boolean = FALSE ) : Parcelable { - fun getCredentials(): String = ApiUtils.getCredentials(username, token) + fun getCredentials(): String = ApiUtils.getCredentials(username, token)!! fun hasSpreedFeatureCapability(capabilityName: String): Boolean { return capabilities?.spreedCapability?.features?.contains(capabilityName) ?: false diff --git a/app/src/main/java/com/nextcloud/talk/extensions/ImageViewExtensions.kt b/app/src/main/java/com/nextcloud/talk/extensions/ImageViewExtensions.kt index b16e30419..377d51d1f 100644 --- a/app/src/main/java/com/nextcloud/talk/extensions/ImageViewExtensions.kt +++ b/app/src/main/java/com/nextcloud/talk/extensions/ImageViewExtensions.kt @@ -118,7 +118,7 @@ fun ImageView.loadUserAvatar( ignoreCache: Boolean ): io.reactivex.disposables.Disposable { val imageRequestUri = ApiUtils.getUrlForAvatar( - user.baseUrl, + user.baseUrl!!, avatarId, requestBigSize ) @@ -155,7 +155,7 @@ private fun ImageView.loadAvatarInternal( user?.let { addHeader( "Authorization", - ApiUtils.getCredentials(user.username, user.token) + ApiUtils.getCredentials(user.username, user.token)!! ) } transformations(CircleCropTransformation()) @@ -196,7 +196,7 @@ fun ImageView.loadThumbnail(url: String, user: User): io.reactivex.disposables.D ) { requestBuilder.addHeader( "Authorization", - ApiUtils.getCredentials(user.username, user.token) + ApiUtils.getCredentials(user.username, user.token)!! ) } @@ -222,7 +222,7 @@ fun ImageView.loadImage(url: String, user: User, placeholder: Drawable? = null): ) { requestBuilder.addHeader( "Authorization", - ApiUtils.getCredentials(user.username, user.token) + ApiUtils.getCredentials(user.username, user.token)!! ) } diff --git a/app/src/main/java/com/nextcloud/talk/invitation/data/InvitationsRepositoryImpl.kt b/app/src/main/java/com/nextcloud/talk/invitation/data/InvitationsRepositoryImpl.kt index 6429db880..4ec9d9b59 100644 --- a/app/src/main/java/com/nextcloud/talk/invitation/data/InvitationsRepositoryImpl.kt +++ b/app/src/main/java/com/nextcloud/talk/invitation/data/InvitationsRepositoryImpl.kt @@ -29,29 +29,29 @@ class InvitationsRepositoryImpl(private val ncApi: NcApi) : InvitationsRepository { override fun fetchInvitations(user: User): Observable { - val credentials: String = ApiUtils.getCredentials(user.username, user.token) + val credentials: String = ApiUtils.getCredentials(user.username, user.token)!! return ncApi.getInvitations( credentials, - ApiUtils.getUrlForInvitation(user.baseUrl) + ApiUtils.getUrlForInvitation(user.baseUrl!!) ).map { mapToInvitationsModel(user, it.ocs?.data!!) } } override fun acceptInvitation(user: User, invitation: Invitation): Observable { - val credentials: String = ApiUtils.getCredentials(user.username, user.token) + val credentials: String = ApiUtils.getCredentials(user.username, user.token)!! return ncApi.acceptInvitation( credentials, - ApiUtils.getUrlForInvitationAccept(user.baseUrl, invitation.id) + ApiUtils.getUrlForInvitationAccept(user.baseUrl!!, invitation.id) ).map { InvitationActionModel(ActionEnum.ACCEPT, it.ocs?.meta?.statusCode!!, invitation) } } override fun rejectInvitation(user: User, invitation: Invitation): Observable { - val credentials: String = ApiUtils.getCredentials(user.username, user.token) + val credentials: String = ApiUtils.getCredentials(user.username, user.token)!! return ncApi.rejectInvitation( credentials, - ApiUtils.getUrlForInvitationReject(user.baseUrl, invitation.id) + ApiUtils.getUrlForInvitationReject(user.baseUrl!!, invitation.id) ).map { InvitationActionModel(ActionEnum.REJECT, it.ocs?.meta?.statusCode!!, invitation) } } diff --git a/app/src/main/java/com/nextcloud/talk/jobs/AddParticipantsToConversation.java b/app/src/main/java/com/nextcloud/talk/jobs/AddParticipantsToConversation.java index 407ce8bca..03e14c8c3 100644 --- a/app/src/main/java/com/nextcloud/talk/jobs/AddParticipantsToConversation.java +++ b/app/src/main/java/com/nextcloud/talk/jobs/AddParticipantsToConversation.java @@ -70,7 +70,7 @@ public class AddParticipantsToConversation extends Worker { data.getLong(BundleKeys.KEY_INTERNAL_USER_ID, -1)) .blockingGet(); - int apiVersion = ApiUtils.getConversationApiVersion(user, new int[] {ApiUtils.APIv4, 1}); + int apiVersion = ApiUtils.getConversationApiVersion(user, new int[] {ApiUtils.API_V4, 1}); String conversationToken = data.getString(BundleKeys.KEY_TOKEN); String credentials = ApiUtils.getCredentials(user.getUsername(), user.getToken()); diff --git a/app/src/main/java/com/nextcloud/talk/jobs/ContactAddressBookWorker.kt b/app/src/main/java/com/nextcloud/talk/jobs/ContactAddressBookWorker.kt index c55949eec..0e089bca2 100644 --- a/app/src/main/java/com/nextcloud/talk/jobs/ContactAddressBookWorker.kt +++ b/app/src/main/java/com/nextcloud/talk/jobs/ContactAddressBookWorker.kt @@ -129,7 +129,7 @@ class ContactAddressBookWorker(val context: Context, workerParameters: WorkerPar ncApi.searchContactsByPhoneNumber( ApiUtils.getCredentials(currentUser.username, currentUser.token), - ApiUtils.getUrlForSearchByNumber(currentUser.baseUrl), + ApiUtils.getUrlForSearchByNumber(currentUser.baseUrl!!), json.toRequestBody("application/json".toMediaTypeOrNull()) ) .subscribeOn(Schedulers.io()) diff --git a/app/src/main/java/com/nextcloud/talk/jobs/DeleteConversationWorker.java b/app/src/main/java/com/nextcloud/talk/jobs/DeleteConversationWorker.java index 16e5851b6..fd953c82f 100644 --- a/app/src/main/java/com/nextcloud/talk/jobs/DeleteConversationWorker.java +++ b/app/src/main/java/com/nextcloud/talk/jobs/DeleteConversationWorker.java @@ -80,7 +80,7 @@ public class DeleteConversationWorker extends Worker { User operationUser = userManager.getUserWithId(operationUserId).blockingGet(); if (operationUser != null) { - int apiVersion = ApiUtils.getConversationApiVersion(operationUser, new int[]{ApiUtils.APIv4, 1}); + int apiVersion = ApiUtils.getConversationApiVersion(operationUser, new int[]{ApiUtils.API_V4, 1}); String credentials = ApiUtils.getCredentials(operationUser.getUsername(), operationUser.getToken()); ncApi = retrofit diff --git a/app/src/main/java/com/nextcloud/talk/jobs/LeaveConversationWorker.java b/app/src/main/java/com/nextcloud/talk/jobs/LeaveConversationWorker.java index 87b15e690..946bdf52d 100644 --- a/app/src/main/java/com/nextcloud/talk/jobs/LeaveConversationWorker.java +++ b/app/src/main/java/com/nextcloud/talk/jobs/LeaveConversationWorker.java @@ -92,7 +92,7 @@ public class LeaveConversationWorker extends Worker { EventStatus.EventType.CONVERSATION_UPDATE, true); - int apiVersion = ApiUtils.getConversationApiVersion(operationUser, new int[] {ApiUtils.APIv4, 1}); + int apiVersion = ApiUtils.getConversationApiVersion(operationUser, new int[] {ApiUtils.API_V4, 1}); ncApi.removeSelfFromRoom(credentials, ApiUtils.getUrlForParticipantsSelf(apiVersion, operationUser.getBaseUrl(), diff --git a/app/src/main/java/com/nextcloud/talk/jobs/NotificationWorker.kt b/app/src/main/java/com/nextcloud/talk/jobs/NotificationWorker.kt index 7057eb375..07a92ac64 100644 --- a/app/src/main/java/com/nextcloud/talk/jobs/NotificationWorker.kt +++ b/app/src/main/java/com/nextcloud/talk/jobs/NotificationWorker.kt @@ -248,7 +248,7 @@ class NotificationWorker(context: Context, workerParams: WorkerParameters) : Wor val soundUri = getCallRingtoneUri(applicationContext, appPreferences) val notificationChannelId = NotificationUtils.NotificationChannels.NOTIFICATION_CHANNEL_CALLS_V4.name - val uri = Uri.parse(signatureVerification.user!!.baseUrl) + val uri = Uri.parse(signatureVerification.user!!.baseUrl!!) val baseUrl = uri.host val notification = @@ -279,7 +279,7 @@ class NotificationWorker(context: Context, workerParams: WorkerParameters) : Wor credentials = ApiUtils.getCredentials( signatureVerification.user!!.username, signatureVerification.user!!.token - ) + )!! ncApi = retrofit!!.newBuilder().client( okHttpClient!!.newBuilder().cookieJar( JavaNetCookieJar( @@ -338,7 +338,7 @@ class NotificationWorker(context: Context, workerParams: WorkerParameters) : Wor ncApi.getNcNotification( credentials, ApiUtils.getUrlForNcNotificationWithId( - user!!.baseUrl, + user!!.baseUrl!!, (pushMessage.notificationId!!).toString() ) ) @@ -451,7 +451,7 @@ class NotificationWorker(context: Context, workerParams: WorkerParameters) : Wor 0 } val pendingIntent = PendingIntent.getActivity(context, requestCode, intent, intentFlag) - val uri = Uri.parse(signatureVerification.user!!.baseUrl) + val uri = Uri.parse(signatureVerification.user!!.baseUrl!!) val baseUrl = uri.host var contentTitle: CharSequence? = "" @@ -601,12 +601,12 @@ class NotificationWorker(context: Context, workerParams: WorkerParameters) : Wor val baseUrl = signatureVerification.user!!.baseUrl val avatarUrl = if ("user" == userType) { ApiUtils.getUrlForAvatar( - baseUrl, + baseUrl!!, notificationUser.id, false ) } else { - ApiUtils.getUrlForGuestAvatar(baseUrl, notificationUser.name, false) + ApiUtils.getUrlForGuestAvatar(baseUrl!!, notificationUser.name, false) } person.setIcon(loadAvatarSync(avatarUrl, context!!)) } @@ -840,8 +840,8 @@ class NotificationWorker(context: Context, workerParams: WorkerParameters) : Wor var inCallOnDifferentDevice = false val apiVersion = ApiUtils.getConversationApiVersion( - signatureVerification.user, - intArrayOf(ApiUtils.APIv4, 1) + signatureVerification.user!!, + intArrayOf(ApiUtils.API_V4, 1) ) var isCallNotificationVisible = true @@ -850,8 +850,8 @@ class NotificationWorker(context: Context, workerParams: WorkerParameters) : Wor credentials, ApiUtils.getUrlForCall( apiVersion, - signatureVerification.user!!.baseUrl, - pushMessage.id + signatureVerification.user!!.baseUrl!!, + pushMessage.id!! ) ) .repeatWhen { completed -> @@ -920,10 +920,10 @@ class NotificationWorker(context: Context, workerParams: WorkerParameters) : Wor if (isOngoingCallNotificationVisible) { val apiVersion = ApiUtils.getConversationApiVersion( - signatureVerification.user, + signatureVerification.user!!, intArrayOf( - ApiUtils.APIv4, - ApiUtils.APIv3, + ApiUtils.API_V4, + ApiUtils.API_V3, 1 ) ) @@ -931,7 +931,7 @@ class NotificationWorker(context: Context, workerParams: WorkerParameters) : Wor credentials, ApiUtils.getUrlForRoom( apiVersion, - signatureVerification.user?.baseUrl, + signatureVerification.user?.baseUrl!!, pushMessage.id ) ) diff --git a/app/src/main/java/com/nextcloud/talk/jobs/ShareOperationWorker.kt b/app/src/main/java/com/nextcloud/talk/jobs/ShareOperationWorker.kt index 45b3cae47..c29d1824c 100644 --- a/app/src/main/java/com/nextcloud/talk/jobs/ShareOperationWorker.kt +++ b/app/src/main/java/com/nextcloud/talk/jobs/ShareOperationWorker.kt @@ -62,7 +62,7 @@ class ShareOperationWorker(context: Context, workerParams: WorkerParameters) : W for (filePath in filesArray) { ncApi.createRemoteShare( credentials, - ApiUtils.getSharingUrl(baseUrl), + ApiUtils.getSharingUrl(baseUrl!!), filePath, roomToken, "10", @@ -87,7 +87,7 @@ class ShareOperationWorker(context: Context, workerParams: WorkerParameters) : W val operationsUser = userManager.getUserWithId(userId).blockingGet() baseUrl = operationsUser.baseUrl - credentials = ApiUtils.getCredentials(operationsUser.username, operationsUser.token) + credentials = ApiUtils.getCredentials(operationsUser.username, operationsUser.token)!! } companion object { diff --git a/app/src/main/java/com/nextcloud/talk/jobs/SignalingSettingsWorker.java b/app/src/main/java/com/nextcloud/talk/jobs/SignalingSettingsWorker.java index a0e4e7d07..6b53c6114 100644 --- a/app/src/main/java/com/nextcloud/talk/jobs/SignalingSettingsWorker.java +++ b/app/src/main/java/com/nextcloud/talk/jobs/SignalingSettingsWorker.java @@ -85,7 +85,7 @@ public class SignalingSettingsWorker extends Worker { for (User user : userEntityObjectList) { - int apiVersion = ApiUtils.getSignalingApiVersion(user, new int[] {ApiUtils.APIv3, 2, 1}); + int apiVersion = ApiUtils.getSignalingApiVersion(user, new int[] {ApiUtils.API_V3, 2, 1}); ncApi.getSignalingSettings( ApiUtils.getCredentials(user.getUsername(), user.getToken()), diff --git a/app/src/main/java/com/nextcloud/talk/jobs/UploadAndShareFilesWorker.kt b/app/src/main/java/com/nextcloud/talk/jobs/UploadAndShareFilesWorker.kt index f171b8f62..5f20742fc 100644 --- a/app/src/main/java/com/nextcloud/talk/jobs/UploadAndShareFilesWorker.kt +++ b/app/src/main/java/com/nextcloud/talk/jobs/UploadAndShareFilesWorker.kt @@ -56,7 +56,7 @@ import com.nextcloud.talk.utils.RemoteFileUtils import com.nextcloud.talk.utils.bundle.BundleKeys.KEY_FROM_NOTIFICATION_START_CALL import com.nextcloud.talk.utils.bundle.BundleKeys.KEY_INTERNAL_USER_ID import com.nextcloud.talk.utils.bundle.BundleKeys.KEY_ROOM_TOKEN -import com.nextcloud.talk.utils.database.user.CapabilitiesUtilNew +import com.nextcloud.talk.utils.CapabilitiesUtil import com.nextcloud.talk.utils.permissions.PlatformPermissionUtil import com.nextcloud.talk.utils.preferences.AppPreferences import okhttp3.MediaType.Companion.toMediaTypeOrNull @@ -186,7 +186,9 @@ class UploadAndShareFilesWorker(val context: Context, workerParameters: WorkerPa } private fun getRemotePath(currentUser: User): String { - var remotePath = CapabilitiesUtilNew.getAttachmentFolder(currentUser)!! + "/" + fileName + var remotePath = CapabilitiesUtil.getAttachmentFolder( + currentUser.capabilities!!.spreedCapability!! + ) + "/" + fileName remotePath = RemoteFileUtils.getNewPathIfFileExists( ncApi, currentUser, diff --git a/app/src/main/java/com/nextcloud/talk/location/GeocodingActivity.kt b/app/src/main/java/com/nextcloud/talk/location/GeocodingActivity.kt index 1ecc4769f..71ae0e931 100644 --- a/app/src/main/java/com/nextcloud/talk/location/GeocodingActivity.kt +++ b/app/src/main/java/com/nextcloud/talk/location/GeocodingActivity.kt @@ -64,6 +64,7 @@ class GeocodingActivity : lateinit var okHttpClient: OkHttpClient lateinit var roomToken: String + private var chatApiVersion: Int = 1 private var nominatimClient: TalkJsonNominatimClient? = null private var searchItem: MenuItem? = null @@ -86,6 +87,7 @@ class GeocodingActivity : Configuration.getInstance().load(context, PreferenceManager.getDefaultSharedPreferences(context)) roomToken = intent.getStringExtra(BundleKeys.KEY_ROOM_TOKEN)!! + chatApiVersion = intent.getIntExtra(BundleKeys.KEY_CHAT_API_VERSION, 1) recyclerView = findViewById(R.id.geocoding_results) recyclerView.layoutManager = LinearLayoutManager(this) @@ -130,6 +132,7 @@ class GeocodingActivity : val intent = Intent(this@GeocodingActivity, LocationPickerActivity::class.java) intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP) intent.putExtra(BundleKeys.KEY_ROOM_TOKEN, roomToken) + intent.putExtra(BundleKeys.KEY_CHAT_API_VERSION, chatApiVersion) intent.putExtra(BundleKeys.KEY_GEOCODING_RESULT, geocodingResult) startActivity(intent) } @@ -158,6 +161,7 @@ class GeocodingActivity : val intent = Intent(this@GeocodingActivity, LocationPickerActivity::class.java) intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP) intent.putExtra(BundleKeys.KEY_ROOM_TOKEN, roomToken) + intent.putExtra(BundleKeys.KEY_CHAT_API_VERSION, chatApiVersion) intent.putExtra(BundleKeys.KEY_GEOCODING_RESULT, geocodingResult) startActivity(intent) } @@ -217,6 +221,7 @@ class GeocodingActivity : val intent = Intent(context, LocationPickerActivity::class.java) intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP) intent.putExtra(BundleKeys.KEY_ROOM_TOKEN, roomToken) + intent.putExtra(BundleKeys.KEY_CHAT_API_VERSION, chatApiVersion) startActivity(intent) return true } 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 c93de415a..d80c7492b 100644 --- a/app/src/main/java/com/nextcloud/talk/location/LocationPickerActivity.kt +++ b/app/src/main/java/com/nextcloud/talk/location/LocationPickerActivity.kt @@ -58,6 +58,7 @@ import com.nextcloud.talk.users.UserManager import com.nextcloud.talk.utils.ApiUtils import com.nextcloud.talk.utils.DisplayUtils import com.nextcloud.talk.utils.bundle.BundleKeys +import com.nextcloud.talk.utils.bundle.BundleKeys.KEY_CHAT_API_VERSION import com.nextcloud.talk.utils.bundle.BundleKeys.KEY_GEOCODING_RESULT import com.nextcloud.talk.utils.bundle.BundleKeys.KEY_ROOM_TOKEN import fr.dudie.nominatim.client.TalkJsonNominatimClient @@ -103,6 +104,7 @@ class LocationPickerActivity : var nominatimClient: TalkJsonNominatimClient? = null lateinit var roomToken: String + private var chatApiVersion: Int = 1 var geocodingResult: GeocodingResult? = null var myLocation: GeoPoint = GeoPoint(COORDINATE_ZERO, COORDINATE_ZERO) @@ -130,6 +132,7 @@ class LocationPickerActivity : NextcloudTalkApplication.sharedApplication!!.componentApplication.inject(this) roomToken = intent.getStringExtra(KEY_ROOM_TOKEN)!! + chatApiVersion = intent.getIntExtra(KEY_CHAT_API_VERSION, 1) geocodingResult = intent.getParcelableExtra(KEY_GEOCODING_RESULT) if (savedInstanceState != null) { @@ -244,6 +247,7 @@ class LocationPickerActivity : val intent = Intent(this, GeocodingActivity::class.java) intent.putExtra(BundleKeys.KEY_GEOCODING_QUERY, query) intent.putExtra(KEY_ROOM_TOKEN, roomToken) + intent.putExtra(KEY_CHAT_API_VERSION, chatApiVersion) startActivity(intent) } return true @@ -465,11 +469,10 @@ class LocationPickerActivity : "\"longitude\":\"$selectedLon\",\"name\":\"$locationNameToShare\"}" val currentUser = userManager.currentUser.blockingGet() - val apiVersion = ApiUtils.getChatApiVersion(currentUser, intArrayOf(1)) ncApi.sendLocation( ApiUtils.getCredentials(currentUser.username, currentUser.token), - ApiUtils.getUrlToSendLocation(apiVersion, currentUser.baseUrl, roomToken), + ApiUtils.getUrlToSendLocation(chatApiVersion, currentUser.baseUrl!!, roomToken), "geo-location", objectId, metaData diff --git a/app/src/main/java/com/nextcloud/talk/models/RetrofitBucket.kt b/app/src/main/java/com/nextcloud/talk/models/RetrofitBucket.kt index 8b6460836..a8a50abe5 100644 --- a/app/src/main/java/com/nextcloud/talk/models/RetrofitBucket.kt +++ b/app/src/main/java/com/nextcloud/talk/models/RetrofitBucket.kt @@ -27,5 +27,5 @@ import kotlinx.parcelize.Parcelize @Parcelize data class RetrofitBucket( var url: String? = null, - var queryMap: Map? = null + var queryMap: MutableMap? = null ) : Parcelable diff --git a/app/src/main/java/com/nextcloud/talk/models/domain/ConversationModel.kt b/app/src/main/java/com/nextcloud/talk/models/domain/ConversationModel.kt index e9e2a164a..c239cd5af 100644 --- a/app/src/main/java/com/nextcloud/talk/models/domain/ConversationModel.kt +++ b/app/src/main/java/com/nextcloud/talk/models/domain/ConversationModel.kt @@ -3,7 +3,7 @@ package com.nextcloud.talk.models.domain import com.nextcloud.talk.models.json.conversations.Conversation class ConversationModel( - var roomId: String?, + var roomId: String? = null, var token: String? = null, var name: String? = null, var displayName: String? = null, @@ -42,7 +42,11 @@ class ConversationModel( var statusClearAt: Long? = 0, var callRecording: Int = 0, var avatarVersion: String? = null, - var hasCustomAvatar: Boolean? = null + var hasCustomAvatar: Boolean? = null, + var callStartTime: Long? = null, + var recordingConsentRequired: Int = 0, + var remoteServer: String? = null, + var remoteToken: String? = null ) { companion object { @@ -95,7 +99,11 @@ class ConversationModel( statusClearAt = conversation.statusClearAt, callRecording = conversation.callRecording, avatarVersion = conversation.avatarVersion, - hasCustomAvatar = conversation.hasCustomAvatar + hasCustomAvatar = conversation.hasCustomAvatar, + callStartTime = conversation.callStartTime, + recordingConsentRequired = conversation.recordingConsentRequired, + remoteServer = conversation.remoteServer, + remoteToken = conversation.remoteToken ) } } diff --git a/app/src/main/java/com/nextcloud/talk/models/domain/converters/DomainEnumNotificationLevelConverter.kt b/app/src/main/java/com/nextcloud/talk/models/domain/converters/DomainEnumNotificationLevelConverter.kt new file mode 100644 index 000000000..037add02b --- /dev/null +++ b/app/src/main/java/com/nextcloud/talk/models/domain/converters/DomainEnumNotificationLevelConverter.kt @@ -0,0 +1,45 @@ +/* + * Nextcloud Talk application + * + * @author Mario Danic + * Copyright (C) 2017-2018 Mario Danic + * + * 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.domain.converters + +import com.bluelinelabs.logansquare.typeconverters.IntBasedTypeConverter +import com.nextcloud.talk.models.domain.NotificationLevel + +class DomainEnumNotificationLevelConverter : IntBasedTypeConverter() { + override fun getFromInt(i: Int): NotificationLevel { + return when (i) { + 0 -> NotificationLevel.DEFAULT + 1 -> NotificationLevel.ALWAYS + 2 -> NotificationLevel.MENTION + 3 -> NotificationLevel.NEVER + else -> NotificationLevel.DEFAULT + } + } + + override fun convertToInt(`object`: NotificationLevel): Int { + return when (`object`) { + NotificationLevel.DEFAULT -> 0 + NotificationLevel.ALWAYS -> 1 + NotificationLevel.MENTION -> 2 + NotificationLevel.NEVER -> 3 + else -> 0 + } + } +} diff --git a/app/src/main/java/com/nextcloud/talk/models/json/capabilities/RoomCapabilitiesOCS.kt b/app/src/main/java/com/nextcloud/talk/models/json/capabilities/RoomCapabilitiesOCS.kt new file mode 100644 index 000000000..193dff529 --- /dev/null +++ b/app/src/main/java/com/nextcloud/talk/models/json/capabilities/RoomCapabilitiesOCS.kt @@ -0,0 +1,42 @@ +/* + * Nextcloud Talk application + * + * @author Mario Danic + * @author Tim Krüger + * @author Andy Scherzinger + * Copyright (C) 2022 Andy Scherzinger + * Copyright (C) 2022 Tim Krüger + * Copyright (C) 2017-2018 Mario Danic + * + * 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.capabilities + +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.parcelize.Parcelize + +@Parcelize +@JsonObject +data class RoomCapabilitiesOCS( + @JsonField(name = ["meta"]) + var meta: GenericMeta?, + @JsonField(name = ["data"]) + var data: SpreedCapability? +) : 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/capabilities/RoomCapabilitiesOverall.kt b/app/src/main/java/com/nextcloud/talk/models/json/capabilities/RoomCapabilitiesOverall.kt new file mode 100644 index 000000000..aa7234929 --- /dev/null +++ b/app/src/main/java/com/nextcloud/talk/models/json/capabilities/RoomCapabilitiesOverall.kt @@ -0,0 +1,37 @@ +/* + * Nextcloud Talk application + * + * @author Mario Danic + * @author Tim Krüger + * Copyright (C) 2022 Tim Krüger + * Copyright (C) 2017-2018 Mario Danic + * + * 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.capabilities + +import android.os.Parcelable +import com.bluelinelabs.logansquare.annotation.JsonField +import com.bluelinelabs.logansquare.annotation.JsonObject +import kotlinx.parcelize.Parcelize + +@Parcelize +@JsonObject +data class RoomCapabilitiesOverall( + @JsonField(name = ["ocs"]) + var ocs: RoomCapabilitiesOCS? = 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/chat/ChatMessage.kt b/app/src/main/java/com/nextcloud/talk/models/json/chat/ChatMessage.kt index 467549314..dc285504c 100644 --- a/app/src/main/java/com/nextcloud/talk/models/json/chat/ChatMessage.kt +++ b/app/src/main/java/com/nextcloud/talk/models/json/chat/ChatMessage.kt @@ -37,7 +37,7 @@ import com.nextcloud.talk.data.user.model.User import com.nextcloud.talk.models.json.chat.ChatUtils.Companion.getParsedMessage import com.nextcloud.talk.models.json.converters.EnumSystemMessageTypeConverter import com.nextcloud.talk.utils.ApiUtils -import com.nextcloud.talk.utils.database.user.CapabilitiesUtilNew +import com.nextcloud.talk.utils.CapabilitiesUtil import com.stfalcon.chatkit.commons.models.IUser import com.stfalcon.chatkit.commons.models.MessageContentType import kotlinx.parcelize.Parcelize @@ -213,7 +213,7 @@ data class ChatMessage( @Suppress("ReturnCount") fun isLinkPreview(): Boolean { - if (CapabilitiesUtilNew.isLinkPreviewAvailable(activeUser!!)) { + if (CapabilitiesUtil.isLinkPreviewAvailable(activeUser!!)) { val regexStringFromServer = activeUser?.capabilities?.coreCapability?.referenceRegex val regexFromServer = regexStringFromServer?.toRegex(setOf(RegexOption.MULTILINE, RegexOption.IGNORE_CASE)) @@ -249,8 +249,8 @@ data class ChatMessage( if (!isVoiceMessage) { if (activeUser != null && activeUser!!.baseUrl != null) { return ApiUtils.getUrlForFilePreviewWithFileId( - activeUser!!.baseUrl, - individualHashMap["id"], + activeUser!!.baseUrl!!, + individualHashMap["id"]!!, sharedApplication!!.resources.getDimensionPixelSize(R.dimen.maximum_file_preview_size) ) } else { @@ -413,11 +413,11 @@ data class ChatMessage( null } actorType == "users" -> { - ApiUtils.getUrlForAvatar(activeUser!!.baseUrl, actorId, true) + ApiUtils.getUrlForAvatar(activeUser!!.baseUrl!!, actorId, true) } actorType == "bridged" -> { ApiUtils.getUrlForAvatar( - activeUser!!.baseUrl, + activeUser!!.baseUrl!!, "bridge-bot", true ) @@ -427,7 +427,7 @@ data class ChatMessage( if (!TextUtils.isEmpty(actorDisplayName)) { apiId = actorDisplayName } - ApiUtils.getUrlForGuestAvatar(activeUser!!.baseUrl, apiId, true) + ApiUtils.getUrlForGuestAvatar(activeUser!!.baseUrl!!, apiId, true) } } } diff --git a/app/src/main/java/com/nextcloud/talk/models/json/conversations/Conversation.kt b/app/src/main/java/com/nextcloud/talk/models/json/conversations/Conversation.kt index 57dc17779..97ec35660 100644 --- a/app/src/main/java/com/nextcloud/talk/models/json/conversations/Conversation.kt +++ b/app/src/main/java/com/nextcloud/talk/models/json/conversations/Conversation.kt @@ -38,8 +38,9 @@ import com.nextcloud.talk.models.json.converters.EnumParticipantTypeConverter import com.nextcloud.talk.models.json.converters.EnumReadOnlyConversationConverter import com.nextcloud.talk.models.json.converters.EnumRoomTypeConverter import com.nextcloud.talk.models.json.participants.Participant.ParticipantType +import com.nextcloud.talk.utils.SpreedFeatures import com.nextcloud.talk.utils.ConversationUtils -import com.nextcloud.talk.utils.database.user.CapabilitiesUtilNew +import com.nextcloud.talk.utils.CapabilitiesUtil import kotlinx.parcelize.Parcelize @Parcelize @@ -160,7 +161,13 @@ data class Conversation( var callStartTime: Long? = null, @JsonField(name = ["recordingConsent"]) - var recordingConsentRequired: Int = 0 + var recordingConsentRequired: Int = 0, + + @JsonField(name = ["remoteServer"]) + var remoteServer: String? = null, + + @JsonField(name = ["remoteToken"]) + var remoteToken: String? = null ) : Parcelable { // This constructor is added to work with the 'com.bluelinelabs.logansquare.annotation.JsonObject' @@ -185,13 +192,20 @@ data class Conversation( @Deprecated("Use ConversationUtil") private fun isLockedOneToOne(conversationUser: User): Boolean { return type == ConversationType.ROOM_TYPE_ONE_TO_ONE_CALL && - CapabilitiesUtilNew.hasSpreedFeatureCapability(conversationUser, "locked-one-to-one-rooms") + CapabilitiesUtil.hasSpreedFeatureCapability( + conversationUser.capabilities?.spreedCapability!!, + SpreedFeatures.LOCKED_ONE_TO_ONE_ROOMS + ) } @Deprecated("Use ConversationUtil") fun canModerate(conversationUser: User): Boolean { return isParticipantOwnerOrModerator && - !isLockedOneToOne(conversationUser) && + ConversationUtils.isLockedOneToOne( + ConversationModel.mapToConversationModel(this), + conversationUser + .capabilities?.spreedCapability!! + ) && type != ConversationType.FORMER_ONE_TO_ONE && !ConversationUtils.isNoteToSelfConversation(ConversationModel.mapToConversationModel(this)) } diff --git a/app/src/main/java/com/nextcloud/talk/openconversations/data/OpenConversationsRepositoryImpl.kt b/app/src/main/java/com/nextcloud/talk/openconversations/data/OpenConversationsRepositoryImpl.kt index cde534757..6da447142 100644 --- a/app/src/main/java/com/nextcloud/talk/openconversations/data/OpenConversationsRepositoryImpl.kt +++ b/app/src/main/java/com/nextcloud/talk/openconversations/data/OpenConversationsRepositoryImpl.kt @@ -31,14 +31,14 @@ class OpenConversationsRepositoryImpl(private val ncApi: NcApi, currentUserProvi OpenConversationsRepository { val currentUser: User = currentUserProvider.currentUser.blockingGet() - val credentials: String = ApiUtils.getCredentials(currentUser.username, currentUser.token) + val credentials: String = ApiUtils.getCredentials(currentUser.username, currentUser.token)!! - val apiVersion = ApiUtils.getConversationApiVersion(currentUser, intArrayOf(ApiUtils.APIv4, ApiUtils.APIv3, 1)) + val apiVersion = ApiUtils.getConversationApiVersion(currentUser, intArrayOf(ApiUtils.API_V4, ApiUtils.API_V3, 1)) override fun fetchConversations(): Observable { return ncApi.getOpenConversations( credentials, - ApiUtils.getUrlForOpenConversations(apiVersion, currentUser.baseUrl) + ApiUtils.getUrlForOpenConversations(apiVersion, currentUser.baseUrl!!) ).map { mapToOpenConversationsModel(it.ocs?.data!!) } } diff --git a/app/src/main/java/com/nextcloud/talk/polls/repositories/PollRepositoryImpl.kt b/app/src/main/java/com/nextcloud/talk/polls/repositories/PollRepositoryImpl.kt index d74c0a158..abd887b1b 100644 --- a/app/src/main/java/com/nextcloud/talk/polls/repositories/PollRepositoryImpl.kt +++ b/app/src/main/java/com/nextcloud/talk/polls/repositories/PollRepositoryImpl.kt @@ -37,7 +37,7 @@ class PollRepositoryImpl(private val ncApi: NcApi, private val currentUserProvid PollRepository { val currentUser: User = currentUserProvider.currentUser.blockingGet() - val credentials: String = ApiUtils.getCredentials(currentUser.username, currentUser.token) + val credentials: String = ApiUtils.getCredentials(currentUser.username, currentUser.token)!! override fun createPoll( roomToken: String, @@ -49,7 +49,7 @@ class PollRepositoryImpl(private val ncApi: NcApi, private val currentUserProvid return ncApi.createPoll( credentials, ApiUtils.getUrlForPoll( - currentUser.baseUrl, + currentUser.baseUrl!!, roomToken ), question, @@ -63,7 +63,7 @@ class PollRepositoryImpl(private val ncApi: NcApi, private val currentUserProvid return ncApi.getPoll( credentials, ApiUtils.getUrlForPoll( - currentUser.baseUrl, + currentUser.baseUrl!!, roomToken, pollId ) @@ -74,7 +74,7 @@ class PollRepositoryImpl(private val ncApi: NcApi, private val currentUserProvid return ncApi.votePoll( credentials, ApiUtils.getUrlForPoll( - currentUser.baseUrl, + currentUser.baseUrl!!, roomToken, pollId ), @@ -86,7 +86,7 @@ class PollRepositoryImpl(private val ncApi: NcApi, private val currentUserProvid return ncApi.closePoll( credentials, ApiUtils.getUrlForPoll( - currentUser.baseUrl, + currentUser.baseUrl!!, roomToken, pollId ) diff --git a/app/src/main/java/com/nextcloud/talk/presenters/MentionAutocompletePresenter.java b/app/src/main/java/com/nextcloud/talk/presenters/MentionAutocompletePresenter.java index 8aa553714..c11eb27b4 100644 --- a/app/src/main/java/com/nextcloud/talk/presenters/MentionAutocompletePresenter.java +++ b/app/src/main/java/com/nextcloud/talk/presenters/MentionAutocompletePresenter.java @@ -77,6 +77,7 @@ public class MentionAutocompletePresenter extends RecyclerViewPresenter private Context context; private String roomToken; + private int chatApiVersion; private List abstractFlexibleItemList = new ArrayList<>(); @@ -87,10 +88,11 @@ public class MentionAutocompletePresenter extends RecyclerViewPresenter currentUser = userManager.getCurrentUser().blockingGet(); } - public MentionAutocompletePresenter(Context context, String roomToken) { + public MentionAutocompletePresenter(Context context, String roomToken, int chatApiVersion) { super(context); this.roomToken = roomToken; this.context = context; + this.chatApiVersion = chatApiVersion; NextcloudTalkApplication.Companion.getSharedApplication().getComponentApplication().inject(this); currentUser = userManager.getCurrentUser().blockingGet(); } @@ -120,8 +122,6 @@ public class MentionAutocompletePresenter extends RecyclerViewPresenter queryString = ""; } - int apiVersion = ApiUtils.getChatApiVersion(currentUser, new int[] {1}); - adapter.setFilter(queryString); Map queryMap = new HashMap<>(); @@ -129,7 +129,7 @@ public class MentionAutocompletePresenter extends RecyclerViewPresenter ncApi.getMentionAutocompleteSuggestions( ApiUtils.getCredentials(currentUser.getUsername(), currentUser.getToken()), - ApiUtils.getUrlForMentionSuggestions(apiVersion, currentUser.getBaseUrl(), roomToken), + ApiUtils.getUrlForMentionSuggestions(chatApiVersion, currentUser.getBaseUrl(), roomToken), queryString, 5, queryMap) .subscribeOn(Schedulers.io()) .observeOn(AndroidSchedulers.mainThread()) diff --git a/app/src/main/java/com/nextcloud/talk/profile/ProfileActivity.kt b/app/src/main/java/com/nextcloud/talk/profile/ProfileActivity.kt index 48020e8c9..6ace02f26 100644 --- a/app/src/main/java/com/nextcloud/talk/profile/ProfileActivity.kt +++ b/app/src/main/java/com/nextcloud/talk/profile/ProfileActivity.kt @@ -66,12 +66,13 @@ import com.nextcloud.talk.ui.dialog.ScopeDialog import com.nextcloud.talk.ui.theme.ViewThemeUtils import com.nextcloud.talk.users.UserManager import com.nextcloud.talk.utils.ApiUtils +import com.nextcloud.talk.utils.SpreedFeatures import com.nextcloud.talk.utils.DisplayUtils import com.nextcloud.talk.utils.Mimetype.IMAGE_JPG import com.nextcloud.talk.utils.Mimetype.IMAGE_PREFIX_GENERIC import com.nextcloud.talk.utils.PickImage import com.nextcloud.talk.utils.PickImage.Companion.REQUEST_PERMISSION_CAMERA -import com.nextcloud.talk.utils.database.user.CapabilitiesUtilNew +import com.nextcloud.talk.utils.CapabilitiesUtil import io.reactivex.Observer import io.reactivex.android.schedulers.AndroidSchedulers import io.reactivex.disposables.Disposable @@ -127,7 +128,7 @@ class ProfileActivity : BaseActivity() { binding.avatarDelete.setOnClickListener { ncApi.deleteAvatar( credentials, - ApiUtils.getUrlForTempAvatar(currentUser!!.baseUrl) + ApiUtils.getUrlForTempAvatar(currentUser!!.baseUrl!!) ) .subscribeOn(Schedulers.io()) .observeOn(AndroidSchedulers.mainThread()) @@ -154,7 +155,7 @@ class ProfileActivity : BaseActivity() { }) } binding.avatarImage.let { ViewCompat.setTransitionName(it, "userAvatar.transitionTag") } - ncApi.getUserProfile(credentials, ApiUtils.getUrlForUserProfile(currentUser!!.baseUrl)) + ncApi.getUserProfile(credentials, ApiUtils.getUrlForUserProfile(currentUser!!.baseUrl!!)) .retry(DEFAULT_RETRIES) .subscribeOn(Schedulers.io()) .observeOn(AndroidSchedulers.mainThread()) @@ -226,13 +227,17 @@ class ProfileActivity : BaseActivity() { item.icon = ContextCompat.getDrawable(this, R.drawable.ic_check) binding.emptyList.root.visibility = View.GONE binding.userinfoList.visibility = View.VISIBLE - if (CapabilitiesUtilNew.isAvatarEndpointAvailable(currentUser!!)) { + if (CapabilitiesUtil.hasSpreedFeatureCapability( + currentUser!!.capabilities!!.spreedCapability!!, + SpreedFeatures.TEMP_USER_AVATAR_API + ) + ) { // TODO later avatar can also be checked via user fields, for now it is in Talk capability binding.avatarButtons.visibility = View.VISIBLE } ncApi.getEditableUserProfileFields( ApiUtils.getCredentials(currentUser!!.username, currentUser!!.token), - ApiUtils.getUrlForUserFields(currentUser!!.baseUrl) + ApiUtils.getUrlForUserFields(currentUser!!.baseUrl!!) ) .subscribeOn(Schedulers.io()) .observeOn(AndroidSchedulers.mainThread()) @@ -292,7 +297,7 @@ class ProfileActivity : BaseActivity() { private fun showUserProfile() { if (currentUser!!.baseUrl != null) { - binding.userinfoBaseurl.text = Uri.parse(currentUser!!.baseUrl).host + binding.userinfoBaseurl.text = Uri.parse(currentUser!!.baseUrl!!).host } DisplayUtils.loadAvatarImage(currentUser, binding.avatarImage, false) if (!TextUtils.isEmpty(userInfo?.displayName)) { @@ -327,10 +332,10 @@ class ProfileActivity : BaseActivity() { } // show edit button - if (CapabilitiesUtilNew.canEditScopes(currentUser!!)) { + if (CapabilitiesUtil.canEditScopes(currentUser!!)) { ncApi.getEditableUserProfileFields( ApiUtils.getCredentials(currentUser!!.username, currentUser!!.token), - ApiUtils.getUrlForUserFields(currentUser!!.baseUrl) + ApiUtils.getUrlForUserFields(currentUser!!.baseUrl!!) ) .subscribeOn(Schedulers.io()) .observeOn(AndroidSchedulers.mainThread()) @@ -438,7 +443,7 @@ class ProfileActivity : BaseActivity() { val credentials = ApiUtils.getCredentials(currentUser!!.username, currentUser!!.token) ncApi.setUserData( credentials, - ApiUtils.getUrlForUserData(currentUser!!.baseUrl, currentUser!!.userId), + ApiUtils.getUrlForUserData(currentUser!!.baseUrl!!, currentUser!!.userId!!), item.field.fieldName, item.text ) @@ -535,7 +540,7 @@ class ProfileActivity : BaseActivity() { // upload file ncApi.uploadAvatar( ApiUtils.getCredentials(currentUser!!.username, currentUser!!.token), - ApiUtils.getUrlForTempAvatar(currentUser!!.baseUrl), + ApiUtils.getUrlForTempAvatar(currentUser!!.baseUrl!!), filePart ) .subscribeOn(Schedulers.io()) @@ -569,7 +574,7 @@ class ProfileActivity : BaseActivity() { val credentials = ApiUtils.getCredentials(currentUser!!.username, currentUser!!.token) ncApi.setUserData( credentials, - ApiUtils.getUrlForUserData(currentUser!!.baseUrl, currentUser!!.userId), + ApiUtils.getUrlForUserData(currentUser!!.baseUrl!!, currentUser!!.userId!!), item.field.scopeName, item.scope!!.name ) diff --git a/app/src/main/java/com/nextcloud/talk/raisehand/RequestAssistanceRepositoryImpl.kt b/app/src/main/java/com/nextcloud/talk/raisehand/RequestAssistanceRepositoryImpl.kt index 757602762..e15b42c2f 100644 --- a/app/src/main/java/com/nextcloud/talk/raisehand/RequestAssistanceRepositoryImpl.kt +++ b/app/src/main/java/com/nextcloud/talk/raisehand/RequestAssistanceRepositoryImpl.kt @@ -31,7 +31,7 @@ class RequestAssistanceRepositoryImpl(private val ncApi: NcApi, currentUserProvi RequestAssistanceRepository { val currentUser: User = currentUserProvider.currentUser.blockingGet() - val credentials: String = ApiUtils.getCredentials(currentUser.username, currentUser.token) + val credentials: String = ApiUtils.getCredentials(currentUser.username, currentUser.token)!! var apiVersion = 1 diff --git a/app/src/main/java/com/nextcloud/talk/receivers/DirectReplyReceiver.kt b/app/src/main/java/com/nextcloud/talk/receivers/DirectReplyReceiver.kt index b66b013d2..fdb8d6891 100644 --- a/app/src/main/java/com/nextcloud/talk/receivers/DirectReplyReceiver.kt +++ b/app/src/main/java/com/nextcloud/talk/receivers/DirectReplyReceiver.kt @@ -91,8 +91,8 @@ class DirectReplyReceiver : BroadcastReceiver() { private fun sendDirectReply() { val credentials = ApiUtils.getCredentials(currentUser.username, currentUser.token) - val apiVersion = ApiUtils.getChatApiVersion(currentUser, intArrayOf(1)) - val url = ApiUtils.getUrlForChat(apiVersion, currentUser.baseUrl, roomToken) + val apiVersion = ApiUtils.getChatApiVersion(currentUser.capabilities!!.spreedCapability!!, intArrayOf(1)) + val url = ApiUtils.getUrlForChat(apiVersion, currentUser.baseUrl!!, roomToken!!) ncApi.sendChatMessage(credentials, url, replyMessage, currentUser.displayName, null, false) ?.subscribeOn(Schedulers.io()) @@ -153,7 +153,7 @@ class DirectReplyReceiver : BroadcastReceiver() { // Add reply Single.fromCallable { - val avatarUrl = ApiUtils.getUrlForAvatar(currentUser.baseUrl, currentUser.userId, false) + val avatarUrl = ApiUtils.getUrlForAvatar(currentUser.baseUrl!!, currentUser.userId, false) val me = Person.Builder() .setName(currentUser.displayName) .setIcon(NotificationUtils.loadAvatarSync(avatarUrl, context)) diff --git a/app/src/main/java/com/nextcloud/talk/receivers/MarkAsReadReceiver.kt b/app/src/main/java/com/nextcloud/talk/receivers/MarkAsReadReceiver.kt index d0c892fe2..c245dc776 100644 --- a/app/src/main/java/com/nextcloud/talk/receivers/MarkAsReadReceiver.kt +++ b/app/src/main/java/com/nextcloud/talk/receivers/MarkAsReadReceiver.kt @@ -80,11 +80,11 @@ class MarkAsReadReceiver : BroadcastReceiver() { private fun markAsRead() { val credentials = ApiUtils.getCredentials(currentUser.username, currentUser.token) - val apiVersion = ApiUtils.getChatApiVersion(currentUser, intArrayOf(1)) + val apiVersion = ApiUtils.getChatApiVersion(currentUser.capabilities!!.spreedCapability!!, intArrayOf(1)) val url = ApiUtils.getUrlForChatReadMarker( apiVersion, - currentUser.baseUrl, - roomToken + currentUser.baseUrl!!, + roomToken!! ) ncApi.setChatReadMarker(credentials, url, messageId) diff --git a/app/src/main/java/com/nextcloud/talk/remotefilebrowser/adapters/RemoteFileBrowserItemsListViewHolder.kt b/app/src/main/java/com/nextcloud/talk/remotefilebrowser/adapters/RemoteFileBrowserItemsListViewHolder.kt index b28d94b29..c99d21d43 100644 --- a/app/src/main/java/com/nextcloud/talk/remotefilebrowser/adapters/RemoteFileBrowserItemsListViewHolder.kt +++ b/app/src/main/java/com/nextcloud/talk/remotefilebrowser/adapters/RemoteFileBrowserItemsListViewHolder.kt @@ -94,7 +94,7 @@ class RemoteFileBrowserItemsListViewHolder( if (item.hasPreview) { val path = ApiUtils.getUrlForFilePreviewWithRemotePath( - currentUser.baseUrl, + currentUser.baseUrl!!, item.path, fileIcon.context.resources.getDimensionPixelSize(R.dimen.small_item_height) ) diff --git a/app/src/main/java/com/nextcloud/talk/repositories/callrecording/CallRecordingRepositoryImpl.kt b/app/src/main/java/com/nextcloud/talk/repositories/callrecording/CallRecordingRepositoryImpl.kt index 71c6d64d2..369bca342 100644 --- a/app/src/main/java/com/nextcloud/talk/repositories/callrecording/CallRecordingRepositoryImpl.kt +++ b/app/src/main/java/com/nextcloud/talk/repositories/callrecording/CallRecordingRepositoryImpl.kt @@ -33,7 +33,7 @@ class CallRecordingRepositoryImpl(private val ncApi: NcApi, currentUserProvider: CallRecordingRepository { val currentUser: User = currentUserProvider.currentUser.blockingGet() - val credentials: String = ApiUtils.getCredentials(currentUser.username, currentUser.token) + val credentials: String = ApiUtils.getCredentials(currentUser.username, currentUser.token)!! var apiVersion = 1 @@ -42,7 +42,7 @@ class CallRecordingRepositoryImpl(private val ncApi: NcApi, currentUserProvider: credentials, ApiUtils.getUrlForRecording( apiVersion, - currentUser.baseUrl, + currentUser.baseUrl!!, roomToken ), 1 @@ -54,7 +54,7 @@ class CallRecordingRepositoryImpl(private val ncApi: NcApi, currentUserProvider: credentials, ApiUtils.getUrlForRecording( apiVersion, - currentUser.baseUrl, + currentUser.baseUrl!!, roomToken ) ).map { mapToStopCallRecordingModel(it.ocs?.meta!!) } 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 index c0706a7d4..0a969998e 100644 --- a/app/src/main/java/com/nextcloud/talk/repositories/conversations/ConversationsRepositoryImpl.kt +++ b/app/src/main/java/com/nextcloud/talk/repositories/conversations/ConversationsRepositoryImpl.kt @@ -38,12 +38,12 @@ class ConversationsRepositoryImpl(private val api: NcApi, private val userProvid get() = userProvider.currentUser.blockingGet() private val credentials: String - get() = ApiUtils.getCredentials(user.username, user.token) + get() = ApiUtils.getCredentials(user.username, user.token)!! override fun allowGuests(token: String, allow: Boolean): Observable { val url = ApiUtils.getUrlForRoomPublic( apiVersion(), - user.baseUrl, + user.baseUrl!!, token ) @@ -100,7 +100,7 @@ class ConversationsRepositoryImpl(private val api: NcApi, private val userProvid } private fun apiVersion(): Int { - return ApiUtils.getConversationApiVersion(user, intArrayOf(ApiUtils.APIv4)) + return ApiUtils.getConversationApiVersion(user, intArrayOf(ApiUtils.API_V4)) } companion object { diff --git a/app/src/main/java/com/nextcloud/talk/repositories/reactions/ReactionsRepositoryImpl.kt b/app/src/main/java/com/nextcloud/talk/repositories/reactions/ReactionsRepositoryImpl.kt index 55de85b81..5a7837e7e 100644 --- a/app/src/main/java/com/nextcloud/talk/repositories/reactions/ReactionsRepositoryImpl.kt +++ b/app/src/main/java/com/nextcloud/talk/repositories/reactions/ReactionsRepositoryImpl.kt @@ -34,13 +34,13 @@ class ReactionsRepositoryImpl(private val ncApi: NcApi, currentUserProvider: Cur ReactionsRepository { val currentUser: User = currentUserProvider.currentUser.blockingGet() - val credentials: String = ApiUtils.getCredentials(currentUser.username, currentUser.token) + val credentials: String = ApiUtils.getCredentials(currentUser.username, currentUser.token)!! override fun addReaction(roomToken: String, message: ChatMessage, emoji: String): Observable { return ncApi.sendReaction( credentials, ApiUtils.getUrlForMessageReaction( - currentUser.baseUrl, + currentUser.baseUrl!!, roomToken, message.id ), @@ -56,7 +56,7 @@ class ReactionsRepositoryImpl(private val ncApi: NcApi, currentUserProvider: Cur return ncApi.deleteReaction( credentials, ApiUtils.getUrlForMessageReaction( - currentUser.baseUrl, + currentUser.baseUrl!!, roomToken, message.id ), diff --git a/app/src/main/java/com/nextcloud/talk/repositories/unifiedsearch/UnifiedSearchRepositoryImpl.kt b/app/src/main/java/com/nextcloud/talk/repositories/unifiedsearch/UnifiedSearchRepositoryImpl.kt index df475b455..d636ced45 100644 --- a/app/src/main/java/com/nextcloud/talk/repositories/unifiedsearch/UnifiedSearchRepositoryImpl.kt +++ b/app/src/main/java/com/nextcloud/talk/repositories/unifiedsearch/UnifiedSearchRepositoryImpl.kt @@ -37,7 +37,7 @@ class UnifiedSearchRepositoryImpl(private val api: NcApi, private val userProvid get() = userProvider.currentUser.blockingGet() private val credentials: String - get() = ApiUtils.getCredentials(user.username, user.token) + get() = ApiUtils.getCredentials(user.username, user.token)!! override fun searchMessages( searchTerm: String, 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 f70b6e7d0..5b08303cf 100644 --- a/app/src/main/java/com/nextcloud/talk/settings/SettingsActivity.kt +++ b/app/src/main/java/com/nextcloud/talk/settings/SettingsActivity.kt @@ -90,6 +90,7 @@ import com.nextcloud.talk.models.json.userprofile.UserProfileOverall import com.nextcloud.talk.profile.ProfileActivity import com.nextcloud.talk.users.UserManager import com.nextcloud.talk.utils.ApiUtils +import com.nextcloud.talk.utils.SpreedFeatures import com.nextcloud.talk.utils.ClosedInterfaceImpl import com.nextcloud.talk.utils.DisplayUtils import com.nextcloud.talk.utils.LoggingUtils.sendMailWithAttachment @@ -97,7 +98,7 @@ import com.nextcloud.talk.utils.NotificationUtils import com.nextcloud.talk.utils.NotificationUtils.getCallRingtoneUri import com.nextcloud.talk.utils.NotificationUtils.getMessageRingtoneUri import com.nextcloud.talk.utils.SecurityUtils -import com.nextcloud.talk.utils.database.user.CapabilitiesUtilNew +import com.nextcloud.talk.utils.CapabilitiesUtil import com.nextcloud.talk.utils.database.user.CurrentUserProviderNew import com.nextcloud.talk.utils.permissions.PlatformPermissionUtil import com.nextcloud.talk.utils.power.PowerManagerUtils @@ -266,7 +267,11 @@ class SettingsActivity : BaseActivity() { } private fun setupPhoneBookIntegration() { - if (CapabilitiesUtilNew.isPhoneBookIntegrationAvailable(currentUser!!)) { + if (CapabilitiesUtil.hasSpreedFeatureCapability( + currentUser?.capabilities?.spreedCapability!!, + SpreedFeatures.PHONEBOOK_SEARCH + ) + ) { binding.settingsPhoneBookIntegration.visibility = View.VISIBLE } else { binding.settingsPhoneBookIntegration.visibility = View.GONE @@ -507,7 +512,7 @@ class SettingsActivity : BaseActivity() { var port = -1 val uri: URI try { - uri = URI(currentUser!!.baseUrl) + uri = URI(currentUser!!.baseUrl!!) host = uri.host port = uri.port Log.d(TAG, "uri is $uri") @@ -823,7 +828,7 @@ class SettingsActivity : BaseActivity() { private fun setupProfileQueryDisposable() { profileQueryDisposable = ncApi.getUserProfile( credentials, - ApiUtils.getUrlForUserProfile(currentUser!!.baseUrl) + ApiUtils.getUrlForUserProfile(currentUser!!.baseUrl!!) ) .subscribeOn(Schedulers.io()) .observeOn(AndroidSchedulers.mainThread()) @@ -854,7 +859,7 @@ class SettingsActivity : BaseActivity() { private fun setupServerAgeWarning() { when { - CapabilitiesUtilNew.isServerEOL(currentUser!!.capabilities) -> { + CapabilitiesUtil.isServerEOL(currentUser!!.serverVersion!!.major) -> { binding.serverAgeWarningText.setTextColor(ContextCompat.getColor((context), R.color.nc_darkRed)) binding.serverAgeWarningText.setText(R.string.nc_settings_server_eol) binding.serverAgeWarningIcon.setColorFilter( @@ -863,7 +868,7 @@ class SettingsActivity : BaseActivity() { ) } - CapabilitiesUtilNew.isServerAlmostEOL(currentUser!!) -> { + CapabilitiesUtil.isServerAlmostEOL(currentUser!!.serverVersion!!.major) -> { binding.serverAgeWarningText.setTextColor( ContextCompat.getColor((context), R.color.nc_darkYellow) ) @@ -889,8 +894,8 @@ class SettingsActivity : BaseActivity() { binding.settingsIncognitoKeyboardSwitch.visibility = View.GONE } - if (CapabilitiesUtilNew.isReadStatusAvailable(currentUser!!)) { - binding.settingsReadPrivacySwitch.isChecked = !CapabilitiesUtilNew.isReadStatusPrivate(currentUser!!) + if (CapabilitiesUtil.isReadStatusAvailable(currentUser!!.capabilities!!.spreedCapability!!)) { + binding.settingsReadPrivacySwitch.isChecked = !CapabilitiesUtil.isReadStatusPrivate(currentUser!!) } else { binding.settingsReadPrivacy.visibility = View.GONE } @@ -954,10 +959,10 @@ class SettingsActivity : BaseActivity() { private fun setupTypingStatusSetting() { if (currentUser!!.externalSignalingServer?.externalSignalingServer?.isNotEmpty() == true) { binding.settingsTypingStatusOnlyWithHpb.visibility = View.GONE - Log.i(TAG, "Typing Status Available: ${CapabilitiesUtilNew.isTypingStatusAvailable(currentUser!!)}") + Log.i(TAG, "Typing Status Available: ${CapabilitiesUtil.isTypingStatusAvailable(currentUser!!)}") - if (CapabilitiesUtilNew.isTypingStatusAvailable(currentUser!!)) { - binding.settingsTypingStatusSwitch.isChecked = !CapabilitiesUtilNew.isTypingStatusPrivate(currentUser!!) + if (CapabilitiesUtil.isTypingStatusAvailable(currentUser!!)) { + binding.settingsTypingStatusSwitch.isChecked = !CapabilitiesUtil.isTypingStatusPrivate(currentUser!!) } else { binding.settingsTypingStatus.visibility = View.GONE } @@ -1209,7 +1214,7 @@ class SettingsActivity : BaseActivity() { private fun checkForPhoneNumber() { ncApi.getUserData( ApiUtils.getCredentials(currentUser!!.username, currentUser!!.token), - ApiUtils.getUrlForUserProfile(currentUser!!.baseUrl) + ApiUtils.getUrlForUserProfile(currentUser!!.baseUrl!!) ).subscribeOn(Schedulers.io()) .observeOn(AndroidSchedulers.mainThread()) .subscribe(object : Observer { @@ -1294,7 +1299,7 @@ class SettingsActivity : BaseActivity() { val phoneNumber = textInputLayout.editText!!.text.toString() ncApi.setUserData( ApiUtils.getCredentials(currentUser!!.username, currentUser!!.token), - ApiUtils.getUrlForUserData(currentUser!!.baseUrl, currentUser!!.userId), + ApiUtils.getUrlForUserData(currentUser!!.baseUrl!!, currentUser!!.userId!!), "phone", phoneNumber ).subscribeOn(Schedulers.io()) @@ -1349,7 +1354,7 @@ class SettingsActivity : BaseActivity() { val json = "{\"key\": \"read_status_privacy\", \"value\" : $booleanValue}" ncApi.setReadStatusPrivacy( ApiUtils.getCredentials(currentUser!!.username, currentUser!!.token), - ApiUtils.getUrlForUserSettings(currentUser!!.baseUrl), + ApiUtils.getUrlForUserSettings(currentUser!!.baseUrl!!), json.toRequestBody("application/json".toMediaTypeOrNull()) ) .subscribeOn(Schedulers.io()) @@ -1387,7 +1392,7 @@ class SettingsActivity : BaseActivity() { val json = "{\"key\": \"typing_privacy\", \"value\" : $booleanValue}" ncApi.setTypingStatusPrivacy( ApiUtils.getCredentials(currentUser!!.username, currentUser!!.token), - ApiUtils.getUrlForUserSettings(currentUser!!.baseUrl), + ApiUtils.getUrlForUserSettings(currentUser!!.baseUrl!!), json.toRequestBody("application/json".toMediaTypeOrNull()) ) .subscribeOn(Schedulers.io()) diff --git a/app/src/main/java/com/nextcloud/talk/shareditems/repositories/SharedItemsRepositoryImpl.kt b/app/src/main/java/com/nextcloud/talk/shareditems/repositories/SharedItemsRepositoryImpl.kt index 21d7419ca..ea3d5f6df 100644 --- a/app/src/main/java/com/nextcloud/talk/shareditems/repositories/SharedItemsRepositoryImpl.kt +++ b/app/src/main/java/com/nextcloud/talk/shareditems/repositories/SharedItemsRepositoryImpl.kt @@ -105,7 +105,7 @@ class SharedItemsRepositoryImpl @Inject constructor(private val ncApi: NcApi, pr fileParameters["link"]!!, fileParameters["mimetype"]!!, previewAvailable, - previewLink(fileParameters["id"], parameters.baseUrl) + previewLink(fileParameters["id"], parameters.baseUrl!!) ) } else if (it.value.messageParameters?.containsKey("object") == true) { val objectParameters = it.value.messageParameters!!["object"]!! @@ -184,7 +184,7 @@ class SharedItemsRepositoryImpl @Inject constructor(private val ncApi: NcApi, pr return ncApi.getSharedItemsOverview( credentials, - ApiUtils.getUrlForChatSharedItemsOverview(1, parameters.baseUrl, parameters.roomToken), + ApiUtils.getUrlForChatSharedItemsOverview(1, parameters.baseUrl!!, parameters.roomToken), 1 ).map { val types = mutableSetOf() @@ -206,7 +206,7 @@ class SharedItemsRepositoryImpl @Inject constructor(private val ncApi: NcApi, pr private fun previewLink(fileId: String?, baseUrl: String): String { return ApiUtils.getUrlForFilePreviewWithFileId( baseUrl, - fileId, + fileId!!, sharedApplication!!.resources.getDimensionPixelSize(R.dimen.maximum_file_preview_size) ) } diff --git a/app/src/main/java/com/nextcloud/talk/translate/viewmodels/TranslateViewModel.kt b/app/src/main/java/com/nextcloud/talk/translate/viewmodels/TranslateViewModel.kt index 99a40e3bc..323a9aad1 100644 --- a/app/src/main/java/com/nextcloud/talk/translate/viewmodels/TranslateViewModel.kt +++ b/app/src/main/java/com/nextcloud/talk/translate/viewmodels/TranslateViewModel.kt @@ -37,8 +37,8 @@ class TranslateViewModel @Inject constructor( fun translateMessage(toLanguage: String, fromLanguage: String?, text: String) { val currentUser: User = userManager.currentUser.blockingGet() - val authorization: String = ApiUtils.getCredentials(currentUser.username, currentUser.token) - val url: String = ApiUtils.getUrlForTranslation(currentUser.baseUrl) + val authorization: String = ApiUtils.getCredentials(currentUser.username, currentUser.token)!! + val url: String = ApiUtils.getUrlForTranslation(currentUser.baseUrl!!) val calculatedFromLanguage = if (fromLanguage == null || fromLanguage == "") { null @@ -60,8 +60,8 @@ class TranslateViewModel @Inject constructor( fun getLanguages() { val currentUser: User = userManager.currentUser.blockingGet() - val authorization: String = ApiUtils.getCredentials(currentUser.username, currentUser.token) - val url: String = ApiUtils.getUrlForLanguages(currentUser.baseUrl) + val authorization: String = ApiUtils.getCredentials(currentUser.username, currentUser.token)!! + val url: String = ApiUtils.getUrlForLanguages(currentUser.baseUrl!!) Log.d(TAG, "URL is: $url") repository.getLanguages(authorization, url) .subscribeOn(Schedulers.io()) diff --git a/app/src/main/java/com/nextcloud/talk/ui/bottom/sheet/ProfileBottomSheet.kt b/app/src/main/java/com/nextcloud/talk/ui/bottom/sheet/ProfileBottomSheet.kt index 605e65b11..70e655c1f 100644 --- a/app/src/main/java/com/nextcloud/talk/ui/bottom/sheet/ProfileBottomSheet.kt +++ b/app/src/main/java/com/nextcloud/talk/ui/bottom/sheet/ProfileBottomSheet.kt @@ -57,7 +57,7 @@ class ProfileBottomSheet(val ncApi: NcApi, val userModel: User, val viewThemeUti fun showFor(user: String, context: Context) { ncApi.hoverCard( ApiUtils.getCredentials(userModel.username, userModel.token), - ApiUtils.getUrlForHoverCard(userModel.baseUrl, user) + ApiUtils.getUrlForHoverCard(userModel.baseUrl!!, user) ).subscribeOn(Schedulers.io()).observeOn(AndroidSchedulers.mainThread()) .subscribe(object : Observer { override fun onSubscribe(d: Disposable) { @@ -121,10 +121,10 @@ class ProfileBottomSheet(val ncApi: NcApi, val userModel: User, val viewThemeUti private fun talkTo(userId: String, context: Context) { val apiVersion = - ApiUtils.getConversationApiVersion(userModel, intArrayOf(ApiUtils.APIv4, 1)) + ApiUtils.getConversationApiVersion(userModel, intArrayOf(ApiUtils.API_V4, 1)) val retrofitBucket = ApiUtils.getRetrofitBucketForCreateRoom( apiVersion, - userModel.baseUrl, + userModel.baseUrl!!, "1", null, userId, diff --git a/app/src/main/java/com/nextcloud/talk/ui/dialog/AttachmentDialog.kt b/app/src/main/java/com/nextcloud/talk/ui/dialog/AttachmentDialog.kt index 0171c3f0e..0db62cacf 100644 --- a/app/src/main/java/com/nextcloud/talk/ui/dialog/AttachmentDialog.kt +++ b/app/src/main/java/com/nextcloud/talk/ui/dialog/AttachmentDialog.kt @@ -35,7 +35,8 @@ import com.nextcloud.talk.application.NextcloudTalkApplication import com.nextcloud.talk.chat.ChatActivity import com.nextcloud.talk.databinding.DialogAttachmentBinding import com.nextcloud.talk.ui.theme.ViewThemeUtils -import com.nextcloud.talk.utils.database.user.CapabilitiesUtilNew +import com.nextcloud.talk.utils.SpreedFeatures +import com.nextcloud.talk.utils.CapabilitiesUtil import javax.inject.Inject @AutoInjector(NextcloudTalkApplication::class) @@ -61,7 +62,7 @@ class AttachmentDialog(val activity: Activity, var chatActivity: ChatActivity) : } private fun initItemsStrings() { - var serverName = CapabilitiesUtilNew.getServerName(chatActivity.conversationUser) + var serverName = CapabilitiesUtil.getServerName(chatActivity.conversationUser) dialogAttachmentBinding.txtAttachFileFromCloud.text = chatActivity.resources?.let { if (serverName.isNullOrEmpty()) { serverName = it.getString(R.string.nc_server_product_name) @@ -71,15 +72,15 @@ class AttachmentDialog(val activity: Activity, var chatActivity: ChatActivity) : } private fun initItemsVisibility() { - if (!CapabilitiesUtilNew.hasSpreedFeatureCapability( - chatActivity.conversationUser, - "geo-location-sharing" + if (!CapabilitiesUtil.hasSpreedFeatureCapability( + chatActivity.spreedCapabilities, + SpreedFeatures.GEO_LOCATION_SHARING ) ) { dialogAttachmentBinding.menuShareLocation.visibility = View.GONE } - if (!CapabilitiesUtilNew.hasSpreedFeatureCapability(chatActivity.conversationUser, "talk-polls") || + if (!CapabilitiesUtil.hasSpreedFeatureCapability(chatActivity.spreedCapabilities, SpreedFeatures.TALK_POLLS) || chatActivity.isOneToOneConversation() ) { dialogAttachmentBinding.menuAttachPoll.visibility = View.GONE diff --git a/app/src/main/java/com/nextcloud/talk/ui/dialog/ChooseAccountDialogFragment.java b/app/src/main/java/com/nextcloud/talk/ui/dialog/ChooseAccountDialogFragment.java index 261df9edc..4ab8605c1 100644 --- a/app/src/main/java/com/nextcloud/talk/ui/dialog/ChooseAccountDialogFragment.java +++ b/app/src/main/java/com/nextcloud/talk/ui/dialog/ChooseAccountDialogFragment.java @@ -54,7 +54,7 @@ import com.nextcloud.talk.ui.theme.ViewThemeUtils; import com.nextcloud.talk.users.UserManager; import com.nextcloud.talk.utils.ApiUtils; import com.nextcloud.talk.utils.DisplayUtils; -import com.nextcloud.talk.utils.database.user.CapabilitiesUtilNew; +import com.nextcloud.talk.utils.CapabilitiesUtil; import java.net.CookieManager; import java.util.ArrayList; @@ -262,7 +262,7 @@ public class ChooseAccountDialogFragment extends DialogFragment { private void loadCurrentStatus(User user) { String credentials = ApiUtils.getCredentials(user.getUsername(), user.getToken()); - if (CapabilitiesUtilNew.isUserStatusAvailable(userManager.getCurrentUser().blockingGet())) { + if (CapabilitiesUtil.isUserStatusAvailable(userManager.getCurrentUser().blockingGet())) { binding.statusView.setVisibility(View.VISIBLE); ncApi.status(credentials, ApiUtils.getUrlForStatus(user.getBaseUrl())). diff --git a/app/src/main/java/com/nextcloud/talk/ui/dialog/ChooseAccountShareToDialogFragment.kt b/app/src/main/java/com/nextcloud/talk/ui/dialog/ChooseAccountShareToDialogFragment.kt index 7e024a1a9..35d5c8d0d 100644 --- a/app/src/main/java/com/nextcloud/talk/ui/dialog/ChooseAccountShareToDialogFragment.kt +++ b/app/src/main/java/com/nextcloud/talk/ui/dialog/ChooseAccountShareToDialogFragment.kt @@ -89,7 +89,7 @@ class ChooseAccountShareToDialogFragment : DialogFragment() { if (user != null) { binding!!.currentAccount.userName.text = user.displayName binding!!.currentAccount.ticker.visibility = View.GONE - binding!!.currentAccount.account.text = Uri.parse(user.baseUrl).host + binding!!.currentAccount.account.text = Uri.parse(user.baseUrl!!).host viewThemeUtils!!.platform.colorImageView(binding!!.currentAccount.accountMenu, ColorRole.PRIMARY) if (user.baseUrl != null && (user.baseUrl!!.startsWith("http://") || user.baseUrl!!.startsWith("https://")) 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 b64e7d619..0006a9bc1 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 @@ -46,7 +46,7 @@ import com.nextcloud.talk.users.UserManager import com.nextcloud.talk.utils.ApiUtils import com.nextcloud.talk.utils.bundle.BundleKeys.KEY_INTERNAL_USER_ID import com.nextcloud.talk.utils.bundle.BundleKeys.KEY_ROOM_TOKEN -import com.nextcloud.talk.utils.database.user.CapabilitiesUtilNew +import com.nextcloud.talk.utils.CapabilitiesUtil import io.reactivex.Observer import io.reactivex.android.schedulers.AndroidSchedulers import io.reactivex.disposables.Disposable @@ -86,7 +86,7 @@ class ConversationsListBottomDialog( initItemsVisibility() initClickListeners() - credentials = ApiUtils.getCredentials(currentUser.username, currentUser.token) + credentials = ApiUtils.getCredentials(currentUser.username, currentUser.token)!! } override fun onStart() { @@ -105,7 +105,10 @@ class ConversationsListBottomDialog( } private fun initItemsVisibility() { - val hasFavoritesCapability = CapabilitiesUtilNew.hasSpreedFeatureCapability(currentUser, "favorites") + val hasFavoritesCapability = CapabilitiesUtil.hasSpreedFeatureCapability( + currentUser.capabilities?.spreedCapability!!, + "favorites" + ) val canModerate = conversation.canModerate(currentUser) binding.conversationRemoveFromFavorites.visibility = setVisibleIf( @@ -116,11 +119,19 @@ class ConversationsListBottomDialog( ) binding.conversationMarkAsRead.visibility = setVisibleIf( - conversation.unreadMessages > 0 && CapabilitiesUtilNew.canSetChatReadMarker(currentUser) + conversation.unreadMessages > 0 && CapabilitiesUtil.hasSpreedFeatureCapability( + currentUser + .capabilities?.spreedCapability!!, + "chat-read-marker" + ) ) binding.conversationMarkAsUnread.visibility = setVisibleIf( - conversation.unreadMessages <= 0 && CapabilitiesUtilNew.canMarkRoomAsUnread(currentUser) + conversation.unreadMessages <= 0 && CapabilitiesUtil.hasSpreedFeatureCapability( + currentUser + .capabilities?.spreedCapability!!, + "chat-unread" + ) ) binding.conversationOperationRename.visibility = setVisibleIf( @@ -178,12 +189,12 @@ class ConversationsListBottomDialog( } private fun addConversationToFavorites() { - val apiVersion = ApiUtils.getConversationApiVersion(currentUser, intArrayOf(ApiUtils.APIv4, ApiUtils.APIv1)) + val apiVersion = ApiUtils.getConversationApiVersion(currentUser, intArrayOf(ApiUtils.API_V4, ApiUtils.API_V1)) ncApi.addConversationToFavorites( credentials, ApiUtils.getUrlForRoomFavorite( apiVersion, - currentUser.baseUrl, + currentUser.baseUrl!!, conversation.token ) ) @@ -218,12 +229,12 @@ class ConversationsListBottomDialog( } private fun removeConversationFromFavorites() { - val apiVersion = ApiUtils.getConversationApiVersion(currentUser, intArrayOf(ApiUtils.APIv4, ApiUtils.APIv1)) + val apiVersion = ApiUtils.getConversationApiVersion(currentUser, intArrayOf(ApiUtils.API_V4, ApiUtils.API_V1)) ncApi.removeConversationFromFavorites( credentials, ApiUtils.getUrlForRoomFavorite( apiVersion, - currentUser.baseUrl, + currentUser.baseUrl!!, conversation.token ) ) @@ -262,8 +273,8 @@ class ConversationsListBottomDialog( credentials, ApiUtils.getUrlForChatReadMarker( chatApiVersion(), - currentUser.baseUrl, - conversation.token + currentUser.baseUrl!!, + conversation.token!! ) ) .subscribeOn(Schedulers.io()) @@ -301,8 +312,8 @@ class ConversationsListBottomDialog( credentials, ApiUtils.getUrlForChatReadMarker( chatApiVersion(), - currentUser.baseUrl, - conversation.token + currentUser.baseUrl!!, + conversation.token!! ), conversation.lastMessage!!.jsonMessageId ) @@ -396,7 +407,7 @@ class ConversationsListBottomDialog( } private fun chatApiVersion(): Int { - return ApiUtils.getChatApiVersion(currentUser, intArrayOf(ApiUtils.APIv1)) + return ApiUtils.getChatApiVersion(currentUser.capabilities!!.spreedCapability!!, intArrayOf(ApiUtils.API_V1)) } companion object { diff --git a/app/src/main/java/com/nextcloud/talk/ui/dialog/DateTimePickerFragment.kt b/app/src/main/java/com/nextcloud/talk/ui/dialog/DateTimePickerFragment.kt index 93a8d42db..65afc1888 100644 --- a/app/src/main/java/com/nextcloud/talk/ui/dialog/DateTimePickerFragment.kt +++ b/app/src/main/java/com/nextcloud/talk/ui/dialog/DateTimePickerFragment.kt @@ -50,7 +50,8 @@ import javax.inject.Inject class DateTimePickerFragment( token: String, id: String, - chatViewModel: ChatViewModel + chatViewModel: ChatViewModel, + private val chatApiVersion: Int ) : DialogFragment() { lateinit var binding: DialogDateTimePickerBinding private var dialogView: View? = null @@ -144,7 +145,7 @@ class DateTimePickerFragment( } private fun getReminder() { - viewModel.getReminder(userManager.currentUser.blockingGet(), roomToken, messageId) + viewModel.getReminder(userManager.currentUser.blockingGet(), roomToken, messageId, chatApiVersion) } private fun showDelete(value: Boolean) { @@ -221,12 +222,18 @@ class DateTimePickerFragment( binding.buttonClose.setOnClickListener { dismiss() } binding.buttonSet.setOnClickListener { currentTimeStamp?.let { time -> - viewModel.setReminder(userManager.currentUser.blockingGet(), roomToken, messageId, time.toInt()) + viewModel.setReminder( + userManager.currentUser.blockingGet(), + roomToken, + messageId, + time.toInt(), + chatApiVersion + ) } dismiss() } binding.buttonDelete.setOnClickListener { - viewModel.deleteReminder(userManager.currentUser.blockingGet(), roomToken, messageId) + viewModel.deleteReminder(userManager.currentUser.blockingGet(), roomToken, messageId, chatApiVersion) } } @@ -299,11 +306,12 @@ class DateTimePickerFragment( private const val HOUR_SIX_PM = 18 @JvmStatic - fun newInstance(token: String, id: String, chatViewModel: ChatViewModel) = + fun newInstance(token: String, id: String, chatViewModel: ChatViewModel, chatApiVersion: Int) = DateTimePickerFragment( token, id, - chatViewModel + chatViewModel, + chatApiVersion ) } } 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 ea6a9e936..b30099e81 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 @@ -46,14 +46,17 @@ import com.nextcloud.talk.models.domain.ConversationReadOnlyState import com.nextcloud.talk.models.domain.ConversationType import com.nextcloud.talk.models.domain.ReactionAddedModel import com.nextcloud.talk.models.domain.ReactionDeletedModel +import com.nextcloud.talk.models.json.capabilities.SpreedCapability import com.nextcloud.talk.models.json.chat.ChatMessage import com.nextcloud.talk.repositories.reactions.ReactionsRepository import com.nextcloud.talk.ui.theme.ViewThemeUtils import com.nextcloud.talk.utils.ApiUtils +import com.nextcloud.talk.utils.SpreedFeatures import com.nextcloud.talk.utils.ConversationUtils import com.nextcloud.talk.utils.DateConstants import com.nextcloud.talk.utils.DateUtils -import com.nextcloud.talk.utils.database.user.CapabilitiesUtilNew +import com.nextcloud.talk.utils.CapabilitiesUtil +import com.nextcloud.talk.utils.CapabilitiesUtil.hasSpreedFeatureCapability import com.vanniktech.emoji.EmojiPopup import com.vanniktech.emoji.EmojiTextView import com.vanniktech.emoji.installDisableKeyboardInput @@ -72,7 +75,8 @@ class MessageActionsDialog( private val user: User?, private val currentConversation: ConversationModel?, private val showMessageDeletionButton: Boolean, - private val hasChatPermission: Boolean + private val hasChatPermission: Boolean, + private val spreedCapabilities: SpreedCapability ) : BottomSheetDialog(chatActivity) { @Inject @@ -100,8 +104,8 @@ class MessageActionsDialog( private val isUserAllowedToEdit = chatActivity.userAllowedByPrivilages(message) - private val isMessageEditable = CapabilitiesUtilNew.hasSpreedFeatureCapability( - user, + private val isMessageEditable = CapabilitiesUtil.hasSpreedFeatureCapability( + spreedCapabilities, "edit-messages" ) && messageHasRegularText && !isOlderThanTwentyFourHours && isUserAllowedToEdit @@ -116,9 +120,9 @@ class MessageActionsDialog( viewThemeUtils.platform.themeDialog(dialogMessageActionsBinding.root) initEmojiBar(hasChatPermission) initMenuItemCopy(!message.isDeleted) - val apiVersion = ApiUtils.getConversationApiVersion(user, intArrayOf(ApiUtils.APIv4, ApiUtils.APIv3, 1)) + val apiVersion = ApiUtils.getConversationApiVersion(user!!, intArrayOf(ApiUtils.API_V4, ApiUtils.API_V3, 1)) chatActivity.chatViewModel.checkForNoteToSelf( - ApiUtils.getCredentials(user!!.username, user.token), + ApiUtils.getCredentials(user!!.username, user.token)!!, ApiUtils.getUrlForRooms( apiVersion, user.baseUrl @@ -144,7 +148,7 @@ class MessageActionsDialog( initMenuItemTranslate( !message.isDeleted && ChatMessage.MessageType.REGULAR_TEXT_MESSAGE == message.getCalculateMessageType() && - CapabilitiesUtilNew.isTranslationsSupported(user) + CapabilitiesUtil.isTranslationsSupported(spreedCapabilities) ) initMenuEditorDetails(message.lastEditTimestamp != 0L && !message.isDeleted) initMenuReplyToMessage(message.replyable && hasChatPermission) @@ -160,7 +164,10 @@ class MessageActionsDialog( ChatMessage.MessageType.REGULAR_TEXT_MESSAGE == message.getCalculateMessageType() && !(message.isDeletedCommentMessage || message.isDeleted) ) - initMenuRemindMessage(!message.isDeleted && CapabilitiesUtilNew.isRemindSupported(user)) + initMenuRemindMessage( + !message.isDeleted && CapabilitiesUtil.hasSpreedFeatureCapability + (spreedCapabilities, "remind-me-later") + ) initMenuMarkAsUnread( message.previousMessageId > NO_PREVIOUS_MESSAGE_ID && ChatMessage.MessageType.SYSTEM_MESSAGE != message.getCalculateMessageType() @@ -242,7 +249,7 @@ class MessageActionsDialog( } private fun initEmojiBar(hasChatPermission: Boolean) { - if (CapabilitiesUtilNew.hasSpreedFeatureCapability(user, "reactions") && + if (hasSpreedFeatureCapability(spreedCapabilities, SpreedFeatures.REACTIONS) && isPermitted(hasChatPermission) && isReactableMessageType(message) ) { diff --git a/app/src/main/java/com/nextcloud/talk/ui/dialog/MoreCallActionsDialog.kt b/app/src/main/java/com/nextcloud/talk/ui/dialog/MoreCallActionsDialog.kt index 73f4a6cbb..68a1ff324 100644 --- a/app/src/main/java/com/nextcloud/talk/ui/dialog/MoreCallActionsDialog.kt +++ b/app/src/main/java/com/nextcloud/talk/ui/dialog/MoreCallActionsDialog.kt @@ -35,7 +35,7 @@ import com.nextcloud.talk.application.NextcloudTalkApplication import com.nextcloud.talk.databinding.DialogMoreCallActionsBinding import com.nextcloud.talk.raisehand.viewmodel.RaiseHandViewModel import com.nextcloud.talk.ui.theme.ViewThemeUtils -import com.nextcloud.talk.utils.database.user.CapabilitiesUtilNew +import com.nextcloud.talk.utils.CapabilitiesUtil import com.nextcloud.talk.viewmodels.CallRecordingViewModel import com.vanniktech.emoji.EmojiTextView import javax.inject.Inject @@ -72,7 +72,7 @@ class MoreCallActionsDialog(private val callActivity: CallActivity) : BottomShee } private fun initItemsVisibility() { - if (CapabilitiesUtilNew.isCallReactionsSupported(callActivity.conversationUser)) { + if (CapabilitiesUtil.isCallReactionsSupported(callActivity.conversationUser)) { binding.callEmojiBar.visibility = View.VISIBLE } else { binding.callEmojiBar.visibility = View.GONE @@ -102,7 +102,7 @@ class MoreCallActionsDialog(private val callActivity: CallActivity) : BottomShee } private fun initEmojiBar() { - if (CapabilitiesUtilNew.isCallReactionsSupported(callActivity.conversationUser)) { + if (CapabilitiesUtil.isCallReactionsSupported(callActivity.conversationUser)) { binding.advancedCallOptionsTitle.visibility = View.GONE val capabilities = callActivity.conversationUser?.capabilities diff --git a/app/src/main/java/com/nextcloud/talk/ui/dialog/SetStatusDialogFragment.kt b/app/src/main/java/com/nextcloud/talk/ui/dialog/SetStatusDialogFragment.kt index eab617bc5..90ec08774 100644 --- a/app/src/main/java/com/nextcloud/talk/ui/dialog/SetStatusDialogFragment.kt +++ b/app/src/main/java/com/nextcloud/talk/ui/dialog/SetStatusDialogFragment.kt @@ -128,8 +128,8 @@ class SetStatusDialogFragment : currentUser = currentUserProvider?.currentUser?.blockingGet() currentStatus = it.getParcelable(ARG_CURRENT_STATUS_PARAM) - credentials = ApiUtils.getCredentials(currentUser?.username, currentUser?.token) - ncApi.getPredefinedStatuses(credentials, ApiUtils.getUrlForPredefinedStatuses(currentUser?.baseUrl)) + credentials = ApiUtils.getCredentials(currentUser?.username, currentUser?.token)!! + ncApi.getPredefinedStatuses(credentials, ApiUtils.getUrlForPredefinedStatuses(currentUser?.baseUrl!!)) .subscribeOn(Schedulers.io()) .observeOn(AndroidSchedulers.mainThread()) .subscribe(object : Observer { @@ -369,7 +369,7 @@ class SetStatusDialogFragment : private fun clearStatus() { val credentials = ApiUtils.getCredentials(currentUser?.username, currentUser?.token) - ncApi.statusDeleteMessage(credentials, ApiUtils.getUrlForStatusMessage(currentUser?.baseUrl)) + ncApi.statusDeleteMessage(credentials, ApiUtils.getUrlForStatusMessage(currentUser?.baseUrl!!)) .subscribeOn(Schedulers.io()) .observeOn(AndroidSchedulers.mainThread()).subscribe(object : Observer { override fun onSubscribe(d: Disposable) { @@ -393,7 +393,7 @@ class SetStatusDialogFragment : private fun setStatus(statusType: StatusType) { visualizeStatus(statusType) - ncApi.setStatusType(credentials, ApiUtils.getUrlForSetStatusType(currentUser?.baseUrl), statusType.string) + ncApi.setStatusType(credentials, ApiUtils.getUrlForSetStatusType(currentUser?.baseUrl!!), statusType.string) .subscribeOn( Schedulers .io() @@ -468,7 +468,7 @@ class SetStatusDialogFragment : ) { ncApi.setCustomStatusMessage( credentials, - ApiUtils.getUrlForSetCustomStatus(currentUser?.baseUrl), + ApiUtils.getUrlForSetCustomStatus(currentUser?.baseUrl!!), statusIcon, inputText, clearAt @@ -499,7 +499,7 @@ class SetStatusDialogFragment : ncApi.setPredefinedStatusMessage( credentials, - ApiUtils.getUrlForSetPredefinedStatus(currentUser?.baseUrl), + ApiUtils.getUrlForSetPredefinedStatus(currentUser?.baseUrl!!), selectedPredefinedStatus!!.id, if (clearAt == -1L) null else clearAt ) diff --git a/app/src/main/java/com/nextcloud/talk/ui/dialog/ShowReactionsDialog.kt b/app/src/main/java/com/nextcloud/talk/ui/dialog/ShowReactionsDialog.kt index 196a21b2c..72d691cda 100644 --- a/app/src/main/java/com/nextcloud/talk/ui/dialog/ShowReactionsDialog.kt +++ b/app/src/main/java/com/nextcloud/talk/ui/dialog/ShowReactionsDialog.kt @@ -154,7 +154,7 @@ class ShowReactionsDialog( ncApi.getReactions( credentials, ApiUtils.getUrlForMessageReaction( - user?.baseUrl, + user?.baseUrl!!, roomToken, chatMessage.id ), @@ -209,7 +209,7 @@ class ShowReactionsDialog( ncApi.deleteReaction( credentials, ApiUtils.getUrlForMessageReaction( - user?.baseUrl, + user?.baseUrl!!, roomToken, message.id ), diff --git a/app/src/main/java/com/nextcloud/talk/upload/chunked/ChunkedFileUploader.kt b/app/src/main/java/com/nextcloud/talk/upload/chunked/ChunkedFileUploader.kt index 23204c263..48f392523 100644 --- a/app/src/main/java/com/nextcloud/talk/upload/chunked/ChunkedFileUploader.kt +++ b/app/src/main/java/com/nextcloud/talk/upload/chunked/ChunkedFileUploader.kt @@ -81,7 +81,7 @@ class ChunkedFileUploader( init { initHttpClient(okHttpClient, currentUser) - remoteChunkUrl = ApiUtils.getUrlForChunkedUpload(currentUser.baseUrl, currentUser.userId) + remoteChunkUrl = ApiUtils.getUrlForChunkedUpload(currentUser.baseUrl!!, currentUser.userId!!) } @Suppress("Detekt.TooGenericExceptionCaught") @@ -295,7 +295,7 @@ class ChunkedFileUploader( ApiUtils.getCredentials( currentUser.username, currentUser.token - ), + )!!, "Authorization" ) ) @@ -304,8 +304,8 @@ class ChunkedFileUploader( private fun assembleChunks(uploadFolderUri: String, targetPath: String) { val destinationUri: String = ApiUtils.getUrlForFileUpload( - currentUser.baseUrl, - currentUser.userId, + currentUser.baseUrl!!, + currentUser.userId!!, targetPath ) val originUri = "$uploadFolderUri/.file" diff --git a/app/src/main/java/com/nextcloud/talk/upload/normal/FileUploader.kt b/app/src/main/java/com/nextcloud/talk/upload/normal/FileUploader.kt index d21f90605..066d7eb9f 100644 --- a/app/src/main/java/com/nextcloud/talk/upload/normal/FileUploader.kt +++ b/app/src/main/java/com/nextcloud/talk/upload/normal/FileUploader.kt @@ -24,7 +24,7 @@ class FileUploader( fun upload(sourceFileUri: Uri, fileName: String, remotePath: String, metaData: String?): Observable { return ncApi.uploadFile( ApiUtils.getCredentials(currentUser.username, currentUser.token), - ApiUtils.getUrlForFileUpload(currentUser.baseUrl, currentUser.userId, remotePath), + ApiUtils.getUrlForFileUpload(currentUser.baseUrl!!, currentUser.userId!!, remotePath), createRequestBody(sourceFileUri) ) .subscribeOn(Schedulers.io()) diff --git a/app/src/main/java/com/nextcloud/talk/utils/AccountUtils.kt b/app/src/main/java/com/nextcloud/talk/utils/AccountUtils.kt index 80cc199dc..5fd99b3fc 100644 --- a/app/src/main/java/com/nextcloud/talk/utils/AccountUtils.kt +++ b/app/src/main/java/com/nextcloud/talk/utils/AccountUtils.kt @@ -69,7 +69,7 @@ object AccountUtils { private fun matchAccounts(importAccount: ImportAccount, user: User): Boolean { var accountFound = false if (importAccount.token != null) { - if (UriUtils.hasHttpProtocolPrefixed(importAccount.baseUrl)) { + if (UriUtils.hasHttpProtocolPrefixed(importAccount.baseUrl!!)) { if ( user.username == importAccount.username && user.baseUrl == importAccount.baseUrl diff --git a/app/src/main/java/com/nextcloud/talk/utils/ApiUtils.java b/app/src/main/java/com/nextcloud/talk/utils/ApiUtils.java deleted file mode 100644 index c36d882f1..000000000 --- a/app/src/main/java/com/nextcloud/talk/utils/ApiUtils.java +++ /dev/null @@ -1,559 +0,0 @@ -/* - * Nextcloud Talk application - * - * @author Mario Danic - * @author Marcel Hibbe - * @author Tim Krüger - * Copyright (C) 2021 Tim Krüger - * Copyright (C) 2021-2022 Marcel Hibbe - * Copyright (C) 2017-2018 Mario Danic - * - * 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.utils; - -import android.net.Uri; -import android.text.TextUtils; -import android.util.Log; - -import com.nextcloud.talk.BuildConfig; -import com.nextcloud.talk.R; -import com.nextcloud.talk.application.NextcloudTalkApplication; -import com.nextcloud.talk.data.user.model.User; -import com.nextcloud.talk.models.RetrofitBucket; -import com.nextcloud.talk.utils.database.user.CapabilitiesUtilNew; - -import java.nio.charset.StandardCharsets; -import java.util.HashMap; -import java.util.Map; - -import androidx.annotation.NonNull; -import androidx.annotation.Nullable; -import okhttp3.Credentials; - -public class ApiUtils { - public static final int APIv1 = 1; - public static final int APIv2 = 2; - public static final int APIv3 = 3; - public static final int APIv4 = 4; - public static final int AVATAR_SIZE_BIG = 512; - public static final int AVATAR_SIZE_SMALL = 64; - private static final String TAG = "ApiUtils"; - private static final String ocsApiVersion = "/ocs/v2.php"; - private static final String spreedApiVersion = "/apps/spreed/api/v1"; - private static final String spreedApiBase = ocsApiVersion + "/apps/spreed/api/v"; - - private static final String userAgent = "Mozilla/5.0 (Android) Nextcloud-Talk v"; - - public static String getUserAgent() { - return userAgent + BuildConfig.VERSION_NAME; - } - - /** - * @deprecated This is only supported on API v1-3, in API v4+ please use - * {@link ApiUtils#getUrlForAttendees(int, String, String)} instead. - */ - @Deprecated - public static String getUrlForRemovingParticipantFromConversation(String baseUrl, String roomToken, boolean isGuest) { - String url = getUrlForParticipants(APIv1, baseUrl, roomToken); - - if (isGuest) { - url += "/guests"; - } - - return url; - } - - public static RetrofitBucket getRetrofitBucketForContactsSearch(String baseUrl, @Nullable String searchQuery) { - RetrofitBucket retrofitBucket = new RetrofitBucket(); - retrofitBucket.setUrl(baseUrl + ocsApiVersion + "/apps/files_sharing/api/v1/sharees"); - - Map queryMap = new HashMap<>(); - - if (searchQuery == null) { - searchQuery = ""; - } - queryMap.put("format", "json"); - queryMap.put("search", searchQuery); - queryMap.put("itemType", "call"); - - retrofitBucket.setQueryMap(queryMap); - - return retrofitBucket; - } - - public static String getUrlForFilePreviewWithRemotePath(String baseUrl, String remotePath, int px) { - return baseUrl + "/index.php/core/preview.png?file=" - + Uri.encode(remotePath, "UTF-8") - + "&x=" + px + "&y=" + px + "&a=1&mode=cover&forceIcon=1"; - } - - public static String getUrlForFilePreviewWithFileId(String baseUrl, String fileId, int px) { - return baseUrl + "/index.php/core/preview?fileId=" - + fileId + "&x=" + px + "&y=" + px + "&a=1&mode=cover&forceIcon=1"; - } - - public static String getSharingUrl(String baseUrl) { - return baseUrl + ocsApiVersion + "/apps/files_sharing/api/v1/shares"; - } - - public static RetrofitBucket getRetrofitBucketForContactsSearchFor14(String baseUrl, @Nullable String searchQuery) { - RetrofitBucket retrofitBucket = getRetrofitBucketForContactsSearch(baseUrl, searchQuery); - retrofitBucket.setUrl(baseUrl + ocsApiVersion + "/core/autocomplete/get"); - - retrofitBucket.getQueryMap().put("itemId", "new"); - - return retrofitBucket; - } - - public static String getUrlForCapabilities(String baseUrl) { - return baseUrl + ocsApiVersion + "/cloud/capabilities"; - } - - public static int getCallApiVersion(User capabilities, int[] versions) throws NoSupportedApiException { - return getConversationApiVersion(capabilities, versions); - } - - public static int getConversationApiVersion(User user, int[] versions) throws NoSupportedApiException { - boolean hasApiV4 = false; - for (int version : versions) { - hasApiV4 |= version == APIv4; - } - - if (!hasApiV4) { - Exception e = new Exception("Api call did not try conversation-v4 api"); - Log.d(TAG, e.getMessage(), e); - } - - for (int version : versions) { - if (user.hasSpreedFeatureCapability("conversation-v" + version)) { - return version; - } - - // Fallback for old API versions - if ((version == APIv1 || version == APIv2)) { - if (user.hasSpreedFeatureCapability("conversation-v2")) { - return version; - } - if (version == APIv1 && - user.hasSpreedFeatureCapability("mention-flag") && - !user.hasSpreedFeatureCapability("conversation-v4")) { - return version; - } - } - } - throw new NoSupportedApiException(); - } - - public static int getSignalingApiVersion(User user, int[] versions) throws NoSupportedApiException { - for (int version : versions) { - if (CapabilitiesUtilNew.hasSpreedFeatureCapability(user, "signaling-v" + version)) { - return version; - } - - if (version == APIv2 && - CapabilitiesUtilNew.hasSpreedFeatureCapability(user, "sip-support") && - !CapabilitiesUtilNew.hasSpreedFeatureCapability(user, "signaling-v3")) { - return version; - } - - if (version == APIv1 && - !CapabilitiesUtilNew.hasSpreedFeatureCapability(user, "signaling-v3")) { - // Has no capability, we just assume it is always there when there is no v3 or later - return version; - } - } - throw new NoSupportedApiException(); - } - - public static int getChatApiVersion(User user, int[] versions) throws NoSupportedApiException { - for (int version : versions) { - if (version == APIv1 && CapabilitiesUtilNew.hasSpreedFeatureCapability(user, "chat-v2")) { - // Do not question that chat-v2 capability shows the availability of api/v1/ endpoint *see no evil* - return version; - } - } - throw new NoSupportedApiException(); - } - - protected static String getUrlForApi(int version, String baseUrl) { - return baseUrl + spreedApiBase + version; - } - - public static String getUrlForRooms(int version, String baseUrl) { - return getUrlForApi(version, baseUrl) + "/room"; - } - - public static String getUrlForRoom(int version, String baseUrl, String token) { - return getUrlForRooms(version, baseUrl) + "/" + token; - } - - public static String getUrlForAttendees(int version, String baseUrl, String token) { - return getUrlForRoom(version, baseUrl, token) + "/attendees"; - } - - public static String getUrlForParticipants(int version, String baseUrl, String token) { - if (token == null || token.isEmpty()) { - Log.e(TAG, "token was null or empty"); - } - return getUrlForRoom(version, baseUrl, token) + "/participants"; - } - - public static String getUrlForParticipantsActive(int version, String baseUrl, String token) { - return getUrlForParticipants(version, baseUrl, token) + "/active"; - } - - public static String getUrlForParticipantsSelf(int version, String baseUrl, String token) { - 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"; - } - - public static String getUrlForRoomModerators(int version, String baseUrl, String token) { - return getUrlForRoom(version, baseUrl, token) + "/moderators"; - } - - public static String getUrlForRoomNotificationLevel(int version, String baseUrl, String token) { - return getUrlForRoom(version, baseUrl, token) + "/notify"; - } - - public static String getUrlForRoomPublic(int version, String baseUrl, String token) { - return getUrlForRoom(version, baseUrl, token) + "/public"; - } - - public static String getUrlForRoomPassword(int version, String baseUrl, String token) { - return getUrlForRoom(version, baseUrl, token) + "/password"; - } - - public static String getUrlForRoomReadOnlyState(int version, String baseUrl, String token) { - return getUrlForRoom(version, baseUrl, token) + "/read-only"; - } - - public static String getUrlForRoomWebinaryLobby(int version, String baseUrl, String token) { - return getUrlForRoom(version, baseUrl, token) + "/webinar/lobby"; - } - - public static String getUrlForRoomNotificationCalls(int version, String baseUrl, String token) { - return getUrlForRoom(version, baseUrl, token) + "/notify-calls"; - } - - public static String getUrlForCall(int version, String baseUrl, String token) { - return getUrlForApi(version, baseUrl) + "/call/" + token; - } - - public static String getUrlForChat(int version, String baseUrl, String token) { - return getUrlForApi(version, baseUrl) + "/chat/" + token; - } - - public static String getUrlForMentionSuggestions(int version, String baseUrl, String token) { - return getUrlForChat(version, baseUrl, token) + "/mentions"; - } - - public static String getUrlForChatMessage(int version, String baseUrl, String token, String messageId) { - return getUrlForChat(version, baseUrl, token) + "/" + messageId; - } - - public static String getUrlForChatSharedItems(int version, String baseUrl, String token) { - return getUrlForChat(version, baseUrl, token) + "/share"; - } - - public static String getUrlForChatSharedItemsOverview(int version, String baseUrl, String token) { - return getUrlForChatSharedItems(version, baseUrl, token) + "/overview"; - } - - public static String getUrlForSignaling(int version, String baseUrl) { - return getUrlForApi(version, baseUrl) + "/signaling"; - } - - public static String getUrlForSignalingBackend(int version, String baseUrl) { - return getUrlForSignaling(version, baseUrl) + "/backend"; - } - - public static String getUrlForSignalingSettings(int version, String baseUrl) { - return getUrlForSignaling(version, baseUrl) + "/settings"; - } - - public static String getUrlForSignaling(int version, String baseUrl, String token) { - return getUrlForSignaling(version, baseUrl) + "/" + token; - } - - public static String getUrlForOpenConversations(int version, String baseUrl) { - return getUrlForApi(version, baseUrl) + "/listed-room"; - } - - public static RetrofitBucket getRetrofitBucketForCreateRoom(int version, String baseUrl, String roomType, - @Nullable String source, - @Nullable String invite, - @Nullable String conversationName) { - RetrofitBucket retrofitBucket = new RetrofitBucket(); - retrofitBucket.setUrl(getUrlForRooms(version, baseUrl)); - Map queryMap = new HashMap<>(); - - queryMap.put("roomType", roomType); - if (invite != null) { - queryMap.put("invite", invite); - } - if (source != null) { - queryMap.put("source", source); - } - - if (conversationName != null) { - queryMap.put("roomName", conversationName); - } - - retrofitBucket.setQueryMap(queryMap); - - return retrofitBucket; - } - - public static RetrofitBucket getRetrofitBucketForAddParticipant(int version, String baseUrl, String token, String user) { - RetrofitBucket retrofitBucket = new RetrofitBucket(); - retrofitBucket.setUrl(getUrlForParticipants(version, baseUrl, token)); - - Map queryMap = new HashMap<>(); - - queryMap.put("newParticipant", user); - - retrofitBucket.setQueryMap(queryMap); - - return retrofitBucket; - - } - - public static RetrofitBucket getRetrofitBucketForAddParticipantWithSource( - int version, - String baseUrl, - String token, - String source, - String id - ) { - RetrofitBucket retrofitBucket = getRetrofitBucketForAddParticipant(version, baseUrl, token, id); - retrofitBucket.getQueryMap().put("source", source); - return retrofitBucket; - } - - public static String getUrlForUserProfile(String baseUrl) { - return baseUrl + ocsApiVersion + "/cloud/user"; - } - - public static String getUrlForUserData(String baseUrl, String userId) { - return baseUrl + ocsApiVersion + "/cloud/users/" + userId; - } - - public static String getUrlForUserSettings(String baseUrl) { - // FIXME Introduce API version - return baseUrl + ocsApiVersion + spreedApiVersion + "/settings/user"; - } - - public static String getUrlPostfixForStatus() { - return "/status.php"; - } - - public static String getUrlForAvatar(String baseUrl, String name, boolean requestBigSize) { - int avatarSize = requestBigSize ? AVATAR_SIZE_BIG : AVATAR_SIZE_SMALL; - return baseUrl + "/index.php/avatar/" + Uri.encode(name) + "/" + avatarSize; - } - - public static String getUrlForGuestAvatar(String baseUrl, String name, boolean requestBigSize) { - int avatarSize = requestBigSize ? AVATAR_SIZE_BIG : AVATAR_SIZE_SMALL; - return baseUrl + "/index.php/avatar/guest/" + Uri.encode(name) + "/" + avatarSize; - } - - public static String getUrlForConversationAvatar(int version, String baseUrl, String token) { - return getUrlForRoom(version, baseUrl, token) + "/avatar"; - } - - public static String getUrlForConversationAvatarWithVersion(int version, String baseUrl, String token, - boolean isDark, - String avatarVersion) { - String isDarkString = ""; - if (isDark) { - isDarkString = "/dark"; - } - - String avatarVersionString = ""; - if (avatarVersion != null) { - avatarVersionString = "?avatarVersion=" + avatarVersion; - } - - return getUrlForRoom(version, baseUrl, token) + "/avatar" + isDarkString + avatarVersionString; - } - - public static String getCredentials(String username, String token) { - if (TextUtils.isEmpty(username) && TextUtils.isEmpty(token)) { - return null; - } - return Credentials.basic(username, token, StandardCharsets.UTF_8); - } - - public static String getUrlNextcloudPush(String baseUrl) { - return baseUrl + ocsApiVersion + "/apps/notifications/api/v2/push"; - } - - public static String getUrlPushProxy() { - return NextcloudTalkApplication.Companion.getSharedApplication(). - getApplicationContext().getResources().getString(R.string.nc_push_server_url) + "/devices"; - } - - // see https://github.com/nextcloud/notifications/blob/master/docs/ocs-endpoint-v2.md - public static String getUrlForNcNotificationWithId(String baseUrl, String notificationId) { - return baseUrl + ocsApiVersion + "/apps/notifications/api/v2/notifications/" + notificationId; - } - - public static String getUrlForSearchByNumber(String baseUrl) { - return baseUrl + ocsApiVersion + "/cloud/users/search/by-phone"; - } - - public static String getUrlForFileUpload(String baseUrl, String user, String remotePath) { - return baseUrl + "/remote.php/dav/files/" + user + remotePath; - } - - public static String getUrlForChunkedUpload(String baseUrl, String user) { - return baseUrl + "/remote.php/dav/uploads/" + user; - } - - public static String getUrlForFileDownload(String baseUrl, String user, String remotePath) { - return baseUrl + "/remote.php/dav/files/" + user + "/" + remotePath; - } - - public static String getUrlForTempAvatar(String baseUrl) { - return baseUrl + ocsApiVersion + "/apps/spreed/temp-user-avatar"; - } - - public static String getUrlForUserFields(String baseUrl) { - return baseUrl + ocsApiVersion + "/cloud/user/fields"; - } - - public static String getUrlToSendLocation(int version, String baseUrl, String roomToken) { - return getUrlForChat(version, baseUrl, roomToken) + "/share"; - } - - public static String getUrlForHoverCard(String baseUrl, String userId) { - return baseUrl + ocsApiVersion + - "/hovercard/v1/" + userId; - } - - public static String getUrlForChatReadMarker(int version, String baseUrl, String roomToken) { - return getUrlForChat(version, baseUrl, roomToken) + "/read"; - } - - /* - * OCS Status API - */ - - public static String getUrlForStatus(String baseUrl) { - return baseUrl + ocsApiVersion + "/apps/user_status/api/v1/user_status"; - } - - public static String getUrlForSetStatusType(String baseUrl) { - return getUrlForStatus(baseUrl) + "/status"; - } - - public static String getUrlForPredefinedStatuses(String baseUrl) { - return baseUrl + ocsApiVersion + "/apps/user_status/api/v1/predefined_statuses"; - } - - public static String getUrlForStatusMessage(String baseUrl) { - return getUrlForStatus(baseUrl) + "/message"; - } - - public static String getUrlForSetCustomStatus(String baseUrl) { - return baseUrl + ocsApiVersion + "/apps/user_status/api/v1/user_status/message/custom"; - } - - public static String getUrlForSetPredefinedStatus(String baseUrl) { - return baseUrl + ocsApiVersion + "/apps/user_status/api/v1/user_status/message/predefined"; - } - - public static String getUrlForUserStatuses(String baseUrl) { - return baseUrl + ocsApiVersion + "/apps/user_status/api/v1/statuses"; - } - - public static String getUrlForMessageReaction(String baseUrl, - String roomToken, - String messageId) { - return baseUrl + ocsApiVersion + spreedApiVersion + "/reaction/" + roomToken + "/" + messageId; - } - - @NonNull - public static String getUrlForUnifiedSearch(@NonNull String baseUrl, @NonNull String providerId) { - return baseUrl + ocsApiVersion + "/search/providers/" + providerId + "/search"; - } - - public static String getUrlForPoll(String baseUrl, - String roomToken, - String pollId) { - return getUrlForPoll(baseUrl, roomToken) + "/" + pollId; - } - - public static String getUrlForPoll(String baseUrl, - String roomToken) { - return baseUrl + ocsApiVersion + spreedApiVersion + "/poll/" + roomToken; - } - - public static String getUrlForMessageExpiration(int version, String baseUrl, String token) { - return getUrlForRoom(version, baseUrl, token) + "/message-expiration"; - } - - public static String getUrlForOpenGraph(String baseUrl) { - return baseUrl + ocsApiVersion + "/references/resolve"; - } - - public static String getUrlForRecording(int version, String baseUrl, String token) { - return getUrlForApi(version, baseUrl) + "/recording/" + token; - } - - public static String getUrlForRequestAssistance(int version, String baseUrl, String token) { - return getUrlForApi(version, baseUrl) + "/breakout-rooms/" + token + "/request-assistance"; - } - - public static String getUrlForConversationDescription(int version, String baseUrl, String token) { - return getUrlForRoom(version, baseUrl, token) + "/description"; - } - - public static String getUrlForTranslation(String baseUrl) { - return baseUrl + ocsApiVersion + "/translation/translate"; - } - - public static String getUrlForLanguages(String baseUrl) { - return baseUrl + ocsApiVersion + "/translation/languages"; - } - - public static String getUrlForReminder(User user, String roomToken, String messageId, int version) { - String url = ApiUtils.getUrlForChatMessage(version, user.getBaseUrl(), roomToken, messageId); - return url + "/reminder"; - } - - public static String getUrlForRecordingConsent(int version, String baseUrl, String token) { - return getUrlForRoom(version, baseUrl, token) + "/recording-consent"; - } - - public static String getUrlForInvitation(String baseUrl) { - return baseUrl + ocsApiVersion + spreedApiVersion + "/federation/invitation"; - } - - public static String getUrlForInvitationAccept(String baseUrl, int id) { - return getUrlForInvitation(baseUrl) + "/" + id; - } - - public static String getUrlForInvitationReject(String baseUrl, int id) { - return getUrlForInvitation(baseUrl) + "/" + id; - } -} diff --git a/app/src/main/java/com/nextcloud/talk/utils/ApiUtils.kt b/app/src/main/java/com/nextcloud/talk/utils/ApiUtils.kt new file mode 100644 index 000000000..dc496b21d --- /dev/null +++ b/app/src/main/java/com/nextcloud/talk/utils/ApiUtils.kt @@ -0,0 +1,577 @@ +/* + * Nextcloud Talk application + * + * @author Mario Danic + * @author Marcel Hibbe + * @author Tim Krüger + * Copyright (C) 2021 Tim Krüger + * Copyright (C) 2021-2022 Marcel Hibbe + * Copyright (C) 2017-2018 Mario Danic + * + * 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.utils + +import android.net.Uri +import android.text.TextUtils +import android.util.Log +import com.nextcloud.talk.BuildConfig +import com.nextcloud.talk.R +import com.nextcloud.talk.application.NextcloudTalkApplication.Companion.sharedApplication +import com.nextcloud.talk.data.user.model.User +import com.nextcloud.talk.models.RetrofitBucket +import com.nextcloud.talk.models.json.capabilities.SpreedCapability +import com.nextcloud.talk.utils.CapabilitiesUtil.hasSpreedFeatureCapability +import okhttp3.Credentials.basic +import java.nio.charset.StandardCharsets + +@Suppress("TooManyFunctions") +object ApiUtils { + private val TAG = ApiUtils::class.java.simpleName + const val API_V1 = 1 + private const val API_V2 = 2 + const val API_V3 = 3 + const val API_V4 = 4 + private const val AVATAR_SIZE_BIG = 512 + private const val AVATAR_SIZE_SMALL = 64 + private const val OCS_API_VERSION = "/ocs/v2.php" + private const val SPREED_API_VERSION = "/apps/spreed/api/v1" + private const val SPREED_API_BASE = "$OCS_API_VERSION/apps/spreed/api/v" + + @JvmStatic + val userAgent = "Mozilla/5.0 (Android) Nextcloud-Talk v" + get() = field + BuildConfig.VERSION_NAME + + @Deprecated( + "This is only supported on API v1-3, in API v4+ please use " + + "{@link ApiUtils#getUrlForAttendees(int, String, String)} instead." + ) + fun getUrlForRemovingParticipantFromConversation(baseUrl: String?, roomToken: String?, isGuest: Boolean): String { + var url = getUrlForParticipants(API_V1, baseUrl, roomToken) + if (isGuest) { + url += "/guests" + } + return url + } + + private fun getRetrofitBucketForContactsSearch(baseUrl: String, searchQuery: String?): RetrofitBucket { + var query = searchQuery + val retrofitBucket = RetrofitBucket() + retrofitBucket.url = "$baseUrl$OCS_API_VERSION/apps/files_sharing/api/v1/sharees" + val queryMap: MutableMap = HashMap() + if (query == null) { + query = "" + } + queryMap["format"] = "json" + queryMap["search"] = query + queryMap["itemType"] = "call" + retrofitBucket.queryMap = queryMap + return retrofitBucket + } + + fun getUrlForFilePreviewWithRemotePath(baseUrl: String, remotePath: String?, px: Int): String { + return ( + baseUrl + "/index.php/core/preview.png?file=" + + Uri.encode(remotePath, "UTF-8") + + "&x=" + px + "&y=" + px + "&a=1&mode=cover&forceIcon=1" + ) + } + + fun getUrlForFilePreviewWithFileId(baseUrl: String, fileId: String, px: Int): String { + return ( + baseUrl + "/index.php/core/preview?fileId=" + + fileId + "&x=" + px + "&y=" + px + "&a=1&mode=cover&forceIcon=1" + ) + } + + fun getSharingUrl(baseUrl: String): String { + return "$baseUrl$OCS_API_VERSION/apps/files_sharing/api/v1/shares" + } + + fun getRetrofitBucketForContactsSearchFor14(baseUrl: String, searchQuery: String?): RetrofitBucket { + val retrofitBucket = getRetrofitBucketForContactsSearch(baseUrl, searchQuery) + retrofitBucket.url = "$baseUrl$OCS_API_VERSION/core/autocomplete/get" + retrofitBucket.queryMap?.put("itemId", "new") + return retrofitBucket + } + + @JvmStatic + fun getUrlForCapabilities(baseUrl: String): String { + return "$baseUrl$OCS_API_VERSION/cloud/capabilities" + } + + @Throws(NoSupportedApiException::class) + fun getCallApiVersion(capabilities: User, versions: IntArray): Int { + return getConversationApiVersion(capabilities, versions) + } + + @JvmStatic + @Throws(NoSupportedApiException::class) + @Suppress("ReturnCount") + fun getConversationApiVersion(user: User, versions: IntArray): Int { + var hasApiV4 = false + for (version in versions) { + hasApiV4 = hasApiV4 or (version == API_V4) + } + if (!hasApiV4) { + val e = Exception("Api call did not try conversation-v4 api") + Log.d(TAG, e.message, e) + } + for (version in versions) { + if (user.hasSpreedFeatureCapability("conversation-v$version")) { + return version + } + + // Fallback for old API versions + if (version == API_V1 || version == API_V2) { + if (user.hasSpreedFeatureCapability("conversation-v2")) { + return version + } + if (version == API_V1 && + user.hasSpreedFeatureCapability("mention-flag") && + !user.hasSpreedFeatureCapability("conversation-v4") + ) { + return version + } + } + } + throw NoSupportedApiException() + } + + @JvmStatic + @Throws(NoSupportedApiException::class) + @Suppress("ReturnCount") + fun getSignalingApiVersion(user: User, versions: IntArray): Int { + val spreedCapabilities = user.capabilities!!.spreedCapability + for (version in versions) { + if (spreedCapabilities != null) { + if (hasSpreedFeatureCapability(spreedCapabilities, "signaling-v$version")) { + return version + } + if (version == API_V2 && + hasSpreedFeatureCapability(spreedCapabilities, "sip-support") && + !hasSpreedFeatureCapability(spreedCapabilities, "signaling-v3") + ) { + return version + } + if (version == API_V1 && + !hasSpreedFeatureCapability(spreedCapabilities, "signaling-v3") + ) { + // Has no capability, we just assume it is always there when there is no v3 or later + return version + } + } + } + throw NoSupportedApiException() + } + + @JvmStatic + @Throws(NoSupportedApiException::class) + fun getChatApiVersion(spreedCapabilities: SpreedCapability, versions: IntArray): Int { + for (version in versions) { + if (version == API_V1 && hasSpreedFeatureCapability(spreedCapabilities, "chat-v2")) { + // Do not question that chat-v2 capability shows the availability of api/v1/ endpoint *see no evil* + return version + } + } + throw NoSupportedApiException() + } + + private fun getUrlForApi(version: Int, baseUrl: String?): String { + return baseUrl + SPREED_API_BASE + version + } + + fun getUrlForRooms(version: Int, baseUrl: String?): String { + return getUrlForApi(version, baseUrl) + "/room" + } + + @JvmStatic + fun getUrlForRoom(version: Int, baseUrl: String?, token: String?): String { + return getUrlForRooms(version, baseUrl) + "/" + token + } + + fun getUrlForAttendees(version: Int, baseUrl: String?, token: String?): String { + return getUrlForRoom(version, baseUrl, token) + "/attendees" + } + + fun getUrlForParticipants(version: Int, baseUrl: String?, token: String?): String { + if (token.isNullOrEmpty()) { + Log.e(TAG, "token was null or empty") + } + return getUrlForRoom(version, baseUrl, token) + "/participants" + } + + fun getUrlForParticipantsActive(version: Int, baseUrl: String?, token: String?): String { + return getUrlForParticipants(version, baseUrl, token) + "/active" + } + + @JvmStatic + fun getUrlForParticipantsSelf(version: Int, baseUrl: String?, token: String?): String { + return getUrlForParticipants(version, baseUrl, token) + "/self" + } + + fun getUrlForParticipantsResendInvitations(version: Int, baseUrl: String?, token: String?): String { + return getUrlForParticipants(version, baseUrl, token) + "/resend-invitations" + } + + fun getUrlForRoomFavorite(version: Int, baseUrl: String?, token: String?): String { + return getUrlForRoom(version, baseUrl, token) + "/favorite" + } + + fun getUrlForRoomModerators(version: Int, baseUrl: String?, token: String?): String { + return getUrlForRoom(version, baseUrl, token) + "/moderators" + } + + @JvmStatic + fun getUrlForRoomNotificationLevel(version: Int, baseUrl: String?, token: String?): String { + return getUrlForRoom(version, baseUrl, token) + "/notify" + } + + fun getUrlForRoomPublic(version: Int, baseUrl: String?, token: String?): String { + return getUrlForRoom(version, baseUrl, token) + "/public" + } + + fun getUrlForRoomPassword(version: Int, baseUrl: String?, token: String?): String { + return getUrlForRoom(version, baseUrl, token) + "/password" + } + + fun getUrlForRoomReadOnlyState(version: Int, baseUrl: String?, token: String?): String { + return getUrlForRoom(version, baseUrl, token) + "/read-only" + } + + fun getUrlForRoomWebinaryLobby(version: Int, baseUrl: String?, token: String?): String { + return getUrlForRoom(version, baseUrl, token) + "/webinar/lobby" + } + + @JvmStatic + fun getUrlForRoomNotificationCalls(version: Int, baseUrl: String?, token: String?): String { + return getUrlForRoom(version, baseUrl, token) + "/notify-calls" + } + + fun getUrlForCall(version: Int, baseUrl: String?, token: String): String { + return getUrlForApi(version, baseUrl) + "/call/" + token + } + + fun getUrlForChat(version: Int, baseUrl: String?, token: String): String { + return getUrlForApi(version, baseUrl) + "/chat/" + token + } + + @JvmStatic + fun getUrlForMentionSuggestions(version: Int, baseUrl: String?, token: String): String { + return getUrlForChat(version, baseUrl, token) + "/mentions" + } + + fun getUrlForChatMessage(version: Int, baseUrl: String?, token: String, messageId: String): String { + return getUrlForChat(version, baseUrl, token) + "/" + messageId + } + + fun getUrlForChatSharedItems(version: Int, baseUrl: String?, token: String): String { + return getUrlForChat(version, baseUrl, token) + "/share" + } + + fun getUrlForChatSharedItemsOverview(version: Int, baseUrl: String?, token: String): String { + return getUrlForChatSharedItems(version, baseUrl, token) + "/overview" + } + + fun getUrlForSignaling(version: Int, baseUrl: String?): String { + return getUrlForApi(version, baseUrl) + "/signaling" + } + + @JvmStatic + fun getUrlForSignalingBackend(version: Int, baseUrl: String?): String { + return getUrlForSignaling(version, baseUrl) + "/backend" + } + + @JvmStatic + fun getUrlForSignalingSettings(version: Int, baseUrl: String?): String { + return getUrlForSignaling(version, baseUrl) + "/settings" + } + + fun getUrlForSignaling(version: Int, baseUrl: String?, token: String): String { + return getUrlForSignaling(version, baseUrl) + "/" + token + } + + fun getUrlForOpenConversations(version: Int, baseUrl: String?): String { + return getUrlForApi(version, baseUrl) + "/listed-room" + } + + @Suppress("LongParameterList") + fun getRetrofitBucketForCreateRoom( + version: Int, + baseUrl: String?, + roomType: String, + source: String?, + invite: String?, + conversationName: String? + ): RetrofitBucket { + val retrofitBucket = RetrofitBucket() + retrofitBucket.url = getUrlForRooms(version, baseUrl) + val queryMap: MutableMap = HashMap() + queryMap["roomType"] = roomType + if (invite != null) { + queryMap["invite"] = invite + } + if (source != null) { + queryMap["source"] = source + } + if (conversationName != null) { + queryMap["roomName"] = conversationName + } + retrofitBucket.queryMap = queryMap + return retrofitBucket + } + + @JvmStatic + fun getRetrofitBucketForAddParticipant( + version: Int, + baseUrl: String?, + token: String?, + user: String + ): RetrofitBucket { + val retrofitBucket = RetrofitBucket() + retrofitBucket.url = getUrlForParticipants(version, baseUrl, token) + val queryMap: MutableMap = HashMap() + queryMap["newParticipant"] = user + retrofitBucket.queryMap = queryMap + return retrofitBucket + } + + @JvmStatic + fun getRetrofitBucketForAddParticipantWithSource( + version: Int, + baseUrl: String?, + token: String?, + source: String, + id: String + ): RetrofitBucket { + val retrofitBucket = getRetrofitBucketForAddParticipant(version, baseUrl, token, id) + retrofitBucket.queryMap?.put("source", source) + return retrofitBucket + } + + fun getUrlForUserProfile(baseUrl: String): String { + return "$baseUrl$OCS_API_VERSION/cloud/user" + } + + fun getUrlForUserData(baseUrl: String, userId: String): String { + return "$baseUrl$OCS_API_VERSION/cloud/users/$userId" + } + + fun getUrlForUserSettings(baseUrl: String): String { + // FIXME Introduce API version + return "$baseUrl$OCS_API_VERSION$SPREED_API_VERSION/settings/user" + } + + fun getUrlPostfixForStatus(): String { + return "/status.php" + } + + @JvmStatic + fun getUrlForAvatar(baseUrl: String?, name: String?, requestBigSize: Boolean): String { + val avatarSize = if (requestBigSize) AVATAR_SIZE_BIG else AVATAR_SIZE_SMALL + return baseUrl + "/index.php/avatar/" + Uri.encode(name) + "/" + avatarSize + } + + @JvmStatic + fun getUrlForGuestAvatar(baseUrl: String?, name: String?, requestBigSize: Boolean): String { + val avatarSize = if (requestBigSize) AVATAR_SIZE_BIG else AVATAR_SIZE_SMALL + return baseUrl + "/index.php/avatar/guest/" + Uri.encode(name) + "/" + avatarSize + } + + fun getUrlForConversationAvatar(version: Int, baseUrl: String?, token: String?): String { + return getUrlForRoom(version, baseUrl, token) + "/avatar" + } + + fun getUrlForConversationAvatarWithVersion( + version: Int, + baseUrl: String?, + token: String?, + isDark: Boolean, + avatarVersion: String? + ): String { + var isDarkString = "" + if (isDark) { + isDarkString = "/dark" + } + var avatarVersionString = "" + if (avatarVersion != null) { + avatarVersionString = "?avatarVersion=$avatarVersion" + } + return getUrlForRoom(version, baseUrl, token) + "/avatar" + isDarkString + avatarVersionString + } + + @JvmStatic + fun getCredentials(username: String?, token: String?): String? { + return if (TextUtils.isEmpty(username) && TextUtils.isEmpty(token)) { + null + } else { + basic(username!!, token!!, StandardCharsets.UTF_8) + } + } + + @JvmStatic + fun getUrlNextcloudPush(baseUrl: String): String { + return "$baseUrl$OCS_API_VERSION/apps/notifications/api/v2/push" + } + + @JvmStatic + fun getUrlPushProxy(): String { + return sharedApplication!!.applicationContext.resources.getString(R.string.nc_push_server_url) + "/devices" + } + + // see https://github.com/nextcloud/notifications/blob/master/docs/ocs-endpoint-v2.md + fun getUrlForNcNotificationWithId(baseUrl: String, notificationId: String): String { + return "$baseUrl$OCS_API_VERSION/apps/notifications/api/v2/notifications/$notificationId" + } + + fun getUrlForSearchByNumber(baseUrl: String): String { + return "$baseUrl$OCS_API_VERSION/cloud/users/search/by-phone" + } + + fun getUrlForFileUpload(baseUrl: String, user: String, remotePath: String): String { + return "$baseUrl/remote.php/dav/files/$user$remotePath" + } + + fun getUrlForChunkedUpload(baseUrl: String, user: String): String { + return "$baseUrl/remote.php/dav/uploads/$user" + } + + fun getUrlForFileDownload(baseUrl: String, user: String, remotePath: String): String { + return "$baseUrl/remote.php/dav/files/$user/$remotePath" + } + + fun getUrlForTempAvatar(baseUrl: String): String { + return "$baseUrl$OCS_API_VERSION/apps/spreed/temp-user-avatar" + } + + fun getUrlForUserFields(baseUrl: String): String { + return "$baseUrl$OCS_API_VERSION/cloud/user/fields" + } + + fun getUrlToSendLocation(version: Int, baseUrl: String?, roomToken: String): String { + return getUrlForChat(version, baseUrl, roomToken) + "/share" + } + + fun getUrlForHoverCard(baseUrl: String, userId: String): String { + return baseUrl + OCS_API_VERSION + + "/hovercard/v1/" + userId + } + + fun getUrlForChatReadMarker(version: Int, baseUrl: String?, roomToken: String): String { + return getUrlForChat(version, baseUrl, roomToken) + "/read" + } + + /* + * OCS Status API + */ + @JvmStatic + fun getUrlForStatus(baseUrl: String): String { + return "$baseUrl$OCS_API_VERSION/apps/user_status/api/v1/user_status" + } + + fun getUrlForSetStatusType(baseUrl: String): String { + return getUrlForStatus(baseUrl) + "/status" + } + + fun getUrlForPredefinedStatuses(baseUrl: String): String { + return "$baseUrl$OCS_API_VERSION/apps/user_status/api/v1/predefined_statuses" + } + + fun getUrlForStatusMessage(baseUrl: String): String { + return getUrlForStatus(baseUrl) + "/message" + } + + fun getUrlForSetCustomStatus(baseUrl: String): String { + return "$baseUrl$OCS_API_VERSION/apps/user_status/api/v1/user_status/message/custom" + } + + fun getUrlForSetPredefinedStatus(baseUrl: String): String { + return "$baseUrl$OCS_API_VERSION/apps/user_status/api/v1/user_status/message/predefined" + } + + fun getUrlForUserStatuses(baseUrl: String): String { + return "$baseUrl$OCS_API_VERSION/apps/user_status/api/v1/statuses" + } + + fun getUrlForMessageReaction(baseUrl: String, roomToken: String, messageId: String): String { + return "$baseUrl$OCS_API_VERSION$SPREED_API_VERSION/reaction/$roomToken/$messageId" + } + + fun getUrlForUnifiedSearch(baseUrl: String, providerId: String): String { + return "$baseUrl$OCS_API_VERSION/search/providers/$providerId/search" + } + + fun getUrlForPoll(baseUrl: String, roomToken: String, pollId: String): String { + return getUrlForPoll(baseUrl, roomToken) + "/" + pollId + } + + fun getUrlForPoll(baseUrl: String, roomToken: String): String { + return "$baseUrl$OCS_API_VERSION$SPREED_API_VERSION/poll/$roomToken" + } + + @JvmStatic + fun getUrlForMessageExpiration(version: Int, baseUrl: String?, token: String?): String { + return getUrlForRoom(version, baseUrl, token) + "/message-expiration" + } + + fun getUrlForOpenGraph(baseUrl: String): String { + return "$baseUrl$OCS_API_VERSION/references/resolve" + } + + fun getUrlForRecording(version: Int, baseUrl: String?, token: String): String { + return getUrlForApi(version, baseUrl) + "/recording/" + token + } + + fun getUrlForRequestAssistance(version: Int, baseUrl: String?, token: String): String { + return getUrlForApi(version, baseUrl) + "/breakout-rooms/" + token + "/request-assistance" + } + + fun getUrlForConversationDescription(version: Int, baseUrl: String?, token: String?): String { + return getUrlForRoom(version, baseUrl, token) + "/description" + } + + fun getUrlForTranslation(baseUrl: String): String { + return "$baseUrl$OCS_API_VERSION/translation/translate" + } + + fun getUrlForLanguages(baseUrl: String): String { + return "$baseUrl$OCS_API_VERSION/translation/languages" + } + + fun getUrlForReminder(user: User, roomToken: String, messageId: String, version: Int): String { + val url = getUrlForChatMessage(version, user.baseUrl!!, roomToken, messageId) + return "$url/reminder" + } + + fun getUrlForRecordingConsent(version: Int, baseUrl: String?, token: String?): String { + return getUrlForRoom(version, baseUrl, token) + "/recording-consent" + } + + fun getUrlForInvitation(baseUrl: String): String { + return baseUrl + OCS_API_VERSION + SPREED_API_VERSION + "/federation/invitation" + } + + fun getUrlForInvitationAccept(baseUrl: String, id: Int): String { + return getUrlForInvitation(baseUrl) + "/" + id + } + + fun getUrlForInvitationReject(baseUrl: String, id: Int): String { + return getUrlForInvitation(baseUrl) + "/" + id + } + + @JvmStatic + fun getUrlForRoomCapabilities(version: Int, baseUrl: String?, token: String?): String { + return getUrlForRooms(version, baseUrl) + "/" + token + "/capabilities" + } +} diff --git a/app/src/main/java/com/nextcloud/talk/utils/CapabilitiesUtil.kt b/app/src/main/java/com/nextcloud/talk/utils/CapabilitiesUtil.kt new file mode 100644 index 000000000..d58cf1bf5 --- /dev/null +++ b/app/src/main/java/com/nextcloud/talk/utils/CapabilitiesUtil.kt @@ -0,0 +1,275 @@ +/* + * Nextcloud Talk application + * + * @author Andy Scherzinger + * @author Mario Danic + * @author Marcel Hibbe + * Copyright (C) 2023-2024 Marcel Hibbe + * Copyright (C) 2021 Andy Scherzinger (info@andy-scherzinger.de) + * Copyright (C) 2017-2018 Mario Danic + * + * 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.utils + +import com.nextcloud.talk.data.user.model.User +import com.nextcloud.talk.models.json.capabilities.SpreedCapability + +enum class SpreedFeatures(val value: String) { + RECORDING_V1("recording-v1"), + REACTIONS("reactions"), + RAISE_HAND("raise-hand"), + DIRECT_MENTION_FLAG("direct-mention-flag"), + CONVERSATION_CALL_FLAGS("conversation-call-flags"), + SILENT_SEND("silent-send"), + MENTION_FLAG("mention-flag"), + DELETE_MESSAGES("delete-messages"), + READ_ONLY_ROOMS("read-only-rooms"), + RICH_OBJECT_LIST_MEDIA("rich-object-list-media"), + SILENT_CALL("silent-call"), + MESSAGE_EXPIRATION("message-expiration"), + WEBINARY_LOBBY("webinary-lobby"), + VOICE_MESSAGE_SHARING("voice-message-sharing"), + INVITE_GROUPS_AND_MAILS("invite-groups-and-mails"), + CIRCLES_SUPPORT("circles-support"), + LAST_ROOM_ACTIVITY("last-room-activity"), + NOTIFICATION_LEVELS("notification-levels"), + CLEAR_HISTORY("clear-history"), + AVATAR("avatar"), + LISTABLE_ROOMS("listable-rooms"), + LOCKED_ONE_TO_ONE_ROOMS("locked-one-to-one-rooms"), + TEMP_USER_AVATAR_API("temp-user-avatar-api"), + PHONEBOOK_SEARCH("phonebook-search"), + GEO_LOCATION_SHARING("geo-location-sharing"), + TALK_POLLS("talk-polls") +} + +@Suppress("TooManyFunctions") +object CapabilitiesUtil { + + //region Version checks + fun isServerEOL(serverVersion: Int): Boolean { + return (serverVersion < SERVER_VERSION_MIN_SUPPORTED) + } + + fun isServerAlmostEOL(serverVersion: Int): Boolean { + return (serverVersion < SERVER_VERSION_SUPPORT_WARNING) + } + + // endregion + + //region CoreCapabilities + + @JvmStatic + fun isLinkPreviewAvailable(user: User): Boolean { + return user.capabilities?.coreCapability?.referenceApi != null && + user.capabilities?.coreCapability?.referenceApi == "true" + } + + // endregion + + //region SpreedCapabilities + + @JvmStatic + fun hasSpreedFeatureCapability(spreedCapabilities: SpreedCapability, spreedFeatures: SpreedFeatures): Boolean { + if (spreedCapabilities.features != null) { + return spreedCapabilities.features!!.contains(spreedFeatures.value) + } + return false + } + + @JvmStatic + @Deprecated("Add your capability to Capability enums and use hasSpreedFeatureCapability with enum.") + fun hasSpreedFeatureCapability(spreedCapabilities: SpreedCapability, capabilityName: String): Boolean { + if (spreedCapabilities.features != null) { + return spreedCapabilities.features!!.contains(capabilityName) + } + return false + } + + fun getMessageMaxLength(spreedCapabilities: SpreedCapability): Int { + if (spreedCapabilities.config?.containsKey("chat") == true) { + val chatConfigHashMap = spreedCapabilities.config!!["chat"] + if (chatConfigHashMap?.containsKey("max-length") == true) { + val chatSize = (chatConfigHashMap["max-length"]!!.toString()).toInt() + return if (chatSize > 0) { + chatSize + } else { + DEFAULT_CHAT_SIZE + } + } + } + + return DEFAULT_CHAT_SIZE + } + + fun isReadStatusAvailable(spreedCapabilities: SpreedCapability): Boolean { + if (spreedCapabilities.config?.containsKey("chat") == true) { + val map: Map? = spreedCapabilities.config!!["chat"] + return map != null && map.containsKey("read-privacy") + } + return false + } + + @JvmStatic + fun isCallRecordingAvailable(spreedCapabilities: SpreedCapability): Boolean { + if (hasSpreedFeatureCapability(spreedCapabilities, SpreedFeatures.RECORDING_V1) && + spreedCapabilities.config?.containsKey("call") == true + ) { + val map: Map? = spreedCapabilities.config!!["call"] + if (map != null && map.containsKey("recording")) { + return (map["recording"].toString()).toBoolean() + } + } + return false + } + + @JvmStatic + fun getAttachmentFolder(spreedCapabilities: SpreedCapability): String { + if (spreedCapabilities.config?.containsKey("attachments") == true) { + val map = spreedCapabilities.config!!["attachments"] + if (map?.containsKey("folder") == true) { + return map["folder"].toString() + } + } + return "/Talk" + } + + fun isConversationDescriptionEndpointAvailable(spreedCapabilities: SpreedCapability): Boolean { + return hasSpreedFeatureCapability(spreedCapabilities, "room-description") + } + + fun isUnifiedSearchAvailable(spreedCapabilities: SpreedCapability): Boolean { + return hasSpreedFeatureCapability(spreedCapabilities, "unified-search") + } + + fun isAbleToCall(spreedCapabilities: SpreedCapability): Boolean { + return if ( + spreedCapabilities.config?.containsKey("call") == true && + spreedCapabilities.config!!["call"] != null && + spreedCapabilities.config!!["call"]!!.containsKey("enabled") + ) { + java.lang.Boolean.parseBoolean(spreedCapabilities.config!!["call"]!!["enabled"].toString()) + } else { + // older nextcloud versions without the capability can't disable the calls + true + } + } + + fun isCallReactionsSupported(user: User?): Boolean { + if (user?.capabilities != null) { + val capabilities = user.capabilities + return capabilities?.spreedCapability?.config?.containsKey("call") == true && + capabilities.spreedCapability!!.config!!["call"] != null && + capabilities.spreedCapability!!.config!!["call"]!!.containsKey("supported-reactions") + } + return false + } + + fun isTranslationsSupported(spreedCapabilities: SpreedCapability): Boolean { + return spreedCapabilities.config?.containsKey("chat") == true && + spreedCapabilities.config!!["chat"] != null && + spreedCapabilities.config!!["chat"]!!.containsKey("has-translation-providers") && + spreedCapabilities.config!!["chat"]!!["has-translation-providers"] == true + } + + fun getRecordingConsentType(spreedCapabilities: SpreedCapability): Int { + if ( + spreedCapabilities.config?.containsKey("call") == true && + spreedCapabilities.config!!["call"] != null && + spreedCapabilities.config!!["call"]!!.containsKey("recording-consent") + ) { + return when ( + spreedCapabilities.config!!["call"]!!["recording-consent"].toString() + .toInt() + ) { + 1 -> RECORDING_CONSENT_REQUIRED + 2 -> RECORDING_CONSENT_DEPEND_ON_CONVERSATION + else -> RECORDING_CONSENT_NOT_REQUIRED + } + } + return RECORDING_CONSENT_NOT_REQUIRED + } + + // endregion + + //region SpreedCapabilities that can't be used with federation as the settings for them are global + + fun isReadStatusPrivate(user: User): Boolean { + if (user.capabilities?.spreedCapability?.config?.containsKey("chat") == true) { + val map = user.capabilities!!.spreedCapability!!.config!!["chat"] + if (map?.containsKey("read-privacy") == true) { + return (map["read-privacy"]!!.toString()).toInt() == 1 + } + } + return false + } + + fun isTypingStatusAvailable(user: User): Boolean { + if (user.capabilities?.spreedCapability?.config?.containsKey("chat") == true) { + val map = user.capabilities!!.spreedCapability!!.config!!["chat"] + return map != null && map.containsKey("typing-privacy") + } + return false + } + + fun isTypingStatusPrivate(user: User): Boolean { + if (user.capabilities?.spreedCapability?.config?.containsKey("chat") == true) { + val map = user.capabilities!!.spreedCapability!!.config!!["chat"] + if (map?.containsKey("typing-privacy") == true) { + return (map["typing-privacy"]!!.toString()).toInt() == 1 + } + } + return false + } + + // endregion + + //region ThemingCapabilities + + fun getServerName(user: User?): String? { + if (user?.capabilities?.themingCapability != null) { + return user.capabilities!!.themingCapability!!.name + } + return "" + } + + // endregion + + //region ProvisioningCapabilities + + fun canEditScopes(user: User): Boolean { + return user.capabilities?.provisioningCapability?.accountPropertyScopesVersion != null && + user.capabilities!!.provisioningCapability!!.accountPropertyScopesVersion!! > 1 + } + + // endregion + + //region UserStatusCapabilities + + @JvmStatic + fun isUserStatusAvailable(user: User): Boolean { + return user.capabilities?.userStatusCapability?.enabled == true && + user.capabilities?.userStatusCapability?.supportsEmoji == true + } + + // endregion + + const val DEFAULT_CHAT_SIZE = 1000 + const val RECORDING_CONSENT_NOT_REQUIRED = 0 + const val RECORDING_CONSENT_REQUIRED = 1 + const val RECORDING_CONSENT_DEPEND_ON_CONVERSATION = 2 + private const val SERVER_VERSION_MIN_SUPPORTED = 14 + private const val SERVER_VERSION_SUPPORT_WARNING = 18 +} diff --git a/app/src/main/java/com/nextcloud/talk/utils/ConversationUtils.kt b/app/src/main/java/com/nextcloud/talk/utils/ConversationUtils.kt index a4c2414a8..92dea95de 100644 --- a/app/src/main/java/com/nextcloud/talk/utils/ConversationUtils.kt +++ b/app/src/main/java/com/nextcloud/talk/utils/ConversationUtils.kt @@ -1,10 +1,9 @@ package com.nextcloud.talk.utils -import com.nextcloud.talk.data.user.model.User import com.nextcloud.talk.models.domain.ConversationModel import com.nextcloud.talk.models.domain.ConversationType import com.nextcloud.talk.models.domain.ParticipantType -import com.nextcloud.talk.utils.database.user.CapabilitiesUtilNew +import com.nextcloud.talk.models.json.capabilities.SpreedCapability /* * Nextcloud Talk application @@ -45,28 +44,28 @@ object ConversationUtils { ParticipantType.MODERATOR == conversation.participantType } - private fun isLockedOneToOne(conversation: ConversationModel, conversationUser: User): Boolean { + fun isLockedOneToOne(conversation: ConversationModel, spreedCapabilities: SpreedCapability): Boolean { return conversation.type == ConversationType.ROOM_TYPE_ONE_TO_ONE_CALL && - CapabilitiesUtilNew.hasSpreedFeatureCapability(conversationUser, "locked-one-to-one-rooms") + CapabilitiesUtil.hasSpreedFeatureCapability(spreedCapabilities, "locked-one-to-one-rooms") } - fun canModerate(conversation: ConversationModel, conversationUser: User): Boolean { + fun canModerate(conversation: ConversationModel, spreedCapabilities: SpreedCapability): Boolean { return isParticipantOwnerOrModerator(conversation) && - !isLockedOneToOne(conversation, conversationUser) && + !isLockedOneToOne(conversation, spreedCapabilities) && conversation.type != ConversationType.FORMER_ONE_TO_ONE && !isNoteToSelfConversation(conversation) } - fun isLobbyViewApplicable(conversation: ConversationModel, conversationUser: User): Boolean { - return !canModerate(conversation, conversationUser) && + fun isLobbyViewApplicable(conversation: ConversationModel, spreedCapabilities: SpreedCapability): Boolean { + return !canModerate(conversation, spreedCapabilities) && ( conversation.type == ConversationType.ROOM_GROUP_CALL || conversation.type == ConversationType.ROOM_PUBLIC_CALL ) } - fun isNameEditable(conversation: ConversationModel, conversationUser: User): Boolean { - return canModerate(conversation, conversationUser) && + fun isNameEditable(conversation: ConversationModel, spreedCapabilities: SpreedCapability): Boolean { + return canModerate(conversation, spreedCapabilities) && ConversationType.ROOM_TYPE_ONE_TO_ONE_CALL != conversation.type } @@ -79,12 +78,12 @@ object ConversationUtils { } } - fun canDelete(conversation: ConversationModel, conversationUser: User): Boolean { + fun canDelete(conversation: ConversationModel, spreedCapability: SpreedCapability): Boolean { return if (conversation.canDeleteConversation != null) { // Available since APIv2 conversation.canDeleteConversation!! } else { - canModerate(conversation, conversationUser) + canModerate(conversation, spreedCapability) // Fallback for APIv1 } } diff --git a/app/src/main/java/com/nextcloud/talk/utils/FileViewerUtils.kt b/app/src/main/java/com/nextcloud/talk/utils/FileViewerUtils.kt index 92cc4183f..d2aeb4783 100644 --- a/app/src/main/java/com/nextcloud/talk/utils/FileViewerUtils.kt +++ b/app/src/main/java/com/nextcloud/talk/utils/FileViewerUtils.kt @@ -61,7 +61,6 @@ import com.nextcloud.talk.utils.MimetypeUtils.isGif import com.nextcloud.talk.utils.MimetypeUtils.isMarkdown import com.nextcloud.talk.utils.bundle.BundleKeys.KEY_ACCOUNT import com.nextcloud.talk.utils.bundle.BundleKeys.KEY_FILE_ID -import com.nextcloud.talk.utils.database.user.CapabilitiesUtilNew import java.io.File import java.util.concurrent.ExecutionException @@ -308,7 +307,7 @@ class FileViewerUtils(private val context: Context, private val user: User) { .putString(DownloadFileToCacheWorker.KEY_USER_ID, user.userId) .putString( DownloadFileToCacheWorker.KEY_ATTACHMENT_FOLDER, - CapabilitiesUtilNew.getAttachmentFolder(user) + CapabilitiesUtil.getAttachmentFolder(user.capabilities!!.spreedCapability!!) ) .putString(DownloadFileToCacheWorker.KEY_FILE_NAME, fileInfo.fileName) .putString(DownloadFileToCacheWorker.KEY_FILE_PATH, path) diff --git a/app/src/main/java/com/nextcloud/talk/utils/ParticipantPermissions.kt b/app/src/main/java/com/nextcloud/talk/utils/ParticipantPermissions.kt index dddb8753e..829991b5a 100644 --- a/app/src/main/java/com/nextcloud/talk/utils/ParticipantPermissions.kt +++ b/app/src/main/java/com/nextcloud/talk/utils/ParticipantPermissions.kt @@ -22,22 +22,21 @@ package com.nextcloud.talk.utils -import com.nextcloud.talk.data.user.model.User import com.nextcloud.talk.models.domain.ConversationModel +import com.nextcloud.talk.models.json.capabilities.SpreedCapability import com.nextcloud.talk.models.json.conversations.Conversation -import com.nextcloud.talk.utils.database.user.CapabilitiesUtilNew /** * see https://nextcloud-talk.readthedocs.io/en/latest/constants/#attendee-permissions */ class ParticipantPermissions( - private val user: User, + private val spreedCapabilities: SpreedCapability, private val conversation: ConversationModel ) { @Deprecated("Use ChatRepository.ConversationModel") - constructor(user: User, conversation: Conversation) : this( - user, + constructor(spreedCapabilities: SpreedCapability, conversation: Conversation) : this( + spreedCapabilities, ConversationModel.mapToConversationModel(conversation) ) @@ -52,8 +51,8 @@ class ParticipantPermissions( private val hasChatPermission = (conversation.permissions and CHAT) == CHAT private fun hasConversationPermissions(): Boolean { - return CapabilitiesUtilNew.hasSpreedFeatureCapability( - user, + return CapabilitiesUtil.hasSpreedFeatureCapability( + spreedCapabilities, "conversation-permissions" ) } @@ -91,7 +90,7 @@ class ParticipantPermissions( } fun hasChatPermission(): Boolean { - if (CapabilitiesUtilNew.hasSpreedFeatureCapability(user, "chat-permission")) { + if (CapabilitiesUtil.hasSpreedFeatureCapability(spreedCapabilities, "chat-permission")) { return hasChatPermission } // if capability is not available then the spreed version doesn't support to restrict this diff --git a/app/src/main/java/com/nextcloud/talk/utils/PushUtils.kt b/app/src/main/java/com/nextcloud/talk/utils/PushUtils.kt index 0cfac75b7..69c85fef9 100644 --- a/app/src/main/java/com/nextcloud/talk/utils/PushUtils.kt +++ b/app/src/main/java/com/nextcloud/talk/utils/PushUtils.kt @@ -238,7 +238,7 @@ class PushUtils { val credentials = ApiUtils.getCredentials(user.username, user.token) ncApi.registerDeviceForNotificationsWithNextcloud( credentials, - ApiUtils.getUrlNextcloudPush(user.baseUrl), + ApiUtils.getUrlNextcloudPush(user.baseUrl!!), nextcloudRegisterPushMap ) .subscribe(object : Observer { diff --git a/app/src/main/java/com/nextcloud/talk/utils/RemoteFileUtils.kt b/app/src/main/java/com/nextcloud/talk/utils/RemoteFileUtils.kt index 2e3681f88..d54cdcbc5 100644 --- a/app/src/main/java/com/nextcloud/talk/utils/RemoteFileUtils.kt +++ b/app/src/main/java/com/nextcloud/talk/utils/RemoteFileUtils.kt @@ -53,8 +53,8 @@ object RemoteFileUtils { return ncApi.checkIfFileExists( ApiUtils.getCredentials(currentUser.username, currentUser.token), ApiUtils.getUrlForFileUpload( - currentUser.baseUrl, - currentUser.userId, + currentUser.baseUrl!!, + currentUser.userId!!, remotePath ) ) 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 41c644878..2e6e10244 100644 --- a/app/src/main/java/com/nextcloud/talk/utils/ShareUtils.kt +++ b/app/src/main/java/com/nextcloud/talk/utils/ShareUtils.kt @@ -22,10 +22,10 @@ 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.models.domain.ConversationModel object ShareUtils { - fun getStringForIntent(context: Context, user: User, conversation: Conversation?): String { + fun getStringForIntent(context: Context, user: User, conversation: ConversationModel?): String { return String.format( context.resources.getString(R.string.nc_share_text), user.baseUrl, diff --git a/app/src/main/java/com/nextcloud/talk/utils/bundle/BundleKeys.kt b/app/src/main/java/com/nextcloud/talk/utils/bundle/BundleKeys.kt index a8cb1e405..e899a040a 100644 --- a/app/src/main/java/com/nextcloud/talk/utils/bundle/BundleKeys.kt +++ b/app/src/main/java/com/nextcloud/talk/utils/bundle/BundleKeys.kt @@ -89,4 +89,5 @@ object BundleKeys { const val KEY_REAUTHORIZE_ACCOUNT = "KEY_REAUTHORIZE_ACCOUNT" const val KEY_PASSWORD = "KEY_PASSWORD" const val KEY_REMOTE_TALK_SHARE = "KEY_REMOTE_TALK_SHARE" + const val KEY_CHAT_API_VERSION = "KEY_CHAT_API_VERSION" } diff --git a/app/src/main/java/com/nextcloud/talk/utils/database/user/CapabilitiesUtilNew.kt b/app/src/main/java/com/nextcloud/talk/utils/database/user/CapabilitiesUtilNew.kt deleted file mode 100644 index 1969c6912..000000000 --- a/app/src/main/java/com/nextcloud/talk/utils/database/user/CapabilitiesUtilNew.kt +++ /dev/null @@ -1,267 +0,0 @@ -/* - * Nextcloud Talk application - * - * @author Andy Scherzinger - * @author Mario Danic - * Copyright (C) 2021 Andy Scherzinger (info@andy-scherzinger.de) - * Copyright (C) 2017-2018 Mario Danic - * - * 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.utils.database.user - -import com.nextcloud.talk.data.user.model.User -import com.nextcloud.talk.models.json.capabilities.Capabilities - -@Suppress("TooManyFunctions") -object CapabilitiesUtilNew { - fun hasNotificationsCapability(user: User, capabilityName: String): Boolean { - return user.capabilities?.spreedCapability?.features?.contains(capabilityName) == true - } - - fun hasExternalCapability(user: User, capabilityName: String?): Boolean { - if (user.capabilities?.externalCapability?.containsKey("v1") == true) { - return user.capabilities!!.externalCapability!!["v1"]?.contains(capabilityName!!) == true - } - return false - } - - @JvmStatic - fun isServerEOL(capabilities: Capabilities?): Boolean { - // Capability is available since Talk 4 => Nextcloud 14 => Autmn 2018 - return !hasSpreedFeatureCapability(capabilities, "no-ping") - } - - fun isServerAlmostEOL(user: User): Boolean { - // Capability is available since Talk 8 => Nextcloud 18 => January 2020 - return !hasSpreedFeatureCapability(user, "chat-replies") - } - - fun canSetChatReadMarker(user: User): Boolean { - return hasSpreedFeatureCapability(user, "chat-read-marker") - } - - fun canMarkRoomAsUnread(user: User): Boolean { - return hasSpreedFeatureCapability(user, "chat-unread") - } - - @JvmStatic - fun hasSpreedFeatureCapability(user: User?, capabilityName: String): Boolean { - return hasSpreedFeatureCapability(user?.capabilities, capabilityName) - } - - @JvmStatic - fun hasSpreedFeatureCapability(capabilities: Capabilities?, capabilityName: String): Boolean { - if (capabilities?.spreedCapability?.features != null) { - return capabilities.spreedCapability!!.features!!.contains(capabilityName) - } - return false - } - - fun getMessageMaxLength(user: User?): Int { - if (user?.capabilities?.spreedCapability?.config?.containsKey("chat") == true) { - val chatConfigHashMap = user.capabilities!!.spreedCapability!!.config!!["chat"] - if (chatConfigHashMap?.containsKey("max-length") == true) { - val chatSize = (chatConfigHashMap["max-length"]!!.toString()).toInt() - return if (chatSize > 0) { - chatSize - } else { - DEFAULT_CHAT_SIZE - } - } - } - - return DEFAULT_CHAT_SIZE - } - - fun isPhoneBookIntegrationAvailable(user: User): Boolean { - return user.capabilities?.spreedCapability?.features?.contains("phonebook-search") == true - } - - fun isReadStatusAvailable(user: User): Boolean { - if (user.capabilities?.spreedCapability?.config?.containsKey("chat") == true) { - val map: Map? = user.capabilities!!.spreedCapability!!.config!!["chat"] - return map != null && map.containsKey("read-privacy") - } - return false - } - - fun isReadStatusPrivate(user: User): Boolean { - if (user.capabilities?.spreedCapability?.config?.containsKey("chat") == true) { - val map = user.capabilities!!.spreedCapability!!.config!!["chat"] - if (map?.containsKey("read-privacy") == true) { - return (map["read-privacy"]!!.toString()).toInt() == 1 - } - } - return false - } - - fun isTypingStatusAvailable(user: User): Boolean { - if (user.capabilities?.spreedCapability?.config?.containsKey("chat") == true) { - val map = user.capabilities!!.spreedCapability!!.config!!["chat"] - return map != null && map.containsKey("typing-privacy") - } - return false - } - - fun isTypingStatusPrivate(user: User): Boolean { - if (user.capabilities?.spreedCapability?.config?.containsKey("chat") == true) { - val map = user.capabilities!!.spreedCapability!!.config!!["chat"] - if (map?.containsKey("typing-privacy") == true) { - return (map["typing-privacy"]!!.toString()).toInt() == 1 - } - } - return false - } - - @JvmStatic - fun isCallRecordingAvailable(user: User): Boolean { - if (hasSpreedFeatureCapability(user, "recording-v1") && - user.capabilities?.spreedCapability?.config?.containsKey("call") == true - ) { - val map: Map? = user.capabilities!!.spreedCapability!!.config!!["call"] - if (map != null && map.containsKey("recording")) { - return (map["recording"].toString()).toBoolean() - } - } - return false - } - - @JvmStatic - fun isUserStatusAvailable(user: User): Boolean { - return user.capabilities?.userStatusCapability?.enabled == true && - user.capabilities?.userStatusCapability?.supportsEmoji == true - } - - @JvmStatic - fun getAttachmentFolder(user: User): String { - if (user.capabilities?.spreedCapability?.config?.containsKey("attachments") == true) { - val map = user.capabilities!!.spreedCapability!!.config!!["attachments"] - if (map?.containsKey("folder") == true) { - return map["folder"].toString() - } - } - return "/Talk" - } - - fun getServerName(user: User?): String? { - if (user?.capabilities?.themingCapability != null) { - return user.capabilities!!.themingCapability!!.name - } - return "" - } - - // TODO later avatar can also be checked via user fields, for now it is in Talk capability - fun isAvatarEndpointAvailable(user: User): Boolean { - return user.capabilities?.spreedCapability?.features?.contains("temp-user-avatar-api") == true - } - - fun isConversationAvatarEndpointAvailable(user: User): Boolean { - return user.capabilities?.spreedCapability?.features?.contains("avatar") == true - } - - fun isConversationDescriptionEndpointAvailable(user: User): Boolean { - return user.capabilities?.spreedCapability?.features?.contains("room-description") == true - } - - fun canEditScopes(user: User): Boolean { - return user.capabilities?.provisioningCapability?.accountPropertyScopesVersion != null && - user.capabilities!!.provisioningCapability!!.accountPropertyScopesVersion!! > 1 - } - - fun isAbleToCall(user: User?): Boolean { - if (user?.capabilities != null) { - val capabilities = user.capabilities - return if ( - capabilities?.spreedCapability?.config?.containsKey("call") == true && - capabilities.spreedCapability!!.config!!["call"] != null && - capabilities.spreedCapability!!.config!!["call"]!!.containsKey("enabled") - ) { - java.lang.Boolean.parseBoolean(capabilities.spreedCapability!!.config!!["call"]!!["enabled"].toString()) - } else { - // older nextcloud versions without the capability can't disable the calls - true - } - } - return false - } - - fun isCallReactionsSupported(user: User?): Boolean { - if (user?.capabilities != null) { - val capabilities = user.capabilities - return capabilities?.spreedCapability?.config?.containsKey("call") == true && - capabilities.spreedCapability!!.config!!["call"] != null && - capabilities.spreedCapability!!.config!!["call"]!!.containsKey("supported-reactions") - } - return false - } - - @JvmStatic - fun isUnifiedSearchAvailable(user: User): Boolean { - return hasSpreedFeatureCapability(user, "unified-search") - } - - @JvmStatic - fun isLinkPreviewAvailable(user: User): Boolean { - return user.capabilities?.coreCapability?.referenceApi != null && - user.capabilities?.coreCapability?.referenceApi == "true" - } - - fun isTranslationsSupported(user: User?): Boolean { - if (user?.capabilities != null) { - val capabilities = user.capabilities - return capabilities?.spreedCapability?.config?.containsKey("chat") == true && - capabilities.spreedCapability!!.config!!["chat"] != null && - capabilities.spreedCapability!!.config!!["chat"]!!.containsKey("has-translation-providers") && - capabilities.spreedCapability!!.config!!["chat"]!!["has-translation-providers"] == true - } - - return false - } - - fun isRemindSupported(user: User?): Boolean { - if (user?.capabilities != null) { - val capabilities = user.capabilities - return capabilities?.spreedCapability?.features?.contains("remind-me-later") == true - } - - return false - } - - fun getRecordingConsentType(user: User?): Int { - if (user?.capabilities != null) { - val capabilities = user.capabilities - if ( - capabilities?.spreedCapability?.config?.containsKey("call") == true && - capabilities.spreedCapability!!.config!!["call"] != null && - capabilities.spreedCapability!!.config!!["call"]!!.containsKey("recording-consent") - ) { - return when ( - capabilities.spreedCapability!!.config!!["call"]!!["recording-consent"].toString() - .toInt() - ) { - 1 -> RECORDING_CONSENT_REQUIRED - 2 -> RECORDING_CONSENT_DEPEND_ON_CONVERSATION - else -> RECORDING_CONSENT_NOT_REQUIRED - } - } - } - return RECORDING_CONSENT_NOT_REQUIRED - } - - const val DEFAULT_CHAT_SIZE = 1000 - const val RECORDING_CONSENT_NOT_REQUIRED = 0 - const val RECORDING_CONSENT_REQUIRED = 1 - const val RECORDING_CONSENT_DEPEND_ON_CONVERSATION = 2 -} diff --git a/app/src/main/java/com/nextcloud/talk/utils/preferences/preferencestorage/DatabaseStorageModule.java b/app/src/main/java/com/nextcloud/talk/utils/preferences/preferencestorage/DatabaseStorageModule.java index cc4365c55..8652a99be 100644 --- a/app/src/main/java/com/nextcloud/talk/utils/preferences/preferencestorage/DatabaseStorageModule.java +++ b/app/src/main/java/com/nextcloud/talk/utils/preferences/preferencestorage/DatabaseStorageModule.java @@ -35,7 +35,7 @@ import com.nextcloud.talk.data.user.model.User; import com.nextcloud.talk.models.json.generic.GenericOverall; import com.nextcloud.talk.utils.ApiUtils; import com.nextcloud.talk.utils.UserIdUtils; -import com.nextcloud.talk.utils.database.user.CapabilitiesUtilNew; +import com.nextcloud.talk.utils.CapabilitiesUtil; import javax.inject.Inject; @@ -158,7 +158,8 @@ public class DatabaseStorageModule { }); } else if ("conversation_info_message_notifications_dropdown".equals(key)) { - if (CapabilitiesUtilNew.hasSpreedFeatureCapability(conversationUser, "notification-levels")) { + if (CapabilitiesUtil.hasSpreedFeatureCapability(conversationUser.getCapabilities().getSpreedCapability(), "notification" + + "-levels")) { if (TextUtils.isEmpty(messageNotificationLevel) || !messageNotificationLevel.equals(value)) { int intValue; switch (value) { @@ -175,7 +176,7 @@ public class DatabaseStorageModule { intValue = 0; } - int apiVersion = ApiUtils.getConversationApiVersion(conversationUser, new int[]{ApiUtils.APIv4, 1}); + int apiVersion = ApiUtils.getConversationApiVersion(conversationUser, new int[]{ApiUtils.API_V4, 1}); ncApi.setNotificationLevel(ApiUtils.getCredentials(conversationUser.getUsername(), conversationUser.getToken()), diff --git a/app/src/main/java/com/nextcloud/talk/viewmodels/GeoCodingViewModel.kt b/app/src/main/java/com/nextcloud/talk/viewmodels/GeoCodingViewModel.kt index d66d9059c..bc08d85d6 100644 --- a/app/src/main/java/com/nextcloud/talk/viewmodels/GeoCodingViewModel.kt +++ b/app/src/main/java/com/nextcloud/talk/viewmodels/GeoCodingViewModel.kt @@ -25,7 +25,6 @@ import androidx.lifecycle.LiveData import androidx.lifecycle.MutableLiveData import androidx.lifecycle.ViewModel import com.nextcloud.talk.activities.CallActivity.Companion.TAG -import com.nextcloud.talk.location.GeocodingActivity import fr.dudie.nominatim.client.TalkJsonNominatimClient import fr.dudie.nominatim.model.Address import kotlinx.coroutines.CoroutineScope @@ -70,9 +69,9 @@ class GeoCodingViewModel : ViewModel() { try { val results = nominatimClient.search(query) as ArrayList
for (address in results) { - Log.d(GeocodingActivity.TAG, address.displayName) - Log.d(GeocodingActivity.TAG, address.latitude.toString()) - Log.d(GeocodingActivity.TAG, address.longitude.toString()) + Log.d(TAG, address.displayName) + Log.d(TAG, address.latitude.toString()) + Log.d(TAG, address.longitude.toString()) } geocodingResults = results geocodingResultsLiveData.postValue(results) diff --git a/app/src/main/java/com/nextcloud/talk/webrtc/WebSocketConnectionHelper.java b/app/src/main/java/com/nextcloud/talk/webrtc/WebSocketConnectionHelper.java index 96b0a6fdb..adec118c3 100644 --- a/app/src/main/java/com/nextcloud/talk/webrtc/WebSocketConnectionHelper.java +++ b/app/src/main/java/com/nextcloud/talk/webrtc/WebSocketConnectionHelper.java @@ -113,7 +113,7 @@ public class WebSocketConnectionHelper { } HelloOverallWebSocketMessage getAssembledHelloModel(User user, String ticket) { - int apiVersion = ApiUtils.getSignalingApiVersion(user, new int[]{ApiUtils.APIv3, 2, 1}); + int apiVersion = ApiUtils.getSignalingApiVersion(user, new int[]{ApiUtils.API_V3, 2, 1}); HelloOverallWebSocketMessage helloOverallWebSocketMessage = new HelloOverallWebSocketMessage(); helloOverallWebSocketMessage.setType("hello"); diff --git a/app/src/test/java/com/nextcloud/talk/utils/ParticipantPermissionsTest.kt b/app/src/test/java/com/nextcloud/talk/utils/ParticipantPermissionsTest.kt index be1ed2cae..17c8dedf3 100644 --- a/app/src/test/java/com/nextcloud/talk/utils/ParticipantPermissionsTest.kt +++ b/app/src/test/java/com/nextcloud/talk/utils/ParticipantPermissionsTest.kt @@ -22,7 +22,7 @@ package com.nextcloud.talk.utils -import com.nextcloud.talk.data.user.model.User +import com.nextcloud.talk.models.json.capabilities.SpreedCapability import com.nextcloud.talk.models.json.conversations.Conversation import junit.framework.TestCase import org.junit.Test @@ -31,7 +31,7 @@ class ParticipantPermissionsTest : TestCase() { @Test fun test_areFlagsSet() { - val user = User() + val spreedCapability = SpreedCapability() val conversation = Conversation() conversation.permissions = ParticipantPermissions.PUBLISH_SCREEN or ParticipantPermissions.JOIN_CALL or @@ -39,7 +39,7 @@ class ParticipantPermissionsTest : TestCase() { val attendeePermissions = ParticipantPermissions( - user, + spreedCapability, conversation ) 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 427890305..27084164b 100644 --- a/app/src/test/java/com/nextcloud/talk/utils/ShareUtilsTest.kt +++ b/app/src/test/java/com/nextcloud/talk/utils/ShareUtilsTest.kt @@ -23,7 +23,7 @@ import android.content.Context import android.content.res.Resources 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.models.domain.ConversationModel import com.nextcloud.talk.users.UserManager import io.reactivex.Maybe import org.junit.Assert @@ -49,19 +49,19 @@ class ShareUtilsTest { private val baseUrl = "https://my.nextcloud.com" private val token = "2aotbrjr" - private lateinit var conversation: Conversation + private lateinit var conversation: ConversationModel @Before fun setUp() { MockitoAnnotations.openMocks(this) Mockito.`when`(userManager!!.currentUser).thenReturn(Maybe.just(user)) - Mockito.`when`(user!!.baseUrl).thenReturn(baseUrl) + Mockito.`when`(user!!.baseUrl!!).thenReturn(baseUrl) Mockito.`when`(context!!.resources).thenReturn(resources) Mockito.`when`(resources!!.getString(R.string.nc_share_text)) .thenReturn("Join the conversation at %1\$s/index.php/call/%2\$s") Mockito.`when`(resources.getString(R.string.nc_share_text_pass)).thenReturn("\nPassword: %1\$s") - conversation = Conversation(token = token) + conversation = ConversationModel(token = token) } @Test diff --git a/detekt.yml b/detekt.yml index 089cbd7f6..d38d10547 100644 --- a/detekt.yml +++ b/detekt.yml @@ -1,5 +1,5 @@ build: - maxIssues: 116 + maxIssues: 122 weights: # complexity: 2 # LongParameterList: 1 diff --git a/gradle/verification-keyring.keys b/gradle/verification-keyring.keys index ec2a8f58b..2904e0911 100644 --- a/gradle/verification-keyring.keys +++ b/gradle/verification-keyring.keys @@ -1313,8 +1313,6 @@ lQyC8nl8P5PgkEZ5CHcGymZlpzihR3ECrPJTk39Sb7D3SxCW4WrChV3kVfmLgvc= -----END PGP PUBLIC KEY BLOCK----- pub C21CE653B639E41A -uid Eric Kuck - sub 4F80368F9034B8D0 -----BEGIN PGP PUBLIC KEY BLOCK----- Version: BCPG v1.68 @@ -1324,21 +1322,20 @@ aBF7dud1bzw7voZo5ieGK923wUB+R9vQYd5DYfNLBHj9/TrTVCfKfUIeeEQRZYBz ufYcDwi4uVx9VPj2wRhkK+lzxphvosJCNFK8Vn82oY7eHQ1RA4AEhCeE/hz8maq6 NPoOPjpEN0DVnPIYdjPsdqd4UKQzkX/wMOxghz8SdcVROzUoL+9pZzx968OFuGrV lUD0su37S6To1IUn6WNEuy1uJTzT3Zqi0hfm31AqPxlLWDOwnuKvUJl3RObyli2k -CBtDa5xPE6GU6ZUEFUZ7qbk7iV5p8uTchKVbABEBAAG0IUVyaWMgS3VjayA8ZXJp -Y0BibHVlbGluZWxhYnMuY29tPrkBDQRU5ChoAQgAxC44rEZjgnJevvrzdL5vCVqC -1WI9cZ7L8DwF/pvm7NbRKC5GgXigul18UET80q4E3WIi0tTMG+pVWO+1v0dEu/Re -B/l+hc76iwJjOlwSiQ1jvq6/q0Nhne0/0khSYNWyd0AwJ2VZktcD93dJV4EqTm1O -Ck1gigAd/GN5wslQkMST/nUYUGm4cA/RZVSA8PSFZDZ2CxHyRyHgaOQNBUmWG2gf -ExUrrJA26iKowkNqZXWegnzYwlf8ZRE6MZM0JPLOUw/+r4ybI8ny+/U55s2sm0XZ -CcJvNda5N3SoaC/OgGWZFx1s9UksN7MmvhznaSUMeaeVFbGC3nu9dsQhV9RxMwAR -AQABiQEfBBgBAgAJBQJU5ChoAhsMAAoJEMIc5lO2OeQadSwH/07x1foZKkFRGMlj -wCmofKGSqZ9fu6ueOIV6fwHjrhlfkSyKN+96xbjhwIvWhKdSmWP/AsUqRDD/mTHw -ZMdlgmdXkGEvvCuJDL5FlQzl9OWeeplfVhLysx6dzj/G8AUXlfEIGBvb8Q56d5dK -MpId4H4vt+YIzS8x/ry+QTTDJAOu1cVJfwoX34yMcZ+IHTzly2XKi4zQ41DyfrgY -lCodWna10RtBdPZY41Jf4xSezX2q7KZBXXRgyVNYu3dDuNzhJAJ6jy7eMcb6urK6 -n73cz5uZPmWIbp4cAecZB0BfMj/PW37dK0oYdWKLxaDwpxvIV7T45Y64Md2FCC+d -nC2Xh7c= -=kzY9 +CBtDa5xPE6GU6ZUEFUZ7qbk7iV5p8uTchKVbABEBAAG5AQ0EVOQoaAEIAMQuOKxG +Y4JyXr7683S+bwlagtViPXGey/A8Bf6b5uzW0SguRoF4oLpdfFBE/NKuBN1iItLU +zBvqVVjvtb9HRLv0Xgf5foXO+osCYzpcEokNY76uv6tDYZ3tP9JIUmDVsndAMCdl +WZLXA/d3SVeBKk5tTgpNYIoAHfxjecLJUJDEk/51GFBpuHAP0WVUgPD0hWQ2dgsR +8kch4GjkDQVJlhtoHxMVK6yQNuoiqMJDamV1noJ82MJX/GUROjGTNCTyzlMP/q+M +myPJ8vv1OebNrJtF2QnCbzXWuTd0qGgvzoBlmRcdbPVJLDezJr4c52klDHmnlRWx +gt57vXbEIVfUcTMAEQEAAYkBHwQYAQIACQUCVOQoaAIbDAAKCRDCHOZTtjnkGnUs +B/9O8dX6GSpBURjJY8ApqHyhkqmfX7urnjiFen8B464ZX5EsijfvesW44cCL1oSn +Uplj/wLFKkQw/5kx8GTHZYJnV5BhL7wriQy+RZUM5fTlnnqZX1YS8rMenc4/xvAF +F5XxCBgb2/EOeneXSjKSHeB+L7fmCM0vMf68vkE0wyQDrtXFSX8KF9+MjHGfiB08 +5ctlyouM0ONQ8n64GJQqHVp2tdEbQXT2WONSX+MUns19quymQV10YMlTWLt3Q7jc +4SQCeo8u3jHG+rqyup+93M+bmT5liG6eHAHnGQdAXzI/z1t+3StKGHVii8Wg8Kcb +yFe0+OWOuDHdhQgvnZwtl4e3 +=DwNF -----END PGP PUBLIC KEY BLOCK----- pub C488A74FCAE540C6 @@ -1674,43 +1671,6 @@ fW1AkBVEk6siyL8PXfxmj9ev3H9xiQVLyJ6HpdHTLVjHjFkgNOLd =R7zg -----END PGP PUBLIC KEY BLOCK----- -pub D041CAD2E452550F -uid Deanna - -sub 5199F3DAE89C332D ------BEGIN PGP PUBLIC KEY BLOCK----- -Version: BCPG v1.68 - -mQGNBGCtdhoBDADdopjDt4eUNEqLJSw1ZICSR0oq09SOVtJSaSYdF8UiXjBfL1Ds -fhTDqSv5pT2a2gLj0OU3tFhWHvINLaKKCjQnHVcFXi2LTxt+XBOjRYkFjHVisbaZ -PZ6HnTMStPrvs+hQ168vU3VfYOsOLN22j53I/Ba+FA7E0G0bqkratuT5L7BTR1mC -fqDaeisWSCllfe6EEysaFF+/1RcRy+Yt+8ZWV0FZEF7UwQvqKHcYmlkqPIn3v/8y -J/yvmzIEtCQ1F+bvJbzaROmeJf254G2Uh7IfMYEm9WlqnGwNdbIhil7bdxq8Y/0H -XbQPaESxkki7yL5JTfH/+UzdklMe+Dga273L/cgzfjV3zJJ9vR94W5ABAbGYh4ZW -aKvNnT1m4vTbEMfo4r3NF2zc+K9Ly/JNaHqkR5M4SVElvN2lsC5KNUiRvExhg+h0 -mKyx61mu3gUIrC1UOmqhtx7RzQQf7ESMdzmNHY0P93lR0Ic10fyli0wfl7A6q7+q -zV2a1V2k9Yg6B9sAEQEAAbQgRGVhbm5hIDxkZWFubmFnYXJjaWFAZ29vZ2xlLmNv -bT65AY0EYK12GgEMAMgP3//QeBsTS3IrfSp3m44el96X6BWona2yo4DvVyuwqfUL -ZE+Nhj7I+kEZLrA29AOySOD/6quJ4MIJZfq/Do920Di8/10WQ00OdCM1wH7bMz2U -vcSqsr0iOgQtycuUf7JOHSTME9vqk+C3Lhn0r59AVaRdXEe6zBgNZyzZJeCr5F8w -RhglPlwvhOGs2aLEqlCxFnY4pLayQFoQyw1lDjHIXHg5JtfOHvqiNXVDcGpyKLG8 -SzImp62iL4sfuA0weVIQeS9kZiQabSYKvSf3TvNXYTgmFz/vjPbYhv9LTkBroTlV -g3l+UmAxLrHVuXMx0zX3jfNNHAqUjVhPYZhnifMkmGJgLeMIVqr5Q/tx8pzyYiiO -cqQ1zDg8ubJDGRue1JjlUGdw19OvhFDs+lydukt8Mmhb0gPkBLi2syZHgYHtEooX -PLwEsJ+SynZCFhZiWj8BsWNFJpaDd8ynNeWhMAcwi3B5ZeQiZaAlV0sItxsrzvbu -4ZYZtkjAkQdsaaTWSwARAQABiQG8BBgBCgAmFiEEaWthmaKp2MKc54zA0EHK0uRS -VQ8FAmCtdhoCGwwFCQPCZwAACgkQ0EHK0uRSVQ+G7wwAvaVPDgnM+i2pGQPwq6Mk -SzhKEG4H1pvBWyYR8H9D3p/dE33IjVu3EEy1h37Nzdyp46KtASGNe3KBodSsh6gv -PlV5pNGxMNbX6fo8ZGtS83C+6uTF1cYmuO1nmi8P4+7qtcNZg4xv/ujAZIC20kem -YKDth3FvPxEXsoxY+Ns7sxgd3SqoyLhjcyoczI8uyhim5nfvvbnEd6WrdiBPBtb/ -F1h/nfqdFj2TcZkAlnzGnlVlgU8J60u6zE+9VvBm0lJR73Ar55mQEwarGFPL1a3/ -A7ZEeNa0Dc3Oa5sKMYtxMlGKZ0WGUoGcDWiaDEsv5YyRnaSOaXKM1NkJCR013QAr -RcHrRBPo+0/RIZVE+b8oEcmGzdL8HNwnm7e06ruZryF9LQA5YBmCKE0urigmgEvC -zZsj/fMJ+OIZcAhE7UVae48GpW2kLATxmK01oSzvizIlmN3rVz2EnjOun2iuuEpF -/lmDbjK5n1r3f8npB1l1fT5cozzQJkPVYzhBWH1KXP5X -=nh9O ------END PGP PUBLIC KEY BLOCK----- - pub D364ABAA39A47320 sub 3F606403DCA455C8 -----BEGIN PGP PUBLIC KEY BLOCK----- diff --git a/gradle/verification-metadata.xml b/gradle/verification-metadata.xml index 09f34c0ed..48d04192f 100644 --- a/gradle/verification-metadata.xml +++ b/gradle/verification-metadata.xml @@ -7,6 +7,9 @@ + + + @@ -2854,16 +2857,42 @@ + + + + + + + + + + + + + + + + + + + + + + + + + +