From 356462d6ab3955fd3bd3c23c9caeedba3b0aa5ec Mon Sep 17 00:00:00 2001 From: Fr4nzD13trich Date: Sat, 4 Oct 2025 10:41:35 +0200 Subject: [PATCH] updated to 22.0.0 --- README.md | 6 +- app/build.gradle | 22 +- .../talk/account/WebViewLoginActivity.kt | 2 +- .../BrowserLoginActivityViewModel.kt | 2 +- .../com/nextcloud/talk/api/NcApiCoroutines.kt | 3 +- .../com/nextcloud/talk/chat/ChatActivity.kt | 44 +-- .../talk/chat/data/ChatMessageRepository.kt | 2 +- .../data/network/ChatNetworkDataSource.kt | 3 +- .../chat/data/network/RetrofitChatNetwork.kt | 5 +- .../talk/chat/viewmodels/ChatViewModel.kt | 19 -- .../talk/contacts/ContactsApplication.kt | 2 +- .../talk/contextchat/ContextChatView.kt | 240 ++++++++++++++++ .../talk/contextchat/ContextChatViewModel.kt | 109 ++++++++ .../ConversationsListActivity.kt | 26 +- .../talk/dagger/modules/RestModule.java | 10 - .../talk/dagger/modules/ViewModelModule.kt | 6 + .../nextcloud/talk/jobs/NotificationWorker.kt | 9 + .../messagesearch/MessageSearchActivity.kt | 2 + .../messagesearch/MessageSearchViewModel.kt | 4 +- .../talk/models/domain/SearchMessageEntry.kt | 1 + .../json/conversations/ConversationEnums.kt | 2 +- .../UnifiedSearchRepositoryImpl.kt | 15 +- .../talk/ui/BackgroundVoiceMessageCard.kt | 2 +- .../nextcloud/talk/ui/ComposeChatAdapter.kt | 249 +++++++++++++---- .../talk/ui/dialog/ContextChatCompose.kt | 262 ------------------ .../nextcloud/talk/utils/bundle/BundleKeys.kt | 1 + .../res/drawable/baseline_tag_faces_24.xml | 7 +- .../res/layout/activity_conversations.xml | 2 +- app/src/main/res/values-b+en+001/strings.xml | 3 +- app/src/main/res/values-be/strings.xml | 68 ++++- app/src/main/res/values-cs-rCZ/strings.xml | 9 +- app/src/main/res/values-da/strings.xml | 70 ++++- app/src/main/res/values-de/strings.xml | 2 +- app/src/main/res/values-el/strings.xml | 60 ++++ app/src/main/res/values-es/strings.xml | 2 +- app/src/main/res/values-et-rEE/strings.xml | 2 +- app/src/main/res/values-eu/strings.xml | 1 + app/src/main/res/values-fr/strings.xml | 2 +- app/src/main/res/values-ga/strings.xml | 2 +- app/src/main/res/values-gl/strings.xml | 16 +- app/src/main/res/values-hu-rHU/strings.xml | 30 +- app/src/main/res/values-it/strings.xml | 248 ++++++++++++++++- app/src/main/res/values-ja-rJP/strings.xml | 10 + app/src/main/res/values-pl/strings.xml | 2 +- app/src/main/res/values-pt-rBR/strings.xml | 3 +- app/src/main/res/values-ru/strings.xml | 2 +- app/src/main/res/values-sr/strings.xml | 2 +- app/src/main/res/values-sv/strings.xml | 5 +- app/src/main/res/values-sw/strings.xml | 2 +- app/src/main/res/values-tr/strings.xml | 2 +- app/src/main/res/values-uk/strings.xml | 2 +- app/src/main/res/values-zh-rCN/strings.xml | 6 +- app/src/main/res/values-zh-rHK/strings.xml | 2 +- app/src/main/res/values-zh-rTW/strings.xml | 2 +- app/src/main/res/values/strings.xml | 2 +- .../messagesearch/MessageSearchHelperTest.kt | 5 +- gradle/verification-metadata.xml | 40 +++ gradle/wrapper/gradle-wrapper.properties | 2 +- gradlew | 3 - gradlew.bat | 3 +- 60 files changed, 1198 insertions(+), 469 deletions(-) create mode 100644 app/src/main/java/com/nextcloud/talk/contextchat/ContextChatView.kt create mode 100644 app/src/main/java/com/nextcloud/talk/contextchat/ContextChatViewModel.kt delete mode 100644 app/src/main/java/com/nextcloud/talk/ui/dialog/ContextChatCompose.kt diff --git a/README.md b/README.md index 8bd80b0..de33ccb 100644 --- a/README.md +++ b/README.md @@ -12,6 +12,10 @@ [Get it on F-Droid](https://f-droid.org/packages/com.nextcloud.talk2/) + [Get it with Obtainium](https://apps.obtainium.imranr.dev/redirect?r=obtainium://app/%7B%22id%22%3A%22com.nextcloud.talk2%22%2C%22url%22%3A%22https%3A%2F%2Fgithub.com%2Fnextcloud%2Ftalk-android%22%2C%22author%22%3A%22nextcloud%22%2C%22name%22%3A%22Talk%22%2C%22preferredApkIndex%22%3A0%2C%22additionalSettings%22%3A%22%7B%5C%22includePrereleases%5C%22%3Afalse%2C%5C%22fallbackToOlderReleases%5C%22%3Atrue%2C%5C%22filterReleaseTitlesByRegEx%5C%22%3A%5C%22%5C%22%2C%5C%22filterReleaseNotesByRegEx%5C%22%3A%5C%22%5C%22%2C%5C%22verifyLatestTag%5C%22%3Atrue%2C%5C%22sortMethodChoice%5C%22%3A%5C%22date%5C%22%2C%5C%22useLatestAssetDateAsReleaseDate%5C%22%3Afalse%2C%5C%22releaseTitleAsVersion%5C%22%3Afalse%2C%5C%22trackOnly%5C%22%3Afalse%2C%5C%22versionExtractionRegEx%5C%22%3A%5C%22%5C%22%2C%5C%22matchGroupToUse%5C%22%3A%5C%22%5C%22%2C%5C%22versionDetection%5C%22%3Atrue%2C%5C%22releaseDateAsVersion%5C%22%3Afalse%2C%5C%22useVersionCodeAsOSVersion%5C%22%3Afalse%2C%5C%22apkFilterRegEx%5C%22%3A%5C%22%5Enextcloud.*%5C%22%2C%5C%22invertAPKFilter%5C%22%3Afalse%2C%5C%22autoApkFilterByArch%5C%22%3Atrue%2C%5C%22appName%5C%22%3A%5C%22Nextcloud%20Talk%5C%22%2C%5C%22appAuthor%5C%22%3A%5C%22%5C%22%2C%5C%22shizukuPretendToBeGooglePlay%5C%22%3Afalse%2C%5C%22allowInsecure%5C%22%3Afalse%2C%5C%22exemptFromBackgroundUpdates%5C%22%3Afalse%2C%5C%22skipUpdateNotifications%5C%22%3Afalse%2C%5C%22about%5C%22%3A%5C%22%5C%22%2C%5C%22refreshBeforeDownload%5C%22%3Atrue%7D%22%2C%22overrideSource%22%3Anull%7D) + Please note that Notifications won't work with the F-Droid version due to missing Google Play Services. @@ -112,4 +116,4 @@ If you have problems to receive talk notifications on your android phone, please ## Remarks :scroll: -Google Play and the Google Play logo are trademarks of Google Inc. \ No newline at end of file +Google Play and the Google Play logo are trademarks of Google Inc. diff --git a/app/build.gradle b/app/build.gradle index 90e1578..c510cbb 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -39,8 +39,8 @@ android { // mayor.minor.hotfix.increment (for increment: 01-50=Alpha / 51-89=RC / 90-99=stable) // xx .xxx .xx .xx - versionCode 230000005 - versionName "23.0.0 Alpha 05" + versionCode 230000009 + versionName "23.0.0 Alpha 09" flavorDimensions "default" renderscriptTargetApi = 19 @@ -158,7 +158,7 @@ kapt { ext { androidxCameraVersion = "1.5.0" coilKtVersion = "2.7.0" - daggerVersion = "2.57.1" + daggerVersion = "2.57.2" emojiVersion = "1.6.0" fidoVersion = "4.1.0-patch2" lifecycleVersion = '2.9.4' @@ -169,7 +169,7 @@ ext { prismVersion = "2.0.0" retrofit2Version = "3.0.0" roomVersion = "2.8.0" - workVersion = "2.10.4" + workVersion = "2.10.5" espressoVersion = "3.7.0" androidxTestVersion = "1.5.0" media3_version = "1.8.0" @@ -186,12 +186,12 @@ configurations.configureEach { dependencies { implementation "androidx.room:room-testing-android:${roomVersion}" - implementation 'androidx.compose.foundation:foundation-layout:1.9.1' + implementation 'androidx.compose.foundation:foundation-layout:1.9.2' spotbugsPlugins 'com.h3xstream.findsecbugs:findsecbugs-plugin:1.14.0' spotbugsPlugins 'com.mebigfatguy.fb-contrib:fb-contrib:7.6.14' detektPlugins("io.gitlab.arturbosch.detekt:detekt-formatting:1.23.8") - implementation("androidx.compose.runtime:runtime:1.9.1") + implementation("androidx.compose.runtime:runtime:1.9.2") implementation 'androidx.preference:preference-ktx:1.2.1' implementation 'androidx.datastore:datastore-core:1.1.7' implementation 'androidx.datastore:datastore-preferences:1.1.7' @@ -316,7 +316,7 @@ dependencies { implementation 'com.github.nextcloud-deps:android-talk-webrtc:132.6834.0' gplayImplementation 'com.google.android.gms:play-services-base:18.8.0' - gplayImplementation "com.google.firebase:firebase-messaging:25.0.0" + gplayImplementation "com.google.firebase:firebase-messaging:25.0.1" //compose implementation(platform("androidx.compose:compose-bom:2025.09.00")) @@ -328,18 +328,18 @@ dependencies { //tests testRuntimeOnly 'org.junit.platform:junit-platform-launcher:1.13.4' - androidTestImplementation("androidx.compose.ui:ui-test-junit4:1.9.1") + androidTestImplementation("androidx.compose.ui:ui-test-junit4:1.9.2") debugImplementation("androidx.compose.ui:ui-test-manifest") testImplementation 'junit:junit:4.13.2' - testImplementation 'org.mockito:mockito-core:5.19.0' + testImplementation 'org.mockito:mockito-core:5.20.0' testImplementation 'androidx.arch.core:core-testing:2.2.0' androidTestImplementation "androidx.test:core:1.7.0" androidTestImplementation "org.jetbrains.kotlinx:kotlinx-coroutines-test:1.10.2" androidTestImplementation 'androidx.test:core-ktx:1.7.0' - androidTestImplementation 'org.mockito:mockito-android:5.19.0' + androidTestImplementation 'org.mockito:mockito-android:5.20.0' androidTestImplementation "androidx.work:work-testing:${workVersion}" // Espresso core androidTestImplementation ("androidx.test.espresso:espresso-core:$espressoVersion", { @@ -360,7 +360,7 @@ dependencies { testImplementation 'org.junit.vintage:junit-vintage-engine:5.13.4' // DO NOT REMOVE testImplementation "androidx.room:room-testing:${roomVersion}" testImplementation("com.squareup.okhttp3:mockwebserver:$okhttpVersion") - testImplementation("com.google.dagger:hilt-android-testing:2.57.1") + testImplementation("com.google.dagger:hilt-android-testing:2.57.2") testImplementation("org.robolectric:robolectric:4.16") } diff --git a/app/src/main/java/com/nextcloud/talk/account/WebViewLoginActivity.kt b/app/src/main/java/com/nextcloud/talk/account/WebViewLoginActivity.kt index 0d52529..e2fcb5a 100644 --- a/app/src/main/java/com/nextcloud/talk/account/WebViewLoginActivity.kt +++ b/app/src/main/java/com/nextcloud/talk/account/WebViewLoginActivity.kt @@ -1,7 +1,7 @@ /* * Nextcloud Talk - Android Client * - * SPDX-FileCopyrightText: 2025 Your Name + * SPDX-FileCopyrightText: 2025 Julius Linus * SPDX-License-Identifier: GPL-3.0-or-later */ package com.nextcloud.talk.account diff --git a/app/src/main/java/com/nextcloud/talk/account/viewmodels/BrowserLoginActivityViewModel.kt b/app/src/main/java/com/nextcloud/talk/account/viewmodels/BrowserLoginActivityViewModel.kt index b76b27c..e9560c5 100644 --- a/app/src/main/java/com/nextcloud/talk/account/viewmodels/BrowserLoginActivityViewModel.kt +++ b/app/src/main/java/com/nextcloud/talk/account/viewmodels/BrowserLoginActivityViewModel.kt @@ -1,7 +1,7 @@ /* * Nextcloud Talk - Android Client * - * SPDX-FileCopyrightText: 2025 Your Name + * SPDX-FileCopyrightText: 2025 Julius Linus * SPDX-License-Identifier: GPL-3.0-or-later */ 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 4211aa2..a0cf017 100644 --- a/app/src/main/java/com/nextcloud/talk/api/NcApiCoroutines.kt +++ b/app/src/main/java/com/nextcloud/talk/api/NcApiCoroutines.kt @@ -277,7 +277,8 @@ interface NcApiCoroutines { suspend fun getContextOfChatMessage( @Header("Authorization") authorization: String, @Url url: String, - @Query("limit") limit: Int + @Query("limit") limit: Int, + @Query("threadId") threadId: Int? ): ChatOverall @GET 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 6477727..aecdd39 100644 --- a/app/src/main/java/com/nextcloud/talk/chat/ChatActivity.kt +++ b/app/src/main/java/com/nextcloud/talk/chat/ChatActivity.kt @@ -65,6 +65,7 @@ import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.setValue import androidx.compose.ui.platform.ComposeView import androidx.coordinatorlayout.widget.CoordinatorLayout +import androidx.core.content.ContextCompat import androidx.core.content.FileProvider import androidx.core.content.PermissionChecker import androidx.core.content.PermissionChecker.PERMISSION_GRANTED @@ -134,6 +135,8 @@ import com.nextcloud.talk.application.NextcloudTalkApplication import com.nextcloud.talk.chat.data.model.ChatMessage import com.nextcloud.talk.chat.viewmodels.ChatViewModel import com.nextcloud.talk.chat.viewmodels.MessageInputViewModel +import com.nextcloud.talk.contextchat.ContextChatView +import com.nextcloud.talk.contextchat.ContextChatViewModel import com.nextcloud.talk.conversationinfo.ConversationInfoActivity import com.nextcloud.talk.conversationinfo.viewmodel.ConversationInfoViewModel import com.nextcloud.talk.conversationlist.ConversationsListActivity @@ -168,7 +171,6 @@ import com.nextcloud.talk.ui.PlaybackSpeed import com.nextcloud.talk.ui.PlaybackSpeedControl import com.nextcloud.talk.ui.StatusDrawable import com.nextcloud.talk.ui.bottom.sheet.ProfileBottomSheet -import com.nextcloud.talk.ui.dialog.ContextChatCompose import com.nextcloud.talk.ui.dialog.DateTimeCompose import com.nextcloud.talk.ui.dialog.FileAttachmentPreviewFragment import com.nextcloud.talk.ui.dialog.MessageActionsDialog @@ -203,6 +205,7 @@ import com.nextcloud.talk.utils.bundle.BundleKeys.KEY_FILE_PATHS import com.nextcloud.talk.utils.bundle.BundleKeys.KEY_INTERNAL_USER_ID import com.nextcloud.talk.utils.bundle.BundleKeys.KEY_IS_BREAKOUT_ROOM import com.nextcloud.talk.utils.bundle.BundleKeys.KEY_IS_MODERATOR +import com.nextcloud.talk.utils.bundle.BundleKeys.KEY_OPENED_VIA_NOTIFICATION import com.nextcloud.talk.utils.bundle.BundleKeys.KEY_RECORDING_STATE import com.nextcloud.talk.utils.bundle.BundleKeys.KEY_ROOM_TOKEN import com.nextcloud.talk.utils.bundle.BundleKeys.KEY_START_CALL_AFTER_ROOM_SWITCH @@ -246,7 +249,6 @@ import java.util.Locale import java.util.concurrent.ExecutionException import javax.inject.Inject import kotlin.math.roundToInt -import androidx.core.content.ContextCompat @Suppress("TooManyFunctions") @AutoInjector(NextcloudTalkApplication::class) @@ -287,6 +289,7 @@ class ChatActivity : lateinit var chatViewModel: ChatViewModel lateinit var conversationInfoViewModel: ConversationInfoViewModel + lateinit var contextChatViewModel: ContextChatViewModel lateinit var messageInputViewModel: MessageInputViewModel private var chatMenu: Menu? = null @@ -323,28 +326,27 @@ class ChatActivity : registerForActivityResult(ActivityResultContracts.StartActivityForResult()) { executeIfResultOk(it) { intent -> runBlocking { - val id = intent?.getStringExtra(MessageSearchActivity.RESULT_KEY_MESSAGE_ID) - id?.let { - startContextChatWindowForMessage(id) + val messageId = intent?.getStringExtra(MessageSearchActivity.RESULT_KEY_MESSAGE_ID) + val threadId = intent?.getStringExtra(MessageSearchActivity.RESULT_KEY_THREAD_ID) + messageId?.let { + startContextChatWindowForMessage(messageId, threadId) } } } } - private fun startContextChatWindowForMessage(id: String?) { + private fun startContextChatWindowForMessage(messageId: String?, threadId: String?) { binding.genericComposeView.apply { - val shouldDismiss = mutableStateOf(false) setContent { - val bundle = bundleOf() - bundle.putString(BundleKeys.KEY_CREDENTIALS, credentials!!) - bundle.putString(BundleKeys.KEY_BASE_URL, conversationUser!!.baseUrl) - bundle.putString(KEY_ROOM_TOKEN, roomToken) - bundle.putString(BundleKeys.KEY_MESSAGE_ID, id) - bundle.putString( - KEY_CONVERSATION_NAME, - currentConversation!!.displayName + contextChatViewModel.getContextForChatMessages( + credentials = credentials!!, + baseUrl = conversationUser!!.baseUrl!!, + token = roomToken, + threadId = threadId, + messageId = messageId!!, + title = currentConversation!!.displayName ) - ContextChatCompose(bundle).GetDialogView(shouldDismiss, context) + ContextChatView(context, contextChatViewModel) } } Log.d(TAG, "Should open something else") @@ -366,6 +368,7 @@ class ChatActivity : var sessionIdAfterRoomJoined: String? = null lateinit var roomToken: String var conversationThreadId: Long? = null + var openedViaNotification: Boolean = false var conversationThreadInfo: ThreadInfo? = null var conversationUser: User? = null lateinit var spreedCapabilities: SpreedCapability @@ -408,12 +411,11 @@ class ChatActivity : private val onBackPressedCallback = object : OnBackPressedCallback(true) { override fun handleOnBackPressed() { - if (isChatThread()) { + if (!openedViaNotification && isChatThread()) { isEnabled = false onBackPressedDispatcher.onBackPressed() } else { val intent = Intent(this@ChatActivity, ConversationsListActivity::class.java) - intent.putExtras(Bundle()) startActivity(intent) } } @@ -514,6 +516,8 @@ class ChatActivity : conversationInfoViewModel = ViewModelProvider(this, viewModelFactory)[ConversationInfoViewModel::class.java] + contextChatViewModel = ViewModelProvider(this, viewModelFactory)[ContextChatViewModel::class.java] + val urlForChatting = ApiUtils.getUrlForChat(chatApiVersion, conversationUser?.baseUrl, roomToken) val credentials = ApiUtils.getCredentials(conversationUser!!.username, conversationUser!!.token) chatViewModel.initData( @@ -592,6 +596,8 @@ class ChatActivity : null } + openedViaNotification = extras?.getBoolean(KEY_OPENED_VIA_NOTIFICATION) ?: false + sharedText = extras?.getString(BundleKeys.KEY_SHARED_TEXT).orEmpty() Log.d(TAG, " roomToken = $roomToken") @@ -4431,7 +4437,7 @@ class ChatActivity : } if (!foundMessage) { Log.d(TAG, "quoted message with id " + parentMessage.id + " was not found in adapter") - startContextChatWindowForMessage(parentMessage.id) + startContextChatWindowForMessage(parentMessage.id, conversationThreadId.toString()) } } 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 e8dadd3..2b4399f 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 @@ -1,7 +1,7 @@ /* * Nextcloud Talk - Android Client * - * SPDX-FileCopyrightText: 2024 Your Name + * SPDX-FileCopyrightText: 2025 Marcel Hibbe * SPDX-License-Identifier: GPL-3.0-or-later */ diff --git a/app/src/main/java/com/nextcloud/talk/chat/data/network/ChatNetworkDataSource.kt b/app/src/main/java/com/nextcloud/talk/chat/data/network/ChatNetworkDataSource.kt index 637cf5d..5dcdfe3 100644 --- a/app/src/main/java/com/nextcloud/talk/chat/data/network/ChatNetworkDataSource.kt +++ b/app/src/main/java/com/nextcloud/talk/chat/data/network/ChatNetworkDataSource.kt @@ -74,7 +74,8 @@ interface ChatNetworkDataSource { baseUrl: String, token: String, messageId: String, - limit: Int + limit: Int, + threadId: Int? ): List suspend fun getOpenGraph(credentials: String, baseUrl: String, extractedLinkToPreview: String): Reference? suspend fun unbindRoom(credentials: String, baseUrl: String, roomToken: String): GenericOverall diff --git a/app/src/main/java/com/nextcloud/talk/chat/data/network/RetrofitChatNetwork.kt b/app/src/main/java/com/nextcloud/talk/chat/data/network/RetrofitChatNetwork.kt index 057472f..6bb6836 100644 --- a/app/src/main/java/com/nextcloud/talk/chat/data/network/RetrofitChatNetwork.kt +++ b/app/src/main/java/com/nextcloud/talk/chat/data/network/RetrofitChatNetwork.kt @@ -198,10 +198,11 @@ class RetrofitChatNetwork(private val ncApi: NcApi, private val ncApiCoroutines: baseUrl: String, token: String, messageId: String, - limit: Int + limit: Int, + threadId: Int? ): List { val url = ApiUtils.getUrlForChatMessageContext(baseUrl, token, messageId) - return ncApiCoroutines.getContextOfChatMessage(credentials, url, limit).ocs?.data ?: listOf() + return ncApiCoroutines.getContextOfChatMessage(credentials, url, limit, threadId).ocs?.data ?: listOf() } override suspend fun getOpenGraph( 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 7b8f6dc..5d05189 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 @@ -35,7 +35,6 @@ import com.nextcloud.talk.models.domain.ConversationModel import com.nextcloud.talk.models.domain.ReactionAddedModel import com.nextcloud.talk.models.domain.ReactionDeletedModel import com.nextcloud.talk.models.json.capabilities.SpreedCapability -import com.nextcloud.talk.models.json.chat.ChatMessageJson import com.nextcloud.talk.models.json.chat.ChatOverallSingleMessage import com.nextcloud.talk.models.json.conversations.RoomOverall import com.nextcloud.talk.models.json.generic.GenericOverall @@ -171,10 +170,6 @@ class ChatViewModel @Inject constructor( val voiceMessagePlaybackSpeedPreferences: LiveData> get() = _voiceMessagePlaybackSpeedPreferences - private val _getContextChatMessages: MutableLiveData> = MutableLiveData() - val getContextChatMessages: LiveData> - get() = _getContextChatMessages - private val _threadRetrieveState = MutableStateFlow(ThreadRetrieveUiState.None) val threadRetrieveState: StateFlow = _threadRetrieveState @@ -944,20 +939,6 @@ class ChatViewModel @Inject constructor( } } - fun getContextForChatMessages(credentials: String, baseUrl: String, token: String, messageId: String, limit: Int) { - viewModelScope.launch { - val messages = chatNetworkDataSource.getContextForChatMessage( - credentials, - baseUrl, - token, - messageId, - limit - ) - - _getContextChatMessages.value = messages - } - } - fun getOpenGraph(credentials: String, baseUrl: String, urlToPreview: String) { viewModelScope.launch { _getOpenGraph.value = chatNetworkDataSource.getOpenGraph(credentials, baseUrl, urlToPreview) diff --git a/app/src/main/java/com/nextcloud/talk/contacts/ContactsApplication.kt b/app/src/main/java/com/nextcloud/talk/contacts/ContactsApplication.kt index 445f092..cc70210 100644 --- a/app/src/main/java/com/nextcloud/talk/contacts/ContactsApplication.kt +++ b/app/src/main/java/com/nextcloud/talk/contacts/ContactsApplication.kt @@ -1,7 +1,7 @@ /* * Nextcloud Talk - Android Client * - * SPDX-FileCopyrightText: 2024 Your Name + * SPDX-FileCopyrightText: 2024 Sowjanya Kota * SPDX-License-Identifier: GPL-3.0-or-later */ diff --git a/app/src/main/java/com/nextcloud/talk/contextchat/ContextChatView.kt b/app/src/main/java/com/nextcloud/talk/contextchat/ContextChatView.kt new file mode 100644 index 0000000..5fb014e --- /dev/null +++ b/app/src/main/java/com/nextcloud/talk/contextchat/ContextChatView.kt @@ -0,0 +1,240 @@ +/* + * Nextcloud Talk - Android Client + * + * SPDX-FileCopyrightText: 2025 Julius Linus + * SPDX-FileCopyrightText: 2025 Marcel Hibbe + * SPDX-License-Identifier: GPL-3.0-or-later + */ + +package com.nextcloud.talk.contextchat + +import android.content.Context +import androidx.compose.foundation.background +import androidx.compose.foundation.layout.Arrangement +import androidx.compose.foundation.layout.Box +import androidx.compose.foundation.layout.Column +import androidx.compose.foundation.layout.Row +import androidx.compose.foundation.layout.fillMaxHeight +import androidx.compose.foundation.layout.fillMaxSize +import androidx.compose.foundation.layout.fillMaxWidth +import androidx.compose.foundation.layout.padding +import androidx.compose.foundation.layout.size +import androidx.compose.foundation.layout.wrapContentSize +import androidx.compose.material.icons.Icons +import androidx.compose.material.icons.filled.Close +import androidx.compose.material.icons.filled.Info +import androidx.compose.material.icons.filled.MoreVert +import androidx.compose.material3.DropdownMenu +import androidx.compose.material3.DropdownMenuItem +import androidx.compose.material3.HorizontalDivider +import androidx.compose.material3.Icon +import androidx.compose.material3.IconButton +import androidx.compose.material3.MaterialTheme +import androidx.compose.material3.Surface +import androidx.compose.material3.Text +import androidx.compose.runtime.Composable +import androidx.compose.runtime.SideEffect +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 +import androidx.compose.ui.platform.LocalContext +import androidx.compose.ui.res.stringResource +import androidx.compose.ui.unit.dp +import androidx.compose.ui.unit.sp +import androidx.compose.ui.window.Dialog +import androidx.compose.ui.window.DialogProperties +import com.nextcloud.talk.R +import com.nextcloud.talk.data.database.mappers.asModel +import com.nextcloud.talk.models.json.chat.ChatMessageJson +import com.nextcloud.talk.ui.ComposeChatAdapter +import com.nextcloud.talk.utils.preview.ComposePreviewUtils + +@Composable +fun ContextChatView(context: Context, contextViewModel: ContextChatViewModel) { + val contextChatMessagesState = contextViewModel.getContextChatMessagesState.collectAsState().value + + when (contextChatMessagesState) { + ContextChatViewModel.ContextChatRetrieveUiState.None -> {} + is ContextChatViewModel.ContextChatRetrieveUiState.Success -> { + ContextChatSuccessView( + visible = true, + context = context, + contextChatRetrieveUiStateSuccess = contextChatMessagesState, + onDismiss = { + contextViewModel.clearContextChatState() + } + ) + } + + is ContextChatViewModel.ContextChatRetrieveUiState.Error -> { + ContextChatErrorView() + } + } +} + +@Composable +fun ContextChatErrorView() { + Column( + modifier = Modifier.fillMaxSize(), + horizontalAlignment = Alignment.CenterHorizontally + ) { + Icon( + Icons.Filled.Info, + contentDescription = "Info Icon" + ) + + Text( + stringResource(R.string.nc_capabilities_failed) + ) + } +} + +@Composable +fun ContextChatSuccessView( + visible: Boolean, + context: Context, + contextChatRetrieveUiStateSuccess: ContextChatViewModel.ContextChatRetrieveUiState.Success, + onDismiss: () -> Unit +) { + val previewUtils = ComposePreviewUtils.getInstance(LocalContext.current) + val colorScheme = previewUtils.viewThemeUtils.getColorScheme(context) + + if (visible) { + MaterialTheme(colorScheme) { + Dialog( + onDismissRequest = onDismiss, + properties = DialogProperties( + dismissOnBackPress = true, + dismissOnClickOutside = true, + usePlatformDefaultWidth = false + ) + ) { + Surface { + Column( + modifier = Modifier.Companion + .fillMaxWidth() + .fillMaxHeight() + .padding(top = 16.dp) + ) { + Row( + modifier = Modifier.Companion.align(Alignment.Companion.Start), + verticalAlignment = Alignment.Companion.CenterVertically + ) { + IconButton(onClick = onDismiss) { + Icon( + Icons.Filled.Close, + stringResource(R.string.close), + modifier = Modifier.Companion + .size(24.dp) + ) + } + Column(verticalArrangement = Arrangement.Center) { + Text(contextChatRetrieveUiStateSuccess.title ?: "", fontSize = 18.sp) + + if (!contextChatRetrieveUiStateSuccess.subTitle.isNullOrEmpty()) { + Text(contextChatRetrieveUiStateSuccess.subTitle, fontSize = 12.sp) + } + } + + // This code was written back then but not needed yet, but it's not deleted yet + // because it may be used soon when further migrating to Compose... + + // Spacer(modifier = Modifier.weight(1f)) + // val cInt = context.resources.getColor(R.color.high_emphasis_text, null) + // Icon( + // painterResource(R.drawable.ic_call_black_24dp), + // "", + // tint = Color(cInt), + // modifier = Modifier + // .padding() + // .padding(end = 16.dp) + // .alpha(HALF_ALPHA) + // ) + // + // Icon( + // painterResource(R.drawable.ic_baseline_videocam_24), + // "", + // tint = Color(cInt), + // modifier = Modifier + // .padding() + // .alpha(HALF_ALPHA) + // ) + // + // ComposeChatMenu(colorScheme.background, false) + } + + val messages = contextChatRetrieveUiStateSuccess.messages.map(ChatMessageJson::asModel) + val messageId = contextChatRetrieveUiStateSuccess.messageId + val threadId = contextChatRetrieveUiStateSuccess.threadId + val adapter = ComposeChatAdapter( + messagesJson = contextChatRetrieveUiStateSuccess.messages, + messageId = messageId, + threadId = threadId + ) + SideEffect { + adapter.addMessages(messages.toMutableList(), true) + } + adapter.GetView() + } + } + } + } + } +} + +// This code was written back then but not needed yet, but it's not deleted yet +// because it may be used soon when further migrating to Compose... +@Composable +private fun ComposeChatMenu(backgroundColor: Color, enabled: Boolean = true) { + var expanded by remember { mutableStateOf(false) } + + Box( + modifier = Modifier.Companion.wrapContentSize(Alignment.Companion.TopStart) + ) { + IconButton(onClick = { expanded = true }) { + Icon( + imageVector = Icons.Default.MoreVert, + contentDescription = "More options" + ) + } + + DropdownMenu( + expanded = expanded, + onDismissRequest = { expanded = false }, + modifier = Modifier.Companion.background(backgroundColor) + ) { + DropdownMenuItem( + text = { Text(stringResource(R.string.nc_search)) }, + onClick = { + expanded = false + }, + enabled = enabled + ) + + HorizontalDivider() + + DropdownMenuItem( + text = { Text(stringResource(R.string.nc_conversation_menu_conversation_info)) }, + onClick = { + expanded = false + }, + enabled = enabled + ) + + HorizontalDivider() + + DropdownMenuItem( + text = { Text(stringResource(R.string.nc_shared_items)) }, + onClick = { + expanded = false + }, + enabled = enabled + ) + } + } +} diff --git a/app/src/main/java/com/nextcloud/talk/contextchat/ContextChatViewModel.kt b/app/src/main/java/com/nextcloud/talk/contextchat/ContextChatViewModel.kt new file mode 100644 index 0000000..462725d --- /dev/null +++ b/app/src/main/java/com/nextcloud/talk/contextchat/ContextChatViewModel.kt @@ -0,0 +1,109 @@ +/* + * Nextcloud Talk - Android Client + * + * SPDX-FileCopyrightText: 2025 Marcel Hibbe + * SPDX-License-Identifier: GPL-3.0-or-later + */ + +package com.nextcloud.talk.contextchat + +import androidx.lifecycle.ViewModel +import androidx.lifecycle.viewModelScope +import autodagger.AutoInjector +import com.nextcloud.talk.application.NextcloudTalkApplication +import com.nextcloud.talk.chat.data.network.ChatNetworkDataSource +import com.nextcloud.talk.chat.viewmodels.ChatViewModel +import com.nextcloud.talk.models.json.chat.ChatMessageJson +import com.nextcloud.talk.users.UserManager +import kotlinx.coroutines.flow.MutableStateFlow +import kotlinx.coroutines.flow.StateFlow +import kotlinx.coroutines.launch +import javax.inject.Inject + +@AutoInjector(NextcloudTalkApplication::class) +class ContextChatViewModel @Inject constructor(private val chatNetworkDataSource: ChatNetworkDataSource) : + ViewModel() { + + @Inject + lateinit var chatViewModel: ChatViewModel + + @Inject + lateinit var userManager: UserManager + + var threadId: String? = null + + private val _getContextChatMessagesState = + MutableStateFlow(ContextChatRetrieveUiState.None) + val getContextChatMessagesState: StateFlow = _getContextChatMessagesState + + @Suppress("LongParameterList") + fun getContextForChatMessages( + credentials: String, + baseUrl: String, + token: String, + threadId: String?, + messageId: String, + title: String + ) { + viewModelScope.launch { + val user = userManager.currentUser.blockingGet() + + if (!user.hasSpreedFeatureCapability("chat-get-context") || + !user.hasSpreedFeatureCapability("federation-v1") + ) { + _getContextChatMessagesState.value = ContextChatRetrieveUiState.Error + } + + var messages = chatNetworkDataSource.getContextForChatMessage( + credentials = credentials, + baseUrl = baseUrl, + token = token, + messageId = messageId, + limit = LIMIT, + threadId = threadId?.toInt() + ) + + if (threadId.isNullOrEmpty()) { + messages = messages.filter { !isThreadChildMessage(it) } + } + + val subTitle = if (threadId?.isNotEmpty() == true) { + messages.firstOrNull()?.threadTitle + } else { + "" + } + + _getContextChatMessagesState.value = ContextChatRetrieveUiState.Success( + messageId = messageId, + threadId = threadId, + messages = messages, + title = title, + subTitle = subTitle + ) + } + } + + fun isThreadChildMessage(currentMessage: ChatMessageJson): Boolean = + currentMessage.hasThread && + currentMessage.threadId != currentMessage.id + + fun clearContextChatState() { + _getContextChatMessagesState.value = ContextChatRetrieveUiState.None + } + + sealed class ContextChatRetrieveUiState { + data object None : ContextChatRetrieveUiState() + data class Success( + val messageId: String, + val threadId: String?, + val messages: List, + val title: String?, + val subTitle: String? + ) : ContextChatRetrieveUiState() + data object Error : ContextChatRetrieveUiState() + } + + companion object { + private const val LIMIT = 50 + } +} 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 06324a6..b7d0c3a 100644 --- a/app/src/main/java/com/nextcloud/talk/conversationlist/ConversationsListActivity.kt +++ b/app/src/main/java/com/nextcloud/talk/conversationlist/ConversationsListActivity.kt @@ -38,14 +38,12 @@ import androidx.activity.OnBackPressedCallback import androidx.annotation.OptIn import androidx.appcompat.app.AlertDialog import androidx.appcompat.widget.SearchView -import androidx.compose.runtime.mutableStateOf import androidx.compose.ui.platform.ViewCompositionStrategy import androidx.core.content.pm.ShortcutInfoCompat import androidx.core.content.pm.ShortcutManagerCompat import androidx.core.graphics.drawable.IconCompat import androidx.core.graphics.drawable.toDrawable import androidx.core.net.toUri -import androidx.core.os.bundleOf import androidx.core.view.MenuItemCompat import androidx.core.view.isVisible import androidx.fragment.app.DialogFragment @@ -115,7 +113,8 @@ import com.nextcloud.talk.threadsoverview.ThreadsOverviewActivity import com.nextcloud.talk.ui.BackgroundVoiceMessageCard import com.nextcloud.talk.ui.dialog.ChooseAccountDialogFragment import com.nextcloud.talk.ui.dialog.ChooseAccountShareToDialogFragment -import com.nextcloud.talk.ui.dialog.ContextChatCompose +import com.nextcloud.talk.contextchat.ContextChatView +import com.nextcloud.talk.contextchat.ContextChatViewModel import com.nextcloud.talk.ui.dialog.ConversationsListBottomDialog import com.nextcloud.talk.ui.dialog.FilterConversationFragment import com.nextcloud.talk.ui.dialog.FilterConversationFragment.Companion.ARCHIVE @@ -204,6 +203,7 @@ class ConversationsListActivity : lateinit var contactsViewModel: ContactsViewModel lateinit var conversationsListViewModel: ConversationsListViewModel + lateinit var contextChatViewModel: ContextChatViewModel override val appBarLayoutType: AppBarLayoutType get() = AppBarLayoutType.SEARCH_BAR @@ -263,6 +263,7 @@ class ConversationsListActivity : currentUser = currentUserProvider.currentUser.blockingGet() conversationsListViewModel = ViewModelProvider(this, viewModelFactory)[ConversationsListViewModel::class.java] + contextChatViewModel = ViewModelProvider(this, viewModelFactory)[ContextChatViewModel::class.java] binding = ActivityConversationsBinding.inflate(layoutInflater) setupActionBar() @@ -1533,15 +1534,16 @@ class ConversationsListActivity : ).model.displayName binding.genericComposeView.apply { - val shouldDismiss = mutableStateOf(false) setContent { - val bundle = bundleOf() - bundle.putString(BundleKeys.KEY_CREDENTIALS, credentials!!) - bundle.putString(BundleKeys.KEY_BASE_URL, currentUser!!.baseUrl) - bundle.putString(KEY_ROOM_TOKEN, token) - bundle.putString(BundleKeys.KEY_MESSAGE_ID, item.messageEntry.messageId) - bundle.putString(BundleKeys.KEY_CONVERSATION_NAME, conversationName) - ContextChatCompose(bundle).GetDialogView(shouldDismiss, context) + contextChatViewModel.getContextForChatMessages( + credentials = credentials!!, + baseUrl = currentUser!!.baseUrl!!, + token = token, + threadId = item.messageEntry.threadId, + messageId = item.messageEntry.messageId!!, + title = item.messageEntry.title + ) + ContextChatView(context, contextChatViewModel) } } } @@ -2244,7 +2246,7 @@ class ConversationsListActivity : ) val bundle = Bundle() - bundle.putString(ThreadsOverviewActivity.KEY_APPBAR_TITLE, getString(R.string.followed_threads)) + bundle.putString(ThreadsOverviewActivity.KEY_APPBAR_TITLE, getString(R.string.threads)) bundle.putString(ThreadsOverviewActivity.KEY_THREADS_SOURCE_URL, threadsUrl) val threadsOverviewIntent = Intent(context, ThreadsOverviewActivity::class.java) threadsOverviewIntent.putExtras(bundle) diff --git a/app/src/main/java/com/nextcloud/talk/dagger/modules/RestModule.java b/app/src/main/java/com/nextcloud/talk/dagger/modules/RestModule.java index 8d8233a..06c2f0d 100644 --- a/app/src/main/java/com/nextcloud/talk/dagger/modules/RestModule.java +++ b/app/src/main/java/com/nextcloud/talk/dagger/modules/RestModule.java @@ -219,16 +219,6 @@ public class RestModule { httpClient.addInterceptor(new HeadersInterceptor()); - List specs = new ArrayList<>(); - if (BuildConfig.DEBUG) { - specs.add(ConnectionSpec.COMPATIBLE_TLS); - specs.add(ConnectionSpec.CLEARTEXT); - httpClient.connectionSpecs(specs); - } else { - specs.add(ConnectionSpec.COMPATIBLE_TLS); - httpClient.connectionSpecs(specs); - } - if (BuildConfig.DEBUG && !context.getResources().getBoolean(R.bool.nc_is_debug)) { HttpLoggingInterceptor loggingInterceptor = new HttpLoggingInterceptor(); loggingInterceptor.setLevel(HttpLoggingInterceptor.Level.BODY); diff --git a/app/src/main/java/com/nextcloud/talk/dagger/modules/ViewModelModule.kt b/app/src/main/java/com/nextcloud/talk/dagger/modules/ViewModelModule.kt index 7d44652..5ee1068 100644 --- a/app/src/main/java/com/nextcloud/talk/dagger/modules/ViewModelModule.kt +++ b/app/src/main/java/com/nextcloud/talk/dagger/modules/ViewModelModule.kt @@ -13,6 +13,7 @@ import com.nextcloud.talk.account.viewmodels.BrowserLoginActivityViewModel import com.nextcloud.talk.chat.viewmodels.ChatViewModel import com.nextcloud.talk.chat.viewmodels.MessageInputViewModel import com.nextcloud.talk.contacts.ContactsViewModel +import com.nextcloud.talk.contextchat.ContextChatViewModel import com.nextcloud.talk.conversationcreation.ConversationCreationViewModel import com.nextcloud.talk.conversationinfo.viewmodel.ConversationInfoViewModel import com.nextcloud.talk.conversationinfoedit.viewmodel.ConversationInfoEditViewModel @@ -166,4 +167,9 @@ abstract class ViewModelModule { @IntoMap @ViewModelKey(BrowserLoginActivityViewModel::class) abstract fun browserLoginActivityViewModel(viewModel: BrowserLoginActivityViewModel): ViewModel + + @Binds + @IntoMap + @ViewModelKey(ContextChatViewModel::class) + abstract fun contextChatViewModel(viewModel: ContextChatViewModel): ViewModel } 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 df26436..4a996cb 100644 --- a/app/src/main/java/com/nextcloud/talk/jobs/NotificationWorker.kt +++ b/app/src/main/java/com/nextcloud/talk/jobs/NotificationWorker.kt @@ -85,6 +85,8 @@ import com.nextcloud.talk.utils.bundle.BundleKeys.KEY_ROOM_ONE_TO_ONE import com.nextcloud.talk.utils.bundle.BundleKeys.KEY_ROOM_TOKEN import com.nextcloud.talk.utils.bundle.BundleKeys.KEY_SHARE_RECORDING_TO_CHAT_URL import com.nextcloud.talk.utils.bundle.BundleKeys.KEY_SYSTEM_NOTIFICATION_ID +import com.nextcloud.talk.utils.bundle.BundleKeys.KEY_THREAD_ID +import com.nextcloud.talk.utils.bundle.BundleKeys.KEY_OPENED_VIA_NOTIFICATION import com.nextcloud.talk.utils.preferences.AppPreferences import io.reactivex.Observable import io.reactivex.Observer @@ -397,6 +399,10 @@ class NotificationWorker(context: Context, workerParams: WorkerParameters) : Wor val ncNotification = notificationOverall.ocs!!.notification if (ncNotification != null) { enrichPushMessageByNcNotificationData(ncNotification) + + val threadId = parseThreadId(ncNotification.objectId) + threadId?.let { intent.putExtra(KEY_THREAD_ID, it) } + showNotification(intent, ncNotification) } } @@ -827,6 +833,8 @@ class NotificationWorker(context: Context, workerParams: WorkerParameters) : Wor } } + private fun parseThreadId(objectId: String?): Long? = objectId?.split("/")?.getOrNull(2)?.toLongOrNull() + private fun sendNotification(notificationId: Int, notification: Notification) { Log.d(TAG, "show notification with id $notificationId") if (ActivityCompat.checkSelfPermission( @@ -982,6 +990,7 @@ class NotificationWorker(context: Context, workerParams: WorkerParameters) : Wor val bundle = Bundle() bundle.putString(KEY_ROOM_TOKEN, pushMessage.id) bundle.putLong(KEY_INTERNAL_USER_ID, signatureVerification.user!!.id!!) + bundle.putBoolean(KEY_OPENED_VIA_NOTIFICATION, true) intent.putExtras(bundle) return intent } diff --git a/app/src/main/java/com/nextcloud/talk/messagesearch/MessageSearchActivity.kt b/app/src/main/java/com/nextcloud/talk/messagesearch/MessageSearchActivity.kt index bf87be3..f6c54ec 100644 --- a/app/src/main/java/com/nextcloud/talk/messagesearch/MessageSearchActivity.kt +++ b/app/src/main/java/com/nextcloud/talk/messagesearch/MessageSearchActivity.kt @@ -166,6 +166,7 @@ class MessageSearchActivity : BaseActivity() { if (state is MessageSearchViewModel.FinishedState) { val resultIntent = Intent().apply { putExtra(RESULT_KEY_MESSAGE_ID, state.selectedMessageId) + putExtra(RESULT_KEY_THREAD_ID, state.selectedThreadId) } setResult(Activity.RESULT_OK, resultIntent) finish() @@ -244,5 +245,6 @@ class MessageSearchActivity : BaseActivity() { companion object { const val RESULT_KEY_MESSAGE_ID = "MessageSearchActivity.result.message" + const val RESULT_KEY_THREAD_ID = "MessageSearchActivity.result.thread" } } diff --git a/app/src/main/java/com/nextcloud/talk/messagesearch/MessageSearchViewModel.kt b/app/src/main/java/com/nextcloud/talk/messagesearch/MessageSearchViewModel.kt index e84f035..81b64a8 100644 --- a/app/src/main/java/com/nextcloud/talk/messagesearch/MessageSearchViewModel.kt +++ b/app/src/main/java/com/nextcloud/talk/messagesearch/MessageSearchViewModel.kt @@ -42,7 +42,7 @@ class MessageSearchViewModel @Inject constructor(private val unifiedSearchReposi object EmptyState : ViewState() object ErrorState : ViewState() class LoadedState(val results: List, val hasMore: Boolean) : ViewState() - class FinishedState(val selectedMessageId: String) : ViewState() + class FinishedState(val selectedMessageId: String, val selectedThreadId: String?) : ViewState() private lateinit var messageSearchHelper: MessageSearchHelper @@ -95,7 +95,7 @@ class MessageSearchViewModel @Inject constructor(private val unifiedSearchReposi } fun selectMessage(messageEntry: SearchMessageEntry) { - _state.value = FinishedState(messageEntry.messageId!!) + _state.value = FinishedState(messageEntry.messageId!!, messageEntry.threadId) } companion object { diff --git a/app/src/main/java/com/nextcloud/talk/models/domain/SearchMessageEntry.kt b/app/src/main/java/com/nextcloud/talk/models/domain/SearchMessageEntry.kt index 7ef317b..e3d85b6 100644 --- a/app/src/main/java/com/nextcloud/talk/models/domain/SearchMessageEntry.kt +++ b/app/src/main/java/com/nextcloud/talk/models/domain/SearchMessageEntry.kt @@ -13,5 +13,6 @@ data class SearchMessageEntry( val title: String, val messageExcerpt: String, val conversationToken: String, + val threadId: String?, val messageId: String? ) diff --git a/app/src/main/java/com/nextcloud/talk/models/json/conversations/ConversationEnums.kt b/app/src/main/java/com/nextcloud/talk/models/json/conversations/ConversationEnums.kt index 56a8d96..c91c7ea 100644 --- a/app/src/main/java/com/nextcloud/talk/models/json/conversations/ConversationEnums.kt +++ b/app/src/main/java/com/nextcloud/talk/models/json/conversations/ConversationEnums.kt @@ -1,7 +1,7 @@ /* * Nextcloud Talk - Android Client * - * SPDX-FileCopyrightText: 2024 Your Name + * SPDX-FileCopyrightText: 2024 Marcel Hibbe * SPDX-License-Identifier: GPL-3.0-or-later */ diff --git a/app/src/main/java/com/nextcloud/talk/repositories/unifiedsearch/UnifiedSearchRepositoryImpl.kt b/app/src/main/java/com/nextcloud/talk/repositories/unifiedsearch/UnifiedSearchRepositoryImpl.kt index 88ce017..07db819 100644 --- a/app/src/main/java/com/nextcloud/talk/repositories/unifiedsearch/UnifiedSearchRepositoryImpl.kt +++ b/app/src/main/java/com/nextcloud/talk/repositories/unifiedsearch/UnifiedSearchRepositoryImpl.kt @@ -66,6 +66,7 @@ class UnifiedSearchRepositoryImpl(private val api: NcApi, private val userProvid private const val ATTRIBUTE_CONVERSATION = "conversation" private const val ATTRIBUTE_MESSAGE_ID = "messageId" + private const val ATTRIBUTE_THREAD_ID = "threadId" private fun mapToMessageResults( data: UnifiedSearchResponseData, @@ -81,13 +82,15 @@ class UnifiedSearchRepositoryImpl(private val api: NcApi, private val userProvid private fun mapToMessage(unifiedSearchEntry: UnifiedSearchEntry, searchTerm: String): SearchMessageEntry { val conversation = unifiedSearchEntry.attributes?.get(ATTRIBUTE_CONVERSATION)!! val messageId = unifiedSearchEntry.attributes?.get(ATTRIBUTE_MESSAGE_ID) + val threadId = unifiedSearchEntry.attributes?.get(ATTRIBUTE_THREAD_ID) return SearchMessageEntry( - searchTerm, - unifiedSearchEntry.thumbnailUrl, - unifiedSearchEntry.title!!, - unifiedSearchEntry.subline!!, - conversation, - messageId + searchTerm = searchTerm, + thumbnailURL = unifiedSearchEntry.thumbnailUrl, + title = unifiedSearchEntry.title!!, + messageExcerpt = unifiedSearchEntry.subline!!, + conversationToken = conversation, + threadId = threadId, + messageId = messageId ) } } diff --git a/app/src/main/java/com/nextcloud/talk/ui/BackgroundVoiceMessageCard.kt b/app/src/main/java/com/nextcloud/talk/ui/BackgroundVoiceMessageCard.kt index 88e75cf..e578ee3 100644 --- a/app/src/main/java/com/nextcloud/talk/ui/BackgroundVoiceMessageCard.kt +++ b/app/src/main/java/com/nextcloud/talk/ui/BackgroundVoiceMessageCard.kt @@ -1,7 +1,7 @@ /* * Nextcloud Talk - Android Client * - * SPDX-FileCopyrightText: 2024 Your Name + * SPDX-FileCopyrightText: 2024 Julius Linus * SPDX-License-Identifier: GPL-3.0-or-later */ diff --git a/app/src/main/java/com/nextcloud/talk/ui/ComposeChatAdapter.kt b/app/src/main/java/com/nextcloud/talk/ui/ComposeChatAdapter.kt index b391aca..13a9653 100644 --- a/app/src/main/java/com/nextcloud/talk/ui/ComposeChatAdapter.kt +++ b/app/src/main/java/com/nextcloud/talk/ui/ComposeChatAdapter.kt @@ -127,6 +127,7 @@ import kotlin.random.Random class ComposeChatAdapter( private var messagesJson: List? = null, private var messageId: String? = null, + private var threadId: String? = null, private val utils: ComposePreviewUtils? = null ) { @@ -195,6 +196,7 @@ class ComposeChatAdapter( private const val ANIMATED_BLINK = 500 private const val FLOAT_06 = 0.6f private const val HALF_OPACITY = 127 + private const val MESSAGE_LENGTH_THRESHOLD = 25 } private var incomingShape: RoundedCornerShape = RoundedCornerShape(2.dp, 20.dp, 20.dp, 20.dp) @@ -354,7 +356,8 @@ class ComposeChatAdapter( this.isReaction() || this.isPollVotedMessage() || this.isEditMessage() || - this.isInfoMessageAboutDeletion() + this.isInfoMessageAboutDeletion() || + this.isThreadCreatedMessage() private fun ChatMessage.isInfoMessageAboutDeletion(): Boolean = this.parentMessageId != null && @@ -366,6 +369,9 @@ class ComposeChatAdapter( private fun ChatMessage.isEditMessage(): Boolean = this.systemMessageType == ChatMessage.SystemMessageType.MESSAGE_EDITED + private fun ChatMessage.isThreadCreatedMessage(): Boolean = + this.systemMessageType == ChatMessage.SystemMessageType.THREAD_CREATED + private fun ChatMessage.isReaction(): Boolean = systemMessageType == ChatMessage.SystemMessageType.REACTION || systemMessageType == ChatMessage.SystemMessageType.REACTION_DELETED || @@ -429,16 +435,30 @@ class ComposeChatAdapter( message: ChatMessage, includePadding: Boolean = true, playAnimation: Boolean = false, - content: - @Composable - (RowScope.() -> Unit) + content: @Composable () -> Unit ) { + fun shouldShowTimeNextToContent(message: ChatMessage): Boolean { + val containsLinebreak = message.message?.contains("\n") ?: false || + message.message?.contains("\r") ?: false + + return ((message.message?.length ?: 0) < MESSAGE_LENGTH_THRESHOLD) && + !isFirstMessageOfThreadInNormalChat(message) && + message.messageParameters.isNullOrEmpty() && + !containsLinebreak + } + val incoming = message.actorId != currentUser.userId val color = if (incoming) { if (message.isDeleted) { - LocalContext.current.resources.getColor(R.color.bg_message_list_incoming_bubble_deleted, null) + LocalContext.current.resources.getColor( + R.color.bg_message_list_incoming_bubble_deleted, + null + ) } else { - LocalContext.current.resources.getColor(R.color.bg_message_list_incoming_bubble, null) + LocalContext.current.resources.getColor( + R.color.bg_message_list_incoming_bubble, + null + ) } } else { if (message.isDeleted) { @@ -449,11 +469,15 @@ class ComposeChatAdapter( } val shape = if (incoming) incomingShape else outgoingShape + val rowModifier = if (message.id == messageId && playAnimation) { + Modifier.withCustomAnimation(incoming) + } else { + Modifier + } + Row( - modifier = ( - if (message.id == messageId && playAnimation) Modifier.withCustomAnimation(incoming) else Modifier - ) - .fillMaxWidth(1f) + modifier = rowModifier.fillMaxWidth(), + horizontalArrangement = if (incoming) Arrangement.Start else Arrangement.End ) { if (incoming) { val imageUri = message.actorId?.let { viewModel.contactsViewModel.getImageUri(it, true) } @@ -465,11 +489,10 @@ class ComposeChatAdapter( modifier = Modifier .size(48.dp) .align(Alignment.CenterVertically) - .padding() .padding(end = 8.dp) ) } else { - Spacer(Modifier.weight(1f)) + Spacer(Modifier.width(8.dp)) } Surface( @@ -480,38 +503,51 @@ class ComposeChatAdapter( color = Color(color), shape = shape ) { - val timeString = DateUtils(LocalContext.current).getLocalTimeStringFromTimestamp(message.timestamp) - val modifier = if (includePadding) Modifier.padding(8.dp, 4.dp, 8.dp, 4.dp) else Modifier + val modifier = if (includePadding) { + Modifier.padding(16.dp, 4.dp, 16.dp, 4.dp) + } else { + Modifier + } + Column(modifier = modifier) { - if (message.parentMessageId != null && !message.isDeleted && messagesJson != null) { + if (messagesJson != null && + message.parentMessageId != null && + !message.isDeleted && + message.parentMessageId.toString() != threadId + ) { messagesJson!! .find { it.parentMessage?.id == message.parentMessageId } - ?.parentMessage!!.asModel().let { CommonMessageQuote(LocalContext.current, it) } + ?.parentMessage!!.asModel() + .let { CommonMessageQuote(LocalContext.current, it) } } if (incoming) { Text(message.actorDisplayName.toString(), fontSize = AUTHOR_TEXT_SIZE) } - Row { + ThreadTitle(message) + + if (shouldShowTimeNextToContent(message)) { + Row( + verticalAlignment = Alignment.CenterVertically + ) { + content() + Row( + verticalAlignment = Alignment.CenterVertically, + modifier = Modifier.padding(top = 6.dp, start = 8.dp) + ) { + TimeDisplay(message) + ReadStatus(message) + } + } + } else { content() - Spacer(modifier = Modifier.size(8.dp)) - Text( - timeString, - fontSize = TIME_TEXT_SIZE, - textAlign = TextAlign.End, - modifier = Modifier.align(Alignment.CenterVertically) - ) - if (message.readStatus == ReadStatus.NONE) { - val read = painterResource(R.drawable.ic_check_all) - Icon( - read, - "", - modifier = Modifier - .padding(start = 2.dp) - .size(12.dp) - .align(Alignment.CenterVertically) - ) + Row( + modifier = Modifier.align(Alignment.End), + verticalAlignment = Alignment.CenterVertically + ) { + TimeDisplay(message) + ReadStatus(message) } } } @@ -519,6 +555,55 @@ class ComposeChatAdapter( } } + @Composable + private fun TimeDisplay(message: ChatMessage) { + val timeString = DateUtils(LocalContext.current) + .getLocalTimeStringFromTimestamp(message.timestamp) + Text( + timeString, + fontSize = TIME_TEXT_SIZE, + textAlign = TextAlign.Center + ) + } + + @Composable + private fun ReadStatus(message: ChatMessage) { + if (message.readStatus == ReadStatus.NONE) { + val read = painterResource(R.drawable.ic_check_all) + Icon( + read, + "", + modifier = Modifier + .padding(start = 4.dp) + .size(16.dp) + ) + } + } + + @Composable + private fun ThreadTitle(message: ChatMessage) { + if (isFirstMessageOfThreadInNormalChat(message)) { + Row { + val read = painterResource(R.drawable.outline_forum_24) + Icon( + read, + "", + modifier = Modifier + .padding(end = 6.dp) + .size(18.dp) + .align(Alignment.CenterVertically) + ) + Text( + text = message.threadTitle ?: "", + fontSize = REGULAR_TEXT_SIZE, + fontWeight = FontWeight.SemiBold + ) + } + } + } + + fun isFirstMessageOfThreadInNormalChat(message: ChatMessage): Boolean = threadId == null && message.isThread + @Composable private fun Modifier.withCustomAnimation(incoming: Boolean): Modifier { val infiniteTransition = rememberInfiniteTransition() @@ -750,8 +835,8 @@ class ComposeChatAdapter( read, "", modifier = Modifier - .padding(start = 2.dp) - .size(12.dp) + .padding(start = 4.dp) + .size(16.dp) .align(Alignment.CenterVertically) ) } @@ -762,29 +847,30 @@ class ComposeChatAdapter( @Composable private fun VoiceMessage(message: ChatMessage, state: MutableState) { CommonMessageBody(message, playAnimation = state.value) { - Icon( - Icons.Filled.PlayArrow, - "play", - modifier = Modifier - .size(24.dp) - .align(Alignment.CenterVertically) - ) + Row( + verticalAlignment = Alignment.CenterVertically + ) { + Icon( + Icons.Filled.PlayArrow, + contentDescription = "play", + modifier = Modifier.size(24.dp) + ) - AndroidView( - factory = { ctx -> - WaveformSeekBar(ctx).apply { - setWaveData(FloatArray(DEFAULT_WAVE_SIZE) { Random.nextFloat() }) // READ ONLY for now - setColors( - colorScheme.inversePrimary.toArgb(), - colorScheme.onPrimaryContainer.toArgb() - ) - } - }, - modifier = Modifier - .align(Alignment.CenterVertically) - .width(180.dp) - .height(80.dp) - ) + AndroidView( + factory = { ctx -> + WaveformSeekBar(ctx).apply { + setWaveData(FloatArray(DEFAULT_WAVE_SIZE) { Random.nextFloat() }) // READ ONLY for now + setColors( + colorScheme.inversePrimary.toArgb(), + colorScheme.onPrimaryContainer.toArgb() + ) + } + }, + modifier = Modifier + .width(180.dp) + .height(80.dp) + ) + } } } @@ -856,6 +942,7 @@ class ComposeChatAdapter( message.extractedUrlToPreview!! ) CommonMessageBody(message, playAnimation = state.value) { + EnrichedText(message) Row( modifier = Modifier .drawWithCache { @@ -960,9 +1047,17 @@ class ComposeChatAdapter( @Preview(showBackground = true, widthDp = 380, heightDp = 800) @Composable +@Suppress("MagicNumber", "LongMethod") fun AllMessageTypesPreview() { val previewUtils = ComposePreviewUtils.getInstance(LocalContext.current) - val adapter = remember { ComposeChatAdapter(messagesJson = null, messageId = null, previewUtils) } + val adapter = remember { + ComposeChatAdapter( + messagesJson = null, + messageId = null, + threadId = null, + previewUtils + ) + } val sampleMessages = remember { listOf( @@ -982,6 +1077,42 @@ fun AllMessageTypesPreview() { timestamp = System.currentTimeMillis() actorDisplayName = "User2" messageType = ChatMessage.MessageType.REGULAR_TEXT_MESSAGE.name + }, + ChatMessage().apply { + jsonMessageId = 3 + actorId = "user1_id" + message = "This is a really really really really really really really really really long message" + timestamp = System.currentTimeMillis() + actorDisplayName = "User2" + messageType = ChatMessage.MessageType.REGULAR_TEXT_MESSAGE.name + }, + ChatMessage().apply { + jsonMessageId = 4 + actorId = "user1_id" + message = "some \n linebreak" + timestamp = System.currentTimeMillis() + actorDisplayName = "User2" + messageType = ChatMessage.MessageType.REGULAR_TEXT_MESSAGE.name + }, + ChatMessage().apply { + jsonMessageId = 5 + actorId = "user1_id" + threadTitle = "Thread title" + isThread = true + message = "Content of a first thread message" + timestamp = System.currentTimeMillis() + actorDisplayName = "User2" + messageType = ChatMessage.MessageType.REGULAR_TEXT_MESSAGE.name + }, + ChatMessage().apply { + jsonMessageId = 6 + actorId = "user1_id" + threadTitle = "looooooooooooong Thread title" + isThread = true + message = "Content" + timestamp = System.currentTimeMillis() + actorDisplayName = "User2" + messageType = ChatMessage.MessageType.REGULAR_TEXT_MESSAGE.name } ) } diff --git a/app/src/main/java/com/nextcloud/talk/ui/dialog/ContextChatCompose.kt b/app/src/main/java/com/nextcloud/talk/ui/dialog/ContextChatCompose.kt deleted file mode 100644 index 0da924a..0000000 --- a/app/src/main/java/com/nextcloud/talk/ui/dialog/ContextChatCompose.kt +++ /dev/null @@ -1,262 +0,0 @@ -/* - * Nextcloud Talk - Android Client - * - * SPDX-FileCopyrightText: 2025 Julius Linus - * SPDX-License-Identifier: GPL-3.0-or-later - */ - -package com.nextcloud.talk.ui.dialog - -import android.app.Activity -import android.content.Context -import android.content.ContextWrapper -import android.content.pm.ActivityInfo -import android.os.Bundle -import androidx.compose.foundation.background -import androidx.compose.foundation.layout.Arrangement -import androidx.compose.foundation.layout.Box -import androidx.compose.foundation.layout.Column -import androidx.compose.foundation.layout.Row -import androidx.compose.foundation.layout.fillMaxHeight -import androidx.compose.foundation.layout.fillMaxWidth -import androidx.compose.foundation.layout.padding -import androidx.compose.foundation.layout.size -import androidx.compose.foundation.layout.wrapContentSize -import androidx.compose.material.icons.Icons -import androidx.compose.material.icons.filled.Close -import androidx.compose.material.icons.filled.Info -import androidx.compose.material.icons.filled.MoreVert -import androidx.compose.material3.DropdownMenu -import androidx.compose.material3.DropdownMenuItem -import androidx.compose.material3.HorizontalDivider -import androidx.compose.material3.Icon -import androidx.compose.material3.IconButton -import androidx.compose.material3.MaterialTheme -import androidx.compose.material3.Surface -import androidx.compose.material3.Text -import androidx.compose.runtime.Composable -import androidx.compose.runtime.MutableState -import androidx.compose.runtime.SideEffect -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 -import androidx.compose.ui.res.stringResource -import androidx.compose.ui.unit.dp -import androidx.compose.ui.unit.sp -import androidx.compose.ui.window.Dialog -import androidx.compose.ui.window.DialogProperties -import androidx.lifecycle.ViewModel -import androidx.lifecycle.asFlow -import autodagger.AutoInjector -import com.nextcloud.talk.R -import com.nextcloud.talk.application.NextcloudTalkApplication -import com.nextcloud.talk.chat.viewmodels.ChatViewModel -import com.nextcloud.talk.data.database.mappers.asModel -import com.nextcloud.talk.models.json.chat.ChatMessageJson -import com.nextcloud.talk.ui.ComposeChatAdapter -import com.nextcloud.talk.ui.theme.ViewThemeUtils -import com.nextcloud.talk.users.UserManager -import com.nextcloud.talk.utils.bundle.BundleKeys -import javax.inject.Inject - -@Suppress("FunctionNaming", "LongMethod", "StaticFieldLeak") -class ContextChatCompose(val bundle: Bundle) { - - companion object { - const val LIMIT = 50 - const val HALF_ALPHA = 0.5f - } - - @AutoInjector(NextcloudTalkApplication::class) - inner class ContextChatComposeViewModel : ViewModel() { - @Inject - lateinit var viewThemeUtils: ViewThemeUtils - - @Inject - lateinit var chatViewModel: ChatViewModel - - @Inject - lateinit var userManager: UserManager - - init { - NextcloudTalkApplication.sharedApplication!!.componentApplication.inject(this) - val credentials = bundle.getString(BundleKeys.KEY_CREDENTIALS)!! - val baseUrl = bundle.getString(BundleKeys.KEY_BASE_URL)!! - val token = bundle.getString(BundleKeys.KEY_ROOM_TOKEN)!! - val messageId = bundle.getString(BundleKeys.KEY_MESSAGE_ID)!! - - chatViewModel.getContextForChatMessages(credentials, baseUrl, token, messageId, LIMIT) - } - } - - private fun Context.requireActivity(): Activity { - var context = this - while (context is ContextWrapper) { - if (context is Activity) return context - context = context.baseContext - } - throw IllegalStateException("No activity was present but it is required.") - } - - @Composable - fun GetDialogView( - shouldDismiss: MutableState, - context: Context, - contextViewModel: ContextChatComposeViewModel = ContextChatComposeViewModel() - ) { - if (shouldDismiss.value) { - context.requireActivity().requestedOrientation = ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED - return - } - - context.requireActivity().requestedOrientation = ActivityInfo.SCREEN_ORIENTATION_LOCKED - val colorScheme = contextViewModel.viewThemeUtils.getColorScheme(context) - MaterialTheme(colorScheme) { - Dialog( - onDismissRequest = { - shouldDismiss.value = true - }, - properties = DialogProperties( - dismissOnBackPress = true, - dismissOnClickOutside = true, - usePlatformDefaultWidth = false - ) - ) { - Surface { - Column( - modifier = Modifier - .fillMaxWidth() - .fillMaxHeight() - .padding(top = 16.dp) - ) { - val user = contextViewModel.userManager.currentUser.blockingGet() - val shouldShow = !user.hasSpreedFeatureCapability("chat-get-context") || - !user.hasSpreedFeatureCapability("federation-v1") - Row( - modifier = Modifier.align(Alignment.Start), - verticalAlignment = Alignment.CenterVertically - ) { - IconButton(onClick = { - shouldDismiss.value = true - }) { - Icon( - Icons.Filled.Close, - stringResource(R.string.close), - modifier = Modifier - .size(24.dp) - ) - } - Column(verticalArrangement = Arrangement.Center) { - val name = bundle.getString(BundleKeys.KEY_CONVERSATION_NAME)!! - Text(name, fontSize = 24.sp) - } - // Spacer(modifier = Modifier.weight(1f)) - // val cInt = context.resources.getColor(R.color.high_emphasis_text, null) - // Icon( - // painterResource(R.drawable.ic_call_black_24dp), - // "", - // tint = Color(cInt), - // modifier = Modifier - // .padding() - // .padding(end = 16.dp) - // .alpha(HALF_ALPHA) - // ) - // - // Icon( - // painterResource(R.drawable.ic_baseline_videocam_24), - // "", - // tint = Color(cInt), - // modifier = Modifier - // .padding() - // .alpha(HALF_ALPHA) - // ) - // - // ComposeChatMenu(colorScheme.background, false) - } - if (shouldShow) { - Icon( - Icons.Filled.Info, - "Info Icon", - modifier = Modifier.align(Alignment.CenterHorizontally) - ) - - Text( - stringResource(R.string.nc_capabilities_failed), - modifier = Modifier.align(Alignment.CenterHorizontally) - ) - } else { - val contextState = contextViewModel - .chatViewModel - .getContextChatMessages - .asFlow() - .collectAsState(listOf()) - val messagesJson = contextState.value - val messages = messagesJson.map(ChatMessageJson::asModel) - val messageId = bundle.getString(BundleKeys.KEY_MESSAGE_ID)!! - val adapter = ComposeChatAdapter(messagesJson, messageId) - SideEffect { - adapter.addMessages(messages.toMutableList(), true) - } - adapter.GetView() - } - } - } - } - } - } - - @Composable - private fun ComposeChatMenu(backgroundColor: Color, enabled: Boolean = true) { - var expanded by remember { mutableStateOf(false) } - - Box( - modifier = Modifier.wrapContentSize(Alignment.TopStart) - ) { - IconButton(onClick = { expanded = true }) { - Icon( - imageVector = Icons.Default.MoreVert, - contentDescription = "More options" - ) - } - - DropdownMenu( - expanded = expanded, - onDismissRequest = { expanded = false }, - modifier = Modifier.background(backgroundColor) - ) { - DropdownMenuItem( - text = { Text(stringResource(R.string.nc_search)) }, - onClick = { - expanded = false - }, - enabled = enabled - ) - - HorizontalDivider() - - DropdownMenuItem( - text = { Text(stringResource(R.string.nc_conversation_menu_conversation_info)) }, - onClick = { - expanded = false - }, - enabled = enabled - ) - - HorizontalDivider() - - DropdownMenuItem( - text = { Text(stringResource(R.string.nc_shared_items)) }, - onClick = { - expanded = false - }, - enabled = enabled - ) - } - } - } -} 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 7d6d528..d31b7c6 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 @@ -84,4 +84,5 @@ object BundleKeys { const val KEY_FOCUS_INPUT: String = "KEY_FOCUS_INPUT" const val KEY_THREAD_ID = "KEY_THREAD_ID" const val KEY_FROM_QR: String = "KEY_FROM_QR" + const val KEY_OPENED_VIA_NOTIFICATION: String = "KEY_OPENED_VIA_NOTIFICATION" } diff --git a/app/src/main/res/drawable/baseline_tag_faces_24.xml b/app/src/main/res/drawable/baseline_tag_faces_24.xml index 3a4f458..ecdf841 100644 --- a/app/src/main/res/drawable/baseline_tag_faces_24.xml +++ b/app/src/main/res/drawable/baseline_tag_faces_24.xml @@ -1,10 +1,9 @@ - + ~ SPDX-FileCopyrightText: 2023-2024 Google LLC + ~ SPDX-License-Identifier: Apache-2.0 +--> folder Loading … %1$s (%2$d) - Followed threads 4 hours Failed to fetch pending invitations (edited) @@ -670,6 +669,8 @@ Thread notifications Reply Thread title + Threads + No threads found Today Tomorrow Translate diff --git a/app/src/main/res/values-be/strings.xml b/app/src/main/res/values-be/strings.xml index faa77d0..4653a74 100644 --- a/app/src/main/res/values-be/strings.xml +++ b/app/src/main/res/values-be/strings.xml @@ -31,8 +31,8 @@ Дазвол на камеру атрыманы. Выберыце камеру яшчэ раз. Скасаваць уваход Выбраць аватар з воблака - Ачысціць паведамленне статусу - Ачысціць паведамленне статусу пасля + Ачысціць + Ачысціць паведамленне статусу праз Закрыць Значок Закрыць Злучэнне ўсталявана @@ -88,6 +88,7 @@ Апусціць руку Размова %1$s пазначана як прачытаная Размова %1$s пазначана як непрачытаная + Згаданы Спачатку новыя Спачатку старыя А-Я @@ -124,6 +125,7 @@ Укл./выкл. камеру Пакласці слухаўку Укл./выкл. мікрафон + Адкрыць рэжым «Picture-in-Picture» Пераключыцца на відэа з сабой УВАХОДНЫ Назва размовы @@ -190,6 +192,7 @@ Паведамленне паспяхова выдалена, але яно магло трапіць у іншыя сэрвісы Выдаліць зараз Карыстальнік %1$s быў выдалены + Пазбавіць правоў мадэратара Запісаць галасавое паведамленне Адправіць паведамленне Бягучы ўліковы запіс @@ -206,16 +209,24 @@ Аптымізацыя батарэі ўключана, што можа выклікаць праблемы. Вам варта адключыць аптымізацыю батарэі! Налады батарэі Прылада - Адкрыць кантрольны спіс вырашэння праблем + Адкрыць спіс вырашэння праблем Адкрыць экран дыягностыкі Адкрыць dontkillmyapp.com + Атрыманне апошняга push-токена firebase + Генерацыя апошняга push-токена firebase + Не зададзены push-токен firebase. Стварыце справаздачу пра памылку. + Push-токен firebase Сэрвісы Google Play недаступны. Апавяшчэнні не падтрымліваюцца Сэрвісы Google Play Сэрвісы Google Play даступны + Апошняя рэгістрацыя push на push-проксі + Пакуль не зарэгістраваны на push-проксі + Апошняя рэгістрацыя push на серверы Пакуль не зарэгістраваны на серверы Метаінфармацыя Стварэнне сістэмнай справаздачы Канал апавяшчэнняў аб выкліках уключаны? + Ці ўключаны канал апавяшчэнняў пра паведамленні? Дазволы на апавяшчэнні Тэлефон Версія сервера Talk @@ -234,6 +245,8 @@ Не Захаваць у сховішча? Так + Не ўдалося атрымаць імя для паказу, скасаванне + Не ўдалося захаваць імя для паказу, скасаванне Рэдагаваць Рэдагаваць Рэдагаваць паведамленне @@ -260,7 +273,8 @@ Пераслаць Пераслаць … Галерэя - Атрымаць зыходны код + У вас яшчэ няма сервера?\nНацісніце тут, каб атрымаць яго ў пастаўшчыка + Зыходны код Група Госць Гасцявы доступ @@ -285,6 +299,7 @@ Запрашэнні Далучыцца да адкрытых размоў Пакінуць + Перш чым пакінуць размову, вам трэба прызначыць новага мадэратара %1$s | Апошняе змяненне: %2$s Выйсці з размовы Выхад з выкліку … @@ -333,6 +348,7 @@ Вам не дазволена ўключаць гук! Вам не дазволена ўключаць відэа! Не цяпер + %1$s на канале апавяшчэнняў %2$s Выклікі Апавяшчаць пры ўваходных выкліках Паведамленні @@ -341,6 +357,7 @@ Апавяшчаць пра ход выканання запампоўвання Налады апавяшчэнняў Апавяшчэнні наладжаны няправільна + Дазвол на апавяшчэнні і налады батарэі зададзены правільна. Калі ў вас усё адно ўзнікаюць праблемы з атрыманнем апавяшчэнняў, праверце, ці ўключаны каналы апавяшчэнняў для выклікаў і паведамленняў. Дадатковую дапамогу можна знайсці на сайце DontKillMyApp.com або ў спісе пошуку і вырашэння праблем. Калі гэта не дапаможа, перайдзіце на экран дыягностыкі і адпраўце справаздачу пра памылку. Вырашэнне праблем з апавяшчэннямі Заўсёды апавяшчаць Апавяшчаць пры згадванні @@ -366,6 +383,7 @@ Паведамленні Прыватнасць Асабістыя звесткі + Прызначыць мадэратарам Публічная размова Push-апавяшчэнні адключаны Нешта пайшло не так, памылка: %1$s @@ -456,15 +474,22 @@ Порт проксі Тып проксі Імя карыстальніка проксі + Абагульваць мой статус прачытання і паказваць статус прачытання іншых + Статус прачытання + Паўторна аўтарызаваць уліковы запіс Выдаліць Выдаліць уліковы запіс - Час чакання блакіроўкі экрана пры бяздзейнасці + Пацвердзіце свой намер выдаліць бягучы ўліковы запіс. + Блакіраваць %1$s з дапамогай блакіроўкі экрана Android або даступнага біяметрычнага метаду + Час чакання блакіроўкі пры бяздзейнасці Блакіроўка экрана Забараняе рабіць здымкі экрана ў спісе нядаўняга і ўнутры праграмы Бяспека экрана Версія сервера вельмі старая і не будзе падтрымлівацца ў наступным выпуску! Версія сервера занадта старая і не падтрымліваецца гэтай версіяй праграмы для Android. Сервер не падтрымліваецца + Праграма для апавяшчэнняў не ўсталявана на серверы + Зададзена рэжымам эканоміі зараду батарэі Цёмная Сістэмная тэма @@ -488,7 +513,7 @@ Няма абагуленых элементаў Месцазнаходжанне Абагуленае месцазнаходжанне - Калі апавяшчэнні настроены няправільна, паказваць звычайнае папярэджанне + Калі апавяшчэнні наладжаны няправільна, паказваць звычайнае папярэджанне Паказваць звычайнае папярэджанне аб апавяшчэннях Сартаваць па Пачаць супольны чат @@ -505,7 +530,7 @@ Не ўдалося запампаваць Не ўдалося запампаваць %1$s Няўдача - Абагульванне ад %1$s + Абагульванне з %1$s Запампаваць з прылады Запампоўванне %1$s у %2$s - %3$s\%% @@ -521,11 +546,14 @@ Так На наступным тыдні Няма архіваваных размоў + Няма захаваных пазасеткавых паведамленняў + Няма інтэграцыі нумара тэлефона з-за адсутнасці дазволаў Усе паведамленні Толькі згадкі з @ Выкл. Прадвызначаныя - 1 гадзіна + Прытрымлівацца налад размовы + 1 гадзіну У сетцы Статус у сетцы Адкрытыя размовы @@ -533,6 +561,7 @@ Адкрыць Нататкі Перайсці да гутаркі Прайграць/прыпыніць галасавое паведамленне + Кіраванне хуткасцю прайгравання Дадаць варыянт Рэдагаваць голас Завяршыць апытанне @@ -556,6 +585,7 @@ Абагульванне файлаў са сховішча немагчыма без дазволаў Нядаўнія гутаркі Выклік запісваецца + Скасаваць пачатак запісу Не ўдалося зрабіць запіс. Звярніцеся да адміністратара. Пачаць запіс Вы сапраўды хочаце спыніць запіс? @@ -577,6 +607,13 @@ Сканіраваць QR-код Сінхранізацыя толькі з даверанымі серверамі Федэратыўны + Бачна толькі карыстальнікам гэтага сервера і гасцям + Лакальна + Бачна толькі людзям, якія супалі праз інтэграцыю нумара тэлефона з дапамогай Talk на мабільным тэлефоне + Прыватна + Сінхранізацыя з даверанымі серверамі і глабальнай і публічнай адраснай кнігай + Апублікавана + Пераключальнік бачнасці Змяніць узровень прыватнасці %1$s Прагартаць уніз Значок пошуку @@ -590,7 +627,7 @@ Задаць Задаць аватар з камеры Задаць статус - Задаць паведамленне статусу + Задаць Абагуліць Далучайцеся да размовы %1$s у %2$s Аўдыя @@ -605,9 +642,9 @@ Абранае Вам не дазволена пачынаць выклік Стварыць гутарку + пачаў(-ла) выклік Паведамленне статусу Статус вернуты - Пераключыцца на пакой для абмеркавання Пераключыцца на галоўны пакой Зрабіць фота Памылка пры здымку @@ -626,6 +663,7 @@ Апавяшчэнні гутаркі Адказаць Загаловак гутаркі + Гутаркі Гутарак не знойдзена Сёння Заўтра @@ -648,7 +686,7 @@ Разблакіраваць Непрачытанае Запампаваць новы аватар з прылады - %1$s сёння не на працы і можа не адказаць + %1$s не на працы і можа не адказаць %1$s сёння не на працы Замена: Аватар карыстальніка @@ -659,9 +697,17 @@ Twitter Вэб-сайт Статус + Не ўдалося атрымаць асабістую інфармацыю карыстальніка. + Асабістая інфармацыя не зададзена Дадайце імя, аватар і кантактную інфармацыю на старонку вашага профілю. Відэавыклік Які ў вас статус? + + Паглядзець %d падобнае паведамленне + Паглядзець %d падобныя паведамленні + Паглядзець %d падобных паведамленняў + Паглядзець %d падобных паведамленняў + Гэтая размова будзе аўтаматычна выдалена для ўсіх праз %1$d дзень бяздзейнасці. Гэтая размова будзе аўтаматычна выдалена для ўсіх праз %1$d дні бяздзейнасці. diff --git a/app/src/main/res/values-cs-rCZ/strings.xml b/app/src/main/res/values-cs-rCZ/strings.xml index 118e8de..9eea8be 100644 --- a/app/src/main/res/values-cs-rCZ/strings.xml +++ b/app/src/main/res/values-cs-rCZ/strings.xml @@ -67,7 +67,6 @@ složka Načítání… %1$s (%2$d) - Sledovaná vlákna 4 hodiny Nepodařilo se získat čekající pozvání (upraveno) @@ -80,6 +79,10 @@ Opustili jste konverzaci %1$s Načíst další výsledky Místní čas: %1$s + Oprávnění k přístupu k poloze odepřeno + Povolte to v nastavení aplikace + Služby určování polohy vypnuty + Abyste mohli používat tuto funkci zapněte polohové služby (GPS) Uzamknout konverzaci Symbol zámku Přestat se hlásit @@ -93,6 +96,7 @@ Největší jako první Nejmenší jako první Zpráva zkopírována + Opravdu chcete tuto zprávu smazat? Zprávu jste smazali Upraveno %1$s Klepnutím anketu otevřete @@ -100,6 +104,7 @@ Hledejte psaním… Hledat… Zprávy + Ztlumit veškerá upozornění Zvolený účet byl naimportován a je k dispozici O aplikaci Aktivní uživatel @@ -664,6 +669,8 @@ Notifikace ohledně vlákna Odpověď Název vlákna + Vláken + Nenalezeny žádné hrozby 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 index 105a49c..85ceb6f 100644 --- a/app/src/main/res/values-da/strings.xml +++ b/app/src/main/res/values-da/strings.xml @@ -10,6 +10,7 @@ Når en samtale er arkiveret, vil den blive skjult som standard. Vælg filteret \"Arkiveret\" for at se arkiverede samtaler. Direkte omtaler vil stadig blive modtaget. Arkiveret Arkiverede %1$s + Lydopkald Bluetooth Lydudgang Telefon @@ -35,8 +36,10 @@ Luk Luk ikon Forbindelse oprettet + Ingen forbindelse til server Forbindelse mistet - Sendte beskeder er i kø Lås optagelse for kontinuerlig optagelse af talebeskeden + Samtale er arkiveret Samtalen er skrivebeskyttet Samtalen kunne ikke indstilles som skrivebeskyttet Samtaler @@ -46,12 +49,16 @@ Farezone %1$s i %2$s Slet avatar + Slet stemmeoptagelse Slettede samtale %1$s Forstyr ikke Ryd ikke Redigér + Beskeder der er ældre end 24 timer kan ikke redigeres + Rediger besked Nylige Krypteret + Afslut opkald Afslut opkald for alle Der opstod et problem med at indlæse dine chats En fejl opstod under fjernelse af blokering af deltager @@ -71,18 +78,25 @@ Forlad opkald Du forlod samtalen %1$s Indlæs flere resultater + Lokal tid: %1$s + Lokationstilladelse nægtet + Aktiver det venligst under app indstillingerne + Lokationsservice deaktiveret + Aktiver venligst lokationsservice (GPS) for at bruge denne funktion Lås samtale Låsesymbol Sænk hånden Marker samtalen %1$s som læst Marker samtalen %1$s som ulæst - Nævnt + Omtalt Nyeste først Ældste først A - Å Å - A Største først Mindste først + Besked kopieret + Er du sikker på at du ønsker at slette denne besked? Besked slettet af dig Redigeret af %1$s Rør for at åbne afstemning @@ -136,6 +150,8 @@ Din SSL indstilling forhindrede forbindelse Skift godkendelsescertifikat Skift adgangskode + Annuller redigering + Annuller redigering Slet alle beskeder Alle beskeder blev slettet Ønsker du virkelig at slette alle beskeder i denne samtale? @@ -166,6 +182,7 @@ Kopier Opret ny samtale Opret afstemning + Dig: I dag I går Slet @@ -174,6 +191,7 @@ Hvis du sletter konversationen, vil den også blive slettet for alle andre deltagere. Slet besked Besked slettet, men kan kan være lækket til andre services + Slet nu Brugeren %1$s blev fjernet Degrader fra moderator Optag stemmebesked @@ -232,7 +250,10 @@ Kunne ikke opbevare skærmnavn, afbryder Redigér Redigér + Rediger besked Redigeret af admin + Begivenheds samtale menu + Planlæg 8 timer 4 uger Slået fra @@ -249,6 +270,7 @@ Du har afventende invitationer Tilbage Tilladelse til filadgang er krævet + Filtrer samtaler Bruger følger et offentligt link Dig: %1$s Videresend @@ -275,8 +297,11 @@ Batterioptimering bliver ikke ignoreret. Dette bør ændres for at være sikker på at notifikationer virker i baggrunden! Klik venligst på OK og vælg \"Alle apps\" -> %1$s -> Optimer ikke Ignorer batterioptimering Vigtig samtale + Brugerstatus \"Forstyr ikke\" ignoreres ved vigtige samtaler + Ugyldigt tidspunkt Invitationer Deltag i åbne samtaler + Behold Du skal udnævne en ny moderator inden du kan forlade samtalen. %1$s| Sidst ændret: %2$s Forlad samtale @@ -296,6 +321,12 @@ Ikke indstillet Marker som læst Marker som ulæst + Samtale markeret som vigtig + Samtal ikke markeret som følsom + Samtale markeret som følsom + Samtale ikke markeret som vigtig + Mødet sluttede + Besked til føjet til noter Mislykkede Kunne ikke sende besked: Offline @@ -303,6 +334,7 @@ Besked læst Sender Beskeden blev sendt + Mikrofon er aktiveret og lyden optages For at aktivere kommunikation så tillad venligst \"Mikrofon\" Du missede et opkald fra %s Moderator @@ -335,6 +367,7 @@ Giv aldrig besked For nuværende offline, venligst kontroller din forbindelse OK + Igangværende møde Begynd en samtale til registrerede brugere Også åben for gæste app brugere Ejer @@ -356,6 +389,9 @@ Forfrem til moderator Offentlig samtale Pushbeskeder er slået fra + Desværre, noget gik galt, fejlen er %1$s + Desværre, noget gik galt, kan ikke hente test push besked + Push notifikation afsendt. Du bør nu modtage en notifikation på apparatet med titlen \'Test push notifikationer\' Tryk-for-at-tale Med mikrofonen deaktiveret, hold&nede for at bruge Tryk-for-at-tale Påmind mig senere @@ -368,6 +404,7 @@ Omdøb Besvar Svar privat + Rummet er bevaret Gem Gemt 30 sekunder @@ -382,6 +419,10 @@ Søg Ryd søgning Vælg konto + Opdater besked + Send stemmeoptagelse + Følsom samtale + Besked forhåndsvisning vil blive deaktiveret i samtalelisten og notifikationer %1$s sendte en GIF. Du sendte en GIF. %1$s sendte en video. @@ -452,6 +493,7 @@ Serverversionen er for gammel og er ikke understøttet af denne version af Android app\'en Ikke understøttet server Server notifikations app ikke installeret + Sat af batterisparer Mørk Brug system default tema @@ -483,6 +525,10 @@ Start tid Skift konto Team + Test push notifikationer + Testresultater + I dag kl. %1$s + I morgen kl. %1$s Vælg filer Send disse filer til %1$s? Send denne fil til %1$s? @@ -504,16 +550,21 @@ Webinar Ja Næste uge + Ingen arkiverede samtaler Ingen offline beskeder gemt Ingen telefonnummerintegration på grund af manglende rettigheder + Alle beskeder Kun omtalt med @ Deaktivér Standard + Følg samtaleindstillinger 1 time Online Online status Åbne samtaler Åben i appe\'en filer + Åben noter + Gå til tråd Afspil/pauser stemmebesked Afspilningshastighedskontrol Tilføj valg @@ -533,9 +584,11 @@ Stemme Stemme indsendt Tidligere sat + QR koden kunne ikke læses Løft hånden Alle Deling af filer fra lager er ikke muligt uden rettigheder + Seneste tråde Opkaldet optages Annuller opstagelsesstart Optagelsen fejlede. Kontakt venligst din administrator @@ -593,6 +646,7 @@ Vis blokerede deltagere Favorit Du har ikke tilladelse til at starte et opkald + Opret en tråd startede et opkald Statusbesked Status omvendt @@ -611,6 +665,12 @@ Denne uge Dette er en testbesked Denne weekend + Annuller trådoprettelse + Trådnotifikationer + Svar + Trådtitel + Tråde + Ingen tråde fundet I dag I morgen Oversæt @@ -652,6 +712,14 @@ Se %d lignende besked Se %d lignende beskeder + + Denne samtale vil automatisk blive slettet for alle efter%1$d dage med inaktivitet + Denne samtale vil automatisk blive slettet for alle efter %1$d dage med inaktivitet + + + %d svar + %d svar + %d stemme %d stemmer diff --git a/app/src/main/res/values-de/strings.xml b/app/src/main/res/values-de/strings.xml index b9a3586..3805405 100644 --- a/app/src/main/res/values-de/strings.xml +++ b/app/src/main/res/values-de/strings.xml @@ -67,7 +67,6 @@ Ordner Lade … %1$s (%2$d) - Nachverfolgte Themen 4 Stunden Ausstehende Einladungen konnten nicht abgerufen werden (Bearbeitet) @@ -670,6 +669,7 @@ Themen-Benachrichtigungen Antwort Thementitel + Themen Keine Themen gefunden Heute Morgen diff --git a/app/src/main/res/values-el/strings.xml b/app/src/main/res/values-el/strings.xml index 1bb70d8..c97cbd3 100644 --- a/app/src/main/res/values-el/strings.xml +++ b/app/src/main/res/values-el/strings.xml @@ -3,14 +3,18 @@ Επεξεργασία Προσθήκη Αναζήτηση στο %s + Αρχειοθέτηση συνομιλίας Αρχειοθετήθηκε Έξοδος ήχου Τηλέφωνο Μεγάφωνο + Η κατάστασή σας ορίστηκε αυτόματα Εικόνα προφίλ Λείπω Απασχολημένος Ημερολόγιο + Η κλήση εκτελείται για μία ώρα. + Κλήση χωρίς ειδοποίηση Επιλογή εικόνας προφίλ από το cloud Εκκαθάριση μηνύματος κατάστασης Εκκαθάριση μηνύματος κατάστασης μετά από @@ -28,16 +32,19 @@ Πρόσφατα Κρυπτογραφημένο Τερματισμός κλήσης + Τερματισμός κλήσης για όλους Αποτυχία αποθήκευσης %1$s 15 λεπτά φάκελος Φόρτωση … %1$s (%2$d) 4 ώρες + (επεξεργασμένο) Αόρατο Αργότερα σήμερα Αποχώρηση από την κλήση Φόρτωση περισσοτέρων αποτελεσμάτων + Τοπική ώρα: %1$s Κλειδώστε τη συνομιλία Κατεβάστε το χέρι Νεότερο πρώτα @@ -47,7 +54,9 @@ Μεγαλύτερο πρώτα Μικρότερο πρώτα Το μήνυμα διαγράφηκε από εσάς + Επεξεργάστηκε από %1$s Κανένα αποτέλεσμα + Αναζήτηση … Μηνύματα Ο επιλεγμένος λογαριασμός έχει εισαχθεί και είναι τώρα διαθέσιμος Περί @@ -112,6 +121,7 @@ Αντιγραφή Δημιουργία νέας συνομιλίας Δημιουργία ψηφοφορίας + Εσείς: Σήμερα Χθές Διαγραφή @@ -120,6 +130,7 @@ Αν διαγράψετε την συνομιλία, θα διαγραφεί επίσης για όλους τους υπόλοιπους συμμετέχοντες. Διαγραφή μηνύματος Το μήνυμα διαγράφηκε με επιτυχία, αλλά ενδέχεται να έχει διαρρεύσει σε άλλες υπηρεσίες + Διαγραφή τώρα Υποβάθμιση από συντονιστή Εγγραφή φωνητικού μηνύματος Αποστολή μηνύματος @@ -145,13 +156,16 @@ Επεξεργασία Επεξεργασία μηνύματος 8 ώρες + 4 εβδομάδες Απενεργοποίηση 1 μέρα 1 ώρα 1 εβδομάδα + Τα μηνύματα συνομιλίας μπορούν να λήξουν μετά από συγκεκριμένο χρόνο. Σημείωση: Τα αρχεία που κοινοποιούνται στη συνομιλία δεν θα διαγραφούν για τον κάτοχο, αλλά δεν θα κοινοποιούνται πλέον στη συνομιλία. Αποτυχία λήψης ρυθμίσεων σήματος Αποδοχή Απόρριψη + Δεν υπάρχουν εκκρεμείς προσκλήσεις Πίσω Χρήστης από δημόσιο σύνδεσμο Εσείς: %1$s @@ -162,6 +176,7 @@ Λήψη πηγαίου κώδικα Ομάδα Επισκέπτης + Πρόσβαση επισκεπτών Επιτρέψτε τους επισκέπτες Εισάγετε συνθηματικό Ορίστε έναν κωδικό πρόσβασης για να περιορίσετε ποιος μπορεί να χρησιμοποιήσει τον δημόσιο σύνδεσμο. @@ -170,8 +185,11 @@ Κοινή χρήση συνδέσμου συνομιλίας Εισάγετε ένα μήνυμα ... Σημαντική συνομιλία + Η κατάσταση χρήστη \"Μην ενοχλείτε\" αγνοείται για σημαντικές συνομιλίες Προσκλήσεις Δημιουργία νέας συνομιλίας + Διατήρηση + Πρέπει να προβιβάσετε έναν νέο συντονιστή πριν μπορέσετε να εγκαταλείψετε τη συνομιλία %1$s Τελευταία τροποποίηση %2$s Εγκατάλειψη συνομιλίας Αποχώρηση από την κλήση ... @@ -179,6 +197,8 @@ Άδεια χρήσης Το όριο %s χαρακτήρων έχει συμπληρωθεί Αναμονή + Αυτή η συνάντηση είναι προγραμματισμένη για %1$s + Η συνάντηση θα ξεκινήσει σύντομα Αυτή τη στιγμή είστε σε αναμονή Η τρέχουσα τοποθεσία σας απαιτείται δικαιώματα τοποθεσίας @@ -189,12 +209,14 @@ Σήμανση ως αναγνωσμένο επισήμανση ως μή-αναγνωσμένο Απέτυχε + Εκτός σύνδεσης Ακύρωση απάντησης Το μήνυμα διαβάστηκε Το μήνυμα στάλθηκε Συντονιστής Νέα συνομιλία Ορατότητα + Αδιάβαστες αναφορές Μη αναγνωσμένα μηνύματα Το %1$s δεν είναι διαθέσιμο (δεν έχει εγκατασταθεί ή έχει απαγορευθεί από τον διαχειριστή) Επισκέπτης @@ -225,6 +247,7 @@ Ιδιωτικότητα Προσωπικές πληροφορίες Προαγωγή από συντονιστή + Δημόσια συνομιλία Οι ειδοποιήσεις push απενεργοποιήθηκαν Push-to-talk Με απενεργοποιημένο το μικρόφωνο, πιέστε και κρατήστε το & για χρήση του Push-to-talk @@ -232,6 +255,7 @@ Αφαίρεση από τα αγαπημένα Αφαίρεση ομάδων και μελών Αφαίρεση συμμετέχοντα + Αφαίρεση ομάδας και μελών Μετονομασία συνομιλίας Μετονομασία Απάντηση @@ -249,6 +273,8 @@ Αναζήτηση Εκκαθάριση αναζήτησης Επιλογή λογαριασμού + Ευαίσθητη συνομιλία + Η προεπισκόπηση μηνυμάτων θα απενεργοποιηθεί στη λίστα συνομιλιών και στις ειδοποιήσεις %1$s έστειλε GIF. Στείλατε εικόνα GIF. %1$s έστειλε βίντεο. @@ -315,6 +341,7 @@ θέμα Φωτεινό Θέμα + Κοινή χρήση της κατάστασης πληκτρολόγησής μου και εμφάνιση της κατάστασης πληκτρολόγησης των άλλων Ο διαμεσολαβητής απαιτεί διαπιστευτήρια Προειδοποίηση Μόνο ο παρόν λογαριασμός μπορεί να επαναεγκριθεί @@ -324,12 +351,15 @@ Διαμοιρασμός τοποθεσίας Διαμοιρασμός αυτής της τοποθεσίας Επιλογή λογαριασμού + Κοινόχρηστα αντικείμενα Κάρτα του Deck + Δεν υπάρχουν κοινόχρηστα αντικείμενα Τοποθεσία Διαμοιρασμένες τοποθεσίες Ταξινόμηση κατά Ώρα έναρξης Αλλαγή λογαριασμού + Ομάδα Επιλογή αρχείων Να σταλούν αυτά τα αρχεία στον %1$s; Να σταλεί αυτό το αρχείο στον %1$s; @@ -339,6 +369,7 @@ Γίνεται μεταφόρτωση Βγάλε φωτογραφία Χρήστης + Εγγραφή ομιλίας από %1$s (%2$s) Κρατήστε για εγγραφή, αφήστε για αποστολή. Απαιτούνται δικαιώματα για ηχογράφηση « Σύρετε για ακύρωση @@ -348,23 +379,38 @@ Δεν υπάρχει ενσωμάτωση αριθμού τηλεφώνου λόγω έλλειψης δικαιωμάτων Απενεργοποιημένο Προεπιλογή + Ακολούθηση ρυθμίσεων συνομιλίας 1 ώρα Σε σύνδεση Κατάσταση σε σύνδεση Άνοιγμα συνομιλιών Άνοιγμα την εφαρμογή Αρχεία + Μετάβαση στη συζήτηση Αναπαραγωγή/παύση ηχητικού μηνύματος Προσθήκη επιλογής + Τερματισμός δημοσκόπησης + Πολλαπλές απαντήσεις Επιλογές Ιδιωτική δημοσκόπηση + Ερώτηση Αποτελέσματα Ρυθμίσεις Ψήφος + Προηγουμένως ορισμένη Σηκώστε το χέρι \'Ολα Η κοινή χρήση αρχείων από τον χώρο αποθήκευσης δεν είναι δυνατή χωρίς δικαιώματα + Πρόσφατες συζητήσεις + Ακύρωση έναρξης εγγραφής + Η εγγραφή απέτυχε. Παρακαλούμε επικοινωνήστε με τον διαχειριστή σας. Έναρξη εγγραφής + Διακοπή εγγραφής + Η συγκατάθεση εγγραφής απαιτείται για όλες τις κλήσεις + Απαιτείται συγκατάθεση εγγραφής πριν από τη συμμετοχή σε κλήση σε αυτή τη συνομιλία + Συγκατάθεση εγγραφής + Η κλήση μπορεί να καταγράφεται. Καταγραφή + Επαναφορά κατάστασης Αποθήκευση Scan QR Code Συγχρονισμός μόνο με έμπιστους διακομιστές. @@ -382,6 +428,7 @@ Αποστολή email Αποστολή σε Αποστολή σε … + Αποστολή χωρίς ειδοποίηση Ορισμός Ορισμός κατάστασης Ορισμός μηνύματος κατάστασης @@ -390,8 +437,10 @@ Αρχείο Μέσα ενημέρωσης Άλλο + Δημοσκόπηση Ομιλία Αγαπημένο + Δημιουργία συζήτησης Μήνυμα κατάστασης Βγάλε μια φωτογραφία Αποστολή @@ -400,14 +449,21 @@ 30 λεπτά Αυτή την εβδομάδα Αυτό το Σαββατοκύριακο + Ειδοποιήσεις συζήτησης + Τίτλος συζήτησης + Συζητήσεις Σήμερα Αύριο Μετάφραση + Αντιγραφή μεταφρασμένου κειμένου Ανίχνευση γλώσσας Ρυθμίσεις συσκευής Δεν ήταν δυνατός ο εντοπισμός της γλώσσας + Η μετάφραση απέτυχε Από Έως + Απο-αρχειοθέτηση συνομιλίας + Απο-αποκλεισμός Μη αναγνωσμένο Μεταφόρτωση νέας εικόνας προφίλ από την συσκευή Άβαταρ χρήστη @@ -422,4 +478,8 @@ Δεν ορίστηκαν προσωπικές πληροφορίες Προσθέστε όνομα, εικόνα και λεπτομέρειες επικοινωνίας στο προφίλ σας. Ποια είναι η κατάστασή σας; + + %d απάντηση + %d απαντήσεις + diff --git a/app/src/main/res/values-es/strings.xml b/app/src/main/res/values-es/strings.xml index 927505c..103b2c5 100644 --- a/app/src/main/res/values-es/strings.xml +++ b/app/src/main/res/values-es/strings.xml @@ -67,7 +67,6 @@ carpeta Cargando … %1$s (%2$d) - Hilos suscritos 4 horas Fallo al obtener invitaciones pendientes (editado) @@ -671,6 +670,7 @@ Notificaciones para hilos Responder Título del hilo + Hilos No se encontraron hilos Hoy Mañana diff --git a/app/src/main/res/values-et-rEE/strings.xml b/app/src/main/res/values-et-rEE/strings.xml index 84a63ed..5db65f2 100644 --- a/app/src/main/res/values-et-rEE/strings.xml +++ b/app/src/main/res/values-et-rEE/strings.xml @@ -67,7 +67,6 @@ kaust Laadimisel... %1$s (%2$d) - Jutulõngad, mida sa jälgid 4 tundi Ootel kutsete laadimine ei õnnestunud (muudetud) @@ -670,6 +669,7 @@ Jutulõngade teavitused Vasta Jutulõnga pealkiri + Jutulõngad Ühtegi jutulõnga ei leidu Täna Homme diff --git a/app/src/main/res/values-eu/strings.xml b/app/src/main/res/values-eu/strings.xml index f8aa767..03992d7 100644 --- a/app/src/main/res/values-eu/strings.xml +++ b/app/src/main/res/values-eu/strings.xml @@ -79,6 +79,7 @@ Hasi idazten bilatzeko … Bilatu … Mezuak + Isilarazi jakinarazpen guztiak Aukeratutako kontua inportatu da eta eskuragarri dago Honi buruz Erabiltzaile aktiboa diff --git a/app/src/main/res/values-fr/strings.xml b/app/src/main/res/values-fr/strings.xml index 5cebfd8..06cfe12 100644 --- a/app/src/main/res/values-fr/strings.xml +++ b/app/src/main/res/values-fr/strings.xml @@ -67,7 +67,6 @@ Dossier Chargement… %1$s (%2$d) - Conversations suivies 4 heures Échec de la récupération des invitations en attente (modifié) @@ -667,6 +666,7 @@ Notifications de conversation Répondre Titre de la conversation + Conversations 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 ceaef09..13c8425 100644 --- a/app/src/main/res/values-ga/strings.xml +++ b/app/src/main/res/values-ga/strings.xml @@ -67,7 +67,6 @@ fillteán Á lódáil… %1$s (%2$d) - Snáitheanna leanta 4 uair an chloig Theip ar chuirí ar feitheamh a fháil (in eagar) @@ -670,6 +669,7 @@ Fógraí snáithe Freagra Teideal an snáithe + Snáitheanna Níor aimsíodh aon snáitheanna Inniu Amárach diff --git a/app/src/main/res/values-gl/strings.xml b/app/src/main/res/values-gl/strings.xml index d5a807a..3d7e3a7 100644 --- a/app/src/main/res/values-gl/strings.xml +++ b/app/src/main/res/values-gl/strings.xml @@ -67,7 +67,6 @@ cartafol Cargando… %1$s (%2$d) - Fíos seguidos 4 horas Produciuse un fallo ao recuperar os convites pendentes (editado) @@ -105,7 +104,7 @@ Comece a escribir para buscar… Buscar… Mensaxes - Enmudecer todas as notificacións + Silenciar todas as notificacións A conta seleccionada foi importada e xa está dispoñíbel Sobre Usuario activo @@ -375,14 +374,14 @@ Participantes Engadir participantes Contrasinal - Establecer os permisos + Estabelecer os permisos Algúns permisos foron denegados. Autorice os permisos Abrir os axustes Conceda os permisos en Axustes > Permisos Non se atopou a conta Parolar a través de %s - Enmudecer o micrófono + Silenciar o micrófono Activar o micrófono Mensaxes Privacidade @@ -588,7 +587,7 @@ Non foi posíbel ler o código QR. Erguer a man Todo - Non é posible compartir ficheiros desde o almacenamento sen permisos + Non é posíbel compartir ficheiros desde o almacenamento sen permisos Fíos recentes Estase a gravar a chamada Cancelar o inicio da gravación @@ -608,9 +607,9 @@ Cambióuselle o nome a conversa %1$s Volver enviar Restabelecer o estado - Non é posible unirse a outras salas mentres está nunha chamada + Non é posíbel unirse a outras salas mentres está nunha chamada Gardar - Scan QR Code + Escanear o código QR Sincronizar só con servidores de confianza Federado Visíbel só para as persoas desta instancia e os convidados @@ -655,7 +654,7 @@ Cambiar á sala principal Tirar unha foto Produciuse un erro ao tirar a foto - Non é posible tirar unha foto sen permisos + Non é posíbel tirar unha foto sen permisos Volver tirar a foto Enviar Cambiar de cámara @@ -670,6 +669,7 @@ Notificacións de fíos Responder Título do fío + Fíos Non se atopou ningún fío Hoxe Mañá diff --git a/app/src/main/res/values-hu-rHU/strings.xml b/app/src/main/res/values-hu-rHU/strings.xml index a9ed840..809e40d 100644 --- a/app/src/main/res/values-hu-rHU/strings.xml +++ b/app/src/main/res/values-hu-rHU/strings.xml @@ -5,6 +5,7 @@ Hozzáadás a jegyzetekhez A(z) %1$s beszélgetés hozzáadva a kedvencekhez Keresés itt: %s + Megjelenés nem kapcsolódottként Beszélgetés archiválása Ha archivál egy beszélgetést, akkor alapértelmezetten el lesz rejtve. Válassza az „Archiválva” szűrőt az archivált beszélgetések megtekintéséhez. A közvetlen említéseket továbbra is meg fogja kapni. Archiválva @@ -48,6 +49,7 @@ Veszélyes területet %1$s itt: %2$s Profilkép törlése + Hangfelvétel törlése %1$s beszélgetés törlése Ne zavarjanak Ne törölje @@ -77,6 +79,10 @@ Elhagyta a következő beszélgetést: %1$s További találatok betöltése Helyi idő: %1$s + Hely engedély szükséges + Engedélyezze az alkalmazásbeállításokban + Helyszolgáltatások letiltva + A funkció használatához engedélyezze a helyszolgáltatásokat (GPS) Beszélgetés zárolása Zár szimbólum Kéz letétele @@ -90,6 +96,7 @@ Legnagyobb elöl Legkisebb elöl Üzenet másolva + Biztos, hogy törli ezt az üzenetet? Törölte az üzenetet Szerkesztette: %1$s Koppintson a szavazás megnyitásához @@ -97,6 +104,7 @@ Kezdjen el gépelni a kereséshez… Keresés… Üzenetek + Összes értesítés némítása A kiválasztott fiók importálva lett és elérhető Leírás Aktív felhasználó @@ -326,6 +334,7 @@ Üzenet elolvasva Küldés Üzenet elküldve + A mikrofon engedélyezve van, és a hang felvételre kerül A hanghívás engedélyezéséhez meg kell adnia a „Mikrofon” engedélyt. Nem fogadott hívás a következőtől: %s Moderátor @@ -411,6 +420,7 @@ Keresés törlése Fiók kiválasztása Üzenet frissítése + Hangfelvétel küldése Érzékeny beszélgetés Az üzenet-előnézet le lesz tiltva a beszélgetési listában és az értesítésekben %1$s GIF képet küldött. @@ -543,15 +553,18 @@ Nincs archivált beszélgetés Nincs mentett offline üzenet A hiányzó engedélyek miatt nincs telefonszám-integráció - Minden üzenet + Összes üzenet csak @-megemlítések + Ki Alapértelmezett + Beszélgetésbeállítások követése 1 óra Elérhető Elérhető állapot Beszélgetések megnyitása Megnyitás a Fájlok alkalmazásban Jegyzetek megnyitása + Ugrás a szálhoz Hangüzenet lejátszása/szüneteltetése Lejátszási sebesség vezérlése Lehetőség hozzáadása @@ -571,9 +584,11 @@ Szavazat leadása Szavazat leadva Előzőleg beállított + A QR-kód nem olvasható el Kéz felemelése Összes A fájlok megosztása a tárhelyről engedély nélkül nem lehetséges + Legutóbbi szálak A hívásról felvétel készül Felvétel indításának megszakítása A felvétel sikertelen. Lépjen kapcsolatba a rendszergazdával. @@ -594,7 +609,7 @@ Állapot visszaállítása Hívás közben nem lehet más szobákhoz csatlakozni Mentés - Scan QR Code + QR-kód leolvasása Szinkronizálás csak a megbízható kiszolgálókkal Föderált Csak az ezen a példányon lévő személyek és a vendégek láthatják @@ -631,6 +646,7 @@ Kitiltott résztvevők megjelenítése Kedvenc Nincs jogosultsága hívást indítani + Szál létrehozása hívás indítás Állapotüzenet Üzenet visszaállítva @@ -649,6 +665,12 @@ Ez a hét Ez egy tesztüzenet Ezen a hétvégén + Szál létrehozásának megszakítása + Szálértesítések + Válasz + Szál címe + Szálak + Nem találhatók szálak Ma Holnap Lefordítás @@ -694,6 +716,10 @@ Ez a beszélgetés %1$d nap tétlenség után mindenkinél törölve lesz Ez a beszélgetés %1$d nap tétlenség után mindenkinél törölve lesz + + %d válasz + %d válasz + %d szavazat %d szavazat diff --git a/app/src/main/res/values-it/strings.xml b/app/src/main/res/values-it/strings.xml index 8d7399b..6e01104 100644 --- a/app/src/main/res/values-it/strings.xml +++ b/app/src/main/res/values-it/strings.xml @@ -2,11 +2,15 @@ Modifica Aggiungi + Aggiungi alle Note + Aggiunta conversazione %1$s ai preferiti Cerca in %s Appari non in linea Archivia conversazione + Una volta archiviata, una conversazione verrà nascosta per impostazione predefinita. Seleziona il filtro “Archiviate” per visualizzare le conversazioni archiviate. Le menzioni dirette continueranno a essere ricevute. Archiviati Archiviato %1$s + Chiamata audio Bluetooth Uscita audio Telefono @@ -15,9 +19,14 @@ Stato impostato automaticamente Avatar Assente + Tasto indietro + Bandisci + Bandisci partecipante + Lista dei bandi Occupato Calendario Opzioni avanzate per le chiamate + La chiamata è in corso da un\'ora. Chiama senza notifica Autorizzazione fotocamera concessa. Scegli di nuovo la fotocamera. Annulla l\'accesso @@ -25,44 +34,77 @@ Cancella il messaggio di stato Cancella il messaggio di stato dopo Chiudi + Chiudi Icona Connessione stabilita + Nessuna connessione al server + Connessione persa - I messaggi inviati sono in coda + Blocca registrazione per registrare in modo continuo il messaggio vocale + La conversazione è archiviata + La conversazione è in sola lettura + Impossibile impostare conversazione in Sola-lettura Conversazioni Crea conversazione + Crea problema Personalizzato Zona pericolosa + %1$s in %2$s Elimina avatar + Cancella registrazione vocale + Cancellata conversazione %1$s Non disturbare Non cancellare Modifica + Messaggi più vecchi di 24 ore non possono essere modificati Modifica messaggio Recenti Cifrato + Termina chiamata + Termina chiamata per tutti Si è verificato un problema durante il caricamento delle tue chat + Si è verificato un errore durante la rimozione del ban dal partecipante Salvataggio di %1$s fallito 15 minuti cartella Caricamento … %1$s (%2$d) - Argomenti seguiti 4 ore + Impossibile recuperare gli inviti in sospeso + (modificato) + Note interne Invisibile + Impossibile recuperare le lingue + Recupero non riuscito Più tardi oggi Lascia la chiamata + Hai lasciato la conversazione %1$s Mostra altri risultati + Ora locale: %1$s + Autorizzazione alla localizzazione negata + Abilitala nelle impostazioni dell\'app. + Servizi di localizzazione disattivati + Abilita i servizi di localizzazione (GPS) per utilizzare questa funzione. Blocca conversazione Simbolo lucchetto Abbassa la mano + Contrassegna la conversazione %1$s come letta + Contrassegna la conversazione %1$s come non letta + Citato Prima i più recenti Prima i più datati A - Z Z - A Prima i più grandi Prima i più piccoli + Messaggio copiato + Vuoi davvero eliminare questo messaggio? Messaggio eliminato da te + Modificato da %1$s + Premi per aprire il sondaggio Nessun risultato di ricerca Inizia a digitare per cercare … Cerca … Messaggi + Muta tutte le notifiche L\'account selezionato è ora importato e disponibile Informazioni Utente attivo @@ -77,13 +119,19 @@ OK, tutto fatto! Appunta: %1$s Sblocca %1$s + Per abilitare gli altoparlanti Bluetooth, concedi l\'autorizzazione “Dispositivi vicini”. Rispondi come videochiamata Rispondi solo come chiamata vocale Cambia l\'uscita audio + Attiva/disattiva fotocamera Riaggancia + Attiva/disattiva microfono + Apri la modalità picture-in-picture + Passa al video personale IN ARRIVO Nome della conversazione Notifiche di chiamata + %1$s ha alazato la mano Riconnessione in corso … STA SQUILLANDO %1$s in chiamata @@ -93,13 +141,17 @@ %s chiamata %s videochiamata %s chiamata vocale + Per abilitare la comunicazione video, concedi l\'autorizzazione “Fotocamera”. Annulla Recupero delle capacità non riuscito, interruzione in corso + Sottotitolo Ti fidi del certificato SSL fino ad ora sconosciuto, rilasciato da %1$s per %2$s, valido da %3$s a %4$s? Controlla il certificato La tua configurazione SSL ha impedito la connessione Cambia certificato di autenticazione Cambia password + Cancella modifica + Cancella modifica Elimina tutti i messaggi Tutti i messaggi sono stati eliminati Vuoi davvero eliminare tutti i messaggi in questa conversazione? @@ -119,15 +171,18 @@ Seleziona certificato di autenticazione Connessione in corso… Fine + Descrizione della conversazione Informazioni di conversazione Chiamata video Chiamata vocale + Conversazione non trovata Impostazioni conversazione Unisciti a una conversazione o iniziane una nuova Saluta i tuoi amici e i tuoi colleghi! Copia Crea una nuova conversazione Crea sondaggio + Tu: Oggi Ieri Elimina @@ -136,31 +191,69 @@ Se elimini la conversazione, sarà eliminata anche per tutti i partecipanti. Elimina messaggio Messaggio eliminato correttamente, ma potrebbe essere stato distribuito ad altri servizi + Cancella ora + L\'utente %1$s è stato rimosso Declassa da moderatore Registra messaggio vocale Invia messaggio Account attuale Server + App di notifica server installata? Utente + Stato utente abilitato? Versione Android Applicazione Nome applicazione + Utenti registrati + Versione App + L\'ottimizzazione della batteria viene ignorata, tutto bene + L\'ottimizzazione della batteria è abilitata e potrebbe causare problemi. È necessario disabilitare l\'ottimizzazione della batteria! Impostazioni batteria Dispositivo + Apri la lista di controllo per la risoluzione dei problemi + Apri schermata diagnosi + Apri dontkillmyapp.com + Ultimo recupero token push Firebase + Generazione dell\'ultimo token push Firebase + Nessun token push Firebase impostato. Si prega di creare una segnalazione di bug. + Firebase push token + I servizi Google Play non sono disponibili. Le notifiche non sono supportate. + Servizi Google Play + Servizi Google Play non disponibili + Ultima registrazione push presso il proxy push + Non ancora registrato su push proxy + Ultima registrazione push sul server + Non ancora registrato sul server + Meta informazioni + Generazione del rapporto di sistema + Canale di notifica delle chiamate abilitato? + Canale di notifica dei messaggi abilitato? + Permessi di notifica Telefono Versione del server Talk + Versione server Esterno Interni + Modalità di segnalazione Password non valida + Il server è attualmente in modalità di manutenzione. + L\'app non è aggiornata + L\'app è troppo vecchia e non è più supportata da questo server. Si prega di aggiornare. Aggiorna Vuoi autorizzare nuovamente o eliminare questo account? + Salvare questo file multimediale nella memoria consentirà a tutte le altre app presenti sul dispositivo di accedere a questo. + Continuare? No + Salvare nella memoria? Il nome visualizzato non può essere recuperato, interruzione in corso Nome visualizzato non memorizzato, interruzione in corso Modifica Modifica Modifica messaggio + Modificato da admin + Menu conversazione evento + Programma 8 ore 4 settimane Spenta @@ -172,8 +265,12 @@ Recupero delle impostazioni di segnalazione non riuscito Accetta Rifiuta + da %1$s a %2$s Nessun invito in attesa + Hai inviti in attesa Indietro + È richiesta l\'autorizzazione per l\'accesso al file + Filtra conversazioni Utente che segue un collegamento pubblico Tu: %1$s Inoltra @@ -184,17 +281,27 @@ Gruppo Ospite Accesso ospiti + Impossibile abilitare/disabilitare l\'accesso ospite. + Consenti agli ospiti di condividere un link pubblico per partecipare a questa conversazione. Consenti ospiti Digita una password + Password per accesso ospiti + Errore durante l\'impostazione/disattivazione della password. Imposta una password per limitare chi può utilizzare il collegamento pubblico. Protezione password Rispedisci inviti + Gli inviti non sono stati inviati a causa di un errore. + Gli inviti sono stati inviati nuovamente. Condividi collegamento della conversazione Digita un messaggio … + L\'ottimizzazione della batteria non viene ignorata. Questo dovrebbe essere modificato per garantire che le notifiche funzionino in background! Fare clic su OK e selezionare \"Tutte le app\" -> %1$s -> Non ottimizzare + Ignora ottimizzazione batteria Conversazione importante Lo stato utente “Non disturbare” viene ignorato per le conversazioni importanti. + Orario non valido Inviti Entra nelle conversazioni aperte + Mantieni Devi promuovere un nuovo moderatore prima di poter lasciare la conversazione. %1$s | Ultima modifica: %2$s Lascia la conversazione @@ -214,12 +321,22 @@ Non impostato Segna come letto Segna come non letto + Conversazione contrassegnata come importante + Conversazione non contrassegnata come sensibile + Conversazione contrassegnata come sensibile + Conversazione non contrassegnata come importante + Meeting terminato + Messaggio aggiunto alle note Non riuscito Invio del messaggio non riuscito: Offline Annulla risposta Messaggio letto + Inviando Messaggio inviato + Il microfono è attivato e l\'audio è in registrazione. + Per abilitare la comunicazione vocale, concedi l\'autorizzazione “Microfono”. + Hai perso una chiamata da %s Moderatore Nuova conversazione Visibilità @@ -228,7 +345,11 @@ %1$s non disponibile (non installato o limitato dall\'amministratore) Ospite No + Nessuna conversazione aperta + Non ci sono conversazioni aperte a cui puoi partecipare.\nO non ci sono conversazioni aperte o hai già partecipato a tutte. Nessun proxy + Non è consentito attivare l\'audio! + Non è consentito attivare il video! Non ora %1$s sul canale di notifica %2$s Chiamate @@ -236,19 +357,28 @@ Messaggi Notifica sui messaggi in arrivo Caricamenti + Notifica sullo stato di avanzamento del caricamento Impostazioni di notifica + Le notifiche non sono configurate correttamente + Le impostazioni relative alle notifiche e alla batteria sono configurate correttamente per ricevere le notifiche. Se riscontri comunque problemi nella ricezione delle notifiche, verifica che i canali di notifica per chiamate e messaggi siano abilitati. Ulteriori informazioni sono disponibili su DontKillMyApp.com o nella lista di controllo per la risoluzione dei problemi. Se ciò non fosse d\'aiuto, vai alla schermata di diagnosi e invia una segnalazione di bug. + Risoluzione dei problemi relativi alle notifiche Notifica sempre Notifica su menzione Non notificare mai Attualmente non in linea, controlla la tua connettività OK + Meeting in corso Apri la conversazione agli utenti registrati Apri anche agli utenti dell\'applicazione ospite Proprietario Partecipanti Aggiungi partecipanti Password + Imposta permessi + Alcuni permessi sono stati negati. + Per favore, concedi i permessi Apri impostazioni + Concedi i permessi da Impostazioni > Permessi Account non trovato Chat tramite %s Spegni microfono @@ -259,22 +389,29 @@ Promuovi a moderatore Conversazione pubblica Notifiche push disabilitate + Qualcosa è andato storto, l\'errore è %1$s + Ci dispiace, si è verificato un errore, impossibile recuperare il messaggio di prova. + La notifica push è stata inviata con successo. Ora dovresti ricevere una notifica su questo dispositivo con il titolo “Test delle notifiche push”. Premi per parlare Con il microfono disabilitato, fai clic e mantieni per utilizzare Premi per parlare Ricordamelo più tardi Rimuovi dai preferiti Rimuovi gruppo e membri Rimuovi partecipante + Rimuovi Password + Rimuovi team e membri Rinomina conversazione Rinomina Rispondi Rispondi in privato + La camera è stata prenotata con successo. Salva Salvato correttamente 30 secondi 5 minuti 1 minuto 10 minuti + Immediato 600 60 30 @@ -282,6 +419,8 @@ Cerca Svuota ricerca Seleziona account + Aggiorna messaggio + Invia registrazione vocale Conversazione delicata L\'anteprima dei messaggi sarà disabilitata nell\'elenco delle conversazioni e nelle notifiche. %1$s ha inviato una GIF. @@ -292,6 +431,7 @@ Hai inviato un audio. %1$s ha inviato un\'immagine. Hai inviato un\'immagine. + %1$s ha mandato una scheda Deck Prova di connessione al server Aggiorna il tuo database %1$s Importazione dell\'account selezionato non riuscita @@ -307,18 +447,25 @@ Indirizzo server https://… %1$s funziona solo con %2$s 13 e successivi Imposta una nuova password + Imposta Password Impostazioni Il tuo account preesistente è stato aggiornato, invece di aggiungerne un nuovo Avanzate Aspetto Chiamate + Per favore, contatta l\'amministratore di + Apri la schermata di diagnosi per controllare le impostazioni o creare un rapporto sui bug + Diagonsi Ordina alla tastiera di disattivare l\'apprendimento personalizzato (senza garanzie) Tastiera incognito Nessun suono L\'applicazione Talk non è installata sul server sul quale hai provato ad autenticarti Notifiche + Le notifiche sono state rifiutate + Le notifiche sono state concesse Messaggi Verifica i contatti in base al numero di telefono per integrare il collegamento di Talk nell\'applicazione dei contatti di sistema + Errore 429 Troppe Richieste Puoi impostare il tuo numero di telefono in modo che gli altri utenti ti trovino Digita numero di telefono Numero di telefono non valido @@ -345,12 +492,16 @@ La versione del server è molto datata e non sarà più supportata nella prossima versione! La versione del server è troppo datata e non supportata da questa versione dell\'applicazione Android Server non supportato + App di notifiche server non installata + Impostato dal risparmio batteria Scuro Usa valori predefiniti di sistema tema Chiaro Tema Condividi il mio stato di digitazione e mostra lo stato di digitazione degli altri. + Lo stato di digitazione è disponibile solo quando si utilizza un backend ad alte prestazioni (HPB). + Stato di digitazione Il proxy richiede credenziali Avviso Può essere autorizzato nuovamente solo l\'account attuale @@ -363,25 +514,35 @@ Scegli account Oggetti condivisi Scheda di Deck + Immagini, file, messaggi vocali … Nessun elemento condiviso Posizione Posizione condivisa Quando le notifiche non sono impostate correttamente, mostra un avviso regolare Mostra avviso di notifica regolare Ordina per + Inizia chat di gruppo Ora di inizio Cambia account Team + Prova notifiche push + Risultati test + Oggi alle %1$s + Domani alle %1$s Scegli i file Inviare questi file a %1$s? Inviare questo file a %1$s? Spiacenti, caricamento non riuscito + Impossibile caricare %1$s Problema Condividi da %1$s Carica dal dispositivo Caricamento + %1$s a %2$s - %3$s\%% Scatta foto + Cattura video Utente + Registrazione video da %1$s Registrazione Talk da %1$s (%2$s) Tieni premuto per registrare, rilascia per inviare. Autorizzazione di registrazione audio richiesta @@ -389,32 +550,64 @@ Webinar Settimana successiva + Nessuna conversazione archiviato + Nessun messaggio offline salvato Nessuna integrazione del numero di telefono a causa di autorizzazioni mancanti + Tutti i messaggi + \@-solo menzioni Spento Predefinito + Segui le impostazioni della conversazione 1 ora In linea Stato in linea Apri conversazioni Apri nell\'applicazione File + Apri note + Vai all\'argomento Riproduci/ferma messaggio vocale + Velocità di riproduzione Aggiungi opzione + Modifica voto + Termina sondaggio + Vuoi davvero terminare questo sondaggio? Non è possibile annullare l\'operazione. + Non puoi votare con più opzioni per questo sondaggio. + Risposta multipla + Cancella opzione %1$d + Opzione %1$d Opzioni Sondaggio privato Domanda + La tua domanda Risultati Impostazioni Votare + Voto inviato Impostato in precedenza + Il QR code non può essere letto Alza la mano Tutti La condivisione dei file dall\'archiviazione non è possibile senza permessi + Argomenti recenti + La chiamata viene registrata + Annulla avvio registrazione + La registrazione è fallita. Per favore, contatta un amministratore. + Avvia registrazione + Vuoi davvero interrompere la registrazione? + Interrompi registrazione chiamata + Termina registrazione + Interrompi registrazione … Il permesso di registrazione è richiesto per tutte le call + La registrazione potrebbe includere la tua voce, il video dalla telecamera e la condivisione dello schermo. È necessario il tuo consenso prima di partecipare alla chiamata. Acconsenti? Richiedi il consenso alla registrazione prima di partecipare alla chiamata in questa conversazione Permesso di registrazione La chiamata potrebbe essere registrata. Registrazione + Conversazione %1$s rimossa dai preferiti + La conversazione %1$s è stata rinominata + Reinvia Ripristina stato + Non è possibile entrare in altre stanze mentre si è impegnati in una chiamata. Salva Scan QR Code Sincronizza solo con server fidati @@ -428,24 +621,37 @@ Cambio di ambito Cambia livello di privacy di %1$s Scorri in fondo + Cerca Icona secondi fa Selezionato Invia email Invia a + Non è consentito condividere contenuti in questa chat. Invia a… + Invia messaggio senza notifica Imposta + Imposta avatar dalla fotocamera Imposta stato Imposta messaggio di stato Condividi + Partecipa alla conversazione %1$s su %2$s Audio File Media Altro Sondaggio + Registrazione chiamata Voce + Mostra motivo del bando + Mostra partecipanti banditi Preferito Non ti è consentito avviare una chiamata + Crea un argomeno + ha iniziato una chiamata Messaggio di stato + Stato Ripristinato + Passa a sessione secondaria + Passa a stanza principale Scatta una foto Errore acquisizione immagine Non è possibile scattare una foto senza autorizzazioni @@ -457,21 +663,38 @@ Accendi/spegni la torcia 30 minuti Questa settimana + Questo è un messaggio di test Questo fine settimana + Cancella creazione argomento + Notifiche dagli argomenti + Rispondi + Titolo dell\'argomento + Argomenti + Nessun argomento trovato Oggi Domani Traduci + Traduzione + Copia testo tradotto Rileva lingua Impostazioni dei dispositivi Impossibile rilevare la lingua Traduzione fallita Da A + e 1 altro stanno scrivendo … + stanno scrivendo … + sta scrivendo … + e %1$s altri stanno scrivendo … Disarchivia conversazione + Una volta che una conversazione viene rimossa dall\'archivio, verrà nuovamente visualizzata per impostazione predefinita. Non archiviato %1$s Rimuovi ban Da leggere Carica nuovo avatar dal dispositivo + %1$s è fuori ufficio e potrebbe non rispondere + %1$s è fuori ufficio oggi + Sostituzione: Avatar dell\'utente Indirizzo Nome completo @@ -483,5 +706,26 @@ Impossibile ottenere le informazioni personali dell\'utente. Nessuna informazione personale impostata Aggiungi nome, immagine e dettagli di contatto sulla tua pagina di profilo. + Chiamata video Qual è il tuo stato? - + + Vedi %d messaggio simile + Vedi %d messaggi simili + Vedi %d messaggi simili + + + Questa conversazione verrà automaticamente cancellata per tutti dopo %1$d giorno di inattività. + Questa conversazione verrà automaticamente cancellata per tutti dopo %1$d giorni di inattività. + Questa conversazione verrà automaticamente cancellata per tutti dopo %1$d giorni di inattività. + + + %d risposta + %d risposte + %d risposte + + + %d voto + %d voti + %d voti + + diff --git a/app/src/main/res/values-ja-rJP/strings.xml b/app/src/main/res/values-ja-rJP/strings.xml index c639afd..d0fba1d 100644 --- a/app/src/main/res/values-ja-rJP/strings.xml +++ b/app/src/main/res/values-ja-rJP/strings.xml @@ -166,6 +166,7 @@ 会話を削除すると、ほかの参加者でも一緒に解除されます。 メッセージを削除 メッセージは削除されましたが、他サービスへは転送されている可能性があります。 + 今すぐ削除 ユーザー%1$sは削除されました モデレータから降格 ボイスメッセージを録音 @@ -225,6 +226,7 @@ 編集 メッセージを編集 管理者に編集されました + スケジュール 8時間 4週間 オフ @@ -268,6 +270,7 @@ 重要な会議 招待 オープンな会話に参加する + 保持 会話から離れる前に、新しいモデレーターを昇格させる必要があります %1$s最終更新:%2$s 会話を離れる @@ -289,6 +292,7 @@ 未読にする 失敗しました メッセージの送信に失敗しました: + オフライン 返信をキャンセル メッセージ既読 メッセージ送信済 @@ -366,6 +370,7 @@ 検索 検索をクリア アカウントを選択 + プライベートな会話 %1$sがGIFを送信しました。 GIFを送信しました。 %1$sが動画ファイルを送信しました。 @@ -577,6 +582,8 @@ 今週 これはテストメッセージです この週末 + 返信 + スレッド 今日 明日 翻訳 @@ -606,6 +613,9 @@ 個人情報はありません プロフィールページに名前、写真、連絡先の詳細を追加します。 現在のオンラインステータスは? + + %d件の返信 + %d投票数 diff --git a/app/src/main/res/values-pl/strings.xml b/app/src/main/res/values-pl/strings.xml index c5b4f8f..78ed36c 100644 --- a/app/src/main/res/values-pl/strings.xml +++ b/app/src/main/res/values-pl/strings.xml @@ -67,7 +67,6 @@ katalog Wczytywanie… %1$s (%2$d) - Obserwowane wątki 4 godziny Nie udało się pobrać oczekujących zaproszeń (edytowane) @@ -670,6 +669,7 @@ Powiadomienia wątków Odpowiedź Tytuł wątku + Wątki Nie znaleziono wątków Dzisiaj Jutro diff --git a/app/src/main/res/values-pt-rBR/strings.xml b/app/src/main/res/values-pt-rBR/strings.xml index 7dda2b8..cfba471 100644 --- a/app/src/main/res/values-pt-rBR/strings.xml +++ b/app/src/main/res/values-pt-rBR/strings.xml @@ -67,7 +67,6 @@ pasta Carregando … %1$s (%2$d) - Fios seguidos 4 horas Falha ao buscar convites pendentes (editado) @@ -670,6 +669,8 @@ Notificações de fios Responder Título do fio + Fios + Nenhum fio encontrado Hoje Amanhã Traduzir diff --git a/app/src/main/res/values-ru/strings.xml b/app/src/main/res/values-ru/strings.xml index c72b8b1..4b9eea0 100644 --- a/app/src/main/res/values-ru/strings.xml +++ b/app/src/main/res/values-ru/strings.xml @@ -67,7 +67,6 @@ каталог Загрузка … %1$s (%2$d) - Отслеживаемые темы 4 часа Не удалось получить ожидающие приглашения (изменено) @@ -664,6 +663,7 @@ Уведомления для темы Ответ Заголовок темы + Темы Сегодня Завтра Помочь с переводом diff --git a/app/src/main/res/values-sr/strings.xml b/app/src/main/res/values-sr/strings.xml index b617a4d..a478797 100644 --- a/app/src/main/res/values-sr/strings.xml +++ b/app/src/main/res/values-sr/strings.xml @@ -67,7 +67,6 @@ фасцикли Учитавање… %1$s (%2$d) - Низови које пратите 4 сата Није успело добављање позивница на чекању (уређено) @@ -670,6 +669,7 @@ Обавештења низова Одговори Наслов нити + Нити Није пронађен ниједан низ Данас Сутра diff --git a/app/src/main/res/values-sv/strings.xml b/app/src/main/res/values-sv/strings.xml index 316ba5b..3465dc5 100644 --- a/app/src/main/res/values-sv/strings.xml +++ b/app/src/main/res/values-sv/strings.xml @@ -66,7 +66,6 @@ mapp Läser in … %1$s (%2$d) - Följda trådar 4 timmar Kunde inte hämta väntande inbjudningar (redigerad) @@ -553,6 +552,8 @@ Inga arkiverade konversationer Inga offlinemeddelanden sparade Ingen telefonnummerintegrering på grund av saknade behörigheter + Alla meddelanden + Endast @-omnämnanden Av Förvald Följ konversationsinställningar @@ -666,6 +667,8 @@ Trådaviseringar Svara Trådtitel + Trådar + Inga trådar hittades Idag I morgon Översätt diff --git a/app/src/main/res/values-sw/strings.xml b/app/src/main/res/values-sw/strings.xml index cd866e3..a91fc6b 100644 --- a/app/src/main/res/values-sw/strings.xml +++ b/app/src/main/res/values-sw/strings.xml @@ -67,7 +67,6 @@ folda Inapakia %1$s (%2$d) - Mazungumzo yaliyofuatwa Masaa 4 Imeshindwa kuleta mialiko ambayo haijashughulikiwa (imehaririwa) @@ -672,6 +671,7 @@ Arifa za mjadala Jibu Kichwa cha mjadala + Mijadala Hakuna nyuzi zilizopatikana Leo Kesho diff --git a/app/src/main/res/values-tr/strings.xml b/app/src/main/res/values-tr/strings.xml index d39f16b..74e83e1 100644 --- a/app/src/main/res/values-tr/strings.xml +++ b/app/src/main/res/values-tr/strings.xml @@ -67,7 +67,6 @@ klasör Yükleniyor… %1$s (%2$d) - Takip edilen yazışmalar 4 saat Bekleyen davetler alınamadı (düzenlendi) @@ -670,6 +669,7 @@ Yazışma bildirimleri Yanıtla Yazışma başlığı + Yazışmalar Herhangi bir yazışma bulunamadı Bugün Yarın diff --git a/app/src/main/res/values-uk/strings.xml b/app/src/main/res/values-uk/strings.xml index cab7c82..289e889 100644 --- a/app/src/main/res/values-uk/strings.xml +++ b/app/src/main/res/values-uk/strings.xml @@ -67,7 +67,6 @@ каталог Завантаження … %1$s (%2$d) - Відстежувані теми 4 години Не вдалося отримати очікувані запрошення (відредаговано) @@ -661,6 +660,7 @@ Цими вихідними Відхилити створення гілки Назва гілки + Нитки Сьогодні Завтра Перекласти diff --git a/app/src/main/res/values-zh-rCN/strings.xml b/app/src/main/res/values-zh-rCN/strings.xml index 2c527b2..7fa6c41 100644 --- a/app/src/main/res/values-zh-rCN/strings.xml +++ b/app/src/main/res/values-zh-rCN/strings.xml @@ -48,7 +48,6 @@ 文件夹 正在加载 … %1$s (%2$d) - 关注的帖子 4小时 (已编辑) 隐身 @@ -286,7 +285,7 @@ 当被提及时提醒 从不提醒 当前离线,请检查您的连接 - OK + 确定 向注册用户开放对话 同样对访客用户开放 所有者 @@ -548,6 +547,7 @@ 本周末 帖子通知 帖子‌标题 + 帖子‌ 今天 明天 翻译 @@ -579,7 +579,7 @@ 检索个人用户信息失败 未设置个人信息 在你的个人资料页上添加姓名、图片和联系方式。 - 你什么状态? + 您的状态如何? %d 票 diff --git a/app/src/main/res/values-zh-rHK/strings.xml b/app/src/main/res/values-zh-rHK/strings.xml index 61c45b6..aeaf70f 100644 --- a/app/src/main/res/values-zh-rHK/strings.xml +++ b/app/src/main/res/values-zh-rHK/strings.xml @@ -67,7 +67,6 @@ 資料夾 加載中 … %1$s(%2$d) - 關注的討論串 4 小時 無法擷取待定的邀請 (已編輯) @@ -670,6 +669,7 @@ 討論串通知 回覆 討論串標題 + 討論串 找不到討論串 今日 明日 diff --git a/app/src/main/res/values-zh-rTW/strings.xml b/app/src/main/res/values-zh-rTW/strings.xml index 16e4864..a9d7885 100644 --- a/app/src/main/res/values-zh-rTW/strings.xml +++ b/app/src/main/res/values-zh-rTW/strings.xml @@ -67,7 +67,6 @@ 資料夾 正在載入…… %1$s (%2$d) - 已追蹤的討論串 4小時 擷取擱置中的邀請失敗 (已編輯) @@ -670,6 +669,7 @@ 討論串通知 回覆 討論串標題 + 討論串 找不到討論串 今天 明天 diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index cc40c3c..01c5cd8 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -554,12 +554,12 @@ How to translate with transifex: and %1$s others are typing … %1$s in %2$s + Threads Go to thread Create a thread Thread title Cancel thread creation Recent threads - Followed threads Reply %d reply diff --git a/app/src/test/java/com/nextcloud/talk/messagesearch/MessageSearchHelperTest.kt b/app/src/test/java/com/nextcloud/talk/messagesearch/MessageSearchHelperTest.kt index 814c70b..9e51c4b 100644 --- a/app/src/test/java/com/nextcloud/talk/messagesearch/MessageSearchHelperTest.kt +++ b/app/src/test/java/com/nextcloud/talk/messagesearch/MessageSearchHelperTest.kt @@ -27,8 +27,9 @@ class MessageSearchHelperTest { title: String = "foo", messageExcerpt: String = "foo", conversationToken: String = "foo", - messageId: String? = "foo" - ) = SearchMessageEntry(searchTerm, thumbnailURL, title, messageExcerpt, conversationToken, messageId) + messageId: String? = "foo", + threadId: String? = "foo" + ) = SearchMessageEntry(searchTerm, thumbnailURL, title, messageExcerpt, conversationToken, threadId, messageId) @Before fun setUp() { diff --git a/gradle/verification-metadata.xml b/gradle/verification-metadata.xml index f77a341..85186c8 100644 --- a/gradle/verification-metadata.xml +++ b/gradle/verification-metadata.xml @@ -20218,6 +20218,11 @@ + + + + + @@ -20396,6 +20401,11 @@ + + + + + @@ -20486,6 +20496,11 @@ + + + + + @@ -21826,6 +21841,11 @@ + + + + + @@ -21852,6 +21872,11 @@ + + + + + @@ -21873,6 +21898,11 @@ + + + + + @@ -21899,6 +21929,11 @@ + + + + + @@ -21920,6 +21955,11 @@ + + + + + diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties index 2a84e18..2e11132 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-9.0.0-bin.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-9.1.0-bin.zip networkTimeout=10000 validateDistributionUrl=true zipStoreBase=GRADLE_USER_HOME diff --git a/gradlew b/gradlew index ef07e01..adff685 100755 --- a/gradlew +++ b/gradlew @@ -114,7 +114,6 @@ case "$( uname )" in #( NONSTOP* ) nonstop=true ;; esac -CLASSPATH="\\\"\\\"" # Determine the Java command to use to start the JVM. @@ -172,7 +171,6 @@ fi # For Cygwin or MSYS, switch paths to Windows format before running java if "$cygwin" || "$msys" ; then APP_HOME=$( cygpath --path --mixed "$APP_HOME" ) - CLASSPATH=$( cygpath --path --mixed "$CLASSPATH" ) JAVACMD=$( cygpath --unix "$JAVACMD" ) @@ -212,7 +210,6 @@ DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"' set -- \ "-Dorg.gradle.appname=$APP_BASE_NAME" \ - -classpath "$CLASSPATH" \ -jar "$APP_HOME/gradle/wrapper/gradle-wrapper.jar" \ "$@" diff --git a/gradlew.bat b/gradlew.bat index 5eed7ee..e509b2d 100644 --- a/gradlew.bat +++ b/gradlew.bat @@ -70,11 +70,10 @@ goto fail :execute @rem Setup the command line -set CLASSPATH= @rem Execute Gradle -"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" -jar "%APP_HOME%\gradle\wrapper\gradle-wrapper.jar" %* +"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -jar "%APP_HOME%\gradle\wrapper\gradle-wrapper.jar" %* :end @rem End local scope for the variables with windows NT shell