diff --git a/.editorconfig b/.editorconfig index 7de780eb349..be62f0799ad 100644 --- a/.editorconfig +++ b/.editorconfig @@ -38,6 +38,10 @@ indent_size=2 [*.{kt,kts}] # IDE does not follow this Ktlint rule strictly, but the default ordering is pretty good anyway, so let's ditch it +insert_final_newline = true +ktlint_function_signature_rule_force_multiline_when_parameter_count_greater_or_equal_than=unset +ktlint_function_signature_body_expression_wrapping=multiline ktlint_standard_import-ordering = disabled +ktlint_standard_wrapping = enabled ij_kotlin_allow_trailing_comma = false ij_kotlin_allow_trailing_comma_on_call_site = false diff --git a/app/src/gplay/java/com/nextcloud/talk/utils/ClosedInterfaceImpl.kt b/app/src/gplay/java/com/nextcloud/talk/utils/ClosedInterfaceImpl.kt index e6d9ca62a66..6c854458169 100644 --- a/app/src/gplay/java/com/nextcloud/talk/utils/ClosedInterfaceImpl.kt +++ b/app/src/gplay/java/com/nextcloud/talk/utils/ClosedInterfaceImpl.kt @@ -55,10 +55,7 @@ class ClosedInterfaceImpl : ClosedInterface, ProviderInstaller.ProviderInstallLi // unused atm } - override fun onProviderInstallFailed( - p0: Int, - p1: Intent? - ) { + override fun onProviderInstallFailed(p0: Int, p1: Intent?) { // unused atm } 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 9d8aef034d9..7f1b8400e7b 100644 --- a/app/src/main/java/com/nextcloud/talk/account/AccountVerificationActivity.kt +++ b/app/src/main/java/com/nextcloud/talk/account/AccountVerificationActivity.kt @@ -148,51 +148,55 @@ class AccountVerificationActivity : BaseActivity() { private fun determineBaseUrlProtocol(checkForcedHttps: Boolean) { cookieManager.cookieStore.removeAll() baseUrl = baseUrl!!.replace("http://", "").replace("https://", "") - val queryUrl: String = if (checkForcedHttps) { - "https://" + baseUrl + ApiUtils.getUrlPostfixForStatus() - } else { - "http://" + baseUrl + ApiUtils.getUrlPostfixForStatus() - } + val queryUrl: String = + if (checkForcedHttps) { + "https://" + baseUrl + ApiUtils.getUrlPostfixForStatus() + } else { + "http://" + baseUrl + ApiUtils.getUrlPostfixForStatus() + } ncApi.getServerStatus(queryUrl) .subscribeOn(Schedulers.io()) .observeOn(AndroidSchedulers.mainThread()) - .subscribe(object : Observer { - override fun onSubscribe(d: Disposable) { - disposables.add(d) - } - - override fun onNext(status: Status) { - baseUrl = if (checkForcedHttps) { - "https://$baseUrl" - } else { - "http://$baseUrl" + .subscribe( + object : Observer { + override fun onSubscribe(d: Disposable) { + disposables.add(d) } - if (isAccountImport) { - val bundle = Bundle() - bundle.putString(KEY_BASE_URL, baseUrl) - bundle.putString(KEY_USERNAME, username) - bundle.putString(KEY_PASSWORD, "") - - val intent = Intent(context, WebViewLoginActivity::class.java) - intent.putExtras(bundle) - startActivity(intent) - } else { - findServerTalkApp() + + override fun onNext(status: Status) { + baseUrl = + if (checkForcedHttps) { + "https://$baseUrl" + } else { + "http://$baseUrl" + } + if (isAccountImport) { + val bundle = Bundle() + bundle.putString(KEY_BASE_URL, baseUrl) + bundle.putString(KEY_USERNAME, username) + bundle.putString(KEY_PASSWORD, "") + + val intent = Intent(context, WebViewLoginActivity::class.java) + intent.putExtras(bundle) + startActivity(intent) + } else { + findServerTalkApp() + } } - } - override fun onError(e: Throwable) { - if (checkForcedHttps) { - determineBaseUrlProtocol(false) - } else { - abortVerification() + override fun onError(e: Throwable) { + if (checkForcedHttps) { + determineBaseUrlProtocol(false) + } else { + abortVerification() + } } - } - override fun onComplete() { - // unused atm + override fun onComplete() { + // unused atm + } } - }) + ) } private fun findServerTalkApp() { @@ -201,52 +205,58 @@ class AccountVerificationActivity : BaseActivity() { ncApi.getCapabilities(credentials, ApiUtils.getUrlForCapabilities(baseUrl)) .subscribeOn(Schedulers.io()) - .subscribe(object : Observer { - override fun onSubscribe(d: Disposable) { - disposables.add(d) - } + .subscribe( + object : Observer { + override fun onSubscribe(d: Disposable) { + disposables.add(d) + } - override fun onNext(capabilitiesOverall: CapabilitiesOverall) { - val hasTalk = - capabilitiesOverall.ocs!!.data!!.capabilities != null && - capabilitiesOverall.ocs!!.data!!.capabilities!!.spreedCapability != null && - capabilitiesOverall.ocs!!.data!!.capabilities!!.spreedCapability!!.features != null && - !capabilitiesOverall.ocs!!.data!!.capabilities!!.spreedCapability!!.features!!.isEmpty() - if (hasTalk) { - fetchProfile(credentials, capabilitiesOverall) - } else { + override fun onNext(capabilitiesOverall: CapabilitiesOverall) { + val hasTalk = + capabilitiesOverall.ocs!!.data!!.capabilities != null && + capabilitiesOverall.ocs!!.data!!.capabilities!!.spreedCapability != null && + capabilitiesOverall.ocs!!.data!!.capabilities!!.spreedCapability!!.features != null && + !capabilitiesOverall.ocs!!.data!!.capabilities!!.spreedCapability!!.features!!.isEmpty() + if (hasTalk) { + fetchProfile(credentials, capabilitiesOverall) + } else { + if (resources != null) { + runOnUiThread { + binding.progressText.text = + String + .format( + resources!!.getString(R.string.nc_nextcloud_talk_app_not_installed), + resources!!.getString(R.string.nc_app_product_name) + ) + } + } + ApplicationWideMessageHolder.getInstance().messageType = + ApplicationWideMessageHolder.MessageType.SERVER_WITHOUT_TALK + abortVerification() + } + } + + override fun onError(e: Throwable) { if (resources != null) { runOnUiThread { - binding.progressText.text = String.format( - resources!!.getString(R.string.nc_nextcloud_talk_app_not_installed), - resources!!.getString(R.string.nc_app_product_name) - ) + binding.progressText.text = + String + .format( + resources!!.getString(R.string.nc_nextcloud_talk_app_not_installed), + resources!!.getString(R.string.nc_app_product_name) + ) } } ApplicationWideMessageHolder.getInstance().messageType = ApplicationWideMessageHolder.MessageType.SERVER_WITHOUT_TALK abortVerification() } - } - override fun onError(e: Throwable) { - if (resources != null) { - runOnUiThread { - binding.progressText.text = String.format( - resources!!.getString(R.string.nc_nextcloud_talk_app_not_installed), - resources!!.getString(R.string.nc_app_product_name) - ) - } + override fun onComplete() { + // unused atm } - ApplicationWideMessageHolder.getInstance().messageType = - ApplicationWideMessageHolder.MessageType.SERVER_WITHOUT_TALK - abortVerification() } - - override fun onComplete() { - // unused atm - } - }) + ) } private fun storeProfile(displayName: String?, userId: String, capabilities: Capabilities) { @@ -266,39 +276,41 @@ class AccountVerificationActivity : BaseActivity() { ) ) .subscribeOn(Schedulers.io()) - .subscribe(object : MaybeObserver { - override fun onSubscribe(d: Disposable) { - disposables.add(d) - } + .subscribe( + object : MaybeObserver { + override fun onSubscribe(d: Disposable) { + disposables.add(d) + } - @SuppressLint("SetTextI18n") - override fun onSuccess(user: User) { - internalAccountId = user.id!! - if (ClosedInterfaceImpl().isGooglePlayServicesAvailable) { - ClosedInterfaceImpl().setUpPushTokenRegistration() - } else { - Log.w(TAG, "Skipping push registration.") - runOnUiThread { - binding.progressText.text = - """ ${binding.progressText.text} + @SuppressLint("SetTextI18n") + override fun onSuccess(user: User) { + internalAccountId = user.id!! + if (ClosedInterfaceImpl().isGooglePlayServicesAvailable) { + ClosedInterfaceImpl().setUpPushTokenRegistration() + } else { + Log.w(TAG, "Skipping push registration.") + runOnUiThread { + binding.progressText.text = + """ ${binding.progressText.text} ${resources!!.getString(R.string.nc_push_disabled)} - """.trimIndent() + """.trimIndent() + } + fetchAndStoreCapabilities() } - fetchAndStoreCapabilities() } - } - @SuppressLint("SetTextI18n") - override fun onError(e: Throwable) { - binding.progressText.text = """ ${binding.progressText.text}""".trimIndent() + - resources!!.getString(R.string.nc_display_name_not_stored) - abortVerification() - } + @SuppressLint("SetTextI18n") + override fun onError(e: Throwable) { + binding.progressText.text = """ ${binding.progressText.text}""".trimIndent() + + resources!!.getString(R.string.nc_display_name_not_stored) + abortVerification() + } - override fun onComplete() { - // unused atm + override fun onComplete() { + // unused atm + } } - }) + ) } private fun fetchProfile(credentials: String, capabilities: CapabilitiesOverall) { @@ -307,53 +319,55 @@ class AccountVerificationActivity : BaseActivity() { ApiUtils.getUrlForUserProfile(baseUrl) ) .subscribeOn(Schedulers.io()) - .subscribe(object : Observer { - override fun onSubscribe(d: Disposable) { - disposables.add(d) - } + .subscribe( + object : Observer { + override fun onSubscribe(d: Disposable) { + disposables.add(d) + } - @SuppressLint("SetTextI18n") - override fun onNext(userProfileOverall: UserProfileOverall) { - var displayName: String? = null - if (!TextUtils.isEmpty(userProfileOverall.ocs!!.data!!.displayName)) { - displayName = userProfileOverall.ocs!!.data!!.displayName - } else if (!TextUtils.isEmpty(userProfileOverall.ocs!!.data!!.displayNameAlt)) { - displayName = userProfileOverall.ocs!!.data!!.displayNameAlt + @SuppressLint("SetTextI18n") + override fun onNext(userProfileOverall: UserProfileOverall) { + var displayName: String? = null + if (!TextUtils.isEmpty(userProfileOverall.ocs!!.data!!.displayName)) { + displayName = userProfileOverall.ocs!!.data!!.displayName + } else if (!TextUtils.isEmpty(userProfileOverall.ocs!!.data!!.displayNameAlt)) { + displayName = userProfileOverall.ocs!!.data!!.displayNameAlt + } + if (!TextUtils.isEmpty(displayName)) { + storeProfile( + displayName, + userProfileOverall.ocs!!.data!!.userId!!, + capabilities.ocs!!.data!!.capabilities!! + ) + } else { + runOnUiThread { + binding.progressText.text = + """ + ${binding.progressText.text} + ${resources!!.getString(R.string.nc_display_name_not_fetched)} + """.trimIndent() + } + abortVerification() + } } - if (!TextUtils.isEmpty(displayName)) { - storeProfile( - displayName, - userProfileOverall.ocs!!.data!!.userId!!, - capabilities.ocs!!.data!!.capabilities!! - ) - } else { + + @SuppressLint("SetTextI18n") + override fun onError(e: Throwable) { runOnUiThread { binding.progressText.text = """ - ${binding.progressText.text} - ${resources!!.getString(R.string.nc_display_name_not_fetched)} + ${binding.progressText.text} + ${resources!!.getString(R.string.nc_display_name_not_fetched)} """.trimIndent() } abortVerification() } - } - @SuppressLint("SetTextI18n") - override fun onError(e: Throwable) { - runOnUiThread { - binding.progressText.text = - """ - ${binding.progressText.text} - ${resources!!.getString(R.string.nc_display_name_not_fetched)} - """.trimIndent() + override fun onComplete() { + // unused atm } - abortVerification() - } - - override fun onComplete() { - // unused atm } - }) + ) } @SuppressLint("SetTextI18n") @@ -365,8 +379,8 @@ class AccountVerificationActivity : BaseActivity() { runOnUiThread { binding.progressText.text = """ - ${binding.progressText.text} - ${resources!!.getString(R.string.nc_push_disabled)} + ${binding.progressText.text} + ${resources!!.getString(R.string.nc_push_disabled)} """.trimIndent() } } @@ -376,8 +390,8 @@ class AccountVerificationActivity : BaseActivity() { runOnUiThread { binding.progressText.text = """ - ${binding.progressText.text} - ${resources!!.getString(R.string.nc_capabilities_failed)} + ${binding.progressText.text} + ${resources!!.getString(R.string.nc_capabilities_failed)} """.trimIndent() } abortVerification() @@ -389,8 +403,8 @@ class AccountVerificationActivity : BaseActivity() { runOnUiThread { binding.progressText.text = """ - ${binding.progressText.text} - ${resources!!.getString(R.string.nc_external_server_failed)} + ${binding.progressText.text} + ${resources!!.getString(R.string.nc_external_server_failed)} """.trimIndent() } } @@ -415,10 +429,15 @@ class AccountVerificationActivity : BaseActivity() { Data.Builder() .putLong(KEY_INTERNAL_USER_ID, internalAccountId) .build() - val signalingSettingsWorker = OneTimeWorkRequest.Builder(SignalingSettingsWorker::class.java) - .setInputData(userData) - .build() - val websocketConnectionsWorker = OneTimeWorkRequest.Builder(WebsocketConnectionsWorker::class.java).build() + val signalingSettingsWorker = + OneTimeWorkRequest + .Builder(SignalingSettingsWorker::class.java) + .setInputData(userData) + .build() + val websocketConnectionsWorker = + OneTimeWorkRequest + .Builder(WebsocketConnectionsWorker::class.java) + .build() WorkManager.getInstance(applicationContext!!) .beginWith(signalingSettingsWorker) @@ -473,8 +492,10 @@ class AccountVerificationActivity : BaseActivity() { private fun abortVerification() { if (isAccountImport) { - ApplicationWideMessageHolder.getInstance().messageType = ApplicationWideMessageHolder.MessageType - .FAILED_TO_IMPORT_ACCOUNT + ApplicationWideMessageHolder.getInstance().messageType = + ApplicationWideMessageHolder + .MessageType + .FAILED_TO_IMPORT_ACCOUNT runOnUiThread { Handler().postDelayed({ val intent = Intent(this, ServerSelectionActivity::class.java) 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 d6bc6712903..4aa51dcf13a 100644 --- a/app/src/main/java/com/nextcloud/talk/account/ServerSelectionActivity.kt +++ b/app/src/main/java/com/nextcloud/talk/account/ServerSelectionActivity.kt @@ -74,15 +74,16 @@ class ServerSelectionActivity : BaseActivity() { private var statusQueryDisposable: Disposable? = null - private val onBackPressedCallback = object : OnBackPressedCallback(true) { - override fun handleOnBackPressed() { - if (intent.hasExtra(ADD_ADDITIONAL_ACCOUNT) && intent.getBooleanExtra(ADD_ADDITIONAL_ACCOUNT, false)) { - finish() - } else { - finishAffinity() + private val onBackPressedCallback = + object : OnBackPressedCallback(true) { + override fun handleOnBackPressed() { + if (intent.hasExtra(ADD_ADDITIONAL_ACCOUNT) && intent.getBooleanExtra(ADD_ADDITIONAL_ACCOUNT, false)) { + finish() + } else { + finishAffinity() + } } } - } @SuppressLint("SourceLockedOrientationActivity") override fun onCreate(savedInstanceState: Bundle?) { @@ -100,10 +101,12 @@ class ServerSelectionActivity : BaseActivity() { override fun onResume() { super.onResume() - binding.hostUrlInputHelperText.text = String.format( - resources!!.getString(R.string.nc_server_helper_text), - resources!!.getString(R.string.nc_server_product_name) - ) + binding.hostUrlInputHelperText.text = + String + .format( + resources!!.getString(R.string.nc_server_helper_text), + resources!!.getString(R.string.nc_server_product_name) + ) binding.serverEntryTextInputLayout.setEndIconOnClickListener { checkServerAndProceed() } if (resources!!.getBoolean(R.bool.hide_auth_cert)) { @@ -179,15 +182,21 @@ class ServerSelectionActivity : BaseActivity() { ) ) { if (availableAccounts.size > 1) { - binding.importOrChooseProviderText.text = String.format( - resources!!.getString(R.string.nc_server_import_accounts), - AccountUtils.getAppNameBasedOnPackage(resources!!.getString(R.string.nc_import_accounts_from)) - ) + binding.importOrChooseProviderText.text = + String + .format( + resources!!.getString(R.string.nc_server_import_accounts), + AccountUtils + .getAppNameBasedOnPackage(resources!!.getString(R.string.nc_import_accounts_from)) + ) } else { - binding.importOrChooseProviderText.text = String.format( - resources!!.getString(R.string.nc_server_import_account), - AccountUtils.getAppNameBasedOnPackage(resources!!.getString(R.string.nc_import_accounts_from)) - ) + binding.importOrChooseProviderText.text = + String + .format( + resources!!.getString(R.string.nc_server_import_account), + AccountUtils + .getAppNameBasedOnPackage(resources!!.getString(R.string.nc_import_accounts_from)) + ) } } else { if (availableAccounts.size > 1) { @@ -210,13 +219,14 @@ class ServerSelectionActivity : BaseActivity() { private fun showVisitProvidersInfo() { binding.importOrChooseProviderText.setText(R.string.nc_get_from_provider) binding.importOrChooseProviderText.setOnClickListener { - val browserIntent = Intent( - Intent.ACTION_VIEW, - Uri.parse( - resources!! - .getString(R.string.nc_providers_url) + val browserIntent = + Intent( + Intent.ACTION_VIEW, + Uri.parse( + resources!! + .getString(R.string.nc_providers_url) + ) ) - ) startActivity(browserIntent) } } @@ -249,129 +259,133 @@ class ServerSelectionActivity : BaseActivity() { private fun checkServer(url: String, checkForcedHttps: Boolean) { val queryStatusUrl = url + ApiUtils.getUrlPostfixForStatus() - statusQueryDisposable = ncApi.getServerStatus(queryStatusUrl) - .subscribeOn(Schedulers.io()) - .observeOn(AndroidSchedulers.mainThread()) - .subscribe({ status: Status -> - val productName = resources!!.getString(R.string.nc_server_product_name) - val versionString: String = status.version!!.substring(0, status.version!!.indexOf(".")) - val version: Int = versionString.toInt() - - if (isServerStatusQueryable(status) && version >= MIN_SERVER_MAJOR_VERSION) { - findServerTalkApp(url) - } else if (!status.installed) { - setErrorText( - String.format( - resources!!.getString(R.string.nc_server_not_installed), - productName + statusQueryDisposable = + ncApi + .getServerStatus(queryStatusUrl) + .subscribeOn(Schedulers.io()) + .observeOn(AndroidSchedulers.mainThread()) + .subscribe({ status: Status -> + val productName = resources!!.getString(R.string.nc_server_product_name) + val versionString: String = status.version!!.substring(0, status.version!!.indexOf(".")) + val version: Int = versionString.toInt() + + if (isServerStatusQueryable(status) && version >= MIN_SERVER_MAJOR_VERSION) { + findServerTalkApp(url) + } else if (!status.installed) { + setErrorText( + String.format( + resources!!.getString(R.string.nc_server_not_installed), + productName + ) ) - ) - } else if (status.needsUpgrade) { - setErrorText( - String.format( - resources!!.getString(R.string.nc_server_db_upgrade_needed), - productName + } else if (status.needsUpgrade) { + setErrorText( + String.format( + resources!!.getString(R.string.nc_server_db_upgrade_needed), + productName + ) ) - ) - } else if (status.maintenance) { - setErrorText( - String.format( - resources!!.getString(R.string.nc_server_maintenance), - productName + } else if (status.maintenance) { + setErrorText( + String.format( + resources!!.getString(R.string.nc_server_maintenance), + productName + ) ) - ) - } else if (!status.version!!.startsWith("13.")) { - setErrorText( - String.format( - resources!!.getString(R.string.nc_server_version), - resources!!.getString(R.string.nc_app_product_name), - productName + } else if (!status.version!!.startsWith("13.")) { + setErrorText( + String.format( + resources!!.getString(R.string.nc_server_version), + resources!!.getString(R.string.nc_app_product_name), + productName + ) ) - ) - } - }, { throwable: Throwable -> - if (checkForcedHttps) { - checkServer(queryStatusUrl.replace("https://", "http://"), false) - } else { - if (throwable.localizedMessage != null) { - setErrorText(throwable.localizedMessage) - } else if (throwable.cause is CertificateException) { - setErrorText(resources!!.getString(R.string.nc_certificate_error)) - } else { - hideserverEntryProgressBar() } + }, { throwable: Throwable -> + if (checkForcedHttps) { + checkServer(queryStatusUrl.replace("https://", "http://"), false) + } else { + if (throwable.localizedMessage != null) { + setErrorText(throwable.localizedMessage) + } else if (throwable.cause is CertificateException) { + setErrorText(resources!!.getString(R.string.nc_certificate_error)) + } else { + hideserverEntryProgressBar() + } + if (binding.importOrChooseProviderText.visibility != View.INVISIBLE) { + binding.importOrChooseProviderText.visibility = View.VISIBLE + binding.certTextView.visibility = View.VISIBLE + } + dispose() + } + }) { + hideserverEntryProgressBar() if (binding.importOrChooseProviderText.visibility != View.INVISIBLE) { binding.importOrChooseProviderText.visibility = View.VISIBLE binding.certTextView.visibility = View.VISIBLE } dispose() } - }) { - hideserverEntryProgressBar() - if (binding.importOrChooseProviderText.visibility != View.INVISIBLE) { - binding.importOrChooseProviderText.visibility = View.VISIBLE - binding.certTextView.visibility = View.VISIBLE - } - dispose() - } } private fun findServerTalkApp(queryUrl: String) { ncApi.getCapabilities(ApiUtils.getUrlForCapabilities(queryUrl)) .subscribeOn(Schedulers.io()) - .subscribe(object : Observer { - override fun onSubscribe(d: Disposable) { - // unused atm - } + .subscribe( + object : Observer { + override fun onSubscribe(d: Disposable) { + // unused atm + } - override fun onNext(capabilitiesOverall: CapabilitiesOverall) { - val capabilities = capabilitiesOverall.ocs?.data?.capabilities + override fun onNext(capabilitiesOverall: CapabilitiesOverall) { + val capabilities = capabilitiesOverall.ocs?.data?.capabilities - val hasTalk = - capabilities?.spreedCapability != null && - capabilities.spreedCapability?.features != null && - capabilities.spreedCapability?.features?.isNotEmpty() == true + val hasTalk = + capabilities?.spreedCapability != null && + capabilities.spreedCapability?.features != null && + capabilities.spreedCapability?.features?.isNotEmpty() == true - if (hasTalk) { - runOnUiThread { - if (CapabilitiesUtilNew.isServerEOL(capabilities)) { - if (resources != null) { - runOnUiThread { - setErrorText(resources!!.getString(R.string.nc_settings_server_eol)) + if (hasTalk) { + runOnUiThread { + if (CapabilitiesUtilNew.isServerEOL(capabilities)) { + if (resources != null) { + runOnUiThread { + setErrorText(resources!!.getString(R.string.nc_settings_server_eol)) + } } - } - } else { - val bundle = Bundle() - bundle.putString(BundleKeys.KEY_BASE_URL, queryUrl.replace("/status.php", "")) + } else { + val bundle = Bundle() + bundle.putString(BundleKeys.KEY_BASE_URL, queryUrl.replace("/status.php", "")) - val intent = Intent(context, WebViewLoginActivity::class.java) - intent.putExtras(bundle) - startActivity(intent) + val intent = Intent(context, WebViewLoginActivity::class.java) + intent.putExtras(bundle) + startActivity(intent) + } + } + } else { + if (resources != null) { + runOnUiThread { + setErrorText(resources!!.getString(R.string.nc_server_unsupported)) + } } } - } else { + } + + override fun onError(e: Throwable) { + Log.e(TAG, "Error while checking capabilities", e) if (resources != null) { runOnUiThread { - setErrorText(resources!!.getString(R.string.nc_server_unsupported)) + setErrorText(resources!!.getString(R.string.nc_common_error_sorry)) } } } - } - override fun onError(e: Throwable) { - Log.e(TAG, "Error while checking capabilities", e) - if (resources != null) { - runOnUiThread { - setErrorText(resources!!.getString(R.string.nc_common_error_sorry)) - } + override fun onComplete() { + // unused atm } } - - override fun onComplete() { - // unused atm - } - }) + ) } private fun isServerStatusQueryable(status: Status): Boolean { diff --git a/app/src/main/java/com/nextcloud/talk/account/SwitchAccountActivity.kt b/app/src/main/java/com/nextcloud/talk/account/SwitchAccountActivity.kt index c19c3223fd2..03748132434 100644 --- a/app/src/main/java/com/nextcloud/talk/account/SwitchAccountActivity.kt +++ b/app/src/main/java/com/nextcloud/talk/account/SwitchAccountActivity.kt @@ -72,25 +72,29 @@ class SwitchAccountActivity : BaseActivity() { private val userItems: MutableList> = ArrayList() private var isAccountImport = false - private val onImportItemClickListener = FlexibleAdapter.OnItemClickListener { _, position -> - if (userItems.size > position) { - val account = (userItems[position] as AdvancedUserItem).account - reauthorizeFromImport(account) - } - true - } + private val onImportItemClickListener = + FlexibleAdapter + .OnItemClickListener { _, position -> + if (userItems.size > position) { + val account = (userItems[position] as AdvancedUserItem).account + reauthorizeFromImport(account) + } + true + } - private val onSwitchItemClickListener = FlexibleAdapter.OnItemClickListener { _, position -> - if (userItems.size > position) { - val user = (userItems[position] as AdvancedUserItem).user + private val onSwitchItemClickListener = + FlexibleAdapter + .OnItemClickListener { _, position -> + if (userItems.size > position) { + val user = (userItems[position] as AdvancedUserItem).user - if (userManager.setUserAsActive(user).blockingGet()) { - cookieManager.cookieStore.removeAll() - finish() + if (userManager.setUserAsActive(user).blockingGet()) { + cookieManager.cookieStore.removeAll() + finish() + } + } + true } - } - true - } @SuppressLint("SourceLockedOrientationActivity") override fun onCreate(savedInstanceState: Bundle?) { @@ -137,11 +141,12 @@ class SwitchAccountActivity : BaseActivity() { if (!isAccountImport) { for (user in userManager.users.blockingGet()) { if (!user.current) { - val userId: String? = if (user.userId != null) { - user.userId - } else { - user.username - } + val userId: String? = + if (user.userId != null) { + user.userId + } else { + user.username + } participant = Participant() participant.actorType = Participant.ActorType.USERS participant.actorId = userId diff --git a/app/src/main/java/com/nextcloud/talk/account/WebViewLoginActivity.kt b/app/src/main/java/com/nextcloud/talk/account/WebViewLoginActivity.kt index 00c9232137e..227f921845f 100644 --- a/app/src/main/java/com/nextcloud/talk/account/WebViewLoginActivity.kt +++ b/app/src/main/java/com/nextcloud/talk/account/WebViewLoginActivity.kt @@ -99,13 +99,14 @@ class WebViewLoginActivity : BaseActivity() { private var automatedLoginAttempted = false private var webViewFidoBridge: WebViewFidoBridge? = null - private val onBackPressedCallback = object : OnBackPressedCallback(true) { - override fun handleOnBackPressed() { - val intent = Intent(context, MainActivity::class.java) - intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP) - startActivity(intent) + private val onBackPressedCallback = + object : OnBackPressedCallback(true) { + override fun handleOnBackPressed() { + val intent = Intent(context, MainActivity::class.java) + intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP) + startActivity(intent) + } } - } private val webLoginUserAgent: String get() = ( Build.MANUFACTURER.substring(0, 1).toUpperCase(Locale.getDefault()) + @@ -167,155 +168,163 @@ class WebViewLoginActivity : BaseActivity() { android.webkit.CookieManager.getInstance().removeAllCookies(null) val headers: MutableMap = HashMap() headers["OCS-APIRequest"] = "true" - binding.webview.webViewClient = object : WebViewClient() { - private var basePageLoaded = false - override fun shouldInterceptRequest(view: WebView, request: WebResourceRequest): WebResourceResponse? { - webViewFidoBridge?.delegateShouldInterceptRequest(view, request) - return super.shouldInterceptRequest(view, request) - } + binding.webview.webViewClient = + object : WebViewClient() { + private var basePageLoaded = false - override fun onPageStarted(view: WebView, url: String, favicon: Bitmap?) { - super.onPageStarted(view, url, favicon) - webViewFidoBridge?.delegateOnPageStarted(view, url, favicon) - } - - @Deprecated("Use shouldOverrideUrlLoading(WebView view, WebResourceRequest request)") - override fun shouldOverrideUrlLoading(view: WebView, url: String): Boolean { - if (url.startsWith(assembledPrefix!!)) { - parseAndLoginFromWebView(url) - return true + override fun shouldInterceptRequest(view: WebView, request: WebResourceRequest): WebResourceResponse? { + webViewFidoBridge?.delegateShouldInterceptRequest(view, request) + return super.shouldInterceptRequest(view, request) } - return false - } - - @Suppress("Detekt.TooGenericExceptionCaught") - override fun onPageFinished(view: WebView, url: String) { - loginStep++ - if (!basePageLoaded) { - binding.progressBar.visibility = View.GONE - binding.webview.visibility = View.VISIBLE - basePageLoaded = true + override fun onPageStarted(view: WebView, url: String, favicon: Bitmap?) { + super.onPageStarted(view, url, favicon) + webViewFidoBridge?.delegateOnPageStarted(view, url, favicon) } - if (!TextUtils.isEmpty(username)) { - if (loginStep == 1) { - binding.webview.loadUrl( - "javascript: {document.getElementsByClassName('login')[0].click(); };" - ) - } else if (!automatedLoginAttempted) { - automatedLoginAttempted = true - if (TextUtils.isEmpty(password)) { - binding.webview.loadUrl( - "javascript:var justStore = document.getElementById('user').value = '$username';" - ) - } else { - binding.webview.loadUrl( - "javascript: {" + - "document.getElementById('user').value = '" + username + "';" + - "document.getElementById('password').value = '" + password + "';" + - "document.getElementById('submit').click(); };" - ) - } + + @Deprecated("Use shouldOverrideUrlLoading(WebView view, WebResourceRequest request)") + override fun shouldOverrideUrlLoading(view: WebView, url: String): Boolean { + if (url.startsWith(assembledPrefix!!)) { + parseAndLoginFromWebView(url) + return true } + return false } - super.onPageFinished(view, url) - } + @Suppress("Detekt.TooGenericExceptionCaught") + override fun onPageFinished(view: WebView, url: String) { + loginStep++ + if (!basePageLoaded) { + binding.progressBar.visibility = View.GONE + binding.webview.visibility = View.VISIBLE - override fun onReceivedClientCertRequest(view: WebView, request: ClientCertRequest) { - val user = userManager.currentUser.blockingGet() - var alias: String? = null - if (!reauthorizeAccount) { - alias = appPreferences.temporaryClientCertAlias - } - if (TextUtils.isEmpty(alias) && user != null) { - alias = user.clientCertificate - } - if (!TextUtils.isEmpty(alias)) { - val finalAlias = alias - Thread { - try { - val privateKey = KeyChain.getPrivateKey(applicationContext, finalAlias!!) - val certificates = KeyChain.getCertificateChain( - applicationContext, - finalAlias + basePageLoaded = true + } + if (!TextUtils.isEmpty(username)) { + if (loginStep == 1) { + binding.webview.loadUrl( + "javascript: {document.getElementsByClassName('login')[0].click(); };" ) - if (privateKey != null && certificates != null) { - request.proceed(privateKey, certificates) + } else if (!automatedLoginAttempted) { + automatedLoginAttempted = true + if (TextUtils.isEmpty(password)) { + binding.webview.loadUrl( + "javascript:var justStore = document.getElementById('user').value = '$username';" + ) } else { - request.cancel() + binding.webview.loadUrl( + "javascript: {" + + "document.getElementById('user').value = '" + username + "';" + + "document.getElementById('password').value = '" + password + "';" + + "document.getElementById('submit').click(); };" + ) } - } catch (e: KeyChainException) { - request.cancel() - } catch (e: InterruptedException) { - request.cancel() } - }.start() - } else { - KeyChain.choosePrivateKeyAlias( - this@WebViewLoginActivity, - { chosenAlias: String? -> - if (chosenAlias != null) { - appPreferences!!.temporaryClientCertAlias = chosenAlias - Thread { - var privateKey: PrivateKey? = null - try { - privateKey = KeyChain.getPrivateKey(applicationContext, chosenAlias) - val certificates = KeyChain.getCertificateChain( + } + + super.onPageFinished(view, url) + } + + override fun onReceivedClientCertRequest(view: WebView, request: ClientCertRequest) { + val user = userManager.currentUser.blockingGet() + var alias: String? = null + if (!reauthorizeAccount) { + alias = appPreferences.temporaryClientCertAlias + } + if (TextUtils.isEmpty(alias) && user != null) { + alias = user.clientCertificate + } + if (!TextUtils.isEmpty(alias)) { + val finalAlias = alias + Thread { + try { + val privateKey = KeyChain.getPrivateKey(applicationContext, finalAlias!!) + val certificates = + KeyChain + .getCertificateChain( applicationContext, - chosenAlias + finalAlias ) - if (privateKey != null && certificates != null) { - request.proceed(privateKey, certificates) - } else { - request.cancel() - } - } catch (e: KeyChainException) { - request.cancel() - } catch (e: InterruptedException) { - request.cancel() - } - }.start() - } else { + if (privateKey != null && certificates != null) { + request.proceed(privateKey, certificates) + } else { + request.cancel() + } + } catch (e: KeyChainException) { + request.cancel() + } catch (e: InterruptedException) { request.cancel() } - }, - arrayOf("RSA", "EC"), - null, - request.host, - request.port, - null - ) + }.start() + } else { + KeyChain.choosePrivateKeyAlias( + this@WebViewLoginActivity, + { chosenAlias: String? -> + if (chosenAlias != null) { + appPreferences!!.temporaryClientCertAlias = chosenAlias + Thread { + var privateKey: PrivateKey? = null + try { + privateKey = + KeyChain + .getPrivateKey(applicationContext, chosenAlias) + val certificates = + KeyChain + .getCertificateChain( + applicationContext, + chosenAlias + ) + if (privateKey != null && certificates != null) { + request.proceed(privateKey, certificates) + } else { + request.cancel() + } + } catch (e: KeyChainException) { + request.cancel() + } catch (e: InterruptedException) { + request.cancel() + } + }.start() + } else { + request.cancel() + } + }, + arrayOf("RSA", "EC"), + null, + request.host, + request.port, + null + ) + } } - } - @Suppress("Detekt.TooGenericExceptionCaught") - override fun onReceivedSslError(view: WebView, handler: SslErrorHandler, error: SslError) { - try { - val sslCertificate = error.certificate - val f: Field = sslCertificate.javaClass.getDeclaredField("mX509Certificate") - f.isAccessible = true - val cert = f[sslCertificate] as X509Certificate - if (cert == null) { - handler.cancel() - } else { - try { - trustManager.checkServerTrusted(arrayOf(cert), "generic") - handler.proceed() - } catch (exception: CertificateException) { - eventBus.post(CertificateEvent(cert, trustManager, handler)) + @Suppress("Detekt.TooGenericExceptionCaught") + override fun onReceivedSslError(view: WebView, handler: SslErrorHandler, error: SslError) { + try { + val sslCertificate = error.certificate + val f: Field = sslCertificate.javaClass.getDeclaredField("mX509Certificate") + f.isAccessible = true + val cert = f[sslCertificate] as X509Certificate + if (cert == null) { + handler.cancel() + } else { + try { + trustManager.checkServerTrusted(arrayOf(cert), "generic") + handler.proceed() + } catch (exception: CertificateException) { + eventBus.post(CertificateEvent(cert, trustManager, handler)) + } } + } catch (exception: Exception) { + handler.cancel() } - } catch (exception: Exception) { - handler.cancel() } - } - @Deprecated("Deprecated in super implementation") - override fun onReceivedError(view: WebView, errorCode: Int, description: String, failingUrl: String) { - super.onReceivedError(view, errorCode, description, failingUrl) + @Deprecated("Deprecated in super implementation") + override fun onReceivedError(view: WebView, errorCode: Int, description: String, failingUrl: String) { + super.onReceivedError(view, errorCode, description, failingUrl) + } } - } binding.webview.loadUrl("$baseUrl/index.php/login/flow", headers) } @@ -417,17 +426,23 @@ class WebViewLoginActivity : BaseActivity() { } for (value in values) { if (value.startsWith("user" + LOGIN_URL_DATA_KEY_VALUE_SEPARATOR)) { - loginData.username = URLDecoder.decode( - value.substring(("user" + LOGIN_URL_DATA_KEY_VALUE_SEPARATOR).length) - ) + loginData.username = + URLDecoder + .decode( + value.substring(("user" + LOGIN_URL_DATA_KEY_VALUE_SEPARATOR).length) + ) } else if (value.startsWith("password" + LOGIN_URL_DATA_KEY_VALUE_SEPARATOR)) { - loginData.token = URLDecoder.decode( - value.substring(("password" + LOGIN_URL_DATA_KEY_VALUE_SEPARATOR).length) - ) + loginData.token = + URLDecoder + .decode( + value.substring(("password" + LOGIN_URL_DATA_KEY_VALUE_SEPARATOR).length) + ) } else if (value.startsWith("server" + LOGIN_URL_DATA_KEY_VALUE_SEPARATOR)) { - loginData.serverUrl = URLDecoder.decode( - value.substring(("server" + LOGIN_URL_DATA_KEY_VALUE_SEPARATOR).length) - ) + loginData.serverUrl = + URLDecoder + .decode( + value.substring(("server" + LOGIN_URL_DATA_KEY_VALUE_SEPARATOR).length) + ) } else { return null } diff --git a/app/src/main/java/com/nextcloud/talk/activities/BaseActivity.kt b/app/src/main/java/com/nextcloud/talk/activities/BaseActivity.kt index 6efc1e8a16a..7b528fc1eda 100644 --- a/app/src/main/java/com/nextcloud/talk/activities/BaseActivity.kt +++ b/app/src/main/java/com/nextcloud/talk/activities/BaseActivity.kt @@ -61,7 +61,9 @@ import javax.inject.Inject @AutoInjector(NextcloudTalkApplication::class) open class BaseActivity : AppCompatActivity() { enum class AppBarLayoutType { - TOOLBAR, SEARCH_BAR, EMPTY + TOOLBAR, + SEARCH_BAR, + EMPTY } @Inject @@ -196,27 +198,31 @@ open class BaseActivity : AppCompatActivity() { } @SuppressLint("StringFormatMatches") - val dialogText = String.format( - resources.getString(R.string.nc_certificate_dialog_text), - issuedBy, - issuedFor, - validFrom, - validUntil - ) - - val dialogBuilder = MaterialAlertDialogBuilder(this).setIcon( - viewThemeUtils.dialog.colorMaterialAlertDialogIcon( - context, - R.drawable.ic_security_white_24dp - ) - ).setTitle(R.string.nc_certificate_dialog_title) - .setMessage(dialogText) - .setPositiveButton(R.string.nc_yes) { _, _ -> - trustManager.addCertInTrustStore(cert) - sslErrorHandler?.proceed() - }.setNegativeButton(R.string.nc_no) { _, _ -> - sslErrorHandler?.cancel() - } + val dialogText = + String + .format( + resources.getString(R.string.nc_certificate_dialog_text), + issuedBy, + issuedFor, + validFrom, + validUntil + ) + + val dialogBuilder = + MaterialAlertDialogBuilder(this) + .setIcon( + viewThemeUtils.dialog.colorMaterialAlertDialogIcon( + context, + R.drawable.ic_security_white_24dp + ) + ).setTitle(R.string.nc_certificate_dialog_title) + .setMessage(dialogText) + .setPositiveButton(R.string.nc_yes) { _, _ -> + trustManager.addCertInTrustStore(cert) + sslErrorHandler?.proceed() + }.setNegativeButton(R.string.nc_no) { _, _ -> + sslErrorHandler?.cancel() + } viewThemeUtils.dialog.colorMaterialAlertDialogBackground(context, dialogBuilder) 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 8a6c92466d7..292cd0cee52 100644 --- a/app/src/main/java/com/nextcloud/talk/activities/CallActivity.kt +++ b/app/src/main/java/com/nextcloud/talk/activities/CallActivity.kt @@ -268,35 +268,38 @@ class CallActivity : CallBaseActivity() { private val screenParticipantDisplayItemManagersHandler = Handler(Looper.getMainLooper()) private val callParticipantEventDisplayers: MutableMap = HashMap() private val callParticipantEventDisplayersHandler = Handler(Looper.getMainLooper()) - private val callParticipantListObserver: CallParticipantList.Observer = object : CallParticipantList.Observer { - override fun onCallParticipantsChanged( - joined: Collection, - updated: Collection, - left: Collection, - unchanged: Collection - ) { - handleCallParticipantsChanged(joined, updated, left, unchanged) - } + private val callParticipantListObserver: CallParticipantList.Observer = + object : CallParticipantList.Observer { + override fun onCallParticipantsChanged( + joined: Collection, + updated: Collection, + left: Collection, + unchanged: Collection + ) { + handleCallParticipantsChanged(joined, updated, left, unchanged) + } - override fun onCallEndedForAll() { - Log.d(TAG, "A moderator ended the call for all.") - hangup(true) + override fun onCallEndedForAll() { + Log.d(TAG, "A moderator ended the call for all.") + hangup(true) + } } - } private var callParticipantList: CallParticipantList? = null private var switchToRoomToken = "" private var isBreakoutRoom = false - private val localParticipantMessageListener = LocalParticipantMessageListener { token -> - switchToRoomToken = token - hangup(true) - } - private val offerMessageListener = OfferMessageListener { sessionId, roomType, sdp, nick -> - getOrCreatePeerConnectionWrapperForSessionIdAndType( - sessionId, - roomType, - false - ) - } + private val localParticipantMessageListener = + LocalParticipantMessageListener { token -> + switchToRoomToken = token + hangup(true) + } + private val offerMessageListener = + OfferMessageListener { sessionId, roomType, sdp, nick -> + getOrCreatePeerConnectionWrapperForSessionIdAndType( + sessionId, + roomType, + false + ) + } private var externalSignalingServer: ExternalSignalingServer? = null private var webSocketClient: WebSocketInstance? = null private var webSocketConnectionHelper: WebSocketConnectionHelper? = null @@ -314,54 +317,55 @@ class CallActivity : CallBaseActivity() { private var moreCallActionsDialog: MoreCallActionsDialog? = null private var elapsedSeconds: Long = 0 - private var requestPermissionLauncher = registerForActivityResult( - ActivityResultContracts.RequestMultiplePermissions() - ) { permissionMap: Map -> - val rationaleList: MutableList = ArrayList() - val audioPermission = permissionMap[Manifest.permission.RECORD_AUDIO] - if (audioPermission != null) { - if (java.lang.Boolean.TRUE == audioPermission) { - if (!microphoneOn) { - onMicrophoneClick() + private var requestPermissionLauncher = + registerForActivityResult( + ActivityResultContracts.RequestMultiplePermissions() + ) { permissionMap: Map -> + val rationaleList: MutableList = ArrayList() + val audioPermission = permissionMap[Manifest.permission.RECORD_AUDIO] + if (audioPermission != null) { + if (java.lang.Boolean.TRUE == audioPermission) { + if (!microphoneOn) { + onMicrophoneClick() + } + } else { + rationaleList.add(resources.getString(R.string.nc_microphone_permission_hint)) } - } else { - rationaleList.add(resources.getString(R.string.nc_microphone_permission_hint)) } - } - val cameraPermission = permissionMap[Manifest.permission.CAMERA] - if (cameraPermission != null) { - if (java.lang.Boolean.TRUE == cameraPermission) { - if (!videoOn) { - onCameraClick() - } - if (cameraEnumerator!!.deviceNames.isEmpty()) { - binding!!.cameraButton.visibility = View.GONE - } - if (cameraEnumerator!!.deviceNames.size > 1) { - binding!!.switchSelfVideoButton.visibility = View.VISIBLE + val cameraPermission = permissionMap[Manifest.permission.CAMERA] + if (cameraPermission != null) { + if (java.lang.Boolean.TRUE == cameraPermission) { + if (!videoOn) { + onCameraClick() + } + if (cameraEnumerator!!.deviceNames.isEmpty()) { + binding!!.cameraButton.visibility = View.GONE + } + if (cameraEnumerator!!.deviceNames.size > 1) { + binding!!.switchSelfVideoButton.visibility = View.VISIBLE + } + } else { + rationaleList.add(resources.getString(R.string.nc_camera_permission_hint)) } - } else { - rationaleList.add(resources.getString(R.string.nc_camera_permission_hint)) } - } - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) { - val bluetoothPermission = permissionMap[Manifest.permission.BLUETOOTH_CONNECT] - if (bluetoothPermission != null) { - if (java.lang.Boolean.TRUE == bluetoothPermission) { - enableBluetoothManager() - } else { - // Only ask for bluetooth when already asking to grant microphone or camera access. Asking - // for bluetooth solely is not important enough here and would most likely annoy the user. - if (rationaleList.isNotEmpty()) { - rationaleList.add(resources.getString(R.string.nc_bluetooth_permission_hint)) + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) { + val bluetoothPermission = permissionMap[Manifest.permission.BLUETOOTH_CONNECT] + if (bluetoothPermission != null) { + if (java.lang.Boolean.TRUE == bluetoothPermission) { + enableBluetoothManager() + } else { + // Only ask for bluetooth when already asking to grant microphone or camera access. Asking + // for bluetooth solely is not important enough here and would most likely annoy the user. + if (rationaleList.isNotEmpty()) { + rationaleList.add(resources.getString(R.string.nc_bluetooth_permission_hint)) + } } } } + if (rationaleList.isNotEmpty()) { + showRationaleDialogForSettings(rationaleList) + } } - if (rationaleList.isNotEmpty()) { - showRationaleDialogForSettings(rationaleList) - } - } private var canPublishAudioStream = false private var canPublishVideoStream = false private var isModerator = false @@ -371,11 +375,12 @@ class CallActivity : CallBaseActivity() { private lateinit var micInputAudioRecorder: AudioRecord private var micInputAudioRecordThread: Thread? = null private var isMicInputAudioThreadRunning: Boolean = false - private val bufferSize = AudioRecord.getMinBufferSize( - SAMPLE_RATE, - AudioFormat.CHANNEL_IN_MONO, - AudioFormat.ENCODING_PCM_16BIT - ) + private val bufferSize = + AudioRecord.getMinBufferSize( + SAMPLE_RATE, + AudioFormat.CHANNEL_IN_MONO, + AudioFormat.ENCODING_PCM_16BIT + ) private var recordingConsentGiven = false @@ -432,9 +437,10 @@ class CallActivity : CallBaseActivity() { } } } - callRecordingViewModel = ViewModelProvider(this, viewModelFactory).get( - CallRecordingViewModel::class.java - ) + callRecordingViewModel = + ViewModelProvider(this, viewModelFactory).get( + CallRecordingViewModel::class.java + ) callRecordingViewModel!!.setData(roomToken!!) callRecordingViewModel!!.setRecordingState(extras.getInt(KEY_RECORDING_STATE)) callRecordingViewModel!!.viewState.observe(this) { viewState: CallRecordingViewModel.ViewState? -> @@ -458,15 +464,16 @@ class CallActivity : CallBaseActivity() { } } else if (viewState is RecordingConfirmStopState) { if (isAllowedToStartOrStopRecording) { - val dialogBuilder = MaterialAlertDialogBuilder(this) - .setTitle(R.string.record_stop_confirm_title) - .setMessage(R.string.record_stop_confirm_message) - .setPositiveButton(R.string.record_stop_description) { _: DialogInterface?, _: Int -> - callRecordingViewModel!!.stopRecording() - } - .setNegativeButton(R.string.nc_common_dismiss) { _: DialogInterface?, _: Int -> - callRecordingViewModel!!.dismissStopRecording() - } + val dialogBuilder = + MaterialAlertDialogBuilder(this) + .setTitle(R.string.record_stop_confirm_title) + .setMessage(R.string.record_stop_confirm_message) + .setPositiveButton(R.string.record_stop_description) { _: DialogInterface?, _: Int -> + callRecordingViewModel!!.stopRecording() + } + .setNegativeButton(R.string.nc_common_dismiss) { _: DialogInterface?, _: Int -> + callRecordingViewModel!!.dismissStopRecording() + } viewThemeUtils.dialog.colorMaterialAlertDialogBackground(this, dialogBuilder) val dialog = dialogBuilder.show() viewThemeUtils.platform.colorTextButtons( @@ -491,10 +498,13 @@ class CallActivity : CallBaseActivity() { } initClickListeners() binding!!.microphoneButton.setOnTouchListener(MicrophoneButtonTouchListener()) - pulseAnimation = PulseAnimation.create().with(binding!!.microphoneButton) - .setDuration(310) - .setRepeatCount(PulseAnimation.INFINITE) - .setRepeatMode(PulseAnimation.REVERSE) + pulseAnimation = + PulseAnimation + .create() + .with(binding!!.microphoneButton) + .setDuration(310) + .setRepeatCount(PulseAnimation.INFINITE) + .setRepeatMode(PulseAnimation.REVERSE) basicInitialization() callParticipants = HashMap() participantDisplayItems = HashMap() @@ -507,18 +517,19 @@ class CallActivity : CallBaseActivity() { private fun checkRecordingConsentAndInitiateCall() { fun askForRecordingConsent() { - val materialAlertDialogBuilder = MaterialAlertDialogBuilder(this) - .setTitle(R.string.recording_consent_title) - .setMessage(R.string.recording_consent_description) - .setCancelable(false) - .setPositiveButton(R.string.nc_yes) { _, _ -> - recordingConsentGiven = true - initiateCall() - } - .setNegativeButton(R.string.nc_no) { _, _ -> - recordingConsentGiven = false - hangup(true) - } + val materialAlertDialogBuilder = + MaterialAlertDialogBuilder(this) + .setTitle(R.string.recording_consent_title) + .setMessage(R.string.recording_consent_description) + .setCancelable(false) + .setPositiveButton(R.string.nc_yes) { _, _ -> + recordingConsentGiven = true + initiateCall() + } + .setNegativeButton(R.string.nc_no) { _, _ -> + recordingConsentGiven = false + hangup(true) + } viewThemeUtils.dialog.colorMaterialAlertDialogBackground(this, materialAlertDialogBuilder) val dialog = materialAlertDialogBuilder.show() @@ -532,37 +543,41 @@ class CallActivity : CallBaseActivity() { CapabilitiesUtilNew.RECORDING_CONSENT_NOT_REQUIRED -> initiateCall() CapabilitiesUtilNew.RECORDING_CONSENT_REQUIRED -> askForRecordingConsent() CapabilitiesUtilNew.RECORDING_CONSENT_DEPEND_ON_CONVERSATION -> { - val getRoomApiVersion = ApiUtils.getConversationApiVersion( - conversationUser, - intArrayOf(ApiUtils.APIv4, 1) - ) + val getRoomApiVersion = + ApiUtils + .getConversationApiVersion( + conversationUser, + intArrayOf(ApiUtils.APIv4, 1) + ) ncApi!!.getRoom(credentials, ApiUtils.getUrlForRoom(getRoomApiVersion, baseUrl, roomToken)) .retry(API_RETRIES) .subscribeOn(Schedulers.io()) .observeOn(AndroidSchedulers.mainThread()) - .subscribe(object : Observer { - override fun onSubscribe(d: Disposable) { - // unused atm - } + .subscribe( + object : Observer { + override fun onSubscribe(d: Disposable) { + // unused atm + } - override fun onNext(roomOverall: RoomOverall) { - val conversation = roomOverall.ocs!!.data - if (conversation?.recordingConsentRequired == 1) { - askForRecordingConsent() - } else { - initiateCall() + override fun onNext(roomOverall: RoomOverall) { + val conversation = roomOverall.ocs!!.data + if (conversation?.recordingConsentRequired == 1) { + askForRecordingConsent() + } else { + initiateCall() + } } - } - override fun onError(e: Throwable) { - Log.e(TAG, "Failed to get room", e) - Snackbar.make(binding!!.root, R.string.nc_common_error_sorry, Snackbar.LENGTH_LONG).show() - } + override fun onError(e: Throwable) { + Log.e(TAG, "Failed to get room", e) + Snackbar.make(binding!!.root, R.string.nc_common_error_sorry, Snackbar.LENGTH_LONG) + .show() + } - override fun onComplete() { - // unused atm - } - }) + override fun onComplete() { + // unused atm + } + }) } } } @@ -722,11 +737,12 @@ class CallActivity : CallBaseActivity() { } catch (t: Throwable) { Log.w(TAG, "Camera2Enumerator threw an error", t) } - cameraEnumerator = if (camera2EnumeratorIsSupported) { - Camera2Enumerator(this) - } else { - Camera1Enumerator(MagicWebRTCUtils.shouldEnableVideoHardwareAcceleration()) - } + cameraEnumerator = + if (camera2EnumeratorIsSupported) { + Camera2Enumerator(this) + } else { + Camera1Enumerator(MagicWebRTCUtils.shouldEnableVideoHardwareAcceleration()) + } } private fun basicInitialization() { @@ -735,19 +751,22 @@ class CallActivity : CallBaseActivity() { // Create a new PeerConnectionFactory instance. val options = PeerConnectionFactory.Options() - val defaultVideoEncoderFactory = DefaultVideoEncoderFactory( - rootEglBase!!.eglBaseContext, - true, - true - ) + val defaultVideoEncoderFactory = + DefaultVideoEncoderFactory( + rootEglBase!!.eglBaseContext, + true, + true + ) val defaultVideoDecoderFactory = DefaultVideoDecoderFactory( rootEglBase!!.eglBaseContext ) - peerConnectionFactory = PeerConnectionFactory.builder() - .setOptions(options) - .setVideoEncoderFactory(defaultVideoEncoderFactory) - .setVideoDecoderFactory(defaultVideoDecoderFactory) - .createPeerConnectionFactory() + peerConnectionFactory = + PeerConnectionFactory + .builder() + .setOptions(options) + .setVideoEncoderFactory(defaultVideoEncoderFactory) + .setVideoDecoderFactory(defaultVideoDecoderFactory) + .createPeerConnectionFactory() // Create MediaConstraints - Will be useful for specifying video and audio constraints. audioConstraints = MediaConstraints() 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 ce631df93f7..1b58c371b9e 100644 --- a/app/src/main/java/com/nextcloud/talk/activities/MainActivity.kt +++ b/app/src/main/java/com/nextcloud/talk/activities/MainActivity.kt @@ -74,22 +74,27 @@ class MainActivity : BaseActivity(), ActionBarProvider { @Inject lateinit var userManager: UserManager - private val onBackPressedCallback = object : OnBackPressedCallback(true) { - override fun handleOnBackPressed() { - finish() + private val onBackPressedCallback = + object : OnBackPressedCallback(true) { + override fun handleOnBackPressed() { + finish() + } } - } override fun onCreate(savedInstanceState: Bundle?) { Log.d(TAG, "onCreate: Activity: " + System.identityHashCode(this).toString()) super.onCreate(savedInstanceState) - ProcessLifecycleOwner.get().lifecycle.addObserver(object : DefaultLifecycleObserver { - override fun onStart(owner: LifecycleOwner) { - lockScreenIfConditionsApply() - } - }) + ProcessLifecycleOwner + .get() + .lifecycle + .addObserver( + object : DefaultLifecycleObserver { + override fun onStart(owner: LifecycleOwner) { + lockScreenIfConditionsApply() + } + }) // Set the default theme to replace the launch screen theme. setTheme(R.style.AppTheme) @@ -274,33 +279,34 @@ class MainActivity : BaseActivity(), ActionBarProvider { appPreferences.isDbRoomMigrated = true } - userManager.users.subscribe(object : SingleObserver> { - override fun onSubscribe(d: Disposable) { - // unused atm - } + userManager.users.subscribe( + object : SingleObserver> { + override fun onSubscribe(d: Disposable) { + // unused atm + } - override fun onSuccess(users: List) { - if (users.isNotEmpty()) { - ClosedInterfaceImpl().setUpPushTokenRegistration() - runOnUiThread { - openConversationList() - } - } else { - runOnUiThread { - launchServerSelection() + override fun onSuccess(users: List) { + if (users.isNotEmpty()) { + ClosedInterfaceImpl().setUpPushTokenRegistration() + runOnUiThread { + openConversationList() + } + } else { + runOnUiThread { + launchServerSelection() + } } } - } - override fun onError(e: Throwable) { - Log.e(TAG, "Error loading existing users", e) - Toast.makeText( - context, - context.resources.getString(R.string.nc_common_error_sorry), - Toast.LENGTH_SHORT - ).show() - } - }) + override fun onError(e: Throwable) { + Log.e(TAG, "Error loading existing users", e) + Toast.makeText( + context, + context.resources.getString(R.string.nc_common_error_sorry), + Toast.LENGTH_SHORT + ).show() + } + }) } } diff --git a/app/src/main/java/com/nextcloud/talk/adapters/GeocodingAdapter.kt b/app/src/main/java/com/nextcloud/talk/adapters/GeocodingAdapter.kt index 603c73537e0..8e922b359b4 100644 --- a/app/src/main/java/com/nextcloud/talk/adapters/GeocodingAdapter.kt +++ b/app/src/main/java/com/nextcloud/talk/adapters/GeocodingAdapter.kt @@ -32,7 +32,6 @@ import fr.dudie.nominatim.model.Address class GeocodingAdapter(private val context: Context, private var dataSource: List
) : RecyclerView.Adapter() { - interface OnItemClickListener { fun onItemClick(position: Int) } @@ -44,11 +43,15 @@ class GeocodingAdapter(private val context: Context, private var dataSource: Lis } private var listener: OnItemClickListener? = null + fun setOnItemClickListener(listener: OnItemClickListener) { this.listener = listener } - override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder { + override fun onCreateViewHolder( + parent: ViewGroup, + viewType: Int + ): ViewHolder { val inflater = LayoutInflater.from(context) val view = inflater.inflate(R.layout.geocoding_item, parent, false) return ViewHolder(view) diff --git a/app/src/main/java/com/nextcloud/talk/adapters/PredefinedStatusViewHolder.kt b/app/src/main/java/com/nextcloud/talk/adapters/PredefinedStatusViewHolder.kt index 7ddd83be4ff..b71ba3f2e18 100644 --- a/app/src/main/java/com/nextcloud/talk/adapters/PredefinedStatusViewHolder.kt +++ b/app/src/main/java/com/nextcloud/talk/adapters/PredefinedStatusViewHolder.kt @@ -41,11 +41,13 @@ class PredefinedStatusViewHolder(private val binding: PredefinedStatusBinding) : } else { val clearAt = status.clearAt!! if (clearAt.type.equals("period")) { - binding.clearAt.text = DisplayUtils.getRelativeTimestamp( - context, - System.currentTimeMillis() + clearAt.time.toInt() * ONE_SECOND_IN_MILLIS, - true - ) + binding.clearAt.text = + DisplayUtils + .getRelativeTimestamp( + context, + System.currentTimeMillis() + clearAt.time.toInt() * ONE_SECOND_IN_MILLIS, + true + ) } else { // end-of if (clearAt.time.equals("day")) { 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 4906bb7bcfa..5bbd505a65a 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 @@ -102,7 +102,10 @@ class ConversationItem( return VIEW_TYPE } - override fun createViewHolder(view: View, adapter: FlexibleAdapter?>?): ConversationItemViewHolder { + override fun createViewHolder( + view: View, + adapter: FlexibleAdapter?>? + ): ConversationItemViewHolder { return ConversationItemViewHolder(view, adapter) } diff --git a/app/src/main/java/com/nextcloud/talk/adapters/items/MessageResultItem.kt b/app/src/main/java/com/nextcloud/talk/adapters/items/MessageResultItem.kt index c9384ce2aae..457738e5b73 100644 --- a/app/src/main/java/com/nextcloud/talk/adapters/items/MessageResultItem.kt +++ b/app/src/main/java/com/nextcloud/talk/adapters/items/MessageResultItem.kt @@ -39,7 +39,7 @@ import eu.davidea.flexibleadapter.items.IFlexible import eu.davidea.flexibleadapter.items.ISectionable import eu.davidea.viewholders.FlexibleViewHolder -data class MessageResultItem constructor( +data class MessageResultItem( private val context: Context, private val currentUser: User, val messageEntry: SearchMessageEntry, @@ -49,7 +49,6 @@ data class MessageResultItem constructor( AbstractFlexibleItem(), IFilterable, ISectionable { - class ViewHolder(view: View, adapter: FlexibleAdapter<*>) : FlexibleViewHolder(view, adapter) { var binding: RvItemSearchMessageBinding @@ -95,10 +94,11 @@ data class MessageResultItem constructor( const val VIEW_TYPE = FlexibleItemViewType.MESSAGE_RESULT_ITEM } - override fun getHeader(): GenericTextHeaderItem = MessagesTextHeaderItem(context, viewThemeUtils) - .apply { - isHidden = showHeader // FlexibleAdapter needs this hack for some reason - } + override fun getHeader(): GenericTextHeaderItem = + MessagesTextHeaderItem(context, viewThemeUtils) + .apply { + isHidden = showHeader // FlexibleAdapter needs this hack for some reason + } override fun setHeader(header: GenericTextHeaderItem?) { // nothing, header is always the same diff --git a/app/src/main/java/com/nextcloud/talk/adapters/messages/CallStartedMessageInterface.kt b/app/src/main/java/com/nextcloud/talk/adapters/messages/CallStartedMessageInterface.kt index 9d39d987c5b..a71e19943ad 100644 --- a/app/src/main/java/com/nextcloud/talk/adapters/messages/CallStartedMessageInterface.kt +++ b/app/src/main/java/com/nextcloud/talk/adapters/messages/CallStartedMessageInterface.kt @@ -21,5 +21,6 @@ package com.nextcloud.talk.adapters.messages interface CallStartedMessageInterface { fun joinAudioCall() + fun joinVideoCall() } 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 c6154ddaa14..bf32e5e0278 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 @@ -75,34 +75,39 @@ class CallStartedViewHolder(incomingView: View, payload: Any) : private fun setUpAvatarProfile(message: ChatMessage) { val user = userManager.currentUser.blockingGet() - val url: String = if (message.actorType == "guests" || message.actorType == "guest") { - ApiUtils.getUrlForGuestAvatar( - user!!.baseUrl, - message.actorDisplayName, - true - ) - } else { - ApiUtils.getUrlForAvatar(user!!.baseUrl, message.actorDisplayName, false) - } - - val imageRequest: ImageRequest = ImageRequest.Builder(context) - .data(url) - .crossfade(true) - .transformations(CircleCropTransformation()) - .target(object : Target { - override fun onStart(placeholder: Drawable?) { - // unused atm - } - - override fun onError(error: Drawable?) { - // unused atm - } - - override fun onSuccess(result: Drawable) { - binding.callAuthorChip.chipIcon = result - } - }) - .build() + val url: String = + if (message.actorType == "guests" || message.actorType == "guest") { + ApiUtils.getUrlForGuestAvatar( + user!!.baseUrl, + message.actorDisplayName, + true + ) + } else { + ApiUtils.getUrlForAvatar(user!!.baseUrl, message.actorDisplayName, false) + } + + val imageRequest: ImageRequest = + ImageRequest + .Builder(context) + .data(url) + .crossfade(true) + .transformations(CircleCropTransformation()) + .target( + object : Target { + override fun onStart(placeholder: Drawable?) { + // unused atm + } + + override fun onError(error: Drawable?) { + // unused atm + } + + override fun onSuccess(result: Drawable) { + binding.callAuthorChip.chipIcon = result + } + } + ) + .build() imageLoader(context).enqueue(imageRequest) } diff --git a/app/src/main/java/com/nextcloud/talk/adapters/messages/CommonMessageInterface.kt b/app/src/main/java/com/nextcloud/talk/adapters/messages/CommonMessageInterface.kt index 34116479bfa..d334cc25612 100644 --- a/app/src/main/java/com/nextcloud/talk/adapters/messages/CommonMessageInterface.kt +++ b/app/src/main/java/com/nextcloud/talk/adapters/messages/CommonMessageInterface.kt @@ -4,6 +4,8 @@ import com.nextcloud.talk.models.json.chat.ChatMessage interface CommonMessageInterface { fun onLongClickReactions(chatMessage: ChatMessage) + fun onClickReaction(chatMessage: ChatMessage, emoji: String) + fun onOpenMessageActionsDialog(chatMessage: ChatMessage) } 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 60ea4bb88cb..62f37ec69a4 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 @@ -81,20 +81,24 @@ class IncomingLinkPreviewMessageViewHolder(incomingView: View, payload: Any) : sharedApplication!!.componentApplication.inject(this) binding.messageTime.text = dateUtils.getLocalTimeStringFromTimestamp(message.timestamp) - var processedMessageText = messageUtils.enrichChatMessageText( - binding.messageText.context, - message, - true, - viewThemeUtils - ) + var processedMessageText = + messageUtils + .enrichChatMessageText( + binding.messageText.context, + message, + true, + viewThemeUtils + ) - processedMessageText = messageUtils.processMessageParameters( - binding.messageText.context, - viewThemeUtils, - processedMessageText!!, - message, - itemView - ) + processedMessageText = + messageUtils + .processMessageParameters( + binding.messageText.context, + viewThemeUtils, + processedMessageText!!, + message, + itemView + ) binding.messageText.text = processedMessageText @@ -195,13 +199,14 @@ class IncomingLinkPreviewMessageViewHolder(incomingView: View, payload: Any) : } binding.messageQuote.quotedMessageAuthor.text = parentChatMessage.actorDisplayName ?: context.getText(R.string.nc_nick_guest) - binding.messageQuote.quotedMessage.text = messageUtils - .enrichChatReplyMessageText( - binding.messageQuote.quotedMessage.context, - parentChatMessage, - true, - viewThemeUtils - ) + binding.messageQuote.quotedMessage.text = + messageUtils + .enrichChatReplyMessageText( + binding.messageQuote.quotedMessage.context, + parentChatMessage, + true, + viewThemeUtils + ) binding.messageQuote.quotedMessageAuthor .setTextColor(ContextCompat.getColor(context, R.color.textColorMaxContrast)) 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 a88a1de93a6..b3d5e3283c1 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 @@ -180,13 +180,14 @@ class IncomingLocationMessageViewHolder(incomingView: View, payload: Any) : } binding.messageQuote.quotedMessageAuthor.text = parentChatMessage.actorDisplayName ?: context.getText(R.string.nc_nick_guest) - binding.messageQuote.quotedMessage.text = messageUtils - .enrichChatReplyMessageText( - binding.messageQuote.quotedMessage.context, - parentChatMessage, - true, - viewThemeUtils - ) + binding.messageQuote.quotedMessage.text = + messageUtils + .enrichChatReplyMessageText( + binding.messageQuote.quotedMessage.context, + parentChatMessage, + true, + viewThemeUtils + ) binding.messageQuote.quotedMessageAuthor .setTextColor(context.resources.getColor(R.color.textColorMaxContrast, null)) @@ -219,18 +220,19 @@ class IncomingLocationMessageViewHolder(incomingView: View, payload: Any) : binding.webview.settings.javaScriptEnabled = true - binding.webview.webViewClient = object : WebViewClient() { - @Deprecated("Use shouldOverrideUrlLoading(WebView view, WebResourceRequest request)") - override fun shouldOverrideUrlLoading(view: WebView?, url: String?): Boolean { - return if (url != null && UriUtils.hasHttpProtocolPrefixed(url) - ) { - view?.context?.startActivity(Intent(Intent.ACTION_VIEW, Uri.parse(url))) - true - } else { - false + binding.webview.webViewClient = + object : WebViewClient() { + @Deprecated("Use shouldOverrideUrlLoading(WebView view, WebResourceRequest request)") + override fun shouldOverrideUrlLoading(view: WebView?, url: String?): Boolean { + return if (url != null && UriUtils.hasHttpProtocolPrefixed(url) + ) { + view?.context?.startActivity(Intent(Intent.ACTION_VIEW, Uri.parse(url))) + true + } else { + false + } } } - } val urlStringBuffer = StringBuffer("file:///android_asset/leafletMapMessagePreview.html") urlStringBuffer.append( @@ -246,15 +248,16 @@ class IncomingLocationMessageViewHolder(incomingView: View, payload: Any) : binding.webview.loadUrl(urlStringBuffer.toString()) - binding.webview.setOnTouchListener(object : View.OnTouchListener { - override fun onTouch(v: View?, event: MotionEvent?): Boolean { - when (event?.action) { - MotionEvent.ACTION_UP -> openGeoLink() - } + binding.webview.setOnTouchListener( + object : View.OnTouchListener { + override fun onTouch(v: View?, event: MotionEvent?): Boolean { + when (event?.action) { + MotionEvent.ACTION_UP -> openGeoLink() + } - return v?.onTouchEvent(event) ?: true - } - }) + return v?.onTouchEvent(event) ?: true + } + }) } private fun openGeoLink() { 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 14867564693..c6fe536314a 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 @@ -49,7 +49,6 @@ import javax.inject.Inject @AutoInjector(NextcloudTalkApplication::class) class IncomingPollMessageViewHolder(incomingView: View, payload: Any) : MessageHolders.IncomingTextMessageViewHolder(incomingView, payload) { - private val binding: ItemCustomIncomingPollMessageBinding = ItemCustomIncomingPollMessageBinding.bind(itemView) @Inject @@ -132,7 +131,9 @@ class IncomingPollMessageViewHolder(incomingView: View, payload: Any) : val isOwnerOrModerator = (payload as? MessagePayload)!!.isOwnerOrModerator ?: false binding.bubble.setOnClickListener { - val pollVoteDialog = PollMainDialogFragment.newInstance( + val pollVoteDialog = + PollMainDialogFragment + .newInstance( message.activeUser!!, roomToken, isOwnerOrModerator, @@ -203,7 +204,8 @@ class IncomingPollMessageViewHolder(incomingView: View, payload: Any) : } binding.messageQuote.quotedMessageAuthor.text = parentChatMessage.actorDisplayName ?: context.getText(R.string.nc_nick_guest) - binding.messageQuote.quotedMessage.text = messageUtils + binding.messageQuote.quotedMessage.text = + messageUtils .enrichChatReplyMessageText( binding.messageQuote.quotedMessage.context, parentChatMessage, 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 5b07dbbd5ba..9aeef171bf9 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 @@ -85,20 +85,24 @@ class IncomingTextMessageViewHolder(itemView: View, payload: Any) : var textSize = context.resources!!.getDimension(R.dimen.chat_text_size) - var processedMessageText = messageUtils.enrichChatMessageText( - binding.messageText.context, - message, - true, - viewThemeUtils - ) + var processedMessageText = + messageUtils + .enrichChatMessageText( + binding.messageText.context, + message, + true, + viewThemeUtils + ) - processedMessageText = messageUtils.processMessageParameters( - binding.messageText.context, - viewThemeUtils, - processedMessageText!!, - message, - itemView - ) + processedMessageText = + messageUtils + .processMessageParameters( + binding.messageText.context, + viewThemeUtils, + processedMessageText!!, + message, + itemView + ) val messageParameters = message.messageParameters if ( @@ -197,19 +201,21 @@ class IncomingTextMessageViewHolder(itemView: View, payload: Any) : } ?: run { binding.messageQuote.quotedMessageImage.visibility = View.GONE } - binding.messageQuote.quotedMessageAuthor.text = if (parentChatMessage.actorDisplayName.isNullOrEmpty()) { - context.getText(R.string.nc_nick_guest) - } else { - parentChatMessage.actorDisplayName - } + binding.messageQuote.quotedMessageAuthor.text = + if (parentChatMessage.actorDisplayName.isNullOrEmpty()) { + context.getText(R.string.nc_nick_guest) + } else { + parentChatMessage.actorDisplayName + } - binding.messageQuote.quotedMessage.text = messageUtils - .enrichChatReplyMessageText( - binding.messageQuote.quotedMessage.context, - parentChatMessage, - true, - viewThemeUtils - ) + binding.messageQuote.quotedMessage.text = + messageUtils + .enrichChatReplyMessageText( + binding.messageQuote.quotedMessage.context, + parentChatMessage, + true, + viewThemeUtils + ) if (parentChatMessage.actorId?.equals(message.activeUser!!.userId) == true) { viewThemeUtils.platform.colorViewBackground(binding.messageQuote.quoteColoredView, ColorRole.PRIMARY) 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 bb90eb72c4d..7b2a2b04ff1 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 @@ -115,10 +115,12 @@ class IncomingVoiceMessageViewHolder(incomingView: View, payload: Any) : if (message.isPlayingVoiceMessage) { showPlayButton() - binding.playPauseBtn.icon = ContextCompat.getDrawable( - context!!, - R.drawable.ic_baseline_pause_voice_message_24 - ) + binding.playPauseBtn.icon = + ContextCompat + .getDrawable( + context!!, + R.drawable.ic_baseline_pause_voice_message_24 + ) val d = message.voiceMessageDuration.toLong() val t = message.voiceMessagePlayedSeconds.toLong() binding.voiceMessageDuration.text = android.text.format.DateUtils.formatElapsedTime(d - t) @@ -126,10 +128,12 @@ class IncomingVoiceMessageViewHolder(incomingView: View, payload: Any) : binding.seekbar.progress = message.voiceMessageSeekbarProgress } else { binding.playPauseBtn.visibility = View.VISIBLE - binding.playPauseBtn.icon = ContextCompat.getDrawable( - context!!, - R.drawable.ic_baseline_play_arrow_voice_message_24 - ) + binding.playPauseBtn.icon = + ContextCompat + .getDrawable( + context!!, + R.drawable.ic_baseline_play_arrow_voice_message_24 + ) } if (message.isDownloadingVoiceMessage) { @@ -145,31 +149,34 @@ class IncomingVoiceMessageViewHolder(incomingView: View, payload: Any) : if (message.resetVoiceMessage) { binding.playPauseBtn.visibility = View.VISIBLE - binding.playPauseBtn.icon = ContextCompat.getDrawable( - context!!, - R.drawable.ic_baseline_play_arrow_voice_message_24 - ) + binding.playPauseBtn.icon = + ContextCompat + .getDrawable( + context!!, + R.drawable.ic_baseline_play_arrow_voice_message_24 + ) binding.seekbar.progress = SEEKBAR_START message.resetVoiceMessage = false message.voiceMessagePlayedSeconds = 0 binding.voiceMessageDuration.visibility = View.INVISIBLE } - binding.seekbar.setOnSeekBarChangeListener(object : SeekBar.OnSeekBarChangeListener { - override fun onStopTrackingTouch(seekBar: SeekBar) { - // unused atm - } + binding.seekbar.setOnSeekBarChangeListener( + object : SeekBar.OnSeekBarChangeListener { + override fun onStopTrackingTouch(seekBar: SeekBar) { + // unused atm + } - override fun onStartTrackingTouch(seekBar: SeekBar) { - // unused atm - } + override fun onStartTrackingTouch(seekBar: SeekBar) { + // unused atm + } - override fun onProgressChanged(seekBar: SeekBar, progress: Int, fromUser: Boolean) { - if (fromUser) { - voiceMessageInterface.updateMediaPlayerProgressBySlider(message, progress) + override fun onProgressChanged(seekBar: SeekBar, progress: Int, fromUser: Boolean) { + if (fromUser) { + voiceMessageInterface.updateMediaPlayerProgressBySlider(message, progress) + } } - } - }) + }) Reaction().showReactions( message, @@ -219,14 +226,17 @@ class IncomingVoiceMessageViewHolder(incomingView: View, payload: Any) : Log.d(TAG, "WorkInfo.State.RUNNING in ViewHolder") showVoiceMessageLoading() } + WorkInfo.State.SUCCEEDED -> { Log.d(TAG, "WorkInfo.State.SUCCEEDED in ViewHolder") showPlayButton() } + WorkInfo.State.FAILED -> { Log.d(TAG, "WorkInfo.State.FAILED in ViewHolder") showPlayButton() } + else -> { } } @@ -274,14 +284,16 @@ class IncomingVoiceMessageViewHolder(incomingView: View, payload: Any) : } else if (message.actorType == "bots" && message.actorId == "changelog") { binding.messageUserAvatar.loadChangelogBotAvatar() } else if (message.actorType == "bots") { - val drawable = TextDrawable.builder() - .beginConfig() - .bold() - .endConfig() - .buildRound( - ">", - ResourcesCompat.getColor(context!!.resources, R.color.black, null) - ) + val drawable = + TextDrawable + .builder() + .beginConfig() + .bold() + .endConfig() + .buildRound( + ">", + ResourcesCompat.getColor(context!!.resources, R.color.black, null) + ) binding.messageUserAvatar.visibility = View.VISIBLE binding.messageUserAvatar.setImageDrawable(drawable) } @@ -306,8 +318,10 @@ class IncomingVoiceMessageViewHolder(incomingView: View, payload: Any) : } ?: run { binding.messageQuote.quotedMessageImage.visibility = View.GONE } - binding.messageQuote.quotedMessageAuthor.text = parentChatMessage.actorDisplayName - ?: context!!.getText(R.string.nc_nick_guest) + binding.messageQuote.quotedMessageAuthor.text = + parentChatMessage + .actorDisplayName + ?: context!!.getText(R.string.nc_nick_guest) binding.messageQuote.quotedMessage.text = messageUtils .enrichChatReplyMessageText( binding.messageQuote.quotedMessage.context, 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 f73524cf3cd..18b0a4cf01b 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 @@ -37,12 +37,7 @@ import io.reactivex.disposables.Disposable import io.reactivex.schedulers.Schedulers class LinkPreview { - fun showLink( - message: ChatMessage, - ncApi: NcApi, - binding: ReferenceInsideMessageBinding, - context: Context - ) { + fun showLink(message: ChatMessage, ncApi: NcApi, binding: ReferenceInsideMessageBinding, context: Context) { binding.referenceName.text = "" binding.referenceDescription.text = "" binding.referenceLink.text = "" 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 7a1f9aa81b9..e8d5cd2d533 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 @@ -47,7 +47,6 @@ import javax.inject.Inject @AutoInjector(NextcloudTalkApplication::class) class OutcomingLinkPreviewMessageViewHolder(outcomingView: View, payload: Any) : MessageHolders.OutcomingTextMessageViewHolder(outcomingView, payload) { - private val binding: ItemCustomOutcomingLinkPreviewMessageBinding = ItemCustomOutcomingLinkPreviewMessageBinding.bind(itemView) @@ -84,13 +83,15 @@ class OutcomingLinkPreviewMessageViewHolder(outcomingView: View, payload: Any) : colorizeMessageBubble(message) var processedMessageText = messageUtils.enrichChatMessageText(binding.messageText.context, message, false, viewThemeUtils) - processedMessageText = messageUtils.processMessageParameters( - binding.messageText.context, - viewThemeUtils, - processedMessageText!!, - message, - itemView - ) + processedMessageText = + messageUtils + .processMessageParameters( + binding.messageText.context, + viewThemeUtils, + processedMessageText!!, + message, + itemView + ) binding.messageText.text = processedMessageText diff --git a/app/src/main/java/com/nextcloud/talk/application/NextcloudTalkApplication.kt b/app/src/main/java/com/nextcloud/talk/application/NextcloudTalkApplication.kt index 56974740942..f0d43febd94 100644 --- a/app/src/main/java/com/nextcloud/talk/application/NextcloudTalkApplication.kt +++ b/app/src/main/java/com/nextcloud/talk/application/NextcloudTalkApplication.kt @@ -117,17 +117,18 @@ class NextcloudTalkApplication : MultiDexApplication(), LifecycleObserver { lateinit var okHttpClient: OkHttpClient //endregion - val hook: SQLiteDatabaseHook = object : SQLiteDatabaseHook { - override fun preKey(database: SQLiteDatabase) { - // unused atm - } + val hook: SQLiteDatabaseHook = + object : SQLiteDatabaseHook { + override fun preKey(database: SQLiteDatabase) { + // unused atm + } - override fun postKey(database: SQLiteDatabase) { - Log.i("TalkApplication", "DB cipher_migrate START") - database.rawExecSQL("PRAGMA cipher_migrate;") - Log.i("TalkApplication", "DB cipher_migrate END") + override fun postKey(database: SQLiteDatabase) { + Log.i("TalkApplication", "DB cipher_migrate START") + database.rawExecSQL("PRAGMA cipher_migrate;") + Log.i("TalkApplication", "DB cipher_migrate END") + } } - } //region private methods private fun initializeWebRtc() { @@ -157,9 +158,11 @@ class NextcloudTalkApplication : MultiDexApplication(), LifecycleObserver { sharedApplication = this val securityKeyManager = SecurityKeyManager.getInstance() - val securityKeyConfig = SecurityKeyManagerConfig.Builder() - .setEnableDebugLogging(BuildConfig.DEBUG) - .build() + val securityKeyConfig = + SecurityKeyManagerConfig + .Builder() + .setEnableDebugLogging(BuildConfig.DEBUG) + .build() securityKeyManager.init(this, securityKeyConfig) initializeWebRtc() @@ -201,11 +204,13 @@ class NextcloudTalkApplication : MultiDexApplication(), LifecycleObserver { .then(websocketConnectionsWorker) .enqueue() - val periodicCapabilitiesUpdateWork = PeriodicWorkRequest.Builder( - CapabilitiesWorker::class.java, - HALF_DAY, - TimeUnit.HOURS - ).build() + val periodicCapabilitiesUpdateWork = + PeriodicWorkRequest + .Builder( + CapabilitiesWorker::class.java, + HALF_DAY, + TimeUnit.HOURS + ).build() WorkManager.getInstance(applicationContext).enqueueUniquePeriodicWork( "DailyCapabilitiesUpdateWork", ExistingPeriodicWorkPolicy.REPLACE, @@ -221,13 +226,15 @@ class NextcloudTalkApplication : MultiDexApplication(), LifecycleObserver { //region Protected methods protected fun buildComponent() { - componentApplication = DaggerNextcloudTalkApplicationComponent.builder() - .busModule(BusModule()) - .contextModule(ContextModule(applicationContext)) - .databaseModule(DatabaseModule()) - .restModule(RestModule(applicationContext)) - .arbitraryStorageModule(ArbitraryStorageModule()) - .build() + componentApplication = + DaggerNextcloudTalkApplicationComponent + .builder() + .busModule(BusModule()) + .contextModule(ContextModule(applicationContext)) + .databaseModule(DatabaseModule()) + .restModule(RestModule(applicationContext)) + .arbitraryStorageModule(ArbitraryStorageModule()) + .build() } override fun attachBaseContext(base: Context) { @@ -236,20 +243,22 @@ class NextcloudTalkApplication : MultiDexApplication(), LifecycleObserver { } private fun buildDefaultImageLoader(): ImageLoader { - val imageLoaderBuilder = ImageLoader.Builder(applicationContext) - .memoryCache { - // Use 50% of the application's available memory. - MemoryCache.Builder(applicationContext).maxSizePercent(FIFTY_PERCENT).build() - } - .crossfade(true) // Show a short crossfade when loading images from network or disk into an ImageView. - .components { - if (SDK_INT >= P) { - add(ImageDecoderDecoder.Factory()) - } else { - add(GifDecoder.Factory()) + val imageLoaderBuilder = + ImageLoader + .Builder(applicationContext) + .memoryCache { + // Use 50% of the application's available memory. + MemoryCache.Builder(applicationContext).maxSizePercent(FIFTY_PERCENT).build() + } + .crossfade(true) // Show a short crossfade when loading images from network or disk into an ImageView. + .components { + if (SDK_INT >= P) { + add(ImageDecoderDecoder.Factory()) + } else { + add(GifDecoder.Factory()) + } + add(SvgDecoder.Factory()) } - add(SvgDecoder.Factory()) - } if (BuildConfig.DEBUG) { imageLoaderBuilder.logger(DebugLogger()) diff --git a/app/src/main/java/com/nextcloud/talk/bottomsheet/items/BasicListItemWithImage.kt b/app/src/main/java/com/nextcloud/talk/bottomsheet/items/BasicListItemWithImage.kt index 247494f0ba6..9eb9d1ca67a 100644 --- a/app/src/main/java/com/nextcloud/talk/bottomsheet/items/BasicListItemWithImage.kt +++ b/app/src/main/java/com/nextcloud/talk/bottomsheet/items/BasicListItemWithImage.kt @@ -25,6 +25,7 @@ import androidx.annotation.DrawableRes interface ListItemWithImage { val title: String + fun populateIcon(imageView: ImageView) } @@ -32,7 +33,6 @@ data class BasicListItemWithImage( @DrawableRes val iconRes: Int, override val title: String ) : ListItemWithImage { - override fun populateIcon(imageView: ImageView) { imageView.setImageResource(iconRes) } diff --git a/app/src/main/java/com/nextcloud/talk/bottomsheet/items/BottomSheets.kt b/app/src/main/java/com/nextcloud/talk/bottomsheet/items/BottomSheets.kt index fa11981de08..92dafd5156e 100644 --- a/app/src/main/java/com/nextcloud/talk/bottomsheet/items/BottomSheets.kt +++ b/app/src/main/java/com/nextcloud/talk/bottomsheet/items/BottomSheets.kt @@ -46,7 +46,8 @@ fun MaterialDialog.listItemsWithImage( val layoutManager = LinearLayoutManager(windowContext) return customListAdapter( - adapter = ListIconDialogAdapter( + adapter = + ListIconDialogAdapter( dialog = this, items = items, disabledItems = disabledIndices, diff --git a/app/src/main/java/com/nextcloud/talk/bottomsheet/items/ListIconDialogAdapter.kt b/app/src/main/java/com/nextcloud/talk/bottomsheet/items/ListIconDialogAdapter.kt index ccae4ac4f17..ba526d9d63d 100644 --- a/app/src/main/java/com/nextcloud/talk/bottomsheet/items/ListIconDialogAdapter.kt +++ b/app/src/main/java/com/nextcloud/talk/bottomsheet/items/ListIconDialogAdapter.kt @@ -57,7 +57,6 @@ internal class ListIconDialogAdapter( private var waitForPositiveButton: Boolean, private var selection: ListItemListener ) : RecyclerView.Adapter(), DialogAdapter> { - private var disabledIndices: IntArray = disabledItems ?: IntArray(0) fun itemClicked(index: Int) { @@ -79,10 +78,7 @@ internal class ListIconDialogAdapter( } } - override fun onCreateViewHolder( - parent: ViewGroup, - viewType: Int - ): ListItemViewHolder { + override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ListItemViewHolder { val listItemView: View = parent.inflate(dialog.windowContext, R.layout.menu_item_sheet) val viewHolder = ListItemViewHolder( itemView = listItemView, diff --git a/app/src/main/java/com/nextcloud/talk/call/ReactionAnimator.kt b/app/src/main/java/com/nextcloud/talk/call/ReactionAnimator.kt index 746644b8c64..83212a68c5a 100644 --- a/app/src/main/java/com/nextcloud/talk/call/ReactionAnimator.kt +++ b/app/src/main/java/com/nextcloud/talk/call/ReactionAnimator.kt @@ -46,10 +46,7 @@ class ReactionAnimator( ) { private val reactionsList: MutableList = ArrayList() - fun addReaction( - emoji: String, - displayName: String - ) { + fun addReaction(emoji: String, displayName: String) { val callReaction = CallReaction(emoji, displayName) reactionsList.add(callReaction) @@ -182,6 +179,7 @@ class ReactionAnimator( private const val BOTTOM_MARGIN: Int = 5 } } + data class CallReaction( var emoji: String, var userName: String 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 5d88fdc6490..044d42451e3 100644 --- a/app/src/main/java/com/nextcloud/talk/callnotification/CallNotificationActivity.kt +++ b/app/src/main/java/com/nextcloud/talk/callnotification/CallNotificationActivity.kt @@ -147,14 +147,16 @@ class CallNotificationActivity : CallBaseActivity() { } private fun initObservers() { - val apiVersion = ApiUtils.getConversationApiVersion( - userBeingCalled, - intArrayOf( - ApiUtils.APIv4, - ApiUtils.APIv3, - 1 - ) - ) + val apiVersion = + ApiUtils + .getConversationApiVersion( + userBeingCalled, + intArrayOf( + ApiUtils.APIv4, + ApiUtils.APIv3, + 1 + ) + ) callNotificationViewModel.getRoomViewState.observe(this) { state -> when (state) { @@ -174,15 +176,16 @@ class CallNotificationActivity : CallBaseActivity() { } val notificationHandler = Handler(Looper.getMainLooper()) - notificationHandler.post(object : Runnable { - override fun run() { - if (NotificationUtils.isNotificationVisible(context, notificationTimestamp!!.toInt())) { - notificationHandler.postDelayed(this, ONE_SECOND) - } else { - finish() + notificationHandler.post( + object : Runnable { + override fun run() { + if (NotificationUtils.isNotificationVisible(context, notificationTimestamp!!.toInt())) { + notificationHandler.postDelayed(this, ONE_SECOND) + } else { + finish() + } } - } - }) + }) showAnswerControls() diff --git a/app/src/main/java/com/nextcloud/talk/callnotification/viewmodel/CallNotificationViewModel.kt b/app/src/main/java/com/nextcloud/talk/callnotification/viewmodel/CallNotificationViewModel.kt index 776daf6d8ae..34c63fbaec5 100644 --- a/app/src/main/java/com/nextcloud/talk/callnotification/viewmodel/CallNotificationViewModel.kt +++ b/app/src/main/java/com/nextcloud/talk/callnotification/viewmodel/CallNotificationViewModel.kt @@ -33,7 +33,9 @@ import io.reactivex.disposables.Disposable import io.reactivex.schedulers.Schedulers import javax.inject.Inject -class CallNotificationViewModel @Inject constructor(private val repository: ChatRepository) : +class CallNotificationViewModel +@Inject +constructor(private val repository: ChatRepository) : ViewModel() { sealed interface ViewState 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 2bf2c3d47db..087fb1e07a1 100644 --- a/app/src/main/java/com/nextcloud/talk/settings/SettingsActivity.kt +++ b/app/src/main/java/com/nextcloud/talk/settings/SettingsActivity.kt @@ -490,6 +490,7 @@ class SettingsActivity : BaseActivity() { ).show() restartApp() } + WorkInfo.State.FAILED, WorkInfo.State.CANCELLED -> { Toast.makeText( context, @@ -1098,7 +1099,8 @@ class SettingsActivity : BaseActivity() { dialog.setOnShowListener(object : OnShowListener { override fun onShow(dialogInterface: DialogInterface) { val button = dialog.getButton(AlertDialog.BUTTON_POSITIVE) - button.setOnClickListener(object : View.OnClickListener { + button.setOnClickListener( + object : View.OnClickListener { override fun onClick(view: View) { setPhoneNumber(phoneNumberInputLayout, dialog) } @@ -1123,7 +1125,8 @@ class SettingsActivity : BaseActivity() { phoneNumber ).subscribeOn(Schedulers.io()) .observeOn(AndroidSchedulers.mainThread()) - .subscribe(object : Observer { + .subscribe( + object : Observer { override fun onSubscribe(d: Disposable) { // unused atm } @@ -1140,6 +1143,7 @@ class SettingsActivity : BaseActivity() { Snackbar.LENGTH_LONG ).show() } + else -> { textInputLayout.helperText = context.resources.getString( R.string.nc_settings_phone_book_integration_phone_number_dialog_invalid @@ -1150,9 +1154,10 @@ class SettingsActivity : BaseActivity() { } override fun onError(e: Throwable) { - textInputLayout.helperText = context.resources.getString( - R.string.nc_settings_phone_book_integration_phone_number_dialog_invalid - ) + textInputLayout.helperText = + context.resources.getString( + R.string.nc_settings_phone_book_integration_phone_number_dialog_invalid + ) Log.e(TAG, "setPhoneNumber error", e) } @@ -1177,24 +1182,25 @@ class SettingsActivity : BaseActivity() { ) .subscribeOn(Schedulers.io()) .observeOn(AndroidSchedulers.mainThread()) - .subscribe(object : Observer { - override fun onSubscribe(d: Disposable) { - // unused atm - } - - override fun onNext(genericOverall: GenericOverall) { - // unused atm - } - - override fun onError(e: Throwable) { - appPreferences.setReadPrivacy(!newBoolean) - binding.settingsReadPrivacySwitch.isChecked = !newBoolean - } - - override fun onComplete() { - // unused atm - } - }) + .subscribe( + object : Observer { + override fun onSubscribe(d: Disposable) { + // unused atm + } + + override fun onNext(genericOverall: GenericOverall) { + // unused atm + } + + override fun onError(e: Throwable) { + appPreferences.setReadPrivacy(!newBoolean) + binding.settingsReadPrivacySwitch.isChecked = !newBoolean + } + + override fun onComplete() { + // unused atm + } + }) } } } @@ -1215,25 +1221,26 @@ class SettingsActivity : BaseActivity() { ) .subscribeOn(Schedulers.io()) .observeOn(AndroidSchedulers.mainThread()) - .subscribe(object : Observer { - override fun onSubscribe(d: Disposable) { - // unused atm - } - - override fun onNext(genericOverall: GenericOverall) { - loadCapabilitiesAndUpdateSettings() - Log.i(TAG, "onNext called typing status set") - } - - override fun onError(e: Throwable) { - appPreferences.typingStatus = !newBoolean - binding.settingsTypingStatusSwitch.isChecked = !newBoolean - } - - override fun onComplete() { - // unused atm - } - }) + .subscribe( + object : Observer { + override fun onSubscribe(d: Disposable) { + // unused atm + } + + override fun onNext(genericOverall: GenericOverall) { + loadCapabilitiesAndUpdateSettings() + Log.i(TAG, "onNext called typing status set") + } + + override fun onError(e: Throwable) { + appPreferences.typingStatus = !newBoolean + binding.settingsTypingStatusSwitch.isChecked = !newBoolean + } + + override fun onComplete() { + // unused atm + } + }) } } } diff --git a/app/src/main/java/com/nextcloud/talk/shareditems/activities/SharedItemsActivity.kt b/app/src/main/java/com/nextcloud/talk/shareditems/activities/SharedItemsActivity.kt index 3e47243c01a..94835aed527 100644 --- a/app/src/main/java/com/nextcloud/talk/shareditems/activities/SharedItemsActivity.kt +++ b/app/src/main/java/com/nextcloud/talk/shareditems/activities/SharedItemsActivity.kt @@ -99,14 +99,15 @@ class SharedItemsActivity : AppCompatActivity() { handleModelChange(state, user, roomToken, isUserConversationOwnerOrModerator) } - binding.imageRecycler.addOnScrollListener(object : RecyclerView.OnScrollListener() { - override fun onScrollStateChanged(recyclerView: RecyclerView, newState: Int) { - super.onScrollStateChanged(recyclerView, newState) - if (!recyclerView.canScrollVertically(1) && newState == RecyclerView.SCROLL_STATE_IDLE) { - viewModel.loadNextItems() + binding.imageRecycler.addOnScrollListener( + object : RecyclerView.OnScrollListener() { + override fun onScrollStateChanged(recyclerView: RecyclerView, newState: Int) { + super.onScrollStateChanged(recyclerView, newState) + if (!recyclerView.canScrollVertically(1) && newState == RecyclerView.SCROLL_STATE_IDLE) { + viewModel.loadNextItems() + } } - } - }) + }) viewModel.initialize(user, roomToken) } @@ -122,35 +123,41 @@ class SharedItemsActivity : AppCompatActivity() { is SharedItemsViewModel.LoadingItemsState, SharedItemsViewModel.InitialState -> { showLoading() } + is SharedItemsViewModel.NoSharedItemsState -> { showEmpty() } + is SharedItemsViewModel.LoadedState -> { val sharedMediaItems = state.items Log.d(TAG, "Items received: $sharedMediaItems") val showGrid = state.selectedType == SharedItemType.MEDIA - val layoutManager = if (showGrid) { - GridLayoutManager(this, SPAN_COUNT) - } else { - LinearLayoutManager(this, LinearLayoutManager.VERTICAL, false) - } - - val adapter = SharedItemsAdapter( - showGrid, - user, - roomToken, - isUserConversationOwnerOrModerator, - viewThemeUtils - ).apply { - items = sharedMediaItems.items - } + val layoutManager = + if (showGrid) { + GridLayoutManager(this, SPAN_COUNT) + } else { + LinearLayoutManager(this, LinearLayoutManager.VERTICAL, false) + } + + val adapter = + SharedItemsAdapter( + showGrid, + user, + roomToken, + isUserConversationOwnerOrModerator, + viewThemeUtils + ).apply { + items = sharedMediaItems.items + } binding.imageRecycler.adapter = adapter binding.imageRecycler.layoutManager = layoutManager } + is SharedItemsViewModel.TypesLoadedState -> { initTabs(state.types) } + else -> {} } @@ -239,15 +246,16 @@ class SharedItemsActivity : AppCompatActivity() { binding.sharedItemsTabs.addTab(tabOther) } - binding.sharedItemsTabs.addOnTabSelectedListener(object : TabLayout.OnTabSelectedListener { - override fun onTabSelected(tab: TabLayout.Tab) { - viewModel.initialLoadItems(tab.tag as SharedItemType) - } + binding.sharedItemsTabs.addOnTabSelectedListener( + object : TabLayout.OnTabSelectedListener { + override fun onTabSelected(tab: TabLayout.Tab) { + viewModel.initialLoadItems(tab.tag as SharedItemType) + } - override fun onTabUnselected(tab: TabLayout.Tab) = Unit + override fun onTabUnselected(tab: TabLayout.Tab) = Unit - override fun onTabReselected(tab: TabLayout.Tab) = Unit - }) + override fun onTabReselected(tab: TabLayout.Tab) = Unit + }) } override fun onOptionsItemSelected(item: MenuItem): Boolean { diff --git a/app/src/main/java/com/nextcloud/talk/shareditems/adapters/SharedItemsAdapter.kt b/app/src/main/java/com/nextcloud/talk/shareditems/adapters/SharedItemsAdapter.kt index 009e2a5977a..f3d7aa3bce5 100644 --- a/app/src/main/java/com/nextcloud/talk/shareditems/adapters/SharedItemsAdapter.kt +++ b/app/src/main/java/com/nextcloud/talk/shareditems/adapters/SharedItemsAdapter.kt @@ -87,13 +87,15 @@ class SharedItemsAdapter( } private fun showPoll(item: SharedItem, context: Context) { - val pollVoteDialog = PollMainDialogFragment.newInstance( - user, - roomToken, - isUserConversationOwnerOrModerator, - item.id, - item.name - ) + val pollVoteDialog = + PollMainDialogFragment + .newInstance( + user, + roomToken, + isUserConversationOwnerOrModerator, + item.id, + item.name + ) pollVoteDialog.show( (context as SharedItemsActivity).supportFragmentManager, TAG diff --git a/app/src/main/java/com/nextcloud/talk/shareditems/repositories/SharedItemsRepository.kt b/app/src/main/java/com/nextcloud/talk/shareditems/repositories/SharedItemsRepository.kt index 174afc7cafe..edf0a180a44 100644 --- a/app/src/main/java/com/nextcloud/talk/shareditems/repositories/SharedItemsRepository.kt +++ b/app/src/main/java/com/nextcloud/talk/shareditems/repositories/SharedItemsRepository.kt @@ -27,16 +27,9 @@ import com.nextcloud.talk.shareditems.model.SharedItems import io.reactivex.Observable interface SharedItemsRepository { - fun media( - parameters: Parameters, - type: SharedItemType - ): Observable? + fun media(parameters: Parameters, type: SharedItemType): Observable? - fun media( - parameters: Parameters, - type: SharedItemType, - lastKnownMessageId: Int? - ): Observable? + fun media(parameters: Parameters, type: SharedItemType, lastKnownMessageId: Int?): Observable? fun availableTypes(parameters: Parameters): Observable> 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 450a477c97b..e2b3eae6c97 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 @@ -45,12 +45,11 @@ import java.util.HashMap import java.util.Locale import javax.inject.Inject -class SharedItemsRepositoryImpl @Inject constructor(private val ncApi: NcApi, private val dateUtils: DateUtils) : +class SharedItemsRepositoryImpl +@Inject +constructor(private val ncApi: NcApi, private val dateUtils: DateUtils) : SharedItemsRepository { - override fun media( - parameters: SharedItemsRepository.Parameters, - type: SharedItemType - ): Observable? { + override fun media(parameters: SharedItemsRepository.Parameters, type: SharedItemType): Observable? { return media(parameters, type, null) } @@ -86,9 +85,10 @@ class SharedItemsRepositoryImpl @Inject constructor(private val ncApi: NcApi, pr if (mediaItems != null) { for (it in mediaItems) { val actorParameters = it.value.messageParameters!!["actor"]!! - val dateTime = dateUtils.getLocalDateTimeStringFromTimestamp( - it.value.timestamp * DateConstants.SECOND_DIVIDER - ) + val dateTime = + dateUtils.getLocalDateTimeStringFromTimestamp( + it.value.timestamp * DateConstants.SECOND_DIVIDER + ) if (it.value.messageParameters?.containsKey("file") == true) { val fileParameters = it.value.messageParameters!!["file"]!! @@ -96,19 +96,20 @@ class SharedItemsRepositoryImpl @Inject constructor(private val ncApi: NcApi, pr val previewAvailable = "yes".equals(fileParameters["preview-available"]!!, ignoreCase = true) - items[it.value.id] = SharedFileItem( - fileParameters["id"]!!, - fileParameters["name"]!!, - actorParameters["id"]!!, - actorParameters["name"]!!, - dateTime, - fileParameters["size"]!!.toLong(), - fileParameters["path"]!!, - fileParameters["link"]!!, - fileParameters["mimetype"]!!, - previewAvailable, - previewLink(fileParameters["id"], parameters.baseUrl) - ) + items[it.value.id] = + SharedFileItem( + fileParameters["id"]!!, + fileParameters["name"]!!, + actorParameters["id"]!!, + actorParameters["name"]!!, + dateTime, + fileParameters["size"]!!.toLong(), + fileParameters["path"]!!, + fileParameters["link"]!!, + fileParameters["mimetype"]!!, + previewAvailable, + previewLink(fileParameters["id"], parameters.baseUrl) + ) } else if (it.value.messageParameters?.containsKey("object") == true) { val objectParameters = it.value.messageParameters!!["object"]!! items[it.value.id] = itemFromObject(objectParameters, actorParameters, dateTime) @@ -137,45 +138,49 @@ class SharedItemsRepositoryImpl @Inject constructor(private val ncApi: NcApi, pr val returnValue: SharedItem when (objectParameters["type"]) { "talk-poll" -> { - returnValue = SharedPollItem( - objectParameters["id"]!!, - objectParameters["name"]!!, - actorParameters["id"]!!, - actorParameters["name"]!!, - dateTime - ) + returnValue = + SharedPollItem( + objectParameters["id"]!!, + objectParameters["name"]!!, + actorParameters["id"]!!, + actorParameters["name"]!!, + dateTime + ) } "geo-location" -> { - returnValue = SharedLocationItem( - objectParameters["id"]!!, - objectParameters["name"]!!, - actorParameters["id"]!!, - actorParameters["name"]!!, - dateTime, - Uri.parse(objectParameters["id"]!!.replace("geo:", "geo:0,0?z=11&q=")) - ) + returnValue = + SharedLocationItem( + objectParameters["id"]!!, + objectParameters["name"]!!, + actorParameters["id"]!!, + actorParameters["name"]!!, + dateTime, + Uri.parse(objectParameters["id"]!!.replace("geo:", "geo:0,0?z=11&q=")) + ) } "deck-card" -> { - returnValue = SharedDeckCardItem( - objectParameters["id"]!!, - objectParameters["name"]!!, - actorParameters["id"]!!, - actorParameters["name"]!!, - dateTime, - Uri.parse(objectParameters["link"]!!) - ) + returnValue = + SharedDeckCardItem( + objectParameters["id"]!!, + objectParameters["name"]!!, + actorParameters["id"]!!, + actorParameters["name"]!!, + dateTime, + Uri.parse(objectParameters["link"]!!) + ) } else -> { - returnValue = SharedOtherItem( - objectParameters["id"]!!, - objectParameters["name"]!!, - actorParameters["id"]!!, - actorParameters["name"]!!, - dateTime - ) + returnValue = + SharedOtherItem( + objectParameters["id"]!!, + objectParameters["name"]!!, + actorParameters["id"]!!, + actorParameters["name"]!!, + dateTime + ) } } return returnValue diff --git a/app/src/main/java/com/nextcloud/talk/shareditems/viewmodels/SharedItemsViewModel.kt b/app/src/main/java/com/nextcloud/talk/shareditems/viewmodels/SharedItemsViewModel.kt index 6ce35e89e3c..2214746a136 100644 --- a/app/src/main/java/com/nextcloud/talk/shareditems/viewmodels/SharedItemsViewModel.kt +++ b/app/src/main/java/com/nextcloud/talk/shareditems/viewmodels/SharedItemsViewModel.kt @@ -36,16 +36,22 @@ import io.reactivex.disposables.Disposable import io.reactivex.schedulers.Schedulers import javax.inject.Inject -class SharedItemsViewModel @Inject constructor( +class SharedItemsViewModel +@Inject +constructor( private val repository: SharedItemsRepository ) : ViewModel() { private lateinit var repositoryParameters: SharedItemsRepository.Parameters sealed interface ViewState + object InitialState : ViewState + object NoSharedItemsState : ViewState + open class TypesLoadedState(val types: Set, val selectedType: SharedItemType) : ViewState + class LoadingItemsState(types: Set, selectedType: SharedItemType) : TypesLoadedState(types, selectedType) @@ -57,50 +63,54 @@ class SharedItemsViewModel @Inject constructor( get() = _viewState fun initialize(user: User, roomToken: String) { - repositoryParameters = SharedItemsRepository.Parameters( - user.userId!!, - user.token!!, - user.baseUrl!!, - roomToken - ) + repositoryParameters = + SharedItemsRepository + .Parameters( + user.userId!!, + user.token!!, + user.baseUrl!!, + roomToken + ) loadAvailableTypes() } private fun loadAvailableTypes() { repository.availableTypes(repositoryParameters).subscribeOn(Schedulers.io()) ?.observeOn(AndroidSchedulers.mainThread()) - ?.subscribe(object : Observer> { + ?.subscribe( + object : Observer> { - var types: Set? = null + var types: Set? = null - override fun onSubscribe(d: Disposable) = Unit + override fun onSubscribe(d: Disposable) = Unit - override fun onNext(types: Set) { - this.types = types - } + override fun onNext(types: Set) { + this.types = types + } - override fun onError(e: Throwable) { - Log.d(TAG, "An error occurred: $e") - } + override fun onError(e: Throwable) { + Log.d(TAG, "An error occurred: $e") + } - override fun onComplete() { - val newTypes = this.types - if (newTypes.isNullOrEmpty()) { - this@SharedItemsViewModel._viewState.value = NoSharedItemsState - } else { - val selectedType = chooseInitialType(newTypes) - this@SharedItemsViewModel._viewState.value = - TypesLoadedState(newTypes, selectedType) - initialLoadItems(selectedType) + override fun onComplete() { + val newTypes = this.types + if (newTypes.isNullOrEmpty()) { + this@SharedItemsViewModel._viewState.value = NoSharedItemsState + } else { + val selectedType = chooseInitialType(newTypes) + this@SharedItemsViewModel._viewState.value = + TypesLoadedState(newTypes, selectedType) + initialLoadItems(selectedType) + } } - } - }) + }) } - private fun chooseInitialType(newTypes: Set): SharedItemType = when { - newTypes.contains(SharedItemType.MEDIA) -> SharedItemType.MEDIA - else -> newTypes.toList().first() - } + private fun chooseInitialType(newTypes: Set): SharedItemType = + when { + newTypes.contains(SharedItemType.MEDIA) -> SharedItemType.MEDIA + else -> newTypes.toList().first() + } fun initialLoadItems(type: SharedItemType) { val state = _viewState.value @@ -123,6 +133,7 @@ class SharedItemsViewModel @Inject constructor( ?.subscribe(SharedMediaItemsObserver()) } } + else -> return } } @@ -161,12 +172,14 @@ class SharedItemsViewModel @Inject constructor( private fun setCurrentState(items: SharedItems) { when (val state = this@SharedItemsViewModel._viewState.value) { is TypesLoadedState -> { - this@SharedItemsViewModel._viewState.value = LoadedState( - state.types, - state.selectedType, - items - ) + this@SharedItemsViewModel._viewState.value = + LoadedState( + state.types, + state.selectedType, + items + ) } + else -> return } } diff --git a/app/src/main/java/com/nextcloud/talk/translate/repositories/TranslateRepository.kt b/app/src/main/java/com/nextcloud/talk/translate/repositories/TranslateRepository.kt index e067fc06274..b8f6640a716 100644 --- a/app/src/main/java/com/nextcloud/talk/translate/repositories/TranslateRepository.kt +++ b/app/src/main/java/com/nextcloud/talk/translate/repositories/TranslateRepository.kt @@ -12,8 +12,5 @@ interface TranslateRepository { fromLanguage: String? ): Observable - fun getLanguages( - authorization: String, - url: String - ): Observable> + fun getLanguages(authorization: String, url: String): Observable> } diff --git a/app/src/main/java/com/nextcloud/talk/translate/repositories/TranslateRepositoryImpl.kt b/app/src/main/java/com/nextcloud/talk/translate/repositories/TranslateRepositoryImpl.kt index 9102b577259..ab28a7c74ab 100644 --- a/app/src/main/java/com/nextcloud/talk/translate/repositories/TranslateRepositoryImpl.kt +++ b/app/src/main/java/com/nextcloud/talk/translate/repositories/TranslateRepositoryImpl.kt @@ -5,7 +5,9 @@ import com.nextcloud.talk.translate.repositories.model.Language import io.reactivex.Observable import javax.inject.Inject -class TranslateRepositoryImpl @Inject constructor(private val ncApi: NcApi) : TranslateRepository { +class TranslateRepositoryImpl +@Inject +constructor(private val ncApi: NcApi) : TranslateRepository { override fun translateMessage( authorization: String, url: String, diff --git a/app/src/main/java/com/nextcloud/talk/translate/ui/TranslateActivity.kt b/app/src/main/java/com/nextcloud/talk/translate/ui/TranslateActivity.kt index c0bf087d012..98cadf94d00 100644 --- a/app/src/main/java/com/nextcloud/talk/translate/ui/TranslateActivity.kt +++ b/app/src/main/java/com/nextcloud/talk/translate/ui/TranslateActivity.kt @@ -116,6 +116,7 @@ class TranslateActivity : BaseActivity() { super.onResume() languages?.let { setItems() } } + override fun onSaveInstanceState(outState: Bundle) { outState.run { putString(BundleKeys.SAVED_TRANSLATED_MESSAGE, binding.translatedMessageTextview.text.toString()) @@ -128,10 +129,12 @@ class TranslateActivity : BaseActivity() { binding.copyTranslatedMessage.setOnClickListener { val clipboardManager = getSystemService(Context.CLIPBOARD_SERVICE) as ClipboardManager - val clipData = ClipData.newPlainText( - resources?.getString(R.string.nc_app_product_name), - binding.translatedMessageTextview.text?.toString() - ) + val clipData = + ClipData + .newPlainText( + resources?.getString(R.string.nc_app_product_name), + binding.translatedMessageTextview.text?.toString() + ) clipboardManager.setPrimaryClip(clipData) } } @@ -189,18 +192,19 @@ class TranslateActivity : BaseActivity() { } private fun showDialog(titleInt: Int, messageInt: Int) { - val dialogBuilder = MaterialAlertDialogBuilder(this@TranslateActivity) - .setIcon( - viewThemeUtils.dialog.colorMaterialAlertDialogIcon( - context, - R.drawable.ic_warning_white + val dialogBuilder = + MaterialAlertDialogBuilder(this@TranslateActivity) + .setIcon( + viewThemeUtils.dialog.colorMaterialAlertDialogIcon( + context, + R.drawable.ic_warning_white + ) ) - ) - .setTitle(titleInt) - .setMessage(messageInt) - .setPositiveButton(R.string.nc_ok) { dialog, _ -> - dialog.dismiss() - } + .setTitle(titleInt) + .setMessage(messageInt) + .setPositiveButton(R.string.nc_ok) { dialog, _ -> + dialog.dismiss() + } viewThemeUtils.dialog.colorMaterialAlertDialogBackground(context, dialogBuilder) @@ -236,17 +240,21 @@ class TranslateActivity : BaseActivity() { fillSpinners() val text = intent.extras!!.getString(BundleKeys.KEY_TRANSLATE_MESSAGE) - binding.fromLanguage.onItemClickListener = AdapterView.OnItemClickListener { parent, _, position, _ -> - val fromLabel: String = getISOFromLanguage(parent.getItemAtPosition(position).toString()) - val toLabel: String = getISOFromLanguage(binding.toLanguage.text.toString()) - viewModel.translateMessage(toLabel, fromLabel, text!!) - } + binding.fromLanguage.onItemClickListener = + AdapterView + .OnItemClickListener { parent, _, position, _ -> + val fromLabel: String = getISOFromLanguage(parent.getItemAtPosition(position).toString()) + val toLabel: String = getISOFromLanguage(binding.toLanguage.text.toString()) + viewModel.translateMessage(toLabel, fromLabel, text!!) + } - binding.toLanguage.onItemClickListener = AdapterView.OnItemClickListener { parent, _, position, _ -> - val toLabel: String = getISOFromLanguage(parent.getItemAtPosition(position).toString()) - val fromLabel: String = getISOFromLanguage(binding.fromLanguage.text.toString()) - viewModel.translateMessage(toLabel, fromLabel, text!!) - } + binding.toLanguage.onItemClickListener = + AdapterView + .OnItemClickListener { parent, _, position, _ -> + val toLabel: String = getISOFromLanguage(parent.getItemAtPosition(position).toString()) + val fromLabel: String = getISOFromLanguage(binding.fromLanguage.text.toString()) + viewModel.translateMessage(toLabel, fromLabel, text!!) + } } private fun fillSpinners() { 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 72839a3ae26..4d49b67f27e 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 @@ -15,13 +15,16 @@ import io.reactivex.disposables.Disposable import io.reactivex.schedulers.Schedulers import javax.inject.Inject -class TranslateViewModel @Inject constructor( +class TranslateViewModel +@Inject +constructor( private val repository: TranslateRepository, private val userManager: UserManager ) : ViewModel() { sealed interface ViewState data object StartState : ViewState + class TranslatedState(val msg: String) : ViewState class LanguagesRetrievedState(val list: List) : ViewState @@ -38,7 +41,12 @@ class TranslateViewModel @Inject constructor( val currentUser: User = userManager.currentUser.blockingGet() val authorization: String = ApiUtils.getCredentials(currentUser.username, currentUser.token) val url: String = ApiUtils.getUrlForTranslation(currentUser.baseUrl) - val calculatedFromLanguage = if (fromLanguage == null || fromLanguage == "") { null } else { fromLanguage } + val calculatedFromLanguage = + if (fromLanguage == null || fromLanguage == "") { + null + } else { + fromLanguage + } Log.i(TAG, "translateMessage Called") repository.translateMessage( authorization, @@ -60,25 +68,26 @@ class TranslateViewModel @Inject constructor( repository.getLanguages(authorization, url) .subscribeOn(Schedulers.io()) ?.observeOn(AndroidSchedulers.mainThread()) - ?.subscribe(object : Observer> { - override fun onSubscribe(d: Disposable) { - // unused atm - } - - override fun onError(e: Throwable) { - _viewState.value = LanguagesErrorState - Log.e(TAG, "Error while retrieving languages: $e") - } - - override fun onComplete() { - // unused atm - } - - override fun onNext(list: List) { - _viewState.value = LanguagesRetrievedState(list) - Log.d(TAG, "Languages retrieved: $list") - } - }) + ?.subscribe( + object : Observer> { + override fun onSubscribe(d: Disposable) { + // unused atm + } + + override fun onError(e: Throwable) { + _viewState.value = LanguagesErrorState + Log.e(TAG, "Error while retrieving languages: $e") + } + + override fun onComplete() { + // unused atm + } + + override fun onNext(list: List) { + _viewState.value = LanguagesRetrievedState(list) + Log.d(TAG, "Languages retrieved: $list") + } + }) } inner class TranslateObserver : Observer { @@ -99,6 +108,7 @@ class TranslateViewModel @Inject constructor( // nothing? } } + companion object { private val TAG = TranslateViewModel::class.simpleName } diff --git a/app/src/main/java/com/nextcloud/talk/ui/MicInputCloud.kt b/app/src/main/java/com/nextcloud/talk/ui/MicInputCloud.kt index cc1ce661c30..d7a2eb10d84 100644 --- a/app/src/main/java/com/nextcloud/talk/ui/MicInputCloud.kt +++ b/app/src/main/java/com/nextcloud/talk/ui/MicInputCloud.kt @@ -97,11 +97,13 @@ class MicInputCloud(context: Context, attrs: AttributeSet) : View(context, attrs private var centerX: Float = 0f private var centerY: Float = 0f - private val bottomCirclePaint = Paint(ANTI_ALIAS_FLAG).apply { - color = primaryColor - style = Paint.Style.FILL - alpha = DEFAULT_OPACITY - } + private val bottomCirclePaint = + Paint(ANTI_ALIAS_FLAG) + .apply { + color = primaryColor + style = Paint.Style.FILL + alpha = DEFAULT_OPACITY + } private val topCircleBounds = Rect(0, 0, 0, 0) private val iconBounds = topCircleBounds @@ -117,45 +119,51 @@ class MicInputCloud(context: Context, attrs: AttributeSet) : View(context, attrs } private fun createAnimators() { - ovalOneAnimator = ValueAnimator.ofInt( - o1h, - OVAL_ONE_DEFAULT_HEIGHT + ANIMATION_CAP, - o1h - ).apply { - duration = OVAL_ONE_ANIMATION_LENGTH - interpolator = LinearInterpolator() - repeatCount = ValueAnimator.INFINITE - addUpdateListener { valueAnimator -> - o1h = valueAnimator.animatedValue as Int - } - } + ovalOneAnimator = + ValueAnimator + .ofInt( + o1h, + OVAL_ONE_DEFAULT_HEIGHT + ANIMATION_CAP, + o1h + ).apply { + duration = OVAL_ONE_ANIMATION_LENGTH + interpolator = LinearInterpolator() + repeatCount = ValueAnimator.INFINITE + addUpdateListener { valueAnimator -> + o1h = valueAnimator.animatedValue as Int + } + } - ovalTwoAnimator = ValueAnimator.ofInt( - o2h, - OVAL_TWO_DEFAULT_HEIGHT + ANIMATION_CAP, - o2h - ).apply { - duration = OVAL_TWO_ANIMATION_LENGTH - interpolator = LinearInterpolator() - repeatCount = ValueAnimator.INFINITE - addUpdateListener { valueAnimator -> - o2h = valueAnimator.animatedValue as Int - } - } + ovalTwoAnimator = + ValueAnimator + .ofInt( + o2h, + OVAL_TWO_DEFAULT_HEIGHT + ANIMATION_CAP, + o2h + ).apply { + duration = OVAL_TWO_ANIMATION_LENGTH + interpolator = LinearInterpolator() + repeatCount = ValueAnimator.INFINITE + addUpdateListener { valueAnimator -> + o2h = valueAnimator.animatedValue as Int + } + } - ovalThreeAnimator = ValueAnimator.ofInt( - o3h, - OVAL_THREE_DEFAULT_HEIGHT + ANIMATION_CAP, - o3h - ).apply { - duration = OVAL_THREE_ANIMATION_LENGTH - interpolator = LinearInterpolator() - repeatCount = ValueAnimator.INFINITE - addUpdateListener { valueAnimator -> - o3h = valueAnimator.animatedValue as Int - invalidate() // needed to animate the other listeners as well - } - } + ovalThreeAnimator = + ValueAnimator + .ofInt( + o3h, + OVAL_THREE_DEFAULT_HEIGHT + ANIMATION_CAP, + o3h + ).apply { + duration = OVAL_THREE_ANIMATION_LENGTH + interpolator = LinearInterpolator() + repeatCount = ValueAnimator.INFINITE + addUpdateListener { valueAnimator -> + o3h = valueAnimator.animatedValue as Int + invalidate() // needed to animate the other listeners as well + } + } } private fun destroyAnimators() { @@ -259,33 +267,35 @@ class MicInputCloud(context: Context, attrs: AttributeSet) : View(context, attrs val heightMode = MeasureSpec.getMode(heightMeasureSpec) val heightSize = MeasureSpec.getSize(heightMeasureSpec) - val width: Int = when (widthMode) { - MeasureSpec.EXACTLY -> { - widthSize - } + val width: Int = + when (widthMode) { + MeasureSpec.EXACTLY -> { + widthSize + } - MeasureSpec.AT_MOST -> { - desiredWidth.coerceAtMost(widthSize) - } + MeasureSpec.AT_MOST -> { + desiredWidth.coerceAtMost(widthSize) + } - else -> { - desiredWidth + else -> { + desiredWidth + } } - } - val height: Int = when (heightMode) { - MeasureSpec.EXACTLY -> { - heightSize - } + val height: Int = + when (heightMode) { + MeasureSpec.EXACTLY -> { + heightSize + } - MeasureSpec.AT_MOST -> { - desiredHeight.coerceAtMost(heightSize) - } + MeasureSpec.AT_MOST -> { + desiredHeight.coerceAtMost(heightSize) + } - else -> { - desiredHeight + else -> { + desiredHeight + } } - } centerX = (width / 2).toFloat() centerY = (height / 2).toFloat() @@ -311,17 +321,18 @@ class MicInputCloud(context: Context, attrs: AttributeSet) : View(context, attrs } override fun performClick(): Boolean { - state = if (state == ViewState.PAUSED_STATE) { - ovalOneAnimator?.resume() - ovalTwoAnimator?.resume() - ovalThreeAnimator?.resume() - ViewState.PLAY_STATE - } else { - ovalOneAnimator?.pause() - ovalTwoAnimator?.pause() - ovalThreeAnimator?.pause() - ViewState.PAUSED_STATE - } + state = + if (state == ViewState.PAUSED_STATE) { + ovalOneAnimator?.resume() + ovalTwoAnimator?.resume() + ovalThreeAnimator?.resume() + ViewState.PLAY_STATE + } else { + ovalOneAnimator?.pause() + ovalTwoAnimator?.pause() + ovalThreeAnimator?.pause() + ViewState.PAUSED_STATE + } invalidate() return super.performClick() } diff --git a/app/src/main/java/com/nextcloud/talk/ui/WaveformSeekBar.kt b/app/src/main/java/com/nextcloud/talk/ui/WaveformSeekBar.kt index be54b4f9703..73db28fb1dd 100644 --- a/app/src/main/java/com/nextcloud/talk/ui/WaveformSeekBar.kt +++ b/app/src/main/java/com/nextcloud/talk/ui/WaveformSeekBar.kt @@ -54,7 +54,10 @@ class WaveformSeekBar : AppCompatSeekBar { init() } - fun setColors(@ColorInt p: Int, @ColorInt s: Int) { + fun setColors( + @ColorInt p: Int, + @ColorInt s: Int + ) { primary = p secondary = s invalidate() 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 cfc9839e20f..50d59303add 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,28 +57,29 @@ class ProfileBottomSheet(val ncApi: NcApi, val userModel: User) { ApiUtils.getCredentials(userModel.username, userModel.token), ApiUtils.getUrlForHoverCard(userModel.baseUrl, user) ).subscribeOn(Schedulers.io()).observeOn(AndroidSchedulers.mainThread()) - .subscribe(object : Observer { - override fun onSubscribe(d: Disposable) { - // unused atm - } - - override fun onNext(hoverCardOverall: HoverCardOverall) { - bottomSheet( - hoverCardOverall.ocs!!.data!!.actions!!, - hoverCardOverall.ocs!!.data!!.displayName!!, - user, - context - ) - } - - override fun onError(e: Throwable) { - Log.e(TAG, "Failed to get hover card for user $user", e) - } - - override fun onComplete() { - // unused atm - } - }) + .subscribe( + object : Observer { + override fun onSubscribe(d: Disposable) { + // unused atm + } + + override fun onNext(hoverCardOverall: HoverCardOverall) { + bottomSheet( + hoverCardOverall.ocs!!.data!!.actions!!, + hoverCardOverall.ocs!!.data!!.displayName!!, + user, + context + ) + } + + override fun onError(e: Throwable) { + Log.e(TAG, "Failed to get hover card for user $user", e) + } + + override fun onComplete() { + // unused atm + } + }) } @SuppressLint("CheckResult") @@ -104,11 +105,12 @@ class ProfileBottomSheet(val ncApi: NcApi, val userModel: User) { } private fun configureActionListItem(action: HoverCardAction): BasicListItemWithImage { - val drawable = when (AllowedAppIds.createFor(action)) { - PROFILE -> R.drawable.ic_user - EMAIL -> R.drawable.ic_email - SPREED -> R.drawable.ic_talk - } + val drawable = + when (AllowedAppIds.createFor(action)) { + PROFILE -> R.drawable.ic_user + EMAIL -> R.drawable.ic_email + SPREED -> R.drawable.ic_talk + } return BasicListItemWithImage( drawable, @@ -119,14 +121,16 @@ class ProfileBottomSheet(val ncApi: NcApi, val userModel: User) { private fun talkTo(userId: String, context: Context) { val apiVersion = ApiUtils.getConversationApiVersion(userModel, intArrayOf(ApiUtils.APIv4, 1)) - val retrofitBucket = ApiUtils.getRetrofitBucketForCreateRoom( - apiVersion, - userModel.baseUrl, - "1", - null, - userId, - null - ) + val retrofitBucket = + ApiUtils + .getRetrofitBucketForCreateRoom( + apiVersion, + userModel.baseUrl, + "1", + null, + userId, + null + ) val credentials = ApiUtils.getCredentials(userModel.username, userModel.token) ncApi.createRoom( credentials, @@ -135,38 +139,41 @@ class ProfileBottomSheet(val ncApi: NcApi, val userModel: User) { ) .subscribeOn(Schedulers.io()) .observeOn(AndroidSchedulers.mainThread()) - .subscribe(object : Observer { - override fun onSubscribe(d: Disposable) { - // unused atm - } - - override fun onNext(roomOverall: RoomOverall) { - val bundle = Bundle() - bundle.putString(BundleKeys.KEY_ROOM_TOKEN, roomOverall.ocs!!.data!!.token) - bundle.putString(BundleKeys.KEY_ROOM_ID, roomOverall.ocs!!.data!!.roomId) - - val chatIntent = Intent(context, ChatActivity::class.java) - chatIntent.putExtras(bundle) - chatIntent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP) - context.startActivity(chatIntent) - } - - override fun onError(e: Throwable) { - Log.e(TAG, e.message, e) - } - - override fun onComplete() { - // unused atm - } - }) + .subscribe( + object : Observer { + override fun onSubscribe(d: Disposable) { + // unused atm + } + + override fun onNext(roomOverall: RoomOverall) { + val bundle = Bundle() + bundle.putString(BundleKeys.KEY_ROOM_TOKEN, roomOverall.ocs!!.data!!.token) + bundle.putString(BundleKeys.KEY_ROOM_ID, roomOverall.ocs!!.data!!.roomId) + + val chatIntent = Intent(context, ChatActivity::class.java) + chatIntent.putExtras(bundle) + chatIntent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP) + context.startActivity(chatIntent) + } + + override fun onError(e: Throwable) { + Log.e(TAG, e.message, e) + } + + override fun onComplete() { + // unused atm + } + }) } private fun composeEmail(address: String, context: Context) { val addresses = arrayListOf(address) - val intent = Intent(Intent.ACTION_SENDTO).apply { - data = Uri.parse("mailto:") // only email apps should handle this - putExtra(Intent.EXTRA_EMAIL, addresses) - } + val intent = + Intent(Intent.ACTION_SENDTO) + .apply { + data = Uri.parse("mailto:") // only email apps should handle this + putExtra(Intent.EXTRA_EMAIL, addresses) + } context.startActivity(intent) } 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 c050a9b15bb..43745d14cc6 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 @@ -61,12 +61,14 @@ class AttachmentDialog(val activity: Activity, var chatActivity: ChatActivity) : private fun initItemsStrings() { var serverName = CapabilitiesUtilNew.getServerName(chatActivity.conversationUser) - dialogAttachmentBinding.txtAttachFileFromCloud.text = chatActivity.resources?.let { - if (serverName.isNullOrEmpty()) { - serverName = it.getString(R.string.nc_server_product_name) - } - String.format(it.getString(R.string.nc_upload_from_cloud), serverName) - } + dialogAttachmentBinding.txtAttachFileFromCloud.text = + chatActivity + .resources?.let { + if (serverName.isNullOrEmpty()) { + serverName = it.getString(R.string.nc_server_product_name) + } + String.format(it.getString(R.string.nc_upload_from_cloud), serverName) + } } private fun initItemsVisibility() { 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 3fe01b13106..f9350e96119 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 @@ -112,11 +112,12 @@ class ChooseAccountShareToDialogFragment : DialogFragment() { userEntity = userItem if (!userEntity.current) { var userId: String? - userId = if (userEntity.userId != null) { - userEntity.userId - } else { - userEntity.username - } + userId = + if (userEntity.userId != null) { + userEntity.userId + } else { + userEntity.username + } participant = Participant() participant.actorType = Participant.ActorType.USERS participant.actorId = userId @@ -155,20 +156,23 @@ class ChooseAccountShareToDialogFragment : DialogFragment() { binding = null } - private val onSwitchItemClickListener = FlexibleAdapter.OnItemClickListener { view, position -> - if (userItems.size > position) { - val user = userItems[position].user - if (userManager!!.setUserAsActive(user).blockingGet()) { - cookieManager!!.cookieStore.removeAll() - activity?.recreate() - dismiss() + private val onSwitchItemClickListener = + FlexibleAdapter + .OnItemClickListener { view, position -> + if (userItems.size > position) { + val user = userItems[position].user + if (userManager!!.setUserAsActive(user).blockingGet()) { + cookieManager!!.cookieStore.removeAll() + activity?.recreate() + dismiss() + } + } + true } - } - true - } companion object { val TAG = ChooseAccountShareToDialogFragment::class.java.simpleName + fun newInstance(): ChooseAccountShareToDialogFragment { return ChooseAccountShareToDialogFragment() } 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 9463b34d488..85bb184bcb7 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 @@ -107,35 +107,42 @@ class ConversationsListBottomDialog( val hasFavoritesCapability = CapabilitiesUtilNew.hasSpreedFeatureCapability(currentUser, "favorites") val canModerate = conversation.canModerate(currentUser) - binding.conversationRemoveFromFavorites.visibility = setVisibleIf( - hasFavoritesCapability && conversation.favorite - ) - binding.conversationAddToFavorites.visibility = setVisibleIf( - hasFavoritesCapability && !conversation.favorite - ) + binding.conversationRemoveFromFavorites.visibility = + setVisibleIf( + hasFavoritesCapability && conversation.favorite + ) + binding.conversationAddToFavorites.visibility = + setVisibleIf( + hasFavoritesCapability && !conversation.favorite + ) - binding.conversationMarkAsRead.visibility = setVisibleIf( - conversation.unreadMessages > 0 && CapabilitiesUtilNew.canSetChatReadMarker(currentUser) - ) + binding.conversationMarkAsRead.visibility = + setVisibleIf( + conversation.unreadMessages > 0 && CapabilitiesUtilNew.canSetChatReadMarker(currentUser) + ) - binding.conversationMarkAsUnread.visibility = setVisibleIf( - conversation.unreadMessages <= 0 && CapabilitiesUtilNew.canMarkRoomAsUnread(currentUser) - ) + binding.conversationMarkAsUnread.visibility = + setVisibleIf( + conversation.unreadMessages <= 0 && CapabilitiesUtilNew.canMarkRoomAsUnread(currentUser) + ) - binding.conversationOperationRename.visibility = setVisibleIf( - conversation.isNameEditable(currentUser) - ) + binding.conversationOperationRename.visibility = + setVisibleIf( + conversation.isNameEditable(currentUser) + ) - binding.conversationOperationDelete.visibility = setVisibleIf( - canModerate - ) + binding.conversationOperationDelete.visibility = + setVisibleIf( + canModerate + ) - binding.conversationOperationLeave.visibility = setVisibleIf( - conversation.canLeave() && - // leaving is by api not possible for the last user with moderator permissions. - // for now, hide this option for all moderators. - !conversation.canModerate(currentUser) - ) + binding.conversationOperationLeave.visibility = + setVisibleIf( + conversation.canLeave() && + // leaving is by api not possible for the last user with moderator permissions. + // for now, hide this option for all moderators. + !conversation.canModerate(currentUser) + ) } private fun setVisibleIf(boolean: Boolean): Int { @@ -189,31 +196,32 @@ class ConversationsListBottomDialog( .subscribeOn(Schedulers.io()) .observeOn(AndroidSchedulers.mainThread()) .retry(1) - .subscribe(object : Observer { - override fun onSubscribe(d: Disposable) { - // unused atm - } + .subscribe( + object : Observer { + override fun onSubscribe(d: Disposable) { + // unused atm + } - override fun onNext(genericOverall: GenericOverall) { - activity.fetchRooms() - activity.showSnackbar( - String.format( - context.resources.getString(R.string.added_to_favorites), - conversation.displayName + override fun onNext(genericOverall: GenericOverall) { + activity.fetchRooms() + activity.showSnackbar( + String.format( + context.resources.getString(R.string.added_to_favorites), + conversation.displayName + ) ) - ) - dismiss() - } + dismiss() + } - override fun onError(e: Throwable) { - activity.showSnackbar(context.resources.getString(R.string.nc_common_error_sorry)) - dismiss() - } + override fun onError(e: Throwable) { + activity.showSnackbar(context.resources.getString(R.string.nc_common_error_sorry)) + dismiss() + } - override fun onComplete() { - // unused atm - } - }) + override fun onComplete() { + // unused atm + } + }) } private fun removeConversationFromFavorites() { @@ -229,31 +237,32 @@ class ConversationsListBottomDialog( .subscribeOn(Schedulers.io()) .observeOn(AndroidSchedulers.mainThread()) .retry(1) - .subscribe(object : Observer { - override fun onSubscribe(d: Disposable) { - // unused atm - } + .subscribe( + object : Observer { + override fun onSubscribe(d: Disposable) { + // unused atm + } - override fun onNext(genericOverall: GenericOverall) { - activity.fetchRooms() - activity.showSnackbar( - String.format( - context.resources.getString(R.string.removed_from_favorites), - conversation.displayName + override fun onNext(genericOverall: GenericOverall) { + activity.fetchRooms() + activity.showSnackbar( + String.format( + context.resources.getString(R.string.removed_from_favorites), + conversation.displayName + ) ) - ) - dismiss() - } + dismiss() + } - override fun onError(e: Throwable) { - activity.showSnackbar(context.resources.getString(R.string.nc_common_error_sorry)) - dismiss() - } + override fun onError(e: Throwable) { + activity.showSnackbar(context.resources.getString(R.string.nc_common_error_sorry)) + dismiss() + } - override fun onComplete() { - // unused atm - } - }) + override fun onComplete() { + // unused atm + } + }) } private fun markConversationAsUnread() { @@ -268,31 +277,32 @@ class ConversationsListBottomDialog( .subscribeOn(Schedulers.io()) .observeOn(AndroidSchedulers.mainThread()) .retry(1) - .subscribe(object : Observer { - override fun onSubscribe(d: Disposable) { - // unused atm - } + .subscribe( + object : Observer { + override fun onSubscribe(d: Disposable) { + // unused atm + } - override fun onNext(genericOverall: GenericOverall) { - activity.fetchRooms() - activity.showSnackbar( - String.format( - context.resources.getString(R.string.marked_as_unread), - conversation.displayName + override fun onNext(genericOverall: GenericOverall) { + activity.fetchRooms() + activity.showSnackbar( + String.format( + context.resources.getString(R.string.marked_as_unread), + conversation.displayName + ) ) - ) - dismiss() - } + dismiss() + } - override fun onError(e: Throwable) { - activity.showSnackbar(context.resources.getString(R.string.nc_common_error_sorry)) - dismiss() - } + override fun onError(e: Throwable) { + activity.showSnackbar(context.resources.getString(R.string.nc_common_error_sorry)) + dismiss() + } - override fun onComplete() { - // unused atm - } - }) + override fun onComplete() { + // unused atm + } + }) } private fun markConversationAsRead() { @@ -308,46 +318,50 @@ class ConversationsListBottomDialog( .subscribeOn(Schedulers.io()) .observeOn(AndroidSchedulers.mainThread()) .retry(1) - .subscribe(object : Observer { - override fun onSubscribe(d: Disposable) { - // unused atm - } + .subscribe( + object : Observer { + override fun onSubscribe(d: Disposable) { + // unused atm + } - override fun onNext(genericOverall: GenericOverall) { - activity.fetchRooms() - activity.showSnackbar( - String.format( - context.resources.getString(R.string.marked_as_read), - conversation.displayName + override fun onNext(genericOverall: GenericOverall) { + activity.fetchRooms() + activity.showSnackbar( + String.format( + context.resources.getString(R.string.marked_as_read), + conversation.displayName + ) ) - ) - dismiss() - } + dismiss() + } - override fun onError(e: Throwable) { - activity.showSnackbar(context.resources.getString(R.string.nc_common_error_sorry)) - dismiss() - } + override fun onError(e: Throwable) { + activity.showSnackbar(context.resources.getString(R.string.nc_common_error_sorry)) + dismiss() + } - override fun onComplete() { - // unused atm - } - }) + override fun onComplete() { + // unused atm + } + }) } private fun renameConversation() { if (!TextUtils.isEmpty(conversation.token)) { dismiss() - val conversationDialog = RenameConversationDialogFragment.newInstance( - conversation.token!!, - conversation.displayName!! - ) + val conversationDialog = + RenameConversationDialogFragment + .newInstance( + conversation.token!!, + conversation.displayName!! + ) conversationDialog.show( activity.supportFragmentManager, TAG ) } } + private fun leaveConversation() { val dataBuilder = Data.Builder() dataBuilder.putString(KEY_ROOM_TOKEN, conversation.token) 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 886ef57f99f..5716687afe5 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 @@ -107,13 +107,13 @@ class DateTimePickerFragment( binding.dateTimePickerLaterTodayTextview.text = getTimeFromTimeStamp(laterTodayTimeStamp) if (Calendar.getInstance().get(Calendar.DAY_OF_WEEK) == Calendar.SATURDAY) { - tomorrowTimeStamp = getTimeFromCalendar( - hour = HOUR_EIGHT_AM, - minute = 0, - daysToAdd = 1, - weekInYear = - currentWeekInYear + 1 - ) + tomorrowTimeStamp = + getTimeFromCalendar( + hour = HOUR_EIGHT_AM, + minute = 0, + daysToAdd = 1, + weekInYear = currentWeekInYear + 1 + ) binding.dateTimePickerWeekend.visibility = View.GONE // because today is the weekend } else { @@ -123,13 +123,14 @@ class DateTimePickerFragment( binding.dateTimePickerTomorrowTextview.text = getTimeFromTimeStamp(tomorrowTimeStamp) binding.dateTimePickerWeekendTextview.text = getTimeFromTimeStamp(weekendTimeStamp) - nextWeekTimeStamp = getTimeFromCalendar( - hour = HOUR_EIGHT_AM, - day = Calendar.MONDAY, - minute = 0, - weekInYear = - currentWeekInYear + 1 - ) // this should only pick mondays from next week only + nextWeekTimeStamp = + getTimeFromCalendar( + hour = HOUR_EIGHT_AM, + day = Calendar.MONDAY, + minute = 0, + weekInYear = + currentWeekInYear + 1 + ) // this should only pick mondays from next week only binding.dateTimePickerNextWeekTextview.text = getTimeFromTimeStamp(nextWeekTimeStamp) // This is to hide the later today option, if it's past 6pm @@ -194,14 +195,19 @@ class DateTimePickerFragment( setTimeStamp(getTimeFromTimeStamp(nextWeekTimeStamp)) } binding.dateTimePickerCustom.setOnClickListener { - val constraintsBuilder = CalendarConstraints.Builder() - .setValidator(DateValidatorPointForward.now()) - .build() + val constraintsBuilder = + CalendarConstraints + .Builder() + .setValidator(DateValidatorPointForward.now()) + .build() val time = System.currentTimeMillis() - val datePicker = MaterialDatePicker.Builder.datePicker() - .setTitleText(R.string.nc_remind) - .setSelection(time + TimeZone.getDefault().getOffset(time)) - .setCalendarConstraints(constraintsBuilder).build() + val datePicker = + MaterialDatePicker + .Builder + .datePicker() + .setTitleText(R.string.nc_remind) + .setSelection(time + TimeZone.getDefault().getOffset(time)) + .setCalendarConstraints(constraintsBuilder).build() datePicker.addOnPositiveButtonClickListener { selection -> val localTimeInMillis = selection - TimeZone.getDefault().getOffset(selection) @@ -232,20 +238,23 @@ class DateTimePickerFragment( private fun setUpTimePicker(year: Int, month: Int, day: Int, weekInYear: Int) { val locale = if (DateFormat.is24HourFormat(requireContext())) TimeFormat.CLOCK_24H else TimeFormat.CLOCK_12H - val timePicker = MaterialTimePicker.Builder() - .setTitleText(R.string.nc_remind) - .setTimeFormat(locale) - .build() + val timePicker = + MaterialTimePicker + .Builder() + .setTitleText(R.string.nc_remind) + .setTimeFormat(locale) + .build() timePicker.addOnPositiveButtonClickListener { - val timestamp = getTimeFromCalendar( - year, - month, - day, - timePicker.hour, - timePicker.minute, - weekInYear = weekInYear - ) + val timestamp = + getTimeFromCalendar( + year, + month, + day, + timePicker.hour, + timePicker.minute, + weekInYear = weekInYear + ) setTimeStamp(getTimeFromTimeStamp(timestamp)) currentTimeStamp = timestamp / ONE_SEC } @@ -263,16 +272,19 @@ class DateTimePickerFragment( daysToAdd: Int = 0, weekInYear: Int = Calendar.getInstance().get(Calendar.WEEK_OF_YEAR) ): Long { - val calendar: Calendar = Calendar.getInstance().apply { - set(Calendar.YEAR, year) - set(Calendar.MONTH, month) - set(Calendar.DAY_OF_WEEK, day) - add(Calendar.DAY_OF_WEEK, daysToAdd) - set(Calendar.WEEK_OF_YEAR, weekInYear) - set(Calendar.HOUR_OF_DAY, hour) - set(Calendar.MINUTE, minute) - set(Calendar.SECOND, 0) - } + val calendar: Calendar = + Calendar + .getInstance() + .apply { + set(Calendar.YEAR, year) + set(Calendar.MONTH, month) + set(Calendar.DAY_OF_WEEK, day) + add(Calendar.DAY_OF_WEEK, daysToAdd) + set(Calendar.WEEK_OF_YEAR, weekInYear) + set(Calendar.HOUR_OF_DAY, hour) + set(Calendar.MINUTE, minute) + set(Calendar.SECOND, 0) + } return calendar.timeInMillis } @@ -281,11 +293,12 @@ class DateTimePickerFragment( } private fun getTimeFromTimeStamp(time: Long): String { - return DateUtils.formatDateTime( - requireContext(), - time, - DateUtils.FORMAT_SHOW_DATE - ) + ", " + DateUtils.formatDateTime( + return DateUtils + .formatDateTime( + requireContext(), + time, + DateUtils.FORMAT_SHOW_DATE + ) + ", " + DateUtils.formatDateTime( requireContext(), time, DateUtils.FORMAT_SHOW_TIME @@ -299,11 +312,7 @@ class DateTimePickerFragment( private const val HOUR_SIX_PM = 18 @JvmStatic - fun newInstance( - token: String, - id: String, - chatViewModel: ChatViewModel - ) = DateTimePickerFragment( + fun newInstance(token: String, id: String, chatViewModel: ChatViewModel) = DateTimePickerFragment( token, id, chatViewModel diff --git a/app/src/main/java/com/nextcloud/talk/ui/dialog/FileAttachmentPreviewFragment.kt b/app/src/main/java/com/nextcloud/talk/ui/dialog/FileAttachmentPreviewFragment.kt index e4f004b95b6..b96854ec3b6 100644 --- a/app/src/main/java/com/nextcloud/talk/ui/dialog/FileAttachmentPreviewFragment.kt +++ b/app/src/main/java/com/nextcloud/talk/ui/dialog/FileAttachmentPreviewFragment.kt @@ -51,6 +51,7 @@ class FileAttachmentPreviewFragment( @Inject lateinit var viewThemeUtils: ViewThemeUtils + override fun onCreateDialog(savedInstanceState: Bundle?): Dialog { binding = DialogFileAttachmentPreviewBinding.inflate(LayoutInflater.from(context)) return MaterialAlertDialogBuilder(requireContext()).setView(binding.root).create() @@ -93,8 +94,8 @@ class FileAttachmentPreviewFragment( filenames: String, filesToUpload: MutableList, functionToCall: (files: MutableList, caption: String) -> Unit - ) = - FileAttachmentPreviewFragment(filenames, filesToUpload, functionToCall) + ) = FileAttachmentPreviewFragment(filenames, filesToUpload, functionToCall) + val TAG: String = FilterConversationFragment::class.java.simpleName } } diff --git a/app/src/main/java/com/nextcloud/talk/ui/dialog/FilterConversationFragment.kt b/app/src/main/java/com/nextcloud/talk/ui/dialog/FilterConversationFragment.kt index aa8061e42c1..20d0382cc5e 100644 --- a/app/src/main/java/com/nextcloud/talk/ui/dialog/FilterConversationFragment.kt +++ b/app/src/main/java/com/nextcloud/talk/ui/dialog/FilterConversationFragment.kt @@ -55,6 +55,7 @@ class FilterConversationFragment( @Inject lateinit var arbitraryStorageManager: ArbitraryStorageManager + override fun onCreateDialog(savedInstanceState: Bundle?): Dialog { binding = DialogFilterConversationBinding.inflate(LayoutInflater.from(context)) dialogView = binding.root @@ -62,11 +63,7 @@ class FilterConversationFragment( return MaterialAlertDialogBuilder(requireContext()).setView(dialogView).create() } - override fun onCreateView( - inflater: LayoutInflater, - container: ViewGroup?, - savedInstanceState: Bundle? - ): View? { + override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? { NextcloudTalkApplication.sharedApplication!!.componentApplication.inject(this) setUpColors() setUpListeners() @@ -133,6 +130,7 @@ class FilterConversationFragment( savedFilterState: MutableMap, conversationsListActivity: ConversationsListActivity ) = FilterConversationFragment(savedFilterState, conversationsListActivity) + val TAG: String = FilterConversationFragment::class.java.simpleName const val MENTION: String = "mention" const val UNREAD: String = "unread" 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 884eacd1a1e..36e943f452f 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 @@ -143,26 +143,28 @@ class MessageActionsDialog( true } - popup = EmojiPopup( - rootView = dialogMessageActionsBinding.root, - editText = dialogMessageActionsBinding.emojiMore, - onEmojiPopupShownListener = { - dialogMessageActionsBinding.emojiMore.clearFocus() - dialogMessageActionsBinding.messageActions.visibility = View.GONE - }, - onEmojiClickListener = { - popup.dismiss() - clickOnEmoji(message, it.unicode) - }, - onEmojiPopupDismissListener = { - dialogMessageActionsBinding.emojiMore.clearFocus() - dialogMessageActionsBinding.messageActions.visibility = View.VISIBLE - - val imm: InputMethodManager = context.getSystemService(Context.INPUT_METHOD_SERVICE) as - InputMethodManager - imm.hideSoftInputFromWindow(dialogMessageActionsBinding.emojiMore.windowToken, 0) - } - ) + popup = + EmojiPopup( + rootView = dialogMessageActionsBinding.root, + editText = dialogMessageActionsBinding.emojiMore, + onEmojiPopupShownListener = { + dialogMessageActionsBinding.emojiMore.clearFocus() + dialogMessageActionsBinding.messageActions.visibility = View.GONE + }, + onEmojiClickListener = { + popup.dismiss() + clickOnEmoji(message, it.unicode) + }, + onEmojiPopupDismissListener = { + dialogMessageActionsBinding.emojiMore.clearFocus() + dialogMessageActionsBinding.messageActions.visibility = View.VISIBLE + + val imm: InputMethodManager = + context + .getSystemService(Context.INPUT_METHOD_SERVICE) as InputMethodManager + imm.hideSoftInputFromWindow(dialogMessageActionsBinding.emojiMore.windowToken, 0) + } + ) dialogMessageActionsBinding.emojiMore.installDisableKeyboardInput(popup) dialogMessageActionsBinding.emojiMore.installForceSingleEmoji() } @@ -329,6 +331,7 @@ class MessageActionsDialog( dialogMessageActionsBinding.menuTranslateMessage.visibility = getVisibility(visible) } + private fun initMenuShare(visible: Boolean) { if (visible) { dialogMessageActionsBinding.menuShare.setOnClickListener { 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 30769c72312..88ea3dcca9a 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 @@ -108,7 +108,9 @@ class MoreCallActionsDialog(private val callActivity: CallActivity) : BottomShee val availableReactions: ArrayList<*> = capabilities?.spreedCapability?.config!!["call"]!!["supported-reactions"] as ArrayList<*> - val param = LinearLayout.LayoutParams( + val param = + LinearLayout + .LayoutParams( LinearLayout.LayoutParams.MATCH_PARENT, LinearLayout.LayoutParams.MATCH_PARENT, 1.0f diff --git a/app/src/main/java/com/nextcloud/talk/ui/dialog/SaveToStorageDialogFragment.kt b/app/src/main/java/com/nextcloud/talk/ui/dialog/SaveToStorageDialogFragment.kt index 89f7afc0f96..88afab5e4d3 100644 --- a/app/src/main/java/com/nextcloud/talk/ui/dialog/SaveToStorageDialogFragment.kt +++ b/app/src/main/java/com/nextcloud/talk/ui/dialog/SaveToStorageDialogFragment.kt @@ -53,6 +53,7 @@ class SaveToStorageDialogFragment : DialogFragment() { sharedApplication!!.componentApplication.inject(this) fileName = arguments?.getString(KEY_FILE_NAME)!! } + override fun onCreateDialog(savedInstanceState: Bundle?): Dialog { val dialogText = StringBuilder() dialogText.append(resources.getString(R.string.nc_dialog_save_to_storage_content)) @@ -60,14 +61,15 @@ class SaveToStorageDialogFragment : DialogFragment() { dialogText.append("\n") dialogText.append(resources.getString(R.string.nc_dialog_save_to_storage_continue)) - val dialogBuilder = MaterialAlertDialogBuilder(requireContext()) - .setTitle(R.string.nc_dialog_save_to_storage_title) - .setMessage(dialogText) - .setPositiveButton(R.string.nc_dialog_save_to_storage_yes) { _: DialogInterface?, _: Int -> - saveImageToStorage(fileName) - } - .setNegativeButton(R.string.nc_dialog_save_to_storage_no) { _: DialogInterface?, _: Int -> - } + val dialogBuilder = + MaterialAlertDialogBuilder(requireContext()) + .setTitle(R.string.nc_dialog_save_to_storage_title) + .setMessage(dialogText) + .setPositiveButton(R.string.nc_dialog_save_to_storage_yes) { _: DialogInterface?, _: Int -> + saveImageToStorage(fileName) + } + .setNegativeButton(R.string.nc_dialog_save_to_storage_no) { _: DialogInterface?, _: Int -> + } viewThemeUtils.dialog.colorMaterialAlertDialogBackground( requireContext(), dialogBuilder @@ -82,9 +84,7 @@ class SaveToStorageDialogFragment : DialogFragment() { } @SuppressLint("LongLogTag") - private fun saveImageToStorage( - fileName: String - ) { + private fun saveImageToStorage(fileName: String) { val sourceFilePath = requireContext().cacheDir.path val workerTag = SAVE_TO_STORAGE_WORKER_PREFIX + fileName @@ -101,15 +101,19 @@ class SaveToStorageDialogFragment : DialogFragment() { Log.e(TAG, "Error when checking if worker already exists", e) } - val data: Data = Data.Builder() - .putString(SaveFileToStorageWorker.KEY_FILE_NAME, fileName) - .putString(SaveFileToStorageWorker.KEY_SOURCE_FILE_PATH, "$sourceFilePath/$fileName") - .build() + val data: Data = + Data + .Builder() + .putString(SaveFileToStorageWorker.KEY_FILE_NAME, fileName) + .putString(SaveFileToStorageWorker.KEY_SOURCE_FILE_PATH, "$sourceFilePath/$fileName") + .build() - val saveWorker: OneTimeWorkRequest = OneTimeWorkRequest.Builder(SaveFileToStorageWorker::class.java) - .setInputData(data) - .addTag(workerTag) - .build() + val saveWorker: OneTimeWorkRequest = + OneTimeWorkRequest + .Builder(SaveFileToStorageWorker::class.java) + .setInputData(data) + .addTag(workerTag) + .build() WorkManager.getInstance().enqueue(saveWorker) } 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 a52b6856947..b343f23a299 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 @@ -131,37 +131,41 @@ class SetStatusDialogFragment : ncApi.getPredefinedStatuses(credentials, ApiUtils.getUrlForPredefinedStatuses(currentUser?.baseUrl)) .subscribeOn(Schedulers.io()) .observeOn(AndroidSchedulers.mainThread()) - .subscribe(object : Observer { - override fun onSubscribe(d: Disposable) { - // unused atm - } - - override fun onNext(responseBody: ResponseBody) { - val predefinedStatusOverall: PredefinedStatusOverall = LoganSquare.parse( - responseBody - .string(), - PredefinedStatusOverall::class.java - ) - predefinedStatusOverall.ocs?.data?.let { it1 -> predefinedStatusesList.addAll(it1) } - - if (currentStatus?.messageIsPredefined == true && - currentStatus?.messageId?.isNotEmpty() == true - ) { - val messageId = currentStatus!!.messageId - selectedPredefinedStatus = predefinedStatusesList.firstOrNull { ps -> messageId == ps.id } + .subscribe( + object : Observer { + override fun onSubscribe(d: Disposable) { + // unused atm } - adapter.notifyDataSetChanged() - } + override fun onNext(responseBody: ResponseBody) { + val predefinedStatusOverall: PredefinedStatusOverall = + LoganSquare + .parse( + responseBody + .string(), + PredefinedStatusOverall::class.java + ) + predefinedStatusOverall.ocs?.data?.let { it1 -> predefinedStatusesList.addAll(it1) } + + if (currentStatus?.messageIsPredefined == true && + currentStatus?.messageId?.isNotEmpty() == true + ) { + val messageId = currentStatus!!.messageId + selectedPredefinedStatus = + predefinedStatusesList.firstOrNull { ps -> messageId == ps.id } + } + + adapter.notifyDataSetChanged() + } - override fun onError(e: Throwable) { - Log.e(TAG, "Error while fetching predefined statuses", e) - } + override fun onError(e: Throwable) { + Log.e(TAG, "Error while fetching predefined statuses", e) + } - override fun onComplete() { - // unused atm - } - }) + override fun onComplete() { + // unused atm + } + }) } } @@ -193,31 +197,33 @@ class SetStatusDialogFragment : binding.setStatus.setOnClickListener { setStatusMessage() } binding.emoji.setOnClickListener { openEmojiPopup() } - popup = EmojiPopup( - rootView = view, - editText = binding.emoji, - onEmojiClickListener = { - popup.dismiss() - binding.emoji.clearFocus() - val imm: InputMethodManager = context?.getSystemService(Context.INPUT_METHOD_SERVICE) as - InputMethodManager - imm.hideSoftInputFromWindow(binding.emoji.windowToken, 0) - } - ) + popup = + EmojiPopup( + rootView = view, + editText = binding.emoji, + onEmojiClickListener = { + popup.dismiss() + binding.emoji.clearFocus() + val imm: InputMethodManager = + context?.getSystemService(Context.INPUT_METHOD_SERVICE) as InputMethodManager + imm.hideSoftInputFromWindow(binding.emoji.windowToken, 0) + } + ) binding.emoji.installDisableKeyboardInput(popup) binding.emoji.installForceSingleEmoji() binding.clearStatusAfterSpinner.apply { this.adapter = createClearTimesArrayAdapter() - onItemSelectedListener = object : OnItemSelectedListener { - override fun onItemSelected(parent: AdapterView<*>, view: View, position: Int, id: Long) { - setClearStatusAfterValue(position) - } + onItemSelectedListener = + object : OnItemSelectedListener { + override fun onItemSelected(parent: AdapterView<*>, view: View, position: Int, id: Long) { + setClearStatusAfterValue(position) + } - override fun onNothingSelected(parent: AdapterView<*>?) { - // nothing to do + override fun onNothingSelected(parent: AdapterView<*>?) { + // nothing to do + } } - } } viewThemeUtils.platform.themeDialog(binding.root) @@ -245,9 +251,11 @@ class SetStatusDialogFragment : binding.remainingClearTime.apply { binding.clearStatusMessageTextView.text = getString(R.string.clear_status_message) visibility = View.VISIBLE - text = DisplayUtils.getRelativeTimestamp(context, it.clearAt * ONE_SECOND_IN_MILLIS, true) - .toString() - .decapitalize(Locale.getDefault()) + text = + DisplayUtils + .getRelativeTimestamp(context, it.clearAt * ONE_SECOND_IN_MILLIS, true) + .toString() + .decapitalize(Locale.getDefault()) setOnClickListener { visibility = View.GONE binding.clearStatusAfterSpinner.visibility = View.VISIBLE @@ -309,21 +317,27 @@ class SetStatusDialogFragment : POS_TODAY -> { // today - val date = Calendar.getInstance().apply { - set(Calendar.HOUR_OF_DAY, LAST_HOUR_OF_DAY) - set(Calendar.MINUTE, LAST_MINUTE_OF_HOUR) - set(Calendar.SECOND, LAST_SECOND_OF_MINUTE) - } + val date = + Calendar + .getInstance() + .apply { + set(Calendar.HOUR_OF_DAY, LAST_HOUR_OF_DAY) + set(Calendar.MINUTE, LAST_MINUTE_OF_HOUR) + set(Calendar.SECOND, LAST_SECOND_OF_MINUTE) + } clearAt = date.timeInMillis / ONE_SECOND_IN_MILLIS } POS_END_OF_WEEK -> { // end of week - val date = Calendar.getInstance().apply { - set(Calendar.HOUR_OF_DAY, LAST_HOUR_OF_DAY) - set(Calendar.MINUTE, LAST_MINUTE_OF_HOUR) - set(Calendar.SECOND, LAST_SECOND_OF_MINUTE) - } + val date = + Calendar + .getInstance() + .apply { + set(Calendar.HOUR_OF_DAY, LAST_HOUR_OF_DAY) + set(Calendar.MINUTE, LAST_MINUTE_OF_HOUR) + set(Calendar.SECOND, LAST_SECOND_OF_MINUTE) + } while (date.get(Calendar.DAY_OF_WEEK) != Calendar.SUNDAY) { date.add(Calendar.DAY_OF_YEAR, 1) @@ -348,16 +362,17 @@ class SetStatusDialogFragment : return returnValue } - private fun clearAtToUnixTimeTypeEndOf( - clearAt: ClearAt - ): Long { + private fun clearAtToUnixTimeTypeEndOf(clearAt: ClearAt): Long { var returnValue = -1L if (clearAt.time == "day") { - val date = Calendar.getInstance().apply { - set(Calendar.HOUR_OF_DAY, LAST_HOUR_OF_DAY) - set(Calendar.MINUTE, LAST_MINUTE_OF_HOUR) - set(Calendar.SECOND, LAST_SECOND_OF_MINUTE) - } + val date = + Calendar + .getInstance() + .apply { + set(Calendar.HOUR_OF_DAY, LAST_HOUR_OF_DAY) + set(Calendar.MINUTE, LAST_MINUTE_OF_HOUR) + set(Calendar.SECOND, LAST_SECOND_OF_MINUTE) + } returnValue = date.timeInMillis / ONE_SECOND_IN_MILLIS } return returnValue @@ -371,23 +386,24 @@ class SetStatusDialogFragment : val credentials = ApiUtils.getCredentials(currentUser?.username, currentUser?.token) ncApi.statusDeleteMessage(credentials, ApiUtils.getUrlForStatusMessage(currentUser?.baseUrl)) .subscribeOn(Schedulers.io()) - .observeOn(AndroidSchedulers.mainThread()).subscribe(object : Observer { - override fun onSubscribe(d: Disposable) { - // unused atm - } + .observeOn(AndroidSchedulers.mainThread()).subscribe( + object : Observer { + override fun onSubscribe(d: Disposable) { + // unused atm + } - override fun onNext(statusOverall: GenericOverall) { - // unused atm - } + override fun onNext(statusOverall: GenericOverall) { + // unused atm + } - override fun onError(e: Throwable) { - Log.e(TAG, "Failed to clear status", e) - } + override fun onError(e: Throwable) { + Log.e(TAG, "Failed to clear status", e) + } - override fun onComplete() { - dismiss() - } - }) + override fun onComplete() { + dismiss() + } + }) } private fun setStatus(statusType: StatusType) { @@ -398,24 +414,25 @@ class SetStatusDialogFragment : Schedulers .io() ) - .observeOn(AndroidSchedulers.mainThread()).subscribe(object : Observer { - override fun onSubscribe(d: Disposable) { - // unused atm - } + .observeOn(AndroidSchedulers.mainThread()).subscribe( + object : Observer { + override fun onSubscribe(d: Disposable) { + // unused atm + } - override fun onNext(statusOverall: GenericOverall) { - Log.d(TAG, "statusType successfully set") - } + override fun onNext(statusOverall: GenericOverall) { + Log.d(TAG, "statusType successfully set") + } - override fun onError(e: Throwable) { - Log.e(TAG, "Failed to set statusType", e) - clearTopStatus() - } + override fun onError(e: Throwable) { + Log.e(TAG, "Failed to set statusType", e) + clearTopStatus() + } - override fun onComplete() { - // unused atm - } - }) + override fun onComplete() { + // unused atm + } + }) } private fun visualizeStatus(statusType: String) { @@ -424,16 +441,22 @@ class SetStatusDialogFragment : private fun visualizeStatus(statusType: StatusType) { clearTopStatus() - val views: Triple = when (statusType) { - StatusType.ONLINE -> Triple(binding.onlineStatus, binding.onlineHeadline, binding.onlineIcon) - StatusType.AWAY -> Triple(binding.awayStatus, binding.awayHeadline, binding.awayIcon) - StatusType.DND -> Triple(binding.dndStatus, binding.dndHeadline, binding.dndIcon) - StatusType.INVISIBLE -> Triple(binding.invisibleStatus, binding.invisibleHeadline, binding.invisibleIcon) - else -> { - Log.d(TAG, "unknown status") - return + val views: Triple = + when (statusType) { + StatusType.ONLINE -> Triple(binding.onlineStatus, binding.onlineHeadline, binding.onlineIcon) + StatusType.AWAY -> Triple(binding.awayStatus, binding.awayHeadline, binding.awayIcon) + StatusType.DND -> Triple(binding.dndStatus, binding.dndHeadline, binding.dndIcon) + StatusType.INVISIBLE -> Triple( + binding.invisibleStatus, + binding.invisibleHeadline, + binding.invisibleIcon + ) + + else -> { + Log.d(TAG, "unknown status") + return + } } - } views.first.isChecked = true viewThemeUtils.platform.colorTextView(views.second, ColorRole.ON_SECONDARY_CONTAINER) } @@ -475,24 +498,26 @@ class SetStatusDialogFragment : ) .subscribeOn(Schedulers.io()) .observeOn(AndroidSchedulers.mainThread()) - ?.subscribe(object : Observer { + ?.subscribe( + object : Observer { - override fun onSubscribe(d: Disposable) { // unused atm - } + override fun onSubscribe(d: Disposable) { + // unused atm + } - override fun onNext(t: GenericOverall) { - Log.d(TAG, "CustomStatusMessage successfully set") - dismiss() - } + override fun onNext(t: GenericOverall) { + Log.d(TAG, "CustomStatusMessage successfully set") + dismiss() + } - override fun onError(e: Throwable) { - Log.e(TAG, "failed to set CustomStatusMessage", e) - } + override fun onError(e: Throwable) { + Log.e(TAG, "failed to set CustomStatusMessage", e) + } - override fun onComplete() { - // unused atm - } - }) + override fun onComplete() { + // unused atm + } + }) } else { val clearAt = clearAtToUnixTime(selectedPredefinedStatus!!.clearAt) @@ -503,20 +528,21 @@ class SetStatusDialogFragment : if (clearAt == -1L) null else clearAt ) .subscribeOn(Schedulers.io()) - .observeOn(AndroidSchedulers.mainThread())?.subscribe(object : Observer { - override fun onSubscribe(d: Disposable) = Unit + .observeOn(AndroidSchedulers.mainThread())?.subscribe( + object : Observer { + override fun onSubscribe(d: Disposable) = Unit - override fun onNext(t: GenericOverall) { - Log.d(TAG, "PredefinedStatusMessage successfully set") - dismiss() - } + override fun onNext(t: GenericOverall) { + Log.d(TAG, "PredefinedStatusMessage successfully set") + dismiss() + } - override fun onError(e: Throwable) { - Log.e(TAG, "failed to set PredefinedStatusMessage", e) - } + override fun onError(e: Throwable) { + Log.e(TAG, "failed to set PredefinedStatusMessage", e) + } - override fun onComplete() = Unit - }) + override fun onComplete() = Unit + }) } } 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 467f952130d..3d0d9eb0f5c 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 @@ -123,20 +123,21 @@ class ShowReactionsDialog( binding.emojiReactionsTabs.getTabAt(0)?.select() - binding.emojiReactionsTabs.addOnTabSelectedListener(object : OnTabSelectedListener { - override fun onTabSelected(tab: TabLayout.Tab) { - // called when a tab is reselected - updateParticipantsForEmoji(chatMessage, tab.customView?.tag as String?) - } + binding.emojiReactionsTabs.addOnTabSelectedListener( + object : OnTabSelectedListener { + override fun onTabSelected(tab: TabLayout.Tab) { + // called when a tab is reselected + updateParticipantsForEmoji(chatMessage, tab.customView?.tag as String?) + } - override fun onTabUnselected(tab: TabLayout.Tab) { - // called when a tab is reselected - } + override fun onTabUnselected(tab: TabLayout.Tab) { + // called when a tab is reselected + } - override fun onTabReselected(tab: TabLayout.Tab) { - // called when a tab is reselected - } - }) + override fun onTabReselected(tab: TabLayout.Tab) { + // called when a tab is reselected + } + }) viewThemeUtils.material.themeTabLayoutOnSurface(binding.emojiReactionsTabs) @@ -161,38 +162,39 @@ class ShowReactionsDialog( ) ?.subscribeOn(Schedulers.io()) ?.observeOn(AndroidSchedulers.mainThread()) - ?.subscribe(object : Observer { - override fun onSubscribe(d: Disposable) { - // unused atm - } + ?.subscribe( + object : Observer { + override fun onSubscribe(d: Disposable) { + // unused atm + } - override fun onNext(reactionsOverall: ReactionsOverall) { - val reactionVoters: ArrayList = ArrayList() - if (reactionsOverall.ocs?.data != null) { - val map = reactionsOverall.ocs?.data - for (key in map!!.keys) { - for (reactionVoter in reactionsOverall.ocs?.data!![key]!!) { - reactionVoters.add(ReactionItem(reactionVoter, key)) + override fun onNext(reactionsOverall: ReactionsOverall) { + val reactionVoters: ArrayList = ArrayList() + if (reactionsOverall.ocs?.data != null) { + val map = reactionsOverall.ocs?.data + for (key in map!!.keys) { + for (reactionVoter in reactionsOverall.ocs?.data!![key]!!) { + reactionVoters.add(ReactionItem(reactionVoter, key)) + } } - } - Collections.sort(reactionVoters, ReactionComparator(user?.userId)) + Collections.sort(reactionVoters, ReactionComparator(user?.userId)) - adapter?.list?.addAll(reactionVoters) - adapter?.notifyDataSetChanged() - } else { - Log.e(TAG, "no voters for this reaction") + adapter?.list?.addAll(reactionVoters) + adapter?.notifyDataSetChanged() + } else { + Log.e(TAG, "no voters for this reaction") + } } - } - override fun onError(e: Throwable) { - Log.e(TAG, "failed to retrieve list of reaction voters") - } + override fun onError(e: Throwable) { + Log.e(TAG, "failed to retrieve list of reaction voters") + } - override fun onComplete() { - // unused atm - } - }) + override fun onComplete() { + // unused atm + } + }) } override fun onClick(reactionItem: ReactionItem) { @@ -216,23 +218,24 @@ class ShowReactionsDialog( ) ?.subscribeOn(Schedulers.io()) ?.observeOn(AndroidSchedulers.mainThread()) - ?.subscribe(object : Observer { - override fun onSubscribe(d: Disposable) { - // unused atm - } + ?.subscribe( + object : Observer { + override fun onSubscribe(d: Disposable) { + // unused atm + } - override fun onNext(genericOverall: GenericOverall) { - Log.d(TAG, "deleted reaction: $emoji") - } + override fun onNext(genericOverall: GenericOverall) { + Log.d(TAG, "deleted reaction: $emoji") + } - override fun onError(e: Throwable) { - Log.e(TAG, "error while deleting reaction: $emoji") - } + override fun onError(e: Throwable) { + Log.e(TAG, "error while deleting reaction: $emoji") + } - override fun onComplete() { - dismiss() - } - }) + override fun onComplete() { + dismiss() + } + }) } companion object { @@ -261,44 +264,48 @@ class ShowReactionsDialog( } // own account - val ownAccount = compareOwnAccount( - activeUser, - reactionItem1.reactionVoter.actorId, - reactionItem2.reactionVoter.actorId - ) + val ownAccount = + compareOwnAccount( + activeUser, + reactionItem1.reactionVoter.actorId, + reactionItem2.reactionVoter.actorId + ) if (ownAccount != 0) { return ownAccount } // display-name - val displayName = StringComparator() - .compare( - reactionItem1.reactionVoter.actorDisplayName, - reactionItem2.reactionVoter.actorDisplayName - ) + val displayName = + StringComparator() + .compare( + reactionItem1.reactionVoter.actorDisplayName, + reactionItem2.reactionVoter.actorDisplayName + ) if (displayName != 0) { return displayName } // timestamp - val timestamp = LongComparator() - .compare( - reactionItem1.reactionVoter.timestamp, - reactionItem2.reactionVoter.timestamp - ) + val timestamp = + LongComparator() + .compare( + reactionItem1.reactionVoter.timestamp, + reactionItem2.reactionVoter.timestamp + ) if (timestamp != 0) { return timestamp } // actor-id - val actorId = StringComparator() - .compare( - reactionItem1.reactionVoter.actorId, - reactionItem2.reactionVoter.actorId - ) + val actorId = + StringComparator() + .compare( + reactionItem1.reactionVoter.actorId, + reactionItem2.reactionVoter.actorId + ) if (actorId != 0) { return actorId diff --git a/app/src/main/java/com/nextcloud/talk/ui/recyclerview/MessageSwipeCallback.kt b/app/src/main/java/com/nextcloud/talk/ui/recyclerview/MessageSwipeCallback.kt index 62ee05c665c..811553998f6 100644 --- a/app/src/main/java/com/nextcloud/talk/ui/recyclerview/MessageSwipeCallback.kt +++ b/app/src/main/java/com/nextcloud/talk/ui/recyclerview/MessageSwipeCallback.kt @@ -176,13 +176,14 @@ class MessageSwipeCallback(private val context: Context, private val messageSwip val alpha: Int val scale: Float if (showing) { - scale = if (replyButtonProgress <= SCALE_PROGRESS_TOP_THRESHOLD) { - SCALE_PROGRESS_MULTIPLIER * (replyButtonProgress / SCALE_PROGRESS_TOP_THRESHOLD) - } else { - SCALE_PROGRESS_MULTIPLIER - - SCALE_PROGRESS_BOTTOM_THRESHOLD * - ((replyButtonProgress - SCALE_PROGRESS_TOP_THRESHOLD) / SCALE_PROGRESS_BOTTOM_THRESHOLD) - } + scale = + if (replyButtonProgress <= SCALE_PROGRESS_TOP_THRESHOLD) { + SCALE_PROGRESS_MULTIPLIER * (replyButtonProgress / SCALE_PROGRESS_TOP_THRESHOLD) + } else { + SCALE_PROGRESS_MULTIPLIER - + SCALE_PROGRESS_BOTTOM_THRESHOLD * + ((replyButtonProgress - SCALE_PROGRESS_TOP_THRESHOLD) / SCALE_PROGRESS_BOTTOM_THRESHOLD) + } alpha = min(FULLY_OPAQUE, FULLY_OPAQUE * (replyButtonProgress / SCALE_PROGRESS_TOP_THRESHOLD)).toInt() } else { scale = replyButtonProgress @@ -201,25 +202,28 @@ class MessageSwipeCallback(private val context: Context, private val messageSwip } private fun drawReplyIcon(alpha: Int, scale: Float, canvas: Canvas) { - val x: Int = if (view.translationX > convertToDp(SWIPE_LIMIT)) { - convertToDp(SWIPE_LIMIT) / AXIS_BASE - } else { - (view.translationX / AXIS_BASE).toInt() - } + val x: Int = + if (view.translationX > convertToDp(SWIPE_LIMIT)) { + convertToDp(SWIPE_LIMIT) / AXIS_BASE + } else { + (view.translationX / AXIS_BASE).toInt() + } val y = (view.top + view.measuredHeight / AXIS_BASE).toFloat() shareRound.alpha = alpha imageDrawable.alpha = alpha - shareRound.colorFilter = PorterDuffColorFilter( - ContextCompat.getColor(context, R.color.bg_message_list_incoming_bubble), - PorterDuff.Mode.SRC_IN - ) - imageDrawable.colorFilter = PorterDuffColorFilter( - ContextCompat.getColor(context, R.color.high_emphasis_text), - PorterDuff.Mode.SRC_IN - ) + shareRound.colorFilter = + PorterDuffColorFilter( + ContextCompat.getColor(context, R.color.bg_message_list_incoming_bubble), + PorterDuff.Mode.SRC_IN + ) + imageDrawable.colorFilter = + PorterDuffColorFilter( + ContextCompat.getColor(context, R.color.high_emphasis_text), + PorterDuff.Mode.SRC_IN + ) shareRound.setBounds( (x - convertToDp(BACKGROUND_BOUNDS_PIXEL) * scale).toInt(), diff --git a/app/src/main/java/com/nextcloud/talk/ui/theme/MaterialSchemesProvider.kt b/app/src/main/java/com/nextcloud/talk/ui/theme/MaterialSchemesProvider.kt index fc6b8f2e7da..40050debaf0 100644 --- a/app/src/main/java/com/nextcloud/talk/ui/theme/MaterialSchemesProvider.kt +++ b/app/src/main/java/com/nextcloud/talk/ui/theme/MaterialSchemesProvider.kt @@ -27,6 +27,8 @@ import com.nextcloud.talk.models.json.capabilities.Capabilities interface MaterialSchemesProvider { fun getMaterialSchemesForUser(user: User?): MaterialSchemes + fun getMaterialSchemesForCapabilities(capabilities: Capabilities?): MaterialSchemes + fun getMaterialSchemesForCurrentUser(): MaterialSchemes } diff --git a/app/src/main/java/com/nextcloud/talk/ui/theme/MaterialSchemesProviderImpl.kt b/app/src/main/java/com/nextcloud/talk/ui/theme/MaterialSchemesProviderImpl.kt index ffccd9f9488..8f388ef0f65 100644 --- a/app/src/main/java/com/nextcloud/talk/ui/theme/MaterialSchemesProviderImpl.kt +++ b/app/src/main/java/com/nextcloud/talk/ui/theme/MaterialSchemesProviderImpl.kt @@ -31,19 +31,21 @@ import com.nextcloud.talk.utils.database.user.CurrentUserProviderNew import java.util.concurrent.ConcurrentHashMap import javax.inject.Inject -internal class MaterialSchemesProviderImpl @Inject constructor( +internal class MaterialSchemesProviderImpl +@Inject +constructor( private val userProvider: CurrentUserProviderNew, private val colorUtil: ColorUtil ) : MaterialSchemesProvider { - private val themeCache: ConcurrentHashMap = ConcurrentHashMap() override fun getMaterialSchemesForUser(user: User?): MaterialSchemes { - val url: String = if (user?.baseUrl != null) { - user.baseUrl!! - } else { - FALLBACK_URL - } + val url: String = + if (user?.baseUrl != null) { + user.baseUrl!! + } else { + FALLBACK_URL + } if (!themeCache.containsKey(url)) { themeCache[url] = getMaterialSchemesForCapabilities(user?.capabilities) diff --git a/app/src/main/java/com/nextcloud/talk/ui/theme/TalkSpecificViewThemeUtils.kt b/app/src/main/java/com/nextcloud/talk/ui/theme/TalkSpecificViewThemeUtils.kt index 5a06acef8cf..55024f73a56 100644 --- a/app/src/main/java/com/nextcloud/talk/ui/theme/TalkSpecificViewThemeUtils.kt +++ b/app/src/main/java/com/nextcloud/talk/ui/theme/TalkSpecificViewThemeUtils.kt @@ -73,7 +73,9 @@ import kotlin.math.roundToInt * */ @Suppress("TooManyFunctions") -class TalkSpecificViewThemeUtils @Inject constructor( +class TalkSpecificViewThemeUtils +@Inject +constructor( schemes: MaterialSchemes, private val appcompat: AndroidXViewThemeUtils ) : @@ -87,39 +89,46 @@ class TalkSpecificViewThemeUtils @Inject constructor( bubbleResource = R.drawable.shape_grouped_incoming_message } - val bgBubbleColor = if (deleted) { - resources.getColor(R.color.bg_message_list_incoming_bubble_deleted, null) - } else { - resources.getColor(R.color.bg_message_list_incoming_bubble, null) - } - val bubbleDrawable = DisplayUtils.getMessageSelector( - bgBubbleColor, - resources.getColor(R.color.transparent, null), - bgBubbleColor, - bubbleResource - ) + val bgBubbleColor = + if (deleted) { + resources.getColor(R.color.bg_message_list_incoming_bubble_deleted, null) + } else { + resources.getColor(R.color.bg_message_list_incoming_bubble, null) + } + val bubbleDrawable = + DisplayUtils + .getMessageSelector( + bgBubbleColor, + resources.getColor(R.color.transparent, null), + bgBubbleColor, + bubbleResource + ) ViewCompat.setBackground(bubble, bubbleDrawable) } fun themeOutgoingMessageBubble(bubble: View, grouped: Boolean, deleted: Boolean) { withScheme(bubble) { scheme -> - val bgBubbleColor = if (deleted) { - ColorUtils.setAlphaComponent(scheme.surfaceVariant, HALF_ALPHA_INT) - } else { - scheme.surfaceVariant - } - - val layout = if (grouped) { - R.drawable.shape_grouped_outcoming_message - } else { - R.drawable.shape_outcoming_message - } - val bubbleDrawable = DisplayUtils.getMessageSelector( - bgBubbleColor, - ResourcesCompat.getColor(bubble.resources, R.color.transparent, null), - bgBubbleColor, - layout - ) + val bgBubbleColor = + if (deleted) { + ColorUtils.setAlphaComponent(scheme.surfaceVariant, HALF_ALPHA_INT) + } else { + scheme.surfaceVariant + } + + val layout = + if (grouped) { + R.drawable.shape_grouped_outcoming_message + } else { + R.drawable.shape_outcoming_message + } + val bubbleDrawable = + DisplayUtils + .getMessageSelector( + bgBubbleColor, + ResourcesCompat.getColor(bubble.resources, R.color.transparent, null), + bgBubbleColor, + layout + ) ViewCompat.setBackground(bubble, bubbleDrawable) } } @@ -161,9 +170,10 @@ class TalkSpecificViewThemeUtils @Inject constructor( fun setCheckedBackground(emoji: EmojiTextView) { withScheme(emoji) { scheme -> - val drawable = AppCompatResources - .getDrawable(emoji.context, R.drawable.reaction_self_bottom_sheet_background)!! - .mutate() + val drawable = + AppCompatResources + .getDrawable(emoji.context, R.drawable.reaction_self_bottom_sheet_background)!! + .mutate() DrawableCompat.setTintList( drawable, ColorStateList.valueOf(scheme.primary) @@ -174,17 +184,19 @@ class TalkSpecificViewThemeUtils @Inject constructor( fun setCheckedBackground(linearLayout: LinearLayout, incoming: Boolean) { withScheme(linearLayout) { scheme -> - val drawable = AppCompatResources - .getDrawable(linearLayout.context, R.drawable.reaction_self_background)!! - .mutate() - val backgroundColor = if (incoming) { - scheme.primaryContainer - } else { - ContextCompat.getColor( - linearLayout.context, - R.color.bg_message_list_incoming_bubble - ) - } + val drawable = + AppCompatResources + .getDrawable(linearLayout.context, R.drawable.reaction_self_background)!! + .mutate() + val backgroundColor = + if (incoming) { + scheme.primaryContainer + } else { + ContextCompat.getColor( + linearLayout.context, + R.color.bg_message_list_incoming_bubble + ) + } DrawableCompat.setTintList( drawable, ColorStateList.valueOf(backgroundColor) @@ -195,10 +207,12 @@ class TalkSpecificViewThemeUtils @Inject constructor( fun getPlaceholderImage(context: Context, mimetype: String?): Drawable? { val drawableResourceId = DrawableUtils.getDrawableResourceIdForMimeType(mimetype) - val drawable = AppCompatResources.getDrawable( - context, - drawableResourceId - ) + val drawable = + AppCompatResources + .getDrawable( + context, + drawableResourceId + ) if (drawable != null && THEMEABLE_PLACEHOLDER_IDS.contains(drawableResourceId)) { colorDrawable(context, drawable) } @@ -212,7 +226,10 @@ class TalkSpecificViewThemeUtils @Inject constructor( } @TargetApi(Build.VERSION_CODES.O) - fun themePlaceholderAvatar(avatar: View, @DrawableRes foreground: Int): Drawable? { + fun themePlaceholderAvatar( + avatar: View, + @DrawableRes foreground: Int + ): Drawable? { var drawable: LayerDrawable? = null withScheme(avatar) { scheme -> val layers = arrayOfNulls(2) @@ -295,11 +312,7 @@ class TalkSpecificViewThemeUtils @Inject constructor( } } - fun themeAndHighlightText( - textView: TextView, - originalText: String?, - c: String? - ) { + fun themeAndHighlightText(textView: TextView, originalText: String?, c: String?) { withScheme(textView) { scheme -> var constraint = c constraint = FlexibleUtils.toLowerCase(constraint) @@ -315,8 +328,10 @@ class TalkSpecificViewThemeUtils @Inject constructor( Spannable.SPAN_EXCLUSIVE_EXCLUSIVE ) spanText.setSpan(StyleSpan(Typeface.BOLD), start, end, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE) - start = FlexibleUtils.toLowerCase(originalText) - .indexOf(constraint, end + 1) // +1 skips the consecutive span + start = + FlexibleUtils + .toLowerCase(originalText) + .indexOf(constraint, end + 1) // +1 skips the consecutive span } while (start != -1) textView.setText(spanText, TextView.BufferType.SPANNABLE) } else { @@ -374,11 +389,7 @@ class TalkSpecificViewThemeUtils @Inject constructor( } } - fun getTextColor( - isOutgoingMessage: Boolean, - isSelfReaction: Boolean, - binding: ReactionsInsideMessageBinding - ): Int { + fun getTextColor(isOutgoingMessage: Boolean, isSelfReaction: Boolean, binding: ReactionsInsideMessageBinding): Int { return withScheme(binding.root) { scheme -> return@withScheme if (!isOutgoingMessage || isSelfReaction) { ContextCompat.getColor(binding.root.context, R.color.high_emphasis_text) diff --git a/app/src/main/java/com/nextcloud/talk/ui/theme/ViewThemeUtils.kt b/app/src/main/java/com/nextcloud/talk/ui/theme/ViewThemeUtils.kt index 5c058d16bc5..4475f68664f 100644 --- a/app/src/main/java/com/nextcloud/talk/ui/theme/ViewThemeUtils.kt +++ b/app/src/main/java/com/nextcloud/talk/ui/theme/ViewThemeUtils.kt @@ -30,7 +30,9 @@ import com.nextcloud.android.common.ui.theme.utils.MaterialViewThemeUtils import javax.inject.Inject @Suppress("TooManyFunctions") -class ViewThemeUtils @Inject constructor( +class ViewThemeUtils +@Inject +constructor( schemes: MaterialSchemes, @JvmField val platform: AndroidViewThemeUtils, diff --git a/app/src/main/java/com/nextcloud/talk/upload/chunked/ChunkFromFileRequestBody.kt b/app/src/main/java/com/nextcloud/talk/upload/chunked/ChunkFromFileRequestBody.kt index e3451af0639..4cc9e55edf1 100644 --- a/app/src/main/java/com/nextcloud/talk/upload/chunked/ChunkFromFileRequestBody.kt +++ b/app/src/main/java/com/nextcloud/talk/upload/chunked/ChunkFromFileRequestBody.kt @@ -55,6 +55,7 @@ class ChunkFromFileRequestBody( private var mTransferred: Long private var mDataTransferListener: OnDataTransferProgressListener private val mBuffer = ByteBuffer.allocate(BUFFER_CAPACITY) + override fun contentLength(): Long { return try { mChunkSize.coerceAtMost(mChannel.size() - mOffset) 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 5c0fcbc6682..5b94375da17 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 @@ -82,17 +82,14 @@ class ChunkedFileUploader( } @Suppress("Detekt.TooGenericExceptionCaught") - fun upload( - localFile: File, - mimeType: MediaType?, - targetPath: String - ): Boolean { + fun upload(localFile: File, mimeType: MediaType?, targetPath: String): Boolean { try { val uploadFolderUri: String = remoteChunkUrl + "/" + FileUtils.md5Sum(localFile) - val davResource = DavResource( - okHttpClientNoRedirects!!, - uploadFolderUri.toHttpUrlOrNull()!! - ) + val davResource = + DavResource( + okHttpClientNoRedirects!!, + uploadFolderUri.toHttpUrlOrNull()!! + ) createFolder(davResource) @@ -136,10 +133,7 @@ class ChunkedFileUploader( } @Suppress("Detekt.ComplexMethod") - private fun getUploadedChunks( - davResource: DavResource, - uploadFolderUri: String - ): MutableList { + private fun getUploadedChunks(davResource: DavResource, uploadFolderUri: String): MutableList { val davResponse = DavResponse() val memberElements: MutableList = ArrayList() val rootElement = arrayOfNulls(1) @@ -197,11 +191,12 @@ class ChunkedFileUploader( val nextChunk: Chunk? = findNextFittingChunk(chunks, start) if (nextChunk == null) { // create new chunk - val end: Long = if (start + CHUNK_SIZE <= length) { - start + CHUNK_SIZE - 1 - } else { - length - } + val end: Long = + if (start + CHUNK_SIZE <= length) { + start + CHUNK_SIZE - 1 + } else { + length + } missingChunks.add(Chunk(start, end)) start = end + 1 } else if (nextChunk.start == start) { @@ -246,21 +241,23 @@ class ChunkedFileUploader( // Log.d(TAG, "chunk.start:${chunk.start}") // Log.d(TAG, "chunk.end:${chunk.end}") - val chunkFromFileRequestBody = ChunkFromFileRequestBody( - localFile, - mimeType, - channel, - chunkSize, - chunk.start, - listener - ) + val chunkFromFileRequestBody = + ChunkFromFileRequestBody( + localFile, + mimeType, + channel, + chunkSize, + chunk.start, + listener + ) val chunkUri = "$uploadFolderUri/$startString-$endString" - val davResource = DavResource( - okHttpClientNoRedirects!!, - chunkUri.toHttpUrlOrNull()!! - ) + val davResource = + DavResource( + okHttpClientNoRedirects!!, + chunkUri.toHttpUrlOrNull()!! + ) davResource.put( chunkFromFileRequestBody ) { response: Response -> @@ -306,11 +303,13 @@ class ChunkedFileUploader( } private fun assembleChunks(uploadFolderUri: String, targetPath: String) { - val destinationUri: String = ApiUtils.getUrlForFileUpload( - currentUser.baseUrl, - currentUser.userId, - targetPath - ) + val destinationUri: String = + ApiUtils + .getUrlForFileUpload( + currentUser.baseUrl, + currentUser.userId, + targetPath + ) val originUri = "$uploadFolderUri/.file" DavResource( @@ -359,30 +358,39 @@ class ChunkedFileUploader( is OCId -> { remoteFileBrowserItem.remoteId = property.ocId } + is ResourceType -> { remoteFileBrowserItem.isFile = !property.types.contains(ResourceType.COLLECTION) } + is GetLastModified -> { remoteFileBrowserItem.modifiedTimestamp = property.lastModified } + is GetContentType -> { remoteFileBrowserItem.mimeType = property.type } + is OCSize -> { remoteFileBrowserItem.size = property.ocSize } + is NCPreview -> { remoteFileBrowserItem.hasPreview = property.isNcPreview } + is OCFavorite -> { remoteFileBrowserItem.isFavorite = property.isOcFavorite } + is DisplayName -> { remoteFileBrowserItem.displayName = property.displayName } + is NCEncrypted -> { remoteFileBrowserItem.isEncrypted = property.isNcEncrypted } + is NCPermission -> { remoteFileBrowserItem.permissions = property.ncPermission } diff --git a/app/src/main/java/com/nextcloud/talk/upload/chunked/OnDataTransferProgressListener.kt b/app/src/main/java/com/nextcloud/talk/upload/chunked/OnDataTransferProgressListener.kt index 049fee4fb16..6ba46334271 100644 --- a/app/src/main/java/com/nextcloud/talk/upload/chunked/OnDataTransferProgressListener.kt +++ b/app/src/main/java/com/nextcloud/talk/upload/chunked/OnDataTransferProgressListener.kt @@ -25,7 +25,5 @@ package com.nextcloud.talk.upload.chunked interface OnDataTransferProgressListener { - fun onTransferProgress( - percentage: Int - ) + fun onTransferProgress(percentage: Int) } 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 514aae0da9b..d21f9060589 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 @@ -21,12 +21,7 @@ class FileUploader( val roomToken: String, val ncApi: NcApi ) { - fun upload( - sourceFileUri: Uri, - fileName: String, - remotePath: String, - metaData: String? - ): Observable { + 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), diff --git a/app/src/main/java/com/nextcloud/talk/users/UserManager.kt b/app/src/main/java/com/nextcloud/talk/users/UserManager.kt index 378cb811295..2967958f231 100644 --- a/app/src/main/java/com/nextcloud/talk/users/UserManager.kt +++ b/app/src/main/java/com/nextcloud/talk/users/UserManager.kt @@ -143,10 +143,12 @@ class UserManager internal constructor(private val userRepository: UsersReposito return findUser(userAttributes) .map { user: User? -> when (user) { - null -> createUser( - username, - userAttributes - ) + null -> + createUser( + username, + userAttributes + ) + else -> { user.token = userAttributes.token user.baseUrl = userAttributes.serverUrl @@ -187,17 +189,20 @@ class UserManager internal constructor(private val userRepository: UsersReposito user.token = userAttributes.token user.displayName = userAttributes.displayName if (userAttributes.pushConfigurationState != null) { - user.pushConfigurationState = LoganSquare - .parse(userAttributes.pushConfigurationState, PushConfigurationState::class.java) + user.pushConfigurationState = + LoganSquare + .parse(userAttributes.pushConfigurationState, PushConfigurationState::class.java) } if (userAttributes.capabilities != null) { - user.capabilities = LoganSquare - .parse(userAttributes.capabilities, Capabilities::class.java) + user.capabilities = + LoganSquare + .parse(userAttributes.capabilities, Capabilities::class.java) } user.clientCertificate = userAttributes.certificateAlias if (userAttributes.externalSignalingServer != null) { - user.externalSignalingServer = LoganSquare - .parse(userAttributes.externalSignalingServer, ExternalSignalingServer::class.java) + user.externalSignalingServer = + LoganSquare + .parse(userAttributes.externalSignalingServer, ExternalSignalingServer::class.java) } user.current = userAttributes.currentUser == true } @@ -211,8 +216,9 @@ class UserManager internal constructor(private val userRepository: UsersReposito user.displayName = userAttributes.displayName } if (userAttributes.pushConfigurationState != null) { - user.pushConfigurationState = LoganSquare - .parse(userAttributes.pushConfigurationState, PushConfigurationState::class.java) + user.pushConfigurationState = + LoganSquare + .parse(userAttributes.pushConfigurationState, PushConfigurationState::class.java) } if (!TextUtils.isEmpty(userAttributes.userId)) { user.userId = userAttributes.userId @@ -224,8 +230,9 @@ class UserManager internal constructor(private val userRepository: UsersReposito user.clientCertificate = userAttributes.certificateAlias } if (!TextUtils.isEmpty(userAttributes.externalSignalingServer)) { - user.externalSignalingServer = LoganSquare - .parse(userAttributes.externalSignalingServer, ExternalSignalingServer::class.java) + user.externalSignalingServer = + LoganSquare + .parse(userAttributes.externalSignalingServer, ExternalSignalingServer::class.java) } user.current = userAttributes.currentUser == true return user 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 26232c2a6ad..0fd2b9c2e6c 100644 --- a/app/src/main/java/com/nextcloud/talk/utils/AccountUtils.kt +++ b/app/src/main/java/com/nextcloud/talk/utils/AccountUtils.kt @@ -80,7 +80,7 @@ object AccountUtils { ( user.baseUrl == "http://" + importAccount.baseUrl || user.baseUrl == "https://" + importAccount.baseUrl - ) + ) ) { accountFound = true } @@ -97,12 +97,15 @@ object AccountUtils { val packageManager = context.packageManager var appName = "" try { - appName = packageManager.getApplicationLabel( - packageManager.getApplicationInfo( - packageName, - PackageManager.GET_META_DATA - ) - ) as String + appName = + packageManager + .getApplicationLabel( + packageManager + .getApplicationInfo( + packageName, + PackageManager.GET_META_DATA + ) + ) as String } catch (e: PackageManager.NameNotFoundException) { Log.e(TAG, "Failed to get app name based on package") } @@ -116,10 +119,12 @@ object AccountUtils { val packageInfo = pm.getPackageInfo(context.getString(R.string.nc_import_accounts_from), 0) if (packageInfo.versionCode >= MIN_SUPPORTED_FILES_APP_VERSION) { val ownSignatures = pm.getPackageInfo(context.packageName, PackageManager.GET_SIGNATURES).signatures - val filesAppSignatures = pm.getPackageInfo( - context.getString(R.string.nc_import_accounts_from), - PackageManager.GET_SIGNATURES - ).signatures + val filesAppSignatures = + pm + .getPackageInfo( + context.getString(R.string.nc_import_accounts_from), + PackageManager.GET_SIGNATURES + ).signatures return if (Arrays.equals(ownSignatures, filesAppSignatures)) { val accMgr = AccountManager.get(context) diff --git a/app/src/main/java/com/nextcloud/talk/utils/AudioUtils.kt b/app/src/main/java/com/nextcloud/talk/utils/AudioUtils.kt index 8151ad39e7e..9f3b0b604f2 100644 --- a/app/src/main/java/com/nextcloud/talk/utils/AudioUtils.kt +++ b/app/src/main/java/com/nextcloud/talk/utils/AudioUtils.kt @@ -45,10 +45,12 @@ object AudioUtils : DefaultLifecycleObserver { private const val VALUE_10 = 10 private const val TIME_LIMIT = 5000 private const val DEFAULT_SIZE = 500 + private enum class LifeCycleFlag { PAUSED, RESUMED } + private lateinit var currentLifeCycleFlag: LifeCycleFlag override fun onResume(owner: LifecycleOwner) { @@ -112,96 +114,102 @@ object AudioUtils : DefaultLifecycleObserver { * ******************************************************************************************** */ - mediaCodec.setCallback(object : MediaCodec.Callback() { - private var extractor: MediaExtractor? = null - val tempList = mutableListOf() - override fun onInputBufferAvailable(codec: MediaCodec, index: Int) { - // Setting up the extractor if not already done - if (extractor == null) { - extractor = MediaExtractor() - try { - extractor!!.setDataSource(path) - extractor!!.selectTrack(0) - } catch (e: IOException) { - e.printStackTrace() + mediaCodec.setCallback( + object : MediaCodec.Callback() { + private var extractor: MediaExtractor? = null + val tempList = mutableListOf() + + override fun onInputBufferAvailable(codec: MediaCodec, index: Int) { + // Setting up the extractor if not already done + if (extractor == null) { + extractor = MediaExtractor() + try { + extractor!!.setDataSource(path) + extractor!!.selectTrack(0) + } catch (e: IOException) { + e.printStackTrace() + } } - } - // Boiler plate, Extracts a buffer of encoded audio data to be sent to the codec for processing - val byteBuffer = codec.getInputBuffer(index) - if (byteBuffer != null) { - val sampleSize = extractor!!.readSampleData(byteBuffer, 0) - if (sampleSize > 0) { - val isOver = !extractor!!.advance() - codec.queueInputBuffer( - index, - 0, - sampleSize, - extractor!!.sampleTime, - if (isOver) MediaCodec.BUFFER_FLAG_END_OF_STREAM else 0 - ) + // Boiler plate, Extracts a buffer of encoded audio data to be sent to the codec for processing + val byteBuffer = codec.getInputBuffer(index) + if (byteBuffer != null) { + val sampleSize = extractor!!.readSampleData(byteBuffer, 0) + if (sampleSize > 0) { + val isOver = !extractor!!.advance() + codec.queueInputBuffer( + index, + 0, + sampleSize, + extractor!!.sampleTime, + if (isOver) MediaCodec.BUFFER_FLAG_END_OF_STREAM else 0 + ) + } } } - } - - override fun onOutputBufferAvailable(codec: MediaCodec, index: Int, info: MediaCodec.BufferInfo) { - // Boiler plate to get the audio data in a usable form - val outputBuffer = codec.getOutputBuffer(index) - val bufferFormat = codec.getOutputFormat(index) - val samples = outputBuffer!!.order(ByteOrder.nativeOrder()).asShortBuffer() - val numChannels = bufferFormat.getInteger(MediaFormat.KEY_CHANNEL_COUNT) - if (index < 0 || index >= numChannels) { - return - } - val sampleLength = (samples.remaining() / numChannels) - // Squeezes the value of each sample between [0,1) using y = (x-1)/x - for (i in 0 until sampleLength) { - val x = abs(samples[i * numChannels + index].toInt()) / VALUE_10 - val y = (if (x > 0) ((x - 1) / x.toFloat()) else x.toFloat()) - tempList.add(y) + override fun onOutputBufferAvailable(codec: MediaCodec, index: Int, info: MediaCodec.BufferInfo) { + // Boiler plate to get the audio data in a usable form + val outputBuffer = codec.getOutputBuffer(index) + val bufferFormat = codec.getOutputFormat(index) + val samples = outputBuffer!!.order(ByteOrder.nativeOrder()).asShortBuffer() + val numChannels = bufferFormat.getInteger(MediaFormat.KEY_CHANNEL_COUNT) + if (index < 0 || index >= numChannels) { + return + } + val sampleLength = (samples.remaining() / numChannels) + + // Squeezes the value of each sample between [0,1) using y = (x-1)/x + for (i in 0 until sampleLength) { + val x = abs(samples[i * numChannels + index].toInt()) / VALUE_10 + val y = (if (x > 0) ((x - 1) / x.toFloat()) else x.toFloat()) + tempList.add(y) + } + + codec.releaseOutputBuffer(index, false) + + // Cancels the process if it ends, exceeds the time limit, or the activity falls out of view + val currTime = SystemClock.elapsedRealtime() - startTime + if (info.flags and MediaCodec.BUFFER_FLAG_END_OF_STREAM > 0 || + currTime > TIME_LIMIT || + currentLifeCycleFlag == LifeCycleFlag.PAUSED + ) { + Log.d( + TAG, + "Processing ended with time: $currTime \n" + + "Is finished: ${info.flags and MediaCodec.BUFFER_FLAG_END_OF_STREAM > 0} \n" + + "Lifecycle state: $currentLifeCycleFlag" + ) + codec.stop() + codec.release() + extractor!!.release() + extractor = null + result = + if (currTime < TIME_LIMIT) { + tempList + } else { + Log.e( + TAG, + "Error in MediaCodec Callback:\n\tonOutputBufferAvailable: Time limit exceeded" + ) + null + } + } } - codec.releaseOutputBuffer(index, false) - - // Cancels the process if it ends, exceeds the time limit, or the activity falls out of view - val currTime = SystemClock.elapsedRealtime() - startTime - if (info.flags and MediaCodec.BUFFER_FLAG_END_OF_STREAM > 0 || - currTime > TIME_LIMIT || - currentLifeCycleFlag == LifeCycleFlag.PAUSED - ) { - Log.d( - TAG, - "Processing ended with time: $currTime \n" + - "Is finished: ${info.flags and MediaCodec.BUFFER_FLAG_END_OF_STREAM > 0} \n" + - "Lifecycle state: $currentLifeCycleFlag" - ) + override fun onError(codec: MediaCodec, e: CodecException) { + Log.e(TAG, "Error in MediaCodec Callback: \n$e") codec.stop() codec.release() extractor!!.release() extractor = null - result = if (currTime < TIME_LIMIT) { - tempList - } else { - Log.e(TAG, "Error in MediaCodec Callback:\n\tonOutputBufferAvailable: Time limit exceeded") - null - } + result = null + } + + override fun onOutputFormatChanged(codec: MediaCodec, format: MediaFormat) { + // unused atm } - } - - override fun onError(codec: MediaCodec, e: CodecException) { - Log.e(TAG, "Error in MediaCodec Callback: \n$e") - codec.stop() - codec.release() - extractor!!.release() - extractor = null - result = null - } - - override fun onOutputFormatChanged(codec: MediaCodec, format: MediaFormat) { - // unused atm - } - }) + }) // More Boiler plate to start the codec mediaFormat.setInteger(MediaFormat.KEY_PCM_ENCODING, AudioFormat.ENCODING_PCM_16BIT) diff --git a/app/src/main/java/com/nextcloud/talk/utils/BitmapShrinker.kt b/app/src/main/java/com/nextcloud/talk/utils/BitmapShrinker.kt index 7b457677211..23a10391100 100644 --- a/app/src/main/java/com/nextcloud/talk/utils/BitmapShrinker.kt +++ b/app/src/main/java/com/nextcloud/talk/utils/BitmapShrinker.kt @@ -34,21 +34,13 @@ object BitmapShrinker { private const val DEGREES_270 = 270f @JvmStatic - fun shrinkBitmap( - path: String, - reqWidth: Int, - reqHeight: Int - ): Bitmap { + fun shrinkBitmap(path: String, reqWidth: Int, reqHeight: Int): Bitmap { val bitmap = decodeBitmap(path, reqWidth, reqHeight) return rotateBitmap(path, bitmap) } // solution inspired by https://developer.android.com/topic/performance/graphics/load-bitmap - private fun decodeBitmap( - path: String, - requestedWidth: Int, - requestedHeight: Int - ): Bitmap { + private fun decodeBitmap(path: String, requestedWidth: Int, requestedHeight: Int): Bitmap { return BitmapFactory.Options().run { inJustDecodeBounds = true BitmapFactory.decodeFile(path, this) @@ -59,11 +51,7 @@ object BitmapShrinker { } // solution inspired by https://developer.android.com/topic/performance/graphics/load-bitmap - private fun getInSampleSize( - options: BitmapFactory.Options, - requestedWidth: Int, - requestedHeight: Int - ): Int { + private fun getInSampleSize(options: BitmapFactory.Options, requestedWidth: Int, requestedHeight: Int): Int { val (height: Int, width: Int) = options.run { outHeight to outWidth } var inSampleSize = 1 if (height > requestedHeight || width > requestedWidth) { @@ -94,7 +82,9 @@ object BitmapShrinker { matrix.postRotate(DEGREES_270) } } - val rotatedBitmap = Bitmap.createBitmap( + val rotatedBitmap = + Bitmap + .createBitmap( bitmap, 0, 0, diff --git a/app/src/main/java/com/nextcloud/talk/utils/ContactUtils.kt b/app/src/main/java/com/nextcloud/talk/utils/ContactUtils.kt index c7da1abd242..02bf48d6a0c 100644 --- a/app/src/main/java/com/nextcloud/talk/utils/ContactUtils.kt +++ b/app/src/main/java/com/nextcloud/talk/utils/ContactUtils.kt @@ -12,13 +12,16 @@ object ContactUtils { ContactsContract.CommonDataKinds.StructuredName.CONTACT_ID + " = ?" val whereNameParams = arrayOf(ContactsContract.CommonDataKinds.StructuredName.CONTENT_ITEM_TYPE, id) - val nameCursor = context.contentResolver.query( - ContactsContract.Data.CONTENT_URI, - null, - whereName, - whereNameParams, - ContactsContract.CommonDataKinds.StructuredName.GIVEN_NAME - ) + val nameCursor = + context + .contentResolver + .query( + ContactsContract.Data.CONTENT_URI, + null, + whereName, + whereNameParams, + ContactsContract.CommonDataKinds.StructuredName.GIVEN_NAME + ) if (nameCursor != null) { while (nameCursor.moveToNext()) { displayName = 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 a4c2414a8ec..acb85934240 100644 --- a/app/src/main/java/com/nextcloud/talk/utils/ConversationUtils.kt +++ b/app/src/main/java/com/nextcloud/talk/utils/ConversationUtils.kt @@ -60,9 +60,9 @@ object ConversationUtils { fun isLobbyViewApplicable(conversation: ConversationModel, conversationUser: User): Boolean { return !canModerate(conversation, conversationUser) && ( - conversation.type == ConversationType.ROOM_GROUP_CALL || + conversation.type == ConversationType.ROOM_GROUP_CALL|| conversation.type == ConversationType.ROOM_PUBLIC_CALL - ) + ) } fun isNameEditable(conversation: ConversationModel, conversationUser: User): Boolean { diff --git a/app/src/main/java/com/nextcloud/talk/utils/DateUtils.kt b/app/src/main/java/com/nextcloud/talk/utils/DateUtils.kt index 6f94209e2e7..db62160ffbf 100644 --- a/app/src/main/java/com/nextcloud/talk/utils/DateUtils.kt +++ b/app/src/main/java/com/nextcloud/talk/utils/DateUtils.kt @@ -35,18 +35,25 @@ class DateUtils(val context: Context) { private val cal = Calendar.getInstance() private val tz = cal.timeZone - /* date formatter in local timezone and locale */ - private var format: DateFormat = DateFormat.getDateTimeInstance( - DateFormat.DEFAULT, // dateStyle - DateFormat.SHORT, // timeStyle - context.resources.configuration.locales[0] - ) + // date formatter in local timezone and locale + private var format: DateFormat = + DateFormat + .getDateTimeInstance( + // dateStyle + DateFormat.DEFAULT, + // timeStyle + DateFormat.SHORT, + context.resources.configuration.locales[0] + ) - /* date formatter in local timezone and locale */ - private var formatTime: DateFormat = DateFormat.getTimeInstance( - DateFormat.SHORT, // timeStyle - context.resources.configuration.locales[0] - ) + // date formatter in local timezone and locale + private var formatTime: DateFormat = + DateFormat + .getTimeInstance( + // timeStyle + DateFormat.SHORT, + context.resources.configuration.locales[0] + ) init { format.timeZone = tz diff --git a/app/src/main/java/com/nextcloud/talk/utils/FileSortOrder.kt b/app/src/main/java/com/nextcloud/talk/utils/FileSortOrder.kt index f3bfffb1509..44d1f914c0b 100644 --- a/app/src/main/java/com/nextcloud/talk/utils/FileSortOrder.kt +++ b/app/src/main/java/com/nextcloud/talk/utils/FileSortOrder.kt @@ -41,14 +41,15 @@ open class FileSortOrder(var name: String, var isAscending: Boolean) { val sort_small_to_big: FileSortOrder = FileSortOrderBySize(sort_small_to_big_id, true) val sort_big_to_small: FileSortOrder = FileSortOrderBySize(sort_big_to_small_id, false) - val sortOrders: Map = mapOf( - sort_a_to_z.name to sort_a_to_z, - sort_z_to_a.name to sort_z_to_a, - sort_old_to_new.name to sort_old_to_new, - sort_new_to_old.name to sort_new_to_old, - sort_small_to_big.name to sort_small_to_big, - sort_big_to_small.name to sort_big_to_small - ) + val sortOrders: Map = + mapOf( + sort_a_to_z.name to sort_a_to_z, + sort_z_to_a.name to sort_z_to_a, + sort_old_to_new.name to sort_old_to_new, + sort_new_to_old.name to sort_new_to_old, + sort_small_to_big.name to sort_small_to_big, + sort_big_to_small.name to sort_big_to_small + ) fun getFileSortOrder(key: String?): FileSortOrder { return if (TextUtils.isEmpty(key) || !sortOrders.containsKey(key)) { diff --git a/app/src/main/java/com/nextcloud/talk/utils/FileUtils.kt b/app/src/main/java/com/nextcloud/talk/utils/FileUtils.kt index aeff10873fb..55c60322e54 100644 --- a/app/src/main/java/com/nextcloud/talk/utils/FileUtils.kt +++ b/app/src/main/java/com/nextcloud/talk/utils/FileUtils.kt @@ -94,20 +94,21 @@ object FileUtils { val fileName = getFileName(sourceFileUri, context) val scheme = sourceFileUri.scheme - val file = if (scheme == null) { - Log.d(TAG, "relative uri: " + sourceFileUri.path) - throw IllegalArgumentException("relative paths are not supported") - } else if (ContentResolver.SCHEME_CONTENT == scheme) { - copyFileToCache(context, sourceFileUri, fileName) - } else if (ContentResolver.SCHEME_FILE == scheme) { - if (sourceFileUri.path != null) { - sourceFileUri.path?.let { File(it) } + val file = + if (scheme == null) { + Log.d(TAG, "relative uri: " + sourceFileUri.path) + throw IllegalArgumentException("relative paths are not supported") + } else if (ContentResolver.SCHEME_CONTENT == scheme) { + copyFileToCache(context, sourceFileUri, fileName) + } else if (ContentResolver.SCHEME_FILE == scheme) { + if (sourceFileUri.path != null) { + sourceFileUri.path?.let { File(it) } + } else { + throw IllegalArgumentException("uri does not contain path") + } } else { - throw IllegalArgumentException("uri does not contain path") + throw IllegalArgumentException("unsupported scheme: " + sourceFileUri.path) } - } else { - throw IllegalArgumentException("unsupported scheme: " + sourceFileUri.path) - } return file } 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 99c8511b605..5a27e0bc35e 100644 --- a/app/src/main/java/com/nextcloud/talk/utils/FileViewerUtils.kt +++ b/app/src/main/java/com/nextcloud/talk/utils/FileViewerUtils.kt @@ -72,10 +72,7 @@ import java.util.concurrent.ExecutionException * - SharedItemsViewHolder */ class FileViewerUtils(private val context: Context, private val user: User) { - fun openFile( - message: ChatMessage, - progressUi: ProgressUi - ) { + fun openFile(message: ChatMessage, progressUi: ProgressUi) { val fileName = message.selectedIndividualHashMap!![PreviewMessageViewHolder.KEY_NAME]!! val mimetype = message.selectedIndividualHashMap!![PreviewMessageViewHolder.KEY_MIMETYPE]!! val link = message.selectedIndividualHashMap!!["link"]!! @@ -167,13 +164,16 @@ class FileViewerUtils(private val context: Context, private val user: User) { VIDEO_QUICKTIME, VIDEO_OGG -> openMediaView(filename, mimetype) + IMAGE_PNG, IMAGE_JPEG, IMAGE_GIF -> openImageView(filename, mimetype) + TEXT_MARKDOWN, TEXT_PLAIN -> openTextView(filename, mimetype) + else -> openFileByExternalApp(filename, mimetype) } @@ -207,17 +207,19 @@ class FileViewerUtils(private val context: Context, private val user: User) { } fun openFileInFilesApp(link: String, keyID: String) { - val accountString = user.username + "@" + - user.baseUrl - ?.replace("https://", "") - ?.replace("http://", "") + val accountString = + user.username + "@" + + user.baseUrl + ?.replace("https://", "") + ?.replace("http://", "") if (canWeOpenFilesApp(context, accountString)) { val filesAppIntent = Intent(Intent.ACTION_VIEW, null) - val componentName = ComponentName( - context.getString(R.string.nc_import_accounts_from), - "com.owncloud.android.ui.activity.FileDisplayActivity" - ) + val componentName = + ComponentName( + context.getString(R.string.nc_import_accounts_from), + "com.owncloud.android.ui.activity.FileDisplayActivity" + ) filesAppIntent.component = componentName filesAppIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK) filesAppIntent.setPackage(context.getString(R.string.nc_import_accounts_from)) @@ -225,10 +227,11 @@ class FileViewerUtils(private val context: Context, private val user: User) { filesAppIntent.putExtra(KEY_FILE_ID, keyID) context.startActivity(filesAppIntent) } else { - val browserIntent = Intent( - Intent.ACTION_VIEW, - Uri.parse(link) - ) + val browserIntent = + Intent( + Intent.ACTION_VIEW, + Uri.parse(link) + ) browserIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK) context.startActivity(browserIntent) } @@ -271,6 +274,7 @@ class FileViewerUtils(private val context: Context, private val user: User) { VIDEO_OGG, TEXT_MARKDOWN, TEXT_PLAIN -> true + else -> false } } @@ -299,28 +303,33 @@ class FileViewerUtils(private val context: Context, private val user: User) { } val downloadWorker: OneTimeWorkRequest - val size: Long = if (fileInfo.fileSize == null) { - -1 - } else { - fileInfo.fileSize!! - } + val size: Long = + if (fileInfo.fileSize == null) { + -1 + } else { + fileInfo.fileSize!! + } - val data: Data = Data.Builder() - .putString(DownloadFileToCacheWorker.KEY_BASE_URL, user.baseUrl) - .putString(DownloadFileToCacheWorker.KEY_USER_ID, user.userId) - .putString( - DownloadFileToCacheWorker.KEY_ATTACHMENT_FOLDER, - CapabilitiesUtilNew.getAttachmentFolder(user) - ) - .putString(DownloadFileToCacheWorker.KEY_FILE_NAME, fileInfo.fileName) - .putString(DownloadFileToCacheWorker.KEY_FILE_PATH, path) - .putLong(DownloadFileToCacheWorker.KEY_FILE_SIZE, size) - .build() - - downloadWorker = OneTimeWorkRequest.Builder(DownloadFileToCacheWorker::class.java) - .setInputData(data) - .addTag(fileInfo.fileId) - .build() + val data: Data = + Data + .Builder() + .putString(DownloadFileToCacheWorker.KEY_BASE_URL, user.baseUrl) + .putString(DownloadFileToCacheWorker.KEY_USER_ID, user.userId) + .putString( + DownloadFileToCacheWorker.KEY_ATTACHMENT_FOLDER, + CapabilitiesUtilNew.getAttachmentFolder(user) + ) + .putString(DownloadFileToCacheWorker.KEY_FILE_NAME, fileInfo.fileName) + .putString(DownloadFileToCacheWorker.KEY_FILE_PATH, path) + .putLong(DownloadFileToCacheWorker.KEY_FILE_SIZE, size) + .build() + + downloadWorker = + OneTimeWorkRequest + .Builder(DownloadFileToCacheWorker::class.java) + .setInputData(data) + .addTag(fileInfo.fileId) + .build() WorkManager.getInstance().enqueue(downloadWorker) progressUi.progressBar?.visibility = View.VISIBLE WorkManager.getInstance(context).getWorkInfoByIdLiveData(downloadWorker.id) @@ -346,13 +355,16 @@ class FileViewerUtils(private val context: Context, private val user: User) { WorkInfo.State.RUNNING -> { val progress = workInfo.progress.getInt(DownloadFileToCacheWorker.PROGRESS, -1) if (progress > -1) { - progressUi.messageText?.text = String.format( - context.resources.getString(R.string.filename_progress), - fileName, - progress - ) + progressUi.messageText?.text = + String + .format( + context.resources.getString(R.string.filename_progress), + fileName, + progress + ) } } + WorkInfo.State.SUCCEEDED -> { if (progressUi.previewImage.isShown && openWhenDownloaded) { openFileByMimetype(fileName, mimetype) @@ -367,10 +379,12 @@ class FileViewerUtils(private val context: Context, private val user: User) { progressUi.messageText?.text = fileName progressUi.progressBar?.visibility = View.GONE } + WorkInfo.State.FAILED -> { progressUi.messageText?.text = fileName progressUi.progressBar?.visibility = View.GONE } + else -> { } } diff --git a/app/src/main/java/com/nextcloud/talk/utils/ImageEmojiEditText.kt b/app/src/main/java/com/nextcloud/talk/utils/ImageEmojiEditText.kt index 2fa12d87b14..165c94fa1f4 100644 --- a/app/src/main/java/com/nextcloud/talk/utils/ImageEmojiEditText.kt +++ b/app/src/main/java/com/nextcloud/talk/utils/ImageEmojiEditText.kt @@ -39,7 +39,6 @@ Implementation based on this example: https://developer.android.com/guide/topics/text/image-keyboard */ class ImageEmojiEditText : EmojiEditText { - // Callback function to be called when the user selects an image, pass image Uri lateinit var onCommitContentListener: ((Uri) -> Unit) diff --git a/app/src/main/java/com/nextcloud/talk/utils/NotificationUtils.kt b/app/src/main/java/com/nextcloud/talk/utils/NotificationUtils.kt index a5682d9597f..26197156bb2 100644 --- a/app/src/main/java/com/nextcloud/talk/utils/NotificationUtils.kt +++ b/app/src/main/java/com/nextcloud/talk/utils/NotificationUtils.kt @@ -331,10 +331,7 @@ object NotificationUtils { ) } - fun getMessageRingtoneUri( - context: Context, - appPreferences: AppPreferences - ): Uri? { + fun getMessageRingtoneUri(context: Context, appPreferences: AppPreferences): Uri? { return getRingtoneUri( context, appPreferences.messageRingtoneUri, @@ -346,7 +343,9 @@ object NotificationUtils { fun loadAvatarSync(avatarUrl: String, context: Context): IconCompat? { var avatarIcon: IconCompat? = null - val request = ImageRequest.Builder(context) + val request = + ImageRequest + .Builder(context) .data(avatarUrl) .transformations(CircleCropTransformation()) .placeholder(R.drawable.account_circle_96dp) 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 dddb8753e5a..cfb066454f9 100644 --- a/app/src/main/java/com/nextcloud/talk/utils/ParticipantPermissions.kt +++ b/app/src/main/java/com/nextcloud/talk/utils/ParticipantPermissions.kt @@ -34,7 +34,6 @@ class ParticipantPermissions( private val user: User, private val conversation: ConversationModel ) { - @Deprecated("Use ChatRepository.ConversationModel") constructor(user: User, conversation: Conversation) : this( user, @@ -99,7 +98,6 @@ class ParticipantPermissions( } companion object { - val TAG = ParticipantPermissions::class.simpleName const val DEFAULT = 0 const val CUSTOM = 1 diff --git a/app/src/main/java/com/nextcloud/talk/utils/PickImage.kt b/app/src/main/java/com/nextcloud/talk/utils/PickImage.kt index 1900791f0f4..f796ba69373 100644 --- a/app/src/main/java/com/nextcloud/talk/utils/PickImage.kt +++ b/app/src/main/java/com/nextcloud/talk/utils/PickImage.kt @@ -106,21 +106,25 @@ class PickImage( } private fun handleAvatar(remotePath: String?) { - val uri = currentUser!!.baseUrl + "/index.php/apps/files/api/v1/thumbnail/512/512/" + - Uri.encode(remotePath, "/") - val downloadCall = ncApi.downloadResizedImage( - ApiUtils.getCredentials(currentUser!!.username, currentUser!!.token), - uri - ) - downloadCall.enqueue(object : Callback { - override fun onResponse(call: Call, response: Response) { - saveBitmapAndPassToImagePicker(BitmapFactory.decodeStream(response.body()!!.byteStream())) - } + val uri = + currentUser!!.baseUrl + "/index.php/apps/files/api/v1/thumbnail/512/512/" + + Uri.encode(remotePath, "/") + val downloadCall = + ncApi + .downloadResizedImage( + ApiUtils.getCredentials(currentUser!!.username, currentUser!!.token), + uri + ) + downloadCall.enqueue( + object : Callback { + override fun onResponse(call: Call, response: Response) { + saveBitmapAndPassToImagePicker(BitmapFactory.decodeStream(response.body()!!.byteStream())) + } - override fun onFailure(call: Call, t: Throwable) { - // unused atm - } - }) + override fun onFailure(call: Call, t: Throwable) { + // unused atm + } + }) } // only possible with API26 @@ -172,17 +176,20 @@ class PickImage( val uri: Uri = data?.data!! handleImage(uri) } + REQUEST_CODE_SELECT_REMOTE_FILES -> { val pathList = data?.getStringArrayListExtra(RemoteFileBrowserActivity.EXTRA_SELECTED_PATHS) if (pathList?.size!! >= 1) { handleAvatar(pathList[0]) } } + REQUEST_CODE_TAKE_PICTURE -> { data?.data?.path?.let { selectLocal(File(it)) } } + else -> { Log.w(TAG, "Unknown intent request code") } 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 5e7dbe4e1a7..e4381032f1a 100644 --- a/app/src/main/java/com/nextcloud/talk/utils/PushUtils.kt +++ b/app/src/main/java/com/nextcloud/talk/utils/PushUtils.kt @@ -82,13 +82,16 @@ class PushUtils { init { sharedApplication!!.componentApplication.inject(this) - val keyPath = sharedApplication!! - .getDir("PushKeystore", Context.MODE_PRIVATE) - .absolutePath + val keyPath = + sharedApplication!! + .getDir("PushKeystore", Context.MODE_PRIVATE) + .absolutePath publicKeyFile = File(keyPath, "push_key.pub") privateKeyFile = File(keyPath, "push_key.priv") - proxyServer = sharedApplication!! - .resources.getString(R.string.nc_push_server_url) + proxyServer = + sharedApplication!! + .resources + .getString(R.string.nc_push_server_url) } fun verifySignature(signatureBytes: ByteArray?, subjectBytes: ByteArray?): SignatureVerification { @@ -101,10 +104,11 @@ class PushUtils { var publicKey: PublicKey? for (user in users) { if (user.pushConfigurationState != null) { - publicKey = readKeyFromString( - true, - user.pushConfigurationState!!.userPublicKey - ) as PublicKey? + publicKey = + readKeyFromString( + true, + user.pushConfigurationState!!.userPublicKey + ) as PublicKey? signature.initVerify(publicKey) signature.update(subjectBytes) if (signature.verify(signatureBytes)) { @@ -237,58 +241,60 @@ class PushUtils { ApiUtils.getUrlNextcloudPush(user.baseUrl), nextcloudRegisterPushMap ) - .subscribe(object : Observer { - override fun onSubscribe(d: Disposable) { - // unused atm - } + .subscribe( + object : Observer { + override fun onSubscribe(d: Disposable) { + // unused atm + } - override fun onNext(pushRegistrationOverall: PushRegistrationOverall) { - Log.d(TAG, "pushTokenHash successfully registered at nextcloud server.") - val proxyMap: MutableMap = HashMap() - proxyMap["pushToken"] = token - proxyMap["deviceIdentifier"] = pushRegistrationOverall.ocs!!.data!!.deviceIdentifier - proxyMap["deviceIdentifierSignature"] = pushRegistrationOverall.ocs!!.data!!.signature - proxyMap["userPublicKey"] = pushRegistrationOverall.ocs!!.data!!.publicKey - registerDeviceWithPushProxy(ncApi, proxyMap, user) - } + override fun onNext(pushRegistrationOverall: PushRegistrationOverall) { + Log.d(TAG, "pushTokenHash successfully registered at nextcloud server.") + val proxyMap: MutableMap = HashMap() + proxyMap["pushToken"] = token + proxyMap["deviceIdentifier"] = pushRegistrationOverall.ocs!!.data!!.deviceIdentifier + proxyMap["deviceIdentifierSignature"] = pushRegistrationOverall.ocs!!.data!!.signature + proxyMap["userPublicKey"] = pushRegistrationOverall.ocs!!.data!!.publicKey + registerDeviceWithPushProxy(ncApi, proxyMap, user) + } - override fun onError(e: Throwable) { - Log.e(TAG, "Failed to register device with nextcloud", e) - eventBus!!.post(EventStatus(user.id!!, EventStatus.EventType.PUSH_REGISTRATION, false)) - } + override fun onError(e: Throwable) { + Log.e(TAG, "Failed to register device with nextcloud", e) + eventBus!!.post(EventStatus(user.id!!, EventStatus.EventType.PUSH_REGISTRATION, false)) + } - override fun onComplete() { - // unused atm - } - }) + override fun onComplete() { + // unused atm + } + }) } private fun registerDeviceWithPushProxy(ncApi: NcApi, proxyMap: Map, user: User) { ncApi.registerDeviceForNotificationsWithPushProxy(ApiUtils.getUrlPushProxy(), proxyMap) .subscribeOn(Schedulers.io()) - .subscribe(object : Observer { - override fun onSubscribe(d: Disposable) { - // unused atm - } + .subscribe( + object : Observer { + override fun onSubscribe(d: Disposable) { + // unused atm + } - override fun onNext(t: Unit) { - try { - Log.d(TAG, "pushToken successfully registered at pushproxy.") - updatePushStateForUser(proxyMap, user) - } catch (e: IOException) { - Log.e(TAG, "IOException while updating user", e) + override fun onNext(t: Unit) { + try { + Log.d(TAG, "pushToken successfully registered at pushproxy.") + updatePushStateForUser(proxyMap, user) + } catch (e: IOException) { + Log.e(TAG, "IOException while updating user", e) + } } - } - override fun onError(e: Throwable) { - Log.e(TAG, "Failed to register device with pushproxy", e) - eventBus!!.post(EventStatus(user.id!!, EventStatus.EventType.PUSH_REGISTRATION, false)) - } + override fun onError(e: Throwable) { + Log.e(TAG, "Failed to register device with pushproxy", e) + eventBus!!.post(EventStatus(user.id!!, EventStatus.EventType.PUSH_REGISTRATION, false)) + } - override fun onComplete() { - // unused atm - } - }) + override fun onComplete() { + // unused atm + } + }) } @Throws(IOException::class) @@ -300,32 +306,33 @@ class PushUtils { pushConfigurationState.userPublicKey = proxyMap["userPublicKey"] pushConfigurationState.usesRegularPass = java.lang.Boolean.FALSE if (user.id != null) { - userManager!!.updatePushState(user.id!!, pushConfigurationState).subscribe(object : SingleObserver { - override fun onSubscribe(d: Disposable) { - // unused atm - } + userManager!!.updatePushState(user.id!!, pushConfigurationState).subscribe( + object : SingleObserver { + override fun onSubscribe(d: Disposable) { + // unused atm + } - override fun onSuccess(integer: Int) { - eventBus!!.post( - EventStatus( - getIdForUser(user), - EventStatus.EventType.PUSH_REGISTRATION, - true + override fun onSuccess(integer: Int) { + eventBus!!.post( + EventStatus( + getIdForUser(user), + EventStatus.EventType.PUSH_REGISTRATION, + true + ) ) - ) - } + } - override fun onError(e: Throwable) { - Log.e(TAG, "update push state for user failed", e) - eventBus!!.post( - EventStatus( - getIdForUser(user), - EventStatus.EventType.PUSH_REGISTRATION, - false + override fun onError(e: Throwable) { + Log.e(TAG, "update push state for user failed", e) + eventBus!!.post( + EventStatus( + getIdForUser(user), + EventStatus.EventType.PUSH_REGISTRATION, + false + ) ) - ) - } - }) + } + }) } else { Log.e(TAG, "failed to update updatePushStateForUser. user.getId() was null") } @@ -333,17 +340,18 @@ class PushUtils { private fun readKeyFromString(readPublicKey: Boolean, keyString: String?): Key? { var keyString = keyString - keyString = if (readPublicKey) { - keyString!!.replace("\\n".toRegex(), "").replace( - "-----BEGIN PUBLIC KEY-----", - "" - ).replace("-----END PUBLIC KEY-----", "") - } else { - keyString!!.replace("\\n".toRegex(), "").replace( - "-----BEGIN PRIVATE KEY-----", - "" - ).replace("-----END PRIVATE KEY-----", "") - } + keyString = + if (readPublicKey) { + keyString!!.replace("\\n".toRegex(), "").replace( + "-----BEGIN PUBLIC KEY-----", + "" + ).replace("-----END PUBLIC KEY-----", "") + } else { + keyString!!.replace("\\n".toRegex(), "").replace( + "-----BEGIN PRIVATE KEY-----", + "" + ).replace("-----END PRIVATE KEY-----", "") + } var keyFactory: KeyFactory? = null try { keyFactory = KeyFactory.getInstance("RSA") @@ -364,11 +372,12 @@ class PushUtils { fun readKeyFromFile(readPublicKey: Boolean): Key? { val path: String - path = if (readPublicKey) { - publicKeyFile.absolutePath - } else { - privateKeyFile.absolutePath - } + path = + if (readPublicKey) { + publicKeyFile.absolutePath + } else { + privateKeyFile.absolutePath + } try { FileInputStream(path).use { fileInputStream -> val bytes = ByteArray(fileInputStream.available()) 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 4786997e445..2e3681f8893 100644 --- a/app/src/main/java/com/nextcloud/talk/utils/RemoteFileUtils.kt +++ b/app/src/main/java/com/nextcloud/talk/utils/RemoteFileUtils.kt @@ -31,11 +31,7 @@ import io.reactivex.schedulers.Schedulers object RemoteFileUtils { private val TAG = RemoteFileUtils::class.java.simpleName - fun getNewPathIfFileExists( - ncApi: NcApi, - currentUser: User, - remotePath: String - ): String { + fun getNewPathIfFileExists(ncApi: NcApi, currentUser: User, remotePath: String): String { var finalPath = remotePath val fileExists = doesFileExist( ncApi, @@ -53,11 +49,7 @@ object RemoteFileUtils { return finalPath } - private fun doesFileExist( - ncApi: NcApi, - currentUser: User, - remotePath: String - ): Observable { + private fun doesFileExist(ncApi: NcApi, currentUser: User, remotePath: String): Observable { return ncApi.checkIfFileExists( ApiUtils.getCredentials(currentUser.username, currentUser.token), ApiUtils.getUrlForFileUpload( @@ -72,11 +64,7 @@ object RemoteFileUtils { } } - private fun getFileNameWithoutCollision( - ncApi: NcApi, - currentUser: User, - remotePath: String - ): String { + private fun getFileNameWithoutCollision(ncApi: NcApi, currentUser: User, remotePath: String): String { val extPos = remotePath.lastIndexOf('.') var suffix: String var extension = "" 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 3aea9377225..41c64487835 100644 --- a/app/src/main/java/com/nextcloud/talk/utils/ShareUtils.kt +++ b/app/src/main/java/com/nextcloud/talk/utils/ShareUtils.kt @@ -25,11 +25,7 @@ import com.nextcloud.talk.data.user.model.User import com.nextcloud.talk.models.json.conversations.Conversation object ShareUtils { - fun getStringForIntent( - context: Context, - user: User, - conversation: Conversation? - ): String { + fun getStringForIntent(context: Context, user: User, conversation: Conversation?): 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/UriUtils.kt b/app/src/main/java/com/nextcloud/talk/utils/UriUtils.kt index e4d7cfaaf3b..f44cb2ce667 100644 --- a/app/src/main/java/com/nextcloud/talk/utils/UriUtils.kt +++ b/app/src/main/java/com/nextcloud/talk/utils/UriUtils.kt @@ -49,11 +49,10 @@ class UriUtils { fun isInstanceInternalFileUrl(baseUrl: String, url: String): Boolean { // https://cloud.nextcloud.com/apps/files/?dir=/Engineering&fileid=41 return ( - url.startsWith("$baseUrl/apps/files/") || - url.startsWith("$baseUrl/index.php/apps/files/") - ) && - Uri.parse(url).queryParameterNames.contains("fileid") && - Regex(""".*fileid=\d*""").matches(url) + url.startsWith("$baseUrl/apps/files/") || url.startsWith("$baseUrl/index.php/apps/files/") + ) + && Uri.parse(url).queryParameterNames.contains("fileid") + && Regex(""".*fileid=\d*""").matches(url) } fun isInstanceInternalFileUrlNew(baseUrl: String, url: String): Boolean { diff --git a/app/src/main/java/com/nextcloud/talk/utils/database/user/CurrentUserProviderImpl.kt b/app/src/main/java/com/nextcloud/talk/utils/database/user/CurrentUserProviderImpl.kt index 21aaa887502..75a425cacb0 100644 --- a/app/src/main/java/com/nextcloud/talk/utils/database/user/CurrentUserProviderImpl.kt +++ b/app/src/main/java/com/nextcloud/talk/utils/database/user/CurrentUserProviderImpl.kt @@ -30,8 +30,9 @@ import javax.inject.Inject /** * Listens to changes in the database and provides the current user without needing to query the database everytime. */ -class CurrentUserProviderImpl @Inject constructor(private val userManager: UserManager) : CurrentUserProviderNew { - +class CurrentUserProviderImpl +@Inject +constructor(private val userManager: UserManager) : CurrentUserProviderNew { private var _currentUser: User? = null // synchronized to avoid multiple observers initialized from different threads @@ -45,10 +46,12 @@ class CurrentUserProviderImpl @Inject constructor(private val userManager: UserM // immediately get a result synchronously _currentUser = userManager.currentUser.blockingGet() if (currentUserObserver == null) { - currentUserObserver = userManager.currentUserObservable - .subscribe { - _currentUser = it - } + currentUserObserver = + userManager + .currentUserObservable + .subscribe { + _currentUser = it + } } } return _currentUser?.let { Maybe.just(it) } ?: Maybe.empty() diff --git a/app/src/main/java/com/nextcloud/talk/utils/message/MessageUtils.kt b/app/src/main/java/com/nextcloud/talk/utils/message/MessageUtils.kt index 786d9f7f4a8..e96a0903fa7 100644 --- a/app/src/main/java/com/nextcloud/talk/utils/message/MessageUtils.kt +++ b/app/src/main/java/com/nextcloud/talk/utils/message/MessageUtils.kt @@ -95,14 +95,15 @@ class MessageUtils(val context: Context) { var processedMessageText = spannedText val messageParameters = message.messageParameters if (messageParameters != null && messageParameters.size > 0) { - processedMessageText = processMessageParameters( - themingContext, - viewThemeUtils, - messageParameters, - message, - processedMessageText, - itemView - ) + processedMessageText = + processMessageParameters( + themingContext, + viewThemeUtils, + messageParameters, + message, + processedMessageText, + itemView + ) } return processedMessageText } @@ -122,22 +123,25 @@ class MessageUtils(val context: Context) { if (individualHashMap != null) { when (individualHashMap["type"]) { "user", "guest", "call", "user-group" -> { - val chip = if (individualHashMap["id"] == message.activeUser!!.userId) { - R.xml.chip_you - } else { - R.xml.chip_others - } - messageStringInternal = DisplayUtils.searchAndReplaceWithMentionSpan( - key, - themingContext, - messageStringInternal, - individualHashMap["id"]!!, - individualHashMap["name"]!!, - individualHashMap["type"]!!, - message.activeUser!!, - chip, - viewThemeUtils - ) + val chip = + if (individualHashMap["id"] == message.activeUser!!.userId) { + R.xml.chip_you + } else { + R.xml.chip_others + } + messageStringInternal = + DisplayUtils + .searchAndReplaceWithMentionSpan( + key, + themingContext, + messageStringInternal, + individualHashMap["id"]!!, + individualHashMap["name"]!!, + individualHashMap["type"]!!, + message.activeUser!!, + chip, + viewThemeUtils + ) } "file" -> { @@ -155,19 +159,21 @@ class MessageUtils(val context: Context) { fun getRenderedMarkdownText(context: Context, markdown: String, textColor: Int): Spanned { val drawable = TaskListDrawable(textColor, textColor, context.getColor(R.color.bg_default)) - val markwon = Markwon.builder(context).usePlugin(object : AbstractMarkwonPlugin() { - override fun configureTheme(builder: MarkwonTheme.Builder) { - builder.isLinkUnderlined(true).headingBreakHeight(0) - } + val markwon = + Markwon.builder(context).usePlugin( + object : AbstractMarkwonPlugin() { + override fun configureTheme(builder: MarkwonTheme.Builder) { + builder.isLinkUnderlined(true).headingBreakHeight(0) + } - override fun configureConfiguration(builder: MarkwonConfiguration.Builder) { - builder.linkResolver { view: View?, link: String? -> - Log.i(TAG, "Link action not implemented $view / $link") - } - } - }) - .usePlugin(TaskListPlugin.create(drawable)) - .usePlugin(StrikethroughPlugin.create()).build() + override fun configureConfiguration(builder: MarkwonConfiguration.Builder) { + builder.linkResolver { view: View?, link: String? -> + Log.i(TAG, "Link action not implemented $view / $link") + } + } + }) + .usePlugin(TaskListPlugin.create(drawable)) + .usePlugin(StrikethroughPlugin.create()).build() return markwon.toMarkdown(markdown) } diff --git a/app/src/main/java/com/nextcloud/talk/utils/permissions/PlatformPermissionUtil.kt b/app/src/main/java/com/nextcloud/talk/utils/permissions/PlatformPermissionUtil.kt index 51085108aff..963ba087b72 100644 --- a/app/src/main/java/com/nextcloud/talk/utils/permissions/PlatformPermissionUtil.kt +++ b/app/src/main/java/com/nextcloud/talk/utils/permissions/PlatformPermissionUtil.kt @@ -23,9 +23,14 @@ package com.nextcloud.talk.utils.permissions interface PlatformPermissionUtil { val privateBroadcastPermission: String + fun isCameraPermissionGranted(): Boolean + fun isMicrophonePermissionGranted(): Boolean + fun isBluetoothPermissionGranted(): Boolean + fun isFilesPermissionGranted(): Boolean + fun isPostNotificationsPermissionGranted(): Boolean } diff --git a/app/src/main/java/com/nextcloud/talk/utils/preferences/AppPreferencesImpl.kt b/app/src/main/java/com/nextcloud/talk/utils/preferences/AppPreferencesImpl.kt index a1d893c27e7..0f7075c516e 100644 --- a/app/src/main/java/com/nextcloud/talk/utils/preferences/AppPreferencesImpl.kt +++ b/app/src/main/java/com/nextcloud/talk/utils/preferences/AppPreferencesImpl.kt @@ -45,13 +45,14 @@ class AppPreferencesImpl(val context: Context) : AppPreferences { }.getCompleted() } - override fun setProxyType(proxyType: String?) = runBlocking { - async { - if (proxyType != null) { - writeString(PROXY_TYPE, proxyType) + override fun setProxyType(proxyType: String?) = + runBlocking { + async { + if (proxyType != null) { + writeString(PROXY_TYPE, proxyType) + } } } - } override fun removeProxyType() { proxyType = "" @@ -61,13 +62,14 @@ class AppPreferencesImpl(val context: Context) : AppPreferences { return runBlocking { async { readString(PROXY_HOST).first() } }.getCompleted() } - override fun setProxyHost(proxyHost: String?) = runBlocking { - async { - if (proxyHost != null) { - writeString(PROXY_HOST, proxyHost) + override fun setProxyHost(proxyHost: String?) = + runBlocking { + async { + if (proxyHost != null) { + writeString(PROXY_HOST, proxyHost) + } } } - } override fun removeProxyHost() { proxyHost = "" @@ -77,13 +79,14 @@ class AppPreferencesImpl(val context: Context) : AppPreferences { return runBlocking { async { readString(PROXY_PORT).first() } }.getCompleted() } - override fun setProxyPort(proxyPort: String?) = runBlocking { - async { - if (proxyPort != null) { - writeString(PROXY_PORT, proxyPort) + override fun setProxyPort(proxyPort: String?) = + runBlocking { + async { + if (proxyPort != null) { + writeString(PROXY_PORT, proxyPort) + } } } - } override fun removeProxyPort() { proxyPort = "" @@ -93,11 +96,12 @@ class AppPreferencesImpl(val context: Context) : AppPreferences { return runBlocking { async { readBoolean(PROXY_CRED).first() } }.getCompleted() } - override fun setProxyNeedsCredentials(proxyNeedsCredentials: Boolean) = runBlocking { - async { - writeBoolean(PROXY_CRED, proxyNeedsCredentials) + override fun setProxyNeedsCredentials(proxyNeedsCredentials: Boolean) = + runBlocking { + async { + writeBoolean(PROXY_CRED, proxyNeedsCredentials) + } } - } override fun removeProxyCredentials() { setProxyNeedsCredentials(false) @@ -107,13 +111,14 @@ class AppPreferencesImpl(val context: Context) : AppPreferences { return runBlocking { async { readString(PROXY_USERNAME).first() } }.getCompleted() } - override fun setProxyUsername(proxyUsername: String?) = runBlocking { - async { - if (proxyUsername != null) { - writeString(PROXY_USERNAME, proxyUsername) + override fun setProxyUsername(proxyUsername: String?) = + runBlocking { + async { + if (proxyUsername != null) { + writeString(PROXY_USERNAME, proxyUsername) + } } } - } override fun removeProxyUsername() { proxyUsername = "" @@ -123,13 +128,14 @@ class AppPreferencesImpl(val context: Context) : AppPreferences { return runBlocking { async { readString(PROXY_PASSWORD).first() } }.getCompleted() } - override fun setProxyPassword(proxyPassword: String?) = runBlocking { - async { - if (proxyPassword != null) { - writeString(PROXY_PASSWORD, proxyPassword) + override fun setProxyPassword(proxyPassword: String?) = + runBlocking { + async { + if (proxyPassword != null) { + writeString(PROXY_PASSWORD, proxyPassword) + } } } - } override fun removeProxyPassword() { proxyPassword = "" @@ -139,13 +145,14 @@ class AppPreferencesImpl(val context: Context) : AppPreferences { return runBlocking { async { readString(PUSH_TOKEN).first() } }.getCompleted() } - override fun setPushToken(pushToken: String?) = runBlocking { - async { - if (pushToken != null) { - writeString(PUSH_TOKEN, pushToken) + override fun setPushToken(pushToken: String?) = + runBlocking { + async { + if (pushToken != null) { + writeString(PUSH_TOKEN, pushToken) + } } } - } override fun removePushToken() { pushToken = "" @@ -155,13 +162,14 @@ class AppPreferencesImpl(val context: Context) : AppPreferences { return runBlocking { async { readString(TEMP_CLIENT_CERT_ALIAS).first() } }.getCompleted() } - override fun setTemporaryClientCertAlias(alias: String?) = runBlocking { - async { - if (alias != null) { - writeString(TEMP_CLIENT_CERT_ALIAS, alias) + override fun setTemporaryClientCertAlias(alias: String?) = + runBlocking { + async { + if (alias != null) { + writeString(TEMP_CLIENT_CERT_ALIAS, alias) + } } } - } override fun removeTemporaryClientCertAlias() { temporaryClientCertAlias = "" @@ -171,11 +179,12 @@ class AppPreferencesImpl(val context: Context) : AppPreferences { return runBlocking { async { readBoolean(PUSH_TO_TALK_INTRO_SHOWN).first() } }.getCompleted() } - override fun setPushToTalkIntroShown(shown: Boolean) = runBlocking { - async { - writeBoolean(PUSH_TO_TALK_INTRO_SHOWN, shown) + override fun setPushToTalkIntroShown(shown: Boolean) = + runBlocking { + async { + writeBoolean(PUSH_TO_TALK_INTRO_SHOWN, shown) + } } - } override fun removePushToTalkIntroShown() { pushToTalkIntroShown = false @@ -185,13 +194,14 @@ class AppPreferencesImpl(val context: Context) : AppPreferences { return runBlocking { async { readString(CALL_RINGTONE).first() } }.getCompleted() } - override fun setCallRingtoneUri(value: String?) = runBlocking { - async { - if (value != null) { - writeString(CALL_RINGTONE, value) + override fun setCallRingtoneUri(value: String?) = + runBlocking { + async { + if (value != null) { + writeString(CALL_RINGTONE, value) + } } } - } override fun removeCallRingtoneUri() { callRingtoneUri = "" @@ -201,13 +211,14 @@ class AppPreferencesImpl(val context: Context) : AppPreferences { return runBlocking { async { readString(MESSAGE_RINGTONE).first() } }.getCompleted() } - override fun setMessageRingtoneUri(value: String?) = runBlocking { - async { - if (value != null) { - writeString(MESSAGE_RINGTONE, value) + override fun setMessageRingtoneUri(value: String?) = + runBlocking { + async { + if (value != null) { + writeString(MESSAGE_RINGTONE, value) + } } } - } override fun removeMessageRingtoneUri() { messageRingtoneUri = "" @@ -217,11 +228,12 @@ class AppPreferencesImpl(val context: Context) : AppPreferences { return runBlocking { async { readBoolean(NOTIFY_UPGRADE_V2).first() } }.getCompleted() } - override fun setNotificationChannelIsUpgradedToV2(value: Boolean) = runBlocking { - async { - writeBoolean(NOTIFY_UPGRADE_V2, value) + override fun setNotificationChannelIsUpgradedToV2(value: Boolean) = + runBlocking { + async { + writeBoolean(NOTIFY_UPGRADE_V2, value) + } } - } override fun removeNotificationChannelUpgradeToV2() { setNotificationChannelIsUpgradedToV2(false) @@ -231,11 +243,12 @@ class AppPreferencesImpl(val context: Context) : AppPreferences { return runBlocking { async { readBoolean(NOTIFY_UPGRADE_V3).first() } }.getCompleted() } - override fun setNotificationChannelIsUpgradedToV3(value: Boolean) = runBlocking { - async { - writeBoolean(NOTIFY_UPGRADE_V3, value) + override fun setNotificationChannelIsUpgradedToV3(value: Boolean) = + runBlocking { + async { + writeBoolean(NOTIFY_UPGRADE_V3, value) + } } - } override fun removeNotificationChannelUpgradeToV3() { setNotificationChannelIsUpgradedToV3(false) @@ -245,11 +258,12 @@ class AppPreferencesImpl(val context: Context) : AppPreferences { return runBlocking { async { readBoolean(SCREEN_SECURITY).first() } }.getCompleted() } - override fun setScreenSecurity(value: Boolean) = runBlocking { - async { - writeBoolean(SCREEN_SECURITY, value) + override fun setScreenSecurity(value: Boolean) = + runBlocking { + async { + writeBoolean(SCREEN_SECURITY, value) + } } - } override fun removeScreenSecurity() { setScreenSecurity(false) @@ -259,11 +273,12 @@ class AppPreferencesImpl(val context: Context) : AppPreferences { return runBlocking { async { readBoolean(SCREEN_LOCK).first() } }.getCompleted() } - override fun setScreenLock(value: Boolean) = runBlocking { - async { - writeBoolean(SCREEN_LOCK, value) + override fun setScreenLock(value: Boolean) = + runBlocking { + async { + writeBoolean(SCREEN_LOCK, value) + } } - } override fun removeScreenLock() { setScreenLock(false) @@ -274,11 +289,12 @@ class AppPreferencesImpl(val context: Context) : AppPreferences { return read } - override fun setIncognitoKeyboard(value: Boolean) = runBlocking { - async { - writeBoolean(INCOGNITO_KEYBOARD, value) + override fun setIncognitoKeyboard(value: Boolean) = + runBlocking { + async { + writeBoolean(INCOGNITO_KEYBOARD, value) + } } - } override fun removeIncognitoKeyboard() { setIncognitoKeyboard(false) @@ -288,17 +304,19 @@ class AppPreferencesImpl(val context: Context) : AppPreferences { return runBlocking { async { readBoolean(PHONE_BOOK_INTEGRATION).first() } }.getCompleted() } - override fun setPhoneBookIntegration(value: Boolean) = runBlocking { - async { - writeBoolean(PHONE_BOOK_INTEGRATION, value) + override fun setPhoneBookIntegration(value: Boolean) = + runBlocking { + async { + writeBoolean(PHONE_BOOK_INTEGRATION, value) + } } - } - override fun removeLinkPreviews() = runBlocking { - async { - writeBoolean(LINK_PREVIEWS, false) + override fun removeLinkPreviews() = + runBlocking { + async { + writeBoolean(LINK_PREVIEWS, false) + } } - } override fun getScreenLockTimeout(): String { val default = context.resources.getString(R.string.nc_screen_lock_timeout_sixty) @@ -306,13 +324,14 @@ class AppPreferencesImpl(val context: Context) : AppPreferences { return read.ifEmpty { default } } - override fun setScreenLockTimeout(value: String?) = runBlocking { - async { - if (value != null) { - writeString(SCREEN_LOCK_TIMEOUT, value) + override fun setScreenLockTimeout(value: String?) = + runBlocking { + async { + if (value != null) { + writeString(SCREEN_LOCK_TIMEOUT, value) + } } } - } override fun removeScreenLockTimeout() { screenLockTimeout = "" @@ -325,14 +344,15 @@ class AppPreferencesImpl(val context: Context) : AppPreferences { return read.ifEmpty { default } } - override fun setTheme(value: String?) = runBlocking { - async { - if (value != null) { - val key = context.resources.getString(R.string.nc_settings_theme_key) - writeString(key, value) + override fun setTheme(value: String?) = + runBlocking { + async { + if (value != null) { + val key = context.resources.getString(R.string.nc_settings_theme_key) + writeString(key, value) + } } } - } override fun removeTheme() { theme = "" @@ -343,27 +363,30 @@ class AppPreferencesImpl(val context: Context) : AppPreferences { return read } - override fun setDbCypherToUpgrade(value: Boolean) = runBlocking { - async { - writeBoolean(DB_CYPHER_V4_UPGRADE, value) + override fun setDbCypherToUpgrade(value: Boolean) = + runBlocking { + async { + writeBoolean(DB_CYPHER_V4_UPGRADE, value) + } } - } override fun getIsDbRoomMigrated(): Boolean { return runBlocking { async { readBoolean(DB_ROOM_MIGRATED).first() } }.getCompleted() } - override fun setIsDbRoomMigrated(value: Boolean) = runBlocking { - async { - writeBoolean(DB_ROOM_MIGRATED, value) + override fun setIsDbRoomMigrated(value: Boolean) = + runBlocking { + async { + writeBoolean(DB_ROOM_MIGRATED, value) + } } - } - override fun setPhoneBookIntegrationLastRun(currentTimeMillis: Long) = runBlocking { - async { - writeLong(PHONE_BOOK_INTEGRATION_LAST_RUN, currentTimeMillis) + override fun setPhoneBookIntegrationLastRun(currentTimeMillis: Long) = + runBlocking { + async { + writeLong(PHONE_BOOK_INTEGRATION_LAST_RUN, currentTimeMillis) + } } - } override fun getPhoneBookIntegrationLastRun(defaultValue: Long?): Long { val result = if (defaultValue != null) { @@ -387,24 +410,26 @@ class AppPreferencesImpl(val context: Context) : AppPreferences { return runBlocking { async { readBoolean(key).first() } }.getCompleted() } - override fun setTypingStatus(value: Boolean) = runBlocking { - async { - writeBoolean(TYPING_STATUS, value) + override fun setTypingStatus(value: Boolean) = + runBlocking { + async { + writeBoolean(TYPING_STATUS, value) + } } - } override fun getTypingStatus(): Boolean { return runBlocking { async { readBoolean(TYPING_STATUS).first() } }.getCompleted() } - override fun setSorting(value: String?) = runBlocking { - val key = context.resources.getString(R.string.nc_file_browser_sort_by_key) - async { - if (value != null) { - writeString(key, value) + override fun setSorting(value: String?) = + runBlocking { + val key = context.resources.getString(R.string.nc_file_browser_sort_by_key) + async { + if (value != null) { + writeString(key, value) + } } } - } override fun getSorting(): String { val key = context.resources.getString(R.string.nc_file_browser_sort_by_key) @@ -413,11 +438,12 @@ class AppPreferencesImpl(val context: Context) : AppPreferences { return read.ifEmpty { default } } - override fun saveWaveFormForFile(filename: String, array: Array) = runBlocking { - async { - writeString(filename, array.contentToString()) + override fun saveWaveFormForFile(filename: String, array: Array) = + runBlocking { + async { + writeString(filename, array.contentToString()) + } } - } override fun getWaveFormFromFile(filename: String): Array { val string = runBlocking { async { readString(filename).first() } }.getCompleted() @@ -426,29 +452,32 @@ class AppPreferencesImpl(val context: Context) : AppPreferences { override fun clear() {} - private suspend fun writeString(key: String, value: String) = context.dataStore.edit { settings -> - settings[ - stringPreferencesKey( - key - ) - ] = value - } + private suspend fun writeString(key: String, value: String) = + context.dataStore.edit { settings -> + settings[ + stringPreferencesKey( + key + ) + ] = value + } /** * Returns a Flow of type String * @param key the key of the persisted data to be observed */ - fun readString(key: String, defaultValue: String = ""): Flow = context.dataStore.data.map { preferences -> - preferences[stringPreferencesKey(key)] ?: defaultValue - } + fun readString(key: String, defaultValue: String = ""): Flow = + context.dataStore.data.map { preferences -> + preferences[stringPreferencesKey(key)] ?: defaultValue + } - private suspend fun writeBoolean(key: String, value: Boolean) = context.dataStore.edit { settings -> - settings[ - booleanPreferencesKey( - key - ) - ] = value - } + private suspend fun writeBoolean(key: String, value: Boolean) = + context.dataStore.edit { settings -> + settings[ + booleanPreferencesKey( + key + ) + ] = value + } /** * Returns a Flow of type Boolean @@ -459,17 +488,19 @@ class AppPreferencesImpl(val context: Context) : AppPreferences { preferences[booleanPreferencesKey(key)] ?: defaultValue } - private suspend fun writeLong(key: String, value: Long) = context.dataStore.edit { settings -> - settings[ - longPreferencesKey( - key - ) - ] = value - } + private suspend fun writeLong(key: String, value: Long) = + context.dataStore.edit { settings -> + settings[ + longPreferencesKey( + key + ) + ] = value + } - private fun readLong(key: String, defaultValue: Long = 0): Flow = context.dataStore.data.map { preferences -> - preferences[longPreferencesKey(key)] ?: defaultValue - } + private fun readLong(key: String, defaultValue: Long = 0): Flow = + context.dataStore.data.map { preferences -> + preferences[longPreferencesKey(key)] ?: defaultValue + } companion object { @Suppress("UnusedPrivateProperty") @@ -499,6 +530,7 @@ class AppPreferencesImpl(val context: Context) : AppPreferences { const val DB_ROOM_MIGRATED = "db_room_migrated" const val PHONE_BOOK_INTEGRATION_LAST_RUN = "phone_book_integration_last_run" const val TYPING_STATUS = "typing_status" + private fun String.convertStringToArray(): Array { var varString = this val floatList = mutableListOf() diff --git a/app/src/main/java/com/nextcloud/talk/utils/rx/SearchViewObservable.kt b/app/src/main/java/com/nextcloud/talk/utils/rx/SearchViewObservable.kt index 2d84fbffa80..afcd8665e9a 100644 --- a/app/src/main/java/com/nextcloud/talk/utils/rx/SearchViewObservable.kt +++ b/app/src/main/java/com/nextcloud/talk/utils/rx/SearchViewObservable.kt @@ -30,17 +30,18 @@ class SearchViewObservable { @JvmStatic fun observeSearchView(searchView: SearchView): Observable { val subject: PublishSubject = PublishSubject.create() - searchView.setOnQueryTextListener(object : SearchView.OnQueryTextListener { - override fun onQueryTextSubmit(query: String): Boolean { - subject.onComplete() - return true - } + searchView.setOnQueryTextListener( + object : SearchView.OnQueryTextListener { + override fun onQueryTextSubmit(query: String): Boolean { + subject.onComplete() + return true + } - override fun onQueryTextChange(newText: String): Boolean { - subject.onNext(newText) - return true - } - }) + override fun onQueryTextChange(newText: String): Boolean { + subject.onNext(newText) + return true + } + }) return subject } } diff --git a/app/src/main/java/com/nextcloud/talk/utils/ssl/SSLSocketFactoryCompat.kt b/app/src/main/java/com/nextcloud/talk/utils/ssl/SSLSocketFactoryCompat.kt index e4a2a845cee..7ecb7a8d79a 100644 --- a/app/src/main/java/com/nextcloud/talk/utils/ssl/SSLSocketFactoryCompat.kt +++ b/app/src/main/java/com/nextcloud/talk/utils/ssl/SSLSocketFactoryCompat.kt @@ -54,11 +54,11 @@ class SSLSocketFactoryCompat( } } - override fun getDefaultCipherSuites(): Array? = cipherSuites - ?: delegate.defaultCipherSuites + override fun getDefaultCipherSuites(): Array? = + cipherSuites ?: delegate.defaultCipherSuites - override fun getSupportedCipherSuites(): Array? = cipherSuites - ?: delegate.supportedCipherSuites + override fun getSupportedCipherSuites(): Array? = + cipherSuites ?: delegate.supportedCipherSuites override fun createSocket(s: Socket, host: String, port: Int, autoClose: Boolean): Socket { val ssl = delegate.createSocket(s, host, port, autoClose) diff --git a/app/src/main/java/com/nextcloud/talk/viewmodels/CallRecordingViewModel.kt b/app/src/main/java/com/nextcloud/talk/viewmodels/CallRecordingViewModel.kt index 3cff3d02b55..683fc392a5b 100644 --- a/app/src/main/java/com/nextcloud/talk/viewmodels/CallRecordingViewModel.kt +++ b/app/src/main/java/com/nextcloud/talk/viewmodels/CallRecordingViewModel.kt @@ -34,8 +34,9 @@ import io.reactivex.disposables.Disposable import io.reactivex.schedulers.Schedulers import javax.inject.Inject -class CallRecordingViewModel @Inject constructor(private val repository: CallRecordingRepository) : ViewModel() { - +class CallRecordingViewModel +@Inject +constructor(private val repository: CallRecordingRepository) : ViewModel() { @Inject lateinit var userManager: UserManager @@ -45,9 +46,13 @@ class CallRecordingViewModel @Inject constructor(private val repository: CallRec open class RecordingStartedState(val hasVideo: Boolean, val showStartedInfo: Boolean) : ViewState object RecordingStoppedState : ViewState + open class RecordingStartingState(val hasVideo: Boolean) : ViewState + object RecordingStoppingState : ViewState + object RecordingConfirmStopState : ViewState + object RecordingErrorState : ViewState private val _viewState: MutableLiveData = MutableLiveData(RecordingStoppedState) @@ -61,20 +66,25 @@ class CallRecordingViewModel @Inject constructor(private val repository: CallRec is RecordingStartedState -> { _viewState.value = RecordingConfirmStopState } + RecordingStoppedState -> { startRecording() } + RecordingConfirmStopState -> { // confirm dialog to stop recording might have been dismissed without to click an action. // just show it again. _viewState.value = RecordingConfirmStopState } + is RecordingStartingState -> { stopRecording() } + RecordingErrorState -> { stopRecording() } + else -> {} } } 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 d66d9059c8d..d1ac09f9f1e 100644 --- a/app/src/main/java/com/nextcloud/talk/viewmodels/GeoCodingViewModel.kt +++ b/app/src/main/java/com/nextcloud/talk/viewmodels/GeoCodingViewModel.kt @@ -40,6 +40,7 @@ class GeoCodingViewModel : ViewModel() { private val okHttpClient: OkHttpClient = OkHttpClient.Builder().build() private var geocodingResults: List
= ArrayList() private var query: String = "" + fun getGeocodingResultsLiveData(): LiveData> { return geocodingResultsLiveData } @@ -57,11 +58,12 @@ class GeoCodingViewModel : ViewModel() { } init { - nominatimClient = TalkJsonNominatimClient( - "https://nominatim.openstreetmap.org/", - okHttpClient, - " android@nextcloud.com" - ) + nominatimClient = + TalkJsonNominatimClient( + "https://nominatim.openstreetmap.org/", + okHttpClient, + " android@nextcloud.com" + ) } fun searchLocation() { diff --git a/app/src/main/java/com/nextcloud/talk/webrtc/WebSocketInstance.kt b/app/src/main/java/com/nextcloud/talk/webrtc/WebSocketInstance.kt index 7e4c5b4ac81..21d872a6f87 100644 --- a/app/src/main/java/com/nextcloud/talk/webrtc/WebSocketInstance.kt +++ b/app/src/main/java/com/nextcloud/talk/webrtc/WebSocketInstance.kt @@ -323,10 +323,12 @@ class WebSocketInstance internal constructor( isConnected = true reconnecting = false val oldResumeId = resumeId - val (_, helloResponseWebSocketMessage1) = LoganSquare.parse( - text, - HelloResponseOverallWebSocketMessage::class.java - ) + val (_, helloResponseWebSocketMessage1) = + LoganSquare + .parse( + text, + HelloResponseOverallWebSocketMessage::class.java + ) if (helloResponseWebSocketMessage1 != null) { resumeId = helloResponseWebSocketMessage1.resumeId sessionId = helloResponseWebSocketMessage1.sessionId @@ -382,9 +384,11 @@ class WebSocketInstance internal constructor( Log.d(TAG, " roomToken: $roomToken") Log.d(TAG, " session: $normalBackendSession") try { - val message = LoganSquare.serialize( - webSocketConnectionHelper.getAssembledJoinOrLeaveRoomModel(roomToken, normalBackendSession) - ) + val message = + LoganSquare + .serialize( + webSocketConnectionHelper.getAssembledJoinOrLeaveRoomModel(roomToken, normalBackendSession) + ) if (roomToken == "") { Log.d(TAG, "sending 'leave room' via websocket") currentNormalBackendSession = "" @@ -404,9 +408,11 @@ class WebSocketInstance internal constructor( private fun sendCallMessage(ncSignalingMessage: NCSignalingMessage) { try { - val message = LoganSquare.serialize( - webSocketConnectionHelper.getAssembledCallMessageModel(ncSignalingMessage) - ) + val message = + LoganSquare + .serialize( + webSocketConnectionHelper.getAssembledCallMessageModel(ncSignalingMessage) + ) sendMessage(message) } catch (e: IOException) { Log.e(TAG, "Failed to serialize signaling message", e) diff --git a/app/src/main/java/third/parties/fresco/BetterImageSpan.kt b/app/src/main/java/third/parties/fresco/BetterImageSpan.kt index fbd003ed0e7..5c39dad086f 100644 --- a/app/src/main/java/third/parties/fresco/BetterImageSpan.kt +++ b/app/src/main/java/third/parties/fresco/BetterImageSpan.kt @@ -45,94 +45,97 @@ import androidx.annotation.IntDef * DynamicDrawableSpan (ImageSpan's parent) adjusts sizes as if alignment was ALIGN_BASELINE * which can lead to unnecessary whitespace. */ -open class BetterImageSpan @JvmOverloads constructor( - val drawable: Drawable, - @param:BetterImageSpanAlignment private val mAlignment: Int = ALIGN_BASELINE -) : ReplacementSpan() { - @IntDef(*[ALIGN_BASELINE, ALIGN_BOTTOM, ALIGN_CENTER]) - @Retention(AnnotationRetention.SOURCE) - annotation class BetterImageSpanAlignment +open class BetterImageSpan + @JvmOverloads + constructor( + val drawable: Drawable, + @param:BetterImageSpanAlignment private val mAlignment: Int = ALIGN_BASELINE + ) : ReplacementSpan() { + @IntDef(*[ALIGN_BASELINE, ALIGN_BOTTOM, ALIGN_CENTER]) + @Retention(AnnotationRetention.SOURCE) + annotation class BetterImageSpanAlignment - private var mWidth = 0 - private var mHeight = 0 - private var mBounds: Rect? = null - private val mFontMetricsInt = FontMetricsInt() + private var mWidth = 0 + private var mHeight = 0 + private var mBounds: Rect? = null + private val mFontMetricsInt = FontMetricsInt() - init { - updateBounds() - } + init { + updateBounds() + } - /** - * Returns the width of the image span and increases the height if font metrics are available. - */ - override fun getSize( - paint: Paint, - text: CharSequence, - start: Int, - end: Int, - fontMetrics: FontMetricsInt? - ): Int { - updateBounds() - if (fontMetrics == null) { + /** + * Returns the width of the image span and increases the height if font metrics are available. + */ + override fun getSize( + paint: Paint, + text: CharSequence, + start: Int, + end: Int, + fontMetrics: FontMetricsInt? + ): Int { + updateBounds() + if (fontMetrics == null) { + return mWidth + } + val offsetAbove = getOffsetAboveBaseline(fontMetrics) + val offsetBelow = mHeight + offsetAbove + if (offsetAbove < fontMetrics.ascent) { + fontMetrics.ascent = offsetAbove + } + if (offsetAbove < fontMetrics.top) { + fontMetrics.top = offsetAbove + } + if (offsetBelow > fontMetrics.descent) { + fontMetrics.descent = offsetBelow + } + if (offsetBelow > fontMetrics.bottom) { + fontMetrics.bottom = offsetBelow + } return mWidth } - val offsetAbove = getOffsetAboveBaseline(fontMetrics) - val offsetBelow = mHeight + offsetAbove - if (offsetAbove < fontMetrics.ascent) { - fontMetrics.ascent = offsetAbove - } - if (offsetAbove < fontMetrics.top) { - fontMetrics.top = offsetAbove - } - if (offsetBelow > fontMetrics.descent) { - fontMetrics.descent = offsetBelow - } - if (offsetBelow > fontMetrics.bottom) { - fontMetrics.bottom = offsetBelow + + override fun draw( + canvas: Canvas, + text: CharSequence, + start: Int, + end: Int, + x: Float, + top: Int, + y: Int, + bottom: Int, + paint: Paint + ) { + paint.getFontMetricsInt(mFontMetricsInt) + val iconTop = y + getOffsetAboveBaseline(mFontMetricsInt) + canvas.translate(x, iconTop.toFloat()) + drawable.draw(canvas) + canvas.translate(-x, -iconTop.toFloat()) } - return mWidth - } - override fun draw( - canvas: Canvas, - text: CharSequence, - start: Int, - end: Int, - x: Float, - top: Int, - y: Int, - bottom: Int, - paint: Paint - ) { - paint.getFontMetricsInt(mFontMetricsInt) - val iconTop = y + getOffsetAboveBaseline(mFontMetricsInt) - canvas.translate(x, iconTop.toFloat()) - drawable.draw(canvas) - canvas.translate(-x, -iconTop.toFloat()) - } + private fun updateBounds() { + mBounds = drawable.bounds + mWidth = mBounds!!.width() + mHeight = mBounds!!.height() + } - private fun updateBounds() { - mBounds = drawable.bounds - mWidth = mBounds!!.width() - mHeight = mBounds!!.height() - } + private fun getOffsetAboveBaseline(fm: FontMetricsInt): Int { + return when (mAlignment) { + ALIGN_BOTTOM -> fm.descent - mHeight + ALIGN_CENTER -> { + val textHeight = fm.descent - fm.ascent + val offset = (textHeight - mHeight) / 2 + fm.ascent + offset + } - private fun getOffsetAboveBaseline(fm: FontMetricsInt): Int { - return when (mAlignment) { - ALIGN_BOTTOM -> fm.descent - mHeight - ALIGN_CENTER -> { - val textHeight = fm.descent - fm.ascent - val offset = (textHeight - mHeight) / 2 - fm.ascent + offset + ALIGN_BASELINE -> -mHeight + else -> -mHeight } - ALIGN_BASELINE -> -mHeight - else -> -mHeight } - } - companion object { - const val ALIGN_BOTTOM = 0 - const val ALIGN_BASELINE = 1 - const val ALIGN_CENTER = 2 + companion object { + const val ALIGN_BOTTOM = 0 + const val ALIGN_BASELINE = 1 + const val ALIGN_CENTER = 2 + } } -}