mirror of
https://github.com/nextcloud/android.git
synced 2024-12-19 23:42:03 +03:00
Merge remote-tracking branch 'origin/master' into dev
This commit is contained in:
commit
3de6dfb9a6
24 changed files with 452 additions and 316 deletions
|
@ -1,9 +1,9 @@
|
||||||
/*
|
/*
|
||||||
* Nextcloud - Android Client
|
* Nextcloud - Android Client
|
||||||
*
|
*
|
||||||
* SPDX-FileCopyrightText: 2022 Álvaro Brey Vilas
|
* SPDX-FileCopyrightText: 2022 Álvaro Brey <alvaro@alvarobrey.com>
|
||||||
* SPDX-FileCopyrightText: 2022 Nextcloud GmbH
|
* SPDX-FileCopyrightText: 2022 Nextcloud GmbH
|
||||||
* SPDX-License-Identifier: GPL-3.0-or-later
|
* SPDX-License-Identifier: AGPL-3.0-or-later
|
||||||
*/
|
*/
|
||||||
package com.owncloud.android.files
|
package com.owncloud.android.files
|
||||||
|
|
||||||
|
|
|
@ -2,7 +2,7 @@
|
||||||
* Nextcloud - Android Client
|
* Nextcloud - Android Client
|
||||||
*
|
*
|
||||||
* SPDX-FileCopyrightText: 2020 Chris Narkiewicz <hello@ezaquarii.com>
|
* SPDX-FileCopyrightText: 2020 Chris Narkiewicz <hello@ezaquarii.com>
|
||||||
* SPDX-FileCopyrightText: 2019 Tobias Kaminsky
|
* SPDX-FileCopyrightText: 2019 Tobias Kaminsky <tobias@kaminsky.me>
|
||||||
* SPDX-FileCopyrightText: 2019 Nextcloud GmbH
|
* SPDX-FileCopyrightText: 2019 Nextcloud GmbH
|
||||||
* SPDX-License-Identifier: AGPL-3.0-or-later OR GPL-2.0-only
|
* SPDX-License-Identifier: AGPL-3.0-or-later OR GPL-2.0-only
|
||||||
*/
|
*/
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
/*
|
/*
|
||||||
* Nextcloud - Android Client
|
* Nextcloud - Android Client
|
||||||
*
|
*
|
||||||
|
* SPDX-FileCopyrightText: 2024 Jonas Mayer <jonas.mayer@nextcloud.com>
|
||||||
* SPDX-FileCopyrightText: 2020 Chris Narkiewicz <hello@ezaquarii.com>
|
* SPDX-FileCopyrightText: 2020 Chris Narkiewicz <hello@ezaquarii.com>
|
||||||
* SPDX-FileCopyrightText: 2017 Mario Danic <mario@lovelyhq.com>
|
* SPDX-FileCopyrightText: 2017 Mario Danic <mario@lovelyhq.com>
|
||||||
* SPDX-FileCopyrightText: 2017 Nextcloud GmbH
|
* SPDX-FileCopyrightText: 2017 Nextcloud GmbH
|
||||||
|
@ -64,7 +65,7 @@ class FilesSyncWork(
|
||||||
|
|
||||||
private lateinit var syncedFolder: SyncedFolder
|
private lateinit var syncedFolder: SyncedFolder
|
||||||
|
|
||||||
@Suppress("MagicNumber")
|
@Suppress("MagicNumber", "ReturnCount")
|
||||||
override fun doWork(): Result {
|
override fun doWork(): Result {
|
||||||
val syncFolderId = inputData.getLong(SYNCED_FOLDER_ID, -1)
|
val syncFolderId = inputData.getLong(SYNCED_FOLDER_ID, -1)
|
||||||
val changedFiles = inputData.getStringArray(CHANGED_FILES)
|
val changedFiles = inputData.getStringArray(CHANGED_FILES)
|
||||||
|
@ -72,25 +73,39 @@ class FilesSyncWork(
|
||||||
backgroundJobManager.logStartOfWorker(BackgroundJobManagerImpl.formatClassTag(this::class) + "_" + syncFolderId)
|
backgroundJobManager.logStartOfWorker(BackgroundJobManagerImpl.formatClassTag(this::class) + "_" + syncFolderId)
|
||||||
Log_OC.d(TAG, "File-sync worker started for folder ID: $syncFolderId")
|
Log_OC.d(TAG, "File-sync worker started for folder ID: $syncFolderId")
|
||||||
|
|
||||||
if (canExitEarly(changedFiles, syncFolderId)) {
|
// Create all the providers we'll need
|
||||||
val result = Result.success()
|
|
||||||
backgroundJobManager.logEndOfWorker(
|
|
||||||
BackgroundJobManagerImpl.formatClassTag(this::class) +
|
|
||||||
"_" + syncFolderId,
|
|
||||||
result
|
|
||||||
)
|
|
||||||
return result
|
|
||||||
}
|
|
||||||
|
|
||||||
val resources = context.resources
|
val resources = context.resources
|
||||||
val lightVersion = resources.getBoolean(R.bool.syncedFolder_light)
|
val lightVersion = resources.getBoolean(R.bool.syncedFolder_light)
|
||||||
FilesSyncHelper.restartUploadsIfNeeded(
|
val filesystemDataProvider = FilesystemDataProvider(contentResolver)
|
||||||
uploadsStorageManager,
|
val currentLocale = resources.configuration.locale
|
||||||
userAccountManager,
|
val dateFormat = SimpleDateFormat("yyyy:MM:dd HH:mm:ss", currentLocale)
|
||||||
connectivityService,
|
dateFormat.timeZone = TimeZone.getTimeZone(TimeZone.getDefault().id)
|
||||||
powerManagementService
|
|
||||||
|
if (!setSyncedFolder(syncFolderId)) {
|
||||||
|
Log_OC.d(TAG, "File-sync kill worker since syncedFolder ($syncFolderId) is not enabled!")
|
||||||
|
return logEndOfWorker(syncFolderId)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Always first try to schedule uploads to make sure files are uploaded even if worker was killed to early
|
||||||
|
uploadFilesFromFolder(
|
||||||
|
context,
|
||||||
|
resources,
|
||||||
|
lightVersion,
|
||||||
|
filesystemDataProvider,
|
||||||
|
currentLocale,
|
||||||
|
dateFormat,
|
||||||
|
syncedFolder
|
||||||
)
|
)
|
||||||
|
|
||||||
|
if (canExitEarly(changedFiles, syncFolderId)) {
|
||||||
|
return logEndOfWorker(syncFolderId)
|
||||||
|
}
|
||||||
|
|
||||||
|
val user = userAccountManager.getUser(syncedFolder.account)
|
||||||
|
if (user.isPresent) {
|
||||||
|
backgroundJobManager.startFilesUploadJob(user.get())
|
||||||
|
}
|
||||||
|
|
||||||
// Get changed files from ContentObserverWork (only images and videos) or by scanning filesystem
|
// Get changed files from ContentObserverWork (only images and videos) or by scanning filesystem
|
||||||
Log_OC.d(
|
Log_OC.d(
|
||||||
TAG,
|
TAG,
|
||||||
|
@ -100,13 +115,7 @@ class FilesSyncWork(
|
||||||
collectChangedFiles(changedFiles)
|
collectChangedFiles(changedFiles)
|
||||||
Log_OC.d(TAG, "File-sync worker (${syncedFolder.remotePath}) finished checking files.")
|
Log_OC.d(TAG, "File-sync worker (${syncedFolder.remotePath}) finished checking files.")
|
||||||
|
|
||||||
// Create all the providers we'll need
|
uploadFilesFromFolder(
|
||||||
val filesystemDataProvider = FilesystemDataProvider(contentResolver)
|
|
||||||
val currentLocale = resources.configuration.locale
|
|
||||||
val dateFormat = SimpleDateFormat("yyyy:MM:dd HH:mm:ss", currentLocale)
|
|
||||||
dateFormat.timeZone = TimeZone.getTimeZone(TimeZone.getDefault().id)
|
|
||||||
|
|
||||||
syncFolder(
|
|
||||||
context,
|
context,
|
||||||
resources,
|
resources,
|
||||||
lightVersion,
|
lightVersion,
|
||||||
|
@ -116,6 +125,17 @@ class FilesSyncWork(
|
||||||
syncedFolder
|
syncedFolder
|
||||||
)
|
)
|
||||||
|
|
||||||
|
FilesSyncHelper.restartUploadsIfNeeded(
|
||||||
|
uploadsStorageManager,
|
||||||
|
userAccountManager,
|
||||||
|
connectivityService,
|
||||||
|
powerManagementService
|
||||||
|
)
|
||||||
|
|
||||||
|
return logEndOfWorker(syncFolderId)
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun logEndOfWorker(syncFolderId: Long): Result {
|
||||||
Log_OC.d(TAG, "File-sync worker (${syncedFolder.remotePath}) finished")
|
Log_OC.d(TAG, "File-sync worker (${syncedFolder.remotePath}) finished")
|
||||||
val result = Result.success()
|
val result = Result.success()
|
||||||
backgroundJobManager.logEndOfWorker(
|
backgroundJobManager.logEndOfWorker(
|
||||||
|
@ -140,6 +160,7 @@ class FilesSyncWork(
|
||||||
// If we are in power save mode better to postpone scan and upload
|
// If we are in power save mode better to postpone scan and upload
|
||||||
val overridePowerSaving = inputData.getBoolean(OVERRIDE_POWER_SAVING, false)
|
val overridePowerSaving = inputData.getBoolean(OVERRIDE_POWER_SAVING, false)
|
||||||
if ((powerManagementService.isPowerSavingEnabled && !overridePowerSaving)) {
|
if ((powerManagementService.isPowerSavingEnabled && !overridePowerSaving)) {
|
||||||
|
Log_OC.d(TAG, "File-sync kill worker since powerSaving is enabled!")
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -148,9 +169,8 @@ class FilesSyncWork(
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
// or sync worker already running and no changed files to be processed
|
// or sync worker already running
|
||||||
val alreadyRunning = backgroundJobManager.bothFilesSyncJobsRunning(syncedFolderID)
|
if (backgroundJobManager.bothFilesSyncJobsRunning(syncedFolderID)) {
|
||||||
if (alreadyRunning && changedFiles.isNullOrEmpty()) {
|
|
||||||
Log_OC.d(
|
Log_OC.d(
|
||||||
TAG,
|
TAG,
|
||||||
"File-sync kill worker since another instance of the worker " +
|
"File-sync kill worker since another instance of the worker " +
|
||||||
|
@ -159,8 +179,17 @@ class FilesSyncWork(
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!setSyncedFolder(syncedFolderID)) {
|
val passedScanInterval = (
|
||||||
Log_OC.d(TAG, "File-sync kill worker since syncedFolder ($syncedFolderID) is not enabled!")
|
syncedFolder.lastScanTimestampMs +
|
||||||
|
FilesSyncHelper.calculateScanInterval(syncedFolder, connectivityService, powerManagementService)
|
||||||
|
) <= System.currentTimeMillis()
|
||||||
|
|
||||||
|
if (!passedScanInterval && changedFiles.isNullOrEmpty() && !overridePowerSaving) {
|
||||||
|
Log_OC.d(
|
||||||
|
TAG,
|
||||||
|
"File-sync kill worker since started before scan " +
|
||||||
|
"Interval and nothing todo (${syncedFolder.localPath})!"
|
||||||
|
)
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -184,10 +213,12 @@ class FilesSyncWork(
|
||||||
// filesystemDataProvider database (potentially needs a long time)
|
// filesystemDataProvider database (potentially needs a long time)
|
||||||
FilesSyncHelper.insertAllDBEntriesForSyncedFolder(syncedFolder)
|
FilesSyncHelper.insertAllDBEntriesForSyncedFolder(syncedFolder)
|
||||||
}
|
}
|
||||||
|
syncedFolder.lastScanTimestampMs = System.currentTimeMillis()
|
||||||
|
syncedFolderProvider.updateSyncFolder(syncedFolder)
|
||||||
}
|
}
|
||||||
|
|
||||||
@Suppress("LongMethod") // legacy code
|
@Suppress("LongMethod") // legacy code
|
||||||
private fun syncFolder(
|
private fun uploadFilesFromFolder(
|
||||||
context: Context,
|
context: Context,
|
||||||
resources: Resources,
|
resources: Resources,
|
||||||
lightVersion: Boolean,
|
lightVersion: Boolean,
|
||||||
|
|
|
@ -2,7 +2,7 @@
|
||||||
* Nextcloud - Android Client
|
* Nextcloud - Android Client
|
||||||
*
|
*
|
||||||
* SPDX-FileCopyrightText: 2019 Chris Narkiewicz <hello@ezaquarii.com>
|
* SPDX-FileCopyrightText: 2019 Chris Narkiewicz <hello@ezaquarii.com>
|
||||||
* SPDX-FileCopyrightText: 2018 Tobias Kaminsky
|
* SPDX-FileCopyrightText: 2018 Tobias Kaminsky <tobias@kaminsky.me>
|
||||||
* SPDX-FileCopyrightText: 2018 Nextcloud GmbH
|
* SPDX-FileCopyrightText: 2018 Nextcloud GmbH
|
||||||
* SPDX-License-Identifier: AGPL-3.0-or-later OR GPL-2.0-only
|
* SPDX-License-Identifier: AGPL-3.0-or-later OR GPL-2.0-only
|
||||||
*/
|
*/
|
||||||
|
|
|
@ -1,9 +1,9 @@
|
||||||
/*
|
/*
|
||||||
* Nextcloud - Android Client
|
* Nextcloud - Android Client
|
||||||
*
|
*
|
||||||
* SPDX-FileCopyrightText: 2022 Álvaro Brey Vilas
|
* SPDX-FileCopyrightText: 2022 Álvaro Brey <alvaro@alvarobrey.com>
|
||||||
* SPDX-FileCopyrightText: 2022 Nextcloud GmbH
|
* SPDX-FileCopyrightText: 2022 Nextcloud GmbH
|
||||||
* SPDX-License-Identifier: GPL-3.0-or-later
|
* SPDX-License-Identifier: AGPL-3.0-or-later
|
||||||
*/
|
*/
|
||||||
package com.owncloud.android.ui.adapter
|
package com.owncloud.android.ui.adapter
|
||||||
|
|
||||||
|
|
|
@ -1,9 +1,9 @@
|
||||||
/*
|
/*
|
||||||
* Nextcloud - Android Client
|
* Nextcloud - Android Client
|
||||||
*
|
*
|
||||||
* SPDX-FileCopyrightText: 2022 Álvaro Brey Vilas
|
* SPDX-FileCopyrightText: 2022 Álvaro Brey <alvaro@alvarobrey.com>
|
||||||
* SPDX-FileCopyrightText: 2022 Nextcloud GmbH
|
* SPDX-FileCopyrightText: 2022 Nextcloud GmbH
|
||||||
* SPDX-License-Identifier: GPL-3.0-or-later
|
* SPDX-License-Identifier: AGPL-3.0-or-later
|
||||||
*/
|
*/
|
||||||
package com.owncloud.android.ui.dialog
|
package com.owncloud.android.ui.dialog
|
||||||
|
|
||||||
|
|
|
@ -1,9 +1,9 @@
|
||||||
/*
|
/*
|
||||||
* Nextcloud - Android Client
|
* Nextcloud - Android Client
|
||||||
*
|
*
|
||||||
* SPDX-FileCopyrightText: 2022 Álvaro Brey Vilas
|
* SPDX-FileCopyrightText: 2022 Álvaro Brey <alvaro@alvarobrey.com>
|
||||||
* SPDX-FileCopyrightText: 2022 Nextcloud GmbH
|
* SPDX-FileCopyrightText: 2022 Nextcloud GmbH
|
||||||
* SPDX-License-Identifier: GPL-3.0-or-later
|
* SPDX-License-Identifier: AGPL-3.0-or-later
|
||||||
*/
|
*/
|
||||||
package com.owncloud.android.ui.events
|
package com.owncloud.android.ui.events
|
||||||
|
|
||||||
|
|
|
@ -407,14 +407,19 @@ public class GalleryFragment extends OCFileListFragment implements GalleryFragme
|
||||||
|
|
||||||
private void updateSubtitle(GalleryFragmentBottomSheetDialog.MediaState mediaState) {
|
private void updateSubtitle(GalleryFragmentBottomSheetDialog.MediaState mediaState) {
|
||||||
requireActivity().runOnUiThread(() -> {
|
requireActivity().runOnUiThread(() -> {
|
||||||
String subTitle = requireContext().getResources().getString(R.string.subtitle_photos_videos);
|
if (!isAdded()) {
|
||||||
if (mediaState == GalleryFragmentBottomSheetDialog.MediaState.MEDIA_STATE_PHOTOS_ONLY) {
|
return;
|
||||||
subTitle = requireContext().getResources().getString(R.string.subtitle_photos_only);
|
|
||||||
} else if (mediaState == GalleryFragmentBottomSheetDialog.MediaState.MEDIA_STATE_VIDEOS_ONLY) {
|
|
||||||
subTitle = requireContext().getResources().getString(R.string.subtitle_videos_only);
|
|
||||||
}
|
}
|
||||||
if (requireActivity() instanceof ToolbarActivity) {
|
|
||||||
((ToolbarActivity) requireActivity()).updateToolbarSubtitle(subTitle);
|
String subTitle = getResources().getString(R.string.subtitle_photos_videos);
|
||||||
|
if (mediaState == GalleryFragmentBottomSheetDialog.MediaState.MEDIA_STATE_PHOTOS_ONLY) {
|
||||||
|
subTitle = getResources().getString(R.string.subtitle_photos_only);
|
||||||
|
} else if (mediaState == GalleryFragmentBottomSheetDialog.MediaState.MEDIA_STATE_VIDEOS_ONLY) {
|
||||||
|
subTitle = getResources().getString(R.string.subtitle_videos_only);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (requireActivity() instanceof ToolbarActivity toolbarActivity) {
|
||||||
|
toolbarActivity.updateToolbarSubtitle(subTitle);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,9 +1,9 @@
|
||||||
/*
|
/*
|
||||||
* Nextcloud - Android Client
|
* Nextcloud - Android Client
|
||||||
*
|
*
|
||||||
* SPDX-FileCopyrightText: 2022 Álvaro Brey Vilas <alvaro@alvarobrey.com>
|
* SPDX-FileCopyrightText: 2022 Álvaro Brey <alvaro@alvarobrey.com>
|
||||||
* SPDX-FileCopyrightText: 2022 Nextcloud GmbH
|
* SPDX-FileCopyrightText: 2022 Nextcloud GmbH
|
||||||
* SPDX-License-Identifier: GPL-3.0-or-later
|
* SPDX-License-Identifier: AGPL-3.0-or-later
|
||||||
*/
|
*/
|
||||||
package com.owncloud.android.ui.fragment
|
package com.owncloud.android.ui.fragment
|
||||||
|
|
||||||
|
|
|
@ -1,9 +1,9 @@
|
||||||
/*
|
/*
|
||||||
* Nextcloud - Android Client
|
* Nextcloud - Android Client
|
||||||
*
|
*
|
||||||
* SPDX-FileCopyrightText: 2022 Álvaro Brey Vilas <alvaro@alvarobrey.com>
|
* SPDX-FileCopyrightText: 2022 Álvaro Brey <alvaro@alvarobrey.com>
|
||||||
* SPDX-FileCopyrightText: 2022 Nextcloud GmbH
|
* SPDX-FileCopyrightText: 2022 Nextcloud GmbH
|
||||||
* SPDX-License-Identifier: GPL-3.0-or-later
|
* SPDX-License-Identifier: AGPL-3.0-or-later
|
||||||
*/
|
*/
|
||||||
package com.owncloud.android.ui.preview
|
package com.owncloud.android.ui.preview
|
||||||
|
|
||||||
|
|
|
@ -18,7 +18,6 @@ import android.widget.FrameLayout;
|
||||||
import android.widget.TextView;
|
import android.widget.TextView;
|
||||||
|
|
||||||
import com.nextcloud.client.account.User;
|
import com.nextcloud.client.account.User;
|
||||||
import com.nextcloud.client.account.UserAccountManager;
|
|
||||||
import com.nextcloud.ui.fileactions.FileActionsBottomSheet;
|
import com.nextcloud.ui.fileactions.FileActionsBottomSheet;
|
||||||
import com.nextcloud.utils.extensions.BundleExtensionsKt;
|
import com.nextcloud.utils.extensions.BundleExtensionsKt;
|
||||||
import com.nextcloud.utils.extensions.FileExtensionsKt;
|
import com.nextcloud.utils.extensions.FileExtensionsKt;
|
||||||
|
@ -29,7 +28,6 @@ import com.owncloud.android.ui.dialog.ConfirmationDialogFragment;
|
||||||
import com.owncloud.android.ui.dialog.RemoveFilesDialogFragment;
|
import com.owncloud.android.ui.dialog.RemoveFilesDialogFragment;
|
||||||
import com.owncloud.android.utils.DisplayUtils;
|
import com.owncloud.android.utils.DisplayUtils;
|
||||||
import com.owncloud.android.utils.MimeTypeUtil;
|
import com.owncloud.android.utils.MimeTypeUtil;
|
||||||
import com.owncloud.android.utils.theme.ViewThemeUtils;
|
|
||||||
|
|
||||||
import org.mozilla.universalchardet.ReaderFactory;
|
import org.mozilla.universalchardet.ReaderFactory;
|
||||||
|
|
||||||
|
@ -45,8 +43,6 @@ import java.util.LinkedList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Scanner;
|
import java.util.Scanner;
|
||||||
|
|
||||||
import javax.inject.Inject;
|
|
||||||
|
|
||||||
import androidx.annotation.NonNull;
|
import androidx.annotation.NonNull;
|
||||||
import androidx.appcompat.widget.SearchView;
|
import androidx.appcompat.widget.SearchView;
|
||||||
import androidx.core.view.MenuItemCompat;
|
import androidx.core.view.MenuItemCompat;
|
||||||
|
@ -64,9 +60,6 @@ public class PreviewTextFileFragment extends PreviewTextFragment {
|
||||||
private TextLoadAsyncTask textLoadAsyncTask;
|
private TextLoadAsyncTask textLoadAsyncTask;
|
||||||
private User user;
|
private User user;
|
||||||
|
|
||||||
@Inject UserAccountManager accountManager;
|
|
||||||
@Inject ViewThemeUtils viewThemeUtils;
|
|
||||||
|
|
||||||
public static PreviewTextFileFragment create(User user, OCFile file, boolean openSearch, String searchQuery) {
|
public static PreviewTextFileFragment create(User user, OCFile file, boolean openSearch, String searchQuery) {
|
||||||
Bundle args = new Bundle();
|
Bundle args = new Bundle();
|
||||||
args.putParcelable(EXTRA_FILE, file);
|
args.putParcelable(EXTRA_FILE, file);
|
||||||
|
@ -144,7 +137,7 @@ public class PreviewTextFileFragment extends PreviewTextFragment {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
void loadAndShowTextPreview() {
|
public void loadAndShowTextPreview() {
|
||||||
textLoadAsyncTask = new TextLoadAsyncTask(new WeakReference<>(binding.textPreview),
|
textLoadAsyncTask = new TextLoadAsyncTask(new WeakReference<>(binding.textPreview),
|
||||||
new WeakReference<>(binding.emptyListProgress));
|
new WeakReference<>(binding.emptyListProgress));
|
||||||
textLoadAsyncTask.execute(getFile().getStoragePath());
|
textLoadAsyncTask.execute(getFile().getStoragePath());
|
||||||
|
@ -228,7 +221,7 @@ public class PreviewTextFileFragment extends PreviewTextFragment {
|
||||||
if (searchView != null) {
|
if (searchView != null) {
|
||||||
searchView.setOnQueryTextListener(PreviewTextFileFragment.this);
|
searchView.setOnQueryTextListener(PreviewTextFileFragment.this);
|
||||||
|
|
||||||
if (searchOpen) {
|
if (searchOpen && searchView != null) {
|
||||||
searchView.setQuery(searchQuery, true);
|
searchView.setQuery(searchQuery, true);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,229 +0,0 @@
|
||||||
/*
|
|
||||||
* Nextcloud - Android Client
|
|
||||||
*
|
|
||||||
* SPDX-FileCopyrightText: 2019-2022 Tobias Kaminsky <tobias@kaminsky.me>
|
|
||||||
* SPDX-FileCopyrightText: 2019-2022 Andy Scherzinger <info@andy-scherzinger.de>
|
|
||||||
* SPDX-FileCopyrightText: 2019 Chris Narkiewicz <hello@ezaquarii.com>
|
|
||||||
* SPDX-FileCopyrightText: 2016 ownCloud Inc.
|
|
||||||
* SPDX-FileCopyrightText: 2014 Jorge Antonio Diaz-Benito Soriano <jorge.diazbenitosoriano@gmail.com>
|
|
||||||
* SPDX-License-Identifier: GPL-2.0-only AND (AGPL-3.0-or-later OR GPL-2.0-only)
|
|
||||||
*/
|
|
||||||
package com.owncloud.android.ui.preview;
|
|
||||||
|
|
||||||
import android.app.Activity;
|
|
||||||
import android.content.res.Resources;
|
|
||||||
import android.graphics.Color;
|
|
||||||
import android.os.Bundle;
|
|
||||||
import android.os.Handler;
|
|
||||||
import android.text.Html;
|
|
||||||
import android.text.Spanned;
|
|
||||||
import android.text.TextUtils;
|
|
||||||
import android.text.method.LinkMovementMethod;
|
|
||||||
import android.view.LayoutInflater;
|
|
||||||
import android.view.View;
|
|
||||||
import android.view.ViewGroup;
|
|
||||||
import android.widget.TextView;
|
|
||||||
|
|
||||||
import com.nextcloud.client.account.UserAccountManager;
|
|
||||||
import com.nextcloud.client.device.DeviceInfo;
|
|
||||||
import com.nextcloud.client.di.Injectable;
|
|
||||||
import com.owncloud.android.R;
|
|
||||||
import com.owncloud.android.databinding.TextFilePreviewBinding;
|
|
||||||
import com.owncloud.android.datamodel.OCFile;
|
|
||||||
import com.owncloud.android.lib.common.utils.Log_OC;
|
|
||||||
import com.owncloud.android.ui.activity.FileDisplayActivity;
|
|
||||||
import com.owncloud.android.ui.fragment.FileFragment;
|
|
||||||
import com.owncloud.android.utils.DisplayUtils;
|
|
||||||
import com.owncloud.android.utils.MimeTypeUtil;
|
|
||||||
import com.owncloud.android.utils.StringUtils;
|
|
||||||
import com.owncloud.android.utils.theme.ViewThemeUtils;
|
|
||||||
|
|
||||||
import javax.inject.Inject;
|
|
||||||
|
|
||||||
import androidx.annotation.NonNull;
|
|
||||||
import androidx.annotation.Nullable;
|
|
||||||
import androidx.appcompat.widget.SearchView;
|
|
||||||
import io.noties.markwon.AbstractMarkwonPlugin;
|
|
||||||
import io.noties.markwon.Markwon;
|
|
||||||
import io.noties.markwon.MarkwonConfiguration;
|
|
||||||
import io.noties.markwon.core.MarkwonTheme;
|
|
||||||
import io.noties.markwon.ext.strikethrough.StrikethroughPlugin;
|
|
||||||
import io.noties.markwon.ext.tables.TablePlugin;
|
|
||||||
import io.noties.markwon.ext.tasklist.TaskListDrawable;
|
|
||||||
import io.noties.markwon.ext.tasklist.TaskListPlugin;
|
|
||||||
import io.noties.markwon.html.HtmlPlugin;
|
|
||||||
import io.noties.markwon.syntax.Prism4jTheme;
|
|
||||||
import io.noties.markwon.syntax.Prism4jThemeDefault;
|
|
||||||
import io.noties.markwon.syntax.SyntaxHighlightPlugin;
|
|
||||||
import io.noties.prism4j.Prism4j;
|
|
||||||
import io.noties.prism4j.annotations.PrismBundle;
|
|
||||||
|
|
||||||
@PrismBundle(
|
|
||||||
include = {
|
|
||||||
"c", "clike", "clojure", "cpp", "csharp", "css", "dart", "git", "go", "groovy", "java", "javascript", "json",
|
|
||||||
"kotlin", "latex", "makefile", "markdown", "markup", "python", "scala", "sql", "swift", "yaml"
|
|
||||||
},
|
|
||||||
grammarLocatorClassName = ".MarkwonGrammarLocator"
|
|
||||||
)
|
|
||||||
public abstract class PreviewTextFragment extends FileFragment implements SearchView.OnQueryTextListener, Injectable {
|
|
||||||
private static final String TAG = PreviewTextFragment.class.getSimpleName();
|
|
||||||
|
|
||||||
protected SearchView searchView;
|
|
||||||
protected String searchQuery = "";
|
|
||||||
protected boolean searchOpen;
|
|
||||||
protected Handler handler;
|
|
||||||
protected String originalText;
|
|
||||||
|
|
||||||
@Inject UserAccountManager accountManager;
|
|
||||||
@Inject DeviceInfo deviceInfo;
|
|
||||||
@Inject ViewThemeUtils viewThemeUtils;
|
|
||||||
|
|
||||||
protected TextFilePreviewBinding binding;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* {@inheritDoc}
|
|
||||||
*/
|
|
||||||
@Override
|
|
||||||
public View onCreateView(@NonNull LayoutInflater inflater, ViewGroup container,
|
|
||||||
Bundle savedInstanceState) {
|
|
||||||
super.onCreateView(inflater, container, savedInstanceState);
|
|
||||||
Log_OC.e(TAG, "onCreateView");
|
|
||||||
|
|
||||||
binding = TextFilePreviewBinding.inflate(inflater, container, false);
|
|
||||||
View view = binding.getRoot();
|
|
||||||
|
|
||||||
binding.emptyListProgress.setVisibility(View.VISIBLE);
|
|
||||||
|
|
||||||
return view;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onStart() {
|
|
||||||
super.onStart();
|
|
||||||
Log_OC.e(TAG, "onStart");
|
|
||||||
|
|
||||||
loadAndShowTextPreview();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onDestroyView() {
|
|
||||||
super.onDestroyView();
|
|
||||||
binding = null;
|
|
||||||
}
|
|
||||||
|
|
||||||
abstract void loadAndShowTextPreview();
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean onQueryTextSubmit(String query) {
|
|
||||||
performSearch(query, 0);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean onQueryTextChange(final String newText) {
|
|
||||||
performSearch(newText, 500);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
private void performSearch(final String query, int delay) {
|
|
||||||
handler.removeCallbacksAndMessages(null);
|
|
||||||
|
|
||||||
if (originalText != null) {
|
|
||||||
if (getActivity() instanceof FileDisplayActivity) {
|
|
||||||
FileDisplayActivity fileDisplayActivity = (FileDisplayActivity) getActivity();
|
|
||||||
fileDisplayActivity.setSearchQuery(query);
|
|
||||||
}
|
|
||||||
handler.postDelayed(() -> markText(query), delay);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (delay == 0 && searchView != null) {
|
|
||||||
searchView.clearFocus();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void markText(String query) {
|
|
||||||
// called asynchronously - must check preconditions in case of UI detachment
|
|
||||||
if (binding == null) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
final Activity activity = getActivity();
|
|
||||||
if (activity == null) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
final Resources resources = activity.getResources();
|
|
||||||
if (resources == null) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!TextUtils.isEmpty(query)) {
|
|
||||||
String coloredText = StringUtils.searchAndColor(originalText,
|
|
||||||
query,
|
|
||||||
resources.getColor(R.color.primary));
|
|
||||||
binding.textPreview.setText(Html.fromHtml(coloredText.replace("\n", "<br \\>")));
|
|
||||||
} else {
|
|
||||||
setText(binding.textPreview, originalText, getFile(), activity, false, false, viewThemeUtils);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
protected static Spanned getRenderedMarkdownText(Activity activity,
|
|
||||||
String markdown,
|
|
||||||
ViewThemeUtils viewThemeUtils) {
|
|
||||||
Prism4j prism4j = new Prism4j(new MarkwonGrammarLocator());
|
|
||||||
Prism4jTheme prism4jTheme = Prism4jThemeDefault.create();
|
|
||||||
TaskListDrawable drawable = new TaskListDrawable(Color.GRAY, Color.GRAY, Color.WHITE);
|
|
||||||
viewThemeUtils.platform.tintPrimaryDrawable(activity, drawable);
|
|
||||||
|
|
||||||
final Markwon markwon = Markwon.builder(activity)
|
|
||||||
.usePlugin(new AbstractMarkwonPlugin() {
|
|
||||||
@Override
|
|
||||||
public void configureTheme(@NonNull MarkwonTheme.Builder builder) {
|
|
||||||
builder.linkColor(viewThemeUtils.platform.primaryColor(activity));
|
|
||||||
builder.headingBreakHeight(0);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void configureConfiguration(@NonNull MarkwonConfiguration.Builder builder) {
|
|
||||||
builder.linkResolver((view, link) -> DisplayUtils.startLinkIntent(activity, link));
|
|
||||||
}
|
|
||||||
})
|
|
||||||
.usePlugin(TablePlugin.create(activity))
|
|
||||||
.usePlugin(TaskListPlugin.create(drawable))
|
|
||||||
.usePlugin(StrikethroughPlugin.create())
|
|
||||||
.usePlugin(HtmlPlugin.create())
|
|
||||||
.usePlugin(SyntaxHighlightPlugin.create(prism4j, prism4jTheme))
|
|
||||||
.build();
|
|
||||||
|
|
||||||
return markwon.toMarkdown(markdown);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Finishes the preview
|
|
||||||
*/
|
|
||||||
protected void finish() {
|
|
||||||
requireActivity().runOnUiThread(() -> requireActivity().onBackPressed());
|
|
||||||
}
|
|
||||||
|
|
||||||
public static void setText(TextView textView,
|
|
||||||
@Nullable String text,
|
|
||||||
@Nullable OCFile file,
|
|
||||||
Activity activity,
|
|
||||||
boolean ignoreMimetype,
|
|
||||||
boolean preview,
|
|
||||||
ViewThemeUtils viewThemeUtils) {
|
|
||||||
if (text == null) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if ((ignoreMimetype || file != null && MimeTypeUtil.MIMETYPE_TEXT_MARKDOWN.equals(file.getMimeType()))
|
|
||||||
&& activity != null) {
|
|
||||||
if (!preview) {
|
|
||||||
// clickable links prevent to open full view of rich workspace
|
|
||||||
textView.setMovementMethod(LinkMovementMethod.getInstance());
|
|
||||||
}
|
|
||||||
textView.setText(getRenderedMarkdownText(activity, text, viewThemeUtils));
|
|
||||||
} else {
|
|
||||||
textView.setText(text);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -0,0 +1,243 @@
|
||||||
|
/*
|
||||||
|
* Nextcloud - Android Client
|
||||||
|
*
|
||||||
|
* SPDX-FileCopyrightText: 2024 Alper Ozturk <alper.ozturk@nextcloud.com>
|
||||||
|
* SPDX-FileCopyrightText: 2019-2022 Tobias Kaminsky <tobias@kaminsky.me>
|
||||||
|
* SPDX-FileCopyrightText: 2019-2022 Andy Scherzinger <info@andy-scherzinger.de>
|
||||||
|
* SPDX-FileCopyrightText: 2019 Chris Narkiewicz <hello@ezaquarii.com>
|
||||||
|
* SPDX-FileCopyrightText: 2016 ownCloud Inc.
|
||||||
|
* SPDX-FileCopyrightText: 2014 Jorge Antonio Diaz-Benito Soriano <jorge.diazbenitosoriano@gmail.com>
|
||||||
|
* SPDX-License-Identifier: GPL-2.0-only AND (AGPL-3.0-or-later OR GPL-2.0-only)
|
||||||
|
*/
|
||||||
|
package com.owncloud.android.ui.preview
|
||||||
|
|
||||||
|
import android.app.Activity
|
||||||
|
import android.graphics.Color
|
||||||
|
import android.os.Bundle
|
||||||
|
import android.os.Handler
|
||||||
|
import android.text.Spanned
|
||||||
|
import android.text.TextUtils
|
||||||
|
import android.text.method.LinkMovementMethod
|
||||||
|
import android.view.LayoutInflater
|
||||||
|
import android.view.View
|
||||||
|
import android.view.ViewGroup
|
||||||
|
import android.widget.TextView
|
||||||
|
import androidx.appcompat.widget.SearchView
|
||||||
|
import androidx.core.content.ContextCompat
|
||||||
|
import com.nextcloud.android.common.ui.theme.utils.ColorRole
|
||||||
|
import com.nextcloud.client.account.UserAccountManager
|
||||||
|
import com.nextcloud.client.device.DeviceInfo
|
||||||
|
import com.nextcloud.client.di.Injectable
|
||||||
|
import com.nextcloud.utils.extensions.setHtmlContent
|
||||||
|
import com.owncloud.android.MainApp
|
||||||
|
import com.owncloud.android.R
|
||||||
|
import com.owncloud.android.databinding.TextFilePreviewBinding
|
||||||
|
import com.owncloud.android.datamodel.OCFile
|
||||||
|
import com.owncloud.android.lib.common.utils.Log_OC
|
||||||
|
import com.owncloud.android.ui.activity.FileDisplayActivity
|
||||||
|
import com.owncloud.android.ui.fragment.FileFragment
|
||||||
|
import com.owncloud.android.utils.DisplayUtils
|
||||||
|
import com.owncloud.android.utils.MimeTypeUtil
|
||||||
|
import com.owncloud.android.utils.StringUtils
|
||||||
|
import com.owncloud.android.utils.theme.ViewThemeUtils
|
||||||
|
import io.noties.markwon.AbstractMarkwonPlugin
|
||||||
|
import io.noties.markwon.Markwon
|
||||||
|
import io.noties.markwon.MarkwonConfiguration
|
||||||
|
import io.noties.markwon.core.MarkwonTheme
|
||||||
|
import io.noties.markwon.ext.strikethrough.StrikethroughPlugin
|
||||||
|
import io.noties.markwon.ext.tables.TablePlugin
|
||||||
|
import io.noties.markwon.ext.tasklist.TaskListDrawable
|
||||||
|
import io.noties.markwon.ext.tasklist.TaskListPlugin
|
||||||
|
import io.noties.markwon.html.HtmlPlugin
|
||||||
|
import io.noties.markwon.syntax.Prism4jTheme
|
||||||
|
import io.noties.markwon.syntax.Prism4jThemeDefault
|
||||||
|
import io.noties.markwon.syntax.SyntaxHighlightPlugin
|
||||||
|
import io.noties.prism4j.Prism4j
|
||||||
|
import io.noties.prism4j.annotations.PrismBundle
|
||||||
|
import javax.inject.Inject
|
||||||
|
|
||||||
|
@PrismBundle(
|
||||||
|
include = [
|
||||||
|
"c", "clike", "clojure", "cpp", "csharp", "css", "dart", "git", "go", "groovy", "java",
|
||||||
|
"javascript", "json", "kotlin", "latex", "makefile", "markdown", "markup", "python", "scala",
|
||||||
|
"sql", "swift", "yaml"
|
||||||
|
],
|
||||||
|
grammarLocatorClassName = ".MarkwonGrammarLocator"
|
||||||
|
)
|
||||||
|
abstract class PreviewTextFragment : FileFragment(), SearchView.OnQueryTextListener, Injectable {
|
||||||
|
|
||||||
|
@JvmField
|
||||||
|
protected var searchView: SearchView? = null
|
||||||
|
|
||||||
|
@JvmField
|
||||||
|
protected var searchQuery: String = ""
|
||||||
|
|
||||||
|
@JvmField
|
||||||
|
protected var searchOpen: Boolean = false
|
||||||
|
|
||||||
|
@JvmField
|
||||||
|
protected var handler: Handler? = null
|
||||||
|
|
||||||
|
@JvmField
|
||||||
|
protected var originalText: String? = null
|
||||||
|
|
||||||
|
@Inject
|
||||||
|
lateinit var accountManager: UserAccountManager
|
||||||
|
|
||||||
|
@Inject
|
||||||
|
lateinit var deviceInfo: DeviceInfo
|
||||||
|
|
||||||
|
@Inject
|
||||||
|
lateinit var viewThemeUtils: ViewThemeUtils
|
||||||
|
|
||||||
|
protected lateinit var binding: TextFilePreviewBinding
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@inheritDoc}
|
||||||
|
*/
|
||||||
|
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? {
|
||||||
|
super.onCreateView(inflater, container, savedInstanceState)
|
||||||
|
Log_OC.e(TAG, "onCreateView")
|
||||||
|
|
||||||
|
binding = TextFilePreviewBinding.inflate(inflater, container, false)
|
||||||
|
|
||||||
|
binding.emptyListProgress.visibility = View.VISIBLE
|
||||||
|
|
||||||
|
return binding.root
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onStart() {
|
||||||
|
super.onStart()
|
||||||
|
Log_OC.e(TAG, "onStart")
|
||||||
|
|
||||||
|
loadAndShowTextPreview()
|
||||||
|
}
|
||||||
|
|
||||||
|
abstract fun loadAndShowTextPreview()
|
||||||
|
|
||||||
|
override fun onQueryTextSubmit(query: String): Boolean {
|
||||||
|
performSearch(query, 0)
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
@Suppress("MagicNumber")
|
||||||
|
override fun onQueryTextChange(newText: String): Boolean {
|
||||||
|
performSearch(newText, 500)
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun performSearch(query: String, delay: Int) {
|
||||||
|
handler?.removeCallbacksAndMessages(null)
|
||||||
|
|
||||||
|
if (originalText != null) {
|
||||||
|
if (activity is FileDisplayActivity) {
|
||||||
|
val fileDisplayActivity = activity as FileDisplayActivity?
|
||||||
|
fileDisplayActivity?.setSearchQuery(query)
|
||||||
|
}
|
||||||
|
handler?.postDelayed({ markText(query) }, delay.toLong())
|
||||||
|
}
|
||||||
|
|
||||||
|
if (delay == 0 && searchView != null) {
|
||||||
|
searchView?.clearFocus()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun markText(query: String) {
|
||||||
|
if (!TextUtils.isEmpty(query)) {
|
||||||
|
val coloredText = StringUtils.searchAndColor(
|
||||||
|
originalText,
|
||||||
|
query,
|
||||||
|
ContextCompat.getColor(requireContext(), R.color.primary)
|
||||||
|
)
|
||||||
|
|
||||||
|
binding.textPreview.setHtmlContent(coloredText.replace("\n", "<br \\>"))
|
||||||
|
} else {
|
||||||
|
val activity = activity ?: return
|
||||||
|
setText(binding.textPreview, originalText, file, activity, false, false, viewThemeUtils)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Finishes the preview
|
||||||
|
*/
|
||||||
|
protected fun finish() {
|
||||||
|
requireActivity().runOnUiThread { requireActivity().onBackPressed() }
|
||||||
|
}
|
||||||
|
|
||||||
|
companion object {
|
||||||
|
private val TAG: String = PreviewTextFragment::class.java.simpleName
|
||||||
|
|
||||||
|
protected fun getRenderedMarkdownText(
|
||||||
|
activity: Activity?,
|
||||||
|
markdown: String?,
|
||||||
|
viewThemeUtils: ViewThemeUtils?
|
||||||
|
): Spanned {
|
||||||
|
val prism4j = Prism4j(MarkwonGrammarLocator())
|
||||||
|
val prism4jTheme: Prism4jTheme = Prism4jThemeDefault.create()
|
||||||
|
val drawable = TaskListDrawable(Color.GRAY, Color.GRAY, Color.WHITE)
|
||||||
|
|
||||||
|
if (activity == null || markdown == null) {
|
||||||
|
return Markwon.builder(MainApp.getAppContext()).build().toMarkdown(markdown ?: "")
|
||||||
|
}
|
||||||
|
|
||||||
|
viewThemeUtils?.platform?.tintDrawable(activity, drawable, ColorRole.PRIMARY)
|
||||||
|
|
||||||
|
val markwon = Markwon.builder(activity)
|
||||||
|
.usePlugin(object : AbstractMarkwonPlugin() {
|
||||||
|
override fun configureTheme(builder: MarkwonTheme.Builder) {
|
||||||
|
val linkColor = viewThemeUtils?.platform?.primaryColor(activity)
|
||||||
|
linkColor?.let {
|
||||||
|
builder.linkColor(it)
|
||||||
|
}
|
||||||
|
|
||||||
|
builder.headingBreakHeight(0)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun configureConfiguration(builder: MarkwonConfiguration.Builder) {
|
||||||
|
builder.linkResolver { _: View?, link: String? ->
|
||||||
|
DisplayUtils.startLinkIntent(
|
||||||
|
activity,
|
||||||
|
link
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.usePlugin(TablePlugin.create(activity))
|
||||||
|
.usePlugin(TaskListPlugin.create(drawable))
|
||||||
|
.usePlugin(StrikethroughPlugin.create())
|
||||||
|
.usePlugin(HtmlPlugin.create())
|
||||||
|
.usePlugin(SyntaxHighlightPlugin.create(prism4j, prism4jTheme))
|
||||||
|
.build()
|
||||||
|
|
||||||
|
return markwon.toMarkdown(markdown)
|
||||||
|
}
|
||||||
|
|
||||||
|
@Suppress("LongParameterList", "ComplexCondition")
|
||||||
|
@JvmStatic
|
||||||
|
fun setText(
|
||||||
|
textView: TextView,
|
||||||
|
text: String?,
|
||||||
|
file: OCFile?,
|
||||||
|
activity: Activity?,
|
||||||
|
ignoreMimetype: Boolean,
|
||||||
|
preview: Boolean,
|
||||||
|
viewThemeUtils: ViewThemeUtils?
|
||||||
|
) {
|
||||||
|
if (text == null) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((ignoreMimetype || file != null && MimeTypeUtil.MIMETYPE_TEXT_MARKDOWN == file.mimeType) &&
|
||||||
|
activity != null
|
||||||
|
) {
|
||||||
|
if (!preview) {
|
||||||
|
// clickable links prevent to open full view of rich workspace
|
||||||
|
textView.movementMethod = LinkMovementMethod.getInstance()
|
||||||
|
}
|
||||||
|
textView.text = getRenderedMarkdownText(activity, text, viewThemeUtils)
|
||||||
|
} else {
|
||||||
|
textView.text = text
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -18,15 +18,11 @@ import android.view.ViewGroup;
|
||||||
|
|
||||||
import com.google.android.material.floatingactionbutton.FloatingActionButton;
|
import com.google.android.material.floatingactionbutton.FloatingActionButton;
|
||||||
import com.nextcloud.android.lib.richWorkspace.RichWorkspaceDirectEditingRemoteOperation;
|
import com.nextcloud.android.lib.richWorkspace.RichWorkspaceDirectEditingRemoteOperation;
|
||||||
import com.nextcloud.client.account.UserAccountManager;
|
|
||||||
import com.nextcloud.utils.extensions.FileExtensionsKt;
|
import com.nextcloud.utils.extensions.FileExtensionsKt;
|
||||||
import com.owncloud.android.R;
|
import com.owncloud.android.R;
|
||||||
import com.owncloud.android.lib.common.operations.RemoteOperationResult;
|
import com.owncloud.android.lib.common.operations.RemoteOperationResult;
|
||||||
import com.owncloud.android.ui.activity.FileDisplayActivity;
|
import com.owncloud.android.ui.activity.FileDisplayActivity;
|
||||||
import com.owncloud.android.utils.DisplayUtils;
|
import com.owncloud.android.utils.DisplayUtils;
|
||||||
import com.owncloud.android.utils.theme.ViewThemeUtils;
|
|
||||||
|
|
||||||
import javax.inject.Inject;
|
|
||||||
|
|
||||||
import androidx.annotation.NonNull;
|
import androidx.annotation.NonNull;
|
||||||
import androidx.appcompat.widget.SearchView;
|
import androidx.appcompat.widget.SearchView;
|
||||||
|
@ -35,9 +31,6 @@ import androidx.core.view.MenuItemCompat;
|
||||||
public class PreviewTextStringFragment extends PreviewTextFragment {
|
public class PreviewTextStringFragment extends PreviewTextFragment {
|
||||||
private static final String EXTRA_FILE = "FILE";
|
private static final String EXTRA_FILE = "FILE";
|
||||||
|
|
||||||
@Inject UserAccountManager accountManager;
|
|
||||||
@Inject ViewThemeUtils viewThemeUtils;
|
|
||||||
|
|
||||||
private final static String TAG = "PreviewTextStringFragment";
|
private final static String TAG = "PreviewTextStringFragment";
|
||||||
private boolean isEditorWebviewLaunched = false;
|
private boolean isEditorWebviewLaunched = false;
|
||||||
|
|
||||||
|
@ -128,7 +121,7 @@ public class PreviewTextStringFragment extends PreviewTextFragment {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void loadAndShowTextPreview() {
|
public void loadAndShowTextPreview() {
|
||||||
originalText = getFile().getRichWorkspace();
|
originalText = getFile().getRichWorkspace();
|
||||||
setText(binding.textPreview, originalText, getFile(), requireActivity(), true, false, viewThemeUtils);
|
setText(binding.textPreview, originalText, getFile(), requireActivity(), true, false, viewThemeUtils);
|
||||||
|
|
||||||
|
|
|
@ -1,9 +1,9 @@
|
||||||
/*
|
/*
|
||||||
* Nextcloud - Android Client
|
* Nextcloud - Android Client
|
||||||
*
|
*
|
||||||
* SPDX-FileCopyrightText: 2022 Álvaro Brey Vilas <alvaro@alvarobrey.com>
|
* SPDX-FileCopyrightText: 2022 Álvaro Brey <alvaro@alvarobrey.com>
|
||||||
* SPDX-FileCopyrightText: 2022 Nextcloud GmbH
|
* SPDX-FileCopyrightText: 2022 Nextcloud GmbH
|
||||||
* SPDX-License-Identifier: GPL-3.0-or-later
|
* SPDX-License-Identifier: AGPL-3.0-or-later
|
||||||
*/
|
*/
|
||||||
package com.owncloud.android.ui.preview.pdf
|
package com.owncloud.android.ui.preview.pdf
|
||||||
|
|
||||||
|
|
|
@ -1,9 +1,9 @@
|
||||||
/*
|
/*
|
||||||
* Nextcloud - Android Client
|
* Nextcloud - Android Client
|
||||||
*
|
*
|
||||||
* SPDX-FileCopyrightText: 2022 Álvaro Brey Vilas <alvaro@alvarobrey.com>
|
* SPDX-FileCopyrightText: 2022 Álvaro Brey <alvaro@alvarobrey.com>
|
||||||
* SPDX-FileCopyrightText: 2022 Nextcloud GmbH
|
* SPDX-FileCopyrightText: 2022 Nextcloud GmbH
|
||||||
* SPDX-License-Identifier: GPL-3.0-or-later
|
* SPDX-License-Identifier: AGPL-3.0-or-later
|
||||||
*/
|
*/
|
||||||
package com.owncloud.android.ui.preview.pdf
|
package com.owncloud.android.ui.preview.pdf
|
||||||
|
|
||||||
|
|
|
@ -1,9 +1,9 @@
|
||||||
/*
|
/*
|
||||||
* Nextcloud - Android Client
|
* Nextcloud - Android Client
|
||||||
*
|
*
|
||||||
* SPDX-FileCopyrightText: 2022 Álvaro Brey Vilas <alvaro@alvarobrey.com>
|
* SPDX-FileCopyrightText: 2022 Álvaro Brey <alvaro@alvarobrey.com>
|
||||||
* SPDX-FileCopyrightText: 2022 Nextcloud GmbH
|
* SPDX-FileCopyrightText: 2022 Nextcloud GmbH
|
||||||
* SPDX-License-Identifier: GPL-3.0-or-later
|
* SPDX-License-Identifier: AGPL-3.0-or-later
|
||||||
*/
|
*/
|
||||||
package com.owncloud.android.ui.preview.pdf
|
package com.owncloud.android.ui.preview.pdf
|
||||||
|
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
/*
|
/*
|
||||||
* Nextcloud - Android Client
|
* Nextcloud - Android Client
|
||||||
*
|
*
|
||||||
|
* SPDX-FileCopyrightText: 2024 Jonas Mayer <jonas.mayer@nextcloud.com>
|
||||||
* SPDX-FileCopyrightText: 2020 Chris Narkiewicz <hello@ezaquarii.com>
|
* SPDX-FileCopyrightText: 2020 Chris Narkiewicz <hello@ezaquarii.com>
|
||||||
* SPDX-FileCopyrightText: 2017 Mario Danic <mario@lovelyhq.com>
|
* SPDX-FileCopyrightText: 2017 Mario Danic <mario@lovelyhq.com>
|
||||||
* SPDX-FileCopyrightText: 2017 Nextcloud GmbH
|
* SPDX-FileCopyrightText: 2017 Nextcloud GmbH
|
||||||
|
@ -17,6 +18,7 @@ import android.provider.MediaStore;
|
||||||
import com.nextcloud.client.account.UserAccountManager;
|
import com.nextcloud.client.account.UserAccountManager;
|
||||||
import com.nextcloud.client.device.PowerManagementService;
|
import com.nextcloud.client.device.PowerManagementService;
|
||||||
import com.nextcloud.client.jobs.BackgroundJobManager;
|
import com.nextcloud.client.jobs.BackgroundJobManager;
|
||||||
|
import com.nextcloud.client.jobs.BackgroundJobManagerImpl;
|
||||||
import com.nextcloud.client.jobs.upload.FileUploadHelper;
|
import com.nextcloud.client.jobs.upload.FileUploadHelper;
|
||||||
import com.nextcloud.client.network.ConnectivityService;
|
import com.nextcloud.client.network.ConnectivityService;
|
||||||
import com.owncloud.android.MainApp;
|
import com.owncloud.android.MainApp;
|
||||||
|
@ -27,15 +29,20 @@ import com.owncloud.android.datamodel.SyncedFolderProvider;
|
||||||
import com.owncloud.android.datamodel.UploadsStorageManager;
|
import com.owncloud.android.datamodel.UploadsStorageManager;
|
||||||
import com.owncloud.android.lib.common.utils.Log_OC;
|
import com.owncloud.android.lib.common.utils.Log_OC;
|
||||||
|
|
||||||
|
import org.lukhnos.nnio.file.AccessDeniedException;
|
||||||
import org.lukhnos.nnio.file.FileVisitResult;
|
import org.lukhnos.nnio.file.FileVisitResult;
|
||||||
|
import org.lukhnos.nnio.file.FileVisitor;
|
||||||
import org.lukhnos.nnio.file.Path;
|
import org.lukhnos.nnio.file.Path;
|
||||||
import org.lukhnos.nnio.file.Paths;
|
import org.lukhnos.nnio.file.Paths;
|
||||||
import org.lukhnos.nnio.file.SimpleFileVisitor;
|
import org.lukhnos.nnio.file.SimpleFileVisitor;
|
||||||
import org.lukhnos.nnio.file.attribute.BasicFileAttributes;
|
import org.lukhnos.nnio.file.attribute.BasicFileAttributes;
|
||||||
import org.lukhnos.nnio.file.Files;
|
import org.lukhnos.nnio.file.Files;
|
||||||
|
import org.lukhnos.nnio.file.impl.FileBasedPathImpl;
|
||||||
|
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
|
import java.util.Arrays;
|
||||||
|
import java.util.Collections;
|
||||||
|
|
||||||
import static com.owncloud.android.datamodel.OCFile.PATH_SEPARATOR;
|
import static com.owncloud.android.datamodel.OCFile.PATH_SEPARATOR;
|
||||||
|
|
||||||
|
@ -51,16 +58,50 @@ public final class FilesSyncHelper {
|
||||||
// utility class -> private constructor
|
// utility class -> private constructor
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Copy of {@link Files#walkFileTree(Path, FileVisitor)} that walks the file tree in random order.
|
||||||
|
*
|
||||||
|
* @see org.lukhnos.nnio.file.Files#walkFileTree(Path, FileVisitor)
|
||||||
|
*/
|
||||||
|
public static void walkFileTreeRandomly(Path start, FileVisitor<? super Path> visitor) throws IOException {
|
||||||
|
File file = start.toFile();
|
||||||
|
if (!file.canRead()) {
|
||||||
|
visitor.visitFileFailed(start, new AccessDeniedException(file.toString()));
|
||||||
|
} else {
|
||||||
|
if (Files.isDirectory(start)) {
|
||||||
|
FileVisitResult preVisitDirectoryResult = visitor.preVisitDirectory(start, (BasicFileAttributes)null);
|
||||||
|
if (preVisitDirectoryResult == FileVisitResult.CONTINUE) {
|
||||||
|
File[] children = start.toFile().listFiles();
|
||||||
|
Collections.shuffle(Arrays.asList(children));
|
||||||
|
if (children != null) {
|
||||||
|
File[] var5 = children;
|
||||||
|
int var6 = children.length;
|
||||||
|
|
||||||
|
for(int var7 = 0; var7 < var6; ++var7) {
|
||||||
|
File child = var5[var7];
|
||||||
|
walkFileTreeRandomly(FileBasedPathImpl.get(child), visitor);
|
||||||
|
}
|
||||||
|
|
||||||
|
visitor.postVisitDirectory(start, (IOException)null);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
visitor.visitFile(start, new BasicFileAttributes(file));
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private static void insertCustomFolderIntoDB(Path path,
|
private static void insertCustomFolderIntoDB(Path path,
|
||||||
SyncedFolder syncedFolder,
|
SyncedFolder syncedFolder,
|
||||||
FilesystemDataProvider filesystemDataProvider,
|
FilesystemDataProvider filesystemDataProvider,
|
||||||
long lastCheck,
|
long lastCheck) {
|
||||||
long thisCheck) {
|
|
||||||
|
|
||||||
final long enabledTimestampMs = syncedFolder.getEnabledTimestampMs();
|
final long enabledTimestampMs = syncedFolder.getEnabledTimestampMs();
|
||||||
|
|
||||||
try {
|
try {
|
||||||
Files.walkFileTree(path, new SimpleFileVisitor<>() {
|
|
||||||
|
walkFileTreeRandomly(path, new SimpleFileVisitor<>() {
|
||||||
@Override
|
@Override
|
||||||
public FileVisitResult visitFile(Path path, BasicFileAttributes attrs) {
|
public FileVisitResult visitFile(Path path, BasicFileAttributes attrs) {
|
||||||
File file = path.toFile();
|
File file = path.toFile();
|
||||||
|
@ -98,7 +139,6 @@ public final class FilesSyncHelper {
|
||||||
return FileVisitResult.CONTINUE;
|
return FileVisitResult.CONTINUE;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
syncedFolder.setLastScanTimestampMs(thisCheck);
|
|
||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
Log_OC.e(TAG, "Something went wrong while indexing files for auto upload", e);
|
Log_OC.e(TAG, "Something went wrong while indexing files for auto upload", e);
|
||||||
}
|
}
|
||||||
|
@ -113,7 +153,6 @@ public final class FilesSyncHelper {
|
||||||
if (syncedFolder.isEnabled() && (syncedFolder.isExisting() || enabledTimestampMs >= 0)) {
|
if (syncedFolder.isEnabled() && (syncedFolder.isExisting() || enabledTimestampMs >= 0)) {
|
||||||
MediaFolderType mediaType = syncedFolder.getType();
|
MediaFolderType mediaType = syncedFolder.getType();
|
||||||
final long lastCheckTimestampMs = syncedFolder.getLastScanTimestampMs();
|
final long lastCheckTimestampMs = syncedFolder.getLastScanTimestampMs();
|
||||||
final long thisCheckTimestampMs = System.currentTimeMillis();
|
|
||||||
|
|
||||||
Log_OC.d(TAG,"File-sync start check folder "+syncedFolder.getLocalPath());
|
Log_OC.d(TAG,"File-sync start check folder "+syncedFolder.getLocalPath());
|
||||||
long startTime = System.nanoTime();
|
long startTime = System.nanoTime();
|
||||||
|
@ -121,21 +160,21 @@ public final class FilesSyncHelper {
|
||||||
if (mediaType == MediaFolderType.IMAGE) {
|
if (mediaType == MediaFolderType.IMAGE) {
|
||||||
FilesSyncHelper.insertContentIntoDB(MediaStore.Images.Media.INTERNAL_CONTENT_URI,
|
FilesSyncHelper.insertContentIntoDB(MediaStore.Images.Media.INTERNAL_CONTENT_URI,
|
||||||
syncedFolder,
|
syncedFolder,
|
||||||
lastCheckTimestampMs, thisCheckTimestampMs);
|
lastCheckTimestampMs);
|
||||||
FilesSyncHelper.insertContentIntoDB(MediaStore.Images.Media.EXTERNAL_CONTENT_URI,
|
FilesSyncHelper.insertContentIntoDB(MediaStore.Images.Media.EXTERNAL_CONTENT_URI,
|
||||||
syncedFolder,
|
syncedFolder,
|
||||||
lastCheckTimestampMs, thisCheckTimestampMs);
|
lastCheckTimestampMs);
|
||||||
} else if (mediaType == MediaFolderType.VIDEO) {
|
} else if (mediaType == MediaFolderType.VIDEO) {
|
||||||
FilesSyncHelper.insertContentIntoDB(MediaStore.Video.Media.INTERNAL_CONTENT_URI,
|
FilesSyncHelper.insertContentIntoDB(MediaStore.Video.Media.INTERNAL_CONTENT_URI,
|
||||||
syncedFolder,
|
syncedFolder,
|
||||||
lastCheckTimestampMs, thisCheckTimestampMs);
|
lastCheckTimestampMs);
|
||||||
FilesSyncHelper.insertContentIntoDB(MediaStore.Video.Media.EXTERNAL_CONTENT_URI,
|
FilesSyncHelper.insertContentIntoDB(MediaStore.Video.Media.EXTERNAL_CONTENT_URI,
|
||||||
syncedFolder,
|
syncedFolder,
|
||||||
lastCheckTimestampMs, thisCheckTimestampMs);
|
lastCheckTimestampMs);
|
||||||
} else {
|
} else {
|
||||||
FilesystemDataProvider filesystemDataProvider = new FilesystemDataProvider(contentResolver);
|
FilesystemDataProvider filesystemDataProvider = new FilesystemDataProvider(contentResolver);
|
||||||
Path path = Paths.get(syncedFolder.getLocalPath());
|
Path path = Paths.get(syncedFolder.getLocalPath());
|
||||||
FilesSyncHelper.insertCustomFolderIntoDB(path, syncedFolder, filesystemDataProvider, lastCheckTimestampMs, thisCheckTimestampMs);
|
FilesSyncHelper.insertCustomFolderIntoDB(path, syncedFolder, filesystemDataProvider, lastCheckTimestampMs);
|
||||||
}
|
}
|
||||||
|
|
||||||
Log_OC.d(TAG,"File-sync finished full check for custom folder "+syncedFolder.getLocalPath()+" within "+(System.nanoTime() - startTime)+ "ns");
|
Log_OC.d(TAG,"File-sync finished full check for custom folder "+syncedFolder.getLocalPath()+" within "+(System.nanoTime() - startTime)+ "ns");
|
||||||
|
@ -177,7 +216,7 @@ public final class FilesSyncHelper {
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void insertContentIntoDB(Uri uri, SyncedFolder syncedFolder,
|
private static void insertContentIntoDB(Uri uri, SyncedFolder syncedFolder,
|
||||||
long lastCheckTimestampMs, long thisCheckTimestampMs) {
|
long lastCheckTimestampMs) {
|
||||||
final Context context = MainApp.getAppContext();
|
final Context context = MainApp.getAppContext();
|
||||||
final ContentResolver contentResolver = context.getContentResolver();
|
final ContentResolver contentResolver = context.getContentResolver();
|
||||||
|
|
||||||
|
@ -224,7 +263,6 @@ public final class FilesSyncHelper {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
cursor.close();
|
cursor.close();
|
||||||
syncedFolder.setLastScanTimestampMs(thisCheckTimestampMs);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -260,5 +298,34 @@ public final class FilesSyncHelper {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static long calculateScanInterval(
|
||||||
|
SyncedFolder syncedFolder,
|
||||||
|
ConnectivityService connectivityService,
|
||||||
|
PowerManagementService powerManagementService
|
||||||
|
) {
|
||||||
|
long defaultInterval = BackgroundJobManagerImpl.DEFAULT_PERIODIC_JOB_INTERVAL_MINUTES * 1000 * 60;
|
||||||
|
if (!connectivityService.isConnected() || connectivityService.isInternetWalled()) {
|
||||||
|
return defaultInterval * 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((syncedFolder.isWifiOnly() && !connectivityService.getConnectivity().isWifi())) {
|
||||||
|
return defaultInterval * 4;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (powerManagementService.getBattery().getLevel() < 80){
|
||||||
|
return defaultInterval * 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (powerManagementService.getBattery().getLevel() < 50){
|
||||||
|
return defaultInterval * 4;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (powerManagementService.getBattery().getLevel() < 20){
|
||||||
|
return defaultInterval * 8;
|
||||||
|
}
|
||||||
|
|
||||||
|
return defaultInterval;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -516,6 +516,7 @@
|
||||||
|
|
||||||
قد تستغرق هذه العملية بعض الوقت.</string>
|
قد تستغرق هذه العملية بعض الوقت.</string>
|
||||||
<string name="manage_space_title">إدارة المساحة</string>
|
<string name="manage_space_title">إدارة المساحة</string>
|
||||||
|
<string name="max_file_count_warning_message">تجاوزت الحد الأقصى المسموح به لزمن رفع الملفات. رجاءً، لا تقم برفع عدد يزيد عن 500 ملف في كل مرة.</string>
|
||||||
<string name="media_err_invalid_progressive_playback">ملف الوسائط لا يمكن بثه</string>
|
<string name="media_err_invalid_progressive_playback">ملف الوسائط لا يمكن بثه</string>
|
||||||
<string name="media_err_io">تعذرت قراءة ملف الوسائط</string>
|
<string name="media_err_io">تعذرت قراءة ملف الوسائط</string>
|
||||||
<string name="media_err_malformed">يحتوي ملف الوسائط على ترميز غير صحيح</string>
|
<string name="media_err_malformed">يحتوي ملف الوسائط على ترميز غير صحيح</string>
|
||||||
|
@ -670,8 +671,11 @@
|
||||||
<string name="prefs_value_theme_light">فاتح</string>
|
<string name="prefs_value_theme_light">فاتح</string>
|
||||||
<string name="prefs_value_theme_system">اتبع النظام</string>
|
<string name="prefs_value_theme_system">اتبع النظام</string>
|
||||||
<string name="preview_image_description">معاينة الصورة</string>
|
<string name="preview_image_description">معاينة الصورة</string>
|
||||||
|
<string name="preview_image_downloading_image_for_edit">جارٍ تنزيل الصورة لبدء شاشة التعديل، يرجى الانتظار...</string>
|
||||||
<string name="preview_image_error_no_local_file">لا يوجد ملف محلي للمعاينة</string>
|
<string name="preview_image_error_no_local_file">لا يوجد ملف محلي للمعاينة</string>
|
||||||
<string name="preview_image_error_unknown_format">تعذرت عملية عرض الصورة</string>
|
<string name="preview_image_error_unknown_format">تعذرت عملية عرض الصورة</string>
|
||||||
|
<string name="preview_image_file_is_not_downloaded">لم يتم تنزيل الملف</string>
|
||||||
|
<string name="preview_image_file_is_not_exist">الملف غير موجود</string>
|
||||||
<string name="preview_media_unhandled_http_code_message">الملف مقفلٌ حالياً من قِبَل مستخدِمٍ أو عمليةٍ أخرى؛ وبالتالي لا يمكن حذفه. الرجاء معاودة المحاولة في وقتٍ لاحقٍ.</string>
|
<string name="preview_media_unhandled_http_code_message">الملف مقفلٌ حالياً من قِبَل مستخدِمٍ أو عمليةٍ أخرى؛ وبالتالي لا يمكن حذفه. الرجاء معاودة المحاولة في وقتٍ لاحقٍ.</string>
|
||||||
<string name="preview_sorry">آسف</string>
|
<string name="preview_sorry">آسف</string>
|
||||||
<string name="privacy">الخصوصية</string>
|
<string name="privacy">الخصوصية</string>
|
||||||
|
@ -911,6 +915,9 @@
|
||||||
<string name="trashbin_file_remove">حذف نهائي</string>
|
<string name="trashbin_file_remove">حذف نهائي</string>
|
||||||
<string name="trashbin_loading_failed">فشل تحميل سلة المحذوفات</string>
|
<string name="trashbin_loading_failed">فشل تحميل سلة المحذوفات</string>
|
||||||
<string name="trashbin_not_emptied">تعذر حذف الملفات نهائياً!</string>
|
<string name="trashbin_not_emptied">تعذر حذف الملفات نهائياً!</string>
|
||||||
|
<string name="unified_search_fragment_calendar_event_not_found">لم يمكن العثور على الحدث. يمكنك دائمًا المزامنة للتحديث. جارٍ إعادة التوجيه إلى الويب...</string>
|
||||||
|
<string name="unified_search_fragment_contact_not_found">لم يمكن العثور على جهة الاتصال. يمكنك دائمًا المزامنة للتحديث. جارٍ إعادة التوجيه إلى الويب...</string>
|
||||||
|
<string name="unified_search_fragment_permission_needed">مطلوب أذونات لفتح نتيجة البحث و إلّا ستتم إعادة توجيهها إلى الويب...</string>
|
||||||
<string name="unlock_file">فتح قفل الملف</string>
|
<string name="unlock_file">فتح قفل الملف</string>
|
||||||
<string name="unread_comments">توجد تعليقات غير مقروءة</string>
|
<string name="unread_comments">توجد تعليقات غير مقروءة</string>
|
||||||
<string name="unset_encrypted">لم يتم تحديد التشفير</string>
|
<string name="unset_encrypted">لم يتم تحديد التشفير</string>
|
||||||
|
|
|
@ -512,6 +512,7 @@
|
||||||
<string name="manage_space_clear_data">Daten löschen</string>
|
<string name="manage_space_clear_data">Daten löschen</string>
|
||||||
<string name="manage_space_description">Einstellungen, Datenbank und Server-Zertifikate von %1$s\'s Daten werden dauerhaft gelöscht.\n\nHerunter geladene Dateien bleiben unangetastet.\n\nDieser Vorgang kann eine Zeit dauern.</string>
|
<string name="manage_space_description">Einstellungen, Datenbank und Server-Zertifikate von %1$s\'s Daten werden dauerhaft gelöscht.\n\nHerunter geladene Dateien bleiben unangetastet.\n\nDieser Vorgang kann eine Zeit dauern.</string>
|
||||||
<string name="manage_space_title">Verwalte Speicherplatz</string>
|
<string name="manage_space_title">Verwalte Speicherplatz</string>
|
||||||
|
<string name="max_file_count_warning_message">Sie haben die maximale Anzahl an Datei-Uploads erreicht. Bitte laden Sie weniger als 500 Dateien gleichzeitig hoch.</string>
|
||||||
<string name="media_err_invalid_progressive_playback">Die Mediendatei kann nicht gestreamt werden</string>
|
<string name="media_err_invalid_progressive_playback">Die Mediendatei kann nicht gestreamt werden</string>
|
||||||
<string name="media_err_io">Konnte die Mediendatei nicht lesen</string>
|
<string name="media_err_io">Konnte die Mediendatei nicht lesen</string>
|
||||||
<string name="media_err_malformed">Mediendatei ist nicht korrekt encodiert</string>
|
<string name="media_err_malformed">Mediendatei ist nicht korrekt encodiert</string>
|
||||||
|
@ -666,8 +667,11 @@
|
||||||
<string name="prefs_value_theme_light">Hell</string>
|
<string name="prefs_value_theme_light">Hell</string>
|
||||||
<string name="prefs_value_theme_system">Systemvorgaben verwenden</string>
|
<string name="prefs_value_theme_system">Systemvorgaben verwenden</string>
|
||||||
<string name="preview_image_description">Bildvorschau</string>
|
<string name="preview_image_description">Bildvorschau</string>
|
||||||
|
<string name="preview_image_downloading_image_for_edit">Bild wird für das Bearbeiten heruntergeladen, bitte warten…</string>
|
||||||
<string name="preview_image_error_no_local_file">Keine lokale Datei für die Vorschau vorhanden</string>
|
<string name="preview_image_error_no_local_file">Keine lokale Datei für die Vorschau vorhanden</string>
|
||||||
<string name="preview_image_error_unknown_format">Bild kann nicht angezeigt werden</string>
|
<string name="preview_image_error_unknown_format">Bild kann nicht angezeigt werden</string>
|
||||||
|
<string name="preview_image_file_is_not_downloaded">Datei nicht heruntergeladen</string>
|
||||||
|
<string name="preview_image_file_is_not_exist">Datei existiert nicht</string>
|
||||||
<string name="preview_media_unhandled_http_code_message">Die Datei ist derzeit von einem anderen Benutzer oder Prozess gesperrt und kann daher nicht gelöscht werden. Bitte später noch einmal versuchen.</string>
|
<string name="preview_media_unhandled_http_code_message">Die Datei ist derzeit von einem anderen Benutzer oder Prozess gesperrt und kann daher nicht gelöscht werden. Bitte später noch einmal versuchen.</string>
|
||||||
<string name="preview_sorry">Entschuldigung</string>
|
<string name="preview_sorry">Entschuldigung</string>
|
||||||
<string name="privacy">Datenschutz</string>
|
<string name="privacy">Datenschutz</string>
|
||||||
|
@ -885,6 +889,9 @@
|
||||||
<string name="trashbin_file_remove">Endgültig löschen</string>
|
<string name="trashbin_file_remove">Endgültig löschen</string>
|
||||||
<string name="trashbin_loading_failed">Laden des Papierkorbs fehlgeschlagen!</string>
|
<string name="trashbin_loading_failed">Laden des Papierkorbs fehlgeschlagen!</string>
|
||||||
<string name="trashbin_not_emptied">Dateien konnten nicht endgültig gelöscht werden!</string>
|
<string name="trashbin_not_emptied">Dateien konnten nicht endgültig gelöscht werden!</string>
|
||||||
|
<string name="unified_search_fragment_calendar_event_not_found">Termin nicht gefunden, Sie können jederzeit die Synchronisierung wiederholen. Weiterleiten zum Web…</string>
|
||||||
|
<string name="unified_search_fragment_contact_not_found">Kontakt nicht gefunden, Sie können jederzeit synchronisieren für eine Aktualisierung. Weiterleiten zum Web…</string>
|
||||||
|
<string name="unified_search_fragment_permission_needed">Berechtigungen für das Öffnen der Suchergebnisse notwendig, ansonsten werden Sie zum Web weitergeleitet</string>
|
||||||
<string name="unlock_file">Datei entsperren</string>
|
<string name="unlock_file">Datei entsperren</string>
|
||||||
<string name="unread_comments">Es gibt ungelesene Kommentare</string>
|
<string name="unread_comments">Es gibt ungelesene Kommentare</string>
|
||||||
<string name="unset_encrypted">Verschlüsselung aufheben</string>
|
<string name="unset_encrypted">Verschlüsselung aufheben</string>
|
||||||
|
|
|
@ -512,6 +512,7 @@
|
||||||
<string name="manage_space_clear_data">Borrar datos</string>
|
<string name="manage_space_clear_data">Borrar datos</string>
|
||||||
<string name="manage_space_description">Las configuraciones, base de datos y certificados del servidor de los datos de %1$s serán eliminados permanentemente.\n\nLos archivos descargados se mantendrán sin cambios.\n\nEste proceso puede tomar algo de tiempo. </string>
|
<string name="manage_space_description">Las configuraciones, base de datos y certificados del servidor de los datos de %1$s serán eliminados permanentemente.\n\nLos archivos descargados se mantendrán sin cambios.\n\nEste proceso puede tomar algo de tiempo. </string>
|
||||||
<string name="manage_space_title">Administrar espacio</string>
|
<string name="manage_space_title">Administrar espacio</string>
|
||||||
|
<string name="max_file_count_warning_message">Ha alcanzado el límite de carga máxima de archivos. Por favor, cargue menos de 500 archivos a la vez.</string>
|
||||||
<string name="media_err_invalid_progressive_playback">No se puede transmitir el archivo multimedia</string>
|
<string name="media_err_invalid_progressive_playback">No se puede transmitir el archivo multimedia</string>
|
||||||
<string name="media_err_io">No fue posible leer el archivo de medios</string>
|
<string name="media_err_io">No fue posible leer el archivo de medios</string>
|
||||||
<string name="media_err_malformed">El archivo de medios tiene una codificación incorrecta</string>
|
<string name="media_err_malformed">El archivo de medios tiene una codificación incorrecta</string>
|
||||||
|
@ -666,8 +667,11 @@
|
||||||
<string name="prefs_value_theme_light">Claro</string>
|
<string name="prefs_value_theme_light">Claro</string>
|
||||||
<string name="prefs_value_theme_system">Seguir el del sistema</string>
|
<string name="prefs_value_theme_system">Seguir el del sistema</string>
|
||||||
<string name="preview_image_description">Vista previa de imagen</string>
|
<string name="preview_image_description">Vista previa de imagen</string>
|
||||||
|
<string name="preview_image_downloading_image_for_edit">Descargando la imagen para abrir la pantalla de edición, por favor espere...</string>
|
||||||
<string name="preview_image_error_no_local_file">No existe un archivo local a previsualizar</string>
|
<string name="preview_image_error_no_local_file">No existe un archivo local a previsualizar</string>
|
||||||
<string name="preview_image_error_unknown_format">No es posible mostrar la imagen</string>
|
<string name="preview_image_error_unknown_format">No es posible mostrar la imagen</string>
|
||||||
|
<string name="preview_image_file_is_not_downloaded">El archivo no está descargado</string>
|
||||||
|
<string name="preview_image_file_is_not_exist">El archivo no existe</string>
|
||||||
<string name="preview_media_unhandled_http_code_message">El archivo se encuentra bloqueado actualmente por otro usuario o proceso y, por lo tanto, no es posible eliminarlo. Por favor, intente de nuevo más tarde.</string>
|
<string name="preview_media_unhandled_http_code_message">El archivo se encuentra bloqueado actualmente por otro usuario o proceso y, por lo tanto, no es posible eliminarlo. Por favor, intente de nuevo más tarde.</string>
|
||||||
<string name="preview_sorry">Disculpa</string>
|
<string name="preview_sorry">Disculpa</string>
|
||||||
<string name="privacy">Privacidad</string>
|
<string name="privacy">Privacidad</string>
|
||||||
|
@ -677,6 +681,7 @@
|
||||||
<string name="push_notifications_temp_error">En este momento las notificaciones push no están disponibles.</string>
|
<string name="push_notifications_temp_error">En este momento las notificaciones push no están disponibles.</string>
|
||||||
<string name="qr_could_not_be_read">¡No se pudo leer el código QR!</string>
|
<string name="qr_could_not_be_read">¡No se pudo leer el código QR!</string>
|
||||||
<string name="receive_external_files_activity_start_sync_folder_is_not_exists_message">No se pudo encontrar la carpeta, la sincronización se ha cancelado</string>
|
<string name="receive_external_files_activity_start_sync_folder_is_not_exists_message">No se pudo encontrar la carpeta, la sincronización se ha cancelado</string>
|
||||||
|
<string name="receive_external_files_activity_unable_to_find_file_to_upload">No se pudo encontrar el archivo a cargar</string>
|
||||||
<string name="recommend_subject">¡Prueba %1$s en tu dispositivo!</string>
|
<string name="recommend_subject">¡Prueba %1$s en tu dispositivo!</string>
|
||||||
<string name="recommend_text">Quiero invitarte a usar %1$s en tu dispositivo\nDescárgalo aquí:%2$s </string>
|
<string name="recommend_text">Quiero invitarte a usar %1$s en tu dispositivo\nDescárgalo aquí:%2$s </string>
|
||||||
<string name="recommend_urls">%1$s ó %2$s</string>
|
<string name="recommend_urls">%1$s ó %2$s</string>
|
||||||
|
@ -884,6 +889,9 @@
|
||||||
<string name="trashbin_file_remove">Borrar permanentemente</string>
|
<string name="trashbin_file_remove">Borrar permanentemente</string>
|
||||||
<string name="trashbin_loading_failed">¡No se pudo cargar la papelera de reciclaje!</string>
|
<string name="trashbin_loading_failed">¡No se pudo cargar la papelera de reciclaje!</string>
|
||||||
<string name="trashbin_not_emptied">¡Los archivos no pudieron ser eliminados permanentemente!</string>
|
<string name="trashbin_not_emptied">¡Los archivos no pudieron ser eliminados permanentemente!</string>
|
||||||
|
<string name="unified_search_fragment_calendar_event_not_found">Evento no encontrado, siempre puede sincronizar para actualizar. Redirigiendo a la web...</string>
|
||||||
|
<string name="unified_search_fragment_contact_not_found">Contacto no encontrado, siempre puede sincronizar para actualizar. Redirigiendo a la web...</string>
|
||||||
|
<string name="unified_search_fragment_permission_needed">Permisos requeridos para abrir los resultados de búsqueda, de lo contrario se redirigirá a la web...</string>
|
||||||
<string name="unlock_file">Archivo desbloqueado</string>
|
<string name="unlock_file">Archivo desbloqueado</string>
|
||||||
<string name="unread_comments">Existen comentarios sin leer</string>
|
<string name="unread_comments">Existen comentarios sin leer</string>
|
||||||
<string name="unset_encrypted">Desestablecer encripción</string>
|
<string name="unset_encrypted">Desestablecer encripción</string>
|
||||||
|
|
|
@ -512,6 +512,7 @@
|
||||||
<string name="manage_space_clear_data">Limpar os datos</string>
|
<string name="manage_space_clear_data">Limpar os datos</string>
|
||||||
<string name="manage_space_description">Van ser eliminados definitivamente os axustes , base de datos e certificados do servidor de %1$s.\n\nOs ficheiros descargados conservaranse sen cambios.\n\nEste proceso pode levar bastante tempo.</string>
|
<string name="manage_space_description">Van ser eliminados definitivamente os axustes , base de datos e certificados do servidor de %1$s.\n\nOs ficheiros descargados conservaranse sen cambios.\n\nEste proceso pode levar bastante tempo.</string>
|
||||||
<string name="manage_space_title">Xestionar o espazo</string>
|
<string name="manage_space_title">Xestionar o espazo</string>
|
||||||
|
<string name="max_file_count_warning_message">Acadou o límite máximo de envío de ficheiros. Envíe menos de 500 ficheiros dunha sentada.</string>
|
||||||
<string name="media_err_invalid_progressive_playback">Non é posíbel transmitir o ficheiro multimedia</string>
|
<string name="media_err_invalid_progressive_playback">Non é posíbel transmitir o ficheiro multimedia</string>
|
||||||
<string name="media_err_io">Non foi posíbel ler o ficheiro multimedia</string>
|
<string name="media_err_io">Non foi posíbel ler o ficheiro multimedia</string>
|
||||||
<string name="media_err_malformed">O ficheiro multimedia ten unha codificación incorrecta</string>
|
<string name="media_err_malformed">O ficheiro multimedia ten unha codificación incorrecta</string>
|
||||||
|
@ -594,7 +595,7 @@
|
||||||
<string name="permission_storage_access">Precísanse permisos adicionais para enviar e descargar ficheiros.</string>
|
<string name="permission_storage_access">Precísanse permisos adicionais para enviar e descargar ficheiros.</string>
|
||||||
<string name="picture_set_as_no_app">Non se atopou unha aplicación coa que definir unha imaxe</string>
|
<string name="picture_set_as_no_app">Non se atopou unha aplicación coa que definir unha imaxe</string>
|
||||||
<string name="pin_home">Fixar na pantalla de Inicio</string>
|
<string name="pin_home">Fixar na pantalla de Inicio</string>
|
||||||
<string name="pin_shortcut_label">Aberto %1$s</string>
|
<string name="pin_shortcut_label">Abrir %1$s</string>
|
||||||
<string name="placeholder_fileSize">389 KB</string>
|
<string name="placeholder_fileSize">389 KB</string>
|
||||||
<string name="placeholder_filename">marcadordeposición.txt</string>
|
<string name="placeholder_filename">marcadordeposición.txt</string>
|
||||||
<string name="placeholder_media_time">12:23:45</string>
|
<string name="placeholder_media_time">12:23:45</string>
|
||||||
|
@ -667,8 +668,11 @@
|
||||||
<string name="prefs_value_theme_light">Claro</string>
|
<string name="prefs_value_theme_light">Claro</string>
|
||||||
<string name="prefs_value_theme_system">Seguir o sistema</string>
|
<string name="prefs_value_theme_system">Seguir o sistema</string>
|
||||||
<string name="preview_image_description">Vista previa da imaxe</string>
|
<string name="preview_image_description">Vista previa da imaxe</string>
|
||||||
|
<string name="preview_image_downloading_image_for_edit">Descargando a imaxe para iniciar a pantalla de edición, agarde…</string>
|
||||||
<string name="preview_image_error_no_local_file">Non hai ficheiro local que ver</string>
|
<string name="preview_image_error_no_local_file">Non hai ficheiro local que ver</string>
|
||||||
<string name="preview_image_error_unknown_format">Non é posíbel amosar a imaxe</string>
|
<string name="preview_image_error_unknown_format">Non é posíbel amosar a imaxe</string>
|
||||||
|
<string name="preview_image_file_is_not_downloaded">O ficheiro non está descargado</string>
|
||||||
|
<string name="preview_image_file_is_not_exist">O ficheiro non existe</string>
|
||||||
<string name="preview_media_unhandled_http_code_message">O ficheiro está bloqueado actualmente por outro usuario ou proceso e, polo tanto, non é posíbel eliminalo. Ténteo de novo máis tarde.</string>
|
<string name="preview_media_unhandled_http_code_message">O ficheiro está bloqueado actualmente por outro usuario ou proceso e, polo tanto, non é posíbel eliminalo. Ténteo de novo máis tarde.</string>
|
||||||
<string name="preview_sorry">Desculpe.</string>
|
<string name="preview_sorry">Desculpe.</string>
|
||||||
<string name="privacy">Privacidade</string>
|
<string name="privacy">Privacidade</string>
|
||||||
|
|
|
@ -512,6 +512,7 @@
|
||||||
<string name="manage_space_clear_data">清除資料</string>
|
<string name="manage_space_clear_data">清除資料</string>
|
||||||
<string name="manage_space_description">來自 %1$s 的設定,資料庫與伺服器憑證相關資料將被永久刪除,已下載的檔案將不會變動,此過程需要花費一些時間。</string>
|
<string name="manage_space_description">來自 %1$s 的設定,資料庫與伺服器憑證相關資料將被永久刪除,已下載的檔案將不會變動,此過程需要花費一些時間。</string>
|
||||||
<string name="manage_space_title">管理空間</string>
|
<string name="manage_space_title">管理空間</string>
|
||||||
|
<string name="max_file_count_warning_message">您已達最大檔案上傳限制。一次上傳僅能上傳少於 500 個檔案。</string>
|
||||||
<string name="media_err_invalid_progressive_playback">此媒體檔案無法被串流播放</string>
|
<string name="media_err_invalid_progressive_playback">此媒體檔案無法被串流播放</string>
|
||||||
<string name="media_err_io">無法讀取媒體檔案</string>
|
<string name="media_err_io">無法讀取媒體檔案</string>
|
||||||
<string name="media_err_malformed">媒體檔案編碼不正確</string>
|
<string name="media_err_malformed">媒體檔案編碼不正確</string>
|
||||||
|
@ -666,8 +667,11 @@
|
||||||
<string name="prefs_value_theme_light">淺色</string>
|
<string name="prefs_value_theme_light">淺色</string>
|
||||||
<string name="prefs_value_theme_system">跟隨系統</string>
|
<string name="prefs_value_theme_system">跟隨系統</string>
|
||||||
<string name="preview_image_description">圖片預覽</string>
|
<string name="preview_image_description">圖片預覽</string>
|
||||||
|
<string name="preview_image_downloading_image_for_edit">正在下載影像以啟動編輯畫面,請稍候……</string>
|
||||||
<string name="preview_image_error_no_local_file">沒有可供預覽的本機檔案</string>
|
<string name="preview_image_error_no_local_file">沒有可供預覽的本機檔案</string>
|
||||||
<string name="preview_image_error_unknown_format">無法顯示圖片</string>
|
<string name="preview_image_error_unknown_format">無法顯示圖片</string>
|
||||||
|
<string name="preview_image_file_is_not_downloaded">檔案未下載</string>
|
||||||
|
<string name="preview_image_file_is_not_exist">檔案不存在</string>
|
||||||
<string name="preview_media_unhandled_http_code_message">檔案目前已被其他使用者或處理程序鎖定,因此無法刪除。請稍後再試。</string>
|
<string name="preview_media_unhandled_http_code_message">檔案目前已被其他使用者或處理程序鎖定,因此無法刪除。請稍後再試。</string>
|
||||||
<string name="preview_sorry">很抱歉</string>
|
<string name="preview_sorry">很抱歉</string>
|
||||||
<string name="privacy">隱私權</string>
|
<string name="privacy">隱私權</string>
|
||||||
|
@ -885,6 +889,9 @@
|
||||||
<string name="trashbin_file_remove">永久刪除</string>
|
<string name="trashbin_file_remove">永久刪除</string>
|
||||||
<string name="trashbin_loading_failed">載入回收桶失敗!</string>
|
<string name="trashbin_loading_failed">載入回收桶失敗!</string>
|
||||||
<string name="trashbin_not_emptied">無法永久刪除檔案!</string>
|
<string name="trashbin_not_emptied">無法永久刪除檔案!</string>
|
||||||
|
<string name="unified_search_fragment_calendar_event_not_found">找不到活動,您隨時可以同步更新。正在重新導向至網路……</string>
|
||||||
|
<string name="unified_search_fragment_contact_not_found">找不到聯絡人,您隨時可以同步更新。正在重新導向至網路……</string>
|
||||||
|
<string name="unified_search_fragment_permission_needed">開啟搜尋結果需要權限,否則其將會重新導向至網路……</string>
|
||||||
<string name="unlock_file">解鎖檔案</string>
|
<string name="unlock_file">解鎖檔案</string>
|
||||||
<string name="unread_comments">有未讀留言</string>
|
<string name="unread_comments">有未讀留言</string>
|
||||||
<string name="unset_encrypted">取消加密</string>
|
<string name="unset_encrypted">取消加密</string>
|
||||||
|
|
|
@ -3,7 +3,7 @@
|
||||||
*
|
*
|
||||||
* SPDX-FileCopyrightText: 2022 Álvaro Brey <alvaro@alvarobrey.com>
|
* SPDX-FileCopyrightText: 2022 Álvaro Brey <alvaro@alvarobrey.com>
|
||||||
* SPDX-FileCopyrightText: 2022 Nextcloud GmbH
|
* SPDX-FileCopyrightText: 2022 Nextcloud GmbH
|
||||||
* SPDX-License-Identifier: GPL-3.0-or-later
|
* SPDX-License-Identifier: AGPL-3.0-or-later
|
||||||
*/
|
*/
|
||||||
package com.owncloud.android.ui.adapter
|
package com.owncloud.android.ui.adapter
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue