From 3192e01abe73d3fb980f757d50f9087f90a34653 Mon Sep 17 00:00:00 2001 From: gavine99 Date: Sun, 8 Sep 2024 09:32:04 +1000 Subject: [PATCH 001/885] changes to enable unified push notifications in generic build. Signed-off-by: Gavin Element --- README.md | 6 +- app/build.gradle | 5 +- app/src/generic/AndroidManifest.xml | 22 +++ .../nextcloud/talk/receivers/UnifiedPush.kt | 163 ++++++++++++++++++ .../talk/utils/ClosedInterfaceImpl.java | 29 +++- .../firebase/NCFirebaseMessagingService.kt | 1 + .../talk/utils/ClosedInterfaceImpl.kt | 18 +- .../account/AccountVerificationActivity.kt | 7 +- .../nextcloud/talk/activities/MainActivity.kt | 20 ++- .../ConversationsListActivity.kt | 4 +- .../talk/diagnose/DiagnoseActivity.kt | 68 ++++---- .../talk/interfaces/ClosedInterface.kt | 9 +- .../nextcloud/talk/jobs/NotificationWorker.kt | 36 +++- .../talk/jobs/PushRegistrationWorker.java | 5 +- .../talk/settings/SettingsActivity.kt | 36 +++- .../nextcloud/talk/utils/bundle/BundleKeys.kt | 1 + app/src/main/res/layout/activity_settings.xml | 37 +++- app/src/main/res/values/strings.xml | 19 +- .../talk/utils/ClosedInterfaceImpl.java | 19 +- gradle/verification-metadata.xml | 10 +- 20 files changed, 446 insertions(+), 69 deletions(-) create mode 100644 app/src/generic/AndroidManifest.xml create mode 100644 app/src/generic/java/com/nextcloud/talk/receivers/UnifiedPush.kt diff --git a/README.md b/README.md index 4ea25808be..a58e2a5359 100644 --- a/README.md +++ b/README.md @@ -13,7 +13,8 @@ alt="Get it on F-Droid" height="80">](https://f-droid.org/packages/com.nextcloud.talk2/) -Please note that Notifications won't work with the F-Droid version due to missing Google Play Services. +Please note that the F-Droid version uses UnifiedPush notifications and the Play Store version uses Google Play +Services notifications. ||||||| |---|---|---|---|---|---| @@ -63,7 +64,8 @@ Easy starting points are also reviewing [pull requests](https://github.com/nextc So you would like to contribute by testing? Awesome, we appreciate that very much. To report a bug for the alpha or beta version, just create an issue on github like you would for the stable version and - provide the version number. Please remember that Google Services are necessary to receive push notifications. + provide the version number. Please remember that Google Services are necessary to receive push notifications in the +Play Store version whereas the F-Droid version uses UnifiedPush notifications. #### Beta versions (Release Candidates) :package: diff --git a/app/build.gradle b/app/build.gradle index 5d02952046..8798d8ec65 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -303,6 +303,9 @@ dependencies { implementation 'com.github.nextcloud.android-common:ui:0.23.0' implementation 'com.github.nextcloud-deps:android-talk-webrtc:121.6167.0' + // unified push library for generic flavour + genericImplementation 'org.codeberg.UnifiedPush:android-connector:2.4.0' + gplayImplementation 'com.google.android.gms:play-services-base:18.5.0' gplayImplementation "com.google.firebase:firebase-messaging:24.0.1" @@ -418,4 +421,4 @@ detekt { ksp { arg('room.schemaLocation', "$projectDir/schemas") -} \ No newline at end of file +} diff --git a/app/src/generic/AndroidManifest.xml b/app/src/generic/AndroidManifest.xml new file mode 100644 index 0000000000..842263df52 --- /dev/null +++ b/app/src/generic/AndroidManifest.xml @@ -0,0 +1,22 @@ + + + + + + + + + + + + + + diff --git a/app/src/generic/java/com/nextcloud/talk/receivers/UnifiedPush.kt b/app/src/generic/java/com/nextcloud/talk/receivers/UnifiedPush.kt new file mode 100644 index 0000000000..36c086ffa2 --- /dev/null +++ b/app/src/generic/java/com/nextcloud/talk/receivers/UnifiedPush.kt @@ -0,0 +1,163 @@ +/* + * Nextcloud Talk - Android Client + * + * SPDX-FileCopyrightText: 2024 Your Name + * SPDX-License-Identifier: GPL-3.0-or-later + */ + +package com.nextcloud.talk.receivers + +import android.content.Context +import android.content.pm.PackageManager +import android.os.Build +import android.text.SpannableString +import android.text.method.LinkMovementMethod +import android.text.util.Linkify +import android.util.Log +import android.widget.TextView +import androidx.appcompat.app.AlertDialog +import androidx.work.Data +import androidx.work.OneTimeWorkRequest +import androidx.work.WorkManager +import com.nextcloud.talk.R +import com.nextcloud.talk.activities.MainActivity +import com.nextcloud.talk.jobs.NotificationWorker +import com.nextcloud.talk.utils.bundle.BundleKeys +import org.greenrobot.eventbus.EventBus +import org.unifiedpush.android.connector.MessagingReceiver +import org.unifiedpush.android.connector.PREF_MASTER +import org.unifiedpush.android.connector.PREF_MASTER_NO_DISTRIB_DIALOG_ACK +import org.unifiedpush.android.connector.UnifiedPush + +class UnifiedPush : MessagingReceiver() { + private val TAG: String? = UnifiedPush::class.java.simpleName + + companion object { + fun getNumberOfDistributorsAvailable(context: Context) : Int { + return UnifiedPush.getDistributors(context).size + } + + private fun resetSeenNoDistributorsInfo(context: Context) { + context.getSharedPreferences(PREF_MASTER, Context.MODE_PRIVATE) + .edit().putBoolean(PREF_MASTER_NO_DISTRIB_DIALOG_ACK, false).apply() + } + + fun registerForPushMessaging(context: Context, accountName: String): Boolean { + // if a distributor is registered and available, re-register to ensure in sync + if (UnifiedPush.getSavedDistributor(context) !== null) { + UnifiedPush.registerApp(context, accountName) + return false + } + + val distributors = UnifiedPush.getDistributors(context) + + // if no distributors available + if (distributors.isEmpty()) { + // if user has already been shown the info dialog, return + val preferences = context.getSharedPreferences(PREF_MASTER, Context.MODE_PRIVATE) + if (preferences.getBoolean(PREF_MASTER_NO_DISTRIB_DIALOG_ACK, false) == true) { + return false + } + + // show user some info about unified push + val message = TextView(context) + val s = SpannableString(context.getString(R.string.unified_push_no_distributors_dialog_text)) + Linkify.addLinks(s, Linkify.WEB_URLS) + message.text = s + message.movementMethod = LinkMovementMethod.getInstance() + message.setPadding(32, 32, 32, 32) + AlertDialog.Builder(context) + .setTitle(context.getString(R.string.unified_push_no_distributors_dialog_title)) + .setView(message) + .setPositiveButton(context.getString(R.string.nc_ok)) { + _, _ -> preferences.edit().putBoolean(PREF_MASTER_NO_DISTRIB_DIALOG_ACK, true).apply() + }.setOnDismissListener { + // send message to main activity that it can move on to it's next default activity + EventBus.getDefault().post(MainActivity.ProceedToConversationsListMessageEvent()) + }.show() + + return true // have a dialog to show, need main activity to wait + } + + // 1 distributor available + if (distributors.size == 1) { + UnifiedPush.saveDistributor(context, distributors.first()) + UnifiedPush.registerApp(context, accountName) + return false + } + + // multiple distributors available, show dialog for user to choose + val distributorsArray = distributors.toTypedArray() + val distributorsNameArray = distributorsArray.map { + try { + val ai = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) { + context.packageManager.getApplicationInfo( + it, + PackageManager.ApplicationInfoFlags.of(PackageManager.GET_META_DATA.toLong()) + ) + } else { + context.packageManager.getApplicationInfo(it, 0) + } + context.packageManager.getApplicationLabel(ai) + } catch (e: PackageManager.NameNotFoundException) { + it + } as String + }.toTypedArray() + + AlertDialog.Builder(context) + .setTitle(context.getString(R.string.unified_push_choose_distributor_title)) + .setItems(distributorsNameArray) { _, which -> + val distributor = distributorsArray[which] + UnifiedPush.saveDistributor(context, distributor) + UnifiedPush.registerApp(context, accountName) + }.setOnDismissListener { + // send message to main activity that it can move on to it's next default activity + EventBus.getDefault().post(MainActivity.ProceedToConversationsListMessageEvent()) + }.show() + + return true // have a dialog to show, need main activity to wait + } + + fun unregisterForPushMessaging(context: Context, accountName: String) { + // try and unregister with unified push distributor + UnifiedPush.unregisterApp(context, instance = accountName) + resetSeenNoDistributorsInfo(context) + } + } + + override fun onMessage(context: Context, message: ByteArray, instance: String) { + Log.d(TAG, "UP onMessage") + + val messageString = message.toString(Charsets.UTF_8) + + if (messageString.isNotEmpty() && instance.isNotEmpty()) { + val messageData = Data.Builder() + .putString(BundleKeys.KEY_NOTIFICATION_SUBJECT, messageString) + .putString(BundleKeys.KEY_NOTIFICATION_SIGNATURE, instance) + .putInt( + BundleKeys.KEY_NOTIFICATION_BACKEND_TYPE, NotificationWorker.Companion.BackendType.UNIFIED_PUSH.value) + .build() + val notificationWork = + OneTimeWorkRequest.Builder(NotificationWorker::class.java).setInputData(messageData) + .build() + WorkManager.getInstance().enqueue(notificationWork) + } + } + + override fun onNewEndpoint(context: Context, endpoint: String, instance: String) { + // called when a new endpoint is to be used for sending push messages + // do nothing + } + + override fun onRegistrationFailed(context: Context, instance: String) { + // called when the registration is not possible, eg. no network + // just dump the registration to make sure it is cleaned up. re-register will be auto-reattempted + unregisterForPushMessaging(context, instance) + + } + + override fun onUnregistered(context: Context, instance: String) { + // called when this application is remotely unregistered from receiving push messages + unregisterForPushMessaging(context, instance) + } +} diff --git a/app/src/generic/java/com/nextcloud/talk/utils/ClosedInterfaceImpl.java b/app/src/generic/java/com/nextcloud/talk/utils/ClosedInterfaceImpl.java index cafaa071d5..5bad91d55c 100644 --- a/app/src/generic/java/com/nextcloud/talk/utils/ClosedInterfaceImpl.java +++ b/app/src/generic/java/com/nextcloud/talk/utils/ClosedInterfaceImpl.java @@ -8,7 +8,11 @@ package com.nextcloud.talk.utils; +import android.content.Context; import com.nextcloud.talk.interfaces.ClosedInterface; +import com.nextcloud.talk.receivers.UnifiedPush; +import androidx.annotation.NonNull; + public class ClosedInterfaceImpl implements ClosedInterface { @Override @@ -17,12 +21,29 @@ public void providerInstallerInstallIfNeededAsync() { } @Override - public boolean isGooglePlayServicesAvailable() { - return false; + public boolean isPushMessagingServiceAvailable(Context context) { + return (UnifiedPush.Companion.getNumberOfDistributorsAvailable(context) > 0); + } + + @Override + public String pushMessagingProvider() { + return "unifiedpush"; + } + + @Override + public boolean registerWithServer(@NonNull Context context, String username) { + // unified push available in generic build + if (username == null) + return false; + return UnifiedPush.Companion.registerForPushMessaging(context, username); } + @NonNull @Override - public void setUpPushTokenRegistration() { - // no push notifications for generic build variant + public void unregisterWithServer(@NonNull Context context, @NonNull String username) { + // unified push available in generic build + if (username == null) + return; + UnifiedPush.Companion.unregisterForPushMessaging(context, username); } } diff --git a/app/src/gplay/java/com/nextcloud/talk/services/firebase/NCFirebaseMessagingService.kt b/app/src/gplay/java/com/nextcloud/talk/services/firebase/NCFirebaseMessagingService.kt index ac4e888aee..5e0d44aff5 100644 --- a/app/src/gplay/java/com/nextcloud/talk/services/firebase/NCFirebaseMessagingService.kt +++ b/app/src/gplay/java/com/nextcloud/talk/services/firebase/NCFirebaseMessagingService.kt @@ -50,6 +50,7 @@ class NCFirebaseMessagingService : FirebaseMessagingService() { val messageData = Data.Builder() .putString(BundleKeys.KEY_NOTIFICATION_SUBJECT, subject) .putString(BundleKeys.KEY_NOTIFICATION_SIGNATURE, signature) + .putInt(BundleKeys.KEY_NOTIFICATION_BACKEND_TYPE, NotificationWorker.Companion.BackendType.FIREBASE_CLOUD_MESSAGING.value) .build() val notificationWork = OneTimeWorkRequest.Builder(NotificationWorker::class.java).setInputData(messageData) 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 6a2fd0d3b9..dbc108bd9c 100644 --- a/app/src/gplay/java/com/nextcloud/talk/utils/ClosedInterfaceImpl.kt +++ b/app/src/gplay/java/com/nextcloud/talk/utils/ClosedInterfaceImpl.kt @@ -8,6 +8,7 @@ */ package com.nextcloud.talk.utils +import android.content.Context import android.content.Intent import android.util.Log import androidx.work.ExistingPeriodicWorkPolicy @@ -18,6 +19,7 @@ import autodagger.AutoInjector import com.google.android.gms.common.ConnectionResult import com.google.android.gms.common.GoogleApiAvailability import com.google.android.gms.security.ProviderInstaller +import com.nextcloud.talk.activities.BaseActivity import com.nextcloud.talk.application.NextcloudTalkApplication import com.nextcloud.talk.interfaces.ClosedInterface import com.nextcloud.talk.jobs.GetFirebasePushTokenWorker @@ -26,7 +28,13 @@ import java.util.concurrent.TimeUnit @AutoInjector(NextcloudTalkApplication::class) class ClosedInterfaceImpl : ClosedInterface, ProviderInstaller.ProviderInstallListener { - override val isGooglePlayServicesAvailable: Boolean = isGPlayServicesAvailable() + override fun isPushMessagingServiceAvailable(context: Context): Boolean { + return isGPlayServicesAvailable() + } + + override fun pushMessagingProvider(): String { + return "gplay" + } override fun providerInstallerInstallIfNeededAsync() { NextcloudTalkApplication.sharedApplication?.let { @@ -59,11 +67,17 @@ class ClosedInterfaceImpl : ClosedInterface, ProviderInstaller.ProviderInstallLi } } - override fun setUpPushTokenRegistration() { + override fun registerWithServer(context: Context, username: String?): Boolean { val firebasePushTokenWorker = OneTimeWorkRequest.Builder(GetFirebasePushTokenWorker::class.java).build() WorkManager.getInstance().enqueue(firebasePushTokenWorker) setUpPeriodicTokenRefreshFromFCM() + + return false + } + + override fun unregisterWithServer(context: Context, username: String?) { + // do nothing } private fun setUpPeriodicTokenRefreshFromFCM() { 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 0b3a3caefe..7a58cd884d 100644 --- a/app/src/main/java/com/nextcloud/talk/account/AccountVerificationActivity.kt +++ b/app/src/main/java/com/nextcloud/talk/account/AccountVerificationActivity.kt @@ -9,6 +9,7 @@ package com.nextcloud.talk.account import android.annotation.SuppressLint +import android.content.Context import android.content.Intent import android.content.pm.ActivityInfo import android.os.Bundle @@ -235,6 +236,8 @@ class AccountVerificationActivity : BaseActivity() { } private fun storeProfile(displayName: String?, userId: String, capabilitiesOverall: CapabilitiesOverall) { + val activityContext: Context = this // for capture by lambda used by subscribe() below + userManager.storeProfile( username, UserManager.UserAttributes( @@ -260,8 +263,8 @@ class AccountVerificationActivity : BaseActivity() { @SuppressLint("SetTextI18n") override fun onSuccess(user: User) { internalAccountId = user.id!! - if (ClosedInterfaceImpl().isGooglePlayServicesAvailable) { - ClosedInterfaceImpl().setUpPushTokenRegistration() + if (ClosedInterfaceImpl().isPushMessagingServiceAvailable(context)) { + ClosedInterfaceImpl().registerWithServer(activityContext, user.username) } else { Log.w(TAG, "Skipping push registration.") runOnUiThread { 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 e56f4f8983..be58a0333c 100644 --- a/app/src/main/java/com/nextcloud/talk/activities/MainActivity.kt +++ b/app/src/main/java/com/nextcloud/talk/activities/MainActivity.kt @@ -46,10 +46,14 @@ import io.reactivex.SingleObserver import io.reactivex.android.schedulers.AndroidSchedulers import io.reactivex.disposables.Disposable import io.reactivex.schedulers.Schedulers +import org.greenrobot.eventbus.ThreadMode +import org.greenrobot.eventbus.Subscribe import javax.inject.Inject @AutoInjector(NextcloudTalkApplication::class) class MainActivity : BaseActivity(), ActionBarProvider { + class ProceedToConversationsListMessageEvent { } + lateinit var binding: ActivityMainBinding @Inject @@ -76,9 +80,7 @@ class MainActivity : BaseActivity(), ActionBarProvider { }) // Set the default theme to replace the launch screen theme. - setTheme(R.style.AppTheme) binding = ActivityMainBinding.inflate(layoutInflater) - setContentView(binding.root) NextcloudTalkApplication.sharedApplication!!.componentApplication.inject(this) @@ -138,6 +140,11 @@ class MainActivity : BaseActivity(), ActionBarProvider { super.onStop() } + @Subscribe(threadMode = ThreadMode.MAIN) + fun onMessageEvent(event: ProceedToConversationsListMessageEvent) { + openConversationList() + } + private fun openConversationList() { val intent = Intent(this, ConversationsListActivity::class.java) intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP) @@ -257,6 +264,7 @@ class MainActivity : BaseActivity(), ActionBarProvider { appPreferences.isDbRoomMigrated = true } + val activityContext: Context = this // for capture by lambda used by subscribe() below userManager.users.subscribe(object : SingleObserver> { override fun onSubscribe(d: Disposable) { // unused atm @@ -264,9 +272,13 @@ class MainActivity : BaseActivity(), ActionBarProvider { override fun onSuccess(users: List) { if (users.isNotEmpty()) { - ClosedInterfaceImpl().setUpPushTokenRegistration() runOnUiThread { - openConversationList() + var needUIFeedbackFromUser = ClosedInterfaceImpl().registerWithServer(activityContext, + users.first().username) + // if push registration does not need to show a dialog, open the conversation list now + if (needUIFeedbackFromUser == false) { + openConversationList() + } } } else { runOnUiThread { diff --git a/app/src/main/java/com/nextcloud/talk/conversationlist/ConversationsListActivity.kt b/app/src/main/java/com/nextcloud/talk/conversationlist/ConversationsListActivity.kt index 9b9d74f549..6828e2af42 100644 --- a/app/src/main/java/com/nextcloud/talk/conversationlist/ConversationsListActivity.kt +++ b/app/src/main/java/com/nextcloud/talk/conversationlist/ConversationsListActivity.kt @@ -250,7 +250,7 @@ class ConversationsListActivity : // handle notification permission on API level >= 33 if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU && !platformPermissionUtil.isPostNotificationsPermissionGranted() && - ClosedInterfaceImpl().isGooglePlayServicesAvailable + ClosedInterfaceImpl().isPushMessagingServiceAvailable(context) ) { requestPermissions( arrayOf(Manifest.permission.POST_NOTIFICATIONS), @@ -1428,7 +1428,7 @@ class ConversationsListActivity : // whenever user allowed notifications, also check to ignore battery optimization if (grantResults.isNotEmpty() && grantResults[0] == PackageManager.PERMISSION_GRANTED) { if (!PowerManagerUtils().isIgnoringBatteryOptimizations() && - ClosedInterfaceImpl().isGooglePlayServicesAvailable + ClosedInterfaceImpl().isPushMessagingServiceAvailable(context) ) { val dialogText = String.format( context.resources.getString(R.string.nc_ignore_battery_optimization_dialog_text), diff --git a/app/src/main/java/com/nextcloud/talk/diagnose/DiagnoseActivity.kt b/app/src/main/java/com/nextcloud/talk/diagnose/DiagnoseActivity.kt index 68e69dc65d..1437141e9c 100644 --- a/app/src/main/java/com/nextcloud/talk/diagnose/DiagnoseActivity.kt +++ b/app/src/main/java/com/nextcloud/talk/diagnose/DiagnoseActivity.kt @@ -64,7 +64,8 @@ class DiagnoseActivity : BaseActivity() { @Inject lateinit var platformPermissionUtil: PlatformPermissionUtil - private var isGooglePlayServicesAvailable: Boolean = false + private var isPushMessagingServiceAvailable: Boolean = false + private var pushMessagingProvider: String = "" private val markdownText = SpannableStringBuilder() @@ -82,7 +83,8 @@ class DiagnoseActivity : BaseActivity() { super.onResume() supportActionBar?.show() - isGooglePlayServicesAvailable = ClosedInterfaceImpl().isGooglePlayServicesAvailable + isPushMessagingServiceAvailable = ClosedInterfaceImpl().isPushMessagingServiceAvailable(context) + pushMessagingProvider = ClosedInterfaceImpl().pushMessagingProvider() markdownText.clear() setupMetaValues() @@ -214,12 +216,14 @@ class DiagnoseActivity : BaseActivity() { addKey(context.resources.getString(R.string.nc_diagnose_android_version_title)) addValue(Build.VERSION.SDK_INT.toString()) - if (isGooglePlayServicesAvailable) { - addKey(context.resources.getString(R.string.nc_diagnose_gplay_available_title)) - addValue(context.resources.getString(R.string.nc_diagnose_gplay_available_yes)) - } else { - addKey(context.resources.getString(R.string.nc_diagnose_gplay_available_title)) - addValue(context.resources.getString(R.string.nc_diagnose_gplay_available_no)) + addKey(context.resources.getString(R.string.nc_diagnose_push_notifications_available_title)) + if (pushMessagingProvider == "gplay") { + addValue(context.resources.getString(R.string.nc_diagnose_push_notifications_gplay)) + } else if (pushMessagingProvider == "unifiedpush") { + addValue(context.resources.getString(R.string.nc_diagnose_push_notifications_unified_push)) + } + if (isPushMessagingServiceAvailable == false) { + addValue(context.resources.getString(R.string.nc_diagnose_push_notifications_available_no)) } } @@ -237,7 +241,7 @@ class DiagnoseActivity : BaseActivity() { addKey(context.resources.getString(R.string.nc_diagnose_flavor)) addValue(BuildConfig.FLAVOR) - if (isGooglePlayServicesAvailable) { + if (isPushMessagingServiceAvailable) { addKey(context.resources.getString(R.string.nc_diagnose_battery_optimization_title)) if (PowerManagerUtils().isIgnoringBatteryOptimizations()) { @@ -270,30 +274,32 @@ class DiagnoseActivity : BaseActivity() { ) ) - addKey(context.resources.getString(R.string.nc_diagnose_firebase_push_token_title)) - if (appPreferences.pushToken.isNullOrEmpty()) { - addValue(context.resources.getString(R.string.nc_diagnose_firebase_push_token_missing)) - } else { - addValue("${appPreferences.pushToken.substring(0, 5)}...") - } + if (pushMessagingProvider == "gplay") { + addKey(context.resources.getString(R.string.nc_diagnose_firebase_push_token_title)) + if (appPreferences.pushToken.isNullOrEmpty()) { + addValue(context.resources.getString(R.string.nc_diagnose_firebase_push_token_missing)) + } else { + addValue("${appPreferences.pushToken.substring(0, 5)}...") + } - addKey(context.resources.getString(R.string.nc_diagnose_firebase_push_token_latest_generated)) - if (appPreferences.pushTokenLatestGeneration != null && appPreferences.pushTokenLatestGeneration != 0L) { - addValue( - DisplayUtils.unixTimeToHumanReadable( - appPreferences - .pushTokenLatestGeneration + addKey(context.resources.getString(R.string.nc_diagnose_firebase_push_token_latest_generated)) + if (appPreferences.pushTokenLatestGeneration != null && appPreferences.pushTokenLatestGeneration != 0L) { + addValue( + DisplayUtils.unixTimeToHumanReadable( + appPreferences + .pushTokenLatestGeneration + ) ) - ) - } else { - addValue(context.resources.getString(R.string.nc_common_unknown)) - } + } else { + addValue(context.resources.getString(R.string.nc_common_unknown)) + } - addKey(context.resources.getString(R.string.nc_diagnose_firebase_push_token_latest_fetch)) - if (appPreferences.pushTokenLatestFetch != null && appPreferences.pushTokenLatestFetch != 0L) { - addValue(DisplayUtils.unixTimeToHumanReadable(appPreferences.pushTokenLatestFetch)) - } else { - addValue(context.resources.getString(R.string.nc_common_unknown)) + addKey(context.resources.getString(R.string.nc_diagnose_firebase_push_token_latest_fetch)) + if (appPreferences.pushTokenLatestFetch != null && appPreferences.pushTokenLatestFetch != 0L) { + addValue(DisplayUtils.unixTimeToHumanReadable(appPreferences.pushTokenLatestFetch)) + } else { + addValue(context.resources.getString(R.string.nc_common_unknown)) + } } } @@ -324,7 +330,7 @@ class DiagnoseActivity : BaseActivity() { ) ) - if (isGooglePlayServicesAvailable) { + if ((isPushMessagingServiceAvailable) && (pushMessagingProvider == "gplay")) { setupPushRegistrationDiagnose() } diff --git a/app/src/main/java/com/nextcloud/talk/interfaces/ClosedInterface.kt b/app/src/main/java/com/nextcloud/talk/interfaces/ClosedInterface.kt index eda9062443..cd761861cd 100644 --- a/app/src/main/java/com/nextcloud/talk/interfaces/ClosedInterface.kt +++ b/app/src/main/java/com/nextcloud/talk/interfaces/ClosedInterface.kt @@ -7,9 +7,14 @@ */ package com.nextcloud.talk.interfaces +import android.content.Context + + interface ClosedInterface { - val isGooglePlayServicesAvailable: Boolean + fun isPushMessagingServiceAvailable(context: Context): Boolean + fun pushMessagingProvider(): String fun providerInstallerInstallIfNeededAsync() - fun setUpPushTokenRegistration() + fun registerWithServer(context: Context, username: String?): Boolean + fun unregisterWithServer(context: Context, username: String?) } diff --git a/app/src/main/java/com/nextcloud/talk/jobs/NotificationWorker.kt b/app/src/main/java/com/nextcloud/talk/jobs/NotificationWorker.kt index 870bb94194..4145a7cfe6 100644 --- a/app/src/main/java/com/nextcloud/talk/jobs/NotificationWorker.kt +++ b/app/src/main/java/com/nextcloud/talk/jobs/NotificationWorker.kt @@ -148,7 +148,33 @@ class NotificationWorker(context: Context, workerParams: WorkerParameters) : Wor sharedApplication!!.componentApplication.inject(this) context = applicationContext - initDecryptedData(inputData) + when (inputData.getInt(BundleKeys.KEY_NOTIFICATION_BACKEND_TYPE, -1)) { + Companion.BackendType.FIREBASE_CLOUD_MESSAGING.value -> { + initDecryptedData(inputData) + } + Companion.BackendType.UNIFIED_PUSH.value -> { + pushMessage = LoganSquare.parse(inputData.getString(BundleKeys.KEY_NOTIFICATION_SUBJECT), + DecryptedPushMessage::class.java) + + val messageUser = inputData.getString(BundleKeys.KEY_NOTIFICATION_SIGNATURE) + val users = userManager!!.users.blockingGet() + if (users != null && users.size > 0) { + for (user in users) { + if (user.username == messageUser) { + signatureVerification = SignatureVerification(true, user) + break + } + } + } + if (signatureVerification === null) + return Result.failure() + } + else -> { + // message not received from a valid backend + return Result.failure() + } + } + initNcApiAndCredentials() notificationManager = NotificationManagerCompat.from(context!!) @@ -1050,5 +1076,13 @@ class NotificationWorker(context: Context, workerParams: WorkerParameters) : Wor private const val TIMER_COUNT = 12 private const val TIMER_DELAY: Long = 5 private const val GET_ROOM_RETRY_COUNT: Long = 3 + enum class BackendType(val value: Int) { + NONE(-1), + FIREBASE_CLOUD_MESSAGING(1), + UNIFIED_PUSH(2); + companion object { + fun fromInt(value: Int) = BackendType.values().first { it.value == value } + } + } } } diff --git a/app/src/main/java/com/nextcloud/talk/jobs/PushRegistrationWorker.java b/app/src/main/java/com/nextcloud/talk/jobs/PushRegistrationWorker.java index 6473d0e06d..9d9165252b 100644 --- a/app/src/main/java/com/nextcloud/talk/jobs/PushRegistrationWorker.java +++ b/app/src/main/java/com/nextcloud/talk/jobs/PushRegistrationWorker.java @@ -40,15 +40,18 @@ public class PushRegistrationWorker extends Worker { @Inject OkHttpClient okHttpClient; + Context workerContext; + public PushRegistrationWorker(@NonNull Context context, @NonNull WorkerParameters workerParams) { super(context, workerParams); + workerContext = context; } @NonNull @Override public Result doWork() { NextcloudTalkApplication.Companion.getSharedApplication().getComponentApplication().inject(this); - if (new ClosedInterfaceImpl().isGooglePlayServicesAvailable()) { + if (new ClosedInterfaceImpl().isPushMessagingServiceAvailable(workerContext)) { Data data = getInputData(); String origin = data.getString("origin"); Log.d(TAG, "PushRegistrationWorker called via " + origin); 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 e86439a59a..abb34ccdc3 100644 --- a/app/src/main/java/com/nextcloud/talk/settings/SettingsActivity.kt +++ b/app/src/main/java/com/nextcloud/talk/settings/SettingsActivity.kt @@ -149,6 +149,7 @@ class SettingsActivity : BaseActivity(), SetPhoneNumberDialogFragment.SetPhoneNu ) setupDiagnose() + setupResetPushPreference() setupPrivacyUrl() setupSourceCodeUrl() binding.settingsVersionSummary.text = String.format("v" + BuildConfig.VERSION_NAME) @@ -262,8 +263,8 @@ class SettingsActivity : BaseActivity(), SetPhoneNumberDialogFragment.SetPhoneNu @Suppress("LongMethod") private fun setupNotificationPermissionSettings() { - if (ClosedInterfaceImpl().isGooglePlayServicesAvailable) { - binding.settingsGplayOnlyWrapper.visibility = View.VISIBLE + if (ClosedInterfaceImpl().isPushMessagingServiceAvailable(context)) { + binding.settingsPushNotificationsOnlyWrapper.visibility = View.VISIBLE setTroubleshootingClickListenersIfNecessary() @@ -327,8 +328,20 @@ class SettingsActivity : BaseActivity(), SetPhoneNumberDialogFragment.SetPhoneNu binding.settingsNotificationsPermissionWrapper.visibility = View.GONE } } else { - binding.settingsGplayOnlyWrapper.visibility = View.GONE - binding.settingsGplayNotAvailable.visibility = View.VISIBLE + binding.settingsPushNotificationsOnlyWrapper.visibility = View.GONE + + val pushMessagingProvider = ClosedInterfaceImpl().pushMessagingProvider() + if (pushMessagingProvider == "gplay") { + binding.settingsPushNotificationsNotAvailableText.append("\n".plus( + resources!!.getString(R.string.nc_diagnose_push_notifications_gplay).plus("\n").plus(resources!! + .getString(R.string.nc_diagnose_push_notifications_gplay_rectify)))) + } else if (pushMessagingProvider == "unifiedpush") { + binding.settingsPushNotificationsNotAvailableText.append("\n".plus( + resources!!.getString(R.string.nc_diagnose_push_notifications_unified_push).plus("\n").plus + (resources!!.getString(R.string.nc_diagnose_push_notifications_unified_push_rectify)))) + } + + binding.settingsPushNotificationsNotAvailable.visibility = View.VISIBLE } } @@ -464,6 +477,21 @@ class SettingsActivity : BaseActivity(), SetPhoneNumberDialogFragment.SetPhoneNu } } + private fun setupResetPushPreference() { + binding.resetPushNotificationsWrapper.setOnClickListener { + for (user in userManager.users.blockingGet()) { + ClosedInterfaceImpl().unregisterWithServer(binding.root.context, user.username) + } + + Snackbar.make( + binding.root, + resources!!.getString(R.string.prefs_reset_push_done), + Snackbar.LENGTH_LONG + ).show() + true + } + } + private fun setupLicenceSetting() { if (!TextUtils.isEmpty(resources!!.getString(R.string.nc_gpl3_url))) { binding.settingsLicence.setOnClickListener { diff --git a/app/src/main/java/com/nextcloud/talk/utils/bundle/BundleKeys.kt b/app/src/main/java/com/nextcloud/talk/utils/bundle/BundleKeys.kt index 53de01b275..1bf4e83fbb 100644 --- a/app/src/main/java/com/nextcloud/talk/utils/bundle/BundleKeys.kt +++ b/app/src/main/java/com/nextcloud/talk/utils/bundle/BundleKeys.kt @@ -32,6 +32,7 @@ object BundleKeys { const val KEY_MODIFIED_BASE_URL = "KEY_MODIFIED_BASE_URL" const val KEY_NOTIFICATION_SUBJECT = "KEY_NOTIFICATION_SUBJECT" const val KEY_NOTIFICATION_SIGNATURE = "KEY_NOTIFICATION_SIGNATURE" + const val KEY_NOTIFICATION_BACKEND_TYPE = "KEY_NOTIFICATION_BACKEND_TYPE" const val KEY_INTERNAL_USER_ID = "KEY_INTERNAL_USER_ID" const val KEY_CONVERSATION_TYPE = "KEY_CONVERSATION_TYPE" const val KEY_INVITED_PARTICIPANTS = "KEY_INVITED_PARTICIPANTS" diff --git a/app/src/main/res/layout/activity_settings.xml b/app/src/main/res/layout/activity_settings.xml index 36c164bc63..afe7830677 100644 --- a/app/src/main/res/layout/activity_settings.xml +++ b/app/src/main/res/layout/activity_settings.xml @@ -206,7 +206,7 @@ android:textStyle="bold"/> @@ -254,7 +254,7 @@ + android:text="@string/nc_diagnose_push_notifications_available_no" /> @@ -602,14 +603,36 @@ android:id="@+id/diagnose_title" android:layout_width="wrap_content" android:layout_height="wrap_content" - android:textSize="@dimen/headline_text_size" - android:text="@string/nc_settings_diagnose_title"/> + android:text="@string/nc_settings_diagnose_title" + android:textSize="@dimen/headline_text_size" /> + android:text="@string/nc_settings_diagnose_subtitle" /> + + + + + + + - \ No newline at end of file + diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 13ed2b442f..037bab4c89 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -191,9 +191,14 @@ How to translate with transifex: App name App version Registered users - Google Play services - Google Play services are available - Google Play services are not available. Notifications are not supported + Push notification services + Push notifications are not available. + Push notifications are using the Google Play engine. + An alternate version of Talk is available for devices + without the Google Play Apis. + Push notifications are using the UnifiedPush engine. + Notifications can be enabled via UnifiedPush. + Please see https://unifiedpush.org Battery settings Battery optimization is not ignored. This should be changed! Battery optimization is ignored, all fine @@ -810,4 +815,12 @@ How to translate with transifex: Show ban reason Error occurred when unbanning participant Connection lost + Choose a UnifiedPush distributor to use for + notifications + You can use UnifiedPush + To enable push and chat notifications you need to install a + Unified Push distributor.\nFor more information visit https://unifiedpush.org + Reset push notifications + Reset push notifications in case of push messaging issues + Push notifications reset diff --git a/app/src/qa/java/com/nextcloud/talk/utils/ClosedInterfaceImpl.java b/app/src/qa/java/com/nextcloud/talk/utils/ClosedInterfaceImpl.java index 94778d8176..7fc3530d67 100644 --- a/app/src/qa/java/com/nextcloud/talk/utils/ClosedInterfaceImpl.java +++ b/app/src/qa/java/com/nextcloud/talk/utils/ClosedInterfaceImpl.java @@ -8,7 +8,11 @@ package com.nextcloud.talk.utils; +import android.content.Context; import com.nextcloud.talk.interfaces.ClosedInterface; +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; + public class ClosedInterfaceImpl implements ClosedInterface { @Override @@ -17,12 +21,23 @@ public void providerInstallerInstallIfNeededAsync() { } @Override - public boolean isGooglePlayServicesAvailable() { + public boolean isPushMessagingServiceAvailable(Context context) { + return false; + } + + @Override + public String pushMessagingProvider() { + return "qa"; + } + + @Override + public boolean registerWithServer(Context context, @Nullable String username) { + // no push notifications for qa build flavour :( return false; } @Override - public void setUpPushTokenRegistration() { + public void unregisterWithServer(@NonNull Context context, @Nullable String username) { // no push notifications for qa build flavour :( } } diff --git a/gradle/verification-metadata.xml b/gradle/verification-metadata.xml index e5e82d0b49..0ff0914807 100644 --- a/gradle/verification-metadata.xml +++ b/gradle/verification-metadata.xml @@ -5631,7 +5631,15 @@ - + + + + + + + + + From 758e45470236b5b561045673fea90ebd4860fa44 Mon Sep 17 00:00:00 2001 From: Nextcloud bot Date: Sun, 8 Sep 2024 04:54:22 +0000 Subject: [PATCH 002/885] Fix(l10n): Update translations from Transifex Signed-off-by: Nextcloud bot --- app/src/main/res/values-b+en+001/strings.xml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/app/src/main/res/values-b+en+001/strings.xml b/app/src/main/res/values-b+en+001/strings.xml index ff09b6df26..b0ee417057 100644 --- a/app/src/main/res/values-b+en+001/strings.xml +++ b/app/src/main/res/values-b+en+001/strings.xml @@ -335,6 +335,8 @@ Never notify Currently offline, please check your connectivity OK + Open conversation to registered users + Also open to guest app users Owner Participants Add participants @@ -411,6 +413,7 @@ Server does not have supported Talk app installed Server address https://… %1$s only works with %2$s 13 and up + Set Password Settings Your already existing account was updated, instead of adding a new one Advanced From b2ebafaf2dd7e2663ec4f275129baa6fa4b7d91c Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Sun, 8 Sep 2024 17:00:40 +0000 Subject: [PATCH 003/885] Update dependency io.gitlab.arturbosch.detekt:detekt-formatting to v1.23.7 Signed-off-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- app/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/build.gradle b/app/build.gradle index 5d02952046..8390b63234 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -185,7 +185,7 @@ dependencies { implementation 'androidx.datastore:datastore-core:1.1.1' implementation 'androidx.datastore:datastore-preferences:1.1.1' implementation 'androidx.test.ext:junit-ktx:1.2.1' - detektPlugins("io.gitlab.arturbosch.detekt:detekt-formatting:1.23.6") + detektPlugins("io.gitlab.arturbosch.detekt:detekt-formatting:1.23.7") implementation fileTree(include: ['*'], dir: 'libs') From e83e9fa8dff303f0db6ca3fd7dbc02d5afe7223f Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Sun, 8 Sep 2024 17:03:43 +0000 Subject: [PATCH 004/885] Update dependency io.gitlab.arturbosch.detekt:detekt-gradle-plugin to v1.23.7 Signed-off-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- build.gradle | 2 +- gradle/verification-metadata.xml | 14 +++++++++++++- 2 files changed, 14 insertions(+), 2 deletions(-) diff --git a/build.gradle b/build.gradle index 1016313219..d78bd1b411 100644 --- a/build.gradle +++ b/build.gradle @@ -26,7 +26,7 @@ buildscript { classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:${kotlinVersion}" classpath "org.jetbrains.kotlin:kotlin-serialization:${kotlinVersion}" classpath 'com.github.spotbugs.snom:spotbugs-gradle-plugin:6.0.22' - classpath "io.gitlab.arturbosch.detekt:detekt-gradle-plugin:1.23.6" + classpath "io.gitlab.arturbosch.detekt:detekt-gradle-plugin:1.23.7" classpath "org.jlleitschuh.gradle:ktlint-gradle:12.1.1" classpath "com.google.dagger:hilt-android-gradle-plugin:$hilt_version" diff --git a/gradle/verification-metadata.xml b/gradle/verification-metadata.xml index e5e82d0b49..884007a433 100644 --- a/gradle/verification-metadata.xml +++ b/gradle/verification-metadata.xml @@ -16,6 +16,7 @@ + @@ -39,7 +40,10 @@ - + + + + @@ -5713,6 +5717,14 @@ + + + + + + + + From 214fd0a803258b88102a74daee6b5d91e9e992ee Mon Sep 17 00:00:00 2001 From: Nextcloud bot Date: Mon, 9 Sep 2024 04:17:30 +0000 Subject: [PATCH 005/885] Fix(l10n): Update translations from Transifex Signed-off-by: Nextcloud bot --- app/src/main/res/values-eu/strings.xml | 7 +++++++ app/src/main/res/values-ga/strings.xml | 2 ++ app/src/main/res/values-zh-rTW/strings.xml | 1 + 3 files changed, 10 insertions(+) diff --git a/app/src/main/res/values-eu/strings.xml b/app/src/main/res/values-eu/strings.xml index 23a4231e38..cd500e544e 100644 --- a/app/src/main/res/values-eu/strings.xml +++ b/app/src/main/res/values-eu/strings.xml @@ -1,5 +1,6 @@ + Aldatu Kontuaren ikonoa %1$s elkarrizketa gogokoetara gehitu da Bilatu %s(e)n @@ -11,6 +12,8 @@ Kabledun entzungailua Avatarra Kanpoan + Debekatu + Debekatu parte-hartzailea Egutegia Dei-ezarpen aurreratuak Deia ordubetez egon da martxan. @@ -41,6 +44,7 @@ %1$s(%2$d) 4 ordu (editatuta) + Barneko oharra Ikusezina Ezin izan dira hizkuntzak berreskuratu Ezin izan da berreskuratu @@ -255,6 +259,7 @@ Moderatzailea Ez da inoiz elkartu Elkarrizketa berria + Ikusgarritasuna Irakurri gabeko aipamenak Irakurri gabeko mezuak %1$s ez dago erabilgarri (administratzaileak instalatu edo mugatu gabe) @@ -360,6 +365,7 @@ Aurreratua Itxura Deiak + Diagnostikoa Teklatuaren ikasketa pertsonalizatua desgaitzen du (bermerik gabe) Teklatu ezkutua Soinurik ez @@ -560,6 +566,7 @@ idazten ari dira ... idazten ari da ... eta beste %1$s idazten ari dira ... + Debekua kendu Irakurri gabe Igo avatar berria gailutik Erabltzaile-avatarra diff --git a/app/src/main/res/values-ga/strings.xml b/app/src/main/res/values-ga/strings.xml index 86b73b91e8..a9ccad4225 100644 --- a/app/src/main/res/values-ga/strings.xml +++ b/app/src/main/res/values-ga/strings.xml @@ -335,6 +335,7 @@ Ná cuir in iúl riamh Faoi láthair, seiceáil do nascacht le do thoil Ceart go leor + Oscail an comhrá d\'úsáideoirí cláraithe Chomh maith leis sin oscailte d\'úsáideoirí aip aoi Úinéir Rannpháirtithe @@ -412,6 +413,7 @@ Níl an aip Talk tacaithe ag an bhfreastalaí suiteáilte Seoladh an fhreastalaí https://… Ní oibríonn %1$s ach le %2$s 13 agus níos sine + Socraigh Pasfhocal Socruithe Nuashonraíodh do chuntas a bhí ann cheana féin, in ionad ceann nua a chur leis Casta diff --git a/app/src/main/res/values-zh-rTW/strings.xml b/app/src/main/res/values-zh-rTW/strings.xml index 1ee8757b8a..2ea95d5be4 100644 --- a/app/src/main/res/values-zh-rTW/strings.xml +++ b/app/src/main/res/values-zh-rTW/strings.xml @@ -413,6 +413,7 @@ 伺服器未安裝受支援的 Talk 應用程式 伺服器地址 https://… %1$s!只能在%2$s13版以上運作 + 設定密碼 設定 已更新您現有的帳號,而非新增帳號 進階 From 356b37c61b6e64a63190da8b09e0428f8a2e5a64 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Mon, 9 Sep 2024 08:41:28 +0000 Subject: [PATCH 006/885] Update dependency gradle to v8.10.1 Signed-off-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- gradle/verification-metadata.xml | 11 +++++++++++ gradle/wrapper/gradle-wrapper.properties | 2 +- 2 files changed, 12 insertions(+), 1 deletion(-) diff --git a/gradle/verification-metadata.xml b/gradle/verification-metadata.xml index 884007a433..12919b95be 100644 --- a/gradle/verification-metadata.xml +++ b/gradle/verification-metadata.xml @@ -56,6 +56,7 @@ + @@ -5935,6 +5936,11 @@ + + + + + @@ -5991,6 +5997,11 @@ + + + + + diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties index 9355b41557..0aaefbcaf0 100644 --- a/gradle/wrapper/gradle-wrapper.properties +++ b/gradle/wrapper/gradle-wrapper.properties @@ -1,6 +1,6 @@ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-8.10-bin.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-8.10.1-bin.zip networkTimeout=10000 validateDistributionUrl=true zipStoreBase=GRADLE_USER_HOME From b672ccb1afc39b94aa93925b0d761257cb181b3c Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Mon, 9 Sep 2024 15:31:01 +0000 Subject: [PATCH 007/885] Update actions/setup-java action to v4.3.0 Signed-off-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- .github/workflows/analysis.yml | 2 +- .github/workflows/assembleFlavors.yml | 2 +- .github/workflows/check.yml | 2 +- .github/workflows/codeql.yml | 2 +- .github/workflows/qa.yml | 2 +- .github/workflows/unit-tests.yml | 2 +- 6 files changed, 6 insertions(+), 6 deletions(-) diff --git a/.github/workflows/analysis.yml b/.github/workflows/analysis.yml index 032bfbeca5..d24bd37feb 100644 --- a/.github/workflows/analysis.yml +++ b/.github/workflows/analysis.yml @@ -49,7 +49,7 @@ jobs: repository: ${{ steps.get-vars.outputs.repo }} ref: ${{ steps.get-vars.outputs.branch }} - name: Set up JDK 17 - uses: actions/setup-java@6a0805fcefea3d4657a47ac4c165951e33482018 # v4.2.2 + uses: actions/setup-java@2dfa2011c5b2a0f1489bf9e433881c92c1631f88 # v4.3.0 with: distribution: "temurin" java-version: 17 diff --git a/.github/workflows/assembleFlavors.yml b/.github/workflows/assembleFlavors.yml index a6b96ad3b9..428773e390 100644 --- a/.github/workflows/assembleFlavors.yml +++ b/.github/workflows/assembleFlavors.yml @@ -24,7 +24,7 @@ jobs: steps: - uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332 # v4.1.7 - name: set up JDK 17 - uses: actions/setup-java@6a0805fcefea3d4657a47ac4c165951e33482018 # v4.2.2 + uses: actions/setup-java@2dfa2011c5b2a0f1489bf9e433881c92c1631f88 # v4.3.0 with: distribution: "temurin" java-version: 17 diff --git a/.github/workflows/check.yml b/.github/workflows/check.yml index cc36896e07..9c1ae7d89a 100644 --- a/.github/workflows/check.yml +++ b/.github/workflows/check.yml @@ -24,7 +24,7 @@ jobs: steps: - uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332 # v4.1.7 - name: Set up JDK 17 - uses: actions/setup-java@6a0805fcefea3d4657a47ac4c165951e33482018 # v4.2.2 + uses: actions/setup-java@2dfa2011c5b2a0f1489bf9e433881c92c1631f88 # v4.3.0 with: distribution: "temurin" java-version: 17 diff --git a/.github/workflows/codeql.yml b/.github/workflows/codeql.yml index bace496ac2..32832b4f1c 100644 --- a/.github/workflows/codeql.yml +++ b/.github/workflows/codeql.yml @@ -43,7 +43,7 @@ jobs: with: languages: ${{ matrix.language }} - name: Set up JDK 17 - uses: actions/setup-java@6a0805fcefea3d4657a47ac4c165951e33482018 # v4.2.2 + uses: actions/setup-java@2dfa2011c5b2a0f1489bf9e433881c92c1631f88 # v4.3.0 with: distribution: "temurin" java-version: 17 diff --git a/.github/workflows/qa.yml b/.github/workflows/qa.yml index d9d6b7eb8f..71cb6718dd 100644 --- a/.github/workflows/qa.yml +++ b/.github/workflows/qa.yml @@ -25,7 +25,7 @@ jobs: - uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332 # v4.1.7 if: ${{ steps.check-secrets.outputs.ok == 'true' }} - name: set up JDK 17 - uses: actions/setup-java@6a0805fcefea3d4657a47ac4c165951e33482018 # v4.2.2 + uses: actions/setup-java@2dfa2011c5b2a0f1489bf9e433881c92c1631f88 # v4.3.0 if: ${{ steps.check-secrets.outputs.ok == 'true' }} with: distribution: "temurin" diff --git a/.github/workflows/unit-tests.yml b/.github/workflows/unit-tests.yml index 4db169ecc2..9696048d53 100644 --- a/.github/workflows/unit-tests.yml +++ b/.github/workflows/unit-tests.yml @@ -23,7 +23,7 @@ jobs: steps: - uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332 # v4.1.7 - name: Set up JDK 17 - uses: actions/setup-java@6a0805fcefea3d4657a47ac4c165951e33482018 # v4.2.2 + uses: actions/setup-java@2dfa2011c5b2a0f1489bf9e433881c92c1631f88 # v4.3.0 with: distribution: "temurin" java-version: 17 From 216b9d8c0a7ce9f47b1a5595debc2699f9382594 Mon Sep 17 00:00:00 2001 From: Nextcloud bot Date: Tue, 10 Sep 2024 04:22:23 +0000 Subject: [PATCH 008/885] Fix(l10n): Update translations from Transifex Signed-off-by: Nextcloud bot --- app/src/main/res/values-ar/strings.xml | 10 - app/src/main/res/values-ast/strings.xml | 5 - app/src/main/res/values-b+en+001/strings.xml | 10 - app/src/main/res/values-bg-rBG/strings.xml | 8 - app/src/main/res/values-ca/strings.xml | 9 - app/src/main/res/values-cs-rCZ/strings.xml | 10 - app/src/main/res/values-da/strings.xml | 328 ------------------- app/src/main/res/values-de/strings.xml | 10 - app/src/main/res/values-el/strings.xml | 8 - app/src/main/res/values-es-rEC/strings.xml | 12 +- app/src/main/res/values-es/strings.xml | 10 - app/src/main/res/values-eu/strings.xml | 10 - app/src/main/res/values-fa/strings.xml | 10 +- app/src/main/res/values-fi-rFI/strings.xml | 10 +- app/src/main/res/values-fr/strings.xml | 11 +- app/src/main/res/values-ga/strings.xml | 10 - app/src/main/res/values-gl/strings.xml | 10 - app/src/main/res/values-hr/strings.xml | 8 - app/src/main/res/values-hu-rHU/strings.xml | 9 - app/src/main/res/values-it/strings.xml | 8 - app/src/main/res/values-ja-rJP/strings.xml | 10 - app/src/main/res/values-ko/strings.xml | 9 - app/src/main/res/values-lt-rLT/strings.xml | 8 - app/src/main/res/values-nb-rNO/strings.xml | 10 - app/src/main/res/values-nl/strings.xml | 8 - app/src/main/res/values-pl/strings.xml | 10 - app/src/main/res/values-pt-rBR/strings.xml | 10 - app/src/main/res/values-ru/strings.xml | 12 +- app/src/main/res/values-sc/strings.xml | 8 - app/src/main/res/values-sk-rSK/strings.xml | 10 - app/src/main/res/values-sl/strings.xml | 9 - app/src/main/res/values-sr/strings.xml | 10 - app/src/main/res/values-sv/strings.xml | 10 - app/src/main/res/values-tr/strings.xml | 10 - app/src/main/res/values-uk/strings.xml | 9 - app/src/main/res/values-zh-rCN/strings.xml | 10 - app/src/main/res/values-zh-rHK/strings.xml | 10 - app/src/main/res/values-zh-rTW/strings.xml | 10 - 38 files changed, 9 insertions(+), 670 deletions(-) delete mode 100644 app/src/main/res/values-da/strings.xml diff --git a/app/src/main/res/values-ar/strings.xml b/app/src/main/res/values-ar/strings.xml index cf9a26d3fb..fc2147533c 100644 --- a/app/src/main/res/values-ar/strings.xml +++ b/app/src/main/res/values-ar/strings.xml @@ -1,7 +1,6 @@ تحرير - أيقونة الحساب أضِف إلى الملاحظات أضِف المحادثة %1$sإلى المُفضّلة بحث في %s @@ -76,7 +75,6 @@ الأعلى حجماً أولاً الأقل حجماً أولاً مُسحت الرسالة بواسطتك - نهاية صلاحية الرسالة تمّ التعديل من قِبَل %1$s أنقُر لفتح الاستبيان لا توجد نتائج @@ -95,7 +93,6 @@ إضِف مُشاركين أضف إلى المفضلة تم! - السماح للضيوف الرمز: %1$s فتح قفل %1$s لتمكين مكبرات صوت البلوتوث، يرجى منح إذن \"الأجهزة المجاورة\". @@ -137,7 +134,6 @@ هل تريد مسح جميع الرسائل في هذه المحادثة؟ تغيير شهادة العميل تعيين شهادة العميل - أغلِق التطبيق و إنسَخ تمّ النسخ إلى الحافظة @@ -279,8 +275,6 @@ الاشعارات في هذه المحادثة ستتجاوز إعداد الحالة \"يُرجى عدم الإزعاج\" دعوات إنضَمَّ إلى محادثات جارية - يجب عليك ترقية مشرف لاحد المشاركين قبل مغادرة %1$s. - تعذر مغادرة المحادثة %1$s| آخر تعديل: %2$s غادر المحادثة مُغادرة المكالمة … @@ -476,9 +470,6 @@ شارك الموقع الحالي رابط المشاركة مشاركة الموقع - %1$s دعوة - انضم للمحادثة في %1$s /index.php/call/ %2$s - /كلمة المرور: %1$s شارِك هذا الموقع إختر حسابًا عناصر مُشارَكة @@ -613,7 +604,6 @@ هذا الأسبوع هذه رسالة اختبار نهاية هذا الأسبوع - المُرفَقات اليوم غدا ترجِم diff --git a/app/src/main/res/values-ast/strings.xml b/app/src/main/res/values-ast/strings.xml index e20348f9b1..6780489f71 100644 --- a/app/src/main/res/values-ast/strings.xml +++ b/app/src/main/res/values-ast/strings.xml @@ -1,7 +1,6 @@ Editar - Iconu de la cuenta Amestar a Notes La conversación «%1$s» metióse en Favoritos Buscar en: %s @@ -53,7 +52,6 @@ Primero lo grande Primero lo pequeño Desaniciesti\'l mensaxe - Caducidá de los mensaxes Toca p\'abrir la encuesta Nun hai nengún resultáu de la busca Buscar… @@ -83,7 +81,6 @@ ¿De xuru que quies desaniciar tolos mensaxes d\'esta conversación? Camudar el certificáu del veceru Configurar el certificáu del veceru - Zarrar l\'aplicación y Copiar Copióse nel cartafueyu @@ -161,7 +158,6 @@ Compartir l\'enllaz de la converación Converación importante Invitaciones - Nun se pudo colar de la conversación Colar de la conversación Colando de la llamada… Llicencia @@ -254,7 +250,6 @@ Estilu Alvertencia Compartir l\'enllaz - \nContraseña: %1$s Elementos compartíos Nun hai nengún elementu compartíu Llocalización diff --git a/app/src/main/res/values-b+en+001/strings.xml b/app/src/main/res/values-b+en+001/strings.xml index b0ee417057..ed551a2abc 100644 --- a/app/src/main/res/values-b+en+001/strings.xml +++ b/app/src/main/res/values-b+en+001/strings.xml @@ -1,7 +1,6 @@ Edit - Account icon Add to Notes Added conversation %1$s to favourites Search in %s @@ -76,7 +75,6 @@ Biggest first Smallest first Message deleted by you - Message expiration Edited by %1$s Tap to open poll No search results @@ -95,7 +93,6 @@ Add participants Add to favourites OK, all done! - Allow guests Pin: %1$s Unlock %1$s To enable Bluetooth speakers please grant \"Nearby devices\" permission. @@ -137,7 +134,6 @@ Do you really want to delete all messages in this conversation? Change client certificate Set up client certificate - Close app and Copy Copied to clipboard @@ -279,8 +275,6 @@ Notifications in this conversation will override Do Not Disturb settings Invitations Join open conversations - You need to promote a new moderator before you can leave %1$s. - Could not leave conversation %1$s | Last modified: %2$s Leave conversation Leaving call … @@ -476,9 +470,6 @@ Share current location Share link Share location - %1$s invitation - Join the conversation at %1$s/index.php/call/%2$s - \nPassword: %1$s Share this location Choose account Shared items @@ -613,7 +604,6 @@ This week This is a test message This weekend - Attachments Today Tomorrow Translate diff --git a/app/src/main/res/values-bg-rBG/strings.xml b/app/src/main/res/values-bg-rBG/strings.xml index 5b444c6e19..a64d6ecf68 100644 --- a/app/src/main/res/values-bg-rBG/strings.xml +++ b/app/src/main/res/values-bg-rBG/strings.xml @@ -1,7 +1,6 @@ Редактиране - Икона на профил Търсене в %s Bluetooth /Блутут/ Аудио изход @@ -63,7 +62,6 @@ Добавяне на участници Добави към любимите Добре, всичко е готово! - Позволи гости Pin: %1$s Отключване %1$s Разширени опции за повикване @@ -192,8 +190,6 @@ Въвеждане на съобщение … Важен разговор Известията в този разговор ще отменят настройките „Не безпокойте“ - Трябва да предложите нов модератор, преди да можете да напуснете%1$s. - Не можете да напуснете разговора %1$s Последна промяна: %2$s Напускане на разговор Напускане на обаждането … @@ -366,9 +362,6 @@ Споделяне на текущо местоположение Връзка за споделяне Споделяне на местоположение - %1$s покана - Присъединяване към разговора на %1$s/index.php/разговор/%2$s - \nПарола: %1$s Споделяне на това местоположение Избор на профил Споделени елементи @@ -485,7 +478,6 @@ Превключване на фенерче 30 минути Тази седмица - Прикачени файлове Днес Утре Превод diff --git a/app/src/main/res/values-ca/strings.xml b/app/src/main/res/values-ca/strings.xml index 5195e77052..4cb5ef29d8 100644 --- a/app/src/main/res/values-ca/strings.xml +++ b/app/src/main/res/values-ca/strings.xml @@ -1,7 +1,6 @@ Edició - Icona del compte Cerca a %s Bluetooth Sortida d\'àudio @@ -47,7 +46,6 @@ Més gran primer Més petit primer Missatge suprimit per tu - Caducitat del missatge Toqueu per obrir l\'enquesta No s\'han trobat resultats Comença a escriure per cercar … @@ -65,7 +63,6 @@ Afegeix participants Afegeix a preferits D\'acord, tot fet! - Permet visitants Ancora: %1$s Desbloca %1$s Opcions avançades de trucada @@ -194,8 +191,6 @@ Les notificacions d\'aquesta conversa anul·laran els paràmetres de no destorbar. Invitacions Uneix-te a converses obertes - Heu de designar un nou moderador abans de deixar %1$s. - No s\'ha pogut abandonar la conversa %1$s | Darrera modificació: %2$s Surt de la conversa S\'està abandonant la trucada… @@ -370,9 +365,6 @@ Comparteix la ubicació actual Comparteix un enllaç Comparteix la ubicació - %1$s invitació - Afegiu-vos a la conversa a %1$s/index.php/call/%2$s - \nContrasenya: %1$s Comparteix aquesta localització Trieu un compte Elements compartits @@ -490,7 +482,6 @@ Commuta la llanterna 30 minuts Aquesta setmana - Adjunts Avui Demà Traducció diff --git a/app/src/main/res/values-cs-rCZ/strings.xml b/app/src/main/res/values-cs-rCZ/strings.xml index 6dd95c93e0..65dfa5e89e 100644 --- a/app/src/main/res/values-cs-rCZ/strings.xml +++ b/app/src/main/res/values-cs-rCZ/strings.xml @@ -1,7 +1,6 @@ Upravit - Ikona účtu Konverzace %1$s přidána do oblíbených Hledat v %s Hlasový hovor @@ -61,7 +60,6 @@ Největší jako první Nejmenší jako první Zprávu jste smazali - Skončení platnosti zprávy Klepnutím anketu otevřete Nic nenalezeno Hledejte psaním… @@ -79,7 +77,6 @@ Přidat účastníky Přidat do oblíbených OK, vše hotovo! - Povolit hosty Pin: %1$s Odemknout %1$s Pro použití bluetooth reproduktorů je třeba udělit oprávnění „Zařízení poblíž“. @@ -118,7 +115,6 @@ Opravdu chcete všechny zprávy v této konverzaci smazat? Změnit klientský certifikát Nastavit klientský certifikát - Zavřít aplikaci a Zkopírovat Zkopírováno do schránky @@ -233,8 +229,6 @@ Upozornění v této konverzaci budou ignorovat režim Nerušit Pozvání Přidat se do všem přístupných konverzací - Než budete moci opustit %1$s, je třeba předat někomu roli moderátora. - Konverzaci zatím nemůžete opustit %1$s | Naposledy upraveno: %2$s Opustit konverzaci Opouštění hovoru… @@ -421,9 +415,6 @@ Sdílet stávající umístění Nasdílet odkaz Sdílet umístění - %1$s pozvání - Připojte se ke konverzaci na %1$s/index.php/call/%2$s - \nHeslo: %1$s Sdílet toto umístění Zvolte účet Sdílené položky @@ -551,7 +542,6 @@ Tento týden Toto je zkušební zpráva Tento víkend - Přílohy Dnes Zítra Překládání diff --git a/app/src/main/res/values-da/strings.xml b/app/src/main/res/values-da/strings.xml deleted file mode 100644 index 36c70496f3..0000000000 --- a/app/src/main/res/values-da/strings.xml +++ /dev/null @@ -1,328 +0,0 @@ - - - Redigér - Konto ikon - Søg i %s - Telefon - Avatar - Ikke tilstede - Kalender - Ryd status notifikation - Ryd status notifikationer efter - Luk - Forbindelse oprettet - Samtaler - Opret samtale - Valgfrit - Forstyr ikke - Ryd ikke - Rediger - Nylige - Krypteret - Kunne ikke gemme %1$s - mappe - Loading … - %1$s (%2$d) - 4 timer - Usynlig - Indlæs flere resultater - Nyeste først - Ældste først - A - Å - Å - A - Største først - Mindste først - Ingen søgeresultater - Beskeder - Den valgte konto blev importeret og kan bruges nu - Om - Aktiv bruger - Tilføj konto - Kontoen er planlagt til sletning, og kan ikke ændres - Tilføj vedhæftelse - Tilføj deltagere - Føj til favoritter - OK, alt er klar! - Tillad gæster - Lås op %1$s - Samtalenavn - Intet respons i 45 sekunder, rør skærmen for at forsøge igen - Annuller - Anskaffelse af evner fejlede, annullerer - Stoler du på det, indtil nu, ukendte SSL certifikat ,udstedt af %1$s for %2$s, gyldig fra %3$s til %4$s? - Tjek certifikatet - Din SSL indstilling forhindrede forbindelse - Skift godkendelsescertifikat - Alle beskeder blev slettet - Skift kliencertifikat - Indstil klientcertifikat - og - Kopiér - Kopieret til udklipsholder - Opret - Deaktiveret - Afvis - Noget gik galt, undskyld! - Sæt - Spring over - Ukendt - Vælg godkendelsescertifikat - Forbinder ... - Færdig - Samtaleinfo - Videoopkald - Stemmeopkald - Samtalen blev ikke fundet - Samtale indstillinger - Deltag i en samtale eller start en ny - Sig hej til dine venner og kollegaer. - Kopiér - Opret afstemning - I dag - I går - Slet - Slet samtale - Hvis du sletter konversationen, vil den også blive slettet for alle andre deltagere. - Slet - Degrader fra moderator - Send besked - Nuværende konto - Server - ruger - App - App navn - Batteriindstillinger - Enhed - Telefon - Ekstern - Ugyldigt kodeord - Vedligeholdelsestilstand - Opdater - Display navn kunne ikke hentes, afbrydes - Kunne ikke opbevare skærmnavn, afbryder - Redigér - E-mail - Slået fra - 1 dag - 1 time - 1 uge - Anskaffelse af signaleringsindstillinger fejlede - Accepter - Afvis - Tilbage - Bruger følger et offentligt link - Dig: %1$s - Videresend - Har du ikke en server endnu?\nKlik her for at skaffe en udbyder - Hent kildekode - Gruppe - Grupper - Gæst - Tillad gæster - Enter a password - Adgangskodebeskyttelse - Svagt password - Vigtig samtale - notifikationer under denne samtale vil ignorere Forstyr ikke indstillinger - Du skal udnævne en ny moderator før du kan forlade %1$s. - Kunne ikke forlade samtalen - %1$s| Sidst ændret: %2$s - Forlad samtale - GNU General Public License, Version 3 - Licens - %skarakterbegrænsning nået - Lobby - Du venter nu i lobbyen. - Tryk for at låse op - Ikke indstillet - Marker som læst - Marker som ulæst - Beskeden blev sendt - Moderator - Aldrig ansluttet - Ny samtale - Synlighed - Ulæste beskedder - Gæst - Nej - Ikke proxy - %1$s på %2$s notifikationskanal - Opkald - Beskeder - Uploadede filer - Meddelelsesindstillinger - Giv altid besked - Giv besked når du bliver omtalt - Giv aldrig besked - For nuværende offline, venligst kontroller din forbindelse - OK - Begynd en samtale til registrerede brugere - Ejer - Deltagere - Tilføj deltagere - Indstillinger - Konto blev ikke fundet - Beskeder - Privatliv - Personlige oplysninger - Forfrem til moderator - Ny offentlig samtale - Offentlige samtaler lader dig invitere folk udefra gennem et speciel lavet link. - Pushbeskeder er slået fra - Tryk-for-at-tale - Med mikrofonen deaktiveret, hold&nede for at bruge Push-to-talk - Opdater - Påmind mig senere - Fjern fra favoritter - Fjern deltager - Omdøb samtale - Omdøb - Besvar - Svar privat - Gem - Gemt - 30 sekunder - 5 minutter - 1 minut - 10 minutter - 600 - 60 - 30 - 300 - Søg - Vælg konto - Vælg deltagere - %1$s sendte en GIF. - Du sendte en GIF. - %1$s sendte en video. - Du sendte en video. - %1$s sendte en vedhæftning. - Du sendte en vedhæftning. - %1$s sendte en lyd. - Du sendte en lyd. - %1$s sendte et billede. - Du sendte et billede. - Test server forbindelsen - Opdater venligst din %1$s database - Den valgte konto kunne ikke importeres - Linket til dit %1$s web interface når du åbner den i browseren. - Importer konto fra %1$s appen - Importer konto - Importer konti fra %1$s appen - Importer konti - Få venligst %1$s ud fra vedligeholdelse - Afslut venligst din %1$s installation - Tester forbindelsen - Serveradresse https://… - %1$svirker kun med %2$s 13 og nyere - Indstillinger - Vi har opdateret din eksisterende konto i stedet for at tilføje en ny - Avanceret - Udseende - Opkald - Indstiller tastatur til at deaktivere personaliseret indlæring (uden garanti) - Inkognito tastatur - Ingen lyd - Talk appen er ikke installeret på serveren du prøver at blive godkendt på - Notifikationslyde - Notifikationer - Beskeder - Indtast telefonnummer - Telefonnummer - Privatliv - Proxy host - Proxy port - Proxy type - Del min læsestatus og vis andres læsestatus - Fjern - Fjern konto - Bekræft venligst din hensigt til at fjerne den aktuelle konto. - Lås %1$s med Android Skærm lås en understøttet biometrisk metode - Skærm lås inaktivitets timeout - Skærm lås - Forhindrer skærmkopi i nyeste liste og i selve app-en - Skærm sikkerhed - Sat af batteri-spare funktion - Mørk - Brug system default - tema - Lys - Tema - Advarsler - Kun nuværende konto kan gen autoriseres - Del link - %1$s invitation - Deltag i samtalen på %1$s/index.php/call/%2$s - \nAdgangskode: %1$s - Vælg konto - Sted - Sortér efter - Start tid - Skift konto - Teams - Upload fra enhed - Uploader - Tag et billede - ruger - Synlig - Webinar - Ja - Næste uge - 1 time - Online - Online status - Tilføj valg - Valgmuligheder - Resultater - Indstillinger - Stemme - Alle - Gem - Synkroniser kun til betroede servere - Forbundet - Kun synlig for personer i denne instans og gæster - Lokal - Kun synlig for personer, der matches via telefonnummerintegration via Talk på mobil - Privat - Synkroniser til betroede servere og den globale og offentlige adressebog - Udgivet - Skift privatlivsniveau for %1$s - få sekunder siden - Markeret - Send e-mail - Sæt - Sæt status - Sæt statusbesked - Del - Audio - Fil - Medier - Andet - Telefonsvarer - Favorit - Statusbesked - Tag et billede - Send - Skift kamera - 30 minutter - Denne uge - Vedhæftede filer - I dag - I morgen - Oversæt - Enhedsindstillinger - Kunne ikke finde sprog - Fra - Til - Ulæst - Adresse - Fulde navn - E-mail - Telefonnummer - Twitter - Hjemmeside - Status - Personlig information ikke konfigureret - Tilføj navn, billede og kontakt information på din profilside. - Hvad er din status - diff --git a/app/src/main/res/values-de/strings.xml b/app/src/main/res/values-de/strings.xml index b7b4e6ad0d..ee04926a14 100644 --- a/app/src/main/res/values-de/strings.xml +++ b/app/src/main/res/values-de/strings.xml @@ -1,7 +1,6 @@ Bearbeiten - Konto-Icon Zu Notizen hinzufügen Unterhaltung %1$s zu Favoriten hinzugefügt Suche in %s @@ -76,7 +75,6 @@ Größste zuerst Kleinste zuerst Nachricht von Ihnen gelöscht - Nachrichtenablauf Bearbeitet von %1$s Tippen, um die Umfrage zu öffnen Keine Suchergebnisse @@ -95,7 +93,6 @@ Teilnehmer hinzufügen Zu Favoriten hinzufügen OK, alles erledigt! - Gäste zulassen PIN: %1$s %1$s entsperren Um Bluetooth-Lautsprecher zu aktivieren, bitte die Berechtigung „Geräte in der Nähe“ erteilen. @@ -137,7 +134,6 @@ Möchten Sie wirklich alle Nachrichten dieser Unterhaltung löschen? Client-Zertifikat ändern Client-Zertifikat einrichten - App schließen und Kopieren In die Zwischenablage kopiert @@ -279,8 +275,6 @@ Benachrichtigungen in dieser Unterhaltung überschreiben Nicht-Stören-Einstellungen Einladungen Offenen Unterhaltungen beitreten - Sie müssen einen neuen Moderator bestimmen, bevor Sie %1$s verlassen können. - Unterhaltung konnte nicht verlassen werden %1$s | Zuletzt geändert: %2$s Unterhaltung verlassen Verlasse Anruf … @@ -476,9 +470,6 @@ Aktuelle Position teilen Link teilen Ort teilen - %1$s Einladung - Treten Sie der Unterhaltung %1$s/index.php/call/%2$s bei - \nPasswort: %1$s Diesen Ort teilen Konto auswählen Geteilte Elemente @@ -613,7 +604,6 @@ Diese Woche Dies ist eine Testnachricht Dieses Wochenende - Anhänge Heute Morgen Übersetzen diff --git a/app/src/main/res/values-el/strings.xml b/app/src/main/res/values-el/strings.xml index 63eaf118c5..51187bf1ec 100644 --- a/app/src/main/res/values-el/strings.xml +++ b/app/src/main/res/values-el/strings.xml @@ -1,7 +1,6 @@ Επεξεργασία - Εικονίδιο λογαριασμού Αναζήτηση στο %s Έξοδος ήχου Τηλέφωνο @@ -53,7 +52,6 @@ Προσθήκη συμμετεχόντων Προσθήκη στα αγαπημένα Εντάξει, ολοκληρώθηκαν όλα! - Επιτρέπονται οι επισκέπτες Ξεκλείδωμα %1$s Κλείσιμο τηλεφώνου ΕΙΣΕΡΧΟΜΕΝΗ @@ -161,8 +159,6 @@ Σημαντική συνομιλία Οι Ειδοποιήσεις σε αυτή την συνομιλία θα παρακάμψουν τις ρυθμίσεις Μην ενοχλείτε Προσκλήσεις - Πρέπει να προάγεται νέο συντονιστή πρίν αποχωρήσετε %1$s. - Δεν μπόρεσε να αποχωρήση από την συνομιλία %1$s Τελευταία τροποποίηση %2$s Εγκατάλειψη συνομιλίας Αποχώρηση από την κλήση ... @@ -320,9 +316,6 @@ Διαμοιρασμός τρέχουσας τοποθεσίας Διαμοιρασμός συνδέσμου Διαμοιρασμός τοποθεσίας - %1$s πρόσκληση - Συμμετοχή στην συνομιλία από %1$s/index.php/call/%2$s - \nΣυνθηματικό: %1$s Διαμοιρασμός αυτής της τοποθεσίας Επιλογή λογαριασμού Κάρτα του Deck @@ -399,7 +392,6 @@ 30 λεπτά Αυτή την εβδομάδα Αυτό το Σαββατοκύριακο - Συνημμένα Σήμερα Αύριο Μετάφραση diff --git a/app/src/main/res/values-es-rEC/strings.xml b/app/src/main/res/values-es-rEC/strings.xml index e33cc74fc7..3bd0a0aa65 100644 --- a/app/src/main/res/values-es-rEC/strings.xml +++ b/app/src/main/res/values-es-rEC/strings.xml @@ -1,6 +1,6 @@ - Ícono de la cuenta + Editar Compartir en %s Bluetooth Salida de audio @@ -48,7 +48,6 @@ Más grande primero Más pequeño primero Mensaje eliminado por ti - Vencimiento del mensaje Toca para abrir la encuesta No hay resultados de búsqueda Comienza a escribir para buscar... @@ -66,7 +65,6 @@ Agregar participantes Agregar a tus favoritos ¡OK, ya terminamos! - Permitir invitados Fijar: %1$s Desbloquear %1$s Opciones avanzadas de llamada @@ -102,7 +100,6 @@ ¿Realmente quieres borrar todos los mensajes de esta conversación? Cambia el certificado del cliente Configura un certificado de cliente - Cerrar aplicación y Copiar Copiado al portapapeles @@ -199,8 +196,6 @@ Escribe un mensaje... Conversación importante Las notificaciones en esta conversación anularán la configuración de No molestar - Necesitas promover a un nuevo moderador antes de poder abandonar %1$s. - No se pudo abandonar la conversación %1$s | Última modificación: %2$s Dejar la conversación Saliendo de la llamada... @@ -228,6 +223,7 @@ Moderador Nunca se unió Nueva conversación + Visibilidad Menciones no leídas Mensajes no leídos %1$s no disponible (no instalado o restringido por el administrador) @@ -377,9 +373,6 @@ Compartir ubicación actual Compartir liga Compartir ubicación - %1$s invitación - Unirse a la conversación en %1$s/index.php/call/%2$s - \nContraseña:%1$s Compartir esta ubicación Elige la cuenta Elementos compartidos @@ -497,7 +490,6 @@ 30 minutos Esta semana Este es un mensaje de prueba - Adjuntos Hoy Mañana Traducir diff --git a/app/src/main/res/values-es/strings.xml b/app/src/main/res/values-es/strings.xml index 244754637b..6b799f48c4 100644 --- a/app/src/main/res/values-es/strings.xml +++ b/app/src/main/res/values-es/strings.xml @@ -1,7 +1,6 @@ Editar - Icono de la cuenta Añadir a Notas Se añadió la conversación %1$s a los favoritos Buscar en %s @@ -66,7 +65,6 @@ Más grandes primero Más pequeñas primero Has eliminado este mensaje - Caducidad de mensajes Editado por %1$s Pulse para abrir la encuesta No hay resultados de búsqueda @@ -85,7 +83,6 @@ Añadir participantes Añadir a favoritos OK. Todo hecho. - Permitir invitados Pin: %1$s Desbloquear %1$s Para habilitar los parlantes bluetooth, por favor, otorgue el permiso \"Dispositivos cercanos\". @@ -127,7 +124,6 @@ ¿Seguro que quieres borrar todos los mensajes en esta conversación? Cambiar certificado de cliente Configurar certificado de cliente - Cerrar app y Copiar Copiado al portapapeles @@ -269,8 +265,6 @@ Las notificaciones de esta conversación anularán el ajuste de No Molestar Invitaciones Unirse a conversaciones abiertas - Necesitas establecer a un nuevo moderador antes de salir %1$s - No puedes dejar la conversación %1$s | Modificado por última vez: %2$s Abandonar conversación Abandonando llamada … @@ -466,9 +460,6 @@ Compartir ubicación actual Compartir enlace Compartir ubicación - %1$s invitación - Únete a la conversación en %1$s/index.php/call/%2$s - \nContraseña: %1$s Compartir esta ubicación Elija una cuenta Elementos compartidos @@ -599,7 +590,6 @@ Esta semana Esto es un mensaje de prueba Este fin de semana - Adjuntos Hoy Mañana Traducir diff --git a/app/src/main/res/values-eu/strings.xml b/app/src/main/res/values-eu/strings.xml index cd500e544e..b84f9a9183 100644 --- a/app/src/main/res/values-eu/strings.xml +++ b/app/src/main/res/values-eu/strings.xml @@ -1,7 +1,6 @@ Aldatu - Kontuaren ikonoa %1$s elkarrizketa gogokoetara gehitu da Bilatu %s(e)n Audio deia @@ -63,7 +62,6 @@ Handienak lehenengo Txikienak lehenengo Mezua ezabatu duzu - Mezuen iraungitzea Sakatu galdeketa irekitzeko Ez dago bilaketaren emaitzarik Hasi idazten bilatzeko … @@ -81,7 +79,6 @@ Gehitu parte-hartzaileak Gehitu gogokoetara Ados, dena eginda! - Gonbidatuak baimendu Pin: %1$s Desblokeatu %1$s Bluetooth bozgorailuak gaitzeko, eman \"Inguruko gailuak\" baimena. @@ -120,7 +117,6 @@ Ziur zaude elkarrizketa honen mezu guztiak ezabatu nahi dituzula? Aldatu bezeroaren ziurtagiria Konfiguratu bezeroaren ziurtagiria - Itxi aplikazioa eta Kopiatu Kopiatu arbelera @@ -229,8 +225,6 @@ Ez Molestatu ezarpenek sahiestuko dituzte elkarrizketa honen jakinarazpenak Gonbidapenak Sartu elkarrizketa irekietara - Moderatzaile berri bat hautatu behar duzu %1$s utzi baino lehen. - Ezin izan da elkarrizketatik irten %1$s | Azkenengoz aldatuta: %2$s Atera elkarrizketatik Deia uzten … @@ -418,9 +412,6 @@ Partekatu uneko kokapena Partekatu esteka Partekatu kokapena - Gonbidapen %1$s - Elkartu elkarrizketara hemen %1$s/index.php/call/%2$s - \nPasahitza: %1$s Partekatu kokapen hau Aukeratu kontua Partekatutako elementuak @@ -550,7 +541,6 @@ Aste honetan Hau probako mezu bat da Asteburu hau - Eranskinak Gaur Bihar Itzuli diff --git a/app/src/main/res/values-fa/strings.xml b/app/src/main/res/values-fa/strings.xml index 965c600167..d36463450b 100644 --- a/app/src/main/res/values-fa/strings.xml +++ b/app/src/main/res/values-fa/strings.xml @@ -1,6 +1,6 @@ - آیکون حساب + ویرایش افزودن به یادداشت‌ها گفتگوی %1$sبه علاقه‌مندی‌ها افزوده شد جستجو در %s @@ -62,7 +62,6 @@ افزودن عضو افزودن‌ به مورد علاقه‌ها خوب ، همه انجام شد! - اجازه میهمانان Pin: %1$s باز کردن %1$s گزینه‌های پیشرفتهٔ تماس @@ -169,8 +168,6 @@ گفتگوی مهم دعوت‌ها پیوستن به گفتگوهای باز - قبل از ترک %1$s، باید یک مدیر جدید را تعیین کنید. - نمی‌توان مکالمه را ترک کرد تغییرات %1$s | آخرین تغییرات: %2$s ترک گفتگو در حال ترک تماس ... @@ -194,6 +191,7 @@ مدیر تاکنون ملحق نشده‌اید گفتگوی جدید + Visibility پیام‌های خوانده نشده مهمان نه @@ -319,9 +317,6 @@ هم‌رسانی مکان فعلی هم‌رسانی پیوند هم‌رسانی مکان - %1$s دعوت - به مکالمهٔ ‪%1$s/index.php/call/%2$s‬ ملحق شوید - \nرمز عبور: %1$s هم‌رسانی این مکان حساب کاربری را انتخاب کنید موارد هم‌رسانی‌شده @@ -396,7 +391,6 @@ ۳۰ دقیقه این هفته این آخر هفته - پیوست ها امروز فردا ترجمه diff --git a/app/src/main/res/values-fi-rFI/strings.xml b/app/src/main/res/values-fi-rFI/strings.xml index d30c56a5e5..25770b6bdc 100644 --- a/app/src/main/res/values-fi-rFI/strings.xml +++ b/app/src/main/res/values-fi-rFI/strings.xml @@ -1,6 +1,6 @@ - Tilikuvake + Muokkaa Etsi kohteesta %s Bluetooth Äänen ulostulo @@ -41,7 +41,6 @@ Ö - A Suurin ensin Pienin ensin - Viestin vanheneminen Ei hakutuloksia Aloita kirjoittaminen hakeaksesi… Hae… @@ -58,7 +57,6 @@ Lisää osallistujat Lisää suosikkeihin OK, kaikki valmista! - Salli vieraat Pin: %1$s Avaa lukitus %1$s Lopeta @@ -163,7 +161,6 @@ Tämän keskustelun ilmoitukset eivät noudata Älä häiritse -asetuksia Kutsut Liity avoimiin keskusteluihin - Ei voitu poistua keskustelusta %1$s | Viimeksi muokattu: %2$s Poistu keskustelusta Poistutaan puhelusta… @@ -189,6 +186,7 @@ Moderaattori Ei koskaan liitytty Uusi keskustelu + Näkyvyys Lukemattomat maininnat Lukemattomat viestit Vieras @@ -316,9 +314,6 @@ Jaa nykyinen sijainti Jaa linkki Jaa sijainti - %1$s kutsu - Liity keskusteluun osoitteessa %1$s/index.php/call/%2$s - \nSalasana: %1$s Jaa tämä sijainti Valitse tili Jaetut tietueet @@ -403,7 +398,6 @@ 30 minuuttia Tämä viikko Tämä viikonloppu - Liitteet Tänään Huomenna Käännä diff --git a/app/src/main/res/values-fr/strings.xml b/app/src/main/res/values-fr/strings.xml index e573ced2dd..225d4b3a2e 100644 --- a/app/src/main/res/values-fr/strings.xml +++ b/app/src/main/res/values-fr/strings.xml @@ -1,7 +1,6 @@ Modifier - Icône du compte Ajouter à Notes La conversation %1$s a été ajoutée aux favorites Rechercher dans %s @@ -75,7 +74,6 @@ Les plus gros d\'abord Le plus petit en premier Message supprimé par vous - Expiration du message Modifié par %1$s Toucher pour ouvrir le sondage Aucun résultat de recherche @@ -94,7 +92,6 @@ Ajouter des participants Ajouter aux favoris OK, tout est fini ! - Autoriser les invités Épingler : %1$s Déverrouiller %1$s Pour activer les écouteurs Bluetooth, merci de donner la permission « Appareils à proximité ». @@ -134,7 +131,6 @@ Voulez-vous vraiment supprimer tous les messages de cette conversation ? Modifier le certificat du client Configurer le certificat du client - Fermer l\'application et Copier Copié dans le presse-papier @@ -266,8 +262,6 @@ Les notifications dans cette conversation l\'emportent sur les paramètres « Ne Pas Déranger ». Invitations Rejoindre des conversations ouvertes - Vous devez désigner un nouveau modérateur avant de quitter %1$s. - Impossible de quitter la conversation %1$s | Dernière modification : %2$s Quitter la conversation Fin d\'appel … @@ -296,6 +290,7 @@ Modérateur Jamais contacté Nouvelle conversation + Visibilité Mentions non lues Messages non lus %1$s non disponible (non installé ou restreint par l\'administrateur) @@ -461,9 +456,6 @@ De l\'aide supplémentaire peut être trouvée sur DontKillMyApp.com ou dans la Partager la position actuelle Lien de partage Partager la position - %1$s invitation - Rejoins la conversation à %1$s/index.php/call/%2$s - \nMot de passe : %1$s Partager cette position Sélectionnez un compte Éléments partagés @@ -597,7 +589,6 @@ De l\'aide supplémentaire peut être trouvée sur DontKillMyApp.com ou dans la Cette semaine Ceci est un message de test Ce week-end - Pièces jointes Aujourd\'hui Demain Traduire diff --git a/app/src/main/res/values-ga/strings.xml b/app/src/main/res/values-ga/strings.xml index a9ccad4225..a898e82e3f 100644 --- a/app/src/main/res/values-ga/strings.xml +++ b/app/src/main/res/values-ga/strings.xml @@ -1,7 +1,6 @@ Cuir in eagar - Deilbhín cuntais Cuir le Nótaí Cuireadh comhrá %1$s le ceanáin Cuardaigh i %s @@ -76,7 +75,6 @@ An ceann is mó ar dtús Is lú ar dtús Scrios tú an teachtaireacht - Teachtaireacht in éag Curtha in eagar ag %1$s Tapáil chun vótaíocht a oscailt Gan torthaí cuardaigh @@ -95,7 +93,6 @@ Cuir rannpháirtithe leis Cuir le ceanáin Ceart go leor, déanta go léir! - Ceadaigh aíonna Bioráin: %1$s Díghlasáil %1$s Chun cainteoirí Bluetooth a chumasú, deonaigh cead \"Gléasanna in aice láimhe\" le do thoil. @@ -137,7 +134,6 @@ An bhfuil tú cinnte gur mhaith leat gach teachtaireacht sa chomhrá seo a scriosadh? Athraigh teastas an chliaint Socraigh teastas cliant - Dún an aip agus Cóipeáil Cóipeáladh chuig an ngearrthaisce @@ -279,8 +275,6 @@ Sáróidh fógraí sa chomhrá seo na socruithe Ná Cuir Isteach cuirí Glac páirt i gcomhráite oscailte - Ní mór duit modhnóir nua a chur chun cinn sular féidir leat %1$s a fhágáil. - Níorbh fhéidir an comhrá a fhágáil %1$s | Athraithe is déanaí: %2$s Fág an comhrá Ag fágáil an ghlao… @@ -476,9 +470,6 @@ Roinn an suíomh reatha Comhroinn nasc Comhroinn suíomh - Cuireadh %1$s - Glac páirt sa chomhrá ag %1$s/index.php/call/%2$s - \nFocal Faire: %1$s Roinn an suíomh seo Roghnaigh cuntas Míreanna roinnte @@ -613,7 +604,6 @@ An tseachtain seo Is teachtaireacht tástála é seo An deireadh seachtaine seo - Ceangaltáin Inniu Amárach Aistrigh diff --git a/app/src/main/res/values-gl/strings.xml b/app/src/main/res/values-gl/strings.xml index 887f2d963d..093a2d8d88 100644 --- a/app/src/main/res/values-gl/strings.xml +++ b/app/src/main/res/values-gl/strings.xml @@ -1,7 +1,6 @@ Editar - Icona da conta Engadir a Notas Engadiuse a conversa %1$s aos favoritos Buscar en %s @@ -76,7 +75,6 @@ Primeiro o máis grande Primeiro o máis pequeno Mensaxe eliminada por Vde. - Caducidade da mensaxe Editado por %1$s Toque para abrir a enquisa Sen resultados de busca @@ -95,7 +93,6 @@ Engadir participantes Engadir a favoritos Conforme, todo feito! - Permitir convidados Pin: %1$s Desbloquear %1$s Para activar os altofalantes Bluetooth, conceda os permiso para «Dispositivos próximos». @@ -137,7 +134,6 @@ Confirma que quere eliminar todas as mensaxes desta conversa? Cambiar o certificado do cliente Configurar o certificado do cliente - Pechar a aplicación e Copiar Copiado no portapapeis @@ -279,8 +275,6 @@ As notificacións nesta conversa anularán os axustes de «Non molestar» Convites Unirse a conversas abertas - Debe promover un novo moderador antes de poder abandonar %1$s. - Non foi posíbel dixar a conversa %1$s | Última modificación: %2$s Deixar a conversa Abandonando a chamada… @@ -476,9 +470,6 @@ Compartir a localización actual Ligazón para compartir Compartir a localización - %1$s convite - Únase á conversa en %1$s/index.php/call/%2$s - \nContrasinal: %1$s Compartir esta localización Escoller unha conta Elementos compartidos @@ -613,7 +604,6 @@ Esta semana Esta é unha mensaxe de proba Este fin de semana - Anexos Hoxe Mañá Traducir diff --git a/app/src/main/res/values-hr/strings.xml b/app/src/main/res/values-hr/strings.xml index d7d3f00371..4111d7d117 100644 --- a/app/src/main/res/values-hr/strings.xml +++ b/app/src/main/res/values-hr/strings.xml @@ -1,7 +1,6 @@ Uredi - Ikona korisničkog računa Traži u %s Telefon Zvučnik @@ -54,7 +53,6 @@ Dodaj sudionike Dodaj u favorite U redu, završeno! - Dopusti pristup gostima Prikvači: %1$s Otključaj %1$s Poklopi @@ -159,8 +157,6 @@ Važan razgovor Obavijesti u okviru ovog razgovora prikazuju se neovisno o postavkama Ne uznemiravaj Pozivnice - Morate odabrati novog moderatora prije nego što napustite %1$s. - Nije moguće napustiti razgovor %1$s | Posljednja izmjena: %2$s Napusti razgovor Napuštanje poziva … @@ -322,9 +318,6 @@ Dijeli trenutačnu lokaciju Dijeli poveznicu Dijeli lokaciju - %1$s pozivnica - Pridruži se razgovoru na adresi %1$s/index.php/call/%2$s - \nZaporka: %1$s Dijeli ovu lokaciju Odaberi račun Deck kartica @@ -398,7 +391,6 @@ Uključi/isključi svjetlo 30 minuta Ovaj tjedan - Privici Danas Sutra Prevedi diff --git a/app/src/main/res/values-hu-rHU/strings.xml b/app/src/main/res/values-hu-rHU/strings.xml index 12c6efa649..d53b77a8e9 100644 --- a/app/src/main/res/values-hu-rHU/strings.xml +++ b/app/src/main/res/values-hu-rHU/strings.xml @@ -1,7 +1,6 @@ Szerkesztés - Fiókikon A(z) %1$s beszélgetés hozzáadva a kedvencekhez Keresés itt: %s Audio hívás @@ -74,7 +73,6 @@ Résztvevők hozzáadása Hozzáadás a kedvencekhez Rendben, minden kész! - Vendégek engedélyezése PIN: %1$s %1$s feloldása Speciális hívásbeállítások @@ -111,7 +109,6 @@ Biztos, hogy törli a beszélgetés összes üzenetét? Klienstanúsítvány módosítása Klienstanúsítvány beállítása - Alkalmazás bezárása és Másolás Vágólapra másolva @@ -213,8 +210,6 @@ E beszélgetés értesítései felülírják a Ne zavarjanak beállításokat Meghívások Csatlakozás a nyílt beszélgetésekhez - Új moderátort kell kineveznie, mielőtt elhagyhatja ezt: %1$s. - Nem sikerült elhagyni a beszélgetést %1$s | Utoljára módosítva: %2$s Beszélgetés elhagyása Hívás elhagyása… @@ -399,9 +394,6 @@ Jelenlegi hely megosztása Megosztási hivatkozás Hely megosztása - %1$s meghívás - Csatlakozzon a beszélgetéshez itt: %1$s/index.php/call/%2$s - \nJelszó: %1$s Ezen hely megosztása Válasszon fiókot Megosztott elemek @@ -528,7 +520,6 @@ Ez a hét Ez egy teszt üzenet Ezen a hétvégén - Mellékletek Ma Holnap Lefordítás diff --git a/app/src/main/res/values-it/strings.xml b/app/src/main/res/values-it/strings.xml index 131e824ef9..8e3be4aa36 100644 --- a/app/src/main/res/values-it/strings.xml +++ b/app/src/main/res/values-it/strings.xml @@ -1,7 +1,6 @@ Modifica - Icona dell\'account Cerca in %s Bluetooth Uscita audio @@ -62,7 +61,6 @@ Aggiungi partecipanti Aggiungi ai preferiti OK, tutto fatto! - Consenti ospiti Appunta: %1$s Sblocca %1$s Opzioni avanzate per le chiamate @@ -177,8 +175,6 @@ Conversazione importante Le notifiche in questa conversazione ignoreranno l\'impostazione Non disturbare Inviti - Devi promuovere un nuovo moderatore prima di poter abbandonare %1$s. - Impossibile lasciare la conversazione %1$s | Ultima modifica: %2$s Lascia la conversazione Chiusura della chiamata in corso … @@ -346,9 +342,6 @@ Condividi la posizione attuale Collegamento di condivisione Condividi posizione - %1$s invito - Partecipa alla conversazione su %1$s/index.php/call/%2$s - \nPassword: %1$s Condividi questa posizione Scegli account Oggetti condivisi @@ -437,7 +430,6 @@ Accendi/spegni la torcia 30 minuti Questa settimana - Allegati Oggi Domani Traduci diff --git a/app/src/main/res/values-ja-rJP/strings.xml b/app/src/main/res/values-ja-rJP/strings.xml index bd73d625aa..bdeb071a70 100644 --- a/app/src/main/res/values-ja-rJP/strings.xml +++ b/app/src/main/res/values-ja-rJP/strings.xml @@ -1,7 +1,6 @@ 編集 - アカウントアイコン メモに追加する %1$s会話をお気に入りに追加した %sを検索 @@ -66,7 +65,6 @@ サイズ(降順) サイズ(昇順) あなたが削除したメッセージ - メッセージの有効期限 %1$sに編集されました タップして投票を開く 検索結果なし @@ -85,7 +83,6 @@ 参加を追加 お気に入りに追加 OK、すべて完了! - ゲストを許可する ピン: %1$s %1$sを解除 Bluetooth スピーカーを有効にするには、「近くのデバイス」の権限を付与してください。 @@ -127,7 +124,6 @@ 本当にこの会話の全てのメッセージを削除してもよろしいですか? クライアント証明書を変更する クライアント証明書を設定する - アプリを閉じる かつ コピー クリップボードにコピーされました @@ -268,8 +264,6 @@ この会話の通知設定は、取り込み中設定を上書きします 招待 オープンな会話に参加する - %1$sを退出する前に、新しいモデレータを昇格させる必要があります。 - 会話を退出できませんでした %1$s最終更新:%2$s 会話を離れる 通話を終了 … @@ -462,9 +456,6 @@ 現在の位置を共有 共有リンク 位置を共有 - %1$s を招待 - %1$s/index.php/call/%2$s での会話に参加する - \nパスワード:%1$s この位置を共有 アカウントを選択 共有済みアイテム @@ -594,7 +585,6 @@ 今週 これはテストメッセージです この週末 - 添付ファイル 今日 明日 翻訳 diff --git a/app/src/main/res/values-ko/strings.xml b/app/src/main/res/values-ko/strings.xml index 1ff9cf63ac..b63dfc3760 100644 --- a/app/src/main/res/values-ko/strings.xml +++ b/app/src/main/res/values-ko/strings.xml @@ -1,7 +1,6 @@ 편집 - 계정 아이콘 %s 검색 음성 통화 블루투스 @@ -49,7 +48,6 @@ 큰 것 먼저 작은 것 먼저 메시지를 삭제함 - 메시지 만료 투표를 열기 위하여 탭하세요. 결과를 찾을 수 없음 ...를 검색하기 위하여 입력을 시작합니다 @@ -67,7 +65,6 @@ 참가자 추가 즐겨찾기에 추가 모두 완료되었습니다! - 손님 초대 핀: %1$s %1$s 잠금 해제 영상 통화로 응답합니다. @@ -187,8 +184,6 @@ 메시지 입력… 중요한 대화 공개 대화에 참가 - %1$s(을)를 떠나기 전에 새로운 중재자를 임명해야 합니다. - 대화를 떠날 수 없습니다. %1$s | 최종 수정: %2$s 대화 나가기 통화 종료 중 ... @@ -360,9 +355,6 @@ 주소록을 읽기 위하여 권한이 필요합니다. 현재 위치 공유 위치 공유 - %1$s 초대 - %1$s/index.php/call/%2$s 대화에 참가 - \n패스워드: %1$s 이 위치를 공유 계정 선택 공유된 항목들 @@ -479,7 +471,6 @@ 30분 이번 주 이번 주말 - 첨부파일 오늘 내일 번역: diff --git a/app/src/main/res/values-lt-rLT/strings.xml b/app/src/main/res/values-lt-rLT/strings.xml index 122dfacb81..fa5034ddeb 100644 --- a/app/src/main/res/values-lt-rLT/strings.xml +++ b/app/src/main/res/values-lt-rLT/strings.xml @@ -1,7 +1,6 @@ Taisyti - Paskyros piktograma Ieškoti %s Telefonas Avataras @@ -48,7 +47,6 @@ Pridėti dalyvius Pridėti į mėgstamus Gerai, viskas atlikta! - Leisti svečius Atrakinti %1$s Padėti ragelį Pokalbio pavadinimas @@ -128,8 +126,6 @@ Silpnas slaptažodis Svarbus pokalbis Pakvietimai - Prieš išeidami iš %1$s, turite paaukštinti naują moderatorių. - Nepavyko išeiti iš pokalbio %1$s | Paskutinį kartą modifikuota: %2$s Išeiti iš pokalbio GNU Bendroji Viešoji Licencija, Versija 3 @@ -249,9 +245,6 @@ Įspėjimas Iš naujo įgaliota gali būti tik esama paskyra Bendrinimo nuoroda - %1$s pakvietimas - Prisijunkite prie pokalbio, adresu %1$s/index.php/call/%2$s - \nSlaptažodis: %1$s Bendrinti šią vietą Parinkti paskyrą Bendrinami elementai @@ -318,7 +311,6 @@ 30 minučių Šią savaitę Šį savaitgalį - Priedai Šiandiena Rytoj Verskite diff --git a/app/src/main/res/values-nb-rNO/strings.xml b/app/src/main/res/values-nb-rNO/strings.xml index 6a716f650f..df99a1e526 100644 --- a/app/src/main/res/values-nb-rNO/strings.xml +++ b/app/src/main/res/values-nb-rNO/strings.xml @@ -1,7 +1,6 @@ Rediger - Kontoikon Legg til notater La til samtale %1$s i favoritter Søk i %s @@ -76,7 +75,6 @@ Største først Minste først Melding slettet av deg - Utløp av melding Redigert av %1$s Trykk for å åpne avstemningen Ingen søkeresultater @@ -95,7 +93,6 @@ Legg til deltager Legg til favoritter OK, ferdig! - Tillat gjester PIN: %1$s Lås opp %1$s For å aktivere Bluetooth-høyttalere, vennligst gi \"Enheter i nærheten\" tillatelse. @@ -137,7 +134,6 @@ Ønsker du virkelig å slette alle meldinger i denne samtalen? Endre klient sertifikat Sett opp klient sertifikat - Lukk app og Kopi Kopiert til utklippstavlen @@ -279,8 +275,6 @@ Varsler i denne samtalen overstyrer innstillingene for Ikke forstyrr Invitasjoner Bli med i åpne samtaler - Du må utnevne en ny moderator før du kan forlate %1$s. - Kunne ikke forlate samtalen %1$s | Sist endret: %2$s Forlat samtale Forlater samtalen... @@ -474,9 +468,6 @@ Del gjeldende plassering Del lenke Del plassering - %1$s invitasjon - Delta i samtalen via %1$s/index.php/call/%2$s - \nPassord: %1$s Del denne plasseringen Velg konto Delte elementer @@ -611,7 +602,6 @@ Denne uken Dette er en testmelding Denne helgen - Vedlegg I dag I morgen Oversette diff --git a/app/src/main/res/values-nl/strings.xml b/app/src/main/res/values-nl/strings.xml index 1e8b612d12..1b3384d34d 100644 --- a/app/src/main/res/values-nl/strings.xml +++ b/app/src/main/res/values-nl/strings.xml @@ -1,7 +1,6 @@ Bewerken - Accountpictogram Zoeken in %s Bluetooth Audio output @@ -60,7 +59,6 @@ Toevoegen deelnemers Toevoegen aan favorieten OK, alles in orde! - Laat gasten toe Pin: %1$s Ontgrendel %1$s Geavanceerde oproepopties @@ -177,8 +175,6 @@ Kies er eentje van een provider. Belangrijk gesprek Meldingen in dit gesprek negeren de Niet-Storen instellingen Uitnodigingen - Je moet eerst een nieuwe moderator kiezen voordat je het gesprek kan verlaten %1$s. - Kon het gesprek niet verlaten %1$s | Laatst gewijzigd: %2$s Verlaat gesprek Verlaten gesprek … @@ -347,9 +343,6 @@ Kies er eentje van een provider. Deel huidige locatie Deel link Deel locatie - %1$s uitnodiging - Neem deel aan het gesprek %1$s/index.php/call/%2$s - \nWachtwoord: %1$s Deel deze locatie Kies account Gedeelde objecten @@ -447,7 +440,6 @@ Kies er eentje van een provider. Schakel zaklamp 30 minuten Deze week - Bijlagen Vandaag Morgen Vertaal diff --git a/app/src/main/res/values-pl/strings.xml b/app/src/main/res/values-pl/strings.xml index 684492436d..3cc23610bf 100644 --- a/app/src/main/res/values-pl/strings.xml +++ b/app/src/main/res/values-pl/strings.xml @@ -1,7 +1,6 @@ Edycja - Ikona konta Dodaj do Notatek Dodano rozmowę %1$s do ulubionych Szukaj w %s @@ -66,7 +65,6 @@ Od największych Od najmniejszych Wiadomość usunięta przez Ciebie - Wygaśnięcie wiadomości Edytowany przez %1$s Dotknij, aby otworzyć sondę Brak wyników wyszukiwania @@ -85,7 +83,6 @@ Dodaj uczestników Dodaj do ulubionych OK, wszystko gotowe! - Zezwól gościom Przypnij: %1$s Odblokuj %1$s Aby włączyć głośniki Bluetooth, należy udzielić dostępu dla \"Urządzenia w pobliżu\". @@ -127,7 +124,6 @@ Czy na pewno chcesz usunąć wszystkie wiadomości z tej rozmowy? Zmień certyfikat klienta Skonfiguruj certyfikat klienta - Zamknij aplikację i Skopiuj Kopiuj do schowka @@ -269,8 +265,6 @@ Powiadomienia w tej rozmowie ignorują ustawienia \"Nie przeszkadzać\" Zaproszenia Dołącz do otwartych rozmów - Musisz promować nowego moderatora, zanim opuścisz %1$s. - Nie udało się opuścić rozmowy %1$s | Ostatnio zmodyfikowany: %2$s Opuść rozmowę Opuszczanie połączenia… @@ -465,9 +459,6 @@ Udostępnij obecną lokalizację Udostępnij link Udostępnij lokalizację - zaproszenie %1$s - Dołącz do rozmowy %1$s/index.php/call/%2$s - \nHasło: %1$s Udostępnij tę lokalizację Wybierz konto Udostępnione elementy @@ -598,7 +589,6 @@ W tym tygodniu To jest wiadomość testowa W ten weekend - Załączniki Dzisiaj Jutro Tłumaczenie diff --git a/app/src/main/res/values-pt-rBR/strings.xml b/app/src/main/res/values-pt-rBR/strings.xml index edada7a00e..e1fc37f2d8 100644 --- a/app/src/main/res/values-pt-rBR/strings.xml +++ b/app/src/main/res/values-pt-rBR/strings.xml @@ -1,7 +1,6 @@ Editar - Ícone da conta Adicionar às Notas Conversa adicionada %1$s para favoritos Pesquisar em %s @@ -76,7 +75,6 @@ Maior primeiro Menor primeiro Mensagem excluída por você - Expiração da mensagem Editado por %1$s Toque para abrir a enquete Nenhum resultado encontrado @@ -95,7 +93,6 @@ Adicionar participantes Adicionar aos favoritos OK, tudo pronto! - Permitir convidados Pino: %1$s Desbloquear %1$s Para ativar os alto-falantes bluetooth, conceda a permissão \"Dispositivos próximos\". @@ -137,7 +134,6 @@ Tem certeza de que deseja excluir todas as mensagens desta conversa? Alterar certificado do cliente Configurar certificado do cliente - Fechar aplicativo e Copiar Copiado para a área de transferência @@ -279,8 +275,6 @@ As notificações nesta conversa substituirão as configurações de Não perturbe Convites Participe de conversas abertas - Você precisa promover alguém a moderador antes de sair de %1$s. - Não foi possível sair da conversa %1$s | Modificado recentemente: %2$s Sair da conversa Saindo da chamada … @@ -475,9 +469,6 @@ Compartilhe a localização atual Compartilhar link Compartilhar localização - Convite do %1$s - Junte-se à conversa em %1$s/index.php/call/%2$s - \nSenha: %1$s Compartilhe este local Escolha a conta Itens compartilhados @@ -612,7 +603,6 @@ Esta semana Esta é uma mensagem de teste Este fim de semana - Anexos Hoje Amanhã Traduzir diff --git a/app/src/main/res/values-ru/strings.xml b/app/src/main/res/values-ru/strings.xml index 4b1af01b82..2ca69b9a9e 100644 --- a/app/src/main/res/values-ru/strings.xml +++ b/app/src/main/res/values-ru/strings.xml @@ -1,7 +1,6 @@ Редактирование - Значок учётной записи Искать в %s Аудиозвонок Bluetooth @@ -55,7 +54,6 @@ Самый большой первый Самый маленький первый Сообщение удалено вами - Срок истечения сообщения Нажмите для открытия опроса Ничего не найдено Начните печатать для поиска … @@ -73,7 +71,6 @@ Добавить участников Добавить в избранное Всё готово! - Разрешить гостей Пин: %1$s Разблокировать %1$s Дополнительные настройки звонка @@ -110,7 +107,6 @@ Вы действительно хотите удалить все сообщения в этой беседе? Изменение клиентского сертификата Установка клиентского сертификата - Закрыть приложение и Копировать Скопировано в буфер обмена @@ -211,8 +207,6 @@ Уведомления в этом чате имеют приоритет над настройками режима \"Не беспокоить\" Приглашения Присоединиться к открытым обсуждениям - Перед выходом из обсуждения %1$s необходимо назначить нового модератора. - Не удалось выйти из обсуждения %1$s | Последнее изменение: %2$s Покинуть беседу Завершение вызова … @@ -391,9 +385,6 @@ Поделиться текущим местоположением Поделиться ссылкой Поделиться местоположением - %1$s приглашение - Присоединиться к беседе в %1$s/index.php/call/%2$s - \nПароль: %1$s Поделиться этим местом Выбрать учётную запись Общие элементы @@ -405,6 +396,7 @@ Сортировать по Время начала Сменить аккаунт + Команда Команды Выберите файлы Отправить эти файлы %1$s? @@ -427,6 +419,7 @@ « Сдвинуть для отмены Вебинар Да + Значок создания новой беседы Следующая неделя Отсутствуют разрешения на интеграцию номера телефона 1 час @@ -517,7 +510,6 @@ 30 минут Эта неделя Эта неделя - Вложения Сегодня Завтра Помочь с переводом diff --git a/app/src/main/res/values-sc/strings.xml b/app/src/main/res/values-sc/strings.xml index 910be65eb6..8948b5b0da 100644 --- a/app/src/main/res/values-sc/strings.xml +++ b/app/src/main/res/values-sc/strings.xml @@ -1,7 +1,6 @@ Modìfica - Icona de su contu Chirca in %s Telèfonu Altoparlante @@ -51,7 +50,6 @@ Aguinghe partetzipantes Agiunghe a preferidos AB, fatu! - Autoriza persones invitadas Apunta: %1$s Isbloca %1$s Serra @@ -155,8 +153,6 @@ Cumpartzi su ligòngiu de sa resonada Tzarrada importante Is notìficas in custa resonada ant a ignorare sa cunfiguratzione No istorbare - Depes promòvere un\'àtera persona chi moderet antis de lassare %1$s - No at fatu a lassare sa resonada %1$s | Ùrtima modìfica: %2$s Lassa resonada GNU General Public License, Versione 3 @@ -310,9 +306,6 @@ Cumpartzi sa positzione atuale Cumpartzi ligòngiu Cumpartzi positzione - %1$s invitu - Intra in sa tzarrada in %1$s/index.php/call/%2$s - \nCrae: %1$s Cumpartzi custa positzione Sèbera contu Ischeda in Deck @@ -384,7 +377,6 @@ Ativa sa tortza 30 minutos Custa chida - Alligongiados Oe Cras Borta diff --git a/app/src/main/res/values-sk-rSK/strings.xml b/app/src/main/res/values-sk-rSK/strings.xml index fcdf9ad9c6..115fd5905d 100644 --- a/app/src/main/res/values-sk-rSK/strings.xml +++ b/app/src/main/res/values-sk-rSK/strings.xml @@ -1,7 +1,6 @@ Upraviť - Ikona účtu Pridať do poznámok Pridať konverzáciu %1$s k obľúbeným Hľadať v %s @@ -66,7 +65,6 @@ Najväčšie prvé Najmenšie prvé Správu ste odstránili - Vypršanie platnosti správy Upravil%1$s Klepnutím otvoríte anketu Žiadne výsledky vyhľadávania @@ -85,7 +83,6 @@ Pridať účastníkov Pridať do obľúbených OK, všetko hotovo! - Povoliť hostí Špendlík: %1$s Odomknúť %1$s Ak chcete povoliť reproduktory bluetooth, udeľte povolenie „Zariadenia v blízkosti“. @@ -126,7 +123,6 @@ Naozaj chcete vymazať všetky správy v tejto konverzácii? Zmeniť klientský certifikát Nastaviť klientský certifikát - Zavrieť aplikáciu a Kopírovať Skopírované do schránky @@ -268,8 +264,6 @@ Oznámenia v tejto konverzácii sa prepíšu nastavením Nerušiť Pozvánky Pripojiť sa k prebiehajúcim konverzáciam - Skôr než budete môcť opustiť %1$s , je potrebné niekomu odovzdať rolu moderátora. - Nie je možné opustiť konverzáciu %1$s | Posledná úprava: %2$s Opustiť konverzáciu Opúšťam hovor … @@ -464,9 +458,6 @@ Zdieľať súčasnú polohu Zdieľať odkaz Zdieľať polohu - %1$sPozvánka - Pripojte sa ku konverzácii na %1$s/index.php/call/%2$s - \nHeslo: %1$s Zdieľať túto polohu Zvoliť účet Zdieľané položky @@ -596,7 +587,6 @@ Tento týždeň Toto je skúšobná správa Tento víkend - Prílohy Dnes Zajtra Preložiť diff --git a/app/src/main/res/values-sl/strings.xml b/app/src/main/res/values-sl/strings.xml index d54c8a13eb..9057bb8ca9 100644 --- a/app/src/main/res/values-sl/strings.xml +++ b/app/src/main/res/values-sl/strings.xml @@ -1,7 +1,6 @@ Uredi - Ikona računa Poišči v %s Bluetooth Odvod zvoka @@ -48,7 +47,6 @@ najprej največje najprej najmanjše Sporočilo ste izbrisali - Pretek sporočila Pritisnite za prikaz ankete Ni zadetkov iskanja Vpišite niz za iskanje … @@ -66,7 +64,6 @@ Dodaj udeležence Dodaj med priljubljene Opravilo je uspešno končano! - Dovoli povezave z gosti Koda PIN: %1$s Odkleni %1$s Napredne možnosti klica @@ -199,8 +196,6 @@ Prikaz obvestil v tem pogovoru onemogočil nastavitev Ne moti. Povabila Pridruži se odprtemu pogovoru - Pred odhodom iz %1$s morate nekoga določiti za moderatorja. - Pogovora ni mogoče zapustiti %1$s | Nazadnje spremenjeno: %2$s Zapusti pogovor Poteka prekinjanje klica … @@ -376,9 +371,6 @@ Objavi trenutno mesto Povezava za souporabo Objavi trenutno mesto - povabilo %1$s - Pridružite se pogovoru na %1$s/index.php/call/%2$s - \nGeslo: %1$s Objavi trenutno mesto Izbor računa Predmeti v souporabi @@ -496,7 +488,6 @@ Preklopi bliskavico 30 minut Ta teden - Priloge Danes Jutri Prevodi diff --git a/app/src/main/res/values-sr/strings.xml b/app/src/main/res/values-sr/strings.xml index 6bca6ae861..2eb69510b8 100644 --- a/app/src/main/res/values-sr/strings.xml +++ b/app/src/main/res/values-sr/strings.xml @@ -1,7 +1,6 @@ Измени - Икона налога Додај у Белешке Разговор %1$s је додат у омиљене Тражи у %s @@ -76,7 +75,6 @@ Прво највеће Прво најмање Обрисали сте поруку - Рок трајања поруке Уредио је %1$s Тапните да отворите гласање Нема резултата претраге @@ -95,7 +93,6 @@ Додај учеснике Додај у омиљене У реду, све готово! - Дозволи госте Прикачено: %1$s Откључај %1$s Ако желите да укључите bluetooth звучнике, молимо вас да дате дозволу „Оближњи уређаји” @@ -137,7 +134,6 @@ Да ли заиста желите да обришете све поруке у овом разговору? Измени клијентски сертификат Подесите клијентски сертификат - Затвори апликацију и Копирај Копирано у клипборд @@ -279,8 +275,6 @@ Обавештења у овом разговору ће преиначити Не узнемиравај поставке. Позивнице Придружи се отвореном разговору - Морате одредити новог модератора пре него што напустите %1$s. - Не можете напустити разговор %1$s | Последње измењено: %2$s Напусти разговор Напуштање позива ... @@ -475,9 +469,6 @@ Дели тренутну локацију Подели везу Дели локацију - %1$s позивница - Придружи се разговору на%1$s/index.php/call/%2$s - \nЛозинка: %1$s Подели ову локацију Одаберите налог Дељене ставке @@ -612,7 +603,6 @@ Ове недеље Ово је тест порука Овог викенда - Прилози Данас Сутра Превођење diff --git a/app/src/main/res/values-sv/strings.xml b/app/src/main/res/values-sv/strings.xml index e7b5a7d2ef..d73ba3ad83 100644 --- a/app/src/main/res/values-sv/strings.xml +++ b/app/src/main/res/values-sv/strings.xml @@ -1,7 +1,6 @@ Redigera - Kontoikon Lägg till i anteckningar Lade till konversationen %1$s till favoriter Sök i %s @@ -74,7 +73,6 @@ Störst först Minst först Meddelandet togs bort av dig - Meddelande löper ut Redigerad av %1$s Tryck för att öppna omröstningen Inga sökresultat @@ -93,7 +91,6 @@ Lägg till deltagare Lägg till som favorit Ok, allt klart! - Tillåt gäster Pin: %1$s Lås upp %1$s För att aktivera bluetooth-högtalare måste du bevilja tillstånd för \"Enheter i närheten\". @@ -134,7 +131,6 @@ Vill du verkligen ta bort alla meddelanden i den här konversationen? Ändra klientcertifikat Konfigurera klientcertifikat - Stäng appen och Kopiera Kopierat till urklipp @@ -275,8 +271,6 @@ Meddelanden i den här konversationen kommer att åsidosätta Stör inte-inställningar Inbjudningar Gå med i öppna konversationer - Du måste tilldela en ny moderator innan du kan lämna %1$s. - Kunde inte lämna konversationen %1$s | Senast ändrad: %2$s Lämna konversationen Lägger på … @@ -470,9 +464,6 @@ Dela aktuell plats Delningslänk Dela plats - %1$s inbjudan - Gå med i konversationen på %1$s/index.php/call/%2$s - \nLösenord: %1$s Dela den här platsen Välj konto Delade objekt @@ -604,7 +595,6 @@ Denna vecka Detta är ett testmeddelande Denna helgen - Bilagor Idag I morgon Översätt diff --git a/app/src/main/res/values-tr/strings.xml b/app/src/main/res/values-tr/strings.xml index 0ea192d512..1401d28fe4 100644 --- a/app/src/main/res/values-tr/strings.xml +++ b/app/src/main/res/values-tr/strings.xml @@ -1,7 +1,6 @@ Düzenle - Hesap simgesi Notlar uygulamasına ekle %1$s görüşmesi sık kullanılara eklendi %s içinde arama @@ -76,7 +75,6 @@ Büyükten küçüğe Küçükten büyüğe İleti sizin tarafınızdan silindi - İleti süresi %1$s tarafından düzenlendi Anketi açmak için dokunun Aramadan bir sonuç alınamadı @@ -95,7 +93,6 @@ Katılımcı ekle Sık kullanılanlara ekle Hepsi tamam! - Konuklar katılabilsin Pin: %1$s %1$s kilidini aç Bluetooth hoparlörleri etkinleştirmek için lütfen \"Yakındaki aygıtlar\" izni verin. @@ -137,7 +134,6 @@ Bu görüşmedeki tüm iletileri silmek istediğinize emin misiniz? İstemci sertifikasını değiştir İstemci sertifikası kurulumu - Uygulamayı kapat ve Kopyala Panoya kopyalandı @@ -279,8 +275,6 @@ Bu görüşmedeki bildirimler Rahatsız Etmeyin ayarlarını değiştirecek Davetler Açık görüşmelere katıl - %1$s görüşmesinden ayrılabilmek için başka bir kullanıcıyı sorumluluğa yükseltmelisiniz. - Görüşmeden ayrılınamadı %1$s | Son değişiklik: %2$s Görüşmeden ayrıl Çağrıdan çıkılıyor… @@ -475,9 +469,6 @@ Geçerli konumu paylaş Bağlantıyı paylaş Konumu paylaş - %1$s davet - Çağrıya şuradan katılın %1$s/index.php/call/%2$s - \nParola: %1$s Bu konumu paylaş Hesap seçin Paylaşılmış ögeler @@ -612,7 +603,6 @@ Bu hafta Bu bir deneme iletisidir Bu hafta sonu - Ek dosyalar Bugün Yarın Çevir diff --git a/app/src/main/res/values-uk/strings.xml b/app/src/main/res/values-uk/strings.xml index b3ef108a75..998cc352de 100644 --- a/app/src/main/res/values-uk/strings.xml +++ b/app/src/main/res/values-uk/strings.xml @@ -1,7 +1,6 @@ Редагувати - Зображення облікового запису Пошук у %s Голосовий виклик Bluetooth @@ -48,7 +47,6 @@ Найбільші за розміром спочатку Найменші за розміром спочатку Ви вилучили повідомлення - Термін дії повідомлення Натисніть, щоб відкрити опитування Нічого не знайдено Що шукаємо? @@ -66,7 +64,6 @@ Додати учасників Додати зірочку ОК, все готово! - Дозволити гостей ПІН: %1$s Розблокувати %1$s Розширені опції дзвінка @@ -192,8 +189,6 @@ Введіть повідомлення ... Важлива розмова Сповіщення в цій розмові ігнорують опцію \"Не турбувати\" - Ви повинні призначити нового модератора перш ніж покинути %1$s. - Неможливо покинути розмову %1$s | Остання зміна: %2$s Вийти з групи Завершення виклику ... @@ -365,9 +360,6 @@ Поділіться поточним місцем розташування Доступ за посиланням Поділіться місцем розташування - %1$s запрошення - Приєднатися до бесіди в %1$s/index.php/call/%2$s - \nПароль: %1$s Поділіться цим розташуванням Оберіть обліковий запис Спільні елементи @@ -457,7 +449,6 @@ 30 хвилин Цього тижня Цими вихідними - Вкладення Сьогодні Завтра Перекласти diff --git a/app/src/main/res/values-zh-rCN/strings.xml b/app/src/main/res/values-zh-rCN/strings.xml index 7aeb0a25a7..7eb4be2acf 100644 --- a/app/src/main/res/values-zh-rCN/strings.xml +++ b/app/src/main/res/values-zh-rCN/strings.xml @@ -1,7 +1,6 @@ 编辑 - 账户图标 对话%1$s已添加至收藏 搜索位置 %s 语音通话 @@ -57,7 +56,6 @@ 大文件在前 小文件在前 消息被你删除了 - 消息过期 点击打开投票 无搜索结果 开始输入以搜索 @@ -75,7 +73,6 @@ 添加参与者 添加收藏 OK,已完成! - 允许访客 固定:%1$s 解锁 %1$s 使用蓝牙音箱需要“附近的设备”权限 @@ -113,7 +110,6 @@ 你真想删除对话中的所有信息吗? 修改客户端证书 设置客户端证书 - 关闭应用 复制 已复制到剪贴板 @@ -217,8 +213,6 @@ 此对话中的通知将覆盖免打扰设置 邀请函 加入公开对话 - 在您离开%1$s之前您需要选出一位新的主持人。 - 无法离开对话 %1$s 我上一次更改: %2$s 离开对话 正在离开通话 ... @@ -404,9 +398,6 @@ 分享当前位置 共享链接 分享位置 - %1$s邀请 - 加入在 %1$s/index.php/call/%2$s 中的对话 - \n密码: %1$s 分享这个位置 选择一个账户 已分享项目 @@ -536,7 +527,6 @@ 本周 这是一个测试消息 本周末 - 附件 今天 明天 翻译 diff --git a/app/src/main/res/values-zh-rHK/strings.xml b/app/src/main/res/values-zh-rHK/strings.xml index 9a1b5aeab6..9990eb14f6 100644 --- a/app/src/main/res/values-zh-rHK/strings.xml +++ b/app/src/main/res/values-zh-rHK/strings.xml @@ -1,7 +1,6 @@ 編輯 - 帳戶圖示 添加到筆記 添加了對話 %1$s 至最愛 %s內搜尋 @@ -76,7 +75,6 @@ 最大先 最小先 訊息被您刪除 - 訊息過期時間 由 %1$s 編輯 點按即可打開民意調查 無搜尋結果 @@ -95,7 +93,6 @@ 添加參與者 加到我的最愛 完成 - 允許訪客 密碼:%1$s 解鎖 %1$s 要啟用藍牙喇叭,請授予「鄰近裝置」權限。 @@ -137,7 +134,6 @@ 您確定要刪除對話內所有的訊息嗎? 更改客戶端證書 設置客戶端證書 - 關閉應用程式 複製 已複製到剪貼板 @@ -279,8 +275,6 @@ 此對話中的通告將覆蓋\"請勿打擾\"設置 邀請 加入公開對話 - 在您離開 %1$s 之前您需要推舉一位新的主持人。 - 無法離開對話 %1$s | 上次修改時間:%2$s 結束對話 正在離開通話 … @@ -476,9 +470,6 @@ 分享目前位置 分享連結 分享位置 - %1$s 邀請 - 加入於 %1$s/index.php/call/%2$s 的對話 - \n密碼:%1$s 分享此位置 選擇帳戶 分享項目 @@ -613,7 +604,6 @@ 本星期 此乃測試訊息 本週末 - 附件 今日 明日 翻譯 diff --git a/app/src/main/res/values-zh-rTW/strings.xml b/app/src/main/res/values-zh-rTW/strings.xml index 2ea95d5be4..fffc78a55b 100644 --- a/app/src/main/res/values-zh-rTW/strings.xml +++ b/app/src/main/res/values-zh-rTW/strings.xml @@ -1,7 +1,6 @@ 編輯 - 帳號圖示 新增至筆記 已新增對話 %1$s 至最愛 在 %s內搜尋 @@ -76,7 +75,6 @@ 最大優先 最小優先 訊息已被您刪除 - 訊息過期 由 %1$s 編輯 點按開啟投票 無搜尋結果 @@ -95,7 +93,6 @@ 新增成員 加到我的最愛 完成 - 允許訪客 密碼:%1$s 解鎖 %1$s 要啟用藍牙喇叭,請授予「鄰近裝置」權限。 @@ -137,7 +134,6 @@ 您確定要刪除對話內所有的訊息嗎? 變更客戶端憑證 設定客戶端憑證 - 關閉應用程式 複製 已複製至剪貼簿 @@ -279,8 +275,6 @@ 在這個交談的通知將會覆蓋不要打擾的設定 邀請 加入開放對話 - 在您離開 %1$s 之前您需要推舉一位新的主持人。 - 無法離開對話 %1$s | 上次修改時間:%2$s 結束對話 正在離開通話 … @@ -476,9 +470,6 @@ 分享目前位置 分享連結 分享位置 - %1$s 邀請 - 加入位於 %1$s/index.php/call/%2$s 的對話 - \n密碼:%1$s 分享地點 選擇帳號 已分享項目 @@ -613,7 +604,6 @@ 這個禮拜 這是測試訊息 本週末 - 附件 今天 明天 翻譯 From 87e08d3b96668d362bc872543f7a31bcc2e5e674 Mon Sep 17 00:00:00 2001 From: Joas Schilling Date: Tue, 10 Sep 2024 11:39:27 +0200 Subject: [PATCH 009/885] ci: Update workflows [skip-ci] Signed-off-by: Joas Schilling --- .github/workflows/autoApproveSync.yml | 6 +++ .github/workflows/command-rebase.yml | 54 --------------------------- 2 files changed, 6 insertions(+), 54 deletions(-) delete mode 100644 .github/workflows/command-rebase.yml diff --git a/.github/workflows/autoApproveSync.yml b/.github/workflows/autoApproveSync.yml index 4beff67439..738cf41311 100644 --- a/.github/workflows/autoApproveSync.yml +++ b/.github/workflows/autoApproveSync.yml @@ -29,6 +29,12 @@ jobs: runs-on: ubuntu-latest if: ${{ contains(github.event.pull_request.labels.*.name, 'sync') && github.actor == 'nextcloud-android-bot' }} steps: + - name: Disabled on forks + if: ${{ github.event.pull_request.head.repo.full_name != github.repository }} + run: | + echo 'Can not approve PRs from forks' + exit 1 + - uses: hmarr/auto-approve-action@f0939ea97e9205ef24d872e76833fa908a770363 # v4.0.0 with: github-token: "${{ secrets.GITHUB_TOKEN }}" diff --git a/.github/workflows/command-rebase.yml b/.github/workflows/command-rebase.yml deleted file mode 100644 index 28dfdd3b4d..0000000000 --- a/.github/workflows/command-rebase.yml +++ /dev/null @@ -1,54 +0,0 @@ -# This workflow is provided via the organization template repository -# -# https://github.com/nextcloud/.github -# https://docs.github.com/en/actions/learn-github-actions/sharing-workflows-with-your-organization - -# SPDX-FileCopyrightText: 2021-2024 Nextcloud GmbH and Nextcloud contributors -# SPDX-License-Identifier: MIT - -name: Rebase command - -on: - issue_comment: - types: created - -permissions: - contents: read - -jobs: - rebase: - runs-on: ubuntu-latest - permissions: - contents: none - - # On pull requests and if the comment starts with `/rebase` - if: github.event.issue.pull_request != '' && startsWith(github.event.comment.body, '/rebase') - - steps: - - name: Add reaction on start - uses: peter-evans/create-or-update-comment@71345be0265236311c031f5c7866368bd1eff043 # v4.0.0 - with: - token: ${{ secrets.COMMAND_BOT_PAT }} - repository: ${{ github.event.repository.full_name }} - comment-id: ${{ github.event.comment.id }} - reaction-type: "+1" - - - name: Checkout the latest code - uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332 # v4.1.7 - with: - fetch-depth: 0 - token: ${{ secrets.COMMAND_BOT_PAT }} - - - name: Automatic Rebase - uses: cirrus-actions/rebase@b87d48154a87a85666003575337e27b8cd65f691 # 1.8 - env: - GITHUB_TOKEN: ${{ secrets.COMMAND_BOT_PAT }} - - - name: Add reaction on failure - uses: peter-evans/create-or-update-comment@71345be0265236311c031f5c7866368bd1eff043 # v4.0.0 - if: failure() - with: - token: ${{ secrets.COMMAND_BOT_PAT }} - repository: ${{ github.event.repository.full_name }} - comment-id: ${{ github.event.comment.id }} - reaction-type: "-1" From beece3d892ffa6fdbfec4e035b600c47e3ce369b Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Tue, 10 Sep 2024 19:54:03 +0000 Subject: [PATCH 010/885] fix(deps): update dependency androidx.compose.runtime:runtime to v1.7.1 Signed-off-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- app/build.gradle | 2 +- gradle/verification-metadata.xml | 32 ++++++++++++++++++++++++++++++++ 2 files changed, 33 insertions(+), 1 deletion(-) diff --git a/app/build.gradle b/app/build.gradle index 8390b63234..13f57c793b 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -180,7 +180,7 @@ dependencies { spotbugsPlugins 'com.h3xstream.findsecbugs:findsecbugs-plugin:1.13.0' spotbugsPlugins 'com.mebigfatguy.fb-contrib:fb-contrib:7.6.4' - implementation("androidx.compose.runtime:runtime:1.7.0") + implementation("androidx.compose.runtime:runtime:1.7.1") implementation 'androidx.preference:preference-ktx:1.2.1' implementation 'androidx.datastore:datastore-core:1.1.1' implementation 'androidx.datastore:datastore-preferences:1.1.1' diff --git a/gradle/verification-metadata.xml b/gradle/verification-metadata.xml index 12919b95be..85b33b5367 100644 --- a/gradle/verification-metadata.xml +++ b/gradle/verification-metadata.xml @@ -619,11 +619,43 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + From 2d46532f9fe328186a5c4134e6f3bcc3d2be3664 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Tue, 10 Sep 2024 20:11:30 +0000 Subject: [PATCH 011/885] fix(deps): update dependency androidx.compose.ui:ui-test-junit4 to v1.7.1 Signed-off-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- app/build.gradle | 2 +- gradle/verification-metadata.xml | 127 +++++++++++++++++++++++++++++++ 2 files changed, 128 insertions(+), 1 deletion(-) diff --git a/app/build.gradle b/app/build.gradle index 13f57c793b..0e33b4f93c 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -316,7 +316,7 @@ dependencies { debugImplementation("androidx.compose.ui:ui-tooling") //tests - androidTestImplementation("androidx.compose.ui:ui-test-junit4:1.7.0") + androidTestImplementation("androidx.compose.ui:ui-test-junit4:1.7.1") debugImplementation("androidx.compose.ui:ui-test-manifest") testImplementation 'junit:junit:4.13.2' diff --git a/gradle/verification-metadata.xml b/gradle/verification-metadata.xml index 85b33b5367..a988a892b2 100644 --- a/gradle/verification-metadata.xml +++ b/gradle/verification-metadata.xml @@ -664,6 +664,133 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + From 8f68d280168d777bed79193439e93e9c056356b4 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Tue, 10 Sep 2024 20:32:37 +0000 Subject: [PATCH 012/885] fix(deps): update dependency androidx.compose:compose-bom to v2024.09.01 Signed-off-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- app/build.gradle | 6 +- gradle/verification-metadata.xml | 133 +++++++++++++++++++++++++++++++ 2 files changed, 136 insertions(+), 3 deletions(-) diff --git a/app/build.gradle b/app/build.gradle index 0e33b4f93c..99498baa6a 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -307,7 +307,7 @@ dependencies { gplayImplementation "com.google.firebase:firebase-messaging:24.0.1" //compose - implementation(platform("androidx.compose:compose-bom:2024.09.00")) + implementation(platform("androidx.compose:compose-bom:2024.09.01")) implementation("androidx.compose.ui:ui") implementation 'androidx.compose.material3:material3:1.3.0' implementation("androidx.compose.ui:ui-tooling-preview") @@ -352,14 +352,14 @@ dependencies { implementation 'com.github.nextcloud.android-common:ui:0.23.0' implementation 'com.github.nextcloud-deps:android-talk-webrtc:121.6167.0' - implementation(platform("androidx.compose:compose-bom:2024.09.00")) + implementation(platform("androidx.compose:compose-bom:2024.09.01")) implementation("io.coil-kt:coil-compose:2.7.0") implementation "com.google.dagger:hilt-android:$hilt_version" kapt "com.google.dagger:hilt-android-compiler:$hilt_version" implementation("androidx.lifecycle:lifecycle-viewmodel-compose:2.8.5") - androidTestImplementation(platform("androidx.compose:compose-bom:2024.09.00")) + androidTestImplementation(platform("androidx.compose:compose-bom:2024.09.01")) androidTestImplementation("androidx.compose.ui:ui-test-junit4") testImplementation "org.mockito.kotlin:mockito-kotlin:$mockitoKotlinVersion" testImplementation "org.jetbrains.kotlinx:kotlinx-coroutines-test:$coroutines_version" diff --git a/gradle/verification-metadata.xml b/gradle/verification-metadata.xml index a988a892b2..7d6462dcd5 100644 --- a/gradle/verification-metadata.xml +++ b/gradle/verification-metadata.xml @@ -614,6 +614,88 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + @@ -672,6 +754,14 @@ + + + + + + + + @@ -680,6 +770,14 @@ + + + + + + + + @@ -688,6 +786,14 @@ + + + + + + + + @@ -736,6 +842,14 @@ + + + + + + + + @@ -766,6 +880,9 @@ + + + @@ -783,6 +900,14 @@ + + + + + + + + @@ -791,6 +916,14 @@ + + + + + + + + From 4fd9428fb4bdecacacbb35f79c924076c533e2e4 Mon Sep 17 00:00:00 2001 From: Nextcloud bot Date: Wed, 11 Sep 2024 02:58:58 +0000 Subject: [PATCH 013/885] Fix(l10n): Update translations from Transifex Signed-off-by: Nextcloud bot --- app/src/main/res/values-ru/strings.xml | 42 ++++++++++++++++++++++++++ app/src/main/res/values-tr/strings.xml | 1 + 2 files changed, 43 insertions(+) diff --git a/app/src/main/res/values-ru/strings.xml b/app/src/main/res/values-ru/strings.xml index 2ca69b9a9e..b88bcfe884 100644 --- a/app/src/main/res/values-ru/strings.xml +++ b/app/src/main/res/values-ru/strings.xml @@ -1,6 +1,7 @@ Редактирование + Добавить в заметки Искать в %s Аудиозвонок Bluetooth @@ -20,6 +21,10 @@ Очищать статус после Закрыть Соединение установлено + Соединение потеряно + Соединение потеряно - отправленные сообщения ставятся в очередь + Блокировка записи для непрерывной записи голосового сообщения + Разговор доступен только для чтения Разговоры Создать обсуждение Задать @@ -29,16 +34,20 @@ Не беспокоить Не очищать Редактировать + Невозможно редактировать сообщения старше 24 часов. Вернуться Недавние Зашифровано Возникла проблема при загрузке ваших чатов + Произошла ошибка при разблокировке участника Не удалось сохранить %1$s каталог Загрузка … %1$s (%2$d) 4 часа + Не удалось получить ожидающие приглашения (изменено) + Внутреннее примечание Невидимый Позже сегодня Вы покинули чат %1$s @@ -47,6 +56,7 @@ Опустить руку Отметить чат %1$s как прочитанный Отметить чат %1$s как непрочитанный + Упомянул Самый новый первый Самый старый первый А - Я @@ -54,6 +64,7 @@ Самый большой первый Самый маленький первый Сообщение удалено вами + Отредактировано %1$s Нажмите для открытия опроса Ничего не найдено Начните печатать для поиска … @@ -73,6 +84,7 @@ Всё готово! Пин: %1$s Разблокировать %1$s + Чтобы включить динамики Bluetooth, предоставьте разрешение «Устройства поблизости». Дополнительные настройки звонка Ответить как видеозвонок Ответить как голосовой звонок @@ -95,6 +107,7 @@ %s звонок %s видеозвонок %s голосовой вызов + Для включения видеосвязи предоставьте разрешение «Камера». Отмена Не удалось получить список поддерживаемых протоколов Подпись @@ -102,6 +115,7 @@ Проверьте сертификат Заданные параметры SSL не позволяют подключиться Изменить сертификат для подтверждения подлинности + Проверьте подключение к Интернету. Удалить все сообщения Все сообщения были удалены Вы действительно хотите удалить все сообщения в этой беседе? @@ -124,6 +138,7 @@ Информация о беседе Видеозвонок Голосовой вызов + Разговор не найден Параметры обсуждения Присоединитесь к обсуждению или же начните новое Поприветствуйте своих друзей и коллег. @@ -138,25 +153,38 @@ При удалении беседы, она будет также удалена у других участников Удалить Сообщение удалено, но его содержимое могло быть прочитано другими службами + Пользователь %1$s был удален Сместить с поста модератора Запись голосового сообщения Отправить сообщение Текущая учётная запись Сервер + Установлено ли приложение для уведомлений сервера? + Пользователь + Статус пользователя включен? Версия ОС Android Приложение Название приложения + Зарегистрированные пользователи + Версия приложения + Оптимизация батареи игнорируется, все в порядке + Оптимизация батареи не игнорируется. Это следует изменить! Настройки батареи Устройство + Открыть контрольный список устранения неполадок + Открыть экран диагностики Телефон Внешний Внутренние + Режим сигнализации Неверный пароль Режим обслуживания В настоящее время сервер находится в режиме технического обслуживания. + Приложение устарело Версия приложения слишком старая и больше не поддерживается этим сервером. Пожалуйста обносите приложение. Обновить Вы хотите повторно авторизоваться или удалить эту учётную запись? + Сохранение этого медиафайла в хранилище позволит всем другим приложениям на вашем устройстве получить к нему доступ. Продолжить? Нет Сохранить в хранилище? @@ -177,8 +205,10 @@ Принять Отклонить Нет ожидающих приглашений + У вас есть ожидающие приглашения Назад Требуется разрешение на доступ к файлу + Фильтровать разговоры Пользователь, вошедший по ссылке Вы: %1$s Переслать @@ -203,6 +233,7 @@ Приглашения были разосланы повторно. Поделиться ссылкой на беседу Напишите сообщение … + Игнорировать оптимизацию батареи Важное обсуждение Уведомления в этом чате имеют приоритет над настройками режима \"Не беспокоить\" Приглашения @@ -230,6 +261,7 @@ Отменить ответ Сообщение прочитано Сообщение отправлено + Для включения голосовой связи предоставьте разрешение «Микрофон». Вы пропустили звонок от %s Модератор Никогда не использовался @@ -240,6 +272,7 @@ Приложение %1$s недоступно (не установлено, либо использование приложения ограничено администратором) Гость Нет + Нет открытых разговоров Не использовать прокси-сервер Вам запрещено активировать аудио! Вам запрещено активировать видео! @@ -251,6 +284,8 @@ Загрузки Уведомление о ходе загрузки Параметры уведомлений + Разрешение на уведомления и настройки батареи настроены правильно для получения уведомлений. Если у вас все равно возникли проблемы с получением уведомлений, проверьте, включены ли каналы уведомлений для звонков и сообщений. Дополнительную помощь можно найти на сайте DontKillMyApp.com или в контрольном списке устранения неполадок. Если это не помогло, перейдите на экран диагностики и отправьте отчет об ошибке. + Устранение неполадок с уведомлениями Всегда уведомлять Уведомлять при упоминании Не уведомлять @@ -261,6 +296,8 @@ Владелец Участники Добавить участников + Установить разрешения + В некоторых разрешениях было отказано. Открыть настройки Учётная запись не найдена Чат через %s @@ -329,17 +366,22 @@ На сервере не установлено приложение «Конференции» Адрес сервера https://… Работа приложения %1$s возможна только с серверами %2$s версии 13 или старше + Установить пароль Параметры Вместо создания новой учётной записи было выполнено обновление существующей Дополнительно Внешний вид Вызовы + Откройте экран диагностики, чтобы проверить настройки или создать отчет об ошибке. Указывает клавиатуре отключить персонализированное обучение (без гарантий) Клавиатура инкогнито Без звука На сервере, к которому вы пытаетесь подключиться, приложение «Talk» не установлено. Звуки уведомления Уведомления + Уведомления отклонены + Уведомления отклонены. Разрешите уведомления в настройках Android + Уведомления отклонены. Разрешите уведомления в настройках Android Сообщения Сопоставление контактов по номеру телефона для создания ярлыков на приложения «Конференции» в приложение системных контактов Вы можете указать свой номер телефона, чтобы другие пользователи могли вас найти diff --git a/app/src/main/res/values-tr/strings.xml b/app/src/main/res/values-tr/strings.xml index 1401d28fe4..49250032ab 100644 --- a/app/src/main/res/values-tr/strings.xml +++ b/app/src/main/res/values-tr/strings.xml @@ -407,6 +407,7 @@ Sunucuda desteklenen bir Konuş uygulaması kurulu değil Sunucu adresi https://… %1$s yalnızca %2$s 13 ve üzerinde çalışır + Parola ayarla Ayarlar Zaten bir hesabınız bulunduğundan yeni hesap eklenmesi yerine geçerli hesap güncellendi Gelişmiş From f374e6fe50f4a6c24c80ec05a4d3a0dc2ad4da6f Mon Sep 17 00:00:00 2001 From: sowjanyakch Date: Wed, 22 May 2024 16:09:12 +0200 Subject: [PATCH 014/885] ConversationCreationActivity UI Signed-off-by: sowjanyakch --- .../contacts/ContactsActivityViewModel.kt | 104 +++++++++++++ .../repository/FakeRepositorySuccess.kt | 4 + gradle/verification-metadata.xml | 138 +++++++++++++++++- 3 files changed, 241 insertions(+), 5 deletions(-) create mode 100644 app/src/main/java/com/nextcloud/talk/contacts/ContactsActivityViewModel.kt diff --git a/app/src/main/java/com/nextcloud/talk/contacts/ContactsActivityViewModel.kt b/app/src/main/java/com/nextcloud/talk/contacts/ContactsActivityViewModel.kt new file mode 100644 index 0000000000..6c87c66089 --- /dev/null +++ b/app/src/main/java/com/nextcloud/talk/contacts/ContactsActivityViewModel.kt @@ -0,0 +1,104 @@ +/* + * Nextcloud Talk - Android Client + * + * SPDX-FileCopyrightText: 2024 Your Name + * SPDX-License-Identifier: GPL-3.0-or-later + */ + +package com.nextcloud.talk.contacts + +import androidx.lifecycle.ViewModel +import androidx.lifecycle.viewModelScope +import com.nextcloud.talk.data.user.model.User +import com.nextcloud.talk.models.json.autocomplete.AutocompleteUser +import com.nextcloud.talk.models.json.conversations.Conversation +import com.nextcloud.talk.users.UserManager +import com.nextcloud.talk.utils.ApiUtils +import kotlinx.coroutines.flow.MutableStateFlow +import kotlinx.coroutines.flow.StateFlow +import kotlinx.coroutines.launch +import javax.inject.Inject + +class ContactsActivityViewModel @Inject constructor( + private val repository: ContactsRepository, + private val userManager: UserManager +) : ViewModel() { + + private val _contactsViewState = MutableStateFlow(ContactsUiState.None) + val contactsViewState: StateFlow = _contactsViewState + private val _roomViewState = MutableStateFlow(RoomUiState.None) + val roomViewState: StateFlow = _roomViewState + private val _currentUser = userManager.currentUser.blockingGet() + val currentUser: User = _currentUser + private val _searchQuery = MutableStateFlow("") + val searchQuery: StateFlow = _searchQuery + private val shareTypes: MutableList = mutableListOf(ShareType.User.shareType) + val shareTypeList: List = shareTypes + + init { + getContactsFromSearchParams() + } + + fun updateSearchQuery(query: String) { + _searchQuery.value = query + } + + fun updateShareTypes(value: String) { + shareTypes.add(value) + } + + fun getContactsFromSearchParams() { + _contactsViewState.value = ContactsUiState.Loading + viewModelScope.launch { + try { + val contacts = repository.getContacts( + searchQuery.value, + shareTypeList + ) + val contactsList: List? = contacts.ocs!!.data + _contactsViewState.value = ContactsUiState.Success(contactsList) + } catch (exception: Exception) { + _contactsViewState.value = ContactsUiState.Error(exception.message ?: "") + } + } + } + + fun createRoom(roomType: String, sourceType: String, userId: String, conversationName: String?) { + viewModelScope.launch { + try { + val room = repository.createRoom( + roomType, + sourceType, + userId, + conversationName + ) + + val conversation: Conversation? = room.ocs?.data + _roomViewState.value = RoomUiState.Success(conversation) + } catch (exception: Exception) { + _roomViewState.value = RoomUiState.Error(exception.message ?: "") + } + } + } + + fun getImageUri(avatarId: String, requestBigSize: Boolean): String { + return ApiUtils.getUrlForAvatar( + _currentUser.baseUrl, + avatarId, + requestBigSize + ) + } +} + +sealed class ContactsUiState { + data object None : ContactsUiState() + data object Loading : ContactsUiState() + data class Success(val contacts: List?) : ContactsUiState() + data class Error(val message: String) : ContactsUiState() +} + +sealed class RoomUiState { + data object None : RoomUiState() + data class Success(val conversation: Conversation?) : RoomUiState() + data class Error(val message: String) : RoomUiState() +} diff --git a/app/src/test/java/com/nextcloud/talk/contacts/repository/FakeRepositorySuccess.kt b/app/src/test/java/com/nextcloud/talk/contacts/repository/FakeRepositorySuccess.kt index f5d87d9195..9022ba0598 100644 --- a/app/src/test/java/com/nextcloud/talk/contacts/repository/FakeRepositorySuccess.kt +++ b/app/src/test/java/com/nextcloud/talk/contacts/repository/FakeRepositorySuccess.kt @@ -29,4 +29,8 @@ class FakeRepositorySuccess : ContactsRepository { override fun getImageUri(avatarId: String, requestBigSize: Boolean): String { return "https://mydomain.com/index.php/avatar/$avatarId/512" } + + override fun getImageUri(avatarId: String, requestBigSize: Boolean): String { + TODO("Not yet implemented") + } } diff --git a/gradle/verification-metadata.xml b/gradle/verification-metadata.xml index 7d6462dcd5..65ffd8068b 100644 --- a/gradle/verification-metadata.xml +++ b/gradle/verification-metadata.xml @@ -4,13 +4,13 @@ true true - - - - + + + + @@ -151,7 +151,6 @@ - @@ -163,6 +162,7 @@ + @@ -252,6 +252,7 @@ + @@ -349,6 +350,50 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + @@ -365,6 +410,14 @@ + + + + + + + + @@ -378,6 +431,11 @@ + + + + + @@ -399,6 +457,76 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + From 9fcb1427dbcb0f785ab9b73a726ffa731e7f753f Mon Sep 17 00:00:00 2001 From: sowjanyakch Date: Mon, 9 Sep 2024 22:39:06 +0200 Subject: [PATCH 015/885] Make contacts select and deselect via search Signed-off-by: sowjanyakch --- .../talk/contacts/ContactsActivityCompose.kt | 50 ++++++------------- .../talk/contacts/ContactsViewModel.kt | 13 ++++- .../talk/contacts/SearchComponent.kt | 2 - 3 files changed, 26 insertions(+), 39 deletions(-) diff --git a/app/src/main/java/com/nextcloud/talk/contacts/ContactsActivityCompose.kt b/app/src/main/java/com/nextcloud/talk/contacts/ContactsActivityCompose.kt index 5fdbc3c733..b57e87061d 100644 --- a/app/src/main/java/com/nextcloud/talk/contacts/ContactsActivityCompose.kt +++ b/app/src/main/java/com/nextcloud/talk/contacts/ContactsActivityCompose.kt @@ -52,9 +52,7 @@ import androidx.compose.runtime.Composable import androidx.compose.runtime.DisposableEffect import androidx.compose.runtime.collectAsState import androidx.compose.runtime.getValue -import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.remember -import androidx.compose.runtime.setValue import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.graphics.Color @@ -116,9 +114,9 @@ class ContactsActivityCompose : BaseActivity() { @Suppress("DEPRECATION") intent.getParcelableArrayListExtra("selectedParticipants") ?: emptyList() } - } - val participants = selectedParticipants.toSet().toMutableList() - contactsViewModel.updateSelectedParticipants(participants) + }.toSet().toMutableList() + contactsViewModel.updateSelectedParticipants(selectedParticipants) + MaterialTheme( colorScheme = colorScheme ) { @@ -137,8 +135,7 @@ class ContactsActivityCompose : BaseActivity() { ContactsList( contactsUiState = uiState.value, contactsViewModel = contactsViewModel, - context = context, - selectedParticipants = selectedParticipants.toMutableList() + context = context ) } } @@ -168,13 +165,8 @@ class ContactsActivityCompose : BaseActivity() { } @Composable -fun ContactItemRow( - contact: AutocompleteUser, - contactsViewModel: ContactsViewModel, - context: Context, - selectedContacts: MutableList -) { - var isSelected by remember { mutableStateOf(selectedContacts.contains(contact)) } +fun ContactItemRow(contact: AutocompleteUser, contactsViewModel: ContactsViewModel, context: Context) { + var isSelected = remember(contact) { contactsViewModel.selectedParticipantsList.value.contains(contact) } val roomUiState by contactsViewModel.roomViewState.collectAsState() val isAddParticipants = contactsViewModel.isAddParticipantsView.collectAsState() Row( @@ -191,14 +183,11 @@ fun ContactItemRow( ) } else { isSelected = !isSelected - selectedContacts.apply { - if (isSelected) { - add(contact) - } else { - remove(contact) - } + if (isSelected) { + contactsViewModel.selectContact(contact) + } else { + contactsViewModel.deselectContact(contact) } - contactsViewModel.updateSelectedParticipants(selectedContacts) } } ), @@ -363,12 +352,7 @@ fun ConversationCreationOptions(context: Context, contactsViewModel: ContactsVie } @Composable -fun ContactsList( - contactsUiState: ContactsUiState, - contactsViewModel: ContactsViewModel, - context: Context, - selectedParticipants: MutableList -) { +fun ContactsList(contactsUiState: ContactsUiState, contactsViewModel: ContactsViewModel, context: Context) { when (contactsUiState) { is ContactsUiState.None -> { } @@ -381,7 +365,7 @@ fun ContactsList( val contacts = contactsUiState.contacts Log.d(CompanionClass.TAG, "Contacts:$contacts") if (contacts != null) { - ContactsItem(contacts, contactsViewModel, context, selectedParticipants) + ContactsItem(contacts, contactsViewModel, context) } } is ContactsUiState.Error -> { @@ -395,12 +379,7 @@ fun ContactsList( @OptIn(ExperimentalFoundationApi::class) @Composable -fun ContactsItem( - contacts: List, - contactsViewModel: ContactsViewModel, - context: Context, - selectedParticipants: MutableList -) { +fun ContactsItem(contacts: List, contactsViewModel: ContactsViewModel, context: Context) { val groupedContacts: Map> = contacts.groupBy { contact -> ( if (contact.source == "users") { @@ -432,8 +411,7 @@ fun ContactsItem( ContactItemRow( contact = contact, contactsViewModel = contactsViewModel, - context = context, - selectedContacts = selectedParticipants + context = context ) Log.d(CompanionClass.TAG, "Contacts:$contact") } diff --git a/app/src/main/java/com/nextcloud/talk/contacts/ContactsViewModel.kt b/app/src/main/java/com/nextcloud/talk/contacts/ContactsViewModel.kt index 7dda675913..b045dd11a4 100644 --- a/app/src/main/java/com/nextcloud/talk/contacts/ContactsViewModel.kt +++ b/app/src/main/java/com/nextcloud/talk/contacts/ContactsViewModel.kt @@ -13,6 +13,7 @@ import com.nextcloud.talk.models.json.autocomplete.AutocompleteUser import com.nextcloud.talk.models.json.conversations.Conversation import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.flow.StateFlow +import kotlinx.coroutines.flow.asStateFlow import kotlinx.coroutines.launch import javax.inject.Inject @@ -31,7 +32,7 @@ class ContactsViewModel @Inject constructor( private val _searchState = MutableStateFlow(false) val searchState: StateFlow = _searchState private val selectedParticipants = MutableStateFlow>(emptyList()) - val selectedParticipantsList: StateFlow> = selectedParticipants + val selectedParticipantsList: StateFlow> = selectedParticipants.asStateFlow() private val _isAddParticipantsView = MutableStateFlow(false) val isAddParticipantsView: StateFlow = _isAddParticipantsView @@ -43,6 +44,16 @@ class ContactsViewModel @Inject constructor( _searchQuery.value = query } + fun selectContact(contact: AutocompleteUser) { + val updatedParticipants = selectedParticipants.value + contact + selectedParticipants.value = updatedParticipants + } + + fun deselectContact(contact: AutocompleteUser) { + val updatedParticipants = selectedParticipants.value - contact + selectedParticipants.value = updatedParticipants + } + fun updateSelectedParticipants(participants: List) { selectedParticipants.value = participants } diff --git a/app/src/main/java/com/nextcloud/talk/contacts/SearchComponent.kt b/app/src/main/java/com/nextcloud/talk/contacts/SearchComponent.kt index 5a793d40e3..0e73a7afdf 100644 --- a/app/src/main/java/com/nextcloud/talk/contacts/SearchComponent.kt +++ b/app/src/main/java/com/nextcloud/talk/contacts/SearchComponent.kt @@ -19,7 +19,6 @@ import androidx.compose.material3.IconButton import androidx.compose.material3.Text import androidx.compose.material3.TextField import androidx.compose.runtime.Composable -import androidx.compose.runtime.collectAsState import androidx.compose.ui.Modifier import androidx.compose.ui.platform.LocalSoftwareKeyboardController import androidx.compose.ui.res.stringResource @@ -31,7 +30,6 @@ import com.nextcloud.talk.R @Composable fun DisplaySearch(text: String, onTextChange: (String) -> Unit, contactsViewModel: ContactsViewModel) { - val isAddParticipants = contactsViewModel.isAddParticipantsView.collectAsState() val keyboardController = LocalSoftwareKeyboardController.current TextField( modifier = Modifier From 922c329fab3d65157c4537937cfc32b0f2cb1ff5 Mon Sep 17 00:00:00 2001 From: sowjanyakch Date: Mon, 9 Sep 2024 22:47:37 +0200 Subject: [PATCH 016/885] Fix bug - select contacts onclick Signed-off-by: sowjanyakch --- .../com/nextcloud/talk/contacts/ContactsActivityCompose.kt | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/app/src/main/java/com/nextcloud/talk/contacts/ContactsActivityCompose.kt b/app/src/main/java/com/nextcloud/talk/contacts/ContactsActivityCompose.kt index b57e87061d..c1b22e6b0c 100644 --- a/app/src/main/java/com/nextcloud/talk/contacts/ContactsActivityCompose.kt +++ b/app/src/main/java/com/nextcloud/talk/contacts/ContactsActivityCompose.kt @@ -52,7 +52,9 @@ import androidx.compose.runtime.Composable import androidx.compose.runtime.DisposableEffect import androidx.compose.runtime.collectAsState import androidx.compose.runtime.getValue +import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.remember +import androidx.compose.runtime.setValue import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.graphics.Color @@ -166,7 +168,7 @@ class ContactsActivityCompose : BaseActivity() { @Composable fun ContactItemRow(contact: AutocompleteUser, contactsViewModel: ContactsViewModel, context: Context) { - var isSelected = remember(contact) { contactsViewModel.selectedParticipantsList.value.contains(contact) } + var isSelected by remember { mutableStateOf(contactsViewModel.selectedParticipantsList.value.contains(contact)) } val roomUiState by contactsViewModel.roomViewState.collectAsState() val isAddParticipants = contactsViewModel.isAddParticipantsView.collectAsState() Row( From 06e48c6aad1d1bf6a187b47e3d7485c617bf5e3d Mon Sep 17 00:00:00 2001 From: sowjanyakch Date: Tue, 10 Sep 2024 11:49:43 +0200 Subject: [PATCH 017/885] Set background color for search Signed-off-by: sowjanyakch --- .idea/inspectionProfiles/ktlint.xml | 24 +++ .../contacts/ContactsActivityViewModel.kt | 104 ----------- .../talk/contacts/SearchComponent.kt | 5 +- gradle/verification-keyring.keys | 164 +++++++++++------- gradle/verification-metadata.xml | 148 ++-------------- 5 files changed, 147 insertions(+), 298 deletions(-) delete mode 100644 app/src/main/java/com/nextcloud/talk/contacts/ContactsActivityViewModel.kt diff --git a/.idea/inspectionProfiles/ktlint.xml b/.idea/inspectionProfiles/ktlint.xml index 18d15ddc14..e8f89f3ed2 100644 --- a/.idea/inspectionProfiles/ktlint.xml +++ b/.idea/inspectionProfiles/ktlint.xml @@ -1,6 +1,30 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - @@ -410,14 +365,6 @@ - - - - - - - - @@ -431,11 +378,6 @@ - - - - - @@ -457,76 +399,6 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - @@ -2357,6 +2229,11 @@ + + + + + @@ -6448,6 +6325,11 @@ + + + + + From 082669a3bf93a6adf960064224377816ec893ac9 Mon Sep 17 00:00:00 2001 From: sowjanyakch Date: Tue, 10 Sep 2024 12:03:14 +0200 Subject: [PATCH 018/885] ktlint Format Signed-off-by: sowjanyakch --- .../com/nextcloud/talk/chat/ChatActivity.kt | 21 +++++++------------ 1 file changed, 8 insertions(+), 13 deletions(-) diff --git a/app/src/main/java/com/nextcloud/talk/chat/ChatActivity.kt b/app/src/main/java/com/nextcloud/talk/chat/ChatActivity.kt index e482d51770..21bdd850ad 100644 --- a/app/src/main/java/com/nextcloud/talk/chat/ChatActivity.kt +++ b/app/src/main/java/com/nextcloud/talk/chat/ChatActivity.kt @@ -2546,19 +2546,14 @@ class ChatActivity : private fun isScrolledToBottom() = layoutManager?.findFirstVisibleItemPosition() == 0 - private fun shouldInsertNewMessagesNotice( - newMessagesAvailable: Boolean, - chatMessageList: List - ) = if (newMessagesAvailable) { - chatMessageList.any { it.actorId != conversationUser!!.userId } - } else { - false - } - - private fun updateUnreadMessageInfos( - chatMessageList: List, - scrollToEndOnUpdate: Boolean - ) { + private fun shouldInsertNewMessagesNotice(newMessagesAvailable: Boolean, chatMessageList: List) = + if (newMessagesAvailable) { + chatMessageList.any { it.actorId != conversationUser!!.userId } + } else { + false + } + + private fun updateUnreadMessageInfos(chatMessageList: List, scrollToEndOnUpdate: Boolean) { val unreadChatMessage = ChatMessage() unreadChatMessage.jsonMessageId = -1 unreadChatMessage.actorId = "-1" From 3d1644a76d10d79938d19750fc4c423532b9945f Mon Sep 17 00:00:00 2001 From: sowjanyakch Date: Tue, 10 Sep 2024 14:28:27 +0200 Subject: [PATCH 019/885] Avoid conflicting overloads Signed-off-by: sowjanyakch --- .../talk/contacts/repository/FakeRepositorySuccess.kt | 4 ---- 1 file changed, 4 deletions(-) diff --git a/app/src/test/java/com/nextcloud/talk/contacts/repository/FakeRepositorySuccess.kt b/app/src/test/java/com/nextcloud/talk/contacts/repository/FakeRepositorySuccess.kt index 9022ba0598..f5d87d9195 100644 --- a/app/src/test/java/com/nextcloud/talk/contacts/repository/FakeRepositorySuccess.kt +++ b/app/src/test/java/com/nextcloud/talk/contacts/repository/FakeRepositorySuccess.kt @@ -29,8 +29,4 @@ class FakeRepositorySuccess : ContactsRepository { override fun getImageUri(avatarId: String, requestBigSize: Boolean): String { return "https://mydomain.com/index.php/avatar/$avatarId/512" } - - override fun getImageUri(avatarId: String, requestBigSize: Boolean): String { - TODO("Not yet implemented") - } } From 2549e884fd460141aeb03424a62e878259cc6f3f Mon Sep 17 00:00:00 2001 From: Marcel Hibbe Date: Wed, 11 Sep 2024 09:56:54 +0200 Subject: [PATCH 020/885] change background color for searchbar in contacts screen not the best solution. Needs to be improved with theming of Compose. Signed-off-by: Marcel Hibbe --- .../main/java/com/nextcloud/talk/contacts/SearchComponent.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/src/main/java/com/nextcloud/talk/contacts/SearchComponent.kt b/app/src/main/java/com/nextcloud/talk/contacts/SearchComponent.kt index d4b7feccf1..644dc315c5 100644 --- a/app/src/main/java/com/nextcloud/talk/contacts/SearchComponent.kt +++ b/app/src/main/java/com/nextcloud/talk/contacts/SearchComponent.kt @@ -37,7 +37,7 @@ fun DisplaySearch(text: String, onTextChange: (String) -> Unit, contactsViewMode modifier = Modifier .fillMaxWidth() .height(60.dp) - .background(color = colorResource(id = R.color.grey_600)), + .background(color = colorResource(id = R.color.appbar)), value = text, onValueChange = { onTextChange(it) }, placeholder = { From 5921faa8a82a5862aa64d976dcf7ed71f6511810 Mon Sep 17 00:00:00 2001 From: Marcel Hibbe Date: Tue, 10 Sep 2024 11:20:36 +0200 Subject: [PATCH 021/885] set background color for password dialog Signed-off-by: Marcel Hibbe --- .../talk/conversationcreation/ConversationCreationActivity.kt | 3 +++ 1 file changed, 3 insertions(+) diff --git a/app/src/main/java/com/nextcloud/talk/conversationcreation/ConversationCreationActivity.kt b/app/src/main/java/com/nextcloud/talk/conversationcreation/ConversationCreationActivity.kt index 51297510a8..021f6e9cf3 100644 --- a/app/src/main/java/com/nextcloud/talk/conversationcreation/ConversationCreationActivity.kt +++ b/app/src/main/java/com/nextcloud/talk/conversationcreation/ConversationCreationActivity.kt @@ -60,6 +60,7 @@ import androidx.compose.ui.Modifier import androidx.compose.ui.graphics.Color import androidx.compose.ui.platform.LocalContext import androidx.compose.ui.platform.LocalView +import androidx.compose.ui.res.colorResource import androidx.compose.ui.res.painterResource import androidx.compose.ui.res.stringResource import androidx.compose.ui.text.style.TextAlign @@ -471,6 +472,8 @@ fun ShowPasswordDialog(onDismiss: () -> Unit, conversationCreationViewModel: Con var password by remember { mutableStateOf("") } AlertDialog( + containerColor = colorResource(id = R.color.dialog_background), + onDismissRequest = onDismiss, confirmButton = { Button(onClick = { From 270d76554f0198c1e2ba77fb61132a55c2852750 Mon Sep 17 00:00:00 2001 From: Marcel Hibbe Date: Mon, 9 Sep 2024 15:43:57 +0200 Subject: [PATCH 022/885] fix flickering of unread mention bubble bug was introduced with https://github.com/nextcloud/talk-android/pull/3417 Signed-off-by: Marcel Hibbe --- .../ConversationsListActivity.kt | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/app/src/main/java/com/nextcloud/talk/conversationlist/ConversationsListActivity.kt b/app/src/main/java/com/nextcloud/talk/conversationlist/ConversationsListActivity.kt index 9b9d74f549..13457b34a0 100644 --- a/app/src/main/java/com/nextcloud/talk/conversationlist/ConversationsListActivity.kt +++ b/app/src/main/java/com/nextcloud/talk/conversationlist/ConversationsListActivity.kt @@ -1009,13 +1009,13 @@ class ConversationsListActivity : newFragment.show(supportFragmentManager, FilterConversationFragment.TAG) } - binding.newMentionPopupBubble?.hide() - binding.newMentionPopupBubble?.setPopupBubbleListener { - binding.recyclerView?.smoothScrollToPosition( + binding.newMentionPopupBubble.hide() + binding.newMentionPopupBubble.setPopupBubbleListener { + binding.recyclerView.smoothScrollToPosition( nextUnreadConversationScrollPosition ) } - binding.newMentionPopupBubble?.let { viewThemeUtils.material.colorMaterialButtonPrimaryFilled(it) } + binding.newMentionPopupBubble.let { viewThemeUtils.material.colorMaterialButtonPrimaryFilled(it) } } private fun hideLogoForBrandedClients() { @@ -1039,14 +1039,14 @@ class ConversationsListActivity : val position = adapter!!.getGlobalPositionOf(flexItem) if (hasUnreadItems(conversation) && position > lastVisibleItem) { nextUnreadConversationScrollPosition = position - if (!binding.newMentionPopupBubble?.isShown!!) { - binding.newMentionPopupBubble?.show() + if (!binding.newMentionPopupBubble.isShown) { + binding.newMentionPopupBubble.show() } return@subscribe } - nextUnreadConversationScrollPosition = 0 - binding.newMentionPopupBubble?.hide() } + nextUnreadConversationScrollPosition = 0 + binding.newMentionPopupBubble.hide() } catch (e: NullPointerException) { Log.d( TAG, From bef414fc10e26bda7df171766e6bc1dd2c143f95 Mon Sep 17 00:00:00 2001 From: Marcel Hibbe Date: Mon, 9 Sep 2024 15:55:23 +0200 Subject: [PATCH 023/885] fix logic to show UnifiedSearch results when federation capability exists Signed-off-by: Marcel Hibbe --- app/src/main/java/com/nextcloud/talk/utils/CapabilitiesUtil.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/src/main/java/com/nextcloud/talk/utils/CapabilitiesUtil.kt b/app/src/main/java/com/nextcloud/talk/utils/CapabilitiesUtil.kt index 69d34c497d..63e55c08db 100644 --- a/app/src/main/java/com/nextcloud/talk/utils/CapabilitiesUtil.kt +++ b/app/src/main/java/com/nextcloud/talk/utils/CapabilitiesUtil.kt @@ -161,7 +161,7 @@ object CapabilitiesUtil { } fun isUnifiedSearchAvailable(spreedCapabilities: SpreedCapability): Boolean { - if (hasSpreedFeatureCapability(spreedCapabilities, SpreedFeatures.FEDERATION_V1)) { + if (!hasSpreedFeatureCapability(spreedCapabilities, SpreedFeatures.FEDERATION_V1)) { return false } return hasSpreedFeatureCapability(spreedCapabilities, SpreedFeatures.UNIFIED_SEARCH) From 4209bfa2b4a241159dd0e6a0747ad1c51de5bc32 Mon Sep 17 00:00:00 2001 From: Marcel Hibbe Date: Mon, 9 Sep 2024 16:04:08 +0200 Subject: [PATCH 024/885] fix to set searchBehaviorSubject regardless of searchHelper being not null same for swipeRefreshLayoutView?.isRefreshing If searchHelper would be null (= when UnifiedSearch is not available) then going back to conversations list view would not trigger to check to show for unread mentions bubble. This fix will make it independent from searchHelper. Signed-off-by: Marcel Hibbe --- .../talk/conversationlist/ConversationsListActivity.kt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/app/src/main/java/com/nextcloud/talk/conversationlist/ConversationsListActivity.kt b/app/src/main/java/com/nextcloud/talk/conversationlist/ConversationsListActivity.kt index 13457b34a0..14c0e6b5c1 100644 --- a/app/src/main/java/com/nextcloud/talk/conversationlist/ConversationsListActivity.kt +++ b/app/src/main/java/com/nextcloud/talk/conversationlist/ConversationsListActivity.kt @@ -667,9 +667,9 @@ class ConversationsListActivity : if (searchHelper != null) { // cancel any pending searches searchHelper!!.cancelSearch() - binding.swipeRefreshLayoutView?.isRefreshing = false - searchBehaviorSubject.onNext(false) } + binding.swipeRefreshLayoutView?.isRefreshing = false + searchBehaviorSubject.onNext(false) binding.swipeRefreshLayoutView?.isEnabled = true searchView!!.onActionViewCollapsed() From 6ddf06e9fdda9d0a1f9bfd28665faf4f28843734 Mon Sep 17 00:00:00 2001 From: Marcel Hibbe Date: Mon, 9 Sep 2024 16:29:52 +0200 Subject: [PATCH 025/885] improve to align unread conversation after tapping on unread mentions button ...instead to just show it on top Signed-off-by: Marcel Hibbe --- .../talk/conversationlist/ConversationsListActivity.kt | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/app/src/main/java/com/nextcloud/talk/conversationlist/ConversationsListActivity.kt b/app/src/main/java/com/nextcloud/talk/conversationlist/ConversationsListActivity.kt index 14c0e6b5c1..1483815e4b 100644 --- a/app/src/main/java/com/nextcloud/talk/conversationlist/ConversationsListActivity.kt +++ b/app/src/main/java/com/nextcloud/talk/conversationlist/ConversationsListActivity.kt @@ -1011,8 +1011,10 @@ class ConversationsListActivity : binding.newMentionPopupBubble.hide() binding.newMentionPopupBubble.setPopupBubbleListener { - binding.recyclerView.smoothScrollToPosition( - nextUnreadConversationScrollPosition + val layoutManager = binding.recyclerView.layoutManager as SmoothScrollLinearLayoutManager? + layoutManager?.scrollToPositionWithOffset( + nextUnreadConversationScrollPosition, + binding.recyclerView.height / 3 ) } binding.newMentionPopupBubble.let { viewThemeUtils.material.colorMaterialButtonPrimaryFilled(it) } From 796053e271b2fd6b2541538bd3b618e1fe0917d0 Mon Sep 17 00:00:00 2001 From: Marcel Hibbe Date: Tue, 10 Sep 2024 12:30:30 +0200 Subject: [PATCH 026/885] remove theming of call buttons to remove disabled look for dark mode In dark mode, the call buttons looked like disabled otherwise. There is still the 3-dots menu next to the call icons like disabled for dark and light mode. But this is a different bug that needs to be fixed in another branch(could not find the reason for now). Signed-off-by: Marcel Hibbe --- .../java/com/nextcloud/talk/chat/ChatActivity.kt | 12 ------------ 1 file changed, 12 deletions(-) diff --git a/app/src/main/java/com/nextcloud/talk/chat/ChatActivity.kt b/app/src/main/java/com/nextcloud/talk/chat/ChatActivity.kt index 21bdd850ad..c41ac3c231 100644 --- a/app/src/main/java/com/nextcloud/talk/chat/ChatActivity.kt +++ b/app/src/main/java/com/nextcloud/talk/chat/ChatActivity.kt @@ -2733,18 +2733,6 @@ class ChatActivity : super.onCreateOptionsMenu(menu) menuInflater.inflate(R.menu.menu_conversation, menu) - context.let { - viewThemeUtils.platform.colorToolbarMenuIcon( - it, - menu.findItem(R.id.conversation_voice_call) - ) - - viewThemeUtils.platform.colorToolbarMenuIcon( - it, - menu.findItem(R.id.conversation_video_call) - ) - } - if (conversationUser?.userId == "?") { menu.removeItem(R.id.conversation_info) } else { From 9a14764321354258d2d750e0e0d8d6c4c13a9cc5 Mon Sep 17 00:00:00 2001 From: Marcel Hibbe Date: Wed, 11 Sep 2024 17:05:07 +0200 Subject: [PATCH 027/885] do not try to pull chat messages when offline or paused Otherwise, it resulted in a lot of flickering because _lastCommonReadFlow was emitted every 500ms. And anyway if we know we are offline or paused then it doesn't make sense to execute the sync method. chain which caused the flickering was: updateUiForLastCommonRead (_lastCommonReadFlow) -> updateReadStatusOfAllMessages - notifyDataSetChanged -> onBindViewHolder -> IncomingLinkPreviewMessageViewHolder Signed-off-by: Marcel Hibbe --- .../network/OfflineFirstChatRepository.kt | 42 ++++++++++--------- 1 file changed, 22 insertions(+), 20 deletions(-) diff --git a/app/src/main/java/com/nextcloud/talk/chat/data/network/OfflineFirstChatRepository.kt b/app/src/main/java/com/nextcloud/talk/chat/data/network/OfflineFirstChatRepository.kt index 2da9ae6fe1..e7a49ac414 100644 --- a/app/src/main/java/com/nextcloud/talk/chat/data/network/OfflineFirstChatRepository.kt +++ b/app/src/main/java/com/nextcloud/talk/chat/data/network/OfflineFirstChatRepository.kt @@ -199,29 +199,31 @@ class OfflineFirstChatRepository @Inject constructor( val networkParams = Bundle() while (true) { - if (!monitor.isOnline.first() || itIsPaused) Thread.sleep(HALF_SECOND) - - // sync database with server (This is a long blocking call because long polling (lookIntoFuture) is set) - networkParams.putSerializable(BundleKeys.KEY_FIELD_MAP, fieldMap) - - val resultsFromSync = sync(networkParams) - if (!resultsFromSync.isNullOrEmpty()) { - val chatMessages = resultsFromSync.map(ChatMessageEntity::asModel) - val pair = Pair(true, chatMessages) - _messageFlow.emit(pair) - } + if (!monitor.isOnline.first() || itIsPaused) { + Thread.sleep(HALF_SECOND) + } else { + // sync database with server (This is a long blocking call because long polling (lookIntoFuture) is set) + networkParams.putSerializable(BundleKeys.KEY_FIELD_MAP, fieldMap) + + val resultsFromSync = sync(networkParams) + if (!resultsFromSync.isNullOrEmpty()) { + val chatMessages = resultsFromSync.map(ChatMessageEntity::asModel) + val pair = Pair(true, chatMessages) + _messageFlow.emit(pair) + } - updateUiForLastCommonRead() + updateUiForLastCommonRead() - val newestMessage = chatDao.getNewestMessageId(internalConversationId).toInt() + val newestMessage = chatDao.getNewestMessageId(internalConversationId).toInt() - // update field map vars for next cycle - fieldMap = getFieldMap( - lookIntoFuture = true, - includeLastKnown = false, - setReadMarker = true, - lastKnown = newestMessage - ) + // update field map vars for next cycle + fieldMap = getFieldMap( + lookIntoFuture = true, + includeLastKnown = false, + setReadMarker = true, + lastKnown = newestMessage + ) + } } } From 24c27d0029467c08355f149e335ab0ea397e354f Mon Sep 17 00:00:00 2001 From: Marcel Hibbe Date: Wed, 11 Sep 2024 17:21:41 +0200 Subject: [PATCH 028/885] sleep one second before websocket reconnect otherwise it's an endless loop without delay which may stress the devices... Signed-off-by: Marcel Hibbe --- .../main/java/com/nextcloud/talk/webrtc/WebSocketInstance.kt | 3 +++ 1 file changed, 3 insertions(+) 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 73c465a0f2..451d4f5eab 100644 --- a/app/src/main/java/com/nextcloud/talk/webrtc/WebSocketInstance.kt +++ b/app/src/main/java/com/nextcloud/talk/webrtc/WebSocketInstance.kt @@ -41,6 +41,7 @@ import org.greenrobot.eventbus.EventBus import org.greenrobot.eventbus.Subscribe import org.greenrobot.eventbus.ThreadMode import java.io.IOException +import java.lang.Thread.sleep import javax.inject.Inject @AutoInjector(NextcloudTalkApplication::class) @@ -127,6 +128,7 @@ class WebSocketInstance internal constructor( isConnected = false messagesQueue = ArrayList() } + sleep(ONE_SECOND) restartWebSocket() } @@ -485,5 +487,6 @@ class WebSocketInstance internal constructor( companion object { private const val TAG = "WebSocketInstance" private const val NORMAL_CLOSURE = 1000 + private const val ONE_SECOND: Long = 1000 } } From 9a44a9bf199247772eb191a8962515a8bf5c490c Mon Sep 17 00:00:00 2001 From: Nextcloud bot Date: Thu, 12 Sep 2024 02:50:22 +0000 Subject: [PATCH 029/885] Fix(l10n): Update translations from Transifex Signed-off-by: Nextcloud bot --- app/src/main/res/values-ru/strings.xml | 3 +++ app/src/main/res/values-sv/strings.xml | 4 ++++ 2 files changed, 7 insertions(+) diff --git a/app/src/main/res/values-ru/strings.xml b/app/src/main/res/values-ru/strings.xml index b88bcfe884..3890c774ce 100644 --- a/app/src/main/res/values-ru/strings.xml +++ b/app/src/main/res/values-ru/strings.xml @@ -173,6 +173,7 @@ Устройство Открыть контрольный список устранения неполадок Открыть экран диагностики + Разрешения на уведомления Телефон Внешний Внутренние @@ -299,6 +300,7 @@ Установить разрешения В некоторых разрешениях было отказано. Открыть настройки + Пожалуйста, предоставьте разрешения в разделе «Настройки» > «Разрешения». Учётная запись не найдена Чат через %s Выключить микрофон @@ -384,6 +386,7 @@ Уведомления отклонены. Разрешите уведомления в настройках Android Сообщения Сопоставление контактов по номеру телефона для создания ярлыков на приложения «Конференции» в приложение системных контактов + Ошибка 429 Слишком много запросов Вы можете указать свой номер телефона, чтобы другие пользователи могли вас найти Введите номер телефона Неправильный номер телефона diff --git a/app/src/main/res/values-sv/strings.xml b/app/src/main/res/values-sv/strings.xml index d73ba3ad83..cb250541f0 100644 --- a/app/src/main/res/values-sv/strings.xml +++ b/app/src/main/res/values-sv/strings.xml @@ -102,6 +102,7 @@ Lägg på Växla mikrofon Öppna bild i bild-läge + Växla till egen video INKOMMANDE Samtalsnamn Samtalsaviseringar @@ -350,6 +351,7 @@ Med mikrofon inaktiverad klickar du på &vänta för att använda Push-to-talk Uppdatera Påminn mig senare + Fjärrljud av Ta bort från favoriter Ta bort grupp och medlemmar Ta bort deltagare @@ -371,6 +373,7 @@ Sök Välj ett konto Välj deltagare + Skicka redigerat meddelande %1$s skickade en GIF. Du skickade en GIF. %1$s skickade en video. @@ -551,6 +554,7 @@ Privat Synkronisera med betrodda servrar och den globala och offentliga adressboken Publicerad + Växla omfång Ändra hemlighetsnivå för %1$s Bläddra till botten sekunder sedan From df6d54d51c30f15267d1c6b4a2b73a18c18c2f36 Mon Sep 17 00:00:00 2001 From: sowjanyakch Date: Wed, 22 May 2024 16:09:12 +0200 Subject: [PATCH 030/885] Add endpoints upload and delete Conversation Avatar Signed-off-by: sowjanyakch --- .../com/nextcloud/talk/api/NcApiCoroutines.kt | 14 ++ .../contacts/ContactsActivityViewModel.kt | 104 +++++++++++++ .../ConversationCreationRepository.kt | 4 + .../ConversationCreationRepositoryImpl.kt | 33 +++++ .../ConversationCreationViewModel.kt | 42 ++++++ .../repository/FakeRepositorySuccess.kt | 4 + gradle/verification-metadata.xml | 138 +++++++++++++++++- 7 files changed, 334 insertions(+), 5 deletions(-) create mode 100644 app/src/main/java/com/nextcloud/talk/contacts/ContactsActivityViewModel.kt diff --git a/app/src/main/java/com/nextcloud/talk/api/NcApiCoroutines.kt b/app/src/main/java/com/nextcloud/talk/api/NcApiCoroutines.kt index d08d2b317a..b5cb33a13f 100644 --- a/app/src/main/java/com/nextcloud/talk/api/NcApiCoroutines.kt +++ b/app/src/main/java/com/nextcloud/talk/api/NcApiCoroutines.kt @@ -11,13 +11,16 @@ import com.nextcloud.talk.models.json.autocomplete.AutocompleteOverall import com.nextcloud.talk.models.json.conversations.RoomOverall import com.nextcloud.talk.models.json.generic.GenericOverall import com.nextcloud.talk.models.json.participants.AddParticipantOverall +import okhttp3.MultipartBody import retrofit2.http.DELETE import retrofit2.http.Field import retrofit2.http.FormUrlEncoded import retrofit2.http.GET import retrofit2.http.Header +import retrofit2.http.Multipart import retrofit2.http.POST import retrofit2.http.PUT +import retrofit2.http.Part import retrofit2.http.Query import retrofit2.http.QueryMap import retrofit2.http.Url @@ -96,4 +99,15 @@ interface NcApiCoroutines { @Url url: String?, @Field("password") password: String? ): GenericOverall + + @Multipart + @POST + suspend fun uploadConversationAvatar( + @Header("Authorization") authorization: String, + @Url url: String, + @Part("attachment") attachment: MultipartBody.Part + ): RoomOverall + + @DELETE + suspend fun deleteConversationAvatar(@Header("Authorization") authorization: String, @Url url: String): RoomOverall } diff --git a/app/src/main/java/com/nextcloud/talk/contacts/ContactsActivityViewModel.kt b/app/src/main/java/com/nextcloud/talk/contacts/ContactsActivityViewModel.kt new file mode 100644 index 0000000000..6c87c66089 --- /dev/null +++ b/app/src/main/java/com/nextcloud/talk/contacts/ContactsActivityViewModel.kt @@ -0,0 +1,104 @@ +/* + * Nextcloud Talk - Android Client + * + * SPDX-FileCopyrightText: 2024 Your Name + * SPDX-License-Identifier: GPL-3.0-or-later + */ + +package com.nextcloud.talk.contacts + +import androidx.lifecycle.ViewModel +import androidx.lifecycle.viewModelScope +import com.nextcloud.talk.data.user.model.User +import com.nextcloud.talk.models.json.autocomplete.AutocompleteUser +import com.nextcloud.talk.models.json.conversations.Conversation +import com.nextcloud.talk.users.UserManager +import com.nextcloud.talk.utils.ApiUtils +import kotlinx.coroutines.flow.MutableStateFlow +import kotlinx.coroutines.flow.StateFlow +import kotlinx.coroutines.launch +import javax.inject.Inject + +class ContactsActivityViewModel @Inject constructor( + private val repository: ContactsRepository, + private val userManager: UserManager +) : ViewModel() { + + private val _contactsViewState = MutableStateFlow(ContactsUiState.None) + val contactsViewState: StateFlow = _contactsViewState + private val _roomViewState = MutableStateFlow(RoomUiState.None) + val roomViewState: StateFlow = _roomViewState + private val _currentUser = userManager.currentUser.blockingGet() + val currentUser: User = _currentUser + private val _searchQuery = MutableStateFlow("") + val searchQuery: StateFlow = _searchQuery + private val shareTypes: MutableList = mutableListOf(ShareType.User.shareType) + val shareTypeList: List = shareTypes + + init { + getContactsFromSearchParams() + } + + fun updateSearchQuery(query: String) { + _searchQuery.value = query + } + + fun updateShareTypes(value: String) { + shareTypes.add(value) + } + + fun getContactsFromSearchParams() { + _contactsViewState.value = ContactsUiState.Loading + viewModelScope.launch { + try { + val contacts = repository.getContacts( + searchQuery.value, + shareTypeList + ) + val contactsList: List? = contacts.ocs!!.data + _contactsViewState.value = ContactsUiState.Success(contactsList) + } catch (exception: Exception) { + _contactsViewState.value = ContactsUiState.Error(exception.message ?: "") + } + } + } + + fun createRoom(roomType: String, sourceType: String, userId: String, conversationName: String?) { + viewModelScope.launch { + try { + val room = repository.createRoom( + roomType, + sourceType, + userId, + conversationName + ) + + val conversation: Conversation? = room.ocs?.data + _roomViewState.value = RoomUiState.Success(conversation) + } catch (exception: Exception) { + _roomViewState.value = RoomUiState.Error(exception.message ?: "") + } + } + } + + fun getImageUri(avatarId: String, requestBigSize: Boolean): String { + return ApiUtils.getUrlForAvatar( + _currentUser.baseUrl, + avatarId, + requestBigSize + ) + } +} + +sealed class ContactsUiState { + data object None : ContactsUiState() + data object Loading : ContactsUiState() + data class Success(val contacts: List?) : ContactsUiState() + data class Error(val message: String) : ContactsUiState() +} + +sealed class RoomUiState { + data object None : RoomUiState() + data class Success(val conversation: Conversation?) : RoomUiState() + data class Error(val message: String) : RoomUiState() +} diff --git a/app/src/main/java/com/nextcloud/talk/conversationcreation/ConversationCreationRepository.kt b/app/src/main/java/com/nextcloud/talk/conversationcreation/ConversationCreationRepository.kt index 6ebb6c3508..12c9dbad84 100644 --- a/app/src/main/java/com/nextcloud/talk/conversationcreation/ConversationCreationRepository.kt +++ b/app/src/main/java/com/nextcloud/talk/conversationcreation/ConversationCreationRepository.kt @@ -7,9 +7,11 @@ package com.nextcloud.talk.conversationcreation +import com.nextcloud.talk.models.domain.ConversationModel import com.nextcloud.talk.models.json.conversations.RoomOverall import com.nextcloud.talk.models.json.generic.GenericOverall import com.nextcloud.talk.models.json.participants.AddParticipantOverall +import java.io.File interface ConversationCreationRepository { @@ -21,4 +23,6 @@ interface ConversationCreationRepository { suspend fun createRoom(roomType: String, conversationName: String?): RoomOverall fun getImageUri(avatarId: String, requestBigSize: Boolean): String suspend fun setPassword(roomToken: String, password: String): GenericOverall + suspend fun uploadConversationAvatar(file: File, roomToken: String): ConversationModel + suspend fun deleteConversationAvatar(roomToken: String): ConversationModel } diff --git a/app/src/main/java/com/nextcloud/talk/conversationcreation/ConversationCreationRepositoryImpl.kt b/app/src/main/java/com/nextcloud/talk/conversationcreation/ConversationCreationRepositoryImpl.kt index 4e00f174c7..1f804e3ade 100644 --- a/app/src/main/java/com/nextcloud/talk/conversationcreation/ConversationCreationRepositoryImpl.kt +++ b/app/src/main/java/com/nextcloud/talk/conversationcreation/ConversationCreationRepositoryImpl.kt @@ -10,6 +10,7 @@ package com.nextcloud.talk.conversationcreation import com.nextcloud.talk.api.NcApiCoroutines import com.nextcloud.talk.data.user.model.User import com.nextcloud.talk.models.RetrofitBucket +import com.nextcloud.talk.models.domain.ConversationModel import com.nextcloud.talk.models.json.conversations.RoomOverall import com.nextcloud.talk.models.json.generic.GenericOverall import com.nextcloud.talk.models.json.participants.AddParticipantOverall @@ -17,6 +18,11 @@ import com.nextcloud.talk.users.UserManager import com.nextcloud.talk.utils.ApiUtils import com.nextcloud.talk.utils.ApiUtils.getRetrofitBucketForAddParticipant import com.nextcloud.talk.utils.ApiUtils.getRetrofitBucketForAddParticipantWithSource +import com.nextcloud.talk.utils.Mimetype +import okhttp3.MediaType.Companion.toMediaTypeOrNull +import okhttp3.MultipartBody +import okhttp3.RequestBody.Companion.asRequestBody +import java.io.File class ConversationCreationRepositoryImpl( private val ncApiCoroutines: NcApiCoroutines, @@ -126,6 +132,33 @@ class ConversationCreationRepositoryImpl( return result } + override suspend fun uploadConversationAvatar(file: File, roomToken: String): ConversationModel { + val builder = MultipartBody.Builder() + builder.setType(MultipartBody.FORM) + builder.addFormDataPart( + "file", + file.name, + file.asRequestBody(Mimetype.IMAGE_PREFIX_GENERIC.toMediaTypeOrNull()) + ) + val filePart: MultipartBody.Part = MultipartBody.Part.createFormData( + "file", + file.name, + file.asRequestBody(Mimetype.IMAGE_JPG.toMediaTypeOrNull()) + ) + val response = ncApiCoroutines.uploadConversationAvatar( + credentials!!, + ApiUtils.getUrlForConversationAvatar(1, _currentUser.baseUrl!!, roomToken), + filePart + ) + return ConversationModel.mapToConversationModel(response.ocs?.data!!, _currentUser) + } + + override suspend fun deleteConversationAvatar(roomToken: String): ConversationModel { + val url = ApiUtils.getUrlForConversationAvatar(1, _currentUser.baseUrl!!, roomToken) + val response = ncApiCoroutines.deleteConversationAvatar(credentials!!, url) + return ConversationModel.mapToConversationModel(response.ocs?.data!!, _currentUser) + } + override suspend fun allowGuests(token: String, allow: Boolean): GenericOverall { val url = ApiUtils.getUrlForRoomPublic( apiVersion, diff --git a/app/src/main/java/com/nextcloud/talk/conversationcreation/ConversationCreationViewModel.kt b/app/src/main/java/com/nextcloud/talk/conversationcreation/ConversationCreationViewModel.kt index 759637cde1..2b92133834 100644 --- a/app/src/main/java/com/nextcloud/talk/conversationcreation/ConversationCreationViewModel.kt +++ b/app/src/main/java/com/nextcloud/talk/conversationcreation/ConversationCreationViewModel.kt @@ -11,6 +11,7 @@ import android.util.Log import androidx.compose.runtime.mutableStateOf import androidx.lifecycle.ViewModel import androidx.lifecycle.viewModelScope +import com.nextcloud.talk.models.domain.ConversationModel import com.nextcloud.talk.models.json.autocomplete.AutocompleteUser import com.nextcloud.talk.models.json.conversations.Conversation import com.nextcloud.talk.models.json.generic.GenericMeta @@ -18,6 +19,7 @@ import com.nextcloud.talk.repositories.conversations.ConversationsRepositoryImpl import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.flow.StateFlow import kotlinx.coroutines.launch +import java.io.File import javax.inject.Inject class ConversationCreationViewModel @Inject constructor( @@ -27,6 +29,12 @@ class ConversationCreationViewModel @Inject constructor( val selectedParticipants: StateFlow> = _selectedParticipants private val roomViewState = MutableStateFlow(RoomUIState.None) + private val _uploadState = MutableStateFlow(UploadAvatarState.Loading) + val uploadState: StateFlow = _uploadState + + private val _deleteState = MutableStateFlow(DeleteAvatarState.Loading) + val deleteState: StateFlow = _deleteState + fun updateSelectedParticipants(participants: List) { _selectedParticipants.value = participants } @@ -116,6 +124,28 @@ class ConversationCreationViewModel @Inject constructor( } } + fun uploadConversationAvatar(file: File, roomToken: String) { + viewModelScope.launch { + try { + val response = repository.uploadConversationAvatar(file, roomToken) + _uploadState.value = UploadAvatarState.Success(response) + } catch (e: Exception) { + _uploadState.value = UploadAvatarState.Error(e) + } + } + } + + fun deleteConversationAvatar(roomToken: String) { + viewModelScope.launch { + try { + val result = repository.deleteConversationAvatar(roomToken) + _deleteState.value = DeleteAvatarState.Success(result) + } catch (e: Exception) { + _deleteState.value = DeleteAvatarState.Error(e) + } + } + } + fun getImageUri(avatarId: String, requestBigSize: Boolean): String { return repository.getImageUri(avatarId, requestBigSize) } @@ -154,3 +184,15 @@ sealed class AddParticipantsUiState { data class Success(val participants: List?) : AddParticipantsUiState() data class Error(val message: String) : AddParticipantsUiState() } + +sealed class UploadAvatarState { + object Loading : UploadAvatarState() + data class Success(val roomOverall: ConversationModel) : UploadAvatarState() + data class Error(val exception: Exception) : UploadAvatarState() +} + +sealed class DeleteAvatarState { + object Loading : DeleteAvatarState() + data class Success(val roomOverall: ConversationModel) : DeleteAvatarState() + data class Error(val exception: Exception) : DeleteAvatarState() +} diff --git a/app/src/test/java/com/nextcloud/talk/contacts/repository/FakeRepositorySuccess.kt b/app/src/test/java/com/nextcloud/talk/contacts/repository/FakeRepositorySuccess.kt index f5d87d9195..9022ba0598 100644 --- a/app/src/test/java/com/nextcloud/talk/contacts/repository/FakeRepositorySuccess.kt +++ b/app/src/test/java/com/nextcloud/talk/contacts/repository/FakeRepositorySuccess.kt @@ -29,4 +29,8 @@ class FakeRepositorySuccess : ContactsRepository { override fun getImageUri(avatarId: String, requestBigSize: Boolean): String { return "https://mydomain.com/index.php/avatar/$avatarId/512" } + + override fun getImageUri(avatarId: String, requestBigSize: Boolean): String { + TODO("Not yet implemented") + } } diff --git a/gradle/verification-metadata.xml b/gradle/verification-metadata.xml index 634c94ad30..e1c53723b4 100644 --- a/gradle/verification-metadata.xml +++ b/gradle/verification-metadata.xml @@ -4,13 +4,13 @@ true true - - - - + + + + @@ -151,7 +151,6 @@ - @@ -163,6 +162,7 @@ + @@ -252,6 +252,7 @@ + @@ -349,6 +350,50 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + @@ -365,6 +410,14 @@ + + + + + + + + @@ -378,6 +431,11 @@ + + + + + @@ -399,6 +457,76 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + From fa014aab3a9a6d78b434683dbe4b464c182067e5 Mon Sep 17 00:00:00 2001 From: sowjanyakch Date: Wed, 11 Sep 2024 17:58:52 +0200 Subject: [PATCH 031/885] Make pickImage work Signed-off-by: sowjanyakch --- .../ConversationCreationActivity.kt | 114 ++++++++++++++---- .../ConversationCreationViewModel.kt | 8 +- 2 files changed, 99 insertions(+), 23 deletions(-) diff --git a/app/src/main/java/com/nextcloud/talk/conversationcreation/ConversationCreationActivity.kt b/app/src/main/java/com/nextcloud/talk/conversationcreation/ConversationCreationActivity.kt index 021f6e9cf3..e2bf8e5ea7 100644 --- a/app/src/main/java/com/nextcloud/talk/conversationcreation/ConversationCreationActivity.kt +++ b/app/src/main/java/com/nextcloud/talk/conversationcreation/ConversationCreationActivity.kt @@ -13,6 +13,7 @@ import android.annotation.SuppressLint import android.app.Activity import android.content.Context import android.content.Intent +import android.net.Uri import android.os.Bundle import androidx.activity.compose.ManagedActivityResultLauncher import androidx.activity.compose.rememberLauncherForActivityResult @@ -77,6 +78,7 @@ import com.nextcloud.talk.chat.ChatActivity import com.nextcloud.talk.contacts.ContactsActivityCompose import com.nextcloud.talk.contacts.loadImage import com.nextcloud.talk.models.json.autocomplete.AutocompleteUser +import com.nextcloud.talk.utils.PickImage import com.nextcloud.talk.utils.bundle.BundleKeys import javax.inject.Inject @@ -84,7 +86,7 @@ import javax.inject.Inject class ConversationCreationActivity : BaseActivity() { @Inject lateinit var viewModelFactory: ViewModelProvider.Factory - + private lateinit var pickImage: PickImage override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) @@ -93,13 +95,16 @@ class ConversationCreationActivity : BaseActivity() { this, viewModelFactory )[ConversationCreationViewModel::class.java] + val conversationUser = conversationCreationViewModel.currentUser + pickImage = PickImage(this, conversationUser) + setContent { val colorScheme = viewThemeUtils.getColorScheme(this) val context = LocalContext.current MaterialTheme( colorScheme = colorScheme ) { - ConversationCreationScreen(conversationCreationViewModel, context) + ConversationCreationScreen(conversationCreationViewModel, context, pickImage) } SetStatusBarColor() } @@ -125,15 +130,47 @@ private fun SetStatusBarColor() { @OptIn(ExperimentalMaterial3Api::class) @Composable -fun ConversationCreationScreen(conversationCreationViewModel: ConversationCreationViewModel, context: Context) { +fun ConversationCreationScreen( + conversationCreationViewModel: ConversationCreationViewModel, + context: Context, + pickImage: PickImage +) { + var selectedImageUri by remember { mutableStateOf(null) } + + val imagePickerLauncher = rememberLauncherForActivityResult( + contract = ActivityResultContracts.StartActivityForResult() + ) { result -> + if (result.resultCode == Activity.RESULT_OK) { + pickImage.onImagePickerResult(result.data) { uri -> + selectedImageUri = uri + } + } + } + + val remoteFilePickerLauncher = rememberLauncherForActivityResult( + contract = ActivityResultContracts.StartActivityForResult() + ) { result -> + if (result.resultCode == Activity.RESULT_OK) { + pickImage.onSelectRemoteFilesResult(imagePickerLauncher, result.data) + } + } + + val cameraLauncher = rememberLauncherForActivityResult( + contract = ActivityResultContracts.StartActivityForResult() + ) { result -> + if (result.resultCode == Activity.RESULT_OK) { + pickImage.onTakePictureResult(imagePickerLauncher, result.data) + } + } + val launcher = rememberLauncherForActivityResult( contract = ActivityResultContracts.StartActivityForResult(), - onResult = { result -> if (result.resultCode == Activity.RESULT_OK) { val data = result.data - val selectedParticipants = data?.getParcelableArrayListExtra("selectedParticipants") - ?: emptyList() + val selectedParticipants = + data?.getParcelableArrayListExtra("selectedParticipants") + ?: emptyList() val participants = selectedParticipants.toMutableList() conversationCreationViewModel.updateSelectedParticipants(participants) } @@ -162,8 +199,16 @@ fun ConversationCreationScreen(conversationCreationViewModel: ConversationCreati .padding(paddingValues) .verticalScroll(rememberScrollState()) ) { - DefaultUserAvatar() - UploadAvatar() + DefaultUserAvatar(selectedImageUri) + UploadAvatar( + pickImage = pickImage, + onImageSelected = { uri -> selectedImageUri = uri }, + imagePickerLauncher = imagePickerLauncher, + remoteFilePickerLauncher = remoteFilePickerLauncher, + cameraLauncher = cameraLauncher, + onDeleteImage = { selectedImageUri = null } + ) + ConversationNameAndDescription(conversationCreationViewModel) AddParticipants(launcher, context, conversationCreationViewModel) RoomCreationOptions(conversationCreationViewModel) @@ -174,31 +219,51 @@ fun ConversationCreationScreen(conversationCreationViewModel: ConversationCreati } @Composable -fun DefaultUserAvatar() { +fun DefaultUserAvatar(selectedImageUri: Uri?) { Box( modifier = Modifier.fillMaxWidth(), contentAlignment = Alignment.Center ) { - AsyncImage( - model = R.drawable.ic_circular_group, - contentDescription = stringResource(id = R.string.user_avatar), - modifier = Modifier - .size(width = 84.dp, height = 84.dp) - .padding(top = 8.dp) - ) + if (selectedImageUri != null) { + AsyncImage( + model = selectedImageUri, + contentDescription = stringResource(id = R.string.user_avatar), + modifier = Modifier + .size(84.dp) + .padding(top = 8.dp) + ) + } else { + AsyncImage( + model = R.drawable.ic_circular_group, + contentDescription = stringResource(id = R.string.user_avatar), + modifier = Modifier + .size(84.dp) + .padding(top = 8.dp) + ) + } } } @Composable -fun UploadAvatar() { +fun UploadAvatar( + pickImage: PickImage, + onImageSelected: (Uri) -> Unit, + imagePickerLauncher: ManagedActivityResultLauncher, + remoteFilePickerLauncher: ManagedActivityResultLauncher, + cameraLauncher: ManagedActivityResultLauncher, + onDeleteImage: () -> Unit +) { Row( modifier = Modifier .fillMaxWidth() .padding(16.dp), horizontalArrangement = Arrangement.Center ) { - IconButton(onClick = { - }) { + IconButton( + onClick = { + pickImage.takePicture(cameraLauncher) + } + ) { Icon( painter = painterResource(id = R.drawable.ic_baseline_photo_camera_24), contentDescription = null, @@ -207,6 +272,7 @@ fun UploadAvatar() { } IconButton(onClick = { + pickImage.selectLocal(imagePickerLauncher) }) { Icon( painter = painterResource(id = R.drawable.ic_folder_multiple_image), @@ -214,9 +280,11 @@ fun UploadAvatar() { modifier = Modifier.size(24.dp) ) } - - IconButton(onClick = { - }) { + IconButton( + onClick = { + pickImage.selectRemote(remoteFilePickerLauncher) + } + ) { Icon( painter = painterResource(id = R.drawable.baseline_tag_faces_24), contentDescription = null, @@ -225,6 +293,7 @@ fun UploadAvatar() { } IconButton(onClick = { + onDeleteImage() }) { Icon( painter = painterResource(id = R.drawable.ic_delete_grey600_24dp), @@ -530,6 +599,7 @@ fun CreateConversation(conversationCreationViewModel: ConversationCreationViewMo } } } + class CompanionClass { companion object { internal val TAG = ConversationCreationActivity::class.simpleName diff --git a/app/src/main/java/com/nextcloud/talk/conversationcreation/ConversationCreationViewModel.kt b/app/src/main/java/com/nextcloud/talk/conversationcreation/ConversationCreationViewModel.kt index 2b92133834..e710b3b3e4 100644 --- a/app/src/main/java/com/nextcloud/talk/conversationcreation/ConversationCreationViewModel.kt +++ b/app/src/main/java/com/nextcloud/talk/conversationcreation/ConversationCreationViewModel.kt @@ -11,11 +11,13 @@ import android.util.Log import androidx.compose.runtime.mutableStateOf import androidx.lifecycle.ViewModel import androidx.lifecycle.viewModelScope +import com.nextcloud.talk.data.user.model.User import com.nextcloud.talk.models.domain.ConversationModel import com.nextcloud.talk.models.json.autocomplete.AutocompleteUser import com.nextcloud.talk.models.json.conversations.Conversation import com.nextcloud.talk.models.json.generic.GenericMeta import com.nextcloud.talk.repositories.conversations.ConversationsRepositoryImpl.Companion.STATUS_CODE_OK +import com.nextcloud.talk.users.UserManager import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.flow.StateFlow import kotlinx.coroutines.launch @@ -23,7 +25,8 @@ import java.io.File import javax.inject.Inject class ConversationCreationViewModel @Inject constructor( - private val repository: ConversationCreationRepository + private val repository: ConversationCreationRepository, + private val userManager: UserManager ) : ViewModel() { private val _selectedParticipants = MutableStateFlow>(emptyList()) val selectedParticipants: StateFlow> = _selectedParticipants @@ -35,6 +38,9 @@ class ConversationCreationViewModel @Inject constructor( private val _deleteState = MutableStateFlow(DeleteAvatarState.Loading) val deleteState: StateFlow = _deleteState + private val _currentUser = userManager.currentUser.blockingGet() + val currentUser: User = _currentUser + fun updateSelectedParticipants(participants: List) { _selectedParticipants.value = participants } From f8bc4f2e96761cf30025ee4a34cd4fb0915ca0e6 Mon Sep 17 00:00:00 2001 From: sowjanyakch Date: Thu, 12 Sep 2024 09:21:07 +0200 Subject: [PATCH 032/885] upload conversation avatar Signed-off-by: sowjanyakch --- .../com/nextcloud/talk/api/NcApiCoroutines.kt | 2 +- .../ConversationCreationActivity.kt | 11 +++-- .../ConversationCreationViewModel.kt | 47 +++---------------- 3 files changed, 13 insertions(+), 47 deletions(-) diff --git a/app/src/main/java/com/nextcloud/talk/api/NcApiCoroutines.kt b/app/src/main/java/com/nextcloud/talk/api/NcApiCoroutines.kt index b5cb33a13f..537bdeb14d 100644 --- a/app/src/main/java/com/nextcloud/talk/api/NcApiCoroutines.kt +++ b/app/src/main/java/com/nextcloud/talk/api/NcApiCoroutines.kt @@ -105,7 +105,7 @@ interface NcApiCoroutines { suspend fun uploadConversationAvatar( @Header("Authorization") authorization: String, @Url url: String, - @Part("attachment") attachment: MultipartBody.Part + @Part attachment: MultipartBody.Part ): RoomOverall @DELETE diff --git a/app/src/main/java/com/nextcloud/talk/conversationcreation/ConversationCreationActivity.kt b/app/src/main/java/com/nextcloud/talk/conversationcreation/ConversationCreationActivity.kt index e2bf8e5ea7..0ba7aee210 100644 --- a/app/src/main/java/com/nextcloud/talk/conversationcreation/ConversationCreationActivity.kt +++ b/app/src/main/java/com/nextcloud/talk/conversationcreation/ConversationCreationActivity.kt @@ -212,7 +212,7 @@ fun ConversationCreationScreen( ConversationNameAndDescription(conversationCreationViewModel) AddParticipants(launcher, context, conversationCreationViewModel) RoomCreationOptions(conversationCreationViewModel) - CreateConversation(conversationCreationViewModel, context) + CreateConversation(conversationCreationViewModel, context,selectedImageUri) } } ) @@ -275,7 +275,7 @@ fun UploadAvatar( pickImage.selectLocal(imagePickerLauncher) }) { Icon( - painter = painterResource(id = R.drawable.ic_folder_multiple_image), + painter = painterResource(id = R.drawable.upload), contentDescription = null, modifier = Modifier.size(24.dp) ) @@ -286,7 +286,7 @@ fun UploadAvatar( } ) { Icon( - painter = painterResource(id = R.drawable.baseline_tag_faces_24), + painter = painterResource(id = R.drawable.ic_mimetype_folder), contentDescription = null, modifier = Modifier.size(24.dp) ) @@ -571,7 +571,7 @@ fun ShowPasswordDialog(onDismiss: () -> Unit, conversationCreationViewModel: Con } @Composable -fun CreateConversation(conversationCreationViewModel: ConversationCreationViewModel, context: Context) { +fun CreateConversation(conversationCreationViewModel: ConversationCreationViewModel, context: Context,selectedImageUri: Uri?) { val selectedParticipants by conversationCreationViewModel.selectedParticipants.collectAsState() Box( modifier = Modifier @@ -584,7 +584,8 @@ fun CreateConversation(conversationCreationViewModel: ConversationCreationViewMo conversationCreationViewModel.createRoomAndAddParticipants( roomType = CompanionClass.ROOM_TYPE_GROUP, conversationName = conversationCreationViewModel.roomName.value, - participants = selectedParticipants.toSet() + participants = selectedParticipants.toSet(), + selectedImageUri = selectedImageUri ) { roomToken -> val bundle = Bundle() bundle.putString(BundleKeys.KEY_ROOM_TOKEN, roomToken) diff --git a/app/src/main/java/com/nextcloud/talk/conversationcreation/ConversationCreationViewModel.kt b/app/src/main/java/com/nextcloud/talk/conversationcreation/ConversationCreationViewModel.kt index e710b3b3e4..13fc607f59 100644 --- a/app/src/main/java/com/nextcloud/talk/conversationcreation/ConversationCreationViewModel.kt +++ b/app/src/main/java/com/nextcloud/talk/conversationcreation/ConversationCreationViewModel.kt @@ -7,12 +7,13 @@ package com.nextcloud.talk.conversationcreation +import android.net.Uri import android.util.Log import androidx.compose.runtime.mutableStateOf +import androidx.core.net.toFile import androidx.lifecycle.ViewModel import androidx.lifecycle.viewModelScope import com.nextcloud.talk.data.user.model.User -import com.nextcloud.talk.models.domain.ConversationModel import com.nextcloud.talk.models.json.autocomplete.AutocompleteUser import com.nextcloud.talk.models.json.conversations.Conversation import com.nextcloud.talk.models.json.generic.GenericMeta @@ -21,7 +22,6 @@ import com.nextcloud.talk.users.UserManager import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.flow.StateFlow import kotlinx.coroutines.launch -import java.io.File import javax.inject.Inject class ConversationCreationViewModel @Inject constructor( @@ -32,12 +32,6 @@ class ConversationCreationViewModel @Inject constructor( val selectedParticipants: StateFlow> = _selectedParticipants private val roomViewState = MutableStateFlow(RoomUIState.None) - private val _uploadState = MutableStateFlow(UploadAvatarState.Loading) - val uploadState: StateFlow = _uploadState - - private val _deleteState = MutableStateFlow(DeleteAvatarState.Loading) - val deleteState: StateFlow = _deleteState - private val _currentUser = userManager.currentUser.blockingGet() val currentUser: User = _currentUser @@ -72,6 +66,7 @@ class ConversationCreationViewModel @Inject constructor( roomType: String, conversationName: String, participants: Set, + selectedImageUri: Uri?, onRoomCreated: (String) -> Unit ) { val scope = when { @@ -114,6 +109,9 @@ class ConversationCreationViewModel @Inject constructor( repository.setPassword(token, _password.value) } repository.openConversation(token, scope) + if(selectedImageUri!= null){ + repository.uploadConversationAvatar(selectedImageUri.toFile(), token) + } onRoomCreated(token) } catch (exception: Exception) { allowGuestsResult.value = AllowGuestsUiState.Error(exception.message ?: "") @@ -130,28 +128,6 @@ class ConversationCreationViewModel @Inject constructor( } } - fun uploadConversationAvatar(file: File, roomToken: String) { - viewModelScope.launch { - try { - val response = repository.uploadConversationAvatar(file, roomToken) - _uploadState.value = UploadAvatarState.Success(response) - } catch (e: Exception) { - _uploadState.value = UploadAvatarState.Error(e) - } - } - } - - fun deleteConversationAvatar(roomToken: String) { - viewModelScope.launch { - try { - val result = repository.deleteConversationAvatar(roomToken) - _deleteState.value = DeleteAvatarState.Success(result) - } catch (e: Exception) { - _deleteState.value = DeleteAvatarState.Error(e) - } - } - } - fun getImageUri(avatarId: String, requestBigSize: Boolean): String { return repository.getImageUri(avatarId, requestBigSize) } @@ -191,14 +167,3 @@ sealed class AddParticipantsUiState { data class Error(val message: String) : AddParticipantsUiState() } -sealed class UploadAvatarState { - object Loading : UploadAvatarState() - data class Success(val roomOverall: ConversationModel) : UploadAvatarState() - data class Error(val exception: Exception) : UploadAvatarState() -} - -sealed class DeleteAvatarState { - object Loading : DeleteAvatarState() - data class Success(val roomOverall: ConversationModel) : DeleteAvatarState() - data class Error(val exception: Exception) : DeleteAvatarState() -} From 3946240e4f44cc03f0b661acdc814281816f8104 Mon Sep 17 00:00:00 2001 From: sowjanyakch Date: Thu, 12 Sep 2024 10:03:49 +0200 Subject: [PATCH 033/885] Add verification metadata Signed-off-by: sowjanyakch --- .../contacts/ContactsActivityViewModel.kt | 104 ------------- gradle/verification-metadata.xml | 138 +----------------- 2 files changed, 5 insertions(+), 237 deletions(-) delete mode 100644 app/src/main/java/com/nextcloud/talk/contacts/ContactsActivityViewModel.kt diff --git a/app/src/main/java/com/nextcloud/talk/contacts/ContactsActivityViewModel.kt b/app/src/main/java/com/nextcloud/talk/contacts/ContactsActivityViewModel.kt deleted file mode 100644 index 6c87c66089..0000000000 --- a/app/src/main/java/com/nextcloud/talk/contacts/ContactsActivityViewModel.kt +++ /dev/null @@ -1,104 +0,0 @@ -/* - * Nextcloud Talk - Android Client - * - * SPDX-FileCopyrightText: 2024 Your Name - * SPDX-License-Identifier: GPL-3.0-or-later - */ - -package com.nextcloud.talk.contacts - -import androidx.lifecycle.ViewModel -import androidx.lifecycle.viewModelScope -import com.nextcloud.talk.data.user.model.User -import com.nextcloud.talk.models.json.autocomplete.AutocompleteUser -import com.nextcloud.talk.models.json.conversations.Conversation -import com.nextcloud.talk.users.UserManager -import com.nextcloud.talk.utils.ApiUtils -import kotlinx.coroutines.flow.MutableStateFlow -import kotlinx.coroutines.flow.StateFlow -import kotlinx.coroutines.launch -import javax.inject.Inject - -class ContactsActivityViewModel @Inject constructor( - private val repository: ContactsRepository, - private val userManager: UserManager -) : ViewModel() { - - private val _contactsViewState = MutableStateFlow(ContactsUiState.None) - val contactsViewState: StateFlow = _contactsViewState - private val _roomViewState = MutableStateFlow(RoomUiState.None) - val roomViewState: StateFlow = _roomViewState - private val _currentUser = userManager.currentUser.blockingGet() - val currentUser: User = _currentUser - private val _searchQuery = MutableStateFlow("") - val searchQuery: StateFlow = _searchQuery - private val shareTypes: MutableList = mutableListOf(ShareType.User.shareType) - val shareTypeList: List = shareTypes - - init { - getContactsFromSearchParams() - } - - fun updateSearchQuery(query: String) { - _searchQuery.value = query - } - - fun updateShareTypes(value: String) { - shareTypes.add(value) - } - - fun getContactsFromSearchParams() { - _contactsViewState.value = ContactsUiState.Loading - viewModelScope.launch { - try { - val contacts = repository.getContacts( - searchQuery.value, - shareTypeList - ) - val contactsList: List? = contacts.ocs!!.data - _contactsViewState.value = ContactsUiState.Success(contactsList) - } catch (exception: Exception) { - _contactsViewState.value = ContactsUiState.Error(exception.message ?: "") - } - } - } - - fun createRoom(roomType: String, sourceType: String, userId: String, conversationName: String?) { - viewModelScope.launch { - try { - val room = repository.createRoom( - roomType, - sourceType, - userId, - conversationName - ) - - val conversation: Conversation? = room.ocs?.data - _roomViewState.value = RoomUiState.Success(conversation) - } catch (exception: Exception) { - _roomViewState.value = RoomUiState.Error(exception.message ?: "") - } - } - } - - fun getImageUri(avatarId: String, requestBigSize: Boolean): String { - return ApiUtils.getUrlForAvatar( - _currentUser.baseUrl, - avatarId, - requestBigSize - ) - } -} - -sealed class ContactsUiState { - data object None : ContactsUiState() - data object Loading : ContactsUiState() - data class Success(val contacts: List?) : ContactsUiState() - data class Error(val message: String) : ContactsUiState() -} - -sealed class RoomUiState { - data object None : RoomUiState() - data class Success(val conversation: Conversation?) : RoomUiState() - data class Error(val message: String) : RoomUiState() -} diff --git a/gradle/verification-metadata.xml b/gradle/verification-metadata.xml index e1c53723b4..634c94ad30 100644 --- a/gradle/verification-metadata.xml +++ b/gradle/verification-metadata.xml @@ -4,13 +4,13 @@ true true + + + + - - - - @@ -151,6 +151,7 @@ + @@ -162,7 +163,6 @@ - @@ -252,7 +252,6 @@ - @@ -350,50 +349,6 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - @@ -410,14 +365,6 @@ - - - - - - - - @@ -431,11 +378,6 @@ - - - - - @@ -457,76 +399,6 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - From f20ec95b5f17f3c7d92288672a416def587f2c50 Mon Sep 17 00:00:00 2001 From: sowjanyakch Date: Thu, 12 Sep 2024 10:10:01 +0200 Subject: [PATCH 034/885] Avoid conflicting overloads Signed-off-by: sowjanyakch --- .../talk/contacts/repository/FakeRepositorySuccess.kt | 4 ---- 1 file changed, 4 deletions(-) diff --git a/app/src/test/java/com/nextcloud/talk/contacts/repository/FakeRepositorySuccess.kt b/app/src/test/java/com/nextcloud/talk/contacts/repository/FakeRepositorySuccess.kt index 9022ba0598..f5d87d9195 100644 --- a/app/src/test/java/com/nextcloud/talk/contacts/repository/FakeRepositorySuccess.kt +++ b/app/src/test/java/com/nextcloud/talk/contacts/repository/FakeRepositorySuccess.kt @@ -29,8 +29,4 @@ class FakeRepositorySuccess : ContactsRepository { override fun getImageUri(avatarId: String, requestBigSize: Boolean): String { return "https://mydomain.com/index.php/avatar/$avatarId/512" } - - override fun getImageUri(avatarId: String, requestBigSize: Boolean): String { - TODO("Not yet implemented") - } } From 6bc3b1a6e9398dfeaa9b5aba04f0888e6a8ff51a Mon Sep 17 00:00:00 2001 From: sowjanyakch Date: Thu, 12 Sep 2024 14:52:33 +0200 Subject: [PATCH 035/885] Make avatar circular Signed-off-by: sowjanyakch --- app/build.gradle | 2 +- .../ConversationCreationActivity.kt | 15 +++++++++++++-- .../ConversationCreationViewModel.kt | 3 +-- 3 files changed, 15 insertions(+), 5 deletions(-) diff --git a/app/build.gradle b/app/build.gradle index 99498baa6a..a5aa0ebb40 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -15,7 +15,7 @@ import com.github.spotbugs.snom.SpotBugsTask plugins { id "org.jetbrains.kotlin.plugin.compose" version "2.0.20" id "org.jetbrains.kotlin.kapt" - id 'com.google.devtools.ksp' version '2.0.20-1.0.25' + id 'com.google.devtools.ksp' version '2.0.20-1.0.24' } apply plugin: 'com.android.application' diff --git a/app/src/main/java/com/nextcloud/talk/conversationcreation/ConversationCreationActivity.kt b/app/src/main/java/com/nextcloud/talk/conversationcreation/ConversationCreationActivity.kt index 0ba7aee210..89acf6c856 100644 --- a/app/src/main/java/com/nextcloud/talk/conversationcreation/ConversationCreationActivity.kt +++ b/app/src/main/java/com/nextcloud/talk/conversationcreation/ConversationCreationActivity.kt @@ -33,6 +33,7 @@ import androidx.compose.foundation.layout.padding import androidx.compose.foundation.layout.size import androidx.compose.foundation.layout.width import androidx.compose.foundation.rememberScrollState +import androidx.compose.foundation.shape.CircleShape import androidx.compose.foundation.verticalScroll import androidx.compose.material.icons.Icons import androidx.compose.material.icons.automirrored.filled.ArrowBack @@ -58,7 +59,9 @@ import androidx.compose.runtime.remember import androidx.compose.runtime.setValue import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier +import androidx.compose.ui.draw.clip import androidx.compose.ui.graphics.Color +import androidx.compose.ui.layout.ContentScale import androidx.compose.ui.platform.LocalContext import androidx.compose.ui.platform.LocalView import androidx.compose.ui.res.colorResource @@ -212,7 +215,7 @@ fun ConversationCreationScreen( ConversationNameAndDescription(conversationCreationViewModel) AddParticipants(launcher, context, conversationCreationViewModel) RoomCreationOptions(conversationCreationViewModel) - CreateConversation(conversationCreationViewModel, context,selectedImageUri) + CreateConversation(conversationCreationViewModel, context, selectedImageUri) } } ) @@ -228,17 +231,21 @@ fun DefaultUserAvatar(selectedImageUri: Uri?) { AsyncImage( model = selectedImageUri, contentDescription = stringResource(id = R.string.user_avatar), + contentScale = ContentScale.Crop, modifier = Modifier .size(84.dp) .padding(top = 8.dp) + .clip(CircleShape) ) } else { AsyncImage( model = R.drawable.ic_circular_group, contentDescription = stringResource(id = R.string.user_avatar), + contentScale = ContentScale.Crop, modifier = Modifier .size(84.dp) .padding(top = 8.dp) + .clip(CircleShape) ) } } @@ -571,7 +578,11 @@ fun ShowPasswordDialog(onDismiss: () -> Unit, conversationCreationViewModel: Con } @Composable -fun CreateConversation(conversationCreationViewModel: ConversationCreationViewModel, context: Context,selectedImageUri: Uri?) { +fun CreateConversation( + conversationCreationViewModel: ConversationCreationViewModel, + context: Context, + selectedImageUri: Uri? +) { val selectedParticipants by conversationCreationViewModel.selectedParticipants.collectAsState() Box( modifier = Modifier diff --git a/app/src/main/java/com/nextcloud/talk/conversationcreation/ConversationCreationViewModel.kt b/app/src/main/java/com/nextcloud/talk/conversationcreation/ConversationCreationViewModel.kt index 13fc607f59..38586a6e38 100644 --- a/app/src/main/java/com/nextcloud/talk/conversationcreation/ConversationCreationViewModel.kt +++ b/app/src/main/java/com/nextcloud/talk/conversationcreation/ConversationCreationViewModel.kt @@ -109,7 +109,7 @@ class ConversationCreationViewModel @Inject constructor( repository.setPassword(token, _password.value) } repository.openConversation(token, scope) - if(selectedImageUri!= null){ + if (selectedImageUri != null) { repository.uploadConversationAvatar(selectedImageUri.toFile(), token) } onRoomCreated(token) @@ -166,4 +166,3 @@ sealed class AddParticipantsUiState { data class Success(val participants: List?) : AddParticipantsUiState() data class Error(val message: String) : AddParticipantsUiState() } - From c2231a51d4ab138768effcefd84afe77a50bb7e6 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Thu, 12 Sep 2024 15:38:13 +0000 Subject: [PATCH 036/885] Update plugin com.google.devtools.ksp to v2.0.20-1.0.25 Signed-off-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- app/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/build.gradle b/app/build.gradle index a5aa0ebb40..99498baa6a 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -15,7 +15,7 @@ import com.github.spotbugs.snom.SpotBugsTask plugins { id "org.jetbrains.kotlin.plugin.compose" version "2.0.20" id "org.jetbrains.kotlin.kapt" - id 'com.google.devtools.ksp' version '2.0.20-1.0.24' + id 'com.google.devtools.ksp' version '2.0.20-1.0.25' } apply plugin: 'com.android.application' From 569be55395981143e8db8c2b9bd7e0ff0638b994 Mon Sep 17 00:00:00 2001 From: rapterjet2004 Date: Tue, 10 Sep 2024 07:38:12 -0500 Subject: [PATCH 037/885] Implement queued messages for offline support Signed-off-by: rapterjet2004 --- .../talk/chat/MessageInputFragment.kt | 22 ++++++++++++----- .../chat/viewmodels/MessageInputViewModel.kt | 15 +++++++++++- .../utils/preferences/AppPreferencesImpl.kt | 24 ++++++++++--------- app/src/main/res/values/strings.xml | 1 + 4 files changed, 44 insertions(+), 18 deletions(-) diff --git a/app/src/main/java/com/nextcloud/talk/chat/MessageInputFragment.kt b/app/src/main/java/com/nextcloud/talk/chat/MessageInputFragment.kt index 4a49ea8d60..5bd77d9b12 100644 --- a/app/src/main/java/com/nextcloud/talk/chat/MessageInputFragment.kt +++ b/app/src/main/java/com/nextcloud/talk/chat/MessageInputFragment.kt @@ -73,6 +73,7 @@ import com.nextcloud.talk.utils.text.Spans import com.otaliastudios.autocomplete.Autocomplete import com.stfalcon.chatkit.commons.models.IMessage import com.vanniktech.emoji.EmojiPopup +import kotlinx.coroutines.delay import kotlinx.coroutines.flow.collect import kotlinx.coroutines.flow.onEach import kotlinx.coroutines.launch @@ -141,6 +142,11 @@ class MessageInputFragment : Fragment() { saveState() } + override fun onResume() { + super.onResume() + chatActivity.messageInputViewModel.restoreMessageQueue(chatActivity.roomToken) + } + override fun onDestroyView() { super.onDestroyView() if (mentionAutocomplete != null && mentionAutocomplete!!.isPopupShowing) { @@ -178,12 +184,19 @@ class MessageInputFragment : Fragment() { val connectionGained = (!wasOnline && isOnline) wasOnline = !binding.fragmentMessageInputView.isShown Log.d(TAG, "isOnline: $isOnline\nwasOnline: $wasOnline\nconnectionGained: $connectionGained") - - // FIXME timeout exception - maybe something to do with the room? - // handleMessageQueue(isOnline) + delay(500) + handleMessageQueue(isOnline) handleUI(isOnline, connectionGained) }.collect() } + + chatActivity.messageInputViewModel.messageQueueSizeFlow.observe(viewLifecycleOwner) { size -> + if (size > 0) { + binding.fragmentConnectionLost.text = getString(R.string.connection_lost_queued, size) + } else { + binding.fragmentConnectionLost.text = getString(R.string.connection_lost_sent_messages_are_queued) + } + } } private fun handleUI(isOnline: Boolean, connectionGained: Boolean) { @@ -220,12 +233,9 @@ class MessageInputFragment : Fragment() { binding.fragmentConnectionLost.clearAnimation() binding.fragmentConnectionLost.visibility = View.GONE binding.fragmentConnectionLost.setBackgroundColor(resources.getColor(R.color.hwSecurityRed)) - binding.fragmentConnectionLost.text = - getString(R.string.connection_lost_sent_messages_are_queued) binding.fragmentConnectionLost.visibility = View.VISIBLE binding.fragmentMessageInputView.attachmentButton.isEnabled = false binding.fragmentMessageInputView.recordAudioButton.isEnabled = false - binding.fragmentMessageInputView.messageInput.isEnabled = false } } diff --git a/app/src/main/java/com/nextcloud/talk/chat/viewmodels/MessageInputViewModel.kt b/app/src/main/java/com/nextcloud/talk/chat/viewmodels/MessageInputViewModel.kt index 4489ca8301..a3e641b52d 100644 --- a/app/src/main/java/com/nextcloud/talk/chat/viewmodels/MessageInputViewModel.kt +++ b/app/src/main/java/com/nextcloud/talk/chat/viewmodels/MessageInputViewModel.kt @@ -14,6 +14,7 @@ import androidx.lifecycle.LifecycleOwner import androidx.lifecycle.LiveData import androidx.lifecycle.MutableLiveData import androidx.lifecycle.ViewModel +import androidx.lifecycle.asLiveData import com.nextcloud.talk.chat.data.io.AudioFocusRequestManager import com.nextcloud.talk.chat.data.io.AudioRecorderManager import com.nextcloud.talk.chat.data.io.MediaPlayerManager @@ -26,6 +27,8 @@ import io.reactivex.Observer import io.reactivex.android.schedulers.AndroidSchedulers import io.reactivex.disposables.Disposable import io.reactivex.schedulers.Schedulers +import kotlinx.coroutines.flow.MutableStateFlow +import kotlinx.coroutines.flow.update import javax.inject.Inject class MessageInputViewModel @Inject constructor( @@ -51,7 +54,7 @@ class MessageInputViewModel @Inject constructor( ) private var isQueueing: Boolean = false - private val messageQueue: MutableList = mutableListOf() + private var messageQueue: MutableList = mutableListOf() override fun onResume(owner: LifecycleOwner) { super.onResume(owner) @@ -119,6 +122,10 @@ class MessageInputViewModel @Inject constructor( val isVoicePreviewPlaying: LiveData get() = _isVoicePreviewPlaying + private val _messageQueueSizeFlow = MutableStateFlow(messageQueue.size) + val messageQueueSizeFlow: LiveData + get() = _messageQueueSizeFlow.asLiveData() + @Suppress("LongParameterList") fun sendChatMessage( roomToken: String, @@ -132,6 +139,7 @@ class MessageInputViewModel @Inject constructor( if (isQueueing) { messageQueue.add(QueuedMessage(message, displayName, replyTo, sendWithoutNotification)) dataStore.saveMessageQueue(roomToken, messageQueue) + _messageQueueSizeFlow.update { messageQueue.size } return } @@ -259,4 +267,9 @@ class MessageInputViewModel @Inject constructor( fun switchToMessageQueue(shouldQueue: Boolean) { isQueueing = shouldQueue } + + fun restoreMessageQueue(roomToken: String) { + messageQueue = dataStore.getMessageQueue(roomToken) + _messageQueueSizeFlow.tryEmit(messageQueue.size) + } } 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 267c86eb44..b1b948bbd0 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 @@ -484,7 +484,7 @@ class AppPreferencesImpl(val context: Context) : AppPreferences { var queueStr = "" queue?.let { for (msg in queue) { - val msgStr = "[${msg.message},${msg.replyTo},${msg.displayName},${msg.sendWithoutNotification}]" + val msgStr = "${msg.message},${msg.replyTo},${msg.displayName},${msg.sendWithoutNotification}^" queueStr += msgStr } } @@ -500,18 +500,20 @@ class AppPreferencesImpl(val context: Context) : AppPreferences { val queue: MutableList = mutableListOf() if (queueStr.isEmpty()) return queue - for (msgStr in queueStr.split("]")) { + for (msgStr in queueStr.split("^")) { try { - val msgArray = msgStr.replace("[", "").split(",") - val message = msgArray[MESSAGE_INDEX] - val replyTo = msgArray[REPLY_TO_INDEX].toInt() - val displayName = msgArray[DISPLY_NAME_INDEX] - val silent = msgArray[SILENT_INDEX].toBoolean() - - val qMsg = MessageInputViewModel.QueuedMessage(message, displayName, replyTo, silent) - queue.add(qMsg) + if (msgStr.isNotEmpty()) { + val msgArray = msgStr.split(",") + val message = msgArray[MESSAGE_INDEX] + val replyTo = msgArray[REPLY_TO_INDEX].toInt() + val displayName = msgArray[DISPLY_NAME_INDEX] + val silent = msgArray[SILENT_INDEX].toBoolean() + + val qMsg = MessageInputViewModel.QueuedMessage(message, displayName, replyTo, silent) + queue.add(qMsg) + } } catch (e: IndexOutOfBoundsException) { - Log.e(TAG, "Message string: $msgStr\n $e") + Log.e(TAG, "Message string: $msgStr\n Queue String: $queueStr \n$e") } } diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 13ed2b442f..c23acb5fbe 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -802,6 +802,7 @@ How to translate with transifex: Show banned participants Bans list Connection lost - Sent messages are queued + Connection lost - %1$d are queued Connection established Message deleted by you Unban From dc32a4a2f11a060f15f632c94ced258f8999582d Mon Sep 17 00:00:00 2001 From: Marcel Hibbe Date: Fri, 13 Sep 2024 15:26:22 +0200 Subject: [PATCH 038/885] fix order of queued messages add delay between sending of queued messages to increase the chance they are received on server in the correct order. This is not the best solution though as it blocks the UI a bit so may have to be improved! Signed-off-by: Marcel Hibbe --- .../talk/chat/viewmodels/MessageInputViewModel.kt | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/app/src/main/java/com/nextcloud/talk/chat/viewmodels/MessageInputViewModel.kt b/app/src/main/java/com/nextcloud/talk/chat/viewmodels/MessageInputViewModel.kt index a3e641b52d..e74ebfc15b 100644 --- a/app/src/main/java/com/nextcloud/talk/chat/viewmodels/MessageInputViewModel.kt +++ b/app/src/main/java/com/nextcloud/talk/chat/viewmodels/MessageInputViewModel.kt @@ -29,6 +29,7 @@ import io.reactivex.disposables.Disposable import io.reactivex.schedulers.Schedulers import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.flow.update +import java.lang.Thread.sleep import javax.inject.Inject class MessageInputViewModel @Inject constructor( @@ -79,9 +80,6 @@ class MessageInputViewModel @Inject constructor( mediaPlayerManager.handleOnStop() } - companion object { - private val TAG = MessageInputViewModel::class.java.simpleName - } val getAudioFocusChange: LiveData get() = audioFocusRequestManager.getManagerState @@ -252,6 +250,7 @@ class MessageInputViewModel @Inject constructor( dataStore.saveMessageQueue(roomToken, null) // empties the queue while (queue.size > 0) { val msg = queue.removeFirst() + sleep(DELAY_BETWEEN_QUEUED_MESSAGES) sendChatMessage( roomToken, credentials, @@ -272,4 +271,9 @@ class MessageInputViewModel @Inject constructor( messageQueue = dataStore.getMessageQueue(roomToken) _messageQueueSizeFlow.tryEmit(messageQueue.size) } + + companion object { + private val TAG = MessageInputViewModel::class.java.simpleName + private const val DELAY_BETWEEN_QUEUED_MESSAGES: Long = 100 + } } From 016298e7af1f57854eabe39faabb3bf8b0ce7aec Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Fri, 13 Sep 2024 13:30:36 +0000 Subject: [PATCH 039/885] Update github/codeql-action action to v3.26.7 Signed-off-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- .github/workflows/codeql.yml | 4 ++-- .github/workflows/scorecard.yml | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/codeql.yml b/.github/workflows/codeql.yml index 32832b4f1c..3b92074ed0 100644 --- a/.github/workflows/codeql.yml +++ b/.github/workflows/codeql.yml @@ -39,7 +39,7 @@ jobs: with: swap-size-gb: 10 - name: Initialize CodeQL - uses: github/codeql-action/init@4dd16135b69a43b6c8efb853346f8437d92d3c93 # v3.26.6 + uses: github/codeql-action/init@8214744c546c1e5c8f03dde8fab3a7353211988d # v3.26.7 with: languages: ${{ matrix.language }} - name: Set up JDK 17 @@ -53,4 +53,4 @@ jobs: echo "org.gradle.jvmargs=-Xmx4g -XX:MaxMetaspaceSize=512m -XX:+HeapDumpOnOutOfMemoryError" > "$HOME/.gradle/gradle.properties" ./gradlew assembleDebug - name: Perform CodeQL Analysis - uses: github/codeql-action/analyze@4dd16135b69a43b6c8efb853346f8437d92d3c93 # v3.26.6 + uses: github/codeql-action/analyze@8214744c546c1e5c8f03dde8fab3a7353211988d # v3.26.7 diff --git a/.github/workflows/scorecard.yml b/.github/workflows/scorecard.yml index 26aff35d58..fa12539201 100644 --- a/.github/workflows/scorecard.yml +++ b/.github/workflows/scorecard.yml @@ -42,6 +42,6 @@ jobs: # Upload the results to GitHub's code scanning dashboard. - name: "Upload to code-scanning" - uses: github/codeql-action/upload-sarif@4dd16135b69a43b6c8efb853346f8437d92d3c93 # v3.26.6 + uses: github/codeql-action/upload-sarif@8214744c546c1e5c8f03dde8fab3a7353211988d # v3.26.7 with: sarif_file: results.sarif From 6706bc2790fb11b1f3c8d9dfd42e5f587d49b4e9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Calvi=C3=B1o=20S=C3=A1nchez?= Date: Wed, 28 Aug 2024 08:16:09 +0200 Subject: [PATCH 040/885] Store federation properties in signaling settings MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Starting with Talk 20 the signaling settings include a "federation" property that provide the values needed to join a federated room in the external signaling settings. The "federation" property is specific to each conversation, and it will be returned although empty for non-federated conversations. Signed-off-by: Daniel Calviño Sánchez --- .../nextcloud/talk/activities/CallActivity.kt | 2 ++ .../talk/models/ExternalSignalingServer.kt | 7 +++-- .../settings/FederationHelloAuthParams.kt | 24 +++++++++++++++ .../signaling/settings/FederationSettings.kt | 30 +++++++++++++++++++ .../signaling/settings/SignalingSettings.kt | 6 ++-- 5 files changed, 65 insertions(+), 4 deletions(-) create mode 100644 app/src/main/java/com/nextcloud/talk/models/json/signaling/settings/FederationHelloAuthParams.kt create mode 100644 app/src/main/java/com/nextcloud/talk/models/json/signaling/settings/FederationSettings.kt 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 f0b746be0f..21696470a4 100644 --- a/app/src/main/java/com/nextcloud/talk/activities/CallActivity.kt +++ b/app/src/main/java/com/nextcloud/talk/activities/CallActivity.kt @@ -1475,6 +1475,8 @@ class CallActivity : CallBaseActivity() { signalingSettingsOverall.ocs!!.settings!!.externalSignalingServer externalSignalingServer!!.externalSignalingTicket = signalingSettingsOverall.ocs!!.settings!!.externalSignalingTicket + externalSignalingServer!!.federation = + signalingSettingsOverall.ocs!!.settings!!.federation hasExternalSignalingServer = true } else { hasExternalSignalingServer = false diff --git a/app/src/main/java/com/nextcloud/talk/models/ExternalSignalingServer.kt b/app/src/main/java/com/nextcloud/talk/models/ExternalSignalingServer.kt index 9ed3f7b4de..b561f9bde6 100644 --- a/app/src/main/java/com/nextcloud/talk/models/ExternalSignalingServer.kt +++ b/app/src/main/java/com/nextcloud/talk/models/ExternalSignalingServer.kt @@ -10,6 +10,7 @@ package com.nextcloud.talk.models import android.os.Parcelable import com.bluelinelabs.logansquare.annotation.JsonField import com.bluelinelabs.logansquare.annotation.JsonObject +import com.nextcloud.talk.models.json.signaling.settings.FederationSettings import kotlinx.parcelize.Parcelize @Parcelize @@ -18,8 +19,10 @@ data class ExternalSignalingServer( @JsonField(name = ["externalSignalingServer"]) var externalSignalingServer: String? = null, @JsonField(name = ["externalSignalingTicket"]) - var externalSignalingTicket: String? = null + var externalSignalingTicket: String? = null, + @JsonField(name = ["federation"]) + var federation: FederationSettings? = null ) : Parcelable { // This constructor is added to work with the 'com.bluelinelabs.logansquare.annotation.JsonObject' - constructor() : this(null, null) + constructor() : this(null, null, null) } diff --git a/app/src/main/java/com/nextcloud/talk/models/json/signaling/settings/FederationHelloAuthParams.kt b/app/src/main/java/com/nextcloud/talk/models/json/signaling/settings/FederationHelloAuthParams.kt new file mode 100644 index 0000000000..396ab7f2d5 --- /dev/null +++ b/app/src/main/java/com/nextcloud/talk/models/json/signaling/settings/FederationHelloAuthParams.kt @@ -0,0 +1,24 @@ +/* + * Nextcloud Talk - Android Client + * + * SPDX-FileCopyrightText: 2024 Daniel Calviño Sánchez + * SPDX-License-Identifier: GPL-3.0-or-later + */ +package com.nextcloud.talk.models.json.signaling.settings + +import android.os.Parcelable +import com.bluelinelabs.logansquare.annotation.JsonField +import com.bluelinelabs.logansquare.annotation.JsonObject +import kotlinx.parcelize.Parcelize +import kotlinx.serialization.Serializable + +@Parcelize +@JsonObject +@Serializable +data class FederationHelloAuthParams( + @JsonField(name = ["token"]) + var token: String? = null, +) : Parcelable { + // This constructor is added to work with the 'com.bluelinelabs.logansquare.annotation.JsonObject' + constructor() : this(null) +} diff --git a/app/src/main/java/com/nextcloud/talk/models/json/signaling/settings/FederationSettings.kt b/app/src/main/java/com/nextcloud/talk/models/json/signaling/settings/FederationSettings.kt new file mode 100644 index 0000000000..27c29364c4 --- /dev/null +++ b/app/src/main/java/com/nextcloud/talk/models/json/signaling/settings/FederationSettings.kt @@ -0,0 +1,30 @@ +/* + * Nextcloud Talk - Android Client + * + * SPDX-FileCopyrightText: 2024 Daniel Calviño Sánchez + * SPDX-License-Identifier: GPL-3.0-or-later + */ +package com.nextcloud.talk.models.json.signaling.settings + +import android.os.Parcelable +import com.bluelinelabs.logansquare.annotation.JsonField +import com.bluelinelabs.logansquare.annotation.JsonObject +import kotlinx.parcelize.Parcelize +import kotlinx.serialization.Serializable + +@Parcelize +@JsonObject +@Serializable +data class FederationSettings( + @JsonField(name = ["server"]) + var server: String? = null, + @JsonField(name = ["nextcloudServer"]) + var nextcloudServer: String? = null, + @JsonField(name = ["helloAuthParams"]) + var helloAuthParams: FederationHelloAuthParams? = null, + @JsonField(name = ["roomId"]) + var roomId: String? = null +) : Parcelable { + // This constructor is added to work with the 'com.bluelinelabs.logansquare.annotation.JsonObject' + constructor() : this(null, null, null, null) +} diff --git a/app/src/main/java/com/nextcloud/talk/models/json/signaling/settings/SignalingSettings.kt b/app/src/main/java/com/nextcloud/talk/models/json/signaling/settings/SignalingSettings.kt index 55d50664ef..89dc837a5b 100644 --- a/app/src/main/java/com/nextcloud/talk/models/json/signaling/settings/SignalingSettings.kt +++ b/app/src/main/java/com/nextcloud/talk/models/json/signaling/settings/SignalingSettings.kt @@ -24,8 +24,10 @@ data class SignalingSettings( @JsonField(name = ["server"]) var externalSignalingServer: String? = null, @JsonField(name = ["ticket"]) - var externalSignalingTicket: String? = null + var externalSignalingTicket: String? = null, + @JsonField(name = ["federation"]) + var federation: FederationSettings? = null ) : Parcelable { // This constructor is added to work with the 'com.bluelinelabs.logansquare.annotation.JsonObject' - constructor() : this(null, null, null) + constructor() : this(null, null, null, null) } From f3c7913f16ad38b13c3bde152a68ac7a882cf613 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Calvi=C3=B1o=20S=C3=A1nchez?= Date: Wed, 28 Aug 2024 08:20:00 +0200 Subject: [PATCH 041/885] Get signaling settings by room when starting a call MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This is necessary to get the specific federation properties for the room. Signed-off-by: Daniel Calviño Sánchez --- .../main/java/com/nextcloud/talk/activities/CallActivity.kt | 2 +- app/src/main/java/com/nextcloud/talk/utils/ApiUtils.kt | 4 ++++ 2 files changed, 5 insertions(+), 1 deletion(-) 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 21696470a4..4ce448f33d 100644 --- a/app/src/main/java/com/nextcloud/talk/activities/CallActivity.kt +++ b/app/src/main/java/com/nextcloud/talk/activities/CallActivity.kt @@ -1453,7 +1453,7 @@ class CallActivity : CallBaseActivity() { private fun fetchSignalingSettings() { Log.d(TAG, "fetchSignalingSettings") val apiVersion = ApiUtils.getSignalingApiVersion(conversationUser, intArrayOf(ApiUtils.API_V3, 2, 1)) - ncApi!!.getSignalingSettings(credentials, ApiUtils.getUrlForSignalingSettings(apiVersion, baseUrl)) + ncApi!!.getSignalingSettings(credentials, ApiUtils.getUrlForSignalingSettings(apiVersion, baseUrl, roomToken!!)) .subscribeOn(Schedulers.io()) .retry(API_RETRIES) .observeOn(AndroidSchedulers.mainThread()) diff --git a/app/src/main/java/com/nextcloud/talk/utils/ApiUtils.kt b/app/src/main/java/com/nextcloud/talk/utils/ApiUtils.kt index c0168c4135..fb4e6a770c 100644 --- a/app/src/main/java/com/nextcloud/talk/utils/ApiUtils.kt +++ b/app/src/main/java/com/nextcloud/talk/utils/ApiUtils.kt @@ -283,6 +283,10 @@ object ApiUtils { return getUrlForSignaling(version, baseUrl) + "/settings" } + fun getUrlForSignalingSettings(version: Int, baseUrl: String?, token: String): String { + return getUrlForSignaling(version, baseUrl) + "/settings?token=" + token + } + fun getUrlForSignaling(version: Int, baseUrl: String?, token: String): String { return getUrlForSignaling(version, baseUrl) + "/" + token } From 86b06488c3a5092d557b5403a0ab33586cd8a926 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Calvi=C3=B1o=20S=C3=A1nchez?= Date: Wed, 28 Aug 2024 08:24:51 +0200 Subject: [PATCH 042/885] Provide federation values when joining a room in the external signaling MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The "federation" values are used by the external signaling server to establish a connection with the remote signaling server in a federated room. For now this is applied only in calls; when the room is joined in the chat view again after a call it will still join it in the old way, without federation properties, which will cause the connection with the remote signaling server to be closed. Signed-off-by: Daniel Calviño Sánchez --- .../com/nextcloud/talk/activities/CallActivity.kt | 3 ++- .../models/json/websocket/RoomWebSocketMessage.kt | 6 ++++-- .../talk/webrtc/WebSocketConnectionHelper.java | 13 ++++++++++++- .../com/nextcloud/talk/webrtc/WebSocketInstance.kt | 12 +++++++++--- 4 files changed, 27 insertions(+), 7 deletions(-) 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 4ce448f33d..a24264c0b9 100644 --- a/app/src/main/java/com/nextcloud/talk/activities/CallActivity.kt +++ b/app/src/main/java/com/nextcloud/talk/activities/CallActivity.kt @@ -1632,7 +1632,8 @@ class CallActivity : CallBaseActivity() { private fun callOrJoinRoomViaWebSocket() { if (hasExternalSignalingServer) { - webSocketClient!!.joinRoomWithRoomTokenAndSession(roomToken!!, callSession) + webSocketClient!!.joinRoomWithRoomTokenAndSession(roomToken!!, callSession, + externalSignalingServer!!.federation) } else { performCall() } diff --git a/app/src/main/java/com/nextcloud/talk/models/json/websocket/RoomWebSocketMessage.kt b/app/src/main/java/com/nextcloud/talk/models/json/websocket/RoomWebSocketMessage.kt index a836a3b8ef..ce3af7fa6d 100644 --- a/app/src/main/java/com/nextcloud/talk/models/json/websocket/RoomWebSocketMessage.kt +++ b/app/src/main/java/com/nextcloud/talk/models/json/websocket/RoomWebSocketMessage.kt @@ -20,8 +20,10 @@ class RoomWebSocketMessage( @JsonField(name = ["sessionid"]) var sessionId: String? = null, @JsonField(name = ["properties"]) - var roomPropertiesWebSocketMessage: RoomPropertiesWebSocketMessage? = null + var roomPropertiesWebSocketMessage: RoomPropertiesWebSocketMessage? = null, + @JsonField(name = ["federation"]) + var roomFederationWebSocketMessage: RoomFederationWebSocketMessage? = null ) : Parcelable { // This constructor is added to work with the 'com.bluelinelabs.logansquare.annotation.JsonObject' - constructor() : this(null, null, null) + constructor() : this(null, null, null, null) } diff --git a/app/src/main/java/com/nextcloud/talk/webrtc/WebSocketConnectionHelper.java b/app/src/main/java/com/nextcloud/talk/webrtc/WebSocketConnectionHelper.java index bd32ff6b88..a8ed4c6677 100644 --- a/app/src/main/java/com/nextcloud/talk/webrtc/WebSocketConnectionHelper.java +++ b/app/src/main/java/com/nextcloud/talk/webrtc/WebSocketConnectionHelper.java @@ -12,6 +12,7 @@ import com.nextcloud.talk.application.NextcloudTalkApplication; import com.nextcloud.talk.data.user.model.User; import com.nextcloud.talk.models.json.signaling.NCSignalingMessage; +import com.nextcloud.talk.models.json.signaling.settings.FederationSettings; import com.nextcloud.talk.models.json.websocket.ActorWebSocketMessage; import com.nextcloud.talk.models.json.websocket.AuthParametersWebSocketMessage; import com.nextcloud.talk.models.json.websocket.AuthWebSocketMessage; @@ -19,6 +20,7 @@ import com.nextcloud.talk.models.json.websocket.CallWebSocketMessage; import com.nextcloud.talk.models.json.websocket.HelloOverallWebSocketMessage; import com.nextcloud.talk.models.json.websocket.HelloWebSocketMessage; +import com.nextcloud.talk.models.json.websocket.RoomFederationWebSocketMessage; import com.nextcloud.talk.models.json.websocket.RoomOverallWebSocketMessage; import com.nextcloud.talk.models.json.websocket.RoomWebSocketMessage; import com.nextcloud.talk.utils.ApiUtils; @@ -128,12 +130,21 @@ HelloOverallWebSocketMessage getAssembledHelloModelForResume(String resumeId) { return helloOverallWebSocketMessage; } - RoomOverallWebSocketMessage getAssembledJoinOrLeaveRoomModel(String roomId, String sessionId) { + RoomOverallWebSocketMessage getAssembledJoinOrLeaveRoomModel(String roomId, String sessionId, + FederationSettings federation) { RoomOverallWebSocketMessage roomOverallWebSocketMessage = new RoomOverallWebSocketMessage(); roomOverallWebSocketMessage.setType("room"); RoomWebSocketMessage roomWebSocketMessage = new RoomWebSocketMessage(); roomWebSocketMessage.setRoomId(roomId); roomWebSocketMessage.setSessionId(sessionId); + if (federation != null) { + RoomFederationWebSocketMessage roomFederationWebSocketMessage = new RoomFederationWebSocketMessage(); + roomFederationWebSocketMessage.setSignaling(federation.getServer()); + roomFederationWebSocketMessage.setUrl(federation.getNextcloudServer() + "/ocs/v2.php/apps/spreed/api/v3/signaling/backend"); + roomFederationWebSocketMessage.setRoomid(federation.getRoomId()); + roomFederationWebSocketMessage.setToken(federation.getHelloAuthParams().getToken()); + roomWebSocketMessage.setRoomFederationWebSocketMessage(roomFederationWebSocketMessage); + } roomOverallWebSocketMessage.setRoomWebSocketMessage(roomWebSocketMessage); return roomOverallWebSocketMessage; } 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 451d4f5eab..98138b8735 100644 --- a/app/src/main/java/com/nextcloud/talk/webrtc/WebSocketInstance.kt +++ b/app/src/main/java/com/nextcloud/talk/webrtc/WebSocketInstance.kt @@ -20,6 +20,7 @@ import com.nextcloud.talk.events.WebSocketCommunicationEvent import com.nextcloud.talk.models.json.participants.Participant import com.nextcloud.talk.models.json.participants.Participant.ActorType import com.nextcloud.talk.models.json.signaling.NCSignalingMessage +import com.nextcloud.talk.models.json.signaling.settings.FederationSettings import com.nextcloud.talk.models.json.websocket.BaseWebSocketMessage import com.nextcloud.talk.models.json.websocket.ByeWebSocketMessage import com.nextcloud.talk.models.json.websocket.CallOverallWebSocketMessage @@ -75,6 +76,7 @@ class WebSocketInstance internal constructor( private val connectionUrl: String private var currentRoomToken: String? = null private var currentNormalBackendSession: String? = null + private var currentFederation: FederationSettings? = null private var reconnecting = false private val usersHashMap: HashMap private var messagesQueue: MutableList = ArrayList() @@ -367,24 +369,28 @@ class WebSocketInstance internal constructor( return hasMCU } - fun joinRoomWithRoomTokenAndSession(roomToken: String, normalBackendSession: String?) { + fun joinRoomWithRoomTokenAndSession(roomToken: String, normalBackendSession: String?, + federation: FederationSettings? = null) { Log.d(TAG, "joinRoomWithRoomTokenAndSession") Log.d(TAG, " roomToken: $roomToken") Log.d(TAG, " session: $normalBackendSession") try { val message = LoganSquare.serialize( - webSocketConnectionHelper.getAssembledJoinOrLeaveRoomModel(roomToken, normalBackendSession) + webSocketConnectionHelper.getAssembledJoinOrLeaveRoomModel(roomToken, normalBackendSession, federation) ) if (roomToken == "") { Log.d(TAG, "sending 'leave room' via websocket") currentNormalBackendSession = "" + currentFederation = null sendMessage(message) - } else if (roomToken == currentRoomToken && normalBackendSession == currentNormalBackendSession) { + } else if (roomToken == currentRoomToken && normalBackendSession == currentNormalBackendSession && + federation == currentFederation) { Log.d(TAG, "roomToken & session are unchanged. Joining locally without to send websocket message") sendRoomJoinedEvent() } else { Log.d(TAG, "Sending join room message via websocket") currentNormalBackendSession = normalBackendSession + currentFederation = federation sendMessage(message) } } catch (e: IOException) { From 3b7c5e1d27ec2a63b1e3549f9a7917ad0ae7a11c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Calvi=C3=B1o=20S=C3=A1nchez?= Date: Wed, 28 Aug 2024 08:30:38 +0200 Subject: [PATCH 043/885] Store actor data from signaling messages with participant updates MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Starting with Talk 20 the signaling messages that provide updates to the participants ("participants->update" in the external signaling server, "usersInRoom" in the internal signaling server) now include "actorType" and "actorId" properties for each participant. Signed-off-by: Daniel Calviño Sánchez --- .../nextcloud/talk/activities/CallActivity.kt | 4 ++++ .../talk/adapters/ParticipantDisplayItem.java | 7 +++++++ .../nextcloud/talk/call/CallParticipant.java | 5 +++++ .../talk/call/CallParticipantList.java | 2 ++ .../talk/call/CallParticipantModel.java | 16 +++++++++++++++ .../call/MutableCallParticipantModel.java | 7 +++++++ .../signaling/SignalingMessageReceiver.java | 15 ++++++++++++++ ...lParticipantListExternalSignalingTest.java | 4 ++++ ...lParticipantListInternalSignalingTest.java | 4 ++++ ...ingMessageReceiverParticipantListTest.java | 20 +++++++++++++------ 10 files changed, 78 insertions(+), 6 deletions(-) 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 a24264c0b9..98916daa96 100644 --- a/app/src/main/java/com/nextcloud/talk/activities/CallActivity.kt +++ b/app/src/main/java/com/nextcloud/talk/activities/CallActivity.kt @@ -2160,6 +2160,10 @@ class CallActivity : CallBaseActivity() { Log.d(TAG, " newSession joined: $sessionId") addCallParticipant(sessionId) + if (participant.actorType != null && participant.actorId != null) { + callParticipants[sessionId]!!.setActor(participant.actorType, participant.actorId) + } + val userId = participant.userId if (userId != null) { callParticipants[sessionId]!!.setUserId(userId) diff --git a/app/src/main/java/com/nextcloud/talk/adapters/ParticipantDisplayItem.java b/app/src/main/java/com/nextcloud/talk/adapters/ParticipantDisplayItem.java index 0eae25ac92..059e169de7 100644 --- a/app/src/main/java/com/nextcloud/talk/adapters/ParticipantDisplayItem.java +++ b/app/src/main/java/com/nextcloud/talk/adapters/ParticipantDisplayItem.java @@ -14,6 +14,7 @@ import com.nextcloud.talk.call.CallParticipantModel; import com.nextcloud.talk.call.RaisedHand; +import com.nextcloud.talk.models.json.participants.Participant; import com.nextcloud.talk.utils.ApiUtils; import org.webrtc.EglBase; @@ -38,6 +39,8 @@ public class ParticipantDisplayItem { private final CallParticipantModel callParticipantModel; + private Participant.ActorType actorType; + private String actorId; private String userId; private PeerConnection.IceConnectionState iceConnectionState; private String nick; @@ -82,6 +85,8 @@ public void destroy() { } private void updateFromModel() { + actorType = callParticipantModel.getActorType(); + actorId = callParticipantModel.getActorId(); userId = callParticipantModel.getUserId(); nick = callParticipantModel.getNick(); @@ -166,6 +171,8 @@ public void removeObserver(Observer observer) { public String toString() { return "ParticipantSession{" + "userId='" + userId + '\'' + + ", actorType='" + actorType + '\'' + + ", actorId='" + actorId + '\'' + ", session='" + session + '\'' + ", nick='" + nick + '\'' + ", urlForAvatar='" + urlForAvatar + '\'' + diff --git a/app/src/main/java/com/nextcloud/talk/call/CallParticipant.java b/app/src/main/java/com/nextcloud/talk/call/CallParticipant.java index 50c1ae6691..af1ac26728 100644 --- a/app/src/main/java/com/nextcloud/talk/call/CallParticipant.java +++ b/app/src/main/java/com/nextcloud/talk/call/CallParticipant.java @@ -6,6 +6,7 @@ */ package com.nextcloud.talk.call; +import com.nextcloud.talk.models.json.participants.Participant; import com.nextcloud.talk.signaling.SignalingMessageReceiver; import com.nextcloud.talk.webrtc.PeerConnectionWrapper; @@ -132,6 +133,10 @@ public CallParticipantModel getCallParticipantModel() { return callParticipantModel; } + public void setActor(Participant.ActorType actorType, String actorId) { + callParticipantModel.setActor(actorType, actorId); + } + public void setUserId(String userId) { callParticipantModel.setUserId(userId); } diff --git a/app/src/main/java/com/nextcloud/talk/call/CallParticipantList.java b/app/src/main/java/com/nextcloud/talk/call/CallParticipantList.java index 05712f5c06..921900e7ec 100644 --- a/app/src/main/java/com/nextcloud/talk/call/CallParticipantList.java +++ b/app/src/main/java/com/nextcloud/talk/call/CallParticipantList.java @@ -122,6 +122,8 @@ public void onAllParticipantsUpdate(long inCall) { private Participant copyParticipant(Participant participant) { Participant copiedParticipant = new Participant(); + copiedParticipant.setActorId(participant.getActorId()); + copiedParticipant.setActorType(participant.getActorType()); copiedParticipant.setInCall(participant.getInCall()); copiedParticipant.setInternal(participant.getInternal()); copiedParticipant.setLastPing(participant.getLastPing()); diff --git a/app/src/main/java/com/nextcloud/talk/call/CallParticipantModel.java b/app/src/main/java/com/nextcloud/talk/call/CallParticipantModel.java index 5a05cbc425..bd59a28e83 100644 --- a/app/src/main/java/com/nextcloud/talk/call/CallParticipantModel.java +++ b/app/src/main/java/com/nextcloud/talk/call/CallParticipantModel.java @@ -8,6 +8,8 @@ import android.os.Handler; +import com.nextcloud.talk.models.json.participants.Participant; + import org.webrtc.MediaStream; import org.webrtc.PeerConnection; @@ -25,6 +27,8 @@ * * Audio and video in screen shares, on the other hand, are always seen as available. * + * Actor type and actor id will be set only in Talk >= 20. + * * Clients of the model can observe it with CallParticipantModel.Observer to be notified when any value changes. * Getters called after receiving a notification are guaranteed to provide at least the value that triggered the * notification, but it may return even a more up to date one (so getting the value again on the following @@ -39,6 +43,8 @@ public class CallParticipantModel { protected final String sessionId; + protected Data actorType; + protected Data actorId; protected Data userId; protected Data nick; @@ -81,6 +87,8 @@ public void setValue(T value) { public CallParticipantModel(String sessionId) { this.sessionId = sessionId; + this.actorType = new Data<>(); + this.actorId = new Data<>(); this.userId = new Data<>(); this.nick = new Data<>(); @@ -101,6 +109,14 @@ public String getSessionId() { return sessionId; } + public Participant.ActorType getActorType() { + return actorType.getValue(); + } + + public String getActorId() { + return actorId.getValue(); + } + public String getUserId() { return userId.getValue(); } diff --git a/app/src/main/java/com/nextcloud/talk/call/MutableCallParticipantModel.java b/app/src/main/java/com/nextcloud/talk/call/MutableCallParticipantModel.java index f1288a8a03..221b383521 100644 --- a/app/src/main/java/com/nextcloud/talk/call/MutableCallParticipantModel.java +++ b/app/src/main/java/com/nextcloud/talk/call/MutableCallParticipantModel.java @@ -6,6 +6,8 @@ */ package com.nextcloud.talk.call; +import com.nextcloud.talk.models.json.participants.Participant; + import org.webrtc.MediaStream; import org.webrtc.PeerConnection; @@ -20,6 +22,11 @@ public MutableCallParticipantModel(String sessionId) { super(sessionId); } + public void setActor(Participant.ActorType actorType, String actorId) { + this.actorType.setValue(actorType); + this.actorId.setValue(actorId); + } + public void setUserId(String userId) { this.userId.setValue(userId); } diff --git a/app/src/main/java/com/nextcloud/talk/signaling/SignalingMessageReceiver.java b/app/src/main/java/com/nextcloud/talk/signaling/SignalingMessageReceiver.java index 4abfe757be..90f658f928 100644 --- a/app/src/main/java/com/nextcloud/talk/signaling/SignalingMessageReceiver.java +++ b/app/src/main/java/com/nextcloud/talk/signaling/SignalingMessageReceiver.java @@ -6,6 +6,7 @@ */ package com.nextcloud.talk.signaling; +import com.nextcloud.talk.models.json.converters.EnumActorTypeConverter; import com.nextcloud.talk.models.json.converters.EnumParticipantTypeConverter; import com.nextcloud.talk.models.json.participants.Participant; import com.nextcloud.talk.models.json.signaling.NCIceCandidate; @@ -38,6 +39,8 @@ */ public abstract class SignalingMessageReceiver { + private final EnumActorTypeConverter enumActorTypeConverter = new EnumActorTypeConverter(); + private final ParticipantListMessageNotifier participantListMessageNotifier = new ParticipantListMessageNotifier(); private final LocalParticipantMessageNotifier localParticipantMessageNotifier = new LocalParticipantMessageNotifier(); @@ -398,6 +401,8 @@ private void processParticipantsUpdate(Map updateMap) { // "nextcloudSessionId": #STRING#, // Optional // "internal": #BOOLEAN#, // Optional // "participantPermissions": #INTEGER#, // Talk >= 13 + // "actorType": #STRING#, // Talk >= 20 + // "actorId": #STRING#, // Talk >= 20 // }, // ... // ], @@ -447,6 +452,8 @@ protected void processUsersInRoom(List> users) { // "sessionId": #STRING#, // "userId": #STRING#, // Always included, although it can be empty // "participantPermissions": #INTEGER#, // Talk >= 13 + // "actorType": #STRING#, // Talk >= 20 + // "actorId": #STRING#, // Talk >= 20 // }, // ... // ], @@ -492,6 +499,14 @@ private Participant getParticipantFromMessageMap(Map participant participant.setInternal(Boolean.TRUE); } + if (participantMap.get("actorType") != null && !participantMap.get("actorType").toString().isEmpty()) { + participant.setActorType(enumActorTypeConverter.getFromString(participantMap.get("actorType").toString())); + } + + if (participantMap.get("actorId") != null && !participantMap.get("actorId").toString().isEmpty()) { + participant.setActorId(participantMap.get("actorId").toString()); + } + // Only in external signaling messages if (participantMap.get("participantType") != null) { int participantTypeInt = Integer.parseInt(participantMap.get("participantType").toString()); diff --git a/app/src/test/java/com/nextcloud/talk/call/CallParticipantListExternalSignalingTest.java b/app/src/test/java/com/nextcloud/talk/call/CallParticipantListExternalSignalingTest.java index 51a1d20c97..02b6dc7aa7 100644 --- a/app/src/test/java/com/nextcloud/talk/call/CallParticipantListExternalSignalingTest.java +++ b/app/src/test/java/com/nextcloud/talk/call/CallParticipantListExternalSignalingTest.java @@ -71,6 +71,8 @@ private Participant newUser(long inCall, long lastPing, String sessionId, Partic participant.setSessionId(sessionId); participant.setType(type); participant.setUserId(userId); + participant.setActorType(Participant.ActorType.USERS); + participant.setActorId(userId); return participant; } @@ -81,6 +83,8 @@ private Participant newGuest(long inCall, long lastPing, String sessionId, Parti participant.setLastPing(lastPing); participant.setSessionId(sessionId); participant.setType(type); + participant.setActorType(Participant.ActorType.GUESTS); + participant.setActorId("sha1-" + sessionId); return participant; } diff --git a/app/src/test/java/com/nextcloud/talk/call/CallParticipantListInternalSignalingTest.java b/app/src/test/java/com/nextcloud/talk/call/CallParticipantListInternalSignalingTest.java index 9ec9ed776a..a93325fce9 100644 --- a/app/src/test/java/com/nextcloud/talk/call/CallParticipantListInternalSignalingTest.java +++ b/app/src/test/java/com/nextcloud/talk/call/CallParticipantListInternalSignalingTest.java @@ -61,6 +61,8 @@ private Participant newUser(long inCall, long lastPing, String sessionId, String participant.setLastPing(lastPing); participant.setSessionId(sessionId); participant.setUserId(userId); + participant.setActorType(Participant.ActorType.USERS); + participant.setActorId(userId); return participant; } @@ -70,6 +72,8 @@ private Participant newGuest(long inCall, long lastPing, String sessionId) { participant.setInCall(inCall); participant.setLastPing(lastPing); participant.setSessionId(sessionId); + participant.setActorType(Participant.ActorType.GUESTS); + participant.setActorId("sha1-" + sessionId); return participant; } diff --git a/app/src/test/java/com/nextcloud/talk/signaling/SignalingMessageReceiverParticipantListTest.java b/app/src/test/java/com/nextcloud/talk/signaling/SignalingMessageReceiverParticipantListTest.java index 5ac43b06d7..fa1e14220d 100644 --- a/app/src/test/java/com/nextcloud/talk/signaling/SignalingMessageReceiverParticipantListTest.java +++ b/app/src/test/java/com/nextcloud/talk/signaling/SignalingMessageReceiverParticipantListTest.java @@ -58,10 +58,12 @@ public void testInternalSignalingParticipantListMessageUsersInRoom() { user1.put("roomId", 108); user1.put("sessionId", "theSessionId1"); user1.put("userId", "theUserId"); - // If "participantPermissions" is set in any of the participants all the other participants in the message - // would have it too. But for test simplicity, and as it is not relevant for the processing, in this test it - // is included only in one of the participants. + // If any of the following properties is set in any of the participants all the other participants in the + // message would have it too. But for test simplicity, and as it is not relevant for the processing, in this + // test they are included only in one of the participants. user1.put("participantPermissions", 42); + user1.put("actorType", "federated_users"); + user1.put("actorId", "theActorId"); users.add(user1); Map user2 = new HashMap<>(); user2.put("inCall", 0); @@ -78,6 +80,8 @@ public void testInternalSignalingParticipantListMessageUsersInRoom() { expectedParticipant1.setLastPing(4815); expectedParticipant1.setSessionId("theSessionId1"); expectedParticipant1.setUserId("theUserId"); + expectedParticipant1.setActorType(Participant.ActorType.FEDERATED); + expectedParticipant1.setActorId("theActorId"); expectedParticipantList.add(expectedParticipant1); Participant expectedParticipant2 = new Participant(); @@ -266,11 +270,13 @@ public void testExternalSignalingParticipantListMessageParticipantsUpdate() { user1.put("sessionId", "theSessionId1"); user1.put("participantType", 3); user1.put("userId", "theUserId"); - // If "nextcloudSessionId" or "participantPermissions" is set in any of the participants all the other - // participants in the message would have them too. But for test simplicity, and as it is not relevant for - // the processing, in this test they are included only in one of the participants. + // If any of the following properties is set in any of the participants all the other participants in the + // message would have it too. But for test simplicity, and as it is not relevant for the processing, in this + // test they are included only in one of the participants. user1.put("nextcloudSessionId", "theNextcloudSessionId"); user1.put("participantPermissions", 42); + user1.put("actorType", "federated_users"); + user1.put("actorId", "theActorId"); users.add(user1); Map user2 = new HashMap<>(); user2.put("inCall", 0); @@ -289,6 +295,8 @@ public void testExternalSignalingParticipantListMessageParticipantsUpdate() { expectedParticipant1.setSessionId("theSessionId1"); expectedParticipant1.setType(Participant.ParticipantType.USER); expectedParticipant1.setUserId("theUserId"); + expectedParticipant1.setActorType(Participant.ActorType.FEDERATED); + expectedParticipant1.setActorId("theActorId"); expectedParticipantList.add(expectedParticipant1); Participant expectedParticipant2 = new Participant(); From 0ff783ef0b0ba664549334f21dc60b779ad0b509 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Calvi=C3=B1o=20S=C3=A1nchez?= Date: Wed, 28 Aug 2024 08:32:37 +0200 Subject: [PATCH 044/885] Show proper avatar for federated users in calls MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Daniel Calviño Sánchez --- .../nextcloud/talk/activities/CallActivity.kt | 2 ++ .../talk/adapters/ParticipantDisplayItem.java | 19 ++++++++++++++++--- 2 files changed, 18 insertions(+), 3 deletions(-) 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 98916daa96..0f3db1b274 100644 --- a/app/src/main/java/com/nextcloud/talk/activities/CallActivity.kt +++ b/app/src/main/java/com/nextcloud/talk/activities/CallActivity.kt @@ -2517,10 +2517,12 @@ class CallActivity : CallBaseActivity() { } val defaultGuestNick = resources.getString(R.string.nc_nick_guest) val participantDisplayItem = ParticipantDisplayItem( + context, baseUrl, defaultGuestNick, rootEglBase, videoStreamType, + roomToken, callParticipantModel ) val sessionId = callParticipantModel.sessionId diff --git a/app/src/main/java/com/nextcloud/talk/adapters/ParticipantDisplayItem.java b/app/src/main/java/com/nextcloud/talk/adapters/ParticipantDisplayItem.java index 059e169de7..b4bc87c568 100644 --- a/app/src/main/java/com/nextcloud/talk/adapters/ParticipantDisplayItem.java +++ b/app/src/main/java/com/nextcloud/talk/adapters/ParticipantDisplayItem.java @@ -8,6 +8,7 @@ */ package com.nextcloud.talk.adapters; +import android.content.Context; import android.os.Handler; import android.os.Looper; import android.text.TextUtils; @@ -16,6 +17,7 @@ import com.nextcloud.talk.call.RaisedHand; import com.nextcloud.talk.models.json.participants.Participant; import com.nextcloud.talk.utils.ApiUtils; +import com.nextcloud.talk.utils.DisplayUtils; import org.webrtc.EglBase; import org.webrtc.MediaStream; @@ -30,6 +32,8 @@ public class ParticipantDisplayItem { private final ParticipantDisplayItemNotifier participantDisplayItemNotifier = new ParticipantDisplayItemNotifier(); + private final Context context; + private final String baseUrl; private final String defaultGuestNick; private final EglBase rootEglBase; @@ -37,6 +41,8 @@ public class ParticipantDisplayItem { private final String session; private final String streamType; + private final String roomToken; + private final CallParticipantModel callParticipantModel; private Participant.ActorType actorType; @@ -65,8 +71,10 @@ public void onReaction(String reaction) { } }; - public ParticipantDisplayItem(String baseUrl, String defaultGuestNick, EglBase rootEglBase, String streamType, - CallParticipantModel callParticipantModel) { + public ParticipantDisplayItem(Context context, String baseUrl, String defaultGuestNick, EglBase rootEglBase, + String streamType, String roomToken, CallParticipantModel callParticipantModel) { + this.context = context; + this.baseUrl = baseUrl; this.defaultGuestNick = defaultGuestNick; this.rootEglBase = rootEglBase; @@ -74,6 +82,8 @@ public ParticipantDisplayItem(String baseUrl, String defaultGuestNick, EglBase r this.session = callParticipantModel.getSessionId(); this.streamType = streamType; + this.roomToken = roomToken; + this.callParticipantModel = callParticipantModel; this.callParticipantModel.addObserver(callParticipantModelObserver, handler); @@ -112,7 +122,10 @@ private void updateFromModel() { } private void updateUrlForAvatar() { - if (!TextUtils.isEmpty(userId)) { + if (actorType == Participant.ActorType.FEDERATED) { + int darkTheme = DisplayUtils.INSTANCE.isDarkModeOn(context) ? 1 : 0; + urlForAvatar = ApiUtils.getUrlForFederatedAvatar(baseUrl, roomToken, actorId, darkTheme, true); + } else if (!TextUtils.isEmpty(userId)) { urlForAvatar = ApiUtils.getUrlForAvatar(baseUrl, userId, true); } else { urlForAvatar = ApiUtils.getUrlForGuestAvatar(baseUrl, getNick(), true); From 166107d7d231bf734a7f8c66ec0235063657e152 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Calvi=C3=B1o=20S=C3=A1nchez?= Date: Wed, 28 Aug 2024 13:26:35 +0200 Subject: [PATCH 045/885] fixup! Provide federation values when joining a room in the external signaling MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Daniel Calviño Sánchez --- .../RoomFederationWebSocketMessage.kt | 28 +++++++++++++++++++ 1 file changed, 28 insertions(+) create mode 100644 app/src/main/java/com/nextcloud/talk/models/json/websocket/RoomFederationWebSocketMessage.kt diff --git a/app/src/main/java/com/nextcloud/talk/models/json/websocket/RoomFederationWebSocketMessage.kt b/app/src/main/java/com/nextcloud/talk/models/json/websocket/RoomFederationWebSocketMessage.kt new file mode 100644 index 0000000000..e5352bd45e --- /dev/null +++ b/app/src/main/java/com/nextcloud/talk/models/json/websocket/RoomFederationWebSocketMessage.kt @@ -0,0 +1,28 @@ +/* + * Nextcloud Talk - Android Client + * + * SPDX-FileCopyrightText: 2024 Daniel Calviño Sánchez + * SPDX-License-Identifier: GPL-3.0-or-later + */ +package com.nextcloud.talk.models.json.websocket + +import android.os.Parcelable +import com.bluelinelabs.logansquare.annotation.JsonField +import com.bluelinelabs.logansquare.annotation.JsonObject +import kotlinx.parcelize.Parcelize + +@Parcelize +@JsonObject +class RoomFederationWebSocketMessage( + @JsonField(name = ["signaling"]) + var signaling: String? = null, + @JsonField(name = ["url"]) + var url: String? = null, + @JsonField(name = ["roomid"]) + var roomid: String? = null, + @JsonField(name = ["token"]) + var token: String? = null +) : Parcelable { + // This constructor is added to work with the 'com.bluelinelabs.logansquare.annotation.JsonObject' + constructor() : this(null, null, null, null) +} From 18a0394d3b98958f68c872a5db17679297111bef Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Calvi=C3=B1o=20S=C3=A1nchez?= Date: Fri, 13 Sep 2024 12:52:19 +0200 Subject: [PATCH 046/885] fixup! Provide federation values when joining a room in the external signaling MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Daniel Calviño Sánchez --- .../java/com/nextcloud/talk/activities/CallActivity.kt | 5 +++-- .../com/nextcloud/talk/webrtc/WebSocketInstance.kt | 10 +++++++--- 2 files changed, 10 insertions(+), 5 deletions(-) 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 0f3db1b274..706a635e20 100644 --- a/app/src/main/java/com/nextcloud/talk/activities/CallActivity.kt +++ b/app/src/main/java/com/nextcloud/talk/activities/CallActivity.kt @@ -1632,8 +1632,9 @@ class CallActivity : CallBaseActivity() { private fun callOrJoinRoomViaWebSocket() { if (hasExternalSignalingServer) { - webSocketClient!!.joinRoomWithRoomTokenAndSession(roomToken!!, callSession, - externalSignalingServer!!.federation) + webSocketClient!!.joinRoomWithRoomTokenAndSession( + roomToken!!, callSession, externalSignalingServer!!.federation + ) } else { performCall() } 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 98138b8735..fc5feb6bad 100644 --- a/app/src/main/java/com/nextcloud/talk/webrtc/WebSocketInstance.kt +++ b/app/src/main/java/com/nextcloud/talk/webrtc/WebSocketInstance.kt @@ -369,8 +369,11 @@ class WebSocketInstance internal constructor( return hasMCU } - fun joinRoomWithRoomTokenAndSession(roomToken: String, normalBackendSession: String?, - federation: FederationSettings? = null) { + fun joinRoomWithRoomTokenAndSession( + roomToken: String, + normalBackendSession: String?, + federation: FederationSettings? = null + ) { Log.d(TAG, "joinRoomWithRoomTokenAndSession") Log.d(TAG, " roomToken: $roomToken") Log.d(TAG, " session: $normalBackendSession") @@ -384,7 +387,8 @@ class WebSocketInstance internal constructor( currentFederation = null sendMessage(message) } else if (roomToken == currentRoomToken && normalBackendSession == currentNormalBackendSession && - federation == currentFederation) { + federation?.roomId == currentFederation?.roomId && federation?.nextcloudServer == federation?.nextcloudServer + ) { Log.d(TAG, "roomToken & session are unchanged. Joining locally without to send websocket message") sendRoomJoinedEvent() } else { From c7af117f4e024749870f3cdc82d9fe98cb4e07dc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Calvi=C3=B1o=20S=C3=A1nchez?= Date: Fri, 13 Sep 2024 12:54:40 +0200 Subject: [PATCH 047/885] fixup! Store federation properties in signaling settings MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Daniel Calviño Sánchez --- .../models/json/signaling/settings/FederationHelloAuthParams.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/src/main/java/com/nextcloud/talk/models/json/signaling/settings/FederationHelloAuthParams.kt b/app/src/main/java/com/nextcloud/talk/models/json/signaling/settings/FederationHelloAuthParams.kt index 396ab7f2d5..290a8f8ede 100644 --- a/app/src/main/java/com/nextcloud/talk/models/json/signaling/settings/FederationHelloAuthParams.kt +++ b/app/src/main/java/com/nextcloud/talk/models/json/signaling/settings/FederationHelloAuthParams.kt @@ -17,7 +17,7 @@ import kotlinx.serialization.Serializable @Serializable data class FederationHelloAuthParams( @JsonField(name = ["token"]) - var token: String? = null, + var token: String? = null ) : Parcelable { // This constructor is added to work with the 'com.bluelinelabs.logansquare.annotation.JsonObject' constructor() : this(null) From 148dedbc6cb803ad210080feed2c90ad7047e19a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Calvi=C3=B1o=20S=C3=A1nchez?= Date: Fri, 13 Sep 2024 12:55:50 +0200 Subject: [PATCH 048/885] fixup! Provide federation values when joining a room in the external signaling MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Daniel Calviño Sánchez --- .../nextcloud/talk/webrtc/WebSocketConnectionHelper.java | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/app/src/main/java/com/nextcloud/talk/webrtc/WebSocketConnectionHelper.java b/app/src/main/java/com/nextcloud/talk/webrtc/WebSocketConnectionHelper.java index a8ed4c6677..57452c0943 100644 --- a/app/src/main/java/com/nextcloud/talk/webrtc/WebSocketConnectionHelper.java +++ b/app/src/main/java/com/nextcloud/talk/webrtc/WebSocketConnectionHelper.java @@ -138,11 +138,15 @@ RoomOverallWebSocketMessage getAssembledJoinOrLeaveRoomModel(String roomId, Stri roomWebSocketMessage.setRoomId(roomId); roomWebSocketMessage.setSessionId(sessionId); if (federation != null) { + String federationAuthToken = null; + if (federation.getHelloAuthParams() != null) { + federationAuthToken = federation.getHelloAuthParams().getToken(); + } RoomFederationWebSocketMessage roomFederationWebSocketMessage = new RoomFederationWebSocketMessage(); roomFederationWebSocketMessage.setSignaling(federation.getServer()); roomFederationWebSocketMessage.setUrl(federation.getNextcloudServer() + "/ocs/v2.php/apps/spreed/api/v3/signaling/backend"); roomFederationWebSocketMessage.setRoomid(federation.getRoomId()); - roomFederationWebSocketMessage.setToken(federation.getHelloAuthParams().getToken()); + roomFederationWebSocketMessage.setToken(federationAuthToken); roomWebSocketMessage.setRoomFederationWebSocketMessage(roomFederationWebSocketMessage); } roomOverallWebSocketMessage.setRoomWebSocketMessage(roomWebSocketMessage); From 4cea7b239059e167b5ddebfd79cd53e832329171 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Calvi=C3=B1o=20S=C3=A1nchez?= Date: Fri, 13 Sep 2024 12:58:07 +0200 Subject: [PATCH 049/885] Provide federation values to external signaling server in chat MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Otherwise the WebSocket configuration and session clashes with the one from the CallActivity, which already uses the federated settings. Signed-off-by: Daniel Calviño Sánchez --- .../com/nextcloud/talk/chat/ChatActivity.kt | 59 +++++++++++++++++-- 1 file changed, 54 insertions(+), 5 deletions(-) diff --git a/app/src/main/java/com/nextcloud/talk/chat/ChatActivity.kt b/app/src/main/java/com/nextcloud/talk/chat/ChatActivity.kt index c41ac3c231..f35c205e28 100644 --- a/app/src/main/java/com/nextcloud/talk/chat/ChatActivity.kt +++ b/app/src/main/java/com/nextcloud/talk/chat/ChatActivity.kt @@ -120,10 +120,12 @@ import com.nextcloud.talk.jobs.ShareOperationWorker import com.nextcloud.talk.jobs.UploadAndShareFilesWorker import com.nextcloud.talk.location.LocationPickerActivity import com.nextcloud.talk.messagesearch.MessageSearchActivity +import com.nextcloud.talk.models.ExternalSignalingServer import com.nextcloud.talk.models.domain.ConversationModel import com.nextcloud.talk.models.json.capabilities.SpreedCapability import com.nextcloud.talk.models.json.chat.ReadStatus import com.nextcloud.talk.models.json.conversations.ConversationEnums +import com.nextcloud.talk.models.json.signaling.settings.SignalingSettingsOverall import com.nextcloud.talk.polls.ui.PollCreateDialogFragment import com.nextcloud.talk.remotefilebrowser.activities.RemoteFileBrowserActivity import com.nextcloud.talk.shareditems.activities.SharedItemsActivity @@ -177,6 +179,8 @@ import com.stfalcon.chatkit.messages.MessageHolders import com.stfalcon.chatkit.messages.MessageHolders.ContentChecker import com.stfalcon.chatkit.messages.MessagesListAdapter import com.stfalcon.chatkit.utils.DateFormatter +import io.reactivex.Observer +import io.reactivex.disposables.Disposable import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.flow.collect @@ -302,6 +306,7 @@ class ChatActivity : var webSocketInstance: WebSocketInstance? = null var signalingMessageSender: SignalingMessageSender? = null + var externalSignalingServer: ExternalSignalingServer? = null var getRoomInfoTimerHandler: Handler? = null @@ -631,10 +636,12 @@ class ChatActivity : logConversationInfos("joinRoomWithPassword#onNext") + setupWebsocket() if (webSocketInstance != null) { webSocketInstance?.joinRoomWithRoomTokenAndSession( roomToken, - sessionIdAfterRoomJoined + sessionIdAfterRoomJoined, + externalSignalingServer?.federation ) } if (startCallFromNotification != null && startCallFromNotification) { @@ -952,7 +959,6 @@ class ChatActivity : pullChatMessagesPending = false - setupWebsocket() webSocketInstance?.getSignalingMessageReceiver()?.addListener(localParticipantMessageListener) webSocketInstance?.getSignalingMessageReceiver()?.addListener(conversationMessageListener) @@ -2391,10 +2397,12 @@ class ChatActivity : } else { Log.d(TAG, "sessionID was valid -> skip joinRoom") + setupWebsocket() if (webSocketInstance != null) { webSocketInstance?.joinRoomWithRoomTokenAndSession( roomToken, - sessionIdAfterRoomJoined + sessionIdAfterRoomJoined, + externalSignalingServer?.federation ) } } @@ -2423,16 +2431,57 @@ class ChatActivity : } private fun setupWebsocket() { - if (conversationUser == null) { + if (currentConversation == null || conversationUser == null) { return } - webSocketInstance = WebSocketConnectionHelper.getWebSocketInstanceForUser(conversationUser!!) + + if (currentConversation!!.remoteServer != null) { + val apiVersion = ApiUtils.getSignalingApiVersion(conversationUser!!, intArrayOf(ApiUtils.API_V3, 2, 1)) + ncApi!!.getSignalingSettings(credentials, ApiUtils.getUrlForSignalingSettings(apiVersion, conversationUser!!.baseUrl, + roomToken!!)).blockingSubscribe(object : Observer { + override fun onSubscribe(d: Disposable) { + // unused atm + } + + override fun onNext(signalingSettingsOverall: SignalingSettingsOverall) { + if (signalingSettingsOverall.ocs!!.settings!!.externalSignalingServer == null) { + return + } + + externalSignalingServer = ExternalSignalingServer() + externalSignalingServer!!.externalSignalingServer = signalingSettingsOverall.ocs!!.settings!! + .externalSignalingServer + externalSignalingServer!!.externalSignalingTicket = signalingSettingsOverall.ocs!!.settings!! + .externalSignalingTicket + externalSignalingServer!!.federation = signalingSettingsOverall.ocs!!.settings!!.federation + + webSocketInstance = WebSocketConnectionHelper.getExternalSignalingInstanceForServer( + externalSignalingServer!!.externalSignalingServer, + conversationUser, + externalSignalingServer!!.externalSignalingTicket, + TextUtils.isEmpty(credentials) + ) + } + + override fun onError(e: Throwable) { + Log.e(CallActivity.TAG, e.message, e) + } + + override fun onComplete() { + // unused atm + } + }) + } else { + webSocketInstance = WebSocketConnectionHelper.getWebSocketInstanceForUser(conversationUser!!) + } if (webSocketInstance == null) { Log.d(TAG, "webSocketInstance not set up. This should only happen when not using the HPB") } signalingMessageSender = webSocketInstance?.signalingMessageSender + webSocketInstance?.getSignalingMessageReceiver()?.addListener(localParticipantMessageListener) + webSocketInstance?.getSignalingMessageReceiver()?.addListener(conversationMessageListener) } private fun processCallStartedMessages(chatMessageList: List) { From 033e3e86c181dfadf5d13132d0205fb581068ee5 Mon Sep 17 00:00:00 2001 From: Marcel Hibbe Date: Fri, 13 Sep 2024 16:56:46 +0200 Subject: [PATCH 050/885] reformat code Signed-off-by: Marcel Hibbe --- .../java/com/nextcloud/talk/activities/CallActivity.kt | 4 ++-- app/src/main/java/com/nextcloud/talk/chat/ChatActivity.kt | 8 +++++--- .../java/com/nextcloud/talk/webrtc/WebSocketInstance.kt | 8 ++++++-- 3 files changed, 13 insertions(+), 7 deletions(-) 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 706a635e20..90e3689f1a 100644 --- a/app/src/main/java/com/nextcloud/talk/activities/CallActivity.kt +++ b/app/src/main/java/com/nextcloud/talk/activities/CallActivity.kt @@ -1633,8 +1633,8 @@ class CallActivity : CallBaseActivity() { private fun callOrJoinRoomViaWebSocket() { if (hasExternalSignalingServer) { webSocketClient!!.joinRoomWithRoomTokenAndSession( - roomToken!!, callSession, externalSignalingServer!!.federation - ) + roomToken!!, callSession, externalSignalingServer!!.federation + ) } else { performCall() } diff --git a/app/src/main/java/com/nextcloud/talk/chat/ChatActivity.kt b/app/src/main/java/com/nextcloud/talk/chat/ChatActivity.kt index f35c205e28..ae0cc210e5 100644 --- a/app/src/main/java/com/nextcloud/talk/chat/ChatActivity.kt +++ b/app/src/main/java/com/nextcloud/talk/chat/ChatActivity.kt @@ -2437,8 +2437,10 @@ class ChatActivity : if (currentConversation!!.remoteServer != null) { val apiVersion = ApiUtils.getSignalingApiVersion(conversationUser!!, intArrayOf(ApiUtils.API_V3, 2, 1)) - ncApi!!.getSignalingSettings(credentials, ApiUtils.getUrlForSignalingSettings(apiVersion, conversationUser!!.baseUrl, - roomToken!!)).blockingSubscribe(object : Observer { + ncApi!!.getSignalingSettings( + credentials, + ApiUtils.getUrlForSignalingSettings(apiVersion, conversationUser!!.baseUrl, roomToken!!) + ).blockingSubscribe(object : Observer { override fun onSubscribe(d: Disposable) { // unused atm } @@ -3239,7 +3241,7 @@ class ChatActivity : val lon = data["longitude"]!! metaData = "{\"type\":\"geo-location\",\"id\":\"geo:$lat,$lon\",\"latitude\":\"$lat\"," + - "\"longitude\":\"$lon\",\"name\":\"$name\"}" + "\"longitude\":\"$lon\",\"name\":\"$name\"}" } when (type) { 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 fc5feb6bad..10f338b1a2 100644 --- a/app/src/main/java/com/nextcloud/talk/webrtc/WebSocketInstance.kt +++ b/app/src/main/java/com/nextcloud/talk/webrtc/WebSocketInstance.kt @@ -369,6 +369,7 @@ class WebSocketInstance internal constructor( return hasMCU } + @Suppress("Detekt.ComplexMethod") fun joinRoomWithRoomTokenAndSession( roomToken: String, normalBackendSession: String?, @@ -386,8 +387,11 @@ class WebSocketInstance internal constructor( currentNormalBackendSession = "" currentFederation = null sendMessage(message) - } else if (roomToken == currentRoomToken && normalBackendSession == currentNormalBackendSession && - federation?.roomId == currentFederation?.roomId && federation?.nextcloudServer == federation?.nextcloudServer + } else if ( + roomToken == currentRoomToken && + normalBackendSession == currentNormalBackendSession && + federation?.roomId == currentFederation?.roomId && + federation?.nextcloudServer == federation?.nextcloudServer ) { Log.d(TAG, "roomToken & session are unchanged. Joining locally without to send websocket message") sendRoomJoinedEvent() From cc83e90d7f0c7c0dab5118b9907a179b1e7748bf Mon Sep 17 00:00:00 2001 From: Nextcloud bot Date: Fri, 13 Sep 2024 15:06:36 +0000 Subject: [PATCH 051/885] Fix(l10n): Update translations from Transifex Signed-off-by: Nextcloud bot --- app/src/main/res/values-sv/strings.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/src/main/res/values-sv/strings.xml b/app/src/main/res/values-sv/strings.xml index cb250541f0..4333348c19 100644 --- a/app/src/main/res/values-sv/strings.xml +++ b/app/src/main/res/values-sv/strings.xml @@ -470,7 +470,7 @@ Dela den här platsen Välj konto Delade objekt - Kortlek-kort + Deck-kort Bilder, filer, röstmeddelanden ... Inga delade objekt Plats From fa88fa4b078bc4f12e7b6364943267addc31b201 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Fri, 13 Sep 2024 15:09:25 +0000 Subject: [PATCH 052/885] Update dependency org.jetbrains.kotlinx:kotlinx-coroutines-test to v1.9.0 Signed-off-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- app/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/build.gradle b/app/build.gradle index 99498baa6a..fe102c819a 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -325,7 +325,7 @@ dependencies { androidTestImplementation "androidx.test:core:1.6.1" - androidTestImplementation "org.jetbrains.kotlinx:kotlinx-coroutines-test:1.8.1" + androidTestImplementation "org.jetbrains.kotlinx:kotlinx-coroutines-test:1.9.0" androidTestImplementation 'androidx.test:core-ktx:1.6.1' androidTestImplementation 'org.mockito:mockito-android:5.13.0' androidTestImplementation "androidx.work:work-testing:${workVersion}" From 80774f3d5995e3d3e4d8e15368effa8f7f4732cf Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Fri, 13 Sep 2024 15:11:25 +0000 Subject: [PATCH 053/885] Update dependency org.jetbrains.kotlinx:kotlinx-coroutines-test to v1.9.0 Signed-off-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- app/build.gradle | 2 +- gradle/verification-metadata.xml | 5 +++++ 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/app/build.gradle b/app/build.gradle index 99498baa6a..35724ec246 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -165,7 +165,7 @@ ext { espressoVersion = "3.6.1" androidxTestVersion = "1.5.0" media3_version = "1.4.1" - coroutines_version = "1.8.1" + coroutines_version = "1.9.0" mockitoKotlinVersion = "5.4.0" } diff --git a/gradle/verification-metadata.xml b/gradle/verification-metadata.xml index 634c94ad30..a14e92c169 100644 --- a/gradle/verification-metadata.xml +++ b/gradle/verification-metadata.xml @@ -6284,6 +6284,11 @@ + + + + + From 92c840f044dfee1a775cf039a7781344ce48562c Mon Sep 17 00:00:00 2001 From: Nextcloud bot Date: Fri, 13 Sep 2024 15:18:27 +0000 Subject: [PATCH 054/885] Fix(l10n): Update translations from Transifex Signed-off-by: Nextcloud bot --- app/src/main/res/values-de/strings.xml | 1 + 1 file changed, 1 insertion(+) diff --git a/app/src/main/res/values-de/strings.xml b/app/src/main/res/values-de/strings.xml index ee04926a14..009d215395 100644 --- a/app/src/main/res/values-de/strings.xml +++ b/app/src/main/res/values-de/strings.xml @@ -28,6 +28,7 @@ Schließen-Symbol Verbindung hergestellt Verbindung verloren + Verbindung verloren - %1$d Nachrichten in der Warteschlange Verbindung verloren - Gesendete Nachrichten der Warteschlange hinzugefügt Aufnahme sperren für kontinuierliche Aufzeichnung der Sprachnachricht Unterhaltung ist schreibgeschützt From 0480ceef7f596e877a44f711cdac68eacc9447d1 Mon Sep 17 00:00:00 2001 From: Marcel Hibbe Date: Fri, 13 Sep 2024 18:41:46 +0200 Subject: [PATCH 055/885] fix to show connection lost hint when internet is gone otherwise it showed "connection gained" with red background when loosing connection for the first time Signed-off-by: Marcel Hibbe --- .../main/java/com/nextcloud/talk/chat/MessageInputFragment.kt | 1 + 1 file changed, 1 insertion(+) diff --git a/app/src/main/java/com/nextcloud/talk/chat/MessageInputFragment.kt b/app/src/main/java/com/nextcloud/talk/chat/MessageInputFragment.kt index 5bd77d9b12..03858b4b5f 100644 --- a/app/src/main/java/com/nextcloud/talk/chat/MessageInputFragment.kt +++ b/app/src/main/java/com/nextcloud/talk/chat/MessageInputFragment.kt @@ -233,6 +233,7 @@ class MessageInputFragment : Fragment() { binding.fragmentConnectionLost.clearAnimation() binding.fragmentConnectionLost.visibility = View.GONE binding.fragmentConnectionLost.setBackgroundColor(resources.getColor(R.color.hwSecurityRed)) + binding.fragmentConnectionLost.text = getString(R.string.connection_lost_sent_messages_are_queued) binding.fragmentConnectionLost.visibility = View.VISIBLE binding.fragmentMessageInputView.attachmentButton.isEnabled = false binding.fragmentMessageInputView.recordAudioButton.isEnabled = false From c6d5d7b2d84b3c364f26e5887f0a1bda3ee088e1 Mon Sep 17 00:00:00 2001 From: Nextcloud bot Date: Sat, 14 Sep 2024 02:56:28 +0000 Subject: [PATCH 056/885] Fix(l10n): Update translations from Transifex Signed-off-by: Nextcloud bot --- app/src/main/res/values-b+en+001/strings.xml | 1 + app/src/main/res/values-gl/strings.xml | 1 + app/src/main/res/values-tr/strings.xml | 1 + app/src/main/res/values-zh-rHK/strings.xml | 1 + 4 files changed, 4 insertions(+) diff --git a/app/src/main/res/values-b+en+001/strings.xml b/app/src/main/res/values-b+en+001/strings.xml index ed551a2abc..5d9b0e3aef 100644 --- a/app/src/main/res/values-b+en+001/strings.xml +++ b/app/src/main/res/values-b+en+001/strings.xml @@ -28,6 +28,7 @@ Close Icon Connection established Connection lost + Connection lost - %1$d are queued Connection lost - Sent messages are queued Lock recording for continuously recording of the voice message Conversation is read only diff --git a/app/src/main/res/values-gl/strings.xml b/app/src/main/res/values-gl/strings.xml index 093a2d8d88..80a03cb399 100644 --- a/app/src/main/res/values-gl/strings.xml +++ b/app/src/main/res/values-gl/strings.xml @@ -28,6 +28,7 @@ Icona «Pechar» Estabeleceuse a conexión Perdeuse a conexión + Perdeuse a conexión – %1$d póñense en cola Perdeuse a conexión – As mensaxes enviadas póñense en cola Bloquear a gravación para gravar continuamente a mensaxe de voz A conversa é só de lectura diff --git a/app/src/main/res/values-tr/strings.xml b/app/src/main/res/values-tr/strings.xml index 49250032ab..b233ad9ac1 100644 --- a/app/src/main/res/values-tr/strings.xml +++ b/app/src/main/res/values-tr/strings.xml @@ -28,6 +28,7 @@ Kapatma simgesi Bağlantı kuruldu Bağlantı kesildi + Bağlantı kesildi. %1$d ileti kuyruğa alındı Bağlantı kesildi. Gönderilen iletiler kuyruğa alındı Sesli iletinin sürekli olarak kaydedilmesi için kaydı kilitleyin Görüşme salt okunur diff --git a/app/src/main/res/values-zh-rHK/strings.xml b/app/src/main/res/values-zh-rHK/strings.xml index 9990eb14f6..f094e0aa5c 100644 --- a/app/src/main/res/values-zh-rHK/strings.xml +++ b/app/src/main/res/values-zh-rHK/strings.xml @@ -28,6 +28,7 @@ 關閉圖示 連線已建立 連線已中斷 + 連線中斷 - %1$d 已排隊等待傳送 連線已中斷 - 已發送的訊息已排隊等待傳送 鎖定錄音以連續錄製音頻訊息 對話是唯讀 From d357669e2660f0aeaf0c4e39e2cd9e2053a52313 Mon Sep 17 00:00:00 2001 From: Marcel Hibbe Date: Sat, 14 Sep 2024 16:36:10 +0200 Subject: [PATCH 057/885] add v20.0.0 to CHANGELOG.md Signed-off-by: Marcel Hibbe --- CHANGELOG.md | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index ad49c2084d..60a89080a7 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -9,6 +9,26 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). Types of changes can be: Added/Changed/Deprecated/Removed/Fixed/Security +## [20.0.0] - 2024-09-14 + +### Added +- Offline support for conversations list and chat +- Federated calls +- Allow banning users and guests +- Open internal links for files app from any screen +- Show conversation description in chat and when listing open conversations + +### Changed +- New workflow for conversation creation + +### Fixed +- Connection fails with wired internet +- Minor bugs + +Minimum: Android 7.0 Nougat + +For a full list, please see https://github.com/nextcloud/talk-android/milestone/85?closed=1 + ## [19.0.1] - 2024-05-23 ### Fixed From ee6ca8f1aed2ffc01e39c521ec1c1d757587669c Mon Sep 17 00:00:00 2001 From: Nextcloud bot Date: Sun, 15 Sep 2024 03:35:39 +0000 Subject: [PATCH 058/885] Fix(l10n): Update translations from Transifex Signed-off-by: Nextcloud bot --- app/src/main/res/values-ga/strings.xml | 1 + 1 file changed, 1 insertion(+) diff --git a/app/src/main/res/values-ga/strings.xml b/app/src/main/res/values-ga/strings.xml index a898e82e3f..184a233b27 100644 --- a/app/src/main/res/values-ga/strings.xml +++ b/app/src/main/res/values-ga/strings.xml @@ -28,6 +28,7 @@ Dún Deilbhín Ceangal bunaithe Ceangal caillte + Ceangal caillte - tá %1$d scuaine Ceangal caillte - Tá na teachtaireachtaí seolta i scuaine Taifeadadh glas chun an teachtaireacht gutha a thaifeadadh go leanúnach Tá an comhrá léite amháin From 516cd96934aa4f4d2ae90bc5967a6bc7bac52770 Mon Sep 17 00:00:00 2001 From: sowjanyakch Date: Sun, 15 Sep 2024 15:57:47 +0200 Subject: [PATCH 059/885] Update SETUP.md Signed-off-by: sowjanyakch --- SETUP.md | 12 ++---------- 1 file changed, 2 insertions(+), 10 deletions(-) diff --git a/SETUP.md b/SETUP.md index 96cf791a47..540fca71af 100644 --- a/SETUP.md +++ b/SETUP.md @@ -12,7 +12,6 @@ 1. [Working with Android Studio](#working-with-android-studio) 1. [Working in a terminal with gradle](#working-in-a-terminal-with-gradle) 1. [App flavours](#app-flavours) - 1. [Update Android Studio ktlint formatter](#update-android-studio-ktlint-formatter) 1. [Troubleshooting](#troubleshooting) 1. [Compilation fails with "java.lang.OutOfMemoryError: Java heap space" error](#compilation-fails-with-javalangoutofmemoryerror-java-heap-space-error) @@ -43,13 +42,13 @@ We recommend to use the last version available in the stable channel of Android The Android SDK is necessary to build the app. Install it via Android Studio itself: -```Settings``` → ```Appearance & Behavior``` → ```System Settings``` → ```Android SDK``` +```Settings``` → ```Languages & Frameworks```→ ```Android SDK``` After installing it, add the full path to the directories 'tools/' and 'platform-tools/' from your Android SDK installation into the PATH variable of your environment. Open the Android SDK Manager under Android Studio's settings -```Settings``` → ```Appearance & Behavior``` → ```System Settings``` → ```Android SDK``` +```Settings``` → ```Languages & Frameworks```→ ```Android SDK``` To build the Nextcloud for Android app you will need to install at least the next SDK packages: @@ -114,13 +113,6 @@ The app is currently equipped to be built with three flavours: * **Gplay** - with Google stuff (push notification), used for Google Play store * **Qa** - build per pr for testing -### Update Android Studio ktlint formatter - -To update the formatter rules for kotlin files: -1. Download [latest release][9] to project's root folder -2. Run the following command: ```java -jar ktlint --android applyToIDEAProject -y``` -3. Diff the changed files and incorporate the updates/changes only. This needs to be done by hand since the Android Studio files contain formatting rules for java and xml as well which are overridden (as in removed) by the ktlint generator. - ## Troubleshooting ### Compilation fails with "java.lang.OutOfMemoryError: Java heap space" error From 3521308496a12f449396e2797f26b9a3272fb46c Mon Sep 17 00:00:00 2001 From: Marcel Hibbe Date: Sun, 15 Sep 2024 17:06:35 +0200 Subject: [PATCH 060/885] manually bump to 20.1.0 Alpha 02 As build script was not able to push to master, it failed and next time it tried to build the same version again. Thats why Google complained the apk already exists. The bot was now changed to have admin permissions. So this commit will bump the version number manually and in the next runs everything should work again. Signed-off-by: Marcel Hibbe --- app/build.gradle | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/app/build.gradle b/app/build.gradle index 7b54f62601..e46ca69ff0 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -40,8 +40,8 @@ android { // mayor.minor.hotfix.increment (for increment: 01-50=Alpha / 51-89=RC / 90-99=stable) // xx .xxx .xx .xx - versionCode 200010001 - versionName "20.1.0 Alpha 01" + versionCode 200010002 + versionName "20.1.0 Alpha 02" flavorDimensions "default" renderscriptTargetApi 19 From a6dcd14f4e186e275fd07b286fce72af948af0ff Mon Sep 17 00:00:00 2001 From: Nextcloud Android Bot Date: Sun, 15 Sep 2024 15:19:35 +0000 Subject: [PATCH 061/885] Weekly 20.1.0 Alpha 03 --- app/build.gradle | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/app/build.gradle b/app/build.gradle index e46ca69ff0..9b3dfe84b2 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -40,8 +40,8 @@ android { // mayor.minor.hotfix.increment (for increment: 01-50=Alpha / 51-89=RC / 90-99=stable) // xx .xxx .xx .xx - versionCode 200010002 - versionName "20.1.0 Alpha 02" + versionCode 200010003 + versionName "20.1.0 Alpha 03" flavorDimensions "default" renderscriptTargetApi 19 From 0af66a3a6e1985f83d6c2eae4f1b2492217e05ba Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Sun, 15 Sep 2024 23:15:38 +0000 Subject: [PATCH 062/885] Update dependency joda-time:joda-time to v2.13.0 Signed-off-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- app/build.gradle | 2 +- gradle/verification-metadata.xml | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/app/build.gradle b/app/build.gradle index 9b3dfe84b2..25cdc7d9c6 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -261,7 +261,7 @@ dependencies { implementation 'com.github.wooplr:Spotlight:1.3' implementation 'com.google.code.findbugs:jsr305:3.0.2' implementation 'com.github.nextcloud-deps:ChatKit:0.4.2' - implementation 'joda-time:joda-time:2.12.7' + implementation 'joda-time:joda-time:2.13.0' implementation "io.coil-kt:coil:${coilKtVersion}" implementation "io.coil-kt:coil-gif:${coilKtVersion}" implementation "io.coil-kt:coil-svg:${coilKtVersion}" diff --git a/gradle/verification-metadata.xml b/gradle/verification-metadata.xml index a14e92c169..e41fd9d12c 100644 --- a/gradle/verification-metadata.xml +++ b/gradle/verification-metadata.xml @@ -218,6 +218,7 @@ + From b99cdd2e29a52a085cd26115edefabaf550ca24f Mon Sep 17 00:00:00 2001 From: Nextcloud bot Date: Mon, 16 Sep 2024 02:45:50 +0000 Subject: [PATCH 063/885] Fix(l10n): Update translations from Transifex Signed-off-by: Nextcloud bot --- app/src/main/res/values-ar/strings.xml | 1 + app/src/main/res/values-pt-rBR/strings.xml | 2 ++ 2 files changed, 3 insertions(+) diff --git a/app/src/main/res/values-ar/strings.xml b/app/src/main/res/values-ar/strings.xml index fc2147533c..ef45c63f6f 100644 --- a/app/src/main/res/values-ar/strings.xml +++ b/app/src/main/res/values-ar/strings.xml @@ -28,6 +28,7 @@ أيقونة الإغلاق تم الاتصال انقطع الاتصال + إنقَطَع الاتصال - %1$d وُضِعَت في قائمة انتظار انقطع الاتصال - الرسالة المطلوب إرسالها تمّ تحضيرها للإرسال في قائمة بحسب الأولوية قَفْل التسجيل للتسجيل المستمر للرسالة الصوتية المحادثة للقراءة فقط diff --git a/app/src/main/res/values-pt-rBR/strings.xml b/app/src/main/res/values-pt-rBR/strings.xml index e1fc37f2d8..2dea6c1105 100644 --- a/app/src/main/res/values-pt-rBR/strings.xml +++ b/app/src/main/res/values-pt-rBR/strings.xml @@ -28,6 +28,7 @@ Fechar ícone Conexão estabelecida Conexão perdida + Conexão perdida - %1$d estão na fila Conexão perdida - As mensagens enviadas estão na fila Gravação de bloqueio para gravação contínua da mensagem de voz A conversa é somente leitura @@ -407,6 +408,7 @@ O servidor não tem o aplicativo Talk suportado instalado Endereço do servidor https://… %1$s somente funciona com%2$s 13 e posterior + Definir Senha Configurações Sua conta atual foi atualizada, em vez de adicionar uma nova Avançada From 911c52c37b474849100f44e0a50adfc2c5340b04 Mon Sep 17 00:00:00 2001 From: Nextcloud Android Bot Date: Mon, 16 Sep 2024 03:11:25 +0000 Subject: [PATCH 064/885] Weekly 20.1.0 Alpha 04 --- app/build.gradle | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/app/build.gradle b/app/build.gradle index 25cdc7d9c6..9a2d54a4a3 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -40,8 +40,8 @@ android { // mayor.minor.hotfix.increment (for increment: 01-50=Alpha / 51-89=RC / 90-99=stable) // xx .xxx .xx .xx - versionCode 200010003 - versionName "20.1.0 Alpha 03" + versionCode 200010004 + versionName "20.1.0 Alpha 04" flavorDimensions "default" renderscriptTargetApi 19 From 37033af668205861a92d03afa0fdd04b5fc25085 Mon Sep 17 00:00:00 2001 From: Marcel Hibbe Date: Mon, 16 Sep 2024 11:38:38 +0200 Subject: [PATCH 065/885] remove duplicated dependencies found by the tool https://stackblitz.com/edit/find-gradle-dependency-duplicates?file=src%2Fapp%2Fapp.component.ts Signed-off-by: Marcel Hibbe --- app/build.gradle | 4 ---- 1 file changed, 4 deletions(-) diff --git a/app/build.gradle b/app/build.gradle index 9a2d54a4a3..c27cca710c 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -344,15 +344,11 @@ dependencies { spotbugsPlugins 'com.h3xstream.findsecbugs:findsecbugs-plugin:1.13.0' spotbugsPlugins 'com.mebigfatguy.fb-contrib:fb-contrib:7.6.4' - gplayImplementation 'com.google.android.gms:play-services-base:18.5.0' - gplayImplementation "com.google.firebase:firebase-messaging:24.0.1" - implementation 'androidx.activity:activity-ktx:1.9.2' implementation 'com.github.nextcloud.android-common:ui:0.23.0' implementation 'com.github.nextcloud-deps:android-talk-webrtc:121.6167.0' - implementation(platform("androidx.compose:compose-bom:2024.09.01")) implementation("io.coil-kt:coil-compose:2.7.0") implementation "com.google.dagger:hilt-android:$hilt_version" From 3f06801e593b0ebee0c43c90ac5f1376bc4d409d Mon Sep 17 00:00:00 2001 From: Marcel Hibbe Date: Mon, 16 Sep 2024 16:45:53 +0200 Subject: [PATCH 066/885] fix to load chat for old server version With server version 23.0.12 it happened that the chat did not load because values were null. Now default values in json model are set (because that's easier than changing the entity). Additionally a check was added in CallActivity that a callStartTime of 0 would not be used (but it should not be used anyway if it would be 0 because then capability should also not be available). Signed-off-by: Marcel Hibbe --- .../main/java/com/nextcloud/talk/activities/CallActivity.kt | 4 +++- .../talk/models/json/conversations/Conversation.kt | 6 +++--- 2 files changed, 6 insertions(+), 4 deletions(-) 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 90e3689f1a..6376ce8fe3 100644 --- a/app/src/main/java/com/nextcloud/talk/activities/CallActivity.kt +++ b/app/src/main/java/com/nextcloud/talk/activities/CallActivity.kt @@ -1744,7 +1744,9 @@ class CallActivity : CallBaseActivity() { } private fun startCallTimeCounter(callStartTime: Long?) { - if (callStartTime != null && hasSpreedFeatureCapability( + if (callStartTime != null && + callStartTime != 0L && + hasSpreedFeatureCapability( conversationUser!!.capabilities!!.spreedCapability!!, SpreedFeatures.RECORDING_V1 ) ) { diff --git a/app/src/main/java/com/nextcloud/talk/models/json/conversations/Conversation.kt b/app/src/main/java/com/nextcloud/talk/models/json/conversations/Conversation.kt index 2411a39793..7b22165cc4 100644 --- a/app/src/main/java/com/nextcloud/talk/models/json/conversations/Conversation.kt +++ b/app/src/main/java/com/nextcloud/talk/models/json/conversations/Conversation.kt @@ -144,16 +144,16 @@ data class Conversation( var callRecording: Int = 0, @JsonField(name = ["avatarVersion"]) - var avatarVersion: String? = null, + var avatarVersion: String? = "", // Be aware that variables with "is" at the beginning will lead to the error: // "@JsonField annotation can only be used on private fields if both getter and setter are present." // Instead, name it with "has" at the beginning: isCustomAvatar -> hasCustomAvatar @JsonField(name = ["isCustomAvatar"]) - var hasCustomAvatar: Boolean? = null, + var hasCustomAvatar: Boolean? = false, @JsonField(name = ["callStartTime"]) - var callStartTime: Long? = null, + var callStartTime: Long? = 0L, @JsonField(name = ["recordingConsent"]) var recordingConsentRequired: Int = 0, From 198a9ddb9efe2c75f79b0e0209a169f89332c9f9 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Tue, 17 Sep 2024 00:41:05 +0000 Subject: [PATCH 067/885] Update ubuntu:noble Docker digest to 56a8952 Signed-off-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- .devcontainer/Dockerfile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.devcontainer/Dockerfile b/.devcontainer/Dockerfile index 3474beb7a4..65bfb57e6a 100644 --- a/.devcontainer/Dockerfile +++ b/.devcontainer/Dockerfile @@ -1,4 +1,4 @@ -FROM ubuntu:noble@sha256:8a37d68f4f73ebf3d4efafbcf66379bf3728902a8038616808f04e34a9ab63ee +FROM ubuntu:noble@sha256:56a8952801afd93876eea675cae9ab861bf8d2e6a4f978e4b0237ce94e1c3b49 ARG DEBIAN_FRONTEND=noninteractive ENV ANDROID_HOME=/usr/lib/android-sdk From 2f05ffb3d645aef50104db57bb8cdbba61df81f4 Mon Sep 17 00:00:00 2001 From: Nextcloud bot Date: Tue, 17 Sep 2024 02:55:40 +0000 Subject: [PATCH 068/885] Fix(l10n): Update translations from Transifex Signed-off-by: Nextcloud bot --- app/src/main/res/values-de/strings.xml | 2 +- app/src/main/res/values-sl/strings.xml | 4 ++-- app/src/main/res/values-sr/strings.xml | 2 ++ app/src/main/res/values-sv/strings.xml | 1 + 4 files changed, 6 insertions(+), 3 deletions(-) diff --git a/app/src/main/res/values-de/strings.xml b/app/src/main/res/values-de/strings.xml index 009d215395..9396f7d1ba 100644 --- a/app/src/main/res/values-de/strings.xml +++ b/app/src/main/res/values-de/strings.xml @@ -29,7 +29,7 @@ Verbindung hergestellt Verbindung verloren Verbindung verloren - %1$d Nachrichten in der Warteschlange - Verbindung verloren - Gesendete Nachrichten der Warteschlange hinzugefügt + Verbindung verloren - Gesendete Nachrichten werden der Warteschlange hinzugefügt Aufnahme sperren für kontinuierliche Aufzeichnung der Sprachnachricht Unterhaltung ist schreibgeschützt Unterhaltungen diff --git a/app/src/main/res/values-sl/strings.xml b/app/src/main/res/values-sl/strings.xml index 9057bb8ca9..fbda6e9147 100644 --- a/app/src/main/res/values-sl/strings.xml +++ b/app/src/main/res/values-sl/strings.xml @@ -35,7 +35,7 @@ Poteka nalaganje … %1$s (%2$d) 4 urah - (urejano) + (spremenjeno) Drugim nevidno Naloži več zadetkov Simbol zaklepa @@ -269,7 +269,7 @@ Odstrani iz priljubljenih Odstrani skupino in člane Odstrani udeležence - odstrani ekipo in člane + Odstrani skupino in člane Preimenuj pogovor Preimenuj Odgovori diff --git a/app/src/main/res/values-sr/strings.xml b/app/src/main/res/values-sr/strings.xml index 2eb69510b8..419339fcc1 100644 --- a/app/src/main/res/values-sr/strings.xml +++ b/app/src/main/res/values-sr/strings.xml @@ -28,6 +28,7 @@ Икона затвори Веза успостављена Веза је прекинута + Веза је прекинута - %1$d су стављене у ред Веза је прекинута - Послате поруке су стављене у ред Закључајте снимање да би се гласовна порука непрестано снимала. Овај разговор је само-за-читање @@ -407,6 +408,7 @@ Сервер нема инсталирану подржану Talk апликацију Адреса сервера https://… %1$s ради само са%2$s верзије 13 и већом + Постави лозинку Поставке Ваш постојећи налог је ажуриран, уместо што је додат нови налог Напредно diff --git a/app/src/main/res/values-sv/strings.xml b/app/src/main/res/values-sv/strings.xml index 4333348c19..0ac98b8efa 100644 --- a/app/src/main/res/values-sv/strings.xml +++ b/app/src/main/res/values-sv/strings.xml @@ -27,6 +27,7 @@ Stäng Anslutning etablerad Anslutning förlorad + Anslutningen förlorad - %1$d står i kö Anslutning förlorad - Skickade meddelanden är i kö Lås inspelning för kontinuerlig inspelning av röstmeddelandet Konversationen är skrivskyddad From 7bbe4f8673c228e635d62e62557477a058122eda Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Tue, 17 Sep 2024 05:08:03 +0000 Subject: [PATCH 069/885] Update ubuntu:noble Docker digest to dfc1087 Signed-off-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- .devcontainer/Dockerfile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.devcontainer/Dockerfile b/.devcontainer/Dockerfile index 65bfb57e6a..1e2cb0cefd 100644 --- a/.devcontainer/Dockerfile +++ b/.devcontainer/Dockerfile @@ -1,4 +1,4 @@ -FROM ubuntu:noble@sha256:56a8952801afd93876eea675cae9ab861bf8d2e6a4f978e4b0237ce94e1c3b49 +FROM ubuntu:noble@sha256:dfc10878be8d8fc9c61cbff33166cb1d1fe44391539243703c72766894fa834a ARG DEBIAN_FRONTEND=noninteractive ENV ANDROID_HOME=/usr/lib/android-sdk From 722914fb6cbfd783cba62907fe1b21e3d3832c1a Mon Sep 17 00:00:00 2001 From: Marcel Hibbe Date: Mon, 16 Sep 2024 12:56:20 +0200 Subject: [PATCH 070/885] fix to show user status in conversation list Signed-off-by: Marcel Hibbe --- .../data/network/OfflineFirstConversationsRepository.kt | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/app/src/main/java/com/nextcloud/talk/conversationlist/data/network/OfflineFirstConversationsRepository.kt b/app/src/main/java/com/nextcloud/talk/conversationlist/data/network/OfflineFirstConversationsRepository.kt index 397a86dca7..1258ee649e 100644 --- a/app/src/main/java/com/nextcloud/talk/conversationlist/data/network/OfflineFirstConversationsRepository.kt +++ b/app/src/main/java/com/nextcloud/talk/conversationlist/data/network/OfflineFirstConversationsRepository.kt @@ -19,6 +19,7 @@ import com.nextcloud.talk.data.database.model.ConversationEntity import com.nextcloud.talk.data.network.NetworkMonitor import com.nextcloud.talk.data.user.model.User import com.nextcloud.talk.models.domain.ConversationModel +import com.nextcloud.talk.utils.CapabilitiesUtil.isUserStatusAvailable import com.nextcloud.talk.utils.database.user.CurrentUserProviderNew import io.reactivex.Observer import io.reactivex.android.schedulers.AndroidSchedulers @@ -107,8 +108,10 @@ class OfflineFirstConversationsRepository @Inject constructor( return null } + val includeStatus = isUserStatusAvailable(user) + try { - val conversationsList = network.getRooms(user, user.baseUrl!!, false) + val conversationsList = network.getRooms(user, user.baseUrl!!, includeStatus) .subscribeOn(Schedulers.io()) .observeOn(AndroidSchedulers.mainThread()) .blockingSingle() From 5991b914604f0f6061bd1d113fa7c031c7b5d7f3 Mon Sep 17 00:00:00 2001 From: Marcel Hibbe Date: Tue, 17 Sep 2024 11:30:36 +0200 Subject: [PATCH 071/885] fix to show accounts from older servers in switch account dialog if invitations were not supported, the account did not show up Signed-off-by: Marcel Hibbe --- .../dialog/ChooseAccountDialogFragment.java | 49 +++++++++++++------ 1 file changed, 33 insertions(+), 16 deletions(-) diff --git a/app/src/main/java/com/nextcloud/talk/ui/dialog/ChooseAccountDialogFragment.java b/app/src/main/java/com/nextcloud/talk/ui/dialog/ChooseAccountDialogFragment.java index 24c7de5e11..8e53821479 100644 --- a/app/src/main/java/com/nextcloud/talk/ui/dialog/ChooseAccountDialogFragment.java +++ b/app/src/main/java/com/nextcloud/talk/ui/dialog/ChooseAccountDialogFragment.java @@ -170,27 +170,21 @@ public void onSubscribe(Disposable d) { @Override public void onNext(InvitationsModel invitationsModel) { - Participant participant; - participant = new Participant(); - participant.setActorType(Participant.ActorType.USERS); - participant.setActorId(userId); - participant.setDisplayName(finalUserEntity.getDisplayName()); - userItems.add( - new AdvancedUserItem( - participant, - finalUserEntity, - null, - viewThemeUtils, - invitationsModel.getInvitations().size() - )); - adapter.addListener(onSwitchItemClickListener); - adapter.addListener(onSwitchItemLongClickListener); - adapter.updateDataSet(userItems, false); + addAccountToSwitcherList( + userId, + finalUserEntity, + invitationsModel.getInvitations().size() + ); } @Override public void onError(@io.reactivex.annotations.NonNull Throwable e) { Log.e(TAG, "Failed to fetch invitations", e); + addAccountToSwitcherList( + userId, + finalUserEntity, + 0 + ); } @Override @@ -203,6 +197,29 @@ public void onComplete() { } } + private void addAccountToSwitcherList( + String userId, + User finalUserEntity, + int actionsRequiredCount + ) { + Participant participant; + participant = new Participant(); + participant.setActorType(Participant.ActorType.USERS); + participant.setActorId(userId); + participant.setDisplayName(finalUserEntity.getDisplayName()); + userItems.add( + new AdvancedUserItem( + participant, + finalUserEntity, + null, + viewThemeUtils, + actionsRequiredCount + )); + adapter.addListener(onSwitchItemClickListener); + adapter.addListener(onSwitchItemLongClickListener); + adapter.updateDataSet(userItems, false); + } + private void setupListeners(User user) { // Creating listeners for quick-actions binding.currentAccount.getRoot().setOnClickListener(v -> dismiss()); From 28906dd9996f384d7ec9f5148309e65b2e6fdf0e Mon Sep 17 00:00:00 2001 From: Marcel Hibbe Date: Tue, 17 Sep 2024 12:05:02 +0200 Subject: [PATCH 072/885] dont show error when fetching pending invitations failed Signed-off-by: Marcel Hibbe --- .../talk/conversationlist/ConversationsListActivity.kt | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/app/src/main/java/com/nextcloud/talk/conversationlist/ConversationsListActivity.kt b/app/src/main/java/com/nextcloud/talk/conversationlist/ConversationsListActivity.kt index 1483815e4b..e3a367f0c7 100644 --- a/app/src/main/java/com/nextcloud/talk/conversationlist/ConversationsListActivity.kt +++ b/app/src/main/java/com/nextcloud/talk/conversationlist/ConversationsListActivity.kt @@ -323,9 +323,7 @@ class ConversationsListActivity : } is ConversationsListViewModel.GetFederationInvitationsErrorState -> { - if (isNetworkAvailable(context)) { - Snackbar.make(binding.root, R.string.get_invitations_error, Snackbar.LENGTH_LONG).show() - } + // do nothing } else -> {} From 45ecaed26d69ce809562168c978b40b9ad6b8e99 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Wed, 18 Sep 2024 00:58:18 +0000 Subject: [PATCH 073/885] Update dependency com.android.tools.build:gradle to v8.6.1 Signed-off-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build.gradle b/build.gradle index d78bd1b411..7b8f49a831 100644 --- a/build.gradle +++ b/build.gradle @@ -22,7 +22,7 @@ buildscript { } dependencies { - classpath 'com.android.tools.build:gradle:8.6.0' + classpath 'com.android.tools.build:gradle:8.6.1' classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:${kotlinVersion}" classpath "org.jetbrains.kotlin:kotlin-serialization:${kotlinVersion}" classpath 'com.github.spotbugs.snom:spotbugs-gradle-plugin:6.0.22' From 3db9bc6247ba6381071b8b749db59ee1d070f35a Mon Sep 17 00:00:00 2001 From: Nextcloud bot Date: Wed, 18 Sep 2024 02:53:40 +0000 Subject: [PATCH 074/885] Fix(l10n): Update translations from Transifex Signed-off-by: Nextcloud bot --- app/src/main/res/values-ru/strings.xml | 1 + app/src/main/res/values-sc/strings.xml | 20 +++++++++++--------- 2 files changed, 12 insertions(+), 9 deletions(-) diff --git a/app/src/main/res/values-ru/strings.xml b/app/src/main/res/values-ru/strings.xml index 3890c774ce..0e92628e65 100644 --- a/app/src/main/res/values-ru/strings.xml +++ b/app/src/main/res/values-ru/strings.xml @@ -518,6 +518,7 @@ Переключить область видимости Изменить уровень конфиденциальности %1$s Прокрутить вниз + Поиск значка несколько секунд назад Посмотреть %1$s похожие сообщения Выбрано diff --git a/app/src/main/res/values-sc/strings.xml b/app/src/main/res/values-sc/strings.xml index 8948b5b0da..eaeba09a04 100644 --- a/app/src/main/res/values-sc/strings.xml +++ b/app/src/main/res/values-sc/strings.xml @@ -73,7 +73,7 @@ Cantzellados totu is messàgios A beru boles cantzellare totu is messàgios in custa resonada? Càmbia tzertificadu cliente - Imposta tzertificadu cliente + Cunfigura su tzertificadu de cliente e Còpia Copiadu in punta de billete @@ -81,7 +81,7 @@ Disativadu Iscarta Ddoe at àpidu un\'errore! - Imposta + Cunfigura Brinca Disconnotu Seletziona tzertificadu autenticatzione @@ -146,7 +146,7 @@ Persone invitada Autoriza persones invitadas Dìgita una crae noa - Imposta una crae pro limitare is chi podent impreare su ligòngiu pùblicu. + Cunfigura una crae pro limitare is chi podent impreare su ligòngiu pùblicu. Bardiadura de sa crae Crae dèbile Torra a imbiare is invitos @@ -165,7 +165,7 @@ Positzione disconnota Blocadu Toca pro isblocare - No impostadu + Non cunfiguradu Marca comente lèghidu Marca comente non lèghidu Annulla risposta @@ -268,10 +268,10 @@ Notìficas Messàgios Verìfica is cuntatos subra sa base de su nùmeru de telèfonu pro integrare su curtziadòrgiu de Talk in sìaplicatzione de is cuntatos de sistema - Podes impostare su nùmeru de telèfonu tuo aici is àteras utèntzias t\'ant a pòdere agatare + Podes cunfigurare su nùmeru de telèfonu tuo, in manera chi àteras utèntzias t\'ant a pòdere agatare Inserta nùmeru de telèfonu Nùmeru de telèfonu non bàlidu - Nùmeru de telèfonu impostadu + Nùmeru de telèfonu cunfiguradu Nùmeru de telèfonu Integratzione de su nùmeru de telèfonu Riservadesa @@ -294,7 +294,7 @@ Sa versione de su serbidore est betza meda e no at a èssere suportada in sa versione imbeniente! Sa versione de su serbidore est betza meda e non suportada dae custa versione de aplicatzione Android Serbidore non suportadu - Impostadu dae su sarva-bateria + Cunfiguradu dae su sarva-bateria Iscuru Imprea cunfiguratziones predefinidas de sistema tema @@ -361,8 +361,9 @@ Imbia messàgiu de posta eletrònica Imbia a Imbia a … - Imposta istadu - Imposta messàgiu de istadu + Cunfigura + Cunfigura un\'istadu + Cunfigura su messàgiu de istadu Cumpartzi Àudio Archìviu @@ -384,6 +385,7 @@ Impossìbile rilevare sa lìngua Dae A + De lèghere Càrriga un\'avatar nou dae dispositivu Avatar de s\'utente Indiritzu From 9e91bdeb1d243a008093475420cd0486b9221185 Mon Sep 17 00:00:00 2001 From: Marcel Hibbe Date: Wed, 18 Sep 2024 17:34:10 +0200 Subject: [PATCH 075/885] fix to hide messageInputFragment when user has no restriction to write The messageInputFragment was hidden by checkShowMessageInputView(), but it was immediately shown again by checkLobbyState() This fix will execute checkShowMessageInputView() inside checkLobbyState() in the correct order. Additionally, the check checkLobbyState() has to be already executed in GetCapabilitiesInitialLoadState as well as checkShowCallButtons() Otherwise the expected behavior would only be set after 30 seconds. An improvemnt for the future must be to improve the capabilities handling. Signed-off-by: Marcel Hibbe --- app/src/main/java/com/nextcloud/talk/chat/ChatActivity.kt | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/app/src/main/java/com/nextcloud/talk/chat/ChatActivity.kt b/app/src/main/java/com/nextcloud/talk/chat/ChatActivity.kt index ae0cc210e5..94ffafe28a 100644 --- a/app/src/main/java/com/nextcloud/talk/chat/ChatActivity.kt +++ b/app/src/main/java/com/nextcloud/talk/chat/ChatActivity.kt @@ -577,7 +577,6 @@ class ChatActivity : invalidateOptionsMenu() checkShowCallButtons() - checkShowMessageInputView() checkLobbyState() updateRoomTimerHandler() } @@ -603,6 +602,9 @@ class ChatActivity : loadAvatarForStatusBar() setupSwipeToReply() setActionBarTitle() + + checkShowCallButtons() + checkLobbyState() updateRoomTimerHandler() val urlForChatting = ApiUtils.getUrlForChat(chatApiVersion, conversationUser?.baseUrl, roomToken) @@ -1892,12 +1894,12 @@ class ChatActivity : } else { binding.lobby.lobbyView.visibility = View.GONE binding.messagesListView.visibility = View.VISIBLE - binding.fragmentContainerActivityChat.visibility = View.VISIBLE + checkShowMessageInputView() } } else { binding.lobby.lobbyView.visibility = View.GONE binding.messagesListView.visibility = View.VISIBLE - binding.fragmentContainerActivityChat.visibility = View.VISIBLE + checkShowMessageInputView() } } From 6122650202b540e18b524fb5d205702846b25422 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Wed, 18 Sep 2024 19:56:24 +0000 Subject: [PATCH 076/885] Update dependency androidx.compose.runtime:runtime to v1.7.2 Signed-off-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- app/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/build.gradle b/app/build.gradle index c27cca710c..96fd12ea02 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -180,7 +180,7 @@ dependencies { spotbugsPlugins 'com.h3xstream.findsecbugs:findsecbugs-plugin:1.13.0' spotbugsPlugins 'com.mebigfatguy.fb-contrib:fb-contrib:7.6.4' - implementation("androidx.compose.runtime:runtime:1.7.1") + implementation("androidx.compose.runtime:runtime:1.7.2") implementation 'androidx.preference:preference-ktx:1.2.1' implementation 'androidx.datastore:datastore-core:1.1.1' implementation 'androidx.datastore:datastore-preferences:1.1.1' From bc57bb20de6fed0fc1f96b84bafc590fb0cb1b40 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Wed, 18 Sep 2024 19:58:23 +0000 Subject: [PATCH 077/885] Update dependency androidx.compose.ui:ui-test-junit4 to v1.7.2 Signed-off-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- app/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/build.gradle b/app/build.gradle index 96fd12ea02..7e3b45f9a7 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -316,7 +316,7 @@ dependencies { debugImplementation("androidx.compose.ui:ui-tooling") //tests - androidTestImplementation("androidx.compose.ui:ui-test-junit4:1.7.1") + androidTestImplementation("androidx.compose.ui:ui-test-junit4:1.7.2") debugImplementation("androidx.compose.ui:ui-test-manifest") testImplementation 'junit:junit:4.13.2' From c1c68570b3bc8d75906b9014531cfc530fad926d Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Wed, 18 Sep 2024 20:18:10 +0000 Subject: [PATCH 078/885] Update dependency androidx.compose:compose-bom to v2024.09.02 Signed-off-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- app/build.gradle | 4 ++-- gradle/verification-metadata.xml | 5 +++++ 2 files changed, 7 insertions(+), 2 deletions(-) diff --git a/app/build.gradle b/app/build.gradle index 96fd12ea02..0956529b56 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -307,7 +307,7 @@ dependencies { gplayImplementation "com.google.firebase:firebase-messaging:24.0.1" //compose - implementation(platform("androidx.compose:compose-bom:2024.09.01")) + implementation(platform("androidx.compose:compose-bom:2024.09.02")) implementation("androidx.compose.ui:ui") implementation 'androidx.compose.material3:material3:1.3.0' implementation("androidx.compose.ui:ui-tooling-preview") @@ -355,7 +355,7 @@ dependencies { kapt "com.google.dagger:hilt-android-compiler:$hilt_version" implementation("androidx.lifecycle:lifecycle-viewmodel-compose:2.8.5") - androidTestImplementation(platform("androidx.compose:compose-bom:2024.09.01")) + androidTestImplementation(platform("androidx.compose:compose-bom:2024.09.02")) androidTestImplementation("androidx.compose.ui:ui-test-junit4") testImplementation "org.mockito.kotlin:mockito-kotlin:$mockitoKotlinVersion" testImplementation "org.jetbrains.kotlinx:kotlinx-coroutines-test:$coroutines_version" diff --git a/gradle/verification-metadata.xml b/gradle/verification-metadata.xml index e41fd9d12c..deff7f67b8 100644 --- a/gradle/verification-metadata.xml +++ b/gradle/verification-metadata.xml @@ -620,6 +620,11 @@ + + + + + From ef3cd824c014ffbfdb4812deceb26da8126523ce Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Wed, 18 Sep 2024 20:20:43 +0000 Subject: [PATCH 079/885] Update dependency androidx.lifecycle:lifecycle-runtime-ktx to v2.8.6 Signed-off-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- app/build.gradle | 2 +- gradle/verification-metadata.xml | 5 +++++ 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/app/build.gradle b/app/build.gradle index 96fd12ea02..97a50eaef6 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -312,7 +312,7 @@ dependencies { implementation 'androidx.compose.material3:material3:1.3.0' implementation("androidx.compose.ui:ui-tooling-preview") implementation 'androidx.activity:activity-compose:1.9.2' - implementation 'androidx.lifecycle:lifecycle-runtime-ktx:2.8.5' + implementation 'androidx.lifecycle:lifecycle-runtime-ktx:2.8.6' debugImplementation("androidx.compose.ui:ui-tooling") //tests diff --git a/gradle/verification-metadata.xml b/gradle/verification-metadata.xml index e41fd9d12c..4393b95a72 100644 --- a/gradle/verification-metadata.xml +++ b/gradle/verification-metadata.xml @@ -1427,6 +1427,11 @@ + + + + + From d480fe30085a492995633881756500654106d85f Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Wed, 18 Sep 2024 21:24:09 +0000 Subject: [PATCH 080/885] Update dependency androidx.lifecycle:lifecycle-viewmodel-compose to v2.8.6 Signed-off-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- app/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/build.gradle b/app/build.gradle index a8f69960bb..f744dd334c 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -354,7 +354,7 @@ dependencies { implementation "com.google.dagger:hilt-android:$hilt_version" kapt "com.google.dagger:hilt-android-compiler:$hilt_version" - implementation("androidx.lifecycle:lifecycle-viewmodel-compose:2.8.5") + implementation("androidx.lifecycle:lifecycle-viewmodel-compose:2.8.6") androidTestImplementation(platform("androidx.compose:compose-bom:2024.09.02")) androidTestImplementation("androidx.compose.ui:ui-test-junit4") testImplementation "org.mockito.kotlin:mockito-kotlin:$mockitoKotlinVersion" From 7c37d1f1110eee4e039c226d559c2abecef8a40a Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Wed, 18 Sep 2024 21:26:18 +0000 Subject: [PATCH 081/885] Update lifecycleVersion to v2.8.6 Signed-off-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- app/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/build.gradle b/app/build.gradle index a8f69960bb..ef36e248e0 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -153,7 +153,7 @@ ext { daggerVersion = "2.52" emojiVersion = "1.5.0" fidoVersion = "4.1.0-patch2" - lifecycleVersion = '2.8.5' + lifecycleVersion = '2.8.6' okhttpVersion = "4.12.0" markwonVersion = "4.6.2" materialDialogsVersion = "3.3.0" From 663ba0a2ed80ac1ec09cb5a9f4ecc94e59862d10 Mon Sep 17 00:00:00 2001 From: Nextcloud bot Date: Thu, 19 Sep 2024 02:51:16 +0000 Subject: [PATCH 082/885] Fix(l10n): Update translations from Transifex Signed-off-by: Nextcloud bot --- app/src/main/res/values-zh-rTW/strings.xml | 1 + 1 file changed, 1 insertion(+) diff --git a/app/src/main/res/values-zh-rTW/strings.xml b/app/src/main/res/values-zh-rTW/strings.xml index fffc78a55b..19d07e4e08 100644 --- a/app/src/main/res/values-zh-rTW/strings.xml +++ b/app/src/main/res/values-zh-rTW/strings.xml @@ -28,6 +28,7 @@ 關閉按鈕 連線已建立 連線中斷 + 連線中斷 - %1$d 已排入佇列 連線中斷 -傳送的訊息已排入佇列 鎖定錄音以連續錄製語音訊息 對話為唯讀 From 7a91e3a38fcfc14734b034d1d9f3b428bf55e3cb Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Thu, 19 Sep 2024 10:37:37 +0000 Subject: [PATCH 083/885] Update github/codeql-action action to v3.26.8 Signed-off-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- .github/workflows/codeql.yml | 4 ++-- .github/workflows/scorecard.yml | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/codeql.yml b/.github/workflows/codeql.yml index 3b92074ed0..f1baac3924 100644 --- a/.github/workflows/codeql.yml +++ b/.github/workflows/codeql.yml @@ -39,7 +39,7 @@ jobs: with: swap-size-gb: 10 - name: Initialize CodeQL - uses: github/codeql-action/init@8214744c546c1e5c8f03dde8fab3a7353211988d # v3.26.7 + uses: github/codeql-action/init@294a9d92911152fe08befb9ec03e240add280cb3 # v3.26.8 with: languages: ${{ matrix.language }} - name: Set up JDK 17 @@ -53,4 +53,4 @@ jobs: echo "org.gradle.jvmargs=-Xmx4g -XX:MaxMetaspaceSize=512m -XX:+HeapDumpOnOutOfMemoryError" > "$HOME/.gradle/gradle.properties" ./gradlew assembleDebug - name: Perform CodeQL Analysis - uses: github/codeql-action/analyze@8214744c546c1e5c8f03dde8fab3a7353211988d # v3.26.7 + uses: github/codeql-action/analyze@294a9d92911152fe08befb9ec03e240add280cb3 # v3.26.8 diff --git a/.github/workflows/scorecard.yml b/.github/workflows/scorecard.yml index fa12539201..e5e6986d15 100644 --- a/.github/workflows/scorecard.yml +++ b/.github/workflows/scorecard.yml @@ -42,6 +42,6 @@ jobs: # Upload the results to GitHub's code scanning dashboard. - name: "Upload to code-scanning" - uses: github/codeql-action/upload-sarif@8214744c546c1e5c8f03dde8fab3a7353211988d # v3.26.7 + uses: github/codeql-action/upload-sarif@294a9d92911152fe08befb9ec03e240add280cb3 # v3.26.8 with: sarif_file: results.sarif From bddf1361f8a72b80471ff97536f9c69fef82fa50 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Thu, 19 Sep 2024 16:56:56 +0000 Subject: [PATCH 084/885] Update dependency org.jetbrains.kotlinx:kotlinx-serialization-json to v1.7.3 Signed-off-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- app/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/build.gradle b/app/build.gradle index 96c21d77cd..50bcca20ff 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -189,7 +189,7 @@ dependencies { implementation fileTree(include: ['*'], dir: 'libs') - implementation "org.jetbrains.kotlinx:kotlinx-serialization-json:1.7.2" + implementation "org.jetbrains.kotlinx:kotlinx-serialization-json:1.7.3" implementation 'androidx.appcompat:appcompat:1.7.0' implementation 'com.google.android.material:material:1.12.0' From b080e891bb4409494a1597a2fc772edb9e3a9b70 Mon Sep 17 00:00:00 2001 From: Marcel Hibbe Date: Wed, 18 Sep 2024 16:46:32 +0200 Subject: [PATCH 085/885] fix to not remove call buttons for federated conversations after 30 seconds After 30 seconds (when the capabilities were updated) the call buttons of federated conversations were removed (this was done back then when fed calls were not implemented). However this happened not always because of the check "if (this::spreedCapabilities.isInitialized) {...." It seems this check sometimes is false when it's supposed to be true. This has be to further investigated and has to be be simplified/improved by a cleaner architecture. Signed-off-by: Marcel Hibbe --- app/src/main/java/com/nextcloud/talk/chat/ChatActivity.kt | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/app/src/main/java/com/nextcloud/talk/chat/ChatActivity.kt b/app/src/main/java/com/nextcloud/talk/chat/ChatActivity.kt index 94ffafe28a..f71e164646 100644 --- a/app/src/main/java/com/nextcloud/talk/chat/ChatActivity.kt +++ b/app/src/main/java/com/nextcloud/talk/chat/ChatActivity.kt @@ -2812,10 +2812,7 @@ class ChatActivity : menu.removeItem(R.id.shared_items) } - if (currentConversation!!.remoteServer != null) { - menu.removeItem(R.id.conversation_video_call) - menu.removeItem(R.id.conversation_voice_call) - } else if (CapabilitiesUtil.isAbleToCall(spreedCapabilities)) { + if (CapabilitiesUtil.isAbleToCall(spreedCapabilities)) { conversationVoiceCallMenuItem = menu.findItem(R.id.conversation_voice_call) conversationVideoMenuItem = menu.findItem(R.id.conversation_video_call) From 44e87dbd4217110894f99f19bd37819a60d30758 Mon Sep 17 00:00:00 2001 From: Nextcloud Android Bot Date: Mon, 23 Sep 2024 03:12:32 +0000 Subject: [PATCH 086/885] Weekly 20.1.0 Alpha 05 --- app/build.gradle | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/app/build.gradle b/app/build.gradle index 50bcca20ff..cde12d1169 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -40,8 +40,8 @@ android { // mayor.minor.hotfix.increment (for increment: 01-50=Alpha / 51-89=RC / 90-99=stable) // xx .xxx .xx .xx - versionCode 200010004 - versionName "20.1.0 Alpha 04" + versionCode 200010005 + versionName "20.1.0 Alpha 05" flavorDimensions "default" renderscriptTargetApi 19 From 317f74580664ca08e8f3751589246919a13cc34d Mon Sep 17 00:00:00 2001 From: sowjanyakch Date: Wed, 18 Sep 2024 17:57:54 +0200 Subject: [PATCH 087/885] Only display delete icon when user avatar is selected Signed-off-by: sowjanyakch --- .../ConversationCreationActivity.kt | 24 +++++++++++-------- 1 file changed, 14 insertions(+), 10 deletions(-) diff --git a/app/src/main/java/com/nextcloud/talk/conversationcreation/ConversationCreationActivity.kt b/app/src/main/java/com/nextcloud/talk/conversationcreation/ConversationCreationActivity.kt index 89acf6c856..e70a44b1a7 100644 --- a/app/src/main/java/com/nextcloud/talk/conversationcreation/ConversationCreationActivity.kt +++ b/app/src/main/java/com/nextcloud/talk/conversationcreation/ConversationCreationActivity.kt @@ -209,7 +209,8 @@ fun ConversationCreationScreen( imagePickerLauncher = imagePickerLauncher, remoteFilePickerLauncher = remoteFilePickerLauncher, cameraLauncher = cameraLauncher, - onDeleteImage = { selectedImageUri = null } + onDeleteImage = { selectedImageUri = null }, + selectedImageUri = selectedImageUri ) ConversationNameAndDescription(conversationCreationViewModel) @@ -258,7 +259,8 @@ fun UploadAvatar( imagePickerLauncher: ManagedActivityResultLauncher, remoteFilePickerLauncher: ManagedActivityResultLauncher, cameraLauncher: ManagedActivityResultLauncher, - onDeleteImage: () -> Unit + onDeleteImage: () -> Unit, + selectedImageUri: Uri? ) { Row( modifier = Modifier @@ -299,14 +301,16 @@ fun UploadAvatar( ) } - IconButton(onClick = { - onDeleteImage() - }) { - Icon( - painter = painterResource(id = R.drawable.ic_delete_grey600_24dp), - contentDescription = null, - modifier = Modifier.size(24.dp) - ) + if (selectedImageUri != null) { + IconButton(onClick = { + onDeleteImage() + }) { + Icon( + painter = painterResource(id = R.drawable.ic_delete_grey600_24dp), + contentDescription = null, + modifier = Modifier.size(24.dp) + ) + } } } } From bc0223680110f0d0a6f2dd1110b48fdcb38c7557 Mon Sep 17 00:00:00 2001 From: sowjanyakch Date: Wed, 18 Sep 2024 18:06:32 +0200 Subject: [PATCH 088/885] Make Conversation name text limit to single line Signed-off-by: sowjanyakch --- .../talk/conversationcreation/ConversationCreationActivity.kt | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/app/src/main/java/com/nextcloud/talk/conversationcreation/ConversationCreationActivity.kt b/app/src/main/java/com/nextcloud/talk/conversationcreation/ConversationCreationActivity.kt index e70a44b1a7..9708f13be2 100644 --- a/app/src/main/java/com/nextcloud/talk/conversationcreation/ConversationCreationActivity.kt +++ b/app/src/main/java/com/nextcloud/talk/conversationcreation/ConversationCreationActivity.kt @@ -327,7 +327,8 @@ fun ConversationNameAndDescription(conversationCreationViewModel: ConversationCr label = { Text(text = stringResource(id = R.string.nc_call_name)) }, modifier = Modifier .padding(start = 16.dp, end = 16.dp) - .fillMaxWidth() + .fillMaxWidth(), + singleLine = true ) OutlinedTextField( value = conversationDescription.value, From 4dd22d62238e11889b10b1ed16088c6d5150d9a4 Mon Sep 17 00:00:00 2001 From: sowjanyakch Date: Wed, 18 Sep 2024 18:34:52 +0200 Subject: [PATCH 089/885] Get selectedImageUri from ViewModel Signed-off-by: sowjanyakch --- .../ConversationCreationActivity.kt | 18 ++++++++---------- .../ConversationCreationViewModel.kt | 13 +++++++++---- 2 files changed, 17 insertions(+), 14 deletions(-) diff --git a/app/src/main/java/com/nextcloud/talk/conversationcreation/ConversationCreationActivity.kt b/app/src/main/java/com/nextcloud/talk/conversationcreation/ConversationCreationActivity.kt index 9708f13be2..518c2e61ef 100644 --- a/app/src/main/java/com/nextcloud/talk/conversationcreation/ConversationCreationActivity.kt +++ b/app/src/main/java/com/nextcloud/talk/conversationcreation/ConversationCreationActivity.kt @@ -138,14 +138,14 @@ fun ConversationCreationScreen( context: Context, pickImage: PickImage ) { - var selectedImageUri by remember { mutableStateOf(null) } + val selectedImageUri = conversationCreationViewModel.selectedImageUriState.collectAsState().value val imagePickerLauncher = rememberLauncherForActivityResult( contract = ActivityResultContracts.StartActivityForResult() ) { result -> if (result.resultCode == Activity.RESULT_OK) { pickImage.onImagePickerResult(result.data) { uri -> - selectedImageUri = uri + conversationCreationViewModel.updateSelectedImageUri(uri) } } } @@ -205,18 +205,18 @@ fun ConversationCreationScreen( DefaultUserAvatar(selectedImageUri) UploadAvatar( pickImage = pickImage, - onImageSelected = { uri -> selectedImageUri = uri }, + onImageSelected = { uri -> conversationCreationViewModel.updateSelectedImageUri(uri) }, imagePickerLauncher = imagePickerLauncher, remoteFilePickerLauncher = remoteFilePickerLauncher, cameraLauncher = cameraLauncher, - onDeleteImage = { selectedImageUri = null }, + onDeleteImage = { conversationCreationViewModel.updateSelectedImageUri(null) }, selectedImageUri = selectedImageUri ) ConversationNameAndDescription(conversationCreationViewModel) AddParticipants(launcher, context, conversationCreationViewModel) RoomCreationOptions(conversationCreationViewModel) - CreateConversation(conversationCreationViewModel, context, selectedImageUri) + CreateConversation(conversationCreationViewModel, context) } } ) @@ -550,11 +550,11 @@ fun ConversationOptions( @Composable fun ShowPasswordDialog(onDismiss: () -> Unit, conversationCreationViewModel: ConversationCreationViewModel) { + var password by remember { mutableStateOf("") } AlertDialog( containerColor = colorResource(id = R.color.dialog_background), - onDismissRequest = onDismiss, confirmButton = { Button(onClick = { @@ -585,8 +585,7 @@ fun ShowPasswordDialog(onDismiss: () -> Unit, conversationCreationViewModel: Con @Composable fun CreateConversation( conversationCreationViewModel: ConversationCreationViewModel, - context: Context, - selectedImageUri: Uri? + context: Context ) { val selectedParticipants by conversationCreationViewModel.selectedParticipants.collectAsState() Box( @@ -600,8 +599,7 @@ fun CreateConversation( conversationCreationViewModel.createRoomAndAddParticipants( roomType = CompanionClass.ROOM_TYPE_GROUP, conversationName = conversationCreationViewModel.roomName.value, - participants = selectedParticipants.toSet(), - selectedImageUri = selectedImageUri + participants = selectedParticipants.toSet() ) { roomToken -> val bundle = Bundle() bundle.putString(BundleKeys.KEY_ROOM_TOKEN, roomToken) diff --git a/app/src/main/java/com/nextcloud/talk/conversationcreation/ConversationCreationViewModel.kt b/app/src/main/java/com/nextcloud/talk/conversationcreation/ConversationCreationViewModel.kt index 38586a6e38..99fa5ae679 100644 --- a/app/src/main/java/com/nextcloud/talk/conversationcreation/ConversationCreationViewModel.kt +++ b/app/src/main/java/com/nextcloud/talk/conversationcreation/ConversationCreationViewModel.kt @@ -32,6 +32,10 @@ class ConversationCreationViewModel @Inject constructor( val selectedParticipants: StateFlow> = _selectedParticipants private val roomViewState = MutableStateFlow(RoomUIState.None) + private val selectedImageUri = MutableStateFlow(null) + val selectedImageUriState:StateFlow = selectedImageUri + + private val _currentUser = userManager.currentUser.blockingGet() val currentUser: User = _currentUser @@ -39,6 +43,10 @@ class ConversationCreationViewModel @Inject constructor( _selectedParticipants.value = participants } + fun updateSelectedImageUri(uri:Uri?){ + selectedImageUri.value = uri + } + private val _roomName = MutableStateFlow("") val roomName: StateFlow = _roomName private val _password = MutableStateFlow("") @@ -66,7 +74,6 @@ class ConversationCreationViewModel @Inject constructor( roomType: String, conversationName: String, participants: Set, - selectedImageUri: Uri?, onRoomCreated: (String) -> Unit ) { val scope = when { @@ -109,9 +116,7 @@ class ConversationCreationViewModel @Inject constructor( repository.setPassword(token, _password.value) } repository.openConversation(token, scope) - if (selectedImageUri != null) { - repository.uploadConversationAvatar(selectedImageUri.toFile(), token) - } + selectedImageUri.value?.let { repository.uploadConversationAvatar(it.toFile(), token) } onRoomCreated(token) } catch (exception: Exception) { allowGuestsResult.value = AllowGuestsUiState.Error(exception.message ?: "") From 384ba6945fe8557ea9fa243de296abf266a122b1 Mon Sep 17 00:00:00 2001 From: sowjanyakch Date: Thu, 19 Sep 2024 14:57:12 +0200 Subject: [PATCH 090/885] ktlint format Signed-off-by: sowjanyakch --- .../java/com/nextcloud/talk/activities/CallActivity.kt | 4 +++- app/src/main/java/com/nextcloud/talk/chat/ChatActivity.kt | 2 +- .../conversationcreation/ConversationCreationActivity.kt | 8 ++------ .../conversationcreation/ConversationCreationViewModel.kt | 5 ++--- 4 files changed, 8 insertions(+), 11 deletions(-) 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 6376ce8fe3..4302e27549 100644 --- a/app/src/main/java/com/nextcloud/talk/activities/CallActivity.kt +++ b/app/src/main/java/com/nextcloud/talk/activities/CallActivity.kt @@ -1633,7 +1633,9 @@ class CallActivity : CallBaseActivity() { private fun callOrJoinRoomViaWebSocket() { if (hasExternalSignalingServer) { webSocketClient!!.joinRoomWithRoomTokenAndSession( - roomToken!!, callSession, externalSignalingServer!!.federation + roomToken!!, + callSession, + externalSignalingServer!!.federation ) } else { performCall() diff --git a/app/src/main/java/com/nextcloud/talk/chat/ChatActivity.kt b/app/src/main/java/com/nextcloud/talk/chat/ChatActivity.kt index f71e164646..7d4a4d9027 100644 --- a/app/src/main/java/com/nextcloud/talk/chat/ChatActivity.kt +++ b/app/src/main/java/com/nextcloud/talk/chat/ChatActivity.kt @@ -3240,7 +3240,7 @@ class ChatActivity : val lon = data["longitude"]!! metaData = "{\"type\":\"geo-location\",\"id\":\"geo:$lat,$lon\",\"latitude\":\"$lat\"," + - "\"longitude\":\"$lon\",\"name\":\"$name\"}" + "\"longitude\":\"$lon\",\"name\":\"$name\"}" } when (type) { diff --git a/app/src/main/java/com/nextcloud/talk/conversationcreation/ConversationCreationActivity.kt b/app/src/main/java/com/nextcloud/talk/conversationcreation/ConversationCreationActivity.kt index 518c2e61ef..2e5e833238 100644 --- a/app/src/main/java/com/nextcloud/talk/conversationcreation/ConversationCreationActivity.kt +++ b/app/src/main/java/com/nextcloud/talk/conversationcreation/ConversationCreationActivity.kt @@ -138,7 +138,7 @@ fun ConversationCreationScreen( context: Context, pickImage: PickImage ) { - val selectedImageUri = conversationCreationViewModel.selectedImageUriState.collectAsState().value + val selectedImageUri = conversationCreationViewModel.selectedImageUriState.collectAsState().value val imagePickerLauncher = rememberLauncherForActivityResult( contract = ActivityResultContracts.StartActivityForResult() @@ -550,7 +550,6 @@ fun ConversationOptions( @Composable fun ShowPasswordDialog(onDismiss: () -> Unit, conversationCreationViewModel: ConversationCreationViewModel) { - var password by remember { mutableStateOf("") } AlertDialog( @@ -583,10 +582,7 @@ fun ShowPasswordDialog(onDismiss: () -> Unit, conversationCreationViewModel: Con } @Composable -fun CreateConversation( - conversationCreationViewModel: ConversationCreationViewModel, - context: Context -) { +fun CreateConversation(conversationCreationViewModel: ConversationCreationViewModel, context: Context) { val selectedParticipants by conversationCreationViewModel.selectedParticipants.collectAsState() Box( modifier = Modifier diff --git a/app/src/main/java/com/nextcloud/talk/conversationcreation/ConversationCreationViewModel.kt b/app/src/main/java/com/nextcloud/talk/conversationcreation/ConversationCreationViewModel.kt index 99fa5ae679..c30630ffba 100644 --- a/app/src/main/java/com/nextcloud/talk/conversationcreation/ConversationCreationViewModel.kt +++ b/app/src/main/java/com/nextcloud/talk/conversationcreation/ConversationCreationViewModel.kt @@ -33,8 +33,7 @@ class ConversationCreationViewModel @Inject constructor( private val roomViewState = MutableStateFlow(RoomUIState.None) private val selectedImageUri = MutableStateFlow(null) - val selectedImageUriState:StateFlow = selectedImageUri - + val selectedImageUriState: StateFlow = selectedImageUri private val _currentUser = userManager.currentUser.blockingGet() val currentUser: User = _currentUser @@ -43,7 +42,7 @@ class ConversationCreationViewModel @Inject constructor( _selectedParticipants.value = participants } - fun updateSelectedImageUri(uri:Uri?){ + fun updateSelectedImageUri(uri: Uri?) { selectedImageUri.value = uri } From 8bf9e3552e3dcbbdd2244902cf6e645bea0123b3 Mon Sep 17 00:00:00 2001 From: sowjanyakch Date: Fri, 20 Sep 2024 16:07:43 +0200 Subject: [PATCH 091/885] rename variable selectedImageUri Signed-off-by: sowjanyakch --- .../conversationcreation/ConversationCreationActivity.kt | 2 +- .../conversationcreation/ConversationCreationViewModel.kt | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/app/src/main/java/com/nextcloud/talk/conversationcreation/ConversationCreationActivity.kt b/app/src/main/java/com/nextcloud/talk/conversationcreation/ConversationCreationActivity.kt index 2e5e833238..74bf4d6150 100644 --- a/app/src/main/java/com/nextcloud/talk/conversationcreation/ConversationCreationActivity.kt +++ b/app/src/main/java/com/nextcloud/talk/conversationcreation/ConversationCreationActivity.kt @@ -138,7 +138,7 @@ fun ConversationCreationScreen( context: Context, pickImage: PickImage ) { - val selectedImageUri = conversationCreationViewModel.selectedImageUriState.collectAsState().value + val selectedImageUri = conversationCreationViewModel.selectedImageUri.collectAsState().value val imagePickerLauncher = rememberLauncherForActivityResult( contract = ActivityResultContracts.StartActivityForResult() diff --git a/app/src/main/java/com/nextcloud/talk/conversationcreation/ConversationCreationViewModel.kt b/app/src/main/java/com/nextcloud/talk/conversationcreation/ConversationCreationViewModel.kt index c30630ffba..0fa663d889 100644 --- a/app/src/main/java/com/nextcloud/talk/conversationcreation/ConversationCreationViewModel.kt +++ b/app/src/main/java/com/nextcloud/talk/conversationcreation/ConversationCreationViewModel.kt @@ -32,8 +32,8 @@ class ConversationCreationViewModel @Inject constructor( val selectedParticipants: StateFlow> = _selectedParticipants private val roomViewState = MutableStateFlow(RoomUIState.None) - private val selectedImageUri = MutableStateFlow(null) - val selectedImageUriState: StateFlow = selectedImageUri + private val _selectedImageUri = MutableStateFlow(null) + val selectedImageUri: StateFlow = _selectedImageUri private val _currentUser = userManager.currentUser.blockingGet() val currentUser: User = _currentUser @@ -43,7 +43,7 @@ class ConversationCreationViewModel @Inject constructor( } fun updateSelectedImageUri(uri: Uri?) { - selectedImageUri.value = uri + _selectedImageUri.value = uri } private val _roomName = MutableStateFlow("") From 4f9122b685f5c5bbdefe101afa9c27c205cd33fa Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Mon, 23 Sep 2024 22:55:13 +0000 Subject: [PATCH 092/885] Update dependency gradle to v8.10.2 Signed-off-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- gradle/wrapper/gradle-wrapper.properties | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties index 0aaefbcaf0..df97d72b8b 100644 --- a/gradle/wrapper/gradle-wrapper.properties +++ b/gradle/wrapper/gradle-wrapper.properties @@ -1,6 +1,6 @@ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-8.10.1-bin.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-8.10.2-bin.zip networkTimeout=10000 validateDistributionUrl=true zipStoreBase=GRADLE_USER_HOME From 78a55c016f64d077840134346a359ae953bcba22 Mon Sep 17 00:00:00 2001 From: sowjanyakch Date: Fri, 20 Sep 2024 16:45:16 +0200 Subject: [PATCH 093/885] change functionPattern to support composable functions and ktlintFormat Signed-off-by: sowjanyakch --- detekt.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/detekt.yml b/detekt.yml index 164d9ca8e6..8dd64c30cf 100644 --- a/detekt.yml +++ b/detekt.yml @@ -278,7 +278,7 @@ naming: minimumFunctionNameLength: 3 FunctionNaming: active: true - functionPattern: '^([a-z$][a-zA-Z$0-9]*)|(`.*`)$' + functionPattern: '^([a-z$A-Z][a-zA-Z$0-9]*)|(`.*`)$' excludeClassPattern: '$^' ignoreOverridden: true excludes: From aeacfa09b6037eca18a7c03df01134201e03fcf8 Mon Sep 17 00:00:00 2001 From: Marcel Hibbe Date: Tue, 24 Sep 2024 14:18:25 +0200 Subject: [PATCH 094/885] avoid UninitializedPropertyAccessException for spreedCapabilities reported issue on gplay console was: Exception kotlin.UninitializedPropertyAccessException: lateinit property spreedCapabilities has not been initialized at com.nextcloud.talk.chat.ChatActivity.getSpreedCapabilities (ChatActivity.kt:284) at com.nextcloud.talk.chat.ChatActivity.processExpiredMessages (ChatActivity.kt:2536) at com.nextcloud.talk.chat.ChatActivity.access$processExpiredMessages (ChatActivity.kt:204) at com.nextcloud.talk.chat.ChatActivity$initObservers$10$1.invokeSuspend (ChatActivity.kt:820) This is just a hotfix while hoping processExpiredMessages is executed again while spreedCapabilities are available. To improve the situation in the long term, we should move more logic to viewModel and have better control over sequence of actions. Signed-off-by: Marcel Hibbe --- app/src/main/java/com/nextcloud/talk/chat/ChatActivity.kt | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/app/src/main/java/com/nextcloud/talk/chat/ChatActivity.kt b/app/src/main/java/com/nextcloud/talk/chat/ChatActivity.kt index 7d4a4d9027..dda05c6e7c 100644 --- a/app/src/main/java/com/nextcloud/talk/chat/ChatActivity.kt +++ b/app/src/main/java/com/nextcloud/talk/chat/ChatActivity.kt @@ -2535,8 +2535,12 @@ class ChatActivity : } } - if (CapabilitiesUtil.hasSpreedFeatureCapability(spreedCapabilities, SpreedFeatures.MESSAGE_EXPIRATION)) { - deleteExpiredMessages() + if (this::spreedCapabilities.isInitialized) { + if (CapabilitiesUtil.hasSpreedFeatureCapability(spreedCapabilities, SpreedFeatures.MESSAGE_EXPIRATION)) { + deleteExpiredMessages() + } + } else { + Log.w(TAG, "spreedCapabilities are not initialized in processExpiredMessages()") } } From b78267d96fc14ec5766e3a515957f6b8afe15e9b Mon Sep 17 00:00:00 2001 From: Marcel Hibbe Date: Tue, 24 Sep 2024 13:49:18 +0200 Subject: [PATCH 095/885] try to avoid NPE for currentConversation On gplay console the following NPE was reported for the line participantPermissions = ParticipantPermissions(spreedCapabilities, currentConversation!!) E FATAL EXCEPTION: main Process: com.nextcloud.talk2, PID: 6626 java.lang.NullPointerException at com.nextcloud.talk.chat.ChatActivity.initObservers$lambda$13(ChatActivity.kt:583) at com.nextcloud.talk.chat.ChatActivity.$r8$lambda$QKH5JCFLmCzRMlSJ-EV-m4IW5ig(Unknown Source:0) which seems that currentConversation was null. If it would have been spreedCapabilities, then the error would have been thrown in the line before.. A reason MAY BE that the observer is triggered before setData on the ViewModel is executed. While this fix is just not executing code when currentConversation is null, it's unsure if it will follow up problems (like an empty chat) or if the observer is triggered another time when currentConversation is available. So it's just a hotfix. To improve the situation in the long term, we should move more logic to viewModel and only use Flow instead to mix it with LiveData. Signed-off-by: Marcel Hibbe --- .../com/nextcloud/talk/chat/ChatActivity.kt | 81 +++++++++++-------- 1 file changed, 48 insertions(+), 33 deletions(-) diff --git a/app/src/main/java/com/nextcloud/talk/chat/ChatActivity.kt b/app/src/main/java/com/nextcloud/talk/chat/ChatActivity.kt index dda05c6e7c..8b739ff5de 100644 --- a/app/src/main/java/com/nextcloud/talk/chat/ChatActivity.kt +++ b/app/src/main/java/com/nextcloud/talk/chat/ChatActivity.kt @@ -571,48 +571,63 @@ class ChatActivity : chatViewModel.getCapabilitiesViewState.observe(this) { state -> when (state) { is ChatViewModel.GetCapabilitiesUpdateState -> { - spreedCapabilities = state.spreedCapabilities - chatApiVersion = ApiUtils.getChatApiVersion(spreedCapabilities, intArrayOf(1)) - participantPermissions = ParticipantPermissions(spreedCapabilities, currentConversation!!) - - invalidateOptionsMenu() - checkShowCallButtons() - checkLobbyState() - updateRoomTimerHandler() + if (currentConversation != null) { + spreedCapabilities = state.spreedCapabilities + chatApiVersion = ApiUtils.getChatApiVersion(spreedCapabilities, intArrayOf(1)) + participantPermissions = ParticipantPermissions(spreedCapabilities, currentConversation!!) + + invalidateOptionsMenu() + checkShowCallButtons() + checkLobbyState() + updateRoomTimerHandler() + } else { + Log.w( + TAG, + "currentConversation was null in observer ChatViewModel.GetCapabilitiesUpdateState" + ) + } } is ChatViewModel.GetCapabilitiesInitialLoadState -> { - spreedCapabilities = state.spreedCapabilities - chatApiVersion = ApiUtils.getChatApiVersion(spreedCapabilities, intArrayOf(1)) - participantPermissions = ParticipantPermissions(spreedCapabilities, currentConversation!!) - - supportFragmentManager.commit { - setReorderingAllowed(true) // optimizes out redundant replace operations - replace(R.id.fragment_container_activity_chat, messageInputFragment) - } + if (currentConversation != null) { + spreedCapabilities = state.spreedCapabilities + chatApiVersion = ApiUtils.getChatApiVersion(spreedCapabilities, intArrayOf(1)) + participantPermissions = ParticipantPermissions(spreedCapabilities, currentConversation!!) + + supportFragmentManager.commit { + setReorderingAllowed(true) // optimizes out redundant replace operations + replace(R.id.fragment_container_activity_chat, messageInputFragment) + } - joinRoomWithPassword() + joinRoomWithPassword() - if (conversationUser?.userId != "?" && - CapabilitiesUtil.hasSpreedFeatureCapability(spreedCapabilities, SpreedFeatures.MENTION_FLAG) - ) { - binding.chatToolbar.setOnClickListener { _ -> showConversationInfoScreen() } - } + if (conversationUser?.userId != "?" && + CapabilitiesUtil.hasSpreedFeatureCapability(spreedCapabilities, SpreedFeatures.MENTION_FLAG) + ) { + binding.chatToolbar.setOnClickListener { _ -> showConversationInfoScreen() } + } - loadAvatarForStatusBar() - setupSwipeToReply() - setActionBarTitle() + loadAvatarForStatusBar() + setupSwipeToReply() + setActionBarTitle() - checkShowCallButtons() - checkLobbyState() - updateRoomTimerHandler() + checkShowCallButtons() + checkLobbyState() + updateRoomTimerHandler() - val urlForChatting = ApiUtils.getUrlForChat(chatApiVersion, conversationUser?.baseUrl, roomToken) + val urlForChatting = + ApiUtils.getUrlForChat(chatApiVersion, conversationUser?.baseUrl, roomToken) - if (adapter?.isEmpty == true) { - chatViewModel.loadMessages( - withCredentials = credentials!!, - withUrl = urlForChatting + if (adapter?.isEmpty == true) { + chatViewModel.loadMessages( + withCredentials = credentials!!, + withUrl = urlForChatting + ) + } + } else { + Log.w( + TAG, + "currentConversation was null in observer ChatViewModel.GetCapabilitiesInitialLoadState" ) } } From 1302c8516659c388b96da08714015ed4a729a4f4 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Tue, 24 Sep 2024 14:19:56 +0000 Subject: [PATCH 096/885] Update actions/setup-java action to v4.4.0 Signed-off-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- .github/workflows/analysis.yml | 2 +- .github/workflows/assembleFlavors.yml | 2 +- .github/workflows/check.yml | 2 +- .github/workflows/codeql.yml | 2 +- .github/workflows/qa.yml | 2 +- .github/workflows/unit-tests.yml | 2 +- 6 files changed, 6 insertions(+), 6 deletions(-) diff --git a/.github/workflows/analysis.yml b/.github/workflows/analysis.yml index d24bd37feb..b5be46d99a 100644 --- a/.github/workflows/analysis.yml +++ b/.github/workflows/analysis.yml @@ -49,7 +49,7 @@ jobs: repository: ${{ steps.get-vars.outputs.repo }} ref: ${{ steps.get-vars.outputs.branch }} - name: Set up JDK 17 - uses: actions/setup-java@2dfa2011c5b2a0f1489bf9e433881c92c1631f88 # v4.3.0 + uses: actions/setup-java@b36c23c0d998641eff861008f374ee103c25ac73 # v4.4.0 with: distribution: "temurin" java-version: 17 diff --git a/.github/workflows/assembleFlavors.yml b/.github/workflows/assembleFlavors.yml index 428773e390..3680c9c4b9 100644 --- a/.github/workflows/assembleFlavors.yml +++ b/.github/workflows/assembleFlavors.yml @@ -24,7 +24,7 @@ jobs: steps: - uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332 # v4.1.7 - name: set up JDK 17 - uses: actions/setup-java@2dfa2011c5b2a0f1489bf9e433881c92c1631f88 # v4.3.0 + uses: actions/setup-java@b36c23c0d998641eff861008f374ee103c25ac73 # v4.4.0 with: distribution: "temurin" java-version: 17 diff --git a/.github/workflows/check.yml b/.github/workflows/check.yml index 9c1ae7d89a..5e276c62c2 100644 --- a/.github/workflows/check.yml +++ b/.github/workflows/check.yml @@ -24,7 +24,7 @@ jobs: steps: - uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332 # v4.1.7 - name: Set up JDK 17 - uses: actions/setup-java@2dfa2011c5b2a0f1489bf9e433881c92c1631f88 # v4.3.0 + uses: actions/setup-java@b36c23c0d998641eff861008f374ee103c25ac73 # v4.4.0 with: distribution: "temurin" java-version: 17 diff --git a/.github/workflows/codeql.yml b/.github/workflows/codeql.yml index f1baac3924..10c85edfca 100644 --- a/.github/workflows/codeql.yml +++ b/.github/workflows/codeql.yml @@ -43,7 +43,7 @@ jobs: with: languages: ${{ matrix.language }} - name: Set up JDK 17 - uses: actions/setup-java@2dfa2011c5b2a0f1489bf9e433881c92c1631f88 # v4.3.0 + uses: actions/setup-java@b36c23c0d998641eff861008f374ee103c25ac73 # v4.4.0 with: distribution: "temurin" java-version: 17 diff --git a/.github/workflows/qa.yml b/.github/workflows/qa.yml index 71cb6718dd..2fcc86e5bf 100644 --- a/.github/workflows/qa.yml +++ b/.github/workflows/qa.yml @@ -25,7 +25,7 @@ jobs: - uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332 # v4.1.7 if: ${{ steps.check-secrets.outputs.ok == 'true' }} - name: set up JDK 17 - uses: actions/setup-java@2dfa2011c5b2a0f1489bf9e433881c92c1631f88 # v4.3.0 + uses: actions/setup-java@b36c23c0d998641eff861008f374ee103c25ac73 # v4.4.0 if: ${{ steps.check-secrets.outputs.ok == 'true' }} with: distribution: "temurin" diff --git a/.github/workflows/unit-tests.yml b/.github/workflows/unit-tests.yml index 9696048d53..a020dc8608 100644 --- a/.github/workflows/unit-tests.yml +++ b/.github/workflows/unit-tests.yml @@ -23,7 +23,7 @@ jobs: steps: - uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332 # v4.1.7 - name: Set up JDK 17 - uses: actions/setup-java@2dfa2011c5b2a0f1489bf9e433881c92c1631f88 # v4.3.0 + uses: actions/setup-java@b36c23c0d998641eff861008f374ee103c25ac73 # v4.4.0 with: distribution: "temurin" java-version: 17 From 7dc70514812a697339e3d456598de69795e1c271 Mon Sep 17 00:00:00 2001 From: Marcel Hibbe Date: Tue, 24 Sep 2024 16:25:33 +0200 Subject: [PATCH 097/885] Fix crash when externalSignalingServer is empty Otherwise, following crash happened, as it was tried to deal with the empty url: 2024-09-24 15:10:30.719 17765-17765 WebSocketInstance com.nextcloud.talk2 D restartWebSocket: /spreed 2024-09-24 15:10:30.722 17765-17765 System.err com.nextcloud.talk2 W java.lang.IllegalArgumentException: Expected URL scheme 'http' or 'https' but no scheme was found for /spree... 2024-09-24 15:10:30.723 17765-17765 System.err com.nextcloud.talk2 W at okhttp3.HttpUrl$Builder.parse$okhttp(HttpUrl.kt:1261) Signed-off-by: Marcel Hibbe --- app/src/main/java/com/nextcloud/talk/chat/ChatActivity.kt | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/app/src/main/java/com/nextcloud/talk/chat/ChatActivity.kt b/app/src/main/java/com/nextcloud/talk/chat/ChatActivity.kt index 7d4a4d9027..b3dff56de4 100644 --- a/app/src/main/java/com/nextcloud/talk/chat/ChatActivity.kt +++ b/app/src/main/java/com/nextcloud/talk/chat/ChatActivity.kt @@ -2448,7 +2448,9 @@ class ChatActivity : } override fun onNext(signalingSettingsOverall: SignalingSettingsOverall) { - if (signalingSettingsOverall.ocs!!.settings!!.externalSignalingServer == null) { + if (signalingSettingsOverall.ocs!!.settings!!.externalSignalingServer == null || + signalingSettingsOverall.ocs!!.settings!!.externalSignalingServer?.isEmpty() == true + ) { return } From 8e9c152988fbbced4db0436b627e7800bc9feb98 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Tue, 24 Sep 2024 20:07:01 +0000 Subject: [PATCH 098/885] Update github/codeql-action action to v3.26.9 Signed-off-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- .github/workflows/codeql.yml | 4 ++-- .github/workflows/scorecard.yml | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/codeql.yml b/.github/workflows/codeql.yml index 10c85edfca..9970c2fb7e 100644 --- a/.github/workflows/codeql.yml +++ b/.github/workflows/codeql.yml @@ -39,7 +39,7 @@ jobs: with: swap-size-gb: 10 - name: Initialize CodeQL - uses: github/codeql-action/init@294a9d92911152fe08befb9ec03e240add280cb3 # v3.26.8 + uses: github/codeql-action/init@461ef6c76dfe95d5c364de2f431ddbd31a417628 # v3.26.9 with: languages: ${{ matrix.language }} - name: Set up JDK 17 @@ -53,4 +53,4 @@ jobs: echo "org.gradle.jvmargs=-Xmx4g -XX:MaxMetaspaceSize=512m -XX:+HeapDumpOnOutOfMemoryError" > "$HOME/.gradle/gradle.properties" ./gradlew assembleDebug - name: Perform CodeQL Analysis - uses: github/codeql-action/analyze@294a9d92911152fe08befb9ec03e240add280cb3 # v3.26.8 + uses: github/codeql-action/analyze@461ef6c76dfe95d5c364de2f431ddbd31a417628 # v3.26.9 diff --git a/.github/workflows/scorecard.yml b/.github/workflows/scorecard.yml index e5e6986d15..8a8d98cb16 100644 --- a/.github/workflows/scorecard.yml +++ b/.github/workflows/scorecard.yml @@ -42,6 +42,6 @@ jobs: # Upload the results to GitHub's code scanning dashboard. - name: "Upload to code-scanning" - uses: github/codeql-action/upload-sarif@294a9d92911152fe08befb9ec03e240add280cb3 # v3.26.8 + uses: github/codeql-action/upload-sarif@461ef6c76dfe95d5c364de2f431ddbd31a417628 # v3.26.9 with: sarif_file: results.sarif From 372fc3a0db6d88fed1a6da5a9c291f926b403745 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Wed, 25 Sep 2024 02:03:28 +0000 Subject: [PATCH 099/885] Update dependency com.github.spotbugs.snom:spotbugs-gradle-plugin to v6.0.23 Signed-off-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build.gradle b/build.gradle index 7b8f49a831..82c6dfff15 100644 --- a/build.gradle +++ b/build.gradle @@ -25,7 +25,7 @@ buildscript { classpath 'com.android.tools.build:gradle:8.6.1' classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:${kotlinVersion}" classpath "org.jetbrains.kotlin:kotlin-serialization:${kotlinVersion}" - classpath 'com.github.spotbugs.snom:spotbugs-gradle-plugin:6.0.22' + classpath 'com.github.spotbugs.snom:spotbugs-gradle-plugin:6.0.23' classpath "io.gitlab.arturbosch.detekt:detekt-gradle-plugin:1.23.7" classpath "org.jlleitschuh.gradle:ktlint-gradle:12.1.1" classpath "com.google.dagger:hilt-android-gradle-plugin:$hilt_version" From b1cc652657e1a03ba667ca9d4638d9233ac38f7c Mon Sep 17 00:00:00 2001 From: Nextcloud bot Date: Wed, 25 Sep 2024 02:53:27 +0000 Subject: [PATCH 100/885] Fix(l10n): Update translations from Transifex Signed-off-by: Nextcloud bot --- app/src/main/res/values-cs-rCZ/strings.xml | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/app/src/main/res/values-cs-rCZ/strings.xml b/app/src/main/res/values-cs-rCZ/strings.xml index 65dfa5e89e..620e729cdb 100644 --- a/app/src/main/res/values-cs-rCZ/strings.xml +++ b/app/src/main/res/values-cs-rCZ/strings.xml @@ -164,7 +164,12 @@ Zařízení Otevřít diagnostickou obrazovku Otevřít dontkillmyapp.com + Ještě nezaregistrováno na serveru + Metainformace Vytváření výkazu o systému + Kanál upozorňování na hovory zapnut? + Kanál upozorňování na zprávy zapnut? + Oprávnění upozornění Telefon Verze Talk na serveru Verze serveru @@ -185,7 +190,10 @@ Ano Nepodařilo se získat zobrazované jméno, přerušuje se Nepodařilo se uložit zobrazované jméno, přerušuje se + Upravit ikonu Upravit + Upravit text zprávy + Upraveno správcem E-mail 8 hodin 4 týdny @@ -198,6 +206,9 @@ Nepodařilo se získat nastavení signalizace Přijmout Zamítnout + od %1$s v %2$s + Žádné nevyřízené pozvánky + Máte nevyřízené pozvánky Zpět Je zapotřebí oprávnění pro přístup k souborům Filtrovat konverzace @@ -327,6 +338,7 @@ Hledat Vyberte účet Vybrat účastníky + Poslat upravovací zprávu %1$s poslal(a) GIF animaci. Odeslali jste GIF animaci. %1$s poslal(a) video. @@ -357,11 +369,13 @@ Na serveru není nainstalovaná podporovaná verze aplikace Talk Adresa serveru https://… %1$s funguje pouze s %2$s 13 a novějším + Nastavit heslo Nastavení Namísto přidání nového byl zaktualizován váš stávající účet Pokročilé Vzhled Volání + Otevřít diagnostickou obrazovku pro kontrolu nastavení nebo vytvoření hlášení chyby Diagnostika Dát klávesnici pokyn, že má vypnout přizpůsobené učení se (bez záruky) Inkognito klávesnice @@ -447,6 +461,7 @@ « Zrušíte přejetím prstem Webinář Ano + Ikona vytváření nové konverzace Příští týden Není možné propojit telefonní čísla, protože chybí potřebná oprávnění 1 hodina @@ -503,6 +518,7 @@ Přepnout pohled Změnit úroveň soukromí pro %1$s Odrolovat na konec + Ikona vyhledávání sekund před Viz %1$s podobných zpráv Vybráno @@ -516,6 +532,7 @@ Nastavit stav Nastavit stavovou zprávu Sdílet + Připojit se ke konverzaci %1$s na %2$s Zvuk Soubor Média @@ -523,6 +540,8 @@ Anketa Nahrávka hovoru Hlas + Zobrazit důvod vyloučení + Zobrazit vyloučené účasníky Oblíbené Nemáte oprávnění pro zahájení hovoru zahájen hovor @@ -557,6 +576,7 @@ píší… píše… a %1$s ostatní píší… + Zrušit vyloučení Nastavit jako nepřečtené Nahrát nový profilový obrázek ze zařízení Zástupný obrázek uživatele From 45d7969890add40b6a3aa5e9b03d769bc8637d9f Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Wed, 25 Sep 2024 07:53:51 +0000 Subject: [PATCH 101/885] Update dependency org.junit.vintage:junit-vintage-engine to v5.11.1 Signed-off-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- app/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/build.gradle b/app/build.gradle index cde12d1169..c36c4d0eaf 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -360,7 +360,7 @@ dependencies { testImplementation "org.mockito.kotlin:mockito-kotlin:$mockitoKotlinVersion" testImplementation "org.jetbrains.kotlinx:kotlinx-coroutines-test:$coroutines_version" - testImplementation 'org.junit.vintage:junit-vintage-engine:5.11.0' + testImplementation 'org.junit.vintage:junit-vintage-engine:5.11.1' } tasks.register('installGitHooks', Copy) { From 856c0761c90e2bf33485fec88daee44d3daa88b2 Mon Sep 17 00:00:00 2001 From: parneet-guraya Date: Wed, 25 Sep 2024 22:04:11 +0530 Subject: [PATCH 102/885] Fix logic for date time retrieval Signed-off-by: parneet-guraya --- .../talk/ui/dialog/DateTimePickerFragment.kt | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) 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 42f87f285e..747cdc09ee 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 @@ -200,10 +200,9 @@ class DateTimePickerFragment : DialogFragment() { val year = calendar.get(Calendar.YEAR) val month = calendar.get(Calendar.MONTH) - val day = calendar.get(Calendar.DAY_OF_WEEK) - val weekInYear = calendar.get(Calendar.WEEK_OF_YEAR) + val day = calendar.get(Calendar.DAY_OF_YEAR) - setUpTimePicker(year, month, day, weekInYear) + setUpTimePicker(year, month, day) } datePicker.show(this.parentFragmentManager, TAG) } @@ -226,7 +225,7 @@ class DateTimePickerFragment : DialogFragment() { } } - private fun setUpTimePicker(year: Int, month: Int, day: Int, weekInYear: Int) { + private fun setUpTimePicker(year: Int, month: Int, day: Int) { val locale = if (DateFormat.is24HourFormat(requireContext())) TimeFormat.CLOCK_24H else TimeFormat.CLOCK_12H val timePicker = MaterialTimePicker.Builder() .setTitleText(R.string.nc_remind) @@ -240,7 +239,6 @@ class DateTimePickerFragment : DialogFragment() { day, timePicker.hour, timePicker.minute, - weekInYear = weekInYear ) setTimeStamp(getTimeFromTimeStamp(timestamp)) currentTimeStamp = timestamp / ONE_SEC @@ -260,14 +258,16 @@ class DateTimePickerFragment : DialogFragment() { hour: Int = Calendar.getInstance().get(Calendar.HOUR_OF_DAY), minute: Int = Calendar.getInstance().get(Calendar.MINUTE), daysToAdd: Int = 0, - weekInYear: Int = Calendar.getInstance().get(Calendar.WEEK_OF_YEAR), + weekInYear: Int = -1, weekDay: Int = -1 ): Long { val calendar: Calendar = Calendar.getInstance().apply { set(Calendar.YEAR, year) set(Calendar.MONTH, month) - if (weekDay > -1) set(Calendar.DAY_OF_WEEK, weekDay) else set(Calendar.DAY_OF_YEAR, day) - if (daysToAdd > 0) add(Calendar.DAY_OF_YEAR, daysToAdd) else set(Calendar.WEEK_OF_YEAR, weekInYear) + set(Calendar.DAY_OF_YEAR,day) + if (weekDay > -1) set(Calendar.DAY_OF_WEEK, weekDay) + if (daysToAdd > 0) add(Calendar.DAY_OF_YEAR, daysToAdd) + if (weekInYear != -1) set(Calendar.WEEK_OF_YEAR, weekInYear) set(Calendar.HOUR_OF_DAY, hour) set(Calendar.MINUTE, minute) set(Calendar.SECOND, 0) From eaae8b923d8ca820774a4505f517c407ce691d3f Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Wed, 25 Sep 2024 19:25:31 +0000 Subject: [PATCH 103/885] Update actions/checkout action to v4.2.0 Signed-off-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- .github/workflows/analysis.yml | 2 +- .github/workflows/assembleFlavors.yml | 2 +- .github/workflows/check.yml | 2 +- .github/workflows/codeql.yml | 2 +- .github/workflows/gradle-wrapper-validation.yml | 2 +- .github/workflows/qa.yml | 2 +- .github/workflows/reuse.yml | 2 +- .github/workflows/scorecard.yml | 2 +- .github/workflows/unit-tests.yml | 2 +- 9 files changed, 9 insertions(+), 9 deletions(-) diff --git a/.github/workflows/analysis.yml b/.github/workflows/analysis.yml index b5be46d99a..df08967031 100644 --- a/.github/workflows/analysis.yml +++ b/.github/workflows/analysis.yml @@ -44,7 +44,7 @@ jobs: echo "repo=${{ github.event.pull_request.head.repo.full_name }}" } >> "$GITHUB_OUTPUT" fi - - uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332 # v4.1.7 + - uses: actions/checkout@d632683dd7b4114ad314bca15554477dd762a938 # v4.2.0 with: repository: ${{ steps.get-vars.outputs.repo }} ref: ${{ steps.get-vars.outputs.branch }} diff --git a/.github/workflows/assembleFlavors.yml b/.github/workflows/assembleFlavors.yml index 3680c9c4b9..fca5c0b98e 100644 --- a/.github/workflows/assembleFlavors.yml +++ b/.github/workflows/assembleFlavors.yml @@ -22,7 +22,7 @@ jobs: matrix: flavor: [ Generic, Gplay ] steps: - - uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332 # v4.1.7 + - uses: actions/checkout@d632683dd7b4114ad314bca15554477dd762a938 # v4.2.0 - name: set up JDK 17 uses: actions/setup-java@b36c23c0d998641eff861008f374ee103c25ac73 # v4.4.0 with: diff --git a/.github/workflows/check.yml b/.github/workflows/check.yml index 5e276c62c2..d559a38f42 100644 --- a/.github/workflows/check.yml +++ b/.github/workflows/check.yml @@ -22,7 +22,7 @@ jobs: matrix: task: [ detekt, ktlintCheck ] steps: - - uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332 # v4.1.7 + - uses: actions/checkout@d632683dd7b4114ad314bca15554477dd762a938 # v4.2.0 - name: Set up JDK 17 uses: actions/setup-java@b36c23c0d998641eff861008f374ee103c25ac73 # v4.4.0 with: diff --git a/.github/workflows/codeql.yml b/.github/workflows/codeql.yml index 9970c2fb7e..d0c4cb4e03 100644 --- a/.github/workflows/codeql.yml +++ b/.github/workflows/codeql.yml @@ -33,7 +33,7 @@ jobs: language: [ 'java' ] steps: - name: Checkout repository - uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332 # v4.1.7 + uses: actions/checkout@d632683dd7b4114ad314bca15554477dd762a938 # v4.2.0 - name: Set Swap Space uses: pierotofy/set-swap-space@49819abfb41bd9b44fb781159c033dba90353a7c # v1.0 with: diff --git a/.github/workflows/gradle-wrapper-validation.yml b/.github/workflows/gradle-wrapper-validation.yml index edae2f673e..76520536d2 100644 --- a/.github/workflows/gradle-wrapper-validation.yml +++ b/.github/workflows/gradle-wrapper-validation.yml @@ -25,5 +25,5 @@ jobs: name: "Validation" runs-on: ubuntu-latest steps: - - uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332 # v4.1.7 + - uses: actions/checkout@d632683dd7b4114ad314bca15554477dd762a938 # v4.2.0 - uses: gradle/wrapper-validation-action@f9c9c575b8b21b6485636a91ffecd10e558c62f6 # v3.5.0 diff --git a/.github/workflows/qa.yml b/.github/workflows/qa.yml index 2fcc86e5bf..a4cab5e057 100644 --- a/.github/workflows/qa.yml +++ b/.github/workflows/qa.yml @@ -22,7 +22,7 @@ jobs: - name: Check if secrets are available run: echo "ok=${{ secrets.KS_PASS != '' }}" >> "$GITHUB_OUTPUT" id: check-secrets - - uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332 # v4.1.7 + - uses: actions/checkout@d632683dd7b4114ad314bca15554477dd762a938 # v4.2.0 if: ${{ steps.check-secrets.outputs.ok == 'true' }} - name: set up JDK 17 uses: actions/setup-java@b36c23c0d998641eff861008f374ee103c25ac73 # v4.4.0 diff --git a/.github/workflows/reuse.yml b/.github/workflows/reuse.yml index 95eaba80e7..b5252f9fa5 100644 --- a/.github/workflows/reuse.yml +++ b/.github/workflows/reuse.yml @@ -16,7 +16,7 @@ jobs: runs-on: ubuntu-latest steps: - name: Checkout - uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332 # v4.1.7 + uses: actions/checkout@d632683dd7b4114ad314bca15554477dd762a938 # v4.2.0 - name: REUSE Compliance Check uses: fsfe/reuse-action@3ae3c6bdf1257ab19397fab11fd3312144692083 # v4.0.0 diff --git a/.github/workflows/scorecard.yml b/.github/workflows/scorecard.yml index 8a8d98cb16..fc5f9cea06 100644 --- a/.github/workflows/scorecard.yml +++ b/.github/workflows/scorecard.yml @@ -29,7 +29,7 @@ jobs: steps: - name: "Checkout code" - uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332 # v4.1.7 + uses: actions/checkout@d632683dd7b4114ad314bca15554477dd762a938 # v4.2.0 with: persist-credentials: false diff --git a/.github/workflows/unit-tests.yml b/.github/workflows/unit-tests.yml index a020dc8608..1d573b409a 100644 --- a/.github/workflows/unit-tests.yml +++ b/.github/workflows/unit-tests.yml @@ -21,7 +21,7 @@ jobs: test: runs-on: ubuntu-latest steps: - - uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332 # v4.1.7 + - uses: actions/checkout@d632683dd7b4114ad314bca15554477dd762a938 # v4.2.0 - name: Set up JDK 17 uses: actions/setup-java@b36c23c0d998641eff861008f374ee103c25ac73 # v4.4.0 with: From 381804c8922051543800ba4c4fdc6efe142e5470 Mon Sep 17 00:00:00 2001 From: sowjanyakch Date: Fri, 20 Sep 2024 15:41:02 +0200 Subject: [PATCH 104/885] Add Change Password dialogue Signed-off-by: sowjanyakch --- .../ConversationCreationActivity.kt | 93 ++++++++++++++++++- .../ConversationCreationViewModel.kt | 7 ++ app/src/main/res/values/strings.xml | 3 + 3 files changed, 99 insertions(+), 4 deletions(-) diff --git a/app/src/main/java/com/nextcloud/talk/conversationcreation/ConversationCreationActivity.kt b/app/src/main/java/com/nextcloud/talk/conversationcreation/ConversationCreationActivity.kt index 74bf4d6150..1f68b2686f 100644 --- a/app/src/main/java/com/nextcloud/talk/conversationcreation/ConversationCreationActivity.kt +++ b/app/src/main/java/com/nextcloud/talk/conversationcreation/ConversationCreationActivity.kt @@ -20,6 +20,7 @@ import androidx.activity.compose.rememberLauncherForActivityResult import androidx.activity.compose.setContent import androidx.activity.result.ActivityResult import androidx.activity.result.contract.ActivityResultContracts +import androidx.compose.foundation.background import androidx.compose.foundation.clickable import androidx.compose.foundation.isSystemInDarkTheme import androidx.compose.foundation.layout.Arrangement @@ -28,17 +29,21 @@ import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.Row import androidx.compose.foundation.layout.Spacer import androidx.compose.foundation.layout.fillMaxHeight +import androidx.compose.foundation.layout.fillMaxSize import androidx.compose.foundation.layout.fillMaxWidth +import androidx.compose.foundation.layout.height import androidx.compose.foundation.layout.padding import androidx.compose.foundation.layout.size import androidx.compose.foundation.layout.width import androidx.compose.foundation.rememberScrollState import androidx.compose.foundation.shape.CircleShape +import androidx.compose.foundation.shape.RoundedCornerShape import androidx.compose.foundation.verticalScroll import androidx.compose.material.icons.Icons import androidx.compose.material.icons.automirrored.filled.ArrowBack import androidx.compose.material3.AlertDialog import androidx.compose.material3.Button +import androidx.compose.material3.Card import androidx.compose.material3.ExperimentalMaterial3Api import androidx.compose.material3.HorizontalDivider import androidx.compose.material3.Icon @@ -48,6 +53,7 @@ import androidx.compose.material3.OutlinedTextField import androidx.compose.material3.Scaffold import androidx.compose.material3.Switch import androidx.compose.material3.Text +import androidx.compose.material3.TextButton import androidx.compose.material3.TextField import androidx.compose.material3.TopAppBar import androidx.compose.runtime.Composable @@ -56,6 +62,7 @@ import androidx.compose.runtime.collectAsState import androidx.compose.runtime.getValue import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.remember +import androidx.compose.runtime.saveable.rememberSaveable import androidx.compose.runtime.setValue import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier @@ -70,6 +77,7 @@ import androidx.compose.ui.res.stringResource import androidx.compose.ui.text.style.TextAlign import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.sp +import androidx.compose.ui.window.Dialog import androidx.core.view.WindowCompat import androidx.lifecycle.ViewModelProvider import autodagger.AutoInjector @@ -436,6 +444,9 @@ fun RoomCreationOptions(conversationCreationViewModel: ConversationCreationViewM .isConversationAvailableForRegisteredUsers.value val isOpenForGuestAppUsers = conversationCreationViewModel.openForGuestAppUsers.value + val isPasswordSet = conversationCreationViewModel.isPasswordEnabled.value + val isPasswordChanged = conversationCreationViewModel.isPasswordChanged.value + Text( text = stringResource(id = R.string.nc_new_conversation_visibility).uppercase(), fontSize = 14.sp, @@ -456,7 +467,7 @@ fun RoomCreationOptions(conversationCreationViewModel: ConversationCreationViewM conversationCreationViewModel = conversationCreationViewModel ) - if (isGuestsAllowed) { + if (isGuestsAllowed && !isPasswordSet) { ConversationOptions( icon = R.drawable.ic_lock_grey600_24px, text = R.string.nc_set_password, @@ -465,6 +476,15 @@ fun RoomCreationOptions(conversationCreationViewModel: ConversationCreationViewM ) } + if (isGuestsAllowed && isPasswordSet) { + ConversationOptions( + icon = R.drawable.ic_lock_grey600_24px, + text = R.string.nc_change_password, + showDialog = false, + conversationCreationViewModel = conversationCreationViewModel + ) + } + ConversationOptions( icon = R.drawable.baseline_format_list_bulleted_24, text = R.string.nc_open_conversation_to_registered_users, @@ -505,7 +525,7 @@ fun ConversationOptions( showDialog: Boolean, conversationCreationViewModel: ConversationCreationViewModel ) { - var showPasswordDialog by remember { mutableStateOf(false) } + var showPasswordDialog by rememberSaveable { mutableStateOf(false) } Row( modifier = Modifier .fillMaxWidth() @@ -545,19 +565,84 @@ fun ConversationOptions( conversationCreationViewModel = conversationCreationViewModel ) } + if (conversationCreationViewModel.isPasswordChanged.value) { + ShowChangePassword( + onDismiss = { + }, + conversationCreationViewModel = conversationCreationViewModel + ) + } + } +} + +@Composable +fun ShowChangePassword(onDismiss: () -> Unit, conversationCreationViewModel: ConversationCreationViewModel) { + var changedPassword by rememberSaveable { mutableStateOf("") } + Dialog(onDismissRequest = { }) { + Card( + modifier = Modifier + .fillMaxWidth() + .height(375.dp) + .padding(16.dp) + .background(color = colorResource(id = R.color.appbar)) + .clickable { + if (conversationCreationViewModel.isPasswordEnabled.value) { + } + }, + shape = RoundedCornerShape(16.dp) + ) { + Column( + modifier = Modifier + .fillMaxSize(), + verticalArrangement = Arrangement.Center, + horizontalAlignment = Alignment.CenterHorizontally + ) { + Text(text = stringResource(id = R.string.nc_change_password)) + OutlinedTextField( + value = changedPassword, + onValueChange = { + changedPassword = it + }, + label = { Text(text = stringResource(id = R.string.nc_set_new_password)) }, + singleLine = true + ) + + TextButton( + onClick = { }, + modifier = Modifier.padding(8.dp) + ) { + Text(text = stringResource(id = R.string.nc_change_password)) + } + TextButton( + onClick = { }, + modifier = Modifier.padding(8.dp) + ) { + Text(text = stringResource(id = R.string.nc_remove_password)) + } + TextButton( + onClick = { }, + modifier = Modifier.padding(8.dp) + ) { + Text(text = stringResource(id = R.string.nc_cancel)) + } + } + } } } @Composable fun ShowPasswordDialog(onDismiss: () -> Unit, conversationCreationViewModel: ConversationCreationViewModel) { - var password by remember { mutableStateOf("") } + var password by rememberSaveable { mutableStateOf("") } AlertDialog( containerColor = colorResource(id = R.color.dialog_background), onDismissRequest = onDismiss, confirmButton = { Button(onClick = { - conversationCreationViewModel.updatePassword(password) + if (password.isNotEmpty()) { + conversationCreationViewModel.updatePassword(password) + conversationCreationViewModel.isPasswordEnabled(true) + } onDismiss() }) { Text(text = stringResource(id = R.string.save)) diff --git a/app/src/main/java/com/nextcloud/talk/conversationcreation/ConversationCreationViewModel.kt b/app/src/main/java/com/nextcloud/talk/conversationcreation/ConversationCreationViewModel.kt index 0fa663d889..33249c9ee6 100644 --- a/app/src/main/java/com/nextcloud/talk/conversationcreation/ConversationCreationViewModel.kt +++ b/app/src/main/java/com/nextcloud/talk/conversationcreation/ConversationCreationViewModel.kt @@ -38,6 +38,12 @@ class ConversationCreationViewModel @Inject constructor( private val _currentUser = userManager.currentUser.blockingGet() val currentUser: User = _currentUser + private val _isPasswordEnabled = mutableStateOf(false) + val isPasswordEnabled = _isPasswordEnabled + + private val _isPasswordChanged = mutableStateOf(false) + val isPasswordChanged = _isPasswordChanged + fun updateSelectedParticipants(participants: List) { _selectedParticipants.value = participants } @@ -73,6 +79,7 @@ class ConversationCreationViewModel @Inject constructor( roomType: String, conversationName: String, participants: Set, + selectedImageUri: Uri?, onRoomCreated: (String) -> Unit ) { val scope = when { diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index c23acb5fbe..858f3bb0d7 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -434,6 +434,9 @@ How to translate with transifex: Allow guests to share a public link to join this conversation. Cannot enable/disable guest access. Set Password + Change Password + Remove Password + Set a new password Password protection Set a password to restrict who can use the public link. Guest access password From 31c0d74356c86a499a6e5b667f880cbea1309350 Mon Sep 17 00:00:00 2001 From: sowjanyakch Date: Mon, 23 Sep 2024 17:51:30 +0200 Subject: [PATCH 105/885] Add change password dialog Signed-off-by: sowjanyakch --- .../ConversationCreationActivity.kt | 68 +++++++++++-------- .../ConversationCreationViewModel.kt | 6 +- 2 files changed, 40 insertions(+), 34 deletions(-) diff --git a/app/src/main/java/com/nextcloud/talk/conversationcreation/ConversationCreationActivity.kt b/app/src/main/java/com/nextcloud/talk/conversationcreation/ConversationCreationActivity.kt index 1f68b2686f..f732a1f838 100644 --- a/app/src/main/java/com/nextcloud/talk/conversationcreation/ConversationCreationActivity.kt +++ b/app/src/main/java/com/nextcloud/talk/conversationcreation/ConversationCreationActivity.kt @@ -445,7 +445,6 @@ fun RoomCreationOptions(conversationCreationViewModel: ConversationCreationViewM val isOpenForGuestAppUsers = conversationCreationViewModel.openForGuestAppUsers.value val isPasswordSet = conversationCreationViewModel.isPasswordEnabled.value - val isPasswordChanged = conversationCreationViewModel.isPasswordChanged.value Text( text = stringResource(id = R.string.nc_new_conversation_visibility).uppercase(), @@ -463,7 +462,6 @@ fun RoomCreationOptions(conversationCreationViewModel: ConversationCreationViewM } ) }, - showDialog = false, conversationCreationViewModel = conversationCreationViewModel ) @@ -471,7 +469,6 @@ fun RoomCreationOptions(conversationCreationViewModel: ConversationCreationViewM ConversationOptions( icon = R.drawable.ic_lock_grey600_24px, text = R.string.nc_set_password, - showDialog = true, conversationCreationViewModel = conversationCreationViewModel ) } @@ -480,7 +477,6 @@ fun RoomCreationOptions(conversationCreationViewModel: ConversationCreationViewM ConversationOptions( icon = R.drawable.ic_lock_grey600_24px, text = R.string.nc_change_password, - showDialog = false, conversationCreationViewModel = conversationCreationViewModel ) } @@ -496,7 +492,6 @@ fun RoomCreationOptions(conversationCreationViewModel: ConversationCreationViewM } ) }, - showDialog = false, conversationCreationViewModel = conversationCreationViewModel ) @@ -511,7 +506,6 @@ fun RoomCreationOptions(conversationCreationViewModel: ConversationCreationViewM } ) }, - showDialog = false, conversationCreationViewModel = conversationCreationViewModel ) } @@ -522,19 +516,23 @@ fun ConversationOptions( icon: Int? = null, text: Int, switch: @Composable (() -> Unit)? = null, - showDialog: Boolean, conversationCreationViewModel: ConversationCreationViewModel ) { var showPasswordDialog by rememberSaveable { mutableStateOf(false) } + var showPasswordChangeDialog by rememberSaveable { mutableStateOf(false) } Row( modifier = Modifier .fillMaxWidth() .padding(start = 16.dp, end = 16.dp, bottom = 8.dp) .then( - if (showDialog) { + if (!conversationCreationViewModel.isPasswordEnabled.value) { Modifier.clickable { showPasswordDialog = true } + } else if (conversationCreationViewModel.isPasswordEnabled.value) { + Modifier.clickable { + showPasswordChangeDialog = true + } } else { Modifier } @@ -565,9 +563,10 @@ fun ConversationOptions( conversationCreationViewModel = conversationCreationViewModel ) } - if (conversationCreationViewModel.isPasswordChanged.value) { + if (showPasswordChangeDialog) { ShowChangePassword( onDismiss = { + showPasswordChangeDialog = false }, conversationCreationViewModel = conversationCreationViewModel ) @@ -578,17 +577,15 @@ fun ConversationOptions( @Composable fun ShowChangePassword(onDismiss: () -> Unit, conversationCreationViewModel: ConversationCreationViewModel) { var changedPassword by rememberSaveable { mutableStateOf("") } - Dialog(onDismissRequest = { }) { + Dialog(onDismissRequest = { + onDismiss() + }) { Card( modifier = Modifier .fillMaxWidth() .height(375.dp) .padding(16.dp) - .background(color = colorResource(id = R.color.appbar)) - .clickable { - if (conversationCreationViewModel.isPasswordEnabled.value) { - } - }, + .background(color = colorResource(id = R.color.appbar)), shape = RoundedCornerShape(16.dp) ) { Column( @@ -606,21 +603,32 @@ fun ShowChangePassword(onDismiss: () -> Unit, conversationCreationViewModel: Con label = { Text(text = stringResource(id = R.string.nc_set_new_password)) }, singleLine = true ) - - TextButton( - onClick = { }, - modifier = Modifier.padding(8.dp) - ) { - Text(text = stringResource(id = R.string.nc_change_password)) + if (changedPassword.isNotEmpty() && changedPassword.isNotBlank()) { + TextButton( + onClick = { + conversationCreationViewModel.updatePassword(changedPassword) + conversationCreationViewModel.isPasswordEnabled.value = true + onDismiss() + }, + modifier = Modifier.padding(8.dp) + ) { + Text(text = stringResource(id = R.string.nc_change_password)) + } } TextButton( - onClick = { }, + onClick = { + conversationCreationViewModel.isPasswordEnabled.value = true + onDismiss() + }, modifier = Modifier.padding(8.dp) ) { Text(text = stringResource(id = R.string.nc_remove_password)) } TextButton( - onClick = { }, + onClick = { + conversationCreationViewModel.isPasswordEnabled.value = true + onDismiss() + }, modifier = Modifier.padding(8.dp) ) { Text(text = stringResource(id = R.string.nc_cancel)) @@ -633,18 +641,18 @@ fun ShowChangePassword(onDismiss: () -> Unit, conversationCreationViewModel: Con @Composable fun ShowPasswordDialog(onDismiss: () -> Unit, conversationCreationViewModel: ConversationCreationViewModel) { var password by rememberSaveable { mutableStateOf("") } - AlertDialog( containerColor = colorResource(id = R.color.dialog_background), onDismissRequest = onDismiss, confirmButton = { - Button(onClick = { - if (password.isNotEmpty()) { - conversationCreationViewModel.updatePassword(password) - conversationCreationViewModel.isPasswordEnabled(true) + Button( + onClick = { + if (password.isNotEmpty() && password.isNotBlank()) { + conversationCreationViewModel.updatePassword(password) + conversationCreationViewModel.isPasswordEnabled(true) + } } - onDismiss() - }) { + ) { Text(text = stringResource(id = R.string.save)) } }, diff --git a/app/src/main/java/com/nextcloud/talk/conversationcreation/ConversationCreationViewModel.kt b/app/src/main/java/com/nextcloud/talk/conversationcreation/ConversationCreationViewModel.kt index 33249c9ee6..509bf4be31 100644 --- a/app/src/main/java/com/nextcloud/talk/conversationcreation/ConversationCreationViewModel.kt +++ b/app/src/main/java/com/nextcloud/talk/conversationcreation/ConversationCreationViewModel.kt @@ -41,17 +41,15 @@ class ConversationCreationViewModel @Inject constructor( private val _isPasswordEnabled = mutableStateOf(false) val isPasswordEnabled = _isPasswordEnabled - private val _isPasswordChanged = mutableStateOf(false) - val isPasswordChanged = _isPasswordChanged - fun updateSelectedParticipants(participants: List) { _selectedParticipants.value = participants } + fun isPasswordEnabled(value: Boolean) { + isPasswordEnabled.value = value fun updateSelectedImageUri(uri: Uri?) { _selectedImageUri.value = uri } - private val _roomName = MutableStateFlow("") val roomName: StateFlow = _roomName private val _password = MutableStateFlow("") From c165e9fe0c628fa60a81d1059908e818e5491321 Mon Sep 17 00:00:00 2001 From: sowjanyakch Date: Mon, 23 Sep 2024 18:35:38 +0200 Subject: [PATCH 106/885] UI improvements Signed-off-by: sowjanyakch --- .../ConversationCreationActivity.kt | 70 +++++++++++-------- app/src/main/res/values/strings.xml | 3 +- 2 files changed, 43 insertions(+), 30 deletions(-) diff --git a/app/src/main/java/com/nextcloud/talk/conversationcreation/ConversationCreationActivity.kt b/app/src/main/java/com/nextcloud/talk/conversationcreation/ConversationCreationActivity.kt index f732a1f838..23eb61e87e 100644 --- a/app/src/main/java/com/nextcloud/talk/conversationcreation/ConversationCreationActivity.kt +++ b/app/src/main/java/com/nextcloud/talk/conversationcreation/ConversationCreationActivity.kt @@ -26,6 +26,7 @@ import androidx.compose.foundation.isSystemInDarkTheme import androidx.compose.foundation.layout.Arrangement import androidx.compose.foundation.layout.Box import androidx.compose.foundation.layout.Column +import androidx.compose.foundation.layout.PaddingValues import androidx.compose.foundation.layout.Row import androidx.compose.foundation.layout.Spacer import androidx.compose.foundation.layout.fillMaxHeight @@ -37,13 +38,11 @@ import androidx.compose.foundation.layout.size import androidx.compose.foundation.layout.width import androidx.compose.foundation.rememberScrollState import androidx.compose.foundation.shape.CircleShape -import androidx.compose.foundation.shape.RoundedCornerShape import androidx.compose.foundation.verticalScroll import androidx.compose.material.icons.Icons import androidx.compose.material.icons.automirrored.filled.ArrowBack import androidx.compose.material3.AlertDialog import androidx.compose.material3.Button -import androidx.compose.material3.Card import androidx.compose.material3.ExperimentalMaterial3Api import androidx.compose.material3.HorizontalDivider import androidx.compose.material3.Icon @@ -51,6 +50,7 @@ import androidx.compose.material3.IconButton import androidx.compose.material3.MaterialTheme import androidx.compose.material3.OutlinedTextField import androidx.compose.material3.Scaffold +import androidx.compose.material3.Surface import androidx.compose.material3.Switch import androidx.compose.material3.Text import androidx.compose.material3.TextButton @@ -74,6 +74,7 @@ import androidx.compose.ui.platform.LocalView import androidx.compose.ui.res.colorResource import androidx.compose.ui.res.painterResource import androidx.compose.ui.res.stringResource +import androidx.compose.ui.text.font.FontWeight import androidx.compose.ui.text.style.TextAlign import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.sp @@ -580,58 +581,69 @@ fun ShowChangePassword(onDismiss: () -> Unit, conversationCreationViewModel: Con Dialog(onDismissRequest = { onDismiss() }) { - Card( + Surface( modifier = Modifier .fillMaxWidth() .height(375.dp) - .padding(16.dp) - .background(color = colorResource(id = R.color.appbar)), - shape = RoundedCornerShape(16.dp) + .padding(32.dp) + .background(color = colorResource(id = R.color.appbar)) ) { Column( modifier = Modifier - .fillMaxSize(), + .fillMaxSize() + .padding(vertical = 16.dp, horizontal = 16.dp), verticalArrangement = Arrangement.Center, horizontalAlignment = Alignment.CenterHorizontally ) { - Text(text = stringResource(id = R.string.nc_change_password)) + Text(text = stringResource(id = R.string.nc_set_new_password), fontWeight = FontWeight.SemiBold) + Spacer(modifier = Modifier.height(16.dp)) OutlinedTextField( value = changedPassword, onValueChange = { changedPassword = it }, - label = { Text(text = stringResource(id = R.string.nc_set_new_password)) }, + label = { Text(text = stringResource(id = R.string.nc_password)) }, singleLine = true ) - if (changedPassword.isNotEmpty() && changedPassword.isNotBlank()) { + Spacer(modifier = Modifier.height(16.dp)) + + Column( + modifier = Modifier.fillMaxWidth() + .padding(vertical = 8.dp), + verticalArrangement = Arrangement.Center, + horizontalAlignment = Alignment.CenterHorizontally + ) { TextButton( onClick = { conversationCreationViewModel.updatePassword(changedPassword) conversationCreationViewModel.isPasswordEnabled.value = true onDismiss() }, - modifier = Modifier.padding(8.dp) + enabled = changedPassword.isNotEmpty() && changedPassword.isNotBlank(), + contentPadding = PaddingValues(horizontal = 16.dp, vertical = 8.dp) ) { Text(text = stringResource(id = R.string.nc_change_password)) } - } - TextButton( - onClick = { - conversationCreationViewModel.isPasswordEnabled.value = true - onDismiss() - }, - modifier = Modifier.padding(8.dp) - ) { - Text(text = stringResource(id = R.string.nc_remove_password)) - } - TextButton( - onClick = { - conversationCreationViewModel.isPasswordEnabled.value = true - onDismiss() - }, - modifier = Modifier.padding(8.dp) - ) { - Text(text = stringResource(id = R.string.nc_cancel)) + Spacer(modifier = Modifier.height(4.dp)) + TextButton( + onClick = { + conversationCreationViewModel.isPasswordEnabled.value = false + onDismiss() + }, + contentPadding = PaddingValues(horizontal = 16.dp, vertical = 8.dp) + ) { + Text( + text = stringResource(id = R.string.nc_remove_password), + color = colorResource(id = R.color.nc_darkRed) + ) + } + Spacer(modifier = Modifier.height(4.dp)) + TextButton( + onClick = { onDismiss() }, + contentPadding = PaddingValues(horizontal = 16.dp, vertical = 8.dp) + ) { + Text(text = stringResource(id = R.string.nc_cancel)) + } } } } diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 858f3bb0d7..b6d2d6469f 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -434,9 +434,10 @@ How to translate with transifex: Allow guests to share a public link to join this conversation. Cannot enable/disable guest access. Set Password + Password Change Password Remove Password - Set a new password + Set new password Password protection Set a password to restrict who can use the public link. Guest access password From 8c967c4f5678305a0829d940ec975b910b469e33 Mon Sep 17 00:00:00 2001 From: sowjanyakch Date: Mon, 23 Sep 2024 19:14:16 +0200 Subject: [PATCH 107/885] use open lock icon for set password Signed-off-by: sowjanyakch --- .../ConversationCreationActivity.kt | 23 +++++++++---------- .../ConversationCreationViewModel.kt | 5 ++-- .../res/drawable/baseline_lock_open_24.xml | 18 +++++++++++++++ 3 files changed, 32 insertions(+), 14 deletions(-) create mode 100644 app/src/main/res/drawable/baseline_lock_open_24.xml diff --git a/app/src/main/java/com/nextcloud/talk/conversationcreation/ConversationCreationActivity.kt b/app/src/main/java/com/nextcloud/talk/conversationcreation/ConversationCreationActivity.kt index 23eb61e87e..4ead1257c2 100644 --- a/app/src/main/java/com/nextcloud/talk/conversationcreation/ConversationCreationActivity.kt +++ b/app/src/main/java/com/nextcloud/talk/conversationcreation/ConversationCreationActivity.kt @@ -61,7 +61,6 @@ import androidx.compose.runtime.DisposableEffect import androidx.compose.runtime.collectAsState import androidx.compose.runtime.getValue import androidx.compose.runtime.mutableStateOf -import androidx.compose.runtime.remember import androidx.compose.runtime.saveable.rememberSaveable import androidx.compose.runtime.setValue import androidx.compose.ui.Alignment @@ -468,7 +467,7 @@ fun RoomCreationOptions(conversationCreationViewModel: ConversationCreationViewM if (isGuestsAllowed && !isPasswordSet) { ConversationOptions( - icon = R.drawable.ic_lock_grey600_24px, + icon = R.drawable.baseline_lock_open_24, text = R.string.nc_set_password, conversationCreationViewModel = conversationCreationViewModel ) @@ -656,6 +655,16 @@ fun ShowPasswordDialog(onDismiss: () -> Unit, conversationCreationViewModel: Con AlertDialog( containerColor = colorResource(id = R.color.dialog_background), onDismissRequest = onDismiss, + title = { Text(text = stringResource(id = R.string.nc_set_password)) }, + text = { + TextField( + value = password, + onValueChange = { + password = it + }, + label = { Text(text = stringResource(id = R.string.nc_guest_access_password_dialog_hint)) } + ) + }, confirmButton = { Button( onClick = { @@ -668,16 +677,6 @@ fun ShowPasswordDialog(onDismiss: () -> Unit, conversationCreationViewModel: Con Text(text = stringResource(id = R.string.save)) } }, - title = { Text(text = stringResource(id = R.string.nc_set_password)) }, - text = { - TextField( - value = password, - onValueChange = { - password = it - }, - label = { Text(text = stringResource(id = R.string.nc_guest_access_password_dialog_hint)) } - ) - }, dismissButton = { Button(onClick = { onDismiss() }) { Text(text = stringResource(id = R.string.nc_cancel)) diff --git a/app/src/main/java/com/nextcloud/talk/conversationcreation/ConversationCreationViewModel.kt b/app/src/main/java/com/nextcloud/talk/conversationcreation/ConversationCreationViewModel.kt index 509bf4be31..66421bb540 100644 --- a/app/src/main/java/com/nextcloud/talk/conversationcreation/ConversationCreationViewModel.kt +++ b/app/src/main/java/com/nextcloud/talk/conversationcreation/ConversationCreationViewModel.kt @@ -46,7 +46,9 @@ class ConversationCreationViewModel @Inject constructor( } fun isPasswordEnabled(value: Boolean) { - isPasswordEnabled.value = value + _isPasswordEnabled.value = value + } + fun updateSelectedImageUri(uri: Uri?) { _selectedImageUri.value = uri } @@ -77,7 +79,6 @@ class ConversationCreationViewModel @Inject constructor( roomType: String, conversationName: String, participants: Set, - selectedImageUri: Uri?, onRoomCreated: (String) -> Unit ) { val scope = when { diff --git a/app/src/main/res/drawable/baseline_lock_open_24.xml b/app/src/main/res/drawable/baseline_lock_open_24.xml new file mode 100644 index 0000000000..ed16256a53 --- /dev/null +++ b/app/src/main/res/drawable/baseline_lock_open_24.xml @@ -0,0 +1,18 @@ + + + + + + + From ebace8713afdc6e208dc09281880e406f2851c4f Mon Sep 17 00:00:00 2001 From: sowjanyakch Date: Wed, 25 Sep 2024 08:29:08 +0200 Subject: [PATCH 108/885] Rounded corners for change password dialog Signed-off-by: sowjanyakch --- .../ConversationCreationActivity.kt | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/app/src/main/java/com/nextcloud/talk/conversationcreation/ConversationCreationActivity.kt b/app/src/main/java/com/nextcloud/talk/conversationcreation/ConversationCreationActivity.kt index 4ead1257c2..b45db2f035 100644 --- a/app/src/main/java/com/nextcloud/talk/conversationcreation/ConversationCreationActivity.kt +++ b/app/src/main/java/com/nextcloud/talk/conversationcreation/ConversationCreationActivity.kt @@ -38,11 +38,13 @@ import androidx.compose.foundation.layout.size import androidx.compose.foundation.layout.width import androidx.compose.foundation.rememberScrollState import androidx.compose.foundation.shape.CircleShape +import androidx.compose.foundation.shape.RoundedCornerShape import androidx.compose.foundation.verticalScroll import androidx.compose.material.icons.Icons import androidx.compose.material.icons.automirrored.filled.ArrowBack import androidx.compose.material3.AlertDialog import androidx.compose.material3.Button +import androidx.compose.material3.Card import androidx.compose.material3.ExperimentalMaterial3Api import androidx.compose.material3.HorizontalDivider import androidx.compose.material3.Icon @@ -50,7 +52,6 @@ import androidx.compose.material3.IconButton import androidx.compose.material3.MaterialTheme import androidx.compose.material3.OutlinedTextField import androidx.compose.material3.Scaffold -import androidx.compose.material3.Surface import androidx.compose.material3.Switch import androidx.compose.material3.Text import androidx.compose.material3.TextButton @@ -580,11 +581,12 @@ fun ShowChangePassword(onDismiss: () -> Unit, conversationCreationViewModel: Con Dialog(onDismissRequest = { onDismiss() }) { - Surface( + Card( modifier = Modifier .fillMaxWidth() .height(375.dp) .padding(32.dp) + .clip(RoundedCornerShape(16.dp)) .background(color = colorResource(id = R.color.appbar)) ) { Column( @@ -666,7 +668,7 @@ fun ShowPasswordDialog(onDismiss: () -> Unit, conversationCreationViewModel: Con ) }, confirmButton = { - Button( + TextButton( onClick = { if (password.isNotEmpty() && password.isNotBlank()) { conversationCreationViewModel.updatePassword(password) @@ -678,7 +680,7 @@ fun ShowPasswordDialog(onDismiss: () -> Unit, conversationCreationViewModel: Con } }, dismissButton = { - Button(onClick = { onDismiss() }) { + TextButton(onClick = { onDismiss() }) { Text(text = stringResource(id = R.string.nc_cancel)) } } From ebc2fd2702fc22d7bfe6698b86a91408926e6895 Mon Sep 17 00:00:00 2001 From: Marcel Hibbe Date: Wed, 25 Sep 2024 13:47:37 +0200 Subject: [PATCH 109/885] Add test for conversation conversion This test respects different API versions and checks if default values are set as expected. - remove deprecated+unused methods - remove comments - remove unnecessary double-bang operator Signed-off-by: Marcel Hibbe --- .../nextcloud/talk/activities/CallActivity.kt | 5 +- .../ConversationInfoActivity.kt | 8 +- .../database/mappers/ConversationMapUtils.kt | 42 ++--- .../talk/models/domain/ConversationModel.kt | 88 +++------- .../models/json/conversations/Conversation.kt | 133 ++++----------- .../dialog/ConversationsListBottomDialog.kt | 2 +- .../nextcloud/talk/utils/ConversationUtils.kt | 19 --- .../talk/json/ConversationConversionTest.kt | 157 ++++++++++++++++++ .../resources/RoomOverallExample_APIv1.json | 66 ++++++++ .../resources/RoomOverallExample_APIv2.json | 51 ++++++ .../resources/RoomOverallExample_APIv4.json | 83 +++++++++ 11 files changed, 436 insertions(+), 218 deletions(-) create mode 100644 app/src/test/java/com/nextcloud/talk/json/ConversationConversionTest.kt create mode 100644 app/src/test/resources/RoomOverallExample_APIv1.json create mode 100644 app/src/test/resources/RoomOverallExample_APIv2.json create mode 100644 app/src/test/resources/RoomOverallExample_APIv4.json 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 4302e27549..7f9ee8f6b5 100644 --- a/app/src/main/java/com/nextcloud/talk/activities/CallActivity.kt +++ b/app/src/main/java/com/nextcloud/talk/activities/CallActivity.kt @@ -1745,9 +1745,8 @@ class CallActivity : CallBaseActivity() { ApplicationWideCurrentRoomHolder.getInstance().callStartTime = conversation.callStartTime } - private fun startCallTimeCounter(callStartTime: Long?) { - if (callStartTime != null && - callStartTime != 0L && + private fun startCallTimeCounter(callStartTime: Long) { + if (callStartTime != 0L && hasSpreedFeatureCapability( conversationUser!!.capabilities!!.spreedCapability!!, SpreedFeatures.RECORDING_V1 ) diff --git a/app/src/main/java/com/nextcloud/talk/conversationinfo/ConversationInfoActivity.kt b/app/src/main/java/com/nextcloud/talk/conversationinfo/ConversationInfoActivity.kt index 8ab356befe..2005ebdffa 100644 --- a/app/src/main/java/com/nextcloud/talk/conversationinfo/ConversationInfoActivity.kt +++ b/app/src/main/java/com/nextcloud/talk/conversationinfo/ConversationInfoActivity.kt @@ -356,8 +356,8 @@ class ConversationInfoActivity : binding.webinarInfoView.startTimeButton.setOnClickListener { MaterialDialog(this, BottomSheet(WRAP_CONTENT)).show { val currentTimeCalendar = Calendar.getInstance() - if (conversation!!.lobbyTimer != null && conversation!!.lobbyTimer != 0L) { - currentTimeCalendar.timeInMillis = conversation!!.lobbyTimer!! * DateConstants.SECOND_DIVIDER + if (conversation!!.lobbyTimer != 0L) { + currentTimeCalendar.timeInMillis = conversation!!.lobbyTimer * DateConstants.SECOND_DIVIDER } dateTimePicker( @@ -746,13 +746,13 @@ class ConversationInfoActivity : setupWebinaryView() - if (!ConversationUtils.canLeave(conversation!!)) { + if (!conversation!!.canLeaveConversation) { binding.leaveConversationAction.visibility = GONE } else { binding.leaveConversationAction.visibility = VISIBLE } - if (!ConversationUtils.canDelete(conversation!!, spreedCapabilities)) { + if (!conversation!!.canDeleteConversation) { binding.deleteConversationAction.visibility = GONE } else { binding.deleteConversationAction.visibility = VISIBLE diff --git a/app/src/main/java/com/nextcloud/talk/data/database/mappers/ConversationMapUtils.kt b/app/src/main/java/com/nextcloud/talk/data/database/mappers/ConversationMapUtils.kt index 37d8fbced4..c6c80a485e 100644 --- a/app/src/main/java/com/nextcloud/talk/data/database/mappers/ConversationMapUtils.kt +++ b/app/src/main/java/com/nextcloud/talk/data/database/mappers/ConversationMapUtils.kt @@ -116,36 +116,36 @@ fun Conversation.asEntity(accountId: Long) = ConversationEntity( internalId = "$accountId@$token", accountId = accountId, - token = token!!, - name = name!!, - displayName = displayName!!, - description = description!!, - type = type!!, + token = token, + name = name, + displayName = displayName, + description = description, + type = type, lastPing = lastPing, - participantType = participantType!!, + participantType = participantType, hasPassword = hasPassword, - sessionId = sessionId!!, - actorId = actorId!!, - actorType = actorType!!, + sessionId = sessionId, + actorId = actorId, + actorType = actorType, favorite = favorite, lastActivity = lastActivity, unreadMessages = unreadMessages, unreadMention = unreadMention, lastMessage = lastMessage?.let { LoganSquare.serialize(lastMessage) }, - objectType = objectType!!, - notificationLevel = notificationLevel!!, - conversationReadOnlyState = conversationReadOnlyState!!, - lobbyState = lobbyState!!, - lobbyTimer = lobbyTimer!!, + objectType = objectType, + notificationLevel = notificationLevel, + conversationReadOnlyState = conversationReadOnlyState, + lobbyState = lobbyState, + lobbyTimer = lobbyTimer, lastReadMessage = lastReadMessage, lastCommonReadMessage = lastCommonReadMessage, hasCall = hasCall, callFlag = callFlag, canStartCall = canStartCall, - canLeaveConversation = canLeaveConversation!!, - canDeleteConversation = canDeleteConversation!!, - unreadMentionDirect = unreadMentionDirect!!, - notificationCalls = notificationCalls!!, + canLeaveConversation = canLeaveConversation, + canDeleteConversation = canDeleteConversation, + unreadMentionDirect = unreadMentionDirect, + notificationCalls = notificationCalls, permissions = permissions, messageExpiration = messageExpiration, status = status, @@ -153,9 +153,9 @@ fun Conversation.asEntity(accountId: Long) = statusMessage = statusMessage, statusClearAt = statusClearAt, callRecording = callRecording, - avatarVersion = avatarVersion!!, - hasCustomAvatar = hasCustomAvatar!!, - callStartTime = callStartTime!!, + avatarVersion = avatarVersion, + hasCustomAvatar = hasCustomAvatar, + callStartTime = callStartTime, recordingConsentRequired = recordingConsentRequired, remoteServer = remoteServer, remoteToken = remoteToken diff --git a/app/src/main/java/com/nextcloud/talk/models/domain/ConversationModel.kt b/app/src/main/java/com/nextcloud/talk/models/domain/ConversationModel.kt index 6e361a7110..d653b80986 100644 --- a/app/src/main/java/com/nextcloud/talk/models/domain/ConversationModel.kt +++ b/app/src/main/java/com/nextcloud/talk/models/domain/ConversationModel.kt @@ -16,7 +16,6 @@ import com.nextcloud.talk.models.json.participants.Participant class ConversationModel( var internalId: String, var accountId: Long, - // var roomId: String? = null, var token: String, var name: String, var displayName: String, @@ -70,46 +69,45 @@ class ConversationModel( return ConversationModel( internalId = user.id!!.toString() + "@" + conversation.token, accountId = user.id!!, - // roomId = conversation.roomId, - token = conversation.token!!, - name = conversation.name!!, - displayName = conversation.displayName!!, - description = conversation.description!!, - type = conversation.type.let { ConversationEnums.ConversationType.valueOf(it!!.name) }, + token = conversation.token, + name = conversation.name, + displayName = conversation.displayName, + description = conversation.description, + type = conversation.type.let { ConversationEnums.ConversationType.valueOf(it.name) }, lastPing = conversation.lastPing, - participantType = conversation.participantType.let { Participant.ParticipantType.valueOf(it!!.name) }, + participantType = conversation.participantType.let { Participant.ParticipantType.valueOf(it.name) }, hasPassword = conversation.hasPassword, - sessionId = conversation.sessionId!!, - actorId = conversation.actorId!!, - actorType = conversation.actorType!!, + sessionId = conversation.sessionId, + actorId = conversation.actorId, + actorType = conversation.actorType, password = conversation.password, favorite = conversation.favorite, lastActivity = conversation.lastActivity, unreadMessages = conversation.unreadMessages, unreadMention = conversation.unreadMention, lastMessage = conversation.lastMessage, - objectType = conversation.objectType.let { ConversationEnums.ObjectType.valueOf(it!!.name) }, + objectType = conversation.objectType.let { ConversationEnums.ObjectType.valueOf(it.name) }, notificationLevel = conversation.notificationLevel.let { ConversationEnums.NotificationLevel.valueOf( - it!!.name + it.name ) }, conversationReadOnlyState = conversation.conversationReadOnlyState.let { ConversationEnums.ConversationReadOnlyState.valueOf( - it!!.name + it.name ) }, - lobbyState = conversation.lobbyState.let { ConversationEnums.LobbyState.valueOf(it!!.name) }, - lobbyTimer = conversation.lobbyTimer!!, + lobbyState = conversation.lobbyState.let { ConversationEnums.LobbyState.valueOf(it.name) }, + lobbyTimer = conversation.lobbyTimer, lastReadMessage = conversation.lastReadMessage, lastCommonReadMessage = conversation.lastCommonReadMessage, hasCall = conversation.hasCall, callFlag = conversation.callFlag, canStartCall = conversation.canStartCall, - canLeaveConversation = conversation.canLeaveConversation!!, - canDeleteConversation = conversation.canDeleteConversation!!, - unreadMentionDirect = conversation.unreadMentionDirect!!, - notificationCalls = conversation.notificationCalls!!, + canLeaveConversation = conversation.canLeaveConversation, + canDeleteConversation = conversation.canDeleteConversation, + unreadMentionDirect = conversation.unreadMentionDirect, + notificationCalls = conversation.notificationCalls, permissions = conversation.permissions, messageExpiration = conversation.messageExpiration, status = conversation.status, @@ -117,9 +115,9 @@ class ConversationModel( statusMessage = conversation.statusMessage, statusClearAt = conversation.statusClearAt, callRecording = conversation.callRecording, - avatarVersion = conversation.avatarVersion!!, - hasCustomAvatar = conversation.hasCustomAvatar!!, - callStartTime = conversation.callStartTime!!, + avatarVersion = conversation.avatarVersion, + hasCustomAvatar = conversation.hasCustomAvatar, + callStartTime = conversation.callStartTime, recordingConsentRequired = conversation.recordingConsentRequired, remoteServer = conversation.remoteServer, remoteToken = conversation.remoteToken @@ -127,47 +125,3 @@ class ConversationModel( } } } - -// enum class ConversationType { -// DUMMY, -// ROOM_TYPE_ONE_TO_ONE_CALL, -// ROOM_GROUP_CALL, -// ROOM_PUBLIC_CALL, -// ROOM_SYSTEM, -// FORMER_ONE_TO_ONE, -// NOTE_TO_SELF -// } -// -// enum class ParticipantType { -// DUMMY, -// OWNER, -// MODERATOR, -// USER, -// GUEST, -// USER_FOLLOWING_LINK, -// GUEST_MODERATOR -// } -// -// enum class ObjectType { -// DEFAULT, -// SHARE_PASSWORD, -// FILE, -// ROOM -// } -// -// enum class NotificationLevel { -// DEFAULT, -// ALWAYS, -// MENTION, -// NEVER -// } -// -// enum class ConversationReadOnlyState { -// CONVERSATION_READ_WRITE, -// CONVERSATION_READ_ONLY -// } -// -// enum class LobbyState { -// LOBBY_STATE_ALL_PARTICIPANTS, -// LOBBY_STATE_MODERATORS_ONLY -// } diff --git a/app/src/main/java/com/nextcloud/talk/models/json/conversations/Conversation.kt b/app/src/main/java/com/nextcloud/talk/models/json/conversations/Conversation.kt index 7b22165cc4..65cd280c91 100644 --- a/app/src/main/java/com/nextcloud/talk/models/json/conversations/Conversation.kt +++ b/app/src/main/java/com/nextcloud/talk/models/json/conversations/Conversation.kt @@ -12,8 +12,6 @@ package com.nextcloud.talk.models.json.conversations import android.os.Parcelable import com.bluelinelabs.logansquare.annotation.JsonField import com.bluelinelabs.logansquare.annotation.JsonObject -import com.nextcloud.talk.data.user.model.User -import com.nextcloud.talk.models.domain.ConversationModel import com.nextcloud.talk.models.json.chat.ChatMessageJson import com.nextcloud.talk.models.json.converters.ConversationObjectTypeConverter import com.nextcloud.talk.models.json.converters.EnumLobbyStateConverter @@ -22,48 +20,45 @@ import com.nextcloud.talk.models.json.converters.EnumParticipantTypeConverter import com.nextcloud.talk.models.json.converters.EnumReadOnlyConversationConverter import com.nextcloud.talk.models.json.converters.EnumRoomTypeConverter import com.nextcloud.talk.models.json.participants.Participant.ParticipantType -import com.nextcloud.talk.utils.ConversationUtils import kotlinx.parcelize.Parcelize @Parcelize @JsonObject data class Conversation( - // @JsonField(name = ["id"]) - // var roomId: String? = null, @JsonField(name = ["token"]) - var token: String? = null, + var token: String = "", @JsonField(name = ["name"]) - var name: String? = null, + var name: String = "", @JsonField(name = ["displayName"]) - var displayName: String? = null, + var displayName: String = "", @JsonField(name = ["description"]) - var description: String? = null, + var description: String = "", @JsonField(name = ["type"], typeConverter = EnumRoomTypeConverter::class) - var type: ConversationEnums.ConversationType? = null, + var type: ConversationEnums.ConversationType = ConversationEnums.ConversationType.DUMMY, @JsonField(name = ["lastPing"]) var lastPing: Long = 0, @JsonField(name = ["participantType"], typeConverter = EnumParticipantTypeConverter::class) - var participantType: ParticipantType? = null, + var participantType: ParticipantType = ParticipantType.DUMMY, @JsonField(name = ["hasPassword"]) var hasPassword: Boolean = false, @JsonField(name = ["sessionId"]) - var sessionId: String? = null, + var sessionId: String = "0", @JsonField(name = ["actorId"]) - var actorId: String? = null, + var actorId: String = "", @JsonField(name = ["actorType"]) - var actorType: String? = null, + var actorType: String = "", - var password: String? = null, + var password: String? = null, //check if this can be removed.Does not belong to api response but is used internally? @JsonField(name = ["isFavorite"]) var favorite: Boolean = false, @@ -81,19 +76,20 @@ data class Conversation( var lastMessage: ChatMessageJson? = null, @JsonField(name = ["objectType"], typeConverter = ConversationObjectTypeConverter::class) - var objectType: ConversationEnums.ObjectType? = null, + var objectType: ConversationEnums.ObjectType = ConversationEnums.ObjectType.DEFAULT, @JsonField(name = ["notificationLevel"], typeConverter = EnumNotificationLevelConverter::class) - var notificationLevel: ConversationEnums.NotificationLevel? = null, + var notificationLevel: ConversationEnums.NotificationLevel = ConversationEnums.NotificationLevel.DEFAULT, @JsonField(name = ["readOnly"], typeConverter = EnumReadOnlyConversationConverter::class) - var conversationReadOnlyState: ConversationEnums.ConversationReadOnlyState? = null, + var conversationReadOnlyState: ConversationEnums.ConversationReadOnlyState = + ConversationEnums.ConversationReadOnlyState.CONVERSATION_READ_WRITE, @JsonField(name = ["lobbyState"], typeConverter = EnumLobbyStateConverter::class) - var lobbyState: ConversationEnums.LobbyState? = null, + var lobbyState: ConversationEnums.LobbyState = ConversationEnums.LobbyState.LOBBY_STATE_ALL_PARTICIPANTS, @JsonField(name = ["lobbyTimer"]) - var lobbyTimer: Long? = null, + var lobbyTimer: Long = 0, @JsonField(name = ["lastReadMessage"]) var lastReadMessage: Int = 0, @@ -111,16 +107,16 @@ data class Conversation( var canStartCall: Boolean = false, @JsonField(name = ["canLeaveConversation"]) - var canLeaveConversation: Boolean? = null, + var canLeaveConversation: Boolean = true, @JsonField(name = ["canDeleteConversation"]) - var canDeleteConversation: Boolean? = null, + var canDeleteConversation: Boolean = false, @JsonField(name = ["unreadMentionDirect"]) - var unreadMentionDirect: Boolean? = null, + var unreadMentionDirect: Boolean = false, @JsonField(name = ["notificationCalls"]) - var notificationCalls: Int? = null, + var notificationCalls: Int = 0, @JsonField(name = ["permissions"]) var permissions: Int = 0, @@ -129,107 +125,38 @@ data class Conversation( var messageExpiration: Int = 0, @JsonField(name = ["status"]) - var status: String? = null, + var status: String? = "", @JsonField(name = ["statusIcon"]) - var statusIcon: String? = null, + var statusIcon: String? = "", @JsonField(name = ["statusMessage"]) - var statusMessage: String? = null, + var statusMessage: String? = "", @JsonField(name = ["statusClearAt"]) - var statusClearAt: Long? = 0, + var statusClearAt: Long? = null, @JsonField(name = ["callRecording"]) var callRecording: Int = 0, @JsonField(name = ["avatarVersion"]) - var avatarVersion: String? = "", + var avatarVersion: String = "", // Be aware that variables with "is" at the beginning will lead to the error: // "@JsonField annotation can only be used on private fields if both getter and setter are present." // Instead, name it with "has" at the beginning: isCustomAvatar -> hasCustomAvatar @JsonField(name = ["isCustomAvatar"]) - var hasCustomAvatar: Boolean? = false, + var hasCustomAvatar: Boolean = false, @JsonField(name = ["callStartTime"]) - var callStartTime: Long? = 0L, + var callStartTime: Long = 0L, @JsonField(name = ["recordingConsent"]) var recordingConsentRequired: Int = 0, @JsonField(name = ["remoteServer"]) - var remoteServer: String? = null, + var remoteServer: String? = "", @JsonField(name = ["remoteToken"]) - var remoteToken: String? = null -) : Parcelable { - @Deprecated("Use ConversationUtil") - val isPublic: Boolean - get() = ConversationEnums.ConversationType.ROOM_PUBLIC_CALL == type - - @Deprecated("Use ConversationUtil") - val isGuest: Boolean - get() = ParticipantType.GUEST == participantType || - ParticipantType.GUEST_MODERATOR == participantType || - ParticipantType.USER_FOLLOWING_LINK == participantType - - @Deprecated("Use ConversationUtil") - val isParticipantOwnerOrModerator: Boolean - get() = ParticipantType.OWNER == participantType || - ParticipantType.GUEST_MODERATOR == participantType || - ParticipantType.MODERATOR == participantType - - @Deprecated("Use ConversationUtil") - fun canModerate(conversationUser: User): Boolean { - return isParticipantOwnerOrModerator && - !ConversationUtils.isLockedOneToOne( - ConversationModel.mapToConversationModel(this, conversationUser), - conversationUser.capabilities?.spreedCapability!! - ) && - type != ConversationEnums.ConversationType.FORMER_ONE_TO_ONE && - !ConversationUtils.isNoteToSelfConversation( - ConversationModel.mapToConversationModel(this, conversationUser) - ) - } - - @Deprecated("Use ConversationUtil") - fun isLobbyViewApplicable(conversationUser: User): Boolean { - return !canModerate(conversationUser) && - ( - type == ConversationEnums.ConversationType.ROOM_GROUP_CALL || - type == ConversationEnums.ConversationType.ROOM_PUBLIC_CALL - ) - } - - @Deprecated("Use ConversationUtil") - fun isNameEditable(conversationUser: User): Boolean { - return canModerate(conversationUser) && ConversationEnums.ConversationType.ROOM_TYPE_ONE_TO_ONE_CALL != type - } - - @Deprecated("Use ConversationUtil") - fun canLeave(): Boolean { - return if (canLeaveConversation != null) { - // Available since APIv2 - canLeaveConversation!! - } else { - true - } - } - - @Deprecated("Use ConversationUtil") - fun canDelete(conversationUser: User): Boolean { - return if (canDeleteConversation != null) { - // Available since APIv2 - canDeleteConversation!! - } else { - canModerate(conversationUser) - // Fallback for APIv1 - } - } - - @Deprecated("Use ConversationUtil") - fun isNoteToSelfConversation(): Boolean { - return type == ConversationEnums.ConversationType.NOTE_TO_SELF - } -} + var remoteToken: String? = "" +) : Parcelable 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 1ca4054ca1..66cff6d7b3 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 @@ -134,7 +134,7 @@ class ConversationsListBottomDialog( ) binding.conversationOperationLeave.visibility = setVisibleIf( - ConversationUtils.canLeave(conversation) && + conversation.canLeaveConversation && // leaving is by api not possible for the last user with moderator permissions. // for now, hide this option for all moderators. !ConversationUtils.canModerate(conversation, currentUser.capabilities!!.spreedCapability!!) 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 793ed6eff5..08dbb8587a 100644 --- a/app/src/main/java/com/nextcloud/talk/utils/ConversationUtils.kt +++ b/app/src/main/java/com/nextcloud/talk/utils/ConversationUtils.kt @@ -55,25 +55,6 @@ object ConversationUtils { ConversationEnums.ConversationType.ROOM_TYPE_ONE_TO_ONE_CALL != conversation.type } - fun canLeave(conversation: ConversationModel): Boolean { - return if (conversation.canLeaveConversation != null) { - // Available since APIv2 - conversation.canLeaveConversation!! - } else { - true - } - } - - fun canDelete(conversation: ConversationModel, spreedCapability: SpreedCapability): Boolean { - return if (conversation.canDeleteConversation != null) { - // Available since APIv2 - conversation.canDeleteConversation!! - } else { - canModerate(conversation, spreedCapability) - // Fallback for APIv1 - } - } - fun isNoteToSelfConversation(currentConversation: ConversationModel?): Boolean { return currentConversation != null && currentConversation.type == ConversationEnums.ConversationType.NOTE_TO_SELF diff --git a/app/src/test/java/com/nextcloud/talk/json/ConversationConversionTest.kt b/app/src/test/java/com/nextcloud/talk/json/ConversationConversionTest.kt new file mode 100644 index 0000000000..4115926d59 --- /dev/null +++ b/app/src/test/java/com/nextcloud/talk/json/ConversationConversionTest.kt @@ -0,0 +1,157 @@ +import com.bluelinelabs.logansquare.LoganSquare +import com.nextcloud.talk.data.database.mappers.asEntity +import com.nextcloud.talk.data.database.mappers.asModel +import com.nextcloud.talk.data.database.model.ConversationEntity +import com.nextcloud.talk.models.json.conversations.ConversationEnums +import com.nextcloud.talk.models.json.conversations.RoomOverall +import com.nextcloud.talk.models.json.participants.Participant +import org.junit.Assert.* +import org.junit.Test +import org.junit.runner.RunWith +import org.junit.runners.Parameterized +import java.io.File + +@RunWith(Parameterized::class) +class ConversationConversionTest( + private val jsonFileName: String +) { + + companion object { + @JvmStatic + @Parameterized.Parameters(name = "{index}: testDeserialization({0})") + fun data(): List { + return listOf( + "RoomOverallExample_APIv1.json", + "RoomOverallExample_APIv2.json", + "RoomOverallExample_APIv4.json" + ) + } + } + + @Test + fun testDeserialization() { + val jsonFile = File("src/test/resources/$jsonFileName") + val jsonString = jsonFile.readText() + + val roomOverall: RoomOverall = LoganSquare.parse(jsonString, RoomOverall::class.java) + assertNotNull(roomOverall) + + val conversationJson = roomOverall.ocs!!.data!! + assertNotNull(conversationJson) + + val conversationEntity = conversationJson.asEntity(1) + assertNotNull(conversationEntity) + + val apiVersion : Int = jsonFileName.substringAfterLast("APIv").first().digitToInt() + + checkConversationEntity(conversationEntity, apiVersion) + + val conversationModel = conversationEntity.asModel() + val conversationEntityConvertedBack = conversationModel.asEntity() + + checkConversationEntity(conversationEntityConvertedBack, apiVersion) + } + + private fun checkConversationEntity( + conversationEntity: ConversationEntity, + apiVersion: Int + ) { + assertEquals("1@juwd77g6", conversationEntity.internalId) + assertEquals(1, conversationEntity.accountId) + + // check if default values are set for the fields when API_V1 is used + if (apiVersion == 1) { + // default values for API_V2 fields + assertEquals(false, conversationEntity.canDeleteConversation) + assertEquals(true, conversationEntity.canLeaveConversation) + + // default values for API_V3 fields + assertEquals("", conversationEntity.description) + assertEquals("", conversationEntity.actorType) + assertEquals("", conversationEntity.actorId) + assertEquals(0, conversationEntity.callFlag) + assertEquals(0, conversationEntity.lastCommonReadMessage) + + // default values for API_V4 fields + assertEquals("", conversationEntity.avatarVersion) + assertEquals(0, conversationEntity.callStartTime) + assertEquals(0, conversationEntity.callRecording) + assertEquals(false, conversationEntity.unreadMentionDirect) + assertEquals("", conversationEntity.status) + assertEquals("", conversationEntity.statusIcon) + assertEquals("", conversationEntity.statusMessage) + assertEquals(null, conversationEntity.statusClearAt) + assertEquals("", conversationEntity.avatarVersion) + assertEquals(0, conversationEntity.callStartTime) + assertEquals(0, conversationEntity.callRecording) + } + + if (apiVersion >= 1) { + assertEquals("juwd77g6", conversationEntity.token) + assertEquals(ConversationEnums.ConversationType.ROOM_TYPE_ONE_TO_ONE_CALL, conversationEntity.type) + assertEquals("marcel", conversationEntity.name) + assertEquals("Marcel", conversationEntity.displayName) + assertEquals(Participant.ParticipantType.OWNER, conversationEntity.participantType) + assertEquals( + ConversationEnums.ConversationReadOnlyState.CONVERSATION_READ_WRITE, + conversationEntity.conversationReadOnlyState + ) + assertEquals(1727185155, conversationEntity.lastPing) + assertEquals("0", conversationEntity.sessionId) + assertEquals(false, conversationEntity.hasPassword) + assertEquals(false, conversationEntity.hasCall) + assertEquals(true, conversationEntity.canStartCall) + assertEquals(1727098966, conversationEntity.lastActivity) + assertEquals(false, conversationEntity.favorite) + assertEquals(ConversationEnums.NotificationLevel.ALWAYS, conversationEntity.notificationLevel) + assertEquals(ConversationEnums.LobbyState.LOBBY_STATE_ALL_PARTICIPANTS, conversationEntity.lobbyState) + assertEquals(0, conversationEntity.lobbyTimer) + assertEquals(0, conversationEntity.unreadMessages) + assertEquals(false, conversationEntity.unreadMention) + assertEquals(92320, conversationEntity.lastReadMessage) + assertNotNull(conversationEntity.lastMessage) + assertTrue(conversationEntity.lastMessage is String) + assertTrue(conversationEntity.lastMessage!!.contains("token")) + assertEquals(ConversationEnums.ObjectType.DEFAULT, conversationEntity.objectType) + } + + if (apiVersion >= 2) { + assertEquals(false, conversationEntity.canDeleteConversation) + assertEquals(true, conversationEntity.canLeaveConversation) + } + + if (apiVersion >= 3) { + assertEquals("test", conversationEntity.description) + // assertEquals("", conversationEntity.attendeeId) // Not implemented + // assertEquals("", conversationEntity.attendeePin) // Not implemented + assertEquals("users", conversationEntity.actorType) + assertEquals("marcel2", conversationEntity.actorId) + + // assertEquals("", conversationEntity.listable) // Not implemented + assertEquals(0, conversationEntity.callFlag) + // assertEquals("", conversationEntity.sipEnabled) // Not implemented + // assertEquals("", conversationEntity.canEnableSIP) // Not implemented + assertEquals(92320, conversationEntity.lastCommonReadMessage) + } + + if (apiVersion >= 4) { + assertEquals("143a9df3", conversationEntity.avatarVersion) + assertEquals(0, conversationEntity.callStartTime) + assertEquals(0, conversationEntity.callRecording) + assertEquals(false, conversationEntity.unreadMentionDirect) + // assertEquals(, conversationEntity.breakoutRoomMode) // Not implemented + // assertEquals(, conversationEntity.breakoutRoomStatus) // Not implemented + assertEquals("away", conversationEntity.status) + assertEquals("👻", conversationEntity.statusIcon) + assertEquals("buuuuh", conversationEntity.statusMessage) + assertEquals(null, conversationEntity.statusClearAt) + assertEquals("143a9df3", conversationEntity.avatarVersion) + // assertEquals("", conversationEntity.isCustomAvatar) // Not implemented + assertEquals(0, conversationEntity.callStartTime) + assertEquals(0, conversationEntity.callRecording) + // assertEquals("", conversationEntity.recordingConsent) // Not implemented + // assertEquals("", conversationEntity.mentionPermissions) // Not implemented + // assertEquals("", conversationEntity.isArchived) // Not implemented + } + } +} diff --git a/app/src/test/resources/RoomOverallExample_APIv1.json b/app/src/test/resources/RoomOverallExample_APIv1.json new file mode 100644 index 0000000000..993f95c512 --- /dev/null +++ b/app/src/test/resources/RoomOverallExample_APIv1.json @@ -0,0 +1,66 @@ +{ + "ocs": { + "meta": { + "status": "ok", + "statuscode": 200, + "message": "OK" + }, + "data": { + "id": 6410, + "token": "juwd77g6", + "type": 1, + "name": "marcel", + "displayName": "Marcel", + "objectType": "", + "objectId": "", + "participantType": 1, + "participantInCall": false, + "participantFlags": 0, + "readOnly": 0, + "count": 0, + "hasPassword": false, + "hasCall": false, + "canStartCall": true, + "lastActivity": 1727098966, + "lastReadMessage": 92320, + "unreadMessages": 0, + "unreadMention": false, + "isFavorite": false, + "notificationLevel": 1, + "lobbyState": 0, + "lobbyTimer": 0, + "lastPing": 1727185155, + "sessionId": "0", + "participants": { + "marcel": { + "name": "marcel", + "type": 1, + "call": 0, + "sessionId": "tonIuryMpwk5mR2h6lFqPC6M8m6hxdT4YN9X9I1v4i2LOJb9r3FzANx\/7HT0j6r8fzBFPJqnOrT\/mdvHzFlfqQsr6Gxo0\/aLkDfIRL32XlGIzficfLaBNCsyctPxwgHv0fwmJUOS2i0ONdC+QWyTJ4bpYw1Ch9hiybxCgEtss3xy9fbjPwWj3gLvpMpcH0OuNkfEwHqByhpiAb3xuu60\/6j671uwYiGe2Ba7PzLFJ3LVuVRXXTbeaZlVwTAioOu" + }, + "Testuser.Lastname": { + "name": "Testuser", + "type": 1, + "call": 0, + "sessionId": "0" + } + }, + "numGuests": 0, + "guestList": "", + "lastMessage": { + "id": 175430, + "token": "juwd77g6", + "actorType": "users", + "actorId": "marcel", + "actorDisplayName": "Marcel", + "timestamp": 1727182442, + "message": "test", + "messageParameters": [], + "systemMessage": "", + "messageType": "comment", + "isReplyable": true, + "referenceId": "" + } + } + } +} diff --git a/app/src/test/resources/RoomOverallExample_APIv2.json b/app/src/test/resources/RoomOverallExample_APIv2.json new file mode 100644 index 0000000000..9148c6b875 --- /dev/null +++ b/app/src/test/resources/RoomOverallExample_APIv2.json @@ -0,0 +1,51 @@ +{ + "ocs": { + "meta": { + "status": "ok", + "statuscode": 200, + "message": "OK" + }, + "data": { + "id": 6410, + "token": "juwd77g6", + "type": 1, + "name": "marcel", + "displayName": "Marcel", + "objectType": "", + "objectId": "", + "participantType": 1, + "participantFlags": 0, + "readOnly": 0, + "hasPassword": false, + "hasCall": false, + "canStartCall": true, + "lastActivity": 1727098966, + "lastReadMessage": 92320, + "unreadMessages": 0, + "unreadMention": false, + "isFavorite": false, + "canLeaveConversation": true, + "canDeleteConversation": false, + "notificationLevel": 1, + "lobbyState": 0, + "lobbyTimer": 0, + "lastPing": 1727185155, + "sessionId": "0", + "guestList": "", + "lastMessage": { + "id": 175430, + "token": "juwd77g6", + "actorType": "users", + "actorId": "marcel", + "actorDisplayName": "Marcel", + "timestamp": 1727182442, + "message": "test", + "messageParameters": [], + "systemMessage": "", + "messageType": "comment", + "isReplyable": true, + "referenceId": "" + } + } + } +} diff --git a/app/src/test/resources/RoomOverallExample_APIv4.json b/app/src/test/resources/RoomOverallExample_APIv4.json new file mode 100644 index 0000000000..59ef478ca2 --- /dev/null +++ b/app/src/test/resources/RoomOverallExample_APIv4.json @@ -0,0 +1,83 @@ +{ + "ocs": { + "meta": { + "status": "ok", + "statuscode": 200, + "message": "OK" + }, + "data": { + "id": 181, + "token": "juwd77g6", + "type": 1, + "name": "marcel", + "displayName": "Marcel", + "objectType": "", + "objectId": "", + "participantType": 1, + "participantFlags": 0, + "readOnly": 0, + "hasPassword": false, + "hasCall": false, + "callStartTime": 0, + "callRecording": 0, + "canStartCall": true, + "lastActivity": 1727098966, + "lastReadMessage": 92320, + "unreadMessages": 0, + "unreadMention": false, + "unreadMentionDirect": false, + "isFavorite": false, + "canLeaveConversation": true, + "canDeleteConversation": false, + "notificationLevel": 1, + "notificationCalls": 1, + "lobbyState": 0, + "lobbyTimer": 0, + "lastPing": 1727185155, + "sessionId": "0", + "lastMessage": { + "id": 92320, + "token": "3853979093", + "actorType": "users", + "actorId": "marcel", + "actorDisplayName": "Marcel", + "timestamp": 1726673204, + "message": "Test", + "messageParameters": [], + "systemMessage": "", + "messageType": "comment", + "isReplyable": true, + "referenceId": "", + "reactions": {}, + "expirationTimestamp": 0, + "markdown": true + }, + "sipEnabled": 0, + "actorType": "users", + "actorId": "marcel2", + "attendeeId": 5810, + "permissions": 254, + "attendeePermissions": 0, + "callPermissions": 0, + "defaultPermissions": 0, + "canEnableSIP": false, + "attendeePin": "", + "description": "test", + "lastCommonReadMessage": 92320, + "listable": 0, + "callFlag": 0, + "messageExpiration": 0, + "avatarVersion": "143a9df3", + "isCustomAvatar": false, + "breakoutRoomMode": 0, + "breakoutRoomStatus": 0, + "recordingConsent": 0, + "mentionPermissions": 0, + "isArchived": false, + "status": "away", + "statusIcon": "👻", + "statusMessage": "buuuuh", + "statusClearAt": null + } + } +} From 16c49bc430ee1837695f5a8f6a69176214b17390 Mon Sep 17 00:00:00 2001 From: Marcel Hibbe Date: Thu, 26 Sep 2024 11:44:34 +0200 Subject: [PATCH 110/885] bump versions for SERVER_VERSION_MIN_SUPPORTED + SERVER_VERSION_SUPPORT_WARNING Signed-off-by: Marcel Hibbe --- .../main/java/com/nextcloud/talk/utils/CapabilitiesUtil.kt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/app/src/main/java/com/nextcloud/talk/utils/CapabilitiesUtil.kt b/app/src/main/java/com/nextcloud/talk/utils/CapabilitiesUtil.kt index 63e55c08db..7329b085a1 100644 --- a/app/src/main/java/com/nextcloud/talk/utils/CapabilitiesUtil.kt +++ b/app/src/main/java/com/nextcloud/talk/utils/CapabilitiesUtil.kt @@ -295,6 +295,6 @@ object CapabilitiesUtil { const val RECORDING_CONSENT_NOT_REQUIRED = 0 const val RECORDING_CONSENT_REQUIRED = 1 const val RECORDING_CONSENT_DEPEND_ON_CONVERSATION = 2 - private const val SERVER_VERSION_MIN_SUPPORTED = 14 - private const val SERVER_VERSION_SUPPORT_WARNING = 18 + private const val SERVER_VERSION_MIN_SUPPORTED = 17 + private const val SERVER_VERSION_SUPPORT_WARNING = 26 } From 28bb0d7106e1d621fda8de187ec2e082a7d75c20 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Thu, 26 Sep 2024 15:16:35 +0000 Subject: [PATCH 111/885] Update dependency com.github.nextcloud.android-common:ui to v0.23.1 Signed-off-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- app/build.gradle | 4 ++-- gradle/verification-metadata.xml | 24 ++++++++++++++++++++++++ 2 files changed, 26 insertions(+), 2 deletions(-) diff --git a/app/build.gradle b/app/build.gradle index c36c4d0eaf..2bdb32925e 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -300,7 +300,7 @@ dependencies { implementation 'androidx.core:core-ktx:1.13.1' implementation 'androidx.activity:activity-ktx:1.9.2' - implementation 'com.github.nextcloud.android-common:ui:0.23.0' + implementation 'com.github.nextcloud.android-common:ui:0.23.1' implementation 'com.github.nextcloud-deps:android-talk-webrtc:121.6167.0' gplayImplementation 'com.google.android.gms:play-services-base:18.5.0' @@ -346,7 +346,7 @@ dependencies { implementation 'androidx.activity:activity-ktx:1.9.2' - implementation 'com.github.nextcloud.android-common:ui:0.23.0' + implementation 'com.github.nextcloud.android-common:ui:0.23.1' implementation 'com.github.nextcloud-deps:android-talk-webrtc:121.6167.0' implementation("io.coil-kt:coil-compose:2.7.0") diff --git a/gradle/verification-metadata.xml b/gradle/verification-metadata.xml index dd1f01422e..325911d915 100644 --- a/gradle/verification-metadata.xml +++ b/gradle/verification-metadata.xml @@ -4569,6 +4569,14 @@ + + + + + + + + @@ -4617,6 +4625,14 @@ + + + + + + + + @@ -4665,6 +4681,14 @@ + + + + + + + + From 0c39083b35f39e8cb17aede08483bc53417fd594 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Thu, 26 Sep 2024 21:22:11 +0000 Subject: [PATCH 112/885] Update dependency ubuntu to v24 Signed-off-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- .github/workflows/analysis.yml | 2 +- .github/workflows/codeql.yml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/analysis.yml b/.github/workflows/analysis.yml index df08967031..c283a0b590 100644 --- a/.github/workflows/analysis.yml +++ b/.github/workflows/analysis.yml @@ -24,7 +24,7 @@ concurrency: jobs: analysis: - runs-on: ubuntu-22.04 + runs-on: ubuntu-24.04 steps: - name: Setup variables id: get-vars diff --git a/.github/workflows/codeql.yml b/.github/workflows/codeql.yml index d0c4cb4e03..1c0ba92a96 100644 --- a/.github/workflows/codeql.yml +++ b/.github/workflows/codeql.yml @@ -22,7 +22,7 @@ permissions: jobs: analyze: name: Analyze - runs-on: ubuntu-22.04 + runs-on: ubuntu-24.04 permissions: actions: read contents: read From ca747af78cb4c128f16d6ad2291ed25f69254583 Mon Sep 17 00:00:00 2001 From: Nextcloud bot Date: Fri, 27 Sep 2024 02:51:56 +0000 Subject: [PATCH 113/885] Fix(l10n): Update translations from Transifex Signed-off-by: Nextcloud bot --- app/src/main/res/values-b+en+001/strings.xml | 1 + app/src/main/res/values-de/strings.xml | 1 + app/src/main/res/values-es/strings.xml | 1 + app/src/main/res/values-eu/strings.xml | 1 + app/src/main/res/values-fi-rFI/strings.xml | 1 + app/src/main/res/values-fr/strings.xml | 3 +++ app/src/main/res/values-ga/strings.xml | 3 +++ app/src/main/res/values-gl/strings.xml | 3 +++ app/src/main/res/values-hr/strings.xml | 2 ++ app/src/main/res/values-hu-rHU/strings.xml | 3 +++ app/src/main/res/values-it/strings.xml | 3 +++ app/src/main/res/values-ja-rJP/strings.xml | 3 +++ app/src/main/res/values-ko/strings.xml | 3 +++ app/src/main/res/values-lt-rLT/strings.xml | 2 ++ app/src/main/res/values-nb-rNO/strings.xml | 3 +++ app/src/main/res/values-nl/strings.xml | 2 ++ app/src/main/res/values-pl/strings.xml | 3 +++ app/src/main/res/values-pt-rBR/strings.xml | 3 +++ app/src/main/res/values-ru/strings.xml | 3 +++ app/src/main/res/values-sc/strings.xml | 2 ++ app/src/main/res/values-sk-rSK/strings.xml | 3 +++ app/src/main/res/values-sl/strings.xml | 3 +++ app/src/main/res/values-sr/strings.xml | 3 +++ app/src/main/res/values-sv/strings.xml | 3 +++ app/src/main/res/values-tr/strings.xml | 3 +++ app/src/main/res/values-uk/strings.xml | 3 +++ app/src/main/res/values-zh-rCN/strings.xml | 3 +++ app/src/main/res/values-zh-rHK/strings.xml | 3 +++ app/src/main/res/values-zh-rTW/strings.xml | 3 +++ 29 files changed, 73 insertions(+) diff --git a/app/src/main/res/values-b+en+001/strings.xml b/app/src/main/res/values-b+en+001/strings.xml index 5d9b0e3aef..a85f1b1808 100644 --- a/app/src/main/res/values-b+en+001/strings.xml +++ b/app/src/main/res/values-b+en+001/strings.xml @@ -408,6 +408,7 @@ Server does not have supported Talk app installed Server address https://… %1$s only works with %2$s 13 and up + Set new password Set Password Settings Your already existing account was updated, instead of adding a new one diff --git a/app/src/main/res/values-de/strings.xml b/app/src/main/res/values-de/strings.xml index 9396f7d1ba..a6a4d3cc7d 100644 --- a/app/src/main/res/values-de/strings.xml +++ b/app/src/main/res/values-de/strings.xml @@ -408,6 +408,7 @@ Auf dem Server ist keine unterstützte Talk-App installiert Serveradresse https://… %1$s funktioniert nur mit %2$s 13 und höher + Neues Passwort setzen Passwort festlegen Einstellungen Statt ein neues Konto hinzuzufügen, wurde Ihr aktuelles Konto aktualisiert. diff --git a/app/src/main/res/values-es/strings.xml b/app/src/main/res/values-es/strings.xml index 6b799f48c4..7fe4e59732 100644 --- a/app/src/main/res/values-es/strings.xml +++ b/app/src/main/res/values-es/strings.xml @@ -397,6 +397,7 @@ El servidor no tiene una app Talk soportada instalada Dirección del servidor https://… %1$s sólo trabaja con %2$s 13 y superior + Establecer contraseña nueva Configuración Tu cuenta ya existente ha sido actualizada en lugar de añadir una nueva Avanzado diff --git a/app/src/main/res/values-eu/strings.xml b/app/src/main/res/values-eu/strings.xml index b84f9a9183..4e3bc1d65e 100644 --- a/app/src/main/res/values-eu/strings.xml +++ b/app/src/main/res/values-eu/strings.xml @@ -354,6 +354,7 @@ Zerbitzariak ez du Talk aplikazio bateragarririk instalatuta Zerbitzariaren helbidea https://… %1$s (e)k %2$s 13rekin eta goragokoarekin bakarrik egiten du lan + Ezarri pasahitz berria Ezarpenak Zure kontua eguneratu egin da, beste kontu bat gehitu beharrean Aurreratua diff --git a/app/src/main/res/values-fi-rFI/strings.xml b/app/src/main/res/values-fi-rFI/strings.xml index 25770b6bdc..1167a71e21 100644 --- a/app/src/main/res/values-fi-rFI/strings.xml +++ b/app/src/main/res/values-fi-rFI/strings.xml @@ -268,6 +268,7 @@ Testataan yhteyttä Tuettua Talk-sovellusta ei ole asennettu palvelimelle Palvelimen osoite https://… + Aseta uusi salasana: Asetukset Olemassa oleva tilisi päivitettiin sen sijaan, että olisi lisätty tili Lisäasetukset diff --git a/app/src/main/res/values-fr/strings.xml b/app/src/main/res/values-fr/strings.xml index 225d4b3a2e..d3c191f9e5 100644 --- a/app/src/main/res/values-fr/strings.xml +++ b/app/src/main/res/values-fr/strings.xml @@ -125,6 +125,7 @@ Vérifier le certificat Votre configuration SSL a empêché la connexion Modifier le certificat d\'authentification + Changer son mot de passe Veuillez vérifier votre connexion Internet Supprimer tous les messages Tous les messages ont été supprimés @@ -322,6 +323,7 @@ De l\'aide supplémentaire peut être trouvée sur DontKillMyApp.com ou dans la Propriétaire Participants Ajouter des participants + Mot de passe Définir les autorisations Certaines autorisations n\'ont pas été accordées. Merci de donner les autorisations @@ -394,6 +396,7 @@ De l\'aide supplémentaire peut être trouvée sur DontKillMyApp.com ou dans la Le serveur n\'a pas d\'application Talk prise en charge installée. Adresse du serveur https://… %1$s ne fonctionne qu\'avec %2$s 13 et supérieur + Définir un nouveau mot de passe Paramètres Nous avons mis à jour votre compte existant au lieu d’en ajouter un nouveau Avancé diff --git a/app/src/main/res/values-ga/strings.xml b/app/src/main/res/values-ga/strings.xml index 184a233b27..abe37c521b 100644 --- a/app/src/main/res/values-ga/strings.xml +++ b/app/src/main/res/values-ga/strings.xml @@ -127,6 +127,7 @@ Seiceáil an teastas Chuir do shocrú SSL cosc ​​ar cheangal Athraigh teastas fíordheimhnithe + Athraigh do phasfhocal Seiceáil do nasc idirlín le do thoil Glan an Cnaipe Eagar Glan an Teachtaireacht in Eagar @@ -335,6 +336,7 @@ Úinéir Rannpháirtithe Cuir rannpháirtithe leis + Pasfhocal Socraigh ceadanna Diúltaíodh roinnt ceadanna. Ceadaigh ceadanna le do thoil @@ -408,6 +410,7 @@ Níl an aip Talk tacaithe ag an bhfreastalaí suiteáilte Seoladh an fhreastalaí https://… Ní oibríonn %1$s ach le %2$s 13 agus níos sine + Socraigh pasfhocal nua Socraigh Pasfhocal Socruithe Nuashonraíodh do chuntas a bhí ann cheana féin, in ionad ceann nua a chur leis diff --git a/app/src/main/res/values-gl/strings.xml b/app/src/main/res/values-gl/strings.xml index 80a03cb399..52e6037cc4 100644 --- a/app/src/main/res/values-gl/strings.xml +++ b/app/src/main/res/values-gl/strings.xml @@ -127,6 +127,7 @@ Verificar o certificado A súa configuración SSL impediu a conexión Cambiar o certificado de autenticación + Cambiar o contrasinal Comprobe a conexión á Internet Botón de limpar a edición Limpar a mensaxe de edición @@ -335,6 +336,7 @@ Propietario Participantes Engadir participantes + Contrasinal Establecer os permisos Algúns permisos foron denegados. Autorice os permisos @@ -408,6 +410,7 @@ O servidor non ten instalada a aplicación Talk Enderezo do servidor https://… %1$s só funciona con %2$s 13 ou superior + Definir un novo contrasinal Definir o contrasinal Axustes Actualizouse a súa conta xa existente no canto de crear unha nova diff --git a/app/src/main/res/values-hr/strings.xml b/app/src/main/res/values-hr/strings.xml index 4111d7d117..6b135f7bf3 100644 --- a/app/src/main/res/values-hr/strings.xml +++ b/app/src/main/res/values-hr/strings.xml @@ -73,6 +73,7 @@ Pogledaj vjerodajnicu Vezu je onemogućila vaša postavka SSL-a Promijeni vjerodajnicu za autentifikaciju + Promijeni zaporku Izbriši sve poruke Izbrisane su sve poruke Želite li zaista izbrisati sve poruke u ovom razgovoru? @@ -202,6 +203,7 @@ Vlasnik Sudionici Dodaj sudionike + Zaporka Otvori postavke Račun nije pronađen Razmjenjujte poruke putem %s diff --git a/app/src/main/res/values-hu-rHU/strings.xml b/app/src/main/res/values-hu-rHU/strings.xml index d53b77a8e9..9638c8732b 100644 --- a/app/src/main/res/values-hu-rHU/strings.xml +++ b/app/src/main/res/values-hu-rHU/strings.xml @@ -104,6 +104,7 @@ Ellenőrizze a tanúsítványt Az SSL beállítás megakadályozta a kapcsolódást Hitelesítési tanúsítvány módosítása + Jelszó módosítása Összes üzenet törlése Az összes üzenet törölve lett Biztos, hogy törli a beszélgetés összes üzenetét? @@ -266,6 +267,7 @@ Tulajdonos Résztvevők Résztvevők hozzáadása + Jelszó Jogosultságok beállításaa Néhány jogosultság meg lett tagadva. Engedélyezzen jogosultságokat @@ -337,6 +339,7 @@ A kiszolgálón nincs támogatott Beszélgetés alkalmazás telepítve Kiszolgálócím https://… A(z) %1$s csak %2$s 13 vagy újabb verzióval működik + Jelszó beállítása Beállítások Új fiók hozzáadása helyett, a már létező fiókja lett frissítve Speciális diff --git a/app/src/main/res/values-it/strings.xml b/app/src/main/res/values-it/strings.xml index 8e3be4aa36..174ac008e4 100644 --- a/app/src/main/res/values-it/strings.xml +++ b/app/src/main/res/values-it/strings.xml @@ -86,6 +86,7 @@ Controlla il certificato La tua configurazione SSL ha impedito la connessione Cambia certificato di autenticazione + Cambia password Elimina tutti i messaggi Tutti i messaggi sono stati eliminati Vuoi davvero eliminare tutti i messaggi in questa conversazione? @@ -224,6 +225,7 @@ Proprietario Partecipanti Aggiungi partecipanti + Password Apri impostazioni Account non trovato Chat tramite %s @@ -289,6 +291,7 @@ Sul server non è installata un\'applicazione Talk supportata Indirizzo server https://… %1$s funziona solo con %2$s 13 e successivi + Imposta una nuova password Impostazioni Il tuo account preesistente è stato aggiornato, invece di aggiungerne un nuovo Avanzate diff --git a/app/src/main/res/values-ja-rJP/strings.xml b/app/src/main/res/values-ja-rJP/strings.xml index bdeb071a70..acf4be88f8 100644 --- a/app/src/main/res/values-ja-rJP/strings.xml +++ b/app/src/main/res/values-ja-rJP/strings.xml @@ -116,6 +116,7 @@ 証明書をチェックアウトする SSL設定で接続が妨げられました 認証証明書を変更する + パスワードを変更 あなたのインターネット接続をチェックしてください 編集ボタンを削除 編集メッセージを削除 @@ -321,6 +322,7 @@ オーナー 参加者 参加を追加 + パスワード 権限セット 一部の権限が拒否されました。 権限を許可してください @@ -394,6 +396,7 @@ サーバーにサポートされているトークアプリがインストールされていません サーバーのアドレス https://… %1$sは%2$s 13以降でのみ動作します + 新しいパスワードの設定 設定 新しいアカウントを追加する代わりに、既存のアカウントが更新されました 高度な diff --git a/app/src/main/res/values-ko/strings.xml b/app/src/main/res/values-ko/strings.xml index b63dfc3760..f946127728 100644 --- a/app/src/main/res/values-ko/strings.xml +++ b/app/src/main/res/values-ko/strings.xml @@ -87,6 +87,7 @@ 인증서 확인 SSL 설정에서 연결을 거부함 인증서 변경 + 암호 변경 모든 메시지 삭제 모든 메시지가 삭제되었습니다. 이 대화에서 모든 메시지를 삭제하시겠습니까? @@ -237,6 +238,7 @@ Owner 참가자 참가자 추가 + 암호 설정 열기 계정을 찾을 수 없습니다. %s을 통한 채팅 @@ -303,6 +305,7 @@ 서버에 지원되는 토크 앱이 설치되어 있지 않습니다. 서버 주소 https://… %1$s은(는) %2$s 13 이상에서만 작동합니다 + 새 암호 설정 설정 새 계정을 추가하는 대신 기존 계정이 업데이트됨 고급 diff --git a/app/src/main/res/values-lt-rLT/strings.xml b/app/src/main/res/values-lt-rLT/strings.xml index fa5034ddeb..f1e79eb475 100644 --- a/app/src/main/res/values-lt-rLT/strings.xml +++ b/app/src/main/res/values-lt-rLT/strings.xml @@ -56,6 +56,7 @@ Ar pasitikite iki šiol nežinomu SSL liudijimu, kurį išdavė %1$s, kuris skirtas %2$s ir galioja nuo %3$s iki %4$s? Jūsų SSL sąranka neleido ryšio Keisti tapatybės nustatymo liudijimą + Pakeisti slaptažodį Keisti kliento programėlės liudijimą Nustatyti kliento programėlės liudijimą ir @@ -157,6 +158,7 @@ Savininkas Dalyviai Pridėti dalyvius + Slaptažodis Atverti nustatymus Paskyra nerasta Išjungti mikrofoną diff --git a/app/src/main/res/values-nb-rNO/strings.xml b/app/src/main/res/values-nb-rNO/strings.xml index df99a1e526..b59f6bcec5 100644 --- a/app/src/main/res/values-nb-rNO/strings.xml +++ b/app/src/main/res/values-nb-rNO/strings.xml @@ -126,6 +126,7 @@ Sjekk sertifikatet Ditt SSL-oppsett forhindret tilkobling Endre sertifikat for autentisering + Endre passord Vennligst kontroller internettforbindelsen din Tøm redigeringsknapp Fjern redigeringsmelding @@ -333,6 +334,7 @@ Eier Deltakere Legg til deltager + PassordP Angi rettigheter Noen rettigheter ble nektet. Vennligst tillat rettigheter @@ -406,6 +408,7 @@ Serveren har ikke en støttet Talk app installert Serveradresse https://… %1$s fungerer bare med %2$s 13 og høyere + Angi nytt passord Instillinger Din allerede eksisterende konto ble oppdatert, istedenfor å legge til en ny Avansert diff --git a/app/src/main/res/values-nl/strings.xml b/app/src/main/res/values-nl/strings.xml index 1b3384d34d..171722e06d 100644 --- a/app/src/main/res/values-nl/strings.xml +++ b/app/src/main/res/values-nl/strings.xml @@ -86,6 +86,7 @@ Controleer het certificaat Je SSL-instellingen blokkeerden de verbinding Authenticatiecertificaat veranderen + Wijzig wachtwoord Alle berichten verwijderen Alle berichten zijn verwijderd Wil je echt dit alle andere berichten in dit gesprek echt verwijderen? @@ -225,6 +226,7 @@ Kies er eentje van een provider. Eigenaar Deelnemers Deelnemers toevoegen + Wachtwoord Openen instellingen Account niet gevonden Chat via %s diff --git a/app/src/main/res/values-pl/strings.xml b/app/src/main/res/values-pl/strings.xml index 3cc23610bf..8bc2800946 100644 --- a/app/src/main/res/values-pl/strings.xml +++ b/app/src/main/res/values-pl/strings.xml @@ -116,6 +116,7 @@ Sprawdź certyfikat Twoje ustawienia SSL uniemożliwiają połaczenie Zmień certyfikat uwierzytelnienia + Zmień hasło Proszę sprawdzić swoje połączenie z internetem Wyczyść przycisk Edytuj Wyczyść Edytuj wiadomość @@ -324,6 +325,7 @@ Właściciel Uczestnicy Dodaj uczestników + Hasło Ustaw uprawnienia Odmówiono niektórych uprawnień. Zezwól na uprawnienia @@ -397,6 +399,7 @@ Serwer nie obsługuje zainstalowanej aplikacji Talk Adres serwera https://… %1$s działa tylko z %2$s 13 i nowszym + Ustaw nowe hasło Ustawienia Zamiast dodawać nowe, zaktualizowano Twoje istniejące konto Zaawansowane diff --git a/app/src/main/res/values-pt-rBR/strings.xml b/app/src/main/res/values-pt-rBR/strings.xml index 2dea6c1105..4b0afc34fb 100644 --- a/app/src/main/res/values-pt-rBR/strings.xml +++ b/app/src/main/res/values-pt-rBR/strings.xml @@ -127,6 +127,7 @@ Confira o certificado Sua configuração SSL impediu a conexão Alterar certificado de autenticação + Alterar senha Por favor, verifique sua conexão à internet Botão Limpar Editar Limpar Editar Mensagem @@ -335,6 +336,7 @@ Proprietário Participantes Adicionar participantes + Senha Definir permissões Algumas permissões foram negadas. Por favor, permita permissões @@ -408,6 +410,7 @@ O servidor não tem o aplicativo Talk suportado instalado Endereço do servidor https://… %1$s somente funciona com%2$s 13 e posterior + Definir nova senha Definir Senha Configurações Sua conta atual foi atualizada, em vez de adicionar uma nova diff --git a/app/src/main/res/values-ru/strings.xml b/app/src/main/res/values-ru/strings.xml index 0e92628e65..c158876423 100644 --- a/app/src/main/res/values-ru/strings.xml +++ b/app/src/main/res/values-ru/strings.xml @@ -115,6 +115,7 @@ Проверьте сертификат Заданные параметры SSL не позволяют подключиться Изменить сертификат для подтверждения подлинности + Изменить пароль Проверьте подключение к Интернету. Удалить все сообщения Все сообщения были удалены @@ -297,6 +298,7 @@ Владелец Участники Добавить участников + Пароль Установить разрешения В некоторых разрешениях было отказано. Открыть настройки @@ -368,6 +370,7 @@ На сервере не установлено приложение «Конференции» Адрес сервера https://… Работа приложения %1$s возможна только с серверами %2$s версии 13 или старше + Установить новый пароль Установить пароль Параметры Вместо создания новой учётной записи было выполнено обновление существующей diff --git a/app/src/main/res/values-sc/strings.xml b/app/src/main/res/values-sc/strings.xml index eaeba09a04..1d2d15c965 100644 --- a/app/src/main/res/values-sc/strings.xml +++ b/app/src/main/res/values-sc/strings.xml @@ -69,6 +69,7 @@ Controlla su tzertificadu Sa cunfiguratzione SSL at refudadu sa connessione Càmbia tzertificadu autenticatzione + Càmbia crae Cantzella totu is messàgios Cantzellados totu is messàgios A beru boles cantzellare totu is messàgios in custa resonada? @@ -193,6 +194,7 @@ Mere Partetzipantes Aguinghe partetzipantes + Crae Aberi sa cunfiguratzione Contu no agatadu Tzarrada via %s diff --git a/app/src/main/res/values-sk-rSK/strings.xml b/app/src/main/res/values-sk-rSK/strings.xml index 115fd5905d..e506e4af86 100644 --- a/app/src/main/res/values-sk-rSK/strings.xml +++ b/app/src/main/res/values-sk-rSK/strings.xml @@ -116,6 +116,7 @@ Skontrolujte certifikát Vaša konfigurácia SSL zabránila pripojeniu Zmeniť autentifikačný certifikát + Zmeniť heslo Tlačidlo Vymazať úpravy Správa vymazať úpravy Vymazať všetky správy @@ -323,6 +324,7 @@ Vlastník Účastníci Pridať účastníkov + Heslo Nastaviť oprávnenia Niektoré oprávnenia neboli udelené. Prosím, udeľte oprávnenia @@ -396,6 +398,7 @@ Na serveri nie je nainštalovaná podporovaná apka Rozhovor Adresa servera https://… %1$spracuje iba s %2$s13 a vyššie + Vytvoriť nové heslo Nastavenia Namiesto pridania nového účtu, bol aktualizovaný existujúci účet Rozšírené diff --git a/app/src/main/res/values-sl/strings.xml b/app/src/main/res/values-sl/strings.xml index fbda6e9147..d77fc914f4 100644 --- a/app/src/main/res/values-sl/strings.xml +++ b/app/src/main/res/values-sl/strings.xml @@ -94,6 +94,7 @@ Preveri potrdilo Nastavitve SSL onemogočajo vzpostavitev povezave Spremeni potrdilo za overitev + Spremeni geslo Izbriši vsa sporočila Vsa sporočilo so izbrisana Ali res želite izbrisati vsa sporočila tega pogovora? @@ -249,6 +250,7 @@ Lastnik Udeleženci Dodaj udeležence + Geslo Odpri nastavitve Računa ni mogoče najti Klepet prek %s @@ -317,6 +319,7 @@ Na strežniku ni nameščenega ustreznega programa Talk Naslov strežnika: https:// Program %1$s je podprt le na različicah %2$s 13 in novejših. + Nastavi novo geslo Nastavitve Že obstoječ račun je posodobljen, zato nov račun ni bil dodan Napredno diff --git a/app/src/main/res/values-sr/strings.xml b/app/src/main/res/values-sr/strings.xml index 419339fcc1..1298a08313 100644 --- a/app/src/main/res/values-sr/strings.xml +++ b/app/src/main/res/values-sr/strings.xml @@ -127,6 +127,7 @@ Провери сертификат Ваша ССЛ постава је онемогућила повезивање Измени сертификат за пријаву + Промени лозинку Молимо вас да проверите везу са интернетом Обриши дугме за уређивање Обриши Уреди поруку @@ -335,6 +336,7 @@ Власник Учесници Додај учеснике + Лозинка Постави дозволе Неке дозволе нису одобрене. Молимо вас да дате дозволе @@ -408,6 +410,7 @@ Сервер нема инсталирану подржану Talk апликацију Адреса сервера https://… %1$s ради само са%2$s верзије 13 и већом + Постави нову лозинку Постави лозинку Поставке Ваш постојећи налог је ажуриран, уместо што је додат нови налог diff --git a/app/src/main/res/values-sv/strings.xml b/app/src/main/res/values-sv/strings.xml index 0ac98b8efa..12334612b5 100644 --- a/app/src/main/res/values-sv/strings.xml +++ b/app/src/main/res/values-sv/strings.xml @@ -125,6 +125,7 @@ Kontrollera certifikatet Dina SSL-inställningar förhindrade anslutning Ändra autentiseringscertifikat + Ändra lösenord Kontrollerar din internetanslutning Rensa redigeringsknapp Rensa redigera meddelande @@ -332,6 +333,7 @@ Ägare Deltagare Lägg till deltagare + Lösenord Ange behörigheter Vissa behörigheter nekades. Tillåt behörigheter @@ -405,6 +407,7 @@ Servern har inte korrekt Talk-app installerad Serveradress https://… %1$s fungerar bara med %2$s 13 och uppåt + Ange nytt lösenord Ange lösenord Inställningar Ditt redan befintliga konto uppdaterades, istället för att lägga till ett nytt diff --git a/app/src/main/res/values-tr/strings.xml b/app/src/main/res/values-tr/strings.xml index b233ad9ac1..0140c21873 100644 --- a/app/src/main/res/values-tr/strings.xml +++ b/app/src/main/res/values-tr/strings.xml @@ -127,6 +127,7 @@ Sertifikayı denetleyin SSL kurulumunuz bağlantı kurulmasını engelliyor Kimlik doğrulama sertifikasını değiştir + Parolayı değiştir Lütfen İnternet bağlantınızı denetleyin Düzenlemeyi temizle düğmesi Düzenlemeyi temizle iletisi @@ -335,6 +336,7 @@ Sahip Katılımcılar Katılımcı ekle + Parola İzinleri ayarla Bazı izinler verilmemiş. Lütfen izinleri verin @@ -408,6 +410,7 @@ Sunucuda desteklenen bir Konuş uygulaması kurulu değil Sunucu adresi https://… %1$s yalnızca %2$s 13 ve üzerinde çalışır + Yeni parola ayarla Parola ayarla Ayarlar Zaten bir hesabınız bulunduğundan yeni hesap eklenmesi yerine geçerli hesap güncellendi diff --git a/app/src/main/res/values-uk/strings.xml b/app/src/main/res/values-uk/strings.xml index 998cc352de..57da8bb69b 100644 --- a/app/src/main/res/values-uk/strings.xml +++ b/app/src/main/res/values-uk/strings.xml @@ -93,6 +93,7 @@ Перевірка сертифікату Ваші налаштування SSL завадили з’єднанню Змінити сертифікат авторизації + Змінити Пароль Вилучити усі повідомлення Всі повідомлення видалено Ви дійсно бажаєте вилучити усі повідомлення у цій розмові? @@ -240,6 +241,7 @@ Власник Учасники Додати учасників + Пароль Відкрити налаштування Акаунт не знайдено Чат з %s @@ -307,6 +309,7 @@ На сервері не встановлено застосунок \"Talk\", який може підтримуватися Адреса сервера https://… Застосунок %1$s сумісний з %2$s версії 13 або вище + Встановіть новий пароль Налаштування Замість створення нового облікового запису було виконано оновлення існуючого Додатково diff --git a/app/src/main/res/values-zh-rCN/strings.xml b/app/src/main/res/values-zh-rCN/strings.xml index 7eb4be2acf..d88c0784cd 100644 --- a/app/src/main/res/values-zh-rCN/strings.xml +++ b/app/src/main/res/values-zh-rCN/strings.xml @@ -105,6 +105,7 @@ 检查证书 您的 SSL 设置阻止了连接 更换验证证书 + 更改密码 删除所有消息 已删除所有消息 你真想删除对话中的所有信息吗? @@ -270,6 +271,7 @@ 拥有者 参与者 添加参与者 + 密码 设置权限 部分权限被拒绝 请允许权限 @@ -341,6 +343,7 @@ 服务器没有安装受支持的通话应用程序 服务器地址 https://… %1$s 仅支持 %2$s 13 及更高版本 + 设置新密码 设置 已经更新了您现有的账号,而不是添加新的账号 高级 diff --git a/app/src/main/res/values-zh-rHK/strings.xml b/app/src/main/res/values-zh-rHK/strings.xml index f094e0aa5c..ea1f700b6f 100644 --- a/app/src/main/res/values-zh-rHK/strings.xml +++ b/app/src/main/res/values-zh-rHK/strings.xml @@ -127,6 +127,7 @@ 請檢查憑證 您的SSL設定阻擋這連線。 更改驗證證書 + 變更密碼 請檢查您的網際網路連線 清除編輯按鈕 清除編輯訊息 @@ -335,6 +336,7 @@ 擁有者 參與者 添加參與者 + 密碼 設置權限 部份權限被拒絕。 請允許權限 @@ -408,6 +410,7 @@ 伺服器未安裝受支持的 Talk 應用程式 伺服器網址 https://… %1$s!只能在%2$s13版以上運作 + 設置新密碼 設置密碼 設定 已經更新了您現有的帳戶,而不是添加新的帳戶 diff --git a/app/src/main/res/values-zh-rTW/strings.xml b/app/src/main/res/values-zh-rTW/strings.xml index 19d07e4e08..2ad484f918 100644 --- a/app/src/main/res/values-zh-rTW/strings.xml +++ b/app/src/main/res/values-zh-rTW/strings.xml @@ -127,6 +127,7 @@ 請檢查憑證 您的SSL設定阻擋這連線。 變更驗證憑證 + 變更密碼 請檢查您的網際網路連線 清除編輯按鈕 清除編輯訊息 @@ -335,6 +336,7 @@ 擁有者 參與者 新增成員 + 密碼 設定權限 部份權限被拒絕。 請允許權限 @@ -408,6 +410,7 @@ 伺服器未安裝受支援的 Talk 應用程式 伺服器地址 https://… %1$s!只能在%2$s13版以上運作 + 設定新密碼 設定密碼 設定 已更新您現有的帳號,而非新增帳號 From 78e738bd51c3fd9d22f94518b2aacba3e2cfb5f5 Mon Sep 17 00:00:00 2001 From: Marcel Hibbe Date: Fri, 27 Sep 2024 09:14:09 +0200 Subject: [PATCH 114/885] add copyright to fix reuse Signed-off-by: Marcel Hibbe --- REUSE.toml | 2 +- .../nextcloud/talk/json/ConversationConversionTest.kt | 9 +++++++++ 2 files changed, 10 insertions(+), 1 deletion(-) diff --git a/REUSE.toml b/REUSE.toml index f8f6ded520..7873e8620a 100644 --- a/REUSE.toml +++ b/REUSE.toml @@ -6,7 +6,7 @@ SPDX-PackageSupplier = "Nextcloud Android team " SPDX-PackageDownloadLocation = "https://github.com/nextcloud/talk-android" [[annotations]] -path = ["app/src/main/res/values-**/strings.xml", "**/.gitignore", ".idea/**", "app/src/test/resources/robolectric.properties", "app/src/test/resources/mockito-extensions/org.mockito.plugins.MockMaker", "fastlane/metadata/**", "app/schemas/com.nextcloud.talk.data.source.local.TalkDatabase/**.json", "app/src/generic/fastlane/metadata/android/**/full_description.txt"] +path = ["app/src/main/res/values-**/strings.xml", "**/.gitignore", ".idea/**", "app/src/test/resources/robolectric.properties", "app/src/test/resources/mockito-extensions/org.mockito.plugins.MockMaker", "app/src/test/resources/**.json", "fastlane/metadata/**", "app/schemas/com.nextcloud.talk.data.source.local.TalkDatabase/**.json", "app/src/generic/fastlane/metadata/android/**/full_description.txt"] precedence = "aggregate" SPDX-FileCopyrightText = "2017-2024 Nextcloud GmbH and Nextcloud contributors" SPDX-License-Identifier = "GPL-3.0-or-later" diff --git a/app/src/test/java/com/nextcloud/talk/json/ConversationConversionTest.kt b/app/src/test/java/com/nextcloud/talk/json/ConversationConversionTest.kt index 4115926d59..1b44293b81 100644 --- a/app/src/test/java/com/nextcloud/talk/json/ConversationConversionTest.kt +++ b/app/src/test/java/com/nextcloud/talk/json/ConversationConversionTest.kt @@ -1,3 +1,12 @@ +/* + * Nextcloud Talk - Android Client + * + * SPDX-FileCopyrightText: 2024 Marcel Hibbe + * SPDX-License-Identifier: GPL-3.0-or-later + */ + +package com.nextcloud.talk.json + import com.bluelinelabs.logansquare.LoganSquare import com.nextcloud.talk.data.database.mappers.asEntity import com.nextcloud.talk.data.database.mappers.asModel From 1347ec29c4af7328dbc0e135848e61e880f412bf Mon Sep 17 00:00:00 2001 From: sowjanyakch Date: Thu, 26 Sep 2024 12:46:45 +0200 Subject: [PATCH 115/885] Set empty status message and default emoji Signed-off-by: sowjanyakch --- .../nextcloud/talk/ui/dialog/SetStatusDialogFragment.kt | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) 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 1e8577aba3..940f198ba2 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 @@ -22,7 +22,6 @@ import android.widget.AdapterView.OnItemSelectedListener import android.widget.ArrayAdapter import android.widget.ImageView import android.widget.TextView -import androidx.core.widget.doAfterTextChanged import androidx.fragment.app.DialogFragment import androidx.recyclerview.widget.LinearLayoutManager import autodagger.AutoInjector @@ -177,6 +176,8 @@ class SetStatusDialogFragment : setupGeneralStatusOptions() + binding.emoji.setText(getString(R.string.default_emoji)) + binding.clearStatus.setOnClickListener { clearStatus() } binding.setStatus.setOnClickListener { setStatusMessage() } binding.emoji.setOnClickListener { openEmojiPopup() } @@ -214,10 +215,6 @@ class SetStatusDialogFragment : viewThemeUtils.material.colorMaterialButtonPrimaryTonal(binding.setStatus) viewThemeUtils.material.colorTextInputLayout(binding.customStatusInputContainer) - - binding.customStatusInput.doAfterTextChanged { text -> - binding.setStatus.isEnabled = !text.isNullOrEmpty() - } } private fun setupCurrentStatus() { @@ -225,7 +222,6 @@ class SetStatusDialogFragment : binding.emoji.setText(it.icon) binding.customStatusInput.text?.clear() binding.customStatusInput.setText(it.message?.trim()) - binding.setStatus.isEnabled = it.message?.isEmpty() == false visualizeStatus(it.status) if (it.clearAt > 0) { From 25846fe23f844f7ae1e04dd79aec8aa3fa6c288e Mon Sep 17 00:00:00 2001 From: sowjanyakch Date: Thu, 26 Sep 2024 16:28:31 +0200 Subject: [PATCH 116/885] set default emoji only when status icon is null Signed-off-by: sowjanyakch --- .../talk/models/json/conversations/Conversation.kt | 2 +- .../nextcloud/talk/ui/dialog/SetStatusDialogFragment.kt | 4 +++- .../com/nextcloud/talk/json/ConversationConversionTest.kt | 7 ++----- 3 files changed, 6 insertions(+), 7 deletions(-) diff --git a/app/src/main/java/com/nextcloud/talk/models/json/conversations/Conversation.kt b/app/src/main/java/com/nextcloud/talk/models/json/conversations/Conversation.kt index 65cd280c91..af0757c857 100644 --- a/app/src/main/java/com/nextcloud/talk/models/json/conversations/Conversation.kt +++ b/app/src/main/java/com/nextcloud/talk/models/json/conversations/Conversation.kt @@ -58,7 +58,7 @@ data class Conversation( @JsonField(name = ["actorType"]) var actorType: String = "", - var password: String? = null, //check if this can be removed.Does not belong to api response but is used internally? + var password: String? = null, // check if this can be removed.Does not belong to api response but is used internally? @JsonField(name = ["isFavorite"]) var favorite: Boolean = false, 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 940f198ba2..96e6d8692c 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 @@ -176,7 +176,9 @@ class SetStatusDialogFragment : setupGeneralStatusOptions() - binding.emoji.setText(getString(R.string.default_emoji)) + if (currentStatus?.icon == null) { + binding.emoji.setText(getString(R.string.default_emoji)) + } binding.clearStatus.setOnClickListener { clearStatus() } binding.setStatus.setOnClickListener { setStatusMessage() } diff --git a/app/src/test/java/com/nextcloud/talk/json/ConversationConversionTest.kt b/app/src/test/java/com/nextcloud/talk/json/ConversationConversionTest.kt index 1b44293b81..7508bccbfd 100644 --- a/app/src/test/java/com/nextcloud/talk/json/ConversationConversionTest.kt +++ b/app/src/test/java/com/nextcloud/talk/json/ConversationConversionTest.kt @@ -51,7 +51,7 @@ class ConversationConversionTest( val conversationEntity = conversationJson.asEntity(1) assertNotNull(conversationEntity) - val apiVersion : Int = jsonFileName.substringAfterLast("APIv").first().digitToInt() + val apiVersion: Int = jsonFileName.substringAfterLast("APIv").first().digitToInt() checkConversationEntity(conversationEntity, apiVersion) @@ -61,10 +61,7 @@ class ConversationConversionTest( checkConversationEntity(conversationEntityConvertedBack, apiVersion) } - private fun checkConversationEntity( - conversationEntity: ConversationEntity, - apiVersion: Int - ) { + private fun checkConversationEntity(conversationEntity: ConversationEntity, apiVersion: Int) { assertEquals("1@juwd77g6", conversationEntity.internalId) assertEquals(1, conversationEntity.accountId) From ce8c4b2b8462557cc17fd59291a56d756a01ccf3 Mon Sep 17 00:00:00 2001 From: sowjanyakch Date: Thu, 26 Sep 2024 16:35:08 +0200 Subject: [PATCH 117/885] fix file name of voice recording Signed-off-by: sowjanyakch --- .../talk/chat/data/io/MediaRecorderManager.kt | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/app/src/main/java/com/nextcloud/talk/chat/data/io/MediaRecorderManager.kt b/app/src/main/java/com/nextcloud/talk/chat/data/io/MediaRecorderManager.kt index 6e2bae64b0..1a50af5b92 100644 --- a/app/src/main/java/com/nextcloud/talk/chat/data/io/MediaRecorderManager.kt +++ b/app/src/main/java/com/nextcloud/talk/chat/data/io/MediaRecorderManager.kt @@ -140,14 +140,19 @@ class MediaRecorderManager : LifecycleAwareManager { private fun setVoiceRecordFileName(context: Context, currentConversation: ConversationModel) { val simpleDateFormat = SimpleDateFormat(FILE_DATE_PATTERN) val date: String = simpleDateFormat.format(Date()) + val regex = "[/\\\\:%]".toRegex() + val displayName = currentConversation.displayName.replace(regex, " ") + val validDisplayName = displayName.replace("\\s+".toRegex(), " ") - val fileNameWithoutSuffix = String.format( + var fileNameWithoutSuffix = String.format( context.resources.getString(R.string.nc_voice_message_filename), date, - currentConversation.displayName + validDisplayName ) + if (fileNameWithoutSuffix.length > 146) { + fileNameWithoutSuffix = fileNameWithoutSuffix.substring(0, 146) + } val fileName = fileNameWithoutSuffix + VOICE_MESSAGE_FILE_SUFFIX - currentVoiceRecordFile = "${context.cacheDir.absolutePath}/$fileName" } From 2478aa884b3d90fd5253a174774afb563b7ec4e7 Mon Sep 17 00:00:00 2001 From: sowjanyakch Date: Thu, 26 Sep 2024 16:49:07 +0200 Subject: [PATCH 118/885] put file length value in utils Signed-off-by: sowjanyakch --- .../com/nextcloud/talk/chat/data/io/MediaRecorderManager.kt | 5 +++-- app/src/main/java/com/nextcloud/talk/utils/FileUtils.kt | 1 + 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/app/src/main/java/com/nextcloud/talk/chat/data/io/MediaRecorderManager.kt b/app/src/main/java/com/nextcloud/talk/chat/data/io/MediaRecorderManager.kt index 1a50af5b92..168d8a2847 100644 --- a/app/src/main/java/com/nextcloud/talk/chat/data/io/MediaRecorderManager.kt +++ b/app/src/main/java/com/nextcloud/talk/chat/data/io/MediaRecorderManager.kt @@ -13,6 +13,7 @@ import android.media.MediaRecorder import android.util.Log import com.nextcloud.talk.R import com.nextcloud.talk.models.domain.ConversationModel +import com.nextcloud.talk.utils.FileUtils import java.io.IOException import java.text.SimpleDateFormat import java.util.Date @@ -149,8 +150,8 @@ class MediaRecorderManager : LifecycleAwareManager { date, validDisplayName ) - if (fileNameWithoutSuffix.length > 146) { - fileNameWithoutSuffix = fileNameWithoutSuffix.substring(0, 146) + if (fileNameWithoutSuffix.length > FileUtils.FILE_MAX_LENGTH) { + fileNameWithoutSuffix = fileNameWithoutSuffix.substring(0, FileUtils.FILE_MAX_LENGTH) } val fileName = fileNameWithoutSuffix + VOICE_MESSAGE_FILE_SUFFIX currentVoiceRecordFile = "${context.cacheDir.absolutePath}/$fileName" 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 7a9ea633b0..c7ab912813 100644 --- a/app/src/main/java/com/nextcloud/talk/utils/FileUtils.kt +++ b/app/src/main/java/com/nextcloud/talk/utils/FileUtils.kt @@ -27,6 +27,7 @@ object FileUtils { private val TAG = FileUtils::class.java.simpleName private const val RADIX: Int = 16 private const val MD5_LENGTH: Int = 32 + const val FILE_MAX_LENGTH = 146 /** * Creates a new [File] From de582f8b0b7bd4a8304418698ba964b5d1c8d487 Mon Sep 17 00:00:00 2001 From: sowjanyakch Date: Fri, 27 Sep 2024 12:33:52 +0200 Subject: [PATCH 119/885] use variable "VOICE_MESSAGE_PREFIX_MAX_LENGTH" to restrict length of voice recording file name Signed-off-by: sowjanyakch --- .../com/nextcloud/talk/chat/data/io/MediaRecorderManager.kt | 6 +++--- app/src/main/java/com/nextcloud/talk/utils/FileUtils.kt | 1 - 2 files changed, 3 insertions(+), 4 deletions(-) diff --git a/app/src/main/java/com/nextcloud/talk/chat/data/io/MediaRecorderManager.kt b/app/src/main/java/com/nextcloud/talk/chat/data/io/MediaRecorderManager.kt index 168d8a2847..a08ef504e6 100644 --- a/app/src/main/java/com/nextcloud/talk/chat/data/io/MediaRecorderManager.kt +++ b/app/src/main/java/com/nextcloud/talk/chat/data/io/MediaRecorderManager.kt @@ -13,7 +13,6 @@ import android.media.MediaRecorder import android.util.Log import com.nextcloud.talk.R import com.nextcloud.talk.models.domain.ConversationModel -import com.nextcloud.talk.utils.FileUtils import java.io.IOException import java.text.SimpleDateFormat import java.util.Date @@ -32,6 +31,7 @@ class MediaRecorderManager : LifecycleAwareManager { private const val VOICE_MESSAGE_CHANNELS = 1 private const val FILE_DATE_PATTERN = "yyyy-MM-dd HH-mm-ss" private const val VOICE_MESSAGE_FILE_SUFFIX = ".mp3" + private const val VOICE_MESSAGE_PREFIX_MAX_LENGTH = 146 } var currentVoiceRecordFile: String = "" @@ -150,8 +150,8 @@ class MediaRecorderManager : LifecycleAwareManager { date, validDisplayName ) - if (fileNameWithoutSuffix.length > FileUtils.FILE_MAX_LENGTH) { - fileNameWithoutSuffix = fileNameWithoutSuffix.substring(0, FileUtils.FILE_MAX_LENGTH) + if (fileNameWithoutSuffix.length > VOICE_MESSAGE_PREFIX_MAX_LENGTH) { + fileNameWithoutSuffix = fileNameWithoutSuffix.substring(0, VOICE_MESSAGE_PREFIX_MAX_LENGTH) } val fileName = fileNameWithoutSuffix + VOICE_MESSAGE_FILE_SUFFIX currentVoiceRecordFile = "${context.cacheDir.absolutePath}/$fileName" 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 c7ab912813..7a9ea633b0 100644 --- a/app/src/main/java/com/nextcloud/talk/utils/FileUtils.kt +++ b/app/src/main/java/com/nextcloud/talk/utils/FileUtils.kt @@ -27,7 +27,6 @@ object FileUtils { private val TAG = FileUtils::class.java.simpleName private const val RADIX: Int = 16 private const val MD5_LENGTH: Int = 32 - const val FILE_MAX_LENGTH = 146 /** * Creates a new [File] From 94d62a943fbc8e9c1c368419e28a472ce3ae800e Mon Sep 17 00:00:00 2001 From: Marcel Hibbe Date: Fri, 27 Sep 2024 16:48:16 +0200 Subject: [PATCH 120/885] fix position and animation of typing indicator Without this fix, typing indicator moves up and wont go down Signed-off-by: Marcel Hibbe --- .../com/nextcloud/talk/chat/ChatActivity.kt | 18 ++++++++++-------- 1 file changed, 10 insertions(+), 8 deletions(-) diff --git a/app/src/main/java/com/nextcloud/talk/chat/ChatActivity.kt b/app/src/main/java/com/nextcloud/talk/chat/ChatActivity.kt index 486df17b42..6679695d31 100644 --- a/app/src/main/java/com/nextcloud/talk/chat/ChatActivity.kt +++ b/app/src/main/java/com/nextcloud/talk/chat/ChatActivity.kt @@ -1307,16 +1307,16 @@ class ChatActivity : runOnUiThread { binding.typingIndicator.text = typingString - if (participantNames.size > 0) { - binding.typingIndicatorWrapper.visibility = View.VISIBLE - binding.typingIndicatorWrapper.animate() - .translationYBy(DisplayUtils.convertDpToPixel(-18f, context)) - .setInterpolator(AccelerateDecelerateInterpolator()) - .duration = TYPING_INDICATOR_ANIMATION_DURATION + val typingIndicatorPositionY = if (participantNames.size > 0) { + TYPING_INDICATOR_POSITION_VISIBLE } else { - binding.typingIndicatorWrapper.visibility = View.INVISIBLE - binding.typingIndicatorWrapper.y += DisplayUtils.convertDpToPixel(18f, context) + TYPING_INDICATOR_POSITION_HIDDEN } + + binding.typingIndicatorWrapper.animate() + .translationY(DisplayUtils.convertDpToPixel(typingIndicatorPositionY, context)) + .setInterpolator(AccelerateDecelerateInterpolator()) + .duration = TYPING_INDICATOR_ANIMATION_DURATION } } @@ -3696,6 +3696,8 @@ class ChatActivity : private const val COMMA = ", " private const val TYPING_INDICATOR_ANIMATION_DURATION = 200L private const val TYPING_INDICATOR_MAX_NAME_LENGTH = 14 + private const val TYPING_INDICATOR_POSITION_VISIBLE = -18f + private const val TYPING_INDICATOR_POSITION_HIDDEN = -1f private const val TYPING_DURATION_TO_SEND_NEXT_TYPING_MESSAGE = 10000L private const val TYPING_INTERVAL_TO_SEND_NEXT_TYPING_MESSAGE = 1000L private const val TYPING_STARTED_SIGNALING_MESSAGE_TYPE = "startedTyping" From d380cbd676e7cf41ce2468630fecd8a6b05600f2 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Fri, 27 Sep 2024 17:09:54 +0000 Subject: [PATCH 121/885] Update mockito monorepo to v5.14.0 Signed-off-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- app/build.gradle | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/app/build.gradle b/app/build.gradle index 2bdb32925e..58328f7ecc 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -320,14 +320,14 @@ dependencies { debugImplementation("androidx.compose.ui:ui-test-manifest") testImplementation 'junit:junit:4.13.2' - testImplementation 'org.mockito:mockito-core:5.13.0' + testImplementation 'org.mockito:mockito-core:5.14.0' testImplementation 'androidx.arch.core:core-testing:2.2.0' androidTestImplementation "androidx.test:core:1.6.1" androidTestImplementation "org.jetbrains.kotlinx:kotlinx-coroutines-test:1.9.0" androidTestImplementation 'androidx.test:core-ktx:1.6.1' - androidTestImplementation 'org.mockito:mockito-android:5.13.0' + androidTestImplementation 'org.mockito:mockito-android:5.14.0' androidTestImplementation "androidx.work:work-testing:${workVersion}" // Espresso core androidTestImplementation ("androidx.test.espresso:espresso-core:$espressoVersion", { From 81704eb6558eefb8a1db35eb67f6eebfb8da0e83 Mon Sep 17 00:00:00 2001 From: Nextcloud bot Date: Sat, 28 Sep 2024 02:50:17 +0000 Subject: [PATCH 122/885] Fix(l10n): Update translations from Transifex Signed-off-by: Nextcloud bot --- app/src/main/res/values-ar/strings.xml | 4 ++++ app/src/main/res/values-ast/strings.xml | 3 +++ app/src/main/res/values-bg-rBG/strings.xml | 2 ++ app/src/main/res/values-ca/strings.xml | 3 +++ app/src/main/res/values-cs-rCZ/strings.xml | 3 +++ app/src/main/res/values-de/strings.xml | 3 +++ app/src/main/res/values-fr/strings.xml | 10 +++++----- app/src/main/res/values-gl/strings.xml | 1 + app/src/main/res/values-pt-rBR/strings.xml | 1 + app/src/main/res/values-sr/strings.xml | 1 + app/src/main/res/values-sv/strings.xml | 1 + app/src/main/res/values-zh-rTW/strings.xml | 1 + 12 files changed, 28 insertions(+), 5 deletions(-) diff --git a/app/src/main/res/values-ar/strings.xml b/app/src/main/res/values-ar/strings.xml index ef45c63f6f..746faae0e1 100644 --- a/app/src/main/res/values-ar/strings.xml +++ b/app/src/main/res/values-ar/strings.xml @@ -127,6 +127,7 @@ تحقق من الشهادة إعدادات SSL الخاص بك تمنع الاتصال تغيير شهادة المصادقة + تعديل الكلمة السرية رجاءً، تحقَّق من اتصالك بالإنترنت محو زر التحرير محو تحرير الرسالة @@ -335,6 +336,7 @@ المالك المشارِكون إضِف مشاركين + كلمة المرور تعيين الأذونات بعض الأذونات تمّ رفضها إسمَح بالأذونات رجاءً @@ -359,6 +361,7 @@ إزالتها مِن المفضلة حذف المجموعة group و الأعضاء حذف مشارك + حذف كلمة المرور إزالة الفريق و الأعضاء إعادة تسمية المحادثة تغيير تسمية @@ -408,6 +411,7 @@ الخادوم ليس فيه تطبيق Talk مدعوم عنوان الخادوم https://… %1$s يعمل فقط مع %2$s 13 وأكثر + عَيِّن كلمة مرور جديدة تعيين كلمة المرور الإعدادات تم تحديث حسابك الموجود بالفعل، بدلاً من إضافة حساب جديد diff --git a/app/src/main/res/values-ast/strings.xml b/app/src/main/res/values-ast/strings.xml index 6780489f71..6cc5be8058 100644 --- a/app/src/main/res/values-ast/strings.xml +++ b/app/src/main/res/values-ast/strings.xml @@ -76,6 +76,7 @@ %1$s na llamada P\'activar la comunicación per videu, concede\'l permisu «Cámara». Encaboxar + Camudar la contraseña Desaniciar tolos mensaxes Desaniciáronse tolos mensaxes ¿De xuru que quies desaniciar tolos mensaxes d\'esta conversación? @@ -187,6 +188,7 @@ Propietariu Participantes Amestar participantes + Contraseña Abrir la configuración Nun s\'atopó la cuenta Activar el micrófonu @@ -229,6 +231,7 @@ Nun se pue importar la cuenta seleicionada Fina la instalación de: %1$s Probando la conexón + Afitar una contraseña nueva Configuración Aspeutu Llamaes diff --git a/app/src/main/res/values-bg-rBG/strings.xml b/app/src/main/res/values-bg-rBG/strings.xml index a64d6ecf68..ead00f12c2 100644 --- a/app/src/main/res/values-bg-rBG/strings.xml +++ b/app/src/main/res/values-bg-rBG/strings.xml @@ -92,6 +92,7 @@ Провери сертификата Вашата настройка на SSL, предотврати връзката Променете сертификата за удостоверяване + Промяна на парола Изтриване на всички съобщения Всички съобщения бяха изтрити Сигурни ли сте, че искате да изтриете всички съобщения в този разговор? @@ -242,6 +243,7 @@ Създател Участници Добавяне на участници + Парола Отваряне на настройките Няма намерен профил Чат чрез %s diff --git a/app/src/main/res/values-ca/strings.xml b/app/src/main/res/values-ca/strings.xml index 4cb5ef29d8..b731db4def 100644 --- a/app/src/main/res/values-ca/strings.xml +++ b/app/src/main/res/values-ca/strings.xml @@ -91,6 +91,7 @@ Verifica el certificat La vostra configuració SSL ha impedit la connexió Canvia el certificat d’autenticació + Canvia la contrasenya Suprimeix tots els missatges S\'han suprimit tots els missatges Segur que voleu suprimir tots els missatges d\'aquesta conversa? @@ -244,6 +245,7 @@ Propietari Participants Afegeix participants + Contrasenya Obre la configuració No s\'ha trobat el compte Xateja mitjançant %s @@ -311,6 +313,7 @@ El servidor no té instal·lada l\'aplicació Talk Adreça del servidor https://… %1$s només funciona amb %2$s 13 i endavant + Estableix una contrasenya nova Paràmetres S\'ha actualitzat el vostre compte ja existent enlloc d’afegir-ne un de nou Avançat diff --git a/app/src/main/res/values-cs-rCZ/strings.xml b/app/src/main/res/values-cs-rCZ/strings.xml index 620e729cdb..9b411fb0d4 100644 --- a/app/src/main/res/values-cs-rCZ/strings.xml +++ b/app/src/main/res/values-cs-rCZ/strings.xml @@ -110,6 +110,7 @@ Zkontrolovat certifikát Vaše nastavení SSL zabránilo připojení Změnit certifikát sloužící pro ověřování se + Změnit heslo Smazat všechny zprávy Všechny zprávy byly vymazány Opravdu chcete všechny zprávy v této konverzaci smazat? @@ -297,6 +298,7 @@ Vlastník Účastníci Přidat účastníky + Heslo Nastavit oprávnění Některá oprávnění byla odepřena. Udělte oprávnění @@ -369,6 +371,7 @@ Na serveru není nainstalovaná podporovaná verze aplikace Talk Adresa serveru https://… %1$s funguje pouze s %2$s 13 a novějším + Nastavit nové heslo Nastavit heslo Nastavení Namísto přidání nového byl zaktualizován váš stávající účet diff --git a/app/src/main/res/values-de/strings.xml b/app/src/main/res/values-de/strings.xml index a6a4d3cc7d..06913e15ae 100644 --- a/app/src/main/res/values-de/strings.xml +++ b/app/src/main/res/values-de/strings.xml @@ -127,6 +127,7 @@ Überprüfen Sie das Zertifikat Ihre SSL-Konfiguration hat die Verbindung verhindert Authentifizierungs-Zertifikat ändern + Passwort ändern Bitte die Internetverbindung prüfen Bearbeitung des Nachrichtentextes abbrechen Bearbeitungsnachricht löschen @@ -335,6 +336,7 @@ Besitzer Teilnehmer Teilnehmer hinzufügen + Passwort Berechtigungen festlegen Einige Berechtigungen wurden abgelehnt. Bitte alle Berechtigungen erteilen. @@ -359,6 +361,7 @@ Von Favoriten entfernen Gruppe und Mitglieder entfernen Teilnehmer entfernen + Passwort entfernen Team und Mitglieder entfernen Unterhaltung umbenennen Umbenennen diff --git a/app/src/main/res/values-fr/strings.xml b/app/src/main/res/values-fr/strings.xml index d3c191f9e5..e5e8421fb4 100644 --- a/app/src/main/res/values-fr/strings.xml +++ b/app/src/main/res/values-fr/strings.xml @@ -151,7 +151,7 @@ Appel vocal Discussion non trouvée Paramètres de la conversation - Rejoignez une conversation ou démarrez-en une nouvelle + Rejoignez une conversation ou lancez-en une nouvelle Dites bonjour à vos amis et collègues ! Copier Créer une nouvelle conversation @@ -522,9 +522,9 @@ De l\'aide supplémentaire peut être trouvée sur DontKillMyApp.com ou dans la Tout le partage de fichier n\'est pas possible sans les permissions L\'appel est enregistré - Annuler le démarrage de l\'enregistrement + Annuler le lancement de l\'enregistrement L\'enregistrement a échoué. Veuillez contacter votre administrateur. - Commencer l\'enregistrement + Lancer l\'enregistrement Voulez-vous vraiment arrêter l\'enregistrement ? Arrêter l\'enregistrement de l\'appel Arrêter l\'enregistrement @@ -574,8 +574,8 @@ De l\'aide supplémentaire peut être trouvée sur DontKillMyApp.com ou dans la Voix Montrer la raison du bannissement Favori - Vous n\'êtes pas autorisé à commencer un appel - a démarré un appel + Vous n\'êtes pas autorisé à lancer un appel + a lancé un appel Message d\'état Basculer vers la salle de sous-groupe Basculer vers la salle principale diff --git a/app/src/main/res/values-gl/strings.xml b/app/src/main/res/values-gl/strings.xml index 52e6037cc4..4ad114c5eb 100644 --- a/app/src/main/res/values-gl/strings.xml +++ b/app/src/main/res/values-gl/strings.xml @@ -361,6 +361,7 @@ Retirar de favoritos Retirar grupo e membros Retirar participante + Retirar o contrasinal Retirar equipo e membros Cambiar o nome da conversa Cambiar o nome diff --git a/app/src/main/res/values-pt-rBR/strings.xml b/app/src/main/res/values-pt-rBR/strings.xml index 4b0afc34fb..3a5dcf315f 100644 --- a/app/src/main/res/values-pt-rBR/strings.xml +++ b/app/src/main/res/values-pt-rBR/strings.xml @@ -361,6 +361,7 @@ Remover dos favoritos Remover grupo e membros Excluir participante + Excluir Senha Remover equipe e membros Renomear conversa Renomear diff --git a/app/src/main/res/values-sr/strings.xml b/app/src/main/res/values-sr/strings.xml index 1298a08313..b58d96c400 100644 --- a/app/src/main/res/values-sr/strings.xml +++ b/app/src/main/res/values-sr/strings.xml @@ -361,6 +361,7 @@ Уклони из омиљених Уклони групу и чланове Уклони учесника + Уклони лозинку Уклони тим и чланове Преименуј разговор Преименуј diff --git a/app/src/main/res/values-sv/strings.xml b/app/src/main/res/values-sv/strings.xml index 12334612b5..0518c9f1c4 100644 --- a/app/src/main/res/values-sv/strings.xml +++ b/app/src/main/res/values-sv/strings.xml @@ -358,6 +358,7 @@ Ta bort från favoriter Ta bort grupp och medlemmar Ta bort deltagare + Ta bort lösenordet Ta bort team och medlemmar Byt namn på konversation Döp om diff --git a/app/src/main/res/values-zh-rTW/strings.xml b/app/src/main/res/values-zh-rTW/strings.xml index 2ad484f918..2d61c6a3ea 100644 --- a/app/src/main/res/values-zh-rTW/strings.xml +++ b/app/src/main/res/values-zh-rTW/strings.xml @@ -361,6 +361,7 @@ 取消我的最愛 移除群組與成員 移除參與者 + 移除密碼 移除團隊與成員 重新命名對話 重新命名 From ddd131f22558362842a7d8da28c06c020dc141ec Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Sun, 29 Sep 2024 01:40:37 +0000 Subject: [PATCH 123/885] Update dependency com.mebigfatguy.fb-contrib:fb-contrib to v7.6.5 Signed-off-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- app/build.gradle | 4 ++-- gradle/verification-metadata.xml | 9 +++++++++ 2 files changed, 11 insertions(+), 2 deletions(-) diff --git a/app/build.gradle b/app/build.gradle index 58328f7ecc..7c661acf17 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -178,7 +178,7 @@ configurations.configureEach { dependencies { spotbugsPlugins 'com.h3xstream.findsecbugs:findsecbugs-plugin:1.13.0' - spotbugsPlugins 'com.mebigfatguy.fb-contrib:fb-contrib:7.6.4' + spotbugsPlugins 'com.mebigfatguy.fb-contrib:fb-contrib:7.6.5' implementation("androidx.compose.runtime:runtime:1.7.2") implementation 'androidx.preference:preference-ktx:1.2.1' @@ -342,7 +342,7 @@ dependencies { androidTestImplementation('com.android.support.test.espresso:espresso-intents:3.0.2') spotbugsPlugins 'com.h3xstream.findsecbugs:findsecbugs-plugin:1.13.0' - spotbugsPlugins 'com.mebigfatguy.fb-contrib:fb-contrib:7.6.4' + spotbugsPlugins 'com.mebigfatguy.fb-contrib:fb-contrib:7.6.5' implementation 'androidx.activity:activity-ktx:1.9.2' diff --git a/gradle/verification-metadata.xml b/gradle/verification-metadata.xml index 325911d915..970b168217 100644 --- a/gradle/verification-metadata.xml +++ b/gradle/verification-metadata.xml @@ -17,6 +17,7 @@ + @@ -5398,6 +5399,14 @@ + + + + + + + + From 5a4047432a55fdb8c646fc5b97dcaa0fb2e5aaaf Mon Sep 17 00:00:00 2001 From: Nextcloud bot Date: Sun, 29 Sep 2024 03:11:01 +0000 Subject: [PATCH 124/885] Fix(l10n): Update translations from Transifex Signed-off-by: Nextcloud bot --- app/src/main/res/values-ga/strings.xml | 1 + app/src/main/res/values-ru/strings.xml | 1 + 2 files changed, 2 insertions(+) diff --git a/app/src/main/res/values-ga/strings.xml b/app/src/main/res/values-ga/strings.xml index abe37c521b..603f466edd 100644 --- a/app/src/main/res/values-ga/strings.xml +++ b/app/src/main/res/values-ga/strings.xml @@ -361,6 +361,7 @@ Bain ó cheanáin Bain grúpa agus baill Bain rannpháirtí + Bain Pasfhocal Bain foireann agus baill Fuaim iargúlta múchta Athainmnigh diff --git a/app/src/main/res/values-ru/strings.xml b/app/src/main/res/values-ru/strings.xml index c158876423..b119056969 100644 --- a/app/src/main/res/values-ru/strings.xml +++ b/app/src/main/res/values-ru/strings.xml @@ -574,6 +574,7 @@ печатают... печатает... и ещё %1$s собеседника печатают... + Разбанить Непрочитанное Загрузить новый аватар с устройства Изображение профиля From c5700cdf6a7f8265686ed1e55e0b29b0238935ec Mon Sep 17 00:00:00 2001 From: Nextcloud Android Bot Date: Mon, 30 Sep 2024 03:14:11 +0000 Subject: [PATCH 125/885] Weekly 20.1.0 Alpha 06 --- app/build.gradle | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/app/build.gradle b/app/build.gradle index 7c661acf17..bf83c97c2f 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -40,8 +40,8 @@ android { // mayor.minor.hotfix.increment (for increment: 01-50=Alpha / 51-89=RC / 90-99=stable) // xx .xxx .xx .xx - versionCode 200010005 - versionName "20.1.0 Alpha 05" + versionCode 200010006 + versionName "20.1.0 Alpha 06" flavorDimensions "default" renderscriptTargetApi 19 From 3a8f474357b96f60b868eeb2efb7ae4a623349d2 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Mon, 30 Sep 2024 13:18:55 +0000 Subject: [PATCH 126/885] Update github/codeql-action action to v3.26.10 Signed-off-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- .github/workflows/codeql.yml | 4 ++-- .github/workflows/scorecard.yml | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/codeql.yml b/.github/workflows/codeql.yml index 1c0ba92a96..56d9eebcf8 100644 --- a/.github/workflows/codeql.yml +++ b/.github/workflows/codeql.yml @@ -39,7 +39,7 @@ jobs: with: swap-size-gb: 10 - name: Initialize CodeQL - uses: github/codeql-action/init@461ef6c76dfe95d5c364de2f431ddbd31a417628 # v3.26.9 + uses: github/codeql-action/init@e2b3eafc8d227b0241d48be5f425d47c2d750a13 # v3.26.10 with: languages: ${{ matrix.language }} - name: Set up JDK 17 @@ -53,4 +53,4 @@ jobs: echo "org.gradle.jvmargs=-Xmx4g -XX:MaxMetaspaceSize=512m -XX:+HeapDumpOnOutOfMemoryError" > "$HOME/.gradle/gradle.properties" ./gradlew assembleDebug - name: Perform CodeQL Analysis - uses: github/codeql-action/analyze@461ef6c76dfe95d5c364de2f431ddbd31a417628 # v3.26.9 + uses: github/codeql-action/analyze@e2b3eafc8d227b0241d48be5f425d47c2d750a13 # v3.26.10 diff --git a/.github/workflows/scorecard.yml b/.github/workflows/scorecard.yml index fc5f9cea06..27d6162d48 100644 --- a/.github/workflows/scorecard.yml +++ b/.github/workflows/scorecard.yml @@ -42,6 +42,6 @@ jobs: # Upload the results to GitHub's code scanning dashboard. - name: "Upload to code-scanning" - uses: github/codeql-action/upload-sarif@461ef6c76dfe95d5c364de2f431ddbd31a417628 # v3.26.9 + uses: github/codeql-action/upload-sarif@e2b3eafc8d227b0241d48be5f425d47c2d750a13 # v3.26.10 with: sarif_file: results.sarif From e8e89c80b73068687b4f170648129fe045b40c93 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Mon, 30 Sep 2024 13:23:20 +0000 Subject: [PATCH 127/885] Update mockito monorepo to v5.14.1 Signed-off-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- app/build.gradle | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/app/build.gradle b/app/build.gradle index bf83c97c2f..c13e35febc 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -320,14 +320,14 @@ dependencies { debugImplementation("androidx.compose.ui:ui-test-manifest") testImplementation 'junit:junit:4.13.2' - testImplementation 'org.mockito:mockito-core:5.14.0' + testImplementation 'org.mockito:mockito-core:5.14.1' testImplementation 'androidx.arch.core:core-testing:2.2.0' androidTestImplementation "androidx.test:core:1.6.1" androidTestImplementation "org.jetbrains.kotlinx:kotlinx-coroutines-test:1.9.0" androidTestImplementation 'androidx.test:core-ktx:1.6.1' - androidTestImplementation 'org.mockito:mockito-android:5.14.0' + androidTestImplementation 'org.mockito:mockito-android:5.14.1' androidTestImplementation "androidx.work:work-testing:${workVersion}" // Espresso core androidTestImplementation ("androidx.test.espresso:espresso-core:$espressoVersion", { From d76a1d0bd946b0633ddaa0253c4c0f1a8cacb8ed Mon Sep 17 00:00:00 2001 From: sowjanyakch Date: Sun, 29 Sep 2024 21:13:48 +0200 Subject: [PATCH 128/885] make predefined status use custom time Signed-off-by: sowjanyakch --- .../com/nextcloud/talk/ui/dialog/SetStatusDialogFragment.kt | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) 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 96e6d8692c..3392dfda91 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 @@ -479,13 +479,11 @@ class SetStatusDialogFragment : } }) } else { - val clearAt = clearAtToUnixTime(selectedPredefinedStatus!!.clearAt) - ncApi.setPredefinedStatusMessage( credentials, ApiUtils.getUrlForSetPredefinedStatus(currentUser?.baseUrl!!), selectedPredefinedStatus!!.id, - if (clearAt == -1L) null else clearAt + clearAt ) .subscribeOn(Schedulers.io()) .observeOn(AndroidSchedulers.mainThread())?.subscribe(object : Observer { From d572ba110fdeea10f322a255a7dd0aaf4cc30272 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Tue, 1 Oct 2024 18:22:46 +0000 Subject: [PATCH 129/885] Update dependency com.android.tools.build:gradle to v8.7.0 Signed-off-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- build.gradle | 2 +- gradle/verification-metadata.xml | 9 +++++++++ 2 files changed, 10 insertions(+), 1 deletion(-) diff --git a/build.gradle b/build.gradle index 82c6dfff15..5281329d2a 100644 --- a/build.gradle +++ b/build.gradle @@ -22,7 +22,7 @@ buildscript { } dependencies { - classpath 'com.android.tools.build:gradle:8.6.1' + classpath 'com.android.tools.build:gradle:8.7.0' classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:${kotlinVersion}" classpath "org.jetbrains.kotlin:kotlin-serialization:${kotlinVersion}" classpath 'com.github.spotbugs.snom:spotbugs-gradle-plugin:6.0.23' diff --git a/gradle/verification-metadata.xml b/gradle/verification-metadata.xml index 970b168217..e9784b7193 100644 --- a/gradle/verification-metadata.xml +++ b/gradle/verification-metadata.xml @@ -144,6 +144,7 @@ + @@ -3059,6 +3060,14 @@ + + + + + + + + From d960eaf62eead9a993e36d6849dc024133148f92 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Tue, 1 Oct 2024 22:10:11 +0000 Subject: [PATCH 130/885] Update dependency com.github.spotbugs.snom:spotbugs-gradle-plugin to v6.0.24 Signed-off-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build.gradle b/build.gradle index 5281329d2a..070195cb9c 100644 --- a/build.gradle +++ b/build.gradle @@ -25,7 +25,7 @@ buildscript { classpath 'com.android.tools.build:gradle:8.7.0' classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:${kotlinVersion}" classpath "org.jetbrains.kotlin:kotlin-serialization:${kotlinVersion}" - classpath 'com.github.spotbugs.snom:spotbugs-gradle-plugin:6.0.23' + classpath 'com.github.spotbugs.snom:spotbugs-gradle-plugin:6.0.24' classpath "io.gitlab.arturbosch.detekt:detekt-gradle-plugin:1.23.7" classpath "org.jlleitschuh.gradle:ktlint-gradle:12.1.1" classpath "com.google.dagger:hilt-android-gradle-plugin:$hilt_version" From 2a5b72e72174736f39f903ba33e9e83d8824b5ab Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Tue, 1 Oct 2024 22:11:22 +0000 Subject: [PATCH 131/885] Update dependency com.google.firebase:firebase-messaging to v24.0.2 Signed-off-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- app/build.gradle | 2 +- gradle/verification-metadata.xml | 8 ++++++++ 2 files changed, 9 insertions(+), 1 deletion(-) diff --git a/app/build.gradle b/app/build.gradle index c13e35febc..341bf2097a 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -304,7 +304,7 @@ dependencies { implementation 'com.github.nextcloud-deps:android-talk-webrtc:121.6167.0' gplayImplementation 'com.google.android.gms:play-services-base:18.5.0' - gplayImplementation "com.google.firebase:firebase-messaging:24.0.1" + gplayImplementation "com.google.firebase:firebase-messaging:24.0.2" //compose implementation(platform("androidx.compose:compose-bom:2024.09.02")) diff --git a/gradle/verification-metadata.xml b/gradle/verification-metadata.xml index e9784b7193..1ccdf9ab33 100644 --- a/gradle/verification-metadata.xml +++ b/gradle/verification-metadata.xml @@ -5195,6 +5195,14 @@ + + + + + + + + From c2d747dd0002513edd0404f9a712fc667d3b8bc2 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Wed, 2 Oct 2024 04:37:39 +0000 Subject: [PATCH 132/885] Update ubuntu:noble Docker digest to b359f10 Signed-off-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- .devcontainer/Dockerfile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.devcontainer/Dockerfile b/.devcontainer/Dockerfile index 1e2cb0cefd..e5a364107f 100644 --- a/.devcontainer/Dockerfile +++ b/.devcontainer/Dockerfile @@ -1,4 +1,4 @@ -FROM ubuntu:noble@sha256:dfc10878be8d8fc9c61cbff33166cb1d1fe44391539243703c72766894fa834a +FROM ubuntu:noble@sha256:b359f1067efa76f37863778f7b6d0e8d911e3ee8efa807ad01fbf5dc1ef9006b ARG DEBIAN_FRONTEND=noninteractive ENV ANDROID_HOME=/usr/lib/android-sdk From 305f1732ba890939f5a1d2b097dea6d5726e8873 Mon Sep 17 00:00:00 2001 From: Marcel Hibbe Date: Wed, 2 Oct 2024 14:01:35 +0200 Subject: [PATCH 133/885] fix availability of search feature. Hide search feature if room is federated. Also, for conversation list the check for federation inside isUnifiedSearchAvailable makes no sense. Signed-off-by: Marcel Hibbe --- app/src/main/java/com/nextcloud/talk/chat/ChatActivity.kt | 4 +++- .../main/java/com/nextcloud/talk/utils/CapabilitiesUtil.kt | 3 --- 2 files changed, 3 insertions(+), 4 deletions(-) diff --git a/app/src/main/java/com/nextcloud/talk/chat/ChatActivity.kt b/app/src/main/java/com/nextcloud/talk/chat/ChatActivity.kt index 6679695d31..8882d6d22d 100644 --- a/app/src/main/java/com/nextcloud/talk/chat/ChatActivity.kt +++ b/app/src/main/java/com/nextcloud/talk/chat/ChatActivity.kt @@ -2825,7 +2825,9 @@ class ChatActivity : } val searchItem = menu.findItem(R.id.conversation_search) - searchItem.isVisible = CapabilitiesUtil.isUnifiedSearchAvailable(spreedCapabilities) + + searchItem.isVisible = CapabilitiesUtil.isUnifiedSearchAvailable(spreedCapabilities) && + currentConversation!!.remoteServer.isNullOrEmpty() if (currentConversation!!.remoteServer != null || !CapabilitiesUtil.isSharedItemsAvailable(spreedCapabilities) diff --git a/app/src/main/java/com/nextcloud/talk/utils/CapabilitiesUtil.kt b/app/src/main/java/com/nextcloud/talk/utils/CapabilitiesUtil.kt index 7329b085a1..0a02bd9149 100644 --- a/app/src/main/java/com/nextcloud/talk/utils/CapabilitiesUtil.kt +++ b/app/src/main/java/com/nextcloud/talk/utils/CapabilitiesUtil.kt @@ -161,9 +161,6 @@ object CapabilitiesUtil { } fun isUnifiedSearchAvailable(spreedCapabilities: SpreedCapability): Boolean { - if (!hasSpreedFeatureCapability(spreedCapabilities, SpreedFeatures.FEDERATION_V1)) { - return false - } return hasSpreedFeatureCapability(spreedCapabilities, SpreedFeatures.UNIFIED_SEARCH) } From ce8143a8077a75781bf77db44c5b95fcecb80b6b Mon Sep 17 00:00:00 2001 From: Marcel Hibbe Date: Wed, 2 Oct 2024 14:03:11 +0200 Subject: [PATCH 134/885] center search results in chat Signed-off-by: Marcel Hibbe --- app/src/main/java/com/nextcloud/talk/chat/ChatActivity.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/src/main/java/com/nextcloud/talk/chat/ChatActivity.kt b/app/src/main/java/com/nextcloud/talk/chat/ChatActivity.kt index 8882d6d22d..14caa42fc3 100644 --- a/app/src/main/java/com/nextcloud/talk/chat/ChatActivity.kt +++ b/app/src/main/java/com/nextcloud/talk/chat/ChatActivity.kt @@ -2070,7 +2070,7 @@ class ChatActivity : private fun onMessageSearchResult(intent: Intent?) { val messageId = intent?.getStringExtra(MessageSearchActivity.RESULT_KEY_MESSAGE_ID) messageId?.let { id -> - scrollToMessageWithId(id) + scrollToAndCenterMessageWithId(id) } } From b1d72c1a8349a714cabff2e5b16668515c2a4a93 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Wed, 2 Oct 2024 19:38:35 +0000 Subject: [PATCH 135/885] Update dependency androidx.compose.runtime:runtime to v1.7.3 Signed-off-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- app/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/build.gradle b/app/build.gradle index 341bf2097a..271a7d1180 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -180,7 +180,7 @@ dependencies { spotbugsPlugins 'com.h3xstream.findsecbugs:findsecbugs-plugin:1.13.0' spotbugsPlugins 'com.mebigfatguy.fb-contrib:fb-contrib:7.6.5' - implementation("androidx.compose.runtime:runtime:1.7.2") + implementation("androidx.compose.runtime:runtime:1.7.3") implementation 'androidx.preference:preference-ktx:1.2.1' implementation 'androidx.datastore:datastore-core:1.1.1' implementation 'androidx.datastore:datastore-preferences:1.1.1' From 0cf1467ca6894e604bbef0cde43dc2d25ff5ab7f Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Wed, 2 Oct 2024 19:39:39 +0000 Subject: [PATCH 136/885] Update dependency androidx.compose.ui:ui-test-junit4 to v1.7.3 Signed-off-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- app/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/build.gradle b/app/build.gradle index 341bf2097a..c9b12f2685 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -316,7 +316,7 @@ dependencies { debugImplementation("androidx.compose.ui:ui-tooling") //tests - androidTestImplementation("androidx.compose.ui:ui-test-junit4:1.7.2") + androidTestImplementation("androidx.compose.ui:ui-test-junit4:1.7.3") debugImplementation("androidx.compose.ui:ui-test-manifest") testImplementation 'junit:junit:4.13.2' From 51dc692402373328f79075cb26a8051d6572b53b Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Wed, 2 Oct 2024 22:37:14 +0000 Subject: [PATCH 137/885] Update dependency androidx.compose:compose-bom to v2024.09.03 Signed-off-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- app/build.gradle | 4 ++-- gradle/verification-metadata.xml | 5 +++++ 2 files changed, 7 insertions(+), 2 deletions(-) diff --git a/app/build.gradle b/app/build.gradle index d8eb251952..a90c9df6c3 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -307,7 +307,7 @@ dependencies { gplayImplementation "com.google.firebase:firebase-messaging:24.0.2" //compose - implementation(platform("androidx.compose:compose-bom:2024.09.02")) + implementation(platform("androidx.compose:compose-bom:2024.09.03")) implementation("androidx.compose.ui:ui") implementation 'androidx.compose.material3:material3:1.3.0' implementation("androidx.compose.ui:ui-tooling-preview") @@ -355,7 +355,7 @@ dependencies { kapt "com.google.dagger:hilt-android-compiler:$hilt_version" implementation("androidx.lifecycle:lifecycle-viewmodel-compose:2.8.6") - androidTestImplementation(platform("androidx.compose:compose-bom:2024.09.02")) + androidTestImplementation(platform("androidx.compose:compose-bom:2024.09.03")) androidTestImplementation("androidx.compose.ui:ui-test-junit4") testImplementation "org.mockito.kotlin:mockito-kotlin:$mockitoKotlinVersion" testImplementation "org.jetbrains.kotlinx:kotlinx-coroutines-test:$coroutines_version" diff --git a/gradle/verification-metadata.xml b/gradle/verification-metadata.xml index 1ccdf9ab33..01bacec009 100644 --- a/gradle/verification-metadata.xml +++ b/gradle/verification-metadata.xml @@ -627,6 +627,11 @@ + + + + + From 7ddf048061fd67f2996771f651e73be8e3e52399 Mon Sep 17 00:00:00 2001 From: Nextcloud bot Date: Thu, 3 Oct 2024 02:51:05 +0000 Subject: [PATCH 138/885] Fix(l10n): Update translations from Transifex Signed-off-by: Nextcloud bot --- app/src/main/res/values-b+en+001/strings.xml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/app/src/main/res/values-b+en+001/strings.xml b/app/src/main/res/values-b+en+001/strings.xml index a85f1b1808..65576c610a 100644 --- a/app/src/main/res/values-b+en+001/strings.xml +++ b/app/src/main/res/values-b+en+001/strings.xml @@ -127,6 +127,7 @@ Check out the certificate Your SSL setup prevented connection Change authentication certificate + Change Password Please check your internet connection Clear Edit Button Clear Edit Message @@ -335,6 +336,7 @@ Owner Participants Add participants + Password Set permissions Some permissions were denied. Please allow permissions @@ -359,6 +361,7 @@ Remove from favourites Remove group and members Remove participant + Remove Password Remove team and members Rename conversation Rename From 7dfdeff1dee8241289895dcf73cb89e1283f1322 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Thu, 3 Oct 2024 21:57:48 +0000 Subject: [PATCH 139/885] Update github/codeql-action action to v3.26.11 Signed-off-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- .github/workflows/codeql.yml | 4 ++-- .github/workflows/scorecard.yml | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/codeql.yml b/.github/workflows/codeql.yml index 56d9eebcf8..2b65890051 100644 --- a/.github/workflows/codeql.yml +++ b/.github/workflows/codeql.yml @@ -39,7 +39,7 @@ jobs: with: swap-size-gb: 10 - name: Initialize CodeQL - uses: github/codeql-action/init@e2b3eafc8d227b0241d48be5f425d47c2d750a13 # v3.26.10 + uses: github/codeql-action/init@6db8d6351fd0be61f9ed8ebd12ccd35dcec51fea # v3.26.11 with: languages: ${{ matrix.language }} - name: Set up JDK 17 @@ -53,4 +53,4 @@ jobs: echo "org.gradle.jvmargs=-Xmx4g -XX:MaxMetaspaceSize=512m -XX:+HeapDumpOnOutOfMemoryError" > "$HOME/.gradle/gradle.properties" ./gradlew assembleDebug - name: Perform CodeQL Analysis - uses: github/codeql-action/analyze@e2b3eafc8d227b0241d48be5f425d47c2d750a13 # v3.26.10 + uses: github/codeql-action/analyze@6db8d6351fd0be61f9ed8ebd12ccd35dcec51fea # v3.26.11 diff --git a/.github/workflows/scorecard.yml b/.github/workflows/scorecard.yml index 27d6162d48..74ca98d585 100644 --- a/.github/workflows/scorecard.yml +++ b/.github/workflows/scorecard.yml @@ -42,6 +42,6 @@ jobs: # Upload the results to GitHub's code scanning dashboard. - name: "Upload to code-scanning" - uses: github/codeql-action/upload-sarif@e2b3eafc8d227b0241d48be5f425d47c2d750a13 # v3.26.10 + uses: github/codeql-action/upload-sarif@6db8d6351fd0be61f9ed8ebd12ccd35dcec51fea # v3.26.11 with: sarif_file: results.sarif From 778230d0397c62d484cf2c0497da1925bce7dc88 Mon Sep 17 00:00:00 2001 From: Nextcloud bot Date: Fri, 4 Oct 2024 02:52:39 +0000 Subject: [PATCH 140/885] Fix(l10n): Update translations from Transifex Signed-off-by: Nextcloud bot --- app/src/main/res/values-ar/strings.xml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/app/src/main/res/values-ar/strings.xml b/app/src/main/res/values-ar/strings.xml index 746faae0e1..f894fe7aa4 100644 --- a/app/src/main/res/values-ar/strings.xml +++ b/app/src/main/res/values-ar/strings.xml @@ -527,7 +527,7 @@ إحذِف الخيار %1$s الخيار %1$s الخيارات - إستبيان خاصٌّ + إستبيان خاص سؤال سؤالك النتائج @@ -560,7 +560,7 @@ يراه فقط المستخدِمون على هذا الخادوم و الضيوف محلي يراه فقط المستخدِمون الذين أمكن مطابقة أرقام هواتفهم عبر تطبيق المحادثة Talk على الهاتف النقّال - خاصُّ + خاص قم بالمزامنة مع الخوادم الموثوقة ودفتر العناوين العالمية والعامة منشورة تبديل النطاق Scope toggle From 89948c638c7d2ea77737b20bbb99c68294a27cee Mon Sep 17 00:00:00 2001 From: Marcel Hibbe Date: Fri, 4 Oct 2024 11:35:45 +0200 Subject: [PATCH 141/885] move phoneScreenshots to images folder Signed-off-by: Marcel Hibbe --- README.md | 2 +- .../phoneScreenshots/conversationList_dark.png | Bin .../phoneScreenshots/conversationList_light.png | Bin .../phoneScreenshots/markdown_light.png | Bin .../phoneScreenshots/searchParticipant_light.png | Bin .../phoneScreenshots/serverSelection.png | Bin .../phoneScreenshots/settings_light.png | Bin .../{ => images}/phoneScreenshots/voiceCall.png | Bin .../phoneScreenshots/voiceRecord_light.png | Bin 9 files changed, 1 insertion(+), 1 deletion(-) rename fastlane/metadata/android/en-US/{ => images}/phoneScreenshots/conversationList_dark.png (100%) rename fastlane/metadata/android/en-US/{ => images}/phoneScreenshots/conversationList_light.png (100%) rename fastlane/metadata/android/en-US/{ => images}/phoneScreenshots/markdown_light.png (100%) rename fastlane/metadata/android/en-US/{ => images}/phoneScreenshots/searchParticipant_light.png (100%) rename fastlane/metadata/android/en-US/{ => images}/phoneScreenshots/serverSelection.png (100%) rename fastlane/metadata/android/en-US/{ => images}/phoneScreenshots/settings_light.png (100%) rename fastlane/metadata/android/en-US/{ => images}/phoneScreenshots/voiceCall.png (100%) rename fastlane/metadata/android/en-US/{ => images}/phoneScreenshots/voiceRecord_light.png (100%) diff --git a/README.md b/README.md index 4ea25808be..8bd80b0c79 100644 --- a/README.md +++ b/README.md @@ -17,7 +17,7 @@ Please note that Notifications won't work with the F-Droid version due to missin ||||||| |---|---|---|---|---|---| -|![Conversation list](/fastlane/metadata/android/en-US/phoneScreenshots/conversationList_light.png "Conversation list")|![Participant search](/fastlane/metadata/android/en-US/phoneScreenshots/searchParticipant_light.png "Participant search")|![Voice call](/fastlane/metadata/android/en-US/phoneScreenshots/voiceCall.png "Voice call")|![Voice recording](/fastlane/metadata/android/en-US/phoneScreenshots/voiceRecord_light.png "Voice recording")|![Markdown view](/fastlane/metadata/android/en-US/phoneScreenshots/markdown_light.png "Markdown view")|![Settings](/fastlane/metadata/android/en-US/phoneScreenshots/settings_light.png "Settings")| +|![Conversation list](/fastlane/metadata/android/en-US/images/phoneScreenshots/conversationList_light.png "Conversation list")|![Participant search](/fastlane/metadata/android/en-US/images/phoneScreenshots/searchParticipant_light.png "Participant search")|![Voice call](/fastlane/metadata/android/en-US/images/phoneScreenshots/voiceCall.png "Voice call")|![Voice recording](/fastlane/metadata/android/en-US/images/phoneScreenshots/voiceRecord_light.png "Voice recording")|![Markdown view](/fastlane/metadata/android/en-US/images/phoneScreenshots/markdown_light.png "Markdown view")|![Settings](/fastlane/metadata/android/en-US/images/phoneScreenshots/settings_light.png "Settings")| **Video & audio calls through Nextcloud on Android** diff --git a/fastlane/metadata/android/en-US/phoneScreenshots/conversationList_dark.png b/fastlane/metadata/android/en-US/images/phoneScreenshots/conversationList_dark.png similarity index 100% rename from fastlane/metadata/android/en-US/phoneScreenshots/conversationList_dark.png rename to fastlane/metadata/android/en-US/images/phoneScreenshots/conversationList_dark.png diff --git a/fastlane/metadata/android/en-US/phoneScreenshots/conversationList_light.png b/fastlane/metadata/android/en-US/images/phoneScreenshots/conversationList_light.png similarity index 100% rename from fastlane/metadata/android/en-US/phoneScreenshots/conversationList_light.png rename to fastlane/metadata/android/en-US/images/phoneScreenshots/conversationList_light.png diff --git a/fastlane/metadata/android/en-US/phoneScreenshots/markdown_light.png b/fastlane/metadata/android/en-US/images/phoneScreenshots/markdown_light.png similarity index 100% rename from fastlane/metadata/android/en-US/phoneScreenshots/markdown_light.png rename to fastlane/metadata/android/en-US/images/phoneScreenshots/markdown_light.png diff --git a/fastlane/metadata/android/en-US/phoneScreenshots/searchParticipant_light.png b/fastlane/metadata/android/en-US/images/phoneScreenshots/searchParticipant_light.png similarity index 100% rename from fastlane/metadata/android/en-US/phoneScreenshots/searchParticipant_light.png rename to fastlane/metadata/android/en-US/images/phoneScreenshots/searchParticipant_light.png diff --git a/fastlane/metadata/android/en-US/phoneScreenshots/serverSelection.png b/fastlane/metadata/android/en-US/images/phoneScreenshots/serverSelection.png similarity index 100% rename from fastlane/metadata/android/en-US/phoneScreenshots/serverSelection.png rename to fastlane/metadata/android/en-US/images/phoneScreenshots/serverSelection.png diff --git a/fastlane/metadata/android/en-US/phoneScreenshots/settings_light.png b/fastlane/metadata/android/en-US/images/phoneScreenshots/settings_light.png similarity index 100% rename from fastlane/metadata/android/en-US/phoneScreenshots/settings_light.png rename to fastlane/metadata/android/en-US/images/phoneScreenshots/settings_light.png diff --git a/fastlane/metadata/android/en-US/phoneScreenshots/voiceCall.png b/fastlane/metadata/android/en-US/images/phoneScreenshots/voiceCall.png similarity index 100% rename from fastlane/metadata/android/en-US/phoneScreenshots/voiceCall.png rename to fastlane/metadata/android/en-US/images/phoneScreenshots/voiceCall.png diff --git a/fastlane/metadata/android/en-US/phoneScreenshots/voiceRecord_light.png b/fastlane/metadata/android/en-US/images/phoneScreenshots/voiceRecord_light.png similarity index 100% rename from fastlane/metadata/android/en-US/phoneScreenshots/voiceRecord_light.png rename to fastlane/metadata/android/en-US/images/phoneScreenshots/voiceRecord_light.png From 5cd68dde88ba56bc4c3e9ac508f82254e91cfc84 Mon Sep 17 00:00:00 2001 From: Marcel Hibbe Date: Fri, 4 Oct 2024 11:46:06 +0200 Subject: [PATCH 142/885] add app icon to images folder Signed-off-by: Marcel Hibbe --- .../metadata/android/en-US/images/icon.png | Bin 0 -> 129190 bytes 1 file changed, 0 insertions(+), 0 deletions(-) create mode 100644 fastlane/metadata/android/en-US/images/icon.png diff --git a/fastlane/metadata/android/en-US/images/icon.png b/fastlane/metadata/android/en-US/images/icon.png new file mode 100644 index 0000000000000000000000000000000000000000..b377442e3c5b0e9f5faccf89ed05de1f7a47f1f0 GIT binary patch literal 129190 zcmagFWk4KFvj(~g1b250!QI`0ySux)y95YMu;3OTL4s>=cX!v|?y$gJ-tXu==iK{) z-JPlKuIiGfpXq77Dk(@J!Q;aN001Ousn03^00j6a1OOHq{B`3s`vd?$HCn4_xoOGE z@tQi?Ga8#YnwT?s**k&d006&`my@xnt+^YiiMgeo0av?!@elK3|0QTl?#-v{Mb`Gw*UIOI*jLQrD{eGK?ob;b2 zZngsCTJlPyVva86q#TSKjLhVM@TB}MW){3EpC$gSGx$n?+{(?(iI<7V)6yv>!PVQr&De{? za&oYo^xpZTetGFuhBdSQwd^{%dnLYm5J*`MczQGmjso7>y}w`sV#iF<$@@o!H3Z#MnA0#`L}Cvzqh zb5}=q7gKX_4|4}Mihn%u?iXGqYcF#<_@l4?+TD}u(1BWq}u%u(kusTva4RNu|ZbI9Yf& zIT=_P|D^#OI9_mHYYXqs#%|zNtjys2WaeOCVOL{e=VjsMW#^`2X60pO{%7QWT7&Ds z%-GHN|F8XfR+I9Bd&tZ4N?E(QIl6fNbL(HJu4?Z5ud9Du+FAdT>QdXs|7$J)}t+=Y~dk%gI& zEDcFdM~_xw~n9bf7s9ePlNwbso;M9x(7x8FqAO;2bO>@{sWE7 z9l#Le0>+xeq=5_o02piyj?Djv2mnBx=$<%1_gNWpKnNPGhZ-9jo5}b~e|&GhNw1Pt zObKYY)tk*xVk~CCmtsg`NkQ3UXCb5`sG>$AN@_@DzBl}k$I-&(qpQPy&cw^Quflx} z0x?HE)hWEtM^$S&OhjteYXq4&gp}ExqSOHS#<5@NEGggaycN?49RIB96ivL?)+hd~ z5Yw)|sB+M;-g4d=s;@h|igQXLULfzb?9NWrQ+gPm>+ue7=SkgnOk?0+hsc38ro4;p z>ClSTl{WU~u^;L!HE4=|Mt5ZA;G?KkZ~c&oDgr?*$2<%RdBgni8lZnO%|Iu!`|SES zQ!e$Jv37_Td!#oqsaSPZ{TFeHRU~mrqS4yv+eZ7cgrQ@53l|_|BJO$}S$!p8jC*_` zamOq^9|Xs!+6PJz!v&!VsLn1UcQ(T9Yl<_pBH-vwf~;&(QR{#J3r z1DORBfK~tjW8O|5z#t|ZC%>|zGaA@(?!}_xi#BN(6BiyHh_q>X@PMoHj2jdWe9*Ez zHEr|!^NIx^Ic^IqufLmGf0hLJ{j9$u0~~H(82aB!=GqdUR`nq7hu-;NfWJLiTW=~l z9z^r}Atr_3D*VZV6h#N9AiQ9smANPa^D9Q`3w@tGtl+M9+Sfg4&jHKW$iG_)?2y{- z-5BmWM#n|YUqUPD2Y{_fuWkEZE8Cw99Z`%Th&;R+j64Azi(A@ZY3;Xf0>BHGyg>9x zLAXvT#)XH^dH(45f4Hq`0mUBQVJxyPb$glpFs0PHe0D5jSj!&a2elEN)Ez}r1RkO!KQsm_{8%U;cmmuQ%TGq7_cJO9zavlV>)IEbKYo4e}!b`ySw7v1HU3%pUhkWp{ZkGcAx zQup;QBE1Gb|AN&@42YdgX-Q`s7OERBZUTOkFoYmfVkw$KtU50M1^*Q;$di4OsO{bp z@X(R_aP;SG49TMo9EFc3$eqZ1cAbzL*NO8wzUJpI*8o4_potF`)<~z~L}iz!CVpc| zDP?qDZgvp?UD5#2S;qxg7Ch}`Y+Uj526Pn`M(RnQd%+N(({|Es1G00V?L}& z0ztWe0OU?ZhzAZb&3bedpvW^%oE#$l zaBU{Se0C})_A}xh`0&ePI-n-^HrEE}oZEk_NI(|sPP+F=db0Ch2#_=*Zn_#llRVe~ zaGDjEYY1o@xa`C+h3*!cE3`J6Ph-LH!H`l2vVf|az$5ZzhB5ZQ&U1kpM{>AmBRwyG z3d{p`G67#KgYJ@uUP=I(T9# znMQ7`P}-EdACdy1a@;|6^$~nTo^2sg1h5ZVM5wz{L-*CdAWK;)<(kbS>RYH9KOL%+ zS-hA2C20cX65um3EmgmCHU!&Kz|*?&%F997I`ZZ0EJb0tXzya1%*isx-_q0p^FR*o=F6WQ&5r*nuF zw;Dp$fZ)%d=Z@zdPp(Z_-}5(T+fxMKD$E6T!;j=8?t^QBFxn$|-;J4Tpxz)#%wOk` zm)n2_!f{h76Y;(cbR)?w>+N`;bth34u0jvp7}hCXgIBG)!Y1{kkHf`|g0O!UdCoa? zcKzOE#MA`^;FU9ogtyJ-(vV1U6`60fwTchGw_0=2=^6N7a{dynYil?cyaC*#Oo7Yp z_Kto1;c!d4S>CGfW{SJ*B4$wTus&)KxEn;C^4#_eCn_uXLsuF%l)-8QHP%;gfc~Z| z_%>Cz{+4tf!Yglz55Iyg!l*CNg-%Wkm&}sjLK)yF)&oxCl@d*+SC^qMB9EpaV=$mK z6>YvY`W^h9UoPXjNI7_s)wRW$HaN>aV8KJBU9pk;WhQ{jeO^i_*0u=&TJ8M%dLKso z^@4~>XvP&@5{>Y%Oj?`dA@u_ncTl?*QNqZnkAj{%DYHAP&3y`|GoV1I-T_JO8-vep zF)KgxP88sS;LYpZ%!1zX8|*Z4BjS7ga0#rwrJ}Uqj*zuieztvs^Xb4uge|&`m!Xio z(G;xAb3*-=KlkFnd6jH1ev_zP+CbYR^D&5CLvaNdAeC@%yQS2-vCvSYT+slZp*0nf zIe_b1;pjJ2gKzQGzZeZRl_<2t6w1#*^ril3M}b!N_@x74c?0SR?2GD|GMqs3&<8NM zum9ryj=&5uE4*fgKU}iPgD6 zTsB?HNx^ibL1laKA08WeHD(2BD^F09>$a!^)&@yXdB3y3S@L-uhay8t*|J^vtrirp zaHDR^0Z_YaI$&=|pe}?U9=?JNxfimj>yd|fF9G=v_Z@p;U}p&c0)&DLJ*$A{x8w*n zNcJ#l6Qyl$LmHj)5uwvVzIm`eEYF4|GW25w^pAm^M-0JN6cR<3RICs)2(NYF0Up>5 za3{7Qs_lfQW*p;}2*Ie^RN9!8_(&xbo4#1{zUfbTy(U;?a7>5X= z9EA7s&+%+}V<36r&I=@)d<6tCeYgnO8*+XgMr4CzWn+{yhb(mi@vuScl{mRa8_j+? zBHg2Ci=Suam|d2eR1Z`&x~m9EfUsmm=9Y@c^Fc6reg$amB%il7tJ8ak7c5Ef z7RgS#=+4beoCAqIt$!P zh+OYzf(*>#@Iwnq$`i0e+v6d3cs*J{f0)~ciW`Pi`?W!_fz7N_Zdelgd}qAR%8|1Z z6NExPCygA!-{2p(M!Y#2D0DpQhuhQpCviJ&AxS=cX-nvfDJvjJ%nPeQM3(t(i3~Q* zG?=WNSIb`RbZ-njw>$Hh0TDdY*f_ez<7TYdYBvJSI}l3)LZe!!HL zq_Gmqwcc@_;tVZWcT6!WQ4m%6(k|mXaTm-bT=)|8>h~!KsjM*%t>V6jqRPZAloRod zo%CGlc7VcJ!S6(%ZbBkXq=6BB(T8tSFHq8moxb72_jd8$-7_|sq;)zr@j88+BIY+J z7BKihuK{&;ya1G3gXW9G(=IUMnu&OaPwg+y>!4mL;KL5m>Am|VIsY0%q8oD^rm{}< zlCglyHPw!?9q^(obmgfj5`>XGAjW&c$wv6ul>H;Vx*~myCf(WIW(G0tO?w|ut8{+? zHq8@-G&Wzk0xxO-eiT8K0H<#?%fiO1p9!^Ds7zgc9DK{qZM*W2 zvoH$hn`~B3K@!|<4~q^aL1fhoW~Jfp zPQnX)capT&vk72haVl^`Wm(kd05t}VK&5o0SIg@LDNEK(S8W2C#@PT5a}D~t{sv(8 z95TickQ~UB$1V;uB~;(`<$U#)%#Zv%q@8X)J@PCZw>>ut%8HmvkKI|vroI?}!yy+Z zKOu||8ghh-IR$hpriVR^N^_howWYlXu!B4gyjBk95T3a{cz8*?Gg+@?r?*TYFHOm} ziOEZ<$%~<#A&@Emg}?Kx1Qhn8?FW@vke^A`sqkh&n(LFH5I*~wO_il=VG9V_=x!`% z#}G%)T3M{jL%tLN&6@zg60$amI0}P9SCY)t!&AdMsL<6QmNzcT5_qVz`PAVQXOtJh z>$rPU z$uJi_SLkW{L_&VmbFxJLPuJcY$Hy+b67#->%i&E#M_MlKffaZJB#!tXTyx-ZeS;K^*%I)I zdVL%%j59OB8`ogp+4bU?!o@{K_CNEe^SJsf`Q|wJ+~X@@6mi}C?n3s}`$Y^Uh^KSN z3kIvxJsZQQ&(sC*F|=;queL+E$%^EUl4~Kc?20aw3G|s@T(E^N`snX^$&?^n<9b4L zZ^AuqQ6yS1js;zzo1}9De>LE5C8atCO>d{nl@lgeP3~TICEhK0Vzml6RHxJY#09WS zqkEGC4a=p$0F&61xM6Bz6q@Je05|uLr@BCX4{$ZSN=ABc!@uKdsMCgN2@})>hwyV{ z@aym|QB2dWL?I&?mf~+qXik_k3{hV%R|n@HM6^q{s`kf*sWTdCDo~*1$%;B$u?w?5 zQ*a5upw`e_@f>3%n{HJ)ZN%O=T?H!J7LT^c$UCfSSPZn{l4YXBK=4!xXfThVs=l=9~;9{#lI zA1;b{=6iCpGr4R#d1)E+dd#e9kuww%_;q5PrO}eG*+z|Tz3?|VVej*Flfv}ikJg#A zby~}y@U()Lql=9g!M@5{D)^3d2;5%6TVfEsZw*U#)w#lTamQR56kTMXsAj=wLSH)N ze0)Tq!EqKZWYPhzN5Wrw?yu2>91y-~elDwKcI%WQ%=f{NcBpy^F4WI~lNXjiJ-#*< z9 z1=0X;hp+)w=LNf`>wCQn#l|2W@avVS#&)lBjK3qtPskZ>a(k|u6IcNIEkS>W6aMyb zPD)o}i!LMX(6~>)M|Xx5zWs?!sQjYlVSXoAr0S0gtCW^cxin&jDqA_O@DVI0Pr4a44;9<#(9HU>e(Vaw&lI9O7bIJd{S}$Ih;#? z>TZw?N8>fz2Ac96_UQC&l6`pbX@k?1z|Q;?WM1W(yy35p5!4oth;f64kx08-z*50N z*NB61xMUJ^Ub7v()LQhHaxZSH*~pDd97~`BHDAJCCvHexWg)}s#mA(sISoZ>*Ih|7 zm=FrdJ(s1)SDSOo4L_gT?N=OFPcR|lBRccHxq+DMsII>o6aLfL-vO;mYYw2ATE)kk zOT;Ev-oi~@i}SPTMIuy6fH5+eMe!$o__^8>^V@ZjX#9f_?%q*SHz@my)DM-j#r=5t zBc$*m&fUFW@!b0Z(nZ_6^@t(Fxyq~ohLV0mI)9yXz*&jY@+`|LYEY1IMOp_4w-)L| zuh(5n>v_qGxP}Mj2iy2k64L1k-;-w+m=o->5H4-qg{=Xb#J1KYE4lLg&21kXfvx1w zzfa%xzl|0&Fm*u% z^m{u@K}Z6PAvdyt2^JCTy`awvTku_W#n$y7tFqIiXC9{Wz{LM8og zG8v-3r7E0!jaA-JCKjvccqxT0t*UvIZW_p<-=1mdFv;!5pht;Xtz7pDwR7rEjj@p3 zJ?5#95&1rB(w8i)=I$q?kFa@4<*wO+?@<<q#4uoL1U4}!)OY~_yB_tSfldlpKL zH2|sWzyw0Bn*_#4=i+ugyXfZIsB*a%#YA>O`>^Zf(tgn<3t+>=XRrG(?1adH?LC13 z-~@hx3#$BZffMX;@1;^Cv!cUUt(=;QZ22MMfF#c8F^60kTERL5%QA*q{Vgr)Kll2}|S+5IB(5$hCVUM%cI?QGi z!Fm?rvvLzaZh@MPvxz8y!&9M{!t7d%W*Rx~_8%u!u*d~NHKXd{AtO?^l#<1M7u-{L z<0OdaoRQ*YRh-mj+p{2bgH7 z6_%GqBDSw->dvRw^Wlzt6OLu=`~E?k2sI0#!GMMhbf{XlsAV)f zX?jRq15624&KU5ocPCefcf5r z#Muz@9OVx0^0tC_HEz>xbhG!I^Vv-r<`0)jq=aZAAd^P=M z#xQYyQ!eW4&nPwiErsP*61DEIKIf43UnVG@)Xl2%T5)E0QRuZ94J4wMT$3Sa(22M2 z+SXq%Wp9ez1cR6%#6<<*m6{aawCAUqB_Q=m3%e0=-Z2lSVVc}+Q8As-N;K)S@6SSg z#@w8ceOKtNNfCs7rPGmOT6-l;J2*n*S@>4-kKT)9-^JTn%$0Z{ZRJaN&7|jtb=z|a zq;3eJ(3V*JDIIW;{I_BAQgekDvz~QHpoc4=6rc^@Uh^NbD7C_h`yXf({XG0pYijdt zBeU7_LG@b5aIaU1*{4oPJ!gQ`Pfq6)BoE{ON2rS^d2`ZX@_^vV>4VF1;n)^wjJ~2o z16UNQDe6MI{NX_eEd=%56BMW9W%2DYr&^y+(4m+wC$?_&v1`n@Tuqb-Et4ma=D?3h z-OO(qLROgSkwSktK&OD;7VKCskRxtfQ<=E9pH*W)2RD=0fQ9ri!vl}&Rj8@Ln(Ug7 zqi>fHA=^l<08g%fZmdJq&j0U=d?`Qyd z@KSGeS~db{PHFeWRXtOW_zyQGyo70We(2v0+&Dl25#aRzX#poq1s@Jxz?s0nlvND-c-}Ly$-OhNMt?wMs4NQ~UrC9itzO<^RVosmn-GD5 zHHHWx>*+A}8d}uU4&L)95)(wlRIP05LTbXcDgZ|s*Y5RxyJBO&O^8;##OBv>ok5auHc1(b~pm60(d_hRY9Ia_=Pn}4d&BTwG7)aP;?BM zI$1mTYqcR-pRc6a=WofJ<6@58*WHsCZwnfI?x|^F%12#_Lh(_my6R~pJLRK9!D9;o z(KT10viL8V%IXxy6RbRTCj@3~RO!jeujg^GsnoV@8384!i9u&8@$-JW61IliY>y^f z7i$8R;-wvZ`x3^o1!W-%jyx;o=&9rStZRZ0vfcBBVH~b;{~5kit_M1M?>J-|a}*hB znQQ`-_JOP5B)tnel!fCVang8{YMemH@9eud*QlxagXt3g_JGBs86Xjxsg$tgGOHs{ z+xXI!^Tw^qMPnL6K!K3OxC}8j?DE<>ZmQ zB9E47)NTFtE0>o##-RnjOY2l z|Cf{=c}mThXQd^q@R$e2!>k zRK5>OX@fRn4QNMA(D@Un>1ES05?_fR!$#eoTsG+oX4!z!-o&OC&}(d_E{uf*!>zPT znMk4MZfYw~?8N@Ac^4|X?KLd~$T^&$>R35V6=z)+qwO$T$k7&T-6lbn?8swV^R3!= zL9yPLj~-%eskVQuMR>K*>yr`&^amvrW68yk#ozY08>|VxFN60;{TC`%Z$|mNl5qrCi-UXdU$GzIi3U{De zwPu9N@CzN|a&}$Zp7qz{W>dE4+bp}B`i?O)#P+&B?T3!tW2XD?+34Vp70+2`ZvJ>| zj zMqe3R#QLfynT2IjutZ*{%<5pc>>D^Bwvh8Adg7$olbAn&@hIE}&f9Ww`4JmU`UGSRRj(9OMn0V`$Gn7uklWxYS|mCc-yA!!E$g;14nMqH zv+^s&q+FJRVI1n)w_mxVv~j6}KiGXPhzA44(aST(@h>9i0d-iqIKJO`4NlH>`0Gf`Ld z{)2Yn1Yyt;b{CMU_{s00D*rN+e~WE2IE~T-KWobj1ubzbnds*_`uE$exRF$*Z(pOh zaYBV^pyqUmH5{CJ0wwcY`u`02kp;w>i)3^%B}ukw^fx(KnnoMf(gPbCsS-WEsJ_Mn z{2p)VJlhcXR@K1Vh6``?dhj`rkGCDC6Hlqz);8&qtRAJ$R7ThX z5|;U#R~V}zWy<~>xPJP}2YVtO5CsKvu~Acc=F-KjJSWsn%ZB@|)zK!P1#gt^bCZgM zF-rH;Pqsd)X1cVV88fWg7T(l|HdQpY3lLn9pQZNgqJChjVJTl(AFuX1gSXzr-1?M0 z{rg#fGlHRI3G_a~W2KF!qaNcc3j&4I$}k&!dr=R73bsNPcY05}+YQ}2p6cL!=wSR6*Xz%>@KJ^^F%Vtw0^SBlA+!D ziHSVMh4Wg^DRqxzET3q&0Rpoeu)Gb*ANTQqh00mMt~}7=-<2DEB>Dr7780uC@eo3^ zp^ZYvF^#GA$0s=)w_Jx5GL^GqDpd7Wy1IeiVV+fczOAT*5L=b83OqLYyu?<<%f9R< zhP^@>E;hmc>Gl|3t%$?Rh=S>B<8^F<+-uNENgedEh~NTdanuRL?o}d;7X%aKh=DOJ z^BvP((xxug0PUj)G|Qf$=X;RfLKXMmEDlX{FJ9y>G_}gyWyfV~Rdu;wG)7s;=fiA> z==v~-cV(oro2PbQv%;4!Cw#JVAnksh8tjjsjj&-3UZ>UoYJcYDmhG@s2;RNkqCl&c zoJ8bf2!8Az`=KoHGs&1;T7ztoj4&fWcyK=c^X$~(8fUaA;k}vxUFnCHgvc)j<6&E zSBrP}d$lM+UT^{YYH*6bNJZr$sYKb7RsdAtA%>&~3%^4^%)&F!!bTTlAR0g8iWbIn z;_6QSjpnFGgeno{$i7{hZy#Uvj`R={Vz+W~_C%|v8gq_z;id3v$p=&-BfV!Y&bdefdTioK$ax_N%)}syd zaMITjpQVG8jgS`8F!E!{BhdG^L%s5jYb~N^&HP4R$NSX-y7LIi^c>`5=@6WIeqiVU zeomYqIdG4#M7vu6>gnI8No&l_hRZ8 zsQiK#y0fn6a`Y`mu78=w zz^A?RXATXB2CA=ofQe}!y4t4Fu{|2S6gn015T*D|@D?YC*+|fpv*O0M;zI5lAU9>K zKF;p)IsGj_IGGDSat3!Kb|gDzBIZ#$Z^{ttk>I&_N3?^=8G9Zp~+8Gld5*=~XK(q55gTK^LuuPlcqYv8+eaUkUSN=W?E8Hhh-rz-43pM{fKmG&ZZQKj*P%kJ+(NYD5c3MLxhBHi$5j9 zVJq@ikrv8i_z$HzLs~IngD7|#|z)dN>=zyWo>$o91`KB zjQ^u4d50al1dO!PEzxzd4)nP_iWDBi8pQYY=xW{EF$0V&B4qxwnclqXA&?F#DW2x` zf-oClcjsOOW)_dt0QZ~2LE3)%zTsB|a&lhh*9rn3#h&Vn;h^PH3uSwdG!z+~R}S8t|4N zH9XWxv!(W5KK*r35vY5aGf6mwB@wB^0Lnm%P) z(>UHIaKatJR0=%WR`<9CUVZdv_Pe}rzJ2`evc9VZx(BWG-L8^zli1aky>@BMqXrt*S+I`P4^W!13anN zv7sB#-`f}fJ{nup&LqRQgM^xu%ZJB-lmdb`GD=*--C4h!i!FMOlGlZxQW!ElL=#x; zRX-=uYvy!h2)YX+U(hN}CGW)kT{`PY1-xhplpOvft{WwOG^_AR{HsLRh{9RN)COi0 zxqZkJyeD`;`(V(Yd2S~p5{jEQz{Yl9n@E3C?+o{6*bKT_FA@fHzXl&Mv$=kSeBS$G{%*`mmWz0u7~S@pxT#8xdkby!a#L;!oF4 zyJ$^ZfhoL zx$r-hA@j@Gmv@UPOtIZ)1wVy^Q}EaWjRN$J5+za=i|gRSm<5a@@H|6Z!aw znn3;c900=&{B{c7H#4<7TSp|pCQmyX zY)^(#OW%bpfSZ_M0jN7uCdnHTnBrINT|_&_!+ELc`DTEJI7R)UlRjPYkV}T;4T=aU z#@!r`oEfYUiL*2Ch^Q(UEzXKIGk1z^oww04L^IeQTrl%AxQ%;7LOSKUkB1iU1yidD z^nW;R-uhmOouxatt6+v(PT6P2m((Bg z6W`d3MEH5+yk(8*6x8mKFEmM0e%mCZO!YefZcs=*@MA$)N?T{U>*X733vBp>izVZ+ z;k|s#dRBA`X$n+)u5?XmC+ZaYQIDU4vb+0H-S|T+1vevS*7k9{H{DSs;Nj^7DcBMQ zyo759jX3&kQ05szF5^Uy7Np5i(2pY12LexGV%N|}rxF4eKi#O)#hdZBKK(Gq+rvt< zEtR|sKh_nbVD^zd4B&WxDTvN$$7IiF$7(+)NyCesI+@?NSBFIVJo_j-0X*;+5AL5z z;N23(>$yBkTg=ASV_BY=nEqYSC_>*6C1xzQ3c$e&{sl=y2*+X}c}e-ZOq}ZX-FukRin4^q_USa#mJXK!ex#w6kwCjJKpmj`b7|ccm2J> zx2^~_?p*+Z2%Tl+<#p<6+;-C%KUl6o_W3n6ok|u2FyHHDFVzz}e!R*?7~!i+w3y;d z9oV9B|1RsGtTMN&_%I za32NAo@kpt*OW9=P>QZGQlgzrA0xsDBhER_t{sVm@8E;Ku`Iw?@Qo~pi3hyV{sb)b z;D!Oe5nzK&+jv-46dOP(+*%+su}8qM`w`_a*B&sC!O4IcVI(|b=ghQ3K3eXZN$@06 zoUA@oeA0Y;Gyzl8|8n^Uxp;JrnHdAtT}9YUpL*mbhYx>pH>pe9GaylAX%d@Kjb_K; zA#8y^0$$Z~#|t{%+0G8goNeS2cVW2=^--1?dK<@eKs5ICZzJM&LCOd+pQd`T1-|7W zY1X@lyk+>GLg;m0xES2vAmp%5o!Ku6_a4HkemnXSJCV4ln7K5y5~`3)9L)dT`-2ki zd87G$a$^D+wYn#qEK{Yn1;h9VG#$%7beho4f5$(##T?-_m`KoXmfBR za}RW1QyF0UO;1s7^h1?d&w8{X)7n&;g*lvk0L<;hUsy+SrncZ+H z-(?t}c=?uNv^!2(A6VBMZlzDF%Heuy!^JJpRh=}dJCMh!^7B`I()?z9JV#X*5AgLh z4)D6tl8ilI#Y1*6USt&ty(}^4$++*9P+g$fma}y_d(auHuy-TVr>hrj@<6bI7-d3dLZi`$kzWR2#>-08VJE*lj0xmzKH$J;{&qqRuqj)@mkdiN#=A`|yzYZY#(|?D^ZV=GoI%I1CSNh&#m2nRm!N2cP*~ z0q7Ab|A6zC)I!5&VK<1D6~M8-ja+*0b?e|1%%lb`K_U+R@#i;ZaG>nNPwP_cvms1K z5ff1|24(U`OJt+G#6~VA|FudZgjt7X&PXn?E*(ACr#AaFUli6=1F1r+a!e0nzv_Ay zGBc_>#kV#Pe|4iQale=4lsUXL*`Oy`ivhI1-&&lPjtSe*i?2Y;NHzkAbZoD?J(&wO z9XJLOFXkrwq@SsTj{N&^w4_CMq~p@L64vLS(x=@&C(oxJ8BITvpMWV;l`m^_kATny z^yT%tL#TNjXr^5?SA5_8PIk_kIF$aDMe{f!l+oj+QOND|m*#}e#uhUe)sVXPA~v3} z0I#2X0*91z0F{vmTAq@gegR2DZtX@TM%>uP=R*%J29el!UgEym9Pk{EEVx&O3jVgc z%Hr{Q#82oUR&TS@4?UCamt5iX#2b)WNR@bJ#@JryddPu=$|!dxskGBUQ&Dd z%4Psn;td%}4|2r<6o5fj$?@Nzb{M?IPfP0fK+h zVIgnp8PLj1Aoyk&WrM@V3B}Ex-aJjrQQ>ZhCS)uFpNaW>N*MDCC#6TR`tdK8MOID` zX9@9cw6?eiBJvg8*fox+q0%3)dQ8#N*n8@&I9pSjUj4T|Kh-aLc+xOEE|h-EbpI;2 zsb0IzXXPV7-PajVxlzXR_kd0&E}b}ke%@krmeM;DfOWKGwwaA`{cHZET77^QiIzYw z`avM$hYy)<6)(Dn5<>{@vjG3__^O}4$EOwtdm>;=ehVRcOl!#MDkL16`fVEO(%2j1$s+j}^{Il!}Z)pP!$1K5Dv?4=a? z;AF3-I;!gD^ttusoMfUHO_h}KGGz+>-) z7ja|#(4U8J(U+C8sPL0^c->s##1}z@uIoRmvK(JMGy@`fe$SLE_YtI27D!)EJlY@FKJi=%Dr{XW=x4wWu7uHe`hs@vW_Ah_FzNqs%L^XgMb`fj+!)cEV~|jfDN> zR&EfW&)3XuJs_-=`$afI`_dHmI{yxPFetaJVqm_)4Wk$E(6#~CL;`%itbza-1@g`c zIELq^^W(#bK)qP&xxj}5$@q_tPUU(upz>ROAhnd4_eEzCp%D)?(LAa5DC41Ug*5Ct z+R(HUn?vUuMz%xo=vZ#cvH!I;c2YBL-kFEaKz)p1Vu&iMTD}v+ER&eXV7xuhgiE)Y zk}m#I3w&x2#aQ?3^+sHQD^xyfq@^3?=x$Kpq1gQTcamy111Xd@l6X4L>pvhfpIZ< zO465H*bZO*zG-?p&U4<-coD5K#K(z6A(v~BQ%5xnkURdu8+^cOlWgHA_>M=Nd%UjQ8_4-CaihkGmuEogO~{Ee zHqOV6Xi1H7wrYq_KA$nu>qB;gl$r!3P~&A(`oQV*g9|bUX-Pq>Bu5wuvqgT9!SAv7 z9sJ`~w~*n%M<$@a0T%$jmN^DSZUaLOXJGZSzo-c~AS8!tCSNMS*MA!#f~$heo3aw2 zAV}QJvb$wpfyeds!RtY^5sYITWz7MOvauqywz5p4_@OL z4Ob57L5m)+hcFkjQ(IdV20X@C&(=_g7~&C(CoELKI4{eN8A_Yk%Y|Mx*3{>Ap}Y{D znfV=!j?-z$czyWw@0Z-8f(qr*Gr2%Oq0TT;GOVi%y-f2NNx~jPy533w6k0> zQnwWvBGZ}Rnsl39txHg32k4ht?sZ}&vM{0=&&GVpkaPWx0}-?r<}1WU_qSPCh~**z z8Fqf6)+0X-`uN*ue6vX*e!v{f?Bj){sLa(@c*;3pR#~KGo7&$l9+pNnZ~yGK*IRTV zgEy(|-dC~fJ>lnoJRD2P8-itFm!wdvN@0PU?oNB~S!J5(s?@=7e*)!5{JA^^Egfq0 zB#v+f5}0X0sV=^3fQcIERCElFC7?9aQealM#s1h(SB;9sTbBDR%R*4y!vDeji^k4t zJafa|aUi~YgSFhT{V=3{2;0jtTe$0FdE)6baTnU6TwqDPsv(S+aeR4J4RGkfMj~iA z!an31qB}puODiRF;mc2kAhFJ;p>u>n8MoNPky_>qiCy@1(;+n&ZoI$(zR5TfecFoC z^1{G9@L8n57b%-FZt&U!_l{2;kOzSnod^|n`rp1w6t8g7!MD&3alpp{iOx$BL*}W2 zxiUgE^=~i^%9k}JOlq}=Q%>l~iKIS}ryXR`c(B2{CfDm{jOkWnseXj~r9=CGIOL>t z8>KmZjkL@eQ-(jMg#6L{sAl%`mfsnjc0cwImYu{ytMp~Z$Y|)`PcV{9yN;1sYF6{7 z&^VCVK6zU~r15U3X`WeKFq=c!*e)FhGW*8}WG<_Ri4PT0Kjh{E9q@>PY57!<-e5-w zb``WT+i5N;ea}0t!T(y&IF`8941SdV@Lq-;Se+}p7wE21ww6hC(c*PEaT(1;rdyIi ze6}evV?6LG-0oE@EU#D$MO%`3Nn_#Kt=rfQOESDgoIl#-MT{1>*FiV8ew63`30e=40x(MpZY6mDOc&25{_mN z6CpE$PMkgP5N0YdGs=O3sK_<1>aKmO?t>l?iFi+$Vx`{0SBNDdq-Wb82u~qU&crE^ zP}tl9?KRniodS>lQ&@UNz;DM6++m^mOinkermCwwzA=z}h!m>)2` zcMJ!L7zW^Y)U0Bz(y`KiWitJdU+KQNMH0xCSK&^uKzXt*wkKz`)cv3r5jd77Bk+P7 zKXfY^F?-s~hz1OMoNgwlOGPfgjj3Ax_Qr;&hrM8v9Ts=sImo^v@5)2g8)LXF>#Wb` z0*bMs3dPqj>q2LH4c=)>va4t{i{N}D?e#6Do76stD86dHi#=0MTQDY=yg&y89(UO) z1|WODf+G+04o_v1&nv+J&e{mdEFNaccBNVB3I56)v=}|M@cHavG4w0j{U|YERd?=l zOHEICv1r#uUjkm5qGS88L6NCZx1-Pz!|3|ie8m2tf;a>*4^QzU1@e3#|64OmUaNK; z)^Dc7kId!)cAh(-w5D0=pNj5l^V#hKisyS_PlNm<)R9~;dMvde3dJZ!6ukO8AVdgVR4>sl$7Q94r z;F`0y8(Qbe`$MQ>#*LdK_@H*V(>=lZ^)EmGW~TrEJ5-#88Kb9}H;0~F15k`gn8*X& z0833ysutU}8D~~SUmy!VkI79(zH8NUh=BX6Jl&hBXniapxiB7D;WuPL7q0c(W>L@R)ZgNCv_ zXk_j5aEu;8MCY;(p=u;uqf4zAI8 z-due3@a-73KlKC6TDt>6^VZ>1ictxf_-c13o>!Dd3c@~?l%nP-bjS(R1zX$vM%Bb9 zre%ir+uBUC9@kJTZs_MWT(NruA8HTnlD~E*JjS!!IUiEZ?p ztAftqpuG&hk3D$p$(I*{zvE!r4Zj26?l(Ms321*0=&u4K;^2!G*L93SMN(A(cs;#s zwAhNp+4!K~P|-8}TlN;xW}VQ;Lea$rAaom$v(f0pA3i)4Q7cNlR@^0ow6Zua)Z5lu z0&2g?YzPf{so$iS1i~tXjv~{l56qZTkPM$%;FQVI7#G5eBvOLwZ ziVk;(;z2y8(H$`}O!Q9viXl?Bmif9QCRd(MDf4-t<-746!#U9QEVIcc;dKvvn0Z9o zGy3}Cbe;}nEZD&;%UWPrq%!KgxJ=kc&tLn@1W(EZU#OqfCdkod4DBBS_$}A3-1SRU z4|fXO(HVfd-|+YgfOgG{KVT8|T0v5v!|UY;T~{)DxaLK#t((;+m)FX?3lddh~0 z?OUY#0vyiXn|UI3wk?^9qA^m50L$KKu#UNc7-Y z4_S0R5a>HE9vwyFXZ?)r7osUCowjM%hC$%707FrAF6C%wEl6cL=0o1#I+l359W{as zjC13p`Wyz~QTeL)6)0-uy`H?c=-&^%(HgNm?r8jJ9l0bT8-GX>y7qGhP0D!r>KJ-a z*7(`lSjdV@sGJzB63=gNnO!?cBpcP61(7#W?mStEUG<6Aq~TbU&u*^kCA(SMB)LmN zZACdVjOMS(gs}*;$b&^}8an!`dhgdBy7trywD&s+?pO!l?l(N%0K69HUmPBE6K4R> zSI$iAW*0jN+GteByqTq$Lz^wpZGkk9ui492K~z~dnzD~-x;&h$*S8$vn%szYZU z7q?Z9#zmD4{n`gT^OSBdCc)B%UN(P&Fi`QhDCr#sJIDEoa{hv?BI6(AgF6=Ir11Lq zECm14Hv?wh6cB7QH!AN@W*OYDJI&F7)7H^(=<%O-XWoPyb__b0<~cc@X7R1K2Nw zi1tMS?~AUVx$bCdop`{D7Pu<>l#&yL=mt%O+xVh~_V$WUSXpaECGe6B{Y+8yF4v@5 z$~Jr;k{uoRFHiH5J~mVn8eEa8!mg_i-e^5`2zYOjXcs(g3_T^wGRnLUDmNP3ipOLq zIFj%7jEqUSH3peq>vOh8HE|;R@#=)Cp*0#)Gz*sRMMk%cU6X%AGY_myu6u53PKdu5 zAaq+D&jK~VW3tTi=wsO$M-A0n>3x~?IWR8^y^ZLk>TP)zwrX5`*tsN=cFusUj0{G) z4LRpdSbqlIo55!%Mxe#H;BN;kec_LE^gliy{Ot{Qq~~+@8{YHfK>urqT7VX%6|rI% zf@wxfKa}B%ptCHBcN$z$D$@HhZ5rL#7K~Cx$A{oJ$hLrr{g0_A%;;OM)2o3k(gMI2 zoSh8_Ixq}*VmJiv`N7Ujbh?gqO1lnc1KjY^z=F4hAtP3ynCgNmzm79I=mf@mMS{7z zVE~iSKRFSePKa7@>prqM0|(CsFxD#ipUB7|2nX(b4gt+t=svh&nMmBM(>N$6-R33l zDJNR1?h|gA&yol!l~lhvMF7oRkpVdF<3Y+NDmU3@hhQx9)fu268itPL?`^DYEI=^F zAT>Hj8{Kop34^xr>Lfc?)+(IK=>Wd``jxwW@CfGIR&d8T0C&IP@y`bE698TUK&+rB z2XP4ea2d%{kUe@}2bfaDpf?JGA*jNAdKi{aQc2uo43j>l<2Hlv*?3RdShZ58B-0dw3AV8zJ?D(w@ZolvXhuC#bT9{{uyEFXqyg+n)+src6e zml85M{KseFz@h>?=d#{R6N^I^IM9}@qsC4~m36Rkty6iXieo~rN7b~}{2<;+q46u9 zqStu@ly8YA&3P&x@+?m9h(hLb8=@oa(v957I{ZlltcG?5;=C-V%+5-Lohxa@{FrcguNOOElUQU+NXPU z!udXwBbF78OB#NW5g5PAdO7@tz+@indFXJ^Qk{iJ&Hb^?-v;wkmfZtkJ-e-;^-)9n zAb`)le&w!r)|B3UaL1ehxcd!{-;dtk7K}fz2tg(IuDk&j7(3}|V%b**QkTa#h=cgl z?yX^LRd}$bMEbbr9z{t-TG&XA(x(6KG{!;n2Cy<*l#(xW_I1qDw+B6E0wVQ>-s(>L79rID?UA9j;2gF-ca_U=v?I`5UU zLspH2_|gWRKnde+!*Nry*)U|Lr3CB7*^U*n^3ghPYOf`&B}T+E&HvI=wL z1MyAYRN&WO*F9x7{{D=|MS>o2P~B4Gy3AjeXO8-32LbbTfUb{S{u+Hqyuv1Hizna~$>8qYa95o2uYe7&sq{l6_Um5pJ|XZJzLM@<$FOLf;}GK++32tib)RG1ne&O7r0a2~tiS0yhnoiS^pnVX{D zNMWpBjXRvWSA!?UBW#_7`C;J=p5LgLjJ6o2upCFancoz!XY2%cy;&-J=D3wC8*c;H zc$FtsK6424pk;QJsqA2oKn@9A4}C?Bh`VaR!nNE%M!X&9zm| zyVDxqiibM|N^=^E^IvK5M!5`Q+{_=nuMSP}YlJZqFjG*naFfH?LqdbgWL2&IH^*a< zy-salj(S)>qWF})&JUGWEKetS$^o?2ep^TX3l;X;4K}Rd?E!bc{_)=p;QN<5Thwqt z8-{0nK5-DHAJJHGRi}_u-OPkhFJr^C%^(*3M`)_ZpxQf}jHPjtKm;u~GYGB1SKtrc zhPBNk<+A|?Si$_Yx!ZE)98*UyG&BeCEs8iVhy28GqM30{eyjaRVF&cYT zpM@cr=}m6yYoHeXx%u6KN;*j?IBjYu)X+{8LTs@+XHk9y9T~cj!QdK|lX0YU zN}p`-w=iuR5y3wi9X+S=D%VO&@tIi+0_Sf8P^I8-ujOgI7vrMl!KfIm)c5p|AmiHd zFK0A>`kuh~UZE^83QzQK%J8gAPyfV*G+?#lpv5X+x|9KvM6(*Rh?Ynk^9E@+h@V;K|$)(1LH zm&Ptil^Kg033NwZa0zLnb&?fZ8sa+s@aj}V6=^LOJkcV!7uuEPPSu;&W$&N$o*BIm zJ(hHcD2M2re?b$+#G3-_C3-We@mZ(e!o5n-GCyv`IC}hlTX&R=u9crT8t&uAMYM-U zrR>b0isD)u|H7kUjvY;<;ak3^Er($6?YGD}EJMisnj#Me;b=iRO=_gnGEIYmEypsV zG(muxZMeSmIdck>hQNDr1tpr->qA+A!%)n*$%bS<%u#Ul)oBPeClnO;TC~Qi z{)+h~e0K+a zy_K24S=K!X4lCtkGun_^kbnny8qS2Z@eE%di_GrFa@7Mj_JD}8zRVJ`Q4I?%8hcU& zG;-+%Se4}XT_SNFTW*v3JDZHbX&**5yf3|ugWRj6_lE5{t9ccS!r362l@Wgkgy}1^ zZ0y6Ff@q5h8|b)P9<;BD`K9q$4MyO!?ZcaMv?@ZH*Je&?a^x7XIl7gSROet~2-bOJ zlf#Dudygi0F5ks{m@{E?6hR3e5j8 z{%GnVo-v}Lzg{>{MU=So%?e%1647gwF*h3g=0t=ksdXH|@jr`JhSCliyj@-6sFA~?cMh=D||>$>*;xzG=9ETN1&=F{loeP%llI1C-9{% zA9@QBw_S9WbEclxV~>xltr;RR=;`2J5R3V1u|8j{M}nhb*IR};D34Le&E2nm z_iyjO4+A*S*Gm9oWfP*o^;Zo^rGy5;)JIIGwd%)FNBJ{1#e`6e?J%ZEDX{Q!eaGC& zG~*-h?j&+e3PgSi>K~8IQ&QOP53D&<->Xl4Xt!rgORUGE)32JuMoI zxW`@(Jq$j`7mdqr3z=g+yUgeZgP1pZW@6ADfSeM43#8_5q}7KdPJouvuQ>+Qf!JAZ z!Mjr8tGU$X&ZBs}G~;n6<$lEQML(oDrfa{<2g^8vlMdo(7wdS#*9^h+i0_r2nCK7M z--dlASKkPjodqb*PpDi>*Pb=<3GG8`3B)ZLxS&RT0T&< z|I0=Pw;bG74#1_?zx$N{{vm(|0G2H_tRSON2!y7vHbJaeT6ja)!#lBw^A_UD1(z%Gx=KN-Wb(4)aI|o44fs+AC z*K9yW)$-K4+GBU<^fS1t(eS=ho_jHE6Qz9~X!E%XT@`IM%a5Ul49Di%0_r>ibiYnY zGW?M82|Z@OR^z1a{JYU-hploh>3MLz^I&8ER8Qz+V?X5!vqYV@+5K$(1`%)>2Xb9@ zo=9KTnyam1O7gCFrlO+ys-UlM;uh4wIrR^%M-b@`538_n2=43!TeJTpUjY{I-I(ki2r+mFFaNYtK#BqBa>Qp=?0not9 z73`Mg)DXL#T6w*;uhPWb=8LiSp&$cs%^!|#*zqu)&LVFDo&P4vJQki0&p6i&& z)2w`LqsCwP7WQ{XC0dve8MXDKyeSqU&*R!x;iPax zyA|DsgOhZv2LyG_BVmq_k&iK$l5wY=oF)m9yl)`SoA)r`VWOoMbGz2-e6N?G&zCl| zA9(QElP}TUZdJH#8~^~{-ht1w8{JXnxwkd1;?`MEgRtqfYF>sG?XbBT6zR5hB9W5f zh%O7c4^ddV^+#T8p>$aJ51M!YOJAl_*t_OTU2EEA{cVbG#urh%rVx@+T5#591hV1q z`81`n6+PNvLHBm3&p{XrP28shSXSa&0pq~n5Fb-K#2*d68`TpQ^p)0b%1cxQCDLTlgWYlBvv+Y~_- z@|dm@C$b@7{&q5|;%LNI-`Z-chEvmdZldzaeK|QgpNm}UVZf#8n8Q}gQw4Dij#ucW zG`VsadMT<%ayaN2Z}0K+lx{IQ{8Pg9M(DOVWc6SUSp$0SpM{QZ-|pnrfx|O>3&5q< zz3bIz?QK959tB=IteDKojr3bup+&0MOxb;Lh}lNHUV zZ1v$0NtMbrlC52c>Z)jQrZ|E_MaGw`r5gLdPg0OPwk8IKmBok(5fxfVXPmoXyyLTh zx+OGQKF5S9c|Ls}D`8L}9C$`a^?Vq-kWzN`ivd0VKxA0s3_w}dvf_@mw`CgULb)w> z)*nT%v)A3yKKntaltHm-tv_39>I7Ret4njIhX)sZaWckMlCsI&dL+dbz@d7BmMw!z zvPinmha|5kuo-T}Du`geak zdVdF6dl0Yz+5THhDXSpJ`Wwa&7y`Dvz6G)quyj3lC>qx(lw;Y48Hz9pzBFN_eLo3L zhq9S_H{Qf~zdmkN4pf*+#~#=zfN~G+a~10Ab!Y zQMW87-2O0a6JwjKJ5`~z?-?7_t!r5m893Kr&%&Y33@_*R6u_sSUcK#cT8I;4?mSw@yNo@$%R8|bS{K`$-^E81s+tx$%ZgqN0b9Y5Q zkgqsNSXpj89oI%R@2qFCE9JnIOiA`QJ~kqwj5)k2ppd?`|E=v=Ik@s0G?^ooRq^PP z-*AZ2L3h?qWl*LXHYoh>U)Ma$@D|Oc#DNy79-A@sCwkcZ107;rZyY z)3Z3wl@pX4EB?pjx|Y~U6s%#?8u?d-o}F1=SXL#^r>Fnf!9{H>qOp@#NPRxI4_W8+ zsD{BJ8u&W^!-+5^dhM){&s`E z0&9IbOT@WY9fzb4l)Nq#WL=LnJDf^VP5}CY03Lhr+LK3mK{qGd(hdN6|626^B}wtX z^j$BN&hjW4Shh=2ag+xflSPSGW$cZu20mJ-VOUq^!&C?hv9=k%D&>7Bs9-qc-W79Y z{Kf&vWCqx7QGxHhCmIF+(D0F`!9lTwKL+1RdRU1TjvX6}O379E`x11{O=)JABr4b3 zW+@X&T|P)*H+I~@sIooo%!}a=*xs=^3HfUa3NwK|l3&7CH5AG%Q|Mv1JZII`1Um+Z z#*%599iFsbHZXCUiHCFIEmx#EU_`^v#{AU{qS1BL(EZoWECkwA)WRBP2eKeln9boL$GZNn2!a8diC4!*N@dhRVJAzH~?t@;j4B7a!8&))%YKM6%I{F+X9L4FJ9r zz#pnRzBS;M^b>;2!~aNlFU}guSLJG9gg=x%{@ckW6@{x-#y0X5~eznP?db zk>qob%N>9uc~Gv6+^cCt6H=^A@Ssr^-Z?PmQ=4r8Fy0N|?SwAn#V zgX#CJ44c$RbLT`)=JZIYGbe2rU^C)D=7tf729wt}l?70(qUDiq`br>Y31arhz7rr$ zO6u$ITAXbMY|ZD)!QZ06zoZHp4-V``~x?J zdt%0KYlpd9|3@matPC58Uskfos3*gHpp2swmA6CSyc+oV)!5Wsu=!i^kUAk;)Q-Cl zz8!k+ydH|+E*)#Sp5U8(Dk#i8d_XW5qQ&i!%{iOM!K5;>E=9T?+cl&+&6zaXz-I9+Cez%n*VhfYT&IeoqTjwH^-nLr%_Ea1=p0hGLu(_60 zc}iW*y3jiJS78@|7QIUJFs;MLFaPWeLEL&F+mHv0tcZ%bBg612bo}}0kZ)p`yL>k( zTzcKRz5u|FZB}ae)Nz>^m}CX=i&f$=ve9IN+Gw>U{4Lf?QF}mMM*a}mWYAPo7grOZ zUVlT1GnQ{|n0p$0F}WghFHOD4xa%y z^q&0mbwQR1b^vP29Pov=H+)$~eYEs2=9mK&%^(nR;gLE4)pboH!|ZV2q3s>PipZBj zmlldq&&8PWAG&A8e``Rm0ke}frA=rYf#CZ9e8%b3iyt|1z|T9}Vp{<1FQa!c{u95@ z(z>Q>)-v}DXC5oaV9~W1wN70}kDC--LtZy+rB!4vuA8+FlSN9sx=^d2uh0G0g;8GJ zV`E`L&R#Jo^Z35)NTEfWoXxDUb?jZzH^Zq;9(=GM5fw}zg-tm&@uwylzR5Y zC&?1T`&gD!pIxr|iq?$#L{7sH#aNoW43uM3HqVtESD2yo4)g9$J+FpdRQ(B@cB!o2h7BznIrIe)b+{Y%Cdm-(^zBZp3neR+tG>onm<1q&|X^);^u^7U9;yMF1_xZUj($b*BZ~jCRhxK!K#o#)J+Rm z(@ag;^;Cu^oFMAX;q|)FH1Tap8XIK3KjKSVLSHCrC-9F2m61Wb9(O}QXmIXhH-4qa zml|O3KJlwe-@z9&%YZuqj&pn)z#Icr_ePuHKL5NivXz&C^wGPfK*wPw>rQ#DGER!C z63~i&X_>^vdKj+C7WiL|Q#5?@bR%xb2y8uP(D|FTsWNour1z)@HrPxtqAr^OD>Yo} zk4O?rMk^c7Iy(~2QE-MQWC~oggg?6OqoR{RR^I@a({>1kL)AuiI#)pz$^40$3Tl~n z0WLeZR>G(dCwF5lc7OIor&lig$k9xA9^sa704}}mU6+9VPXWAgl%9k1Dy>_2r6HA! za4(e&S%Cv294f3^%BM0GV}Xp{=orMe7b31~{wif-{82?((a9g(DI6Ba@G+G1Sa{?t z^#e+S5pR0xMi0hFiBZX=*)k9nglC6%HH#4PTOJcF;@87*npl2i_>oGi#appe(Rs4} znImBK<2a`U*dS_oYKDu}Sv>5Px5SQya~k|vYQ21JYtoE?V9JJ+%GKBfz}wb*O)*kwJ~hI9c0~7Yro{+<2N|7Pleyq6RYH0%#_I!>d!gxEksU>ioQgEIhoM!c zhAW%}7$QzLa5>RhE!kX4A4+L5{&qh%@`sDX`YN91!E_8SwHJm$avdjpo(Rc^RvCK zX*2+EhSom!^vZ?5KOOW<05^38;L_{f`J&$YBfZ0oKVb7>hviHmFJ*C(WWp-rA0C_c zKVU4O!b~-)!HUWj0(-Ber>o^Ablq>AT#r^-(rtYB#>6}zNPSvEt`j3)=4OMzlnklAbyQsyU^FtnZTRfi9D6lfFjv zI^pB%Ehpd0L&V$jq&W3-R8o!Z>WKO~>caQeINA9W{O^g&I~Cjw4r#$Yi5k6R1jeA z(+DkSsgzDgnH39zm5MhZ0qk-g2%}%E;vV){Fr?#`y670=@g*dSoNCyb80l{tpDtof z8BXRjtTjU>A8umBW*M0R9~+i{-i!;&$bq>ka*`_@q+p1?LxE`3#o(102xn|YuvTsC z5F|MWy{}LBtpS_azKWeV44n?fvQaJYh5?CesnK#LuJ7yw9|vAXnZD9#zn;NZGZ(6(dMqGEGUCq=3DCDA zsy74pEs8_05r&RKwu^KrJ4&px)<+Gw+%zJ;~To^yvV;X@cOU zfNl5xd4!AK_0CTL@K0K6FVgp?D}8tTP&)h_WkXU%c|&=q@2e+E12kE1L&64~-be(; zQRKZdK2^^BunBcVsor>*ZX|kSbW8m+VK6PWDc|G6^rWy=3!BAoC&vuRq6`uZC*|gN z<&YaaR+=5Br+#yJ=}4ADkNcb|9aQjrE#EYMmF((3G?H@T(uMY!Ohg$C``_GekSn3J z;8FQ{7~xy&(Bwlr2cDHiyiy=l-E%-ZSwGhNvOS=0=u|>1e6FTo@;eSsDvE+9W!E+@ zR5n}N&cAAoC%j=jSX|GaP2^D5Tv`Loo0#nI-14>!&y$aGmMuCOW^MY%fc6_tuU_~U zH-Pk6hnq43aPhm|dD0plX$@}t$C_;+*cj31h6kAzB3D@_d}GoBX7=!B^<0=&C2KS? z(GeVkhr*u4UK=(}H6DGO3C0<2SiAH1xn`H~z$@#^ddR zsDReS+V>0&z)`CjB<4a#<^YU`$ec1K>oAlq1-Q9p1o$nFnDJst$2i73wNM)^cqjodTAutg@|qIfP4t(&>YSxbIKSQz$bdvf!$w zz@vTo9V`-Ani>(6lI##Hq>ZQ~%6s?Um?aq0+VcdVOH%s5%K-|cal&W}>7Dd+-ASff zes&%pMg(Qv$a(9O-|6y^stO#vtM_rD%rU6=kBO`t)qDJfWrE0*Z9hU8A6J zJ$ZM#W#@pE#?o}TAJ+m~JYyQFd*ffgL;IwHYS4#(qZ(JB>)`w{cZ4<~;(WtzijEvf znMbYY%3Ud}TQL<5b|Oe3G(r1M4Z} zEoBE>ANt&8e*s9WGs=OLTY<)8QfTf<2PxF~mq7dE)2kP*pJ%wwHr#X>fZp+KZ2SZN z`%)I`uO3|KVd{j)Vruz%cz)#7^&aq=c~kLi^v`{8N^N;6jH5@2U^l@@VZ}WRjT+2g zV%BI$d1c1YbqP`LtH@T3RSIOP(=dKmIgjQ&>kuD54OCgdQDl|H;dX&P7;U^6@qm=8 zM+9RCA#&ikY>tzZB-6B+9hfPJ*gVU<{xX#-PKk1&BZT-YcTdmgw7*x0*YO})3p|eK z*?20AbMOOzeaw{`5SYR8$}s0LcFk*c)H}+{VxTr^=*PCi$}^h|US}0w2JuqJ^9clb zNq9^iTPP3Fzv!)|ZRnYy3}=_jNom@7vHs*b>l^CNvtIS~Kpe2>WqTHMwbsw1X<1l_ zO+&V^oj95(q8_h>X1`q?T?YEM;wFO|aKWBExcFVa@S6er10=ULuUjjlJ7l5M@&m&? zG7<>JReDh>%Gw$!G6plWTi)@?jQX%3yuVpc&lHV^)=ux`Iz6hmz⪻3&Wucb7acH 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 a6G-PM_RVJUh%IvU8&H Date: Fri, 4 Oct 2024 13:24:28 +0000 Subject: [PATCH 143/885] Update dependency org.junit.vintage:junit-vintage-engine to v5.11.2 Signed-off-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- app/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/build.gradle b/app/build.gradle index a90c9df6c3..ec8c2e870f 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -360,7 +360,7 @@ dependencies { testImplementation "org.mockito.kotlin:mockito-kotlin:$mockitoKotlinVersion" testImplementation "org.jetbrains.kotlinx:kotlinx-coroutines-test:$coroutines_version" - testImplementation 'org.junit.vintage:junit-vintage-engine:5.11.1' + testImplementation 'org.junit.vintage:junit-vintage-engine:5.11.2' } tasks.register('installGitHooks', Copy) { From 2ba5a46fc0e2b26e939af6c876aae5b6c54c7411 Mon Sep 17 00:00:00 2001 From: Nextcloud bot Date: Sat, 5 Oct 2024 02:51:21 +0000 Subject: [PATCH 144/885] Fix(l10n): Update translations from Transifex Signed-off-by: Nextcloud bot --- app/src/main/res/values-fr/strings.xml | 3 +++ app/src/main/res/values-tr/strings.xml | 1 + 2 files changed, 4 insertions(+) diff --git a/app/src/main/res/values-fr/strings.xml b/app/src/main/res/values-fr/strings.xml index e5e8421fb4..172cd2a9f1 100644 --- a/app/src/main/res/values-fr/strings.xml +++ b/app/src/main/res/values-fr/strings.xml @@ -27,6 +27,7 @@ Fermer Icône de fermeture Connexion établie + Connexion perdue Connexion perdue - les messages envoyés sont mis en file d\'attente Verrouiller l\'enregistrement pour enregistrer en continu le message vocal La conversation est en lecture seule @@ -348,6 +349,7 @@ De l\'aide supplémentaire peut être trouvée sur DontKillMyApp.com ou dans la Retirer des favoris Supprimer un groupe et ses membres Retirer le participant + Supprimer le Mot de passe Supprimer l\'équipe et ses membres Renommer la conversation Renommer @@ -397,6 +399,7 @@ De l\'aide supplémentaire peut être trouvée sur DontKillMyApp.com ou dans la Adresse du serveur https://… %1$s ne fonctionne qu\'avec %2$s 13 et supérieur Définir un nouveau mot de passe + Définir le Mot de passe Paramètres Nous avons mis à jour votre compte existant au lieu d’en ajouter un nouveau Avancé diff --git a/app/src/main/res/values-tr/strings.xml b/app/src/main/res/values-tr/strings.xml index 0140c21873..acdbc7e050 100644 --- a/app/src/main/res/values-tr/strings.xml +++ b/app/src/main/res/values-tr/strings.xml @@ -361,6 +361,7 @@ Sık kullanılanlardan kaldır Grup ve üyelerini sil Katılımcıyı çıkar + Parolayı kaldır Takımı ve üyelerini kaldır Görüşmeyi yeniden adlandır Yeniden adlandır From f9e41bbdde25db8157c32b15b0e1a302704c8502 Mon Sep 17 00:00:00 2001 From: Nextcloud Android Bot Date: Mon, 7 Oct 2024 03:13:25 +0000 Subject: [PATCH 145/885] Weekly 20.1.0 Alpha 07 --- app/build.gradle | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/app/build.gradle b/app/build.gradle index ec8c2e870f..ac28217702 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -40,8 +40,8 @@ android { // mayor.minor.hotfix.increment (for increment: 01-50=Alpha / 51-89=RC / 90-99=stable) // xx .xxx .xx .xx - versionCode 200010006 - versionName "20.1.0 Alpha 06" + versionCode 200010007 + versionName "20.1.0 Alpha 07" flavorDimensions "default" renderscriptTargetApi 19 From 24a4a8f256831eca344acd1794dc3f3c52846903 Mon Sep 17 00:00:00 2001 From: nextcloud-android-bot Date: Mon, 7 Oct 2024 13:36:11 +0000 Subject: [PATCH 146/885] =?UTF-8?q?=F0=9F=94=84=20synced=20local=20'.githu?= =?UTF-8?q?b/workflows/'=20with=20remote=20'config/workflows/'?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: nextcloud-android-bot --- .github/workflows/analysis.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/analysis.yml b/.github/workflows/analysis.yml index c283a0b590..22bad3af61 100644 --- a/.github/workflows/analysis.yml +++ b/.github/workflows/analysis.yml @@ -55,7 +55,7 @@ jobs: java-version: 17 - name: Install dependencies run: | - python3 -m pip install defusedxml + sudo apt install python3-defusedxml - name: Run analysis wrapper env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} From 4571732480e0cddef9438bf573e6709a0e2bc2a3 Mon Sep 17 00:00:00 2001 From: Andy Scherzinger Date: Mon, 7 Oct 2024 15:45:20 +0200 Subject: [PATCH 147/885] fix(ktlint): Replace wildcard import Signed-off-by: Andy Scherzinger --- .../com/nextcloud/talk/json/ConversationConversionTest.kt | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/app/src/test/java/com/nextcloud/talk/json/ConversationConversionTest.kt b/app/src/test/java/com/nextcloud/talk/json/ConversationConversionTest.kt index 7508bccbfd..ff70557654 100644 --- a/app/src/test/java/com/nextcloud/talk/json/ConversationConversionTest.kt +++ b/app/src/test/java/com/nextcloud/talk/json/ConversationConversionTest.kt @@ -14,7 +14,9 @@ import com.nextcloud.talk.data.database.model.ConversationEntity import com.nextcloud.talk.models.json.conversations.ConversationEnums import com.nextcloud.talk.models.json.conversations.RoomOverall import com.nextcloud.talk.models.json.participants.Participant -import org.junit.Assert.* +import org.junit.Assert.assertEquals +import org.junit.Assert.assertNotNull +import org.junit.Assert.assertTrue import org.junit.Test import org.junit.runner.RunWith import org.junit.runners.Parameterized From ba56ee574cd4e608344161612bb14c8363ec4640 Mon Sep 17 00:00:00 2001 From: Andy Scherzinger Date: Mon, 7 Oct 2024 15:46:22 +0200 Subject: [PATCH 148/885] ci(detekt): Bump score to turn green again Signed-off-by: Andy Scherzinger --- detekt.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/detekt.yml b/detekt.yml index 8dd64c30cf..63e05ff12b 100644 --- a/detekt.yml +++ b/detekt.yml @@ -1,7 +1,7 @@ # SPDX-FileCopyrightText: 2017-2024 Nextcloud GmbH and Nextcloud contributors # SPDX-License-Identifier: GPL-3.0-or-later build: - maxIssues: 168 + maxIssues: 178 weights: # complexity: 2 # LongParameterList: 1 From 47e9c71ea948e7b5999aa701c14a2a176f59ad1e Mon Sep 17 00:00:00 2001 From: Andy Scherzinger Date: Mon, 7 Oct 2024 16:34:59 +0200 Subject: [PATCH 149/885] style(ktlint): Fix formatting in kotlin Signed-off-by: Andy Scherzinger --- .../nextcloud/talk/models/json/conversations/Conversation.kt | 3 ++- .../com/nextcloud/talk/ui/dialog/DateTimePickerFragment.kt | 4 ++-- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/app/src/main/java/com/nextcloud/talk/models/json/conversations/Conversation.kt b/app/src/main/java/com/nextcloud/talk/models/json/conversations/Conversation.kt index af0757c857..2e48b7c81d 100644 --- a/app/src/main/java/com/nextcloud/talk/models/json/conversations/Conversation.kt +++ b/app/src/main/java/com/nextcloud/talk/models/json/conversations/Conversation.kt @@ -58,7 +58,8 @@ data class Conversation( @JsonField(name = ["actorType"]) var actorType: String = "", - var password: String? = null, // check if this can be removed.Does not belong to api response but is used internally? + // check if this can be removed. Doesn't belong to api-response but is used internally? + var password: String? = null, @JsonField(name = ["isFavorite"]) var favorite: Boolean = false, 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 747cdc09ee..fb2bc1acad 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 @@ -238,7 +238,7 @@ class DateTimePickerFragment : DialogFragment() { month, day, timePicker.hour, - timePicker.minute, + timePicker.minute ) setTimeStamp(getTimeFromTimeStamp(timestamp)) currentTimeStamp = timestamp / ONE_SEC @@ -264,7 +264,7 @@ class DateTimePickerFragment : DialogFragment() { val calendar: Calendar = Calendar.getInstance().apply { set(Calendar.YEAR, year) set(Calendar.MONTH, month) - set(Calendar.DAY_OF_YEAR,day) + set(Calendar.DAY_OF_YEAR, day) if (weekDay > -1) set(Calendar.DAY_OF_WEEK, weekDay) if (daysToAdd > 0) add(Calendar.DAY_OF_YEAR, daysToAdd) if (weekInYear != -1) set(Calendar.WEEK_OF_YEAR, weekInYear) From a0356aa51f4d2d009cef2d45319ca6f0a2a0eeba Mon Sep 17 00:00:00 2001 From: Andy Scherzinger Date: Mon, 7 Oct 2024 17:44:29 +0200 Subject: [PATCH 150/885] ci(lint): Bump lint scores Signed-off-by: Andy Scherzinger --- scripts/analysis/lint-results.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/analysis/lint-results.txt b/scripts/analysis/lint-results.txt index a82ac51714..13235d5fbe 100644 --- a/scripts/analysis/lint-results.txt +++ b/scripts/analysis/lint-results.txt @@ -1,2 +1,2 @@ DO NOT TOUCH; GENERATED BY DRONE - Lint Report: 131 errors and 86 warnings + Lint Report: 132 errors and 94 warnings From 873b33281288144e394fcedd6c162e589dd73e9f Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Mon, 7 Oct 2024 16:02:23 +0000 Subject: [PATCH 151/885] chore(deps): update actions/upload-artifact action to v4.4.1 Signed-off-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- .github/workflows/assembleFlavors.yml | 2 +- .github/workflows/unit-tests.yml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/assembleFlavors.yml b/.github/workflows/assembleFlavors.yml index fca5c0b98e..2e2d2e6fd0 100644 --- a/.github/workflows/assembleFlavors.yml +++ b/.github/workflows/assembleFlavors.yml @@ -33,7 +33,7 @@ jobs: echo "org.gradle.jvmargs=-Xmx2g -XX:MaxMetaspaceSize=512m -XX:+HeapDumpOnOutOfMemoryError" >> gradle.properties ./gradlew assemble${{ matrix.flavor }} - name: Archive apk - uses: actions/upload-artifact@50769540e7f4bd5e21e526ee35c689e35e0d6874 # v4.4.0 + uses: actions/upload-artifact@604373da6381bf24206979c74d06a550515601b9 # v4.4.1 if: ${{ always() }} with: name: Nextcloud-${{ matrix.flavor }}-APK diff --git a/.github/workflows/unit-tests.yml b/.github/workflows/unit-tests.yml index 1d573b409a..0be0bf4905 100644 --- a/.github/workflows/unit-tests.yml +++ b/.github/workflows/unit-tests.yml @@ -33,7 +33,7 @@ jobs: arguments: testGplayDebugUnit - name: Upload test artifacts if: ${{ failure() }} - uses: actions/upload-artifact@50769540e7f4bd5e21e526ee35c689e35e0d6874 # v4.4.0 + uses: actions/upload-artifact@604373da6381bf24206979c74d06a550515601b9 # v4.4.1 with: name: test-results path: app/build/reports/tests/testGplayDebugUnitTest/ From 006ec3bc1c0d17246cb7f38a2788ccf2610cfdb3 Mon Sep 17 00:00:00 2001 From: Andy Scherzinger Date: Mon, 7 Oct 2024 18:29:15 +0200 Subject: [PATCH 152/885] build.gradle(java): Lock-in jdk on 17 Signed-off-by: Andy Scherzinger --- app/build.gradle | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/app/build.gradle b/app/build.gradle index ac28217702..b12798899e 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -126,6 +126,10 @@ android { targetCompatibility JavaVersion.VERSION_17 } + kotlinOptions { + jvmTarget = '17' + } + buildFeatures { viewBinding true buildConfig = true From 38d551c399a5414c95f01a284831aefb729827ec Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Mon, 7 Oct 2024 19:29:13 +0000 Subject: [PATCH 153/885] chore(deps): update actions/checkout action to v4.2.1 Signed-off-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- .github/workflows/analysis.yml | 2 +- .github/workflows/assembleFlavors.yml | 2 +- .github/workflows/check.yml | 2 +- .github/workflows/codeql.yml | 2 +- .github/workflows/gradle-wrapper-validation.yml | 2 +- .github/workflows/qa.yml | 2 +- .github/workflows/reuse.yml | 2 +- .github/workflows/scorecard.yml | 2 +- .github/workflows/unit-tests.yml | 2 +- 9 files changed, 9 insertions(+), 9 deletions(-) diff --git a/.github/workflows/analysis.yml b/.github/workflows/analysis.yml index 22bad3af61..76212b9665 100644 --- a/.github/workflows/analysis.yml +++ b/.github/workflows/analysis.yml @@ -44,7 +44,7 @@ jobs: echo "repo=${{ github.event.pull_request.head.repo.full_name }}" } >> "$GITHUB_OUTPUT" fi - - uses: actions/checkout@d632683dd7b4114ad314bca15554477dd762a938 # v4.2.0 + - uses: actions/checkout@eef61447b9ff4aafe5dcd4e0bbf5d482be7e7871 # v4.2.1 with: repository: ${{ steps.get-vars.outputs.repo }} ref: ${{ steps.get-vars.outputs.branch }} diff --git a/.github/workflows/assembleFlavors.yml b/.github/workflows/assembleFlavors.yml index 2e2d2e6fd0..7cdd2d2afb 100644 --- a/.github/workflows/assembleFlavors.yml +++ b/.github/workflows/assembleFlavors.yml @@ -22,7 +22,7 @@ jobs: matrix: flavor: [ Generic, Gplay ] steps: - - uses: actions/checkout@d632683dd7b4114ad314bca15554477dd762a938 # v4.2.0 + - uses: actions/checkout@eef61447b9ff4aafe5dcd4e0bbf5d482be7e7871 # v4.2.1 - name: set up JDK 17 uses: actions/setup-java@b36c23c0d998641eff861008f374ee103c25ac73 # v4.4.0 with: diff --git a/.github/workflows/check.yml b/.github/workflows/check.yml index d559a38f42..0afc8c1bca 100644 --- a/.github/workflows/check.yml +++ b/.github/workflows/check.yml @@ -22,7 +22,7 @@ jobs: matrix: task: [ detekt, ktlintCheck ] steps: - - uses: actions/checkout@d632683dd7b4114ad314bca15554477dd762a938 # v4.2.0 + - uses: actions/checkout@eef61447b9ff4aafe5dcd4e0bbf5d482be7e7871 # v4.2.1 - name: Set up JDK 17 uses: actions/setup-java@b36c23c0d998641eff861008f374ee103c25ac73 # v4.4.0 with: diff --git a/.github/workflows/codeql.yml b/.github/workflows/codeql.yml index 2b65890051..0f97992dc5 100644 --- a/.github/workflows/codeql.yml +++ b/.github/workflows/codeql.yml @@ -33,7 +33,7 @@ jobs: language: [ 'java' ] steps: - name: Checkout repository - uses: actions/checkout@d632683dd7b4114ad314bca15554477dd762a938 # v4.2.0 + uses: actions/checkout@eef61447b9ff4aafe5dcd4e0bbf5d482be7e7871 # v4.2.1 - name: Set Swap Space uses: pierotofy/set-swap-space@49819abfb41bd9b44fb781159c033dba90353a7c # v1.0 with: diff --git a/.github/workflows/gradle-wrapper-validation.yml b/.github/workflows/gradle-wrapper-validation.yml index 76520536d2..bc8eb8d180 100644 --- a/.github/workflows/gradle-wrapper-validation.yml +++ b/.github/workflows/gradle-wrapper-validation.yml @@ -25,5 +25,5 @@ jobs: name: "Validation" runs-on: ubuntu-latest steps: - - uses: actions/checkout@d632683dd7b4114ad314bca15554477dd762a938 # v4.2.0 + - uses: actions/checkout@eef61447b9ff4aafe5dcd4e0bbf5d482be7e7871 # v4.2.1 - uses: gradle/wrapper-validation-action@f9c9c575b8b21b6485636a91ffecd10e558c62f6 # v3.5.0 diff --git a/.github/workflows/qa.yml b/.github/workflows/qa.yml index a4cab5e057..8373beb4b5 100644 --- a/.github/workflows/qa.yml +++ b/.github/workflows/qa.yml @@ -22,7 +22,7 @@ jobs: - name: Check if secrets are available run: echo "ok=${{ secrets.KS_PASS != '' }}" >> "$GITHUB_OUTPUT" id: check-secrets - - uses: actions/checkout@d632683dd7b4114ad314bca15554477dd762a938 # v4.2.0 + - uses: actions/checkout@eef61447b9ff4aafe5dcd4e0bbf5d482be7e7871 # v4.2.1 if: ${{ steps.check-secrets.outputs.ok == 'true' }} - name: set up JDK 17 uses: actions/setup-java@b36c23c0d998641eff861008f374ee103c25ac73 # v4.4.0 diff --git a/.github/workflows/reuse.yml b/.github/workflows/reuse.yml index b5252f9fa5..c4c63391fb 100644 --- a/.github/workflows/reuse.yml +++ b/.github/workflows/reuse.yml @@ -16,7 +16,7 @@ jobs: runs-on: ubuntu-latest steps: - name: Checkout - uses: actions/checkout@d632683dd7b4114ad314bca15554477dd762a938 # v4.2.0 + uses: actions/checkout@eef61447b9ff4aafe5dcd4e0bbf5d482be7e7871 # v4.2.1 - name: REUSE Compliance Check uses: fsfe/reuse-action@3ae3c6bdf1257ab19397fab11fd3312144692083 # v4.0.0 diff --git a/.github/workflows/scorecard.yml b/.github/workflows/scorecard.yml index 74ca98d585..15f59138df 100644 --- a/.github/workflows/scorecard.yml +++ b/.github/workflows/scorecard.yml @@ -29,7 +29,7 @@ jobs: steps: - name: "Checkout code" - uses: actions/checkout@d632683dd7b4114ad314bca15554477dd762a938 # v4.2.0 + uses: actions/checkout@eef61447b9ff4aafe5dcd4e0bbf5d482be7e7871 # v4.2.1 with: persist-credentials: false diff --git a/.github/workflows/unit-tests.yml b/.github/workflows/unit-tests.yml index 0be0bf4905..97709169b6 100644 --- a/.github/workflows/unit-tests.yml +++ b/.github/workflows/unit-tests.yml @@ -21,7 +21,7 @@ jobs: test: runs-on: ubuntu-latest steps: - - uses: actions/checkout@d632683dd7b4114ad314bca15554477dd762a938 # v4.2.0 + - uses: actions/checkout@eef61447b9ff4aafe5dcd4e0bbf5d482be7e7871 # v4.2.1 - name: Set up JDK 17 uses: actions/setup-java@b36c23c0d998641eff861008f374ee103c25ac73 # v4.4.0 with: From 3b60858e6de2163bcc5c42a6e876e3548b499bdf Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Mon, 7 Oct 2024 19:29:18 +0000 Subject: [PATCH 154/885] chore(deps): update github/codeql-action action to v3.26.12 Signed-off-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- .github/workflows/codeql.yml | 4 ++-- .github/workflows/scorecard.yml | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/codeql.yml b/.github/workflows/codeql.yml index 2b65890051..f53ce02b1d 100644 --- a/.github/workflows/codeql.yml +++ b/.github/workflows/codeql.yml @@ -39,7 +39,7 @@ jobs: with: swap-size-gb: 10 - name: Initialize CodeQL - uses: github/codeql-action/init@6db8d6351fd0be61f9ed8ebd12ccd35dcec51fea # v3.26.11 + uses: github/codeql-action/init@c36620d31ac7c881962c3d9dd939c40ec9434f2b # v3.26.12 with: languages: ${{ matrix.language }} - name: Set up JDK 17 @@ -53,4 +53,4 @@ jobs: echo "org.gradle.jvmargs=-Xmx4g -XX:MaxMetaspaceSize=512m -XX:+HeapDumpOnOutOfMemoryError" > "$HOME/.gradle/gradle.properties" ./gradlew assembleDebug - name: Perform CodeQL Analysis - uses: github/codeql-action/analyze@6db8d6351fd0be61f9ed8ebd12ccd35dcec51fea # v3.26.11 + uses: github/codeql-action/analyze@c36620d31ac7c881962c3d9dd939c40ec9434f2b # v3.26.12 diff --git a/.github/workflows/scorecard.yml b/.github/workflows/scorecard.yml index 74ca98d585..99f2a96f38 100644 --- a/.github/workflows/scorecard.yml +++ b/.github/workflows/scorecard.yml @@ -42,6 +42,6 @@ jobs: # Upload the results to GitHub's code scanning dashboard. - name: "Upload to code-scanning" - uses: github/codeql-action/upload-sarif@6db8d6351fd0be61f9ed8ebd12ccd35dcec51fea # v3.26.11 + uses: github/codeql-action/upload-sarif@c36620d31ac7c881962c3d9dd939c40ec9434f2b # v3.26.12 with: sarif_file: results.sarif From 8d599ed29975e6d4c751befe65f50c8ff46c0d9e Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Tue, 8 Oct 2024 22:11:32 +0000 Subject: [PATCH 155/885] chore(deps): update actions/upload-artifact action to v4.4.2 Signed-off-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- .github/workflows/assembleFlavors.yml | 2 +- .github/workflows/unit-tests.yml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/assembleFlavors.yml b/.github/workflows/assembleFlavors.yml index 7cdd2d2afb..2b43c35ee5 100644 --- a/.github/workflows/assembleFlavors.yml +++ b/.github/workflows/assembleFlavors.yml @@ -33,7 +33,7 @@ jobs: echo "org.gradle.jvmargs=-Xmx2g -XX:MaxMetaspaceSize=512m -XX:+HeapDumpOnOutOfMemoryError" >> gradle.properties ./gradlew assemble${{ matrix.flavor }} - name: Archive apk - uses: actions/upload-artifact@604373da6381bf24206979c74d06a550515601b9 # v4.4.1 + uses: actions/upload-artifact@84480863f228bb9747b473957fcc9e309aa96097 # v4.4.2 if: ${{ always() }} with: name: Nextcloud-${{ matrix.flavor }}-APK diff --git a/.github/workflows/unit-tests.yml b/.github/workflows/unit-tests.yml index 97709169b6..945d2c455b 100644 --- a/.github/workflows/unit-tests.yml +++ b/.github/workflows/unit-tests.yml @@ -33,7 +33,7 @@ jobs: arguments: testGplayDebugUnit - name: Upload test artifacts if: ${{ failure() }} - uses: actions/upload-artifact@604373da6381bf24206979c74d06a550515601b9 # v4.4.1 + uses: actions/upload-artifact@84480863f228bb9747b473957fcc9e309aa96097 # v4.4.2 with: name: test-results path: app/build/reports/tests/testGplayDebugUnitTest/ From 0f88b4af4554678d316ad471b7ec4c91eef5fd25 Mon Sep 17 00:00:00 2001 From: Nextcloud bot Date: Wed, 9 Oct 2024 02:52:49 +0000 Subject: [PATCH 156/885] Fix(l10n): Update translations from Transifex Signed-off-by: Nextcloud bot --- app/src/main/res/values-lt-rLT/strings.xml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/app/src/main/res/values-lt-rLT/strings.xml b/app/src/main/res/values-lt-rLT/strings.xml index f1e79eb475..2628c6101e 100644 --- a/app/src/main/res/values-lt-rLT/strings.xml +++ b/app/src/main/res/values-lt-rLT/strings.xml @@ -256,6 +256,7 @@ Rikiuoti pagal Pradžios laikas Perjungti paskyrą + Komandos Įkeliama Fotografuoti Naudotojas @@ -293,6 +294,7 @@ prieš keletą sekundžių Pasirinkta Siųsti elektroninį laišką + Siųsti be pranešimo Nustatyti Nustatyti būseną Nustatyti būsenos žinutę From 6bbf995ab7036c87746ed95706b49e6c5064b950 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Wed, 9 Oct 2024 20:24:40 +0000 Subject: [PATCH 157/885] chore(deps): update actions/upload-artifact action to v4.4.3 Signed-off-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- .github/workflows/assembleFlavors.yml | 2 +- .github/workflows/unit-tests.yml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/assembleFlavors.yml b/.github/workflows/assembleFlavors.yml index 2b43c35ee5..324133c67f 100644 --- a/.github/workflows/assembleFlavors.yml +++ b/.github/workflows/assembleFlavors.yml @@ -33,7 +33,7 @@ jobs: echo "org.gradle.jvmargs=-Xmx2g -XX:MaxMetaspaceSize=512m -XX:+HeapDumpOnOutOfMemoryError" >> gradle.properties ./gradlew assemble${{ matrix.flavor }} - name: Archive apk - uses: actions/upload-artifact@84480863f228bb9747b473957fcc9e309aa96097 # v4.4.2 + uses: actions/upload-artifact@b4b15b8c7c6ac21ea08fcf65892d2ee8f75cf882 # v4.4.3 if: ${{ always() }} with: name: Nextcloud-${{ matrix.flavor }}-APK diff --git a/.github/workflows/unit-tests.yml b/.github/workflows/unit-tests.yml index 945d2c455b..3333144489 100644 --- a/.github/workflows/unit-tests.yml +++ b/.github/workflows/unit-tests.yml @@ -33,7 +33,7 @@ jobs: arguments: testGplayDebugUnit - name: Upload test artifacts if: ${{ failure() }} - uses: actions/upload-artifact@84480863f228bb9747b473957fcc9e309aa96097 # v4.4.2 + uses: actions/upload-artifact@b4b15b8c7c6ac21ea08fcf65892d2ee8f75cf882 # v4.4.3 with: name: test-results path: app/build/reports/tests/testGplayDebugUnitTest/ From fa8272f5958407e7d58be5938a692fdfa5728599 Mon Sep 17 00:00:00 2001 From: Nextcloud bot Date: Thu, 10 Oct 2024 02:53:21 +0000 Subject: [PATCH 158/885] Fix(l10n): Update translations from Transifex Signed-off-by: Nextcloud bot --- app/src/main/res/values-cs-rCZ/strings.xml | 1 + 1 file changed, 1 insertion(+) diff --git a/app/src/main/res/values-cs-rCZ/strings.xml b/app/src/main/res/values-cs-rCZ/strings.xml index 9b411fb0d4..0dbaad76c5 100644 --- a/app/src/main/res/values-cs-rCZ/strings.xml +++ b/app/src/main/res/values-cs-rCZ/strings.xml @@ -443,6 +443,7 @@ Řadit podle Čas zahájení Přepnout účet + Týmy Vyberte soubory Odeslat tyto soubory k %1$s? Odeslat tento soubor k %1$s? From 6fd2ab2c548bc7d128300f05b62898e12ce08024 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Thu, 10 Oct 2024 11:08:32 +0000 Subject: [PATCH 159/885] fix(deps): update kotlin monorepo to v2.0.21 Signed-off-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- build.gradle | 2 +- gradle/verification-metadata.xml | 30 ++++++++++++++++++++++++++++++ 2 files changed, 31 insertions(+), 1 deletion(-) diff --git a/build.gradle b/build.gradle index 070195cb9c..88cd1b8ead 100644 --- a/build.gradle +++ b/build.gradle @@ -11,7 +11,7 @@ buildscript { ext { - kotlinVersion = '2.0.20' + kotlinVersion = '2.0.21' hilt_version = '2.44' } diff --git a/gradle/verification-metadata.xml b/gradle/verification-metadata.xml index 01bacec009..8d4b8ab8e6 100644 --- a/gradle/verification-metadata.xml +++ b/gradle/verification-metadata.xml @@ -6134,6 +6134,11 @@ + + + + + @@ -6164,6 +6169,11 @@ + + + + + @@ -6194,6 +6204,11 @@ + + + + + @@ -6224,6 +6239,11 @@ + + + + + @@ -6254,6 +6274,11 @@ + + + + + @@ -6269,6 +6294,11 @@ + + + + + From 72200ba23698d375057c9339a445ce03813f86fb Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Thu, 10 Oct 2024 17:36:35 +0000 Subject: [PATCH 160/885] chore(deps): update plugin org.jetbrains.kotlin.plugin.compose to v2.0.21 Signed-off-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- app/build.gradle | 2 +- gradle/verification-metadata.xml | 5 +++++ 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/app/build.gradle b/app/build.gradle index b12798899e..7adebe8565 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -13,7 +13,7 @@ import com.github.spotbugs.snom.Effort import com.github.spotbugs.snom.SpotBugsTask plugins { - id "org.jetbrains.kotlin.plugin.compose" version "2.0.20" + id "org.jetbrains.kotlin.plugin.compose" version "2.0.21" id "org.jetbrains.kotlin.kapt" id 'com.google.devtools.ksp' version '2.0.20-1.0.25' } diff --git a/gradle/verification-metadata.xml b/gradle/verification-metadata.xml index 8d4b8ab8e6..0e53bd4b62 100644 --- a/gradle/verification-metadata.xml +++ b/gradle/verification-metadata.xml @@ -6375,6 +6375,11 @@ + + + + + From 26ba3a172503e262696de2a60d676864fb0b1124 Mon Sep 17 00:00:00 2001 From: Nextcloud bot Date: Fri, 11 Oct 2024 03:00:24 +0000 Subject: [PATCH 161/885] Fix(l10n): Update translations from Transifex Signed-off-by: Nextcloud bot --- app/src/main/res/values-ar/strings.xml | 10 +++++----- app/src/main/res/values-lt-rLT/strings.xml | 1 + 2 files changed, 6 insertions(+), 5 deletions(-) diff --git a/app/src/main/res/values-ar/strings.xml b/app/src/main/res/values-ar/strings.xml index f894fe7aa4..433fd8f474 100644 --- a/app/src/main/res/values-ar/strings.xml +++ b/app/src/main/res/values-ar/strings.xml @@ -245,7 +245,7 @@ لا توجد دعوات معلقة لديك دعوات معلقة العودة - إذن الوصول إلى الملف لازمٌ + إذن الوصول إلى الملف مطلوب فرز المحادثات المستخدم يتابع رابط عام أنت: %1$s @@ -289,7 +289,7 @@ هذا الاجتماع سيبدأ قريباً أنت حاليا في انتظار الاستقبال موقعك الحالي - إذن الموقع لازمٌ + إذن الموقع مطلوب الموقع غير معلوم مقفل أنقُر لفكّ القُفْل @@ -471,7 +471,7 @@ تحذير يمكن إعادة تفويض الحساب الجاري فقط شارك جهة اتصال - إذن قراءة جهات الاتصال لازمٌ + إذن قراءة جهات الاتصال مطلوب شارك الموقع الحالي رابط المشاركة مشاركة الموقع @@ -493,7 +493,7 @@ إرسال هذا الملف إلى %1$s؟ عذرًا، فشل الرفع فشلت عملية رفع %1$s - إخفاق + فشل مُشارَكةٌ مِن %1$s إرفَع من الجهاز الرَّفْعُ جارٍ … @@ -505,7 +505,7 @@ مرئيّ تسجيل محادثة Talk من %1$s (%2$s) أُنقُر مُطوّلاً للتسجيل، ثم أفلِت للإرسال. - الإذن لتسجيل الصوت لازمٌ + الإذن لتسجيل الصوت مطلوب « إسحب للإلغاء ويبنار نعم diff --git a/app/src/main/res/values-lt-rLT/strings.xml b/app/src/main/res/values-lt-rLT/strings.xml index 2628c6101e..be8ac2f966 100644 --- a/app/src/main/res/values-lt-rLT/strings.xml +++ b/app/src/main/res/values-lt-rLT/strings.xml @@ -318,6 +318,7 @@ Šiandiena Rytoj Verskite + Aptikti kalbą Įrenginio nustatymai Nepavyko aptikti kalbos Nuo From a399d472aa08f29a7c882bb86f88a4035d73d1af Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Fri, 11 Oct 2024 08:13:00 +0000 Subject: [PATCH 162/885] chore(deps): update plugin com.google.devtools.ksp to v2.0.21-1.0.25 Signed-off-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- app/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/build.gradle b/app/build.gradle index 7adebe8565..3f53da8cde 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -15,7 +15,7 @@ import com.github.spotbugs.snom.SpotBugsTask plugins { id "org.jetbrains.kotlin.plugin.compose" version "2.0.21" id "org.jetbrains.kotlin.kapt" - id 'com.google.devtools.ksp' version '2.0.20-1.0.25' + id 'com.google.devtools.ksp' version '2.0.21-1.0.25' } apply plugin: 'com.android.application' From 8eeca17d86192476f0221a1e107247246bafc0d1 Mon Sep 17 00:00:00 2001 From: rapterjet2004 Date: Fri, 11 Oct 2024 10:51:37 -0500 Subject: [PATCH 163/885] WIP Signed-off-by: rapterjet2004 --- .../java/com/nextcloud/talk/api/NcApi.java | 8 +++++ .../ConversationInfoActivity.kt | 20 ++++++++++++ .../viewmodel/ConversationInfoViewModel.kt | 12 ++++++- .../talk/models/domain/ConversationModel.kt | 4 ++- .../models/json/conversations/Conversation.kt | 5 ++- .../conversations/ConversationsRepository.kt | 5 +++ .../ConversationsRepositoryImpl.kt | 9 ++++++ .../main/res/drawable/outline_archive_24.xml | 18 +++++++++++ .../res/layout/activity_conversation_info.xml | 31 +++++++++++++++++++ app/src/main/res/values/strings.xml | 2 ++ 10 files changed, 111 insertions(+), 3 deletions(-) create mode 100644 app/src/main/res/drawable/outline_archive_24.xml diff --git a/app/src/main/java/com/nextcloud/talk/api/NcApi.java b/app/src/main/java/com/nextcloud/talk/api/NcApi.java index f0957ef4d3..c2c8c63864 100644 --- a/app/src/main/java/com/nextcloud/talk/api/NcApi.java +++ b/app/src/main/java/com/nextcloud/talk/api/NcApi.java @@ -727,4 +727,12 @@ Observable banActor(@Header("Authorization") String authorization, @DELETE Observable unbanActor(@Header("Authorization") String authorization, @Url String url); + + @POST + Observable archiveConversation(@Header("Authorization") String authorization, + @Url String url); + + @DELETE + Observable unarchiveConversation(@Header("Authorization") String authorization, + @Url String url); } \ No newline at end of file diff --git a/app/src/main/java/com/nextcloud/talk/conversationinfo/ConversationInfoActivity.kt b/app/src/main/java/com/nextcloud/talk/conversationinfo/ConversationInfoActivity.kt index 2005ebdffa..e9bf60b64d 100644 --- a/app/src/main/java/com/nextcloud/talk/conversationinfo/ConversationInfoActivity.kt +++ b/app/src/main/java/com/nextcloud/talk/conversationinfo/ConversationInfoActivity.kt @@ -179,17 +179,36 @@ class ConversationInfoActivity : databaseStorageModule = DatabaseStorageModule(conversationUser, conversationToken) } + if (!spreedCapabilities.features!!.contains(ARCHIVED_CONVERSATIONS)) { + binding.archiveConversationBtn.visibility = GONE + } + binding.deleteConversationAction.setOnClickListener { showDeleteConversationDialog() } binding.leaveConversationAction.setOnClickListener { leaveConversation() } binding.clearConversationHistory.setOnClickListener { showClearHistoryDialog() } binding.addParticipantsAction.setOnClickListener { addParticipants() } binding.listBansButton.setOnClickListener { listBans() } + binding.archiveConversationBtn.setOnClickListener { + if (conversation!!.isArchived) { + viewModel.unarchiveConversation(conversationUser, conversationToken) + } else { + viewModel.archiveConversation(conversationUser, conversationToken) + } + } viewModel.getRoom(conversationUser, conversationToken) themeTextViews() themeSwitchPreferences() + if (conversation!!.isArchived) { + binding.archiveConversationIcon.setImageDrawable(resources.getDrawable(R.drawable.ic_eye)) + binding.archiveConversationText.text = resources.getString(R.string.unarchive_conversation) + } else { + binding.archiveConversationIcon.setImageDrawable(resources.getDrawable(R.drawable.outline_archive_24)) + binding.archiveConversationText.text = resources.getString(R.string.archive_conversation) + } + binding.addParticipantsAction.visibility = GONE binding.progressBar.let { viewThemeUtils.platform.colorCircularProgressBar(it, ColorRole.PRIMARY) } @@ -1445,6 +1464,7 @@ class ConversationInfoActivity : private const val DEMOTE_OR_PROMOTE = 1 private const val REMOVE_FROM_CONVERSATION = 2 private const val BAN_FROM_CONVERSATION = 3 + private const val ARCHIVED_CONVERSATIONS = "archived-conversations" } /** diff --git a/app/src/main/java/com/nextcloud/talk/conversationinfo/viewmodel/ConversationInfoViewModel.kt b/app/src/main/java/com/nextcloud/talk/conversationinfo/viewmodel/ConversationInfoViewModel.kt index 3a145beebd..afed00c8a4 100644 --- a/app/src/main/java/com/nextcloud/talk/conversationinfo/viewmodel/ConversationInfoViewModel.kt +++ b/app/src/main/java/com/nextcloud/talk/conversationinfo/viewmodel/ConversationInfoViewModel.kt @@ -18,6 +18,7 @@ import com.nextcloud.talk.models.domain.ConversationModel import com.nextcloud.talk.models.json.capabilities.SpreedCapability import com.nextcloud.talk.models.json.generic.GenericOverall import com.nextcloud.talk.models.json.participants.TalkBan +import com.nextcloud.talk.repositories.conversations.ConversationsRepository import com.nextcloud.talk.utils.ApiUtils import io.reactivex.Observer import io.reactivex.android.schedulers.AndroidSchedulers @@ -26,7 +27,8 @@ import io.reactivex.schedulers.Schedulers import javax.inject.Inject class ConversationInfoViewModel @Inject constructor( - private val chatNetworkDataSource: ChatNetworkDataSource + private val chatNetworkDataSource: ChatNetworkDataSource, + private val conversationsRepository: ConversationsRepository ) : ViewModel() { object LifeCycleObserver : DefaultLifecycleObserver { @@ -200,6 +202,14 @@ class ConversationInfoViewModel @Inject constructor( }) } + fun archiveConversation(user: User, token: String) { + // TODO + } + + fun unarchiveConversation(user: User, token: String) { + // TODO + } + inner class GetRoomObserver : Observer { override fun onSubscribe(d: Disposable) { // unused atm diff --git a/app/src/main/java/com/nextcloud/talk/models/domain/ConversationModel.kt b/app/src/main/java/com/nextcloud/talk/models/domain/ConversationModel.kt index d653b80986..85e3abed88 100644 --- a/app/src/main/java/com/nextcloud/talk/models/domain/ConversationModel.kt +++ b/app/src/main/java/com/nextcloud/talk/models/domain/ConversationModel.kt @@ -59,6 +59,7 @@ class ConversationModel( var recordingConsentRequired: Int = 0, var remoteServer: String? = null, var remoteToken: String? = null, + var isArchived: Boolean = false, // attributes that don't come from API. This should be changed?! var password: String? = null @@ -120,7 +121,8 @@ class ConversationModel( callStartTime = conversation.callStartTime, recordingConsentRequired = conversation.recordingConsentRequired, remoteServer = conversation.remoteServer, - remoteToken = conversation.remoteToken + remoteToken = conversation.remoteToken, + isArchived = conversation.isArchived ) } } diff --git a/app/src/main/java/com/nextcloud/talk/models/json/conversations/Conversation.kt b/app/src/main/java/com/nextcloud/talk/models/json/conversations/Conversation.kt index 2e48b7c81d..f50cb29a54 100644 --- a/app/src/main/java/com/nextcloud/talk/models/json/conversations/Conversation.kt +++ b/app/src/main/java/com/nextcloud/talk/models/json/conversations/Conversation.kt @@ -159,5 +159,8 @@ data class Conversation( var remoteServer: String? = "", @JsonField(name = ["remoteToken"]) - var remoteToken: String? = "" + var remoteToken: String? = "", + + @JsonField(name = ["isArchived"]) + var isArchived: Boolean ) : Parcelable diff --git a/app/src/main/java/com/nextcloud/talk/repositories/conversations/ConversationsRepository.kt b/app/src/main/java/com/nextcloud/talk/repositories/conversations/ConversationsRepository.kt index 80cf47990e..04e4980530 100644 --- a/app/src/main/java/com/nextcloud/talk/repositories/conversations/ConversationsRepository.kt +++ b/app/src/main/java/com/nextcloud/talk/repositories/conversations/ConversationsRepository.kt @@ -7,6 +7,7 @@ */ package com.nextcloud.talk.repositories.conversations +import com.nextcloud.talk.models.json.generic.GenericOverall import io.reactivex.Observable interface ConversationsRepository { @@ -29,4 +30,8 @@ interface ConversationsRepository { val successful: Boolean ) fun resendInvitations(token: String): Observable + + fun archiveConversation(credentials: String, url: String): Observable + + fun unarchiveConversation(credentials: String, url: String): Observable } diff --git a/app/src/main/java/com/nextcloud/talk/repositories/conversations/ConversationsRepositoryImpl.kt b/app/src/main/java/com/nextcloud/talk/repositories/conversations/ConversationsRepositoryImpl.kt index 4b89720964..e4f8ece5bd 100644 --- a/app/src/main/java/com/nextcloud/talk/repositories/conversations/ConversationsRepositoryImpl.kt +++ b/app/src/main/java/com/nextcloud/talk/repositories/conversations/ConversationsRepositoryImpl.kt @@ -11,6 +11,7 @@ import com.bluelinelabs.logansquare.LoganSquare import com.nextcloud.talk.api.NcApi import com.nextcloud.talk.data.user.model.User import com.nextcloud.talk.models.json.conversations.password.PasswordOverall +import com.nextcloud.talk.models.json.generic.GenericOverall import com.nextcloud.talk.repositories.conversations.ConversationsRepository.AllowGuestsResult import com.nextcloud.talk.repositories.conversations.ConversationsRepository.PasswordResult import com.nextcloud.talk.repositories.conversations.ConversationsRepository.ResendInvitationsResult @@ -89,6 +90,14 @@ class ConversationsRepositoryImpl( } } + override fun archiveConversation(credentials: String, url: String): Observable { + return api.archiveConversation(credentials, url) + } + + override fun unarchiveConversation(credentials: String, url: String): Observable { + return api.unarchiveConversation(credentials, url) + } + private fun apiVersion(): Int { return ApiUtils.getConversationApiVersion(user, intArrayOf(ApiUtils.API_V4)) } diff --git a/app/src/main/res/drawable/outline_archive_24.xml b/app/src/main/res/drawable/outline_archive_24.xml new file mode 100644 index 0000000000..b94ba5dd94 --- /dev/null +++ b/app/src/main/res/drawable/outline_archive_24.xml @@ -0,0 +1,18 @@ + + + + + + diff --git a/app/src/main/res/layout/activity_conversation_info.xml b/app/src/main/res/layout/activity_conversation_info.xml index 63738ce3d8..8168c85312 100644 --- a/app/src/main/res/layout/activity_conversation_info.xml +++ b/app/src/main/res/layout/activity_conversation_info.xml @@ -383,6 +383,37 @@ + + + + + + + + + Show ban reason Error occurred when unbanning participant Connection lost + Archive Conversation + Unarchive Conversation From e23b62f4b07104e4d5c8e526f6fd5c7a5f5b84ea Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Sat, 12 Oct 2024 02:03:28 +0000 Subject: [PATCH 164/885] chore(deps): update ubuntu:noble docker digest to ee6860a Signed-off-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- .devcontainer/Dockerfile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.devcontainer/Dockerfile b/.devcontainer/Dockerfile index e5a364107f..8a1c1062c4 100644 --- a/.devcontainer/Dockerfile +++ b/.devcontainer/Dockerfile @@ -1,4 +1,4 @@ -FROM ubuntu:noble@sha256:b359f1067efa76f37863778f7b6d0e8d911e3ee8efa807ad01fbf5dc1ef9006b +FROM ubuntu:noble@sha256:ee6860ab126bb8291052401af00acad20d69c16e46579a47dac1c57cd4688446 ARG DEBIAN_FRONTEND=noninteractive ENV ANDROID_HOME=/usr/lib/android-sdk From 37c0854d6ee9abc4258d087c2cf7ecaef673544d Mon Sep 17 00:00:00 2001 From: Nextcloud bot Date: Sat, 12 Oct 2024 02:50:35 +0000 Subject: [PATCH 165/885] Fix(l10n): Update translations from Transifex Signed-off-by: Nextcloud bot --- app/src/main/res/values-ar/strings.xml | 4 +-- app/src/main/res/values-cs-rCZ/strings.xml | 29 ++++++++++++++++++++++ app/src/main/res/values-zh-rHK/strings.xml | 1 + 3 files changed, 32 insertions(+), 2 deletions(-) diff --git a/app/src/main/res/values-ar/strings.xml b/app/src/main/res/values-ar/strings.xml index 433fd8f474..23b598dc67 100644 --- a/app/src/main/res/values-ar/strings.xml +++ b/app/src/main/res/values-ar/strings.xml @@ -232,7 +232,7 @@ البريد الإلكتروني 8 ساعات 4 أسابيع - موقوف + معطل 1 يوم 1 ساعة 1 أسبوع @@ -357,7 +357,7 @@ في وضعية تعطل المايكرفون، علق على الزر & لاستخدام اضغط للتحدث إنعاش ذكرني لاحقا - الصَّوت القصِي remote موقوف + الصوت البعيد معطل إزالتها مِن المفضلة حذف المجموعة group و الأعضاء حذف مشارك diff --git a/app/src/main/res/values-cs-rCZ/strings.xml b/app/src/main/res/values-cs-rCZ/strings.xml index 0dbaad76c5..410f0a5cc5 100644 --- a/app/src/main/res/values-cs-rCZ/strings.xml +++ b/app/src/main/res/values-cs-rCZ/strings.xml @@ -1,6 +1,7 @@ Upravit + Přidat do Poznámek Konverzace %1$s přidána do oblíbených Hledat v %s Hlasový hovor @@ -11,6 +12,10 @@ Drátová náhlavní souprava Profilový obrázek Pryč + Tlačítko zpět + Vyloučit + Vyloučit účastníka + Seznam vyloučení Kalendář Pokročilé předvolby pro hovor Hovor trvá už hodinu. @@ -20,7 +25,9 @@ Vyčistit stavovou zprávu Vyčistit stavovou zprávu po uplynutí Zavřít + Ikona zavření Spojení navázáno + Spojení ztraceno Zamknout nahrávku pro nepřetržité nahrávání hlasové zprávy Konverzace Vytvořit konverzaci @@ -32,6 +39,7 @@ Nerušit Nečistit Upravit + Upravit ikon zprávy Backspace Nedávné Šifrované @@ -42,6 +50,7 @@ %1$s (%2$d) 4 hodiny (upraveno) + Interní poznámka Není vidět Jazyky se nepodařilo získat Získání se nezdařil @@ -111,6 +120,8 @@ Vaše nastavení SSL zabránilo připojení Změnit certifikát sloužící pro ověřování se Změnit heslo + Vyčistit tlačítko úprav + Vyčistit zprávu úpravy Smazat všechny zprávy Všechny zprávy byly vymazány Opravdu chcete všechny zprávy v této konverzaci smazat? @@ -156,6 +167,7 @@ Server Je nainstalovaná aplikace upozorňování na serveru? Uživatel + Je zapnutý stav uživatele? Verze systému Android Aplikace Název aplikace @@ -163,8 +175,15 @@ Verze aplikace Nastavení správy napájení Zařízení + Otevřít kontrolní seznam řešení problémů Otevřít diagnostickou obrazovku Otevřít dontkillmyapp.com + push token Firebase + Služby Google Play + Služby Google Play jsou k dispozici + Poslední push registrace na push proxy + Zatím nezregistrováno u push proxy + Poslední push registrace na serveru Ještě nezaregistrováno na serveru Metainformace Vytváření výkazu o systému @@ -237,6 +256,8 @@ Pozvánky byly znovu odeslány. Sdílet odkaz na konverzaci Zadejte zprávu… + Úspora energie z akumulátoru není ignorována. Pokud chcete, aby upozorňování na pozadí fungovalo správně, mělo by toto být změněno! Klikněte na OK a vyberte „Všechny aplikace“ -> %1$s -> neoptimalizovat + Ignorovat úsporu energie z akumulátoru Důležitá konverzace Upozornění v této konverzaci budou ignorovat režim Nerušit Pozvání @@ -288,6 +309,8 @@ Nahrané Upozorňovat ohledně postupu při nahrávání Nastavení upozorňování + Oprávnění k upozorňování a nastavení ohledně spotřeby energie z akumulátoru jsou nastavené správně pro dostávání upozornění. Pokud i tak máte problémy s dostáváním notifikací, zkontrolujte zda jsou zapnuté kanály upozorňování na hovory a zprávy. Další pomoc je možné nalézt na DontKillMyApp.com nebo v kontrolním seznamu řešení problémů. Pokud toto nepomůže, přejděte na diagnostickou obrazovku a zašlete hlášení chyby. + Řešení problémů s upozorňováním Vždy upozorňovat Upozornit, když vás někdo zmíní Nikdy neupozorňovat @@ -323,6 +346,8 @@ Odebrat z oblíbených Odebrat skupinu a její členy Odebrat účastníka + Odebrat heslo + Odebrat tým a uživatele Přejmenovat konverzaci Přejmenovat Odpovědět @@ -386,6 +411,9 @@ Aplikace Talk není na serveru, vůči kterému jste se pokusili ověřit, vůbec nainstalována Zvuky upozornění Upozornění + Upozorňování jsou odmítnuta + Upozorňování jsou odmítána. Povolte je v nastavení systému Android + Upozorňování jsou udělena Zprávy Najít kontakty se stejným telefonním číslem a přidat zkratku Talk do systémové aplikace pro kontakty Chyba 429 – příliš mnoho požadavků @@ -443,6 +471,7 @@ Řadit podle Čas zahájení Přepnout účet + Tým Týmy Vyberte soubory Odeslat tyto soubory k %1$s? diff --git a/app/src/main/res/values-zh-rHK/strings.xml b/app/src/main/res/values-zh-rHK/strings.xml index ea1f700b6f..1ba86de8b5 100644 --- a/app/src/main/res/values-zh-rHK/strings.xml +++ b/app/src/main/res/values-zh-rHK/strings.xml @@ -361,6 +361,7 @@ 取消我的最愛 移除群組及組員 移除參與者 + 移除密碼 移除團隊和成員 重新命名對話 重新命名 From 691cc39be28159b8d024505503fac5126c1a57cc Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Sat, 12 Oct 2024 11:07:16 +0000 Subject: [PATCH 166/885] chore(deps): update ubuntu:noble docker digest to ab64a83 Signed-off-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- .devcontainer/Dockerfile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.devcontainer/Dockerfile b/.devcontainer/Dockerfile index 8a1c1062c4..d603462dc9 100644 --- a/.devcontainer/Dockerfile +++ b/.devcontainer/Dockerfile @@ -1,4 +1,4 @@ -FROM ubuntu:noble@sha256:ee6860ab126bb8291052401af00acad20d69c16e46579a47dac1c57cd4688446 +FROM ubuntu:noble@sha256:ab64a8382e935382638764d8719362bb50ee418d944c1f3d26e0c99fae49a345 ARG DEBIAN_FRONTEND=noninteractive ENV ANDROID_HOME=/usr/lib/android-sdk From d8089beeb2f32168545802a2764e555114e6672b Mon Sep 17 00:00:00 2001 From: Nextcloud bot Date: Sun, 13 Oct 2024 02:57:15 +0000 Subject: [PATCH 167/885] Fix(l10n): Update translations from Transifex Signed-off-by: Nextcloud bot --- app/src/main/res/values-ar/strings.xml | 6 +++--- app/src/main/res/values-cs-rCZ/strings.xml | 8 ++++++++ app/src/main/res/values-gl/strings.xml | 2 +- 3 files changed, 12 insertions(+), 4 deletions(-) diff --git a/app/src/main/res/values-ar/strings.xml b/app/src/main/res/values-ar/strings.xml index 23b598dc67..e90ff67528 100644 --- a/app/src/main/res/values-ar/strings.xml +++ b/app/src/main/res/values-ar/strings.xml @@ -55,7 +55,7 @@ %1$s (%2$d) 4 ساعات تعذّر جلب الدعوات المعلقة - (مُعدّلة) + (معدّلة) ملاحظة داخلية غير مرئي أيقونة الانضمام لمحادثة مفتوحة @@ -139,7 +139,7 @@ و إنسَخ تمّ النسخ إلى الحافظة - أنشِيء + إنشاء مُعطّل تجاهل حدث خطأ ما! @@ -158,7 +158,7 @@ إنضم لمحادثةٍ او ابدأ محادثةً جديدةً رحّب بالأصدقاء و الزملاء! أنسخ - أنشِيءْ محادثة جديدة + إنشاء محادثة جديدة صَوّت، رجاءً اليوم أمس diff --git a/app/src/main/res/values-cs-rCZ/strings.xml b/app/src/main/res/values-cs-rCZ/strings.xml index 410f0a5cc5..d2f5a14046 100644 --- a/app/src/main/res/values-cs-rCZ/strings.xml +++ b/app/src/main/res/values-cs-rCZ/strings.xml @@ -29,6 +29,7 @@ Spojení navázáno Spojení ztraceno Zamknout nahrávku pro nepřetržité nahrávání hlasové zprávy + Konverzace je pouze pro čtení Konverzace Vytvořit konverzaci Nahlásit problém @@ -44,14 +45,17 @@ Nedávné Šifrované Došlo k problému při načítání vašich chatů + Došlo k chybě při rušení vyloučení účastníka Nepodařilo se uložit %1$s složka Načítání… %1$s (%2$d) 4 hodiny + Nepodařilo se získat čekající pozvání (upraveno) Interní poznámka Není vidět + Ikona přidání se do otevřené konverzace Jazyky se nepodařilo získat Získání se nezdařil Později dnes @@ -69,6 +73,7 @@ Největší jako první Nejmenší jako první Zprávu jste smazali + Upraveno %1$s Klepnutím anketu otevřete Nic nenalezeno Hledejte psaním… @@ -120,6 +125,7 @@ Vaše nastavení SSL zabránilo připojení Změnit certifikát sloužící pro ověřování se Změnit heslo + Zkontrolujte své připojení k Internetu Vyčistit tlačítko úprav Vyčistit zprávu úpravy Smazat všechny zprávy @@ -178,6 +184,8 @@ Otevřít kontrolní seznam řešení problémů Otevřít diagnostickou obrazovku Otevřít dontkillmyapp.com + Stažení nejnovějšího push tokenu firebase + Vytvoření nejnovějšího push tokenu firebase push token Firebase Služby Google Play Služby Google Play jsou k dispozici diff --git a/app/src/main/res/values-gl/strings.xml b/app/src/main/res/values-gl/strings.xml index 4ad114c5eb..0f74407907 100644 --- a/app/src/main/res/values-gl/strings.xml +++ b/app/src/main/res/values-gl/strings.xml @@ -414,7 +414,7 @@ Definir un novo contrasinal Definir o contrasinal Axustes - Actualizouse a súa conta xa existente no canto de crear unha nova + Actualizouse a súa conta xa existente en troques de crear unha nova Avanzado Aparencia Chamadas From 9e7555a91145fac2375f3c179acab38b377bc4a3 Mon Sep 17 00:00:00 2001 From: Nextcloud bot Date: Mon, 14 Oct 2024 02:49:49 +0000 Subject: [PATCH 168/885] Fix(l10n): Update translations from Transifex Signed-off-by: Nextcloud bot --- app/src/main/res/values-ar/strings.xml | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/app/src/main/res/values-ar/strings.xml b/app/src/main/res/values-ar/strings.xml index e90ff67528..07db85f76e 100644 --- a/app/src/main/res/values-ar/strings.xml +++ b/app/src/main/res/values-ar/strings.xml @@ -103,7 +103,7 @@ تغيير مَخرِج الصوت تبديل الكاميرا إنهاء المكالمة - تبديل لاقط الصوت microphone + تبديل لاقط الصوت فتح وضعية \"صورة في صورة\" PIP تبديل إلى الفيديو الذاتي واردة @@ -305,7 +305,7 @@ مشرِف عدم الانضمام محادثة جديدة - الرؤية Visibility + الرؤية إشاراتٌ غير مقروءة رسائل غير مقروءة %1$sغير متاحٍ (غير مُنصّب أو مُقيّد من قبل المُشرف) @@ -368,7 +368,7 @@ رد ردّ على الخاص حفظ - تمّ الحفط بنجاحٍ + تمّ الحفط بنجاح 30 ثانية 5 دقائق 1 دقيقة @@ -563,7 +563,7 @@ خاص قم بالمزامنة مع الخوادم الموثوقة ودفتر العناوين العالمية والعامة منشورة - تبديل النطاق Scope toggle + تبديل النطاق تغيير مستوى الخصوصية لـ%1$s مرِّر للأسفل أيقونة البحث @@ -594,8 +594,8 @@ لا يُمكنُك إجراءُ مكالمة بدأت مكالمةً رسالة الحالة - تبديل إلى غرفة جانبية breakout room - تبديل إلى الغرفة الرئيسية main room + تبديل إلى غرفة جانبية + تبديل إلى الغرفة الرئيسية خُذ صورة خطأ في أخذ الصورة لا يمكن أخذ صورة من دون تصريح From c9d3aebdc7fa63fa941aa7ccd12a571bf9679f24 Mon Sep 17 00:00:00 2001 From: Nextcloud Android Bot Date: Mon, 14 Oct 2024 03:13:52 +0000 Subject: [PATCH 169/885] Weekly 20.1.0 Alpha 08 --- app/build.gradle | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/app/build.gradle b/app/build.gradle index 3f53da8cde..2c9e34a63b 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -40,8 +40,8 @@ android { // mayor.minor.hotfix.increment (for increment: 01-50=Alpha / 51-89=RC / 90-99=stable) // xx .xxx .xx .xx - versionCode 200010007 - versionName "20.1.0 Alpha 07" + versionCode 200010008 + versionName "20.1.0 Alpha 08" flavorDimensions "default" renderscriptTargetApi 19 From 94f33c13bc8ffd56a6fdc944ff4a3cbf4de22097 Mon Sep 17 00:00:00 2001 From: rapterjet2004 Date: Mon, 14 Oct 2024 09:00:24 -0500 Subject: [PATCH 170/885] WIP got archived working - still have some todos Signed-off-by: rapterjet2004 --- .../11.json | 12 +++-- .../ConversationInfoActivity.kt | 39 ++++++++-------- .../viewmodel/ConversationInfoViewModel.kt | 46 ++++++++++++++++++- .../ConversationsListActivity.kt | 16 ++++++- .../database/mappers/ConversationMapUtils.kt | 9 ++-- .../data/database/model/ConversationEntity.kt | 3 +- .../talk/models/domain/ConversationModel.kt | 4 +- .../models/json/conversations/Conversation.kt | 2 +- .../ui/dialog/FilterConversationFragment.kt | 12 ++++- .../java/com/nextcloud/talk/utils/ApiUtils.kt | 4 ++ .../res/layout/dialog_filter_conversation.xml | 7 +++ app/src/main/res/values/strings.xml | 1 + 12 files changed, 121 insertions(+), 34 deletions(-) diff --git a/app/schemas/com.nextcloud.talk.data.source.local.TalkDatabase/11.json b/app/schemas/com.nextcloud.talk.data.source.local.TalkDatabase/11.json index 6fa34ab2ef..a655cd9f79 100644 --- a/app/schemas/com.nextcloud.talk.data.source.local.TalkDatabase/11.json +++ b/app/schemas/com.nextcloud.talk.data.source.local.TalkDatabase/11.json @@ -2,7 +2,7 @@ "formatVersion": 1, "database": { "version": 11, - "identityHash": "bc802cadfdef41d3eb94ffbb0729eb89", + "identityHash": "7edb537b6987d0de6586a6760c970958", "entities": [ { "tableName": "User", @@ -138,7 +138,7 @@ }, { "tableName": "Conversations", - "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`internalId` TEXT NOT NULL, `accountId` INTEGER NOT NULL, `token` TEXT NOT NULL, `displayName` TEXT NOT NULL, `actorId` TEXT NOT NULL, `actorType` TEXT NOT NULL, `avatarVersion` TEXT NOT NULL, `callFlag` INTEGER NOT NULL, `callRecording` INTEGER NOT NULL, `callStartTime` INTEGER NOT NULL, `canDeleteConversation` INTEGER NOT NULL, `canLeaveConversation` INTEGER NOT NULL, `canStartCall` INTEGER NOT NULL, `description` TEXT NOT NULL, `hasCall` INTEGER NOT NULL, `hasPassword` INTEGER NOT NULL, `isCustomAvatar` INTEGER NOT NULL, `isFavorite` INTEGER NOT NULL, `lastActivity` INTEGER NOT NULL, `lastCommonReadMessage` INTEGER NOT NULL, `lastMessage` TEXT, `lastPing` INTEGER NOT NULL, `lastReadMessage` INTEGER NOT NULL, `lobbyState` TEXT NOT NULL, `lobbyTimer` INTEGER NOT NULL, `messageExpiration` INTEGER NOT NULL, `name` TEXT NOT NULL, `notificationCalls` INTEGER NOT NULL, `notificationLevel` TEXT NOT NULL, `objectType` TEXT NOT NULL, `participantType` TEXT NOT NULL, `permissions` INTEGER NOT NULL, `readOnly` TEXT NOT NULL, `recordingConsent` INTEGER NOT NULL, `remoteServer` TEXT, `remoteToken` TEXT, `sessionId` TEXT NOT NULL, `status` TEXT, `statusClearAt` INTEGER, `statusIcon` TEXT, `statusMessage` TEXT, `type` TEXT NOT NULL, `unreadMention` INTEGER NOT NULL, `unreadMentionDirect` INTEGER NOT NULL, `unreadMessages` INTEGER NOT NULL, PRIMARY KEY(`internalId`), FOREIGN KEY(`accountId`) REFERENCES `User`(`id`) ON UPDATE CASCADE ON DELETE CASCADE )", + "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`internalId` TEXT NOT NULL, `accountId` INTEGER NOT NULL, `token` TEXT NOT NULL, `displayName` TEXT NOT NULL, `actorId` TEXT NOT NULL, `actorType` TEXT NOT NULL, `avatarVersion` TEXT NOT NULL, `callFlag` INTEGER NOT NULL, `callRecording` INTEGER NOT NULL, `callStartTime` INTEGER NOT NULL, `canDeleteConversation` INTEGER NOT NULL, `canLeaveConversation` INTEGER NOT NULL, `canStartCall` INTEGER NOT NULL, `description` TEXT NOT NULL, `hasCall` INTEGER NOT NULL, `hasPassword` INTEGER NOT NULL, `isCustomAvatar` INTEGER NOT NULL, `isFavorite` INTEGER NOT NULL, `lastActivity` INTEGER NOT NULL, `lastCommonReadMessage` INTEGER NOT NULL, `lastMessage` TEXT, `lastPing` INTEGER NOT NULL, `lastReadMessage` INTEGER NOT NULL, `lobbyState` TEXT NOT NULL, `lobbyTimer` INTEGER NOT NULL, `messageExpiration` INTEGER NOT NULL, `name` TEXT NOT NULL, `notificationCalls` INTEGER NOT NULL, `notificationLevel` TEXT NOT NULL, `objectType` TEXT NOT NULL, `participantType` TEXT NOT NULL, `permissions` INTEGER NOT NULL, `readOnly` TEXT NOT NULL, `recordingConsent` INTEGER NOT NULL, `remoteServer` TEXT, `remoteToken` TEXT, `sessionId` TEXT NOT NULL, `status` TEXT, `statusClearAt` INTEGER, `statusIcon` TEXT, `statusMessage` TEXT, `type` TEXT NOT NULL, `unreadMention` INTEGER NOT NULL, `unreadMentionDirect` INTEGER NOT NULL, `unreadMessages` INTEGER NOT NULL, `hasArchived` INTEGER NOT NULL, PRIMARY KEY(`internalId`), FOREIGN KEY(`accountId`) REFERENCES `User`(`id`) ON UPDATE CASCADE ON DELETE CASCADE )", "fields": [ { "fieldPath": "internalId", @@ -409,6 +409,12 @@ "columnName": "unreadMessages", "affinity": "INTEGER", "notNull": true + }, + { + "fieldPath": "hasArchived", + "columnName": "hasArchived", + "affinity": "INTEGER", + "notNull": true } ], "primaryKey": { @@ -713,7 +719,7 @@ "views": [], "setupQueries": [ "CREATE TABLE IF NOT EXISTS room_master_table (id INTEGER PRIMARY KEY,identity_hash TEXT)", - "INSERT OR REPLACE INTO room_master_table (id,identity_hash) VALUES(42, 'bc802cadfdef41d3eb94ffbb0729eb89')" + "INSERT OR REPLACE INTO room_master_table (id,identity_hash) VALUES(42, '7edb537b6987d0de6586a6760c970958')" ] } } \ No newline at end of file diff --git a/app/src/main/java/com/nextcloud/talk/conversationinfo/ConversationInfoActivity.kt b/app/src/main/java/com/nextcloud/talk/conversationinfo/ConversationInfoActivity.kt index e9bf60b64d..6dbfca996f 100644 --- a/app/src/main/java/com/nextcloud/talk/conversationinfo/ConversationInfoActivity.kt +++ b/app/src/main/java/com/nextcloud/talk/conversationinfo/ConversationInfoActivity.kt @@ -179,36 +179,17 @@ class ConversationInfoActivity : databaseStorageModule = DatabaseStorageModule(conversationUser, conversationToken) } - if (!spreedCapabilities.features!!.contains(ARCHIVED_CONVERSATIONS)) { - binding.archiveConversationBtn.visibility = GONE - } - binding.deleteConversationAction.setOnClickListener { showDeleteConversationDialog() } binding.leaveConversationAction.setOnClickListener { leaveConversation() } binding.clearConversationHistory.setOnClickListener { showClearHistoryDialog() } binding.addParticipantsAction.setOnClickListener { addParticipants() } binding.listBansButton.setOnClickListener { listBans() } - binding.archiveConversationBtn.setOnClickListener { - if (conversation!!.isArchived) { - viewModel.unarchiveConversation(conversationUser, conversationToken) - } else { - viewModel.archiveConversation(conversationUser, conversationToken) - } - } viewModel.getRoom(conversationUser, conversationToken) themeTextViews() themeSwitchPreferences() - if (conversation!!.isArchived) { - binding.archiveConversationIcon.setImageDrawable(resources.getDrawable(R.drawable.ic_eye)) - binding.archiveConversationText.text = resources.getString(R.string.unarchive_conversation) - } else { - binding.archiveConversationIcon.setImageDrawable(resources.getDrawable(R.drawable.outline_archive_24)) - binding.archiveConversationText.text = resources.getString(R.string.archive_conversation) - } - binding.addParticipantsAction.visibility = GONE binding.progressBar.let { viewThemeUtils.platform.colorCircularProgressBar(it, ColorRole.PRIMARY) } @@ -760,6 +741,26 @@ class ConversationInfoActivity : } } + if (!spreedCapabilities.features!!.contains(ARCHIVED_CONVERSATIONS)) { + binding.archiveConversationBtn.visibility = GONE + } + + binding.archiveConversationBtn.setOnClickListener { + if (conversation!!.hasArchived) { + viewModel.unarchiveConversation(conversationUser, conversationToken) + } else { + viewModel.archiveConversation(conversationUser, conversationToken) + } + } + + if (conversation!!.hasArchived) { + binding.archiveConversationIcon.setImageDrawable(resources.getDrawable(R.drawable.ic_eye)) + binding.archiveConversationText.text = resources.getString(R.string.unarchive_conversation) + } else { + binding.archiveConversationIcon.setImageDrawable(resources.getDrawable(R.drawable.outline_archive_24)) + binding.archiveConversationText.text = resources.getString(R.string.archive_conversation) + } + if (!isDestroyed) { binding.dangerZoneOptions.visibility = VISIBLE diff --git a/app/src/main/java/com/nextcloud/talk/conversationinfo/viewmodel/ConversationInfoViewModel.kt b/app/src/main/java/com/nextcloud/talk/conversationinfo/viewmodel/ConversationInfoViewModel.kt index afed00c8a4..562e913577 100644 --- a/app/src/main/java/com/nextcloud/talk/conversationinfo/viewmodel/ConversationInfoViewModel.kt +++ b/app/src/main/java/com/nextcloud/talk/conversationinfo/viewmodel/ConversationInfoViewModel.kt @@ -203,11 +203,53 @@ class ConversationInfoViewModel @Inject constructor( } fun archiveConversation(user: User, token: String) { - // TODO + val apiVersion = ApiUtils.getConversationApiVersion(user, intArrayOf(ApiUtils.API_V4, ApiUtils.API_V1)) + val url = ApiUtils.getUrlForArchive(apiVersion, user.baseUrl, token) + conversationsRepository.archiveConversation(user.getCredentials(), url) + .subscribeOn(Schedulers.io()) + ?.observeOn(AndroidSchedulers.mainThread()) + ?.subscribe(object : Observer { + override fun onSubscribe(p0: Disposable) { + // unused + } + + override fun onError(e: Throwable) { + Log.d("Julius", "Error in archive $e") + } + + override fun onComplete() { + // unused atm + } + + override fun onNext(n: GenericOverall) { + Log.d("Julius", "Archived successful") + } + }) } fun unarchiveConversation(user: User, token: String) { - // TODO + val apiVersion = ApiUtils.getConversationApiVersion(user, intArrayOf(ApiUtils.API_V4, ApiUtils.API_V1)) + val url = ApiUtils.getUrlForArchive(apiVersion, user.baseUrl, token) + conversationsRepository.unarchiveConversation(user.getCredentials(), url) + .subscribeOn(Schedulers.io()) + ?.observeOn(AndroidSchedulers.mainThread()) + ?.subscribe(object : Observer { + override fun onSubscribe(p0: Disposable) { + // unused + } + + override fun onError(e: Throwable) { + Log.d("Julius", "Error in unarchive $e") + } + + override fun onComplete() { + // unused atm + } + + override fun onNext(n: GenericOverall) { + Log.d("Julius", "unArchived successful") + } + }) } inner class GetRoomObserver : Observer { diff --git a/app/src/main/java/com/nextcloud/talk/conversationlist/ConversationsListActivity.kt b/app/src/main/java/com/nextcloud/talk/conversationlist/ConversationsListActivity.kt index e3a367f0c7..73a6fc9396 100644 --- a/app/src/main/java/com/nextcloud/talk/conversationlist/ConversationsListActivity.kt +++ b/app/src/main/java/com/nextcloud/talk/conversationlist/ConversationsListActivity.kt @@ -210,7 +210,8 @@ class ConversationsListActivity : private var filterState = mutableMapOf( FilterConversationFragment.MENTION to false, - FilterConversationFragment.UNREAD to false + FilterConversationFragment.UNREAD to false, + FilterConversationFragment.ARCHIVE to false ) val searchBehaviorSubject = BehaviorSubject.createDefault(false) private lateinit var accountIconBadge: BadgeDrawable @@ -413,9 +414,18 @@ class ConversationsListActivity : ).blockingGet()?.value ?: "" ) == "true" + filterState[FilterConversationFragment.ARCHIVE] = ( + arbitraryStorageManager.getStorageSetting( + accountId, + FilterConversationFragment.ARCHIVE, + "" + ).blockingGet()?.value ?: "" + ) == "true" + val newItems: MutableList> = ArrayList() if (filterState[FilterConversationFragment.UNREAD] == false && - filterState[FilterConversationFragment.MENTION] == false + filterState[FilterConversationFragment.MENTION] == false && + filterState[FilterConversationFragment.ARCHIVE] == false ) { adapter!!.updateDataSet(conversationItems, true) } else { @@ -449,6 +459,8 @@ class ConversationsListActivity : ) FilterConversationFragment.UNREAD -> result = result && (conversation.unreadMessages > 0) + + FilterConversationFragment.ARCHIVE -> result = result && conversation.hasArchived } } } diff --git a/app/src/main/java/com/nextcloud/talk/data/database/mappers/ConversationMapUtils.kt b/app/src/main/java/com/nextcloud/talk/data/database/mappers/ConversationMapUtils.kt index c6c80a485e..90acf61174 100644 --- a/app/src/main/java/com/nextcloud/talk/data/database/mappers/ConversationMapUtils.kt +++ b/app/src/main/java/com/nextcloud/talk/data/database/mappers/ConversationMapUtils.kt @@ -59,7 +59,8 @@ fun ConversationModel.asEntity() = callStartTime = callStartTime, recordingConsentRequired = recordingConsentRequired, remoteServer = remoteServer, - remoteToken = remoteToken + remoteToken = remoteToken, + hasArchived = hasArchived ) fun ConversationEntity.asModel() = @@ -109,7 +110,8 @@ fun ConversationEntity.asModel() = callStartTime = callStartTime, recordingConsentRequired = recordingConsentRequired, remoteServer = remoteServer, - remoteToken = remoteToken + remoteToken = remoteToken, + hasArchived = hasArchived ) fun Conversation.asEntity(accountId: Long) = @@ -158,5 +160,6 @@ fun Conversation.asEntity(accountId: Long) = callStartTime = callStartTime, recordingConsentRequired = recordingConsentRequired, remoteServer = remoteServer, - remoteToken = remoteToken + remoteToken = remoteToken, + hasArchived = hasArchived ) diff --git a/app/src/main/java/com/nextcloud/talk/data/database/model/ConversationEntity.kt b/app/src/main/java/com/nextcloud/talk/data/database/model/ConversationEntity.kt index 1c0d067dec..4f46522647 100644 --- a/app/src/main/java/com/nextcloud/talk/data/database/model/ConversationEntity.kt +++ b/app/src/main/java/com/nextcloud/talk/data/database/model/ConversationEntity.kt @@ -92,7 +92,8 @@ data class ConversationEntity( @ColumnInfo(name = "type") var type: ConversationEnums.ConversationType, @ColumnInfo(name = "unreadMention") var unreadMention: Boolean = false, @ColumnInfo(name = "unreadMentionDirect") var unreadMentionDirect: Boolean, - @ColumnInfo(name = "unreadMessages") var unreadMessages: Int = 0 + @ColumnInfo(name = "unreadMessages") var unreadMessages: Int = 0, + @ColumnInfo(name = "hasArchived") var hasArchived: Boolean = false // missing/not needed: attendeeId // missing/not needed: attendeePin // missing/not needed: attendeePermissions diff --git a/app/src/main/java/com/nextcloud/talk/models/domain/ConversationModel.kt b/app/src/main/java/com/nextcloud/talk/models/domain/ConversationModel.kt index 85e3abed88..e6a036564e 100644 --- a/app/src/main/java/com/nextcloud/talk/models/domain/ConversationModel.kt +++ b/app/src/main/java/com/nextcloud/talk/models/domain/ConversationModel.kt @@ -59,7 +59,7 @@ class ConversationModel( var recordingConsentRequired: Int = 0, var remoteServer: String? = null, var remoteToken: String? = null, - var isArchived: Boolean = false, + var hasArchived: Boolean = false, // attributes that don't come from API. This should be changed?! var password: String? = null @@ -122,7 +122,7 @@ class ConversationModel( recordingConsentRequired = conversation.recordingConsentRequired, remoteServer = conversation.remoteServer, remoteToken = conversation.remoteToken, - isArchived = conversation.isArchived + hasArchived = conversation.hasArchived ) } } diff --git a/app/src/main/java/com/nextcloud/talk/models/json/conversations/Conversation.kt b/app/src/main/java/com/nextcloud/talk/models/json/conversations/Conversation.kt index f50cb29a54..6ef2bd50ed 100644 --- a/app/src/main/java/com/nextcloud/talk/models/json/conversations/Conversation.kt +++ b/app/src/main/java/com/nextcloud/talk/models/json/conversations/Conversation.kt @@ -162,5 +162,5 @@ data class Conversation( var remoteToken: String? = "", @JsonField(name = ["isArchived"]) - var isArchived: Boolean + var hasArchived: Boolean = false ) : Parcelable 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 486c505af2..d077b92a28 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 @@ -69,7 +69,8 @@ class FilterConversationFragment : DialogFragment() { binding.run { listOf( unreadFilterChip, - mentionedFilterChip + mentionedFilterChip, + archivedFilterChip ) }.forEach(viewThemeUtils.talk::themeChipFilter) @@ -89,6 +90,12 @@ class FilterConversationFragment : DialogFragment() { processSubmit() } + binding.archivedFilterChip.setOnCheckedChangeListener { _, isChecked -> + filterState[ARCHIVE] = isChecked + binding.archivedFilterChip.isChecked = isChecked + processSubmit() + } + binding.buttonClose.setOnClickListener { dismiss() } @@ -104,9 +111,11 @@ class FilterConversationFragment : DialogFragment() { val accountId = UserIdUtils.getIdForUser(userManager.currentUser.blockingGet()) val mentionValue = filterState[MENTION] == true val unreadValue = filterState[UNREAD] == true + val archivedValue = filterState[ARCHIVE] == true arbitraryStorageManager.storeStorageSetting(accountId, MENTION, mentionValue.toString(), "") arbitraryStorageManager.storeStorageSetting(accountId, UNREAD, unreadValue.toString(), "") + arbitraryStorageManager.storeStorageSetting(accountId, ARCHIVE, archivedValue.toString(), "") (requireActivity() as ConversationsListActivity).filterConversation() } @@ -126,5 +135,6 @@ class FilterConversationFragment : DialogFragment() { val TAG: String = FilterConversationFragment::class.java.simpleName const val MENTION: String = "mention" const val UNREAD: String = "unread" + const val ARCHIVE: String = "archive" } } diff --git a/app/src/main/java/com/nextcloud/talk/utils/ApiUtils.kt b/app/src/main/java/com/nextcloud/talk/utils/ApiUtils.kt index fb4e6a770c..557c876fca 100644 --- a/app/src/main/java/com/nextcloud/talk/utils/ApiUtils.kt +++ b/app/src/main/java/com/nextcloud/talk/utils/ApiUtils.kt @@ -588,4 +588,8 @@ object ApiUtils { fun getUrlForUnban(baseUrl: String, token: String, banId: Int): String { return "${getUrlForBans(baseUrl, token)}/$banId" } + + fun getUrlForArchive(version: Int, baseUrl: String?, token: String?): String { + return "${getUrlForRoom(version, baseUrl, token)}/archive" + } } diff --git a/app/src/main/res/layout/dialog_filter_conversation.xml b/app/src/main/res/layout/dialog_filter_conversation.xml index 2fa293fe1e..75c1d79d0a 100644 --- a/app/src/main/res/layout/dialog_filter_conversation.xml +++ b/app/src/main/res/layout/dialog_filter_conversation.xml @@ -48,6 +48,13 @@ android:layout_height="wrap_content" android:text="@string/mentioned" /> + + Connection lost Archive Conversation Unarchive Conversation + Archived From 82bf7e320d02f8d1d62b3c93f977907d908f19b8 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Mon, 14 Oct 2024 19:10:00 +0000 Subject: [PATCH 171/885] fix(deps): update dependency com.android.tools.build:gradle to v8.7.1 Signed-off-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build.gradle b/build.gradle index 88cd1b8ead..4d5867a6ce 100644 --- a/build.gradle +++ b/build.gradle @@ -22,7 +22,7 @@ buildscript { } dependencies { - classpath 'com.android.tools.build:gradle:8.7.0' + classpath 'com.android.tools.build:gradle:8.7.1' classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:${kotlinVersion}" classpath "org.jetbrains.kotlin:kotlin-serialization:${kotlinVersion}" classpath 'com.github.spotbugs.snom:spotbugs-gradle-plugin:6.0.24' From db7c2a18d97c6cc83e4fe905e5d2eac7b8984478 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Mon, 14 Oct 2024 23:01:58 +0000 Subject: [PATCH 172/885] fix(deps): update dependency com.github.spotbugs.snom:spotbugs-gradle-plugin to v6.0.25 Signed-off-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build.gradle b/build.gradle index 4d5867a6ce..bb704ca436 100644 --- a/build.gradle +++ b/build.gradle @@ -25,7 +25,7 @@ buildscript { classpath 'com.android.tools.build:gradle:8.7.1' classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:${kotlinVersion}" classpath "org.jetbrains.kotlin:kotlin-serialization:${kotlinVersion}" - classpath 'com.github.spotbugs.snom:spotbugs-gradle-plugin:6.0.24' + classpath 'com.github.spotbugs.snom:spotbugs-gradle-plugin:6.0.25' classpath "io.gitlab.arturbosch.detekt:detekt-gradle-plugin:1.23.7" classpath "org.jlleitschuh.gradle:ktlint-gradle:12.1.1" classpath "com.google.dagger:hilt-android-gradle-plugin:$hilt_version" From b731d6ad3827e824d672b35b653fb736d6119a6b Mon Sep 17 00:00:00 2001 From: Nextcloud bot Date: Tue, 15 Oct 2024 02:50:51 +0000 Subject: [PATCH 173/885] Fix(l10n): Update translations from Transifex Signed-off-by: Nextcloud bot --- app/src/main/res/values-ca/strings.xml | 91 ++++++++++++++++++++++ app/src/main/res/values-cs-rCZ/strings.xml | 7 ++ 2 files changed, 98 insertions(+) diff --git a/app/src/main/res/values-ca/strings.xml b/app/src/main/res/values-ca/strings.xml index b731db4def..0c9826e4ed 100644 --- a/app/src/main/res/values-ca/strings.xml +++ b/app/src/main/res/values-ca/strings.xml @@ -1,7 +1,10 @@ Edició + Afegeix-ho a les notes + S\'ha afegit la conversa %1$s als preferits Cerca a %s + Trucada d\'àudio Bluetooth Sortida d\'àudio Telèfon @@ -9,6 +12,10 @@ Auriculars per cable Avatar Absent + Botó Enrere + Prohibeix + Prohibeix el participant + Llista de prohibicions Calendari Opcions avançades de trucada La trucada porta una hora en marxa. @@ -18,27 +25,50 @@ Esborrar el missatge d\'estat Esborra el missatge d\'estat després Tanca + Tanca la icona S\'ha establert la connexió + S\'ha perdut la connexió + S\'ha perdut la connexió: %1$d a la cua + S\'ha perdut la connexió: els missatges enviats s\'han posat a la cua + Bloqueja l\'enregistrament per a l\'enregistrament continu del missatge de veu + La conversa és només de lectura Converses Crea una conversa + Crea un error Personalitzat + Zona de perill Suprimeix l\'avatar + Conversa suprimida %1$s No molesteu No l\'esborris Editar + No es poden editar missatges de més de 24 hores + Editeu la icona del missatge Retrocés Recent Xifrat S\'ha produït un problema carregant els xats + S\'ha produït un error en anul·lar la prohibició del participant No s\'ha pogut desar %1$s carpeta Carregant … %1$s (%2$d) 4 hores + No s\'han pogut recuperar les invitacions pendents + (editat) + Nota interna Invisible + Icona d\'Uniu-vos a les converses obertes + No s\'han pogut recuperar els idiomes + Ha fallat la recuperació + Avui més tard + Heu abandonat la conversa %1$s Carregar més resultats Símbol de bloqueig Baixa mà + S\'ha marcat com a llegida la conversa %1$s + S\'ha marcat com a no llegida la conversa %1$s + Mencionat Més nou primer Més antic primer A - Z @@ -46,6 +76,7 @@ Més gran primer Més petit primer Missatge suprimit per tu + Editat per %1$s Toqueu per obrir l\'enquesta No s\'han trobat resultats Comença a escriure per cercar … @@ -65,12 +96,15 @@ D\'acord, tot fet! Ancora: %1$s Desbloca %1$s + Per a habilitar els altaveus Bluetooth, concediu el permís de \"Dispositius propers\". Opcions avançades de trucada Respon com a trucada de vídeo Respon només com a trucada de veu Canvia la sortida d\'àudio Commuta la càmera + Penja Commuta el micròfon + Obre la imatge en mode d\'imatge Canviar al vídeo propi ENTRANT Nom de la conversa @@ -85,13 +119,17 @@ %strucada %s trucada de vídeo %s trucada de veu + Per habilitar la comunicació per vídeo, concediu el permís de \"Càmera\". Cancel·la No s\'han pogut obtenir les funcionalitats, s\'està avortant + Subtítol Us en refieu del certificat SSL desconegut fins ara, emès per %1$s per %2$s, vàlid del %3$s fins el %4$s? Verifica el certificat La vostra configuració SSL ha impedit la connexió Canvia el certificat d’autenticació Canvia la contrasenya + Comproveu la connexió a Internet + Esborra el botó Edita Suprimeix tots els missatges S\'han suprimit tots els missatges Segur que voleu suprimir tots els missatges d\'aquesta conversa? @@ -110,6 +148,7 @@ Selecciona el certificat d’autenticació S\'està connectant … Fet + Descripció de la conversa Informació de la conversa Trucada de vídeo Trucada de veu @@ -128,29 +167,63 @@ Al suprimir la conversa, també serà suprimit per a la resta de participants. Suprimir El missatge s\'ha suprimit correctament, però podria haver-se filtrat a altres serveis + S\'ha suprimit l\'usuari %1$s Deposat des del moderador Grava un missatge de veu Envia un missatge Compte actual Servidor + S\'ha instal·lat l\'aplicació de notificació del servidor? Usuari + S\'ha habilitat l\'estat de l\'usuari? Versió d\'Android Aplicació Nom de l\'aplicació Usuaris registrats + Versió de l\'aplicació + S\'ha ignorat l\'optimització de la bateria, tot bé + No s\'ha ignorat l\'optimització de la bateria. S\'hauria de canviar! Paràmetres de la bateria Dispositiu + Obre la llista de comprovació de resolució de problemes + Obre la pantalla de diagnòstic + Obre dontkillmyapp.com + Serveis de Google Play no està disponible. No s\'admeten les notificacions. + Serveis de Google Play + Serveis de Google Play està disponible + Últim registre de notificacions al servidor intermediari de notificacions automàtiques + Encara no s\'ha registrat al servidor intermediari de notificacions automàtiques + Últim registre de notificacions automàtiques al servidor + Encara no s\'ha registrat al servidor + Informació de les metadades + Generació de l\'informe del sistema + S\'ha activat el canal de notificació de trucades? + S\'ha habilitat el canal de notificació de missatges? + Permisos de notificacions + Telèfon + Versió de Converses del servidor + Versió del servidor Extern Intern + Mode de senyal Contrasenya no vàlida Mode de manteniment + El servidor està en mode de manteniment. + L\'aplicació és obsoleta + L\'aplicació és massa antiga i ja no és compatible amb aquest servidor. Actualitzeu-la. Actualització Voleu reautoritzar o suprimir aquest compte? + Desar aquest suport per emmagatzemar-lo permetrà que qualsevol altra aplicació del dispositiu hi accedeixi. + Voleu continuar? No + Voleu desar a l\'emmagatzematge? No s’ha pogut obtenir el nom de visualització, s\'està avortant No s\'ha pogut emmagatzemar el nom de visualització, s\'està avortant + Edita la icona Edició + Edita el missatge de text + Editat per l\'administrador Correu 8 hores 4 setmanes @@ -163,7 +236,11 @@ No s\'ha pogut obtenir la configuració de senyalització Accepta Rebutja + No hi ha cap invitació pendent + Teniu invitacions pendents Enrere + Cal permís per accedir als fitxers + Filtra les converses Usuari que segueix un enllaç públic Tu: %1$s Reenvia @@ -188,6 +265,8 @@ S\'han tornat a enviar les invitacions. Comparteix l\'enllaç de la conversa Introduïu un missatge … + L\'optimització de la bateria no s\'ignora. Això hauria de canviar-se per a garantir que les notificacions funcionin en segon pla. Feu clic a D\'acord i seleccioneu \"Totes les aplicacions\" -> %1$s -> No optimitzis + Ignora l\'optimització de la bateria Conversa important Les notificacions d\'aquesta conversa anul·laran els paràmetres de no destorbar. Invitacions @@ -198,6 +277,7 @@ Llicència Pública General de GNU, Versió 3 Llicència S\'ha arribat al límit de %s caràcters + Fes una llista de les converses obertes Vestíbul Aquesta reunió està programada per a %1$s La reunió començarà aviat @@ -214,6 +294,7 @@ Cancel·la la resposta Missatge llegit Missatge enviat + Per a habilitar la comunicació per veu, concediu el permís de \"Micròfon\". Teniu una trucada perduda de %s Moderador Mai no us hi heu unit @@ -224,6 +305,8 @@ %1$s no està disponible (no instal·lat o restringit per l\'administrador) Convidat No + No hi ha converses obertes + No hi ha converses obertes a què us pugueu unir.\nO bé no hi ha converses obertes o ja us heu unit a totes. Sense proxy No teniu permís per activar l\'àudio No teniu permís per activar el vídeo @@ -235,6 +318,8 @@ Pujades Notifica el progrés de càrrega Paràmetres de les notificacions + Els permisos de notificacions i la configuració de la bateria estan configurats correctament per rebre notificacions. Si igualment teniu problemes per rebre notificacions, comproveu si els canals de notificació per a trucades i missatges estan habilitats. Podeu trobar més ajuda a DontKillMyApp.com o a la llista de comprovació de resolució de problemes. Si això no us ajuda, aneu a la pantalla de diagnòstic i envieu un informe d\'error. + Resolució de problemes de notificació Notifica sempre Notifica només quan s\'esmenti No notifiquis mai @@ -246,7 +331,11 @@ Participants Afegeix participants Contrasenya + Establiu els permisos + Alguns permisos s\'han denegat. + Permeteu els permisos Obre la configuració + Concediu els permisos a Configuració > Permisos No s\'ha trobat el compte Xateja mitjançant %s Silencia el micròfon @@ -266,6 +355,8 @@ Suprimeix de favorits Suprimeix el grup i els membres Suprimeix el participant + Suprimeix la contrasenya + Suprimeix l\'equip i els membres Reanomena la conversa Anomena Respon diff --git a/app/src/main/res/values-cs-rCZ/strings.xml b/app/src/main/res/values-cs-rCZ/strings.xml index d2f5a14046..a43861fe6f 100644 --- a/app/src/main/res/values-cs-rCZ/strings.xml +++ b/app/src/main/res/values-cs-rCZ/strings.xml @@ -28,6 +28,8 @@ Ikona zavření Spojení navázáno Spojení ztraceno + Spojení ztraceno – %1$d jsou zařazené do fronty + Spojení ztraceno – odeslané zprávy jsou zařazené do fronty Zamknout nahrávku pro nepřetržité nahrávání hlasové zprávy Konverzace je pouze pro čtení Konverzace @@ -40,6 +42,7 @@ Nerušit Nečistit Upravit + Není možné upravovat zprávy starší než 24 hodin Upravit ikon zprávy Backspace Nedávné @@ -179,6 +182,8 @@ Název aplikace Registrovaní uživatelé Verze aplikace + Optimalizace pro nízkou spotřebu energie z akumulátoru je ignorována, všechno v pořádku + Optimalizace pro nízkou spotřebu energie z akumulátoru není ignorována. Toto by mělo být změněno! Nastavení správy napájení Zařízení Otevřít kontrolní seznam řešení problémů @@ -186,7 +191,9 @@ Otevřít dontkillmyapp.com Stažení nejnovějšího push tokenu firebase Vytvoření nejnovějšího push tokenu firebase + Nenastaven žádný push token firebase. Prosím vytvořte hlášení chyby. push token Firebase + Služby Google Play nejsou k dispozici. Upozorňování proto nejsou podporována Služby Google Play Služby Google Play jsou k dispozici Poslední push registrace na push proxy From 9516576c4f81128d1df99c343d6bbeb68fc54845 Mon Sep 17 00:00:00 2001 From: nextcloud-android-bot Date: Tue, 15 Oct 2024 02:49:31 +0000 Subject: [PATCH 174/885] =?UTF-8?q?=F0=9F=94=84=20synced=20local=20'.githu?= =?UTF-8?q?b/workflows/'=20with=20remote=20'config/workflows/'?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: nextcloud-android-bot --- .github/workflows/codeql.yml | 4 ++-- .github/workflows/scorecard.yml | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/codeql.yml b/.github/workflows/codeql.yml index efa349f682..f93230561f 100644 --- a/.github/workflows/codeql.yml +++ b/.github/workflows/codeql.yml @@ -39,7 +39,7 @@ jobs: with: swap-size-gb: 10 - name: Initialize CodeQL - uses: github/codeql-action/init@c36620d31ac7c881962c3d9dd939c40ec9434f2b # v3.26.12 + uses: github/codeql-action/init@f779452ac5af1c261dce0346a8f964149f49322b # v3.26.13 with: languages: ${{ matrix.language }} - name: Set up JDK 17 @@ -53,4 +53,4 @@ jobs: echo "org.gradle.jvmargs=-Xmx4g -XX:MaxMetaspaceSize=512m -XX:+HeapDumpOnOutOfMemoryError" > "$HOME/.gradle/gradle.properties" ./gradlew assembleDebug - name: Perform CodeQL Analysis - uses: github/codeql-action/analyze@c36620d31ac7c881962c3d9dd939c40ec9434f2b # v3.26.12 + uses: github/codeql-action/analyze@f779452ac5af1c261dce0346a8f964149f49322b # v3.26.13 diff --git a/.github/workflows/scorecard.yml b/.github/workflows/scorecard.yml index fc32557b88..6a3181bc2c 100644 --- a/.github/workflows/scorecard.yml +++ b/.github/workflows/scorecard.yml @@ -42,6 +42,6 @@ jobs: # Upload the results to GitHub's code scanning dashboard. - name: "Upload to code-scanning" - uses: github/codeql-action/upload-sarif@c36620d31ac7c881962c3d9dd939c40ec9434f2b # v3.26.12 + uses: github/codeql-action/upload-sarif@f779452ac5af1c261dce0346a8f964149f49322b # v3.26.13 with: sarif_file: results.sarif From 39305d7e96f8f74ba59069fae7abd0b149278441 Mon Sep 17 00:00:00 2001 From: rapterjet2004 Date: Tue, 15 Oct 2024 08:15:13 -0500 Subject: [PATCH 175/885] Ironed out the bugs Signed-off-by: rapterjet2004 --- .../ConversationInfoActivity.kt | 4 ++ .../ConversationsListActivity.kt | 49 +++++++++++-------- .../ui/dialog/FilterConversationFragment.kt | 2 + .../res/layout/dialog_filter_conversation.xml | 2 +- 4 files changed, 36 insertions(+), 21 deletions(-) diff --git a/app/src/main/java/com/nextcloud/talk/conversationinfo/ConversationInfoActivity.kt b/app/src/main/java/com/nextcloud/talk/conversationinfo/ConversationInfoActivity.kt index 6dbfca996f..7f00539abd 100644 --- a/app/src/main/java/com/nextcloud/talk/conversationinfo/ConversationInfoActivity.kt +++ b/app/src/main/java/com/nextcloud/talk/conversationinfo/ConversationInfoActivity.kt @@ -748,8 +748,12 @@ class ConversationInfoActivity : binding.archiveConversationBtn.setOnClickListener { if (conversation!!.hasArchived) { viewModel.unarchiveConversation(conversationUser, conversationToken) + binding.archiveConversationIcon.setImageDrawable(resources.getDrawable(R.drawable.outline_archive_24)) + binding.archiveConversationText.text = resources.getString(R.string.archive_conversation) } else { viewModel.archiveConversation(conversationUser, conversationToken) + binding.archiveConversationIcon.setImageDrawable(resources.getDrawable(R.drawable.ic_eye)) + binding.archiveConversationText.text = resources.getString(R.string.unarchive_conversation) } } diff --git a/app/src/main/java/com/nextcloud/talk/conversationlist/ConversationsListActivity.kt b/app/src/main/java/com/nextcloud/talk/conversationlist/ConversationsListActivity.kt index 73a6fc9396..fcb8ad497c 100644 --- a/app/src/main/java/com/nextcloud/talk/conversationlist/ConversationsListActivity.kt +++ b/app/src/main/java/com/nextcloud/talk/conversationlist/ConversationsListActivity.kt @@ -211,7 +211,8 @@ class ConversationsListActivity : mutableMapOf( FilterConversationFragment.MENTION to false, FilterConversationFragment.UNREAD to false, - FilterConversationFragment.ARCHIVE to false + FilterConversationFragment.ARCHIVE to false, + FilterConversationFragment.DEFAULT to true ) val searchBehaviorSubject = BehaviorSubject.createDefault(false) private lateinit var accountIconBadge: BadgeDrawable @@ -381,7 +382,7 @@ class ConversationsListActivity : sortConversations(conversationItemsWithHeader) // Filter Conversations - if (!filterState.containsValue(true)) filterableConversationItems = conversationItems + if (!containsTrue()) filterableConversationItems = conversationItems filterConversation() adapter!!.updateDataSet(filterableConversationItems, false) Handler().postDelayed({ checkToShowUnreadBubble() }, UNREAD_BUBBLE_DELAY.toLong()) @@ -396,6 +397,14 @@ class ConversationsListActivity : } } + private fun containsTrue(): Boolean { + for ((k, v) in filterState) { + if (k != FilterConversationFragment.DEFAULT && v) return true + } + + return false + } + fun filterConversation() { val accountId = UserIdUtils.getIdForUser(userManager.currentUser.blockingGet()) filterState[FilterConversationFragment.UNREAD] = ( @@ -423,22 +432,15 @@ class ConversationsListActivity : ) == "true" val newItems: MutableList> = ArrayList() - if (filterState[FilterConversationFragment.UNREAD] == false && - filterState[FilterConversationFragment.MENTION] == false && - filterState[FilterConversationFragment.ARCHIVE] == false - ) { - adapter!!.updateDataSet(conversationItems, true) - } else { - val items = conversationItems - for (i in items) { - val conversation = (i as ConversationItem).model - if (filter(conversation)) { - newItems.add(i) - } + val items = conversationItems + for (i in items) { + val conversation = (i as ConversationItem).model + if (filter(conversation)) { + newItems.add(i) } - adapter!!.updateDataSet(newItems, true) - setFilterableItems(newItems) } + adapter!!.updateDataSet(newItems, true) + setFilterableItems(newItems) updateFilterConversationButtonColor() } @@ -460,11 +462,18 @@ class ConversationsListActivity : FilterConversationFragment.UNREAD -> result = result && (conversation.unreadMessages > 0) - FilterConversationFragment.ARCHIVE -> result = result && conversation.hasArchived + FilterConversationFragment.DEFAULT -> { + result = if (filterState[FilterConversationFragment.ARCHIVE] == true) { + result && conversation.hasArchived + } else { + result && !conversation.hasArchived + } + } } } } + Log.d("Julius", "Conversation: ${conversation.name} Result: $result") return result } @@ -661,7 +670,7 @@ class ConversationsListActivity : override fun onMenuItemActionExpand(item: MenuItem): Boolean { initSearchDisposable() adapter!!.setHeadersShown(true) - if (!filterState.containsValue(true)) filterableConversationItems = searchableConversationItems + if (!containsTrue()) filterableConversationItems = searchableConversationItems adapter!!.updateDataSet(filterableConversationItems, false) adapter!!.showAllHeaders() binding.swipeRefreshLayoutView?.isEnabled = false @@ -671,7 +680,7 @@ class ConversationsListActivity : override fun onMenuItemActionCollapse(item: MenuItem): Boolean { adapter!!.setHeadersShown(false) - if (!filterState.containsValue(true)) filterableConversationItems = conversationItemsWithHeader + if (!containsTrue()) filterableConversationItems = conversationItemsWithHeader adapter!!.updateDataSet(filterableConversationItems, false) adapter!!.hideAllHeaders() if (searchHelper != null) { @@ -1838,7 +1847,7 @@ class ConversationsListActivity : } fun updateFilterConversationButtonColor() { - if (filterState.containsValue(true)) { + if (containsTrue()) { binding.filterConversationsButton.let { viewThemeUtils.platform.colorImageView(it, ColorRole.PRIMARY) } } else { binding.filterConversationsButton.let { 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 d077b92a28..6eb3c17195 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 @@ -104,6 +104,7 @@ class FilterConversationFragment : DialogFragment() { private fun setUpChips() { binding.unreadFilterChip.isChecked = filterState[UNREAD]!! binding.mentionedFilterChip.isChecked = filterState[MENTION]!! + binding.archivedFilterChip.isChecked = filterState[ARCHIVE]!! } private fun processSubmit() { @@ -136,5 +137,6 @@ class FilterConversationFragment : DialogFragment() { const val MENTION: String = "mention" const val UNREAD: String = "unread" const val ARCHIVE: String = "archive" + const val DEFAULT: String = "default" } } diff --git a/app/src/main/res/layout/dialog_filter_conversation.xml b/app/src/main/res/layout/dialog_filter_conversation.xml index 75c1d79d0a..c2e9a029a1 100644 --- a/app/src/main/res/layout/dialog_filter_conversation.xml +++ b/app/src/main/res/layout/dialog_filter_conversation.xml @@ -32,7 +32,7 @@ android:layout_marginTop="@dimen/standard_half_margin" android:layout_marginEnd="@dimen/standard_margin" android:layout_marginBottom="@dimen/standard_half_margin" - app:chipSpacingHorizontal="@dimen/standard_margin"> + app:chipSpacingHorizontal="@dimen/standard_half_margin"> Date: Tue, 15 Oct 2024 14:29:11 +0000 Subject: [PATCH 176/885] fix(deps): update mockito monorepo to v5.14.2 Signed-off-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- app/build.gradle | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/app/build.gradle b/app/build.gradle index 2c9e34a63b..1375c3f75c 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -324,14 +324,14 @@ dependencies { debugImplementation("androidx.compose.ui:ui-test-manifest") testImplementation 'junit:junit:4.13.2' - testImplementation 'org.mockito:mockito-core:5.14.1' + testImplementation 'org.mockito:mockito-core:5.14.2' testImplementation 'androidx.arch.core:core-testing:2.2.0' androidTestImplementation "androidx.test:core:1.6.1" androidTestImplementation "org.jetbrains.kotlinx:kotlinx-coroutines-test:1.9.0" androidTestImplementation 'androidx.test:core-ktx:1.6.1' - androidTestImplementation 'org.mockito:mockito-android:5.14.1' + androidTestImplementation 'org.mockito:mockito-android:5.14.2' androidTestImplementation "androidx.work:work-testing:${workVersion}" // Espresso core androidTestImplementation ("androidx.test.espresso:espresso-core:$espressoVersion", { From 210a6aaf1c13a57da5c95e32a2a58a4c95c96c8c Mon Sep 17 00:00:00 2001 From: Nextcloud bot Date: Wed, 16 Oct 2024 03:05:08 +0000 Subject: [PATCH 177/885] Fix(l10n): Update translations from Transifex Signed-off-by: Nextcloud bot --- app/src/main/res/values-ar/strings.xml | 2 +- app/src/main/res/values-ca/strings.xml | 32 ++++++++++++++++++++++ app/src/main/res/values-lt-rLT/strings.xml | 3 ++ 3 files changed, 36 insertions(+), 1 deletion(-) diff --git a/app/src/main/res/values-ar/strings.xml b/app/src/main/res/values-ar/strings.xml index 07db85f76e..d32dad7336 100644 --- a/app/src/main/res/values-ar/strings.xml +++ b/app/src/main/res/values-ar/strings.xml @@ -524,7 +524,7 @@ هل تريد حقا إنهاء هذا الاستبيان؟ لا يمكن التراجع عن هذا الخيار لاحقاً. لا يمكنك التصويت مع المزيد من الخيارات في هذا الاستبيان. إجابات متعددة - إحذِف الخيار %1$s + حذف الخيار %1$s الخيار %1$s الخيارات إستبيان خاص diff --git a/app/src/main/res/values-ca/strings.xml b/app/src/main/res/values-ca/strings.xml index 0c9826e4ed..a6902808a7 100644 --- a/app/src/main/res/values-ca/strings.xml +++ b/app/src/main/res/values-ca/strings.xml @@ -405,19 +405,26 @@ Adreça del servidor https://… %1$s només funciona amb %2$s 13 i endavant Estableix una contrasenya nova + Defineix la contrasenya Paràmetres S\'ha actualitzat el vostre compte ja existent enlloc d’afegir-ne un de nou Avançat Aparença Trucades + Obre la pantalla de diagnòstic per a comprovar la configuració o crear un informe d\'error + Diagnòstic Indica al teclat que desactivi l\'aprenentatge personalitzat (sense garanties) Teclat d\'incògnit Sense so L\'aplicació Talk no està instal·lada al servidor amb el qual heu intentat autenticar-vos So de les notificacions Notificacions + Les notificacions s\'han rebutjat + S\'han rebutjat les notificacions. Permeteu les notificacions a la configuració d\'Android. + S\'han concedit les notificacions Missatges Fes coincidir els contactes basats en el número de telèfon per a integrar la drecera de Talk a l\'aplicació de contactes del sistema + Error 429 massa sol·licituds Podeu establir el vostre número de telèfon perquè altres usuaris puguin trobar-vos Introduïu el número de telèfon Número de telèfon no vàlid @@ -451,6 +458,8 @@ Clar Tema Comparteix el meu estat d\'escriptura i mostra l\'estat d\'escriptura dels altres + L\'estat d\'escriptura només està disponible quan s\'utilitza un backend d\'alt rendiment (HPB) + Estat d\'escriptura El proxy necessita credencials Avís Només el compte actual pot ser re-autoritzat @@ -493,6 +502,7 @@ « Llisqueu per cancel·lar Webinar + Icona de Creació de conversa nova Setmana següent No hi ha integració amb el número de telèfon perquè falten permisos 1 hora @@ -527,11 +537,16 @@ Realment voleu aturar l\'enregistrament? Aturar l\'enregistrament de la trucada Aturar l\'enregistrament + S\'està aturant l\'enregistrament… Cal el consentiment de gravació per a totes les trucades + L\'enregistrament pot incloure la veu, el vídeo de la càmera i la compartició de pantalla. Es requereix el vostre consentiment abans d\'unir-vos a la trucada. Doneu el consentiment? Requereix el consentiment per gravar abans d\'unir-te a la trucada en aquesta conversa Consentiment de gravació És possible que la trucada sigui gravada. Enregistrament + S\'ha suprimit la conversa %1$s dels preferits + S\'ha canviat el nom de la conversa %1$s + No és possible unir-se a altres sales mentre s\'està en una trucada Desa Sincronitza només amb servidors de confiança Federat @@ -544,7 +559,9 @@ Commuta l\'abast Canvia el nivell de privadesa de %1$s Desplaça al final + Icona de Cerca fa uns segons + Visualitzeu %1$s missatges similars Seleccionat Enviar correu Envia a @@ -561,10 +578,16 @@ Multimèdia Altres Enquesta + Enregistrament de trucades Veu + Mostra el motiu de la prohibició + Mostra els participants prohibits Preferits No teniu permís per a iniciar una trucada + ha inciat una trucada Missatge d\'estat + Canvia a la sala de descans + Canvia a la sala principal Prendre una fotografia S\'ha produït un error en fer la foto No es pot fer una fotografia sense permisos @@ -576,9 +599,12 @@ Commuta la llanterna 30 minuts Aquesta setmana + Això és un missatge de prova + Aquest cap de setmana Avui Demà Traducció + Traducció Copia el text traduït Detectar idioma Paràmetres del dispositiu @@ -586,6 +612,11 @@ La traducció ha fallat De A + i 1 altre està escrivint… + estan escrivint… + està escrivint… + i %1$s més estan escrivint… + Anul·la la prohibició Per llegir Puja l\'avatar nou des del dispositiu Utilitzar avatar @@ -599,6 +630,7 @@ No s\'ha pogut recuperar la informació personal de l\'usuari. No hi ha arranjament d\'informació personal Afegiu el nom, foto i detalls de contacte a la vostra pàgina de perfil. + Videotrucada Quin és el vostre estat? %d vot diff --git a/app/src/main/res/values-lt-rLT/strings.xml b/app/src/main/res/values-lt-rLT/strings.xml index be8ac2f966..cda4233b99 100644 --- a/app/src/main/res/values-lt-rLT/strings.xml +++ b/app/src/main/res/values-lt-rLT/strings.xml @@ -172,7 +172,9 @@ Įkelti iš naujo Priminti vėliau Šalinti iš mėgstamų + Šalinti grupę ir narius Šalinti dalyvį + Šalinti komandą ir narius Pervadinti pokalbį Pervadinti Atsakyti @@ -256,6 +258,7 @@ Rikiuoti pagal Pradžios laikas Perjungti paskyrą + Komanda Komandos Įkeliama Fotografuoti From 55d5f246f803c590ad18ae469a81506cd8cd1617 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Wed, 16 Oct 2024 03:45:00 +0000 Subject: [PATCH 178/885] chore(deps): update ubuntu:noble docker digest to d4f6f70 Signed-off-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- .devcontainer/Dockerfile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.devcontainer/Dockerfile b/.devcontainer/Dockerfile index d603462dc9..012c6a3449 100644 --- a/.devcontainer/Dockerfile +++ b/.devcontainer/Dockerfile @@ -1,4 +1,4 @@ -FROM ubuntu:noble@sha256:ab64a8382e935382638764d8719362bb50ee418d944c1f3d26e0c99fae49a345 +FROM ubuntu:noble@sha256:d4f6f70979d0758d7a6f81e34a61195677f4f4fa576eaf808b79f17499fd93d1 ARG DEBIAN_FRONTEND=noninteractive ENV ANDROID_HOME=/usr/lib/android-sdk From ea7d48fb67789ca89069119b19164f73a1329cac Mon Sep 17 00:00:00 2001 From: rapterjet2004 Date: Wed, 16 Oct 2024 08:57:40 -0500 Subject: [PATCH 179/885] detekt Signed-off-by: rapterjet2004 --- .../main/java/com/nextcloud/talk/utils/FileUtils.kt | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) 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 aeff10873f..b3a51c9cbb 100644 --- a/app/src/main/java/com/nextcloud/talk/utils/FileUtils.kt +++ b/app/src/main/java/com/nextcloud/talk/utils/FileUtils.kt @@ -30,6 +30,7 @@ import android.content.ContentResolver import android.content.Context import android.database.Cursor import android.net.Uri +import android.os.Build import android.provider.OpenableColumns import android.util.Log import java.io.File @@ -115,7 +116,17 @@ object FileUtils { fun copyFileToCache(context: Context, sourceFileUri: Uri, filename: String): File? { val cachedFile = File(context.cacheDir, filename) - if (!cachedFile.canonicalPath.startsWith(context.cacheDir.canonicalPath, true)) { + val aboveOrEqualAPI26Check = + Build.VERSION.SDK_INT >= Build.VERSION_CODES.O && + !cachedFile.toPath().normalize().startsWith(context.cacheDir.toPath()) + + val belowAPI26Check = + Build.VERSION.SDK_INT < Build.VERSION_CODES.O && + !cachedFile.canonicalPath.startsWith(context.cacheDir.canonicalPath, true) + + val isOutsideCacheDir = aboveOrEqualAPI26Check || belowAPI26Check + + if (isOutsideCacheDir) { Log.w(TAG, "cachedFile was not created in cacheDir. Aborting for security reasons.") cachedFile.delete() return null From 2d37338a31b04f3c20afbe171c5e96e44378da0a Mon Sep 17 00:00:00 2001 From: Nextcloud bot Date: Thu, 17 Oct 2024 02:57:49 +0000 Subject: [PATCH 180/885] Fix(l10n): Update translations from Transifex Signed-off-by: Nextcloud bot --- app/src/main/res/values-ar/strings.xml | 16 ++++++++-------- app/src/main/res/values-el/strings.xml | 2 ++ app/src/main/res/values-es-rEC/strings.xml | 1 + app/src/main/res/values-es/strings.xml | 2 ++ app/src/main/res/values-eu/strings.xml | 2 ++ app/src/main/res/values-fa/strings.xml | 2 ++ app/src/main/res/values-fi-rFI/strings.xml | 2 ++ 7 files changed, 19 insertions(+), 8 deletions(-) diff --git a/app/src/main/res/values-ar/strings.xml b/app/src/main/res/values-ar/strings.xml index d32dad7336..11fc63ecb1 100644 --- a/app/src/main/res/values-ar/strings.xml +++ b/app/src/main/res/values-ar/strings.xml @@ -1,8 +1,8 @@ تحرير - أضِف إلى الملاحظات - أضِف المحادثة %1$sإلى المُفضّلة + إضافة إلى الملاحظات + إضافة المحادثة %1$sإلى المُفضّلة بحث في %s مكالمة صوتية البلوتوث @@ -88,9 +88,9 @@ أضف حساباً تمت جدولة الحساب للحذف ، ولا يمكن تغييره افتح القائمة الرئيسية - أضِف مُرفَقاً attachment + إضافة مرفق إضِف إيموجي emoji - أضِف إلى المحادثة + إضافة إلى المحادثة إضِف مُشاركين أضف إلى المفضلة تم! @@ -276,7 +276,7 @@ محادثة مهمة الاشعارات في هذه المحادثة ستتجاوز إعداد الحالة \"يُرجى عدم الإزعاج\" دعوات - إنضَمَّ إلى محادثات جارية + الانضمام إلى محادثات جارية %1$s| آخر تعديل: %2$s غادر المحادثة مُغادرة المكالمة … @@ -478,7 +478,7 @@ شارِك هذا الموقع إختر حسابًا عناصر مُشارَكة - بطاقة Deck card + بطاقة صور، و ملفات، ورسائل صوتية ... لا توجد عناصر مُشارَكة الموقع @@ -620,7 +620,7 @@ فشل الترجمة مِن : إلى : - و واحدٌ آخر يكتب ... 1 + و شخص آخر يكتب ... يكتبون ... يكتب... و%1$s آخرون يقومون بالكتابة... @@ -637,7 +637,7 @@ الحاله فشل في استرداد المعلومات الشخصية للمستخدم لم يتم تعيين أي معلومات شخصية - أضِف الاسم والصورة وتفاصيل الاتصال في صفحة ملفك الشخصي. + إضافة الاسم والصورة وتفاصيل الاتصال في صفحة ملفك الشخصي. مكالمة مرئية ماهي حالتك؟ diff --git a/app/src/main/res/values-el/strings.xml b/app/src/main/res/values-el/strings.xml index 51187bf1ec..c6ad210a70 100644 --- a/app/src/main/res/values-el/strings.xml +++ b/app/src/main/res/values-el/strings.xml @@ -71,6 +71,7 @@ Ελέγξτε το πιστοποιητικό Η ρύθμιση SSL απέτρεψε την σύνδεση Αλλαγή πιστοποιητικού πιστοποίησης + Αλλαγή συνθηματικού Διαγραφή όλων των μηνυμάτων Όλα τα μηνύματα διαγράφηκαν Θέλετε πραγματικά να διαγράψετε όλα τα μηνύματα σε αυτήν τη συνομιλία; @@ -202,6 +203,7 @@ Ιδιοκτήτης Συμμετέχοντες Προσθήκη συμμετεχόντων + Συνθηματικό Άνοιγμα ρυθμίσεων Δεν βρέθηκε λογαριασμός Συνομιλία μέσω %s diff --git a/app/src/main/res/values-es-rEC/strings.xml b/app/src/main/res/values-es-rEC/strings.xml index 3bd0a0aa65..e15b972dcb 100644 --- a/app/src/main/res/values-es-rEC/strings.xml +++ b/app/src/main/res/values-es-rEC/strings.xml @@ -95,6 +95,7 @@ Verifica el certificado Tu configuración de SSL impidió la conexión Cambiar el certificado de atuenticación + Cambiar contraseña Borrar todos los mensajes Todos los mensajes se han eliminado ¿Realmente quieres borrar todos los mensajes de esta conversación? diff --git a/app/src/main/res/values-es/strings.xml b/app/src/main/res/values-es/strings.xml index 7fe4e59732..1bee8f2ced 100644 --- a/app/src/main/res/values-es/strings.xml +++ b/app/src/main/res/values-es/strings.xml @@ -116,6 +116,7 @@ Comprobar el certificado Tu configuración SSL impidió la conexión Cambiar certificado de autenticación + Cambiar contraseña Por favor, verifique su conexión a internet Limpiar botón de edición Limpiar mensaje de edición @@ -324,6 +325,7 @@ Propietario Participantes Añadir participantes + Contraseña Establecer permisos Algunos permisos fueron denegados. Por favor, otorgue los permisos diff --git a/app/src/main/res/values-eu/strings.xml b/app/src/main/res/values-eu/strings.xml index 4e3bc1d65e..414a6054f9 100644 --- a/app/src/main/res/values-eu/strings.xml +++ b/app/src/main/res/values-eu/strings.xml @@ -112,6 +112,7 @@ Egiaztatu ziurtagiria Zure SSL konfigurazioak konexioa eragotzi du Aldatu autentifikazio ziurtagiria + Aldatu pasahitza Ezabatu mezu guztiak Mezu guztiak ezabatu dira Ziur zaude elkarrizketa honen mezu guztiak ezabatu nahi dituzula? @@ -282,6 +283,7 @@ Jabea Parte-hartzaileak Gehitu parte-hartzaileak + Pasahitza Ezarri baimenak Baimen batzuk ukatu egin dira. Eman baimenak, mesedez diff --git a/app/src/main/res/values-fa/strings.xml b/app/src/main/res/values-fa/strings.xml index d36463450b..635e044ba1 100644 --- a/app/src/main/res/values-fa/strings.xml +++ b/app/src/main/res/values-fa/strings.xml @@ -85,6 +85,7 @@ گواهی را بررسی کنید راه اندازی SSL شما مانع از اتصال شد گواهی تأیید اعتبار را تغییر دهید + تغییر گذرواژه حذف تمام پیام‌ها تمام پیام‌ها حذف شدند آیا واقعا می‌خواهید تمام پیام‌ها را در این مکالمه حذف کنید؟ @@ -213,6 +214,7 @@ مالک شركت كنندگان افزودن شرکت‌کننده + گذرواژه تنظیم دسترسی‌ها تنظیمات را باز کنید حساب یافت نشد diff --git a/app/src/main/res/values-fi-rFI/strings.xml b/app/src/main/res/values-fi-rFI/strings.xml index 1167a71e21..1892dc813e 100644 --- a/app/src/main/res/values-fi-rFI/strings.xml +++ b/app/src/main/res/values-fi-rFI/strings.xml @@ -70,6 +70,7 @@ Tarkista varmenne SSL-asetukset esti yhteyden Vaihda tunnistautumisvarmenne + Vaihda salasana Poista kaikki viestit Kaikki viestit poistettiin Haluatko varmasti poistaa kaikki viestit tästä keskustelusta? @@ -207,6 +208,7 @@ Omistaja Osallistujat Lisää osallistujat + Salasana Avaa asetukset Tiliä ei löydy Mykistä mikrofoni From 4f4285810bfd0b8f36fcb8b0d0fa4c9a3941b0c7 Mon Sep 17 00:00:00 2001 From: Nextcloud bot Date: Fri, 18 Oct 2024 03:01:00 +0000 Subject: [PATCH 181/885] Fix(l10n): Update translations from Transifex Signed-off-by: Nextcloud bot --- app/src/main/res/values-ar/strings.xml | 4 ++-- app/src/main/res/values-lt-rLT/strings.xml | 1 + 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/app/src/main/res/values-ar/strings.xml b/app/src/main/res/values-ar/strings.xml index 11fc63ecb1..98f4a2549b 100644 --- a/app/src/main/res/values-ar/strings.xml +++ b/app/src/main/res/values-ar/strings.xml @@ -191,7 +191,7 @@ فتح dontkillmyapp.com آخر أَمَارَات إدخال push token في \"فاير بيس\" firebase تمّ جلبها آخر أَمَارَات إدخال push token في \"فاير بيس\" firebase تمّ توليدها - لم يتم تعيين أيّ أَمَارَات إدخال push token. من فضلك، أنشيء تقريراً حول هذا الخطأ. + لم يتم تعيين أيّ رموز توكن push token. من فضلك، أنشيء تقريراً حول هذا الخطأ. أَمَارَة إدخال push token في \"فاير بيس\" firebase خدمات متجر التطبيقات من قوقل Google Play غير متاحة. و الإشعارات غير مدعومة خدمات متجر التطبيقات من قوقل Google play @@ -467,7 +467,7 @@ مشاركة حالة كتابتي وإظهار حالة كتابة الآخرين لا تتوفر حالة الكتابة إلا عند استخدام خلفية سريعة الأداء (HPB) حالة الكتابة - الوكيل بحاجة إلى حيثيّات الدخول credentials + الوكيل بحاجة إلى بيانات تسجيل الدخول تحذير يمكن إعادة تفويض الحساب الجاري فقط شارك جهة اتصال diff --git a/app/src/main/res/values-lt-rLT/strings.xml b/app/src/main/res/values-lt-rLT/strings.xml index cda4233b99..6e17f8e1d0 100644 --- a/app/src/main/res/values-lt-rLT/strings.xml +++ b/app/src/main/res/values-lt-rLT/strings.xml @@ -216,6 +216,7 @@ Serveryje nėra įdiegta palaikoma Pokalbių programėlė Serverio adresas https://… %1$s veikia tik naudojant %2$s 13 ar naujesnę versiją + Nustatyti naują slaptažodį Nustatymai Vietoj naujos paskyros pridėjimo, buvo atnaujinta jūsų esama paskyra Išplėstiniai From 1c0e473e1af87a83f44e3a4003626e256ed64af6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Calvi=C3=B1o=20S=C3=A1nchez?= Date: Fri, 18 Oct 2024 13:53:03 +0200 Subject: [PATCH 182/885] Fix ignored blank lines in Javadocs MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Daniel Calviño Sánchez --- .../nextcloud/talk/call/CallParticipant.java | 2 +- .../talk/call/CallParticipantList.java | 2 +- .../call/CallParticipantListNotifier.java | 2 +- .../talk/call/CallParticipantModel.java | 16 ++--- .../call/MutableCallParticipantModel.java | 2 +- .../LocalParticipantMessageNotifier.java | 2 +- .../talk/signaling/OfferMessageNotifier.java | 2 +- .../ParticipantListMessageNotifier.java | 2 +- .../signaling/SignalingMessageReceiver.java | 58 +++++++++---------- .../webrtc/DataChannelMessageNotifier.java | 2 +- .../talk/webrtc/PeerConnectionNotifier.java | 2 +- 11 files changed, 46 insertions(+), 46 deletions(-) diff --git a/app/src/main/java/com/nextcloud/talk/call/CallParticipant.java b/app/src/main/java/com/nextcloud/talk/call/CallParticipant.java index af1ac26728..4aa207fdf7 100644 --- a/app/src/main/java/com/nextcloud/talk/call/CallParticipant.java +++ b/app/src/main/java/com/nextcloud/talk/call/CallParticipant.java @@ -15,7 +15,7 @@ /** * Model for (remote) call participants. - * + *

* This class keeps track of the state changes in a call participant and updates its data model as needed. View classes * are expected to directly use the read-only data model. */ diff --git a/app/src/main/java/com/nextcloud/talk/call/CallParticipantList.java b/app/src/main/java/com/nextcloud/talk/call/CallParticipantList.java index 921900e7ec..4a1c7370bf 100644 --- a/app/src/main/java/com/nextcloud/talk/call/CallParticipantList.java +++ b/app/src/main/java/com/nextcloud/talk/call/CallParticipantList.java @@ -17,7 +17,7 @@ /** * Helper class to keep track of the participants in a call based on the signaling messages. - * + *

* The CallParticipantList adds a listener for participant list messages as soon as it is created and starts tracking * the call participants until destroyed. Notifications about the changes can be received by adding an observer to the * CallParticipantList; note that no sorting is guaranteed on the participants. diff --git a/app/src/main/java/com/nextcloud/talk/call/CallParticipantListNotifier.java b/app/src/main/java/com/nextcloud/talk/call/CallParticipantListNotifier.java index 2c0d169856..f02b300e0c 100644 --- a/app/src/main/java/com/nextcloud/talk/call/CallParticipantListNotifier.java +++ b/app/src/main/java/com/nextcloud/talk/call/CallParticipantListNotifier.java @@ -15,7 +15,7 @@ /** * Helper class to register and notify CallParticipantList.Observers. - * + *

* This class is only meant for internal use by CallParticipantList; listeners must register themselves against * a CallParticipantList rather than against a CallParticipantListNotifier. */ diff --git a/app/src/main/java/com/nextcloud/talk/call/CallParticipantModel.java b/app/src/main/java/com/nextcloud/talk/call/CallParticipantModel.java index bd59a28e83..f5409ad33e 100644 --- a/app/src/main/java/com/nextcloud/talk/call/CallParticipantModel.java +++ b/app/src/main/java/com/nextcloud/talk/call/CallParticipantModel.java @@ -17,23 +17,23 @@ /** * Read-only data model for (remote) call participants. - * + *

* If the hand was never raised null is returned by "getRaisedHand()". Otherwise a RaisedHand object is returned with * the current state (raised or not) and the timestamp when the raised hand state last changed. - * + *

* The received audio and video are available only if the participant is sending them and also has them enabled. * Before a connection is established it is not known whether audio and video are available or not, so null is returned * in that case (therefore it should not be autoboxed to a plain boolean without checking that). - * + *

* Audio and video in screen shares, on the other hand, are always seen as available. - * + *

* Actor type and actor id will be set only in Talk >= 20. - * + *

* Clients of the model can observe it with CallParticipantModel.Observer to be notified when any value changes. * Getters called after receiving a notification are guaranteed to provide at least the value that triggered the * notification, but it may return even a more up to date one (so getting the value again on the following * notification may return the same value as before). - * + *

* Besides onChange(), which notifies about changes in the model values, CallParticipantModel.Observer provides * additional methods to be notified about one-time events that are not reflected in the model values, like reactions. */ @@ -169,11 +169,11 @@ public void addObserver(Observer observer) { /** * Adds an observer to be notified when any value changes. - * + *

* The observer will be notified on the thread associated to the given handler. If no handler is given the * observer will be immediately notified on the same thread that changed the value; the observer will be * immediately notified too if the thread of the handler is the same thread that changed the value. - * + *

* An observer is expected to be added only once. If the same observer is added again it will be notified just * once on the thread of the last handler. * diff --git a/app/src/main/java/com/nextcloud/talk/call/MutableCallParticipantModel.java b/app/src/main/java/com/nextcloud/talk/call/MutableCallParticipantModel.java index 221b383521..c8bbdedce9 100644 --- a/app/src/main/java/com/nextcloud/talk/call/MutableCallParticipantModel.java +++ b/app/src/main/java/com/nextcloud/talk/call/MutableCallParticipantModel.java @@ -13,7 +13,7 @@ /** * Mutable data model for (remote) call participants. - * + *

* There is no synchronization when setting the values; if needed, it should be handled by the clients of the model. */ public class MutableCallParticipantModel extends CallParticipantModel { diff --git a/app/src/main/java/com/nextcloud/talk/signaling/LocalParticipantMessageNotifier.java b/app/src/main/java/com/nextcloud/talk/signaling/LocalParticipantMessageNotifier.java index f3fffbf754..154a1aa8b6 100644 --- a/app/src/main/java/com/nextcloud/talk/signaling/LocalParticipantMessageNotifier.java +++ b/app/src/main/java/com/nextcloud/talk/signaling/LocalParticipantMessageNotifier.java @@ -12,7 +12,7 @@ /** * Helper class to register and notify LocalParticipantMessageListeners. - * + *

* This class is only meant for internal use by SignalingMessageReceiver; listeners must register themselves against * a SignalingMessageReceiver rather than against a LocalParticipantMessageNotifier. */ diff --git a/app/src/main/java/com/nextcloud/talk/signaling/OfferMessageNotifier.java b/app/src/main/java/com/nextcloud/talk/signaling/OfferMessageNotifier.java index b0dd8ba3bf..f8947b5391 100644 --- a/app/src/main/java/com/nextcloud/talk/signaling/OfferMessageNotifier.java +++ b/app/src/main/java/com/nextcloud/talk/signaling/OfferMessageNotifier.java @@ -12,7 +12,7 @@ /** * Helper class to register and notify OfferMessageListeners. - * + *

* This class is only meant for internal use by SignalingMessageReceiver; listeners must register themselves against * a SignalingMessageReceiver rather than against an OfferMessageNotifier. */ diff --git a/app/src/main/java/com/nextcloud/talk/signaling/ParticipantListMessageNotifier.java b/app/src/main/java/com/nextcloud/talk/signaling/ParticipantListMessageNotifier.java index c860574e12..fe8622f0e7 100644 --- a/app/src/main/java/com/nextcloud/talk/signaling/ParticipantListMessageNotifier.java +++ b/app/src/main/java/com/nextcloud/talk/signaling/ParticipantListMessageNotifier.java @@ -15,7 +15,7 @@ /** * Helper class to register and notify ParticipantListMessageListeners. - * + *

* This class is only meant for internal use by SignalingMessageReceiver; listeners must register themselves against * a SignalingMessageReceiver rather than against a ParticipantListMessageNotifier. */ diff --git a/app/src/main/java/com/nextcloud/talk/signaling/SignalingMessageReceiver.java b/app/src/main/java/com/nextcloud/talk/signaling/SignalingMessageReceiver.java index 90f658f928..fb3e9c1912 100644 --- a/app/src/main/java/com/nextcloud/talk/signaling/SignalingMessageReceiver.java +++ b/app/src/main/java/com/nextcloud/talk/signaling/SignalingMessageReceiver.java @@ -20,20 +20,20 @@ /** * Hub to register listeners for signaling messages of different kinds. - * + *

* In general, if a listener is added while an event is being handled the new listener will not receive that event. * An exception to that is adding a WebRtcMessageListener when handling an offer in an OfferMessageListener; in that * case the "onOffer()" method of the WebRtcMessageListener will be called for that same offer. - * + *

* Similarly, if a listener is removed while an event is being handled the removed listener will still receive that * event. Again the exception is removing a WebRtcMessageListener when handling an offer in an OfferMessageListener; in * that case the "onOffer()" method of the WebRtcMessageListener will not be called for that offer. - * + *

* Adding and removing listeners, as well as notifying them is internally synchronized. This should be kept in mind * if listeners are added or removed when handling an event to prevent deadlocks (nevertheless, just adding or * removing a listener in the same thread handling the event is fine, and in most cases it will be fine too if done * in a different thread, as long as the notifier thread is not forced to wait until the listener is added or removed). - * + *

* SignalingMessageReceiver does not fetch the signaling messages itself; subclasses must fetch them and then call * the appropriate protected methods to process the messages and notify the listeners. */ @@ -55,7 +55,7 @@ public abstract class SignalingMessageReceiver { /** * Listener for participant list messages. - * + *

* The messages are implicitly bound to the room currently joined in the signaling server; listeners are expected * to know the current room. */ @@ -63,17 +63,17 @@ public interface ParticipantListMessageListener { /** * List of all the participants in the room. - * + *

* This message is received only when the internal signaling server is used. - * + *

* The message is received periodically, and the participants may not have been modified since the last message. - * + *

* Only the following participant properties are set: * - inCall * - lastPing * - sessionId * - userId (if the participant is not a guest) - * + *

* "participantPermissions" is provided in the message (since Talk 13), but not currently set in the * participant. "publishingPermissions" was provided instead in Talk 12, but it was not used anywhere, so it is * ignored. @@ -84,25 +84,25 @@ public interface ParticipantListMessageListener { /** * List of all the participants in the call or the room (depending on what triggered the event). - * + *

* This message is received only when the external signaling server is used. - * + *

* The message is received when any participant changed, although what changed is not provided and should be * derived from the difference with previous messages. The list of participants may include only the * participants in the call (including those that just left it and thus triggered the event) or all the * participants currently in the room (participants in the room but not currently active, that is, without a * session, are not included). - * + *

* Only the following participant properties are set: * - inCall * - lastPing * - sessionId * - type * - userId (if the participant is not a guest) - * + *

* "nextcloudSessionId" is provided in the message (when the "inCall" property of any participant changed), but * not currently set in the participant. - * + *

* "participantPermissions" is provided in the message (since Talk 13), but not currently set in the * participant. "publishingPermissions" was provided instead in Talk 12, but it was not used anywhere, so it is * ignored. @@ -113,7 +113,7 @@ public interface ParticipantListMessageListener { /** * Update of the properties of all the participants in the room. - * + *

* This message is received only when the external signaling server is used. * * @param inCall the new value of the inCall property @@ -123,17 +123,17 @@ public interface ParticipantListMessageListener { /** * Listener for local participant messages. - * + *

* The messages are implicitly bound to the local participant (or, rather, its session); listeners are expected * to know the local participant. - * + *

* The messages are related to the conversation, so the local participant may or may not be in a call when they * are received. */ public interface LocalParticipantMessageListener { /** * Request for the client to switch to the given conversation. - * + *

* This message is received only when the external signaling server is used. * * @param token the token of the conversation to switch to. @@ -143,10 +143,10 @@ public interface LocalParticipantMessageListener { /** * Listener for call participant messages. - * + *

* The messages are bound to a specific call participant (or, rather, session), so each listener is expected to * handle messages only for a single call participant. - * + *

* Although "unshareScreen" is technically bound to a specific peer connection it is instead treated as a general * message on the call participant. */ @@ -166,11 +166,11 @@ public interface ConversationMessageListener { /** * Listener for WebRTC offers. - * + *

* Unlike the WebRtcMessageListener, which is bound to a specific peer connection, an OfferMessageListener listens * to all offer messages, no matter which peer connection they are bound to. This can be used, for example, to * create a new peer connection when a remote offer for which there is no previous connection is received. - * + *

* When an offer is received all OfferMessageListeners are notified before any WebRtcMessageListener is notified. */ public interface OfferMessageListener { @@ -179,7 +179,7 @@ public interface OfferMessageListener { /** * Listener for WebRTC messages. - * + *

* The messages are bound to a specific peer connection, so each listener is expected to handle messages only for * a single peer connection. */ @@ -192,7 +192,7 @@ public interface WebRtcMessageListener { /** * Adds a listener for participant list messages. - * + *

* A listener is expected to be added only once. If the same listener is added again it will be notified just once. * * @param listener the ParticipantListMessageListener @@ -207,7 +207,7 @@ public void removeListener(ParticipantListMessageListener listener) { /** * Adds a listener for local participant messages. - * + *

* A listener is expected to be added only once. If the same listener is added again it will be notified just once. * * @param listener the LocalParticipantMessageListener @@ -222,7 +222,7 @@ public void removeListener(LocalParticipantMessageListener listener) { /** * Adds a listener for call participant messages. - * + *

* A listener is expected to be added only once. If the same listener is added again it will no longer be notified * for the messages from the previous session ID. * @@ -247,7 +247,7 @@ public void removeListener(ConversationMessageListener listener) { /** * Adds a listener for all offer messages. - * + *

* A listener is expected to be added only once. If the same listener is added again it will be notified just once. * * @param listener the OfferMessageListener @@ -262,7 +262,7 @@ public void removeListener(OfferMessageListener listener) { /** * Adds a listener for WebRTC messages from the given session ID and room type. - * + *

* A listener is expected to be added only once. If the same listener is added again it will no longer be notified * for the messages from the previous session ID or room type. * @@ -475,7 +475,7 @@ protected void processUsersInRoom(List> users) { /** * Creates and initializes a Participant from the data in the given map. - * + *

* Maps from internal and external signaling server messages can be used. Nevertheless, besides the differences * between the messages and the optional properties, it is expected that the message is correct and the given data * is parseable. Broken messages (for example, a string instead of an integer for "inCall" or a missing diff --git a/app/src/main/java/com/nextcloud/talk/webrtc/DataChannelMessageNotifier.java b/app/src/main/java/com/nextcloud/talk/webrtc/DataChannelMessageNotifier.java index a2f1b5f5eb..2fca22ac8f 100644 --- a/app/src/main/java/com/nextcloud/talk/webrtc/DataChannelMessageNotifier.java +++ b/app/src/main/java/com/nextcloud/talk/webrtc/DataChannelMessageNotifier.java @@ -12,7 +12,7 @@ /** * Helper class to register and notify DataChannelMessageListeners. - * + *

* This class is only meant for internal use by PeerConnectionWrapper; listeners must register themselves against * a PeerConnectionWrapper rather than against a DataChannelMessageNotifier. */ diff --git a/app/src/main/java/com/nextcloud/talk/webrtc/PeerConnectionNotifier.java b/app/src/main/java/com/nextcloud/talk/webrtc/PeerConnectionNotifier.java index ff0930c9c1..cea2a86616 100644 --- a/app/src/main/java/com/nextcloud/talk/webrtc/PeerConnectionNotifier.java +++ b/app/src/main/java/com/nextcloud/talk/webrtc/PeerConnectionNotifier.java @@ -15,7 +15,7 @@ /** * Helper class to register and notify PeerConnectionObserver. - * + *

* This class is only meant for internal use by PeerConnectionWrapper; observers must register themselves against * a PeerConnectionWrapper rather than against a PeerConnectionNotifier. */ From a77f08b74a5b2014a132c193fca473c6454b7447 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Sat, 19 Oct 2024 02:41:25 +0000 Subject: [PATCH 183/885] fix(deps): update dependency androidx.activity:activity-compose to v1.9.3 Signed-off-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- app/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/build.gradle b/app/build.gradle index 1375c3f75c..d928e4acc3 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -315,7 +315,7 @@ dependencies { implementation("androidx.compose.ui:ui") implementation 'androidx.compose.material3:material3:1.3.0' implementation("androidx.compose.ui:ui-tooling-preview") - implementation 'androidx.activity:activity-compose:1.9.2' + implementation 'androidx.activity:activity-compose:1.9.3' implementation 'androidx.lifecycle:lifecycle-runtime-ktx:2.8.6' debugImplementation("androidx.compose.ui:ui-tooling") From e86e3c9aaf670be005af7bdf9b2092effd02b782 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Sat, 19 Oct 2024 02:42:50 +0000 Subject: [PATCH 184/885] fix(deps): update dependency androidx.activity:activity-ktx to v1.9.3 Signed-off-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- app/build.gradle | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/app/build.gradle b/app/build.gradle index 1375c3f75c..1448465edc 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -303,7 +303,7 @@ dependencies { }) implementation 'androidx.core:core-ktx:1.13.1' - implementation 'androidx.activity:activity-ktx:1.9.2' + implementation 'androidx.activity:activity-ktx:1.9.3' implementation 'com.github.nextcloud.android-common:ui:0.23.1' implementation 'com.github.nextcloud-deps:android-talk-webrtc:121.6167.0' @@ -348,7 +348,7 @@ dependencies { spotbugsPlugins 'com.h3xstream.findsecbugs:findsecbugs-plugin:1.13.0' spotbugsPlugins 'com.mebigfatguy.fb-contrib:fb-contrib:7.6.5' - implementation 'androidx.activity:activity-ktx:1.9.2' + implementation 'androidx.activity:activity-ktx:1.9.3' implementation 'com.github.nextcloud.android-common:ui:0.23.1' From 8444ac0e886734d6a7aaab6d0ff39d4e06327f94 Mon Sep 17 00:00:00 2001 From: Nextcloud bot Date: Sat, 19 Oct 2024 03:05:59 +0000 Subject: [PATCH 185/885] Fix(l10n): Update translations from Transifex Signed-off-by: Nextcloud bot --- app/src/main/res/values-zh-rCN/strings.xml | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/app/src/main/res/values-zh-rCN/strings.xml b/app/src/main/res/values-zh-rCN/strings.xml index d88c0784cd..d170ae0666 100644 --- a/app/src/main/res/values-zh-rCN/strings.xml +++ b/app/src/main/res/values-zh-rCN/strings.xml @@ -64,7 +64,7 @@ 所选帐户现已导入并可用 关于 活跃用户 - 添加账户 + 添加账号 此账号已计划删除,且无法更改 打开主菜单 添加附件 @@ -277,7 +277,7 @@ 请允许权限 打开设置 请在 “设置” > “权限” 中开启权限 - 未找到账户 + 未找到账号 通过 %s 聊天 将麦克风静音 启用麦克风 @@ -372,7 +372,7 @@ 代理用户名 分享我的消息读取状态,并显示其他人的消息读取状态 消息读取状态 - 重新授权账户 + 重新授权账号 移除 移除账号 请确认您真要移除当前账号。 @@ -402,7 +402,7 @@ 共享链接 分享位置 分享这个位置 - 选择一个账户 + 选择账号 已分享项目 看板卡片 图片、文件、语音消息 @@ -411,7 +411,7 @@ 分享的位置 排序依据 开始时间 - 切换账户 + 切换账号 团队 团队 选择文件 From 38b19f8bdca7f4f8c731b180903d9a35324c7e68 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Sat, 19 Oct 2024 04:54:01 +0000 Subject: [PATCH 186/885] fix(deps): update dependency androidx.compose.ui:ui-test-junit4 to v1.7.4 Signed-off-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- app/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/build.gradle b/app/build.gradle index d928e4acc3..b10c06c161 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -320,7 +320,7 @@ dependencies { debugImplementation("androidx.compose.ui:ui-tooling") //tests - androidTestImplementation("androidx.compose.ui:ui-test-junit4:1.7.3") + androidTestImplementation("androidx.compose.ui:ui-test-junit4:1.7.4") debugImplementation("androidx.compose.ui:ui-test-manifest") testImplementation 'junit:junit:4.13.2' From 5b8d0febf4631e6e77968f4e3178166cc3db7b8d Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Sat, 19 Oct 2024 05:17:39 +0000 Subject: [PATCH 187/885] fix(deps): update dependency androidx.compose:compose-bom to v2024.10.00 Signed-off-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- app/build.gradle | 4 ++-- gradle/verification-metadata.xml | 5 +++++ 2 files changed, 7 insertions(+), 2 deletions(-) diff --git a/app/build.gradle b/app/build.gradle index 2ad6de6042..7cfde51b62 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -311,7 +311,7 @@ dependencies { gplayImplementation "com.google.firebase:firebase-messaging:24.0.2" //compose - implementation(platform("androidx.compose:compose-bom:2024.09.03")) + implementation(platform("androidx.compose:compose-bom:2024.10.00")) implementation("androidx.compose.ui:ui") implementation 'androidx.compose.material3:material3:1.3.0' implementation("androidx.compose.ui:ui-tooling-preview") @@ -359,7 +359,7 @@ dependencies { kapt "com.google.dagger:hilt-android-compiler:$hilt_version" implementation("androidx.lifecycle:lifecycle-viewmodel-compose:2.8.6") - androidTestImplementation(platform("androidx.compose:compose-bom:2024.09.03")) + androidTestImplementation(platform("androidx.compose:compose-bom:2024.10.00")) androidTestImplementation("androidx.compose.ui:ui-test-junit4") testImplementation "org.mockito.kotlin:mockito-kotlin:$mockitoKotlinVersion" testImplementation "org.jetbrains.kotlinx:kotlinx-coroutines-test:$coroutines_version" diff --git a/gradle/verification-metadata.xml b/gradle/verification-metadata.xml index 0e53bd4b62..470ad71101 100644 --- a/gradle/verification-metadata.xml +++ b/gradle/verification-metadata.xml @@ -632,6 +632,11 @@ + + + + + From 614545fdf218b4ce2c7b861998550f8543cfdeeb Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Sat, 19 Oct 2024 06:06:47 +0000 Subject: [PATCH 188/885] chore(deps): update ubuntu:noble docker digest to 99c3519 Signed-off-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- .devcontainer/Dockerfile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.devcontainer/Dockerfile b/.devcontainer/Dockerfile index 012c6a3449..ebd29943e2 100644 --- a/.devcontainer/Dockerfile +++ b/.devcontainer/Dockerfile @@ -1,4 +1,4 @@ -FROM ubuntu:noble@sha256:d4f6f70979d0758d7a6f81e34a61195677f4f4fa576eaf808b79f17499fd93d1 +FROM ubuntu:noble@sha256:99c35190e22d294cdace2783ac55effc69d32896daaa265f0bbedbcde4fbe3e5 ARG DEBIAN_FRONTEND=noninteractive ENV ANDROID_HOME=/usr/lib/android-sdk From 6deffd7548e0c1e1c659c72ff260af0347dc6e9f Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Sat, 19 Oct 2024 07:48:42 +0000 Subject: [PATCH 189/885] fix(deps): update dependency androidx.compose.runtime:runtime to v1.7.4 Signed-off-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- app/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/build.gradle b/app/build.gradle index 7cfde51b62..7d9634ebd8 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -184,7 +184,7 @@ dependencies { spotbugsPlugins 'com.h3xstream.findsecbugs:findsecbugs-plugin:1.13.0' spotbugsPlugins 'com.mebigfatguy.fb-contrib:fb-contrib:7.6.5' - implementation("androidx.compose.runtime:runtime:1.7.3") + implementation("androidx.compose.runtime:runtime:1.7.4") implementation 'androidx.preference:preference-ktx:1.2.1' implementation 'androidx.datastore:datastore-core:1.1.1' implementation 'androidx.datastore:datastore-preferences:1.1.1' From c89473020cf270057f929a4d14eee380ebf3dbd0 Mon Sep 17 00:00:00 2001 From: Nextcloud bot Date: Sun, 20 Oct 2024 02:53:41 +0000 Subject: [PATCH 190/885] Fix(l10n): Update translations from Transifex Signed-off-by: Nextcloud bot --- app/src/main/res/values-zh-rCN/strings.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/src/main/res/values-zh-rCN/strings.xml b/app/src/main/res/values-zh-rCN/strings.xml index d170ae0666..be080c0437 100644 --- a/app/src/main/res/values-zh-rCN/strings.xml +++ b/app/src/main/res/values-zh-rCN/strings.xml @@ -268,7 +268,7 @@ OK 向注册用户开放对话 同样对访客用户开放 - 拥有者 + 所有者 参与者 添加参与者 密码 From a5c1c64456f6a70c487283faca8dc9ad7a56427e Mon Sep 17 00:00:00 2001 From: Nextcloud bot Date: Mon, 21 Oct 2024 02:49:22 +0000 Subject: [PATCH 191/885] Fix(l10n): Update translations from Transifex Signed-off-by: Nextcloud bot --- app/src/main/res/values-ar/strings.xml | 6 +++--- app/src/main/res/values-zh-rCN/strings.xml | 4 ++-- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/app/src/main/res/values-ar/strings.xml b/app/src/main/res/values-ar/strings.xml index 98f4a2549b..edccf1dcfc 100644 --- a/app/src/main/res/values-ar/strings.xml +++ b/app/src/main/res/values-ar/strings.xml @@ -415,7 +415,7 @@ تعيين كلمة المرور الإعدادات تم تحديث حسابك الموجود بالفعل، بدلاً من إضافة حساب جديد - مُتقدّمة + متقدمة المظهر المكالمات فتح شاشة فحص الأعطال لاختبار الإعدادات أو تكوين تقرير بالعطل @@ -487,14 +487,14 @@ وقت البدء تبديل الحساب الفريق - الفِرَق + الفرق اختر الملفات إرسال هذه الملفات إلى %1$s؟ إرسال هذا الملف إلى %1$s؟ عذرًا، فشل الرفع فشلت عملية رفع %1$s فشل - مُشارَكةٌ مِن %1$s + مشاركة من %1$s إرفَع من الجهاز الرَّفْعُ جارٍ … %1$s إلى %2$s - %3$s\%% diff --git a/app/src/main/res/values-zh-rCN/strings.xml b/app/src/main/res/values-zh-rCN/strings.xml index be080c0437..bf6fd451f3 100644 --- a/app/src/main/res/values-zh-rCN/strings.xml +++ b/app/src/main/res/values-zh-rCN/strings.xml @@ -58,7 +58,7 @@ 消息被你删除了 点击打开投票 无搜索结果 - 开始输入以搜索 + 开始输入以搜索… 搜索... 消息 所选帐户现已导入并可用 @@ -484,7 +484,7 @@ 联合云 仅对该实例用户和来宾可见 本地 - 只对通过手机上Talk应用的电话号码整合功能匹配的人可见 + 只对通过手机上 Talk 应用的电话号码集成功能匹配的人可见 私有 同步到受信任的服务器、全局和公共地址簿 已发布 From a331ba63720d3b4d64c2d3b7d328685fb8965e10 Mon Sep 17 00:00:00 2001 From: Nextcloud Android Bot Date: Mon, 21 Oct 2024 03:14:34 +0000 Subject: [PATCH 192/885] Weekly 20.1.0 Alpha 09 --- app/build.gradle | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/app/build.gradle b/app/build.gradle index 7d9634ebd8..ea762f6b34 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -40,8 +40,8 @@ android { // mayor.minor.hotfix.increment (for increment: 01-50=Alpha / 51-89=RC / 90-99=stable) // xx .xxx .xx .xx - versionCode 200010008 - versionName "20.1.0 Alpha 08" + versionCode 200010009 + versionName "20.1.0 Alpha 09" flavorDimensions "default" renderscriptTargetApi 19 From 818a8431431910204a12766120de3a3b9bf88702 Mon Sep 17 00:00:00 2001 From: Marcel Hibbe Date: Tue, 1 Oct 2024 14:49:13 +0200 Subject: [PATCH 193/885] check if sync succeeded Decrease message limit for retries of message loading make it possible to add any amount (up to 100) of messages to UI for initial loading. add logging only make initial request for chat messages when newest message from DB is not equal the lastReadMessage that is offered by the conversation Signed-off-by: Marcel Hibbe --- .../network/OfflineFirstChatRepository.kt | 200 +++++++++++------- 1 file changed, 128 insertions(+), 72 deletions(-) diff --git a/app/src/main/java/com/nextcloud/talk/chat/data/network/OfflineFirstChatRepository.kt b/app/src/main/java/com/nextcloud/talk/chat/data/network/OfflineFirstChatRepository.kt index e7a49ac414..262188b030 100644 --- a/app/src/main/java/com/nextcloud/talk/chat/data/network/OfflineFirstChatRepository.kt +++ b/app/src/main/java/com/nextcloud/talk/chat/data/network/OfflineFirstChatRepository.kt @@ -108,26 +108,63 @@ class OfflineFirstChatRepository @Inject constructor( override fun loadInitialMessages(withNetworkParams: Bundle): Job = scope.launch { Log.d(TAG, "---- loadInitialMessages ------------") + Log.d(TAG, "conversationModel.internalId: " + conversationModel.internalId) newXChatLastCommonRead = conversationModel.lastCommonReadMessage - val fieldMap = getFieldMap( - lookIntoFuture = false, - includeLastKnown = true, - setReadMarker = true, - lastKnown = null - ) - withNetworkParams.putSerializable(BundleKeys.KEY_FIELD_MAP, fieldMap) - withNetworkParams.putString(BundleKeys.KEY_ROOM_TOKEN, conversationModel.token) + Log.d(TAG, "conversationModel.lastReadMessage:" + conversationModel.lastReadMessage) + + var newestMessageId = chatDao.getNewestMessageId(internalConversationId) + Log.d(TAG, "newestMessageId: $newestMessageId") + if (newestMessageId.toInt() == 0) { + Log.d(TAG, "newestMessageId from db was 0. Must only happen when chat is loaded for the first time") + } - sync(withNetworkParams) + if (conversationModel.lastReadMessage.toLong() != newestMessageId) { + Log.d(TAG, "An online request is made because chat is not up to date") + + // set up field map to load the newest messages + val fieldMap = getFieldMap( + lookIntoFuture = false, + includeLastKnown = true, + setReadMarker = true, + lastKnown = null + ) + withNetworkParams.putSerializable(BundleKeys.KEY_FIELD_MAP, fieldMap) + withNetworkParams.putString(BundleKeys.KEY_ROOM_TOKEN, conversationModel.token) + + Log.d(TAG, "Starting online request for initial loading") + val chatMessageEntities = sync(withNetworkParams) + if (chatMessageEntities == null) { + Log.e(TAG, "initial loading of messages failed") + } + + newestMessageId = chatDao.getNewestMessageId(internalConversationId) + Log.d(TAG, "newestMessageId after sync: $newestMessageId") + } else { + Log.d(TAG, "Initial online request is skipped because offline messages are up to date") + } - val newestMessageId = chatDao.getNewestMessageId(internalConversationId) - Log.d(TAG, "newestMessageId after sync: $newestMessageId") + val chatBlock = getBlockOfMessage(newestMessageId.toInt()) - showLast100MessagesBeforeAndEqual( + val amountBetween = chatDao.getCountBetweenMessageIds( internalConversationId, - chatDao.getNewestMessageId(internalConversationId) + newestMessageId, + chatBlock!!.oldestMessageId + ) + + Log.d(TAG, "amount of messages between newestMessageId and oldest message of same ChatBlock:$amountBetween") + val limit = if (amountBetween > DEFAULT_MESSAGES_LIMIT) { + DEFAULT_MESSAGES_LIMIT + } else { + amountBetween + } + Log.d(TAG, "limit of messages to load for UI (max 100 to ensure performance is okay):$limit") + + showMessagesBeforeAndEqual( + internalConversationId, + newestMessageId, + limit ) // delay is a dirty workaround to make sure messages are added to adapter on initial load before dealing @@ -175,10 +212,11 @@ class OfflineFirstChatRepository @Inject constructor( val loadFromServer = hasToLoadPreviousMessagesFromServer(beforeMessageId) if (loadFromServer) { + Log.d(TAG, "Starting online request for loadMoreMessages") sync(withNetworkParams) } - showLast100MessagesBefore(internalConversationId, beforeMessageId) + showMessagesBefore(internalConversationId, beforeMessageId, DEFAULT_MESSAGES_LIMIT) updateUiForLastCommonRead() } @@ -205,6 +243,7 @@ class OfflineFirstChatRepository @Inject constructor( // sync database with server (This is a long blocking call because long polling (lookIntoFuture) is set) networkParams.putSerializable(BundleKeys.KEY_FIELD_MAP, fieldMap) + Log.d(TAG, "Starting online request for long polling") val resultsFromSync = sync(networkParams) if (!resultsFromSync.isNullOrEmpty()) { val chatMessages = resultsFromSync.map(ChatMessageEntity::asModel) @@ -240,15 +279,15 @@ class OfflineFirstChatRepository @Inject constructor( loadFromServer = false } else { // we know that beforeMessageId and blockForMessage.oldestMessageId are in the same block. - // As we want the last 100 entries before beforeMessageId, we calculate if these messages are 100 - // entries apart from each other + // As we want the last DEFAULT_MESSAGES_LIMIT entries before beforeMessageId, we calculate if these + // messages are DEFAULT_MESSAGES_LIMIT entries apart from each other val amountBetween = chatDao.getCountBetweenMessageIds( internalConversationId, beforeMessageId, blockForMessage.oldestMessageId ) - loadFromServer = amountBetween < 100 + loadFromServer = amountBetween < DEFAULT_MESSAGES_LIMIT Log.d( TAG, @@ -263,7 +302,8 @@ class OfflineFirstChatRepository @Inject constructor( lookIntoFuture: Boolean, includeLastKnown: Boolean, setReadMarker: Boolean, - lastKnown: Int? + lastKnown: Int?, + limit: Int = DEFAULT_MESSAGES_LIMIT ): HashMap { val fieldMap = HashMap() @@ -278,7 +318,7 @@ class OfflineFirstChatRepository @Inject constructor( } fieldMap["timeout"] = if (lookIntoFuture) 30 else 0 - fieldMap["limit"] = 100 + fieldMap["limit"] = limit fieldMap["lookIntoFuture"] = if (lookIntoFuture) 1 else 0 fieldMap["setReadMarker"] = if (setReadMarker) 1 else 0 @@ -294,12 +334,12 @@ class OfflineFirstChatRepository @Inject constructor( lookIntoFuture = false, includeLastKnown = true, setReadMarker = false, - lastKnown = messageId.toInt() + lastKnown = messageId.toInt(), + limit = 1 ) bundle.putSerializable(BundleKeys.KEY_FIELD_MAP, fieldMap) - // Although only the single message will be returned, a server request will load 100 messages. - // If this turns out to be confusion for debugging we could load set the limit to 1 for this request. + Log.d(TAG, "Starting online request for single message (e.g. a reply)") sync(bundle) } return chatDao.getChatMessageForConversation(internalConversationId, messageId) @@ -308,59 +348,70 @@ class OfflineFirstChatRepository @Inject constructor( @Suppress("UNCHECKED_CAST") private fun getMessagesFromServer(bundle: Bundle): Pair>? { - Log.d(TAG, "An online request is made!!!!!!!!!!!!!!!!!!!!") val fieldMap = bundle.getSerializable(BundleKeys.KEY_FIELD_MAP) as HashMap - try { - val result = network.pullChatMessages(credentials, urlForChatting, fieldMap) - .subscribeOn(Schedulers.io()) - .observeOn(AndroidSchedulers.mainThread()) - // .timeout(3, TimeUnit.SECONDS) - .map { it -> - when (it.code()) { - HTTP_CODE_OK -> { - Log.d(TAG, "getMessagesFromServer HTTP_CODE_OK") - newXChatLastCommonRead = it.headers()["X-Chat-Last-Common-Read"]?.let { - Integer.parseInt(it) + var attempts = 1 + while (attempts < 5) { + Log.d(TAG, "message limit: " + fieldMap["limit"]) + try { + val result = network.pullChatMessages(credentials, urlForChatting, fieldMap) + .subscribeOn(Schedulers.io()) + .observeOn(AndroidSchedulers.mainThread()) + .map { it -> + when (it.code()) { + HTTP_CODE_OK -> { + Log.d(TAG, "getMessagesFromServer HTTP_CODE_OK") + newXChatLastCommonRead = it.headers()["X-Chat-Last-Common-Read"]?.let { + Integer.parseInt(it) + } + + return@map Pair( + HTTP_CODE_OK, + (it.body() as ChatOverall).ocs!!.data!! + ) } - return@map Pair( - HTTP_CODE_OK, - (it.body() as ChatOverall).ocs!!.data!! - ) - } - - HTTP_CODE_NOT_MODIFIED -> { - Log.d(TAG, "getMessagesFromServer HTTP_CODE_NOT_MODIFIED") + HTTP_CODE_NOT_MODIFIED -> { + Log.d(TAG, "getMessagesFromServer HTTP_CODE_NOT_MODIFIED") - return@map Pair( - HTTP_CODE_NOT_MODIFIED, - listOf() - ) - } + return@map Pair( + HTTP_CODE_NOT_MODIFIED, + listOf() + ) + } - HTTP_CODE_PRECONDITION_FAILED -> { - Log.d(TAG, "getMessagesFromServer HTTP_CODE_PRECONDITION_FAILED") + HTTP_CODE_PRECONDITION_FAILED -> { + Log.d(TAG, "getMessagesFromServer HTTP_CODE_PRECONDITION_FAILED") - return@map Pair( - HTTP_CODE_PRECONDITION_FAILED, - listOf() - ) - } + return@map Pair( + HTTP_CODE_PRECONDITION_FAILED, + listOf() + ) + } - else -> { - return@map Pair( - HTTP_CODE_PRECONDITION_FAILED, - listOf() - ) + else -> { + return@map Pair( + HTTP_CODE_PRECONDITION_FAILED, + listOf() + ) + } } } + .blockingSingle() + return result + } catch (e: Exception) { + Log.e(TAG, "Something went wrong when pulling chat messages (attempt: $attempts)", e) + attempts++ + + val newMessageLimit = when (attempts) { + 2 -> 50 + 3 -> 10 + else -> 5 } - .blockingSingle() - return result - } catch (e: Exception) { - Log.e(TAG, "Something went wrong when pulling chat messages", e) + fieldMap["limit"] = newMessageLimit + } } + Log.e(TAG, "All attempts to get messages from server failed") return null } @@ -370,7 +421,12 @@ class OfflineFirstChatRepository @Inject constructor( return null } - val result = getMessagesFromServer(bundle) ?: return listOf() + val result = getMessagesFromServer(bundle) + if (result == null) { + Log.d(TAG, "No result from server") + return null + } + var chatMessagesFromSync: List? = null val fieldMap = bundle.getSerializable(BundleKeys.KEY_FIELD_MAP) as HashMap @@ -471,7 +527,7 @@ class OfflineFirstChatRepository @Inject constructor( ChatMessage.SystemMessageType.CLEARED_CHAT -> { // for lookIntoFuture just deleting everything would be fine. // But lets say we did not open the chat for a while and in between it was cleared. - // We just load the last 100 messages but this don't contain the system message. + // We just load the last messages but this don't contain the system message. // We scroll up and load the system message. Deleting everything is not an option as we // would loose the messages that we want to keep. We only want to // delete the messages and chatBlocks older than the system message. @@ -488,13 +544,12 @@ class OfflineFirstChatRepository @Inject constructor( * 304 is returned when oldest message of chat was queried or when long polling request returned with no * modification. hasHistory is only set to false, when 304 was returned for the the oldest message */ - private fun getHasHistory(statusCode: Int, lookIntoFuture: Boolean): Boolean { - return if (statusCode == HTTP_CODE_NOT_MODIFIED) { + private fun getHasHistory(statusCode: Int, lookIntoFuture: Boolean): Boolean = + if (statusCode == HTTP_CODE_NOT_MODIFIED) { lookIntoFuture } else { true } - } private suspend fun getBlockOfMessage(queriedMessageId: Int?): ChatBlockEntity? { var blockContainingQueriedMessage: ChatBlockEntity? = null @@ -563,7 +618,7 @@ class OfflineFirstChatRepository @Inject constructor( } } - private suspend fun showLast100MessagesBeforeAndEqual(internalConversationId: String, messageId: Long) { + private suspend fun showMessagesBeforeAndEqual(internalConversationId: String, messageId: Long, limit: Int) { suspend fun getMessagesBeforeAndEqual( messageId: Long, internalConversationId: String, @@ -580,7 +635,7 @@ class OfflineFirstChatRepository @Inject constructor( val list = getMessagesBeforeAndEqual( messageId, internalConversationId, - 100 + limit ) if (list.isNotEmpty()) { @@ -589,7 +644,7 @@ class OfflineFirstChatRepository @Inject constructor( } } - private suspend fun showLast100MessagesBefore(internalConversationId: String, messageId: Long) { + private suspend fun showMessagesBefore(internalConversationId: String, messageId: Long, limit: Int) { suspend fun getMessagesBefore( messageId: Long, internalConversationId: String, @@ -606,7 +661,7 @@ class OfflineFirstChatRepository @Inject constructor( val list = getMessagesBefore( messageId, internalConversationId, - 100 + limit ) if (list.isNotEmpty()) { @@ -638,5 +693,6 @@ class OfflineFirstChatRepository @Inject constructor( private const val HTTP_CODE_PRECONDITION_FAILED = 412 private const val HALF_SECOND = 500L private const val DELAY_TO_ENSURE_MESSAGES_ARE_ADDED: Long = 100 + private const val DEFAULT_MESSAGES_LIMIT = 100 } } From b1d6086684e67dce90c18f6cb4421a9328b69147 Mon Sep 17 00:00:00 2001 From: Marcel Hibbe Date: Tue, 1 Oct 2024 15:54:09 +0200 Subject: [PATCH 194/885] load conversation from DB first, then update by request if connection is available Signed-off-by: Marcel Hibbe --- .../talk/chat/viewmodels/ChatViewModel.kt | 2 +- .../data/OfflineConversationsRepository.kt | 2 +- .../OfflineFirstConversationsRepository.kt | 20 ++++++++++--------- 3 files changed, 13 insertions(+), 11 deletions(-) diff --git a/app/src/main/java/com/nextcloud/talk/chat/viewmodels/ChatViewModel.kt b/app/src/main/java/com/nextcloud/talk/chat/viewmodels/ChatViewModel.kt index d0c6659968..39a09bdcb0 100644 --- a/app/src/main/java/com/nextcloud/talk/chat/viewmodels/ChatViewModel.kt +++ b/app/src/main/java/com/nextcloud/talk/chat/viewmodels/ChatViewModel.kt @@ -225,7 +225,7 @@ class ChatViewModel @Inject constructor( fun getRoom(user: User, token: String) { _getRoomViewState.value = GetRoomStartState - conversationRepository.getConversationSettings(token) + conversationRepository.getRoom(token) // chatNetworkDataSource.getRoom(user, token) // .subscribeOn(Schedulers.io()) diff --git a/app/src/main/java/com/nextcloud/talk/conversationlist/data/OfflineConversationsRepository.kt b/app/src/main/java/com/nextcloud/talk/conversationlist/data/OfflineConversationsRepository.kt index a264a84eee..92591fe4e1 100644 --- a/app/src/main/java/com/nextcloud/talk/conversationlist/data/OfflineConversationsRepository.kt +++ b/app/src/main/java/com/nextcloud/talk/conversationlist/data/OfflineConversationsRepository.kt @@ -35,5 +35,5 @@ interface OfflineConversationsRepository { * Called once onStart to emit a conversation to [conversationFlow] * to be handled asynchronously. */ - fun getConversationSettings(roomToken: String): Job + fun getRoom(roomToken: String): Job } diff --git a/app/src/main/java/com/nextcloud/talk/conversationlist/data/network/OfflineFirstConversationsRepository.kt b/app/src/main/java/com/nextcloud/talk/conversationlist/data/network/OfflineFirstConversationsRepository.kt index 1258ee649e..c9d2762018 100644 --- a/app/src/main/java/com/nextcloud/talk/conversationlist/data/network/OfflineFirstConversationsRepository.kt +++ b/app/src/main/java/com/nextcloud/talk/conversationlist/data/network/OfflineFirstConversationsRepository.kt @@ -56,17 +56,19 @@ class OfflineFirstConversationsRepository @Inject constructor( override fun getRooms(): Job = scope.launch { - val resultsFromSync = sync() - if (!resultsFromSync.isNullOrEmpty()) { - val conversations = resultsFromSync.map(ConversationEntity::asModel) - _roomListFlow.emit(conversations) - } else { - val conversationsFromDb = getListOfConversations(user.id!!) - _roomListFlow.emit(conversationsFromDb) + val initialConversationModels = getListOfConversations(user.id!!) + _roomListFlow.emit(initialConversationModels) + + if (monitor.isOnline.first()) { + val conversationEntitiesFromSync = getRoomsFromServer() + if (!conversationEntitiesFromSync.isNullOrEmpty()) { + val conversationModelsFromSync = conversationEntitiesFromSync.map(ConversationEntity::asModel) + _roomListFlow.emit(conversationModelsFromSync) + } } } - override fun getConversationSettings(roomToken: String): Job = + override fun getRoom(roomToken: String): Job = scope.launch { val id = user.id!! val model = getConversation(id, roomToken) @@ -100,7 +102,7 @@ class OfflineFirstConversationsRepository @Inject constructor( } } - private suspend fun sync(): List? { + private suspend fun getRoomsFromServer(): List? { var conversationsFromSync: List? = null if (!monitor.isOnline.first()) { From dc38904d01b0704a6f1e5760592737183807590b Mon Sep 17 00:00:00 2001 From: Marcel Hibbe Date: Wed, 2 Oct 2024 15:07:37 +0200 Subject: [PATCH 195/885] delay progress bar delay progress bar for one second before showing up for slow connection Signed-off-by: Marcel Hibbe --- .../main/java/com/nextcloud/talk/chat/ChatActivity.kt | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/app/src/main/java/com/nextcloud/talk/chat/ChatActivity.kt b/app/src/main/java/com/nextcloud/talk/chat/ChatActivity.kt index 14caa42fc3..a1587d667f 100644 --- a/app/src/main/java/com/nextcloud/talk/chat/ChatActivity.kt +++ b/app/src/main/java/com/nextcloud/talk/chat/ChatActivity.kt @@ -183,6 +183,7 @@ import io.reactivex.Observer import io.reactivex.disposables.Disposable import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.delay import kotlinx.coroutines.flow.collect import kotlinx.coroutines.flow.onEach import kotlinx.coroutines.launch @@ -416,7 +417,12 @@ class ChatActivity : messageInputViewModel = ViewModelProvider(this, viewModelFactory)[MessageInputViewModel::class.java] - binding.progressBar.visibility = View.VISIBLE + this.lifecycleScope.launch { + delay(DELAY_TO_SHOW_PROGRESS_BAR) + if (adapter?.isEmpty == true) { + binding.progressBar.visibility = View.VISIBLE + } + } onBackPressedDispatcher.addCallback(this, onBackPressedCallback) @@ -3712,5 +3718,6 @@ class ChatActivity : private const val CURRENT_AUDIO_POSITION_KEY = "CURRENT_AUDIO_POSITION" private const val CURRENT_AUDIO_WAS_PLAYING_KEY = "CURRENT_AUDIO_PLAYING" private const val RESUME_AUDIO_TAG = "RESUME_AUDIO_TAG" + private const val DELAY_TO_SHOW_PROGRESS_BAR = 1000L } } From 3d37cc083190f6064639e43ede48db99360733a8 Mon Sep 17 00:00:00 2001 From: Marcel Hibbe Date: Wed, 9 Oct 2024 16:21:53 +0200 Subject: [PATCH 196/885] only do initial request if newestMessageIdFromDb is lower than lastReadMessage from conversation If conversation has a newer message id than DB then an online request is necessary If conversation has an older message id than DB then an online request is not necessary (this could happen when updating of DB is implemented for push notification, not yet done). If conversation has the same message id like DB than request can be skipped Signed-off-by: Marcel Hibbe --- .../network/OfflineFirstChatRepository.kt | 35 +++++++++++++------ 1 file changed, 25 insertions(+), 10 deletions(-) diff --git a/app/src/main/java/com/nextcloud/talk/chat/data/network/OfflineFirstChatRepository.kt b/app/src/main/java/com/nextcloud/talk/chat/data/network/OfflineFirstChatRepository.kt index 262188b030..80fd70c846 100644 --- a/app/src/main/java/com/nextcloud/talk/chat/data/network/OfflineFirstChatRepository.kt +++ b/app/src/main/java/com/nextcloud/talk/chat/data/network/OfflineFirstChatRepository.kt @@ -114,13 +114,28 @@ class OfflineFirstChatRepository @Inject constructor( Log.d(TAG, "conversationModel.lastReadMessage:" + conversationModel.lastReadMessage) - var newestMessageId = chatDao.getNewestMessageId(internalConversationId) - Log.d(TAG, "newestMessageId: $newestMessageId") - if (newestMessageId.toInt() == 0) { + var newestMessageIdFromDb = chatDao.getNewestMessageId(internalConversationId) + Log.d(TAG, "newestMessageId: $newestMessageIdFromDb") + if (newestMessageIdFromDb.toInt() == 0) { Log.d(TAG, "newestMessageId from db was 0. Must only happen when chat is loaded for the first time") } - if (conversationModel.lastReadMessage.toLong() != newestMessageId) { + // infos from Ivan to + // "Why is it lastReadMessageId that is checked? Shouldn't it be lastMessage instead? + // https://github.com/nextcloud/talk-ios/blob/master/NextcloudTalk/NCChatController.m#L473 " + // + // answer: + // "I guess we do it with the lastReadMessageId in order to place the separator of "Unread messages" when you enter the chat" + // + // if it turns out lastMessage can be used instead lastReadMessage, use this: + // val doInitialLoadFromServer = conversationModel.lastMessage?.let { + // newestMessageIdFromDb < it.id + // } ?: true + // Log.d(TAG, "doInitialLoadFromServer:$doInitialLoadFromServer") + // + // if (doInitialLoadFromServer) { + + if (newestMessageIdFromDb < conversationModel.lastReadMessage.toLong()) { Log.d(TAG, "An online request is made because chat is not up to date") // set up field map to load the newest messages @@ -139,17 +154,17 @@ class OfflineFirstChatRepository @Inject constructor( Log.e(TAG, "initial loading of messages failed") } - newestMessageId = chatDao.getNewestMessageId(internalConversationId) - Log.d(TAG, "newestMessageId after sync: $newestMessageId") + newestMessageIdFromDb = chatDao.getNewestMessageId(internalConversationId) + Log.d(TAG, "newestMessageId after sync: $newestMessageIdFromDb") } else { Log.d(TAG, "Initial online request is skipped because offline messages are up to date") } - val chatBlock = getBlockOfMessage(newestMessageId.toInt()) + val chatBlock = getBlockOfMessage(newestMessageIdFromDb.toInt()) val amountBetween = chatDao.getCountBetweenMessageIds( internalConversationId, - newestMessageId, + newestMessageIdFromDb, chatBlock!!.oldestMessageId ) @@ -163,7 +178,7 @@ class OfflineFirstChatRepository @Inject constructor( showMessagesBeforeAndEqual( internalConversationId, - newestMessageId, + newestMessageIdFromDb, limit ) @@ -172,7 +187,7 @@ class OfflineFirstChatRepository @Inject constructor( delay(DELAY_TO_ENSURE_MESSAGES_ARE_ADDED) updateUiForLastCommonRead() - updateUiForLastReadMessage(newestMessageId) + updateUiForLastReadMessage(newestMessageIdFromDb) initMessagePolling() } From adf18020c1750095a6490aadb96034dc353eb04c Mon Sep 17 00:00:00 2001 From: Marcel Hibbe Date: Wed, 16 Oct 2024 14:20:45 +0200 Subject: [PATCH 197/885] Fix unintended deletion of conversations (+related messages&chatBlocks) Mistake was, that the conversations from DB and sync could differ due to values. E.g. when a user changed the status, the conversations from DB and sync would differ. So there were conversations (+related messages&chatBlocks) deleted sometimes. This caused bugs that when entering a chat, all data was loaded again. In the previous implementation (before this PR), this error was only visible in the UI when you were offline (in this case, nothing was displayed!). To fix the bug, only the internalId's are compared. Signed-off-by: Marcel Hibbe --- .../data/network/OfflineFirstConversationsRepository.kt | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/app/src/main/java/com/nextcloud/talk/conversationlist/data/network/OfflineFirstConversationsRepository.kt b/app/src/main/java/com/nextcloud/talk/conversationlist/data/network/OfflineFirstConversationsRepository.kt index c9d2762018..f02eeff402 100644 --- a/app/src/main/java/com/nextcloud/talk/conversationlist/data/network/OfflineFirstConversationsRepository.kt +++ b/app/src/main/java/com/nextcloud/talk/conversationlist/data/network/OfflineFirstConversationsRepository.kt @@ -131,10 +131,12 @@ class OfflineFirstConversationsRepository @Inject constructor( } private suspend fun deleteLeftConversations(conversationsFromSync: List) { + val conversationsFromSyncIds = conversationsFromSync.map { it.internalId }.toSet() val oldConversationsFromDb = dao.getConversationsForUser(user.id!!).first() - val conversationsToDelete = oldConversationsFromDb.filterNot { conversationsFromSync.contains(it) } - val conversationIdsToDelete = conversationsToDelete.map { it.internalId } + val conversationIdsToDelete = oldConversationsFromDb + .map { it.internalId } + .filterNot { it in conversationsFromSyncIds } dao.deleteConversations(conversationIdsToDelete) } From 7eb8b9fa707e024afaf2fee35c0bdbdc0fa73bdb Mon Sep 17 00:00:00 2001 From: Marcel Hibbe Date: Wed, 16 Oct 2024 15:20:23 +0200 Subject: [PATCH 198/885] extract getCappedMessagesAmountOfChatBlock Signed-off-by: Marcel Hibbe --- .../network/OfflineFirstChatRepository.kt | 35 +++++++++++-------- 1 file changed, 20 insertions(+), 15 deletions(-) diff --git a/app/src/main/java/com/nextcloud/talk/chat/data/network/OfflineFirstChatRepository.kt b/app/src/main/java/com/nextcloud/talk/chat/data/network/OfflineFirstChatRepository.kt index 80fd70c846..bb3b2dfc20 100644 --- a/app/src/main/java/com/nextcloud/talk/chat/data/network/OfflineFirstChatRepository.kt +++ b/app/src/main/java/com/nextcloud/talk/chat/data/network/OfflineFirstChatRepository.kt @@ -160,21 +160,7 @@ class OfflineFirstChatRepository @Inject constructor( Log.d(TAG, "Initial online request is skipped because offline messages are up to date") } - val chatBlock = getBlockOfMessage(newestMessageIdFromDb.toInt()) - - val amountBetween = chatDao.getCountBetweenMessageIds( - internalConversationId, - newestMessageIdFromDb, - chatBlock!!.oldestMessageId - ) - - Log.d(TAG, "amount of messages between newestMessageId and oldest message of same ChatBlock:$amountBetween") - val limit = if (amountBetween > DEFAULT_MESSAGES_LIMIT) { - DEFAULT_MESSAGES_LIMIT - } else { - amountBetween - } - Log.d(TAG, "limit of messages to load for UI (max 100 to ensure performance is okay):$limit") + val limit = getCappedMessagesAmountOfChatBlock(newestMessageIdFromDb) showMessagesBeforeAndEqual( internalConversationId, @@ -192,6 +178,25 @@ class OfflineFirstChatRepository @Inject constructor( initMessagePolling() } + private suspend fun getCappedMessagesAmountOfChatBlock(messageId: Long): Int { + val chatBlock = getBlockOfMessage(messageId.toInt()) + + val amountBetween = chatDao.getCountBetweenMessageIds( + internalConversationId, + messageId, + chatBlock!!.oldestMessageId + ) + + Log.d(TAG, "amount of messages between newestMessageId and oldest message of same ChatBlock:$amountBetween") + val limit = if (amountBetween > DEFAULT_MESSAGES_LIMIT) { + DEFAULT_MESSAGES_LIMIT + } else { + amountBetween + } + Log.d(TAG, "limit of messages to load for UI (max 100 to ensure performance is okay):$limit") + return limit + } + private suspend fun updateUiForLastReadMessage(newestMessageId: Long) { val scrollToLastRead = conversationModel.lastReadMessage.toLong() < newestMessageId if (scrollToLastRead) { From c81b1fa62f190ab4ea5d5dfc69780f38237ac5f0 Mon Sep 17 00:00:00 2001 From: Marcel Hibbe Date: Wed, 16 Oct 2024 16:11:26 +0200 Subject: [PATCH 199/885] pass newestMessageIdFromDb to initMessagePolling Signed-off-by: Marcel Hibbe --- .../nextcloud/talk/chat/data/ChatMessageRepository.kt | 4 +--- .../talk/chat/data/network/OfflineFirstChatRepository.kt | 9 +++++---- 2 files changed, 6 insertions(+), 7 deletions(-) diff --git a/app/src/main/java/com/nextcloud/talk/chat/data/ChatMessageRepository.kt b/app/src/main/java/com/nextcloud/talk/chat/data/ChatMessageRepository.kt index d39fb85410..a55a458031 100644 --- a/app/src/main/java/com/nextcloud/talk/chat/data/ChatMessageRepository.kt +++ b/app/src/main/java/com/nextcloud/talk/chat/data/ChatMessageRepository.kt @@ -56,10 +56,8 @@ interface ChatMessageRepository : LifecycleAwareManager { * Long polls the server for any updates to the chat, if found, it synchronizes * the database with the server and emits the new messages to [messageFlow], * else it simply retries after timeout. - * - * [withNetworkParams] credentials and url. */ - fun initMessagePolling(): Job + fun initMessagePolling(initialMessageId: Long): Job /** * Gets a individual message. diff --git a/app/src/main/java/com/nextcloud/talk/chat/data/network/OfflineFirstChatRepository.kt b/app/src/main/java/com/nextcloud/talk/chat/data/network/OfflineFirstChatRepository.kt index bb3b2dfc20..012428ed8c 100644 --- a/app/src/main/java/com/nextcloud/talk/chat/data/network/OfflineFirstChatRepository.kt +++ b/app/src/main/java/com/nextcloud/talk/chat/data/network/OfflineFirstChatRepository.kt @@ -158,6 +158,8 @@ class OfflineFirstChatRepository @Inject constructor( Log.d(TAG, "newestMessageId after sync: $newestMessageIdFromDb") } else { Log.d(TAG, "Initial online request is skipped because offline messages are up to date") + // if conversationModel was not up to date and there are new messages, they will just get pulled with + // look into future.. Old messages will be displayed immediately beforehand. } val limit = getCappedMessagesAmountOfChatBlock(newestMessageIdFromDb) @@ -175,7 +177,7 @@ class OfflineFirstChatRepository @Inject constructor( updateUiForLastCommonRead() updateUiForLastReadMessage(newestMessageIdFromDb) - initMessagePolling() + initMessagePolling(newestMessageIdFromDb) } private suspend fun getCappedMessagesAmountOfChatBlock(messageId: Long): Int { @@ -240,18 +242,17 @@ class OfflineFirstChatRepository @Inject constructor( updateUiForLastCommonRead() } - override fun initMessagePolling(): Job = + override fun initMessagePolling(initialMessageId: Long): Job = scope.launch { Log.d(TAG, "---- initMessagePolling ------------") - val initialMessageId = chatDao.getNewestMessageId(internalConversationId).toInt() Log.d(TAG, "newestMessage: $initialMessageId") var fieldMap = getFieldMap( lookIntoFuture = true, includeLastKnown = false, setReadMarker = true, - lastKnown = initialMessageId + lastKnown = initialMessageId.toInt() ) val networkParams = Bundle() From 7e3a4e4a83c274b0e7bb0d21ce98d45010976813 Mon Sep 17 00:00:00 2001 From: Marcel Hibbe Date: Thu, 17 Oct 2024 11:54:02 +0200 Subject: [PATCH 200/885] refactoring and logging Signed-off-by: Marcel Hibbe --- .../com/nextcloud/talk/chat/ChatActivity.kt | 133 +++++++++--------- .../network/OfflineFirstChatRepository.kt | 57 ++++---- 2 files changed, 93 insertions(+), 97 deletions(-) diff --git a/app/src/main/java/com/nextcloud/talk/chat/ChatActivity.kt b/app/src/main/java/com/nextcloud/talk/chat/ChatActivity.kt index a1587d667f..2670aac1f7 100644 --- a/app/src/main/java/com/nextcloud/talk/chat/ChatActivity.kt +++ b/app/src/main/java/com/nextcloud/talk/chat/ChatActivity.kt @@ -1250,9 +1250,7 @@ class ChatActivity : @Suppress("MagicNumber", "LongMethod") private fun updateTypingIndicator() { - fun ellipsize(text: String): String { - return DisplayUtils.ellipsize(text, TYPING_INDICATOR_MAX_NAME_LENGTH) - } + fun ellipsize(text: String): String = DisplayUtils.ellipsize(text, TYPING_INDICATOR_MAX_NAME_LENGTH) val participantNames = ArrayList() @@ -1326,10 +1324,9 @@ class ChatActivity : } } - private fun isTypingStatusEnabled(): Boolean { - return webSocketInstance != null && + private fun isTypingStatusEnabled(): Boolean = + webSocketInstance != null && !CapabilitiesUtil.isTypingStatusPrivate(conversationUser!!) - } private fun setupSwipeToReply() { if (this::participantPermissions.isInitialized && @@ -1428,15 +1425,18 @@ class ChatActivity : } fun isOneToOneConversation() = - currentConversation != null && currentConversation?.type != null && + currentConversation != null && + currentConversation?.type != null && currentConversation?.type == ConversationEnums.ConversationType.ROOM_TYPE_ONE_TO_ONE_CALL private fun isGroupConversation() = - currentConversation != null && currentConversation?.type != null && + currentConversation != null && + currentConversation?.type != null && currentConversation?.type == ConversationEnums.ConversationType.ROOM_GROUP_CALL private fun isPublicConversation() = - currentConversation != null && currentConversation?.type != null && + currentConversation != null && + currentConversation?.type != null && currentConversation?.type == ConversationEnums.ConversationType.ROOM_PUBLIC_CALL private fun updateRoomTimerHandler() { @@ -1674,11 +1674,10 @@ class ChatActivity : adapter?.notifyDataSetChanged() } - private fun isChildOfExpandableSystemMessage(chatMessage: ChatMessage): Boolean { - return isSystemMessage(chatMessage) && + private fun isChildOfExpandableSystemMessage(chatMessage: ChatMessage): Boolean = + isSystemMessage(chatMessage) && !chatMessage.expandableParent && chatMessage.lastItemOfExpandableGroup != 0 - } @SuppressLint("NotifyDataSetChanged") override fun expandSystemMessage(chatMessageToExpand: ChatMessage) { @@ -1764,12 +1763,11 @@ class ChatActivity : } } - fun isRecordAudioPermissionGranted(): Boolean { - return PermissionChecker.checkSelfPermission( + fun isRecordAudioPermissionGranted(): Boolean = + PermissionChecker.checkSelfPermission( context, Manifest.permission.RECORD_AUDIO ) == PERMISSION_GRANTED - } fun requestRecordAudioPermissions() { requestPermissions( @@ -1876,11 +1874,10 @@ class ChatActivity : } } - private fun isReadOnlyConversation(): Boolean { - return currentConversation?.conversationReadOnlyState != null && + private fun isReadOnlyConversation(): Boolean = + currentConversation?.conversationReadOnlyState != null && currentConversation?.conversationReadOnlyState == ConversationEnums.ConversationReadOnlyState.CONVERSATION_READ_ONLY - } private fun checkLobbyState() { if (currentConversation != null && @@ -1896,7 +1893,8 @@ class ChatActivity : sb.append(resources!!.getText(R.string.nc_lobby_waiting)) .append("\n\n") - if (currentConversation?.lobbyTimer != null && currentConversation?.lobbyTimer != + if (currentConversation?.lobbyTimer != null && + currentConversation?.lobbyTimer != 0L ) { val timestampMS = (currentConversation?.lobbyTimer ?: 0) * DateConstants.SECOND_DIVIDER @@ -2095,7 +2093,7 @@ class ChatActivity : if (position != null && position >= 0) { binding.messagesListView.scrollToPosition(position) } else { - // TODO show error that we don't have that message? + Log.d(TAG, "message $messageId that should be scrolled to was not found (scrollToMessageWithId)") } } @@ -2107,6 +2105,12 @@ class ChatActivity : position, binding.messagesListView.height / 2 ) + } else { + Log.d( + TAG, + "message $messageId that should be scrolled to was not found " + + "(scrollToAndCenterMessageWithId)" + ) } } } @@ -2270,11 +2274,10 @@ class ChatActivity : startActivity(intent) } - private fun validSessionId(): Boolean { - return currentConversation != null && + private fun validSessionId(): Boolean = + currentConversation != null && sessionIdAfterRoomJoined?.isNotEmpty() == true && sessionIdAfterRoomJoined != "0" - } @Suppress("Detekt.TooGenericExceptionCaught") private fun cancelNotificationsForCurrentConversation() { @@ -2327,14 +2330,11 @@ class ChatActivity : } } - private fun isActivityNotChangingConfigurations(): Boolean { - return !isChangingConfigurations - } + private fun isActivityNotChangingConfigurations(): Boolean = !isChangingConfigurations - private fun isNotInCall(): Boolean { - return !ApplicationWideCurrentRoomHolder.getInstance().isInCall && + private fun isNotInCall(): Boolean = + !ApplicationWideCurrentRoomHolder.getInstance().isInCall && !ApplicationWideCurrentRoomHolder.getInstance().isDialing - } private fun setActionBarTitle() { val title = binding.chatToolbar.findViewById(R.id.chat_toolbar_title) @@ -2775,11 +2775,10 @@ class ChatActivity : } } - private fun isSameDayNonSystemMessages(messageLeft: ChatMessage, messageRight: ChatMessage): Boolean { - return TextUtils.isEmpty(messageLeft.systemMessage) && + private fun isSameDayNonSystemMessages(messageLeft: ChatMessage, messageRight: ChatMessage): Boolean = + TextUtils.isEmpty(messageLeft.systemMessage) && TextUtils.isEmpty(messageRight.systemMessage) && DateFormatter.isSameDay(messageLeft.createdAt, messageRight.createdAt) - } override fun onLoadMore(page: Int, totalItemsCount: Int) { val id = ( @@ -2799,15 +2798,14 @@ class ChatActivity : ) } - override fun format(date: Date): String { - return if (DateFormatter.isToday(date)) { + override fun format(date: Date): String = + if (DateFormatter.isToday(date)) { resources!!.getString(R.string.nc_date_header_today) } else if (DateFormatter.isYesterday(date)) { resources!!.getString(R.string.nc_date_header_yesterday) } else { DateFormatter.format(date, DateFormatter.Template.STRING_DAY_MONTH_YEAR) } - } override fun onCreateOptionsMenu(menu: Menu): Boolean { super.onCreateOptionsMenu(menu) @@ -2869,8 +2867,8 @@ class ChatActivity : return true } - override fun onOptionsItemSelected(item: MenuItem): Boolean { - return when (item.itemId) { + override fun onOptionsItemSelected(item: MenuItem): Boolean = + when (item.itemId) { R.id.conversation_video_call -> { startACall(false, false) true @@ -2898,7 +2896,6 @@ class ChatActivity : else -> super.onOptionsItemSelected(item) } - } private fun showSharedItems() { val intent = Intent(this, SharedItemsActivity::class.java) @@ -2960,25 +2957,23 @@ class ChatActivity : return chatMessageMap.values.toList() } - private fun isInfoMessageAboutDeletion(currentMessage: MutableMap.MutableEntry): Boolean { - return currentMessage.value.parentMessageId != null && currentMessage.value.systemMessageType == ChatMessage - .SystemMessageType.MESSAGE_DELETED - } + private fun isInfoMessageAboutDeletion(currentMessage: MutableMap.MutableEntry): Boolean = + currentMessage.value.parentMessageId != null && + currentMessage.value.systemMessageType == ChatMessage + .SystemMessageType.MESSAGE_DELETED - private fun isReactionsMessage(currentMessage: MutableMap.MutableEntry): Boolean { - return currentMessage.value.systemMessageType == ChatMessage.SystemMessageType.REACTION || + private fun isReactionsMessage(currentMessage: MutableMap.MutableEntry): Boolean = + currentMessage.value.systemMessageType == ChatMessage.SystemMessageType.REACTION || currentMessage.value.systemMessageType == ChatMessage.SystemMessageType.REACTION_DELETED || currentMessage.value.systemMessageType == ChatMessage.SystemMessageType.REACTION_REVOKED - } - private fun isEditMessage(currentMessage: MutableMap.MutableEntry): Boolean { - return currentMessage.value.parentMessageId != null && currentMessage.value.systemMessageType == ChatMessage - .SystemMessageType.MESSAGE_EDITED - } + private fun isEditMessage(currentMessage: MutableMap.MutableEntry): Boolean = + currentMessage.value.parentMessageId != null && + currentMessage.value.systemMessageType == ChatMessage + .SystemMessageType.MESSAGE_EDITED - private fun isPollVotedMessage(currentMessage: MutableMap.MutableEntry): Boolean { - return currentMessage.value.systemMessageType == ChatMessage.SystemMessageType.POLL_VOTED - } + private fun isPollVotedMessage(currentMessage: MutableMap.MutableEntry): Boolean = + currentMessage.value.systemMessageType == ChatMessage.SystemMessageType.POLL_VOTED private fun startACall(isVoiceOnlyCall: Boolean, callWithoutNotification: Boolean) { currentConversation?.let { @@ -3082,9 +3077,8 @@ class ChatActivity : } } - private fun isSystemMessage(message: ChatMessage): Boolean { - return ChatMessage.MessageType.SYSTEM_MESSAGE == message.getCalculateMessageType() - } + private fun isSystemMessage(message: ChatMessage): Boolean = + ChatMessage.MessageType.SYSTEM_MESSAGE == message.getCalculateMessageType() fun deleteMessage(message: IMessage) { if (!participantPermissions.hasChatPermission()) { @@ -3327,20 +3321,26 @@ class ChatActivity : fileViewerUtils.openFileInFilesApp(link!!, keyID!!) } - private fun hasVisibleItems(message: ChatMessage): Boolean { - return !message.isDeleted || // copy message - message.replyable || // reply to - message.replyable && // reply privately - conversationUser?.userId?.isNotEmpty() == true && conversationUser!!.userId != "?" && + private fun hasVisibleItems(message: ChatMessage): Boolean = + !message.isDeleted || + // copy message + message.replyable || + // reply to + message.replyable && + // reply privately + conversationUser?.userId?.isNotEmpty() == true && + conversationUser!!.userId != "?" && message.user.id.startsWith("users/") && message.user.id.substring(ACTOR_LENGTH) != currentConversation?.actorId && currentConversation?.type != ConversationEnums.ConversationType.ROOM_TYPE_ONE_TO_ONE_CALL || - isShowMessageDeletionButton(message) || // delete - ChatMessage.MessageType.REGULAR_TEXT_MESSAGE == message.getCalculateMessageType() || // forward - message.previousMessageId > NO_PREVIOUS_MESSAGE_ID && // mark as unread + isShowMessageDeletionButton(message) || + // delete + ChatMessage.MessageType.REGULAR_TEXT_MESSAGE == message.getCalculateMessageType() || + // forward + message.previousMessageId > NO_PREVIOUS_MESSAGE_ID && + // mark as unread ChatMessage.MessageType.SYSTEM_MESSAGE != message.getCalculateMessageType() && BuildConfig.DEBUG - } private fun setMessageAsDeleted(message: IMessage?) { val messageTemp = message as ChatMessage @@ -3458,8 +3458,8 @@ class ChatActivity : return isUserAllowedByPrivileges } - override fun hasContentFor(message: ChatMessage, type: Byte): Boolean { - return when (type) { + override fun hasContentFor(message: ChatMessage, type: Byte): Boolean = + when (type) { CONTENT_TYPE_LOCATION -> message.hasGeoLocation() CONTENT_TYPE_VOICE_MESSAGE -> message.isVoiceMessage CONTENT_TYPE_POLL -> message.isPoll() @@ -3470,7 +3470,6 @@ class ChatActivity : else -> false } - } private fun processMostRecentMessage(recent: ChatMessage, chatMessageList: List) { when (recent.systemMessageType) { diff --git a/app/src/main/java/com/nextcloud/talk/chat/data/network/OfflineFirstChatRepository.kt b/app/src/main/java/com/nextcloud/talk/chat/data/network/OfflineFirstChatRepository.kt index 012428ed8c..ea40912da7 100644 --- a/app/src/main/java/com/nextcloud/talk/chat/data/network/OfflineFirstChatRepository.kt +++ b/app/src/main/java/com/nextcloud/talk/chat/data/network/OfflineFirstChatRepository.kt @@ -108,35 +108,36 @@ class OfflineFirstChatRepository @Inject constructor( override fun loadInitialMessages(withNetworkParams: Bundle): Job = scope.launch { Log.d(TAG, "---- loadInitialMessages ------------") - Log.d(TAG, "conversationModel.internalId: " + conversationModel.internalId) - newXChatLastCommonRead = conversationModel.lastCommonReadMessage + Log.d(TAG, "conversationModel.internalId: " + conversationModel.internalId) Log.d(TAG, "conversationModel.lastReadMessage:" + conversationModel.lastReadMessage) var newestMessageIdFromDb = chatDao.getNewestMessageId(internalConversationId) - Log.d(TAG, "newestMessageId: $newestMessageIdFromDb") - if (newestMessageIdFromDb.toInt() == 0) { - Log.d(TAG, "newestMessageId from db was 0. Must only happen when chat is loaded for the first time") - } - - // infos from Ivan to - // "Why is it lastReadMessageId that is checked? Shouldn't it be lastMessage instead? - // https://github.com/nextcloud/talk-ios/blob/master/NextcloudTalk/NCChatController.m#L473 " - // - // answer: - // "I guess we do it with the lastReadMessageId in order to place the separator of "Unread messages" when you enter the chat" - // - // if it turns out lastMessage can be used instead lastReadMessage, use this: - // val doInitialLoadFromServer = conversationModel.lastMessage?.let { - // newestMessageIdFromDb < it.id - // } ?: true - // Log.d(TAG, "doInitialLoadFromServer:$doInitialLoadFromServer") - // - // if (doInitialLoadFromServer) { - - if (newestMessageIdFromDb < conversationModel.lastReadMessage.toLong()) { - Log.d(TAG, "An online request is made because chat is not up to date") + Log.d(TAG, "newestMessageIdFromDb: $newestMessageIdFromDb") + + val weAlreadyHaveSomeOfflineMessages = newestMessageIdFromDb > 0 + val weHaveAtLeastTheLastReadMessage = newestMessageIdFromDb >= conversationModel.lastReadMessage.toLong() + Log.d(TAG, "weAlreadyHaveSomeOfflineMessages:$weAlreadyHaveSomeOfflineMessages") + Log.d(TAG, "weHaveAtLeastTheLastReadMessage:$weHaveAtLeastTheLastReadMessage") + + if (weAlreadyHaveSomeOfflineMessages && weHaveAtLeastTheLastReadMessage) { + Log.d( + TAG, + "Initial online request is skipped because offline messages are up to date" + + " until lastReadMessage" + ) + Log.d(TAG, "For messages newer than lastRead, lookIntoFuture will load them.") + } else { + if (!weAlreadyHaveSomeOfflineMessages) { + Log.d(TAG, "An online request for newest 100 messages is made because offline chat is empty") + } else { + Log.d( + TAG, + "An online request for newest 100 messages is made because we don't have the lastReadMessage " + + "(gaps could be closed by scrolling up to merge the chatblocks)" + ) + } // set up field map to load the newest messages val fieldMap = getFieldMap( @@ -155,11 +156,7 @@ class OfflineFirstChatRepository @Inject constructor( } newestMessageIdFromDb = chatDao.getNewestMessageId(internalConversationId) - Log.d(TAG, "newestMessageId after sync: $newestMessageIdFromDb") - } else { - Log.d(TAG, "Initial online request is skipped because offline messages are up to date") - // if conversationModel was not up to date and there are new messages, they will just get pulled with - // look into future.. Old messages will be displayed immediately beforehand. + Log.d(TAG, "newestMessageIdFromDb after sync: $newestMessageIdFromDb") } val limit = getCappedMessagesAmountOfChatBlock(newestMessageIdFromDb) @@ -367,7 +364,7 @@ class OfflineFirstChatRepository @Inject constructor( .map(ChatMessageEntity::asModel) } - @Suppress("UNCHECKED_CAST") + @Suppress("UNCHECKED_CAST", "MagicNumber") private fun getMessagesFromServer(bundle: Bundle): Pair>? { val fieldMap = bundle.getSerializable(BundleKeys.KEY_FIELD_MAP) as HashMap From f817c20b4edf429f1daa3c9f3de35c2384ddb47a Mon Sep 17 00:00:00 2001 From: Marcel Hibbe Date: Mon, 21 Oct 2024 15:33:25 +0200 Subject: [PATCH 201/885] fix to handle chats without offline messages when connection is lost avoid NPE: java.lang.NullPointerException at com.nextcloud.talk.chat.data.network.OfflineFirstChatRepository.getCappedMessagesAmountOfChatBlock(OfflineFirstChatRepository.kt:186) at com.nextcloud.talk.chat.data.network.OfflineFirstChatRepository.access$getCappedMessagesAmountOfChatBlock(OfflineFirstChatRepository.kt:43) at com.nextcloud.talk.chat.data.network.OfflineFirstChatRepository$loadInitialMessages$1.invokeSuspend(OfflineFirstChatRepository.kt:162) Signed-off-by: Marcel Hibbe --- .../network/OfflineFirstChatRepository.kt | 51 +++++++++++-------- 1 file changed, 29 insertions(+), 22 deletions(-) diff --git a/app/src/main/java/com/nextcloud/talk/chat/data/network/OfflineFirstChatRepository.kt b/app/src/main/java/com/nextcloud/talk/chat/data/network/OfflineFirstChatRepository.kt index ea40912da7..4c52f7f315 100644 --- a/app/src/main/java/com/nextcloud/talk/chat/data/network/OfflineFirstChatRepository.kt +++ b/app/src/main/java/com/nextcloud/talk/chat/data/network/OfflineFirstChatRepository.kt @@ -159,20 +159,22 @@ class OfflineFirstChatRepository @Inject constructor( Log.d(TAG, "newestMessageIdFromDb after sync: $newestMessageIdFromDb") } - val limit = getCappedMessagesAmountOfChatBlock(newestMessageIdFromDb) + if (newestMessageIdFromDb.toInt() != 0) { + val limit = getCappedMessagesAmountOfChatBlock(newestMessageIdFromDb) - showMessagesBeforeAndEqual( - internalConversationId, - newestMessageIdFromDb, - limit - ) + showMessagesBeforeAndEqual( + internalConversationId, + newestMessageIdFromDb, + limit + ) - // delay is a dirty workaround to make sure messages are added to adapter on initial load before dealing - // with them (otherwise there is a race condition). - delay(DELAY_TO_ENSURE_MESSAGES_ARE_ADDED) + // delay is a dirty workaround to make sure messages are added to adapter on initial load before dealing + // with them (otherwise there is a race condition). + delay(DELAY_TO_ENSURE_MESSAGES_ARE_ADDED) - updateUiForLastCommonRead() - updateUiForLastReadMessage(newestMessageIdFromDb) + updateUiForLastCommonRead() + updateUiForLastReadMessage(newestMessageIdFromDb) + } initMessagePolling(newestMessageIdFromDb) } @@ -180,20 +182,25 @@ class OfflineFirstChatRepository @Inject constructor( private suspend fun getCappedMessagesAmountOfChatBlock(messageId: Long): Int { val chatBlock = getBlockOfMessage(messageId.toInt()) - val amountBetween = chatDao.getCountBetweenMessageIds( - internalConversationId, - messageId, - chatBlock!!.oldestMessageId - ) + if (chatBlock != null) { + val amountBetween = chatDao.getCountBetweenMessageIds( + internalConversationId, + messageId, + chatBlock.oldestMessageId + ) - Log.d(TAG, "amount of messages between newestMessageId and oldest message of same ChatBlock:$amountBetween") - val limit = if (amountBetween > DEFAULT_MESSAGES_LIMIT) { - DEFAULT_MESSAGES_LIMIT + Log.d(TAG, "amount of messages between newestMessageId and oldest message of same ChatBlock:$amountBetween") + val limit = if (amountBetween > DEFAULT_MESSAGES_LIMIT) { + DEFAULT_MESSAGES_LIMIT + } else { + amountBetween + } + Log.d(TAG, "limit of messages to load for UI (max 100 to ensure performance is okay):$limit") + return limit } else { - amountBetween + Log.e(TAG, "No chat block found. Returning 0 as limit.") + return 0 } - Log.d(TAG, "limit of messages to load for UI (max 100 to ensure performance is okay):$limit") - return limit } private suspend fun updateUiForLastReadMessage(newestMessageId: Long) { From 867d04a02429626ef2b066dfc592975e663c38c4 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Mon, 21 Oct 2024 15:49:36 +0000 Subject: [PATCH 202/885] fix(deps): update dependency org.junit.vintage:junit-vintage-engine to v5.11.3 Signed-off-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- app/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/build.gradle b/app/build.gradle index ea762f6b34..d7dddc1e8a 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -364,7 +364,7 @@ dependencies { testImplementation "org.mockito.kotlin:mockito-kotlin:$mockitoKotlinVersion" testImplementation "org.jetbrains.kotlinx:kotlinx-coroutines-test:$coroutines_version" - testImplementation 'org.junit.vintage:junit-vintage-engine:5.11.2' + testImplementation 'org.junit.vintage:junit-vintage-engine:5.11.3' } tasks.register('installGitHooks', Copy) { From 9cbfe3ab6fe8aa15c15d657fcade5d9b72c9d94d Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Mon, 21 Oct 2024 20:43:10 +0000 Subject: [PATCH 203/885] fix(deps): update dependency com.google.firebase:firebase-messaging to v24.0.3 Signed-off-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- app/build.gradle | 2 +- gradle/verification-metadata.xml | 8 ++++++++ 2 files changed, 9 insertions(+), 1 deletion(-) diff --git a/app/build.gradle b/app/build.gradle index d7dddc1e8a..97aadf546c 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -308,7 +308,7 @@ dependencies { implementation 'com.github.nextcloud-deps:android-talk-webrtc:121.6167.0' gplayImplementation 'com.google.android.gms:play-services-base:18.5.0' - gplayImplementation "com.google.firebase:firebase-messaging:24.0.2" + gplayImplementation "com.google.firebase:firebase-messaging:24.0.3" //compose implementation(platform("androidx.compose:compose-bom:2024.10.00")) diff --git a/gradle/verification-metadata.xml b/gradle/verification-metadata.xml index 470ad71101..f34f146c3b 100644 --- a/gradle/verification-metadata.xml +++ b/gradle/verification-metadata.xml @@ -5213,6 +5213,14 @@ + + + + + + + + From 4705469f5f1638a8de8df677db6da0d9d46877a4 Mon Sep 17 00:00:00 2001 From: Nextcloud bot Date: Tue, 22 Oct 2024 02:56:30 +0000 Subject: [PATCH 204/885] Fix(l10n): Update translations from Transifex Signed-off-by: Nextcloud bot --- app/src/main/res/values-ar/strings.xml | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/app/src/main/res/values-ar/strings.xml b/app/src/main/res/values-ar/strings.xml index edccf1dcfc..f052ca0642 100644 --- a/app/src/main/res/values-ar/strings.xml +++ b/app/src/main/res/values-ar/strings.xml @@ -174,7 +174,7 @@ أرسل رسالة الحساب الحالي خادوم - هل تطبيق إشعارات الخادوم مُثبّت؟ + هل تم تثبيت تطبيق إشعارات الخادم؟ مستخدم هل حالة المُستخدِم مُمكّنة؟ إصدار أندرويد @@ -198,8 +198,8 @@ خدمات متجر التطبيقات من قوقل Google play متاحة آخر تسجيل لعملية إدخال push في وكيل الإدخال push proxy لم يتم التسجيل بعدُ في وكيل الإدخال push proxy - آخر تسجيل لعملية إدخال push في الخادوم - لم يتم التسجيل بعدُ في الخادوم + آخر تسجيل لعملية إدخال push في الخادم + لم يتم التسجيل بعدُ في الخادم معلومات وصفية توليد تقرير نظامي هل قناة الإشعار بالمكالمات مُمكّنة؟ @@ -207,13 +207,13 @@ إذونات الإشعارات الهاتف رقم إصدار خادوم \"المحادثة\" Talk - رقم إصدار الخادوم + رقم إصدار الخادم خارجي داخلي وضعية إرسال الإشارات كلمة المرور غير صحيحة وضع الصيانة - الخادوم حالياً في وضع الصيانة + الخادم حالياً في وضع الصيانة التطبيق غير مُحدَّث التطبيق قديم جدًا ولم يعد مدعوماً من قبل هذا الخادوم. يُرجى التحديث. تحديث @@ -397,7 +397,7 @@ لقد قمت بإرسال تصويتٍ. %1$s أرسَلَ رسالةً صوتيةً. لقد قُمت بإرسال رسالةٍ صوتيةٍ. - إفحَص الاتصال بالخادوم + إفحَص الاتصال بالخادم الرجاء ترقية %1$s قاعدة البيانات الخاصة بك فشل في استيراد حساب محدد الرابط إلى %1$s واجهتك على الوب عند فتحها في المتصفح @@ -408,8 +408,8 @@ الرجاء إخراج %1$sمن الصيانة الرجاء إنهاء %1$s التثبيت الخاص بك إختبار الاتصال - الخادوم ليس فيه تطبيق Talk مدعوم - عنوان الخادوم https://… + الخادم ليس فيه تطبيق Talk مدعوم + عنوان الخادم https://… %1$s يعمل فقط مع %2$s 13 وأكثر عَيِّن كلمة مرور جديدة تعيين كلمة المرور @@ -457,7 +457,7 @@ أمان الشاشة نسخة الخادوم قديمةٌ جداً ولن يتم توفير الدعم لها في الإصدارت القادمة! نسخة الخادوم قديمةٌ جداً وغير مدعومة من هذه النسخة من تطبيق الأندرويد - خادوم غير مدعوم + خادم غير مدعوم تم تعيين توفير شحن البطارية ليلي استخدم النظام الافتراضي @@ -557,7 +557,7 @@ حفظ قم فقط بالمزامنة مع الخوادم الموثوقة المتحدة - يراه فقط المستخدِمون على هذا الخادوم و الضيوف + يراه فقط المستخدِمون على هذا الخادم و الضيوف محلي يراه فقط المستخدِمون الذين أمكن مطابقة أرقام هواتفهم عبر تطبيق المحادثة Talk على الهاتف النقّال خاص From 498a1274d9a9e9c1aa3620613d901e506e83d79a Mon Sep 17 00:00:00 2001 From: rapterjet2004 Date: Thu, 19 Sep 2024 06:22:07 -0500 Subject: [PATCH 205/885] git Signed-off-by: rapterjet2004 --- .idea/inspectionProfiles/ktlint.xml | 4 ++ .../messages/TemporaryMessageViewHolder.kt | 59 +++++++++++++++++++ .../com/nextcloud/talk/chat/ChatActivity.kt | 14 +++++ .../res/layout/item_temporary_message.xml | 47 +++++++++++++++ 4 files changed, 124 insertions(+) create mode 100644 app/src/main/java/com/nextcloud/talk/adapters/messages/TemporaryMessageViewHolder.kt create mode 100644 app/src/main/res/layout/item_temporary_message.xml diff --git a/.idea/inspectionProfiles/ktlint.xml b/.idea/inspectionProfiles/ktlint.xml index e8f89f3ed2..51c63581ed 100644 --- a/.idea/inspectionProfiles/ktlint.xml +++ b/.idea/inspectionProfiles/ktlint.xml @@ -3,15 +3,19 @@ + + + + + From 9457e23da09822e00ef510d8856ac5939875d51e Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Thu, 31 Oct 2024 02:29:22 +0000 Subject: [PATCH 267/885] Update lifecycleVersion to v2.8.7 Signed-off-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- app/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/build.gradle b/app/build.gradle index 07c093c808..0ecd811efa 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -157,7 +157,7 @@ ext { daggerVersion = "2.52" emojiVersion = "1.5.0" fidoVersion = "4.1.0-patch2" - lifecycleVersion = '2.8.6' + lifecycleVersion = '2.8.7' okhttpVersion = "4.12.0" markwonVersion = "4.6.2" materialDialogsVersion = "3.3.0" From 7f74a1a3830988d3fa813ce1f12ebb88546e2687 Mon Sep 17 00:00:00 2001 From: Nextcloud bot Date: Thu, 31 Oct 2024 02:51:57 +0000 Subject: [PATCH 268/885] Fix(l10n): Update translations from Transifex Signed-off-by: Nextcloud bot --- app/src/main/res/values-ru/strings.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/src/main/res/values-ru/strings.xml b/app/src/main/res/values-ru/strings.xml index 9e8674452b..33f81c831a 100644 --- a/app/src/main/res/values-ru/strings.xml +++ b/app/src/main/res/values-ru/strings.xml @@ -156,7 +156,7 @@ Удалить Сообщение удалено, но его содержимое могло быть прочитано другими службами Пользователь %1$s был удален - Сместить с поста модератора + Исключить из модераторов Запись голосового сообщения Отправить сообщение Текущая учётная запись From 7eb793686b5256b14296728c2ee4fbb632288533 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Thu, 31 Oct 2024 05:21:30 +0000 Subject: [PATCH 269/885] Update androidxCameraVersion to v1.4.0 Signed-off-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- app/build.gradle | 2 +- gradle/verification-metadata.xml | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/app/build.gradle b/app/build.gradle index 0ecd811efa..bb92bf3edb 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -152,7 +152,7 @@ kapt { } ext { - androidxCameraVersion = "1.3.4" + androidxCameraVersion = "1.4.0" coilKtVersion = "2.7.0" daggerVersion = "2.52" emojiVersion = "1.5.0" diff --git a/gradle/verification-metadata.xml b/gradle/verification-metadata.xml index 6286a6bb22..25efac524d 100644 --- a/gradle/verification-metadata.xml +++ b/gradle/verification-metadata.xml @@ -163,6 +163,7 @@ + From 114c4143072379af69b699accdad37baf27b57b6 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Thu, 31 Oct 2024 05:23:02 +0000 Subject: [PATCH 270/885] Update dependency androidx.constraintlayout:constraintlayout to v2.2.0 Signed-off-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- app/build.gradle | 2 +- gradle/verification-metadata.xml | 7 +++++++ 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/app/build.gradle b/app/build.gradle index 0ecd811efa..e669fba6dc 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -197,7 +197,7 @@ dependencies { implementation 'androidx.appcompat:appcompat:1.7.0' implementation 'com.google.android.material:material:1.12.0' - implementation 'androidx.constraintlayout:constraintlayout:2.1.4' + implementation 'androidx.constraintlayout:constraintlayout:2.2.0' implementation "com.vanniktech:emoji-google:0.18.0" implementation "androidx.emoji2:emoji2:${emojiVersion}" implementation "androidx.emoji2:emoji2-bundled:${emojiVersion}" diff --git a/gradle/verification-metadata.xml b/gradle/verification-metadata.xml index 6286a6bb22..1347d1a3fa 100644 --- a/gradle/verification-metadata.xml +++ b/gradle/verification-metadata.xml @@ -194,12 +194,14 @@ + + @@ -6403,6 +6405,11 @@ + + + + + From 509012d6a73042f34aee8bb1cf2d3a8df60cfe78 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Thu, 31 Oct 2024 08:03:10 +0000 Subject: [PATCH 271/885] Update dependency androidx.lifecycle:lifecycle-viewmodel-compose to v2.8.7 Signed-off-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- app/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/build.gradle b/app/build.gradle index 87566e9952..e1bf8233e9 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -358,7 +358,7 @@ dependencies { implementation "com.google.dagger:hilt-android:$hilt_version" kapt "com.google.dagger:hilt-android-compiler:$hilt_version" - implementation("androidx.lifecycle:lifecycle-viewmodel-compose:2.8.6") + implementation("androidx.lifecycle:lifecycle-viewmodel-compose:2.8.7") androidTestImplementation(platform("androidx.compose:compose-bom:2024.10.00")) androidTestImplementation("androidx.compose.ui:ui-test-junit4") testImplementation "org.mockito.kotlin:mockito-kotlin:$mockitoKotlinVersion" From bf3d654105b7e5f52eb691b33588f5afd11c061f Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Thu, 31 Oct 2024 20:17:03 +0000 Subject: [PATCH 272/885] Update dependency androidx.compose:compose-bom to v2024.10.01 Signed-off-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- app/build.gradle | 4 ++-- gradle/verification-metadata.xml | 5 +++++ 2 files changed, 7 insertions(+), 2 deletions(-) diff --git a/app/build.gradle b/app/build.gradle index e1bf8233e9..b1e4182ca7 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -311,7 +311,7 @@ dependencies { gplayImplementation "com.google.firebase:firebase-messaging:24.0.3" //compose - implementation(platform("androidx.compose:compose-bom:2024.10.00")) + implementation(platform("androidx.compose:compose-bom:2024.10.01")) implementation("androidx.compose.ui:ui") implementation 'androidx.compose.material3:material3:1.3.1' implementation("androidx.compose.ui:ui-tooling-preview") @@ -359,7 +359,7 @@ dependencies { kapt "com.google.dagger:hilt-android-compiler:$hilt_version" implementation("androidx.lifecycle:lifecycle-viewmodel-compose:2.8.7") - androidTestImplementation(platform("androidx.compose:compose-bom:2024.10.00")) + androidTestImplementation(platform("androidx.compose:compose-bom:2024.10.01")) androidTestImplementation("androidx.compose.ui:ui-test-junit4") testImplementation "org.mockito.kotlin:mockito-kotlin:$mockitoKotlinVersion" testImplementation "org.jetbrains.kotlinx:kotlinx-coroutines-test:$coroutines_version" diff --git a/gradle/verification-metadata.xml b/gradle/verification-metadata.xml index 1eaa06525d..625aa833d9 100644 --- a/gradle/verification-metadata.xml +++ b/gradle/verification-metadata.xml @@ -640,6 +640,11 @@ + + + + + From df4ca4828576565e5af15eae4c8a7ff8acea0902 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Thu, 31 Oct 2024 20:20:52 +0000 Subject: [PATCH 273/885] Update dependency com.android.tools.build:gradle to v8.7.2 Signed-off-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build.gradle b/build.gradle index bb704ca436..1f63dd9f10 100644 --- a/build.gradle +++ b/build.gradle @@ -22,7 +22,7 @@ buildscript { } dependencies { - classpath 'com.android.tools.build:gradle:8.7.1' + classpath 'com.android.tools.build:gradle:8.7.2' classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:${kotlinVersion}" classpath "org.jetbrains.kotlin:kotlin-serialization:${kotlinVersion}" classpath 'com.github.spotbugs.snom:spotbugs-gradle-plugin:6.0.25' From 2e3749cf5865f5987c11b41a685dd190e928a13f Mon Sep 17 00:00:00 2001 From: Nextcloud bot Date: Fri, 1 Nov 2024 02:50:39 +0000 Subject: [PATCH 274/885] Fix(l10n): Update translations from Transifex Signed-off-by: Nextcloud bot --- app/src/main/res/values-ga/strings.xml | 4 ++++ app/src/main/res/values-pt-rBR/strings.xml | 7 +++++++ 2 files changed, 11 insertions(+) diff --git a/app/src/main/res/values-ga/strings.xml b/app/src/main/res/values-ga/strings.xml index 18745513e5..fab811d5ea 100644 --- a/app/src/main/res/values-ga/strings.xml +++ b/app/src/main/res/values-ga/strings.xml @@ -4,6 +4,8 @@ Cuir le Nótaí Cuireadh comhrá %1$s le ceanáin Cuardaigh i %s + Comhrá Cartlainne + Nuair a bheidh comhrá curtha i gcartlann, cuirfear i bhfolach é de réir réamhshocraithe. Roghnaigh an scagaire \'Cartlannaithe\' chun féachaint ar chomhráite sa chartlann. Gheofar tagairtí díreacha fós. Cartlannaithe Glao Fuaime Bluetooth @@ -628,6 +630,8 @@ ag clóscríobh… ag clóscríobh… agus %1$s eile ag clóscríobh … + Comhrá Díchartlann + Nuair a bheidh comhrá gan chartlannú, taispeánfar arís é de réir réamhshocraithe. Dícosc Neamhléite Íosluchtaigh avatar nua ar an teileafón diff --git a/app/src/main/res/values-pt-rBR/strings.xml b/app/src/main/res/values-pt-rBR/strings.xml index 1ea2275279..0067deb58a 100644 --- a/app/src/main/res/values-pt-rBR/strings.xml +++ b/app/src/main/res/values-pt-rBR/strings.xml @@ -4,6 +4,8 @@ Adicionar às Notas Conversa adicionada %1$s para favoritos Pesquisar em %s + Arquive conversa + Depois que uma conversa for arquivada, ela ficará oculta por padrão. Selecione o filtro \'Arquivado\' para visualizar conversas arquivadas. Menções diretas ainda serão recebidas. Arquivado Chamada de áudio Bluetooth @@ -38,6 +40,7 @@ Criar problema Personalizar Zona de perigo + %1$s em %2$s Excluir avatar Conversa excluída %1$s Não perturbe @@ -392,6 +395,8 @@ Você enviou um áudio. %1$s enviou uma imagem. Você enviou uma imagem. + %1$s enviei uma carta deck + Você enviou uma carta de deck %1$s enviou uma localização. Você enviou um local. %1$s enviou uma enquete. @@ -625,6 +630,8 @@ estão digitando… está digitando … e %1$s outros estão digitando... + Conversa Desarquiva + Uma vez que uma conversa não for marcada, ela será mostrada por padrão novamente. Proibir Não lido Carregar novo avatar do dispositivo From 33ce2611087a75e609630f03abac53234f00b8b3 Mon Sep 17 00:00:00 2001 From: Nextcloud bot Date: Sat, 2 Nov 2024 03:34:37 +0000 Subject: [PATCH 275/885] Fix(l10n): Update translations from Transifex Signed-off-by: Nextcloud bot --- app/src/main/res/values-ar/strings.xml | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/app/src/main/res/values-ar/strings.xml b/app/src/main/res/values-ar/strings.xml index 8a51a5a611..880288fa50 100644 --- a/app/src/main/res/values-ar/strings.xml +++ b/app/src/main/res/values-ar/strings.xml @@ -4,6 +4,8 @@ إضافة إلى الملاحظات إضافة المحادثة %1$sإلى المُفضّلة بحث في %s + أرشفة المحادثة + بمجرد أرشفة المحادثة، ستكون مخفية بشكل تلقائي. إختَر فلترة \"المؤرشف\" لعرض المحادثات المؤرشفة. سوف تظل الإشارات المباشرة متاحة. مؤرشفة مكالمة صوتية البلوتوث @@ -628,6 +630,8 @@ يكتبون ... يكتب... و%1$s آخرون يقومون بالكتابة... + إرجاع المحادثة من الأرشيف + بمجرد إعادة المحادثة من الأرشيف، سوف تظهر مجدداً بشكل تلقائي. رفع الحظر غير مقروء رفع صورة رمزية جديدة للملف الشخصي من الجهاز From 7c7192de1ddad5f1eef0edaa3aa131294c21863e Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Sat, 2 Nov 2024 21:08:14 +0000 Subject: [PATCH 276/885] Update dependency com.github.spotbugs.snom:spotbugs-gradle-plugin to v6.0.26 Signed-off-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build.gradle b/build.gradle index 1f63dd9f10..fc4e16991f 100644 --- a/build.gradle +++ b/build.gradle @@ -25,7 +25,7 @@ buildscript { classpath 'com.android.tools.build:gradle:8.7.2' classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:${kotlinVersion}" classpath "org.jetbrains.kotlin:kotlin-serialization:${kotlinVersion}" - classpath 'com.github.spotbugs.snom:spotbugs-gradle-plugin:6.0.25' + classpath 'com.github.spotbugs.snom:spotbugs-gradle-plugin:6.0.26' classpath "io.gitlab.arturbosch.detekt:detekt-gradle-plugin:1.23.7" classpath "org.jlleitschuh.gradle:ktlint-gradle:12.1.1" classpath "com.google.dagger:hilt-android-gradle-plugin:$hilt_version" From a4d953cdd02477a50038f7480c92b6d9f89ee6c5 Mon Sep 17 00:00:00 2001 From: Nextcloud bot Date: Sun, 3 Nov 2024 03:00:32 +0000 Subject: [PATCH 277/885] Fix(l10n): Update translations from Transifex Signed-off-by: Nextcloud bot --- app/src/main/res/values-lt-rLT/strings.xml | 1 + 1 file changed, 1 insertion(+) diff --git a/app/src/main/res/values-lt-rLT/strings.xml b/app/src/main/res/values-lt-rLT/strings.xml index 3ca42af458..9570c03de4 100644 --- a/app/src/main/res/values-lt-rLT/strings.xml +++ b/app/src/main/res/values-lt-rLT/strings.xml @@ -326,6 +326,7 @@ Nustatyti būseną Nustatyti būsenos žinutę Bendrinti + Garso įrašai Failas Medija Kita From 0e3ea77b9c9ebde880a617df32d11f7e5277bc10 Mon Sep 17 00:00:00 2001 From: Nextcloud bot Date: Mon, 4 Nov 2024 03:00:18 +0000 Subject: [PATCH 278/885] Fix(l10n): Update translations from Transifex Signed-off-by: Nextcloud bot --- app/src/main/res/values-tr/strings.xml | 26 +- app/src/main/res/values-ug/strings.xml | 655 +++++++++++++++++++++++++ 2 files changed, 668 insertions(+), 13 deletions(-) create mode 100644 app/src/main/res/values-ug/strings.xml diff --git a/app/src/main/res/values-tr/strings.xml b/app/src/main/res/values-tr/strings.xml index 88bb716ea1..8846a4ec43 100644 --- a/app/src/main/res/values-tr/strings.xml +++ b/app/src/main/res/values-tr/strings.xml @@ -97,7 +97,7 @@ Hepsi tamam! Pin: %1$s %1$s kilidini aç - Bluetooth hoparlörleri etkinleştirmek için lütfen \"Yakındaki aygıtlar\" izni verin. + Bluetooth hoparlörleri kullanıma almak için lütfen \"Yakındaki aygıtlar\" izni verin. Gelişmiş çağrı seçenekleri Görüntülü çağrı olarak yanıtla Yalnızca sesli çağrı olarak yanıtla @@ -141,7 +141,7 @@ Kopyala Panoya kopyalandı Ekle - Devre dışı + Kullanımdan kaldırılmış Yok say Ne yazık ki bir sorun çıktı! Ayarla @@ -177,7 +177,7 @@ Sunucu Sunucu bildirimi uygulaması kurulmuş mu? Kullanıcı adı - Kullanıcı durumu etkinleştirilmiş mi? + Kullanıcı durumu kullanıma alınmış mı? Android sürümü Uygulama Uygulama adı @@ -203,8 +203,8 @@ Henüz sunucuda kaydedilmemiş Üst veri bilgileri Sistem raporu hazırlama - Çağrı bildirimi kanalı etkin mi? - İleti bildirimi kanalı etkin mi? + Çağrı bildirimi kanalı kullanıma alınmış mı? + İleti bildirimi kanalı kullanıma alınmış mı? Bildirim izinleri Telefon Sunucunun Konuş sürümü @@ -218,7 +218,7 @@ Uygulama sürümü çok eski Uygulama çok eski ve artık bu sunucu tarafından desteklenmiyor. Lütfen güncelleyin. Güncelle - Bu hesabı yeniden etkinleştirmek ya da silmek ister misiniz? + Bu hesabı yeniden kullanıma almak ya da silmek ister misiniz? Bu ortamı depolama alanına kaydetmek, aygıtınızdaki diğer uygulamaların da buna erişmesine izin verir. İlerlemek istiyor musunuz? Hayır @@ -258,8 +258,8 @@ Gruplar Konuk Konuk erişimi - Konuk erişimi etkinleştirilemez ya da devre dışı bırakılamaz. - Bu seçenek etkinleştirildiğinde, konuklar bu görüşmeyi herkese açık bir katılma bağlantısı ile paylaşabilir. + Konuk erişimi kullanıma alınamaz ya da kullanımdan kaldırılamaz. + Bu seçenek kullanıma alındığında, konuklar bu görüşmeyi herkese açık bir katılma bağlantısı ile paylaşabilir. Konuklar katılabilsin Bir parola yazın Konuk erişimi parolası @@ -325,7 +325,7 @@ Yüklemeler Yükleme ilerlemesi bildirilsin Bildirim ayarları - Bildirim izni ve pil ayarları, bildirimleri almak için doğru şekilde ayarlanmış. Yine de bildirim almakta sorun yaşıyorsanız lütfen çağrı ve iletiler için bildirim kanallarının etkin olup olmadığını denetleyin. Daha fazla yardım almak için DontKillMyApp.com adresine ya da sorun giderme kontrol listesine bakabilirsiniz. Bunlar işe yaramazsa lütfen tanılama ekranına gidin ve bir hata bildirimi gönderin. + Bildirim izni ve pil ayarları, bildirimleri almak için doğru şekilde ayarlanmış. Yine de bildirim almakta sorun yaşıyorsanız lütfen çağrı ve iletiler için bildirim kanallarının kullanıma alınmış olup olmadığını denetleyin. Daha fazla yardım almak için DontKillMyApp.com adresine ya da sorun giderme kontrol listesine bakabilirsiniz. Bunlar işe yaramazsa lütfen tanılama ekranına gidin ve bir hata bildirimi gönderin. Bildirim sorunlarını çözme Her zaman bildirilsin Anmalar bildirilsin @@ -353,9 +353,9 @@ Sorumluluğa yükselt Herkese açık görüşme ekle Herkese açık görüşmelere dışarıdan kişiler özel oluşturulmuş bir bağlantı ile davet edilebilir. - Anında bildirimler devre dışı + Anında bildirimler kullanımdan kaldırılmış Bas-konuş - Mikrofon devre dışı iken, Bas-konuş üzerine tıklayıp basılı tutun + Mikrofon kullanımdan kaldırılmışken, Bas-konuş üzerine tıklayıp basılı tutun Yenlle Sonra hatırlat Uzak ses kapalı @@ -421,7 +421,7 @@ Çağrılar Ayarları denetlemek için tanılama ekranını açın ya da bir hata bildirimi oluşturun Tanılama - Tuş takımında kişisel öğrenmeyi devre dışı bırakır (garanti edilmez) + Tuş takımında kişisel öğrenmeyi kullanımdan kaldırır (garanti edilmez) Tuş takımı gizliliği Ses yok Kimlik doğrulaması yapmak istediğiniz sunucu üzerinde Konuş uygulaması kurulu değil @@ -540,7 +540,7 @@ İzin verilmeden depolamadaki dosyalar paylaşılamaz Çağrı kaydediliyor Kaydı başlatmaktan vazgeç - Kayıt yapılamadı. lütfen yöneticinizle görüşün. + Kayıt yapılamadı. lütfen yöneticiniz ile görüşün. Kaydı başlat Kaydı durdurmak istediğinize emin misiniz? Çağrı kaydını durdur diff --git a/app/src/main/res/values-ug/strings.xml b/app/src/main/res/values-ug/strings.xml new file mode 100644 index 0000000000..7ed7078e14 --- /dev/null +++ b/app/src/main/res/values-ug/strings.xml @@ -0,0 +1,655 @@ + + + تەھرىر + ئىزاھاتقا قوشۇڭ + ياقتۇرىدىغانلارغا% 1 $ s پاراڭ قوشۇلدى + % S دىن ئىزدەڭ + ئارخىپ سۆھبەت + سۆھبەت ئارخىپلاشتۇرۇلغاندىن كېيىن ، سۈكۈتتىكى ھالەتتە يوشۇرۇن بولىدۇ. ئارخىپ پاراڭلىرىنى كۆرۈش ئۈچۈن سۈزگۈچ \ 'ئارخىپ \' نى تاللاڭ. بىۋاسىتە تىلغا ئېلىنىدۇ. + ئارخىپلاشتۇرۇلغان + Audio Call + كۆك چىش + ئاۋاز چىقىرىش + تېلېفون + سۆزلىگۈچى + سىملىق تىڭشىغۇچ + Avatar + يىراق + قايتىش كۇنۇپكىسى + Ban + قاتناشقۇچىنى چەكلەش + چەكلەش تىزىملىكى + كالېندار + ئىلغار چاقىرىش تاللانمىلىرى + تېلېفون بىر سائەت داۋاملاشتى. + ئۇقتۇرۇش قىلماي تېلېفون قىلىڭ + كامېرا ئىجازەتنامىسى بېرىلگەن. كامېرانى قايتا تاللاڭ. + بۇلۇتتىن باش سۈرىتىنى تاللاڭ + ھالەت ئۇچۇرىنى تازىلاش + كېيىنكى ھالەت ئۇچۇرىنى تازىلاڭ + تاقاش + سىنبەلگە تاقاش + ئۇلىنىش قۇرۇلدى + ئۇلىنىش يوقاپ كەتتى + ئۇلىنىش يوقاپ كەتتى -% 1 $ d ئۆچرەتتە + ئۇلىنىش يوقاپ كەتتى - ئەۋەتىلگەن ئۇچۇرلار ئۆچرەتتە تۇرىدۇ + ئاۋاز ئۇچۇرىنى ئۇدا خاتىرىلەش ئۈچۈن قۇلۇپ خاتىرىلەش + سۆھبەت پەقەت ئوقۇلىدۇ + سۆھبەت + سۆھبەت قۇرۇش + مەسىلە پەيدا قىلىڭ + Custom + خەتەر رايونى + % 2 $ s دىكى% 1 $ s + باش سۈرىتىنى ئۆچۈرۈڭ + ئۆچۈرۈلگەن سۆھبەت% 1 $ s + ئاۋارە قىلماڭ + ئېنىق ئەمەس + تەھرىر + 24 سائەتتىن چوڭ ئۇچۇرلارنى تەھرىرلىيەلمەيدۇ + ئۇچۇر سىنبەلگىسىنى تەھرىرلەش + Backspace + يېقىنقى + شىفىرلانغان + پاراڭلىرىڭىزنى يۈكلەشتە مەسىلە كۆرۈلدى + قاتناشقۇچىنى چەكلىگەندە خاتالىق كۆرۈلدى + % 1 $ نى تېجەلمىدى + ھۆججەت قىسقۇچ + Loading… + % 1 $ s (% 2 $ d) + 4 سائەت + ساقلىنىۋاتقان تەكلىپلەرنى ئالالمىدى + (تەھرىرلەندى) + ئىچكى خاتىرە + كۆرۈنمەيدۇ + ئوچۇق سۆھبەت سىنبەلگىسىگە قوشۇلۇڭ + تىللارنى ئەسلىگە كەلتۈرگىلى بولمىدى + ئەسلىگە كەلتۈرۈش مەغلۇب بولدى + بۈگۈن بۈگۈن + سۆھبەتتىن% 1 $ s ئايرىلدىڭىز + تېخىمۇ كۆپ نەتىجىلەرنى يۈكلەڭ + قۇلۇپ بەلگىسى + تۆۋەن قول + بەلگە قىلىنغان سۆھبەت% 1 $ s دەپ يېزىلغان + % 1 $ s ئوقۇلمىغان دەپ بەلگە قويۇلغان + تىلغا ئېلىنغان + ئەڭ يېڭى + ئەڭ كونا + A - Z. + Z - A. + ئەڭ چوڭ + ئەڭ كىچىك + سىز ئۆچۈرگەن ئۇچۇر + % 1 $ s تەھرىرلىگەن + بېلەت تاشلاشنى چېكىڭ + ئىزدەش نەتىجىسى يوق + ئىزدەشنى باشلاڭ… + ئىزدەش… + ئۇچۇرلار + تاللانغان ھېسابات ھازىر ئىمپورت قىلىندى ۋە ئىشلەتكىلى بولىدۇ + ھەققىدە + ئاكتىپ ئىشلەتكۈچى + ھېسابات قوشۇڭ + ھېسابات ئۆچۈرۈلمەكچى ، ئۇنى ئۆزگەرتىشكە بولمايدۇ + ئاساسلىق تىزىملىكنى ئېچىڭ + قوشۇمچە ھۆججەت قوشۇڭ + Emojis نى قوشۇڭ + سۆھبەتكە قوشۇڭ + قاتناشقۇچىلارنى قوشۇڭ + ياقتۇرىدىغانلارغا قوشۇڭ + ماقۇل ، ھەممىسى تامام! + Pin:% 1 $ s + قۇلۇپ ئېچىش% 1 $ s + كۆك چىش ياڭراتقۇنى قوزغىتىش ئۈچۈن \ "يېقىن ئەتراپتىكى ئۈسكۈنىلەر \" ئىجازەتنامىسىنى بېرىڭ. + ئىلغار تېلېفون تاللانمىلىرى + سىنلىق تېلېفون سۈپىتىدە جاۋاب بېرىڭ + پەقەت ئاۋازلىق تېلېفون سۈپىتىدە جاۋاب بېرىڭ + ئاۋاز چىقىرىشنى ئۆزگەرتىش + كامېرانى ئالماشتۇرۇڭ + ئېسىلىڭ + مىكروفوننى ئالماشتۇرۇڭ + رەسىمدىكى ھالەتنى ئېچىڭ + ئۆزى سىنغا ئالماشتۇرۇڭ + INCOMING + سۆھبەت ئىسمى + تېلېفون ئۇقتۇرۇشى + % 1 $ s قولىنى كۆتۈردى + قايتا ئۇلىنىش… + RINGING + تېلېفوندا% 1 $ s + تېلېفون بىلەن% 1 $ s + سىن بىلەن% 1 $ s + 45 سېكۇنتتا جاۋاب يوق ، قايتا سىناڭ + % s تېلېفون + % s سىنلىق سۆزلىشىش + % s ئاۋازلىق تېلېفون + سىن ئالاقىسىنى قوزغىتىش ئۈچۈن \ "كامېرا \" ئىجازەت بېرىڭ. + بىكار قىلىش + ئىقتىدارغا ئېرىشەلمىدى ، چۈشۈرۈۋېتىلدى + Caption + ھازىرغا قەدەر نامەلۇم SSL گۇۋاھنامىسى% 2 $ s ئۈچۈن% 1 $ s تارقىتىلغان ،% 3 $ s دىن% 4 $ s غىچە بولغانلىقىغا ئىشىنەمسىز؟ + گۇۋاھنامىنى تەكشۈرۈپ بېقىڭ + SSL تەڭشىكىڭىز ئۇلىنىشنىڭ ئالدىنى ئالدى + دەلىللەش گۇۋاھنامىسىنى ئۆزگەرتىڭ + پارولنى ئۆزگەرتىش + تور ئۇلىنىشىڭىزنى تەكشۈرۈپ بېقىڭ + تەھرىرلەش كۇنۇپكىسىنى تازىلاش + تەھرىرلەش ئۇچۇرىنى تازىلاش + بارلىق ئۇچۇرلارنى ئۆچۈرۈڭ + بارلىق ئۇچۇرلار ئۆچۈرۈلدى + بۇ سۆھبەتتىكى بارلىق ئۇچۇرلارنى ئۆچۈرمەكچىمۇ؟ + خېرىدار گۇۋاھنامىسىنى ئۆزگەرتىش + خېرىدار گۇۋاھنامىسى ئورنىتىڭ + ۋە + كۆچۈرۈڭ + چاپلاش تاختىسىغا كۆچۈرۈلدى + قۇر + چەكلەنگەن + خىزمەتتىن ھەيدەش + كەچۈرۈڭ ، چاتاق چىقتى! + Set + ئاتلاش + نامەلۇم + دەلىللەش گۇۋاھنامىسىنى تاللاڭ + ئۇلىنىش… + تامام + سۆھبەت چۈشەندۈرۈشى + سۆھبەت ئۇچۇرى + سىنلىق تېلېفون + ئاۋازلىق تېلېفون + سۆھبەت تېپىلمىدى + سۆھبەت تەڭشەكلىرى + سۆھبەتكە قاتنىشىڭ ياكى يېڭى باشلاڭ + دوستلىرىڭىز ۋە خىزمەتداشلىرىڭىزغا سالام! + كۆچۈرۈڭ + يېڭى سۆھبەت قۇر + راي سىناش + بۈگۈن + تۈنۈگۈن + ئۆچۈرۈش + ھەممىنى ئۆچۈرۈڭ + سۆھبەتنى ئۆچۈرۈڭ + ئەگەر سۆھبەتنى ئۆچۈرسىڭىز ، ئۇ باشقا بارلىق قاتناشقۇچىلار ئۈچۈن ئۆچۈرۈلىدۇ. + ئۆچۈرۈش + ئۇچۇر مۇۋەپپەقىيەتلىك ئۆچۈرۈلدى ، ئەمما ئۇ باشقا مۇلازىمەتلەرگە ئاشكارىلانغان بولۇشى مۇمكىن + ئىشلەتكۈچى% 1 $ s چىقىرىۋېتىلدى + رىياسەتچىدىن تۆۋەنلەش + ئاۋازلىق ئۇچۇرنى خاتىرىلەڭ + ئۇچۇر ئەۋەتىڭ + نۆۋەتتىكى ھېسابات + مۇلازىمېتىر + مۇلازىمېتىر ئۇقتۇرۇش دېتالى ئورنىتىلدى؟ + ئىشلەتكۈچى + ئىشلەتكۈچى ھالىتى قوزغىتىلدى؟ + ئاندروئىد نەشرى + ئەپ + ئەپ ئىسمى + تىزىملاتقان ئابونتلار + ئەپ نۇسخىسى + باتارېيەنى ئەلالاشتۇرۇشقا سەل قارىلىدۇ ، ھەممىسى ياخشى + باتارېيەنى ئەلالاشتۇرۇشقا سەل قاراشقا بولمايدۇ. بۇنى ئۆزگەرتىش كېرەك! + باتارېيە تەڭشىكى + ئۈسكۈنە + چاتاقنى تەكشۈرۈش تىزىملىكىنى ئېچىڭ + دىئاگنوز قويۇش ئېكرانىنى ئېچىڭ + Dontkillmyapp.com نى ئېچىڭ + ئەڭ يېڭى ئوت ئۆچۈرۈش ئىتتىرىش بەلگىسى + ئەڭ يېڭى ئوت ئۆچۈرۈش بەلبېغى + ئوت ئۆچۈرۈش ئىتتىرىش بەلگىسى يوق. خاتالىق دوكلاتىنى تەييارلاڭ. + Firebase ئىتتىرىش بەلگىسى + Google Play مۇلازىمىتىنى ئىشلەتكىلى بولمايدۇ. ئۇقتۇرۇشنى قوللىمايدۇ + Google Play مۇلازىمىتى + Google Play مۇلازىمىتى بار + ئىتتىرىش ۋاكالەتچىسىدىكى ئەڭ يېڭى ئىتتىرىش + ئىتتىرىش ۋاكالەتچىسىدە تېخى تىزىملىتىلمىدى + مۇلازىمېتىردىكى ئەڭ يېڭى ئىتتىرىش + مۇلازىمېتىردا تېخى تىزىملىتىلمىدى + Meta information + سىستېما دوكلاتىنىڭ ئەۋلادلىرى + چاقىرىش ئۇقتۇرۇشى قانىلى قوزغىتىلدى؟ + ئۇچۇر ئۇقتۇرۇش قانىلى قوزغىتىلدى؟ + ئۇقتۇرۇش ئىجازىتى + تېلېفون + مۇلازىمېتىر پاراڭ نۇسخىسى + مۇلازىمېتىر نەشرى + سىرتقى + ئىچكى + سىگنال ھالىتى + پارول ئىناۋەتسىز + ئاسراش ھالىتى + مۇلازىمېتىر ھازىر ئاسراش ھالىتىدە. + ئەپنىڭ ۋاقتى ئۆتتى + بۇ دېتال بەك كونا بولۇپ ، ئەمدى بۇ مۇلازىمېتىر قوللىمايدۇ. يېڭىلاڭ. + يېڭىلاش + بۇ ھېساباتنى قايتا تەستىقلىماقچىمۇ ياكى ئۆچۈرمەكچىمۇ؟ + بۇ مېدىيانى ساقلاشقا ئۈسكۈنىڭىزدىكى باشقا ئەپلەرنى زىيارەت قىلالايدۇ. + داۋاملاشتۇرامسىز؟ + ياق + ساقلاشقا ساقلامسىز؟ + ھەئە + كۆرسىتىش نامىنى تاپقىلى بولمايدۇ ، ئەمەلدىن قالدۇرىدۇ + كۆرسىتىش نامىنى ساقلىيالمىدى ، ئەمەلدىن قالدۇرۇلدى + سىنبەلگىنى تەھرىرلەش + تەھرىر + ئۇچۇر تېكىستىنى تەھرىرلەش + باشقۇرغۇچى تەرىپىدىن تەھرىرلەندى + ئېلخەت + 8 سائەت + 4 ھەپتە + Off + 1 كۈن + 1 سائەت + 1 ھەپتە + پاراڭلىشىش ۋاقتى توشىدۇ + پاراڭلىشىش ئۇچۇرلىرى مەلۇم ۋاقىتتىن كېيىن توشىدۇ. ئەسكەرتىش: پاراڭدا ھەمبەھىرلەنگەن ھۆججەتلەر ئىگىسى ئۈچۈن ئۆچۈرۈلمەيدۇ ، ئەمما سۆھبەتتە ئەمدى ھەمبەھىرلەنمەيدۇ. + سىگنال تەڭشىكىنى ئالالمىدى + قوبۇل قىلىڭ + رەت قىلىش + % 1 $ s دىن% 2 $ s + كۈتۈلمىگەن تەكلىپلەر يوق + تەكلىپنامىڭىز ساقلىنىۋاتىدۇ + قايتىش + ھۆججەتلەرنى زىيارەت قىلىش ئىجازەتنامىسى تەلەپ قىلىنىدۇ + سۈزگۈچ سۆھبەت + ئاممىۋى ئۇلىنىشقا ئەگىشىدىغان ئىشلەتكۈچى + سىز:% 1 $ s + ئالدىغا + ئالدىغا… + مۇلازىمېتىرىڭىز يوقمۇ؟ \ n تەمىنلىگۈچىدىن بىرنى ئېلىش ئۈچۈن بۇ يەرنى چېكىڭ + مەنبە كودىغا ئېرىشىش + گۇرۇپپا + گۇرۇپپىلار + مېھمان + مېھمان زىيارەت قىلىش + مېھمانلارنىڭ زىيارەت قىلىشىنى قوزغىتالمايدۇ ياكى چەكلىيەلمەيدۇ. + مېھمانلارنىڭ ئاممىۋى سۆھبەتتىن ئورتاقلىشىشىغا يول قويۇڭ. + مېھمانلارغا رۇخسەت قىلىڭ + پارول كىرگۈزۈڭ + مېھمان زىيارەت قىلىش پارولى + پارولنى تەڭشەش / چەكلەشتە خاتالىق. + ئاممىۋى ئۇلىنىشنى كىمنىڭ ئىشلىتەلەيدىغانلىقىنى چەكلەش ئۈچۈن پارول بەلگىلەڭ. + پارولنى قوغداش + پارول ئاجىز + تەكلىپنامىنى قايتۇرۇڭ + خاتالىق سەۋەبىدىن تەكلىپنامە ئەۋەتىلمىدى. + تەكلىپنامە يەنە ئەۋەتىلدى. + سۆھبەت ئۇلانمىسىنى ھەمبەھىرلەڭ + ئۇچۇر كىرگۈزۈڭ… + باتارېيەنى ئەلالاشتۇرۇشقا سەل قاراشقا بولمايدۇ. ئۇقتۇرۇشنىڭ ئارقا سۇپىدا ئىشلىشىگە كاپالەتلىك قىلىش ئۈچۈن بۇنى ئۆزگەرتىش كېرەك! «جەزملە» نى چېكىپ ، \ "بارلىق ئەپلەر \" ->% 1 $ s -> ئەلالاشتۇرماڭ + باتارېيەنىڭ ئەلالاشتۇرۇشىغا پەرۋا قىلماڭ + مۇھىم سۆھبەت + بۇ سۆھبەتتىكى ئۇقتۇرۇشلار قالايمىقانلاشتۇرماڭ + تەكلىپنامە + ئوچۇق سۆھبەتكە قاتنىشىڭ + % 1 $ s | ئاخىرقى قېتىم ئۆزگەرتىلگەن:% 2 $ s + سۆھبەتتىن ۋاز كېچىڭ + تېلېفوندىن ئايرىلىش… + GNU ئومۇمىي ئاممىۋى ئىجازەتنامىسى ، 3-نەشرى + ئىجازەتنامە + % s ھەرپ چېكى چەكلەنگەن + ئوچۇق سۆھبەتلەرنى تىزىڭ + Lobby + بۇ يىغىن% 1 $ s غا ئورۇنلاشتۇرۇلغان + يىغىن پات يېقىندا باشلىنىدۇ + سىز ھازىر كۈتۈپخانىدا ساقلاۋاتىسىز. + ھازىرقى ئورنىڭىز + ئورۇن رۇخسىتى تەلەپ قىلىنىدۇ + ئورنى نامەلۇم + قۇلۇپلاندى + قۇلۇپنى چېكىڭ + تەڭشەلمىدى + ئوقۇغاندەك بەلگە قويۇڭ + ئوقۇلمىغان دەپ بەلگە قويۇڭ + ئۇچۇر ئەۋەتمىدى: + جاۋابنى ئەمەلدىن قالدۇرۇڭ + ئۇچۇر ئوقۇلدى + ئۇچۇر ئەۋەتىلدى + ئاۋازلىق ئالاقىنى قوزغىتىش ئۈچۈن \ "مىكروفون \" ئىجازەت بېرىڭ. + % S دىن كەلگەن تېلېفوننى قولدىن بېرىپ قويدىڭىز + رىياسەتچى + ئەزەلدىن قوشۇلمىدى + يېڭى سۆھبەت + كۆرۈنۈشچانلىقى + ئوقۇلمىغان تىلغا ئېلىنغان + ئوقۇلمىغان ئۇچۇرلار + % 1 $ s ئىشلەتكىلى بولمايدۇ (باشقۇرغۇچى تەرىپىدىن ئورنىتىلمىغان ياكى چەكلەنمىگەن) + مېھمان + ياق + ئوچۇق سۆھبەت يوق + سىز قاتنىشالايدىغان ئوچۇق سۆھبەت يوق. \ N يا ئوچۇق سۆھبەت يوق ، ياكى ئاللىبۇرۇن ئۇلارنىڭ ھەممىسىگە قوشۇلدىڭىز. + ۋاكالەتچى يوق + ئاۋازنى قوزغىتىشىڭىزغا رۇخسەت قىلىنمايدۇ! + سىننى ئاكتىپلىشىڭىزغا رۇخسەت قىلىنمايدۇ! + % 2 $ s ئۇقتۇرۇش قانىلىدا% 1 $ s + تېلېفون قىلىدۇ + كەلگەن تېلېفونلار ھەققىدە خەۋەر قىلىڭ + ئۇچۇرلار + كەلگەن ئۇچۇرلار ھەققىدە خەۋەر قىلىڭ + يۈكلەش + يوللاش جەريانى ھەققىدە ئۇقتۇرۇش قىلىڭ + ئۇقتۇرۇش تەڭشىكى + ئۇقتۇرۇش تاپشۇرۇۋېلىش ئۈچۈن ئۇقتۇرۇش ئىجازىتى ۋە باتارېيە تەڭشىكى توغرا تەڭشەلدى. قانداقلا بولمىسۇن ئۇقتۇرۇش تاپشۇرۇۋېلىشتا مەسىلىگە يولۇقسىڭىز ، تېلېفون ۋە ئۇچۇرلارنىڭ ئۇقتۇرۇش يوللىرىنىڭ ئوچۇق ياكى ئەمەسلىكىنى تەكشۈرۈڭ. تېخىمۇ كۆپ ياردەملەرنى DontKillMyApp.com ياكى چاتاقلارنى تەكشۈرۈش تىزىملىكىدىن تاپالايسىز. ئەگەر بۇ پايدىسى بولمىسا ، دىئاگنوز قويۇش ئېكرانىغا بېرىپ خاتالىق دوكلاتىنى ئەۋەتىڭ. + ئۇقتۇرۇش كاشىلىسى + ھەمىشە خەۋەر قىلىڭ + تىلغا ئېلىنغاندا ئۇقتۇرۇش قىلىڭ + ھەرگىز ئۇقتۇرماڭ + ھازىر تورسىز ، ئۇلىنىشىڭىزنى تەكشۈرۈپ بېقىڭ + ماقۇل + تىزىملاتقان ئابونتلارغا ئوچۇق سۆھبەت + مېھمان ئەپ ئىشلەتكۈچىلەرگىمۇ ئېچىڭ + ئىگىسى + قاتناشقۇچىلار + قاتناشقۇچىلارنى قوشۇڭ + پارول + ئىجازەت بەلگىلەڭ + بەزى ئىجازەتلەر رەت قىلىندى. + رۇخسەت قىلىڭ + تەڭشەكلەرنى ئېچىڭ + تەڭشەكلەر> ئىجازەتلەر + ھېسابات تېپىلمىدى + % S ئارقىلىق پاراڭ + ئۈنسىز مىكروفون + مىكروفوننى قوزغىتىڭ + ئۇچۇرلار + مەخپىيەتلىك + شەخسىي ئۇچۇر + رىياسەتچىگە تەشۋىق قىلىڭ + يېڭى ئاممىۋى سۆھبەت + ئاممىۋى پاراڭلار سىزنى ئالاھىدە ياسالغان ئۇلىنىش ئارقىلىق سىرتتىن كىشىلەرنى تەكلىپ قىلالايدۇ. + ئىتتىرىش ئۇقتۇرۇشى چەكلەنگەن + پاراڭلىشىش + مىكروفون چەكلەنگەندىن كېيىن «چېكىش» ئارقىلىق «Push-to-talk» نى ئىشلىتىڭ + يېڭىلاش + كېيىن ماڭا ئەسكەرتىڭ + يىراقتىكى ئاۋازنى ئۆچۈرۈڭ + ياقتۇرىدىغانلاردىن ئۆچۈرۈڭ + گۇرۇپپا ۋە ئەزالارنى چىقىرىۋېتىڭ + قاتناشقۇچىنى ئېلىۋېتىڭ + پارولنى ئۆچۈرۈڭ + گۇرۇپپا ۋە ئەزالارنى چىقىرىۋېتىڭ + سۆھبەتنىڭ نامىنى ئۆزگەرتىڭ + ئىسىم ئۆزگەرتىش + جاۋاب + شەخسىي جاۋاب قايتۇرۇڭ + ساقلاش + مۇۋەپپەقىيەتلىك ساقلاندى + 30 سېكۇنت + 5 مىنۇت + 1 مىنۇت + 10 مىنۇت + 600 + 60 + 30 + 300 + ئىزدەش + ھېسابات تاللاڭ + قاتناشقۇچىلارنى تاللاڭ + تەھرىرلەش ئۇچۇرى ئەۋەتىڭ + % 1 $ s GIF ئەۋەتتى. + سىز بىر سوۋغات ئەۋەتتىڭىز. + % 1 $ s سىن ئەۋەتتى. + سىن ئەۋەتتىڭىز. + % 1 $ s قوشۇمچە ھۆججەت ئەۋەتتى. + قوشۇمچە ھۆججەت ئەۋەتتىڭىز. + % 1 $ s ئاۋاز ئەۋەتتى. + ئاۋاز ئەۋەتتىڭىز. + % 1 $ s رەسىم ئەۋەتتى. + رەسىم ئەۋەتتىڭىز. + % 1 $ s پالۋان كارتىسى ئەۋەتتى + پالۋان كارتىسى ئەۋەتتىڭىز + % 1 $ s ئورۇن ئەۋەتتى. + سىز بىر ئورۇن ئەۋەتتىڭىز. + % 1 $ s راي سىناشقا ئەۋەتكەن. + راي سىناشقا ئەۋەتتىڭىز. + % 1 $ s ئاۋازلىق ئۇچۇر ئەۋەتتى. + ئاۋازلىق ئۇچۇر ئەۋەتتىڭىز. + مۇلازىمېتىر ئۇلىنىشىنى سىناش + % 1 $ s سانداننى يېڭىلاڭ + تاللانغان ھېساباتنى ئەكىرىش مەغلۇب بولدى + تور كۆرگۈچتە ئاچقاندا% 1 $ s تور كۆرۈنمە يۈزىگە ئۇلىنىش. + % 1 $ s دېتالىدىن ھېسابات ئەكىرىڭ + ھېسابات ئەكىرىش + % 1 $ s دېتالىدىن ھېسابات ئەكىرىڭ + ھېسابات ئەكىرىش + % 1 $ s نى ئاسراشتىن چىقىرىڭ + % 1 $ s قاچىلاشنى تاماملاڭ + سىناق ئۇلىنىشى + مۇلازىمېتىر قاچىلانغان Talk ئەپنى قوللىمايدۇ + مۇلازىمېتىر ئادرېسى https: //… + % 1 $ s پەقەت% 2 $ s 13 ۋە ئۇنىڭدىن يۇقىرى ئىشلەيدۇ + يېڭى پارول بەلگىلەڭ + پارول بەلگىلەڭ + تەڭشەك + بار بولغان ھېساباتىڭىز يېڭى ھېسابات قوشۇشنىڭ ئورنىغا يېڭىلاندى + ئىلغار + كۆرۈنۈش + تېلېفون قىلىدۇ + تەڭشەكلەرنى تەكشۈرۈش ياكى خاتالىق دوكلاتىنى تەكشۈرۈش ئۈچۈن دىئاگنوز ئېكرانىنى ئېچىڭ + دىئاگنوز + خاسلاشتۇرۇلغان ئۆگىنىشنى چەكلەش ئۈچۈن كۇنۇپكا تاختىسىغا بۇيرۇق بېرىدۇ (كاپالەتسىز) + Incognito كۇنۇپكا تاختىسى + ئاۋاز يوق + سىز دەلىللىمەكچى بولغان مۇلازىمېتىرغا پاراڭ دېتالى ئورنىتىلمىدى + ئۇقتۇرۇش ئاۋازى + ئۇقتۇرۇش + ئۇقتۇرۇش رەت قىلىندى + ئۇقتۇرۇش رەت قىلىندى. ئاندىرويىد تەڭشىكىدە ئۇقتۇرۇشقا يول قويۇڭ + ئۇقتۇرۇش تارقىتىلدى + ئۇچۇرلار + تېلېفون نومۇرىنى ئاساس قىلغان ئالاقىنى ماسلاشتۇرۇپ ، سۆزلىشىش تېزلەتمىسىنى سىستېما ئالاقىلىشىش دېتالىغا بىرلەشتۈرۈڭ + 429 خاتالىق بەك كۆپ + تېلېفون نومۇرىڭىزنى تەڭشىسىڭىز بولىدۇ ، شۇنداق بولغاندا باشقا ئىشلەتكۈچىلەر سىزنى تاپالايدۇ + تېلېفون نومۇرىنى كىرگۈزۈڭ + تېلېفون نومۇرى ئىناۋەتسىز + تېلېفون نومۇرى مۇۋەپپەقىيەتلىك تەڭشەلدى + تېلېفون نومۇرى + تېلېفون نومۇرىنى بىرلەشتۈرۈش + مەخپىيەتلىك + ۋاكالەتچى + ۋاكالەتچى پارول + ۋاكالەتچى ئېغىز + ۋاكالەتچى تىپى + ۋاكالەتچى ئىشلەتكۈچى ئىسمى + مېنىڭ ئوقۇش ھالىتىمنى ھەمبەھىرلەڭ ۋە باشقىلارنىڭ ئوقۇش ھالىتىنى كۆرسىتىڭ + ئوقۇش ھالىتى + ھېساباتقا ئىجازەت بېرىش + ئۆچۈرۈڭ + ھېساباتنى ئۆچۈرۈڭ + نۆۋەتتىكى ھېساباتنى ئۆچۈرۈش نىيىتىڭىزنى جەزملەشتۈرۈڭ. + ئاندىرويىد ئېكران قۇلۇپى ياكى قوللايدىغان بىئولوگىيەلىك ئۇسۇل بىلەن% 1 $ s نى قۇلۇپلاڭ + ئېكران قۇلۇپسىز ھەرىكەت ۋاقتى + ئېكران قۇلۇپى + يېقىنقى تىزىملىك ۋە ئەپ ئىچىدىكى ئېكران كۆرۈنۈشلىرىنىڭ ئالدىنى ئالىدۇ + ئېكران بىخەتەرلىكى + مۇلازىمېتىر نۇسخىسى ناھايىتى كونا بولۇپ ، كېيىنكى نەشرىدە قوللىمايدۇ! + مۇلازىمېتىر نۇسخىسى بەك كونا بولۇپ ، ئاندىرويىد دېتالىنىڭ بۇ نەشرىنى قوللىمايدۇ + قوللىمايدىغان مۇلازىمېتىر + باتارېيە ساقلىغۇچى تەرىپىدىن تەڭشەلدى + قاراڭغۇ + سىستېما سۈكۈتتىكى ھالىتىنى ئىشلىتىڭ + تېما + نۇر + باشتېما + مېنىڭ خەت بېسىش ھالىتىمنى ھەمبەھىرلەپ ، باشقىلارنىڭ خەت بېسىش ھالىتىنى كۆرسىتىڭ + خەت بېسىش ھالىتى پەقەت يۇقىرى ئىقتىدارلىق ئارقا كۆرۈنۈش (HPB) نى ئىشلەتكەندىلا بولىدۇ + يېزىش ھالىتى + ۋاكالەتچى كىنىشكا تەلەپ قىلىدۇ + ئاگاھلاندۇرۇش + پەقەت نۆۋەتتىكى ھېساباتنىلا رۇخسەت قىلىشقا بولىدۇ + ئالاقىلىشىش + ئالاقىداشلارنى ئوقۇش ئىجازەتنامىسى تەلەپ قىلىنىدۇ + نۆۋەتتىكى ئورۇننى ئورتاقلىشىڭ + ئۇلىنىشنى ھەمبەھىرلەش + ئورۇننى ئورتاقلىشىش + بۇ ئورۇننى ئورتاقلىشىڭ + ھېسابات تاللاڭ + ئورتاق بەھرىلىنىدىغان بۇيۇملار + پالۋان كارتىسى + رەسىم ، ھۆججەت ، ئاۋازلىق ئۇچۇرلار… + ئورتاق بەھرىلىنىدىغان تۈر يوق + ئورنى + ئورتاق ئورۇن + تەرتىپلەش + باشلىنىش ۋاقتى + ھېساباتنى ئالماشتۇرۇش + Team + كوماندىلار + ھۆججەتلەرنى تاللاڭ + بۇ ھۆججەتلەرنى% 1 $ s غا ئەۋەتىڭ؟ + بۇ ھۆججەتنى% 1 $ s غا ئەۋەتىڭ؟ + كەچۈرۈڭ ، يوللاش مەغلۇپ بولدى + % 1 $ s نى يۈكلىيەلمىدى + مەغلۇبىيەت + % 1 $ s دىن ئورتاقلىشىش + ئۈسكۈنىدىن يۈكلەش + يۈكلەش + % 1 $ s دىن% 2 $ s -% 3 $ s \ %% + رەسىمگە تارتىڭ + سىن ئېلىڭ + ئىشلەتكۈچى + سىن خاتىرىلەش نىسبىتى% 1 $ s + كۆرگىلى بولىدۇ + سۆزلىشىش خاتىرىسى% 1 $ s (% 2 $ s) + خاتىرىلەش ، ئەۋەتىش ئۈچۈن قويۇپ بېرىش. + ئاۋاز خاتىرىلەش ئىجازىتى تەلەپ قىلىنىدۇ + «ئەمەلدىن قالدۇرۇش + Webinar + ھەئە + يېڭى سۆھبەت قۇرۇش سىنبەلگىسى + كېلەر ھەپتە + ئىجازەت يوقالغانلىقتىن تېلېفون نومۇرىنى بىرلەشتۈرۈش يوق + 1 سائەت + توردا + توردىكى ئورنى + ئوچۇق سۆھبەت + ھۆججەتلەر دېتالىدا ئېچىڭ + ئاۋازلىق ئۇچۇرنى قويۇش / توختىتىش + تاللاش قوشۇڭ + بېلەتنى تەھرىرلەش + راي سىناشنى ئاخىرلاشتۇرۇڭ + بۇ راي سىناشنى راستىنلا ئاخىرلاشتۇرماقچىمۇ؟ بۇنى ئەمەلدىن قالدۇرغىلى بولمايدۇ. + بۇ راي سىناشقا تېخىمۇ كۆپ تاللاشلار بىلەن بېلەت تاشلىيالمايسىز. + كۆپ جاۋاب + % 1 $ s نى ئۆچۈرۈڭ + تاللاش% 1 $ s + تاللانما + شەخسىي راي سىناش + سوئال + سوئالىڭىز + نەتىجە + تەڭشەك + بېلەت تاشلاش + بېلەت تاشلاندى + قولىنى كۆتۈرۈڭ + ھەممىسى + ھۆججەتلەرنى ساقلاشتىن ئورتاقلىشىش رۇخسەتسىز مۇمكىن ئەمەس + تېلېفون خاتىرىلىنىۋاتىدۇ + خاتىرىلەشنى باشلاشنى ئەمەلدىن قالدۇرۇڭ + خاتىرىلەش مەغلۇپ بولدى. باشقۇرغۇچىڭىز بىلەن ئالاقىلىشىڭ. + خاتىرىلەشنى باشلاڭ + خاتىرىلەشنى توختاتماقچىمۇ؟ + چاقىرىش خاتىرىسىنى توختىتىڭ + خاتىرىلەشنى توختىتىڭ + خاتىرىلەشنى توختىتىش… + بارلىق تېلېفونلاردا خاتىرىلەش ئىجازىتى تەلەپ قىلىنىدۇ + بۇ خاتىرىدە ئاۋازىڭىز ، كامېرادىكى سىن ۋە ئېكران ھەمبەھىرلىنىشىڭىز بولۇشى مۇمكىن. تېلېفونغا قاتنىشىشتىن بۇرۇن سىزنىڭ رۇخسىتىڭىز تەلەپ قىلىنىدۇ. ماقۇلمۇ؟ + بۇ سۆھبەتكە چاقىرىشتىن بۇرۇن خاتىرىلەش ئىجازىتىنى تەلەپ قىلىڭ + خاتىرىلەش + تېلېفون خاتىرىلەنگەن بولۇشى مۇمكىن. + خاتىرىلەش + ياقتۇرىدىغان سۆزلەردىن% 1 $ s ئۆچۈرۈلدى + سۆھبەت% 1 $ s غا ئۆزگەرتىلدى + تېلېفون قىلغاندا باشقا ياتاقلارغا قوشۇلۇش مۇمكىن ئەمەس + ساقلاش + پەقەت ئىشەنچلىك مۇلازىمېتىرلارغا ماسقەدەملەڭ + فېدېراتسىيە + پەقەت بۇ مىسالدىكى كىشىلەر ۋە مېھمانلارلا كۆرۈنىدۇ + يەرلىك + پەقەت كۆچمە تېلېفوندا سۆزلىشىش ئارقىلىق تېلېفون نومۇرىنى بىرلەشتۈرۈش ئارقىلىق ماسلاشقان كىشىلەرگە كۆرۈندى + شەخسىي + ئىشەنچلىك مۇلازىمېتىرلار ۋە دۇنياۋى ۋە ئاممىۋى ئادرېس دەپتىرىگە ماسقەدەملەڭ + ئېلان قىلىندى + دائىرە ئالماشتۇرۇش + % 1 $ s نىڭ مەخپىيەتلىك دەرىجىسىنى ئۆزگەرتىڭ + ئاستىغا يۆتكەڭ + سىنبەلگە ئىزدەش + سېكۇنت بۇرۇن + مۇشۇنىڭغا ئوخشاش ئۇچۇرلارنى% 1 $ گە قاراڭ + تاللانغان + ئېلېكترونلۇق خەت ئەۋەتىڭ + ئەۋەتىش + بۇ سۆھبەتكە مەزمۇن ئورتاقلىشىڭىزغا رۇخسەت قىلىنمايدۇ + ئەۋەتىش… + ئۇقتۇرۇشسىز ئەۋەتىڭ + Set + كامېرادىن باش سۈرىتىنى تەڭشەڭ + ھالەت بەلگىلەڭ + ھالەت ئۇچۇرىنى بەلگىلەڭ + ھەمبەھىرلەش + % 2 $ s دىكى سۆھبەتكە قوشۇلۇڭ + Audio + ھۆججەت + Media + باشقىلىرى + راي سىناش + چاقىرىش خاتىرىسى + ئاۋاز + چەكلەش سەۋەبىنى كۆرسىتىڭ + چەكلەنگەن قاتناشقۇچىلارنى كۆرسىتىش + ئامراق + سىزنىڭ تېلېفوننى باشلىشىڭىزغا رۇخسەت قىلىنمايدۇ + تېلېفون باشلىدى + ھالەت ئۇچۇرى + بۆسۈش ئۆيىگە ئالماشتۇرۇڭ + ئاساسلىق ئۆيگە ئالماشتۇرۇڭ + رەسىمگە تارتىڭ + رەسىمگە تارتىشتا خاتالىق + رۇخسەتسىز رەسىمگە تارتىش مۇمكىن ئەمەس + قايتا سۈرەتكە تارتىڭ + ئەۋەتىڭ + كامېرا ئالماشتۇرۇش + Crop photo + رەسىمنىڭ چوڭ-كىچىكلىكىنى ئازايتىش + مەشئەلنى ئالماشتۇرۇڭ + 30 مىنۇت + بۇ ھەپتە + بۇ بىر سىناق ئۇچۇرى + بۇ ھەپتە ئاخىرى + بۈگۈن + ئەتە + تەرجىمە + تەرجىمە + تەرجىمە قىلىنغان تېكىستنى كۆچۈرۈڭ + تىلنى ئېنىقلاش + ئۈسكۈنىنىڭ تەڭشىكى + تىلنى بايقىيالمىدى + تەرجىمە مەغلۇب بولدى + From + To + يەنە 1 بولسا خەت بېسىۋاتىدۇ… + are typing… + يېزىۋاتىدۇ… + ۋە% 1 $ s باشقىلار يېزىۋاتىدۇ… + تەرتىپسىز سۆھبەت + سۆھبەت بىر تەرەپ قىلىنمىغاندىن كېيىن ، سۈكۈتتىكى ھالەتتە يەنە كۆرسىتىلىدۇ. + Unban + ئوقۇمىغان + ئۈسكۈنىدىن يېڭى باش سۈرىتىنى يۈكلەڭ + ئىشلەتكۈچى باش سۈرىتى + ئادرېس + تولۇق ئىسمى + ئېلخەت + تېلېفون نومۇرى + Twitter + تور بېكەت + ھالەت + شەخسىي ئىشلەتكۈچى ئۇچۇرىغا ئېرىشەلمىدى. + شەخسىي ئۇچۇر يوق + ئارخىپ بېتىڭىزگە ئىسىم ، رەسىم ۋە ئالاقىلىشىش تەپسىلاتلىرىنى قوشۇڭ. + Video Call + ئەھۋالىڭىز نېمە؟ + + %d vote + %d votes + + From 88dc32e3118d67bc77fda8825c1d0d8ff675743c Mon Sep 17 00:00:00 2001 From: Nextcloud bot Date: Tue, 5 Nov 2024 02:53:00 +0000 Subject: [PATCH 279/885] Fix(l10n): Update translations from Transifex Signed-off-by: Nextcloud bot --- app/src/main/res/values-sr/strings.xml | 7 +++++++ app/src/main/res/values-tr/strings.xml | 7 +++++++ 2 files changed, 14 insertions(+) diff --git a/app/src/main/res/values-sr/strings.xml b/app/src/main/res/values-sr/strings.xml index fea2f19c92..2a620d5942 100644 --- a/app/src/main/res/values-sr/strings.xml +++ b/app/src/main/res/values-sr/strings.xml @@ -4,6 +4,8 @@ Додај у Белешке Разговор %1$s је додат у омиљене Тражи у %s + Архивирај разговор + Када се разговор архивира, подразумевано ће бити сакривен. Да бисте видели архивиране разговоре, изаберите филтер ’Архивирано’. И даље ће се примати директна помињања. Архивирано Гласовни позив Bluetooth @@ -38,6 +40,7 @@ Креирај проблем Прилагођено Зона опасности + %1$s у %2$s Обриши аватар Разговор %1$s је обрисан Не узнемиравај @@ -392,6 +395,8 @@ Послали сте звук. %1$s је послао слику. Послали сте слику. + %1$s је послао картицу шпила + Послали сте картицу шпила %1$s је послао локацију. Послали сте локацију. %1$s је послао гласање. @@ -625,6 +630,8 @@ куцају... куца... и %1$s других куцају… + Деархивирај разговор + Када се разговор деархивира, поново ће се подразумевано приказивати. Уклони забрану Непрочитано Отпреми нови аватар са уређаја diff --git a/app/src/main/res/values-tr/strings.xml b/app/src/main/res/values-tr/strings.xml index 8846a4ec43..f2556bdd7d 100644 --- a/app/src/main/res/values-tr/strings.xml +++ b/app/src/main/res/values-tr/strings.xml @@ -4,6 +4,8 @@ Notlar uygulamasına ekle %1$s görüşmesi sık kullanılara eklendi %s içinde arama + Görüşmeyi arşivle + Bir görüşme arşivlendiğinde, varsayılan olarak gizlenir. Arşivlenmiş görüşmeleri görüntülemek için \'Arşivlenmiş\' süzgecini seçin. Doğrudan anmalar yine de alınır. Arşivlenmiş Sesli çağrı Bluetooth @@ -38,6 +40,7 @@ Sorun ekle Özel Tehlikeli bölge + %1$s, %2$s içinde Avatarı sil %1$s görüşmesi silindi Rahatsız etmeyin @@ -392,6 +395,8 @@ Bir ses gönderdiniz. %1$s bir görsel gönderdi. Bir görsel gönderdiniz. + %1$s bir tahta kartı gönderdi + Bir tahta kartı gönderdiniz %1$s bir konum gönderdi. Bir konum gönderdiniz. %1$s bir anket gönderdi. @@ -625,6 +630,8 @@ kişi yazıyor… yazıyor… ve %1$s diğer kişi yazıyor… + Görüşmeyi arşivden çıkar + Bir görüşme arşivden çıkarıldığında varsayılan olarak yeniden gösterilir. Yasaklamayı kaldır Okunmamış Aygıttan yeni avatar yükle From afe0e08ffd1072445233b51e78374627da756475 Mon Sep 17 00:00:00 2001 From: Nextcloud bot Date: Tue, 5 Nov 2024 10:56:29 +0000 Subject: [PATCH 280/885] Fix(l10n): Update translations from Transifex Signed-off-by: Nextcloud bot --- app/src/main/res/values-ug/strings.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/src/main/res/values-ug/strings.xml b/app/src/main/res/values-ug/strings.xml index 7ed7078e14..54dc502055 100644 --- a/app/src/main/res/values-ug/strings.xml +++ b/app/src/main/res/values-ug/strings.xml @@ -5,7 +5,7 @@ ياقتۇرىدىغانلارغا% 1 $ s پاراڭ قوشۇلدى % S دىن ئىزدەڭ ئارخىپ سۆھبەت - سۆھبەت ئارخىپلاشتۇرۇلغاندىن كېيىن ، سۈكۈتتىكى ھالەتتە يوشۇرۇن بولىدۇ. ئارخىپ پاراڭلىرىنى كۆرۈش ئۈچۈن سۈزگۈچ \ 'ئارخىپ \' نى تاللاڭ. بىۋاسىتە تىلغا ئېلىنىدۇ. + سۆھبەت ئارخىپلاشتۇرۇلغاندىن كېيىن ، سۈكۈتتىكى ھالەتتە يوشۇرۇن بولىدۇ. ئارخىپ پاراڭلىرىنى كۆرۈش ئۈچۈن سۈزگۈچ \\'ئارخىپ \\' نى تاللاڭ. بىۋاسىتە تىلغا ئېلىنىدۇ. ئارخىپلاشتۇرۇلغان Audio Call كۆك چىش From d53ef9a65f7efa71a6d9120ce55037b93e949770 Mon Sep 17 00:00:00 2001 From: Nextcloud bot Date: Tue, 5 Nov 2024 12:26:27 +0000 Subject: [PATCH 281/885] Fix(l10n): Update translations from Transifex Signed-off-by: Nextcloud bot --- app/src/main/res/values-ug/strings.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/src/main/res/values-ug/strings.xml b/app/src/main/res/values-ug/strings.xml index 54dc502055..0314821fc3 100644 --- a/app/src/main/res/values-ug/strings.xml +++ b/app/src/main/res/values-ug/strings.xml @@ -5,7 +5,7 @@ ياقتۇرىدىغانلارغا% 1 $ s پاراڭ قوشۇلدى % S دىن ئىزدەڭ ئارخىپ سۆھبەت - سۆھبەت ئارخىپلاشتۇرۇلغاندىن كېيىن ، سۈكۈتتىكى ھالەتتە يوشۇرۇن بولىدۇ. ئارخىپ پاراڭلىرىنى كۆرۈش ئۈچۈن سۈزگۈچ \\'ئارخىپ \\' نى تاللاڭ. بىۋاسىتە تىلغا ئېلىنىدۇ. + سۆھبەت ئارخىپلاشتۇرۇلغاندىن كېيىن ، سۈكۈتتىكى ھالەتتە يوشۇرۇن بولىدۇ. ئارخىپ پاراڭلىرىنى كۆرۈش ئۈچۈن سۈزگۈچ ئارخىپ نى تاللاڭ. بىۋاسىتە تىلغا ئېلىنىدۇ. ئارخىپلاشتۇرۇلغان Audio Call كۆك چىش From 675bc9bec09efb1cbdf49bab90ac962fc4f5499e Mon Sep 17 00:00:00 2001 From: Marcel Hibbe Date: Mon, 28 Oct 2024 13:41:49 +0100 Subject: [PATCH 282/885] fix messages not shown + improve unread marker behavior this commit will avoid to fail to show messages in adapter. This was caused by the usage of messagesListAdapter.deleteById("-1"); in UnreadNoticeMessageViewHolder. The bug seems to exist in the past already but was never reported (Sometimes, when receiving a lot of messages it could happen that some message in between is not shown in UI). However with recent changes after release 20.0.2 the bug appeared more often. The root cause was not analyzed, but the handling was modified in general as the unread marker behavior was never really good. By not using deleteById but replace it with new unread marker logic, the bug of disappearing messages is solved and the unread messages marker behavior is improved. Signed-off-by: Marcel Hibbe --- .../UnreadNoticeMessageViewHolder.java | 2 +- .../com/nextcloud/talk/chat/ChatActivity.kt | 77 +++++++++---------- .../talk/chat/data/ChatMessageRepository.kt | 3 +- .../network/OfflineFirstChatRepository.kt | 32 ++++++-- 4 files changed, 66 insertions(+), 48 deletions(-) diff --git a/app/src/main/java/com/nextcloud/talk/adapters/messages/UnreadNoticeMessageViewHolder.java b/app/src/main/java/com/nextcloud/talk/adapters/messages/UnreadNoticeMessageViewHolder.java index 6615b4f0d9..6ae3d5003f 100644 --- a/app/src/main/java/com/nextcloud/talk/adapters/messages/UnreadNoticeMessageViewHolder.java +++ b/app/src/main/java/com/nextcloud/talk/adapters/messages/UnreadNoticeMessageViewHolder.java @@ -24,7 +24,7 @@ public UnreadNoticeMessageViewHolder(View itemView, Object payload) { @Override public void viewDetached() { - messagesListAdapter.deleteById("-1"); +// messagesListAdapter.deleteById("-1"); } @Override diff --git a/app/src/main/java/com/nextcloud/talk/chat/ChatActivity.kt b/app/src/main/java/com/nextcloud/talk/chat/ChatActivity.kt index df0adc0ecc..552a14c8de 100644 --- a/app/src/main/java/com/nextcloud/talk/chat/ChatActivity.kt +++ b/app/src/main/java/com/nextcloud/talk/chat/ChatActivity.kt @@ -756,6 +756,8 @@ class ChatActivity : is MessageInputViewModel.SendChatMessageSuccessState -> { myFirstMessage = state.message + removeUnreadMessagesMarker() + if (binding.unreadMessagesPopup.isShown == true) { binding.unreadMessagesPopup.hide() } @@ -853,9 +855,10 @@ class ChatActivity : this.lifecycleScope.launch { chatViewModel.getMessageFlow - .onEach { pair -> - val lookIntoFuture = pair.first - var chatMessageList = pair.second + .onEach { triple -> + val lookIntoFuture = triple.first + val setUnreadMessagesMarker = triple.second + var chatMessageList = triple.third chatMessageList = handleSystemMessages(chatMessageList) @@ -871,7 +874,8 @@ class ChatActivity : } if (lookIntoFuture) { - processMessagesFromTheFuture(chatMessageList) + Log.d(TAG, "chatMessageList.size in getMessageFlow:" + chatMessageList.size) + processMessagesFromTheFuture(chatMessageList, setUnreadMessagesMarker) } else { processMessagesNotFromTheFuture(chatMessageList) collapseSystemMessages() @@ -1011,6 +1015,13 @@ class ChatActivity : } } + private fun removeUnreadMessagesMarker() { + val index = adapter?.getMessagePositionById("-1") + if (index != null && index != -1) { + adapter?.items?.removeAt(index) + } + } + @Suppress("Detekt.TooGenericExceptionCaught") override fun onResume() { super.onResume() @@ -2653,13 +2664,22 @@ class ChatActivity : } } - private fun processMessagesFromTheFuture(chatMessageList: List) { - val newMessagesAvailable = (adapter?.itemCount ?: 0) > 0 && chatMessageList.isNotEmpty() - val insertNewMessagesNotice = shouldInsertNewMessagesNotice(newMessagesAvailable, chatMessageList) - val scrollToEndOnUpdate = isScrolledToBottom() + private fun processMessagesFromTheFuture(chatMessageList: List, setUnreadMessagesMarker: Boolean) { + binding.scrollDownButton.visibility = View.GONE + + val scrollToBottom: Boolean - if (insertNewMessagesNotice) { - updateUnreadMessageInfos(chatMessageList, scrollToEndOnUpdate) + if (setUnreadMessagesMarker) { + scrollToBottom = false + setUnreadMessageMarker(chatMessageList) + } else { + if (isScrolledToBottom()) { + scrollToBottom = true + } else { + scrollToBottom = false + binding.unreadMessagesPopup.show() + // here we have the problem that the chat jumps for every update + } } for (chatMessage in chatMessageList) { @@ -2674,44 +2694,21 @@ class ChatActivity : (currentConversation?.type == ConversationEnums.ConversationType.ROOM_TYPE_ONE_TO_ONE_CALL) chatMessage.isFormerOneToOneConversation = (currentConversation?.type == ConversationEnums.ConversationType.FORMER_ONE_TO_ONE) - it.addToStart(chatMessage, scrollToEndOnUpdate) + Log.d(TAG, "chatMessage to add:" + chatMessage.message) + it.addToStart(chatMessage, scrollToBottom) } } - - if (insertNewMessagesNotice && scrollToEndOnUpdate && adapter != null) { - scrollToFirstUnreadMessage() - } } private fun isScrolledToBottom() = layoutManager?.findFirstVisibleItemPosition() == 0 - private fun shouldInsertNewMessagesNotice(newMessagesAvailable: Boolean, chatMessageList: List) = - if (newMessagesAvailable) { - chatMessageList.any { it.actorId != conversationUser!!.userId } - } else { - false - } - - private fun updateUnreadMessageInfos(chatMessageList: List, scrollToEndOnUpdate: Boolean) { + private fun setUnreadMessageMarker(chatMessageList: List) { val unreadChatMessage = ChatMessage() unreadChatMessage.jsonMessageId = -1 unreadChatMessage.actorId = "-1" unreadChatMessage.timestamp = chatMessageList[0].timestamp unreadChatMessage.message = context.getString(R.string.nc_new_messages) adapter?.addToStart(unreadChatMessage, false) - - if (scrollToEndOnUpdate) { - binding.scrollDownButton.visibility = View.GONE - newMessagesCount = 0 - } else { - if (binding.unreadMessagesPopup.isShown) { - newMessagesCount++ - } else { - newMessagesCount = 1 - binding.scrollDownButton.visibility = View.GONE - binding.unreadMessagesPopup.show() - } - } } private fun processMessagesNotFromTheFuture(chatMessageList: List) { @@ -2754,7 +2751,8 @@ class ChatActivity : return false } - if (!message1IsSystem && ( + if (!message1IsSystem && + ( (message1.actorType != message2.actorType) || (message2.actorId != message1.actorId) ) @@ -2863,9 +2861,8 @@ class ChatActivity : TextUtils.isEmpty(messageRight.systemMessage) && DateFormatter.isSameDay(messageLeft.createdAt, messageRight.createdAt) - private fun isSameDayMessages(message1: ChatMessage, message2: ChatMessage): Boolean { - return DateFormatter.isSameDay(message1.createdAt, message2.createdAt) - } + private fun isSameDayMessages(message1: ChatMessage, message2: ChatMessage): Boolean = + DateFormatter.isSameDay(message1.createdAt, message2.createdAt) override fun onLoadMore(page: Int, totalItemsCount: Int) { val id = ( diff --git a/app/src/main/java/com/nextcloud/talk/chat/data/ChatMessageRepository.kt b/app/src/main/java/com/nextcloud/talk/chat/data/ChatMessageRepository.kt index a55a458031..860da6c21f 100644 --- a/app/src/main/java/com/nextcloud/talk/chat/data/ChatMessageRepository.kt +++ b/app/src/main/java/com/nextcloud/talk/chat/data/ChatMessageRepository.kt @@ -22,7 +22,8 @@ interface ChatMessageRepository : LifecycleAwareManager { */ val messageFlow: Flow< - Pair< + Triple< + Boolean, Boolean, List > diff --git a/app/src/main/java/com/nextcloud/talk/chat/data/network/OfflineFirstChatRepository.kt b/app/src/main/java/com/nextcloud/talk/chat/data/network/OfflineFirstChatRepository.kt index 4c52f7f315..b0fc8d0812 100644 --- a/app/src/main/java/com/nextcloud/talk/chat/data/network/OfflineFirstChatRepository.kt +++ b/app/src/main/java/com/nextcloud/talk/chat/data/network/OfflineFirstChatRepository.kt @@ -53,7 +53,8 @@ class OfflineFirstChatRepository @Inject constructor( override val messageFlow: Flow< - Pair< + Triple< + Boolean, Boolean, List > @@ -62,7 +63,8 @@ class OfflineFirstChatRepository @Inject constructor( private val _messageFlow: MutableSharedFlow< - Pair< + Triple< + Boolean, Boolean, List > @@ -142,6 +144,7 @@ class OfflineFirstChatRepository @Inject constructor( // set up field map to load the newest messages val fieldMap = getFieldMap( lookIntoFuture = false, + timeout = 0, includeLastKnown = true, setReadMarker = true, lastKnown = null @@ -229,6 +232,7 @@ class OfflineFirstChatRepository @Inject constructor( val fieldMap = getFieldMap( lookIntoFuture = false, + timeout = 0, includeLastKnown = false, setReadMarker = true, lastKnown = beforeMessageId.toInt() @@ -254,6 +258,9 @@ class OfflineFirstChatRepository @Inject constructor( var fieldMap = getFieldMap( lookIntoFuture = true, + // timeout for first longpoll is 0, so "unread message" info is not shown if there were + // initially no messages but someone writes us in the first 30 seconds. + timeout = 0, includeLastKnown = false, setReadMarker = true, lastKnown = initialMessageId.toInt() @@ -261,6 +268,8 @@ class OfflineFirstChatRepository @Inject constructor( val networkParams = Bundle() + var showUnreadMessagesMarker = true + while (true) { if (!monitor.isOnline.first() || itIsPaused) { Thread.sleep(HALF_SECOND) @@ -272,8 +281,14 @@ class OfflineFirstChatRepository @Inject constructor( val resultsFromSync = sync(networkParams) if (!resultsFromSync.isNullOrEmpty()) { val chatMessages = resultsFromSync.map(ChatMessageEntity::asModel) - val pair = Pair(true, chatMessages) + + val weHaveMessagesFromOurself = chatMessages.any { it.actorId == currentUser.userId } + showUnreadMessagesMarker = showUnreadMessagesMarker && !weHaveMessagesFromOurself + + val pair = Triple(true, showUnreadMessagesMarker, chatMessages) _messageFlow.emit(pair) + } else { + Log.d(TAG, "resultsFromSync are null or empty") } updateUiForLastCommonRead() @@ -283,10 +298,13 @@ class OfflineFirstChatRepository @Inject constructor( // update field map vars for next cycle fieldMap = getFieldMap( lookIntoFuture = true, + timeout = 30, includeLastKnown = false, setReadMarker = true, lastKnown = newestMessage ) + + showUnreadMessagesMarker = false } } } @@ -325,6 +343,7 @@ class OfflineFirstChatRepository @Inject constructor( private fun getFieldMap( lookIntoFuture: Boolean, + timeout: Int, includeLastKnown: Boolean, setReadMarker: Boolean, lastKnown: Int?, @@ -342,7 +361,7 @@ class OfflineFirstChatRepository @Inject constructor( fieldMap["lastCommonReadId"] = it } - fieldMap["timeout"] = if (lookIntoFuture) 30 else 0 + fieldMap["timeout"] = timeout fieldMap["limit"] = limit fieldMap["lookIntoFuture"] = if (lookIntoFuture) 1 else 0 fieldMap["setReadMarker"] = if (setReadMarker) 1 else 0 @@ -357,6 +376,7 @@ class OfflineFirstChatRepository @Inject constructor( if (loadFromServer) { val fieldMap = getFieldMap( lookIntoFuture = false, + timeout = 0, includeLastKnown = true, setReadMarker = false, lastKnown = messageId.toInt(), @@ -664,7 +684,7 @@ class OfflineFirstChatRepository @Inject constructor( ) if (list.isNotEmpty()) { - val pair = Pair(false, list) + val pair = Triple(false, false, list) _messageFlow.emit(pair) } } @@ -690,7 +710,7 @@ class OfflineFirstChatRepository @Inject constructor( ) if (list.isNotEmpty()) { - val pair = Pair(false, list) + val pair = Triple(false, false, list) _messageFlow.emit(pair) } } From 29f7265b198a755c46d6503621d1ad34d7160812 Mon Sep 17 00:00:00 2001 From: Marcel Hibbe Date: Tue, 29 Oct 2024 14:20:25 +0100 Subject: [PATCH 283/885] implement "Unread messages" popup with normal button replace com.nextcloud.ui.popupbubble.PopupBubble with MaterialButton. com.nextcloud.ui.popupbubble.PopupBubble was forked from https://github.com/webianks/PopupBubble which is quite outdated. com.nextcloud.ui.popupbubble.PopupBubble is still used in ConversationsListActivity but there it should also be removed. Removing this recycler view stuff will also help a bit to switch to JetpackCompose Signed-off-by: Marcel Hibbe --- .../UnreadNoticeMessageViewHolder.java | 1 - .../com/nextcloud/talk/chat/ChatActivity.kt | 65 +++++++------------ app/src/main/res/layout/activity_chat.xml | 5 +- 3 files changed, 29 insertions(+), 42 deletions(-) diff --git a/app/src/main/java/com/nextcloud/talk/adapters/messages/UnreadNoticeMessageViewHolder.java b/app/src/main/java/com/nextcloud/talk/adapters/messages/UnreadNoticeMessageViewHolder.java index 6ae3d5003f..2628470c4e 100644 --- a/app/src/main/java/com/nextcloud/talk/adapters/messages/UnreadNoticeMessageViewHolder.java +++ b/app/src/main/java/com/nextcloud/talk/adapters/messages/UnreadNoticeMessageViewHolder.java @@ -24,7 +24,6 @@ public UnreadNoticeMessageViewHolder(View itemView, Object payload) { @Override public void viewDetached() { -// messagesListAdapter.deleteById("-1"); } @Override diff --git a/app/src/main/java/com/nextcloud/talk/chat/ChatActivity.kt b/app/src/main/java/com/nextcloud/talk/chat/ChatActivity.kt index 552a14c8de..1ca68beb3b 100644 --- a/app/src/main/java/com/nextcloud/talk/chat/ChatActivity.kt +++ b/app/src/main/java/com/nextcloud/talk/chat/ChatActivity.kt @@ -296,7 +296,6 @@ class ChatActivity : var mentionAutocomplete: Autocomplete<*>? = null var layoutManager: LinearLayoutManager? = null var pullChatMessagesPending = false - var newMessagesCount = 0 var startCallFromNotification: Boolean = false var startCallFromRoomSwitch: Boolean = false @@ -758,8 +757,8 @@ class ChatActivity : removeUnreadMessagesMarker() - if (binding.unreadMessagesPopup.isShown == true) { - binding.unreadMessagesPopup.hide() + if (binding.unreadMessagesPopup.isShown) { + binding.unreadMessagesPopup.visibility = View.GONE } binding.messagesListView.smoothScrollToPosition(0) } @@ -770,8 +769,8 @@ class ChatActivity : if (code.toString().startsWith("2")) { myFirstMessage = state.message - if (binding.unreadMessagesPopup.isShown == true) { - binding.unreadMessagesPopup.hide() + if (binding.unreadMessagesPopup.isShown) { + binding.unreadMessagesPopup.visibility = View.GONE } binding.messagesListView.smoothScrollToPosition(0) @@ -1016,7 +1015,7 @@ class ChatActivity : } private fun removeUnreadMessagesMarker() { - val index = adapter?.getMessagePositionById("-1") + val index = adapter?.getMessagePositionById(UNREAD_MESSAGES_MARKER_ID.toString()) if (index != null && index != -1) { adapter?.items?.removeAt(index) } @@ -1041,22 +1040,9 @@ class ChatActivity : setupSwipeToReply() - binding.unreadMessagesPopup.setRecyclerView(binding.messagesListView) - - binding.unreadMessagesPopup.setPopupBubbleListener { _ -> - if (newMessagesCount != 0) { - val scrollPosition = if (newMessagesCount - 1 < 0) { - 0 - } else { - newMessagesCount - 1 - } - Handler().postDelayed( - { - binding.messagesListView.smoothScrollToPosition(scrollPosition) - }, - NEW_MESSAGES_POPUP_BUBBLE_DELAY - ) - } + binding.unreadMessagesPopup.setOnClickListener { + binding.messagesListView.smoothScrollToPosition(0) + binding.unreadMessagesPopup.visibility = View.GONE } binding.scrollDownButton.setOnClickListener { @@ -1075,21 +1061,14 @@ class ChatActivity : super.onScrollStateChanged(recyclerView, newState) if (newState == AbsListView.OnScrollListener.SCROLL_STATE_IDLE) { - if (layoutManager!!.findFirstCompletelyVisibleItemPosition() > 0 && - !binding.unreadMessagesPopup.isShown - ) { - binding.scrollDownButton.visibility = View.VISIBLE - } else { + if (isScrolledToBottom()) { + binding.unreadMessagesPopup.visibility = View.GONE binding.scrollDownButton.visibility = View.GONE - } - - if (newMessagesCount != 0 && layoutManager != null) { - if (layoutManager!!.findFirstCompletelyVisibleItemPosition() < newMessagesCount) { - newMessagesCount = 0 - - if (binding.unreadMessagesPopup.isShown) { - binding.unreadMessagesPopup.hide() - } + } else { + if (binding.unreadMessagesPopup.isShown) { + binding.scrollDownButton.visibility = View.GONE + } else { + binding.scrollDownButton.visibility = View.VISIBLE } } } @@ -2677,7 +2656,7 @@ class ChatActivity : scrollToBottom = true } else { scrollToBottom = false - binding.unreadMessagesPopup.show() + binding.unreadMessagesPopup.visibility = View.VISIBLE // here we have the problem that the chat jumps for every update } } @@ -2698,13 +2677,18 @@ class ChatActivity : it.addToStart(chatMessage, scrollToBottom) } } + + // workaround to jump back to unread messages marker + if (setUnreadMessagesMarker) { + scrollToFirstUnreadMessage() + } } private fun isScrolledToBottom() = layoutManager?.findFirstVisibleItemPosition() == 0 private fun setUnreadMessageMarker(chatMessageList: List) { val unreadChatMessage = ChatMessage() - unreadChatMessage.jsonMessageId = -1 + unreadChatMessage.jsonMessageId = UNREAD_MESSAGES_MARKER_ID unreadChatMessage.actorId = "-1" unreadChatMessage.timestamp = chatMessageList[0].timestamp unreadChatMessage.message = context.getString(R.string.nc_new_messages) @@ -2736,7 +2720,7 @@ class ChatActivity : private fun scrollToFirstUnreadMessage() { adapter?.let { - scrollToAndCenterMessageWithId("-1") + scrollToAndCenterMessageWithId(UNREAD_MESSAGES_MARKER_ID.toString()) } } @@ -3552,7 +3536,7 @@ class ChatActivity : CONTENT_TYPE_POLL -> message.isPoll() CONTENT_TYPE_LINK_PREVIEW -> message.isLinkPreview() CONTENT_TYPE_SYSTEM_MESSAGE -> !TextUtils.isEmpty(message.systemMessage) - CONTENT_TYPE_UNREAD_NOTICE_MESSAGE -> message.id == "-1" + CONTENT_TYPE_UNREAD_NOTICE_MESSAGE -> message.id == UNREAD_MESSAGES_MARKER_ID.toString() CONTENT_TYPE_CALL_STARTED -> message.id == "-2" CONTENT_TYPE_TEMP -> message.id == "-3" CONTENT_TYPE_DECK_CARD -> message.isDeckCard() @@ -3762,6 +3746,7 @@ class ChatActivity : private const val CONTENT_TYPE_LINK_PREVIEW: Byte = 7 private const val CONTENT_TYPE_DECK_CARD: Byte = 8 private const val CONTENT_TYPE_TEMP: Byte = 9 + private const val UNREAD_MESSAGES_MARKER_ID = -1 private const val NEW_MESSAGES_POPUP_BUBBLE_DELAY: Long = 200 private const val GET_ROOM_INFO_DELAY_NORMAL: Long = 30000 private const val GET_ROOM_INFO_DELAY_LOBBY: Long = 5000 diff --git a/app/src/main/res/layout/activity_chat.xml b/app/src/main/res/layout/activity_chat.xml index b73e404d93..c6d5e791be 100644 --- a/app/src/main/res/layout/activity_chat.xml +++ b/app/src/main/res/layout/activity_chat.xml @@ -157,8 +157,9 @@ app:textAutoLink="all" tools:visibility="visible" /> - From 662ddd275e8baf4ae5738b27eb6f0de4505e8af9 Mon Sep 17 00:00:00 2001 From: Marcel Hibbe Date: Tue, 29 Oct 2024 14:47:20 +0100 Subject: [PATCH 284/885] remove unused constants from ChatActivity Signed-off-by: Marcel Hibbe --- .../com/nextcloud/talk/chat/ChatActivity.kt | 34 +------------------ 1 file changed, 1 insertion(+), 33 deletions(-) diff --git a/app/src/main/java/com/nextcloud/talk/chat/ChatActivity.kt b/app/src/main/java/com/nextcloud/talk/chat/ChatActivity.kt index 1ca68beb3b..0845caddd6 100644 --- a/app/src/main/java/com/nextcloud/talk/chat/ChatActivity.kt +++ b/app/src/main/java/com/nextcloud/talk/chat/ChatActivity.kt @@ -3747,28 +3747,15 @@ class ChatActivity : private const val CONTENT_TYPE_DECK_CARD: Byte = 8 private const val CONTENT_TYPE_TEMP: Byte = 9 private const val UNREAD_MESSAGES_MARKER_ID = -1 - private const val NEW_MESSAGES_POPUP_BUBBLE_DELAY: Long = 200 + private const val CALL_STARTED_ID = -2 private const val GET_ROOM_INFO_DELAY_NORMAL: Long = 30000 private const val GET_ROOM_INFO_DELAY_LOBBY: Long = 5000 - private const val HTTP_CODE_OK: Int = 200 private const val AGE_THRESHOLD_FOR_DELETE_MESSAGE: Int = 21600000 // (6 hours in millis = 6 * 3600 * 1000) private const val REQUEST_SHARE_FILE_PERMISSION: Int = 221 private const val REQUEST_RECORD_AUDIO_PERMISSION = 222 private const val REQUEST_READ_CONTACT_PERMISSION = 234 private const val REQUEST_CAMERA_PERMISSION = 223 - private const val OBJECT_MESSAGE: String = "{object}" - private const val MINIMUM_VOICE_RECORD_DURATION: Int = 1000 - private const val MINIMUM_VOICE_RECORD_TO_STOP: Int = 200 - private const val VOICE_RECORD_CANCEL_SLIDER_X: Int = -50 - private const val VOICE_RECORD_LOCK_BUTTON_Y: Int = -130 private const val VOICE_MESSAGE_META_DATA = "{\"messageType\":\"voice-message\"}" - private const val VOICE_MESSAGE_FILE_SUFFIX = ".mp3" - - // Samplingrate 22050 was chosen because somehow 44100 failed to playback on safari when recorded on android. - // Please test with firefox, chrome, safari and mobile clients if changing anything regarding the sound. - private const val VOICE_MESSAGE_SAMPLING_RATE = 22050 - private const val VOICE_MESSAGE_ENCODING_BIT_RATE = 32000 - private const val VOICE_MESSAGE_CHANNELS = 1 private const val FILE_DATE_PATTERN = "yyyy-MM-dd HH-mm-ss" private const val VIDEO_SUFFIX = ".mp4" private const val FULLY_OPAQUE_INT: Int = 255 @@ -3777,40 +3764,21 @@ class ChatActivity : private const val NO_PREVIOUS_MESSAGE_ID: Int = -1 private const val TOOLBAR_AVATAR_RATIO = 1.5 private const val STATUS_SIZE_IN_DP = 9f - private const val HTTP_CODE_NOT_MODIFIED = 304 - private const val HTTP_CODE_PRECONDITION_FAILED = 412 private const val HTTP_BAD_REQUEST = 400 private const val HTTP_FORBIDDEN = 403 private const val HTTP_NOT_FOUND = 404 - private const val QUOTED_MESSAGE_IMAGE_MAX_HEIGHT = 96f - private const val MENTION_AUTO_COMPLETE_ELEVATION = 6f private const val MESSAGE_PULL_LIMIT = 100 - private const val PAGE_SIZE = 100 private const val INVITE_LENGTH = 6 private const val ACTOR_LENGTH = 6 - private const val ANIMATION_DURATION: Long = 750 - private const val LOOKING_INTO_FUTURE_TIMEOUT = 30 private const val CHUNK_SIZE: Int = 10 private const val ONE_SECOND_IN_MILLIS = 1000 - private const val SAMPLE_RATE = 8000 - private const val VOICE_RECORDING_LOCK_ANIMATION_DURATION = 500 - private const val AUDIO_VALUE_MAX = 40 - private const val AUDIO_VALUE_MIN = 20 - private const val AUDIO_VALUE_SLEEP: Long = 50 private const val WHITESPACE = " " private const val COMMA = ", " private const val TYPING_INDICATOR_ANIMATION_DURATION = 200L private const val TYPING_INDICATOR_MAX_NAME_LENGTH = 14 private const val TYPING_INDICATOR_POSITION_VISIBLE = -18f private const val TYPING_INDICATOR_POSITION_HIDDEN = -1f - private const val TYPING_DURATION_TO_SEND_NEXT_TYPING_MESSAGE = 10000L - private const val TYPING_INTERVAL_TO_SEND_NEXT_TYPING_MESSAGE = 1000L - private const val TYPING_STARTED_SIGNALING_MESSAGE_TYPE = "startedTyping" - private const val TYPING_STOPPED_SIGNALING_MESSAGE_TYPE = "stoppedTyping" - private const val CALL_STARTED_ID = -2 private const val MILISEC_15: Long = 15 - private const val LINEBREAK = "\n" - private const val CURSOR_KEY = "_cursor" private const val CURRENT_AUDIO_MESSAGE_KEY = "CURRENT_AUDIO_MESSAGE" private const val CURRENT_AUDIO_POSITION_KEY = "CURRENT_AUDIO_POSITION" private const val CURRENT_AUDIO_WAS_PLAYING_KEY = "CURRENT_AUDIO_PLAYING" From ff9055252755ac312d55dfec640bd314dcc6bf39 Mon Sep 17 00:00:00 2001 From: Marcel Hibbe Date: Tue, 5 Nov 2024 13:31:42 +0100 Subject: [PATCH 285/885] rename pair to triple Signed-off-by: Marcel Hibbe --- .../chat/data/network/OfflineFirstChatRepository.kt | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/app/src/main/java/com/nextcloud/talk/chat/data/network/OfflineFirstChatRepository.kt b/app/src/main/java/com/nextcloud/talk/chat/data/network/OfflineFirstChatRepository.kt index b0fc8d0812..7be5caaed3 100644 --- a/app/src/main/java/com/nextcloud/talk/chat/data/network/OfflineFirstChatRepository.kt +++ b/app/src/main/java/com/nextcloud/talk/chat/data/network/OfflineFirstChatRepository.kt @@ -285,8 +285,8 @@ class OfflineFirstChatRepository @Inject constructor( val weHaveMessagesFromOurself = chatMessages.any { it.actorId == currentUser.userId } showUnreadMessagesMarker = showUnreadMessagesMarker && !weHaveMessagesFromOurself - val pair = Triple(true, showUnreadMessagesMarker, chatMessages) - _messageFlow.emit(pair) + val triple = Triple(true, showUnreadMessagesMarker, chatMessages) + _messageFlow.emit(triple) } else { Log.d(TAG, "resultsFromSync are null or empty") } @@ -684,8 +684,8 @@ class OfflineFirstChatRepository @Inject constructor( ) if (list.isNotEmpty()) { - val pair = Triple(false, false, list) - _messageFlow.emit(pair) + val triple = Triple(false, false, list) + _messageFlow.emit(triple) } } @@ -710,8 +710,8 @@ class OfflineFirstChatRepository @Inject constructor( ) if (list.isNotEmpty()) { - val pair = Triple(false, false, list) - _messageFlow.emit(pair) + val triple = Triple(false, false, list) + _messageFlow.emit(triple) } } From 219163c4a88ce0c1012b27cc060f02e09bf141cc Mon Sep 17 00:00:00 2001 From: Marcel Hibbe Date: Tue, 5 Nov 2024 12:06:23 +0100 Subject: [PATCH 286/885] revert 11.json to the state before modifications for "hasArchived" Signed-off-by: Marcel Hibbe --- .../11.json | 1434 ++++++++--------- 1 file changed, 714 insertions(+), 720 deletions(-) diff --git a/app/schemas/com.nextcloud.talk.data.source.local.TalkDatabase/11.json b/app/schemas/com.nextcloud.talk.data.source.local.TalkDatabase/11.json index a655cd9f79..d021477167 100644 --- a/app/schemas/com.nextcloud.talk.data.source.local.TalkDatabase/11.json +++ b/app/schemas/com.nextcloud.talk.data.source.local.TalkDatabase/11.json @@ -1,725 +1,719 @@ { - "formatVersion": 1, - "database": { - "version": 11, - "identityHash": "7edb537b6987d0de6586a6760c970958", - "entities": [ - { - "tableName": "User", - "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `userId` TEXT, `username` TEXT, `baseUrl` TEXT, `token` TEXT, `displayName` TEXT, `pushConfigurationState` TEXT, `capabilities` TEXT, `serverVersion` TEXT DEFAULT '', `clientCertificate` TEXT, `externalSignalingServer` TEXT, `current` INTEGER NOT NULL, `scheduledForDeletion` INTEGER NOT NULL)", - "fields": [ - { - "fieldPath": "id", - "columnName": "id", - "affinity": "INTEGER", - "notNull": true - }, - { - "fieldPath": "userId", - "columnName": "userId", - "affinity": "TEXT", - "notNull": false - }, - { - "fieldPath": "username", - "columnName": "username", - "affinity": "TEXT", - "notNull": false - }, - { - "fieldPath": "baseUrl", - "columnName": "baseUrl", - "affinity": "TEXT", - "notNull": false - }, - { - "fieldPath": "token", - "columnName": "token", - "affinity": "TEXT", - "notNull": false - }, - { - "fieldPath": "displayName", - "columnName": "displayName", - "affinity": "TEXT", - "notNull": false - }, - { - "fieldPath": "pushConfigurationState", - "columnName": "pushConfigurationState", - "affinity": "TEXT", - "notNull": false - }, - { - "fieldPath": "capabilities", - "columnName": "capabilities", - "affinity": "TEXT", - "notNull": false - }, - { - "fieldPath": "serverVersion", - "columnName": "serverVersion", - "affinity": "TEXT", - "notNull": false, - "defaultValue": "''" - }, - { - "fieldPath": "clientCertificate", - "columnName": "clientCertificate", - "affinity": "TEXT", - "notNull": false - }, - { - "fieldPath": "externalSignalingServer", - "columnName": "externalSignalingServer", - "affinity": "TEXT", - "notNull": false - }, - { - "fieldPath": "current", - "columnName": "current", - "affinity": "INTEGER", - "notNull": true - }, - { - "fieldPath": "scheduledForDeletion", - "columnName": "scheduledForDeletion", - "affinity": "INTEGER", - "notNull": true - } - ], - "primaryKey": { - "autoGenerate": true, - "columnNames": [ - "id" - ] - }, - "indices": [], - "foreignKeys": [] - }, - { - "tableName": "ArbitraryStorage", - "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`accountIdentifier` INTEGER NOT NULL, `key` TEXT NOT NULL, `object` TEXT, `value` TEXT, PRIMARY KEY(`accountIdentifier`, `key`))", - "fields": [ - { - "fieldPath": "accountIdentifier", - "columnName": "accountIdentifier", - "affinity": "INTEGER", - "notNull": true - }, - { - "fieldPath": "key", - "columnName": "key", - "affinity": "TEXT", - "notNull": true - }, - { - "fieldPath": "storageObject", - "columnName": "object", - "affinity": "TEXT", - "notNull": false - }, - { - "fieldPath": "value", - "columnName": "value", - "affinity": "TEXT", - "notNull": false - } - ], - "primaryKey": { - "autoGenerate": false, - "columnNames": [ - "accountIdentifier", - "key" - ] - }, - "indices": [], - "foreignKeys": [] - }, - { - "tableName": "Conversations", - "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`internalId` TEXT NOT NULL, `accountId` INTEGER NOT NULL, `token` TEXT NOT NULL, `displayName` TEXT NOT NULL, `actorId` TEXT NOT NULL, `actorType` TEXT NOT NULL, `avatarVersion` TEXT NOT NULL, `callFlag` INTEGER NOT NULL, `callRecording` INTEGER NOT NULL, `callStartTime` INTEGER NOT NULL, `canDeleteConversation` INTEGER NOT NULL, `canLeaveConversation` INTEGER NOT NULL, `canStartCall` INTEGER NOT NULL, `description` TEXT NOT NULL, `hasCall` INTEGER NOT NULL, `hasPassword` INTEGER NOT NULL, `isCustomAvatar` INTEGER NOT NULL, `isFavorite` INTEGER NOT NULL, `lastActivity` INTEGER NOT NULL, `lastCommonReadMessage` INTEGER NOT NULL, `lastMessage` TEXT, `lastPing` INTEGER NOT NULL, `lastReadMessage` INTEGER NOT NULL, `lobbyState` TEXT NOT NULL, `lobbyTimer` INTEGER NOT NULL, `messageExpiration` INTEGER NOT NULL, `name` TEXT NOT NULL, `notificationCalls` INTEGER NOT NULL, `notificationLevel` TEXT NOT NULL, `objectType` TEXT NOT NULL, `participantType` TEXT NOT NULL, `permissions` INTEGER NOT NULL, `readOnly` TEXT NOT NULL, `recordingConsent` INTEGER NOT NULL, `remoteServer` TEXT, `remoteToken` TEXT, `sessionId` TEXT NOT NULL, `status` TEXT, `statusClearAt` INTEGER, `statusIcon` TEXT, `statusMessage` TEXT, `type` TEXT NOT NULL, `unreadMention` INTEGER NOT NULL, `unreadMentionDirect` INTEGER NOT NULL, `unreadMessages` INTEGER NOT NULL, `hasArchived` INTEGER NOT NULL, PRIMARY KEY(`internalId`), FOREIGN KEY(`accountId`) REFERENCES `User`(`id`) ON UPDATE CASCADE ON DELETE CASCADE )", - "fields": [ - { - "fieldPath": "internalId", - "columnName": "internalId", - "affinity": "TEXT", - "notNull": true - }, - { - "fieldPath": "accountId", - "columnName": "accountId", - "affinity": "INTEGER", - "notNull": true - }, - { - "fieldPath": "token", - "columnName": "token", - "affinity": "TEXT", - "notNull": true - }, - { - "fieldPath": "displayName", - "columnName": "displayName", - "affinity": "TEXT", - "notNull": true - }, - { - "fieldPath": "actorId", - "columnName": "actorId", - "affinity": "TEXT", - "notNull": true - }, - { - "fieldPath": "actorType", - "columnName": "actorType", - "affinity": "TEXT", - "notNull": true - }, - { - "fieldPath": "avatarVersion", - "columnName": "avatarVersion", - "affinity": "TEXT", - "notNull": true - }, - { - "fieldPath": "callFlag", - "columnName": "callFlag", - "affinity": "INTEGER", - "notNull": true - }, - { - "fieldPath": "callRecording", - "columnName": "callRecording", - "affinity": "INTEGER", - "notNull": true - }, - { - "fieldPath": "callStartTime", - "columnName": "callStartTime", - "affinity": "INTEGER", - "notNull": true - }, - { - "fieldPath": "canDeleteConversation", - "columnName": "canDeleteConversation", - "affinity": "INTEGER", - "notNull": true - }, - { - "fieldPath": "canLeaveConversation", - "columnName": "canLeaveConversation", - "affinity": "INTEGER", - "notNull": true - }, - { - "fieldPath": "canStartCall", - "columnName": "canStartCall", - "affinity": "INTEGER", - "notNull": true - }, - { - "fieldPath": "description", - "columnName": "description", - "affinity": "TEXT", - "notNull": true - }, - { - "fieldPath": "hasCall", - "columnName": "hasCall", - "affinity": "INTEGER", - "notNull": true - }, - { - "fieldPath": "hasPassword", - "columnName": "hasPassword", - "affinity": "INTEGER", - "notNull": true - }, - { - "fieldPath": "hasCustomAvatar", - "columnName": "isCustomAvatar", - "affinity": "INTEGER", - "notNull": true - }, - { - "fieldPath": "favorite", - "columnName": "isFavorite", - "affinity": "INTEGER", - "notNull": true - }, - { - "fieldPath": "lastActivity", - "columnName": "lastActivity", - "affinity": "INTEGER", - "notNull": true - }, - { - "fieldPath": "lastCommonReadMessage", - "columnName": "lastCommonReadMessage", - "affinity": "INTEGER", - "notNull": true - }, - { - "fieldPath": "lastMessage", - "columnName": "lastMessage", - "affinity": "TEXT", - "notNull": false - }, - { - "fieldPath": "lastPing", - "columnName": "lastPing", - "affinity": "INTEGER", - "notNull": true - }, - { - "fieldPath": "lastReadMessage", - "columnName": "lastReadMessage", - "affinity": "INTEGER", - "notNull": true - }, - { - "fieldPath": "lobbyState", - "columnName": "lobbyState", - "affinity": "TEXT", - "notNull": true - }, - { - "fieldPath": "lobbyTimer", - "columnName": "lobbyTimer", - "affinity": "INTEGER", - "notNull": true - }, - { - "fieldPath": "messageExpiration", - "columnName": "messageExpiration", - "affinity": "INTEGER", - "notNull": true - }, - { - "fieldPath": "name", - "columnName": "name", - "affinity": "TEXT", - "notNull": true - }, - { - "fieldPath": "notificationCalls", - "columnName": "notificationCalls", - "affinity": "INTEGER", - "notNull": true - }, - { - "fieldPath": "notificationLevel", - "columnName": "notificationLevel", - "affinity": "TEXT", - "notNull": true - }, - { - "fieldPath": "objectType", - "columnName": "objectType", - "affinity": "TEXT", - "notNull": true - }, - { - "fieldPath": "participantType", - "columnName": "participantType", - "affinity": "TEXT", - "notNull": true - }, - { - "fieldPath": "permissions", - "columnName": "permissions", - "affinity": "INTEGER", - "notNull": true - }, - { - "fieldPath": "conversationReadOnlyState", - "columnName": "readOnly", - "affinity": "TEXT", - "notNull": true - }, - { - "fieldPath": "recordingConsentRequired", - "columnName": "recordingConsent", - "affinity": "INTEGER", - "notNull": true - }, - { - "fieldPath": "remoteServer", - "columnName": "remoteServer", - "affinity": "TEXT", - "notNull": false - }, - { - "fieldPath": "remoteToken", - "columnName": "remoteToken", - "affinity": "TEXT", - "notNull": false - }, - { - "fieldPath": "sessionId", - "columnName": "sessionId", - "affinity": "TEXT", - "notNull": true - }, - { - "fieldPath": "status", - "columnName": "status", - "affinity": "TEXT", - "notNull": false - }, - { - "fieldPath": "statusClearAt", - "columnName": "statusClearAt", - "affinity": "INTEGER", - "notNull": false - }, - { - "fieldPath": "statusIcon", - "columnName": "statusIcon", - "affinity": "TEXT", - "notNull": false - }, - { - "fieldPath": "statusMessage", - "columnName": "statusMessage", - "affinity": "TEXT", - "notNull": false - }, - { - "fieldPath": "type", - "columnName": "type", - "affinity": "TEXT", - "notNull": true - }, - { - "fieldPath": "unreadMention", - "columnName": "unreadMention", - "affinity": "INTEGER", - "notNull": true - }, - { - "fieldPath": "unreadMentionDirect", - "columnName": "unreadMentionDirect", - "affinity": "INTEGER", - "notNull": true - }, - { - "fieldPath": "unreadMessages", - "columnName": "unreadMessages", - "affinity": "INTEGER", - "notNull": true - }, + "formatVersion": 1, + "database": { + "version": 11, + "identityHash": "bc802cadfdef41d3eb94ffbb0729eb89", + "entities": [ { - "fieldPath": "hasArchived", - "columnName": "hasArchived", - "affinity": "INTEGER", - "notNull": true - } - ], - "primaryKey": { - "autoGenerate": false, - "columnNames": [ - "internalId" - ] - }, - "indices": [ - { - "name": "index_Conversations_accountId", - "unique": false, - "columnNames": [ - "accountId" - ], - "orders": [], - "createSql": "CREATE INDEX IF NOT EXISTS `index_Conversations_accountId` ON `${TABLE_NAME}` (`accountId`)" - } - ], - "foreignKeys": [ - { - "table": "User", - "onDelete": "CASCADE", - "onUpdate": "CASCADE", - "columns": [ - "accountId" - ], - "referencedColumns": [ - "id" - ] - } - ] - }, - { - "tableName": "ChatMessages", - "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`internalId` TEXT NOT NULL, `accountId` INTEGER NOT NULL, `token` TEXT NOT NULL, `id` INTEGER NOT NULL, `internalConversationId` TEXT NOT NULL, `actorDisplayName` TEXT NOT NULL, `message` TEXT NOT NULL, `actorId` TEXT NOT NULL, `actorType` TEXT NOT NULL, `deleted` INTEGER NOT NULL, `expirationTimestamp` INTEGER NOT NULL, `isReplyable` INTEGER NOT NULL, `lastEditActorDisplayName` TEXT, `lastEditActorId` TEXT, `lastEditActorType` TEXT, `lastEditTimestamp` INTEGER, `markdown` INTEGER, `messageParameters` TEXT, `messageType` TEXT NOT NULL, `parent` INTEGER, `reactions` TEXT, `reactionsSelf` TEXT, `systemMessage` TEXT NOT NULL, `timestamp` INTEGER NOT NULL, PRIMARY KEY(`internalId`), FOREIGN KEY(`internalConversationId`) REFERENCES `Conversations`(`internalId`) ON UPDATE CASCADE ON DELETE CASCADE )", - "fields": [ - { - "fieldPath": "internalId", - "columnName": "internalId", - "affinity": "TEXT", - "notNull": true - }, - { - "fieldPath": "accountId", - "columnName": "accountId", - "affinity": "INTEGER", - "notNull": true - }, - { - "fieldPath": "token", - "columnName": "token", - "affinity": "TEXT", - "notNull": true - }, - { - "fieldPath": "id", - "columnName": "id", - "affinity": "INTEGER", - "notNull": true - }, - { - "fieldPath": "internalConversationId", - "columnName": "internalConversationId", - "affinity": "TEXT", - "notNull": true - }, - { - "fieldPath": "actorDisplayName", - "columnName": "actorDisplayName", - "affinity": "TEXT", - "notNull": true - }, - { - "fieldPath": "message", - "columnName": "message", - "affinity": "TEXT", - "notNull": true - }, - { - "fieldPath": "actorId", - "columnName": "actorId", - "affinity": "TEXT", - "notNull": true - }, - { - "fieldPath": "actorType", - "columnName": "actorType", - "affinity": "TEXT", - "notNull": true - }, - { - "fieldPath": "deleted", - "columnName": "deleted", - "affinity": "INTEGER", - "notNull": true - }, - { - "fieldPath": "expirationTimestamp", - "columnName": "expirationTimestamp", - "affinity": "INTEGER", - "notNull": true - }, - { - "fieldPath": "replyable", - "columnName": "isReplyable", - "affinity": "INTEGER", - "notNull": true - }, - { - "fieldPath": "lastEditActorDisplayName", - "columnName": "lastEditActorDisplayName", - "affinity": "TEXT", - "notNull": false - }, - { - "fieldPath": "lastEditActorId", - "columnName": "lastEditActorId", - "affinity": "TEXT", - "notNull": false - }, - { - "fieldPath": "lastEditActorType", - "columnName": "lastEditActorType", - "affinity": "TEXT", - "notNull": false - }, - { - "fieldPath": "lastEditTimestamp", - "columnName": "lastEditTimestamp", - "affinity": "INTEGER", - "notNull": false - }, - { - "fieldPath": "renderMarkdown", - "columnName": "markdown", - "affinity": "INTEGER", - "notNull": false - }, - { - "fieldPath": "messageParameters", - "columnName": "messageParameters", - "affinity": "TEXT", - "notNull": false - }, - { - "fieldPath": "messageType", - "columnName": "messageType", - "affinity": "TEXT", - "notNull": true - }, - { - "fieldPath": "parentMessageId", - "columnName": "parent", - "affinity": "INTEGER", - "notNull": false - }, - { - "fieldPath": "reactions", - "columnName": "reactions", - "affinity": "TEXT", - "notNull": false - }, - { - "fieldPath": "reactionsSelf", - "columnName": "reactionsSelf", - "affinity": "TEXT", - "notNull": false - }, - { - "fieldPath": "systemMessageType", - "columnName": "systemMessage", - "affinity": "TEXT", - "notNull": true - }, - { - "fieldPath": "timestamp", - "columnName": "timestamp", - "affinity": "INTEGER", - "notNull": true - } - ], - "primaryKey": { - "autoGenerate": false, - "columnNames": [ - "internalId" - ] - }, - "indices": [ - { - "name": "index_ChatMessages_internalId", - "unique": true, - "columnNames": [ - "internalId" - ], - "orders": [], - "createSql": "CREATE UNIQUE INDEX IF NOT EXISTS `index_ChatMessages_internalId` ON `${TABLE_NAME}` (`internalId`)" - }, - { - "name": "index_ChatMessages_internalConversationId", - "unique": false, - "columnNames": [ - "internalConversationId" - ], - "orders": [], - "createSql": "CREATE INDEX IF NOT EXISTS `index_ChatMessages_internalConversationId` ON `${TABLE_NAME}` (`internalConversationId`)" - } - ], - "foreignKeys": [ - { - "table": "Conversations", - "onDelete": "CASCADE", - "onUpdate": "CASCADE", - "columns": [ - "internalConversationId" - ], - "referencedColumns": [ - "internalId" - ] - } - ] - }, - { - "tableName": "ChatBlocks", - "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `internalConversationId` TEXT NOT NULL, `accountId` INTEGER, `token` TEXT, `oldestMessageId` INTEGER NOT NULL, `newestMessageId` INTEGER NOT NULL, `hasHistory` INTEGER NOT NULL, FOREIGN KEY(`internalConversationId`) REFERENCES `Conversations`(`internalId`) ON UPDATE CASCADE ON DELETE CASCADE )", - "fields": [ - { - "fieldPath": "id", - "columnName": "id", - "affinity": "INTEGER", - "notNull": true - }, - { - "fieldPath": "internalConversationId", - "columnName": "internalConversationId", - "affinity": "TEXT", - "notNull": true - }, - { - "fieldPath": "accountId", - "columnName": "accountId", - "affinity": "INTEGER", - "notNull": false - }, - { - "fieldPath": "token", - "columnName": "token", - "affinity": "TEXT", - "notNull": false - }, - { - "fieldPath": "oldestMessageId", - "columnName": "oldestMessageId", - "affinity": "INTEGER", - "notNull": true - }, - { - "fieldPath": "newestMessageId", - "columnName": "newestMessageId", - "affinity": "INTEGER", - "notNull": true - }, - { - "fieldPath": "hasHistory", - "columnName": "hasHistory", - "affinity": "INTEGER", - "notNull": true - } - ], - "primaryKey": { - "autoGenerate": true, - "columnNames": [ - "id" - ] - }, - "indices": [ - { - "name": "index_ChatBlocks_internalConversationId", - "unique": false, - "columnNames": [ - "internalConversationId" - ], - "orders": [], - "createSql": "CREATE INDEX IF NOT EXISTS `index_ChatBlocks_internalConversationId` ON `${TABLE_NAME}` (`internalConversationId`)" - } + "tableName": "User", + "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `userId` TEXT, `username` TEXT, `baseUrl` TEXT, `token` TEXT, `displayName` TEXT, `pushConfigurationState` TEXT, `capabilities` TEXT, `serverVersion` TEXT DEFAULT '', `clientCertificate` TEXT, `externalSignalingServer` TEXT, `current` INTEGER NOT NULL, `scheduledForDeletion` INTEGER NOT NULL)", + "fields": [ + { + "fieldPath": "id", + "columnName": "id", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "userId", + "columnName": "userId", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "username", + "columnName": "username", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "baseUrl", + "columnName": "baseUrl", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "token", + "columnName": "token", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "displayName", + "columnName": "displayName", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "pushConfigurationState", + "columnName": "pushConfigurationState", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "capabilities", + "columnName": "capabilities", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "serverVersion", + "columnName": "serverVersion", + "affinity": "TEXT", + "notNull": false, + "defaultValue": "''" + }, + { + "fieldPath": "clientCertificate", + "columnName": "clientCertificate", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "externalSignalingServer", + "columnName": "externalSignalingServer", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "current", + "columnName": "current", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "scheduledForDeletion", + "columnName": "scheduledForDeletion", + "affinity": "INTEGER", + "notNull": true + } + ], + "primaryKey": { + "autoGenerate": true, + "columnNames": [ + "id" + ] + }, + "indices": [], + "foreignKeys": [] + }, + { + "tableName": "ArbitraryStorage", + "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`accountIdentifier` INTEGER NOT NULL, `key` TEXT NOT NULL, `object` TEXT, `value` TEXT, PRIMARY KEY(`accountIdentifier`, `key`))", + "fields": [ + { + "fieldPath": "accountIdentifier", + "columnName": "accountIdentifier", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "key", + "columnName": "key", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "storageObject", + "columnName": "object", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "value", + "columnName": "value", + "affinity": "TEXT", + "notNull": false + } + ], + "primaryKey": { + "autoGenerate": false, + "columnNames": [ + "accountIdentifier", + "key" + ] + }, + "indices": [], + "foreignKeys": [] + }, + { + "tableName": "Conversations", + "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`internalId` TEXT NOT NULL, `accountId` INTEGER NOT NULL, `token` TEXT NOT NULL, `displayName` TEXT NOT NULL, `actorId` TEXT NOT NULL, `actorType` TEXT NOT NULL, `avatarVersion` TEXT NOT NULL, `callFlag` INTEGER NOT NULL, `callRecording` INTEGER NOT NULL, `callStartTime` INTEGER NOT NULL, `canDeleteConversation` INTEGER NOT NULL, `canLeaveConversation` INTEGER NOT NULL, `canStartCall` INTEGER NOT NULL, `description` TEXT NOT NULL, `hasCall` INTEGER NOT NULL, `hasPassword` INTEGER NOT NULL, `isCustomAvatar` INTEGER NOT NULL, `isFavorite` INTEGER NOT NULL, `lastActivity` INTEGER NOT NULL, `lastCommonReadMessage` INTEGER NOT NULL, `lastMessage` TEXT, `lastPing` INTEGER NOT NULL, `lastReadMessage` INTEGER NOT NULL, `lobbyState` TEXT NOT NULL, `lobbyTimer` INTEGER NOT NULL, `messageExpiration` INTEGER NOT NULL, `name` TEXT NOT NULL, `notificationCalls` INTEGER NOT NULL, `notificationLevel` TEXT NOT NULL, `objectType` TEXT NOT NULL, `participantType` TEXT NOT NULL, `permissions` INTEGER NOT NULL, `readOnly` TEXT NOT NULL, `recordingConsent` INTEGER NOT NULL, `remoteServer` TEXT, `remoteToken` TEXT, `sessionId` TEXT NOT NULL, `status` TEXT, `statusClearAt` INTEGER, `statusIcon` TEXT, `statusMessage` TEXT, `type` TEXT NOT NULL, `unreadMention` INTEGER NOT NULL, `unreadMentionDirect` INTEGER NOT NULL, `unreadMessages` INTEGER NOT NULL, PRIMARY KEY(`internalId`), FOREIGN KEY(`accountId`) REFERENCES `User`(`id`) ON UPDATE CASCADE ON DELETE CASCADE )", + "fields": [ + { + "fieldPath": "internalId", + "columnName": "internalId", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "accountId", + "columnName": "accountId", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "token", + "columnName": "token", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "displayName", + "columnName": "displayName", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "actorId", + "columnName": "actorId", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "actorType", + "columnName": "actorType", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "avatarVersion", + "columnName": "avatarVersion", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "callFlag", + "columnName": "callFlag", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "callRecording", + "columnName": "callRecording", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "callStartTime", + "columnName": "callStartTime", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "canDeleteConversation", + "columnName": "canDeleteConversation", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "canLeaveConversation", + "columnName": "canLeaveConversation", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "canStartCall", + "columnName": "canStartCall", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "description", + "columnName": "description", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "hasCall", + "columnName": "hasCall", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "hasPassword", + "columnName": "hasPassword", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "hasCustomAvatar", + "columnName": "isCustomAvatar", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "favorite", + "columnName": "isFavorite", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "lastActivity", + "columnName": "lastActivity", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "lastCommonReadMessage", + "columnName": "lastCommonReadMessage", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "lastMessage", + "columnName": "lastMessage", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "lastPing", + "columnName": "lastPing", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "lastReadMessage", + "columnName": "lastReadMessage", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "lobbyState", + "columnName": "lobbyState", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "lobbyTimer", + "columnName": "lobbyTimer", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "messageExpiration", + "columnName": "messageExpiration", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "name", + "columnName": "name", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "notificationCalls", + "columnName": "notificationCalls", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "notificationLevel", + "columnName": "notificationLevel", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "objectType", + "columnName": "objectType", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "participantType", + "columnName": "participantType", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "permissions", + "columnName": "permissions", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "conversationReadOnlyState", + "columnName": "readOnly", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "recordingConsentRequired", + "columnName": "recordingConsent", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "remoteServer", + "columnName": "remoteServer", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "remoteToken", + "columnName": "remoteToken", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "sessionId", + "columnName": "sessionId", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "status", + "columnName": "status", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "statusClearAt", + "columnName": "statusClearAt", + "affinity": "INTEGER", + "notNull": false + }, + { + "fieldPath": "statusIcon", + "columnName": "statusIcon", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "statusMessage", + "columnName": "statusMessage", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "type", + "columnName": "type", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "unreadMention", + "columnName": "unreadMention", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "unreadMentionDirect", + "columnName": "unreadMentionDirect", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "unreadMessages", + "columnName": "unreadMessages", + "affinity": "INTEGER", + "notNull": true + } + ], + "primaryKey": { + "autoGenerate": false, + "columnNames": [ + "internalId" + ] + }, + "indices": [ + { + "name": "index_Conversations_accountId", + "unique": false, + "columnNames": [ + "accountId" + ], + "orders": [], + "createSql": "CREATE INDEX IF NOT EXISTS `index_Conversations_accountId` ON `${TABLE_NAME}` (`accountId`)" + } + ], + "foreignKeys": [ + { + "table": "User", + "onDelete": "CASCADE", + "onUpdate": "CASCADE", + "columns": [ + "accountId" + ], + "referencedColumns": [ + "id" + ] + } + ] + }, + { + "tableName": "ChatMessages", + "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`internalId` TEXT NOT NULL, `accountId` INTEGER NOT NULL, `token` TEXT NOT NULL, `id` INTEGER NOT NULL, `internalConversationId` TEXT NOT NULL, `actorDisplayName` TEXT NOT NULL, `message` TEXT NOT NULL, `actorId` TEXT NOT NULL, `actorType` TEXT NOT NULL, `deleted` INTEGER NOT NULL, `expirationTimestamp` INTEGER NOT NULL, `isReplyable` INTEGER NOT NULL, `lastEditActorDisplayName` TEXT, `lastEditActorId` TEXT, `lastEditActorType` TEXT, `lastEditTimestamp` INTEGER, `markdown` INTEGER, `messageParameters` TEXT, `messageType` TEXT NOT NULL, `parent` INTEGER, `reactions` TEXT, `reactionsSelf` TEXT, `systemMessage` TEXT NOT NULL, `timestamp` INTEGER NOT NULL, PRIMARY KEY(`internalId`), FOREIGN KEY(`internalConversationId`) REFERENCES `Conversations`(`internalId`) ON UPDATE CASCADE ON DELETE CASCADE )", + "fields": [ + { + "fieldPath": "internalId", + "columnName": "internalId", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "accountId", + "columnName": "accountId", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "token", + "columnName": "token", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "id", + "columnName": "id", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "internalConversationId", + "columnName": "internalConversationId", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "actorDisplayName", + "columnName": "actorDisplayName", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "message", + "columnName": "message", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "actorId", + "columnName": "actorId", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "actorType", + "columnName": "actorType", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "deleted", + "columnName": "deleted", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "expirationTimestamp", + "columnName": "expirationTimestamp", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "replyable", + "columnName": "isReplyable", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "lastEditActorDisplayName", + "columnName": "lastEditActorDisplayName", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "lastEditActorId", + "columnName": "lastEditActorId", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "lastEditActorType", + "columnName": "lastEditActorType", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "lastEditTimestamp", + "columnName": "lastEditTimestamp", + "affinity": "INTEGER", + "notNull": false + }, + { + "fieldPath": "renderMarkdown", + "columnName": "markdown", + "affinity": "INTEGER", + "notNull": false + }, + { + "fieldPath": "messageParameters", + "columnName": "messageParameters", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "messageType", + "columnName": "messageType", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "parentMessageId", + "columnName": "parent", + "affinity": "INTEGER", + "notNull": false + }, + { + "fieldPath": "reactions", + "columnName": "reactions", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "reactionsSelf", + "columnName": "reactionsSelf", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "systemMessageType", + "columnName": "systemMessage", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "timestamp", + "columnName": "timestamp", + "affinity": "INTEGER", + "notNull": true + } + ], + "primaryKey": { + "autoGenerate": false, + "columnNames": [ + "internalId" + ] + }, + "indices": [ + { + "name": "index_ChatMessages_internalId", + "unique": true, + "columnNames": [ + "internalId" + ], + "orders": [], + "createSql": "CREATE UNIQUE INDEX IF NOT EXISTS `index_ChatMessages_internalId` ON `${TABLE_NAME}` (`internalId`)" + }, + { + "name": "index_ChatMessages_internalConversationId", + "unique": false, + "columnNames": [ + "internalConversationId" + ], + "orders": [], + "createSql": "CREATE INDEX IF NOT EXISTS `index_ChatMessages_internalConversationId` ON `${TABLE_NAME}` (`internalConversationId`)" + } + ], + "foreignKeys": [ + { + "table": "Conversations", + "onDelete": "CASCADE", + "onUpdate": "CASCADE", + "columns": [ + "internalConversationId" + ], + "referencedColumns": [ + "internalId" + ] + } + ] + }, + { + "tableName": "ChatBlocks", + "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `internalConversationId` TEXT NOT NULL, `accountId` INTEGER, `token` TEXT, `oldestMessageId` INTEGER NOT NULL, `newestMessageId` INTEGER NOT NULL, `hasHistory` INTEGER NOT NULL, FOREIGN KEY(`internalConversationId`) REFERENCES `Conversations`(`internalId`) ON UPDATE CASCADE ON DELETE CASCADE )", + "fields": [ + { + "fieldPath": "id", + "columnName": "id", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "internalConversationId", + "columnName": "internalConversationId", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "accountId", + "columnName": "accountId", + "affinity": "INTEGER", + "notNull": false + }, + { + "fieldPath": "token", + "columnName": "token", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "oldestMessageId", + "columnName": "oldestMessageId", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "newestMessageId", + "columnName": "newestMessageId", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "hasHistory", + "columnName": "hasHistory", + "affinity": "INTEGER", + "notNull": true + } + ], + "primaryKey": { + "autoGenerate": true, + "columnNames": [ + "id" + ] + }, + "indices": [ + { + "name": "index_ChatBlocks_internalConversationId", + "unique": false, + "columnNames": [ + "internalConversationId" + ], + "orders": [], + "createSql": "CREATE INDEX IF NOT EXISTS `index_ChatBlocks_internalConversationId` ON `${TABLE_NAME}` (`internalConversationId`)" + } + ], + "foreignKeys": [ + { + "table": "Conversations", + "onDelete": "CASCADE", + "onUpdate": "CASCADE", + "columns": [ + "internalConversationId" + ], + "referencedColumns": [ + "internalId" + ] + } + ] + } ], - "foreignKeys": [ - { - "table": "Conversations", - "onDelete": "CASCADE", - "onUpdate": "CASCADE", - "columns": [ - "internalConversationId" - ], - "referencedColumns": [ - "internalId" - ] - } + "views": [], + "setupQueries": [ + "CREATE TABLE IF NOT EXISTS room_master_table (id INTEGER PRIMARY KEY,identity_hash TEXT)", + "INSERT OR REPLACE INTO room_master_table (id,identity_hash) VALUES(42, 'bc802cadfdef41d3eb94ffbb0729eb89')" ] - } - ], - "views": [], - "setupQueries": [ - "CREATE TABLE IF NOT EXISTS room_master_table (id INTEGER PRIMARY KEY,identity_hash TEXT)", - "INSERT OR REPLACE INTO room_master_table (id,identity_hash) VALUES(42, '7edb537b6987d0de6586a6760c970958')" - ] - } + } } \ No newline at end of file From 4ff9b2b3c67583945bfacf5b6ee2592a30a9fb38 Mon Sep 17 00:00:00 2001 From: Marcel Hibbe Date: Tue, 5 Nov 2024 12:07:21 +0100 Subject: [PATCH 287/885] add 12.json which includes modifications for "hasArchived" Signed-off-by: Marcel Hibbe --- .../12.json | 725 ++++++++++++++++++ 1 file changed, 725 insertions(+) create mode 100644 app/schemas/com.nextcloud.talk.data.source.local.TalkDatabase/12.json diff --git a/app/schemas/com.nextcloud.talk.data.source.local.TalkDatabase/12.json b/app/schemas/com.nextcloud.talk.data.source.local.TalkDatabase/12.json new file mode 100644 index 0000000000..05c1320a86 --- /dev/null +++ b/app/schemas/com.nextcloud.talk.data.source.local.TalkDatabase/12.json @@ -0,0 +1,725 @@ +{ + "formatVersion": 1, + "database": { + "version": 12, + "identityHash": "7edb537b6987d0de6586a6760c970958", + "entities": [ + { + "tableName": "User", + "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `userId` TEXT, `username` TEXT, `baseUrl` TEXT, `token` TEXT, `displayName` TEXT, `pushConfigurationState` TEXT, `capabilities` TEXT, `serverVersion` TEXT DEFAULT '', `clientCertificate` TEXT, `externalSignalingServer` TEXT, `current` INTEGER NOT NULL, `scheduledForDeletion` INTEGER NOT NULL)", + "fields": [ + { + "fieldPath": "id", + "columnName": "id", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "userId", + "columnName": "userId", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "username", + "columnName": "username", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "baseUrl", + "columnName": "baseUrl", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "token", + "columnName": "token", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "displayName", + "columnName": "displayName", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "pushConfigurationState", + "columnName": "pushConfigurationState", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "capabilities", + "columnName": "capabilities", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "serverVersion", + "columnName": "serverVersion", + "affinity": "TEXT", + "notNull": false, + "defaultValue": "''" + }, + { + "fieldPath": "clientCertificate", + "columnName": "clientCertificate", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "externalSignalingServer", + "columnName": "externalSignalingServer", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "current", + "columnName": "current", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "scheduledForDeletion", + "columnName": "scheduledForDeletion", + "affinity": "INTEGER", + "notNull": true + } + ], + "primaryKey": { + "autoGenerate": true, + "columnNames": [ + "id" + ] + }, + "indices": [], + "foreignKeys": [] + }, + { + "tableName": "ArbitraryStorage", + "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`accountIdentifier` INTEGER NOT NULL, `key` TEXT NOT NULL, `object` TEXT, `value` TEXT, PRIMARY KEY(`accountIdentifier`, `key`))", + "fields": [ + { + "fieldPath": "accountIdentifier", + "columnName": "accountIdentifier", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "key", + "columnName": "key", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "storageObject", + "columnName": "object", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "value", + "columnName": "value", + "affinity": "TEXT", + "notNull": false + } + ], + "primaryKey": { + "autoGenerate": false, + "columnNames": [ + "accountIdentifier", + "key" + ] + }, + "indices": [], + "foreignKeys": [] + }, + { + "tableName": "Conversations", + "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`internalId` TEXT NOT NULL, `accountId` INTEGER NOT NULL, `token` TEXT NOT NULL, `displayName` TEXT NOT NULL, `actorId` TEXT NOT NULL, `actorType` TEXT NOT NULL, `avatarVersion` TEXT NOT NULL, `callFlag` INTEGER NOT NULL, `callRecording` INTEGER NOT NULL, `callStartTime` INTEGER NOT NULL, `canDeleteConversation` INTEGER NOT NULL, `canLeaveConversation` INTEGER NOT NULL, `canStartCall` INTEGER NOT NULL, `description` TEXT NOT NULL, `hasCall` INTEGER NOT NULL, `hasPassword` INTEGER NOT NULL, `isCustomAvatar` INTEGER NOT NULL, `isFavorite` INTEGER NOT NULL, `lastActivity` INTEGER NOT NULL, `lastCommonReadMessage` INTEGER NOT NULL, `lastMessage` TEXT, `lastPing` INTEGER NOT NULL, `lastReadMessage` INTEGER NOT NULL, `lobbyState` TEXT NOT NULL, `lobbyTimer` INTEGER NOT NULL, `messageExpiration` INTEGER NOT NULL, `name` TEXT NOT NULL, `notificationCalls` INTEGER NOT NULL, `notificationLevel` TEXT NOT NULL, `objectType` TEXT NOT NULL, `participantType` TEXT NOT NULL, `permissions` INTEGER NOT NULL, `readOnly` TEXT NOT NULL, `recordingConsent` INTEGER NOT NULL, `remoteServer` TEXT, `remoteToken` TEXT, `sessionId` TEXT NOT NULL, `status` TEXT, `statusClearAt` INTEGER, `statusIcon` TEXT, `statusMessage` TEXT, `type` TEXT NOT NULL, `unreadMention` INTEGER NOT NULL, `unreadMentionDirect` INTEGER NOT NULL, `unreadMessages` INTEGER NOT NULL, `hasArchived` INTEGER NOT NULL, PRIMARY KEY(`internalId`), FOREIGN KEY(`accountId`) REFERENCES `User`(`id`) ON UPDATE CASCADE ON DELETE CASCADE )", + "fields": [ + { + "fieldPath": "internalId", + "columnName": "internalId", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "accountId", + "columnName": "accountId", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "token", + "columnName": "token", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "displayName", + "columnName": "displayName", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "actorId", + "columnName": "actorId", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "actorType", + "columnName": "actorType", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "avatarVersion", + "columnName": "avatarVersion", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "callFlag", + "columnName": "callFlag", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "callRecording", + "columnName": "callRecording", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "callStartTime", + "columnName": "callStartTime", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "canDeleteConversation", + "columnName": "canDeleteConversation", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "canLeaveConversation", + "columnName": "canLeaveConversation", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "canStartCall", + "columnName": "canStartCall", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "description", + "columnName": "description", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "hasCall", + "columnName": "hasCall", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "hasPassword", + "columnName": "hasPassword", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "hasCustomAvatar", + "columnName": "isCustomAvatar", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "favorite", + "columnName": "isFavorite", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "lastActivity", + "columnName": "lastActivity", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "lastCommonReadMessage", + "columnName": "lastCommonReadMessage", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "lastMessage", + "columnName": "lastMessage", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "lastPing", + "columnName": "lastPing", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "lastReadMessage", + "columnName": "lastReadMessage", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "lobbyState", + "columnName": "lobbyState", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "lobbyTimer", + "columnName": "lobbyTimer", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "messageExpiration", + "columnName": "messageExpiration", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "name", + "columnName": "name", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "notificationCalls", + "columnName": "notificationCalls", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "notificationLevel", + "columnName": "notificationLevel", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "objectType", + "columnName": "objectType", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "participantType", + "columnName": "participantType", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "permissions", + "columnName": "permissions", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "conversationReadOnlyState", + "columnName": "readOnly", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "recordingConsentRequired", + "columnName": "recordingConsent", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "remoteServer", + "columnName": "remoteServer", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "remoteToken", + "columnName": "remoteToken", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "sessionId", + "columnName": "sessionId", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "status", + "columnName": "status", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "statusClearAt", + "columnName": "statusClearAt", + "affinity": "INTEGER", + "notNull": false + }, + { + "fieldPath": "statusIcon", + "columnName": "statusIcon", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "statusMessage", + "columnName": "statusMessage", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "type", + "columnName": "type", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "unreadMention", + "columnName": "unreadMention", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "unreadMentionDirect", + "columnName": "unreadMentionDirect", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "unreadMessages", + "columnName": "unreadMessages", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "hasArchived", + "columnName": "hasArchived", + "affinity": "INTEGER", + "notNull": true + } + ], + "primaryKey": { + "autoGenerate": false, + "columnNames": [ + "internalId" + ] + }, + "indices": [ + { + "name": "index_Conversations_accountId", + "unique": false, + "columnNames": [ + "accountId" + ], + "orders": [], + "createSql": "CREATE INDEX IF NOT EXISTS `index_Conversations_accountId` ON `${TABLE_NAME}` (`accountId`)" + } + ], + "foreignKeys": [ + { + "table": "User", + "onDelete": "CASCADE", + "onUpdate": "CASCADE", + "columns": [ + "accountId" + ], + "referencedColumns": [ + "id" + ] + } + ] + }, + { + "tableName": "ChatMessages", + "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`internalId` TEXT NOT NULL, `accountId` INTEGER NOT NULL, `token` TEXT NOT NULL, `id` INTEGER NOT NULL, `internalConversationId` TEXT NOT NULL, `actorDisplayName` TEXT NOT NULL, `message` TEXT NOT NULL, `actorId` TEXT NOT NULL, `actorType` TEXT NOT NULL, `deleted` INTEGER NOT NULL, `expirationTimestamp` INTEGER NOT NULL, `isReplyable` INTEGER NOT NULL, `lastEditActorDisplayName` TEXT, `lastEditActorId` TEXT, `lastEditActorType` TEXT, `lastEditTimestamp` INTEGER, `markdown` INTEGER, `messageParameters` TEXT, `messageType` TEXT NOT NULL, `parent` INTEGER, `reactions` TEXT, `reactionsSelf` TEXT, `systemMessage` TEXT NOT NULL, `timestamp` INTEGER NOT NULL, PRIMARY KEY(`internalId`), FOREIGN KEY(`internalConversationId`) REFERENCES `Conversations`(`internalId`) ON UPDATE CASCADE ON DELETE CASCADE )", + "fields": [ + { + "fieldPath": "internalId", + "columnName": "internalId", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "accountId", + "columnName": "accountId", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "token", + "columnName": "token", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "id", + "columnName": "id", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "internalConversationId", + "columnName": "internalConversationId", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "actorDisplayName", + "columnName": "actorDisplayName", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "message", + "columnName": "message", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "actorId", + "columnName": "actorId", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "actorType", + "columnName": "actorType", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "deleted", + "columnName": "deleted", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "expirationTimestamp", + "columnName": "expirationTimestamp", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "replyable", + "columnName": "isReplyable", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "lastEditActorDisplayName", + "columnName": "lastEditActorDisplayName", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "lastEditActorId", + "columnName": "lastEditActorId", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "lastEditActorType", + "columnName": "lastEditActorType", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "lastEditTimestamp", + "columnName": "lastEditTimestamp", + "affinity": "INTEGER", + "notNull": false + }, + { + "fieldPath": "renderMarkdown", + "columnName": "markdown", + "affinity": "INTEGER", + "notNull": false + }, + { + "fieldPath": "messageParameters", + "columnName": "messageParameters", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "messageType", + "columnName": "messageType", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "parentMessageId", + "columnName": "parent", + "affinity": "INTEGER", + "notNull": false + }, + { + "fieldPath": "reactions", + "columnName": "reactions", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "reactionsSelf", + "columnName": "reactionsSelf", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "systemMessageType", + "columnName": "systemMessage", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "timestamp", + "columnName": "timestamp", + "affinity": "INTEGER", + "notNull": true + } + ], + "primaryKey": { + "autoGenerate": false, + "columnNames": [ + "internalId" + ] + }, + "indices": [ + { + "name": "index_ChatMessages_internalId", + "unique": true, + "columnNames": [ + "internalId" + ], + "orders": [], + "createSql": "CREATE UNIQUE INDEX IF NOT EXISTS `index_ChatMessages_internalId` ON `${TABLE_NAME}` (`internalId`)" + }, + { + "name": "index_ChatMessages_internalConversationId", + "unique": false, + "columnNames": [ + "internalConversationId" + ], + "orders": [], + "createSql": "CREATE INDEX IF NOT EXISTS `index_ChatMessages_internalConversationId` ON `${TABLE_NAME}` (`internalConversationId`)" + } + ], + "foreignKeys": [ + { + "table": "Conversations", + "onDelete": "CASCADE", + "onUpdate": "CASCADE", + "columns": [ + "internalConversationId" + ], + "referencedColumns": [ + "internalId" + ] + } + ] + }, + { + "tableName": "ChatBlocks", + "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `internalConversationId` TEXT NOT NULL, `accountId` INTEGER, `token` TEXT, `oldestMessageId` INTEGER NOT NULL, `newestMessageId` INTEGER NOT NULL, `hasHistory` INTEGER NOT NULL, FOREIGN KEY(`internalConversationId`) REFERENCES `Conversations`(`internalId`) ON UPDATE CASCADE ON DELETE CASCADE )", + "fields": [ + { + "fieldPath": "id", + "columnName": "id", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "internalConversationId", + "columnName": "internalConversationId", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "accountId", + "columnName": "accountId", + "affinity": "INTEGER", + "notNull": false + }, + { + "fieldPath": "token", + "columnName": "token", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "oldestMessageId", + "columnName": "oldestMessageId", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "newestMessageId", + "columnName": "newestMessageId", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "hasHistory", + "columnName": "hasHistory", + "affinity": "INTEGER", + "notNull": true + } + ], + "primaryKey": { + "autoGenerate": true, + "columnNames": [ + "id" + ] + }, + "indices": [ + { + "name": "index_ChatBlocks_internalConversationId", + "unique": false, + "columnNames": [ + "internalConversationId" + ], + "orders": [], + "createSql": "CREATE INDEX IF NOT EXISTS `index_ChatBlocks_internalConversationId` ON `${TABLE_NAME}` (`internalConversationId`)" + } + ], + "foreignKeys": [ + { + "table": "Conversations", + "onDelete": "CASCADE", + "onUpdate": "CASCADE", + "columns": [ + "internalConversationId" + ], + "referencedColumns": [ + "internalId" + ] + } + ] + } + ], + "views": [], + "setupQueries": [ + "CREATE TABLE IF NOT EXISTS room_master_table (id INTEGER PRIMARY KEY,identity_hash TEXT)", + "INSERT OR REPLACE INTO room_master_table (id,identity_hash) VALUES(42, '7edb537b6987d0de6586a6760c970958')" + ] + } +} \ No newline at end of file From 11a4738a4cbebab9ddf3e4f190fa8923b47bb115 Mon Sep 17 00:00:00 2001 From: Marcel Hibbe Date: Tue, 5 Nov 2024 14:37:58 +0100 Subject: [PATCH 288/885] fix addArchiveConversations migration method this will set NOT NULL and DEFAULT 0 to hasArchived column Otherwise there would be an error when updating from the previous DB version: IllegalStateException: Migration didn't properly handle: Conversations(com.nextcloud.talk.data.database.model.ConversationEntity) Signed-off-by: Marcel Hibbe --- .../java/com/nextcloud/talk/data/source/local/Migrations.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/src/main/java/com/nextcloud/talk/data/source/local/Migrations.kt b/app/src/main/java/com/nextcloud/talk/data/source/local/Migrations.kt index e255357cb4..b23e99fd47 100644 --- a/app/src/main/java/com/nextcloud/talk/data/source/local/Migrations.kt +++ b/app/src/main/java/com/nextcloud/talk/data/source/local/Migrations.kt @@ -250,7 +250,7 @@ object Migrations { try { db.execSQL( "ALTER TABLE Conversations " + - "ADD `hasArchived` INTEGER;" + "ADD COLUMN hasArchived INTEGER NOT NULL DEFAULT 0;" ) } catch (e: SQLException) { Log.i("Migrations", "hasArchived already exists") From be55a908d5bde434c223e15cc35e5aa4788bba89 Mon Sep 17 00:00:00 2001 From: sowjanyakch Date: Tue, 15 Oct 2024 22:53:24 +0200 Subject: [PATCH 289/885] Rename .java to .kt Signed-off-by: sowjanyakch --- .../{LeaveConversationWorker.java => LeaveConversationWorker.kt} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename app/src/main/java/com/nextcloud/talk/jobs/{LeaveConversationWorker.java => LeaveConversationWorker.kt} (100%) diff --git a/app/src/main/java/com/nextcloud/talk/jobs/LeaveConversationWorker.java b/app/src/main/java/com/nextcloud/talk/jobs/LeaveConversationWorker.kt similarity index 100% rename from app/src/main/java/com/nextcloud/talk/jobs/LeaveConversationWorker.java rename to app/src/main/java/com/nextcloud/talk/jobs/LeaveConversationWorker.kt From f6824f94f1b9d69873835338b6bf86e319acd399 Mon Sep 17 00:00:00 2001 From: sowjanyakch Date: Tue, 15 Oct 2024 22:53:24 +0200 Subject: [PATCH 290/885] Convert LeaveConversationWorker from java to Kotlin Signed-off-by: sowjanyakch --- .../talk/jobs/LeaveConversationWorker.kt | 161 ++++++++---------- 1 file changed, 70 insertions(+), 91 deletions(-) diff --git a/app/src/main/java/com/nextcloud/talk/jobs/LeaveConversationWorker.kt b/app/src/main/java/com/nextcloud/talk/jobs/LeaveConversationWorker.kt index aee52845e4..fcf4567e48 100644 --- a/app/src/main/java/com/nextcloud/talk/jobs/LeaveConversationWorker.kt +++ b/app/src/main/java/com/nextcloud/talk/jobs/LeaveConversationWorker.kt @@ -5,111 +5,90 @@ * SPDX-FileCopyrightText: 2017-2018 Mario Danic * SPDX-License-Identifier: GPL-3.0-or-later */ -package com.nextcloud.talk.jobs; +package com.nextcloud.talk.jobs + +import android.content.Context +import android.util.Log +import androidx.work.Worker +import androidx.work.WorkerParameters +import autodagger.AutoInjector +import com.nextcloud.talk.api.NcApi +import com.nextcloud.talk.application.NextcloudTalkApplication +import com.nextcloud.talk.application.NextcloudTalkApplication.Companion.sharedApplication +import com.nextcloud.talk.events.EventStatus +import com.nextcloud.talk.models.json.generic.GenericOverall +import com.nextcloud.talk.users.UserManager +import com.nextcloud.talk.utils.ApiUtils +import com.nextcloud.talk.utils.ApiUtils.getConversationApiVersion +import com.nextcloud.talk.utils.ApiUtils.getCredentials +import com.nextcloud.talk.utils.ApiUtils.getUrlForParticipantsSelf +import com.nextcloud.talk.utils.UserIdUtils.getIdForUser +import com.nextcloud.talk.utils.bundle.BundleKeys +import io.reactivex.Observer +import io.reactivex.disposables.Disposable +import io.reactivex.schedulers.Schedulers +import okhttp3.JavaNetCookieJar +import okhttp3.OkHttpClient +import org.greenrobot.eventbus.EventBus +import retrofit2.Retrofit +import java.net.CookieManager +import javax.inject.Inject + +@AutoInjector(NextcloudTalkApplication::class) +class LeaveConversationWorker(val context: Context, workerParams: WorkerParameters) : + Worker(context, workerParams) { -import android.content.Context; -import android.util.Log; + @Inject + lateinit var ncApi: NcApi -import com.nextcloud.talk.api.NcApi; -import com.nextcloud.talk.application.NextcloudTalkApplication; -import com.nextcloud.talk.data.user.model.User; -import com.nextcloud.talk.events.EventStatus; -import com.nextcloud.talk.models.json.generic.GenericOverall; -import com.nextcloud.talk.users.UserManager; -import com.nextcloud.talk.utils.ApiUtils; -import com.nextcloud.talk.utils.UserIdUtils; -import com.nextcloud.talk.utils.bundle.BundleKeys; + @Inject + lateinit var userManager: UserManager -import org.greenrobot.eventbus.EventBus; -import java.net.CookieManager; + override fun doWork(): Result { + sharedApplication!!.componentApplication.inject(this) + val data = inputData + val conversationToken = data.getString(BundleKeys.KEY_ROOM_TOKEN) + val currentUser = userManager.currentUser.blockingGet() -import javax.inject.Inject; + if (currentUser != null) { + val credentials = getCredentials(currentUser.username, currentUser.token) -import androidx.annotation.NonNull; -import androidx.work.Data; -import androidx.work.Worker; -import androidx.work.WorkerParameters; -import autodagger.AutoInjector; -import io.reactivex.Observer; -import io.reactivex.disposables.Disposable; -import io.reactivex.schedulers.Schedulers; -import okhttp3.JavaNetCookieJar; -import okhttp3.OkHttpClient; -import retrofit2.Retrofit; + val apiVersion = getConversationApiVersion(currentUser, intArrayOf(ApiUtils.API_V4, 1)) -@AutoInjector(NextcloudTalkApplication.class) -public class LeaveConversationWorker extends Worker { + ncApi.removeSelfFromRoom( + credentials, getUrlForParticipantsSelf( + apiVersion, + currentUser.baseUrl, + conversationToken + ) + ) + .subscribeOn(Schedulers.io()) + .subscribe(object : Observer { + var disposable: Disposable? = null - private static final String TAG = "LeaveConversationWorker"; + override fun onSubscribe(d: Disposable) { + disposable = d + } - @Inject - Retrofit retrofit; - - @Inject - OkHttpClient okHttpClient; + override fun onNext(p0: GenericOverall) { - @Inject - UserManager userManager; + } - @Inject - EventBus eventBus; + override fun onError(e: Throwable) { + Log.e(TAG, "failed to remove self from room", e) + } - NcApi ncApi; + override fun onComplete() { + disposable!!.dispose() + } + }) + } - public LeaveConversationWorker(@NonNull Context context, @NonNull WorkerParameters workerParams) { - super(context, workerParams); - NextcloudTalkApplication.Companion.getSharedApplication().getComponentApplication().inject(this); + return Result.success() } - @NonNull - @Override - public Result doWork() { - Data data = getInputData(); - long operationUserId = data.getLong(BundleKeys.KEY_INTERNAL_USER_ID, -1); - String conversationToken = data.getString(BundleKeys.KEY_ROOM_TOKEN); - User operationUser = userManager.getUserWithId(operationUserId).blockingGet(); - - if (operationUser != null) { - String credentials = ApiUtils.getCredentials(operationUser.getUsername(), operationUser.getToken()); - ncApi = retrofit.newBuilder().client(okHttpClient.newBuilder().cookieJar(new - JavaNetCookieJar(new CookieManager())).build()).build().create(NcApi.class); - - EventStatus eventStatus = new EventStatus(UserIdUtils.INSTANCE.getIdForUser(operationUser), - EventStatus.EventType.CONVERSATION_UPDATE, - true); - - int apiVersion = ApiUtils.getConversationApiVersion(operationUser, new int[] {ApiUtils.API_V4, 1}); - - ncApi.removeSelfFromRoom(credentials, ApiUtils.getUrlForParticipantsSelf(apiVersion, - operationUser.getBaseUrl(), - conversationToken)) - .subscribeOn(Schedulers.io()) - .blockingSubscribe(new Observer() { - Disposable disposable; - - @Override - public void onSubscribe(Disposable d) { - disposable = d; - } - - @Override - public void onNext(GenericOverall genericOverall) { - eventBus.postSticky(eventStatus); - } - - @Override - public void onError(Throwable e) { - Log.e(TAG, "failed to remove self from room", e); - } - - @Override - public void onComplete() { - disposable.dispose(); - } - }); - } - - return Result.success(); + companion object { + private const val TAG = "LeaveConversationWorker" } } From e04f2362e334979fd0c45f84cb1cce20b03137aa Mon Sep 17 00:00:00 2001 From: sowjanyakch Date: Tue, 15 Oct 2024 22:53:56 +0200 Subject: [PATCH 291/885] remove unused imports Signed-off-by: sowjanyakch --- .../com/nextcloud/talk/jobs/LeaveConversationWorker.kt | 7 ------- 1 file changed, 7 deletions(-) diff --git a/app/src/main/java/com/nextcloud/talk/jobs/LeaveConversationWorker.kt b/app/src/main/java/com/nextcloud/talk/jobs/LeaveConversationWorker.kt index fcf4567e48..1aa232adee 100644 --- a/app/src/main/java/com/nextcloud/talk/jobs/LeaveConversationWorker.kt +++ b/app/src/main/java/com/nextcloud/talk/jobs/LeaveConversationWorker.kt @@ -15,23 +15,16 @@ import autodagger.AutoInjector import com.nextcloud.talk.api.NcApi import com.nextcloud.talk.application.NextcloudTalkApplication import com.nextcloud.talk.application.NextcloudTalkApplication.Companion.sharedApplication -import com.nextcloud.talk.events.EventStatus import com.nextcloud.talk.models.json.generic.GenericOverall import com.nextcloud.talk.users.UserManager import com.nextcloud.talk.utils.ApiUtils import com.nextcloud.talk.utils.ApiUtils.getConversationApiVersion import com.nextcloud.talk.utils.ApiUtils.getCredentials import com.nextcloud.talk.utils.ApiUtils.getUrlForParticipantsSelf -import com.nextcloud.talk.utils.UserIdUtils.getIdForUser import com.nextcloud.talk.utils.bundle.BundleKeys import io.reactivex.Observer import io.reactivex.disposables.Disposable import io.reactivex.schedulers.Schedulers -import okhttp3.JavaNetCookieJar -import okhttp3.OkHttpClient -import org.greenrobot.eventbus.EventBus -import retrofit2.Retrofit -import java.net.CookieManager import javax.inject.Inject @AutoInjector(NextcloudTalkApplication::class) From 088e6fd79f5dbd13d0419fdc2fd1ff0d8ea05a9e Mon Sep 17 00:00:00 2001 From: sowjanyakch Date: Tue, 22 Oct 2024 08:38:48 +0200 Subject: [PATCH 292/885] Start unique work Signed-off-by: sowjanyakch --- .../ConversationInfoActivity.kt | 46 +++++++++++++++---- .../talk/jobs/LeaveConversationWorker.kt | 14 +++--- app/src/main/res/values/strings.xml | 3 ++ 3 files changed, 47 insertions(+), 16 deletions(-) diff --git a/app/src/main/java/com/nextcloud/talk/conversationinfo/ConversationInfoActivity.kt b/app/src/main/java/com/nextcloud/talk/conversationinfo/ConversationInfoActivity.kt index 6381194a0f..1f3d646718 100644 --- a/app/src/main/java/com/nextcloud/talk/conversationinfo/ConversationInfoActivity.kt +++ b/app/src/main/java/com/nextcloud/talk/conversationinfo/ConversationInfoActivity.kt @@ -21,13 +21,16 @@ import android.view.MenuItem import android.view.View import android.view.View.GONE import android.view.View.VISIBLE +import android.widget.Toast import androidx.appcompat.app.AlertDialog import androidx.core.content.res.ResourcesCompat import androidx.fragment.app.FragmentTransaction import androidx.lifecycle.ViewModelProvider import androidx.lifecycle.lifecycleScope import androidx.work.Data +import androidx.work.ExistingWorkPolicy import androidx.work.OneTimeWorkRequest +import androidx.work.WorkInfo import androidx.work.WorkManager import autodagger.AutoInjector import com.afollestad.materialdialogs.LayoutMode.WRAP_CONTENT @@ -635,17 +638,40 @@ class ConversationInfoActivity : } private fun leaveConversation() { - workerData?.let { - WorkManager.getInstance(context).enqueue( - OneTimeWorkRequest.Builder( - LeaveConversationWorker::class - .java - ).setInputData(it).build() - ) + workerData?.let { data -> + val workRequest = OneTimeWorkRequest.Builder(LeaveConversationWorker::class.java) + .setInputData(data) + .build() - val intent = Intent(context, MainActivity::class.java) - intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP) - startActivity(intent) + + WorkManager.getInstance(context) + .enqueueUniqueWork( + "leave_conversation_work", + ExistingWorkPolicy.REPLACE, + workRequest + ) + + + WorkManager.getInstance(context).getWorkInfoByIdLiveData(workRequest.id) + .observe(this, { workInfo: WorkInfo? -> + if (workInfo != null) { + when (workInfo.state) { + WorkInfo.State.SUCCEEDED -> { + + val intent = Intent(context, MainActivity::class.java) + intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP) + startActivity(intent) + } + WorkInfo.State.FAILED -> { + + Toast.makeText(context, R.string.nc_last_moderator_leaving_room_warning, Toast.LENGTH_LONG).show() + } + else -> { + + } + } + } + }) } } diff --git a/app/src/main/java/com/nextcloud/talk/jobs/LeaveConversationWorker.kt b/app/src/main/java/com/nextcloud/talk/jobs/LeaveConversationWorker.kt index 1aa232adee..1f6f222264 100644 --- a/app/src/main/java/com/nextcloud/talk/jobs/LeaveConversationWorker.kt +++ b/app/src/main/java/com/nextcloud/talk/jobs/LeaveConversationWorker.kt @@ -14,7 +14,6 @@ import androidx.work.WorkerParameters import autodagger.AutoInjector import com.nextcloud.talk.api.NcApi import com.nextcloud.talk.application.NextcloudTalkApplication -import com.nextcloud.talk.application.NextcloudTalkApplication.Companion.sharedApplication import com.nextcloud.talk.models.json.generic.GenericOverall import com.nextcloud.talk.users.UserManager import com.nextcloud.talk.utils.ApiUtils @@ -39,10 +38,10 @@ class LeaveConversationWorker(val context: Context, workerParams: WorkerParamete override fun doWork(): Result { - sharedApplication!!.componentApplication.inject(this) val data = inputData val conversationToken = data.getString(BundleKeys.KEY_ROOM_TOKEN) val currentUser = userManager.currentUser.blockingGet() + lateinit var workResult:Result if (currentUser != null) { val credentials = getCredentials(currentUser.username, currentUser.token) @@ -58,10 +57,9 @@ class LeaveConversationWorker(val context: Context, workerParams: WorkerParamete ) .subscribeOn(Schedulers.io()) .subscribe(object : Observer { - var disposable: Disposable? = null override fun onSubscribe(d: Disposable) { - disposable = d + } override fun onNext(p0: GenericOverall) { @@ -70,15 +68,19 @@ class LeaveConversationWorker(val context: Context, workerParams: WorkerParamete override fun onError(e: Throwable) { Log.e(TAG, "failed to remove self from room", e) + if(e.message?.contains("HTTP 400") == true){ + workResult = Result.failure() + } } override fun onComplete() { - disposable!!.dispose() + workResult = Result.success() + } }) } - return Result.success() + return workResult } companion object { diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 92ed5be924..fb81016d33 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -505,6 +505,9 @@ How to translate with transifex: Delete Message deleted successfully, but it might have been leaked to other services You are not allowed to start a call + + You need to promote a new moderator before you can leave the conversation + Share Send to From aa5fd42c59540bb20033e8578c471b58f5a2ebbb Mon Sep 17 00:00:00 2001 From: sowjanyakch Date: Fri, 25 Oct 2024 09:17:30 +0200 Subject: [PATCH 293/885] handle workResult Signed-off-by: sowjanyakch --- .../java/com/nextcloud/talk/jobs/LeaveConversationWorker.kt | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/app/src/main/java/com/nextcloud/talk/jobs/LeaveConversationWorker.kt b/app/src/main/java/com/nextcloud/talk/jobs/LeaveConversationWorker.kt index 1f6f222264..801efbea23 100644 --- a/app/src/main/java/com/nextcloud/talk/jobs/LeaveConversationWorker.kt +++ b/app/src/main/java/com/nextcloud/talk/jobs/LeaveConversationWorker.kt @@ -38,6 +38,7 @@ class LeaveConversationWorker(val context: Context, workerParams: WorkerParamete override fun doWork(): Result { + NextcloudTalkApplication.sharedApplication!!.componentApplication.inject(this) val data = inputData val conversationToken = data.getString(BundleKeys.KEY_ROOM_TOKEN) val currentUser = userManager.currentUser.blockingGet() @@ -78,6 +79,9 @@ class LeaveConversationWorker(val context: Context, workerParams: WorkerParamete } }) + }else{ + + workResult = Result.failure() } return workResult From a07a5446befc4b9ba4b0a9973450c82dc1fd1991 Mon Sep 17 00:00:00 2001 From: sowjanyakch Date: Sun, 27 Oct 2024 16:59:13 +0100 Subject: [PATCH 294/885] make worker listenable Signed-off-by: sowjanyakch --- .../ConversationInfoActivity.kt | 3 -- .../talk/jobs/LeaveConversationWorker.kt | 46 +++++++++---------- 2 files changed, 21 insertions(+), 28 deletions(-) diff --git a/app/src/main/java/com/nextcloud/talk/conversationinfo/ConversationInfoActivity.kt b/app/src/main/java/com/nextcloud/talk/conversationinfo/ConversationInfoActivity.kt index 1f3d646718..ca39bb0726 100644 --- a/app/src/main/java/com/nextcloud/talk/conversationinfo/ConversationInfoActivity.kt +++ b/app/src/main/java/com/nextcloud/talk/conversationinfo/ConversationInfoActivity.kt @@ -643,7 +643,6 @@ class ConversationInfoActivity : .setInputData(data) .build() - WorkManager.getInstance(context) .enqueueUniqueWork( "leave_conversation_work", @@ -651,13 +650,11 @@ class ConversationInfoActivity : workRequest ) - WorkManager.getInstance(context).getWorkInfoByIdLiveData(workRequest.id) .observe(this, { workInfo: WorkInfo? -> if (workInfo != null) { when (workInfo.state) { WorkInfo.State.SUCCEEDED -> { - val intent = Intent(context, MainActivity::class.java) intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP) startActivity(intent) diff --git a/app/src/main/java/com/nextcloud/talk/jobs/LeaveConversationWorker.kt b/app/src/main/java/com/nextcloud/talk/jobs/LeaveConversationWorker.kt index 801efbea23..7e9f63b5e7 100644 --- a/app/src/main/java/com/nextcloud/talk/jobs/LeaveConversationWorker.kt +++ b/app/src/main/java/com/nextcloud/talk/jobs/LeaveConversationWorker.kt @@ -7,11 +7,14 @@ */ package com.nextcloud.talk.jobs +import android.annotation.SuppressLint import android.content.Context import android.util.Log -import androidx.work.Worker +import androidx.work.ListenableWorker import androidx.work.WorkerParameters +import androidx.work.impl.utils.futures.SettableFuture import autodagger.AutoInjector +import com.google.common.util.concurrent.ListenableFuture import com.nextcloud.talk.api.NcApi import com.nextcloud.talk.application.NextcloudTalkApplication import com.nextcloud.talk.models.json.generic.GenericOverall @@ -22,13 +25,15 @@ import com.nextcloud.talk.utils.ApiUtils.getCredentials import com.nextcloud.talk.utils.ApiUtils.getUrlForParticipantsSelf import com.nextcloud.talk.utils.bundle.BundleKeys import io.reactivex.Observer +import io.reactivex.android.schedulers.AndroidSchedulers import io.reactivex.disposables.Disposable import io.reactivex.schedulers.Schedulers import javax.inject.Inject +@SuppressLint("RestrictedApi") @AutoInjector(NextcloudTalkApplication::class) -class LeaveConversationWorker(val context: Context, workerParams: WorkerParameters) : - Worker(context, workerParams) { +class LeaveConversationWorker(context: Context, workerParams: WorkerParameters) : + ListenableWorker(context, workerParams) { @Inject lateinit var ncApi: NcApi @@ -36,55 +41,46 @@ class LeaveConversationWorker(val context: Context, workerParams: WorkerParamete @Inject lateinit var userManager: UserManager + private val result = SettableFuture.create() - override fun doWork(): Result { + override fun startWork(): ListenableFuture { NextcloudTalkApplication.sharedApplication!!.componentApplication.inject(this) - val data = inputData - val conversationToken = data.getString(BundleKeys.KEY_ROOM_TOKEN) + val conversationToken = inputData.getString(BundleKeys.KEY_ROOM_TOKEN) val currentUser = userManager.currentUser.blockingGet() - lateinit var workResult:Result - if (currentUser != null) { + if (currentUser != null && conversationToken != null) { val credentials = getCredentials(currentUser.username, currentUser.token) - val apiVersion = getConversationApiVersion(currentUser, intArrayOf(ApiUtils.API_V4, 1)) ncApi.removeSelfFromRoom( - credentials, getUrlForParticipantsSelf( - apiVersion, - currentUser.baseUrl, - conversationToken - ) + credentials, getUrlForParticipantsSelf(apiVersion, currentUser.baseUrl, conversationToken) ) .subscribeOn(Schedulers.io()) + .observeOn(AndroidSchedulers.mainThread()) .subscribe(object : Observer { - override fun onSubscribe(d: Disposable) { } override fun onNext(p0: GenericOverall) { - } override fun onError(e: Throwable) { - Log.e(TAG, "failed to remove self from room", e) - if(e.message?.contains("HTTP 400") == true){ - workResult = Result.failure() + Log.e(TAG, "Failed to remove self from room", e) + if (e.message?.contains("HTTP 400") == true) { + result.set(Result.failure()) } } override fun onComplete() { - workResult = Result.success() - + result.set(Result.success()) } }) - }else{ - - workResult = Result.failure() + } else { + result.set(Result.failure()) } - return workResult + return result } companion object { From 9df91b6e74a09e438fd9e0f77687c2b8be5e30d0 Mon Sep 17 00:00:00 2001 From: sowjanyakch Date: Sun, 27 Oct 2024 17:01:17 +0100 Subject: [PATCH 295/885] refresh main activity after leaving a conversation Signed-off-by: sowjanyakch --- .../nextcloud/talk/ui/dialog/ConversationsListBottomDialog.kt | 4 ++++ 1 file changed, 4 insertions(+) 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 66cff6d7b3..9dbd718413 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 @@ -6,6 +6,7 @@ */ package com.nextcloud.talk.ui.dialog +import android.content.Intent import android.os.Bundle import android.text.TextUtils import android.view.View @@ -18,6 +19,7 @@ import autodagger.AutoInjector import com.google.android.material.bottomsheet.BottomSheetBehavior import com.google.android.material.bottomsheet.BottomSheetDialog import com.nextcloud.talk.R +import com.nextcloud.talk.activities.MainActivity import com.nextcloud.talk.api.NcApi import com.nextcloud.talk.application.NextcloudTalkApplication import com.nextcloud.talk.conversation.RenameConversationDialogFragment @@ -393,6 +395,8 @@ class ConversationsListBottomDialog( conversation.displayName ) ) + val intent = Intent(context, MainActivity::class.java) + context.startActivity(intent) } WorkInfo.State.FAILED -> { From f6489eb10d11f6bc71ec205172201c87763397c6 Mon Sep 17 00:00:00 2001 From: sowjanyakch Date: Sun, 27 Oct 2024 17:04:14 +0100 Subject: [PATCH 296/885] ktlintFormat Signed-off-by: sowjanyakch --- .../talk/conversationinfo/ConversationInfoActivity.kt | 8 +++++--- .../com/nextcloud/talk/jobs/LeaveConversationWorker.kt | 4 ++-- 2 files changed, 7 insertions(+), 5 deletions(-) diff --git a/app/src/main/java/com/nextcloud/talk/conversationinfo/ConversationInfoActivity.kt b/app/src/main/java/com/nextcloud/talk/conversationinfo/ConversationInfoActivity.kt index ca39bb0726..b5c66e3dd6 100644 --- a/app/src/main/java/com/nextcloud/talk/conversationinfo/ConversationInfoActivity.kt +++ b/app/src/main/java/com/nextcloud/talk/conversationinfo/ConversationInfoActivity.kt @@ -660,11 +660,13 @@ class ConversationInfoActivity : startActivity(intent) } WorkInfo.State.FAILED -> { - - Toast.makeText(context, R.string.nc_last_moderator_leaving_room_warning, Toast.LENGTH_LONG).show() + Toast.makeText( + context, + R.string.nc_last_moderator_leaving_room_warning, + Toast.LENGTH_LONG + ).show() } else -> { - } } } diff --git a/app/src/main/java/com/nextcloud/talk/jobs/LeaveConversationWorker.kt b/app/src/main/java/com/nextcloud/talk/jobs/LeaveConversationWorker.kt index 7e9f63b5e7..3c946b254e 100644 --- a/app/src/main/java/com/nextcloud/talk/jobs/LeaveConversationWorker.kt +++ b/app/src/main/java/com/nextcloud/talk/jobs/LeaveConversationWorker.kt @@ -53,13 +53,13 @@ class LeaveConversationWorker(context: Context, workerParams: WorkerParameters) val apiVersion = getConversationApiVersion(currentUser, intArrayOf(ApiUtils.API_V4, 1)) ncApi.removeSelfFromRoom( - credentials, getUrlForParticipantsSelf(apiVersion, currentUser.baseUrl, conversationToken) + credentials, + getUrlForParticipantsSelf(apiVersion, currentUser.baseUrl, conversationToken) ) .subscribeOn(Schedulers.io()) .observeOn(AndroidSchedulers.mainThread()) .subscribe(object : Observer { override fun onSubscribe(d: Disposable) { - } override fun onNext(p0: GenericOverall) { From 6c4685dce5893fdbcd2ae00bc093e55d816da7f6 Mon Sep 17 00:00:00 2001 From: sowjanyakch Date: Tue, 29 Oct 2024 16:57:01 +0100 Subject: [PATCH 297/885] handle errors properly Signed-off-by: sowjanyakch --- .../conversationinfo/ConversationInfoActivity.kt | 12 ++++++------ .../talk/jobs/LeaveConversationWorker.kt | 16 ++++++++++++++-- 2 files changed, 20 insertions(+), 8 deletions(-) diff --git a/app/src/main/java/com/nextcloud/talk/conversationinfo/ConversationInfoActivity.kt b/app/src/main/java/com/nextcloud/talk/conversationinfo/ConversationInfoActivity.kt index b5c66e3dd6..2cfcb07ea1 100644 --- a/app/src/main/java/com/nextcloud/talk/conversationinfo/ConversationInfoActivity.kt +++ b/app/src/main/java/com/nextcloud/talk/conversationinfo/ConversationInfoActivity.kt @@ -21,7 +21,6 @@ import android.view.MenuItem import android.view.View import android.view.View.GONE import android.view.View.VISIBLE -import android.widget.Toast import androidx.appcompat.app.AlertDialog import androidx.core.content.res.ResourcesCompat import androidx.fragment.app.FragmentTransaction @@ -660,11 +659,12 @@ class ConversationInfoActivity : startActivity(intent) } WorkInfo.State.FAILED -> { - Toast.makeText( - context, - R.string.nc_last_moderator_leaving_room_warning, - Toast.LENGTH_LONG - ).show() + val errorType = workInfo.outputData.getString("error_type") + if (errorType == LeaveConversationWorker.ERROR_NO_OTHER_MODERATORS_OR_OWNERS_LEFT) { + Snackbar.make( binding.root, R.string.nc_last_moderator_leaving_room_warning, Snackbar.LENGTH_LONG ).show() + } else { + Snackbar.make( binding.root, R.string.nc_common_error_sorry, Snackbar.LENGTH_LONG ).show() + } } else -> { } diff --git a/app/src/main/java/com/nextcloud/talk/jobs/LeaveConversationWorker.kt b/app/src/main/java/com/nextcloud/talk/jobs/LeaveConversationWorker.kt index 3c946b254e..55eeb897e6 100644 --- a/app/src/main/java/com/nextcloud/talk/jobs/LeaveConversationWorker.kt +++ b/app/src/main/java/com/nextcloud/talk/jobs/LeaveConversationWorker.kt @@ -10,6 +10,7 @@ package com.nextcloud.talk.jobs import android.annotation.SuppressLint import android.content.Context import android.util.Log +import androidx.work.Data import androidx.work.ListenableWorker import androidx.work.WorkerParameters import androidx.work.impl.utils.futures.SettableFuture @@ -28,6 +29,7 @@ import io.reactivex.Observer import io.reactivex.android.schedulers.AndroidSchedulers import io.reactivex.disposables.Disposable import io.reactivex.schedulers.Schedulers +import retrofit2.HttpException import javax.inject.Inject @SuppressLint("RestrictedApi") @@ -67,9 +69,17 @@ class LeaveConversationWorker(context: Context, workerParams: WorkerParameters) override fun onError(e: Throwable) { Log.e(TAG, "Failed to remove self from room", e) - if (e.message?.contains("HTTP 400") == true) { - result.set(Result.failure()) + val httpException = e as? HttpException + val errorData = if (httpException?.code() == 400) { + Data.Builder() + .putString("error_type", ERROR_NO_OTHER_MODERATORS_OR_OWNERS_LEFT) + .build() } + else { + Data.Builder() + .putString("error_type", ERROR_OTHER) + .build() } + result.set(Result.failure(errorData)) } override fun onComplete() { @@ -85,5 +95,7 @@ class LeaveConversationWorker(context: Context, workerParams: WorkerParameters) companion object { private const val TAG = "LeaveConversationWorker" + const val ERROR_NO_OTHER_MODERATORS_OR_OWNERS_LEFT = "NO_OTHER_MODERATORS_OR_OWNERS_LEFT" + const val ERROR_OTHER = "ERROR_OTHER" } } From a39ca256dea7aba191c5fa9889350baf2c571913 Mon Sep 17 00:00:00 2001 From: sowjanyakch Date: Tue, 29 Oct 2024 17:24:31 +0100 Subject: [PATCH 298/885] add const val for error code Signed-off-by: sowjanyakch --- .../conversationinfo/ConversationInfoActivity.kt | 12 ++++++++++-- .../nextcloud/talk/jobs/LeaveConversationWorker.kt | 9 +++++---- 2 files changed, 15 insertions(+), 6 deletions(-) diff --git a/app/src/main/java/com/nextcloud/talk/conversationinfo/ConversationInfoActivity.kt b/app/src/main/java/com/nextcloud/talk/conversationinfo/ConversationInfoActivity.kt index 2cfcb07ea1..56630615a8 100644 --- a/app/src/main/java/com/nextcloud/talk/conversationinfo/ConversationInfoActivity.kt +++ b/app/src/main/java/com/nextcloud/talk/conversationinfo/ConversationInfoActivity.kt @@ -661,9 +661,17 @@ class ConversationInfoActivity : WorkInfo.State.FAILED -> { val errorType = workInfo.outputData.getString("error_type") if (errorType == LeaveConversationWorker.ERROR_NO_OTHER_MODERATORS_OR_OWNERS_LEFT) { - Snackbar.make( binding.root, R.string.nc_last_moderator_leaving_room_warning, Snackbar.LENGTH_LONG ).show() + Snackbar.make( + binding.root, + R.string.nc_last_moderator_leaving_room_warning, + Snackbar.LENGTH_LONG + ).show() } else { - Snackbar.make( binding.root, R.string.nc_common_error_sorry, Snackbar.LENGTH_LONG ).show() + Snackbar.make( + binding.root, + R.string.nc_common_error_sorry, + Snackbar.LENGTH_LONG + ).show() } } else -> { diff --git a/app/src/main/java/com/nextcloud/talk/jobs/LeaveConversationWorker.kt b/app/src/main/java/com/nextcloud/talk/jobs/LeaveConversationWorker.kt index 55eeb897e6..bf746199e2 100644 --- a/app/src/main/java/com/nextcloud/talk/jobs/LeaveConversationWorker.kt +++ b/app/src/main/java/com/nextcloud/talk/jobs/LeaveConversationWorker.kt @@ -70,15 +70,15 @@ class LeaveConversationWorker(context: Context, workerParams: WorkerParameters) override fun onError(e: Throwable) { Log.e(TAG, "Failed to remove self from room", e) val httpException = e as? HttpException - val errorData = if (httpException?.code() == 400) { + val errorData = if (httpException?.code() == HTTP_ERROR_CODE_400) { Data.Builder() .putString("error_type", ERROR_NO_OTHER_MODERATORS_OR_OWNERS_LEFT) .build() - } - else { + } else { Data.Builder() .putString("error_type", ERROR_OTHER) - .build() } + .build() + } result.set(Result.failure(errorData)) } @@ -97,5 +97,6 @@ class LeaveConversationWorker(context: Context, workerParams: WorkerParameters) private const val TAG = "LeaveConversationWorker" const val ERROR_NO_OTHER_MODERATORS_OR_OWNERS_LEFT = "NO_OTHER_MODERATORS_OR_OWNERS_LEFT" const val ERROR_OTHER = "ERROR_OTHER" + const val HTTP_ERROR_CODE_400 = 400 } } From 2ad8c2eabcd114825460e9b214b8cd68e2e6f8d3 Mon Sep 17 00:00:00 2001 From: Marcel Hibbe Date: Tue, 5 Nov 2024 15:00:51 +0100 Subject: [PATCH 299/885] set nc_last_moderator_leaving_room_warning to one line in strings.xml Signed-off-by: Marcel Hibbe --- app/src/main/res/values/strings.xml | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index fb81016d33..8fc1c3406a 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -505,9 +505,7 @@ How to translate with transifex: Delete Message deleted successfully, but it might have been leaked to other services You are not allowed to start a call - - You need to promote a new moderator before you can leave the conversation - + You need to promote a new moderator before you can leave the conversation Share Send to From d96682889c77c6363d295b4d10ebdc6af59d766c Mon Sep 17 00:00:00 2001 From: rapterjet2004 Date: Thu, 24 Oct 2024 08:39:16 -0500 Subject: [PATCH 300/885] fix to display message queue when revisiting chat in offline mode Signed-off-by: rapterjet2004 --- app/src/main/java/com/nextcloud/talk/chat/ChatActivity.kt | 6 ++---- .../java/com/nextcloud/talk/chat/MessageInputFragment.kt | 2 -- .../nextcloud/talk/chat/viewmodels/MessageInputViewModel.kt | 1 - 3 files changed, 2 insertions(+), 7 deletions(-) diff --git a/app/src/main/java/com/nextcloud/talk/chat/ChatActivity.kt b/app/src/main/java/com/nextcloud/talk/chat/ChatActivity.kt index 0845caddd6..08103488ce 100644 --- a/app/src/main/java/com/nextcloud/talk/chat/ChatActivity.kt +++ b/app/src/main/java/com/nextcloud/talk/chat/ChatActivity.kt @@ -91,13 +91,13 @@ import com.nextcloud.talk.adapters.messages.IncomingPreviewMessageViewHolder import com.nextcloud.talk.adapters.messages.IncomingTextMessageViewHolder import com.nextcloud.talk.adapters.messages.IncomingVoiceMessageViewHolder import com.nextcloud.talk.adapters.messages.MessagePayload +import com.nextcloud.talk.adapters.messages.OutcomingDeckCardViewHolder import com.nextcloud.talk.adapters.messages.OutcomingLinkPreviewMessageViewHolder import com.nextcloud.talk.adapters.messages.OutcomingLocationMessageViewHolder import com.nextcloud.talk.adapters.messages.OutcomingPollMessageViewHolder import com.nextcloud.talk.adapters.messages.OutcomingPreviewMessageViewHolder import com.nextcloud.talk.adapters.messages.OutcomingTextMessageViewHolder import com.nextcloud.talk.adapters.messages.OutcomingVoiceMessageViewHolder -import com.nextcloud.talk.adapters.messages.OutcomingDeckCardViewHolder import com.nextcloud.talk.adapters.messages.PreviewMessageInterface import com.nextcloud.talk.adapters.messages.PreviewMessageViewHolder import com.nextcloud.talk.adapters.messages.SystemMessageInterface @@ -540,7 +540,6 @@ class ChatActivity : messageInputViewModel.messageQueueFlow.observe(this) { list -> list.forEachIndexed { _, qMsg -> - Log.d("Julius", "Message recieved: ${qMsg.message}") val temporaryChatMessage = ChatMessage() temporaryChatMessage.jsonMessageId = -3 temporaryChatMessage.actorId = "-3" @@ -565,7 +564,6 @@ class ChatActivity : pos = adapter?.getMessagePositionById("-3") } adapter?.notifyDataSetChanged() - Log.d("Julius", "End i: $i") } } @@ -664,13 +662,13 @@ class ChatActivity : withCredentials = credentials!!, withUrl = urlForChatting ) + messageInputViewModel.getTempMessagesFromMessageQueue(currentConversation!!.internalId) } } else { Log.w( TAG, "currentConversation was null in observer ChatViewModel.GetCapabilitiesInitialLoadState" ) - messageInputViewModel.getTempMessagesFromMessageQueue(currentConversation!!.internalId) } } diff --git a/app/src/main/java/com/nextcloud/talk/chat/MessageInputFragment.kt b/app/src/main/java/com/nextcloud/talk/chat/MessageInputFragment.kt index 79af0a4f53..9ddcc6c560 100644 --- a/app/src/main/java/com/nextcloud/talk/chat/MessageInputFragment.kt +++ b/app/src/main/java/com/nextcloud/talk/chat/MessageInputFragment.kt @@ -190,8 +190,6 @@ class MessageInputFragment : Fragment() { } chatActivity.messageInputViewModel.messageQueueSizeFlow.observe(viewLifecycleOwner) { size -> - Log.d("Julius", "MessageQueueSizeFlow recieved: $size") - if (size > 0) { binding.fragmentConnectionLost.text = getString(R.string.connection_lost_queued, size) } else { diff --git a/app/src/main/java/com/nextcloud/talk/chat/viewmodels/MessageInputViewModel.kt b/app/src/main/java/com/nextcloud/talk/chat/viewmodels/MessageInputViewModel.kt index c553de7d98..6e17ac0b61 100644 --- a/app/src/main/java/com/nextcloud/talk/chat/viewmodels/MessageInputViewModel.kt +++ b/app/src/main/java/com/nextcloud/talk/chat/viewmodels/MessageInputViewModel.kt @@ -277,7 +277,6 @@ class MessageInputViewModel @Inject constructor( val queue = dataStore.getMessageQueue(internalId) val list = mutableListOf() for (msg in queue) { - Log.d("Julius", "Msg: ${msg.message}") list.add(msg) } _messageQueueFlow.postValue(list) From d9bcf14696e07971f731743e2202baf9afeae68e Mon Sep 17 00:00:00 2001 From: Nextcloud bot Date: Wed, 6 Nov 2024 02:54:03 +0000 Subject: [PATCH 301/885] Fix(l10n): Update translations from Transifex Signed-off-by: Nextcloud bot --- app/src/main/res/values-b+en+001/strings.xml | 1 + app/src/main/res/values-de/strings.xml | 1 + app/src/main/res/values-es-rEC/strings.xml | 1 + app/src/main/res/values-es/strings.xml | 1 + app/src/main/res/values-eu/strings.xml | 1 + app/src/main/res/values-fa/strings.xml | 1 + app/src/main/res/values-fr/strings.xml | 1 + app/src/main/res/values-ga/strings.xml | 1 + app/src/main/res/values-gl/strings.xml | 1 + app/src/main/res/values-hu-rHU/strings.xml | 1 + app/src/main/res/values-ja-rJP/strings.xml | 1 + app/src/main/res/values-ko/strings.xml | 1 + app/src/main/res/values-nb-rNO/strings.xml | 1 + app/src/main/res/values-pl/strings.xml | 1 + app/src/main/res/values-pt-rBR/strings.xml | 1 + app/src/main/res/values-ru/strings.xml | 1 + app/src/main/res/values-sk-rSK/strings.xml | 1 + app/src/main/res/values-sl/strings.xml | 1 + app/src/main/res/values-sr/strings.xml | 1 + app/src/main/res/values-sv/strings.xml | 1 + app/src/main/res/values-tr/strings.xml | 1 + app/src/main/res/values-ug/strings.xml | 1 + app/src/main/res/values-uk/strings.xml | 1 + app/src/main/res/values-zh-rCN/strings.xml | 1 + app/src/main/res/values-zh-rHK/strings.xml | 1 + app/src/main/res/values-zh-rTW/strings.xml | 1 + 26 files changed, 26 insertions(+) diff --git a/app/src/main/res/values-b+en+001/strings.xml b/app/src/main/res/values-b+en+001/strings.xml index 83c32c32fa..b9ca51b817 100644 --- a/app/src/main/res/values-b+en+001/strings.xml +++ b/app/src/main/res/values-b+en+001/strings.xml @@ -281,6 +281,7 @@ Notifications in this conversation will override Do Not Disturb settings Invitations Join open conversations + You need to promote a new moderator before you can leave the conversation %1$s | Last modified: %2$s Leave conversation Leaving call … diff --git a/app/src/main/res/values-de/strings.xml b/app/src/main/res/values-de/strings.xml index cfc6814e16..4a6140301a 100644 --- a/app/src/main/res/values-de/strings.xml +++ b/app/src/main/res/values-de/strings.xml @@ -281,6 +281,7 @@ Benachrichtigungen in dieser Unterhaltung überschreiben Nicht-Stören-Einstellungen Einladungen Offenen Unterhaltungen beitreten + Sie müssen einen neuen Moderator bestimmen, bevor Sie die Unterhaltung verlassen können. %1$s | Zuletzt geändert: %2$s Unterhaltung verlassen Verlasse Anruf … diff --git a/app/src/main/res/values-es-rEC/strings.xml b/app/src/main/res/values-es-rEC/strings.xml index a115a8b8ec..cc53c2220c 100644 --- a/app/src/main/res/values-es-rEC/strings.xml +++ b/app/src/main/res/values-es-rEC/strings.xml @@ -198,6 +198,7 @@ Escribe un mensaje... Conversación importante Las notificaciones en esta conversación anularán la configuración de No molestar + Necesitas promover un nuevo moderador antes de poder abandonar la conversación %1$s | Última modificación: %2$s Dejar la conversación Saliendo de la llamada... diff --git a/app/src/main/res/values-es/strings.xml b/app/src/main/res/values-es/strings.xml index 432a2daa99..2056c5e0d0 100644 --- a/app/src/main/res/values-es/strings.xml +++ b/app/src/main/res/values-es/strings.xml @@ -267,6 +267,7 @@ Las notificaciones de esta conversación anularán el ajuste de No Molestar Invitaciones Unirse a conversaciones abiertas + Debe escoger a un nuevo moderador antes de que pueda abandonar la conversación %1$s | Modificado por última vez: %2$s Abandonar conversación Abandonando llamada … diff --git a/app/src/main/res/values-eu/strings.xml b/app/src/main/res/values-eu/strings.xml index 3651f95b5d..31b8633e2e 100644 --- a/app/src/main/res/values-eu/strings.xml +++ b/app/src/main/res/values-eu/strings.xml @@ -227,6 +227,7 @@ Ez Molestatu ezarpenek sahiestuko dituzte elkarrizketa honen jakinarazpenak Gonbidapenak Sartu elkarrizketa irekietara + Moderatzaile berri bat sustatu behar duzu elkarrizketatik irten aurretik %1$s | Azkenengoz aldatuta: %2$s Atera elkarrizketatik Deia uzten … diff --git a/app/src/main/res/values-fa/strings.xml b/app/src/main/res/values-fa/strings.xml index 8c61cbb8d2..b1d572b11b 100644 --- a/app/src/main/res/values-fa/strings.xml +++ b/app/src/main/res/values-fa/strings.xml @@ -170,6 +170,7 @@ گفتگوی مهم دعوت‌ها پیوستن به گفتگوهای باز + You need to promote a new moderator before you can leave the conversation تغییرات %1$s | آخرین تغییرات: %2$s ترک گفتگو در حال ترک تماس ... diff --git a/app/src/main/res/values-fr/strings.xml b/app/src/main/res/values-fr/strings.xml index 8e0b743f1a..62ecc8dd38 100644 --- a/app/src/main/res/values-fr/strings.xml +++ b/app/src/main/res/values-fr/strings.xml @@ -280,6 +280,7 @@ Les notifications dans cette conversation l\'emportent sur les paramètres « Ne Pas Déranger ». Invitations Rejoindre des conversations ouvertes + Vous devez promouvoir un nouveau modérateur avant de pouvoir quitter la conversation. %1$s | Dernière modification : %2$s Quitter la conversation Fin d\'appel … diff --git a/app/src/main/res/values-ga/strings.xml b/app/src/main/res/values-ga/strings.xml index fab811d5ea..5b743df9ea 100644 --- a/app/src/main/res/values-ga/strings.xml +++ b/app/src/main/res/values-ga/strings.xml @@ -281,6 +281,7 @@ Sáróidh fógraí sa chomhrá seo na socruithe Ná Cuir Isteach cuirí Glac páirt i gcomhráite oscailte + Ní mór duit modhnóir nua a chur chun cinn sula bhféadfaidh tú an comhrá a fhágáil %1$s | Athraithe is déanaí: %2$s Fág an comhrá Ag fágáil an ghlao… diff --git a/app/src/main/res/values-gl/strings.xml b/app/src/main/res/values-gl/strings.xml index fc620edd37..f81648edae 100644 --- a/app/src/main/res/values-gl/strings.xml +++ b/app/src/main/res/values-gl/strings.xml @@ -281,6 +281,7 @@ As notificacións nesta conversa anularán os axustes de «Non molestar» Convites Unirse a conversas abertas + Debe promover un novo moderador antes de poder deixar a conversa %1$s | Última modificación: %2$s Deixar a conversa Abandonando a chamada… diff --git a/app/src/main/res/values-hu-rHU/strings.xml b/app/src/main/res/values-hu-rHU/strings.xml index a10d4cb265..cd7fac376a 100644 --- a/app/src/main/res/values-hu-rHU/strings.xml +++ b/app/src/main/res/values-hu-rHU/strings.xml @@ -212,6 +212,7 @@ E beszélgetés értesítései felülírják a Ne zavarjanak beállításokat Meghívások Csatlakozás a nyílt beszélgetésekhez + Új moderátort kell kineveznie, mielőtt elhagyhatja a beszélgetést %1$s | Utoljára módosítva: %2$s Beszélgetés elhagyása Hívás elhagyása… diff --git a/app/src/main/res/values-ja-rJP/strings.xml b/app/src/main/res/values-ja-rJP/strings.xml index 5347e5f784..8a12003d59 100644 --- a/app/src/main/res/values-ja-rJP/strings.xml +++ b/app/src/main/res/values-ja-rJP/strings.xml @@ -266,6 +266,7 @@ この会話の通知設定は、取り込み中設定を上書きします 招待 オープンな会話に参加する + 会話から離れる前に、新しいモデレーターを昇格させる必要があります %1$s最終更新:%2$s 会話を離れる 通話を終了 … diff --git a/app/src/main/res/values-ko/strings.xml b/app/src/main/res/values-ko/strings.xml index fdbf5c523a..9916bf1c04 100644 --- a/app/src/main/res/values-ko/strings.xml +++ b/app/src/main/res/values-ko/strings.xml @@ -186,6 +186,7 @@ 메시지 입력… 중요한 대화 공개 대화에 참가 + 대화를 떠나기 전 새 중재자를 임명해야 합니다. %1$s | 최종 수정: %2$s 대화 나가기 통화 종료 중 ... diff --git a/app/src/main/res/values-nb-rNO/strings.xml b/app/src/main/res/values-nb-rNO/strings.xml index aa6eb40d43..cf08169005 100644 --- a/app/src/main/res/values-nb-rNO/strings.xml +++ b/app/src/main/res/values-nb-rNO/strings.xml @@ -277,6 +277,7 @@ Varsler i denne samtalen overstyrer innstillingene for Ikke forstyrr Invitasjoner Bli med i åpne samtaler + Du må forfremme en ny moderator før du kan forlate samtalen %1$s | Sist endret: %2$s Forlat samtale Forlater samtalen... diff --git a/app/src/main/res/values-pl/strings.xml b/app/src/main/res/values-pl/strings.xml index 1158995460..621a5230ea 100644 --- a/app/src/main/res/values-pl/strings.xml +++ b/app/src/main/res/values-pl/strings.xml @@ -267,6 +267,7 @@ Powiadomienia w tej rozmowie ignorują ustawienia \"Nie przeszkadzać\" Zaproszenia Dołącz do otwartych rozmów + Zanim opuścisz rozmowę, musisz wybrać nowego moderatora %1$s | Ostatnio zmodyfikowany: %2$s Opuść rozmowę Opuszczanie połączenia… diff --git a/app/src/main/res/values-pt-rBR/strings.xml b/app/src/main/res/values-pt-rBR/strings.xml index 0067deb58a..944f90fd57 100644 --- a/app/src/main/res/values-pt-rBR/strings.xml +++ b/app/src/main/res/values-pt-rBR/strings.xml @@ -281,6 +281,7 @@ As notificações nesta conversa substituirão as configurações de Não perturbe Convites Participe de conversas abertas + Você precisa promover um novo moderador antes de sair da conversa %1$s | Modificado recentemente: %2$s Sair da conversa Saindo da chamada … diff --git a/app/src/main/res/values-ru/strings.xml b/app/src/main/res/values-ru/strings.xml index 33f81c831a..75eb322247 100644 --- a/app/src/main/res/values-ru/strings.xml +++ b/app/src/main/res/values-ru/strings.xml @@ -244,6 +244,7 @@ Уведомления в этом чате имеют приоритет над настройками режима \"Не беспокоить\" Приглашения Присоединиться к открытым обсуждениям + Вам нужно назначить нового модератора перед тем, как покинуть обсуждение %1$s | Последнее изменение: %2$s Покинуть беседу Завершение вызова … diff --git a/app/src/main/res/values-sk-rSK/strings.xml b/app/src/main/res/values-sk-rSK/strings.xml index 00bccbe351..4742bdde26 100644 --- a/app/src/main/res/values-sk-rSK/strings.xml +++ b/app/src/main/res/values-sk-rSK/strings.xml @@ -266,6 +266,7 @@ Oznámenia v tejto konverzácii sa prepíšu nastavením Nerušiť Pozvánky Pripojiť sa k prebiehajúcim konverzáciam + Skôr než budete môcť opustiť rozhovor, je potrebné niekomu odovzdať rolu moderátora. %1$s | Posledná úprava: %2$s Opustiť konverzáciu Opúšťam hovor … diff --git a/app/src/main/res/values-sl/strings.xml b/app/src/main/res/values-sl/strings.xml index 1231af394e..0ff5c52f02 100644 --- a/app/src/main/res/values-sl/strings.xml +++ b/app/src/main/res/values-sl/strings.xml @@ -198,6 +198,7 @@ Prikaz obvestil v tem pogovoru onemogočil nastavitev Ne moti. Povabila Pridruži se odprtemu pogovoru + Pred odhodom iz pogovora je treba nekoga določiti za moderatorja. %1$s | Nazadnje spremenjeno: %2$s Zapusti pogovor Poteka prekinjanje klica … diff --git a/app/src/main/res/values-sr/strings.xml b/app/src/main/res/values-sr/strings.xml index 2a620d5942..3959aeb3bf 100644 --- a/app/src/main/res/values-sr/strings.xml +++ b/app/src/main/res/values-sr/strings.xml @@ -281,6 +281,7 @@ Обавештења у овом разговору ће преиначити Не узнемиравај поставке. Позивнице Придружи се отвореном разговору + Морате да промовишете новог модератора пре него што напустите разговор %1$s | Последње измењено: %2$s Напусти разговор Напуштање позива ... diff --git a/app/src/main/res/values-sv/strings.xml b/app/src/main/res/values-sv/strings.xml index e364317004..a4c81bf1c4 100644 --- a/app/src/main/res/values-sv/strings.xml +++ b/app/src/main/res/values-sv/strings.xml @@ -278,6 +278,7 @@ Meddelanden i den här konversationen kommer att åsidosätta Stör inte-inställningar Inbjudningar Gå med i öppna konversationer + Du måste tilldela en ny moderator innan du kan lämna konversationen %1$s | Senast ändrad: %2$s Lämna konversationen Lägger på … diff --git a/app/src/main/res/values-tr/strings.xml b/app/src/main/res/values-tr/strings.xml index f2556bdd7d..2ab4fa8685 100644 --- a/app/src/main/res/values-tr/strings.xml +++ b/app/src/main/res/values-tr/strings.xml @@ -281,6 +281,7 @@ Bu görüşmedeki bildirimler Rahatsız Etmeyin ayarlarını değiştirecek Davetler Açık görüşmelere katıl + Görüşmeden ayrılmadan önce başka bir kullanıcıyı sorumluluğa yükseltmelisiniz %1$s | Son değişiklik: %2$s Görüşmeden ayrıl Çağrıdan çıkılıyor… diff --git a/app/src/main/res/values-ug/strings.xml b/app/src/main/res/values-ug/strings.xml index 0314821fc3..75958cb653 100644 --- a/app/src/main/res/values-ug/strings.xml +++ b/app/src/main/res/values-ug/strings.xml @@ -281,6 +281,7 @@ بۇ سۆھبەتتىكى ئۇقتۇرۇشلار قالايمىقانلاشتۇرماڭ تەكلىپنامە ئوچۇق سۆھبەتكە قاتنىشىڭ + سۆھبەتتىن ئايرىلىشتىن بۇرۇن يېڭى رىياسەتچىنى تەشۋىق قىلىشىڭىز كېرەك % 1 $ s | ئاخىرقى قېتىم ئۆزگەرتىلگەن:% 2 $ s سۆھبەتتىن ۋاز كېچىڭ تېلېفوندىن ئايرىلىش… diff --git a/app/src/main/res/values-uk/strings.xml b/app/src/main/res/values-uk/strings.xml index 57da8bb69b..3ef381b1bf 100644 --- a/app/src/main/res/values-uk/strings.xml +++ b/app/src/main/res/values-uk/strings.xml @@ -190,6 +190,7 @@ Введіть повідомлення ... Важлива розмова Сповіщення в цій розмові ігнорують опцію \"Не турбувати\" + Перед тим, як вийти з розмови, вам потрібно призначити нового модератора %1$s | Остання зміна: %2$s Вийти з групи Завершення виклику ... diff --git a/app/src/main/res/values-zh-rCN/strings.xml b/app/src/main/res/values-zh-rCN/strings.xml index c99fd493f2..3047569504 100644 --- a/app/src/main/res/values-zh-rCN/strings.xml +++ b/app/src/main/res/values-zh-rCN/strings.xml @@ -215,6 +215,7 @@ 此对话中的通知将覆盖免打扰设置 邀请函 加入公开对话 + 在您离开对话之前需要推举一位新的主持人 %1$s 我上一次更改: %2$s 离开对话 正在离开通话 ... diff --git a/app/src/main/res/values-zh-rHK/strings.xml b/app/src/main/res/values-zh-rHK/strings.xml index 6676313dee..5908538138 100644 --- a/app/src/main/res/values-zh-rHK/strings.xml +++ b/app/src/main/res/values-zh-rHK/strings.xml @@ -281,6 +281,7 @@ 此對話中的通告將覆蓋\"請勿打擾\"設置 邀請 加入公開對話 + 在您離開對話之前您需要推舉一位新的主持人 %1$s | 上次修改時間:%2$s 結束對話 正在離開通話 … diff --git a/app/src/main/res/values-zh-rTW/strings.xml b/app/src/main/res/values-zh-rTW/strings.xml index ca446587d6..8795980471 100644 --- a/app/src/main/res/values-zh-rTW/strings.xml +++ b/app/src/main/res/values-zh-rTW/strings.xml @@ -281,6 +281,7 @@ 在這個交談的通知將會覆蓋不要打擾的設定 邀請 加入開放對話 + 在您離開對話前,您必須授權一位新的主持人 %1$s | 上次修改時間:%2$s 結束對話 正在離開通話 … From 315e263d312bc55eeafa57ff2a17323f1ab33fda Mon Sep 17 00:00:00 2001 From: Christian Reiner Date: Thu, 31 Oct 2024 17:19:19 +0100 Subject: [PATCH 302/885] fix spelling of property name in ChatViewModel Signed-off-by: Christian Reiner --- .../talk/chat/viewmodels/ChatViewModel.kt | 14 +++++++------- .../talk/ui/dialog/MessageActionsDialog.kt | 4 ++-- 2 files changed, 9 insertions(+), 9 deletions(-) diff --git a/app/src/main/java/com/nextcloud/talk/chat/viewmodels/ChatViewModel.kt b/app/src/main/java/com/nextcloud/talk/chat/viewmodels/ChatViewModel.kt index 39a09bdcb0..6b80b3d91d 100644 --- a/app/src/main/java/com/nextcloud/talk/chat/viewmodels/ChatViewModel.kt +++ b/app/src/main/java/com/nextcloud/talk/chat/viewmodels/ChatViewModel.kt @@ -141,12 +141,12 @@ class ChatViewModel @Inject constructor( val getReminderExistState: LiveData get() = _getReminderExistState - object NoteToSelfNotAvaliableState : ViewState - open class NoteToSelfAvaliableState(val roomToken: String) : ViewState + object NoteToSelfNotAvailableState : ViewState + open class NoteToSelfAvailableState(val roomToken: String) : ViewState - private val _getNoteToSelfAvaliability: MutableLiveData = MutableLiveData(NoteToSelfNotAvaliableState) - val getNoteToSelfAvaliability: LiveData - get() = _getNoteToSelfAvaliability + private val _getNoteToSelfAvailability: MutableLiveData = MutableLiveData(NoteToSelfNotAvailableState) + val getNoteToSelfAvailability: LiveData + get() = _getNoteToSelfAvailability object GetRoomStartState : ViewState object GetRoomErrorState : ViewState @@ -732,9 +732,9 @@ class ChatViewModel @Inject constructor( val model = ConversationModel.mapToConversationModel(it, userProvider.currentUser.blockingGet()) ConversationUtils.isNoteToSelfConversation(model) } - _getNoteToSelfAvaliability.value = NoteToSelfAvaliableState(noteToSelf.token!!) + _getNoteToSelfAvailability.value = NoteToSelfAvailableState(noteToSelf.token!!) } catch (e: NoSuchElementException) { - _getNoteToSelfAvaliability.value = NoteToSelfNotAvaliableState + _getNoteToSelfAvailability.value = NoteToSelfNotAvailableState Log.e(TAG, "Note to self not found $e") } } 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 88a84fcf9d..0a4445ca2d 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 @@ -120,9 +120,9 @@ class MessageActionsDialog( ), false ) - chatActivity.chatViewModel.getNoteToSelfAvaliability.observe(this) { state -> + chatActivity.chatViewModel.getNoteToSelfAvailability.observe(this) { state -> when (state) { - is ChatViewModel.NoteToSelfAvaliableState -> { + is ChatViewModel.NoteToSelfAvailableState -> { initMenuAddToNote( !message.isDeleted && !ConversationUtils.isNoteToSelfConversation(currentConversation), state.roomToken From 238532feb2926bfb94243a66c302c585c7ab630a Mon Sep 17 00:00:00 2001 From: Christian Reiner Date: Thu, 31 Oct 2024 22:28:04 +0100 Subject: [PATCH 303/885] adjust outcoming message view holders to use full available width in NoteToSelf chat Signed-off-by: Christian Reiner --- .../AdjustableMessageHolderInterface.kt | 51 ++++++++++++++ .../messages/OutcomingDeckCardViewHolder.kt | 6 +- .../OutcomingLinkPreviewMessageViewHolder.kt | 6 +- .../OutcomingLocationMessageViewHolder.kt | 7 +- .../OutcomingTextMessageViewHolder.kt | 8 ++- .../OutcomingVoiceMessageViewHolder.kt | 6 +- .../messages/TalkMessagesListAdapter.java | 70 +++++++++++-------- 7 files changed, 113 insertions(+), 41 deletions(-) create mode 100644 app/src/main/java/com/nextcloud/talk/adapters/messages/AdjustableMessageHolderInterface.kt diff --git a/app/src/main/java/com/nextcloud/talk/adapters/messages/AdjustableMessageHolderInterface.kt b/app/src/main/java/com/nextcloud/talk/adapters/messages/AdjustableMessageHolderInterface.kt new file mode 100644 index 0000000000..12bbd1e068 --- /dev/null +++ b/app/src/main/java/com/nextcloud/talk/adapters/messages/AdjustableMessageHolderInterface.kt @@ -0,0 +1,51 @@ +/* + * Nextcloud Talk - Android Client + * + * SPDX-FileCopyrightText: 2024 Christian Reiner + * SPDX-License-Identifier: GPL-3.0-or-later + */ + +package com.nextcloud.talk.adapters.messages + +import android.widget.RelativeLayout +import androidx.viewbinding.ViewBinding +import com.nextcloud.talk.databinding.ItemCustomOutcomingDeckCardMessageBinding +import com.nextcloud.talk.databinding.ItemCustomOutcomingLinkPreviewMessageBinding +import com.nextcloud.talk.databinding.ItemCustomOutcomingLocationMessageBinding +import com.nextcloud.talk.databinding.ItemCustomOutcomingPollMessageBinding +import com.nextcloud.talk.databinding.ItemCustomOutcomingTextMessageBinding +import com.nextcloud.talk.databinding.ItemCustomOutcomingVoiceMessageBinding +import com.nextcloud.talk.models.domain.ConversationModel +import com.nextcloud.talk.models.json.conversations.ConversationEnums.ConversationType + +interface AdjustableMessageHolderInterface { + + val binding: ViewBinding + + fun adjustIfNoteToSelf(viewHolder: AdjustableMessageHolderInterface, currentConversation: ConversationModel?) { + if (currentConversation?.type == ConversationType.NOTE_TO_SELF) { + when (viewHolder.binding.javaClass) { + ItemCustomOutcomingTextMessageBinding::class.java -> + (viewHolder.binding as ItemCustomOutcomingTextMessageBinding).bubble + ItemCustomOutcomingDeckCardMessageBinding::class.java -> + (viewHolder.binding as ItemCustomOutcomingDeckCardMessageBinding).bubble + ItemCustomOutcomingLinkPreviewMessageBinding::class.java -> + (viewHolder.binding as ItemCustomOutcomingLinkPreviewMessageBinding).bubble + ItemCustomOutcomingPollMessageBinding::class.java -> + (viewHolder.binding as ItemCustomOutcomingPollMessageBinding).bubble + ItemCustomOutcomingVoiceMessageBinding::class.java -> + (viewHolder.binding as ItemCustomOutcomingVoiceMessageBinding).bubble + ItemCustomOutcomingLocationMessageBinding::class.java -> + (viewHolder.binding as ItemCustomOutcomingLocationMessageBinding).bubble + else -> null + }?.let { + RelativeLayout.LayoutParams(binding.root.layoutParams).apply { + marginStart = 0 + marginEnd = 0 + }.run { + it.layoutParams = this + } + } + } + } +} diff --git a/app/src/main/java/com/nextcloud/talk/adapters/messages/OutcomingDeckCardViewHolder.kt b/app/src/main/java/com/nextcloud/talk/adapters/messages/OutcomingDeckCardViewHolder.kt index 49e649e265..7c053f170d 100644 --- a/app/src/main/java/com/nextcloud/talk/adapters/messages/OutcomingDeckCardViewHolder.kt +++ b/app/src/main/java/com/nextcloud/talk/adapters/messages/OutcomingDeckCardViewHolder.kt @@ -1,6 +1,7 @@ /* * Nextcloud Talk - Android Client * + * SPDX-FileCopyrightText: 2024 Christian Reiner * SPDX-FileCopyrightText: 2024 Sowjanya Kota * SPDX-License-Identifier: GPL-3.0-or-later */ @@ -43,9 +44,10 @@ import javax.inject.Inject @AutoInjector(NextcloudTalkApplication::class) class OutcomingDeckCardViewHolder( outcomingView: View -) : MessageHolders.OutcomingTextMessageViewHolder(outcomingView) { +) : MessageHolders.OutcomingTextMessageViewHolder(outcomingView), + AdjustableMessageHolderInterface { - private val binding: ItemCustomOutcomingDeckCardMessageBinding = ItemCustomOutcomingDeckCardMessageBinding.bind( + override val binding: ItemCustomOutcomingDeckCardMessageBinding = ItemCustomOutcomingDeckCardMessageBinding.bind( itemView ) 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 e557a98cba..c22f16dbb3 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 @@ -1,6 +1,7 @@ /* * Nextcloud Talk - Android Client * + * SPDX-FileCopyrightText: 2024 Christian Reiner * SPDX-FileCopyrightText: 2022 Marcel Hibbe * SPDX-FileCopyrightText: 2017-2019 Mario Danic * SPDX-License-Identifier: GPL-3.0-or-later @@ -38,9 +39,10 @@ import javax.inject.Inject @AutoInjector(NextcloudTalkApplication::class) class OutcomingLinkPreviewMessageViewHolder(outcomingView: View, payload: Any) : - MessageHolders.OutcomingTextMessageViewHolder(outcomingView, payload) { + MessageHolders.OutcomingTextMessageViewHolder(outcomingView, payload), + AdjustableMessageHolderInterface { - private val binding: ItemCustomOutcomingLinkPreviewMessageBinding = + override val binding: ItemCustomOutcomingLinkPreviewMessageBinding = ItemCustomOutcomingLinkPreviewMessageBinding.bind(itemView) @Inject diff --git a/app/src/main/java/com/nextcloud/talk/adapters/messages/OutcomingLocationMessageViewHolder.kt b/app/src/main/java/com/nextcloud/talk/adapters/messages/OutcomingLocationMessageViewHolder.kt index ada48c130b..7ae85a5c6d 100644 --- a/app/src/main/java/com/nextcloud/talk/adapters/messages/OutcomingLocationMessageViewHolder.kt +++ b/app/src/main/java/com/nextcloud/talk/adapters/messages/OutcomingLocationMessageViewHolder.kt @@ -1,6 +1,7 @@ /* * Nextcloud Talk - Android Client * + * SPDX-FileCopyrightText: 2024 Christian Reiner * SPDX-FileCopyrightText: 2021 Marcel Hibbe * SPDX-FileCopyrightText: 2017-2018 Mario Danic * SPDX-License-Identifier: GPL-3.0-or-later @@ -47,8 +48,10 @@ import kotlin.math.roundToInt @AutoInjector(NextcloudTalkApplication::class) class OutcomingLocationMessageViewHolder(incomingView: View) : - MessageHolders.OutcomingTextMessageViewHolder(incomingView) { - private val binding: ItemCustomOutcomingLocationMessageBinding = + MessageHolders.OutcomingTextMessageViewHolder(incomingView), + AdjustableMessageHolderInterface { + + override val binding: ItemCustomOutcomingLocationMessageBinding = ItemCustomOutcomingLocationMessageBinding.bind(itemView) private val realView: View = itemView diff --git a/app/src/main/java/com/nextcloud/talk/adapters/messages/OutcomingTextMessageViewHolder.kt b/app/src/main/java/com/nextcloud/talk/adapters/messages/OutcomingTextMessageViewHolder.kt index ba0b4fe1ae..68e2c515d4 100644 --- a/app/src/main/java/com/nextcloud/talk/adapters/messages/OutcomingTextMessageViewHolder.kt +++ b/app/src/main/java/com/nextcloud/talk/adapters/messages/OutcomingTextMessageViewHolder.kt @@ -1,6 +1,7 @@ /* * Nextcloud Talk - Android Client * + * SPDX-FileCopyrightText: 2024 Christian Reiner * SPDX-FileCopyrightText: 2021 Andy Scherzinger * SPDX-FileCopyrightText: 2021 Marcel Hibbe * SPDX-FileCopyrightText: 2017-2018 Mario Danic @@ -38,8 +39,11 @@ import kotlinx.coroutines.withContext import javax.inject.Inject @AutoInjector(NextcloudTalkApplication::class) -class OutcomingTextMessageViewHolder(itemView: View) : OutcomingTextMessageViewHolder(itemView) { - private val binding: ItemCustomOutcomingTextMessageBinding = ItemCustomOutcomingTextMessageBinding.bind(itemView) +class OutcomingTextMessageViewHolder(itemView: View) : + OutcomingTextMessageViewHolder(itemView), + AdjustableMessageHolderInterface { + + override val binding: ItemCustomOutcomingTextMessageBinding = ItemCustomOutcomingTextMessageBinding.bind(itemView) private val realView: View = itemView @Inject diff --git a/app/src/main/java/com/nextcloud/talk/adapters/messages/OutcomingVoiceMessageViewHolder.kt b/app/src/main/java/com/nextcloud/talk/adapters/messages/OutcomingVoiceMessageViewHolder.kt index 45b9e8ec7f..4f3f57a241 100644 --- a/app/src/main/java/com/nextcloud/talk/adapters/messages/OutcomingVoiceMessageViewHolder.kt +++ b/app/src/main/java/com/nextcloud/talk/adapters/messages/OutcomingVoiceMessageViewHolder.kt @@ -1,6 +1,7 @@ /* * Nextcloud Talk - Android Client * + * SPDX-FileCopyrightText: 2024 Christian Reiner * SPDX-FileCopyrightText: 2023 Andy Scherzinger * SPDX-FileCopyrightText: 2023 Julius Linus * SPDX-FileCopyrightText: 2021 Marcel Hibbe @@ -45,9 +46,10 @@ import javax.inject.Inject @AutoInjector(NextcloudTalkApplication::class) class OutcomingVoiceMessageViewHolder(outcomingView: View) : - MessageHolders.OutcomingTextMessageViewHolder(outcomingView) { + MessageHolders.OutcomingTextMessageViewHolder(outcomingView), + AdjustableMessageHolderInterface { - private val binding: ItemCustomOutcomingVoiceMessageBinding = ItemCustomOutcomingVoiceMessageBinding.bind(itemView) + override val binding: ItemCustomOutcomingVoiceMessageBinding = ItemCustomOutcomingVoiceMessageBinding.bind(itemView) @JvmField @Inject diff --git a/app/src/main/java/com/nextcloud/talk/adapters/messages/TalkMessagesListAdapter.java b/app/src/main/java/com/nextcloud/talk/adapters/messages/TalkMessagesListAdapter.java index 10f6693064..d331f1d61f 100644 --- a/app/src/main/java/com/nextcloud/talk/adapters/messages/TalkMessagesListAdapter.java +++ b/app/src/main/java/com/nextcloud/talk/adapters/messages/TalkMessagesListAdapter.java @@ -1,6 +1,7 @@ /* * Nextcloud Talk - Android Client * + * SPDX-FileCopyrightText: 2024 Christian Reiner * SPDX-FileCopyrightText: 2020 Tobias Kaminsky * SPDX-License-Identifier: GPL-3.0-or-later */ @@ -34,43 +35,50 @@ public List getItems() { @Override public void onBindViewHolder(ViewHolder holder, int position) { + if (holder instanceof IncomingTextMessageViewHolder holderInstance) { + holderInstance.assignCommonMessageInterface(chatActivity); + } else if (holder instanceof OutcomingTextMessageViewHolder holderInstance) { + holderInstance.assignCommonMessageInterface(chatActivity); + holderInstance.adjustIfNoteToSelf(holderInstance, chatActivity.getCurrentConversation()); - if (holder instanceof IncomingTextMessageViewHolder) { - ((IncomingTextMessageViewHolder) holder).assignCommonMessageInterface(chatActivity); - } else if (holder instanceof OutcomingTextMessageViewHolder) { - ((OutcomingTextMessageViewHolder) holder).assignCommonMessageInterface(chatActivity); + } else if (holder instanceof IncomingLocationMessageViewHolder holderInstance) { + holderInstance.assignCommonMessageInterface(chatActivity); + } else if (holder instanceof OutcomingLocationMessageViewHolder holderInstance) { + holderInstance.assignCommonMessageInterface(chatActivity); + holderInstance.adjustIfNoteToSelf(holderInstance, chatActivity.getCurrentConversation()); - } else if (holder instanceof IncomingLocationMessageViewHolder) { - ((IncomingLocationMessageViewHolder) holder).assignCommonMessageInterface(chatActivity); - } else if (holder instanceof OutcomingLocationMessageViewHolder) { - ((OutcomingLocationMessageViewHolder) holder).assignCommonMessageInterface(chatActivity); + } else if (holder instanceof IncomingLinkPreviewMessageViewHolder holderInstance) { + holderInstance.assignCommonMessageInterface(chatActivity); + } else if (holder instanceof OutcomingLinkPreviewMessageViewHolder holderInstance) { + holderInstance.assignCommonMessageInterface(chatActivity); + holderInstance.adjustIfNoteToSelf(holderInstance, chatActivity.getCurrentConversation()); - } else if (holder instanceof IncomingLinkPreviewMessageViewHolder) { - ((IncomingLinkPreviewMessageViewHolder) holder).assignCommonMessageInterface(chatActivity); - } else if (holder instanceof OutcomingLinkPreviewMessageViewHolder) { - ((OutcomingLinkPreviewMessageViewHolder) holder).assignCommonMessageInterface(chatActivity); + } else if (holder instanceof IncomingVoiceMessageViewHolder holderInstance) { + holderInstance.assignVoiceMessageInterface(chatActivity); + holderInstance.assignCommonMessageInterface(chatActivity); + } else if (holder instanceof OutcomingVoiceMessageViewHolder holderInstance) { + holderInstance.assignVoiceMessageInterface(chatActivity); + holderInstance.assignCommonMessageInterface(chatActivity); + holderInstance.adjustIfNoteToSelf(holderInstance, chatActivity.getCurrentConversation()); - } else if (holder instanceof IncomingVoiceMessageViewHolder) { - ((IncomingVoiceMessageViewHolder) holder).assignVoiceMessageInterface(chatActivity); - ((IncomingVoiceMessageViewHolder) holder).assignCommonMessageInterface(chatActivity); - } else if (holder instanceof OutcomingVoiceMessageViewHolder) { - ((OutcomingVoiceMessageViewHolder) holder).assignVoiceMessageInterface(chatActivity); - ((OutcomingVoiceMessageViewHolder) holder).assignCommonMessageInterface(chatActivity); + } else if (holder instanceof PreviewMessageViewHolder holderInstance) { + holderInstance.assignPreviewMessageInterface(chatActivity); + holderInstance.assignCommonMessageInterface(chatActivity); - } else if (holder instanceof PreviewMessageViewHolder) { - ((PreviewMessageViewHolder) holder).assignPreviewMessageInterface(chatActivity); - ((PreviewMessageViewHolder) holder).assignCommonMessageInterface(chatActivity); + } else if (holder instanceof SystemMessageViewHolder holderInstance) { + holderInstance.assignSystemMessageInterface(chatActivity); - } else if (holder instanceof SystemMessageViewHolder) { - ((SystemMessageViewHolder) holder).assignSystemMessageInterface(chatActivity); - } else if (holder instanceof CallStartedViewHolder) { - ((CallStartedViewHolder) holder).assignCallStartedMessageInterface(chatActivity); - } else if (holder instanceof TemporaryMessageViewHolder) { - ((TemporaryMessageViewHolder) holder).assignTemporaryMessageInterface(chatActivity); - }else if (holder instanceof IncomingDeckCardViewHolder){ - ((IncomingDeckCardViewHolder) holder).assignCommonMessageInterface(chatActivity); - } else if(holder instanceof OutcomingDeckCardViewHolder){ - ((OutcomingDeckCardViewHolder) holder).assignCommonMessageInterface(chatActivity); + } else if (holder instanceof CallStartedViewHolder holderInstance) { + holderInstance.assignCallStartedMessageInterface(chatActivity); + + } else if (holder instanceof TemporaryMessageViewHolder holderInstance) { + holderInstance.assignTemporaryMessageInterface(chatActivity); + + } else if (holder instanceof IncomingDeckCardViewHolder holderInstance) { + holderInstance.assignCommonMessageInterface(chatActivity); + } else if (holder instanceof OutcomingDeckCardViewHolder holderInstance) { + holderInstance.assignCommonMessageInterface(chatActivity); + holderInstance.adjustIfNoteToSelf(holderInstance, chatActivity.getCurrentConversation()); } super.onBindViewHolder(holder, position); From cabd248e13a81e13d4411962d501d8e206244121 Mon Sep 17 00:00:00 2001 From: Andy Scherzinger Date: Thu, 7 Nov 2024 14:32:42 +0100 Subject: [PATCH 304/885] ci: bump detekt score Signed-off-by: Andy Scherzinger --- detekt.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/detekt.yml b/detekt.yml index 63e05ff12b..449cb490dc 100644 --- a/detekt.yml +++ b/detekt.yml @@ -1,7 +1,7 @@ # SPDX-FileCopyrightText: 2017-2024 Nextcloud GmbH and Nextcloud contributors # SPDX-License-Identifier: GPL-3.0-or-later build: - maxIssues: 178 + maxIssues: 179 weights: # complexity: 2 # LongParameterList: 1 From 3ac1b18d3d39c0fb83e760e6c4937bce404dd75f Mon Sep 17 00:00:00 2001 From: Andy Scherzinger Date: Thu, 7 Nov 2024 15:42:58 +0100 Subject: [PATCH 305/885] fix(spotbugs): Improve spotbugs scoring Signed-off-by: Andy Scherzinger --- .../talk/call/CallParticipantList.java | 2 +- .../MentionAutocompletePresenter.java | 47 ++++++++++--------- .../dialog/ChooseAccountDialogFragment.java | 6 +-- 3 files changed, 30 insertions(+), 25 deletions(-) diff --git a/app/src/main/java/com/nextcloud/talk/call/CallParticipantList.java b/app/src/main/java/com/nextcloud/talk/call/CallParticipantList.java index 4a1c7370bf..4b3727aa47 100644 --- a/app/src/main/java/com/nextcloud/talk/call/CallParticipantList.java +++ b/app/src/main/java/com/nextcloud/talk/call/CallParticipantList.java @@ -86,8 +86,8 @@ private void processParticipantList(List participants) { callParticipants.remove(callParticipant.getSessionId()); // No need to copy it, as it will be no longer used. callParticipant.setInCall(Participant.InCallFlags.DISCONNECTED); - left.add(callParticipant); } + left.addAll(knownCallParticipantsNotFound); if (!joined.isEmpty() || !updated.isEmpty() || !left.isEmpty()) { callParticipantListNotifier.notifyChanged(joined, updated, left, unchanged); diff --git a/app/src/main/java/com/nextcloud/talk/presenters/MentionAutocompletePresenter.java b/app/src/main/java/com/nextcloud/talk/presenters/MentionAutocompletePresenter.java index 9ec1f67e39..5d5f206990 100644 --- a/app/src/main/java/com/nextcloud/talk/presenters/MentionAutocompletePresenter.java +++ b/app/src/main/java/com/nextcloud/talk/presenters/MentionAutocompletePresenter.java @@ -126,28 +126,33 @@ public void onSubscribe(@NonNull Disposable d) { @Override public void onNext(@NonNull MentionOverall mentionOverall) { - List mentionsList = mentionOverall.getOcs().getData(); - - if (mentionsList.size() == 0) { - adapter.clear(); - } else { - List internalAbstractFlexibleItemList = - new ArrayList<>(mentionsList.size()); - for (Mention mention : mentionsList) { - internalAbstractFlexibleItemList.add( - new MentionAutocompleteItem( - mention, - currentUser, - context, - roomToken, - viewThemeUtils)); + if (mentionOverall.getOcs() != null) { + List mentionsList = mentionOverall.getOcs().getData(); + + if (mentionsList != null) { + + if (mentionsList.isEmpty()) { + adapter.clear(); + } else { + List internalAbstractFlexibleItemList = + new ArrayList<>(mentionsList.size()); + for (Mention mention : mentionsList) { + internalAbstractFlexibleItemList.add( + new MentionAutocompleteItem( + mention, + currentUser, + context, + roomToken, + viewThemeUtils)); + } + + if (adapter.getItemCount() != 0) { + adapter.clear(); + } + + adapter.updateDataSet(internalAbstractFlexibleItemList); + } } - - if (adapter.getItemCount() != 0) { - adapter.clear(); - } - - adapter.updateDataSet(internalAbstractFlexibleItemList); } } diff --git a/app/src/main/java/com/nextcloud/talk/ui/dialog/ChooseAccountDialogFragment.java b/app/src/main/java/com/nextcloud/talk/ui/dialog/ChooseAccountDialogFragment.java index 8e53821479..729fa51816 100644 --- a/app/src/main/java/com/nextcloud/talk/ui/dialog/ChooseAccountDialogFragment.java +++ b/app/src/main/java/com/nextcloud/talk/ui/dialog/ChooseAccountDialogFragment.java @@ -109,7 +109,7 @@ public void onViewCreated(@NonNull View view, Bundle savedInstanceState) { themeViews(); setupCurrentUser(user); - setupListeners(user); + setupListeners(); setupAdapter(); prepareViews(); } @@ -220,7 +220,7 @@ private void addAccountToSwitcherList( adapter.updateDataSet(userItems, false); } - private void setupListeners(User user) { + private void setupListeners() { // Creating listeners for quick-actions binding.currentAccount.getRoot().setOnClickListener(v -> dismiss()); @@ -240,7 +240,7 @@ private void setupListeners(User user) { binding.setStatus.setOnClickListener(v -> { dismiss(); - if (status != null) { + if (status != null && getActivity() != null) { SetStatusDialogFragment setStatusDialog = SetStatusDialogFragment.newInstance(status); setStatusDialog.show(getActivity().getSupportFragmentManager(), "fragment_set_status"); } else { From e2d1d2ee8e810760ff39c1744bf1a41a7fdefa29 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Fri, 8 Nov 2024 02:05:15 +0000 Subject: [PATCH 306/885] chore(deps): update plugin com.google.devtools.ksp to v2.0.21-1.0.27 Signed-off-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- app/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/build.gradle b/app/build.gradle index b1e4182ca7..9b9bfb1cee 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -15,7 +15,7 @@ import com.github.spotbugs.snom.SpotBugsTask plugins { id "org.jetbrains.kotlin.plugin.compose" version "2.0.21" id "org.jetbrains.kotlin.kapt" - id 'com.google.devtools.ksp' version '2.0.21-1.0.26' + id 'com.google.devtools.ksp' version '2.0.21-1.0.27' } apply plugin: 'com.android.application' From f54796627596fc51846be34f43671a918b10cf89 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Thu, 31 Oct 2024 05:35:31 +0000 Subject: [PATCH 307/885] Update dependency com.vanniktech:emoji-google to v0.21.0 Signed-off-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- app/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/build.gradle b/app/build.gradle index 9b9bfb1cee..64b9637abd 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -198,7 +198,7 @@ dependencies { implementation 'androidx.appcompat:appcompat:1.7.0' implementation 'com.google.android.material:material:1.12.0' implementation 'androidx.constraintlayout:constraintlayout:2.2.0' - implementation "com.vanniktech:emoji-google:0.18.0" + implementation "com.vanniktech:emoji-google:0.21.0" implementation "androidx.emoji2:emoji2:${emojiVersion}" implementation "androidx.emoji2:emoji2-bundled:${emojiVersion}" implementation "androidx.emoji2:emoji2-views:${emojiVersion}" From 00622b77ca4adcfbc53eec9030c06864eb011410 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Fri, 8 Nov 2024 19:06:37 +0000 Subject: [PATCH 308/885] chore(deps): update github/codeql-action action to v3.27.1 Signed-off-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- .github/workflows/codeql.yml | 4 ++-- .github/workflows/scorecard.yml | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/codeql.yml b/.github/workflows/codeql.yml index 18325b3d34..a2500fa5ac 100644 --- a/.github/workflows/codeql.yml +++ b/.github/workflows/codeql.yml @@ -39,7 +39,7 @@ jobs: with: swap-size-gb: 10 - name: Initialize CodeQL - uses: github/codeql-action/init@662472033e021d55d94146f66f6058822b0b39fd # v3.27.0 + uses: github/codeql-action/init@4f3212b61783c3c68e8309a0f18a699764811cda # v3.27.1 with: languages: ${{ matrix.language }} - name: Set up JDK 17 @@ -53,4 +53,4 @@ jobs: echo "org.gradle.jvmargs=-Xmx4g -XX:MaxMetaspaceSize=512m -XX:+HeapDumpOnOutOfMemoryError" > "$HOME/.gradle/gradle.properties" ./gradlew assembleDebug - name: Perform CodeQL Analysis - uses: github/codeql-action/analyze@662472033e021d55d94146f66f6058822b0b39fd # v3.27.0 + uses: github/codeql-action/analyze@4f3212b61783c3c68e8309a0f18a699764811cda # v3.27.1 diff --git a/.github/workflows/scorecard.yml b/.github/workflows/scorecard.yml index 1c29392098..809598b6a8 100644 --- a/.github/workflows/scorecard.yml +++ b/.github/workflows/scorecard.yml @@ -42,6 +42,6 @@ jobs: # Upload the results to GitHub's code scanning dashboard. - name: "Upload to code-scanning" - uses: github/codeql-action/upload-sarif@662472033e021d55d94146f66f6058822b0b39fd # v3.27.0 + uses: github/codeql-action/upload-sarif@4f3212b61783c3c68e8309a0f18a699764811cda # v3.27.1 with: sarif_file: results.sarif From 3595c1d3157a45db913425212f9a4cb45213cbc1 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Fri, 8 Nov 2024 19:11:12 +0000 Subject: [PATCH 309/885] fix(deps): update dependency com.github.nextcloud.android-common:ui to v0.23.2 Signed-off-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- app/build.gradle | 4 ++-- gradle/verification-metadata.xml | 24 ++++++++++++++++++++++++ 2 files changed, 26 insertions(+), 2 deletions(-) diff --git a/app/build.gradle b/app/build.gradle index 64b9637abd..dc224058cd 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -304,7 +304,7 @@ dependencies { implementation 'androidx.core:core-ktx:1.13.1' implementation 'androidx.activity:activity-ktx:1.9.3' - implementation 'com.github.nextcloud.android-common:ui:0.23.1' + implementation 'com.github.nextcloud.android-common:ui:0.23.2' implementation 'com.github.nextcloud-deps:android-talk-webrtc:121.6167.0' gplayImplementation 'com.google.android.gms:play-services-base:18.5.0' @@ -350,7 +350,7 @@ dependencies { implementation 'androidx.activity:activity-ktx:1.9.3' - implementation 'com.github.nextcloud.android-common:ui:0.23.1' + implementation 'com.github.nextcloud.android-common:ui:0.23.2' implementation 'com.github.nextcloud-deps:android-talk-webrtc:121.6167.0' implementation("io.coil-kt:coil-compose:2.7.0") diff --git a/gradle/verification-metadata.xml b/gradle/verification-metadata.xml index 625aa833d9..bcd62fbb3e 100644 --- a/gradle/verification-metadata.xml +++ b/gradle/verification-metadata.xml @@ -4610,6 +4610,14 @@ + + + + + + + + @@ -4666,6 +4674,14 @@ + + + + + + + + @@ -4722,6 +4738,14 @@ + + + + + + + + From 956f2c435bd0695e93d54d0168df07aeb3b1c27e Mon Sep 17 00:00:00 2001 From: sowjanyakch Date: Thu, 7 Nov 2024 18:15:19 +0100 Subject: [PATCH 310/885] modify activity_conversation_info.xml Signed-off-by: sowjanyakch --- .../java/com/nextcloud/talk/api/NcApi.java | 2 +- .../res/layout/activity_conversation_info.xml | 46 +++++++++++++++++++ app/src/main/res/values/strings.xml | 1 + 3 files changed, 48 insertions(+), 1 deletion(-) diff --git a/app/src/main/java/com/nextcloud/talk/api/NcApi.java b/app/src/main/java/com/nextcloud/talk/api/NcApi.java index f0957ef4d3..962c3aecdf 100644 --- a/app/src/main/java/com/nextcloud/talk/api/NcApi.java +++ b/app/src/main/java/com/nextcloud/talk/api/NcApi.java @@ -435,7 +435,7 @@ Observable setNotificationLevel(@Header("Authorization") String @FormUrlEncoded @PUT - Observable setReadOnlyState(@Header("Authorization") String authorization, + Observable setConversationReadOnly(@Header("Authorization") String authorization, @Url String url, @Field("state") int state); diff --git a/app/src/main/res/layout/activity_conversation_info.xml b/app/src/main/res/layout/activity_conversation_info.xml index ded8afea10..fc910e367a 100644 --- a/app/src/main/res/layout/activity_conversation_info.xml +++ b/app/src/main/res/layout/activity_conversation_info.xml @@ -300,6 +300,52 @@ + + + + + + + + + + + + + Unread mentions Conversations Open conversations + Lock conversation There was a problem loading your chats Close Close Icon From 50569a09af8064f1ac403437b82c9fa12bc478a7 Mon Sep 17 00:00:00 2001 From: sowjanyakch Date: Fri, 8 Nov 2024 12:54:30 +0100 Subject: [PATCH 311/885] set conversation read only Signed-off-by: sowjanyakch --- .../ConversationInfoActivity.kt | 30 ++++++++++++++++++ .../viewmodel/ConversationInfoViewModel.kt | 31 +++++++++++++++++++ .../conversations/ConversationsRepository.kt | 2 ++ .../ConversationsRepositoryImpl.kt | 4 +++ .../java/com/nextcloud/talk/utils/ApiUtils.kt | 2 +- .../nextcloud/talk/utils/ConversationUtils.kt | 8 +++++ .../res/layout/activity_conversation_info.xml | 5 ++- app/src/main/res/values/strings.xml | 1 + 8 files changed, 79 insertions(+), 4 deletions(-) diff --git a/app/src/main/java/com/nextcloud/talk/conversationinfo/ConversationInfoActivity.kt b/app/src/main/java/com/nextcloud/talk/conversationinfo/ConversationInfoActivity.kt index 56630615a8..ae4674f3af 100644 --- a/app/src/main/java/com/nextcloud/talk/conversationinfo/ConversationInfoActivity.kt +++ b/app/src/main/java/com/nextcloud/talk/conversationinfo/ConversationInfoActivity.kt @@ -256,6 +256,18 @@ class ConversationInfoActivity : else -> {} } } + + viewModel.getConversationReadOnlyState.observe(this) { state -> + when (state) { + is ConversationInfoViewModel.SetConversationReadOnlySuccessState -> { + } + is ConversationInfoViewModel.SetConversationReadOnlyErrorState -> { + Snackbar.make(binding.root, R.string.conversation_read_only_failed, Snackbar.LENGTH_LONG).show() + } + else -> { + } + } + } } private fun setupActionBar() { @@ -658,6 +670,7 @@ class ConversationInfoActivity : intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP) startActivity(intent) } + WorkInfo.State.FAILED -> { val errorType = workInfo.outputData.getString("error_type") if (errorType == LeaveConversationWorker.ERROR_NO_OTHER_MODERATORS_OR_OWNERS_LEFT) { @@ -674,6 +687,7 @@ class ConversationInfoActivity : ).show() } } + else -> { } } @@ -826,6 +840,18 @@ class ConversationInfoActivity : binding.archiveConversationTextHint.text = resources.getString(R.string.archive_hint) } + if (ConversationUtils.isConversationReadOnlyAvailable(conversationCopy, spreedCapabilities)) { + binding.lockConversation.visibility = VISIBLE + binding.lockConversation.setOnClickListener { + val isChecked = binding.lockConversationSwitch.isChecked + binding.lockConversationSwitch.isChecked = !isChecked + val state = if (isChecked) 0 else 1 + makeConversationReadOnly(conversationUser, conversationToken, state) + } + } else { + binding.lockConversation.visibility = GONE + } + if (!isDestroyed) { binding.dangerZoneOptions.visibility = VISIBLE @@ -898,6 +924,10 @@ class ConversationInfoActivity : } } + private fun makeConversationReadOnly(conversationUser: User, roomToken: String, state: Int) { + viewModel.setConversationReadOnly(conversationUser, roomToken, state) + } + private fun initRecordingConsentOption() { fun hide() { binding.recordingConsentView.recordingConsentSettingsCategory.visibility = GONE diff --git a/app/src/main/java/com/nextcloud/talk/conversationinfo/viewmodel/ConversationInfoViewModel.kt b/app/src/main/java/com/nextcloud/talk/conversationinfo/viewmodel/ConversationInfoViewModel.kt index a84fd4da8f..68e278a994 100644 --- a/app/src/main/java/com/nextcloud/talk/conversationinfo/viewmodel/ConversationInfoViewModel.kt +++ b/app/src/main/java/com/nextcloud/talk/conversationinfo/viewmodel/ConversationInfoViewModel.kt @@ -76,6 +76,13 @@ class ConversationInfoViewModel @Inject constructor( val getUnBanActorState: LiveData get() = _getUnBanActorState + object SetConversationReadOnlySuccessState : ViewState + object SetConversationReadOnlyErrorState : ViewState + + private val _getConversationReadOnlyState: MutableLiveData = MutableLiveData() + val getConversationReadOnlyState: LiveData + get() = _getConversationReadOnlyState + object GetRoomStartState : ViewState object GetRoomErrorState : ViewState open class GetRoomSuccessState(val conversationModel: ConversationModel) : ViewState @@ -178,6 +185,30 @@ class ConversationInfoViewModel @Inject constructor( }) } + fun setConversationReadOnly(user: User, token: String, state: Int) { + val apiVersion = ApiUtils.getConversationApiVersion(user, intArrayOf(ApiUtils.API_V4, ApiUtils.API_V1)) + val url = ApiUtils.getUrlForConversationReadOnly(apiVersion, user.baseUrl!!, token) + conversationsRepository.setConversationReadOnly(user.getCredentials(), url, state) + .subscribeOn(Schedulers.io()) + ?.observeOn(AndroidSchedulers.mainThread()) + ?.subscribe(object : Observer { + override fun onSubscribe(p0: Disposable) { + } + + override fun onError(error: Throwable) { + _getConversationReadOnlyState.value = SetConversationReadOnlyErrorState + } + + override fun onComplete() { + // unused atm + } + + override fun onNext(p0: GenericOverall) { + _getConversationReadOnlyState.value = SetConversationReadOnlySuccessState + } + }) + } + fun unbanActor(user: User, token: String, banId: Int) { val url = ApiUtils.getUrlForUnban(user.baseUrl!!, token, banId) chatNetworkDataSource.unbanActor(user.getCredentials(), url) diff --git a/app/src/main/java/com/nextcloud/talk/repositories/conversations/ConversationsRepository.kt b/app/src/main/java/com/nextcloud/talk/repositories/conversations/ConversationsRepository.kt index 2905da2e67..9415927321 100644 --- a/app/src/main/java/com/nextcloud/talk/repositories/conversations/ConversationsRepository.kt +++ b/app/src/main/java/com/nextcloud/talk/repositories/conversations/ConversationsRepository.kt @@ -34,4 +34,6 @@ interface ConversationsRepository { suspend fun archiveConversation(credentials: String, url: String): GenericOverall suspend fun unarchiveConversation(credentials: String, url: String): GenericOverall + + fun setConversationReadOnly(credentials: String, url: String, state: Int): Observable } diff --git a/app/src/main/java/com/nextcloud/talk/repositories/conversations/ConversationsRepositoryImpl.kt b/app/src/main/java/com/nextcloud/talk/repositories/conversations/ConversationsRepositoryImpl.kt index 3f0549612e..458b97efea 100644 --- a/app/src/main/java/com/nextcloud/talk/repositories/conversations/ConversationsRepositoryImpl.kt +++ b/app/src/main/java/com/nextcloud/talk/repositories/conversations/ConversationsRepositoryImpl.kt @@ -100,6 +100,10 @@ class ConversationsRepositoryImpl( return coroutineApi.unarchiveConversation(credentials, url) } + override fun setConversationReadOnly(credentials: String, url: String, state: Int): Observable { + return api.setConversationReadOnly(credentials, url, state) + } + private fun apiVersion(): Int { return ApiUtils.getConversationApiVersion(user, intArrayOf(ApiUtils.API_V4)) } diff --git a/app/src/main/java/com/nextcloud/talk/utils/ApiUtils.kt b/app/src/main/java/com/nextcloud/talk/utils/ApiUtils.kt index 557c876fca..04ee69e5de 100644 --- a/app/src/main/java/com/nextcloud/talk/utils/ApiUtils.kt +++ b/app/src/main/java/com/nextcloud/talk/utils/ApiUtils.kt @@ -231,7 +231,7 @@ object ApiUtils { return getUrlForRoom(version, baseUrl, token) + "/password" } - fun getUrlForRoomReadOnlyState(version: Int, baseUrl: String?, token: String?): String { + fun getUrlForConversationReadOnly(version: Int, baseUrl: String?, token: String?): String { return getUrlForRoom(version, baseUrl, token) + "/read-only" } 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 08dbb8587a..04345b3c86 100644 --- a/app/src/main/java/com/nextcloud/talk/utils/ConversationUtils.kt +++ b/app/src/main/java/com/nextcloud/talk/utils/ConversationUtils.kt @@ -42,6 +42,14 @@ object ConversationUtils { !isNoteToSelfConversation(conversation) } + fun isConversationReadOnlyAvailable( + conversation: ConversationModel, + spreedCapabilities: SpreedCapability + ): Boolean { + return CapabilitiesUtil.hasSpreedFeatureCapability(spreedCapabilities, SpreedFeatures.READ_ONLY_ROOMS) && + canModerate(conversation, spreedCapabilities) + } + fun isLobbyViewApplicable(conversation: ConversationModel, spreedCapabilities: SpreedCapability): Boolean { return !canModerate(conversation, spreedCapabilities) && ( diff --git a/app/src/main/res/layout/activity_conversation_info.xml b/app/src/main/res/layout/activity_conversation_info.xml index fc910e367a..f1c830ca33 100644 --- a/app/src/main/res/layout/activity_conversation_info.xml +++ b/app/src/main/res/layout/activity_conversation_info.xml @@ -335,14 +335,13 @@ diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 1ff4be6654..cffc2508ff 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -824,4 +824,5 @@ How to translate with transifex: Archived Once a conversation is archived, it will be hidden by default. Select the filter \'Archived\' to view archived conversations. Direct mentions will still be received. Once a conversation is unarchived, it will be shown by default again. + Failed to set conversation Read-only From 17e105b09c9b63623189b54ec9c57711ec0761ca Mon Sep 17 00:00:00 2001 From: sowjanyakch Date: Fri, 8 Nov 2024 14:35:09 +0100 Subject: [PATCH 312/885] store lock setting in arbitrary storage Signed-off-by: sowjanyakch --- .../talk/conversationinfo/ConversationInfoActivity.kt | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/app/src/main/java/com/nextcloud/talk/conversationinfo/ConversationInfoActivity.kt b/app/src/main/java/com/nextcloud/talk/conversationinfo/ConversationInfoActivity.kt index ae4674f3af..f63793fabf 100644 --- a/app/src/main/java/com/nextcloud/talk/conversationinfo/ConversationInfoActivity.kt +++ b/app/src/main/java/com/nextcloud/talk/conversationinfo/ConversationInfoActivity.kt @@ -839,13 +839,15 @@ class ConversationInfoActivity : binding.archiveConversationText.text = resources.getString(R.string.archive_conversation) binding.archiveConversationTextHint.text = resources.getString(R.string.archive_hint) } - if (ConversationUtils.isConversationReadOnlyAvailable(conversationCopy, spreedCapabilities)) { binding.lockConversation.visibility = VISIBLE + binding.lockConversationSwitch.isChecked = databaseStorageModule!!.getBoolean("lock_switch", false) + binding.lockConversation.setOnClickListener { - val isChecked = binding.lockConversationSwitch.isChecked - binding.lockConversationSwitch.isChecked = !isChecked - val state = if (isChecked) 0 else 1 + val isLocked = binding.lockConversationSwitch.isChecked + binding.lockConversationSwitch.isChecked = !isLocked + databaseStorageModule!!.saveBoolean("lock_switch", !isLocked) + val state = if (isLocked) 0 else 1 makeConversationReadOnly(conversationUser, conversationToken, state) } } else { From 00632e5d70f3e4616ce148b0864b3b0e41de1702 Mon Sep 17 00:00:00 2001 From: sowjanyakch Date: Fri, 8 Nov 2024 17:26:13 +0100 Subject: [PATCH 313/885] suppress string format invalid Signed-off-by: sowjanyakch --- .../nextcloud/talk/conversationinfo/ConversationInfoActivity.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/src/main/java/com/nextcloud/talk/conversationinfo/ConversationInfoActivity.kt b/app/src/main/java/com/nextcloud/talk/conversationinfo/ConversationInfoActivity.kt index f63793fabf..50bfddd775 100644 --- a/app/src/main/java/com/nextcloud/talk/conversationinfo/ConversationInfoActivity.kt +++ b/app/src/main/java/com/nextcloud/talk/conversationinfo/ConversationInfoActivity.kt @@ -1327,7 +1327,7 @@ class ConversationInfoActivity : } } - @SuppressLint("CheckResult") + @SuppressLint("CheckResult", "StringFormatInvalid") override fun onItemClick(view: View?, position: Int): Boolean { if (!ConversationUtils.canModerate(conversation!!, spreedCapabilities)) { return true From 8a4c45e8ca4f22af92b5d51c4bc8c3e2cd359d3c Mon Sep 17 00:00:00 2001 From: Nextcloud bot Date: Sat, 9 Nov 2024 02:58:55 +0000 Subject: [PATCH 314/885] Fix(l10n): Update translations from Transifex Signed-off-by: Nextcloud bot --- app/src/main/res/values-ar/strings.xml | 3 ++- app/src/main/res/values-lt-rLT/strings.xml | 1 + 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/app/src/main/res/values-ar/strings.xml b/app/src/main/res/values-ar/strings.xml index 880288fa50..91f77d2566 100644 --- a/app/src/main/res/values-ar/strings.xml +++ b/app/src/main/res/values-ar/strings.xml @@ -38,7 +38,7 @@ محادثات انشاء محادثة تكوين إشكالية - مُخصّص + مخصص منطقة خطر %1$s في %2$s إمسح صورة الملف الشخصي الرمزية @@ -281,6 +281,7 @@ الاشعارات في هذه المحادثة ستتجاوز إعداد الحالة \"يُرجى عدم الإزعاج\" دعوات الانضمام إلى محادثات جارية + تحتاج إلى إنشاء ميسر جديد قبل أن تتمكن من مغادرة المحادثة %1$s| آخر تعديل: %2$s غادر المحادثة مُغادرة المكالمة … diff --git a/app/src/main/res/values-lt-rLT/strings.xml b/app/src/main/res/values-lt-rLT/strings.xml index 9570c03de4..f7f82cec4d 100644 --- a/app/src/main/res/values-lt-rLT/strings.xml +++ b/app/src/main/res/values-lt-rLT/strings.xml @@ -111,6 +111,7 @@ Android versija Programėlė Programėlės pavadinimas + Programėlės versija Akumuliatoriaus nustatymai Įrenginys Telefonas From 60853df4c0eeb388e6da0fb1c132a0e392ee7e57 Mon Sep 17 00:00:00 2001 From: Nextcloud bot Date: Mon, 11 Nov 2024 02:58:20 +0000 Subject: [PATCH 315/885] Fix(l10n): Update translations from Transifex Signed-off-by: Nextcloud bot --- app/src/main/res/values-ar/strings.xml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/app/src/main/res/values-ar/strings.xml b/app/src/main/res/values-ar/strings.xml index 91f77d2566..4509b3c298 100644 --- a/app/src/main/res/values-ar/strings.xml +++ b/app/src/main/res/values-ar/strings.xml @@ -201,9 +201,9 @@ خدمات متجر التطبيقات من قوقل Google play خدمات متجر التطبيقات من قوقل Google play متاحة آخر تسجيل لعملية إدخال push في وكيل الإدخال push proxy - لم يتم التسجيل بعدُ في وكيل الإدخال push proxy + لم يتم التسجيل حتى الآن في وكيل الإرسال Push proxy آخر تسجيل لعملية إدخال push في الخادم - لم يتم التسجيل بعدُ في الخادم + لم يتم التسجيل حتى الآن في الخادم معلومات وصفية توليد تقرير النظام هل قناة الإشعار بالمكالمات مُمكّنة؟ @@ -344,7 +344,7 @@ كلمة المرور تعيين الأذونات بعض الأذونات تمّ رفضها - إسمَح بالأذونات رجاءً + يرجى السماح بالأذونات فتح الإعدادات إمنح الأذونات رجاءً من Settings > Permissions الحساب غير موجود From 3e10813ae0fb85f0f11722c6d9ef7722c18688c4 Mon Sep 17 00:00:00 2001 From: Nextcloud Android Bot Date: Mon, 11 Nov 2024 03:13:27 +0000 Subject: [PATCH 316/885] Weekly 20.1.0 Alpha 11 --- app/build.gradle | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/app/build.gradle b/app/build.gradle index dc224058cd..f2fb3cf58d 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -40,8 +40,8 @@ android { // mayor.minor.hotfix.increment (for increment: 01-50=Alpha / 51-89=RC / 90-99=stable) // xx .xxx .xx .xx - versionCode 200010010 - versionName "20.1.0 Alpha 10" + versionCode 200010011 + versionName "20.1.0 Alpha 11" flavorDimensions "default" renderscriptTargetApi 19 From 990f6ec3faf6b1f26eb3b7fa66eb34dd6df70f9d Mon Sep 17 00:00:00 2001 From: rapterjet2004 Date: Wed, 6 Nov 2024 10:02:21 -0600 Subject: [PATCH 317/885] Better Call Started Indicator - Pinned to MessageInputFragment - Collapsable - Looks cool Signed-off-by: rapterjet2004 --- .../messages/CallStartedViewHolder.kt | 115 ------------------ .../messages/TalkMessagesListAdapter.java | 3 - .../com/nextcloud/talk/chat/ChatActivity.kt | 39 ++---- .../talk/chat/MessageInputFragment.kt | 101 +++++++++++++++ .../chat/viewmodels/MessageInputViewModel.kt | 9 ++ .../res/drawable/ic_keyboard_arrow_up.xml | 21 ++++ .../main/res/layout/call_started_message.xml | 42 ++++++- .../res/layout/fragment_message_input.xml | 72 ++++++----- 8 files changed, 222 insertions(+), 180 deletions(-) delete mode 100644 app/src/main/java/com/nextcloud/talk/adapters/messages/CallStartedViewHolder.kt create mode 100644 app/src/main/res/drawable/ic_keyboard_arrow_up.xml 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 deleted file mode 100644 index c726c64e93..0000000000 --- a/app/src/main/java/com/nextcloud/talk/adapters/messages/CallStartedViewHolder.kt +++ /dev/null @@ -1,115 +0,0 @@ -/* - * Nextcloud Talk - Android Client - * - * SPDX-FileCopyrightText: 2023 Julius Linus - * SPDX-License-Identifier: GPL-3.0-or-later - */ -package com.nextcloud.talk.adapters.messages - -import android.content.Context -import android.graphics.drawable.Drawable -import android.view.View -import autodagger.AutoInjector -import coil.Coil.imageLoader -import coil.request.ImageRequest -import coil.target.Target -import coil.transform.CircleCropTransformation -import com.nextcloud.talk.application.NextcloudTalkApplication -import com.nextcloud.talk.databinding.CallStartedMessageBinding -import com.nextcloud.talk.chat.data.model.ChatMessage -import com.nextcloud.talk.ui.theme.ViewThemeUtils -import com.nextcloud.talk.users.UserManager -import com.nextcloud.talk.utils.ApiUtils -import com.stfalcon.chatkit.messages.MessageHolders -import javax.inject.Inject - -@AutoInjector(NextcloudTalkApplication::class) -class CallStartedViewHolder(incomingView: View, payload: Any) : - MessageHolders.BaseIncomingMessageViewHolder(incomingView, payload) { - private val binding: CallStartedMessageBinding = CallStartedMessageBinding.bind(incomingView) - - @Inject - lateinit var context: Context - - @Inject - lateinit var userManager: UserManager - - @Inject - lateinit var viewThemeUtils: ViewThemeUtils - - private lateinit var messageInterface: CallStartedMessageInterface - - override fun onBind(message: ChatMessage) { - super.onBind(message) - NextcloudTalkApplication.sharedApplication!!.componentApplication.inject(this) - themeBackground() - setUpAvatarProfile(message) - binding.callAuthorChip.text = message.actorDisplayName - binding.joinVideoCall.setOnClickListener { messageInterface.joinVideoCall() } - binding.joinAudioCall.setOnClickListener { messageInterface.joinAudioCall() } - } - - private fun themeBackground() { - binding.callStartedBackground.apply { - viewThemeUtils.talk.themeOutgoingMessageBubble(this, grouped = true, false) - } - - binding.callAuthorChip.apply { - viewThemeUtils.material.colorChipBackground(this) - } - } - - 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() - - imageLoader(context).enqueue(imageRequest) - } - - fun assignCallStartedMessageInterface(inf: CallStartedMessageInterface) { - messageInterface = inf - } - - override fun viewDetached() { - // unused atm - } - - override fun viewAttached() { - // unused atm - } - - override fun viewRecycled() { - // unused atm - } - - companion object { - val TAG: String? = CallStartedViewHolder::class.simpleName - } -} diff --git a/app/src/main/java/com/nextcloud/talk/adapters/messages/TalkMessagesListAdapter.java b/app/src/main/java/com/nextcloud/talk/adapters/messages/TalkMessagesListAdapter.java index d331f1d61f..6eda1ff98c 100644 --- a/app/src/main/java/com/nextcloud/talk/adapters/messages/TalkMessagesListAdapter.java +++ b/app/src/main/java/com/nextcloud/talk/adapters/messages/TalkMessagesListAdapter.java @@ -68,9 +68,6 @@ public void onBindViewHolder(ViewHolder holder, int position) { } else if (holder instanceof SystemMessageViewHolder holderInstance) { holderInstance.assignSystemMessageInterface(chatActivity); - } else if (holder instanceof CallStartedViewHolder holderInstance) { - holderInstance.assignCallStartedMessageInterface(chatActivity); - } else if (holder instanceof TemporaryMessageViewHolder holderInstance) { holderInstance.assignTemporaryMessageInterface(chatActivity); diff --git a/app/src/main/java/com/nextcloud/talk/chat/ChatActivity.kt b/app/src/main/java/com/nextcloud/talk/chat/ChatActivity.kt index 08103488ce..247cb50ece 100644 --- a/app/src/main/java/com/nextcloud/talk/chat/ChatActivity.kt +++ b/app/src/main/java/com/nextcloud/talk/chat/ChatActivity.kt @@ -81,7 +81,6 @@ import com.nextcloud.talk.activities.BaseActivity import com.nextcloud.talk.activities.CallActivity import com.nextcloud.talk.activities.TakePhotoActivity import com.nextcloud.talk.adapters.messages.CallStartedMessageInterface -import com.nextcloud.talk.adapters.messages.CallStartedViewHolder import com.nextcloud.talk.adapters.messages.CommonMessageInterface import com.nextcloud.talk.adapters.messages.IncomingDeckCardViewHolder import com.nextcloud.talk.adapters.messages.IncomingLinkPreviewMessageViewHolder @@ -879,7 +878,7 @@ class ChatActivity : } processExpiredMessages() - processCallStartedMessages(chatMessageList) + processCallStartedMessages() adapter?.notifyDataSetChanged() } @@ -1199,17 +1198,6 @@ class ChatActivity : R.layout.item_custom_outcoming_preview_message ) - messageHolders.registerContentType( - CONTENT_TYPE_CALL_STARTED, - CallStartedViewHolder::class.java, - payload, - R.layout.call_started_message, - CallStartedViewHolder::class.java, - payload, - R.layout.call_started_message, - this - ) - messageHolders.registerContentType( CONTENT_TYPE_TEMP, TemporaryMessageViewHolder::class.java, @@ -2559,7 +2547,7 @@ class ChatActivity : webSocketInstance?.getSignalingMessageReceiver()?.addListener(conversationMessageListener) } - private fun processCallStartedMessages(chatMessageList: List) { + private fun processCallStartedMessages() { try { val mostRecentCallSystemMessage = adapter?.items?.first { it.item is ChatMessage && @@ -2577,8 +2565,7 @@ class ChatActivity : if (mostRecentCallSystemMessage != null) { processMostRecentMessage( - mostRecentCallSystemMessage as ChatMessage, - chatMessageList + mostRecentCallSystemMessage as ChatMessage ) } } catch (e: NoSuchElementException) { @@ -3542,29 +3529,21 @@ class ChatActivity : else -> false } - private fun processMostRecentMessage(recent: ChatMessage, chatMessageList: List) { + private fun processMostRecentMessage(recent: ChatMessage) { when (recent.systemMessageType) { - ChatMessage.SystemMessageType.CALL_STARTED -> { // add CallStartedMessage with id -2 + ChatMessage.SystemMessageType.CALL_STARTED -> { if (!callStarted) { - val callStartedChatMessage = ChatMessage() - callStartedChatMessage.jsonMessageId = CALL_STARTED_ID - callStartedChatMessage.actorId = "-2" - val name = if (recent.actorDisplayName.isNullOrEmpty()) "Guest" else recent.actorDisplayName - callStartedChatMessage.actorDisplayName = name - callStartedChatMessage.actorType = recent.actorType - callStartedChatMessage.timestamp = chatMessageList[0].timestamp - callStartedChatMessage.message = null - adapter?.addToStart(callStartedChatMessage, false) + messageInputViewModel.showCallStartedIndicator(recent, true) callStarted = true } - } // remove CallStartedMessage with id -2 + } ChatMessage.SystemMessageType.CALL_ENDED, ChatMessage.SystemMessageType.CALL_MISSED, ChatMessage.SystemMessageType.CALL_TRIED, ChatMessage.SystemMessageType.CALL_ENDED_EVERYONE -> { - adapter?.deleteById("-2") callStarted = false - } // remove message of id -2 + messageInputViewModel.showCallStartedIndicator(recent, false) + } else -> {} } } diff --git a/app/src/main/java/com/nextcloud/talk/chat/MessageInputFragment.kt b/app/src/main/java/com/nextcloud/talk/chat/MessageInputFragment.kt index 9ddcc6c560..1047849efc 100644 --- a/app/src/main/java/com/nextcloud/talk/chat/MessageInputFragment.kt +++ b/app/src/main/java/com/nextcloud/talk/chat/MessageInputFragment.kt @@ -9,6 +9,7 @@ package com.nextcloud.talk.chat import android.content.res.Resources import android.graphics.drawable.ColorDrawable +import android.graphics.drawable.Drawable import android.os.Build import android.os.Bundle import android.os.CountDownTimer @@ -36,6 +37,7 @@ import android.widget.PopupMenu import android.widget.RelativeLayout import android.widget.SeekBar import androidx.appcompat.app.AppCompatActivity +import androidx.appcompat.content.res.AppCompatResources import androidx.appcompat.view.ContextThemeWrapper import androidx.core.content.ContextCompat import androidx.core.widget.doAfterTextChanged @@ -43,7 +45,11 @@ import androidx.emoji2.widget.EmojiTextView import androidx.fragment.app.Fragment import androidx.lifecycle.lifecycleScope import autodagger.AutoInjector +import coil.Coil.imageLoader import coil.load +import coil.request.ImageRequest +import coil.target.Target +import coil.transform.CircleCropTransformation import com.google.android.flexbox.FlexboxLayout import com.google.android.material.button.MaterialButton import com.google.android.material.snackbar.Snackbar @@ -118,6 +124,7 @@ class MessageInputFragment : Fragment() { private var mentionAutocomplete: Autocomplete<*>? = null private var xcounter = 0f private var ycounter = 0f + private var isCollapsed = false override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) @@ -196,6 +203,49 @@ class MessageInputFragment : Fragment() { binding.fragmentConnectionLost.text = getString(R.string.connection_lost_sent_messages_are_queued) } } + + chatActivity.messageInputViewModel.callStartedFlow.observe(viewLifecycleOwner) { + val (message, show) = it + if (show) { + binding.fragmentCallStarted.callAuthorChip.text = message.actorDisplayName + binding.fragmentCallStarted.callAuthorChipSecondary.text = message.actorDisplayName + 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.actorId, false) + } + + val imageRequest: ImageRequest = ImageRequest.Builder(requireContext()) + .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.fragmentCallStarted.callAuthorChip.chipIcon = result + binding.fragmentCallStarted.callAuthorChipSecondary.chipIcon = result + } + }) + .build() + + imageLoader(requireContext()).enqueue(imageRequest) + binding.fragmentCallStarted.root.visibility = View.VISIBLE + } else { + binding.fragmentCallStarted.root.visibility = View.GONE + } + } } private fun handleUI(isOnline: Boolean, connectionGained: Boolean) { @@ -390,6 +440,41 @@ class MessageInputFragment : Fragment() { binding.fragmentMessageInputView.button?.contentDescription = resources.getString(R.string.nc_description_send_message_button) + + binding.fragmentCallStarted.joinAudioCall.setOnClickListener { + chatActivity.joinAudioCall() + } + + binding.fragmentCallStarted.joinVideoCall.setOnClickListener { + chatActivity.joinVideoCall() + } + + binding.fragmentCallStarted.callStartedCloseBtn.setOnClickListener { + isCollapsed = !isCollapsed + if (isCollapsed) { + binding.fragmentCallStarted.callAuthorLayout.visibility = View.GONE + binding.fragmentCallStarted.callBtnLayout.visibility = View.GONE + binding.fragmentCallStarted.callAuthorChipSecondary.visibility = View.VISIBLE + binding.fragmentCallStarted.callStartedSecondaryText.visibility = View.VISIBLE + } else { + binding.fragmentCallStarted.callAuthorLayout.visibility = View.VISIBLE + binding.fragmentCallStarted.callBtnLayout.visibility = View.VISIBLE + binding.fragmentCallStarted.callAuthorChipSecondary.visibility = View.GONE + binding.fragmentCallStarted.callStartedSecondaryText.visibility = View.GONE + } + + setDropDown(isCollapsed) + } + } + + private fun setDropDown(collapsed: Boolean) { + val drawable = if (collapsed) { + AppCompatResources.getDrawable(requireContext(), R.drawable.ic_keyboard_arrow_up) + } else { + AppCompatResources.getDrawable(requireContext(), R.drawable.ic_keyboard_arrow_down) + } + + binding.fragmentCallStarted.callStartedCloseBtn.setImageDrawable(drawable) } @Suppress("ClickableViewAccessibility", "CyclomaticComplexMethod", "LongMethod") @@ -907,6 +992,22 @@ class MessageInputFragment : Fragment() { binding.fragmentEditView.clearEdit.let { viewThemeUtils.platform.colorImageView(it, ColorRole.PRIMARY) } + + binding.fragmentCallStarted.callStartedBackground.apply { + viewThemeUtils.talk.themeOutgoingMessageBubble(this, grouped = true, false) + } + + binding.fragmentCallStarted.callAuthorChip.apply { + viewThemeUtils.material.colorChipBackground(this) + } + + binding.fragmentCallStarted.callAuthorChipSecondary.apply { + viewThemeUtils.material.colorChipBackground(this) + } + + binding.fragmentCallStarted.callStartedCloseBtn.apply { + viewThemeUtils.platform.colorImageView(this, ColorRole.PRIMARY) + } } private fun cancelReply() { diff --git a/app/src/main/java/com/nextcloud/talk/chat/viewmodels/MessageInputViewModel.kt b/app/src/main/java/com/nextcloud/talk/chat/viewmodels/MessageInputViewModel.kt index 6e17ac0b61..4292a02817 100644 --- a/app/src/main/java/com/nextcloud/talk/chat/viewmodels/MessageInputViewModel.kt +++ b/app/src/main/java/com/nextcloud/talk/chat/viewmodels/MessageInputViewModel.kt @@ -18,6 +18,7 @@ import androidx.lifecycle.asLiveData import com.nextcloud.talk.chat.data.io.AudioFocusRequestManager import com.nextcloud.talk.chat.data.io.AudioRecorderManager import com.nextcloud.talk.chat.data.io.MediaPlayerManager +import com.nextcloud.talk.chat.data.model.ChatMessage import com.nextcloud.talk.chat.data.network.ChatNetworkDataSource import com.nextcloud.talk.models.json.chat.ChatOverallSingleMessage import com.nextcloud.talk.models.json.generic.GenericOverall @@ -129,6 +130,10 @@ class MessageInputViewModel @Inject constructor( val messageQueueFlow: LiveData> get() = _messageQueueFlow + private val _callStartedFlow: MutableLiveData> = MutableLiveData() + val callStartedFlow: LiveData> + get() = _callStartedFlow + @Suppress("LongParameterList") fun sendChatMessage( internalId: String, @@ -314,6 +319,10 @@ class MessageInputViewModel @Inject constructor( dataStore.saveMessageQueue(internalId, queue) } + fun showCallStartedIndicator(recent: ChatMessage, show: Boolean) { + _callStartedFlow.postValue(Pair(recent, show)) + } + companion object { private val TAG = MessageInputViewModel::class.java.simpleName private const val DELAY_BETWEEN_QUEUED_MESSAGES: Long = 1000 diff --git a/app/src/main/res/drawable/ic_keyboard_arrow_up.xml b/app/src/main/res/drawable/ic_keyboard_arrow_up.xml new file mode 100644 index 0000000000..93ed0650f9 --- /dev/null +++ b/app/src/main/res/drawable/ic_keyboard_arrow_up.xml @@ -0,0 +1,21 @@ + + + + + + diff --git a/app/src/main/res/layout/call_started_message.xml b/app/src/main/res/layout/call_started_message.xml index 33360a4c02..7dd2f1a04c 100644 --- a/app/src/main/res/layout/call_started_message.xml +++ b/app/src/main/res/layout/call_started_message.xml @@ -20,7 +20,46 @@ + + + + + + + + + + @@ -42,6 +81,7 @@ + - - + + + + - + \ No newline at end of file From 07cf834cc51bd4bb7c149bd666d634010e6a171c Mon Sep 17 00:00:00 2001 From: Marcel Hibbe Date: Fri, 8 Nov 2024 14:27:41 +0100 Subject: [PATCH 318/885] hide archiveConversationTextHint when archive not available Signed-off-by: Marcel Hibbe --- .../talk/conversationinfo/ConversationInfoActivity.kt | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/app/src/main/java/com/nextcloud/talk/conversationinfo/ConversationInfoActivity.kt b/app/src/main/java/com/nextcloud/talk/conversationinfo/ConversationInfoActivity.kt index 56630615a8..9f1809eee9 100644 --- a/app/src/main/java/com/nextcloud/talk/conversationinfo/ConversationInfoActivity.kt +++ b/app/src/main/java/com/nextcloud/talk/conversationinfo/ConversationInfoActivity.kt @@ -403,10 +403,9 @@ class ConversationInfoActivity : } } - private fun webinaryRoomType(conversation: ConversationModel): Boolean { - return conversation.type == ConversationEnums.ConversationType.ROOM_GROUP_CALL || + private fun webinaryRoomType(conversation: ConversationModel): Boolean = + conversation.type == ConversationEnums.ConversationType.ROOM_GROUP_CALL || conversation.type == ConversationEnums.ConversationType.ROOM_PUBLIC_CALL - } private fun reconfigureLobbyTimerView(dateTime: Calendar? = null) { val isChecked = binding.webinarInfoView.lobbySwitch.isChecked @@ -794,6 +793,7 @@ class ConversationInfoActivity : if (!CapabilitiesUtil.isArchiveConversationsAvailable(spreedCapabilities)) { binding.archiveConversationBtn.visibility = GONE + binding.archiveConversationTextHint.visibility = GONE } binding.archiveConversationBtn.setOnClickListener { From 60925231464891f03080c2d66ce7802f22c7bbb5 Mon Sep 17 00:00:00 2001 From: Marcel Hibbe Date: Fri, 8 Nov 2024 14:44:55 +0100 Subject: [PATCH 319/885] delete isArchiveConversationsAvailable only more complex checks should be made in CapabilitiesUtil, just checking a capability should be done directly via hasSpreedFeatureCapability Signed-off-by: Marcel Hibbe --- .../ConversationInfoActivity.kt | 3 +- .../nextcloud/talk/utils/CapabilitiesUtil.kt | 58 +++++++------------ 2 files changed, 23 insertions(+), 38 deletions(-) diff --git a/app/src/main/java/com/nextcloud/talk/conversationinfo/ConversationInfoActivity.kt b/app/src/main/java/com/nextcloud/talk/conversationinfo/ConversationInfoActivity.kt index 9f1809eee9..aed4473ef3 100644 --- a/app/src/main/java/com/nextcloud/talk/conversationinfo/ConversationInfoActivity.kt +++ b/app/src/main/java/com/nextcloud/talk/conversationinfo/ConversationInfoActivity.kt @@ -77,6 +77,7 @@ import com.nextcloud.talk.shareditems.activities.SharedItemsActivity import com.nextcloud.talk.ui.dialog.DialogBanListFragment import com.nextcloud.talk.utils.ApiUtils import com.nextcloud.talk.utils.CapabilitiesUtil +import com.nextcloud.talk.utils.CapabilitiesUtil.hasSpreedFeatureCapability import com.nextcloud.talk.utils.ConversationUtils import com.nextcloud.talk.utils.DateConstants import com.nextcloud.talk.utils.DateUtils @@ -791,7 +792,7 @@ class ConversationInfoActivity : } } - if (!CapabilitiesUtil.isArchiveConversationsAvailable(spreedCapabilities)) { + if (!hasSpreedFeatureCapability(spreedCapabilities, SpreedFeatures.ARCHIVE_CONVERSATIONS)) { binding.archiveConversationBtn.visibility = GONE binding.archiveConversationTextHint.visibility = GONE } diff --git a/app/src/main/java/com/nextcloud/talk/utils/CapabilitiesUtil.kt b/app/src/main/java/com/nextcloud/talk/utils/CapabilitiesUtil.kt index 996262296d..54bb10e2fc 100644 --- a/app/src/main/java/com/nextcloud/talk/utils/CapabilitiesUtil.kt +++ b/app/src/main/java/com/nextcloud/talk/utils/CapabilitiesUtil.kt @@ -84,14 +84,11 @@ object CapabilitiesUtil { //region CoreCapabilities @JvmStatic - fun isLinkPreviewAvailable(user: User): Boolean { - return user.capabilities?.coreCapability?.referenceApi != null && + fun isLinkPreviewAvailable(user: User): Boolean = + user.capabilities?.coreCapability?.referenceApi != null && user.capabilities?.coreCapability?.referenceApi == "true" - } - fun canGeneratePrettyURL(user: User): Boolean { - return user.capabilities?.coreCapability?.modRewriteWorking == true - } + fun canGeneratePrettyURL(user: User): Boolean = user.capabilities?.coreCapability?.modRewriteWorking == true // endregion @@ -105,9 +102,8 @@ object CapabilitiesUtil { return false } - fun isSharedItemsAvailable(spreedCapabilities: SpreedCapability): Boolean { - return hasSpreedFeatureCapability(spreedCapabilities, SpreedFeatures.RICH_OBJECT_LIST_MEDIA) - } + fun isSharedItemsAvailable(spreedCapabilities: SpreedCapability): Boolean = + hasSpreedFeatureCapability(spreedCapabilities, SpreedFeatures.RICH_OBJECT_LIST_MEDIA) fun getMessageMaxLength(spreedCapabilities: SpreedCapability): Int { if (spreedCapabilities.config?.containsKey("chat") == true) { @@ -157,16 +153,14 @@ object CapabilitiesUtil { return "/Talk" } - fun isConversationDescriptionEndpointAvailable(spreedCapabilities: SpreedCapability): Boolean { - return hasSpreedFeatureCapability(spreedCapabilities, SpreedFeatures.ROOM_DESCRIPTION) - } + fun isConversationDescriptionEndpointAvailable(spreedCapabilities: SpreedCapability): Boolean = + hasSpreedFeatureCapability(spreedCapabilities, SpreedFeatures.ROOM_DESCRIPTION) - fun isUnifiedSearchAvailable(spreedCapabilities: SpreedCapability): Boolean { - return hasSpreedFeatureCapability(spreedCapabilities, SpreedFeatures.UNIFIED_SEARCH) - } + fun isUnifiedSearchAvailable(spreedCapabilities: SpreedCapability): Boolean = + hasSpreedFeatureCapability(spreedCapabilities, SpreedFeatures.UNIFIED_SEARCH) - fun isAbleToCall(spreedCapabilities: SpreedCapability): Boolean { - return if ( + fun isAbleToCall(spreedCapabilities: SpreedCapability): Boolean = + if ( spreedCapabilities.config?.containsKey("call") == true && spreedCapabilities.config!!["call"] != null && spreedCapabilities.config!!["call"]!!.containsKey("enabled") @@ -176,7 +170,6 @@ object CapabilitiesUtil { // older nextcloud versions without the capability can't disable the calls true } - } fun isCallReactionsSupported(user: User?): Boolean { if (user?.capabilities != null) { @@ -188,12 +181,11 @@ object CapabilitiesUtil { return false } - fun isTranslationsSupported(spreedCapabilities: SpreedCapability): Boolean { - return spreedCapabilities.config?.containsKey("chat") == true && + fun isTranslationsSupported(spreedCapabilities: SpreedCapability): Boolean = + spreedCapabilities.config?.containsKey("chat") == true && spreedCapabilities.config!!["chat"] != null && spreedCapabilities.config!!["chat"]!!.containsKey("has-translation-providers") && spreedCapabilities.config!!["chat"]!!["has-translation-providers"] == true - } fun getRecordingConsentType(spreedCapabilities: SpreedCapability): Int { if ( @@ -213,9 +205,8 @@ object CapabilitiesUtil { return RECORDING_CONSENT_NOT_REQUIRED } - fun isBanningAvailable(spreedCapabilities: SpreedCapability): Boolean { - return hasSpreedFeatureCapability(spreedCapabilities, SpreedFeatures.BAN_V1) - } + fun isBanningAvailable(spreedCapabilities: SpreedCapability): Boolean = + hasSpreedFeatureCapability(spreedCapabilities, SpreedFeatures.BAN_V1) // endregion @@ -249,16 +240,11 @@ object CapabilitiesUtil { return false } - fun isFederationAvailable(user: User): Boolean { - return hasSpreedFeatureCapability(user.capabilities!!.spreedCapability!!, SpreedFeatures.FEDERATION_V1) && + fun isFederationAvailable(user: User): Boolean = + hasSpreedFeatureCapability(user.capabilities!!.spreedCapability!!, SpreedFeatures.FEDERATION_V1) && user.capabilities!!.spreedCapability!!.config?.containsKey("federation") == true && user.capabilities!!.spreedCapability!!.config!!["federation"] != null && user.capabilities!!.spreedCapability!!.config!!["federation"]!!.containsKey("enabled") - } - - fun isArchiveConversationsAvailable(spreedCapabilities: SpreedCapability): Boolean { - return hasSpreedFeatureCapability(spreedCapabilities, SpreedFeatures.ARCHIVE_CONVERSATIONS) - } // endregion @@ -275,20 +261,18 @@ object CapabilitiesUtil { //region ProvisioningCapabilities - fun canEditScopes(user: User): Boolean { - return user.capabilities?.provisioningCapability?.accountPropertyScopesVersion != null && + fun canEditScopes(user: User): Boolean = + user.capabilities?.provisioningCapability?.accountPropertyScopesVersion != null && user.capabilities!!.provisioningCapability!!.accountPropertyScopesVersion!! > 1 - } // endregion //region UserStatusCapabilities @JvmStatic - fun isUserStatusAvailable(user: User): Boolean { - return user.capabilities?.userStatusCapability?.enabled == true && + fun isUserStatusAvailable(user: User): Boolean = + user.capabilities?.userStatusCapability?.enabled == true && user.capabilities?.userStatusCapability?.supportsEmoji == true - } // endregion From 2a2f8a8148c34534353f8b1274b29eca2f845c14 Mon Sep 17 00:00:00 2001 From: Marcel Hibbe Date: Fri, 8 Nov 2024 14:46:56 +0100 Subject: [PATCH 320/885] hide archivedFilterChip when capability is not available Otherwise it would be shown for older NC versions without to be useful Signed-off-by: Marcel Hibbe --- .../talk/ui/dialog/FilterConversationFragment.kt | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) 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 6eb3c17195..852a32bb6a 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 @@ -22,6 +22,8 @@ import com.nextcloud.talk.conversationlist.ConversationsListActivity import com.nextcloud.talk.databinding.DialogFilterConversationBinding import com.nextcloud.talk.ui.theme.ViewThemeUtils import com.nextcloud.talk.users.UserManager +import com.nextcloud.talk.utils.CapabilitiesUtil.hasSpreedFeatureCapability +import com.nextcloud.talk.utils.SpreedFeatures import com.nextcloud.talk.utils.UserIdUtils import javax.inject.Inject @@ -104,7 +106,14 @@ class FilterConversationFragment : DialogFragment() { private fun setUpChips() { binding.unreadFilterChip.isChecked = filterState[UNREAD]!! binding.mentionedFilterChip.isChecked = filterState[MENTION]!! - binding.archivedFilterChip.isChecked = filterState[ARCHIVE]!! + + binding.archivedFilterChip.visibility = View.GONE + userManager.currentUser.blockingGet().capabilities?.spreedCapability?.let { + if (hasSpreedFeatureCapability(it, SpreedFeatures.ARCHIVE_CONVERSATIONS)) { + binding.archivedFilterChip.visibility = View.VISIBLE + binding.archivedFilterChip.isChecked = filterState[ARCHIVE]!! + } + } } private fun processSubmit() { From 1968d4369137a10e4ad0d95a2458bdb88510d503 Mon Sep 17 00:00:00 2001 From: Marcel Hibbe Date: Mon, 11 Nov 2024 15:43:27 +0100 Subject: [PATCH 321/885] require archived-conversations-v2 For archived conversations, require "-v2". This is done because on server api, "archived-conversations" was already released for 20.0.2 by mistake which should have only be done for 20.1 As it's planned to release android talk 20.0.3 with a fresh master state, the archived conversations feature must be hidden manually, This is done by required "-v2". Either it's served as this in the future or it can be removed for the 20.1.0 release. Signed-off-by: Marcel Hibbe --- app/src/main/java/com/nextcloud/talk/utils/CapabilitiesUtil.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/src/main/java/com/nextcloud/talk/utils/CapabilitiesUtil.kt b/app/src/main/java/com/nextcloud/talk/utils/CapabilitiesUtil.kt index 54bb10e2fc..1b9d672968 100644 --- a/app/src/main/java/com/nextcloud/talk/utils/CapabilitiesUtil.kt +++ b/app/src/main/java/com/nextcloud/talk/utils/CapabilitiesUtil.kt @@ -56,7 +56,7 @@ enum class SpreedFeatures(val value: String) { DELETE_MESSAGES_UNLIMITED("delete-messages-unlimited"), BAN_V1("ban-v1"), EDIT_MESSAGES_NOTE_TO_SELF("edit-messages-note-to-self"), - ARCHIVE_CONVERSATIONS("archived-conversations") + ARCHIVE_CONVERSATIONS("archived-conversations-v2") } @Suppress("TooManyFunctions") From 1396653c5d3adad5ae675ebefa2c986d5a631783 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Mon, 11 Nov 2024 15:06:47 +0000 Subject: [PATCH 322/885] chore(deps): update dependency gradle to v8.11 Signed-off-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- gradle/verification-metadata.xml | 5 +++++ gradle/wrapper/gradle-wrapper.properties | 2 +- 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/gradle/verification-metadata.xml b/gradle/verification-metadata.xml index bcd62fbb3e..abb6bb49f7 100644 --- a/gradle/verification-metadata.xml +++ b/gradle/verification-metadata.xml @@ -6384,6 +6384,11 @@ + + + + + diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties index df97d72b8b..94113f200e 100644 --- a/gradle/wrapper/gradle-wrapper.properties +++ b/gradle/wrapper/gradle-wrapper.properties @@ -1,6 +1,6 @@ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-8.10.2-bin.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-8.11-bin.zip networkTimeout=10000 validateDistributionUrl=true zipStoreBase=GRADLE_USER_HOME From edd6a015640fd9735762b17ccfc102a7f67d3f9b Mon Sep 17 00:00:00 2001 From: Nextcloud bot Date: Tue, 12 Nov 2024 03:00:50 +0000 Subject: [PATCH 323/885] Fix(l10n): Update translations from Transifex Signed-off-by: Nextcloud bot --- app/src/main/res/values-ca/strings.xml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/app/src/main/res/values-ca/strings.xml b/app/src/main/res/values-ca/strings.xml index 1e39de8389..9f7ba9f3ee 100644 --- a/app/src/main/res/values-ca/strings.xml +++ b/app/src/main/res/values-ca/strings.xml @@ -4,6 +4,8 @@ Afegeix-ho a les notes S\'ha afegit la conversa %1$s als preferits Cerca a %s + Arxiva la conversa + Un cop arxivada una conversa, s\'ocultarà per defecte. Seleccioneu el filtre \"Arxivada\" per a veure les converses arxivades. Es continuaran rebent les mencions directes. Arxivat Trucada d\'àudio Bluetooth @@ -272,6 +274,7 @@ Les notificacions d\'aquesta conversa anul·laran els paràmetres de no destorbar. Invitacions Uneix-te a converses obertes + Heu de promocionar un nou moderador abans de deixar la conversa %1$s | Darrera modificació: %2$s Surt de la conversa S\'està abandonant la trucada… From 52fd3f90020a999a66fcfd35fd8267f8babacc2c Mon Sep 17 00:00:00 2001 From: sowjanyakch Date: Fri, 25 Oct 2024 10:02:43 +0200 Subject: [PATCH 324/885] Add support for all parameter in leave call endpoint Signed-off-by: sowjanyakch --- .../main/java/com/nextcloud/talk/activities/CallActivity.kt | 2 +- app/src/main/java/com/nextcloud/talk/api/NcApi.java | 3 ++- 2 files changed, 3 insertions(+), 2 deletions(-) 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 839d1e05d4..b795f23d21 100644 --- a/app/src/main/java/com/nextcloud/talk/activities/CallActivity.kt +++ b/app/src/main/java/com/nextcloud/talk/activities/CallActivity.kt @@ -2028,7 +2028,7 @@ class CallActivity : CallBaseActivity() { callParticipantList!!.removeObserver(callParticipantListObserver) callParticipantList!!.destroy() } - ncApi!!.leaveCall(credentials, ApiUtils.getUrlForCall(apiVersion, baseUrl, roomToken!!)) + ncApi!!.leaveCall(credentials, ApiUtils.getUrlForCall(apiVersion, baseUrl, roomToken!!), false) .subscribeOn(Schedulers.io()) .observeOn(AndroidSchedulers.mainThread()) .subscribe(object : Observer { diff --git a/app/src/main/java/com/nextcloud/talk/api/NcApi.java b/app/src/main/java/com/nextcloud/talk/api/NcApi.java index f0957ef4d3..1fb46f0ffb 100644 --- a/app/src/main/java/com/nextcloud/talk/api/NcApi.java +++ b/app/src/main/java/com/nextcloud/talk/api/NcApi.java @@ -246,7 +246,8 @@ Observable joinCall(@Nullable @Header("Authorization") String au Server URL is: baseUrl + ocsApiVersion + spreedApiVersion + /call/callToken */ @DELETE - Observable leaveCall(@Nullable @Header("Authorization") String authorization, @Url String url); + Observable leaveCall(@Nullable @Header("Authorization") String authorization, @Url String url, + @Field("all") Boolean all); @GET Observable getSignalingSettings(@Nullable @Header("Authorization") String authorization, From ed9fc185bf029c0874930d1c4391af4633988e2a Mon Sep 17 00:00:00 2001 From: sowjanyakch Date: Fri, 25 Oct 2024 13:09:50 +0200 Subject: [PATCH 325/885] implement long click and short click on hangup button Signed-off-by: sowjanyakch --- .../nextcloud/talk/activities/CallActivity.kt | 58 +++++++++++++------ .../java/com/nextcloud/talk/api/NcApi.java | 2 +- app/src/main/res/layout/call_activity.xml | 34 +++++++++-- app/src/main/res/values/strings.xml | 1 + 4 files changed, 70 insertions(+), 25 deletions(-) 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 b795f23d21..57a7166d67 100644 --- a/app/src/main/java/com/nextcloud/talk/activities/CallActivity.kt +++ b/app/src/main/java/com/nextcloud/talk/activities/CallActivity.kt @@ -263,7 +263,7 @@ class CallActivity : CallBaseActivity() { override fun onCallEndedForAll() { Log.d(TAG, "A moderator ended the call for all.") - hangup(true) + hangup(true, false) } } private var callParticipantList: CallParticipantList? = null @@ -271,7 +271,7 @@ class CallActivity : CallBaseActivity() { private var isBreakoutRoom = false private val localParticipantMessageListener = LocalParticipantMessageListener { token -> switchToRoomToken = token - hangup(true) + hangup(true,false) } private val offerMessageListener = OfferMessageListener { sessionId, roomType, sdp, nick -> getOrCreatePeerConnectionWrapperForSessionIdAndType( @@ -470,7 +470,7 @@ class CallActivity : CallBaseActivity() { binding!!.callRecordingIndicator.visibility = View.GONE } } - initClickListeners() + initClickListeners(isModerator) binding!!.microphoneButton.setOnTouchListener(MicrophoneButtonTouchListener()) pulseAnimation = PulseAnimation.create().with(binding!!.microphoneButton) .setDuration(310) @@ -498,7 +498,7 @@ class CallActivity : CallBaseActivity() { } .setNegativeButton(R.string.nc_no) { _, _ -> recordingConsentGiven = false - hangup(true) + hangup(true,false) } viewThemeUtils.dialog.colorMaterialAlertDialogBackground(this, materialAlertDialogBuilder) @@ -613,7 +613,8 @@ class CallActivity : CallBaseActivity() { } } - private fun initClickListeners() { + @SuppressLint("ClickableViewAccessibility") + private fun initClickListeners(isModerator:Boolean) { binding!!.pictureInPictureButton.setOnClickListener { enterPipMode() } binding!!.audioOutputButton.setOnClickListener { @@ -663,7 +664,22 @@ class CallActivity : CallBaseActivity() { ).show() } } - binding!!.hangupButton.setOnClickListener { hangup(true) } + + binding!!.hangupButton.setOnClickListener { + hangup(true, false) + } + + if (isModerator) { + binding!!. hangupButton.setOnLongClickListener { + showPopupMenu() + true + } + } + + binding!!.popupMenu.setOnClickListener { + hangup(true, true) + binding!!.popupMenu.visibility = View.GONE + } binding!!.switchSelfVideoButton.setOnClickListener { switchCamera() } binding!!.gridview.onItemClickListener = AdapterView.OnItemClickListener { _: AdapterView<*>?, _: View?, _: Int, _: Long -> @@ -675,7 +691,7 @@ class CallActivity : CallBaseActivity() { binding!!.callStates.callStateRelativeLayout.setOnClickListener { if (currentCallStatus === CallStatus.CALLING_TIMEOUT) { setCallState(CallStatus.RECONNECTING) - hangupNetworkCalls(false) + hangupNetworkCalls(false, false) } } binding!!.callRecordingIndicator.setOnClickListener { @@ -699,6 +715,11 @@ class CallActivity : CallBaseActivity() { binding!!.lowerHandButton.setOnClickListener { l: View? -> raiseHandViewModel!!.lowerHand() } } + private fun showPopupMenu() { + binding!!.popupMenu.visibility = View.VISIBLE + + } + private fun createCameraEnumerator() { var camera2EnumeratorIsSupported = false try { @@ -1442,7 +1463,7 @@ class CallActivity : CallBaseActivity() { Log.d(TAG, "localStream is null") } if (currentCallStatus !== CallStatus.LEAVING) { - hangup(true) + hangup(true, false) } powerManagerUtils!!.updatePhoneState(PowerManagerUtils.PhoneState.IDLE) super.onDestroy() @@ -1726,7 +1747,7 @@ class CallActivity : CallBaseActivity() { override fun onError(e: Throwable) { Log.e(TAG, "Failed to join call", e) Snackbar.make(binding!!.root, R.string.nc_common_error_sorry, Snackbar.LENGTH_LONG).show() - hangup(true) + hangup(true, false) } override fun onComplete() { @@ -1877,7 +1898,7 @@ class CallActivity : CallBaseActivity() { Log.d(TAG, "onMessageEvent 'hello'") if (!webSocketCommunicationEvent.getHashMap()!!.containsKey("oldResumeId")) { if (currentCallStatus === CallStatus.RECONNECTING) { - hangup(false) + hangup(false, false) } else { setCallState(CallStatus.RECONNECTING) runOnUiThread { initiateCall() } @@ -1953,7 +1974,7 @@ class CallActivity : CallBaseActivity() { } } - private fun hangup(shutDownView: Boolean) { + private fun hangup(shutDownView: Boolean, endCallForAll:Boolean) { Log.d(TAG, "hangup! shutDownView=$shutDownView") if (shutDownView) { setCallState(CallStatus.LEAVING) @@ -2018,17 +2039,18 @@ class CallActivity : CallBaseActivity() { ApplicationWideCurrentRoomHolder.getInstance().isInCall = false ApplicationWideCurrentRoomHolder.getInstance().isDialing = false - hangupNetworkCalls(shutDownView) + hangupNetworkCalls(shutDownView,endCallForAll) } - private fun hangupNetworkCalls(shutDownView: Boolean) { + private fun hangupNetworkCalls(shutDownView: Boolean, endCallForAll: Boolean) { Log.d(TAG, "hangupNetworkCalls. shutDownView=$shutDownView") val apiVersion = ApiUtils.getCallApiVersion(conversationUser, intArrayOf(ApiUtils.API_V4, 1)) if (callParticipantList != null) { callParticipantList!!.removeObserver(callParticipantListObserver) callParticipantList!!.destroy() } - ncApi!!.leaveCall(credentials, ApiUtils.getUrlForCall(apiVersion, baseUrl, roomToken!!), false) + + ncApi!!.leaveCall(credentials, ApiUtils.getUrlForCall(apiVersion, baseUrl, roomToken!!),endCallForAll) .subscribeOn(Schedulers.io()) .observeOn(AndroidSchedulers.mainThread()) .subscribe(object : Observer { @@ -2122,7 +2144,7 @@ class CallActivity : CallBaseActivity() { ApplicationWideCurrentRoomHolder.getInstance().isInCall ) { Log.d(TAG, "Most probably a moderator ended the call for all.") - hangup(true) + hangup(true, false) return } @@ -2249,7 +2271,7 @@ class CallActivity : CallBaseActivity() { context.resources.getString(R.string.nc_common_error_sorry), Snackbar.LENGTH_LONG ).show() - hangup(true) + hangup(true,false) return null } peerConnectionWrapper = if (hasMCU && publisher) { @@ -2565,7 +2587,7 @@ class CallActivity : CallBaseActivity() { } CallStatus.CALLING_TIMEOUT -> handler!!.post { - hangup(false) + hangup(false, false) binding!!.callStates.callStateTextView.setText(R.string.nc_call_timeout) binding!!.callModeTextView.text = descriptionForCallType if (binding!!.callStates.callStateRelativeLayout.visibility != View.VISIBLE) { @@ -2835,7 +2857,7 @@ class CallActivity : CallBaseActivity() { if (iceConnectionState == IceConnectionState.FAILED) { setCallState(CallStatus.PUBLISHER_FAILED) webSocketClient!!.clearResumeId() - hangup(false) + hangup(false, false) } } } diff --git a/app/src/main/java/com/nextcloud/talk/api/NcApi.java b/app/src/main/java/com/nextcloud/talk/api/NcApi.java index 1fb46f0ffb..07e150bc7f 100644 --- a/app/src/main/java/com/nextcloud/talk/api/NcApi.java +++ b/app/src/main/java/com/nextcloud/talk/api/NcApi.java @@ -247,7 +247,7 @@ Observable joinCall(@Nullable @Header("Authorization") String au */ @DELETE Observable leaveCall(@Nullable @Header("Authorization") String authorization, @Url String url, - @Field("all") Boolean all); + @Query("all") Boolean all); @GET Observable getSignalingSettings(@Nullable @Header("Authorization") String authorization, diff --git a/app/src/main/res/layout/call_activity.xml b/app/src/main/res/layout/call_activity.xml index 8a08edcbb2..1000915654 100644 --- a/app/src/main/res/layout/call_activity.xml +++ b/app/src/main/res/layout/call_activity.xml @@ -94,7 +94,8 @@ android:src="@drawable/record_stop" android:translationZ="2dp" android:visibility="gone" - tools:visibility="visible"> + tools:visibility="visible"> + + + + +