Clean up & version updates

Signed-off-by: Mario Danic <mario@lovelyhq.com>
This commit is contained in:
Mario Danic 2020-01-29 23:36:43 +01:00
parent 9fb9f38974
commit 3f24da27ec
No known key found for this signature in database
GPG Key ID: CDE0BBD2738C4CC0
3 changed files with 15 additions and 973 deletions

View File

@ -154,9 +154,9 @@ android {
}
ext {
work_version = '2.3.0-rc01'
work_version = '2.3.0'
koin_version = "2.1.0-alpha-1"
lifecycle_version = '2.2.0-rc03'
lifecycle_version = '2.2.0'
coil_version = "0.9.1"
room_version = "2.2.3"
}
@ -227,19 +227,19 @@ dependencies {
implementation 'androidx.appcompat:appcompat:1.1.0'
implementation 'androidx.core:core-ktx:1.2.0-rc01'
implementation 'androidx.sharetarget:sharetarget:1.0.0-rc01'
implementation 'com.google.android.material:material:1.2.0-alpha03'
implementation 'com.google.android.material:material:1.2.0-alpha04'
implementation 'androidx.constraintlayout:constraintlayout:2.0.0-beta4'
implementation 'com.github.vanniktech:Emoji:0.6.0'
implementation group: 'androidx.emoji', name: 'emoji-bundled', version: '1.0.0'
implementation 'org.michaelevans.colorart:library:0.0.3'
implementation 'com.google.android:flexbox:1.1.0'
implementation 'com.gitlab.bitfireAT:dav4jvm:ee66e8e5'
implementation 'com.google.android:flexbox:2.0.0'
implementation 'com.gitlab.bitfireAT:dav4jvm:1.0'
implementation 'org.conscrypt:conscrypt-android:2.2.1'
implementation 'androidx.lifecycle:lifecycle-extensions:2.1.0'
implementation 'androidx.lifecycle:lifecycle-extensions:2.2.0'
implementation 'androidx.biometric:biometric:1.0.1'
implementation "androidx.lifecycle:lifecycle-extensions:2.1.0"
implementation "androidx.lifecycle:lifecycle-extensions:2.2.0"
implementation 'androidx.multidex:multidex:2.0.1'
@ -253,9 +253,9 @@ dependencies {
implementation 'com.bluelinelabs:conductor-autodispose:3.0.0-rc2'
implementation "com.github.miquelbeltran:conductor-viewmodel:1.0.3"
implementation 'com.squareup.okhttp3:okhttp:3.14.3'
implementation 'com.squareup.okhttp3:okhttp-urlconnection:3.14.3'
implementation 'com.squareup.okhttp3:logging-interceptor:3.14.3'
implementation 'com.squareup.okhttp3:okhttp:3.14.4'
implementation 'com.squareup.okhttp3:okhttp-urlconnection:3.14.4'
implementation 'com.squareup.okhttp3:logging-interceptor:3.14.4'
implementation 'com.squareup.retrofit2:retrofit:2.7.1'
implementation 'com.squareup.retrofit2:adapter-rxjava2:2.7.1'
@ -299,7 +299,7 @@ dependencies {
implementation 'com.github.natario1:Autocomplete:v1.1.0'
implementation 'com.github.cotechde.hwsecurity:hwsecurity-fido:2.4.5'
implementation 'com.github.cotechde.hwsecurity:hwsecurity-fido:2.5.1'
implementation 'com.novoda:merlin:1.2.1'
@ -316,10 +316,10 @@ dependencies {
kapt 'org.parceler:parceler:1.1.12'
testImplementation 'junit:junit:4.13'
testImplementation 'org.mockito:mockito-core:3.0.0'
testImplementation 'org.powermock:powermock-core:2.0.2'
testImplementation 'org.powermock:powermock-module-junit4:2.0.2'
testImplementation 'org.powermock:powermock-api-mockito2:2.0.2'
testImplementation 'org.mockito:mockito-core:3.2.4'
testImplementation 'org.powermock:powermock-core:2.0.4'
testImplementation 'org.powermock:powermock-module-junit4:2.0.4'
testImplementation 'org.powermock:powermock-api-mockito2:2.0.4'
androidTestImplementation('androidx.test.espresso:espresso-core:3.3.0-alpha03', {
exclude group: 'com.android.support', module: 'support-annotations'

View File

@ -1,293 +0,0 @@
/*
* Nextcloud Talk application
*
* @author Mario Danic
* Copyright (C) 2017 Mario Danic <mario@lovelyhq.com>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package com.nextcloud.talk.controllers.bottomsheet
import android.content.ComponentName
import android.content.Intent
import android.graphics.PorterDuff
import android.os.Bundle
import android.text.Editable
import android.text.InputType
import android.text.TextUtils
import android.text.TextWatcher
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.view.inputmethod.EditorInfo
import android.widget.Button
import android.widget.ImageView
import butterknife.BindView
import butterknife.OnClick
import com.bluelinelabs.conductor.RouterTransaction
import com.bluelinelabs.conductor.changehandler.HorizontalChangeHandler
import com.google.android.material.textfield.TextInputLayout
import com.nextcloud.talk.R
import com.nextcloud.talk.controllers.base.BaseController
import com.nextcloud.talk.events.BottomSheetLockEvent
import com.nextcloud.talk.models.json.conversations.Conversation
import com.nextcloud.talk.utils.EmojiTextInputEditText
import com.nextcloud.talk.utils.ShareUtils
import com.nextcloud.talk.utils.bundle.BundleKeys
import com.nextcloud.talk.utils.singletons.ApplicationWideMessageHolder
import com.vanniktech.emoji.EmojiPopup
import org.parceler.Parcels
class EntryMenuController(private val originalBundle: Bundle) : BaseController() {
@JvmField
@BindView(R.id.ok_button)
internal var proceedButton: Button? = null
@JvmField
@BindView(R.id.text_edit)
internal var editText: EmojiTextInputEditText? = null
@JvmField
@BindView(R.id.text_input_layout)
internal var textInputLayout: TextInputLayout? = null
@JvmField
@BindView(R.id.smileyButton)
internal var smileyButton: ImageView? = null
private val operationCode: Int
private var conversation: Conversation? = null
private var shareIntent: Intent? = null
private val packageName: String
private val name: String
private val callUrl: String
private var emojiPopup: EmojiPopup? = null
init {
this.operationCode = originalBundle.getInt(BundleKeys.KEY_OPERATION_CODE)
if (originalBundle.containsKey(BundleKeys.KEY_ROOM)) {
this.conversation = Parcels.unwrap(originalBundle.getParcelable(BundleKeys.KEY_ROOM))
}
if (originalBundle.containsKey(BundleKeys.KEY_SHARE_INTENT)) {
this.shareIntent = Parcels.unwrap(originalBundle.getParcelable(BundleKeys.KEY_SHARE_INTENT))
}
this.name = originalBundle.getString(BundleKeys.KEY_APP_ITEM_NAME, "")
this.packageName = originalBundle.getString(BundleKeys.KEY_APP_ITEM_PACKAGE_NAME, "")
this.callUrl = originalBundle.getString(BundleKeys.KEY_CALL_URL, "")
}
override fun inflateView(inflater: LayoutInflater, container: ViewGroup): View {
return inflater.inflate(R.layout.controller_entry_menu, container, false)
}
@OnClick(R.id.smileyButton)
internal fun onSmileyClick() {
emojiPopup!!.toggle()
}
override fun onAttach(view: View) {
super.onAttach(view)
if (ApplicationWideMessageHolder.getInstance().messageType != null && ApplicationWideMessageHolder.getInstance()
.messageType == ApplicationWideMessageHolder.MessageType.CALL_PASSWORD_WRONG) {
textInputLayout!!.error = resources!!.getString(R.string.nc_wrong_password)
ApplicationWideMessageHolder.getInstance().messageType = null
if (proceedButton!!.isEnabled) {
proceedButton!!.isEnabled = false
proceedButton!!.alpha = 0.7f
}
}
}
@OnClick(R.id.ok_button)
fun onProceedButtonClick() {
val bundle: Bundle
if (operationCode == 99) {
eventBus.post(BottomSheetLockEvent(false, 0, false, false))
bundle = Bundle()
bundle.putParcelable(BundleKeys.KEY_ROOM, Parcels.wrap(conversation))
bundle.putString(BundleKeys.KEY_CALL_URL, callUrl)
bundle.putString(BundleKeys.KEY_CONVERSATION_PASSWORD,
editText!!.text!!.toString())
bundle.putInt(BundleKeys.KEY_OPERATION_CODE, operationCode)
if (originalBundle.containsKey(BundleKeys.KEY_SERVER_CAPABILITIES)) {
bundle.putParcelable(BundleKeys.KEY_SERVER_CAPABILITIES,
originalBundle.getParcelable(BundleKeys.KEY_SERVER_CAPABILITIES))
}
router.pushController(RouterTransaction.with(OperationsMenuController(bundle))
.pushChangeHandler(HorizontalChangeHandler())
.popChangeHandler(HorizontalChangeHandler()))
} else if (operationCode != 7 && operationCode != 10 && operationCode != 11) {
eventBus.post(BottomSheetLockEvent(false, 0, false, false))
bundle = Bundle()
if (operationCode == 4 || operationCode == 6) {
conversation!!.password = editText!!.text!!.toString()
} else {
conversation!!.name = editText!!.text!!.toString()
}
bundle.putParcelable(BundleKeys.KEY_ROOM, Parcels.wrap(conversation))
bundle.putInt(BundleKeys.KEY_OPERATION_CODE, operationCode)
router.pushController(RouterTransaction.with(OperationsMenuController(bundle))
.pushChangeHandler(HorizontalChangeHandler())
.popChangeHandler(HorizontalChangeHandler()))
} else if (operationCode == 7) {
if (activity != null) {
shareIntent!!.putExtra(Intent.EXTRA_TEXT, ShareUtils.getStringForIntent(activity,
editText!!.text!!.toString(), conversation!!))
val intent = Intent(shareIntent)
intent.component = ComponentName(packageName, name)
intent.flags = Intent.FLAG_ACTIVITY_NEW_TASK
activity!!.startActivity(intent)
eventBus.post(BottomSheetLockEvent(true, 0, false, true))
}
} else if (operationCode != 11) {
eventBus.post(BottomSheetLockEvent(false, 0, false, false))
bundle = Bundle()
bundle.putInt(BundleKeys.KEY_OPERATION_CODE, operationCode)
bundle.putString(BundleKeys.KEY_CALL_URL, editText!!.text!!.toString())
router.pushController(RouterTransaction.with(OperationsMenuController(bundle))
.pushChangeHandler(HorizontalChangeHandler())
.popChangeHandler(HorizontalChangeHandler()))
} else if (operationCode == 11) {
eventBus.post(BottomSheetLockEvent(false, 0, false, false))
originalBundle.putString(BundleKeys.KEY_CONVERSATION_NAME,
editText!!.text!!.toString())
router.pushController(
RouterTransaction.with(OperationsMenuController(originalBundle))
.pushChangeHandler(HorizontalChangeHandler())
.popChangeHandler(HorizontalChangeHandler()))
}
}
override fun onViewBound(view: View) {
super.onViewBound(view)
if (conversation != null && operationCode == 2) {
editText!!.setText(conversation!!.name)
}
editText!!.setOnEditorActionListener { v, actionId, event ->
if (actionId == EditorInfo.IME_ACTION_DONE
&& proceedButton != null
&& proceedButton!!.isEnabled) {
proceedButton!!.callOnClick()
true
}
false
}
editText!!.addTextChangedListener(object : TextWatcher {
override fun beforeTextChanged(s: CharSequence, start: Int, count: Int, after: Int) {
}
override fun onTextChanged(s: CharSequence, start: Int, before: Int, count: Int) {
}
override fun afterTextChanged(s: Editable) {
if (!TextUtils.isEmpty(s)) {
if (operationCode == 2) {
if (conversation!!.name == null || conversation!!.name != s.toString()) {
if (!proceedButton!!.isEnabled) {
proceedButton!!.isEnabled = true
proceedButton!!.alpha = 1.0f
}
textInputLayout!!.isErrorEnabled = false
} else {
if (proceedButton!!.isEnabled) {
proceedButton!!.isEnabled = false
proceedButton!!.alpha = 0.38f
}
textInputLayout!!.error = resources!!.getString(R.string.nc_call_name_is_same)
}
} else if (operationCode != 10) {
if (!proceedButton!!.isEnabled) {
proceedButton!!.isEnabled = true
proceedButton!!.alpha = 1.0f
}
textInputLayout!!.isErrorEnabled = false
} else if ((editText!!.text!!.toString().startsWith("http://") || editText!!.text!!.toString().startsWith("https://")) && editText!!.text!!.toString().contains("/call/")) {
// operation code 10
if (!proceedButton!!.isEnabled) {
proceedButton!!.isEnabled = true
proceedButton!!.alpha = 1.0f
}
textInputLayout!!.isErrorEnabled = false
} else {
if (proceedButton!!.isEnabled) {
proceedButton!!.isEnabled = false
proceedButton!!.alpha = 0.38f
}
textInputLayout!!.error = resources!!.getString(R.string.nc_wrong_link)
}
} else {
if (proceedButton!!.isEnabled) {
proceedButton!!.isEnabled = false
proceedButton!!.alpha = 0.38f
}
textInputLayout!!.isErrorEnabled = false
}
}
})
var labelText = ""
when (operationCode) {
11, 2 -> {
labelText = resources!!.getString(R.string.nc_call_name)
editText!!.inputType = InputType.TYPE_CLASS_TEXT
smileyButton!!.visibility = View.VISIBLE
emojiPopup = EmojiPopup.Builder.fromRootView(view)
.setOnEmojiPopupShownListener {
if (resources != null) {
smileyButton!!.setColorFilter(resources!!.getColor(R.color.colorPrimary),
PorterDuff.Mode.SRC_IN)
}
}
.setOnEmojiPopupDismissListener {
if (smileyButton != null) {
smileyButton!!.setColorFilter(resources!!.getColor(R.color.emoji_icons),
PorterDuff.Mode.SRC_IN)
}
}
.setOnEmojiClickListener { emoji, imageView -> editText!!.editableText.append(" ") }
.build(editText!!)
}
4 -> {
labelText = resources!!.getString(R.string.nc_new_password)
editText!!.inputType = InputType.TYPE_CLASS_TEXT or InputType.TYPE_TEXT_VARIATION_PASSWORD
}
6, 7, 99 -> {
// 99 is joining a conversation via password
labelText = resources!!.getString(R.string.nc_password)
editText!!.inputType = InputType.TYPE_CLASS_TEXT or InputType.TYPE_TEXT_VARIATION_PASSWORD
}
10 -> {
labelText = resources!!.getString(R.string.nc_conversation_link)
editText!!.inputType = InputType.TYPE_CLASS_TEXT or InputType.TYPE_TEXT_VARIATION_URI
}
else -> {
}
}
textInputLayout!!.isPasswordVisibilityToggleEnabled = operationCode == 99 || operationCode == 4 || operationCode == 6 || operationCode == 7
textInputLayout!!.hint = labelText
textInputLayout!!.requestFocus()
}
}

View File

@ -1,665 +0,0 @@
/*
* Nextcloud Talk application
*
* @author Mario Danic
* Copyright (C) 2017 Mario Danic <mario@lovelyhq.com>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package com.nextcloud.talk.controllers.bottomsheet
import android.app.Activity
import android.content.Intent
import android.net.Uri
import android.os.Bundle
import android.os.Handler
import android.text.TextUtils
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.view.inputmethod.InputMethodManager
import android.widget.Button
import android.widget.ImageView
import android.widget.ProgressBar
import android.widget.TextView
import butterknife.BindView
import com.bluelinelabs.conductor.RouterTransaction
import com.bluelinelabs.conductor.changehandler.HorizontalChangeHandler
import com.nextcloud.talk.R
import com.nextcloud.talk.activities.MagicCallActivity
import com.nextcloud.talk.api.NcApi
import com.nextcloud.talk.controllers.base.BaseController
import com.nextcloud.talk.events.BottomSheetLockEvent
import com.nextcloud.talk.models.RetrofitBucket
import com.nextcloud.talk.models.json.capabilities.Capabilities
import com.nextcloud.talk.models.json.capabilities.CapabilitiesOverall
import com.nextcloud.talk.models.json.conversations.Conversation
import com.nextcloud.talk.models.json.conversations.ConversationOverall
import com.nextcloud.talk.models.json.generic.GenericOverall
import com.nextcloud.talk.models.json.participants.AddParticipantOverall
import com.nextcloud.talk.newarch.domain.repository.offline.UsersRepository
import com.nextcloud.talk.newarch.local.models.UserNgEntity
import com.nextcloud.talk.newarch.local.models.getCredentials
import com.nextcloud.talk.utils.ApiUtils
import com.nextcloud.talk.utils.ConductorRemapping
import com.nextcloud.talk.utils.DisplayUtils
import com.nextcloud.talk.utils.bundle.BundleKeys
import com.nextcloud.talk.utils.singletons.ApplicationWideMessageHolder
import io.reactivex.Observer
import io.reactivex.android.schedulers.AndroidSchedulers
import io.reactivex.disposables.Disposable
import io.reactivex.schedulers.Schedulers
import kotlinx.coroutines.GlobalScope
import kotlinx.coroutines.launch
import org.koin.android.ext.android.inject
import org.parceler.Parcels
import retrofit2.HttpException
import java.util.*
class OperationsMenuController(args: Bundle) : BaseController() {
@JvmField
@BindView(R.id.progress_bar)
internal var progressBar: ProgressBar? = null
@JvmField
@BindView(R.id.result_image_view)
internal var resultImageView: ImageView? = null
@JvmField
@BindView(R.id.result_text_view)
internal var resultsTextView: TextView? = null
@JvmField
@BindView(R.id.ok_button)
internal var okButton: Button? = null
@JvmField
@BindView(R.id.web_button)
internal var webButton: Button? = null
val ncApi: NcApi by inject()
val usersRepository: UsersRepository by inject()
private val operationCode: Int
private var conversation: Conversation? = null
private var currentUser: UserNgEntity? = null
private val callPassword: String
private val callUrl: String
private var baseUrl: String? = null
private var conversationToken: String? = null
private var disposable: Disposable? = null
private var conversationType: Conversation.ConversationType? = null
private var invitedUsers: ArrayList<String>? = ArrayList()
private var invitedGroups: ArrayList<String>? = ArrayList()
private var serverCapabilities: Capabilities? = null
private var credentials: String? = null
private val conversationName: String
init {
this.operationCode = args.getInt(BundleKeys.KEY_OPERATION_CODE)
if (args.containsKey(BundleKeys.KEY_ROOM)) {
this.conversation = Parcels.unwrap(args.getParcelable(BundleKeys.KEY_ROOM))
}
this.callPassword = args.getString(BundleKeys.KEY_CONVERSATION_PASSWORD, "")
this.callUrl = args.getString(BundleKeys.KEY_CALL_URL, "")
if (args.containsKey(BundleKeys.KEY_INVITED_PARTICIPANTS)) {
this.invitedUsers = args.getStringArrayList(BundleKeys.KEY_INVITED_PARTICIPANTS)
}
if (args.containsKey(BundleKeys.KEY_INVITED_GROUP)) {
this.invitedGroups = args.getStringArrayList(BundleKeys.KEY_INVITED_GROUP)
}
if (args.containsKey(BundleKeys.KEY_CONVERSATION_TYPE)) {
this.conversationType = Parcels.unwrap(args.getParcelable(BundleKeys.KEY_CONVERSATION_TYPE))
}
if (args.containsKey(BundleKeys.KEY_SERVER_CAPABILITIES)) {
this.serverCapabilities = Parcels.unwrap(args.getParcelable(BundleKeys.KEY_SERVER_CAPABILITIES))
}
this.conversationName = args.getString(BundleKeys.KEY_CONVERSATION_NAME, "")
}
override fun inflateView(inflater: LayoutInflater, container: ViewGroup): View {
return inflater.inflate(R.layout.controller_operations_menu, container, false)
}
override fun onViewBound(view: View) {
super.onViewBound(view)
processOperation()
}
private fun processOperation() {
GlobalScope.launch {
currentUser = usersRepository.getActiveUser()
val operationsObserver = OperationsObserver()
if (!TextUtils.isEmpty(callUrl) && callUrl.contains("/call")) {
conversationToken = callUrl.substring(callUrl.lastIndexOf("/") + 1)
if (callUrl.contains("/index.php")) {
baseUrl = callUrl.substring(0, callUrl.indexOf("/index.php"))
} else {
baseUrl = callUrl.substring(0, callUrl.indexOf("/call"))
}
}
if (currentUser != null) {
credentials = currentUser!!.getCredentials()
if (!TextUtils.isEmpty(baseUrl) && baseUrl != currentUser!!.baseUrl) {
credentials = null
}
when (operationCode) {
2 -> ncApi.renameRoom(credentials,
ApiUtils.getRoom(currentUser!!.baseUrl, conversation!!.token),
conversation!!.name)
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.retry(1)
.subscribe(operationsObserver)
3 -> ncApi.makeRoomPublic(credentials,
ApiUtils.getUrlForRoomVisibility(currentUser!!.baseUrl, conversation!!
.token))
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.retry(1)
.subscribe(operationsObserver)
4, 5, 6 -> {
var pass: String? = ""
if (conversation!!.password != null) {
pass = conversation!!.password
}
ncApi.setPassword(credentials, ApiUtils.getUrlForPassword(currentUser!!.baseUrl,
conversation!!.token), pass)
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.retry(1)
.subscribe(operationsObserver)
}
7 -> {
}
8 -> ncApi.makeRoomPrivate(credentials,
ApiUtils.getUrlForRoomVisibility(currentUser!!.baseUrl, conversation!!
.token))
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.retry(1)
.subscribe(operationsObserver)
10 -> ncApi.getRoom(credentials, ApiUtils.getRoom(baseUrl, conversationToken))
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.retry(1)
.subscribe(object : Observer<ConversationOverall> {
override fun onSubscribe(d: Disposable) {
disposable = d
}
override fun onNext(conversationOverall: ConversationOverall) {
conversation = conversationOverall.ocs.data
fetchCapabilities(credentials)
}
override fun onError(e: Throwable) {
showResultImage(false, false)
dispose()
}
override fun onComplete() {
dispose()
}
})
11 -> {
val retrofitBucket: RetrofitBucket
var isGroupCallWorkaround = false
var invite: String? = null
if (invitedGroups!!.size > 0) {
invite = invitedGroups!![0]
}
if (conversationType == Conversation.ConversationType.PUBLIC_CONVERSATION || !currentUser!!.hasSpreedFeatureCapability("empty-group-room")) {
retrofitBucket = ApiUtils.getRetrofitBucketForCreateRoom(currentUser!!.baseUrl,
"3", invite, conversationName)
} else {
var roomType = "2"
if (!currentUser!!.hasSpreedFeatureCapability("empty-group-room")) {
isGroupCallWorkaround = true
roomType = "3"
}
retrofitBucket = ApiUtils.getRetrofitBucketForCreateRoom(currentUser!!.baseUrl,
roomType, invite, conversationName)
}
val isGroupCallWorkaroundFinal = isGroupCallWorkaround
ncApi.createRoom(credentials, retrofitBucket.url, retrofitBucket.queryMap)
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.retry(1)
.subscribe(object : Observer<ConversationOverall> {
override fun onSubscribe(d: Disposable) {
}
override fun onNext(conversationOverall: ConversationOverall) {
conversation = conversationOverall.ocs.data
ncApi.getRoom(credentials,
ApiUtils.getRoom(currentUser!!.baseUrl, conversation!!.token))
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(object : Observer<ConversationOverall> {
override fun onSubscribe(d: Disposable) {
}
override fun onNext(conversationOverall: ConversationOverall) {
conversation = conversationOverall.ocs.data
if (conversationType == Conversation.ConversationType.PUBLIC_CONVERSATION && isGroupCallWorkaroundFinal) {
performGroupCallWorkaround(credentials)
} else {
inviteUsersToAConversation()
}
}
override fun onError(e: Throwable) {
showResultImage(false, false)
dispose()
}
override fun onComplete() {
}
})
}
override fun onError(e: Throwable) {
showResultImage(false, false)
dispose()
}
override fun onComplete() {
dispose()
}
})
}
97, 98 -> if (operationCode == 97) {
ncApi.removeConversationFromFavorites(credentials,
ApiUtils.getUrlForConversationFavorites(currentUser!!.baseUrl,
conversation!!.token))
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.retry(1)
.subscribe(operationsObserver)
} else {
ncApi.addConversationToFavorites(credentials,
ApiUtils.getUrlForConversationFavorites(currentUser!!.baseUrl,
conversation!!.token))
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.retry(1)
.subscribe(operationsObserver)
}
99 -> ncApi.joinRoom(credentials,
ApiUtils.getUrlForSettingMyselfAsActiveParticipant(baseUrl, conversationToken),
callPassword)
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.retry(1)
.subscribe(operationsObserver)
else -> {
}
}// Operation 7 is sharing, so we handle this differently
}
}
}
private fun performGroupCallWorkaround(credentials: String?) {
ncApi.makeRoomPrivate(credentials,
ApiUtils.getUrlForRoomVisibility(currentUser!!.baseUrl, conversation!!.token))
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.retry(1)
.subscribe(object : Observer<GenericOverall> {
override fun onSubscribe(d: Disposable) {
}
override fun onNext(genericOverall: GenericOverall) {
inviteUsersToAConversation()
}
override fun onError(e: Throwable) {
showResultImage(false, false)
dispose()
}
override fun onComplete() {
dispose()
}
})
}
private fun showResultImage(everythingOK: Boolean, isGuestSupportError: Boolean) {
progressBar!!.visibility = View.GONE
if (everythingOK) {
resultImageView!!.setImageDrawable(DisplayUtils.getTintedDrawable(resources!!, R.drawable
.ic_check_circle_black_24dp, R.color.nc_darkGreen))
} else {
resultImageView!!.setImageDrawable(DisplayUtils.getTintedDrawable(resources!!, R.drawable
.ic_cancel_black_24dp, R.color.nc_darkRed))
}
resultImageView!!.visibility = View.VISIBLE
if (everythingOK) {
resultsTextView!!.setText(R.string.nc_all_ok_operation)
} else {
resultsTextView!!.setTextColor(resources!!.getColor(R.color.nc_darkRed))
if (!isGuestSupportError) {
resultsTextView!!.setText(R.string.nc_failed_to_perform_operation)
} else {
resultsTextView!!.setText(R.string.nc_failed_signaling_settings)
webButton!!.setOnClickListener { v ->
eventBus.post(BottomSheetLockEvent(true, 0, false, true))
val browserIntent = Intent(Intent.ACTION_VIEW, Uri.parse(callUrl))
startActivity(browserIntent)
BottomSheetLockEvent(true, 0, false, true)
}
webButton!!.visibility = View.VISIBLE
}
}
resultsTextView!!.visibility = View.VISIBLE
if (everythingOK) {
eventBus.post(BottomSheetLockEvent(true, 2500, true, true))
} else {
resultImageView!!.setImageDrawable(DisplayUtils.getTintedDrawable(resources!!, R.drawable
.ic_cancel_black_24dp, R.color.nc_darkRed))
okButton!!.setOnClickListener { v -> eventBus.post(BottomSheetLockEvent(true, 0, operationCode != 99 && operationCode != 10, true)) }
okButton!!.visibility = View.VISIBLE
}
}
private fun dispose() {
if (disposable != null && !disposable!!.isDisposed) {
disposable!!.dispose()
}
disposable = null
}
public override fun onDestroy() {
super.onDestroy()
dispose()
}
private fun fetchCapabilities(credentials: String?) {
ncApi.getCapabilities(credentials, ApiUtils.getUrlForCapabilities(baseUrl))
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(object : Observer<CapabilitiesOverall> {
override fun onSubscribe(d: Disposable) {
}
override fun onNext(capabilitiesOverall: CapabilitiesOverall) {
val hasChatV2Capability = capabilitiesOverall.ocs?.data?.capabilities?.spreedCapability?.features?.contains("chat-v2") == true
val hasGuestSignaling = capabilitiesOverall.ocs?.data?.capabilities?.spreedCapability?.features?.contains("guest-signaling") == true
if (hasChatV2Capability) {
if (conversation!!.hasPassword && conversation!!.isGuest) {
eventBus.post(BottomSheetLockEvent(true, 0,
true, false))
val bundle = Bundle()
bundle.putParcelable(BundleKeys.KEY_ROOM, Parcels.wrap(conversation))
bundle.putString(BundleKeys.KEY_CALL_URL, callUrl)
bundle.putParcelable(BundleKeys.KEY_SERVER_CAPABILITIES,
Parcels.wrap(capabilitiesOverall.ocs.data.capabilities))
bundle.putInt(BundleKeys.KEY_OPERATION_CODE, 99)
router.pushController(RouterTransaction.with(EntryMenuController(bundle))
.pushChangeHandler(HorizontalChangeHandler())
.popChangeHandler(HorizontalChangeHandler()))
} else {
initiateConversation(false, capabilitiesOverall.ocs.data.capabilities)
}
} else if (hasGuestSignaling) {
initiateCall()
} else {
showResultImage(false, true)
}
}
override fun onError(e: Throwable) {
showResultImage(false, false)
}
override fun onComplete() {
}
})
}
private fun inviteUsersToAConversation() {
var retrofitBucket: RetrofitBucket
val localInvitedUsers = invitedUsers
val localInvitedGroups = invitedGroups
if (localInvitedGroups!!.size > 0) {
localInvitedGroups.removeAt(0)
}
if (localInvitedUsers!!.size > 0 || localInvitedGroups.size > 0 && currentUser!!.hasSpreedFeatureCapability("invite-groups-and-mails")) {
if (localInvitedGroups.size > 0 && currentUser!!.hasSpreedFeatureCapability(
"invite-groups-and-mails")) {
for (i in localInvitedGroups.indices) {
val groupId = localInvitedGroups[i]
retrofitBucket = ApiUtils.getRetrofitBucketForAddGroupParticipant(currentUser!!.baseUrl,
conversation!!.token,
groupId)
ncApi.addParticipant(credentials, retrofitBucket.url, retrofitBucket.queryMap)
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.retry(1)
.subscribe(object : Observer<AddParticipantOverall> {
override fun onSubscribe(d: Disposable) {
}
override fun onNext(addParticipantOverall: AddParticipantOverall) {}
override fun onError(e: Throwable) {
dispose()
}
override fun onComplete() {
synchronized(localInvitedGroups) {
localInvitedGroups.remove(groupId)
}
if (localInvitedGroups.size == 0 && localInvitedUsers.size == 0) {
initiateConversation(true, null)
}
dispose()
}
})
}
}
for (i in localInvitedUsers.indices) {
val userId = invitedUsers!![i]
retrofitBucket = ApiUtils.getRetrofitBucketForAddParticipant(currentUser!!.baseUrl,
conversation!!.token,
userId)
ncApi.addParticipant(credentials, retrofitBucket.url, retrofitBucket.queryMap)
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.retry(1)
.subscribe(object : Observer<AddParticipantOverall> {
override fun onSubscribe(d: Disposable) {
}
override fun onNext(addParticipantOverall: AddParticipantOverall) {}
override fun onError(e: Throwable) {
dispose()
}
override fun onComplete() {
synchronized(localInvitedUsers) {
localInvitedUsers.remove(userId)
}
if (localInvitedGroups.size == 0 && localInvitedUsers.size == 0) {
initiateConversation(true, null)
}
dispose()
}
})
}
} else {
if (!currentUser!!.hasSpreedFeatureCapability("chat-v2")) {
showResultImage(true, false)
} else {
initiateConversation(true, null)
}
}
}
private fun initiateConversation(dismissView: Boolean, capabilities: Capabilities?) {
val bundle = Bundle()
var isGuestUser = false
val hasChatCapability: Boolean
if (baseUrl != null && baseUrl != currentUser!!.baseUrl) {
isGuestUser = true
hasChatCapability = capabilities?.spreedCapability?.features?.contains("chat-v2") == true
} else {
hasChatCapability = currentUser!!.hasSpreedFeatureCapability("chat-v2")
}
if (hasChatCapability) {
eventBus.post(BottomSheetLockEvent(true, 0,
true, true, dismissView))
val conversationIntent = Intent(activity, MagicCallActivity::class.java)
bundle.putString(BundleKeys.KEY_CONVERSATION_TOKEN, conversation!!.token)
bundle.putString(BundleKeys.KEY_ROOM_ID, conversation!!.conversationId)
bundle.putString(BundleKeys.KEY_CONVERSATION_NAME,
conversation!!.displayName)
val conversationUser: UserNgEntity
if (isGuestUser) {
conversationUser = UserNgEntity(-1, "?", "?", baseUrl!!)
conversationUser.capabilities = capabilities!!
} else {
conversationUser = currentUser!!
}
bundle.putParcelable(BundleKeys.KEY_USER_ENTITY, conversationUser)
bundle.putParcelable(BundleKeys.KEY_ACTIVE_CONVERSATION,
Parcels.wrap(conversation))
bundle.putString(BundleKeys.KEY_CONVERSATION_PASSWORD, callPassword)
conversationIntent.putExtras(bundle)
if (parentController != null) {
ConductorRemapping.remapChatController(parentController!!.router,
conversationUser.id!!,
conversation!!.token!!, bundle, true)
}
} else {
initiateCall()
}
}
private fun initiateCall() {
eventBus.post(BottomSheetLockEvent(true, 0, true, true))
val bundle = Bundle()
bundle.putString(BundleKeys.KEY_CONVERSATION_TOKEN, conversation!!.token)
bundle.putParcelable(BundleKeys.KEY_USER_ENTITY, currentUser)
if (baseUrl != null && baseUrl != currentUser!!.baseUrl) {
bundle.putString(BundleKeys.KEY_MODIFIED_BASE_URL, baseUrl)
}
bundle.putParcelable(BundleKeys.KEY_ACTIVE_CONVERSATION,
Parcels.wrap(conversation))
if (activity != null) {
val callIntent = Intent(activity, MagicCallActivity::class.java)
callIntent.putExtras(bundle)
val imm = activity!!.getSystemService(Activity.INPUT_METHOD_SERVICE) as InputMethodManager
imm.toggleSoftInput(InputMethodManager.HIDE_IMPLICIT_ONLY, 0)
Handler().postDelayed({ parentController!!.router.popCurrentController() },
100)
startActivity(callIntent)
}
}
private inner class OperationsObserver : Observer<Any> {
override fun onSubscribe(d: Disposable) {
disposable = d
}
override fun onNext(o: Any) {
if (operationCode != 99) {
showResultImage(true, false)
} else {
val roomOverall = o as ConversationOverall
conversation = roomOverall.ocs.data
initiateConversation(true, serverCapabilities)
}
}
override fun onError(e: Throwable) {
if (operationCode != 99 || e !is HttpException) {
showResultImage(false, false)
} else {
if (e.response()!!.code() == 403) {
eventBus.post(BottomSheetLockEvent(true, 0, false,
false))
ApplicationWideMessageHolder.getInstance().messageType = ApplicationWideMessageHolder.MessageType.CALL_PASSWORD_WRONG
router.popCurrentController()
} else {
showResultImage(false, false)
}
}
dispose()
}
override fun onComplete() {
dispose()
}
}
}