diff --git a/app/src/androidTest/java/com/nextcloud/test/GrantStoragePermissionRule.kt b/app/src/androidTest/java/com/nextcloud/test/GrantStoragePermissionRule.kt index 3bade62247c4..6bc4cd750e18 100644 --- a/app/src/androidTest/java/com/nextcloud/test/GrantStoragePermissionRule.kt +++ b/app/src/androidTest/java/com/nextcloud/test/GrantStoragePermissionRule.kt @@ -27,6 +27,7 @@ class GrantStoragePermissionRule private constructor() { Build.VERSION.SDK_INT < Build.VERSION_CODES.R -> GrantPermissionRule.grant( Manifest.permission.WRITE_EXTERNAL_STORAGE ) + else -> GrantManageExternalStoragePermissionRule() } } diff --git a/app/src/androidTest/java/com/owncloud/android/files/services/FileUploaderIT.kt b/app/src/androidTest/java/com/owncloud/android/files/services/FileUploaderIT.kt index e9f844454e3a..00c568d506ad 100644 --- a/app/src/androidTest/java/com/owncloud/android/files/services/FileUploaderIT.kt +++ b/app/src/androidTest/java/com/owncloud/android/files/services/FileUploaderIT.kt @@ -57,9 +57,9 @@ abstract class FileUploaderIT : AbstractOnServerIT() { uploadsStorageManager = UploadsStorageManager(accountManager, contentResolver) } - /** - * uploads a file, overwrites it with an empty one, check if overwritten - */ + // /** + // * uploads a file, overwrites it with an empty one, check if overwritten + // */ // disabled, flaky test // @Test // fun testKeepLocalAndOverwriteRemote() { diff --git a/app/src/androidTest/java/com/owncloud/android/ui/trashbin/TrashbinLocalRepository.kt b/app/src/androidTest/java/com/owncloud/android/ui/trashbin/TrashbinLocalRepository.kt index ebf52449514c..ae90c9569748 100644 --- a/app/src/androidTest/java/com/owncloud/android/ui/trashbin/TrashbinLocalRepository.kt +++ b/app/src/androidTest/java/com/owncloud/android/ui/trashbin/TrashbinLocalRepository.kt @@ -28,6 +28,7 @@ class TrashbinLocalRepository(private val testCase: TrashbinActivityIT.TestCase) override fun getFolder(remotePath: String?, callback: LoadFolderCallback?) { when (testCase) { TrashbinActivityIT.TestCase.ERROR -> callback?.onError(R.string.trashbin_loading_failed) + TrashbinActivityIT.TestCase.FILES -> { val files = ArrayList() files.add( @@ -69,6 +70,7 @@ class TrashbinLocalRepository(private val testCase: TrashbinActivityIT.TestCase) callback?.onSuccess(files) } + TrashbinActivityIT.TestCase.EMPTY -> callback?.onSuccess(ArrayList()) } } diff --git a/app/src/main/java/com/nextcloud/client/assistant/AssistantViewModel.kt b/app/src/main/java/com/nextcloud/client/assistant/AssistantViewModel.kt index def6bf60882b..7bc212667745 100644 --- a/app/src/main/java/com/nextcloud/client/assistant/AssistantViewModel.kt +++ b/app/src/main/java/com/nextcloud/client/assistant/AssistantViewModel.kt @@ -180,10 +180,15 @@ class AssistantViewModel( when { selectedTaskType == null -> AssistantScreenState.Loading + isTranslation -> AssistantScreenState.Translation(selectedTask) + isChat && chats.isEmpty() -> AssistantScreenState.emptyChatList() + isChat -> AssistantScreenState.ChatContent + !isChat && (tasks == null || tasks.isEmpty()) -> AssistantScreenState.emptyTaskList() + else -> { if (!_isTranslationTask.value) { AssistantScreenState.TaskContent diff --git a/app/src/main/java/com/nextcloud/client/assistant/extensions/TaskExtensions.kt b/app/src/main/java/com/nextcloud/client/assistant/extensions/TaskExtensions.kt index ef884a9642c3..5bc6dacf6a0d 100644 --- a/app/src/main/java/com/nextcloud/client/assistant/extensions/TaskExtensions.kt +++ b/app/src/main/java/com/nextcloud/client/assistant/extensions/TaskExtensions.kt @@ -10,7 +10,6 @@ package com.nextcloud.client.assistant.extensions import android.content.Context -import androidx.compose.ui.res.stringResource import com.nextcloud.utils.date.DateFormatPattern import com.nextcloud.utils.date.DateFormatter import com.owncloud.android.R @@ -58,18 +57,23 @@ private fun Task.getStatusIconV1(): Int = when (status) { "0" -> { R.drawable.ic_unknown } + "1" -> { R.drawable.ic_clock } + "2" -> { R.drawable.ic_modification_desc } + "3" -> { R.drawable.ic_check_circle_outline } + "4" -> { R.drawable.image_fail } + else -> { R.drawable.ic_unknown } @@ -79,18 +83,23 @@ private fun Task.getStatusIconDescriptionV1(): Int = when (status) { "0" -> { R.string.assistant_task_status_unknown } + "1" -> { R.string.assistant_task_status_scheduled } + "2" -> { R.string.assistant_task_status_running } + "3" -> { R.string.assistant_task_status_successful } + "4" -> { R.string.assistant_task_status_failed } + else -> { R.string.assistant_task_status_unknown } @@ -100,18 +109,23 @@ private fun Task.getStatusIconV2(): Int = when (status) { "STATUS_UNKNOWN" -> { R.drawable.ic_unknown } + "STATUS_SCHEDULED" -> { R.drawable.ic_clock } + "STATUS_RUNNING" -> { R.drawable.ic_modification_desc } + "STATUS_SUCCESSFUL" -> { R.drawable.ic_check_circle_outline } + "STATUS_FAILED" -> { R.drawable.image_fail } + else -> { R.drawable.ic_unknown } @@ -121,18 +135,23 @@ private fun Task.getStatusIconDescriptionV2(): Int = when (status) { "STATUS_UNKNOWN" -> { R.string.assistant_task_status_unknown } + "STATUS_SCHEDULED" -> { R.string.assistant_task_status_scheduled } + "STATUS_RUNNING" -> { R.string.assistant_task_status_running } + "STATUS_SUCCESSFUL" -> { R.string.assistant_task_status_successful } + "STATUS_FAILED" -> { R.string.assistant_task_status_failed } + else -> { R.string.assistant_task_status_unknown } diff --git a/app/src/main/java/com/nextcloud/client/assistant/translate/TranslationScreenState.kt b/app/src/main/java/com/nextcloud/client/assistant/translate/TranslationScreenState.kt index fe4e8976610a..ae69aebd3f7f 100644 --- a/app/src/main/java/com/nextcloud/client/assistant/translate/TranslationScreenState.kt +++ b/app/src/main/java/com/nextcloud/client/assistant/translate/TranslationScreenState.kt @@ -132,8 +132,11 @@ data class EditedTranslation( fun TranslationScreenState.withShimmer(shimmer: Boolean): TranslationScreenState = when (this) { is NewTranslation -> copy(shimmer = shimmer) + is ExistingTranslation -> copy(shimmer = shimmer) + is EditedTranslation -> copy(shimmer = shimmer) + Uninitialized -> { Uninitialized } @@ -162,6 +165,7 @@ fun TranslationScreenState.withTargetText(text: String): TranslationScreenState fun TranslationScreenState.withSource(newSource: TranslationSideState): TranslationScreenState = when (this) { is NewTranslation -> copy(source = newSource) + is ExistingTranslation -> EditedTranslation( taskTypeData = taskTypeData, source = newSource, @@ -170,6 +174,7 @@ fun TranslationScreenState.withSource(newSource: TranslationSideState): Translat ) is EditedTranslation -> copy(source = newSource) + Uninitialized -> { Uninitialized } @@ -188,6 +193,7 @@ fun TranslationScreenState.withTarget(newTarget: TranslationSideState): Translat ) is EditedTranslation -> copy(target = newTarget) + Uninitialized -> { Uninitialized } diff --git a/app/src/main/java/com/nextcloud/client/documentscan/DocumentScanActivity.kt b/app/src/main/java/com/nextcloud/client/documentscan/DocumentScanActivity.kt index daf9487bd8a0..7424948cae90 100644 --- a/app/src/main/java/com/nextcloud/client/documentscan/DocumentScanActivity.kt +++ b/app/src/main/java/com/nextcloud/client/documentscan/DocumentScanActivity.kt @@ -103,10 +103,12 @@ class DocumentScanActivity : viewModel.onClickDone() true } + android.R.id.home -> { onBackPressedDispatcher.onBackPressed() true } + else -> false } } @@ -129,6 +131,7 @@ class DocumentScanActivity : startPageScan() } } + is DocumentScanViewModel.UIState.RequestExportState -> { updateButtonsEnabled(false) if (state.shouldRequestExportType) { @@ -137,6 +140,7 @@ class DocumentScanActivity : } } } + DocumentScanViewModel.UIState.DoneState, DocumentScanViewModel.UIState.CanceledState -> { finish() } diff --git a/app/src/main/java/com/nextcloud/client/documentscan/DocumentScanViewModel.kt b/app/src/main/java/com/nextcloud/client/documentscan/DocumentScanViewModel.kt index e7cc433c2b89..0210ff07e135 100644 --- a/app/src/main/java/com/nextcloud/client/documentscan/DocumentScanViewModel.kt +++ b/app/src/main/java/com/nextcloud/client/documentscan/DocumentScanViewModel.kt @@ -138,6 +138,7 @@ class DocumentScanViewModel @Inject constructor( ExportType.PDF -> { exportToPdf(state.pageList) } + ExportType.IMAGES -> { exportToImages(state.pageList) } diff --git a/app/src/main/java/com/nextcloud/client/editimage/EditImageActivity.kt b/app/src/main/java/com/nextcloud/client/editimage/EditImageActivity.kt index 795f974d1eb3..48920e1ab858 100644 --- a/app/src/main/java/com/nextcloud/client/editimage/EditImageActivity.kt +++ b/app/src/main/java/com/nextcloud/client/editimage/EditImageActivity.kt @@ -174,6 +174,7 @@ class EditImageActivity : // determine output file format format = when (file.mimeType) { MimeType.PNG -> Bitmap.CompressFormat.PNG + MimeType.WEBP -> { if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) { Bitmap.CompressFormat.WEBP_LOSSY diff --git a/app/src/main/java/com/nextcloud/client/errorhandling/ShowErrorActivity.kt b/app/src/main/java/com/nextcloud/client/errorhandling/ShowErrorActivity.kt index 1a7e60379c63..87c138f9b1b6 100644 --- a/app/src/main/java/com/nextcloud/client/errorhandling/ShowErrorActivity.kt +++ b/app/src/main/java/com/nextcloud/client/errorhandling/ShowErrorActivity.kt @@ -63,6 +63,7 @@ class ShowErrorActivity : AppCompatActivity() { onClickedShare() true } + else -> super.onOptionsItemSelected(item) } diff --git a/app/src/main/java/com/nextcloud/client/etm/EtmActivity.kt b/app/src/main/java/com/nextcloud/client/etm/EtmActivity.kt index 61fbe2736e2a..9e3f41039989 100644 --- a/app/src/main/java/com/nextcloud/client/etm/EtmActivity.kt +++ b/app/src/main/java/com/nextcloud/client/etm/EtmActivity.kt @@ -57,6 +57,7 @@ class EtmActivity : } true } + else -> super.onOptionsItemSelected(item) } diff --git a/app/src/main/java/com/nextcloud/client/etm/pages/EtmAccountsFragment.kt b/app/src/main/java/com/nextcloud/client/etm/pages/EtmAccountsFragment.kt index b05e7c499ed9..3d788f89ad0d 100644 --- a/app/src/main/java/com/nextcloud/client/etm/pages/EtmAccountsFragment.kt +++ b/app/src/main/java/com/nextcloud/client/etm/pages/EtmAccountsFragment.kt @@ -55,6 +55,7 @@ class EtmAccountsFragment : EtmBaseFragment() { onClickedShare() true } + else -> super.onOptionsItemSelected(item) } diff --git a/app/src/main/java/com/nextcloud/client/etm/pages/EtmFileTransferFragment.kt b/app/src/main/java/com/nextcloud/client/etm/pages/EtmFileTransferFragment.kt index 7af132bc7b0c..5c45a6bdb2eb 100644 --- a/app/src/main/java/com/nextcloud/client/etm/pages/EtmFileTransferFragment.kt +++ b/app/src/main/java/com/nextcloud/client/etm/pages/EtmFileTransferFragment.kt @@ -144,10 +144,12 @@ class EtmFileTransferFragment : EtmBaseFragment() { scheduleTestDownload() true } + R.id.etm_test_upload -> { scheduleTestUpload() true } + else -> super.onOptionsItemSelected(item) } diff --git a/app/src/main/java/com/nextcloud/client/etm/pages/EtmMigrations.kt b/app/src/main/java/com/nextcloud/client/etm/pages/EtmMigrations.kt index 3fd58f5d347f..926f949273fa 100644 --- a/app/src/main/java/com/nextcloud/client/etm/pages/EtmMigrations.kt +++ b/app/src/main/java/com/nextcloud/client/etm/pages/EtmMigrations.kt @@ -70,6 +70,7 @@ class EtmMigrations : EtmBaseFragment() { onDeleteMigrationsClicked() true } + else -> super.onOptionsItemSelected(item) } diff --git a/app/src/main/java/com/nextcloud/client/etm/pages/EtmPreferencesFragment.kt b/app/src/main/java/com/nextcloud/client/etm/pages/EtmPreferencesFragment.kt index e10b29f333e5..3061c8df997b 100644 --- a/app/src/main/java/com/nextcloud/client/etm/pages/EtmPreferencesFragment.kt +++ b/app/src/main/java/com/nextcloud/client/etm/pages/EtmPreferencesFragment.kt @@ -50,6 +50,7 @@ class EtmPreferencesFragment : EtmBaseFragment() { onClickedShare() true } + else -> super.onOptionsItemSelected(item) } diff --git a/app/src/main/java/com/nextcloud/client/jobs/OfflineSyncWork.kt b/app/src/main/java/com/nextcloud/client/jobs/OfflineSyncWork.kt index 26cddf08e5c4..2c0e0ebf91a1 100644 --- a/app/src/main/java/com/nextcloud/client/jobs/OfflineSyncWork.kt +++ b/app/src/main/java/com/nextcloud/client/jobs/OfflineSyncWork.kt @@ -119,6 +119,7 @@ class OfflineSyncWork( Log_OC.d(TAG, "$folderName: eTag unchanged") null } + ResultCode.FILE_NOT_FOUND -> { val removalResult = storageManager.removeFolder(folder, true, true) if (!removalResult) { @@ -126,10 +127,12 @@ class OfflineSyncWork( } null } + ResultCode.ETAG_CHANGED -> { Log_OC.d(TAG, "$folderName: eTag changed") result?.data?.get(0) as? String } + else -> if (connectivityService.isInternetWalled) { Log_OC.d(TAG, "No connectivity, skipping sync") null 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 fc1b9d7be6e9..8785981b90af 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 @@ -142,6 +142,7 @@ class AutoUploadHelper { is AccessDeniedException -> { Log_OC.w(TAG, "Access denied: $file") } + else -> { Log_OC.e(TAG, "Failed to visit file: $file", exc) } diff --git a/app/src/main/java/com/nextcloud/client/jobs/offlineOperations/OfflineOperationsWorker.kt b/app/src/main/java/com/nextcloud/client/jobs/offlineOperations/OfflineOperationsWorker.kt index 64b83867e827..b53a4cc5dc04 100644 --- a/app/src/main/java/com/nextcloud/client/jobs/offlineOperations/OfflineOperationsWorker.kt +++ b/app/src/main/java/com/nextcloud/client/jobs/offlineOperations/OfflineOperationsWorker.kt @@ -223,18 +223,22 @@ class OfflineOperationsWorker( Log_OC.d(TAG, "πŸ“‚ Creating folder at ${type.path}") createFolder(operation, client) } + is OfflineOperationType.CreateFile -> { Log_OC.d(TAG, "πŸ“€ Uploading file: local=${type.localPath} β†’ remote=${type.remotePath}") createFile(operation, client) } + is OfflineOperationType.RenameFile -> { Log_OC.d(TAG, "✏️ Renaming ${operation.path} β†’ ${type.newName}") renameFile(operation, client) } + is OfflineOperationType.RemoveFile -> { Log_OC.d(TAG, "πŸ—‘ Removing file: ${operation.path}") ocFile?.let { removeFile(it, client) } } + else -> { Log_OC.d(TAG, "⚠️ Unsupported operation type: $type") null diff --git a/app/src/main/java/com/nextcloud/client/logger/LogEntry.kt b/app/src/main/java/com/nextcloud/client/logger/LogEntry.kt index 6e47993fe704..f105a5550070 100644 --- a/app/src/main/java/com/nextcloud/client/logger/LogEntry.kt +++ b/app/src/main/java/com/nextcloud/client/logger/LogEntry.kt @@ -29,7 +29,7 @@ data class LogEntry(val timestamp: Date, val level: Level, val tag: String, val */ private val ENTRY_PARSE_REGEXP = Regex( pattern = - """(\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}\.\d{3}Z);([ADEIVW]);([^;]+);(.*)""" + """(\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}\.\d{3}Z);([ADEIVW]);([^;]+);(.*)""" ) @JvmStatic diff --git a/app/src/main/java/com/nextcloud/client/logger/LoggerImpl.kt b/app/src/main/java/com/nextcloud/client/logger/LoggerImpl.kt index 148000c88921..fad910d4576d 100644 --- a/app/src/main/java/com/nextcloud/client/logger/LoggerImpl.kt +++ b/app/src/main/java/com/nextcloud/client/logger/LoggerImpl.kt @@ -134,6 +134,7 @@ internal class LoggerImpl( event.onResult(entries, loaded.logSize) } } + is Delete -> handler.deleteAll() } } diff --git a/app/src/main/java/com/nextcloud/client/logger/ui/LogsViewModel.kt b/app/src/main/java/com/nextcloud/client/logger/ui/LogsViewModel.kt index 46e4a8cbd566..5349713ff4e2 100644 --- a/app/src/main/java/com/nextcloud/client/logger/ui/LogsViewModel.kt +++ b/app/src/main/java/com/nextcloud/client/logger/ui/LogsViewModel.kt @@ -103,6 +103,7 @@ class LogsViewModel @Inject constructor( val sizeKb = logsSize / KILOBYTE return when { isLoading.value == true -> context.getString(R.string.logs_status_loading) + isFiltered -> context.getString( R.string.logs_status_filtered, sizeKb, @@ -110,7 +111,9 @@ class LogsViewModel @Inject constructor( allEntries.size, filterDurationMs ) + !isFiltered -> context.getString(R.string.logs_status_not_filtered, sizeKb) + else -> "" } } diff --git a/app/src/main/java/com/nextcloud/client/media/AudioFocusManager.kt b/app/src/main/java/com/nextcloud/client/media/AudioFocusManager.kt index 358b39344b58..3cd1e1da7166 100644 --- a/app/src/main/java/com/nextcloud/client/media/AudioFocusManager.kt +++ b/app/src/main/java/com/nextcloud/client/media/AudioFocusManager.kt @@ -26,9 +26,12 @@ internal class AudioFocusManager( AudioManager.AUDIOFOCUS_GAIN, AudioManager.AUDIOFOCUS_GAIN_TRANSIENT, AudioManager.AUDIOFOCUS_GAIN_TRANSIENT_MAY_DUCK -> AudioFocus.FOCUS + AudioManager.AUDIOFOCUS_LOSS, AudioManager.AUDIOFOCUS_LOSS_TRANSIENT -> AudioFocus.LOST + AudioManager.AUDIOFOCUS_LOSS_TRANSIENT_CAN_DUCK -> AudioFocus.DUCK + else -> null } focus?.let { onFocusChange(it) } diff --git a/app/src/main/java/com/nextcloud/client/media/ErrorFormat.kt b/app/src/main/java/com/nextcloud/client/media/ErrorFormat.kt index cb3cfec1b707..8b34266453a7 100644 --- a/app/src/main/java/com/nextcloud/client/media/ErrorFormat.kt +++ b/app/src/main/java/com/nextcloud/client/media/ErrorFormat.kt @@ -83,6 +83,7 @@ object ErrorFormat { PlaybackException.ERROR_CODE_DECODING_FORMAT_EXCEEDS_CAPABILITIES -> { R.string.media_err_unsupported } + PlaybackException.ERROR_CODE_IO_UNSPECIFIED, PlaybackException.ERROR_CODE_IO_NETWORK_CONNECTION_FAILED, PlaybackException.ERROR_CODE_IO_INVALID_HTTP_CONTENT_TYPE, @@ -93,13 +94,16 @@ object ErrorFormat { PlaybackException.ERROR_CODE_IO_READ_POSITION_OUT_OF_RANGE -> { R.string.media_err_io } + PlaybackException.ERROR_CODE_TIMEOUT -> { R.string.media_err_timeout } + PlaybackException.ERROR_CODE_PARSING_CONTAINER_MALFORMED, PlaybackException.ERROR_CODE_PARSING_MANIFEST_MALFORMED -> { R.string.media_err_malformed } + else -> { R.string.media_err_invalid_progressive_playback } diff --git a/app/src/main/java/com/nextcloud/client/network/WalledCheckCache.kt b/app/src/main/java/com/nextcloud/client/network/WalledCheckCache.kt index 7246732dea75..39599ab9f65b 100644 --- a/app/src/main/java/com/nextcloud/client/network/WalledCheckCache.kt +++ b/app/src/main/java/com/nextcloud/client/network/WalledCheckCache.kt @@ -19,6 +19,7 @@ class WalledCheckCache @Inject constructor(private val clock: Clock) { @Synchronized fun isExpired(): Boolean = when (val timestamp = cachedEntry?.first) { null -> true + else -> { val diff = clock.currentTime - timestamp diff >= CACHE_TIME_MS diff --git a/app/src/main/java/com/nextcloud/ui/ClientIntegrationScreen.kt b/app/src/main/java/com/nextcloud/ui/ClientIntegrationScreen.kt index ddc24cfbbf81..4f94026af605 100644 --- a/app/src/main/java/com/nextcloud/ui/ClientIntegrationScreen.kt +++ b/app/src/main/java/com/nextcloud/ui/ClientIntegrationScreen.kt @@ -70,6 +70,7 @@ fun ClientIntegrationScreen(clientIntegrationUI: ClientIntegrationUI, baseUrl: S } } } + else -> { LazyRow(modifier = Modifier.padding(it)) { items(layoutRows) { row -> diff --git a/app/src/main/java/com/nextcloud/ui/SetOnlineStatusBottomSheet.kt b/app/src/main/java/com/nextcloud/ui/SetOnlineStatusBottomSheet.kt index 4825aa7bf58f..b917d5706fe6 100644 --- a/app/src/main/java/com/nextcloud/ui/SetOnlineStatusBottomSheet.kt +++ b/app/src/main/java/com/nextcloud/ui/SetOnlineStatusBottomSheet.kt @@ -124,10 +124,15 @@ class SetOnlineStatusBottomSheet(val currentStatus: Status?) : clearTopStatus() val views: Triple = when (statusType) { StatusType.ONLINE -> Triple(binding.onlineStatus, binding.onlineHeadline, binding.onlineIcon) + StatusType.AWAY -> Triple(binding.awayStatus, binding.awayHeadline, binding.awayIcon) + StatusType.BUSY -> Triple(binding.busyStatus, binding.busyHeadline, binding.busyIcon) + StatusType.DND -> Triple(binding.dndStatus, binding.dndHeadline, binding.dndIcon) + StatusType.INVISIBLE -> Triple(binding.invisibleStatus, binding.invisibleHeadline, binding.invisibleIcon) + else -> { Log.d(TAG, "unknown status") return diff --git a/app/src/main/java/com/nextcloud/ui/SetStatusMessageBottomSheet.kt b/app/src/main/java/com/nextcloud/ui/SetStatusMessageBottomSheet.kt index 7a909e761f6a..8712727746c4 100644 --- a/app/src/main/java/com/nextcloud/ui/SetStatusMessageBottomSheet.kt +++ b/app/src/main/java/com/nextcloud/ui/SetStatusMessageBottomSheet.kt @@ -193,11 +193,14 @@ class SetStatusMessageBottomSheet(val user: User, val currentStatus: Status?) : private fun setClearStatusAfterValue(item: Int) { clearAt = when (item) { - POS_DONT_CLEAR -> null // don't clear + POS_DONT_CLEAR -> null + + // don't clear POS_FIFTEEN_MINUTES -> { // 15 minutes System.currentTimeMillis() / ONE_SECOND_IN_MILLIS + FIFTEEN_MINUTES * ONE_MINUTE_IN_SECONDS } + POS_HALF_AN_HOUR -> { // 30 minutes System.currentTimeMillis() / ONE_SECOND_IN_MILLIS + THIRTY_MINUTES * ONE_MINUTE_IN_SECONDS diff --git a/app/src/main/java/com/nextcloud/ui/composeActivity/ComposeActivity.kt b/app/src/main/java/com/nextcloud/ui/composeActivity/ComposeActivity.kt index c35f8fa6a506..dfa429d2f15a 100644 --- a/app/src/main/java/com/nextcloud/ui/composeActivity/ComposeActivity.kt +++ b/app/src/main/java/com/nextcloud/ui/composeActivity/ComposeActivity.kt @@ -106,6 +106,7 @@ class ComposeActivity : DrawerActivity() { toggleDrawer() true } + else -> super.onOptionsItemSelected(item) } diff --git a/app/src/main/java/com/nextcloud/ui/fileactions/FileActionsBottomSheet.kt b/app/src/main/java/com/nextcloud/ui/fileactions/FileActionsBottomSheet.kt index 62467f7d9b0f..28619ed1741f 100644 --- a/app/src/main/java/com/nextcloud/ui/fileactions/FileActionsBottomSheet.kt +++ b/app/src/main/java/com/nextcloud/ui/fileactions/FileActionsBottomSheet.kt @@ -130,6 +130,7 @@ class FileActionsBottomSheet : } FileActionsViewModel.UiState.Loading -> {} + FileActionsViewModel.UiState.Error -> { activity?.let { DisplayUtils.showSnackMessage(it, R.string.error_file_actions) diff --git a/app/src/main/java/com/nextcloud/ui/fileactions/FileActionsViewModel.kt b/app/src/main/java/com/nextcloud/ui/fileactions/FileActionsViewModel.kt index 62b310b010c2..ec4b48cd5a28 100644 --- a/app/src/main/java/com/nextcloud/ui/fileactions/FileActionsViewModel.kt +++ b/app/src/main/java/com/nextcloud/ui/fileactions/FileActionsViewModel.kt @@ -109,6 +109,7 @@ class FileActionsViewModel @Inject constructor( val file = files.first() UiState.LoadedForSingleFile(availableActions, file, getLockInfo(file)) } + else -> UiState.LoadedForMultipleFiles(availableActions, files.size) } _uiState.postValue(state) diff --git a/app/src/main/java/com/nextcloud/ui/trashbinFileActions/TrashbinFileActionsBottomSheet.kt b/app/src/main/java/com/nextcloud/ui/trashbinFileActions/TrashbinFileActionsBottomSheet.kt index 3ba288a2970d..82422d9e64ee 100644 --- a/app/src/main/java/com/nextcloud/ui/trashbinFileActions/TrashbinFileActionsBottomSheet.kt +++ b/app/src/main/java/com/nextcloud/ui/trashbinFileActions/TrashbinFileActionsBottomSheet.kt @@ -106,6 +106,7 @@ class TrashbinFileActionsBottomSheet : } TrashbinFileActionsViewModel.UiState.Loading -> {} + TrashbinFileActionsViewModel.UiState.Error -> { activity?.let { DisplayUtils.showSnackMessage(it, R.string.error_file_actions) diff --git a/app/src/main/java/com/nextcloud/utils/BitmapExtensions.kt b/app/src/main/java/com/nextcloud/utils/BitmapExtensions.kt index 545354c60bc8..104efca9972f 100644 --- a/app/src/main/java/com/nextcloud/utils/BitmapExtensions.kt +++ b/app/src/main/java/com/nextcloud/utils/BitmapExtensions.kt @@ -78,8 +78,11 @@ fun Bitmap?.rotateBitmapViaExif(orientation: Int): Bitmap? { val matrix = Matrix() when (orientation) { ExifInterface.ORIENTATION_NORMAL -> return this + ExifInterface.ORIENTATION_FLIP_HORIZONTAL -> matrix.setScale(-1f, 1f) + ExifInterface.ORIENTATION_ROTATE_180 -> matrix.setRotate(180f) + ExifInterface.ORIENTATION_FLIP_VERTICAL -> { matrix.setRotate(180f) matrix.postScale(-1f, 1f) @@ -91,12 +94,14 @@ fun Bitmap?.rotateBitmapViaExif(orientation: Int): Bitmap? { } ExifInterface.ORIENTATION_ROTATE_90 -> matrix.setRotate(90f) + ExifInterface.ORIENTATION_TRANSVERSE -> { matrix.setRotate(-90f) matrix.postScale(-1f, 1f) } ExifInterface.ORIENTATION_ROTATE_270 -> matrix.setRotate(-90f) + else -> return this } diff --git a/app/src/main/java/com/owncloud/android/authentication/PassCodeManager.kt b/app/src/main/java/com/owncloud/android/authentication/PassCodeManager.kt index 4694629d51c7..c5b2dbc3446a 100644 --- a/app/src/main/java/com/owncloud/android/authentication/PassCodeManager.kt +++ b/app/src/main/java/com/owncloud/android/authentication/PassCodeManager.kt @@ -77,7 +77,7 @@ class PassCodeManager(private val preferences: AppPreferences, private val clock } } - if (!askedForPin && preferences.lockTimestamp != 0L || askPinWhenDeviceLocked) { + if ((!askedForPin && preferences.lockTimestamp != 0L) || askPinWhenDeviceLocked) { updateLockTimestamp() askPinWhenDeviceLocked = false } diff --git a/app/src/main/java/com/owncloud/android/datamodel/ContentResolverHelper.kt b/app/src/main/java/com/owncloud/android/datamodel/ContentResolverHelper.kt index 4f2f6042fcd9..3a8866733c48 100644 --- a/app/src/main/java/com/owncloud/android/datamodel/ContentResolverHelper.kt +++ b/app/src/main/java/com/owncloud/android/datamodel/ContentResolverHelper.kt @@ -49,6 +49,7 @@ object ContentResolverHelper { val queryArgs = getQueryArgsBundle(selection, sortColumn, sortDirection, limit) contentResolver.query(uri, projection, queryArgs, cancellationSignal) } + else -> { val sortOrder = getSortOrderString(sortColumn, sortDirection, limit) contentResolver.query( diff --git a/app/src/main/java/com/owncloud/android/datamodel/quickPermission/QuickPermissionType.kt b/app/src/main/java/com/owncloud/android/datamodel/quickPermission/QuickPermissionType.kt index a09aa0673e0a..d867fb69e0c5 100644 --- a/app/src/main/java/com/owncloud/android/datamodel/quickPermission/QuickPermissionType.kt +++ b/app/src/main/java/com/owncloud/android/datamodel/quickPermission/QuickPermissionType.kt @@ -27,10 +27,15 @@ enum class QuickPermissionType(val iconId: Int, val textId: Int) { fun getPermissionFlag(isFolder: Boolean): Int = when (this) { NONE -> OCShare.NO_PERMISSION + VIEW_ONLY -> OCShare.READ_PERMISSION_FLAG + CAN_EDIT -> if (isFolder) OCShare.MAXIMUM_PERMISSIONS_FOR_FOLDER else OCShare.MAXIMUM_PERMISSIONS_FOR_FILE + FILE_REQUEST -> OCShare.CREATE_PERMISSION_FLAG + SECURE_FILE_DROP -> OCShare.CREATE_PERMISSION_FLAG + OCShare.READ_PERMISSION_FLAG + else -> { // Custom permission's flag can't be determined OCShare.NO_PERMISSION 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 f137102a71d7..651f4741639d 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 @@ -261,7 +261,7 @@ class FileDisplayActivity : loadSavedInstanceState(savedInstanceState) - /** USER INTERFACE */ + // USER INTERFACE initLayout() initUI() initTaskRetainerFragment() @@ -536,7 +536,7 @@ class FileDisplayActivity : } private fun initFragments() { - /** First fragment */ + // First fragment val listOfFiles = this.listOfFilesFragment if (listOfFiles != null && TextUtils.isEmpty(searchQuery)) { listOfFiles.listDirectory(getCurrentDir(), file, MainApp.isOnlyOnDevice()) @@ -544,7 +544,7 @@ class FileDisplayActivity : Log_OC.e(TAG, "Still have a chance to lose the initialization of list fragment >(") } - /** reset views */ + // reset views resetScrollingAndUpdateActionBar() } @@ -605,6 +605,7 @@ class FileDisplayActivity : private fun handleCommonIntents(intent: Intent) { when (intent.action) { Intent.ACTION_VIEW -> handleOpenFileViaIntent(intent) + OPEN_FILE -> { onOpenFileIntent(intent) } @@ -788,11 +789,7 @@ class FileDisplayActivity : var leftFragment: Fragment? get() = supportFragmentManager.findFragmentByTag(TAG_LIST_OF_FILES) - /** - * Replaces the first fragment managed by the activity with the received as a parameter. - * - * @param fragment New Fragment to set. - */ + // Replaces the first fragment managed by the activity with the received as a parameter. private set(fragment) { setLeftFragment(fragment, true) } @@ -1235,6 +1232,7 @@ class FileDisplayActivity : android.R.id.home -> { when { shouldOpenDrawer() -> openDrawer() + else -> { handleBackPressImpl() } @@ -1646,9 +1644,11 @@ class FileDisplayActivity : mSyncInProgress -> { it.setEmptyListMessage(EmptyListState.LOADING) } + MainApp.isOnlyOnDevice() -> { it.setEmptyListMessage(EmptyListState.ONLY_ON_DEVICE) } + else -> it.setEmptyListMessage(SearchType.NO_SEARCH) } } @@ -2351,21 +2351,6 @@ class FileDisplayActivity : * change. * @param ignoreFocus reloads file list even without focus, e.g. on tablet mode, focus can still be in detail view */ - - /** - * Starts an operation to refresh the requested folder. - * - * - * The operation is run in a new background thread created on the fly. - * - * - * The refresh updates is a "light sync": properties of regular files in folder are updated (including associated - * shares), but not their contents. Only the contents of files marked to be kept-in-sync are synchronized too. - * - * @param folder Folder to refresh. - * @param ignoreETag If 'true', the data from the server will be fetched and sync'ed even if the eTag didn't - * change. - */ @JvmOverloads fun startSyncFolderOperation(folder: OCFile?, ignoreETag: Boolean, ignoreFocus: Boolean = false) { Log_OC.d(TAG, "startSyncFolderOperation called, ignoreEtag: $ignoreETag, ignoreFocus: $ignoreFocus") @@ -2378,7 +2363,7 @@ class FileDisplayActivity : handler.postDelayed({ val user = getUser() - if (!ignoreFocus && !hasWindowFocus() || !user.isPresent) { + 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 @@ -2532,7 +2517,7 @@ class FileDisplayActivity : return // not reachable under normal conditions } val actualUser = user.get() - if (showPreview && file.isDown && !file.isDownloading || streamMedia) { + if ((showPreview && file.isDown && !file.isDownloading) || streamMedia) { if (showInActivity) { startMediaActivity(file, startPlaybackPosition, autoplay, actualUser) } else { diff --git a/app/src/main/java/com/owncloud/android/ui/activity/FolderPickerActivity.kt b/app/src/main/java/com/owncloud/android/ui/activity/FolderPickerActivity.kt index 106c22183bbf..63f82db8cdff 100644 --- a/app/src/main/java/com/owncloud/android/ui/activity/FolderPickerActivity.kt +++ b/app/src/main/java/com/owncloud/android/ui/activity/FolderPickerActivity.kt @@ -410,8 +410,11 @@ open class FolderPickerActivity : // for copy and move, disable selecting parent folder of target files private fun isFolderSelectable(type: String): Boolean = when { action != MOVE_OR_COPY -> true + action == MOVE_OR_COPY && type == COPY -> true + targetFilePaths.isNullOrEmpty() -> true + file?.isFolder != true -> true // all of the target files are already in the selected directory @@ -419,6 +422,7 @@ open class FolderPickerActivity : // some of the target files are parents of the selected folder targetFilePaths?.any { PathUtils.isAncestor(it, file?.remotePath ?: "") } == true -> false + else -> true } diff --git a/app/src/main/java/com/owncloud/android/ui/activity/InternalTwoWaySyncActivity.kt b/app/src/main/java/com/owncloud/android/ui/activity/InternalTwoWaySyncActivity.kt index f85127cd2ded..3727d3885de6 100644 --- a/app/src/main/java/com/owncloud/android/ui/activity/InternalTwoWaySyncActivity.kt +++ b/app/src/main/java/com/owncloud/android/ui/activity/InternalTwoWaySyncActivity.kt @@ -206,6 +206,7 @@ class InternalTwoWaySyncActivity : android.R.id.home -> { onBackPressedDispatcher.onBackPressed() } + R.id.action_dismiss_two_way_sync -> { disableTwoWaySyncAndWorkers() } diff --git a/app/src/main/java/com/owncloud/android/ui/activity/ManageAccountsActivity.kt b/app/src/main/java/com/owncloud/android/ui/activity/ManageAccountsActivity.kt index 79bd72d76099..e54406aa0f1d 100644 --- a/app/src/main/java/com/owncloud/android/ui/activity/ManageAccountsActivity.kt +++ b/app/src/main/java/com/owncloud/android/ui/activity/ManageAccountsActivity.kt @@ -437,9 +437,11 @@ class ManageAccountsActivity : R.id.action_open_account -> { accountClicked(user) } + R.id.action_delete_account -> { openAccountRemovalDialog(user, supportFragmentManager) } + else -> { openAccount(user) } diff --git a/app/src/main/java/com/owncloud/android/ui/activity/ManageSpaceActivity.kt b/app/src/main/java/com/owncloud/android/ui/activity/ManageSpaceActivity.kt index 4279b2f2a066..674a7d1dab62 100644 --- a/app/src/main/java/com/owncloud/android/ui/activity/ManageSpaceActivity.kt +++ b/app/src/main/java/com/owncloud/android/ui/activity/ManageSpaceActivity.kt @@ -149,6 +149,7 @@ class ManageSpaceActivity : finish() true } + else -> { Log_OC.w(TAG, "Unknown menu item triggered") super.onOptionsItemSelected(item) diff --git a/app/src/main/java/com/owncloud/android/ui/activity/NotificationsActivity.kt b/app/src/main/java/com/owncloud/android/ui/activity/NotificationsActivity.kt index dc24fb140963..15c1b584c77a 100644 --- a/app/src/main/java/com/owncloud/android/ui/activity/NotificationsActivity.kt +++ b/app/src/main/java/com/owncloud/android/ui/activity/NotificationsActivity.kt @@ -319,9 +319,11 @@ class NotificationsActivity : android.R.id.home -> { onBackPressedDispatcher.onBackPressed() } + R.id.action_empty_notifications -> { DeleteAllNotificationsTask(client, this).execute() } + else -> { retval = super.onOptionsItemSelected(item) } diff --git a/app/src/main/java/com/owncloud/android/ui/activity/PassCodeActivity.kt b/app/src/main/java/com/owncloud/android/ui/activity/PassCodeActivity.kt index 805ce701f358..641945b43448 100644 --- a/app/src/main/java/com/owncloud/android/ui/activity/PassCodeActivity.kt +++ b/app/src/main/java/com/owncloud/android/ui/activity/PassCodeActivity.kt @@ -361,6 +361,7 @@ class PassCodeActivity : timeInSecond, timeInSecond ) + else -> { val minutes = timeInSecond / 60 val remainingSeconds = timeInSecond % 60 @@ -371,6 +372,7 @@ class PassCodeActivity : minutes, minutes ) + else -> { val minuteText = resources.getQuantityString( R.plurals.delay_message_minutes_part, 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 d361e128f4c0..4f32e0d8f9b8 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 @@ -105,7 +105,9 @@ class SyncedFoldersActivity : } else if (f1.isEnabled && f2.isEnabled) { when { f1.folderName == null -> -1 + f2.folderName == null -> 1 + else -> f1.folderName.lowercase(Locale.getDefault()).compareTo( f2.folderName.lowercase(Locale.getDefault()) ) @@ -531,6 +533,7 @@ class SyncedFoldersActivity : var result = true when (item.itemId) { android.R.id.home -> finish() + R.id.action_create_custom_folder -> { Log_OC.d(TAG, "Show custom folder dialog") if (PermissionUtil.checkStoragePermission(this)) { @@ -560,6 +563,7 @@ class SyncedFoldersActivity : } result = super.onOptionsItemSelected(item) } + else -> result = super.onOptionsItemSelected(item) } return result @@ -835,6 +839,7 @@ class SyncedFoldersActivity : load(getItemsDisplayedPerFolder(), true) } } + else -> super.onRequestPermissionsResult(requestCode, permissions, grantResults) } } 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 3d3437785e5d..343659e8938a 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 @@ -216,14 +216,22 @@ class OCFileListDelegate( // shares val shouldHideShare = ( - hideItemOptions || - !file.isFolder && - file.isEncrypted || - file.isEncrypted && - !EncryptionUtils.supportsSecureFiledrop(file, user) || - searchType == SearchType.FAVORITE_SEARCH || - file.isFolder && - currentDirectory?.isEncrypted ?: false + ( + hideItemOptions || + ( + !file.isFolder && + file.isEncrypted + ) || + ( + file.isEncrypted && + !EncryptionUtils.supportsSecureFiledrop(file, user) + ) || + (searchType == SearchType.FAVORITE_SEARCH) || + ( + file.isFolder && + (currentDirectory?.isEncrypted ?: false) + ) + ) ) // sharing an encrypted subfolder is not possible if (shouldHideShare) { viewHolder.shared.visibility = View.GONE @@ -390,6 +398,7 @@ class OCFileListDelegate( } file.isSharedViaLink -> R.drawable.shared_via_link to R.string.shared_icon_shared_via_link + else -> R.drawable.ic_unshared to R.string.shared_icon_share } } 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 9573d7c11476..a08fe38d189f 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 @@ -475,6 +475,7 @@ class SyncedFolderAdapter( ) ) } + VIEW_TYPE_FOOTER -> { FooterViewHolder( SyncedFoldersFooterBinding.inflate( @@ -484,6 +485,7 @@ class SyncedFolderAdapter( ) ) } + VIEW_TYPE_EMPTY -> { EmptyViewHolder( SyncedFoldersEmptyBinding.inflate( @@ -493,6 +495,7 @@ class SyncedFolderAdapter( ) ) } + else -> { MainViewHolder( GridSyncItemBinding.inflate( 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 6e5b0c6a4f20..da62218ff348 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 @@ -70,6 +70,7 @@ class UnifiedSearchListAdapter( ) UnifiedSearchHeaderViewHolder(binding, viewThemeUtils, context) } + VIEW_TYPE_FOOTER -> { val binding = UnifiedSearchFooterBinding.inflate( layoutInflater, @@ -78,6 +79,7 @@ class UnifiedSearchListAdapter( ) UnifiedSearchFooterViewHolder(binding, context, listInterface) } + VIEW_TYPE_ITEM -> { val binding = UnifiedSearchItemBinding.inflate( layoutInflater, @@ -95,6 +97,7 @@ class UnifiedSearchListAdapter( viewThemeUtils ) } + VIEW_TYPE_CURRENT_DIR -> { val isRTL = DisplayUtils.isRTL() val binding = UnifiedSearchCurrentDirectoryItemBinding.inflate(layoutInflater, parent, false) @@ -110,10 +113,12 @@ class UnifiedSearchListAdapter( currentDirItemAction ) } + VIEW_TYPE_EMPTY -> { val binding = UnifiedSearchEmptyBinding.inflate(layoutInflater, parent, false) EmptyViewHolder(binding) } + else -> throw IllegalArgumentException("Invalid view type") } } diff --git a/app/src/main/java/com/owncloud/android/ui/dialog/ChooseTemplateDialogFragment.kt b/app/src/main/java/com/owncloud/android/ui/dialog/ChooseTemplateDialogFragment.kt index a9f4e32e0f68..4f0d97f6a385 100644 --- a/app/src/main/java/com/owncloud/android/ui/dialog/ChooseTemplateDialogFragment.kt +++ b/app/src/main/java/com/owncloud/android/ui/dialog/ChooseTemplateDialogFragment.kt @@ -234,12 +234,15 @@ class ChooseTemplateDialogFragment : selectedTemplate == null -> { DisplayUtils.showSnackMessage(binding.list, R.string.select_one_template) } + errorMessage != null -> { DisplayUtils.showSnackMessage(requireActivity(), errorMessage) } + name.equals(DOT + selectedTemplate.extension, ignoreCase = true) -> { DisplayUtils.showSnackMessage(binding.list, R.string.enter_filename) } + else -> { val fullPath = if (!name.endsWith(selectedTemplate.extension)) { path + DOT + selectedTemplate.extension diff --git a/app/src/main/java/com/owncloud/android/ui/dialog/MultipleAccountsDialog.kt b/app/src/main/java/com/owncloud/android/ui/dialog/MultipleAccountsDialog.kt index 83caa6582bcb..db0f0a8749dd 100644 --- a/app/src/main/java/com/owncloud/android/ui/dialog/MultipleAccountsDialog.kt +++ b/app/src/main/java/com/owncloud/android/ui/dialog/MultipleAccountsDialog.kt @@ -65,13 +65,13 @@ class MultipleAccountsDialog : return builder.create() } + /** + * creates the account list items list including the add-account action in case + * multi account support is enabled. + * + * @return list of account list items + */ private val accountListItems: List - /** - * creates the account list items list including the add-account action in case - * multi account support is enabled. - * - * @return list of account list items - */ get() { val users = accountManager?.allUsers ?: listOf() 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 96e61a9dd5ea..8eec8a5aefa1 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 @@ -609,6 +609,7 @@ open class ExtendedListFragment : true ) } + SearchType.FILE_SEARCH -> { setMessageForEmptyList( R.string.file_list_empty_headline_server_search, @@ -616,6 +617,7 @@ open class ExtendedListFragment : R.drawable.ic_search_light_grey ) } + SearchType.FAVORITE_SEARCH -> { setMessageForEmptyList( R.string.file_list_empty_favorite_headline, @@ -623,6 +625,7 @@ open class ExtendedListFragment : R.drawable.ic_star_light_yellow ) } + SearchType.RECENTLY_MODIFIED_SEARCH -> { setMessageForEmptyList( R.string.file_list_empty_headline_server_search, @@ -630,6 +633,7 @@ open class ExtendedListFragment : R.drawable.ic_list_empty_recent ) } + SearchType.REGULAR_FILTER -> { setMessageForEmptyList( R.string.file_list_empty_headline_search, @@ -637,6 +641,7 @@ open class ExtendedListFragment : R.drawable.ic_search_light_grey ) } + SearchType.SHARED_FILTER -> { setMessageForEmptyList( R.string.file_list_empty_shared_headline, @@ -644,6 +649,7 @@ open class ExtendedListFragment : R.drawable.ic_list_empty_shared ) } + SearchType.GALLERY_SEARCH -> { setMessageForEmptyList( R.string.file_list_empty_headline_server_search, @@ -651,6 +657,7 @@ open class ExtendedListFragment : R.drawable.file_image ) } + SearchType.LOCAL_SEARCH -> { setMessageForEmptyList( R.string.file_list_empty_headline_server_search, @@ -658,6 +665,7 @@ open class ExtendedListFragment : R.drawable.ic_search_light_grey ) } + EmptyListState.OFFLINE_MODE -> { setMessageForEmptyList( R.string.offline_mode_info_title, @@ -666,6 +674,7 @@ open class ExtendedListFragment : true ) } + EmptyListState.LOADING -> { setMessageForEmptyList( R.string.file_list_loading, @@ -673,6 +682,7 @@ open class ExtendedListFragment : null ) } + EmptyListState.ADD_FOLDER -> { setMessageForEmptyList( R.string.folder_list_empty_headline, @@ -681,6 +691,7 @@ open class ExtendedListFragment : true ) } + EmptyListState.ONLY_ON_DEVICE -> { setMessageForEmptyList( R.string.file_list_empty_headline, @@ -689,6 +700,7 @@ open class ExtendedListFragment : true ) } + EmptyListState.LOCAL_FILE_LIST_EMPTY_FILE -> { setMessageForEmptyList( R.string.file_list_empty_headline, @@ -697,6 +709,7 @@ open class ExtendedListFragment : true ) } + EmptyListState.LOCAL_FILE_LIST_EMPTY_FOLDER -> { setMessageForEmptyList( R.string.folder_list_empty_headline, @@ -705,6 +718,7 @@ open class ExtendedListFragment : true ) } + EmptyListState.ERROR -> { setMessageForEmptyList( R.string.file_list_error_headline, @@ -713,6 +727,7 @@ open class ExtendedListFragment : false ) } + else -> { setMessageForEmptyList( R.string.file_list_empty_headline, @@ -728,12 +743,12 @@ open class ExtendedListFragment : } } + /** + * Get the text of EmptyListMessage TextView. + * + * @return String empty text view text-value + */ val emptyViewText: String - /** - * Get the text of EmptyListMessage TextView. - * - * @return String empty text view text-value - */ get() = if (mEmptyListContainer != null && mEmptyListMessage != null) { mEmptyListMessage?.getText() .toString() diff --git a/app/src/main/java/com/owncloud/android/ui/fragment/GalleryFragmentBottomSheetDialog.kt b/app/src/main/java/com/owncloud/android/ui/fragment/GalleryFragmentBottomSheetDialog.kt index 4b382de4c831..76662c64b8d3 100644 --- a/app/src/main/java/com/owncloud/android/ui/fragment/GalleryFragmentBottomSheetDialog.kt +++ b/app/src/main/java/com/owncloud/android/ui/fragment/GalleryFragmentBottomSheetDialog.kt @@ -71,10 +71,12 @@ class GalleryFragmentBottomSheetDialog(private val actions: GalleryFragmentBotto binding.tickMarkShowImages.visibility = View.VISIBLE binding.tickMarkShowVideos.visibility = View.GONE } + MediaState.MEDIA_STATE_VIDEOS_ONLY -> { binding.tickMarkShowImages.visibility = View.GONE binding.tickMarkShowVideos.visibility = View.VISIBLE } + else -> { binding.tickMarkShowImages.visibility = View.VISIBLE binding.tickMarkShowVideos.visibility = View.VISIBLE 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 c9da435e7e61..059dd689a2a0 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 @@ -286,6 +286,7 @@ class OCFileListSearchTask( metadata, ocFile ) + is DecryptedFolderMetadataFile -> RefreshFolderOperation.updateFileNameForEncryptedFile( fileDataStorage, 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 46ef6486c751..7c8bd588807f 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 @@ -241,6 +241,7 @@ class UnifiedSearchFragment : is UnifiedSearchFragmentScreenState.ShowingContent -> { toggleEmptyListVisible(show = false) } + is UnifiedSearchFragmentScreenState.Empty -> { showEmptyView(state) } diff --git a/app/src/main/java/com/owncloud/android/ui/fragment/contactsbackup/BackupListAdapter.kt b/app/src/main/java/com/owncloud/android/ui/fragment/contactsbackup/BackupListAdapter.kt index 178d26f22aa9..65ce44374614 100644 --- a/app/src/main/java/com/owncloud/android/ui/fragment/contactsbackup/BackupListAdapter.kt +++ b/app/src/main/java/com/owncloud/android/ui/fragment/contactsbackup/BackupListAdapter.kt @@ -89,6 +89,7 @@ class BackupListAdapter( context ) } + VIEW_TYPE_CONTACTS -> { ContactItemViewHolder( ContactlistListItemBinding.inflate( @@ -98,6 +99,7 @@ class BackupListAdapter( ) ) } + else -> { CalendarItemViewHolder( CalendarlistListItemBinding.inflate( diff --git a/app/src/main/java/com/owncloud/android/ui/fragment/util/GalleryFastScrollViewHelper.kt b/app/src/main/java/com/owncloud/android/ui/fragment/util/GalleryFastScrollViewHelper.kt index 277e47693853..874858963b30 100644 --- a/app/src/main/java/com/owncloud/android/ui/fragment/util/GalleryFastScrollViewHelper.kt +++ b/app/src/main/java/com/owncloud/android/ui/fragment/util/GalleryFastScrollViewHelper.kt @@ -124,7 +124,9 @@ class GalleryFastScrollViewHelper(private val mView: RecyclerView, private val m val totalSeenRows = seenRowsInPreviousSections + seenRowsInThisSection val seenHeaders = when { - isHeader -> itemCoord.section() // don't count the current section header + isHeader -> itemCoord.section() + + // don't count the current section header else -> itemCoord.section() + 1 } diff --git a/app/src/main/java/com/owncloud/android/ui/preview/PreviewImageFragment.kt b/app/src/main/java/com/owncloud/android/ui/preview/PreviewImageFragment.kt index 9b16124a0e6d..3fd3acc3874e 100644 --- a/app/src/main/java/com/owncloud/android/ui/preview/PreviewImageFragment.kt +++ b/app/src/main/java/com/owncloud/android/ui/preview/PreviewImageFragment.kt @@ -82,19 +82,14 @@ import kotlin.math.min * This fragment shows a preview of a downloaded image. * Trying to get an instance with a NULL [OCFile] will produce an [IllegalStateException]. * If the [OCFile] passed is not downloaded, an [IllegalStateException] is generated on instantiation too. - */ - -/** - * Creates an empty fragment for image previews. * + * Creates an empty fragment for image previews. * * MUST BE KEPT: the system uses it when tries to re-instantiate a fragment automatically (for instance, when the * device is turned a aside). * - * * DO NOT CALL IT: an [OCFile] and [User] must be provided for a successful construction */ - @Suppress("TooManyFunctions") class PreviewImageFragment : FileFragment(), diff --git a/app/src/main/java/com/owncloud/android/ui/preview/PreviewMediaFragment.kt b/app/src/main/java/com/owncloud/android/ui/preview/PreviewMediaFragment.kt index de86259e9337..3f68ba5ded0a 100644 --- a/app/src/main/java/com/owncloud/android/ui/preview/PreviewMediaFragment.kt +++ b/app/src/main/java/com/owncloud/android/ui/preview/PreviewMediaFragment.kt @@ -78,26 +78,19 @@ import javax.inject.Inject /** * This fragment shows a preview of a downloaded media file (audio or video). * - * * Trying to get an instance with NULL [OCFile] or ownCloud [User] values will produce an * [IllegalStateException]. * - * * By now, if the [OCFile] passed is not downloaded, an [IllegalStateException] is generated on * instantiation too. - */ - -/** - * Creates an empty fragment for previews. * + * Creates an empty fragment for previews. * * MUST BE KEPT: the system uses it when tries to reinstantiate a fragment automatically (for instance, when the * device is turned a aside). * - * * DO NOT CALL IT: an [OCFile] and [User] must be provided for a successful construction */ - @Suppress("NestedBlockDepth", "ComplexMethod", "LongMethod", "TooManyFunctions") class PreviewMediaFragment : FileFragment(), diff --git a/app/src/main/java/com/owncloud/android/ui/preview/PreviewTextFragment.kt b/app/src/main/java/com/owncloud/android/ui/preview/PreviewTextFragment.kt index 99b0bffc4bf3..a1b2692fd090 100644 --- a/app/src/main/java/com/owncloud/android/ui/preview/PreviewTextFragment.kt +++ b/app/src/main/java/com/owncloud/android/ui/preview/PreviewTextFragment.kt @@ -235,8 +235,8 @@ abstract class PreviewTextFragment : return } - if ((ignoreMimetype || file != null && MimeTypeUtil.MIMETYPE_TEXT_MARKDOWN == file.mimeType) && - activity != null + if ((ignoreMimetype || ((file != null) && (MimeTypeUtil.MIMETYPE_TEXT_MARKDOWN == file.mimeType))) && + (activity != null) ) { if (!preview) { // clickable links prevent to open full view of rich workspace diff --git a/app/src/main/java/com/owncloud/android/ui/unifiedsearch/GetSearchProvidersTask.kt b/app/src/main/java/com/owncloud/android/ui/unifiedsearch/GetSearchProvidersTask.kt index 220c40eb3089..0e5fd445ac7e 100644 --- a/app/src/main/java/com/owncloud/android/ui/unifiedsearch/GetSearchProvidersTask.kt +++ b/app/src/main/java/com/owncloud/android/ui/unifiedsearch/GetSearchProvidersTask.kt @@ -31,6 +31,7 @@ class GetSearchProvidersTask(private val client: NextcloudClient) : () -> GetSea providers = result.resultData ) } + else -> Result() } } 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..9c5dbced6b8d 100644 --- a/app/src/main/java/com/owncloud/android/utils/FileSortOrderByName.kt +++ b/app/src/main/java/com/owncloud/android/utils/FileSortOrderByName.kt @@ -70,8 +70,11 @@ class FileSortOrderByName internal constructor(name: String?, ascending: Boolean when { o1.isDirectory && o2.isDirectory -> sortMultiplier * o1.path.lowercase(Locale.getDefault()) .compareTo(o2.path.lowercase(Locale.getDefault())) + o1.isDirectory -> -1 + o2.isDirectory -> 1 + else -> sortMultiplier * AlphanumComparator.compare( o1.path.lowercase(Locale.getDefault()), o2.path.lowercase(Locale.getDefault()) 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..2c7608e0d003 100644 --- a/app/src/main/java/com/owncloud/android/utils/FileSortOrderBySize.kt +++ b/app/src/main/java/com/owncloud/android/utils/FileSortOrderBySize.kt @@ -52,8 +52,11 @@ class FileSortOrderBySize internal constructor(name: String?, ascending: Boolean o1.isDirectory && o2.isDirectory -> sortMultiplier * (folderSizes[o1] ?: 0L).compareTo( folderSizes[o2] ?: 0L ) + o1.isDirectory -> -1 + o2.isDirectory -> 1 + else -> sortMultiplier * o1.length().compareTo(o2.length()) } } diff --git a/app/src/main/java/com/owncloud/android/utils/SyncedFolderUtils.kt b/app/src/main/java/com/owncloud/android/utils/SyncedFolderUtils.kt index b51652a1ff1b..1f55b1a6ddbe 100644 --- a/app/src/main/java/com/owncloud/android/utils/SyncedFolderUtils.kt +++ b/app/src/main/java/com/owncloud/android/utils/SyncedFolderUtils.kt @@ -41,15 +41,20 @@ object SyncedFolderUtils { */ fun isQualifyingMediaFolder(mediaFolder: MediaFolder?): Boolean = when { mediaFolder == null -> false + AUTO_QUALIFYING_FOLDER_TYPE_SET.contains(mediaFolder.type) -> true + !isQualifiedFolder(mediaFolder.absolutePath) -> false + else -> { when { mediaFolder.numberOfFiles < SINGLE_FILE -> false + // music album (just one cover-art image) mediaFolder.type == MediaFolderType.IMAGE -> containsQualifiedImages( mediaFolder.filePaths.map { File(it) } ) + else -> true } } @@ -79,15 +84,20 @@ object SyncedFolderUtils { */ fun isQualifyingMediaFolder(folderPath: String?, folderType: MediaFolderType): Boolean = when { AUTO_QUALIFYING_FOLDER_TYPE_SET.contains(folderType) -> true + !isQualifiedFolder(folderPath) -> false + folderPath == null -> false + else -> { val files: List = getFileList(File(folderPath)) when { // no files files.size < SINGLE_FILE -> false + // music album (just one cover-art image) folderType == MediaFolderType.IMAGE -> containsQualifiedImages(files) + else -> true } } @@ -130,6 +140,7 @@ object SyncedFolderUtils { !DISQUALIFIED_MEDIA_DETECTION_FILE_SET.contains(fileName.lowercase()) && !hasExcludePrefix(fileName) } + else -> false } diff --git a/app/src/main/java/com/owncloud/android/utils/UriUtils.kt b/app/src/main/java/com/owncloud/android/utils/UriUtils.kt index 34a1f7d4bfa9..fde89b8dcef0 100644 --- a/app/src/main/java/com/owncloud/android/utils/UriUtils.kt +++ b/app/src/main/java/com/owncloud/android/utils/UriUtils.kt @@ -71,12 +71,15 @@ object UriUtils { MimeTypeUtil.isImage(mimeType) -> { MediaStore.Images.ImageColumns.DISPLAY_NAME } + MimeTypeUtil.isVideo(mimeType) -> { MediaStore.Video.VideoColumns.DISPLAY_NAME } + MimeTypeUtil.isAudio(mimeType) -> { MediaStore.Audio.AudioColumns.DISPLAY_NAME } + else -> { MediaStore.Files.FileColumns.DISPLAY_NAME } diff --git a/app/src/main/java/com/owncloud/android/utils/theme/FilesSpecificViewThemeUtils.kt b/app/src/main/java/com/owncloud/android/utils/theme/FilesSpecificViewThemeUtils.kt index 22c853ae9226..c52e6c509773 100644 --- a/app/src/main/java/com/owncloud/android/utils/theme/FilesSpecificViewThemeUtils.kt +++ b/app/src/main/java/com/owncloud/android/utils/theme/FilesSpecificViewThemeUtils.kt @@ -84,14 +84,17 @@ class FilesSpecificViewThemeUtils @Inject constructor( createAvatarBase(R.drawable.ic_group) androidViewThemeUtils.colorImageViewBackgroundAndIcon(avatar) } + ShareType.FEDERATED_GROUP -> { createAvatarBase(R.drawable.ic_group) androidViewThemeUtils.colorImageViewBackgroundAndIcon(avatar) } + ShareType.ROOM -> { createAvatarBase(R.drawable.ic_talk, AvatarPadding.LARGE) androidViewThemeUtils.colorImageViewBackgroundAndIcon(avatar) } + ShareType.CIRCLE -> { createAvatarBase(R.drawable.ic_circles) avatar.background.setColorFilter( @@ -103,10 +106,12 @@ class FilesSpecificViewThemeUtils @Inject constructor( PorterDuff.Mode.SRC_IN ) } + ShareType.EMAIL -> { createAvatarBase(R.drawable.ic_email, AvatarPadding.LARGE) androidViewThemeUtils.colorImageViewBackgroundAndIcon(avatar) } + else -> Log_OC.d(TAG, "Unknown share type") } } diff --git a/app/src/main/java/com/owncloud/android/utils/theme/MaterialSchemesProviderImpl.kt b/app/src/main/java/com/owncloud/android/utils/theme/MaterialSchemesProviderImpl.kt index 7886e474ef36..91c7774a103b 100644 --- a/app/src/main/java/com/owncloud/android/utils/theme/MaterialSchemesProviderImpl.kt +++ b/app/src/main/java/com/owncloud/android/utils/theme/MaterialSchemesProviderImpl.kt @@ -49,6 +49,7 @@ internal class MaterialSchemesProviderImpl @Inject constructor( logger.d(TAG, "User is anonymous, using default schemes") getDefaultMaterialSchemes() } + else -> getMaterialSchemesForUser(user) } diff --git a/app/src/test/java/com/nextcloud/client/logger/LogEntryTest.kt b/app/src/test/java/com/nextcloud/client/logger/LogEntryTest.kt index 8428f34f2067..a4b6e18a2e28 100644 --- a/app/src/test/java/com/nextcloud/client/logger/LogEntryTest.kt +++ b/app/src/test/java/com/nextcloud/client/logger/LogEntryTest.kt @@ -80,7 +80,7 @@ class LogEntryTest { timestamp = Date(0), level = Level.DEBUG, tag = - """ι–εΊ·η·—η΄ ι›œθ¨˜""", + """ι–εΊ·η·—η΄ ι›œθ¨˜""", message = "倏炉冬扇" ) assertEquals("1970-01-01T00:00:00.000Z;D;ι–εΊ·η·—η΄ ι›œθ¨˜;倏炉冬扇", entry.toString()) diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index da4bd75656f0..2d944b87bd89 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -80,7 +80,7 @@ shotVersion = "6.1.0" slfj = "2.0.17" splash-screen = "1.2.0" spotbugsGradlePlugin = "6.4.8" -spotless = "8.1.0" +spotless = "8.2.1" stateless4jVersion = "2.6.0" webkitVersion = "1.15.0" workRuntime = "2.11.1" diff --git a/gradle/verification-metadata.xml b/gradle/verification-metadata.xml index 2f40ca6e2ebc..2be1fd54ae2e 100644 --- a/gradle/verification-metadata.xml +++ b/gradle/verification-metadata.xml @@ -203,6 +203,7 @@ + @@ -346,6 +347,7 @@ + @@ -20007,6 +20009,11 @@ + + + + +