From 2c531a5e676eb7a7570826c582d896df79d056df Mon Sep 17 00:00:00 2001 From: alperozturk Date: Fri, 5 Dec 2025 14:38:39 +0100 Subject: [PATCH 001/216] chore: 3.35.0 RC1 Signed-off-by: alperozturk --- app/build.gradle.kts | 2 +- fastlane/metadata/android/en-US/30350051.txt | 12 ++++++++++++ fastlane/metadata/android/en-US/30350051.txt.license | 2 ++ 3 files changed, 15 insertions(+), 1 deletion(-) create mode 100644 fastlane/metadata/android/en-US/30350051.txt create mode 100644 fastlane/metadata/android/en-US/30350051.txt.license diff --git a/app/build.gradle.kts b/app/build.gradle.kts index 470eede4ce09..6a877768922a 100644 --- a/app/build.gradle.kts +++ b/app/build.gradle.kts @@ -65,7 +65,7 @@ configurations.configureEach { val versionMajor = 3 val versionMinor = 35 val versionPatch = 0 -val versionBuild = 0 // 0-50=Alpha / 51-98=RC / 90-99=stable +val versionBuild = 51 // 0-50=Alpha / 51-98=RC / 90-99=stable val ndkEnv = buildMap { file("${project.rootDir}/ndk.env").readLines().forEach { diff --git a/fastlane/metadata/android/en-US/30350051.txt b/fastlane/metadata/android/en-US/30350051.txt new file mode 100644 index 000000000000..9625e2ecc070 --- /dev/null +++ b/fastlane/metadata/android/en-US/30350051.txt @@ -0,0 +1,12 @@ +## 3.35.0 RC1 (December 5, 2025) + +- Auto-upload logic completely redesigned and improved +- Improved file listing performance (shared, favorites, and navigation) +- New chat feature in assistant +- Enhanced unified search +- Minimum Android version: 9 +- Bug fixes and stability improvements + +Minimum: NC 20 Server, Android 9 Pie + +For a full list, please see https://github.com/nextcloud/android/milestone/118 \ No newline at end of file diff --git a/fastlane/metadata/android/en-US/30350051.txt.license b/fastlane/metadata/android/en-US/30350051.txt.license new file mode 100644 index 000000000000..3804756b12c8 --- /dev/null +++ b/fastlane/metadata/android/en-US/30350051.txt.license @@ -0,0 +1,2 @@ +# SPDX-FileCopyrightText: 2025 Nextcloud GmbH and Nextcloud contributors +# SPDX-License-Identifier: AGPL-3.0-or-later \ No newline at end of file From e8056523af2d6b5fe01dcb41f13bf8b044cbc466 Mon Sep 17 00:00:00 2001 From: alperozturk Date: Fri, 5 Dec 2025 09:35:13 +0100 Subject: [PATCH 002/216] fix: group folder adapter crash Signed-off-by: alperozturk --- .../com/owncloud/android/ui/adapter/GroupFolderListAdapter.kt | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/app/src/main/java/com/owncloud/android/ui/adapter/GroupFolderListAdapter.kt b/app/src/main/java/com/owncloud/android/ui/adapter/GroupFolderListAdapter.kt index db2f5527d57a..19d05b70a6b0 100644 --- a/app/src/main/java/com/owncloud/android/ui/adapter/GroupFolderListAdapter.kt +++ b/app/src/main/java/com/owncloud/android/ui/adapter/GroupFolderListAdapter.kt @@ -1,6 +1,7 @@ /* * Nextcloud - Android Client * + * SPDX-FileCopyrightText: 2025 Alper Ozturk * SPDX-FileCopyrightText: 2023 Tobias Kaminsky * SPDX-FileCopyrightText: 2023 Nextcloud GmbH * SPDX-License-Identifier: AGPL-3.0-or-later OR GPL-2.0-only @@ -27,7 +28,7 @@ class GroupFolderListAdapter( private val groupFolderListInterface: GroupfolderListInterface, private val isDarkMode: Boolean ) : RecyclerView.Adapter() { - lateinit var list: List + private var list: List = listOf() fun setData(result: Map) { list = result.values.sortedBy { it.mountPoint } From 8d0ccec7c8db6f59bb1102698a5c9da9f80d40b6 Mon Sep 17 00:00:00 2001 From: alperozturk Date: Fri, 5 Dec 2025 15:39:08 +0100 Subject: [PATCH 003/216] fix: auto upload worker crash Signed-off-by: alperozturk --- .../java/com/nextcloud/client/jobs/BackgroundJobManagerImpl.kt | 1 - 1 file changed, 1 deletion(-) diff --git a/app/src/main/java/com/nextcloud/client/jobs/BackgroundJobManagerImpl.kt b/app/src/main/java/com/nextcloud/client/jobs/BackgroundJobManagerImpl.kt index 51aa55843538..ed9aaefa6eff 100644 --- a/app/src/main/java/com/nextcloud/client/jobs/BackgroundJobManagerImpl.kt +++ b/app/src/main/java/com/nextcloud/client/jobs/BackgroundJobManagerImpl.kt @@ -501,7 +501,6 @@ internal class BackgroundJobManagerImpl( TimeUnit.SECONDS ) .setInputData(arguments) - .setExpedited(OutOfQuotaPolicy.RUN_AS_NON_EXPEDITED_WORK_REQUEST) .build() workManager.enqueueUniquePeriodicWork( From ba0e367001f2de1fe3eb5e3e721e2d0597b43ce3 Mon Sep 17 00:00:00 2001 From: alperozturk Date: Fri, 5 Dec 2025 15:55:52 +0100 Subject: [PATCH 004/216] create changelogs directory Signed-off-by: alperozturk --- fastlane/metadata/android/en-US/{ => changelogs}/30350051.txt | 0 .../metadata/android/en-US/{ => changelogs}/30350051.txt.license | 0 2 files changed, 0 insertions(+), 0 deletions(-) rename fastlane/metadata/android/en-US/{ => changelogs}/30350051.txt (100%) rename fastlane/metadata/android/en-US/{ => changelogs}/30350051.txt.license (100%) diff --git a/fastlane/metadata/android/en-US/30350051.txt b/fastlane/metadata/android/en-US/changelogs/30350051.txt similarity index 100% rename from fastlane/metadata/android/en-US/30350051.txt rename to fastlane/metadata/android/en-US/changelogs/30350051.txt diff --git a/fastlane/metadata/android/en-US/30350051.txt.license b/fastlane/metadata/android/en-US/changelogs/30350051.txt.license similarity index 100% rename from fastlane/metadata/android/en-US/30350051.txt.license rename to fastlane/metadata/android/en-US/changelogs/30350051.txt.license From 90721586632a285530ebb6829a7295e2fed2d977 Mon Sep 17 00:00:00 2001 From: Nextcloud bot Date: Sat, 6 Dec 2025 02:47:08 +0000 Subject: [PATCH 005/216] fix(l10n): Update translations from Transifex Signed-off-by: Nextcloud bot --- app/src/main/res/values-ar/strings.xml | 20 +------ app/src/main/res/values-ast/strings.xml | 11 +--- app/src/main/res/values-b+en+001/strings.xml | 22 ++------ app/src/main/res/values-bg-rBG/strings.xml | 12 +---- app/src/main/res/values-br/strings.xml | 11 +--- app/src/main/res/values-ca/strings.xml | 18 +------ app/src/main/res/values-cs-rCZ/strings.xml | 18 ------- app/src/main/res/values-da/strings.xml | 18 ------- app/src/main/res/values-de/strings.xml | 20 +------ app/src/main/res/values-el/strings.xml | 12 ----- app/src/main/res/values-eo/strings.xml | 7 +-- app/src/main/res/values-es-rAR/strings.xml | 16 +----- app/src/main/res/values-es-rCO/strings.xml | 14 +---- app/src/main/res/values-es-rEC/strings.xml | 12 +---- app/src/main/res/values-es-rMX/strings.xml | 17 +----- app/src/main/res/values-es/strings.xml | 20 +------ app/src/main/res/values-et-rEE/strings.xml | 27 +++------- app/src/main/res/values-eu/strings.xml | 21 +------- app/src/main/res/values-fa/strings.xml | 16 +----- app/src/main/res/values-fi-rFI/strings.xml | 19 +------ app/src/main/res/values-fr/strings.xml | 21 +------- app/src/main/res/values-ga/strings.xml | 29 ++++------ app/src/main/res/values-gd/strings.xml | 8 +-- app/src/main/res/values-gl/strings.xml | 23 ++------ app/src/main/res/values-hr/strings.xml | 13 +---- app/src/main/res/values-hu-rHU/strings.xml | 21 +------- app/src/main/res/values-in/strings.xml | 21 +------- app/src/main/res/values-is/strings.xml | 21 +------- app/src/main/res/values-it/strings.xml | 18 +------ app/src/main/res/values-iw/strings.xml | 10 +--- app/src/main/res/values-ja-rJP/strings.xml | 21 +------- app/src/main/res/values-ka/strings.xml | 13 +---- app/src/main/res/values-ko/strings.xml | 20 +------ app/src/main/res/values-lo/strings.xml | 21 +------- app/src/main/res/values-lt-rLT/strings.xml | 17 +----- app/src/main/res/values-lv/strings.xml | 12 +---- app/src/main/res/values-mk/strings.xml | 11 +--- app/src/main/res/values-nb-rNO/strings.xml | 18 +------ app/src/main/res/values-nl/strings.xml | 21 +------- app/src/main/res/values-pl/strings.xml | 21 +------- app/src/main/res/values-pt-rBR/strings.xml | 27 +++------- app/src/main/res/values-pt-rPT/strings.xml | 18 +------ app/src/main/res/values-ro/strings.xml | 17 +----- app/src/main/res/values-ru/strings.xml | 22 +------- app/src/main/res/values-sc/strings.xml | 9 +--- app/src/main/res/values-sk-rSK/strings.xml | 21 +------- app/src/main/res/values-sl/strings.xml | 14 +---- app/src/main/res/values-sq/strings.xml | 9 +--- app/src/main/res/values-sr-rSP/strings.xml | 7 +-- app/src/main/res/values-sr/strings.xml | 21 +------- app/src/main/res/values-sv/strings.xml | 21 +------- app/src/main/res/values-sw/strings.xml | 21 +------- app/src/main/res/values-th-rTH/strings.xml | 10 +--- app/src/main/res/values-tk/strings.xml | 8 +-- app/src/main/res/values-tr/strings.xml | 21 +------- app/src/main/res/values-ug/strings.xml | 56 +++++++++++++------- app/src/main/res/values-uk/strings.xml | 21 +------- app/src/main/res/values-vi/strings.xml | 13 +---- app/src/main/res/values-zh-rCN/strings.xml | 21 +------- app/src/main/res/values-zh-rHK/strings.xml | 23 ++------ app/src/main/res/values-zh-rTW/strings.xml | 23 ++------ 61 files changed, 165 insertions(+), 929 deletions(-) diff --git a/app/src/main/res/values-ar/strings.xml b/app/src/main/res/values-ar/strings.xml index 16392ec44aca..8ed15c818c37 100644 --- a/app/src/main/res/values-ar/strings.xml +++ b/app/src/main/res/values-ar/strings.xml @@ -44,23 +44,17 @@ عرض أداة واحدة من لوحة المعلومات بحث في %s الحالة غير متصل - إضافة مهمة جديدة - أنشِئ مهمة جديدة من الأسفل - أكتُب أيَّ نص هل أنت متأكد أنك ترغب بحذف هذه المهمة؟ حذف المهمّة حاول إرسالة رسالة لإثارة محادثة. أهلاً بك! كيف يمكنني مساعدتك اليوم؟ - تحميل قائمة المهام ... حدث خطأ أثناء إنشاء المهمة تمّ إنشاء المهمة بنجاح حدث خطأ أثناء حذف المهمة تمّ حذف المهمة بنجاح - قائمة المهام فارغة. تعذّر جلب قائمة المهام. قم رجاءً بالتحقُّق من اتصالك بالإنترنت. حذف مهمة مخرجات المهمة ليست جاهزة بعد. - تعذّر جلب أنواع المهام. قم رجاءً بالتحقُّق من اتصالك بالإنترنت. المُساعِد مُدخَلات المُخرَجَات @@ -121,6 +115,7 @@ مشغول التقويم التقاويم + Cancel هناك مشكلة في تحميل الشهادة المتغيرات في تطبيق المطورين عُد إليه فيما بعد أو أعد تحميله @@ -207,7 +202,6 @@ لا توجد أي محادثات حتى الآن محادثات نُسخت - تم النسخ إلى الحافظة حدث خطأٌ خلال محاولة نسخ هذا الملف أو المجلد لا يمكن نسخ مجلد في مجلدات هوَّ يتضمنها الملف موجود بالفعل في المجلد الوجهة @@ -404,10 +398,8 @@ التحميل جارٍ … لم يُعّد التطبيق يدعم نوع الملف هذا. منذ ثواني - التصريح مطلوب تصريحات التخزين %1$s يعمل بشكل أفضل مع أذونات الوصول إلى التخزين. يمكنك اختيار الوصول الكامل إلى جميع الملفات، أو الوصول للقراءة فقط إلى الصور ومقاطع الفيديو. - %1$s يحتاج إلى أذونات إدارة الملفات لرفع الملفات. يمكنك اختيار الوصول الكامل إلى جميع الملفات، أو الوصول للقراءة فقط إلى الصور ومقاطع الفيديو. السماح بالوصول من التطبيقات الأخرى جار التحقق من الوجهة… تنظيف… @@ -443,7 +435,6 @@ إعادة التسمية فشل الرفع. لايوجد اتصال بالإنترنت حدث خطأ في استيراد إصدار الملف! - تم استيراد إصدار الملف بنجاح. التفاصيل تحميل تصدير @@ -478,7 +469,6 @@ محلّي : %1$s نقل الكل عن بعد : %1$s - تم نقل كافة الملفات إعادة توجيه 4 ساعات قامت Google بتقييد تنزيل ملفات APK/AAB! @@ -532,7 +522,6 @@ تمّ إقفاله من التطبيق%1$s %1$s سجلات تطبيق الأندرويد لا يوجد تطبيق لارسال السجلات . الرجاء تثبيت عميل البريد الالكتروني. - الدخول كـ%1$s تسجيل الدخول الرابط الخاص بك %1$s يكون واجهة الموقع عند فتحها في المتصفح احذف السجلات @@ -630,7 +619,6 @@ وصل الخادم إلى نهاية العمر الافتراضي ، يرجى الترقية! المزيد من القائمة أدخل رمزك السري - سيتم طلب رمز المرور في كل مرة يتم فيها تشغيل التطبيق أدخل رمزك السري من فضلك الرمزين السريين لا يتطابقان أعد إدخال رمزك السري @@ -638,11 +626,10 @@ تمت إزالة الرمز السري رمز المرور المخزن رمز المرور غير صحيح + إيقاف غير قادر على فتح ملف PDF محمي بكلمة مرور. الرجاء استخدام عارض PDF خارجي. - اضغط على الصفحة لتكبيرها سماح رفض - الصلاحيات الإضافية المطلوبة لتحميل وتنزيل الملفات. إختَر جهة اتصال للمشاركة معها لم يتم العثور على تطبيق لتعيين صورة به ثبِّت في الشاشة الرئيسية @@ -836,7 +823,6 @@ شارك الرابط أرسل الرابط غير محدد - شارك مع… الصورة الرمزية من المستخدم المشترك شارك المشاركات @@ -889,7 +875,6 @@ التخزين الداخلي الأفلام الموسيقى - النفاذ الكامل الوسائط للقراءة فقط الصور منصة الإنتاجية ذاتية الاستضافة التي تبقيك تحت السيطرة.\nهذه هي النسخة التطويرية الرسمية ، وتضم عينة يومية من أي وظيفة جديدة غير مختبرة ، والتي قد تسبب عدم الاستقرار وفقدان البيانات. التطبيق مخصص للمستخدمين الراغبين في الاختبار والإبلاغ عن الأخطاء في حالة حدوثها. لا تستخدمه لعملك الإنتاجي!\n\nيتوفر كل من النسخة الرسمية والنسخة التطويرية على F-droid، ويمكن تثبيتهما في نفس الوقت. @@ -1032,7 +1017,6 @@ تعذّر العثور على الملف. هل أنت متأكد من وجود هذا الملف؛ أم أنه هنالك تعارضاً لم يُحل حتى الآن؟ لم نتمكن من إيجاد الملف على الخادم. يمكن أن يكون قد تمّ حذفه من قِبل مُستخدِمٍ آخر اسم المجلد - إعادة عملية الرفع غير الناجحة للملفات المحلية اختر مجلد للرفع فشل الرفع %1$s فشل الرفع ، قم بتسجيل الدخول مرة أخرى diff --git a/app/src/main/res/values-ast/strings.xml b/app/src/main/res/values-ast/strings.xml index a471cad91d37..f1cdfd434851 100644 --- a/app/src/main/res/values-ast/strings.xml +++ b/app/src/main/res/values-ast/strings.xml @@ -24,10 +24,8 @@ Puertu del proxy Buscar en: %s Apaecer desconectáu - Escribi daqué Desaniciar la xera Nun ye posible dir en cata de la llista de xeres. Comprueba la conexón a internet. - Nun ye posible dir en cata de los tipos de xeres. Comprueba la conexón a internet. Asistente Entrada Salida @@ -63,6 +61,7 @@ Ocupáu Calendariu Calendarios + Cancel Hai un problema cargando\'l certificáu Caxellu Borrar @@ -103,7 +102,6 @@ Nun s\'atopó nenguna conversación Conversaciones Copióse - Copióse nel cartafueyu Asocedió un fallú entrín s\'intentaba copiar esta carpeta o ficheru El ficheru yá ta presente na carpeta destín Nun ye posible copiar. Comprueba si\'l ficheru esiste. @@ -237,7 +235,6 @@ Cargando… Nun s\'afitó una aplicación pa remanar esta triba de ficheru. hai segundos - Precísense permisos Permisos d\'almacenameintu Comprobando\'l destín… Precísase más espaciu @@ -284,7 +281,6 @@ Llocal: %1$s Mover too Llugar remotu: %1$s - Moviéronse tolos ficheros Avanzar 4 hores Esti iconu amuesa la disponibilidá de la semeya en direuto @@ -373,7 +369,6 @@ El sirvidor algamó la fin de vida. ¡Anueva! Menú de Más Introduz el to códigu de pasu - La contraseña va ser solicitada cada vegada que s\'anicie l\'aplicación Introduz el to códigu de pasu, por favor Les contraseñes nun son les mesmes Por favor, vuelvi inxertar la contraseña @@ -381,11 +376,10 @@ Desanicióse\'l códigu d\'accesu Contraseña almacenada Contraseña incorrecta + Posar Nun ye posible abrir el PDF protexíu con contraseña. Usa un visor de PDFs esternu. - Toca nuna páxina p\'averar Permitir Negar - Ríquense permisos adicionales pa xubir y baxar ficheros. Abrir «%1$s» desanicióse guardáu en carpeta orixinal @@ -528,7 +522,6 @@ Almacenamientu internu Filmes Música - Accesu completu Semeyes Añu/Mes/Día Añu/Mes diff --git a/app/src/main/res/values-b+en+001/strings.xml b/app/src/main/res/values-b+en+001/strings.xml index d9c7ec8d78c5..967a05a04442 100644 --- a/app/src/main/res/values-b+en+001/strings.xml +++ b/app/src/main/res/values-b+en+001/strings.xml @@ -45,26 +45,20 @@ Search in %s Appear offline Output shown here is generated by AI. Make sure to always double-check. - Add new task Failed to send a message Failed to fetch chat messages - Create a new task from bottom right - Type some text Are you sure you want to delete this task? Delete task Try sending a message to spark a conversation. Hello there! What can I help you with today? - Loading task list… An error occurred while creating the task Task successfully created An error occurred while deleting the task Task successfully deleted - Task list is empty. Task list is empty. Check assistant app configuration. Unable to fetch task list, please check your internet connection. Delete Task The task output is not ready yet. - Unable to fetch task types, please check your internet connection. Assistant Input Output @@ -133,6 +127,7 @@ Busy Calendar Calendars + Cancel There is a problem loading the certificate. Changelog dev version Check back later or reload. @@ -225,7 +220,6 @@ Failed to fetch conversation list Conversations Copied - Copied to clipboard An error occurred while trying to copy this file or folder It is not possible to copy a folder into one of its own underlying folders The file is already present in the destination folder @@ -329,6 +323,7 @@ Assistant More More Nextcloud Apps + Cannot open file chooser Failed to pick email address. Set as encrypted Unable to retrieve server certificate @@ -398,6 +393,7 @@ You don’t have permission to create or upload files in this folder. External shares Add or upload + Failed to create conflict dialog Failed to pass file to download manager Failed to print file Failed to start editor @@ -439,10 +435,8 @@ Loading… No app set up to handle this file type. seconds ago - Permissions needed Storage permissions %1$s works best with permissions to access storage. You can choose full access to all files, or read-only access to photos and videos. - %1$s needs file management permissions to upload files. You can choose full access to all files, or read-only access to photos and videos. Allow access from other apps Checking destination… Cleaning… @@ -480,7 +474,6 @@ Upload failed. No internet connection %s already exists, no conflict detected Error restoring file version! - Successfully restored file version. Details Download Export @@ -520,7 +513,6 @@ Local: %1$s Move all Remote: %1$s - All files were moved Forward 4 hours Google restricts the download of APK/AAB files! @@ -575,7 +567,6 @@ Locked by %1$s app %1$s Android app logs No app for sending logs found. Please install an email client. - Logged in as %1$s Log in The link to your %1$s web interface when you open it in the browser. Delete logs @@ -678,7 +669,6 @@ The server has reached end of life, please upgrade! More menu Enter your passcode - The passcode will be requested every time the app is started Please enter your passcode The passcode will be requested every time the app is opened or reopened after 5 seconds. The passcodes are not the same @@ -688,10 +678,8 @@ Passcode stored Incorrect passcode Unable to open password-protected PDF. Please use an external PDF viewer. - Tap on a page to zoom in Allow Deny - Additional permissions required to upload and download files. Pick contact to share with No app found to set a picture with Pin to home screen @@ -800,7 +788,6 @@ Failed to remove notification. Remove Deleted - Remove Enter a new name Could not rename local copy, try a different name Renaming not possible, name already taken @@ -896,7 +883,6 @@ Share link Send link Unset - Share with… Avatar from shared user share shared @@ -953,7 +939,6 @@ Storage permission is required for Auto-upload. Storage permission is required for file uploads. Don\'t ask - Full access Media read-only Pictures The self-hosted productivity platform that keeps you in control.\n\nFeatures:\n* Easy, modern interface, suited to the theme of your server\n* Upload files to your Nextcloud server\n* Share them with others\n* Keep your favorite files and folders synced\n* Search across all folders on your server\n* Auto Upload for photos and videos taken by your device\n* Keep up to date with notifications\n* Multi-account support\n* Secure access to your data with fingerprint or PIN\n* Integration with DAVx⁵ (formerly known as DAVdroid) for easy setup of calendar and contacts synchronization\n\nPlease report all issues at https://github.com/nextcloud/android/issues and discuss this app at https://help.nextcloud.com/c/clients/android\n\nNew to Nextcloud? Nextcloud is a private file sync and share and communication server. It is libre software, and you can host it yourself or pay a company to do it for you. That way, you are in control of your photos, your calendar and contact data, your documents and everything else.\n\nCheck out Nextcloud at https://nextcloud.com @@ -1099,7 +1084,6 @@ File not found. Are you sure that this file exists or has a previous conflict not been resolved? We couldnt locate the file on server. Another user may have deleted the file Folder name - Retry to upload failed local files Choose upload folder Could not upload %1$s Upload failed, log in again diff --git a/app/src/main/res/values-bg-rBG/strings.xml b/app/src/main/res/values-bg-rBG/strings.xml index 02dd6d37c7d5..2276e65904d4 100644 --- a/app/src/main/res/values-bg-rBG/strings.xml +++ b/app/src/main/res/values-bg-rBG/strings.xml @@ -95,6 +95,7 @@ Зает Kалендар Kалендари + Cancel Проблем при зареждане на сертификата. Версия за разработка на журнал за промени Проверка отново по-късно или презареждане. @@ -175,7 +176,6 @@ Изтриване на разговора Няма намерени разговори Разговори - Копирано в клипборда Възникна грешка при опита за копиране на файла или папката Не може да копирате папка в нейна подпапка Файлът вече съществува в зададената папка @@ -345,10 +345,8 @@ Зареждане… Няма приложение, което да се справи с подобен тип файл. преди секунди - Необходими са права Права за хранилище %1$s работи най-добре с права за достъп до хранилище. Можете да изберете пълен достъп до всички файлове или достъп само за четене на снимки и видеоклипове. - %1$s се нуждае от права за управление на файлове, за да качва файлове. Можете да изберете пълен достъп до всички файлове или достъп само за четене на снимки и видеоклипове. Проверка на дестинацията… Почистване… Обновяване на папката за съхранение на данни @@ -374,7 +372,6 @@ Файлът не може да бъде синхронизиран. Показана е актуалната версия. Преименувай Грешка при възстановяването! - Възстанявяването завърши. Подробности Изтегляне Експорт /изнасям/ @@ -404,7 +401,6 @@ Локален: %1$s Премести всички Отдалечен: %1$s - Всички файлове са преместени. Напред 4 чàса Иконата служи за индикация дали \"live photo\" е налична @@ -519,7 +515,6 @@ Сървърът е достигнал края на живота си, моля, надстройте! Повече Въведете кода за достъп - Кода ще бъде изискван при всяко стартиране на приложението Моля, въведете кода за достъп Кодовете не съвпадат Моля, въведете кода за достъп отново @@ -527,10 +522,9 @@ Кодът за достъп е изтрит Кодът е запаметен Грешен код - Докосване на страницата за увеличение на мащаба + Пауза Да Не - Изискват се допълнителни права за изтегляне и сваляне на файлове. Няма намерени приложения за задаване на снимка Отваряне на %1$s стоп @@ -684,7 +678,6 @@ Връзка за споделяне Изпратете връзката Зануляване - Споделете чрез ... Аватар от споделен потребител сподели споделено @@ -735,7 +728,6 @@ Вътрешна памет Филми Музика - Пълен достъп Медия само за четене Снимки Самостоятелно хостваната платформа за производителност, която ви помага да поддържате контрол. \ NТова е официалната версия за разработка, включваща ежедневна извадка от всяка нова непроверена функционалност, която може да причини нестабилност и загуба на данни. Приложението е за потребители, които желаят да тестват и да докладват грешки, ако възникнат. Не го използвайте за вашата продуктивна работа! \ N \ nИ двете версии - официалната за разработчици и обикновената версия са налични на F-droid и могат да бъдат инсталирани едновременно. diff --git a/app/src/main/res/values-br/strings.xml b/app/src/main/res/values-br/strings.xml index 1b2367e255f2..05b67da706a0 100644 --- a/app/src/main/res/values-br/strings.xml +++ b/app/src/main/res/values-br/strings.xml @@ -33,7 +33,6 @@ Porzh Proksi Diskouez a ra ur widget dre daolenn-vourzh Klask e %s - Skrivañ un tamm testenn Ha sur oc\'h e fell deoc\'h dilemel an trevell-mañ ? C\'hoarvezet ez eus ur fazi en ur grouiñ an trevell Trevell bet krouet ervat @@ -41,7 +40,6 @@ Trevell bet dilamet ervat N\'eus ket bet gallet tizhout ar roll trevelloù, gwiriit ho kevreadenn genrouedad. Dilemel an trevell - N\'eus ket bet gallet tizhout ar seurtoù trevelloù, gwiriit ho kevreadenn genrouedad. Skoazeller Enmont Ezvont @@ -100,6 +98,7 @@ O labourat Deiziataer Deiziataerioù + Cancel Ur gudenn zo bet evit kargañ an testeni. Stumm diorren marilh ar c\'hemmoù Gwiriañ diwezhatoc\'h pe adkargañ. @@ -179,7 +178,6 @@ N\'eus ket bet gallet kavout ho savete diwezhañ ! Dilemel an diviz Diviz - Eilet er golver C\'hoarvezet ez eys ur fazi en ur glask eilañ ar restr pe ar renkell Ne c\'haller ket eilañ ur renkell en unan eus hec\'h isrenkelloù Er renkell bal emañ ar restr c\'hoazh @@ -359,7 +357,6 @@ O kargañ... N\'eus bet kefluniet arload ebet evit merañ ar seurt restroù-mañ. eilenn zo - Rekis eo bezañ aotreet Aotreoù sanailhet O wiriañ ar pal... O naetaat... @@ -384,7 +381,6 @@ N\'eo ket posuple kempredañ ar restr. O diskwell ar stumm diwezha kavet. Adenvel Ur fazi zo bet en ur adober stumm ar restr ! - Adtapet eo bet stumm ar restr. Munudoù Pellgargañ ar restr a zo bet adanvet %1$s e pad ar bellkas @@ -412,7 +408,6 @@ Diabarzh: %1$s Dblasañ pep tra Pell : %1$s - Diblaset eo bet tout ar restroù War-raok Anv Notenn @@ -500,7 +495,6 @@ E fin buhez eo ar servijour, adnevesiit mar-plij ! Muioc\'h a rollioù Lakait o c\'hod-tremen - Ar c\'hod-tremen a vo goulennet bewech a vo lakaet war dro ar meziant-mañ Enankit ho kod-tremen Disheñvel eo ar c\'hodoù tremen Enankit en-dro ho kod tremen @@ -508,9 +502,9 @@ Dilamet eo bet ar c\'hod tremen Kod tremen enrollet Kod tremen direizh + Ehanañ Aotrañ Difennet - Aotreoù ouzhpenn ez eus ezhomp evit pellkas ha pellgargañ restroù. Meziant ebet kavet evit lakaat ur skeudenn gant Disaotreañ gwiriañ ar saver pod-tredañ a c\'hel lezel an ardivink pellkargañ restroù pa ne vez ket kalz a dredañ kenn ! dilamet @@ -628,7 +622,6 @@ Rannan liamm Kal liamm N\'eo ket bet lakaet - Rannañ gant ... Avatar deus un implijer rannet rannadenn rannet diff --git a/app/src/main/res/values-ca/strings.xml b/app/src/main/res/values-ca/strings.xml index 5ea87123c138..6ec01058f7ba 100644 --- a/app/src/main/res/values-ca/strings.xml +++ b/app/src/main/res/values-ca/strings.xml @@ -42,22 +42,17 @@ Mostra un giny del tauler Cerca a %s Apareixeu fora de línia - Afegeix una tasca nova - Escriu una mica de text Segur que voleu suprimir aquesta tasca? Suprimeix la tasca Prova d\'enviar un missatge per iniciar una conversa. Hola! En què et puc ajudar avui? - S\'està carregant la llista de tasques... S\'ha produït un error en crear la tasca La tasca s\'ha creat correctament S\'ha produït un error en suprimir la tasca La tasca s\'ha suprimit correctament - La llista de grups està buida. No s\'ha pogut obtenir la llista de tasques. Comproveu la vostra connexió a Internet. Suprimeix la tasca La sortida de la tasca encara no està a punt. - No s\'han pogut obtenir els tipus de tasques. Comproveu la connexió a Internet. Assistent Entrada Sortida @@ -117,6 +112,7 @@ Ocupat Calendari Calendaris + Cancel Hi ha un problema carregant el certificat. Històric de canvis de la versió de desenvolupament Torneu-ho a comprovar més tard o torneu a carregar. @@ -204,7 +200,6 @@ Encara no hi ha converses Converses Copiat - Copiat al porta-retalls Hi ha hagut un error en copiar aquest fitxer o carpeta No és possible copiar una carpeta a cap de les que conté El fitxer ja existeix a la carpeta de destinació @@ -395,10 +390,8 @@ S\'està carregant… No hi ha cap aplicació configurada per gestionar aquest tipus de fitxer. fa uns segons - Es necessiten permisos Permisos d\'emmagatzematge %1$streballa millor amb permisos d\'accés a l\'emmagatzematge. Podeu triar entre accés complet als fitxers o accés de només lectura a fotografies i vídeos. - %1$snecessita permisos de gestió de fitxers per a la pujada de fitxers. Podeu triar entre accés complet als fitxers o accés de només lectura a fotografies i vídeos. Permet l\'accés des d\'altres aplicacions S\'està comprovant la destinació… S\'està netejant… @@ -433,7 +426,6 @@ El fitxer no s\'ha pogut sincronitzar. Se\'n mostra la darrera versió disponible. Canvia el nom S\'ha produït un error restaurant la versió del fitxer! - Versió del fitxer restaurada amb èxit. Detalls Baixada Exporta @@ -467,7 +459,6 @@ Local: %1$s Mou-los tots Remot: %1$s - S\'han mogut tots els fitxers Endavant 4 hores Google ha restringit la baixada de fitxers APK/AAB! @@ -521,7 +512,6 @@ Blocat per l\'aplicació %1$s %1$s registres de la aplicació d\'Android. No s\'ha trobat cap aplicació per enviar els registres. Instal·leu un client de correu electrònic. - S\'ha iniciat la sessió com a %1$s Inicia la sessió Enllaç a la interfície web del %1$s quan l\'obriu en el navegador. Suprimeix els registres @@ -610,7 +600,6 @@ El servidor ha arribat al final de la seva vida, si us plau actualitzeu! Menú més Escriviu el vostre codi d\'accés - Es requerirà el codi d\'accés cada vegada que s\'iniciï l\'aplicació Escriviu el codi d\'accés Els codis d\'accés no coincideixen Torneu a escriure el codi d\'accés @@ -618,11 +607,10 @@ S\'ha suprimit el codi d\'accés S\'ha desat el codi d\'accés Codi d\'accés incorrecte + Posa en pausa No s\'ha pogut obrir el PDF protegit amb contrasenya. Utilitzeu un visor PDF extern. - Toca en una pàgina per ampliar Permet Denega - Es necessiten permisos addicionals per pujada i baixada de fitxers. Trieu el contacte amb què compartir No s\'ha trobat cap aplicació per establir-hi la foto Fixa-ho a la pantalla d\'inici @@ -796,7 +784,6 @@ Comparteix l\'enllaç Envia l\'enllaç No definit - Comparteix amb… Avatar de l\'usuari compartit comparteix compartit @@ -847,7 +834,6 @@ Emmagatzematge intern Peŀlícules Música - Accés complet Medis de només lectura Fotos La plataforma de productivitat privada (auto-allotjada) que us dóna el control sobre les vostres dades.\nAquesta és la versió oficial en desenvolupament, que permet provar qualsevol novetat diària, i que per tant pot causar inestabilitat i fins i tot la pèrdua de dades. Aquesta aplicació és pels usuaris que estan disposats a provar i informar d\'incidències. No feu servir aquesta versió de l\'aplicació en el vostre entorn de feina!\n\nAmbdues versions, la de desenvolupament i la normal, són disponibles a F-droid, i poden ser instal·lades al mateix temps. diff --git a/app/src/main/res/values-cs-rCZ/strings.xml b/app/src/main/res/values-cs-rCZ/strings.xml index 66a8886a46d7..61cf6ad18d4c 100644 --- a/app/src/main/res/values-cs-rCZ/strings.xml +++ b/app/src/main/res/values-cs-rCZ/strings.xml @@ -45,24 +45,18 @@ Hledat v %s Jevit se offline Zde zobrazený výstup je vytvořen AI. Vždy si informace ověřujte. - Přidat nový úkol - Z pravého dolního rohu vytvořte nový úkol - Zadejte nějaký text Opravdu chcete tuto úlohu smazat? Smazat úkol Zkuste poslat zprávu pro rozproudění konverzace. Zdravím! Jak vám mohu pomoci? - Načítání seznamu úkolů … Při vytváření úlohy se vyskytla chyba Úloha byla úspěšně vytvořena Při mazání úlohy se vyskytla chyba Úloha úspěšně smazána - Seznam úkolů je prázdný. Seznam úkolů je prázdný. Zkontrolujte nastavení aplikace Asistent. Nedaří se získat seznam úloh – zkontrolujte připojení k Internetu. Smazat úlohu Výstup z úkolu ještě není připraven. - Nedaří se získat typy úloh – zkontrolujte připojení k Internetu. Asistent Vstup Výstup @@ -218,7 +212,6 @@ Zatím žádná konverzace Konverzace Zkopírováno - Zkopírováno do schránky Při pokusu o zkopírování tohoto souboru či složky došlo k chybě Není možné zkopírovat složku do některé z jejích vlastních podsložek Soubor už v cílové složce existuje @@ -431,10 +424,8 @@ Načítání … Není nastaveno pomocí které aplikace otevírat tento typ souboru. před několika sekundami - Vyžadována oprávnění Oprávnění k úložišti %1$s funguje nejlépe s oprávněními pro přístup k úložišti. Je možné zvolit plný přístup k veškerým souborům nebo přístup pouze pro čtení k fotkám a videím. - Aby %1$s mohlo nahrávat soubory na server, potřebuje oprávnění pro správu souborů. Je možné zvolit plný přístup k veškerým souborům nebo přístup pouze pro čtení k fotkám a videím. Umožnit přístup z ostatních aplikací Prověřování cílového umístění … Čištění … @@ -472,7 +463,6 @@ Nahrávání se nezdařilo. Není k dispozici připojení k Internetu %s už existuje – nezjištěny žádné konflikty Chyba při obnovování verze souboru! - Verze souboru úspěšně obnovena. Podrobnosti Stáhnout Exportovat @@ -512,7 +502,6 @@ Místní: %1$s Přesunout vše Vzdálené: %1$s - Všechny soubory byly přesunuty Vpřed 4 hodiny Google omezil stahování APK/AAB souborů! @@ -567,7 +556,6 @@ Uzamčeno aplikací %1$s Záznamy událostí v aplikaci %1$s pro Android Nebyla nalezena žádná aplikace, přes kterou by bylo možné odeslat záznamy událostí. Nainstalujte si e-mailového klienta. - Přihlášeni jako %1$s Přihlásit Odkaz na webové rozhraní vámi využívané instance %1$s, když ho otevíráte ve webovém prohlížeči. Smazat záznamy událostí @@ -670,7 +658,6 @@ Verze aplikace na straně serveru už je příliš stará na to, aby šla nadále používat – přejděte na novější! Další nabídka Zadejte svůj bezpečnostní kód - Bezpečnostní kód bude vyžadován při každém spuštění aplikace Zadejte svůj bezpečnostní kód Bezpečnostní kód bude vyžadován při každém spuštění aplikace nebo jejím znovuotevření za déle než 5 sekund. Zadání bezpečnostního kódu se neshodují @@ -680,10 +667,8 @@ Bezpečnostní kód uložen Nesprávný bezpečnostní kód Nedaří se otevřít heslem chráněné PDF. Použijte externí prohlížeč PDF. - Pokud chcete stránku zvětšit, klepněte na ni Povolit Odepřít - Vyžadována dodatečná oprávnění pro nahrávání a stahování souborů. Vyberte kontakt kterému nasdílet Nenalezena žádná aplikace pro nastavení obrázku Připnout na domovskou obrazovku @@ -885,7 +870,6 @@ Odkaz na sdílení Poslat odkaz Zrušit nastavení - Sdílet s … Avatar uživatele, který nasdílel sdílet sdílené @@ -938,7 +922,6 @@ Vnitřní úložiště Videa Hudba - Plný přístup Média pouze pro čtení Obrázky Platforma pro produktivitu hostovaná u vás, kde vaše data jsou opravdu vaše.\nToto je oficiální vývojová verze, sloužící jako denně aktualizovaná ukázka nových nevyzkoušených funkcí, což může způsobovat nestabilitu a ztráty dat. Je určeno pro uživatele, kteří jsou ochotní testovat a hlásit chyby na které narazí. Nepoužívejte pro svou produktivní práci!\n\nJak vývojová tak produkční verze jsou k dispozici na F-droid a mohou být nainstalovány souběžně. @@ -1083,7 +1066,6 @@ Soubor nenalezen. Opravdu tento soubor existuje nebo má předchozí nevyřešenou kolizi? Soubor se nepodařilo nalézt na serveru. Možná ho smazal jiný uživatel Název složky - Pokus si se znovu nahrát místní soubory Vybrat složku pro nahrávání Nepodařilo se nahrát %1$s Nahrání se nezdařilo, znovu se přihlaste diff --git a/app/src/main/res/values-da/strings.xml b/app/src/main/res/values-da/strings.xml index f681b9aa4093..ff6f06f94e29 100644 --- a/app/src/main/res/values-da/strings.xml +++ b/app/src/main/res/values-da/strings.xml @@ -45,23 +45,17 @@ Søg i %s Er offline Output der vises her er genereret af AI. Vær sikker på at du altid dobbelttjekker indholdet. - Tilføj en ny opgave - Opret en ny opgave fra bunden til højre - Skriv noget tekst Er du sikker på du vil slette denne opgave? Slet opgave Prøv at sende en besked for at starte en samtale. Hej! Hvad kan jeg hjælpe dig med i dag? - Indlæser opgaveliste... En fejl opstod under oprettelse af opgaven Opgaven er oprettet En fejl opstod under sletning af opgaven Opgaven er slettet - Opgavelisten er tom. Kan ikke hente ophaveliste. Kontroller venligst din internetforbindelse. Slet opgave Opgaveoutputtet er endnu ikke klar. - Kan ikke hente opgavetyper. Kontroller venligst din internetforbindelse. Assistent Input Output @@ -215,7 +209,6 @@ Endnu ingen samtaler Samtaler Kopieret - Kopieret til udklipsholder Der opstod en fejl under forsøg på at kopiere denne fil eller mappe Det er ikke muligt at kopiere en mappe til en af dens egne undermapper Filen findes allerede i destinationsmappen @@ -426,10 +419,8 @@ Indlæser... Ingen app er sat op til at håndtere denne filtype. sekunder siden - Tilladelser er nødvendige Tilladelser for lagring %1$s fungerer bedst når adgang til lager tillades. Du kan vælge fuld adgang til alle filer, eller læsebegrænset adgang til fotografier og videoer. - %1$s kræver tilladelse til filhåndtering for at uploade filer. Du kan vælg fuld adgang for alle filer, eller læsebegrænset adgang til fotografier og videoer. Tillad adgang fra andre apps Tjekker destination... Renser ud... @@ -467,7 +458,6 @@ Upload mislykkedes. Ingen internetforbindelse %s eksisterer allerede. Ingen konflikt detekteret Fejl ved genskabning af fil version! - Succes ved genskabning af fil version! Detaljer Download Eksportér @@ -504,7 +494,6 @@ Lokal: %1$s Flyt alle Fjern: %1$s - Alle filer blev flyttet Videresend 4 timer Google begrænser download af APK/AAB filer! @@ -559,7 +548,6 @@ Låst af app\'en %1$s %1$s Android app logfiler Der er ingen app tilgængelig til at sende log filer. Venligst installer en e-mailklient. - Logget på som %1$s Log ind Linket til dit %1$s web interface når du åbner den i browseren. Slet logs @@ -659,7 +647,6 @@ Serveren har nået sit livs ende, opgrader venligst! Mere menu Angiv din passkode - Denne passkode vil blive forespurgt hver gang app\'en startes Indtast venligst din adgangskode Passkode\'erne er ikke ens Indtast venligst dit kodeord igen @@ -668,10 +655,8 @@ Passkode blev gendannet Forkert passkode Ikke i stand til at åbne kodeordsbeskyttet PDF. Brug venligst en ekstern PDF-fremviser. - Tryk på en side for at zoome ind Tillad Afvis - Yderligere tilladelser nødvendige for at hente og sende filer. Vælg en kontakt at dele med Ingen apps fundet til at vælge et billede med Fastgør til hjemmeskærm @@ -874,7 +859,6 @@ Del link Send link Fjern indstilling - Del med... Avatar fra delt bruger Del Delt @@ -927,7 +911,6 @@ Internt lager Film Musik - Fuld adgang Medie skrivebeskyttet Billeder Den selv-hostede produktivitetsplatform som sikrer dig kontrol.\n\nFunktioner:\n* Let, moderne interface, passende til temaet for din server\n* Upload filer til din Nextcloud server\n* Del dem med andre\n* Hold dine favorit filer og mapper synkroniserede\n* Søg på tværs af mapper på din server\n* Auto upload for billeder og videoer taget af dit apparat\n* Hold dig opdateret med notifikationer\n* Multi-konti understøttelse\n* Sikker adgang til dine data med fingeraftryk eller PIN\n* Integration med DAVx⁵ (tidligere kendt som DAVdroid) for let opsætning af kalender- og kontaktsynkronisering\n\nRapporter venligst alle problemer på https://github.com/nextcloud/android/issues og diskuter denne app på https://help.nextcloud.com/c/clients/android\n\nNy i forhold til Nextcloud? Nextcloud er en privat filsynkroniserings, delings- og kommunikationsserver. Det er gratis software, og du kan selv hoste eller betale et firma for at gøre det for dig. På den måde har du fuldstændig kontrol over dine billeder, kalendere, kontaktdata, dine dokumenter og alt andet.\n\nSe Nextcloud på https://nextcloud.com @@ -1073,7 +1056,6 @@ Filen ikke fundet. Er du sikker på at denne file eksisterer eller er en tidligere konflikt ikke blevet løst ? Vi kunne ikke finde filen på serveren. En anden bruger har måske slettet filen Mappenavn - Forsøg igen at uploade fejlede lokale filer Vælg upload mappe Kunne ikke uploade %1$s Overførelse fejlede, log ind igen diff --git a/app/src/main/res/values-de/strings.xml b/app/src/main/res/values-de/strings.xml index fea3bdfdec69..a023c8698a2d 100644 --- a/app/src/main/res/values-de/strings.xml +++ b/app/src/main/res/values-de/strings.xml @@ -45,26 +45,20 @@ Suche in %s Offline erscheinen Die hier gezeigte Ausgabe wurde von KI erstellt. Bitte genau überprüfen. - Neue Aufgabe hinzufügen Eine Nachricht konnte nicht gesendet werden Chatnachrichten konnten nicht abgerufen werden - Unten rechts eine neue Aufgabe erstellen - Bitte einen Text eingeben Möchten Sie diese Aufgabe wirklich löschen? Aufgabe löschen Versuchen Sie, eine Nachricht zu senden, um eine Unterhaltung anzustoßen. Hallo! Womit kann ich Ihnen heute helfen? - Lade Aufgabenliste… Es ist ein Fehler beim Erstellen der Aufgabe aufgetreten Aufgabe erstellt Es ist ein Fehler beim Löschen der Aufgabe aufgetreten Aufgabe gelöscht - Aufgabenliste ist leer. Die Aufgabenliste ist leer. Bitte die Konfiguration der Assistenten-App überprüfen. Die Aufgabenliste kann nicht abgerufen werden. Bitte überprüfen Sie Ihre Internetverbindung. Aufgabe löschen Die Aufgabenausgabe ist noch nicht fertig. - Die Aufgabentypen können nicht abgerufen werden. Bitte überprüfen Sie Ihre Internetverbindung. Assistent Eingabe Ausgabe @@ -225,7 +219,6 @@ Liste der Unterhaltungen konnte nicht abgerufen werden Unterhaltungen Kopiert - In die Zwischenablage kopiert Es ist ein Fehler beim Kopieren der Datei oder des Ordners aufgetreten. Es ist nicht möglich, einen Ordner in einen seiner Unterordner zu kopieren Die Datei existiert bereits im Zielverzeichnis @@ -329,6 +322,7 @@ Assistent Mehr Weitere Nextcloud-Apps + Dateiauswahl konnte nicht geöffnet werden E-Mail-Adresse konnte nicht ausgewählt werden. Als verschlüsselt festlegen Serverzertifikat kann nicht abgerufen werden @@ -398,6 +392,7 @@ Sie haben keine Berechtigung, in diesen Ordner Dateien hochzuladen oder zu erstellen. Externe Freigaben Hinzufügen oder hochladen + Die Erstellung des Konfliktdialogs ist fehlgeschlagen Datei konnte nicht an den Downloadmanager übergeben werden Datei konnte nicht gedruckt werden Editor konnte nicht gestartet werden @@ -439,10 +434,8 @@ Lade… Es wurde keine App für diesen Dateityp gefunden. Gerade eben - Berechtigungen erforderlich Speicherberechtigungen %1$s funktioniert am besten mit Berechtigungen für den Zugriff auf den Speicher. Sie können vollen Zugriff auf alle Dateien oder schreibgeschützten Zugriff auf Fotos und Videos wählen. - %1$s benötigt Dateiverwaltungsberechtigungen, um Dateien hochzuladen. Sie können vollen Zugriff auf alle Dateien oder schreibgeschützten Zugriff auf Fotos und Videos wählen.  Zugriff von anderen Apps zulassen Prüfe Zielort… Aufräumen… @@ -480,7 +473,6 @@ Upload fehlgeschlagen. Keine Internetverbindung %s existiert bereits, kein Konflikt erkannt Fehler beim Wiederherstellen der Dateiversion! - Dateiversion wiederhergestellt Details Herunterladen Exportieren @@ -520,7 +512,6 @@ Lokal: %1$s Alle verschieben Remote: %1$s - Alle Dateien wurden verschoben Weiterleiten 4 Stunden Google hat das Herunterladen von APK/AAB-Dateien eingeschränkt! @@ -575,7 +566,6 @@ Gesperrt von der App %1$s %1$s Android-App Meldungen Keine App zum Senden von Protokolldateien gefunden. Bitte installieren Sie einen E-Mail-Client. - Angemeldet als %1$s Anmelden Der Link zu Ihrer %1$s Webseite, wenn Sie diese im Browser öffnen. Lösche Logs @@ -678,7 +668,6 @@ Die Serverversion wird nicht mehr unterstützt, bitte aktualisieren Sie diesen! Weiteres Menü PIN eingeben - Die PIN wird jedes mal beim Start der App abgefragt Bitte geben Sie Ihre PIN ein Die PIN wird jedes mal beim Start der App oder beim erneuten Öffnen nach 5 Sekunden abgefragt Die PINs stimmen nicht überein @@ -688,10 +677,8 @@ PIN gespeichert PIN nicht korrekt Passwortgeschützte PDF-Datei konnte nicht geöffnet werden. Bitte verwenden Sie einen externen PDF-Viewer. - Auf eine Seite klicken, um hereinzuzoomen Zulassen Ablehnen - Sie haben nicht die erforderlichen Rechte, um Dateien hoch- oder herunterzuladen. Kontakt zum Teilen auswählen Keine App gefunden, mit der ein Bid gesetzt werden könnte An Startbildschirm anheften @@ -895,7 +882,6 @@ Link teilen Link teilen Entfernen - Teilen mit… Avatar des geteilten Nutzers Teilen geteilt @@ -952,7 +938,6 @@ Für das automatische Hochladen ist die Speicherberechtigung erforderlich Um Dateien hochladen zu können, ist die Speicherberechtigung erforderlich Nicht nachfragen - Voller Zugriff Medien schreibgeschützt Bilder Die selbstgehostete Produktivitätsplattform, mit der Sie die Kontrolle behalten.\n\nFunktionen:\n* Einfache, moderne Benutzeroberfläche, die an das Design Ihres Servers angepasst ist\n* Laden Sie Dateien auf Ihren Nextcloud-Server hoch\n* Teilen Sie sie mit anderen\n * Halten Sie Ihre Lieblingsdateien und -ordner synchronisiert\n* Durchsuchen Sie alle Ordner auf Ihrem Server\n* Automatisches Hochladen von Fotos und Videos, die mit Ihrem Gerät aufgenommen wurden\n* Bleiben Sie mit Benachrichtigungen auf dem Laufenden\n* Unterstützung für mehrere Konten\n* Sicherer Zugriff auf Ihre Daten mit Fingerabdruck oder PIN\n* Integration mit DAVx⁵ (früher bekannt als DAVdroid) zur einfachen Einrichtung der Kalender- und Kontaktsynchronisierung\n\nBitte melden Sie alle Probleme unter https://github.com/nextcloud/android/issues und diskutieren Sie über diese App unter https://help.nextcloud.com/c/clients/android\n\nNeu bei Nextcloud? Nextcloud ist ein privater Dateisynchronisierungs-, Freigabe- und Kommunikationsserver. Es handelt sich um kostenlose Software, die Sie selbst, oder gegen Gebühr bei einem Dienstleister hosten können. Auf diese Weise haben Sie die Kontrolle über Ihre Fotos, Ihre Kalender- und Kontaktdaten, Ihre Dokumente und alles andere.\n\nSehen Sie sich Nextcloud unter https://nextcloud.com an. @@ -1098,7 +1083,6 @@ Datei nicht gefunden. Sind Sie sicher, dass diese Datei existiert oder wurde ein früherer Konflikt nicht gelöst? Wir konnten die Datei auf dem Server nicht finden. Ein anderer Benutzer hat möglicherweise die Datei gelöscht. Ordnername - Fehlgeschlagene lokale Dateien erneut hochladen Hochladeordner auswählen Konnte %1$s nicht hochladen Hochladen fehlgeschlagen, bitte erneut anmelden diff --git a/app/src/main/res/values-el/strings.xml b/app/src/main/res/values-el/strings.xml index 2a13b92a3127..7ae9a8f20cbf 100644 --- a/app/src/main/res/values-el/strings.xml +++ b/app/src/main/res/values-el/strings.xml @@ -33,7 +33,6 @@ Εμφάνιση ενός γραφικού στοιχείου από τον πίνακα ελέγχου Αναζήτηση στο %s Τα αποτελέσματα που εμφανίζονται εδώ έχουν δημιουργηθεί από τεχνητή νοημοσύνη. Φροντίστε να τα ελέγχετε πάντα διπλά. - Πληκτρολογήστε κάποιο κείμενο Διαγραφή εργασίας Δοκιμάστε να στείλετε ένα μήνυμα για να ξεκινήσετε μια συνομιλία. Γεια σας! Τι μπορώ να κάνω για σας σήμερα; @@ -174,7 +173,6 @@ Δεν υπάρχουν ακόμη συνομιλίες Συνομιλίες Αντιγράφηκε - Αντιγράφηκε στο πρόχειρο Παρουσιάστηκε σφάλμα κατά την προσπάθεια αντιγραφής αυτού του αρχείου ή φακέλου Δεν είναι δυνατό να αντιγραφεί ο φάκελος σε απογονικό Το αρχείο υπάρχει ήδη στο φάκελο προορισμού @@ -349,10 +347,8 @@ Φόρτωση… Δεν βρέθηκε εφαρμογή για τον τύπο αρχείου. δευτερόλεπτα πριν - Απαιτούνται δικαιώματα Άδειες αποθήκευσης %1$s λειτουργεί καλύτερα με δικαιώματα πρόσβασης στον χώρο αποθήκευσης. Μπορείτε να επιλέξετε πλήρη πρόσβαση σε όλα τα αρχεία ή πρόσβαση μόνο για ανάγνωση σε φωτογραφίες και βίντεο. - %1$s χρειάζεται δικαιώματα διαχείρισης αρχείων για τη μεταφόρτωση αρχείων. Μπορείτε να επιλέξετε πλήρη πρόσβαση σε όλα τα αρχεία ή πρόσβαση μόνο για ανάγνωση σε φωτογραφίες και βίντεο. Γίνεται έλεγχος προορισμού… Γίνεται εκκαθάριση… Γίνεται ενημέρωση φακέλου Αποθήκευση Δεδομένων @@ -378,7 +374,6 @@ Το αρχείο δεν μπόρεσε να συγχρονιστεί. Προβολή της πιο πρόσφατης έκδοσης. Μετονομασία Σφάλμα κατά την επαναφορά έκδοσης αρχείου! - Επιτυχημένη επαναφορά έκδοσης αρχείου. Λεπτομέρειες Λήψη Εξαγωγή @@ -408,7 +403,6 @@ Τοπικά: %1$s Μετακίνηση όλων Απομακρυσμένα: %1$s - Όλα τα αρχεία μετακινήθηκαν Προώθηση 4 ώρες Το όνομα θα δημιουργήσει ένα κρυφό αρχείο @@ -446,7 +440,6 @@ Κλειδωμένο από την εφαρμογή %1$s %1$s ιστορικό της εφαρμογής Android Δεν βρέθηκε εφαρμογή για αποστολή αρχείων καταγραφής. Εγκαταστήστε ένα πρόγραμμα -πελάτη ηλεκτρονικής αλληλογραφίας. - Σε σύνδεση ως %1$s Είσοδος Ο σύνδεσμος προς τη διεπαφή ιστού %1$s όταν την ανοίγετε στο πρόγραμμα περιήγησης. Διαγραφή καταγραφών @@ -526,7 +519,6 @@ Ο διακομιστής έφτασε στο τέλος το χρόνου υποστήριξης, παρακαλούμε αναβαθμίστε! Περισσότερο μενού Εισάγετε τον κωδικό πρόσβασης - Ο κωδικός πρόσβασης θα ζητείται κάθε φορά που εκκινεί η εφαρμογή Παρακαλούμε εισάγετε τον κωδικό πρόσβασης Οι κωδικοί πρόσβασης δεν ταιριάζουν Παρακαλούμε εισάγετε ξανά τον κωδικό πρόσβασης @@ -534,10 +526,8 @@ Διεγράφη ο κωδικός πρόσβασης Ο κωδικός πρόσβασης αποθηκεύτηκε Εσφαλμένος κωδικός πρόσβασης - Πατήστε σε μια σελίδα για μεγέθυνση Επιτρέπεται Απόρριψη - Επιπλέον διακαιώματα απαιτούνται για μεταφόρτωση και λήψη αρχείων. Δεν βρέθηκε εφαρμογή για τον ορισμό φωτογραφίας Άνοιγμα %1$s Παύση @@ -691,7 +681,6 @@ Διαμοιρασμός συνδέσμου Αποστολή συνδέσμου Απενεργοποίηση - Διαμοιρασμός με… Εικόνα προφίλ από κοινόχρηστο χρήστη διαμοιρασμός διαμοιρασμένα @@ -742,7 +731,6 @@ Εσωτερικός αποθηκευτικός χώρος Βίντεο Μουσική - Πλήρης πρόσβαση Media μόνο για ανάγνωση Φωτογραφίες Η αυτόνομη πλατφόρμα λειτουργικότητας που σας κρατά υπό έλεγχο. \nΑυτή είναι η επίσημη αναπτυξιακή έκδοση, που περιλαμβάνει καθημερινό δείγμα οποιασδήποτε νέας μη δοκιμασμένης λειτουργικότητας, η οποία μπορεί να προκαλέσει αστάθεια και απώλεια δεδομένων. Η εφαρμογή προορίζεται για χρήστες που είναι πρόθυμοι να δοκιμάσουν και να αναφέρουν σφάλματα όταν προκύψουν. Μην το χρησιμοποιείτε για την κανονική εργασία σας! \n\nΗ επίσημη έκδοση dev και η κανονική έκδοση είναι διαθέσιμες στο F-droid και μπορούν να εγκατασταθούν ταυτόχρονα. diff --git a/app/src/main/res/values-eo/strings.xml b/app/src/main/res/values-eo/strings.xml index de8cac3e8f0f..3877406bcb4d 100644 --- a/app/src/main/res/values-eo/strings.xml +++ b/app/src/main/res/values-eo/strings.xml @@ -70,6 +70,7 @@ Ĉiuj dosieroj Okupita Kalendaro + Cancel Ekestis problemo dum ŝargo de la atestilo. Markobutono Elekti lokan dosierujon... @@ -136,7 +137,6 @@ Importado estas planita kaj komenciĝos tre baldaŭ Neniu dosiero trovebla Ne eblis trovi vian lastan savkopion! - Kopiita en la tondejon Eraro okazis dum provo kopii ĉi tiun dosieron aŭ dosierujon Ne eblas kopii dosierujon en unu el ĝiaj idoj La dosiero jam ekzistas en la cela dosierujo @@ -257,7 +257,6 @@ La dosiero ne eblis sinkroniĝi. Nun montriĝas lasta disponebla versio. Alinomi Eraro dum restaŭro de dosierversio! - Sukcese restaŭriĝis dosierversio. Detaloj Elŝuti Eksporti @@ -286,7 +285,6 @@ Loka: %1$s Movi ĉion Fora: %1$s - Ĉiuj dosieroj moviĝis Antaŭen 4 horoj Nomo @@ -360,7 +358,6 @@ La servilo nun malaktualas, bonvolu ĝisdatigi ĝin! Pliaj menuoj Entajpu vian pasvorton - La pasvorto estos petita ĉiufoje, kiam la aplikaĵo ekkomenciĝas Bonvolu entajpi vian pasvorton La pasvortoj ne samas Bonvolu reentajpi vian pasvorton @@ -370,7 +367,6 @@ Neĝusta pasvorto Permesi Rifuzi - Pliaj permesoj bezonataj por el- kaj alŝuti dosierojn. Neniu aplikaĵo trovita por uzi tiun bildon forigita konservita en origina dosierujo @@ -464,7 +460,6 @@ Kunhavigi ligilon Sendi ligilon Malprotekti - Kunhavigi kun... Avataro el kunhavuzanto kunhavo kunhavigita diff --git a/app/src/main/res/values-es-rAR/strings.xml b/app/src/main/res/values-es-rAR/strings.xml index 5ae7fce12946..b98b5bb094a5 100644 --- a/app/src/main/res/values-es-rAR/strings.xml +++ b/app/src/main/res/values-es-rAR/strings.xml @@ -33,7 +33,6 @@ Puerto del Proxy Muestra un widget del panel Buscar en %s - Escriba un texto ¿Está seguro que desea eliminar esta tarea? Ocurrió un error al crear la tarea Tarea creada exitosamente @@ -41,7 +40,6 @@ Tarea eliminada exitosamente No se pudo obtener la lista de tareas, por favor revise su conexión a internet. Eliminar tarea - No se pudieron obtener los tipos de tareas, por favor, revise su conexión a internet. Asistente Entrada Salida @@ -100,6 +98,7 @@ Media Calendario Calendarios + Cancel Se presentó un problema al cargar el certificado. Registro de cambios versión de desarrollo Volvé a intentarlo más tarde o recargá. @@ -177,7 +176,6 @@ La importación está calendarizada y deberá iniciar en breve No se encontraron archivos No se pudo encontrar su última copia de seguridad! - Copiado al portapapeles Se presentó un error al intentar copiar este archivo o carpeta No es posible copiar una carpeta dentro de una de sus sub carpetas El archivo ya existe en la carpeta destino @@ -358,10 +356,8 @@ Cargando… No se cuenta con una aplicación que maneje este tipo de archivo. hace algunos segundos - Permisos necesarios Permisos de almacenamiento %1$s funciona mejor con permisos para acceder al almacenamiento. Puedes elegir acceso completo a todos los archivos o acceso de solo lectura a fotos y videos. - %1$s necesita permisos de gestión de archivos para cargar archivos. Puedes elegir acceso completo a todos los archivos o acceso de solo lectura a fotos y videos. Verificando destino… Limpiando… Actualización de la carpeta de almacenamiento de datos @@ -387,7 +383,6 @@ No se pudo sincronizar el archivo. Mostrando la última versión disponible. Renombrar Error al restaurar la versión del archivo! - Versión de archivo restaurada con éxito. Detalles Descargar Exportar @@ -420,7 +415,6 @@ Local: %1$s Mover todo Remoto: %1$s - Todos los archivos fueron movidos Reenviar 4 horas ¡Google restringió la descarga de archivos APK/AAB! @@ -470,7 +464,6 @@ Bloqueado por la aplicación %1$s  %1$s bitácora de aplicación Android No se encontró una app para enviar los logs. Por favor, instalá un cliente de correo electrónico. - Logueado como %1$s Iniciar sesión El enlace a tu interfaz web %1$s cuando lo abras en el navegador. Eliminar registros @@ -551,7 +544,6 @@ El servidor ha llegado al final de su vida útil, por favor actualice! Más menú Ingrese su código de seguridad - El código de seguridad será solicitado cada vez que inicie la aplicación Favor de ingresar su código de seguridad Los códigos de seguridad no son iguales Favor de reingresar el código de seguridad @@ -560,10 +552,8 @@ Código de seguridad almacenado Código de seguridad incorrecto No es posible abrir archivos PDF protegidos por contraseñas. Por favor, use un visor PDF externo. - Toca una página para hacer zoom Permitir Rechazar - Se requieren permisos adicionales para cargar y descargar archivos. No se encontró ninguna aplicación para establecer una imagen con Abrir %1$s detener @@ -660,7 +650,6 @@ Error al borrar la notificación. Eliminar Borrado - Eliminar Ingrese un nombre nuevo No se pudo cambiar el nombre de la copia local, intente con un nombre diferente No se puede renombrar, el nombre ya está utilizado @@ -735,7 +724,6 @@ Compartir link Enviar Link Desconectado - Compartir con… Avatar de usuario compartido compartir compartido @@ -783,7 +771,6 @@ Almacenamiento interno Películas Música - Acceso completo Sólo lectura de medios Imágenes La plataforma de productividad autohospedada que lo mantiene en control. \ NEsta es la versión de desarrollo oficial, que presenta una muestra diaria de cualquier funcionalidad nueva no probada, que puede causar inestabilidad y pérdida de datos. La aplicación es para usuarios que deseen probar e informar errores en caso de que ocurran. ¡No lo use para su trabajo productivo! \ N \ nTanto el desarrollador oficial como la versión regular están disponibles en F-droid y se pueden instalar al mismo tiempo. @@ -913,7 +900,6 @@ Archivo no encontrado. ¿Está seguro que este archivo existe o tiene un conflicto previo que no ha sido resuelto? No se pudo ubicar el archivo en el servidor. Otro usuario pudo haber eliminado el archivo Nombre de la carpeta - Reintentar la carga de archivos locales fallidos Seleccione la carpeta de cargas No fue posible cargar %1$s Falló la carga, vuelve a iniciar sesión diff --git a/app/src/main/res/values-es-rCO/strings.xml b/app/src/main/res/values-es-rCO/strings.xml index e3bcda18a807..d2aae445afcb 100644 --- a/app/src/main/res/values-es-rCO/strings.xml +++ b/app/src/main/res/values-es-rCO/strings.xml @@ -40,21 +40,15 @@ Puerto proxy Muestra un widget del panel de control Buscar en %s - Añadir nueva tarea - Crear una nueva tarea abajo a la derecha - Escriba un texto ¿Está seguro que desea eliminar esta tarea? Eliminar tarea - Cargando lista de tareas… Se ha producido un error al crear la tarea Tarea creada exitosamente Ocurrió un error al eliminar la tarea Tarea eliminada con éxito - La lista de tareas está vacía. No se pudo obtener la lista de tareas, por favor revise su conexión a internet. Eliminar tarea El resultado de la tarea aún no está listo. - No se pudieron obtener los tipos de tareas, por favor, revise su conexión a internet. Asistente Entrada Salida @@ -114,6 +108,7 @@ Medios de comunicación Calendario Calendarios + Cancel Se presentó un problema al cargar el certificado. Cambios en la versión para desarrolladores Vuelve más tarde o recarga. @@ -194,7 +189,6 @@ No se encontraron archivos ¡No fue posible encontrar tu último respaldo! Conversaciones - Copiado al portapapeles Se presentó un error al intentar copiar este archivo o carpeta No es posible copiar una carpeta dentro de una de sus sub carpetas El archivo ya existe en la carpeta destino @@ -392,10 +386,8 @@ Cargando… No se cuenta con una aplicación que maneje este tipo de archivo. hace algunos segundos - Se requieren permisos Permisos de almacenamiento %1$s funciona mejor con permisos para acceder al almacenamiento. Puede escoger entre el acceso completo a los archivos, o acceso solo de lectura a fotos y vídeos. - %1$s necesita permisos de gestión de archivos para subir archivos. Puede escoger entre acceso completo a todos los archivos, o acceso de solo lectura a fotos y vídeos. Permitir acceso desde otras aplicaciones Verificando el destino… Limpiando… @@ -449,7 +441,6 @@ Local: %1$s Mover todos Remoto: %1$s - Se han movido todos los archivos Adelante Nombre Contraseña @@ -506,7 +497,6 @@ Por favor verifica más tarde. 1 hora Ingresa tu código de seguridad - El código de seguridad será solicitado cada vez que inicie la aplicación Por favor ingresa tu código de seguridad Los códigos de seguridad no son iguales Por favor reingresa el código de seguridad @@ -514,7 +504,6 @@ Código de seguirdad eliminado Código de seguridad almacenado Código de seguridad incorrecto - Se requieren permisos adicionales para cargar y descargar archivos. No se encontró una aplicación con la cual establecer la imagen Borrado mantenido en la carpeta original @@ -588,7 +577,6 @@ %1$s (remoto) Configuraciones Compartir enlace - Compartir con… compartido Ordenar por Ocultar diff --git a/app/src/main/res/values-es-rEC/strings.xml b/app/src/main/res/values-es-rEC/strings.xml index c660e755d47b..85e1a432625a 100644 --- a/app/src/main/res/values-es-rEC/strings.xml +++ b/app/src/main/res/values-es-rEC/strings.xml @@ -87,6 +87,7 @@ Ocupado Calendario Calendarios + Cancelar Se presentó un problema al cargar el certificado. Registro de cambios de la versión de desarrollo Vuelva a intentarlo más tarde o recargue. @@ -168,7 +169,6 @@ No se encontraron conversaciones Conversaciones Copiado - Copiado al portapapeles Se presentó un error al intentar copiar este archivo o carpeta No es posible copiar una carpeta dentro de una de sus sub carpetas El archivo ya existe en la carpeta destino @@ -334,10 +334,8 @@ Cargando… No se cuenta con una aplicación que maneje este tipo de archivo. hace algunos segundos - Permisos necesarios Permisos de almacenamiento %1$s funciona mejor con permisos para acceder al almacenamiento. Puedes elegir acceso completo a todos los archivos o acceso de solo lectura a fotos y videos. - %1$s necesita permisos de gestión de archivos para cargar archivos. Puedes elegir acceso completo a todos los archivos o acceso de solo lectura a fotos y videos. Verificando el destino… Limpiando… Actualizando la carpeta de almacenamiento de datos @@ -363,7 +361,6 @@ El archivo no pudo ser sincronizado. Mostrando la última versión disponible. Renombrar Error al restaurar la versión del archivo - Se ha restaurado la versión del archivo correctamente. Detalles Descargar Exportar @@ -393,7 +390,6 @@ Local: %1$s Mover todos Remoto: %1$s - Se han movido todos los archivos Adelante 4 horas El nombre resultará en un archivo oculto @@ -514,7 +510,6 @@ El servidor ha alcanzado el final de su vida útil, ¡por favor, actualízalo! Más menú Ingresa tu código de seguridad - El código de seguridad será solicitado cada vez que inicie la aplicación Por favor ingresa tu código de seguridad Los códigos de seguridad no son iguales Por favor reingresa el código de seguridad @@ -522,11 +517,10 @@ Código de seguirdad eliminado Código de seguridad almacenado Código de seguridad incorrecto + Pausar No se puede abrir un PDF protegido con contraseña. Por favor, utiliza un visor de PDF externo. - Toca una página para hacer zoom Permitir Denegar - Se requieren permisos adicionales para cargar y descargar archivos. No se encontró una aplicación con la cual establecer la imagen Abrir %1$s detener @@ -678,7 +672,6 @@ Compartir liga Enviar enlace Sin establecer - Compartir con… Avatar del usuario compartido compartir compartido @@ -727,7 +720,6 @@ Almacenamiento interno Películas Música - Acceso completo Solo lectura de medios Imágenes La plataforma de productividad autohospedada que te mantiene en control.\nEsta es la versión de desarrollo oficial, que presenta una muestra diaria de cualquier nueva funcionalidad no probada, lo que puede causar inestabilidad y pérdida de datos. La aplicación es para usuarios dispuestos a probar y reportar errores en caso de que ocurran. ¡No la utilices para tu trabajo productivo!\n\nTanto la versión oficial de desarrollo como la regular están disponibles en F-Droid y se pueden instalar al mismo tiempo. diff --git a/app/src/main/res/values-es-rMX/strings.xml b/app/src/main/res/values-es-rMX/strings.xml index cddc40792a92..1c5f08daee8e 100644 --- a/app/src/main/res/values-es-rMX/strings.xml +++ b/app/src/main/res/values-es-rMX/strings.xml @@ -34,7 +34,6 @@ Muestra un widget del panel Buscar en %s Aparecer como desconectado - Escriba algo de texto ¿Está seguro de eliminar esta tarea? Eliminar tarea Ocurrió un error al crear la tarea @@ -43,7 +42,6 @@ Tarea eliminada exitosamente No se pudo obtener la lista de tareas, por favor, revise su conexión a internet. Eliminar tarea - No se pudieron obtener los tipos de tareas, por favor, revise su conexión a internet. Asistente Entrada Salida @@ -103,6 +101,7 @@ Ocupado Calendario Calendarios + Cancel Se presentó un problema al cargar el certificado. Registro de cambios para la versión de desarrollo. Intente más tarde o recargue. @@ -184,7 +183,6 @@ ¡No fue posible encontrar tu último respaldo! Conversaciones Copiado - Copiado al portapapeles Se presentó un error al intentar copiar este archivo o carpeta No es posible copiar una carpeta dentro de una de sus sub carpetas El archivo ya existe en la carpeta destino @@ -365,10 +363,8 @@ Cargando… No se cuenta con una aplicación que maneje este tipo de archivo. hace algunos segundos - Se requieren permisos Permisos de almacenamiento %1$s funciona mejor con permisos para acceder al almacenamiento. Puede elegir acceso completo a todos los archivos o acceso de sólo lectura a fotos y videos. - %1$s necesita permisos de gestión de archivos para cargar archivos. Puede elegir acceso completo a todos los archivos o acceso de sólo lectura a fotos y videos. Verificando el destino… Limpiando… Actualizando la carpeta de almacenamiento de datos @@ -394,7 +390,6 @@ El archivo no pudo ser sincronizado. Mostrando la última versión disponible. Renombrar ¡Error al restaurar la versión del archivo! - La versión del archivo fue restaurada con éxito. Detalles Descargar Exportar @@ -427,7 +422,6 @@ Local: %1$s Mover todos Remoto: %1$s - Se han movido todos los archivos Adelante 4 horas ¡Google restringió la descarga de archivos APK/AAB! @@ -477,7 +471,6 @@ Bloqueado por la aplicación %1$s  %1$s bitácora de aplicación Android No se encontró una aplicación para enviar los registros. Por favor, instale un cliente de correo electrónico. - Sesión iniciada como %1$s Iniciar sesión El enlace a su interfaz web de %1$s cuando lo abre en el navegador. Eliminar los registros @@ -559,7 +552,6 @@ ¡El servidor ha alcanzado el final de su vida útil, por favor, actualícelo! Menú Ingresa tu código de seguridad - El código de seguridad será solicitado cada vez que inicie la aplicación Por favor ingresa tu código de seguridad Los códigos de seguridad no son iguales Por favor reingresa el código de seguridad @@ -567,11 +559,10 @@ Código de seguirdad eliminado Código de seguridad almacenado Código de seguridad incorrecto + Pausar No se puede abrir un PDF protegido con contraseña. Por favor, utilice un visor PDF externo. - Toque una página para enfocar Permitir Denegar - Se requieren permisos adicionales para cargar y descargar archivos. No se encontró una aplicación con la cual establecer la imagen Abrir %1$s detener @@ -668,7 +659,6 @@ No se pudo eliminar la notificación. Eliminar Eliminado - Borrar Ingresa un nombre nuevo No se pudo renombrar la copia local, intenta con un nombre diferente No fue posible renombrar, el nombre ya está ocupado @@ -747,7 +737,6 @@ Compartir liga Enviar enlace Desestablecer - Compartir con… Avatar del usuario compartido compartir compartido @@ -799,7 +788,6 @@ Almacenamiento interno Películas Música - Acceso completo Sólo lectura de medios Imágenes La plataforma de productividad auto hospedada que Ud. mantiene en control.\n\nEsta es la versión oficial de desarrollo, presentando una muestra diaria de funcionalidad no probada, que puede provocar inestabilidad y pérdida de la información. Esta aplicación es para usuarios que deseen probar y reportar errores que puedan llegar a ocurrir. ¡No la use para su trabajo productivo!\n\nTanto la versión oficial de desarrollo como la versión regular están disponibles en F-droid, y se pueden instalar al mismo tiempo. @@ -929,7 +917,6 @@ Archivo no encontrado. ¿Está seguro que este archivo existe o tiene un conflicto previo que no ha sido resuelto? No se pudo ubicar el archivo en el servidor. Otro usuario pudo haber eliminado el archivo Nombre de la carpeta - Reintentar la carga de archivos locales fallidos Selecciona la carpeta de cargas No fue posible cargar %1$s La carga falló, inicia sesión de nuevo diff --git a/app/src/main/res/values-es/strings.xml b/app/src/main/res/values-es/strings.xml index 549f1e325c09..8df92c661853 100644 --- a/app/src/main/res/values-es/strings.xml +++ b/app/src/main/res/values-es/strings.xml @@ -45,23 +45,17 @@ Buscar en %s Aparecer como desconectado Esta salida fue generada mediante IA. Asegúrese de revisar de nuevo. - Añadir nueva tarea - Crear una nueva tarea abajo a la derecha - Escriba algo de texto ¿Está seguro de querer eliminar esta tarea? Eliminar tarea Intente enviar un mensaje para iniciar una conversación. ¡Hola!, ¿En qué te puedo ayudar hoy? - Cargando lista de tareas… Ocurrió un error al crear la tarea Tarea creada exitosamente Ocurrió un error al eliminar la tarea La tarea fue eliminada exitosamente - La lista de tareas está vacía. No se pudo obtener la lista de tareas, por favor, revise su conexión a internet. Eliminar tarea El resultado de la tarea no está listo aún. - No se pudieron obtener los tipos de tareas, por favor, revise su conexión a internet. Asistente Entrada Salida @@ -126,6 +120,7 @@ Ocupado Calendario Calendarios + Cancelar Existe un problema al cargar el certificado. Historial de cambios de la versión de desarroll Regrese luego o recargue. @@ -214,7 +209,6 @@ No hay conversaciones todavía Conversaciones Copiado - Copiado al portapapeles Se ha producido un error al tratar de copiar este archivo o carpeta No se puede copiar una carpeta dentro de una de sus propias subcarpetas. El fichero ya existe en el directorio de destino @@ -425,10 +419,8 @@ Cargando… No hay una app configurada para manejar este tipo de archivos. hace segundos - Permisos necesarios Permisos de almacenamiento %1$s funciona mejor con permisos para acceder al almacenamiento. Puede escoger entre el acceso completo a los archivos, o acceso solo de lectura a fotos y vídeos. - %1$s necesita permisos de gestión de archivos para subir archivos. Puede escoger entre acceso completo a todos los archivos, o acceso de solo lectura a fotos y vídeos. Permitir acceso desde otras aplicaciones Comprobando destino… Limpiando… @@ -466,7 +458,6 @@ Falló la subida. Sin conexión a Internet %s ya existe, no se detectó conflicto ¡Error al restaurar la versión del archivo! - Versión del archivo restaurada con éxito. Detalles Descargar Exportar @@ -501,7 +492,6 @@ Local: %1$s Mover todo Remoto: %1$s - Se han movido todos los archivos Adelante 4 horas ¡Google ha restringido la descarga de archivos APK/AAB! @@ -556,7 +546,6 @@ Bloqueado por la app %1$s Se han encontrado %1$s aplicaciones de registros para Android No se ha encontrado una app para enviar los registros. Por favor, instale un cliente de correo electrónico. - Se ha autenticado como %1$s Iniciar sesión El enlace a tu interface web %1$s cuando lo abres en tu navegador. Eliminar registros @@ -656,7 +645,6 @@ El servidor ha alcanzado su final de vida. ¡Por favor, actualiza! Menú Introduce tu código de acceso - Se solicitará el código de acceso cada vez que se inicie la aplicación Por favor introduzca su código de acceso Los códigos de acceso no son iguales Por favor, vuelve a introducir tu código de acceso @@ -665,10 +653,8 @@ Código de acceso almacenado Código de acceso incorrecto No es posible abrir archivos PDF protegidos por contraseñas. Por favor, use un visor PDF externo. - Toca sobre una página para hacer zoom Permitir Denegar - Se necesitan permisos adicionales para subir y descargar archivos. Elija un contacto con quien compartir No se ha encontrado una app para establecer con ella la imagen Anclar a la pantalla de inicio @@ -775,7 +761,6 @@ Fallo al quitar notificación. Quitar Eliminado - Quitar Introduce un nombre nuevo No se ha podido cambiar el nombre de la copia local, prueba un nombre diferente No se ha podido dar un nombre nuevo, el nombre ya está tomado @@ -871,7 +856,6 @@ Compartir enlace Enviar enlace Desmarcar - Compartir con… Avatar del usuario compartido compartido compartido @@ -924,7 +908,6 @@ Almacenamiento interno Películas Música - Acceso completo Medios en sólo lectura Imágenes La plataforma de productividad auto-hospedada que le mantiene en control.\n\nCaracterísticas;\n* Interfaz moderna y fácil de usar adecuada al tema de su servidor\n* Cargue archivos a su servidor Nextcloud\n* Comparta los mismos con otros\n* Mantenga sus archivos y carpetas favoritas sincronizados\n* Busque en todas las carpetas de su servidor\n* Carga automática para fotos y videos capturados en su dispositivo\n* Manténgase al día con notificaciones\n* Soporte para múltiples cuentas\n* Acceda a su información de forma segura usando su huella dactilar o PIN\n* Integración con DAVx5 (anteriormente conocido como DAVdroid) para configurar fácilmente la sincronización del calendario y contactos\n\nPor favor, reporte cualquier problema en https://github.com/nextcloud/android/issues y discuta acerca de esta aplicación en https://help.nextcloud.com/c/clients/android\n\n¿Es Ud. nuevo en Nextcloud? Nextcloud es un servidor privado para sincronizar y compartir archivos, y comunicación. Es un programa de uso libre, y lo puede hospedar Ud. mismo o pagar a una compañía para hacerlo por Ud. De esa manera, Ud. está en control de sus fotos, su calendario e información de sus contactos, sus documentos y todo lo demás.\n\nConozca Nextcloud en https://nextcloud.com @@ -1069,7 +1052,6 @@ Archivo no encontrado. ¿Está seguro de que este archivo existe o tiene un conflicto previo que no ha sido resuelto? No pudimos ubicar el archivo en el servidor. Otro usuario podría haber eliminado el archivo Nombre de la carpeta - Reintentar la subida de archivos locales fallidos Elegir carpeta de subida No se ha podido subir %1$s Subida fallida, vuelve a iniciar sesión diff --git a/app/src/main/res/values-et-rEE/strings.xml b/app/src/main/res/values-et-rEE/strings.xml index 8e6a224a133e..aa19f7e06a2d 100644 --- a/app/src/main/res/values-et-rEE/strings.xml +++ b/app/src/main/res/values-et-rEE/strings.xml @@ -15,7 +15,7 @@ Loendivaade Taasta kontaktid ja kalender Uus kaust - Liiguta või kopeeri + Teisalda või kopeeri Ava rakendusega Otsi Üksikasjad @@ -24,7 +24,7 @@ Järjesta Aktiivne kasutaja Tegevusi veel pole - Lisamisi, muutmisi, jagamisi ega muid sündmuseid veel pole. + Lisamisi, muutmisi, jagamisi ega muid sündmusi veel pole. Saada Saada link… Tegevus @@ -45,26 +45,20 @@ Otsi siin: %s Sellega paistad olema võrgust väljas See väljund on loodud tehisaru poolt. Palun topeltkontrolli selle õigsust ka ise. - Lisa uus ülesanne Sõnumi saatmine ei õnnestu Ei õnnestunud laadida vestluse sõnumeid - Loo uus ülesanne all paremal asuvast valikust - Kirjuta midagi vahvat Kas sa oled kindel, et soovid selle ülesande kustutada? Kustuta ülesanne Vestluse algatamiseks proovi sata üks sõnum. Hei! Kuidas saan sind täna aidata? - Laadin ülesannete loendit… Ülesande loomisel tekkis viga Ülesande loomine õnnestus Ülesande kustutamisel tekkis viga Ülesande kustutamine õnnestus - Ülesannete loend on tühi. Ülesannete loend on tühi. Kontrolli Abilise rakenduse seadistusi. Ülesannete loendi laadimine ei õnnestunud. Palun kontrolli oma nutiseadme internetiühenduse toimivust. Kustuta ülesanne Ülesande väljund pole veel valmis. - Ülesannete tüüpide laadimine ei õnnestunud. Palun kontrolli oma nutiseadme internetiühenduse toimivust. Abiline Sisend Väljund @@ -133,6 +127,7 @@ Hõivatud Kalender Kalendrid + Katkesta Sertifikaadi laadimisel tekkis viga. Arendusversiooni muudatuste logi Palun kontrolli hiljem või laadi kohe uuesti. @@ -225,7 +220,6 @@ Vestluste loendi laadimine ei õnnestunud. Vestlused Kopeeritud - Kopeeritud lõikepuhvrisse Selle faili või kausta kopeerimisel tekkis tõrge Kausta ei saa kopeerida tema enda alamkausta See fail on juba sihtkaustas olemas @@ -329,6 +323,7 @@ Abiline Veel Veel Nextcloudi rakendusi + Failivalija avamine ei õnnestu Ei õnnestu valida e-posti aadressi Määra krüptituks Serveri sertifikaadi laadimine ei õnnestu @@ -398,6 +393,7 @@ Sul puuduvad õigused siia kausta failide üleslaadimiseks või loomiseks. Välised jaoskaustad Lisa või laadi üles + Failikonfilktiteabe vaate loomine ei õnnestu Ei õnnestunud faili allalaadimishaldurile edasi anda Faili trükkimine ei õnnestunud Ei õnnestunud avada muutmisvaadet @@ -439,10 +435,8 @@ Laadimine… Puudub rakendus seda tüüpi failide avamiseks. sekundit tagasi - Õigused on vajalikud Andmeruumi õigused %1$s vajab tõhusaks tööks õigust kasutada andmeruumi. Võid valida kõikide failide täisõiguste või fotode ja videote lugemisõiguse vahel. - %1$s vajab failide haldamise luba, et faile üles laadida. Võid valida kas täieliku ligipääsu kõigile failidele või ainult lugemisligipääsu fotodele ja videotele. Luba ligipääs teistest rakendustest Sihtkoha kontrollimine... Puhastamine... @@ -480,7 +474,6 @@ Üleslaadimine ei õnnestunud. Internetiühendus puudub %s on juba olemas, failikonflikti ei tundu tekkima Viga faili versiooni taastamisel! - Faili versiooni taastamine õnnestus. Üksikasjad Laadi alla Ekspordi @@ -520,7 +513,6 @@ Kohalik: %1$s Teisalda kõik Kaughallatav: %1$s - Kõik failid on teisaldatud Edasi 4 tundi Google piirab APK/AAB failide allalaadimist! @@ -575,7 +567,6 @@ Lukustatud %1$s rakenduse poolt %1$s Androidi rakenduse logid Ei leidu rakendust logide edastamiseks. Palun paigalda e-posti klient. - Sisse logitud kui %1$s Logi sisse See on sinu %1$s kasutajaliidese veebiaadress, kui sa avad ta veebibrauseris. Kustuta logid @@ -678,7 +669,6 @@ Server on jõudnud oma kasutusea lõpuni. Palun uuenda serveri tarkvara! Lisamenüü Sisesta oma täiendav salasõna - Täiendavat salasõna küsitakse iga kord, kui sa selle rakenduse käivitad Palun sisesta oma täiendav salasõna Täiendavat salasõna küsitakse iga kord, kui rakendust avatakse või avatakse uuesti 5 sekundi möödumisel. Täiendavad salasõnad pole samad @@ -687,11 +677,10 @@ Täiendav salasõna on kustutatud Täiendav salasõna on salvestatud Vale täiendav salasõna + Paus Ei õnnestu avada salasõnaga kaitstud pdf-faili. Palun kasuta välist pdf-failide vaatamise rakendust. - Suumimiseks klõpsa lehel Luba Keela - Failide üles- ja allalaadimiseks on vaja täiendavaid õiguseid. Vali kontakt, kellega soovid sisu jagada Ei leidu rakendust pildi määramiseks Kinnita avalehele @@ -800,7 +789,6 @@ Teavituse eemaldamine ei õnnestunud. Eemalda Kustutatud - Eemalda Sisesta uus nimi Lokaalse koopia nime muutmine ei õnnestunud, palun proovi teist nime Nime muutmine pole võimalik, nimi on juba kasutuses @@ -896,7 +884,6 @@ Jaga linki Saada link Eemalda seadistus - Jaga kasutades… Tunnuspilt jaganud kasutajalt jaga jagatud @@ -953,7 +940,6 @@ Automaatseks üleslaadimiseks on vajalikud andmeruumi kasutamise õigused. Failide üleslaadimiseks on vajalikud andmeruumi kasutamise õigused. Ära küsi - Täisõiguslik ligipääs Meedium on vaid lugemisõigustes Pildid Tarbetarkvara sinu serveris ja sinu kontrolli all.\n\nOmadused:\n* Lihtne ja moodne kasutajaliides, mille välimus ühtib serveris seadistatud kujundusega\n* Laadi oma failid üles enda Nextcloudi serverisse\n* Jaga oma faile teistega\n* Hoia oma lemmikfailid ja -kaustad sünkroonis\n* Otsi kõigist kaustadest oma serveris\n* Oma seadmega tehtud piltide ja videode automaatne üleslaadimine\n* Hoia end kursis uuenduste abil\n* Mitme konto kasutamise võimalus\n* Muuda oma andmetele ligipääs turvalisemaks kasutades sõrmejälge või PIN-koodi\n* Lõiming DAVx⁵ rakendusega (vana nimega DAVdroid), mis võimaldab lihtsalt kalender ja kontaktid sünkroonis hoida\n\nTeavita kõigist probleemidest aadressil https://github.com/nextcloud/android/issues ja osale rakenduse kohta käivas arutelus aadressil https://help.nextcloud.com/c/clients/android\n\nKas Nextcloud on sinu jaoks midagi uut? Nextcloud on privaatne failide sünkroniseerimise ja jagamise ning suhtlusserver. Lahendus on vaba tarkvara ja põhineb avatud lähtekoodil ning sa saad selle oma serverisse püsti panna või lasta seda kellelgi teisel teha või osta lahendus valmisteenusena. Nii omad kontrolli oma piltide, kalendri, kontaktandmete, dokumentide ja kõige muu üle.\n\nUuri Nextcloudi kohta aadressil https://nextcloud.com @@ -1099,7 +1085,6 @@ Faili ei leidu. Kas sa oled kindel, et ta päriselt on olemas või pole varasem failikonflikt lahendatud? Ei suutnud serverist leida faili. Ilmselt on mõni muu kasutaja selle kustutanud Kausta nimi - Ebaõnnestunud kohalike failide üleslaadimiseks proovi uuesti Vali üleslaadimise kaust %1$s ei õnnestunud üles laadida Üleslaadimine ei õnnestunud, palun logi uuesti sisse diff --git a/app/src/main/res/values-eu/strings.xml b/app/src/main/res/values-eu/strings.xml index a62f384d1d78..347e42a01ead 100644 --- a/app/src/main/res/values-eu/strings.xml +++ b/app/src/main/res/values-eu/strings.xml @@ -43,21 +43,15 @@ Proxy-ataka Paneleko trepeta bat erakusten du Bilatu %s(e)n - Gehitu zeregin berria - Sortu zeregin berri bat eskuineko botoiarekin - Idatzi testu bat Ziur zeregin hau ezabatu nahi duzula? Ezabatu zeregina - Zereginen zerrenda kargatzen... Errore bat gertatu da zeregina sortzean Zeregina behar bezala sortu da Errore bat gertatu da zeregina ezabatzean Zeregina ongi ezabatu da - Zereginen zerrenda hutsik dago. Ezin da zereginen zerrenda eskuratu. Egiaztatu Interneteko konexioa. Ezabatu zeregina Zereginaren irteera ez dago prest oraindik. - Ezin dira zeregin motak eskuratu, egiaztatu Interneteko konexioa. Morroia Sarrera Irteera @@ -119,6 +113,7 @@ Lanpetua Egutegia Egutegiak + Cancel Arazo bat dago ziurtagiria kargatzean. Garapen bertsioaren aldaketa-egunkaria Begiratu berriro geroago edo kargatu berriro. @@ -205,7 +200,6 @@ Ez da elkarrizketarik aurkitu Elkarrizketak Kopiatuta - Arbelera kopiatua Fitxategi edo karpeta kopiatzean errore bat gertatu da. Ezin da karpeta bat bere azpikarpeta batera kopiatu Fitxategi hau existitzen da jadanik helburuko karpetan @@ -403,10 +397,8 @@ Kargatzen… Ez dago aplikaziorik konfiguratuta fitxategi-mota honetarako. duela segundo batzuk - Baimenak behar dira Biltegiratze-baimenak %1$shobeto dabil biltegia atzitzeko baimenekin. Fitxategi guztietarako sarbide osoa aukera dezakezu, edo argazki eta bideoak \"irakurtzeko soilik\" baimena eman. - %1$s-k fitxategiak kudeatzeko baimenak behar ditu fitxategiak igotzeko. Fitxategi guztietarako sarbide osoa aukera dezakezu, edo \"irakurtzeko soilik\" baimena argazki eta bideoentzat. Baimendu sarbidea beste aplikaziotatik Helburua egiaztatzen... Garbitzen… @@ -442,7 +434,6 @@ Aldatu izena Igoerak huts egin du. Ez dago internet konexiorik Errorea fitxategiaren bertsioa berreskuratzean! - Fitxategiaren bertsioa ondo berreskuratu da. Xehetasunak Deskargatu Esportatu @@ -477,7 +468,6 @@ Bertakoa: %1$s Mugitu guztia Urrunekoa: %1$s - Fitxategi guztiak mugitu dira Birbidali 4 ordu Google-k muga jarri die APK/AAB fitxategien deskargei! @@ -531,7 +521,6 @@ %1$s aplikazioak blokeatuta %1$s Android aplikazioaren egunkariak Ez da aurkitu egunkariak bidaltzeko aplikaziorik. Instalatu posta elektroniko bezero bat. - Saioa hasita %1$s gisa Hasi saioa Zure %1$s web interfazerako esteka, nabigatzailean irekitzen duzunean. Ezabatu egunkariak @@ -625,7 +614,6 @@ Zerbitzaria bizitzaren amaierara iritsi da, bertsio-berritu! Gehiago menua Sartu zure pasahitza - Pasahitza eskatuko da aplikazioa abiatzen den aldiro Sartu zure pasahitza Pasahitzak ez datoz bat Sartu pasahitza berriro @@ -633,11 +621,10 @@ Pasahitza ezabatuta Pasahitza gordeta Okerreko pasahitza + Gelditu Ezin izan da pasahitzez babestutako PDFa ireki. Mesedez erabili kanpoko PDF ikustaile bat. - Ukitu orrialdean handitzeko Baimendu Ukatu - Fitxategiak kargatu eta deskargatzeko baimen gehigarriak behar dira Aukeratu partekatzeko kontaktua Ez da aplikaziorik aurkitu irudia ezartzeko Finkatu pantaila nagusian @@ -744,7 +731,6 @@ Huts egin du jakinarazpena kentzean Ezabatu Ezabatuta - Kendu Idatzi izen berri bat Ezin izan da kopia lokala berrizendatu, saiatu beste izen batekin Ezin izan da berrizendatu, izena hartua zegoen @@ -833,7 +819,6 @@ Partekatu esteka Bidali esteka Ezarri gabe - Partekatu honekin… Partekatutako erabiltzailearen abatarra partekatu partekatua @@ -886,7 +871,6 @@ Barneko biltegiratzea Pelikulak Musika - Sarbide osoa Mutimediak irakurtzeko soilik Irudiak Zure kontrola bermatzen dituzten auto-ostatatutako produktibitate-plataformak.\n\nEzaugarriak:\n* Interfaze erraza, modernoa, zure zerbitzariaren gaira egokitua\n* Igo fitxategiak zure Nextcloud zerbitzarira\n* Partekatu beste batzuekin\n* Mantendu zure fitxategi eta karpeta sinkronizatuak\n* Bilatu zure zerbitzariko karpeta guztietan\n* Igo automatikoki zure gailuz hartutako argazki eta bideoak\n* Eguneratuta egon jakinarazpenekin\n* Kontu anitzak onartzen dira\n* Datu seguruak zure zerbitzarian hatz-marka edo PINaren bidez* Davx⁵-ekin integratzea (lehenago Davdroid izenarekin ezagutzen dena) egutegiaren eta kontaktuen sinkronizazioa erraz konfiguratzeko\n\n Mesedez akatsen berri eman https://github.com/nextcloud/android web orrian eta eztabaidatu aplikazio honi buruz https://help.nextcloud.com/c/clients/android web orrian\n\n Berria Nextclouden? Nextcloud fitxategi pribatuen sinkronizatu eta partekatzeko zerbitzaria da. Software librea da, eta zuk zeuk ostatatu edo ordaindu dezakezu enpresa bati zure ordez egiteko. Horrela, zure argazkiak, egutegia eta harremanetarako datuak, dokumentuak eta gainerako guztia kontrolatzen ahal dituzu.\n\nBegiratu Nextcloud informazioa https://nextcloud.com webgunean. @@ -1028,7 +1012,6 @@ Fitxategia ez da aurkitu. Ziur al zaude fitxategi hau badagoela edo aurretik konpondu gabeko gatazka bat duela? Ezin izan dugu fitxategia zerbitzarian kokatu. Baliteke beste erabiltzaile batek fitxategia ezabatu izana Karpetaren izena - Saiatu berriro huts egin duten tokiko fitxategiak kargatzen Aukeratu karga-karpeta Ezin da %1$s igo Kargatzeak huts egin du, hasi saioa berriz diff --git a/app/src/main/res/values-fa/strings.xml b/app/src/main/res/values-fa/strings.xml index 6a9eb395bc40..f5cf5ff960aa 100644 --- a/app/src/main/res/values-fa/strings.xml +++ b/app/src/main/res/values-fa/strings.xml @@ -35,7 +35,6 @@ نمایش یک ابزارک از پیشخوان جستجو در %s نمایش آفلاین - مقداری متن را تایپ کنید وظیفه را حذف کنید Task successfully deleted حساب مرتبط یافت نشد! @@ -90,6 +89,7 @@ مشغول تقویم تقویم‌ها + انصراف در حال بارگذاری گواهینامه، یک مشکل وجود دارد. تغییرات نسخه در حال توسعه بعدا چک فرمایید یا مجددا بارگذاری کنید. @@ -172,7 +172,6 @@ No conversations found گفتگو کپی شد - در حافظه رونویسی شد یک خطا در زمان تلاش برای کپی این فایل یا شاخه رخ داد کپی کردن پوشه در یکی از پوشه های زیرین خود امکان پذیر نیست فایل در حال حاضر در پوشه مقصد موجود است @@ -350,10 +349,8 @@ درحال بارگیری... هیچ برنامه ای برای استفاده این نوع فایل تنظیم نشده است. ثانیه‌هایی پیش - مجوزهای مورد نیاز مجوزهای ذخیره سازی %1$s با مجوز دسترسی به فضای ذخیره سازی بهترین کار را دارد. می‌توانید دسترسی کامل به همه فایل‌ها یا دسترسی فقط خواندنی به عکس‌ها و ویدیوها را انتخاب کنید. - %1$s برای آپلود فایل ها به مجوزهای مدیریت فایل نیاز دارد. می‌توانید دسترسی کامل به همه فایل‌ها یا دسترسی فقط خواندنی به عکس‌ها و ویدیوها را انتخاب کنید. در حال بررسی مقصد... درحال پاک‌سازی… به روزرسانی مسیر ذخیره سازی @@ -379,7 +376,6 @@ پرونده نمی تواند همگام سازی شود. نمایش آخرین نسخه موجود تغییرنام خطا در بازیابی نسخه پرونده! - نسخه پرونده با موفقیت بازیابی شد. جزییات دانلود گرفتن خروجی @@ -412,7 +408,6 @@ محلی: %1$s انتقال همه از راه دور:%1$s - همه فایل‌ها انتقال یافتند ارسال کردن ۴ ساعت این آیکون، نمایانگر دسترسی به تصویر زنده است @@ -462,7 +457,6 @@ برنامه توسط %1$s قفل شده است لاگ‌های برنامه‌های اندروید %1$s برنامه‌ای برای فرستادن گزارش‌ها پیدا نشد. لطفا یک کارخواه رایانامه نصب کنید. - وارد شده با عنوان %1$s ورود پیوند به رابط وب %1$s شما زمانی که در مرورگر بازش می‌کنید. حذف لاگ‌ها @@ -544,7 +538,6 @@ سرور به پایان عمر رسیده است، لطفاً ارتقا دهید! منوی بیشتر رمز خود را وارد کنید - هر بار که برنامه باز شود, شما نیاز به استفاده از کد عبور خواهید داشت لطفا کد عبور خود را وارد کنید رمزهای وارد شده یکسان نیستند لطفا کد عبور خود را دوباره وارد کنید @@ -552,11 +545,10 @@ کد عبور حذف شد رمز ذخیره شد رمز نادرست + توقف کردن PDF محافظت شده با رمز عبور باز نمی شود. لطفا از یک نمایشگر PDF خارجی استفاده کنید. - برای بزرگنمایی روی صفحه ضربه بزنید اجازه دادن غیر مجاز - نیاز به مجوزهای اضافی برای بارگذاری و دریافت پرونده‌ها می باشد. هیچ برنامه ای برای تنظیم عکس یافت نشد باز کنید %1$s توقف @@ -648,7 +640,6 @@ حذف اعلان انجام نشد. حذف حذف شده - حذف نام جدید وارد کنید تغییر نام نسخه محلی امکان پذیر نیست، نام دیگری را امتحان کنید تغییر نام ممکن نیست، این نام قبلا استفاده شده است @@ -729,7 +720,6 @@ اشتراک گذاشتن لینک فرستادن پیوند ناتنظیم - هم‌رسانی با… چهرک از کاربر مشترک هم‌رسانی هم‌رسانده @@ -780,7 +770,6 @@ ذخیره‌ساز داخلی فیلم‌ها آهنگ‌ها - دسترسی کامل رسانه فقط‌خواندنی نگاره‌ها "بستر خودمیزبانی که به شما اختیارات کامل می‌دهد. این نسخه رسمی درحال توسعه می‌باشد، شامل یک نمونه روزانه از هر قابلیت جدید آزمایش نشده است، چیزی که ممکن است باعث ناپایداری و از دست دادن اطلاعات شود. این برنامک برای کاربرانی می‌باشد که قصد آزمایش دارند، و در صورت بروز مشکل آن را گزارش دهند. از آن برای کار تولیدی استفاده نکنید! هردو نسخه عادی و در حال توسعه در F-droid در دسترس هستند و به صورت هم‌زمان قابل نصب هستند. " @@ -902,7 +891,6 @@ فایل یافت نشد. آیا مطمئن هستید که فایل وجود دارد یا ممکن است تداخل قبلی آن رفع نشده است؟ نتوانستیم فایل را در فضای سرویس‌دهنده پیدا کنیم. ممکن است توسط کاربر دیگری حذف شده باشد نام پوشه - تلاش مجدد آپلود فایل‌های محلی ناموفق پوشه آپلود را انتخاب کنید %1$sآپلود نشد بارگذاری شکست خورد. دوباره وارد شوید diff --git a/app/src/main/res/values-fi-rFI/strings.xml b/app/src/main/res/values-fi-rFI/strings.xml index 728ca8e06bbc..e345d9222e05 100644 --- a/app/src/main/res/values-fi-rFI/strings.xml +++ b/app/src/main/res/values-fi-rFI/strings.xml @@ -34,19 +34,14 @@ Näyttää yhden pienoissovelluksen konsolista Etsi kohteesta %s Näytä olevan poissa - Lisää uusi tehtävä - Syötä tekstiä Haluatko varmasti poistaa tämän tehtävän? Poista tehtävä - Ladataan tehtävälistaa… Tehtävän luonti epäonnistui Tehtävä luotu Tehtävän poisto epäonnistui Tehtävä poistettu - Tehtävälista on tyhjä. Tehtävälistan haku epäonnistui, tarkista internetyhteytesi. Poista tehtävä - Tehtävätyyppen haku epäonnistui, tarkista internetyhteytesi. Avustaja Liitettyä tiliä ei löydy! Pääsy epäonnistui: %1$s @@ -104,6 +99,7 @@ Varattu Kalenteri Kalenterit + Peruuta Varmennetta ladatessa ilmeni ongelmia. Muutosloki kehitysversiolle Lataa uudelleen tai yritä myöhemmin uudelleen. @@ -185,7 +181,6 @@ Viimeisintä varmuuskopiota ei löytynyt! Keskusteluja ei löytynyt Keskustelut - Kopioitu leikepöydälle Tätä tiedostoa tai kansiota kopioitaessa tapahtui virhe Ei ole mahdollista kopioida kansiota yhteen sen alikansiosta. Tiedosto on jo olemassa kohdekansiossa @@ -368,10 +363,8 @@ Ladataan… Tälle tiedostotyypille ei löytynyt sovellusta. sekuntia sitten - Käyttöoikeus tarvitaan Tallennusoikeudet %1$s toimii parhaiten, kun sille on myönnetty käyttöoikeus tallennustilan käyttöön. Voit myöntää täydet käyttöoikeudet tai vain luku-oikeudet kuviin ja videoihin. - %1$s tarvitsee käyttöoikeuden tallennustilan käyttöön tiedostojen lähettämiseksi. Voit myöntää täydet oikeudet kaikkiin tiedostoihin tai vain luku -oikeudet kuviin ja videoihin. Tarkistetaan kohdetta… Siivotaan… Päivitetään tietojen tallennuspolkua @@ -403,7 +396,6 @@ Nimeä uudelleen Lähetys epäonnistui. Ei internetyhteyttä Virhe palauttaessa tiedostoversiota! - Tiedostoversio palautettu onnistuneesti. Tiedot Lataa Vie @@ -437,7 +429,6 @@ Paikallinen: %1$s Siirrä kaikki Etä: %1$s - Kaikki tiedostot siirrettiin Välitä 4 tuntia Google rajoitti APK- ja AAB-tiedostojen latauksen! @@ -484,7 +475,6 @@ Lukinnut %1$s sovellus %1$sin Android-sovelluksen lokit Sovellusta ei löytynyt lokien lähettämistä varten. Asenna sähköpostisovellus. - Kirjautuneena tilillä %1$s Kirjaudu sisään Linkki %1$s selainkäyttöliittymääsi. Poista lokitiedot @@ -566,7 +556,6 @@ Palvelimen elinkaari on päättynyt, päivitä! Lisää -valikko Anna suojakoodisi - Suojakoodi kysytään joka kerta, kun sovellus käynnistetään Anna suojakoodi Suojakoodit eivät täsmää Anna suojakoodisi uudelleen @@ -574,10 +563,9 @@ Suojakoodi poistettu Suojakoodi tallennettu Virheellinen suojakoodi - Napauta sivua lähentääksesi + Keskeytä Salli Kiellä - Tiedostojen lähetys ja lataaminen vaatii lisäoikeuksia. Kuvan liittämiseksi ei löytynyt sovellusta Avaa %1$s pysäytä @@ -673,7 +661,6 @@ GNU yleinen lisenssi, versio 2 Ilmoitusta ei voitu poistaa Poista Poistettu - Poista Anna uusi nimi Paikallisen kopion nimeä ei voitu muuttaa, yritä eri nimeä Nimen muutos epäonnistui, nimi on jo käytössä @@ -749,7 +736,6 @@ GNU yleinen lisenssi, versio 2 Jaa linkki Lähetä linkki Poista - Jaa… Kuvake jaetulta käyttäjältä jaa jaettu @@ -800,7 +786,6 @@ GNU yleinen lisenssi, versio 2 Sisäinen tallennustila Elokuvat Musiikki - Täysi pääsy Media vain luku-tilassa Kuvat Itse ylläpidetty työalusta jota sinä kontrolloit. \nTämä on virallinen kehitysversio, sisältäen pävittäin vaihtuvia uusia ja testaamattomia toimintoja, jotka voivat epävakauttaa ohjelmistoa ja aiheuttaa tietojen häviämistä. Sovellus on tarkoitettu käyttäjille jotka haluavat testata ja raportoida ohjelman virheitä jos niitä tapahtuu. Älä käytä sitä työ ympäristössä!\n\nSekä virallinen kehitysversio että normaali versio ovat saatavilla F-droid:ssa ja ne voidaan asentaa samanaikaisesti. diff --git a/app/src/main/res/values-fr/strings.xml b/app/src/main/res/values-fr/strings.xml index 6e9691aac1f8..45be2b123443 100644 --- a/app/src/main/res/values-fr/strings.xml +++ b/app/src/main/res/values-fr/strings.xml @@ -45,26 +45,20 @@ Recherche dans %s Apparaître hors-ligne Les résultats affichés ici sont générés par l\'IA. Veillez à toujours les vérifier. - Ajouter une nouvelle tâche Échec de l\'envoi du message Impossible de récupérer les messages de conversation - Créer une nouvelle tâche en bas à droite - Tapez du texte Êtes-vous sûr de vouloir supprimer cette tâche ? Supprimer la tâche Essayez d\'envoyer un message pour déclencher une conversation. Bonjour ! En quoi puis-je vous aider aujourd’hui ? - Chargement de la liste des tâches... Une erreur est survenue lors de la création de la tâche La tâche a bien été créée Une erreur est survenue lors de la suppression de la tâche Tâche supprimée avec succès - La liste des tâches est vide. La liste des tâches est vide. Vérifiez la configuration de l’application de l’assistant. Impossible de récupérer la liste des tâches, veuillez vérifier votre connexion Internet. Supprimer la tâche Le résultat de la tâche n\'est pas encore prêt. - Impossible de récupérer les types des tâches, veuillez vérifier votre connexion Internet. Assistant Entrée Sortie @@ -133,6 +127,7 @@ Occupé Agenda Agendas + Annuler Le chargement du certificat pose problème. Notes de version de la version de développement Revenez plus tard ou actualisez la page. @@ -225,7 +220,6 @@ Impossible de récupérer la liste des conversations Discussions Copié - Copié dans le presse-papier Une erreur est survenue lors de la copie de ce fichier ou dossier Il n\'est pas possible de copier un dossier vers un de ses descendants Le fichier existe déjà dans le dossier de destination @@ -439,10 +433,8 @@ Chargement… Aucune application trouvée pour ce type de fichier. à l\'instant - Autorisations requises Autorisations d\'accès au stockage %1$s fonctionne mieux avec les autorisations d\'accès au stockage. Vous pouvez choisir un accès complet à tous les fichiers ou un accès en lecture seule aux photos et vidéos. - %1$s a besoin d\'autorisations concernant la gestion des fichiers afin de téléverser des fichiers. Vous pouvez choisir un accès complet à tous les fichiers ou un accès en lecture seule aux photos et vidéos. Autoriser l\'accès à partir d\'autres applications Vérification de la destination… Nettoyage… @@ -480,7 +472,6 @@ Échec du téléversement. Pas de connexion internet %s existe déjà, aucun conflit détecté Erreur, la version du fichier n\'a pas été restaurée ! - Restauration de la version du fichier réussie. Détails Télécharger Exporter @@ -520,7 +511,6 @@ Local : %1$s Tout déplacer Distant : %1$s - Tous les fichiers ont été déplacés Suivant 4 heures Google restreint le téléchargement des fichiers APK / AAB ! @@ -575,7 +565,6 @@ Verrouillé par %1$s application Logs de l\'application Android %1$s Pas d\'app d\'envoie de logs trouvé. Installer un client e-mail. - Connecté en tant que %1$s Se connecter Adresse URL visible dans la barre d\'adresse de votre navigateur Web lorsque vous êtes connecté à %1$s. Supprimer les logs @@ -678,7 +667,6 @@ Le serveur est obsolète, veuillez mettre à jour ! Plus de menu Saisissez votre code de sécurité - Le code de sécurité sera demandé à chaque ouverture de l\'application Veuillez saisir votre code de sécurité Le code de sécurité sera demandé chaque fois que l’application est ouverte ou rouverte après 5 secondes. Les codes de sécurité ne sont pas identiques @@ -687,11 +675,10 @@ Code de sécurité supprimé Code de sécurité enregistré Code de sécurité incorrect + Pause Impossible d\'ouvrir un PDF protégé par un mot de passe. Veuillez utiliser une visionneuse PDF externe. - Appuyez sur une page pour zoomer Accepter Refuser - Des permissions supplémentaires sont exigées pour téléverser et télécharger des fichiers. Choisir un contact avec qui partager Aucune application trouvée pour utiliser cette image Épingler sur l\'écran d\'accueil @@ -800,7 +787,6 @@ Erreur lors de la suppression des notifications. Supprimer Supprimé - Supprimer Entrez un nouveau nom Impossible de renommer la version locale; veuillez réessayer avec un nom différent Impossible de renommer, le nom est déjà utilisé @@ -896,7 +882,6 @@ Lien de partage Envoyer le lien Désactiver - Partager avec… Avatar de l\'utilisateur partagé partage partagé @@ -953,7 +938,6 @@ L\'autorisation d\'accès au stockage est requise pour le téléchargement automatique. L\'autorisation de stockage est requise pour le téléchargement de fichiers. Ne pas demander - Accès complet Média en lecture seule Images La plateforme de productivité auto-hébergée qui vous permet de garder le contrôle.\n\nFonctionnalités :\n* Interface simple et moderne, adaptée au thème de votre serveur\n* Importez des fichiers sur votre serveur Nextcloud\n* Partagez-les avec d\'autres personnes\n* Synchronisez vos fichiers et dossiers favoris\n* Recherchez dans tous les dossiers de votre serveur\n* Import automatique des photos et vidéos prises par votre appareil\n* Restez informé grâce aux notifications\n* Prise en charge multi-comptes\n* Accès sécurisé à vos données par empreinte digitale ou code PIN\n* Intégration à DAVx⁵ (anciennement DAVdroid) pour une configuration facile de la synchronisation du calendrier et des contacts\n\nVeuillez signaler tous les problèmes sur https://github.com/nextcloud/android/issues et discuter de cette application sur https://help.nextcloud.com/c/clients/android\n\nNouveauté sur Nextcloud ? Nextcloud est un serveur privé de synchronisation, de partage et de communication de fichiers. C\'est un logiciel libre, et vous pouvez l\'héberger vous-même ou faire appel à une entreprise pour le faire pour vous. De cette façon, vous contrôlez vos photos, votre calendrier et vos données de contact, vos documents et tout le reste.\n\nConsultez Nextcloud sur https://nextcloud.com @@ -1099,7 +1083,6 @@ Fichier non trouvé. Êtes-vous sûr que ce fichier existe ou qu\'un conflit précédent n\'a pas été résolu ? Impossible de retrouver le fichier sur le serveur. Un autre utilisateur l\'a peut-être supprimé Nom du dossier - Réessayer de téléverser les fichiers locaux qui ont échoué Sélectionnez le dossier de téléversement Impossible d\'envoyer %1$s Le téléversement a échoué, reconnectez-vous diff --git a/app/src/main/res/values-ga/strings.xml b/app/src/main/res/values-ga/strings.xml index 220a42ed2947..8c4b2a613253 100644 --- a/app/src/main/res/values-ga/strings.xml +++ b/app/src/main/res/values-ga/strings.xml @@ -45,27 +45,24 @@ Cuardaigh i %s Le feiceáil as líne Is í an intleacht shaorga a ghineann an t-aschur a thaispeántar anseo. Déan cinnte go ndéanann tú seiceáil dhúbailte i gcónaí. - Cuir tasc nua leis - Cruthaigh tasc nua ón mbun ar dheis - Clóscríobh roinnt téacs + Theip ar theachtaireacht a sheoladh + Theip ar theachtaireachtaí comhrá a fháil An bhfuil tú cinnte gur mhaith leat an tasc seo a scriosadh? Scrios tasc Bain triail as teachtaireacht a sheoladh chun tús a chur le comhrá. Dia duit ann! Cad is féidir liom cabhrú leat inniu? - Liosta tascanna á lódáil… Tharla earráid agus an tasc á chruthú D\'éirigh leis an tasc a chruthú Tharla earráid agus an tasc á scriosadh D\'éirigh leis an tasc a scriosadh - Tá liosta tascanna folamh. Tá an liosta tascanna folamh. Seiceáil cumraíocht aip an chúntóra. Ní féidir liosta tascanna a fháil, seiceáil do nasc idirlín le do thoil. Scrios Tasc Níl an t-aschur tasc réidh fós. - Ní féidir cineálacha tascanna a fháil, seiceáil do nasc idirlín le do thoil. Cúntóir Ionchur Aschur + Ag smaoineamh… Cuntas gaolmhar gan aimsiú! Theip ar rochtain: %1$s Níl an cuntas curtha leis an ngléas seo fós @@ -130,6 +127,7 @@ Gnóthach Féilire Féilirí + Cealaigh Tharla fadhb agus an teastas á lódáil. Changelog leagan dev Seiceáil siar ar ball nó athlódáil. @@ -214,12 +212,14 @@ Níor aimsíodh aon chomhad Níorbh fhéidir do chúltaca deiridh a aimsiú! Athruithe ábhair á mbrath + Theip ar chomhrá a chruthú Scrios an comhrá + Theip ar an gcomhrá a scriosadh Níor aimsíodh aon chomhrá Níl aon chomhrá fós + Theip ar an liosta comhráite a fháil Comhráite Cóipeáladh - Cóipeáladh chuig an ngearrthaisce Tharla earráid agus iarracht á déanamh an comhad nó an fillteán seo a chóipeáil Ní féidir fillteán a chóipeáil isteach i gceann dá bhunfhillteáin féin Tá an comhad i láthair cheana féin san fhillteán ceann scríbe @@ -323,6 +323,7 @@ Cúntóir Tuilleadh Tuilleadh aipeanna Nextcloud + Ní féidir an roghnóir comhad a oscailt Theip ar an seoladh ríomhphoist a phiocadh. Socraigh mar criptithe Ní féidir teastas an fhreastalaí a fháil @@ -392,6 +393,7 @@ Níl cead agat comhaid a chruthú ná a uaslódáil sa fhillteán seo. Scaireanna seachtracha Cuir leis nó uaslódáil + Theip ar chomhrá coinbhleachta a chruthú Theip ar an gcomhad a chur ar aghaidh chuig an mbainisteoir íoslódála Theip ar an gcomhad a phriontáil Theip ar an eagarthóir a thosú @@ -433,10 +435,8 @@ Á lódáil… Níl aon aip socraithe chun an cineál comhaid seo a láimhseáil. soicind ó shin - Ceadanna ag teastáil Ceadanna stórála Is fearr a oibríonn %1$s le ceadanna chun an stóras a rochtain. Is féidir leat rochtain iomlán a roghnú ar gach comhad, nó rochtain inléite amháin ar ghrianghraif agus físeáin. - Teastaíonn cead bainistíochta comhad ó %1$s chun comhaid a uaslódáil. Is féidir leat rochtain iomlán a roghnú ar gach comhad, nó rochtain inléite amháin ar ghrianghraif agus físeáin. Ceadaigh rochtain ó aipeanna eile Ceann scríbe á sheiceáil… Glanadh… @@ -474,7 +474,6 @@ Theip ar an uaslódáil. Gan nasc idirlín Tá %s ann cheana féin, níor braitheadh ​​aon choimhlint Earráid agus leagan an chomhaid á athchóiriú! - D\'éirigh leis an leagan comhaid a athchóiriú. Sonraí Íoslódáil Easpórtáil @@ -514,7 +513,6 @@ Áitiúil: %1$s Bog ar fad Cianda: %1$s - Bogadh gach comhad Ar aghaidh 4 uair an chloig Chuir Google cosc ar chomhaid APK/AAB a íoslódáil! @@ -569,7 +567,6 @@ Glasáilte ag aip %1$s %1$s loga aip Android Níor aimsíodh aon aip chun logaí a sheoladh. Suiteáil cliant ríomhphoist le do thoil. - Logáilte isteach mar %1$s Logáil isteach An nasc chuig do chomhéadan gréasáin %1$s nuair a osclaíonn tú é sa bhrabhsálaí. Scrios logs @@ -672,7 +669,6 @@ Tá deireadh ré sroichte ag an bhfreastalaí, uasghrádaigh le do thoil! Tuilleadh roghchlár Cuir isteach do phaschód - Iarrfar an paschód gach uair a thosófar an app Cuir isteach do phaschód le do thoil Iarrfar an pasfhocal gach uair a osclófar nó a athosclófar an aip tar éis 5 soicind. Níl na paschóid mar an gcéanna @@ -681,11 +677,10 @@ Scriosadh an paschód Paschód stóráilte Paschód mícheart + Sos Ní féidir an PDF atá cosanta ag pasfhocal a oscailt. Bain úsáid as breathnóir PDF seachtrach le do thoil. - Tapáil ar leathanach chun zúmáil isteach Ceadaigh shéanadh - Ceadanna breise a theastaíonn chun comhaid a uaslódáil agus a íoslódáil. Roghnaigh teagmháil le roinnt leis Níor aimsíodh aon aip chun pictiúr a shocrú leis Pinn chuig an scáileán baile @@ -794,7 +789,6 @@ Theip ar an bhfógra a bhaint. Bain Scriosta - Bain Cuir isteach ainm nua Níorbh fhéidir cóip logánta a athainmniú, bain triail as ainm eile Ní féidir athainmniú a dhéanamh, ainm glactha cheana féin @@ -890,7 +884,6 @@ Comhroinn nasc Seol nasc Neamhsocraithe - Roinn le… Avatar ó úsáideoir roinnte sciar roinnte @@ -947,7 +940,6 @@ Tá cead stórála ag teastáil le haghaidh uaslódáil uathoibríoch. Tá cead stórála ag teastáil le haghaidh uaslódálacha comhad. Ná fiafraigh - Rochtain iomlán Meáin inléite amháin Pictiúir An t-ardán táirgiúlachta féinóstáilte a choinníonn tú i gceannas.\n\nGnéithe:\n* Comhéadan éasca, nua-aimseartha, oiriúnach do théama do fhreastalaí\n* Uaslódáil comhaid chuig do fhreastalaí Nextcloud\n* Roinn iad le daoine eile\n* Coinnigh do chuid comhad agus fillteáin is fearr leat sioncrónaithe\n* Cuardaigh trasna na bhfillteán go léir ar do fhreastalaí\n* Uaslódáil Uathoibríoch le haghaidh grianghraif agus físeáin a thóg do ghléas\n* Coinnigh suas chun dáta le fógraí\n* Tacaíocht ilchuntais\n* Rochtain shlán ar do shonraí le méarloirg nó PIN\n* Comhtháthú le DAVx⁵ (ar a dtugtaí DAVdroid roimhe seo) le haghaidh socrú éasca ar shioncrónú féilire agus teagmhálacha\n\nTuairiscigh gach fadhb ag https://github.com/nextcloud/android/issues agus pléigh an aip seo ag https://help.nextcloud.com/c/clients/android\n\nNua le Nextcloud? Is freastalaí príobháideach sioncrónaithe, comhroinnte agus cumarsáide comhad é Nextcloud. Is bogearraí saor in aisce é, agus is féidir leat é a óstáil tú féin nó cuideachta a íoc chun é a dhéanamh duit. Ar an mbealach sin, tá smacht agat ar do ghrianghraif, do shonraí féilire agus teagmhála, do dhoiciméid agus gach rud eile.\n\nFéach ar Nextcloud ag https://nextcloud.com @@ -1093,7 +1085,6 @@ Comhad gan aimsiú. An bhfuil tú cinnte go bhfuil an comhad seo ann nó nár réitíodh coinbhleacht roimhe seo? Níorbh fhéidir linn an comhad a aimsiú ar an bhfreastalaí. Seans gur scrios úsáideoir eile an comhad Ainm fillteáin - Déan iarracht arís comhaid logánta ar theip orthu a uaslódáil Roghnaigh fillteán uaslódála Níorbh fhéidir %1$s a uaslódáil Theip ar an uaslódáil, logáil isteach arís diff --git a/app/src/main/res/values-gd/strings.xml b/app/src/main/res/values-gd/strings.xml index 739b4db2f844..6cc1bf8722dc 100644 --- a/app/src/main/res/values-gd/strings.xml +++ b/app/src/main/res/values-gd/strings.xml @@ -75,6 +75,7 @@ Annsachdan Na h-uile faidhle Meadhanan + Cancel Thachair duilgheadas le luchdadh an teisteanais. Loga nan atharraichean – tionndadh leasachaidh Bogsa-cromaige @@ -140,7 +141,6 @@ Chaidh ion-phortadh a chur air an sgeideal is tòisichidh i a dh’aithghearr Cha deach faidhle a lorg Cha deach an lethbhreac-glèidhidh mu dheireadh agad a lorg! - Chaidh lethbhreac dheth a chur air an stòr-bhòrd Thachair mearachd le lethbhreac dhen fhaidhle no pasgan seo Cha ghabh lethbhreac de phasgan a chur am broinn fo-phasgan aige fhèin Tha am faidhle sa cheann-uidhe mu thràth @@ -298,7 +298,6 @@ Cha b’ urrainn dhuinn am faidhle a shioncronachadh. A’ sealltainn an tionndaidh mu dheireadh a tha ri fhaighinn. Thoir ainm ùr air Mearachd ag aiseag tionndadh dhen fhaidhle! - Chaidh tionndadh dhen fhaidhle aiseag. Mion-fhiosrachadh Luchdaich a-nuas Chaidh %1$s a thoirt air an fhaidhle rè an luuchdaidh suas @@ -326,7 +325,6 @@ Ionadail: %1$s Gluais na h-uile Cèin: %1$s - Chaidh a h-uile faidhle a ghluasad Sìn air adhart 4 uairean a thìde Ainm @@ -421,7 +419,6 @@ Ràinig am frithealaiche deireadh a bheatha, tha e feumach air àrdachadh! Clàr-taice nan nithean a bharrachd Cuir a-steach an còd-faire agad - Thèid an còd-faire iarraidh ort gach turas a thèid an aplacaid a chur gu dol Cuir a-steach an còd-faire agad Chan eil an dà chòd-fhaire co-ionnann Cuir a-steach an còd-faire agad a-rithist @@ -431,7 +428,6 @@ Tha an còd-faire ceàrr Ceadaich Diùlt - Tha feum air barrachd cheadan mus gabh faidhlichean a luchdadh suas is a-nuas. Cha deach aplacaid a lorg airson dealbhan a chur leatha cuir stad air toglaich @@ -501,7 +497,6 @@ Cha deach leinn am brath a thoirt air falbh. Thoir air falbh Chaidh a sguabadh às - Thoir air falbh Cuir a-steach ainm ùr Cha b’ urrainn dhuinn an t-ainm ùr a thoirt air an lethbhreac ionadail, feuch ainm eile Tha ghabh an t-ainm ùr a thoirt air on a tha e ’ga chleachdadh mu thràth @@ -557,7 +552,6 @@ Ceangal co-roinnidh Cuir an ceangal Neo-shuidhich - Co-roinn le… Avatar cleachdaiche cho-roinnte co-roinn ’ga cho-roinneadh diff --git a/app/src/main/res/values-gl/strings.xml b/app/src/main/res/values-gl/strings.xml index 7b3af84dbdd1..eb3f374e550e 100644 --- a/app/src/main/res/values-gl/strings.xml +++ b/app/src/main/res/values-gl/strings.xml @@ -45,26 +45,20 @@ Buscar en %s Aparecer como sen conexión O resultado que se amosa aquí foi xerado por IA. Asegúrese de facer sempre unha dobre comprobación - Engadir unha nova tarefa Produciuse un fallo ao enviar unha mensaxe Produciuse un fallo ao recuperar as mensaxes da parola - Crear unha nova tarefa a desde a parte inferior dereita - Escriba algún texto Confirma que quere eliminar esta tarefa? Eliminar tarefa Probe a enviar unha mensaxe para iniciar unha conversa. Ola! En que podo axudarlle hoxe? - Cargando a lista de tarefas… Produciuse un erro ao crear a tarefa A tarefa creouse satisfactoriamente Produciuse un erro ao eliminar a tarefa A tarefa foi eliminada satisfactoriamente - A lista de tarefas está baleira A lista de tarefas está baleira. Comprobe a configuración da aplicación do asistente. Non é posíbel recuperar a lista de tarefas. Comprobe a conexión a Internet. Eliminar tarefa A saída da tarefa aínda non está preparada. - Non é posíbel recuperar os tipos de tarefas. Comprobe a conexión a Internet. Asistente Entrada Saída @@ -133,6 +127,7 @@ Ocupado Calendario Calendarios + Cancelar Hai un problema ao cargar o certificado. Notas da versión de desenvolvemento Volver máis tarde ou volver cargar. @@ -225,7 +220,6 @@ Produciuse un fallo ao recuperar a lista de conversas. Conversas Copiado - Copiado no portapapeis Produciuse un erro ao tentar copiar este ficheiro ou cartafol. Non é posíbel copiar un cartafol nun dos seus propios subcartafoles Este ficheiro xa existe no cartafol de destino @@ -329,6 +323,7 @@ Asistente Máis Máis aplicacións de Nextcloud + Non é posíbel abrir o selector de ficheiros Produciuse un fallo ao escoller o enderezo de correo. Definir como cifrado Non é posíbel recuperar o certificado de servidor @@ -398,6 +393,7 @@ Non ten permiso para ou crear ou enviar os ficheiros neste cartafol. Comparticións externas Engadir ou enviar + Produciuse un fallo ao crear o diálogo de conflito Produciuse un fallo ao pasar o ficheiro para o xestor de descargas Produciuse un fallo ao imprimir o ficheiro Produciuse un fallo ao iniciar o editor @@ -439,10 +435,8 @@ Cargando… Non foi configurada unha aplicación para manexar este tipo de ficheiro. hai uns segundos - Necesítanse permisos Permisos de almacenamento %1$s funciona mellor con permisos para acceder ao almacenamento. Pode escoller acceso completo a todos os ficheiros ou acceso de só lectura a fotos e vídeos. - %1$s precisa permisos de xestión de ficheiros para enviar ficheiros. Pode escoller acceso completo a todos os ficheiros ou acceso de só lectura a fotos e vídeos. Permitir o acceso desde outras aplicacións Comprobando o destino… Limpando… @@ -480,7 +474,6 @@ Produciuse un fallo no envío. Non hai conexión a Internet %s xa existe, non se detectou ningún conflito Produciuse un erro ao restaurar a versión do ficheiro - Versión do ficheiro restaurada satisfactoriamente. Detalles Descargar Exportar @@ -520,7 +513,6 @@ Local: %1$s Mover todo Remoto: %1$s - Foron movidos todos os ficheiros Reenviar 4 horas Google restrinxiu a descarga de ficheiros APK/AAB. @@ -575,7 +567,6 @@ Bloqueado pola aplicación %1$s Atopáronse %1$s aplicacións de rexistros para Android Non se atopou ningunha aplicación para enviar rexistros. Instale un cliente de correo-e. - Conectado como %1$s Acceder A ligazón á súa interface web %1$s cando a abre no navegador. Eliminar rexistros @@ -678,7 +669,6 @@ O servidor acadou a fin da súa vida. Anóveo! Máis menús Introduza o seu código de acceso - Solicitaráselle o código de acceso cada vez que inicie a aplicación Introduza o seu código de acceso Solicitaráselle o código de acceso cada vez que se abra a aplicación ou se volva abrir após 5 segundos. Os códigos de acceso non son iguais @@ -687,11 +677,10 @@ O código de acceso foi eliminado Gardouse o código de acceso Código de acceso incorrecto + Pausa Non é posíbel abrir o PDF protexido con contrasinal. Use un visor de PDF externo. - Toque nunha páxina para ampliala Permitir Denegar - Precísanse permisos adicionais para enviar e descargar ficheiros. Escolla un contacto co que compartir Non se atopou unha aplicación coa que definir unha imaxe Fixar na pantalla de Inicio @@ -801,7 +790,6 @@ Produciuse un fallo ao retirar a notificación. Retirar Eliminado - Retirar Introduza un nome novo Non foi posíbel cambiarlle o nome a copia local, ténteo cun un nome diferente Non foi posíbel cambiarlle o nome, o nome xa está ocupado @@ -897,7 +885,6 @@ Ligazón para compartir Enviar ligazón Sen definir - Compartir con… Avatar de usuario compartido compartir compartido @@ -954,7 +941,6 @@ Precisase de permiso de almacenamento para o envío automático. Precisase de permiso de almacenamento para o envío de ficheiros. Non preguntar - Acceso completo Medios de só lectura Imaxes A plataforma de produtividade en aloxamento autónomo que mantén controlada.\n\nCaracterísticas:\n* Interface doada e moderna, totalmente tematizada ao aliñarse co tema do seu servidor\n* Enviar os seus ficheiros ao seu Nextcloud\n* Compartir os seus ficheiros con outras persoas\n* Conservar os seus ficheiros e cartafoles favoritos sincronizados\n* Buscar en todos os cartafoles do servidor\n* Enviar automaticamente fotos e vídeos feitos no seu dispositivo\n* Estar ao día coas notificacións\n* Admite múltiples contas\n* Acceso seguro aos seus datos con pegada dactilar ou PIN\n* Integración con DAVx⁵ (anteriormente coñecido como DAVdroid) para facilitar a configuración da sincronización de calendarios e contactos\n\nAgradecémoslle que nos informe de calquera problema en https://github.com/nextcloud/android/issues, pode conversar sobre esta aplicación en https://help.nextcloud.com/c/clients/android\n\nE novo en Nextcloud? Nextcloud é un servidor privado para sincronizar e compartir ficheiros. É completamente libre e pode instalalo Vde. ou contratar a unha empresa ou cooperativa para que o faga por Vde. É o camiño para que sexa Vde. quen teña o control sobre as súas fotos, calendario, caderno de contactos, documentos e todo o demais.\n\nCoñeza Nextcloud en https://nextcloud.com @@ -1100,7 +1086,6 @@ Non se atopou o ficheiro. Está seguro de que este ficheiro existe ou non se resolveu un conflito anterior? Non foi posíbel localizar o ficheiro no servidor. Outro usuario pode ter eliminado o ficheiro Nome do cartafol - Tentar de novo enviar os ficheiros locais que fallaron Escoller o cartafol de envío Non foi posíbel enviar: %1$s Produciuse un fallo no envío, acceda de novo. diff --git a/app/src/main/res/values-hr/strings.xml b/app/src/main/res/values-hr/strings.xml index 955d8eff7a98..162e473ca1d2 100644 --- a/app/src/main/res/values-hr/strings.xml +++ b/app/src/main/res/values-hr/strings.xml @@ -84,6 +84,7 @@ Zauzeto Kalendar Kalendari + Cancel Došlo je do poteškoća prilikom učitavanja vjerodajnice. Zapis promjena razvojne inačice Potvrdni okvir @@ -159,7 +160,6 @@ Obriši razgovor Nije pronađen nijedan razgovor Razgovori - Kopirano u međuspremnik Došlo je do pogreške prilikom kopiranja ove datoteke ili mape Nije moguće kopirati mapu u jednu od svojih osnovnih mapa Datoteka je već prisutna u odredišnoj mapi @@ -312,10 +312,8 @@ Učitavanje… Nije postavljena nijedna aplikacija za obrađivanje ove vrste datoteka. prije nekoliko sekundi - Potrebna su dopuštenja Dopuštenja za pohranu %1$sradi najbolje s dozvoljenim pristupom prostoru za pohranu. Možete odabrati potpuni pristup svim datotekama ili samo mogućnost \"čitanja\" za fotografije i video materijale. - %1$szahtijeva dodatna dopuštenja za slanje datoteka. Možete odabrati potpuni pristup svim datotekama ili samo mogućnost \"čitanja\" za fotografije i video materijale. Provjera odredišta... Čišćenje… Ažuriranje mape za pohranu datoteka @@ -341,7 +339,6 @@ Datoteku nije moguće sinkronizirati. Prikazana je posljednja dostupna inačica. Preimenuj Pogreška pri vraćanju inačice datoteke! - Inačica datoteke uspješno je vraćena. Pojedinosti Preuzmi Izvoz @@ -371,7 +368,6 @@ Lokalno: %1$s Premjesti sve Udaljeno: %1$s - Sve datoteke su premještene Naprijed 4 sata Datoteka s ovakvim nazivom će biti skrivena @@ -481,7 +477,6 @@ Poslužitelj je na kraju radnog vijeka, nadogradite ga! Više izbornika Unesite zaporku - Zaporka će se tražiti prilikom svakog pokretanja aplikacije Unesite zaporku Zaporke se ne podudaraju Ponovno unesite zaporku @@ -489,10 +484,9 @@ Zaporka je izbrisana Zaporka je spremljena Neispravna zaporka - Pritisni na stranicu za uvećavanje + Pauza Dopusti Spriječi - Potrebna su dodatna dopuštenja za otpremanje i preuzimanje datoteka. Nije pronađena nijedna aplikacija za postavljanje slike s zaustavi uključi/isključi @@ -565,7 +559,6 @@ Nije uspjelo uklanjanje obavijesti. Ukloni Izbrisano - Ukloni Unesite novi naziv Nije moguće preimenovati lokalnu kopiju, pokušajte s drugim nazivom Preimenovanje nije moguće, naziv je već zauzet @@ -631,7 +624,6 @@ Dijeli poveznicu Pošalji poveznicu Ukloni - Dijeli s… Avatar iz dijeljenog korisnika dijeli dijeljeno @@ -680,7 +672,6 @@ Unutarnja pohrana Filmovi Glazba - Puni pristup Medijske datoteke samo za čitanje Slike Samopostavljena platforma pospješuje produktivnost i omogućuje vam da zadržite kontrolu.\nTo je službena razvojna inačica koja se isporučuje s dnevnim uzorkom svake nove neispitane funkcionalnosti, što može uzrokovati nestabilnost i gubitak podataka. Aplikacija je namijenjena korisnicima koji žele testirati i prijaviti pogreške, ako se iste pojave. Nemojte je upotrebljavati za važne radne zadatke!\n\nSlužbena razvojna i uobičajena inačica dostupne su putem F-droida i mogu biti istovremeno instalirane. diff --git a/app/src/main/res/values-hu-rHU/strings.xml b/app/src/main/res/values-hu-rHU/strings.xml index e4bd07ffa8d5..f96d7a79eea6 100644 --- a/app/src/main/res/values-hu-rHU/strings.xml +++ b/app/src/main/res/values-hu-rHU/strings.xml @@ -44,21 +44,15 @@ Egy modult jelenít meg a irányítópultról Keresés itt: %s Megjelenés nem kapcsolódottként - Új feladat hozzáadása - Új feladat létrehozása a jobb lentiből - Gépeljen be szöveget Valóban törölni akarja ezt a feladatot? Feladat törlése - Feladatlista betöltése… Hiba történt egy feladat létrehozása során Feladat sikeresen létrehozva Hiba történt a feladat törlése során Feladat sikeresen törölve - A feladatlista üres. A feladatlista nem kérhető le, ellenőrizze az internetkapcsolatát. Feladat törlése A feladat kimenete még nincs kész. - A feladattípusok nem kérhetők le, ellenőrizze az internetkapcsolatát. Asszisztens Bemenet Kimenet @@ -124,6 +118,7 @@ Foglalt Naptár Naptárak + Cancel Probléma történt a tanúsítvány betöltésekor. Változásnapló fejlesztői verziója Nézzen vissza később vagy töltse újra. @@ -209,7 +204,6 @@ A legutóbbi biztonsági mentés nem található! Nem található beszélgetés Beszélgetések - Vágólapra másolva Hiba történt a fájl vagy mappa másolása közben Nem másolható egy mappa a saját almappájába A fájl már létezik a célmappában @@ -420,10 +414,8 @@ Betöltés… Nincs alkalmazás beállítva ehhez a fájltípushoz. másodperce - Engedély szükséges Tárhely engedélyek A %1$s a tároló engedéllyel működik a legjobban. Választhat, hogy az összes fájlhoz teljes hozzáférést ad, vagy csak írásvédett elérést a fényképekhez és a videókhoz. - A %1$s számára fájlkezelési engedély szükséges a fájlok feltöltéséhez. Választhat, hogy az összes fájlhoz teljes hozzáférést ad, vagy csak írásvédett elérést a fényképekhez és a videókhoz. Egyéb alkalmazások hozzáférésének engedélyezése Cél ellenőrzése… Tisztítás… @@ -461,7 +453,6 @@ A feltöltés sikertelen. Nincs internetkapcsolat. A(z) %s már létezik, nincs ütközés észlelve Hiba a fájl verziójának visszaállításakor! - Fájl verzió sikeresen visszaállítva. Részletek Letöltés Exportálás @@ -496,7 +487,6 @@ Helyi: %1$s Összes áthelyezése Távoli: %1$s - Összes fájl áthelyezve Tovább 4 óra A Google korlátozta az APK/AAB-fájlok letöltését. @@ -551,7 +541,6 @@ Zárolta: %1$s alkalmazás %1$s androidos alkalmazás naplói Nincs alkalmazás a napló küldéshez. Telepítsen egy levelezőprogramot. - Bejelentkezve mint %1$s Bejelentkezés A %1$s webes felületére mutató hivatkozás, amikor megnyitja a böngészőben. Naplók törlése @@ -651,7 +640,6 @@ A kiszolgáló elérte az életciklusa végét, kérjük frissítsen! További menü Írja be a számkódodat - A számkódra minden alkalommal szükség lesz az alkalmazás indításakor Adja meg a számkódot A számkódok nem egyeznek Adja meg újra a számkódot @@ -659,11 +647,10 @@ Számkód törölve Számkód eltárolva Hibás számkód + Szünet A jelszóval védett PDF nem nyitható meg. Használjon külső PDF-megjelenítőt. - A nagyításhoz koppintson a lapra Engedélyezés Megtagadás - További jogosultságokra van szükség a fájlok fel- és letöltéséhez. Válasszon névjegyet a megosztáshoz Nincs alkalmazás a képbeállításhoz Rögzítés a kezdőképernyőre @@ -770,7 +757,6 @@ Az értesítés eltávolítása sikertelen. Eltávolítás Törölve - Eltávolítás Adjon meg egy új nevet A helyi másolat nem nevezhető át, próbáljon meg egy másik nevet Nem nevezhető át, ez a név már foglalt @@ -866,7 +852,6 @@ Megosztás hivatkozással Hivatkozás küldése Kikapcsolás - Megosztás vele… Avatár a megosztott felhasználótól megosztás megosztva @@ -919,7 +904,6 @@ Belső tárhely Filmek Zene - Teljes hozzáférés Írásvédett média Képek A saját üzemeltetésű irodai platform, amely az Ön kezébe adja az irányítást. @@ -1083,7 +1067,6 @@ A Nextcloud itt érhető el: https://nextcloud.com A fájl nem található. Biztos, hogy létezik ez a fájl, vagy egy előző ütközés nem lett feloldva? A fájl nem található a kiszolgálón. Lehet, hogy egy másik felhasználó törölte a fájlt. Mappa neve - Sikertelen helyi fájlok újbóli feltöltése Válasszon feltöltési mappát A(z) %1$s feltöltése sikertelen Feltöltés sikertelen, újra be kell jelentkeznie diff --git a/app/src/main/res/values-in/strings.xml b/app/src/main/res/values-in/strings.xml index 9321f2649443..a51dd7c9acb0 100644 --- a/app/src/main/res/values-in/strings.xml +++ b/app/src/main/res/values-in/strings.xml @@ -44,21 +44,15 @@ Menampilkan satu gawit dari dasbor Cari dalam %s Tampak offline - Tambahkan tugas baru - Buat tugas baru dari kanan bawah - Tulis beberapa teks Apakah Anda yakin ingin menghapus tugas ini? Hapus tugas - Memuat daftar tugas... Terjadi kesalahan saat membuat tugas Tugas berhasil dibuat Terjadi kesalahan saat menghapus tugas Tugas berhasil dihapus - Daftar tugas kosong. Tidak dapat memperoleh daftar tugas, mohon periksa koneksi internet Anda. Hapus Tugas Output tugas belum siap. - Tidak dapat memperoleh jenis tugas, mohon periksa koneksi internet Anda. Asisten Input Output @@ -127,6 +121,7 @@ Otomatis unggah hanya bekerja dengan baik apabila Anda mengeluarkan aplikasi ini Sibuk Kalender Kalender + Cancel Terjadi permasalahan memuat sertifikat. Perubahan versi dev Periksa kembali nanti atau muat ulang. @@ -212,7 +207,6 @@ Otomatis unggah hanya bekerja dengan baik apabila Anda mengeluarkan aplikasi ini Tidak dapat menemukan pencadangan terakhir kamu! Mendeteksi perubahan konten Tersalin - Disalin ke papan klip Terjadi kesalahan ketika mencoba menyalin berkas atau folder ini Tidak memungkinkan untuk menyalin folder kedalam turunannya Berkas sudah ada didalam folder tujuan @@ -423,10 +417,8 @@ Otomatis unggah hanya bekerja dengan baik apabila Anda mengeluarkan aplikasi ini Memuat… Tidak ada aplikasi untuk membuka jenis berkas ini. beberapa detik yang lalu - Hak akses diperlukan Izin penyimpanan %1$s bekerja paling baik dengan izin akses penyimpanan. Anda dapat memilih akses ke semua berkas, atau akses hanya baca untuk foto dan video. - %1$s membutuhkan izin manajemen berkas untuk mengunggah berkas. Anda dapat memilih akses penuh ke semua berkas, atau akses hanya baca untuk foto dan video. Izinkan akses dari aplikasi lain Memeriksa tujuan… Membersihkan… @@ -464,7 +456,6 @@ Otomatis unggah hanya bekerja dengan baik apabila Anda mengeluarkan aplikasi ini Unggahan gagal. Tidak ada koneksi internet %s sudah ada, tidak ada konflik yang terdeteksi Kesalahan terjadi saat memulihkan versi file! - Berhasil memulihkan versi berkas. Detail Unduh Ekspor @@ -504,7 +495,6 @@ Otomatis unggah hanya bekerja dengan baik apabila Anda mengeluarkan aplikasi ini Lokal: %1$s Pindahkan semua Remote: %1$s - Semua berkas sudah dipindahkan Teruskan 4 jam Google melarang mengunduh file APK/AAB! @@ -559,7 +549,6 @@ Otomatis unggah hanya bekerja dengan baik apabila Anda mengeluarkan aplikasi ini Dikunci oleh aplikasi %1$s %1$s Android apl log Tidak ada aplikasi untuk mengirim log yang ditemukan. Silakan instal klien email. - Masuk sebagai %1$s Masuk Tautkan ke antarmuka web %1$s Anda saat Anda membukanya di peramban. Hapus log @@ -661,7 +650,6 @@ Otomatis unggah hanya bekerja dengan baik apabila Anda mengeluarkan aplikasi ini Server telah mencapai batas hidupnya, tolong ditingkatkan! Menu lainnya Masukkan kode sandi Anda - Kode sandi akan diminta setiap kali apl dijalankan. Masukkan kode kunci Anda Kode sandi tidak sama Masukkan lagi kode kunci Anda @@ -669,11 +657,10 @@ Otomatis unggah hanya bekerja dengan baik apabila Anda mengeluarkan aplikasi ini Kata sandi terhapus Kode sandi disimpan Kode sandi salah + Jeda Tidak dapat membuka PDF yang dilindungi sandi. Silakan gunakan penampil PDF eksternal. - Ketuk pada halaman untuk memperbesar Izinkan Tolak - Diperlukan ijin tambahan untuk mengunggah dan mengunduh berkas. Pilih kontak untuk dibagikan Tidak ada aplikasi untuk menyetel gambar yang ditemukan. Sematkan ke tampilan beranda @@ -779,7 +766,6 @@ Otomatis unggah hanya bekerja dengan baik apabila Anda mengeluarkan aplikasi ini Gagal menghapus notifikasi. Hapus Dihapus - Hapus Masukkan nama baru Tidak dapat mengganti nama salinan lokal, coba nama yang berbeda Pengubahan nama tidak memungkinkan, nama sudah diambil @@ -875,7 +861,6 @@ Otomatis unggah hanya bekerja dengan baik apabila Anda mengeluarkan aplikasi ini Bagikan tautan Kirim tautan Belum disetel - Bagikan dengan… Foto profil dari pengguna yang dibagikan bagikan dibagikan @@ -926,7 +911,6 @@ Otomatis unggah hanya bekerja dengan baik apabila Anda mengeluarkan aplikasi ini Penyimpanan internal Film Musik - Akses penuh Media hanya baca Gambar Platform produktivitas mandiri yang memberi Anda kendali penuh.\n\Fitur:\n* Mudah, tampilan modern, dan cocok dengan tema server Anda\n* Unggah file ke server Nextcloud Anda\n* Bagikan dengan yang lain\n* Buat file dan folder favorit Anda tetap tersinkron\n* Telusuri semua folder di server Anda\n* Unggah otomatis untuk foto dan video yang diambil dari perangkat Anda\n* Tetap terkabarkan dengan notifikasi\n* Mendukung penggunaan banyak akun (multi-account)\n* Akses data Anda dengan aman dengan sidik jari atau PIN\n* Integrasi dengan DAVx⁵ (dulu dikenal sebagai DAVdroid) untuk pemasangan sinkronisasi kalender dan kontak yang mudah\n\nTolong laporkan semua masalah aplikasi ini di https://github.com/nextcloud/android/issues dan diskusikan aplikasi ini di https://help.nextcloud.com/c/clients/android\n\nBaru mencoba Nextcloud? Nextcloud adalah server pribadi untuk sinkronisasi dan berbagi file serta berkomunikasi. Nextcloud adalah software libre sehingga Anda dapat meng-host sendiri atau membayar perusahaan untuk melakukannya untuk Anda. Dengan begitu, Anda memiliki kendali atas foto Anda, kalender dan data kontak Anda, dokumen dan semuanya yang Anda miliki.\n\nYuk, cek Nextcloud di https://nextcloud.com @@ -1076,7 +1060,6 @@ Berikut ini adalah daftar berkas lokal, dan berkas jarak jauh di %5$s yang terhu Berkas tidak ditemukan. Apakah Anda yakin bahwa berkas ini ada atau sebelumnya memiliki pertentangan yang belum terselesaikan? Kami tidak dapat menemukan berkas di server. Pengguna lain mungkin telah menghapus berkas tersebut. Nama folder - Mencoba mengunggah ulang file lokal yang gagal Pilih folder untuk mengunggah Tidak bisa mengunggah %1$s Unggahan gagal, coba masuk kembali diff --git a/app/src/main/res/values-is/strings.xml b/app/src/main/res/values-is/strings.xml index f73146ab1bf7..de294f0d5f0c 100644 --- a/app/src/main/res/values-is/strings.xml +++ b/app/src/main/res/values-is/strings.xml @@ -44,21 +44,15 @@ Sýnir einn viðmótshluta af stjórnborði Leita í %s Birtast ótengt - Bæta við nýju verki - Þú getur búið til nýtt verk neðst til hægri - Skrifaðu einhvern texta Ertu viss um að þú viljir eyða þessu verki? Eyða verki - Hleð inn verkefnalista… Villa kom upp við að búa til verkið Tókst að búa til verk Villa kom upp við að eyða verkinu Tókst að eyða verki - Verkefnalisti er tómur. Ekki er hægt að sækja verkefnalista, athugaðu nettenginguna þína. Eyða verki Yfirlitið yfir verkin er ekki tilbúið. - Ekki er hægt að sækja tegundir verka, athugaðu nettenginguna þína. Meðhjálpari Inntak Frálag @@ -124,6 +118,7 @@ Upptekinn Dagatal Dagatöl + Cancel Það kom upp vandamál við að lesa inn skilríkið. Breytingaskrá þróunarútgáfu Athugaðu aftur síðar eða endurlestu. @@ -208,7 +203,6 @@ Engin skrá fannst Gat ekki fundið síðasta öryggisafritið þitt! Samtöl - Afritað á klippispjald Villa kom upp við að reyna að afrita þessa skrá eða möppu Ekki er hægt að afrita möppu inn í eina af undirmöppum sínum Skráin er þegar til í móttökumöppunni @@ -419,10 +413,8 @@ Hleð inn… Ekkert forrit er uppsett til að meðhöndla þessa tegund skráa. sekúndum síðan - Heimilda er krafist Heimildir gagnageymslu %1$s virkar best með heimildum til að nota geymslurými. Þú getur valið að gefa fullan aðgang að öllum skrám, eða aðgang til að einungis lesa ljósmyndir og myndskeið. - %1$s þarf skráaumsýsluheimildir til að geta sent inn skrár. Þú getur valið að gefa fullan aðgang að öllum skrám, eða aðgang til að einungis lesa ljósmyndir og myndskeið. Leyfa aðgang úr öðrum forritum Athuga áfangastað… Hreinsun @@ -460,7 +452,6 @@ Innsending mistókst. Engin internettenging %s er þegar til, engir árekstrar fundust Villa við að endurheimta útgáfu skráar! - Tókst að endurheimta útgáfu skráar. Nánar Sækja Flytja út @@ -495,7 +486,6 @@ Staðvært: %1$s Færa allt Fjartengt: %1$s - Allar skrár voru færðar Áfram 4 klukkustundir Google takmarkaði niðurhal á APK/AAB-skrám! @@ -550,7 +540,6 @@ Læst af %1$s-forritinu %1$s atvikaskrár Android-forrita Ekkert forrit fannst til að senda atvikaskrár. Settu upp tölvupóstforrit. - Skráð inn sem %1$s Skrá inn Tengillinn á vefviðmót %1$s þegar þú opnar það í vafranum. Eyða atvikaskrám @@ -650,7 +639,6 @@ Netþjónninn er kominn að endimörkum líftíma síns, endilega uppfærðu hann! Valmynd með fleiru Settu inn lykilkóða - Lykilkóðans verður krafist í hvert skipti sem forritið er ræst Settu inn lykilkóðann þinn Lykilkóðarnir eru ekki eins Settu aftur inn lykilkóðann þinn @@ -658,11 +646,10 @@ Aðgangskóða eytt Geymdi lykilkóða Rangur lykilkóði + Í bið Get ekki opnað lykilorðsvarða PDF-skrár. Notaðu frekar utanaðkomandi PDF-skoðara. - Ýttu á síðu til að renna að Leyfa Neita - Krafist er viðbótarheimilda til að senda inn og sækja skrár. Veldu tengilið til að deila með Engin forrit fundust til að setja mynd Festa á upphafsskjá @@ -769,7 +756,6 @@ Mistókst að fjarlægja tilkynningu. Fjarlægja Eytt - Fjarlægja Settu inn nýtt nafn Gat endurnefnt staðvært afrit, prófaðu annað heiti Ekki hægt að endurnefna, heitið er frátekið @@ -865,7 +851,6 @@ Deila tengli Senda tengil... Endurstilla - Deila með %1 Auðkennismynd frá deildum notanda Deila deilt @@ -918,7 +903,6 @@ Innbyggð geymsla Kvikmyndir Tónlist - Fullur aðgangur Skrifvarinn gagnamiðill Ljósmyndir Sjálfhýsta Nextcloud-kerfið er opið og frjálst, og heldur þér við stjórnvölinn.\n\nEiginleikar:\n* Auðvelt, nútímalegt viðmót, sem hentar þema netþjónsins þíns\n* Sendu skrár inn á Nextcloud-þjóninn þinn\n* Deildu þeim með öðrum\n* Haltu eftirlætisskránum þínum og möppum samstilltum\n* Leitaðu í öllum möppum á netþjóninum þínum\n* Sjálfvirk innsending á myndum og myndskeiðum sem þú tekur á snjalltækinu þínu\n* Haltu öllu uppfærðu í gegnum tilkynningar\n* Styður marga aðganga fyrir hvern notanda\n* Tryggðu aðgang að gögnunum þínum með fingrafari eða PIN-númeri\n* Samþætting við DAVx⁵ (áður þekkt sem DAVdroid) fyrir auðvelda uppssetningu á samstilltu dagatali og tengiliðum\n\nTilkynntu öll vandamál á https://github.com/nextcloud/android/issues og ræddu um þennan hugbúnað á https://help.nextcloud.com/c/clients/android\n\nEr Nextcloud nýtt fyrir þér? Nextcloud er þinn eiginn netþjónn til að samstilla skrár og deila í samstarfs og samskiptaumhverfi. Þetta er frjáls hugbúnaður sem þú getur hýst sjálf/ur eða borgað þjónustuaðila fyrir að gera fyrir þig. Með þessu ert það þú sem ert við stjórnvölinn með gögnin sem þú vilt hafa aðgengileg í gegnum netið, hvort sem það eru ljósmyndir, dagatal, tengiliðir, skjölin þín, og margt fleira.\n\nSkoðaðu Nextcloud á https://nextcloud.com @@ -1063,7 +1047,6 @@ Skrá fannst ekki. Ertu viss um að þessi skrá sé til staðar eða er eldri árekstur ekki leystur? Ekki var hægt að finna skrána á netþjóninum. Annar notandi gæti hafa eytt skránni Heiti möppu - Reyna aftur að senda inn skrár á tæki sem mistókust Veldu innsendingarmöppu Gat ekki sent inn %1$s Innsending mistókst, skráðu þig inn aftur diff --git a/app/src/main/res/values-it/strings.xml b/app/src/main/res/values-it/strings.xml index 892eff189f1e..5e4596adb5c3 100644 --- a/app/src/main/res/values-it/strings.xml +++ b/app/src/main/res/values-it/strings.xml @@ -43,8 +43,6 @@ Mostra un widget dal cruscotto Cerca in %s Appari non in linea - Aggiungi nuova attività - Aggiungi del testo Sei sicuro di voler rimuovere questa attività? Elimina attività Un errore è intercorso durante la creazione del task @@ -54,7 +52,6 @@ Impossibile recuperare la lista dei Task, verifica la tua connessione a internet. Cancella task Il risultato del task non è ancora pronto. - Impossibile recuperare i tipi di task, per favore verifica la tua connessione a internet. Assistente Input Output @@ -114,6 +111,7 @@ Occupato Calendario Calendari + Cancel Si è verificato un problema durante il caricamento del certificato. Novità versione di sviluppo Controlla più tardi o ricarica @@ -198,7 +196,6 @@ Nessuna conversazione trovata Conversazioni Copiato - Copiato negli appunti Si è verificato un errore durante il tentativo di copiare il file o la cartella Impossibile copiare una cartella in una delle sue cartelle sottostanti Il file è già presente nella cartella di destinazione @@ -392,10 +389,8 @@ Caricamento in corso… Nessuna applicazione configurata per gestire questo tipo di file. secondi fa - Permessi richiesti Autorizzazioni di archiviazione %1$s funziona meglio con l\'autorizzazione di accedere all\'archiviazione. Puoi scegliere l\'accesso completo a tutti i file o quello in sola lettura a foto e video. - %1$s richiede l\'autorizzazione di gestione file per inviare i file. Puoi scegliere l\'accesso completo a tutti i file o quello in sola lettura a foto e video. Permetti l\'accesso da altre app Controllo della destinazione… Pulizia in corso… @@ -431,7 +426,6 @@ Rinomina Caricamento fallito. Nessuna connessione ad internet Errore durante il ripristino della versione del file! - Versione del file ripristinata correttamente. Dettagli Scarica Esporta @@ -466,7 +460,6 @@ Locale: %1$s Sposta tutto Remoto %1$s - Tutti i file sono stati spostati Inoltra 4 ore Google ha limitato il download di file APK/AAB! @@ -520,7 +513,6 @@ Bloccato dall\'applicazione %1$s Registri applicazione %1$s Android Non è stata trovata alcuna applicazione per inviare i log. Installa un client di posta elettronica. - Connesso come %1$s Accedi Il collegamento alla tua interfaccia web di %1$s quando la apri nel browser. Elimina log @@ -609,7 +601,6 @@ Il server ha raggiunto la fine della sua vita, aggiornalo! Menu Altro Digita il tuo codice segreto - Il codice segreto sarà richiesto ogni volta che l\'applicazione è avviata Digita il tuo codice segreto I codici segreti non corrispondono Digita nuovamente il codice segreto @@ -617,11 +608,10 @@ Codice segreto eliminato Codice segreto memorizzato Codice segreto non corretto + Pausa Impossibile aprire il PDF protetto da password. Usa un visualizzatore PDF esterno. - Tocca una pagina per ingrandire Consenti Nega - Permessi aggiuntivi richiesti per caricare e scaricare i file. Seleziona il contatto con cui condividere Nessuna applicazione trovata per impostare un\'immagine Apri %1$s @@ -725,7 +715,6 @@ Rimozione notifica non riuscita. Rimuovi Eliminato - Rimuovi Digita un nuovo nome La copia locale non può essere rinominata, prova un nome diverso Rinomina non consentita, nome già utilizzato @@ -809,7 +798,6 @@ Condividi collegamento Invia collegamento Rimuovi - Condividi con… Avatar da un utente condiviso condivisione condiviso @@ -861,7 +849,6 @@ Archiviazione interna Video Musica - Accesso completo Multimediali in sola lettura Immagini La piattaforma di produttività auto-gestita che ti lascia al comando.\nQuesta è la versione di sviluppo ufficiale e include funzionalità nuove, non testate che potrebbero provocare instabilità e perdite di dati. Questa applicazione è pensata per gli utenti che desiderano provare le nuove funzionalità e segnalare bug, se si verificano. Non utilizzarla in ambienti di produzione!\n\nSia la versione di sviluppo che quella normale sono disponibili su F-droid, e possono essere installate contemporaneamente. @@ -997,7 +984,6 @@ File non trovato. Sei sicuro che questo file esista o che un conflitto precedente non sia stato risolto? Non siamo riusciti a individuare il file sul server. Un altro utente potrebbe aver eliminato il file Nome della cartella - Riprova a caricare i file locali non riusciti Scegli la cartella di caricamento Impossibile caricare %1$s Caricamento non riuscito, effettua nuovamente l\'accesso diff --git a/app/src/main/res/values-iw/strings.xml b/app/src/main/res/values-iw/strings.xml index 9344ffcc45bf..8f069beed5a1 100644 --- a/app/src/main/res/values-iw/strings.xml +++ b/app/src/main/res/values-iw/strings.xml @@ -86,6 +86,7 @@ עסוק לוח שנה לוחות שנה + ביטול קיימת בעיה בטעינת האישור. יומן שינויים של גרסת פיתוח בדוק שוב מאוחר יותר או טען שנית @@ -158,7 +159,6 @@ לא נמצא קובץ לא ניתן למצוא את הגיבוי האחרון שלך! דיונים - הועתק ללוח הגזירים אירעה שגיאה בזמן ניסיון להעתיק את הקובץ או התיקייה אי אפשר להעתיק תיקייה לתוך אחת התיקיות שתחתיה הקובץ כבר קיים בתיקיית היעד @@ -295,7 +295,6 @@ בטעינה… לא הוגדר יישומון לטיפול בסוג קובץ שכזה. לפני מספר שניות - נדרשות הרשאות הרשאות אחסון בודק יעד… מתבצע ניקיון… @@ -321,7 +320,6 @@ לא ניתן לסנכרן את הקובץ. הגרסה הזמינה העדכניות ביותר שלו מוצגת. שינוי שם שחזור גרסת הקובץ נתקלה בשגיאה! - גרסת הקובץ שוחזרה בהצלחה. פרטים הורדה ייצוא @@ -351,7 +349,6 @@ מקומי: %1$s להעביר הכול מרוחק: %1$s - כל הקבצים הועברו העברה 4 שעות שם @@ -439,7 +436,6 @@ השרת הגיע לתום חייו, נא לשדרג! תפריט עוד יש להכניס את הקוד שלך - בכל פעם שיישום זה נפתח יהיה צורך להכניס את הקוד נא להקליד את מילת הצופן שלך הקודים אינם זהים יש להכניס את הקוד שנית @@ -447,9 +443,9 @@ מילת צופן נמחקה הקוד נשמר קוד שגוי + השהה לאפשר לדחות - נדרשות הרשאות נוספות כדי להעלות ולהוריד קבצים לא נמצא יישומון להגדיר אתו תמונה השבתת בדיקת חיסכון בחשמל גורמת להעלאת קבצים כשהסוללה חלשה! נמחק @@ -515,7 +511,6 @@ הסרת ההתראה נכשלה. הסרה נמחק - הסרה נא להזין שם חדש לא ניתן לשנות שם של עותק מקומי, נא לנסות שם אחר אי אפשר לשנות שם, השם כבר תפוס @@ -573,7 +568,6 @@ קישור לשיתוף שליחת קישור ביטול הגדרה - שיתף עם… תמונה ייצוגית מהמשתמש השיתופי שיתוף משותף diff --git a/app/src/main/res/values-ja-rJP/strings.xml b/app/src/main/res/values-ja-rJP/strings.xml index 61f0b27eff77..3eee232b0dae 100644 --- a/app/src/main/res/values-ja-rJP/strings.xml +++ b/app/src/main/res/values-ja-rJP/strings.xml @@ -45,23 +45,17 @@ %s の中を検索 オフライン ここに表示されている出力はAIによって生成されます。必ず二重チェックを行ってください。 - 新しいタスクを追加 - 右下から新しいタスクを作成する - テキストを入力 本当にこのタスクを削除しますか? タスクを削除 メッセージを送って会話を始めてみましょう。 こんにちは!何かお手伝いできることはありますか? - タスクリストを読み込み中... タスクの作成中にエラーが発生しました。 タスクは正常に作成されました。 タスクの削除中にエラーが発生しました。 タスクは正常に削除されました。 - タスクリストが空です タスクリストを取得できません。インターネット接続を確認してください。 タスクを削除 タスクの出力はまだ準備ができていません。 - タスクタイプを取得できません。インターネット接続を確認してください。 アシスタント 入力 出力 @@ -129,6 +123,7 @@ ビジー カレンダー カレンダー + キャンセル 証明書の読み込みに問題がありました。 開発バージョンの変更履歴 後で確認するか、再読込をしてください @@ -217,7 +212,6 @@ まだ会話はありません 会話 コピー - クリップボードにコピーされました このファイルまたはフォルダーをコピーする際にエラーが発生しました フォルダをその下のフォルダにコピーすることはできません そのファイルは移動先フォルダーにすでに存在します。 @@ -428,10 +422,8 @@ 読み込み中… このファイル形式に設定されたアプリがありません。 数秒前 - 必要な権限 ストレージの権限 %1$sは、ストレージへのアクセスが許可されることでより良く動作します。全てのファイルへのフルアクセスまたは写真や動画への読み取り専用を選ぶことができます。 - %1$sは、ファイルをアップロードするためいファイル管理の権限を必要としています。全てのファイルへのフルアクセスまたは写真や動画への読み取り専用を選ぶことができます。 他のアプリからのアクセスを許可する 移動先の確認中… クリーニング中… @@ -469,7 +461,6 @@ アップロードに失敗しました。インターネット接続がありません %sはすでに存在します。強豪は検出されませんでした。 ファイルバージョンの復元中にエラーが発生しました。 - ファイルバージョンが正常に復元されました。 詳細 ダウンロード エクスポート @@ -508,7 +499,6 @@ ローカル: %1$s すべて移動 リモート: %1$s - 全ファイル移動済 転送 4時間 GoogleがAPK/AABファイルのダウンロードを制限! @@ -563,7 +553,6 @@ %1$sアプリによりロック %1$s アンドロイドアプリログ ログを送信するためのアプリが見つかりません。メールクライアントをインストールしてください。 - %1$sとしてログインしました ログイン %1$sをWeb画面でブラウザーで開くときのURL ログを消去 @@ -665,7 +654,6 @@ サーバーのEOLが終わったので、アップグレードしてください! その他のメニュー パスコードを入力 - アプリ開始時には毎回パスコードが要求されます パスコードを入力してください パスコードが一致しません パスコードを再入力してください @@ -673,11 +661,10 @@ パスコードを削除しました パスコードを保存しました パスコードが正しくありません + 一時停止 パスワード保護されたPDFファイルを開くことは出来ません。外部ビューワを使ってください - ズームするにはページをタップ 許可 拒否 - ファイルをダウンロードとアップロードする追加の権限が必要です。 共有するユーザーを選択 画像を設定するアプリが見つかりませんでした ホームスクリーンにピン留めする @@ -784,7 +771,6 @@ 通知の削除に失敗 削除 削除済み - 削除 新しい名前を入力 ローカルコピーの名前が変更できません。別の名前を試してください 名前の変更ができません。その名前は使われています @@ -880,7 +866,6 @@ URLで共有 リンクを送信 設定を解除 - …と共有 共有ユーザーからのアバター 共有 共有中 @@ -933,7 +918,6 @@ 内部ストレージ 動画 音楽 - フルアクセス メディア読み取り専用 写真 あなたの作業を強力に管理する、自己ホスト型の生産性向上プラットフォーム。\nこれは公式の開発バージョンです。まだ十分なテストをしていない新しいサンプル機能を毎日提供しており、不安定な挙動やデータの消失を招く可能性があります。 このアプリはテストユーザーのためのもので、不具合が発生した場合にレポートを必要とします。 実業務では使用しないでください!\n\n公式開発の正規バージョンはF-droidからもインストールできます。 @@ -1077,7 +1061,6 @@ ファイルが見つかりません。このファイルが存在することを確認するか、以前の競合が解決されていない可能性はありますか? サーバ上でファイルを見つけられませんでした。別のユーザがファイルを削除した可能性があります フォルダー名 - 失敗したローカル ファイルのアップロードを再試行します アップロードフォルダーを選択 %1$sをアップロードできませんでした アップロード失敗、要 再ログイン diff --git a/app/src/main/res/values-ka/strings.xml b/app/src/main/res/values-ka/strings.xml index 7c0228365750..4fc80eafd51c 100644 --- a/app/src/main/res/values-ka/strings.xml +++ b/app/src/main/res/values-ka/strings.xml @@ -83,6 +83,7 @@ Busy Calendar Calendars + Cancel There is a problem loading the certificate. Changelog dev version Check back later or reload. @@ -164,7 +165,6 @@ No conversations found Conversations Copied - Copied to clipboard An error occurred while trying to copy this file or folder It is not possible to copy a folder into one of its own underlying folders The file is already present in the destination folder @@ -334,10 +334,8 @@ Loading… No app set up to handle this file type. seconds ago - Permissions needed Storage permissions %1$s works best with permissions to access storage. You can choose full access to all files, or read-only access to photos and videos. - %1$s needs file management permissions to upload files. You can choose full access to all files, or read-only access to photos and videos. Checking destination… Cleaning… Updating data storage folder @@ -363,7 +361,6 @@ File could not be synced. Showing latest available version. Rename Error restoring file version! - Successfully restored file version. Details Download Export @@ -393,7 +390,6 @@ Local: %1$s Move all Remote: %1$s - All files were moved Forward 4 hours Name will result in a hidden file @@ -441,7 +437,6 @@ Locked by %1$s app %1$s Android app logs No app for sending logs found. Please install an email client. - Logged in as %1$s Log in The link to your %1$s web interface when you open it in the browser. Delete logs @@ -522,7 +517,6 @@ The server has reached end of life, please upgrade! More menu Enter your passcode - The passcode will be requested every time the app is started Please enter your passcode The passcodes are not the same Please reenter your passcode @@ -531,10 +525,8 @@ Passcode stored Incorrect passcode Unable to open password-protected PDF. Please use an external PDF viewer. - Tap on a page to zoom in Allow Deny - Additional permissions required to upload and download files. No app found to set a picture with Open %1$s stop @@ -619,7 +611,6 @@ Failed to remove notification. Remove Deleted - Remove Enter a new name Could not rename local copy, try a different name Renaming not possible, name already taken @@ -693,7 +684,6 @@ Share link Send link Unset - Share with… Avatar from shared user share shared @@ -742,7 +732,6 @@ Internal storage Movies Music - Full access Media read-only Pictures The self-hosted productivity platform that keeps you in control.\nThis is the official development version, featuring a daily sample of any new untested functionality, which may cause instability and data loss. The app is for users willing to test, and report bugs should they occur. Do not use it for your productive work!\n\nBoth the official dev and regular version are available on F-droid, and can be installed at the same time. diff --git a/app/src/main/res/values-ko/strings.xml b/app/src/main/res/values-ko/strings.xml index c2ec9dbce6bf..cae35b760225 100644 --- a/app/src/main/res/values-ko/strings.xml +++ b/app/src/main/res/values-ko/strings.xml @@ -45,22 +45,17 @@ %s에서 검색 접속 안함으로 표시 이 출력은 AI에 의해 생성되었습니다. 반드시 다시 확인하세요. - 새 작업 추가 - 텍스트 입력 이 작업을 삭제하시겠습니까? 결과 삭제 대화를 시작하기 위해 메시지를 보내보세요. 안녕하세요! 오늘은 무엇을 도와드릴까요? - 작업 목록 불러오는 중... 작업을 생성하는 중에 오류가 발생했습니다. 작업이 성공적으로 생성됨 작업을 삭제하는 중에 오류가 발생했습니다. 작업이 성공적으로 삭제됨 - 작업 목록이 비어있습니다. 작업 목록을 가져올 수 없습니다. 인터넷 연결을 확인하세요. 작업 삭제 작업을 출력할 준비가 되지 않았습니다. - 작업 유형을 가져올 수 없습니다. 인터넷 연결을 확인하세요. 어시스턴트 입력 출력 @@ -120,6 +115,7 @@ 바쁨 일정 일정 + 취소 인증서를 불러올 수 없습니다. 개발 버전 변경점 잠시 후 다시 확인하거나 새로고침 하십시오. @@ -205,7 +201,6 @@ 대화를 찾을 수 없습니다. 아직 대화가 존재하지 않음 대화 - 클립보드로 복사됨 이 파일이나 폴더를 복사할 수 없음 폴더를 자기 자신의 하위 폴더로 복사할 수 없음 파일이 대상 폴더에 이미 존재함 @@ -399,10 +394,8 @@ 불러오는 중… 이 파일을 위한 앱이 존재하지 않습니다. 초 전 - 권한 필요함 저장소 권한 %1$s은(는) 저장소에 접근할 권한이 있어야 원활하게 동작합니다. 모든 파일에 대한 완전한 접근 혹은 사진과 동영상에 대한 읽기 전용 접근 중 하나를 선택할 수 있습니다. - %1$s은(는) 파일 권한이 있어야 원활하게 작동합니다. 모든 파일에 대한 완전한 접근 혹은 사진과 동영상에 대한 읽기 전용 접근 중 하나를 선택할 수 있습니다. 다른 앱에서의 접근 허용 대상 점검 중… 정리 중… @@ -438,7 +431,6 @@ 이름 바꾸기 업로드 실패. 인터넷에 연결되지 않았습니다 파일 버전을 되돌리는데 오류가 발생했습니다. - 성공적으로 파일 버전을 되돌렸습니다. 세부사항 다운로드 내보내기 @@ -472,7 +464,6 @@ 로컬: %1$s 모두 이동 원격: %1$s - 모든 파일이 이동됨 앞으로 4 시간 Google이 APK/AAB 파일 다운로드를 제한했습니다! @@ -526,7 +517,6 @@ %1$s앱에 의해 잠김 %1$s Android 앱 로그 로그 전송용 앱이 없습니다. 이메일 클라이언트를 설치하십시오. - %1$s(으)로 로그인됨 로그인 %1$s 웹 인터페이스를 브라우저에서 열면 링크됩니다. 로그 삭제 @@ -616,7 +606,6 @@ 서버의 수명이 다된것 같네요, 업그레이드 해주세요! 메뉴 더 보기 암호를 입력하십시오 - 앱을 시작할 때마다 암호를 물어봅니다 암호를 입력하십시오 암호가 일치하지 않습니다 암호를 다시 입력하십시오 @@ -624,11 +613,10 @@ 암호 삭제됨 암호 저장됨 암호가 잘못됨 + 일시 정지 암호로 보호된 PDF를 열 수 없습니다. 외부 PDF 뷰어를 사용하세요. - 페이지를 탭하여 확대 허용 거부 - 파일을 업로드 및 다운로드하려면 추가 권한이 필요합니다. 공유할 연락처를 선택 사진을 설정할 앱을 찾을 수 없음 %1$s 열기 @@ -732,7 +720,6 @@ 알림을 지우는데 실패했습니다. 삭제 삭제함 - 삭제 새 이름 입력 로컬 파일의 이름을 변경할 수 없습니다. 다른 이름을 입력하십시오 이름을 변경할 수 없음. 이름이 이미 사용중입니다. @@ -815,7 +802,6 @@ 링크 공유 링크 보내기 설정 해제 - 다음과 공유 공유 사용자의 아바타 공유 공유됨 @@ -868,7 +854,6 @@ 내부 저장소 영화 음악 - 완전한 접근 읽기 전용 미디어 접근 그림 컨트롤 가능한 자체 호스팅 생산성 플랫폼.\n이는 공식 개발 버전으로, 테스트되지 않은 새로운 기능을 매일 샘플로 제공하므로 불안정과 데이터 손실이 발생할 수 있습니다. 이 애플리케이션은 기꺼이 테스트하고 버그가 발생하면 보고하는 사용자를 대상으로 합니다. 생산적인 작업에는 사용하지 마십시오!\n\n공식 개발 버전 및 일반 버전은 모두 F-droid에서 사용할 수 있으며, 동시에 설치할 수 있습니다. @@ -1005,7 +990,6 @@ 파일을 찾을 수 없음. 이 파일의 존재 및 파일 충돌 여부를 다시 확인하십시오. 파일을 서버에서 찾을 수 없습니다. 다른 사용자가 파일을 삭제했을 수도 있습니다 폴더 이름 - 실패한 파일 업로드 다시 시도 업로드 폴더 선택 %1$s을(를) 업로드할 수 없음 업로드 실패, 다시 로그인하십시오 diff --git a/app/src/main/res/values-lo/strings.xml b/app/src/main/res/values-lo/strings.xml index 5c9cdf130489..94bcbd617580 100644 --- a/app/src/main/res/values-lo/strings.xml +++ b/app/src/main/res/values-lo/strings.xml @@ -45,24 +45,18 @@ ຄົ້ນຫາໃນ%s Appear offline ຜົນລັບທີ່ສະແດງຢູ່ນີ້ຖືກສ້າງຂຶ້ນໂດຍ AI. ກະລຸນາກວດສອບຄືນທຸກຄັ້ງໃຫ້ແນ່ໃຈ. - Add new task - Create a new task from bottom right - Type some text Are you sure you want to delete this task? Delete task ລອງສົ່ງຂໍ້ຄວາມເພື່ອເລີ່ມການສົນທະນາ. ສະບາຍດີ! ມີຫຍັງໃຫ້ຂ້ອຍຊ່ວຍມື້ນີ້ບໍ່? - Loading task list… An error occurred while creating the task Task successfully created An error occurred while deleting the task Task successfully deleted - Task list is empty. Task list is empty. Check assistant app configuration. Unable to fetch task list, please check your internet connection. Delete Task The task output is not ready yet. - Unable to fetch task types, please check your internet connection. Assistant Input Output @@ -130,6 +124,7 @@ Busy ປະຕິທິນ Calendars + ຍົກເລີກ ມີບັນຫາໃນການໂຫຼດການຢັ້ງຢືນ ເວີຊັ້ນຂອງ Changelog Check back later or reload. @@ -219,7 +214,6 @@ ຍັງບໍ່ມີການສົນທະນາ ການສົນທະນາ Copied - ສໍາເນົາຄລິບ ມີຂໍ້ຜິດພາດເກີດຂຶ້ນໃນຂະນະທີ່ພະຍາຍາມສໍາເນົາຟາຍຫຼືໂຟນເດີນີ້ ມັນເປັນໄປບໍ່ໄດ້ທີ່ຈະສໍາເນົາໂຟນເດີ ເປັນຫນຶ່ງໃນໂຟນເດີ ພື້ນຖານ ຟາຍມີຢູ່ແລ້ວໃນໂຟນເດີຈຸດຫມາຍປາຍທາງ @@ -432,10 +426,8 @@ ກຳລັງໂຫຼດ ບໍ່ມີແອັບພລິເຄຊັນທີ່ຕັ້ງໄວ້ເພື່ອຈັດການກັບຟາຍປະເພດນີ້. ວິນາທີຜ່ານມາ - Permissions needed Storage permissions %1$s works best with permissions to access storage. You can choose full access to all files, or read-only access to photos and videos. - %1$s needs file management permissions to upload files. You can choose full access to all files, or read-only access to photos and videos. Allow access from other apps ການກວດກາຈຸດຫມາຍປາຍທາງ... ກຳລັງລ້າງ @@ -473,7 +465,6 @@ Upload failed. No internet connection %s already exists, no conflict detected ຂໍ້ຜິດພາດໃນການກູ້ຄືນເວີຊັ້ນຟາຍ! - ຟາຍທີ່ ໄດ້ ຮັບການກຸ້ຄືນສໍາເລັດ . ລາຍລະອຽດ ດາວໂຫຼດ Export @@ -513,7 +504,6 @@ ຊ່ອງເກັບ%1$s ຢ້າຍທັງໝົດ ໄລຍະໄກ:%1$s - ຟາຍທັງໝົດຖືກຍ້າຍ ໄປຂ້າງຫນ້າ 4 ຊົ່ວໂມງ Google restricted downloading APK/AAB files! @@ -568,7 +558,6 @@ Locked by %1$s app ບັນທຶກແອັບພີເຄເຊິນ%1$s No app for sending logs found. Please install an email client. - Logged in as %1$s ເຂົ້າລະບົບ ການເຊື່ອມຕໍ່ເວັບໄຊຂອງທ່ານ %1$sເມື່ອທ່ານເປີດມັນໃນເວັບໄຊ ລຶບ @@ -670,7 +659,6 @@ ການເຂົ້າຟາຍເຊີເວີສິ້ນສຸດ, ກະລຸນາຍົກລະດັບ! ເມນູເພີ່ມເຕີມ ປ້ອນລະຫັດຂອງທ່ານ - ລະຫັດຜ່ານຈະຖືກຮ້ອງຂໍເມື່ອແອັບພລິເຄຊັນເລີ່ມຕົ້ນ ກະລຸນາປ້ອນລະຫັດຂອງທ່ານ The passcode will be requested every time the app is opened or reopened after 5 seconds. ລະຫັດຜ່ານບໍ່ຄືກັນ @@ -679,11 +667,10 @@ ລຶບລະຫັດຜ່ານແລ້ວ ລະຫັດຜ່ານທີ່ເກັບໄວ້ ລະຫັດຜ່ານບໍ່ຖືກຕ້ອງ + Pause Unable to open password-protected PDF. Please use an external PDF viewer. - Tap on a page to zoom in ອະນຸຍາດ ປະຕິເສດ - ການອະນຸຍາດເພີ່ມເຕີມທີ່ຈໍາເປັນເພື່ອອັບໂຫຼດ ແລະ ດາວໂຫລດຟາຍ Pick contact to share with ບໍ່ພົບແອັບພລິເຄຊັນເພື່ອຕັ້ງຮູບດ້ວຍ Pin to home screen @@ -790,7 +777,6 @@ ບໍ່ສາມາດລຶບການແຈ້ງການແຈ້ງເຕືອນໄດ້. ຍ້າຍອອກ ລືບ - ລຶບອອກ ໃສ່ຊື່ໃໝ່ ບໍ່ສາມາດປ່ຽນຊື່ສໍາເນົາໃນຊ່ອງເກັບຂໍ້ມູນໄດ້, ລອງໃຊ້ຊື່ອື່ນ ປ່ຽນຊື່ບໍ່ໄດ້ ມີຊື່ແລ້ວ @@ -886,7 +872,6 @@ ແບ່ງປັນລິງ ສົ່ງລິງ ຍົກເລີກການຕັ້ງຄ່າ - ແບ່ງປັນດ້ວຍ Avatar ຈາກຜູ້ໃຊ້ ແບ່ງປັນ ແບ່ງປັນ ໄດ້ແບ່ງປັນ @@ -939,7 +924,6 @@ ການເກັບກໍາຂໍ້ມູນພາຍໃນ ລະຄອນໂທລະທັດ ເພງ - Full access Media read-only ຮູບພາບ The self-hosted productivity platform that keeps you in control.\n\nFeatures:\n* Easy, modern interface, suited to the theme of your server\n* Upload files to your Nextcloud server\n* Share them with others\n* Keep your favorite files and folders synced\n* Search across all folders on your server\n* Auto Upload for photos and videos taken by your device\n* Keep up to date with notifications\n* Multi-account support\n* Secure access to your data with fingerprint or PIN\n* Integration with DAVx⁵ (formerly known as DAVdroid) for easy setup of calendar and contacts synchronization\n\nPlease report all issues at https://github.com/nextcloud/android/issues and discuss this app at https://help.nextcloud.com/c/clients/android\n\nNew to Nextcloud? Nextcloud is a private file sync and share and communication server. It is libre software, and you can host it yourself or pay a company to do it for you. That way, you are in control of your photos, your calendar and contact data, your documents and everything else.\n\nCheck out Nextcloud at https://nextcloud.com @@ -1085,7 +1069,6 @@ File not found. Are you sure that this file exists or has a previous conflict not been resolved? We couldnt locate the file on server. Another user may have deleted the file ຊື່ໂຟນເດີ - Retry to upload failed local files ເລືອກໂຟນເດີອັບໂຫລດ ບໍ່ສາມາດອັບໂຫຼດໄດ້%1$s ອັບໂຫຼດບໍ່ສຳເລັດ, ເຂົ້າສູ່ລະບົບອີກຄັ້ງ diff --git a/app/src/main/res/values-lt-rLT/strings.xml b/app/src/main/res/values-lt-rLT/strings.xml index 719788185464..e4722bca4458 100644 --- a/app/src/main/res/values-lt-rLT/strings.xml +++ b/app/src/main/res/values-lt-rLT/strings.xml @@ -36,20 +36,15 @@ Rodo vieną valdiklį iš skydelio Ieškoti %s Atrodyti atsijungusiu - Pridėti naują užduotį - Įrašykite kokį nors tekstą Ar tikrai norite ištrinti šią užduotį? Ištrinti užduotį - Įkeliamas užduočių sąrašas… Kuriant užduotį, įvyko klaida Užduotis sėkmingai sukurta Ištrinant užduotį, įvyko klaida Užduotis sėkmingai ištrinta - Užduočių sąrašas tuščias. Nepavyko gauti užduočių sąrašo, patikrinkite savo interneto ryšį. Ištrinti užduotį Išvestis dar neparuošta. - Negalima gauti užduočių tipų. Patikrinkite interneto ryšį. Asistentas. Įvestis Išvestis @@ -107,6 +102,7 @@ Užimtas laikas Kalendorius Kalendoriai + Atsisakyti Klaida, įkeliant liudijimą. Dev versijos pakeitimų žurnalas Patikrinkite vėliau arba įkelkite iš naujo. @@ -185,7 +181,6 @@ Nepavyko rasti jūsų paskutinės atsarginės kopijos! Pokalbiai Nukopijuota - Nukopijuota į iškarpinę Klaida kopijuojant failą ar aplanką Neįmanoma nukopijuoti aplanko į poaplankį Failas aplanke jau egzistuoja @@ -348,7 +343,6 @@ Įkeliama… Nėra šios programos failo tipui tvarkyti. prieš keletą sekundžių - Neturite teisių Saugyklos leidimai %1$s geriausiai veikia, kai yra suteikti leidimai prieigai prie saugyklos. Jūs galite pasirinkti pilną prieigą prie visų failų arba tik skaitymo prieigą prie nuotraukų ir vaizdo įrašų. Tikrinama paskirties vieta… @@ -383,7 +377,6 @@   Pervadinti Klaida atkuriant failo versiją! - Failo versija sėkmingai atkurta. Išsamiau Atsisiųsti Eksportuoti @@ -414,7 +407,6 @@ Vietinis: %1$s Perkelti visus Nuotolinis: %1$s - Visi failai buvo perkelti Persiųsti 4 valandos „Google“ apribojo APK/AAB failų atsisiuntimą! @@ -456,7 +448,6 @@ Užrakino %1$s programėlė %1$s Android žurnalai Nerasta jokios programėlės, skirtos siųsti žurnalus. Įsidiekite el. pašto kliento programėlę. - Prisijungta kaip %1$s Prisijungti Nuoroda į jūsų %1$s saityno sąsają, kuomet atveriate ją naršyklėje. Ištrinti žurnalus @@ -534,7 +525,6 @@ Serverio naudojimo laikas baigėsi, prašome atnaujinkite! Daugiau meniu Įveskite užraktą - Užrakto kodas bus reikalaujamas kiekvieną kartą paleidžiant programėlę Prašome įvesti slaptažodį Nesutampa užraktas Įveskite užraktą @@ -542,9 +532,9 @@ Leidimo kodas ištrintas Užraktas išsaugotas Neteisingas užraktas + Pristabdyti Leisti Drausti - Papildomos teisės reikalingos įkelti šiuos atsisiųstus failus. Nerasta programa, su kuria būtų galima nustatyti nuotrauką Atverti %1$s stabdyti @@ -630,7 +620,6 @@ Nepavyko pašalinti pranešimo. Šalinti Ištrinta - Šalinti Įveskite naują pavadinimą Nepavyko pervadinti vietinės kopijos, pabandykite kitą pavadinimą Pervadinimas neįmanomas, pavadinimas jau užimtas @@ -700,7 +689,6 @@ Viešinio nuoroda Siųsti nuorodą Nenustatyta - Bendrinti su… Bendrinamo naudotojo avataras bendrinti bendrinama @@ -749,7 +737,6 @@ Vidinė saugykla Filmai Muzika - Pilna prieiga Medija tik skaitymui Paveikslėliai Savarankiška platforma.\nTai yra oficiali vystoma versija, turinti neišbandytų funkcijų, kurios gali sukelti nestabilumą ar duomenų praradimą. Programa skirta naudotojams, norintiems išbandyti naujausią versiją ir pranešti apie aptiktas klaidas ar neatitiktis. Nenaudokite jo produktyviam darbui!\n\n Tiek oficialią „dev“ versiją, tiek įprastinę versija „F-droid“ galima įdiegti tuo pačiu metu. diff --git a/app/src/main/res/values-lv/strings.xml b/app/src/main/res/values-lv/strings.xml index 63decdc4eb7a..6a787cba8495 100644 --- a/app/src/main/res/values-lv/strings.xml +++ b/app/src/main/res/values-lv/strings.xml @@ -30,7 +30,6 @@ Pievienot %1$s Starpniekservera ports Meklēt %s - Pievienot jaunu uzdevumu Sveiciens! Ar ko šodien varu palīdzēt? Nevar iegūt uzdevumu sarakstu, lūgums pārbaudīt savienojumu ar internetu. Izdzēst uzdevumu @@ -86,6 +85,7 @@ Aizņemts Kalendārs Kalendāri + Atcelt Radusies problēma, ielādējot sertifikātu. Izvēlēties vietēju mapi… Izvēlēties attālu mapi… @@ -146,7 +146,6 @@ Datne nav atrasta Nevarēja atrast pēdējo dublējumu! Izdzēst sarunu - Nokopēts starpliktuvē Radās kļūda, mēģinot kopēt šo datni vai mapi Nav iespējams kopēt mapi tās apakšmapē Datne jau pastāv mērķa mapē @@ -307,7 +306,6 @@ Vietēji: %1$s Pārvietot visu Attāli: %1$s - Visas datnes tika pārvietotas Turpināt 4 stundas Vārds @@ -334,7 +332,6 @@ Datne netika atrasta vietējā datņu sistēmā Tālāku mapju vairs nav. %1$s Android lietotnes žurnāli - Pieteicies kā %1$s Pieteikties Saite uz %1$s tīmekļa saskarni, kad tā tiek atvērta pārlūkā. Atsvaidzināt @@ -386,7 +383,6 @@ Tiešsaistes stāvoklis Atvērt %1$s Ievadiet piekļuves kodu - Piekļuves kods tiks pieprasīts katrā lietotnes palaišanas reizē Lūgums ievadīt savu piekļuves kodu Šie piekļuves kodi nav vienādi Lūgums atkārtoti ievadīt savu piekļuves kodu @@ -394,11 +390,10 @@ Kods noņemts Kods saglabāts Nepareizs piekļuves kods + Pauzēt Nav iespējams atvērt ar paroli aizsargātu PDF. Lūgums izmantot ārēju PDF skatītāju. - Piesist lapai, lai pietuvinātu Atļaut Noraidīt - Nepieciešamas papildu tiesības, lai augšupielādētu un lejupielādētu datnes. Nav atrasta neviena lietotne, ar ko iestatīt attēlu Piespraust sākuma ekrānam Atvērt %1$s @@ -478,7 +473,6 @@ Dzēšana neizdevās Noņemt Izdzēsta - Noņemt Ievadīt jaunu nosaukumu Nevarēja pārdēvēt vietējo kopiju, jāmēģina cits nosaukums Pārsaukšana nav iespējama, nosaukums jau izmantots @@ -522,7 +516,6 @@ Koplietot saiti Nosūtīt saiti Neuzstādīts - Koplietot ar… koplietots Dalībnieka pievienošana neizdevās Reģistrēties ar pakalpojumu sniedzēju @@ -628,7 +621,6 @@ Nav datņu augšupielādei Datne netika atrasta. Vai tiešām tā pastāv vai arī nav novērsta iepriekšēja nesaderība? Mapes nosaukums - Atkārto vietējo datņu neizdevušās augšupielādes Izvēlēties augšupielāžu mapi Nevarēja augšupielādēt %1$s Augšupielāde neizdevās, jāpiesakās vēlreiz diff --git a/app/src/main/res/values-mk/strings.xml b/app/src/main/res/values-mk/strings.xml index 19d7c0cdbb45..d58f9eb8200b 100644 --- a/app/src/main/res/values-mk/strings.xml +++ b/app/src/main/res/values-mk/strings.xml @@ -85,6 +85,7 @@ Зафатен Календар Календари + Откажи Има проблем со вчитување на сертификатот. Changelog dev version Поле за избирање @@ -160,7 +161,6 @@ Неможам да ја пронајдам последната резервна копија! Нема пронајдено разговори Разговори - Копирано во клипборд Настана грешка при обидот за копирање на оваа датотека или папка Не е возможно да се копира папката во истата таа папка Датотеката веќе постои во папката @@ -302,7 +302,6 @@ Се вчитува… Нема апликација за прикажување на овој вид на датотека. пред секунди - Потребни се дозволи Дозвола за складирање Проверка на дестинацијата… Чистење… @@ -328,7 +327,6 @@ Датотеката неможе да се синхронизира. Прикажување на последно достапната верзија. Преименувај Грешка при враќање на верзија на датотека ! - Успешно вратена верзија на датотеката. Детали Преземање Извези @@ -358,7 +356,6 @@ Локално: %1$s Премести ги сите Одалечено: %1$s - Сите датотеки беа преместени Препрати 4 часа Име @@ -385,7 +382,6 @@ Заклучено од %1$s Заклучено од апликацијата %1$s %1$s Апликација на Андроид за логови - Најавени сте како %1$s Најава Избриши записи Освежи @@ -457,7 +453,6 @@ Серверот го достигна крајот на животот, ве молиме надградете го! Мени повеќе Венсете го вашиот код - Кодот ќе биде баран секогаш кога ќе биде покрената апликацијата Внесете код Кодовите не се исти Внесете го повторно кодот @@ -465,9 +460,9 @@ Кодот е избришан Кодот е снимен Неточен код + Пауза Дозволи Забрани - Потебни се дополнителни привилегии за прикачување и превземање на датотеки. Не е пронајдена апликација за поставување на слики Отвори %1$s стоп @@ -538,7 +533,6 @@ Неуспешно бришење на известувањата. Отстрани Избришан - Отстрани Внеси ново име Локалната копија не може да се преименува; пробајте со друго име Преименувањето не е возможно, тоа име веќе е зафатено @@ -600,7 +594,6 @@ Сподели ја врската Испрати линк Непоставено - Сподели со… Аватар од корисникот кој споделува сподели споделено diff --git a/app/src/main/res/values-nb-rNO/strings.xml b/app/src/main/res/values-nb-rNO/strings.xml index 40e0d174f3e7..8014ae5336d2 100644 --- a/app/src/main/res/values-nb-rNO/strings.xml +++ b/app/src/main/res/values-nb-rNO/strings.xml @@ -41,8 +41,6 @@ Viser en widget fra dashbordet Søk i %s Vis som frakoblet - Legg til ny oppgave - Skriv inn litt tekst Er du sikker på at du vil slette denne oppgaven? Slett oppgave Prøv å sende en melding for å starte en samtale. @@ -53,7 +51,6 @@ Oppgaven er slettet Kan ikke hente oppgavelisten, vennligst sjekk internettforbindelsen din. Slett oppgave - Kan ikke hente oppgavetyper, vennligst sjekk internettforbindelsen din. Assistent Inndata Utdata @@ -113,6 +110,7 @@ Opptatt Kalender Kalendere + Cancel Det er et problem med lasting av sertifikatet. Endringslogg utviklingsversjon Kom tilbake senere eller last på nytt. @@ -197,7 +195,6 @@ Ingen samtaler enda Samtaler Kopiert - Kopiert til utklippstavlen En feil oppsto ved kopiering av denne filen eller mappen Det er ikke mulig å kopiere en mappe inn i sin egen undermappe Filen finnes allerede i målmappen @@ -384,10 +381,8 @@ Laster… Ingen app er satt opp til å håndtere denne filtypen. for få sekunder siden - Rettigheter mangler Rettinheter for lagring %1$sfungerer best med tillatelser til lagring. Du kan velge full tilgang til alle filer, eller skrivebeskyttet tilgang til bilder og videoer. - %1$strenger filbehandlingstillatelser for å laste opp filer. Du kan velge full tilgang til alle filer, eller skrivebeskyttet tilgang til bilder og videoer. Sjekker mål… Tømmer… Oppdaterer datalagringsmappe @@ -420,7 +415,6 @@ Kunne ikke synkronisere fil. Viser sist tilgjengelige versjon. Gi nytt navn Feil ved gjennoppretting av fil versjon! - Vellykket gjenoppretting av fil versjon. Detaljer Last ned Eksporter @@ -454,7 +448,6 @@ Lokal: %1$s Flytt alle Ekstern: %1$s - Alle filene ble flyttet Fremover 4 timer Google begrenset nedlasting APK / AAB filer! @@ -507,7 +500,6 @@ Låst av %1$s app %1$s Android-app-logger Fant ingen app til å sende logger med. Vennligst installer en e-post-klient. - Logget inn som %1$s Logg inn Koblingen til %1$s nettgrensesnitt når du åpner det i nettleseren. Slett logg @@ -590,7 +582,6 @@ Server er ikke lengre supportert, ver vennlig å oppgradere! Mer meny Skriv inn passordet ditt - Passordet vil bli krevd hver gang appen startes Sett inn passordet ditt Passordene er ikke like Skriv inn passordet på nytt @@ -598,11 +589,10 @@ Passkode slettet Passord lagret Feil passord + Pause Kan ikke åpne passordbeskyttet PDF. Vennligst bruk en ekstern PDF-viser. - Ta på siden for zoom Tillatt ikke tillatt - Flere tillatelser trengs for å laste opp og ned filer. Fant ikke noe app å sette bilde med. Åpne %1$s stopp @@ -703,7 +693,6 @@ Kunne ikke fjerne meldingen. Fjern Slettet - Fjern Skriv inn et nytt navn Kunne ikke endre navn på lokal kopi, prøv et annet navn Endring av navn ikke mulig, navnet er allerde benyttet @@ -784,7 +773,6 @@ Del lenke Send lenke Ikke satt - Del med… Avatar fra delt bruker del delt @@ -836,7 +824,6 @@ Intern lagring Filmer Musikk - Full tilgang Skrivebeskyttet media Bilder Den selvstyrte produktivitetsplattformen som du har kontroll over.\nDette er den offisielle utviklingsversjonen, med et daglig utvalg av ny uprøvd funksjonalitet, som kan forårsake ustabilitet og tap av data. Appen er for brukere som er villige til å teste, og rapporterer feil hvis de skulle oppstå. Ikke bruk den til ditt produktive arbeid!\n\nBåde den offisielle utvikler versjonen og den vanlige versjonen er tilgjengelig på F-droid, og kan installeres samtidig. @@ -970,7 +957,6 @@ Finner ikke filen. Er du sikker på at denne filen eksisterer, eller er en tidligere konflikt ikke løst? Vi finner ikke filen på serveren. En annen bruker kan ha slettet filen. Mappenavn - Prøv på nytt å laste opp mislykkede lokale filer Velg opplastingsmappe Kunne ikke laste opp %1$s Opplasting mislyktes, logg inn igjen diff --git a/app/src/main/res/values-nl/strings.xml b/app/src/main/res/values-nl/strings.xml index d572a8089cf9..8f127b81f213 100644 --- a/app/src/main/res/values-nl/strings.xml +++ b/app/src/main/res/values-nl/strings.xml @@ -44,21 +44,15 @@ Toont één widget van dashboard Zoeken in %s Toon afwezig - Nieuwe taak toevoegen - Maak een nieuwe taak vanuit de rechteronderhoek - Geef wat tekst in Bent u zeker dat u deze taak wilt verwijderen? Verwijder taak - Laden takenlijst... Er is een fout opgetreden bij het aanmaken van de taak Taak succesvol aangemaakt Er is een fout opgetreden bij het verwijderen van de taak Taak succesvol verwijderd - Takenlijst is leeg. Kan takenlijst niet ophalen. Controleer je internetverbinding. Verwijder taak De taakuitvoer is nog niet klaar. - Kan taken types niet ophalen. Controleer je internetverbinding. Assistent Input Output @@ -119,6 +113,7 @@ Bezet Agenda Agenda\'s + Annuleren Er is een probleem met het laden van het certificaat. Changelog dev versie Kom later terug of laad opnieuw. @@ -205,7 +200,6 @@ Geen gesprekken gevonden Gesprekken Gekopieerd - Gekopieerd naar het klembord Er trad een fout op bij het kopiëren van dit bestand of deze map Een map kan niet naar een onderliggende map worden gekopieerd Het bestand bestaat al in de doelmap @@ -415,10 +409,8 @@ Laden… Er is geen app ingesteld om dit bestandsformaat te behandelen. seconden geleden - Machtigingen nodig Opslagmachtigingen %1$s werkt het best met opslagmachtigingen. Je kan kiezen tussen volledige toegang tot alle bestanden, of alleen lezen toegang tot foto\'s en video\'s. - %1$s heeft bestandsbeheer machtiging nodig om bestanden te uploaden. Je kan kiezen tussel volledige toegang tot alle bestanden, of alleen lezen toegang tot foto\'s en videos. Toegang door andere apps toestaan Doelmap controleren… Opruimen… @@ -455,7 +447,6 @@ Hernoemen Upload mislukt. Geen internetverbinding Fout bij herstellen bestandsversie! - Herstellen bestandsversie succesvol Details Downloaden Exporteren @@ -490,7 +481,6 @@ Lokaal: %1$s Alles verplaatsen Extern: %1$s - Alle bestanden zijn verplaatst Doorsturen 4 uur Google heeft het downloaden van APK/AAB files beperkt! @@ -545,7 +535,6 @@ Vergrendeld door %1$s app %1$s-Android-app-logs Geen applicatie gevonden voor het versturen van de logs. Installeer een email client. - Ingelogd als %1$s Inloggen De link naar je %1$s web interface wanneer je die opent in de browser. Verwijderen logs @@ -643,7 +632,6 @@ Deze server is verouderd, graag upgraden! Meer menu Toegangscode invoeren - De toegangscode wordt elke keer gevraagd bij opstarten van de app Voer je toegangscode in De codes komen niet overeen Voer nogmaals je toegangscode in @@ -651,11 +639,10 @@ Toegangscode verwijderd Toegangscode opgeslagen Onjuiste toegangscode + Pauze Niet mogelijk om wachtwoord-beschermde PDF te openen. Gebruik een externe PDF-viewer. - Tik op een pagina om in te zoomen Toestaan Weigeren - Aanvullende machtigingen vereist voor het uploaden en downloaden van bestanden. Kies contact om mee te delen Geen app gevonden om afbeelding in te stellen Vastzetten op startscherm @@ -762,7 +749,6 @@ Niet gelukt om melding af te handelen Verwijder Verwijderd - Verwijderen Voer een nieuwe naam in Kon lokale kopie niet hernoemen, probeer een andere naam Hernoemen niet mogelijk, naam is al in gebruik @@ -856,7 +842,6 @@ Deel link Verstuur link uitgeschakeld - Deel met… Avatar van een gedeelde gebruiker delen deelde @@ -909,7 +894,6 @@ Interne opslag Films Muziek - Volledige toegang Media alleen lezen Afbeeldingen Het zelf-gehoste productiviteitsplatform dat je de controle geeft.\n\nKenmerken:\n* Eenvoudige, moderne interface, afgestemd op het thema van jouw server\n* Bestanden uploaden naar je Nextcloud-server\n* Deel ze met anderen\n* Houd je favoriete bestanden en mappen gesynchroniseerd\n* Zoek in alle mappen op je server\n* Auto-upload voor foto\'s en video\'s gemaakt door je apparaat\n* Blijf op de hoogte met meldingen\n* Ondersteuning voor meerdere accounts\n* Veilige toegang tot je gegevens met vingerafdruk of PIN\n* Integratie met DAVx⁵ (voorheen bekend als DAVdroid) voor een gemakkelijke installatie van kalender- en contactensynchronisatie\n\nRapporteer alle problemen op https://github.com/nextcloud/android/issues en bespreek deze app op https://help.nextcloud.com/c/clients/android\n\nNieuw bij Nextcloud? Nextcloud is een privé server voor bestandssynchronisatie en -deling en communicatie. Het is libre software en je kunt het zelf hosten of een bedrijf betalen om het voor je te doen. Op die manier heb je de controle over je foto\'s, je agenda en contactgegevens, je documenten en alles wat erbij hoort.\n\nBekijk Nextcloud op https://nextcloud.com @@ -1050,7 +1034,6 @@ Bestand niet gevonden. Weet je zeker dat het bestand bestaat of is een eerder conflict niet opgelost? Wij konden het bestand niet vinden op de server. Een andere gebruiker kan het verwijderd hebben Mapnaam - Probeer mislukte uploads van bestanden opnieuw Kies een uploadmap Kon %1$s niet uploaden Uploaden mislukt, je moet opnieuw inloggen diff --git a/app/src/main/res/values-pl/strings.xml b/app/src/main/res/values-pl/strings.xml index e5c37b793842..d545307a0f90 100644 --- a/app/src/main/res/values-pl/strings.xml +++ b/app/src/main/res/values-pl/strings.xml @@ -45,26 +45,20 @@ Szukaj w %s Wyglądaj jako offline Ten wynik został wygenerowany przez AI. Upewnij się, że został sprawdzony i odpowiednio dostosowany. - Dodaj nowe zadanie Nie udało się wysłać wiadomości Nie udało się pobrać wiadomości czatu - Utwórz nowe zadanie w prawym dolnym rogu - Wpisz jakiś tekst Czy na pewno chcesz usunąć to zadanie? Usuń zadanie Spróbuj wysłać wiadomość, aby rozpocząć rozmowę. Cześć! W czym mogę Ci dziś pomóc? - Ładowanie listy zadań… Wystąpił błąd podczas tworzenia zadania Zadanie pomyślnie utworzone Wystąpił błąd podczas usuwania zadania Zadanie pomyślnie usunięte - Lista zadań jest pusta. Lista zadań jest pusta. Sprawdź konfigurację asystenta aplikacji. Nie można pobrać listy zadań. Sprawdź swoje połączenie internetowe. Usuń zadanie Wynik zadanie nie jest jeszcze gotowy - Nie można pobrać typów zadań. Sprawdź swoje połączenie internetowe. Asystent Wejście Wyjście @@ -133,6 +127,7 @@ Brak dostępności Kalendarz Kalendarze + Anuluj Problem podczas ładowania certyfikatu. Dziennik zmian wersji dev Sprawdź później lub załaduj ponownie. @@ -225,7 +220,6 @@ Nie udało się pobrać listy konwersacji Rozmowy Skopiowane - Skopiowano do schowka Wystąpił błąd podczas próby kopiowania tego pliku lub katalogu Nie można skopiować katalogu do jednego z jego podkatalogów Plik już istnieje w katalogu docelowym @@ -439,10 +433,8 @@ Wczytywanie… Brak aplikacji dla tego typu plików. przed chwilą - Potrzebne uprawnienia Uprawnienia do pamięci %1$s działa najlepiej z uprawnieniami dostępu do pamięci. Możesz wybrać pełny dostęp do wszystkich plików lub dostęp tylko do odczytu dla zdjęć i filmów. - %1$s potrzebuje uprawnień do zarządzania plikami, aby wysyłać pliki. Możesz wybrać pełny dostęp do wszystkich plików lub dostęp tylko do odczytu dla zdjęć i filmów. Zezwalaj na dostęp z innych aplikacji Sprawdzanie miejsca… Czyszczenie… @@ -480,7 +472,6 @@ Przesyłanie nie powiodło się. Brak połączenia internetowego %s już istnieje, nie znaleziono konfliktów Wystąpił błąd podczas przywracania wersji pliku! - Pomyślnie przywrócono wersję pliku. Szczegóły Pobierz Eksportuj @@ -520,7 +511,6 @@ Lokalnie: %1$s Przenieś wszystko Zdalnie: %1$s - Wszystkie pliki zostały przeniesione Prześlij dalej 4 godziny Google ograniczyło możliwość pobierania plików APK/AAB! @@ -575,7 +565,6 @@ Zablokowany przez aplikację %1$s %1$s logi aplikacji Android Brak aplikacji do wysyłania logów. Zainstaluj klienta poczty e-mail. - Zalogowany jako %1$s Zaloguj Link do interfejsu internetowego %1$s, aby otworzyć w przeglądarce. Usuń dziennik @@ -678,7 +667,6 @@ Serwer korzysta ze starej wersji. Dokonaj aktualizacji! Więcej Wprowadź kod PIN - Kod PIN będzie wymagany przy każdym uruchomieniu aplikacji Podaj kod PIN Kod PIN będzie wymagany przy każdym uruchomieniu aplikacji lub przy ponownym otwarciu po 5 sekundach. Podane kody PIN nie są takie same @@ -687,11 +675,10 @@ Kod PIN został usunięty Kod PIN został zapisany Kod PIN nieprawidłowy + Wstrzymaj Nie można otworzyć pliku PDF które jest chronione hasłem. Użyj zewnętrznej przeglądarki plików PDF. - Dotknij strony, aby powiększyć Akceptuj Odrzuć - Wymagane są dodatkowe uprawnienia do pobierania i wysyłania plików. Wybierz kontakt, któremu chcesz udostępnić Nie znaleziono aplikacji do ustawienia obrazu Przypnij do ekranu głównego @@ -800,7 +787,6 @@ Usunięcie powiadomienia nie powiodło się. Usuń Usunięto - Usuń Wprowadź nową nazwę Nie można zmienić nazwy lokalnej kopii, użyj innej nazwy Nie można zmienić nazwy, nazwa jest już zajęta @@ -896,7 +882,6 @@ Udostępnij link Wyślij link Nieustalone - Udostępnij z… Awatar użytkownika udostępniającego udostępnij udostępniono @@ -953,7 +938,6 @@ Potrzebne jest pozwolenie aby automatyczne przesyłanie działało Potrzebne jest pozwolenie aby przesłać pliki Nie pytaj - Pełny dostęp Multimedia tylko do odczytu Obrazy Samodzielnie hostowana platforma produktywności, która zapewnia Ci kontrolę.\n\nFunkcje:\n* Łatwy, nowoczesny interfejs, dostosowany do motywu Twojego serwera\n* Przesyłaj pliki na serwer Nextcloud\n* Udostępniaj je innym\n* Synchronizuj ulubione pliki i katalogi\n* Przeszukuj wszystkie katalogi na serwerze\n* Automatyczne przesyłanie zdjęć i filmów wykonanych Twoim urządzeniem\n* Bądź na bieżąco dzięki powiadomieniom\n* Obsługa wielu kont\n* Bezpieczny dostęp do danych za pomocą odcisku palca lub kodu PIN\n* Integracja z DAVx⁵ (dawniej znanym jako DAVdroid) w celu łatwej konfiguracji synchronizacji kalendarza i kontaktów\n\nWszystkie problemy należy zgłaszać na stronie https://github.com/nextcloud/android/issues, a dyskusje na temat tej aplikacji na stronie https://help.nextcloud.com/c/clients/android\n\nJesteś nowy w Nextcloud? Nextcloud to prywatny serwer do synchronizacji, udostępniania i komunikacji plików. To wolne oprogramowanie, możesz je hostować samodzielnie lub zapłacić firmie, aby zrobiła to za Ciebie. W ten sposób masz kontrolę nad swoimi zdjęciami, kalendarzem i danymi kontaktowymi, dokumentami i wszystkim innym.\n\nSprawdź Nextcloud na https://nextcloud.com @@ -1099,7 +1083,6 @@ Plik nie znaleziony. Czy jesteś pewien, że ten plik istnieje lub poprzedni konflikt został rozwiązany? Nie mogliśmy odnaleźć pliku na serwerze. Inny użytkownik mógł usunąć plik Nazwa katalogu - Spróbuj ponownie przesłać pliki lokalne, które nie powiodły się Wybierz katalog do wysłania Nie udało się wysłać %1$s Wysyłanie nie powiodło się, zaloguj się ponownie diff --git a/app/src/main/res/values-pt-rBR/strings.xml b/app/src/main/res/values-pt-rBR/strings.xml index 0b148f55c2cd..f0b16b0b12c0 100644 --- a/app/src/main/res/values-pt-rBR/strings.xml +++ b/app/src/main/res/values-pt-rBR/strings.xml @@ -45,26 +45,20 @@ Pesquisar em %s Aparecer off-line A saída mostrada aqui é gerada por IA. Certifique-se de sempre verificar novamente. - Adicionar nova tarefa Falha ao enviar uma mensagem Falha ao buscar mensagens de bate-papo - Criar uma nova tarefa no canto inferior direito - Digite algum texto Tem certeza de que deseja excluir esta tarefa? Excluir tarefa Tente enviar uma mensagem para iniciar uma conversa. Oi! Em que posso ajudá-lo hoje? - Carregando a lista de tarefas… Ocorreu um erro ao criar a tarefa Tarefa criada com sucesso Ocorreu um erro ao excluir a tarefa Tarefa excluída com sucesso - A lista de tarefas está vazia A lista de tarefas está vazia. Verifique a configuração do aplicativo assistente. Não foi possível buscar a lista de tarefas. Verifique sua conexão com a Internet. Excluir Tarefa O resultado da tarefa ainda não está pronto. - Não foi possível buscar os tipos de tarefas. Verifique sua conexão com a Internet. Assistente Entrada Saída @@ -133,6 +127,7 @@ Ocupado Calendário Calendários + Cancelar Existe um problema ao carregar o certificado. Changelog da versão dev Volte mais tarde ou recarregue. @@ -225,7 +220,6 @@ Falha ao buscar a lista de conversas Conversas Copiado - Copiado para a área de transferência Ocorreu um erro ao tentar copiar este arquivo ou pasta Não é possível copiar uma pasta para uma das suas próprias pastas subjacentes O arquivo já está presente na pasta destino @@ -329,6 +323,7 @@ Assistente Mais Mais Aplicativos Nextcloud + Não é possível abrir o seletor de arquivos Falha ao escolher o endereço de e-mail. Definir como criptografado Não é possível recuperar o certificado do servidor @@ -398,6 +393,7 @@ Você não tem permissão para criar ou enviar arquivos para esta pasta. Compartilhamentos externos Adicionar ou enviar + Falha ao criar caixa de diálogo de conflito Erro ao enviar o arquivo ao gerenciador de downloads Erro ao imprimir o arquivo Erro ao iniciar editor @@ -439,10 +435,8 @@ Carregando… Nenhuma aplicação definida para manipular este tipo de arquivo. segundos atrás - Permissões necessárias Permissões de armazenamento %1$s funciona melhor com permissões para acessar o armazenamento. Você pode escolher acesso total a todos os arquivos ou acesso somente leitura a fotos e vídeos. - %1$s precisa de permissões de gerenciamento de arquivos para fazer upload de arquivos. Você pode escolher acesso total a todos os arquivos ou acesso somente leitura a fotos e vídeos. Permitir acesso por outros apps Verificando destino… Limpando… @@ -480,7 +474,6 @@ O upload falhou. Sem conexão com a Internet %s já existe, nenhum conflito detectado Erro recuperando arquivo! - Arquivo recuperado com sucesso. Detalhes Baixar Exportar @@ -520,7 +513,6 @@ Local: %1$s Mover tudo Remoto: %1$s - Todos os arquivos foram movidos Adiante 4 horas Google restringiu o download de arquivos APK/AAB! @@ -575,7 +567,6 @@ Trancado pelo aplicativo %1$s %1$s logs do aplicativo Android Nenhum aplicativo para envio de registros foi encontrado. Instale um cliente de e-mail. - Logado como %1$s Entrar O link da interface da web do seu %1$s quando você o abre no navegador. Excluir logs @@ -678,7 +669,6 @@ O servidor chegou ao fim da vida. Por favor, atualize! Mais menus Digite o código de acesso - O código de acesso será solicitado toda vez que o aplicativo for iniciado Digite sua senha A senha será solicitada sempre que o aplicativo for aberto ou reaberto após 5 segundos. Os códigos de acesso não são os mesmos @@ -687,11 +677,10 @@ Frase secreta excluída Código de acesso salvo Código de acesso incorreto + Pausar Não é possível abrir o PDF protegido por senha. Use um visualizador de PDF externo. - Toque em uma página para ampliar Permitir Negar - Permissões adicionais são necessárias para enviar ou baixar arquivos. Escolher um contato para compartilhar Nenhum aplicativo encontrado para definir uma imagem Fixar na tela inicial @@ -710,7 +699,7 @@ Renomear a nova versão O que fazer se o arquivo já existir? Adicionar uma conta - Permita que o aplicativo acesse e gerencie todos os arquivos do seu dispositivo. + Permita que o aplicativo acesse e gerencie todos os arquivos do seu dispositivo Acesso a todos os arquivos Sincronizar calendário e contatos Nem o F-Droid nem o Google Play estão instalados @@ -800,7 +789,6 @@ Erro ao remover a notificação. Remover Excluído - Remover Digite um novo nome Não foi possível renomear a cópia local, tente um nome diferente Não foi possível renomear pois o nome já existe @@ -896,7 +884,6 @@ Compartilhar link Enviar link Não definido - Compartilhar com… Avatar de usuário compartilhado compartilhar compartilhado @@ -950,10 +937,9 @@ Filmes Músicas Acesso a todos os arquivos - É necessária permissão de armazenamento para o upload automático. + É necessária conceder permissão de armazenamento para o upload automático. É necessário conceder permissão de armazenamento para o envio de arquivos. Não pergunte - Acesso total Mídia somente leitura Imagens A plataforma de produtividade auto-hospedada que mantém você no controle.\n\nRecursos:\n* Interface fácil e moderna, adequada ao tema do seu servidor\n* Faça upload de arquivos para o seu servidor Nextcloud\n* Compartilhe-os com outras pessoas\n * Mantenha seus arquivos e pastas favoritos sincronizados\n* Pesquise todas as pastas do seu servidor\n* Faça upload automático de fotos e vídeos feitos pelo seu dispositivo\n* Mantenha-se atualizado com notificações\n* Suporte para várias contas\n* Acesso seguro aos seus dados com impressão digital ou PIN\n* Integração com DAVx⁵ (anteriormente conhecido como DAVdroid) para facilitar a configuração de sincronização de calendário e contatos\n\nPor favor, relate todos os problemas em https://github.com/nextcloud/android/issues e discuta este aplicativo em https://help.nextcloud.com/c/clients/android\n\n Novo no Nextcloud? Nextcloud é um servidor privado de sincronização e compartilhamento de arquivos e de comunicação. É um software livre e você pode hospedá-lo sozinho ou pagar uma empresa para fazer isso por você. Dessa forma, você controla suas fotos, sua agenda e dados de contatos, seus documentos e tudo mais.\n\nConheça o Nextcloud em https://nextcloud.com @@ -1099,7 +1085,6 @@ Arquivo não encontrado. Tem certeza de que este arquivo existe ou um conflito anterior não foi resolvido? Não foi possível localizar o arquivo no servidor. Outro usuário pode ter excluído o arquivo Nome da pasta - Repetir o upload de arquivos locais com falha Escolher pasta para upload Não foi possível enviar %1$s Upload falhou. Logue-se novamente diff --git a/app/src/main/res/values-pt-rPT/strings.xml b/app/src/main/res/values-pt-rPT/strings.xml index 501835adbc64..74ad4889b624 100644 --- a/app/src/main/res/values-pt-rPT/strings.xml +++ b/app/src/main/res/values-pt-rPT/strings.xml @@ -44,17 +44,12 @@ Mostra um \'\'widget\'\' do painel Procurar em %s Aparecer offline - Adicionar nova tarefa - Criar uma nova tarefa a partir do canto inferior direito - Digite algum texto Tem a certeza que deseja eliminar esta tarefa? Eliminar tarefa - A carregar a lista de tarefas... Ocorreu um erro enquanto criava a tarefa Tarefa criada com sucesso Ocorreu um erro enquanto eliminava a tarefa Tarefa eliminada com sucesso - A lista de tarefas está vazia. Eliminar Tarefa O resultado da tarefa ainda não está pronto. Assistente @@ -114,6 +109,7 @@ Ocupado Calendário Calendários + Cancelar Ocorreu um problema ao carregar o certificado. Registo de alterações desta versão Verificar mais tarde ou recarregar. @@ -194,7 +190,6 @@ Nenhum ficheiro encontrado Não foi encontrada a sua última cópia de segurança! Conversações - Copiado para a área de transferência Ocorreu um erro quando tentava copiar este ficheiro ou pasta Não é possível copiar a pasta para uma das suas próprias pastas internas O ficheiro já existe na pasta de destino @@ -379,9 +374,7 @@ A carregar… Nenhuma aplicação para usar este tipo de ficheiro. há segundos - Permissões necessárias Permissões de armazenamento - %1$s precisa de permissões de gestão de ficheiros para enviar os ficheiros. Pode escolher o acesso completo para todos os ficheiros ou acesso só de leitura para as fotografias e vídeos. Permitir o acesso de outras aplicações Verificando destino… Limpando… @@ -408,7 +401,6 @@ O ficheiro não pôde ser sincronizado. Está a ser exibida a última versão disponível. Renomear Erro ao restaurar a versão do ficheiro! - Sucesso a restaurar a versão do ficheiro. Detalhes Transferir Exportar @@ -438,7 +430,6 @@ Local: %1$s Mover todos Remoto: %1$s - Todos os ficheiros foram movidos Avançar 4 horas Google restringiu a transferência dos ficheiros APK/AAB! @@ -489,7 +480,6 @@ Bloqueado pela aplicação %1$s %1$s registos de aplicação Android Não foi encontrada nenhuma aplicação para o envio de registos. Por favor, Instale um cliente de correio eletrónico. - Autenticado como %1$s Iniciar Sessão A hiperligação para a sua interface da Web %1$s quando a abre no seu navegador. Eliminar registos @@ -572,7 +562,6 @@ O servidor chegou ao fim de vida, por favor, actualize-o! Menu mais Insira o seu código - O código será solicitado sempre que a aplicação é iniciada Por favor, insira o seu código Os códigos não coincidem Por favor, reinsira o seu código @@ -580,9 +569,9 @@ Código eliminado Código guardado Código incorreto + Pausar Permitir Negar - Necessário permissões adicionais para enviar e transferir ficheiros. Nenhuma aplicação encontrada para definir a imagem Abrir %1$s parar @@ -669,7 +658,6 @@ Falha ao remover notificação. Remover Eliminado - Remover Introduza um novo nome Não foi possível renomear a cópia local, tente um nome diferente Renomeação impossível, nome já utilizado @@ -742,7 +730,6 @@ Partilhar hiperligação Enviar hiperligação Retirar - Partilhar com… Avatar do utilizador partilhado partilhar partilhado @@ -793,7 +780,6 @@ Armazenamento interno Filmes Música - Acesso completo Imagens A plataforma de produtividade auto-hospedada que o mantém no controlo.\n\nCaracterísticas:\n* Interface moderna e fácil de utilizar, adequada ao tema do seu servidor\n* Envie ficheiros para o seu servidor Nextcloud\n* Partilhe-os com outras pessoas\n* Mantenha os seus ficheiros e pastas favoritos sincronizados\n* Pesquise em todas as pastas do seu servidor\n* Upload automático de fotografias e vídeos tirados pelo seu dispositivo\n* Mantenha-se actualizado com notificações\n* Suporte a múltiplas contas\n* Acesso seguro aos seus dados com impressão digital ou PIN\n* Integração com o DAVx⁵ (anteriormente conhecido como DAVdroid) para uma fácil configuração da sincronização de calendário e contactos\n\nPor favor, comunique todos os problemas em https://github.com/nextcloud/android/issues e discuta esta aplicação em https://help.nextcloud.com/c/clients/android\n\nNovo no Nextcloud? O Nextcloud é um servidor privado de sincronização, partilha e comunicação de ficheiros. É um software livre e pode hospedá-lo você mesmo ou contratar uma empresa para o fazer por si. Desta forma, controla as suas fotografias, o seu calendário e dados de contacto, os seus documentos e tudo o resto. \n\nVeja o Nextcloud em https://nextcloud.com A plataforma de produtividade auto-alojada que o/a mantém no controlo.\nEsta é a versão de desenvolvimento oficial, com uma amostra diária de funcionalidades não testadas que podem causar instabilidade e perda de dados. A aplicação é para pessoas dispostas a testar e reportar erros, caso ocorram. Não a use para o seu trabalho de produção!\n\nTanto a versão de desenvolvimento como a normal estão disponíveis no F-droid e podem ser instaladas ao mesmo tempo. diff --git a/app/src/main/res/values-ro/strings.xml b/app/src/main/res/values-ro/strings.xml index 2bfea29a98dd..4040360224cf 100644 --- a/app/src/main/res/values-ro/strings.xml +++ b/app/src/main/res/values-ro/strings.xml @@ -42,8 +42,6 @@ Port proxy Arată un singur widget din panoul principal Caută in %s - Adaugă sarcină nouă - Tastează un text Sigur doriți să ștergeți acest task? A apărut o eroare la crearea taskului Task creat cu succes @@ -52,7 +50,6 @@ Nu se poate prelua lista taskurilor, vă rugăm să verificați conexiunea la internet. Şterge task Rezultatul sarcinii nu este disponbil încă - Nu se pot prelua tipurile taskurilor, vă rugăm să verificați conexiunea la internet. Asistent Intrare Rezultat @@ -112,6 +109,7 @@ Ocupat Calendar Calendare + Cancel Există o problemă la încărcarea certificatului. Jurnalul de modificări pentru versiunea în curs de dezvoltare Revino mai târziu sau reîncarcă. @@ -196,7 +194,6 @@ Nu sunt conversații Conversații Copiat - Copiat în clipboard A apărut o eroare în timpul copierii fișierului sau dosarului Nu se poate copia un dosar intr-un descendent Fișierul există deja în dosarul de destinație @@ -383,10 +380,8 @@ Se încarcă… Nu este instalată nicio aplicație care să deschidă acest tip de fișiere. secunde în urmă - Este necesară acordarea permisiunii Permisiuni de stocare %1$s funcționează cel mai bine cu permisiuni de acces la spațiul de stocare. Puteți alege accesul complet la toate fișierele sau accesul doar pentru citire la fotografii și videoclipuri. - %1$s are nevoie de permisiuni de gestionare a fișierelor pentru a încărca fișiere. Puteți alege accesul complet la toate fișierele sau accesul doar pentru citire la fotografii și videoclipuri. Se verifică destinația… Curățare… Se actualizează dosarul de stocare a datelor @@ -420,7 +415,6 @@ Fișierul nu a putut fi sincronizat. Aceastea sunt ultimile versiuni disponibile. Redenumire Eroare în restaurarea acestei versiuni a fisierului! - S-a restaurat cu succes versiunea acestui fișier. Detalii Descarcă Exportă @@ -454,7 +448,6 @@ Local: %1$s Mutare tot La distanță: %1$s - Toate fișierele au fost mutate Înainte 4 ore Google a restricționat descărcarea fișierelor APK/AAB! @@ -507,7 +500,6 @@ Blocat de aplicația%1$s %1$s înregistrările app-ului Android Nu există nici o aplicație pentru a trimite fisiere log. Vă rugăm instalați un client de email. - Autentificat ca %1$s Autentificare Linkul către %1$s interfața web atunci când deschizi linkul în browser. Șterge fișiere log @@ -588,7 +580,6 @@ Acest server a ajuns la finalul perioadei de suport, vă rugăm faceți un upgrade! Meniul de mai multe Introdu parola - Parola va fi solicitată de fiecare dată când deschideți aplicația Vă rugăm introduceți parola Parolele nu se potrivesc Vă rugăm reintroduceți parola @@ -596,11 +587,10 @@ Parolă ștearsă Parolă stocată Parolă incorectă + Pauză Nu s-a putut deschide fisierul PDF protejat cu parolă. Va rugăm folosiți o altă aplicație pentru vizualizarea fișierului PDF. - Atingeți ușor o pagină pentru a mări imaginea Permiteți Refuzați - Sunt necesare drepturi adiționale pentru a încărca și descărca fișiere. Nu a fost găsită o aplicație pentru a seta imaginea Deschide %1$s stop @@ -678,7 +668,6 @@ Eșuare în eliminarea notificărilor. Șterge Șters - Elimină Introduceţi un nou nume Nu s-a putut redenumi copia locală, încercați un alt nume Redenumirea nu este posibilă, numele este deja luat @@ -747,7 +736,6 @@ Partajază legătură Trimite legătură Desetează - Partajează cu… Avatar de la utilizatorul primit Distribuie partajat @@ -795,7 +783,6 @@ Stocare internă Filme Muzică - Acces complet Media read-only Poze Platforma de productivitate locală care vă menține în control.\nAceasta este versiunea de dezvoltare oficială, cuprinzând exemple zilnice de funcționalități netestate, care pot crea instabilitate sau pierderi de date. Aplicația este pentru utilizatori care doresc să testeze și să raporteze bug-uri dacă acestea apar. Nu folosiți în producție!\n\n Și versiunea oficială de dezvoltare și cea stabilă sunt disponibile pe F-droid și pot fi instalate în același timp. diff --git a/app/src/main/res/values-ru/strings.xml b/app/src/main/res/values-ru/strings.xml index 26298baa39ba..947e385a1eab 100644 --- a/app/src/main/res/values-ru/strings.xml +++ b/app/src/main/res/values-ru/strings.xml @@ -44,21 +44,15 @@ Показывает один виджет с главного экрана. Искать в %s \"Не в сети\" для остальных - Добавить новую задачу - Создайте новую задачу в правом нижнем углу - Наберите какой-то текст Вы уверены, что хотите удалить эту задачу? Удалить задачу - Загрузить список задач… Произошла ошибка при создании задачи Задача успешно создана Произошла ошибка во время удаления задачи Задача удалена - Сптсок задач пуст. Не удается получить список задач, проверьте ваше подключение к Интернету. Удалить задачу Вывод задания еще не готов. - Не удается получить список задач, проверьте ваше подключение к Интернету. Помощник Ввод Вывод @@ -120,6 +114,7 @@ Занят Календарь Календари + Cancel Проблема при загрузке сертификата. Журнал изменений версии для разработчиков Зайдите позже или перезагрузите. @@ -207,7 +202,6 @@ Не найдено ни одного обсуждения Беседы Скопировано - Скопировано в буфер обмена Произошла ошибка при попытке копирования этого файла или каталога Невозможно копирование каталога в его подкаталог Файл уже существует в каталоге назначения @@ -418,11 +412,8 @@ Получение данных… Не найдено приложение для открытия этого типа файлов. несколько секунд назад - Недостаточно прав Права на хранилище %1$s работает лучше всего при наличии доступа к хранилищу. Вы можете выбрать полный доступ к файлам или доступ только для чтения к фото и видео. - %1$s необходимы права на управления файлами, для их загрузки. -Вы можете выбрать полный доступ к файлам или доступ только для чтения к фото и видео. Разрешить доступ из других приложений Проверка назначения… Очистка… @@ -460,7 +451,6 @@ Загрузка не удалась. Нет интернет-соединения %s уже существует, конфликтов не обнаружено Ошибка восстановления версии файла! - Версия файла успешно восстановлена Свойства Скачать Экспорт @@ -496,7 +486,6 @@ На устройстве: %1$s Переместить все На сервере: %1$s - Все файлы перемещены Вперёд 4 часа Google ограничил загрузку файлов APK/AAB! @@ -551,7 +540,6 @@ Заблокировано приложением %1$s Журналы приложения %1$s для Android Приложение для отправки журналов не найдено. Пожалуйста, установите почтовый клиент. - Выполнен вход как %1$s Войти Ссылка для в %1$s через веб-интерфейс для использования в браузере. Удалить журнал @@ -651,7 +639,6 @@ Версия сервера Nextcloud более не поддерживается, требуется её обновление. Дополнительное меню Введите код - Код будет запрашиваться каждый раз при запуске приложения Введите ваш код Коды не совпадают Введите ваш код ещё раз @@ -659,11 +646,10 @@ Код удалён Код сохранён Некорректный код + Пауза Невозможно открыть защищенный паролем PDF-файл. Воспользуйтесь сторонним просмотрщиком PDF. - Нажмите на страницу, чтобы увеличить Разрешить Запретить - Для отправки и скачивания файлов требуются дополнительные права доступа. Выберите контакт, которому вы хотите предоставить общий доступ Не найдено приложений для обработки изображений Закрепить на главном экране @@ -770,7 +756,6 @@ Не удалось скрыть уведомление. Удалить Удалено - Исключить Введите новое имя Невозможно переименовать локальную копию, попробуйте другое имя Переименование невозможно, имя занято @@ -866,7 +851,6 @@ Общий доступ по ссылке Отправить ссылку Сброс - Поделиться… Аватар от общего пользователя общий ресурс поделился @@ -919,7 +903,6 @@ Внутреннее хранилище Фильмы Музыка - Полный доступ Носитель только для чтения Изображения Устанавливаемая на свой сервер платформа для повышения продуктивности, которая позволяет держать всё под контролем.\n\nFeatures:\n* Простой, современный интерфейс, соответствующий тематике вашего сервера\n* Загружайте файлы на свой сервер Nextcloud\n* Делитесь ими с другими\n* Синхронизируйте избранные файлы и папки\n* Поиск по всем папкам на вашем сервере\n* Автоматическая загрузка фотографий и видео, снятых на вашем устройстве\n* Будьте в курсе событий благодаря уведомлениям\n* Поддержка нескольких учётных записей\n* Безопасный доступ к вашим данным с помощью отпечатка пальца или PIN-кода\n* Интеграция с DAVx⁵ (ранее известен как DAVdroid) для простой настройки синхронизации календаря и контактов\n\nПожалуйста, сообщайте обо всех проблемах на https://github.com/nextcloud/android/issues и обсуждайте это приложение на https://help.nextcloud.com/c/clients/android\n\nНовичок в Nextcloud? Nextcloud — это приватный сервер синхронизации и обмена файлами и коммуникационный сервер. Это свободное программное обеспечение, и вы можете разместить его самостоятельно или заплатить компании, чтобы это сделали за вас. Таким образом, вы управляете своими фотографиями, календарём и контактными данными, документами и всем остальным.\n\nОзнакомьтесь с Nextcloud по адресу https://nextcloud.com @@ -1064,7 +1047,6 @@ Файл не найден. Вы уверены, что этот файл существует или предыдущий конфликт не был разрешен? Нам не удалось найти файл на сервере. Возможно, другой пользователь удалил файл Имя каталога - Повторить попытку загрузки неудачно загруженных локальных файлов Выбрать каталог для передачи Не удалось передать файл «%1$s» Ошибка передачи файла, необходимо войти в систему diff --git a/app/src/main/res/values-sc/strings.xml b/app/src/main/res/values-sc/strings.xml index 01ad2bb45676..e823d82a24dc 100644 --- a/app/src/main/res/values-sc/strings.xml +++ b/app/src/main/res/values-sc/strings.xml @@ -84,6 +84,7 @@ Impinnadu Calendàriu Calendàrios + Cancel Problema in su carrigamentu de su tzertificadu. Registru de is modìficas de sa versione dispositivu Casella de ispunta @@ -158,7 +159,6 @@ Peruna resonada agatada Cunversatziones Copiadu - Copiadu in punta de billete Ddoe at àpidu un\'errore in sa còpia de su documentu o de sa cartella No est possìbile a copiare una cartella a intro de una de is cartellas in suta Su documentu est giai presente in sa cartella de destinatzione @@ -330,7 +330,6 @@ No at fatu a sincronizare su documentu. Mustrende s\'ùrtima versione a disponimentu. Torra a numenare Errore in su recùperu de sa versione documentu! - Recùperu de sa versione documentu fatu. Detàllios Iscàrriga Esporta @@ -363,7 +362,6 @@ Locale: %1$s Tràmuda totu Remotu: %1$s - Totu is documentos tramudados Torra a imbiare 4 oras Nùmene @@ -464,7 +462,6 @@ Su serbidore est a sa fine de sa vida sua, agiorna·ddu! Àteros menu Inserta su còdighe de atzessu - Su còdighe de atzessu at a èssere rechestu ogni borta chi s\'aplicatzione s\'aviat. Inserta su còdighe de atzessu Is còdighes de atzessu non sunt is pròpios Torra a insertare su còdighe de atzessu @@ -472,9 +469,9 @@ Còdighe de atzessu cantzelladu Còdighe de atzessu sarvadu Còdighe de atzessu isballiadu + Pàusa Permite Nega - Sunt rechertos àteros permissos pro carrigare e iscarrigare documentos. Peruna aplicatzione agatada pro cunfigurare un\'immàgine firma parti @@ -553,7 +550,6 @@ No at fatu a nche bogare sa notìfica. Boga Cantzellada - Boga Inserta unu nùmene nou No at fatu a torrare a numenare sa còpia locale, proa cun un\'àteru nùmene Impossìbile a torrare a numenare, su nùmene esistit giai @@ -620,7 +616,6 @@ Cumpartzi ligòngiu Imbia ligòngiu Non cunfiguradu - Cumpartzi cun... Avatar dae utente cumpartzidu cumpartzi cumpartzidu diff --git a/app/src/main/res/values-sk-rSK/strings.xml b/app/src/main/res/values-sk-rSK/strings.xml index c30aa9c77d4a..23e3b334ce2e 100644 --- a/app/src/main/res/values-sk-rSK/strings.xml +++ b/app/src/main/res/values-sk-rSK/strings.xml @@ -45,23 +45,17 @@ Hľadať v %s Zdá sa byť offline Výstup zobrazený tu je generovaný umelou inteligenciou. Uistite sa, že vždy dôkladne skontrolujete. - Pridať novú úlohu - Vytvorte novú úlohu vpravo dole - Napíšte nejaký text Naozaj chcete vymazať túto úlohu? Odstrániť úlohu Skúste poslať správu, aby ste rozprúdili konverzáciu. Dobrý deň! S čím vám dnes môžem pomôcť? - Načítavam zoznam úloh... Pri vytváraní úlohy nastala chyba Úloha bola úspešne vytvorená Pri odstraňovaní úlohy nastala chyba Úloha bola úspešne odstránená - Zoznam úloh je prázdny. Nie je možné načítať zoznam úloh, skontrolujte svoje internetové pripojenie. Vymazať Úlohu Výstup úlohy ešte nie je dostupný. - Nie je možné načítať typy úloh, skontrolujte svoje internetové pripojenie. Asistent Vstup Výstup @@ -122,6 +116,7 @@ Zaneprázdnený Kalendár Kalendáre + Cancel Nastal problém s načítaním certifikátu. Zmeny v dev verzii Skúste to neskôr alebo znova načítajte. @@ -210,7 +205,6 @@ Zatiaľ žiadne konverzácie Konverzácie Skopírované - Skopírované do schránky Počas kopírovania súboru alebo zložky sa vyskytla chyba Nie je možné skopírovať priečinok do samého seba Súbor už v cieľovom priečinku existuje @@ -407,10 +401,8 @@ Načítavam… Aplikácia pre váš typ súboru sa nenašla. pred sekundami - Vyžadujú sa o oprávnenia Oprávnenia úložiska %1$s funguje najlepšie s oprávnením pre prístup k úložisku. Môžete si vybrať úplný prístup ku všetkým súborom alebo prístup iba na čítanie k fotografiám a videám. - %1$s potrebuje na nahrávanie súborov oprávnenie na správu súborov. Môžete si vybrať úplný prístup ku všetkým súborom alebo prístup iba na čítanie k fotografiám a videám. Povoliť prístup z ostatných aplikácií Kontrolujem umiestnenie… Čistenie… @@ -446,7 +438,6 @@ Premenovať Nahrávanie zlyhalo. Žiadne pripojenie k internetu Chyba pri obnove verzie súboru! - Verzia súboru úspešne obnovená. Podrobnosti Stiahnuť Export @@ -481,7 +472,6 @@ Lokálne: %1$s Presunúť všetko Vzdialené: %1$s - Všetky súbory boli presunuté Preposlať 4 hodiny Google obmedzil sťahovanie APK/AAB súborov! @@ -535,7 +525,6 @@ Zamknuté od aplikácie %1$s %1$s Android app logs Aplikácia na odoslanie logov nenájdená. Prosím nainštalujte emailovú aplikáciu. - Prihlásený ako %1$s Prihlásiť sa Odkaz k vašemu %1$s webovému rozhraniu keď ho otvoríte v prehliadači. Zmazať záznamy @@ -629,7 +618,6 @@ Verzia servra už nie je podporovaná, prosím aktualizujte! Ďalšie menu Vložte svoje heslo - Heslo bude nutné zadať vždy po štarte aplikácie Vložte prosím svoje heslo Heslá sa nezhodujú Vložte prosím znovu svoje heslo @@ -637,11 +625,10 @@ Bezpečnostný kód odstránený Bezpečnostný kód uložený Nesprávne heslo + Pauza Nepodarilo sa otvoriť heslom chránený PDF súbor. Prosím, použite externý PDF prehliadač. - Klepnutím na stránku priblížite Povoliť Odmietnuť - Na nahrávanie a sťahovanie súborov sú potrebné dodatočné oprávnenia. Vybrať kontakt pre zdieľanie Aplikácia na nastavenie obrázku sa nenašla Pripnúť na domovskú obrazovku @@ -746,7 +733,6 @@ Odstránenie upozornenia zlyhalo. Odstrániť Zmazané - Odobrať Zadajte nové meno Nepodarilo sa premenovať lokálnu kópiu, skúste iné meno Premenovanie sa nepodarilo, meno sa už používa @@ -835,7 +821,6 @@ Sprístupniť odkaz Odoslať odkaz Zrušiť - Zdieľať s… Avatar od sprístupneného používateľa sprístupniť sprístupnené @@ -888,7 +873,6 @@ Interné úložisko Videá Hudba - Plný prístup Médiá iba načítanie Obrázky Platforma, ktorú môžete bežať na vlastnom serveri, ktorú môžete mať kompletne pod kontrolou.\nToto je oficiálna vývojová verzia, obsahujúca dennú vzorku všetkých nových a nevyskúšaných funkcií, ktoré môžu spôsobovať nestabilitu a viesť ku strate dát. Aplikácia v tomto štádiu vývoja je určená tým používateľom, ktorí sú ochotní skúšať a hlásiť chyby, ktoré sa vyskytnú. Nepoužívajte ju pre svoju produkčnú prácu.\n\nObe oficiálne verzie, tak vývojová ako aj produkčná sú k dispozícii na F-droid a je možné ich mať nainštalované súbežne. @@ -1028,7 +1012,6 @@ Súbor nenájdený. Ste si istý, že tento súbor existuje alebo predchádzajúci konflikt nebol vyriešený ? Nepodarilo sa nám nájsť súbor na serveri. Iný užívateľ mohol súbor vymazať. Názov priečinka - Opakujte pokus o nahratie zlyhaných lokálnych súborov Vyber priečinok pre nahratie Nepodarilo sa nahrať %1$s Nahrávanie neúspešné, je potrebné sa znovu prihlásiť diff --git a/app/src/main/res/values-sl/strings.xml b/app/src/main/res/values-sl/strings.xml index 76e79f7a0c41..f25d53b813c7 100644 --- a/app/src/main/res/values-sl/strings.xml +++ b/app/src/main/res/values-sl/strings.xml @@ -88,6 +88,7 @@ Zasedeno Koledar Koledarji + Prekliči Prišlo je do težav med nalaganjem potrdila. Dnevnik razvojne različice Preverite kasneje ali ponovno naložite @@ -171,7 +172,6 @@ Ni še začetih pogovorov Pogovori Kopirano - Kopirano v odložišče Prišlo je do napake med kopiranjem datoteke v mapo Ni mogoče kopirati mape v podrejeno mapo Datoteka v ciljni mapi že obstaja @@ -342,10 +342,8 @@ Poteka nalaganje … Ni določenega programa za odpiranje te vrste datotek. pred nekaj sekundami - Zahtevana so posebna dovoljenja Dovoljenje shrambe %1$s deluje najbolje z dostopom do shrambe. Lahko izberete popoln dostop do vseh datotek, ali samo bralni dostop do fotografij in videoposnetkov. - %1$s potrebuje dovoljenje za upravljanje z datotekami, da lahko pošlje datoteke. Na voljo sta možnosti popolnega dostopa do vseh datotek in dostop le za branje in ogled fotografij oziroma videoposnetkov. Poteka preverjanje cilja … Poteka čiščenje … Poteka osodabljanje podatkovne mape @@ -371,7 +369,6 @@ Datoteke ni mogoče uskladiti. Prikazana je zadnja razpoložljiva različica. Preimenuj Prišlo je do napake med obnavljanjem različice datoteke! - Različica datoteke je uspešno obnovljena. Podrobnosti Prejmi Izvozi @@ -401,7 +398,6 @@ Krajevno: %1$s Premakni vse Oddaljeno: %1$s - Vse datoteke so premaknjene Naprej po 4 urah Ima bo označeno kot skrita datoteka @@ -449,7 +445,6 @@ Zaklenjeno s strani %1$s %1$s dnevniki programa Ni nameščenega programa za pošiljanje dnevnikov. Namestiti je treba program za elektronsko pošto. - Prijavljen kot %1$s Prijava Povezava do spletnega vmesnika %1$s, ki se odpre v brskalniku. Izbriši dnevnike @@ -531,7 +526,6 @@ Strežnik je dosegel konec podpore. Posodobite ga! Meni več Vnesite kodo PIN programa - Koda bo zahtevana vsakič pred zagonom programa. Vnesite kodo PIN Vpisani kodi PIN nista enaki Ponovno vnesite kodo PIN @@ -539,11 +533,10 @@ Koda PIN je izbrisana Koda PIN je shranjena Napačna koda PIN + Premor Ni mogoče odpreti z geslom zaščitenega dokumenta PDF. Uporabiti je treba zunanji pregledovalnik. - Kliknite na stran za približanje Dovoli Zavrni - Za prejemanje oziroma pošiljanje datotek v oblak so zahtevana dodatna dovoljenja. Ni najdenega programa za nastavitev slike Odpri %1$s ustavi @@ -628,7 +621,6 @@ Odstranjevanje obvestil je spodletelo. Odstrani Izbrisano - Odstrani Vnesite novo ime Ni mogoče preimenovati krajevne kopije. Poskusite vpisati drugačno ime. Preimenovanje ni mogoče. Ime je že uporabljeno. @@ -701,7 +693,6 @@ Omogoči souporabo s povezavo Pošlji povezavo Odstrani izbor - Omogoči souporabo … Sličica uporabnika souporaba v souporabi @@ -752,7 +743,6 @@ Notranja shramba Video Glasba - Poln dostop Predstavna vsebina samo za branje Slike Okolje, ki vam omogoči popoln nadzor nad datotekami.\nUporabljate uradno razvojno različico, ki omogoča zagon nepreizkušene, dnevno spreminjajoče se kode, ta pa lahko povzroči nestabilnost in izgubo podatkov. Program je namenjen uporabnikom, ki so pripravljeni preizkušati novosti, poročati o težavah in iskati napake. Programa ni priporočljivo uporabiti za resno delo!\n\nObe različici, stabilna in razvojna, sta na voljo na F-droid in ju je mogoče uporabljati nameščeni sočasno. diff --git a/app/src/main/res/values-sq/strings.xml b/app/src/main/res/values-sq/strings.xml index 2f1cd90e7b5d..f033fd4adb27 100644 --- a/app/src/main/res/values-sq/strings.xml +++ b/app/src/main/res/values-sq/strings.xml @@ -71,6 +71,7 @@ Favorites Të gjithë skedarët Kalendar + Cancel Pati një problem gjatë ngarkimit të dëshmisë. Versioni dev i ndryshimeve Checkbox @@ -137,7 +138,6 @@ Asnjë skedarë i gjetur Ne nuk mund të gjejmë backup-in tuaj të fundit! Bisedat - U kopjua në clipboard Ndodhi një gabim teksa përpiqej të kopjohej ky skedar apo kjo dosje S’është e mundur të kopjohet një dosje në një tjetër brenda saj Kartela gjendet tashmë te dosja destinacion @@ -282,7 +282,6 @@ Skedari nuk mund të sinkronizohet. Duke shfaqur versionin më të fundit në dispozicion. Riemërto Gabim në rikthimin e versionit të skedarit! - Versioni i skedarit i rikthyer me sukses. Detajet Shkarkoje Eksport @@ -311,7 +310,6 @@ Vendore: %1$s Zhvendosi të gjitha E largët: %1$s - U zhvendosën të gjithë skedarët Përpara 4 orë Emër @@ -392,7 +390,6 @@ Serveri ka arritur fundin e jetës, ju lutemi përmirësojeni! Më shumë menu Jepni kodkalimin tuaj - Kodkalimi do të kërkohet sa herë që niset aplikacioni Ju lutemi, futni kodkalimin tuaj Kodkalimet s\’janë të njëjtë Ju lutemi, rifutni kodkalimin tuaj @@ -400,9 +397,9 @@ Kodkalimi u hoq Kodkalimi u depozitua Kodkalim i pasaktë + Pauzë Lejo Refuzo - Që të ngarkoni dhe shkarkoni skedar kërkohen leje shtesë. Nuk u gjet asnjë aplikacion për të vendosur foton Çaktivizimi i kontrollit të ruajtjes së energjisë mund të rezultojë në ngarkimin e skedarëve kur gjendeni në gjendje të ulët të baterisë! të fshira @@ -462,7 +459,6 @@ Dështoi heqja e njoftimit. Hiq E fshirë - Hiqe Jepni një emër të ri Nuk mund të riemërtohet kopja lokale, provoni një emër ndryshe Riemërtimi nuk është i mundur, emri është i zënë @@ -516,7 +512,6 @@ Lidhje ndarjeje Dërgo lidhjen E pavendosur - Ndajeni me… Avatar nga përdoruesi i përbashkët ndaje ndarë diff --git a/app/src/main/res/values-sr-rSP/strings.xml b/app/src/main/res/values-sr-rSP/strings.xml index 2732826e17ba..cfc2a00a06fc 100644 --- a/app/src/main/res/values-sr-rSP/strings.xml +++ b/app/src/main/res/values-sr-rSP/strings.xml @@ -75,6 +75,7 @@ Optimizacija baterije Omiljene Svi fajlovi + Poništi Pojavio se problem prilikom učitavanja sertifikata. Dnevnik izmena razvojne verzije Štikliranje @@ -135,7 +136,6 @@ Uvoženje je zakazano i počeće uskoro Nijedan fajl nije nađen Ne mogu da nađem poslednju rezervu! - Kopirano u ostavu Greška prilikom kopiranja ovog fajla ili fascikle Ne može da se iskopira fascikla u neku od svojih podfascikli. Fajl već postoji u odredišnoj fascikli @@ -269,7 +269,6 @@ Fajl ne može da se sinhronizuje. Prikazuje se poslednja dostupna verzija. Preimenuj Greška prilikom vraćanja verzije fajla! - Uspešno povratio verziju fajla. Detalji Preuzmi Fajl preimenovan u %1$sza vreme otpremanja @@ -297,7 +296,6 @@ Lokalni: %1$s Premesti sve Udaljeni: %1$s - Svi fajlovi su premešteni Prosledi 4 sata Ime @@ -380,7 +378,6 @@ Server je izašao iz garancije, molimo ažurirajte ga! još menija Unesite kod za zaključavanje - Kod će biti zatražen svaki put kad se aplikacija pokrene Molimo unesite kôd za zaključavanje Kodovi se ne poklapaju Ponovo unesite kôd za zaključavanje @@ -390,7 +387,6 @@ Neispravan kod Dozvoli Odbij - Dodatne dozvole potrebne da se otpremaju i skidaju fajlovi. Nijedna aplikacija nije nađena da se sa njom postavi slika Isključivanje provere uštede baterije može da dovede do toga da otpremate fajlove sa praznom baterijom! obrisano @@ -499,7 +495,6 @@ Veza deljenja Pošalji vezu Ukloni - Podeli sa… Avatar od deljenog korisnika deljenje podeljeno diff --git a/app/src/main/res/values-sr/strings.xml b/app/src/main/res/values-sr/strings.xml index 8420490a4e40..a1e9e7647db2 100644 --- a/app/src/main/res/values-sr/strings.xml +++ b/app/src/main/res/values-sr/strings.xml @@ -45,23 +45,17 @@ Тражи у %s Прикажи као ван мреже Излаз који је овде приказан је генерисала AI. Обавезно га детаљно проверите. - Додај нови задатак - Креирај нови задатак од доњег десног - Откуцајте неки текст Да ли сте сигурни да желите да обришете овај задатак? Обриши задатак Покушајте да пошаљете поруку и тако започнете разговор. Здраво! Како данас могу да вам помогнем? - Листа задатака се учитава… Дошло је до грешке током креирања задатка Задатак је успешно креиран Дошло је до грешке током брисања задатка Задатак је успешно завршен - Листа задатака је празна. Не може да се преузме листа задатака, молимо вас да проверите везу са интернетом. Обриши задатак Излаз задатка још увек није спреман. - Не могу да се преузму типови задатака, молимо вас да проверите везу са интернетом. Асистент Унос Излаз @@ -129,6 +123,7 @@ Заузет Календар Календари + Откажи Појавио се проблем приликом учитавања сертификата. Дневник измена развојне верзије Покушајте касније или поново учитајте. @@ -218,7 +213,6 @@ Још увек нема разговора Разговори Копирано - Копирано у клипборд Грешка приликом копирања овог фајла или фасцикле Фасцикла се не може копирати у неку од својих потфасцикли. Фајл већ постоји у одредишној фасцикли @@ -429,10 +423,8 @@ Учитавам… Немате апликацију за овај тип фајла. пре пар секунди - Потребне дозволе Дозволе за складиште %1$s најбоље ради када има дозволу да приступи складишту. Можете избрати пуни приступ свим фајловима, или приступ само-за -читање фотографија и видео снимака. - %1$s захтева дозволе управљања за отпремање фајлова. Можете изабрати пуни приступ свим фајловима, или приступ само-за-читање слика и видео снимака. Дозволи приступ из осталих апликација Проверавам одредиште… Чистим… @@ -470,7 +462,6 @@ Отпремање није успело. Нема везе са интернетом %s већ постоји, није откривен конфликт Грешка при враћању верзије фајла! - Успешно враћена верзија фајла. Детаљи Преузми Извези @@ -510,7 +501,6 @@ Локални: %1$s Премести све Удаљени: %1$s - Сви фајлови су премештени Проследи 4 сата Google је забранио преузимање APK/AAB фајлова! @@ -565,7 +555,6 @@ Закључала апликација %1$s Записници %1$s Андроид апликације Нема апликације за слање дневника. Инсталирајте клијент за е-пошту. - Пријављен као %1$s Пријава Линк на ваш %1$s веб интерфејс када га отворите у прегледачу. Обриши записнике @@ -667,7 +656,6 @@ Сервер је превише стар. Ажурирајте га! Додатни мени Унесите кôд - Код ће бити затражен сваки пут кад се апликација покрене Унесите ваш кôд Кодови се не поклапају Поново унесите свој кôд @@ -675,11 +663,10 @@ Кôд обрисан Код је сачуван Неисправан код + Паузирај Не може да се отвори PDF заштићен лозинком. Молимо вас да употребите спољни PDF приказивач. - Тапните на страницу да је зумирате Дозволи Одбиј - Потребне су дозволе за отпремање и преузимање фајлова. Изаберите контакт са којим желите да поделите Нема апликације којом се поставља слика Закачи на почетни екран @@ -786,7 +773,6 @@ Грешка при уклањању обавештења. Уклони Обрисано - Уклони Унесите нов назив Не могу да преименујем локалну копију. Пробајте други назив Преименовање није могуће. Назив већ постоји @@ -882,7 +868,6 @@ Веза дељења Пошаљи везу Уклони - Подели са… Аватар од дељеног корисника дељење подељено @@ -935,7 +920,6 @@ Интерно складиште Филмови Музика - Пуни приступ Само читање медија Слике Платформа продуктивности на вашем серверу и под вашом контролом.\nОсобине:\n* Једноставан и модеран интерфејс, усклађен са темом на серверу\n* Отпремање фајлова на Nextcloud сервер\n* Дељење фајлова са другима\n* Синхронизација омиљених фајлова и фасцикли\n* Претрага кроз све фасцикле на серверу\n* Аутоматско отпремање слика и видео записа са уређаја\n* Обавештења са сервера\n* Подршка за више налога\n* Безбедан приступ свим подацима преко отиска прста или пина\n* Интеграција са DAVx⁵ (раније познатом као DAVdroid) за лако подешавање синхронизације календара и контаката\n\nСве проблеме можете да пријавите на https://github.com/nextcloud/android/issues а о апликацији дискутујте на https://help.nextcloud.com/c/clients/android\n\nНови сте на Nextcloud? Nextcloud је лични сервер за синхронизацију, дељење фајлова и комуникацију. То је слободан софтвер и можете га сами поставити на свој сервер или платити компанији да то учини уместо вас. На тај начин, сами контролишете своје слике, календаре, контакте, документа и све остало.\n\nПогледајте Nextcloud на https://nextcloud.com @@ -1081,7 +1065,6 @@ Фајл није пронађен. Да ли сте стигурни да овај фајл постоји, или да можда конфилкт већ раније није разрешен? Нисмо могли да лоцирамо фајл на серверу. Можда га је обрисао неки други корисник Назив фасцикле - Покушајте поново да отпремите локалне фајлове Одредите фасциклу за отпремање Не могу да отпремим %1$s Неуспешно отпремање. Поново се пријавите diff --git a/app/src/main/res/values-sv/strings.xml b/app/src/main/res/values-sv/strings.xml index eed1d73587b0..484acb6ff8ed 100644 --- a/app/src/main/res/values-sv/strings.xml +++ b/app/src/main/res/values-sv/strings.xml @@ -45,26 +45,20 @@ Sök i %s Visa som frånkopplad Utdata som visas här genereras av AI. Se till att alltid dubbelkolla. - Lägg till ny uppgift Kunde inte skicka ett meddelande Kunde inte hämta chattmeddelanden - Skapa en ny uppgift från nedre högra hörnet - Skriv någon text Är du säker på att du vill ta bort den här uppgiften? Ta bort uppgift Försök att skicka ett meddelande för att få igång en konversation. Hej! Vad kan jag hjälpa dig med idag? - Laddar uppgiftslista… Ett fel uppstod när uppgiften skapades Uppgiften har skapats Ett fel uppstod när uppgiften skulle tas bort Uppgiften har raderats - Uppgiftslistan är tom. Uppgiftslistan är tom. Kontrollera konfigurationen för assistentappen. Det går inte att hämta uppgiftslistan, kontrollera din internetanslutning. Ta bort uppgift Uppgiftens resultat är inte redo än. - Det går inte att hämta uppgiftstyper, kontrollera din internetanslutning. Assistent Inmatning Utdata @@ -132,6 +126,7 @@ Upptagen Kalender Kalendrar + Avbryt Det uppstod ett problem med att läsa in certifikatet. Ändringslogg utvecklingsversion Återkom senare eller ladda om @@ -224,7 +219,6 @@ Kunde inte hämta konversationslistan Konversationer Kopierad - Kopierat till urklipp Ett fel uppstod, kunde inte kopiera filen eller mappen Det är inte möjligt att kopiera mappen till en av dess undermappar Filen finns redan i målmappen @@ -438,10 +432,8 @@ Läser in… Det finns ingen applikation för att hantera denna filtyp sekunder sedan - Behörighet saknas Lagringsbehörigheter %1$s fungerar bäst med åtkomstbehörighet till lagringsutrymmet. Du kan välja att ha fullständig åtkomst till alla filer eller läsåtkomst till bilder och videor. - %1$s behöver behörighet för filåtkomst för filuppladdning. Du kan välja att ha fullständig åtkomst till alla filer eller endast läsåtkomst till bilder och videor. Tillåt åtkomst från andra appar Kontrollerar mål… Rensar upp… @@ -479,7 +471,6 @@ Uppladdning misslyckades. Ingen internetanslutning %s finns redan, ingen konflikt upptäcktes Fel vid återställning av filversion! - Lyckades återställa filversion. Detaljer Hämta Exportera @@ -519,7 +510,6 @@ Lokal: %1$s Flytta all Extern: %1$s - Alla filer flyttades Vidarebefordra 4 timmar Google begränsad nedladdning av APK/AAB-filer! @@ -574,7 +564,6 @@ Låst av %1$s app %1$s Android-apploggar Ingen app för att skicka loggar hittades. Vänligen installera en e-postklient. - Inloggad som %1$s Logga in Länken till din %1$s webbsida när du öppnar den i webbläsaren. Ta bort loggar @@ -677,7 +666,6 @@ Servern har nått slutet av livet, vänligen uppgradera! Mer Meny Skriv in ditt lösenord - Koden kommer efterfrågas varje gång du startar appen Vänligen ange ditt lösenord Lösenkoden begärs varje gång appen öppnas eller öppnas igen efter 5 sekunder Koderna matchar inte @@ -686,11 +674,10 @@ Lösenord raderat Kod sparad Ogiltigt lösenord + Pausa Kan inte öppna lösenordsskyddad PDF. Använd en extern PDF-läsare. - Tryck på sidan för zoomning Tillåt Neka - Ytterligare rättigheter krävs för att ladda upp eller hämta filer Välj kontakt att dela med Ingen app hittades för att ställa in en bild med Fäst på hemskärmen @@ -800,7 +787,6 @@ Kunde inte radera notifiering. Ta bort Borttagen - Ta bort Ange ett nytt namn Det gick inte att byta namn på lokal kopia, prova ett annat namn Namnbytning är inte möjligt, namnet är redan taget @@ -896,7 +882,6 @@ Dela länk Skicka länk Inaktivera - Delad med… Profilbild från delad användare dela delad @@ -953,7 +938,6 @@ Lagringsbehörighet krävs för auto-uppladdning. Lagringsbehörighet krävs för filuppladdningar. Fråga inte - Fullständig åtkomst En läsåtkomst till media Bilder Den självhostade produktivitetsplattformen som ger dig full kontroll. n\nFunktioner:\n* Enkelt, modernt gränssnitt som passar temat på din server\n* Ladda upp filer till din Nextcloud-server\n* Dela dem med andra\n* Håll dina favoritfiler och mappar synkroniserade\n* Sök i alla mappar på din server\n* Automatisk uppladdning av foton och videor som tagits med din enhet\n* Håll dig uppdaterad med aviseringar\n* Stöd för flera konton\n* Säker åtkomst till dina data med fingeravtryck eller PIN-kod\n* Integration med DAVx⁵ (tidigare känt som DAVdroid) för enkel konfiguration av synkronisering av kalender och kontakter\n\nRapportera alla problem till https://github.com/nextcloud/android/issues och diskutera denna app på https://help.nextcloud.com/c/clients/android\n\nNy på Nextcloud? Nextcloud är en privat server för synkronisering och delning av filer samt kommunikation. Det är fri programvara, och du kan själv vara värd för den eller betala ett företag för att göra det åt dig. På så sätt har du kontroll över dina foton, din kalender och dina kontaktuppgifter, dina dokument och allt annat.\n\nKolla in Nextcloud på https://nextcloud.com @@ -1099,7 +1083,6 @@ Filen hittades inte. Är du säker på att denna fil existerar eller har en tidigare konflikt inte blivit löst? Vi kunde inte hitta filen på servern. En annan användare kan ha raderat filen. Mappnamn - Försök igen att ladda upp misslyckade lokala filer Välj mapp för uppladdning Kunde inte ladda upp %1$s Uppladdningen misslyckades, logga in igen diff --git a/app/src/main/res/values-sw/strings.xml b/app/src/main/res/values-sw/strings.xml index 1e77a8d90844..40907913eb0e 100644 --- a/app/src/main/res/values-sw/strings.xml +++ b/app/src/main/res/values-sw/strings.xml @@ -45,24 +45,18 @@ Tafuta katika %s Tokea nje ya mtandao Matokeo yaliyoonyeshwa hapa yanatolewa na AI. Hakikisha kuangalia mara mbili kila wakati. - Ongeza jukumu jipya - Ongeza jukumu jipya kutoka chini kulia - Andika maandishi kadhaa Je, una uhakika unataka kufuta jukumu hili? Futa jukumu Jaribu kutuma ujumbe ili kuzua mazungumzo. Hujambo! Nikusaidie nini leo? - Inapakia orodha ya kazi... Hitilafu ilitokea wakati wa kuunda jukumu Jukumu limeundwa kwa mafanikio Hitilafu ilitokea wakati wa kufuta jukumu Jukumu limefutwa kwa mafanikio - Orodha ya majukumu ni tupu. Orodha ya majukumu iko tupu. Angalia usanidi wa programu ya Mratibu. Imeshindwa kuleta orodha ya kazi, tafadhali angalia muunganisho wako wa mtandao Futa jukumu Toleo la kazi bado halijawa tayari. - Imeshindwa kuleta aina za kazi, tafadhali angalia muunganisho wako wa mtandao Msaidizi Ingilio Tokeo @@ -130,6 +124,7 @@ Bize Kalenda Kalenda + Ghairi Kuna tatizo la kupakia cheti. Toleo la mabadiliko ya dev Angalia tena baadaye au upakie upya. @@ -219,7 +214,6 @@ Bado hakuna mazungumzo Mazungumzo Iliyonakiliwa - Nakili katika ubao wa kunakili Hitilafu ilitokea wakati wa kujaribu kunakili faili au folda hii Haiwezekani kunakili folda kwenye mojawapo ya folda zake za msingi Faili tayari iko kwenye folda lengwa @@ -432,10 +426,8 @@ Inapakia Hakuna programu iliyosanidiwa kushughulikia aina hii ya faili. sukunde zilizopita - Ruhusa zinahitajika Ruhusa za kuhifadhi %1$s inafanya kazi vyema ikiwa na ruhusa ya kufikia hifadhi. Unaweza kuchagua ufikiaji kamili wa faili zote, au ufikiaji wa kusoma tu kwa picha na video. - %1$s inahitaji ruhusa za usimamizi wa faili ili kupakia faili. Unaweza kuchagua ufikiaji kamili wa faili zote, au ufikiaji wa kusoma tu kwa picha na video. Ruhusu ufikiaji kutoka kwa programu zingine Inakagua lengwa... Inasafisha... @@ -473,7 +465,6 @@ Imeshindwa kupakia. Hakuna muunganisho wa mtandao %s tayari ipo, hakuna mzozo uliogunduliwa Hitilafu katika kurejesha toleo la faili! - Imefaulu kurejesha toleo la faili. Maelezo ya kina Pakua Safirisha @@ -513,7 +504,6 @@ Ndani: %1$s Hamisha zote Mbali: %1$s - Faili zote zilihamishwa Mbele Masaa 4 Google ilizuia kupakua faili za APK/AAB! @@ -568,7 +558,6 @@ Imefungwa na programu %1$s %1$s Kumbukumbu za programu ya Android Hakuna programu ya kutuma kumbukumbu iliyopatikana. Tafadhali sakinisha kiteja cha barua pepe. - Imeingia kama %1$s Ingia Kiungo cha kiolesura chako cha %1$s unapokifungua kwenye kivinjari. Futa kumbukumbu @@ -670,7 +659,6 @@ Seva imefikia mwisho wa maisha, tafadhali pata toleo jipya zaidi! Menyu zaidi Weka nambari yako ya siri - Nambari ya siri itaombwa kila wakati programu inapoanzishwa Tafadhali weka nenosiri lako Nambari ya siri itaombwa kila wakati programu inapofunguliwa au kufunguliwa tena baada ya sekunde 5. Nambari za siri hazifanani @@ -679,11 +667,10 @@ Nambari ya siri imefutwa Nambari ya siri iliyohifadhiwa Nambari ya siri isiyo sahihi + Sitisha Haiwezi kufungua PDF iliyolindwa na nenosiri. Tafadhali tumia kitazamaji cha nje cha PDF. - Gonga kwenye ukurasa ili kuvuta ndani Ruhusu Kataa - Ruhusa za ziada zinahitajika ili kupakia na kupakua faili. Chagua mtu wa kushiriki naye Hakuna programu iliyopatikana ya kuweka picha nayo Bandika kwenye skrini ya nyumbani @@ -790,7 +777,6 @@ Imeshindwa kuondoa arifa. Ondoa Vilivyofutwa - Ondoa Ingiza jina jipya Haikuweza kubadilisha jina la nakala ya ndani, jaribu jina tofauti Kubadilisha jina hakuwezekani, jina tayari limechukuliwa @@ -886,7 +872,6 @@ Shirikisha kiungo Tuma kiungo Unset - Shiriki na... Avatar kutoka kwa mtumiaji aliyeshirikiwa share imeshirikiwa @@ -939,7 +924,6 @@ Hifadhi ya ndani Filamu Muziki - Ufikiaji kamili Vyombo vya habari vya kusoma pekee Picha Mfumo wa tija unaojiendesha unaokuweka katika udhibiti.\n\nVipengele:\n* Kiolesura rahisi, cha kisasa, kinacholingana na mandhari ya seva yako\n* Pakia faili kwenye seva yako ya Nextcloud\n* Zishiriki na wengine\n* Weka faili na folda zako uzipendazo zisawazishwe\n* Tafuta kwenye folda zote kwenye seva yako\n* Pakia Kiotomatiki kwa picha na video zilizochukuliwa na kifaa chako* Usaidizi wa data nyingi\n* Linda ufikiaji salama wa data yako ukitumia alama za vidole au PIN\n* Kuunganishwa na DAVx⁵ (zamani ikijulikana kama DAVdroid) kwa usanidi rahisi wa kalenda na ulandanishi wa anwani\n\nTafadhali ripoti matatizo yote katika https://github.com/nextcloud/android/issues na ujadili programu hii kwenye https://help.nextclouds/android/Nextclouds/android? Nextcloud ni upatanishi wa faili binafsi na seva ya kushiriki na mawasiliano. Ni programu isiyolipishwa, na unaweza kuikaribisha wewe mwenyewe au kulipa kampuni ili ikufanyie hivyo. Kwa njia hiyo, unadhibiti picha zako, kalenda na data yako ya mawasiliano, hati zako na kila kitu kingine.\n\nAngalia Nextcloud katika https://nextcloud.com @@ -1085,7 +1069,6 @@ Faili haijapatikana. Je, una uhakika kuwa faili hii ipo au mgogoro wa awali haujatatuliwa? Hatukuweza kupata faili kwenye seva. Mtumiaji mwingine anaweza kuwa amefuta faili Jina la kisanduku - Jaribu tena kupakia faili za ndani ambazo hazijafanikiwa Chagua folda ya kupakia Haikuweza kupakia %1$s Upakiaji haukufaulu, ingia tena diff --git a/app/src/main/res/values-th-rTH/strings.xml b/app/src/main/res/values-th-rTH/strings.xml index f3bcf38e4147..b445f08ddecb 100644 --- a/app/src/main/res/values-th-rTH/strings.xml +++ b/app/src/main/res/values-th-rTH/strings.xml @@ -31,7 +31,6 @@ แสดงหนึ่งวิดเจ็ตจากแดชบอร์ด ค้นหาใน %s แสดงเป็นออฟไลน์ - พิมพ์ข้อความของคุณ ไม่พบบัญชีที่เกี่ยวข้อง! การเข้าถึงล้มเหลว: %1$s บัญชียังไม่ถูกเพิ่มบนอุปกรณ์นี้ @@ -82,6 +81,7 @@ สื่อ ปฏิทิน ปฏิทิน + Cancel มีปัญหาในการโหลดใบรับรอง บันทึกการเปลี่ยนแปลงรุ่น dev กลับมาตรวจสอบภายหลัง หรือรีโหลด @@ -155,7 +155,6 @@ กำหนดเวลานำเข้าแล้ว และจะเริ่มในอีกสักครู่ ไม่พบไฟล์ ไม่สามารถหาการสำรองข้อมูลครั้งล่าสุด! - คัดลอกไปยังคลิปบอร์ดแล้ว เกิดข้อผิดพลาดขณะพยายามคัดลอกไฟล์หรือโฟลเดอร์นี้ ไม่สามารถคัดลอกโฟลเดอร์เข้าไปยังโฟลเดอร์ที่อยู่ในนั้น ไฟล์นี้มีในโฟลเดอร์ปลายทางอยู่แล้ว @@ -280,10 +279,8 @@ กำลังโหลด… ไม่มีแอปที่ถูกตั้งค่าเพื่อรองรับไฟล์ประเภทนี้ วินาทีที่ผ่านมา - ต้องการสิทธิ์ สิทธิ์ที่จัดเก็บ %1$s จะทำงานได้ดีที่สุดเมื่ออนุญาตสิทธิ์เข้าถึงที่จัดเก็บ คุณสามารถเลือกว่าจะให้เข้าถึงเต็มรูปแบบสำหรับทุกไฟล์ หรือเข้าถึงแบบอ่านเท่านั้นสำหรับรูปภาพและวิดีโอ - %1$s ต้องการสิทธิ์จัดการไฟล์เพื่ออัปโหลดไฟล์ คุณสามารถเลือกว่าจะให้เข้าถึงเต็มรูปแบบสำหรับทุกไฟล์ หรือเข้าถึงแบบอ่านเท่านั้นสำหรับรูปภาพและวิดีโอ กำลังตรวจสอบปลายทาง… กำลังล้าง… กำลังอัปเดตโฟลเดอร์จัดเก็บข้อมูล @@ -309,7 +306,6 @@ ไม่สามารถซิงค์ไฟล์ กำลังแสดงรุ่นล่าสุดที่ใช้งานได้ เปลี่ยนชื่อ เกิดข้อผิดพลาดในการกู้คืนรุ่นไฟล์! - กู้คืนรุ่นไฟล์เสร็จสมบูรณ์ รายละเอียด ดาวน์โหลด ส่งออก @@ -339,7 +335,6 @@ ในเครื่อง: %1$s ย้ายทั้งหมด ระยะไกล: %1$s - ย้ายไฟล์ทั้งหมดแล้ว ส่งต่อ 4 ชั่วโมง ชื่อจะทำให้ไฟล์ถูกซ่อน @@ -443,11 +438,11 @@ เซิฟเวอร์หมดอายุการใช้งานแล้ว โปรดอัปเกรด! เมนูเพิ่มเติม ใส่รหัสยืนยันของคุณ - จะมีการร้องขอรหัสยืนยันทุกครั้งเมื่อเริ่มต้นใช้แอพฯ รหัสยืนยันของคุณไม่ตรงกัน กรุณากรอกรหัสผ่านของคุณใหม่อีกครั้ง รหัสยืนยันที่เก็บไว้ รหัสยืนยันไม่ถูกต้อง + หยุดชั่วคราว เก็บไว้ในโฟลเดอร์ต้นฉบับ ถูกย้ายไปยังโฟลเดอร์แอพพลิเคชัน เพิ่มบัญชี @@ -478,7 +473,6 @@ โหลดใหม่ ลบออก ลบแล้ว - ลบออก กรอกชื่อใหม่ ขอลบบัญชี คืนค่า diff --git a/app/src/main/res/values-tk/strings.xml b/app/src/main/res/values-tk/strings.xml index 58f722c48e46..e17d0ebce51a 100644 --- a/app/src/main/res/values-tk/strings.xml +++ b/app/src/main/res/values-tk/strings.xml @@ -76,6 +76,7 @@ Halanýanlar Ähli faýllar Mediýa + Cancel Şahadatnamany ýüklemekde näsazlyk bar. Özgeriş žurnalynyň gowlaşdyrmak döwri Bellik gutusy @@ -141,7 +142,6 @@ Import meýilnama edilen we gysga wagtda başlar Hiç hili faýl tapylmady Soňky ätiýaçlyk nusgasyny tapyp bilmedim! - Panele göçürildi Bu faýly ýa-da bukjany göçürjek bolanyňyzda ýalňyşlyk ýüze çykdy Bir bukjany onuň öz esasy bukjalarynyň birine göçürmek mümkin däl Faýl niýetlenen bukjada eýýäm bar @@ -296,7 +296,6 @@ Faýl sinhronlap bolmady. Iň soňky wersiýasyny görkezmek. Adyny üýtgetmek Faýl wersiýasyny dikeltmekdäki ýalňyşlyklar! - Faýl wersiýasy üstünlikli dikeldildi. Jikme-jiklikler Göçürip almak %1$sFaýl ýüklenende üýtgedildi @@ -324,7 +323,6 @@ Ýerli:%1$s Hemmesini süýşüriň Uzakdan:%1$s - Ähli faýllar süýşürildi Öňe 4 sagat Ady @@ -415,7 +413,6 @@ Serwer ömrüniň ahyryna ýetdi, täzelemegiňizi haýyş edýäris! Has köp menýu Giriş koduňyzy giriziň - Giriş programmasynyň kody her gezek işe başlanda talap ediler. Parolyňyzy giriziň haýyş edýäris Giriş parollary deň däl Giriş koduňyzy täzeden ýazmagyňyzy haýyş edýäris @@ -425,7 +422,6 @@ Gizlin kod nädogry Rugsat ber inkär et - Faýllary ýüklemek we göçürip almak üçin goşmaça rugsatlar gerek. Surat goýmak üçin hiç bir programma tapylmady Dur üýtgetmek @@ -493,7 +489,6 @@ Duýduryşy aýyrmak başartmady. Aýyrmak Öçürildi - Aýyrmak Täze at giriziň Ýerli göçürmäniň adyny üýtgedip bilmedim, başga bir at synap görüň Adyny üýtgetmek mümkin däl, at eýýäm alyndy @@ -549,7 +544,6 @@ Baglanyşyk paýlaş Baglanyşyk iber Gurnalmady - Paýlaşmak bilen… Paýlaşylan ulanyjydan awatar paýlaş paýlaşdy diff --git a/app/src/main/res/values-tr/strings.xml b/app/src/main/res/values-tr/strings.xml index 978572e9a53b..a6980e422d11 100644 --- a/app/src/main/res/values-tr/strings.xml +++ b/app/src/main/res/values-tr/strings.xml @@ -45,23 +45,17 @@ %s içinde ara Çevrim dışı görün Bu çıktı yapay zeka tarafından oluşturuldu. Her zaman iki kez kontrol ettiğinizden emin olun. - Yeni görev ekle - Sağ alttan yeni bir görev oluşturun - Bir şeyler yazın Bu görevi silmek istediğinize emin misiniz? Görevi sil Bir görüşme başlatacak bir ileti göndermeyi dene. Merhaba! Bugün size nasıl yardımcı olabilirim? - Görev listesi yükleniyor… Görev oluşturulurken bir sorun çıktı Görev oluşturuldu Görev silinirken bir sorun çıktı Görev silindi - Görev listesi boş. Görev listesi alınamadı. Lütfen İnternet bağlantınızı denetleyin. Görevi sil Görev çıktısı henüz hazır değil. - Görev türleri alınamadı. Lütfen İnternet bağlantınızı denetleyin. Yardımcı Giriş Çıkış @@ -129,6 +123,7 @@ Meşgul Takvim Takvimler + İptal Sertifika yüklenirken bir sorun çıktı. Değişiklik günlüğü geliştirici sürümü Bir süre sonra bakın ya da yeniden yükleyin @@ -217,7 +212,6 @@ Henüz bir görüşme yok Görüşmeler Kopyalandı - Panoya kopyalandı Bu dosya ya da klasör kopyalanmaya çalışılırken bir sorun çıktı Bir klasör kendi alt klasörü olarak kopyalanamaz Dosya hedef klasörde zaten var @@ -428,10 +422,8 @@ Yükleniyor … Bu dosya türü için uygulama bulunamadı. saniye önce - İzinler gerekli Depolama izinleri %1$s depolamaya erişim izinleriyle en iyi şekilde çalışır. Tüm dosyalara tam erişim ya da fotoğraf ve videolara salt okunur erişim vermeyi seçebilirsiniz. - %1$sdosya yükleyebilmek için dosya yönetimi izinlerine gerek duyuyor. Tüm dosyalara tam erişim ya da fotoğraf ve videolara salt okunur erişim vermeyi seçebilirsiniz. Diğer uygulamalardan erişilebilsin Hedef denetleniyor … Temizleniyor … @@ -469,7 +461,6 @@ Yüklenemedi. İnternet bağlantısı yok %s zaten var. Herhangi bir çakışma bulunmadı Geri yüklenecek dosya sürümünü seçin! - Dosya sürümü geri yüklendi. Ayrıntılar İndir Dışa aktar @@ -509,7 +500,6 @@ Yerel: %1$s Tümünü taşı Uzak: %1$s - Tüm dosyalar taşındı İlet 4 saat Google APK/AAB dosyalarının indirilmesini kısıtlıyor! @@ -564,7 +554,6 @@ %1$s uygulaması tarafından kilitlenmiş %1$s Android uygulaması günlükleri Günlüklerin gönderilebileceği bir uygulama bulunamadı. Lütfen bir e-posta uygulaması kurun. - %1$s olarak oturum açıldı Oturum aç %1$s site arayüzü için tarayıcıda açacağınız bağlantı. Günlükleri sil @@ -666,7 +655,6 @@ Sunucu ömrünün sonuna geldi, lütfen sürümünü yükseltin! Diğerleri menüsü Parolanızı yazın - Parola uygulama her başlatıldığında sorulacak Lütfen parolanızı yazın Parola ile onayı aynı değil Lütfen parolanızı yeniden yazın @@ -674,11 +662,10 @@ Parola kodu silindi Parola depolandı Parola yanlış + Duraklat Parola ile korunmuş PDF dosyaları açılamıyor. Lütfen bir dış PDF görüntüleyici kullanın. - Yakınlaştırmak için sayfanın üzerine dokunun İzin ver Reddet - Dosya yüklemek ve indirmek için ek izinler gerekli. Paylaşılacak kişiyi seçin Görselin ayarlanabileceği bir uygulama bulunamadı Ana sayfaya sabitle @@ -785,7 +772,6 @@ Bildirim silinemedi. Sil Silindi - Kaldır Yeni bir ad yazın Yerel kopyanın adı değiştirilemedi. Lütfen başka bir ad deneyin Ad zaten kullanıldığından yeniden adlandırılamadı @@ -881,7 +867,6 @@ Paylaşım bağlantısı Bağlantı gönder Kaldır - Şununla paylaş … Paylaşılmış kullanıcının avatarı paylaş paylaşılmış @@ -934,7 +919,6 @@ İç depolama Filmler Müzikler - Tüm dosyalara erişim Ortam dosyalarına salt okunur erişim Fotoğraflar Sizin kontrolunuz altında barındırılan üretkenlik platformu.\n\nÖzellikleri:\n* Sunucunuzun temasına uygun, kolay kullanılan, modern arayüz\n* Dosyaları Nextcloud sunucunuza yükleme\n* Başkaları ile paylaşma\n* İstediğiniz dosya ve klasörleri eşitleme\n* Sunucunuzdaki tüm klasörlerde arama\n* Aygıtınızdaki fotoğraf ve görüntüleri otomatik olarak yükleme\n* Güncelleme bildirimleri\n* Birden çok hesap desteği\n* Verilere parmak izi ya da PIN kodu ile güvenli erişim\n* Kolay takvim ve kişi eşitleme kurulumu için DAVx⁵ bütünleştirmesi (eski adı DAVdroid)\n\nLütfen olabilecek sorunları https://github.com/nextcloud/android/issues adresine bildirin ve uygulama ile ilgili görüşlerinizi https://help.nextcloud.com/c/clients/android adresine yazın\n\nNextcloud kullanmaya yeni mi başladınız? Nextcloud kişisel dosyaları eşitlemek ve paylaşmak için kullanılan bir iletişim sunucusudur. Özgür bir yazılımdır ve kendiniz barındırabileceğiniz gibi bir kuruluş üzerinde ücretli olarak barındırabilirsiniz. Böylece fotoğraflarınız, takviminiz, kişi bilgileriniz ve belgeleriniz gibi pek çok veriyi kendi kontrolunuz altında tutabilirsiniz.\n\nNextcloud hakkında bilgi almak için https://nextcloud.com sitesine bakabilirsiniz. @@ -1080,7 +1064,6 @@ Dosya bulunamadı. Bu dosyanın var olduğundan ya da daha önceki bir çakışmanın çözüldüğünden emin misiniz? Dosya sunucuda bulunamadı. Başka bir kullanıcı dosyayı silmiş olabilir Klasör adı - Tamamlanamamış yerel dosyaları yeniden yükle Yüklenecek klasörü seçin %1$s yüklemesi tamamlanamadı Yüklenemedi, yeniden oturum açmalısınız diff --git a/app/src/main/res/values-ug/strings.xml b/app/src/main/res/values-ug/strings.xml index 1c47b4996287..ca916dbaf138 100644 --- a/app/src/main/res/values-ug/strings.xml +++ b/app/src/main/res/values-ug/strings.xml @@ -10,6 +10,7 @@ تەھرىر بارلىق ئۇقتۇرۇشلارنى تازىلاڭ ئەخلەت ساندۇقى + ئەۋەت / ئورتاق كاتەكچە كۆرۈنۈش تىزىملىك كۆرۈنۈشى ئالاقىلىشىش ۋە كالېندارنى ئەسلىگە كەلتۈرۈش @@ -31,11 +32,21 @@ يېڭى بىخەتەر ھۆججەت چۈشۈرۈش %1$s غا قوشۇڭ ئاساسى URL + كۆچۈرۈش تاخ + سىننى چەكلەڭ + خاتىرىنى چەكلە + سىرتقى تور بېكەتلەر + كۆپ ھېساباتنى چەكلە + ھەمبەھىرلەشنى چەكلە + قوغداشنى يولغا قوي + ۋاكالەتچى ماشىنا نامى ۋاكالەتچى ئېغىز باشقۇرۇش تاختىسىدىكى بىر كىچىك قورالنى كۆرسىتىدۇ %s دىن ئىزدەڭ تورسىز كۆرۈنۈش - بەزى تېكىستلەرنى كىرگۈزۈڭ + بۇ يەردىكى نەتىنج + بىر ئۇچۇرنى ئەۋەتىش مەغلۇپ بولدى + پاراڭ ئۇچۇرلىرىنى چۈشۈرۈش مەغلۇپ بولدى بۇ ۋەزىپىنى ئۆچۈرمەكچىمۇ؟ ۋەزىپىنى ئۆچۈرۈڭ پاراڭلىشىش ئۈچۈن ئۇچۇر ئەۋەتىپ بېقىڭ. @@ -44,12 +55,14 @@ ۋەزىپە مۇۋەپپەقىيەتلىك قۇرۇلدى ۋەزىپىنى ئۆچۈرگەندە خاتالىق كۆرۈلدى ۋەزىپە مۇۋەپپەقىيەتلىك ئۆچۈرۈلدى + ۋەزىپە تىزىملىكى قۇرۇق. ياردەمچى ئەپنىڭ سەپلىمىسىنى تەكشۈر. ۋەزىپە تىزىملىكىنى ئالالمىدى ، تور ئۇلىنىشىڭىزنى تەكشۈرۈپ بېقىڭ. ۋەزىپىنى ئۆچۈرۈڭ - ۋەزىپە تۈرلىرىنى ئېلىپ كېتەلمىدىڭىز ، تور ئۇلىنىشىڭىزنى تەكشۈرۈپ بېقىڭ. + ۋەزىپە نەتىنجىسى تېخى تەييار ئەمەس. ياردەمچى كىرگۈزۈش چىقىرىش + ئويلاۋاتىدۇ... بىرلەشمە ھېسابات تېپىلمىدى! زىيارەت مەغلۇپ بولدى:%1$s بۇ ھېسابات تېخى بۇ ئۈسكۈنىگە قوشۇلمىدى @@ -81,17 +94,25 @@ %1$s كۆپ ھېساباتنى قوللىمايدۇ ئۇلىنىش قۇرالمىدى كىرىشنى ئەمەلدىن قالدۇرۇڭ + ئىناۋەتلىك بىر مۇلازىمېتىر ئادىرسى كىرگۈزۈڭ. + كىرىش تەپسىلاتىنى چۈشۈرەلمىدى. قايتا سىناپ بېقىڭ. كىرىش تەلىپىڭىزنى بىر تەرەپ قىلىشتا مەسىلە كۆرۈلدى. كېيىن قايتا سىناڭ. + بۇ ئۇلىنىشنى ئاچىدىغان تور كۆرگۈ تېپىلمىدى. تور كۆرگۈچىڭىزدە كىرىش جەريانىنى تاماملاڭ + باتارىيە تېجىگۈچ ئۇچۇق بولغانلىقتىن ئاپتۇماتىك چىقىرىش توختىتىپ قۇيۇلدى. ئەسلى ھۆججەت قىسقۇچتا ساقلىنىدۇ + باتارىيە تۆۋەن، چىقىرىشقا ئۇزۇنراق ۋاقىت كىتىشى مۇمكىن پەقەت ئۆلچەمسىز Wi-Fi غا يۈكلەڭ - / AutoUpload + / ئۆزلىكىدىن چىقىرىش + بۇ قىسقۇچ بولشا باش قىسقۇچنىڭ ئىچىدە بار، شۇڭلاشقا قوشلاپ چىقىرىلىشنى كەلتۈرۈپ چىقىرىشى مۇمكىن + چىقىرىش ئۈچۈن ۋايف + ھۆججەتلەرنى %s دىن %s سەپلەڭ يېڭى خاس ھۆججەت قىسقۇچ قۇرۇش ئىختىيارى ھۆججەت قىسقۇچ ئورنىتىڭ توك تېجەش تەكشۈرۈشىنى چەكلەڭ ھۆججەت قىسقۇچنى يوشۇرۇش - Avatar + باش سۈرەت يىراق زاپاسلاش تەڭشىكى ئالاقىلىشىش ۋە كالېندار زاپاسلاش @@ -102,10 +123,11 @@ ياردەمچى ياقتۇرىدىغانلار بارلىق ھۆججەتلەر - Media + كۆپ-ۋاستە ئالدىراش كالېندار كالېندار + ۋاز كەچ گۇۋاھنامىنى يۈكلەشتە مەسىلە بار. Changelog dev نەشرى كېيىن قايتا تەكشۈرۈڭ ياكى قايتا يۈكلەڭ. @@ -115,7 +137,7 @@ قېلىپنى تاللاڭ ۋە ھۆججەت نامىنى كىرگۈزۈڭ. قايسى ھۆججەتنى ساقلاشنى تاللاڭ! كىچىك قورالنى تاللاڭ - Clear + تازلا ئۇقتۇرۇشنى تازىلاش مەغلۇب بولدى. كېيىنكى ھالەتنى ئېنىقلاش تېكىست%1$s دىن كۆچۈرۈلگەن @@ -133,7 +155,7 @@ ئىچكى ساقلىغۇچ يېتەرلىك ئەمەس يوچۇن خاتالىق بۇ ئۈلۈشنى قالدۇرۇڭ - Loading… + يۈكلەۋاتىدۇ… كېيىنكى ياق ھازىر @@ -173,6 +195,7 @@ تاللانغان تۈرلەرنى ۋە ئۇلارنىڭ مەزمۇنىنى ئۆچۈرمەكچىمۇ؟ پەقەت يەرلىك زىددىيەتنى ھەل قىلىش دىئالوگى قۇرغىلى بولمايدۇ + قىسقۇچ توقۇنۇشى يەرلىك ھۆججەت ئەگەر ھەر ئىككى نەشرىنى تاللىسىڭىز ، يەرلىك ھۆججەتنىڭ نامىغا بىر سان قوشۇلىدۇ. ئەگەر ھەر ئىككى نەشرىنى تاللىسىڭىز ، يەرلىك ھۆججەت قىسقۇچنىڭ نامىغا بىر سان قوشۇلىدۇ. @@ -185,14 +208,18 @@ ھازىر زاپاسلاڭ زاپاسلاش پىلانلانغان بولۇپ ، پات يېقىندا باشلىنىدۇ پىلانلانغان ئىمپورت ۋە پات يېقىندا باشلىنىدۇ + كىرگۈزۈشنى باشلىغىلى بولمىدى. قايتا سىناڭ ھۆججەت تېپىلمىدى ئاخىرقى زاپاسلاشنى تاپالمىدىڭىز! + مەزمۇن ئۆزگ + سۆھبەت قۇرۇش مەغلۇپ بولدى سۆھبەتنى ئۆچۈرۈڭ + سۆھبەتنى ئۆچۈرۈش مەغلۇپ بولدى پاراڭ تېپىلمىدى تېخى سۆھبەت يوق + سۆھبەت تىزىملىكىنى چۈشۈرۈش مەغلۇپ بولدى سۆھبەت كۆچۈرۈلگەن - چاپلاش تاختىسىغا كۆچۈرۈلدى بۇ ھۆججەت ياكى ھۆججەت قىسقۇچنى كۆچۈرمەكچى بولغاندا خاتالىق كۆرۈلدى قىسقۇچنى ئۆزىنىڭ ئاستىدىكى قىسقۇچنىڭ بىرىگە كۆچۈرگىلى بولمايدۇ مەنزىل ھۆججەت قىسقۇچىدا ھۆججەت بار @@ -382,10 +409,8 @@ Loading… بۇ ھۆججەت تىپىنى بىر تەرەپ قىلىدىغان ھېچقانداق دېتال قۇرۇلمىغان. سېكۇنت بۇرۇن - ئىجازەت لازىم ساقلاش ئىجازەتنامىسى %1$s ساقلاشقا رۇخسەت قىلىش بىلەن ئەڭ ياخشى ئىشلەيدۇ. بارلىق ھۆججەتلەرنى تولۇق زىيارەت قىلالايسىز ياكى رەسىم ۋە سىنلارنى ئوقۇشقىلا بولىدۇ. - %1$s ھۆججەت يوللاش ئۈچۈن ھۆججەت باشقۇرۇش ئىجازەتنامىسىگە موھتاج. بارلىق ھۆججەتلەرنى تولۇق زىيارەت قىلالايسىز ياكى رەسىم ۋە سىنلارنى ئوقۇشقىلا بولىدۇ. مەنزىلنى تەكشۈرۈش… تازىلاش… سانلىق مەلۇمات ساقلاش قىسقۇچىنى يېڭىلاش @@ -418,7 +443,6 @@ ھۆججەت ماسقەدەملەنمىدى. ئەڭ يېڭى نەشرىنى كۆرسىتىش. ئىسىم ئۆزگەرتىش ھۆججەت نەشرىنى ئەسلىگە كەلتۈرۈشتە خاتالىق! - ھۆججەت نەشرى مۇۋەپپەقىيەتلىك ئەسلىگە كەلتۈرۈلدى. تەپسىلاتى چۈشۈر ئېكسپورت @@ -452,7 +476,6 @@ يەرلىك:%1$s ھەممىنى يۆتكەڭ يىراقتىن:%1$s - بارلىق ھۆججەتلەر يۆتكەلدى ئالدىغا 4 سائەت Google APK / AAB ھۆججىتىنى چۈشۈرۈشنى چەكلىدى! @@ -506,7 +529,6 @@ %1$s ئەپ تەرىپىدىن قۇلۇپلانغان %1$s ئاندىرويىد ئەپ خاتىرىسى خاتىرە ئەۋەتىدىغان ئەپ تېپىلمىدى. ئېلېكترونلۇق خەت خېرىدارنى قاچىلاڭ. - %1$s دەپ تىزىمغا كىردى كىرىڭ تور كۆرگۈچتە ئاچقاندا%1$s تور كۆرۈنمە يۈزىگە ئۇلىنىش. خاتىرىلەرنى ئۆچۈرۈڭ @@ -593,7 +615,6 @@ مۇلازىمېتىر ئۆمرىنىڭ ئاخىرىغا يەتتى ، يېڭىلاڭ! تېخىمۇ كۆپ تىزىملىك مەخپىي نومۇرىڭىزنى كىرگۈزۈڭ - ھەر قېتىم ئەپ قوزغالغاندا مەخپىي نومۇر تەلەپ قىلىنىدۇ مەخپىي نومۇرىڭىزنى كىرگۈزۈڭ مەخپىي نومۇر ئوخشاش بولمايدۇ پارولىڭىزنى قايتا كىرگۈزۈڭ @@ -601,11 +622,10 @@ مەخپىي نومۇر ئۆچۈرۈلدى مەخپىي نومۇر ساقلاندى مەخپىي نومۇر خاتا + توختات پارول بىلەن قوغدالغان PDF نى ئاچقىلى بولمايدۇ. سىرتقى PDF كۆرگۈچنى ئىشلىتىڭ. - چوڭايتىش ئۈچۈن بىر بەتنى چېكىڭ رۇخسەت قىلىڭ رەت قىلىش - ھۆججەتلەرنى يوللاش ۋە چۈشۈرۈش ئۈچۈن قوشۇمچە ئىجازەتلەر. رەسىم ئورنىتىدىغان ھېچقانداق دېتال تېپىلمىدى %1$s نى ئېچىڭ توختا @@ -704,7 +724,6 @@ ئۇقتۇرۇشنى ئۆچۈرەلمىدى. ئۆچۈرۈڭ ئۆچۈرۈلدى - ئۆچۈرۈڭ يېڭى ئىسىم كىرگۈزۈڭ يەرلىك نۇسخىنىڭ نامىنى ئۆزگەرتەلمىدى ، باشقا ئىسىمنى سىناپ بېقىڭ ئىسىم ئۆزگەرتىش مۇمكىن ئەمەس ، ئىسمى ئاللىبۇرۇن ئېلىنغان @@ -788,7 +807,6 @@ ئۇلىنىشنى ھەمبەھىرلەش ئۇلىنىش ئەۋەتىڭ Unset - بىلەن ئورتاقلىشىش… ئورتاق ئىشلەتكۈچىلەرنىڭ ئاۋاتلىقى share ئورتاقلاشتى @@ -840,7 +858,6 @@ ئىچكى ساقلىغۇچ كىنولار مۇزىكا - تولۇق زىيارەت مېدىيا ئوقۇشقىلا بولىدۇ رەسىملەر ئۆزى كونترول قىلىدىغان ئىشلەپچىقىرىش سۇپىسى سىزنى كونترول قىلىدۇ. \ N بۇ رەسمىي تەرەققىيات نۇسخىسى بولۇپ ، ھەر كۈنى يېڭى سىناقتىن ئۆتمىگەن ئىقتىدارلارنىڭ ئەۋرىشكىسى بار ، بۇ مۇقىمسىزلىق ۋە سانلىق مەلۇماتلارنىڭ يوقىلىشىنى كەلتۈرۈپ چىقىرىشى مۇمكىن. بۇ ئەپ سىناق قىلىشنى خالايدىغان ئىشلەتكۈچىلەر ئۈچۈن بولۇپ ، خاتالىق كۆرۈلسە دوكلات قىلىدۇ. ئۇنى ئىشلەپچىقىرىش خىزمىتىڭىزگە ئىشلەتمەڭ! \ N \ n ھەر ئىككىلىسى رەسمىي dev ۋە دائىملىق نۇسخىسى F-droid دا بار ، بىرلا ۋاقىتتا ئورنىتىشقا بولىدۇ. @@ -976,7 +993,6 @@ ھۆججەت تېپىلمىدى. بۇ ھۆججەتنىڭ بارلىقىغا ياكى ئىلگىرىكى توقۇنۇشنىڭ ھەل قىلىنمىغانلىقىغا ئىشىنەمسىز؟ مۇلازىمېتىردىكى ھۆججەتنى تاپالمىدۇق. يەنە بىر ئىشلەتكۈچى ھۆججەتنى ئۆچۈرۈۋەتكەن بولۇشى مۇمكىن قىسقۇچ ئاتى - مەغلۇپ بولغان يەرلىك ھۆججەتلەرنى قايتا سىناڭ يۈكلەش قىسقۇچىنى تاللاڭ %1$s نى يۈكلىيەلمىدى يۈكلەش مەغلۇپ بولدى ، قايتا كىرىڭ diff --git a/app/src/main/res/values-uk/strings.xml b/app/src/main/res/values-uk/strings.xml index 061ec1720ad9..7eaced248ace 100644 --- a/app/src/main/res/values-uk/strings.xml +++ b/app/src/main/res/values-uk/strings.xml @@ -45,24 +45,18 @@ Пошук у %s Перебуваю поза мережею Показаний тут результат генерується штучним інтелектом. Обов\'язково перевіряйте його двічі. - Додати нове завдання - Створити нове завдання праворуч внизу - Вставте будь-який текст Дійсно вилучити це завдання? Вилучити завдання Спробуйте надіслати повідомлення, щоб розпочати розмову. Привіт! Чим я можу вам сьогодні допомогти? - Отримання списку завдань... Помилка під час додавання завдання Успішно додано завдання Помилка під час вилучення завдання Завдання вилучено - Список завдань порожній Список завдань порожній. Перевірте налаштування застосунку асистента. Неможливо отримати список завдань. Перевірте з\'єднання з мережею Вилучити завдання Поки неможливо показати завдання - Не вдалося отримати типи завдань. Перевірте з\'єднання з мережею. Помічник Введення Виведення @@ -130,6 +124,7 @@ Зайнято Календар Календарі + Скасувати Помилка завантаження сертифіката. Версія для розробника зі списку змін Перевірити пізніше або перезавантажити. @@ -218,7 +213,6 @@ Поки що немає розмов Розмови Скопійовано - Скопійовано Виникла помилка під час спроби копіювати цей файл або каталог Неможливо скопіювати каталог до одного із вкладених підкаталогів Файл вже присутній у каталозі призначення @@ -431,10 +425,8 @@ Завантаження… Відсутній застосунок для відкриття файлу такого типу. кілька секунд тому - Потрібні дозволи Доступ до пам\'яти %1$s Найкраще працює з дозволами для доступу до зберігання. Ви можете вибрати повний доступ до всіх файлів або доступ лише для читання до фотографій і відео. - %1$s для завантаження файлів потрібні дозволи на керування файлами. Ви можете вибрати повний доступ до всіх файлів або доступ лише для читання до фотографій і відео. Дозволити доступ з інших застосунків Перевірка місця призначення... Очищення... @@ -472,7 +464,6 @@ Не вдалося завантажити. Відсутнє з\'єднання з мережею. %s вже наявний, відсутні конфлікти Помилка під час відновлення версії файлу! - Успішно відновлено версію файлу. Деталі Отримати Експортувати @@ -512,7 +503,6 @@ Локально: %1$s Перемістити все Віддалено: %1$s - Усі файли переміщено Вперед 4 години Ґуґл обмежив звантаження файлів APK/AAB! @@ -567,7 +557,6 @@ Заблоковано %1$s %1$s Журнали застосунку для Android Не знайдено застосунку для надсилання журналу. Будь ласка, встановіть поштовий клієнт. - Увійшли як %1$s Увійти Посилання на ваш веб-інтерфейс %1$s, коли ви відкриєте його у веб-переглядачі. Вилучити журнал @@ -669,7 +658,6 @@ Завершилася підтримка серверної версії, будь ласка, встановіть нову! Більше параметрів Зазначте пароль - Щоразу під час запуску застосунку вам потрібно буде зазначати пароль Введіть пароль на застосунок Код доступу буде запитуватися щоразу, як застосунок відкриватимуть або повторно відкриють через 5 секунд. Парольні фрази не збігаються @@ -678,11 +666,10 @@ Пароль вилучено Пароль збережено Недійсний пароль + Пауза Неможливо відкрити файл PDF, який захищено паролем. Скористайтеся зовнішнім переглядачем PDF. - Тапніть по сторінці для збільшення Дозволити Заборонити - Додаткові дозволи потрібні для завантаження та звантаження файлів. Виберіть контакт для обміну Не знайдено застосунків для встановлення зображення для Закріпити на домівці @@ -789,7 +776,6 @@ Неможливо зняти сповіщення. Вилучити Вилучено - Вилучити Введіть нове ім\'я Неможливо перейменувати локальну копію, спробуйте інше ім\'я Неможливо перейменувати, таке ім\'я уже існує @@ -885,7 +871,6 @@ Поділитися посиланням Надіслати посилання Зняти - Поділитися з... Значок спільного користувача поділитися надано доступ @@ -938,7 +923,6 @@ Внутрішнє сховище Відео Музика - Повний доступ Мультимедія лише для читання Зображення Самостійна платформа для підвищення продуктивності, яка дозволяє вам зберігати контроль. n\nОсобливості:\n* Простий, сучасний інтерфейс, що відповідає темі вашого сервера\n* Завантажуйте файли на ваш сервер Nextcloud\n* Діліться ними з іншими\n* Синхронізуйте ваші улюблені файли та папки\n* Здійснюйте пошук у всіх папках на вашому сервері\n* Автоматичне завантаження фотографій та відео, зроблених вашим пристроєм\n* Будьте в курсі подій завдяки сповіщенням\n* Підтримка декількох облікових записів\n* Безпечний доступ до ваших даних за допомогою відбитка пальця або PIN-коду\n* Інтеграція з DAVx⁵ (раніше відомим як DAVdroid) для легкого налаштування синхронізації календаря та контактів\n\nБудь ласка, повідомляйте про всі проблеми на https://github.com/nextcloud/android/issues та обговорюйте цей додаток на https://help.nextcloud.com/c/clients/android\n\nНовий у Nextcloud? Nextcloud — це приватний сервер для синхронізації та обміну файлами, а також для спілкування. Це вільне програмне забезпечення, яке ви можете розмістити самостійно або заплатити компанії, щоб вона зробила це за вас. Таким чином, ви контролюєте свої фотографії, календар і контакти, документи та все інше.\n\nОзнайомтеся з Nextcloud на https://nextcloud.com @@ -1084,7 +1068,6 @@ Файл не знайдено. Чи файл дійсно присутній? Можливо, що попередній конфлікт не було вирішено? Не вдалося знайти файл на сервері. Можливо, що інший користувач раніше вилучив цей файл. Назва каталогу - Повторно після помилки завантажити файли, що на пристрої Оберіть каталог для завантаження Не вдалося завантажити %1$s Помилка під час завантаження, увійдіть ще раз diff --git a/app/src/main/res/values-vi/strings.xml b/app/src/main/res/values-vi/strings.xml index d137ab3e1258..ad0631fc917b 100644 --- a/app/src/main/res/values-vi/strings.xml +++ b/app/src/main/res/values-vi/strings.xml @@ -83,6 +83,7 @@ Bận Lịch Lịch + Cancel Có vấn đề khi tải chứng chỉ. Nhật kí phiên bản nhà phát triển Hộp chọn @@ -160,7 +161,6 @@ Không tìm thấy cuộc trò chuyện nào Đàm thoại Đã sao chép - Sao chép vào bảng tạm Đã xảy ra lỗi khi cố gắng sao chép tệp hoặc thư mục này Không thể sao chép một thư mục vào một trong các thư mục cơ bản của chính nó Tập tin đã có trong thư mục đích @@ -318,10 +318,8 @@ Đang tải… Không có ứng dụng nào được thiết lập để xử lý loại tệp này. vài giây trước - Cần quyền Quyền bộ nhớ %1$s hoạt động tốt nhất khi có quyền truy cập bộ nhớ. Bạn có thể chọn truy cập đầy đủ vào tất cả tệp, hoặc truy cập chỉ đọc vào ảnh và video. - %1$s cần quyền quản lý tệp để tải tệp lên. Bạn có thể chọn truy cập đầy đủ vào tất cả tệp, hoặc truy cập chỉ đọc vào ảnh và video. Đang kiểm tra diểm cuối Đang xóa… Đang cập nhật thư mục lưu trữ dữ liệu @@ -347,7 +345,6 @@ Tệp không thể được đồng bộ. Đang hiển thị phiên bản mới nhất có sẵn. Đổi tên Lỗi khi khôi phục phiên bản tệp! - Khôi phục phiên bản tệp thành công. Chi tiết Tải về Xuất ra @@ -376,7 +373,6 @@ Cục bộ: %1$s Dịch chuyển tất cả Từ xa: %1$s - Tất cả tập tin đã được dịch chuyển Forward 4 tiếng Tên sẽ dẫn đến tệp ẩn @@ -484,7 +480,6 @@ Máy chủ không được hỗ trợ nữa, hãy nâng cấp! Thêm menu Nhập mã PIN của bạn - Mã PIN sẽ được yêu cầu mỗi khi ứng dụng được khởi động Hãy nhập mã PIN của bạn Mã PIN không giống nhau Hãy nhập lại mã PIN của bạn @@ -492,10 +487,9 @@ Mã PIN đã được xóa Mã PIN đã được lưu Sai mã PIN - Nhấn vào trang để phóng to + Tạm dừng Cho phép Từ chối - Các quyền bổ sung cần thiết để tải lên và tải xuống tệp. Không tìm thấy ứng dụng nào để đặt ảnh với Mở trong %1$s dừng @@ -573,7 +567,6 @@ Không xóa được thông báo. Xóa Đã xóa - Xoá Nhập tên mới Không thể đổi tên bản sao cục bộ, hãy thử một tên khác Không thể đổi tên, tên đã được sử dụng @@ -640,7 +633,6 @@ Chia sẻ liên kết Gửi liên kết Bỏ cài đặt - Chia sẽ với… Hình đại diện từ người dùng được chia sẻ chia sẽ đã chia sẽ @@ -689,7 +681,6 @@ Bộ nhớ trong Phim Nhạc - Truy cập đầy đủ Chỉ đọc phương tiện Ảnh Nền tảng năng suất tự lưu trữ giúp bạn kiểm soát diff --git a/app/src/main/res/values-zh-rCN/strings.xml b/app/src/main/res/values-zh-rCN/strings.xml index 60a61957eb30..facc1b27e15f 100644 --- a/app/src/main/res/values-zh-rCN/strings.xml +++ b/app/src/main/res/values-zh-rCN/strings.xml @@ -45,23 +45,17 @@ 在 %s 中搜索 显示为离线 此处显示的输出是由人工智慧产生的。请务必仔细检查。 - 添加新任务 - 从右下角创建新任务 - 输入一些文字 您确定要删除这些任务吗? 删除任务 尝试发送消息来发起对话。 您好!请问我能帮您些什么? - 正在加载任务列表… 创建任务时发生错误 任务已创建 删除任务时发生错误 任务已删除 - 任务列表为空。 无法获取任务列表,请检查你的互联网连接。 删除任务 任务输出尚未就绪。 - 无法获取任务类型,请检查您的网络连接。 助手 输入 输出结果 @@ -129,6 +123,7 @@ 忙碌 日历 日历 + 取消 加载证书失败。 开发版本修改日志 请稍后重试 @@ -217,7 +212,6 @@ 未找到对话 尚无对话 对话 - 复制到剪贴板 尝试复制这个文件或文件夹时发生了错误 将文件夹复制到其自己的底层文件夹中是不可能的 该文件已存在于目标文件夹中 @@ -430,10 +424,8 @@ 正在加载... 此文件类型未设置默认打开程序 几秒前 - 需要权限 存储权限 %1$s在有权限访问的存储上工作得最好。您可以选择对所有文件获取完整权限,或者对照片和视频提供只读权限。 - %1$s需要文件管理权限以上传文件。您可以选择对所有文件获取完整权限,或者对照片和视频提供只读权限。 允许从其他应用访问 正在检查目的地… 清除中… @@ -471,7 +463,6 @@ 上传失败,没有互联网连接 %s 已存在,未检测到冲突 恢复文件版本时发生错误! - 成功恢复文件版本。 详情 下载 导出 @@ -511,7 +502,6 @@ 本地: %1$s 移动全部 远程: %1$s - 所有文件已被移动 向前 4小时 Google 限制下载 APK/AAB 文件! @@ -566,7 +556,6 @@ 被 %1$s 应用锁定 %1$s 安卓应用日志 没有找到发送日志文件的应用程序。请安装电子邮件客户端。 - 以 %1$s 登录 登录 在浏览器中打开 %1$s 时显示的 web 界面的链接 删除日志 @@ -668,7 +657,6 @@ 服务端即将达到使用寿命,请升级! 更多菜单 输入安全码 - 每次启动应用都会要求输入安全码 请输入安全码 安全码不一致 请再次输入安全码 @@ -676,11 +664,10 @@ 安全码已删除 安全码已存储 安全码不正确 + 暂停 无法打开被密码保护的PDF文件,请使用外部PDF浏览器打开。 - 点击页面以放大 允许 禁止 - 上传和下载文件需要额外权限。 选择需要分享的联系人 找不到可以设置图片的应用程序 固定到主屏幕 @@ -787,7 +774,6 @@ 移除通知失败 移除 已删除 - 移除 输入一个新的名称 本地副本无法重命名,尝试其他名称 无法重命名,名字已经被占用 @@ -883,7 +869,6 @@ 共享链接 发送链接 未设置 - 共享给… 共享用户的头像 共享 已共享 @@ -936,7 +921,6 @@ 内部存储 影片 音乐 - 完整存取权限 媒体只读权限 图片 自托管生产力平台,让您掌控一切。\n\n特征:\n* 简单、现代的界面,适合您的服务器主题\n* 将文件上传到您的 Nextcloud 服务器\n* 与他人分享\n* 保持您喜爱的文件和文件夹同步\n* 搜索服务器上的所有文件夹\n* 自动上传您设备拍摄的照片和视频\n* 随时接收通知\n* 多账号支持\n* 使用指纹或 PIN 安全访问您的数据\n*与 DAVx⁵ 集成(以前称为 DAVdroid),用于轻松设置日历和联系人同步\n\n请在 https://github.com/nextcloud/android/issues 上报告所有问题,并在 https://help.nextcloud.com/c/clients/android 上讨论此应用\n\n您是 Nextcloud 的新用户吗?Nextcloud 是一个私人文件同步、分享和通信服务器。它是自由软件,您可以自行托管,也可以付费让公司为您托管。这样,您就可以掌控您的照片、日历和联系人数据、文档以及其他所有内容。\n\n访问 https://nextcloud.com 查看 Nextcloud @@ -1085,7 +1069,6 @@ 未找到文件。请确认文件是否存在或者有未解决的冲突 我们无法定位服务器上的该文件。其他用户可能已删除该文件 文件夹名称 - 重试上传失败的本地文件 选择上传文件夹 无法上传 %1$s 上传失败,请重新登录 diff --git a/app/src/main/res/values-zh-rHK/strings.xml b/app/src/main/res/values-zh-rHK/strings.xml index f97aca71a85e..0db2a070dd0e 100644 --- a/app/src/main/res/values-zh-rHK/strings.xml +++ b/app/src/main/res/values-zh-rHK/strings.xml @@ -45,26 +45,20 @@ %s內搜尋 顯示為離線 此處顯示的輸出是由人工智慧產生的。請務必仔細檢查。 - 添加新任務 發送訊息失敗 無法擷取聊天訊息 - 從右下角創建新任務 - 輸入一些文字 您確定要刪除此工作項目嗎? 刪除任務 試著發送一條訊息來引發對話。 你好!今天我能幫你什麼忙呢? - 正在載入任務清單 ... 建立任務項目時發生錯誤 已成功建立任務項目 刪除任務時發生了錯誤 任務已刪除 - 任務清單是空的。 任務清單是空的。請檢查小幫手應用程式設定。 無法擷取任務清單,請檢查您的網際網路連線。 刪除任務 任務輸出尚未就緒。 - 無法擷取任務類型,請檢查您的網際網路連線。 助手 輸入 輸出 @@ -133,6 +127,7 @@ 忙碌 日曆 日曆 + 取消 憑證載入時發生問題 開發版本更新紀錄 稍後再回來查看或重新加載。 @@ -225,7 +220,6 @@ 無法擷取對話清單 對話 已複製 - 已複製到剪貼板 嘗試複製檔案或資料夾時發生錯誤 無法將資料夾複製到自己的子資料夾中。 此檔案目前已存在於目標資料夾中。 @@ -329,6 +323,7 @@ 助手 更多 更多 Nextcloud 應用程式 + 無法開啟檔案選取程式 無法挑選電郵地址。 設為已加密的 無法擷取伺服器證書 @@ -398,6 +393,7 @@ 您無權在此資料夾建立或上傳檔案。 外部分享 新增或上傳 + 無法建立衝突對話框 無法下載 列印失敗 起始編輯器失敗 @@ -439,10 +435,8 @@ 載入中… 未設定處理此檔案類型適用的APP 秒前 - 需要權限 儲存空間權限 %1$s 在有存取儲存空間的權限時運作得最好。您可以選擇完整存取所有檔案,或是對照片及影片的唯讀存取。 - %1$s 需要檔案管理權限以上傳檔案。您可以選擇完整存取所有檔案,或是對照片及影片的唯讀存取。 允許從其他應用程式存取 檢查目的地… 清理中… @@ -480,7 +474,6 @@ 上傳失敗。沒有互聯網連接 %s 已存在,未偵測到衝突 還原檔案版本失敗! - 成功地還原檔案版本。 細節 下載 導出 @@ -520,7 +513,6 @@ 近端:%1$s 移動全部 遠端: %1$s - 已經移動所有檔案 向前 4 小時 Google 限制 APK/AAB 檔案下載! @@ -575,7 +567,6 @@ 被 %1$s 應用程式鎖上 %1$s Android 應用程式記錄 找不到用於發送記錄的應用程式。請安裝電子郵件客戶端。 - 登入為 %1$s 登入 在瀏覽器中打開 %1$s 網絡界面的連結。 刪除紀錄檔案 @@ -678,7 +669,6 @@ 伺服器已過期,請升級! 更多選項單 輸入通行碼 - 每次應用程式開啟時,都需要輸入通行碼 請輸入通行碼 每次應用程式開啟或 5 秒後重新開啟時,都需要輸入通行碼。 兩個通行碼不相符 @@ -687,11 +677,10 @@ 通行碼已刪除 通行碼已儲存 通行碼錯誤 + 暫停 無法開啟密碼保護的 PDF。請使用外部 PDF 檢視程式。 - 點擊頁面放大 允許 拒絕 - 上傳與下載檔案需要額外的權限。 挑選要分享的聯絡人 沒有找到編輯圖片的應用程式 釘選至主畫面 @@ -800,7 +789,6 @@ 移除通知失敗 移除 已刪除 - 移除 輸入新名稱 無法重新命名近端複本,請試用不同名稱 不可重新命名,名稱已存在 @@ -896,7 +884,6 @@ 分享連結 傳送連結 解除設定 - 分享給 分享者的虛擬化身頭像 分享 已分享 @@ -953,7 +940,6 @@ 自動上載需要儲存空間權限。 上載檔案需要儲存空間權限。 不要再詢問 - 完整存取權限 僅媒體唯讀 圖片 可自架且始終讓您掌控一切的生產力平台。\n功能:\n* 簡潔、現代的用戶界面,適合您伺服器的佈景主題\n* 上傳檔案到您的 Nextcloud 伺服器\n* 與其他人分享檔案\n* 讓您最愛的檔案與資料夾同步\n* 搜尋您伺服器上所有的資料夾\n* 以通知訊息保持更新\n* 多帳戶支援\n* 使用指紋或 PIN 碼安全存取您的資料\n* 與 DAVx⁵ 整合(先前被稱為 DAVdroid),可輕易設定行事曆與聯絡人同步\n\n請至 https://github.com/nextcloud/android/issues 舉報所有問題,並於 https://help.nextcloud.com/c/clients/android 討論此應用程式\n\n您是 Nextcloud 新手嗎?Nextcloud 是一個私人的檔案同步、共享與通訊的伺服器。它是自由軟體,您可以自行架設,或是付費請專業公司協助您建置。如此,您便可完全掌控您的照片、行事曆與聯絡人資料、您的文件與其他任何東西。\n\n請造訪 https://nextcloud.com 以取得更多資訊 @@ -1099,7 +1085,6 @@ 找不到檔案。您確定該檔案存在,或之前的衝突尚未解決? 我們無法在伺服器上找到檔案。可能有其他用戶刪除了該檔案。 資料夾名稱 - 重試上傳失敗的近端檔案 選擇上傳檔案夾 上傳 %1$s 無法完成 上傳失敗,再重新登入 diff --git a/app/src/main/res/values-zh-rTW/strings.xml b/app/src/main/res/values-zh-rTW/strings.xml index 0a7270a1804c..03cf1cdafe89 100644 --- a/app/src/main/res/values-zh-rTW/strings.xml +++ b/app/src/main/res/values-zh-rTW/strings.xml @@ -45,26 +45,20 @@ 搜尋 %s 顯示為離線 此處顯示的輸出是由人工智慧產生的。請務必仔細檢查。 - 新增任務 傳送訊息失敗 擷取聊天訊息失敗 - 從右下角建立新任務 - 輸入一些文字 您確定要刪除此工作項目嗎? 刪除工作項目 嘗試傳送訊息來引發對話。 嗨!我現在能怎麼協助您呢? - 正在載入工作項目清單…… 建立工作項目時發生錯誤 已成功建立工作項目 刪除工作項目時發生錯誤 已成功刪除工作項目 - 任務清單為空。 任務清單是空的。請檢查小幫手應用程式設定。 無法擷取工作項目清單,請檢查您的網際網路連線。 刪除工作項目 任務輸出尚未就緒。 - 無法擷取工作項目類型,請檢查您的網際網路連線。 助理 輸入 輸出 @@ -133,6 +127,7 @@ 忙碌 行事曆 行事曆 + 取消 載入憑證時發生問題。 開發版本變動紀錄 稍後再回來檢視或重新載入。 @@ -225,7 +220,6 @@ 擷取對話清單失敗 對話 已複製 - 已複製到剪貼簿 嘗試複製此檔案或資料夾時發生錯誤 無法將資料夾複製到自己的子資料夾中 此檔案已經存在於目標資料夾中 @@ -329,6 +323,7 @@ 助理 更多 更多 Nextcloud 應用程式 + 無法開啟檔案選取程式 挑選電子郵件地址失敗。 設為已加密 無法擷取伺服器憑證 @@ -398,6 +393,7 @@ 您無權在此資料夾建立或上傳檔案。 外部分享 新增或上傳 + 無法建立衝突對話方塊 無法將檔案傳遞給下載管理程式 檔案列印失敗 無法啟動編輯器 @@ -439,10 +435,8 @@ 正在載入… 未設置適合處理此檔案類型的應用程式。 幾秒前 - 需要取用權 儲存空間取用權 %1$s 在有儲存空間的取用權時運作得最好。您可以選擇完整存取所有檔案,或是限制照片及影片僅能唯讀存取。 - %1$s 需要檔案管理權才能上傳檔案。您可以選擇完整存取所有檔案,或是限制照片及影片僅能唯讀存取。 允許從其他應用程式存取 正在檢查目的地… 正在清理… @@ -480,7 +474,6 @@ 上傳失敗。沒有網際網路連線 %s 已存在,未偵測到衝突 檔案版本復原錯誤! - 成功回復檔案版本。 詳細資訊 下載 匯出 @@ -520,7 +513,6 @@ 本機:%1$s 移動全部 遠端:%1$s - 已經移動所有檔案 往前 4 小時 Google 限制 APK/AAB 檔案的下載! @@ -575,7 +567,6 @@ 被 %1$s 應用程式鎖定 %1$s Android 應用程式紀錄檔 找不到可用於傳送紀錄檔的應用程式。請安裝電子郵件客戶端。 - 登入身份為 %1$s 登入 在瀏覽器中開啟您 %1$s 網頁介面的連結。 刪除紀錄檔 @@ -678,7 +669,6 @@ 伺服器版本已達生命週期,請升級! 更多選單 請輸入通行碼 - 每次應用程式開啟時,都需要輸入通行碼 請輸入通行碼 每次應用程式開啟或 5 秒後重新開啟時,都需要輸入通行碼。 兩個通行碼不相符 @@ -687,11 +677,10 @@ 通行碼已刪除 通行碼已儲存 通行碼錯誤 + 暫停 無法開啟受密碼保護的 PDF。請使用外部 PDF 檢視程式。 - 點按頁面可以放大 允許 拒絕 - 上傳與下載檔案需要額外的權能。 挑選要分享的聯絡人 沒有找到圖片可設定的應用程式 釘選至主畫面 @@ -800,7 +789,6 @@ 移除通知失敗。 移除 已刪除 - 移除 輸入新名稱 無法重新命名本機副本,請嘗試不同的名稱 無法重新命名,該名稱已被使用 @@ -896,7 +884,6 @@ 分享連結 傳送連結 解除設定 - 分享給… 分享者的頭像 分享 已分享 @@ -953,7 +940,6 @@ 自動上傳功能需要儲存空間權限。 檔案上傳功能需要儲存空間權限。 不要詢問 - 完整存取權 媒體唯讀 圖片 可自架且始終讓您掌控一切的生產力平台。\n功能:\n* 簡潔、現代的使用者介面,適合您伺服器的佈景主題\n* 上傳檔案到您的 Nextcloud 伺服器\n* 與其他人分享檔案\n* 讓您最愛的檔案與資料夾同步\n* 搜尋您伺服器上所有的資料夾\n* 以通知訊息保持更新\n* 多帳號支援\n* 使用指紋或 PIN 碼安全存取您的資料\n* 與 DAVx⁵ 整合(先前被稱為 DAVdroid),可輕易設定行事曆與聯絡人同步\n\n請至 https://github.com/nextcloud/android/issues 回報所有問題,並於 https://help.nextcloud.com/c/clients/android 討論此應用程式\n\n您是 Nextcloud 新手嗎?Nextcloud 是一個私人的檔案同步、共享與通訊的伺服器。它是自由軟體,您可以自行架設,或是付費請專業公司協助您建置。如此,您便可完全掌控您的照片、行事曆與聯絡人資料、您的文件與其他任何東西。\n\n請造訪 https://nextcloud.com 以取得更多資訊 @@ -1099,7 +1085,6 @@ 找不到檔案。您確定該檔案存在,或之前的衝突尚未解決? 我們在伺服器上找不到檔案。可能有其他使用者刪除了該檔案 資料夾名稱 - 重試上傳失敗的本機檔案 選擇上傳資料夾 無法上傳 %1$s 上傳失敗,請重新登入 From 5eb944e5d5dba41dbf1b8dd393223d5cb24b1c89 Mon Sep 17 00:00:00 2001 From: Nextcloud bot Date: Sun, 7 Dec 2025 02:44:58 +0000 Subject: [PATCH 006/216] fix(l10n): Update translations from Transifex Signed-off-by: Nextcloud bot --- app/src/main/res/values-de/strings.xml | 2 + app/src/main/res/values-ug/strings.xml | 206 +++++++++++++++++++------ 2 files changed, 165 insertions(+), 43 deletions(-) diff --git a/app/src/main/res/values-de/strings.xml b/app/src/main/res/values-de/strings.xml index a023c8698a2d..0f3247e6f314 100644 --- a/app/src/main/res/values-de/strings.xml +++ b/app/src/main/res/values-de/strings.xml @@ -127,6 +127,7 @@ Beschäftigt Kalender Kalender + Abbrechen Beim Laden des Zertifikats ist ein Fehler aufgetreten. Änderungen in der Entwicklerversion Schauen Sie später noch einmal vorbei oder laden Sie neu. @@ -676,6 +677,7 @@ PIN gelöscht PIN gespeichert PIN nicht korrekt + Pausieren Passwortgeschützte PDF-Datei konnte nicht geöffnet werden. Bitte verwenden Sie einen externen PDF-Viewer. Zulassen Ablehnen diff --git a/app/src/main/res/values-ug/strings.xml b/app/src/main/res/values-ug/strings.xml index ca916dbaf138..fac835879205 100644 --- a/app/src/main/res/values-ug/strings.xml +++ b/app/src/main/res/values-ug/strings.xml @@ -184,7 +184,7 @@ Google Play دۇكىنىدىن قويۇپ بېرىش نامزاتىغا ئېرىشىڭ كاندىداتنى قويۇپ بېرىش قويۇپ بېرىلىدىغان كاندىدات (RC) پات ئارىدا ئېلان قىلىنىدىغان سۈرەت بولۇپ ، مۇقىم بولۇشى مۆلچەرلەنمەكتە. شەخسىي تەڭشىكىڭىزنى سىناش بۇنىڭغا كاپالەتلىك قىلالايدۇ. Play دۇكىنىدا سىناققا تىزىملىتىڭ ياكى F-Droid نىڭ \ \"نەشرى \" بۆلىكىنى قولدا كۆرۈڭ. - خاتالىق بايقالدى؟ Oddments? + خاتالىق بايقالدى؟ قالدۇق؟ سىناق ئارقىلىق ياردەم GitHub دىكى بىر مەسىلىنى دوكلات قىلىڭ سەپلەڭ @@ -266,6 +266,13 @@ ئېكسپورت تىپىنى تاللاڭ PDF ئەۋلاد مەغلۇب بولدى PDF ھاسىل قىلىش… + بۇ يەردە تۈر قۇرۇشقا بولمىدى: ئىجازەت قۇرۇلمىغان + ھۆججەت قۇرالمىدى: ئىج + قىسقۇچ قۇرالمىدى: ئىج + تۈرنى ئۆچۈرەلمىدى: ئۆچۈرۈش ئىج + تۈرنى يۆتكىيەلمىدى: يۆتكەش ئىج + تۈرنى ئاچالمىدى: ئېچىش ئىج + تۈرنىڭ ئىسمىنى ئۆزگەرتەلمىدى: ئىسىم ئۆزگەرتىش ئىج تامام ئېنىق ئەمەس يەرلىك ھۆججەت قۇرالمايدۇ @@ -291,7 +298,7 @@ بارلىق ھۆججەتلەر ياردەمچى ياقتۇرىدىغانلار - Media + كۆپ-ۋاستە گۇرۇپپا ھۆججەتلىرى ئۆي ئۇقتۇرۇش @@ -306,19 +313,25 @@ ئىشلىتىلگەن %2$s نىڭ%1$s %1$s ئىشلىتىلگەن ئاپتوماتىك يوللاش + بەك كۆپ خاتا ئۇرۇنۇش سەۋەبىدىن %s Counter بەك كونا Hash تېپىلمىدى E2E تېخى تەڭشەلمىدى تور ئۇلىنىشى مۇمكىن ئەمەس ئىمزا ماس كەلمەيدۇ + خام-ئۇچۇرنى تەكشۈرەلمىدى، ئىمزاسى يوق. ياردەمچى تېخىمۇ كۆپ تېخىمۇ كۆپ Nextcloud ئەپلىرى + ھۆججەت تاللىغۇچنى ئاچالمىدى ئېلېكترونلۇق خەت ئادرېسىنى تاللىيالمىدى. شىفىرلانغان قىلىپ تەڭشەڭ + مۇلازىمېتىر گۇۋاھنامىسىنى چۈشۈرەلمىدى + ئاممىۋى ئاچقۇچنى دەلىللىيەلمىدى مەخپىيلەشتۈرۈشنى تەڭشەڭ شىفىرلاش… تاقاش + ھۆججەتنى ئېچىش ئۈچۈن شىفىرىڭىزنى كىرگۈزۈڭ بۇ ھۆججەت قىسقۇچ قۇرۇق ئەمەس. يېڭى ئاچقۇچ ھاسىل قىلىش… 12 سۆزنىڭ ھەممىسى ناھايىتى كۈچلۈك مەخپىي نومۇر ھاسىل قىلىدۇ ، پەقەت شىفىرلانغان ھۆججەتلىرىڭىزنى كۆرەلەيسىز ۋە ئىشلىتەلەيسىز. ئۇنى يېزىپ بىخەتەر جايدا ساقلاڭ. @@ -326,8 +339,11 @@ 12 سۆز مەخپىيلەشتۈرۈش پارولىڭىزغا دىققەت قىلىڭ پارول… ئاچقۇچلارنى ئەسلىگە كەلتۈرۈش… + شەخسىي ئاچقۇچنى چۈشۈرەلمىدى + ئاممىۋىي ئاچقۇچنى چۈشۈرەلمىدى ئاچقۇچلارنى ساقلاش مەخپىيلەشتۈرۈشنى تەڭشەڭ + ئاچقۇچلارنى چۈشۈرىۋاتقاندا كۈتۈلمىگەن بىر خاتالىق يۈز بەردى كۇنۇپكىلارنى ساقلىيالمىدى ، قايتا سىناڭ. شىفىر يېگەندە خاتالىق. پارول خاتا؟ نىشان ھۆججەت نامىنى كىرگۈزۈڭ @@ -338,6 +354,7 @@ ئىنكاس ھۆججىتى %1$s چۈشۈپ كەتتى قېلىپتىن ھۆججەت قۇرۇشتا خاتالىق + ھەمبەھىرلىگۈچىلەرنى چۈشۈرەلمىدى. ھۆججەت ھەرىكىتىنى كۆرسىتىشتە خاتالىق ھۆججەت قۇلۇپ ھالىتىنى ئۆزگەرتىشتە خاتالىق دوكلات @@ -365,6 +382,7 @@ سىناق خىزمىتىنى توختىتىڭ كۆچۈش (ئەپ يېڭىلاش) مايىللىق + قۇرۇلۇش سىناق ھالىتى ھۆججەت يوللاش سىناق چۈشۈرۈشنى تەلەپ قىلىڭ سىناق يۈكلەش @@ -372,8 +390,10 @@ يۆتكەش چۈشۈرۈش يۈكلەش + بۇ يەرگە ھۆججەت چىقىرىش ياكى قۇرۇش ھوقۇقىڭىز يوق سىرتقى ھەمبەھىر قوشۇش ياكى يوللاش + زىددىيەت كۆزنىكى قۇرالمىدى باشقۇرغۇچىنى چۈشۈرۈش ئۈچۈن ھۆججەت يوللىيالمىدى ھۆججەت بېسىش مەغلۇب بولدى تەھرىرلىگۈچنى قوزغىتىش مەغلۇب بولدى @@ -385,8 +405,10 @@ ھۆججەت ئىسمى ئاللىبۇرۇن مەۋجۇت ئۆچۈرۈش ھۆججەت ئۈچۈن پائالىيەتلەرنى ئەسلىگە كەلتۈرۈشتە خاتالىق + سىز بىر ھەمبەھىر قۇرالمايسىز، ھەمبەھىرلەش بۇ ئىشلەتكۈچىدە ئاكتىپ. ئالاقىداشلارنى تاللاش ئۈچۈن بىرەر ئەپ يوق تەپسىلاتلارنى يۈكلىيەلمىدى + ئىختىيارى ئىجازەتنى تاللاڭ ھۆججەت ساقلاڭ بەزى مەزمۇنلارنى يۈكلەڭ ياكى ئۈسكۈنىڭىز بىلەن ماسقەدەملەڭ. @@ -404,13 +426,18 @@ سىز ئورتاقلاشقان ھۆججەت ۋە ھۆججەت قىسقۇچلار بۇ يەردە كۆرۈنىدۇ. ھازىرچە ھېچقانداق نەرسە ئورتاقلاشمىدى سوئالىڭىزغا ھېچقانداق نەتىجە تېپىلمىدى + ئىزدەشنى باشلاڭ + ئۈستىدىكى ئىزدەش بالدىقىغا يېزىپ ھۆججەتلەرنى، ئالاقىداشلارنى، يىلنامە پائالىيەتلىرىنى ھەمدە ھېساباتىڭىز ھەققىدە تېخىمۇ كۆپ نەرسىلەرنى ئىزدەڭ. + ئىنتىرنېت ئۇلىنىشىڭىزنى تەكشۈرۈڭ ياكى كىيىن قايتا سىناڭ + ناچار ئۇلىنىش ھۆججەت قىسقۇچ - LIVE - Loading… + نەق مەيدان + يۈكلەۋاتىدۇ… بۇ ھۆججەت تىپىنى بىر تەرەپ قىلىدىغان ھېچقانداق دېتال قۇرۇلمىغان. سېكۇنت بۇرۇن ساقلاش ئىجازەتنامىسى %1$s ساقلاشقا رۇخسەت قىلىش بىلەن ئەڭ ياخشى ئىشلەيدۇ. بارلىق ھۆججەتلەرنى تولۇق زىيارەت قىلالايسىز ياكى رەسىم ۋە سىنلارنى ئوقۇشقىلا بولىدۇ. + باشقا ئەپلەردىن كىرىشكە يول قوي مەنزىلنى تەكشۈرۈش… تازىلاش… سانلىق مەلۇمات ساقلاش قىسقۇچىنى يېڭىلاش @@ -421,6 +448,7 @@ مەنزىل ھۆججىتىگە يازالمىدى كۆچۈش جەريانىدا مەغلۇپ بولدى كۆرسەتكۈچ يېڭىلانمىدى + %1$s\n(%2$s / %3$s) سانلىق مەلۇمات يۆتكەش… تاماملاندى ئالماشتۇرۇڭ @@ -440,8 +468,11 @@ %s چەكلەنگەن ئىسىم %s. كۆچۈرۈش ياكى كۆچۈرۈشتىن بۇرۇن ھۆججەتنىڭ نامىنى ئۆزگەرتىڭ ھۆججەت تېپىلمىدى + ھۆججەت تېپىلمىدى. بىر ھەمبەھىر قۇرالمىدى. ھۆججەت ماسقەدەملەنمىدى. ئەڭ يېڭى نەشرىنى كۆرسىتىش. ئىسىم ئۆزگەرتىش + چىقىرىش مەغلۇپ بولدى. ئىنتىرنىت ئۇلىنىشى يوق. + %s ئاللىبۇرۇن مەۋجۇت، زىددىيەت بايقالمىدى ھۆججەت نەشرىنى ئەسلىگە كەلتۈرۈشتە خاتالىق! تەپسىلاتى چۈشۈر @@ -458,7 +489,13 @@ ئىشلىتىشكە قولايلىق بولغان تور خەت ساندۇقى ، كالېندار ۋە ئالاقىداشلار ئېكران ئورتاقلىشىش ، تور يىغىنلىرى ۋە تور يىغىنلىرى ھۆججەت قىسقۇچ مەۋجۇت + بۇ قىسقۇچنى %1$s دا ياخشى ئاچقىلى بۇلىدۇ قۇر + %2$d دىن %1$d · %3$s + %s قىسقۇچىنى ماس-قەدەملەۋاتقاندا بىر خاتالىق يۈز بەردى + دېسكا بوشلۇقى يىتەرسىز، ماس-قەدەملەش ئەمەلدىن قالدۇرۇلدى + %s قىسقۇچ مۇۋاپىقىيەتلىك ماس-قەدەملەندى + ماس-قەدەملەۋاتىدۇ... بۇ يەردە ھۆججەت قىسقۇچ يوق ھۆججەت قىسقۇچنىڭ ئىسمى قۇرۇق بولمايدۇ تاللاڭ @@ -515,6 +552,7 @@ ئاخىرقى زاپاسلاش:%1$s ئۇلىنىش ئۇلىنىش ئىسمى + بىخەتەرلىك تەڭشىكى سەۋەبىدىن ئۇلىنىشقا ئەگىشىلمىدى. تەھرىرلەش تىزىملىكتىكى ئورۇنلاشتۇرۇش تېخىمۇ كۆپ نەتىجىلەرنى يۈكلەڭ @@ -573,7 +611,8 @@ يېڭى باھا… يېڭى%1$s مېدىيا ھۆججەت قىسقۇچى بايقالدى. سۈرەت - video + سىن + يېڭى ئۇقتۇرۇش يېڭى نەشرى قۇرۇلدى بۇ ئىشلەتكۈچى ئۈچۈن ھېچقانداق ھەرىكەت يوق ئۇلىنىشنى بىر تەرەپ قىلىدىغان ئەپ يوق @@ -589,6 +628,9 @@ سىنبەلگە ھەرىكەتنى ئىجرا قىلالمىدى. ئارقا كۆرۈنۈش مەشغۇلاتىنىڭ ئۆز-ئارا تەسىر كۆرسىتىدىغان ئۇقتۇرۇشىنى كۆرسىتىڭ + ئارقا سۇپىدىكى خىزمەت + يەرلىك ھۆججەت ئۆزگەرتىشلەرنى بايقايدۇ + مەزمۇن كۆزەتكۈچى چۈشۈرۈشنىڭ ئىلگىرىلىشىنى كۆرسىتىدۇ چۈشۈرۈش ھۆججەت ماسقەدەملەش جەريانى ۋە نەتىجىسىنى كۆرسىتىدۇ @@ -596,7 +638,9 @@ يېڭى مېدىيا قىسقۇچلىرى ۋە شۇنىڭغا ئوخشاشلارغا ئۇقتۇرۇش قىلىڭ ئومۇمىي ئۇقتۇرۇش مۇزىكا قويغۇچنىڭ ئىلگىرىلىشى - Media player + مىدىيا قوي + تورسىز ھۆججەت مەشخۇلاتلىرىنىڭ ئىلگىرلىشىنى كۆرسەت + تورسىز مەشخۇلاتلار مۇلازىمېتىر ئەۋەتكەن ئىتتىرىش ئۇقتۇرۇشىنى كۆرسىتىش: باھادىكى ئەسكەرتىش ، يېڭى يىراقتىكى پايلارنى قوبۇل قىلىش ، باشقۇرغۇچى يوللىغان ئېلان قاتارلىقلار. ئىتتىرىش ئۇقتۇرۇشى يوللاشنىڭ ئىلگىرىلىشىنى كۆرسىتىدۇ @@ -605,17 +649,28 @@ ئوقۇلمىغان ئۇقتۇرۇشلار مەۋجۇت ئۇقتۇرۇش يوق كېيىن قايتا تەكشۈرۈپ بېقىڭ. + ساقلاۋاتقان مەشخۇلات + ساقلاۋاتقان ئۆچۈرۈش مەشخۇلاتى تور ئۇلىنىشى يوق تورغا ئۇلانمىسىڭىزمۇ ھۆججەت قىسقۇچلىرىڭىزنى رەتلىيەلەيسىز ، ھۆججەت قۇرالايسىز. تورغا قايتىپ كەلگەندىن كېيىن ، ساقلاۋاتقان ھەرىكەتلىرىڭىز ئاپتوماتىك ماسقەدەملىنىدۇ. + سىز توردا ئەمەس، لىكىن خىزمەت داۋاملىشىدۇ + ھۆججەت تېخى مەۋجۇت ئەمەس، ئاۋال ھۆججەتنى چىقىرىڭ. + %s قۇرغىلى بولمىدى. مۇلازىمېتىردا ئوخشاش ئىسىمدىكى ھۆججەت مەۋجۇت. + %s نى قۇرغىلى بولمىدى. مۇلازىمېتىردا ئوخشاش ئىسىمدىكى قىسقۇچ مەۋجۇت. تورسىز مەشغۇلاتنى تاماملىغىلى بولمايدۇ. %s تورسىز مەشغۇلات + %s نىڭ ئۆچۈرۈلىشى ئەمەلدىن قالدى. ھۆججەت مۇلازىمېتىردا ئۆزگەرتىلدى. + %s نىڭ ئىسمىنى ئۆزگەرتىش ئەمەلدىن قالدى. مۇلازىمېتىردا ئوخشاش ئىسىمدىكى ھۆججەت مەۋجۇت. + تورسىز مەشغۇلاتنى باشلاۋاتىدۇ 1 سائەت توردا توردىكى ئورنى + %1$s دا ئاچ مۇلازىمېتىر ئۆمرىنىڭ ئاخىرىغا يەتتى ، يېڭىلاڭ! تېخىمۇ كۆپ تىزىملىك مەخپىي نومۇرىڭىزنى كىرگۈزۈڭ مەخپىي نومۇرىڭىزنى كىرگۈزۈڭ + شىفىر بۇ ئەپنى ئاچقاندا ياكى 5 سىكۇنتتىن كىيىن قايتا ئاچقاندا تەلەپ قىلىنىدۇ. مەخپىي نومۇر ئوخشاش بولمايدۇ پارولىڭىزنى قايتا كىرگۈزۈڭ پارولىڭىزنى ئۆچۈرۈڭ @@ -626,10 +681,12 @@ پارول بىلەن قوغدالغان PDF نى ئاچقىلى بولمايدۇ. سىرتقى PDF كۆرگۈچنى ئىشلىتىڭ. رۇخسەت قىلىڭ رەت قىلىش + ھەمبەھىرلەيدىغان ئالاقىداش تاللا رەسىم ئورنىتىدىغان ھېچقانداق دېتال تېپىلمىدى + باش ئېكرانغا مىخلا %1$s نى ئېچىڭ توختا - toggle + ئالماشتۇر مۇلازىمېتىرنى تاللاڭ… توك تېجەش تەكشۈرۈشىنى چەكلىگەندە ، باتارېيە تۆۋەن ھالەتتە ھۆججەت يوللاشنى كەلتۈرۈپ چىقىرىشى مۇمكىن! ئۆچۈرۈلدى @@ -642,8 +699,11 @@ يېڭى نەشرىگە ئۆزگەرتىش ئەگەر ھۆججەت مەۋجۇت بولسا قانداق قىلىش كېرەك؟ ھېسابات قوشۇڭ + بۇ ئەپنىڭ ئۈسكۈنىڭىزدىكى بارلىق ھۆججەتلەرنى ئىشلىتىشكە رۇخسەت قىل + بارلىق ھۆججەتنى ئىشلىتىش كالېندار ۋە ئالاقىداش F-Droid ياكى Google Play ئورنىتىلمىغان + نۆۋەتتىكى ھېسابات ئۈچۈن DAVx5 (ئىلگىرى DAVdroid دەپ ئاتالغان) (v1.3.0 +) نى تەڭشەڭ كالېندار ۋە ئالاقىداش ماسقەدەملەندى ھەققىدە تەپسىلاتى @@ -654,6 +714,9 @@ ماسقەدەملەش كالېندارىڭىز ۋە ئالاقىداشلىرىڭىزنىڭ كۈندىلىك زاپاسلىنىشى ئالاقىلىرىڭىزنىڭ كۈندىلىك زاپاسلىنىشى + سانلىق مەلۇمات ساقلاش ئورنى + سانلىق مەلۇمات ساقلاش ئورنىنى باشقۇرۇش + DAVx5 نى تەڭشىگەندە كۈتۈلمىگەن خاتالىق (ئىلگىرى DAVdroid دەپ ئاتالغان) ئاخىرىغىچە مەخپىيلەشتۈرۈش قۇرۇلدى! E2E mnemonic مونونىكنى كۆرسىتىش ئۈچۈن ئۈسكۈنىنىڭ سالاھىيىتىنى قوزغىتىڭ. @@ -661,7 +724,7 @@ يېڭىدىن تېپىلغان مېدىيا قىسقۇچلىرى ھەققىدە خەۋەر قىلىڭ GNU ئادەتتىكى ئاممىۋى ئىجازەتنامە ، 2-نەشرى ياردەم - Imprint + بارماق بېسىش ئەسلى ھۆججەت… ئەسلى ھۆججەت… يوشۇرۇن ھۆججەت ۋە ھۆججەت قىسقۇچلارنى چىقىرىۋېتىڭ @@ -690,7 +753,9 @@ يەرلىك ھۆججەت قىسقۇچ يىراقتىن قىسقۇچ باشتېما + ئىنتىرۋال ئىككى خىل ماسقەدەملەش ئۈچۈن ئىچكى قىسقۇچلارنى باشقۇرۇڭ + ئىككى يۆنىلىشلىك ماس-قەدەملەشنى قوزغات قاراڭغۇ نۇر سىستېمىغا ئەگىشىڭ @@ -714,7 +779,7 @@ تەۋسىيە قىلىنغان ھۆججەتلەر مەزمۇننى يېڭىلاش قايتا يۈكلەڭ - (remote) + (يىراق) ھۆججەت تاپالمىدى! سىز بۇ خېرىداردا يەرلىكتىن ئاخىرىغىچە مەخپىيلەشتۈرۈشنى ئۆچۈرەلەيسىز بۇ خېرىداردا يەرلىكتىن ئاخىرىغىچە مەخپىيلەشتۈرۈشنى ئۆچۈرەلەيسىز. شىفىرلانغان ھۆججەتلەر مۇلازىمېتىردا قالىدۇ ، ئەمما بۇ كومپيۇتېرغا ئەمدى ماسقەدەملەنمەيدۇ. @@ -752,21 +817,30 @@ ئاپتوماتىك يوللاش رەسىم ۋە سىنلىرىڭىز ئۈچۈن كالېندار ۋە ئالاقىداشلار + DAVx5 بىلەن ماسقەدەملەش ئىزدەش نەتىجىسىگە ئېرىشىشتە خاتالىق بۇ ئىشلەتكۈچى ئۈچۈن بىخەتەر ئورتاقلىشىش ئورنىتىلمىغان + بىخەتەر ئورتاقلىشىش… ھەممىنى تاللاڭ مېدىيا قىسقۇچىنى تەڭشەڭ بىر قېلىپنى تاللاڭ قېلىپنى تاللاڭ ئەۋەتىڭ + ھەمبەھىر ئەۋەتىش كۇنۇپكا سىنبەلگىسىنى ئەۋەتىڭ + مەزمۇننى يۈكلىيەلمىدى + بۇ ئۈسكۈنە ئىنتىرنېتقا ئۇلانمىغاندەك تۇرىدۇ تەڭشەك + چۈشۈرۈش چىكىنى بېكىتەلمىدى. ئىقتىدارىنى تەكشۈرۈڭ. ئۇچۇر بەلگىلە - توردىكى ئورنى + خاتىرىنى بېكىت + توردىكى ھالىتى رەسىمنى ئىشلىتىڭ ئاخىرىدىن ئاخىرىغىچە مەخپىيلەشتۈرۈشنى تەڭشەش جەريانىدا ، ئىختىيارى 12 سۆزلۈك mnemonic تاپشۇرۇۋالىسىز ، بۇ ھۆججەتلەرنى باشقا ئۈسكۈنىلەردە ئېچىشىڭىز كېرەك. بۇ پەقەت بۇ ئۈسكۈنىدە ساقلىنىدۇ ، بۇ ئېكراندا قايتا كۆرسەتكىلى بولىدۇ. ئۇنى بىخەتەر ئورۇنغا خاتىرىلەڭ! ھەمبەھىرلەش چۈشۈرۈش ۋە ماسقەدەملەشكە يول قويۇڭ + سىز بۇ ھەمبەھىرنى يېڭىلىيالمايسىز. بىر خاتىرە قۇشۇپ قايتا سىناپ بېقىڭ. + ھەمبەھىرلە ھەمدە ئۇلىنىشنى كۆچۈر قۇر ئىختىيارى ئىجازەت ئۆچۈر @@ -791,24 +865,27 @@ ۋاقتى توشىدۇ پارول بەلگىلەڭ بىخەتەر ھۆججەت چۈشۈرۈش جەريانىدا قايتا ئىشلىتىشكە بولمايدۇ + داۋاملاشتۇرۇشتىن بۇرۇن ئەڭ كەمدە بىر ئورتاقلىشىش تاللانمىسىنى تاللاڭ. تەھرىرلىيەلەيدۇ ھۆججەت تەلىپى بىخەتەر ھۆججەت چۈشۈرۈش پەقەت كۆرۈش + ھەمبەھىرلەش ئىجازەتلىرى ھەمبەھىرلەش ئوقۇ %1$s (يىراق) %1$s (سۆھبەت) ئىسمى ، فېدېراتسىيە بۇلۇت كىملىكى ياكى ئېلخەت ئادرېسى… + ئىشلەتكۈچىلەر ھەمدە ئەتىرەتلەرنى قوش يېڭى ئېلېكترونلۇق خەت ئەۋەتىڭ تاپشۇرۇۋالغۇچىغا دىققەت قىلىڭ تەڭشەك چۈشۈرۈشنى يوشۇرۇش ئۇلىنىشنى ھەمبەھىرلەش ئۇلىنىش ئەۋەتىڭ - Unset + ئورناتما ئورتاق ئىشلەتكۈچىلەرنىڭ ئاۋاتلىقى - share + ھەمبەھىر ئورتاقلاشتى ئۇلىنىش ئارقىلىق ھەمبەھىرلەندى %1$s بىلەن ئورتاقلاشتى @@ -818,6 +895,7 @@ رەسىملەرنى كۆرسەت ئازراق كۆرسەت سىنلارنى كۆرسەت + مۇلازىمەت ماددىلىرىنى قولدا تەكشۈرۈڭ! تەمىنلىگۈچى بىلەن تىزىملىتىڭ %1$s نىڭ Nextcloud ھېساباتىڭىزنى زىيارەت قىلىشىغا يول قويۇڭ%2$s? تەرتىپلەش @@ -839,7 +917,7 @@ تارقىتىلغان: ئىناۋەتلىكلىكى: دىن: - To: + غا: - خاتالىق توغرىسىدا ھېچقانداق ئۇچۇر يوق گۇۋاھنامە ساقلىيالمىدى گۇۋاھنامە كۆرسىتىلمىدى. @@ -858,12 +936,17 @@ ئىچكى ساقلىغۇچ كىنولار مۇزىكا + بارلىق ھۆججەتنى ئىشلىتىش + ھۆججەت چىقىرىش ئۈچۈن ساقلاش ئىجازىتى تەلەپ قىلىنىدۇ. + ئاپتۇماتىك چىقىرىش ئۈچۈن ساقلاش ئىجازىتى تەلەپ قىلىنىدۇ. + سورىما مېدىيا ئوقۇشقىلا بولىدۇ رەسىملەر + ئۆزىڭىز باشقۇرىدىغان ئىشلەپچىقىرىش ئىقتىدارى سۇپىسى سىزنى كونترول قىلالايدۇ.\n\n ئالاھىدىلىكلىرى:\n* ئاسان، زامانىۋى كۆرۈنمە يۈزى، مۇلازىمېتىرىڭىزنىڭ تېمىسىغا ماس كېلىدۇ\n* ھۆججەتلەرنى Nextcloud مۇلازىمېتىرىڭىزغا يۈكلەش\n* باشقىلار بىلەن ئورتاقلىشىش\n* ياقتۇرىدىغان ھۆججەت ۋە قىسقۇچلىرىڭىزنى ماسلاشتۇرۇڭ\n* مۇلازىمېتىرىڭىزدىكى بارلىق قىسقۇچلارنى ئىزدەش\n* ئۈسكۈنىڭىز تارتقان رەسىم ۋە سىنلارنى ئاپتوماتىك يۈكلەش\n* ئۇقتۇرۇشلار بىلەن يېڭى ئۇچۇرلارنى ساقلاڭ\n* كۆپ ھېسابات قوللاش\n* بارماق ئىزى ياكى PIN ئارقىلىق سانلىق مەلۇماتلىرىڭىزغا بىخەتەر كىرىش\n* كالېندار ۋە ئالاقىلىشىشلارنى ماسلاشتۇرۇشنى ئاسانلاشتۇرۇش ئۈچۈن DAVx⁵ (ئىلگىرى DAVdroid دەپ ئاتالغان) بىلەن بىرلەشتۈرۈش\n\n بارلىق مەسىلىلەرنى https://github.com/nextcloud/android/issues دا دوكلات قىلىڭ ۋە بۇ ئەپنى https://help.nextcloud.com/c/clients/android دا مۇزاكىرە قىلىڭ\n\nNextcloud غا يېڭى كەلدىڭىزمۇ؟ Nextcloud شەخسىي ھۆججەت ماسلاشتۇرۇش ۋە ئورتاقلىشىش ۋە ئالاقە مۇلازىمېتىرى. ئۇ ھەقسىز يۇمشاق دېتال بولۇپ، ئۇنى ئۆزىڭىز ساقلىيالايسىز ياكى شىركەتكە پۇل تۆلەپ قىلالايسىز. بۇ ئۇسۇل ئارقىلىق، سىز رەسىملىرىڭىزنى، كالېندارىڭىزنى ۋە ئالاقە ئۇچۇرلىرىڭىزنى، ھۆججەتلىرىڭىزنى ۋە باشقا ھەممە نەرسىنى كونترول قىلالايسىز.\n\nNextcloud نى https://nextcloud.com دىن كۆرۈڭ. ئۆزى كونترول قىلىدىغان ئىشلەپچىقىرىش سۇپىسى سىزنى كونترول قىلىدۇ. \ N بۇ رەسمىي تەرەققىيات نۇسخىسى بولۇپ ، ھەر كۈنى يېڭى سىناقتىن ئۆتمىگەن ئىقتىدارلارنىڭ ئەۋرىشكىسى بار ، بۇ مۇقىمسىزلىق ۋە سانلىق مەلۇماتلارنىڭ يوقىلىشىنى كەلتۈرۈپ چىقىرىشى مۇمكىن. بۇ ئەپ سىناق قىلىشنى خالايدىغان ئىشلەتكۈچىلەر ئۈچۈن بولۇپ ، خاتالىق كۆرۈلسە دوكلات قىلىدۇ. ئۇنى ئىشلەپچىقىرىش خىزمىتىڭىزگە ئىشلەتمەڭ! \ N \ n ھەر ئىككىلىسى رەسمىي dev ۋە دائىملىق نۇسخىسى F-droid دا بار ، بىرلا ۋاقىتتا ئورنىتىشقا بولىدۇ. ئۆزىڭىزنى كونترول قىلىدىغان ئۆزى ساھىبخانلىق ئىشلەپچىقىرىش سۇپىسى سىزنى كونترول قىلىدىغان ئۆزى ساھىبخانلىق قىلغان ئىشلەپچىقىرىش سۇپىسى (dev ئالدىن كۆرۈش نۇسخىسى) - Stream with… + بىلەن يەتكۈز... ئىچكى ئېقىم مۇمكىن ئەمەس ئۇنىڭ ئورنىغا مېدىيا چۈشۈرۈڭ ياكى سىرتقى ئەپنى ئىشلىتىڭ. يىل / ئاي / كۈن @@ -876,8 +959,10 @@ پەقەت سىنلار تەكلىپ ماسقەدەملەش + يەنىلا ماس-قەدەملە توقۇنۇشلار بايقالدى %1$s ھۆججەت قىسقۇچى ئەمدى مەۋجۇت ئەمەس + كۆپەيتىلگەن ماس-قەدەملەش %1$s نى ماسقەدەملىيەلمىدى %1$s نىڭ مەخپىي نومۇرى خاتا ماس قەدەملىك ھۆججەتلەر مەغلۇپ بولدى @@ -885,7 +970,7 @@ ماسقەدەملەش مەغلۇپ بولدى ، قايتا كىرىڭ ھۆججەت مەزمۇنى ماسقەدەملەندى %1$s ھۆججەت قىسقۇچنى ماسقەدەملەش تاماملانمىدى - 1.3.16 نەشرىگە قەدەر ، بۇ ئۈسكۈنىدىن يۈكلەنگەن ھۆججەتلەر يەرلىك%1$s ھۆججەت قىسقۇچىغا كۆچۈرۈلۈپ ، بىر ھۆججەت كۆپ ھېسابات بىلەن ماس قەدەمدە سانلىق مەلۇمات يوقاپ كېتىشنىڭ ئالدىنى ئالىدۇ. \ N \ n بۇ ئۆزگىرىش سەۋەبىدىن ، بارلىق ھۆججەتلەر ئىلگىرىكى نەشرىگە يۈكلەنگەن. بۇ دېتالنىڭ%2$s ھۆججەت قىسقۇچىغا كۆچۈرۈلگەن. قانداقلا بولمىسۇن ، خاتالىق ھېسابات ماسقەدەملەش جەريانىدا بۇ مەشغۇلاتنىڭ تاماملىنىشىنىڭ ئالدىنى ئالدى. سىز ھۆججەتلەرنى (لار) نى تاشلاپ قويۇپ ، ئۇلىنىشنى%3$s غا ئۆچۈرەلەيسىز ياكى ھۆججەت (لەر) نى%1$s ھۆججەت قىسقۇچىغا يۆتكىسىڭىز ھەمدە ئۇلىنىشنى%4$s غا ساقلاپ قويسىڭىز بولىدۇ. \ N \ n تۆۋەندە كۆرسىتىلگەن يەرلىك ھۆججەت (لار) بولۇپ ، ئۇلانغان%5$s دىكى يىراقتىكى ھۆججەتلەر. + 1.3.16 نەشرىدىن باشلاپ، بۇ ئۈسكۈنىدىن يۈكلەنگەن ھۆججەتلەر يەرلىك %1$s قىسقۇچقا كۆچۈرۈلىدۇ، بۇ بىرلا ھۆججەت كۆپ ھېسابات بىلەن ماسلاشتۇرۇلغاندا سانلىق مەلۇمات يوقىلىپ كېتىشىنىڭ ئالدىنى ئالىدۇ.\n\nبۇ ئۆزگىرىش سەۋەبىدىن، بۇ ئەپنىڭ ئىلگىرىكى نەشرى بىلەن يۈكلەنگەن بارلىق ھۆججەتلەر %2$s قىسقۇچقا كۆچۈرۈلدى. قانداقلا بولمىسۇن، ھېسابات ماسلاشتۇرۇلغاندا خاتالىق سەۋەبىدىن بۇ مەشغۇلات تاماملانمىدى. ھۆججەت(لەر)نى شۇ ھالىتىدە قالدۇرۇپ، %3$s غا ئۇلىنىشنى ئۆچۈرۈۋەتسىڭىز ياكى ھۆججەت(لەر)نى %1$s قىسقۇچقا يۆتكەپ، ئۇلىنىشنى %4$s غا ساقلىسىڭىز بولىدۇ.\n\nتۆۋەندە ئۇلار ئۇلانغان %5$s دىكى يەرلىك ھۆججەت(لەر) ۋە يىراقتىكى ھۆججەت(لەر) كۆرسىتىلدى. بەزى يەرلىك ھۆججەتلەر ئۇنتۇلدى ھۆججەتنىڭ ئەڭ يېڭى نەشرىنى ئېلىش. ماسقەدەملەشنى تاللاڭ @@ -894,6 +979,7 @@ يېتەرلىك بوشلۇق يوق ماسقەدەملەش ھالىتى كۇنۇپكىسى ھۆججەتلەر + ماس-قەدەملەشنى ئاگاھلاندۇرۇش كۇنۇپكىسى تەڭشەك كۇنۇپكىسى قىسقۇچلارنى سەپلەڭ دەرھال يوللاش پۈتۈنلەي يېڭىلاندى. ئاپتوماتىك يوللاشنى ئاساسىي تىزىملىكنىڭ ئىچىدىن قايتا تەڭشەڭ. \ N \ n يېڭى ۋە كېڭەيتىلگەن ئاپتوماتىك يوللاشتىن ھۇزۇرلىنىڭ. @@ -903,10 +989,11 @@ ماسقەدەملەندى خەتكۈچ مۇلازىمەت شەرتلىرى + مەن ئۈستىدىكى ئ ك غا قۇشۇلىمەن مۇلازىمېتىر ئۇلىنىشىنى سىناش 30 مىنۇت بۇ ھەپتە - Thumbnail + باش-سۈرەت مەۋجۇت ھۆججەتنىڭ كىچىك كۆرۈنۈشى يېڭى ھۆججەتنىڭ كىچىك كۆرۈنۈشى يۈكلەش مۆلچەردىكىدىن ئۇزۇنراق @@ -927,6 +1014,7 @@ ھادىسە تېپىلمىدى ، يېڭىلاش ئۈچۈن ھەمىشە ماسقەدەملىيەلەيسىز. تورغا قايتا يۆنىلىش… ئالاقىلىشىش تېپىلمىدى ، يېڭىلاش ئۈچۈن ھەمىشە ماسقەدەملىيەلەيسىز. تورغا قايتا يۆنىلىش… ئىزدەش نەتىجىسىنى ئېچىشقا ئىجازەت تەلەپ قىلىنىدۇ ، بولمىسا ئۇ تورغا ئۇلىنىدۇ. + بۇ قىسقۇچتا نامەلۇم ھۆججەتنى ئېچىش ئوقۇلمىغان ئىنكاسلار مەۋجۇت @@ -955,7 +1043,7 @@ سۈرەت رەسىم ياكى سىن ئالماقچىمۇ؟ كامېرادىن يۈكلەڭ - Video + سىن ھۆججەت ئىسمى ھۆججەت شەكلى Google خەرىتە تېزلەتمە ھۆججىتى (%s) @@ -975,6 +1063,10 @@ ھۆججەتنى يەرلىك ساقلاشقا كۆچۈرگىلى بولمايدۇ ھۆججەت قىسقۇچنى قۇلۇپلاش مەغلۇب بولدى ئىشلەتكۈچى يوللاش ئەمەلدىن قالدۇرۇلدى + بارلىق ھۆججەتكە كىرىشكە يول قوي + ئەپ رۇخسىتى + ھۆججىتىڭىزنى يەرلىك ساقلىغۇچقا كىرمەي تۇرۇپ چىقارغىلى بولمايدۇ. رۇخسەت بېرىش ئۈچۈن چىكىڭ. + چىقىرىش توختىدى – ساقالاش رۇخسىتى كېرەك %1$d d /%2$d d -%3$s شىفىرلاش پەقەت> = Android 5.0 بىلەنلا مۇمكىن بوشلۇق يېتەرلىك بولمىسا تاللانغان ھۆججەتلەرنى%1$s ھۆججەت قىسقۇچىغا كۆچۈرۈپ كېتىشنىڭ ئالدىنى ئالىدۇ. ئۇلارنىڭ ئورنىغا ئۇلارنى يۆتكىمەكچىمۇ؟ @@ -1029,6 +1121,8 @@ ئىشەنچسىز مۇلازىمېتىر گۇۋاھنامىسى مۇلازىمېتىر نۇسخىسىنى ئېلىش… ئەپ ئاخىرلاشتى + ئاتلا + ئوخشاش ئىسىمدىكى ھۆججەت ئاللىبۇرۇن مەۋجۇت تاماملاندى يىراقتىن تېپىلغان ئوخشاش ھۆججەت يوچۇن خاتالىق @@ -1051,10 +1145,12 @@ سەل ساقلاپ تۇرۇڭ… ساقلانغان كىنىشكىنى تەكشۈرۈش شەخسىي ساقلاشتىن ھۆججەت كۆچۈرۈش + كېڭەيتىلمىسىنى ئۆزگەرتىش بۇ ھۆججەتنىڭ باشقا بىر ئەپتە ئېچىلىشىنى كەلتۈرۈپ چىقىرىدۇ يېڭى رەسىم ئاتلاش %1$s دىكى يېڭى ئەھۋالىڭىز نېمە؟ + كىچىك قوراللار پەقەت %1$s 25 دە ياكى ئۇنىڭدىن يۇقىرسىدا باشتاختىدا قوزغىتىلغاندا ئېرىشكىلى بۇلىدۇ ئىشلەتكىلى بولمايدۇ ھۆججەتلەرنى چۈشۈرۈش… ئېلېكترونلۇق خەت ئەۋەتىڭ @@ -1068,6 +1164,10 @@ %d مىنۇت %d مىنۇت + + %d سىكۇنت بۇرۇن + %d سىكۇنت بۇرۇن + %d مىنۇت ئىلگىرى %d مىنۇت ئىلگىرى @@ -1077,60 +1177,80 @@ %d سائەت ئىلگىرى - Could not sync %1$d file (conflicts: %2$d) - Could not sync %1$d files (conflicts: %2$d) + %1$d ھۆججەتنى ماس-قەدەملىگىلى بولمىدى (زىددىيەتلەر: %2$d) + %1$d ھۆججەتلەرنى ماس-قەدەملىگىلى بولمىدى (زىددىيەتلەر: %2$d) - Failed to copy %1$d file from the %2$s folder into - Failed to copy %1$d files from the %2$s folder into + %2$s دىن %1$d ھۆججەتنى كۆچۈرۈش مەغلۇپ بولدى + %2$s دىن %1$d ھۆججەتنى كۆچۈرۈش مەغلۇپ بولدى - Wrote %1$d event to %2$s - Wrote %1$d events to %2$s + %2$s غا %1$d پائالىيەت يازدى + %2$s غا %1$d پائالىيەت يازدى - Created %1$d fresh UID - Created %1$d fresh UIDs + يېڭى %1$d UID قۇرۇلدى + يېڭى %1$d UID قۇرۇلدى - Processed %d entry. - Processed %d entries. + %d تۈرنى بىر-تەرەپ قىلدى. + %d تۈرنى بىر-تەرەپ قىلدى. - Found %d duplicate entry. - Found %d duplicate entries. + كۆپەيتىلگەن %d تۈر تېپىلدى. + كۆپەيتىلگەن %d تۈر تېپىلدى. - Exported %d file - Exported %d files + %d ھۆججەت چىقىرىلدى + %d ھۆججەت چىقىرىلدى - Failed to export %d file - Failed to export %d files + %d ھۆججەتنى چىقىرىش مەغلۇپ بولدى + %d ھۆججەتنى چىقىرىش مەغلۇپ بولدى - Exported %d file, skipped rest due to error - Exported %d files, skipped rest due to error + %d ھۆججەت چىقىرىلدى، قالغانلىرى خاتالىق سەۋەبىدىن ئاتلاندى + %d ھۆججەت چىقىرىلدى، قالغانلىرى خاتالىق سەۋەبىدىن ئاتلاندى + + + سىز بىر قېتىمدا %d ھۆججەت چىقىرالايسىز. + سىز بىر قېتىمدا %d ھۆججەت چىقىرالايسىز. - %1$d folder - %1$d folders + %1$d قىسقۇچ + %1$d قىسقۇچ - %1$d file - %1$d files + %1$d ھۆججەت + %1$d ھۆججەت %1$d تۈر %1$d تۈرلەر - Show %1$d hidden folder - Show %1$d hidden folders + يۇشۇرۇن %1$d قىسقۇچنى كۆرسەت + يۇشۇرۇن %1$d قىسقۇچنى كۆرسەت - %d selected - %d selected + %d تاللاندى + %d تاللاندى + + + بەك كۆپ خاتا ئۇرۇنۇش سەۋەبىدىن %d سىكۇنت كېچىكتۈرۈلدى + بەك كۆپ خاتا ئۇرۇنۇش سەۋەبىدىن %d سىكۇنت كېچىكتۈرۈلدى + + + بەك كۆپ خاتا ئۇرۇنۇش سەۋەبىدىن %d مىنۇت كېچىكتۈرۈلدى + بەك كۆپ خاتا ئۇرۇنۇش سەۋەبىدىن %d مىنۇت كېچىكتۈرۈلدى + + + %d مىنۇت كېچىكتۈرۈلدى + %d مىنۇت كېچىكتۈرۈلدى + + + %d سېكۇنت + %d سېكۇنت %1$d چۈشۈرۈش قالدى From 02dd88f953df3bc54cfe840c86abcc07a82d3320 Mon Sep 17 00:00:00 2001 From: Nextcloud bot Date: Mon, 8 Dec 2025 02:44:49 +0000 Subject: [PATCH 007/216] fix(l10n): Update translations from Transifex Signed-off-by: Nextcloud bot --- app/src/main/res/values-cs-rCZ/strings.xml | 12 ++++++++++++ app/src/main/res/values-de/strings.xml | 2 +- app/src/main/res/values-it/strings.xml | 1 + 3 files changed, 14 insertions(+), 1 deletion(-) diff --git a/app/src/main/res/values-cs-rCZ/strings.xml b/app/src/main/res/values-cs-rCZ/strings.xml index 61cf6ad18d4c..8f8c989ee1ee 100644 --- a/app/src/main/res/values-cs-rCZ/strings.xml +++ b/app/src/main/res/values-cs-rCZ/strings.xml @@ -60,6 +60,7 @@ Asistent Vstup Výstup + Přemýšlení... Související účet nenalezen! Přístup se nezdařil: %1$s Účet zatím není na tomto zařízení přidán @@ -124,6 +125,7 @@ Zaneprázdněn(a) Kalendář Kalendáře + Zrušit Došlo k problému s načtením certifikátu. Seznam změn ve vývojářské verzi Vraťte se sem později nebo načtěte znovu. @@ -208,8 +210,12 @@ Nenalezen žádný soubor Nepodařilo se najít vaši nejaktuálnější zálohu! Zjišťování změn obsahu + Vytváření konverzace selhalo + Odstranit konverzaci + Odstranění konverzace selhalo Nenalezena žádná konverzace Zatím žádná konverzace + Získání seznamu konverzace selhalo Konverzace Zkopírováno Při pokusu o zkopírování tohoto souboru či složky došlo k chybě @@ -311,9 +317,11 @@ Šifrování mezi koncovými body doposud není nastavené Není možné bez připojení k Internetu Signatura se neshoduje + Nebylo možné ověřit metadata, podpis je prázdný. Asistent Další Další Nextcloud aplikace + Nelze otevřít výběr souborů Nepodařilo se vybrat e-mailovou adresu. Nastavit jako šifrované Nedaří se získat certifikát serveru @@ -666,6 +674,7 @@ Bezpečnostní kód smazán Bezpečnostní kód uložen Nesprávný bezpečnostní kód + Pozastavit Nedaří se otevřít heslem chráněné PDF. Použijte externí prohlížeč PDF. Povolit Odepřít @@ -922,6 +931,9 @@ Vnitřní úložiště Videa Hudba + Oprávnění úložiště je nutné pro automatické nahrávání. + Oprávnění úložiště je nutné pro nahrávání souborů. + Neptat se Média pouze pro čtení Obrázky Platforma pro produktivitu hostovaná u vás, kde vaše data jsou opravdu vaše.\nToto je oficiální vývojová verze, sloužící jako denně aktualizovaná ukázka nových nevyzkoušených funkcí, což může způsobovat nestabilitu a ztráty dat. Je určeno pro uživatele, kteří jsou ochotní testovat a hlásit chyby na které narazí. Nepoužívejte pro svou produktivní práci!\n\nJak vývojová tak produkční verze jsou k dispozici na F-droid a mohou být nainstalovány souběžně. diff --git a/app/src/main/res/values-de/strings.xml b/app/src/main/res/values-de/strings.xml index 0f3247e6f314..63e97d1a9c78 100644 --- a/app/src/main/res/values-de/strings.xml +++ b/app/src/main/res/values-de/strings.xml @@ -748,7 +748,7 @@ App-Umschalter anzeigen Nextcloud-App-Vorschläge in der Navigationsüberschrift Versteckte Dateien anzeigen - Zum Programmcode + Zum Quellcode Ordner für \"Automatisches Hochladen\" verwalten Lokaler Ordner Remote-Ordner diff --git a/app/src/main/res/values-it/strings.xml b/app/src/main/res/values-it/strings.xml index 5e4596adb5c3..df660f6a2ade 100644 --- a/app/src/main/res/values-it/strings.xml +++ b/app/src/main/res/values-it/strings.xml @@ -10,6 +10,7 @@ Modifica Cancella tutte le notifiche Svuota cestino + Invia/Condividi Vista Griglia Vista Elenco Ripristina contatti e calendario From 0a0f89a04d349b3257791a63e8d6c2f5a679a3e2 Mon Sep 17 00:00:00 2001 From: alperozturk Date: Mon, 8 Dec 2025 08:22:45 +0100 Subject: [PATCH 008/216] fix: event bus drawer activity Signed-off-by: alperozturk --- .../owncloud/android/ui/activity/DrawerActivity.java | 12 ++---------- 1 file changed, 2 insertions(+), 10 deletions(-) diff --git a/app/src/main/java/com/owncloud/android/ui/activity/DrawerActivity.java b/app/src/main/java/com/owncloud/android/ui/activity/DrawerActivity.java index 3adee261add5..e5ca8a79c66e 100644 --- a/app/src/main/java/com/owncloud/android/ui/activity/DrawerActivity.java +++ b/app/src/main/java/com/owncloud/android/ui/activity/DrawerActivity.java @@ -15,7 +15,6 @@ import android.accounts.AuthenticatorException; import android.accounts.OperationCanceledException; import android.app.Activity; -import android.app.ComponentCaller; import android.content.Context; import android.content.Intent; import android.content.res.ColorStateList; @@ -1208,6 +1207,8 @@ protected void onActivityResult(int requestCode, int resultCode, Intent data) { preferences.setLockTimestamp(0); finish(); } + } else if (requestCode == REQ_ALL_FILES_ACCESS || requestCode == REQ_MEDIA_ACCESS) { + checkStoragePermissionWarningBannerVisibility(); } } @@ -1436,15 +1437,6 @@ public BottomNavigationView getBottomNavigationView() { return bottomNavigationView; } - @Override - public void onActivityResult(int requestCode, int resultCode, @Nullable Intent data, @NonNull ComponentCaller caller) { - super.onActivityResult(requestCode, resultCode, data, caller); - - if (requestCode == REQ_ALL_FILES_ACCESS || requestCode == REQ_MEDIA_ACCESS) { - checkStoragePermissionWarningBannerVisibility(); - } - } - private void checkStoragePermissionWarningBannerVisibility() { if (this instanceof SyncedFoldersActivity syncedFoldersActivity) { syncedFoldersActivity.setupStoragePermissionWarningBanner(); From 44eb9526ee3a5707914caee176d14f5d2e56413b Mon Sep 17 00:00:00 2001 From: alperozturk Date: Mon, 8 Dec 2025 08:50:58 +0100 Subject: [PATCH 009/216] chore: bump version to v3.35.0 RC2 Signed-off-by: alperozturk --- app/build.gradle.kts | 2 +- fastlane/metadata/android/en-US/changelogs/30350052.txt | 7 +++++++ .../metadata/android/en-US/changelogs/30350052.txt.license | 2 ++ 3 files changed, 10 insertions(+), 1 deletion(-) create mode 100644 fastlane/metadata/android/en-US/changelogs/30350052.txt create mode 100644 fastlane/metadata/android/en-US/changelogs/30350052.txt.license diff --git a/app/build.gradle.kts b/app/build.gradle.kts index 6a877768922a..c89f2310843b 100644 --- a/app/build.gradle.kts +++ b/app/build.gradle.kts @@ -65,7 +65,7 @@ configurations.configureEach { val versionMajor = 3 val versionMinor = 35 val versionPatch = 0 -val versionBuild = 51 // 0-50=Alpha / 51-98=RC / 90-99=stable +val versionBuild = 52 // 0-50=Alpha / 51-98=RC / 90-99=stable val ndkEnv = buildMap { file("${project.rootDir}/ndk.env").readLines().forEach { diff --git a/fastlane/metadata/android/en-US/changelogs/30350052.txt b/fastlane/metadata/android/en-US/changelogs/30350052.txt new file mode 100644 index 000000000000..763d472433ea --- /dev/null +++ b/fastlane/metadata/android/en-US/changelogs/30350052.txt @@ -0,0 +1,7 @@ +## 3.35.0 RC2 (December 8, 2025) + +- Fixed crashes on devices running versions earlier than Android 15 + +Minimum: NC 20 Server, Android 9 Pie + +For a full list, please see https://github.com/nextcloud/android/milestone/118 \ No newline at end of file diff --git a/fastlane/metadata/android/en-US/changelogs/30350052.txt.license b/fastlane/metadata/android/en-US/changelogs/30350052.txt.license new file mode 100644 index 000000000000..3804756b12c8 --- /dev/null +++ b/fastlane/metadata/android/en-US/changelogs/30350052.txt.license @@ -0,0 +1,2 @@ +# SPDX-FileCopyrightText: 2025 Nextcloud GmbH and Nextcloud contributors +# SPDX-License-Identifier: AGPL-3.0-or-later \ No newline at end of file From 9429cd8cfbdb9f16f0b4519b5d0511e42bc3a3ca Mon Sep 17 00:00:00 2001 From: Nextcloud bot Date: Tue, 9 Dec 2025 02:49:49 +0000 Subject: [PATCH 010/216] fix(l10n): Update translations from Transifex Signed-off-by: Nextcloud bot --- app/src/main/res/values-sw/strings.xml | 18 +++++++++++++++++- 1 file changed, 17 insertions(+), 1 deletion(-) diff --git a/app/src/main/res/values-sw/strings.xml b/app/src/main/res/values-sw/strings.xml index 40907913eb0e..682e3c436c71 100644 --- a/app/src/main/res/values-sw/strings.xml +++ b/app/src/main/res/values-sw/strings.xml @@ -45,6 +45,8 @@ Tafuta katika %s Tokea nje ya mtandao Matokeo yaliyoonyeshwa hapa yanatolewa na AI. Hakikisha kuangalia mara mbili kila wakati. + Imeshindwa kutuma ujumbe + Imeshindwa kuleta ujumbe wa gumzo Je, una uhakika unataka kufuta jukumu hili? Futa jukumu Jaribu kutuma ujumbe ili kuzua mazungumzo. @@ -60,6 +62,7 @@ Msaidizi Ingilio Tokeo + Inafikiri... Akaunti inayohusishwa haijapatikana! Ufikiaji umeshindwa: %1$s Akaunti bado haijaongezwa kwenye kifaa hiki @@ -209,9 +212,12 @@ Hakuna faili iliyopatikana Haikuweza kupata nakala yako ya mwisho! Inagundua mabadiliko ya maudhui + Imeshindwa kuunda mazungumzo Futa mazungumzo + Imeshindwa kufuta mazungumzo Hakuna mazungumzo yaliyopatikana Bado hakuna mazungumzo + Imeshindwa kuleta orodha ya mazungumzo Mazungumzo Iliyonakiliwa Hitilafu ilitokea wakati wa kujaribu kunakili faili au folda hii @@ -313,9 +319,11 @@ E2E bado haijasanidiwa Haiwezekani bila muunganisho wa mtandao Saini hailingani + Haikuweza kuthibitisha metadata, sahihi ni tupu. Msaidizi Zaidi Programu zaidi za Nextcloud + Haiwezi kufungua kichagua faili Imeshindwa kuchagua anwani ya barua pepe. Weka kama iliyosimbwa Haiwezi kuepua cheti cha seva @@ -385,6 +393,7 @@ Huna ruhusa ya kuunda au kupakia faili katika folda hii. Shiriki za nje Ongeza au pakia + Imeshindwa kuunda mazungumzo ya mzozo Imeshindwa kupitisha faili ili kupakua kidhibiti Imeshindwa kuchapisha faili Imeshindwa kuanzisha kihariri @@ -645,6 +654,7 @@ Hakuna muunganisho wa intaneti Hata bila muunganisho wa mtandao, unaweza kupanga folda zako, kuunda faili. Ukisharejea mtandaoni, vitendo vyako vinavyosubiri vitasawazishwa kiotomatiki. Hauko mtandaoni, lakini kazi inaendelea + Faili bado haipo. Tafadhali pakia faili kwanza. Haikuweza kuunda %s. Faili yenye jina sawa ipo kwenye seva. Haikuweza kuunda %s. Folda yenye jina sawa ipo kwenye seva. Operesheni ya nje ya mtandao haiwezi kukamilika. %s @@ -689,6 +699,8 @@ Badilisha jina la toleo jipya Nini cha kufanya ikiwa faili tayari iko? Ongeza akaunti + Ruhusu programu kufikia na kudhibiti faili zote kwenye kifaa chako + Ufikiaji wa faili zote Sawazisha kalenda na anwani Si F-Droid wala Google Play iliyosakinishwa Sanidi DAVx⁵ (iliyojulikana kama DAVdroid) (v1.3.0+) kwa akaunti ya sasa @@ -873,7 +885,7 @@ Tuma kiungo Unset Avatar kutoka kwa mtumiaji aliyeshirikiwa - share + shiriki imeshirikiwa imeshirikiwa kupitia kiungo Imeshirikiwa na wewe kwa %1$s @@ -924,6 +936,10 @@ Hifadhi ya ndani Filamu Muziki + All files access + Ruhusa ya kuhifadhi inahitajika kwa Upakiaji Kiotomatiki. + Ruhusa ya kuhifadhi inahitajika kwa upakiaji wa faili. + Usiulize Vyombo vya habari vya kusoma pekee Picha Mfumo wa tija unaojiendesha unaokuweka katika udhibiti.\n\nVipengele:\n* Kiolesura rahisi, cha kisasa, kinacholingana na mandhari ya seva yako\n* Pakia faili kwenye seva yako ya Nextcloud\n* Zishiriki na wengine\n* Weka faili na folda zako uzipendazo zisawazishwe\n* Tafuta kwenye folda zote kwenye seva yako\n* Pakia Kiotomatiki kwa picha na video zilizochukuliwa na kifaa chako* Usaidizi wa data nyingi\n* Linda ufikiaji salama wa data yako ukitumia alama za vidole au PIN\n* Kuunganishwa na DAVx⁵ (zamani ikijulikana kama DAVdroid) kwa usanidi rahisi wa kalenda na ulandanishi wa anwani\n\nTafadhali ripoti matatizo yote katika https://github.com/nextcloud/android/issues na ujadili programu hii kwenye https://help.nextclouds/android/Nextclouds/android? Nextcloud ni upatanishi wa faili binafsi na seva ya kushiriki na mawasiliano. Ni programu isiyolipishwa, na unaweza kuikaribisha wewe mwenyewe au kulipa kampuni ili ikufanyie hivyo. Kwa njia hiyo, unadhibiti picha zako, kalenda na data yako ya mawasiliano, hati zako na kila kitu kingine.\n\nAngalia Nextcloud katika https://nextcloud.com From d7be9adbec352b773d65e5b2350396eb4439b741 Mon Sep 17 00:00:00 2001 From: alperozturk Date: Thu, 4 Dec 2025 12:09:22 +0100 Subject: [PATCH 011/216] fix: update file download limit Signed-off-by: alperozturk --- .../nextcloud/client/database/dao/ShareDao.kt | 3 ++ .../utils/extensions/OCShareExtensions.kt | 9 ++++ .../GetFilesDownloadLimitOperation.kt | 30 ------------ .../UpdateShareDownloadLimitOperation.kt | 47 +++++++++++++++++++ .../android/ui/adapter/LinkShareViewHolder.kt | 5 +- .../FileDetailsSharingProcessFragment.kt | 45 +++++++++++++++--- 6 files changed, 100 insertions(+), 39 deletions(-) delete mode 100644 app/src/main/java/com/owncloud/android/operations/GetFilesDownloadLimitOperation.kt create mode 100644 app/src/main/java/com/owncloud/android/operations/UpdateShareDownloadLimitOperation.kt diff --git a/app/src/main/java/com/nextcloud/client/database/dao/ShareDao.kt b/app/src/main/java/com/nextcloud/client/database/dao/ShareDao.kt index 61ea4a09c54a..5f44abbc6e8f 100644 --- a/app/src/main/java/com/nextcloud/client/database/dao/ShareDao.kt +++ b/app/src/main/java/com/nextcloud/client/database/dao/ShareDao.kt @@ -11,10 +11,13 @@ import androidx.room.Dao import androidx.room.Insert import androidx.room.OnConflictStrategy import androidx.room.Query +import androidx.room.Update import com.nextcloud.client.database.entity.ShareEntity @Dao interface ShareDao { + @Update + suspend fun update(entity: ShareEntity) @Insert(onConflict = OnConflictStrategy.REPLACE) suspend fun insertAll(shares: List) diff --git a/app/src/main/java/com/nextcloud/utils/extensions/OCShareExtensions.kt b/app/src/main/java/com/nextcloud/utils/extensions/OCShareExtensions.kt index dcb43b34dbfd..b72274cb8a6b 100644 --- a/app/src/main/java/com/nextcloud/utils/extensions/OCShareExtensions.kt +++ b/app/src/main/java/com/nextcloud/utils/extensions/OCShareExtensions.kt @@ -10,6 +10,15 @@ package com.nextcloud.utils.extensions import com.nextcloud.client.database.entity.ShareEntity import com.owncloud.android.lib.resources.shares.OCShare +fun OCShare?.remainingDownloadLimit(): Int? { + val downloadLimit = this?.fileDownloadLimit ?: return null + return if (downloadLimit.limit > 0) { + downloadLimit.limit - downloadLimit.count + } else { + null + } +} + fun OCShare.hasFileRequestPermission(): Boolean = (isFolder && shareType?.isPublicOrMail() == true) fun List.mergeDistinctByToken(other: List): List = (this + other).distinctBy { it.token } diff --git a/app/src/main/java/com/owncloud/android/operations/GetFilesDownloadLimitOperation.kt b/app/src/main/java/com/owncloud/android/operations/GetFilesDownloadLimitOperation.kt deleted file mode 100644 index b3b35c541078..000000000000 --- a/app/src/main/java/com/owncloud/android/operations/GetFilesDownloadLimitOperation.kt +++ /dev/null @@ -1,30 +0,0 @@ -/* - * Nextcloud - Android Client - * - * SPDX-FileCopyrightText: 2025 ZetaTom <70907959+zetatom@users.noreply.github.com> - * SPDX-License-Identifier: AGPL-3.0-or-later - */ - -package com.owncloud.android.operations - -import com.nextcloud.android.lib.resources.files.FileDownloadLimit -import com.nextcloud.android.lib.resources.files.GetFilesDownloadLimitRemoteOperation -import com.nextcloud.common.NextcloudClient -import com.owncloud.android.datamodel.FileDataStorageManager -import com.owncloud.android.lib.common.operations.RemoteOperationResult -import com.owncloud.android.lib.resources.shares.OCShare -import com.owncloud.android.operations.common.SyncOperation - -class GetFilesDownloadLimitOperation(val share: OCShare, storageManager: FileDataStorageManager) : - SyncOperation( - storageManager - ) { - override fun run(client: NextcloudClient): RemoteOperationResult> { - val token = share.token ?: return RemoteOperationResult(RemoteOperationResult.ResultCode.SHARE_NOT_FOUND) - val operation = GetFilesDownloadLimitRemoteOperation(token) - - val result = operation.execute(client) - - return result - } -} diff --git a/app/src/main/java/com/owncloud/android/operations/UpdateShareDownloadLimitOperation.kt b/app/src/main/java/com/owncloud/android/operations/UpdateShareDownloadLimitOperation.kt new file mode 100644 index 000000000000..9472a458153d --- /dev/null +++ b/app/src/main/java/com/owncloud/android/operations/UpdateShareDownloadLimitOperation.kt @@ -0,0 +1,47 @@ +/* + * Nextcloud - Android Client + * + * SPDX-FileCopyrightText: 2025 Alper Ozturk + * SPDX-License-Identifier: AGPL-3.0-or-later + */ + +package com.owncloud.android.operations + +import com.nextcloud.android.lib.resources.files.FileDownloadLimit +import com.nextcloud.android.lib.resources.files.GetFilesDownloadLimitRemoteOperation +import com.nextcloud.utils.extensions.toEntity +import com.owncloud.android.datamodel.FileDataStorageManager +import com.owncloud.android.lib.common.OwnCloudClient +import com.owncloud.android.lib.resources.shares.OCShare +import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.withContext + +class UpdateShareDownloadLimitOperation( + private val share: OCShare, + private val client: OwnCloudClient, + private val storageManager: FileDataStorageManager, + private val accountName: String +) { + @Suppress("DEPRECATION") + suspend fun run(): OCShare = withContext(Dispatchers.IO) { + val remotePath = share.path ?: return@withContext share + + val op = GetFilesDownloadLimitRemoteOperation(remotePath) + val result = op.execute(client) + + if (!result.isSuccess) { + return@withContext share + } + + val limits = result.data + ?.filterIsInstance() + ?: return@withContext share + + val newLimit = limits.firstOrNull() ?: return@withContext share + + share.fileDownloadLimit = newLimit + storageManager.shareDao.update(share.toEntity(accountName)) + + return@withContext share + } +} diff --git a/app/src/main/java/com/owncloud/android/ui/adapter/LinkShareViewHolder.kt b/app/src/main/java/com/owncloud/android/ui/adapter/LinkShareViewHolder.kt index 4c6f3aa59af1..dd9a01832ccb 100644 --- a/app/src/main/java/com/owncloud/android/ui/adapter/LinkShareViewHolder.kt +++ b/app/src/main/java/com/owncloud/android/ui/adapter/LinkShareViewHolder.kt @@ -18,6 +18,7 @@ import android.text.TextUtils import android.view.View import androidx.core.content.res.ResourcesCompat import androidx.recyclerview.widget.RecyclerView +import com.nextcloud.utils.extensions.remainingDownloadLimit import com.nextcloud.utils.mdm.MDMConfig import com.owncloud.android.R import com.owncloud.android.databinding.FileDetailsShareLinkShareItemBinding @@ -105,8 +106,8 @@ internal class LinkShareViewHolder(itemView: View) : RecyclerView.ViewHolder(ite } val downloadLimit = publicShare.fileDownloadLimit - if (downloadLimit != null && downloadLimit.limit > 0) { - val remaining = downloadLimit.limit - downloadLimit.count + if (downloadLimit != null) { + val remaining = publicShare.remainingDownloadLimit() ?: return val text = context.resources.getQuantityString( R.plurals.share_download_limit_description, remaining, diff --git a/app/src/main/java/com/owncloud/android/ui/fragment/FileDetailsSharingProcessFragment.kt b/app/src/main/java/com/owncloud/android/ui/fragment/FileDetailsSharingProcessFragment.kt index d1d2327a51ed..8a01b9e8bdc1 100644 --- a/app/src/main/java/com/owncloud/android/ui/fragment/FileDetailsSharingProcessFragment.kt +++ b/app/src/main/java/com/owncloud/android/ui/fragment/FileDetailsSharingProcessFragment.kt @@ -16,10 +16,12 @@ import android.view.View import android.view.ViewGroup import androidx.core.view.isVisible import androidx.fragment.app.Fragment +import androidx.lifecycle.lifecycleScope import com.nextcloud.client.di.Injectable import com.nextcloud.utils.extensions.getParcelableArgument import com.nextcloud.utils.extensions.getSerializableArgument import com.nextcloud.utils.extensions.isPublicOrMail +import com.nextcloud.utils.extensions.remainingDownloadLimit import com.nextcloud.utils.extensions.setVisibilityWithAnimation import com.nextcloud.utils.extensions.setVisibleIf import com.owncloud.android.R @@ -33,6 +35,7 @@ import com.owncloud.android.lib.resources.shares.extensions.isAllowDownloadAndSy import com.owncloud.android.lib.resources.shares.extensions.toggleAllowDownloadAndSync import com.owncloud.android.lib.resources.status.NextcloudVersion import com.owncloud.android.lib.resources.status.OCCapability +import com.owncloud.android.operations.UpdateShareDownloadLimitOperation import com.owncloud.android.ui.activity.FileActivity import com.owncloud.android.ui.dialog.ExpirationDatePickerDialogFragment import com.owncloud.android.ui.fragment.util.SharePermissionManager @@ -41,6 +44,9 @@ import com.owncloud.android.utils.ClipboardUtil import com.owncloud.android.utils.DisplayUtils import com.owncloud.android.utils.theme.CapabilityUtils import com.owncloud.android.utils.theme.ViewThemeUtils +import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.launch +import kotlinx.coroutines.withContext import java.text.SimpleDateFormat import java.util.Date import javax.inject.Inject @@ -490,15 +496,40 @@ class FileDetailsSharingProcessFragment : } } + private suspend fun updateShareDownloadLimit() { + val share = share ?: return + val activity = activity as? FileActivity + val client = activity?.clientRepository?.getOwncloudClient() ?: return + val storageManager = activity.storageManager ?: return + val optionalUser = activity.user + if (optionalUser.isEmpty) { + return + } + + val accountName = optionalUser.get().accountName + val operation = UpdateShareDownloadLimitOperation(share, client, storageManager, accountName) + val newShare = operation.run() + + Log_OC.d(TAG, "share download limit updated") + this@FileDetailsSharingProcessFragment.share = newShare + } + private fun updateFileDownloadLimitView() { - if (canSetDownloadLimit()) { - binding.shareProcessSetDownloadLimitSwitch.visibility = View.VISIBLE + if (!canSetDownloadLimit()) { + return + } - val currentDownloadLimit = share?.fileDownloadLimit?.limit ?: capabilities.filesDownloadLimitDefault - if (currentDownloadLimit > 0) { - binding.shareProcessSetDownloadLimitSwitch.isChecked = true - showFileDownloadLimitInput(true) - binding.shareProcessSetDownloadLimitInput.setText("$currentDownloadLimit") + lifecycleScope.launch(Dispatchers.IO) { + updateShareDownloadLimit() + + withContext(Dispatchers.Main) { + val currentLimit = share?.remainingDownloadLimit() ?: return@withContext + binding.shareProcessSetDownloadLimitSwitch.visibility = View.VISIBLE + if (currentLimit > 0) { + binding.shareProcessSetDownloadLimitSwitch.isChecked = true + showFileDownloadLimitInput(true) + binding.shareProcessSetDownloadLimitInput.setText(currentLimit.toString()) + } } } } From bc6850fb53a3ff5f8ed7e15d6dc5fadfb1a2391d Mon Sep 17 00:00:00 2001 From: alperozturk Date: Thu, 4 Dec 2025 12:13:56 +0100 Subject: [PATCH 012/216] fix: update file download limit Signed-off-by: alperozturk --- .../UpdateShareDownloadLimitOperation.kt | 47 ------------------- .../FileDetailsSharingProcessFragment.kt | 41 +++------------- 2 files changed, 6 insertions(+), 82 deletions(-) delete mode 100644 app/src/main/java/com/owncloud/android/operations/UpdateShareDownloadLimitOperation.kt diff --git a/app/src/main/java/com/owncloud/android/operations/UpdateShareDownloadLimitOperation.kt b/app/src/main/java/com/owncloud/android/operations/UpdateShareDownloadLimitOperation.kt deleted file mode 100644 index 9472a458153d..000000000000 --- a/app/src/main/java/com/owncloud/android/operations/UpdateShareDownloadLimitOperation.kt +++ /dev/null @@ -1,47 +0,0 @@ -/* - * Nextcloud - Android Client - * - * SPDX-FileCopyrightText: 2025 Alper Ozturk - * SPDX-License-Identifier: AGPL-3.0-or-later - */ - -package com.owncloud.android.operations - -import com.nextcloud.android.lib.resources.files.FileDownloadLimit -import com.nextcloud.android.lib.resources.files.GetFilesDownloadLimitRemoteOperation -import com.nextcloud.utils.extensions.toEntity -import com.owncloud.android.datamodel.FileDataStorageManager -import com.owncloud.android.lib.common.OwnCloudClient -import com.owncloud.android.lib.resources.shares.OCShare -import kotlinx.coroutines.Dispatchers -import kotlinx.coroutines.withContext - -class UpdateShareDownloadLimitOperation( - private val share: OCShare, - private val client: OwnCloudClient, - private val storageManager: FileDataStorageManager, - private val accountName: String -) { - @Suppress("DEPRECATION") - suspend fun run(): OCShare = withContext(Dispatchers.IO) { - val remotePath = share.path ?: return@withContext share - - val op = GetFilesDownloadLimitRemoteOperation(remotePath) - val result = op.execute(client) - - if (!result.isSuccess) { - return@withContext share - } - - val limits = result.data - ?.filterIsInstance() - ?: return@withContext share - - val newLimit = limits.firstOrNull() ?: return@withContext share - - share.fileDownloadLimit = newLimit - storageManager.shareDao.update(share.toEntity(accountName)) - - return@withContext share - } -} diff --git a/app/src/main/java/com/owncloud/android/ui/fragment/FileDetailsSharingProcessFragment.kt b/app/src/main/java/com/owncloud/android/ui/fragment/FileDetailsSharingProcessFragment.kt index 8a01b9e8bdc1..dd4c1537f038 100644 --- a/app/src/main/java/com/owncloud/android/ui/fragment/FileDetailsSharingProcessFragment.kt +++ b/app/src/main/java/com/owncloud/android/ui/fragment/FileDetailsSharingProcessFragment.kt @@ -16,7 +16,6 @@ import android.view.View import android.view.ViewGroup import androidx.core.view.isVisible import androidx.fragment.app.Fragment -import androidx.lifecycle.lifecycleScope import com.nextcloud.client.di.Injectable import com.nextcloud.utils.extensions.getParcelableArgument import com.nextcloud.utils.extensions.getSerializableArgument @@ -35,7 +34,6 @@ import com.owncloud.android.lib.resources.shares.extensions.isAllowDownloadAndSy import com.owncloud.android.lib.resources.shares.extensions.toggleAllowDownloadAndSync import com.owncloud.android.lib.resources.status.NextcloudVersion import com.owncloud.android.lib.resources.status.OCCapability -import com.owncloud.android.operations.UpdateShareDownloadLimitOperation import com.owncloud.android.ui.activity.FileActivity import com.owncloud.android.ui.dialog.ExpirationDatePickerDialogFragment import com.owncloud.android.ui.fragment.util.SharePermissionManager @@ -44,9 +42,6 @@ import com.owncloud.android.utils.ClipboardUtil import com.owncloud.android.utils.DisplayUtils import com.owncloud.android.utils.theme.CapabilityUtils import com.owncloud.android.utils.theme.ViewThemeUtils -import kotlinx.coroutines.Dispatchers -import kotlinx.coroutines.launch -import kotlinx.coroutines.withContext import java.text.SimpleDateFormat import java.util.Date import javax.inject.Inject @@ -496,41 +491,17 @@ class FileDetailsSharingProcessFragment : } } - private suspend fun updateShareDownloadLimit() { - val share = share ?: return - val activity = activity as? FileActivity - val client = activity?.clientRepository?.getOwncloudClient() ?: return - val storageManager = activity.storageManager ?: return - val optionalUser = activity.user - if (optionalUser.isEmpty) { - return - } - - val accountName = optionalUser.get().accountName - val operation = UpdateShareDownloadLimitOperation(share, client, storageManager, accountName) - val newShare = operation.run() - - Log_OC.d(TAG, "share download limit updated") - this@FileDetailsSharingProcessFragment.share = newShare - } - private fun updateFileDownloadLimitView() { if (!canSetDownloadLimit()) { return } - lifecycleScope.launch(Dispatchers.IO) { - updateShareDownloadLimit() - - withContext(Dispatchers.Main) { - val currentLimit = share?.remainingDownloadLimit() ?: return@withContext - binding.shareProcessSetDownloadLimitSwitch.visibility = View.VISIBLE - if (currentLimit > 0) { - binding.shareProcessSetDownloadLimitSwitch.isChecked = true - showFileDownloadLimitInput(true) - binding.shareProcessSetDownloadLimitInput.setText(currentLimit.toString()) - } - } + val currentLimit = share?.remainingDownloadLimit() ?: return + binding.shareProcessSetDownloadLimitSwitch.visibility = View.VISIBLE + if (currentLimit > 0) { + binding.shareProcessSetDownloadLimitSwitch.isChecked = true + showFileDownloadLimitInput(true) + binding.shareProcessSetDownloadLimitInput.setText(currentLimit.toString()) } } From 95a820af7135bfeb0fdf54344d9bda2df3aae663 Mon Sep 17 00:00:00 2001 From: alperozturk Date: Thu, 4 Dec 2025 12:15:12 +0100 Subject: [PATCH 013/216] fix: update file download limit Signed-off-by: alperozturk --- .../main/java/com/nextcloud/client/database/dao/ShareDao.kt | 4 ---- 1 file changed, 4 deletions(-) diff --git a/app/src/main/java/com/nextcloud/client/database/dao/ShareDao.kt b/app/src/main/java/com/nextcloud/client/database/dao/ShareDao.kt index 5f44abbc6e8f..c83f6a1f3ae5 100644 --- a/app/src/main/java/com/nextcloud/client/database/dao/ShareDao.kt +++ b/app/src/main/java/com/nextcloud/client/database/dao/ShareDao.kt @@ -11,14 +11,10 @@ import androidx.room.Dao import androidx.room.Insert import androidx.room.OnConflictStrategy import androidx.room.Query -import androidx.room.Update import com.nextcloud.client.database.entity.ShareEntity @Dao interface ShareDao { - @Update - suspend fun update(entity: ShareEntity) - @Insert(onConflict = OnConflictStrategy.REPLACE) suspend fun insertAll(shares: List) From 2ef1daaa8149b59191b812f9a563188b5bd06477 Mon Sep 17 00:00:00 2001 From: alperozturk Date: Thu, 4 Dec 2025 12:15:33 +0100 Subject: [PATCH 014/216] fix: update file download limit Signed-off-by: alperozturk --- app/src/main/java/com/nextcloud/client/database/dao/ShareDao.kt | 1 + 1 file changed, 1 insertion(+) diff --git a/app/src/main/java/com/nextcloud/client/database/dao/ShareDao.kt b/app/src/main/java/com/nextcloud/client/database/dao/ShareDao.kt index c83f6a1f3ae5..61ea4a09c54a 100644 --- a/app/src/main/java/com/nextcloud/client/database/dao/ShareDao.kt +++ b/app/src/main/java/com/nextcloud/client/database/dao/ShareDao.kt @@ -15,6 +15,7 @@ import com.nextcloud.client.database.entity.ShareEntity @Dao interface ShareDao { + @Insert(onConflict = OnConflictStrategy.REPLACE) suspend fun insertAll(shares: List) From 2fadd2fe72ba1c5fe74218d4c3d15f13ddcce1dd Mon Sep 17 00:00:00 2001 From: alperozturk Date: Tue, 9 Dec 2025 11:56:36 +0100 Subject: [PATCH 015/216] ui fixes Signed-off-by: alperozturk --- .../FileDetailsSharingProcessFragment.kt | 25 ++++--------------- app/src/main/res/values/strings.xml | 1 - 2 files changed, 5 insertions(+), 21 deletions(-) diff --git a/app/src/main/java/com/owncloud/android/ui/fragment/FileDetailsSharingProcessFragment.kt b/app/src/main/java/com/owncloud/android/ui/fragment/FileDetailsSharingProcessFragment.kt index dd4c1537f038..6052fa51df6c 100644 --- a/app/src/main/java/com/owncloud/android/ui/fragment/FileDetailsSharingProcessFragment.kt +++ b/app/src/main/java/com/owncloud/android/ui/fragment/FileDetailsSharingProcessFragment.kt @@ -198,7 +198,6 @@ class FileDetailsSharingProcessFragment : setCheckboxStates() themeView() setVisibilitiesOfShareOption() - toggleNextButtonAvailability(isAnySharePermissionChecked()) logShareInfo() } @@ -496,11 +495,14 @@ class FileDetailsSharingProcessFragment : return } - val currentLimit = share?.remainingDownloadLimit() ?: return + // user can set download limit thus no need to rely on current limit to show download limit + showFileDownloadLimitInput(true) binding.shareProcessSetDownloadLimitSwitch.visibility = View.VISIBLE + binding.shareProcessSetDownloadLimitInput.visibility = View.VISIBLE + + val currentLimit = share?.remainingDownloadLimit() ?: return if (currentLimit > 0) { binding.shareProcessSetDownloadLimitSwitch.isChecked = true - showFileDownloadLimitInput(true) binding.shareProcessSetDownloadLimitInput.setText(currentLimit.toString()) } } @@ -587,7 +589,6 @@ class FileDetailsSharingProcessFragment : val isCustomPermissionSelected = (optionId == R.id.custom_permission_radio_button) customPermissionLayout.setVisibilityWithAnimation(isCustomPermissionSelected) - toggleNextButtonAvailability(true) } // endregion } @@ -612,13 +613,6 @@ class FileDetailsSharingProcessFragment : ) } - private fun toggleNextButtonAvailability(value: Boolean) { - binding.run { - shareProcessBtnNext.isEnabled = value - shareProcessBtnNext.isClickable = value - } - } - @Suppress("NestedBlockDepth") private fun setCheckboxStates() { val currentPermissions = share?.permissions ?: permission @@ -676,7 +670,6 @@ class FileDetailsSharingProcessFragment : private fun togglePermission(isChecked: Boolean, permissionFlag: Int) { permission = SharePermissionManager.togglePermission(isChecked, permission, permissionFlag) - toggleNextButtonAvailability(true) } private fun showExpirationDateDialog(chosenDateInMillis: Long = chosenExpDateInMills) { @@ -781,14 +774,6 @@ class FileDetailsSharingProcessFragment : return } - if (!isSharePermissionChecked() && !isCustomPermissionSelectedAndAnyCustomPermissionTypeChecked()) { - DisplayUtils.showSnackMessage( - binding.root, - R.string.file_details_sharing_fragment_custom_permission_not_selected - ) - return - } - // if modifying existing share information then execute the process if (share != null) { updateShare() diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index a48e76517e0a..9df94fe5e626 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -1448,7 +1448,6 @@ Sync duplication Could not load content The device is likely not connected to the internet - Please select custom permission Unknown Upload Stopped – Storage Permission Required Your files cannot be uploaded without access to local storage. Tap to grant permission. From 2d5a4e748c4118de84149274022f25c1857ab9a7 Mon Sep 17 00:00:00 2001 From: Nextcloud bot Date: Wed, 10 Dec 2025 02:48:15 +0000 Subject: [PATCH 016/216] fix(l10n): Update translations from Transifex Signed-off-by: Nextcloud bot --- app/src/main/res/values-b+en+001/strings.xml | 2 +- app/src/main/res/values-cs-rCZ/strings.xml | 1 - app/src/main/res/values-da/strings.xml | 3 ++- app/src/main/res/values-de/strings.xml | 1 - app/src/main/res/values-el/strings.xml | 2 ++ app/src/main/res/values-eo/strings.xml | 1 + app/src/main/res/values-es-rAR/strings.xml | 1 + app/src/main/res/values-es-rCO/strings.xml | 1 + app/src/main/res/values-es/strings.xml | 2 +- app/src/main/res/values-et-rEE/strings.xml | 1 - app/src/main/res/values-fr/strings.xml | 1 - app/src/main/res/values-ga/strings.xml | 1 - app/src/main/res/values-gl/strings.xml | 1 - app/src/main/res/values-hu-rHU/strings.xml | 1 - app/src/main/res/values-in/strings.xml | 1 - app/src/main/res/values-is/strings.xml | 1 - app/src/main/res/values-ja-rJP/strings.xml | 1 - app/src/main/res/values-lo/strings.xml | 1 - app/src/main/res/values-nl/strings.xml | 1 - app/src/main/res/values-pl/strings.xml | 1 - app/src/main/res/values-pt-rBR/strings.xml | 1 - app/src/main/res/values-ru/strings.xml | 1 - app/src/main/res/values-sr/strings.xml | 1 - app/src/main/res/values-sv/strings.xml | 1 - app/src/main/res/values-sw/strings.xml | 1 - app/src/main/res/values-tr/strings.xml | 28 +++++++++++++++++++- app/src/main/res/values-ug/strings.xml | 1 - app/src/main/res/values-uk/strings.xml | 1 - app/src/main/res/values-zh-rCN/strings.xml | 1 - app/src/main/res/values-zh-rHK/strings.xml | 1 - app/src/main/res/values-zh-rTW/strings.xml | 1 - 31 files changed, 36 insertions(+), 27 deletions(-) diff --git a/app/src/main/res/values-b+en+001/strings.xml b/app/src/main/res/values-b+en+001/strings.xml index 967a05a04442..6763c16e08f5 100644 --- a/app/src/main/res/values-b+en+001/strings.xml +++ b/app/src/main/res/values-b+en+001/strings.xml @@ -408,7 +408,6 @@ You cannot create a share, sharing is already active from this user. No app available to select contacts Failed to load details - Please select custom permission File Keep Upload some content or sync with your devices. @@ -677,6 +676,7 @@ Passcode deleted Passcode stored Incorrect passcode + Pause Unable to open password-protected PDF. Please use an external PDF viewer. Allow Deny diff --git a/app/src/main/res/values-cs-rCZ/strings.xml b/app/src/main/res/values-cs-rCZ/strings.xml index 8f8c989ee1ee..f7cc036c8dc8 100644 --- a/app/src/main/res/values-cs-rCZ/strings.xml +++ b/app/src/main/res/values-cs-rCZ/strings.xml @@ -405,7 +405,6 @@ Sdílení není možné vytvořit – to už je aktivní od tohoto uživatele. Pro označené kontakty není k dispozici žádná aplikace Nepodařilo se načíst podrobnosti. - Vyberte uživatelsky určená oprávnění Soubor Ponechat Nahrajte nějaký obsah, nebo synchronizujte s vašimi zařízeními. diff --git a/app/src/main/res/values-da/strings.xml b/app/src/main/res/values-da/strings.xml index ff6f06f94e29..a19c710c8ade 100644 --- a/app/src/main/res/values-da/strings.xml +++ b/app/src/main/res/values-da/strings.xml @@ -123,6 +123,7 @@ Optaget Kalender Kalendere + Annullér Der er et problem med lagring af certificering. Changelog udviklingsversion Kig forbi senere eller genindlæs. @@ -394,7 +395,6 @@ Du kan ikke slette en deling, deling er allerede aktiv fra denne bruger. Ingen app tilgængelig til at vælge kontakter Fejl ved indlæsning af detaljer - Vælg venligst brugerdefineret rettighed Fil Behold Upload indhold eller synkroniser med dine enheder. @@ -654,6 +654,7 @@ Adgangskode slettet Passkode blev gendannet Forkert passkode + Pause Ikke i stand til at åbne kodeordsbeskyttet PDF. Brug venligst en ekstern PDF-fremviser. Tillad Afvis diff --git a/app/src/main/res/values-de/strings.xml b/app/src/main/res/values-de/strings.xml index 63e97d1a9c78..1fea68696063 100644 --- a/app/src/main/res/values-de/strings.xml +++ b/app/src/main/res/values-de/strings.xml @@ -408,7 +408,6 @@ Sie können keine Freigabe erstellen, die Freigabe ist von diesem Benutzer bereits aktiviert. Keine App zum Auswählen von Kontakten verfügbar Details konnten nicht geladen werden - Bitte wählen Sie benutzerdefinierte Berechtigung Datei Behalten Laden Sie Inhalt hoch oder synchronisieren Sie mit Ihren Geräten. diff --git a/app/src/main/res/values-el/strings.xml b/app/src/main/res/values-el/strings.xml index 7ae9a8f20cbf..a417c89f7352 100644 --- a/app/src/main/res/values-el/strings.xml +++ b/app/src/main/res/values-el/strings.xml @@ -91,6 +91,7 @@ Απασχολημένος Ημερολόγιο Ημερολόγια + Ακύρωση Πρόβλημα φόρτωσης του πιστοποιητικού. Αρχείο αλλαγών της έκδοσης προγραμματιστή Ελέγξτε ξανά αργότερα ή κάνετε ανανέωση. @@ -526,6 +527,7 @@ Διεγράφη ο κωδικός πρόσβασης Ο κωδικός πρόσβασης αποθηκεύτηκε Εσφαλμένος κωδικός πρόσβασης + Παύση Επιτρέπεται Απόρριψη Δεν βρέθηκε εφαρμογή για τον ορισμό φωτογραφίας diff --git a/app/src/main/res/values-eo/strings.xml b/app/src/main/res/values-eo/strings.xml index 3877406bcb4d..1b368d233e05 100644 --- a/app/src/main/res/values-eo/strings.xml +++ b/app/src/main/res/values-eo/strings.xml @@ -365,6 +365,7 @@ Pasvorto forigita Pasvorto konservita Neĝusta pasvorto + Paŭzigi Permesi Rifuzi Neniu aplikaĵo trovita por uzi tiun bildon diff --git a/app/src/main/res/values-es-rAR/strings.xml b/app/src/main/res/values-es-rAR/strings.xml index b98b5bb094a5..9cb4c0b344b1 100644 --- a/app/src/main/res/values-es-rAR/strings.xml +++ b/app/src/main/res/values-es-rAR/strings.xml @@ -551,6 +551,7 @@ Contraseña eliminada Código de seguridad almacenado Código de seguridad incorrecto + Pausar No es posible abrir archivos PDF protegidos por contraseñas. Por favor, use un visor PDF externo. Permitir Rechazar diff --git a/app/src/main/res/values-es-rCO/strings.xml b/app/src/main/res/values-es-rCO/strings.xml index d2aae445afcb..a2a78afa1e13 100644 --- a/app/src/main/res/values-es-rCO/strings.xml +++ b/app/src/main/res/values-es-rCO/strings.xml @@ -504,6 +504,7 @@ Código de seguirdad eliminado Código de seguridad almacenado Código de seguridad incorrecto + Pausar No se encontró una aplicación con la cual establecer la imagen Borrado mantenido en la carpeta original diff --git a/app/src/main/res/values-es/strings.xml b/app/src/main/res/values-es/strings.xml index 8df92c661853..ee5034bd07d0 100644 --- a/app/src/main/res/values-es/strings.xml +++ b/app/src/main/res/values-es/strings.xml @@ -394,7 +394,6 @@ No puede crear un recurso compartido, el recurso compartido ya está activo desde este usuario. No hay ninguna aplicación disponible para seleccionar contactos Fallo al cargar los detalles - Por favor, seleccione el permiso personalizado Archivo Mantener Sube algún contenido o sincroniza con tus dispositivos. @@ -652,6 +651,7 @@ Código de acceso borrado Código de acceso almacenado Código de acceso incorrecto + Pausar No es posible abrir archivos PDF protegidos por contraseñas. Por favor, use un visor PDF externo. Permitir Denegar diff --git a/app/src/main/res/values-et-rEE/strings.xml b/app/src/main/res/values-et-rEE/strings.xml index aa19f7e06a2d..49f0977277c8 100644 --- a/app/src/main/res/values-et-rEE/strings.xml +++ b/app/src/main/res/values-et-rEE/strings.xml @@ -408,7 +408,6 @@ Jagamise lisamine ei õnnestu. See kasutaja on jagamise juba sisse lülitanud. Kontaktide valimiseks ei leidu sobilikku rakendust Üksikasjade laadimine ei õnnestunud - Palun vali kohandatud õigused Fail Hoia alles Laadi midagi üles või sünkroniseeri oma seadmetega. diff --git a/app/src/main/res/values-fr/strings.xml b/app/src/main/res/values-fr/strings.xml index 45be2b123443..2f0dcd7b1026 100644 --- a/app/src/main/res/values-fr/strings.xml +++ b/app/src/main/res/values-fr/strings.xml @@ -406,7 +406,6 @@ Impossible de créer un partage car le partage est déjà actif pour cet utilisateur. Aucune application disponible pour sélectionner des contacts Impossible de charger les détails - Merci de sélectionner une autorisation Fichier Conserver Déposez du contenu ou synchronisez vos appareils. diff --git a/app/src/main/res/values-ga/strings.xml b/app/src/main/res/values-ga/strings.xml index 8c4b2a613253..fb7dffe6ec72 100644 --- a/app/src/main/res/values-ga/strings.xml +++ b/app/src/main/res/values-ga/strings.xml @@ -408,7 +408,6 @@ Ní féidir leat comhroinnt a chruthú, tá an chomhroinnt gníomhach cheana féin ón úsáideoir seo. Níl aip ar fáil chun teagmhálaithe a roghnú Theip ar lódáil na sonraí - Roghnaigh cead saincheaptha le do thoil Comhad Coinnigh Uaslódáil roinnt inneachair nó sioncronaigh le do ghléasanna. diff --git a/app/src/main/res/values-gl/strings.xml b/app/src/main/res/values-gl/strings.xml index eb3f374e550e..3be672998b76 100644 --- a/app/src/main/res/values-gl/strings.xml +++ b/app/src/main/res/values-gl/strings.xml @@ -408,7 +408,6 @@ Non pode crear unha compartición, a compartición xa está activa desde este usuario. Non hai ningunha aplicación dispoñíbel para seleccionar contactos Produciuse un fallo ao cargar os detalles - Seleccione o permiso personalizado Ficheiro Conservar Envíe algún contido ou sincronice cos seus dispositivos. diff --git a/app/src/main/res/values-hu-rHU/strings.xml b/app/src/main/res/values-hu-rHU/strings.xml index f96d7a79eea6..c6203332fb13 100644 --- a/app/src/main/res/values-hu-rHU/strings.xml +++ b/app/src/main/res/values-hu-rHU/strings.xml @@ -389,7 +389,6 @@ Nem hozhat létre megosztást, a megosztás már aktív ettől a felhasználótól. Nem érhető el alkalmazás a névjegyek kiválasztásához A részletek betöltése sikertelen - Válasszon egyéni engedélyt Fájl Megtartás Töltsön fel új tartalmat vagy szinkronizáljon az eszközeivel. diff --git a/app/src/main/res/values-in/strings.xml b/app/src/main/res/values-in/strings.xml index a51dd7c9acb0..8feb611ea6d5 100644 --- a/app/src/main/res/values-in/strings.xml +++ b/app/src/main/res/values-in/strings.xml @@ -392,7 +392,6 @@ Otomatis unggah hanya bekerja dengan baik apabila Anda mengeluarkan aplikasi ini Anda tidak dapat membagi, opsi berbagi sudah aktif dari pengguna ini. Tidak ada aplikasi yang tersedia untuk memilih kontak Gagal memuat detil - Silakan pilih izin khusus Berkas Simpan Unggah beberapa berkas atau sinkronisasi dengan perangkat anda. diff --git a/app/src/main/res/values-is/strings.xml b/app/src/main/res/values-is/strings.xml index de294f0d5f0c..f9d6d97d571c 100644 --- a/app/src/main/res/values-is/strings.xml +++ b/app/src/main/res/values-is/strings.xml @@ -388,7 +388,6 @@ Þú getur ekki tekið búið til sameign, deiling er þegar virk af hálfu þessa notanda. Ekkert forrit tiltækt til að velja tengiliði Mistókst að hlaða inn ítarupplýsingum - Veldu sérsniðna heimild Skrá Halda Sendu inn eitthvað efni eða samstilltu við tækin þín! diff --git a/app/src/main/res/values-ja-rJP/strings.xml b/app/src/main/res/values-ja-rJP/strings.xml index 3eee232b0dae..62f713d214b4 100644 --- a/app/src/main/res/values-ja-rJP/strings.xml +++ b/app/src/main/res/values-ja-rJP/strings.xml @@ -397,7 +397,6 @@ 共有を作成できません。このユーザーからの共有はすでに有効になっています。 連絡先を選択するためのアプリが利用できません 詳細のロードに失敗しました - カスタムの権限を選択してください。 ファイル 保持 コンテンツをアップロードするか、デバイスと同期してください。 diff --git a/app/src/main/res/values-lo/strings.xml b/app/src/main/res/values-lo/strings.xml index 94bcbd617580..17c5157c1fb0 100644 --- a/app/src/main/res/values-lo/strings.xml +++ b/app/src/main/res/values-lo/strings.xml @@ -399,7 +399,6 @@ You cannot create a share, sharing is already active from this user. No app available to select contacts ການດາວໂຫຼດລາຍລະອຽດບໍ່ສຳເລັດ - Please select custom permission ຟາຍ ຮັກສາໄວ້ ອັບໂຫຼດເນື້ອຫາບາງອັນ ຫຼື sync ອຸປະກອນຂອງທ່ານ diff --git a/app/src/main/res/values-nl/strings.xml b/app/src/main/res/values-nl/strings.xml index 8f127b81f213..df3672b7d4fa 100644 --- a/app/src/main/res/values-nl/strings.xml +++ b/app/src/main/res/values-nl/strings.xml @@ -384,7 +384,6 @@ Kan geen deling maken, deling is al actief van deze gebruiker Geen app beschikbaar voor het selecteren van contactpersonen Kon details niet laden - Selecteer andere toestemming Bestand Behouden Upload je inhoud of synchroniseer met je apparaten. diff --git a/app/src/main/res/values-pl/strings.xml b/app/src/main/res/values-pl/strings.xml index d545307a0f90..4389da1343d7 100644 --- a/app/src/main/res/values-pl/strings.xml +++ b/app/src/main/res/values-pl/strings.xml @@ -406,7 +406,6 @@ Nie można utworzyć udostępnienia — udostępnianie jest już aktywne dla tego użytkownika. Brak aplikacji dla wybranego kontaktu Nie udało się załadować szczegółów - Proszę wybrać własne uprawnienia Plik Zachowaj Wyślij lub zsynchronizuj pliki z urządzeniami. diff --git a/app/src/main/res/values-pt-rBR/strings.xml b/app/src/main/res/values-pt-rBR/strings.xml index f0b16b0b12c0..b7ff9a8698ea 100644 --- a/app/src/main/res/values-pt-rBR/strings.xml +++ b/app/src/main/res/values-pt-rBR/strings.xml @@ -408,7 +408,6 @@ Não é possível criar um compartilhamento, pois o compartilhamento já está ativo para este usuário. Nenhum aplicativo disponível para selecionar contatos Falha ao carregar detalhes - Por favor, selecione a permissão personalizada Arquivo Manter Envie um arquivo ou sincronize com seus dispositivos. diff --git a/app/src/main/res/values-ru/strings.xml b/app/src/main/res/values-ru/strings.xml index 947e385a1eab..f0eef136ea99 100644 --- a/app/src/main/res/values-ru/strings.xml +++ b/app/src/main/res/values-ru/strings.xml @@ -387,7 +387,6 @@ Вы не можете создать общий ресурс — общий доступ уже активен от этого пользователя. Приложение для выбора контактов недоступно Не удалось получить подробные сведения - Пожалуйста выберите права доступа Файл Сохранить Добавьте что-нибудь или синхронизируйте со своими устройствами! diff --git a/app/src/main/res/values-sr/strings.xml b/app/src/main/res/values-sr/strings.xml index a1e9e7647db2..b93c136ef684 100644 --- a/app/src/main/res/values-sr/strings.xml +++ b/app/src/main/res/values-sr/strings.xml @@ -398,7 +398,6 @@ Не можете да креирате дељење, овај корисник је већ активирао дељење. Нема апликације којом могу да се изаберу контакти Грешка при учитавању детаља - Молимо вас да изаберете произвољну дозволу Фајл Задржи Отпремите неки садржај или синхронизујте са вашим уређајима. diff --git a/app/src/main/res/values-sv/strings.xml b/app/src/main/res/values-sv/strings.xml index 484acb6ff8ed..c6a0bf68221d 100644 --- a/app/src/main/res/values-sv/strings.xml +++ b/app/src/main/res/values-sv/strings.xml @@ -405,7 +405,6 @@ Du kan inte skapa en delning, användaren har redan en aktiv delning. Ingen app tillgänglig för att välja kontakter Kunde inte läsa in detaljer - Välj anpassad behörighet Fil Behåll Ladda upp något eller synkronisera med dina enheter diff --git a/app/src/main/res/values-sw/strings.xml b/app/src/main/res/values-sw/strings.xml index 682e3c436c71..da57a8353da9 100644 --- a/app/src/main/res/values-sw/strings.xml +++ b/app/src/main/res/values-sw/strings.xml @@ -408,7 +408,6 @@ Huwezi kuunda kushiriki, kushiriki tayari kunatumika kutoka kwa mtumiaji huyu. Hakuna programu inayopatikana ya kuchagua anwani Imeshindwa kupakia maelezo - Tafadhali chagua ruhusa maalum Faili Weka Pakia baadhi ya maudhui au usawazishe na vifaa vyako. diff --git a/app/src/main/res/values-tr/strings.xml b/app/src/main/res/values-tr/strings.xml index a6980e422d11..64fbde2396ee 100644 --- a/app/src/main/res/values-tr/strings.xml +++ b/app/src/main/res/values-tr/strings.xml @@ -45,6 +45,8 @@ %s içinde ara Çevrim dışı görün Bu çıktı yapay zeka tarafından oluşturuldu. Her zaman iki kez kontrol ettiğinizden emin olun. + Bir ileti gönderilemedi + Sohbet iletileri alınamadı Bu görevi silmek istediğinize emin misiniz? Görevi sil Bir görüşme başlatacak bir ileti göndermeyi dene. @@ -53,12 +55,14 @@ Görev oluşturuldu Görev silinirken bir sorun çıktı Görev silindi + Görev listesi boş. Yardımcı uygulamasının yapılandırmasını denetleyin. Görev listesi alınamadı. Lütfen İnternet bağlantınızı denetleyin. Görevi sil Görev çıktısı henüz hazır değil. Yardımcı Giriş Çıkış + Düşünüyorum… İlişkili hesap bulunamadı! Erişilemedi: %1$s Aygıt üzerinde henüz bu hesap açılmamış @@ -208,8 +212,12 @@ Herhangi bir dosya bulunamadı Son yedeğiniz bulunamadı! İçerik değişiklikleri denetleniyor + Görüşme oluşturulamadı + Görüşmeyi sil + Görüşme silinemedi Herhangi bir görüşme bulunamadı Henüz bir görüşme yok + Görüşme listesi alınamadı Görüşmeler Kopyalandı Bu dosya ya da klasör kopyalanmaya çalışılırken bir sorun çıktı @@ -311,9 +319,11 @@ Uçtan uca şifreleme henüz kurulmamış İnternet bağlantısı olmadan yapılamaz İmza eşleşmiyor + Üst veriler doğrulanamadı. İmza boş. Yardımcı Diğer Diğer Nextcloud uygulamaları + Dosya seçici açılamadı E-posta adresi alınamadı. Şifrelensin Sunucu sertifikası alınamadı @@ -383,6 +393,7 @@ Bu klasörde dosya oluşturma ya da yükleme izniniz yok. Dış paylaşımlar Ekle ya da yükle + Çakışma penceresi oluşturulamadı Dosya indirme yöneticisine aktarılamadı Dosya yazdırılamadı Düzenleyici başlatılamadı @@ -397,7 +408,6 @@ Bir paylaşım oluşturamazsınız. Bu kullanıcı için paylaşım zaten etkin. Kişilerin seçilmesi için kullanılabilecek bir uygulama yok Ayrıntılar yüklenemedi - Lütfen özel izni seçin Dosya Tut Bazı içerikler yükleyin ya da aygıtlarınızla eşitleyin. @@ -417,6 +427,8 @@ Sorgunuzdan bir sonuç alınamadı Aramanızı başlatın Hesabınızdaki dosyaları, kişileri, takvim etkinliklerini ve diğer şeyleri bulmak için yukarıdaki arama çubuğuna yazın. + İnternet bağlantınızı denetleyip yeniden deneyin + Bağlantı kötü klasör CANLI Yükleniyor … @@ -641,6 +653,7 @@ İnternet bağlantısı yok İnternet bağlantınız olmasa bile klasörlerinizi düzenleyebilir, dosyalar oluşturabilirsiniz. Yeniden çevrim içi olduğunuzda, bekleyen işlemleriniz otomatik olarak eşitlenir. Çevrim dışınız ancak çalışma sürüyor + Dosya henüz yok. Önce lütfen dosyayı yükleyin. %s oluşturulamadı. Sunucuda aynı adlı bir dosya var. %s oluşturulamadı. Sunucuda aynı adlı bir klasör var. Çevrim dışı işlem tamamlanamadı. %s @@ -656,6 +669,7 @@ Diğerleri menüsü Parolanızı yazın Lütfen parolanızı yazın + Parola uygulama her açıldıktan ya da yeniden açıldıktan 5 saniye sonra sorulacak. Parola ile onayı aynı değil Lütfen parolanızı yeniden yazın Parolanızı silin @@ -684,6 +698,8 @@ Yeni sürümün adı değiştirilsin Dosya zaten varsa ne yapılsın? Hesap ekle + Uygulamanın cihazınızdaki tüm dosyalara erişmesine ve yönetmesine izin verin + Tüm dosyalara erişme Takvim ve kişi eşitleme F-Droid ya da Google Play kurulmamış Geçerli hesap için DAVx⁵ (eski adıyla DAVdroid) (v1.3.0+) kurun @@ -919,6 +935,10 @@ İç depolama Filmler Müzikler + Tüm dosyalara erişme + Depolama alanı izni otomatik yükleme için gereklidir. + Depolama alanı izni otomatik dosya yüklemeleri için gereklidir. + Sorulmasın Ortam dosyalarına salt okunur erişim Fotoğraflar Sizin kontrolunuz altında barındırılan üretkenlik platformu.\n\nÖzellikleri:\n* Sunucunuzun temasına uygun, kolay kullanılan, modern arayüz\n* Dosyaları Nextcloud sunucunuza yükleme\n* Başkaları ile paylaşma\n* İstediğiniz dosya ve klasörleri eşitleme\n* Sunucunuzdaki tüm klasörlerde arama\n* Aygıtınızdaki fotoğraf ve görüntüleri otomatik olarak yükleme\n* Güncelleme bildirimleri\n* Birden çok hesap desteği\n* Verilere parmak izi ya da PIN kodu ile güvenli erişim\n* Kolay takvim ve kişi eşitleme kurulumu için DAVx⁵ bütünleştirmesi (eski adı DAVdroid)\n\nLütfen olabilecek sorunları https://github.com/nextcloud/android/issues adresine bildirin ve uygulama ile ilgili görüşlerinizi https://help.nextcloud.com/c/clients/android adresine yazın\n\nNextcloud kullanmaya yeni mi başladınız? Nextcloud kişisel dosyaları eşitlemek ve paylaşmak için kullanılan bir iletişim sunucusudur. Özgür bir yazılımdır ve kendiniz barındırabileceğiniz gibi bir kuruluş üzerinde ücretli olarak barındırabilirsiniz. Böylece fotoğraflarınız, takviminiz, kişi bilgileriniz ve belgeleriniz gibi pek çok veriyi kendi kontrolunuz altında tutabilirsiniz.\n\nNextcloud hakkında bilgi almak için https://nextcloud.com sitesine bakabilirsiniz. @@ -1100,6 +1120,8 @@ Sunucu sertifikasına güvenilmiyor Sunucu sürümü alınıyor… Uygulama sonlandırıldı + Atlandı + Aynı adlı bir dosya zaten var. Tamamlandı Uzakta aynı dosya var olduğundan yüklenmedi Bilinmeyen sorun @@ -1189,6 +1211,10 @@ %d dosya dışa aktarıldı, gerisi bir sorun nedeniyle atlandı %d dosya dışa aktarıldı, gerisi bir sorun nedeniyle atlandı + + Bir kerede en fazla %d dosya yükleyebilirsiniz. + Bir kerede en fazla %d dosya yükleyebilirsiniz. + %1$d klasör %1$d klasör diff --git a/app/src/main/res/values-ug/strings.xml b/app/src/main/res/values-ug/strings.xml index fac835879205..ba41795093e6 100644 --- a/app/src/main/res/values-ug/strings.xml +++ b/app/src/main/res/values-ug/strings.xml @@ -408,7 +408,6 @@ سىز بىر ھەمبەھىر قۇرالمايسىز، ھەمبەھىرلەش بۇ ئىشلەتكۈچىدە ئاكتىپ. ئالاقىداشلارنى تاللاش ئۈچۈن بىرەر ئەپ يوق تەپسىلاتلارنى يۈكلىيەلمىدى - ئىختىيارى ئىجازەتنى تاللاڭ ھۆججەت ساقلاڭ بەزى مەزمۇنلارنى يۈكلەڭ ياكى ئۈسكۈنىڭىز بىلەن ماسقەدەملەڭ. diff --git a/app/src/main/res/values-uk/strings.xml b/app/src/main/res/values-uk/strings.xml index 7eaced248ace..c9ccdbe73e24 100644 --- a/app/src/main/res/values-uk/strings.xml +++ b/app/src/main/res/values-uk/strings.xml @@ -398,7 +398,6 @@ Ви не можете створити спільний ресурс, оскільки його вже надано цьому користувачеві. Відсутній застосунок для вибору контактів Не вдалося завантажити подробиці - Виберіть власні дозволи Файл Зберегти Додати дані або синхронізувати з вашими пристроями. diff --git a/app/src/main/res/values-zh-rCN/strings.xml b/app/src/main/res/values-zh-rCN/strings.xml index facc1b27e15f..36a80b234c09 100644 --- a/app/src/main/res/values-zh-rCN/strings.xml +++ b/app/src/main/res/values-zh-rCN/strings.xml @@ -397,7 +397,6 @@ 您无法创建共享,此用户的共享已处于活动状态。 没有可用于选择联系人的应用 加载详情失败 - 请选择自定义权限 文件 保留 上传一些内容或与你的设备同步。 diff --git a/app/src/main/res/values-zh-rHK/strings.xml b/app/src/main/res/values-zh-rHK/strings.xml index 0db2a070dd0e..79ebf9723261 100644 --- a/app/src/main/res/values-zh-rHK/strings.xml +++ b/app/src/main/res/values-zh-rHK/strings.xml @@ -408,7 +408,6 @@ 您無法創建共享,因為該用戶已經啟用了共享。 沒有應用程式可選取聯絡人 載入詳細資訊失敗 - 請選擇自訂權限 檔案 保留 上傳一些項目或與你的設備同步! diff --git a/app/src/main/res/values-zh-rTW/strings.xml b/app/src/main/res/values-zh-rTW/strings.xml index 03cf1cdafe89..a7b35b245d80 100644 --- a/app/src/main/res/values-zh-rTW/strings.xml +++ b/app/src/main/res/values-zh-rTW/strings.xml @@ -408,7 +408,6 @@ 您無法建立分享,來自此使用者的分享已在作用中。 沒有應用程式可選取聯絡人 載入詳細資訊失敗 - 請選取自訂權限 檔案 保留 上傳一些內容或與您的裝置同步。 From 3bb2d185791af9a31f04aad294f58762191edb2d Mon Sep 17 00:00:00 2001 From: alperozturk Date: Tue, 9 Dec 2025 15:01:54 +0100 Subject: [PATCH 017/216] fix: settings activity action bar padding Signed-off-by: alperozturk --- .../android/ui/activity/SettingsActivity.java | 33 +------------------ 1 file changed, 1 insertion(+), 32 deletions(-) diff --git a/app/src/main/java/com/owncloud/android/ui/activity/SettingsActivity.java b/app/src/main/java/com/owncloud/android/ui/activity/SettingsActivity.java index ffdbfd72ae9a..53b3a9496627 100644 --- a/app/src/main/java/com/owncloud/android/ui/activity/SettingsActivity.java +++ b/app/src/main/java/com/owncloud/android/ui/activity/SettingsActivity.java @@ -24,7 +24,6 @@ import android.content.res.Configuration; import android.graphics.drawable.Drawable; import android.net.Uri; -import android.os.Build; import android.os.Bundle; import android.os.Handler; import android.os.Looper; @@ -41,11 +40,9 @@ import android.view.MenuItem; import android.view.View; import android.view.ViewGroup; -import android.view.WindowManager; import android.webkit.URLUtil; import com.google.android.material.dialog.MaterialAlertDialogBuilder; -import com.nextcloud.android.common.ui.util.extensions.WindowExtensionsKt; import com.nextcloud.client.account.User; import com.nextcloud.client.account.UserAccountManager; import com.nextcloud.client.di.Injectable; @@ -57,7 +54,6 @@ import com.nextcloud.client.preferences.AppPreferencesImpl; import com.nextcloud.client.preferences.DarkMode; import com.nextcloud.utils.extensions.ContextExtensionsKt; -import com.nextcloud.utils.extensions.ViewExtensionsKt; import com.nextcloud.utils.mdm.MDMConfig; import com.owncloud.android.MainApp; import com.owncloud.android.R; @@ -154,23 +150,12 @@ public class SettingsActivity extends PreferenceActivity @SuppressWarnings("deprecation") @Override public void onCreate(Bundle savedInstanceState) { - - boolean isApiLevel35OrHigher = (Build.VERSION.SDK_INT >= 35); - if (isApiLevel35OrHigher) { - final var window = getWindow(); - if (window != null) { - WindowExtensionsKt.addSystemBarPaddings(getWindow()); - final var flag = WindowManager.LayoutParams.FLAG_LAYOUT_NO_LIMITS; - window.setFlags(flag, flag); - } - } - super.onCreate(savedInstanceState); getDelegate().installViewFactory(); getDelegate().onCreate(savedInstanceState); addPreferencesFromResource(R.xml.preferences); - + getListView().setFitsSystemWindows(true); setupActionBar(); // Register context menu for list of preferences. @@ -211,10 +196,6 @@ public void onCreate(Bundle savedInstanceState) { // workaround for mismatched color when app dark mode and system dark mode don't agree setListBackground(); showPasscodeDialogIfEnforceAppProtection(); - - if (isApiLevel35OrHigher) { - adjustTopMarginForActionBar(); - } } public static boolean isBackPressed = false; @@ -230,18 +211,6 @@ public void onBackPressed() { }, 2000); } - private void adjustTopMarginForActionBar() { - if (getListView() == null) { - return; - } - - float topMarginInDp = getResources().getDimension(R.dimen.settings_activity_padding); - int topMarginInPx = DisplayUtils.convertDpToPixel(topMarginInDp, this); - ViewExtensionsKt.setMargins(getListView(), 0, topMarginInPx, 0, 0); - - getWindow().getDecorView().setBackgroundColor(ContextCompat.getColor(this, R.color.bg_default)); - } - private void showPasscodeDialogIfEnforceAppProtection() { if (MDMConfig.INSTANCE.enforceProtection(this) && Objects.equals(preferences.getLockPreference(), SettingsActivity.LOCK_NONE) && lock != null) { lock.showDialog(); From 28c38afc7b58a6fc0d5766d318e45b3d8756498d Mon Sep 17 00:00:00 2001 From: Nextcloud bot Date: Thu, 11 Dec 2025 02:46:34 +0000 Subject: [PATCH 018/216] fix(l10n): Update translations from Transifex Signed-off-by: Nextcloud bot --- app/src/main/res/values-uk/strings.xml | 17 +++++++++++ app/src/main/res/values-zh-rCN/strings.xml | 33 +++++++++++++++++----- 2 files changed, 43 insertions(+), 7 deletions(-) diff --git a/app/src/main/res/values-uk/strings.xml b/app/src/main/res/values-uk/strings.xml index c9ccdbe73e24..848173cbdaed 100644 --- a/app/src/main/res/values-uk/strings.xml +++ b/app/src/main/res/values-uk/strings.xml @@ -45,6 +45,8 @@ Пошук у %s Перебуваю поза мережею Показаний тут результат генерується штучним інтелектом. Обов\'язково перевіряйте його двічі. + Не вдалося надіслати повідомлення + Не вдалося отримати повідомлення чату Дійсно вилучити це завдання? Вилучити завдання Спробуйте надіслати повідомлення, щоб розпочати розмову. @@ -60,6 +62,7 @@ Помічник Введення Виведення + Думаю ... Пов\'язаний обліковий запис не знайдено! Доступ невдалий: %1$s Обліковий запис все ще не створено на цьому пристрої @@ -209,8 +212,12 @@ Файл не знайдено Неможливо знайти вашу останню резервну копію Пошук змін у вмісті + Не вдалося створити розмову + Вилучити розмову + Не вдалося вилучити розмову Розмов не знайдено Поки що немає розмов + Не вдалося отримати список розмов Розмови Скопійовано Виникла помилка під час спроби копіювати цей файл або каталог @@ -312,9 +319,11 @@ Наскрізне шифруванння ще не налаштовано Дія не можлива без доступу до з\'єднання з мережею Підпис не збігається + Не вдалося перевірити метадані, сиґнатура порожня. Помічник Більше Більше застосунків Nextcloud + Неможливо відкрити вибір файлів Не вдалося вибрати ел. адресу. Позначити як зашифроване Неможливо отримати сертифікат сервера @@ -384,6 +393,7 @@ У вас відсутній доступ на створення або завантаження файлів до цього каталогу. Зовнішні спільні ресурси Додати або завантажити + Не вдалося створити вікно з інформацією про конфлікт Не вдалося передати файл до менеджера звантажень Не вдалося роздрукувати файл Не вдалося відкрити редактор @@ -643,6 +653,7 @@ Відсутнє з\'єднання з мережею Ви можете впорядковувати каталоги, створювати файли без наявного з\'єднання з мережею. Одразу після відновлення доступу завдання, що в очікуванні, буде автоматично виконано, а файли синхронізовано. Ви користуєтеся застосунком без доступу до мережі + Поки відсутні файли. Спочатку додайте їх. Не вдалося створити %s. Файл з таким ім\'ям вже присутній у хмарі. Не вдалося створити %s. Каталог з таким ім\'ям вже присутній у хмарі. Неможливо виконати офлайнову операцію. %s @@ -687,6 +698,8 @@ Перейменовувати нову версію Що робити, якщо такий файл вже присутній? Додати обліковий запис + Дозволити застосунку доступ та керування всіма файлами на вашому пристрої + Доступ до всіх файлів Синхронізувати календар та контакти Не встановлено ані F-Droid, ані Google Play Встановити DAVx⁵ (раніше відомий як DAVdroid) (v1.3.0+) для поточного користувача @@ -922,6 +935,10 @@ Внутрішнє сховище Відео Музика + Доступ до всіх файлів + Для автоматичного завантаження потрібно надати доступ до місця збереження файлів + Для завантаження файлів потрібно надати доступ до місця збереження файлів + Не питати Мультимедія лише для читання Зображення Самостійна платформа для підвищення продуктивності, яка дозволяє вам зберігати контроль. n\nОсобливості:\n* Простий, сучасний інтерфейс, що відповідає темі вашого сервера\n* Завантажуйте файли на ваш сервер Nextcloud\n* Діліться ними з іншими\n* Синхронізуйте ваші улюблені файли та папки\n* Здійснюйте пошук у всіх папках на вашому сервері\n* Автоматичне завантаження фотографій та відео, зроблених вашим пристроєм\n* Будьте в курсі подій завдяки сповіщенням\n* Підтримка декількох облікових записів\n* Безпечний доступ до ваших даних за допомогою відбитка пальця або PIN-коду\n* Інтеграція з DAVx⁵ (раніше відомим як DAVdroid) для легкого налаштування синхронізації календаря та контактів\n\nБудь ласка, повідомляйте про всі проблеми на https://github.com/nextcloud/android/issues та обговорюйте цей додаток на https://help.nextcloud.com/c/clients/android\n\nНовий у Nextcloud? Nextcloud — це приватний сервер для синхронізації та обміну файлами, а також для спілкування. Це вільне програмне забезпечення, яке ви можете розмістити самостійно або заплатити компанії, щоб вона зробила це за вас. Таким чином, ви контролюєте свої фотографії, календар і контакти, документи та все інше.\n\nОзнайомтеся з Nextcloud на https://nextcloud.com diff --git a/app/src/main/res/values-zh-rCN/strings.xml b/app/src/main/res/values-zh-rCN/strings.xml index 36a80b234c09..744a36118c34 100644 --- a/app/src/main/res/values-zh-rCN/strings.xml +++ b/app/src/main/res/values-zh-rCN/strings.xml @@ -44,7 +44,9 @@ 显示仪表盘中的一个小部件 在 %s 中搜索 显示为离线 - 此处显示的输出是由人工智慧产生的。请务必仔细检查。 + 此处显示的输出结果由 AI 生成。请务必仔细检查。 + 无法发送消息 + 无法获取聊天消息 您确定要删除这些任务吗? 删除任务 尝试发送消息来发起对话。 @@ -53,12 +55,14 @@ 任务已创建 删除任务时发生错误 任务已删除 + 任务列表为空。请检查助手应用配置。 无法获取任务列表,请检查你的互联网连接。 删除任务 任务输出尚未就绪。 助手 输入 输出结果 + 正在思考 … 相关账号未找到! 访问已失败: %1$s 该账号尚未添加到此设备上 @@ -208,10 +212,14 @@ 没有文件被发现 无法找到末次备份 正在检测内容更改 + 无法创建对话 删除对话 + 无法删除对话 未找到对话 尚无对话 + 无法获取对话列表 对话 + 已复制 尝试复制这个文件或文件夹时发生了错误 将文件夹复制到其自己的底层文件夹中是不可能的 该文件已存在于目标文件夹中 @@ -311,9 +319,11 @@ 尚未安装端到端加密 无互联网连接 签名不匹配 + 无法验证元数据,签名为空。 助手 更多 更多 Nextcloud 应用 + 无法打开文件选择器 未能选择电子邮箱地址 设置为加密 无法检索服务器证书 @@ -383,13 +393,14 @@ 您没有在此文件夹中创建或上传文件的权限。 外部共享 添加或上传 + 无法创建冲突对话框 无法将文件传递给下载管理器 打印文件已失败 启动编辑器失败 更新用户界面失败 添加到收藏夹 收藏 - 15 分钟 + 15 分钟 无法更新已共享文件 文件名已存在 删除 @@ -416,8 +427,8 @@ 未找到查询的结果 开始搜索 在上方搜索栏中输入以查找您账号中的文件、联系人、日历事件等。 - 检查你的网络连接或稍后再试 - 连接差 + 请检查您的互联网连接或稍后重试 + 连接不良 文件夹 即时 正在加载... @@ -642,6 +653,7 @@ 无网络连接 即使没有互联网连接,你也可以组织文件夹、创建文件。一旦您重新在线,你的待处理操作将自动同步。 您已离线,但工作仍在继续 + 文件尚不存在。请先上传文件。 无法创建 %s。服务器上存在同名文件。 无法创建 %s。服务器上存在同名文件夹。 无法完成离线操作。%s @@ -657,6 +669,7 @@ 更多菜单 输入安全码 请输入安全码 + 每次打开或 5 秒后重新打开应用时,都会请求输入安全码。 安全码不一致 请再次输入安全码 删除安全码 @@ -685,6 +698,8 @@ 重命名新版本 如果文件已经存在怎么办? 添加账号 + 允许应用访问和管理您设备上的所有文件 + 所有文件访问权限 同步日历和联系人 F-droid 和 Google Play 都没有安装 为当前账号设置 DAVx⁵(以前称为 DAVdroid)(v1.3.0+) @@ -920,6 +935,10 @@ 内部存储 影片 音乐 + 所有文件访问权限 + 自动上传需要存储权限。 + 文件上传需要存储权限。 + 不要询问 媒体只读权限 图片 自托管生产力平台,让您掌控一切。\n\n特征:\n* 简单、现代的界面,适合您的服务器主题\n* 将文件上传到您的 Nextcloud 服务器\n* 与他人分享\n* 保持您喜爱的文件和文件夹同步\n* 搜索服务器上的所有文件夹\n* 自动上传您设备拍摄的照片和视频\n* 随时接收通知\n* 多账号支持\n* 使用指纹或 PIN 安全访问您的数据\n*与 DAVx⁵ 集成(以前称为 DAVdroid),用于轻松设置日历和联系人同步\n\n请在 https://github.com/nextcloud/android/issues 上报告所有问题,并在 https://help.nextcloud.com/c/clients/android 上讨论此应用\n\n您是 Nextcloud 的新用户吗?Nextcloud 是一个私人文件同步、分享和通信服务器。它是自由软件,您可以自行托管,也可以付费让公司为您托管。这样,您就可以掌控您的照片、日历和联系人数据、文档以及其他所有内容。\n\n访问 https://nextcloud.com 查看 Nextcloud @@ -1104,8 +1123,8 @@ 不受信任的服务器证书 正在获取服务器版本… 应用程序已终止 - 跳过 - 相同名称的文件已存在。 + 已跳过 + 同名文件已存在。 已完成 服务端已存在相同的文件,跳过上传 未知错误 @@ -1182,7 +1201,7 @@ 导出了 %d 个文件,跳过了出错的其余部分 - 你一次可以最多上传 %d 个文件。 + 您一次最多可以上传 %d 个文件。 %1$d个文件夹 From 28237219113e6e8e04a00edcfe5280931ef17e53 Mon Sep 17 00:00:00 2001 From: alperozturk Date: Fri, 12 Dec 2025 13:13:23 +0100 Subject: [PATCH 019/216] fix: calculate scan interval network on main thread exception Signed-off-by: alperozturk --- .../ui/activity/SyncedFoldersActivity.kt | 1 + .../android/ui/adapter/SyncedFolderAdapter.kt | 23 +++++++++++++------ 2 files changed, 17 insertions(+), 7 deletions(-) diff --git a/app/src/main/java/com/owncloud/android/ui/activity/SyncedFoldersActivity.kt b/app/src/main/java/com/owncloud/android/ui/activity/SyncedFoldersActivity.kt index 96a853af2a40..b26797716930 100644 --- a/app/src/main/java/com/owncloud/android/ui/activity/SyncedFoldersActivity.kt +++ b/app/src/main/java/com/owncloud/android/ui/activity/SyncedFoldersActivity.kt @@ -240,6 +240,7 @@ class SyncedFoldersActivity : val gridWidth = resources.getInteger(R.integer.media_grid_width) val lightVersion = resources.getBoolean(R.bool.syncedFolder_light) adapter = SyncedFolderAdapter( + lifecycleScope, this, clock, gridWidth, diff --git a/app/src/main/java/com/owncloud/android/ui/adapter/SyncedFolderAdapter.kt b/app/src/main/java/com/owncloud/android/ui/adapter/SyncedFolderAdapter.kt index e701d4468daa..9573d7c11476 100644 --- a/app/src/main/java/com/owncloud/android/ui/adapter/SyncedFolderAdapter.kt +++ b/app/src/main/java/com/owncloud/android/ui/adapter/SyncedFolderAdapter.kt @@ -17,6 +17,7 @@ import android.widget.PopupMenu import androidx.annotation.VisibleForTesting import androidx.core.content.ContextCompat import androidx.core.view.isVisible +import androidx.lifecycle.LifecycleCoroutineScope import com.afollestad.sectionedrecyclerview.SectionedRecyclerViewAdapter import com.afollestad.sectionedrecyclerview.SectionedViewHolder import com.google.android.material.button.MaterialButton @@ -40,6 +41,9 @@ import com.owncloud.android.datamodel.ThumbnailsCacheManager import com.owncloud.android.datamodel.ThumbnailsCacheManager.AsyncMediaThumbnailDrawable import com.owncloud.android.datamodel.ThumbnailsCacheManager.MediaThumbnailGenerationTask import com.owncloud.android.utils.theme.ViewThemeUtils +import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.launch +import kotlinx.coroutines.withContext import java.io.File import java.util.Locale import java.util.concurrent.Executor @@ -51,6 +55,7 @@ import java.util.concurrent.TimeUnit */ @Suppress("LongParameterList", "TooManyFunctions") class SyncedFolderAdapter( + private val lifecycleScope: LifecycleCoroutineScope, private val context: Context, private val clock: Clock, private val gridWidth: Int, @@ -313,15 +318,19 @@ class SyncedFolderAdapter( } private fun initNextScanIndicator(holder: HeaderViewHolder, syncedFolder: SyncedFolder) { - val scanIndicatorText = getNextScanIndicatorText(syncedFolder) + lifecycleScope.launch(Dispatchers.IO) { + val scanIndicatorText = getNextScanIndicatorText(syncedFolder) - holder.binding.scanIndicatorText.setVisibleIf(syncedFolder.isEnabled && (scanIndicatorText != null)) + withContext(Dispatchers.Main) { + holder.binding.scanIndicatorText.setVisibleIf(syncedFolder.isEnabled && (scanIndicatorText != null)) - if (holder.binding.scanIndicatorText.isVisible) { - setMaxWidthOfScanIndicatorText(holder) - holder.binding.scanIndicatorText.text = scanIndicatorText - } else { - setBottomMarginOfTitle(holder) + if (holder.binding.scanIndicatorText.isVisible) { + setMaxWidthOfScanIndicatorText(holder) + holder.binding.scanIndicatorText.text = scanIndicatorText + } else { + setBottomMarginOfTitle(holder) + } + } } } From ea6c03fc3dda64132f77acb805c0765fe49546a3 Mon Sep 17 00:00:00 2001 From: alperozturk Date: Tue, 9 Dec 2025 16:38:13 +0100 Subject: [PATCH 020/216] fix: favorite sub file visibility Signed-off-by: alperozturk --- .../android/ui/adapter/helper/OCFileListAdapterHelper.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/src/main/java/com/owncloud/android/ui/adapter/helper/OCFileListAdapterHelper.kt b/app/src/main/java/com/owncloud/android/ui/adapter/helper/OCFileListAdapterHelper.kt index 9d1fd774e87f..c4b301a189c4 100644 --- a/app/src/main/java/com/owncloud/android/ui/adapter/helper/OCFileListAdapterHelper.kt +++ b/app/src/main/java/com/owncloud/android/ui/adapter/helper/OCFileListAdapterHelper.kt @@ -94,7 +94,7 @@ class OCFileListAdapterHelper { continue } - if (isFavoritesView && !file.isFavorite) { + if (isFavoritesView && !file.isFavorite && !directory.isFavorite) { continue } From aca4bc87194b8d5b3fef0ed786bb62f734bd9153 Mon Sep 17 00:00:00 2001 From: alperozturk Date: Tue, 9 Dec 2025 16:42:11 +0100 Subject: [PATCH 021/216] fix: shared sub file visibility Signed-off-by: alperozturk --- .../datamodel/FileDataStorageManager.java | 24 ------------------- .../adapter/helper/OCFileListAdapterHelper.kt | 2 +- 2 files changed, 1 insertion(+), 25 deletions(-) diff --git a/app/src/main/java/com/owncloud/android/datamodel/FileDataStorageManager.java b/app/src/main/java/com/owncloud/android/datamodel/FileDataStorageManager.java index f63196e8fcfa..01508657858e 100644 --- a/app/src/main/java/com/owncloud/android/datamodel/FileDataStorageManager.java +++ b/app/src/main/java/com/owncloud/android/datamodel/FileDataStorageManager.java @@ -43,7 +43,6 @@ import com.nextcloud.client.database.entity.OfflineOperationEntity; import com.nextcloud.client.jobs.offlineOperations.repository.OfflineOperationsRepository; import com.nextcloud.client.jobs.offlineOperations.repository.OfflineOperationsRepositoryType; -import com.nextcloud.model.OCFileFilterType; import com.nextcloud.model.OfflineOperationRawType; import com.nextcloud.model.OfflineOperationType; import com.nextcloud.model.ShareeEntry; @@ -2755,29 +2754,6 @@ public boolean isPartOfInternalTwoWaySync(OCFile file) { return false; } - public List filter(OCFile file, OCFileFilterType filterType) { - if (!file.isRootDirectory()) { - return getFolderContent(file,false); - } - - final List result = new ArrayList<>(); - final List allFiles = getAllFiles(); - for (OCFile ocFile: allFiles) { - boolean condition = false; - if (filterType == OCFileFilterType.Shared) { - condition = ocFile.isShared(); - } else if (filterType == OCFileFilterType.Favorite) { - condition = ocFile.isFavorite(); - } - - if (condition) { - result.add(ocFile); - } - } - - return result; - } - @Nullable public FileEntity getFileEntity(OCFile file) { if (file == null) { diff --git a/app/src/main/java/com/owncloud/android/ui/adapter/helper/OCFileListAdapterHelper.kt b/app/src/main/java/com/owncloud/android/ui/adapter/helper/OCFileListAdapterHelper.kt index c4b301a189c4..97b1d649cb7d 100644 --- a/app/src/main/java/com/owncloud/android/ui/adapter/helper/OCFileListAdapterHelper.kt +++ b/app/src/main/java/com/owncloud/android/ui/adapter/helper/OCFileListAdapterHelper.kt @@ -90,7 +90,7 @@ class OCFileListAdapterHelper { } } - if (isSharedView && !file.isShared) { + if (isSharedView && !file.isShared && !directory.isShared) { continue } From b4128f69cb239a7abfa034e0e0d50c24f717264a Mon Sep 17 00:00:00 2001 From: alperozturk Date: Wed, 10 Dec 2025 08:15:08 +0100 Subject: [PATCH 022/216] add tests Signed-off-by: alperozturk --- .../adapter/helper/OCFileListAdapterHelper.kt | 4 +- .../ui/adapter/OCFileListAdapterHelperTest.kt | 58 +++++++++++++++++++ 2 files changed, 60 insertions(+), 2 deletions(-) diff --git a/app/src/main/java/com/owncloud/android/ui/adapter/helper/OCFileListAdapterHelper.kt b/app/src/main/java/com/owncloud/android/ui/adapter/helper/OCFileListAdapterHelper.kt index 97b1d649cb7d..06956fa0655b 100644 --- a/app/src/main/java/com/owncloud/android/ui/adapter/helper/OCFileListAdapterHelper.kt +++ b/app/src/main/java/com/owncloud/android/ui/adapter/helper/OCFileListAdapterHelper.kt @@ -90,11 +90,11 @@ class OCFileListAdapterHelper { } } - if (isSharedView && !file.isShared && !directory.isShared) { + if (isSharedView && !directory.isShared && !file.isShared) { continue } - if (isFavoritesView && !file.isFavorite && !directory.isFavorite) { + if (isFavoritesView && !directory.isFavorite && !file.isFavorite) { continue } diff --git a/app/src/test/java/com/owncloud/android/ui/adapter/OCFileListAdapterHelperTest.kt b/app/src/test/java/com/owncloud/android/ui/adapter/OCFileListAdapterHelperTest.kt index 65db28cfe60a..fc4d5900a367 100644 --- a/app/src/test/java/com/owncloud/android/ui/adapter/OCFileListAdapterHelperTest.kt +++ b/app/src/test/java/com/owncloud/android/ui/adapter/OCFileListAdapterHelperTest.kt @@ -130,6 +130,64 @@ class OCFileListAdapterHelperTest { assertEquals(FileSortOrder.SORT_Z_TO_A, sort) } + @Test + fun `prepareFileList favorites tab`() = runBlocking { + val env = Sut() + val root = env.root + + val sub1 = env.directory("/subDir", 1).apply { + isFavorite = true + } + val file1 = env.file(sub1, "image.jpg", 11, MimeType.JPEG) + val file2 = env.file(sub1, "image2.jpg", 12, MimeType.JPEG) + val file3 = env.file(sub1, "image3.jpg", 13, MimeType.JPEG) + val file4 = env.file(sub1, "vid4.mp4", 14, MimeType.MP4) + val file5 = env.file(sub1, "image5.jpg", 15, MimeType.JPEG) + + val sub2 = env.directory("/subDir2", 2).apply { + isFavorite = true + } + val file6 = env.file(sub2, "image6.jpg", 16, MimeType.JPEG) + + env.prepare(listOf(root, sub1, sub2, file1, file2, file3, file4, file5, file6)) + stubPreferences(sort = FileSortOrder.SORT_A_TO_Z, favFirst = true) + val (list, sort) = env.run(sub1) + assertEquals( + listOf("image.jpg", "image2.jpg", "image3.jpg", "image5.jpg", "vid4.mp4"), + list.map { it.fileName } + ) + assertEquals(FileSortOrder.SORT_A_TO_Z, sort) + } + + @Test + fun `prepareFileList share tab`() = runBlocking { + val env = Sut() + val root = env.root + + val sub1 = env.directory("/subDir", 1).apply { + isSharedViaLink = true + } + val file1 = env.file(sub1, "image.jpg", 11, MimeType.JPEG) + val file2 = env.file(sub1, "image2.jpg", 12, MimeType.JPEG) + val file3 = env.file(sub1, "image3.jpg", 13, MimeType.JPEG) + val file4 = env.file(sub1, "vid4.mp4", 14, MimeType.MP4) + val file5 = env.file(sub1, "image5.jpg", 15, MimeType.JPEG) + + val sub2 = env.directory("/subDir2", 2).apply { + isFavorite = true + } + val file6 = env.file(sub2, "image6.jpg", 16, MimeType.JPEG) + + env.prepare(listOf(root, sub1, sub2, file1, file2, file3, file4, file5, file6)) + stubPreferences(sort = FileSortOrder.SORT_A_TO_Z, favFirst = true) + val (list, sort) = env.run(sub1) + assertEquals( + listOf("image.jpg", "image2.jpg", "image3.jpg", "image5.jpg", "vid4.mp4"), + list.map { it.fileName } + ) + assertEquals(FileSortOrder.SORT_A_TO_Z, sort) + } + @Test fun `prepareFileList with multiple folders and favorites first`() = runBlocking { val env = Sut() From a29fc515571b35f58a2d4b4bcae2dc39647355c1 Mon Sep 17 00:00:00 2001 From: alperozturk Date: Wed, 10 Dec 2025 08:47:22 +0100 Subject: [PATCH 023/216] remove unused source Signed-off-by: alperozturk --- .../java/com/nextcloud/model/OCFileFilterType.kt | 13 ------------- 1 file changed, 13 deletions(-) delete mode 100644 app/src/main/java/com/nextcloud/model/OCFileFilterType.kt diff --git a/app/src/main/java/com/nextcloud/model/OCFileFilterType.kt b/app/src/main/java/com/nextcloud/model/OCFileFilterType.kt deleted file mode 100644 index 81451c242346..000000000000 --- a/app/src/main/java/com/nextcloud/model/OCFileFilterType.kt +++ /dev/null @@ -1,13 +0,0 @@ -/* - * Nextcloud - Android Client - * - * SPDX-FileCopyrightText: 2024 Alper Ozturk - * SPDX-License-Identifier: AGPL-3.0-or-later - */ - -package com.nextcloud.model - -enum class OCFileFilterType { - Shared, - Favorite -} From 2e3e7e8a1e569397774c80671abc86f9252992dd Mon Sep 17 00:00:00 2001 From: alperozturk Date: Wed, 10 Dec 2025 09:18:59 +0100 Subject: [PATCH 024/216] check nested files Signed-off-by: alperozturk --- .../nextcloud/client/database/dao/FileDao.kt | 18 +++++++++++++ .../OCFileListAdapterDataProviderImpl.kt | 27 +++++++++++++++++++ .../helper/OCFileListAdapterDataProvider.kt | 2 ++ .../adapter/helper/OCFileListAdapterHelper.kt | 6 +++-- .../MockOCFileListAdapterDataProvider.kt | 6 +++++ .../ui/adapter/OCFileListAdapterHelperTest.kt | 7 +++++ 6 files changed, 64 insertions(+), 2 deletions(-) diff --git a/app/src/main/java/com/nextcloud/client/database/dao/FileDao.kt b/app/src/main/java/com/nextcloud/client/database/dao/FileDao.kt index 06a94aaafdff..3779819f95c0 100644 --- a/app/src/main/java/com/nextcloud/client/database/dao/FileDao.kt +++ b/app/src/main/java/com/nextcloud/client/database/dao/FileDao.kt @@ -146,4 +146,22 @@ interface FileDao { @Query("SELECT remote_id FROM filelist WHERE file_owner = :accountName AND remote_id IS NOT NULL") fun getAllRemoteIds(accountName: String): List + + @Query("SELECT parent FROM filelist WHERE _id = :fileId LIMIT 1") + suspend fun getParentId(fileId: Long): Long? + + @Query("SELECT favorite FROM filelist WHERE _id = :fileId LIMIT 1") + suspend fun isFavoriteFolder(fileId: Long): Int? + + @Query( + """ + SELECT + (share_by_link = 1) OR + (shared_via_users = 1) OR + (permissions LIKE '%S%') + FROM filelist + WHERE _id = :fileId LIMIT 1 + """ + ) + suspend fun isSharedFolder(fileId: Long): Boolean? } diff --git a/app/src/main/java/com/owncloud/android/datamodel/OCFileListAdapterDataProviderImpl.kt b/app/src/main/java/com/owncloud/android/datamodel/OCFileListAdapterDataProviderImpl.kt index 66622510612f..dfc39ee2457d 100644 --- a/app/src/main/java/com/owncloud/android/datamodel/OCFileListAdapterDataProviderImpl.kt +++ b/app/src/main/java/com/owncloud/android/datamodel/OCFileListAdapterDataProviderImpl.kt @@ -10,6 +10,7 @@ package com.owncloud.android.datamodel import com.nextcloud.client.database.entity.FileEntity import com.owncloud.android.ui.adapter.helper.OCFileListAdapterDataProvider +@Suppress("ReturnCount") class OCFileListAdapterDataProviderImpl(private val storageManager: FileDataStorageManager) : OCFileListAdapterDataProvider { override fun convertToOCFiles(id: Long): List = @@ -19,4 +20,30 @@ class OCFileListAdapterDataProviderImpl(private val storageManager: FileDataStor storageManager.fileDao.getFolderContentSuspended(id) override fun createFileInstance(entity: FileEntity): OCFile = storageManager.createFileInstance(entity) + + override suspend fun hasFavoriteParent(fileId: Long): Boolean { + var currentId: Long? = fileId + + while (currentId != null) { + val parentId = storageManager.fileDao.getParentId(currentId) ?: return false + val isFavorite = storageManager.fileDao.isFavoriteFolder(parentId) == 1 + if (isFavorite) return true + currentId = parentId + } + + return false + } + + override suspend fun hasSharedParent(fileId: Long): Boolean { + var currentId: Long? = fileId + + while (currentId != null) { + val parentId = storageManager.fileDao.getParentId(currentId) ?: return false + val isShared = storageManager.fileDao.isSharedFolder(parentId) == true + if (isShared) return true + currentId = parentId + } + + return false + } } diff --git a/app/src/main/java/com/owncloud/android/ui/adapter/helper/OCFileListAdapterDataProvider.kt b/app/src/main/java/com/owncloud/android/ui/adapter/helper/OCFileListAdapterDataProvider.kt index 191b7ce666e3..0dd7387e706e 100644 --- a/app/src/main/java/com/owncloud/android/ui/adapter/helper/OCFileListAdapterDataProvider.kt +++ b/app/src/main/java/com/owncloud/android/ui/adapter/helper/OCFileListAdapterDataProvider.kt @@ -14,4 +14,6 @@ interface OCFileListAdapterDataProvider { fun convertToOCFiles(id: Long): List suspend fun getFolderContent(id: Long): List fun createFileInstance(entity: FileEntity): OCFile + suspend fun hasFavoriteParent(fileId: Long): Boolean + suspend fun hasSharedParent(fileId: Long): Boolean } diff --git a/app/src/main/java/com/owncloud/android/ui/adapter/helper/OCFileListAdapterHelper.kt b/app/src/main/java/com/owncloud/android/ui/adapter/helper/OCFileListAdapterHelper.kt index 06956fa0655b..b3b6c2a68a18 100644 --- a/app/src/main/java/com/owncloud/android/ui/adapter/helper/OCFileListAdapterHelper.kt +++ b/app/src/main/java/com/owncloud/android/ui/adapter/helper/OCFileListAdapterHelper.kt @@ -90,11 +90,13 @@ class OCFileListAdapterHelper { } } - if (isSharedView && !directory.isShared && !file.isShared) { + val hasSharedParent = dataProvider.hasSharedParent(file.fileId) + if (isSharedView && !hasSharedParent && !file.isShared) { continue } - if (isFavoritesView && !directory.isFavorite && !file.isFavorite) { + val hasFavoriteParent = dataProvider.hasFavoriteParent(file.fileId) + if (isFavoritesView && !hasFavoriteParent && !file.isFavorite) { continue } diff --git a/app/src/test/java/com/owncloud/android/ui/adapter/MockOCFileListAdapterDataProvider.kt b/app/src/test/java/com/owncloud/android/ui/adapter/MockOCFileListAdapterDataProvider.kt index c2b71334a569..baeca7f3f8e5 100644 --- a/app/src/test/java/com/owncloud/android/ui/adapter/MockOCFileListAdapterDataProvider.kt +++ b/app/src/test/java/com/owncloud/android/ui/adapter/MockOCFileListAdapterDataProvider.kt @@ -17,6 +17,8 @@ class MockOCFileListAdapterDataProvider : OCFileListAdapterDataProvider { private var offlineOCFile: OCFile? = null private var files = listOf() + var hasFavoriteParent = false + var hasSharedParent = false private fun getEntities(): List = files.map { file -> FileEntity( @@ -94,4 +96,8 @@ class MockOCFileListAdapterDataProvider : OCFileListAdapterDataProvider { } override fun createFileInstance(entity: FileEntity): OCFile = files.first { it.fileId == entity.id } + + override suspend fun hasFavoriteParent(fileId: Long): Boolean = hasFavoriteParent + + override suspend fun hasSharedParent(fileId: Long): Boolean = hasSharedParent } diff --git a/app/src/test/java/com/owncloud/android/ui/adapter/OCFileListAdapterHelperTest.kt b/app/src/test/java/com/owncloud/android/ui/adapter/OCFileListAdapterHelperTest.kt index fc4d5900a367..d318fcffdd76 100644 --- a/app/src/test/java/com/owncloud/android/ui/adapter/OCFileListAdapterHelperTest.kt +++ b/app/src/test/java/com/owncloud/android/ui/adapter/OCFileListAdapterHelperTest.kt @@ -79,6 +79,7 @@ class OCFileListAdapterHelperTest { this.localId = localId etag = "etag_$id" storagePath = localPath + sharees = emptyList() } fun prepare(files: List, offline: OCFile? = null) { @@ -149,6 +150,9 @@ class OCFileListAdapterHelperTest { } val file6 = env.file(sub2, "image6.jpg", 16, MimeType.JPEG) + dataProvider.hasFavoriteParent = true + dataProvider.hasSharedParent = false + env.prepare(listOf(root, sub1, sub2, file1, file2, file3, file4, file5, file6)) stubPreferences(sort = FileSortOrder.SORT_A_TO_Z, favFirst = true) val (list, sort) = env.run(sub1) @@ -178,6 +182,9 @@ class OCFileListAdapterHelperTest { } val file6 = env.file(sub2, "image6.jpg", 16, MimeType.JPEG) + dataProvider.hasFavoriteParent = false + dataProvider.hasSharedParent = true + env.prepare(listOf(root, sub1, sub2, file1, file2, file3, file4, file5, file6)) stubPreferences(sort = FileSortOrder.SORT_A_TO_Z, favFirst = true) val (list, sort) = env.run(sub1) From ecba9124274aa7e4e02b767370a8fc69984dccbb Mon Sep 17 00:00:00 2001 From: alperozturk Date: Wed, 10 Dec 2025 10:38:16 +0100 Subject: [PATCH 025/216] remove filters Signed-off-by: alperozturk --- .../nextcloud/client/database/dao/FileDao.kt | 18 ------------- .../OCFileListAdapterDataProviderImpl.kt | 26 ------------------- .../helper/OCFileListAdapterDataProvider.kt | 2 -- .../adapter/helper/OCFileListAdapterHelper.kt | 10 ------- .../MockOCFileListAdapterDataProvider.kt | 6 ----- .../ui/adapter/OCFileListAdapterHelperTest.kt | 6 ----- 6 files changed, 68 deletions(-) diff --git a/app/src/main/java/com/nextcloud/client/database/dao/FileDao.kt b/app/src/main/java/com/nextcloud/client/database/dao/FileDao.kt index 3779819f95c0..06a94aaafdff 100644 --- a/app/src/main/java/com/nextcloud/client/database/dao/FileDao.kt +++ b/app/src/main/java/com/nextcloud/client/database/dao/FileDao.kt @@ -146,22 +146,4 @@ interface FileDao { @Query("SELECT remote_id FROM filelist WHERE file_owner = :accountName AND remote_id IS NOT NULL") fun getAllRemoteIds(accountName: String): List - - @Query("SELECT parent FROM filelist WHERE _id = :fileId LIMIT 1") - suspend fun getParentId(fileId: Long): Long? - - @Query("SELECT favorite FROM filelist WHERE _id = :fileId LIMIT 1") - suspend fun isFavoriteFolder(fileId: Long): Int? - - @Query( - """ - SELECT - (share_by_link = 1) OR - (shared_via_users = 1) OR - (permissions LIKE '%S%') - FROM filelist - WHERE _id = :fileId LIMIT 1 - """ - ) - suspend fun isSharedFolder(fileId: Long): Boolean? } diff --git a/app/src/main/java/com/owncloud/android/datamodel/OCFileListAdapterDataProviderImpl.kt b/app/src/main/java/com/owncloud/android/datamodel/OCFileListAdapterDataProviderImpl.kt index dfc39ee2457d..3f09d4d6e276 100644 --- a/app/src/main/java/com/owncloud/android/datamodel/OCFileListAdapterDataProviderImpl.kt +++ b/app/src/main/java/com/owncloud/android/datamodel/OCFileListAdapterDataProviderImpl.kt @@ -20,30 +20,4 @@ class OCFileListAdapterDataProviderImpl(private val storageManager: FileDataStor storageManager.fileDao.getFolderContentSuspended(id) override fun createFileInstance(entity: FileEntity): OCFile = storageManager.createFileInstance(entity) - - override suspend fun hasFavoriteParent(fileId: Long): Boolean { - var currentId: Long? = fileId - - while (currentId != null) { - val parentId = storageManager.fileDao.getParentId(currentId) ?: return false - val isFavorite = storageManager.fileDao.isFavoriteFolder(parentId) == 1 - if (isFavorite) return true - currentId = parentId - } - - return false - } - - override suspend fun hasSharedParent(fileId: Long): Boolean { - var currentId: Long? = fileId - - while (currentId != null) { - val parentId = storageManager.fileDao.getParentId(currentId) ?: return false - val isShared = storageManager.fileDao.isSharedFolder(parentId) == true - if (isShared) return true - currentId = parentId - } - - return false - } } diff --git a/app/src/main/java/com/owncloud/android/ui/adapter/helper/OCFileListAdapterDataProvider.kt b/app/src/main/java/com/owncloud/android/ui/adapter/helper/OCFileListAdapterDataProvider.kt index 0dd7387e706e..191b7ce666e3 100644 --- a/app/src/main/java/com/owncloud/android/ui/adapter/helper/OCFileListAdapterDataProvider.kt +++ b/app/src/main/java/com/owncloud/android/ui/adapter/helper/OCFileListAdapterDataProvider.kt @@ -14,6 +14,4 @@ interface OCFileListAdapterDataProvider { fun convertToOCFiles(id: Long): List suspend fun getFolderContent(id: Long): List fun createFileInstance(entity: FileEntity): OCFile - suspend fun hasFavoriteParent(fileId: Long): Boolean - suspend fun hasSharedParent(fileId: Long): Boolean } diff --git a/app/src/main/java/com/owncloud/android/ui/adapter/helper/OCFileListAdapterHelper.kt b/app/src/main/java/com/owncloud/android/ui/adapter/helper/OCFileListAdapterHelper.kt index b3b6c2a68a18..28127ce835ee 100644 --- a/app/src/main/java/com/owncloud/android/ui/adapter/helper/OCFileListAdapterHelper.kt +++ b/app/src/main/java/com/owncloud/android/ui/adapter/helper/OCFileListAdapterHelper.kt @@ -90,16 +90,6 @@ class OCFileListAdapterHelper { } } - val hasSharedParent = dataProvider.hasSharedParent(file.fileId) - if (isSharedView && !hasSharedParent && !file.isShared) { - continue - } - - val hasFavoriteParent = dataProvider.hasFavoriteParent(file.fileId) - if (isFavoritesView && !hasFavoriteParent && !file.isFavorite) { - continue - } - if (file.isTempFile()) { continue } diff --git a/app/src/test/java/com/owncloud/android/ui/adapter/MockOCFileListAdapterDataProvider.kt b/app/src/test/java/com/owncloud/android/ui/adapter/MockOCFileListAdapterDataProvider.kt index baeca7f3f8e5..c2b71334a569 100644 --- a/app/src/test/java/com/owncloud/android/ui/adapter/MockOCFileListAdapterDataProvider.kt +++ b/app/src/test/java/com/owncloud/android/ui/adapter/MockOCFileListAdapterDataProvider.kt @@ -17,8 +17,6 @@ class MockOCFileListAdapterDataProvider : OCFileListAdapterDataProvider { private var offlineOCFile: OCFile? = null private var files = listOf() - var hasFavoriteParent = false - var hasSharedParent = false private fun getEntities(): List = files.map { file -> FileEntity( @@ -96,8 +94,4 @@ class MockOCFileListAdapterDataProvider : OCFileListAdapterDataProvider { } override fun createFileInstance(entity: FileEntity): OCFile = files.first { it.fileId == entity.id } - - override suspend fun hasFavoriteParent(fileId: Long): Boolean = hasFavoriteParent - - override suspend fun hasSharedParent(fileId: Long): Boolean = hasSharedParent } diff --git a/app/src/test/java/com/owncloud/android/ui/adapter/OCFileListAdapterHelperTest.kt b/app/src/test/java/com/owncloud/android/ui/adapter/OCFileListAdapterHelperTest.kt index d318fcffdd76..edd0be902d65 100644 --- a/app/src/test/java/com/owncloud/android/ui/adapter/OCFileListAdapterHelperTest.kt +++ b/app/src/test/java/com/owncloud/android/ui/adapter/OCFileListAdapterHelperTest.kt @@ -150,9 +150,6 @@ class OCFileListAdapterHelperTest { } val file6 = env.file(sub2, "image6.jpg", 16, MimeType.JPEG) - dataProvider.hasFavoriteParent = true - dataProvider.hasSharedParent = false - env.prepare(listOf(root, sub1, sub2, file1, file2, file3, file4, file5, file6)) stubPreferences(sort = FileSortOrder.SORT_A_TO_Z, favFirst = true) val (list, sort) = env.run(sub1) @@ -182,9 +179,6 @@ class OCFileListAdapterHelperTest { } val file6 = env.file(sub2, "image6.jpg", 16, MimeType.JPEG) - dataProvider.hasFavoriteParent = false - dataProvider.hasSharedParent = true - env.prepare(listOf(root, sub1, sub2, file1, file2, file3, file4, file5, file6)) stubPreferences(sort = FileSortOrder.SORT_A_TO_Z, favFirst = true) val (list, sort) = env.run(sub1) From 70ad2512b992aa1a150bf11772eb0ee6a2e60119 Mon Sep 17 00:00:00 2001 From: alperozturk Date: Wed, 10 Dec 2025 10:43:03 +0100 Subject: [PATCH 026/216] remove filters Signed-off-by: alperozturk --- .../android/ui/adapter/helper/OCFileListAdapterHelper.kt | 5 ----- 1 file changed, 5 deletions(-) diff --git a/app/src/main/java/com/owncloud/android/ui/adapter/helper/OCFileListAdapterHelper.kt b/app/src/main/java/com/owncloud/android/ui/adapter/helper/OCFileListAdapterHelper.kt index 28127ce835ee..bca01ae9caba 100644 --- a/app/src/main/java/com/owncloud/android/ui/adapter/helper/OCFileListAdapterHelper.kt +++ b/app/src/main/java/com/owncloud/android/ui/adapter/helper/OCFileListAdapterHelper.kt @@ -12,9 +12,7 @@ import com.nextcloud.client.preferences.AppPreferences import com.nextcloud.utils.extensions.filterFilenames import com.nextcloud.utils.extensions.isTempFile import com.owncloud.android.MainApp -import com.owncloud.android.R import com.owncloud.android.datamodel.OCFile -import com.owncloud.android.ui.activity.DrawerActivity import com.owncloud.android.utils.FileSortOrder import com.owncloud.android.utils.MimeTypeUtil import kotlinx.coroutines.CoroutineScope @@ -23,7 +21,6 @@ import kotlinx.coroutines.Job import kotlinx.coroutines.SupervisorJob import kotlinx.coroutines.launch import kotlinx.coroutines.withContext -import java.util.ArrayList class OCFileListAdapterHelper { private val scope = CoroutineScope(Dispatchers.IO + SupervisorJob()) @@ -65,8 +62,6 @@ class OCFileListAdapterHelper { val showHiddenFiles = preferences.isShowHiddenFilesEnabled() val hasMimeTypeFilter = limitToMimeType.isNotEmpty() val isRootAndPersonalOnly = (OCFile.ROOT_PATH == directory.remotePath && MainApp.isOnlyPersonFiles()) - val isSharedView = (DrawerActivity.menuItemId == R.id.nav_shared) - val isFavoritesView = (DrawerActivity.menuItemId == R.id.nav_favorites) val rawResult = getFolderContent(directory, dataProvider, onlyOnDevice) val filtered = ArrayList(rawResult.size) From ca37d89237e082e07c3561c898236e232b72543d Mon Sep 17 00:00:00 2001 From: Nextcloud bot Date: Sat, 13 Dec 2025 02:45:01 +0000 Subject: [PATCH 027/216] fix(l10n): Update translations from Transifex Signed-off-by: Nextcloud bot --- app/src/main/res/values-et-rEE/strings.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/src/main/res/values-et-rEE/strings.xml b/app/src/main/res/values-et-rEE/strings.xml index 49f0977277c8..aca0ec75b651 100644 --- a/app/src/main/res/values-et-rEE/strings.xml +++ b/app/src/main/res/values-et-rEE/strings.xml @@ -676,7 +676,7 @@ Täiendav salasõna on kustutatud Täiendav salasõna on salvestatud Vale täiendav salasõna - Paus + Peata Ei õnnestu avada salasõnaga kaitstud pdf-faili. Palun kasuta välist pdf-failide vaatamise rakendust. Luba Keela From ea81d0daf32ff67739b4755933f57e6b288693ef Mon Sep 17 00:00:00 2001 From: Nextcloud bot Date: Mon, 15 Dec 2025 02:54:11 +0000 Subject: [PATCH 028/216] fix(l10n): Update translations from Transifex Signed-off-by: Nextcloud bot --- app/src/main/res/values-fi-rFI/strings.xml | 59 ++++++++++++++++++++++ app/src/main/res/values-tr/strings.xml | 6 +-- 2 files changed, 62 insertions(+), 3 deletions(-) diff --git a/app/src/main/res/values-fi-rFI/strings.xml b/app/src/main/res/values-fi-rFI/strings.xml index e345d9222e05..655283b27198 100644 --- a/app/src/main/res/values-fi-rFI/strings.xml +++ b/app/src/main/res/values-fi-rFI/strings.xml @@ -10,6 +10,7 @@ Muokkaa Hylkää kaikki ilmoitukset Tyhjennä roskakori + Lähetä/jaa Ruudukkonäkymä Luettelonäkymä Palauta yhteystiedot ja kalenteri @@ -34,8 +35,10 @@ Näyttää yhden pienoissovelluksen konsolista Etsi kohteesta %s Näytä olevan poissa + Viestin lähettäminen epäonnistui Haluatko varmasti poistaa tämän tehtävän? Poista tehtävä + Hei! Miten voin auttaa sinua tänään? Tehtävän luonti epäonnistui Tehtävä luotu Tehtävän poisto epäonnistui @@ -43,6 +46,7 @@ Tehtävälistan haku epäonnistui, tarkista internetyhteytesi. Poista tehtävä Avustaja + Mietitään… Liitettyä tiliä ei löydy! Pääsy epäonnistui: %1$s Tälle laitteelle ei ole vielä asennettu tiliä. @@ -74,11 +78,15 @@ %1$s ei tue useita tilejä Yhteyden muodostaminen ei onnistunut Peru kirjautuminen + Kirjoita kelvollinen palvelimen osoite. Kirjautumisessa tapahtui virhe. Yritä myöhemmin uudelleen. + Tämän linkin avaamiseksi ei ole selainta. Suorita kirjautuminen loppuun selaimella Säilytetty alkuperäisessä kansiossa, koska se on vain luku + Akku vähissä, lähettäminen saattaa kestää tavanomaista kauemmin Lähetä vain Wi-Fi-yhteydellä /AutoUpload + Odotetaan Wi-Fi-yhteyttä lähetyksen aloittamiseksi Asetukset Luo uusi kansioasetus Määritä oma kansio @@ -166,8 +174,10 @@ Haluatko varmasti poistaa kohteen %1$s ja sen sisällön? Haluatko varmasti poistaa valitut kohteet ja niiden sisällön? Vain paikallisen + Kansion ristiriita Paikallinen tiedosto Jos valitset molemmat versiot, paikallisen tiedoston nimeen lisätään numero. + Jos valitset molemmat versiot, paikallisen kansion nimeen lisätään numero. Palvelintiedosto Yhteystietojen varmuuskopiointi Yhteystietojen käyttöoikeus vaaditaan. @@ -179,8 +189,14 @@ Tuonti on ajastettu ja se alkaa pian Tiedostoa ei löytynyt Viimeisintä varmuuskopiota ei löytynyt! + Havaitaan sisältömuutoksia + Keskustelun luominen epäonnistui + Poista keskustelu + Keskustelun poistaminen epäonnistui Keskusteluja ei löytynyt + Ei keskusteluja vielä Keskustelut + Kopioitu Tätä tiedostoa tai kansiota kopioitaessa tapahtui virhe Ei ole mahdollista kopioida kansiota yhteen sen alikansiosta. Tiedosto on jo olemassa kohdekansiossa @@ -269,6 +285,7 @@ Avustaja Lisää Lisää Nextcloud-sovelluksia + Tiedostovalitsinta ei voi avata Sähköpostiosoitteen valinta epäonnistui. Salaa Palvelimen varmennetta ei voitu noutaa @@ -304,6 +321,7 @@ Haluatko ilmoittaa ongelmasta? (tarvitset GitHub-tilin) Tiedoston noudossa tapahtui virhe Tapahtui virhe mallien lataamisessa + Virhe tilaviestiä asettaessa! Virhe kameraa käynnistäessä Tilit Luonut @@ -327,6 +345,7 @@ Siirrä Lataa Lähetä + Sinulla ei ole oikeutta luoda tai lähettää tiedostoja tähän kansioon. Ulkoiset jaot Lisää tai lähetä Tiedoston välittäminen latausmanagerille epäonnistui @@ -358,6 +377,8 @@ Jakamasi tiedostot ja kansiot näkyvät tässä. Ei mitään jaettua Haulla ei löytynyt tuloksia + Tarkista internetyhteys tai yritä myöhemmin uudelleen + Heikko yhteys kansio LIVE Ladataan… @@ -365,6 +386,7 @@ sekuntia sitten Tallennusoikeudet %1$s toimii parhaiten, kun sille on myönnetty käyttöoikeus tallennustilan käyttöön. Voit myöntää täydet käyttöoikeudet tai vain luku-oikeudet kuviin ja videoihin. + Salli pääsy muista sovelluksista Tarkistetaan kohdetta… Siivotaan… Päivitetään tietojen tallennuspolkua @@ -392,9 +414,11 @@ %s on epäkelpo nimi %s. Nimeä tiedosto uudelleen ennen siirtämistä tai kopioimista Tiedostoa ei löytynyt + Tiedostoa ei löytynyt. Jakoa ei voitu luoda. Tiedostoa ei voitu synkronoida. Näytetään viimeisin saatavilla oleva versio. Nimeä uudelleen Lähetys epäonnistui. Ei internetyhteyttä + %s on jo olemassa, ristiriitaa ei havaittu Virhe palauttaessa tiedostoversiota! Tiedot Lataa @@ -412,6 +436,9 @@ Näytön jako, verkkotapaamiset ja internet-konferenssit Kansio on jo olemassa Luo + Tallennustilaa ei ole riittävästi, synkronointi on peruttu + %s kansio synkronoitu onnistuneesti + Synkronoidaan… Ei kansioita täällä Kansion nimi ei voi olla tyhjä Valitse @@ -455,6 +482,7 @@ Lähetä vain ladattaessa virtaa /InstantUpload Sisäiset jaot + Sisäinen kaksisuuntainen synkronointi Virheellinen URL Näkymätön Nimike ei voi olla tyhjä @@ -534,6 +562,9 @@ Huomiota ei voitu lähettää Note-kuvake Toimenpiteen suorittaminen epäonnistui + Taustatehtävät + Havaitsee paikallisten tiedostojen muutokset + Sisällön tarkkailija Näyttää latauksen edistymisen Lataukset Näyttää tiedostojen synkronoinnin edistymisen ja tulokset @@ -550,9 +581,14 @@ Ei ilmoituksia Katso myöhemmin uudestaan. Ei internetyhteyttä + Olet yhteydettömässä tilassa, mutta työ jatkuu + Tiedostoa ei vielä ole olemassa. Lähetä tiedosto ensin. + Ei voitu luoda %s. Tiedosto samalla nimellä on jo olemassa palvelimella. + Ei voitu luoda %s. Kansio samalla nimellä on jo olemassa palvelimella. 1 tunti Online Online-tila + Avaa sovelluksella %1$s Palvelimen elinkaari on päättynyt, päivitä! Lisää -valikko Anna suojakoodisi @@ -564,9 +600,11 @@ Suojakoodi tallennettu Virheellinen suojakoodi Keskeytä + Salasanasuojatun PDF:n avaaaminen ei onnistu. Käytä erillistä PDF-lukijaa. Salli Kiellä Kuvan liittämiseksi ei löytynyt sovellusta + Kiinnitä kotinäyttöön Avaa %1$s pysäytä vaihda @@ -594,6 +632,8 @@ Synkronoi Päivittäinen kalenterin ja yhteystietojen varmuuskopiointi Päivittäinen varmuuskopio yhteystiedoistasi + Datan tallennustilan sijainti + Hallitse datan tallennustilan sijaintia Päästä päähän -salaus on määritetty! E2E-avainkoodi Jos haluat näyttää avainkoodin, ota käyttöön laitteen valtuudet. @@ -622,6 +662,7 @@ GNU yleinen lisenssi, versio 2 Suosittele kaverille Poista salaus paikallisesti Määritä päästä päähän -salaus + Näytä sovellusvaihdin Nextcloud-sovellusehdotukset navigointipalkissa Näytä piilotetut tiedostot Hanki lähdekoodi @@ -695,10 +736,16 @@ GNU yleinen lisenssi, versio 2 Valitse yksi mallipohja Valitse mallipohja Lähetä + Lähetä jako Lähetä-painikkeen kuvake + Sisältöä ei voitu ladata + Laite ei todennäköisesti ole yhteydessä internetiin Aseta + Aseta viesti Käytä kuvaa Jaa + Salli lataus ja synkronointi + Jaa ja kopioi linkki Luo Mukautetut oikeudet Poista @@ -724,6 +771,7 @@ GNU yleinen lisenssi, versio 2 Voi muokata Tiedostopyyntö Vain katselu + Jaon oikeudet Jaa Lue %1$s (etä) @@ -786,6 +834,7 @@ GNU yleinen lisenssi, versio 2 Sisäinen tallennustila Elokuvat Musiikki + Älä kysy Media vain luku-tilassa Kuvat Itse ylläpidetty työalusta jota sinä kontrolloit. \nTämä on virallinen kehitysversio, sisältäen pävittäin vaihtuvia uusia ja testaamattomia toimintoja, jotka voivat epävakauttaa ohjelmistoa ja aiheuttaa tietojen häviämistä. Sovellus on tarkoitettu käyttäjille jotka haluavat testata ja raportoida ohjelman virheitä jos niitä tapahtuu. Älä käytä sitä työ ympäristössä!\n\nSekä virallinen kehitysversio että normaali versio ovat saatavilla F-droid:ssa ja ne voidaan asentaa samanaikaisesti. @@ -849,7 +898,10 @@ GNU yleinen lisenssi, versio 2 Poista pysyvästi Roskakorin lataaminen epäonnistui! Tiedostoja ei voitu poistaa pysyvästi! + Kaksisuuntaista synkronointia ei ole määritetty + Sisäinen kaksisuuntainen synkronointi Tapahtui odottamaton virhe + Tässä kansiossa Tuntematon Vapauta tiedoston lukitus Lukemattomia kommentteja on olemassa @@ -896,6 +948,7 @@ GNU yleinen lisenssi, versio 2 Tiedostoa ei voitu kopioida paikalliseen tallennustilaan Kansion lukitseminen epäonnistui Käyttäjä peruutti latauksen + Sovelluksen oikeudet %1$d / %2$d - %3$s Salaus on mahdollista vain kun >= Android 5.0 Riittämätön tila estää tiedostojen kopioinnin %1$s kansioon. Haluatko sen sijaan siirtää ne sinne? @@ -948,6 +1001,8 @@ GNU yleinen lisenssi, versio 2 Ei-luotettu palvelinvarmenne Noudetaan palvelimen versiota… Sovellus suljettiin + Ohitettu + Tiedosto samalla nimellä on jo olemassa. Valmiina Tuntematon virhe Virus havaittu. Lähetystä ei voi suorittaa loppuun! @@ -1042,6 +1097,10 @@ GNU yleinen lisenssi, versio 2 %d valittu %d valittu + + Viivästetty %d minuutin + Viivästetty %d minuuttia + %d sekunti %d sekuntia diff --git a/app/src/main/res/values-tr/strings.xml b/app/src/main/res/values-tr/strings.xml index 64fbde2396ee..9a3ec361d629 100644 --- a/app/src/main/res/values-tr/strings.xml +++ b/app/src/main/res/values-tr/strings.xml @@ -1057,7 +1057,7 @@ Herhangi bir yükleme yok Bazı içerikler yükleyin ya da otomatik yükleme özelliğini açın. Başlık genişlemesini aç/kapat - Çakışmayı çöz + Çakışmayı çözümle Yerel depolama alanı doldu Dosya yerel depolamaya kopyalanamadı Klasör kilitlenemedi @@ -1071,7 +1071,7 @@ Seçilmiş dosyaları %1$s klasörüne kopyalamak için yeterli boş alan yok. Bu dosyaları kopyalamak yerine taşımak ister misiniz? Depolama sınırına ulaşıldı Kamera ile belge tarama - Eşitleme çakışması, lütfen sorunu el ile çözün + Eşitleme çakışması, lütfen sorunu el ile çözümleyin Bilinmeyen sorun Seçin Yükle @@ -1081,7 +1081,7 @@ Yüklenmek üzere seçilmiş dosya bulunamadı. Lütfen dosyanın var olup olmadığını denetleyin. Bu dosya yüklenemez Yüklenecek bir dosya yok - Dosya bulunamadı. Bu dosyanın var olduğundan ya da daha önceki bir çakışmanın çözüldüğünden emin misiniz? + Dosya bulunamadı. Bu dosyanın var olduğundan ya da daha önceki bir çakışmanın çözümlendiğinden emin misiniz? Dosya sunucuda bulunamadı. Başka bir kullanıcı dosyayı silmiş olabilir Klasör adı Yüklenecek klasörü seçin From 6c81ab7f66e3ee52598aa97953009421314cb824 Mon Sep 17 00:00:00 2001 From: alperozturk Date: Fri, 5 Dec 2025 12:58:40 +0100 Subject: [PATCH 029/216] fix shared tab Signed-off-by: alperozturk --- .../ui/fragment/OCFileListFragment.java | 53 ++++++------------- .../android/ui/fragment/SearchType.kt | 16 +++++- 2 files changed, 31 insertions(+), 38 deletions(-) diff --git a/app/src/main/java/com/owncloud/android/ui/fragment/OCFileListFragment.java b/app/src/main/java/com/owncloud/android/ui/fragment/OCFileListFragment.java index 25a1d1a0b192..fc27a1244f20 100644 --- a/app/src/main/java/com/owncloud/android/ui/fragment/OCFileListFragment.java +++ b/app/src/main/java/com/owncloud/android/ui/fragment/OCFileListFragment.java @@ -135,8 +135,6 @@ import androidx.annotation.NonNull; import androidx.annotation.Nullable; import androidx.annotation.OptIn; -import androidx.annotation.StringRes; -import androidx.appcompat.app.ActionBar; import androidx.core.content.ContextCompat; import androidx.drawerlayout.widget.DrawerLayout; import androidx.fragment.app.FragmentActivity; @@ -1765,28 +1763,17 @@ public OCFileListAdapter getAdapter() { } protected void setTitle() { - // set title + if (!(getActivity() instanceof FileDisplayActivity fda) || currentSearchType == null) { + return; + } - if (getActivity() instanceof FileDisplayActivity && currentSearchType != null) { - switch (currentSearchType) { - case FAVORITE_SEARCH: - setTitle(R.string.drawer_item_favorites); - break; - case GALLERY_SEARCH: - setTitle(R.string.drawer_item_gallery); - break; - case RECENTLY_MODIFIED_SEARCH: - setTitle(R.string.drawer_item_recently_modified); - break; - case SHARED_FILTER: - setTitle(R.string.drawer_item_shared); - break; - default: - setTitle(themeUtils.getDefaultDisplayNameForRootFolder(getContext()), false); - break; - } + Integer titleId = currentSearchType.titleId(); + String title = themeUtils.getDefaultDisplayNameForRootFolder(fda); + if (titleId != null) { + title = fda.getString(titleId); } + setTitle(title, currentSearchType.isMenu()); } protected void prepareActionBarItems(SearchEvent event) { @@ -2117,15 +2104,6 @@ public void onMessageEvent(FileLockEvent event) { } } - /** - * Theme default action bar according to provided parameters. Replaces back arrow with hamburger menu icon. - * - * @param title string res id of title to be shown in action bar - */ - protected void setTitle(@StringRes final int title) { - setTitle(requireContext().getString(title), true); - } - /** * Theme default action bar according to provided parameters. * @@ -2133,14 +2111,15 @@ protected void setTitle(@StringRes final int title) { * @param showBackAsMenu iff true replace back arrow with hamburger menu icon */ protected void setTitle(final String title, Boolean showBackAsMenu) { - requireActivity().runOnUiThread(() -> { - if (getActivity() != null) { - final ActionBar actionBar = ((FileDisplayActivity) getActivity()).getSupportActionBar(); - final Context context = getContext(); + if (!(getActivity() instanceof FileDisplayActivity fda)) { + return; + } - if (actionBar != null && context != null) { - viewThemeUtils.files.themeActionBar(context, actionBar, title, showBackAsMenu); - } + fda.runOnUiThread(new Runnable() { + @Override + public void run() { + final var actionBar = fda.getSupportActionBar(); + viewThemeUtils.files.themeActionBar(fda, actionBar, title, showBackAsMenu); } }); } diff --git a/app/src/main/java/com/owncloud/android/ui/fragment/SearchType.kt b/app/src/main/java/com/owncloud/android/ui/fragment/SearchType.kt index 4e27e0222e17..dd6355ca13cf 100644 --- a/app/src/main/java/com/owncloud/android/ui/fragment/SearchType.kt +++ b/app/src/main/java/com/owncloud/android/ui/fragment/SearchType.kt @@ -1,6 +1,7 @@ /* * Nextcloud - Android Client * + * SPDX-FileCopyrightText: 2025 Alper Ozturk * SPDX-FileCopyrightText: 2023 Tobias Kaminsky * SPDX-FileCopyrightText: 2022 Unpublished * SPDX-License-Identifier: AGPL-3.0-or-later OR GPL-2.0-only @@ -8,6 +9,7 @@ package com.owncloud.android.ui.fragment import android.os.Parcelable +import com.owncloud.android.R import kotlinx.parcelize.Parcelize @Parcelize @@ -22,7 +24,19 @@ enum class SearchType : Parcelable { // not a real filter, but nevertheless SHARED_FILTER, - GROUPFOLDER + GROUPFOLDER; + + fun isMenu(): Boolean { + return this in listOf(FAVORITE_SEARCH, GALLERY_SEARCH, RECENTLY_MODIFIED_SEARCH, SHARED_FILTER) + } + + fun titleId(): Int? = when (this) { + FAVORITE_SEARCH -> R.string.drawer_item_favorites + GALLERY_SEARCH -> R.string.drawer_item_gallery + RECENTLY_MODIFIED_SEARCH -> R.string.drawer_item_recently_modified + SHARED_FILTER -> R.string.drawer_item_shared + else -> null + } } @Parcelize From 4ae6a7e015eef56d98f6bc3e649e368b7dd20848 Mon Sep 17 00:00:00 2001 From: alperozturk Date: Mon, 8 Dec 2025 10:13:58 +0100 Subject: [PATCH 030/216] fix: shared tab action bar Signed-off-by: alperozturk --- .../ui/fragment/OCFileListFragment.java | 30 +++++++++++-------- 1 file changed, 18 insertions(+), 12 deletions(-) diff --git a/app/src/main/java/com/owncloud/android/ui/fragment/OCFileListFragment.java b/app/src/main/java/com/owncloud/android/ui/fragment/OCFileListFragment.java index fc27a1244f20..beb2c73dae21 100644 --- a/app/src/main/java/com/owncloud/android/ui/fragment/OCFileListFragment.java +++ b/app/src/main/java/com/owncloud/android/ui/fragment/OCFileListFragment.java @@ -124,6 +124,7 @@ import java.util.HashSet; import java.util.Iterator; import java.util.List; +import java.util.Objects; import java.util.Set; import java.util.concurrent.CompletableFuture; import java.util.concurrent.Executors; @@ -185,9 +186,7 @@ public class OCFileListFragment extends ExtendedListFragment implements public static final String FOLDER_LAYOUT_GRID = "GRID"; public static final String SEARCH_EVENT = "SEARCH_EVENT"; - private static final String KEY_FILE = MY_PACKAGE + ".extra.FILE"; - protected static final String KEY_CURRENT_SEARCH_TYPE = "CURRENT_SEARCH_TYPE"; private static final String DIALOG_CREATE_FOLDER = "DIALOG_CREATE_FOLDER"; @@ -317,21 +316,28 @@ public View onCreateView(@NonNull LayoutInflater inflater, ViewGroup container, Log_OC.i(TAG, "onCreateView() start"); View v = super.onCreateView(inflater, container, savedInstanceState); + final Bundle state = savedInstanceState != null ? savedInstanceState : getArguments(); + SearchType argSearchType = null; + SearchEvent argSearchEvent = null; + + if (state != null) { + argSearchType = BundleExtensionsKt.getParcelableArgument(state, KEY_CURRENT_SEARCH_TYPE, SearchType.class); + argSearchEvent = BundleExtensionsKt.getParcelableArgument(state, SEARCH_EVENT, SearchEvent.class); + } + + currentSearchType = Objects.requireNonNullElse(argSearchType, NO_SEARCH); - if (savedInstanceState != null && - BundleExtensionsKt.getParcelableArgument(savedInstanceState, KEY_CURRENT_SEARCH_TYPE, SearchType.class) != null && - BundleExtensionsKt.getParcelableArgument(savedInstanceState, SEARCH_EVENT, SearchEvent.class) != null) { + if (argSearchEvent != null) { + searchEvent = argSearchEvent; + } + + if (searchEvent != null && currentSearchType != NO_SEARCH) { searchFragment = true; - currentSearchType = BundleExtensionsKt.getParcelableArgument(savedInstanceState, KEY_CURRENT_SEARCH_TYPE, SearchType.class); - searchEvent = BundleExtensionsKt.getParcelableArgument(savedInstanceState, SEARCH_EVENT, SearchEvent.class); - } else { - currentSearchType = NO_SEARCH; } - Bundle args = getArguments(); - boolean allowContextualActions = args != null && args.getBoolean(ARG_ALLOW_CONTEXTUAL_ACTIONS, false); + boolean allowContextualActions = (state != null && state.getBoolean(ARG_ALLOW_CONTEXTUAL_ACTIONS, false)); if (allowContextualActions) { - setChoiceModeAsMultipleModal(savedInstanceState); + setChoiceModeAsMultipleModal(state); } mFabMain = requireActivity().findViewById(R.id.fab_main); From a130410ac5d3a6b31a9bcb05d2c3da38414b7b35 Mon Sep 17 00:00:00 2001 From: alperozturk Date: Mon, 8 Dec 2025 12:05:25 +0100 Subject: [PATCH 031/216] rely on existing architecture Signed-off-by: alperozturk --- .../java/com/nextcloud/model/ToolbarItem.kt | 38 --------- .../android/ui/activity/DrawerActivity.java | 15 +++- .../ui/activity/FileDisplayActivity.kt | 27 ++----- .../owncloud/android/ui/events/SearchEvent.kt | 11 ++- .../ui/fragment/OCFileListFragment.java | 77 ++++++++----------- 5 files changed, 60 insertions(+), 108 deletions(-) delete mode 100644 app/src/main/java/com/nextcloud/model/ToolbarItem.kt diff --git a/app/src/main/java/com/nextcloud/model/ToolbarItem.kt b/app/src/main/java/com/nextcloud/model/ToolbarItem.kt deleted file mode 100644 index 8995acc1428b..000000000000 --- a/app/src/main/java/com/nextcloud/model/ToolbarItem.kt +++ /dev/null @@ -1,38 +0,0 @@ -/* - * Nextcloud - Android Client - * - * SPDX-FileCopyrightText: 2025 Alper Ozturk - * SPDX-License-Identifier: AGPL-3.0-or-later - */ - -package com.nextcloud.model - -import android.view.Menu -import com.owncloud.android.R - -enum class ToolbarItem(val navId: Int, val titleId: Int, val style: ToolbarStyle) { - NONE(Menu.NONE, R.string.drawer_item_all_files, ToolbarStyle.SEARCH), - ALL_FILES(R.id.nav_all_files, R.string.drawer_item_all_files, ToolbarStyle.SEARCH), - PERSONAL_FILES(R.id.nav_personal_files, R.string.drawer_item_personal_files, ToolbarStyle.SEARCH), - ACTIVITIES(R.id.nav_activity, R.string.drawer_item_activities, ToolbarStyle.PLAIN), - FAVORITES(R.id.nav_favorites, R.string.drawer_item_favorites, ToolbarStyle.PLAIN), - GALLERY(R.id.nav_gallery, R.string.drawer_item_gallery, ToolbarStyle.PLAIN), - SHARED(R.id.nav_shared, R.string.drawer_item_shared, ToolbarStyle.PLAIN), - GROUP_FOLDERS(R.id.nav_groupfolders, R.string.drawer_item_groupfolders, ToolbarStyle.PLAIN), - ON_DEVICE(R.id.nav_on_device, R.string.drawer_item_on_device, ToolbarStyle.PLAIN), - RECENTLY_MODIFIED(R.id.nav_recently_modified, R.string.drawer_item_recently_modified, ToolbarStyle.PLAIN), - ASSISTANT(R.id.nav_assistant, R.string.drawer_item_assistant, ToolbarStyle.PLAIN), - UPLOADS(R.id.nav_uploads, R.string.drawer_item_uploads_list, ToolbarStyle.PLAIN), - SETTINGS(R.id.nav_settings, R.string.actionbar_settings, ToolbarStyle.PLAIN), - COMMUNITY(R.id.nav_community, R.string.drawer_community, ToolbarStyle.PLAIN), - TRASHBIN(R.id.nav_trashbin, R.string.drawer_item_trashbin, ToolbarStyle.PLAIN); - - companion object { - fun fromNavId(navId: Int): ToolbarItem? = entries.find { it.navId == navId } - } -} - -enum class ToolbarStyle { - PLAIN, - SEARCH -} diff --git a/app/src/main/java/com/owncloud/android/ui/activity/DrawerActivity.java b/app/src/main/java/com/owncloud/android/ui/activity/DrawerActivity.java index e5ca8a79c66e..ddcea4c042b4 100644 --- a/app/src/main/java/com/owncloud/android/ui/activity/DrawerActivity.java +++ b/app/src/main/java/com/owncloud/android/ui/activity/DrawerActivity.java @@ -278,6 +278,7 @@ private void handleBottomNavigationViewClicks() { } EventBus.getDefault().post(new ChangeMenuEvent()); } else if (menuItemId == R.id.nav_favorites) { + resetOnlyPersonalAndOnDevice(); setupToolbar(); handleSearchEvents(new SearchEvent("", SearchRemoteOperation.SearchType.FAVORITE_SEARCH), menuItemId); } else if (menuItemId == R.id.nav_assistant && !(this instanceof ComposeActivity)) { @@ -645,6 +646,16 @@ private void onNavigationItemClicked(final MenuItem menuItem) { Log_OC.w(TAG, "Unknown drawer menu item clicked: " + menuItem.getTitle()); } } + + // from navigation user always sees root level + final var ocFileListFragment = getOCFileListFragment(); + if (ocFileListFragment != null) { + ocFileListFragment.resetFileDepth(); + } + + if (this instanceof FileDisplayActivity fda) { + fda.configureMenuItem(); + } } private void startComposeActivity(ComposeDestination destination, int titleId) { @@ -685,10 +696,6 @@ public void openAddAccount() { } protected void openSharedTab() { - final var ocFileListFragment = getOCFileListFragment(); - if (ocFileListFragment != null) { - ocFileListFragment.resetFileDepth(); - } resetOnlyPersonalAndOnDevice(); SearchEvent searchEvent = new SearchEvent("", SearchRemoteOperation.SearchType.SHARED_FILTER); launchActivityForSearch(searchEvent, R.id.nav_shared); diff --git a/app/src/main/java/com/owncloud/android/ui/activity/FileDisplayActivity.kt b/app/src/main/java/com/owncloud/android/ui/activity/FileDisplayActivity.kt index 30b20ac632da..178fb505784b 100644 --- a/app/src/main/java/com/owncloud/android/ui/activity/FileDisplayActivity.kt +++ b/app/src/main/java/com/owncloud/android/ui/activity/FileDisplayActivity.kt @@ -71,13 +71,11 @@ import com.nextcloud.client.media.PlayerServiceConnection import com.nextcloud.client.network.ClientFactory.CreationException import com.nextcloud.client.preferences.AppPreferences import com.nextcloud.client.utils.IntentUtil -import com.nextcloud.model.ToolbarItem -import com.nextcloud.model.ToolbarStyle import com.nextcloud.model.WorkerState import com.nextcloud.model.WorkerState.FileDownloadCompleted import com.nextcloud.model.WorkerState.FileDownloadStarted -import com.nextcloud.model.WorkerState.OfflineOperationsCompleted import com.nextcloud.model.WorkerState.FileUploadCompleted +import com.nextcloud.model.WorkerState.OfflineOperationsCompleted import com.nextcloud.utils.extensions.getParcelableArgument import com.nextcloud.utils.extensions.isActive import com.nextcloud.utils.extensions.lastFragment @@ -1236,7 +1234,7 @@ class FileDisplayActivity : } resetTitleBarAndScrolling() - configureToolbar() + configureMenuItem() startMetadataSyncForCurrentDir() } @@ -1358,7 +1356,7 @@ class FileDisplayActivity : localBroadcastManager.registerReceiver(it, downloadIntentFilter) } - configureToolbar() + configureMenuItem() // show in-app review dialog to user inAppReviewHelper.showInAppReview(this) @@ -1387,23 +1385,9 @@ class FileDisplayActivity : } } - private fun configureToolbar() { + fun configureMenuItem() { checkAndSetMenuItemId() setNavigationViewItemChecked() - val item = ToolbarItem.fromNavId(menuItemId) - when (item?.style) { - ToolbarStyle.SEARCH -> setupHomeSearchToolbarWithSortAndListButtons() - ToolbarStyle.PLAIN -> { - if (currentDir?.isRootDirectory == true) { - updateActionBarTitleAndHomeButtonByString(getString(item.titleId)) - } else { - setupToolbar() - } - } - else -> { - setupToolbar() - } - } } fun initSyncBroadcastReceiver() { @@ -2749,6 +2733,9 @@ class FileDisplayActivity : Log_OC.d(this, "Switch to Shared fragment") this.leftFragment = SharedListFragment() } + + listOfFilesFragment?.setCurrentSearchType(event) + listOfFilesFragment?.setTitle() } @Subscribe(threadMode = ThreadMode.MAIN) diff --git a/app/src/main/java/com/owncloud/android/ui/events/SearchEvent.kt b/app/src/main/java/com/owncloud/android/ui/events/SearchEvent.kt index e6e95f7b8f11..7fd6aab7cdab 100644 --- a/app/src/main/java/com/owncloud/android/ui/events/SearchEvent.kt +++ b/app/src/main/java/com/owncloud/android/ui/events/SearchEvent.kt @@ -9,6 +9,7 @@ package com.owncloud.android.ui.events import android.os.Parcelable import com.owncloud.android.lib.resources.files.SearchRemoteOperation +import com.owncloud.android.ui.fragment.SearchType import kotlinx.parcelize.Parcelize /** @@ -16,4 +17,12 @@ import kotlinx.parcelize.Parcelize */ @Parcelize -data class SearchEvent(val searchQuery: String, val searchType: SearchRemoteOperation.SearchType) : Parcelable +data class SearchEvent(val searchQuery: String, val searchType: SearchRemoteOperation.SearchType) : Parcelable { + fun toSearchType(): SearchType? = when (searchType) { + SearchRemoteOperation.SearchType.FILE_SEARCH -> SearchType.FILE_SEARCH + SearchRemoteOperation.SearchType.FAVORITE_SEARCH -> SearchType.FAVORITE_SEARCH + SearchRemoteOperation.SearchType.RECENTLY_MODIFIED_SEARCH -> SearchType.RECENTLY_MODIFIED_SEARCH + SearchRemoteOperation.SearchType.SHARED_FILTER -> SearchType.SHARED_FILTER + else -> null + } +} diff --git a/app/src/main/java/com/owncloud/android/ui/fragment/OCFileListFragment.java b/app/src/main/java/com/owncloud/android/ui/fragment/OCFileListFragment.java index beb2c73dae21..0b20224b69d7 100644 --- a/app/src/main/java/com/owncloud/android/ui/fragment/OCFileListFragment.java +++ b/app/src/main/java/com/owncloud/android/ui/fragment/OCFileListFragment.java @@ -248,12 +248,9 @@ public void onCreate(Bundle savedInstanceState) { setHasOptionsMenu(true); mMultiChoiceModeListener = new MultiChoiceModeListener(); - if (savedInstanceState != null) { - currentSearchType = BundleExtensionsKt.getParcelableArgument(savedInstanceState, KEY_CURRENT_SEARCH_TYPE, SearchType.class); - searchEvent = BundleExtensionsKt.getParcelableArgument(savedInstanceState, SEARCH_EVENT, SearchEvent.class); - mFile = BundleExtensionsKt.getParcelableArgument(savedInstanceState, KEY_FILE, OCFile.class); - } - + final Bundle state = savedInstanceState != null ? savedInstanceState : getArguments(); + setSearchArgs(state); + mFile = BundleExtensionsKt.getParcelableArgument(state, KEY_FILE, OCFile.class); searchFragment = currentSearchType != null && isSearchEventSet(searchEvent); } @@ -308,15 +305,7 @@ public void onAttach(@NonNull Context context) { } } - /** - * {@inheritDoc} - */ - @Override - public View onCreateView(@NonNull LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { - Log_OC.i(TAG, "onCreateView() start"); - View v = super.onCreateView(inflater, container, savedInstanceState); - - final Bundle state = savedInstanceState != null ? savedInstanceState : getArguments(); + private void setSearchArgs(Bundle state) { SearchType argSearchType = null; SearchEvent argSearchEvent = null; @@ -334,6 +323,18 @@ public View onCreateView(@NonNull LayoutInflater inflater, ViewGroup container, if (searchEvent != null && currentSearchType != NO_SEARCH) { searchFragment = true; } + } + + /** + * {@inheritDoc} + */ + @Override + public View onCreateView(@NonNull LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { + Log_OC.i(TAG, "onCreateView() start"); + View v = super.onCreateView(inflater, container, savedInstanceState); + + final Bundle state = savedInstanceState != null ? savedInstanceState : getArguments(); + setSearchArgs(state); boolean allowContextualActions = (state != null && state.getBoolean(ARG_ALLOW_CONTEXTUAL_ACTIONS, false)); if (allowContextualActions) { @@ -467,29 +468,7 @@ protected void setAdapter(Bundle args) { protected void prepareCurrentSearch(SearchEvent event) { if (isSearchEventSet(event)) { - - switch (event.getSearchType()) { - case FILE_SEARCH: - currentSearchType = FILE_SEARCH; - break; - - case FAVORITE_SEARCH: - currentSearchType = FAVORITE_SEARCH; - break; - - case RECENTLY_MODIFIED_SEARCH: - currentSearchType = RECENTLY_MODIFIED_SEARCH; - break; - - case SHARED_FILTER: - currentSearchType = SHARED_FILTER; - break; - - default: - // do nothing - break; - } - + setCurrentSearchType(event); prepareActionBarItems(event); } } @@ -1768,7 +1747,7 @@ public OCFileListAdapter getAdapter() { return mAdapter; } - protected void setTitle() { + public void setTitle() { if (!(getActivity() instanceof FileDisplayActivity fda) || currentSearchType == null) { return; } @@ -1782,6 +1761,13 @@ protected void setTitle() { setTitle(title, currentSearchType.isMenu()); } + public void setCurrentSearchType(SearchEvent event) { + final var searchType = event.toSearchType(); + if (searchType != null) { + currentSearchType = searchType; + } + } + protected void prepareActionBarItems(SearchEvent event) { if (event != null) { switch (event.getSearchType()) { @@ -2121,12 +2107,13 @@ protected void setTitle(final String title, Boolean showBackAsMenu) { return; } - fda.runOnUiThread(new Runnable() { - @Override - public void run() { - final var actionBar = fda.getSupportActionBar(); - viewThemeUtils.files.themeActionBar(fda, actionBar, title, showBackAsMenu); - } + final var actionBar = fda.getSupportActionBar(); + if (actionBar == null) { + return; + } + + fda.runOnUiThread(() -> { + viewThemeUtils.files.themeActionBar(fda, actionBar, title, showBackAsMenu); }); } From b3934dc4cf6ad3558eae8dc1f6223979891de5e6 Mon Sep 17 00:00:00 2001 From: alperozturk Date: Mon, 8 Dec 2025 12:08:13 +0100 Subject: [PATCH 032/216] fix crash Signed-off-by: alperozturk --- .../ui/activity/FileDisplayActivity.kt | 2 +- .../ui/fragment/OCFileListFragment.java | 22 ++++++++++++------- 2 files changed, 15 insertions(+), 9 deletions(-) diff --git a/app/src/main/java/com/owncloud/android/ui/activity/FileDisplayActivity.kt b/app/src/main/java/com/owncloud/android/ui/activity/FileDisplayActivity.kt index 178fb505784b..81ec42da9254 100644 --- a/app/src/main/java/com/owncloud/android/ui/activity/FileDisplayActivity.kt +++ b/app/src/main/java/com/owncloud/android/ui/activity/FileDisplayActivity.kt @@ -2735,7 +2735,7 @@ class FileDisplayActivity : } listOfFilesFragment?.setCurrentSearchType(event) - listOfFilesFragment?.setTitle() + listOfFilesFragment?.setActionBarTitle() } @Subscribe(threadMode = ThreadMode.MAIN) diff --git a/app/src/main/java/com/owncloud/android/ui/fragment/OCFileListFragment.java b/app/src/main/java/com/owncloud/android/ui/fragment/OCFileListFragment.java index 0b20224b69d7..e4e37533319a 100644 --- a/app/src/main/java/com/owncloud/android/ui/fragment/OCFileListFragment.java +++ b/app/src/main/java/com/owncloud/android/ui/fragment/OCFileListFragment.java @@ -290,7 +290,7 @@ public void onAttach(@NonNull Context context) { Log_OC.i(TAG, "onAttach"); try { mContainerActivity = (FileFragment.ContainerActivity) context; - setTitle(); + setActionBarTitle(); } catch (ClassCastException e) { throw new IllegalArgumentException(context.toString() + " must implement " + @@ -435,7 +435,7 @@ public void onActivityCreated(Bundle savedInstanceState) { }); } - setTitle(); + setActionBarTitle(); FragmentActivity fragmentActivity; if ((fragmentActivity = getActivity()) != null && fragmentActivity instanceof FileDisplayActivity fileDisplayActivity) { @@ -1516,8 +1516,14 @@ public void listDirectory(boolean onlyOnDevice, boolean fromSearch) { public void refreshDirectory() { searchFragment = false; - setFabVisible(mFile.canCreateFileAndFolder()); - listDirectory(getCurrentFile(), MainApp.isOnlyOnDevice(), false); + if (mFile != null) { + setFabVisible(mFile.canCreateFileAndFolder()); + } + + final var currentFile = getCurrentFile(); + if (currentFile != null) { + listDirectory(currentFile, MainApp.isOnlyOnDevice(), false); + } } public void listDirectory(OCFile directory, boolean onlyOnDevice, boolean fromSearch) { @@ -1747,7 +1753,7 @@ public OCFileListAdapter getAdapter() { return mAdapter; } - public void setTitle() { + public void setActionBarTitle() { if (!(getActivity() instanceof FileDisplayActivity fda) || currentSearchType == null) { return; } @@ -1758,7 +1764,7 @@ public void setTitle() { title = fda.getString(titleId); } - setTitle(title, currentSearchType.isMenu()); + setActionBarTitle(title, currentSearchType.isMenu()); } public void setCurrentSearchType(SearchEvent event) { @@ -1828,7 +1834,7 @@ public void onMessageEvent(ChangeMenuEvent changeMenuEvent) { ((FileDisplayActivity) activity).initSyncBroadcastReceiver(); } - setTitle(themeUtils.getDefaultDisplayNameForRootFolder(getContext()), false); + setActionBarTitle(themeUtils.getDefaultDisplayNameForRootFolder(getContext()), false); activity.getIntent().removeExtra(OCFileListFragment.SEARCH_EVENT); } @@ -2102,7 +2108,7 @@ public void onMessageEvent(FileLockEvent event) { * @param title title to be shown in action bar * @param showBackAsMenu iff true replace back arrow with hamburger menu icon */ - protected void setTitle(final String title, Boolean showBackAsMenu) { + protected void setActionBarTitle(final String title, Boolean showBackAsMenu) { if (!(getActivity() instanceof FileDisplayActivity fda)) { return; } From d076a1d8c17a3dfc276b3d94c272872e2927c957 Mon Sep 17 00:00:00 2001 From: alperozturk Date: Mon, 8 Dec 2025 12:38:14 +0100 Subject: [PATCH 033/216] override updateActionBarTitleAndHomeButton with search type Signed-off-by: alperozturk --- .../android/ui/activity/DrawerActivity.java | 9 +++- .../android/ui/activity/ToolbarActivity.java | 29 +++++++--- .../ui/fragment/OCFileListFragment.java | 54 ++++++++----------- .../android/ui/fragment/SearchType.kt | 4 -- 4 files changed, 51 insertions(+), 45 deletions(-) diff --git a/app/src/main/java/com/owncloud/android/ui/activity/DrawerActivity.java b/app/src/main/java/com/owncloud/android/ui/activity/DrawerActivity.java index ddcea4c042b4..7367d907ad78 100644 --- a/app/src/main/java/com/owncloud/android/ui/activity/DrawerActivity.java +++ b/app/src/main/java/com/owncloud/android/ui/activity/DrawerActivity.java @@ -93,6 +93,7 @@ import com.owncloud.android.ui.fragment.GalleryFragment; import com.owncloud.android.ui.fragment.GroupfolderListFragment; import com.owncloud.android.ui.fragment.OCFileListFragment; +import com.owncloud.android.ui.fragment.SearchType; import com.owncloud.android.ui.fragment.SharedListFragment; import com.owncloud.android.ui.preview.PreviewTextStringFragment; import com.owncloud.android.ui.trashbin.TrashbinActivity; @@ -831,7 +832,13 @@ public void setDrawerIndicatorEnabled(boolean enable) { * Updates title bar and home buttons (state and icon). Assumes that navigation drawer is NOT visible. */ protected void updateActionBarTitleAndHomeButton(OCFile chosenFile) { - super.updateActionBarTitleAndHomeButton(chosenFile); + final var ocFileListFragment = getOCFileListFragment(); + SearchType searchType = SearchType.NO_SEARCH; + if (ocFileListFragment != null) { + searchType = ocFileListFragment.getCurrentSearchType(); + } + + updateActionBarTitleAndHomeButton(chosenFile, searchType); // set home button properties if (mDrawerToggle != null) { diff --git a/app/src/main/java/com/owncloud/android/ui/activity/ToolbarActivity.java b/app/src/main/java/com/owncloud/android/ui/activity/ToolbarActivity.java index f4945899e9ea..8e68a75d47fc 100644 --- a/app/src/main/java/com/owncloud/android/ui/activity/ToolbarActivity.java +++ b/app/src/main/java/com/owncloud/android/ui/activity/ToolbarActivity.java @@ -36,6 +36,7 @@ import com.owncloud.android.datamodel.FileDataStorageManager; import com.owncloud.android.datamodel.OCFile; import com.owncloud.android.lib.common.utils.Log_OC; +import com.owncloud.android.ui.fragment.SearchType; import com.owncloud.android.utils.theme.ThemeColorUtils; import com.owncloud.android.utils.theme.ThemeUtils; import com.owncloud.android.utils.theme.ViewThemeUtils; @@ -153,21 +154,33 @@ public void setupHomeSearchToolbarWithSortAndListButtons() { setupToolbar(true, true); } - /** - * Updates title bar and home buttons (state and icon). - */ - protected void updateActionBarTitleAndHomeButton(OCFile chosenFile) { + public void updateActionBarTitleAndHomeButton(OCFile chosenFile, SearchType searchType) { boolean isRoot = isRoot(chosenFile); - String title = getActionBarTitle(chosenFile, isRoot); + String title = getActionBarTitle(chosenFile, searchType); updateActionBarTitleAndHomeButtonByString(title); if (mAppBar != null) { showHomeSearchToolbar(title, isRoot); } } - private String getActionBarTitle(OCFile chosenFile, boolean isRoot) { - if (isRoot) { - return themeUtils.getDefaultDisplayNameForRootFolder(this); + protected void updateActionBarTitleAndHomeButton(OCFile chosenFile) { + updateActionBarTitleAndHomeButton(chosenFile, SearchType.NO_SEARCH); + } + + public String getActionBarRootTitle(@NonNull SearchType searchType) { + Integer rootTitleId = searchType.titleId(); + String result = themeUtils.getDefaultDisplayNameForRootFolder(this); + + if (rootTitleId != null) { + result = getString(rootTitleId); + } + + return result; + } + + public String getActionBarTitle(OCFile chosenFile, @NonNull SearchType searchType) { + if (isRoot(chosenFile)) { + return getActionBarRootTitle(searchType); } if (chosenFile.isFolder()) { diff --git a/app/src/main/java/com/owncloud/android/ui/fragment/OCFileListFragment.java b/app/src/main/java/com/owncloud/android/ui/fragment/OCFileListFragment.java index e4e37533319a..46ded3e80823 100644 --- a/app/src/main/java/com/owncloud/android/ui/fragment/OCFileListFragment.java +++ b/app/src/main/java/com/owncloud/android/ui/fragment/OCFileListFragment.java @@ -291,7 +291,6 @@ public void onAttach(@NonNull Context context) { try { mContainerActivity = (FileFragment.ContainerActivity) context; setActionBarTitle(); - } catch (ClassCastException e) { throw new IllegalArgumentException(context.toString() + " must implement " + FileFragment.ContainerActivity.class.getSimpleName(), e); @@ -437,9 +436,8 @@ public void onActivityCreated(Bundle savedInstanceState) { setActionBarTitle(); - FragmentActivity fragmentActivity; - if ((fragmentActivity = getActivity()) != null && fragmentActivity instanceof FileDisplayActivity fileDisplayActivity) { - fileDisplayActivity.updateActionBarTitleAndHomeButton(fileDisplayActivity.getCurrentDir()); + if (getActivity() instanceof FileDisplayActivity fileDisplayActivity) { + fileDisplayActivity.updateActionBarTitleAndHomeButton(fileDisplayActivity.getCurrentDir(), currentSearchType); } listDirectory(MainApp.isOnlyOnDevice(), false); } @@ -1064,6 +1062,7 @@ public int onBrowseUp() { Pair result = futureResult.get(); mFile = result.second; setFileDepth(mFile); + setActionBarTitle(); updateFileList(); return result.first; } catch (Exception e) { @@ -1289,7 +1288,11 @@ public OCFileDepth getFileDepth() { private void browseToFolder(OCFile file, int position) { setFileDepth(file); - resetSearchIfBrowsingFromFavorites(); + + if (currentSearchType == FAVORITE_SEARCH) { + resetMenuItems(); + } + listDirectory(file, MainApp.isOnlyOnDevice(), false); // then, notify parent activity to let it update its state and view mContainerActivity.onBrowsedDownTo(file); @@ -1297,13 +1300,6 @@ private void browseToFolder(OCFile file, int position) { saveIndexAndTopPosition(position); } - private void resetSearchIfBrowsingFromFavorites() { - if (currentSearchType == FAVORITE_SEARCH) { - resetSearchAttributes(); - resetMenuItems(); - } - } - @Override public void onActivityResult(int requestCode, int resultCode, Intent data) { if (requestCode == SETUP_ENCRYPTION_REQUEST_CODE && @@ -1753,20 +1749,6 @@ public OCFileListAdapter getAdapter() { return mAdapter; } - public void setActionBarTitle() { - if (!(getActivity() instanceof FileDisplayActivity fda) || currentSearchType == null) { - return; - } - - Integer titleId = currentSearchType.titleId(); - String title = themeUtils.getDefaultDisplayNameForRootFolder(fda); - if (titleId != null) { - title = fda.getString(titleId); - } - - setActionBarTitle(title, currentSearchType.isMenu()); - } - public void setCurrentSearchType(SearchEvent event) { final var searchType = event.toSearchType(); if (searchType != null) { @@ -1774,6 +1756,10 @@ public void setCurrentSearchType(SearchEvent event) { } } + public SearchType getCurrentSearchType() { + return currentSearchType; + } + protected void prepareActionBarItems(SearchEvent event) { if (event != null) { switch (event.getSearchType()) { @@ -2102,12 +2088,16 @@ public void onMessageEvent(FileLockEvent event) { } } - /** - * Theme default action bar according to provided parameters. - * - * @param title title to be shown in action bar - * @param showBackAsMenu iff true replace back arrow with hamburger menu icon - */ + public void setActionBarTitle() { + if (!(getActivity() instanceof FileDisplayActivity fda) || currentSearchType == null) { + return; + } + + String title = fda.getActionBarTitle(mFile, currentSearchType); + boolean isRoot = (getFileDepth() == OCFileDepth.Root) || fda.isRoot(mFile); + setActionBarTitle(title, isRoot); + } + protected void setActionBarTitle(final String title, Boolean showBackAsMenu) { if (!(getActivity() instanceof FileDisplayActivity fda)) { return; diff --git a/app/src/main/java/com/owncloud/android/ui/fragment/SearchType.kt b/app/src/main/java/com/owncloud/android/ui/fragment/SearchType.kt index dd6355ca13cf..7827e6d053f9 100644 --- a/app/src/main/java/com/owncloud/android/ui/fragment/SearchType.kt +++ b/app/src/main/java/com/owncloud/android/ui/fragment/SearchType.kt @@ -26,10 +26,6 @@ enum class SearchType : Parcelable { SHARED_FILTER, GROUPFOLDER; - fun isMenu(): Boolean { - return this in listOf(FAVORITE_SEARCH, GALLERY_SEARCH, RECENTLY_MODIFIED_SEARCH, SHARED_FILTER) - } - fun titleId(): Int? = when (this) { FAVORITE_SEARCH -> R.string.drawer_item_favorites GALLERY_SEARCH -> R.string.drawer_item_gallery From 6809f6dccb3b219445fd2b85da2698d005473e5f Mon Sep 17 00:00:00 2001 From: alperozturk Date: Mon, 8 Dec 2025 14:04:13 +0100 Subject: [PATCH 034/216] remove duplicated calls Signed-off-by: alperozturk --- .../ui/activity/FileDisplayActivity.kt | 23 ++++---- .../android/ui/activity/ToolbarActivity.java | 8 +-- .../ui/fragment/OCFileListFragment.java | 53 +++---------------- 3 files changed, 25 insertions(+), 59 deletions(-) diff --git a/app/src/main/java/com/owncloud/android/ui/activity/FileDisplayActivity.kt b/app/src/main/java/com/owncloud/android/ui/activity/FileDisplayActivity.kt index 81ec42da9254..c5bade95e86f 100644 --- a/app/src/main/java/com/owncloud/android/ui/activity/FileDisplayActivity.kt +++ b/app/src/main/java/com/owncloud/android/ui/activity/FileDisplayActivity.kt @@ -533,7 +533,7 @@ class FileDisplayActivity : } /** reset views */ - resetTitleBarAndScrolling() + resetScrollingAndUpdateActionBar() } // region Handle Intents @@ -632,6 +632,8 @@ class FileDisplayActivity : } } } + + listOfFilesFragment?.setCurrentSearchType(searchEvent) } // endregion @@ -789,8 +791,8 @@ class FileDisplayActivity : return null } - protected fun resetTitleBarAndScrolling() { - updateActionBarTitleAndHomeButton(null) + protected fun resetScrollingAndUpdateActionBar(searchType: SearchType = SearchType.NO_SEARCH) { + updateActionBarTitleAndHomeButton(file, searchType) resetScrolling(true) } @@ -1233,7 +1235,7 @@ class FileDisplayActivity : listOfFiles.registerFabListener() } - resetTitleBarAndScrolling() + resetScrollingAndUpdateActionBar(listOfFilesFragment?.currentSearchType ?: SearchType.NO_SEARCH) configureMenuItem() startMetadataSyncForCurrentDir() } @@ -1519,7 +1521,7 @@ class FileDisplayActivity : private fun handleRemovedFileFromServer(currentFile: OCFile?, currentDir: OCFile?): OCFile? { if (currentFile == null && file?.isFolder == false) { - resetTitleBarAndScrolling() + resetScrollingAndUpdateActionBar() return currentDir } @@ -1797,12 +1799,12 @@ class FileDisplayActivity : startSyncFolderOperation(root, false) } binding.fabMain.setImageResource(R.drawable.ic_plus) - resetTitleBarAndScrolling() + resetScrollingAndUpdateActionBar(listOfFilesFragment?.currentSearchType ?: SearchType.NO_SEARCH) } override fun onBrowsedDownTo(directory: OCFile?) { file = directory - resetTitleBarAndScrolling() + resetScrollingAndUpdateActionBar() startSyncFolderOperation(directory, false) startMetadataSyncForCurrentDir() } @@ -2099,7 +2101,7 @@ class FileDisplayActivity : val fileAvailable = storageManager.fileExists(removedFile.fileId) if (leftFragment is FileFragment && !fileAvailable && removedFile == leftFragment.file) { file = storageManager.getFileById(removedFile.parentId) - resetTitleBarAndScrolling() + resetScrollingAndUpdateActionBar() } val parentFile = storageManager.getFileById(removedFile.parentId) if (parentFile != null && parentFile == getCurrentDir()) { @@ -2305,7 +2307,7 @@ class FileDisplayActivity : leftFragment.updateFileDetails(file, currentUser) } else { if (!file.fileExists()) { - resetTitleBarAndScrolling() + resetScrollingAndUpdateActionBar() } else { leftFragment.updateFileDetails(false, true) } @@ -2735,7 +2737,8 @@ class FileDisplayActivity : } listOfFilesFragment?.setCurrentSearchType(event) - listOfFilesFragment?.setActionBarTitle() + updateActionBarTitleAndHomeButton(null) + //listOfFilesFragment?.setActionBarTitle() } @Subscribe(threadMode = ThreadMode.MAIN) diff --git a/app/src/main/java/com/owncloud/android/ui/activity/ToolbarActivity.java b/app/src/main/java/com/owncloud/android/ui/activity/ToolbarActivity.java index 8e68a75d47fc..8ef0e75a5711 100644 --- a/app/src/main/java/com/owncloud/android/ui/activity/ToolbarActivity.java +++ b/app/src/main/java/com/owncloud/android/ui/activity/ToolbarActivity.java @@ -155,12 +155,14 @@ public void setupHomeSearchToolbarWithSortAndListButtons() { } public void updateActionBarTitleAndHomeButton(OCFile chosenFile, SearchType searchType) { + if (mAppBar == null) { + return; + } + boolean isRoot = isRoot(chosenFile); String title = getActionBarTitle(chosenFile, searchType); updateActionBarTitleAndHomeButtonByString(title); - if (mAppBar != null) { - showHomeSearchToolbar(title, isRoot); - } + showHomeSearchToolbar(title, isRoot); } protected void updateActionBarTitleAndHomeButton(OCFile chosenFile) { diff --git a/app/src/main/java/com/owncloud/android/ui/fragment/OCFileListFragment.java b/app/src/main/java/com/owncloud/android/ui/fragment/OCFileListFragment.java index 46ded3e80823..465f4a097ffe 100644 --- a/app/src/main/java/com/owncloud/android/ui/fragment/OCFileListFragment.java +++ b/app/src/main/java/com/owncloud/android/ui/fragment/OCFileListFragment.java @@ -290,7 +290,6 @@ public void onAttach(@NonNull Context context) { Log_OC.i(TAG, "onAttach"); try { mContainerActivity = (FileFragment.ContainerActivity) context; - setActionBarTitle(); } catch (ClassCastException e) { throw new IllegalArgumentException(context.toString() + " must implement " + FileFragment.ContainerActivity.class.getSimpleName(), e); @@ -434,10 +433,8 @@ public void onActivityCreated(Bundle savedInstanceState) { }); } - setActionBarTitle(); - - if (getActivity() instanceof FileDisplayActivity fileDisplayActivity) { - fileDisplayActivity.updateActionBarTitleAndHomeButton(fileDisplayActivity.getCurrentDir(), currentSearchType); + if (getActivity() instanceof FileDisplayActivity fda) { + fda.updateActionBarTitleAndHomeButton(fda.getCurrentDir(), currentSearchType); } listDirectory(MainApp.isOnlyOnDevice(), false); } @@ -1062,7 +1059,6 @@ public int onBrowseUp() { Pair result = futureResult.get(); mFile = result.second; setFileDepth(mFile); - setActionBarTitle(); updateFileList(); return result.first; } catch (Exception e) { @@ -1810,28 +1806,18 @@ protected void setEmptyView(SearchEvent event) { @Subscribe(threadMode = ThreadMode.MAIN) public void onMessageEvent(ChangeMenuEvent changeMenuEvent) { resetSearchAttributes(); - resetMenuItems(); - Activity activity = getActivity(); - if (activity != null) { - activity.invalidateOptionsMenu(); - - if (activity instanceof FileDisplayActivity) { - ((FileDisplayActivity) activity).initSyncBroadcastReceiver(); - } - - setActionBarTitle(themeUtils.getDefaultDisplayNameForRootFolder(getContext()), false); - activity.getIntent().removeExtra(OCFileListFragment.SEARCH_EVENT); - } - Bundle arguments = getArguments(); - if (arguments != null) { - arguments.putParcelable(OCFileListFragment.SEARCH_EVENT, null); + if (getActivity() instanceof FileDisplayActivity fda) { + fda.invalidateOptionsMenu(); + fda.getIntent().removeExtra(OCFileListFragment.SEARCH_EVENT); + fda.updateActionBarTitleAndHomeButton(null, NO_SEARCH); } if (mFile != null) { setFabVisible(mFile.canCreateFileAndFolder()); } + slideHideBottomBehaviourForBottomNavigationView(true); } @@ -2088,31 +2074,6 @@ public void onMessageEvent(FileLockEvent event) { } } - public void setActionBarTitle() { - if (!(getActivity() instanceof FileDisplayActivity fda) || currentSearchType == null) { - return; - } - - String title = fda.getActionBarTitle(mFile, currentSearchType); - boolean isRoot = (getFileDepth() == OCFileDepth.Root) || fda.isRoot(mFile); - setActionBarTitle(title, isRoot); - } - - protected void setActionBarTitle(final String title, Boolean showBackAsMenu) { - if (!(getActivity() instanceof FileDisplayActivity fda)) { - return; - } - - final var actionBar = fda.getSupportActionBar(); - if (actionBar == null) { - return; - } - - fda.runOnUiThread(() -> { - viewThemeUtils.files.themeActionBar(fda, actionBar, title, showBackAsMenu); - }); - } - @Override public void onStart() { super.onStart(); From 70a2c85f2daa2fba4cc398d0d61e46d24be388f9 Mon Sep 17 00:00:00 2001 From: alperozturk Date: Mon, 8 Dec 2025 14:27:42 +0100 Subject: [PATCH 035/216] while setting toolbar check toolbar style as well Signed-off-by: alperozturk --- .../android/ui/activity/DrawerActivity.java | 15 ++--- .../ui/activity/FileDisplayActivity.kt | 8 +-- .../android/ui/activity/ToolbarActivity.java | 67 ++++++++++++++----- .../ui/fragment/OCFileListFragment.java | 4 +- 4 files changed, 63 insertions(+), 31 deletions(-) diff --git a/app/src/main/java/com/owncloud/android/ui/activity/DrawerActivity.java b/app/src/main/java/com/owncloud/android/ui/activity/DrawerActivity.java index 7367d907ad78..b35c10ea086f 100644 --- a/app/src/main/java/com/owncloud/android/ui/activity/DrawerActivity.java +++ b/app/src/main/java/com/owncloud/android/ui/activity/DrawerActivity.java @@ -93,7 +93,6 @@ import com.owncloud.android.ui.fragment.GalleryFragment; import com.owncloud.android.ui.fragment.GroupfolderListFragment; import com.owncloud.android.ui.fragment.OCFileListFragment; -import com.owncloud.android.ui.fragment.SearchType; import com.owncloud.android.ui.fragment.SharedListFragment; import com.owncloud.android.ui.preview.PreviewTextStringFragment; import com.owncloud.android.ui.trashbin.TrashbinActivity; @@ -832,13 +831,7 @@ public void setDrawerIndicatorEnabled(boolean enable) { * Updates title bar and home buttons (state and icon). Assumes that navigation drawer is NOT visible. */ protected void updateActionBarTitleAndHomeButton(OCFile chosenFile) { - final var ocFileListFragment = getOCFileListFragment(); - SearchType searchType = SearchType.NO_SEARCH; - if (ocFileListFragment != null) { - searchType = ocFileListFragment.getCurrentSearchType(); - } - - updateActionBarTitleAndHomeButton(chosenFile, searchType); + super.updateActionBarTitleAndHomeButton(chosenFile); // set home button properties if (mDrawerToggle != null) { @@ -1458,4 +1451,10 @@ private void checkStoragePermissionWarningBannerVisibility() { uploadFilesActivity.setupStoragePermissionWarningBanner(); } } + + public static boolean isToolbarStyleSearch() { + return menuItemId == Menu.NONE || + menuItemId == R.id.nav_all_files || + menuItemId == R.id.nav_personal_files; + } } diff --git a/app/src/main/java/com/owncloud/android/ui/activity/FileDisplayActivity.kt b/app/src/main/java/com/owncloud/android/ui/activity/FileDisplayActivity.kt index c5bade95e86f..db75a12d1164 100644 --- a/app/src/main/java/com/owncloud/android/ui/activity/FileDisplayActivity.kt +++ b/app/src/main/java/com/owncloud/android/ui/activity/FileDisplayActivity.kt @@ -791,8 +791,8 @@ class FileDisplayActivity : return null } - protected fun resetScrollingAndUpdateActionBar(searchType: SearchType = SearchType.NO_SEARCH) { - updateActionBarTitleAndHomeButton(file, searchType) + protected fun resetScrollingAndUpdateActionBar() { + updateActionBarTitleAndHomeButton(file) resetScrolling(true) } @@ -1235,7 +1235,7 @@ class FileDisplayActivity : listOfFiles.registerFabListener() } - resetScrollingAndUpdateActionBar(listOfFilesFragment?.currentSearchType ?: SearchType.NO_SEARCH) + resetScrollingAndUpdateActionBar() configureMenuItem() startMetadataSyncForCurrentDir() } @@ -1799,7 +1799,7 @@ class FileDisplayActivity : startSyncFolderOperation(root, false) } binding.fabMain.setImageResource(R.drawable.ic_plus) - resetScrollingAndUpdateActionBar(listOfFilesFragment?.currentSearchType ?: SearchType.NO_SEARCH) + resetScrollingAndUpdateActionBar() } override fun onBrowsedDownTo(directory: OCFile?) { diff --git a/app/src/main/java/com/owncloud/android/ui/activity/ToolbarActivity.java b/app/src/main/java/com/owncloud/android/ui/activity/ToolbarActivity.java index 8ef0e75a5711..ab2518d22309 100644 --- a/app/src/main/java/com/owncloud/android/ui/activity/ToolbarActivity.java +++ b/app/src/main/java/com/owncloud/android/ui/activity/ToolbarActivity.java @@ -35,7 +35,9 @@ import com.owncloud.android.R; import com.owncloud.android.datamodel.FileDataStorageManager; import com.owncloud.android.datamodel.OCFile; +import com.owncloud.android.datamodel.OCFileDepth; import com.owncloud.android.lib.common.utils.Log_OC; +import com.owncloud.android.ui.fragment.OCFileListFragment; import com.owncloud.android.ui.fragment.SearchType; import com.owncloud.android.utils.theme.ThemeColorUtils; import com.owncloud.android.utils.theme.ThemeUtils; @@ -136,6 +138,9 @@ public void setupToolbarShowOnlyMenuButtonAndTitle(String title, View.OnClickLis menuButton.setOnClickListener(toggleDrawer); } + /** + * Shows plain action bar + */ public void setupToolbar() { if (mHomeSearchToolbar != null && mDefaultToolbar != null && mHomeSearchToolbar.getVisibility() == View.GONE && mDefaultToolbar.getVisibility() == View.VISIBLE) { Log_OC.d(TAG, "Search toolbar is already hidden, skipping update."); @@ -145,6 +150,9 @@ public void setupToolbar() { setupToolbar(false, false); } + /** + * Shows action bar with search + */ public void setupHomeSearchToolbarWithSortAndListButtons() { if (mHomeSearchToolbar != null && mDefaultToolbar != null && mHomeSearchToolbar.getVisibility() == View.VISIBLE && mDefaultToolbar.getVisibility() == View.GONE) { Log_OC.d(TAG, "Search toolbar is already visible, skipping update."); @@ -154,22 +162,34 @@ public void setupHomeSearchToolbarWithSortAndListButtons() { setupToolbar(true, true); } - public void updateActionBarTitleAndHomeButton(OCFile chosenFile, SearchType searchType) { - if (mAppBar == null) { - return; + private OCFileListFragment getOCFileListFragment() { + if (this instanceof FileDisplayActivity fda) { + return fda.getListOfFilesFragment(); } - boolean isRoot = isRoot(chosenFile); - String title = getActionBarTitle(chosenFile, searchType); - updateActionBarTitleAndHomeButtonByString(title); - showHomeSearchToolbar(title, isRoot); + return null; } - protected void updateActionBarTitleAndHomeButton(OCFile chosenFile) { - updateActionBarTitleAndHomeButton(chosenFile, SearchType.NO_SEARCH); + private OCFileDepth getCurrentDirDepth() { + OCFileListFragment fragment = getOCFileListFragment(); + if (fragment != null) { + return fragment.getFileDepth(); + } + + return null; } - public String getActionBarRootTitle(@NonNull SearchType searchType) { + private SearchType getSearchType() { + OCFileListFragment fragment = getOCFileListFragment(); + if (fragment != null) { + return fragment.getCurrentSearchType(); + } + + return SearchType.NO_SEARCH; + } + + public String getActionBarRootTitle() { + final SearchType searchType = getSearchType(); Integer rootTitleId = searchType.titleId(); String result = themeUtils.getDefaultDisplayNameForRootFolder(this); @@ -180,9 +200,9 @@ public String getActionBarRootTitle(@NonNull SearchType searchType) { return result; } - public String getActionBarTitle(OCFile chosenFile, @NonNull SearchType searchType) { + public String getActionBarTitle(OCFile chosenFile) { if (isRoot(chosenFile)) { - return getActionBarRootTitle(searchType); + return getActionBarRootTitle(); } if (chosenFile.isFolder()) { @@ -198,6 +218,24 @@ public String getActionBarTitle(OCFile chosenFile, @NonNull SearchType searchTyp return fileDataStorageManager.getFilenameConsideringOfflineOperation(parentFile); } + protected void updateActionBarTitleAndHomeButton(OCFile chosenFile) { + if (mAppBar == null) { + return; + } + + final OCFileDepth currentDirDepth = getCurrentDirDepth(); + final boolean isRoot = isRoot(chosenFile) || currentDirDepth == OCFileDepth.Root; + final String title = getActionBarTitle(chosenFile); + updateActionBarTitleAndHomeButtonByString(title); + + final boolean isToolbarStyleSearch = DrawerActivity.isToolbarStyleSearch(); + final boolean canShowSearchBar = (isHomeSearchToolbarShow && isRoot && isToolbarStyleSearch); + + showHomeSearchToolbar(canShowSearchBar); + mSearchText.setText(getString(R.string.appbar_search_in, title)); + } + + public void showSearchView() { if (isHomeSearchToolbarShow) { showHomeSearchToolbar(false); @@ -210,11 +248,6 @@ public void hideSearchView(OCFile chosenFile) { } } - private void showHomeSearchToolbar(String title, boolean isRoot) { - showHomeSearchToolbar(isHomeSearchToolbarShow && isRoot); - mSearchText.setText(getString(R.string.appbar_search_in, title)); - } - @SuppressLint("PrivateResource") private void showHomeSearchToolbar(boolean isShow) { viewThemeUtils.material.themeToolbar(mToolbar); diff --git a/app/src/main/java/com/owncloud/android/ui/fragment/OCFileListFragment.java b/app/src/main/java/com/owncloud/android/ui/fragment/OCFileListFragment.java index 465f4a097ffe..6149709b438c 100644 --- a/app/src/main/java/com/owncloud/android/ui/fragment/OCFileListFragment.java +++ b/app/src/main/java/com/owncloud/android/ui/fragment/OCFileListFragment.java @@ -434,7 +434,7 @@ public void onActivityCreated(Bundle savedInstanceState) { } if (getActivity() instanceof FileDisplayActivity fda) { - fda.updateActionBarTitleAndHomeButton(fda.getCurrentDir(), currentSearchType); + fda.updateActionBarTitleAndHomeButton(fda.getCurrentDir()); } listDirectory(MainApp.isOnlyOnDevice(), false); } @@ -1811,7 +1811,7 @@ public void onMessageEvent(ChangeMenuEvent changeMenuEvent) { if (getActivity() instanceof FileDisplayActivity fda) { fda.invalidateOptionsMenu(); fda.getIntent().removeExtra(OCFileListFragment.SEARCH_EVENT); - fda.updateActionBarTitleAndHomeButton(null, NO_SEARCH); + fda.updateActionBarTitleAndHomeButton(null); } if (mFile != null) { From 4fd30448d5c4f1e29bf25a2b6bf8c1f67d70c906 Mon Sep 17 00:00:00 2001 From: alperozturk Date: Mon, 8 Dec 2025 14:39:46 +0100 Subject: [PATCH 036/216] fix back button action Signed-off-by: alperozturk --- .../android/ui/activity/DrawerActivity.java | 13 +++++++++---- .../android/ui/activity/ToolbarActivity.java | 11 ++++++++--- 2 files changed, 17 insertions(+), 7 deletions(-) diff --git a/app/src/main/java/com/owncloud/android/ui/activity/DrawerActivity.java b/app/src/main/java/com/owncloud/android/ui/activity/DrawerActivity.java index b35c10ea086f..0a5e614deb54 100644 --- a/app/src/main/java/com/owncloud/android/ui/activity/DrawerActivity.java +++ b/app/src/main/java/com/owncloud/android/ui/activity/DrawerActivity.java @@ -648,10 +648,7 @@ private void onNavigationItemClicked(final MenuItem menuItem) { } // from navigation user always sees root level - final var ocFileListFragment = getOCFileListFragment(); - if (ocFileListFragment != null) { - ocFileListFragment.resetFileDepth(); - } + resetFileDepth(); if (this instanceof FileDisplayActivity fda) { fda.configureMenuItem(); @@ -695,7 +692,15 @@ public void openAddAccount() { } } + private void resetFileDepth() { + final var ocFileListFragment = getOCFileListFragment(); + if (ocFileListFragment != null) { + ocFileListFragment.resetFileDepth(); + } + } + protected void openSharedTab() { + resetFileDepth(); resetOnlyPersonalAndOnDevice(); SearchEvent searchEvent = new SearchEvent("", SearchRemoteOperation.SearchType.SHARED_FILTER); launchActivityForSearch(searchEvent, R.id.nav_shared); diff --git a/app/src/main/java/com/owncloud/android/ui/activity/ToolbarActivity.java b/app/src/main/java/com/owncloud/android/ui/activity/ToolbarActivity.java index ab2518d22309..170af4e0408a 100644 --- a/app/src/main/java/com/owncloud/android/ui/activity/ToolbarActivity.java +++ b/app/src/main/java/com/owncloud/android/ui/activity/ToolbarActivity.java @@ -200,8 +200,8 @@ public String getActionBarRootTitle() { return result; } - public String getActionBarTitle(OCFile chosenFile) { - if (isRoot(chosenFile)) { + public String getActionBarTitle(OCFile chosenFile, boolean isRoot) { + if (isRoot) { return getActionBarRootTitle(); } @@ -225,7 +225,7 @@ protected void updateActionBarTitleAndHomeButton(OCFile chosenFile) { final OCFileDepth currentDirDepth = getCurrentDirDepth(); final boolean isRoot = isRoot(chosenFile) || currentDirDepth == OCFileDepth.Root; - final String title = getActionBarTitle(chosenFile); + final String title = getActionBarTitle(chosenFile, isRoot); updateActionBarTitleAndHomeButtonByString(title); final boolean isToolbarStyleSearch = DrawerActivity.isToolbarStyleSearch(); @@ -233,6 +233,11 @@ protected void updateActionBarTitleAndHomeButton(OCFile chosenFile) { showHomeSearchToolbar(canShowSearchBar); mSearchText.setText(getString(R.string.appbar_search_in, title)); + + final var actionBar = getSupportActionBar(); + if (actionBar != null) { + viewThemeUtils.files.themeActionBar(this, actionBar, title, isRoot); + } } From 8058f1bafba505ddefb099ee687f87d68723d8f4 Mon Sep 17 00:00:00 2001 From: alperozturk Date: Mon, 8 Dec 2025 14:52:50 +0100 Subject: [PATCH 037/216] fix overriding calculated behaviour via drawer slide Signed-off-by: alperozturk --- .../android/ui/activity/DrawerActivity.java | 19 +------------------ 1 file changed, 1 insertion(+), 18 deletions(-) diff --git a/app/src/main/java/com/owncloud/android/ui/activity/DrawerActivity.java b/app/src/main/java/com/owncloud/android/ui/activity/DrawerActivity.java index 0a5e614deb54..839fe14b1453 100644 --- a/app/src/main/java/com/owncloud/android/ui/activity/DrawerActivity.java +++ b/app/src/main/java/com/owncloud/android/ui/activity/DrawerActivity.java @@ -321,16 +321,10 @@ private void exitSelectionMode() { } } - /** - * initializes and sets up the drawer toggle. - */ private void setupDrawerToggle() { mDrawerToggle = new ActionBarDrawerToggle(this, mDrawerLayout, R.string.drawer_open, R.string.drawer_close) { - /** Called when a drawer has settled in a completely closed state. */ public void onDrawerClosed(View view) { super.onDrawerClosed(view); - supportInvalidateOptionsMenu(); - mDrawerToggle.setDrawerIndicatorEnabled(isDrawerIndicatorAvailable()); if (pendingRunnable != null) { new Handler().post(pendingRunnable); @@ -339,23 +333,12 @@ public void onDrawerClosed(View view) { closeDrawer(); } - - /** Called when a drawer has settled in a completely open state. */ - public void onDrawerOpened(View drawerView) { - super.onDrawerOpened(drawerView); - mDrawerToggle.setDrawerIndicatorEnabled(true); - supportInvalidateOptionsMenu(); - } }; - // Set the drawer toggle as the DrawerListener mDrawerLayout.addDrawerListener(mDrawerToggle); mDrawerToggle.setDrawerIndicatorEnabled(true); mDrawerToggle.setDrawerSlideAnimationEnabled(true); - Drawable backArrow = ResourcesCompat.getDrawable(getResources(), - R.drawable.ic_arrow_back, - null); - + final Drawable backArrow = ResourcesCompat.getDrawable(getResources(), R.drawable.ic_arrow_back, null); if (backArrow != null) { viewThemeUtils.platform.tintToolbarArrowDrawable(this, mDrawerToggle, backArrow); } From e666068ab5c4de6a03099a2e1f55c55f708b77e9 Mon Sep 17 00:00:00 2001 From: alperozturk Date: Mon, 8 Dec 2025 14:56:54 +0100 Subject: [PATCH 038/216] fix codacy Signed-off-by: alperozturk --- .../com/owncloud/android/ui/activity/FileDisplayActivity.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/src/main/java/com/owncloud/android/ui/activity/FileDisplayActivity.kt b/app/src/main/java/com/owncloud/android/ui/activity/FileDisplayActivity.kt index db75a12d1164..d1cc7ab5a097 100644 --- a/app/src/main/java/com/owncloud/android/ui/activity/FileDisplayActivity.kt +++ b/app/src/main/java/com/owncloud/android/ui/activity/FileDisplayActivity.kt @@ -2738,7 +2738,7 @@ class FileDisplayActivity : listOfFilesFragment?.setCurrentSearchType(event) updateActionBarTitleAndHomeButton(null) - //listOfFilesFragment?.setActionBarTitle() + // listOfFilesFragment?.setActionBarTitle() } @Subscribe(threadMode = ThreadMode.MAIN) From b471ff1c320cbb091a936e59cceb44491006a5d1 Mon Sep 17 00:00:00 2001 From: alperozturk Date: Mon, 8 Dec 2025 15:37:47 +0100 Subject: [PATCH 039/216] fix on device action bar Signed-off-by: alperozturk --- .../android/ui/activity/DrawerActivity.java | 13 +++++++++++-- .../android/ui/activity/FileDisplayActivity.kt | 14 +++++++++++--- .../android/ui/fragment/OCFileListFragment.java | 4 ++++ .../com/owncloud/android/ui/fragment/SearchType.kt | 4 +++- 4 files changed, 29 insertions(+), 6 deletions(-) diff --git a/app/src/main/java/com/owncloud/android/ui/activity/DrawerActivity.java b/app/src/main/java/com/owncloud/android/ui/activity/DrawerActivity.java index 839fe14b1453..54544bf54f67 100644 --- a/app/src/main/java/com/owncloud/android/ui/activity/DrawerActivity.java +++ b/app/src/main/java/com/owncloud/android/ui/activity/DrawerActivity.java @@ -579,8 +579,7 @@ private void onNavigationItemClicked(final MenuItem menuItem) { setupToolbar(); startPhotoSearch(menuItem.getItemId()); } else if (itemId == R.id.nav_on_device) { - EventBus.getDefault().post(new ChangeMenuEvent()); - showFiles(true, false); + showOnDeviceFiles(); } else if (itemId == R.id.nav_uploads) { resetOnlyPersonalAndOnDevice(); startActivity(UploadListActivity.class, Intent.FLAG_ACTIVITY_CLEAR_TOP); @@ -1255,6 +1254,16 @@ public void showFiles(boolean onDeviceOnly, boolean onlyPersonalFiles) { startActivity(intent); } + private void showOnDeviceFiles() { + MainApp.showOnlyFilesOnDevice(true); + MainApp.showOnlyPersonalFiles(false); + + Intent intent = new Intent(getApplicationContext(), FileDisplayActivity.class); + intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP); + intent.setAction(FileDisplayActivity.ON_DEVICE); + startActivity(intent); + } + @Override public void avatarGenerated(Drawable avatarDrawable, Object callContext) { if (callContext instanceof MenuItem menuItem) { diff --git a/app/src/main/java/com/owncloud/android/ui/activity/FileDisplayActivity.kt b/app/src/main/java/com/owncloud/android/ui/activity/FileDisplayActivity.kt index d1cc7ab5a097..3970987ef7db 100644 --- a/app/src/main/java/com/owncloud/android/ui/activity/FileDisplayActivity.kt +++ b/app/src/main/java/com/owncloud/android/ui/activity/FileDisplayActivity.kt @@ -572,6 +572,12 @@ class FileDisplayActivity : leftFragment = GroupfolderListFragment() supportFragmentManager.executePendingTransactions() } + + ON_DEVICE == action -> { + refreshOrInitOCFileListFragment() + listOfFilesFragment?.setCurrentSearchType(SearchType.ON_DEVICE) + updateActionBarTitleAndHomeButton(null) + } } } @@ -2712,9 +2718,10 @@ class FileDisplayActivity : override fun showFiles(onDeviceOnly: Boolean, personalFiles: Boolean) { super.showFiles(onDeviceOnly, personalFiles) - if (onDeviceOnly) { - updateActionBarTitleAndHomeButtonByString(getString(R.string.drawer_item_on_device)) - } + refreshOrInitOCFileListFragment() + } + + private fun refreshOrInitOCFileListFragment() { val ocFileListFragment = this.listOfFilesFragment if (ocFileListFragment != null && (ocFileListFragment !is GalleryFragment) && @@ -3062,6 +3069,7 @@ class FileDisplayActivity : const val LIST_GROUPFOLDERS: String = "LIST_GROUPFOLDERS" const val SINGLE_USER_SIZE: Int = 1 const val OPEN_FILE: String = "NC_OPEN_FILE" + const val ON_DEVICE = "ON_DEVICE" const val TAG_PUBLIC_LINK: String = "PUBLIC_LINK" const val FTAG_CHOOSER_DIALOG: String = "CHOOSER_DIALOG" diff --git a/app/src/main/java/com/owncloud/android/ui/fragment/OCFileListFragment.java b/app/src/main/java/com/owncloud/android/ui/fragment/OCFileListFragment.java index 6149709b438c..5eb9e2c3fd6b 100644 --- a/app/src/main/java/com/owncloud/android/ui/fragment/OCFileListFragment.java +++ b/app/src/main/java/com/owncloud/android/ui/fragment/OCFileListFragment.java @@ -1752,6 +1752,10 @@ public void setCurrentSearchType(SearchEvent event) { } } + public void setCurrentSearchType(SearchType searchType) { + currentSearchType = searchType; + } + public SearchType getCurrentSearchType() { return currentSearchType; } diff --git a/app/src/main/java/com/owncloud/android/ui/fragment/SearchType.kt b/app/src/main/java/com/owncloud/android/ui/fragment/SearchType.kt index 7827e6d053f9..0e473690a7e4 100644 --- a/app/src/main/java/com/owncloud/android/ui/fragment/SearchType.kt +++ b/app/src/main/java/com/owncloud/android/ui/fragment/SearchType.kt @@ -24,13 +24,15 @@ enum class SearchType : Parcelable { // not a real filter, but nevertheless SHARED_FILTER, - GROUPFOLDER; + GROUPFOLDER, + ON_DEVICE; fun titleId(): Int? = when (this) { FAVORITE_SEARCH -> R.string.drawer_item_favorites GALLERY_SEARCH -> R.string.drawer_item_gallery RECENTLY_MODIFIED_SEARCH -> R.string.drawer_item_recently_modified SHARED_FILTER -> R.string.drawer_item_shared + ON_DEVICE -> R.string.drawer_item_on_device else -> null } } From a91774a297d783d39645bb785ba348580eaf427f Mon Sep 17 00:00:00 2001 From: alperozturk Date: Mon, 8 Dec 2025 16:21:06 +0100 Subject: [PATCH 040/216] fix multiple item highlight Signed-off-by: alperozturk --- .../android/ui/activity/DrawerActivity.java | 54 ++++++++++++------- .../android/ui/events/DummyDrawerEvent.kt | 13 ----- 2 files changed, 34 insertions(+), 33 deletions(-) delete mode 100644 app/src/main/java/com/owncloud/android/ui/events/DummyDrawerEvent.kt diff --git a/app/src/main/java/com/owncloud/android/ui/activity/DrawerActivity.java b/app/src/main/java/com/owncloud/android/ui/activity/DrawerActivity.java index 54544bf54f67..3bd267cdc3e1 100644 --- a/app/src/main/java/com/owncloud/android/ui/activity/DrawerActivity.java +++ b/app/src/main/java/com/owncloud/android/ui/activity/DrawerActivity.java @@ -87,7 +87,6 @@ import com.owncloud.android.ui.activities.ActivitiesActivity; import com.owncloud.android.ui.events.AccountRemovedEvent; import com.owncloud.android.ui.events.ChangeMenuEvent; -import com.owncloud.android.ui.events.DummyDrawerEvent; import com.owncloud.android.ui.events.SearchEvent; import com.owncloud.android.ui.fragment.FileDetailsSharingProcessFragment; import com.owncloud.android.ui.fragment.GalleryFragment; @@ -177,6 +176,8 @@ public abstract class DrawerActivity extends ToolbarActivity */ public static int menuItemId = Menu.NONE; + public static int previousMenuItemId = Menu.NONE; + /** * container layout of the quota view. */ @@ -263,9 +264,22 @@ private void checkAssistantBottomNavigationMenu() { .setVisible(isAssistantAvailable); } + private void openFavoritesTab(int menuItemId) { + resetOnlyPersonalAndOnDevice(); + setupToolbar(); + handleSearchEvents(new SearchEvent("", SearchRemoteOperation.SearchType.FAVORITE_SEARCH), menuItemId); + } + + private void openMediaTab(int menuItemId) { + resetOnlyPersonalAndOnDevice(); + setupToolbar(); + startPhotoSearch(menuItemId); + } + @SuppressFBWarnings("RV") private void handleBottomNavigationViewClicks() { bottomNavigationView.setOnItemSelectedListener(menuItem -> { + previousMenuItemId = menuItemId; menuItemId = menuItem.getItemId(); exitSelectionMode(); @@ -278,14 +292,11 @@ private void handleBottomNavigationViewClicks() { } EventBus.getDefault().post(new ChangeMenuEvent()); } else if (menuItemId == R.id.nav_favorites) { - resetOnlyPersonalAndOnDevice(); - setupToolbar(); - handleSearchEvents(new SearchEvent("", SearchRemoteOperation.SearchType.FAVORITE_SEARCH), menuItemId); + openFavoritesTab(menuItem.getItemId()); } else if (menuItemId == R.id.nav_assistant && !(this instanceof ComposeActivity)) { startComposeActivity(new ComposeDestination.AssistantScreen(null), R.string.assistant_screen_top_bar_title); } else if (menuItemId == R.id.nav_gallery) { - setupToolbar(); - startPhotoSearch(menuItem.getItemId()); + openMediaTab(menuItem.getItemId()); } // Remove extra icon from the action bar @@ -536,12 +547,8 @@ private void filterDrawerMenu(final Menu menu, @NonNull final User user) { DrawerMenuUtil.removeMenuItem(menu, R.id.nav_logout, !getResources().getBoolean(R.bool.show_drawer_logout)); } - @Subscribe(threadMode = ThreadMode.MAIN) - public void onMessageEvent(DummyDrawerEvent event) { - unsetAllDrawerMenuItems(); - } - private void onNavigationItemClicked(final MenuItem menuItem) { + previousMenuItemId = menuItemId; int itemId = menuItem.getItemId(); // Settings screen cannot display drawer menu thus no need to highlight @@ -571,13 +578,9 @@ private void onNavigationItemClicked(final MenuItem menuItem) { closeDrawer(); } else if (itemId == R.id.nav_favorites) { - resetOnlyPersonalAndOnDevice(); - setupToolbar(); - handleSearchEvents(new SearchEvent("", SearchRemoteOperation.SearchType.FAVORITE_SEARCH), menuItem.getItemId()); + openFavoritesTab(menuItem.getItemId()); } else if (itemId == R.id.nav_gallery) { - resetOnlyPersonalAndOnDevice(); - setupToolbar(); - startPhotoSearch(menuItem.getItemId()); + openMediaTab(menuItem.getItemId()); } else if (itemId == R.id.nav_on_device) { showOnDeviceFiles(); } else if (itemId == R.id.nav_uploads) { @@ -874,14 +877,18 @@ private void setQuotaInformation(long usedSpace, long totalSpace, int relative, private void unsetAllDrawerMenuItems() { if (drawerNavigationView != null) { - drawerNavigationView.getMenu(); Menu menu = drawerNavigationView.getMenu(); for (int i = 0; i < menu.size(); i++) { menu.getItem(i).setChecked(false); } } - menuItemId = Menu.NONE; + if (bottomNavigationView != null) { + Menu menu = bottomNavigationView.getMenu(); + for (int i = 0; i < menu.size(); i++) { + menu.getItem(i).setChecked(false); + } + } } private void updateQuotaLink() { @@ -957,12 +964,19 @@ public void onLoadFailed(@Nullable Drawable errorDrawable) { */ @SuppressFBWarnings("RV") public void setNavigationViewItemChecked() { + unsetAllDrawerMenuItems(); + + // Don't check any items + if (menuItemId == Menu.NONE) { + return; + } + if (drawerNavigationView != null) { MenuItem menuItem = drawerNavigationView.getMenu().findItem(menuItemId); if (menuItem != null && !menuItem.isChecked()) { - viewThemeUtils.platform.colorNavigationView(drawerNavigationView); menuItem.setChecked(true); + viewThemeUtils.platform.colorNavigationView(drawerNavigationView); } } diff --git a/app/src/main/java/com/owncloud/android/ui/events/DummyDrawerEvent.kt b/app/src/main/java/com/owncloud/android/ui/events/DummyDrawerEvent.kt deleted file mode 100644 index 795d56460c1c..000000000000 --- a/app/src/main/java/com/owncloud/android/ui/events/DummyDrawerEvent.kt +++ /dev/null @@ -1,13 +0,0 @@ -/* - * Nextcloud - Android Client - * - * SPDX-FileCopyrightText: 2017 Mario Danic - * SPDX-FileCopyrightText: 2017 Nextcloud GmbH - * SPDX-License-Identifier: AGPL-3.0-or-later OR GPL-2.0-only - */ -package com.owncloud.android.ui.events - -/** - * Dummy drawer event - */ -class DummyDrawerEvent From f51df53c0b4cd179b4e0de390b80b04d7612c7a6 Mon Sep 17 00:00:00 2001 From: alperozturk Date: Mon, 8 Dec 2025 16:21:23 +0100 Subject: [PATCH 041/216] fix back button behaviour from trashbin Signed-off-by: alperozturk --- .../java/com/owncloud/android/ui/trashbin/TrashbinActivity.kt | 3 +++ 1 file changed, 3 insertions(+) diff --git a/app/src/main/java/com/owncloud/android/ui/trashbin/TrashbinActivity.kt b/app/src/main/java/com/owncloud/android/ui/trashbin/TrashbinActivity.kt index 75fc42f109fd..aa696499c6de 100644 --- a/app/src/main/java/com/owncloud/android/ui/trashbin/TrashbinActivity.kt +++ b/app/src/main/java/com/owncloud/android/ui/trashbin/TrashbinActivity.kt @@ -90,6 +90,7 @@ class TrashbinActivity : private val onBackPressedCallback = object : OnBackPressedCallback(true) { override fun handleOnBackPressed() { + isEnabled = false trashbinPresenter?.navigateUp() } } @@ -292,6 +293,8 @@ class TrashbinActivity : } override fun onPause() { + menuItemId = previousMenuItemId + setNavigationViewItemChecked() super.onPause() active = false trashbinListAdapter?.cancelAllPendingTasks() From 0c0ece2ab5d23130d247128c71e8f5df30573ea3 Mon Sep 17 00:00:00 2001 From: alperozturk Date: Tue, 9 Dec 2025 08:36:26 +0100 Subject: [PATCH 042/216] fix file name in action bar Signed-off-by: alperozturk --- .../ui/activity/FileDisplayActivity.kt | 2 +- .../android/ui/activity/ToolbarActivity.java | 36 ++++++++++++------- 2 files changed, 24 insertions(+), 14 deletions(-) diff --git a/app/src/main/java/com/owncloud/android/ui/activity/FileDisplayActivity.kt b/app/src/main/java/com/owncloud/android/ui/activity/FileDisplayActivity.kt index 3970987ef7db..bcbd74422841 100644 --- a/app/src/main/java/com/owncloud/android/ui/activity/FileDisplayActivity.kt +++ b/app/src/main/java/com/owncloud/android/ui/activity/FileDisplayActivity.kt @@ -2564,7 +2564,7 @@ class FileDisplayActivity : fun configureToolbarForPreview(file: OCFile?) { lockScrolling() - super.updateActionBarTitleAndHomeButton(file) + updateActionBarForFile(file) } /** diff --git a/app/src/main/java/com/owncloud/android/ui/activity/ToolbarActivity.java b/app/src/main/java/com/owncloud/android/ui/activity/ToolbarActivity.java index 170af4e0408a..dc3d232e71b2 100644 --- a/app/src/main/java/com/owncloud/android/ui/activity/ToolbarActivity.java +++ b/app/src/main/java/com/owncloud/android/ui/activity/ToolbarActivity.java @@ -46,6 +46,7 @@ import javax.inject.Inject; import androidx.annotation.NonNull; +import androidx.annotation.Nullable; import androidx.annotation.StringRes; import androidx.appcompat.app.ActionBar; import androidx.appcompat.widget.AppCompatSpinner; @@ -205,27 +206,22 @@ public String getActionBarTitle(OCFile chosenFile, boolean isRoot) { return getActionBarRootTitle(); } - if (chosenFile.isFolder()) { - return fileDataStorageManager.getFilenameConsideringOfflineOperation(chosenFile); - } - - long parentId = chosenFile.getParentId(); - OCFile parentFile = fileDataStorageManager.getFileById(parentId); - if (parentFile == null) { - return ""; - } + return getActionBarTitleFromFile(chosenFile); + } - return fileDataStorageManager.getFilenameConsideringOfflineOperation(parentFile); + private String getActionBarTitleFromFile(OCFile file) { + // if offline rename operation already pointing same file, offline operation name will be used + return fileDataStorageManager.getFilenameConsideringOfflineOperation(file); } - protected void updateActionBarTitleAndHomeButton(OCFile chosenFile) { + protected void updateActionBarTitleAndHomeButton(OCFile file) { if (mAppBar == null) { return; } final OCFileDepth currentDirDepth = getCurrentDirDepth(); - final boolean isRoot = isRoot(chosenFile) || currentDirDepth == OCFileDepth.Root; - final String title = getActionBarTitle(chosenFile, isRoot); + final boolean isRoot = isRoot(file) || currentDirDepth == OCFileDepth.Root; + final String title = getActionBarTitle(file, isRoot); updateActionBarTitleAndHomeButtonByString(title); final boolean isToolbarStyleSearch = DrawerActivity.isToolbarStyleSearch(); @@ -240,6 +236,20 @@ protected void updateActionBarTitleAndHomeButton(OCFile chosenFile) { } } + protected void updateActionBarForFile(@Nullable OCFile file) { + if (mAppBar == null || file == null) { + return; + } + + final String title = getActionBarTitleFromFile(file); + updateActionBarTitleAndHomeButtonByString(title); + + showHomeSearchToolbar(false); + final var actionBar = getSupportActionBar(); + if (actionBar != null) { + viewThemeUtils.files.themeActionBar(this, actionBar, title, false); + } + } public void showSearchView() { if (isHomeSearchToolbarShow) { From faf6745d1ce72194cdebe71a137cdc534541f492 Mon Sep 17 00:00:00 2001 From: alperozturk Date: Tue, 9 Dec 2025 08:41:42 +0100 Subject: [PATCH 043/216] fix lint Signed-off-by: alperozturk --- .../android/ui/activity/DrawerActivity.java | 14 +++++++++++--- .../android/ui/fragment/OCFileListFragment.java | 2 +- .../android/ui/trashbin/TrashbinActivity.kt | 2 +- 3 files changed, 13 insertions(+), 5 deletions(-) diff --git a/app/src/main/java/com/owncloud/android/ui/activity/DrawerActivity.java b/app/src/main/java/com/owncloud/android/ui/activity/DrawerActivity.java index 3bd267cdc3e1..1b19cb80957b 100644 --- a/app/src/main/java/com/owncloud/android/ui/activity/DrawerActivity.java +++ b/app/src/main/java/com/owncloud/android/ui/activity/DrawerActivity.java @@ -176,7 +176,7 @@ public abstract class DrawerActivity extends ToolbarActivity */ public static int menuItemId = Menu.NONE; - public static int previousMenuItemId = Menu.NONE; + private static int previousMenuItemId = Menu.NONE; /** * container layout of the quota view. @@ -279,7 +279,7 @@ private void openMediaTab(int menuItemId) { @SuppressFBWarnings("RV") private void handleBottomNavigationViewClicks() { bottomNavigationView.setOnItemSelectedListener(menuItem -> { - previousMenuItemId = menuItemId; + setPreviousMenuItemId(menuItemId); menuItemId = menuItem.getItemId(); exitSelectionMode(); @@ -548,7 +548,7 @@ private void filterDrawerMenu(final Menu menu, @NonNull final User user) { } private void onNavigationItemClicked(final MenuItem menuItem) { - previousMenuItemId = menuItemId; + setPreviousMenuItemId(menuItemId); int itemId = menuItem.getItemId(); // Settings screen cannot display drawer menu thus no need to highlight @@ -1468,4 +1468,12 @@ public static boolean isToolbarStyleSearch() { menuItemId == R.id.nav_all_files || menuItemId == R.id.nav_personal_files; } + + public static int getPreviousMenuItemId() { + return previousMenuItemId; + } + + public static void setPreviousMenuItemId(int menuItemId) { + previousMenuItemId = menuItemId; + } } diff --git a/app/src/main/java/com/owncloud/android/ui/fragment/OCFileListFragment.java b/app/src/main/java/com/owncloud/android/ui/fragment/OCFileListFragment.java index 5eb9e2c3fd6b..86fa27d10b98 100644 --- a/app/src/main/java/com/owncloud/android/ui/fragment/OCFileListFragment.java +++ b/app/src/main/java/com/owncloud/android/ui/fragment/OCFileListFragment.java @@ -304,7 +304,7 @@ public void onAttach(@NonNull Context context) { } private void setSearchArgs(Bundle state) { - SearchType argSearchType = null; + SearchType argSearchType = NO_SEARCH; SearchEvent argSearchEvent = null; if (state != null) { diff --git a/app/src/main/java/com/owncloud/android/ui/trashbin/TrashbinActivity.kt b/app/src/main/java/com/owncloud/android/ui/trashbin/TrashbinActivity.kt index aa696499c6de..3f770ebdebff 100644 --- a/app/src/main/java/com/owncloud/android/ui/trashbin/TrashbinActivity.kt +++ b/app/src/main/java/com/owncloud/android/ui/trashbin/TrashbinActivity.kt @@ -293,7 +293,7 @@ class TrashbinActivity : } override fun onPause() { - menuItemId = previousMenuItemId + menuItemId = getPreviousMenuItemId() setNavigationViewItemChecked() super.onPause() active = false From c17d5e1254a7ad6676119dc35751b58fac2bab1c Mon Sep 17 00:00:00 2001 From: alperozturk Date: Tue, 9 Dec 2025 08:45:20 +0100 Subject: [PATCH 044/216] reset file depth for bottom navigation view as well Signed-off-by: alperozturk --- .../android/ui/activity/DrawerActivity.java | 75 ++++++++++--------- 1 file changed, 41 insertions(+), 34 deletions(-) diff --git a/app/src/main/java/com/owncloud/android/ui/activity/DrawerActivity.java b/app/src/main/java/com/owncloud/android/ui/activity/DrawerActivity.java index 1b19cb80957b..b8c06c4e32a4 100644 --- a/app/src/main/java/com/owncloud/android/ui/activity/DrawerActivity.java +++ b/app/src/main/java/com/owncloud/android/ui/activity/DrawerActivity.java @@ -276,40 +276,6 @@ private void openMediaTab(int menuItemId) { startPhotoSearch(menuItemId); } - @SuppressFBWarnings("RV") - private void handleBottomNavigationViewClicks() { - bottomNavigationView.setOnItemSelectedListener(menuItem -> { - setPreviousMenuItemId(menuItemId); - menuItemId = menuItem.getItemId(); - - exitSelectionMode(); - resetOnlyPersonalAndOnDevice(); - - if (menuItemId == R.id.nav_all_files) { - showFiles(false,false); - if (this instanceof FileDisplayActivity fda) { - fda.browseToRoot(); - } - EventBus.getDefault().post(new ChangeMenuEvent()); - } else if (menuItemId == R.id.nav_favorites) { - openFavoritesTab(menuItem.getItemId()); - } else if (menuItemId == R.id.nav_assistant && !(this instanceof ComposeActivity)) { - startComposeActivity(new ComposeDestination.AssistantScreen(null), R.string.assistant_screen_top_bar_title); - } else if (menuItemId == R.id.nav_gallery) { - openMediaTab(menuItem.getItemId()); - } - - // Remove extra icon from the action bar - if (getSupportActionBar() != null) { - getSupportActionBar().setIcon(null); - } - - setNavigationViewItemChecked(); - - return false; - }); - } - @Nullable public OCFileListFragment getOCFileListFragment() { Fragment fragment = ActivityExtensionsKt.lastFragment(this); @@ -547,6 +513,7 @@ private void filterDrawerMenu(final Menu menu, @NonNull final User user) { DrawerMenuUtil.removeMenuItem(menu, R.id.nav_logout, !getResources().getBoolean(R.bool.show_drawer_logout)); } + // region navigation item click private void onNavigationItemClicked(final MenuItem menuItem) { setPreviousMenuItemId(menuItemId); int itemId = menuItem.getItemId(); @@ -632,6 +599,46 @@ private void onNavigationItemClicked(final MenuItem menuItem) { } } + resetFileDepthAndConfigureMenuItem(); + } + + @SuppressFBWarnings("RV") + private void handleBottomNavigationViewClicks() { + bottomNavigationView.setOnItemSelectedListener(menuItem -> { + setPreviousMenuItemId(menuItemId); + menuItemId = menuItem.getItemId(); + + exitSelectionMode(); + resetOnlyPersonalAndOnDevice(); + + if (menuItemId == R.id.nav_all_files) { + showFiles(false,false); + if (this instanceof FileDisplayActivity fda) { + fda.browseToRoot(); + } + EventBus.getDefault().post(new ChangeMenuEvent()); + } else if (menuItemId == R.id.nav_favorites) { + openFavoritesTab(menuItem.getItemId()); + } else if (menuItemId == R.id.nav_assistant && !(this instanceof ComposeActivity)) { + startComposeActivity(new ComposeDestination.AssistantScreen(null), R.string.assistant_screen_top_bar_title); + } else if (menuItemId == R.id.nav_gallery) { + openMediaTab(menuItem.getItemId()); + } + + // Remove extra icon from the action bar + if (getSupportActionBar() != null) { + getSupportActionBar().setIcon(null); + } + + setNavigationViewItemChecked(); + resetFileDepthAndConfigureMenuItem(); + + return false; + }); + } + // endregion + + private void resetFileDepthAndConfigureMenuItem() { // from navigation user always sees root level resetFileDepth(); From 908587fefca8165ab184f5220584022e88d11020 Mon Sep 17 00:00:00 2001 From: alperozturk Date: Tue, 9 Dec 2025 10:10:39 +0100 Subject: [PATCH 045/216] fix image preview Signed-off-by: alperozturk --- .../android/ui/activity/ToolbarActivity.java | 16 ++++++---- .../ui/preview/PreviewImageActivity.kt | 29 ++++++++----------- 2 files changed, 22 insertions(+), 23 deletions(-) diff --git a/app/src/main/java/com/owncloud/android/ui/activity/ToolbarActivity.java b/app/src/main/java/com/owncloud/android/ui/activity/ToolbarActivity.java index dc3d232e71b2..2d18da86aaa9 100644 --- a/app/src/main/java/com/owncloud/android/ui/activity/ToolbarActivity.java +++ b/app/src/main/java/com/owncloud/android/ui/activity/ToolbarActivity.java @@ -215,10 +215,6 @@ private String getActionBarTitleFromFile(OCFile file) { } protected void updateActionBarTitleAndHomeButton(OCFile file) { - if (mAppBar == null) { - return; - } - final OCFileDepth currentDirDepth = getCurrentDirDepth(); final boolean isRoot = isRoot(file) || currentDirDepth == OCFileDepth.Root; final String title = getActionBarTitle(file, isRoot); @@ -228,7 +224,10 @@ protected void updateActionBarTitleAndHomeButton(OCFile file) { final boolean canShowSearchBar = (isHomeSearchToolbarShow && isRoot && isToolbarStyleSearch); showHomeSearchToolbar(canShowSearchBar); - mSearchText.setText(getString(R.string.appbar_search_in, title)); + + if (mSearchText != null) { + mSearchText.setText(getString(R.string.appbar_search_in, title)); + } final var actionBar = getSupportActionBar(); if (actionBar != null) { @@ -237,7 +236,7 @@ protected void updateActionBarTitleAndHomeButton(OCFile file) { } protected void updateActionBarForFile(@Nullable OCFile file) { - if (mAppBar == null || file == null) { + if (file == null) { return; } @@ -265,7 +264,12 @@ public void hideSearchView(OCFile chosenFile) { @SuppressLint("PrivateResource") private void showHomeSearchToolbar(boolean isShow) { + if (mAppBar == null) { + return; + } + viewThemeUtils.material.themeToolbar(mToolbar); + if (isShow) { viewThemeUtils.platform.resetStatusBar(this); mAppBar.setStateListAnimator(AnimatorInflater.loadStateListAnimator(mAppBar.getContext(), diff --git a/app/src/main/java/com/owncloud/android/ui/preview/PreviewImageActivity.kt b/app/src/main/java/com/owncloud/android/ui/preview/PreviewImageActivity.kt index 2e06e910a95f..fae01995f9c3 100644 --- a/app/src/main/java/com/owncloud/android/ui/preview/PreviewImageActivity.kt +++ b/app/src/main/java/com/owncloud/android/ui/preview/PreviewImageActivity.kt @@ -10,11 +10,11 @@ import android.content.BroadcastReceiver import android.content.Context import android.content.Intent import android.content.IntentFilter +import android.graphics.drawable.ColorDrawable import android.os.Bundle import android.view.MenuItem import android.view.View import androidx.activity.OnBackPressedCallback -import androidx.appcompat.app.ActionBar import androidx.core.content.ContextCompat import androidx.drawerlayout.widget.DrawerLayout import androidx.localbroadcastmanager.content.LocalBroadcastManager @@ -82,21 +82,17 @@ class PreviewImageActivity : @Inject lateinit var localBroadcastManager: LocalBroadcastManager - private var actionBar: ActionBar? = null - override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) - actionBar = supportActionBar - if (savedInstanceState != null && !savedInstanceState.getBoolean( KEY_SYSTEM_VISIBLE, true ) && - actionBar != null + supportActionBar != null ) { - actionBar?.hide() + supportActionBar?.hide() } setContentView(R.layout.preview_image_activity) @@ -106,11 +102,14 @@ class PreviewImageActivity : setupDrawer() val chosenFile = intent.getParcelableArgument(EXTRA_FILE, OCFile::class.java) - updateActionBarTitleAndHomeButton(chosenFile) - if (actionBar != null) { - viewThemeUtils.files.setWhiteBackButton(this, actionBar!!) - actionBar?.setDisplayHomeAsUpEnabled(true) + supportActionBar?.let { + updateActionBarTitleAndHomeButton(chosenFile) + viewThemeUtils.files.setWhiteBackButton(this, it) + it.setDisplayHomeAsUpEnabled(true) + it.setBackgroundDrawable( + ColorDrawable(ContextCompat.getColor(this, R.color.black)) + ) } fullScreenAnchorView = window.decorView @@ -147,14 +146,10 @@ class PreviewImageActivity : } fun toggleActionBarVisibility(hide: Boolean) { - if (actionBar == null) { - return - } - if (hide) { - actionBar?.hide() + supportActionBar?.hide() } else { - actionBar?.show() + supportActionBar?.show() } } From 6f44834623c1ab096f3929f132fbb1f647696eff Mon Sep 17 00:00:00 2001 From: alperozturk Date: Wed, 10 Dec 2025 11:54:20 +0100 Subject: [PATCH 046/216] fix: search fragment value Signed-off-by: alperozturk --- .../com/owncloud/android/ui/activity/DrawerActivity.java | 9 +++++---- .../owncloud/android/ui/fragment/OCFileListFragment.java | 6 ++++++ 2 files changed, 11 insertions(+), 4 deletions(-) diff --git a/app/src/main/java/com/owncloud/android/ui/activity/DrawerActivity.java b/app/src/main/java/com/owncloud/android/ui/activity/DrawerActivity.java index b8c06c4e32a4..c1ce36bdf5e0 100644 --- a/app/src/main/java/com/owncloud/android/ui/activity/DrawerActivity.java +++ b/app/src/main/java/com/owncloud/android/ui/activity/DrawerActivity.java @@ -264,10 +264,11 @@ private void checkAssistantBottomNavigationMenu() { .setVisible(isAssistantAvailable); } - private void openFavoritesTab(int menuItemId) { + private void openFavoritesTab() { resetOnlyPersonalAndOnDevice(); setupToolbar(); - handleSearchEvents(new SearchEvent("", SearchRemoteOperation.SearchType.FAVORITE_SEARCH), menuItemId); + SearchEvent searchEvent = new SearchEvent("", SearchRemoteOperation.SearchType.FAVORITE_SEARCH); + launchActivityForSearch(searchEvent, R.id.nav_favorites); } private void openMediaTab(int menuItemId) { @@ -545,7 +546,7 @@ private void onNavigationItemClicked(final MenuItem menuItem) { closeDrawer(); } else if (itemId == R.id.nav_favorites) { - openFavoritesTab(menuItem.getItemId()); + openFavoritesTab(); } else if (itemId == R.id.nav_gallery) { openMediaTab(menuItem.getItemId()); } else if (itemId == R.id.nav_on_device) { @@ -618,7 +619,7 @@ private void handleBottomNavigationViewClicks() { } EventBus.getDefault().post(new ChangeMenuEvent()); } else if (menuItemId == R.id.nav_favorites) { - openFavoritesTab(menuItem.getItemId()); + openFavoritesTab(); } else if (menuItemId == R.id.nav_assistant && !(this instanceof ComposeActivity)) { startComposeActivity(new ComposeDestination.AssistantScreen(null), R.string.assistant_screen_top_bar_title); } else if (menuItemId == R.id.nav_gallery) { diff --git a/app/src/main/java/com/owncloud/android/ui/fragment/OCFileListFragment.java b/app/src/main/java/com/owncloud/android/ui/fragment/OCFileListFragment.java index 86fa27d10b98..129c22f88d83 100644 --- a/app/src/main/java/com/owncloud/android/ui/fragment/OCFileListFragment.java +++ b/app/src/main/java/com/owncloud/android/ui/fragment/OCFileListFragment.java @@ -1059,6 +1059,12 @@ public int onBrowseUp() { Pair result = futureResult.get(); mFile = result.second; setFileDepth(mFile); + + // since on browse down sets it to the false, browse up should set back to true if current search type is not NO_SEARCH + if (mFile.isRootDirectory() && currentSearchType != NO_SEARCH) { + searchFragment = true; + } + updateFileList(); return result.first; } catch (Exception e) { From 1fb97739746ebfeb3fb2f2e36de06f427ec9f3d3 Mon Sep 17 00:00:00 2001 From: alperozturk Date: Fri, 12 Dec 2025 16:15:07 +0100 Subject: [PATCH 047/216] fix FileDetailsFragmentBinding.progressBlock' on a null object reference Signed-off-by: alperozturk --- .../owncloud/android/ui/fragment/FileDetailFragment.java | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/app/src/main/java/com/owncloud/android/ui/fragment/FileDetailFragment.java b/app/src/main/java/com/owncloud/android/ui/fragment/FileDetailFragment.java index e1990f7b652a..555286f2e6ad 100644 --- a/app/src/main/java/com/owncloud/android/ui/fragment/FileDetailFragment.java +++ b/app/src/main/java/com/owncloud/android/ui/fragment/FileDetailFragment.java @@ -231,6 +231,7 @@ public View onCreateView(@NonNull LayoutInflater inflater, ViewGroup container, } binding = FileDetailsFragmentBinding.inflate(inflater, container, false); + observeWorkerState(); view = binding.getRoot(); if (getFile() == null || user == null) { @@ -610,8 +611,6 @@ public void updateFileDetails(boolean transferring, boolean refresh) { if (view != null) { view.invalidate(); } - - observeWorkerState(); } @Subscribe(threadMode = ThreadMode.MAIN) @@ -627,6 +626,10 @@ public void onDownloadProgress(FileDownloadProgressEvent event) { private void observeWorkerState() { ActivityExtensionsKt.observeWorker(requireActivity(), state -> { + if (binding == null) { + return Unit.INSTANCE; + } + if (state instanceof WorkerState.FileUploadStarted) { binding.progressText.setText(R.string.uploader_upload_in_progress_ticker); } else { From 625085edea943c4b996a6f66f185de411ed07b4a Mon Sep 17 00:00:00 2001 From: alperozturk Date: Fri, 12 Dec 2025 16:57:27 +0100 Subject: [PATCH 048/216] fix getPreviousFile Signed-off-by: alperozturk --- .../ui/activity/FileDisplayActivity.kt | 10 -- .../ui/fragment/OCFileListFragment.java | 153 ++++++------------ 2 files changed, 47 insertions(+), 116 deletions(-) diff --git a/app/src/main/java/com/owncloud/android/ui/activity/FileDisplayActivity.kt b/app/src/main/java/com/owncloud/android/ui/activity/FileDisplayActivity.kt index bcbd74422841..cdbe74d9b833 100644 --- a/app/src/main/java/com/owncloud/android/ui/activity/FileDisplayActivity.kt +++ b/app/src/main/java/com/owncloud/android/ui/activity/FileDisplayActivity.kt @@ -89,7 +89,6 @@ import com.owncloud.android.R import com.owncloud.android.databinding.FilesBinding import com.owncloud.android.datamodel.FileDataStorageManager import com.owncloud.android.datamodel.OCFile -import com.owncloud.android.datamodel.OCFileDepth import com.owncloud.android.datamodel.SyncedFolderProvider import com.owncloud.android.datamodel.VirtualFolderType import com.owncloud.android.files.services.NameCollisionPolicy @@ -1186,15 +1185,6 @@ class FileDisplayActivity : } } - // shared root - fragment is SharedListFragment && fragment.fileDepth == OCFileDepth.Root -> { - openDrawer() - } - - fragment is SharedListFragment && fragment.fileDepth == OCFileDepth.FirstLevel -> { - openSharedTab() - } - // Normal folder navigation (go up) also works for shared tab else -> { browseUp(fragment) diff --git a/app/src/main/java/com/owncloud/android/ui/fragment/OCFileListFragment.java b/app/src/main/java/com/owncloud/android/ui/fragment/OCFileListFragment.java index 129c22f88d83..bbdad0785f39 100644 --- a/app/src/main/java/com/owncloud/android/ui/fragment/OCFileListFragment.java +++ b/app/src/main/java/com/owncloud/android/ui/fragment/OCFileListFragment.java @@ -126,9 +126,6 @@ import java.util.List; import java.util.Objects; import java.util.Set; -import java.util.concurrent.CompletableFuture; -import java.util.concurrent.Executors; -import java.util.concurrent.Future; import javax.inject.Inject; @@ -954,128 +951,72 @@ private void updateSortAndGridMenuItems() { } } - private boolean shouldNavigateWithoutFilter(OCFile topParent) { - int menuItemId = DrawerActivity.menuItemId; - return (menuItemId != R.id.nav_shared && menuItemId != R.id.nav_favorites) || - (menuItemId == R.id.nav_shared && topParent != null && topParent.isShared()) || - (menuItemId == R.id.nav_favorites && topParent != null && topParent.isFavorite()); - } - private boolean shouldNavigateWithFilter() { - int menuItemId = DrawerActivity.menuItemId; - return menuItemId == R.id.nav_shared || menuItemId == R.id.nav_favorites; + /** + * Call this, when the user presses the up button. + *

+ * Tries to move up the current folder one level. If the parent folder was removed from the database, it continues + * browsing up until finding an existing folders. + *

+ * return Count of folder levels browsed up. + */ + public int onBrowseUp() { + if (mFile == null) { + return 0; + } + + Pair result = getPreviousFile(); + mFile = result.second; + setFileDepth(mFile); + + // since on browse down sets it to the false, browse up should set back to true if current search type is not NO_SEARCH + if (mFile.isRootDirectory() && currentSearchType != NO_SEARCH) { + searchFragment = true; + } + + updateFileList(); + return result.first; } - private Pair getPreviousFileWithoutFilter(FileDataStorageManager storageManager) { + private Pair getPreviousFile() { + if (mFile == null) { + return new Pair<>(0, null); + } + + FileDataStorageManager storageManager = mContainerActivity.getStorageManager(); int moveCount = 0; - OCFile parentDir = null; - String parentPath = null; + String parentPath; + OCFile parentDir; if (mFile.getParentId() != FileDataStorageManager.ROOT_PARENT_ID) { parentPath = new File(mFile.getRemotePath()).getParent(); - - if (parentPath != null) { - parentPath = parentPath.endsWith(OCFile.PATH_SEPARATOR) ? parentPath : parentPath + OCFile.PATH_SEPARATOR; - parentDir = storageManager.getFileByPath(parentPath); - moveCount++; - } + parentPath = ensureTrailingSeparator(parentPath); + parentDir = storageManager.getFileByPath(parentPath); + moveCount++; } else { parentDir = storageManager.getFileByPath(ROOT_PATH); + parentPath = ROOT_PATH; } - while (parentDir == null) { + // Keep going up until we find a valid folder + while (parentDir == null && !ROOT_PATH.equals(parentPath)) { parentPath = new File(parentPath).getParent(); - - if (parentPath != null) { - parentPath = parentPath.endsWith(OCFile.PATH_SEPARATOR) ? parentPath : - parentPath + OCFile.PATH_SEPARATOR; - parentDir = storageManager.getFileByPath(parentPath); - moveCount++; + if (parentPath == null) { + parentPath = ROOT_PATH; // fallback to root } + parentPath = ensureTrailingSeparator(parentPath); + parentDir = storageManager.getFileByPath(parentPath); + moveCount++; } return new Pair<>(moveCount, parentDir); } - private OCFile getPreviousFileWithFilter(FileDataStorageManager storageManager, OCFile currentFile) { - while (true) { - OCFile parent = storageManager.getFileById(currentFile.getParentId()); - if (parent == null) { - return currentFile; - } - - if (parent.isRootDirectory()) { - return parent; - } - - if ((DrawerActivity.menuItemId == R.id.nav_shared && parent.isShared()) || - (DrawerActivity.menuItemId == R.id.nav_favorites && parent.isFavorite())) { - return parent; - } - - currentFile = parent; - } - } - - private Future> getPreviousFile() { - CompletableFuture> completableFuture = new CompletableFuture<>(); - - Executors.newCachedThreadPool().execute(() -> { - var result = new Pair(null, null); - - FileDataStorageManager storageManager = mContainerActivity.getStorageManager(); - OCFile currentFile = getCurrentFile(); - OCFile topParent = storageManager.getTopParent(currentFile); - - if (shouldNavigateWithoutFilter(topParent)) { - result = getPreviousFileWithoutFilter(storageManager); - } else if (shouldNavigateWithFilter()) { - OCFile previousFileWithFilter = getPreviousFileWithFilter(storageManager, currentFile); - result = new Pair<>(0, previousFileWithFilter); - } - - completableFuture.complete(result); - - }); - - return completableFuture; - } - - /** - * Call this, when the user presses the up button. - *

- * Tries to move up the current folder one level. If the parent folder was removed from the database, it continues - * browsing up until finding an existing folders. - *

- * return Count of folder levels browsed up. - */ - public int onBrowseUp() { - if (mFile == null) { - return 0; - } - - try { - Future> futureResult = getPreviousFile(); - Pair result = futureResult.get(); - mFile = result.second; - setFileDepth(mFile); - - // since on browse down sets it to the false, browse up should set back to true if current search type is not NO_SEARCH - if (mFile.isRootDirectory() && currentSearchType != NO_SEARCH) { - searchFragment = true; - } - - updateFileList(); - return result.first; - } catch (Exception e) { - Log_OC.e(TAG,"Error caught in onBrowseUp " + e + " getPreviousFileWithoutFilter() used: "); - - FileDataStorageManager storageManager = mContainerActivity.getStorageManager(); - var result = getPreviousFileWithoutFilter(storageManager); - mFile = result.second; - updateFileList(); - return result.first; + private String ensureTrailingSeparator(String path) { + if (path == null) { + return ROOT_PATH; } + return path.endsWith(OCFile.PATH_SEPARATOR) ? path : path + OCFile.PATH_SEPARATOR; } private void updateFileList() { From c3e42eddc9e98c5e7f9f54f5358729640da9c1c4 Mon Sep 17 00:00:00 2001 From: alperozturk Date: Sat, 13 Dec 2025 11:33:50 +0100 Subject: [PATCH 049/216] fix back press from file details Signed-off-by: alperozturk --- .../ui/activity/FileDisplayActivity.kt | 90 +++++++++++-------- .../ui/fragment/OCFileListFragment.java | 11 ++- 2 files changed, 63 insertions(+), 38 deletions(-) diff --git a/app/src/main/java/com/owncloud/android/ui/activity/FileDisplayActivity.kt b/app/src/main/java/com/owncloud/android/ui/activity/FileDisplayActivity.kt index cdbe74d9b833..fc85ebd5639f 100644 --- a/app/src/main/java/com/owncloud/android/ui/activity/FileDisplayActivity.kt +++ b/app/src/main/java/com/owncloud/android/ui/activity/FileDisplayActivity.kt @@ -1161,53 +1161,71 @@ class FileDisplayActivity : this, object : OnBackPressedCallback(true) { override fun handleOnBackPressed() { - when { - isSearchOpen() -> { - isEnabled = false - resetSearchAction() - } + handleBackPressImpl(before = { + isEnabled = false + }, after = { + isEnabled = true + }) + } + } + ) + } - isDrawerOpen -> { - isEnabled = false - onBackPressedDispatcher.onBackPressed() - } + private fun handleBackPressImpl(before: () -> Unit = {}, after: () -> Unit = {}) { + when { + isSearchOpen() -> { + before() + resetSearchAction() + after() + } - leftFragment is OCFileListFragment -> { - val fragment = leftFragment as OCFileListFragment - - when { - // root - isRoot(getCurrentDir()) -> { - if (fragment.shouldNavigateBackToAllFiles()) { - navigateToAllFiles() - } else { - finish() - } - } - - // Normal folder navigation (go up) also works for shared tab - else -> { - browseUp(fragment) - } - } - } + isDrawerOpen -> { + before() + onBackPressedDispatcher.onBackPressed() + after() + } - else -> { - isEnabled = false - popBack() - } - } + leftFragment is OCFileListFragment -> { + before() + handleOCFileListFragmentBackPress() + after() + } + + else -> { + before() + popBack() + after() + } + } + } + + private fun handleOCFileListFragmentBackPress() { + val fragment = leftFragment as OCFileListFragment + + when { + // root + isRoot(getCurrentDir()) -> { + if (fragment.shouldNavigateBackToAllFiles()) { + navigateToAllFiles() + } else { + finish() } } - ) + + // Normal folder navigation (go up) also works for shared tab + else -> { + browseUp(fragment) + } + } } override fun onOptionsItemSelected(item: MenuItem): Boolean = when (item.itemId) { android.R.id.home -> { when { shouldOpenDrawer() -> openDrawer() - isSearchOpen() -> resetSearchAction() - else -> onBackPressedDispatcher.onBackPressed() + else -> { + handleBackPressImpl() + } } true } diff --git a/app/src/main/java/com/owncloud/android/ui/fragment/OCFileListFragment.java b/app/src/main/java/com/owncloud/android/ui/fragment/OCFileListFragment.java index bbdad0785f39..73b3157a21ce 100644 --- a/app/src/main/java/com/owncloud/android/ui/fragment/OCFileListFragment.java +++ b/app/src/main/java/com/owncloud/android/ui/fragment/OCFileListFragment.java @@ -253,12 +253,19 @@ public void onCreate(Bundle savedInstanceState) { @Override public void onResume() { - if (getActivity() == null) { + // Don't handle search events if we're coming back from back stack + // The fragment has already been properly restored in onCreate/onActivityCreated + if (mFile != null) { + super.onResume(); return; } - Intent intent = getActivity().getIntent(); + final var activity = getActivity(); + if (activity == null) { + return; + } + final Intent intent = activity.getIntent(); if (IntentExtensionsKt.getParcelableArgument(intent, SEARCH_EVENT, SearchEvent.class) != null) { searchEvent = IntentExtensionsKt.getParcelableArgument(intent, SEARCH_EVENT, SearchEvent.class); } From 85b2d0feb0e81802252b722be5e2540574edbe14 Mon Sep 17 00:00:00 2001 From: alperozturk Date: Sat, 13 Dec 2025 11:48:20 +0100 Subject: [PATCH 050/216] fix back press from file details Signed-off-by: alperozturk --- .../owncloud/android/ui/activity/FileDisplayActivity.kt | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/app/src/main/java/com/owncloud/android/ui/activity/FileDisplayActivity.kt b/app/src/main/java/com/owncloud/android/ui/activity/FileDisplayActivity.kt index fc85ebd5639f..2eeda406f9dd 100644 --- a/app/src/main/java/com/owncloud/android/ui/activity/FileDisplayActivity.kt +++ b/app/src/main/java/com/owncloud/android/ui/activity/FileDisplayActivity.kt @@ -1181,7 +1181,7 @@ class FileDisplayActivity : isDrawerOpen -> { before() - onBackPressedDispatcher.onBackPressed() + closeDrawer() after() } @@ -1278,20 +1278,20 @@ class FileDisplayActivity : if (leftFragment is UnifiedSearchFragment) { showSortListGroup(false) - onBackPressedDispatcher.onBackPressed() + supportFragmentManager.popBackStack() } } /** * Use this method when want to pop the fragment on back press. It resets Scrolling (See * [with true][.resetScrolling] and pop the visibility for sortListGroup (See - * [with false][.showSortListGroup]. At last call to onBackPressedDispatcher.onBackPressed() + * [with false][.showSortListGroup]. At last call to supportFragmentManager.popBackStack() */ private fun popBack() { binding.fabMain.setImageResource(R.drawable.ic_plus) resetScrolling(true) showSortListGroup(false) - onBackPressedDispatcher.onBackPressed() + supportFragmentManager.popBackStack() } override fun onSaveInstanceState(outState: Bundle) { From 0716f79a4b3756cd3432406a1fcb16fb216508d0 Mon Sep 17 00:00:00 2001 From: alperozturk Date: Sat, 13 Dec 2025 19:12:02 +0100 Subject: [PATCH 051/216] fix action bar press back from unified search fragment and when fda created or recreated Signed-off-by: alperozturk --- .../android/ui/activity/DrawerActivity.java | 21 +++++++------------ .../ui/activity/FileDisplayActivity.kt | 5 +++++ .../android/ui/activity/ToolbarActivity.java | 12 ++++++++++- .../ui/fragment/OCFileListFragment.java | 2 +- 4 files changed, 25 insertions(+), 15 deletions(-) diff --git a/app/src/main/java/com/owncloud/android/ui/activity/DrawerActivity.java b/app/src/main/java/com/owncloud/android/ui/activity/DrawerActivity.java index c1ce36bdf5e0..f26047d581a3 100644 --- a/app/src/main/java/com/owncloud/android/ui/activity/DrawerActivity.java +++ b/app/src/main/java/com/owncloud/android/ui/activity/DrawerActivity.java @@ -713,19 +713,6 @@ public void startPhotoSearch(int id) { launchActivityForSearch(searchEvent, id); } - private void handleSearchEvents(SearchEvent searchEvent, int menuItemId) { - if (this instanceof FileDisplayActivity) { - final Fragment leftFragment = ((FileDisplayActivity) this).getLeftFragment(); - if (leftFragment instanceof GalleryFragment || leftFragment instanceof SharedListFragment) { - launchActivityForSearch(searchEvent, menuItemId); - } else { - EventBus.getDefault().post(searchEvent); - } - } else { - launchActivityForSearch(searchEvent, menuItemId); - } - } - private void launchActivityForSearch(SearchEvent searchEvent, int menuItemId) { DrawerActivity.menuItemId = menuItemId; Intent intent = new Intent(getApplicationContext(), FileDisplayActivity.class); @@ -1477,6 +1464,14 @@ public static boolean isToolbarStyleSearch() { menuItemId == R.id.nav_personal_files; } + public static boolean isMenuItemIdBelongsToSearchType() { + return menuItemId == R.id.nav_favorites || + menuItemId == R.id.nav_shared || + menuItemId == R.id.nav_on_device || + menuItemId == R.id.nav_recently_modified || + menuItemId == R.id.nav_gallery; + } + public static int getPreviousMenuItemId() { return previousMenuItemId; } diff --git a/app/src/main/java/com/owncloud/android/ui/activity/FileDisplayActivity.kt b/app/src/main/java/com/owncloud/android/ui/activity/FileDisplayActivity.kt index 2eeda406f9dd..ff5e800637b8 100644 --- a/app/src/main/java/com/owncloud/android/ui/activity/FileDisplayActivity.kt +++ b/app/src/main/java/com/owncloud/android/ui/activity/FileDisplayActivity.kt @@ -307,6 +307,11 @@ class FileDisplayActivity : mSwitchAccountButton.setOnClickListener { v: View? -> showManageAccountsDialog() } mNotificationButton.setOnClickListener { v: View? -> startActivity(NotificationsActivity::class.java) } fastScrollUtils.fixAppBarForFastScroll(binding.appbar.appbar, binding.rootLayout) + + // reset ui states when file display activity created/recrated + listOfFilesFragment?.resetSearchAttributes() + menuItemId = R.id.nav_all_files + setNavigationViewItemChecked() } private fun initTaskRetainerFragment() { diff --git a/app/src/main/java/com/owncloud/android/ui/activity/ToolbarActivity.java b/app/src/main/java/com/owncloud/android/ui/activity/ToolbarActivity.java index 2d18da86aaa9..75bbfa7ff180 100644 --- a/app/src/main/java/com/owncloud/android/ui/activity/ToolbarActivity.java +++ b/app/src/main/java/com/owncloud/android/ui/activity/ToolbarActivity.java @@ -181,7 +181,17 @@ private OCFileDepth getCurrentDirDepth() { } private SearchType getSearchType() { - OCFileListFragment fragment = getOCFileListFragment(); + final OCFileListFragment fragment = getOCFileListFragment(); + + // if current navigation not matches, reset search event + if (!DrawerActivity.isMenuItemIdBelongsToSearchType()) { + if (fragment != null) { + fragment.resetSearchAttributes(); + } + + return SearchType.NO_SEARCH; + } + if (fragment != null) { return fragment.getCurrentSearchType(); } diff --git a/app/src/main/java/com/owncloud/android/ui/fragment/OCFileListFragment.java b/app/src/main/java/com/owncloud/android/ui/fragment/OCFileListFragment.java index 73b3157a21ce..18038398955f 100644 --- a/app/src/main/java/com/owncloud/android/ui/fragment/OCFileListFragment.java +++ b/app/src/main/java/com/owncloud/android/ui/fragment/OCFileListFragment.java @@ -1784,7 +1784,7 @@ private void resetMenuItems() { updateSortAndGridMenuItems(); } - private void resetSearchAttributes() { + public void resetSearchAttributes() { searchFragment = false; searchEvent = null; currentSearchType = NO_SEARCH; From 6f82560c9f2d96410722449b48f0cd9d2a2d5943 Mon Sep 17 00:00:00 2001 From: Nextcloud bot Date: Tue, 16 Dec 2025 03:01:12 +0000 Subject: [PATCH 052/216] fix(l10n): Update translations from Transifex Signed-off-by: Nextcloud bot --- app/src/main/res/values-it/strings.xml | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) diff --git a/app/src/main/res/values-it/strings.xml b/app/src/main/res/values-it/strings.xml index df660f6a2ade..e64b3279950a 100644 --- a/app/src/main/res/values-it/strings.xml +++ b/app/src/main/res/values-it/strings.xml @@ -44,18 +44,25 @@ Mostra un widget dal cruscotto Cerca in %s Appari non in linea + Il risultato qui riportato è generato dall\'intelligenza artificiale. Assicurati sempre di ricontrollare. + Impossibile inviare il messaggio + Impossibile recuperare i messaggi della chat Sei sicuro di voler rimuovere questa attività? Elimina attività + Prova a inviare un messaggio per avviare una conversazione. + Ciao! Come posso aiutarti oggi? Un errore è intercorso durante la creazione del task Task creato con successo Un errore è intercorso durante la cancellazione del task Task cancellato con successo + L\'elenco delle attività è vuoto. Controllare la configurazione dell\'app di assistenza. Impossibile recuperare la lista dei Task, verifica la tua connessione a internet. Cancella task Il risultato del task non è ancora pronto. Assistente Input Output + Sto pensando … Account associato non trovato. Accesso non riuscito: %1$s L\'account non è ancora aggiunto su questo dispositivo @@ -87,11 +94,19 @@ %1$s non supporta account multipli Impossibile stabilire la connessione Annulla l\'accesso + Inserisci un indirizzo server valido. + Impossibile recuperare i dati di accesso. Riprova. C\'è stato un problema nella richiesta di login. Per favore, riprova più tardi + Non è disponibile alcun browser per aprire questo link. Completa il procedimento di login nel tuo browser + Il caricamento automatico è sospeso perché è attiva la funzione Risparmio batteria. lasciato nella cartella originale, poiché è in sola lettura + Batteria scarica, il caricamento potrebbe richiedere più tempo Carica solo su Wi-Fi senza limitazioni /AutoUpload + Questa cartella è già inclusa nella sincronizzazione della cartella principale, il che potrebbe causare caricamenti duplicati. + In attesa del Wi-Fi per avviare il caricamento + Caricando i file da %s a %s Configura Crea nuova configurazione di cartella personalizzata Configura una cartella personalizzata @@ -180,6 +195,7 @@ Vuoi davvero eliminare gli elementi selezionati e il loro contenuto? Solo localmente Impossibile creare la finestra di dialogo per la risoluzione dei conflitti + Conflitto cartelle File locale Se selezioni entrambe le versioni, il file locale ha un numero aggiunto al suo nome. Se selezioni entrambe le versioni, alla cartella locale verrà aggiunto un numero al nome. @@ -192,9 +208,15 @@ Esegui backup ora Backup pianificato e partirà a breve Importazione pianificata e partirà a breve + Impossibile avviare l\'importazione. Riprova. Nessun file trovato Non troviamo il tuo ultimo backup! + Rilevamento delle modifiche ai contenuti + Impossibile creare conversazione + Cancella conversazione + Impossibile cancellare conversazione Nessuna conversazione trovata + Ancora nessuna conversazione Conversazioni Copiato Si è verificato un errore durante il tentativo di copiare il file o la cartella From d46e8f1fcf91e59aec2680d2b6f0169b22577e83 Mon Sep 17 00:00:00 2001 From: Nextcloud bot Date: Wed, 17 Dec 2025 02:46:15 +0000 Subject: [PATCH 053/216] fix(l10n): Update translations from Transifex Signed-off-by: Nextcloud bot --- app/src/main/res/values-gl/strings.xml | 4 ++-- app/src/main/res/values-sv/strings.xml | 3 +++ 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/app/src/main/res/values-gl/strings.xml b/app/src/main/res/values-gl/strings.xml index 3be672998b76..54feeb801358 100644 --- a/app/src/main/res/values-gl/strings.xml +++ b/app/src/main/res/values-gl/strings.xml @@ -197,8 +197,8 @@ Non é posíbel crear o diálogo de resolución de conflitos Conflito de cartafol Ficheiro local - Se selecciona ambas versións, o ficheiro local terá un número engadido ao nome. - Se selecciona ambas versións, o cartafol local terá un número engadido ao nome. + Se selecciona ámbalas dúas versións, o ficheiro local terá un número engadido ao nome. + Se selecciona ámbalas dúas versións, o cartafol local terá un número engadido ao nome. Ficheiro do servidor Copia de seguranza dos contactos Precisase de permiso de contacto. diff --git a/app/src/main/res/values-sv/strings.xml b/app/src/main/res/values-sv/strings.xml index c6a0bf68221d..c18f97429ab6 100644 --- a/app/src/main/res/values-sv/strings.xml +++ b/app/src/main/res/values-sv/strings.xml @@ -62,6 +62,7 @@ Assistent Inmatning Utdata + Tänker … Associerat konto kunde inte hittas! Åtkomst misslyckades: %1$s Kontot har ännu inte lagts till på den här enheten @@ -322,6 +323,7 @@ Assistent Mer Fler Nextcloud-appar + Kan inte öppna filväljaren Det gick inte att välja e-postadress. Sätt som krypterad Kunde inte hämta servercertifikatet @@ -391,6 +393,7 @@ Du har inte behörighet att skapa eller ladda upp filer i den här mappen. Externa delningar Lägg till eller ladda upp + Kunde inte skapa konfliktdialog Misslyckades skicka filen till hämtningshanteraren Kunde inte skriva ut filen Kunde inte starta editor From 7c3b780be23966537b236b51d431631cc4555f0c Mon Sep 17 00:00:00 2001 From: alperozturk Date: Fri, 12 Dec 2025 12:10:03 +0100 Subject: [PATCH 054/216] fix: file system provider Signed-off-by: alperozturk --- .../client/database/dao/FileSystemDao.kt | 16 ++ .../client/jobs/BackgroundJobFactory.kt | 2 +- .../jobs/autoUpload/AutoUploadHelper.kt | 9 +- .../jobs/autoUpload/AutoUploadWorker.kt | 6 +- .../jobs/autoUpload/FileSystemRepository.kt | 78 +++++++++- .../android/datamodel/FileSystemDataSet.java | 108 -------------- .../datamodel/FilesystemDataProvider.java | 139 ------------------ .../android/utils/FilesSyncHelper.java | 112 ++------------ 8 files changed, 108 insertions(+), 362 deletions(-) delete mode 100644 app/src/main/java/com/owncloud/android/datamodel/FileSystemDataSet.java diff --git a/app/src/main/java/com/nextcloud/client/database/dao/FileSystemDao.kt b/app/src/main/java/com/nextcloud/client/database/dao/FileSystemDao.kt index fcb567abc210..3dc90d77b318 100644 --- a/app/src/main/java/com/nextcloud/client/database/dao/FileSystemDao.kt +++ b/app/src/main/java/com/nextcloud/client/database/dao/FileSystemDao.kt @@ -8,12 +8,17 @@ package com.nextcloud.client.database.dao import androidx.room.Dao +import androidx.room.Insert +import androidx.room.OnConflictStrategy import androidx.room.Query import com.nextcloud.client.database.entity.FilesystemEntity import com.owncloud.android.db.ProviderMeta @Dao interface FileSystemDao { + @Insert(onConflict = OnConflictStrategy.REPLACE) + fun insertOrReplace(filesystemEntity: FilesystemEntity) + @Query( """ SELECT * @@ -37,4 +42,15 @@ interface FileSystemDao { """ ) suspend fun markFileAsUploaded(localPath: String, syncedFolderId: String) + + @Query( + """ + SELECT * + FROM ${ProviderMeta.ProviderTableMeta.FILESYSTEM_TABLE_NAME} + WHERE ${ProviderMeta.ProviderTableMeta.FILESYSTEM_FILE_LOCAL_PATH} = :localPath + AND ${ProviderMeta.ProviderTableMeta.FILESYSTEM_SYNCED_FOLDER_ID} = :syncedFolderId + LIMIT 1 + """ + ) + fun getFileByPathAndFolder(localPath: String, syncedFolderId: String): FilesystemEntity? } diff --git a/app/src/main/java/com/nextcloud/client/jobs/BackgroundJobFactory.kt b/app/src/main/java/com/nextcloud/client/jobs/BackgroundJobFactory.kt index b7d06ee2d9d3..3e67df51fa92 100644 --- a/app/src/main/java/com/nextcloud/client/jobs/BackgroundJobFactory.kt +++ b/app/src/main/java/com/nextcloud/client/jobs/BackgroundJobFactory.kt @@ -179,7 +179,7 @@ class BackgroundJobFactory @Inject constructor( powerManagementService = powerManagementService, syncedFolderProvider = syncedFolderProvider, backgroundJobManager = backgroundJobManager.get(), - repository = FileSystemRepository(dao = database.fileSystemDao()), + repository = FileSystemRepository(dao = database.fileSystemDao(), context), viewThemeUtils = viewThemeUtils.get() ) diff --git a/app/src/main/java/com/nextcloud/client/jobs/autoUpload/AutoUploadHelper.kt b/app/src/main/java/com/nextcloud/client/jobs/autoUpload/AutoUploadHelper.kt index a43b524b9d16..9250d65ce3bd 100644 --- a/app/src/main/java/com/nextcloud/client/jobs/autoUpload/AutoUploadHelper.kt +++ b/app/src/main/java/com/nextcloud/client/jobs/autoUpload/AutoUploadHelper.kt @@ -29,7 +29,7 @@ class AutoUploadHelper { private const val MAX_DEPTH = 100 } - fun insertCustomFolderIntoDB(folder: SyncedFolder, filesystemDataProvider: FilesystemDataProvider?): Int { + fun insertCustomFolderIntoDB(folder: SyncedFolder, repository: FileSystemRepository?): Int { val path = Paths.get(folder.localPath) if (!Files.exists(path)) { @@ -78,12 +78,7 @@ class AutoUploadHelper { val localPath = file.toLocalPath() - filesystemDataProvider?.storeOrUpdateFileValue( - localPath, - lastModified, - javaFile.isDirectory, - folder - ) + repository?.insertOrReplace(localPath,lastModified, folder) fileCount++ diff --git a/app/src/main/java/com/nextcloud/client/jobs/autoUpload/AutoUploadWorker.kt b/app/src/main/java/com/nextcloud/client/jobs/autoUpload/AutoUploadWorker.kt index 5a793e5f8191..8ae9d481af2d 100644 --- a/app/src/main/java/com/nextcloud/client/jobs/autoUpload/AutoUploadWorker.kt +++ b/app/src/main/java/com/nextcloud/client/jobs/autoUpload/AutoUploadWorker.kt @@ -230,16 +230,16 @@ class AutoUploadWorker( private suspend fun collectFileChangesFromContentObserverWork(contentUris: Array?) = try { withContext(Dispatchers.IO) { if (contentUris.isNullOrEmpty()) { - FilesSyncHelper.insertAllDBEntriesForSyncedFolder(syncedFolder, helper) + FilesSyncHelper.insertAllDBEntriesForSyncedFolder(syncedFolder, helper, repository) } else { - val isContentUrisStored = FilesSyncHelper.insertChangedEntries(syncedFolder, contentUris) + val isContentUrisStored = FilesSyncHelper.insertChangedEntries(syncedFolder, contentUris, repository) if (!isContentUrisStored) { Log_OC.w( TAG, "changed content uris not stored, fallback to insert all db entries to not lose files" ) - FilesSyncHelper.insertAllDBEntriesForSyncedFolder(syncedFolder, helper) + FilesSyncHelper.insertAllDBEntriesForSyncedFolder(syncedFolder, helper, repository) } } syncedFolder.lastScanTimestampMs = System.currentTimeMillis() diff --git a/app/src/main/java/com/nextcloud/client/jobs/autoUpload/FileSystemRepository.kt b/app/src/main/java/com/nextcloud/client/jobs/autoUpload/FileSystemRepository.kt index a4bf50a03fa9..fbee2fedaab3 100644 --- a/app/src/main/java/com/nextcloud/client/jobs/autoUpload/FileSystemRepository.kt +++ b/app/src/main/java/com/nextcloud/client/jobs/autoUpload/FileSystemRepository.kt @@ -7,13 +7,18 @@ package com.nextcloud.client.jobs.autoUpload +import android.content.Context +import android.net.Uri +import android.provider.MediaStore import com.nextcloud.client.database.dao.FileSystemDao +import com.nextcloud.client.database.entity.FilesystemEntity import com.owncloud.android.datamodel.SyncedFolder import com.owncloud.android.lib.common.utils.Log_OC import com.owncloud.android.utils.SyncedFolderUtils import java.io.File +import java.util.zip.CRC32 -class FileSystemRepository(private val dao: FileSystemDao) { +class FileSystemRepository(private val dao: FileSystemDao, private val context: Context) { companion object { private const val TAG = "FilesystemRepository" @@ -63,4 +68,75 @@ class FileSystemRepository(private val dao: FileSystemDao) { Log_OC.e(TAG, "Error marking file as uploaded: ${e.message}", e) } } + + fun insert(uri: Uri, syncedFolder: SyncedFolder) { + val projection = arrayOf(MediaStore.MediaColumns.DATA) + val cursor = context.contentResolver.query(uri, projection, null, null, null) + + cursor?.use { + val columnIndexData = cursor.getColumnIndexOrThrow(MediaStore.MediaColumns.DATA) + + while (cursor.moveToNext()) { + val filePath = cursor.getString(columnIndexData) + Log_OC.d(TAG, "attempt to insert new file entity uri: $uri") + insertOrReplace(filePath, null, syncedFolder) + } + } ?: Log_OC.w(TAG, "Cursor is null for URI: $uri") + } + + fun insertOrReplace(localPath: String?, lastModified: Long?, syncedFolder: SyncedFolder) { + try { + if (localPath == null) { + Log_OC.w(TAG, "localPath path not exists: $localPath") + return + } + + val file = File(localPath) + if (!file.exists()) { + Log_OC.w(TAG, "local file does not exist, cannot insert or replace: $localPath") + return + } + + val entity = dao.getFileByPathAndFolder(localPath, syncedFolder.id.toString()) + if (entity != null && entity.fileSentForUpload == 1) { + Log_OC.w(TAG, "file already uploaded path: $localPath, syncedFolder: ${syncedFolder.localPath}, ${syncedFolder.id}") + return + } + + val crc = getFileChecksum(file) + + val newEntity = FilesystemEntity( + id = entity?.id, + localPath = localPath, + fileIsFolder = if (file.isDirectory) 1 else 0, + fileFoundRecently = System.currentTimeMillis(), + fileSentForUpload = 0, + syncedFolderId = syncedFolder.id.toString(), + crc32 = crc?.toString(), + fileModified = lastModified ?: file.lastModified() + ) + + Log_OC.d(TAG, "inserting new file system entity: $newEntity") + + dao.insertOrReplace(newEntity) + } catch (e: Exception) { + Log_OC.e(TAG, "Failed to insert/update file: $localPath", e) + } + } + + private fun getFileChecksum(file: File): Long? { + return try { + file.inputStream().use { fis -> + val crc = CRC32() + val buffer = ByteArray(64 * 1024) + var bytesRead: Int + while (fis.read(buffer).also { bytesRead = it } > 0) { + crc.update(buffer, 0, bytesRead) + } + crc.value + } + } catch (_: Exception) { + null + } + } } diff --git a/app/src/main/java/com/owncloud/android/datamodel/FileSystemDataSet.java b/app/src/main/java/com/owncloud/android/datamodel/FileSystemDataSet.java deleted file mode 100644 index 44f768c2d511..000000000000 --- a/app/src/main/java/com/owncloud/android/datamodel/FileSystemDataSet.java +++ /dev/null @@ -1,108 +0,0 @@ -/* - * Nextcloud Android client application - * - * @author Mario Danic - * @author Andy Scherzinger - * Copyright (C) 2017 Mario Danic - * Copyright (C) 2017 Nextcloud - * Copyright (C) 2018 Andy Scherzinger - * - * SPDX-License-Identifier: AGPL-3.0-or-later OR GPL-2.0-only - */ -package com.owncloud.android.datamodel; - -import androidx.annotation.Nullable; - -/** - * Model for filesystem data from the database. - */ -public class FileSystemDataSet { - private int id; - private String localPath; - private long modifiedAt; - private boolean folder; - private boolean sentForUpload; - private long foundAt; - private long syncedFolderId; - @Nullable private String crc32; - - public FileSystemDataSet(int id, String localPath, long modifiedAt, boolean folder, boolean sentForUpload, long foundAt, long syncedFolderId, String crc32) { - this.id = id; - this.localPath = localPath; - this.modifiedAt = modifiedAt; - this.folder = folder; - this.sentForUpload = sentForUpload; - this.foundAt = foundAt; - this.syncedFolderId = syncedFolderId; - this.crc32 = crc32; - } - - public FileSystemDataSet() { - // empty constructor - } - - public int getId() { - return this.id; - } - - public String getLocalPath() { - return this.localPath; - } - - public long getModifiedAt() { - return this.modifiedAt; - } - - public boolean isFolder() { - return this.folder; - } - - public boolean isSentForUpload() { - return this.sentForUpload; - } - - public long getFoundAt() { - return this.foundAt; - } - - public long getSyncedFolderId() { - return this.syncedFolderId; - } - - @Nullable - public String getCrc32() { - return this.crc32; - } - - public void setId(int id) { - this.id = id; - } - - public void setLocalPath(String localPath) { - this.localPath = localPath; - } - - public void setModifiedAt(long modifiedAt) { - this.modifiedAt = modifiedAt; - } - - public void setFolder(boolean folder) { - this.folder = folder; - } - - public void setSentForUpload(boolean sentForUpload) { - this.sentForUpload = sentForUpload; - } - - public void setFoundAt(long foundAt) { - this.foundAt = foundAt; - } - - public void setSyncedFolderId(long syncedFolderId) { - this.syncedFolderId = syncedFolderId; - } - - public void setCrc32(@Nullable String crc32) { - this.crc32 = crc32; - } -} diff --git a/app/src/main/java/com/owncloud/android/datamodel/FilesystemDataProvider.java b/app/src/main/java/com/owncloud/android/datamodel/FilesystemDataProvider.java index e1a2016715f6..48f212e8380e 100644 --- a/app/src/main/java/com/owncloud/android/datamodel/FilesystemDataProvider.java +++ b/app/src/main/java/com/owncloud/android/datamodel/FilesystemDataProvider.java @@ -8,19 +8,10 @@ package com.owncloud.android.datamodel; import android.content.ContentResolver; -import android.content.ContentValues; -import android.database.Cursor; -import android.net.Uri; import com.owncloud.android.db.ProviderMeta; import com.owncloud.android.lib.common.utils.Log_OC; -import java.io.BufferedInputStream; -import java.io.FileInputStream; -import java.io.IOException; -import java.io.InputStream; -import java.util.zip.CRC32; - /** * Provider for stored filesystem data. */ @@ -46,134 +37,4 @@ public int deleteAllEntriesForSyncedFolder(String syncedFolderId) { ProviderMeta.ProviderTableMeta.FILESYSTEM_SYNCED_FOLDER_ID + " = ?", new String[]{syncedFolderId}); } - - public void storeOrUpdateFileValue(String localPath, long modifiedAt, boolean isFolder, SyncedFolder syncedFolder) { - Log_OC.d(TAG, "storeOrUpdateFileValue called, localPath: " + localPath + " ID: " + syncedFolder.getId()); - - // takes multiple milliseconds to query data from database (around 75% of execution time) (6ms) - FileSystemDataSet data = getFilesystemDataSet(localPath, syncedFolder); - - int isFolderValue = 0; - if (isFolder) { - isFolderValue = 1; - } - - ContentValues cv = new ContentValues(); - cv.put(ProviderMeta.ProviderTableMeta.FILESYSTEM_FILE_FOUND_RECENTLY, System.currentTimeMillis()); - cv.put(ProviderMeta.ProviderTableMeta.FILESYSTEM_FILE_MODIFIED, modifiedAt); - - if (data == null) { - Log_OC.d(TAG, "storeOrUpdateFileValue data is null"); - - cv.put(ProviderMeta.ProviderTableMeta.FILESYSTEM_FILE_LOCAL_PATH, localPath); - cv.put(ProviderMeta.ProviderTableMeta.FILESYSTEM_FILE_IS_FOLDER, isFolderValue); - cv.put(ProviderMeta.ProviderTableMeta.FILESYSTEM_FILE_SENT_FOR_UPLOAD, Boolean.FALSE); - cv.put(ProviderMeta.ProviderTableMeta.FILESYSTEM_SYNCED_FOLDER_ID, syncedFolder.getId()); - - long newCrc32 = getFileChecksum(localPath); - if (newCrc32 != -1) { - cv.put(ProviderMeta.ProviderTableMeta.FILESYSTEM_CRC32, Long.toString(newCrc32)); - } - - Uri result = contentResolver.insert(ProviderMeta.ProviderTableMeta.CONTENT_URI_FILESYSTEM, cv); - - if (result == null) { - Log_OC.e(TAG, "Failed to insert filesystem data with local path: " + localPath); - } - } else { - Log_OC.d(TAG, "storeOrUpdateFileValue data is not null"); - - if (data.getModifiedAt() != modifiedAt) { - long newCrc32 = getFileChecksum(localPath); - if (data.getCrc32() == null || (newCrc32 != -1 && !data.getCrc32().equals(Long.toString(newCrc32)))) { - cv.put(ProviderMeta.ProviderTableMeta.FILESYSTEM_CRC32, Long.toString(newCrc32)); - cv.put(ProviderMeta.ProviderTableMeta.FILESYSTEM_FILE_SENT_FOR_UPLOAD, 0); - } - } - - // updating data takes multiple milliseconds (around 25% of exec time) (2 ms) - int result = contentResolver.update( - ProviderMeta.ProviderTableMeta.CONTENT_URI_FILESYSTEM, - cv, - ProviderMeta.ProviderTableMeta._ID + "=?", - new String[]{String.valueOf(data.getId())} - ); - - if (result == 0) { - Log_OC.e(TAG, "Failed to update filesystem data with local path: " + localPath); - } - } - } - - private FileSystemDataSet getFilesystemDataSet(String localPathParam, SyncedFolder syncedFolder) { - Log_OC.d(TAG, "getFilesForUpload called, localPath: " + localPathParam + " ID: " + syncedFolder.getId()); - - String[] projection = { - ProviderMeta.ProviderTableMeta._ID, - ProviderMeta.ProviderTableMeta.FILESYSTEM_FILE_LOCAL_PATH, - ProviderMeta.ProviderTableMeta.FILESYSTEM_FILE_MODIFIED, - ProviderMeta.ProviderTableMeta.FILESYSTEM_FILE_IS_FOLDER, - ProviderMeta.ProviderTableMeta.FILESYSTEM_FILE_FOUND_RECENTLY, - ProviderMeta.ProviderTableMeta.FILESYSTEM_FILE_SENT_FOR_UPLOAD, - ProviderMeta.ProviderTableMeta.FILESYSTEM_CRC32 - }; - - String selection = ProviderMeta.ProviderTableMeta.FILESYSTEM_FILE_LOCAL_PATH + " = ? AND " + - ProviderMeta.ProviderTableMeta.FILESYSTEM_SYNCED_FOLDER_ID + " = ?"; - String[] selectionArgs = { localPathParam, String.valueOf(syncedFolder.getId()) }; - - try (Cursor cursor = contentResolver.query( - ProviderMeta.ProviderTableMeta.CONTENT_URI_FILESYSTEM, - projection, - selection, - selectionArgs, - null - )) { - if (cursor != null && cursor.moveToFirst()) { - int id = cursor.getInt(cursor.getColumnIndexOrThrow(ProviderMeta.ProviderTableMeta._ID)); - if (id == -1) { - Log_OC.e(TAG, "Arbitrary value could not be created from cursor"); - return null; - } - - String localPath = cursor.getString(cursor.getColumnIndexOrThrow( - ProviderMeta.ProviderTableMeta.FILESYSTEM_FILE_LOCAL_PATH)); - long modifiedAt = cursor.getLong(cursor.getColumnIndexOrThrow( - ProviderMeta.ProviderTableMeta.FILESYSTEM_FILE_MODIFIED)); - boolean isFolder = cursor.getInt(cursor.getColumnIndexOrThrow( - ProviderMeta.ProviderTableMeta.FILESYSTEM_FILE_IS_FOLDER)) != 0; - long foundAt = cursor.getLong(cursor.getColumnIndexOrThrow( - ProviderMeta.ProviderTableMeta.FILESYSTEM_FILE_FOUND_RECENTLY)); - boolean isSentForUpload = cursor.getInt(cursor.getColumnIndexOrThrow( - ProviderMeta.ProviderTableMeta.FILESYSTEM_FILE_SENT_FOR_UPLOAD)) != 0; - String crc32 = cursor.getString(cursor.getColumnIndexOrThrow( - ProviderMeta.ProviderTableMeta.FILESYSTEM_CRC32)); - - return new FileSystemDataSet(id, localPath, modifiedAt, isFolder, isSentForUpload, foundAt, - syncedFolder.getId(), crc32); - } - } catch (Exception e) { - Log_OC.e(TAG, "DB error restoring arbitrary values.", e); - } - - return null; - } - - private long getFileChecksum(String filepath) { - - try (FileInputStream fileInputStream = new FileInputStream(filepath); - InputStream inputStream = new BufferedInputStream(fileInputStream)) { - CRC32 crc = new CRC32(); - byte[] buf = new byte[1024 * 64]; - int size; - while ((size = inputStream.read(buf)) > 0) { - crc.update(buf, 0, size); - } - - return crc.getValue(); - - } catch (IOException e) { - return -1; - } - } } diff --git a/app/src/main/java/com/owncloud/android/utils/FilesSyncHelper.java b/app/src/main/java/com/owncloud/android/utils/FilesSyncHelper.java index 94461e00d5ad..6d29d58f5b2a 100644 --- a/app/src/main/java/com/owncloud/android/utils/FilesSyncHelper.java +++ b/app/src/main/java/com/owncloud/android/utils/FilesSyncHelper.java @@ -9,9 +9,7 @@ */ package com.owncloud.android.utils; -import android.content.ContentResolver; import android.content.Context; -import android.database.Cursor; import android.net.Uri; import android.provider.MediaStore; @@ -20,11 +18,11 @@ import com.nextcloud.client.jobs.BackgroundJobManager; import com.nextcloud.client.jobs.ContentObserverWork; import com.nextcloud.client.jobs.autoUpload.AutoUploadHelper; +import com.nextcloud.client.jobs.autoUpload.FileSystemRepository; import com.nextcloud.client.jobs.upload.FileUploadHelper; import com.nextcloud.client.network.ConnectivityService; import com.nextcloud.utils.extensions.UriExtensionsKt; import com.owncloud.android.MainApp; -import com.owncloud.android.datamodel.FilesystemDataProvider; import com.owncloud.android.datamodel.MediaFolderType; import com.owncloud.android.datamodel.SyncedFolder; import com.owncloud.android.datamodel.SyncedFolderProvider; @@ -33,8 +31,6 @@ import java.io.File; -import static com.owncloud.android.datamodel.OCFile.PATH_SEPARATOR; - /** * Various utilities that make auto upload tick */ @@ -47,44 +43,21 @@ private FilesSyncHelper() { // utility class -> private constructor } - public static void insertAllDBEntriesForSyncedFolder(SyncedFolder syncedFolder, AutoUploadHelper helper) { - Log_OC.d(TAG, "insertAllDBEntriesForSyncedFolder, called. ID: " + syncedFolder.getId()); - - final Context context = MainApp.getAppContext(); - final ContentResolver contentResolver = context.getContentResolver(); - + public static void insertAllDBEntriesForSyncedFolder(SyncedFolder syncedFolder, AutoUploadHelper helper, FileSystemRepository repository) { final long enabledTimestampMs = syncedFolder.getEnabledTimestampMs(); if (syncedFolder.isEnabled() && (syncedFolder.isExisting() || enabledTimestampMs >= 0)) { MediaFolderType mediaType = syncedFolder.getType(); - final long lastCheckTimestampMs = syncedFolder.getLastScanTimestampMs(); - - Log_OC.d(TAG,"File-sync start check folder "+syncedFolder.getLocalPath()); - long startTime = System.nanoTime(); if (mediaType == MediaFolderType.IMAGE) { - Log_OC.d(TAG, "inserting IMAGE"); - FilesSyncHelper.insertContentIntoDB(MediaStore.Images.Media.INTERNAL_CONTENT_URI, - syncedFolder, - lastCheckTimestampMs); - FilesSyncHelper.insertContentIntoDB(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, - syncedFolder, - lastCheckTimestampMs); + repository.insert(MediaStore.Images.Media.INTERNAL_CONTENT_URI, syncedFolder); + repository.insert(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, syncedFolder); } else if (mediaType == MediaFolderType.VIDEO) { - Log_OC.d(TAG, "inserting VIDEO"); - FilesSyncHelper.insertContentIntoDB(MediaStore.Video.Media.INTERNAL_CONTENT_URI, - syncedFolder, - lastCheckTimestampMs); - FilesSyncHelper.insertContentIntoDB(MediaStore.Video.Media.EXTERNAL_CONTENT_URI, - syncedFolder, - lastCheckTimestampMs); + repository.insert(MediaStore.Video.Media.INTERNAL_CONTENT_URI, syncedFolder); + repository.insert(MediaStore.Video.Media.EXTERNAL_CONTENT_URI, syncedFolder); } else { - Log_OC.d(TAG, "inserting other media types: " + mediaType.toString()); - FilesystemDataProvider filesystemDataProvider = new FilesystemDataProvider(contentResolver); - helper.insertCustomFolderIntoDB(syncedFolder, filesystemDataProvider); + helper.insertCustomFolderIntoDB(syncedFolder, repository); } - - Log_OC.d(TAG,"File-sync finished full check for custom folder "+syncedFolder.getLocalPath()+" within "+(System.nanoTime() - startTime)+ "ns"); } else { if (!syncedFolder.isEnabled()) { Log_OC.w(TAG, "insertAllDBEntriesForSyncedFolder, syncedFolder not enabled"); @@ -108,11 +81,8 @@ public static void insertAllDBEntriesForSyncedFolder(SyncedFolder syncedFolder, * @param contentUris An array of content URI strings collected from {@link ContentObserverWork##checkAndTriggerAutoUpload()}. * @return {@code true} if all changed content URIs were successfully stored; {@code false} otherwise. */ - public static boolean insertChangedEntries(SyncedFolder syncedFolder, String[] contentUris) { - Log_OC.d(TAG, "insertChangedEntries, syncedFolderID: " + syncedFolder.getId()); + public static boolean insertChangedEntries(SyncedFolder syncedFolder, String[] contentUris, FileSystemRepository repository) { final Context context = MainApp.getAppContext(); - final ContentResolver contentResolver = context.getContentResolver(); - final FilesystemDataProvider filesystemDataProvider = new FilesystemDataProvider(contentResolver); for (String contentUriString : contentUris) { if (contentUriString == null) { Log_OC.w(TAG, "null content uri string"); @@ -144,7 +114,7 @@ public static boolean insertChangedEntries(SyncedFolder syncedFolder, String[] c return false; } - filesystemDataProvider.storeOrUpdateFileValue(filePath, file.lastModified(), file.isDirectory(), syncedFolder); + repository.insertOrReplace(filePath, file.lastModified(), syncedFolder); } Log_OC.d(TAG, "changed content uris successfully stored"); @@ -152,70 +122,6 @@ public static boolean insertChangedEntries(SyncedFolder syncedFolder, String[] c return true; } - private static void insertContentIntoDB(Uri uri, SyncedFolder syncedFolder, - long lastCheckTimestampMs) { - Log_OC.d(TAG, "insertContentIntoDB, URI: " + uri + " syncedFolderID: " + syncedFolder.getId() + " lastCheckTimestampMs " + lastCheckTimestampMs); - final Context context = MainApp.getAppContext(); - final ContentResolver contentResolver = context.getContentResolver(); - - Cursor cursor; - int column_index_data; - int column_index_date_modified; - - final FilesystemDataProvider filesystemDataProvider = new FilesystemDataProvider(contentResolver); - - String contentPath; - boolean isFolder; - - String[] projection = {MediaStore.MediaColumns.DATA, MediaStore.MediaColumns.DATE_MODIFIED}; - - String path = syncedFolder.getLocalPath(); - if (!path.endsWith(PATH_SEPARATOR)) { - Log_OC.w(TAG, "path is not ending with: " + PATH_SEPARATOR); - path = path + PATH_SEPARATOR; - } - path = path + "%"; - - long enabledTimestampMs = syncedFolder.getEnabledTimestampMs(); - - cursor = context.getContentResolver().query(uri, projection, MediaStore.MediaColumns.DATA + " LIKE ?", - new String[]{path}, null); - - if (cursor != null) { - column_index_data = cursor.getColumnIndexOrThrow(MediaStore.MediaColumns.DATA); - column_index_date_modified = cursor.getColumnIndexOrThrow(MediaStore.MediaColumns.DATE_MODIFIED); - while (cursor.moveToNext()) { - contentPath = cursor.getString(column_index_data); - isFolder = new File(contentPath).isDirectory(); - - if (syncedFolder.getLastScanTimestampMs() != SyncedFolder.NOT_SCANNED_YET && - cursor.getLong(column_index_date_modified) < (lastCheckTimestampMs / 1000)) { - Log_OC.w(TAG, "skipping contentPath"); - continue; - } - - if (syncedFolder.isExisting() || cursor.getLong(column_index_date_modified) >= enabledTimestampMs / 1000) { - // storeOrUpdateFileValue takes a few ms - // -> Rest of this file check takes not even 1 ms. - filesystemDataProvider.storeOrUpdateFileValue(contentPath, - cursor.getLong(column_index_date_modified), isFolder, - syncedFolder); - } else { - if (!syncedFolder.isExisting()) { - Log_OC.w(TAG, "syncedFolder not exists"); - } - - if (cursor.getLong(column_index_date_modified) < enabledTimestampMs / 1000) { - Log_OC.w(TAG, "column_index_date_modified not meeting condition"); - } - } - } - cursor.close(); - } else { - Log_OC.w(TAG, "cursor is null "); - } - } - public static void restartUploadsIfNeeded(final UploadsStorageManager uploadsStorageManager, final UserAccountManager accountManager, final ConnectivityService connectivityService, From 4d40b9038a00022b34ddb96d2be98973dabfa45a Mon Sep 17 00:00:00 2001 From: alperozturk Date: Fri, 12 Dec 2025 12:29:26 +0100 Subject: [PATCH 055/216] fix: file system provider Signed-off-by: alperozturk --- .../jobs/autoUpload/AutoUploadHelper.kt | 2 +- .../jobs/autoUpload/FileSystemRepository.kt | 61 +++++++++++++------ 2 files changed, 45 insertions(+), 18 deletions(-) diff --git a/app/src/main/java/com/nextcloud/client/jobs/autoUpload/AutoUploadHelper.kt b/app/src/main/java/com/nextcloud/client/jobs/autoUpload/AutoUploadHelper.kt index 9250d65ce3bd..febbfe383005 100644 --- a/app/src/main/java/com/nextcloud/client/jobs/autoUpload/AutoUploadHelper.kt +++ b/app/src/main/java/com/nextcloud/client/jobs/autoUpload/AutoUploadHelper.kt @@ -78,7 +78,7 @@ class AutoUploadHelper { val localPath = file.toLocalPath() - repository?.insertOrReplace(localPath,lastModified, folder) + repository?.insertOrReplace(localPath, lastModified, folder) fileCount++ diff --git a/app/src/main/java/com/nextcloud/client/jobs/autoUpload/FileSystemRepository.kt b/app/src/main/java/com/nextcloud/client/jobs/autoUpload/FileSystemRepository.kt index fbee2fedaab3..1a9438d14034 100644 --- a/app/src/main/java/com/nextcloud/client/jobs/autoUpload/FileSystemRepository.kt +++ b/app/src/main/java/com/nextcloud/client/jobs/autoUpload/FileSystemRepository.kt @@ -18,6 +18,7 @@ import com.owncloud.android.utils.SyncedFolderUtils import java.io.File import java.util.zip.CRC32 +@Suppress("TooGenericExceptionCaught", "NestedBlockDepth", "MagicNumber", "ReturnCount") class FileSystemRepository(private val dao: FileSystemDao, private val context: Context) { companion object { @@ -25,7 +26,6 @@ class FileSystemRepository(private val dao: FileSystemDao, private val context: const val BATCH_SIZE = 50 } - @Suppress("NestedBlockDepth") suspend fun getFilePathsWithIds(syncedFolder: SyncedFolder, lastId: Int): List> { val syncedFolderId = syncedFolder.id.toString() Log_OC.d(TAG, "Fetching candidate files for syncedFolderId = $syncedFolderId") @@ -57,7 +57,6 @@ class FileSystemRepository(private val dao: FileSystemDao, private val context: return filtered } - @Suppress("TooGenericExceptionCaught") suspend fun markFileAsUploaded(localPath: String, syncedFolder: SyncedFolder) { val syncedFolderIdStr = syncedFolder.id.toString() @@ -71,16 +70,42 @@ class FileSystemRepository(private val dao: FileSystemDao, private val context: fun insert(uri: Uri, syncedFolder: SyncedFolder) { val projection = arrayOf(MediaStore.MediaColumns.DATA) - val cursor = context.contentResolver.query(uri, projection, null, null, null) + + var syncedPath = syncedFolder.localPath + if (syncedPath.isNullOrEmpty()) { + Log_OC.w(TAG, "Synced folder path is null or empty") + return + } + + if (!syncedPath.endsWith(File.separator)) { + syncedPath += File.separator + } + + val selection = "${MediaStore.MediaColumns.DATA} LIKE ?" + val selectionArgs = arrayOf("$syncedPath%") + + Log_OC.d(TAG, "Querying MediaStore for files in: $syncedPath") + + val cursor = context.contentResolver.query( + uri, + projection, + selection, + selectionArgs, + null + ) cursor?.use { val columnIndexData = cursor.getColumnIndexOrThrow(MediaStore.MediaColumns.DATA) + var count = 0 while (cursor.moveToNext()) { val filePath = cursor.getString(columnIndexData) - Log_OC.d(TAG, "attempt to insert new file entity uri: $uri") + Log_OC.d(TAG, "Found file in synced folder: $filePath") insertOrReplace(filePath, null, syncedFolder) + count++ } + + Log_OC.d(TAG, "Inserted $count files for syncedFolder: ${syncedFolder.id}") } ?: Log_OC.w(TAG, "Cursor is null for URI: $uri") } @@ -99,7 +124,11 @@ class FileSystemRepository(private val dao: FileSystemDao, private val context: val entity = dao.getFileByPathAndFolder(localPath, syncedFolder.id.toString()) if (entity != null && entity.fileSentForUpload == 1) { - Log_OC.w(TAG, "file already uploaded path: $localPath, syncedFolder: ${syncedFolder.localPath}, ${syncedFolder.id}") + Log_OC.w( + TAG, + "file already uploaded path: $localPath, " + + "syncedFolder: ${syncedFolder.localPath}, ${syncedFolder.id}" + ) return } @@ -124,19 +153,17 @@ class FileSystemRepository(private val dao: FileSystemDao, private val context: } } - private fun getFileChecksum(file: File): Long? { - return try { - file.inputStream().use { fis -> - val crc = CRC32() - val buffer = ByteArray(64 * 1024) - var bytesRead: Int - while (fis.read(buffer).also { bytesRead = it } > 0) { - crc.update(buffer, 0, bytesRead) - } - crc.value + private fun getFileChecksum(file: File): Long? = try { + file.inputStream().use { fis -> + val crc = CRC32() + val buffer = ByteArray(64 * 1024) + var bytesRead: Int + while (fis.read(buffer).also { bytesRead = it } > 0) { + crc.update(buffer, 0, bytesRead) } - } catch (_: Exception) { - null + crc.value } + } catch (_: Exception) { + null } } From ac8d6c314f8fcdc8ef0d4a4657764682e1ea8c3d Mon Sep 17 00:00:00 2001 From: alperozturk Date: Fri, 12 Dec 2025 12:48:40 +0100 Subject: [PATCH 056/216] fix: file system provider Signed-off-by: alperozturk --- .../nextcloud/client/jobs/autoUpload/FileSystemRepository.kt | 2 -- 1 file changed, 2 deletions(-) diff --git a/app/src/main/java/com/nextcloud/client/jobs/autoUpload/FileSystemRepository.kt b/app/src/main/java/com/nextcloud/client/jobs/autoUpload/FileSystemRepository.kt index 1a9438d14034..5984c5024ef5 100644 --- a/app/src/main/java/com/nextcloud/client/jobs/autoUpload/FileSystemRepository.kt +++ b/app/src/main/java/com/nextcloud/client/jobs/autoUpload/FileSystemRepository.kt @@ -104,8 +104,6 @@ class FileSystemRepository(private val dao: FileSystemDao, private val context: insertOrReplace(filePath, null, syncedFolder) count++ } - - Log_OC.d(TAG, "Inserted $count files for syncedFolder: ${syncedFolder.id}") } ?: Log_OC.w(TAG, "Cursor is null for URI: $uri") } From 5878ac1464d722e377b5f91fe3376cee1e1be79f Mon Sep 17 00:00:00 2001 From: alperozturk Date: Fri, 12 Dec 2025 13:01:10 +0100 Subject: [PATCH 057/216] fix: file system provider Signed-off-by: alperozturk --- .../com/nextcloud/client/jobs/autoUpload/AutoUploadHelper.kt | 1 - 1 file changed, 1 deletion(-) diff --git a/app/src/main/java/com/nextcloud/client/jobs/autoUpload/AutoUploadHelper.kt b/app/src/main/java/com/nextcloud/client/jobs/autoUpload/AutoUploadHelper.kt index febbfe383005..3f1d4e68474b 100644 --- a/app/src/main/java/com/nextcloud/client/jobs/autoUpload/AutoUploadHelper.kt +++ b/app/src/main/java/com/nextcloud/client/jobs/autoUpload/AutoUploadHelper.kt @@ -9,7 +9,6 @@ package com.nextcloud.client.jobs.autoUpload import com.nextcloud.utils.extensions.shouldSkipFile import com.nextcloud.utils.extensions.toLocalPath -import com.owncloud.android.datamodel.FilesystemDataProvider import com.owncloud.android.datamodel.SyncedFolder import com.owncloud.android.lib.common.utils.Log_OC import java.io.IOException From c21dd4394dea3517dcf0f5273d042cf6a872e155 Mon Sep 17 00:00:00 2001 From: alperozturk Date: Fri, 12 Dec 2025 13:33:53 +0100 Subject: [PATCH 058/216] obey folder configuration Signed-off-by: alperozturk --- .../jobs/autoUpload/AutoUploadHelper.kt | 9 +--- .../jobs/autoUpload/FileSystemRepository.kt | 53 +++++++++++++++---- .../android/utils/FilesSyncHelper.java | 21 +++++++- 3 files changed, 64 insertions(+), 19 deletions(-) diff --git a/app/src/main/java/com/nextcloud/client/jobs/autoUpload/AutoUploadHelper.kt b/app/src/main/java/com/nextcloud/client/jobs/autoUpload/AutoUploadHelper.kt index 3f1d4e68474b..98dc1534aa90 100644 --- a/app/src/main/java/com/nextcloud/client/jobs/autoUpload/AutoUploadHelper.kt +++ b/app/src/main/java/com/nextcloud/client/jobs/autoUpload/AutoUploadHelper.kt @@ -7,7 +7,6 @@ package com.nextcloud.client.jobs.autoUpload -import com.nextcloud.utils.extensions.shouldSkipFile import com.nextcloud.utils.extensions.toLocalPath import com.owncloud.android.datamodel.SyncedFolder import com.owncloud.android.lib.common.utils.Log_OC @@ -69,15 +68,9 @@ class AutoUploadHelper { val javaFile = file.toFile() val lastModified = attrs?.lastModifiedTime()?.toMillis() ?: javaFile.lastModified() val creationTime = attrs?.creationTime()?.toMillis() - - if (folder.shouldSkipFile(javaFile, lastModified, creationTime)) { - skipCount++ - return FileVisitResult.CONTINUE - } - val localPath = file.toLocalPath() - repository?.insertOrReplace(localPath, lastModified, folder) + repository?.insertOrReplace(localPath, lastModified, creationTime, folder) fileCount++ diff --git a/app/src/main/java/com/nextcloud/client/jobs/autoUpload/FileSystemRepository.kt b/app/src/main/java/com/nextcloud/client/jobs/autoUpload/FileSystemRepository.kt index 5984c5024ef5..39f9aa0c1fbb 100644 --- a/app/src/main/java/com/nextcloud/client/jobs/autoUpload/FileSystemRepository.kt +++ b/app/src/main/java/com/nextcloud/client/jobs/autoUpload/FileSystemRepository.kt @@ -12,6 +12,7 @@ import android.net.Uri import android.provider.MediaStore import com.nextcloud.client.database.dao.FileSystemDao import com.nextcloud.client.database.entity.FilesystemEntity +import com.nextcloud.utils.extensions.shouldSkipFile import com.owncloud.android.datamodel.SyncedFolder import com.owncloud.android.lib.common.utils.Log_OC import com.owncloud.android.utils.SyncedFolderUtils @@ -69,7 +70,11 @@ class FileSystemRepository(private val dao: FileSystemDao, private val context: } fun insert(uri: Uri, syncedFolder: SyncedFolder) { - val projection = arrayOf(MediaStore.MediaColumns.DATA) + val projection = arrayOf( + MediaStore.MediaColumns.DATA, + MediaStore.MediaColumns.DATE_MODIFIED, + MediaStore.MediaColumns.DATE_ADDED + ) var syncedPath = syncedFolder.localPath if (syncedPath.isNullOrEmpty()) { @@ -95,19 +100,41 @@ class FileSystemRepository(private val dao: FileSystemDao, private val context: ) cursor?.use { - val columnIndexData = cursor.getColumnIndexOrThrow(MediaStore.MediaColumns.DATA) - var count = 0 + val idxData = cursor.getColumnIndex(MediaStore.MediaColumns.DATA) + val idxModified = cursor.getColumnIndex(MediaStore.MediaColumns.DATE_MODIFIED) + val idxAdded = cursor.getColumnIndex(MediaStore.MediaColumns.DATE_ADDED) + + if (idxData == -1) { + Log_OC.e(TAG, "MediaStore column DATA missing — cannot process URI: $uri") + return + } while (cursor.moveToNext()) { - val filePath = cursor.getString(columnIndexData) - Log_OC.d(TAG, "Found file in synced folder: $filePath") - insertOrReplace(filePath, null, syncedFolder) - count++ + val filePath = cursor.getString(idxData) + + val lastModifiedMs = + if (idxModified != -1) cursor.getLong(idxModified) * 1000 + else File(filePath).lastModified().also { + Log_OC.w(TAG, "DATE_MODIFIED missing, fallback to File.lastModified() for $filePath") + } + + val creationTimeMs = + if (idxAdded != -1) cursor.getLong(idxAdded) * 1000 + else null.also { + Log_OC.w(TAG, "DATE_ADDED missing, creationTime=null for $filePath") + } + + Log_OC.d( + TAG, + "Found file: $filePath (created=$creationTimeMs, modified=$lastModifiedMs)" + ) + + insertOrReplace(filePath, lastModifiedMs, creationTimeMs, syncedFolder) } - } ?: Log_OC.w(TAG, "Cursor is null for URI: $uri") + } } - fun insertOrReplace(localPath: String?, lastModified: Long?, syncedFolder: SyncedFolder) { + fun insertOrReplace(localPath: String?, lastModified: Long?, creationTime: Long?, syncedFolder: SyncedFolder) { try { if (localPath == null) { Log_OC.w(TAG, "localPath path not exists: $localPath") @@ -120,6 +147,12 @@ class FileSystemRepository(private val dao: FileSystemDao, private val context: return } + val fileModified = (lastModified ?: file.lastModified()) + val shouldSkipFileBasedOnFolderSettings = syncedFolder.shouldSkipFile(file, fileModified, creationTime) + if (shouldSkipFileBasedOnFolderSettings) { + return + } + val entity = dao.getFileByPathAndFolder(localPath, syncedFolder.id.toString()) if (entity != null && entity.fileSentForUpload == 1) { Log_OC.w( @@ -140,7 +173,7 @@ class FileSystemRepository(private val dao: FileSystemDao, private val context: fileSentForUpload = 0, syncedFolderId = syncedFolder.id.toString(), crc32 = crc?.toString(), - fileModified = lastModified ?: file.lastModified() + fileModified = fileModified ) Log_OC.d(TAG, "inserting new file system entity: $newEntity") diff --git a/app/src/main/java/com/owncloud/android/utils/FilesSyncHelper.java b/app/src/main/java/com/owncloud/android/utils/FilesSyncHelper.java index 6d29d58f5b2a..8d90706a2604 100644 --- a/app/src/main/java/com/owncloud/android/utils/FilesSyncHelper.java +++ b/app/src/main/java/com/owncloud/android/utils/FilesSyncHelper.java @@ -10,6 +10,7 @@ package com.owncloud.android.utils; import android.content.Context; +import android.database.Cursor; import android.net.Uri; import android.provider.MediaStore; @@ -114,7 +115,25 @@ public static boolean insertChangedEntries(SyncedFolder syncedFolder, String[] c return false; } - repository.insertOrReplace(filePath, file.lastModified(), syncedFolder); + Long creationTimeMs = null; + String[] projection = { MediaStore.MediaColumns.DATE_ADDED }; + try (Cursor cursor = context.getContentResolver() + .query(contentUri, projection, null, null, null)) { + + if (cursor != null && cursor.moveToFirst()) { + int idxAdded = cursor.getColumnIndex(MediaStore.MediaColumns.DATE_ADDED); + if (idxAdded != -1) { + long dateAddedSec = cursor.getLong(idxAdded); + creationTimeMs = dateAddedSec * 1000; + } else { + Log_OC.w(TAG, "DATE_ADDED missing for: " + filePath); + } + } + } catch (Exception e) { + Log_OC.w(TAG, "Could not query creation time for: " + filePath); + } + + repository.insertOrReplace(filePath, file.lastModified(), creationTimeMs, syncedFolder); } Log_OC.d(TAG, "changed content uris successfully stored"); From e34791a9c2f3c2532ca125f36f31103a378a86fc Mon Sep 17 00:00:00 2001 From: alperozturk Date: Fri, 12 Dec 2025 13:34:10 +0100 Subject: [PATCH 059/216] obey folder configuration Signed-off-by: alperozturk --- .../jobs/autoUpload/FileSystemRepository.kt | 18 ++++++++++++------ 1 file changed, 12 insertions(+), 6 deletions(-) diff --git a/app/src/main/java/com/nextcloud/client/jobs/autoUpload/FileSystemRepository.kt b/app/src/main/java/com/nextcloud/client/jobs/autoUpload/FileSystemRepository.kt index 39f9aa0c1fbb..9d5f73b7a382 100644 --- a/app/src/main/java/com/nextcloud/client/jobs/autoUpload/FileSystemRepository.kt +++ b/app/src/main/java/com/nextcloud/client/jobs/autoUpload/FileSystemRepository.kt @@ -113,15 +113,21 @@ class FileSystemRepository(private val dao: FileSystemDao, private val context: val filePath = cursor.getString(idxData) val lastModifiedMs = - if (idxModified != -1) cursor.getLong(idxModified) * 1000 - else File(filePath).lastModified().also { - Log_OC.w(TAG, "DATE_MODIFIED missing, fallback to File.lastModified() for $filePath") + if (idxModified != -1) { + cursor.getLong(idxModified) * 1000 + } else { + File(filePath).lastModified().also { + Log_OC.w(TAG, "DATE_MODIFIED missing, fallback to File.lastModified() for $filePath") + } } val creationTimeMs = - if (idxAdded != -1) cursor.getLong(idxAdded) * 1000 - else null.also { - Log_OC.w(TAG, "DATE_ADDED missing, creationTime=null for $filePath") + if (idxAdded != -1) { + cursor.getLong(idxAdded) * 1000 + } else { + null.also { + Log_OC.w(TAG, "DATE_ADDED missing, creationTime=null for $filePath") + } } Log_OC.d( From e083257228adf464c05accd303c516ca4669fb20 Mon Sep 17 00:00:00 2001 From: alperozturk Date: Fri, 12 Dec 2025 13:39:45 +0100 Subject: [PATCH 060/216] obey folder configuration Signed-off-by: alperozturk --- .../jobs/autoUpload/FileSystemRepository.kt | 26 +++++++------------ 1 file changed, 10 insertions(+), 16 deletions(-) diff --git a/app/src/main/java/com/nextcloud/client/jobs/autoUpload/FileSystemRepository.kt b/app/src/main/java/com/nextcloud/client/jobs/autoUpload/FileSystemRepository.kt index 9d5f73b7a382..2106f3041511 100644 --- a/app/src/main/java/com/nextcloud/client/jobs/autoUpload/FileSystemRepository.kt +++ b/app/src/main/java/com/nextcloud/client/jobs/autoUpload/FileSystemRepository.kt @@ -112,23 +112,17 @@ class FileSystemRepository(private val dao: FileSystemDao, private val context: while (cursor.moveToNext()) { val filePath = cursor.getString(idxData) - val lastModifiedMs = - if (idxModified != -1) { - cursor.getLong(idxModified) * 1000 - } else { - File(filePath).lastModified().also { - Log_OC.w(TAG, "DATE_MODIFIED missing, fallback to File.lastModified() for $filePath") - } - } + val lastModifiedMs = if (idxModified != -1) { + cursor.getLong(idxModified) * 1000 + } else { + null + } - val creationTimeMs = - if (idxAdded != -1) { - cursor.getLong(idxAdded) * 1000 - } else { - null.also { - Log_OC.w(TAG, "DATE_ADDED missing, creationTime=null for $filePath") - } - } + val creationTimeMs = if (idxAdded != -1) { + cursor.getLong(idxAdded) * 1000 + } else { + null + } Log_OC.d( TAG, From ef9535e12cf6cf09090ee91314d3cbcbddeb61a1 Mon Sep 17 00:00:00 2001 From: alperozturk Date: Fri, 12 Dec 2025 14:20:15 +0100 Subject: [PATCH 061/216] deduplicate logic Signed-off-by: alperozturk --- .../jobs/autoUpload/FileSystemRepository.kt | 24 +++++--- .../utils/extensions/UriExtensions.kt | 43 --------------- .../android/utils/FilesSyncHelper.java | 55 ++----------------- 3 files changed, 22 insertions(+), 100 deletions(-) delete mode 100644 app/src/main/java/com/nextcloud/utils/extensions/UriExtensions.kt diff --git a/app/src/main/java/com/nextcloud/client/jobs/autoUpload/FileSystemRepository.kt b/app/src/main/java/com/nextcloud/client/jobs/autoUpload/FileSystemRepository.kt index 2106f3041511..f3a4dc9c9668 100644 --- a/app/src/main/java/com/nextcloud/client/jobs/autoUpload/FileSystemRepository.kt +++ b/app/src/main/java/com/nextcloud/client/jobs/autoUpload/FileSystemRepository.kt @@ -13,6 +13,7 @@ import android.provider.MediaStore import com.nextcloud.client.database.dao.FileSystemDao import com.nextcloud.client.database.entity.FilesystemEntity import com.nextcloud.utils.extensions.shouldSkipFile +import com.nextcloud.utils.extensions.toFile import com.owncloud.android.datamodel.SyncedFolder import com.owncloud.android.lib.common.utils.Log_OC import com.owncloud.android.utils.SyncedFolderUtils @@ -69,7 +70,8 @@ class FileSystemRepository(private val dao: FileSystemDao, private val context: } } - fun insert(uri: Uri, syncedFolder: SyncedFolder) { + @JvmOverloads + fun insertFromUri(uri: Uri, syncedFolder: SyncedFolder, checkFileType: Boolean = false) { val projection = arrayOf( MediaStore.MediaColumns.DATA, MediaStore.MediaColumns.DATE_MODIFIED, @@ -129,21 +131,27 @@ class FileSystemRepository(private val dao: FileSystemDao, private val context: "Found file: $filePath (created=$creationTimeMs, modified=$lastModifiedMs)" ) - insertOrReplace(filePath, lastModifiedMs, creationTimeMs, syncedFolder) + insertOrReplace(filePath, lastModifiedMs, creationTimeMs, syncedFolder, checkFileType) } } } - fun insertOrReplace(localPath: String?, lastModified: Long?, creationTime: Long?, syncedFolder: SyncedFolder) { + fun insertOrReplace( + localPath: String?, + lastModified: Long?, + creationTime: Long?, + syncedFolder: SyncedFolder, + checkFileType: Boolean = false + ) { try { - if (localPath == null) { - Log_OC.w(TAG, "localPath path not exists: $localPath") + val file = localPath?.toFile() + if (file == null) { + Log_OC.w(TAG, "file null, cannot insert or replace: $localPath") return } - val file = File(localPath) - if (!file.exists()) { - Log_OC.w(TAG, "local file does not exist, cannot insert or replace: $localPath") + if (checkFileType && !syncedFolder.containsTypedFile(file, localPath)) { + Log_OC.w(TAG, "synced folder not contains typed file: $localPath") return } diff --git a/app/src/main/java/com/nextcloud/utils/extensions/UriExtensions.kt b/app/src/main/java/com/nextcloud/utils/extensions/UriExtensions.kt deleted file mode 100644 index 174cf97102e1..000000000000 --- a/app/src/main/java/com/nextcloud/utils/extensions/UriExtensions.kt +++ /dev/null @@ -1,43 +0,0 @@ -/* - * Nextcloud - Android Client - * - * SPDX-FileCopyrightText: 2025 Alper Ozturk - * SPDX-License-Identifier: AGPL-3.0-or-later - */ - -package com.nextcloud.utils.extensions - -import android.content.Context -import android.net.Uri -import android.provider.MediaStore -import com.owncloud.android.lib.common.utils.Log_OC - -/** - * Returns absolute filesystem path to the media item on disk. I/O errors that could occur. From Android 11 onwards, - * this column is read-only for apps that target R and higher. - * - * [More Info](https://developer.android.com/reference/android/provider/MediaStore.MediaColumns#DATA) - */ -@Suppress("ReturnCount", "TooGenericExceptionCaught") -fun Uri.toFilePath(context: Context): String? { - try { - val projection = arrayOf(MediaStore.MediaColumns.DATA) - - val resolver = context.contentResolver - - resolver.query(this, projection, null, null, null)?.use { cursor -> - if (!cursor.moveToFirst()) { - return null - } - - val dataIdx = cursor.getColumnIndex(MediaStore.MediaColumns.DATA) - val data = if (dataIdx != -1) cursor.getString(dataIdx) else null - return data - } - - return null - } catch (e: Exception) { - Log_OC.e("UriExtensions", "exception, toFilePath: $e") - return null - } -} diff --git a/app/src/main/java/com/owncloud/android/utils/FilesSyncHelper.java b/app/src/main/java/com/owncloud/android/utils/FilesSyncHelper.java index 8d90706a2604..0f7dffe27c27 100644 --- a/app/src/main/java/com/owncloud/android/utils/FilesSyncHelper.java +++ b/app/src/main/java/com/owncloud/android/utils/FilesSyncHelper.java @@ -10,7 +10,6 @@ package com.owncloud.android.utils; import android.content.Context; -import android.database.Cursor; import android.net.Uri; import android.provider.MediaStore; @@ -22,16 +21,12 @@ import com.nextcloud.client.jobs.autoUpload.FileSystemRepository; import com.nextcloud.client.jobs.upload.FileUploadHelper; import com.nextcloud.client.network.ConnectivityService; -import com.nextcloud.utils.extensions.UriExtensionsKt; -import com.owncloud.android.MainApp; import com.owncloud.android.datamodel.MediaFolderType; import com.owncloud.android.datamodel.SyncedFolder; import com.owncloud.android.datamodel.SyncedFolderProvider; import com.owncloud.android.datamodel.UploadsStorageManager; import com.owncloud.android.lib.common.utils.Log_OC; -import java.io.File; - /** * Various utilities that make auto upload tick */ @@ -51,11 +46,11 @@ public static void insertAllDBEntriesForSyncedFolder(SyncedFolder syncedFolder, MediaFolderType mediaType = syncedFolder.getType(); if (mediaType == MediaFolderType.IMAGE) { - repository.insert(MediaStore.Images.Media.INTERNAL_CONTENT_URI, syncedFolder); - repository.insert(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, syncedFolder); + repository.insertFromUri(MediaStore.Images.Media.INTERNAL_CONTENT_URI, syncedFolder); + repository.insertFromUri(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, syncedFolder); } else if (mediaType == MediaFolderType.VIDEO) { - repository.insert(MediaStore.Video.Media.INTERNAL_CONTENT_URI, syncedFolder); - repository.insert(MediaStore.Video.Media.EXTERNAL_CONTENT_URI, syncedFolder); + repository.insertFromUri(MediaStore.Video.Media.INTERNAL_CONTENT_URI, syncedFolder); + repository.insertFromUri(MediaStore.Video.Media.EXTERNAL_CONTENT_URI, syncedFolder); } else { helper.insertCustomFolderIntoDB(syncedFolder, repository); } @@ -83,57 +78,19 @@ public static void insertAllDBEntriesForSyncedFolder(SyncedFolder syncedFolder, * @return {@code true} if all changed content URIs were successfully stored; {@code false} otherwise. */ public static boolean insertChangedEntries(SyncedFolder syncedFolder, String[] contentUris, FileSystemRepository repository) { - final Context context = MainApp.getAppContext(); for (String contentUriString : contentUris) { if (contentUriString == null) { Log_OC.w(TAG, "null content uri string"); return false; } - Uri contentUri; try { - contentUri = Uri.parse(contentUriString); + Uri contentUri = Uri.parse(contentUriString); + repository.insertFromUri(contentUri, syncedFolder, true); } catch (Exception e) { Log_OC.e(TAG, "Invalid URI: " + contentUriString, e); return false; } - - String filePath = UriExtensionsKt.toFilePath(contentUri, context); - if (filePath == null) { - Log_OC.w(TAG, "File path is null"); - return false; - } - - File file = new File(filePath); - if (!file.exists()) { - Log_OC.w(TAG, "syncedFolder contains not existing changed file: " + filePath); - return false; - } - - if (!syncedFolder.containsTypedFile(file, filePath)) { - Log_OC.w(TAG, "syncedFolder not contains typed file, changedFile: " + filePath); - return false; - } - - Long creationTimeMs = null; - String[] projection = { MediaStore.MediaColumns.DATE_ADDED }; - try (Cursor cursor = context.getContentResolver() - .query(contentUri, projection, null, null, null)) { - - if (cursor != null && cursor.moveToFirst()) { - int idxAdded = cursor.getColumnIndex(MediaStore.MediaColumns.DATE_ADDED); - if (idxAdded != -1) { - long dateAddedSec = cursor.getLong(idxAdded); - creationTimeMs = dateAddedSec * 1000; - } else { - Log_OC.w(TAG, "DATE_ADDED missing for: " + filePath); - } - } - } catch (Exception e) { - Log_OC.w(TAG, "Could not query creation time for: " + filePath); - } - - repository.insertOrReplace(filePath, file.lastModified(), creationTimeMs, syncedFolder); } Log_OC.d(TAG, "changed content uris successfully stored"); From 58b39bb45b73ee94b2c406eba1de3efec9243a26 Mon Sep 17 00:00:00 2001 From: alperozturk Date: Fri, 12 Dec 2025 14:32:10 +0100 Subject: [PATCH 062/216] deduplicate logic Signed-off-by: alperozturk --- .../jobs/autoUpload/AutoUploadHelper.kt | 66 ++++++++++++++++++- .../jobs/autoUpload/AutoUploadWorker.kt | 7 +- .../android/utils/FilesSyncHelper.java | 65 ------------------ 3 files changed, 67 insertions(+), 71 deletions(-) diff --git a/app/src/main/java/com/nextcloud/client/jobs/autoUpload/AutoUploadHelper.kt b/app/src/main/java/com/nextcloud/client/jobs/autoUpload/AutoUploadHelper.kt index 98dc1534aa90..15b23e20fbe7 100644 --- a/app/src/main/java/com/nextcloud/client/jobs/autoUpload/AutoUploadHelper.kt +++ b/app/src/main/java/com/nextcloud/client/jobs/autoUpload/AutoUploadHelper.kt @@ -7,7 +7,10 @@ package com.nextcloud.client.jobs.autoUpload +import android.provider.MediaStore +import androidx.core.net.toUri import com.nextcloud.utils.extensions.toLocalPath +import com.owncloud.android.datamodel.MediaFolderType import com.owncloud.android.datamodel.SyncedFolder import com.owncloud.android.lib.common.utils.Log_OC import java.io.IOException @@ -27,7 +30,66 @@ class AutoUploadHelper { private const val MAX_DEPTH = 100 } - fun insertCustomFolderIntoDB(folder: SyncedFolder, repository: FileSystemRepository?): Int { + fun insertEntries(folder: SyncedFolder, repository: FileSystemRepository) { + val enabledTimestampMs = folder.enabledTimestampMs + if (!folder.isEnabled || (!folder.isExisting && enabledTimestampMs < 0)) { + Log_OC.w( + TAG, + "Skipping insertDBEntries: enabled=${folder.isEnabled}, " + + "exists=${folder.isExisting}, enabledTs=$enabledTimestampMs" + ) + return + } + + when (folder.type) { + MediaFolderType.IMAGE -> { + repository.insertFromUri(MediaStore.Images.Media.INTERNAL_CONTENT_URI, folder) + repository.insertFromUri(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, folder) + } + + MediaFolderType.VIDEO -> { + repository.insertFromUri(MediaStore.Video.Media.INTERNAL_CONTENT_URI, folder) + repository.insertFromUri(MediaStore.Video.Media.EXTERNAL_CONTENT_URI, folder) + } + + else -> { + insertCustomFolderIntoDB(folder, repository) + } + } + } + + /** + * Attempts to get the file path from a content URI string (e.g., content://media/external/images/media/2281) + * and checks its type. If the conditions are met, the file is stored for auto-upload. + *

+ * If any attempt fails, the method returns {@code false}. + * + * @param syncedFolder The folder marked for auto-upload. + * @param contentUris An array of content URI strings collected from + * {@link ContentObserverWork##checkAndTriggerAutoUpload()}. + * @return {@code true} if all changed content URIs were successfully stored; {@code false} otherwise. + */ + fun insertChangedEntries( + syncedFolder: SyncedFolder, + contentUris: Array?, + repository: FileSystemRepository + ): Boolean { + contentUris?.forEach { uriString -> + try { + val uri = uriString.toUri() + repository.insertFromUri(uri, syncedFolder, true) + } catch (e: Exception) { + Log_OC.e(TAG, "Invalid URI: $uriString", e) + return false + } + } + + Log_OC.d(TAG, "Changed content URIs successfully stored") + + return true + } + + fun insertCustomFolderIntoDB(folder: SyncedFolder, repository: FileSystemRepository): Int { val path = Paths.get(folder.localPath) if (!Files.exists(path)) { @@ -70,7 +132,7 @@ class AutoUploadHelper { val creationTime = attrs?.creationTime()?.toMillis() val localPath = file.toLocalPath() - repository?.insertOrReplace(localPath, lastModified, creationTime, folder) + repository.insertOrReplace(localPath, lastModified, creationTime, folder) fileCount++ diff --git a/app/src/main/java/com/nextcloud/client/jobs/autoUpload/AutoUploadWorker.kt b/app/src/main/java/com/nextcloud/client/jobs/autoUpload/AutoUploadWorker.kt index 8ae9d481af2d..e1fc93df33bc 100644 --- a/app/src/main/java/com/nextcloud/client/jobs/autoUpload/AutoUploadWorker.kt +++ b/app/src/main/java/com/nextcloud/client/jobs/autoUpload/AutoUploadWorker.kt @@ -42,7 +42,6 @@ import com.owncloud.android.lib.common.utils.Log_OC import com.owncloud.android.operations.UploadFileOperation import com.owncloud.android.ui.activity.SettingsActivity import com.owncloud.android.utils.FileStorageUtils -import com.owncloud.android.utils.FilesSyncHelper import com.owncloud.android.utils.MimeType import com.owncloud.android.utils.theme.ViewThemeUtils import kotlinx.coroutines.Dispatchers @@ -230,16 +229,16 @@ class AutoUploadWorker( private suspend fun collectFileChangesFromContentObserverWork(contentUris: Array?) = try { withContext(Dispatchers.IO) { if (contentUris.isNullOrEmpty()) { - FilesSyncHelper.insertAllDBEntriesForSyncedFolder(syncedFolder, helper, repository) + helper.insertEntries(syncedFolder, repository) } else { - val isContentUrisStored = FilesSyncHelper.insertChangedEntries(syncedFolder, contentUris, repository) + val isContentUrisStored = helper.insertChangedEntries(syncedFolder, contentUris, repository) if (!isContentUrisStored) { Log_OC.w( TAG, "changed content uris not stored, fallback to insert all db entries to not lose files" ) - FilesSyncHelper.insertAllDBEntriesForSyncedFolder(syncedFolder, helper, repository) + helper.insertEntries(syncedFolder, repository) } } syncedFolder.lastScanTimestampMs = System.currentTimeMillis() diff --git a/app/src/main/java/com/owncloud/android/utils/FilesSyncHelper.java b/app/src/main/java/com/owncloud/android/utils/FilesSyncHelper.java index 0f7dffe27c27..60ac53201200 100644 --- a/app/src/main/java/com/owncloud/android/utils/FilesSyncHelper.java +++ b/app/src/main/java/com/owncloud/android/utils/FilesSyncHelper.java @@ -10,18 +10,12 @@ package com.owncloud.android.utils; import android.content.Context; -import android.net.Uri; -import android.provider.MediaStore; import com.nextcloud.client.account.UserAccountManager; import com.nextcloud.client.device.PowerManagementService; import com.nextcloud.client.jobs.BackgroundJobManager; -import com.nextcloud.client.jobs.ContentObserverWork; -import com.nextcloud.client.jobs.autoUpload.AutoUploadHelper; -import com.nextcloud.client.jobs.autoUpload.FileSystemRepository; import com.nextcloud.client.jobs.upload.FileUploadHelper; import com.nextcloud.client.network.ConnectivityService; -import com.owncloud.android.datamodel.MediaFolderType; import com.owncloud.android.datamodel.SyncedFolder; import com.owncloud.android.datamodel.SyncedFolderProvider; import com.owncloud.android.datamodel.UploadsStorageManager; @@ -39,65 +33,6 @@ private FilesSyncHelper() { // utility class -> private constructor } - public static void insertAllDBEntriesForSyncedFolder(SyncedFolder syncedFolder, AutoUploadHelper helper, FileSystemRepository repository) { - final long enabledTimestampMs = syncedFolder.getEnabledTimestampMs(); - - if (syncedFolder.isEnabled() && (syncedFolder.isExisting() || enabledTimestampMs >= 0)) { - MediaFolderType mediaType = syncedFolder.getType(); - - if (mediaType == MediaFolderType.IMAGE) { - repository.insertFromUri(MediaStore.Images.Media.INTERNAL_CONTENT_URI, syncedFolder); - repository.insertFromUri(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, syncedFolder); - } else if (mediaType == MediaFolderType.VIDEO) { - repository.insertFromUri(MediaStore.Video.Media.INTERNAL_CONTENT_URI, syncedFolder); - repository.insertFromUri(MediaStore.Video.Media.EXTERNAL_CONTENT_URI, syncedFolder); - } else { - helper.insertCustomFolderIntoDB(syncedFolder, repository); - } - } else { - if (!syncedFolder.isEnabled()) { - Log_OC.w(TAG, "insertAllDBEntriesForSyncedFolder, syncedFolder not enabled"); - } - - if (!syncedFolder.isExisting()) { - Log_OC.w(TAG, "insertAllDBEntriesForSyncedFolder, syncedFolder is not exists"); - } - - Log_OC.w(TAG, "insertAllDBEntriesForSyncedFolder, enabledTimestampMs: " + enabledTimestampMs); - } - } - - /** - * Attempts to get the file path from a content URI string (e.g., content://media/external/images/media/2281) - * and checks its type. If the conditions are met, the file is stored for auto-upload. - *

- * If any attempt fails, the method returns {@code false}. - * - * @param syncedFolder The folder marked for auto-upload. - * @param contentUris An array of content URI strings collected from {@link ContentObserverWork##checkAndTriggerAutoUpload()}. - * @return {@code true} if all changed content URIs were successfully stored; {@code false} otherwise. - */ - public static boolean insertChangedEntries(SyncedFolder syncedFolder, String[] contentUris, FileSystemRepository repository) { - for (String contentUriString : contentUris) { - if (contentUriString == null) { - Log_OC.w(TAG, "null content uri string"); - return false; - } - - try { - Uri contentUri = Uri.parse(contentUriString); - repository.insertFromUri(contentUri, syncedFolder, true); - } catch (Exception e) { - Log_OC.e(TAG, "Invalid URI: " + contentUriString, e); - return false; - } - } - - Log_OC.d(TAG, "changed content uris successfully stored"); - - return true; - } - public static void restartUploadsIfNeeded(final UploadsStorageManager uploadsStorageManager, final UserAccountManager accountManager, final ConnectivityService connectivityService, From 3d16819f7ec74ade1ae357a64651a5ee978fae4f Mon Sep 17 00:00:00 2001 From: alperozturk Date: Fri, 12 Dec 2025 14:38:28 +0100 Subject: [PATCH 063/216] deduplicate logic Signed-off-by: alperozturk --- .../nextcloud/client/jobs/autoUpload/FileSystemRepository.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/src/main/java/com/nextcloud/client/jobs/autoUpload/FileSystemRepository.kt b/app/src/main/java/com/nextcloud/client/jobs/autoUpload/FileSystemRepository.kt index f3a4dc9c9668..8cb6a74dc1ec 100644 --- a/app/src/main/java/com/nextcloud/client/jobs/autoUpload/FileSystemRepository.kt +++ b/app/src/main/java/com/nextcloud/client/jobs/autoUpload/FileSystemRepository.kt @@ -91,7 +91,7 @@ class FileSystemRepository(private val dao: FileSystemDao, private val context: val selection = "${MediaStore.MediaColumns.DATA} LIKE ?" val selectionArgs = arrayOf("$syncedPath%") - Log_OC.d(TAG, "Querying MediaStore for files in: $syncedPath") + Log_OC.d(TAG, "Querying MediaStore for files in: $syncedPath, uri: $uri") val cursor = context.contentResolver.query( uri, From 7a675e29e876b8d28e8f0a3f96cb56b1a3e661ba Mon Sep 17 00:00:00 2001 From: alperozturk Date: Fri, 12 Dec 2025 15:20:04 +0100 Subject: [PATCH 064/216] add repo to tests Signed-off-by: alperozturk --- .../extensions/SyncedFolderExtensions.kt | 2 ++ .../android/utils/AutoUploadHelperTest.kt | 35 +++++++++++++------ 2 files changed, 26 insertions(+), 11 deletions(-) diff --git a/app/src/main/java/com/nextcloud/utils/extensions/SyncedFolderExtensions.kt b/app/src/main/java/com/nextcloud/utils/extensions/SyncedFolderExtensions.kt index 5251aa341812..c7bdadfe6f54 100644 --- a/app/src/main/java/com/nextcloud/utils/extensions/SyncedFolderExtensions.kt +++ b/app/src/main/java/com/nextcloud/utils/extensions/SyncedFolderExtensions.kt @@ -23,6 +23,8 @@ private const val TAG = "SyncedFolderExtensions" */ @Suppress("ReturnCount") fun SyncedFolder.shouldSkipFile(file: File, lastModified: Long, creationTime: Long?): Boolean { + Log_OC.d(TAG, "Checking file: ${file.name}, lastModified=$lastModified, lastScan=$lastScanTimestampMs") + if (isExcludeHidden && file.isHidden) { Log_OC.d(TAG, "Skipping hidden: ${file.absolutePath}") return true diff --git a/app/src/test/java/com/owncloud/android/utils/AutoUploadHelperTest.kt b/app/src/test/java/com/owncloud/android/utils/AutoUploadHelperTest.kt index 1eb86275abb1..d76502ab8f82 100644 --- a/app/src/test/java/com/owncloud/android/utils/AutoUploadHelperTest.kt +++ b/app/src/test/java/com/owncloud/android/utils/AutoUploadHelperTest.kt @@ -7,10 +7,15 @@ package com.owncloud.android.utils +import android.content.Context +import com.nextcloud.client.database.dao.FileSystemDao import com.nextcloud.client.jobs.autoUpload.AutoUploadHelper +import com.nextcloud.client.jobs.autoUpload.FileSystemRepository import com.nextcloud.client.preferences.SubFolderRule import com.owncloud.android.datamodel.MediaFolderType import com.owncloud.android.datamodel.SyncedFolder +import io.mockk.clearAllMocks +import io.mockk.mockk import org.junit.After import org.junit.Assert.assertEquals import org.junit.Assert.assertTrue @@ -27,16 +32,24 @@ class AutoUploadHelperTest { private val helper = AutoUploadHelper() private val accountName = "testAccount" + private val mockDao: FileSystemDao = mockk(relaxed = true) + private val mockContext: Context = mockk(relaxed = true) + + private lateinit var repo: FileSystemRepository + @Before fun setup() { tempDir = Files.createTempDirectory("auto_upload_test_").toFile() tempDir.mkdirs() assertTrue("Failed to create temp directory", tempDir.exists()) + + repo = FileSystemRepository(mockDao, mockContext) } @After fun cleanup() { tempDir.deleteRecursively() + clearAllMocks() } private fun createTestFolder( @@ -81,7 +94,7 @@ class AutoUploadHelperTest { type = MediaFolderType.CUSTOM ) - val processedCount = helper.insertCustomFolderIntoDB(folder, null) + val processedCount = helper.insertCustomFolderIntoDB(folder, repo) assertEquals("Should process 2 files", 2, processedCount) } @@ -98,7 +111,7 @@ class AutoUploadHelperTest { type = MediaFolderType.CUSTOM ) - val processedCount = helper.insertCustomFolderIntoDB(folder, null) + val processedCount = helper.insertCustomFolderIntoDB(folder, repo) assertTrue("Should process at least 1 file", processedCount >= 1) } @@ -120,7 +133,7 @@ class AutoUploadHelperTest { type = MediaFolderType.CUSTOM ) - val processedCount = helper.insertCustomFolderIntoDB(folder, null) + val processedCount = helper.insertCustomFolderIntoDB(folder, repo) // Should only process the new file (modified after last scan) assertEquals("Should process only 1 new file", 1, processedCount) @@ -145,7 +158,7 @@ class AutoUploadHelperTest { lastScanTimestampMs = currentTime } - val processedCount = helper.insertCustomFolderIntoDB(folder, null) + val processedCount = helper.insertCustomFolderIntoDB(folder, repo) // Should only process files newer than enabledTimestamp assertEquals("Should process only files after enabled timestamp", 1, processedCount) @@ -154,7 +167,7 @@ class AutoUploadHelperTest { @Test fun testInsertCustomFolderEmpty() { val folder = createTestFolder(type = MediaFolderType.CUSTOM) - val processedCount = helper.insertCustomFolderIntoDB(folder, null) + val processedCount = helper.insertCustomFolderIntoDB(folder, repo) assertEquals("Empty folder should process 0 files", 0, processedCount) } @@ -167,7 +180,7 @@ class AutoUploadHelperTest { type = MediaFolderType.CUSTOM ) - val processedCount = helper.insertCustomFolderIntoDB(folder, null) + val processedCount = helper.insertCustomFolderIntoDB(folder, repo) assertEquals("Non-existent folder should return 0", 0, processedCount) } @@ -181,7 +194,7 @@ class AutoUploadHelperTest { File(subDir, "nested.txt").writeText("Nested file") val folder = createTestFolder(type = MediaFolderType.CUSTOM) - val processedCount = helper.insertCustomFolderIntoDB(folder, null) + val processedCount = helper.insertCustomFolderIntoDB(folder, repo) assertEquals("Should process files in root and subdirectories", 2, processedCount) } @@ -209,7 +222,7 @@ class AutoUploadHelperTest { lastScanTimestampMs = currentTime } - val processedCount = helper.insertCustomFolderIntoDB(folder, null) + val processedCount = helper.insertCustomFolderIntoDB(folder, repo) // Should skip hidden directory and its contents assertEquals("Should only process regular file", 1, processedCount) @@ -262,7 +275,7 @@ class AutoUploadHelperTest { * ${tempDir.absolutePath}/FOLDER_A/FOLDER_B/FOLDER_D/FOLDER_E/FILE_A.txt -> 1 * Total = 5 files */ - val processedCount = helper.insertCustomFolderIntoDB(syncedFolder, null) + val processedCount = helper.insertCustomFolderIntoDB(syncedFolder, repo) assertEquals("Should process all files in complex nested structure", 5, processedCount) } @@ -303,7 +316,7 @@ class AutoUploadHelperTest { setEnabled(true, currentTime) } - val processedCountSkipOld = helper.insertCustomFolderIntoDB(folderSkipOld, null) + val processedCountSkipOld = helper.insertCustomFolderIntoDB(folderSkipOld, repo) assertEquals( "When 'also upload existing' is disabled, only new files created after enabling should be processed", 1, @@ -318,7 +331,7 @@ class AutoUploadHelperTest { setEnabled(true, currentTime) } - val processedCountAll = helper.insertCustomFolderIntoDB(folderUploadAll, null) + val processedCountAll = helper.insertCustomFolderIntoDB(folderUploadAll, repo) assertEquals( "When 'also upload existing' is enabled, should upload all files", 2, From 1b28c0782d0ce46efbe069fd05a60fbe0683da9f Mon Sep 17 00:00:00 2001 From: alperozturk Date: Fri, 12 Dec 2025 15:58:30 +0100 Subject: [PATCH 065/216] fix tests Signed-off-by: alperozturk --- .../android/utils/AutoUploadHelperTest.kt | 83 ++++++++----------- 1 file changed, 36 insertions(+), 47 deletions(-) diff --git a/app/src/test/java/com/owncloud/android/utils/AutoUploadHelperTest.kt b/app/src/test/java/com/owncloud/android/utils/AutoUploadHelperTest.kt index d76502ab8f82..993ee41a2915 100644 --- a/app/src/test/java/com/owncloud/android/utils/AutoUploadHelperTest.kt +++ b/app/src/test/java/com/owncloud/android/utils/AutoUploadHelperTest.kt @@ -12,6 +12,7 @@ import com.nextcloud.client.database.dao.FileSystemDao import com.nextcloud.client.jobs.autoUpload.AutoUploadHelper import com.nextcloud.client.jobs.autoUpload.FileSystemRepository import com.nextcloud.client.preferences.SubFolderRule +import com.nextcloud.utils.extensions.shouldSkipFile import com.owncloud.android.datamodel.MediaFolderType import com.owncloud.android.datamodel.SyncedFolder import io.mockk.clearAllMocks @@ -23,7 +24,6 @@ import org.junit.Before import org.junit.Test import java.io.File import java.nio.file.Files -import java.nio.file.attribute.FileTime @Suppress("MagicNumber") class AutoUploadHelperTest { @@ -122,21 +122,21 @@ class AutoUploadHelperTest { // Create an old file val oldFile = File(tempDir, "old.txt").apply { writeText("Old") } - oldFile.setLastModified(currentTime - 10000) // 10 seconds ago + val oldFileLastModified = currentTime - 10000 // 10 seconds ago // Create a new file val newFile = File(tempDir, "new.txt").apply { writeText("New") } - newFile.setLastModified(currentTime) val folder = createTestFolder( lastScan = currentTime - 5000, // Last scan was 5 seconds ago type = MediaFolderType.CUSTOM ) - val processedCount = helper.insertCustomFolderIntoDB(folder, repo) + val shouldSkipOldFile = folder.shouldSkipFile(oldFile, oldFileLastModified, null) + assertTrue(shouldSkipOldFile) - // Should only process the new file (modified after last scan) - assertEquals("Should process only 1 new file", 1, processedCount) + val shouldSkipNewFile = folder.shouldSkipFile(newFile, currentTime, null) + assertTrue(!shouldSkipNewFile) } @Test @@ -145,10 +145,9 @@ class AutoUploadHelperTest { // old file should not be scanned val oldFile = File(tempDir, "old.txt").apply { writeText("Old") } - oldFile.setLastModified(currentTime - 10000) + val oldFileLastModified = currentTime - 10000 // 10 seconds ago val newFile = File(tempDir, "new.txt").apply { writeText("New") } - newFile.setLastModified(currentTime) // Enabled 5 seconds ago val folder = createTestFolder( @@ -158,10 +157,11 @@ class AutoUploadHelperTest { lastScanTimestampMs = currentTime } - val processedCount = helper.insertCustomFolderIntoDB(folder, repo) + val shouldSkipOldFile = folder.shouldSkipFile(oldFile, oldFileLastModified, null) + assertTrue(shouldSkipOldFile) - // Should only process files newer than enabledTimestamp - assertEquals("Should process only files after enabled timestamp", 1, processedCount) + val shouldSkipNewFile = folder.shouldSkipFile(newFile, currentTime, null) + assertTrue(!shouldSkipNewFile) } @Test @@ -266,15 +266,15 @@ class AutoUploadHelperTest { type = MediaFolderType.CUSTOM ) - /* - * Expected file count with full paths: - * ${tempDir.absolutePath}/FOLDER_A/FILE_A.txt -> 1 - * ${tempDir.absolutePath}/FOLDER_A/FOLDER_B/FILE_B.txt -> 1 - * ${tempDir.absolutePath}/FOLDER_A/FOLDER_C/FILE_A.txt -> 1 - * ${tempDir.absolutePath}/FOLDER_A/FOLDER_C/FILE_B.txt -> 1 - * ${tempDir.absolutePath}/FOLDER_A/FOLDER_B/FOLDER_D/FOLDER_E/FILE_A.txt -> 1 - * Total = 5 files - */ + /* + * Expected file count with full paths: + * ${tempDir.absolutePath}/FOLDER_A/FILE_A.txt -> 1 + * ${tempDir.absolutePath}/FOLDER_A/FOLDER_B/FILE_B.txt -> 1 + * ${tempDir.absolutePath}/FOLDER_A/FOLDER_C/FILE_A.txt -> 1 + * ${tempDir.absolutePath}/FOLDER_A/FOLDER_C/FILE_B.txt -> 1 + * ${tempDir.absolutePath}/FOLDER_A/FOLDER_B/FOLDER_D/FOLDER_E/FILE_A.txt -> 1 + * Total = 5 files + */ val processedCount = helper.insertCustomFolderIntoDB(syncedFolder, repo) assertEquals("Should process all files in complex nested structure", 5, processedCount) } @@ -287,26 +287,15 @@ class AutoUploadHelperTest { val oldFile = File(tempDir, "old_file.txt").apply { writeText("Old file") } - - val oldFilePath = oldFile.toPath() - Files.setAttribute( - oldFilePath, - "creationTime", - FileTime.fromMillis(currentTime - 60_000) // 1 minute before enabling - ) - - Thread.sleep(1000) + val oldFileCreationTime = currentTime - 10_000 + val oldFileLastModified = currentTime - 5_000 // New file (created after enabling auto-upload) val newFile = File(tempDir, "new_file.txt").apply { writeText("New file") } - val newFilePath = newFile.toPath() - Files.setAttribute( - newFilePath, - "creationTime", - FileTime.fromMillis(currentTime + 60_000) // 1 minute after enabling - ) + val newFileCreationTime = currentTime + 10_000 + val newFileLastModified = currentTime + 5_000 val folderSkipOld = createTestFolder( localPath = tempDir.absolutePath, @@ -316,12 +305,11 @@ class AutoUploadHelperTest { setEnabled(true, currentTime) } - val processedCountSkipOld = helper.insertCustomFolderIntoDB(folderSkipOld, repo) - assertEquals( - "When 'also upload existing' is disabled, only new files created after enabling should be processed", - 1, - processedCountSkipOld - ) + val shouldSkipOldFile = folderSkipOld.shouldSkipFile(oldFile, oldFileLastModified, oldFileCreationTime) + assertTrue(shouldSkipOldFile) + + val shouldSkipNewFile = folderSkipOld.shouldSkipFile(newFile, newFileLastModified, newFileCreationTime) + assertTrue(!shouldSkipNewFile) val folderUploadAll = createTestFolder( localPath = tempDir.absolutePath, @@ -331,11 +319,12 @@ class AutoUploadHelperTest { setEnabled(true, currentTime) } - val processedCountAll = helper.insertCustomFolderIntoDB(folderUploadAll, repo) - assertEquals( - "When 'also upload existing' is enabled, should upload all files", - 2, - processedCountAll - ) + val shouldSkipOldFileIfAlsoUploadExistingFile = + folderUploadAll.shouldSkipFile(oldFile, oldFileLastModified, oldFileCreationTime) + assertTrue(!shouldSkipOldFileIfAlsoUploadExistingFile) + + val shouldSkipNewFileIfAlsoUploadExistingFile = + folderUploadAll.shouldSkipFile(newFile, newFileLastModified, newFileCreationTime) + assertTrue(!shouldSkipNewFileIfAlsoUploadExistingFile) } } From ad4a4831bb02723d586776ea825fd6f6a8003f62 Mon Sep 17 00:00:00 2001 From: alperozturk Date: Tue, 9 Dec 2025 11:40:59 +0100 Subject: [PATCH 066/216] token cannot be null Signed-off-by: alperozturk --- .../operations/UploadFileOperation.java | 27 ++++++++++++++----- 1 file changed, 20 insertions(+), 7 deletions(-) diff --git a/app/src/main/java/com/owncloud/android/operations/UploadFileOperation.java b/app/src/main/java/com/owncloud/android/operations/UploadFileOperation.java index ddeccdc15078..7e57ec1465fe 100644 --- a/app/src/main/java/com/owncloud/android/operations/UploadFileOperation.java +++ b/app/src/main/java/com/owncloud/android/operations/UploadFileOperation.java @@ -481,7 +481,7 @@ private RemoteOperationResult encryptedUpload(OwnCloudClient client, OCFile pare E2EFiles e2eFiles = new E2EFiles(parentFile, null, new File(mOriginalStoragePath), null, null); FileLock fileLock = null; long size; - + boolean folderWasLocked = false; boolean metadataExists = false; String token = null; Object object = null; @@ -497,7 +497,20 @@ private RemoteOperationResult encryptedUpload(OwnCloudClient client, OCFile pare } long counter = getE2ECounter(parentFile); - token = getFolderUnlockTokenOrLockFolder(client, parentFile, counter); + + try { + token = getFolderUnlockTokenOrLockFolder(client, parentFile, counter); + + if (token == null || token.isEmpty()) { + Log_OC.e(TAG, "Failed to obtain folder lock token for encrypted upload"); + return new RemoteOperationResult<>(new IllegalStateException("Cannot proceed: folder lock token is null or empty")); + } + folderWasLocked = true; + Log_OC.d(TAG, "folder successfully locked"); + } catch (Exception e) { + Log_OC.e(TAG, "Failed to lock folder", e); + return new RemoteOperationResult<>(e); + } // Update metadata EncryptionUtilsV2 encryptionUtilsV2 = new EncryptionUtilsV2(); @@ -508,7 +521,7 @@ private RemoteOperationResult encryptedUpload(OwnCloudClient client, OCFile pare if (isEndToEndVersionAtLeastV2()) { if (object == null) { - return new RemoteOperationResult(new IllegalStateException("Metadata does not exist")); + return new RemoteOperationResult<>(new IllegalStateException("Metadata does not exist")); } } else { object = getDecryptedFolderMetadataV1(publicKey, object); @@ -518,7 +531,7 @@ private RemoteOperationResult encryptedUpload(OwnCloudClient client, OCFile pare List fileNames = getCollidedFileNames(object); - RemoteOperationResult collisionResult = checkNameCollision(parentFile, client, fileNames, parentFile.isEncrypted()); + final var collisionResult = checkNameCollision(parentFile, client, fileNames, parentFile.isEncrypted()); if (collisionResult != null) { result = collisionResult; return collisionResult; @@ -563,13 +576,13 @@ private RemoteOperationResult encryptedUpload(OwnCloudClient client, OCFile pare } } catch (FileNotFoundException e) { Log_OC.e(TAG, mFile.getStoragePath() + " does not exist anymore"); - result = new RemoteOperationResult(ResultCode.LOCAL_FILE_NOT_FOUND); + result = new RemoteOperationResult<>(ResultCode.LOCAL_FILE_NOT_FOUND); } catch (OverlappingFileLockException e) { Log_OC.e(TAG, "Overlapping file lock exception"); - result = new RemoteOperationResult(ResultCode.LOCK_FAILED); + result = new RemoteOperationResult<>(ResultCode.LOCK_FAILED); } catch (Exception e) { Log_OC.e(TAG, "UploadFileOperation exception: " + e.getLocalizedMessage()); - result = new RemoteOperationResult(e); + result = new RemoteOperationResult<>(e); } finally { result = cleanupE2EUpload(fileLock, e2eFiles, result, object, client, token); } From db0890840b9981f3b84d143175170dee1cfbd06b Mon Sep 17 00:00:00 2001 From: alperozturk Date: Tue, 9 Dec 2025 13:54:40 +0100 Subject: [PATCH 067/216] fix: e2ee folder unlock Signed-off-by: alperozturk --- .../operations/UploadFileOperation.java | 46 +++++++++++++++---- 1 file changed, 37 insertions(+), 9 deletions(-) diff --git a/app/src/main/java/com/owncloud/android/operations/UploadFileOperation.java b/app/src/main/java/com/owncloud/android/operations/UploadFileOperation.java index 7e57ec1465fe..4e7d9538b5c9 100644 --- a/app/src/main/java/com/owncloud/android/operations/UploadFileOperation.java +++ b/app/src/main/java/com/owncloud/android/operations/UploadFileOperation.java @@ -481,7 +481,6 @@ private RemoteOperationResult encryptedUpload(OwnCloudClient client, OCFile pare E2EFiles e2eFiles = new E2EFiles(parentFile, null, new File(mOriginalStoragePath), null, null); FileLock fileLock = null; long size; - boolean folderWasLocked = false; boolean metadataExists = false; String token = null; Object object = null; @@ -505,7 +504,6 @@ private RemoteOperationResult encryptedUpload(OwnCloudClient client, OCFile pare Log_OC.e(TAG, "Failed to obtain folder lock token for encrypted upload"); return new RemoteOperationResult<>(new IllegalStateException("Cannot proceed: folder lock token is null or empty")); } - folderWasLocked = true; Log_OC.d(TAG, "folder successfully locked"); } catch (Exception e) { Log_OC.e(TAG, "Failed to lock folder", e); @@ -612,13 +610,20 @@ private long getE2ECounter(OCFile parentFile) { private String getFolderUnlockTokenOrLockFolder(OwnCloudClient client, OCFile parentFile, long counter) throws UploadException { if (mFolderUnlockToken != null && !mFolderUnlockToken.isEmpty()) { + Log_OC.d(TAG, "Reusing existing folder unlock token from previous upload attempt"); return mFolderUnlockToken; } String token = EncryptionUtils.lockFolder(parentFile, client, counter); + if (token == null || token.isEmpty()) { + Log_OC.e(TAG, "Lock folder returned null or empty token"); + throw new UploadException("Failed to lock folder: token is null or empty"); + } + mUpload.setFolderUnlockToken(token); uploadsStorageManager.updateUpload(mUpload); + Log_OC.d(TAG, "Folder locked successfully, token saved"); return token; } @@ -763,12 +768,12 @@ private RemoteOperationResult performE2EUpload(E2EClientData data) throws Operat throw new OperationCancelledException(); } - RemoteOperationResult result = mUploadOperation.execute(data.getClient()); + var result = mUploadOperation.execute(data.getClient()); /// move local temporal file or original file to its corresponding // location in the Nextcloud local folder if (!result.isSuccess() && result.getHttpCode() == HttpStatus.SC_PRECONDITION_FAILED) { - result = new RemoteOperationResult(ResultCode.SYNC_CONFLICT); + result = new RemoteOperationResult<>(ResultCode.SYNC_CONFLICT); } return result; @@ -906,17 +911,36 @@ private RemoteOperationResult cleanupE2EUpload(FileLock fileLock, E2EFiles e2eFi e2eFiles.deleteTemporalFileWithOriginalFileComparison(); if (result == null) { - result = new RemoteOperationResult(ResultCode.UNKNOWN_ERROR); + result = new RemoteOperationResult<>(ResultCode.UNKNOWN_ERROR); } logResult(result, mFile.getStoragePath(), mFile.getRemotePath()); + if (token == null || token.isEmpty()) { + Log_OC.e(TAG, "CRITICAL ERROR: Folder was locked but token is null/empty. Cannot unlock! " + + "Folder: " + e2eFiles.getParentFile().getFileName()); + RemoteOperationResult tokenError = new RemoteOperationResult<>( + new IllegalStateException("Folder locked but token lost - manual intervention may be required") + ); + + // Override result only if original operation succeeded + if (result.isSuccess()) { + result = tokenError; + } + return result; + } + // Unlock must be done otherwise folder stays locked and user can't upload any file RemoteOperationResult unlockFolderResult; - if (object instanceof DecryptedFolderMetadataFileV1) { - unlockFolderResult = EncryptionUtils.unlockFolderV1(e2eFiles.getParentFile(), client, token); - } else { - unlockFolderResult = EncryptionUtils.unlockFolder(e2eFiles.getParentFile(), client, token); + try { + if (object instanceof DecryptedFolderMetadataFileV1) { + unlockFolderResult = EncryptionUtils.unlockFolderV1(e2eFiles.getParentFile(), client, token); + } else { + unlockFolderResult = EncryptionUtils.unlockFolder(e2eFiles.getParentFile(), client, token); + } + } catch (Exception e) { + Log_OC.e(TAG, "CRITICAL ERROR: Exception during folder unlock", e); + unlockFolderResult = new RemoteOperationResult<>(e); } if (unlockFolderResult != null && !unlockFolderResult.isSuccess()) { @@ -932,6 +956,10 @@ private RemoteOperationResult cleanupE2EUpload(FileLock fileLock, E2EFiles e2eFi return Unit.INSTANCE; }); } + + // Clear the saved token since folder is now unlocked + mUpload.setFolderUnlockToken(null); + uploadsStorageManager.updateUpload(mUpload); } e2eFiles.deleteEncryptedTempFile(); From b6852f29a264392e5e3e14088a2daa399f264442 Mon Sep 17 00:00:00 2001 From: alperozturk Date: Tue, 9 Dec 2025 14:07:33 +0100 Subject: [PATCH 068/216] fix: e2ee folder unlock Signed-off-by: alperozturk --- .../operations/UploadFileOperation.java | 34 ++++++++++++------- .../android/operations/e2e/E2EFiles.kt | 2 +- 2 files changed, 22 insertions(+), 14 deletions(-) diff --git a/app/src/main/java/com/owncloud/android/operations/UploadFileOperation.java b/app/src/main/java/com/owncloud/android/operations/UploadFileOperation.java index 4e7d9538b5c9..67c72209bf5c 100644 --- a/app/src/main/java/com/owncloud/android/operations/UploadFileOperation.java +++ b/app/src/main/java/com/owncloud/android/operations/UploadFileOperation.java @@ -484,7 +484,7 @@ private RemoteOperationResult encryptedUpload(OwnCloudClient client, OCFile pare boolean metadataExists = false; String token = null; Object object = null; - + FileChannel channel = null; ArbitraryDataProvider arbitraryDataProvider = new ArbitraryDataProviderImpl(getContext()); String publicKey = arbitraryDataProvider.getValue(user.getAccountName(), EncryptionUtils.PUBLIC_KEY); @@ -499,12 +499,6 @@ private RemoteOperationResult encryptedUpload(OwnCloudClient client, OCFile pare try { token = getFolderUnlockTokenOrLockFolder(client, parentFile, counter); - - if (token == null || token.isEmpty()) { - Log_OC.e(TAG, "Failed to obtain folder lock token for encrypted upload"); - return new RemoteOperationResult<>(new IllegalStateException("Cannot proceed: folder lock token is null or empty")); - } - Log_OC.d(TAG, "folder successfully locked"); } catch (Exception e) { Log_OC.e(TAG, "Failed to lock folder", e); return new RemoteOperationResult<>(e); @@ -561,7 +555,7 @@ private RemoteOperationResult encryptedUpload(OwnCloudClient client, OCFile pare Triple channelResult = initFileChannel(result, fileLock, e2eFiles); fileLock = channelResult.getFirst(); result = channelResult.getSecond(); - FileChannel channel = channelResult.getThird(); + channel = channelResult.getThird(); size = getChannelSize(channel); updateSize(size); @@ -582,7 +576,7 @@ private RemoteOperationResult encryptedUpload(OwnCloudClient client, OCFile pare Log_OC.e(TAG, "UploadFileOperation exception: " + e.getLocalizedMessage()); result = new RemoteOperationResult<>(e); } finally { - result = cleanupE2EUpload(fileLock, e2eFiles, result, object, client, token); + result = cleanupE2EUpload(fileLock, channel, e2eFiles, result, object, client, token); } completeE2EUpload(result, e2eFiles, client); @@ -714,7 +708,8 @@ private void setUploadOperationForE2E(String token, private Triple initFileChannel(RemoteOperationResult result, FileLock fileLock, E2EFiles e2eFiles) throws IOException { FileChannel channel = null; - try (RandomAccessFile randomAccessFile = new RandomAccessFile(mFile.getStoragePath(), "rw")) { + try { + RandomAccessFile randomAccessFile = new RandomAccessFile(mFile.getStoragePath(), "rw"); channel = randomAccessFile.getChannel(); fileLock = channel.tryLock(); } catch (IOException ioException) { @@ -743,7 +738,7 @@ private Triple initFileChannel(Rem Log_OC.d(TAG, "Error caught at getChannelFromFile: " + e); } } else { - result = new RemoteOperationResult(ResultCode.LOCK_FAILED); + result = new RemoteOperationResult<>(ResultCode.LOCK_FAILED); } } } @@ -897,17 +892,28 @@ private void completeE2EUpload(RemoteOperationResult result, E2EFiles e2eFiles, e2eFiles.deleteTemporalFile(); } - private RemoteOperationResult cleanupE2EUpload(FileLock fileLock, E2EFiles e2eFiles, RemoteOperationResult result, Object object, OwnCloudClient client, String token) { + private RemoteOperationResult cleanupE2EUpload(FileLock fileLock, FileChannel channel, E2EFiles e2eFiles, RemoteOperationResult result, Object object, OwnCloudClient client, String token) { mUploadStarted.set(false); if (fileLock != null) { try { - fileLock.release(); + // Only release if the channel is still open/valid + if (channel != null && channel.isOpen()) { + fileLock.release(); + } } catch (IOException e) { Log_OC.e(TAG, "Failed to unlock file with path " + mFile.getStoragePath()); } } + if (channel != null) { + try { + channel.close(); + } catch (IOException e) { + Log_OC.e(TAG, "Failed to close file channel", e); + } + } + e2eFiles.deleteTemporalFileWithOriginalFileComparison(); if (result == null) { @@ -960,6 +966,8 @@ private RemoteOperationResult cleanupE2EUpload(FileLock fileLock, E2EFiles e2eFi // Clear the saved token since folder is now unlocked mUpload.setFolderUnlockToken(null); uploadsStorageManager.updateUpload(mUpload); + + Log_OC.d(TAG, "Folder unlock token removed"); } e2eFiles.deleteEncryptedTempFile(); diff --git a/app/src/main/java/com/owncloud/android/operations/e2e/E2EFiles.kt b/app/src/main/java/com/owncloud/android/operations/e2e/E2EFiles.kt index d67a0958857c..aee43b97f19e 100644 --- a/app/src/main/java/com/owncloud/android/operations/e2e/E2EFiles.kt +++ b/app/src/main/java/com/owncloud/android/operations/e2e/E2EFiles.kt @@ -38,7 +38,7 @@ data class E2EFiles( fun deleteEncryptedTempFile() { if (encryptedTempFile != null) { val isTempEncryptedFileDeleted = encryptedTempFile?.delete() - Log_OC.e(tag, "isTempEncryptedFileDeleted: $isTempEncryptedFileDeleted") + Log_OC.d(tag, "isTempEncryptedFileDeleted: $isTempEncryptedFileDeleted") } else { Log_OC.e(tag, "Encrypted temp file cannot be found") } From 626ce42353c0f43bb676069f154d429297be2457 Mon Sep 17 00:00:00 2001 From: alperozturk Date: Wed, 10 Dec 2025 13:37:27 +0100 Subject: [PATCH 069/216] remove reset folder unlock token since ocupload will be used for each item Signed-off-by: alperozturk --- .../owncloud/android/operations/UploadFileOperation.java | 6 ------ 1 file changed, 6 deletions(-) diff --git a/app/src/main/java/com/owncloud/android/operations/UploadFileOperation.java b/app/src/main/java/com/owncloud/android/operations/UploadFileOperation.java index 67c72209bf5c..9bafd4fe593c 100644 --- a/app/src/main/java/com/owncloud/android/operations/UploadFileOperation.java +++ b/app/src/main/java/com/owncloud/android/operations/UploadFileOperation.java @@ -962,12 +962,6 @@ private RemoteOperationResult cleanupE2EUpload(FileLock fileLock, FileChannel ch return Unit.INSTANCE; }); } - - // Clear the saved token since folder is now unlocked - mUpload.setFolderUnlockToken(null); - uploadsStorageManager.updateUpload(mUpload); - - Log_OC.d(TAG, "Folder unlock token removed"); } e2eFiles.deleteEncryptedTempFile(); From e90137bedf20a6c7f5aca753f49689ff9b869741 Mon Sep 17 00:00:00 2001 From: alperozturk Date: Wed, 10 Dec 2025 08:35:45 +0100 Subject: [PATCH 070/216] fix: reopening list from navigation view Signed-off-by: alperozturk --- .../android/ui/fragment/OCFileListFragment.java | 10 +++------- 1 file changed, 3 insertions(+), 7 deletions(-) diff --git a/app/src/main/java/com/owncloud/android/ui/fragment/OCFileListFragment.java b/app/src/main/java/com/owncloud/android/ui/fragment/OCFileListFragment.java index 18038398955f..2f2766ac6f83 100644 --- a/app/src/main/java/com/owncloud/android/ui/fragment/OCFileListFragment.java +++ b/app/src/main/java/com/owncloud/android/ui/fragment/OCFileListFragment.java @@ -1852,17 +1852,14 @@ protected void handleSearchEvent(SearchEvent event) { searchFragment = true; setFabVisible(false); - Runnable switchViewsRunnable = () -> { + new Handler(Looper.getMainLooper()).post(() -> { + updateSortButton(); if (isGridViewPreferred(mFile) && !isGridEnabled()) { switchToGridView(); } else if (!isGridViewPreferred(mFile) && isGridEnabled()) { switchToListView(); } - }; - - updateSortButton(); - - new Handler(Looper.getMainLooper()).post(switchViewsRunnable); + }); final User currentUser = accountManager.getUser(); final var remoteOperation = getSearchRemoteOperation(currentUser, event); @@ -1870,7 +1867,6 @@ protected void handleSearchEvent(SearchEvent event) { searchTask.execute(); } - protected RemoteOperation getSearchRemoteOperation(final User currentUser, final SearchEvent event) { boolean searchOnlyFolders = (getArguments() != null && getArguments().getBoolean(ARG_SEARCH_ONLY_FOLDER, false)); From a4c0d673ad5e34236c39028d850f832aedcd8b3b Mon Sep 17 00:00:00 2001 From: alperozturk Date: Wed, 10 Dec 2025 14:11:18 +0100 Subject: [PATCH 071/216] fix: gallery image scaling Signed-off-by: alperozturk --- .../java/com/nextcloud/utils/OCFileUtils.kt | 91 ++++++++---- .../android/ui/adapter/GalleryRowHolder.kt | 133 +++++++----------- 2 files changed, 113 insertions(+), 111 deletions(-) diff --git a/app/src/main/java/com/nextcloud/utils/OCFileUtils.kt b/app/src/main/java/com/nextcloud/utils/OCFileUtils.kt index 142c6edfa009..98160b8af1c9 100644 --- a/app/src/main/java/com/nextcloud/utils/OCFileUtils.kt +++ b/app/src/main/java/com/nextcloud/utils/OCFileUtils.kt @@ -22,48 +22,81 @@ import com.owncloud.android.utils.MimeTypeUtil object OCFileUtils { private const val TAG = "OCFileUtils" - @Suppress("ReturnCount", "NestedBlockDepth") fun getImageSize(ocFile: OCFile, defaultThumbnailSize: Float): Pair { + val fallback = defaultThumbnailSize.toInt().coerceAtLeast(1) + val fallbackPair = fallback to fallback + try { Log_OC.d(TAG, "Getting image size for: ${ocFile.fileName}") - val widthFromDimension = ocFile.imageDimension?.width - val heightFromDimension = ocFile.imageDimension?.height - if (widthFromDimension != null && heightFromDimension != null) { - val width = widthFromDimension.toInt() - val height = heightFromDimension.toInt() - Log_OC.d(TAG, "Image dimensions are used, width: $width, height: $height") + // Use server-provided imageDimension if available + ocFile.imageDimension?.let { dim -> + val width = dim.width.toInt().coerceAtLeast(1) + val height = dim.height.toInt().coerceAtLeast(1) + Log_OC.d(TAG, "Using server-provided imageDimension: $width x $height") return width to height } - return if (ocFile.exists()) { - val exif = ExifInterface(ocFile.storagePath) - val width = exif.getAttributeInt(ExifInterface.TAG_IMAGE_WIDTH, 0) - val height = exif.getAttributeInt(ExifInterface.TAG_IMAGE_LENGTH, 0) + // Fallback to local file if it exists + val path = ocFile.storagePath + if (!path.isNullOrEmpty() && ocFile.exists()) { - if (width > 0 && height > 0) { - Log_OC.d(TAG, "Exif used width: $width and height: $height") - width to height + // Try EXIF first + val exifSize = getExifSize(path) + if (exifSize != null) { + Log_OC.d(TAG, "EXIF size used: ${exifSize.first} x ${exifSize.second}") + return exifSize } - val (bitmapWidth, bitmapHeight) = BitmapUtils.getImageResolution(ocFile.storagePath) - .let { it[0] to it[1] } - - if (bitmapWidth > 0 && bitmapHeight > 0) { - Log_OC.d(TAG, "BitmapUtils.getImageResolution used width: $bitmapWidth and height: $bitmapHeight") - bitmapWidth to bitmapHeight + // Then try BitmapUtils + val bitmapSize = getBitmapSize(path) + if (bitmapSize != null) { + Log_OC.d(TAG, "BitmapUtils resolution used: ${bitmapSize.first} x ${bitmapSize.second}") + return bitmapSize } + } + + // Fallback to defaultThumbnailSize + Log_OC.d(TAG, "All sources failed, using default size: $fallback x $fallback") + return fallbackPair - val fallback = defaultThumbnailSize.toInt().coerceAtLeast(1) - Log_OC.d(TAG, "Default size used width: $fallback and height: $fallback") - fallback to fallback - } else { - Log_OC.d(TAG, "Default size is used: $defaultThumbnailSize") - val size = defaultThumbnailSize.toInt().coerceAtLeast(1) - size to size + } catch (e: Exception) { + Log_OC.e(TAG, "Error getting image size for ${ocFile.fileName}", e) + } + + return fallbackPair + } + + private fun getExifSize(path: String): Pair? { + return try { + val exif = ExifInterface(path) + var width = exif.getAttributeInt(ExifInterface.TAG_IMAGE_WIDTH, 0) + var height = exif.getAttributeInt(ExifInterface.TAG_IMAGE_LENGTH, 0) + + val orientation = exif.getAttributeInt( + ExifInterface.TAG_ORIENTATION, + ExifInterface.ORIENTATION_NORMAL + ) + if (orientation == ExifInterface.ORIENTATION_ROTATE_90 || + orientation == ExifInterface.ORIENTATION_ROTATE_270 + ) { + val tmp = width + width = height + height = tmp } - } finally { - Log_OC.d(TAG, "-----------------------------") + + if (width > 0 && height > 0) width to height else null + } catch (_: Exception) { + null + } + } + + private fun getBitmapSize(path: String): Pair? { + return try { + val (w, h) = BitmapUtils.getImageResolution(path).takeIf { it.size == 2 } ?: return null + if (w > 0 && h > 0) w to h else null + } catch (_: Exception) { + null } } diff --git a/app/src/main/java/com/owncloud/android/ui/adapter/GalleryRowHolder.kt b/app/src/main/java/com/owncloud/android/ui/adapter/GalleryRowHolder.kt index 877ed965f7e0..84b7a94844f5 100644 --- a/app/src/main/java/com/owncloud/android/ui/adapter/GalleryRowHolder.kt +++ b/app/src/main/java/com/owncloud/android/ui/adapter/GalleryRowHolder.kt @@ -10,7 +10,6 @@ package com.owncloud.android.ui.adapter import android.view.Gravity import android.view.View -import android.view.ViewGroup import android.widget.FrameLayout import android.widget.ImageView import androidx.core.content.ContextCompat @@ -27,8 +26,6 @@ import com.owncloud.android.databinding.GalleryRowBinding import com.owncloud.android.datamodel.FileDataStorageManager import com.owncloud.android.datamodel.GalleryRow import com.owncloud.android.datamodel.OCFile -import com.owncloud.android.lib.resources.files.model.ImageDimension -import com.owncloud.android.utils.DisplayUtils import com.owncloud.android.utils.theme.ViewThemeUtils @Suppress("LongParameterList") @@ -72,16 +69,15 @@ class GalleryRowHolder( if (lastFileCount != requiredCount) { binding.rowLayout.removeAllViews() for (file in row.files) { - val rowLayout = getRowLayout(file) - binding.rowLayout.addView(rowLayout) + binding.rowLayout.addView(getRowLayout(file)) } lastFileCount = requiredCount } - val shrinkRatio = computeShrinkRatio(row) + val dimensions = getDimensions(row) for (i in row.files.indices) { - adjustFile(i, row.files[i], shrinkRatio, row) + adjustFile(i, row.files[i], dimensions[i], row) } } @@ -115,7 +111,7 @@ class GalleryRowHolder( val rowCellImageView = ImageView(context).apply { setImageDrawable(drawable) adjustViewBounds = true - scaleType = ImageView.ScaleType.FIT_XY + scaleType = ImageView.ScaleType.CENTER_CROP layoutParams = FrameLayout.LayoutParams(width, height) } @@ -126,101 +122,74 @@ class GalleryRowHolder( } } - @SuppressWarnings("MagicNumber") - private fun computeShrinkRatio(row: GalleryRow): Float { - val screenWidth = DisplayUtils.convertDpToPixel( - context.resources.configuration.screenWidthDp.toFloat(), - context - ).toFloat() - - return if (row.files.size > 1) { - computeMultiFileShrinkRatio(row, screenWidth) - } else { - computeSingleFileShrinkRatio(row, screenWidth) - } - } + private fun adjustFile( + index: Int, + file: OCFile, + dims: Pair, + row: GalleryRow + ) { + val (width, height) = dims - private fun computeMultiFileShrinkRatio(row: GalleryRow, screenWidth: Float): Float { - val targetHeight = row.getMaxHeight() - var totalUnscaledWidth = 0f + val frameLayout = binding.rowLayout[index] as FrameLayout + val shimmer = frameLayout[0] as LoaderImageView + val thumbnail = frameLayout[1] as ImageView + val checkbox = frameLayout[2] as ImageView - for (file in row.files) { - val (originalWidth, originalHeight) = OCFileUtils.getImageSize(file, defaultThumbnailSize) + val isChecked = ocFileListDelegate.isCheckedFile(file) - val scaledWidth = targetHeight * (originalWidth.toFloat() / originalHeight) - file.imageDimension = ImageDimension(scaledWidth, targetHeight) + adjustRowCell(thumbnail, isChecked) + adjustCheckBox(checkbox, isChecked) - totalUnscaledWidth += scaledWidth + ocFileListDelegate.bindGalleryRow(shimmer, thumbnail, file, this, dims) + + val endMargin = if (index < row.files.size - 1) smallMargin else zero + + thumbnail.layoutParams = FrameLayout.LayoutParams(width, height).apply { + setMargins(0, 0, endMargin, smallMargin) } + shimmer.layoutParams = FrameLayout.LayoutParams(width, height) - val totalAvailableWidth = screenWidth - ((row.files.size - 1) * smallMargin) - return totalAvailableWidth / totalUnscaledWidth + frameLayout.requestLayout() } - private fun computeSingleFileShrinkRatio(row: GalleryRow, screenWidth: Float): Float { - val width = OCFileUtils.getImageSize(row.files[0], defaultThumbnailSize).first - return (screenWidth / galleryAdapter.columns) / width - } + private fun getDimensions(row: GalleryRow): List> { + val screenWidthPx = context.resources.displayMetrics.widthPixels.toFloat() + val marginPx = smallMargin.toFloat() - private fun adjustFile(index: Int, file: OCFile, shrinkRatio: Float, row: GalleryRow) { - val width = file.imageDimension?.width?.times(shrinkRatio)?.toInt() ?: 0 - val height = file.imageDimension?.height?.times(shrinkRatio)?.toInt() ?: 0 + val aspectRatios = row.files.map { file -> + val (w, h) = OCFileUtils.getImageSize(file, defaultThumbnailSize) + if (w > 0 && h > 0) w.toFloat() / h.toFloat() else 1f + } - val frameLayout = binding.rowLayout[index] as FrameLayout - val shimmer = frameLayout[0] as LoaderImageView - val thumbnail = frameLayout[1] as ImageView - val checkBoxImageView = frameLayout[2] as ImageView + // Start with max height based on largest image + val targetHeight = row.getMaxHeight().coerceAtLeast(1f) - val isChecked = ocFileListDelegate.isCheckedFile(file) + val unscaledWidths = aspectRatios.map { ar -> targetHeight * ar } - adjustRowCell(thumbnail, isChecked) - adjustCheckBox(checkBoxImageView, isChecked) - - ocFileListDelegate.bindGalleryRow( - shimmer, - thumbnail, - file, - this, - width to height - ) - - // Update layout params only if they differ - val thumbLp = thumbnail.layoutParams - if (thumbLp.width != width || thumbLp.height != height) { - thumbnail.layoutParams = thumbLp.getFrameLayout(width, height).apply { - val endMargin = if (index < row.files.size - 1) smallMargin else zero - this.setMargins(zero, zero, endMargin, smallMargin) - } - } + // margins + val totalUnscaled = unscaledWidths.sum() + val totalMargins = marginPx * (row.files.size - 1) + val available = screenWidthPx - totalMargins - val shimmerLp = shimmer.layoutParams - if (shimmerLp.width != width || shimmerLp.height != height) { - shimmer.layoutParams = shimmerLp.getFrameLayout(width, height) - } + // calculate shrink ratio + val shrink = available / totalUnscaled - // Force layout update - frameLayout.requestLayout() - } + // prepare scaled dimensions + val dims = unscaledWidths.map { w -> + val finalW = (w * shrink).toInt() + val finalH = (targetHeight * shrink).toInt() + finalW to finalH + } - private fun ViewGroup.LayoutParams?.getFrameLayout(width: Int, height: Int): FrameLayout.LayoutParams = ( - this as? FrameLayout.LayoutParams - ?: FrameLayout.LayoutParams(width, height) - ).apply { - this.width = width - this.height = height + return dims } @Suppress("MagicNumber") private fun adjustRowCell(imageView: ImageView, isChecked: Boolean) { val scale = if (isChecked) 0.8f else 1.0f val radius = if (isChecked) iconRadius else 0f - - // Only update if values changed - if (imageView.scaleX != scale) { - imageView.scaleX = scale - imageView.scaleY = scale - } - + imageView.scaleX = scale + imageView.scaleY = scale imageView.makeRounded(context, radius) } From f757526aaa1bf79381ac6b732278b40b5143737b Mon Sep 17 00:00:00 2001 From: alperozturk Date: Wed, 10 Dec 2025 14:12:09 +0100 Subject: [PATCH 072/216] fix: gallery image scaling Signed-off-by: alperozturk --- .../java/com/nextcloud/utils/OCFileUtils.kt | 41 +++++++++---------- .../android/ui/adapter/GalleryRowHolder.kt | 7 +--- 2 files changed, 20 insertions(+), 28 deletions(-) diff --git a/app/src/main/java/com/nextcloud/utils/OCFileUtils.kt b/app/src/main/java/com/nextcloud/utils/OCFileUtils.kt index 98160b8af1c9..2ad15a7c5d2b 100644 --- a/app/src/main/java/com/nextcloud/utils/OCFileUtils.kt +++ b/app/src/main/java/com/nextcloud/utils/OCFileUtils.kt @@ -19,6 +19,7 @@ import com.owncloud.android.lib.common.utils.Log_OC import com.owncloud.android.utils.BitmapUtils import com.owncloud.android.utils.MimeTypeUtil +@Suppress("TooGenericExceptionCaught", "ReturnCount") object OCFileUtils { private const val TAG = "OCFileUtils" @@ -40,7 +41,6 @@ object OCFileUtils { // Fallback to local file if it exists val path = ocFile.storagePath if (!path.isNullOrEmpty() && ocFile.exists()) { - // Try EXIF first val exifSize = getExifSize(path) if (exifSize != null) { @@ -59,7 +59,6 @@ object OCFileUtils { // Fallback to defaultThumbnailSize Log_OC.d(TAG, "All sources failed, using default size: $fallback x $fallback") return fallbackPair - } catch (e: Exception) { Log_OC.e(TAG, "Error getting image size for ${ocFile.fileName}", e) } @@ -67,28 +66,26 @@ object OCFileUtils { return fallbackPair } - private fun getExifSize(path: String): Pair? { - return try { - val exif = ExifInterface(path) - var width = exif.getAttributeInt(ExifInterface.TAG_IMAGE_WIDTH, 0) - var height = exif.getAttributeInt(ExifInterface.TAG_IMAGE_LENGTH, 0) - - val orientation = exif.getAttributeInt( - ExifInterface.TAG_ORIENTATION, - ExifInterface.ORIENTATION_NORMAL - ) - if (orientation == ExifInterface.ORIENTATION_ROTATE_90 || - orientation == ExifInterface.ORIENTATION_ROTATE_270 - ) { - val tmp = width - width = height - height = tmp - } + private fun getExifSize(path: String): Pair? = try { + val exif = ExifInterface(path) + var width = exif.getAttributeInt(ExifInterface.TAG_IMAGE_WIDTH, 0) + var height = exif.getAttributeInt(ExifInterface.TAG_IMAGE_LENGTH, 0) - if (width > 0 && height > 0) width to height else null - } catch (_: Exception) { - null + val orientation = exif.getAttributeInt( + ExifInterface.TAG_ORIENTATION, + ExifInterface.ORIENTATION_NORMAL + ) + if (orientation == ExifInterface.ORIENTATION_ROTATE_90 || + orientation == ExifInterface.ORIENTATION_ROTATE_270 + ) { + val tmp = width + width = height + height = tmp } + + if (width > 0 && height > 0) width to height else null + } catch (_: Exception) { + null } private fun getBitmapSize(path: String): Pair? { diff --git a/app/src/main/java/com/owncloud/android/ui/adapter/GalleryRowHolder.kt b/app/src/main/java/com/owncloud/android/ui/adapter/GalleryRowHolder.kt index 84b7a94844f5..aae51085d8ed 100644 --- a/app/src/main/java/com/owncloud/android/ui/adapter/GalleryRowHolder.kt +++ b/app/src/main/java/com/owncloud/android/ui/adapter/GalleryRowHolder.kt @@ -122,12 +122,7 @@ class GalleryRowHolder( } } - private fun adjustFile( - index: Int, - file: OCFile, - dims: Pair, - row: GalleryRow - ) { + private fun adjustFile(index: Int, file: OCFile, dims: Pair, row: GalleryRow) { val (width, height) = dims val frameLayout = binding.rowLayout[index] as FrameLayout From 4650b3f7f731955f386123bc4b2e84c62ff5b597 Mon Sep 17 00:00:00 2001 From: alperozturk Date: Wed, 10 Dec 2025 14:34:14 +0100 Subject: [PATCH 073/216] fix: gallery image scaling Signed-off-by: alperozturk --- .../java/com/nextcloud/utils/OCFileUtils.kt | 58 ++++++------- .../android/ui/adapter/GalleryRowHolder.kt | 83 +++++++++---------- 2 files changed, 62 insertions(+), 79 deletions(-) diff --git a/app/src/main/java/com/nextcloud/utils/OCFileUtils.kt b/app/src/main/java/com/nextcloud/utils/OCFileUtils.kt index 2ad15a7c5d2b..9cfe0f9f9e73 100644 --- a/app/src/main/java/com/nextcloud/utils/OCFileUtils.kt +++ b/app/src/main/java/com/nextcloud/utils/OCFileUtils.kt @@ -30,34 +30,23 @@ object OCFileUtils { try { Log_OC.d(TAG, "Getting image size for: ${ocFile.fileName}") - // Use server-provided imageDimension if available + // Server-provided ocFile.imageDimension?.let { dim -> - val width = dim.width.toInt().coerceAtLeast(1) - val height = dim.height.toInt().coerceAtLeast(1) - Log_OC.d(TAG, "Using server-provided imageDimension: $width x $height") - return width to height + val w = dim.width.toInt().coerceAtLeast(1) + val h = dim.height.toInt().coerceAtLeast(1) + Log_OC.d(TAG, "Using server-provided imageDimension: $w x $h") + return w to h } - // Fallback to local file if it exists + // Local file val path = ocFile.storagePath if (!path.isNullOrEmpty() && ocFile.exists()) { - // Try EXIF first - val exifSize = getExifSize(path) - if (exifSize != null) { - Log_OC.d(TAG, "EXIF size used: ${exifSize.first} x ${exifSize.second}") - return exifSize - } - - // Then try BitmapUtils - val bitmapSize = getBitmapSize(path) - if (bitmapSize != null) { - Log_OC.d(TAG, "BitmapUtils resolution used: ${bitmapSize.first} x ${bitmapSize.second}") - return bitmapSize - } + getExifSize(path)?.let { return it } + getBitmapSize(path)?.let { return it } } - // Fallback to defaultThumbnailSize - Log_OC.d(TAG, "All sources failed, using default size: $fallback x $fallback") + // 3 Fallback + Log_OC.d(TAG, "Fallback to default size: $fallback x $fallback") return fallbackPair } catch (e: Exception) { Log_OC.e(TAG, "Error getting image size for ${ocFile.fileName}", e) @@ -68,8 +57,8 @@ object OCFileUtils { private fun getExifSize(path: String): Pair? = try { val exif = ExifInterface(path) - var width = exif.getAttributeInt(ExifInterface.TAG_IMAGE_WIDTH, 0) - var height = exif.getAttributeInt(ExifInterface.TAG_IMAGE_LENGTH, 0) + var w = exif.getAttributeInt(ExifInterface.TAG_IMAGE_WIDTH, 0) + var h = exif.getAttributeInt(ExifInterface.TAG_IMAGE_LENGTH, 0) val orientation = exif.getAttributeInt( ExifInterface.TAG_ORIENTATION, @@ -78,23 +67,24 @@ object OCFileUtils { if (orientation == ExifInterface.ORIENTATION_ROTATE_90 || orientation == ExifInterface.ORIENTATION_ROTATE_270 ) { - val tmp = width - width = height - height = tmp + val tmp = w + w = h + h = tmp } - if (width > 0 && height > 0) width to height else null + if (w > 0 && h > 0) w to h else null } catch (_: Exception) { null } - private fun getBitmapSize(path: String): Pair? { - return try { - val (w, h) = BitmapUtils.getImageResolution(path).takeIf { it.size == 2 } ?: return null - if (w > 0 && h > 0) w to h else null - } catch (_: Exception) { - null - } + private fun getBitmapSize(path: String): Pair? = try { + val options = android.graphics.BitmapFactory.Options().apply { inJustDecodeBounds = true } + android.graphics.BitmapFactory.decodeFile(path, options) + val w = options.outWidth + val h = options.outHeight + if (w > 0 && h > 0) w to h else null + } catch (_: Exception) { + null } fun getMediaPlaceholder(file: OCFile, imageDimension: Pair): BitmapDrawable { diff --git a/app/src/main/java/com/owncloud/android/ui/adapter/GalleryRowHolder.kt b/app/src/main/java/com/owncloud/android/ui/adapter/GalleryRowHolder.kt index aae51085d8ed..01ed35d40aed 100644 --- a/app/src/main/java/com/owncloud/android/ui/adapter/GalleryRowHolder.kt +++ b/app/src/main/java/com/owncloud/android/ui/adapter/GalleryRowHolder.kt @@ -19,7 +19,6 @@ import com.elyeproj.loaderviewlibrary.LoaderImageView import com.nextcloud.android.common.ui.theme.utils.ColorRole import com.nextcloud.utils.OCFileUtils import com.nextcloud.utils.extensions.makeRounded -import com.nextcloud.utils.extensions.mediaSize import com.nextcloud.utils.extensions.setVisibleIf import com.owncloud.android.R import com.owncloud.android.databinding.GalleryRowBinding @@ -68,7 +67,7 @@ class GalleryRowHolder( // Only rebuild if file count changed if (lastFileCount != requiredCount) { binding.rowLayout.removeAllViews() - for (file in row.files) { + row.files.forEach { file -> binding.rowLayout.addView(getRowLayout(file)) } lastFileCount = requiredCount @@ -81,11 +80,11 @@ class GalleryRowHolder( } } - fun updateRowVisuals() { - bind(currentRow) - } + fun updateRowVisuals() = bind(currentRow) private fun getRowLayout(file: OCFile): FrameLayout { + val (width, height) = OCFileUtils.getImageSize(file, defaultThumbnailSize) + val checkbox = ImageView(context).apply { visibility = View.GONE layoutParams = FrameLayout.LayoutParams( @@ -98,16 +97,13 @@ class GalleryRowHolder( } } - val mediaSize = file.mediaSize(defaultThumbnailSize) - val (width, height) = mediaSize - val shimmer = LoaderImageView(context).apply { setImageResource(R.drawable.background) resetLoader() layoutParams = FrameLayout.LayoutParams(width, height) } - val drawable = OCFileUtils.getMediaPlaceholder(file, mediaSize) + val drawable = OCFileUtils.getMediaPlaceholder(file, width to height) val rowCellImageView = ImageView(context).apply { setImageDrawable(drawable) adjustViewBounds = true @@ -122,63 +118,60 @@ class GalleryRowHolder( } } + private fun getDimensions(row: GalleryRow): List> { + val screenWidthPx = context.resources.displayMetrics.widthPixels.toFloat() + val marginPx = smallMargin.toFloat() + val totalMargins = marginPx * (row.files.size - 1) + val availableWidth = screenWidthPx - totalMargins + + val aspectRatios = row.files.map { file -> + val (w, h) = OCFileUtils.getImageSize(file, defaultThumbnailSize) + if (h > 0) w.toFloat() / h else 1.0f + } + + val sumAspectRatios = aspectRatios.sum() + + // calculate row height based on aspect ratios + val rowHeightFloat = if (sumAspectRatios > 0) availableWidth / sumAspectRatios else defaultThumbnailSize + val finalHeight = rowHeightFloat.toInt() + + // for each aspect ratio calculate widths + val finalWidths = aspectRatios.map { ratio -> (rowHeightFloat * ratio).toInt() }.toMutableList() + val usedWidth = finalWidths.sum() + + // based on screen width get remaining pixels + val remainingPixels = (availableWidth - usedWidth).toInt() + + // add to remaining pixels to last image + if (remainingPixels > 0 && finalWidths.isNotEmpty()) { + val lastIndex = finalWidths.lastIndex + finalWidths[lastIndex] = finalWidths[lastIndex] + remainingPixels + } + + return finalWidths.map { w -> w to finalHeight } + } + private fun adjustFile(index: Int, file: OCFile, dims: Pair, row: GalleryRow) { val (width, height) = dims - val frameLayout = binding.rowLayout[index] as FrameLayout val shimmer = frameLayout[0] as LoaderImageView val thumbnail = frameLayout[1] as ImageView val checkbox = frameLayout[2] as ImageView val isChecked = ocFileListDelegate.isCheckedFile(file) - adjustRowCell(thumbnail, isChecked) adjustCheckBox(checkbox, isChecked) ocFileListDelegate.bindGalleryRow(shimmer, thumbnail, file, this, dims) val endMargin = if (index < row.files.size - 1) smallMargin else zero - thumbnail.layoutParams = FrameLayout.LayoutParams(width, height).apply { setMargins(0, 0, endMargin, smallMargin) } shimmer.layoutParams = FrameLayout.LayoutParams(width, height) - frameLayout.requestLayout() } - private fun getDimensions(row: GalleryRow): List> { - val screenWidthPx = context.resources.displayMetrics.widthPixels.toFloat() - val marginPx = smallMargin.toFloat() - - val aspectRatios = row.files.map { file -> - val (w, h) = OCFileUtils.getImageSize(file, defaultThumbnailSize) - if (w > 0 && h > 0) w.toFloat() / h.toFloat() else 1f - } - - // Start with max height based on largest image - val targetHeight = row.getMaxHeight().coerceAtLeast(1f) - - val unscaledWidths = aspectRatios.map { ar -> targetHeight * ar } - - // margins - val totalUnscaled = unscaledWidths.sum() - val totalMargins = marginPx * (row.files.size - 1) - val available = screenWidthPx - totalMargins - - // calculate shrink ratio - val shrink = available / totalUnscaled - - // prepare scaled dimensions - val dims = unscaledWidths.map { w -> - val finalW = (w * shrink).toInt() - val finalH = (targetHeight * shrink).toInt() - finalW to finalH - } - - return dims - } - @Suppress("MagicNumber") private fun adjustRowCell(imageView: ImageView, isChecked: Boolean) { val scale = if (isChecked) 0.8f else 1.0f From 8dbe020b66641b35d27d76a6abb806c966b4c36a Mon Sep 17 00:00:00 2001 From: alperozturk Date: Wed, 10 Dec 2025 14:34:26 +0100 Subject: [PATCH 074/216] fix: gallery image scaling Signed-off-by: alperozturk --- .../java/com/owncloud/android/ui/adapter/GalleryRowHolder.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/src/main/java/com/owncloud/android/ui/adapter/GalleryRowHolder.kt b/app/src/main/java/com/owncloud/android/ui/adapter/GalleryRowHolder.kt index 01ed35d40aed..da4b72e9a11d 100644 --- a/app/src/main/java/com/owncloud/android/ui/adapter/GalleryRowHolder.kt +++ b/app/src/main/java/com/owncloud/android/ui/adapter/GalleryRowHolder.kt @@ -33,7 +33,7 @@ class GalleryRowHolder( private val defaultThumbnailSize: Float, private val ocFileListDelegate: OCFileListDelegate, val storageManager: FileDataStorageManager, - private val galleryAdapter: GalleryAdapter, + galleryAdapter: GalleryAdapter, private val viewThemeUtils: ViewThemeUtils ) : SectionedViewHolder(binding.root) { val context = galleryAdapter.context From a0b8398b0f70c1ea9acb4a5b988ccee5b98f30ff Mon Sep 17 00:00:00 2001 From: alperozturk Date: Fri, 12 Dec 2025 10:11:57 +0100 Subject: [PATCH 075/216] check nullability of the dim just in case Signed-off-by: alperozturk --- .../java/com/owncloud/android/ui/adapter/GalleryRowHolder.kt | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/app/src/main/java/com/owncloud/android/ui/adapter/GalleryRowHolder.kt b/app/src/main/java/com/owncloud/android/ui/adapter/GalleryRowHolder.kt index da4b72e9a11d..fead84f34822 100644 --- a/app/src/main/java/com/owncloud/android/ui/adapter/GalleryRowHolder.kt +++ b/app/src/main/java/com/owncloud/android/ui/adapter/GalleryRowHolder.kt @@ -76,7 +76,8 @@ class GalleryRowHolder( val dimensions = getDimensions(row) for (i in row.files.indices) { - adjustFile(i, row.files[i], dimensions[i], row) + val dim = dimensions.getOrNull(i) ?: (defaultThumbnailSize.toInt() to defaultThumbnailSize.toInt()) + adjustFile(i, row.files[i], dim, row) } } From 54440ded796dd6c34e114192f0b31fcc49876c70 Mon Sep 17 00:00:00 2001 From: alperozturk Date: Fri, 12 Dec 2025 10:17:39 +0100 Subject: [PATCH 076/216] add logs Signed-off-by: alperozturk --- app/src/main/java/com/nextcloud/utils/OCFileUtils.kt | 3 +++ 1 file changed, 3 insertions(+) diff --git a/app/src/main/java/com/nextcloud/utils/OCFileUtils.kt b/app/src/main/java/com/nextcloud/utils/OCFileUtils.kt index 9cfe0f9f9e73..cdcc3506e018 100644 --- a/app/src/main/java/com/nextcloud/utils/OCFileUtils.kt +++ b/app/src/main/java/com/nextcloud/utils/OCFileUtils.kt @@ -72,6 +72,7 @@ object OCFileUtils { h = tmp } + Log_OC.d(TAG, "Using exif imageDimension: $w x $h") if (w > 0 && h > 0) w to h else null } catch (_: Exception) { null @@ -82,6 +83,8 @@ object OCFileUtils { android.graphics.BitmapFactory.decodeFile(path, options) val w = options.outWidth val h = options.outHeight + + Log_OC.d(TAG, "Using bitmap factory imageDimension: $w x $h") if (w > 0 && h > 0) w to h else null } catch (_: Exception) { null From 5b2a6d9ff3d94dd61890cbf55bbc9ef03151e425 Mon Sep 17 00:00:00 2001 From: alperozturk Date: Mon, 15 Dec 2025 09:17:26 +0100 Subject: [PATCH 077/216] fix: stop running gallery background job when user leave Signed-off-by: alperozturk --- .../jobs/gallery/GalleryImageGenerationJob.kt | 2 ++ .../owncloud/android/ui/adapter/GalleryAdapter.kt | 4 ++++ .../android/ui/adapter/OCFileListDelegate.kt | 13 +++++++++++++ .../android/ui/fragment/GalleryFragment.java | 1 + 4 files changed, 20 insertions(+) diff --git a/app/src/main/java/com/nextcloud/client/jobs/gallery/GalleryImageGenerationJob.kt b/app/src/main/java/com/nextcloud/client/jobs/gallery/GalleryImageGenerationJob.kt index 7138193a430c..e597c62e3a7a 100644 --- a/app/src/main/java/com/nextcloud/client/jobs/gallery/GalleryImageGenerationJob.kt +++ b/app/src/main/java/com/nextcloud/client/jobs/gallery/GalleryImageGenerationJob.kt @@ -40,6 +40,8 @@ class GalleryImageGenerationJob(private val user: User, private val storageManag ) private val activeJobs = WeakHashMap() + fun getActiveJobs(): WeakHashMap = activeJobs + fun removeActiveJob(imageView: ImageView, job: CoroutineScope) { if (isActiveJob(imageView, job)) { removeJob(imageView) diff --git a/app/src/main/java/com/owncloud/android/ui/adapter/GalleryAdapter.kt b/app/src/main/java/com/owncloud/android/ui/adapter/GalleryAdapter.kt index 0c84fe6c84e3..f7f0bc2ef76b 100644 --- a/app/src/main/java/com/owncloud/android/ui/adapter/GalleryAdapter.kt +++ b/app/src/main/java/com/owncloud/android/ui/adapter/GalleryAdapter.kt @@ -372,4 +372,8 @@ class GalleryAdapter( override fun setHighlightedItem(file: OCFile) = Unit override fun setSortOrder(mFile: OCFile, sortOrder: FileSortOrder) = Unit + + fun cleanup() { + ocFileListDelegate.cleanup() + } } diff --git a/app/src/main/java/com/owncloud/android/ui/adapter/OCFileListDelegate.kt b/app/src/main/java/com/owncloud/android/ui/adapter/OCFileListDelegate.kt index 7cc6c4b59e6f..b784a83f478a 100644 --- a/app/src/main/java/com/owncloud/android/ui/adapter/OCFileListDelegate.kt +++ b/app/src/main/java/com/owncloud/android/ui/adapter/OCFileListDelegate.kt @@ -413,6 +413,19 @@ class OCFileListDelegate( fun cleanup() { ioScope.cancel() + + val activeJobs = GalleryImageGenerationJob.getActiveJobs() + + // Cancel all pending thumbnail/generation jobs for gallery images + for ((_, job) in activeJobs) { + job.cancel() + } + activeJobs.clear() + + // cancel async tasks from ThumbnailsCacheManager + cancelAllPendingTasks() + + Log_OC.d(TAG, "background jobs cancelled") } companion object { diff --git a/app/src/main/java/com/owncloud/android/ui/fragment/GalleryFragment.java b/app/src/main/java/com/owncloud/android/ui/fragment/GalleryFragment.java index 094c03da6464..cf1a649c2dc0 100644 --- a/app/src/main/java/com/owncloud/android/ui/fragment/GalleryFragment.java +++ b/app/src/main/java/com/owncloud/android/ui/fragment/GalleryFragment.java @@ -120,6 +120,7 @@ public static void setLastMediaItemPosition(Integer position) { public void onDestroyView() { LocalBroadcastManager.getInstance(requireContext()).unregisterReceiver(refreshSearchEventReceiver); setLastMediaItemPosition(null); + mAdapter.cleanup(); super.onDestroyView(); } From a89eb6a14cd039097e66a3c12a79e4031d78e822 Mon Sep 17 00:00:00 2001 From: alperozturk Date: Wed, 17 Dec 2025 11:30:31 +0100 Subject: [PATCH 078/216] add cancel all function Signed-off-by: alperozturk --- .../client/jobs/gallery/GalleryImageGenerationJob.kt | 7 ++++++- .../com/owncloud/android/ui/adapter/OCFileListDelegate.kt | 8 +------- 2 files changed, 7 insertions(+), 8 deletions(-) diff --git a/app/src/main/java/com/nextcloud/client/jobs/gallery/GalleryImageGenerationJob.kt b/app/src/main/java/com/nextcloud/client/jobs/gallery/GalleryImageGenerationJob.kt index e597c62e3a7a..0e4d2149baa9 100644 --- a/app/src/main/java/com/nextcloud/client/jobs/gallery/GalleryImageGenerationJob.kt +++ b/app/src/main/java/com/nextcloud/client/jobs/gallery/GalleryImageGenerationJob.kt @@ -40,7 +40,12 @@ class GalleryImageGenerationJob(private val user: User, private val storageManag ) private val activeJobs = WeakHashMap() - fun getActiveJobs(): WeakHashMap = activeJobs + fun cancelAllActiveJobs() { + for ((_, job) in activeJobs) { + job.cancel() + } + activeJobs.clear() + } fun removeActiveJob(imageView: ImageView, job: CoroutineScope) { if (isActiveJob(imageView, job)) { diff --git a/app/src/main/java/com/owncloud/android/ui/adapter/OCFileListDelegate.kt b/app/src/main/java/com/owncloud/android/ui/adapter/OCFileListDelegate.kt index b784a83f478a..638faacd7596 100644 --- a/app/src/main/java/com/owncloud/android/ui/adapter/OCFileListDelegate.kt +++ b/app/src/main/java/com/owncloud/android/ui/adapter/OCFileListDelegate.kt @@ -414,13 +414,7 @@ class OCFileListDelegate( fun cleanup() { ioScope.cancel() - val activeJobs = GalleryImageGenerationJob.getActiveJobs() - - // Cancel all pending thumbnail/generation jobs for gallery images - for ((_, job) in activeJobs) { - job.cancel() - } - activeJobs.clear() + GalleryImageGenerationJob.cancelAllActiveJobs() // cancel async tasks from ThumbnailsCacheManager cancelAllPendingTasks() From 9df331ae09cab013ecf673522a8b55a964b865e4 Mon Sep 17 00:00:00 2001 From: alperozturk Date: Wed, 19 Nov 2025 16:05:33 +0100 Subject: [PATCH 079/216] fix(file-sort): concurrent modification exception Signed-off-by: alperozturk --- .../com/nextcloud/utils/FileSortOrderTests.kt | 251 ++++++++++++++++++ .../android/utils/FileSortOrderByDate.kt | 15 +- .../android/utils/FileSortOrderByName.kt | 21 +- .../android/utils/FileSortOrderBySize.kt | 18 +- 4 files changed, 284 insertions(+), 21 deletions(-) create mode 100644 app/src/androidTest/java/com/nextcloud/utils/FileSortOrderTests.kt diff --git a/app/src/androidTest/java/com/nextcloud/utils/FileSortOrderTests.kt b/app/src/androidTest/java/com/nextcloud/utils/FileSortOrderTests.kt new file mode 100644 index 000000000000..b2f41b06fa87 --- /dev/null +++ b/app/src/androidTest/java/com/nextcloud/utils/FileSortOrderTests.kt @@ -0,0 +1,251 @@ +/* + * Nextcloud - Android Client + * + * SPDX-FileCopyrightText: 2025 Alper Ozturk + * SPDX-License-Identifier: AGPL-3.0-or-later + */ +package com.nextcloud.utils + +import com.owncloud.android.datamodel.OCFile +import com.owncloud.android.utils.FileSortOrder.Companion.SORT_A_TO_Z_ID +import com.owncloud.android.utils.FileSortOrder.Companion.SORT_BIG_TO_SMALL_ID +import com.owncloud.android.utils.FileSortOrder.Companion.SORT_NEW_TO_OLD_ID +import com.owncloud.android.utils.FileSortOrder.Companion.SORT_OLD_TO_NEW_ID +import com.owncloud.android.utils.FileSortOrder.Companion.SORT_SMALL_TO_BIG_ID +import com.owncloud.android.utils.FileSortOrder.Companion.SORT_Z_TO_A_ID +import com.owncloud.android.utils.FileSortOrderByDate +import com.owncloud.android.utils.FileSortOrderByName +import com.owncloud.android.utils.FileSortOrderBySize +import org.junit.Assert.assertEquals +import org.junit.Assert.assertTrue +import org.junit.Test +import java.io.File +import java.util.concurrent.Executors +import java.util.concurrent.TimeUnit + +class FileSortOrderTests { + + private fun createTempFile(prefix: String, lastModified: Long? = null, sizeBytes: Int? = null): File { + return File.createTempFile(prefix, ".txt").apply { + lastModified?.let { setLastModified(it) } + sizeBytes?.let { writeBytes(ByteArray(it)) } + } + } + + private fun createTempFolder(prefix: String): File { + return File.createTempFile(prefix, "").apply { + delete() + mkdir() + } + } + + private fun createOCFile(path: String, modTime: Long? = null, size: Long? = null): OCFile { + return OCFile(path).apply { + modTime?.let { modificationTimestamp = it } + size?.let { fileLength = it } + } + } + + private fun testConcurrentModification( + files: MutableList, + sorter: com.owncloud.android.utils.FileSortOrder, + iterations: Int = 50 + ) { + val executor = Executors.newFixedThreadPool(2) + try { + repeat(iterations) { i -> + // modifying and sorting files + executor.submit { sorter.sortLocalFiles(files) } + executor.submit { + files.add(createTempFile("temp$i", lastModified = i.toLong())) + if (files.size > 20) files.removeAt(0) + } + } + } finally { + executor.shutdown() + executor.awaitTermination(5, TimeUnit.SECONDS) + } + assertTrue(true) + } + + @Test + fun testSortLocalFilesAscending() { + val file1 = createTempFile("file1", lastModified = 1000) + val file2 = createTempFile("file2", lastModified = 2000) + val file3 = createTempFile("file3", lastModified = 1500) + + val files = mutableListOf(file1, file2, file3) + val sorter = FileSortOrderByDate(SORT_OLD_TO_NEW_ID, ascending = true) + + val sorted = sorter.sortLocalFiles(files) + + assertEquals(listOf(file1, file3, file2), sorted) + } + + @Test + fun testSortLocalFilesAscendingFalse() { + val file1 = createTempFile("file1", lastModified = 1000) + val file2 = createTempFile("file2", lastModified = 2000) + val file3 = createTempFile("file3", lastModified = 1500) + + val files = mutableListOf(file1, file2, file3) + val sorter = FileSortOrderByDate(SORT_OLD_TO_NEW_ID, ascending = false) + + val sorted = sorter.sortLocalFiles(files) + + assertEquals(listOf(file2, file3, file1), sorted) + } + + @Test + fun testSortLocalFilesDescending() { + val file1 = createTempFile("file1", lastModified = 1000) + val file2 = createTempFile("file2", lastModified = 2000) + val file3 = createTempFile("file3", lastModified = 1500) + + val files = mutableListOf(file1, file2, file3) + val sorter = FileSortOrderByDate(SORT_NEW_TO_OLD_ID, ascending = false) + + val sorted = sorter.sortLocalFiles(files) + + assertEquals(listOf(file2, file3, file1), sorted) + } + + @Test + fun testSortLocalFilesNoConcurrentModification() { + val files = mutableListOf( + createTempFile("file1", lastModified = 1000), + createTempFile("file2", lastModified = 2000), + createTempFile("file3", lastModified = 1500) + ) + val sorter = FileSortOrderByDate(SORT_OLD_TO_NEW_ID, ascending = true) + + testConcurrentModification(files, sorter, iterations = 100) + } + + @Test + fun testSortCloudFilesByDate() { + val f1 = createOCFile("/123.txt", modTime = 1000) + val f2 = createOCFile("/124.txt", modTime = 3000) + val f3 = createOCFile("/125.txt", modTime = 2000) + + val files = mutableListOf(f1, f2, f3) + val sorter = FileSortOrderByDate(SORT_OLD_TO_NEW_ID, ascending = true) + + val sorted = sorter.sortCloudFiles(files, foldersBeforeFiles = false, favoritesFirst = false) + + assertEquals(listOf(f1, f3, f2), sorted) + } + + @Test + fun testSortLocalFilesByNameAscending() { + val folder = createTempFolder("folder") + val file1 = createTempFile("apple") + val file2 = createTempFile("banana") + val file3 = createTempFile("cherry") + + val files = mutableListOf(file3, folder, file1, file2) + val sorter = FileSortOrderByName(SORT_A_TO_Z_ID, ascending = true) + + val sorted = sorter.sortLocalFiles(files) + + assertEquals(listOf(folder, file1, file2, file3), sorted) + } + + @Test + fun testSortLocalFilesByNameDescending() { + val file1 = createTempFile("apple") + val file2 = createTempFile("banana") + val file3 = createTempFile("cherry") + + val files = mutableListOf(file1, file2, file3) + val sorter = FileSortOrderByName(SORT_Z_TO_A_ID, ascending = false) + + val sorted = sorter.sortLocalFiles(files) + + assertEquals(listOf(file3, file2, file1), sorted) + } + + @Test + fun testSortCloudFilesByName() { + val f1 = createOCFile("/b.txt") + val f2 = createOCFile("/a.txt") + val f3 = createOCFile("/c.txt") + + val files = mutableListOf(f1, f2, f3) + val sorter = FileSortOrderByName(SORT_A_TO_Z_ID, ascending = true) + + val sorted = sorter.sortCloudFiles(files, foldersBeforeFiles = false, favoritesFirst = false) + + assertEquals(listOf(f2, f1, f3), sorted) + } + + @Test + fun testSortLocalFilesByNameNoConcurrentModification() { + val files = mutableListOf( + createTempFile("apple"), + createTempFile("banana"), + createTempFile("cherry"), + createTempFolder("folder") + ) + val sorter = FileSortOrderByName(SORT_A_TO_Z_ID, ascending = true) + + testConcurrentModification(files, sorter) + } + + @Test + fun testSortLocalFilesBySizeAscending() { + val file1 = createTempFile("file1", sizeBytes = 100) + val file2 = createTempFile("file2", sizeBytes = 300) + val file3 = createTempFile("file3", sizeBytes = 200) + + val files = mutableListOf(file1, file2, file3) + val sorter = FileSortOrderBySize(SORT_SMALL_TO_BIG_ID, ascending = true) + + val sorted = sorter.sortLocalFiles(files) + + assertEquals(listOf(file1, file3, file2), sorted) + } + + @Test + fun testSortLocalFilesBySizeDescending() { + val file1 = createTempFile("file1", sizeBytes = 100) + val file2 = createTempFile("file2", sizeBytes = 300) + val file3 = createTempFile("file3", sizeBytes = 200) + val folder1 = createTempFolder("folder1") + val folder2 = createTempFolder("folder2") + + val files = mutableListOf(file1, file2, file3, folder1, folder2) + val sorter = FileSortOrderBySize(SORT_BIG_TO_SMALL_ID, ascending = false) + + val sorted = sorter.sortLocalFiles(files) + + assertEquals(listOf(folder1, folder2, file2, file3, file1), sorted) + } + + @Test + fun testSortCloudFilesBySize() { + val f1 = createOCFile("/file1.txt", size = 100) + val f2 = createOCFile("/file2.txt", size = 300) + val f3 = createOCFile("/file3.txt", size = 200) + + val files = mutableListOf(f1, f2, f3) + val sorter = FileSortOrderBySize(SORT_SMALL_TO_BIG_ID, ascending = true) + + val sorted = sorter.sortCloudFiles(files, foldersBeforeFiles = false, favoritesFirst = false) + + assertEquals(listOf(f1, f3, f2), sorted) + } + + @Test + fun testSortLocalFilesBySizeNoConcurrentModification() { + val files = mutableListOf( + createTempFile("file1", sizeBytes = 100), + createTempFile("file2", sizeBytes = 200), + createTempFile("file3", sizeBytes = 300), + createTempFolder("folder") + ) + val sorter = FileSortOrderBySize(SORT_SMALL_TO_BIG_ID, ascending = true) + + testConcurrentModification(files, sorter) + } +} diff --git a/app/src/main/java/com/owncloud/android/utils/FileSortOrderByDate.kt b/app/src/main/java/com/owncloud/android/utils/FileSortOrderByDate.kt index 6d59836a9764..da88a68a81ee 100644 --- a/app/src/main/java/com/owncloud/android/utils/FileSortOrderByDate.kt +++ b/app/src/main/java/com/owncloud/android/utils/FileSortOrderByDate.kt @@ -26,10 +26,11 @@ class FileSortOrderByDate(name: String, ascending: Boolean) : FileSortOrder(name favoritesFirst: Boolean ): MutableList { val multiplier = if (isAscending) 1 else -1 - files.sortWith { o1: OCFile, o2: OCFile -> + val copy = files.toMutableList() + copy.sortWith { o1: OCFile, o2: OCFile -> multiplier * o1.modificationTimestamp.compareTo(o2.modificationTimestamp) } - return super.sortCloudFiles(files, foldersBeforeFiles, favoritesFirst) + return super.sortCloudFiles(copy, foldersBeforeFiles, favoritesFirst) } /** @@ -39,10 +40,11 @@ class FileSortOrderByDate(name: String, ascending: Boolean) : FileSortOrder(name */ override fun sortTrashbinFiles(files: MutableList): List { val multiplier = if (isAscending) 1 else -1 - files.sortWith { o1: TrashbinFile, o2: TrashbinFile -> + val copy = files.toMutableList() + copy.sortWith { o1: TrashbinFile, o2: TrashbinFile -> multiplier * o1.deletionTimestamp.compareTo(o2.deletionTimestamp) } - return super.sortTrashbinFiles(files) + return super.sortTrashbinFiles(copy) } /** @@ -52,9 +54,10 @@ class FileSortOrderByDate(name: String, ascending: Boolean) : FileSortOrder(name */ override fun sortLocalFiles(files: MutableList): List { val multiplier = if (isAscending) 1 else -1 - files.sortWith { o1: File, o2: File -> + val copy = files.toMutableList() + copy.sortWith { o1: File, o2: File -> multiplier * o1.lastModified().compareTo(o2.lastModified()) } - return files + return copy } } diff --git a/app/src/main/java/com/owncloud/android/utils/FileSortOrderByName.kt b/app/src/main/java/com/owncloud/android/utils/FileSortOrderByName.kt index cb39a2a03303..48f4ed3b5f6e 100644 --- a/app/src/main/java/com/owncloud/android/utils/FileSortOrderByName.kt +++ b/app/src/main/java/com/owncloud/android/utils/FileSortOrderByName.kt @@ -29,7 +29,8 @@ class FileSortOrderByName internal constructor(name: String?, ascending: Boolean foldersBeforeFiles: Boolean, favoritesFirst: Boolean ): MutableList { - val sortedByName = sortOnlyByName(files) + val copy = files.toMutableList() + val sortedByName = sortOnlyByName(copy) return super.sortCloudFiles(sortedByName, foldersBeforeFiles, favoritesFirst) } @@ -39,12 +40,14 @@ class FileSortOrderByName internal constructor(name: String?, ascending: Boolean * @param files files to sort */ override fun sortTrashbinFiles(files: MutableList): List { - val sortedByName = sortServerFiles(files) + val copy = files.toMutableList() + val sortedByName = sortServerFiles(copy) return super.sortTrashbinFiles(sortedByName) } private fun sortServerFiles(files: MutableList): MutableList { - files.sortWith { o1: ServerFileInterface, o2: ServerFileInterface -> + val copy = files.toMutableList() + copy.sortWith { o1: ServerFileInterface, o2: ServerFileInterface -> when { o1.isFolder && o2.isFolder -> sortMultiplier * AlphanumComparator.compare(o1, o2) o1.isFolder -> -1 @@ -52,12 +55,13 @@ class FileSortOrderByName internal constructor(name: String?, ascending: Boolean else -> sortMultiplier * AlphanumComparator.compare(o1, o2) } } - return files + return copy } private fun sortOnlyByName(files: MutableList): MutableList { - files.sortWith { o1: OCFile, o2: OCFile -> sortMultiplier * AlphanumComparator.compare(o1, o2) } - return files + val copy = files.toMutableList() + copy.sortWith { o1: OCFile, o2: OCFile -> sortMultiplier * AlphanumComparator.compare(o1, o2) } + return copy } /** @@ -66,7 +70,8 @@ class FileSortOrderByName internal constructor(name: String?, ascending: Boolean * @param files files to sort */ override fun sortLocalFiles(files: MutableList): List { - files.sortWith { o1: File, o2: File -> + val copy = files.toMutableList() + copy.sortWith { o1: File, o2: File -> when { o1.isDirectory && o2.isDirectory -> sortMultiplier * o1.path.lowercase(Locale.getDefault()) .compareTo(o2.path.lowercase(Locale.getDefault())) @@ -78,6 +83,6 @@ class FileSortOrderByName internal constructor(name: String?, ascending: Boolean ) } } - return files + return copy } } diff --git a/app/src/main/java/com/owncloud/android/utils/FileSortOrderBySize.kt b/app/src/main/java/com/owncloud/android/utils/FileSortOrderBySize.kt index 5b188f1c4e86..e4f9e4689e8e 100644 --- a/app/src/main/java/com/owncloud/android/utils/FileSortOrderBySize.kt +++ b/app/src/main/java/com/owncloud/android/utils/FileSortOrderBySize.kt @@ -22,17 +22,20 @@ class FileSortOrderBySize internal constructor(name: String?, ascending: Boolean foldersBeforeFiles: Boolean, favoritesFirst: Boolean ): MutableList { - val sortedBySize = sortServerFiles(files) + val copy = files.toMutableList() + val sortedBySize = sortServerFiles(copy) return super.sortCloudFiles(sortedBySize, foldersBeforeFiles, favoritesFirst) } override fun sortTrashbinFiles(files: MutableList): List { - val sortedBySize = sortServerFiles(files) + val copy = files.toMutableList() + val sortedBySize = sortServerFiles(copy) return super.sortTrashbinFiles(sortedBySize) } private fun sortServerFiles(files: MutableList): MutableList { - files.sortWith { o1: ServerFileInterface, o2: ServerFileInterface -> + val copy = files.toMutableList() + copy.sortWith { o1: ServerFileInterface, o2: ServerFileInterface -> when { o1.isFolder && o2.isFolder -> sortMultiplier * o1.fileLength.compareTo(o2.fileLength) o1.isFolder -> -1 @@ -40,14 +43,15 @@ class FileSortOrderBySize internal constructor(name: String?, ascending: Boolean else -> sortMultiplier * o1.fileLength.compareTo(o2.fileLength) } } - return files + return copy } override fun sortLocalFiles(files: MutableList): List { + val copy = files.toMutableList() val folderSizes = - files.associateWith { file -> FileStorageUtils.getFolderSize(file) } + copy.associateWith { file -> FileStorageUtils.getFolderSize(file) } - files.sortWith { o1: File, o2: File -> + copy.sortWith { o1: File, o2: File -> when { o1.isDirectory && o2.isDirectory -> sortMultiplier * (folderSizes[o1] ?: 0L).compareTo( folderSizes[o2] ?: 0L @@ -57,6 +61,6 @@ class FileSortOrderBySize internal constructor(name: String?, ascending: Boolean else -> sortMultiplier * o1.length().compareTo(o2.length()) } } - return files + return copy } } From 45c19859751b790577e96cf771ff333cf06368e5 Mon Sep 17 00:00:00 2001 From: alperozturk Date: Thu, 20 Nov 2025 08:45:55 +0100 Subject: [PATCH 080/216] fix(file-sort): concurrent modification exception Signed-off-by: alperozturk --- .../com/nextcloud/utils/FileSortOrderTests.kt | 369 ++++++++++-------- 1 file changed, 199 insertions(+), 170 deletions(-) diff --git a/app/src/androidTest/java/com/nextcloud/utils/FileSortOrderTests.kt b/app/src/androidTest/java/com/nextcloud/utils/FileSortOrderTests.kt index b2f41b06fa87..3940e70a4269 100644 --- a/app/src/androidTest/java/com/nextcloud/utils/FileSortOrderTests.kt +++ b/app/src/androidTest/java/com/nextcloud/utils/FileSortOrderTests.kt @@ -7,245 +7,274 @@ package com.nextcloud.utils import com.owncloud.android.datamodel.OCFile +import com.owncloud.android.utils.FileSortOrder import com.owncloud.android.utils.FileSortOrder.Companion.SORT_A_TO_Z_ID import com.owncloud.android.utils.FileSortOrder.Companion.SORT_BIG_TO_SMALL_ID import com.owncloud.android.utils.FileSortOrder.Companion.SORT_NEW_TO_OLD_ID import com.owncloud.android.utils.FileSortOrder.Companion.SORT_OLD_TO_NEW_ID import com.owncloud.android.utils.FileSortOrder.Companion.SORT_SMALL_TO_BIG_ID -import com.owncloud.android.utils.FileSortOrder.Companion.SORT_Z_TO_A_ID import com.owncloud.android.utils.FileSortOrderByDate import com.owncloud.android.utils.FileSortOrderByName import com.owncloud.android.utils.FileSortOrderBySize import org.junit.Assert.assertEquals -import org.junit.Assert.assertTrue import org.junit.Test import java.io.File -import java.util.concurrent.Executors +import java.util.concurrent.CountDownLatch import java.util.concurrent.TimeUnit +import kotlin.concurrent.thread class FileSortOrderTests { - private fun createTempFile(prefix: String, lastModified: Long? = null, sizeBytes: Int? = null): File { - return File.createTempFile(prefix, ".txt").apply { + private fun tmpFile(prefix: String, lastModified: Long? = null, size: Int? = null): File = + File.createTempFile(prefix, ".txt").apply { lastModified?.let { setLastModified(it) } - sizeBytes?.let { writeBytes(ByteArray(it)) } + size?.let { writeBytes(ByteArray(it)) } } - } - private fun createTempFolder(prefix: String): File { - return File.createTempFile(prefix, "").apply { - delete() - mkdir() - } + private fun tmpFolder(prefix: String): File = File.createTempFile(prefix, "").apply { + delete() + mkdir() } - private fun createOCFile(path: String, modTime: Long? = null, size: Long? = null): OCFile { - return OCFile(path).apply { - modTime?.let { modificationTimestamp = it } - size?.let { fileLength = it } - } + private fun ocFile(path: String, mod: Long? = null, size: Long? = null) = OCFile(path).apply { + mod?.let { modificationTimestamp = it } + size?.let { fileLength = it } } - private fun testConcurrentModification( - files: MutableList, - sorter: com.owncloud.android.utils.FileSortOrder, - iterations: Int = 50 + private fun runSortTest( + name: String, + items: MutableList, + sorter: FileSortOrder, + expected: List, + isCloud: Boolean = false ) { - val executor = Executors.newFixedThreadPool(2) - try { - repeat(iterations) { i -> - // modifying and sorting files - executor.submit { sorter.sortLocalFiles(files) } - executor.submit { - files.add(createTempFile("temp$i", lastModified = i.toLong())) - if (files.size > 20) files.removeAt(0) - } - } - } finally { - executor.shutdown() - executor.awaitTermination(5, TimeUnit.SECONDS) + val actual = if (isCloud) { + sorter.sortCloudFiles(items as MutableList, false, false) + } else { + sorter.sortLocalFiles(items as MutableList) } - assertTrue(true) - } - @Test - fun testSortLocalFilesAscending() { - val file1 = createTempFile("file1", lastModified = 1000) - val file2 = createTempFile("file2", lastModified = 2000) - val file3 = createTempFile("file3", lastModified = 1500) - - val files = mutableListOf(file1, file2, file3) - val sorter = FileSortOrderByDate(SORT_OLD_TO_NEW_ID, ascending = true) - - val sorted = sorter.sortLocalFiles(files) - - assertEquals(listOf(file1, file3, file2), sorted) + assertEquals(name, expected, actual) } - @Test - fun testSortLocalFilesAscendingFalse() { - val file1 = createTempFile("file1", lastModified = 1000) - val file2 = createTempFile("file2", lastModified = 2000) - val file3 = createTempFile("file3", lastModified = 1500) - - val files = mutableListOf(file1, file2, file3) - val sorter = FileSortOrderByDate(SORT_OLD_TO_NEW_ID, ascending = false) - - val sorted = sorter.sortLocalFiles(files) - - assertEquals(listOf(file2, file3, file1), sorted) - } + private fun testConcurrency(files: MutableList, sorter: FileSortOrder, iterations: Int = 50) { + val latch = CountDownLatch(iterations * 2) + val errors = mutableListOf() + + repeat(iterations) { i -> + thread { + try { + sorter.sortLocalFiles(files) + } catch (e: Throwable) { + errors.add(e) + } finally { + latch.countDown() + } + } - @Test - fun testSortLocalFilesDescending() { - val file1 = createTempFile("file1", lastModified = 1000) - val file2 = createTempFile("file2", lastModified = 2000) - val file3 = createTempFile("file3", lastModified = 1500) + thread { + try { + files.add(tmpFile("tmp$i", lastModified = i.toLong())) + if (files.size > 20) files.removeAt(0) + } catch (e: Throwable) { + errors.add(e) + } finally { + latch.countDown() + } + } + } - val files = mutableListOf(file1, file2, file3) - val sorter = FileSortOrderByDate(SORT_NEW_TO_OLD_ID, ascending = false) + // Wait for threads to finish + val completed = latch.await(5, TimeUnit.SECONDS) - val sorted = sorter.sortLocalFiles(files) + if (errors.isNotEmpty()) { + throw AssertionError("Exceptions occurred in background threads: ${errors.first()}", errors.first()) + } - assertEquals(listOf(file2, file3, file1), sorted) + if (!completed) { + throw AssertionError("Concurrent test timed out") + } } @Test - fun testSortLocalFilesNoConcurrentModification() { - val files = mutableListOf( - createTempFile("file1", lastModified = 1000), - createTempFile("file2", lastModified = 2000), - createTempFile("file3", lastModified = 1500) + fun sortDateOldToNew() { + val file1 = tmpFile("file1", 1000) + val file2 = tmpFile("file2", 2000) + val file3 = tmpFile("file3", 1500) + + runSortTest( + "old→new asc", + mutableListOf(file1, file2, file3), + FileSortOrderByDate(SORT_OLD_TO_NEW_ID, true), + listOf(file1, file3, file2) ) - val sorter = FileSortOrderByDate(SORT_OLD_TO_NEW_ID, ascending = true) - testConcurrentModification(files, sorter, iterations = 100) + runSortTest( + "old→new desc", + mutableListOf(file1, file2, file3), + FileSortOrderByDate(SORT_OLD_TO_NEW_ID, false), + listOf(file2, file3, file1) + ) } @Test - fun testSortCloudFilesByDate() { - val f1 = createOCFile("/123.txt", modTime = 1000) - val f2 = createOCFile("/124.txt", modTime = 3000) - val f3 = createOCFile("/125.txt", modTime = 2000) - - val files = mutableListOf(f1, f2, f3) - val sorter = FileSortOrderByDate(SORT_OLD_TO_NEW_ID, ascending = true) - - val sorted = sorter.sortCloudFiles(files, foldersBeforeFiles = false, favoritesFirst = false) + fun sortDateNewToOld() { + val file1 = tmpFile("file1", 1000) + val file2 = tmpFile("file2", 2000) + val file3 = tmpFile("file3", 1500) + + runSortTest( + "new→old asc", + mutableListOf(file1, file2, file3), + FileSortOrderByDate(SORT_NEW_TO_OLD_ID, true), + listOf(file1, file3, file2) + ) - assertEquals(listOf(f1, f3, f2), sorted) + runSortTest( + "new→old desc", + mutableListOf(file1, file2, file3), + FileSortOrderByDate(SORT_NEW_TO_OLD_ID, false), + listOf(file2, file3, file1) + ) } @Test - fun testSortLocalFilesByNameAscending() { - val folder = createTempFolder("folder") - val file1 = createTempFile("apple") - val file2 = createTempFile("banana") - val file3 = createTempFile("cherry") - - val files = mutableListOf(file3, folder, file1, file2) - val sorter = FileSortOrderByName(SORT_A_TO_Z_ID, ascending = true) - - val sorted = sorter.sortLocalFiles(files) - - assertEquals(listOf(folder, file1, file2, file3), sorted) + fun sortDateCloud() { + val file1 = ocFile("/1", mod = 1000) + val file2 = ocFile("/2", mod = 3000) + val file3 = ocFile("/3", mod = 2000) + + runSortTest( + "cloud old→new asc", + mutableListOf(file1, file2, file3), + FileSortOrderByDate(SORT_OLD_TO_NEW_ID, true), + listOf(file1, file3, file2), + isCloud = true + ) } @Test - fun testSortLocalFilesByNameDescending() { - val file1 = createTempFile("apple") - val file2 = createTempFile("banana") - val file3 = createTempFile("cherry") - - val files = mutableListOf(file1, file2, file3) - val sorter = FileSortOrderByName(SORT_Z_TO_A_ID, ascending = false) - - val sorted = sorter.sortLocalFiles(files) - - assertEquals(listOf(file3, file2, file1), sorted) + fun sortDateConcurrency() { + val items = mutableListOf( + tmpFile("file1", 1000), + tmpFile("file2", 2000), + tmpFile("file3", 1500) + ) + testConcurrency(items, FileSortOrderByDate(SORT_OLD_TO_NEW_ID, true)) } @Test - fun testSortCloudFilesByName() { - val f1 = createOCFile("/b.txt") - val f2 = createOCFile("/a.txt") - val f3 = createOCFile("/c.txt") - - val files = mutableListOf(f1, f2, f3) - val sorter = FileSortOrderByName(SORT_A_TO_Z_ID, ascending = true) - - val sorted = sorter.sortCloudFiles(files, foldersBeforeFiles = false, favoritesFirst = false) + fun sortNameLocal() { + val folder = tmpFolder("folder") + val file1 = tmpFile("apple") + val file2 = tmpFile("banana") + val file3 = tmpFile("cherry") + + runSortTest( + "A→Z asc", + mutableListOf(file3, folder, file1, file2), + FileSortOrderByName(SORT_A_TO_Z_ID, true), + listOf(folder, file1, file2, file3) + ) - assertEquals(listOf(f2, f1, f3), sorted) + runSortTest( + "A→Z desc", + mutableListOf(file3, folder, file1, file2), + FileSortOrderByName(SORT_A_TO_Z_ID, false), + listOf(folder, file3, file2, file1) + ) } @Test - fun testSortLocalFilesByNameNoConcurrentModification() { - val files = mutableListOf( - createTempFile("apple"), - createTempFile("banana"), - createTempFile("cherry"), - createTempFolder("folder") + fun sortNameCloud() { + val file1 = ocFile("/b.txt") + val file2 = ocFile("/a.txt") + val file3 = ocFile("/c.txt") + + runSortTest( + "cloud A→Z asc", + mutableListOf(file1, file2, file3), + FileSortOrderByName(SORT_A_TO_Z_ID, true), + listOf(file2, file1, file3), + isCloud = true ) - val sorter = FileSortOrderByName(SORT_A_TO_Z_ID, ascending = true) - - testConcurrentModification(files, sorter) } @Test - fun testSortLocalFilesBySizeAscending() { - val file1 = createTempFile("file1", sizeBytes = 100) - val file2 = createTempFile("file2", sizeBytes = 300) - val file3 = createTempFile("file3", sizeBytes = 200) - - val files = mutableListOf(file1, file2, file3) - val sorter = FileSortOrderBySize(SORT_SMALL_TO_BIG_ID, ascending = true) - - val sorted = sorter.sortLocalFiles(files) - - assertEquals(listOf(file1, file3, file2), sorted) + fun sortNameConcurrency() { + testConcurrency( + mutableListOf( + tmpFile("apple"), + tmpFile("banana"), + tmpFile("cherry"), + tmpFolder("folder") + ), + FileSortOrderByName(SORT_A_TO_Z_ID, true) + ) } @Test - fun testSortLocalFilesBySizeDescending() { - val file1 = createTempFile("file1", sizeBytes = 100) - val file2 = createTempFile("file2", sizeBytes = 300) - val file3 = createTempFile("file3", sizeBytes = 200) - val folder1 = createTempFolder("folder1") - val folder2 = createTempFolder("folder2") + fun sortSizeLocal() { + val file1 = tmpFile("file1", size = 100) + val file2 = tmpFile("file2", size = 300) + val file3 = tmpFile("file3", size = 200) + val d1 = tmpFolder("folder1") + val d2 = tmpFolder("folder2") + + runSortTest( + "small→big asc", + mutableListOf(file1, file2, file3), + FileSortOrderBySize(SORT_SMALL_TO_BIG_ID, true), + listOf(file1, file3, file2) + ) - val files = mutableListOf(file1, file2, file3, folder1, folder2) - val sorter = FileSortOrderBySize(SORT_BIG_TO_SMALL_ID, ascending = false) + runSortTest( + "small→big desc", + mutableListOf(file1, file2, file3), + FileSortOrderBySize(SORT_SMALL_TO_BIG_ID, false), + listOf(file2, file3, file1) + ) - val sorted = sorter.sortLocalFiles(files) + runSortTest( + "big→small asc (folders first)", + mutableListOf(file1, file2, file3, d1, d2), + FileSortOrderBySize(SORT_BIG_TO_SMALL_ID, true), + listOf(d1, d2, file1, file3, file2) + ) - assertEquals(listOf(folder1, folder2, file2, file3, file1), sorted) + runSortTest( + "big→small desc (folders first)", + mutableListOf(file1, file2, file3, d1, d2), + FileSortOrderBySize(SORT_BIG_TO_SMALL_ID, false), + listOf(d1, d2, file2, file3, file1) + ) } @Test - fun testSortCloudFilesBySize() { - val f1 = createOCFile("/file1.txt", size = 100) - val f2 = createOCFile("/file2.txt", size = 300) - val f3 = createOCFile("/file3.txt", size = 200) - - val files = mutableListOf(f1, f2, f3) - val sorter = FileSortOrderBySize(SORT_SMALL_TO_BIG_ID, ascending = true) - - val sorted = sorter.sortCloudFiles(files, foldersBeforeFiles = false, favoritesFirst = false) - - assertEquals(listOf(f1, f3, f2), sorted) + fun sortSizeCloud() { + val file1 = ocFile("/1", size = 100) + val file2 = ocFile("/2", size = 300) + val file3 = ocFile("/3", size = 200) + + runSortTest( + "cloud small→big asc", + mutableListOf(file1, file2, file3), + FileSortOrderBySize(SORT_SMALL_TO_BIG_ID, true), + listOf(file1, file3, file2), + isCloud = true + ) } @Test - fun testSortLocalFilesBySizeNoConcurrentModification() { - val files = mutableListOf( - createTempFile("file1", sizeBytes = 100), - createTempFile("file2", sizeBytes = 200), - createTempFile("file3", sizeBytes = 300), - createTempFolder("folder") + fun sortSizeConcurrency() { + testConcurrency( + mutableListOf( + tmpFile("file1", size = 100), + tmpFile("file2", size = 200), + tmpFile("file3", size = 300), + tmpFolder("folder") + ), + FileSortOrderBySize(SORT_SMALL_TO_BIG_ID, true) ) - val sorter = FileSortOrderBySize(SORT_SMALL_TO_BIG_ID, ascending = true) - - testConcurrentModification(files, sorter) } } From 84a05cee26fd83b831c76a848e8a898cc36083c8 Mon Sep 17 00:00:00 2001 From: alperozturk Date: Thu, 20 Nov 2025 08:55:07 +0100 Subject: [PATCH 081/216] fix(file-sort): concurrent modification exception Signed-off-by: alperozturk --- .../androidTest/java/com/nextcloud/utils/FileSortOrderTests.kt | 2 ++ 1 file changed, 2 insertions(+) diff --git a/app/src/androidTest/java/com/nextcloud/utils/FileSortOrderTests.kt b/app/src/androidTest/java/com/nextcloud/utils/FileSortOrderTests.kt index 3940e70a4269..0514c2fcfed4 100644 --- a/app/src/androidTest/java/com/nextcloud/utils/FileSortOrderTests.kt +++ b/app/src/androidTest/java/com/nextcloud/utils/FileSortOrderTests.kt @@ -23,6 +23,7 @@ import java.util.concurrent.CountDownLatch import java.util.concurrent.TimeUnit import kotlin.concurrent.thread +@Suppress("MagicNumber", "TooManyFunctions") class FileSortOrderTests { private fun tmpFile(prefix: String, lastModified: Long? = null, size: Int? = null): File = @@ -57,6 +58,7 @@ class FileSortOrderTests { assertEquals(name, expected, actual) } + @Suppress("TooGenericExceptionCaught") private fun testConcurrency(files: MutableList, sorter: FileSortOrder, iterations: Int = 50) { val latch = CountDownLatch(iterations * 2) val errors = mutableListOf() From c2be547cccbe2b12e596cff5db1303cfe94ec8e4 Mon Sep 17 00:00:00 2001 From: alperozturk Date: Thu, 20 Nov 2025 08:58:33 +0100 Subject: [PATCH 082/216] fix(file-sort): concurrent modification exception Signed-off-by: alperozturk --- .../com/nextcloud/utils/FileSortOrderTests.kt | 55 ++++++++++--------- 1 file changed, 28 insertions(+), 27 deletions(-) diff --git a/app/src/androidTest/java/com/nextcloud/utils/FileSortOrderTests.kt b/app/src/androidTest/java/com/nextcloud/utils/FileSortOrderTests.kt index 0514c2fcfed4..c2a7e54c2d5a 100644 --- a/app/src/androidTest/java/com/nextcloud/utils/FileSortOrderTests.kt +++ b/app/src/androidTest/java/com/nextcloud/utils/FileSortOrderTests.kt @@ -42,19 +42,23 @@ class FileSortOrderTests { size?.let { fileLength = it } } - private fun runSortTest( + private fun runSortFiles( name: String, - items: MutableList, + items: MutableList, sorter: FileSortOrder, - expected: List, - isCloud: Boolean = false + expected: List ) { - val actual = if (isCloud) { - sorter.sortCloudFiles(items as MutableList, false, false) - } else { - sorter.sortLocalFiles(items as MutableList) - } + val actual = sorter.sortLocalFiles(items) + assertEquals(name, expected, actual) + } + private fun runSortCloudFiles( + name: String, + items: MutableList, + sorter: FileSortOrder, + expected: List + ) { + val actual = sorter.sortCloudFiles(items, foldersBeforeFiles = false, favoritesFirst = false) assertEquals(name, expected, actual) } @@ -104,14 +108,14 @@ class FileSortOrderTests { val file2 = tmpFile("file2", 2000) val file3 = tmpFile("file3", 1500) - runSortTest( + runSortFiles( "old→new asc", mutableListOf(file1, file2, file3), FileSortOrderByDate(SORT_OLD_TO_NEW_ID, true), listOf(file1, file3, file2) ) - runSortTest( + runSortFiles( "old→new desc", mutableListOf(file1, file2, file3), FileSortOrderByDate(SORT_OLD_TO_NEW_ID, false), @@ -125,14 +129,14 @@ class FileSortOrderTests { val file2 = tmpFile("file2", 2000) val file3 = tmpFile("file3", 1500) - runSortTest( + runSortFiles( "new→old asc", mutableListOf(file1, file2, file3), FileSortOrderByDate(SORT_NEW_TO_OLD_ID, true), listOf(file1, file3, file2) ) - runSortTest( + runSortFiles( "new→old desc", mutableListOf(file1, file2, file3), FileSortOrderByDate(SORT_NEW_TO_OLD_ID, false), @@ -146,12 +150,11 @@ class FileSortOrderTests { val file2 = ocFile("/2", mod = 3000) val file3 = ocFile("/3", mod = 2000) - runSortTest( + runSortCloudFiles( "cloud old→new asc", mutableListOf(file1, file2, file3), FileSortOrderByDate(SORT_OLD_TO_NEW_ID, true), listOf(file1, file3, file2), - isCloud = true ) } @@ -172,14 +175,14 @@ class FileSortOrderTests { val file2 = tmpFile("banana") val file3 = tmpFile("cherry") - runSortTest( + runSortFiles( "A→Z asc", mutableListOf(file3, folder, file1, file2), FileSortOrderByName(SORT_A_TO_Z_ID, true), listOf(folder, file1, file2, file3) ) - runSortTest( + runSortFiles( "A→Z desc", mutableListOf(file3, folder, file1, file2), FileSortOrderByName(SORT_A_TO_Z_ID, false), @@ -193,12 +196,11 @@ class FileSortOrderTests { val file2 = ocFile("/a.txt") val file3 = ocFile("/c.txt") - runSortTest( + runSortCloudFiles( "cloud A→Z asc", mutableListOf(file1, file2, file3), FileSortOrderByName(SORT_A_TO_Z_ID, true), - listOf(file2, file1, file3), - isCloud = true + listOf(file2, file1, file3) ) } @@ -223,28 +225,28 @@ class FileSortOrderTests { val d1 = tmpFolder("folder1") val d2 = tmpFolder("folder2") - runSortTest( + runSortFiles( "small→big asc", mutableListOf(file1, file2, file3), FileSortOrderBySize(SORT_SMALL_TO_BIG_ID, true), listOf(file1, file3, file2) ) - runSortTest( + runSortFiles( "small→big desc", mutableListOf(file1, file2, file3), FileSortOrderBySize(SORT_SMALL_TO_BIG_ID, false), listOf(file2, file3, file1) ) - runSortTest( + runSortFiles( "big→small asc (folders first)", mutableListOf(file1, file2, file3, d1, d2), FileSortOrderBySize(SORT_BIG_TO_SMALL_ID, true), listOf(d1, d2, file1, file3, file2) ) - runSortTest( + runSortFiles( "big→small desc (folders first)", mutableListOf(file1, file2, file3, d1, d2), FileSortOrderBySize(SORT_BIG_TO_SMALL_ID, false), @@ -258,12 +260,11 @@ class FileSortOrderTests { val file2 = ocFile("/2", size = 300) val file3 = ocFile("/3", size = 200) - runSortTest( + runSortCloudFiles( "cloud small→big asc", mutableListOf(file1, file2, file3), FileSortOrderBySize(SORT_SMALL_TO_BIG_ID, true), - listOf(file1, file3, file2), - isCloud = true + listOf(file1, file3, file2) ) } From 978d68b5e7e85d39aa7ef46318cae3f189b9014f Mon Sep 17 00:00:00 2001 From: alperozturk Date: Tue, 25 Nov 2025 08:18:41 +0100 Subject: [PATCH 083/216] fix codacy Signed-off-by: alperozturk --- .../java/com/nextcloud/utils/FileSortOrderTests.kt | 9 ++------- 1 file changed, 2 insertions(+), 7 deletions(-) diff --git a/app/src/androidTest/java/com/nextcloud/utils/FileSortOrderTests.kt b/app/src/androidTest/java/com/nextcloud/utils/FileSortOrderTests.kt index c2a7e54c2d5a..0ba6eaa98647 100644 --- a/app/src/androidTest/java/com/nextcloud/utils/FileSortOrderTests.kt +++ b/app/src/androidTest/java/com/nextcloud/utils/FileSortOrderTests.kt @@ -42,12 +42,7 @@ class FileSortOrderTests { size?.let { fileLength = it } } - private fun runSortFiles( - name: String, - items: MutableList, - sorter: FileSortOrder, - expected: List - ) { + private fun runSortFiles(name: String, items: MutableList, sorter: FileSortOrder, expected: List) { val actual = sorter.sortLocalFiles(items) assertEquals(name, expected, actual) } @@ -154,7 +149,7 @@ class FileSortOrderTests { "cloud old→new asc", mutableListOf(file1, file2, file3), FileSortOrderByDate(SORT_OLD_TO_NEW_ID, true), - listOf(file1, file3, file2), + listOf(file1, file3, file2) ) } From 16d159853b802fbf97f002bd637bde3a383f9dd7 Mon Sep 17 00:00:00 2001 From: alperozturk Date: Wed, 26 Nov 2025 09:24:04 +0100 Subject: [PATCH 084/216] dont change sorting logic Signed-off-by: alperozturk # Conflicts: # app/src/main/java/com/owncloud/android/ui/fragment/LocalFileListFragment.java --- .../com/nextcloud/utils/FileSortOrderTests.kt | 278 ------------------ .../ui/adapter/LocalFileListAdapter.java | 28 +- .../android/utils/FileSortOrderByDate.kt | 15 +- .../android/utils/FileSortOrderByName.kt | 21 +- .../android/utils/FileSortOrderBySize.kt | 18 +- 5 files changed, 43 insertions(+), 317 deletions(-) delete mode 100644 app/src/androidTest/java/com/nextcloud/utils/FileSortOrderTests.kt diff --git a/app/src/androidTest/java/com/nextcloud/utils/FileSortOrderTests.kt b/app/src/androidTest/java/com/nextcloud/utils/FileSortOrderTests.kt deleted file mode 100644 index 0ba6eaa98647..000000000000 --- a/app/src/androidTest/java/com/nextcloud/utils/FileSortOrderTests.kt +++ /dev/null @@ -1,278 +0,0 @@ -/* - * Nextcloud - Android Client - * - * SPDX-FileCopyrightText: 2025 Alper Ozturk - * SPDX-License-Identifier: AGPL-3.0-or-later - */ -package com.nextcloud.utils - -import com.owncloud.android.datamodel.OCFile -import com.owncloud.android.utils.FileSortOrder -import com.owncloud.android.utils.FileSortOrder.Companion.SORT_A_TO_Z_ID -import com.owncloud.android.utils.FileSortOrder.Companion.SORT_BIG_TO_SMALL_ID -import com.owncloud.android.utils.FileSortOrder.Companion.SORT_NEW_TO_OLD_ID -import com.owncloud.android.utils.FileSortOrder.Companion.SORT_OLD_TO_NEW_ID -import com.owncloud.android.utils.FileSortOrder.Companion.SORT_SMALL_TO_BIG_ID -import com.owncloud.android.utils.FileSortOrderByDate -import com.owncloud.android.utils.FileSortOrderByName -import com.owncloud.android.utils.FileSortOrderBySize -import org.junit.Assert.assertEquals -import org.junit.Test -import java.io.File -import java.util.concurrent.CountDownLatch -import java.util.concurrent.TimeUnit -import kotlin.concurrent.thread - -@Suppress("MagicNumber", "TooManyFunctions") -class FileSortOrderTests { - - private fun tmpFile(prefix: String, lastModified: Long? = null, size: Int? = null): File = - File.createTempFile(prefix, ".txt").apply { - lastModified?.let { setLastModified(it) } - size?.let { writeBytes(ByteArray(it)) } - } - - private fun tmpFolder(prefix: String): File = File.createTempFile(prefix, "").apply { - delete() - mkdir() - } - - private fun ocFile(path: String, mod: Long? = null, size: Long? = null) = OCFile(path).apply { - mod?.let { modificationTimestamp = it } - size?.let { fileLength = it } - } - - private fun runSortFiles(name: String, items: MutableList, sorter: FileSortOrder, expected: List) { - val actual = sorter.sortLocalFiles(items) - assertEquals(name, expected, actual) - } - - private fun runSortCloudFiles( - name: String, - items: MutableList, - sorter: FileSortOrder, - expected: List - ) { - val actual = sorter.sortCloudFiles(items, foldersBeforeFiles = false, favoritesFirst = false) - assertEquals(name, expected, actual) - } - - @Suppress("TooGenericExceptionCaught") - private fun testConcurrency(files: MutableList, sorter: FileSortOrder, iterations: Int = 50) { - val latch = CountDownLatch(iterations * 2) - val errors = mutableListOf() - - repeat(iterations) { i -> - thread { - try { - sorter.sortLocalFiles(files) - } catch (e: Throwable) { - errors.add(e) - } finally { - latch.countDown() - } - } - - thread { - try { - files.add(tmpFile("tmp$i", lastModified = i.toLong())) - if (files.size > 20) files.removeAt(0) - } catch (e: Throwable) { - errors.add(e) - } finally { - latch.countDown() - } - } - } - - // Wait for threads to finish - val completed = latch.await(5, TimeUnit.SECONDS) - - if (errors.isNotEmpty()) { - throw AssertionError("Exceptions occurred in background threads: ${errors.first()}", errors.first()) - } - - if (!completed) { - throw AssertionError("Concurrent test timed out") - } - } - - @Test - fun sortDateOldToNew() { - val file1 = tmpFile("file1", 1000) - val file2 = tmpFile("file2", 2000) - val file3 = tmpFile("file3", 1500) - - runSortFiles( - "old→new asc", - mutableListOf(file1, file2, file3), - FileSortOrderByDate(SORT_OLD_TO_NEW_ID, true), - listOf(file1, file3, file2) - ) - - runSortFiles( - "old→new desc", - mutableListOf(file1, file2, file3), - FileSortOrderByDate(SORT_OLD_TO_NEW_ID, false), - listOf(file2, file3, file1) - ) - } - - @Test - fun sortDateNewToOld() { - val file1 = tmpFile("file1", 1000) - val file2 = tmpFile("file2", 2000) - val file3 = tmpFile("file3", 1500) - - runSortFiles( - "new→old asc", - mutableListOf(file1, file2, file3), - FileSortOrderByDate(SORT_NEW_TO_OLD_ID, true), - listOf(file1, file3, file2) - ) - - runSortFiles( - "new→old desc", - mutableListOf(file1, file2, file3), - FileSortOrderByDate(SORT_NEW_TO_OLD_ID, false), - listOf(file2, file3, file1) - ) - } - - @Test - fun sortDateCloud() { - val file1 = ocFile("/1", mod = 1000) - val file2 = ocFile("/2", mod = 3000) - val file3 = ocFile("/3", mod = 2000) - - runSortCloudFiles( - "cloud old→new asc", - mutableListOf(file1, file2, file3), - FileSortOrderByDate(SORT_OLD_TO_NEW_ID, true), - listOf(file1, file3, file2) - ) - } - - @Test - fun sortDateConcurrency() { - val items = mutableListOf( - tmpFile("file1", 1000), - tmpFile("file2", 2000), - tmpFile("file3", 1500) - ) - testConcurrency(items, FileSortOrderByDate(SORT_OLD_TO_NEW_ID, true)) - } - - @Test - fun sortNameLocal() { - val folder = tmpFolder("folder") - val file1 = tmpFile("apple") - val file2 = tmpFile("banana") - val file3 = tmpFile("cherry") - - runSortFiles( - "A→Z asc", - mutableListOf(file3, folder, file1, file2), - FileSortOrderByName(SORT_A_TO_Z_ID, true), - listOf(folder, file1, file2, file3) - ) - - runSortFiles( - "A→Z desc", - mutableListOf(file3, folder, file1, file2), - FileSortOrderByName(SORT_A_TO_Z_ID, false), - listOf(folder, file3, file2, file1) - ) - } - - @Test - fun sortNameCloud() { - val file1 = ocFile("/b.txt") - val file2 = ocFile("/a.txt") - val file3 = ocFile("/c.txt") - - runSortCloudFiles( - "cloud A→Z asc", - mutableListOf(file1, file2, file3), - FileSortOrderByName(SORT_A_TO_Z_ID, true), - listOf(file2, file1, file3) - ) - } - - @Test - fun sortNameConcurrency() { - testConcurrency( - mutableListOf( - tmpFile("apple"), - tmpFile("banana"), - tmpFile("cherry"), - tmpFolder("folder") - ), - FileSortOrderByName(SORT_A_TO_Z_ID, true) - ) - } - - @Test - fun sortSizeLocal() { - val file1 = tmpFile("file1", size = 100) - val file2 = tmpFile("file2", size = 300) - val file3 = tmpFile("file3", size = 200) - val d1 = tmpFolder("folder1") - val d2 = tmpFolder("folder2") - - runSortFiles( - "small→big asc", - mutableListOf(file1, file2, file3), - FileSortOrderBySize(SORT_SMALL_TO_BIG_ID, true), - listOf(file1, file3, file2) - ) - - runSortFiles( - "small→big desc", - mutableListOf(file1, file2, file3), - FileSortOrderBySize(SORT_SMALL_TO_BIG_ID, false), - listOf(file2, file3, file1) - ) - - runSortFiles( - "big→small asc (folders first)", - mutableListOf(file1, file2, file3, d1, d2), - FileSortOrderBySize(SORT_BIG_TO_SMALL_ID, true), - listOf(d1, d2, file1, file3, file2) - ) - - runSortFiles( - "big→small desc (folders first)", - mutableListOf(file1, file2, file3, d1, d2), - FileSortOrderBySize(SORT_BIG_TO_SMALL_ID, false), - listOf(d1, d2, file2, file3, file1) - ) - } - - @Test - fun sortSizeCloud() { - val file1 = ocFile("/1", size = 100) - val file2 = ocFile("/2", size = 300) - val file3 = ocFile("/3", size = 200) - - runSortCloudFiles( - "cloud small→big asc", - mutableListOf(file1, file2, file3), - FileSortOrderBySize(SORT_SMALL_TO_BIG_ID, true), - listOf(file1, file3, file2) - ) - } - - @Test - fun sortSizeConcurrency() { - testConcurrency( - mutableListOf( - tmpFile("file1", size = 100), - tmpFile("file2", size = 200), - tmpFile("file3", size = 300), - tmpFolder("folder") - ), - FileSortOrderBySize(SORT_SMALL_TO_BIG_ID, true) - ) - } -} diff --git a/app/src/main/java/com/owncloud/android/ui/adapter/LocalFileListAdapter.java b/app/src/main/java/com/owncloud/android/ui/adapter/LocalFileListAdapter.java index b8c8423226b4..91bff4ac8bee 100644 --- a/app/src/main/java/com/owncloud/android/ui/adapter/LocalFileListAdapter.java +++ b/app/src/main/java/com/owncloud/android/ui/adapter/LocalFileListAdapter.java @@ -43,6 +43,7 @@ import java.util.List; import java.util.Locale; import java.util.Set; +import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; import androidx.annotation.NonNull; @@ -67,6 +68,7 @@ public class LocalFileListAdapter extends RecyclerView.Adapter checkedFiles; private ViewThemeUtils viewThemeUtils; private boolean isWithinEncryptedFolder; + private final ExecutorService singleThreadExecutor = Executors.newSingleThreadExecutor(); private static final int VIEWTYPE_ITEM = 0; private static final int VIEWTYPE_FOOTER = 1; @@ -372,7 +374,7 @@ public void swapDirectory(final File directory) { mFiles.clear(); mFilesAll.clear(); - Executors.newSingleThreadExecutor().execute(() -> { + singleThreadExecutor.execute(() -> { // Load first page of folders List firstPage = FileHelper.INSTANCE.listDirectoryEntries(directory, currentOffset, PAGE_SIZE, true); @@ -442,15 +444,25 @@ private void notifyItemRange(List updatedList) { }); } + private final Object filesLock = new Object(); + @SuppressLint("NotifyDataSetChanged") public void setSortOrder(FileSortOrder sortOrder) { localFileListFragmentInterface.setLoading(true); - final Handler uiHandler = new Handler(Looper.getMainLooper()); - Executors.newSingleThreadExecutor().execute(() -> { - preferences.setSortOrder(FileSortOrder.Type.localFileListView, sortOrder); - mFiles = sortOrder.sortLocalFiles(mFiles); + singleThreadExecutor.execute(() -> { + List sortedCopy; + synchronized (filesLock) { + sortedCopy = new ArrayList<>(mFiles); + } + + sortedCopy = sortOrder.sortLocalFiles(sortedCopy); - uiHandler.post(() -> { + List finalSortedCopy = sortedCopy; + new Handler(Looper.getMainLooper()).post(() -> { + synchronized (filesLock) { + mFiles = finalSortedCopy; + mFilesAll = new ArrayList<>(finalSortedCopy); + } notifyDataSetChanged(); localFileListFragmentInterface.setLoading(false); }); @@ -591,4 +603,8 @@ public void setFiles(List newFiles) { notifyDataSetChanged(); localFileListFragmentInterface.setLoading(false); } + + public void cleanup() { + singleThreadExecutor.shutdown(); + } } diff --git a/app/src/main/java/com/owncloud/android/utils/FileSortOrderByDate.kt b/app/src/main/java/com/owncloud/android/utils/FileSortOrderByDate.kt index da88a68a81ee..6d59836a9764 100644 --- a/app/src/main/java/com/owncloud/android/utils/FileSortOrderByDate.kt +++ b/app/src/main/java/com/owncloud/android/utils/FileSortOrderByDate.kt @@ -26,11 +26,10 @@ class FileSortOrderByDate(name: String, ascending: Boolean) : FileSortOrder(name favoritesFirst: Boolean ): MutableList { val multiplier = if (isAscending) 1 else -1 - val copy = files.toMutableList() - copy.sortWith { o1: OCFile, o2: OCFile -> + files.sortWith { o1: OCFile, o2: OCFile -> multiplier * o1.modificationTimestamp.compareTo(o2.modificationTimestamp) } - return super.sortCloudFiles(copy, foldersBeforeFiles, favoritesFirst) + return super.sortCloudFiles(files, foldersBeforeFiles, favoritesFirst) } /** @@ -40,11 +39,10 @@ class FileSortOrderByDate(name: String, ascending: Boolean) : FileSortOrder(name */ override fun sortTrashbinFiles(files: MutableList): List { val multiplier = if (isAscending) 1 else -1 - val copy = files.toMutableList() - copy.sortWith { o1: TrashbinFile, o2: TrashbinFile -> + files.sortWith { o1: TrashbinFile, o2: TrashbinFile -> multiplier * o1.deletionTimestamp.compareTo(o2.deletionTimestamp) } - return super.sortTrashbinFiles(copy) + return super.sortTrashbinFiles(files) } /** @@ -54,10 +52,9 @@ class FileSortOrderByDate(name: String, ascending: Boolean) : FileSortOrder(name */ override fun sortLocalFiles(files: MutableList): List { val multiplier = if (isAscending) 1 else -1 - val copy = files.toMutableList() - copy.sortWith { o1: File, o2: File -> + files.sortWith { o1: File, o2: File -> multiplier * o1.lastModified().compareTo(o2.lastModified()) } - return copy + return files } } diff --git a/app/src/main/java/com/owncloud/android/utils/FileSortOrderByName.kt b/app/src/main/java/com/owncloud/android/utils/FileSortOrderByName.kt index 48f4ed3b5f6e..cb39a2a03303 100644 --- a/app/src/main/java/com/owncloud/android/utils/FileSortOrderByName.kt +++ b/app/src/main/java/com/owncloud/android/utils/FileSortOrderByName.kt @@ -29,8 +29,7 @@ class FileSortOrderByName internal constructor(name: String?, ascending: Boolean foldersBeforeFiles: Boolean, favoritesFirst: Boolean ): MutableList { - val copy = files.toMutableList() - val sortedByName = sortOnlyByName(copy) + val sortedByName = sortOnlyByName(files) return super.sortCloudFiles(sortedByName, foldersBeforeFiles, favoritesFirst) } @@ -40,14 +39,12 @@ class FileSortOrderByName internal constructor(name: String?, ascending: Boolean * @param files files to sort */ override fun sortTrashbinFiles(files: MutableList): List { - val copy = files.toMutableList() - val sortedByName = sortServerFiles(copy) + val sortedByName = sortServerFiles(files) return super.sortTrashbinFiles(sortedByName) } private fun sortServerFiles(files: MutableList): MutableList { - val copy = files.toMutableList() - copy.sortWith { o1: ServerFileInterface, o2: ServerFileInterface -> + files.sortWith { o1: ServerFileInterface, o2: ServerFileInterface -> when { o1.isFolder && o2.isFolder -> sortMultiplier * AlphanumComparator.compare(o1, o2) o1.isFolder -> -1 @@ -55,13 +52,12 @@ class FileSortOrderByName internal constructor(name: String?, ascending: Boolean else -> sortMultiplier * AlphanumComparator.compare(o1, o2) } } - return copy + return files } private fun sortOnlyByName(files: MutableList): MutableList { - val copy = files.toMutableList() - copy.sortWith { o1: OCFile, o2: OCFile -> sortMultiplier * AlphanumComparator.compare(o1, o2) } - return copy + files.sortWith { o1: OCFile, o2: OCFile -> sortMultiplier * AlphanumComparator.compare(o1, o2) } + return files } /** @@ -70,8 +66,7 @@ class FileSortOrderByName internal constructor(name: String?, ascending: Boolean * @param files files to sort */ override fun sortLocalFiles(files: MutableList): List { - val copy = files.toMutableList() - copy.sortWith { o1: File, o2: File -> + files.sortWith { o1: File, o2: File -> when { o1.isDirectory && o2.isDirectory -> sortMultiplier * o1.path.lowercase(Locale.getDefault()) .compareTo(o2.path.lowercase(Locale.getDefault())) @@ -83,6 +78,6 @@ class FileSortOrderByName internal constructor(name: String?, ascending: Boolean ) } } - return copy + return files } } diff --git a/app/src/main/java/com/owncloud/android/utils/FileSortOrderBySize.kt b/app/src/main/java/com/owncloud/android/utils/FileSortOrderBySize.kt index e4f9e4689e8e..5b188f1c4e86 100644 --- a/app/src/main/java/com/owncloud/android/utils/FileSortOrderBySize.kt +++ b/app/src/main/java/com/owncloud/android/utils/FileSortOrderBySize.kt @@ -22,20 +22,17 @@ class FileSortOrderBySize internal constructor(name: String?, ascending: Boolean foldersBeforeFiles: Boolean, favoritesFirst: Boolean ): MutableList { - val copy = files.toMutableList() - val sortedBySize = sortServerFiles(copy) + val sortedBySize = sortServerFiles(files) return super.sortCloudFiles(sortedBySize, foldersBeforeFiles, favoritesFirst) } override fun sortTrashbinFiles(files: MutableList): List { - val copy = files.toMutableList() - val sortedBySize = sortServerFiles(copy) + val sortedBySize = sortServerFiles(files) return super.sortTrashbinFiles(sortedBySize) } private fun sortServerFiles(files: MutableList): MutableList { - val copy = files.toMutableList() - copy.sortWith { o1: ServerFileInterface, o2: ServerFileInterface -> + files.sortWith { o1: ServerFileInterface, o2: ServerFileInterface -> when { o1.isFolder && o2.isFolder -> sortMultiplier * o1.fileLength.compareTo(o2.fileLength) o1.isFolder -> -1 @@ -43,15 +40,14 @@ class FileSortOrderBySize internal constructor(name: String?, ascending: Boolean else -> sortMultiplier * o1.fileLength.compareTo(o2.fileLength) } } - return copy + return files } override fun sortLocalFiles(files: MutableList): List { - val copy = files.toMutableList() val folderSizes = - copy.associateWith { file -> FileStorageUtils.getFolderSize(file) } + files.associateWith { file -> FileStorageUtils.getFolderSize(file) } - copy.sortWith { o1: File, o2: File -> + files.sortWith { o1: File, o2: File -> when { o1.isDirectory && o2.isDirectory -> sortMultiplier * (folderSizes[o1] ?: 0L).compareTo( folderSizes[o2] ?: 0L @@ -61,6 +57,6 @@ class FileSortOrderBySize internal constructor(name: String?, ascending: Boolean else -> sortMultiplier * o1.length().compareTo(o2.length()) } } - return copy + return files } } From 5c35aa3b7f3886dfa3c6b1948e0f80d904db2073 Mon Sep 17 00:00:00 2001 From: alperozturk Date: Mon, 1 Dec 2025 08:18:08 +0100 Subject: [PATCH 085/216] fix git conflict Signed-off-by: alperozturk --- .../owncloud/android/ui/fragment/LocalFileListFragment.java | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/app/src/main/java/com/owncloud/android/ui/fragment/LocalFileListFragment.java b/app/src/main/java/com/owncloud/android/ui/fragment/LocalFileListFragment.java index ba732d1b788a..26b3f8de3d6a 100644 --- a/app/src/main/java/com/owncloud/android/ui/fragment/LocalFileListFragment.java +++ b/app/src/main/java/com/owncloud/android/ui/fragment/LocalFileListFragment.java @@ -425,4 +425,10 @@ public interface ContainerActivity { public void setupStoragePermissionWarningBanner() { mAdapter.notifyDataSetChanged(); } + + @Override + public void onDestroyView() { + mAdapter.cleanup(); + super.onDestroyView(); + } } From 1034e570e55036c58809b1b77430bf207a8861c5 Mon Sep 17 00:00:00 2001 From: alperozturk Date: Wed, 17 Dec 2025 11:52:38 +0100 Subject: [PATCH 086/216] remove lock Signed-off-by: alperozturk --- .../android/ui/adapter/LocalFileListAdapter.java | 16 ++++------------ 1 file changed, 4 insertions(+), 12 deletions(-) diff --git a/app/src/main/java/com/owncloud/android/ui/adapter/LocalFileListAdapter.java b/app/src/main/java/com/owncloud/android/ui/adapter/LocalFileListAdapter.java index 91bff4ac8bee..ddcf18e3f3da 100644 --- a/app/src/main/java/com/owncloud/android/ui/adapter/LocalFileListAdapter.java +++ b/app/src/main/java/com/owncloud/android/ui/adapter/LocalFileListAdapter.java @@ -444,25 +444,17 @@ private void notifyItemRange(List updatedList) { }); } - private final Object filesLock = new Object(); - @SuppressLint("NotifyDataSetChanged") public void setSortOrder(FileSortOrder sortOrder) { localFileListFragmentInterface.setLoading(true); singleThreadExecutor.execute(() -> { - List sortedCopy; - synchronized (filesLock) { - sortedCopy = new ArrayList<>(mFiles); - } - + List sortedCopy = new ArrayList<>(mFiles); sortedCopy = sortOrder.sortLocalFiles(sortedCopy); - List finalSortedCopy = sortedCopy; + final List finalSortedCopy = sortedCopy; new Handler(Looper.getMainLooper()).post(() -> { - synchronized (filesLock) { - mFiles = finalSortedCopy; - mFilesAll = new ArrayList<>(finalSortedCopy); - } + mFiles = finalSortedCopy; + mFilesAll = new ArrayList<>(finalSortedCopy); notifyDataSetChanged(); localFileListFragmentInterface.setLoading(false); }); From 60c84572c2fe4fa8d3767ed6ad6474279acc2aac Mon Sep 17 00:00:00 2001 From: alperozturk Date: Thu, 18 Dec 2025 13:48:59 +0100 Subject: [PATCH 087/216] fix: register/unregister broadcast receivers Signed-off-by: alperozturk --- .../ui/activity/FileDisplayActivity.kt | 68 +++++++++++-------- .../android/ui/fragment/SharedListFragment.kt | 1 - 2 files changed, 41 insertions(+), 28 deletions(-) diff --git a/app/src/main/java/com/owncloud/android/ui/activity/FileDisplayActivity.kt b/app/src/main/java/com/owncloud/android/ui/activity/FileDisplayActivity.kt index ff5e800637b8..1c79404ca2b7 100644 --- a/app/src/main/java/com/owncloud/android/ui/activity/FileDisplayActivity.kt +++ b/app/src/main/java/com/owncloud/android/ui/activity/FileDisplayActivity.kt @@ -274,7 +274,6 @@ class FileDisplayActivity : checkStoragePath() - initSyncBroadcastReceiver() observeWorkerState() startMetadataSyncForRoot() handleBackPress() @@ -1330,12 +1329,6 @@ class FileDisplayActivity : // Instead of onPostCreate, starting the loading in onResume for children fragments val leftFragment = this.leftFragment - - // Listen for sync messages - if (leftFragment !is OCFileListFragment || !leftFragment.isSearchFragment) { - initSyncBroadcastReceiver() - } - if (leftFragment !is OCFileListFragment) { if (leftFragment is FileFragment) { super.updateActionBarTitleAndHomeButton(leftFragment.file) @@ -1364,19 +1357,6 @@ class FileDisplayActivity : updateActionBarTitleAndHomeButton(startFile) } - // Listen for upload messages - val uploadIntentFilter = IntentFilter(getUploadFinishMessage()) - mUploadFinishReceiver = UploadFinishReceiver() - localBroadcastManager.registerReceiver(mUploadFinishReceiver!!, uploadIntentFilter) - - // Listen for download messages - val downloadIntentFilter = IntentFilter(getDownloadAddedMessage()) - downloadIntentFilter.addAction(getDownloadFinishMessage()) - mDownloadFinishReceiver = DownloadFinishReceiver() - mDownloadFinishReceiver?.let { - localBroadcastManager.registerReceiver(it, downloadIntentFilter) - } - configureMenuItem() // show in-app review dialog to user @@ -1411,9 +1391,36 @@ class FileDisplayActivity : setNavigationViewItemChecked() } - fun initSyncBroadcastReceiver() { + // region local broadcast manager receivers + private fun registerReceivers() { + Log_OC.d(TAG, "registering receivers") + + registerSyncBroadcastReceiver() + registerDownloadFinishReceiver() + registerUploadFinishReceiver() + } + + private fun registerUploadFinishReceiver() { + val uploadIntentFilter = IntentFilter(getUploadFinishMessage()) + mUploadFinishReceiver = UploadFinishReceiver() + mUploadFinishReceiver?.let { + localBroadcastManager.registerReceiver(mUploadFinishReceiver!!, uploadIntentFilter) + } + } + + private fun registerDownloadFinishReceiver() { + val filter = IntentFilter(getDownloadAddedMessage()).apply { + addAction(getDownloadFinishMessage()) + } + mDownloadFinishReceiver = DownloadFinishReceiver() + mDownloadFinishReceiver?.let { + localBroadcastManager.registerReceiver(it, filter) + } + } + + private fun registerSyncBroadcastReceiver() { if (mSyncBroadcastReceiver == null) { - val syncIntentFilter = IntentFilter(FileSyncAdapter.EVENT_FULL_SYNC_START).apply { + val filter = IntentFilter(FileSyncAdapter.EVENT_FULL_SYNC_START).apply { addAction(FileSyncAdapter.EVENT_FULL_SYNC_END) addAction(FileSyncAdapter.EVENT_FULL_SYNC_FOLDER_CONTENTS_SYNCED) addAction(RefreshFolderOperation.EVENT_SINGLE_FOLDER_CONTENTS_SYNCED) @@ -1422,13 +1429,14 @@ class FileDisplayActivity : mSyncBroadcastReceiver = SyncBroadcastReceiver() mSyncBroadcastReceiver?.let { - localBroadcastManager.registerReceiver(it, syncIntentFilter) + localBroadcastManager.registerReceiver(it, filter) } } } - override fun onPause() { - Log_OC.v(TAG, "onPause() start") + private fun unregisterReceivers() { + Log_OC.d(TAG, "unregistering receivers") + if (mSyncBroadcastReceiver != null) { localBroadcastManager.unregisterReceiver(mSyncBroadcastReceiver!!) mSyncBroadcastReceiver = null @@ -1441,9 +1449,13 @@ class FileDisplayActivity : localBroadcastManager.unregisterReceiver(mDownloadFinishReceiver!!) mDownloadFinishReceiver = null } + } + // endregion - super.onPause() - Log_OC.v(TAG, "onPause() end") + override fun onStop() { + Log_OC.v(TAG, "onStop()") + unregisterReceivers() + super.onStop() } override fun onSortingOrderChosen(selection: FileSortOrder?) { @@ -2803,6 +2815,8 @@ class FileDisplayActivity : public override fun onStart() { super.onStart() + registerReceivers() + if (SettingsActivity.isBackPressed) { Log_OC.d(TAG, "User returned from settings activity, skipping reset content logic") return diff --git a/app/src/main/java/com/owncloud/android/ui/fragment/SharedListFragment.kt b/app/src/main/java/com/owncloud/android/ui/fragment/SharedListFragment.kt index c146a574450c..9756099b7e15 100644 --- a/app/src/main/java/com/owncloud/android/ui/fragment/SharedListFragment.kt +++ b/app/src/main/java/com/owncloud/android/ui/fragment/SharedListFragment.kt @@ -63,7 +63,6 @@ class SharedListFragment : val fileDisplayActivity = activity as FileDisplayActivity fileDisplayActivity.updateActionBarTitleAndHomeButtonByString(getString(R.string.drawer_item_shared)) fileDisplayActivity.setMainFabVisible(false) - fileDisplayActivity.initSyncBroadcastReceiver() } } } From 37ddd40a610d5effc23f2d375888259c5979d9cc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alper=20=C3=96zt=C3=BCrk?= <67455295+alperozturk96@users.noreply.github.com> Date: Thu, 18 Dec 2025 15:50:41 +0100 Subject: [PATCH 088/216] Apply suggestions from code review MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Tom <70907959+ZetaTom@users.noreply.github.com> Signed-off-by: Alper Öztürk <67455295+alperozturk96@users.noreply.github.com> --- .../com/owncloud/android/ui/activity/FileDisplayActivity.kt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/app/src/main/java/com/owncloud/android/ui/activity/FileDisplayActivity.kt b/app/src/main/java/com/owncloud/android/ui/activity/FileDisplayActivity.kt index 1c79404ca2b7..5914cbf61f39 100644 --- a/app/src/main/java/com/owncloud/android/ui/activity/FileDisplayActivity.kt +++ b/app/src/main/java/com/owncloud/android/ui/activity/FileDisplayActivity.kt @@ -1401,10 +1401,10 @@ class FileDisplayActivity : } private fun registerUploadFinishReceiver() { - val uploadIntentFilter = IntentFilter(getUploadFinishMessage()) + val filter = IntentFilter(getUploadFinishMessage()) mUploadFinishReceiver = UploadFinishReceiver() mUploadFinishReceiver?.let { - localBroadcastManager.registerReceiver(mUploadFinishReceiver!!, uploadIntentFilter) + localBroadcastManager.registerReceiver(it, filter) } } From 8bbd2e609d1026e846a4bfd9a58ddf08de675a33 Mon Sep 17 00:00:00 2001 From: alperozturk Date: Thu, 18 Dec 2025 12:35:57 +0100 Subject: [PATCH 089/216] fix: eTag comparison Signed-off-by: alperozturk --- .../extensions/StringExtensionTests.kt | 48 +++++++++---------- .../utils/extensions/StringExtensions.kt | 30 +++++------- .../owncloud/android/datamodel/OCFile.java | 2 +- .../operations/RefreshFolderOperation.java | 2 +- 4 files changed, 39 insertions(+), 43 deletions(-) diff --git a/app/src/androidTest/java/com/nextcloud/extensions/StringExtensionTests.kt b/app/src/androidTest/java/com/nextcloud/extensions/StringExtensionTests.kt index 36600e6caab6..c9985b7309fa 100644 --- a/app/src/androidTest/java/com/nextcloud/extensions/StringExtensionTests.kt +++ b/app/src/androidTest/java/com/nextcloud/extensions/StringExtensionTests.kt @@ -6,7 +6,7 @@ */ package com.nextcloud.extensions -import com.nextcloud.utils.extensions.isNotBlankAndEquals +import com.nextcloud.utils.extensions.eTagChanged import junit.framework.TestCase.assertFalse import junit.framework.TestCase.assertTrue import org.junit.Test @@ -17,160 +17,160 @@ class StringExtensionTests { fun testIsNotBlankAndEqualsWhenGivenBothStringsAreNull() { val str1: String? = null val str2: String? = null - assertFalse(str1.isNotBlankAndEquals(str2)) + assertTrue(str1.eTagChanged(str2)) } @Test fun testIsNotBlankAndEqualsWhenGivenFirstStringIsNull() { val str1: String? = null val str2 = "hello" - assertFalse(str1.isNotBlankAndEquals(str2)) + assertTrue(str1.eTagChanged(str2)) } @Test fun testIsNotBlankAndEqualsWhenGivenSecondStringIsNull() { val str1 = "hello" val str2: String? = null - assertFalse(str1.isNotBlankAndEquals(str2)) + assertTrue(str1.eTagChanged(str2)) } @Test fun testIsNotBlankAndEqualsWhenGivenBothStringsAreEmpty() { val str1 = "" val str2 = "" - assertFalse(str1.isNotBlankAndEquals(str2)) + assertTrue(str1.eTagChanged(str2)) } @Test fun testIsNotBlankAndEqualsWhenGivenFirstStringIsEmpty() { val str1 = "" val str2 = "hello" - assertFalse(str1.isNotBlankAndEquals(str2)) + assertTrue(str1.eTagChanged(str2)) } @Test fun testIsNotBlankAndEqualsWhenGivenSecondStringIsEmpty() { val str1 = "hello" val str2 = "" - assertFalse(str1.isNotBlankAndEquals(str2)) + assertTrue(str1.eTagChanged(str2)) } @Test fun testIsNotBlankAndEqualsWhenGivenBothStringsAreWhitespaceOnly() { val str1 = " " val str2 = " \t " - assertFalse(str1.isNotBlankAndEquals(str2)) + assertTrue(str1.eTagChanged(str2)) } @Test fun testIsNotBlankAndEqualsWhenGivenFirstStringIsWhitespaceOnly() { val str1 = " " val str2 = "hello" - assertFalse(str1.isNotBlankAndEquals(str2)) + assertTrue(str1.eTagChanged(str2)) } @Test fun testIsNotBlankAndEqualsWhenGivenSecondStringIsWhitespaceOnly() { val str1 = "hello" val str2 = " " - assertFalse(str1.isNotBlankAndEquals(str2)) + assertTrue(str1.eTagChanged(str2)) } @Test fun testIsNotBlankAndEqualsWhenGivenStringsAreDifferentButBothValid() { val str1 = "hello" val str2 = "world" - assertFalse(str1.isNotBlankAndEquals(str2)) + assertTrue(str1.eTagChanged(str2)) } @Test fun testIsNotBlankAndEqualsWhenGivenStringsHaveDifferentCase() { val str1 = "Hello" val str2 = "hello" - assertTrue(str1.isNotBlankAndEquals(str2)) + assertFalse(str1.eTagChanged(str2)) } @Test fun testIsNotBlankAndEqualsWhenGivenMixedCaseStrings() { val str1 = "HeLLo WoRLd" val str2 = "hello world" - assertTrue(str1.isNotBlankAndEquals(str2)) + assertFalse(str1.eTagChanged(str2)) } @Test fun testIsNotBlankAndEqualsWhenGivenUppercaseStrings() { val str1 = "HELLO" val str2 = "hello" - assertTrue(str1.isNotBlankAndEquals(str2)) + assertFalse(str1.eTagChanged(str2)) } @Test fun testIsNotBlankAndEqualsWhenGivenBothStringsAreIdenticalAndValid() { val str1 = "hello" val str2 = "hello" - assertTrue(str1.isNotBlankAndEquals(str2)) + assertFalse(str1.eTagChanged(str2)) } @Test fun testIsNotBlankAndEqualsWhenGivenBothStringsAreIdenticalWithSpaces() { val str1 = "hello world" val str2 = "hello world" - assertTrue(str1.isNotBlankAndEquals(str2)) + assertFalse(str1.eTagChanged(str2)) } @Test fun testIsNotBlankAndEqualsWhenGivenBothStringsAreIdenticalSingleCharacter() { val str1 = "a" val str2 = "A" - assertTrue(str1.isNotBlankAndEquals(str2)) + assertFalse(str1.eTagChanged(str2)) } @Test fun testIsNotBlankAndEqualsWhenGivenBothStringsAreIdenticalWithSpecialCharacters() { val str1 = "hello@world!123" val str2 = "HELLO@WORLD!123" - assertTrue(str1.isNotBlankAndEquals(str2)) + assertFalse(str1.eTagChanged(str2)) } @Test fun testIsNotBlankAndEqualsWhenGivenOneHasLeadingWhitespaceAndOtherDoesNot() { val str1 = " hello" val str2 = "HELLO" - assertFalse(str1.isNotBlankAndEquals(str2)) + assertTrue(str1.eTagChanged(str2)) } @Test fun testIsNotBlankAndEqualsWhenGivenOneHasTrailingWhitespaceAndOtherDoesNot() { val str1 = "hello" val str2 = "HELLO " - assertFalse(str1.isNotBlankAndEquals(str2)) + assertTrue(str1.eTagChanged(str2)) } @Test fun testIsNotBlankAndEqualsWhenGivenBothHaveIdenticalWhitespacePaddingDifferentCase() { val str1 = " hello " val str2 = " HELLO " - assertTrue(str1.isNotBlankAndEquals(str2)) + assertFalse(str1.eTagChanged(str2)) } @Test fun testIsNotBlankAndEqualsWhenGivenMixedWhitespaceCharacters() { val str1 = "\t" val str2 = "\n" - assertFalse(str1.isNotBlankAndEquals(str2)) + assertTrue(str1.eTagChanged(str2)) } @Test fun testIsNotBlankAndEqualsWhenGivenOneIsNullAndOtherIsEmpty() { val str1: String? = null val str2 = "" - assertFalse(str1.isNotBlankAndEquals(str2)) + assertTrue(str1.eTagChanged(str2)) } @Test fun testIsNotBlankAndEqualsWhenGivenOneIsNullAndOtherIsWhitespace() { val str1: String? = null val str2 = " " - assertFalse(str1.isNotBlankAndEquals(str2)) + assertTrue(str1.eTagChanged(str2)) } } diff --git a/app/src/main/java/com/nextcloud/utils/extensions/StringExtensions.kt b/app/src/main/java/com/nextcloud/utils/extensions/StringExtensions.kt index b802bac34a55..bd552e5eb76a 100644 --- a/app/src/main/java/com/nextcloud/utils/extensions/StringExtensions.kt +++ b/app/src/main/java/com/nextcloud/utils/extensions/StringExtensions.kt @@ -25,23 +25,19 @@ fun String.removeFileExtension(): String { } } -/** - * Checks if two nullable strings are both valid (non-null, non-empty, non-blank) and equal. - * - * It returns `true` only when both strings meet all the following criteria: - * - Neither string is null - * - Neither string is empty ("") - * - Neither string contains only whitespace characters (spaces, tabs, newlines, etc.) - * - Both strings are equal ignoring case differences - * - * @param other The other nullable string to compare with this string - * @return `true` if both strings are valid and equal ignoring case differences, `false` otherwise - */ -fun String?.isNotBlankAndEquals(other: String?): Boolean = this != null && - other != null && - this.isNotBlank() && - other.isNotBlank() && - this.equals(other, ignoreCase = true) +fun String?.eTagChanged(eTagOnServer: String?): Boolean { + if (eTagOnServer?.isEmpty() == true) { + // provided eTag is empty can't compare treat as eTag changed + return true + } + + return if (this != null) { + !this.equals(eTagOnServer, ignoreCase = true) + } else { + // provided eTag is null can't compare treat as eTag changed + true + } +} fun String.truncateWithEllipsis(limit: Int) = take(limit) + if (length > limit) StringConstants.THREE_DOT else "" diff --git a/app/src/main/java/com/owncloud/android/datamodel/OCFile.java b/app/src/main/java/com/owncloud/android/datamodel/OCFile.java index 11455a2707d2..d9db1173002f 100644 --- a/app/src/main/java/com/owncloud/android/datamodel/OCFile.java +++ b/app/src/main/java/com/owncloud/android/datamodel/OCFile.java @@ -796,7 +796,7 @@ public String getEtagOnServer() { } public boolean isEtagChanged() { - return !StringExtensionsKt.isNotBlankAndEquals(getEtag(), getEtagOnServer()); + return StringExtensionsKt.eTagChanged(getEtag(), getEtagOnServer()); } public boolean isSharedViaLink() { diff --git a/app/src/main/java/com/owncloud/android/operations/RefreshFolderOperation.java b/app/src/main/java/com/owncloud/android/operations/RefreshFolderOperation.java index 66bd13aff1a7..43885e40ab89 100644 --- a/app/src/main/java/com/owncloud/android/operations/RefreshFolderOperation.java +++ b/app/src/main/java/com/owncloud/android/operations/RefreshFolderOperation.java @@ -419,7 +419,7 @@ private RemoteOperationResult checkForChanges(OwnCloudClient client) { String remoteFolderETag = remoteFile.getEtag(); if (remoteFolderETag != null) { String localFolderEtag = mLocalFolder.getEtag(); - mRemoteFolderChanged = !StringExtensionsKt.isNotBlankAndEquals(remoteFolderETag, localFolderEtag); + mRemoteFolderChanged = StringExtensionsKt.eTagChanged(remoteFolderETag, localFolderEtag); Log_OC.d( TAG, "📂 eTag check\n" + From d1b6705dc05324800a871b4bb0b24ba820e0049c Mon Sep 17 00:00:00 2001 From: alperozturk Date: Thu, 18 Dec 2025 14:48:42 +0100 Subject: [PATCH 090/216] better condition Signed-off-by: alperozturk --- .../nextcloud/utils/extensions/StringExtensions.kt | 11 +++-------- 1 file changed, 3 insertions(+), 8 deletions(-) diff --git a/app/src/main/java/com/nextcloud/utils/extensions/StringExtensions.kt b/app/src/main/java/com/nextcloud/utils/extensions/StringExtensions.kt index bd552e5eb76a..afab68450edb 100644 --- a/app/src/main/java/com/nextcloud/utils/extensions/StringExtensions.kt +++ b/app/src/main/java/com/nextcloud/utils/extensions/StringExtensions.kt @@ -26,17 +26,12 @@ fun String.removeFileExtension(): String { } fun String?.eTagChanged(eTagOnServer: String?): Boolean { - if (eTagOnServer?.isEmpty() == true) { - // provided eTag is empty can't compare treat as eTag changed + if (this == null || this.isEmpty() || eTagOnServer == null || eTagOnServer.isEmpty()) { + // provided eTag are empty or null can't compare treat as eTag changed return true } - return if (this != null) { - !this.equals(eTagOnServer, ignoreCase = true) - } else { - // provided eTag is null can't compare treat as eTag changed - true - } + return !this.equals(eTagOnServer, ignoreCase = true) } fun String.truncateWithEllipsis(limit: Int) = take(limit) + if (length > limit) StringConstants.THREE_DOT else "" From a826bdccb9baed8fc4b91e516ea3eb9b66944d46 Mon Sep 17 00:00:00 2001 From: alperozturk Date: Thu, 18 Dec 2025 14:49:49 +0100 Subject: [PATCH 091/216] better condition Signed-off-by: alperozturk --- .../java/com/nextcloud/utils/extensions/StringExtensions.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/src/main/java/com/nextcloud/utils/extensions/StringExtensions.kt b/app/src/main/java/com/nextcloud/utils/extensions/StringExtensions.kt index afab68450edb..f79e2ecda00b 100644 --- a/app/src/main/java/com/nextcloud/utils/extensions/StringExtensions.kt +++ b/app/src/main/java/com/nextcloud/utils/extensions/StringExtensions.kt @@ -27,7 +27,7 @@ fun String.removeFileExtension(): String { fun String?.eTagChanged(eTagOnServer: String?): Boolean { if (this == null || this.isEmpty() || eTagOnServer == null || eTagOnServer.isEmpty()) { - // provided eTag are empty or null can't compare treat as eTag changed + // provided eTags are empty or null can't compare treat as eTag changed return true } From abc8e9956ba9d56b8e01d725952526c39ce08b63 Mon Sep 17 00:00:00 2001 From: alperozturk Date: Thu, 18 Dec 2025 16:02:36 +0100 Subject: [PATCH 092/216] fix codacy Signed-off-by: alperozturk --- .../main/java/com/nextcloud/utils/extensions/StringExtensions.kt | 1 + 1 file changed, 1 insertion(+) diff --git a/app/src/main/java/com/nextcloud/utils/extensions/StringExtensions.kt b/app/src/main/java/com/nextcloud/utils/extensions/StringExtensions.kt index f79e2ecda00b..0f6a4b304f20 100644 --- a/app/src/main/java/com/nextcloud/utils/extensions/StringExtensions.kt +++ b/app/src/main/java/com/nextcloud/utils/extensions/StringExtensions.kt @@ -25,6 +25,7 @@ fun String.removeFileExtension(): String { } } +@Suppress("ComplexCondition") fun String?.eTagChanged(eTagOnServer: String?): Boolean { if (this == null || this.isEmpty() || eTagOnServer == null || eTagOnServer.isEmpty()) { // provided eTags are empty or null can't compare treat as eTag changed From 15835fa22ec2d08ba7591673afb24d5ffa475d69 Mon Sep 17 00:00:00 2001 From: alperozturk Date: Mon, 15 Dec 2025 15:11:22 +0100 Subject: [PATCH 093/216] handle metadata worker edge cases Signed-off-by: alperozturk --- .../nextcloud/client/database/dao/FileDao.kt | 2 +- .../client/jobs/metadata/MetadataWorker.kt | 72 +++++++++++++++---- 2 files changed, 58 insertions(+), 16 deletions(-) diff --git a/app/src/main/java/com/nextcloud/client/database/dao/FileDao.kt b/app/src/main/java/com/nextcloud/client/database/dao/FileDao.kt index 06a94aaafdff..86d02064c7a3 100644 --- a/app/src/main/java/com/nextcloud/client/database/dao/FileDao.kt +++ b/app/src/main/java/com/nextcloud/client/database/dao/FileDao.kt @@ -79,7 +79,7 @@ interface FileDao { AND file_owner = :accountName AND is_encrypted = 0 AND (content_type = :dirType OR content_type = :webdavType) - ORDER BY ${ProviderTableMeta.FILE_DEFAULT_SORT_ORDER} + ORDER BY ${ProviderTableMeta._ID} ASC """ ) fun getNonEncryptedSubfolders( diff --git a/app/src/main/java/com/nextcloud/client/jobs/metadata/MetadataWorker.kt b/app/src/main/java/com/nextcloud/client/jobs/metadata/MetadataWorker.kt index b6e19b318846..2ba5ee016be8 100644 --- a/app/src/main/java/com/nextcloud/client/jobs/metadata/MetadataWorker.kt +++ b/app/src/main/java/com/nextcloud/client/jobs/metadata/MetadataWorker.kt @@ -29,34 +29,64 @@ class MetadataWorker(private val context: Context, params: WorkerParameters, pri @Suppress("DEPRECATION", "ReturnCount") override suspend fun doWork(): Result { - val storageManager = FileDataStorageManager(user, context.contentResolver) val filePath = inputData.getString(FILE_PATH) if (filePath == null) { Log_OC.e(TAG, "❌ Invalid folder path. Aborting metadata sync. $filePath") return Result.failure() } + + val storageManager = FileDataStorageManager(user, context.contentResolver) val currentDir = storageManager.getFileByDecryptedRemotePath(filePath) if (currentDir == null) { Log_OC.e(TAG, "❌ Current directory is null. Aborting metadata sync. $filePath") return Result.failure() } - Log_OC.d(TAG, "🕒 Starting metadata sync for folder: $filePath") + if (currentDir.fileId <= 0) { + Log_OC.e(TAG, "❌ Current directory has invalid ID: ${currentDir.fileId}. Path: $filePath") + return Result.failure() + } + + Log_OC.d(TAG, "🕒 Starting metadata sync for folder: $filePath, id: ${currentDir.fileId}") + + // First check current dir + val currentRefreshResult = refreshFolder(currentDir, storageManager) + if (!currentRefreshResult) { + Log_OC.e(TAG, "❌ Failed to refresh current directory: $filePath") + return Result.failure() + } - // first check current dir - refreshFolder(currentDir, storageManager) + // Re-fetch the folder after refresh to get updated data + val refreshedDir = storageManager.getFileByPath(filePath) + if (refreshedDir == null || refreshedDir.fileId <= 0) { + Log_OC.e(TAG, "❌ Directory invalid after refresh. Path: $filePath") + return Result.failure() + } // then get up-to-date subfolders - val subfolders = storageManager.getNonEncryptedSubfolders(currentDir.fileId, user.accountName) + val subfolders = storageManager.getNonEncryptedSubfolders(refreshedDir.fileId, user.accountName) + Log_OC.d(TAG, "Found ${subfolders.size} subfolders to sync") + + var failedCount = 0 subfolders.forEach { subFolder -> - refreshFolder(subFolder, storageManager) + if (subFolder.fileId <= 0) { + Log_OC.e(TAG, "⚠️ Skipping subfolder with invalid ID: ${subFolder.remotePath}") + failedCount++ + return@forEach + } + + val success = refreshFolder(subFolder, storageManager) + if (!success) { + failedCount++ + } } - Log_OC.d(TAG, "🏁 Metadata sync completed for folder: $filePath") + Log_OC.d(TAG, "🏁 Metadata sync completed for folder: $filePath. Failed: $failedCount/${subfolders.size}") + return Result.success() } @Suppress("DEPRECATION") - private suspend fun refreshFolder(folder: OCFile, storageManager: FileDataStorageManager) = + private suspend fun refreshFolder(folder: OCFile, storageManager: FileDataStorageManager): Boolean = withContext(Dispatchers.IO) { Log_OC.d( TAG, @@ -65,19 +95,31 @@ class MetadataWorker(private val context: Context, params: WorkerParameters, pri " eTag: " + folder.etag + "\n" + " eTagOnServer: " + folder.etagOnServer ) + if (folder.fileId <= 0) { + Log_OC.e(TAG, "❌ Folder has invalid ID: ${folder.remotePath}") + return@withContext false + } + if (!folder.isEtagChanged) { Log_OC.d(TAG, "Skipping ${folder.remotePath}, eTag didn't change") - return@withContext + return@withContext false } - Log_OC.d(TAG, "⏳ Fetching metadata for: ${folder.remotePath}") + Log_OC.d(TAG, "⏳ Fetching metadata for: ${folder.remotePath}, id: ${folder.fileId}") val operation = RefreshFolderOperation(folder, storageManager, user, context) - val result = operation.execute(user, context) - if (result.isSuccess) { - Log_OC.d(TAG, "✅ Successfully fetched metadata for: ${folder.remotePath}") - } else { - Log_OC.e(TAG, "❌ Failed to fetch metadata for: ${folder.remotePath}") + return@withContext try { + val result = operation.execute(user, context) + if (result.isSuccess) { + Log_OC.d(TAG, "✅ Successfully fetched metadata for: ${folder.remotePath}") + true + } else { + Log_OC.e(TAG, "❌ Failed to fetch metadata for: ${folder.remotePath}") + false + } + } catch (e: Exception) { + Log_OC.e(TAG, "❌ Exception refreshing folder ${folder.remotePath}: ${e.message}", e) + false } } } From 8a28c40f143b9a73cf77cd7a132944dc58a0a027 Mon Sep 17 00:00:00 2001 From: alperozturk Date: Mon, 15 Dec 2025 15:12:15 +0100 Subject: [PATCH 094/216] handle metadata worker edge cases Signed-off-by: alperozturk --- .../java/com/nextcloud/client/jobs/metadata/MetadataWorker.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/src/main/java/com/nextcloud/client/jobs/metadata/MetadataWorker.kt b/app/src/main/java/com/nextcloud/client/jobs/metadata/MetadataWorker.kt index 2ba5ee016be8..c5110e71e852 100644 --- a/app/src/main/java/com/nextcloud/client/jobs/metadata/MetadataWorker.kt +++ b/app/src/main/java/com/nextcloud/client/jobs/metadata/MetadataWorker.kt @@ -19,6 +19,7 @@ import com.owncloud.android.operations.RefreshFolderOperation import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.withContext +@Suppress("DEPRECATION", "ReturnCount", "TooGenericExceptionCaught") class MetadataWorker(private val context: Context, params: WorkerParameters, private val user: User) : CoroutineWorker(context, params) { @@ -27,7 +28,6 @@ class MetadataWorker(private val context: Context, params: WorkerParameters, pri const val FILE_PATH = "file_path" } - @Suppress("DEPRECATION", "ReturnCount") override suspend fun doWork(): Result { val filePath = inputData.getString(FILE_PATH) if (filePath == null) { From 4b79ff2a1f15176059ad314192fbd43b767a7429 Mon Sep 17 00:00:00 2001 From: alperozturk Date: Mon, 15 Dec 2025 15:25:26 +0100 Subject: [PATCH 095/216] handle metadata worker edge cases Signed-off-by: alperozturk --- .../com/nextcloud/client/jobs/metadata/MetadataWorker.kt | 8 ++++---- .../main/java/com/owncloud/android/datamodel/OCFile.java | 5 +++++ 2 files changed, 9 insertions(+), 4 deletions(-) diff --git a/app/src/main/java/com/nextcloud/client/jobs/metadata/MetadataWorker.kt b/app/src/main/java/com/nextcloud/client/jobs/metadata/MetadataWorker.kt index c5110e71e852..134c93ab98c1 100644 --- a/app/src/main/java/com/nextcloud/client/jobs/metadata/MetadataWorker.kt +++ b/app/src/main/java/com/nextcloud/client/jobs/metadata/MetadataWorker.kt @@ -41,7 +41,7 @@ class MetadataWorker(private val context: Context, params: WorkerParameters, pri Log_OC.e(TAG, "❌ Current directory is null. Aborting metadata sync. $filePath") return Result.failure() } - if (currentDir.fileId <= 0) { + if (currentDir.hasValidParentId()) { Log_OC.e(TAG, "❌ Current directory has invalid ID: ${currentDir.fileId}. Path: $filePath") return Result.failure() } @@ -57,7 +57,7 @@ class MetadataWorker(private val context: Context, params: WorkerParameters, pri // Re-fetch the folder after refresh to get updated data val refreshedDir = storageManager.getFileByPath(filePath) - if (refreshedDir == null || refreshedDir.fileId <= 0) { + if (refreshedDir == null || refreshedDir.hasValidParentId()) { Log_OC.e(TAG, "❌ Directory invalid after refresh. Path: $filePath") return Result.failure() } @@ -68,7 +68,7 @@ class MetadataWorker(private val context: Context, params: WorkerParameters, pri var failedCount = 0 subfolders.forEach { subFolder -> - if (subFolder.fileId <= 0) { + if (subFolder.hasValidParentId()) { Log_OC.e(TAG, "⚠️ Skipping subfolder with invalid ID: ${subFolder.remotePath}") failedCount++ return@forEach @@ -95,7 +95,7 @@ class MetadataWorker(private val context: Context, params: WorkerParameters, pri " eTag: " + folder.etag + "\n" + " eTagOnServer: " + folder.etagOnServer ) - if (folder.fileId <= 0) { + if (folder.hasValidParentId()) { Log_OC.e(TAG, "❌ Folder has invalid ID: ${folder.remotePath}") return@withContext false } diff --git a/app/src/main/java/com/owncloud/android/datamodel/OCFile.java b/app/src/main/java/com/owncloud/android/datamodel/OCFile.java index d9db1173002f..753f8fca9d84 100644 --- a/app/src/main/java/com/owncloud/android/datamodel/OCFile.java +++ b/app/src/main/java/com/owncloud/android/datamodel/OCFile.java @@ -1166,4 +1166,9 @@ public void setIsRecommendedFile(boolean value) { public boolean isRecommendedFile() { return recommendedFile; } + + // only root directories parent id can be 0 + public boolean hasValidParentId() { + return !isRootDirectory() && getParentId() != 0; + } } From 32c11c424fe16889519c55b7998543ecaa60cb1f Mon Sep 17 00:00:00 2001 From: alperozturk Date: Mon, 15 Dec 2025 15:26:17 +0100 Subject: [PATCH 096/216] handle metadata worker edge cases Signed-off-by: alperozturk --- .../java/com/nextcloud/client/jobs/metadata/MetadataWorker.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/src/main/java/com/nextcloud/client/jobs/metadata/MetadataWorker.kt b/app/src/main/java/com/nextcloud/client/jobs/metadata/MetadataWorker.kt index 134c93ab98c1..1d94fbe014c8 100644 --- a/app/src/main/java/com/nextcloud/client/jobs/metadata/MetadataWorker.kt +++ b/app/src/main/java/com/nextcloud/client/jobs/metadata/MetadataWorker.kt @@ -69,7 +69,7 @@ class MetadataWorker(private val context: Context, params: WorkerParameters, pri var failedCount = 0 subfolders.forEach { subFolder -> if (subFolder.hasValidParentId()) { - Log_OC.e(TAG, "⚠️ Skipping subfolder with invalid ID: ${subFolder.remotePath}") + Log_OC.e(TAG, "❌ Skipping subfolder with invalid ID: ${subFolder.remotePath}") failedCount++ return@forEach } From 99ba3083419e1961aeeb704700ef5f89d3f1cd9e Mon Sep 17 00:00:00 2001 From: alperozturk Date: Mon, 15 Dec 2025 15:28:54 +0100 Subject: [PATCH 097/216] handle metadata worker edge cases Signed-off-by: alperozturk --- .../com/nextcloud/client/jobs/metadata/MetadataWorker.kt | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/app/src/main/java/com/nextcloud/client/jobs/metadata/MetadataWorker.kt b/app/src/main/java/com/nextcloud/client/jobs/metadata/MetadataWorker.kt index 1d94fbe014c8..30bedb87e978 100644 --- a/app/src/main/java/com/nextcloud/client/jobs/metadata/MetadataWorker.kt +++ b/app/src/main/java/com/nextcloud/client/jobs/metadata/MetadataWorker.kt @@ -41,7 +41,7 @@ class MetadataWorker(private val context: Context, params: WorkerParameters, pri Log_OC.e(TAG, "❌ Current directory is null. Aborting metadata sync. $filePath") return Result.failure() } - if (currentDir.hasValidParentId()) { + if (!currentDir.hasValidParentId()) { Log_OC.e(TAG, "❌ Current directory has invalid ID: ${currentDir.fileId}. Path: $filePath") return Result.failure() } @@ -57,7 +57,7 @@ class MetadataWorker(private val context: Context, params: WorkerParameters, pri // Re-fetch the folder after refresh to get updated data val refreshedDir = storageManager.getFileByPath(filePath) - if (refreshedDir == null || refreshedDir.hasValidParentId()) { + if (refreshedDir == null || !refreshedDir.hasValidParentId()) { Log_OC.e(TAG, "❌ Directory invalid after refresh. Path: $filePath") return Result.failure() } @@ -68,7 +68,7 @@ class MetadataWorker(private val context: Context, params: WorkerParameters, pri var failedCount = 0 subfolders.forEach { subFolder -> - if (subFolder.hasValidParentId()) { + if (!subFolder.hasValidParentId()) { Log_OC.e(TAG, "❌ Skipping subfolder with invalid ID: ${subFolder.remotePath}") failedCount++ return@forEach @@ -95,7 +95,7 @@ class MetadataWorker(private val context: Context, params: WorkerParameters, pri " eTag: " + folder.etag + "\n" + " eTagOnServer: " + folder.etagOnServer ) - if (folder.hasValidParentId()) { + if (!folder.hasValidParentId()) { Log_OC.e(TAG, "❌ Folder has invalid ID: ${folder.remotePath}") return@withContext false } From b9b11f30a9f43bfb5350eef32501172d14bc0ebb Mon Sep 17 00:00:00 2001 From: alperozturk Date: Mon, 15 Dec 2025 15:31:28 +0100 Subject: [PATCH 098/216] handle metadata worker edge cases Signed-off-by: alperozturk --- .../main/java/com/owncloud/android/datamodel/OCFile.java | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/app/src/main/java/com/owncloud/android/datamodel/OCFile.java b/app/src/main/java/com/owncloud/android/datamodel/OCFile.java index 753f8fca9d84..03d85e22a902 100644 --- a/app/src/main/java/com/owncloud/android/datamodel/OCFile.java +++ b/app/src/main/java/com/owncloud/android/datamodel/OCFile.java @@ -1169,6 +1169,10 @@ public boolean isRecommendedFile() { // only root directories parent id can be 0 public boolean hasValidParentId() { - return !isRootDirectory() && getParentId() != 0; + if (isRootDirectory()) { + return getParentId() == 0; + } else { + return getParentId() != 0; + } } } From 1382a79787df01598da50f1c65c368155651fb6a Mon Sep 17 00:00:00 2001 From: alperozturk Date: Mon, 15 Dec 2025 15:33:34 +0100 Subject: [PATCH 099/216] handle metadata worker edge cases Signed-off-by: alperozturk --- .../java/com/nextcloud/client/jobs/metadata/MetadataWorker.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/src/main/java/com/nextcloud/client/jobs/metadata/MetadataWorker.kt b/app/src/main/java/com/nextcloud/client/jobs/metadata/MetadataWorker.kt index 30bedb87e978..057268c7287f 100644 --- a/app/src/main/java/com/nextcloud/client/jobs/metadata/MetadataWorker.kt +++ b/app/src/main/java/com/nextcloud/client/jobs/metadata/MetadataWorker.kt @@ -102,7 +102,7 @@ class MetadataWorker(private val context: Context, params: WorkerParameters, pri if (!folder.isEtagChanged) { Log_OC.d(TAG, "Skipping ${folder.remotePath}, eTag didn't change") - return@withContext false + return@withContext true } Log_OC.d(TAG, "⏳ Fetching metadata for: ${folder.remotePath}, id: ${folder.fileId}") From 98b3371f039e1f12d18b8cbef98a83621459a6e8 Mon Sep 17 00:00:00 2001 From: alperozturk Date: Thu, 18 Dec 2025 14:53:14 +0100 Subject: [PATCH 100/216] show search button Signed-off-by: alperozturk --- .../android/ui/adapter/OCFileListAdapter.java | 13 ------------- .../android/ui/adapter/OCFileListDelegate.kt | 2 -- 2 files changed, 15 deletions(-) diff --git a/app/src/main/java/com/owncloud/android/ui/adapter/OCFileListAdapter.java b/app/src/main/java/com/owncloud/android/ui/adapter/OCFileListAdapter.java index d8471ec1e2c2..08f690ccbe93 100644 --- a/app/src/main/java/com/owncloud/android/ui/adapter/OCFileListAdapter.java +++ b/app/src/main/java/com/owncloud/android/ui/adapter/OCFileListAdapter.java @@ -12,9 +12,7 @@ import android.accounts.AccountManager; import android.annotation.SuppressLint; import android.app.Activity; -import android.content.ComponentCallbacks; import android.content.res.ColorStateList; -import android.content.res.Configuration; import android.content.res.Resources; import android.graphics.Color; import android.graphics.drawable.Drawable; @@ -189,17 +187,6 @@ public OCFileListAdapter( // initialise thumbnails cache on background thread ThumbnailsCacheManager.initDiskCacheAsync(); isRTL = DisplayUtils.isRTL(); - - activity.registerComponentCallbacks(new ComponentCallbacks() { - @SuppressLint("NotifyDataSetChanged") - @Override - public void onConfigurationChanged(@NonNull Configuration newConfig) { - notifyDataSetChanged(); // force update of orientation-dependent layout (e.g. share button visibility) - } - @Override - public void onLowMemory() { - } - }); } public boolean isMultiSelect() { diff --git a/app/src/main/java/com/owncloud/android/ui/adapter/OCFileListDelegate.kt b/app/src/main/java/com/owncloud/android/ui/adapter/OCFileListDelegate.kt index 638faacd7596..3d3437785e5d 100644 --- a/app/src/main/java/com/owncloud/android/ui/adapter/OCFileListDelegate.kt +++ b/app/src/main/java/com/owncloud/android/ui/adapter/OCFileListDelegate.kt @@ -8,7 +8,6 @@ package com.owncloud.android.ui.adapter import android.content.Context -import android.content.res.Configuration import android.view.View import android.widget.ImageView import androidx.core.content.ContextCompat @@ -218,7 +217,6 @@ class OCFileListDelegate( // shares val shouldHideShare = ( hideItemOptions || - context.resources.configuration.orientation == Configuration.ORIENTATION_PORTRAIT || !file.isFolder && file.isEncrypted || file.isEncrypted && From 3d214b93c7c11ba3a6ca70fbee06bc81b062e73d Mon Sep 17 00:00:00 2001 From: alperozturk Date: Wed, 17 Dec 2025 15:51:12 +0100 Subject: [PATCH 101/216] fix: empty all files Signed-off-by: alperozturk --- .../com/owncloud/android/ui/activity/FileDisplayActivity.kt | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/app/src/main/java/com/owncloud/android/ui/activity/FileDisplayActivity.kt b/app/src/main/java/com/owncloud/android/ui/activity/FileDisplayActivity.kt index 5914cbf61f39..10a23643efe4 100644 --- a/app/src/main/java/com/owncloud/android/ui/activity/FileDisplayActivity.kt +++ b/app/src/main/java/com/owncloud/android/ui/activity/FileDisplayActivity.kt @@ -564,8 +564,10 @@ class FileDisplayActivity : ALL_FILES == action -> { Log_OC.d(this, "Switch to oc file fragment") menuItemId = R.id.nav_all_files - leftFragment = OCFileListFragment() - supportFragmentManager.executePendingTransactions() + if (leftFragment !is OCFileListFragment) { + leftFragment = OCFileListFragment() + supportFragmentManager.executePendingTransactions() + } browseToRoot() } From e49509e7bac0b1917d9583c8b0cf48c386166b2a Mon Sep 17 00:00:00 2001 From: alperozturk Date: Tue, 16 Dec 2025 12:04:20 +0100 Subject: [PATCH 102/216] fix: upsert single file Signed-off-by: alperozturk --- .../providers/FileContentProvider.java | 74 ++++++++++++------- 1 file changed, 46 insertions(+), 28 deletions(-) diff --git a/app/src/main/java/com/owncloud/android/providers/FileContentProvider.java b/app/src/main/java/com/owncloud/android/providers/FileContentProvider.java index 19e5fc0b2f4a..c4c4c90d0697 100644 --- a/app/src/main/java/com/owncloud/android/providers/FileContentProvider.java +++ b/app/src/main/java/com/owncloud/android/providers/FileContentProvider.java @@ -42,6 +42,7 @@ import androidx.annotation.NonNull; import androidx.annotation.Nullable; import androidx.annotation.VisibleForTesting; +import androidx.sqlite.db.SimpleSQLiteQuery; import androidx.sqlite.db.SupportSQLiteDatabase; import androidx.sqlite.db.SupportSQLiteOpenHelper; import androidx.sqlite.db.SupportSQLiteQuery; @@ -234,34 +235,7 @@ private Uri insert(SupportSQLiteDatabase db, Uri uri, ContentValues values) { switch (mUriMatcher.match(uri)) { case ROOT_DIRECTORY: case SINGLE_FILE: - String where = ProviderTableMeta.FILE_PATH + "=? AND " + ProviderTableMeta.FILE_ACCOUNT_OWNER + "=?"; - - String remotePath = values.getAsString(ProviderTableMeta.FILE_PATH); - String accountName = values.getAsString(ProviderTableMeta.FILE_ACCOUNT_OWNER); - String[] whereArgs = {remotePath, accountName}; - - Cursor doubleCheck = query(db, uri, PROJECTION_FILE_PATH_AND_OWNER, where, whereArgs, null); - // ugly patch; serious refactoring is needed to reduce work in - // FileDataStorageManager and bring it to FileContentProvider - if (!doubleCheck.moveToFirst()) { - doubleCheck.close(); - long rowId = db.insert(ProviderTableMeta.FILE_TABLE_NAME, SQLiteDatabase.CONFLICT_REPLACE, values); - if (rowId > 0) { - return ContentUris.withAppendedId(ProviderTableMeta.CONTENT_URI_FILE, rowId); - } else { - throw new SQLException(ERROR + uri); - } - } else { - // file is already inserted; race condition, let's avoid a duplicated entry - Uri insertedFileUri = ContentUris.withAppendedId( - ProviderTableMeta.CONTENT_URI_FILE, - doubleCheck.getLong(doubleCheck.getColumnIndexOrThrow(ProviderTableMeta._ID)) - ); - doubleCheck.close(); - - return insertedFileUri; - } - + return upsertSingleFile(db, uri, values); case SHARES: Uri insertedShareUri; long idShares = db.insert(ProviderTableMeta.OCSHARES_TABLE_NAME, SQLiteDatabase.CONFLICT_REPLACE, values); @@ -343,6 +317,50 @@ private Uri insert(SupportSQLiteDatabase db, Uri uri, ContentValues values) { } } + private Uri upsertSingleFile(SupportSQLiteDatabase db, Uri uri, ContentValues values) { + String filePath = values.getAsString(ProviderTableMeta.FILE_PATH); + String accountOwner = values.getAsString(ProviderTableMeta.FILE_ACCOUNT_OWNER); + + String where = ProviderTableMeta.FILE_PATH + "=? AND " + ProviderTableMeta.FILE_ACCOUNT_OWNER + "=?"; + String[] whereArgs = {filePath, accountOwner}; + + // Try insert first, ignore conflict + long rowId = db.insert( + ProviderTableMeta.FILE_TABLE_NAME, + SQLiteDatabase.CONFLICT_IGNORE, + values); + + if (rowId <= 0) { + // Already exists: update + int count = db.update( + ProviderTableMeta.FILE_TABLE_NAME, + SQLiteDatabase.CONFLICT_NONE, + values, + where, + whereArgs); + + if (count == 0) { + throw new SQLException("Failed to update existing file: " + uri); + } + + try (Cursor cursor = db.query( + new SimpleSQLiteQuery( + "SELECT " + ProviderTableMeta._ID + + " FROM " + ProviderTableMeta.FILE_TABLE_NAME + + " WHERE " + where, + whereArgs + ))) { + if (cursor.moveToFirst()) { + rowId = cursor.getLong(0); + } else { + throw new SQLException("Failed to fetch ID after update: " + uri); + } + } + } + + return ContentUris.withAppendedId(ProviderTableMeta.CONTENT_URI_FILE, rowId); + } + private void updateFilesTableAccordingToShareInsertion(SupportSQLiteDatabase db, ContentValues newShare) { ContentValues fileValues = new ContentValues(); Integer shareTypeValue = newShare.getAsInteger(ProviderTableMeta.OCSHARES_SHARE_TYPE); From f2803b89b3153671617c0493bad4f46280078b11 Mon Sep 17 00:00:00 2001 From: alperozturk Date: Tue, 16 Dec 2025 12:43:33 +0100 Subject: [PATCH 103/216] add tests for upsert file Signed-off-by: alperozturk --- .../providers/FileContentProviderTests.kt | 157 ++++++++++++++++++ .../providers/FileContentProvider.java | 2 +- 2 files changed, 158 insertions(+), 1 deletion(-) create mode 100644 app/src/androidTest/java/com/owncloud/android/providers/FileContentProviderTests.kt diff --git a/app/src/androidTest/java/com/owncloud/android/providers/FileContentProviderTests.kt b/app/src/androidTest/java/com/owncloud/android/providers/FileContentProviderTests.kt new file mode 100644 index 000000000000..6064af2d56fe --- /dev/null +++ b/app/src/androidTest/java/com/owncloud/android/providers/FileContentProviderTests.kt @@ -0,0 +1,157 @@ +/* + * Nextcloud - Android Client + * + * SPDX-FileCopyrightText: 2025 Alper Ozturk + * SPDX-License-Identifier: AGPL-3.0-or-later + */ + +package com.owncloud.android.providers + +import android.content.ContentValues +import android.content.ContentUris +import android.net.Uri +import androidx.sqlite.db.SimpleSQLiteQuery +import androidx.sqlite.db.SupportSQLiteDatabase +import com.owncloud.android.db.ProviderMeta +import io.mockk.Runs +import io.mockk.every +import io.mockk.just +import io.mockk.mockk +import kotlinx.coroutines.async +import kotlinx.coroutines.awaitAll +import kotlinx.coroutines.coroutineScope +import kotlinx.coroutines.runBlocking +import org.junit.Assert.assertEquals +import org.junit.Assert.assertTrue +import org.junit.Before +import org.junit.Test + +class FileContentProviderTests { + + private lateinit var provider: FileContentProvider + private lateinit var db: SupportSQLiteDatabase + + @Before + fun setup() { + provider = FileContentProvider() + db = mockk() + } + + @Test + fun insertNewFileShouldReturnNewId() { + val values = ContentValues().apply { + put(ProviderMeta.ProviderTableMeta.FILE_PATH, "/path/to/file.txt") + put(ProviderMeta.ProviderTableMeta.FILE_ACCOUNT_OWNER, "user@example.com") + } + + // Mock insert to return new ID + every { db.insert(any(), any(), any()) } returns 42L + + val result: Uri = provider.upsertSingleFile( + db, + ProviderMeta.ProviderTableMeta.CONTENT_URI_FILE, + values + ) + + assertEquals( + ContentUris.withAppendedId(ProviderMeta.ProviderTableMeta.CONTENT_URI_FILE, 42), + result + ) + } + + @Test + fun updateExistingFileShouldReturnSameId() { + val values = ContentValues().apply { + put(ProviderMeta.ProviderTableMeta.FILE_PATH, "/path/to/file.txt") + put(ProviderMeta.ProviderTableMeta.FILE_ACCOUNT_OWNER, "user@example.com") + } + + // Simulate insert conflict + every { db.insert(ProviderMeta.ProviderTableMeta.FILE_TABLE_NAME, any(), values) } returns -1L + + // Simulate update returning 1 row affected + every { + db.update( + ProviderMeta.ProviderTableMeta.FILE_TABLE_NAME, + any(), + values, + any(), + any() + ) + } returns 1 + + // Mock cursor to return ID 99 + val cursor = mockk() + every { cursor.moveToFirst() } returns true + every { cursor.getLong(0) } returns 99L + every { cursor.close() } just Runs + + every { db.query(any()) } returns cursor + + val result: Uri = provider.upsertSingleFile( + db, + ProviderMeta.ProviderTableMeta.CONTENT_URI_FILE, + values + ) + + assertEquals(ContentUris.withAppendedId(ProviderMeta.ProviderTableMeta.CONTENT_URI_FILE, 99), result) + + cursor.close() + } + + @Test + fun testConcurrentUpserts() = runBlocking { + val values = ContentValues().apply { + put(ProviderMeta.ProviderTableMeta.FILE_PATH, "/path/to/file.txt") + put(ProviderMeta.ProviderTableMeta.FILE_ACCOUNT_OWNER, "user@example.com") + } + + // shared state to simulate race + val inserted = mutableListOf() + + // mock insert: fail first call, succeed second + every { db.insert(any(), any(), any()) } answers { + synchronized(inserted) { + if (inserted.isEmpty()) { + // first thread "fails" insert which means already existing file id will be returned + inserted.add(-1L) + -1L + } else { + // second thread "succeeds" it will update existing one + inserted.add(42L) + 42L + } + } + } + + // mock update only one row should be affected + every { db.update(any(), any(), any(), any(), any()) } returns 1 + + // mock query existing file id will return 99 + val cursor = mockk() + every { cursor.moveToFirst() } returns true + every { cursor.getLong(0) } returns 99L + every { cursor.close() } just Runs + every { db.query(any()) } returns cursor + + // launch two coroutines simulating concurrent threads + val results = mutableListOf() + coroutineScope { + val job1 = + async { + results.add(provider.upsertSingleFile(db, ProviderMeta.ProviderTableMeta.CONTENT_URI_FILE, values)) + } + val job2 = + async { + results.add(provider.upsertSingleFile(db, ProviderMeta.ProviderTableMeta.CONTENT_URI_FILE, values)) + } + awaitAll(job1, job2) + } + + // both URIs should be correct (one updated, one inserted) + assertTrue(results.contains(ContentUris.withAppendedId(ProviderMeta.ProviderTableMeta.CONTENT_URI_FILE, 99))) + assertTrue(results.contains(ContentUris.withAppendedId(ProviderMeta.ProviderTableMeta.CONTENT_URI_FILE, 42))) + + cursor.close() + } +} diff --git a/app/src/main/java/com/owncloud/android/providers/FileContentProvider.java b/app/src/main/java/com/owncloud/android/providers/FileContentProvider.java index c4c4c90d0697..47ecdab72fcd 100644 --- a/app/src/main/java/com/owncloud/android/providers/FileContentProvider.java +++ b/app/src/main/java/com/owncloud/android/providers/FileContentProvider.java @@ -317,7 +317,7 @@ private Uri insert(SupportSQLiteDatabase db, Uri uri, ContentValues values) { } } - private Uri upsertSingleFile(SupportSQLiteDatabase db, Uri uri, ContentValues values) { + public Uri upsertSingleFile(SupportSQLiteDatabase db, Uri uri, ContentValues values) { String filePath = values.getAsString(ProviderTableMeta.FILE_PATH); String accountOwner = values.getAsString(ProviderTableMeta.FILE_ACCOUNT_OWNER); From a6916c574a5c965093e70482f9a253ace6a1de02 Mon Sep 17 00:00:00 2001 From: alperozturk Date: Tue, 16 Dec 2025 13:14:16 +0100 Subject: [PATCH 104/216] add tests for upsert file Signed-off-by: alperozturk --- .../com/owncloud/android/providers/FileContentProviderTests.kt | 1 + 1 file changed, 1 insertion(+) diff --git a/app/src/androidTest/java/com/owncloud/android/providers/FileContentProviderTests.kt b/app/src/androidTest/java/com/owncloud/android/providers/FileContentProviderTests.kt index 6064af2d56fe..8027feb9bd08 100644 --- a/app/src/androidTest/java/com/owncloud/android/providers/FileContentProviderTests.kt +++ b/app/src/androidTest/java/com/owncloud/android/providers/FileContentProviderTests.kt @@ -26,6 +26,7 @@ import org.junit.Assert.assertTrue import org.junit.Before import org.junit.Test +@Suppress("MagicNumber") class FileContentProviderTests { private lateinit var provider: FileContentProvider From fe1f5f408de98aa5bc7b6add44a94b4c6db48ebc Mon Sep 17 00:00:00 2001 From: alperozturk Date: Mon, 15 Dec 2025 09:07:23 +0100 Subject: [PATCH 105/216] fix(auto-upload): remove not-existing local files without restarting Signed-off-by: alperozturk # Conflicts: # app/src/main/java/com/nextcloud/client/jobs/autoUpload/FileSystemRepository.kt --- .../client/database/dao/FileSystemDao.kt | 12 ++++++++++++ .../client/jobs/autoUpload/AutoUploadWorker.kt | 15 ++++++++++++--- 2 files changed, 24 insertions(+), 3 deletions(-) diff --git a/app/src/main/java/com/nextcloud/client/database/dao/FileSystemDao.kt b/app/src/main/java/com/nextcloud/client/database/dao/FileSystemDao.kt index 3dc90d77b318..17cc14e7dc02 100644 --- a/app/src/main/java/com/nextcloud/client/database/dao/FileSystemDao.kt +++ b/app/src/main/java/com/nextcloud/client/database/dao/FileSystemDao.kt @@ -19,6 +19,18 @@ interface FileSystemDao { @Insert(onConflict = OnConflictStrategy.REPLACE) fun insertOrReplace(filesystemEntity: FilesystemEntity) + @Query( + """ + DELETE FROM ${ProviderMeta.ProviderTableMeta.FILESYSTEM_TABLE_NAME} + WHERE ${ProviderMeta.ProviderTableMeta.FILESYSTEM_FILE_LOCAL_PATH} = :localPath + AND ${ProviderMeta.ProviderTableMeta._ID} = :id + """ + ) + suspend fun deleteByLocalPathAndId( + localPath: String, + id: Int + ) + @Query( """ SELECT * diff --git a/app/src/main/java/com/nextcloud/client/jobs/autoUpload/AutoUploadWorker.kt b/app/src/main/java/com/nextcloud/client/jobs/autoUpload/AutoUploadWorker.kt index e1fc93df33bc..2df77d2f164c 100644 --- a/app/src/main/java/com/nextcloud/client/jobs/autoUpload/AutoUploadWorker.kt +++ b/app/src/main/java/com/nextcloud/client/jobs/autoUpload/AutoUploadWorker.kt @@ -321,6 +321,15 @@ class AutoUploadWorker( try { var (uploadEntity, upload) = createEntityAndUpload(user, localPath, remotePath) + + // if local file deleted, upload cannot be or retriable thus needs to be removed + if (path.isEmpty() || !file.exists()) { + Log_OC.w(TAG, "detected not existing local file, removing entity") + repository.deleteByLocalPathAndId(path, id) + uploadsStorageManager.removeUpload(upload) + continue + } + try { // Insert/update to IN_PROGRESS state before starting upload val generatedId = uploadsStorageManager.uploadDao.insertOrReplace(uploadEntity) @@ -366,10 +375,10 @@ class AutoUploadWorker( "Exception uploadFiles during creating entity and upload, localPath: $localPath, " + "remotePath: $remotePath, exception: $e" ) + } finally { + // update last id so upload can continue where it left + lastId = id } - - // update last id so upload can continue where it left - lastId = id } } } From af690a1473aa19000b24cabc3ddd07c655aca1f8 Mon Sep 17 00:00:00 2001 From: alperozturk Date: Mon, 15 Dec 2025 09:09:54 +0100 Subject: [PATCH 106/216] fix(auto-upload): remove not-existing local files without restarting Signed-off-by: alperozturk --- .../java/com/nextcloud/client/database/dao/FileSystemDao.kt | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/app/src/main/java/com/nextcloud/client/database/dao/FileSystemDao.kt b/app/src/main/java/com/nextcloud/client/database/dao/FileSystemDao.kt index 17cc14e7dc02..91a03044afde 100644 --- a/app/src/main/java/com/nextcloud/client/database/dao/FileSystemDao.kt +++ b/app/src/main/java/com/nextcloud/client/database/dao/FileSystemDao.kt @@ -26,10 +26,7 @@ interface FileSystemDao { AND ${ProviderMeta.ProviderTableMeta._ID} = :id """ ) - suspend fun deleteByLocalPathAndId( - localPath: String, - id: Int - ) + suspend fun deleteByLocalPathAndId(localPath: String, id: Int) @Query( """ From ce6ecda1caec291cb102828c694448bff06a4c7c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alper=20=C3=96zt=C3=BCrk?= <67455295+alperozturk96@users.noreply.github.com> Date: Mon, 15 Dec 2025 10:12:15 +0100 Subject: [PATCH 107/216] Update app/src/main/java/com/nextcloud/client/jobs/autoUpload/AutoUploadWorker.kt MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Andy Scherzinger Signed-off-by: Alper Öztürk <67455295+alperozturk96@users.noreply.github.com> --- .../com/nextcloud/client/jobs/autoUpload/AutoUploadWorker.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/src/main/java/com/nextcloud/client/jobs/autoUpload/AutoUploadWorker.kt b/app/src/main/java/com/nextcloud/client/jobs/autoUpload/AutoUploadWorker.kt index 2df77d2f164c..736e7550746e 100644 --- a/app/src/main/java/com/nextcloud/client/jobs/autoUpload/AutoUploadWorker.kt +++ b/app/src/main/java/com/nextcloud/client/jobs/autoUpload/AutoUploadWorker.kt @@ -324,7 +324,7 @@ class AutoUploadWorker( // if local file deleted, upload cannot be or retriable thus needs to be removed if (path.isEmpty() || !file.exists()) { - Log_OC.w(TAG, "detected not existing local file, removing entity") + Log_OC.w(TAG, "detected non-existing local file, removing entity") repository.deleteByLocalPathAndId(path, id) uploadsStorageManager.removeUpload(upload) continue From cd7eee275891efd4c407cae83608c0e8af8b2768 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alper=20=C3=96zt=C3=BCrk?= <67455295+alperozturk96@users.noreply.github.com> Date: Mon, 15 Dec 2025 10:13:24 +0100 Subject: [PATCH 108/216] Apply suggestion from @alperozturk96 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Alper Öztürk <67455295+alperozturk96@users.noreply.github.com> --- .../com/nextcloud/client/jobs/autoUpload/AutoUploadWorker.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/src/main/java/com/nextcloud/client/jobs/autoUpload/AutoUploadWorker.kt b/app/src/main/java/com/nextcloud/client/jobs/autoUpload/AutoUploadWorker.kt index 736e7550746e..8484dca92950 100644 --- a/app/src/main/java/com/nextcloud/client/jobs/autoUpload/AutoUploadWorker.kt +++ b/app/src/main/java/com/nextcloud/client/jobs/autoUpload/AutoUploadWorker.kt @@ -322,7 +322,7 @@ class AutoUploadWorker( try { var (uploadEntity, upload) = createEntityAndUpload(user, localPath, remotePath) - // if local file deleted, upload cannot be or retriable thus needs to be removed + // if local file deleted, upload process cannot be started or retriable thus needs to be removed if (path.isEmpty() || !file.exists()) { Log_OC.w(TAG, "detected non-existing local file, removing entity") repository.deleteByLocalPathAndId(path, id) From 8b48ebda358544f3281271f9f3b630aa600037a6 Mon Sep 17 00:00:00 2001 From: alperozturk Date: Wed, 17 Dec 2025 08:51:14 +0100 Subject: [PATCH 109/216] fix: check deleted files for local behaviour delete Signed-off-by: alperozturk --- .../client/jobs/autoUpload/AutoUploadWorker.kt | 8 ++++++-- .../android/operations/UploadFileOperation.java | 16 ++++++++++++++++ 2 files changed, 22 insertions(+), 2 deletions(-) diff --git a/app/src/main/java/com/nextcloud/client/jobs/autoUpload/AutoUploadWorker.kt b/app/src/main/java/com/nextcloud/client/jobs/autoUpload/AutoUploadWorker.kt index 8484dca92950..b01d0643cb96 100644 --- a/app/src/main/java/com/nextcloud/client/jobs/autoUpload/AutoUploadWorker.kt +++ b/app/src/main/java/com/nextcloud/client/jobs/autoUpload/AutoUploadWorker.kt @@ -325,8 +325,7 @@ class AutoUploadWorker( // if local file deleted, upload process cannot be started or retriable thus needs to be removed if (path.isEmpty() || !file.exists()) { Log_OC.w(TAG, "detected non-existing local file, removing entity") - repository.deleteByLocalPathAndId(path, id) - uploadsStorageManager.removeUpload(upload) + deleteNonExistingFile(path, id, upload) continue } @@ -383,6 +382,11 @@ class AutoUploadWorker( } } + private suspend fun deleteNonExistingFile(path: String, id: Int, upload: OCUpload) { + repository.deleteByLocalPathAndId(path, id) + uploadsStorageManager.removeUpload(upload) + } + private fun createEntityAndUpload(user: User, localPath: String, remotePath: String): Pair { val (needsCharging, needsWifi, uploadAction) = getUploadSettings(syncedFolder) Log_OC.d(TAG, "creating oc upload for ${user.accountName}") diff --git a/app/src/main/java/com/owncloud/android/operations/UploadFileOperation.java b/app/src/main/java/com/owncloud/android/operations/UploadFileOperation.java index 9bafd4fe593c..39e524594f5a 100644 --- a/app/src/main/java/com/owncloud/android/operations/UploadFileOperation.java +++ b/app/src/main/java/com/owncloud/android/operations/UploadFileOperation.java @@ -1283,6 +1283,19 @@ public void handleLocalBehaviour() { handleLocalBehaviour(temporalFile, expectedFile, originalFile, client); } + private void deleteNonExistingFile(File file) { + if (file.exists()) { + return; + } + + Log_OC.d(TAG, "deleting non-existing file from upload list and file list"); + + uploadsStorageManager.removeUpload(mOCUploadId); + + // some chunks can be uploaded and can still exists in db thus we have to remove it as well + getStorageManager().removeFile(mFile, true, true); + } + private void handleLocalBehaviour(File temporalFile, File expectedFile, File originalFile, @@ -1293,6 +1306,9 @@ private void handleLocalBehaviour(File temporalFile, Files.delete(originalFile.toPath()); } catch (IOException e) { Log_OC.e(TAG, "Could not delete original file: " + originalFile.getAbsolutePath(), e); + + // if file is not exists we should only delete from our app + deleteNonExistingFile(originalFile); } mFile.setStoragePath(""); getStorageManager().deleteFileInMediaScan(originalFile.getAbsolutePath()); From 4a347c82ee382eb42e2f542b2c88587448bde9e2 Mon Sep 17 00:00:00 2001 From: alperozturk Date: Wed, 17 Dec 2025 09:13:33 +0100 Subject: [PATCH 110/216] fix: check deleted files for other local behaviour Signed-off-by: alperozturk --- .../android/operations/UploadFileOperation.java | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-) diff --git a/app/src/main/java/com/owncloud/android/operations/UploadFileOperation.java b/app/src/main/java/com/owncloud/android/operations/UploadFileOperation.java index 39e524594f5a..f13c73704962 100644 --- a/app/src/main/java/com/owncloud/android/operations/UploadFileOperation.java +++ b/app/src/main/java/com/owncloud/android/operations/UploadFileOperation.java @@ -1300,15 +1300,21 @@ private void handleLocalBehaviour(File temporalFile, File expectedFile, File originalFile, OwnCloudClient client) { + + // only LOCAL_BEHAVIOUR_COPY not using original file + if (mLocalBehaviour != FileUploadWorker.LOCAL_BEHAVIOUR_COPY) { + // if file is not exists we should only delete from our app + deleteNonExistingFile(originalFile); + } + + Log_OC.d(TAG, "handling local behaviour for: " + originalFile.getName() + " behaviour: " + mLocalBehaviour); + switch (mLocalBehaviour) { case FileUploadWorker.LOCAL_BEHAVIOUR_DELETE: try { Files.delete(originalFile.toPath()); } catch (IOException e) { Log_OC.e(TAG, "Could not delete original file: " + originalFile.getAbsolutePath(), e); - - // if file is not exists we should only delete from our app - deleteNonExistingFile(originalFile); } mFile.setStoragePath(""); getStorageManager().deleteFileInMediaScan(originalFile.getAbsolutePath()); @@ -1321,6 +1327,9 @@ private void handleLocalBehaviour(File temporalFile, move(temporalFile, expectedFile); } catch (IOException e) { Log_OC.e(TAG, e.getMessage()); + + // handling non-existing file for local copy as well + deleteNonExistingFile(temporalFile); } } else if (originalFile != null) { try { From b5748458d0dbd6a40e2e2314b0bed06930618554 Mon Sep 17 00:00:00 2001 From: alperozturk Date: Wed, 17 Dec 2025 09:18:42 +0100 Subject: [PATCH 111/216] fix: check exception during auto upload for non-existing file Signed-off-by: alperozturk --- .../nextcloud/client/jobs/autoUpload/AutoUploadWorker.kt | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/app/src/main/java/com/nextcloud/client/jobs/autoUpload/AutoUploadWorker.kt b/app/src/main/java/com/nextcloud/client/jobs/autoUpload/AutoUploadWorker.kt index b01d0643cb96..b13ebabe7578 100644 --- a/app/src/main/java/com/nextcloud/client/jobs/autoUpload/AutoUploadWorker.kt +++ b/app/src/main/java/com/nextcloud/client/jobs/autoUpload/AutoUploadWorker.kt @@ -367,6 +367,12 @@ class AutoUploadWorker( "Exception during upload file, localPath: $localPath, remotePath: $remotePath," + " exception: $e" ) + + if (path.isEmpty() || !file.exists()) { + Log_OC.w(TAG, "detected non-existing local file, removing entity") + deleteNonExistingFile(path, id, upload) + continue + } } } catch (e: Exception) { Log_OC.e( From 83e8dd21d5286c4a7e62925d28410f7ee2f5d9bd Mon Sep 17 00:00:00 2001 From: alperozturk Date: Wed, 17 Dec 2025 11:10:43 +0100 Subject: [PATCH 112/216] fix git conflict Signed-off-by: alperozturk --- .../nextcloud/client/jobs/autoUpload/FileSystemRepository.kt | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/app/src/main/java/com/nextcloud/client/jobs/autoUpload/FileSystemRepository.kt b/app/src/main/java/com/nextcloud/client/jobs/autoUpload/FileSystemRepository.kt index 8cb6a74dc1ec..b322b1bc7fc4 100644 --- a/app/src/main/java/com/nextcloud/client/jobs/autoUpload/FileSystemRepository.kt +++ b/app/src/main/java/com/nextcloud/client/jobs/autoUpload/FileSystemRepository.kt @@ -28,6 +28,10 @@ class FileSystemRepository(private val dao: FileSystemDao, private val context: const val BATCH_SIZE = 50 } + suspend fun deleteByLocalPathAndId(path: String, id: Int) { + dao.deleteByLocalPathAndId(path, id) + } + suspend fun getFilePathsWithIds(syncedFolder: SyncedFolder, lastId: Int): List> { val syncedFolderId = syncedFolder.id.toString() Log_OC.d(TAG, "Fetching candidate files for syncedFolderId = $syncedFolderId") From 7edc507235f06d889b39e3b4ccfb872c9db7a624 Mon Sep 17 00:00:00 2001 From: alperozturk Date: Fri, 19 Dec 2025 08:56:56 +0100 Subject: [PATCH 113/216] fix: navigation from child oc file list fragment Signed-off-by: alperozturk --- .../android/ui/activity/FileDisplayActivity.kt | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/app/src/main/java/com/owncloud/android/ui/activity/FileDisplayActivity.kt b/app/src/main/java/com/owncloud/android/ui/activity/FileDisplayActivity.kt index 10a23643efe4..b3f4ead14303 100644 --- a/app/src/main/java/com/owncloud/android/ui/activity/FileDisplayActivity.kt +++ b/app/src/main/java/com/owncloud/android/ui/activity/FileDisplayActivity.kt @@ -564,10 +564,17 @@ class FileDisplayActivity : ALL_FILES == action -> { Log_OC.d(this, "Switch to oc file fragment") menuItemId = R.id.nav_all_files - if (leftFragment !is OCFileListFragment) { - leftFragment = OCFileListFragment() - supportFragmentManager.executePendingTransactions() + + // Replace only if the fragment is NOT exactly OCFileListFragment + // Using `is OCFileListFragment` would also match subclasses, + // its needed because reinitializing OCFileListFragment itself causes an empty screen + leftFragment?.let { + if (it::class != OCFileListFragment::class) { + leftFragment = OCFileListFragment() + supportFragmentManager.executePendingTransactions() + } } + browseToRoot() } From c65587e2cbf2f2202c98f6111c320522a7fd4f8e Mon Sep 17 00:00:00 2001 From: alperozturk Date: Fri, 19 Dec 2025 11:49:22 +0100 Subject: [PATCH 114/216] fix: loading state Signed-off-by: alperozturk --- .../ui/activity/FileDisplayActivity.kt | 39 ++++++------------- 1 file changed, 12 insertions(+), 27 deletions(-) diff --git a/app/src/main/java/com/owncloud/android/ui/activity/FileDisplayActivity.kt b/app/src/main/java/com/owncloud/android/ui/activity/FileDisplayActivity.kt index b3f4ead14303..f973795ebf23 100644 --- a/app/src/main/java/com/owncloud/android/ui/activity/FileDisplayActivity.kt +++ b/app/src/main/java/com/owncloud/android/ui/activity/FileDisplayActivity.kt @@ -197,7 +197,7 @@ class FileDisplayActivity : private var mSyncInProgress: Boolean = false set(value) { field = value - setBackgroundText() + setEmptyListState() } private var mWaitingToSend: OCFile? = null @@ -797,7 +797,6 @@ class FileDisplayActivity : setLeftFragment(fragment, true) } - @get:Deprecated("") val listOfFilesFragment: OCFileListFragment? get() { val listOfFiles = @@ -1531,7 +1530,6 @@ class FileDisplayActivity : syncResult: Any? ) { if (FileSyncAdapter.EVENT_FULL_SYNC_START == event) { - mSyncInProgress = true return } @@ -1548,14 +1546,7 @@ class FileDisplayActivity : } handleSyncResult(event, syncResult) - DataHolderUtil.getInstance().delete(id) - - mSyncInProgress = - FileSyncAdapter.EVENT_FULL_SYNC_END != event && - RefreshFolderOperation.EVENT_SINGLE_FOLDER_SHARES_SYNCED != event - Log_OC.d(TAG, "Setting progress visibility to $mSyncInProgress") - handleScrollBehaviour(fileListFragment) } @@ -1657,21 +1648,16 @@ class FileDisplayActivity : (syncResult.isException && syncResult.exception is AuthenticatorException) } - /** - * Show a text message on screen view for notifying user if content is loading or folder is empty - */ - private fun setBackgroundText() { - val ocFileListFragment = listOfFilesFragment ?: return - connectivityService.isNetworkAndServerAvailable { result: Boolean? -> + private fun setEmptyListState() { + listOfFilesFragment?.let { when { - mSyncInProgress && result == true -> { - ocFileListFragment.setEmptyListMessage(EmptyListState.LOADING) + mSyncInProgress -> { + it.setEmptyListMessage(EmptyListState.LOADING) } MainApp.isOnlyOnDevice() -> { - ocFileListFragment.setEmptyListMessage(EmptyListState.ONLY_ON_DEVICE) + it.setEmptyListMessage(EmptyListState.ONLY_ON_DEVICE) } - result == true -> ocFileListFragment.setEmptyListMessage(SearchType.NO_SEARCH) - else -> ocFileListFragment.setEmptyListMessage(EmptyListState.OFFLINE_MODE) + else -> it.setEmptyListMessage(SearchType.NO_SEARCH) } } } @@ -2404,19 +2390,20 @@ class FileDisplayActivity : // or if the method is called from a dialog that is being dismissed if (TextUtils.isEmpty(searchQuery) && user.isPresent) { + mSyncInProgress = true + handler.postDelayed({ val user = getUser() if (!ignoreFocus && !hasWindowFocus() || !user.isPresent) { // do not refresh if the user rotates the device while another window has focus // or if the current user is no longer valid + mSyncInProgress = false return@postDelayed } val currentSyncTime = System.currentTimeMillis() - mSyncInProgress = true - // perform folder synchronization - val refreshFolderOperation: RemoteOperation<*> = RefreshFolderOperation( + val operation = RefreshFolderOperation( folder, currentSyncTime, false, @@ -2425,7 +2412,7 @@ class FileDisplayActivity : user.get(), applicationContext ) - refreshFolderOperation.execute( + operation.execute( account, MainApp.getAppContext(), this@FileDisplayActivity, @@ -2434,8 +2421,6 @@ class FileDisplayActivity : ) fetchRecommendedFilesIfNeeded(ignoreETag, folder) - mSyncInProgress = false - ocFileListFragment?.setLoading(false) }, DELAY_TO_REQUEST_REFRESH_OPERATION_LATER) } } From 965ca756ee0bb743a2de65616f47410b85adc573 Mon Sep 17 00:00:00 2001 From: alperozturk Date: Mon, 15 Dec 2025 14:26:23 +0100 Subject: [PATCH 115/216] fix: search task root sub dir content fetch Signed-off-by: alperozturk --- .../ui/fragment/OCFileListSearchTask.kt | 47 +++++++++++++++++-- 1 file changed, 44 insertions(+), 3 deletions(-) diff --git a/app/src/main/java/com/owncloud/android/ui/fragment/OCFileListSearchTask.kt b/app/src/main/java/com/owncloud/android/ui/fragment/OCFileListSearchTask.kt index ef938616dd6c..44ea3d481c05 100644 --- a/app/src/main/java/com/owncloud/android/ui/fragment/OCFileListSearchTask.kt +++ b/app/src/main/java/com/owncloud/android/ui/fragment/OCFileListSearchTask.kt @@ -11,6 +11,7 @@ package com.owncloud.android.ui.fragment import android.annotation.SuppressLint import android.app.Activity import android.content.ContentValues +import android.content.Context import androidx.lifecycle.lifecycleScope import com.nextcloud.client.account.User import com.nextcloud.client.preferences.AppPreferences @@ -40,8 +41,9 @@ import kotlinx.coroutines.launch import kotlinx.coroutines.withContext import kotlinx.coroutines.withTimeoutOrNull import java.lang.ref.WeakReference +import java.util.concurrent.TimeUnit -@Suppress("LongParameterList", "ReturnCount", "TooGenericExceptionCaught") +@Suppress("LongParameterList", "ReturnCount", "TooGenericExceptionCaught", "DEPRECATION", "MagicNumber") @SuppressLint("NotifyDataSetChanged") class OCFileListSearchTask( containerActivity: FileFragment.ContainerActivity, @@ -64,7 +66,6 @@ class OCFileListSearchTask( private var job: Job? = null - @Suppress("TooGenericExceptionCaught", "DEPRECATION", "ReturnCount") fun execute() { Log_OC.d(TAG, "search task running, query: ${event.searchType}") val fragment = fragmentReference.get() ?: return @@ -105,6 +106,14 @@ class OCFileListSearchTask( fragment.adapter.files } + val subDirectories = newList + .filter { it.isFolder } + .sortedBy { it.fileId } + + subDirectories.forEach { dir -> + fetchRootSubDirContent(dir, fileDataStorageManager, fragment.context) + } + val sortedNewList = sortSearchData(newList, searchType, null, setNewSortOrder = { fragment.adapter.setSortOrder(it) }) @@ -126,6 +135,39 @@ class OCFileListSearchTask( fun isFinished(): Boolean = job?.isCompleted == true + private suspend fun fetchRootSubDirContent( + folder: OCFile, + storageManager: FileDataStorageManager?, + context: Context? + ) = withContext(Dispatchers.IO) { + if (context == null || storageManager == null) { + Log_OC.e(TAG, "sub directory content cannot be fetched, context or storage manager is null") + return@withContext + } + + val currentSyncTime = System.currentTimeMillis() + val shouldIgnoreETag = (currentSyncTime - folder.lastSyncDateForProperties) > TimeUnit.MINUTES.toMillis(5) + + Log_OC.d(TAG, "fetching content for: " + folder.remotePath + " ignore eTag: " + shouldIgnoreETag) + + val operation = + RefreshFolderOperation( + folder, + currentSyncTime, + shouldIgnoreETag, + shouldIgnoreETag, + storageManager, + currentUser, + context + ) + val result = operation.execute(currentUser, context) + if (result.isSuccess) { + Log_OC.d(TAG, "sub directory content is fetched") + } else { + Log_OC.e(TAG, "sub directory content cannot be fetched") + } + } + private suspend fun loadCachedDbFiles(searchType: SearchRemoteOperation.SearchType): List { val storage = fileDataStorageManager ?: return emptyList() return if (searchType == SearchRemoteOperation.SearchType.SHARED_FILTER) { @@ -137,7 +179,6 @@ class OCFileListSearchTask( }.mapNotNull { storage.createFileInstance(it) } } - @Suppress("DEPRECATION") private suspend fun fetchRemoteResults(): RemoteOperationResult>? { val fragment = fragmentReference.get() ?: return null val context = fragment.context ?: return null From 09d95ca209402c632a1c6dccf9acd7114a08d725 Mon Sep 17 00:00:00 2001 From: alperozturk Date: Mon, 15 Dec 2025 14:28:18 +0100 Subject: [PATCH 116/216] fix: search task root sub dir content fetch Signed-off-by: alperozturk --- .../com/owncloud/android/ui/fragment/OCFileListSearchTask.kt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/app/src/main/java/com/owncloud/android/ui/fragment/OCFileListSearchTask.kt b/app/src/main/java/com/owncloud/android/ui/fragment/OCFileListSearchTask.kt index 44ea3d481c05..d14f5648088a 100644 --- a/app/src/main/java/com/owncloud/android/ui/fragment/OCFileListSearchTask.kt +++ b/app/src/main/java/com/owncloud/android/ui/fragment/OCFileListSearchTask.kt @@ -111,7 +111,7 @@ class OCFileListSearchTask( .sortedBy { it.fileId } subDirectories.forEach { dir -> - fetchRootSubDirContent(dir, fileDataStorageManager, fragment.context) + fetchDirContent(dir, fileDataStorageManager, fragment.context) } val sortedNewList = sortSearchData(newList, searchType, null, setNewSortOrder = { @@ -135,7 +135,7 @@ class OCFileListSearchTask( fun isFinished(): Boolean = job?.isCompleted == true - private suspend fun fetchRootSubDirContent( + private suspend fun fetchDirContent( folder: OCFile, storageManager: FileDataStorageManager?, context: Context? From 3f04e7a1ac6f53822543f6661570b2c4fab75f21 Mon Sep 17 00:00:00 2001 From: alperozturk Date: Wed, 17 Dec 2025 14:06:41 +0100 Subject: [PATCH 117/216] use saveFileWithParent Signed-off-by: alperozturk --- .../datamodel/FileDataStorageManager.java | 47 +++++++++++++------ .../operations/RefreshFolderOperation.java | 4 ++ .../ui/fragment/OCFileListSearchTask.kt | 44 +---------------- 3 files changed, 38 insertions(+), 57 deletions(-) diff --git a/app/src/main/java/com/owncloud/android/datamodel/FileDataStorageManager.java b/app/src/main/java/com/owncloud/android/datamodel/FileDataStorageManager.java index 01508657858e..bf07037568d7 100644 --- a/app/src/main/java/com/owncloud/android/datamodel/FileDataStorageManager.java +++ b/app/src/main/java/com/owncloud/android/datamodel/FileDataStorageManager.java @@ -547,15 +547,28 @@ public boolean saveFile(OCFile ocFile) { } /** - * traverses a files parent tree to be able to store a file with its parents. Throws a - * RemoteOperationFailedException in case the parent can't be retrieved. + * Ensures that an {@link OCFile} and all of its parent folders are stored locally. + *

+ * If the file has no parent ID and is not the root folder, this method recursively: + *

    + *
  • Resolves the parent path
  • + *
  • Loads the parent from local storage or fetches it from the server
  • + *
  • Saves all missing parent folders
  • + *
  • Assigns the resolved parent ID to the file
  • + *
+ * + * @param ocFile the file to be saved together with its parent hierarchy + * @param context Android context used for remote operations * - * @param ocFile the file - * @param context the app context - * @return the parent file + * @return the same {@link OCFile} instance with a valid parent ID + * + * @throws RemoteOperationFailedException if a parent folder cannot be retrieved + * from the server */ public OCFile saveFileWithParent(OCFile ocFile, Context context) { if (ocFile.getParentId() == 0 && !OCFile.ROOT_PATH.equals(ocFile.getRemotePath())) { + Log_OC.d(TAG, "saving file with parents: " + ocFile.getRemotePath()); + String remotePath = ocFile.getRemotePath(); String parentPath = remotePath.substring(0, remotePath.lastIndexOf(ocFile.getFileName())); @@ -563,19 +576,22 @@ public OCFile saveFileWithParent(OCFile ocFile, Context context) { OCFile returnFile; if (parentFile == null) { - // remote request - ReadFileRemoteOperation operation = new ReadFileRemoteOperation(parentPath); - // TODO Deprecated - RemoteOperationResult result = operation.execute(getUser(), context); - if (result.isSuccess()) { - OCFile remoteFolder = FileStorageUtils.fillOCFile((RemoteFile) result.getData().get(0)); - - returnFile = saveFileWithParent(remoteFolder, context); + Log_OC.d(TAG, "Parent not found locally, fetching: " + parentPath); + + final var operation = new ReadFileRemoteOperation(parentPath); + final var result = operation.execute(getUser(), context); + + if (result.isSuccess() && result.getData().get(0) instanceof RemoteFile remoteFile) { + OCFile folder = FileStorageUtils.fillOCFile(remoteFile); + Log_OC.d(TAG, "Fetched parent folder: " + folder); + returnFile = saveFileWithParent(folder, context); } else { Exception exception = result.getException(); String message = "Error during saving file with parents: " + ocFile.getRemotePath() + " / " + result.getLogMessage(context); + Log_OC.e(TAG, message); + if (exception != null) { throw new RemoteOperationFailedException(message, exception); } else { @@ -583,10 +599,13 @@ public OCFile saveFileWithParent(OCFile ocFile, Context context) { } } } else { + Log_OC.d(TAG, "parent file exists, calling saveFileWithParent: " + ocFile.getRemotePath()); returnFile = saveFileWithParent(parentFile, context); } - ocFile.setParentId(returnFile.getFileId()); + long parentId = returnFile.getFileId(); + Log_OC.d(TAG, "saving parent id of: " + ocFile.getRemotePath() + " with: " + parentId); + ocFile.setParentId(parentId); saveFile(ocFile); } diff --git a/app/src/main/java/com/owncloud/android/operations/RefreshFolderOperation.java b/app/src/main/java/com/owncloud/android/operations/RefreshFolderOperation.java index 43885e40ab89..d299a997b31e 100644 --- a/app/src/main/java/com/owncloud/android/operations/RefreshFolderOperation.java +++ b/app/src/main/java/com/owncloud/android/operations/RefreshFolderOperation.java @@ -267,6 +267,10 @@ protected RemoteOperationResult run(OwnCloudClient client) { updateUserProfile(); } + fileDataStorageManager.saveFileWithParent(mLocalFolder, mContext); + + Log_OC.d(TAG, "STEP 1 --- refreshing folder " + mLocalFolder.getRemotePath()); + result = checkForChanges(client); if (result.isSuccess()) { diff --git a/app/src/main/java/com/owncloud/android/ui/fragment/OCFileListSearchTask.kt b/app/src/main/java/com/owncloud/android/ui/fragment/OCFileListSearchTask.kt index d14f5648088a..2e96e5ac4b84 100644 --- a/app/src/main/java/com/owncloud/android/ui/fragment/OCFileListSearchTask.kt +++ b/app/src/main/java/com/owncloud/android/ui/fragment/OCFileListSearchTask.kt @@ -11,7 +11,6 @@ package com.owncloud.android.ui.fragment import android.annotation.SuppressLint import android.app.Activity import android.content.ContentValues -import android.content.Context import androidx.lifecycle.lifecycleScope import com.nextcloud.client.account.User import com.nextcloud.client.preferences.AppPreferences @@ -41,7 +40,6 @@ import kotlinx.coroutines.launch import kotlinx.coroutines.withContext import kotlinx.coroutines.withTimeoutOrNull import java.lang.ref.WeakReference -import java.util.concurrent.TimeUnit @Suppress("LongParameterList", "ReturnCount", "TooGenericExceptionCaught", "DEPRECATION", "MagicNumber") @SuppressLint("NotifyDataSetChanged") @@ -106,14 +104,6 @@ class OCFileListSearchTask( fragment.adapter.files } - val subDirectories = newList - .filter { it.isFolder } - .sortedBy { it.fileId } - - subDirectories.forEach { dir -> - fetchDirContent(dir, fileDataStorageManager, fragment.context) - } - val sortedNewList = sortSearchData(newList, searchType, null, setNewSortOrder = { fragment.adapter.setSortOrder(it) }) @@ -135,39 +125,6 @@ class OCFileListSearchTask( fun isFinished(): Boolean = job?.isCompleted == true - private suspend fun fetchDirContent( - folder: OCFile, - storageManager: FileDataStorageManager?, - context: Context? - ) = withContext(Dispatchers.IO) { - if (context == null || storageManager == null) { - Log_OC.e(TAG, "sub directory content cannot be fetched, context or storage manager is null") - return@withContext - } - - val currentSyncTime = System.currentTimeMillis() - val shouldIgnoreETag = (currentSyncTime - folder.lastSyncDateForProperties) > TimeUnit.MINUTES.toMillis(5) - - Log_OC.d(TAG, "fetching content for: " + folder.remotePath + " ignore eTag: " + shouldIgnoreETag) - - val operation = - RefreshFolderOperation( - folder, - currentSyncTime, - shouldIgnoreETag, - shouldIgnoreETag, - storageManager, - currentUser, - context - ) - val result = operation.execute(currentUser, context) - if (result.isSuccess) { - Log_OC.d(TAG, "sub directory content is fetched") - } else { - Log_OC.e(TAG, "sub directory content cannot be fetched") - } - } - private suspend fun loadCachedDbFiles(searchType: SearchRemoteOperation.SearchType): List { val storage = fileDataStorageManager ?: return emptyList() return if (searchType == SearchRemoteOperation.SearchType.SHARED_FILTER) { @@ -179,6 +136,7 @@ class OCFileListSearchTask( }.mapNotNull { storage.createFileInstance(it) } } + @Suppress("DEPRECATION") private suspend fun fetchRemoteResults(): RemoteOperationResult>? { val fragment = fragmentReference.get() ?: return null val context = fragment.context ?: return null From 2de8687fb513a13d26b35fc69f97a912c43d2f36 Mon Sep 17 00:00:00 2001 From: alperozturk Date: Wed, 17 Dec 2025 14:09:34 +0100 Subject: [PATCH 118/216] use saveFileWithParent Signed-off-by: alperozturk --- .../owncloud/android/operations/RefreshFolderOperation.java | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/app/src/main/java/com/owncloud/android/operations/RefreshFolderOperation.java b/app/src/main/java/com/owncloud/android/operations/RefreshFolderOperation.java index d299a997b31e..30409c523140 100644 --- a/app/src/main/java/com/owncloud/android/operations/RefreshFolderOperation.java +++ b/app/src/main/java/com/owncloud/android/operations/RefreshFolderOperation.java @@ -267,10 +267,9 @@ protected RemoteOperationResult run(OwnCloudClient client) { updateUserProfile(); } + // check first parent dirs are saved fileDataStorageManager.saveFileWithParent(mLocalFolder, mContext); - Log_OC.d(TAG, "STEP 1 --- refreshing folder " + mLocalFolder.getRemotePath()); - result = checkForChanges(client); if (result.isSuccess()) { From 153cca5f9b4525f3474bea501fa8d13632627cfe Mon Sep 17 00:00:00 2001 From: alperozturk Date: Thu, 18 Dec 2025 12:38:45 +0100 Subject: [PATCH 119/216] revert Signed-off-by: alperozturk --- .../com/owncloud/android/ui/fragment/OCFileListSearchTask.kt | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/app/src/main/java/com/owncloud/android/ui/fragment/OCFileListSearchTask.kt b/app/src/main/java/com/owncloud/android/ui/fragment/OCFileListSearchTask.kt index 2e96e5ac4b84..ef938616dd6c 100644 --- a/app/src/main/java/com/owncloud/android/ui/fragment/OCFileListSearchTask.kt +++ b/app/src/main/java/com/owncloud/android/ui/fragment/OCFileListSearchTask.kt @@ -41,7 +41,7 @@ import kotlinx.coroutines.withContext import kotlinx.coroutines.withTimeoutOrNull import java.lang.ref.WeakReference -@Suppress("LongParameterList", "ReturnCount", "TooGenericExceptionCaught", "DEPRECATION", "MagicNumber") +@Suppress("LongParameterList", "ReturnCount", "TooGenericExceptionCaught") @SuppressLint("NotifyDataSetChanged") class OCFileListSearchTask( containerActivity: FileFragment.ContainerActivity, @@ -64,6 +64,7 @@ class OCFileListSearchTask( private var job: Job? = null + @Suppress("TooGenericExceptionCaught", "DEPRECATION", "ReturnCount") fun execute() { Log_OC.d(TAG, "search task running, query: ${event.searchType}") val fragment = fragmentReference.get() ?: return From 299f44896dd896330b44bfb6ed1cf735f115407a Mon Sep 17 00:00:00 2001 From: alperozturk Date: Fri, 19 Dec 2025 11:18:52 +0100 Subject: [PATCH 120/216] fix etag saving logic Signed-off-by: alperozturk --- .../datamodel/FileDataStorageManager.java | 5 ++++- .../operations/RefreshFolderOperation.java | 20 +++++++------------ 2 files changed, 11 insertions(+), 14 deletions(-) diff --git a/app/src/main/java/com/owncloud/android/datamodel/FileDataStorageManager.java b/app/src/main/java/com/owncloud/android/datamodel/FileDataStorageManager.java index bf07037568d7..7a4f2e51ce88 100644 --- a/app/src/main/java/com/owncloud/android/datamodel/FileDataStorageManager.java +++ b/app/src/main/java/com/owncloud/android/datamodel/FileDataStorageManager.java @@ -51,7 +51,6 @@ import com.owncloud.android.MainApp; import com.owncloud.android.db.ProviderMeta.ProviderTableMeta; import com.owncloud.android.lib.common.network.WebdavEntry; -import com.owncloud.android.lib.common.operations.RemoteOperationResult; import com.owncloud.android.lib.common.utils.Log_OC; import com.owncloud.android.lib.resources.files.ReadFileRemoteOperation; import com.owncloud.android.lib.resources.files.model.FileLockType; @@ -497,9 +496,13 @@ public List getFolderImages(OCFile folder, boolean onlyOnDevice) { } public boolean saveFile(OCFile ocFile) { + Log_OC.d(TAG, "saving file: " + ocFile.getRemotePath() + " etag: " + ocFile.getEtag()); + boolean overridden = false; final ContentValues cv = createContentValuesForFile(ocFile); if (ocFile.isFolder()) { + // only refresh folder operation must update eTag otherwise content of the folder may stay as outdated + cv.remove(ProviderTableMeta.FILE_ETAG); cv.remove(ProviderTableMeta.FILE_STORAGE_PATH); } diff --git a/app/src/main/java/com/owncloud/android/operations/RefreshFolderOperation.java b/app/src/main/java/com/owncloud/android/operations/RefreshFolderOperation.java index 30409c523140..f760af5e0538 100644 --- a/app/src/main/java/com/owncloud/android/operations/RefreshFolderOperation.java +++ b/app/src/main/java/com/owncloud/android/operations/RefreshFolderOperation.java @@ -267,9 +267,6 @@ protected RemoteOperationResult run(OwnCloudClient client) { updateUserProfile(); } - // check first parent dirs are saved - fileDataStorageManager.saveFileWithParent(mLocalFolder, mContext); - result = checkForChanges(client); if (result.isSuccess()) { @@ -403,11 +400,6 @@ private void updatePredefinedStatus(ArbitraryDataProvider arbitraryDataProvider) private RemoteOperationResult checkForChanges(OwnCloudClient client) { mRemoteFolderChanged = true; - if (isMetadataSyncWorkerRunning) { - Log_OC.d(TAG, "Skipping eTag check since metadata worker already did"); - return new RemoteOperationResult<>(ResultCode.OK); - } - RemoteOperationResult result; String remotePath = mLocalFolder.getRemotePath(); @@ -417,16 +409,18 @@ private RemoteOperationResult checkForChanges(OwnCloudClient client) { result = new ReadFileRemoteOperation(remotePath).execute(client); if (result.isSuccess()) { - if (!mIgnoreETag && result.getData().get(0) instanceof RemoteFile remoteFile) { + OCFile remoteFolder = FileStorageUtils.fillOCFile((RemoteFile) result.getData().get(0)); + + if (!mIgnoreETag) { // check if remote and local folder are different - String remoteFolderETag = remoteFile.getEtag(); + String remoteFolderETag = remoteFolder.getEtag(); if (remoteFolderETag != null) { String localFolderEtag = mLocalFolder.getEtag(); mRemoteFolderChanged = StringExtensionsKt.eTagChanged(remoteFolderETag, localFolderEtag); Log_OC.d( TAG, "📂 eTag check\n" + - " Path: " + remoteFile.getRemotePath() + "\n" + + " Path: " + remoteFolder.getRemotePath() + "\n" + " Local eTag: " + localFolderEtag + "\n" + " Remote eTag: " + remoteFolderETag + "\n" + " Changed: " + mRemoteFolderChanged @@ -505,7 +499,7 @@ private void synchronizeData(List folderAndFiles) { mLocalFolder = fileDataStorageManager.getFileByPath(mLocalFolder.getRemotePath()); if (mLocalFolder == null) { - Log_OC.d(TAG,"mLocalFolder cannot be null"); + Log_OC.e(TAG,"mLocalFolder cannot be null"); return; } @@ -514,7 +508,7 @@ private void synchronizeData(List folderAndFiles) { remoteFolder.setParentId(mLocalFolder.getParentId()); remoteFolder.setFileId(mLocalFolder.getFileId()); - Log_OC.d(TAG, "Remote folder " + mLocalFolder.getRemotePath() + " changed - starting update of local data "); + Log_OC.d(TAG, "Remote folder path: " + mLocalFolder.getRemotePath() + " changed - starting update of local data "); List updatedFiles = new ArrayList<>(folderAndFiles.size() - 1); mFilesToSyncContents.clear(); From e3dfa42c2fe3030e5bfbfd237162212dd5e2a545 Mon Sep 17 00:00:00 2001 From: alperozturk Date: Fri, 19 Dec 2025 11:23:12 +0100 Subject: [PATCH 121/216] fix etag saving logic Signed-off-by: alperozturk --- .../com/owncloud/android/datamodel/FileDataStorageManager.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/src/main/java/com/owncloud/android/datamodel/FileDataStorageManager.java b/app/src/main/java/com/owncloud/android/datamodel/FileDataStorageManager.java index 7a4f2e51ce88..0b0bba6c6812 100644 --- a/app/src/main/java/com/owncloud/android/datamodel/FileDataStorageManager.java +++ b/app/src/main/java/com/owncloud/android/datamodel/FileDataStorageManager.java @@ -496,7 +496,7 @@ public List getFolderImages(OCFile folder, boolean onlyOnDevice) { } public boolean saveFile(OCFile ocFile) { - Log_OC.d(TAG, "saving file: " + ocFile.getRemotePath() + " etag: " + ocFile.getEtag()); + Log_OC.d(TAG, "saving file: " + ocFile.getRemotePath()); boolean overridden = false; final ContentValues cv = createContentValuesForFile(ocFile); From 7cbb5de61228058c8ccc1ea23aa9ed1411a09f22 Mon Sep 17 00:00:00 2001 From: alperozturk Date: Fri, 19 Dec 2025 12:53:05 +0100 Subject: [PATCH 122/216] chore: version bump 3.35.0 RC3 Signed-off-by: alperozturk --- app/build.gradle.kts | 2 +- fastlane/metadata/android/en-US/changelogs/30350053.txt | 9 +++++++++ .../android/en-US/changelogs/30350053.txt.license | 2 ++ 3 files changed, 12 insertions(+), 1 deletion(-) create mode 100644 fastlane/metadata/android/en-US/changelogs/30350053.txt create mode 100644 fastlane/metadata/android/en-US/changelogs/30350053.txt.license diff --git a/app/build.gradle.kts b/app/build.gradle.kts index c89f2310843b..8016ee66426e 100644 --- a/app/build.gradle.kts +++ b/app/build.gradle.kts @@ -65,7 +65,7 @@ configurations.configureEach { val versionMajor = 3 val versionMinor = 35 val versionPatch = 0 -val versionBuild = 52 // 0-50=Alpha / 51-98=RC / 90-99=stable +val versionBuild = 53 // 0-50=Alpha / 51-98=RC / 90-99=stable val ndkEnv = buildMap { file("${project.rootDir}/ndk.env").readLines().forEach { diff --git a/fastlane/metadata/android/en-US/changelogs/30350053.txt b/fastlane/metadata/android/en-US/changelogs/30350053.txt new file mode 100644 index 000000000000..f356d02555b3 --- /dev/null +++ b/fastlane/metadata/android/en-US/changelogs/30350053.txt @@ -0,0 +1,9 @@ +## 3.35.0 RC3 (December 19, 2025) + +- Action bar and navigation fixes +- Auto-upload fixes +- Performance improvements and bug fixes + +Minimum: NC 20 Server, Android 9 Pie + +For a full list, please see https://github.com/nextcloud/android/milestone/118 \ No newline at end of file diff --git a/fastlane/metadata/android/en-US/changelogs/30350053.txt.license b/fastlane/metadata/android/en-US/changelogs/30350053.txt.license new file mode 100644 index 000000000000..3804756b12c8 --- /dev/null +++ b/fastlane/metadata/android/en-US/changelogs/30350053.txt.license @@ -0,0 +1,2 @@ +# SPDX-FileCopyrightText: 2025 Nextcloud GmbH and Nextcloud contributors +# SPDX-License-Identifier: AGPL-3.0-or-later \ No newline at end of file From 6e67038d6c32aa494b42dc87f20ac2ec4f97163c Mon Sep 17 00:00:00 2001 From: Nextcloud bot Date: Mon, 22 Dec 2025 13:48:55 +0000 Subject: [PATCH 123/216] fix(l10n): Update translations from Transifex Signed-off-by: Nextcloud bot --- app/src/main/res/values-uk/strings.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/src/main/res/values-uk/strings.xml b/app/src/main/res/values-uk/strings.xml index 848173cbdaed..63ac0c1239e3 100644 --- a/app/src/main/res/values-uk/strings.xml +++ b/app/src/main/res/values-uk/strings.xml @@ -257,7 +257,7 @@ Відмовлено у авторизації за прямим посиланням! Увійти до %2$s з %1$s Вимкнути - Припинити + Сховати Скасувати сповіщення Показати вашу парольну празу з 12 слів Не турбувати From e3e07074aa11406324b15ca2d659c6c6d4cf9b70 Mon Sep 17 00:00:00 2001 From: Nextcloud bot Date: Tue, 23 Dec 2025 02:48:48 +0000 Subject: [PATCH 124/216] fix(l10n): Update translations from Transifex Signed-off-by: Nextcloud bot --- app/src/main/res/values-cs-rCZ/strings.xml | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/app/src/main/res/values-cs-rCZ/strings.xml b/app/src/main/res/values-cs-rCZ/strings.xml index f7cc036c8dc8..f598d60812b2 100644 --- a/app/src/main/res/values-cs-rCZ/strings.xml +++ b/app/src/main/res/values-cs-rCZ/strings.xml @@ -60,7 +60,7 @@ Asistent Vstup Výstup - Přemýšlení... + Přemýšlení… Související účet nenalezen! Přístup se nezdařil: %1$s Účet zatím není na tomto zařízení přidán @@ -210,12 +210,12 @@ Nenalezen žádný soubor Nepodařilo se najít vaši nejaktuálnější zálohu! Zjišťování změn obsahu - Vytváření konverzace selhalo + Vytváření konverzace se nezdařilo Odstranit konverzaci - Odstranění konverzace selhalo + Odstranění konverzace se nezdařilo Nenalezena žádná konverzace Zatím žádná konverzace - Získání seznamu konverzace selhalo + Získání seznamu konverzace se nezdařilo Konverzace Zkopírováno Při pokusu o zkopírování tohoto souboru či složky došlo k chybě @@ -321,7 +321,7 @@ Asistent Další Další Nextcloud aplikace - Nelze otevřít výběr souborů + Nebylo možné otevřít výběr souborů Nepodařilo se vybrat e-mailovou adresu. Nastavit jako šifrované Nedaří se získat certifikát serveru @@ -930,8 +930,8 @@ Vnitřní úložiště Videa Hudba - Oprávnění úložiště je nutné pro automatické nahrávání. - Oprávnění úložiště je nutné pro nahrávání souborů. + Oprávnění k úložišti je nutné pro automatické nahrávání. + Oprávnění k úložišti je nutné pro nahrávání souborů. Neptat se Média pouze pro čtení Obrázky From 57e15f9e78d8a4f546a5ca4939ed126dc0113acc Mon Sep 17 00:00:00 2001 From: Nextcloud bot Date: Thu, 25 Dec 2025 02:47:13 +0000 Subject: [PATCH 125/216] fix(l10n): Update translations from Transifex Signed-off-by: Nextcloud bot --- app/src/main/res/values-cs-rCZ/strings.xml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/app/src/main/res/values-cs-rCZ/strings.xml b/app/src/main/res/values-cs-rCZ/strings.xml index f598d60812b2..cd791296b33d 100644 --- a/app/src/main/res/values-cs-rCZ/strings.xml +++ b/app/src/main/res/values-cs-rCZ/strings.xml @@ -695,6 +695,7 @@ Přejmenovat novou verzi Co udělat pokud soubor už existuje? Přidat účet + Přístup ke všem souborům Synchronizovat kalendář a kontakty F-Droid ani Google Play není nainstalováno Nastavit pro stávající účet DAVx⁵ (dříve známé pod názvem DAVdroid) (verze 1.3.0 a novější) @@ -930,6 +931,7 @@ Vnitřní úložiště Videa Hudba + Přístup ke všem souborům Oprávnění k úložišti je nutné pro automatické nahrávání. Oprávnění k úložišti je nutné pro nahrávání souborů. Neptat se From 2865c69c45ac82571af4ef0226d0e9cce539adee Mon Sep 17 00:00:00 2001 From: Nextcloud bot Date: Sat, 27 Dec 2025 02:46:03 +0000 Subject: [PATCH 126/216] fix(l10n): Update translations from Transifex Signed-off-by: Nextcloud bot --- app/src/main/res/values-cs-rCZ/strings.xml | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/app/src/main/res/values-cs-rCZ/strings.xml b/app/src/main/res/values-cs-rCZ/strings.xml index cd791296b33d..ceb83eb969d7 100644 --- a/app/src/main/res/values-cs-rCZ/strings.xml +++ b/app/src/main/res/values-cs-rCZ/strings.xml @@ -45,6 +45,8 @@ Hledat v %s Jevit se offline Zde zobrazený výstup je vytvořen AI. Vždy si informace ověřujte. + Nepodařilo se odeslat zprávu + Nepodařilo se získat zprávy chatu Opravdu chcete tuto úlohu smazat? Smazat úkol Zkuste poslat zprávu pro rozproudění konverzace. @@ -391,6 +393,7 @@ Nemáte oprávnění pro vytváření nebo nahrávání souborů v této složce. Externí sdílení Přidat nebo nahrát + Nepodařilo se vytvořit dialog o konfliktu Předání souboru správci stahování se nezdařilo Soubor se nepodařilo vytisknout Editor se nepodařilo spustit @@ -695,6 +698,7 @@ Přejmenovat novou verzi Co udělat pokud soubor už existuje? Přidat účet + Umižnit aplikaci přistupovat k a spravovat veškeré soubory na vašem zařízení Přístup ke všem souborům Synchronizovat kalendář a kontakty F-Droid ani Google Play není nainstalováno From c993565ea8dbc6ac697dc9dc7baf37f3ba2b2062 Mon Sep 17 00:00:00 2001 From: Nextcloud bot Date: Sun, 28 Dec 2025 02:48:34 +0000 Subject: [PATCH 127/216] fix(l10n): Update translations from Transifex Signed-off-by: Nextcloud bot --- app/src/main/res/values-sk-rSK/strings.xml | 80 ++++++++++++++++++++++ 1 file changed, 80 insertions(+) diff --git a/app/src/main/res/values-sk-rSK/strings.xml b/app/src/main/res/values-sk-rSK/strings.xml index 23e3b334ce2e..88d5fdc810be 100644 --- a/app/src/main/res/values-sk-rSK/strings.xml +++ b/app/src/main/res/values-sk-rSK/strings.xml @@ -45,6 +45,8 @@ Hľadať v %s Zdá sa byť offline Výstup zobrazený tu je generovaný umelou inteligenciou. Uistite sa, že vždy dôkladne skontrolujete. + Nepodarilo sa odoslať správu + Nepodarilo sa načítať správy chatu Naozaj chcete vymazať túto úlohu? Odstrániť úlohu Skúste poslať správu, aby ste rozprúdili konverzáciu. @@ -53,12 +55,14 @@ Úloha bola úspešne vytvorená Pri odstraňovaní úlohy nastala chyba Úloha bola úspešne odstránená + Zoznam úloh je prázdny. Skontrolujte konfiguráciu aplikácie asistenta. Nie je možné načítať zoznam úloh, skontrolujte svoje internetové pripojenie. Vymazať Úlohu Výstup úlohy ešte nie je dostupný. Asistent Vstup Výstup + Premýšľam … Priradený účet sa nenašiel Prístup zamietnutý: %1$s Účet zatiaľ v zariadení neexistuje @@ -90,12 +94,19 @@ %1$s nepodporuje viacero účtov Nepodarilo sa nadviazať spojenie Zrušiť prihlasovanie + Zadajte platnú adresu servera. + Nepodarilo sa načítať prihlasovacie údaje. Skúste to prosím znova. Pri spracovaní vašej žiadosti o prihlásenie sa vyskytol problém. Skúste to znova neskôr. + Pre tento odkaz nie je k dispozícii žiadny prehliadač. Prosím, dokončite proces prihlasovania vo vašom prehliadači + Automatické nahrávanie je pozastavené, pretože je zapnutý režim šetrenia batérie. ponechané v pôvodnom priečinku, pretože je iba na čítanie + Nízka úroveň batérie, nahrávanie môže trvať dlhšie Nahrávaj iba na neobmedzenom Wi-Fi /AutomatickéNahrávanie Tento adresár je už zahrnutý v synchronizácii nadradeného adresára, čo môže spôsobiť duplicitné nahrávania + Čaká sa na Wi-Fi pre spustenie nahrávania. + Nahrávanie súborov z %s do %s Nastaviť Nastavenie vytvorenia vlastného priečinku Nastaviť vlastný priečinok @@ -200,9 +211,13 @@ Spustenie mportu zlyhalo. Prosím skúste to znova Nenašiel sa žiadny súbor Nenašla sa posledná záloha! + Detekcia zmien obsahu + Nepodarilo sa vytvoriť konverzáciu Zmazať konverzáciu + Nepodarilo sa vymazať konverzáciu Neboli nájdené žiadne konverzácie Zatiaľ žiadne konverzácie + Nepodarilo sa načítať zoznam konverzácií Konverzácie Skopírované Počas kopírovania súboru alebo zložky sa vyskytla chyba @@ -251,6 +266,13 @@ Vyberte typ exportu Generovanie PDF zlyhalo Generuje sa PDF... + Tu nie je možné vytvárať položky: chýba povolenie na vytváranie. + Nie je možné vytvoriť súbor: chýba povolenie. + Nie je možné vytvoriť priečinok: chýba povolenie. + Nie je možné vymazať položku: chýba oprávnenie na vymazanie. + Nie je možné presunúť položku: chýba povolenie na presun. + Nie je možné otvoriť položku: chýba povolenie na čítanie. + Nie je možné premenovať položku: chýba povolenie na premenovanie. Hotové Nemazať Nie je možné vytvoriť lokálny súbor @@ -297,9 +319,11 @@ E2E zatiaľ nie je nastavené Nie je možné bez internetového pripojenia Podpis nesúhlasí + Nebolo možné overiť metadata, podpis je prázdny. Asistent Viac Ďalšie Nextcloud aplikácie + Nie je možné otvoriť výber súboru Nepodarilo sa vybrať e-mailovú adresu. Nastaviť ako zašifrované Nepodarilo sa získať certifikát servera @@ -330,12 +354,14 @@ Chyba pri pridaní komentáru k súboru %1$s zhavarovalo Chyba pri vytváraní súboru zo šablóny + Nie je možné získať zdieľané položky. Chyba pri zobrazovaní akcií súboru Chyba pri zmene stavu uzamknutia súboru Hlásenie Nahlásiť chybu? (vyžaduje účet na Githube) Chyba pri získavaní súboru Chyba pri načítaní šablón + Chyba pri nastavovaní správy stavu! Chyba pri zobrazovaní dialogu nastavenia šifrovania! Chyba pri otváraní fotoaparátu Chyba pri spustení skenovania dokumentu @@ -364,8 +390,10 @@ Prenos Stiahnuť Nahrať + Nemáte povolenie na vytváranie alebo nahrávanie súborov do tejto zložky. Externé zdieľania Pridať alebo nahrať + Nepodarilo sa vytvoriť dialóg o konflikte Nepodarilo sa odovzdať súbor správcovi preberania Nepodarilo sa vytlačiť súbor Nepodarilo sa spustiť editor @@ -377,6 +405,7 @@ Súbor už existuje Zmazať Chyba pri načítavaní aktivít pre súbor + Nemôžete vytvoriť zdieľanie, zdieľanie je už aktívne od tohto používateľa. Nie je k dispozícii žiadna aplikácia pre výber kontaktov Nepodarilo sa načítať podrobnosti Súbor @@ -396,6 +425,10 @@ Tu sa zobrazia súbory a priečinky, ktoré ste sprístupnili. Zatiaľ ste nič nesprístupnili Neboli nájdené žiadne výsledky + Začnite svoje vyhľadávanie + Zadajte do vyhľadávacieho panela vyššie a nájdite súbory, kontakty, udalosti v kalendári a ďalšie vo vašom účte. + Skontrolujte svoje internetové pripojenie alebo to skúste neskôr + Slabé pripojenie priečinok ŽIVÉ Načítavam… @@ -434,9 +467,11 @@ %s nie je povolený názov %s. Prosím premenujte súbor predtým ako bude skopírovaný alebo presunutý Súbor nenájdený + Súbor nenájdený. Nepodarilo sa vytvoriť zdieľanie. Súbor sa nepodarilo zosynchronizovať. Zobrazuje sa posledná dostupná verzia. Premenovať Nahrávanie zlyhalo. Žiadne pripojenie k internetu + %suž existuje, konflikt nebol zistený Chyba pri obnove verzie súboru! Podrobnosti Stiahnuť @@ -455,6 +490,11 @@ Priečinok už existuje Tento adresár je najlepšie prezerať v %1$s. Vytvoriť + %1$d z %2$d · %3$s + Došlo k chybe počas synchronizácie priečinka %s. + Nedostatok miesta na disku, synchronizácia zrušená + %s priečinok bol úspešne synchronizovaný + Synchronizuje sa... Nie sú tu žiadne priečinky Názov adresára nemôže byť prázdny Vybrať @@ -511,6 +551,7 @@ Posledná záloha: %1$s Odkaz Názov odkazu + Odkaz nebol nasledovaný kvôli nastaveniam bezpečnosti. Úprava Náhľad zoznamu Načítať viac výsledkov @@ -587,6 +628,8 @@ Nepodarilo sa vykonať akciu. Zobraziť upozornenia s výsledkami operácií na pozadí Operácie na pozadí + Detekuje zmeny miestnych súborov + Pozorovateľ obsahu Zobrazuje postup sťahovania Stiahnuté Zobrazuje progres a výsledok synchronizácie súborov @@ -595,6 +638,8 @@ Všeobecné notifikácie Priebeh prehrávača hudby Prehrávač médií + Zobrazuje pokrok pri offline operáciách súborov + Offline operácie Zobraz push notifikácie posielané servrom: spomenutie mena v komentároch, nové zdieľanie zo vzdialeného servra, oznámenia od administrátora, atď. Push notifikácie Zobrazuje postup nahrávania @@ -608,8 +653,13 @@ Bez internetového pripojenia Dokonca aj bez internetového pripojenia môžete organizovať svoje adresáre a vytvárať súbory. Keď budete opäť online, vaše nespracované akcie sa automaticky zosynchronizujú. Nie ste pripojený, ale môžete pokračovať v práci + Súbor ešte neexistuje. Prosím, najprv nahrajte súbor. + Nepodarilo sa vytvoriť %s. Súbor s rovnakým názvom už existuje na serveri. + Nepodarilo sa vytvoriť %s. Na serveri už existuje priečinok so rovnakým názvom. Offline operácia nemôže byť dokončená. %s Offline operace + Zrušené odstránenie %s. Súbor bol upravený na serveri. + Zrušené premenovanie %s. Súbor so rovnakým názvom už existuje na serveri. Spúšťanie offline operácií 1 hodina Pripojené @@ -619,6 +669,7 @@ Ďalšie menu Vložte svoje heslo Vložte prosím svoje heslo + Kód bude požadovaný vždy, keď sa aplikácia otvorí alebo znovu otvorí po 5 sekundách. Heslá sa nezhodujú Vložte prosím znovu svoje heslo Odstráňte svoj bezpečnostný kód @@ -647,8 +698,11 @@ Premenovať novú verziu Čo urobiť, ak súbor už existuje? Pridať účet + Povoliť aplikácii prístup a správu všetkých súborov na vašom zariadení + Všetky prístupy k súborom Synchronizácia kalendára a kontaktov F-Droid ani Google Play nie sú nainštalované + Nastavenie DAVx⁵ (predtým známe ako DAVdroid) (v1.3.0+) pre aktuálny účet Synchronizácia kalendára a kontaktov úspešne dokončená O aplikácii Podrobnosti @@ -661,6 +715,7 @@ Denná záloha vašich kontaktov Umiestnenie úložiska údajov Spravovať umiestnenie úložiska údajov + Neočakávaná chyba pri nastavovaní DAVx⁵ (predtým známeho ako DAVdroid) Koncové šifrovanie je nastavené! E2E mnemotechnické Pre zobrazenie mnemotechnické, zapnite prihlasovacie údaje zariadenia. @@ -761,6 +816,7 @@ Automatické nahrávanie vašich fotiek a videí Kalendár a Kontakty + Synchronizácia s DAVx5 Chyba pri získavaní výsledkov vyhľadávania Zabezpečené zdieľanie nie je nastavené pre tohto užívateľa. Bezpečné zdieľanie… @@ -771,13 +827,18 @@ Odoslať Odoslať zdieľanie Ikona tlačidla na odoslanie + Nepodarilo sa načítať obsah + Zariadenie pravdepodobne nie je pripojené na internet. Nastaviť ako + Nie je možné nastaviť limit sťahovania. Skontrolujte možnosti. + Nastaviť správu Nastaviť poznámku Stav pripojenia Použiť obrázok ako Počas nastavovania end-to-end šifrovania dostanete náhodný 12-slovový mnemotechnický záznam, ktorý budete potrebovať na otvorenie svojich súborov na iných zariadeniach. Tento záznam bude uložený iba na tomto zariadení a môže byť znovu zobrazený na tejto obrazovke. Prosím, zapíšte si ho na bezpečné miesto! Zdieľať Povoliť sťahovanie a synchronizáciu + Nemohli sme aktualizovať zdieľanie. Prosím, pridajte poznámku a skúste to znova. Zdieľať a kopírovať odkaz Vytvoriť Vlastné oprávnenia @@ -803,6 +864,7 @@ Nastaviť dátum expirácie Nastaviť heslo Opakované zdieľanie nie je povolené počas bezpečného odovzdávania súborov. + Vyberte si aspoň jednu možnosť zdieľania pred pokračovaním. Môže upravovať Žiadosť o súbor Zabezpečený file drop @@ -873,8 +935,13 @@ Interné úložisko Videá Hudba + Všetky prístupy k súborom + Pre automatické nahrávanie je potrebné povolenie na ukladanie. + Na nahrávanie súborov je potrebné povolenie na ukladanie. + Nepýtať sa Médiá iba načítanie Obrázky + Samo-hostovaná platforma pre produktivitu, ktorá vás ponecháva v kontrole.\n\nFunkcie:\n* Jednoduché, moderné rozhranie prispôsobené téme vášho servera\n* Nahrávanie súborov na váš Nextcloud server\n* Zdieľanie súborov s ostatnými\n* Synchronizácia obľúbených súborov a priečinkov\n* Vyhľadávanie vo všetkých priečinkoch na vašom serveri\n* Automatické nahrávanie fotografií a videí vytvorených vaším zariadením\n* Aktuálny prehľad vďaka upozorneniam\n* Podpora viacerých účtov\n* Zabezpečený prístup k vašim údajom pomocou odtlačku prsta alebo PIN kódu\n* Integrácia s DAVx⁵ (predtým známe ako DAVdroid) pre jednoduché nastavenie synchronizácie kalendára a kontaktov\n\nNahláste prosím všetky problémy na https://github.com/nextcloud/android/issues a diskutujte o tejto aplikácii na https://help.nextcloud.com/c/clients/android\n\nSte v Nextcloude noví? Nextcloud je súkromný server na synchronizáciu a zdieľanie súborov a komunikáciu. Je to slobodný softvér (libre software), ktorý môžete hostovať sami alebo zaplatiť spoločnosti, aby to urobila za vás. Takto máte pod kontrolou svoje fotografie, kalendár, kontaktné údaje, dokumenty a všetko ostatné.\n\nPozrite si Nextcloud na https://nextcloud.com Platforma, ktorú môžete bežať na vlastnom serveri, ktorú môžete mať kompletne pod kontrolou.\nToto je oficiálna vývojová verzia, obsahujúca dennú vzorku všetkých nových a nevyskúšaných funkcií, ktoré môžu spôsobovať nestabilitu a viesť ku strate dát. Aplikácia v tomto štádiu vývoja je určená tým používateľom, ktorí sú ochotní skúšať a hlásiť chyby, ktoré sa vyskytnú. Nepoužívajte ju pre svoju produkčnú prácu.\n\nObe oficiálne verzie, tak vývojová ako aj produkčná sú k dispozícii na F-droid a je možné ich mať nainštalované súbežne. Platforma, ktorú môžete bežať na vlastnom serveri, ktorú môžete mať kompletne pod kontrolou. Platforma, ktorú môžete bežať na vlastnom serveri, ktorú môžete mať kompletne pod kontrolou (vývojová verzia) @@ -946,6 +1013,7 @@ Udalosť sa nenašla, vždy ju môžete synchronizovať a aktualizovať. Prebieha presmerovanie na web… Kontakt sa nenašiel, vždy ho môžete synchronizovať a aktualizovať. Prebieha presmerovanie na web… Pre otvorenie výsledku vyhľadávania sú potrebné práva, inak bude presmerovaný na web… + V tomto priečinku Neznámy Odomknúť súbor Existujú neprečítané komentáre @@ -994,6 +1062,10 @@ Nepodarilo sa skopírovať súbor na lokálne úložište Uzamknutie priečinka zlyhalo Nahrávanie bolo zrušené užívateľom + Povoliť prístup ku všetkým súborom + Povolenia aplikácie + Vaše súbory nemožno nahrať bez prístupu k miestnemu úložisku. Klepnite pre udelenie povolenia. + Nahrávanie zastavené – Vyžaduje sa povolenie pre úložisko %1$d / %2$d - %3$s Šifrovanie je možné iba pri >= Android 5.0 Pre skopírovanie vybratých súborov do adresára %1$s nie je dostatok voľného miesta. Chcete ich namiesto toho presunúť? @@ -1048,6 +1120,8 @@ Nedôveryhodný certifikát servra Načítava sa verzia servera ... Aplikácia ukončená + Preskočené + Súbor s rovnakým názvom už existuje. Dokončené Rovnaký súbor nájdený na vzdialenom mieste, nahrávanie bude preskočené Neznáma chyba @@ -1165,6 +1239,12 @@ %d exportovaných súborov, ostatné vynechané pre chybu %d exportovaných súborov, ostatné vynechané pre chybu + + Môžete naraz nahrať iba %d súbor. + Môžete naraz nahrať až %d súborov. + Môžete naraz nahrať až %d súborov. + Môžete naraz nahrať až %d súbory. + %1$d priečinok %1$d priečinky From 9121c8bee05292319349d9b3f724805ddeef6599 Mon Sep 17 00:00:00 2001 From: Nextcloud bot Date: Wed, 7 Jan 2026 02:49:45 +0000 Subject: [PATCH 128/216] fix(l10n): Update translations from Transifex Signed-off-by: Nextcloud bot --- app/src/main/res/values-eu/strings.xml | 1 + 1 file changed, 1 insertion(+) diff --git a/app/src/main/res/values-eu/strings.xml b/app/src/main/res/values-eu/strings.xml index 347e42a01ead..045bfb467c90 100644 --- a/app/src/main/res/values-eu/strings.xml +++ b/app/src/main/res/values-eu/strings.xml @@ -43,6 +43,7 @@ Proxy-ataka Paneleko trepeta bat erakusten du Bilatu %s(e)n + Lineaz kanpo agertzen da Ziur zeregin hau ezabatu nahi duzula? Ezabatu zeregina Errore bat gertatu da zeregina sortzean From f6cc70a0ece764ce64e495675f094618b660fb81 Mon Sep 17 00:00:00 2001 From: Nextcloud bot Date: Mon, 12 Jan 2026 02:49:05 +0000 Subject: [PATCH 129/216] fix(l10n): Update translations from Transifex Signed-off-by: Nextcloud bot --- app/src/main/res/values-ru/strings.xml | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/app/src/main/res/values-ru/strings.xml b/app/src/main/res/values-ru/strings.xml index f0eef136ea99..ce0c7ffdd39e 100644 --- a/app/src/main/res/values-ru/strings.xml +++ b/app/src/main/res/values-ru/strings.xml @@ -44,8 +44,12 @@ Показывает один виджет с главного экрана. Искать в %s \"Не в сети\" для остальных + Не удалось отправить сообщение + Не удалось загрузить сообщения чата Вы уверены, что хотите удалить эту задачу? Удалить задачу + Попробуйте отправить сообщение, чтобы начать беседу. + Здравствуйте! Чем я могу вам помочь сегодня? Произошла ошибка при создании задачи Задача успешно создана Произошла ошибка во время удаления задачи @@ -198,7 +202,9 @@ Не удалось запустить импорт. Пожалуйста, попробуйте снова Файл не найден Не удалось найти последнюю резервную копию! + Не удалось создать чат Удалить обсуждение + Не удалось создать чат. Не найдено ни одного обсуждения Беседы Скопировано From 8080ae0239d86767007ca9d574f421be847d998b Mon Sep 17 00:00:00 2001 From: ZetaTom <70907959+ZetaTom@users.noreply.github.com> Date: Tue, 6 Jan 2026 15:14:30 +0100 Subject: [PATCH 130/216] Remove logic to handle FAB visibility. Signed-off-by: ZetaTom <70907959+ZetaTom@users.noreply.github.com> --- .../owncloud/android/ui/fragment/FileDetailFragment.java | 6 ------ 1 file changed, 6 deletions(-) diff --git a/app/src/main/java/com/owncloud/android/ui/fragment/FileDetailFragment.java b/app/src/main/java/com/owncloud/android/ui/fragment/FileDetailFragment.java index 555286f2e6ad..49df63f254eb 100644 --- a/app/src/main/java/com/owncloud/android/ui/fragment/FileDetailFragment.java +++ b/app/src/main/java/com/owncloud/android/ui/fragment/FileDetailFragment.java @@ -857,12 +857,6 @@ public void showHideFragmentView(boolean isFragmentReplaced) { binding.tabLayout.setVisibility(isFragmentReplaced ? View.GONE : View.VISIBLE); binding.pager.setVisibility(isFragmentReplaced ? View.GONE : View.VISIBLE); binding.sharingFrameContainer.setVisibility(isFragmentReplaced ? View.VISIBLE : View.GONE); - FloatingActionButton mFabMain = requireActivity().findViewById(R.id.fab_main); - if (isFragmentReplaced) { - mFabMain.hide(); - } else { - mFabMain.show(); - } } /** From c52d4f60c0dbbc13b672f2b57bdb5c463ec44560 Mon Sep 17 00:00:00 2001 From: Nextcloud bot Date: Tue, 13 Jan 2026 02:56:09 +0000 Subject: [PATCH 131/216] fix(l10n): Update translations from Transifex Signed-off-by: Nextcloud bot --- app/src/main/res/values-ko/strings.xml | 1 + app/src/main/res/values-ru/strings.xml | 12 ++++++++++++ 2 files changed, 13 insertions(+) diff --git a/app/src/main/res/values-ko/strings.xml b/app/src/main/res/values-ko/strings.xml index cae35b760225..9f38f57cd7bc 100644 --- a/app/src/main/res/values-ko/strings.xml +++ b/app/src/main/res/values-ko/strings.xml @@ -201,6 +201,7 @@ 대화를 찾을 수 없습니다. 아직 대화가 존재하지 않음 대화 + 복사됨 이 파일이나 폴더를 복사할 수 없음 폴더를 자기 자신의 하위 폴더로 복사할 수 없음 파일이 대상 폴더에 이미 존재함 diff --git a/app/src/main/res/values-ru/strings.xml b/app/src/main/res/values-ru/strings.xml index ce0c7ffdd39e..6dfd569a8b05 100644 --- a/app/src/main/res/values-ru/strings.xml +++ b/app/src/main/res/values-ru/strings.xml @@ -44,6 +44,7 @@ Показывает один виджет с главного экрана. Искать в %s \"Не в сети\" для остальных + Выходные данные, показанные здесь, сгенерированы с помощью искусственного интеллекта. Обязательно всегда перепроверяйте. Не удалось отправить сообщение Не удалось загрузить сообщения чата Вы уверены, что хотите удалить эту задачу? @@ -60,6 +61,7 @@ Помощник Ввод Вывод + Думаю... Связанный аккаунт не найден! Доступ запрещен: %1$s Учётная запись ещё не создана на этом устройстве @@ -93,11 +95,14 @@ Отменить вход Пожалуйста, введите действующий адрес сервера. При обработке вашего запроса на вход возникла проблема. Пожалуйста, повторите попытку позже. + Ни один браузер не доступен для открытия этой ссылки. Пожалуйста, завершите процесс входа в вашем браузере оставлен в исходном каталоге, т.к. файл только для чтения + Батарея разряжена, загрузка может занять больше времени Только через безлимит или Wi-Fi /Автозагрузка Эта папка уже включена в синхронизацию родительской папки, что может привести к дублированию загрузок + Ожидание Wi-Fi для начала загрузки Настроить Создать новую настройку пользовательского каталога Задать пользовательский каталог @@ -607,6 +612,7 @@ Не удалось выполнить задание. Показывать уведомления для взаимодействия с результатами фоновых операций Фоновые задания + Обнаруживать локальные изменения файлов Показывает выполнение получения Загрузки Показывает состояние и результаты синхронизации файлов @@ -630,6 +636,7 @@ Отсутствует подключение к Интернет Даже без подключения к Интернету вы можете упорядочивать папки и создавать файлы. Как только вы вернетесь в сеть, ваши действия будут автоматически синхронизированы. Вы не в сети, но работа продолжается + Файл ещё не существует. Пожалуйста, сначала загрузите файл. Не удалось создать %s. На сервере уже существует файл с таким же именем. Не удалось создать %s. На сервере уже существует папка с таким же имененм. Операция в автономном режиме не может быть завершена. %s @@ -645,6 +652,7 @@ Дополнительное меню Введите код Введите ваш код + Пароль будет запрашиваться каждый раз при открытии приложения или его повторном открытии через 5 секунд. Коды не совпадают Введите ваш код ещё раз Удалите ваш код @@ -673,6 +681,7 @@ Переименовать новую версию Действие в случае, если файл уже существует Добавить аккаунт + Разрешить приложению доступ и управление всеми файлами на вашем устройстве Синхронизировать календарь и контакты Ни F-Droid, ни Google Play не установлены Установите DAVx⁵ (ранее известный как DAVdroid) (v1.3.0+) для текущего аккаунта @@ -908,6 +917,9 @@ Внутреннее хранилище Фильмы Музыка + Для авто-загрузки требуется разрешение на доступ к хранилищу. + Для загрузки файлов требуется разрешение на доступ к хранилищу. + Не спрашивать Носитель только для чтения Изображения Устанавливаемая на свой сервер платформа для повышения продуктивности, которая позволяет держать всё под контролем.\n\nFeatures:\n* Простой, современный интерфейс, соответствующий тематике вашего сервера\n* Загружайте файлы на свой сервер Nextcloud\n* Делитесь ими с другими\n* Синхронизируйте избранные файлы и папки\n* Поиск по всем папкам на вашем сервере\n* Автоматическая загрузка фотографий и видео, снятых на вашем устройстве\n* Будьте в курсе событий благодаря уведомлениям\n* Поддержка нескольких учётных записей\n* Безопасный доступ к вашим данным с помощью отпечатка пальца или PIN-кода\n* Интеграция с DAVx⁵ (ранее известен как DAVdroid) для простой настройки синхронизации календаря и контактов\n\nПожалуйста, сообщайте обо всех проблемах на https://github.com/nextcloud/android/issues и обсуждайте это приложение на https://help.nextcloud.com/c/clients/android\n\nНовичок в Nextcloud? Nextcloud — это приватный сервер синхронизации и обмена файлами и коммуникационный сервер. Это свободное программное обеспечение, и вы можете разместить его самостоятельно или заплатить компании, чтобы это сделали за вас. Таким образом, вы управляете своими фотографиями, календарём и контактными данными, документами и всем остальным.\n\nОзнакомьтесь с Nextcloud по адресу https://nextcloud.com From 03db596337282d9746f8319b1546190c34fd2667 Mon Sep 17 00:00:00 2001 From: Nextcloud bot Date: Wed, 14 Jan 2026 02:51:28 +0000 Subject: [PATCH 132/216] fix(l10n): Update translations from Transifex Signed-off-by: Nextcloud bot --- app/src/main/res/values-de/strings.xml | 3 ++- app/src/main/res/values-gl/strings.xml | 1 + app/src/main/res/values-in/strings.xml | 3 +++ app/src/main/res/values-zh-rTW/strings.xml | 1 + 4 files changed, 7 insertions(+), 1 deletion(-) diff --git a/app/src/main/res/values-de/strings.xml b/app/src/main/res/values-de/strings.xml index 1fea68696063..f3c3e4a7ed23 100644 --- a/app/src/main/res/values-de/strings.xml +++ b/app/src/main/res/values-de/strings.xml @@ -195,7 +195,7 @@ Möchten Sie die ausgewählten Elemente und deren inhalt wirklich löschen? Nur lokal Konfliktlösungsdialog konnte nicht erstellt werden - Ordnerkonfilikt + Ordnerkonflikt Lokale Datei Falls beide Versionen gewählt werden, wird bei der lokalen Datei eine Zahl am Ende des Dateinamens hinzugefügt. Falls beide Versionen gewählt werden, wird beim lokalen Ordner eine Zahl am Ende des Dateinamens hinzugefügt. @@ -755,6 +755,7 @@ Intervall Interne Ordner für 2-Wege-Synchronisierung verwalten 2-Wege-Synchronisierung aktivieren + 2-Wege-Synchronisierung Dunkel Hell Systemvorgaben verwenden diff --git a/app/src/main/res/values-gl/strings.xml b/app/src/main/res/values-gl/strings.xml index 54feeb801358..5e6964c11180 100644 --- a/app/src/main/res/values-gl/strings.xml +++ b/app/src/main/res/values-gl/strings.xml @@ -756,6 +756,7 @@ Intervalo Xestionar os cartafoles internos para a sincronización bidireccional Activar a sincronización bidireccional + Sincronización bidireccional Escuro Claro Seguir o sistema diff --git a/app/src/main/res/values-in/strings.xml b/app/src/main/res/values-in/strings.xml index 8feb611ea6d5..f399a71ec6b1 100644 --- a/app/src/main/res/values-in/strings.xml +++ b/app/src/main/res/values-in/strings.xml @@ -685,6 +685,7 @@ Otomatis unggah hanya bekerja dengan baik apabila Anda mengeluarkan aplikasi ini Tentang Rincian Pengembang + File Umum Lainnya Sinkron @@ -875,6 +876,8 @@ Otomatis unggah hanya bekerja dengan baik apabila Anda mengeluarkan aplikasi ini Daftar dengan penyedia Izinkan %1$s untuk mengakses akun NextCloud %2$s? Urut berdasarkan + Urutkan favorit terlebih dahulu + Urutkan folder sebelum file Sembunyikan Rincian Identitas server tidak dapat diverifikasi diff --git a/app/src/main/res/values-zh-rTW/strings.xml b/app/src/main/res/values-zh-rTW/strings.xml index a7b35b245d80..098746c4423a 100644 --- a/app/src/main/res/values-zh-rTW/strings.xml +++ b/app/src/main/res/values-zh-rTW/strings.xml @@ -755,6 +755,7 @@ 間隔 管理內部資料夾以進行雙向同步 啟用雙向同步 + 雙向同步 深色 淺色 跟隨系統 From fc1792b22c6359c4002fa4e329879185e7de32d7 Mon Sep 17 00:00:00 2001 From: alperozturk Date: Mon, 12 Jan 2026 11:22:38 +0100 Subject: [PATCH 133/216] fix: auto upload worker running check Signed-off-by: alperozturk --- .../java/com/nextcloud/client/jobs/BackgroundJobManager.kt | 2 +- .../com/nextcloud/client/jobs/BackgroundJobManagerImpl.kt | 4 ++-- .../com/nextcloud/client/jobs/autoUpload/AutoUploadWorker.kt | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/app/src/main/java/com/nextcloud/client/jobs/BackgroundJobManager.kt b/app/src/main/java/com/nextcloud/client/jobs/BackgroundJobManager.kt index 219de803ecda..abde68ad4040 100644 --- a/app/src/main/java/com/nextcloud/client/jobs/BackgroundJobManager.kt +++ b/app/src/main/java/com/nextcloud/client/jobs/BackgroundJobManager.kt @@ -165,7 +165,7 @@ interface BackgroundJobManager { fun cancelAllJobs() fun schedulePeriodicHealthStatus() fun startHealthStatus() - fun bothFilesSyncJobsRunning(syncedFolderID: Long): Boolean + fun isAutoUploadWorkerRunning(syncedFolderID: Long): Boolean fun startOfflineOperations() fun startPeriodicallyOfflineOperation() fun scheduleInternal2WaySync(intervalMinutes: Long) diff --git a/app/src/main/java/com/nextcloud/client/jobs/BackgroundJobManagerImpl.kt b/app/src/main/java/com/nextcloud/client/jobs/BackgroundJobManagerImpl.kt index ed9aaefa6eff..0ad01e66c7ad 100644 --- a/app/src/main/java/com/nextcloud/client/jobs/BackgroundJobManagerImpl.kt +++ b/app/src/main/java/com/nextcloud/client/jobs/BackgroundJobManagerImpl.kt @@ -421,8 +421,8 @@ internal class BackgroundJobManagerImpl( workManager.cancelJob(JOB_PERIODIC_CALENDAR_BACKUP, user) } - override fun bothFilesSyncJobsRunning(syncedFolderID: Long): Boolean = - workManager.isWorkRunning(JOB_PERIODIC_FILES_SYNC + "_" + syncedFolderID) && + override fun isAutoUploadWorkerRunning(syncedFolderID: Long): Boolean = + workManager.isWorkRunning(JOB_PERIODIC_FILES_SYNC + "_" + syncedFolderID) || workManager.isWorkRunning(JOB_IMMEDIATE_FILES_SYNC + "_" + syncedFolderID) override fun startPeriodicallyOfflineOperation() { diff --git a/app/src/main/java/com/nextcloud/client/jobs/autoUpload/AutoUploadWorker.kt b/app/src/main/java/com/nextcloud/client/jobs/autoUpload/AutoUploadWorker.kt index b13ebabe7578..2c54909872ae 100644 --- a/app/src/main/java/com/nextcloud/client/jobs/autoUpload/AutoUploadWorker.kt +++ b/app/src/main/java/com/nextcloud/client/jobs/autoUpload/AutoUploadWorker.kt @@ -196,7 +196,7 @@ class AutoUploadWorker( return true } - if (backgroundJobManager.bothFilesSyncJobsRunning(syncedFolderID)) { + if (backgroundJobManager.isAutoUploadWorkerRunning(syncedFolderID)) { Log_OC.w(TAG, "🚧 another worker is already running for $syncedFolderID") return true } From a9a2b4be95104e3e276613cdc41db7f0a22244e2 Mon Sep 17 00:00:00 2001 From: alperozturk96 Date: Tue, 13 Jan 2026 12:09:12 +0100 Subject: [PATCH 134/216] fix Signed-off-by: alperozturk96 --- .../jobs/autoUpload/AutoUploadWorker.kt | 34 +++++-------------- ...FolderDownloadWorkerNotificationManager.kt | 9 ----- .../notification/WorkerNotificationManager.kt | 10 ++++++ 3 files changed, 18 insertions(+), 35 deletions(-) diff --git a/app/src/main/java/com/nextcloud/client/jobs/autoUpload/AutoUploadWorker.kt b/app/src/main/java/com/nextcloud/client/jobs/autoUpload/AutoUploadWorker.kt index 2c54909872ae..17b7a7ebad6f 100644 --- a/app/src/main/java/com/nextcloud/client/jobs/autoUpload/AutoUploadWorker.kt +++ b/app/src/main/java/com/nextcloud/client/jobs/autoUpload/AutoUploadWorker.kt @@ -25,12 +25,10 @@ import com.nextcloud.client.jobs.upload.FileUploadWorker import com.nextcloud.client.jobs.utils.UploadErrorNotificationManager import com.nextcloud.client.network.ConnectivityService import com.nextcloud.client.preferences.SubFolderRule -import com.nextcloud.utils.ForegroundServiceHelper import com.nextcloud.utils.extensions.updateStatus import com.owncloud.android.R import com.owncloud.android.datamodel.ArbitraryDataProviderImpl import com.owncloud.android.datamodel.FileDataStorageManager -import com.owncloud.android.datamodel.ForegroundServiceType import com.owncloud.android.datamodel.MediaFolderType import com.owncloud.android.datamodel.SyncedFolder import com.owncloud.android.datamodel.SyncedFolderProvider @@ -85,8 +83,6 @@ class AutoUploadWorker( syncedFolder = syncedFolderProvider.getSyncedFolderByID(syncFolderId) ?.takeIf { it.isEnabled } ?: return Result.failure() - trySetForeground() - /** * Receives from [com.nextcloud.client.jobs.ContentObserverWork.checkAndTriggerAutoUpload] */ @@ -97,7 +93,6 @@ class AutoUploadWorker( } collectFileChangesFromContentObserverWork(contentUris) - updateNotification() uploadFiles(syncedFolder) Log_OC.d(TAG, "✅ ${syncedFolder.remotePath} finished checking files.") @@ -109,18 +104,11 @@ class AutoUploadWorker( } override suspend fun getForegroundInfo(): ForegroundInfo { - val notification = createNotification( - context.getString(R.string.upload_files) - ) - - return ForegroundServiceHelper.createWorkerForegroundInfo( - NOTIFICATION_ID, - notification, - ForegroundServiceType.DataSync - ) + val notification = createNotification(context.getString(R.string.upload_files)) + return notificationManager.getForegroundInfo(notification) } - private fun updateNotification() { + private suspend fun updateNotification() { getStartNotificationTitle()?.let { (localFolderName, remoteFolderName) -> try { val startNotification = createNotification( @@ -131,7 +119,7 @@ class AutoUploadWorker( ) ) - notificationManager.showNotification(startNotification) + setForeground(notificationManager.getForegroundInfo(startNotification)) } catch (e: Exception) { Log_OC.w(TAG, "⚠️ Could not update notification: ${e.message}") } @@ -141,21 +129,12 @@ class AutoUploadWorker( private suspend fun trySetForeground() { try { val notification = createNotification(context.getString(R.string.upload_files)) - updateForegroundInfo(notification) + setForeground(notificationManager.getForegroundInfo(notification)) } catch (e: Exception) { Log_OC.w(TAG, "⚠️ Could not set foreground service: ${e.message}") } } - private suspend fun updateForegroundInfo(notification: Notification) { - val foregroundInfo = ForegroundServiceHelper.createWorkerForegroundInfo( - NOTIFICATION_ID, - notification, - ForegroundServiceType.DataSync - ) - setForeground(foregroundInfo) - } - private fun createNotification(title: String): Notification = notificationManager.notificationBuilder .setContentTitle(title) .setSmallIcon(R.drawable.uploads) @@ -297,6 +276,9 @@ class AutoUploadWorker( val lightVersion = context.resources.getBoolean(R.bool.syncedFolder_light) val currentLocale = context.resources.configuration.locales[0] + trySetForeground() + updateNotification() + var lastId = 0 while (true) { val filePathsWithIds = repository.getFilePathsWithIds(syncedFolder, lastId) diff --git a/app/src/main/java/com/nextcloud/client/jobs/folderDownload/FolderDownloadWorkerNotificationManager.kt b/app/src/main/java/com/nextcloud/client/jobs/folderDownload/FolderDownloadWorkerNotificationManager.kt index 8502f4632ad6..fed0b8feaff0 100644 --- a/app/src/main/java/com/nextcloud/client/jobs/folderDownload/FolderDownloadWorkerNotificationManager.kt +++ b/app/src/main/java/com/nextcloud/client/jobs/folderDownload/FolderDownloadWorkerNotificationManager.kt @@ -13,9 +13,7 @@ import android.content.Context import android.content.Intent import androidx.work.ForegroundInfo import com.nextcloud.client.jobs.notification.WorkerNotificationManager -import com.nextcloud.utils.ForegroundServiceHelper import com.owncloud.android.R -import com.owncloud.android.datamodel.ForegroundServiceType import com.owncloud.android.datamodel.OCFile import com.owncloud.android.ui.notifications.NotificationUtils import com.owncloud.android.utils.theme.ViewThemeUtils @@ -109,13 +107,6 @@ class FolderDownloadWorkerNotificationManager(private val context: Context, view return getForegroundInfo(notification) } - fun getForegroundInfo(notification: Notification): ForegroundInfo = - ForegroundServiceHelper.createWorkerForegroundInfo( - NOTIFICATION_ID, - notification, - ForegroundServiceType.DataSync - ) - fun dismiss() { notificationManager.cancel(NOTIFICATION_ID) } diff --git a/app/src/main/java/com/nextcloud/client/jobs/notification/WorkerNotificationManager.kt b/app/src/main/java/com/nextcloud/client/jobs/notification/WorkerNotificationManager.kt index 573e1d1d02ac..e5c9f31bb73b 100644 --- a/app/src/main/java/com/nextcloud/client/jobs/notification/WorkerNotificationManager.kt +++ b/app/src/main/java/com/nextcloud/client/jobs/notification/WorkerNotificationManager.kt @@ -14,7 +14,10 @@ import android.graphics.BitmapFactory import android.os.Handler import android.os.Looper import androidx.core.app.NotificationCompat +import androidx.work.ForegroundInfo +import com.nextcloud.utils.ForegroundServiceHelper import com.owncloud.android.R +import com.owncloud.android.datamodel.ForegroundServiceType import com.owncloud.android.utils.theme.ViewThemeUtils open class WorkerNotificationManager( @@ -75,4 +78,11 @@ open class WorkerNotificationManager( fun getId(): Int = id fun getNotification(): Notification = notificationBuilder.build() + + fun getForegroundInfo(notification: Notification): ForegroundInfo = + ForegroundServiceHelper.createWorkerForegroundInfo( + id, + notification, + ForegroundServiceType.DataSync + ) } From 2cc1cf1f58325774fa8118f6a8a9b46ecda2f275 Mon Sep 17 00:00:00 2001 From: ZetaTom <70907959+ZetaTom@users.noreply.github.com> Date: Wed, 14 Jan 2026 11:21:20 +0100 Subject: [PATCH 135/216] Show no results page when no results are available. - results page remained blank when no results were found - improve readability Signed-off-by: ZetaTom <70907959+ZetaTom@users.noreply.github.com> --- .../ui/adapter/UnifiedSearchListAdapter.kt | 2 +- .../ui/fragment/UnifiedSearchFragment.kt | 23 ++++++++----------- .../unifiedsearch/UnifiedSearchViewModel.kt | 6 +---- 3 files changed, 12 insertions(+), 19 deletions(-) diff --git a/app/src/main/java/com/owncloud/android/ui/adapter/UnifiedSearchListAdapter.kt b/app/src/main/java/com/owncloud/android/ui/adapter/UnifiedSearchListAdapter.kt index baf0e9e79123..6e5b0c6a4f20 100644 --- a/app/src/main/java/com/owncloud/android/ui/adapter/UnifiedSearchListAdapter.kt +++ b/app/src/main/java/com/owncloud/android/ui/adapter/UnifiedSearchListAdapter.kt @@ -220,7 +220,7 @@ class UnifiedSearchListAdapter( notifyDataSetChanged() } - fun isCurrentDirItemsEmpty(): Boolean = currentDirItems.isEmpty() + fun hasLocalResults(): Boolean = currentDirItems.isNotEmpty() init { // initialise thumbnails cache on background thread diff --git a/app/src/main/java/com/owncloud/android/ui/fragment/UnifiedSearchFragment.kt b/app/src/main/java/com/owncloud/android/ui/fragment/UnifiedSearchFragment.kt index 833db9694dc1..74f9248640e3 100644 --- a/app/src/main/java/com/owncloud/android/ui/fragment/UnifiedSearchFragment.kt +++ b/app/src/main/java/com/owncloud/android/ui/fragment/UnifiedSearchFragment.kt @@ -318,21 +318,18 @@ class UnifiedSearchFragment : binding.swipeContainingList.isRefreshing = loading } - PairMediatorLiveData(vm.searchResults, vm.isLoading).observe(viewLifecycleOwner) { pair -> - if (pair.second == false) { - var count = 0 + PairMediatorLiveData(vm.searchResults, vm.isLoading).observe(viewLifecycleOwner) { (searchResults, isLoading) -> + if (isLoading == true || searchResults.isNullOrEmpty()) { + return@observe + } - pair.first?.forEach { - count += it.entries.size - } + val hasSearchResult = searchResults.any { searchResult -> searchResult.entries.isNotEmpty() } - if (count == 0 && - pair.first?.isNotEmpty() == true && - context != null && - !adapter.isCurrentDirItemsEmpty() - ) { - showNoResult() - } + if (context != null && + !hasSearchResult && + !adapter.hasLocalResults() + ) { + showNoResult() } } diff --git a/app/src/main/java/com/owncloud/android/ui/unifiedsearch/UnifiedSearchViewModel.kt b/app/src/main/java/com/owncloud/android/ui/unifiedsearch/UnifiedSearchViewModel.kt index 97ba8e494538..4afb9ed10948 100644 --- a/app/src/main/java/com/owncloud/android/ui/unifiedsearch/UnifiedSearchViewModel.kt +++ b/app/src/main/java/com/owncloud/android/ui/unifiedsearch/UnifiedSearchViewModel.kt @@ -37,11 +37,7 @@ class UnifiedSearchViewModel(application: Application) : } private data class UnifiedSearchMetadata(var results: MutableList = mutableListOf()) { - fun nextCursor(): Int? = try { - results.lastOrNull()?.cursor?.toInt() - } catch (e: NumberFormatException) { - null - } + fun nextCursor(): Int? = results.lastOrNull()?.cursor?.toIntOrNull() fun name(): String? = results.lastOrNull()?.name } From 5c771a212fff5f2dd8fb571b31d8eaa0c7cdda79 Mon Sep 17 00:00:00 2001 From: alperozturk Date: Mon, 12 Jan 2026 09:49:15 +0100 Subject: [PATCH 136/216] do not show all sync conflict notifications during app launch Signed-off-by: alperozturk # Conflicts: # app/src/main/res/values/strings.xml --- app/src/main/AndroidManifest.xml | 3 + .../client/jobs/upload/FileUploadHelper.kt | 12 +++ .../AppWideNotificationManager.kt | 79 +++++++++++++++++++ ...ncConflictNotificationBroadcastReceiver.kt | 33 ++++++++ 4 files changed, 127 insertions(+) create mode 100644 app/src/main/java/com/nextcloud/client/notifications/AppWideNotificationManager.kt create mode 100644 app/src/main/java/com/nextcloud/client/notifications/action/SyncConflictNotificationBroadcastReceiver.kt diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index 940739adb944..6a210d519cb1 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -288,6 +288,9 @@ android:exported="false" tools:replace="android:exported" /> + diff --git a/app/src/main/java/com/nextcloud/client/jobs/upload/FileUploadHelper.kt b/app/src/main/java/com/nextcloud/client/jobs/upload/FileUploadHelper.kt index 566d80415c08..0604e5db75f2 100644 --- a/app/src/main/java/com/nextcloud/client/jobs/upload/FileUploadHelper.kt +++ b/app/src/main/java/com/nextcloud/client/jobs/upload/FileUploadHelper.kt @@ -19,6 +19,7 @@ import com.nextcloud.client.device.BatteryStatus import com.nextcloud.client.device.PowerManagementService import com.nextcloud.client.jobs.BackgroundJobManager import com.nextcloud.client.jobs.upload.FileUploadWorker.Companion.currentUploadFileOperation +import com.nextcloud.client.notifications.AppWideNotificationManager import com.nextcloud.client.network.Connectivity import com.nextcloud.client.network.ConnectivityService import com.nextcloud.utils.extensions.getUploadIds @@ -170,6 +171,7 @@ class FileUploadHelper { uploads: Array ): Boolean { var showNotExistMessage = false + var showSyncConflictNotification = false val isOnline = checkConnectivity(connectivityService) val connectivity = connectivityService.connectivity val batteryStatus = powerManagementService.battery @@ -177,6 +179,12 @@ class FileUploadHelper { val uploadsToRetry = mutableListOf() for (upload in uploads) { + if (upload.lastResult == UploadResult.SYNC_CONFLICT) { + Log_OC.d(TAG, "retry upload skipped, sync conflict: ${upload.remotePath}") + showSyncConflictNotification = true + continue + } + val uploadResult = checkUploadConditions( upload, connectivity, @@ -214,6 +222,10 @@ class FileUploadHelper { ) } + if (showSyncConflictNotification) { + AppWideNotificationManager.showSyncConflictNotification(MainApp.getAppContext()) + } + return showNotExistMessage } diff --git a/app/src/main/java/com/nextcloud/client/notifications/AppWideNotificationManager.kt b/app/src/main/java/com/nextcloud/client/notifications/AppWideNotificationManager.kt new file mode 100644 index 000000000000..929d2dc0331d --- /dev/null +++ b/app/src/main/java/com/nextcloud/client/notifications/AppWideNotificationManager.kt @@ -0,0 +1,79 @@ +/* + * Nextcloud - Android Client + * + * SPDX-FileCopyrightText: 2026 Alper Ozturk + * SPDX-License-Identifier: AGPL-3.0-or-later + */ + +package com.nextcloud.client.notifications + +import android.app.PendingIntent +import android.content.Context +import android.content.Intent +import androidx.core.app.NotificationCompat +import androidx.core.app.NotificationManagerCompat +import com.nextcloud.client.notifications.action.SyncConflictNotificationBroadcastReceiver +import com.owncloud.android.R +import com.owncloud.android.ui.activity.UploadListActivity +import com.owncloud.android.ui.notifications.NotificationUtils + +/** + * Responsible for showing **app-wide notifications** in the app. + * + * This manager provides a centralized place to create and display notifications + * that are not tied to a specific screen or feature. + * + */ +object AppWideNotificationManager { + + private const val SYNC_CONFLICT_NOTIFICATION_INTENT_REQ_CODE = 16 + private const val SYNC_CONFLICT_NOTIFICATION_INTENT_ACTION_REQ_CODE = 17 + + private const val SYNC_CONFLICT_NOTIFICATION_ID = 112 + + fun showSyncConflictNotification(context: Context) { + val intent = Intent(context, UploadListActivity::class.java).apply { + flags = Intent.FLAG_ACTIVITY_NEW_TASK or Intent.FLAG_ACTIVITY_CLEAR_TOP + } + + val pendingIntent = PendingIntent.getActivity( + context, + SYNC_CONFLICT_NOTIFICATION_INTENT_REQ_CODE, + intent, + PendingIntent.FLAG_UPDATE_CURRENT or PendingIntent.FLAG_IMMUTABLE + ) + + val actionIntent = Intent(context, SyncConflictNotificationBroadcastReceiver::class.java).apply { + putExtra(SyncConflictNotificationBroadcastReceiver.NOTIFICATION_ID, SYNC_CONFLICT_NOTIFICATION_ID) + } + + val actionPendingIntent = PendingIntent.getBroadcast( + context, + SYNC_CONFLICT_NOTIFICATION_INTENT_ACTION_REQ_CODE, + actionIntent, + PendingIntent.FLAG_UPDATE_CURRENT or PendingIntent.FLAG_IMMUTABLE + ) + + val notification = NotificationCompat.Builder(context, NotificationUtils.NOTIFICATION_CHANNEL_UPLOAD) + .setSmallIcon(R.drawable.uploads) + .setContentTitle(context.getString(R.string.uploader_upload_failed_sync_conflict_error)) + .setContentText(context.getString(R.string.upload_conflict_message)) + .setStyle( + NotificationCompat.BigTextStyle() + .bigText(context.getString(R.string.upload_conflict_message)) + ) + .addAction( + R.drawable.ic_cloud_upload, + context.getString(R.string.upload_list_resolve_conflict), + actionPendingIntent + ) + .setContentIntent(pendingIntent) + .setAutoCancel(true) + .setOnlyAlertOnce(true) + .setPriority(NotificationCompat.PRIORITY_DEFAULT) + .build() + + NotificationManagerCompat.from(context) + .notify(SYNC_CONFLICT_NOTIFICATION_ID, notification) + } +} diff --git a/app/src/main/java/com/nextcloud/client/notifications/action/SyncConflictNotificationBroadcastReceiver.kt b/app/src/main/java/com/nextcloud/client/notifications/action/SyncConflictNotificationBroadcastReceiver.kt new file mode 100644 index 000000000000..db067a497b9e --- /dev/null +++ b/app/src/main/java/com/nextcloud/client/notifications/action/SyncConflictNotificationBroadcastReceiver.kt @@ -0,0 +1,33 @@ +/* + * Nextcloud - Android Client + * + * SPDX-FileCopyrightText: 2026 Alper Ozturk + * SPDX-License-Identifier: AGPL-3.0-or-later + */ + +package com.nextcloud.client.notifications.action + +import android.content.BroadcastReceiver +import android.content.Context +import android.content.Intent +import androidx.core.app.NotificationManagerCompat +import com.owncloud.android.ui.activity.UploadListActivity + +class SyncConflictNotificationBroadcastReceiver : BroadcastReceiver() { + companion object { + const val NOTIFICATION_ID = "NOTIFICATION_ID" + } + + override fun onReceive(context: Context, intent: Intent) { + val notificationId = intent.getIntExtra(NOTIFICATION_ID, -1) + + if (notificationId != -1) { + NotificationManagerCompat.from(context).cancel(notificationId) + } + + val intent = Intent(context, UploadListActivity::class.java).apply { + flags = Intent.FLAG_ACTIVITY_NEW_TASK or Intent.FLAG_ACTIVITY_CLEAR_TOP + } + context.startActivity(intent) + } +} From 0dfd4491de1fbf93b65eb622983a89cc31be12e8 Mon Sep 17 00:00:00 2001 From: alperozturk96 Date: Wed, 14 Jan 2026 08:54:59 +0100 Subject: [PATCH 137/216] fix: lint Signed-off-by: alperozturk96 --- .../AppWideNotificationManager.kt | 25 ++++++++++++++++--- 1 file changed, 21 insertions(+), 4 deletions(-) diff --git a/app/src/main/java/com/nextcloud/client/notifications/AppWideNotificationManager.kt b/app/src/main/java/com/nextcloud/client/notifications/AppWideNotificationManager.kt index 929d2dc0331d..5a1ad0a6ada0 100644 --- a/app/src/main/java/com/nextcloud/client/notifications/AppWideNotificationManager.kt +++ b/app/src/main/java/com/nextcloud/client/notifications/AppWideNotificationManager.kt @@ -7,13 +7,18 @@ package com.nextcloud.client.notifications +import android.Manifest import android.app.PendingIntent import android.content.Context import android.content.Intent +import android.content.pm.PackageManager +import androidx.annotation.RequiresPermission +import androidx.core.app.ActivityCompat import androidx.core.app.NotificationCompat import androidx.core.app.NotificationManagerCompat import com.nextcloud.client.notifications.action.SyncConflictNotificationBroadcastReceiver import com.owncloud.android.R +import com.owncloud.android.lib.common.utils.Log_OC import com.owncloud.android.ui.activity.UploadListActivity import com.owncloud.android.ui.notifications.NotificationUtils @@ -26,11 +31,14 @@ import com.owncloud.android.ui.notifications.NotificationUtils */ object AppWideNotificationManager { + private const val TAG = "AppWideNotificationManager" + private const val SYNC_CONFLICT_NOTIFICATION_INTENT_REQ_CODE = 16 private const val SYNC_CONFLICT_NOTIFICATION_INTENT_ACTION_REQ_CODE = 17 private const val SYNC_CONFLICT_NOTIFICATION_ID = 112 + fun showSyncConflictNotification(context: Context) { val intent = Intent(context, UploadListActivity::class.java).apply { flags = Intent.FLAG_ACTIVITY_NEW_TASK or Intent.FLAG_ACTIVITY_CLEAR_TOP @@ -56,15 +64,15 @@ object AppWideNotificationManager { val notification = NotificationCompat.Builder(context, NotificationUtils.NOTIFICATION_CHANNEL_UPLOAD) .setSmallIcon(R.drawable.uploads) - .setContentTitle(context.getString(R.string.uploader_upload_failed_sync_conflict_error)) - .setContentText(context.getString(R.string.upload_conflict_message)) + .setContentTitle(context.getString(R.string.sync_conflict_notification_title)) + .setContentText(context.getString(R.string.sync_conflict_notification_description)) .setStyle( NotificationCompat.BigTextStyle() - .bigText(context.getString(R.string.upload_conflict_message)) + .bigText(context.getString(R.string.sync_conflict_notification_description)) ) .addAction( R.drawable.ic_cloud_upload, - context.getString(R.string.upload_list_resolve_conflict), + context.getString(R.string.sync_conflict_notification_action_title), actionPendingIntent ) .setContentIntent(pendingIntent) @@ -73,6 +81,15 @@ object AppWideNotificationManager { .setPriority(NotificationCompat.PRIORITY_DEFAULT) .build() + if (ActivityCompat.checkSelfPermission( + context, + Manifest.permission.POST_NOTIFICATIONS + ) != PackageManager.PERMISSION_GRANTED + ) { + Log_OC.w(TAG, "cannot show sync conflict notification, post notification permission is not granted") + return + } + NotificationManagerCompat.from(context) .notify(SYNC_CONFLICT_NOTIFICATION_ID, notification) } From c5cd446a0decdd3850b48c1bcd06e72234f6b51e Mon Sep 17 00:00:00 2001 From: alperozturk96 Date: Wed, 14 Jan 2026 08:55:28 +0100 Subject: [PATCH 138/216] fix: lint Signed-off-by: alperozturk96 [skip ci] --- .../client/notifications/AppWideNotificationManager.kt | 2 -- 1 file changed, 2 deletions(-) diff --git a/app/src/main/java/com/nextcloud/client/notifications/AppWideNotificationManager.kt b/app/src/main/java/com/nextcloud/client/notifications/AppWideNotificationManager.kt index 5a1ad0a6ada0..f58ad90ef0a4 100644 --- a/app/src/main/java/com/nextcloud/client/notifications/AppWideNotificationManager.kt +++ b/app/src/main/java/com/nextcloud/client/notifications/AppWideNotificationManager.kt @@ -12,7 +12,6 @@ import android.app.PendingIntent import android.content.Context import android.content.Intent import android.content.pm.PackageManager -import androidx.annotation.RequiresPermission import androidx.core.app.ActivityCompat import androidx.core.app.NotificationCompat import androidx.core.app.NotificationManagerCompat @@ -38,7 +37,6 @@ object AppWideNotificationManager { private const val SYNC_CONFLICT_NOTIFICATION_ID = 112 - fun showSyncConflictNotification(context: Context) { val intent = Intent(context, UploadListActivity::class.java).apply { flags = Intent.FLAG_ACTIVITY_NEW_TASK or Intent.FLAG_ACTIVITY_CLEAR_TOP From 3a94b9ef5cb917b312dc6851261e65c00a938cf3 Mon Sep 17 00:00:00 2001 From: alperozturk96 Date: Wed, 14 Jan 2026 15:04:26 +0100 Subject: [PATCH 139/216] fix Signed-off-by: alperozturk96 --- app/src/main/res/values/strings.xml | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 9df94fe5e626..01cec706c75f 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -1475,4 +1475,8 @@ Failed to create conflict dialog Cannot open file chooser + + File upload conflicts + Upload conflicts detected. Open uploads to resolve. + Resolve conflicts From f4d0fa069201e4cd929bd09f033695a86c1a220a Mon Sep 17 00:00:00 2001 From: alperozturk Date: Mon, 12 Jan 2026 08:54:40 +0100 Subject: [PATCH 140/216] fix(auto-upload): handle existing sync conflicts Signed-off-by: alperozturk --- .../jobs/autoUpload/AutoUploadWorker.kt | 20 ++++++++++++++++--- .../jobs/autoUpload/FileSystemRepository.kt | 2 +- 2 files changed, 18 insertions(+), 4 deletions(-) diff --git a/app/src/main/java/com/nextcloud/client/jobs/autoUpload/AutoUploadWorker.kt b/app/src/main/java/com/nextcloud/client/jobs/autoUpload/AutoUploadWorker.kt index 17b7a7ebad6f..176766c5aa95 100644 --- a/app/src/main/java/com/nextcloud/client/jobs/autoUpload/AutoUploadWorker.kt +++ b/app/src/main/java/com/nextcloud/client/jobs/autoUpload/AutoUploadWorker.kt @@ -34,6 +34,7 @@ import com.owncloud.android.datamodel.SyncedFolder import com.owncloud.android.datamodel.SyncedFolderProvider import com.owncloud.android.datamodel.UploadsStorageManager import com.owncloud.android.db.OCUpload +import com.owncloud.android.db.UploadResult import com.owncloud.android.lib.common.OwnCloudAccount import com.owncloud.android.lib.common.OwnCloudClientManagerFactory import com.owncloud.android.lib.common.utils.Log_OC @@ -302,7 +303,14 @@ class AutoUploadWorker( ) try { - var (uploadEntity, upload) = createEntityAndUpload(user, localPath, remotePath) + val result = createEntityAndUpload(user, localPath, remotePath) + if (result == null) { + repository.markFileAsHandled(localPath, syncedFolder) + Log_OC.d(TAG, "Marked file as handled due to existing conflict: $localPath") + continue + } + + var (uploadEntity, upload) = result // if local file deleted, upload process cannot be started or retriable thus needs to be removed if (path.isEmpty() || !file.exists()) { @@ -331,7 +339,7 @@ class AutoUploadWorker( ) if (result.isSuccess) { - repository.markFileAsUploaded(localPath, syncedFolder) + repository.markFileAsHandled(localPath, syncedFolder) Log_OC.d(TAG, "✅ upload completed: $localPath") } else { Log_OC.e( @@ -375,7 +383,7 @@ class AutoUploadWorker( uploadsStorageManager.removeUpload(upload) } - private fun createEntityAndUpload(user: User, localPath: String, remotePath: String): Pair { + private fun createEntityAndUpload(user: User, localPath: String, remotePath: String): Pair? { val (needsCharging, needsWifi, uploadAction) = getUploadSettings(syncedFolder) Log_OC.d(TAG, "creating oc upload for ${user.accountName}") @@ -386,6 +394,12 @@ class AutoUploadWorker( accountName = user.accountName ) + val lastUploadResult = uploadEntity?.lastResult?.let { UploadResult.fromValue(it) } + if (lastUploadResult == UploadResult.SYNC_CONFLICT) { + Log_OC.w(TAG, "Conflict already exists, skipping auto-upload: $localPath") + return null + } + val upload = ( uploadEntity?.toOCUpload(null) ?: OCUpload( localPath, diff --git a/app/src/main/java/com/nextcloud/client/jobs/autoUpload/FileSystemRepository.kt b/app/src/main/java/com/nextcloud/client/jobs/autoUpload/FileSystemRepository.kt index b322b1bc7fc4..9ff924c6aadf 100644 --- a/app/src/main/java/com/nextcloud/client/jobs/autoUpload/FileSystemRepository.kt +++ b/app/src/main/java/com/nextcloud/client/jobs/autoUpload/FileSystemRepository.kt @@ -63,7 +63,7 @@ class FileSystemRepository(private val dao: FileSystemDao, private val context: return filtered } - suspend fun markFileAsUploaded(localPath: String, syncedFolder: SyncedFolder) { + suspend fun markFileAsHandled(localPath: String, syncedFolder: SyncedFolder) { val syncedFolderIdStr = syncedFolder.id.toString() try { From 7ad6bd9cebaf984d51b9aa0dbd22532366872684 Mon Sep 17 00:00:00 2001 From: alperozturk Date: Mon, 12 Jan 2026 08:55:47 +0100 Subject: [PATCH 141/216] fix(auto-upload): codacy Signed-off-by: alperozturk --- .../nextcloud/client/jobs/autoUpload/AutoUploadWorker.kt | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/app/src/main/java/com/nextcloud/client/jobs/autoUpload/AutoUploadWorker.kt b/app/src/main/java/com/nextcloud/client/jobs/autoUpload/AutoUploadWorker.kt index 176766c5aa95..77d9efc41695 100644 --- a/app/src/main/java/com/nextcloud/client/jobs/autoUpload/AutoUploadWorker.kt +++ b/app/src/main/java/com/nextcloud/client/jobs/autoUpload/AutoUploadWorker.kt @@ -383,7 +383,11 @@ class AutoUploadWorker( uploadsStorageManager.removeUpload(upload) } - private fun createEntityAndUpload(user: User, localPath: String, remotePath: String): Pair? { + private fun createEntityAndUpload( + user: User, + localPath: String, + remotePath: String + ): Pair? { val (needsCharging, needsWifi, uploadAction) = getUploadSettings(syncedFolder) Log_OC.d(TAG, "creating oc upload for ${user.accountName}") From b11a49d1c42988ebd08ec0f32ffd06243ca6a6fa Mon Sep 17 00:00:00 2001 From: alperozturk96 Date: Wed, 14 Jan 2026 15:38:06 +0100 Subject: [PATCH 142/216] chore: bump version to v3.35.0 RC4 Signed-off-by: alperozturk96 --- app/build.gradle.kts | 2 +- fastlane/metadata/android/en-US/changelogs/30350054.txt | 7 +++++++ .../metadata/android/en-US/changelogs/30350054.txt.license | 2 ++ 3 files changed, 10 insertions(+), 1 deletion(-) create mode 100644 fastlane/metadata/android/en-US/changelogs/30350054.txt create mode 100644 fastlane/metadata/android/en-US/changelogs/30350054.txt.license diff --git a/app/build.gradle.kts b/app/build.gradle.kts index 8016ee66426e..786f0cbc6579 100644 --- a/app/build.gradle.kts +++ b/app/build.gradle.kts @@ -65,7 +65,7 @@ configurations.configureEach { val versionMajor = 3 val versionMinor = 35 val versionPatch = 0 -val versionBuild = 53 // 0-50=Alpha / 51-98=RC / 90-99=stable +val versionBuild = 54 // 0-50=Alpha / 51-98=RC / 90-99=stable val ndkEnv = buildMap { file("${project.rootDir}/ndk.env").readLines().forEach { diff --git a/fastlane/metadata/android/en-US/changelogs/30350054.txt b/fastlane/metadata/android/en-US/changelogs/30350054.txt new file mode 100644 index 000000000000..0e671f560b1e --- /dev/null +++ b/fastlane/metadata/android/en-US/changelogs/30350054.txt @@ -0,0 +1,7 @@ +## 3.35.0 RC4 (January 14, 2026) + +- Auto-upload fixes + +Minimum: NC 20 Server, Android 9 Pie + +For a full list, please see https://github.com/nextcloud/android/milestone/118 \ No newline at end of file diff --git a/fastlane/metadata/android/en-US/changelogs/30350054.txt.license b/fastlane/metadata/android/en-US/changelogs/30350054.txt.license new file mode 100644 index 000000000000..a67e1fec2721 --- /dev/null +++ b/fastlane/metadata/android/en-US/changelogs/30350054.txt.license @@ -0,0 +1,2 @@ +# SPDX-FileCopyrightText: 2026 Nextcloud GmbH and Nextcloud contributors +# SPDX-License-Identifier: AGPL-3.0-or-later \ No newline at end of file From 0bbdc13e82c88fb6b802a981675b0bc36ad4403d Mon Sep 17 00:00:00 2001 From: Nextcloud bot Date: Thu, 15 Jan 2026 02:52:38 +0000 Subject: [PATCH 143/216] fix(l10n): Update translations from Transifex Signed-off-by: Nextcloud bot --- app/src/main/res/values-de/strings.xml | 2 ++ app/src/main/res/values-et-rEE/strings.xml | 3 +++ app/src/main/res/values-gl/strings.xml | 2 ++ app/src/main/res/values-pt-rBR/strings.xml | 3 +++ app/src/main/res/values-zh-rTW/strings.xml | 2 ++ 5 files changed, 12 insertions(+) diff --git a/app/src/main/res/values-de/strings.xml b/app/src/main/res/values-de/strings.xml index f3c3e4a7ed23..402f2c2b1069 100644 --- a/app/src/main/res/values-de/strings.xml +++ b/app/src/main/res/values-de/strings.xml @@ -13,6 +13,7 @@ Senden/Teilen Kachelansicht Listenansicht + Aktion ausgelöst Kontakte und Kalender wiederherstellen Neuer Ordner Verschieben oder kopieren @@ -396,6 +397,7 @@ Die Erstellung des Konfliktdialogs ist fehlgeschlagen Datei konnte nicht an den Downloadmanager übergeben werden Datei konnte nicht gedruckt werden + Aktion konnte nicht gestartet werden! Editor konnte nicht gestartet werden Oberfläche konnte nicht aktualisiert werden Zu den Favoriten hinzufügen diff --git a/app/src/main/res/values-et-rEE/strings.xml b/app/src/main/res/values-et-rEE/strings.xml index aca0ec75b651..b614b47a77a8 100644 --- a/app/src/main/res/values-et-rEE/strings.xml +++ b/app/src/main/res/values-et-rEE/strings.xml @@ -13,6 +13,7 @@ Saada või jaga Ruudustikvaade Loendivaade + Tegevus käivitatud Taasta kontaktid ja kalender Uus kaust Teisalda või kopeeri @@ -396,6 +397,7 @@ Failikonfilktiteabe vaate loomine ei õnnestu Ei õnnestunud faili allalaadimishaldurile edasi anda Faili trükkimine ei õnnestunud + Tegevuse käivitamine ei õnnestunud! Ei õnnestunud avada muutmisvaadet Kasutajaliidese uuendamine ei õnnestunud Lisa lemmikutesse @@ -755,6 +757,7 @@ Välp Halda sisemisi kaustu kahepoolse sünkroonimise jaoks Luba kahepoolne sünkroonimine + Kahepoolne sünkroonimine Hele Tume Kasuta süsteemi kujundust diff --git a/app/src/main/res/values-gl/strings.xml b/app/src/main/res/values-gl/strings.xml index 5e6964c11180..eeb1b07a788f 100644 --- a/app/src/main/res/values-gl/strings.xml +++ b/app/src/main/res/values-gl/strings.xml @@ -13,6 +13,7 @@ Enviar/compartir Ver como grade Ver como lista + Acción activada Restaurar contactos e calendario Novo cartafol Mover ou copiar @@ -396,6 +397,7 @@ Produciuse un fallo ao crear o diálogo de conflito Produciuse un fallo ao pasar o ficheiro para o xestor de descargas Produciuse un fallo ao imprimir o ficheiro + Produciuse un fallo ao iniciar a acción! Produciuse un fallo ao iniciar o editor Produciuse un fallo ao actualizar a IU Engadir a favoritos diff --git a/app/src/main/res/values-pt-rBR/strings.xml b/app/src/main/res/values-pt-rBR/strings.xml index b7ff9a8698ea..1554e5397a9f 100644 --- a/app/src/main/res/values-pt-rBR/strings.xml +++ b/app/src/main/res/values-pt-rBR/strings.xml @@ -13,6 +13,7 @@ Enviar/compartilhar Vista em grade Lista de visualização + Ação acionada Restaurar contatos e calendário Nova pasta Mover ou copiar @@ -396,6 +397,7 @@ Falha ao criar caixa de diálogo de conflito Erro ao enviar o arquivo ao gerenciador de downloads Erro ao imprimir o arquivo + Falha ao iniciar a ação! Erro ao iniciar editor Falha ao atualizar a interface gráfica Adicionar aos favoritos @@ -755,6 +757,7 @@ Intervalo Gerenciar pastas internas para sincronização bidirecional Ativar sincronização bidirecional + Sincronização bidirecional Escuro Claro Seguir o sistema diff --git a/app/src/main/res/values-zh-rTW/strings.xml b/app/src/main/res/values-zh-rTW/strings.xml index 098746c4423a..e75b8adcbb48 100644 --- a/app/src/main/res/values-zh-rTW/strings.xml +++ b/app/src/main/res/values-zh-rTW/strings.xml @@ -13,6 +13,7 @@ 傳送/分享 格狀檢視 清單檢視 + 觸發動作 復原聯絡人與行事曆 新資料夾 移動或複製 @@ -396,6 +397,7 @@ 無法建立衝突對話方塊 無法將檔案傳遞給下載管理程式 檔案列印失敗 + 開始動作失敗! 無法啟動編輯器 更新使用者介面失敗 新增至喜愛 From 4389d19c7259ef066a57635f35618af6d393d64e Mon Sep 17 00:00:00 2001 From: Nextcloud bot Date: Fri, 16 Jan 2026 03:01:40 +0000 Subject: [PATCH 144/216] fix(l10n): Update translations from Transifex Signed-off-by: Nextcloud bot --- app/src/main/res/values-de/strings.xml | 3 +++ app/src/main/res/values-gl/strings.xml | 3 +++ app/src/main/res/values-tr/strings.xml | 6 ++++++ app/src/main/res/values-uk/strings.xml | 6 ++++++ app/src/main/res/values-zh-rTW/strings.xml | 3 +++ 5 files changed, 21 insertions(+) diff --git a/app/src/main/res/values-de/strings.xml b/app/src/main/res/values-de/strings.xml index 402f2c2b1069..86e0fe430b2f 100644 --- a/app/src/main/res/values-de/strings.xml +++ b/app/src/main/res/values-de/strings.xml @@ -962,6 +962,9 @@ Vorschlagen Synchronisieren Trotzdem synchronisieren + Konflikte lösen + Datei-Konflikte beim Hochladen erkannt. \"Uploads\" öffen, um sie aufzulösen. + Dateikonflikte beim Hochladen Konflikte gefunden Der Ordner %1$s existiert nicht mehr Synchronisierungsduplizierung diff --git a/app/src/main/res/values-gl/strings.xml b/app/src/main/res/values-gl/strings.xml index eeb1b07a788f..9f80ac0239b5 100644 --- a/app/src/main/res/values-gl/strings.xml +++ b/app/src/main/res/values-gl/strings.xml @@ -963,6 +963,9 @@ Suxerir Sincronizar Sincronizar de todos os xeitos + Resolver conflitos + Detectáronse conflitos de envío. Abra os envíos para resolvelos. + Conflitos no envío de ficheiros Atopáronse conflitos O cartafol %1$s xa non existe Duplicación de sincronización diff --git a/app/src/main/res/values-tr/strings.xml b/app/src/main/res/values-tr/strings.xml index 9a3ec361d629..345d1de6376b 100644 --- a/app/src/main/res/values-tr/strings.xml +++ b/app/src/main/res/values-tr/strings.xml @@ -13,6 +13,7 @@ Gönder/paylaş Tablo görünümü Liste görünümü + İşlem tetiklendi Kişileri ve takvimi geri yükle Yeni klasör Taşı ya da kopyala @@ -396,6 +397,7 @@ Çakışma penceresi oluşturulamadı Dosya indirme yöneticisine aktarılamadı Dosya yazdırılamadı + İşlem başlatılamadı! Düzenleyici başlatılamadı Kullanıcı arayüzü güncellenemedi Sık kullanılanlara ekle @@ -755,6 +757,7 @@ Aralık İç klasörleri iki yönlü eşitleme ile yönetin İki yönlü eşitlemeyi aç + İki yönlü eşitleme Koyu Açık Sistem ayarı @@ -959,6 +962,9 @@ Öner Eşitle Yine de eşitle + Çakışmaları çözümle + Yükleme çakışmaları bulundu. Çözümlemek için yüklemeleri açın. + Dosya yükleme çakışmaları Çakışmalar bulundu %1$s klasörü artık yok Eşitleme çifti diff --git a/app/src/main/res/values-uk/strings.xml b/app/src/main/res/values-uk/strings.xml index 63ac0c1239e3..1e1f6657e4ea 100644 --- a/app/src/main/res/values-uk/strings.xml +++ b/app/src/main/res/values-uk/strings.xml @@ -13,6 +13,7 @@ Надіслати або поділитися Показувати сіткою Показувати списком + Дію запущено Відновити контакти та календар Новий каталог Перемістити або копіювати @@ -396,6 +397,7 @@ Не вдалося створити вікно з інформацією про конфлікт Не вдалося передати файл до менеджера звантажень Не вдалося роздрукувати файл + Не вдалося виконати дію! Не вдалося відкрити редактор Неможливо оновити інтерфейс Додати зірочку @@ -755,6 +757,7 @@ Інтервал Керувати внутрішніми каталогами для двосторонньої синхронізації Увімкнути двосторонню синхронізацію + Двостороння синхронізація Темна Світла Системна @@ -959,6 +962,9 @@ Запропонувати Синхронізація Синхронізувати попри все + Вирішити конфлікти + Знайдено конфлікти при завантаженні. Відкрийте завантаження для вирішення. + Конфлікти при завантаженні файлів Конфліктів знайдено Каталог %1$s більше недоступний Синхронізувати із задвоєнням diff --git a/app/src/main/res/values-zh-rTW/strings.xml b/app/src/main/res/values-zh-rTW/strings.xml index e75b8adcbb48..bb5bf971fcad 100644 --- a/app/src/main/res/values-zh-rTW/strings.xml +++ b/app/src/main/res/values-zh-rTW/strings.xml @@ -962,6 +962,9 @@ 建議 同步 仍要同步 + 解決衝突 + 偵測到上傳衝突。請開啟上傳檔案以解決問題。 + 檔案上傳衝突 出現衝突 資料夾 %1$s 已不存在 重複同步 From c8bdf540ae1fbd2748d0b39b5695262c75f43aac Mon Sep 17 00:00:00 2001 From: Nextcloud bot Date: Sat, 17 Jan 2026 02:48:11 +0000 Subject: [PATCH 145/216] fix(l10n): Update translations from Transifex Signed-off-by: Nextcloud bot --- app/src/main/res/values-b+en+001/strings.xml | 1 + app/src/main/res/values-cs-rCZ/strings.xml | 1 + app/src/main/res/values-de/strings.xml | 1 + app/src/main/res/values-es/strings.xml | 1 + app/src/main/res/values-et-rEE/strings.xml | 1 + app/src/main/res/values-ga/strings.xml | 7 +++++++ app/src/main/res/values-gl/strings.xml | 1 + app/src/main/res/values-pt-rBR/strings.xml | 1 + app/src/main/res/values-sk-rSK/strings.xml | 1 + app/src/main/res/values-tr/strings.xml | 1 + app/src/main/res/values-ug/strings.xml | 1 + app/src/main/res/values-uk/strings.xml | 1 + app/src/main/res/values-zh-rHK/strings.xml | 1 + app/src/main/res/values-zh-rTW/strings.xml | 1 + 14 files changed, 20 insertions(+) diff --git a/app/src/main/res/values-b+en+001/strings.xml b/app/src/main/res/values-b+en+001/strings.xml index 6763c16e08f5..aade6f962c9f 100644 --- a/app/src/main/res/values-b+en+001/strings.xml +++ b/app/src/main/res/values-b+en+001/strings.xml @@ -825,6 +825,7 @@ Please select one template Select template Send + Send copy to Send share Send button icon Could not load content diff --git a/app/src/main/res/values-cs-rCZ/strings.xml b/app/src/main/res/values-cs-rCZ/strings.xml index ceb83eb969d7..1067beb14858 100644 --- a/app/src/main/res/values-cs-rCZ/strings.xml +++ b/app/src/main/res/values-cs-rCZ/strings.xml @@ -825,6 +825,7 @@ Vyberte jednu šablonu Vybrat šablonu Odeslat + Poslat kopii uživateli Poslat sdílení Ikona tlačítka pro odesílání Nepodařilo se načíst obsah diff --git a/app/src/main/res/values-de/strings.xml b/app/src/main/res/values-de/strings.xml index 86e0fe430b2f..87349b5b16c7 100644 --- a/app/src/main/res/values-de/strings.xml +++ b/app/src/main/res/values-de/strings.xml @@ -828,6 +828,7 @@ Bitte eine Vorlage auswählen Vorlage auswählen Senden + Kopie senden an Freigabe senden Icon für den Senden-Button Inhalt konnte nicht geladen werden diff --git a/app/src/main/res/values-es/strings.xml b/app/src/main/res/values-es/strings.xml index ee5034bd07d0..2be13fec8ec9 100644 --- a/app/src/main/res/values-es/strings.xml +++ b/app/src/main/res/values-es/strings.xml @@ -798,6 +798,7 @@ Por favor, selecciona una plantilla Escoge plantilla Mandar + Enviar copia a Enviar recurso compartido Icono del botón de enviar No se pudo cargar el contenido diff --git a/app/src/main/res/values-et-rEE/strings.xml b/app/src/main/res/values-et-rEE/strings.xml index b614b47a77a8..aadceb0e09d5 100644 --- a/app/src/main/res/values-et-rEE/strings.xml +++ b/app/src/main/res/values-et-rEE/strings.xml @@ -828,6 +828,7 @@ Palun vali üks mall Vali mall Saada + Saada koopia asukohta Saada jaosmeediat Saatmisnupu ikoon Sisu laadimine ei õnnestunud diff --git a/app/src/main/res/values-ga/strings.xml b/app/src/main/res/values-ga/strings.xml index fb7dffe6ec72..b0e8d6725bb0 100644 --- a/app/src/main/res/values-ga/strings.xml +++ b/app/src/main/res/values-ga/strings.xml @@ -13,6 +13,7 @@ Seol/roinn Radharc greille Amharc liosta + Gníomh spreagtha Athchóirigh teagmhálacha agus féilire Fillteán nua Bog nó cóipeáil @@ -396,6 +397,7 @@ Theip ar chomhrá coinbhleachta a chruthú Theip ar an gcomhad a chur ar aghaidh chuig an mbainisteoir íoslódála Theip ar an gcomhad a phriontáil + Theip ar an ngníomh a thosú! Theip ar an eagarthóir a thosú Theip ar an Chomhéadain a nuashonrú Cuir le ceanáin @@ -755,6 +757,7 @@ Eatramh Bainistigh fillteáin inmheánacha le haghaidh sioncronaithe dhá bhealach Cumasaigh sioncronú dhá bhealach + Sioncrónú dhá bhealach Dorcha Solas Lean an córas @@ -825,6 +828,7 @@ Roghnaigh teimpléad amháin le do thoil Roghnaigh teimpléad Seol + Seol cóip chuig Seol sciar Seol deilbhín cnaipe Níorbh fhéidir an t-ábhar a lódáil @@ -959,6 +963,9 @@ Mol Sioncrónaigh Sioncrónaigh ar aon nós + Réiteach coinbhleachtaí + Coimhlintí uaslódála braite. Oscail uaslódálacha le réiteach. + Coimhlintí uaslódála comhad Coimhlint aimsithe Níl fillteán %1$s ann a thuilleadh Sioncronaigh dúbailt diff --git a/app/src/main/res/values-gl/strings.xml b/app/src/main/res/values-gl/strings.xml index 9f80ac0239b5..ad61a89c1813 100644 --- a/app/src/main/res/values-gl/strings.xml +++ b/app/src/main/res/values-gl/strings.xml @@ -829,6 +829,7 @@ Seleccione un modelo Seleccionar o modelo Enviar + Enviar copia a Enviar o compartido Icona do botón de envío Non foi posíbel cargar o contido diff --git a/app/src/main/res/values-pt-rBR/strings.xml b/app/src/main/res/values-pt-rBR/strings.xml index 1554e5397a9f..fb833d6fd28f 100644 --- a/app/src/main/res/values-pt-rBR/strings.xml +++ b/app/src/main/res/values-pt-rBR/strings.xml @@ -828,6 +828,7 @@ Selecione um modelo Selecionar modelo Enviar + Enviar cópia para Enviar compartilhamento Ícone do botão Enviar Não foi possível carregar o conteúdo diff --git a/app/src/main/res/values-sk-rSK/strings.xml b/app/src/main/res/values-sk-rSK/strings.xml index 88d5fdc810be..88804de08dc6 100644 --- a/app/src/main/res/values-sk-rSK/strings.xml +++ b/app/src/main/res/values-sk-rSK/strings.xml @@ -825,6 +825,7 @@ Vyberte jednu šablónu Vybrať šablónu Odoslať + Odoslať kópiu na Odoslať zdieľanie Ikona tlačidla na odoslanie Nepodarilo sa načítať obsah diff --git a/app/src/main/res/values-tr/strings.xml b/app/src/main/res/values-tr/strings.xml index 345d1de6376b..32d8900a25a1 100644 --- a/app/src/main/res/values-tr/strings.xml +++ b/app/src/main/res/values-tr/strings.xml @@ -828,6 +828,7 @@ Lütfen bir kalıp seçin Kalıp seçin Gönder + Kopyasını şuraya gönder Paylaşım gönder Gönderme düğmesi simgesi İçerik yüklenemedi diff --git a/app/src/main/res/values-ug/strings.xml b/app/src/main/res/values-ug/strings.xml index ba41795093e6..0814f9a807b9 100644 --- a/app/src/main/res/values-ug/strings.xml +++ b/app/src/main/res/values-ug/strings.xml @@ -825,6 +825,7 @@ بىر قېلىپنى تاللاڭ قېلىپنى تاللاڭ ئەۋەتىڭ + كۆچۈرمىسىنى ئەۋەت ھەمبەھىر ئەۋەتىش كۇنۇپكا سىنبەلگىسىنى ئەۋەتىڭ مەزمۇننى يۈكلىيەلمىدى diff --git a/app/src/main/res/values-uk/strings.xml b/app/src/main/res/values-uk/strings.xml index 1e1f6657e4ea..ed23bb0f05a8 100644 --- a/app/src/main/res/values-uk/strings.xml +++ b/app/src/main/res/values-uk/strings.xml @@ -828,6 +828,7 @@ Будь ласка, виберіть один шаблон. Виберіть шаблон Надіслати + Надіслати копію до Надати у спільний доступ Зображення кнопки надсилання Не вдалося завантажити вміст diff --git a/app/src/main/res/values-zh-rHK/strings.xml b/app/src/main/res/values-zh-rHK/strings.xml index 79ebf9723261..e1fb8213059b 100644 --- a/app/src/main/res/values-zh-rHK/strings.xml +++ b/app/src/main/res/values-zh-rHK/strings.xml @@ -825,6 +825,7 @@ 請選擇一個模板 選擇範本 傳送 + 傳送副本至 傳送分享 傳送按鈕圖示 無法載入內容 diff --git a/app/src/main/res/values-zh-rTW/strings.xml b/app/src/main/res/values-zh-rTW/strings.xml index bb5bf971fcad..0d422c50da2d 100644 --- a/app/src/main/res/values-zh-rTW/strings.xml +++ b/app/src/main/res/values-zh-rTW/strings.xml @@ -828,6 +828,7 @@ 請選取一個範本 選取範本 傳送 + 傳送副本至 傳送分享 傳送按鈕圖示 無法載入內容 From dcc590d73f70581ad2d448be6275bc545d0dc088 Mon Sep 17 00:00:00 2001 From: Nextcloud bot Date: Sun, 18 Jan 2026 02:51:34 +0000 Subject: [PATCH 146/216] fix(l10n): Update translations from Transifex Signed-off-by: Nextcloud bot --- app/src/main/res/values-b+en+001/strings.xml | 6 ++++++ app/src/main/res/values-et-rEE/strings.xml | 3 +++ app/src/main/res/values-zh-rHK/strings.xml | 6 ++++++ 3 files changed, 15 insertions(+) diff --git a/app/src/main/res/values-b+en+001/strings.xml b/app/src/main/res/values-b+en+001/strings.xml index aade6f962c9f..9a3f66162722 100644 --- a/app/src/main/res/values-b+en+001/strings.xml +++ b/app/src/main/res/values-b+en+001/strings.xml @@ -13,6 +13,7 @@ Send/share Grid view List view + Action triggered Restore contacts and calendar New folder Move or copy @@ -396,6 +397,7 @@ Failed to create conflict dialog Failed to pass file to download manager Failed to print file + Failed to start action! Failed to start editor Failed to update UI Add to favourites @@ -755,6 +757,7 @@ Interval Manage internal folders for two way sync Enable two way sync + Two way sync Dark Light Follow system @@ -960,6 +963,9 @@ Suggest Sync Sync anyway + Resolve conflicts + Upload conflicts detected. Open uploads to resolve. + File upload conflicts Conflicts found The folder %1$s does not exist any more Sync duplication diff --git a/app/src/main/res/values-et-rEE/strings.xml b/app/src/main/res/values-et-rEE/strings.xml index aadceb0e09d5..66099a30074b 100644 --- a/app/src/main/res/values-et-rEE/strings.xml +++ b/app/src/main/res/values-et-rEE/strings.xml @@ -963,6 +963,9 @@ Soovita Sünkrooni Sünkrooni ikkagi + Lahenda failikonfliktid + Tuvastasin failide üleslaadimiskonflikte. Lahendamiseks ava üleslaadimiste vaade. + Failide üleslaadimiskonfliktid Leidsin failikonflikte „%1$s“ kausta pole enam olemas Sünkroonimisel tuvastatud duplikaat diff --git a/app/src/main/res/values-zh-rHK/strings.xml b/app/src/main/res/values-zh-rHK/strings.xml index e1fb8213059b..86f8090effec 100644 --- a/app/src/main/res/values-zh-rHK/strings.xml +++ b/app/src/main/res/values-zh-rHK/strings.xml @@ -13,6 +13,7 @@ 傳送/分享 網格檢視 清單檢視 + 已觸發操作 復原通訊錄與日曆 新資料夾 移動或複製 @@ -396,6 +397,7 @@ 無法建立衝突對話框 無法下載 列印失敗 + 無法啟動操作! 起始編輯器失敗 更新 UI 失敗 加到我的最愛 @@ -755,6 +757,7 @@ 間距 管理內部資料夾以進行雙向同步 啟用雙向同步 + 雙向同步 深色 淺色 跟隨系統 @@ -960,6 +963,9 @@ 建議 同步 仍然同步 + 解決抵觸 + 偵測到上載衝突。請開啟上載項目以解決問題。 + 檔案上載衝突。 出現抵觸 資料夾 %1$s 已不存在 重複同步 From 472ffe45951cb7519f0fc4f64a5ef5f38a209c8c Mon Sep 17 00:00:00 2001 From: Nextcloud bot Date: Mon, 19 Jan 2026 03:01:28 +0000 Subject: [PATCH 147/216] fix(l10n): Update translations from Transifex Signed-off-by: Nextcloud bot --- app/src/main/res/values-ru/strings.xml | 7 +++++++ app/src/main/res/values-uk/strings.xml | 2 +- 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/app/src/main/res/values-ru/strings.xml b/app/src/main/res/values-ru/strings.xml index 6dfd569a8b05..5202dde89206 100644 --- a/app/src/main/res/values-ru/strings.xml +++ b/app/src/main/res/values-ru/strings.xml @@ -211,6 +211,7 @@ Удалить обсуждение Не удалось создать чат. Не найдено ни одного обсуждения + Еще ни одного обсуждения Беседы Скопировано Произошла ошибка при попытке копирования этого файла или каталога @@ -737,6 +738,7 @@ Интервал Управление внутренними папками для двусторонней синхронизации Включить двустороннюю синхронизацию + Двусторонняя синхронизация Тёмное Светлое Как в системе @@ -807,6 +809,7 @@ Пожалуйста, выберите один шаблон Выбрать шаблон Отправить + Отправить копию Отправить ссылку Значок кнопки «отправить» Не удалось загрузить содержимое. @@ -940,6 +943,7 @@ Посоветовать Синхронизировать Синхронизация в любом случае + Конфликт при загрузке файла Обнаружены конфликты Каталог %1$s больше не существует Дублирование синхронизации @@ -994,6 +998,7 @@ Событие не найдено, вы всегда можете синхронизировать его для обновления. Перенаправление на веб-страницу… Контакт не найден, вы всегда можете синхронизировать его для обновления. Перенаправление на веб-страницу… Для открытия результата поиска требуются разрешения, в противном случае он будет перенаправлен на веб-страницу… + В этой папке Неизвестно Разблокировать файл Имеются непрочитанные комментарии @@ -1100,6 +1105,8 @@ Сертификат сервера не является доверенным Получение версия сервера… Работа приложения была прекращена + Пропущенно + Объект с таким же именем уже существует. Завершено Идентичный файл найден на удаленном сервере, загрузка пропущена Неизвестная ошибка diff --git a/app/src/main/res/values-uk/strings.xml b/app/src/main/res/values-uk/strings.xml index ed23bb0f05a8..f3e5bd65caf3 100644 --- a/app/src/main/res/values-uk/strings.xml +++ b/app/src/main/res/values-uk/strings.xml @@ -406,7 +406,7 @@ Неможливо оновити спільні файли Файл з таким ім\'ям вже присутній Вилучити - Помилка з отриманням дії для файлу + Помилка з отриманням подій для файлу Ви не можете створити спільний ресурс, оскільки його вже надано цьому користувачеві. Відсутній застосунок для вибору контактів Не вдалося завантажити подробиці From 4f03389b95ffaadff6035242616cbdb660ce2927 Mon Sep 17 00:00:00 2001 From: alperozturk96 Date: Mon, 19 Jan 2026 15:01:14 +0100 Subject: [PATCH 148/216] chore: bump version to v3.35.0 Signed-off-by: alperozturk96 --- app/build.gradle.kts | 2 +- fastlane/metadata/android/en-US/changelogs/30350090.txt | 8 ++++++++ .../android/en-US/changelogs/30350090.txt.license | 2 ++ 3 files changed, 11 insertions(+), 1 deletion(-) create mode 100644 fastlane/metadata/android/en-US/changelogs/30350090.txt create mode 100644 fastlane/metadata/android/en-US/changelogs/30350090.txt.license diff --git a/app/build.gradle.kts b/app/build.gradle.kts index 786f0cbc6579..7027184b9198 100644 --- a/app/build.gradle.kts +++ b/app/build.gradle.kts @@ -65,7 +65,7 @@ configurations.configureEach { val versionMajor = 3 val versionMinor = 35 val versionPatch = 0 -val versionBuild = 54 // 0-50=Alpha / 51-98=RC / 90-99=stable +val versionBuild = 90 // 0-50=Alpha / 51-98=RC / 90-99=stable val ndkEnv = buildMap { file("${project.rootDir}/ndk.env").readLines().forEach { diff --git a/fastlane/metadata/android/en-US/changelogs/30350090.txt b/fastlane/metadata/android/en-US/changelogs/30350090.txt new file mode 100644 index 000000000000..2a58cb2ca4da --- /dev/null +++ b/fastlane/metadata/android/en-US/changelogs/30350090.txt @@ -0,0 +1,8 @@ +## 3.35.0 (January 19, 2026) + +- Auto-upload fixes +- Performance improvements + +Minimum: NC 20 Server, Android 9 Pie + +For a full list, please see https://github.com/nextcloud/android/milestone/118 \ No newline at end of file diff --git a/fastlane/metadata/android/en-US/changelogs/30350090.txt.license b/fastlane/metadata/android/en-US/changelogs/30350090.txt.license new file mode 100644 index 000000000000..a67e1fec2721 --- /dev/null +++ b/fastlane/metadata/android/en-US/changelogs/30350090.txt.license @@ -0,0 +1,2 @@ +# SPDX-FileCopyrightText: 2026 Nextcloud GmbH and Nextcloud contributors +# SPDX-License-Identifier: AGPL-3.0-or-later \ No newline at end of file From dbf83ce08f719b258322eff75160ceae8b92beca Mon Sep 17 00:00:00 2001 From: alperozturk96 Date: Mon, 19 Jan 2026 15:01:45 +0100 Subject: [PATCH 149/216] chore: bump version to v3.35.0 Signed-off-by: alperozturk96 --- fastlane/metadata/android/en-US/changelogs/30350090.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/fastlane/metadata/android/en-US/changelogs/30350090.txt b/fastlane/metadata/android/en-US/changelogs/30350090.txt index 2a58cb2ca4da..46767b3df7c2 100644 --- a/fastlane/metadata/android/en-US/changelogs/30350090.txt +++ b/fastlane/metadata/android/en-US/changelogs/30350090.txt @@ -1,5 +1,6 @@ ## 3.35.0 (January 19, 2026) +- Bugfixes - Auto-upload fixes - Performance improvements From 4f219ef09b841cd553f755557f365f343ac971d8 Mon Sep 17 00:00:00 2001 From: Nextcloud bot Date: Tue, 20 Jan 2026 02:50:45 +0000 Subject: [PATCH 150/216] fix(l10n): Update translations from Transifex Signed-off-by: Nextcloud bot --- app/src/main/res/values-pt-rBR/strings.xml | 3 +++ app/src/main/res/values-th-rTH/strings.xml | 1 + 2 files changed, 4 insertions(+) diff --git a/app/src/main/res/values-pt-rBR/strings.xml b/app/src/main/res/values-pt-rBR/strings.xml index fb833d6fd28f..7604db378a9a 100644 --- a/app/src/main/res/values-pt-rBR/strings.xml +++ b/app/src/main/res/values-pt-rBR/strings.xml @@ -963,6 +963,9 @@ Sugerir Sincronizar Sincronizar mesmo assim + Resolver conflitos + Conflitos de upload detectados. Abra os uploads para resolver. + Conflitos de upload de arquivos Conflitos encontrados A pasta %1$s não existe mais Duplicação de sincronização diff --git a/app/src/main/res/values-th-rTH/strings.xml b/app/src/main/res/values-th-rTH/strings.xml index b445f08ddecb..09b04cba4eaa 100644 --- a/app/src/main/res/values-th-rTH/strings.xml +++ b/app/src/main/res/values-th-rTH/strings.xml @@ -351,6 +351,7 @@ อัปโหลดไฟล์ที่มีอยู่เดิมด้วย อัปโหลดขณะชาร์จเท่านั้น /อัพโหลดทันที + การแชร์ภายใน URL ไม่ถูกต้อง มองไม่เห็น ป้ายกำกับไม่สามารถเว้นว่างได้ From 5d25509bf9117cf95a86b3faf750663c42dfdc90 Mon Sep 17 00:00:00 2001 From: Nextcloud bot Date: Thu, 22 Jan 2026 02:57:46 +0000 Subject: [PATCH 151/216] fix(l10n): Update translations from Transifex Signed-off-by: Nextcloud bot --- app/src/main/res/values-ar/strings.xml | 1 + app/src/main/res/values-ast/strings.xml | 1 + app/src/main/res/values-b+en+001/strings.xml | 1 + app/src/main/res/values-bg-rBG/strings.xml | 1 + app/src/main/res/values-ca/strings.xml | 1 + app/src/main/res/values-cs-rCZ/strings.xml | 1 + app/src/main/res/values-da/strings.xml | 1 + app/src/main/res/values-de/strings.xml | 1 + app/src/main/res/values-el/strings.xml | 1 + app/src/main/res/values-es-rAR/strings.xml | 1 + app/src/main/res/values-es-rMX/strings.xml | 1 + app/src/main/res/values-es/strings.xml | 1 + app/src/main/res/values-et-rEE/strings.xml | 1 + app/src/main/res/values-eu/strings.xml | 1 + app/src/main/res/values-fa/strings.xml | 1 + app/src/main/res/values-fi-rFI/strings.xml | 1 + app/src/main/res/values-fr/strings.xml | 6 +++++- app/src/main/res/values-ga/strings.xml | 1 + app/src/main/res/values-gl/strings.xml | 1 + app/src/main/res/values-hu-rHU/strings.xml | 1 + app/src/main/res/values-is/strings.xml | 1 + app/src/main/res/values-it/strings.xml | 1 + app/src/main/res/values-ja-rJP/strings.xml | 1 + app/src/main/res/values-ka/strings.xml | 1 + app/src/main/res/values-ko/strings.xml | 1 + app/src/main/res/values-lo/strings.xml | 1 + app/src/main/res/values-nb-rNO/strings.xml | 1 + app/src/main/res/values-nl/strings.xml | 1 + app/src/main/res/values-pl/strings.xml | 1 + app/src/main/res/values-pt-rBR/strings.xml | 1 + app/src/main/res/values-ru/strings.xml | 1 + app/src/main/res/values-sk-rSK/strings.xml | 1 + app/src/main/res/values-sr/strings.xml | 1 + app/src/main/res/values-sv/strings.xml | 1 + app/src/main/res/values-sw/strings.xml | 1 + app/src/main/res/values-tr/strings.xml | 1 + app/src/main/res/values-ug/strings.xml | 1 + app/src/main/res/values-uk/strings.xml | 1 + app/src/main/res/values-vi/strings.xml | 1 + app/src/main/res/values-zh-rCN/strings.xml | 1 + app/src/main/res/values-zh-rHK/strings.xml | 1 + app/src/main/res/values-zh-rTW/strings.xml | 1 + 42 files changed, 46 insertions(+), 1 deletion(-) diff --git a/app/src/main/res/values-ar/strings.xml b/app/src/main/res/values-ar/strings.xml index 8ed15c818c37..484baced618a 100644 --- a/app/src/main/res/values-ar/strings.xml +++ b/app/src/main/res/values-ar/strings.xml @@ -175,6 +175,7 @@ هل وجدت خطأ برمجي أو شيء ناقص؟ ساعدنا بالتجريب إرسل تقرير أخطاء على GitHub + مُساعِد نكست كلاود Nextcloud Assistant إعداد إلغاء التشفير المحلي هل توَدُّ حقاً حذف %1$s؟ diff --git a/app/src/main/res/values-ast/strings.xml b/app/src/main/res/values-ast/strings.xml index f1cdfd434851..248802f9b16d 100644 --- a/app/src/main/res/values-ast/strings.xml +++ b/app/src/main/res/values-ast/strings.xml @@ -95,6 +95,7 @@ Cambiar de cuenta Traducir + Asistente de Nextcloud Namái llocal Ficheru llocal Contautos diff --git a/app/src/main/res/values-b+en+001/strings.xml b/app/src/main/res/values-b+en+001/strings.xml index 9a3f66162722..d681b96eb4aa 100644 --- a/app/src/main/res/values-b+en+001/strings.xml +++ b/app/src/main/res/values-b+en+001/strings.xml @@ -188,6 +188,7 @@ Found a bug? Oddments? Help by testing Report an issue on GitHub + Nextcloud Assistant Configure Remove local encryption Do you really want to delete %1$s? diff --git a/app/src/main/res/values-bg-rBG/strings.xml b/app/src/main/res/values-bg-rBG/strings.xml index 2276e65904d4..07dcd54eecee 100644 --- a/app/src/main/res/values-bg-rBG/strings.xml +++ b/app/src/main/res/values-bg-rBG/strings.xml @@ -155,6 +155,7 @@ Открили сте грешка? Нещо странно? Помогни с тестването Докладвайте за проблем чрез Github + Асистент на \"Nextcloud\" Настройки Премахване на локалното криптиране Наистина ли желаете %1$s да бъде изтрит? diff --git a/app/src/main/res/values-ca/strings.xml b/app/src/main/res/values-ca/strings.xml index 6ec01058f7ba..4c0b6166925f 100644 --- a/app/src/main/res/values-ca/strings.xml +++ b/app/src/main/res/values-ca/strings.xml @@ -172,6 +172,7 @@ Heu trobat cap error? Alguna cosa fora del corrent? Ajudar fent proves Informar d\'una incidència a GitHub + Assistent del Nextcloud Configura Suprimeix el xifratge local Esteu segur que voleu suprimir%1$s? diff --git a/app/src/main/res/values-cs-rCZ/strings.xml b/app/src/main/res/values-cs-rCZ/strings.xml index 1067beb14858..f366a2644edd 100644 --- a/app/src/main/res/values-cs-rCZ/strings.xml +++ b/app/src/main/res/values-cs-rCZ/strings.xml @@ -187,6 +187,7 @@ Našli jste chybu? Něco podivného? Pomozte testováním Nahlásit problém prostřednictvím portálu Github + Nextcloud Asistent Nastavit Odebrat lokální šifrování Opravdu chcete %1$s odstranit? diff --git a/app/src/main/res/values-da/strings.xml b/app/src/main/res/values-da/strings.xml index a19c710c8ade..18a9c0639f9d 100644 --- a/app/src/main/res/values-da/strings.xml +++ b/app/src/main/res/values-da/strings.xml @@ -183,6 +183,7 @@ Fundet en fejl? Mærkværdighed? Hjælp med at test Rapportér et problem på Github + Nextcloud assistent Konfigurer Fjern lokal kryptering Er du sikker på at du vil slette %1$s ? diff --git a/app/src/main/res/values-de/strings.xml b/app/src/main/res/values-de/strings.xml index 87349b5b16c7..04fa10cfa4bc 100644 --- a/app/src/main/res/values-de/strings.xml +++ b/app/src/main/res/values-de/strings.xml @@ -188,6 +188,7 @@ Fehler gefunden? Komisches Verhalten? Helfen Sie durch Testen Fehlerbericht auf GitHub erstellen + Nextcloud Assistant Konfigurieren Lokale Verschlüsselung entfernen Wollen Sie %1$s wirklich löschen? diff --git a/app/src/main/res/values-el/strings.xml b/app/src/main/res/values-el/strings.xml index a417c89f7352..44b52de654a9 100644 --- a/app/src/main/res/values-el/strings.xml +++ b/app/src/main/res/values-el/strings.xml @@ -151,6 +151,7 @@ Βρήκατε σφάλμα; Κάτι σας φαίνεται παράξενο; Βοήθησε δοκιμάζοντας Ανέφερε ένα ζήτημα στο GitHub + Βοηθός Nextcloud Ρύθμιση Αφαίρεση τοπικής κρυπτογράφησης Θέλετε σίγουρα να διαγράψετε το %1$s; diff --git a/app/src/main/res/values-es-rAR/strings.xml b/app/src/main/res/values-es-rAR/strings.xml index 9cb4c0b344b1..7e0a93affc7d 100644 --- a/app/src/main/res/values-es-rAR/strings.xml +++ b/app/src/main/res/values-es-rAR/strings.xml @@ -155,6 +155,7 @@ ¿Encontró una falla? ¿Hay algo raro? Ayúdenos probando Reportar un error en GitHub + Asistente de Nextcloud Configurar Eliminar encriptación local ¿Realmente quieres eliminar %1$s? diff --git a/app/src/main/res/values-es-rMX/strings.xml b/app/src/main/res/values-es-rMX/strings.xml index 1c5f08daee8e..97d337bb1740 100644 --- a/app/src/main/res/values-es-rMX/strings.xml +++ b/app/src/main/res/values-es-rMX/strings.xml @@ -160,6 +160,7 @@ ¿Encontraste una falla? ¿Hay algo raro? Ayúdanos probando Reporta un problema en GitHub + Asistente de Nextcloud Configurar Eliminar el cifrado local ¿Realmente deseas elminiar %1$s? diff --git a/app/src/main/res/values-es/strings.xml b/app/src/main/res/values-es/strings.xml index 2be13fec8ec9..43fb50917907 100644 --- a/app/src/main/res/values-es/strings.xml +++ b/app/src/main/res/values-es/strings.xml @@ -180,6 +180,7 @@ ¿Encontraste un error? ¿Algo va mal? Ayúdanos a realizar pruebas Informar de un problema en GitHub + Asistente de Nextcloud Configurar Eliminar cifrado local ¿Estás seguro de que quieres eliminar %1$s? diff --git a/app/src/main/res/values-et-rEE/strings.xml b/app/src/main/res/values-et-rEE/strings.xml index 66099a30074b..40326234ffa1 100644 --- a/app/src/main/res/values-et-rEE/strings.xml +++ b/app/src/main/res/values-et-rEE/strings.xml @@ -188,6 +188,7 @@ Leidsid vea? Midagi veidrat? Aita testimisega Teavita probleemist GitHubis + Nextcloudi Abiline Seadista Eemalda kohalik krüptimine Oled sa kindel, et soovid %1$s kustutada? diff --git a/app/src/main/res/values-eu/strings.xml b/app/src/main/res/values-eu/strings.xml index 045bfb467c90..ad90a6147185 100644 --- a/app/src/main/res/values-eu/strings.xml +++ b/app/src/main/res/values-eu/strings.xml @@ -174,6 +174,7 @@ Errore bat topatu duzu? Gauza arraroren bat? Lagundu probatzen Jakinarazi arazoa GitHub-en + Nextcloud Assistant Konfiguratu Kendu enkriptatze lokala Ziur zaude %1$s ezabatu nahi duzula? diff --git a/app/src/main/res/values-fa/strings.xml b/app/src/main/res/values-fa/strings.xml index f5cf5ff960aa..080085035bec 100644 --- a/app/src/main/res/values-fa/strings.xml +++ b/app/src/main/res/values-fa/strings.xml @@ -149,6 +149,7 @@ خطایی پیدا کردید؟ عجیب و غریب؟ با آزمایش کردن کمک کنید گزارش یک مورد در GitHub + Nextcloud Assistant " پیکربندی" رمزگذاری محلی را حذف کنید. آیا واقعا می‌خواهید %1$s را حذف کنید؟ diff --git a/app/src/main/res/values-fi-rFI/strings.xml b/app/src/main/res/values-fi-rFI/strings.xml index 655283b27198..67e204d36317 100644 --- a/app/src/main/res/values-fi-rFI/strings.xml +++ b/app/src/main/res/values-fi-rFI/strings.xml @@ -167,6 +167,7 @@ Löysitkö bugin tai jotain muuta outoa? Auta testaamalla Ilmoita ongelmasta GitHubissa + Nextcloud-avustaja Asetukset Poista paikallinen salaus Haluatko varmasti poistaa kohteen %1$s? diff --git a/app/src/main/res/values-fr/strings.xml b/app/src/main/res/values-fr/strings.xml index 2f0dcd7b1026..00ae9a9891a7 100644 --- a/app/src/main/res/values-fr/strings.xml +++ b/app/src/main/res/values-fr/strings.xml @@ -18,7 +18,7 @@ Déplacer ou copier Ouvrir avec Rechercher - Propriétés + Détails Envoyer Paramètres Trier @@ -187,6 +187,7 @@ Vous avez trouvé un bug ? Quelque chose vous semble étrange ? Aidez en réalisant des tests Signaler un problème sur Github + Assistant Nextcloud Configurer Retirer le chiffrement local Souhaitez-vous vraiment supprimer %1$s ? @@ -753,6 +754,7 @@ Intervalle Gestion les dossiers internes pour une synchronisation bidirectionnelle Activer la synchronisation bidirectionnelle + Synchronisation bidirectionnelle Sombre Clair Selon le système @@ -957,6 +959,8 @@ Suggérer Synchroniser Synchroniser quand même + Résoudre les conflits + Conflits de téléversement de fichiers Des conflits ont été trouvés Le dossier %1$s n\'existe plus Duplication de synchronisation diff --git a/app/src/main/res/values-ga/strings.xml b/app/src/main/res/values-ga/strings.xml index b0e8d6725bb0..29e68f2e220d 100644 --- a/app/src/main/res/values-ga/strings.xml +++ b/app/src/main/res/values-ga/strings.xml @@ -188,6 +188,7 @@ Aimsíodh fabht? Oddments? Cabhair trí thástáil Tuairiscigh saincheist ar GitHub + Cúntóir Nextcloud Cumraigh Bain criptiú áitiúil An bhfuil tú cinnte gur mhaith leat %1$s a scriosadh? diff --git a/app/src/main/res/values-gl/strings.xml b/app/src/main/res/values-gl/strings.xml index ad61a89c1813..8c8973680b3d 100644 --- a/app/src/main/res/values-gl/strings.xml +++ b/app/src/main/res/values-gl/strings.xml @@ -188,6 +188,7 @@ Atopou un fallo? hai algo estraño? Axúdenos facendo probas Informe dun incidente no GitHub + Asistente de Nextcloud Configurar Retirar a cifraxe local Confirma que quere eliminar %1$s? diff --git a/app/src/main/res/values-hu-rHU/strings.xml b/app/src/main/res/values-hu-rHU/strings.xml index c6203332fb13..50628278fc08 100644 --- a/app/src/main/res/values-hu-rHU/strings.xml +++ b/app/src/main/res/values-hu-rHU/strings.xml @@ -178,6 +178,7 @@ Hibát talált? Vagy furcsaságot? Segítsen a teszteléssel Jelentse az esetet a GitHubon + Nextcloud Asszisztens Beállítás Helyi titkosítás eltávolítása Biztos, hogy törli ezt: %1$s? diff --git a/app/src/main/res/values-is/strings.xml b/app/src/main/res/values-is/strings.xml index f9d6d97d571c..7d00f2a8382b 100644 --- a/app/src/main/res/values-is/strings.xml +++ b/app/src/main/res/values-is/strings.xml @@ -178,6 +178,7 @@ Fannstu villu? Skringilegheit? Hjálpaðu til við prófanir Tilkynntu um vandamál á GitHub + Nextcloud Assistant meðhjálpari Stilla Fjarlægja staðværa dulritun Viltu virkilega eyða \'%s\'? diff --git a/app/src/main/res/values-it/strings.xml b/app/src/main/res/values-it/strings.xml index e64b3279950a..3d50a673a13e 100644 --- a/app/src/main/res/values-it/strings.xml +++ b/app/src/main/res/values-it/strings.xml @@ -187,6 +187,7 @@ Trovato un bug? Stranezze? Aiutaci nella fase di test Segnala un problema su GitHub + Assistente di Nextcloud Configura Rimuovi la cifratura locale Vuoi davvero eliminare %1$s? diff --git a/app/src/main/res/values-ja-rJP/strings.xml b/app/src/main/res/values-ja-rJP/strings.xml index 62f713d214b4..75830dbe0a65 100644 --- a/app/src/main/res/values-ja-rJP/strings.xml +++ b/app/src/main/res/values-ja-rJP/strings.xml @@ -183,6 +183,7 @@ バグがありましたか? 問題がありますか? テストによるヘルプ Githubでエラーを報告する + Nextcloud アシスタント 構成 ローカル暗号化を解除 本当に %1$s を削除しますか? diff --git a/app/src/main/res/values-ka/strings.xml b/app/src/main/res/values-ka/strings.xml index 4fc80eafd51c..c0e037ea9506 100644 --- a/app/src/main/res/values-ka/strings.xml +++ b/app/src/main/res/values-ka/strings.xml @@ -141,6 +141,7 @@ Found a bug? Oddments? Help by testing Report an issue on GitHub + Nextcloud-ის ასისტენტი Configure Remove local encryption Do you really want to delete %1$s? diff --git a/app/src/main/res/values-ko/strings.xml b/app/src/main/res/values-ko/strings.xml index 9f38f57cd7bc..7eabe4c6be67 100644 --- a/app/src/main/res/values-ko/strings.xml +++ b/app/src/main/res/values-ko/strings.xml @@ -175,6 +175,7 @@ 버그를 찾으셨나요? 무언가 이상하게 작동하나요? 테스트로 돕기 GitHub에 문제점 보고하기 + Nextcloud 어시스턴트 구성 로컬 암호화를 제거합니다. %1$s을(를) 삭제하시겠습니까? diff --git a/app/src/main/res/values-lo/strings.xml b/app/src/main/res/values-lo/strings.xml index 17c5157c1fb0..edda755b22b4 100644 --- a/app/src/main/res/values-lo/strings.xml +++ b/app/src/main/res/values-lo/strings.xml @@ -184,6 +184,7 @@ ພົບຂໍ້ຜິດພາດບໍ? ການຊ່ວຍເຫຼືອ ໂດຍການທົດສອບ ລາຍງານບັນຫາກ່ຽວກັບ GitHub + ຜູ້ຊ່ວຍ Nextcloud ຕັ້ງຄ່າຄອຍຟິກ Remove local encryption ທ່ານຕ້ອງການລືບແທ້ບໍ %1$s? diff --git a/app/src/main/res/values-nb-rNO/strings.xml b/app/src/main/res/values-nb-rNO/strings.xml index 8014ae5336d2..3be4c128cf51 100644 --- a/app/src/main/res/values-nb-rNO/strings.xml +++ b/app/src/main/res/values-nb-rNO/strings.xml @@ -170,6 +170,7 @@ Funnet en feil? Føles noe rart? Hjelp oss å teste Rapporter en feil på GitHub + Nextcloud-assistent Konfigurer Fjern lokal kryptering Ønsker du virkelig å slette %1$s? diff --git a/app/src/main/res/values-nl/strings.xml b/app/src/main/res/values-nl/strings.xml index df3672b7d4fa..9594f2169040 100644 --- a/app/src/main/res/values-nl/strings.xml +++ b/app/src/main/res/values-nl/strings.xml @@ -173,6 +173,7 @@ Bug gevonden? Rare dingen? Help bij testen Meld een probleem op GitHub + Nextcloud Assistent Configureren Verwijder lokale encryptie Wil je %1$s echt verwijderen? diff --git a/app/src/main/res/values-pl/strings.xml b/app/src/main/res/values-pl/strings.xml index 4389da1343d7..4bcc5b6f66a5 100644 --- a/app/src/main/res/values-pl/strings.xml +++ b/app/src/main/res/values-pl/strings.xml @@ -187,6 +187,7 @@ Znalazłeś błąd? Jest coś, co chciałbyś poprawić? Pomóż nam testować Zgłoś problem na GitHubie + Asystent Nextcloud Konfiguruj Usuń szyfrowanie lokalne Czy na pewno chcesz usunąć %1$s? diff --git a/app/src/main/res/values-pt-rBR/strings.xml b/app/src/main/res/values-pt-rBR/strings.xml index 7604db378a9a..45f8ea81c91b 100644 --- a/app/src/main/res/values-pt-rBR/strings.xml +++ b/app/src/main/res/values-pt-rBR/strings.xml @@ -188,6 +188,7 @@ Encontrou um erro? Algo estranho? Ajude testando Reporte um problema no GitHub + Nextcloud Assistente Configurar Remover criptografia local Quer realmente excluir %1$s? diff --git a/app/src/main/res/values-ru/strings.xml b/app/src/main/res/values-ru/strings.xml index 5202dde89206..ed31df597ecc 100644 --- a/app/src/main/res/values-ru/strings.xml +++ b/app/src/main/res/values-ru/strings.xml @@ -183,6 +183,7 @@ Нашли ошибку? Заметили необычное поведение программы? Помогите нам в тестировании Сообщить о проблеме на GitHub + Помощник Nextcloud Настроить Отключить шифрование на устройстве Действительно удалить «%1$s»? diff --git a/app/src/main/res/values-sk-rSK/strings.xml b/app/src/main/res/values-sk-rSK/strings.xml index 88804de08dc6..645fc118af52 100644 --- a/app/src/main/res/values-sk-rSK/strings.xml +++ b/app/src/main/res/values-sk-rSK/strings.xml @@ -187,6 +187,7 @@ Našli ste chybu? Niečo nefunguje? Pomôžte s testovaním Nahlásiť chybu na Githube + Nextcloud Asistent Nastaviť Odstrániť lokálne šifrovanie Naozaj chcete odstrániť %1$s? diff --git a/app/src/main/res/values-sr/strings.xml b/app/src/main/res/values-sr/strings.xml index b93c136ef684..0b64b9739f48 100644 --- a/app/src/main/res/values-sr/strings.xml +++ b/app/src/main/res/values-sr/strings.xml @@ -183,6 +183,7 @@ Нашли сте грешку? Нешто чудно? Помози тестирајући Пријавите проблем на Гитхабу + Nextcloud Асистент Подеси Уклони локално шифровање Заиста желите да обришете %1$s? diff --git a/app/src/main/res/values-sv/strings.xml b/app/src/main/res/values-sv/strings.xml index c18f97429ab6..b81425904601 100644 --- a/app/src/main/res/values-sv/strings.xml +++ b/app/src/main/res/values-sv/strings.xml @@ -187,6 +187,7 @@ Hittat en bugg? Något som är konstigt? Hjälp till att testa Rapportera ditt problem på GitHub + Nextcloud Assistant Konfigurera Ta bort lokal kryptering Vill du verkligen ta bort %1$s? diff --git a/app/src/main/res/values-sw/strings.xml b/app/src/main/res/values-sw/strings.xml index da57a8353da9..0147fc04dd32 100644 --- a/app/src/main/res/values-sw/strings.xml +++ b/app/src/main/res/values-sw/strings.xml @@ -187,6 +187,7 @@ Je, umepata mdudu? Odds? Msaada kwa kupima Ripoti suala kwenye GitHub + Msaidizi wa Nextcloud Sanidi Ondoa usimbaji fiche wa ndani Je, kweli unataka kufuta %1$s? diff --git a/app/src/main/res/values-tr/strings.xml b/app/src/main/res/values-tr/strings.xml index 32d8900a25a1..cc937d517c31 100644 --- a/app/src/main/res/values-tr/strings.xml +++ b/app/src/main/res/values-tr/strings.xml @@ -188,6 +188,7 @@ Bir hata mı buldunuz? Bir gariplik mi var? Deneyerek bize yardımcı olun GitHub üzerinden sorun bildirin + Nextcloud Yardımcısı Yapılandır Yerel şifrelemeyi kaldır %1$s dosyasını silmek istediğinize emin misiniz? diff --git a/app/src/main/res/values-ug/strings.xml b/app/src/main/res/values-ug/strings.xml index 0814f9a807b9..31c4836238e3 100644 --- a/app/src/main/res/values-ug/strings.xml +++ b/app/src/main/res/values-ug/strings.xml @@ -187,6 +187,7 @@ خاتالىق بايقالدى؟ قالدۇق؟ سىناق ئارقىلىق ياردەم GitHub دىكى بىر مەسىلىنى دوكلات قىلىڭ + Nextcloud ياردەمچىسى سەپلەڭ يەرلىك مەخپىيلەشتۈرۈشنى ئۆچۈرۈڭ راستىنلا%1$s نى ئۆچۈرمەكچىمۇ؟ diff --git a/app/src/main/res/values-uk/strings.xml b/app/src/main/res/values-uk/strings.xml index f3e5bd65caf3..6b1de22684f1 100644 --- a/app/src/main/res/values-uk/strings.xml +++ b/app/src/main/res/values-uk/strings.xml @@ -188,6 +188,7 @@ Помітили ваду чи помилку? Допомогти з тестуванням Повідомити про помилку на GitHub + Асистент Nextcloud Налаштування Вилучити шифрування на пристрої Ви справді бажаєте вилучити %1$s? diff --git a/app/src/main/res/values-vi/strings.xml b/app/src/main/res/values-vi/strings.xml index ad0631fc917b..d45faac11611 100644 --- a/app/src/main/res/values-vi/strings.xml +++ b/app/src/main/res/values-vi/strings.xml @@ -140,6 +140,7 @@ Tìm thấy một lỗi? Giúp bằng cách thử Báo cáo vấn đề trên GitHub + Trợ lý Nextcloud Thiết lập Bạn thực sự muốn xóa %1$s? Bạn thực sự muốn xóa mục lựa chọn này? diff --git a/app/src/main/res/values-zh-rCN/strings.xml b/app/src/main/res/values-zh-rCN/strings.xml index 744a36118c34..b32d6f299561 100644 --- a/app/src/main/res/values-zh-rCN/strings.xml +++ b/app/src/main/res/values-zh-rCN/strings.xml @@ -187,6 +187,7 @@ 发现错误?细节? 通过测试帮助 在Github报告问题 OR 通过Github提交问题(issue) + Nextcloud助手 用户配置 移除近端加密 确定删除%1$s? diff --git a/app/src/main/res/values-zh-rHK/strings.xml b/app/src/main/res/values-zh-rHK/strings.xml index 86f8090effec..f19580c4263c 100644 --- a/app/src/main/res/values-zh-rHK/strings.xml +++ b/app/src/main/res/values-zh-rHK/strings.xml @@ -188,6 +188,7 @@ 發現問題或瑕疵? 協助測試 在 GitHub 上舉報問題 + Nextcloud 小幫手 設定 移除近端加密 你真的想要刪除 %1$s? diff --git a/app/src/main/res/values-zh-rTW/strings.xml b/app/src/main/res/values-zh-rTW/strings.xml index 0d422c50da2d..41e2b24f983a 100644 --- a/app/src/main/res/values-zh-rTW/strings.xml +++ b/app/src/main/res/values-zh-rTW/strings.xml @@ -188,6 +188,7 @@ 發現問題或瑕疵? 協助測試 在 GitHub 上回報問題 + Nextcloud 小幫手 設定 移除本機加密 您真的想要刪除 %1$s 嗎? From 77b24b116a9e0a4b7c33c86a9d54736ccf84a877 Mon Sep 17 00:00:00 2001 From: alperozturk Date: Mon, 12 Jan 2026 12:29:43 +0100 Subject: [PATCH 152/216] fix: auto upload file skip check Signed-off-by: alperozturk --- .../jobs/autoUpload/FileSystemRepository.kt | 21 +++++++++---------- .../extensions/SyncedFolderExtensions.kt | 21 +++++++++++++------ 2 files changed, 25 insertions(+), 17 deletions(-) diff --git a/app/src/main/java/com/nextcloud/client/jobs/autoUpload/FileSystemRepository.kt b/app/src/main/java/com/nextcloud/client/jobs/autoUpload/FileSystemRepository.kt index 9ff924c6aadf..f9c12b36b9a1 100644 --- a/app/src/main/java/com/nextcloud/client/jobs/autoUpload/FileSystemRepository.kt +++ b/app/src/main/java/com/nextcloud/client/jobs/autoUpload/FileSystemRepository.kt @@ -159,20 +159,19 @@ class FileSystemRepository(private val dao: FileSystemDao, private val context: return } + val entity = dao.getFileByPathAndFolder(localPath, syncedFolder.id.toString()) + val fileSentForUpload = (entity != null && entity.fileSentForUpload == 1) + if (fileSentForUpload) { + Log_OC.d(TAG, "File was sent for upload, checking if it changed...") + } + val fileModified = (lastModified ?: file.lastModified()) - val shouldSkipFileBasedOnFolderSettings = syncedFolder.shouldSkipFile(file, fileModified, creationTime) - if (shouldSkipFileBasedOnFolderSettings) { + if (syncedFolder.shouldSkipFile(file, fileModified, creationTime, fileSentForUpload)) { return } - val entity = dao.getFileByPathAndFolder(localPath, syncedFolder.id.toString()) - if (entity != null && entity.fileSentForUpload == 1) { - Log_OC.w( - TAG, - "file already uploaded path: $localPath, " + - "syncedFolder: ${syncedFolder.localPath}, ${syncedFolder.id}" - ) - return + if (fileSentForUpload) { + Log_OC.d(TAG, "File was sent for upload before but has changed, will re-upload: $localPath") } val crc = getFileChecksum(file) @@ -182,7 +181,7 @@ class FileSystemRepository(private val dao: FileSystemDao, private val context: localPath = localPath, fileIsFolder = if (file.isDirectory) 1 else 0, fileFoundRecently = System.currentTimeMillis(), - fileSentForUpload = 0, + fileSentForUpload = 0, // Reset to 0 to queue for upload syncedFolderId = syncedFolder.id.toString(), crc32 = crc?.toString(), fileModified = fileModified diff --git a/app/src/main/java/com/nextcloud/utils/extensions/SyncedFolderExtensions.kt b/app/src/main/java/com/nextcloud/utils/extensions/SyncedFolderExtensions.kt index c7bdadfe6f54..7f8cac806f2f 100644 --- a/app/src/main/java/com/nextcloud/utils/extensions/SyncedFolderExtensions.kt +++ b/app/src/main/java/com/nextcloud/utils/extensions/SyncedFolderExtensions.kt @@ -22,7 +22,12 @@ private const val TAG = "SyncedFolderExtensions" * Determines whether a file should be skipped during auto-upload based on folder settings. */ @Suppress("ReturnCount") -fun SyncedFolder.shouldSkipFile(file: File, lastModified: Long, creationTime: Long?): Boolean { +fun SyncedFolder.shouldSkipFile( + file: File, + lastModified: Long, + creationTime: Long?, + fileSentForUpload: Boolean +): Boolean { Log_OC.d(TAG, "Checking file: ${file.name}, lastModified=$lastModified, lastScan=$lastScanTimestampMs") if (isExcludeHidden && file.isHidden) { @@ -38,15 +43,19 @@ fun SyncedFolder.shouldSkipFile(file: File, lastModified: Long, creationTime: Lo return true } } else { - Log_OC.w(TAG, "file sent for upload - cannot determine creation time: ${file.absolutePath}") + Log_OC.w(TAG, "file will be inserted to db - cannot determine creation time: ${file.absolutePath}") return false } } - // Skip files that haven't changed since last scan (already processed) - // BUT only if this is not the first scan - if (lastScanTimestampMs != -1L && lastModified < lastScanTimestampMs) { - Log_OC.d(TAG, "Skipping unchanged file (last modified < last scan): ${file.absolutePath}") + // Skip files that haven't changed since last scan ONLY if they were sent for upload + // AND only if this is not the first scan + if (fileSentForUpload && lastScanTimestampMs != -1L && lastModified < lastScanTimestampMs) { + Log_OC.d( + TAG, + "Skipping unchanged file that was already sent for upload (last modified < last scan): " + + "${file.absolutePath}" + ) return true } From 9e98b7da70e9aefaa1ce5ce0d672b99e80231927 Mon Sep 17 00:00:00 2001 From: alperozturk Date: Mon, 12 Jan 2026 12:59:21 +0100 Subject: [PATCH 153/216] update tests Signed-off-by: alperozturk --- .../android/utils/AutoUploadHelperTest.kt | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/app/src/test/java/com/owncloud/android/utils/AutoUploadHelperTest.kt b/app/src/test/java/com/owncloud/android/utils/AutoUploadHelperTest.kt index 993ee41a2915..a7aff50a8cc3 100644 --- a/app/src/test/java/com/owncloud/android/utils/AutoUploadHelperTest.kt +++ b/app/src/test/java/com/owncloud/android/utils/AutoUploadHelperTest.kt @@ -132,10 +132,10 @@ class AutoUploadHelperTest { type = MediaFolderType.CUSTOM ) - val shouldSkipOldFile = folder.shouldSkipFile(oldFile, oldFileLastModified, null) + val shouldSkipOldFile = folder.shouldSkipFile(oldFile, oldFileLastModified, null, true) assertTrue(shouldSkipOldFile) - val shouldSkipNewFile = folder.shouldSkipFile(newFile, currentTime, null) + val shouldSkipNewFile = folder.shouldSkipFile(newFile, currentTime, null, false) assertTrue(!shouldSkipNewFile) } @@ -157,10 +157,10 @@ class AutoUploadHelperTest { lastScanTimestampMs = currentTime } - val shouldSkipOldFile = folder.shouldSkipFile(oldFile, oldFileLastModified, null) + val shouldSkipOldFile = folder.shouldSkipFile(oldFile, oldFileLastModified, null, true) assertTrue(shouldSkipOldFile) - val shouldSkipNewFile = folder.shouldSkipFile(newFile, currentTime, null) + val shouldSkipNewFile = folder.shouldSkipFile(newFile, currentTime, null, false) assertTrue(!shouldSkipNewFile) } @@ -305,10 +305,10 @@ class AutoUploadHelperTest { setEnabled(true, currentTime) } - val shouldSkipOldFile = folderSkipOld.shouldSkipFile(oldFile, oldFileLastModified, oldFileCreationTime) + val shouldSkipOldFile = folderSkipOld.shouldSkipFile(oldFile, oldFileLastModified, oldFileCreationTime, true) assertTrue(shouldSkipOldFile) - val shouldSkipNewFile = folderSkipOld.shouldSkipFile(newFile, newFileLastModified, newFileCreationTime) + val shouldSkipNewFile = folderSkipOld.shouldSkipFile(newFile, newFileLastModified, newFileCreationTime, false) assertTrue(!shouldSkipNewFile) val folderUploadAll = createTestFolder( @@ -320,11 +320,11 @@ class AutoUploadHelperTest { } val shouldSkipOldFileIfAlsoUploadExistingFile = - folderUploadAll.shouldSkipFile(oldFile, oldFileLastModified, oldFileCreationTime) + folderUploadAll.shouldSkipFile(oldFile, oldFileLastModified, oldFileCreationTime, true) assertTrue(!shouldSkipOldFileIfAlsoUploadExistingFile) val shouldSkipNewFileIfAlsoUploadExistingFile = - folderUploadAll.shouldSkipFile(newFile, newFileLastModified, newFileCreationTime) + folderUploadAll.shouldSkipFile(newFile, newFileLastModified, newFileCreationTime, false) assertTrue(!shouldSkipNewFileIfAlsoUploadExistingFile) } } From 9ef2b06e68d1cae09da5ac31076e51e5da5703dd Mon Sep 17 00:00:00 2001 From: alperozturk96 Date: Thu, 22 Jan 2026 11:13:08 +0100 Subject: [PATCH 154/216] handle oc upload construct Signed-off-by: alperozturk96 --- .../client/database/entity/UploadEntity.kt | 9 +++++++-- .../jobs/autoUpload/AutoUploadWorker.kt | 20 ++++++++++++------- .../client/jobs/upload/FileUploadHelper.kt | 2 +- .../com/owncloud/android/db/OCUpload.java | 2 ++ 4 files changed, 23 insertions(+), 10 deletions(-) diff --git a/app/src/main/java/com/nextcloud/client/database/entity/UploadEntity.kt b/app/src/main/java/com/nextcloud/client/database/entity/UploadEntity.kt index ec9042cc5819..46b88d674d1c 100644 --- a/app/src/main/java/com/nextcloud/client/database/entity/UploadEntity.kt +++ b/app/src/main/java/com/nextcloud/client/database/entity/UploadEntity.kt @@ -18,6 +18,7 @@ import com.owncloud.android.db.ProviderMeta.ProviderTableMeta import com.owncloud.android.db.UploadResult import com.owncloud.android.files.services.NameCollisionPolicy import com.owncloud.android.lib.resources.status.OCCapability +import java.lang.IllegalArgumentException @Entity(tableName = ProviderTableMeta.UPLOADS_TABLE_NAME) data class UploadEntity( @@ -56,13 +57,17 @@ data class UploadEntity( val folderUnlockToken: String? ) -fun UploadEntity.toOCUpload(capability: OCCapability? = null): OCUpload { +fun UploadEntity.toOCUpload(capability: OCCapability? = null): OCUpload? { val localPath = localPath var remotePath = remotePath if (capability != null && remotePath != null) { remotePath = AutoRename.rename(remotePath, capability) } - val upload = OCUpload(localPath, remotePath, accountName) + val upload = try { + OCUpload(localPath, remotePath, accountName) + } catch (_: IllegalArgumentException) { + null + } ?: return null fileSize?.let { upload.fileSize = it } id?.let { upload.uploadId = it.toLong() } diff --git a/app/src/main/java/com/nextcloud/client/jobs/autoUpload/AutoUploadWorker.kt b/app/src/main/java/com/nextcloud/client/jobs/autoUpload/AutoUploadWorker.kt index 77d9efc41695..27f6c96e2943 100644 --- a/app/src/main/java/com/nextcloud/client/jobs/autoUpload/AutoUploadWorker.kt +++ b/app/src/main/java/com/nextcloud/client/jobs/autoUpload/AutoUploadWorker.kt @@ -383,6 +383,7 @@ class AutoUploadWorker( uploadsStorageManager.removeUpload(upload) } + @Suppress("ReturnCount") private fun createEntityAndUpload( user: User, localPath: String, @@ -404,13 +405,18 @@ class AutoUploadWorker( return null } - val upload = ( - uploadEntity?.toOCUpload(null) ?: OCUpload( - localPath, - remotePath, - user.accountName - ) - ).apply { + var upload = try { + (uploadEntity?.toOCUpload(null) ?: OCUpload(localPath, remotePath, user.accountName)) + } catch (_: IllegalArgumentException) { + null + } + + if (upload == null) { + Log_OC.e(TAG, "cannot construct oc upload") + return null + } + + upload = upload.apply { uploadStatus = UploadsStorageManager.UploadStatus.UPLOAD_IN_PROGRESS nameCollisionPolicy = syncedFolder.nameCollisionPolicy isUseWifiOnly = needsWifi diff --git a/app/src/main/java/com/nextcloud/client/jobs/upload/FileUploadHelper.kt b/app/src/main/java/com/nextcloud/client/jobs/upload/FileUploadHelper.kt index 0604e5db75f2..62b3294b73af 100644 --- a/app/src/main/java/com/nextcloud/client/jobs/upload/FileUploadHelper.kt +++ b/app/src/main/java/com/nextcloud/client/jobs/upload/FileUploadHelper.kt @@ -299,7 +299,7 @@ class FileUploadHelper { dao.getUploadsByAccountNameAndStatus(accountName, status.value, nameCollisionPolicy?.serialize()) } else { dao.getUploadsByStatus(status.value, nameCollisionPolicy?.serialize()) - }.map { it.toOCUpload(null) }.toTypedArray() + }.mapNotNull { it.toOCUpload(null) }.toTypedArray() onCompleted(result) } } diff --git a/app/src/main/java/com/owncloud/android/db/OCUpload.java b/app/src/main/java/com/owncloud/android/db/OCUpload.java index 167e9432e003..8679e3ebd726 100644 --- a/app/src/main/java/com/owncloud/android/db/OCUpload.java +++ b/app/src/main/java/com/owncloud/android/db/OCUpload.java @@ -130,9 +130,11 @@ public class OCUpload implements Parcelable { */ public OCUpload(String localPath, String remotePath, String accountName) { if (localPath == null || !localPath.startsWith(File.separator)) { + Log_OC.e(TAG, "oc upload, local path: " + localPath); throw new IllegalArgumentException("Local path must be an absolute path in the local file system"); } if (remotePath == null || !remotePath.startsWith(OCFile.PATH_SEPARATOR)) { + Log_OC.e(TAG, "oc upload, remote path: " + remotePath); throw new IllegalArgumentException("Remote path must be an absolute path in the local file system"); } if (accountName == null || accountName.length() < 1) { From 3416ef30c1eedcfb0cedc84a10c44e1c41120e4e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alper=20=C3=96zt=C3=BCrk?= <67455295+alperozturk96@users.noreply.github.com> Date: Thu, 22 Jan 2026 15:51:48 +0100 Subject: [PATCH 155/216] Apply suggestion from @ZetaTom MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Tom <70907959+ZetaTom@users.noreply.github.com> Signed-off-by: Alper Öztürk <67455295+alperozturk96@users.noreply.github.com> --- .../client/jobs/autoUpload/AutoUploadWorker.kt | 10 +++------- 1 file changed, 3 insertions(+), 7 deletions(-) diff --git a/app/src/main/java/com/nextcloud/client/jobs/autoUpload/AutoUploadWorker.kt b/app/src/main/java/com/nextcloud/client/jobs/autoUpload/AutoUploadWorker.kt index 27f6c96e2943..54b3fdec74b1 100644 --- a/app/src/main/java/com/nextcloud/client/jobs/autoUpload/AutoUploadWorker.kt +++ b/app/src/main/java/com/nextcloud/client/jobs/autoUpload/AutoUploadWorker.kt @@ -405,18 +405,14 @@ class AutoUploadWorker( return null } - var upload = try { - (uploadEntity?.toOCUpload(null) ?: OCUpload(localPath, remotePath, user.accountName)) + val upload = try { + uploadEntity?.toOCUpload(null) ?: OCUpload(localPath, remotePath, user.accountName) } catch (_: IllegalArgumentException) { - null - } - - if (upload == null) { Log_OC.e(TAG, "cannot construct oc upload") return null } - upload = upload.apply { + upload.apply { uploadStatus = UploadsStorageManager.UploadStatus.UPLOAD_IN_PROGRESS nameCollisionPolicy = syncedFolder.nameCollisionPolicy isUseWifiOnly = needsWifi From cfec946263051ce2aeca573fb3d7725bfc71f870 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alper=20=C3=96zt=C3=BCrk?= <67455295+alperozturk96@users.noreply.github.com> Date: Thu, 22 Jan 2026 15:53:21 +0100 Subject: [PATCH 156/216] Apply suggestion from @ZetaTom MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Tom <70907959+ZetaTom@users.noreply.github.com> Signed-off-by: Alper Öztürk <67455295+alperozturk96@users.noreply.github.com> --- .../java/com/nextcloud/client/database/entity/UploadEntity.kt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/app/src/main/java/com/nextcloud/client/database/entity/UploadEntity.kt b/app/src/main/java/com/nextcloud/client/database/entity/UploadEntity.kt index 46b88d674d1c..55255f5fb01a 100644 --- a/app/src/main/java/com/nextcloud/client/database/entity/UploadEntity.kt +++ b/app/src/main/java/com/nextcloud/client/database/entity/UploadEntity.kt @@ -66,8 +66,8 @@ fun UploadEntity.toOCUpload(capability: OCCapability? = null): OCUpload? { val upload = try { OCUpload(localPath, remotePath, accountName) } catch (_: IllegalArgumentException) { - null - } ?: return null + return null + } fileSize?.let { upload.fileSize = it } id?.let { upload.uploadId = it.toLong() } From 79e694ca7b8c28a530eb2668e89e1535573e3abe Mon Sep 17 00:00:00 2001 From: Nextcloud bot Date: Fri, 23 Jan 2026 03:11:11 +0000 Subject: [PATCH 157/216] fix(l10n): Update translations from Transifex Signed-off-by: Nextcloud bot --- app/src/main/res/values-de/strings.xml | 1 + app/src/main/res/values-ga/strings.xml | 1 + app/src/main/res/values-in/strings.xml | 5 +++++ app/src/main/res/values-it/strings.xml | 12 ++++++------ app/src/main/res/values-uk/strings.xml | 19 ++++++++++--------- app/src/main/res/values-zh-rTW/strings.xml | 1 + 6 files changed, 24 insertions(+), 15 deletions(-) diff --git a/app/src/main/res/values-de/strings.xml b/app/src/main/res/values-de/strings.xml index 04fa10cfa4bc..70499133828c 100644 --- a/app/src/main/res/values-de/strings.xml +++ b/app/src/main/res/values-de/strings.xml @@ -60,6 +60,7 @@ Die Aufgabenliste kann nicht abgerufen werden. Bitte überprüfen Sie Ihre Internetverbindung. Aufgabe löschen Die Aufgabenausgabe ist noch nicht fertig. + Text aus einer anderen App kopiert Assistent Eingabe Ausgabe diff --git a/app/src/main/res/values-ga/strings.xml b/app/src/main/res/values-ga/strings.xml index 29e68f2e220d..461feea1fbbf 100644 --- a/app/src/main/res/values-ga/strings.xml +++ b/app/src/main/res/values-ga/strings.xml @@ -60,6 +60,7 @@ Ní féidir liosta tascanna a fháil, seiceáil do nasc idirlín le do thoil. Scrios Tasc Níl an t-aschur tasc réidh fós. + Téacs cóipeáilte ó aip eile Cúntóir Ionchur Aschur diff --git a/app/src/main/res/values-in/strings.xml b/app/src/main/res/values-in/strings.xml index f399a71ec6b1..9d37e3a2b3b8 100644 --- a/app/src/main/res/values-in/strings.xml +++ b/app/src/main/res/values-in/strings.xml @@ -44,8 +44,11 @@ Menampilkan satu gawit dari dasbor Cari dalam %s Tampak offline + Keluaran yang ditampilkan di sini dihasilkan oleh AI. Pastikan untuk selalu memeriksa ulang. Apakah Anda yakin ingin menghapus tugas ini? Hapus tugas + Coba kirim pesan untuk memulai percakapan. + Halo! Apa yang bisa saya bantu hari ini? Terjadi kesalahan saat membuat tugas Tugas berhasil dibuat Terjadi kesalahan saat menghapus tugas @@ -181,6 +184,7 @@ Otomatis unggah hanya bekerja dengan baik apabila Anda mengeluarkan aplikasi ini Menemukan kesalahan? Bantu dengan menguji. Laporkan di GitHub + Nextcloud Assistant Konfigurasi Hilangkan enkripsi lokal Apakah anda yakin ingin menghapus %1$s? @@ -206,6 +210,7 @@ Otomatis unggah hanya bekerja dengan baik apabila Anda mengeluarkan aplikasi ini Tidak ada berkas ditemukan. Tidak dapat menemukan pencadangan terakhir kamu! Mendeteksi perubahan konten + Belum ada percakapan Tersalin Terjadi kesalahan ketika mencoba menyalin berkas atau folder ini Tidak memungkinkan untuk menyalin folder kedalam turunannya diff --git a/app/src/main/res/values-it/strings.xml b/app/src/main/res/values-it/strings.xml index 3d50a673a13e..a14a8f9f66f6 100644 --- a/app/src/main/res/values-it/strings.xml +++ b/app/src/main/res/values-it/strings.xml @@ -53,11 +53,11 @@ Ciao! Come posso aiutarti oggi? Un errore è intercorso durante la creazione del task Task creato con successo - Un errore è intercorso durante la cancellazione del task - Task cancellato con successo + Un errore è intercorso durante l\'eliminazione dell\'attività + Attività eliminata correttamente L\'elenco delle attività è vuoto. Controllare la configurazione dell\'app di assistenza. Impossibile recuperare la lista dei Task, verifica la tua connessione a internet. - Cancella task + Elimina attività Il risultato del task non è ancora pronto. Assistente Input @@ -214,8 +214,8 @@ Non troviamo il tuo ultimo backup! Rilevamento delle modifiche ai contenuti Impossibile creare conversazione - Cancella conversazione - Impossibile cancellare conversazione + Elimina conversazione + Impossibile eliminare la conversazione Nessuna conversazione trovata Ancora nessuna conversazione Conversazioni @@ -280,7 +280,7 @@ Scaricamento in corso… %1$s scaricato Scaricati - Alcuni file sono stati cancellati dall\'utente durante il download + Lo scaricamento di alcuni file è stato annullato dall\'utente Errore durante lo scaricamento dei file Non ancora scaricato Errore inaspettato durante il download dei file diff --git a/app/src/main/res/values-uk/strings.xml b/app/src/main/res/values-uk/strings.xml index 6b1de22684f1..43a9cfc66ced 100644 --- a/app/src/main/res/values-uk/strings.xml +++ b/app/src/main/res/values-uk/strings.xml @@ -60,6 +60,7 @@ Неможливо отримати список завдань. Перевірте з\'єднання з мережею Вилучити завдання Поки неможливо показати завдання + Текст скопійовано з іншого застосунку Помічник Введення Виведення @@ -142,9 +143,9 @@ Неможливо очистити сповіщення. Очистити статус після Текст скопійовано з %1$s - Відсутній текст для копіювання до буферу обміну + Відсутній текст для копіювання до буфера обміну Посилання скопійовано - Неочікувана помилка під час копіювання до буферу обміну + Неочікувана помилка під час копіювання до буфера обміну Назад Скасувати Скасувати синхронізацію @@ -581,7 +582,7 @@ Журнал подій Сервер у режимі обслуговування Очистити дані - Налаштування, база даних та дані сертифікатів серверу від %1$s буде вилучено без можливості відновлення.\n\nФайли, які було звантажено, буде збережено.\n\nЦей процес триватиме певний час. + Налаштування, база даних та дані сертифікатів сервера від %1$s буде вилучено без можливості відновлення.\n\nФайли, які було звантажено, буде збережено.\n\nЦей процес триватиме певний час. Керувати простором Неможливо транслювати мультимедійний файл Неможливо відкрити мультимедійний файл @@ -862,7 +863,7 @@ Ви повинні ввести пароль Помилка під час надання спільного доступу до файлу чи каталогу. Неможливо надати спільний доступ. Будь ласка, перевірте, чи файл існує. - для надання доступу до файла + для надання доступу до файлу Введіть пароль (необов\'язково) Введіть пароль Поділитися посиланням (%1$s) @@ -926,9 +927,9 @@ Неможливо зберегти сертифікат Не вдалося показати сертифікат. Ви все одно бажаєте довіряти цьому сертифікату? - - Сертифікат серверу втратив чинність - - Недовірений сертифікат серверу - - Сертифікат серверу занадто новий + - Сертифікат сервера втратив чинність + - Недовірений сертифікат сервера + - Дійсні дати сертифіката сервера в майбутньому - URL не відповідає імені хоста у сертифікаті Повідомлення про статус Камера @@ -1030,7 +1031,7 @@ Вилучити каталог із внутрішньої двосторонньої синхронізації Помилка під час закриття спільного доступу до файлу чи каталогу. Неможливо закрити спільний доступ. Будь ласка, перевірте, чи файл існує. - для закриття доступу до файла + для закриття доступу до файлу Не вдалося припинити спільний доступ Доступ через ненадійний домен. Будь ласка, перегляньте документацію для отримання додаткової інформації. Помилка під час оновлення спільного ресурсу. @@ -1125,7 +1126,7 @@ Помилка каталогу Файл на пристрої не знайдено Помилка доступу - Не довірений сертифікат серверу + Недовірений сертифікат сервера Отримую версію сервера... Застосунок зупинено Пропущено diff --git a/app/src/main/res/values-zh-rTW/strings.xml b/app/src/main/res/values-zh-rTW/strings.xml index 41e2b24f983a..68f16e1a8112 100644 --- a/app/src/main/res/values-zh-rTW/strings.xml +++ b/app/src/main/res/values-zh-rTW/strings.xml @@ -60,6 +60,7 @@ 無法擷取工作項目清單,請檢查您的網際網路連線。 刪除工作項目 任務輸出尚未就緒。 + 已從其他應用程式複製文字 助理 輸入 輸出 From 4bb580bf39531d3f94e5a59233a564efa87c041a Mon Sep 17 00:00:00 2001 From: alperozturk96 Date: Thu, 22 Jan 2026 09:23:46 +0100 Subject: [PATCH 158/216] fix(auto-upload): sync conflict handling Signed-off-by: alperozturk96 --- .../client/jobs/autoUpload/AutoUploadWorker.kt | 7 +++++++ .../jobs/utils/UploadErrorNotificationManager.kt | 16 ++++++++++++---- 2 files changed, 19 insertions(+), 4 deletions(-) diff --git a/app/src/main/java/com/nextcloud/client/jobs/autoUpload/AutoUploadWorker.kt b/app/src/main/java/com/nextcloud/client/jobs/autoUpload/AutoUploadWorker.kt index 54b3fdec74b1..db464ccfa11d 100644 --- a/app/src/main/java/com/nextcloud/client/jobs/autoUpload/AutoUploadWorker.kt +++ b/app/src/main/java/com/nextcloud/client/jobs/autoUpload/AutoUploadWorker.kt @@ -37,6 +37,7 @@ import com.owncloud.android.db.OCUpload import com.owncloud.android.db.UploadResult import com.owncloud.android.lib.common.OwnCloudAccount import com.owncloud.android.lib.common.OwnCloudClientManagerFactory +import com.owncloud.android.lib.common.operations.RemoteOperationResult import com.owncloud.android.lib.common.utils.Log_OC import com.owncloud.android.operations.UploadFileOperation import com.owncloud.android.ui.activity.SettingsActivity @@ -346,6 +347,12 @@ class AutoUploadWorker( TAG, "❌ upload failed $localPath (${upload.accountName}): ${result.logMessage}" ) + + // Mark CONFLICT files as handled to prevent retries + if (result.code == RemoteOperationResult.ResultCode.SYNC_CONFLICT) { + repository.markFileAsHandled(localPath, syncedFolder) + Log_OC.w(TAG, "Marked CONFLICT file as handled: $localPath") + } } } catch (e: Exception) { uploadsStorageManager.updateStatus( diff --git a/app/src/main/java/com/nextcloud/client/jobs/utils/UploadErrorNotificationManager.kt b/app/src/main/java/com/nextcloud/client/jobs/utils/UploadErrorNotificationManager.kt index a9aa21d61f73..236919c81b3c 100644 --- a/app/src/main/java/com/nextcloud/client/jobs/utils/UploadErrorNotificationManager.kt +++ b/app/src/main/java/com/nextcloud/client/jobs/utils/UploadErrorNotificationManager.kt @@ -80,7 +80,10 @@ object UploadErrorNotificationManager { result: RemoteOperationResult, notifyOnSameFileExists: suspend () -> Unit ): Notification? { - if (!shouldShowConflictDialog(isSameFileOnRemote, operation, result, notifyOnSameFileExists)) return null + if (!shouldShowConflictDialog(isSameFileOnRemote, operation, result, notifyOnSameFileExists)) { + Log_OC.d(TAG, "no need to show conflict resolve notification") + return null + } val textId = result.code.toFailedResultTitleId() val errorMessage = ErrorMessageAdapter.getErrorCauseMessage(result, operation, context.resources) @@ -176,9 +179,14 @@ object UploadErrorNotificationManager { return false } - if (result.code == ResultCode.SYNC_CONFLICT && isSameFileOnRemote) { - Log_OC.w(TAG, "same file exists on remote") - notifyOnSameFileExists() + if (result.code == ResultCode.SYNC_CONFLICT) { + if (isSameFileOnRemote) { + Log_OC.w(TAG, "same file exists on remote") + notifyOnSameFileExists() + } else { + Log_OC.w(TAG, "SYNC_CONFLICT but file not same on remote - no notification needed") + } + return false } From 2cfe1f9154b930809d9f320c323b4402d0fac3b2 Mon Sep 17 00:00:00 2001 From: alperozturk96 Date: Thu, 22 Jan 2026 09:33:46 +0100 Subject: [PATCH 159/216] fix(auto-upload): sync conflict handling Signed-off-by: alperozturk96 --- .../client/jobs/utils/UploadErrorNotificationManager.kt | 2 -- 1 file changed, 2 deletions(-) diff --git a/app/src/main/java/com/nextcloud/client/jobs/utils/UploadErrorNotificationManager.kt b/app/src/main/java/com/nextcloud/client/jobs/utils/UploadErrorNotificationManager.kt index 236919c81b3c..c3a5423f239b 100644 --- a/app/src/main/java/com/nextcloud/client/jobs/utils/UploadErrorNotificationManager.kt +++ b/app/src/main/java/com/nextcloud/client/jobs/utils/UploadErrorNotificationManager.kt @@ -183,8 +183,6 @@ object UploadErrorNotificationManager { if (isSameFileOnRemote) { Log_OC.w(TAG, "same file exists on remote") notifyOnSameFileExists() - } else { - Log_OC.w(TAG, "SYNC_CONFLICT but file not same on remote - no notification needed") } return false From 7a8aaae2486c2c9a77df057931ca310c78a94f03 Mon Sep 17 00:00:00 2001 From: alperozturk96 Date: Thu, 22 Jan 2026 10:07:33 +0100 Subject: [PATCH 160/216] fix(auto-upload): simplify error notification logic Signed-off-by: alperozturk96 --- .../client/jobs/upload/FileUploadWorker.kt | 2 +- .../utils/UploadErrorNotificationManager.kt | 129 +++++++++--------- 2 files changed, 62 insertions(+), 69 deletions(-) diff --git a/app/src/main/java/com/nextcloud/client/jobs/upload/FileUploadWorker.kt b/app/src/main/java/com/nextcloud/client/jobs/upload/FileUploadWorker.kt index 275dce4b470c..d1906e7c8c79 100644 --- a/app/src/main/java/com/nextcloud/client/jobs/upload/FileUploadWorker.kt +++ b/app/src/main/java/com/nextcloud/client/jobs/upload/FileUploadWorker.kt @@ -380,7 +380,7 @@ class FileUploadWorker( notificationManager, operation, result, - showSameFileAlreadyExistsNotification = { + onSameFileConflict = { withContext(Dispatchers.Main) { val showSameFileAlreadyExistsNotification = inputData.getBoolean(SHOW_SAME_FILE_ALREADY_EXISTS_NOTIFICATION, false) diff --git a/app/src/main/java/com/nextcloud/client/jobs/utils/UploadErrorNotificationManager.kt b/app/src/main/java/com/nextcloud/client/jobs/utils/UploadErrorNotificationManager.kt index c3a5423f239b..d9e5abb77963 100644 --- a/app/src/main/java/com/nextcloud/client/jobs/utils/UploadErrorNotificationManager.kt +++ b/app/src/main/java/com/nextcloud/client/jobs/utils/UploadErrorNotificationManager.kt @@ -31,35 +31,67 @@ import java.io.File object UploadErrorNotificationManager { private const val TAG = "UploadErrorNotificationManager" + /** + * Processes the result of an upload operation and manages error notifications. + * * It filters out successful or silent results and handles [ResultCode.SYNC_CONFLICT] + * by checking if the remote file is identical. If it's a "real" conflict or error, + * it displays a notification with relevant actions (e.g., Resolve Conflict, Pause, Cancel). + * + * @param onSameFileConflict Triggered only if a 409 Conflict occurs but files are identical. + */ + @Suppress("ReturnCount") suspend fun handleResult( context: Context, notificationManager: WorkerNotificationManager, operation: UploadFileOperation, result: RemoteOperationResult, - showSameFileAlreadyExistsNotification: suspend () -> Unit = {} + onSameFileConflict: suspend () -> Unit = {} ) { Log_OC.d(TAG, "handle upload result with result code: " + result.code) - val notification = withContext(Dispatchers.IO) { - val isSameFileOnRemote = FileUploadHelper.instance().isSameFileOnRemote( - operation.user, - File(operation.storagePath), - operation.remotePath, - context - ) + if (result.isSuccess || result.isCancelled || operation.isMissingPermissionThrown) { + Log_OC.d(TAG, "operation is successful, cancelled or lack of storage permission, notification skipped") + return + } - getNotification( - isSameFileOnRemote, - context, - notificationManager.notificationBuilder, - operation, - result, - notifyOnSameFileExists = { - showSameFileAlreadyExistsNotification() - operation.handleLocalBehaviour() - } - ) - } ?: return + val silentCodes = setOf( + ResultCode.DELAYED_FOR_WIFI, + ResultCode.DELAYED_FOR_CHARGING, + ResultCode.DELAYED_IN_POWER_SAVE_MODE, + ResultCode.LOCAL_FILE_NOT_FOUND, + ResultCode.LOCK_FAILED + ) + + if (result.code in silentCodes) { + Log_OC.d(TAG, "silent error code, notification skipped") + return + } + + // Do not show an error notification when uploading the same file again (manual uploads only). + if (result.code == ResultCode.SYNC_CONFLICT) { + val isSameFile = withContext(Dispatchers.IO) { + FileUploadHelper.instance().isSameFileOnRemote( + operation.user, + File(operation.storagePath), + operation.remotePath, + context + ) + } + + if (isSameFile) { + Log_OC.w(TAG, "exact same file already exists on remote, error notification skipped") + onSameFileConflict() + return + } + } + + // now we can show error notification + val notification = getNotification( + context, + notificationManager.notificationBuilder, + operation, + result + ) Log_OC.d(TAG, "🔔" + "notification created") @@ -72,19 +104,12 @@ object UploadErrorNotificationManager { } } - private suspend fun getNotification( - isSameFileOnRemote: Boolean, + private fun getNotification( context: Context, builder: NotificationCompat.Builder, operation: UploadFileOperation, - result: RemoteOperationResult, - notifyOnSameFileExists: suspend () -> Unit - ): Notification? { - if (!shouldShowConflictDialog(isSameFileOnRemote, operation, result, notifyOnSameFileExists)) { - Log_OC.d(TAG, "no need to show conflict resolve notification") - return null - } - + result: RemoteOperationResult + ): Notification { val textId = result.code.toFailedResultTitleId() val errorMessage = ErrorMessageAdapter.getErrorCauseMessage(result, operation, context.resources) @@ -97,7 +122,11 @@ object UploadErrorNotificationManager { setProgress(0, 0, false) clearActions() - result.code.takeIf { it == ResultCode.SYNC_CONFLICT }?.let { + // actions for all error types + addAction(UploadBroadcastAction.PauseAndCancel(operation).pauseAction(context)) + addAction(UploadBroadcastAction.PauseAndCancel(operation).cancelAction(context)) + + if (result.code == ResultCode.SYNC_CONFLICT) { addAction( R.drawable.ic_cloud_upload, context.getString(R.string.upload_list_resolve_conflict), @@ -105,11 +134,7 @@ object UploadErrorNotificationManager { ) } - addAction(UploadBroadcastAction.PauseAndCancel(operation).pauseAction(context)) - - addAction(UploadBroadcastAction.PauseAndCancel(operation).cancelAction(context)) - - result.code.takeIf { it == ResultCode.UNAUTHORIZED }?.let { + if (result.code == ResultCode.UNAUTHORIZED) { setContentIntent(credentialPendingIntent(context, operation)) } }.build() @@ -162,36 +187,4 @@ object UploadErrorNotificationManager { PendingIntent.FLAG_IMMUTABLE ) } - - @Suppress("ReturnCount", "ComplexCondition") - private suspend fun shouldShowConflictDialog( - isSameFileOnRemote: Boolean, - operation: UploadFileOperation, - result: RemoteOperationResult, - notifyOnSameFileExists: suspend () -> Unit - ): Boolean { - if (result.isSuccess || - result.isCancelled || - result.code == ResultCode.USER_CANCELLED || - operation.isMissingPermissionThrown - ) { - Log_OC.w(TAG, "operation is successful, cancelled or lack of storage permission") - return false - } - - if (result.code == ResultCode.SYNC_CONFLICT) { - if (isSameFileOnRemote) { - Log_OC.w(TAG, "same file exists on remote") - notifyOnSameFileExists() - } - - return false - } - - val delayedCodes = - setOf(ResultCode.DELAYED_FOR_WIFI, ResultCode.DELAYED_FOR_CHARGING, ResultCode.DELAYED_IN_POWER_SAVE_MODE) - val invalidCodes = setOf(ResultCode.LOCAL_FILE_NOT_FOUND, ResultCode.LOCK_FAILED) - - return result.code !in delayedCodes && result.code !in invalidCodes - } } From 5393094b30a0fab61038e2adf30a2debce349a4b Mon Sep 17 00:00:00 2001 From: alperozturk96 Date: Thu, 22 Jan 2026 10:10:02 +0100 Subject: [PATCH 161/216] fix(auto-upload): simplify error notification logic Signed-off-by: alperozturk96 --- .../client/jobs/utils/UploadErrorNotificationManager.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/src/main/java/com/nextcloud/client/jobs/utils/UploadErrorNotificationManager.kt b/app/src/main/java/com/nextcloud/client/jobs/utils/UploadErrorNotificationManager.kt index d9e5abb77963..5777704af50e 100644 --- a/app/src/main/java/com/nextcloud/client/jobs/utils/UploadErrorNotificationManager.kt +++ b/app/src/main/java/com/nextcloud/client/jobs/utils/UploadErrorNotificationManager.kt @@ -37,7 +37,7 @@ object UploadErrorNotificationManager { * by checking if the remote file is identical. If it's a "real" conflict or error, * it displays a notification with relevant actions (e.g., Resolve Conflict, Pause, Cancel). * - * @param onSameFileConflict Triggered only if a 409 Conflict occurs but files are identical. + * @param onSameFileConflict Triggered only if result code is SYNC_CONFLICT and files are identical. */ @Suppress("ReturnCount") suspend fun handleResult( From 65c14db22e9c71766d2497a1b09aa14d7ac43578 Mon Sep 17 00:00:00 2001 From: alperozturk96 Date: Thu, 22 Jan 2026 10:11:40 +0100 Subject: [PATCH 162/216] remove public handleLocalBehaviour Signed-off-by: alperozturk96 --- .../operations/UploadFileOperation.java | 21 ------------------- 1 file changed, 21 deletions(-) diff --git a/app/src/main/java/com/owncloud/android/operations/UploadFileOperation.java b/app/src/main/java/com/owncloud/android/operations/UploadFileOperation.java index f13c73704962..f29faf6d308a 100644 --- a/app/src/main/java/com/owncloud/android/operations/UploadFileOperation.java +++ b/app/src/main/java/com/owncloud/android/operations/UploadFileOperation.java @@ -1262,27 +1262,6 @@ private RemoteOperationResult checkNameCollision(OCFile parentFile, return null; } - public void handleLocalBehaviour() { - if (user == null || mFile == null || mContext == null) { - Log_OC.d(TAG, "handleLocalBehaviour: user, file, or context is null."); - return; - } - - final var client = getClient(); - if (client == null) { - Log_OC.d(TAG, "handleLocalBehaviour: client is null"); - return; - } - - String expectedPath = FileStorageUtils.getDefaultSavePathFor(user.getAccountName(), mFile); - File expectedFile = new File(expectedPath); - File originalFile = new File(mOriginalStoragePath); - String temporalPath = FileStorageUtils.getInternalTemporalPath(user.getAccountName(), mContext) + mFile.getRemotePath(); - File temporalFile = new File(temporalPath); - - handleLocalBehaviour(temporalFile, expectedFile, originalFile, client); - } - private void deleteNonExistingFile(File file) { if (file.exists()) { return; From f0bbdf896b08bd0b1f9fe2886f882609e57936e2 Mon Sep 17 00:00:00 2001 From: alperozturk96 Date: Thu, 22 Jan 2026 10:14:40 +0100 Subject: [PATCH 163/216] remove public handleLocalBehaviour Signed-off-by: alperozturk96 --- .../client/jobs/utils/UploadErrorNotificationManager.kt | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/app/src/main/java/com/nextcloud/client/jobs/utils/UploadErrorNotificationManager.kt b/app/src/main/java/com/nextcloud/client/jobs/utils/UploadErrorNotificationManager.kt index 5777704af50e..0371a8d53b45 100644 --- a/app/src/main/java/com/nextcloud/client/jobs/utils/UploadErrorNotificationManager.kt +++ b/app/src/main/java/com/nextcloud/client/jobs/utils/UploadErrorNotificationManager.kt @@ -67,7 +67,7 @@ object UploadErrorNotificationManager { return } - // Do not show an error notification when uploading the same file again (manual uploads only). + // do not show an error notification when uploading the same file again if (result.code == ResultCode.SYNC_CONFLICT) { val isSameFile = withContext(Dispatchers.IO) { FileUploadHelper.instance().isSameFileOnRemote( @@ -80,6 +80,8 @@ object UploadErrorNotificationManager { if (isSameFile) { Log_OC.w(TAG, "exact same file already exists on remote, error notification skipped") + + // only show notification for manual uploads onSameFileConflict() return } From 988d7952624c26d079ddf1d918a6fa881e761b3b Mon Sep 17 00:00:00 2001 From: alperozturk96 Date: Thu, 22 Jan 2026 10:15:34 +0100 Subject: [PATCH 164/216] remove public handleLocalBehaviour Signed-off-by: alperozturk96 --- .../client/jobs/utils/UploadErrorNotificationManager.kt | 2 ++ 1 file changed, 2 insertions(+) diff --git a/app/src/main/java/com/nextcloud/client/jobs/utils/UploadErrorNotificationManager.kt b/app/src/main/java/com/nextcloud/client/jobs/utils/UploadErrorNotificationManager.kt index 0371a8d53b45..41edefe7d6fb 100644 --- a/app/src/main/java/com/nextcloud/client/jobs/utils/UploadErrorNotificationManager.kt +++ b/app/src/main/java/com/nextcloud/client/jobs/utils/UploadErrorNotificationManager.kt @@ -98,6 +98,8 @@ object UploadErrorNotificationManager { Log_OC.d(TAG, "🔔" + "notification created") withContext(Dispatchers.Main) { + + // if error code is file specific show new notification for each file if (result.code.isFileSpecificError()) { notificationManager.showNotification(operation.ocUploadId.toInt(), notification) } else { From e7e3aec7adccea9a9ebe477831747b4ad718cec9 Mon Sep 17 00:00:00 2001 From: alperozturk96 Date: Thu, 22 Jan 2026 15:55:27 +0100 Subject: [PATCH 165/216] fix codacy Signed-off-by: alperozturk96 --- .../client/jobs/utils/UploadErrorNotificationManager.kt | 1 - 1 file changed, 1 deletion(-) diff --git a/app/src/main/java/com/nextcloud/client/jobs/utils/UploadErrorNotificationManager.kt b/app/src/main/java/com/nextcloud/client/jobs/utils/UploadErrorNotificationManager.kt index 41edefe7d6fb..5240f112a7f8 100644 --- a/app/src/main/java/com/nextcloud/client/jobs/utils/UploadErrorNotificationManager.kt +++ b/app/src/main/java/com/nextcloud/client/jobs/utils/UploadErrorNotificationManager.kt @@ -98,7 +98,6 @@ object UploadErrorNotificationManager { Log_OC.d(TAG, "🔔" + "notification created") withContext(Dispatchers.Main) { - // if error code is file specific show new notification for each file if (result.code.isFileSpecificError()) { notificationManager.showNotification(operation.ocUploadId.toInt(), notification) From 771aab29f36855031916b9e68dd21a208c02c2b6 Mon Sep 17 00:00:00 2001 From: alperozturk96 Date: Fri, 23 Jan 2026 08:39:55 +0100 Subject: [PATCH 166/216] chore: bump version to 3.35.1 Signed-off-by: alperozturk96 --- app/build.gradle.kts | 2 +- fastlane/metadata/android/en-US/changelogs/30350091.txt | 7 +++++++ .../metadata/android/en-US/changelogs/30350091.txt.license | 2 ++ 3 files changed, 10 insertions(+), 1 deletion(-) create mode 100644 fastlane/metadata/android/en-US/changelogs/30350091.txt create mode 100644 fastlane/metadata/android/en-US/changelogs/30350091.txt.license diff --git a/app/build.gradle.kts b/app/build.gradle.kts index 7027184b9198..5128471efea7 100644 --- a/app/build.gradle.kts +++ b/app/build.gradle.kts @@ -65,7 +65,7 @@ configurations.configureEach { val versionMajor = 3 val versionMinor = 35 val versionPatch = 0 -val versionBuild = 90 // 0-50=Alpha / 51-98=RC / 90-99=stable +val versionBuild = 91 // 0-50=Alpha / 51-98=RC / 90-99=stable val ndkEnv = buildMap { file("${project.rootDir}/ndk.env").readLines().forEach { diff --git a/fastlane/metadata/android/en-US/changelogs/30350091.txt b/fastlane/metadata/android/en-US/changelogs/30350091.txt new file mode 100644 index 000000000000..285411d77720 --- /dev/null +++ b/fastlane/metadata/android/en-US/changelogs/30350091.txt @@ -0,0 +1,7 @@ +## 3.35.1 (January 23, 2026) + +- Auto-upload fixes + +Minimum: NC 20 Server, Android 9 Pie + +For a full list, please see https://github.com/nextcloud/android/milestone/119 \ No newline at end of file diff --git a/fastlane/metadata/android/en-US/changelogs/30350091.txt.license b/fastlane/metadata/android/en-US/changelogs/30350091.txt.license new file mode 100644 index 000000000000..a67e1fec2721 --- /dev/null +++ b/fastlane/metadata/android/en-US/changelogs/30350091.txt.license @@ -0,0 +1,2 @@ +# SPDX-FileCopyrightText: 2026 Nextcloud GmbH and Nextcloud contributors +# SPDX-License-Identifier: AGPL-3.0-or-later \ No newline at end of file From e8d7fb65b0d26708b70b22c9ddf41d071cb7c71d Mon Sep 17 00:00:00 2001 From: alperozturk96 Date: Fri, 23 Jan 2026 08:45:15 +0100 Subject: [PATCH 167/216] chore: bump version to 3.35.1 Signed-off-by: alperozturk96 --- app/build.gradle.kts | 4 ++-- .../android/en-US/changelogs/{30350091.txt => 30350190.txt} | 0 .../changelogs/{30350091.txt.license => 30350190.txt.license} | 0 3 files changed, 2 insertions(+), 2 deletions(-) rename fastlane/metadata/android/en-US/changelogs/{30350091.txt => 30350190.txt} (100%) rename fastlane/metadata/android/en-US/changelogs/{30350091.txt.license => 30350190.txt.license} (100%) diff --git a/app/build.gradle.kts b/app/build.gradle.kts index 5128471efea7..f651b611094d 100644 --- a/app/build.gradle.kts +++ b/app/build.gradle.kts @@ -64,8 +64,8 @@ configurations.configureEach { // semantic versioning for version code val versionMajor = 3 val versionMinor = 35 -val versionPatch = 0 -val versionBuild = 91 // 0-50=Alpha / 51-98=RC / 90-99=stable +val versionPatch = 1 +val versionBuild = 90 // 0-50=Alpha / 51-98=RC / 90-99=stable val ndkEnv = buildMap { file("${project.rootDir}/ndk.env").readLines().forEach { diff --git a/fastlane/metadata/android/en-US/changelogs/30350091.txt b/fastlane/metadata/android/en-US/changelogs/30350190.txt similarity index 100% rename from fastlane/metadata/android/en-US/changelogs/30350091.txt rename to fastlane/metadata/android/en-US/changelogs/30350190.txt diff --git a/fastlane/metadata/android/en-US/changelogs/30350091.txt.license b/fastlane/metadata/android/en-US/changelogs/30350190.txt.license similarity index 100% rename from fastlane/metadata/android/en-US/changelogs/30350091.txt.license rename to fastlane/metadata/android/en-US/changelogs/30350190.txt.license From b352f7d2302df52305ed5ad67c1fb3e34bf5d3b1 Mon Sep 17 00:00:00 2001 From: alperozturk96 Date: Mon, 19 Jan 2026 12:08:45 +0100 Subject: [PATCH 168/216] fix(local-file-list-adapter): navigation Signed-off-by: alperozturk96 --- .../android/ui/adapter/LocalFileListAdapter.java | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/app/src/main/java/com/owncloud/android/ui/adapter/LocalFileListAdapter.java b/app/src/main/java/com/owncloud/android/ui/adapter/LocalFileListAdapter.java index ddcf18e3f3da..676f911e6f49 100644 --- a/app/src/main/java/com/owncloud/android/ui/adapter/LocalFileListAdapter.java +++ b/app/src/main/java/com/owncloud/android/ui/adapter/LocalFileListAdapter.java @@ -371,8 +371,6 @@ public RecyclerView.ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int public void swapDirectory(final File directory) { localFileListFragmentInterface.setLoading(true); currentOffset = 0; - mFiles.clear(); - mFilesAll.clear(); singleThreadExecutor.execute(() -> { // Load first page of folders @@ -398,8 +396,10 @@ public void swapDirectory(final File directory) { @SuppressLint("NotifyDataSetChanged") private void updateUIForFirstPage(List firstPage) { new Handler(Looper.getMainLooper()).post(() -> { - mFiles = new ArrayList<>(firstPage); - mFilesAll = new ArrayList<>(firstPage); + mFiles.clear(); + mFilesAll.clear(); + mFiles.addAll(firstPage); + mFilesAll.addAll(firstPage); notifyDataSetChanged(); localFileListFragmentInterface.setLoading(false); }); @@ -432,15 +432,16 @@ private void loadRemainingEntries(File directory, boolean fetchFolders) { private void notifyItemRange(List updatedList) { new Handler(Looper.getMainLooper()).post(() -> { - int from = mFiles.size(); - int to = updatedList.size(); + int headerOffset = shouldShowHeader() ? 1 : 0; + int startPositionInAdapter = mFiles.size() + headerOffset; + int itemCount = updatedList.size(); mFiles.addAll(updatedList); mFilesAll.addAll(updatedList); Log_OC.d(TAG, "notifyItemRange, item size: " + mFilesAll.size()); - notifyItemRangeInserted(from, to); + notifyItemRangeInserted(startPositionInAdapter, itemCount); }); } From 8bfeb2264e1660b181e3ec4280b3f1a1958f579a Mon Sep 17 00:00:00 2001 From: Nextcloud bot Date: Sat, 24 Jan 2026 03:09:07 +0000 Subject: [PATCH 169/216] fix(l10n): Update translations from Transifex Signed-off-by: Nextcloud bot --- app/src/main/res/values-it/strings.xml | 16 ++++++++-------- app/src/main/res/values-nl/strings.xml | 4 ++++ app/src/main/res/values-pt-rBR/strings.xml | 1 + app/src/main/res/values-sk-rSK/strings.xml | 9 ++++++++- app/src/main/res/values-zh-rCN/strings.xml | 10 +++++++++- 5 files changed, 30 insertions(+), 10 deletions(-) diff --git a/app/src/main/res/values-it/strings.xml b/app/src/main/res/values-it/strings.xml index a14a8f9f66f6..cfd6bedb68b4 100644 --- a/app/src/main/res/values-it/strings.xml +++ b/app/src/main/res/values-it/strings.xml @@ -51,8 +51,8 @@ Elimina attività Prova a inviare un messaggio per avviare una conversazione. Ciao! Come posso aiutarti oggi? - Un errore è intercorso durante la creazione del task - Task creato con successo + Si è verificato un errore durante la creazione dell\'attività + Attività creato correttamente Un errore è intercorso durante l\'eliminazione dell\'attività Attività eliminata correttamente L\'elenco delle attività è vuoto. Controllare la configurazione dell\'app di assistenza. @@ -96,9 +96,9 @@ Annulla l\'accesso Inserisci un indirizzo server valido. Impossibile recuperare i dati di accesso. Riprova. - C\'è stato un problema nella richiesta di login. Per favore, riprova più tardi - Non è disponibile alcun browser per aprire questo link. - Completa il procedimento di login nel tuo browser + Si è verificato un problema nella richiesta di accesso. Riprova più tardi. + Non è disponibile alcun browser per aprire questo collegamento. + Completa la procedura di accesso nel tuo browser Il caricamento automatico è sospeso perché è attiva la funzione Risparmio batteria. lasciato nella cartella originale, poiché è in sola lettura Batteria scarica, il caricamento potrebbe richiedere più tempo @@ -342,14 +342,14 @@ Errore nella scelta della data Errore di commento del file %1$s si è chiuso inaspettatamente - Errore nel creare il file da template + Errore durante la creazione del file dal modello Errore nel mostrare le azioni del file Errore nello sbloccare il file Segnala Segnalare problemi al sistema di tracciamento? (richiede un account GitHub) Errore durante il recupero del file Errore durante il recupero dei modelli - Errore durante la visualizzazione della finestra di dialogo per l\'impostazione della crittografia! + Errore durante la visualizzazione della finestra di dialogo per l\'impostazione della cifratura! Errore di avvio della fotocamera Errore all\'avvio della scansione del documento Impossibile caricare i media catturati @@ -448,7 +448,7 @@ File non trovato Il file non può essere sincronizzato. Viene mostrata l\'ultima versione disponibile. Rinomina - Caricamento fallito. Nessuna connessione ad internet + Caricamento non riuscito. Nessuna connessione a Internet Errore durante il ripristino della versione del file! Dettagli Scarica diff --git a/app/src/main/res/values-nl/strings.xml b/app/src/main/res/values-nl/strings.xml index 9594f2169040..c5a8279a6bd2 100644 --- a/app/src/main/res/values-nl/strings.xml +++ b/app/src/main/res/values-nl/strings.xml @@ -340,6 +340,7 @@ Probleem melden? (vereist een GitHub account) Fout bij ophalen van bestand Fout bij ophalen sjablonen + Fout bij instellen statusbericht! Fout bij het tonen van encryptie instellingsdialoog! Fout bij starten camera Fout bij het starten van documentscan @@ -786,13 +787,16 @@ Selecteer een sjabloon Kies sjabloon Versturen + Stuur kopie naar Share versturen Verstuur-knop pictogram Kon inhoud niet laden Dit apparaat is mogelijk niet aangesloten op het internet Stel in als Kan geen downloadlimiet instellen. Controleer svp de capaciteiten + Stel bericht in Aantekening instellen + Online status Gebruik afbeelding als Tijden het instellen van end-to-end versleuteling ontvang je een mnemonic van 12 woorden, die je nodig hebt om bestanden op je apparaat te openen. Dit wordt alleen opgeslagen op dit apparaat en kan in dit scherm opnieuw getoond worden. Noteer het a.u.b. op een veilige plek! Delen diff --git a/app/src/main/res/values-pt-rBR/strings.xml b/app/src/main/res/values-pt-rBR/strings.xml index 45f8ea81c91b..c565875520ef 100644 --- a/app/src/main/res/values-pt-rBR/strings.xml +++ b/app/src/main/res/values-pt-rBR/strings.xml @@ -60,6 +60,7 @@ Não foi possível buscar a lista de tarefas. Verifique sua conexão com a Internet. Excluir Tarefa O resultado da tarefa ainda não está pronto. + Texto copiado de outro aplicativo Assistente Entrada Saída diff --git a/app/src/main/res/values-sk-rSK/strings.xml b/app/src/main/res/values-sk-rSK/strings.xml index 645fc118af52..bf164f24a633 100644 --- a/app/src/main/res/values-sk-rSK/strings.xml +++ b/app/src/main/res/values-sk-rSK/strings.xml @@ -1,6 +1,6 @@ - %1$s aplikácie pre Android + %1$s aplikácia pre Android O verzia %1$s verzia %1$s, zostavenie #%2$s @@ -13,6 +13,7 @@ Odoslať/Zdieľať Zobrazenie mriežky Zobrazenie zoznamu + Akcia spustená Obnoviť kontakty a kalendár Nový priečinok Presunúť alebo kopírovať @@ -59,6 +60,7 @@ Nie je možné načítať zoznam úloh, skontrolujte svoje internetové pripojenie. Vymazať Úlohu Výstup úlohy ešte nie je dostupný. + Text skopírovaný z inej aplikácie Asistent Vstup Výstup @@ -397,6 +399,7 @@ Nepodarilo sa vytvoriť dialóg o konflikte Nepodarilo sa odovzdať súbor správcovi preberania Nepodarilo sa vytlačiť súbor + Spustenie akcie zlyhalo! Nepodarilo sa spustiť editor Nepodarilo sa aktualizovať UI Pridať do obľúbených @@ -756,6 +759,7 @@ Interval Spravovať interné adresáre pre obojsmernú synchronizáciu Povoliť obojstrannú synchronizáciu + Obojsmerná synchronizácia Tmavý Svetlý Nasledovať systém @@ -961,6 +965,9 @@ Navrhnúť Synchronizovať Aj napriek tomu synchronizovať + Vyriešiť konflikty + Zistené konflikty pri nahrávaní. Otvorte nahrávania a vyriešte ich. + Konflikty pri nahrávaní súboru Objavené konflikty Adresár %1$s už neexistuje Synchronizovať duplikáty diff --git a/app/src/main/res/values-zh-rCN/strings.xml b/app/src/main/res/values-zh-rCN/strings.xml index b32d6f299561..c7be593a42b1 100644 --- a/app/src/main/res/values-zh-rCN/strings.xml +++ b/app/src/main/res/values-zh-rCN/strings.xml @@ -13,6 +13,7 @@ 发送/分享 网格视图 列表视图 + 操作已触发 恢复联系人和日历 新建文件夹 移动或复制 @@ -59,6 +60,7 @@ 无法获取任务列表,请检查你的互联网连接。 删除任务 任务输出尚未就绪。 + 已从其他应用中复制文本 助手 输入 输出结果 @@ -187,7 +189,7 @@ 发现错误?细节? 通过测试帮助 在Github报告问题 OR 通过Github提交问题(issue) - Nextcloud助手 + Nextcloud 助手 用户配置 移除近端加密 确定删除%1$s? @@ -397,6 +399,7 @@ 无法创建冲突对话框 无法将文件传递给下载管理器 打印文件已失败 + 无法启动操作! 启动编辑器失败 更新用户界面失败 添加到收藏夹 @@ -756,6 +759,7 @@ 间隔 管理内部文件夹以实现双向同步 启用双向同步 + 双向同步 深色 浅色 跟随系统 @@ -826,6 +830,7 @@ 请选择一个模板 选择模板 发送 + 发送副本至 发送共享 发送按钮的图标 无法加载内容 @@ -963,6 +968,9 @@ 建议 同步 仍要同步 + 解决冲突 + 检测到上传冲突。请打开上传进行解决。 + 文件上传冲突 发现冲突 文件夹%1$s不再存在 同步重复 From 8a73f7723ecbf70d5b022c4f2f96f9da093e3ff6 Mon Sep 17 00:00:00 2001 From: Nextcloud bot Date: Sun, 25 Jan 2026 03:08:36 +0000 Subject: [PATCH 170/216] fix(l10n): Update translations from Transifex Signed-off-by: Nextcloud bot --- app/src/main/res/values-b+en+001/strings.xml | 1 + app/src/main/res/values-it/strings.xml | 52 ++++++++++++++++++++ app/src/main/res/values-zh-rHK/strings.xml | 1 + 3 files changed, 54 insertions(+) diff --git a/app/src/main/res/values-b+en+001/strings.xml b/app/src/main/res/values-b+en+001/strings.xml index d681b96eb4aa..a60e4d512b1d 100644 --- a/app/src/main/res/values-b+en+001/strings.xml +++ b/app/src/main/res/values-b+en+001/strings.xml @@ -60,6 +60,7 @@ Unable to fetch task list, please check your internet connection. Delete Task The task output is not ready yet. + Text copied from another app Assistant Input Output diff --git a/app/src/main/res/values-it/strings.xml b/app/src/main/res/values-it/strings.xml index cfd6bedb68b4..3166cd379d32 100644 --- a/app/src/main/res/values-it/strings.xml +++ b/app/src/main/res/values-it/strings.xml @@ -408,6 +408,7 @@ I file e le cartelle che condividi saranno mostrati qui. Ancora nessuna condivisione Nessun risultato trovato per la tua interrogazione + Avvia la tua ricerca cartella LIVE Caricamento in corso… @@ -582,6 +583,7 @@ Nuova cartella multimediale %1$s rilevata foto video + Nuova notifica Una nuova versione è stata creata Nessuna azione per questo utente Nessun applicazione disponibile per gestire i collegamenti @@ -653,8 +655,11 @@ Rinomina la nuova versione Cosa fare se il file esiste già? Aggiungi account + Consenti all\'applicazione di accedere e gestire tutti i file sul tuo dispositivo + Accesso a tutti i file Sincronizza calendario e contatti F-Droid o Google Play non installato + Configura DAVx⁵ (originariamente conosciuto come DAVdroid) (v1.3.0+) per l\'account attuale Sincronizzazione calendario e contatti configurata Informazioni Dettagli @@ -706,6 +711,7 @@ Intervallo Gestisci le cartelle interne per la sincronizzazione bidirezionale Abilita sincronizzazione bidirezionale + Sincronizzazione bidirezionale Scuro Chiaro Segui il sistema @@ -767,6 +773,7 @@ Caricamento automatico per le tue foto e video Calendario e contatti + Sincronizza con DAVx⁵ Errore nel recuperare i risultati della ricerca La condivisione sicura non è configurata per questo utente Condivisione sicura... @@ -775,12 +782,20 @@ Scegli un modello Seleziona modello Invia + Invia copia a + Invia condivisione Icona pulsante di invio + Impossibile caricare il contenuto + È probabile che il dispositivo non sia connesso a Internet Imposta come + Imposta message + Imposta nota + Stato in linea Usa immagine come Configurando la cifratura end-to-end, riceverai una frase di 12 parole mnemoniche casuali, che ti servirà per aprire i tuoi file su altri dispositivi. Questa sarà conservata solo su questo dispositivo, e può essere mostrata di nuovo in questa schermata. Annotala in un posto sicuro! Condividi Consenti scaricamento e sincr. + Condividi e copia collegamento Crea Autorizzazioni personalizzate Elimina @@ -805,10 +820,12 @@ Imposta data di scadenza Imposta password La ricondivisione non è consentita durante il file drop sicuro + Seleziona almeno un\'opzione di condivisione prima di continuare. Può modificare Richiesta file File drop sicuro Sola lettura + Permessi di condivisione Condividi Lettura %1$s (remota) @@ -833,6 +850,7 @@ Mostra le foto Mostra meno Mostra i video + Controlla manualmente i termini di servizio! Registrati a un fornitore Vuoi consentire a %1$s di accedere al tuo account Nextcloud %2$s? Ordina per @@ -873,6 +891,8 @@ Archiviazione interna Video Musica + Accesso a tutti i file + Non chiedere Multimediali in sola lettura Immagini La piattaforma di produttività auto-gestita che ti lascia al comando.\nQuesta è la versione di sviluppo ufficiale e include funzionalità nuove, non testate che potrebbero provocare instabilità e perdite di dati. Questa applicazione è pensata per gli utenti che desiderano provare le nuove funzionalità e segnalare bug, se si verificano. Non utilizzarla in ambienti di produzione!\n\nSia la versione di sviluppo che quella normale sono disponibili su F-droid, e possono essere installate contemporaneamente. @@ -891,6 +911,9 @@ Solo video Suggerisci Sincronizzazione + Sincronizza comunque + Risolvi i conflitti + Conflitti caricamento file Conflitti rilevati La cartella %1$s non esiste più Impossibile sincronizzare %1$s @@ -942,6 +965,7 @@ Evento non trovato, puoi sempre sincronizzarti per aggiornare. Reindirizzamento al Web... Contatto non trovato, puoi sempre sincronizzare per aggiornare. Reindirizzamento al Web... Sono necessarie le autorizzazioni per aprire il risultato della ricerca, altrimenti verrà reindirizzato al web... + In questa cartella Sconosciuto Sblocca file Sono presenti commenti non letti @@ -990,6 +1014,8 @@ Il file non può essere copiato nell\'archiviazione locale Blocco della cartella non riuscito Caricamento annullato dall\'utente + Consenti l\'accesso a tutti i file + Permessi applicazione %1$d / %2$d - %3$s La cifratura è possibile solo con >= Android 5.0 La mancanza di spazio impedisce di copiare i file selezionati nella cartella %1$s. Vuoi spostarli in quella cartella? @@ -1044,6 +1070,7 @@ Certificato server non fidato Recupero versione del server… Applicazione terminata + Saltato Completati Stesso file trovato in remoto, salto il caricamento Errore sconosciuto @@ -1087,6 +1114,21 @@ %d minuti %d minuti + + %d secondo fa + %d secondi fa + %d secondi fa + + + %d minuto fa + %d minuti fa + %d minuti fa + + + %d ora fa + %d ore fa + %d ore fa + Impossibile sincronizzare %1$d file (conflitto con: %2$d) Impossibile sincronizzare %1$d file (conflitto con: %2$d) @@ -1142,6 +1184,11 @@ %1$d file %1$d file + + %1$d elemento + %1$d file + %1$d file + Mostra %1$d cartella nascosta Mostra %1$d cartelle nascoste @@ -1152,4 +1199,9 @@ %d selezionati %d selezionati + + %d secondo + %d secondi + %d secondi + diff --git a/app/src/main/res/values-zh-rHK/strings.xml b/app/src/main/res/values-zh-rHK/strings.xml index f19580c4263c..2cbec3d3bb22 100644 --- a/app/src/main/res/values-zh-rHK/strings.xml +++ b/app/src/main/res/values-zh-rHK/strings.xml @@ -60,6 +60,7 @@ 無法擷取任務清單,請檢查您的網際網路連線。 刪除任務 任務輸出尚未就緒。 + 已從其他應用程式複製文字 助手 輸入 輸出 From 9726b06db317116d881ca1d3a4d630ecc59e9932 Mon Sep 17 00:00:00 2001 From: Nextcloud bot Date: Mon, 26 Jan 2026 03:29:50 +0000 Subject: [PATCH 171/216] fix(l10n): Update translations from Transifex Signed-off-by: Nextcloud bot --- app/src/main/res/values-cs-rCZ/strings.xml | 8 ++++++++ app/src/main/res/values-nl/strings.xml | 19 +++++++++++++++++++ .../android/cs-CZ/full_description.txt | 2 +- 3 files changed, 28 insertions(+), 1 deletion(-) diff --git a/app/src/main/res/values-cs-rCZ/strings.xml b/app/src/main/res/values-cs-rCZ/strings.xml index f366a2644edd..3917818f405a 100644 --- a/app/src/main/res/values-cs-rCZ/strings.xml +++ b/app/src/main/res/values-cs-rCZ/strings.xml @@ -13,6 +13,7 @@ Poslat/nasdílet Zobrazení v mřížce Zobrazení v seznamu + Akce spuštěna Obnovit kontakty a kalendář Nová složka Přesunout nebo zkopírovat @@ -59,6 +60,7 @@ Nedaří se získat seznam úloh – zkontrolujte připojení k Internetu. Smazat úlohu Výstup z úkolu ještě není připraven. + Text zkopírován z jiné aplikace Asistent Vstup Výstup @@ -397,6 +399,7 @@ Nepodařilo se vytvořit dialog o konfliktu Předání souboru správci stahování se nezdařilo Soubor se nepodařilo vytisknout + Selhalo spuštění akce! Editor se nepodařilo spustit Nepodařilo se aktualizovat uživatelské rozhraní Přidat do oblíbených @@ -756,6 +759,7 @@ Interval Spravovat interní složky pro dvoucestnou synchronizaci Zapnout obousměrnou synchronizaci + Obousměrná synchronizace Tmavý Světlý Převzít od systému @@ -943,6 +947,7 @@ Neptat se Média pouze pro čtení Obrázky + Platforma pro produktivitu hostovaná u vás, kde vaše data jsou opravdu vaše.\n\nFunkce:\n* Snadno použitelné moderní rozhraní, s motivem vzhledu sladěným s tím nastaveným na serveru\n* Nahrávání souborů na vámi využívaný Nextcloud server\n* Jejich sdílení s ostatními\n* Udržování vašich oblíbených souborů a složek synchronizovaných\n* Vyhledávání napříč všemi složkami na vámi využívaném serveru\n* Automatické nahrávání fotek a videí pořízených vaším zařízením\n* Budete v obraze díky upozorněním\n* Podpora vícero účtů\n* Zabezpečení přístupu k vašim datům otiskem prstu nebo PIN kódem\n* Propojení s aplikací DAVx⁵ (dříve známé jako DAVdroid) pro snadné nastavení synchronizace kalendáře a kontaktů\n\nVeškeré problémy prosíme hlaste na https://github.com/nextcloud/android/issues, diskutovat lze na https://help.nextcloud.com/c/clients/android\n\nJeště Nextcloud neznáte? Je to server pro komunikaci, synchronizaci a sdílení vašich dat. Jedná se o svobodný software, který můžete provozovat sami, nebo si jako službu koupit u jiné společnosti. Díky tomu máte kontrolu nad svými fotkami, kalendářem, kontakty i dokumenty a vším ostatním.\n\nVíce o Nextcloud naleznete na https://nextcloud.com Platforma pro produktivitu hostovaná u vás, kde vaše data jsou opravdu vaše.\nToto je oficiální vývojová verze, sloužící jako denně aktualizovaná ukázka nových nevyzkoušených funkcí, což může způsobovat nestabilitu a ztráty dat. Je určeno pro uživatele, kteří jsou ochotní testovat a hlásit chyby na které narazí. Nepoužívejte pro svou produktivní práci!\n\nJak vývojová tak produkční verze jsou k dispozici na F-droid a mohou být nainstalovány souběžně. Platforma pro produktivitu hostovaná u vás, kde vaše data jsou opravdu vaše Platforma pro produktivitu hostovaná u vás, kde vaše data jsou opravdu vaše (vývojová verze) @@ -960,6 +965,9 @@ Doporučit Synchronizovat Synchronizovat i tak + Vyřešit konflikty + Detekovány konflikty s nahráváním souborů. Otevřít nastavení nahrávání a vyřešit je. + Konflikty při nahrávání souborů Nalezeny konflikty Složka %1$s už neexistuje Synchronizovat duplikaci diff --git a/app/src/main/res/values-nl/strings.xml b/app/src/main/res/values-nl/strings.xml index c5a8279a6bd2..c09cc2523c93 100644 --- a/app/src/main/res/values-nl/strings.xml +++ b/app/src/main/res/values-nl/strings.xml @@ -44,6 +44,8 @@ Toont één widget van dashboard Zoeken in %s Toon afwezig + Kon bericht niet versturen + Chat berichten ophalen is mislukt Bent u zeker dat u deze taak wilt verwijderen? Verwijder taak Er is een fout opgetreden bij het aanmaken van de taak @@ -53,6 +55,7 @@ Kan takenlijst niet ophalen. Controleer je internetverbinding. Verwijder taak De taakuitvoer is nog niet klaar. + Tekst gekopieerd uit een andere app Assistent Input Output @@ -93,6 +96,7 @@ Upload alleen met Wi-Fi /AutomatischUploaden Deze map is al opgenomen in de synchronisatie van de bovenliggende map, wat kan leiden tot dubbele uploads. + Bestanden aan het uploaden van %s naar %s Configureren Maak aangepaste nieuwe map aan Instellen aangepaste map @@ -198,7 +202,12 @@ Import kon niet starten. Probeer alstublieft opnieuw Geen bestand gevonden Je laatste backup is niet te vinden! + Gesprek aanmaken is mislukt + Verwijder gesprek + Gesprek verwijderen is mislukt Geen gesprekken gevonden + Nog geen gesprekken + Ophalen van lijst met gesprekken is mislukt Gesprekken Gekopieerd Er trad een fout op bij het kopiëren van dit bestand of deze map @@ -405,6 +414,8 @@ Geen zoekresultaten voor je opvraag Begin met zoeken Type in bovenstaande zoekbalk om bestanden, contacten, gebeurtenissen en meer te vinden in je account. + Controleer uw internetverbinding en probeer het later opnieuw + Slechte verbinding map LIVE Laden… @@ -465,6 +476,9 @@ Map bestaat al Deze map kan het beste worden bekeken in %1$s. Aanmaken + %1$d van%2$d · %3$s + %s map succesvol gesynchroniseerd + Synchroniseren... Hier zijn geen bestanden Mapnaam mag niet leeg zijn Kies @@ -619,6 +633,7 @@ Geen internet verbinding Zelfs zonder internetverbinding kun je je mappen organiseren en bestanden aanmaken. Zodra je weer online bent, worden de wachtende acties automatisch gesynchroniseerd. Je bent offline, maar het werk gaat door + Bestand bestaat nog niet. Upload het bestand eerst. Kon %s niet aanmaken. Een bestand met dezelfde naam bestaat al op de server. Kon %s niet aanmaken. Een map met dezelfde naam bestaat al op de server. De offline taak kan niet worden voltooid. %s @@ -717,6 +732,7 @@ Interval Interne mappen beheren voor tweeweg-synchronisatie Tweeweg-synchronisatie inschakelen + Tweeweg-synchronisatie Donker Licht Systeem volgen @@ -972,6 +988,7 @@ Gebeurtenis niet gevonden. Je kan altijd synchroniseren voor een update. Doorsturen naar het web... Contactpersoon niet gevonden. Je kan altijd synchroniseren voor een update. Doorsturen naar het web... Er zijn machtigingen nodig om de zoekresultaten te openen, anders wordt de opdracht doorgestuurd naar het web… + In deze map Onbekend Ontgrendel bestand Er zijn ongelezen reacties @@ -1074,6 +1091,8 @@ Niet vertrouwd servercertificaat Server-versie ophalen... App afgesloten + Overgeslagen + Er bestaat al een bestand met deze naam. Voltooid Hetzelfde bestand op de server gevonden. Upload overgeslagen Onbekende fout diff --git a/src/generic/fastlane/metadata/android/cs-CZ/full_description.txt b/src/generic/fastlane/metadata/android/cs-CZ/full_description.txt index bc781005d526..c76c06a0a591 100644 --- a/src/generic/fastlane/metadata/android/cs-CZ/full_description.txt +++ b/src/generic/fastlane/metadata/android/cs-CZ/full_description.txt @@ -10,7 +10,7 @@ Funkce: * Budete v obraze díky upozorněním * Podpora vícero účtů * Zabezpečení přístupu k vašim datům otiskem prstu nebo PIN kódem -* Propojení s aplikací DAVx5 (dříve známé jako DAVdroid) pro snadné nastavení synchronizace kalendáře a kontaktů +* Propojení s aplikací DAVx⁵ (dříve známé jako DAVdroid) pro snadné nastavení synchronizace kalendáře a kontaktů Veškeré problémy prosíme hlaste na https://github.com/nextcloud/android/issues, diskutovat lze na https://help.nextcloud.com/c/clients/android From 96e8c580f2599ec1f48027ff4d1e6954abb9f54d Mon Sep 17 00:00:00 2001 From: Andy Scherzinger Date: Thu, 1 Jan 2026 16:31:04 +0100 Subject: [PATCH 172/216] style(searchbar): Migrate to M3 search bar style Signed-off-by: Andy Scherzinger --- .../android/ui/activity/ToolbarActivity.java | 8 +- app/src/main/res/layout/toolbar_standard.xml | 187 +++++++++--------- 2 files changed, 100 insertions(+), 95 deletions(-) diff --git a/app/src/main/java/com/owncloud/android/ui/activity/ToolbarActivity.java b/app/src/main/java/com/owncloud/android/ui/activity/ToolbarActivity.java index 75bbfa7ff180..63489451c7db 100644 --- a/app/src/main/java/com/owncloud/android/ui/activity/ToolbarActivity.java +++ b/app/src/main/java/com/owncloud/android/ui/activity/ToolbarActivity.java @@ -64,7 +64,8 @@ public abstract class ToolbarActivity extends BaseActivity implements Injectable private AppBarLayout mAppBar; private RelativeLayout mDefaultToolbar; private MaterialToolbar mToolbar; - private MaterialCardView mHomeSearchToolbar; + private MaterialCardView mHomeSearchContainer; + private LinearLayout mHomeSearchToolbar; private ImageView mPreviewImage; private FrameLayout mPreviewImageContainer; private LinearLayout mInfoBox; @@ -88,6 +89,7 @@ private void setupToolbar(boolean isHomeSearchToolbarShow, boolean showSortListB mAppBar = findViewById(R.id.appbar); mDefaultToolbar = findViewById(R.id.default_toolbar); mHomeSearchToolbar = findViewById(R.id.home_toolbar); + mHomeSearchContainer = findViewById(R.id.home_search_container); mMenuButton = findViewById(R.id.menu_button); mSearchText = findViewById(R.id.search_text); mSwitchAccountButton = findViewById(R.id.switch_account_button); @@ -113,7 +115,7 @@ private void setupToolbar(boolean isHomeSearchToolbarShow, boolean showSortListB viewThemeUtils.platform.themeStatusBar(this); viewThemeUtils.material.colorMaterialTextButton(mSwitchAccountButton); - viewThemeUtils.material.themeSearchCardView(mHomeSearchToolbar); + viewThemeUtils.material.themeSearchCardView(mHomeSearchContainer); viewThemeUtils.material.colorMaterialButtonContent(mMenuButton, ColorRole.ON_SURFACE); viewThemeUtils.material.colorMaterialButtonContent(mNotificationButton, ColorRole.ON_SURFACE); viewThemeUtils.platform.colorTextView(mSearchText, ColorRole.ON_SURFACE_VARIANT); @@ -286,7 +288,7 @@ private void showHomeSearchToolbar(boolean isShow) { R.animator.appbar_elevation_off)); mDefaultToolbar.setVisibility(View.GONE); mHomeSearchToolbar.setVisibility(View.VISIBLE); - viewThemeUtils.material.themeSearchCardView(mHomeSearchToolbar); + viewThemeUtils.material.themeSearchCardView(mHomeSearchContainer); viewThemeUtils.material.themeSearchBarText(mSearchText); } else { mAppBar.setStateListAnimator(AnimatorInflater.loadStateListAnimator(mAppBar.getContext(), diff --git a/app/src/main/res/layout/toolbar_standard.xml b/app/src/main/res/layout/toolbar_standard.xml index b44970084204..8c6ee74c84c4 100644 --- a/app/src/main/res/layout/toolbar_standard.xml +++ b/app/src/main/res/layout/toolbar_standard.xml @@ -2,9 +2,9 @@ @@ -56,11 +56,11 @@ + tools:visibility="visible"> @@ -145,91 +145,94 @@ android:lines="1" android:textSize="16sp" android:layout_width="wrap_content" - android:layout_height="48dp"/> + android:layout_height="@dimen/minimum_size_for_touchable_area"/> - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + From 500b03a76fd1432d0c52f21197da2fc1e2b3f295 Mon Sep 17 00:00:00 2001 From: Andy Scherzinger Date: Sun, 25 Jan 2026 15:16:09 +0100 Subject: [PATCH 173/216] style(assistant): Make chat bubbles dark/light aware and like Nextcloud Talk chat bubbles * background color like incoming chat messages * timestamp end-aligned * Make toolbar look like other toolbar usages (headline size, drawer icon) * Ensure tab bar theming respects server-theme Resolves #16351 Signed-off-by: Andy Scherzinger --- .../client/assistant/chat/ChatContent.kt | 22 +++++++++++-------- .../assistant/taskTypes/TaskTypesRow.kt | 7 +++--- app/src/main/res/layout/toolbar_standard.xml | 18 +++++++++------ app/src/main/res/values-night/colors.xml | 2 +- app/src/main/res/values/colors.xml | 2 +- 5 files changed, 30 insertions(+), 21 deletions(-) diff --git a/app/src/main/java/com/nextcloud/client/assistant/chat/ChatContent.kt b/app/src/main/java/com/nextcloud/client/assistant/chat/ChatContent.kt index 930334ae8d4f..f88f54e2a176 100644 --- a/app/src/main/java/com/nextcloud/client/assistant/chat/ChatContent.kt +++ b/app/src/main/java/com/nextcloud/client/assistant/chat/ChatContent.kt @@ -42,7 +42,6 @@ import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.draw.clip import androidx.compose.ui.draw.scale -import androidx.compose.ui.graphics.Color import androidx.compose.ui.layout.ContentScale import androidx.compose.ui.res.colorResource import androidx.compose.ui.res.painterResource @@ -123,7 +122,7 @@ private fun AssistantTypingIndicator() { bottomEnd = CHAT_BUBBLE_CORNER_RADIUS ) ) - .background(color = colorResource(R.color.white)) + .background(color = colorResource(R.color.bg_message_bubble)) ) { TypingAnimation() } @@ -148,7 +147,9 @@ private fun AnimatedAssistantIcon() { modifier = Modifier .size(ASSISTANT_ICON_SIZE) .clip(CircleShape) - .background(Color.White), + .background( + color = colorResource(R.color.bg_message_bubble) + ), contentAlignment = Alignment.Center ) { Image( @@ -205,7 +206,9 @@ private fun AssistantMessageItem(message: ChatMessage) { modifier = Modifier .size(ASSISTANT_ICON_SIZE) .clip(CircleShape) - .background(Color.White), + .background( + color = colorResource(R.color.bg_message_bubble) + ), contentAlignment = Alignment.Center ) { Image( @@ -228,7 +231,7 @@ private fun AssistantMessageItem(message: ChatMessage) { ) ) .background( - color = colorResource(R.color.white) + color = colorResource(R.color.bg_message_bubble) ) ) { MessageTextItem(message) @@ -259,7 +262,7 @@ private fun UserMessageItem(message: ChatMessage) { bottomStart = CHAT_BUBBLE_CORNER_RADIUS ) ) - .background(color = colorResource(R.color.white)) + .background(color = colorResource(R.color.bg_message_bubble)) ) { MessageTextItem(message) } @@ -280,13 +283,14 @@ private fun MessageTextItem(message: ChatMessage) { fontSize = 16.sp ) ) - Spacer(modifier = Modifier.height(8.dp)) + Spacer(modifier = Modifier.height(4.dp)) Text( text = message.time(), style = TextStyle( - color = colorResource(R.color.text_color), + color = colorResource(R.color.secondary_text_color), fontSize = 12.sp - ) + ), + modifier = Modifier.align(Alignment.End) ) } } diff --git a/app/src/main/java/com/nextcloud/client/assistant/taskTypes/TaskTypesRow.kt b/app/src/main/java/com/nextcloud/client/assistant/taskTypes/TaskTypesRow.kt index f1af94510c3e..5c4290868a3f 100644 --- a/app/src/main/java/com/nextcloud/client/assistant/taskTypes/TaskTypesRow.kt +++ b/app/src/main/java/com/nextcloud/client/assistant/taskTypes/TaskTypesRow.kt @@ -15,6 +15,7 @@ import androidx.compose.foundation.layout.Spacer import androidx.compose.foundation.layout.width import androidx.compose.material3.Icon import androidx.compose.material3.IconButton +import androidx.compose.material3.MaterialTheme import androidx.compose.material3.PrimaryScrollableTabRow import androidx.compose.material3.Tab import androidx.compose.material3.TabRowDefaults @@ -43,7 +44,7 @@ fun TaskTypesRow( val selectedTabIndex = data.indexOfFirst { it.id == selectedTaskType?.id }.takeIf { it >= 0 } ?: 0 Row( - modifier = Modifier.background(color = colorResource(R.color.actionbar_color)), + modifier = Modifier.background(color = MaterialTheme.colorScheme.surface), horizontalArrangement = Arrangement.Center ) { if (data.any { it.isChat() }) { @@ -63,11 +64,11 @@ fun TaskTypesRow( PrimaryScrollableTabRow( selectedTabIndex = selectedTabIndex, edgePadding = 0.dp, - containerColor = colorResource(R.color.actionbar_color), + containerColor = MaterialTheme.colorScheme.surface, indicator = { TabRowDefaults.SecondaryIndicator( Modifier.tabIndicatorOffset(selectedTabIndex), - color = colorResource(R.color.primary) + color = MaterialTheme.colorScheme.primary ) } ) { diff --git a/app/src/main/res/layout/toolbar_standard.xml b/app/src/main/res/layout/toolbar_standard.xml index 8c6ee74c84c4..af71bd5843e2 100644 --- a/app/src/main/res/layout/toolbar_standard.xml +++ b/app/src/main/res/layout/toolbar_standard.xml @@ -118,9 +118,7 @@ android:id="@+id/toolbar_linear_layout" android:layout_width="match_parent" android:layout_height="wrap_content" - android:layout_marginStart="@dimen/standard_half_margin" android:layout_marginTop="@dimen/standard_half_margin" - android:layout_marginEnd="@dimen/standard_margin" android:layout_marginBottom="@dimen/standard_quarter_margin" android:orientation="horizontal" android:visibility="gone" @@ -134,18 +132,24 @@ style="@style/Widget.AppTheme.Button.IconButton" android:layout_width="@dimen/minimum_size_for_touchable_area" android:layout_height="@dimen/minimum_size_for_touchable_area" + android:layout_marginStart="@dimen/standard_quarter_margin" + android:layout_marginTop="-4dp" + android:layout_marginEnd="@dimen/standard_half_margin" + android:contentDescription="@string/drawer_open" app:cornerRadius="@dimen/button_corner_radius" app:icon="@drawable/ic_menu" - app:iconTint="@color/black" /> + app:iconSize="@dimen/search_bar_icon_size" + app:iconTint="@color/fontAppbar" /> + android:textColor="@color/black" + android:textSize="24sp" + tools:text="Headline" /> diff --git a/app/src/main/res/values-night/colors.xml b/app/src/main/res/values-night/colors.xml index db1e1d218038..ed63c8d8cb26 100644 --- a/app/src/main/res/values-night/colors.xml +++ b/app/src/main/res/values-night/colors.xml @@ -38,5 +38,5 @@ #1E1E1E @android:color/white - #101418 + #2A2A2A diff --git a/app/src/main/res/values/colors.xml b/app/src/main/res/values/colors.xml index 36d7459ecdaf..03c7d56abea0 100644 --- a/app/src/main/res/values/colors.xml +++ b/app/src/main/res/values/colors.xml @@ -88,5 +88,5 @@ #666666 #A5A5A5 - #F7F9FF + #EFEFEF From b9461713f7bac345bb21cb2351f732dd99b7b3fe Mon Sep 17 00:00:00 2001 From: Andy Scherzinger Date: Sun, 25 Jan 2026 16:38:51 +0100 Subject: [PATCH 174/216] fix(a11y): Set content description to null since image is purely decorative (for the text below it) Signed-off-by: Andy Scherzinger --- .../java/com/nextcloud/client/assistant/AssistantScreen.kt | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/app/src/main/java/com/nextcloud/client/assistant/AssistantScreen.kt b/app/src/main/java/com/nextcloud/client/assistant/AssistantScreen.kt index b8b5d43532cb..d1fd5fbbc79c 100644 --- a/app/src/main/java/com/nextcloud/client/assistant/AssistantScreen.kt +++ b/app/src/main/java/com/nextcloud/client/assistant/AssistantScreen.kt @@ -379,9 +379,8 @@ private fun EmptyContent(paddingValues: PaddingValues, iconId: Int?, description painter = painterResource(id = iconId), modifier = Modifier.size(32.dp), colorFilter = ColorFilter.tint(color = colorResource(R.color.text_color)), - contentDescription = "empty content icon" + contentDescription = null ) - Spacer(modifier = Modifier.height(8.dp)) } From 301769b2738a572b85d827b7845674432fcbdeff Mon Sep 17 00:00:00 2001 From: alperozturk96 Date: Mon, 26 Jan 2026 10:23:10 +0100 Subject: [PATCH 175/216] fix(upload-list-adapter): end timestamp Signed-off-by: alperozturk96 --- .../client/database/entity/UploadEntity.kt | 4 +--- .../datamodel/UploadsStorageManager.java | 9 +++++++- .../android/ui/adapter/UploadListAdapter.java | 22 +++++++++++-------- 3 files changed, 22 insertions(+), 13 deletions(-) diff --git a/app/src/main/java/com/nextcloud/client/database/entity/UploadEntity.kt b/app/src/main/java/com/nextcloud/client/database/entity/UploadEntity.kt index 55255f5fb01a..dc8be81183d0 100644 --- a/app/src/main/java/com/nextcloud/client/database/entity/UploadEntity.kt +++ b/app/src/main/java/com/nextcloud/client/database/entity/UploadEntity.kt @@ -103,9 +103,7 @@ fun OCUpload.toUploadEntity(): UploadEntity { localBehaviour = localAction, nameCollisionPolicy = nameCollisionPolicy?.serialize(), isCreateRemoteFolder = if (isCreateRemoteFolder) 1 else 0, - - // uploadEndTimestamp may overflow max int capacity since it is conversion from long to int. coerceAtMost needed - uploadEndTimestamp = uploadEndTimestamp.coerceAtMost(Int.MAX_VALUE.toLong()).toInt(), + uploadEndTimestamp = uploadEndTimestamp.toInt(), lastResult = lastResult?.value, createdBy = createdBy, isWifiOnly = if (isUseWifiOnly) 1 else 0, diff --git a/app/src/main/java/com/owncloud/android/datamodel/UploadsStorageManager.java b/app/src/main/java/com/owncloud/android/datamodel/UploadsStorageManager.java index 9a72022eef5a..b68ad0c0ec7a 100644 --- a/app/src/main/java/com/owncloud/android/datamodel/UploadsStorageManager.java +++ b/app/src/main/java/com/owncloud/android/datamodel/UploadsStorageManager.java @@ -464,7 +464,14 @@ private OCUpload createOCUploadFromCursor(Cursor c) { c.getColumnIndexOrThrow(ProviderTableMeta.UPLOADS_NAME_COLLISION_POLICY)))); upload.setCreateRemoteFolder(c.getInt( c.getColumnIndexOrThrow(ProviderTableMeta.UPLOADS_IS_CREATE_REMOTE_FOLDER)) == 1); - upload.setUploadEndTimestamp(c.getLong(c.getColumnIndexOrThrow(ProviderTableMeta.UPLOADS_UPLOAD_END_TIMESTAMP))); + + final var uploadEndTimestampColumnIndex= c.getColumnIndex(ProviderTableMeta.UPLOADS_UPLOAD_END_TIMESTAMP); + if (uploadEndTimestampColumnIndex > -1) { + final var uploadEndTimestamp = c.getLong(uploadEndTimestampColumnIndex); + if (uploadEndTimestamp > 0) { + upload.setUploadEndTimestamp(uploadEndTimestamp); + } + } upload.setLastResult(UploadResult.fromValue( c.getInt(c.getColumnIndexOrThrow(ProviderTableMeta.UPLOADS_LAST_RESULT)))); upload.setCreatedBy(c.getInt(c.getColumnIndexOrThrow(ProviderTableMeta.UPLOADS_CREATED_BY))); diff --git a/app/src/main/java/com/owncloud/android/ui/adapter/UploadListAdapter.java b/app/src/main/java/com/owncloud/android/ui/adapter/UploadListAdapter.java index fac48e303d2d..c40b15c68076 100755 --- a/app/src/main/java/com/owncloud/android/ui/adapter/UploadListAdapter.java +++ b/app/src/main/java/com/owncloud/android/ui/adapter/UploadListAdapter.java @@ -369,11 +369,16 @@ public void onBindViewHolder(SectionedViewHolder holder, int section, int relati // upload date long updateTime = item.getUploadEndTimestamp(); - CharSequence dateString = DisplayUtils.getRelativeDateTimeString(parentActivity, - updateTime, - DateUtils.SECOND_IN_MILLIS, - DateUtils.WEEK_IN_MILLIS, 0); - itemViewHolder.binding.uploadDate.setText(dateString); + boolean showUploadDate = item.getUploadStatus() == UploadStatus.UPLOAD_SUCCEEDED && item.getLastResult() == UploadResult.UPLOADED; + itemViewHolder.binding.uploadDate.setVisibility(showUploadDate ? View.VISIBLE : View.GONE); + if (showUploadDate && updateTime > 0) { + CharSequence dateString = DisplayUtils.getRelativeDateTimeString(parentActivity, + updateTime, + DateUtils.SECOND_IN_MILLIS, + DateUtils.WEEK_IN_MILLIS, + 0); + itemViewHolder.binding.uploadDate.setText(dateString); + } // account final Optional optionalUser = accountManager.getUser(item.getAccountName()); @@ -390,7 +395,6 @@ public void onBindViewHolder(SectionedViewHolder holder, int section, int relati } // Reset fields visibility - itemViewHolder.binding.uploadDate.setVisibility(View.VISIBLE); itemViewHolder.binding.uploadRemotePath.setVisibility(View.VISIBLE); itemViewHolder.binding.uploadFileSize.setVisibility(View.VISIBLE); itemViewHolder.binding.uploadStatus.setVisibility(View.VISIBLE); @@ -428,11 +432,12 @@ public void onBindViewHolder(SectionedViewHolder holder, int section, int relati } } - itemViewHolder.binding.uploadDate.setVisibility(View.GONE); itemViewHolder.binding.uploadFileSize.setVisibility(View.GONE); itemViewHolder.binding.uploadProgressBar.invalidate(); } - case UPLOAD_FAILED -> itemViewHolder.binding.uploadDate.setVisibility(View.GONE); + case UPLOAD_FAILED -> { + + } case UPLOAD_SUCCEEDED, UPLOAD_CANCELLED -> itemViewHolder.binding.uploadStatus.setVisibility(View.GONE); } @@ -442,7 +447,6 @@ public void onBindViewHolder(SectionedViewHolder holder, int section, int relati || item.getUploadStatus() == UploadStatus.UPLOAD_CANCELLED) { itemViewHolder.binding.uploadStatus.setVisibility(View.VISIBLE); - itemViewHolder.binding.uploadDate.setVisibility(View.GONE); itemViewHolder.binding.uploadFileSize.setVisibility(View.GONE); } From 8cd0239de6b8b0736cd04e250b8e6a6c91eac08f Mon Sep 17 00:00:00 2001 From: alperozturk96 Date: Mon, 26 Jan 2026 11:11:13 +0100 Subject: [PATCH 176/216] fix(upload-list-adapter): end timestamp Signed-off-by: alperozturk96 [skip ci] --- .../98.json | 1303 +++++++++++++++++ .../client/database/entity/UploadEntity.kt | 10 +- .../datamodel/UploadsStorageManager.java | 6 +- .../com/owncloud/android/db/ProviderMeta.java | 2 + .../android/ui/adapter/UploadListAdapter.java | 19 +- 5 files changed, 1331 insertions(+), 9 deletions(-) create mode 100644 app/schemas/com.nextcloud.client.database.NextcloudDatabase/98.json diff --git a/app/schemas/com.nextcloud.client.database.NextcloudDatabase/98.json b/app/schemas/com.nextcloud.client.database.NextcloudDatabase/98.json new file mode 100644 index 000000000000..ff3d56813529 --- /dev/null +++ b/app/schemas/com.nextcloud.client.database.NextcloudDatabase/98.json @@ -0,0 +1,1303 @@ +{ + "formatVersion": 1, + "database": { + "version": 98, + "identityHash": "02ca435c31a732cd82a36717518c37b3", + "entities": [ + { + "tableName": "arbitrary_data", + "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`_id` INTEGER PRIMARY KEY AUTOINCREMENT, `cloud_id` TEXT, `key` TEXT, `value` TEXT)", + "fields": [ + { + "fieldPath": "id", + "columnName": "_id", + "affinity": "INTEGER" + }, + { + "fieldPath": "cloudId", + "columnName": "cloud_id", + "affinity": "TEXT" + }, + { + "fieldPath": "key", + "columnName": "key", + "affinity": "TEXT" + }, + { + "fieldPath": "value", + "columnName": "value", + "affinity": "TEXT" + } + ], + "primaryKey": { + "autoGenerate": true, + "columnNames": [ + "_id" + ] + } + }, + { + "tableName": "capabilities", + "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`_id` INTEGER PRIMARY KEY AUTOINCREMENT, `assistant` INTEGER, `account` TEXT, `version_mayor` INTEGER, `version_minor` INTEGER, `version_micro` INTEGER, `version_string` TEXT, `version_edition` TEXT, `extended_support` INTEGER, `core_pollinterval` INTEGER, `sharing_api_enabled` INTEGER, `sharing_public_enabled` INTEGER, `sharing_public_password_enforced` INTEGER, `sharing_public_expire_date_enabled` INTEGER, `sharing_public_expire_date_days` INTEGER, `sharing_public_expire_date_enforced` INTEGER, `sharing_public_send_mail` INTEGER, `sharing_public_upload` INTEGER, `sharing_user_send_mail` INTEGER, `sharing_resharing` INTEGER, `sharing_federation_outgoing` INTEGER, `sharing_federation_incoming` INTEGER, `files_bigfilechunking` INTEGER, `files_undelete` INTEGER, `files_versioning` INTEGER, `external_links` INTEGER, `server_name` TEXT, `server_color` TEXT, `server_text_color` TEXT, `server_element_color` TEXT, `server_slogan` TEXT, `server_logo` TEXT, `background_url` TEXT, `end_to_end_encryption` INTEGER, `end_to_end_encryption_keys_exist` INTEGER, `end_to_end_encryption_api_version` TEXT, `activity` INTEGER, `background_default` INTEGER, `background_plain` INTEGER, `richdocument` INTEGER, `richdocument_mimetype_list` TEXT, `richdocument_direct_editing` INTEGER, `richdocument_direct_templates` INTEGER, `richdocument_optional_mimetype_list` TEXT, `sharing_public_ask_for_optional_password` INTEGER, `richdocument_product_name` TEXT, `direct_editing_etag` TEXT, `user_status` INTEGER, `user_status_supports_emoji` INTEGER, `etag` TEXT, `files_locking_version` TEXT, `groupfolders` INTEGER, `drop_account` INTEGER, `security_guard` INTEGER, `forbidden_filename_characters` INTEGER, `forbidden_filenames` INTEGER, `forbidden_filename_extensions` INTEGER, `forbidden_filename_basenames` INTEGER, `files_download_limit` INTEGER, `files_download_limit_default` INTEGER, `recommendation` INTEGER, `notes_folder_path` TEXT, `default_permissions` INTEGER, `user_status_supports_busy` INTEGER, `windows_compatible_filenames` INTEGER, `has_valid_subscription` INTEGER, `client_integration_json` TEXT)", + "fields": [ + { + "fieldPath": "id", + "columnName": "_id", + "affinity": "INTEGER" + }, + { + "fieldPath": "assistant", + "columnName": "assistant", + "affinity": "INTEGER" + }, + { + "fieldPath": "accountName", + "columnName": "account", + "affinity": "TEXT" + }, + { + "fieldPath": "versionMajor", + "columnName": "version_mayor", + "affinity": "INTEGER" + }, + { + "fieldPath": "versionMinor", + "columnName": "version_minor", + "affinity": "INTEGER" + }, + { + "fieldPath": "versionMicro", + "columnName": "version_micro", + "affinity": "INTEGER" + }, + { + "fieldPath": "versionString", + "columnName": "version_string", + "affinity": "TEXT" + }, + { + "fieldPath": "versionEditor", + "columnName": "version_edition", + "affinity": "TEXT" + }, + { + "fieldPath": "extendedSupport", + "columnName": "extended_support", + "affinity": "INTEGER" + }, + { + "fieldPath": "corePollinterval", + "columnName": "core_pollinterval", + "affinity": "INTEGER" + }, + { + "fieldPath": "sharingApiEnabled", + "columnName": "sharing_api_enabled", + "affinity": "INTEGER" + }, + { + "fieldPath": "sharingPublicEnabled", + "columnName": "sharing_public_enabled", + "affinity": "INTEGER" + }, + { + "fieldPath": "sharingPublicPasswordEnforced", + "columnName": "sharing_public_password_enforced", + "affinity": "INTEGER" + }, + { + "fieldPath": "sharingPublicExpireDateEnabled", + "columnName": "sharing_public_expire_date_enabled", + "affinity": "INTEGER" + }, + { + "fieldPath": "sharingPublicExpireDateDays", + "columnName": "sharing_public_expire_date_days", + "affinity": "INTEGER" + }, + { + "fieldPath": "sharingPublicExpireDateEnforced", + "columnName": "sharing_public_expire_date_enforced", + "affinity": "INTEGER" + }, + { + "fieldPath": "sharingPublicSendMail", + "columnName": "sharing_public_send_mail", + "affinity": "INTEGER" + }, + { + "fieldPath": "sharingPublicUpload", + "columnName": "sharing_public_upload", + "affinity": "INTEGER" + }, + { + "fieldPath": "sharingUserSendMail", + "columnName": "sharing_user_send_mail", + "affinity": "INTEGER" + }, + { + "fieldPath": "sharingResharing", + "columnName": "sharing_resharing", + "affinity": "INTEGER" + }, + { + "fieldPath": "sharingFederationOutgoing", + "columnName": "sharing_federation_outgoing", + "affinity": "INTEGER" + }, + { + "fieldPath": "sharingFederationIncoming", + "columnName": "sharing_federation_incoming", + "affinity": "INTEGER" + }, + { + "fieldPath": "filesBigfilechunking", + "columnName": "files_bigfilechunking", + "affinity": "INTEGER" + }, + { + "fieldPath": "filesUndelete", + "columnName": "files_undelete", + "affinity": "INTEGER" + }, + { + "fieldPath": "filesVersioning", + "columnName": "files_versioning", + "affinity": "INTEGER" + }, + { + "fieldPath": "externalLinks", + "columnName": "external_links", + "affinity": "INTEGER" + }, + { + "fieldPath": "serverName", + "columnName": "server_name", + "affinity": "TEXT" + }, + { + "fieldPath": "serverColor", + "columnName": "server_color", + "affinity": "TEXT" + }, + { + "fieldPath": "serverTextColor", + "columnName": "server_text_color", + "affinity": "TEXT" + }, + { + "fieldPath": "serverElementColor", + "columnName": "server_element_color", + "affinity": "TEXT" + }, + { + "fieldPath": "serverSlogan", + "columnName": "server_slogan", + "affinity": "TEXT" + }, + { + "fieldPath": "serverLogo", + "columnName": "server_logo", + "affinity": "TEXT" + }, + { + "fieldPath": "serverBackgroundUrl", + "columnName": "background_url", + "affinity": "TEXT" + }, + { + "fieldPath": "endToEndEncryption", + "columnName": "end_to_end_encryption", + "affinity": "INTEGER" + }, + { + "fieldPath": "endToEndEncryptionKeysExist", + "columnName": "end_to_end_encryption_keys_exist", + "affinity": "INTEGER" + }, + { + "fieldPath": "endToEndEncryptionApiVersion", + "columnName": "end_to_end_encryption_api_version", + "affinity": "TEXT" + }, + { + "fieldPath": "activity", + "columnName": "activity", + "affinity": "INTEGER" + }, + { + "fieldPath": "serverBackgroundDefault", + "columnName": "background_default", + "affinity": "INTEGER" + }, + { + "fieldPath": "serverBackgroundPlain", + "columnName": "background_plain", + "affinity": "INTEGER" + }, + { + "fieldPath": "richdocument", + "columnName": "richdocument", + "affinity": "INTEGER" + }, + { + "fieldPath": "richdocumentMimetypeList", + "columnName": "richdocument_mimetype_list", + "affinity": "TEXT" + }, + { + "fieldPath": "richdocumentDirectEditing", + "columnName": "richdocument_direct_editing", + "affinity": "INTEGER" + }, + { + "fieldPath": "richdocumentTemplates", + "columnName": "richdocument_direct_templates", + "affinity": "INTEGER" + }, + { + "fieldPath": "richdocumentOptionalMimetypeList", + "columnName": "richdocument_optional_mimetype_list", + "affinity": "TEXT" + }, + { + "fieldPath": "sharingPublicAskForOptionalPassword", + "columnName": "sharing_public_ask_for_optional_password", + "affinity": "INTEGER" + }, + { + "fieldPath": "richdocumentProductName", + "columnName": "richdocument_product_name", + "affinity": "TEXT" + }, + { + "fieldPath": "directEditingEtag", + "columnName": "direct_editing_etag", + "affinity": "TEXT" + }, + { + "fieldPath": "userStatus", + "columnName": "user_status", + "affinity": "INTEGER" + }, + { + "fieldPath": "userStatusSupportsEmoji", + "columnName": "user_status_supports_emoji", + "affinity": "INTEGER" + }, + { + "fieldPath": "etag", + "columnName": "etag", + "affinity": "TEXT" + }, + { + "fieldPath": "filesLockingVersion", + "columnName": "files_locking_version", + "affinity": "TEXT" + }, + { + "fieldPath": "groupfolders", + "columnName": "groupfolders", + "affinity": "INTEGER" + }, + { + "fieldPath": "dropAccount", + "columnName": "drop_account", + "affinity": "INTEGER" + }, + { + "fieldPath": "securityGuard", + "columnName": "security_guard", + "affinity": "INTEGER" + }, + { + "fieldPath": "forbiddenFileNameCharacters", + "columnName": "forbidden_filename_characters", + "affinity": "INTEGER" + }, + { + "fieldPath": "forbiddenFileNames", + "columnName": "forbidden_filenames", + "affinity": "INTEGER" + }, + { + "fieldPath": "forbiddenFileNameExtensions", + "columnName": "forbidden_filename_extensions", + "affinity": "INTEGER" + }, + { + "fieldPath": "forbiddenFilenameBaseNames", + "columnName": "forbidden_filename_basenames", + "affinity": "INTEGER" + }, + { + "fieldPath": "filesDownloadLimit", + "columnName": "files_download_limit", + "affinity": "INTEGER" + }, + { + "fieldPath": "filesDownloadLimitDefault", + "columnName": "files_download_limit_default", + "affinity": "INTEGER" + }, + { + "fieldPath": "recommendation", + "columnName": "recommendation", + "affinity": "INTEGER" + }, + { + "fieldPath": "notesFolderPath", + "columnName": "notes_folder_path", + "affinity": "TEXT" + }, + { + "fieldPath": "defaultPermissions", + "columnName": "default_permissions", + "affinity": "INTEGER" + }, + { + "fieldPath": "userStatusSupportsBusy", + "columnName": "user_status_supports_busy", + "affinity": "INTEGER" + }, + { + "fieldPath": "isWCFEnabled", + "columnName": "windows_compatible_filenames", + "affinity": "INTEGER" + }, + { + "fieldPath": "hasValidSubscription", + "columnName": "has_valid_subscription", + "affinity": "INTEGER" + }, + { + "fieldPath": "clientIntegrationJson", + "columnName": "client_integration_json", + "affinity": "TEXT" + } + ], + "primaryKey": { + "autoGenerate": true, + "columnNames": [ + "_id" + ] + } + }, + { + "tableName": "external_links", + "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`_id` INTEGER PRIMARY KEY AUTOINCREMENT, `icon_url` TEXT, `language` TEXT, `type` INTEGER, `name` TEXT, `url` TEXT, `redirect` INTEGER)", + "fields": [ + { + "fieldPath": "id", + "columnName": "_id", + "affinity": "INTEGER" + }, + { + "fieldPath": "iconUrl", + "columnName": "icon_url", + "affinity": "TEXT" + }, + { + "fieldPath": "language", + "columnName": "language", + "affinity": "TEXT" + }, + { + "fieldPath": "type", + "columnName": "type", + "affinity": "INTEGER" + }, + { + "fieldPath": "name", + "columnName": "name", + "affinity": "TEXT" + }, + { + "fieldPath": "url", + "columnName": "url", + "affinity": "TEXT" + }, + { + "fieldPath": "redirect", + "columnName": "redirect", + "affinity": "INTEGER" + } + ], + "primaryKey": { + "autoGenerate": true, + "columnNames": [ + "_id" + ] + } + }, + { + "tableName": "filelist", + "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`_id` INTEGER PRIMARY KEY AUTOINCREMENT, `filename` TEXT, `encrypted_filename` TEXT, `path` TEXT, `path_decrypted` TEXT, `parent` INTEGER, `created` INTEGER, `modified` INTEGER, `content_type` TEXT, `content_length` INTEGER, `media_path` TEXT, `file_owner` TEXT, `last_sync_date` INTEGER, `last_sync_date_for_data` INTEGER, `modified_at_last_sync_for_data` INTEGER, `etag` TEXT, `etag_on_server` TEXT, `share_by_link` INTEGER, `permissions` TEXT, `remote_id` TEXT, `local_id` INTEGER NOT NULL DEFAULT -1, `update_thumbnail` INTEGER, `is_downloading` INTEGER, `favorite` INTEGER, `hidden` INTEGER, `is_encrypted` INTEGER, `etag_in_conflict` TEXT, `shared_via_users` INTEGER, `mount_type` INTEGER, `has_preview` INTEGER, `unread_comments_count` INTEGER, `owner_id` TEXT, `owner_display_name` TEXT, `note` TEXT, `sharees` TEXT, `rich_workspace` TEXT, `metadata_size` TEXT, `metadata_live_photo` TEXT, `locked` INTEGER, `lock_type` INTEGER, `lock_owner` TEXT, `lock_owner_display_name` TEXT, `lock_owner_editor` TEXT, `lock_timestamp` INTEGER, `lock_timeout` INTEGER, `lock_token` TEXT, `tags` TEXT, `metadata_gps` TEXT, `e2e_counter` INTEGER, `internal_two_way_sync_timestamp` INTEGER, `internal_two_way_sync_result` TEXT, `uploaded` INTEGER)", + "fields": [ + { + "fieldPath": "id", + "columnName": "_id", + "affinity": "INTEGER" + }, + { + "fieldPath": "name", + "columnName": "filename", + "affinity": "TEXT" + }, + { + "fieldPath": "encryptedName", + "columnName": "encrypted_filename", + "affinity": "TEXT" + }, + { + "fieldPath": "path", + "columnName": "path", + "affinity": "TEXT" + }, + { + "fieldPath": "pathDecrypted", + "columnName": "path_decrypted", + "affinity": "TEXT" + }, + { + "fieldPath": "parent", + "columnName": "parent", + "affinity": "INTEGER" + }, + { + "fieldPath": "creation", + "columnName": "created", + "affinity": "INTEGER" + }, + { + "fieldPath": "modified", + "columnName": "modified", + "affinity": "INTEGER" + }, + { + "fieldPath": "contentType", + "columnName": "content_type", + "affinity": "TEXT" + }, + { + "fieldPath": "contentLength", + "columnName": "content_length", + "affinity": "INTEGER" + }, + { + "fieldPath": "storagePath", + "columnName": "media_path", + "affinity": "TEXT" + }, + { + "fieldPath": "accountOwner", + "columnName": "file_owner", + "affinity": "TEXT" + }, + { + "fieldPath": "lastSyncDate", + "columnName": "last_sync_date", + "affinity": "INTEGER" + }, + { + "fieldPath": "lastSyncDateForData", + "columnName": "last_sync_date_for_data", + "affinity": "INTEGER" + }, + { + "fieldPath": "modifiedAtLastSyncForData", + "columnName": "modified_at_last_sync_for_data", + "affinity": "INTEGER" + }, + { + "fieldPath": "etag", + "columnName": "etag", + "affinity": "TEXT" + }, + { + "fieldPath": "etagOnServer", + "columnName": "etag_on_server", + "affinity": "TEXT" + }, + { + "fieldPath": "sharedViaLink", + "columnName": "share_by_link", + "affinity": "INTEGER" + }, + { + "fieldPath": "permissions", + "columnName": "permissions", + "affinity": "TEXT" + }, + { + "fieldPath": "remoteId", + "columnName": "remote_id", + "affinity": "TEXT" + }, + { + "fieldPath": "localId", + "columnName": "local_id", + "affinity": "INTEGER", + "notNull": true, + "defaultValue": "-1" + }, + { + "fieldPath": "updateThumbnail", + "columnName": "update_thumbnail", + "affinity": "INTEGER" + }, + { + "fieldPath": "isDownloading", + "columnName": "is_downloading", + "affinity": "INTEGER" + }, + { + "fieldPath": "favorite", + "columnName": "favorite", + "affinity": "INTEGER" + }, + { + "fieldPath": "hidden", + "columnName": "hidden", + "affinity": "INTEGER" + }, + { + "fieldPath": "isEncrypted", + "columnName": "is_encrypted", + "affinity": "INTEGER" + }, + { + "fieldPath": "etagInConflict", + "columnName": "etag_in_conflict", + "affinity": "TEXT" + }, + { + "fieldPath": "sharedWithSharee", + "columnName": "shared_via_users", + "affinity": "INTEGER" + }, + { + "fieldPath": "mountType", + "columnName": "mount_type", + "affinity": "INTEGER" + }, + { + "fieldPath": "hasPreview", + "columnName": "has_preview", + "affinity": "INTEGER" + }, + { + "fieldPath": "unreadCommentsCount", + "columnName": "unread_comments_count", + "affinity": "INTEGER" + }, + { + "fieldPath": "ownerId", + "columnName": "owner_id", + "affinity": "TEXT" + }, + { + "fieldPath": "ownerDisplayName", + "columnName": "owner_display_name", + "affinity": "TEXT" + }, + { + "fieldPath": "note", + "columnName": "note", + "affinity": "TEXT" + }, + { + "fieldPath": "sharees", + "columnName": "sharees", + "affinity": "TEXT" + }, + { + "fieldPath": "richWorkspace", + "columnName": "rich_workspace", + "affinity": "TEXT" + }, + { + "fieldPath": "metadataSize", + "columnName": "metadata_size", + "affinity": "TEXT" + }, + { + "fieldPath": "metadataLivePhoto", + "columnName": "metadata_live_photo", + "affinity": "TEXT" + }, + { + "fieldPath": "locked", + "columnName": "locked", + "affinity": "INTEGER" + }, + { + "fieldPath": "lockType", + "columnName": "lock_type", + "affinity": "INTEGER" + }, + { + "fieldPath": "lockOwner", + "columnName": "lock_owner", + "affinity": "TEXT" + }, + { + "fieldPath": "lockOwnerDisplayName", + "columnName": "lock_owner_display_name", + "affinity": "TEXT" + }, + { + "fieldPath": "lockOwnerEditor", + "columnName": "lock_owner_editor", + "affinity": "TEXT" + }, + { + "fieldPath": "lockTimestamp", + "columnName": "lock_timestamp", + "affinity": "INTEGER" + }, + { + "fieldPath": "lockTimeout", + "columnName": "lock_timeout", + "affinity": "INTEGER" + }, + { + "fieldPath": "lockToken", + "columnName": "lock_token", + "affinity": "TEXT" + }, + { + "fieldPath": "tags", + "columnName": "tags", + "affinity": "TEXT" + }, + { + "fieldPath": "metadataGPS", + "columnName": "metadata_gps", + "affinity": "TEXT" + }, + { + "fieldPath": "e2eCounter", + "columnName": "e2e_counter", + "affinity": "INTEGER" + }, + { + "fieldPath": "internalTwoWaySync", + "columnName": "internal_two_way_sync_timestamp", + "affinity": "INTEGER" + }, + { + "fieldPath": "internalTwoWaySyncResult", + "columnName": "internal_two_way_sync_result", + "affinity": "TEXT" + }, + { + "fieldPath": "uploaded", + "columnName": "uploaded", + "affinity": "INTEGER" + } + ], + "primaryKey": { + "autoGenerate": true, + "columnNames": [ + "_id" + ] + } + }, + { + "tableName": "filesystem", + "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`_id` INTEGER PRIMARY KEY AUTOINCREMENT, `local_path` TEXT, `is_folder` INTEGER, `found_at` INTEGER, `upload_triggered` INTEGER, `syncedfolder_id` TEXT, `crc32` TEXT, `modified_at` INTEGER)", + "fields": [ + { + "fieldPath": "id", + "columnName": "_id", + "affinity": "INTEGER" + }, + { + "fieldPath": "localPath", + "columnName": "local_path", + "affinity": "TEXT" + }, + { + "fieldPath": "fileIsFolder", + "columnName": "is_folder", + "affinity": "INTEGER" + }, + { + "fieldPath": "fileFoundRecently", + "columnName": "found_at", + "affinity": "INTEGER" + }, + { + "fieldPath": "fileSentForUpload", + "columnName": "upload_triggered", + "affinity": "INTEGER" + }, + { + "fieldPath": "syncedFolderId", + "columnName": "syncedfolder_id", + "affinity": "TEXT" + }, + { + "fieldPath": "crc32", + "columnName": "crc32", + "affinity": "TEXT" + }, + { + "fieldPath": "fileModified", + "columnName": "modified_at", + "affinity": "INTEGER" + } + ], + "primaryKey": { + "autoGenerate": true, + "columnNames": [ + "_id" + ] + } + }, + { + "tableName": "ocshares", + "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`_id` INTEGER PRIMARY KEY AUTOINCREMENT, `file_source` INTEGER, `item_source` INTEGER, `share_type` INTEGER, `shate_with` TEXT, `path` TEXT, `permissions` INTEGER, `shared_date` INTEGER, `expiration_date` INTEGER, `token` TEXT, `shared_with_display_name` TEXT, `is_directory` INTEGER, `user_id` TEXT, `id_remote_shared` INTEGER, `owner_share` TEXT, `is_password_protected` INTEGER, `note` TEXT, `hide_download` INTEGER, `share_link` TEXT, `share_label` TEXT, `download_limit_limit` INTEGER, `download_limit_count` INTEGER, `attributes` TEXT)", + "fields": [ + { + "fieldPath": "id", + "columnName": "_id", + "affinity": "INTEGER" + }, + { + "fieldPath": "fileSource", + "columnName": "file_source", + "affinity": "INTEGER" + }, + { + "fieldPath": "itemSource", + "columnName": "item_source", + "affinity": "INTEGER" + }, + { + "fieldPath": "shareType", + "columnName": "share_type", + "affinity": "INTEGER" + }, + { + "fieldPath": "shareWith", + "columnName": "shate_with", + "affinity": "TEXT" + }, + { + "fieldPath": "path", + "columnName": "path", + "affinity": "TEXT" + }, + { + "fieldPath": "permissions", + "columnName": "permissions", + "affinity": "INTEGER" + }, + { + "fieldPath": "sharedDate", + "columnName": "shared_date", + "affinity": "INTEGER" + }, + { + "fieldPath": "expirationDate", + "columnName": "expiration_date", + "affinity": "INTEGER" + }, + { + "fieldPath": "token", + "columnName": "token", + "affinity": "TEXT" + }, + { + "fieldPath": "shareWithDisplayName", + "columnName": "shared_with_display_name", + "affinity": "TEXT" + }, + { + "fieldPath": "isDirectory", + "columnName": "is_directory", + "affinity": "INTEGER" + }, + { + "fieldPath": "userId", + "columnName": "user_id", + "affinity": "TEXT" + }, + { + "fieldPath": "idRemoteShared", + "columnName": "id_remote_shared", + "affinity": "INTEGER" + }, + { + "fieldPath": "accountOwner", + "columnName": "owner_share", + "affinity": "TEXT" + }, + { + "fieldPath": "isPasswordProtected", + "columnName": "is_password_protected", + "affinity": "INTEGER" + }, + { + "fieldPath": "note", + "columnName": "note", + "affinity": "TEXT" + }, + { + "fieldPath": "hideDownload", + "columnName": "hide_download", + "affinity": "INTEGER" + }, + { + "fieldPath": "shareLink", + "columnName": "share_link", + "affinity": "TEXT" + }, + { + "fieldPath": "shareLabel", + "columnName": "share_label", + "affinity": "TEXT" + }, + { + "fieldPath": "downloadLimitLimit", + "columnName": "download_limit_limit", + "affinity": "INTEGER" + }, + { + "fieldPath": "downloadLimitCount", + "columnName": "download_limit_count", + "affinity": "INTEGER" + }, + { + "fieldPath": "attributes", + "columnName": "attributes", + "affinity": "TEXT" + } + ], + "primaryKey": { + "autoGenerate": true, + "columnNames": [ + "_id" + ] + } + }, + { + "tableName": "synced_folders", + "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`_id` INTEGER PRIMARY KEY AUTOINCREMENT, `local_path` TEXT, `remote_path` TEXT, `wifi_only` INTEGER, `charging_only` INTEGER, `existing` INTEGER, `enabled` INTEGER, `enabled_timestamp_ms` INTEGER, `subfolder_by_date` INTEGER, `account` TEXT, `upload_option` INTEGER, `name_collision_policy` INTEGER, `type` INTEGER, `hidden` INTEGER, `sub_folder_rule` INTEGER, `exclude_hidden` INTEGER, `last_scan_timestamp_ms` INTEGER)", + "fields": [ + { + "fieldPath": "id", + "columnName": "_id", + "affinity": "INTEGER" + }, + { + "fieldPath": "localPath", + "columnName": "local_path", + "affinity": "TEXT" + }, + { + "fieldPath": "remotePath", + "columnName": "remote_path", + "affinity": "TEXT" + }, + { + "fieldPath": "wifiOnly", + "columnName": "wifi_only", + "affinity": "INTEGER" + }, + { + "fieldPath": "chargingOnly", + "columnName": "charging_only", + "affinity": "INTEGER" + }, + { + "fieldPath": "existing", + "columnName": "existing", + "affinity": "INTEGER" + }, + { + "fieldPath": "enabled", + "columnName": "enabled", + "affinity": "INTEGER" + }, + { + "fieldPath": "enabledTimestampMs", + "columnName": "enabled_timestamp_ms", + "affinity": "INTEGER" + }, + { + "fieldPath": "subfolderByDate", + "columnName": "subfolder_by_date", + "affinity": "INTEGER" + }, + { + "fieldPath": "account", + "columnName": "account", + "affinity": "TEXT" + }, + { + "fieldPath": "uploadAction", + "columnName": "upload_option", + "affinity": "INTEGER" + }, + { + "fieldPath": "nameCollisionPolicy", + "columnName": "name_collision_policy", + "affinity": "INTEGER" + }, + { + "fieldPath": "type", + "columnName": "type", + "affinity": "INTEGER" + }, + { + "fieldPath": "hidden", + "columnName": "hidden", + "affinity": "INTEGER" + }, + { + "fieldPath": "subFolderRule", + "columnName": "sub_folder_rule", + "affinity": "INTEGER" + }, + { + "fieldPath": "excludeHidden", + "columnName": "exclude_hidden", + "affinity": "INTEGER" + }, + { + "fieldPath": "lastScanTimestampMs", + "columnName": "last_scan_timestamp_ms", + "affinity": "INTEGER" + } + ], + "primaryKey": { + "autoGenerate": true, + "columnNames": [ + "_id" + ] + } + }, + { + "tableName": "list_of_uploads", + "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`_id` INTEGER PRIMARY KEY AUTOINCREMENT, `local_path` TEXT, `remote_path` TEXT, `account_name` TEXT, `file_size` INTEGER, `status` INTEGER, `local_behaviour` INTEGER, `upload_time` INTEGER, `name_collision_policy` INTEGER, `is_create_remote_folder` INTEGER, `upload_end_timestamp` INTEGER, `upload_end_timestamp_long` INTEGER, `last_result` INTEGER, `is_while_charging_only` INTEGER, `is_wifi_only` INTEGER, `created_by` INTEGER, `folder_unlock_token` TEXT)", + "fields": [ + { + "fieldPath": "id", + "columnName": "_id", + "affinity": "INTEGER" + }, + { + "fieldPath": "localPath", + "columnName": "local_path", + "affinity": "TEXT" + }, + { + "fieldPath": "remotePath", + "columnName": "remote_path", + "affinity": "TEXT" + }, + { + "fieldPath": "accountName", + "columnName": "account_name", + "affinity": "TEXT" + }, + { + "fieldPath": "fileSize", + "columnName": "file_size", + "affinity": "INTEGER" + }, + { + "fieldPath": "status", + "columnName": "status", + "affinity": "INTEGER" + }, + { + "fieldPath": "localBehaviour", + "columnName": "local_behaviour", + "affinity": "INTEGER" + }, + { + "fieldPath": "uploadTime", + "columnName": "upload_time", + "affinity": "INTEGER" + }, + { + "fieldPath": "nameCollisionPolicy", + "columnName": "name_collision_policy", + "affinity": "INTEGER" + }, + { + "fieldPath": "isCreateRemoteFolder", + "columnName": "is_create_remote_folder", + "affinity": "INTEGER" + }, + { + "fieldPath": "uploadEndTimestamp", + "columnName": "upload_end_timestamp", + "affinity": "INTEGER" + }, + { + "fieldPath": "uploadEndTimestampLong", + "columnName": "upload_end_timestamp_long", + "affinity": "INTEGER" + }, + { + "fieldPath": "lastResult", + "columnName": "last_result", + "affinity": "INTEGER" + }, + { + "fieldPath": "isWhileChargingOnly", + "columnName": "is_while_charging_only", + "affinity": "INTEGER" + }, + { + "fieldPath": "isWifiOnly", + "columnName": "is_wifi_only", + "affinity": "INTEGER" + }, + { + "fieldPath": "createdBy", + "columnName": "created_by", + "affinity": "INTEGER" + }, + { + "fieldPath": "folderUnlockToken", + "columnName": "folder_unlock_token", + "affinity": "TEXT" + } + ], + "primaryKey": { + "autoGenerate": true, + "columnNames": [ + "_id" + ] + } + }, + { + "tableName": "virtual", + "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`_id` INTEGER PRIMARY KEY AUTOINCREMENT, `type` TEXT, `ocfile_id` INTEGER)", + "fields": [ + { + "fieldPath": "id", + "columnName": "_id", + "affinity": "INTEGER" + }, + { + "fieldPath": "type", + "columnName": "type", + "affinity": "TEXT" + }, + { + "fieldPath": "ocFileId", + "columnName": "ocfile_id", + "affinity": "INTEGER" + } + ], + "primaryKey": { + "autoGenerate": true, + "columnNames": [ + "_id" + ] + } + }, + { + "tableName": "offline_operations", + "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`_id` INTEGER PRIMARY KEY AUTOINCREMENT, `offline_operations_parent_oc_file_id` INTEGER, `offline_operations_path` TEXT, `offline_operations_type` TEXT, `offline_operations_file_name` TEXT, `offline_operations_created_at` INTEGER, `offline_operations_modified_at` INTEGER)", + "fields": [ + { + "fieldPath": "id", + "columnName": "_id", + "affinity": "INTEGER" + }, + { + "fieldPath": "parentOCFileId", + "columnName": "offline_operations_parent_oc_file_id", + "affinity": "INTEGER" + }, + { + "fieldPath": "path", + "columnName": "offline_operations_path", + "affinity": "TEXT" + }, + { + "fieldPath": "type", + "columnName": "offline_operations_type", + "affinity": "TEXT" + }, + { + "fieldPath": "filename", + "columnName": "offline_operations_file_name", + "affinity": "TEXT" + }, + { + "fieldPath": "createdAt", + "columnName": "offline_operations_created_at", + "affinity": "INTEGER" + }, + { + "fieldPath": "modifiedAt", + "columnName": "offline_operations_modified_at", + "affinity": "INTEGER" + } + ], + "primaryKey": { + "autoGenerate": true, + "columnNames": [ + "_id" + ] + } + }, + { + "tableName": "recommended_files", + "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`_id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `name` TEXT NOT NULL, `directory` TEXT NOT NULL, `extension` TEXT NOT NULL, `mime_type` TEXT NOT NULL, `has_preview` INTEGER NOT NULL, `reason` TEXT NOT NULL, `timestamp` INTEGER NOT NULL, `account_name` TEXT)", + "fields": [ + { + "fieldPath": "id", + "columnName": "_id", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "name", + "columnName": "name", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "directory", + "columnName": "directory", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "extension", + "columnName": "extension", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "mimeType", + "columnName": "mime_type", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "hasPreview", + "columnName": "has_preview", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "reason", + "columnName": "reason", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "timestamp", + "columnName": "timestamp", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "accountName", + "columnName": "account_name", + "affinity": "TEXT" + } + ], + "primaryKey": { + "autoGenerate": true, + "columnNames": [ + "_id" + ] + } + }, + { + "tableName": "assistant", + "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `accountName` TEXT, `type` TEXT, `status` TEXT, `userId` TEXT, `appId` TEXT, `input` TEXT, `output` TEXT, `completionExpectedAt` INTEGER, `progress` INTEGER, `lastUpdated` INTEGER, `scheduledAt` INTEGER, `endedAt` INTEGER)", + "fields": [ + { + "fieldPath": "id", + "columnName": "id", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "accountName", + "columnName": "accountName", + "affinity": "TEXT" + }, + { + "fieldPath": "type", + "columnName": "type", + "affinity": "TEXT" + }, + { + "fieldPath": "status", + "columnName": "status", + "affinity": "TEXT" + }, + { + "fieldPath": "userId", + "columnName": "userId", + "affinity": "TEXT" + }, + { + "fieldPath": "appId", + "columnName": "appId", + "affinity": "TEXT" + }, + { + "fieldPath": "input", + "columnName": "input", + "affinity": "TEXT" + }, + { + "fieldPath": "output", + "columnName": "output", + "affinity": "TEXT" + }, + { + "fieldPath": "completionExpectedAt", + "columnName": "completionExpectedAt", + "affinity": "INTEGER" + }, + { + "fieldPath": "progress", + "columnName": "progress", + "affinity": "INTEGER" + }, + { + "fieldPath": "lastUpdated", + "columnName": "lastUpdated", + "affinity": "INTEGER" + }, + { + "fieldPath": "scheduledAt", + "columnName": "scheduledAt", + "affinity": "INTEGER" + }, + { + "fieldPath": "endedAt", + "columnName": "endedAt", + "affinity": "INTEGER" + } + ], + "primaryKey": { + "autoGenerate": true, + "columnNames": [ + "id" + ] + } + } + ], + "setupQueries": [ + "CREATE TABLE IF NOT EXISTS room_master_table (id INTEGER PRIMARY KEY,identity_hash TEXT)", + "INSERT OR REPLACE INTO room_master_table (id,identity_hash) VALUES(42, '02ca435c31a732cd82a36717518c37b3')" + ] + } +} \ No newline at end of file diff --git a/app/src/main/java/com/nextcloud/client/database/entity/UploadEntity.kt b/app/src/main/java/com/nextcloud/client/database/entity/UploadEntity.kt index dc8be81183d0..7322a20e50a3 100644 --- a/app/src/main/java/com/nextcloud/client/database/entity/UploadEntity.kt +++ b/app/src/main/java/com/nextcloud/client/database/entity/UploadEntity.kt @@ -43,8 +43,13 @@ data class UploadEntity( val nameCollisionPolicy: Int?, @ColumnInfo(name = ProviderTableMeta.UPLOADS_IS_CREATE_REMOTE_FOLDER) val isCreateRemoteFolder: Int?, + + // do not use integer value of upload end timestamp, instead use long version of it @ColumnInfo(name = ProviderTableMeta.UPLOADS_UPLOAD_END_TIMESTAMP) val uploadEndTimestamp: Int?, + + @ColumnInfo(name = ProviderTableMeta.UPLOADS_UPLOAD_END_TIMESTAMP_LONG) + val uploadEndTimestampLong: Long?, @ColumnInfo(name = ProviderTableMeta.UPLOADS_LAST_RESULT) val lastResult: Int?, @ColumnInfo(name = ProviderTableMeta.UPLOADS_IS_WHILE_CHARGING_ONLY) @@ -75,7 +80,7 @@ fun UploadEntity.toOCUpload(capability: OCCapability? = null): OCUpload? { localBehaviour?.let { upload.localAction = it } nameCollisionPolicy?.let { upload.nameCollisionPolicy = NameCollisionPolicy.deserialize(it) } isCreateRemoteFolder?.let { upload.isCreateRemoteFolder = it == 1 } - uploadEndTimestamp?.let { upload.uploadEndTimestamp = it.toLong() } + uploadEndTimestampLong?.let { upload.uploadEndTimestamp = it } lastResult?.let { upload.lastResult = UploadResult.fromValue(it) } createdBy?.let { upload.createdBy = it } isWifiOnly?.let { upload.isUseWifiOnly = it == 1 } @@ -103,7 +108,8 @@ fun OCUpload.toUploadEntity(): UploadEntity { localBehaviour = localAction, nameCollisionPolicy = nameCollisionPolicy?.serialize(), isCreateRemoteFolder = if (isCreateRemoteFolder) 1 else 0, - uploadEndTimestamp = uploadEndTimestamp.toInt(), + uploadEndTimestamp = 0, + uploadEndTimestampLong = uploadEndTimestamp, lastResult = lastResult?.value, createdBy = createdBy, isWifiOnly = if (isUseWifiOnly) 1 else 0, diff --git a/app/src/main/java/com/owncloud/android/datamodel/UploadsStorageManager.java b/app/src/main/java/com/owncloud/android/datamodel/UploadsStorageManager.java index b68ad0c0ec7a..b339655b438c 100644 --- a/app/src/main/java/com/owncloud/android/datamodel/UploadsStorageManager.java +++ b/app/src/main/java/com/owncloud/android/datamodel/UploadsStorageManager.java @@ -118,7 +118,9 @@ public synchronized int updateUpload(OCUpload ocUpload) { cv.put(ProviderTableMeta.UPLOADS_ACCOUNT_NAME, ocUpload.getAccountName()); cv.put(ProviderTableMeta.UPLOADS_STATUS, ocUpload.getUploadStatus().value); cv.put(ProviderTableMeta.UPLOADS_LAST_RESULT, ocUpload.getLastResult().getValue()); - cv.put(ProviderTableMeta.UPLOADS_UPLOAD_END_TIMESTAMP, ocUpload.getUploadEndTimestamp()); + + long uploadEndTimestamp = ocUpload.getUploadEndTimestamp(); + cv.put(ProviderTableMeta.UPLOADS_UPLOAD_END_TIMESTAMP_LONG, uploadEndTimestamp); cv.put(ProviderTableMeta.UPLOADS_FILE_SIZE, ocUpload.getFileSize()); cv.put(ProviderTableMeta.UPLOADS_FOLDER_UNLOCK_TOKEN, ocUpload.getFolderUnlockToken()); @@ -465,7 +467,7 @@ private OCUpload createOCUploadFromCursor(Cursor c) { upload.setCreateRemoteFolder(c.getInt( c.getColumnIndexOrThrow(ProviderTableMeta.UPLOADS_IS_CREATE_REMOTE_FOLDER)) == 1); - final var uploadEndTimestampColumnIndex= c.getColumnIndex(ProviderTableMeta.UPLOADS_UPLOAD_END_TIMESTAMP); + final var uploadEndTimestampColumnIndex= c.getColumnIndex(ProviderTableMeta.UPLOADS_UPLOAD_END_TIMESTAMP_LONG); if (uploadEndTimestampColumnIndex > -1) { final var uploadEndTimestamp = c.getLong(uploadEndTimestampColumnIndex); if (uploadEndTimestamp > 0) { diff --git a/app/src/main/java/com/owncloud/android/db/ProviderMeta.java b/app/src/main/java/com/owncloud/android/db/ProviderMeta.java index 46905d69231d..60b2db87aa3c 100644 --- a/app/src/main/java/com/owncloud/android/db/ProviderMeta.java +++ b/app/src/main/java/com/owncloud/android/db/ProviderMeta.java @@ -304,6 +304,8 @@ static public class ProviderTableMeta implements BaseColumns { public static final String UPLOADS_NAME_COLLISION_POLICY = "name_collision_policy"; public static final String UPLOADS_IS_CREATE_REMOTE_FOLDER = "is_create_remote_folder"; public static final String UPLOADS_UPLOAD_END_TIMESTAMP = "upload_end_timestamp"; + public static final String UPLOADS_UPLOAD_END_TIMESTAMP_LONG = "upload_end_timestamp_long"; + public static final String UPLOADS_LAST_RESULT = "last_result"; public static final String UPLOADS_CREATED_BY = "created_by"; public static final String UPLOADS_DEFAULT_SORT_ORDER = ProviderTableMeta._ID + " collate nocase desc"; diff --git a/app/src/main/java/com/owncloud/android/ui/adapter/UploadListAdapter.java b/app/src/main/java/com/owncloud/android/ui/adapter/UploadListAdapter.java index c40b15c68076..4d8e4164cbdf 100755 --- a/app/src/main/java/com/owncloud/android/ui/adapter/UploadListAdapter.java +++ b/app/src/main/java/com/owncloud/android/ui/adapter/UploadListAdapter.java @@ -359,19 +359,28 @@ public void onBindViewHolder(SectionedViewHolder holder, int section, int relati // remote path to parent folder itemViewHolder.binding.uploadRemotePath.setText(new File(item.getRemotePath()).getParent()); + long updateTime = item.getUploadEndTimestamp(); + // file size if (item.getFileSize() != 0) { - itemViewHolder.binding.uploadFileSize.setText(String.format("%s, ", - DisplayUtils.bytesToHumanReadable(item.getFileSize()))); + String fileSizeFormat = "%s "; + + // we have valid update time so we can show the upload date + if (updateTime > 0) { + fileSizeFormat = "%s, "; + } + + String fileSizeInBytes = DisplayUtils.bytesToHumanReadable(item.getFileSize()); + String uploadFileSize = String.format(fileSizeFormat, fileSizeInBytes); + itemViewHolder.binding.uploadFileSize.setText(uploadFileSize); } else { itemViewHolder.binding.uploadFileSize.setText(""); } // upload date - long updateTime = item.getUploadEndTimestamp(); - boolean showUploadDate = item.getUploadStatus() == UploadStatus.UPLOAD_SUCCEEDED && item.getLastResult() == UploadResult.UPLOADED; + boolean showUploadDate = updateTime > 0 && item.getUploadStatus() == UploadStatus.UPLOAD_SUCCEEDED && item.getLastResult() == UploadResult.UPLOADED; itemViewHolder.binding.uploadDate.setVisibility(showUploadDate ? View.VISIBLE : View.GONE); - if (showUploadDate && updateTime > 0) { + if (showUploadDate) { CharSequence dateString = DisplayUtils.getRelativeDateTimeString(parentActivity, updateTime, DateUtils.SECOND_IN_MILLIS, From 61f648baebf47529a85b4de6a7d842ea21ca69cf Mon Sep 17 00:00:00 2001 From: alperozturk96 Date: Mon, 26 Jan 2026 11:32:29 +0100 Subject: [PATCH 177/216] fix db version Signed-off-by: alperozturk96 --- .../{98.json => 97.json} | 13 ++++--------- .../nextcloud/client/database/NextcloudDatabase.kt | 3 ++- .../java/com/owncloud/android/db/ProviderMeta.java | 2 +- 3 files changed, 7 insertions(+), 11 deletions(-) rename app/schemas/com.nextcloud.client.database.NextcloudDatabase/{98.json => 97.json} (99%) diff --git a/app/schemas/com.nextcloud.client.database.NextcloudDatabase/98.json b/app/schemas/com.nextcloud.client.database.NextcloudDatabase/97.json similarity index 99% rename from app/schemas/com.nextcloud.client.database.NextcloudDatabase/98.json rename to app/schemas/com.nextcloud.client.database.NextcloudDatabase/97.json index ff3d56813529..f660a6465ac3 100644 --- a/app/schemas/com.nextcloud.client.database.NextcloudDatabase/98.json +++ b/app/schemas/com.nextcloud.client.database.NextcloudDatabase/97.json @@ -1,8 +1,8 @@ { "formatVersion": 1, "database": { - "version": 98, - "identityHash": "02ca435c31a732cd82a36717518c37b3", + "version": 97, + "identityHash": "41e022924f22a038e9107590342e6112", "entities": [ { "tableName": "arbitrary_data", @@ -38,7 +38,7 @@ }, { "tableName": "capabilities", - "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`_id` INTEGER PRIMARY KEY AUTOINCREMENT, `assistant` INTEGER, `account` TEXT, `version_mayor` INTEGER, `version_minor` INTEGER, `version_micro` INTEGER, `version_string` TEXT, `version_edition` TEXT, `extended_support` INTEGER, `core_pollinterval` INTEGER, `sharing_api_enabled` INTEGER, `sharing_public_enabled` INTEGER, `sharing_public_password_enforced` INTEGER, `sharing_public_expire_date_enabled` INTEGER, `sharing_public_expire_date_days` INTEGER, `sharing_public_expire_date_enforced` INTEGER, `sharing_public_send_mail` INTEGER, `sharing_public_upload` INTEGER, `sharing_user_send_mail` INTEGER, `sharing_resharing` INTEGER, `sharing_federation_outgoing` INTEGER, `sharing_federation_incoming` INTEGER, `files_bigfilechunking` INTEGER, `files_undelete` INTEGER, `files_versioning` INTEGER, `external_links` INTEGER, `server_name` TEXT, `server_color` TEXT, `server_text_color` TEXT, `server_element_color` TEXT, `server_slogan` TEXT, `server_logo` TEXT, `background_url` TEXT, `end_to_end_encryption` INTEGER, `end_to_end_encryption_keys_exist` INTEGER, `end_to_end_encryption_api_version` TEXT, `activity` INTEGER, `background_default` INTEGER, `background_plain` INTEGER, `richdocument` INTEGER, `richdocument_mimetype_list` TEXT, `richdocument_direct_editing` INTEGER, `richdocument_direct_templates` INTEGER, `richdocument_optional_mimetype_list` TEXT, `sharing_public_ask_for_optional_password` INTEGER, `richdocument_product_name` TEXT, `direct_editing_etag` TEXT, `user_status` INTEGER, `user_status_supports_emoji` INTEGER, `etag` TEXT, `files_locking_version` TEXT, `groupfolders` INTEGER, `drop_account` INTEGER, `security_guard` INTEGER, `forbidden_filename_characters` INTEGER, `forbidden_filenames` INTEGER, `forbidden_filename_extensions` INTEGER, `forbidden_filename_basenames` INTEGER, `files_download_limit` INTEGER, `files_download_limit_default` INTEGER, `recommendation` INTEGER, `notes_folder_path` TEXT, `default_permissions` INTEGER, `user_status_supports_busy` INTEGER, `windows_compatible_filenames` INTEGER, `has_valid_subscription` INTEGER, `client_integration_json` TEXT)", + "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`_id` INTEGER PRIMARY KEY AUTOINCREMENT, `assistant` INTEGER, `account` TEXT, `version_mayor` INTEGER, `version_minor` INTEGER, `version_micro` INTEGER, `version_string` TEXT, `version_edition` TEXT, `extended_support` INTEGER, `core_pollinterval` INTEGER, `sharing_api_enabled` INTEGER, `sharing_public_enabled` INTEGER, `sharing_public_password_enforced` INTEGER, `sharing_public_expire_date_enabled` INTEGER, `sharing_public_expire_date_days` INTEGER, `sharing_public_expire_date_enforced` INTEGER, `sharing_public_send_mail` INTEGER, `sharing_public_upload` INTEGER, `sharing_user_send_mail` INTEGER, `sharing_resharing` INTEGER, `sharing_federation_outgoing` INTEGER, `sharing_federation_incoming` INTEGER, `files_bigfilechunking` INTEGER, `files_undelete` INTEGER, `files_versioning` INTEGER, `external_links` INTEGER, `server_name` TEXT, `server_color` TEXT, `server_text_color` TEXT, `server_element_color` TEXT, `server_slogan` TEXT, `server_logo` TEXT, `background_url` TEXT, `end_to_end_encryption` INTEGER, `end_to_end_encryption_keys_exist` INTEGER, `end_to_end_encryption_api_version` TEXT, `activity` INTEGER, `background_default` INTEGER, `background_plain` INTEGER, `richdocument` INTEGER, `richdocument_mimetype_list` TEXT, `richdocument_direct_editing` INTEGER, `richdocument_direct_templates` INTEGER, `richdocument_optional_mimetype_list` TEXT, `sharing_public_ask_for_optional_password` INTEGER, `richdocument_product_name` TEXT, `direct_editing_etag` TEXT, `user_status` INTEGER, `user_status_supports_emoji` INTEGER, `etag` TEXT, `files_locking_version` TEXT, `groupfolders` INTEGER, `drop_account` INTEGER, `security_guard` INTEGER, `forbidden_filename_characters` INTEGER, `forbidden_filenames` INTEGER, `forbidden_filename_extensions` INTEGER, `forbidden_filename_basenames` INTEGER, `files_download_limit` INTEGER, `files_download_limit_default` INTEGER, `recommendation` INTEGER, `notes_folder_path` TEXT, `default_permissions` INTEGER, `user_status_supports_busy` INTEGER, `windows_compatible_filenames` INTEGER, `has_valid_subscription` INTEGER)", "fields": [ { "fieldPath": "id", @@ -369,11 +369,6 @@ "fieldPath": "hasValidSubscription", "columnName": "has_valid_subscription", "affinity": "INTEGER" - }, - { - "fieldPath": "clientIntegrationJson", - "columnName": "client_integration_json", - "affinity": "TEXT" } ], "primaryKey": { @@ -1297,7 +1292,7 @@ ], "setupQueries": [ "CREATE TABLE IF NOT EXISTS room_master_table (id INTEGER PRIMARY KEY,identity_hash TEXT)", - "INSERT OR REPLACE INTO room_master_table (id,identity_hash) VALUES(42, '02ca435c31a732cd82a36717518c37b3')" + "INSERT OR REPLACE INTO room_master_table (id,identity_hash) VALUES(42, '41e022924f22a038e9107590342e6112')" ] } } \ No newline at end of file diff --git a/app/src/main/java/com/nextcloud/client/database/NextcloudDatabase.kt b/app/src/main/java/com/nextcloud/client/database/NextcloudDatabase.kt index a5bafa686668..d14dd9234ff6 100644 --- a/app/src/main/java/com/nextcloud/client/database/NextcloudDatabase.kt +++ b/app/src/main/java/com/nextcloud/client/database/NextcloudDatabase.kt @@ -91,7 +91,8 @@ import com.owncloud.android.db.ProviderMeta AutoMigration(from = 92, to = 93, spec = DatabaseMigrationUtil.ResetCapabilitiesPostMigration::class), AutoMigration(from = 93, to = 94, spec = DatabaseMigrationUtil.ResetCapabilitiesPostMigration::class), AutoMigration(from = 94, to = 95, spec = DatabaseMigrationUtil.ResetCapabilitiesPostMigration::class), - AutoMigration(from = 95, to = 96) + AutoMigration(from = 95, to = 96), + AutoMigration(from = 96, to = 97), ], exportSchema = true ) diff --git a/app/src/main/java/com/owncloud/android/db/ProviderMeta.java b/app/src/main/java/com/owncloud/android/db/ProviderMeta.java index 60b2db87aa3c..1810fc469cfe 100644 --- a/app/src/main/java/com/owncloud/android/db/ProviderMeta.java +++ b/app/src/main/java/com/owncloud/android/db/ProviderMeta.java @@ -23,7 +23,7 @@ */ public class ProviderMeta { public static final String DB_NAME = "filelist"; - public static final int DB_VERSION = 96; + public static final int DB_VERSION = 97; private ProviderMeta() { // No instance From f4182fd25ea434d43b7fba1f58f095cdd5517317 Mon Sep 17 00:00:00 2001 From: alperozturk96 Date: Fri, 16 Jan 2026 12:05:17 +0100 Subject: [PATCH 178/216] fix(tabs-list-mode): layout switch Signed-off-by: alperozturk96 --- .../preferences/AppPreferencesImpl.java | 20 ++++--- .../android/ui/activity/DrawerActivity.java | 7 ++- .../ui/activity/FileDisplayActivity.kt | 1 - .../ui/fragment/ExtendedListFragment.kt | 8 ++- .../ui/fragment/LocalFileListFragment.java | 4 +- .../ui/fragment/OCFileListFragment.java | 52 +++++++++++-------- 6 files changed, 56 insertions(+), 36 deletions(-) diff --git a/app/src/main/java/com/nextcloud/client/preferences/AppPreferencesImpl.java b/app/src/main/java/com/nextcloud/client/preferences/AppPreferencesImpl.java index 3d6330923ec6..682e211fcd5a 100644 --- a/app/src/main/java/com/nextcloud/client/preferences/AppPreferencesImpl.java +++ b/app/src/main/java/com/nextcloud/client/preferences/AppPreferencesImpl.java @@ -655,20 +655,26 @@ public long getPhotoSearchTimestamp() { } /** - * Get preference value for a folder. If folder is not set itself, it finds an ancestor that is set. + * Retrieves a preference value for a specific folder. + *

+ * If the folder itself does not have the preference set, the method searches up its ancestor hierarchy + * until a value is found. If no value is found in any ancestor, the provided {@code defaultValue} is returned. + *

+ * Anonymous users or {@code null} folders will always return the {@code defaultValue}. * - * @param context Context object. - * @param preferenceName Name of the preference to lookup. - * @param folder Folder. - * @param defaultValue Fallback value in case no ancestor is set. - * @return Preference value + * @param context The Android context. + * @param user The user for whom the preference is queried. + * @param preferenceName The name/key of the preference to look up. + * @param folder The folder to check. + * @param defaultValue The value to return if no preference is set in the folder hierarchy. + * @return The preference value for the folder, or {@code defaultValue} if none is set. */ private static String getFolderPreference(final Context context, final User user, final String preferenceName, final OCFile folder, final String defaultValue) { - if (user.isAnonymous()) { + if (user.isAnonymous() || folder == null) { return defaultValue; } diff --git a/app/src/main/java/com/owncloud/android/ui/activity/DrawerActivity.java b/app/src/main/java/com/owncloud/android/ui/activity/DrawerActivity.java index f26047d581a3..c8dc3a114b21 100644 --- a/app/src/main/java/com/owncloud/android/ui/activity/DrawerActivity.java +++ b/app/src/main/java/com/owncloud/android/ui/activity/DrawerActivity.java @@ -545,6 +545,8 @@ private void onNavigationItemClicked(final MenuItem menuItem) { } closeDrawer(); + setupHomeSearchToolbarWithSortAndListButtons(); + updateActionBarTitleAndHomeButton(null); } else if (itemId == R.id.nav_favorites) { openFavoritesTab(); } else if (itemId == R.id.nav_gallery) { @@ -618,6 +620,8 @@ private void handleBottomNavigationViewClicks() { fda.browseToRoot(); } EventBus.getDefault().post(new ChangeMenuEvent()); + setupHomeSearchToolbarWithSortAndListButtons(); + updateActionBarTitleAndHomeButton(null); } else if (menuItemId == R.id.nav_favorites) { openFavoritesTab(); } else if (menuItemId == R.id.nav_assistant && !(this instanceof ComposeActivity)) { @@ -692,8 +696,7 @@ private void resetFileDepth() { } } - protected void openSharedTab() { - resetFileDepth(); + private void openSharedTab() { resetOnlyPersonalAndOnDevice(); SearchEvent searchEvent = new SearchEvent("", SearchRemoteOperation.SearchType.SHARED_FILTER); launchActivityForSearch(searchEvent, R.id.nav_shared); diff --git a/app/src/main/java/com/owncloud/android/ui/activity/FileDisplayActivity.kt b/app/src/main/java/com/owncloud/android/ui/activity/FileDisplayActivity.kt index f973795ebf23..2fa70a55eb61 100644 --- a/app/src/main/java/com/owncloud/android/ui/activity/FileDisplayActivity.kt +++ b/app/src/main/java/com/owncloud/android/ui/activity/FileDisplayActivity.kt @@ -2764,7 +2764,6 @@ class FileDisplayActivity : listOfFilesFragment?.setCurrentSearchType(event) updateActionBarTitleAndHomeButton(null) - // listOfFilesFragment?.setActionBarTitle() } @Subscribe(threadMode = ThreadMode.MAIN) diff --git a/app/src/main/java/com/owncloud/android/ui/fragment/ExtendedListFragment.kt b/app/src/main/java/com/owncloud/android/ui/fragment/ExtendedListFragment.kt index 54bbad82e7ab..f009f632380f 100644 --- a/app/src/main/java/com/owncloud/android/ui/fragment/ExtendedListFragment.kt +++ b/app/src/main/java/com/owncloud/android/ui/fragment/ExtendedListFragment.kt @@ -765,9 +765,13 @@ open class ExtendedListFragment : } } - protected fun setGridSwitchButton() { + protected fun setLayoutSwitchButton() { + setLayoutSwitchButton(isGridEnabled) + } + + protected fun setLayoutSwitchButton(isGrid: Boolean) { mSwitchGridViewButton?.let { - if (isGridEnabled) { + if (isGrid) { it.setContentDescription(getString(R.string.action_switch_list_view)) it.icon = ContextCompat.getDrawable(requireContext(), R.drawable.ic_view_list) } else { diff --git a/app/src/main/java/com/owncloud/android/ui/fragment/LocalFileListFragment.java b/app/src/main/java/com/owncloud/android/ui/fragment/LocalFileListFragment.java index 26b3f8de3d6a..14d5cbc9cf6e 100644 --- a/app/src/main/java/com/owncloud/android/ui/fragment/LocalFileListFragment.java +++ b/app/src/main/java/com/owncloud/android/ui/fragment/LocalFileListFragment.java @@ -134,7 +134,7 @@ public void onActivityCreated(Bundle savedInstanceState) { } } - setGridSwitchButton(); + setLayoutSwitchButton(); if (mSwitchGridViewButton != null) { mSwitchGridViewButton.setOnClickListener(v -> { @@ -143,7 +143,7 @@ public void onActivityCreated(Bundle savedInstanceState) { } else { switchToGridView(); } - setGridSwitchButton(); + setLayoutSwitchButton(); }); } diff --git a/app/src/main/java/com/owncloud/android/ui/fragment/OCFileListFragment.java b/app/src/main/java/com/owncloud/android/ui/fragment/OCFileListFragment.java index 2f2766ac6f83..15dfb62e92d1 100644 --- a/app/src/main/java/com/owncloud/android/ui/fragment/OCFileListFragment.java +++ b/app/src/main/java/com/owncloud/android/ui/fragment/OCFileListFragment.java @@ -433,7 +433,7 @@ public void onActivityCreated(Bundle savedInstanceState) { } else { setGridAsPreferred(); } - setGridSwitchButton(); + setLayoutSwitchButton(); }); } @@ -1570,17 +1570,9 @@ public void updateOCFile(@NonNull OCFile file) { } private void updateLayout() { - // decide grid vs list view - if (isGridViewPreferred(mFile)) { - switchToGridView(); - } else { - switchToListView(); - } - + setLayoutViewMode(); updateSortButton(); - if (mSwitchGridViewButton != null) { - setGridSwitchButton(); - } + setLayoutSwitchButton(); setFabVisible(!mHideFab); slideHideBottomBehaviourForBottomNavigationView(!mHideFab); @@ -1616,14 +1608,34 @@ public void sortFiles(FileSortOrder sortOrder) { } /** - * Determines if user set folder to grid or list view. If folder is not set itself, it finds a parent that is set - * (at least root is set). + * Determines whether a folder should be displayed in grid or list view. + *

+ * The preference is checked for the given folder. If the folder itself does not have a preference set, + * it will fall back to its parent folder recursively until a preference is found (root folder is always set). + * Additionally, if a search event is active and is of type {@code SHARED_FILTER}, grid view is disabled. * - * @param folder Folder to check or null for root folder - * @return 'true' is folder should be shown in grid mode, 'false' if list mode is preferred. + * @param folder The folder to check, or {@code null} to refer to the root folder. + * @return {@code true} if the folder should be displayed in grid mode, {@code false} if list mode is preferred. */ - public boolean isGridViewPreferred(@Nullable OCFile folder) { - return FOLDER_LAYOUT_GRID.equals(preferences.getFolderLayout(folder)); + private boolean isGridViewPreferred(@Nullable OCFile folder) { + if (searchEvent != null) { + return (searchEvent.toSearchType() != SHARED_FILTER) && + FOLDER_LAYOUT_GRID.equals(preferences.getFolderLayout(folder)); + } else { + return FOLDER_LAYOUT_GRID.equals(preferences.getFolderLayout(folder)); + } + } + + private void setLayoutViewMode() { + boolean isGrid = isGridViewPreferred(mFile); + + if (isGrid) { + switchToGridView(); + } else { + switchToListView(); + } + + setLayoutSwitchButton(isGrid); } public void setListAsPreferred() { @@ -1854,11 +1866,7 @@ protected void handleSearchEvent(SearchEvent event) { new Handler(Looper.getMainLooper()).post(() -> { updateSortButton(); - if (isGridViewPreferred(mFile) && !isGridEnabled()) { - switchToGridView(); - } else if (!isGridViewPreferred(mFile) && isGridEnabled()) { - switchToListView(); - } + setLayoutViewMode(); }); final User currentUser = accountManager.getUser(); From c38e5812b208323a3dae7e52715f9d166b29265d Mon Sep 17 00:00:00 2001 From: alperozturk96 Date: Mon, 26 Jan 2026 11:41:33 +0100 Subject: [PATCH 179/216] chore: version bump 3.35.2 Signed-off-by: alperozturk96 --- app/build.gradle.kts | 2 +- fastlane/metadata/android/en-US/changelogs/30350290.txt | 7 +++++++ .../metadata/android/en-US/changelogs/30350290.txt.license | 2 ++ 3 files changed, 10 insertions(+), 1 deletion(-) create mode 100644 fastlane/metadata/android/en-US/changelogs/30350290.txt create mode 100644 fastlane/metadata/android/en-US/changelogs/30350290.txt.license diff --git a/app/build.gradle.kts b/app/build.gradle.kts index f651b611094d..d43a5d86247f 100644 --- a/app/build.gradle.kts +++ b/app/build.gradle.kts @@ -64,7 +64,7 @@ configurations.configureEach { // semantic versioning for version code val versionMajor = 3 val versionMinor = 35 -val versionPatch = 1 +val versionPatch = 2 val versionBuild = 90 // 0-50=Alpha / 51-98=RC / 90-99=stable val ndkEnv = buildMap { diff --git a/fastlane/metadata/android/en-US/changelogs/30350290.txt b/fastlane/metadata/android/en-US/changelogs/30350290.txt new file mode 100644 index 000000000000..7841a42b463f --- /dev/null +++ b/fastlane/metadata/android/en-US/changelogs/30350290.txt @@ -0,0 +1,7 @@ +## 3.35.2 (January 26, 2026) + +- Bugfixes + +Minimum: NC 20 Server, Android 9 Pie + +For a full list, please see https://github.com/nextcloud/android/milestone/121 \ No newline at end of file diff --git a/fastlane/metadata/android/en-US/changelogs/30350290.txt.license b/fastlane/metadata/android/en-US/changelogs/30350290.txt.license new file mode 100644 index 000000000000..a67e1fec2721 --- /dev/null +++ b/fastlane/metadata/android/en-US/changelogs/30350290.txt.license @@ -0,0 +1,2 @@ +# SPDX-FileCopyrightText: 2026 Nextcloud GmbH and Nextcloud contributors +# SPDX-License-Identifier: AGPL-3.0-or-later \ No newline at end of file From 4962d5feeb101ee82cc8fa30587ac174e97cd6ae Mon Sep 17 00:00:00 2001 From: Andy Scherzinger Date: Mon, 26 Jan 2026 10:01:19 +0100 Subject: [PATCH 180/216] style(strings): Remove 'successfully' since it add no further meaning Signed-off-by: Andy Scherzinger --- app/src/main/res/values/strings.xml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 01cec706c75f..fbd706cbb552 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -64,9 +64,9 @@ Delete task Are you sure you want to delete this task? Delete Task - Task successfully created + Task created An error occurred while creating the task - Task successfully deleted + Task deleted An error occurred while deleting the task Input Output @@ -251,7 +251,7 @@ %1$d / %2$d - %3$s Syncing… - %s folder successfully synchronized + %s folder synchronized An error occurred during synchronization of the %s folder %1$d of %2$d · %3$s Insufficient disk space, synchronization canceled From 86e4fa4530c6425dadaccad00eb31f8cabfad060 Mon Sep 17 00:00:00 2001 From: Nextcloud bot Date: Mon, 26 Jan 2026 11:13:10 +0000 Subject: [PATCH 181/216] fix(l10n): Update translations from Transifex Signed-off-by: Nextcloud bot --- app/src/main/res/values-ar/strings.xml | 5 +++-- app/src/main/res/values-ast/strings.xml | 3 +++ app/src/main/res/values-b+en+001/strings.xml | 6 +++--- app/src/main/res/values-bg-rBG/strings.xml | 3 ++- app/src/main/res/values-br/strings.xml | 3 +-- app/src/main/res/values-ca/strings.xml | 5 +++-- app/src/main/res/values-cs-rCZ/strings.xml | 6 +++--- app/src/main/res/values-da/strings.xml | 3 +-- app/src/main/res/values-de/strings.xml | 4 ++-- app/src/main/res/values-el/strings.xml | 4 +++- app/src/main/res/values-eo/strings.xml | 1 + app/src/main/res/values-es-rAR/strings.xml | 3 +-- app/src/main/res/values-es-rCO/strings.xml | 3 +-- app/src/main/res/values-es-rEC/strings.xml | 5 ++++- app/src/main/res/values-es-rMX/strings.xml | 3 +-- app/src/main/res/values-es/strings.xml | 5 +++-- app/src/main/res/values-et-rEE/strings.xml | 7 ++++--- app/src/main/res/values-eu/strings.xml | 5 +++-- app/src/main/res/values-fa/strings.xml | 5 ++++- app/src/main/res/values-fi-rFI/strings.xml | 4 ++-- app/src/main/res/values-fr/strings.xml | 6 +++--- app/src/main/res/values-ga/strings.xml | 7 ++++--- app/src/main/res/values-gl/strings.xml | 6 +++--- app/src/main/res/values-hr/strings.xml | 2 ++ app/src/main/res/values-hu-rHU/strings.xml | 5 +++-- app/src/main/res/values-in/strings.xml | 5 ++--- app/src/main/res/values-is/strings.xml | 4 ++-- app/src/main/res/values-it/strings.xml | 5 +++-- app/src/main/res/values-iw/strings.xml | 1 + app/src/main/res/values-ja-rJP/strings.xml | 6 +++--- app/src/main/res/values-ka/strings.xml | 3 +++ app/src/main/res/values-ko/strings.xml | 5 +++-- app/src/main/res/values-lo/strings.xml | 7 ++++--- app/src/main/res/values-lt-rLT/strings.xml | 4 ++-- app/src/main/res/values-lv/strings.xml | 1 + app/src/main/res/values-mk/strings.xml | 2 ++ app/src/main/res/values-nb-rNO/strings.xml | 3 ++- app/src/main/res/values-nl/strings.xml | 5 ++--- app/src/main/res/values-pl/strings.xml | 6 +++--- app/src/main/res/values-pt-rBR/strings.xml | 6 +++--- app/src/main/res/values-pt-rPT/strings.xml | 3 +-- app/src/main/res/values-ro/strings.xml | 4 ++-- app/src/main/res/values-ru/strings.xml | 5 +++-- app/src/main/res/values-sc/strings.xml | 2 ++ app/src/main/res/values-sk-rSK/strings.xml | 6 +++--- app/src/main/res/values-sl/strings.xml | 3 +++ app/src/main/res/values-sq/strings.xml | 1 + app/src/main/res/values-sr-rSP/strings.xml | 1 + app/src/main/res/values-sr/strings.xml | 6 +++--- app/src/main/res/values-sv/strings.xml | 5 ++--- app/src/main/res/values-sw/strings.xml | 6 +++--- app/src/main/res/values-th-rTH/strings.xml | 1 + app/src/main/res/values-tk/strings.xml | 1 + app/src/main/res/values-tr/strings.xml | 6 +++--- app/src/main/res/values-ug/strings.xml | 7 ++++--- app/src/main/res/values-uk/strings.xml | 7 ++++--- app/src/main/res/values-vi/strings.xml | 2 ++ app/src/main/res/values-zh-rCN/strings.xml | 6 +++--- app/src/main/res/values-zh-rHK/strings.xml | 6 +++--- app/src/main/res/values-zh-rTW/strings.xml | 6 +++--- 60 files changed, 147 insertions(+), 109 deletions(-) diff --git a/app/src/main/res/values-ar/strings.xml b/app/src/main/res/values-ar/strings.xml index 484baced618a..c6e590e08397 100644 --- a/app/src/main/res/values-ar/strings.xml +++ b/app/src/main/res/values-ar/strings.xml @@ -49,15 +49,16 @@ حاول إرسالة رسالة لإثارة محادثة. أهلاً بك! كيف يمكنني مساعدتك اليوم؟ حدث خطأ أثناء إنشاء المهمة - تمّ إنشاء المهمة بنجاح + تمّ إنشاء المُهِمَّة task حدث خطأ أثناء حذف المهمة - تمّ حذف المهمة بنجاح تعذّر جلب قائمة المهام. قم رجاءً بالتحقُّق من اتصالك بالإنترنت. حذف مهمة مخرجات المهمة ليست جاهزة بعد. المُساعِد مُدخَلات المُخرَجَات + فعال + غير معروف الحساب المرتبط غير موجود! فشل الوصول لـ: %1$s هذا الحساب لم تتم إضافته في هذا الجهاز بعد diff --git a/app/src/main/res/values-ast/strings.xml b/app/src/main/res/values-ast/strings.xml index 248802f9b16d..4d9cc07ca1a9 100644 --- a/app/src/main/res/values-ast/strings.xml +++ b/app/src/main/res/values-ast/strings.xml @@ -25,10 +25,13 @@ Buscar en: %s Apaecer desconectáu Desaniciar la xera + Unviar el mensaxe + Creóse la xera Nun ye posible dir en cata de la llista de xeres. Comprueba la conexón a internet. Asistente Entrada Salida + n\'execución Yá esiste nel preséu una cuenta pal mesmu usuariu y sirvidor L\'usuariu inxertáu nun concasa col usuariu d\'esta cuenta Versión del sirvidor non reconocida diff --git a/app/src/main/res/values-b+en+001/strings.xml b/app/src/main/res/values-b+en+001/strings.xml index a60e4d512b1d..30c836e71574 100644 --- a/app/src/main/res/values-b+en+001/strings.xml +++ b/app/src/main/res/values-b+en+001/strings.xml @@ -53,9 +53,8 @@ Try sending a message to spark a conversation. Hello there! What can I help you with today? An error occurred while creating the task - Task successfully created + Task created An error occurred while deleting the task - Task successfully deleted Task list is empty. Check assistant app configuration. Unable to fetch task list, please check your internet connection. Delete Task @@ -64,6 +63,8 @@ Assistant Input Output + running + unknown Thinking … Associated account not found! Access failed: %1$s @@ -497,7 +498,6 @@ %1$d of %2$d · %3$s An error occurred during synchronisation of the %s folder Insufficient disk space, synchronisation cancelled - %s folder successfully synchronised Syncing… No folders here Folder name cannot be empty diff --git a/app/src/main/res/values-bg-rBG/strings.xml b/app/src/main/res/values-bg-rBG/strings.xml index 07dcd54eecee..60730b04cb53 100644 --- a/app/src/main/res/values-bg-rBG/strings.xml +++ b/app/src/main/res/values-bg-rBG/strings.xml @@ -42,8 +42,9 @@ Показва един изпълним модул от таблото за управление Търсене в %s Изтрива задача - Задачата е успешно изтрита Асистент + в процес + неясна Свързания профил не е намерен! Достъп неуспешен: %1$s Профилът все още не съществува на устройството diff --git a/app/src/main/res/values-br/strings.xml b/app/src/main/res/values-br/strings.xml index 05b67da706a0..47b23fb66ce6 100644 --- a/app/src/main/res/values-br/strings.xml +++ b/app/src/main/res/values-br/strings.xml @@ -35,14 +35,13 @@ Klask e %s Ha sur oc\'h e fell deoc\'h dilemel an trevell-mañ ? C\'hoarvezet ez eus ur fazi en ur grouiñ an trevell - Trevell bet krouet ervat C\'hoarvezet ez eus ur fazi en ur zilemel an trevell - Trevell bet dilamet ervat N\'eus ket bet gallet tizhout ar roll trevelloù, gwiriit ho kevreadenn genrouedad. Dilemel an trevell Skoazeller Enmont Ezvont + dianv N\'eo ket bet kavet ar gont stag ! Moned c\'hwitet: %1$s N\'eo ket bet ouzhpennet ar gont ouzh an ardivink-mañ c\'hoazh diff --git a/app/src/main/res/values-ca/strings.xml b/app/src/main/res/values-ca/strings.xml index 4c0b6166925f..130cb4106388 100644 --- a/app/src/main/res/values-ca/strings.xml +++ b/app/src/main/res/values-ca/strings.xml @@ -47,15 +47,16 @@ Prova d\'enviar un missatge per iniciar una conversa. Hola! En què et puc ajudar avui? S\'ha produït un error en crear la tasca - La tasca s\'ha creat correctament + Tasca creada S\'ha produït un error en suprimir la tasca - La tasca s\'ha suprimit correctament No s\'ha pogut obtenir la llista de tasques. Comproveu la vostra connexió a Internet. Suprimeix la tasca La sortida de la tasca encara no està a punt. Assistent Entrada Sortida + en execució + desconegut No s\'ha trobat el compte associat! No s\'ha tingut accés: %1$s Encara no s\'ha afegit el compte en aquest dispositiu diff --git a/app/src/main/res/values-cs-rCZ/strings.xml b/app/src/main/res/values-cs-rCZ/strings.xml index 3917818f405a..dec85b19634a 100644 --- a/app/src/main/res/values-cs-rCZ/strings.xml +++ b/app/src/main/res/values-cs-rCZ/strings.xml @@ -53,9 +53,8 @@ Zkuste poslat zprávu pro rozproudění konverzace. Zdravím! Jak vám mohu pomoci? Při vytváření úlohy se vyskytla chyba - Úloha byla úspěšně vytvořena + Úkol vytvořen Při mazání úlohy se vyskytla chyba - Úloha úspěšně smazána Seznam úkolů je prázdný. Zkontrolujte nastavení aplikace Asistent. Nedaří se získat seznam úloh – zkontrolujte připojení k Internetu. Smazat úlohu @@ -64,6 +63,8 @@ Asistent Vstup Výstup + spuštěné + neznámý Přemýšlení… Související účet nenalezen! Přístup se nezdařil: %1$s @@ -497,7 +498,6 @@ %1$d z %2$d · %3$s Při synchronizování složky %s došlo k chybě Nedostatek prostoru na disku – synchronizace zrušena - složka %s úspěšně synchronizována Synchronizování … Nejsou zde žádné složky Název složky je třeba vyplnit diff --git a/app/src/main/res/values-da/strings.xml b/app/src/main/res/values-da/strings.xml index 18a9c0639f9d..9e50d67eebb4 100644 --- a/app/src/main/res/values-da/strings.xml +++ b/app/src/main/res/values-da/strings.xml @@ -50,15 +50,14 @@ Prøv at sende en besked for at starte en samtale. Hej! Hvad kan jeg hjælpe dig med i dag? En fejl opstod under oprettelse af opgaven - Opgaven er oprettet En fejl opstod under sletning af opgaven - Opgaven er slettet Kan ikke hente ophaveliste. Kontroller venligst din internetforbindelse. Slet opgave Opgaveoutputtet er endnu ikke klar. Assistent Input Output + ukendt Forbundet konto blev ikke fundet! Adgang fejlede: %1$s Kontoen findes endnu ikke på enheden diff --git a/app/src/main/res/values-de/strings.xml b/app/src/main/res/values-de/strings.xml index 70499133828c..c127ab123459 100644 --- a/app/src/main/res/values-de/strings.xml +++ b/app/src/main/res/values-de/strings.xml @@ -55,7 +55,6 @@ Es ist ein Fehler beim Erstellen der Aufgabe aufgetreten Aufgabe erstellt Es ist ein Fehler beim Löschen der Aufgabe aufgetreten - Aufgabe gelöscht Die Aufgabenliste ist leer. Bitte die Konfiguration der Assistenten-App überprüfen. Die Aufgabenliste kann nicht abgerufen werden. Bitte überprüfen Sie Ihre Internetverbindung. Aufgabe löschen @@ -64,6 +63,8 @@ Assistent Eingabe Ausgabe + läuft + unbekannt Denkt nach … Verknüpftes Konto nicht gefunden! Zugriffsfehler: %1$s @@ -497,7 +498,6 @@ %1$d von %2$d · %3$s Es ist ein Fehler beim Synchronisieren des Ordners %s aufgetreten. Unzureichender Speicherplatz, Synchronisierung abgebrochen - %s Ordner erfolgreich synchronisiert Synchronisiere… Keine Ordner vorhanden Der Ordnername darf nicht leer sein diff --git a/app/src/main/res/values-el/strings.xml b/app/src/main/res/values-el/strings.xml index 44b52de654a9..7bed658c0196 100644 --- a/app/src/main/res/values-el/strings.xml +++ b/app/src/main/res/values-el/strings.xml @@ -36,9 +36,11 @@ Διαγραφή εργασίας Δοκιμάστε να στείλετε ένα μήνυμα για να ξεκινήσετε μια συνομιλία. Γεια σας! Τι μπορώ να κάνω για σας σήμερα; - Η εργασία διαγράφηκε με επιτυχία + Η εργασία δημιουργήθηκε Βοηθός Είσοδος + εκτελείται + άγνωστο Δεν βρέθηκε ο συνδεδεμένος λογαριασμός! Αποτυχία πρόσβασης: %1$s Ο λογαριασμός δεν υπάρχει ακόμα στη συσκευή diff --git a/app/src/main/res/values-eo/strings.xml b/app/src/main/res/values-eo/strings.xml index 1b368d233e05..fed7ff75ea89 100644 --- a/app/src/main/res/values-eo/strings.xml +++ b/app/src/main/res/values-eo/strings.xml @@ -27,6 +27,7 @@ Aktivaĵoj Aldoni al %1$s Serĉi en 1%s + nekonata Aliro malsukcesis: %1$s La konto ankoraŭ ne aldoniĝis al tiu ĉi aparato Konto pri samaj uzanto kaj servilo jam ekzistas tiuaparate diff --git a/app/src/main/res/values-es-rAR/strings.xml b/app/src/main/res/values-es-rAR/strings.xml index 7e0a93affc7d..aa373ac17397 100644 --- a/app/src/main/res/values-es-rAR/strings.xml +++ b/app/src/main/res/values-es-rAR/strings.xml @@ -35,14 +35,13 @@ Buscar en %s ¿Está seguro que desea eliminar esta tarea? Ocurrió un error al crear la tarea - Tarea creada exitosamente Ocurrió un error al eliminar la tarea - Tarea eliminada exitosamente No se pudo obtener la lista de tareas, por favor revise su conexión a internet. Eliminar tarea Asistente Entrada Salida + desconocido ¡Cuenta asociada no encontrada! Acceso fallido: %1$s La cuenta aún no se ha agregado a este dispositivo. diff --git a/app/src/main/res/values-es-rCO/strings.xml b/app/src/main/res/values-es-rCO/strings.xml index a2a78afa1e13..9dea1687926f 100644 --- a/app/src/main/res/values-es-rCO/strings.xml +++ b/app/src/main/res/values-es-rCO/strings.xml @@ -43,15 +43,14 @@ ¿Está seguro que desea eliminar esta tarea? Eliminar tarea Se ha producido un error al crear la tarea - Tarea creada exitosamente Ocurrió un error al eliminar la tarea - Tarea eliminada con éxito No se pudo obtener la lista de tareas, por favor revise su conexión a internet. Eliminar tarea El resultado de la tarea aún no está listo. Asistente Entrada Salida + desconocido ¡No se encontró la cuenta asociada! Error de acceso: %1$s La cuenta aún no ha sido agregada a este dispositivo diff --git a/app/src/main/res/values-es-rEC/strings.xml b/app/src/main/res/values-es-rEC/strings.xml index 85e1a432625a..80e8902fc444 100644 --- a/app/src/main/res/values-es-rEC/strings.xml +++ b/app/src/main/res/values-es-rEC/strings.xml @@ -35,7 +35,10 @@ Compartir en %s Aparecer como desconectado Eliminar tarea - Tarea eliminada con éxito + Enviar mensaje + Tarea creada + ejecutándose + desconocido ¡Cuenta asociada no encontrada! Acceso fallido: %1$s La cuenta aún no ha sido agregada a este dispositivo diff --git a/app/src/main/res/values-es-rMX/strings.xml b/app/src/main/res/values-es-rMX/strings.xml index 97d337bb1740..82ce268c8ed1 100644 --- a/app/src/main/res/values-es-rMX/strings.xml +++ b/app/src/main/res/values-es-rMX/strings.xml @@ -37,14 +37,13 @@ ¿Está seguro de eliminar esta tarea? Eliminar tarea Ocurrió un error al crear la tarea - Tarea creada exitosamente Ocurrió un error al eliminar la tarea - Tarea eliminada exitosamente No se pudo obtener la lista de tareas, por favor, revise su conexión a internet. Eliminar tarea Asistente Entrada Salida + desconocido ¡No se encontró la cuenta asociada! Acceso fallido:%1$s La cuenta aún no ha sido agregada a este dispositivo diff --git a/app/src/main/res/values-es/strings.xml b/app/src/main/res/values-es/strings.xml index 43fb50917907..4d9e1b59310d 100644 --- a/app/src/main/res/values-es/strings.xml +++ b/app/src/main/res/values-es/strings.xml @@ -50,15 +50,16 @@ Intente enviar un mensaje para iniciar una conversación. ¡Hola!, ¿En qué te puedo ayudar hoy? Ocurrió un error al crear la tarea - Tarea creada exitosamente + Se creó la tarea Ocurrió un error al eliminar la tarea - La tarea fue eliminada exitosamente No se pudo obtener la lista de tareas, por favor, revise su conexión a internet. Eliminar tarea El resultado de la tarea no está listo aún. Asistente Entrada Salida + funcionando + desconocido ¡Cuenta asociada no encontrada! Acceso fallido: %1$s La cuenta no se ha añadido aún en este dispositivo diff --git a/app/src/main/res/values-et-rEE/strings.xml b/app/src/main/res/values-et-rEE/strings.xml index 40326234ffa1..6408b122d18b 100644 --- a/app/src/main/res/values-et-rEE/strings.xml +++ b/app/src/main/res/values-et-rEE/strings.xml @@ -52,10 +52,10 @@ Kustuta ülesanne Vestluse algatamiseks proovi sata üks sõnum. Hei! Kuidas saan sind täna aidata? + Saada sõnum Ülesande loomisel tekkis viga - Ülesande loomine õnnestus + Ülesanne on koostatud Ülesande kustutamisel tekkis viga - Ülesande kustutamine õnnestus Ülesannete loend on tühi. Kontrolli Abilise rakenduse seadistusi. Ülesannete loendi laadimine ei õnnestunud. Palun kontrolli oma nutiseadme internetiühenduse toimivust. Kustuta ülesanne @@ -63,6 +63,8 @@ Abiline Sisend Väljund + töötab + tundmatu Mõtisklen... Seotud kontot ei leitud! Ligipääs ebaõnnestus: %1$s @@ -496,7 +498,6 @@ %1$d / %2$d · %3$s „%s“ kausta sünkroonimisel tekkis viga Andmekandjal pole piisavalt ruumi, sünkroonimine on katkestatud - %s kausta sünkroonimine õnnestus Sünkroonin… Siin ei ole kaustu Kausta nimi ei saa olla tühi. diff --git a/app/src/main/res/values-eu/strings.xml b/app/src/main/res/values-eu/strings.xml index ad90a6147185..c900e5d952fc 100644 --- a/app/src/main/res/values-eu/strings.xml +++ b/app/src/main/res/values-eu/strings.xml @@ -47,15 +47,16 @@ Ziur zeregin hau ezabatu nahi duzula? Ezabatu zeregina Errore bat gertatu da zeregina sortzean - Zeregina behar bezala sortu da + Eginkizuna sortuta Errore bat gertatu da zeregina ezabatzean - Zeregina ongi ezabatu da Ezin da zereginen zerrenda eskuratu. Egiaztatu Interneteko konexioa. Ezabatu zeregina Zereginaren irteera ez dago prest oraindik. Morroia Sarrera Irteera + Exekutatzen + ezezaguna Ez da aurkitu lotutako konturik Huts egin du atzitzean: %1$s Kontua ez da gailu honetan gehitu oraindik diff --git a/app/src/main/res/values-fa/strings.xml b/app/src/main/res/values-fa/strings.xml index 080085035bec..1ae77810a6fb 100644 --- a/app/src/main/res/values-fa/strings.xml +++ b/app/src/main/res/values-fa/strings.xml @@ -36,7 +36,10 @@ جستجو در %s نمایش آفلاین وظیفه را حذف کنید - Task successfully deleted + فرستادن پیام + Task created + running + نامشخص حساب مرتبط یافت نشد! دسترسی خطای %1$s حساب به این وسیله اضافه نشده است diff --git a/app/src/main/res/values-fi-rFI/strings.xml b/app/src/main/res/values-fi-rFI/strings.xml index 67e204d36317..4d1361b7c412 100644 --- a/app/src/main/res/values-fi-rFI/strings.xml +++ b/app/src/main/res/values-fi-rFI/strings.xml @@ -42,10 +42,11 @@ Tehtävän luonti epäonnistui Tehtävä luotu Tehtävän poisto epäonnistui - Tehtävä poistettu Tehtävälistan haku epäonnistui, tarkista internetyhteytesi. Poista tehtävä Avustaja + käynnissä + tuntematon Mietitään… Liitettyä tiliä ei löydy! Pääsy epäonnistui: %1$s @@ -438,7 +439,6 @@ Kansio on jo olemassa Luo Tallennustilaa ei ole riittävästi, synkronointi on peruttu - %s kansio synkronoitu onnistuneesti Synkronoidaan… Ei kansioita täällä Kansion nimi ei voi olla tyhjä diff --git a/app/src/main/res/values-fr/strings.xml b/app/src/main/res/values-fr/strings.xml index 00ae9a9891a7..8c6aae34ade1 100644 --- a/app/src/main/res/values-fr/strings.xml +++ b/app/src/main/res/values-fr/strings.xml @@ -52,9 +52,8 @@ Essayez d\'envoyer un message pour déclencher une conversation. Bonjour ! En quoi puis-je vous aider aujourd’hui ? Une erreur est survenue lors de la création de la tâche - La tâche a bien été créée + Tâche créée Une erreur est survenue lors de la suppression de la tâche - Tâche supprimée avec succès La liste des tâches est vide. Vérifiez la configuration de l’application de l’assistant. Impossible de récupérer la liste des tâches, veuillez vérifier votre connexion Internet. Supprimer la tâche @@ -62,6 +61,8 @@ Assistant Entrée Sortie + en cours + Inconnu En cours de réflexion... Compte associé introuvable ! L\'accès a échoué: %1$s @@ -492,7 +493,6 @@ %1$d de %2$d · %3$s Une erreur s\'est produite lors de la synchronisation du dossier %s Espace disque insuffisant, synchronisation annulée - Dossier %s synchronisé avec succès Synchronisation en cours… Aucun dossier Le nom du dossier ne peut être vide diff --git a/app/src/main/res/values-ga/strings.xml b/app/src/main/res/values-ga/strings.xml index 461feea1fbbf..ee8cbc8cc633 100644 --- a/app/src/main/res/values-ga/strings.xml +++ b/app/src/main/res/values-ga/strings.xml @@ -52,10 +52,10 @@ Scrios tasc Bain triail as teachtaireacht a sheoladh chun tús a chur le comhrá. Dia duit ann! Cad is féidir liom cabhrú leat inniu? + Seol teachtaireacht Tharla earráid agus an tasc á chruthú - D\'éirigh leis an tasc a chruthú + Tasc cruthaithe Tharla earráid agus an tasc á scriosadh - D\'éirigh leis an tasc a scriosadh Tá an liosta tascanna folamh. Seiceáil cumraíocht aip an chúntóra. Ní féidir liosta tascanna a fháil, seiceáil do nasc idirlín le do thoil. Scrios Tasc @@ -64,6 +64,8 @@ Cúntóir Ionchur Aschur + Ag rith + anaithnid Ag smaoineamh… Cuntas gaolmhar gan aimsiú! Theip ar rochtain: %1$s @@ -497,7 +499,6 @@ %1$d de %2$d · %3$s Tharla earráid le linn sioncrónú an fhillteáin %s Gan dóthain spáis diosca, sioncrónú curtha ar ceal - Sioncrónaíodh an fillteán %s go rathúil Ag sioncrónú… Níl fillteáin anseo Ní féidir ainm fillteáin a bheith folamh diff --git a/app/src/main/res/values-gl/strings.xml b/app/src/main/res/values-gl/strings.xml index 8c8973680b3d..2b1a19915346 100644 --- a/app/src/main/res/values-gl/strings.xml +++ b/app/src/main/res/values-gl/strings.xml @@ -53,9 +53,8 @@ Probe a enviar unha mensaxe para iniciar unha conversa. Ola! En que podo axudarlle hoxe? Produciuse un erro ao crear a tarefa - A tarefa creouse satisfactoriamente + Tarefa creada Produciuse un erro ao eliminar a tarefa - A tarefa foi eliminada satisfactoriamente A lista de tarefas está baleira. Comprobe a configuración da aplicación do asistente. Non é posíbel recuperar a lista de tarefas. Comprobe a conexión a Internet. Eliminar tarefa @@ -63,6 +62,8 @@ Asistente Entrada Saída + en execución + descoñecido Pensando… Non se atopou unha conta asociada! Acceso fallado: %1$s @@ -496,7 +497,6 @@ %1$d de %2$d · %3$s Produciuse un erro durante a sincronización do cartafol %s Non hai espazo abondo no disco, cancelouse a sincronización - O cartafol %s foi sincronizado correctamente Sincronizando… Aquí non hai cartafoles O nome do cartafol non pode estar baleiro diff --git a/app/src/main/res/values-hr/strings.xml b/app/src/main/res/values-hr/strings.xml index 162e473ca1d2..5c266ad4f6d7 100644 --- a/app/src/main/res/values-hr/strings.xml +++ b/app/src/main/res/values-hr/strings.xml @@ -33,6 +33,8 @@ Proxy port Traži u %s Izbriši zadatak + radi + nepoznato Pripadajući račun nije pronađen! Neuspjeli pristup: %1$s Račun još nije dodan na ovaj uređaj diff --git a/app/src/main/res/values-hu-rHU/strings.xml b/app/src/main/res/values-hu-rHU/strings.xml index 50628278fc08..788454026cb0 100644 --- a/app/src/main/res/values-hu-rHU/strings.xml +++ b/app/src/main/res/values-hu-rHU/strings.xml @@ -47,15 +47,16 @@ Valóban törölni akarja ezt a feladatot? Feladat törlése Hiba történt egy feladat létrehozása során - Feladat sikeresen létrehozva + Feladat létrehozva Hiba történt a feladat törlése során - Feladat sikeresen törölve A feladatlista nem kérhető le, ellenőrizze az internetkapcsolatát. Feladat törlése A feladat kimenete még nincs kész. Asszisztens Bemenet Kimenet + fut + ismeretlen A kapcsolódó fiók nem található! Hozzáférési hiba: %1$s Az eszközön még nem létezik a fiók diff --git a/app/src/main/res/values-in/strings.xml b/app/src/main/res/values-in/strings.xml index 9d37e3a2b3b8..b3986f09d1c6 100644 --- a/app/src/main/res/values-in/strings.xml +++ b/app/src/main/res/values-in/strings.xml @@ -50,15 +50,15 @@ Coba kirim pesan untuk memulai percakapan. Halo! Apa yang bisa saya bantu hari ini? Terjadi kesalahan saat membuat tugas - Tugas berhasil dibuat + Tugas dibuat Terjadi kesalahan saat menghapus tugas - Tugas berhasil dihapus Tidak dapat memperoleh daftar tugas, mohon periksa koneksi internet Anda. Hapus Tugas Output tugas belum siap. Asisten Input Output + tidak diketahui Akun terkait tidak ditemukan! Akses gagal: %1$s Akun ini belum ditambahkan ke perangkat ini @@ -480,7 +480,6 @@ Otomatis unggah hanya bekerja dengan baik apabila Anda mengeluarkan aplikasi ini %1$d dari %2$d · %3$s Terjadi kesalahan selama proses sinkronisasi folder %s Ruang disk tidak mencukupi, sinkronisasi dibatalkan - %s folder berhasil disinkronkan Menyinkronkan… Tidak ada folder Nama folder tidak bisa kosong diff --git a/app/src/main/res/values-is/strings.xml b/app/src/main/res/values-is/strings.xml index 7d00f2a8382b..d792f75412e4 100644 --- a/app/src/main/res/values-is/strings.xml +++ b/app/src/main/res/values-is/strings.xml @@ -47,15 +47,15 @@ Ertu viss um að þú viljir eyða þessu verki? Eyða verki Villa kom upp við að búa til verkið - Tókst að búa til verk + Verk búið til Villa kom upp við að eyða verkinu - Tókst að eyða verki Ekki er hægt að sækja verkefnalista, athugaðu nettenginguna þína. Eyða verki Yfirlitið yfir verkin er ekki tilbúið. Meðhjálpari Inntak Frálag + óþekkt Tengdur notandaaðgangur fannst ekki! Aðgangur mistókst: %1$s Aðgangur er ekki ennþá til á tækinu diff --git a/app/src/main/res/values-it/strings.xml b/app/src/main/res/values-it/strings.xml index 3166cd379d32..befe0b60f620 100644 --- a/app/src/main/res/values-it/strings.xml +++ b/app/src/main/res/values-it/strings.xml @@ -52,9 +52,8 @@ Prova a inviare un messaggio per avviare una conversazione. Ciao! Come posso aiutarti oggi? Si è verificato un errore durante la creazione dell\'attività - Attività creato correttamente + Attività creata Un errore è intercorso durante l\'eliminazione dell\'attività - Attività eliminata correttamente L\'elenco delle attività è vuoto. Controllare la configurazione dell\'app di assistenza. Impossibile recuperare la lista dei Task, verifica la tua connessione a internet. Elimina attività @@ -62,6 +61,8 @@ Assistente Input Output + in esecuzione + sconosciuto Sto pensando … Account associato non trovato. Accesso non riuscito: %1$s diff --git a/app/src/main/res/values-iw/strings.xml b/app/src/main/res/values-iw/strings.xml index 8f069beed5a1..15f33eb22c89 100644 --- a/app/src/main/res/values-iw/strings.xml +++ b/app/src/main/res/values-iw/strings.xml @@ -35,6 +35,7 @@ חפש ב %s להופיע במצב בלתי מקוון מחיקת משימה + לא ידוע לא נמצא חשבון משויך! גישה נכשלה: %1$s החשבון לא נוסף למכשיר הזה עדיין diff --git a/app/src/main/res/values-ja-rJP/strings.xml b/app/src/main/res/values-ja-rJP/strings.xml index 75830dbe0a65..0000b27928ba 100644 --- a/app/src/main/res/values-ja-rJP/strings.xml +++ b/app/src/main/res/values-ja-rJP/strings.xml @@ -50,15 +50,16 @@ メッセージを送って会話を始めてみましょう。 こんにちは!何かお手伝いできることはありますか? タスクの作成中にエラーが発生しました。 - タスクは正常に作成されました。 + タスクを作成しました タスクの削除中にエラーが発生しました。 - タスクは正常に削除されました。 タスクリストを取得できません。インターネット接続を確認してください。 タスクを削除 タスクの出力はまだ準備ができていません。 アシスタント 入力 出力 + 実行中 + 不明 関連付けられたアカウントが見つかりません! アクセスに失敗しました: %1$s このアカウントはまだこのデバイスに追加されていません @@ -480,7 +481,6 @@ 作成 フォルダー%sの同期中にエラーが発生しました。 ディスク容量が不足しているため同期を中断しました。 - フォルダー%sの同期に成功しました。 同期中… フォルダーがありません フォルダ名を空にすることはできません diff --git a/app/src/main/res/values-ka/strings.xml b/app/src/main/res/values-ka/strings.xml index c0e037ea9506..6b87c7d397b9 100644 --- a/app/src/main/res/values-ka/strings.xml +++ b/app/src/main/res/values-ka/strings.xml @@ -32,6 +32,9 @@ Shows one widget from dashboard Search in %s Delete task + Send message + Task created + running Associated account not found! Access failed: %1$s The account is not added on this device yet diff --git a/app/src/main/res/values-ko/strings.xml b/app/src/main/res/values-ko/strings.xml index 7eabe4c6be67..0622603118ed 100644 --- a/app/src/main/res/values-ko/strings.xml +++ b/app/src/main/res/values-ko/strings.xml @@ -50,15 +50,16 @@ 대화를 시작하기 위해 메시지를 보내보세요. 안녕하세요! 오늘은 무엇을 도와드릴까요? 작업을 생성하는 중에 오류가 발생했습니다. - 작업이 성공적으로 생성됨 + 작업이 생성됨 작업을 삭제하는 중에 오류가 발생했습니다. - 작업이 성공적으로 삭제됨 작업 목록을 가져올 수 없습니다. 인터넷 연결을 확인하세요. 작업 삭제 작업을 출력할 준비가 되지 않았습니다. 어시스턴트 입력 출력 + 실행중 + 알 수 없음 관련 계정을 찾을 수 없습니다! 접근 실패: %1$s 이 장치에 아직 계정이 추가되지 않았음 diff --git a/app/src/main/res/values-lo/strings.xml b/app/src/main/res/values-lo/strings.xml index edda755b22b4..882b3f831490 100644 --- a/app/src/main/res/values-lo/strings.xml +++ b/app/src/main/res/values-lo/strings.xml @@ -49,10 +49,10 @@ Delete task ລອງສົ່ງຂໍ້ຄວາມເພື່ອເລີ່ມການສົນທະນາ. ສະບາຍດີ! ມີຫຍັງໃຫ້ຂ້ອຍຊ່ວຍມື້ນີ້ບໍ່? + Send message An error occurred while creating the task - Task successfully created + Task created An error occurred while deleting the task - Task successfully deleted Task list is empty. Check assistant app configuration. Unable to fetch task list, please check your internet connection. Delete Task @@ -60,6 +60,8 @@ Assistant Input Output + running + ບໍ່ຮູ້ ບໍ່ພົບບັນຊີທີ່ກ່ຽວຂ້ອງ! ການເຂົ້າເຖິງໄດ້ບໍ່ສຳເລັດ%1$s: ຍັງບໍ່ໄດ້ເພີ່ມບັນຊີໃສ່ໃນອຸປະກອນນີ້ @@ -485,7 +487,6 @@ %1$d of %2$d · %3$s An error occurred during synchronization of the %s folder Insufficient disk space, synchronization canceled - %s folder successfully synchronized Syncing… ບໍ່ມີໂຟນເດີ Folder name cannot be empty diff --git a/app/src/main/res/values-lt-rLT/strings.xml b/app/src/main/res/values-lt-rLT/strings.xml index e4722bca4458..9961f8449b2b 100644 --- a/app/src/main/res/values-lt-rLT/strings.xml +++ b/app/src/main/res/values-lt-rLT/strings.xml @@ -39,15 +39,15 @@ Ar tikrai norite ištrinti šią užduotį? Ištrinti užduotį Kuriant užduotį, įvyko klaida - Užduotis sėkmingai sukurta + Užduotis sukurta Ištrinant užduotį, įvyko klaida - Užduotis sėkmingai ištrinta Nepavyko gauti užduočių sąrašo, patikrinkite savo interneto ryšį. Ištrinti užduotį Išvestis dar neparuošta. Asistentas. Įvestis Išvestis + nežinomas Susieta paskyra nerasta! Prieiga nepavyko: %1$s Paskyra kol kas šiame įrenginyje nėra pridėta diff --git a/app/src/main/res/values-lv/strings.xml b/app/src/main/res/values-lv/strings.xml index 6a787cba8495..27099f22a6fd 100644 --- a/app/src/main/res/values-lv/strings.xml +++ b/app/src/main/res/values-lv/strings.xml @@ -33,6 +33,7 @@ Sveiciens! Ar ko šodien varu palīdzēt? Nevar iegūt uzdevumu sarakstu, lūgums pārbaudīt savienojumu ar internetu. Izdzēst uzdevumu + nezināms Saistītais konts nav atrasts! Piekļuve neizdevās: %1$s Konts vēl nav pievienots šai iekārtai diff --git a/app/src/main/res/values-mk/strings.xml b/app/src/main/res/values-mk/strings.xml index d58f9eb8200b..72c2f87a6664 100644 --- a/app/src/main/res/values-mk/strings.xml +++ b/app/src/main/res/values-mk/strings.xml @@ -33,7 +33,9 @@ Барај во %s Прикажи исклучен Избриши задача + Испрати порака Асистент + непознат Не е пронајдена поврзана сметка! Неуспешен пристап: %1$s Сметката сеуште не е додадена на овој уред diff --git a/app/src/main/res/values-nb-rNO/strings.xml b/app/src/main/res/values-nb-rNO/strings.xml index 3be4c128cf51..582fd9b7f94f 100644 --- a/app/src/main/res/values-nb-rNO/strings.xml +++ b/app/src/main/res/values-nb-rNO/strings.xml @@ -48,12 +48,13 @@ Det oppstod en feil under oppretting av oppgaven Oppgave opprettet Det oppstod en feil under sletting av oppgaven - Oppgaven er slettet Kan ikke hente oppgavelisten, vennligst sjekk internettforbindelsen din. Slett oppgave Assistent Inndata Utdata + kjører + ukjent Tilknyttet bruker ikke funnet! Tilgang mislyktes: %1$s Kontoen er ikke lagt til på denne enheten enda diff --git a/app/src/main/res/values-nl/strings.xml b/app/src/main/res/values-nl/strings.xml index c09cc2523c93..158cbb789296 100644 --- a/app/src/main/res/values-nl/strings.xml +++ b/app/src/main/res/values-nl/strings.xml @@ -49,9 +49,7 @@ Bent u zeker dat u deze taak wilt verwijderen? Verwijder taak Er is een fout opgetreden bij het aanmaken van de taak - Taak succesvol aangemaakt Er is een fout opgetreden bij het verwijderen van de taak - Taak succesvol verwijderd Kan takenlijst niet ophalen. Controleer je internetverbinding. Verwijder taak De taakuitvoer is nog niet klaar. @@ -59,6 +57,8 @@ Assistent Input Output + bezig + onbekend Bijbehorend account niet gevonden! Toegang mislukt: %1$s Dit account is nog niet toegevoegd op dit apparaat @@ -477,7 +477,6 @@ Deze map kan het beste worden bekeken in %1$s. Aanmaken %1$d van%2$d · %3$s - %s map succesvol gesynchroniseerd Synchroniseren... Hier zijn geen bestanden Mapnaam mag niet leeg zijn diff --git a/app/src/main/res/values-pl/strings.xml b/app/src/main/res/values-pl/strings.xml index 4bcc5b6f66a5..9b348fda2399 100644 --- a/app/src/main/res/values-pl/strings.xml +++ b/app/src/main/res/values-pl/strings.xml @@ -52,9 +52,8 @@ Spróbuj wysłać wiadomość, aby rozpocząć rozmowę. Cześć! W czym mogę Ci dziś pomóc? Wystąpił błąd podczas tworzenia zadania - Zadanie pomyślnie utworzone + Zadanie utworzone Wystąpił błąd podczas usuwania zadania - Zadanie pomyślnie usunięte Lista zadań jest pusta. Sprawdź konfigurację asystenta aplikacji. Nie można pobrać listy zadań. Sprawdź swoje połączenie internetowe. Usuń zadanie @@ -62,6 +61,8 @@ Asystent Wejście Wyjście + uruchomiony + nieznane Mylślę ... Nie znaleziono powiązanego konta! Dostęp nieudany: %1$s @@ -492,7 +493,6 @@ %1$d z %2$d · %3$s Wystąpił błąd podczas synchronizacji katalogu %s Brak miejsca na dysku, synchronizacja przewana - %s pomyślnie zsynchronizowany Synchronizacja… Brak katalogów Nazwa katalogu nie może być pusta diff --git a/app/src/main/res/values-pt-rBR/strings.xml b/app/src/main/res/values-pt-rBR/strings.xml index c565875520ef..eef15a6c6ed8 100644 --- a/app/src/main/res/values-pt-rBR/strings.xml +++ b/app/src/main/res/values-pt-rBR/strings.xml @@ -53,9 +53,8 @@ Tente enviar uma mensagem para iniciar uma conversa. Oi! Em que posso ajudá-lo hoje? Ocorreu um erro ao criar a tarefa - Tarefa criada com sucesso + Tarefa criada Ocorreu um erro ao excluir a tarefa - Tarefa excluída com sucesso A lista de tarefas está vazia. Verifique a configuração do aplicativo assistente. Não foi possível buscar a lista de tarefas. Verifique sua conexão com a Internet. Excluir Tarefa @@ -64,6 +63,8 @@ Assistente Entrada Saída + rodando + desconhecido Pensando … Conta associada não encontrada! O acesso falhou: %1$s @@ -497,7 +498,6 @@ %1$d de %2$d · %3$s Ocorreu um erro durante a sincronização da pasta %s Espaço em disco insuficiente, sincronização cancelada - Pasta %s sincronizada com êxito Sincronizando… Sem pastas aqui O nome da pasta não pode ficar vazio diff --git a/app/src/main/res/values-pt-rPT/strings.xml b/app/src/main/res/values-pt-rPT/strings.xml index 74ad4889b624..1f0e686c12f4 100644 --- a/app/src/main/res/values-pt-rPT/strings.xml +++ b/app/src/main/res/values-pt-rPT/strings.xml @@ -47,14 +47,13 @@ Tem a certeza que deseja eliminar esta tarefa? Eliminar tarefa Ocorreu um erro enquanto criava a tarefa - Tarefa criada com sucesso Ocorreu um erro enquanto eliminava a tarefa - Tarefa eliminada com sucesso Eliminar Tarefa O resultado da tarefa ainda não está pronto. Assistente Entrada Saída + desconhecido Conta associada não encontrada! Acesso falhou: %1$s A conta ainda não foi adicionada a este dispositivo diff --git a/app/src/main/res/values-ro/strings.xml b/app/src/main/res/values-ro/strings.xml index 4040360224cf..9afbfe70d0e6 100644 --- a/app/src/main/res/values-ro/strings.xml +++ b/app/src/main/res/values-ro/strings.xml @@ -44,15 +44,15 @@ Caută in %s Sigur doriți să ștergeți acest task? A apărut o eroare la crearea taskului - Task creat cu succes + Sarcina a fost creată A apărut o eroare la ștergerea taskului - Task șters cu succes Nu se poate prelua lista taskurilor, vă rugăm să verificați conexiunea la internet. Şterge task Rezultatul sarcinii nu este disponbil încă Asistent Intrare Rezultat + necunoscut Contul asociat nu a fost găsit! Accesul a eșuat: %1$s Contul nu există încă pe dispozitiv diff --git a/app/src/main/res/values-ru/strings.xml b/app/src/main/res/values-ru/strings.xml index ed31df597ecc..9375844de3b7 100644 --- a/app/src/main/res/values-ru/strings.xml +++ b/app/src/main/res/values-ru/strings.xml @@ -52,15 +52,16 @@ Попробуйте отправить сообщение, чтобы начать беседу. Здравствуйте! Чем я могу вам помочь сегодня? Произошла ошибка при создании задачи - Задача успешно создана + Задача создана Произошла ошибка во время удаления задачи - Задача удалена Не удается получить список задач, проверьте ваше подключение к Интернету. Удалить задачу Вывод задания еще не готов. Помощник Ввод Вывод + запущено + неизвестно Думаю... Связанный аккаунт не найден! Доступ запрещен: %1$s diff --git a/app/src/main/res/values-sc/strings.xml b/app/src/main/res/values-sc/strings.xml index e823d82a24dc..11213c802dfc 100644 --- a/app/src/main/res/values-sc/strings.xml +++ b/app/src/main/res/values-sc/strings.xml @@ -33,6 +33,8 @@ Chirca in %s Mustra•ti foras de lìnia Cantzella faina + in esecutzione + non connotu Contu assotziadu no agatadu! Atzessu faddidu: %1$s Su contu non s\'agatat ancora in custu dispositivu diff --git a/app/src/main/res/values-sk-rSK/strings.xml b/app/src/main/res/values-sk-rSK/strings.xml index bf164f24a633..421af1f30006 100644 --- a/app/src/main/res/values-sk-rSK/strings.xml +++ b/app/src/main/res/values-sk-rSK/strings.xml @@ -53,9 +53,8 @@ Skúste poslať správu, aby ste rozprúdili konverzáciu. Dobrý deň! S čím vám dnes môžem pomôcť? Pri vytváraní úlohy nastala chyba - Úloha bola úspešne vytvorená + Úloha vytvorená Pri odstraňovaní úlohy nastala chyba - Úloha bola úspešne odstránená Zoznam úloh je prázdny. Skontrolujte konfiguráciu aplikácie asistenta. Nie je možné načítať zoznam úloh, skontrolujte svoje internetové pripojenie. Vymazať Úlohu @@ -64,6 +63,8 @@ Asistent Vstup Výstup + spustené + neznámy Premýšľam … Priradený účet sa nenašiel Prístup zamietnutý: %1$s @@ -497,7 +498,6 @@ %1$d z %2$d · %3$s Došlo k chybe počas synchronizácie priečinka %s. Nedostatok miesta na disku, synchronizácia zrušená - %s priečinok bol úspešne synchronizovaný Synchronizuje sa... Nie sú tu žiadne priečinky Názov adresára nemôže byť prázdny diff --git a/app/src/main/res/values-sl/strings.xml b/app/src/main/res/values-sl/strings.xml index f25d53b813c7..57c73057ea50 100644 --- a/app/src/main/res/values-sl/strings.xml +++ b/app/src/main/res/values-sl/strings.xml @@ -36,6 +36,9 @@ Poišči v %s Pokaže kot brez povezave Izbriši nalogo + Naloga je ustvarjena + zagnano + neznano Povezanega računa ni mogoče najti! Dostop je spodletel: %1$s Račun še ni dodan na to napravo. diff --git a/app/src/main/res/values-sq/strings.xml b/app/src/main/res/values-sq/strings.xml index f033fd4adb27..05755bfaca80 100644 --- a/app/src/main/res/values-sq/strings.xml +++ b/app/src/main/res/values-sq/strings.xml @@ -26,6 +26,7 @@ Veprimtari Shtojeni tek %1$s Kërkoni në %s + panjohur Llogaria e lidhur nuk u gjet! Hyrja dështoi: %1$s Kjo llogari nuk është shtuar në këtë paisje akoma diff --git a/app/src/main/res/values-sr-rSP/strings.xml b/app/src/main/res/values-sr-rSP/strings.xml index cfc2a00a06fc..93da663c0cc6 100644 --- a/app/src/main/res/values-sr-rSP/strings.xml +++ b/app/src/main/res/values-sr-rSP/strings.xml @@ -30,6 +30,7 @@ Prikaži kao van mreže Da li ste sigurni da želite da izbrišete ovaj zadatak? Izbriši zadatak + nepoznato Pridruženi nalog nije nađen! Neuspeo pristup: %1$s Nalog još nije dodat na ovaj uređaj diff --git a/app/src/main/res/values-sr/strings.xml b/app/src/main/res/values-sr/strings.xml index 0b64b9739f48..c363d97021d5 100644 --- a/app/src/main/res/values-sr/strings.xml +++ b/app/src/main/res/values-sr/strings.xml @@ -50,15 +50,16 @@ Покушајте да пошаљете поруку и тако започнете разговор. Здраво! Како данас могу да вам помогнем? Дошло је до грешке током креирања задатка - Задатак је успешно креиран + Креиран је задатак Дошло је до грешке током брисања задатка - Задатак је успешно завршен Не може да се преузме листа задатака, молимо вас да проверите везу са интернетом. Обриши задатак Излаз задатка још увек није спреман. Асистент Унос Излаз + извршава се + непознато Придружени налог није нађен! Неуспешан приступ: %1$s Налог још није додат на овај уређај @@ -482,7 +483,6 @@ %1$d од %2$d · %3$s Дошло је до грешке приликом синхронизације фолдера %s Нема довољно простора на диску, синхронизација је отказана. - %s фолдер је успешно синхронизован Синхронизација… Нема фасцикли овде Назив фолдера не може да буде празно diff --git a/app/src/main/res/values-sv/strings.xml b/app/src/main/res/values-sv/strings.xml index b81425904601..a0dff511244f 100644 --- a/app/src/main/res/values-sv/strings.xml +++ b/app/src/main/res/values-sv/strings.xml @@ -52,9 +52,7 @@ Försök att skicka ett meddelande för att få igång en konversation. Hej! Vad kan jag hjälpa dig med idag? Ett fel uppstod när uppgiften skapades - Uppgiften har skapats Ett fel uppstod när uppgiften skulle tas bort - Uppgiften har raderats Uppgiftslistan är tom. Kontrollera konfigurationen för assistentappen. Det går inte att hämta uppgiftslistan, kontrollera din internetanslutning. Ta bort uppgift @@ -62,6 +60,8 @@ Assistent Inmatning Utdata + aktiv + okänt Tänker … Associerat konto kunde inte hittas! Åtkomst misslyckades: %1$s @@ -494,7 +494,6 @@ %1$d av %2$d · %3$s Ett fel uppstod under synkronisering av mappen %s Otillräckligt diskutrymme, synkronisering avbruten - Mappen %s har synkroniserats Synkroniserar... Inga mappar här Mappnamnet får inte vara tomt diff --git a/app/src/main/res/values-sw/strings.xml b/app/src/main/res/values-sw/strings.xml index 0147fc04dd32..da5a74da086d 100644 --- a/app/src/main/res/values-sw/strings.xml +++ b/app/src/main/res/values-sw/strings.xml @@ -51,10 +51,9 @@ Futa jukumu Jaribu kutuma ujumbe ili kuzua mazungumzo. Hujambo! Nikusaidie nini leo? + Tuma ujumbe Hitilafu ilitokea wakati wa kuunda jukumu - Jukumu limeundwa kwa mafanikio Hitilafu ilitokea wakati wa kufuta jukumu - Jukumu limefutwa kwa mafanikio Orodha ya majukumu iko tupu. Angalia usanidi wa programu ya Mratibu. Imeshindwa kuleta orodha ya kazi, tafadhali angalia muunganisho wako wa mtandao Futa jukumu @@ -62,6 +61,8 @@ Msaidizi Ingilio Tokeo + inafanya kazi + haijulikani Inafikiri... Akaunti inayohusishwa haijapatikana! Ufikiaji umeshindwa: %1$s @@ -494,7 +495,6 @@ %1$d of %2$d · %3$s Hitilafu ilitokea wakati wa ulandanishi wa folda ya %s Nafasi ya diski haitoshi, maingiliano yameghairiwa - Folda %s imesawazishwa Inasawazisha... Hakuna folda hapa Jina la folda haliwezi kuwa tupu diff --git a/app/src/main/res/values-th-rTH/strings.xml b/app/src/main/res/values-th-rTH/strings.xml index 09b04cba4eaa..33e25a2a9c56 100644 --- a/app/src/main/res/values-th-rTH/strings.xml +++ b/app/src/main/res/values-th-rTH/strings.xml @@ -31,6 +31,7 @@ แสดงหนึ่งวิดเจ็ตจากแดชบอร์ด ค้นหาใน %s แสดงเป็นออฟไลน์ + ไม่รู้จัก ไม่พบบัญชีที่เกี่ยวข้อง! การเข้าถึงล้มเหลว: %1$s บัญชียังไม่ถูกเพิ่มบนอุปกรณ์นี้ diff --git a/app/src/main/res/values-tk/strings.xml b/app/src/main/res/values-tk/strings.xml index e17d0ebce51a..8497bedaa0e8 100644 --- a/app/src/main/res/values-tk/strings.xml +++ b/app/src/main/res/values-tk/strings.xml @@ -29,6 +29,7 @@ Täze köpçülikleýin paýlaşma baglanyşygyny goşuň Goşuň%1$s Gözlemek%siçinde + näbelli Baglanyşyk hasaby tapylmady! Şowsuz Giriş%1$s: Akaunt entek bu enjamda goşulmaýar diff --git a/app/src/main/res/values-tr/strings.xml b/app/src/main/res/values-tr/strings.xml index cc937d517c31..f53113e5cc44 100644 --- a/app/src/main/res/values-tr/strings.xml +++ b/app/src/main/res/values-tr/strings.xml @@ -53,9 +53,8 @@ Bir görüşme başlatacak bir ileti göndermeyi dene. Merhaba! Bugün size nasıl yardımcı olabilirim? Görev oluşturulurken bir sorun çıktı - Görev oluşturuldu + Görev eklendi Görev silinirken bir sorun çıktı - Görev silindi Görev listesi boş. Yardımcı uygulamasının yapılandırmasını denetleyin. Görev listesi alınamadı. Lütfen İnternet bağlantınızı denetleyin. Görevi sil @@ -63,6 +62,8 @@ Yardımcı Giriş Çıkış + çalışıyor + bilinmiyor Düşünüyorum… İlişkili hesap bulunamadı! Erişilemedi: %1$s @@ -496,7 +497,6 @@ %1$d / %2$d · %3$s %s klasörü eşitlenirken bir sorun çıktı Disk alanı yetersiz. Eşitleme iptal edildi - %s klasörü eşitlendi Eşitleniyor… Burada herhangi bir klasör yok Klasör adı boş olamaz diff --git a/app/src/main/res/values-ug/strings.xml b/app/src/main/res/values-ug/strings.xml index 31c4836238e3..d84687cf07bb 100644 --- a/app/src/main/res/values-ug/strings.xml +++ b/app/src/main/res/values-ug/strings.xml @@ -51,10 +51,10 @@ ۋەزىپىنى ئۆچۈرۈڭ پاراڭلىشىش ئۈچۈن ئۇچۇر ئەۋەتىپ بېقىڭ. ياخشىمۇسىز! بۈگۈن سىزگە نېمە ياردەم بېرەلەيمەن؟ + ئۇچۇر ئەۋەتىڭ ۋەزىپە قۇرغاندا خاتالىق كۆرۈلدى - ۋەزىپە مۇۋەپپەقىيەتلىك قۇرۇلدى + ۋەزىپە قۇرۇلدى ۋەزىپىنى ئۆچۈرگەندە خاتالىق كۆرۈلدى - ۋەزىپە مۇۋەپپەقىيەتلىك ئۆچۈرۈلدى ۋەزىپە تىزىملىكى قۇرۇق. ياردەمچى ئەپنىڭ سەپلىمىسىنى تەكشۈر. ۋەزىپە تىزىملىكىنى ئالالمىدى ، تور ئۇلىنىشىڭىزنى تەكشۈرۈپ بېقىڭ. ۋەزىپىنى ئۆچۈرۈڭ @@ -62,6 +62,8 @@ ياردەمچى كىرگۈزۈش چىقىرىش + ئىجرا بولۇۋاتىدۇ + نامەلۇم ئويلاۋاتىدۇ... بىرلەشمە ھېسابات تېپىلمىدى! زىيارەت مەغلۇپ بولدى:%1$s @@ -494,7 +496,6 @@ %2$d دىن %1$d · %3$s %s قىسقۇچىنى ماس-قەدەملەۋاتقاندا بىر خاتالىق يۈز بەردى دېسكا بوشلۇقى يىتەرسىز، ماس-قەدەملەش ئەمەلدىن قالدۇرۇلدى - %s قىسقۇچ مۇۋاپىقىيەتلىك ماس-قەدەملەندى ماس-قەدەملەۋاتىدۇ... بۇ يەردە ھۆججەت قىسقۇچ يوق ھۆججەت قىسقۇچنىڭ ئىسمى قۇرۇق بولمايدۇ diff --git a/app/src/main/res/values-uk/strings.xml b/app/src/main/res/values-uk/strings.xml index 43a9cfc66ced..b5441903df6b 100644 --- a/app/src/main/res/values-uk/strings.xml +++ b/app/src/main/res/values-uk/strings.xml @@ -52,10 +52,10 @@ Вилучити завдання Спробуйте надіслати повідомлення, щоб розпочати розмову. Привіт! Чим я можу вам сьогодні допомогти? + Надіслати повідомлення Помилка під час додавання завдання - Успішно додано завдання + Завдання створено Помилка під час вилучення завдання - Завдання вилучено Список завдань порожній. Перевірте налаштування застосунку асистента. Неможливо отримати список завдань. Перевірте з\'єднання з мережею Вилучити завдання @@ -64,6 +64,8 @@ Помічник Введення Виведення + біг + невідомо Думаю ... Пов\'язаний обліковий запис не знайдено! Доступ невдалий: %1$s @@ -497,7 +499,6 @@ %1$d із %2$d · %3$s Помилка під час синхронізації каталогу %s Недостатньо місця на диску, синхронізацію скасовано - %s каталог успішно синхронізовано Синхронізація... Тут відсутні каталоги Ім\'я каталогу не може бути порожнім diff --git a/app/src/main/res/values-vi/strings.xml b/app/src/main/res/values-vi/strings.xml index d45faac11611..b7ad0fef2bc2 100644 --- a/app/src/main/res/values-vi/strings.xml +++ b/app/src/main/res/values-vi/strings.xml @@ -32,6 +32,8 @@ Tìm kiếm trong %s Đang offline Xóa nhiệm vụ + đang chạy + không biết Không tìm thấy tài khoản được liên kết! Lỗi truy cập: %1$s Tài khoản chưa được thêm vào thiết bị này. diff --git a/app/src/main/res/values-zh-rCN/strings.xml b/app/src/main/res/values-zh-rCN/strings.xml index c7be593a42b1..77c54b89fa05 100644 --- a/app/src/main/res/values-zh-rCN/strings.xml +++ b/app/src/main/res/values-zh-rCN/strings.xml @@ -53,9 +53,8 @@ 尝试发送消息来发起对话。 您好!请问我能帮您些什么? 创建任务时发生错误 - 任务已创建 + 已创建任务 删除任务时发生错误 - 任务已删除 任务列表为空。请检查助手应用配置。 无法获取任务列表,请检查你的互联网连接。 删除任务 @@ -64,6 +63,8 @@ 助手 输入 输出结果 + 运行中 + 未知 正在思考 … 相关账号未找到! 访问已失败: %1$s @@ -497,7 +498,6 @@ %1$d / %2$d · %3$s 同步 %s 文件夹时出错 磁盘空间不足,同步已取消 - %s 文件夹已成功同步 正在同步… 这里没有文件夹 文件夹名称不能为空 diff --git a/app/src/main/res/values-zh-rHK/strings.xml b/app/src/main/res/values-zh-rHK/strings.xml index 2cbec3d3bb22..5eea67493d17 100644 --- a/app/src/main/res/values-zh-rHK/strings.xml +++ b/app/src/main/res/values-zh-rHK/strings.xml @@ -53,9 +53,8 @@ 試著發送一條訊息來引發對話。 你好!今天我能幫你什麼忙呢? 建立任務項目時發生錯誤 - 已成功建立任務項目 + 創建了任務 刪除任務時發生了錯誤 - 任務已刪除 任務清單是空的。請檢查小幫手應用程式設定。 無法擷取任務清單,請檢查您的網際網路連線。 刪除任務 @@ -64,6 +63,8 @@ 助手 輸入 輸出 + 運行中 + 不詳 思考中 ... 無法找到連結帳戶 存取失敗:%1$s @@ -497,7 +498,6 @@ %1$d / %2$d · %3$s 同步 %s 資料夾時發生錯誤 磁碟空間不足,已取消同步 - 已成功同步 %s 資料夾 同步中 ... 這裡沒有資料夾 資料夾名稱不能為空 diff --git a/app/src/main/res/values-zh-rTW/strings.xml b/app/src/main/res/values-zh-rTW/strings.xml index 68f16e1a8112..ca8f7d1abe04 100644 --- a/app/src/main/res/values-zh-rTW/strings.xml +++ b/app/src/main/res/values-zh-rTW/strings.xml @@ -53,9 +53,8 @@ 嘗試傳送訊息來引發對話。 嗨!我現在能怎麼協助您呢? 建立工作項目時發生錯誤 - 已成功建立工作項目 + 已建立工作 刪除工作項目時發生錯誤 - 已成功刪除工作項目 任務清單是空的。請檢查小幫手應用程式設定。 無法擷取工作項目清單,請檢查您的網際網路連線。 刪除工作項目 @@ -64,6 +63,8 @@ 助理 輸入 輸出 + 執行中 + 未知 正在思考…… 找不到相關的帳號! 存取失敗:%1$s @@ -497,7 +498,6 @@ %1$d / %2$d · %3$s 同步 %s 資料夾時發生錯誤 磁碟空間不足,已取消同步 - 已成功同步 %s 資料夾 正在同步…… 此處無資料夾 資料夾名稱不能為空 From 4897ba2c6645f6471c689399af1cd19c7de50748 Mon Sep 17 00:00:00 2001 From: Nextcloud bot Date: Mon, 26 Jan 2026 11:30:56 +0000 Subject: [PATCH 182/216] fix(l10n): Update translations from Transifex Signed-off-by: Nextcloud bot --- app/src/main/res/values-b+en+001/strings.xml | 9 +++++++++ app/src/main/res/values-cs-rCZ/strings.xml | 4 ++++ app/src/main/res/values-de/strings.xml | 9 +++++++++ app/src/main/res/values-fr/strings.xml | 2 ++ app/src/main/res/values-ga/strings.xml | 2 ++ app/src/main/res/values-tr/strings.xml | 2 ++ 6 files changed, 28 insertions(+) diff --git a/app/src/main/res/values-b+en+001/strings.xml b/app/src/main/res/values-b+en+001/strings.xml index 30c836e71574..6743ddaaa1fe 100644 --- a/app/src/main/res/values-b+en+001/strings.xml +++ b/app/src/main/res/values-b+en+001/strings.xml @@ -48,13 +48,17 @@ Output shown here is generated by AI. Make sure to always double-check. Failed to send a message Failed to fetch chat messages + Go back to assistant page Are you sure you want to delete this task? Delete task Try sending a message to spark a conversation. Hello there! What can I help you with today? + Send message + Open conversation list An error occurred while creating the task Task created An error occurred while deleting the task + Task deleted Task list is empty. Check assistant app configuration. Unable to fetch task list, please check your internet connection. Delete Task @@ -63,7 +67,11 @@ Assistant Input Output + failed running + scheduled + successful + Task status: %1$s unknown Thinking … Associated account not found! @@ -498,6 +506,7 @@ %1$d of %2$d · %3$s An error occurred during synchronisation of the %s folder Insufficient disk space, synchronisation cancelled + %s folder synchronised Syncing… No folders here Folder name cannot be empty diff --git a/app/src/main/res/values-cs-rCZ/strings.xml b/app/src/main/res/values-cs-rCZ/strings.xml index dec85b19634a..9f3f450972af 100644 --- a/app/src/main/res/values-cs-rCZ/strings.xml +++ b/app/src/main/res/values-cs-rCZ/strings.xml @@ -52,6 +52,7 @@ Smazat úkol Zkuste poslat zprávu pro rozproudění konverzace. Zdravím! Jak vám mohu pomoci? + Poslat zprávu Při vytváření úlohy se vyskytla chyba Úkol vytvořen Při mazání úlohy se vyskytla chyba @@ -63,7 +64,10 @@ Asistent Vstup Výstup + nezdařilo se spuštěné + naplánováno + úspěšné neznámý Přemýšlení… Související účet nenalezen! diff --git a/app/src/main/res/values-de/strings.xml b/app/src/main/res/values-de/strings.xml index c127ab123459..2e40370bf785 100644 --- a/app/src/main/res/values-de/strings.xml +++ b/app/src/main/res/values-de/strings.xml @@ -48,13 +48,17 @@ Die hier gezeigte Ausgabe wurde von KI erstellt. Bitte genau überprüfen. Eine Nachricht konnte nicht gesendet werden Chatnachrichten konnten nicht abgerufen werden + Gehe zurück zur Assistentenseite Möchten Sie diese Aufgabe wirklich löschen? Aufgabe löschen Versuchen Sie, eine Nachricht zu senden, um eine Unterhaltung anzustoßen. Hallo! Womit kann ich Ihnen heute helfen? + Nachricht senden + Liste der Unterhaltungen öffnen Es ist ein Fehler beim Erstellen der Aufgabe aufgetreten Aufgabe erstellt Es ist ein Fehler beim Löschen der Aufgabe aufgetreten + Aufgabe gelöscht Die Aufgabenliste ist leer. Bitte die Konfiguration der Assistenten-App überprüfen. Die Aufgabenliste kann nicht abgerufen werden. Bitte überprüfen Sie Ihre Internetverbindung. Aufgabe löschen @@ -63,7 +67,11 @@ Assistent Eingabe Ausgabe + fehlgeschlagen läuft + geplant + erfolgreich + Aufgabenstatus: %1$s unbekannt Denkt nach … Verknüpftes Konto nicht gefunden! @@ -498,6 +506,7 @@ %1$d von %2$d · %3$s Es ist ein Fehler beim Synchronisieren des Ordners %s aufgetreten. Unzureichender Speicherplatz, Synchronisierung abgebrochen + %s Ordner synchronisiert Synchronisiere… Keine Ordner vorhanden Der Ordnername darf nicht leer sein diff --git a/app/src/main/res/values-fr/strings.xml b/app/src/main/res/values-fr/strings.xml index 8c6aae34ade1..a94190efff0c 100644 --- a/app/src/main/res/values-fr/strings.xml +++ b/app/src/main/res/values-fr/strings.xml @@ -61,7 +61,9 @@ Assistant Entrée Sortie + défectueux en cours + planifié Inconnu En cours de réflexion... Compte associé introuvable ! diff --git a/app/src/main/res/values-ga/strings.xml b/app/src/main/res/values-ga/strings.xml index ee8cbc8cc633..67be1aa78e79 100644 --- a/app/src/main/res/values-ga/strings.xml +++ b/app/src/main/res/values-ga/strings.xml @@ -64,7 +64,9 @@ Cúntóir Ionchur Aschur + theip Ag rith + sceidealta anaithnid Ag smaoineamh… Cuntas gaolmhar gan aimsiú! diff --git a/app/src/main/res/values-tr/strings.xml b/app/src/main/res/values-tr/strings.xml index f53113e5cc44..4367251ae313 100644 --- a/app/src/main/res/values-tr/strings.xml +++ b/app/src/main/res/values-tr/strings.xml @@ -62,7 +62,9 @@ Yardımcı Giriş Çıkış + tamamlanamadı çalışıyor + zamanlanmış bilinmiyor Düşünüyorum… İlişkili hesap bulunamadı! From 60a03591d9d09592fecdbd015ed33bdae955c9f1 Mon Sep 17 00:00:00 2001 From: Nextcloud bot Date: Tue, 27 Jan 2026 03:11:02 +0000 Subject: [PATCH 183/216] fix(l10n): Update translations from Transifex Signed-off-by: Nextcloud bot --- app/src/main/res/values-de/strings.xml | 2 +- app/src/main/res/values-pt-rBR/strings.xml | 9 +++++++++ app/src/main/res/values-ru/strings.xml | 19 +++++++++++++++++-- app/src/main/res/values-uk/strings.xml | 8 ++++++++ app/src/main/res/values-zh-rTW/strings.xml | 9 +++++++++ 5 files changed, 44 insertions(+), 3 deletions(-) diff --git a/app/src/main/res/values-de/strings.xml b/app/src/main/res/values-de/strings.xml index 2e40370bf785..1afd52730eac 100644 --- a/app/src/main/res/values-de/strings.xml +++ b/app/src/main/res/values-de/strings.xml @@ -48,7 +48,7 @@ Die hier gezeigte Ausgabe wurde von KI erstellt. Bitte genau überprüfen. Eine Nachricht konnte nicht gesendet werden Chatnachrichten konnten nicht abgerufen werden - Gehe zurück zur Assistentenseite + Zurück zur Assistentenseite wechseln Möchten Sie diese Aufgabe wirklich löschen? Aufgabe löschen Versuchen Sie, eine Nachricht zu senden, um eine Unterhaltung anzustoßen. diff --git a/app/src/main/res/values-pt-rBR/strings.xml b/app/src/main/res/values-pt-rBR/strings.xml index eef15a6c6ed8..87e02699b258 100644 --- a/app/src/main/res/values-pt-rBR/strings.xml +++ b/app/src/main/res/values-pt-rBR/strings.xml @@ -48,13 +48,17 @@ A saída mostrada aqui é gerada por IA. Certifique-se de sempre verificar novamente. Falha ao enviar uma mensagem Falha ao buscar mensagens de bate-papo + Voltar á página de assistente Tem certeza de que deseja excluir esta tarefa? Excluir tarefa Tente enviar uma mensagem para iniciar uma conversa. Oi! Em que posso ajudá-lo hoje? + Enviar mensagem + Abrir lista de conversas Ocorreu um erro ao criar a tarefa Tarefa criada Ocorreu um erro ao excluir a tarefa + Tarefa excluída A lista de tarefas está vazia. Verifique a configuração do aplicativo assistente. Não foi possível buscar a lista de tarefas. Verifique sua conexão com a Internet. Excluir Tarefa @@ -63,7 +67,11 @@ Assistente Entrada Saída + falhou rodando + agendada + sucesso + Status da tarefa: %1$s desconhecido Pensando … Conta associada não encontrada! @@ -498,6 +506,7 @@ %1$d de %2$d · %3$s Ocorreu um erro durante a sincronização da pasta %s Espaço em disco insuficiente, sincronização cancelada + Pasta %s sincronizada Sincronizando… Sem pastas aqui O nome da pasta não pode ficar vazio diff --git a/app/src/main/res/values-ru/strings.xml b/app/src/main/res/values-ru/strings.xml index 9375844de3b7..bec50872ce02 100644 --- a/app/src/main/res/values-ru/strings.xml +++ b/app/src/main/res/values-ru/strings.xml @@ -13,6 +13,7 @@ Отправить/открыть доступ Вид сеткой Вид списком + Действие активировано Восстановить контакты и календарь Создать папку Переместить или копировать @@ -43,24 +44,34 @@ Порт прокси Показывает один виджет с главного экрана. Искать в %s - \"Не в сети\" для остальных + «Не в сети» для остальных Выходные данные, показанные здесь, сгенерированы с помощью искусственного интеллекта. Обязательно всегда перепроверяйте. Не удалось отправить сообщение Не удалось загрузить сообщения чата + Вернуться на страницу помощника Вы уверены, что хотите удалить эту задачу? Удалить задачу Попробуйте отправить сообщение, чтобы начать беседу. Здравствуйте! Чем я могу вам помочь сегодня? + ОТправить сообщение + Открыть список обсуждений Произошла ошибка при создании задачи Задача создана Произошла ошибка во время удаления задачи + Задача отложена + Список задач пуст. Проверьте настройки приложения Помощник. Не удается получить список задач, проверьте ваше подключение к Интернету. Удалить задачу Вывод задания еще не готов. + Текст скопирован из другого приложения Помощник Ввод Вывод + ошибка запущено + запланировано + успешно + Состояние задачи: %1$s неизвестно Думаю... Связанный аккаунт не найден! @@ -104,6 +115,7 @@ /Автозагрузка Эта папка уже включена в синхронизацию родительской папки, что может привести к дублированию загрузок Ожидание Wi-Fi для начала загрузки + Загрузка файлов из %s в %s Настроить Создать новую настройку пользовательского каталога Задать пользовательский каталог @@ -209,12 +221,14 @@ Не удалось запустить импорт. Пожалуйста, попробуйте снова Файл не найден Не удалось найти последнюю резервную копию! + Проверка изменений в папках Не удалось создать чат Удалить обсуждение Не удалось создать чат. Не найдено ни одного обсуждения Еще ни одного обсуждения - Беседы + Не удалось получить список обсуждений + Обсуждения Скопировано Произошла ошибка при попытке копирования этого файла или каталога Невозможно копирование каталога в его подкаталог @@ -481,6 +495,7 @@ Папка уже существует Эту папку лучше всего просматривать в %1$s. Создать + Синхронизировано папок: %s Синхронизация … Здесь нет каталогов Имя папки не может быть пустым diff --git a/app/src/main/res/values-uk/strings.xml b/app/src/main/res/values-uk/strings.xml index b5441903df6b..88103abf36bc 100644 --- a/app/src/main/res/values-uk/strings.xml +++ b/app/src/main/res/values-uk/strings.xml @@ -48,14 +48,17 @@ Показаний тут результат генерується штучним інтелектом. Обов\'язково перевіряйте його двічі. Не вдалося надіслати повідомлення Не вдалося отримати повідомлення чату + Перейти на сторінку асистента Дійсно вилучити це завдання? Вилучити завдання Спробуйте надіслати повідомлення, щоб розпочати розмову. Привіт! Чим я можу вам сьогодні допомогти? Надіслати повідомлення + Відкрити список розмов Помилка під час додавання завдання Завдання створено Помилка під час вилучення завдання + Завдання вилучено Список завдань порожній. Перевірте налаштування застосунку асистента. Неможливо отримати список завдань. Перевірте з\'єднання з мережею Вилучити завдання @@ -64,7 +67,11 @@ Помічник Введення Виведення + не вдалося біг + заплановано + успішно + Статус завдання: %1$s невідомо Думаю ... Пов\'язаний обліковий запис не знайдено! @@ -499,6 +506,7 @@ %1$d із %2$d · %3$s Помилка під час синхронізації каталогу %s Недостатньо місця на диску, синхронізацію скасовано + %s каталог синхронізовано Синхронізація... Тут відсутні каталоги Ім\'я каталогу не може бути порожнім diff --git a/app/src/main/res/values-zh-rTW/strings.xml b/app/src/main/res/values-zh-rTW/strings.xml index ca8f7d1abe04..67ab1cf3fc2f 100644 --- a/app/src/main/res/values-zh-rTW/strings.xml +++ b/app/src/main/res/values-zh-rTW/strings.xml @@ -48,13 +48,17 @@ 此處顯示的輸出是由人工智慧產生的。請務必仔細檢查。 傳送訊息失敗 擷取聊天訊息失敗 + 回到小幫手頁面 您確定要刪除此工作項目嗎? 刪除工作項目 嘗試傳送訊息來引發對話。 嗨!我現在能怎麼協助您呢? + 傳送訊息 + 開啟對話清單 建立工作項目時發生錯誤 已建立工作 刪除工作項目時發生錯誤 + 任務已刪除 任務清單是空的。請檢查小幫手應用程式設定。 無法擷取工作項目清單,請檢查您的網際網路連線。 刪除工作項目 @@ -63,7 +67,11 @@ 助理 輸入 輸出 + 失敗 執行中 + 已排定 + 成功 + 任務狀態:%1$s 未知 正在思考…… 找不到相關的帳號! @@ -498,6 +506,7 @@ %1$d / %2$d · %3$s 同步 %s 資料夾時發生錯誤 磁碟空間不足,已取消同步 + 已同步 %s 個資料夾 正在同步…… 此處無資料夾 資料夾名稱不能為空 From b270821d805e906316644d88395fd0463579aab8 Mon Sep 17 00:00:00 2001 From: Philipp Hasper Date: Mon, 15 Dec 2025 18:46:21 +0100 Subject: [PATCH 184/216] Illustrating timing issue with FileActivity#dismissLoadingDialog This timing issue was reproducible when testing RemoveFilesDialogFragment#removeFiles and sporadically "in the wild". However, no solution offered so far Signed-off-by: Philipp Hasper --- .../nextcloud/client/FileDisplayActivityIT.kt | 54 +++++++++++++++++++ 1 file changed, 54 insertions(+) diff --git a/app/src/androidTest/java/com/nextcloud/client/FileDisplayActivityIT.kt b/app/src/androidTest/java/com/nextcloud/client/FileDisplayActivityIT.kt index ad6c28f597ed..0805ef65e365 100644 --- a/app/src/androidTest/java/com/nextcloud/client/FileDisplayActivityIT.kt +++ b/app/src/androidTest/java/com/nextcloud/client/FileDisplayActivityIT.kt @@ -1,6 +1,7 @@ /* * Nextcloud - Android Client * + * SPDX-FileCopyrightText: 2025 Philipp Hasper * SPDX-FileCopyrightText: 2019 Tobias Kaminsky * SPDX-FileCopyrightText: 2019 Nextcloud GmbH * SPDX-License-Identifier: AGPL-3.0-or-later OR GPL-2.0-only @@ -14,12 +15,14 @@ import androidx.test.espresso.Espresso.onView import androidx.test.espresso.IdlingRegistry import androidx.test.espresso.action.ViewActions.click import androidx.test.espresso.action.ViewActions.closeSoftKeyboard +import androidx.test.espresso.assertion.ViewAssertions.doesNotExist import androidx.test.espresso.assertion.ViewAssertions.matches import androidx.test.espresso.contrib.DrawerActions import androidx.test.espresso.contrib.NavigationViewActions import androidx.test.espresso.contrib.RecyclerViewActions import androidx.test.espresso.matcher.ViewMatchers import androidx.test.espresso.matcher.ViewMatchers.hasDescendant +import androidx.test.espresso.matcher.ViewMatchers.isDisplayed import androidx.test.espresso.matcher.ViewMatchers.withEffectiveVisibility import androidx.test.espresso.matcher.ViewMatchers.withId import androidx.test.espresso.matcher.ViewMatchers.withText @@ -36,6 +39,7 @@ import com.owncloud.android.operations.CreateFolderOperation import com.owncloud.android.ui.activity.FileDisplayActivity import com.owncloud.android.ui.adapter.OCFileListItemViewHolder import com.owncloud.android.utils.EspressoIdlingResource +import org.hamcrest.Matchers.allOf import org.junit.After import org.junit.Assert.assertEquals import org.junit.Assert.assertTrue @@ -44,6 +48,7 @@ import org.junit.Rule import org.junit.Test class FileDisplayActivityIT : AbstractOnServerIT() { + @Before fun registerIdlingResource() { IdlingRegistry.getInstance().register(EspressoIdlingResource.countingIdlingResource) @@ -236,4 +241,53 @@ class FileDisplayActivityIT : AbstractOnServerIT() { } } } + + @Test + fun testShowAndDismissLoadingDialog() { + launchActivity().use { scenario -> + val loadingText = "Some text displayed while loading" + + // Test that display works + scenario.onActivity { sut -> + sut.showLoadingDialog(loadingText) + } + onView(withText(loadingText)) + .check(matches(isDisplayed())) + + // Test that hiding works + scenario.onActivity { sut -> + sut.dismissLoadingDialog() + } + onView(allOf(withText(loadingText), isDisplayed())) + .check(doesNotExist()) + + // Test that there is no timing issue when hiding the dialog directly after. + // This timing issue was reproducible when testing RemoveFilesDialogFragment#removeFiles + // as well as sporadically "in the wild". + scenario.onActivity { sut -> + sut.showLoadingDialog(loadingText) + sut.dismissLoadingDialog() + } + onView(allOf(withText(loadingText), isDisplayed())) + .check(doesNotExist()) + // Wait for a potential timing issue - dialog appearing belatedly + Thread.sleep(1000) + onView(allOf(withText(loadingText), isDisplayed())) + .check(doesNotExist()) + + // Test that multiple display calls after another don't cause a timing issue + scenario.onActivity { sut -> + sut.showLoadingDialog(loadingText) + sut.showLoadingDialog(loadingText) + sut.showLoadingDialog(loadingText) + sut.dismissLoadingDialog() + } + onView(allOf(withText(loadingText), isDisplayed())) + .check(doesNotExist()) + // Wait for a potential timing issue - dialog appearing belatedly + Thread.sleep(1000) + onView(allOf(withText(loadingText), isDisplayed())) + .check(doesNotExist()) + } + } } From aaff1df58352f0bacf6ba7e62aa0facce9224d52 Mon Sep 17 00:00:00 2001 From: Philipp Hasper Date: Tue, 16 Dec 2025 18:24:55 +0100 Subject: [PATCH 185/216] Fixing timing issue with FileActivity's loading dialog show and dismiss. Before dismissing the dialog, we need to wait for a potentially pending transaction. As showing the dialog also includes the dismissing of prior instances, we need to wait there as well. Both is needed to satisfy the test case added in the previous commit. Otherwise, the dialog might be shown after it was meant to be dismissed already. This issue was observed when testing RemoveFilesDialogFragment's removeFiles() and also sporadically "in the wild". Signed-off-by: Philipp Hasper --- .../java/com/owncloud/android/ui/activity/FileActivity.java | 2 ++ 1 file changed, 2 insertions(+) diff --git a/app/src/main/java/com/owncloud/android/ui/activity/FileActivity.java b/app/src/main/java/com/owncloud/android/ui/activity/FileActivity.java index 1e1727283d18..2e87286462a2 100644 --- a/app/src/main/java/com/owncloud/android/ui/activity/FileActivity.java +++ b/app/src/main/java/com/owncloud/android/ui/activity/FileActivity.java @@ -563,6 +563,7 @@ protected void updateFileFromDB(){ public void showLoadingDialog(String message) { runOnUiThread(() -> { FragmentManager fragmentManager = getSupportFragmentManager(); + fragmentManager.executePendingTransactions(); Fragment existingDialog = fragmentManager.findFragmentByTag(DIALOG_WAIT_TAG); if (existingDialog instanceof LoadingDialog loadingDialog) { @@ -585,6 +586,7 @@ public void showLoadingDialog(String message) { public void dismissLoadingDialog() { runOnUiThread(() -> { FragmentManager fragmentManager = getSupportFragmentManager(); + fragmentManager.executePendingTransactions(); Fragment fragment = fragmentManager.findFragmentByTag(DIALOG_WAIT_TAG); if (fragment instanceof LoadingDialog loadingDialogFragment) { From c960583d983ef4809999e8e5c42d8b54e4a63192 Mon Sep 17 00:00:00 2001 From: Philipp Hasper Date: Sun, 24 Aug 2025 17:38:57 +0200 Subject: [PATCH 186/216] Instrumentation tests now automatically grab the notifications permission Before that, when starting individual tests from the command line or from inside the IDE, they could fail because a dialog asking for the permission to post notifications was blocking the view. While we are on it, added a small explanation to the other existing rule. Without that explanation it might be unclear why this is not also done via the same GrantPermissionRule used for the notifications. Signed-off-by: Philipp Hasper --- .../java/com/nextcloud/test/GrantStoragePermissionRule.kt | 5 +++++ .../androidTest/java/com/owncloud/android/AbstractIT.java | 7 ++++++- 2 files changed, 11 insertions(+), 1 deletion(-) diff --git a/app/src/androidTest/java/com/nextcloud/test/GrantStoragePermissionRule.kt b/app/src/androidTest/java/com/nextcloud/test/GrantStoragePermissionRule.kt index b310a897fa42..3bade62247c4 100644 --- a/app/src/androidTest/java/com/nextcloud/test/GrantStoragePermissionRule.kt +++ b/app/src/androidTest/java/com/nextcloud/test/GrantStoragePermissionRule.kt @@ -15,6 +15,10 @@ import org.junit.rules.TestRule import org.junit.runner.Description import org.junit.runners.model.Statement +/** + * Rule to automatically enable the test to write to the external storage. + * Depending on the SDK version, different approaches might be necessary to achieve the full access. + */ class GrantStoragePermissionRule private constructor() { companion object { @@ -30,6 +34,7 @@ class GrantStoragePermissionRule private constructor() { private class GrantManageExternalStoragePermissionRule : TestRule { override fun apply(base: Statement, description: Description): Statement = object : Statement() { override fun evaluate() { + // Refer to https://developer.android.com/training/data-storage/manage-all-files#enable-manage-external-storage-for-testing InstrumentationRegistry.getInstrumentation().uiAutomation.executeShellCommand( "appops set --uid ${InstrumentationRegistry.getInstrumentation().targetContext.packageName} " + "MANAGE_EXTERNAL_STORAGE allow" diff --git a/app/src/androidTest/java/com/owncloud/android/AbstractIT.java b/app/src/androidTest/java/com/owncloud/android/AbstractIT.java index 5ea27541062f..8e6c34db085c 100644 --- a/app/src/androidTest/java/com/owncloud/android/AbstractIT.java +++ b/app/src/androidTest/java/com/owncloud/android/AbstractIT.java @@ -6,6 +6,7 @@ */ package com.owncloud.android; +import android.Manifest; import android.accounts.Account; import android.accounts.AccountManager; import android.accounts.AuthenticatorException; @@ -78,6 +79,7 @@ import androidx.test.espresso.contrib.DrawerActions; import androidx.test.espresso.intent.rule.IntentsTestRule; import androidx.test.platform.app.InstrumentationRegistry; +import androidx.test.rule.GrantPermissionRule; import androidx.test.runner.lifecycle.ActivityLifecycleMonitorRegistry; import androidx.test.runner.lifecycle.Stage; @@ -93,7 +95,10 @@ */ public abstract class AbstractIT { @Rule - public final TestRule permissionRule = GrantStoragePermissionRule.grant(); + public final TestRule storagePermissionRule = GrantStoragePermissionRule.grant(); + + @Rule + public GrantPermissionRule notificationsPermissionRule = GrantPermissionRule.grant(Manifest.permission.POST_NOTIFICATIONS); protected static OwnCloudClient client; protected static NextcloudClient nextcloudClient; From 8c518a09e8de23137a354e28765dff75720a5731 Mon Sep 17 00:00:00 2001 From: Nextcloud bot Date: Wed, 28 Jan 2026 03:11:46 +0000 Subject: [PATCH 187/216] fix(l10n): Update translations from Transifex Signed-off-by: Nextcloud bot --- app/src/main/res/values-pt-rBR/strings.xml | 4 ++-- app/src/main/res/values-sw/strings.xml | 21 +++++++++++++++++++-- app/src/main/res/values-zh-rCN/strings.xml | 13 +++++++++++-- app/src/main/res/values-zh-rHK/strings.xml | 9 +++++++++ 4 files changed, 41 insertions(+), 6 deletions(-) diff --git a/app/src/main/res/values-pt-rBR/strings.xml b/app/src/main/res/values-pt-rBR/strings.xml index 87e02699b258..77c0d6dbb0fd 100644 --- a/app/src/main/res/values-pt-rBR/strings.xml +++ b/app/src/main/res/values-pt-rBR/strings.xml @@ -48,7 +48,7 @@ A saída mostrada aqui é gerada por IA. Certifique-se de sempre verificar novamente. Falha ao enviar uma mensagem Falha ao buscar mensagens de bate-papo - Voltar á página de assistente + Voltar à página de assistente Tem certeza de que deseja excluir esta tarefa? Excluir tarefa Tente enviar uma mensagem para iniciar uma conversa. @@ -68,7 +68,7 @@ Entrada Saída falhou - rodando + executando agendada sucesso Status da tarefa: %1$s diff --git a/app/src/main/res/values-sw/strings.xml b/app/src/main/res/values-sw/strings.xml index da5a74da086d..1db12fb8304b 100644 --- a/app/src/main/res/values-sw/strings.xml +++ b/app/src/main/res/values-sw/strings.xml @@ -13,6 +13,7 @@ Tuma/ shiriki Mwonekano wa gridi Mwonekano wa orodha + Kitendo kimeanzishwa Hifadhi mawasiliano na kalenda Kisanduku kipya Hamisha au nakili @@ -47,21 +48,30 @@ Matokeo yaliyoonyeshwa hapa yanatolewa na AI. Hakikisha kuangalia mara mbili kila wakati. Imeshindwa kutuma ujumbe Imeshindwa kuleta ujumbe wa gumzo + Rudi kwenye ukurasa wa msaidizi Je, una uhakika unataka kufuta jukumu hili? Futa jukumu Jaribu kutuma ujumbe ili kuzua mazungumzo. Hujambo! Nikusaidie nini leo? Tuma ujumbe + Fungua orodha ya mazungumzo Hitilafu ilitokea wakati wa kuunda jukumu + Jukumu limeundwa Hitilafu ilitokea wakati wa kufuta jukumu + Jukumu limefutwa Orodha ya majukumu iko tupu. Angalia usanidi wa programu ya Mratibu. Imeshindwa kuleta orodha ya kazi, tafadhali angalia muunganisho wako wa mtandao Futa jukumu Toleo la kazi bado halijawa tayari. + Maandishi yamenakiliwa kutoka kwenye programu nyingine Msaidizi Ingilio Tokeo + imeshindwa inafanya kazi + imepangwa + imefanikiwa + Hali ya jukumu: %1$s haijulikani Inafikiri... Akaunti inayohusishwa haijapatikana! @@ -398,6 +408,7 @@ Imeshindwa kuunda mazungumzo ya mzozo Imeshindwa kupitisha faili ili kupakua kidhibiti Imeshindwa kuchapisha faili + Imeshindwa kuanza kitendo! Imeshindwa kuanzisha kihariri Imeshindwa kusasisha UI Ongeza kwenye pendwa @@ -495,6 +506,7 @@ %1$d of %2$d · %3$s Hitilafu ilitokea wakati wa ulandanishi wa folda ya %s Nafasi ya diski haitoshi, maingiliano yameghairiwa + %s folda iliyosawazishwa Inasawazisha... Hakuna folda hapa Jina la folda haliwezi kuwa tupu @@ -756,6 +768,7 @@ Muda Dhibiti folda za ndani kwa usawazishaji wa njia mbili Washa usawazishaji wa njia mbili + Usawazishaji wa njia mbili Giza Mwanga Fuata mfumo @@ -826,6 +839,7 @@ Tafadhali chagua kiolezo kimoja Chagua kiolezo Tuma + Tuma nakala kwa Tuma ushiriki Aikoni ya kitufe cha kutuma Haikuweza kupakia maudhui @@ -880,10 +894,10 @@ Tuma barua pepe mpya Dokezo kwa mpokeaji Mipangilio - Hide download + Ficha upakuaji Shirikisha kiungo Tuma kiungo - Unset + Haijawekwa Avatar kutoka kwa mtumiaji aliyeshirikiwa shiriki imeshirikiwa @@ -960,6 +974,9 @@ Pendekeza Sawazisha Sawazisha hata hivyo + Tatua migogoro + Migogoro ya upakiaji imegunduliwa. Fungua vipakizi ili kutatua. + Migogoro ya upakiaji wa faili Migogoro imepatikana Folda %1$s haipo tena Sawazisha nakala diff --git a/app/src/main/res/values-zh-rCN/strings.xml b/app/src/main/res/values-zh-rCN/strings.xml index 77c54b89fa05..615bc55c5828 100644 --- a/app/src/main/res/values-zh-rCN/strings.xml +++ b/app/src/main/res/values-zh-rCN/strings.xml @@ -48,13 +48,17 @@ 此处显示的输出结果由 AI 生成。请务必仔细检查。 无法发送消息 无法获取聊天消息 + 返回助手页面 您确定要删除这些任务吗? 删除任务 尝试发送消息来发起对话。 您好!请问我能帮您些什么? + 发送消息 + 打开对话列表 创建任务时发生错误 - 已创建任务 + 任务已创建 删除任务时发生错误 + 任务已删除 任务列表为空。请检查助手应用配置。 无法获取任务列表,请检查你的互联网连接。 删除任务 @@ -63,7 +67,11 @@ 助手 输入 输出结果 - 运行中 + 失败 + 正在运行 + 已排定 + 成功 + 任务状态:%1$s 未知 正在思考 … 相关账号未找到! @@ -498,6 +506,7 @@ %1$d / %2$d · %3$s 同步 %s 文件夹时出错 磁盘空间不足,同步已取消 + %s 文件夹已同步 正在同步… 这里没有文件夹 文件夹名称不能为空 diff --git a/app/src/main/res/values-zh-rHK/strings.xml b/app/src/main/res/values-zh-rHK/strings.xml index 5eea67493d17..be9a27739f0e 100644 --- a/app/src/main/res/values-zh-rHK/strings.xml +++ b/app/src/main/res/values-zh-rHK/strings.xml @@ -48,13 +48,17 @@ 此處顯示的輸出是由人工智慧產生的。請務必仔細檢查。 發送訊息失敗 無法擷取聊天訊息 + 回到 Assistant 頁面 您確定要刪除此工作項目嗎? 刪除任務 試著發送一條訊息來引發對話。 你好!今天我能幫你什麼忙呢? + 傳送訊息 + 打開對話清單 建立任務項目時發生錯誤 創建了任務 刪除任務時發生了錯誤 + 已刪除任務 任務清單是空的。請檢查小幫手應用程式設定。 無法擷取任務清單,請檢查您的網際網路連線。 刪除任務 @@ -63,7 +67,11 @@ 助手 輸入 輸出 + 失敗 運行中 + 已預先安排好 + 成功 + 任務狀態:%1$s 不詳 思考中 ... 無法找到連結帳戶 @@ -498,6 +506,7 @@ %1$d / %2$d · %3$s 同步 %s 資料夾時發生錯誤 磁碟空間不足,已取消同步 + 已同步 %s 個資料夾 同步中 ... 這裡沒有資料夾 資料夾名稱不能為空 From cdfa4f4fcf9a56c590510dccd2b289092b7bc3fe Mon Sep 17 00:00:00 2001 From: ZetaTom <70907959+ZetaTom@users.noreply.github.com> Date: Tue, 27 Jan 2026 17:58:23 +0100 Subject: [PATCH 188/216] Fix filename overflow issue in unified search - only affected files in current folder - improve split filename layout handling Signed-off-by: ZetaTom <70907959+ZetaTom@users.noreply.github.com> --- .../UnifiedSearchCurrentDirItemViewHolder.kt | 17 +++++-- .../unified_search_current_directory_item.xml | 50 ++++++++++--------- 2 files changed, 39 insertions(+), 28 deletions(-) diff --git a/app/src/main/java/com/owncloud/android/ui/adapter/UnifiedSearchCurrentDirItemViewHolder.kt b/app/src/main/java/com/owncloud/android/ui/adapter/UnifiedSearchCurrentDirItemViewHolder.kt index a99b0174fdbe..a355cd5d4d0b 100644 --- a/app/src/main/java/com/owncloud/android/ui/adapter/UnifiedSearchCurrentDirItemViewHolder.kt +++ b/app/src/main/java/com/owncloud/android/ui/adapter/UnifiedSearchCurrentDirItemViewHolder.kt @@ -8,11 +8,11 @@ package com.owncloud.android.ui.adapter import android.content.Context +import android.view.View import com.afollestad.sectionedrecyclerview.SectionedViewHolder import com.nextcloud.android.common.ui.theme.utils.ColorRole import com.nextcloud.client.account.User import com.nextcloud.client.preferences.AppPreferences -import com.nextcloud.utils.extensions.setVisibleIf import com.owncloud.android.databinding.UnifiedSearchCurrentDirectoryItemBinding import com.owncloud.android.datamodel.FileDataStorageManager import com.owncloud.android.datamodel.OCFile @@ -38,10 +38,17 @@ class UnifiedSearchCurrentDirItemViewHolder( fun bind(file: OCFile) { val filenameWithExtension = storageManager.getFilenameConsideringOfflineOperation(file) val isFolder = file.isFolder - val (filename, extension) = FileStorageUtils.getFilenameAndExtension(filenameWithExtension, isFolder, isRTL) - binding.extension.setVisibleIf(!isFolder) - binding.extension.text = extension - binding.filename.text = filename + val containsBidiControlCharacters = FileStorageUtils.containsBidiControlCharacters(filenameWithExtension) + + if (!containsBidiControlCharacters || isFolder) { + binding.extension.visibility = View.GONE + binding.filename.text = filenameWithExtension + } else { + val (filename, extension) = FileStorageUtils.getFilenameAndExtension(filenameWithExtension, false, isRTL) + binding.extension.text = extension + binding.filename.text = filename + } + viewThemeUtils.platform.colorImageView(binding.thumbnail, ColorRole.PRIMARY) DisplayUtils.setThumbnail( file, diff --git a/app/src/main/res/layout/unified_search_current_directory_item.xml b/app/src/main/res/layout/unified_search_current_directory_item.xml index 15c1a2578744..e05ff86912dd 100644 --- a/app/src/main/res/layout/unified_search_current_directory_item.xml +++ b/app/src/main/res/layout/unified_search_current_directory_item.xml @@ -35,32 +35,36 @@ android:visibility="gone" app:corners="8" /> - + app:layout_constraintEnd_toStartOf="@id/more" + app:layout_constraintStart_toEndOf="@+id/thumbnail" + app:layout_constraintTop_toTopOf="parent"> - + + + + + Date: Tue, 27 Jan 2026 16:37:43 +0100 Subject: [PATCH 189/216] Allow sorting files when SearchType.SHARED_FILTER is active - only filename based sorting options available - OCFiles are shallow copies of OCShare and lack data - hardcoded FileSortOrder.SORT_A_TO_Z for now Signed-off-by: ZetaTom <70907959+ZetaTom@users.noreply.github.com> --- .../ui/fragment/OCFileListSearchTask.kt | 27 +++++++++++-------- 1 file changed, 16 insertions(+), 11 deletions(-) diff --git a/app/src/main/java/com/owncloud/android/ui/fragment/OCFileListSearchTask.kt b/app/src/main/java/com/owncloud/android/ui/fragment/OCFileListSearchTask.kt index ef938616dd6c..c9da435e7e61 100644 --- a/app/src/main/java/com/owncloud/android/ui/fragment/OCFileListSearchTask.kt +++ b/app/src/main/java/com/owncloud/android/ui/fragment/OCFileListSearchTask.kt @@ -176,21 +176,26 @@ class OCFileListSearchTask( return@withContext FileStorageUtils.sortOcFolderDescDateModifiedWithoutFavoritesFirst(newList) } - if (searchType != SearchType.SHARED_FILTER) { - val foldersBeforeFiles = preferences.isSortFoldersBeforeFiles() - val favoritesFirst = preferences.isSortFavoritesFirst() + val foldersBeforeFiles = preferences.isSortFoldersBeforeFiles() + val favoritesFirst = preferences.isSortFavoritesFirst() - val sortOrder = - if (searchType == SearchType.FAVORITE_SEARCH) { - preferences.getSortOrderByType(FileSortOrder.Type.favoritesListView) - } else { - preferences.getSortOrderByFolder(folder) - } + val sortOrder = when (searchType) { + SearchType.FAVORITE_SEARCH -> { + preferences.getSortOrderByType(FileSortOrder.Type.favoritesListView) + } - setNewSortOrder(sortOrder) - newList = sortOrder.sortCloudFiles(newList, foldersBeforeFiles, favoritesFirst) + SearchType.SHARED_FILTER -> { + FileSortOrder.SORT_A_TO_Z + } + + else -> { + preferences.getSortOrderByFolder(folder) + } } + setNewSortOrder(sortOrder) + newList = sortOrder.sortCloudFiles(newList, foldersBeforeFiles, favoritesFirst) + return@withContext newList } From 0253873eb7ceb75f555fac8a333c16d1729ac0b3 Mon Sep 17 00:00:00 2001 From: ZetaTom <70907959+ZetaTom@users.noreply.github.com> Date: Tue, 27 Jan 2026 16:38:32 +0100 Subject: [PATCH 190/216] Remove duplicate entries from shared tab - deduplicate (cachedFiles + newFiles) Signed-off-by: ZetaTom <70907959+ZetaTom@users.noreply.github.com> --- .../com/owncloud/android/ui/adapter/OCShareToOCFileConverter.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/src/main/java/com/owncloud/android/ui/adapter/OCShareToOCFileConverter.kt b/app/src/main/java/com/owncloud/android/ui/adapter/OCShareToOCFileConverter.kt index 45c5216e93f9..fd17de1605f6 100644 --- a/app/src/main/java/com/owncloud/android/ui/adapter/OCShareToOCFileConverter.kt +++ b/app/src/main/java/com/owncloud/android/ui/adapter/OCShareToOCFileConverter.kt @@ -84,7 +84,7 @@ object OCShareToOCFileConverter { } storageManager?.saveShares(newShares, accountName) - cachedFiles + newFiles + (cachedFiles + newFiles).distinctBy { it.remotePath } } private fun buildOcFile(path: String, shares: List): OCFile { From b6b3d2b0d356d29f990d76067a446efce33d13be Mon Sep 17 00:00:00 2001 From: alperozturk96 Date: Tue, 27 Jan 2026 08:49:43 +0100 Subject: [PATCH 191/216] check(set-avatar): user id Signed-off-by: alperozturk96 --- .../main/java/com/owncloud/android/utils/DisplayUtils.java | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/app/src/main/java/com/owncloud/android/utils/DisplayUtils.java b/app/src/main/java/com/owncloud/android/utils/DisplayUtils.java index f6f43e933140..54fad1108db3 100644 --- a/app/src/main/java/com/owncloud/android/utils/DisplayUtils.java +++ b/app/src/main/java/com/owncloud/android/utils/DisplayUtils.java @@ -434,6 +434,11 @@ public static void setAvatar(@NonNull User user, AvatarGenerationListener listen String userId = accountManager.getUserData(user.toPlatformAccount(), com.owncloud.android.lib.common.accounts.AccountUtils.Constants.KEY_USER_ID); + if (userId == null) { + Log_OC.e(TAG, "user id is null, cannot set avatar"); + return; + } + setAvatar(user, userId, listener, avatarRadius, resources, callContext, context); } From b16e99e1a22eff0ec4cf2abaf80b695720f7c512 Mon Sep 17 00:00:00 2001 From: alperozturk96 Date: Tue, 27 Jan 2026 09:00:17 +0100 Subject: [PATCH 192/216] fix(gallery-image-generation-job): concurrent modification exception Signed-off-by: alperozturk96 --- .../nextcloud/client/jobs/gallery/GalleryImageGenerationJob.kt | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/app/src/main/java/com/nextcloud/client/jobs/gallery/GalleryImageGenerationJob.kt b/app/src/main/java/com/nextcloud/client/jobs/gallery/GalleryImageGenerationJob.kt index 0e4d2149baa9..3247771a7307 100644 --- a/app/src/main/java/com/nextcloud/client/jobs/gallery/GalleryImageGenerationJob.kt +++ b/app/src/main/java/com/nextcloud/client/jobs/gallery/GalleryImageGenerationJob.kt @@ -41,7 +41,8 @@ class GalleryImageGenerationJob(private val user: User, private val storageManag private val activeJobs = WeakHashMap() fun cancelAllActiveJobs() { - for ((_, job) in activeJobs) { + val entries = activeJobs.entries.toList() + for ((_, job) in entries) { job.cancel() } activeJobs.clear() From df5587bb4fb933829e60b08c69ce8601f6a5c008 Mon Sep 17 00:00:00 2001 From: alperozturk96 Date: Tue, 27 Jan 2026 09:33:30 +0100 Subject: [PATCH 193/216] fix(file-activity): loading dialog illegal-state-exception Signed-off-by: alperozturk96 --- .../android/ui/activity/FileActivity.java | 18 +++++++++++++++++- 1 file changed, 17 insertions(+), 1 deletion(-) diff --git a/app/src/main/java/com/owncloud/android/ui/activity/FileActivity.java b/app/src/main/java/com/owncloud/android/ui/activity/FileActivity.java index 2e87286462a2..47e079c1f67e 100644 --- a/app/src/main/java/com/owncloud/android/ui/activity/FileActivity.java +++ b/app/src/main/java/com/owncloud/android/ui/activity/FileActivity.java @@ -41,6 +41,7 @@ import com.nextcloud.receiver.NetworkChangeListener; import com.nextcloud.receiver.NetworkChangeReceiver; import com.nextcloud.utils.EditorUtils; +import com.nextcloud.utils.extensions.ActivityExtensionsKt; import com.nextcloud.utils.extensions.BundleExtensionsKt; import com.nextcloud.utils.extensions.FileExtensionsKt; import com.nextcloud.utils.extensions.IntentExtensionsKt; @@ -562,13 +563,23 @@ protected void updateFileFromDB(){ */ public void showLoadingDialog(String message) { runOnUiThread(() -> { + if (!ActivityExtensionsKt.isActive(this)) { + Log_OC.w(TAG, "cannot show loading dialog, activity is finishing"); + return; + } + FragmentManager fragmentManager = getSupportFragmentManager(); fragmentManager.executePendingTransactions(); Fragment existingDialog = fragmentManager.findFragmentByTag(DIALOG_WAIT_TAG); if (existingDialog instanceof LoadingDialog loadingDialog) { Log_OC.d(TAG, "dismiss previous loading dialog"); - loadingDialog.dismiss(); + + if (!fragmentManager.isStateSaved()) { + loadingDialog.dismiss(); + } else { + loadingDialog.dismissAllowingStateLoss(); + } } // Show new dialog @@ -585,6 +596,11 @@ public void showLoadingDialog(String message) { */ public void dismissLoadingDialog() { runOnUiThread(() -> { + if (!ActivityExtensionsKt.isActive(this)) { + Log_OC.w(TAG, "cannot dismiss loading dialog, activity is finishing"); + return; + } + FragmentManager fragmentManager = getSupportFragmentManager(); fragmentManager.executePendingTransactions(); Fragment fragment = fragmentManager.findFragmentByTag(DIALOG_WAIT_TAG); From 7754855f60ccf3a699700b27df3fe9eae5c172e6 Mon Sep 17 00:00:00 2001 From: alperozturk96 Date: Tue, 27 Jan 2026 09:12:36 +0100 Subject: [PATCH 194/216] fix(ui): prevent snackbar crash in bottom sheet and simplify status handling Signed-off-by: alperozturk96 --- .../ui/SetOnlineStatusBottomSheet.kt | 106 ++++++++++-------- app/src/main/res/values/strings.xml | 3 + 2 files changed, 65 insertions(+), 44 deletions(-) diff --git a/app/src/main/java/com/nextcloud/ui/SetOnlineStatusBottomSheet.kt b/app/src/main/java/com/nextcloud/ui/SetOnlineStatusBottomSheet.kt index f27ef8cc55cf..4825aa7bf58f 100644 --- a/app/src/main/java/com/nextcloud/ui/SetOnlineStatusBottomSheet.kt +++ b/app/src/main/java/com/nextcloud/ui/SetOnlineStatusBottomSheet.kt @@ -9,7 +9,6 @@ package com.nextcloud.ui -import android.annotation.SuppressLint import android.os.Bundle import android.util.Log import android.view.LayoutInflater @@ -17,8 +16,11 @@ import android.view.View import android.view.ViewGroup import android.widget.ImageView import android.widget.TextView +import androidx.core.content.ContextCompat +import androidx.lifecycle.lifecycleScope import com.google.android.material.bottomsheet.BottomSheetDialogFragment import com.google.android.material.card.MaterialCardView +import com.nextcloud.android.common.ui.theme.utils.ColorRole import com.nextcloud.client.account.UserAccountManager import com.nextcloud.client.core.AsyncRunner import com.nextcloud.client.di.Injectable @@ -31,6 +33,8 @@ import com.owncloud.android.ui.activity.BaseActivity import com.owncloud.android.utils.DisplayUtils import com.owncloud.android.utils.theme.CapabilityUtils import com.owncloud.android.utils.theme.ViewThemeUtils +import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.launch import javax.inject.Inject class SetOnlineStatusBottomSheet(val currentStatus: Status?) : @@ -47,7 +51,6 @@ class SetOnlineStatusBottomSheet(val currentStatus: Status?) : @Inject lateinit var viewThemeUtils: ViewThemeUtils - @SuppressLint("DefaultLocale") override fun onViewCreated(view: View, savedInstanceState: Bundle?) { super.onViewCreated(view, savedInstanceState) accountManager = (activity as BaseActivity).userAccountManager @@ -56,21 +59,28 @@ class SetOnlineStatusBottomSheet(val currentStatus: Status?) : updateCurrentStatusViews(it) } - binding.onlineStatus.setOnClickListener { setStatus(StatusType.ONLINE) } - binding.awayStatus.setOnClickListener { setStatus(StatusType.AWAY) } - binding.busyStatus.setOnClickListener { setStatus(StatusType.BUSY) } - binding.dndStatus.setOnClickListener { setStatus(StatusType.DND) } - binding.invisibleStatus.setOnClickListener { setStatus(StatusType.INVISIBLE) } - - viewThemeUtils.files.themeStatusCardView(binding.onlineStatus) - viewThemeUtils.files.themeStatusCardView(binding.awayStatus) - viewThemeUtils.files.themeStatusCardView(binding.busyStatus) - viewThemeUtils.files.themeStatusCardView(binding.dndStatus) - viewThemeUtils.files.themeStatusCardView(binding.invisibleStatus) + setupStatusViews() viewThemeUtils.platform.themeDialog(binding.root) - binding.busyStatus.setVisibleIf(CapabilityUtils.getCapability(context).userStatusSupportsBusy.isTrue) + val capability = CapabilityUtils.getCapability(context) + val busyStatus = capability.userStatusSupportsBusy.isTrue + binding.busyStatus.setVisibleIf(busyStatus) + } + + private fun setupStatusViews() { + val statuses = listOf( + binding.onlineStatus to StatusType.ONLINE, + binding.awayStatus to StatusType.AWAY, + binding.busyStatus to StatusType.BUSY, + binding.dndStatus to StatusType.DND, + binding.invisibleStatus to StatusType.INVISIBLE + ) + + statuses.forEach { (view, status) -> + view.setOnClickListener { setStatus(status) } + viewThemeUtils.files.themeStatusCardView(view) + } } private fun updateCurrentStatusViews(it: Status) { @@ -98,8 +108,16 @@ class SetOnlineStatusBottomSheet(val currentStatus: Status?) : } private fun showErrorSnackbar() { - DisplayUtils.showSnackMessage(view, "Failed to set status!") - clearTopStatus() + lifecycleScope.launch(Dispatchers.Main) { + if (!isAdded) { + return@launch + } + + activity?.let { + DisplayUtils.showSnackMessage(it, R.string.set_online_status_bottom_sheet_error_message) + } + clearTopStatus() + } } private fun visualizeStatus(statusType: StatusType) { @@ -116,37 +134,37 @@ class SetOnlineStatusBottomSheet(val currentStatus: Status?) : } } views.first.isChecked = true - viewThemeUtils.platform.colorOnSecondaryContainerTextViewElement(views.second) + viewThemeUtils.platform.colorTextView(views.second, ColorRole.ON_SECONDARY_CONTAINER) } private fun clearTopStatus() { - context?.let { - binding.onlineHeadline.setTextColor( - resources.getColor(com.nextcloud.android.common.ui.R.color.high_emphasis_text) - ) - binding.awayHeadline.setTextColor( - resources.getColor(com.nextcloud.android.common.ui.R.color.high_emphasis_text) - ) - binding.busyHeadline.setTextColor( - resources.getColor(com.nextcloud.android.common.ui.R.color.high_emphasis_text) - ) - binding.dndHeadline.setTextColor( - resources.getColor(com.nextcloud.android.common.ui.R.color.high_emphasis_text) - ) - binding.invisibleHeadline.setTextColor( - resources.getColor(com.nextcloud.android.common.ui.R.color.high_emphasis_text) - ) - - binding.awayIcon.imageTintList = null - binding.dndIcon.imageTintList = null - binding.invisibleIcon.imageTintList = null - - binding.onlineStatus.isChecked = false - binding.awayStatus.isChecked = false - binding.busyStatus.isChecked = false - binding.dndStatus.isChecked = false - binding.invisibleStatus.isChecked = false - } + val ctx = context ?: return + val defaultColor = ContextCompat.getColor( + ctx, + com.nextcloud.android.common.ui.R.color.high_emphasis_text + ) + + listOf( + binding.onlineHeadline, + binding.awayHeadline, + binding.busyHeadline, + binding.dndHeadline, + binding.invisibleHeadline + ).forEach { it.setTextColor(defaultColor) } + + listOf( + binding.awayIcon, + binding.dndIcon, + binding.invisibleIcon + ).forEach { it.imageTintList = null } + + listOf( + binding.onlineStatus, + binding.awayStatus, + binding.busyStatus, + binding.dndStatus, + binding.invisibleStatus + ).forEach { it.isChecked = false } } companion object { diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index fbd706cbb552..a66a788847e4 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -248,6 +248,9 @@ Upload from… Folder name + Failed to set status! + + %1$d / %2$d - %3$s Syncing… From 48588c3d4138b4952c218a8980bda695284fe9fa Mon Sep 17 00:00:00 2001 From: Nextcloud bot Date: Thu, 29 Jan 2026 03:07:44 +0000 Subject: [PATCH 195/216] fix(l10n): Update translations from Transifex Signed-off-by: Nextcloud bot --- app/src/main/res/values-b+en+001/strings.xml | 1 + app/src/main/res/values-cs-rCZ/strings.xml | 1 + app/src/main/res/values-de/strings.xml | 1 + app/src/main/res/values-es/strings.xml | 1 + app/src/main/res/values-et-rEE/strings.xml | 10 +++++++ app/src/main/res/values-fi-rFI/strings.xml | 1 + app/src/main/res/values-fr/strings.xml | 1 + app/src/main/res/values-ga/strings.xml | 1 + app/src/main/res/values-gl/strings.xml | 1 + app/src/main/res/values-hr/strings.xml | 9 ++++++ app/src/main/res/values-hu-rHU/strings.xml | 1 + app/src/main/res/values-lo/strings.xml | 1 + app/src/main/res/values-nl/strings.xml | 1 + app/src/main/res/values-pl/strings.xml | 1 + app/src/main/res/values-pt-rBR/strings.xml | 29 ++++++++++---------- app/src/main/res/values-sk-rSK/strings.xml | 1 + app/src/main/res/values-sr/strings.xml | 1 + app/src/main/res/values-sv/strings.xml | 1 + app/src/main/res/values-sw/strings.xml | 1 + app/src/main/res/values-tr/strings.xml | 1 + app/src/main/res/values-ug/strings.xml | 1 + app/src/main/res/values-uk/strings.xml | 1 + app/src/main/res/values-zh-rHK/strings.xml | 1 + app/src/main/res/values-zh-rTW/strings.xml | 1 + 24 files changed, 55 insertions(+), 14 deletions(-) diff --git a/app/src/main/res/values-b+en+001/strings.xml b/app/src/main/res/values-b+en+001/strings.xml index 6743ddaaa1fe..7d953b5f1232 100644 --- a/app/src/main/res/values-b+en+001/strings.xml +++ b/app/src/main/res/values-b+en+001/strings.xml @@ -849,6 +849,7 @@ Set message Set note Online status + Failed to set status! Use picture as During setup of end-to-end encryption, you will receive a random 12 word mnemonic, which you will need to open your files on other devices. This will only be stored on this device, and can be shown again in this screen. Please note it down in a secure place! Share diff --git a/app/src/main/res/values-cs-rCZ/strings.xml b/app/src/main/res/values-cs-rCZ/strings.xml index 9f3f450972af..1dc01ee685eb 100644 --- a/app/src/main/res/values-cs-rCZ/strings.xml +++ b/app/src/main/res/values-cs-rCZ/strings.xml @@ -844,6 +844,7 @@ Nastavit zprávu Nastavit poznámku Stav online + Nepodařilo se nastavit stav! Použít obrázek jako V průběhu nastavování šifrování mezi koncovými body obdržíte náhodnou 12 slovnou mnemotechnickou frázi, které bude zapotřebí pro otevírání souborů na ostatních zařízeních. Ta bude uložena pouze na tomto zařízení a je možné ji na této obrazovce znovu zobrazit. Prosím poznamenejte si jí na bezpečné místo! Nasdílet diff --git a/app/src/main/res/values-de/strings.xml b/app/src/main/res/values-de/strings.xml index 1afd52730eac..6552cfeab12d 100644 --- a/app/src/main/res/values-de/strings.xml +++ b/app/src/main/res/values-de/strings.xml @@ -849,6 +849,7 @@ Nachricht festlegen Notiz setzen Online-Status + Status konnte nicht gesetzt werden! Nutze Bild als Während der Einrichtung der Ende-zu-Ende-Verschlüsselung erhalten Sie eine zufällige 12-Wörter-Gedächtnisstütze, die Sie benötigen, um Ihre Dateien auf anderen Geräten zu öffnen. Diese wird nur auf diesem Gerät gespeichert und kann in diesem Bildschirm erneut angezeigt werden. Bitte notieren Sie es an einem sicheren Ort! Teilen diff --git a/app/src/main/res/values-es/strings.xml b/app/src/main/res/values-es/strings.xml index 4d9e1b59310d..91036514847e 100644 --- a/app/src/main/res/values-es/strings.xml +++ b/app/src/main/res/values-es/strings.xml @@ -810,6 +810,7 @@ Establecer mensaje Establecer nota Estado en línea + ¡Fallo al establecer estado! Usar imagen como Durante la configuración del cifrado de extremo a extremo, recibirá un mnemónico aleatorio de 12 palabras, que necesitará para abrir sus archivos en otros dispositivos. Esto solo se almacenará en este dispositivo y se puede volver a mostrar en esta pantalla. ¡Por favor anótelo en un lugar seguro! Compartir diff --git a/app/src/main/res/values-et-rEE/strings.xml b/app/src/main/res/values-et-rEE/strings.xml index 6408b122d18b..48618ed0cb59 100644 --- a/app/src/main/res/values-et-rEE/strings.xml +++ b/app/src/main/res/values-et-rEE/strings.xml @@ -48,22 +48,30 @@ See väljund on loodud tehisaru poolt. Palun topeltkontrolli selle õigsust ka ise. Sõnumi saatmine ei õnnestu Ei õnnestunud laadida vestluse sõnumeid + Tagasi Abilise lehele Kas sa oled kindel, et soovid selle ülesande kustutada? Kustuta ülesanne Vestluse algatamiseks proovi sata üks sõnum. Hei! Kuidas saan sind täna aidata? Saada sõnum + Ava vestluste loend Ülesande loomisel tekkis viga Ülesanne on koostatud Ülesande kustutamisel tekkis viga + Ülesanne on kustutatud Ülesannete loend on tühi. Kontrolli Abilise rakenduse seadistusi. Ülesannete loendi laadimine ei õnnestunud. Palun kontrolli oma nutiseadme internetiühenduse toimivust. Kustuta ülesanne Ülesande väljund pole veel valmis. + Tekst on kopeeritud muust rakendusest Abiline Sisend Väljund + ebaõnnestunud töötab + ajastatud + õnnestunud + Ülesande olek: %1$s tundmatu Mõtisklen... Seotud kontot ei leitud! @@ -498,6 +506,7 @@ %1$d / %2$d · %3$s „%s“ kausta sünkroonimisel tekkis viga Andmekandjal pole piisavalt ruumi, sünkroonimine on katkestatud + %s kaust on sünkroonitud Sünkroonin… Siin ei ole kaustu Kausta nimi ei saa olla tühi. @@ -840,6 +849,7 @@ Lisa olekuteade Lisa märge Olek võrgus + Oleku määramine ei õnnestunud! Kasuta pilti kui Läbiva krüptimise kasutuselevõtmisel saad sa juhusliku 12-sõnalise mnemofraasi ehk salafraasi, mille alusel vaid sina saad oma krüptitud faile teistes seadmetes kasutada ja näha. Ta on salvestatud vaid siin seadmes ja on uuesti vaadatav vaid siin vaates. Palun märgi see üles ning hoia turvaliselt kas moodsas digitaalses salasõnalaekas või vana kooli seifis. Jaga diff --git a/app/src/main/res/values-fi-rFI/strings.xml b/app/src/main/res/values-fi-rFI/strings.xml index 4d1361b7c412..73e725beb8be 100644 --- a/app/src/main/res/values-fi-rFI/strings.xml +++ b/app/src/main/res/values-fi-rFI/strings.xml @@ -743,6 +743,7 @@ GNU yleinen lisenssi, versio 2 Laite ei todennäköisesti ole yhteydessä internetiin Aseta Aseta viesti + Tilan asettaminen epäonnistui! Käytä kuvaa Jaa Salli lataus ja synkronointi diff --git a/app/src/main/res/values-fr/strings.xml b/app/src/main/res/values-fr/strings.xml index a94190efff0c..a21e2d1e9dc0 100644 --- a/app/src/main/res/values-fr/strings.xml +++ b/app/src/main/res/values-fr/strings.xml @@ -836,6 +836,7 @@ Définir le message Définir la note Statuts de connexion + Impossible de définir le statut. Utiliser l\'image comme Pendant la configuration du chiffrement de bout en bout, vous recevrez une phrase secrète aléatoire de 12 mots dont vous aurez besoin pour ouvrir vos fichiers sur d\'autres appareils. Cette phrase secrète ne sera stockée que sur cet appareil, et pourra être affichée à nouveau sur cet écran. Veuillez la noter en lieu sûr ! Partager diff --git a/app/src/main/res/values-ga/strings.xml b/app/src/main/res/values-ga/strings.xml index 67be1aa78e79..dc53c12a49f4 100644 --- a/app/src/main/res/values-ga/strings.xml +++ b/app/src/main/res/values-ga/strings.xml @@ -843,6 +843,7 @@ Socraigh teachtaireacht Socraigh nóta Stádas ar líne + Theip ar an stádas a shocrú! Úsáid pictiúr mar Le linn duit criptiú ceann go deireadh a shocrú, gheobhaidh tú cuimhneachán randamach 12 focal, a bheidh ag teastáil uait chun do chuid comhad a oscailt ar ghléasanna eile. Ní stórálfar é seo ach ar an ngléas seo, agus is féidir é a thaispeáint arís sa scáileán seo. Tabhair faoi deara é síos in áit slán le do thoil! Comhroinn diff --git a/app/src/main/res/values-gl/strings.xml b/app/src/main/res/values-gl/strings.xml index 2b1a19915346..ec914a3d0812 100644 --- a/app/src/main/res/values-gl/strings.xml +++ b/app/src/main/res/values-gl/strings.xml @@ -840,6 +840,7 @@ Definir a mensaxe Definir a nota Estado en liña + Produciuse un fallo ao definir o estado! Usar a imaxe como Durante a configuración da cifraxe de extremo a extremo, recibirá un mnemotécnico ao chou de 12 palabras, que necesitará para abrir os seus ficheiros noutros dispositivos. Isto só se almacenará neste dispositivo e pódese amosar de novo nesta pantalla. Anóteo nun lugar seguro! Compartir diff --git a/app/src/main/res/values-hr/strings.xml b/app/src/main/res/values-hr/strings.xml index 5c266ad4f6d7..952e434b1dec 100644 --- a/app/src/main/res/values-hr/strings.xml +++ b/app/src/main/res/values-hr/strings.xml @@ -32,6 +32,7 @@ Osnovni URL Proxy port Traži u %s + Prikaži se kao izvan mreže Izbriši zadatak radi nepoznato @@ -111,6 +112,7 @@ Pogreška Nema dovoljno memorije Nepoznata pogreška + Napusti ovo dijeljenje Učitavanje… Dalje Ne @@ -222,6 +224,7 @@ Početna Obavijesti Na uređaju + Osobne datoteke Nedavno izmijenjeno Dijeljeno Izbrisane datoteke @@ -311,6 +314,7 @@ Još ništa nije dijeljeno Nema rezultata za vaš upit mapa + UŽIVO Učitavanje… Nije postavljena nijedna aplikacija za obrađivanje ove vrste datoteka. prije nekoliko sekundi @@ -437,6 +441,7 @@ Nije moguće premjestiti mapu u jednu od svojih osnovnih mapa Datoteka je već prisutna u odredišnoj mapi Nije moguće premjestiti datoteku. Provjerite postoji li datoteka. + Utišaj sve obavijesti Došlo je do pogreške tijekom čekanja poslužitelja. Nije moguće dovršiti radnju. Došlo je do pogreške tijekom povezivanja s poslužiteljem Došlo je do pogreške tijekom čekanja poslužitelja. Nije moguće dovršiti radnju. @@ -571,6 +576,7 @@ Vrati Vrati odabrano Dohvaćanje datoteke... + Pokušaj ponovno Učitavanje dokumenta nije uspjelo! Prijavite se putem QR koda Zaštita podataka @@ -639,6 +645,8 @@ Prijavite se kod davatelja usluga Dopusti %1$s pristup Nextcloud računu %2$s? Razvrstaj prema + Poredaj favorite na početku + Poredaj mape prije datoteka Sakrij Pojedinosti Nije moguće provjeriti identitet poslužitelja @@ -768,6 +776,7 @@ Lokalni prostor za pohranu je pun Datoteku nije moguće kopirati u lokalni prostor za pohranu Zaključavanje mape nije uspjelo + Korisnik je prekinuo prilaganje Šifriranje je moguće samo na inačici >= Androida 5.0 Nedostatak prostora sprječava kopiranje odabranih datoteka u mapu %1$s. Želite li ih premjestiti tamo? Skeniraj dokument pomoću kamere diff --git a/app/src/main/res/values-hu-rHU/strings.xml b/app/src/main/res/values-hu-rHU/strings.xml index 788454026cb0..5d50dd13ba0d 100644 --- a/app/src/main/res/values-hu-rHU/strings.xml +++ b/app/src/main/res/values-hu-rHU/strings.xml @@ -804,6 +804,7 @@ Üzenet beállítása Jegyzet beállítása Elérhető állapot + Nem sikerült beállítani az állapotot. Kép használata mint A végpontok közti titkosítás beállítása során kap egy 12 véletlenszerű szóból álló mnemonikus kódot, amelyre akkor lesz szüksége, ha más eszközökön akarja megnyitni a fájlokat. Ez csak ezen az eszközön lesz tárolva, és újra megjeleníthető ezen a képernyőn. Jegyezze le, és tárolja biztonságos helyen! Megosztás diff --git a/app/src/main/res/values-lo/strings.xml b/app/src/main/res/values-lo/strings.xml index 882b3f831490..14070c12dc94 100644 --- a/app/src/main/res/values-lo/strings.xml +++ b/app/src/main/res/values-lo/strings.xml @@ -824,6 +824,7 @@ Set message Set note ສະຖານະພາບອອນລາຍ + Failed to set status! ໃຊ້ຮູບເປັນ During setup of end-to-end encryption, you will receive a random 12 word mnemonic, which you will need to open your files on other devices. This will only be stored on this device, and can be shown again in this screen. Please note it down in a secure place! ແບ່ງປັນ diff --git a/app/src/main/res/values-nl/strings.xml b/app/src/main/res/values-nl/strings.xml index 158cbb789296..1b385a22a5a9 100644 --- a/app/src/main/res/values-nl/strings.xml +++ b/app/src/main/res/values-nl/strings.xml @@ -812,6 +812,7 @@ Stel bericht in Aantekening instellen Online status + Instellen status mislukt! Gebruik afbeelding als Tijden het instellen van end-to-end versleuteling ontvang je een mnemonic van 12 woorden, die je nodig hebt om bestanden op je apparaat te openen. Dit wordt alleen opgeslagen op dit apparaat en kan in dit scherm opnieuw getoond worden. Noteer het a.u.b. op een veilige plek! Delen diff --git a/app/src/main/res/values-pl/strings.xml b/app/src/main/res/values-pl/strings.xml index 9b348fda2399..6eb55ba184a9 100644 --- a/app/src/main/res/values-pl/strings.xml +++ b/app/src/main/res/values-pl/strings.xml @@ -833,6 +833,7 @@ Ustaw wiadomość Ustaw notatkę Status online + Nie udało się ustawić statusu. Użyj obrazu jako Podczas konfigurowania szyfrowania typu end-to-end otrzymasz losowy mnemonik składający się z 12-stu słów, który będzie potrzebny do otwierania plików na innych urządzeniach. Będzie on przechowywany tylko na tym urządzeniu i można go ponownie wyświetlić na tym ekranie. Zapisz go w bezpiecznym miejscu! Udostępnij diff --git a/app/src/main/res/values-pt-rBR/strings.xml b/app/src/main/res/values-pt-rBR/strings.xml index 77c0d6dbb0fd..2e6a50258c29 100644 --- a/app/src/main/res/values-pt-rBR/strings.xml +++ b/app/src/main/res/values-pt-rBR/strings.xml @@ -33,15 +33,15 @@ Adicionar novo depósito de arquivos seguro Adicionar em %1$s URL base - Desativar Área de Transferência - Desativar Introdução - Desativar Log - Desativar Sites Externos - Desativar Múltiplas Contas - Desativar Compartilhamento - Impor Proteção - Nome do Host de Proxy - Porta do Proxy + Desativar área de transferência + Desativar introdução + Desativar log + Desativar sites externos + Desativar múltiplas contas + Desativar compartilhamento + Impor proteção + Nome do host de proxy + Porta do proxy Mostra um widget do painel Pesquisar em %s Aparecer off-line @@ -61,7 +61,7 @@ Tarefa excluída A lista de tarefas está vazia. Verifique a configuração do aplicativo assistente. Não foi possível buscar a lista de tarefas. Verifique sua conexão com a Internet. - Excluir Tarefa + Excluir tarefa O resultado da tarefa ainda não está pronto. Texto copiado de outro aplicativo Assistente @@ -113,7 +113,7 @@ O upload automático está pausado porque o Economizador de Bateria está ativado. mantido na pasta original, já que é somente leitura Bateria fraca, o upload pode demorar mais tempo - Enviar só por WiFi não medida + Enviar só por Wi-Fi não medida /UploadAutomático Esta pasta já está incluída na sincronização da pasta pai, o que pode causar uploads duplicados Aguardando o Wi-Fi para iniciar o upload @@ -849,6 +849,7 @@ Definir mensagem Definir nota Status on-line + Falha ao definir o status! Usar imagem como Durante a configuração da criptografia de ponta-a-ponta, você receberá um mnemônico aleatório de 12 palavras, que será necessário para abrir seus arquivos em outros dispositivos. Ele será armazenado apenas neste dispositivo e poderá ser mostrado novamente nesta tela. Por favor, anote-o em um lugar seguro! Compartilhar @@ -963,8 +964,8 @@ Stream com… Streaming interno não é possível Faça o download da mídia ou use um aplicativo externo. - Ano/Mês/Dia - Ano/Mês + Ano/mês/dia + Ano/mês Ano \"%1$s\" foi compartilhado com você %1$s compartilhou \"%2$s\" com você @@ -1006,7 +1007,7 @@ Sincronizado Etiquetas Termos de serviço - Eu concordo com os Termos de Serviço acima + Eu concordo com os termos de serviço acima Teste de conexão ao servidor 30 minutos Esta semana diff --git a/app/src/main/res/values-sk-rSK/strings.xml b/app/src/main/res/values-sk-rSK/strings.xml index 421af1f30006..2d6756478a23 100644 --- a/app/src/main/res/values-sk-rSK/strings.xml +++ b/app/src/main/res/values-sk-rSK/strings.xml @@ -840,6 +840,7 @@ Nastaviť správu Nastaviť poznámku Stav pripojenia + Nepodarilo sa nastaviť stav! Použiť obrázok ako Počas nastavovania end-to-end šifrovania dostanete náhodný 12-slovový mnemotechnický záznam, ktorý budete potrebovať na otvorenie svojich súborov na iných zariadeniach. Tento záznam bude uložený iba na tomto zariadení a môže byť znovu zobrazený na tejto obrazovke. Prosím, zapíšte si ho na bezpečné miesto! Zdieľať diff --git a/app/src/main/res/values-sr/strings.xml b/app/src/main/res/values-sr/strings.xml index c363d97021d5..ff8777330dfc 100644 --- a/app/src/main/res/values-sr/strings.xml +++ b/app/src/main/res/values-sr/strings.xml @@ -819,6 +819,7 @@ Постави поруку Постави белешку Мрежни статус + Није успело постављање статуса! Постави слику као Током постављања шифрирања од почетка-до-краја примићете 12 случајних речи за памћење које ће вам бити неопходне да фајлове отворите на осталим уређајима. Ово ће се сачувати само на овом уређају и може поново да се прикаже на овом екрану. Молимо вас да их забележите на неко сигурно место! Подели diff --git a/app/src/main/res/values-sv/strings.xml b/app/src/main/res/values-sv/strings.xml index a0dff511244f..375cc2005b4c 100644 --- a/app/src/main/res/values-sv/strings.xml +++ b/app/src/main/res/values-sv/strings.xml @@ -835,6 +835,7 @@ Ange meddelande Ange anteckning Online-status + Kunde inte sätta status! Använd bild som Under inställningen av end-to-end-kryptering kommer du att få en slumpmässig lista med 12 krypteringsord, som du behöver för att öppna dina filer på andra enheter. Orden kommer endast att lagras på den här enheten och kan visas igen på den här skärmen. Vänligen notera krypteringsorden på ett säkert ställe! Dela diff --git a/app/src/main/res/values-sw/strings.xml b/app/src/main/res/values-sw/strings.xml index 1db12fb8304b..6c07b38b760e 100644 --- a/app/src/main/res/values-sw/strings.xml +++ b/app/src/main/res/values-sw/strings.xml @@ -849,6 +849,7 @@ Weka ujumbe Weka dokezo Hali ya mtandaoni + Imeshindwa kuweka hali! Tumia picha kama Wakati wa kusanidi usimbaji fiche kutoka mwanzo hadi mwisho, utapokea maneno 12 ya mnemonic nasibu, ambayo utahitaji kufungua faili zako kwenye vifaa vingine. Hii itahifadhiwa kwenye kifaa hiki pekee, na inaweza kuonyeshwa tena kwenye skrini hii. Tafadhali kumbuka kuwa mahali salama! Shirikisha diff --git a/app/src/main/res/values-tr/strings.xml b/app/src/main/res/values-tr/strings.xml index 4367251ae313..96fc0829f413 100644 --- a/app/src/main/res/values-tr/strings.xml +++ b/app/src/main/res/values-tr/strings.xml @@ -841,6 +841,7 @@ İletiyi ayarla Notu ayarla Çevrim içi durumu + Durum ayarlanamadı! Görsel şunun için kullanılsın Uçtan uca şifrelemenin kurulumu sırasında, dosyalarınızı diğer aygıtlarda açabilmeniz için rastgele 12 sözcükten oluşan bir parola alacaksınız. Bu parola yalnızca bu aygıta kaydedilir ve bu sayfadan yeniden görülebilir. Lütfen güvenli bir yere not edin! Paylaş diff --git a/app/src/main/res/values-ug/strings.xml b/app/src/main/res/values-ug/strings.xml index d84687cf07bb..02740fa01a22 100644 --- a/app/src/main/res/values-ug/strings.xml +++ b/app/src/main/res/values-ug/strings.xml @@ -837,6 +837,7 @@ ئۇچۇر بەلگىلە خاتىرىنى بېكىت توردىكى ھالىتى + ھالەتنى بەلگىلەش مەغلۇپ بولدى! رەسىمنى ئىشلىتىڭ ئاخىرىدىن ئاخىرىغىچە مەخپىيلەشتۈرۈشنى تەڭشەش جەريانىدا ، ئىختىيارى 12 سۆزلۈك mnemonic تاپشۇرۇۋالىسىز ، بۇ ھۆججەتلەرنى باشقا ئۈسكۈنىلەردە ئېچىشىڭىز كېرەك. بۇ پەقەت بۇ ئۈسكۈنىدە ساقلىنىدۇ ، بۇ ئېكراندا قايتا كۆرسەتكىلى بولىدۇ. ئۇنى بىخەتەر ئورۇنغا خاتىرىلەڭ! ھەمبەھىرلەش diff --git a/app/src/main/res/values-uk/strings.xml b/app/src/main/res/values-uk/strings.xml index 88103abf36bc..b20fe4cb321b 100644 --- a/app/src/main/res/values-uk/strings.xml +++ b/app/src/main/res/values-uk/strings.xml @@ -849,6 +849,7 @@ Встановити повідомлення Додати примітку Мій статус доступності + Не вдалося встановити статус! Використати як Під час налаштування наскрізного шифрування ви отримаєте парольну фразу з 12 слів, за допомогою якої ви зможете відкривати ваші файлі на інших пристроях. Її буде збережено лише на цьому пристрої та буде показано знову на цьому екрані. Будь ласка, занотуйте цю фразу та збережіть у безпеченому місці! Спільний доступ diff --git a/app/src/main/res/values-zh-rHK/strings.xml b/app/src/main/res/values-zh-rHK/strings.xml index be9a27739f0e..71f1f49283dc 100644 --- a/app/src/main/res/values-zh-rHK/strings.xml +++ b/app/src/main/res/values-zh-rHK/strings.xml @@ -849,6 +849,7 @@ 設置訊息 設定備註 線上狀態 + 狀態切換失敗! 使用圖片作為 在設置端到端加密期間,您將收到一個隨機的 12 字助記碼,您需要在其他設備上打開檔案。這將僅存儲在此設備上,並且可以在此螢幕中再次顯示。請記在安全的地方! 分享 diff --git a/app/src/main/res/values-zh-rTW/strings.xml b/app/src/main/res/values-zh-rTW/strings.xml index 67ab1cf3fc2f..7e3e6f6b0c8c 100644 --- a/app/src/main/res/values-zh-rTW/strings.xml +++ b/app/src/main/res/values-zh-rTW/strings.xml @@ -849,6 +849,7 @@ 設定訊息 設定備註 線上狀態 + 無法設定狀態! 使用圖片作為 在設置端對端加密過程中,您會收到隨機的 12 字記憶密語,您需要有這段密語才能在其他裝置上開啟檔案。這只會儲存在此裝置上,之後可以在此畫面中再次顯示。請將密語寫下來,妥善存放在安全的地方! 分享 From 012b3d959b59c056e568c4456e4662146082c4f5 Mon Sep 17 00:00:00 2001 From: alperozturk96 Date: Wed, 14 Jan 2026 13:08:48 +0100 Subject: [PATCH 196/216] fix(receivers): upload Signed-off-by: alperozturk96 --- ...egate.kt => FileUploadBroadcastManager.kt} | 41 ++++--------------- .../client/jobs/upload/FileUploadWorker.kt | 13 ++---- .../ui/activity/UploadListActivity.java | 16 -------- 3 files changed, 13 insertions(+), 57 deletions(-) rename app/src/main/java/com/nextcloud/client/jobs/upload/{FileUploaderDelegate.kt => FileUploadBroadcastManager.kt} (58%) diff --git a/app/src/main/java/com/nextcloud/client/jobs/upload/FileUploaderDelegate.kt b/app/src/main/java/com/nextcloud/client/jobs/upload/FileUploadBroadcastManager.kt similarity index 58% rename from app/src/main/java/com/nextcloud/client/jobs/upload/FileUploaderDelegate.kt rename to app/src/main/java/com/nextcloud/client/jobs/upload/FileUploadBroadcastManager.kt index 2cff0b44df4c..ea7f4c3671bc 100644 --- a/app/src/main/java/com/nextcloud/client/jobs/upload/FileUploaderDelegate.kt +++ b/app/src/main/java/com/nextcloud/client/jobs/upload/FileUploadBroadcastManager.kt @@ -13,54 +13,31 @@ import androidx.localbroadcastmanager.content.LocalBroadcastManager import com.owncloud.android.lib.common.operations.RemoteOperationResult import com.owncloud.android.operations.UploadFileOperation -class FileUploaderDelegate { - /** - * Sends a broadcast in order to the interested activities can update their view - * - * TODO - no more broadcasts, replace with a callback to subscribed listeners once we drop FileUploader - */ - fun sendBroadcastUploadsAdded(context: Context, localBroadcastManager: LocalBroadcastManager) { +class FileUploadBroadcastManager(private val broadcastManager: LocalBroadcastManager) { + + fun sendAdded(context: Context) { val start = Intent(FileUploadWorker.getUploadsAddedMessage()) - // nothing else needed right now start.setPackage(context.packageName) - localBroadcastManager.sendBroadcast(start) + broadcastManager.sendBroadcast(start) } - /** - * Sends a broadcast in order to the interested activities can update their view - * - * TODO - no more broadcasts, replace with a callback to subscribed listeners once we drop FileUploader - * - * @param upload Finished upload operation - */ - fun sendBroadcastUploadStarted( + fun sendStarted( upload: UploadFileOperation, context: Context, - localBroadcastManager: LocalBroadcastManager ) { val start = Intent(FileUploadWorker.getUploadStartMessage()) start.putExtra(FileUploadWorker.EXTRA_REMOTE_PATH, upload.remotePath) // real remote start.putExtra(FileUploadWorker.EXTRA_OLD_FILE_PATH, upload.originalStoragePath) start.putExtra(FileUploadWorker.ACCOUNT_NAME, upload.user.accountName) start.setPackage(context.packageName) - localBroadcastManager.sendBroadcast(start) + broadcastManager.sendBroadcast(start) } - /** - * Sends a broadcast in order to the interested activities can update their view - * - * TODO - no more broadcasts, replace with a callback to subscribed listeners once we drop FileUploader - * - * @param upload Finished upload operation - * @param uploadResult Result of the upload operation - * @param unlinkedFromRemotePath Path in the uploads tree where the upload was unlinked from - */ - fun sendBroadcastUploadFinished( + fun sendFinished( upload: UploadFileOperation, uploadResult: RemoteOperationResult<*>, unlinkedFromRemotePath: String?, - context: Context, - localBroadcastManager: LocalBroadcastManager + context: Context ) { val end = Intent(FileUploadWorker.getUploadFinishMessage()) // real remote path, after possible automatic renaming @@ -75,6 +52,6 @@ class FileUploaderDelegate { end.putExtra(FileUploadWorker.EXTRA_LINKED_TO_PATH, unlinkedFromRemotePath) } end.setPackage(context.packageName) - localBroadcastManager.sendBroadcast(end) + broadcastManager.sendBroadcast(end) } } diff --git a/app/src/main/java/com/nextcloud/client/jobs/upload/FileUploadWorker.kt b/app/src/main/java/com/nextcloud/client/jobs/upload/FileUploadWorker.kt index d1906e7c8c79..464bcf58d1cb 100644 --- a/app/src/main/java/com/nextcloud/client/jobs/upload/FileUploadWorker.kt +++ b/app/src/main/java/com/nextcloud/client/jobs/upload/FileUploadWorker.kt @@ -131,7 +131,7 @@ class FileUploadWorker( private val notificationId = Random.nextInt() private val notificationManager = UploadNotificationManager(context, viewThemeUtils, notificationId) private val intents = FileUploaderIntents(context) - private val fileUploaderDelegate = FileUploaderDelegate() + private val fileUploadBroadcastManager = FileUploadBroadcastManager(localBroadcastManager) override suspend fun doWork(): Result = try { Log_OC.d(TAG, "FileUploadWorker started") @@ -206,10 +206,6 @@ class FileUploadWorker( notificationManager.dismissNotification() } - private fun setWorkerState(user: User?) { - WorkerStateObserver.send(WorkerState.FileUploadStarted(user)) - } - private fun setIdleWorkerState() { WorkerStateObserver.send(WorkerState.FileUploadCompleted(currentUploadFileOperation?.file)) } @@ -269,9 +265,9 @@ class FileUploadWorker( return@withContext Result.failure() } - setWorkerState(user) val operation = createUploadFileOperation(upload, user) currentUploadFileOperation = operation + fileUploadBroadcastManager.sendStarted(operation, context) val currentIndex = (index + 1) val currentUploadIndex = (currentIndex + previouslyUploadedFileSize) @@ -312,12 +308,11 @@ class FileUploadWorker( if (shouldBroadcast) { // delay broadcast - fileUploaderDelegate.sendBroadcastUploadFinished( + fileUploadBroadcastManager.sendFinished( operation, result, operation.oldFile?.storagePath, - context, - localBroadcastManager + context ) } } diff --git a/app/src/main/java/com/owncloud/android/ui/activity/UploadListActivity.java b/app/src/main/java/com/owncloud/android/ui/activity/UploadListActivity.java index f66a279a44a2..18ad11840361 100755 --- a/app/src/main/java/com/owncloud/android/ui/activity/UploadListActivity.java +++ b/app/src/main/java/com/owncloud/android/ui/activity/UploadListActivity.java @@ -28,8 +28,6 @@ import com.nextcloud.client.jobs.upload.FileUploadHelper; import com.nextcloud.client.jobs.upload.FileUploadWorker; import com.nextcloud.client.utils.Throttler; -import com.nextcloud.model.WorkerState; -import com.nextcloud.utils.extensions.ActivityExtensionsKt; import com.owncloud.android.R; import com.owncloud.android.databinding.UploadListLayoutBinding; import com.owncloud.android.datamodel.OCFile; @@ -49,7 +47,6 @@ import androidx.recyclerview.widget.GridLayoutManager; import androidx.swiperefreshlayout.widget.SwipeRefreshLayout; import edu.umd.cs.findbugs.annotations.SuppressFBWarnings; -import kotlin.Unit; /** * Activity listing pending, active, and completed uploads. User can delete completed uploads from view. Content of this @@ -126,19 +123,6 @@ protected void onCreate(Bundle savedInstanceState) { setupDrawer(); setupContent(); - observeWorkerState(); - } - - private void observeWorkerState() { - ActivityExtensionsKt.observeWorker(this, state -> { - if (state instanceof WorkerState.FileUploadStarted) { - Log_OC.d(TAG, "Upload worker started"); - uploadListAdapter.loadUploadItemsFromDb(); - } else if (state instanceof WorkerState.FileUploadCompleted) { - uploadListAdapter.loadUploadItemsFromDb(() -> swipeListRefreshLayout.setRefreshing(false)); - } - return Unit.INSTANCE; - }); } private void setupContent() { From 732f87a700746c805252e738896b15fbe0892811 Mon Sep 17 00:00:00 2001 From: alperozturk96 Date: Mon, 19 Jan 2026 10:22:44 +0100 Subject: [PATCH 197/216] add documentation and simplify Signed-off-by: alperozturk96 --- .../jobs/upload/FileUploadBroadcastManager.kt | 82 ++++++++++++++----- .../client/jobs/upload/FileUploadWorker.kt | 22 +---- .../java/com/nextcloud/model/WorkerState.kt | 3 - .../ui/activity/FileDisplayActivity.kt | 21 ++--- .../ui/activity/UploadListActivity.java | 26 +++--- .../ui/fragment/FileDetailFragment.java | 16 ---- .../ui/preview/PreviewImageActivity.kt | 5 +- 7 files changed, 80 insertions(+), 95 deletions(-) diff --git a/app/src/main/java/com/nextcloud/client/jobs/upload/FileUploadBroadcastManager.kt b/app/src/main/java/com/nextcloud/client/jobs/upload/FileUploadBroadcastManager.kt index ea7f4c3671bc..e7d3233644ed 100644 --- a/app/src/main/java/com/nextcloud/client/jobs/upload/FileUploadBroadcastManager.kt +++ b/app/src/main/java/com/nextcloud/client/jobs/upload/FileUploadBroadcastManager.kt @@ -11,47 +11,85 @@ import android.content.Context import android.content.Intent import androidx.localbroadcastmanager.content.LocalBroadcastManager import com.owncloud.android.lib.common.operations.RemoteOperationResult +import com.owncloud.android.lib.common.utils.Log_OC import com.owncloud.android.operations.UploadFileOperation +/** + * Manages local broadcasts related to file upload lifecycle events. + * + * This class is responsible for notifying interested components about + * upload queue changes and upload state transitions (added, started, finished). + * + * All broadcasts are sent via [LocalBroadcastManager]. + */ class FileUploadBroadcastManager(private val broadcastManager: LocalBroadcastManager) { + companion object { + private const val TAG = "📣" + "FileUploadBroadcastManager" + + const val UPLOAD_ADDED = "UPLOAD_ADDED" + const val UPLOAD_STARTED = "UPLOAD_START" + const val UPLOAD_FINISHED = "UPLOAD_FINISH" + } + fun sendAdded(context: Context) { - val start = Intent(FileUploadWorker.getUploadsAddedMessage()) - start.setPackage(context.packageName) - broadcastManager.sendBroadcast(start) + Log_OC.d(TAG, "upload added broadcast sent") + val intent = Intent(UPLOAD_ADDED).apply { + setPackage(context.packageName) + } + broadcastManager.sendBroadcast(intent) } fun sendStarted( upload: UploadFileOperation, context: Context, ) { - val start = Intent(FileUploadWorker.getUploadStartMessage()) - start.putExtra(FileUploadWorker.EXTRA_REMOTE_PATH, upload.remotePath) // real remote - start.putExtra(FileUploadWorker.EXTRA_OLD_FILE_PATH, upload.originalStoragePath) - start.putExtra(FileUploadWorker.ACCOUNT_NAME, upload.user.accountName) - start.setPackage(context.packageName) - broadcastManager.sendBroadcast(start) + Log_OC.d(TAG, "upload started broadcast sent") + val intent = Intent(UPLOAD_STARTED).apply { + putExtra(FileUploadWorker.EXTRA_REMOTE_PATH, upload.remotePath) // real remote + putExtra(FileUploadWorker.EXTRA_OLD_FILE_PATH, upload.originalStoragePath) + putExtra(FileUploadWorker.ACCOUNT_NAME, upload.user.accountName) + setPackage(context.packageName) + } + broadcastManager.sendBroadcast(intent) } + /** + * Sends a broadcast indicating that an upload has finished, either + * successfully or with an error. + * + * ### Triggered when + * - [UploadFileOperation] completes execution + * + * ### Observed by + * - [com.owncloud.android.ui.activity.FileDisplayActivity.UploadFinishReceiver] + * - [com.owncloud.android.ui.activity.UploadListActivity.UploadFinishReceiver] + * - [com.owncloud.android.ui.preview.PreviewImageActivity.UploadFinishReceiver] + * + */ fun sendFinished( upload: UploadFileOperation, uploadResult: RemoteOperationResult<*>, unlinkedFromRemotePath: String?, context: Context ) { - val end = Intent(FileUploadWorker.getUploadFinishMessage()) - // real remote path, after possible automatic renaming - end.putExtra(FileUploadWorker.EXTRA_REMOTE_PATH, upload.remotePath) - if (upload.wasRenamed()) { - end.putExtra(FileUploadWorker.EXTRA_OLD_REMOTE_PATH, upload.oldFile!!.remotePath) - } - end.putExtra(FileUploadWorker.EXTRA_OLD_FILE_PATH, upload.originalStoragePath) - end.putExtra(FileUploadWorker.ACCOUNT_NAME, upload.user.accountName) - end.putExtra(FileUploadWorker.EXTRA_UPLOAD_RESULT, uploadResult.isSuccess) - if (unlinkedFromRemotePath != null) { - end.putExtra(FileUploadWorker.EXTRA_LINKED_TO_PATH, unlinkedFromRemotePath) + Log_OC.d(TAG, "upload finished broadcast sent") + val intent = Intent(UPLOAD_FINISHED).apply { + // real remote path, after possible automatic renaming + putExtra(FileUploadWorker.EXTRA_REMOTE_PATH, upload.remotePath) + if (upload.wasRenamed()) { + upload.oldFile?.let { + putExtra(FileUploadWorker.EXTRA_OLD_REMOTE_PATH, it.remotePath) + } + } + putExtra(FileUploadWorker.EXTRA_OLD_FILE_PATH, upload.originalStoragePath) + putExtra(FileUploadWorker.ACCOUNT_NAME, upload.user.accountName) + putExtra(FileUploadWorker.EXTRA_UPLOAD_RESULT, uploadResult.isSuccess) + if (unlinkedFromRemotePath != null) { + putExtra(FileUploadWorker.EXTRA_LINKED_TO_PATH, unlinkedFromRemotePath) + } + setPackage(context.packageName) } - end.setPackage(context.packageName) - broadcastManager.sendBroadcast(end) + broadcastManager.sendBroadcast(intent) } } diff --git a/app/src/main/java/com/nextcloud/client/jobs/upload/FileUploadWorker.kt b/app/src/main/java/com/nextcloud/client/jobs/upload/FileUploadWorker.kt index 464bcf58d1cb..7ce855c8c128 100644 --- a/app/src/main/java/com/nextcloud/client/jobs/upload/FileUploadWorker.kt +++ b/app/src/main/java/com/nextcloud/client/jobs/upload/FileUploadWorker.kt @@ -22,8 +22,6 @@ import com.nextcloud.client.jobs.BackgroundJobManagerImpl import com.nextcloud.client.jobs.utils.UploadErrorNotificationManager import com.nextcloud.client.network.ConnectivityService import com.nextcloud.client.preferences.AppPreferences -import com.nextcloud.model.WorkerState -import com.nextcloud.model.WorkerStateObserver import com.nextcloud.utils.ForegroundServiceHelper import com.nextcloud.utils.extensions.getPercent import com.nextcloud.utils.extensions.updateStatus @@ -77,10 +75,6 @@ class FileUploadWorker( var currentUploadFileOperation: UploadFileOperation? = null - private const val UPLOADS_ADDED_MESSAGE = "UPLOADS_ADDED" - private const val UPLOAD_START_MESSAGE = "UPLOAD_START" - private const val UPLOAD_FINISH_MESSAGE = "UPLOAD_FINISH" - private const val BATCH_SIZE = 100 const val EXTRA_UPLOAD_RESULT = "RESULT" @@ -96,12 +90,6 @@ class FileUploadWorker( const val LOCAL_BEHAVIOUR_FORGET = 2 const val LOCAL_BEHAVIOUR_DELETE = 3 - fun getUploadsAddedMessage(): String = FileUploadWorker::class.java.name + UPLOADS_ADDED_MESSAGE - - fun getUploadStartMessage(): String = FileUploadWorker::class.java.name + UPLOAD_START_MESSAGE - - fun getUploadFinishMessage(): String = FileUploadWorker::class.java.name + UPLOAD_FINISH_MESSAGE - fun cancelCurrentUpload(remotePath: String, accountName: String, onCompleted: () -> Unit) { currentUploadFileOperation?.let { if (it.remotePath == remotePath && it.user.accountName == accountName) { @@ -143,9 +131,6 @@ class FileUploadWorker( val result = uploadFiles() backgroundJobManager.logEndOfWorker(workerName, result) notificationManager.dismissNotification() - if (result == Result.success()) { - setIdleWorkerState() - } result } catch (t: Throwable) { Log_OC.e(TAG, "Error caught at FileUploadWorker $t") @@ -201,15 +186,10 @@ class FileUploadWorker( private fun cleanup() { Log_OC.e(TAG, "FileUploadWorker stopped") - setIdleWorkerState() currentUploadFileOperation?.cancel(null) notificationManager.dismissNotification() } - private fun setIdleWorkerState() { - WorkerStateObserver.send(WorkerState.FileUploadCompleted(currentUploadFileOperation?.file)) - } - @Suppress("ReturnCount", "LongMethod", "DEPRECATION") private suspend fun uploadFiles(): Result = withContext(Dispatchers.IO) { val accountName = inputData.getString(ACCOUNT) @@ -265,6 +245,7 @@ class FileUploadWorker( return@withContext Result.failure() } + fileUploadBroadcastManager.sendAdded(context) val operation = createUploadFileOperation(upload, user) currentUploadFileOperation = operation fileUploadBroadcastManager.sendStarted(operation, context) @@ -307,7 +288,6 @@ class FileUploadWorker( (totalUploadSize > BATCH_SIZE && currentUploadIndex > 0) && currentUploadIndex % BATCH_SIZE == 0 if (shouldBroadcast) { - // delay broadcast fileUploadBroadcastManager.sendFinished( operation, result, diff --git a/app/src/main/java/com/nextcloud/model/WorkerState.kt b/app/src/main/java/com/nextcloud/model/WorkerState.kt index 7ed07584ac2d..d299045f695e 100644 --- a/app/src/main/java/com/nextcloud/model/WorkerState.kt +++ b/app/src/main/java/com/nextcloud/model/WorkerState.kt @@ -17,8 +17,5 @@ sealed class WorkerState { data class FileDownloadStarted(var user: User?, var currentDownload: DownloadFileOperation?) : WorkerState() data class FileDownloadCompleted(var currentFile: OCFile?) : WorkerState() - data class FileUploadStarted(var user: User?) : WorkerState() - data class FileUploadCompleted(var currentFile: OCFile?) : WorkerState() - data object OfflineOperationsCompleted : WorkerState() } diff --git a/app/src/main/java/com/owncloud/android/ui/activity/FileDisplayActivity.kt b/app/src/main/java/com/owncloud/android/ui/activity/FileDisplayActivity.kt index 2fa70a55eb61..9b6a8fafca33 100644 --- a/app/src/main/java/com/owncloud/android/ui/activity/FileDisplayActivity.kt +++ b/app/src/main/java/com/owncloud/android/ui/activity/FileDisplayActivity.kt @@ -64,9 +64,9 @@ import com.nextcloud.client.jobs.download.FileDownloadHelper import com.nextcloud.client.jobs.download.FileDownloadWorker import com.nextcloud.client.jobs.download.FileDownloadWorker.Companion.getDownloadAddedMessage import com.nextcloud.client.jobs.download.FileDownloadWorker.Companion.getDownloadFinishMessage +import com.nextcloud.client.jobs.upload.FileUploadBroadcastManager import com.nextcloud.client.jobs.upload.FileUploadHelper import com.nextcloud.client.jobs.upload.FileUploadWorker -import com.nextcloud.client.jobs.upload.FileUploadWorker.Companion.getUploadFinishMessage import com.nextcloud.client.media.PlayerServiceConnection import com.nextcloud.client.network.ClientFactory.CreationException import com.nextcloud.client.preferences.AppPreferences @@ -74,7 +74,6 @@ import com.nextcloud.client.utils.IntentUtil import com.nextcloud.model.WorkerState import com.nextcloud.model.WorkerState.FileDownloadCompleted import com.nextcloud.model.WorkerState.FileDownloadStarted -import com.nextcloud.model.WorkerState.FileUploadCompleted import com.nextcloud.model.WorkerState.OfflineOperationsCompleted import com.nextcloud.utils.extensions.getParcelableArgument import com.nextcloud.utils.extensions.isActive @@ -1409,7 +1408,7 @@ class FileDisplayActivity : } private fun registerUploadFinishReceiver() { - val filter = IntentFilter(getUploadFinishMessage()) + val filter = IntentFilter(FileUploadBroadcastManager.UPLOAD_FINISHED) mUploadFinishReceiver = UploadFinishReceiver() mUploadFinishReceiver?.let { localBroadcastManager.registerReceiver(it, filter) @@ -1668,13 +1667,11 @@ class FileDisplayActivity : * Once the file upload has finished -> update view */ private inner class UploadFinishReceiver : BroadcastReceiver() { - /** - * Once the file upload has finished -> update view - * - * - * [BroadcastReceiver] to enable upload feedback in UI - */ + private val tag = "UploadFinishReceiver" + override fun onReceive(context: Context?, intent: Intent) { + Log_OC.d(tag,"upload finish received broadcast") + val uploadedRemotePath = intent.getStringExtra(FileUploadWorker.EXTRA_REMOTE_PATH) val accountName = intent.getStringExtra(FileUploadWorker.ACCOUNT_NAME) val account = getAccount() @@ -1909,12 +1906,6 @@ class FileDisplayActivity : previewFile(state) } - is FileUploadCompleted -> { - state.currentFile?.let { - ocFileListFragment?.adapter?.insertFile(it) - } - } - is OfflineOperationsCompleted -> { refreshCurrentDirectory() } diff --git a/app/src/main/java/com/owncloud/android/ui/activity/UploadListActivity.java b/app/src/main/java/com/owncloud/android/ui/activity/UploadListActivity.java index 18ad11840361..16e7f2d9fda6 100755 --- a/app/src/main/java/com/owncloud/android/ui/activity/UploadListActivity.java +++ b/app/src/main/java/com/owncloud/android/ui/activity/UploadListActivity.java @@ -25,8 +25,8 @@ import com.nextcloud.client.core.Clock; import com.nextcloud.client.device.PowerManagementService; import com.nextcloud.client.jobs.BackgroundJobManager; +import com.nextcloud.client.jobs.upload.FileUploadBroadcastManager; import com.nextcloud.client.jobs.upload.FileUploadHelper; -import com.nextcloud.client.jobs.upload.FileUploadWorker; import com.nextcloud.client.utils.Throttler; import com.owncloud.android.R; import com.owncloud.android.databinding.UploadListLayoutBinding; @@ -56,7 +56,7 @@ public class UploadListActivity extends FileActivity { private static final String TAG = UploadListActivity.class.getSimpleName(); - private UploadMessagesReceiver uploadMessagesReceiver; + private UploadFinishReceiver uploadFinishReceiver; private UploadListAdapter uploadListAdapter; @@ -182,12 +182,12 @@ protected void onResume() { super.onResume(); // Listen for upload messages - uploadMessagesReceiver = new UploadMessagesReceiver(); + uploadFinishReceiver = new UploadFinishReceiver(); IntentFilter uploadIntentFilter = new IntentFilter(); - uploadIntentFilter.addAction(FileUploadWorker.Companion.getUploadsAddedMessage()); - uploadIntentFilter.addAction(FileUploadWorker.Companion.getUploadStartMessage()); - uploadIntentFilter.addAction(FileUploadWorker.Companion.getUploadFinishMessage()); - localBroadcastManager.registerReceiver(uploadMessagesReceiver, uploadIntentFilter); + uploadIntentFilter.addAction(FileUploadBroadcastManager.UPLOAD_ADDED); + uploadIntentFilter.addAction(FileUploadBroadcastManager.UPLOAD_STARTED); + uploadIntentFilter.addAction(FileUploadBroadcastManager.UPLOAD_FINISHED); + localBroadcastManager.registerReceiver(uploadFinishReceiver, uploadIntentFilter); Log_OC.v(TAG, "onResume() end"); @@ -196,9 +196,9 @@ protected void onResume() { @Override protected void onPause() { Log_OC.v(TAG, "onPause() start"); - if (uploadMessagesReceiver != null) { - localBroadcastManager.unregisterReceiver(uploadMessagesReceiver); - uploadMessagesReceiver = null; + if (uploadFinishReceiver != null) { + localBroadcastManager.unregisterReceiver(uploadFinishReceiver); + uploadFinishReceiver = null; } super.onPause(); Log_OC.v(TAG, "onPause() end"); @@ -308,13 +308,9 @@ public void onRemoteOperationFinish(RemoteOperation operation, RemoteOperationRe /** * Once the file upload has changed its status -> update uploads list view */ - private class UploadMessagesReceiver extends BroadcastReceiver { - /** - * {@link BroadcastReceiver} to enable syncing feedback in UI - */ + private class UploadFinishReceiver extends BroadcastReceiver { @Override public void onReceive(Context context, Intent intent) { - throttler.run("update_upload_list", () -> uploadListAdapter.loadUploadItemsFromDb()); } } diff --git a/app/src/main/java/com/owncloud/android/ui/fragment/FileDetailFragment.java b/app/src/main/java/com/owncloud/android/ui/fragment/FileDetailFragment.java index 49df63f254eb..22b2ffd82e44 100644 --- a/app/src/main/java/com/owncloud/android/ui/fragment/FileDetailFragment.java +++ b/app/src/main/java/com/owncloud/android/ui/fragment/FileDetailFragment.java @@ -231,7 +231,6 @@ public View onCreateView(@NonNull LayoutInflater inflater, ViewGroup container, } binding = FileDetailsFragmentBinding.inflate(inflater, container, false); - observeWorkerState(); view = binding.getRoot(); if (getFile() == null || user == null) { @@ -624,21 +623,6 @@ public void onDownloadProgress(FileDownloadProgressEvent event) { binding.progressBar.invalidate(); } - private void observeWorkerState() { - ActivityExtensionsKt.observeWorker(requireActivity(), state -> { - if (binding == null) { - return Unit.INSTANCE; - } - - if (state instanceof WorkerState.FileUploadStarted) { - binding.progressText.setText(R.string.uploader_upload_in_progress_ticker); - } else { - binding.progressBlock.setVisibility(View.GONE); - } - return Unit.INSTANCE; - }); - } - private void setFileModificationTimestamp(OCFile file, boolean showDetailedTimestamp) { if (showDetailedTimestamp) { binding.lastModificationTimestamp.setText(DisplayUtils.unixTimeToHumanReadable(file.getModificationTimestamp())); diff --git a/app/src/main/java/com/owncloud/android/ui/preview/PreviewImageActivity.kt b/app/src/main/java/com/owncloud/android/ui/preview/PreviewImageActivity.kt index fae01995f9c3..e028f0023996 100644 --- a/app/src/main/java/com/owncloud/android/ui/preview/PreviewImageActivity.kt +++ b/app/src/main/java/com/owncloud/android/ui/preview/PreviewImageActivity.kt @@ -10,7 +10,6 @@ import android.content.BroadcastReceiver import android.content.Context import android.content.Intent import android.content.IntentFilter -import android.graphics.drawable.ColorDrawable import android.os.Bundle import android.view.MenuItem import android.view.View @@ -26,7 +25,7 @@ import com.nextcloud.client.editimage.EditImageActivity import com.nextcloud.client.jobs.download.FileDownloadHelper import com.nextcloud.client.jobs.download.FileDownloadWorker import com.nextcloud.client.jobs.download.FileDownloadWorker.Companion.getDownloadFinishMessage -import com.nextcloud.client.jobs.upload.FileUploadWorker.Companion.getUploadFinishMessage +import com.nextcloud.client.jobs.upload.FileUploadBroadcastManager import com.nextcloud.client.preferences.AppPreferences import com.nextcloud.model.WorkerState import com.nextcloud.utils.extensions.getParcelableArgument @@ -389,7 +388,7 @@ class PreviewImageActivity : localBroadcastManager.registerReceiver(downloadFinishReceiver!!, downloadIntentFilter) val uploadFinishReceiver = UploadFinishReceiver() - val uploadIntentFilter = IntentFilter(getUploadFinishMessage()) + val uploadIntentFilter = IntentFilter(FileUploadBroadcastManager.UPLOAD_FINISHED) localBroadcastManager.registerReceiver(uploadFinishReceiver, uploadIntentFilter) } From 8d2299a0e0e2188812779077c1cfe1565f426cff Mon Sep 17 00:00:00 2001 From: alperozturk96 Date: Mon, 19 Jan 2026 10:40:52 +0100 Subject: [PATCH 198/216] add documentation and simplify Signed-off-by: alperozturk96 --- .../jobs/upload/FileUploadBroadcastManager.kt | 33 ++++++++++++++----- .../client/jobs/upload/FileUploadWorker.kt | 5 ++- .../ui/activity/FileDisplayActivity.kt | 2 +- .../ui/activity/UploadListActivity.java | 17 +++++----- .../ui/preview/PreviewImageActivity.kt | 9 +++-- 5 files changed, 42 insertions(+), 24 deletions(-) diff --git a/app/src/main/java/com/nextcloud/client/jobs/upload/FileUploadBroadcastManager.kt b/app/src/main/java/com/nextcloud/client/jobs/upload/FileUploadBroadcastManager.kt index e7d3233644ed..acd57bb607cc 100644 --- a/app/src/main/java/com/nextcloud/client/jobs/upload/FileUploadBroadcastManager.kt +++ b/app/src/main/java/com/nextcloud/client/jobs/upload/FileUploadBroadcastManager.kt @@ -1,7 +1,7 @@ /* * Nextcloud - Android Client * - * SPDX-FileCopyrightText: 2023 Alper Ozturk + * SPDX-FileCopyrightText: 2026 Alper Ozturk * SPDX-FileCopyrightText: 2023 Nextcloud GmbH * SPDX-License-Identifier: AGPL-3.0-or-later OR GPL-2.0-only */ @@ -25,13 +25,23 @@ import com.owncloud.android.operations.UploadFileOperation class FileUploadBroadcastManager(private val broadcastManager: LocalBroadcastManager) { companion object { - private const val TAG = "📣" + "FileUploadBroadcastManager" + private const val TAG = "📣" + "FileUploadBroadcastManager" const val UPLOAD_ADDED = "UPLOAD_ADDED" - const val UPLOAD_STARTED = "UPLOAD_START" - const val UPLOAD_FINISHED = "UPLOAD_FINISH" + const val UPLOAD_STARTED = "UPLOAD_STARTED" + const val UPLOAD_FINISHED = "UPLOAD_FINISHED" } + /** + * Sends a broadcast indicating that an upload added + * + * ### Triggered when + * - [UploadFileOperation] added + * + * ### Observed by + * - [com.owncloud.android.ui.activity.UploadListActivity.UploadFinishReceiver] + * + */ fun sendAdded(context: Context) { Log_OC.d(TAG, "upload added broadcast sent") val intent = Intent(UPLOAD_ADDED).apply { @@ -40,10 +50,17 @@ class FileUploadBroadcastManager(private val broadcastManager: LocalBroadcastMan broadcastManager.sendBroadcast(intent) } - fun sendStarted( - upload: UploadFileOperation, - context: Context, - ) { + /** + * Sends a broadcast indicating that an upload started + * + * ### Triggered when + * - [UploadFileOperation] started + * + * ### Observed by + * - [com.owncloud.android.ui.activity.UploadListActivity.UploadFinishReceiver] + * + */ + fun sendStarted(upload: UploadFileOperation, context: Context) { Log_OC.d(TAG, "upload started broadcast sent") val intent = Intent(UPLOAD_STARTED).apply { putExtra(FileUploadWorker.EXTRA_REMOTE_PATH, upload.remotePath) // real remote diff --git a/app/src/main/java/com/nextcloud/client/jobs/upload/FileUploadWorker.kt b/app/src/main/java/com/nextcloud/client/jobs/upload/FileUploadWorker.kt index 7ce855c8c128..4b16dedaff77 100644 --- a/app/src/main/java/com/nextcloud/client/jobs/upload/FileUploadWorker.kt +++ b/app/src/main/java/com/nextcloud/client/jobs/upload/FileUploadWorker.kt @@ -284,8 +284,11 @@ class FileUploadWorker( operation: UploadFileOperation, result: RemoteOperationResult<*> ) { + val isLastUpload = currentUploadIndex == totalUploadSize + val shouldBroadcast = - (totalUploadSize > BATCH_SIZE && currentUploadIndex > 0) && currentUploadIndex % BATCH_SIZE == 0 + (currentUploadIndex % BATCH_SIZE == 0 && totalUploadSize > BATCH_SIZE) || + isLastUpload if (shouldBroadcast) { fileUploadBroadcastManager.sendFinished( diff --git a/app/src/main/java/com/owncloud/android/ui/activity/FileDisplayActivity.kt b/app/src/main/java/com/owncloud/android/ui/activity/FileDisplayActivity.kt index 9b6a8fafca33..f2b51957e73a 100644 --- a/app/src/main/java/com/owncloud/android/ui/activity/FileDisplayActivity.kt +++ b/app/src/main/java/com/owncloud/android/ui/activity/FileDisplayActivity.kt @@ -1670,7 +1670,7 @@ class FileDisplayActivity : private val tag = "UploadFinishReceiver" override fun onReceive(context: Context?, intent: Intent) { - Log_OC.d(tag,"upload finish received broadcast") + Log_OC.d(tag, "upload finish received broadcast") val uploadedRemotePath = intent.getStringExtra(FileUploadWorker.EXTRA_REMOTE_PATH) val accountName = intent.getStringExtra(FileUploadWorker.ACCOUNT_NAME) diff --git a/app/src/main/java/com/owncloud/android/ui/activity/UploadListActivity.java b/app/src/main/java/com/owncloud/android/ui/activity/UploadListActivity.java index 16e7f2d9fda6..7cd2b526c49b 100755 --- a/app/src/main/java/com/owncloud/android/ui/activity/UploadListActivity.java +++ b/app/src/main/java/com/owncloud/android/ui/activity/UploadListActivity.java @@ -177,9 +177,9 @@ private void refresh() { } @Override - protected void onResume() { - Log_OC.v(TAG, "onResume() start"); - super.onResume(); + protected void onStart() { + Log_OC.v(TAG, "onStart() start"); + super.onStart(); // Listen for upload messages uploadFinishReceiver = new UploadFinishReceiver(); @@ -189,19 +189,18 @@ protected void onResume() { uploadIntentFilter.addAction(FileUploadBroadcastManager.UPLOAD_FINISHED); localBroadcastManager.registerReceiver(uploadFinishReceiver, uploadIntentFilter); - Log_OC.v(TAG, "onResume() end"); - + Log_OC.v(TAG, "onStart() end"); } @Override - protected void onPause() { - Log_OC.v(TAG, "onPause() start"); + protected void onStop() { + Log_OC.v(TAG, "onStop() start"); if (uploadFinishReceiver != null) { localBroadcastManager.unregisterReceiver(uploadFinishReceiver); uploadFinishReceiver = null; } - super.onPause(); - Log_OC.v(TAG, "onPause() end"); + super.onStop(); + Log_OC.v(TAG, "onStop() end"); } @Override diff --git a/app/src/main/java/com/owncloud/android/ui/preview/PreviewImageActivity.kt b/app/src/main/java/com/owncloud/android/ui/preview/PreviewImageActivity.kt index e028f0023996..c6f995225862 100644 --- a/app/src/main/java/com/owncloud/android/ui/preview/PreviewImageActivity.kt +++ b/app/src/main/java/com/owncloud/android/ui/preview/PreviewImageActivity.kt @@ -256,6 +256,7 @@ class PreviewImageActivity : public override fun onStart() { super.onStart() + registerReceivers() val optionalUser = user if (optionalUser.isPresent) { var file: OCFile? = file ?: throw IllegalStateException("Instanced with a NULL OCFile") @@ -380,9 +381,7 @@ class PreviewImageActivity : } } - override fun onResume() { - super.onResume() - + private fun registerReceivers() { downloadFinishReceiver = DownloadFinishReceiver() val downloadIntentFilter = IntentFilter(getDownloadFinishMessage()) localBroadcastManager.registerReceiver(downloadFinishReceiver!!, downloadIntentFilter) @@ -392,13 +391,13 @@ class PreviewImageActivity : localBroadcastManager.registerReceiver(uploadFinishReceiver, uploadIntentFilter) } - public override fun onPause() { + public override fun onStop() { if (downloadFinishReceiver != null) { localBroadcastManager.unregisterReceiver(downloadFinishReceiver!!) downloadFinishReceiver = null } - super.onPause() + super.onStop() } private fun backToDisplayActivity() { From 053a142402a3efb4c589229d3e8251b61e0ee79d Mon Sep 17 00:00:00 2001 From: alperozturk96 Date: Mon, 19 Jan 2026 10:44:18 +0100 Subject: [PATCH 199/216] delete unused functions Signed-off-by: alperozturk96 --- .../client/jobs/upload/FileUploadWorker.kt | 15 ++++++-------- .../android/ui/adapter/OCFileListAdapter.java | 20 ------------------- 2 files changed, 6 insertions(+), 29 deletions(-) diff --git a/app/src/main/java/com/nextcloud/client/jobs/upload/FileUploadWorker.kt b/app/src/main/java/com/nextcloud/client/jobs/upload/FileUploadWorker.kt index 4b16dedaff77..112fc17372b6 100644 --- a/app/src/main/java/com/nextcloud/client/jobs/upload/FileUploadWorker.kt +++ b/app/src/main/java/com/nextcloud/client/jobs/upload/FileUploadWorker.kt @@ -133,9 +133,13 @@ class FileUploadWorker( notificationManager.dismissNotification() result } catch (t: Throwable) { - Log_OC.e(TAG, "Error caught at FileUploadWorker $t") - cleanup() + Log_OC.e(TAG, "exception $t") + currentUploadFileOperation?.cancel(null) Result.failure() + } finally { + // Ensure all database operations are complete before signaling completion + uploadsStorageManager.notifyObserversNow() + notificationManager.dismissNotification() } private suspend fun trySetForeground() { @@ -183,13 +187,6 @@ class FileUploadWorker( .setSilent(true) .build() - private fun cleanup() { - Log_OC.e(TAG, "FileUploadWorker stopped") - - currentUploadFileOperation?.cancel(null) - notificationManager.dismissNotification() - } - @Suppress("ReturnCount", "LongMethod", "DEPRECATION") private suspend fun uploadFiles(): Result = withContext(Dispatchers.IO) { val accountName = inputData.getString(ACCOUNT) diff --git a/app/src/main/java/com/owncloud/android/ui/adapter/OCFileListAdapter.java b/app/src/main/java/com/owncloud/android/ui/adapter/OCFileListAdapter.java index 08f690ccbe93..e39d39d02bbf 100644 --- a/app/src/main/java/com/owncloud/android/ui/adapter/OCFileListAdapter.java +++ b/app/src/main/java/com/owncloud/android/ui/adapter/OCFileListAdapter.java @@ -1044,24 +1044,4 @@ public void cleanup() { ocFileListDelegate.cleanup(); helper.cleanup(); } - - public void insertFile(@NonNull OCFile file) { - mFiles.add(file); - mFilesAll.add(file); - - // Re-sort to maintain order - if (sortOrder != null) { - boolean foldersBeforeFiles = preferences.isSortFoldersBeforeFiles(); - boolean favoritesFirst = preferences.isSortFavoritesFirst(); - mFiles = sortOrder.sortCloudFiles(mFiles, foldersBeforeFiles, favoritesFirst); - } - - // Find actual position and notify - int position = mFiles.indexOf(file); - if (shouldShowHeader()) { - position++; - } - - notifyItemInserted(position); - } } From da2461383b77c370aa795026688e564b9755f3ad Mon Sep 17 00:00:00 2001 From: alperozturk96 Date: Mon, 19 Jan 2026 11:09:27 +0100 Subject: [PATCH 200/216] add upload finish event for auto upload worker Signed-off-by: alperozturk96 --- .../client/jobs/BackgroundJobFactory.kt | 5 ++-- .../jobs/autoUpload/AutoUploadWorker.kt | 23 +++++++++++++++++-- 2 files changed, 24 insertions(+), 4 deletions(-) diff --git a/app/src/main/java/com/nextcloud/client/jobs/BackgroundJobFactory.kt b/app/src/main/java/com/nextcloud/client/jobs/BackgroundJobFactory.kt index 3e67df51fa92..4b1dd1d659b2 100644 --- a/app/src/main/java/com/nextcloud/client/jobs/BackgroundJobFactory.kt +++ b/app/src/main/java/com/nextcloud/client/jobs/BackgroundJobFactory.kt @@ -25,9 +25,9 @@ import com.nextcloud.client.integrations.deck.DeckApi import com.nextcloud.client.jobs.autoUpload.AutoUploadWorker import com.nextcloud.client.jobs.autoUpload.FileSystemRepository import com.nextcloud.client.jobs.download.FileDownloadWorker +import com.nextcloud.client.jobs.folderDownload.FolderDownloadWorker import com.nextcloud.client.jobs.metadata.MetadataWorker import com.nextcloud.client.jobs.offlineOperations.OfflineOperationsWorker -import com.nextcloud.client.jobs.folderDownload.FolderDownloadWorker import com.nextcloud.client.jobs.upload.FileUploadWorker import com.nextcloud.client.logger.Logger import com.nextcloud.client.network.ConnectivityService @@ -180,7 +180,8 @@ class BackgroundJobFactory @Inject constructor( syncedFolderProvider = syncedFolderProvider, backgroundJobManager = backgroundJobManager.get(), repository = FileSystemRepository(dao = database.fileSystemDao(), context), - viewThemeUtils = viewThemeUtils.get() + viewThemeUtils = viewThemeUtils.get(), + localBroadcastManager = localBroadcastManager.get() ) private fun createOfflineSyncWork(context: Context, params: WorkerParameters): OfflineSyncWork = OfflineSyncWork( diff --git a/app/src/main/java/com/nextcloud/client/jobs/autoUpload/AutoUploadWorker.kt b/app/src/main/java/com/nextcloud/client/jobs/autoUpload/AutoUploadWorker.kt index db464ccfa11d..66de1a81ba06 100644 --- a/app/src/main/java/com/nextcloud/client/jobs/autoUpload/AutoUploadWorker.kt +++ b/app/src/main/java/com/nextcloud/client/jobs/autoUpload/AutoUploadWorker.kt @@ -11,6 +11,7 @@ import android.app.Notification import android.content.Context import android.content.res.Resources import androidx.exifinterface.media.ExifInterface +import androidx.localbroadcastmanager.content.LocalBroadcastManager import androidx.work.CoroutineWorker import androidx.work.ForegroundInfo import androidx.work.WorkerParameters @@ -21,6 +22,7 @@ import com.nextcloud.client.database.entity.toOCUpload import com.nextcloud.client.database.entity.toUploadEntity import com.nextcloud.client.device.PowerManagementService import com.nextcloud.client.jobs.BackgroundJobManager +import com.nextcloud.client.jobs.upload.FileUploadBroadcastManager import com.nextcloud.client.jobs.upload.FileUploadWorker import com.nextcloud.client.jobs.utils.UploadErrorNotificationManager import com.nextcloud.client.network.ConnectivityService @@ -63,7 +65,8 @@ class AutoUploadWorker( private val syncedFolderProvider: SyncedFolderProvider, private val backgroundJobManager: BackgroundJobManager, private val repository: FileSystemRepository, - val viewThemeUtils: ViewThemeUtils + val viewThemeUtils: ViewThemeUtils, + private val localBroadcastManager: LocalBroadcastManager ) : CoroutineWorker(context, params) { companion object { @@ -75,6 +78,7 @@ class AutoUploadWorker( } private val helper = AutoUploadHelper() + private val fileUploadBroadcastManager = FileUploadBroadcastManager(localBroadcastManager) private lateinit var syncedFolder: SyncedFolder private val notificationManager = AutoUploadNotificationManager(context, viewThemeUtils, NOTIFICATION_ID) @@ -282,6 +286,7 @@ class AutoUploadWorker( updateNotification() var lastId = 0 + while (true) { val filePathsWithIds = repository.getFilePathsWithIds(syncedFolder, lastId) @@ -291,7 +296,7 @@ class AutoUploadWorker( } Log_OC.d(TAG, "Processing batch: lastId=$lastId, count=${filePathsWithIds.size}") - filePathsWithIds.forEach { (path, id) -> + filePathsWithIds.forEachIndexed { batchIndex, (path, id) -> val file = File(path) val localPath = file.absolutePath val remotePath = getRemotePath( @@ -354,6 +359,11 @@ class AutoUploadWorker( Log_OC.w(TAG, "Marked CONFLICT file as handled: $localPath") } } + + val isLastInBatch = (batchIndex == filePathsWithIds.size - 1) + if (isLastInBatch) { + sendUploadFinishEvent(operation, result) + } } catch (e: Exception) { uploadsStorageManager.updateStatus( uploadEntity, @@ -524,4 +534,13 @@ class AutoUploadWorker( } return lastModificationTime } + + private fun sendUploadFinishEvent(operation: UploadFileOperation, result: RemoteOperationResult<*>) { + fileUploadBroadcastManager.sendFinished( + operation, + result, + operation.oldFile?.storagePath, + context + ) + } } From ae0bc28f62a3e1292de271627039cebf5e46b2d4 Mon Sep 17 00:00:00 2001 From: alperozturk96 Date: Mon, 19 Jan 2026 11:14:00 +0100 Subject: [PATCH 201/216] add upload finish event for auto upload worker Signed-off-by: alperozturk96 --- .../com/nextcloud/client/jobs/autoUpload/AutoUploadWorker.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/src/main/java/com/nextcloud/client/jobs/autoUpload/AutoUploadWorker.kt b/app/src/main/java/com/nextcloud/client/jobs/autoUpload/AutoUploadWorker.kt index 66de1a81ba06..d650ca89daae 100644 --- a/app/src/main/java/com/nextcloud/client/jobs/autoUpload/AutoUploadWorker.kt +++ b/app/src/main/java/com/nextcloud/client/jobs/autoUpload/AutoUploadWorker.kt @@ -66,7 +66,7 @@ class AutoUploadWorker( private val backgroundJobManager: BackgroundJobManager, private val repository: FileSystemRepository, val viewThemeUtils: ViewThemeUtils, - private val localBroadcastManager: LocalBroadcastManager + localBroadcastManager: LocalBroadcastManager ) : CoroutineWorker(context, params) { companion object { From fd5dc516a1bd0e6f16b5cc2039772a767144b14d Mon Sep 17 00:00:00 2001 From: alperozturk96 Date: Mon, 19 Jan 2026 11:14:29 +0100 Subject: [PATCH 202/216] add upload finish event for auto upload worker Signed-off-by: alperozturk96 --- .../nextcloud/client/jobs/upload/FileUploadBroadcastManager.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/src/main/java/com/nextcloud/client/jobs/upload/FileUploadBroadcastManager.kt b/app/src/main/java/com/nextcloud/client/jobs/upload/FileUploadBroadcastManager.kt index acd57bb607cc..85e533d2b9fd 100644 --- a/app/src/main/java/com/nextcloud/client/jobs/upload/FileUploadBroadcastManager.kt +++ b/app/src/main/java/com/nextcloud/client/jobs/upload/FileUploadBroadcastManager.kt @@ -2,7 +2,7 @@ * Nextcloud - Android Client * * SPDX-FileCopyrightText: 2026 Alper Ozturk - * SPDX-FileCopyrightText: 2023 Nextcloud GmbH + * SPDX-FileCopyrightText: 2026 Nextcloud GmbH * SPDX-License-Identifier: AGPL-3.0-or-later OR GPL-2.0-only */ package com.nextcloud.client.jobs.upload From 617dbc6363800892f5eb985028ee82674c8724b7 Mon Sep 17 00:00:00 2001 From: alperozturk96 Date: Mon, 19 Jan 2026 11:25:33 +0100 Subject: [PATCH 203/216] add upload started, added event Signed-off-by: alperozturk96 --- .../com/nextcloud/client/jobs/autoUpload/AutoUploadWorker.kt | 2 ++ .../nextcloud/client/jobs/upload/FileUploadBroadcastManager.kt | 2 +- .../java/com/nextcloud/client/jobs/upload/FileUploadWorker.kt | 2 +- 3 files changed, 4 insertions(+), 2 deletions(-) diff --git a/app/src/main/java/com/nextcloud/client/jobs/autoUpload/AutoUploadWorker.kt b/app/src/main/java/com/nextcloud/client/jobs/autoUpload/AutoUploadWorker.kt index d650ca89daae..ac0aa3769d39 100644 --- a/app/src/main/java/com/nextcloud/client/jobs/autoUpload/AutoUploadWorker.kt +++ b/app/src/main/java/com/nextcloud/client/jobs/autoUpload/AutoUploadWorker.kt @@ -331,10 +331,12 @@ class AutoUploadWorker( uploadEntity = uploadEntity.copy(id = generatedId.toInt()) upload.uploadId = generatedId + fileUploadBroadcastManager.sendAdded(context) val operation = createUploadFileOperation(upload, user) Log_OC.d(TAG, "🕒 uploading: $localPath, id: $generatedId") val result = operation.execute(client) + fileUploadBroadcastManager.sendStarted(operation, context) uploadsStorageManager.updateStatus(uploadEntity, result.isSuccess) UploadErrorNotificationManager.handleResult( diff --git a/app/src/main/java/com/nextcloud/client/jobs/upload/FileUploadBroadcastManager.kt b/app/src/main/java/com/nextcloud/client/jobs/upload/FileUploadBroadcastManager.kt index 85e533d2b9fd..0164bcad2001 100644 --- a/app/src/main/java/com/nextcloud/client/jobs/upload/FileUploadBroadcastManager.kt +++ b/app/src/main/java/com/nextcloud/client/jobs/upload/FileUploadBroadcastManager.kt @@ -33,7 +33,7 @@ class FileUploadBroadcastManager(private val broadcastManager: LocalBroadcastMan } /** - * Sends a broadcast indicating that an upload added + * Sends a broadcast indicating that an upload added into database. * * ### Triggered when * - [UploadFileOperation] added diff --git a/app/src/main/java/com/nextcloud/client/jobs/upload/FileUploadWorker.kt b/app/src/main/java/com/nextcloud/client/jobs/upload/FileUploadWorker.kt index 112fc17372b6..ea0bac258db8 100644 --- a/app/src/main/java/com/nextcloud/client/jobs/upload/FileUploadWorker.kt +++ b/app/src/main/java/com/nextcloud/client/jobs/upload/FileUploadWorker.kt @@ -245,7 +245,6 @@ class FileUploadWorker( fileUploadBroadcastManager.sendAdded(context) val operation = createUploadFileOperation(upload, user) currentUploadFileOperation = operation - fileUploadBroadcastManager.sendStarted(operation, context) val currentIndex = (index + 1) val currentUploadIndex = (currentIndex + previouslyUploadedFileSize) @@ -344,6 +343,7 @@ class FileUploadWorker( val file = File(operation.originalStoragePath) val remoteId: String? = operation.file.remoteId task.execute(ThumbnailsCacheManager.ThumbnailGenerationTaskObject(file, remoteId)) + fileUploadBroadcastManager.sendStarted(operation, context) } catch (e: Exception) { Log_OC.e(TAG, "Error uploading", e) result = RemoteOperationResult(e) From 9b1aa1cbd7716fa822c2132aa047e3e970aa719f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alper=20=C3=96zt=C3=BCrk?= <67455295+alperozturk96@users.noreply.github.com> Date: Thu, 29 Jan 2026 15:09:08 +0100 Subject: [PATCH 204/216] Update app/src/main/java/com/nextcloud/client/jobs/upload/FileUploadBroadcastManager.kt MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Tom <70907959+ZetaTom@users.noreply.github.com> Signed-off-by: Alper Öztürk <67455295+alperozturk96@users.noreply.github.com> --- .../nextcloud/client/jobs/upload/FileUploadBroadcastManager.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/src/main/java/com/nextcloud/client/jobs/upload/FileUploadBroadcastManager.kt b/app/src/main/java/com/nextcloud/client/jobs/upload/FileUploadBroadcastManager.kt index 0164bcad2001..cb6a2e30368d 100644 --- a/app/src/main/java/com/nextcloud/client/jobs/upload/FileUploadBroadcastManager.kt +++ b/app/src/main/java/com/nextcloud/client/jobs/upload/FileUploadBroadcastManager.kt @@ -33,7 +33,7 @@ class FileUploadBroadcastManager(private val broadcastManager: LocalBroadcastMan } /** - * Sends a broadcast indicating that an upload added into database. + * Sends a broadcast to indicate that an upload has been added to the database. * * ### Triggered when * - [UploadFileOperation] added From 0595b655089b998d89ba6d1db2da48e173a652b8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alper=20=C3=96zt=C3=BCrk?= <67455295+alperozturk96@users.noreply.github.com> Date: Thu, 29 Jan 2026 15:09:25 +0100 Subject: [PATCH 205/216] Update app/src/main/java/com/nextcloud/client/jobs/upload/FileUploadBroadcastManager.kt MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Tom <70907959+ZetaTom@users.noreply.github.com> Signed-off-by: Alper Öztürk <67455295+alperozturk96@users.noreply.github.com> --- .../nextcloud/client/jobs/upload/FileUploadBroadcastManager.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/src/main/java/com/nextcloud/client/jobs/upload/FileUploadBroadcastManager.kt b/app/src/main/java/com/nextcloud/client/jobs/upload/FileUploadBroadcastManager.kt index cb6a2e30368d..28965d7cbef4 100644 --- a/app/src/main/java/com/nextcloud/client/jobs/upload/FileUploadBroadcastManager.kt +++ b/app/src/main/java/com/nextcloud/client/jobs/upload/FileUploadBroadcastManager.kt @@ -51,7 +51,7 @@ class FileUploadBroadcastManager(private val broadcastManager: LocalBroadcastMan } /** - * Sends a broadcast indicating that an upload started + * Sends a broadcast indicating that an upload started. * * ### Triggered when * - [UploadFileOperation] started From bacae96b3287a1b80df86b3a8a040d64217bdec2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alper=20=C3=96zt=C3=BCrk?= <67455295+alperozturk96@users.noreply.github.com> Date: Thu, 29 Jan 2026 15:09:49 +0100 Subject: [PATCH 206/216] Update app/src/main/java/com/nextcloud/client/jobs/upload/FileUploadBroadcastManager.kt MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Tom <70907959+ZetaTom@users.noreply.github.com> Signed-off-by: Alper Öztürk <67455295+alperozturk96@users.noreply.github.com> --- .../client/jobs/upload/FileUploadBroadcastManager.kt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/app/src/main/java/com/nextcloud/client/jobs/upload/FileUploadBroadcastManager.kt b/app/src/main/java/com/nextcloud/client/jobs/upload/FileUploadBroadcastManager.kt index 28965d7cbef4..148e869ee8fc 100644 --- a/app/src/main/java/com/nextcloud/client/jobs/upload/FileUploadBroadcastManager.kt +++ b/app/src/main/java/com/nextcloud/client/jobs/upload/FileUploadBroadcastManager.kt @@ -17,8 +17,8 @@ import com.owncloud.android.operations.UploadFileOperation /** * Manages local broadcasts related to file upload lifecycle events. * - * This class is responsible for notifying interested components about - * upload queue changes and upload state transitions (added, started, finished). + * This class is responsible for notifying components about upload + * queue changes and upload state transitions (added, started, finished). * * All broadcasts are sent via [LocalBroadcastManager]. */ From 6a49c88630c0f5e7db9d7e0cd707fa297d067d5a Mon Sep 17 00:00:00 2001 From: Nextcloud bot Date: Fri, 30 Jan 2026 03:07:56 +0000 Subject: [PATCH 207/216] fix(l10n): Update translations from Transifex Signed-off-by: Nextcloud bot --- app/src/main/res/values-cs-rCZ/strings.xml | 6 ++++-- app/src/main/res/values-sl/strings.xml | 6 ++++++ 2 files changed, 10 insertions(+), 2 deletions(-) diff --git a/app/src/main/res/values-cs-rCZ/strings.xml b/app/src/main/res/values-cs-rCZ/strings.xml index 1dc01ee685eb..257b8a8f464c 100644 --- a/app/src/main/res/values-cs-rCZ/strings.xml +++ b/app/src/main/res/values-cs-rCZ/strings.xml @@ -56,6 +56,7 @@ Při vytváření úlohy se vyskytla chyba Úkol vytvořen Při mazání úlohy se vyskytla chyba + Úkol smazán Seznam úkolů je prázdný. Zkontrolujte nastavení aplikace Asistent. Nedaří se získat seznam úloh – zkontrolujte připojení k Internetu. Smazat úlohu @@ -404,7 +405,7 @@ Nepodařilo se vytvořit dialog o konfliktu Předání souboru správci stahování se nezdařilo Soubor se nepodařilo vytisknout - Selhalo spuštění akce! + Spuštění akce se nezdařilo! Editor se nepodařilo spustit Nepodařilo se aktualizovat uživatelské rozhraní Přidat do oblíbených @@ -502,6 +503,7 @@ %1$d z %2$d · %3$s Při synchronizování složky %s došlo k chybě Nedostatek prostoru na disku – synchronizace zrušena + %s složka synchronizována Synchronizování … Nejsou zde žádné složky Název složky je třeba vyplnit @@ -971,7 +973,7 @@ Synchronizovat Synchronizovat i tak Vyřešit konflikty - Detekovány konflikty s nahráváním souborů. Otevřít nastavení nahrávání a vyřešit je. + Zjištěny konflikty s nahráváním souborů. Otevřete nastavení nahrávání a vyřešte je. Konflikty při nahrávání souborů Nalezeny konflikty Složka %1$s už neexistuje diff --git a/app/src/main/res/values-sl/strings.xml b/app/src/main/res/values-sl/strings.xml index 57c73057ea50..e8a7be916e66 100644 --- a/app/src/main/res/values-sl/strings.xml +++ b/app/src/main/res/values-sl/strings.xml @@ -991,6 +991,12 @@ %1$d datoteke %1$d datotek + + %1$d predmet + %1$d predmeta + %1$d predmeti + %1$d predmetov + Pokaži %1$d skrito mapo Pokaži %1$d skriti mapi From d3b1a5db989a017209831ea36f04999d3aab35db Mon Sep 17 00:00:00 2001 From: alperozturk96 Date: Fri, 30 Jan 2026 11:06:10 +0100 Subject: [PATCH 208/216] fix(strings): file upload limit message Signed-off-by: alperozturk96 --- .../com/nextcloud/strings/StringsTests.kt | 37 +++++++++++++++++++ .../client/jobs/upload/FileUploadHelper.kt | 2 +- 2 files changed, 38 insertions(+), 1 deletion(-) create mode 100644 app/src/androidTest/java/com/nextcloud/strings/StringsTests.kt diff --git a/app/src/androidTest/java/com/nextcloud/strings/StringsTests.kt b/app/src/androidTest/java/com/nextcloud/strings/StringsTests.kt new file mode 100644 index 000000000000..3c939cd37958 --- /dev/null +++ b/app/src/androidTest/java/com/nextcloud/strings/StringsTests.kt @@ -0,0 +1,37 @@ +/* + * Nextcloud - Android Client + * + * SPDX-FileCopyrightText: 2026 Alper Ozturk + * SPDX-License-Identifier: AGPL-3.0-or-later + */ + +package com.nextcloud.strings + +import android.content.Context +import androidx.test.platform.app.InstrumentationRegistry +import com.nextcloud.client.jobs.upload.FileUploadHelper.Companion.MAX_FILE_COUNT +import com.owncloud.android.R +import org.junit.Assert.assertEquals +import org.junit.Before +import org.junit.Test + +class StringsTests { + + private lateinit var context: Context + + @Before + fun setup() { + context = InstrumentationRegistry.getInstrumentation().targetContext + } + + @Test + fun testMaxFileCountText() { + val message = context.resources.getQuantityString( + R.plurals.file_upload_limit_message, + MAX_FILE_COUNT, + MAX_FILE_COUNT + ) + + assertEquals(message, "You can upload up to 500 files at once.") + } +} diff --git a/app/src/main/java/com/nextcloud/client/jobs/upload/FileUploadHelper.kt b/app/src/main/java/com/nextcloud/client/jobs/upload/FileUploadHelper.kt index 62b3294b73af..809d24c8e66d 100644 --- a/app/src/main/java/com/nextcloud/client/jobs/upload/FileUploadHelper.kt +++ b/app/src/main/java/com/nextcloud/client/jobs/upload/FileUploadHelper.kt @@ -73,7 +73,6 @@ class FileUploadHelper { companion object { private val TAG = FileUploadWorker::class.java.simpleName - @Suppress("MagicNumber") const val MAX_FILE_COUNT = 500 val mBoundListeners = HashMap() @@ -501,6 +500,7 @@ class FileUploadHelper { fun showFileUploadLimitMessage(activity: Activity) { val message = activity.resources.getQuantityString( R.plurals.file_upload_limit_message, + MAX_FILE_COUNT, MAX_FILE_COUNT ) DisplayUtils.showSnackMessage(activity, message) From 50db581a27dfe2a22bac652720df301e450975c0 Mon Sep 17 00:00:00 2001 From: Nextcloud bot Date: Sat, 31 Jan 2026 03:09:11 +0000 Subject: [PATCH 209/216] fix(l10n): Update translations from Transifex Signed-off-by: Nextcloud bot --- app/src/main/res/values-cs-rCZ/strings.xml | 2 ++ app/src/main/res/values-gl/strings.xml | 10 ++++++++++ app/src/main/res/values-hr/strings.xml | 1 + app/src/main/res/values-pl/strings.xml | 19 +++++++++++++++++++ 4 files changed, 32 insertions(+) diff --git a/app/src/main/res/values-cs-rCZ/strings.xml b/app/src/main/res/values-cs-rCZ/strings.xml index 257b8a8f464c..a1b61efb816b 100644 --- a/app/src/main/res/values-cs-rCZ/strings.xml +++ b/app/src/main/res/values-cs-rCZ/strings.xml @@ -53,6 +53,7 @@ Zkuste poslat zprávu pro rozproudění konverzace. Zdravím! Jak vám mohu pomoci? Poslat zprávu + Otevřít seznam konverzací Při vytváření úlohy se vyskytla chyba Úkol vytvořen Při mazání úlohy se vyskytla chyba @@ -69,6 +70,7 @@ spuštěné naplánováno úspěšné + Stav úkolu: %1$s neznámý Přemýšlení… Související účet nenalezen! diff --git a/app/src/main/res/values-gl/strings.xml b/app/src/main/res/values-gl/strings.xml index ec914a3d0812..d23c82ec7ddb 100644 --- a/app/src/main/res/values-gl/strings.xml +++ b/app/src/main/res/values-gl/strings.xml @@ -48,21 +48,30 @@ O resultado que se amosa aquí foi xerado por IA. Asegúrese de facer sempre unha dobre comprobación Produciuse un fallo ao enviar unha mensaxe Produciuse un fallo ao recuperar as mensaxes da parola + Volver á páxina do asistente Confirma que quere eliminar esta tarefa? Eliminar tarefa Probe a enviar unha mensaxe para iniciar unha conversa. Ola! En que podo axudarlle hoxe? + Enviar a mensaxe + Lista de conversas abertas Produciuse un erro ao crear a tarefa Tarefa creada Produciuse un erro ao eliminar a tarefa + Tarefa eliminada A lista de tarefas está baleira. Comprobe a configuración da aplicación do asistente. Non é posíbel recuperar a lista de tarefas. Comprobe a conexión a Internet. Eliminar tarefa A saída da tarefa aínda non está preparada. + Texto copiado desde outra aplicación Asistente Entrada Saída + fallou en execución + programado + satisfactorio + Estado da tarefa: %1$s descoñecido Pensando… Non se atopou unha conta asociada! @@ -497,6 +506,7 @@ %1$d de %2$d · %3$s Produciuse un erro durante a sincronización do cartafol %s Non hai espazo abondo no disco, cancelouse a sincronización + Cartafol %s sincronizado Sincronizando… Aquí non hai cartafoles O nome do cartafol non pode estar baleiro diff --git a/app/src/main/res/values-hr/strings.xml b/app/src/main/res/values-hr/strings.xml index 952e434b1dec..9dd2dc4d0ef5 100644 --- a/app/src/main/res/values-hr/strings.xml +++ b/app/src/main/res/values-hr/strings.xml @@ -495,6 +495,7 @@ Dopusti Spriječi Nije pronađena nijedna aplikacija za postavljanje slike s + Otvori %1$s zaustavi uključi/isključi Onemogućivanje provjere uštede energije može rezultirati otpremanjem datoteka pri niskoj razini napunjenosti baterije! diff --git a/app/src/main/res/values-pl/strings.xml b/app/src/main/res/values-pl/strings.xml index 6eb55ba184a9..3dc585cb6fed 100644 --- a/app/src/main/res/values-pl/strings.xml +++ b/app/src/main/res/values-pl/strings.xml @@ -13,6 +13,7 @@ Wyślij/udostępnij Widok siatki Widok listy + Wywołano akcję Przywróć kontakty i kalendarz Nowy katalog Przenieś lub kopiuj @@ -47,21 +48,30 @@ Ten wynik został wygenerowany przez AI. Upewnij się, że został sprawdzony i odpowiednio dostosowany. Nie udało się wysłać wiadomości Nie udało się pobrać wiadomości czatu + Wróć do strony asystenta Czy na pewno chcesz usunąć to zadanie? Usuń zadanie Spróbuj wysłać wiadomość, aby rozpocząć rozmowę. Cześć! W czym mogę Ci dziś pomóc? + Wyślij wiadomość + Otwórz listę rozmowy Wystąpił błąd podczas tworzenia zadania Zadanie utworzone Wystąpił błąd podczas usuwania zadania + Zadanie usunięte Lista zadań jest pusta. Sprawdź konfigurację asystenta aplikacji. Nie można pobrać listy zadań. Sprawdź swoje połączenie internetowe. Usuń zadanie Wynik zadanie nie jest jeszcze gotowy + Tekst skopiowany z innej aplikacji Asystent Wejście Wyjście + nie powiodło się uruchomiony + zaplanowane + powiodło się + Status zadania: %1$s nieznane Mylślę ... Nie znaleziono powiązanego konta! @@ -325,6 +335,7 @@ Asystent Więcej Więcej aplikacji Nextcloud + Nie można otworzyć selektora plików Nie udało się wybrać adresu e-mail. Ustaw jako zaszyfrowane Nie można pobrać certyfikatu serwera @@ -394,8 +405,10 @@ Nie masz uprawnień do tworzenia ani przesyłania plików w tym folderze. Udostępnienia zewnętrzne Dodaj lub wyślij + Nie udało się utworzyć okna dialogowego konfliktu Nie udało się przekazać pliku do menedżera pobierania Nie udało się wydrukować pliku + Nie udało się rozpocząć akcji! Nie można uruchomić edytora Nie udało się zaktualizować UI Dodaj do ulubionych @@ -493,6 +506,7 @@ %1$d z %2$d · %3$s Wystąpił błąd podczas synchronizacji katalogu %s Brak miejsca na dysku, synchronizacja przewana + Katalog zsynchronizowany %s Synchronizacja… Brak katalogów Nazwa katalogu nie może być pusta @@ -754,6 +768,7 @@ Interwał Zarządzaj wewnętrznymi katalogami w celu synchronizacji dwukierunkowej Włącz synchronizację dwukierunkową + Synchronizacja dwukierunkowa Ciemny Jasny Śledź system @@ -824,6 +839,7 @@ Wybierz jeden szablon Wybierz szablon Wyślij + Wyślij kopię do Wyślij udostępnienie Ikona przycisku wysyłania Nie można załadować zawartości @@ -959,6 +975,9 @@ Propozycja Synchronizuj Synchronizuj mimo wszystko + Rozwiąż konflikty + Wykryto konflikty wysyłania. Otwórz pliki do wysłania, aby je rozwiązać. + Konflikty wysyłania plików Znaleziono konflikty Katalog %1$s nie istnieje Synchronizuj z duplikowane From 4873bac70cc4434f6561ba73aa6767f1754bbbdd Mon Sep 17 00:00:00 2001 From: alperozturk96 Date: Fri, 30 Jan 2026 15:06:44 +0100 Subject: [PATCH 210/216] fix(unified-search): screen state Signed-off-by: alperozturk96 --- .../ui/fragment/UnifiedSearchFragment.kt | 61 ++++++++++--------- .../UnifiedSearchFragmentScreenState.kt | 38 ++++++++++++ .../unifiedsearch/IUnifiedSearchViewModel.kt | 4 ++ .../unifiedsearch/UnifiedSearchViewModel.kt | 7 +++ 4 files changed, 82 insertions(+), 28 deletions(-) create mode 100644 app/src/main/java/com/owncloud/android/ui/fragment/UnifiedSearchFragmentScreenState.kt diff --git a/app/src/main/java/com/owncloud/android/ui/fragment/UnifiedSearchFragment.kt b/app/src/main/java/com/owncloud/android/ui/fragment/UnifiedSearchFragment.kt index 74f9248640e3..46ef6486c751 100644 --- a/app/src/main/java/com/owncloud/android/ui/fragment/UnifiedSearchFragment.kt +++ b/app/src/main/java/com/owncloud/android/ui/fragment/UnifiedSearchFragment.kt @@ -38,6 +38,7 @@ import com.nextcloud.client.network.ClientFactory import com.nextcloud.client.preferences.AppPreferences import com.nextcloud.utils.extensions.getTypedActivity import com.nextcloud.utils.extensions.searchFilesByName +import com.nextcloud.utils.extensions.setVisibleIf import com.nextcloud.utils.extensions.typedActivity import com.owncloud.android.R import com.owncloud.android.databinding.ListFragmentBinding @@ -230,47 +231,41 @@ class UnifiedSearchFragment : adapter.setData(emptyList()) adapter.setDataCurrentDirItems(listOf()) - showStartYourSearch() + vm.updateScreenState(UnifiedSearchFragmentScreenState.Empty.startSearch()) showKeyboard(searchView) } } - private fun makeEmptyListVisible() { - binding.emptyList.run { - root.visibility = View.VISIBLE - emptyListIcon.visibility = View.VISIBLE - emptyListViewHeadline.visibility = View.VISIBLE - emptyListViewText.visibility = View.VISIBLE - emptyListIcon.visibility = View.VISIBLE + private fun handleScreenState(state: UnifiedSearchFragmentScreenState) { + when (state) { + is UnifiedSearchFragmentScreenState.ShowingContent -> { + toggleEmptyListVisible(show = false) + } + is UnifiedSearchFragmentScreenState.Empty -> { + showEmptyView(state) + } } } - private fun showStartYourSearch() { - makeEmptyListVisible() - + private fun toggleEmptyListVisible(show: Boolean) { binding.emptyList.run { - emptyListViewHeadline.text = getString(R.string.file_list_empty_unified_search_start_search) - emptyListViewText.text = getString(R.string.file_list_empty_unified_search_start_search_description) - emptyListIcon.setImageDrawable( - viewThemeUtils.platform.tintDrawable( - requireContext(), - R.drawable.ic_search_grey - ) - ) + root.setVisibleIf(show) + emptyListIcon.setVisibleIf(show) + emptyListViewHeadline.setVisibleIf(show) + emptyListViewText.setVisibleIf(show) + emptyListIcon.setVisibleIf(show) } } - private fun showNoResult() { - makeEmptyListVisible() + private fun showEmptyView(state: UnifiedSearchFragmentScreenState.Empty) { + toggleEmptyListVisible(show = true) binding.emptyList.run { - emptyListViewHeadline.text = - requireContext().getString(R.string.file_list_empty_headline_server_search) - emptyListViewText.text = - requireContext().getString(R.string.file_list_empty_unified_search_no_results) emptyListIcon.setImageDrawable( - viewThemeUtils.platform.tintDrawable(requireContext(), R.drawable.ic_search_grey) + viewThemeUtils.platform.tintDrawable(requireContext(), state.iconId) ) + emptyListViewHeadline.text = requireContext().getString(state.titleId) + emptyListViewText.text = requireContext().getString(state.descriptionId) } } @@ -317,6 +312,9 @@ class UnifiedSearchFragment : vm.isLoading.observe(viewLifecycleOwner) { loading -> binding.swipeContainingList.isRefreshing = loading } + vm.screenState.observe(viewLifecycleOwner) { + handleScreenState(it) + } PairMediatorLiveData(vm.searchResults, vm.isLoading).observe(viewLifecycleOwner) { (searchResults, isLoading) -> if (isLoading == true || searchResults.isNullOrEmpty()) { @@ -329,7 +327,7 @@ class UnifiedSearchFragment : !hasSearchResult && !adapter.hasLocalResults() ) { - showNoResult() + vm.updateScreenState(UnifiedSearchFragmentScreenState.Empty.noResults()) } } @@ -419,7 +417,11 @@ class UnifiedSearchFragment : fun onSearchResultChanged(result: List) { Log_OC.d(TAG, "result") binding.emptyList.emptyListView.visibility = View.GONE - adapter.setData(result.filterOutHiddenFiles(listOfHiddenFiles)) + val newFiles = result.filterOutHiddenFiles(listOfHiddenFiles) + if (newFiles.isNotEmpty()) { + vm.updateScreenState(UnifiedSearchFragmentScreenState.ShowingContent) + } + adapter.setData(newFiles) } @VisibleForTesting @@ -446,6 +448,9 @@ class UnifiedSearchFragment : val files = storageManager .searchFilesByName(this, accountManager.user.accountName, query) .filter { !it.isEncrypted } + if (files.isNotEmpty()) { + vm.updateScreenState(UnifiedSearchFragmentScreenState.ShowingContent) + } adapter.setDataCurrentDirItems(files) } } diff --git a/app/src/main/java/com/owncloud/android/ui/fragment/UnifiedSearchFragmentScreenState.kt b/app/src/main/java/com/owncloud/android/ui/fragment/UnifiedSearchFragmentScreenState.kt new file mode 100644 index 000000000000..8a586b5f6583 --- /dev/null +++ b/app/src/main/java/com/owncloud/android/ui/fragment/UnifiedSearchFragmentScreenState.kt @@ -0,0 +1,38 @@ +/* + * Nextcloud - Android Client + * + * SPDX-FileCopyrightText: 2026 Alper Ozturk + * SPDX-License-Identifier: AGPL-3.0-or-later + */ + +package com.owncloud.android.ui.fragment + +import com.owncloud.android.R + +sealed class UnifiedSearchFragmentScreenState { + + /** + * Content is being displayed (search results or current directory items) + */ + object ShowingContent : UnifiedSearchFragmentScreenState() + + /** + * Empty state with customizable message + */ + data class Empty(val titleId: Int, val descriptionId: Int, val iconId: Int) : UnifiedSearchFragmentScreenState() { + + companion object { + fun startSearch() = Empty( + titleId = R.string.file_list_empty_unified_search_start_search, + descriptionId = R.string.file_list_empty_unified_search_start_search_description, + iconId = R.drawable.ic_search_grey + ) + + fun noResults() = Empty( + titleId = R.string.file_list_empty_headline_server_search, + descriptionId = R.string.file_list_empty_unified_search_no_results, + iconId = R.drawable.ic_search_grey + ) + } + } +} diff --git a/app/src/main/java/com/owncloud/android/ui/unifiedsearch/IUnifiedSearchViewModel.kt b/app/src/main/java/com/owncloud/android/ui/unifiedsearch/IUnifiedSearchViewModel.kt index 04c7d0e00d52..6cc2c6653b35 100644 --- a/app/src/main/java/com/owncloud/android/ui/unifiedsearch/IUnifiedSearchViewModel.kt +++ b/app/src/main/java/com/owncloud/android/ui/unifiedsearch/IUnifiedSearchViewModel.kt @@ -8,10 +8,13 @@ package com.owncloud.android.ui.unifiedsearch import android.net.Uri import androidx.lifecycle.LiveData +import androidx.lifecycle.MutableLiveData import com.owncloud.android.datamodel.OCFile import com.owncloud.android.lib.common.SearchResultEntry +import com.owncloud.android.ui.fragment.UnifiedSearchFragmentScreenState interface IUnifiedSearchViewModel { + val screenState: MutableLiveData val browserUri: LiveData val error: LiveData val file: LiveData @@ -25,4 +28,5 @@ interface IUnifiedSearchViewModel { fun setQuery(query: String) fun openFile(remotePath: String) fun getRemoteFile(remotePath: String) + fun updateScreenState(state: UnifiedSearchFragmentScreenState) } diff --git a/app/src/main/java/com/owncloud/android/ui/unifiedsearch/UnifiedSearchViewModel.kt b/app/src/main/java/com/owncloud/android/ui/unifiedsearch/UnifiedSearchViewModel.kt index 4afb9ed10948..a68756f86a72 100644 --- a/app/src/main/java/com/owncloud/android/ui/unifiedsearch/UnifiedSearchViewModel.kt +++ b/app/src/main/java/com/owncloud/android/ui/unifiedsearch/UnifiedSearchViewModel.kt @@ -25,6 +25,7 @@ import com.owncloud.android.lib.common.SearchResult import com.owncloud.android.lib.common.SearchResultEntry import com.owncloud.android.lib.common.utils.Log_OC import com.owncloud.android.ui.asynctasks.GetRemoteFileTask +import com.owncloud.android.ui.fragment.UnifiedSearchFragmentScreenState import javax.inject.Inject @Suppress("LongParameterList") @@ -53,6 +54,8 @@ class UnifiedSearchViewModel(application: Application) : private lateinit var repository: IUnifiedSearchRepository private var results: MutableMap = mutableMapOf() + override val screenState: MutableLiveData = + MutableLiveData(UnifiedSearchFragmentScreenState.ShowingContent) override val isLoading = MutableLiveData(false) override val searchResults = MutableLiveData>(mutableListOf()) override val error = MutableLiveData("") @@ -244,4 +247,8 @@ class UnifiedSearchViewModel(application: Application) : fun setConnectivityService(connectivityService: ConnectivityService) { this.connectivityService = connectivityService } + + override fun updateScreenState(state: UnifiedSearchFragmentScreenState) { + screenState.value = state + } } From 8179c23e11ef87e30a002eca656ed0e64a3ae349 Mon Sep 17 00:00:00 2001 From: Nextcloud bot Date: Sun, 1 Feb 2026 03:11:42 +0000 Subject: [PATCH 211/216] fix(l10n): Update translations from Transifex Signed-off-by: Nextcloud bot --- app/src/main/res/values-cs-rCZ/strings.xml | 1 + app/src/main/res/values-zh-rCN/strings.xml | 1 + 2 files changed, 2 insertions(+) diff --git a/app/src/main/res/values-cs-rCZ/strings.xml b/app/src/main/res/values-cs-rCZ/strings.xml index a1b61efb816b..3bb4b8a76ffb 100644 --- a/app/src/main/res/values-cs-rCZ/strings.xml +++ b/app/src/main/res/values-cs-rCZ/strings.xml @@ -48,6 +48,7 @@ Zde zobrazený výstup je vytvořen AI. Vždy si informace ověřujte. Nepodařilo se odeslat zprávu Nepodařilo se získat zprávy chatu + Zpět na stránku asistenta Opravdu chcete tuto úlohu smazat? Smazat úkol Zkuste poslat zprávu pro rozproudění konverzace. diff --git a/app/src/main/res/values-zh-rCN/strings.xml b/app/src/main/res/values-zh-rCN/strings.xml index 615bc55c5828..b5e185a44656 100644 --- a/app/src/main/res/values-zh-rCN/strings.xml +++ b/app/src/main/res/values-zh-rCN/strings.xml @@ -849,6 +849,7 @@ 设置消息 设置备注 在线状态 + 无法设置状态! 将图片用作 在端对端加密期间,你将接收一个随机12字助记字串,您需要这个字符串才能在其它设备上开放您的文件。这将只会存储在该设备上,并可以在此画面中再次展示。请记在安全的地方! 共享 From 8c540349480b1db818113766770e1d746afea758 Mon Sep 17 00:00:00 2001 From: Nextcloud bot Date: Mon, 2 Feb 2026 03:14:51 +0000 Subject: [PATCH 212/216] fix(l10n): Update translations from Transifex Signed-off-by: Nextcloud bot --- app/src/main/res/values-ga/strings.xml | 6 ++++++ app/src/main/res/values-hr/strings.xml | 6 ++++++ 2 files changed, 12 insertions(+) diff --git a/app/src/main/res/values-ga/strings.xml b/app/src/main/res/values-ga/strings.xml index dc53c12a49f4..c188fd153d83 100644 --- a/app/src/main/res/values-ga/strings.xml +++ b/app/src/main/res/values-ga/strings.xml @@ -48,14 +48,17 @@ Is í an intleacht shaorga a ghineann an t-aschur a thaispeántar anseo. Déan cinnte go ndéanann tú seiceáil dhúbailte i gcónaí. Theip ar theachtaireacht a sheoladh Theip ar theachtaireachtaí comhrá a fháil + Téigh ar ais chuig leathanach an chúntóra An bhfuil tú cinnte gur mhaith leat an tasc seo a scriosadh? Scrios tasc Bain triail as teachtaireacht a sheoladh chun tús a chur le comhrá. Dia duit ann! Cad is féidir liom cabhrú leat inniu? Seol teachtaireacht + Oscail an liosta comhrá Tharla earráid agus an tasc á chruthú Tasc cruthaithe Tharla earráid agus an tasc á scriosadh + Scriosadh an tasc Tá an liosta tascanna folamh. Seiceáil cumraíocht aip an chúntóra. Ní féidir liosta tascanna a fháil, seiceáil do nasc idirlín le do thoil. Scrios Tasc @@ -67,6 +70,8 @@ theip Ag rith sceidealta + rathúil + Stádas tasc: %1$s anaithnid Ag smaoineamh… Cuntas gaolmhar gan aimsiú! @@ -501,6 +506,7 @@ %1$d de %2$d · %3$s Tharla earráid le linn sioncrónú an fhillteáin %s Gan dóthain spáis diosca, sioncrónú curtha ar ceal + %s fillteán sioncrónaithe Ag sioncrónú… Níl fillteáin anseo Ní féidir ainm fillteáin a bheith folamh diff --git a/app/src/main/res/values-hr/strings.xml b/app/src/main/res/values-hr/strings.xml index 9dd2dc4d0ef5..d5774bea2fa8 100644 --- a/app/src/main/res/values-hr/strings.xml +++ b/app/src/main/res/values-hr/strings.xml @@ -285,6 +285,7 @@ Prijenos Preuzmi Otpremi + Vanjska dijeljenja Dodaj ili otpremi Neuspješno prosljeđivanje datoteke upravitelju preuzimanja Ispisivanje datoteke nije uspjelo @@ -385,6 +386,7 @@ Također otpremi postojeće datoteke Otpremanje samo tijekom punjenja /InstantUpload + Unutarnja dijeljenja Neispravan URL Nevidljiva Oznaka ne može biti prazna @@ -599,9 +601,12 @@ Postavi kao Koristi sliku kao Dijeli + Dopusti preuzimanje i sinkronizaciju Stvori + Prilagođena dopuštenja Izbriši Dijeljenje + Postavi ograničenje preuzimanja Uredi %1$s Dijeli %1$s @@ -621,6 +626,7 @@ Postavi datum isteka Postavi zaporku Uređivanje moguće + Zahtjev za datotekom Samo za gledanje Dijeli Čitaj From 642d7ccc47b0810accc3b276c3e53651b37245a5 Mon Sep 17 00:00:00 2001 From: Nextcloud bot Date: Wed, 4 Feb 2026 03:08:56 +0000 Subject: [PATCH 213/216] fix(l10n): Update translations from Transifex Signed-off-by: Nextcloud bot --- app/src/main/res/values-hu-rHU/strings.xml | 70 ++++++++++++++++++++-- 1 file changed, 64 insertions(+), 6 deletions(-) diff --git a/app/src/main/res/values-hu-rHU/strings.xml b/app/src/main/res/values-hu-rHU/strings.xml index 5d50dd13ba0d..e1bc2a2c3a30 100644 --- a/app/src/main/res/values-hu-rHU/strings.xml +++ b/app/src/main/res/values-hu-rHU/strings.xml @@ -13,6 +13,7 @@ Küldés/megosztás Rács nézet Lista nézet + Művelet kiváltva Névjegyek és naptár helyreállítása Új mappa Áthelyezés vagy másolás @@ -44,19 +45,35 @@ Egy modult jelenít meg a irányítópultról Keresés itt: %s Megjelenés nem kapcsolódottként + Az itt megjelenített kimenetet MI állította elő. Ne felejtse el ellenőrizni. + Nem sikerült elküldeni az üzenetet + Nem sikerült lekérni a csevegőüzeneteket + Vissza az asszisztens oldalára Valóban törölni akarja ezt a feladatot? Feladat törlése + Küldjön egy üzenetet egy beszélgetés elindításához. + Üdvözlöm! Mit tehetek ma Önért? + Üzenet küldése + Beszélgetések megnyitása Hiba történt egy feladat létrehozása során Feladat létrehozva Hiba történt a feladat törlése során + Feladat törölve + A feladatlista üres. Ellenőrizze az asszisztensalkalmazás beállításait. A feladatlista nem kérhető le, ellenőrizze az internetkapcsolatát. Feladat törlése A feladat kimenete még nincs kész. + Szöveg átmásolva egy másik alkalmazásból Asszisztens Bemenet Kimenet + sikertelen fut + beütemezve + sikeres + Feladat állapota: %1$s ismeretlen + Gondolkodás… A kapcsolódó fiók nem található! Hozzáférési hiba: %1$s Az eszközön még nem létezik a fiók @@ -95,9 +112,11 @@ Fejezze be a bejelentkezési folyamatot a böngészőben Az automatikus feltöltés az akkumulátorkímélő mód miatt szünetel. megtartva az eredeti mappában, mivel csak olvasható + Alacsony akkumulátortöltöttség, a feltöltés tovább tarthat Feltöltés csak forgalomkorlát nélküli Wi-Fin /AutoUpload Ez a mappa már szerepel a szülőmappája szinkronizálásában, ami ismételt feltöltéseket okozhat + Várakozás a Wi-Fire a feltöltés megkezdéséhez Fájlok feltöltése innen: %s, ide: %s Beállítás Új egyéni mappabeállítás létrehozása @@ -119,7 +138,7 @@ Foglalt Naptár Naptárak - Cancel + Mégse Probléma történt a tanúsítvány betöltésekor. Változásnapló fejlesztői verziója Nézzen vissza később vagy töltse újra. @@ -204,8 +223,15 @@ Az importálás elkezdése sikertelen. Próbálja újra. Nincs fájl A legutóbbi biztonsági mentés nem található! + Tartalmi változások észlelése + Nem sikerült létrehozni a beszélgetést + Beszélgetés törlése + Nem sikerült a beszélgetés törlése Nem található beszélgetés + Még nincsenek beszélgetések + Nem sikerült lekérni a beszélgetéseket Beszélgetések + Másolva Hiba történt a fájl vagy mappa másolása közben Nem másolható egy mappa a saját almappájába A fájl már létezik a célmappában @@ -305,9 +331,11 @@ A végpontok közti titkosítás még nincs beállítva Internetkapcsolat nélkül nem lehetséges Az aláírás nem egyezik + Nem sikerült ellenőrizni a metaadatokat, az aláírás üres. Asszisztens Továbbiak További nextcloudos alkalmazások + Nem lehet megnyitni a fájlválasztót Az e-mail-cím kiválasztása sikertelen. Titkosítás bekapcsolása A kiszolgáló tanúsítványa nem kérhető le @@ -377,8 +405,10 @@ Nincs engedélye arra, hogy fájlokat hozzon létre vagy töltsön fel ebbe a mappába. Külső megosztások Hozzáadás vagy feltöltés + Nem sikerült létrehozni az ütközéskezelő párbeszédablakot Nem sikerült átadni a fájlt a letöltéskezelőnek A fájl nyomtatása sikertelen + Nem sikerült elkezdeni a műveletet. A szerkesztő indítása sikertelen A felhasználói felület frissítése sikertelen Hozzáadás a kedvencekhez @@ -410,6 +440,8 @@ Nincs találat a kereséséhez Kezdje el a keresést Írjon a fenti sávba a fájlok, névjegyek, naptáresemények és egyebek kereséséhez a fiókjában. + Ellenőrizze az internetkapcsolatot, és próbálja meg újra később + Gyenge kapcsolat mappa ÉLŐ Betöltés… @@ -471,6 +503,11 @@ A mappa már létezik A mappa megtekintéséhez a következő javasolt: %1$s. Létrehozás + %1$d. / %2$d · %3$s + Hiba történt a(z) %s mappa szinkronizációja során + Nincs elegendő lemezterület, a szinkronizálás megszakítva + %s mappa szinkronizálva + Szinkronizálás… Itt nincsenek mappák A mappanév nem lehet üres Válasszon @@ -604,6 +641,8 @@ A művelet végrehajtása sikertelen. Értesítések megjelenítése a háttérműveletek eredményének Háttérműveletek + Észleli a helyi fájlváltozásokat + Tartalomfigyelő Megjeleníti a letöltési folyamatokat Letöltések Megjeleníti a fájlszinkronizálás folyamatát és az eredményeket @@ -627,6 +666,7 @@ Nincs internetkapcsolat Akár internetkapcsolat nélkül is rendszerezheti a mappákat és hozhat létre fájlokat. Amint újra online lesz, a függőben lévő műveletek automatikusan szinkronizálva lesznek. Nincs kapcsolat, de a munka folytatódik + A fájl még nem létezik. Először töltse fel a fájlt. A(z) %s nem hozható létre. Már létezik ilyen nevű fájl a kiszolgálón. A(z) %s nem hozható létre. Már létezik ilyen nevű mappa a kiszolgálón. A kapcsolat nélküli művelet nem fejezhető be. %s @@ -636,12 +676,13 @@ Kapcsolat nélküli műveletek elkezdése 1 óra Elérhető - Online állapot + Elérhető állapot Megnyitás ezzel: %1$s A kiszolgáló elérte az életciklusa végét, kérjük frissítsen! További menü Írja be a számkódodat Adja meg a számkódot + A számkódra minden alkalommal szükség lesz az alkalmazás indításakor, vagy ha 5 másodpercnél később nyitja meg újra. A számkódok nem egyeznek Adja meg újra a számkódot Számkód törlése @@ -670,6 +711,8 @@ Új verzió átnevezése Mit tegyen, ha a fájl már létezik? Fiók hozzáadása + Engedélyezés, hogy az alkalmazás elérje és kezelje az összes fájlt az eszközön + Összes fájl elérése Naptár és névjegyek szinkronizálása Sem az F-Droid, sem a Google Play nincs telepítve DAVx⁵ (régi nevén DAVdroid) (v1.3.0+) beállítása a jelenlegi fiókhoz @@ -725,6 +768,7 @@ Időköz Belső mappák kezelése kétirányú szinkronizáláshoz Kétirányú szinkronizálás engedélyezése + Kétirányú szinkronizálás Sötét Világos Rendszer követése @@ -795,11 +839,12 @@ Válasszon egy sablont Válasszon sablont Küldés + Másolat küldése… Megosztás küldése - Küldés gomb ikon + Küldés gomb ikonja A tartalom nem tölthető be Az eszköz valószínűleg nem kapcsolódik az internethez - Beállítás mint + Beállítás… A letöltési korlát nem állítható be. Ellenőrizze az elérhető funkciókat. Üzenet beállítása Jegyzet beállítása @@ -867,7 +912,7 @@ Videók megjelenítése Kézileg nézze meg a szolgáltatási feltételeket! Regisztráció egy szolgáltatóval - Engedélyezi, hogy a(z) %1$s hozzáférjen a(z) %2$s Nextcloud fiókjához? + Engedélyezi, hogy a(z) %1$s hozzáférjen a(z) %2$s Nextcloud-fiókjához? Rendezés elve Kedvencek előre rendezése Mappák fájlok elé rendezése @@ -895,7 +940,7 @@ – A kiszolgáló tanúsítványa lejárt – A kiszolgáló tanúsítványa nem megbízható – A kiszolgáló tanúsítványa még nem érvényes - – Az URL nem egyezik a tanúsítványban szereplő kiszolgálónévvel + – A webcím nem egyezik a tanúsítványban szereplő kiszolgálónévvel Állapotüzenet Kamera Háttértároló helyének kiválasztása @@ -906,6 +951,10 @@ Belső tárhely Filmek Zene + Összes fájl elérése + Tároló engedély szükséges az automatikus felöltéshez. + Tároló engedély szükséges a fájlfelöltéshez. + Ne kérdezze meg Írásvédett média Képek A saját üzemeltetésű irodai platform, amely az Ön kezébe adja az irányítást. @@ -944,6 +993,9 @@ A Nextcloud itt érhető el: https://nextcloud.com Javaslat Szinkronizálás Szinkronizálás mindenképpen + Ütközések feloldása + Feltöltési ütközések észlelve. A megoldáshoz nyissa meg a feltöltéseket. + Fájlfeltöltési ütközések Ütközések vannak A(z) %1$s mappa már nem létezik Szinkronizálási duplikációk @@ -1105,6 +1157,8 @@ A Nextcloud itt érhető el: https://nextcloud.com A kiszolgáló tanúsítványa nem megbízható Kiszolgálóverzió lekérése… Az alkalmazás leállt + Kihagyva + Már létezik ilyen nevű fájl. Befejezve Ugyanazon fájl található a távoli kiszolgálón, feltöltés kihagyása Ismeretlen hiba @@ -1194,6 +1248,10 @@ A Nextcloud itt érhető el: https://nextcloud.com %d fájl exportálva, a többi hiba miatt kihagyva %d fájl exportálva, a többi hiba miatt kihagyva + + Egyszerre legfeljebb %d fájlt tölthet fel. + Egyszerre legfeljebb %d fájlt tölthet fel. + %1$d mappa %1$d mappa From fde531eb7d2b801e8e89fe45c0fb446d758049c5 Mon Sep 17 00:00:00 2001 From: tobiasKaminsky Date: Tue, 6 Jan 2026 08:57:02 +0100 Subject: [PATCH 214/216] Media: handle back press on selection correct Signed-off-by: tobiasKaminsky --- .../main/java/com/owncloud/android/ui/adapter/GalleryAdapter.kt | 2 ++ 1 file changed, 2 insertions(+) diff --git a/app/src/main/java/com/owncloud/android/ui/adapter/GalleryAdapter.kt b/app/src/main/java/com/owncloud/android/ui/adapter/GalleryAdapter.kt index f7f0bc2ef76b..ca0d1a131994 100644 --- a/app/src/main/java/com/owncloud/android/ui/adapter/GalleryAdapter.kt +++ b/app/src/main/java/com/owncloud/android/ui/adapter/GalleryAdapter.kt @@ -314,8 +314,10 @@ class GalleryAdapter( } } + @SuppressLint("NotifyDataSetChanged") override fun setMultiSelect(boolean: Boolean) { ocFileListDelegate.isMultiSelect = boolean + notifyDataSetChanged() } private fun getAllFiles(): List = cachedAllFiles ?: files.flatMap { galleryItem -> From d317966d4a38474f9740a00fa28aaaa7877e1eb9 Mon Sep 17 00:00:00 2001 From: alperozturk96 Date: Mon, 19 Jan 2026 13:29:37 +0100 Subject: [PATCH 215/216] add doc Signed-off-by: alperozturk96 --- .../CommonOCFileListAdapterInterface.kt | 2 +- .../android/ui/adapter/GalleryAdapter.kt | 23 +++++++++++++++++-- 2 files changed, 22 insertions(+), 3 deletions(-) diff --git a/app/src/main/java/com/owncloud/android/ui/adapter/CommonOCFileListAdapterInterface.kt b/app/src/main/java/com/owncloud/android/ui/adapter/CommonOCFileListAdapterInterface.kt index 314688f7283e..94962be8a753 100644 --- a/app/src/main/java/com/owncloud/android/ui/adapter/CommonOCFileListAdapterInterface.kt +++ b/app/src/main/java/com/owncloud/android/ui/adapter/CommonOCFileListAdapterInterface.kt @@ -33,7 +33,7 @@ interface CommonOCFileListAdapterInterface { fun removeCheckedFile(file: OCFile) fun notifyItemChanged(file: OCFile) fun getFilesCount(): Int - fun setMultiSelect(boolean: Boolean) + fun setMultiSelect(isMultiSelect: Boolean) fun clearCheckedItems() fun selectAll(value: Boolean) } diff --git a/app/src/main/java/com/owncloud/android/ui/adapter/GalleryAdapter.kt b/app/src/main/java/com/owncloud/android/ui/adapter/GalleryAdapter.kt index ca0d1a131994..c97e60b5fc69 100644 --- a/app/src/main/java/com/owncloud/android/ui/adapter/GalleryAdapter.kt +++ b/app/src/main/java/com/owncloud/android/ui/adapter/GalleryAdapter.kt @@ -314,9 +314,28 @@ class GalleryAdapter( } } + /** + * Enables or disables multi-select mode in the gallery. + * + * When multi-select mode is enabled: + * - Checkboxes are shown for all items. + * - Users can select multiple files. + * + * When multi-select mode is disabled: + * - Checkboxes are hidden. + * - Selected files remain visually unselected. + * + * Note: + * - This function is only called when the user explicitly enters or exits multi-select mode. + * It is **not** called for individual file selection or deselection. + * - The entire adapter is refreshed using [notifyDataSetChanged] to properly show or hide + * checkboxes across all rows, as individual item updates are not sufficient in this case. + * + * @param isMultiSelect true to enable multi-select mode, false to disable it. + */ @SuppressLint("NotifyDataSetChanged") - override fun setMultiSelect(boolean: Boolean) { - ocFileListDelegate.isMultiSelect = boolean + override fun setMultiSelect(isMultiSelect: Boolean) { + ocFileListDelegate.isMultiSelect = isMultiSelect notifyDataSetChanged() } From 3c0e2c4915312c4ffc49fa38fc9930ef6d7e794b Mon Sep 17 00:00:00 2001 From: Josh Date: Sat, 7 Feb 2026 10:49:20 -0500 Subject: [PATCH 216/216] fix: use positional formatter specifiers for `auto_upload_worker_start_text` Signed-off-by: Josh --- app/src/main/res/values/strings.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index a66a788847e4..c8ca5dd06b19 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -964,7 +964,7 @@ Show notifications to interact result of background operations Show push notifications sent by the server: Mentions in comments, reception of new remote shares, announcements posted by an admin etc. Send button icon - Uploading files from %s to %s + Uploading files from %1$s to %2$s * Name Password