From 9151e32a5b238ae9c5ff8c47b9ca4362bda01d35 Mon Sep 17 00:00:00 2001 From: alperozturk Date: Mon, 12 Feb 2024 13:04:35 +0100 Subject: [PATCH 01/31] Check emptiness of previousSortGroupState Signed-off-by: alperozturk --- .../com/owncloud/android/ui/activity/FileDisplayActivity.java | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/app/src/main/java/com/owncloud/android/ui/activity/FileDisplayActivity.java b/app/src/main/java/com/owncloud/android/ui/activity/FileDisplayActivity.java index 17350ce3fb..3b63718139 100644 --- a/app/src/main/java/com/owncloud/android/ui/activity/FileDisplayActivity.java +++ b/app/src/main/java/com/owncloud/android/ui/activity/FileDisplayActivity.java @@ -2486,6 +2486,10 @@ public class FileDisplayActivity extends FileActivity * visibility earlier using {@link #setSortListGroup(boolean, boolean)} */ private void popSortListGroupVisibility() { + if (previousSortGroupState.isEmpty()) { + return; + } + boolean popped = previousSortGroupState.pop(); showSortListGroup(popped); } From 0bbff3bcd9fb0d9958626b8f16fd15601e3aad1f Mon Sep 17 00:00:00 2001 From: alperozturk Date: Mon, 12 Feb 2024 14:47:28 +0100 Subject: [PATCH 02/31] Show sort list group for file list Signed-off-by: alperozturk --- .../owncloud/android/ui/activity/FileDisplayActivity.java | 1 + .../com/owncloud/android/ui/adapter/OCFileListAdapter.java | 5 +++++ 2 files changed, 6 insertions(+) diff --git a/app/src/main/java/com/owncloud/android/ui/activity/FileDisplayActivity.java b/app/src/main/java/com/owncloud/android/ui/activity/FileDisplayActivity.java index 3b63718139..76d58e8bdb 100644 --- a/app/src/main/java/com/owncloud/android/ui/activity/FileDisplayActivity.java +++ b/app/src/main/java/com/owncloud/android/ui/activity/FileDisplayActivity.java @@ -2487,6 +2487,7 @@ public class FileDisplayActivity extends FileActivity */ private void popSortListGroupVisibility() { if (previousSortGroupState.isEmpty()) { + showSortListGroup(false); return; } diff --git a/app/src/main/java/com/owncloud/android/ui/adapter/OCFileListAdapter.java b/app/src/main/java/com/owncloud/android/ui/adapter/OCFileListAdapter.java index 00f9e2933d..a7165f3cf8 100644 --- a/app/src/main/java/com/owncloud/android/ui/adapter/OCFileListAdapter.java +++ b/app/src/main/java/com/owncloud/android/ui/adapter/OCFileListAdapter.java @@ -74,6 +74,7 @@ import com.owncloud.android.lib.resources.shares.ShareeUser; import com.owncloud.android.operations.RefreshFolderOperation; import com.owncloud.android.operations.RemoteOperationFailedException; import com.owncloud.android.ui.activity.ComponentsGetter; +import com.owncloud.android.ui.activity.FileDisplayActivity; import com.owncloud.android.ui.fragment.SearchType; import com.owncloud.android.ui.interfaces.OCFileListFragmentInterface; import com.owncloud.android.ui.preview.PreviewTextFragment; @@ -160,6 +161,10 @@ public class OCFileListAdapter extends RecyclerView.Adapter Date: Tue, 13 Feb 2024 10:10:01 +0100 Subject: [PATCH 03/31] Fix visibility of sort list group Signed-off-by: alperozturk --- .../owncloud/android/ui/activity/FileDisplayActivity.java | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/app/src/main/java/com/owncloud/android/ui/activity/FileDisplayActivity.java b/app/src/main/java/com/owncloud/android/ui/activity/FileDisplayActivity.java index 76d58e8bdb..3e55bbdea3 100644 --- a/app/src/main/java/com/owncloud/android/ui/activity/FileDisplayActivity.java +++ b/app/src/main/java/com/owncloud/android/ui/activity/FileDisplayActivity.java @@ -2486,12 +2486,12 @@ public class FileDisplayActivity extends FileActivity * visibility earlier using {@link #setSortListGroup(boolean, boolean)} */ private void popSortListGroupVisibility() { + showSortListGroup(false); + if (previousSortGroupState.isEmpty()) { - showSortListGroup(false); return; } - boolean popped = previousSortGroupState.pop(); - showSortListGroup(popped); + previousSortGroupState.pop(); } } From 610ec1dfb73cf0fcd7daed62d8973cd40bdf0a18 Mon Sep 17 00:00:00 2001 From: Jonas Mayer Date: Tue, 6 Feb 2024 14:35:51 +0100 Subject: [PATCH 04/31] change database query to only return uploads for right account Signed-off-by: Jonas Mayer --- .../owncloud/android/datamodel/UploadsStorageManager.java | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/app/src/main/java/com/owncloud/android/datamodel/UploadsStorageManager.java b/app/src/main/java/com/owncloud/android/datamodel/UploadsStorageManager.java index be3fdf15e1..a00fba2a52 100644 --- a/app/src/main/java/com/owncloud/android/datamodel/UploadsStorageManager.java +++ b/app/src/main/java/com/owncloud/android/datamodel/UploadsStorageManager.java @@ -569,7 +569,7 @@ public class UploadsStorageManager extends Observable { } public OCUpload[] getCurrentAndPendingUploadsForAccount(final @NonNull String accountName) { - return getUploads(ProviderTableMeta.UPLOADS_STATUS + "==" + UploadStatus.UPLOAD_IN_PROGRESS.value + + return getUploads("( " + ProviderTableMeta.UPLOADS_STATUS + "==" + UploadStatus.UPLOAD_IN_PROGRESS.value + " OR " + ProviderTableMeta.UPLOADS_LAST_RESULT + "==" + UploadResult.DELAYED_FOR_WIFI.getValue() + " OR " + ProviderTableMeta.UPLOADS_LAST_RESULT + @@ -578,7 +578,7 @@ public class UploadsStorageManager extends Observable { "==" + UploadResult.DELAYED_FOR_CHARGING.getValue() + " OR " + ProviderTableMeta.UPLOADS_LAST_RESULT + "==" + UploadResult.DELAYED_IN_POWER_SAVE_MODE.getValue() + - " AND " + ProviderTableMeta.UPLOADS_ACCOUNT_NAME + "== ?", + " ) AND " + ProviderTableMeta.UPLOADS_ACCOUNT_NAME + "== ?", accountName); } @@ -588,7 +588,7 @@ public class UploadsStorageManager extends Observable { * If afterId is -1, returns the first page */ public List getCurrentAndPendingUploadsForAccountPageAscById(final long afterId, final @NonNull String accountName) { - final String selection = ProviderTableMeta.UPLOADS_STATUS + "==" + UploadStatus.UPLOAD_IN_PROGRESS.value + + final String selection = "( " + ProviderTableMeta.UPLOADS_STATUS + "==" + UploadStatus.UPLOAD_IN_PROGRESS.value + " OR " + ProviderTableMeta.UPLOADS_LAST_RESULT + "==" + UploadResult.DELAYED_FOR_WIFI.getValue() + " OR " + ProviderTableMeta.UPLOADS_LAST_RESULT + @@ -597,7 +597,7 @@ public class UploadsStorageManager extends Observable { "==" + UploadResult.DELAYED_FOR_CHARGING.getValue() + " OR " + ProviderTableMeta.UPLOADS_LAST_RESULT + "==" + UploadResult.DELAYED_IN_POWER_SAVE_MODE.getValue() + - " AND " + ProviderTableMeta.UPLOADS_ACCOUNT_NAME + "== ?"; + " ) AND " + ProviderTableMeta.UPLOADS_ACCOUNT_NAME + "== ?"; return getUploadPage(afterId, false, selection, accountName); } From 36a6941ab38cc5a46aa84a2016013c30b9a91d7e Mon Sep 17 00:00:00 2001 From: Bhavesh Kumawat Date: Tue, 13 Feb 2024 15:40:14 +0530 Subject: [PATCH 05/31] making quota bar opaque --- app/src/main/res/layout/drawer.xml | 1 + 1 file changed, 1 insertion(+) diff --git a/app/src/main/res/layout/drawer.xml b/app/src/main/res/layout/drawer.xml index 14728bb813..306021a2f8 100644 --- a/app/src/main/res/layout/drawer.xml +++ b/app/src/main/res/layout/drawer.xml @@ -41,6 +41,7 @@ android:layout_gravity="bottom" android:clickable="false" android:orientation="vertical" + android:background="@color/appbar" android:paddingLeft="@dimen/drawer_content_horizontal_padding" android:paddingTop="@dimen/standard_half_padding" android:paddingRight="@dimen/drawer_content_horizontal_padding" From a7160f80d4dc78324617aaefb8fb278ccf3e269b Mon Sep 17 00:00:00 2001 From: Bhavesh Kumawat Date: Tue, 13 Feb 2024 15:41:27 +0530 Subject: [PATCH 06/31] adding one more dummy element --- app/src/main/res/menu/partial_drawer_entries.xml | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/app/src/main/res/menu/partial_drawer_entries.xml b/app/src/main/res/menu/partial_drawer_entries.xml index c7ee3868f1..b2e2b89fb0 100644 --- a/app/src/main/res/menu/partial_drawer_entries.xml +++ b/app/src/main/res/menu/partial_drawer_entries.xml @@ -127,4 +127,17 @@ android:orderInCategory="200" android:title=""/> + + + + + + From d1ce184192e05b96e0786feea42ed36f42ee6c62 Mon Sep 17 00:00:00 2001 From: Andy Scherzinger Date: Wed, 14 Feb 2024 09:39:48 +0100 Subject: [PATCH 07/31] Update screenshot Signed-off-by: Andy Scherzinger --- ...ploadListActivityActivityIT_openDrawer.png | Bin 30046 -> 30039 bytes 1 file changed, 0 insertions(+), 0 deletions(-) diff --git a/app/screenshots/gplay/debug/com.nextcloud.client.UploadListActivityActivityIT_openDrawer.png b/app/screenshots/gplay/debug/com.nextcloud.client.UploadListActivityActivityIT_openDrawer.png index 437678bd36dd9afb019c5624f302cc1e3caffa19..10d5bac2d7e3f55dbd3f0f8ec2964d9233a29d3e 100644 GIT binary patch literal 30039 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 L9u(et^7?-PlSXW5 literal 30046 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 Os`s_-A@4kT@xK86dBkx5 From c585023272c987b6ed10cf6edb76c5758a66293c Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Tue, 6 Feb 2024 03:10:05 +0000 Subject: [PATCH 08/31] Update dependency fastlane to v2.219.0 --- Gemfile.lock | 110 ++++++++++++++++++++++++--------------------------- 1 file changed, 51 insertions(+), 59 deletions(-) diff --git a/Gemfile.lock b/Gemfile.lock index 932f0648d0..836067fe7a 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -1,27 +1,27 @@ GEM remote: https://rubygems.org/ specs: - CFPropertyList (3.0.5) + CFPropertyList (3.0.6) rexml - addressable (2.8.0) - public_suffix (>= 2.0.2, < 5.0) + addressable (2.8.6) + public_suffix (>= 2.0.2, < 6.0) artifactory (3.0.15) atomos (0.1.3) - aws-eventstream (1.2.0) - aws-partitions (1.604.0) - aws-sdk-core (3.131.2) - aws-eventstream (~> 1, >= 1.0.2) - aws-partitions (~> 1, >= 1.525.0) - aws-sigv4 (~> 1.1) + aws-eventstream (1.3.0) + aws-partitions (1.887.0) + aws-sdk-core (3.191.0) + aws-eventstream (~> 1, >= 1.3.0) + aws-partitions (~> 1, >= 1.651.0) + aws-sigv4 (~> 1.8) jmespath (~> 1, >= 1.6.1) - aws-sdk-kms (1.57.0) - aws-sdk-core (~> 3, >= 3.127.0) + aws-sdk-kms (1.77.0) + aws-sdk-core (~> 3, >= 3.191.0) aws-sigv4 (~> 1.1) - aws-sdk-s3 (1.114.0) - aws-sdk-core (~> 3, >= 3.127.0) + aws-sdk-s3 (1.143.0) + aws-sdk-core (~> 3, >= 3.191.0) aws-sdk-kms (~> 1) - aws-sigv4 (~> 1.4) - aws-sigv4 (1.5.0) + aws-sigv4 (~> 1.8) + aws-sigv4 (1.8.0) aws-eventstream (~> 1, >= 1.0.2) babosa (1.0.4) claide (1.1.0) @@ -30,14 +30,13 @@ GEM commander (4.6.0) highline (~> 2.0.0) declarative (0.0.20) - digest-crc (0.6.4) + digest-crc (0.6.5) rake (>= 12.0.0, < 14.0.0) - domain_name (0.5.20190701) - unf (>= 0.0.5, < 1.0.0) - dotenv (2.7.6) + domain_name (0.6.20240107) + dotenv (2.8.1) emoji_regex (3.2.3) - excon (0.92.3) - faraday (1.10.0) + excon (0.109.0) + faraday (1.10.3) faraday-em_http (~> 1.0) faraday-em_synchrony (~> 1.0) faraday-excon (~> 1.1) @@ -65,8 +64,8 @@ GEM faraday-retry (1.0.3) faraday_middleware (1.2.0) faraday (~> 1.0) - fastimage (2.2.6) - fastlane (2.207.0) + fastimage (2.3.0) + fastlane (2.214.0) CFPropertyList (>= 2.3, < 4.0.0) addressable (>= 2.8, < 3.0.0) artifactory (~> 3.0) @@ -90,7 +89,7 @@ GEM json (< 3.0.0) jwt (>= 2.1.0, < 3) mini_magick (>= 4.9.4, < 5.0.0) - multipart-post (~> 2.0.0) + multipart-post (>= 2.0.0, < 3.0.0) naturally (~> 2.2) optparse (~> 0.1.1) plist (>= 3.1.0, < 4.0.0) @@ -107,9 +106,9 @@ GEM xcpretty-travis-formatter (>= 0.0.3) fastlane-plugin-huawei_appgallery_connect (1.0.23) gh_inspector (1.1.3) - google-apis-androidpublisher_v3 (0.25.0) - google-apis-core (>= 0.7, < 2.a) - google-apis-core (0.7.0) + google-apis-androidpublisher_v3 (0.54.0) + google-apis-core (>= 0.11.0, < 2.a) + google-apis-core (0.11.3) addressable (~> 2.5, >= 2.5.1) googleauth (>= 0.16.2, < 2.a) httpclient (>= 2.8.1, < 3.a) @@ -117,31 +116,29 @@ GEM representable (~> 3.0) retriable (>= 2.0, < 4.a) rexml - webrick - google-apis-iamcredentials_v1 (0.13.0) - google-apis-core (>= 0.7, < 2.a) - google-apis-playcustomapp_v1 (0.10.0) - google-apis-core (>= 0.7, < 2.a) - google-apis-storage_v1 (0.18.0) - google-apis-core (>= 0.7, < 2.a) - google-cloud-core (1.6.0) - google-cloud-env (~> 1.0) + google-apis-iamcredentials_v1 (0.17.0) + google-apis-core (>= 0.11.0, < 2.a) + google-apis-playcustomapp_v1 (0.13.0) + google-apis-core (>= 0.11.0, < 2.a) + google-apis-storage_v1 (0.31.0) + google-apis-core (>= 0.11.0, < 2.a) + google-cloud-core (1.6.1) + google-cloud-env (>= 1.0, < 3.a) google-cloud-errors (~> 1.0) google-cloud-env (1.6.0) faraday (>= 0.17.3, < 3.0) - google-cloud-errors (1.2.0) - google-cloud-storage (1.37.0) + google-cloud-errors (1.3.1) + google-cloud-storage (1.47.0) addressable (~> 2.8) digest-crc (~> 0.4) google-apis-iamcredentials_v1 (~> 0.1) - google-apis-storage_v1 (~> 0.1) + google-apis-storage_v1 (~> 0.31.0) google-cloud-core (~> 1.6) googleauth (>= 0.16.2, < 2.a) mini_mime (~> 1.0) - googleauth (1.2.0) + googleauth (1.8.1) faraday (>= 0.17.3, < 3.a) jwt (>= 1.4, < 3.0) - memoist (~> 0.16) multi_json (~> 1.11) os (>= 0.9, < 2.0) signet (>= 0.16, < 2.a) @@ -149,37 +146,36 @@ GEM http-cookie (1.0.5) domain_name (~> 0.5) httpclient (2.8.3) - jmespath (1.6.1) - json (2.6.2) - jwt (2.4.1) - memoist (0.16.2) - mini_magick (4.11.0) - mini_mime (1.1.2) + jmespath (1.6.2) + json (2.7.1) + jwt (2.7.1) + mini_magick (4.12.0) + mini_mime (1.1.5) multi_json (1.15.0) - multipart-post (2.0.0) + multipart-post (2.3.0) nanaimo (0.3.0) naturally (2.2.1) optparse (0.1.1) os (1.1.4) - plist (3.6.0) + plist (3.7.1) public_suffix (4.0.7) - rake (13.0.6) + rake (13.1.0) representable (3.2.0) declarative (< 0.1.0) trailblazer-option (>= 0.1.1, < 0.2.0) uber (< 0.2.0) retriable (3.1.2) - rexml (3.2.5) + rexml (3.2.6) rouge (2.0.7) ruby2_keywords (0.0.5) rubyzip (2.3.2) security (0.1.3) - signet (0.17.0) + signet (0.18.0) addressable (~> 2.8) faraday (>= 0.17.5, < 3.a) jwt (>= 1.5, < 3.0) multi_json (~> 1.10) - simctl (1.6.8) + simctl (1.6.10) CFPropertyList naturally terminal-notifier (2.0.0) @@ -187,17 +183,13 @@ GEM unicode-display_width (~> 1.1, >= 1.1.1) trailblazer-option (0.1.2) tty-cursor (0.7.1) - tty-screen (0.8.1) + tty-screen (0.8.2) tty-spinner (0.9.3) tty-cursor (~> 0.7) uber (0.1.0) - unf (0.1.4) - unf_ext - unf_ext (0.0.8.2) unicode-display_width (1.8.0) - webrick (1.7.0) word_wrap (1.0.0) - xcodeproj (1.22.0) + xcodeproj (1.24.0) CFPropertyList (>= 2.3.3, < 4.0) atomos (~> 0.1.3) claide (>= 1.0.2, < 2.0) From 573e9d6580c2f76dad8692d9f0402e847c456bf0 Mon Sep 17 00:00:00 2001 From: alperozturk Date: Tue, 13 Feb 2024 15:05:49 +0100 Subject: [PATCH 09/31] Check ClassCastException edge, nullability of bundle or intent Signed-off-by: alperozturk --- .../utils/extensions/BundleExtensions.kt | 47 ++++++++++++++----- .../utils/extensions/IntentExtensions.kt | 45 +++++++++++++----- 2 files changed, 68 insertions(+), 24 deletions(-) diff --git a/app/src/main/java/com/nextcloud/utils/extensions/BundleExtensions.kt b/app/src/main/java/com/nextcloud/utils/extensions/BundleExtensions.kt index 18ded1895a..abfa1cd895 100644 --- a/app/src/main/java/com/nextcloud/utils/extensions/BundleExtensions.kt +++ b/app/src/main/java/com/nextcloud/utils/extensions/BundleExtensions.kt @@ -24,22 +24,45 @@ package com.nextcloud.utils.extensions import android.os.Build import android.os.Bundle import android.os.Parcelable +import com.owncloud.android.lib.common.utils.Log_OC +import org.apache.commons.logging.Log import java.io.Serializable -fun Bundle.getSerializableArgument(key: String, type: Class): T? { - return if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) { - this.getSerializable(key, type) - } else { - @Suppress("UNCHECKED_CAST", "DEPRECATION") - this.getSerializable(key) as T +private const val tag = "BundleExtension" + +fun Bundle?.getSerializableArgument(key: String, type: Class): T? { + if (this == null) { + return null + } + + return try { + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) { + this.getSerializable(key, type) + } else { + @Suppress("UNCHECKED_CAST", "DEPRECATION") + this.getSerializable(key) as T + } + } catch (e: ClassCastException) { + Log_OC.e(tag, e.localizedMessage) + null } } -fun Bundle.getParcelableArgument(key: String, type: Class): T? { - return if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) { - this.getParcelable(key, type) - } else { - @Suppress("DEPRECATION") - this.getParcelable(key) +fun Bundle?.getParcelableArgument(key: String, type: Class): T? { + if (this == null) { + return null + } + + return try { + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) { + this.getParcelable(key, type) + } else { + @Suppress("DEPRECATION") + this.getParcelable(key) + } + } catch (e: ClassCastException) { + Log_OC.e(tag, e.localizedMessage) + e.printStackTrace() + null } } diff --git a/app/src/main/java/com/nextcloud/utils/extensions/IntentExtensions.kt b/app/src/main/java/com/nextcloud/utils/extensions/IntentExtensions.kt index 493c388db6..f830cfa489 100644 --- a/app/src/main/java/com/nextcloud/utils/extensions/IntentExtensions.kt +++ b/app/src/main/java/com/nextcloud/utils/extensions/IntentExtensions.kt @@ -24,22 +24,43 @@ package com.nextcloud.utils.extensions import android.content.Intent import android.os.Build import android.os.Parcelable +import com.owncloud.android.lib.common.utils.Log_OC import java.io.Serializable -fun Intent.getSerializableArgument(key: String, type: Class): T? { - return if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) { - this.getSerializableExtra(key, type) - } else { - @Suppress("UNCHECKED_CAST", "DEPRECATION") - this.getSerializableExtra(key) as T +private const val tag = "IntentExtension" + +fun Intent?.getSerializableArgument(key: String, type: Class): T? { + if (this == null) { + return null + } + + return try { + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) { + this.getSerializableExtra(key, type) + } else { + @Suppress("UNCHECKED_CAST", "DEPRECATION") + this.getSerializableExtra(key) as T + } + } catch (e: ClassCastException) { + Log_OC.e(tag, e.localizedMessage) + null } } -fun Intent.getParcelableArgument(key: String, type: Class): T? { - return if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) { - this.getParcelableExtra(key, type) - } else { - @Suppress("DEPRECATION") - this.getParcelableExtra(key) +fun Intent?.getParcelableArgument(key: String, type: Class): T? { + if (this == null) { + return null + } + + return try { + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) { + this.getParcelableExtra(key, type) + } else { + @Suppress("DEPRECATION") + this.getParcelableExtra(key) + } + } catch (e: ClassCastException) { + Log_OC.e(tag, e.localizedMessage) + null } } From b78572140dc115fcee6820567c30dbdbf3bb44b1 Mon Sep 17 00:00:00 2001 From: alperozturk Date: Tue, 13 Feb 2024 15:22:40 +0100 Subject: [PATCH 10/31] Add BundleExtensionTest Signed-off-by: alperozturk --- .../extensions/BundleExtensionsTests.kt | 116 ++++++++++++++++++ 1 file changed, 116 insertions(+) create mode 100644 app/src/androidTest/java/com/nextcloud/extensions/BundleExtensionsTests.kt diff --git a/app/src/androidTest/java/com/nextcloud/extensions/BundleExtensionsTests.kt b/app/src/androidTest/java/com/nextcloud/extensions/BundleExtensionsTests.kt new file mode 100644 index 0000000000..e7214b4bd2 --- /dev/null +++ b/app/src/androidTest/java/com/nextcloud/extensions/BundleExtensionsTests.kt @@ -0,0 +1,116 @@ +/* + * Nextcloud Android client application + * + * @author Alper Ozturk + * Copyright (C) 2024 Alper Ozturk + * Copyright (C) 2024 Nextcloud GmbH + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + */ + +package com.nextcloud.extensions + +import android.os.Bundle +import android.os.Parcel +import android.os.Parcelable +import androidx.test.ext.junit.runners.AndroidJUnit4 +import com.nextcloud.utils.extensions.getParcelableArgument +import com.nextcloud.utils.extensions.getSerializableArgument +import kotlinx.parcelize.Parcelize +import org.junit.Assert.assertEquals +import org.junit.Assert.assertNull +import org.junit.Test +import org.junit.runner.RunWith +import java.io.Serializable + +@RunWith(AndroidJUnit4::class) +class BundleExtensionTest { + + private val key = "testDataKey" + + @Test + fun test_GetSerializableArgument_WhenGivenValidBundle_ShouldReturnExpectedData() { + val bundle = Bundle() + val testObject = TestData("Hello") + bundle.putSerializable(key, testObject) + val retrievedObject = bundle.getSerializableArgument(key, TestData::class.java) + assertEquals(testObject, retrievedObject) + } + + @Test + fun test_GetSerializableArgument_WhenGivenValidBundleAndWrongClassType_ShouldReturnNull() { + val bundle = Bundle() + val testObject = TestData("Hello") + bundle.putSerializable(key, testObject) + val retrievedObject = bundle.getSerializableArgument(key, Array::class.java) + assertNull(retrievedObject) + } + + @Test + fun test_GetParcelableArgument_WhenGivenValidBundleAndWrongClassType_ShouldReturnNull() { + val bundle = Bundle() + val testObject = TestData("Hello") + bundle.putSerializable(key, testObject) + val retrievedObject = bundle.getParcelableArgument(key, OtherTestData::class.java) + assertNull(retrievedObject) + } + + @Test + fun test_GetParcelableArgument_WhenGivenValidBundle_ShouldReturnExpectedData() { + val bundle = Bundle() + val testObject = TestDataParcelable("Hello") + bundle.putParcelable(key, testObject) + val retrievedObject = bundle.getParcelableArgument(key, TestDataParcelable::class.java) + assertEquals(testObject, retrievedObject) + } + + @Test + fun test_GetSerializableArgument_WhenGivenNullBundle_ShouldReturnNull() { + val retrievedObject = (null as Bundle?).getSerializableArgument(key, TestData::class.java) + assertNull(retrievedObject) + } + + @Test + fun test_GetParcelableArgument_WhenGivenNullBundle_ShouldReturnNull() { + val retrievedObject = (null as Bundle?).getParcelableArgument(key, TestDataParcelable::class.java) + assertNull(retrievedObject) + } + + @Parcelize + class OtherTestData : Parcelable + + data class TestData(val message: String) : Serializable + + data class TestDataParcelable(val message: String) : Parcelable { + constructor(parcel: Parcel) : this(parcel.readString() ?: "") + + override fun writeToParcel(parcel: Parcel, flags: Int) { + parcel.writeString(message) + } + + override fun describeContents(): Int { + return 0 + } + + companion object CREATOR : Parcelable.Creator { + override fun createFromParcel(parcel: Parcel): TestDataParcelable { + return TestDataParcelable(parcel) + } + + override fun newArray(size: Int): Array { + return arrayOfNulls(size) + } + } + } +} From 7f8be9130eddbfc25631d69e49420aa9f62560ef Mon Sep 17 00:00:00 2001 From: alperozturk Date: Tue, 13 Feb 2024 15:29:08 +0100 Subject: [PATCH 11/31] Add IntentExtensionTest Signed-off-by: alperozturk --- .../extensions/BundleExtensionsTests.kt | 34 +------ .../extensions/IntentExtensionsTests.kt | 88 +++++++++++++++++++ .../com/nextcloud/test/model/TestModels.kt | 54 ++++++++++++ .../utils/extensions/BundleExtensions.kt | 1 - 4 files changed, 145 insertions(+), 32 deletions(-) create mode 100644 app/src/androidTest/java/com/nextcloud/extensions/IntentExtensionsTests.kt create mode 100644 app/src/androidTest/java/com/nextcloud/test/model/TestModels.kt diff --git a/app/src/androidTest/java/com/nextcloud/extensions/BundleExtensionsTests.kt b/app/src/androidTest/java/com/nextcloud/extensions/BundleExtensionsTests.kt index e7214b4bd2..18e850d38b 100644 --- a/app/src/androidTest/java/com/nextcloud/extensions/BundleExtensionsTests.kt +++ b/app/src/androidTest/java/com/nextcloud/extensions/BundleExtensionsTests.kt @@ -22,17 +22,16 @@ package com.nextcloud.extensions import android.os.Bundle -import android.os.Parcel -import android.os.Parcelable import androidx.test.ext.junit.runners.AndroidJUnit4 +import com.nextcloud.test.model.OtherTestData +import com.nextcloud.test.model.TestData +import com.nextcloud.test.model.TestDataParcelable import com.nextcloud.utils.extensions.getParcelableArgument import com.nextcloud.utils.extensions.getSerializableArgument -import kotlinx.parcelize.Parcelize import org.junit.Assert.assertEquals import org.junit.Assert.assertNull import org.junit.Test import org.junit.runner.RunWith -import java.io.Serializable @RunWith(AndroidJUnit4::class) class BundleExtensionTest { @@ -86,31 +85,4 @@ class BundleExtensionTest { val retrievedObject = (null as Bundle?).getParcelableArgument(key, TestDataParcelable::class.java) assertNull(retrievedObject) } - - @Parcelize - class OtherTestData : Parcelable - - data class TestData(val message: String) : Serializable - - data class TestDataParcelable(val message: String) : Parcelable { - constructor(parcel: Parcel) : this(parcel.readString() ?: "") - - override fun writeToParcel(parcel: Parcel, flags: Int) { - parcel.writeString(message) - } - - override fun describeContents(): Int { - return 0 - } - - companion object CREATOR : Parcelable.Creator { - override fun createFromParcel(parcel: Parcel): TestDataParcelable { - return TestDataParcelable(parcel) - } - - override fun newArray(size: Int): Array { - return arrayOfNulls(size) - } - } - } } diff --git a/app/src/androidTest/java/com/nextcloud/extensions/IntentExtensionsTests.kt b/app/src/androidTest/java/com/nextcloud/extensions/IntentExtensionsTests.kt new file mode 100644 index 0000000000..29ab7e91c2 --- /dev/null +++ b/app/src/androidTest/java/com/nextcloud/extensions/IntentExtensionsTests.kt @@ -0,0 +1,88 @@ +/* + * Nextcloud Android client application + * + * @author Alper Ozturk + * Copyright (C) 2024 Alper Ozturk + * Copyright (C) 2024 Nextcloud GmbH + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + */ + +package com.nextcloud.extensions + +import android.content.Intent +import androidx.test.ext.junit.runners.AndroidJUnit4 +import com.nextcloud.test.model.OtherTestData +import com.nextcloud.test.model.TestData +import com.nextcloud.test.model.TestDataParcelable +import com.nextcloud.utils.extensions.getParcelableArgument +import com.nextcloud.utils.extensions.getSerializableArgument +import org.junit.Assert.assertEquals +import org.junit.Assert.assertNull +import org.junit.Test +import org.junit.runner.RunWith + +@RunWith(AndroidJUnit4::class) +class IntentExtensionTest { + + private val key = "testDataKey" + + @Test + fun test_GetSerializableArgument_WhenGivenValidIntent_ShouldReturnExpectedData() { + val intent = Intent() + val testObject = TestData("Hello") + intent.putExtra(key, testObject) + val retrievedObject = intent.getSerializableArgument(key, TestData::class.java) + assertEquals(testObject, retrievedObject) + } + + @Test + fun test_GetSerializableArgument_WhenGivenValidIntentAndWrongClassType_ShouldReturnNull() { + val intent = Intent() + val testObject = TestData("Hello") + intent.putExtra(key, testObject) + val retrievedObject = intent.getSerializableArgument(key, Array::class.java) + assertNull(retrievedObject) + } + + @Test + fun test_GetParcelableArgument_WhenGivenValidIntentAndWrongClassType_ShouldReturnNull() { + val intent = Intent() + val testObject = TestData("Hello") + intent.putExtra(key, testObject) + val retrievedObject = intent.getParcelableArgument(key, OtherTestData::class.java) + assertNull(retrievedObject) + } + + @Test + fun test_GetParcelableArgument_WhenGivenValidIntent_ShouldReturnExpectedData() { + val intent = Intent() + val testObject = TestDataParcelable("Hello") + intent.putExtra(key, testObject) + val retrievedObject = intent.getParcelableArgument(key, TestDataParcelable::class.java) + assertEquals(testObject, retrievedObject) + } + + @Test + fun test_GetSerializableArgument_WhenGivenNullIntent_ShouldReturnNull() { + val retrievedObject = (null as Intent?).getSerializableArgument(key, TestData::class.java) + assertNull(retrievedObject) + } + + @Test + fun test_GetParcelableArgument_WhenGivenNullIntent_ShouldReturnNull() { + val retrievedObject = (null as Intent?).getParcelableArgument(key, TestDataParcelable::class.java) + assertNull(retrievedObject) + } +} diff --git a/app/src/androidTest/java/com/nextcloud/test/model/TestModels.kt b/app/src/androidTest/java/com/nextcloud/test/model/TestModels.kt new file mode 100644 index 0000000000..e735c16f31 --- /dev/null +++ b/app/src/androidTest/java/com/nextcloud/test/model/TestModels.kt @@ -0,0 +1,54 @@ +/* + * Nextcloud Android client application + * + * @author Alper Ozturk + * Copyright (C) 2024 Alper Ozturk + * Copyright (C) 2024 Nextcloud GmbH + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + */ + +package com.nextcloud.test.model + +import android.os.Parcel +import android.os.Parcelable +import kotlinx.parcelize.Parcelize +import java.io.Serializable + +@Parcelize +class OtherTestData : Parcelable + +data class TestData(val message: String) : Serializable + +data class TestDataParcelable(val message: String) : Parcelable { + constructor(parcel: Parcel) : this(parcel.readString() ?: "") + + override fun writeToParcel(parcel: Parcel, flags: Int) { + parcel.writeString(message) + } + + override fun describeContents(): Int { + return 0 + } + + companion object CREATOR : Parcelable.Creator { + override fun createFromParcel(parcel: Parcel): TestDataParcelable { + return TestDataParcelable(parcel) + } + + override fun newArray(size: Int): Array { + return arrayOfNulls(size) + } + } +} diff --git a/app/src/main/java/com/nextcloud/utils/extensions/BundleExtensions.kt b/app/src/main/java/com/nextcloud/utils/extensions/BundleExtensions.kt index abfa1cd895..bcfe440f45 100644 --- a/app/src/main/java/com/nextcloud/utils/extensions/BundleExtensions.kt +++ b/app/src/main/java/com/nextcloud/utils/extensions/BundleExtensions.kt @@ -25,7 +25,6 @@ import android.os.Build import android.os.Bundle import android.os.Parcelable import com.owncloud.android.lib.common.utils.Log_OC -import org.apache.commons.logging.Log import java.io.Serializable private const val tag = "BundleExtension" From 9419d6cf09a904f6b6016c22d1abaa23374d8298 Mon Sep 17 00:00:00 2001 From: alperozturk Date: Tue, 13 Feb 2024 15:32:59 +0100 Subject: [PATCH 12/31] Fix code analytics Signed-off-by: alperozturk --- ...undleExtensionsTests.kt => BundleExtensionTests.kt} | 4 ++-- ...ntentExtensionsTests.kt => IntentExtensionTests.kt} | 10 +++++----- .../com/nextcloud/utils/extensions/BundleExtensions.kt | 1 + .../com/nextcloud/utils/extensions/IntentExtensions.kt | 1 + 4 files changed, 9 insertions(+), 7 deletions(-) rename app/src/androidTest/java/com/nextcloud/extensions/{BundleExtensionsTests.kt => BundleExtensionTests.kt} (99%) rename app/src/androidTest/java/com/nextcloud/extensions/{IntentExtensionsTests.kt => IntentExtensionTests.kt} (98%) diff --git a/app/src/androidTest/java/com/nextcloud/extensions/BundleExtensionsTests.kt b/app/src/androidTest/java/com/nextcloud/extensions/BundleExtensionTests.kt similarity index 99% rename from app/src/androidTest/java/com/nextcloud/extensions/BundleExtensionsTests.kt rename to app/src/androidTest/java/com/nextcloud/extensions/BundleExtensionTests.kt index 18e850d38b..26e5ac2962 100644 --- a/app/src/androidTest/java/com/nextcloud/extensions/BundleExtensionsTests.kt +++ b/app/src/androidTest/java/com/nextcloud/extensions/BundleExtensionTests.kt @@ -34,8 +34,8 @@ import org.junit.Test import org.junit.runner.RunWith @RunWith(AndroidJUnit4::class) -class BundleExtensionTest { - +class BundleExtensionTests { + private val key = "testDataKey" @Test diff --git a/app/src/androidTest/java/com/nextcloud/extensions/IntentExtensionsTests.kt b/app/src/androidTest/java/com/nextcloud/extensions/IntentExtensionTests.kt similarity index 98% rename from app/src/androidTest/java/com/nextcloud/extensions/IntentExtensionsTests.kt rename to app/src/androidTest/java/com/nextcloud/extensions/IntentExtensionTests.kt index 29ab7e91c2..37a98b1d2b 100644 --- a/app/src/androidTest/java/com/nextcloud/extensions/IntentExtensionsTests.kt +++ b/app/src/androidTest/java/com/nextcloud/extensions/IntentExtensionTests.kt @@ -1,20 +1,20 @@ /* * Nextcloud Android client application - * + * * @author Alper Ozturk * Copyright (C) 2024 Alper Ozturk * Copyright (C) 2024 Nextcloud GmbH - * + * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. - * + * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Affero General Public License for more details. - * + * * You should have received a copy of the GNU Affero General Public License * along with this program. If not, see . */ @@ -34,7 +34,7 @@ import org.junit.Test import org.junit.runner.RunWith @RunWith(AndroidJUnit4::class) -class IntentExtensionTest { +class IntentExtensionTests { private val key = "testDataKey" diff --git a/app/src/main/java/com/nextcloud/utils/extensions/BundleExtensions.kt b/app/src/main/java/com/nextcloud/utils/extensions/BundleExtensions.kt index bcfe440f45..7b4c471738 100644 --- a/app/src/main/java/com/nextcloud/utils/extensions/BundleExtensions.kt +++ b/app/src/main/java/com/nextcloud/utils/extensions/BundleExtensions.kt @@ -27,6 +27,7 @@ import android.os.Parcelable import com.owncloud.android.lib.common.utils.Log_OC import java.io.Serializable +@Suppress("TopLevelPropertyNaming") private const val tag = "BundleExtension" fun Bundle?.getSerializableArgument(key: String, type: Class): T? { diff --git a/app/src/main/java/com/nextcloud/utils/extensions/IntentExtensions.kt b/app/src/main/java/com/nextcloud/utils/extensions/IntentExtensions.kt index f830cfa489..f52ddeffb5 100644 --- a/app/src/main/java/com/nextcloud/utils/extensions/IntentExtensions.kt +++ b/app/src/main/java/com/nextcloud/utils/extensions/IntentExtensions.kt @@ -27,6 +27,7 @@ import android.os.Parcelable import com.owncloud.android.lib.common.utils.Log_OC import java.io.Serializable +@Suppress("TopLevelPropertyNaming") private const val tag = "IntentExtension" fun Intent?.getSerializableArgument(key: String, type: Class): T? { From 3ed94101e83c12d9795ba922173de7fff5a9bd61 Mon Sep 17 00:00:00 2001 From: alperozturk Date: Tue, 13 Feb 2024 15:49:10 +0100 Subject: [PATCH 13/31] Rename test functions Signed-off-by: alperozturk --- .../com/nextcloud/extensions/BundleExtensionTests.kt | 12 ++++++------ .../com/nextcloud/extensions/IntentExtensionTests.kt | 12 ++++++------ 2 files changed, 12 insertions(+), 12 deletions(-) diff --git a/app/src/androidTest/java/com/nextcloud/extensions/BundleExtensionTests.kt b/app/src/androidTest/java/com/nextcloud/extensions/BundleExtensionTests.kt index 26e5ac2962..8543031f98 100644 --- a/app/src/androidTest/java/com/nextcloud/extensions/BundleExtensionTests.kt +++ b/app/src/androidTest/java/com/nextcloud/extensions/BundleExtensionTests.kt @@ -39,7 +39,7 @@ class BundleExtensionTests { private val key = "testDataKey" @Test - fun test_GetSerializableArgument_WhenGivenValidBundle_ShouldReturnExpectedData() { + fun test_get_serializable_argument_when_given_valid_bundle_should_return_expected_data() { val bundle = Bundle() val testObject = TestData("Hello") bundle.putSerializable(key, testObject) @@ -48,7 +48,7 @@ class BundleExtensionTests { } @Test - fun test_GetSerializableArgument_WhenGivenValidBundleAndWrongClassType_ShouldReturnNull() { + fun test_get_serializable_argument_when_given_valid_bundle_and_wrong_class_type_should_return_null() { val bundle = Bundle() val testObject = TestData("Hello") bundle.putSerializable(key, testObject) @@ -57,7 +57,7 @@ class BundleExtensionTests { } @Test - fun test_GetParcelableArgument_WhenGivenValidBundleAndWrongClassType_ShouldReturnNull() { + fun test_get_parcelable_argument_when_given_valid_bundle_and_wrong_class_type_should_return_null() { val bundle = Bundle() val testObject = TestData("Hello") bundle.putSerializable(key, testObject) @@ -66,7 +66,7 @@ class BundleExtensionTests { } @Test - fun test_GetParcelableArgument_WhenGivenValidBundle_ShouldReturnExpectedData() { + fun test_get_parcelable_argument_when_given_valid_bundle_should_return_expected_data() { val bundle = Bundle() val testObject = TestDataParcelable("Hello") bundle.putParcelable(key, testObject) @@ -75,13 +75,13 @@ class BundleExtensionTests { } @Test - fun test_GetSerializableArgument_WhenGivenNullBundle_ShouldReturnNull() { + fun test_get_serializable_argument_when_given_null_bundle_should_return_null() { val retrievedObject = (null as Bundle?).getSerializableArgument(key, TestData::class.java) assertNull(retrievedObject) } @Test - fun test_GetParcelableArgument_WhenGivenNullBundle_ShouldReturnNull() { + fun test_get_parcelable_argument_when_given_null_bundle_should_return_null() { val retrievedObject = (null as Bundle?).getParcelableArgument(key, TestDataParcelable::class.java) assertNull(retrievedObject) } diff --git a/app/src/androidTest/java/com/nextcloud/extensions/IntentExtensionTests.kt b/app/src/androidTest/java/com/nextcloud/extensions/IntentExtensionTests.kt index 37a98b1d2b..f81640ab8e 100644 --- a/app/src/androidTest/java/com/nextcloud/extensions/IntentExtensionTests.kt +++ b/app/src/androidTest/java/com/nextcloud/extensions/IntentExtensionTests.kt @@ -39,7 +39,7 @@ class IntentExtensionTests { private val key = "testDataKey" @Test - fun test_GetSerializableArgument_WhenGivenValidIntent_ShouldReturnExpectedData() { + fun test_get_serializable_argument_when_given_valid_intent_should_return_expected_data() { val intent = Intent() val testObject = TestData("Hello") intent.putExtra(key, testObject) @@ -48,7 +48,7 @@ class IntentExtensionTests { } @Test - fun test_GetSerializableArgument_WhenGivenValidIntentAndWrongClassType_ShouldReturnNull() { + fun test_get_serializable_argument_when_given_valid_intent_and_wrong_class_type_should_return_null() { val intent = Intent() val testObject = TestData("Hello") intent.putExtra(key, testObject) @@ -57,7 +57,7 @@ class IntentExtensionTests { } @Test - fun test_GetParcelableArgument_WhenGivenValidIntentAndWrongClassType_ShouldReturnNull() { + fun test_get_parcelable_argument_when_given_valid_intent_and_wrong_class_type_should_return_null() { val intent = Intent() val testObject = TestData("Hello") intent.putExtra(key, testObject) @@ -66,7 +66,7 @@ class IntentExtensionTests { } @Test - fun test_GetParcelableArgument_WhenGivenValidIntent_ShouldReturnExpectedData() { + fun test_get_parcelable_argument_when_given_valid_intent_should_return_expected_data() { val intent = Intent() val testObject = TestDataParcelable("Hello") intent.putExtra(key, testObject) @@ -75,13 +75,13 @@ class IntentExtensionTests { } @Test - fun test_GetSerializableArgument_WhenGivenNullIntent_ShouldReturnNull() { + fun test_get_serializable_argument_when_given_null_intent_should_return_null() { val retrievedObject = (null as Intent?).getSerializableArgument(key, TestData::class.java) assertNull(retrievedObject) } @Test - fun test_GetParcelableArgument_WhenGivenNullIntent_ShouldReturnNull() { + fun test_get_parcelable_argument_when_given_null_intent_should_return_null() { val retrievedObject = (null as Intent?).getParcelableArgument(key, TestDataParcelable::class.java) assertNull(retrievedObject) } From 43ec7f9e69064fdbef3b7098f85b05eefd3f01fc Mon Sep 17 00:00:00 2001 From: alperozturk Date: Tue, 13 Feb 2024 16:00:21 +0100 Subject: [PATCH 14/31] Ignore test functions Signed-off-by: alperozturk --- .../java/com/nextcloud/extensions/BundleExtensionTests.kt | 1 + .../java/com/nextcloud/extensions/IntentExtensionTests.kt | 1 + 2 files changed, 2 insertions(+) diff --git a/app/src/androidTest/java/com/nextcloud/extensions/BundleExtensionTests.kt b/app/src/androidTest/java/com/nextcloud/extensions/BundleExtensionTests.kt index 8543031f98..f59aa377ce 100644 --- a/app/src/androidTest/java/com/nextcloud/extensions/BundleExtensionTests.kt +++ b/app/src/androidTest/java/com/nextcloud/extensions/BundleExtensionTests.kt @@ -33,6 +33,7 @@ import org.junit.Assert.assertNull import org.junit.Test import org.junit.runner.RunWith +@Suppress("FunctionNaming") @RunWith(AndroidJUnit4::class) class BundleExtensionTests { diff --git a/app/src/androidTest/java/com/nextcloud/extensions/IntentExtensionTests.kt b/app/src/androidTest/java/com/nextcloud/extensions/IntentExtensionTests.kt index f81640ab8e..0b7a29919b 100644 --- a/app/src/androidTest/java/com/nextcloud/extensions/IntentExtensionTests.kt +++ b/app/src/androidTest/java/com/nextcloud/extensions/IntentExtensionTests.kt @@ -33,6 +33,7 @@ import org.junit.Assert.assertNull import org.junit.Test import org.junit.runner.RunWith +@Suppress("FunctionNaming") @RunWith(AndroidJUnit4::class) class IntentExtensionTests { From aa6ca04c0c5e8e0def304e7cc94942ca6d223565 Mon Sep 17 00:00:00 2001 From: alperozturk Date: Tue, 13 Feb 2024 16:40:30 +0100 Subject: [PATCH 15/31] Wrong class type will only test with min Android Q Signed-off-by: alperozturk --- .../java/com/nextcloud/extensions/BundleExtensionTests.kt | 3 +++ .../java/com/nextcloud/extensions/IntentExtensionTests.kt | 3 +++ 2 files changed, 6 insertions(+) diff --git a/app/src/androidTest/java/com/nextcloud/extensions/BundleExtensionTests.kt b/app/src/androidTest/java/com/nextcloud/extensions/BundleExtensionTests.kt index f59aa377ce..d838a68e70 100644 --- a/app/src/androidTest/java/com/nextcloud/extensions/BundleExtensionTests.kt +++ b/app/src/androidTest/java/com/nextcloud/extensions/BundleExtensionTests.kt @@ -21,8 +21,10 @@ package com.nextcloud.extensions +import android.os.Build import android.os.Bundle import androidx.test.ext.junit.runners.AndroidJUnit4 +import androidx.test.filters.SdkSuppress import com.nextcloud.test.model.OtherTestData import com.nextcloud.test.model.TestData import com.nextcloud.test.model.TestDataParcelable @@ -48,6 +50,7 @@ class BundleExtensionTests { assertEquals(testObject, retrievedObject) } + @SdkSuppress(minSdkVersion = Build.VERSION_CODES.Q) @Test fun test_get_serializable_argument_when_given_valid_bundle_and_wrong_class_type_should_return_null() { val bundle = Bundle() diff --git a/app/src/androidTest/java/com/nextcloud/extensions/IntentExtensionTests.kt b/app/src/androidTest/java/com/nextcloud/extensions/IntentExtensionTests.kt index 0b7a29919b..6d587b2114 100644 --- a/app/src/androidTest/java/com/nextcloud/extensions/IntentExtensionTests.kt +++ b/app/src/androidTest/java/com/nextcloud/extensions/IntentExtensionTests.kt @@ -22,7 +22,9 @@ package com.nextcloud.extensions import android.content.Intent +import android.os.Build import androidx.test.ext.junit.runners.AndroidJUnit4 +import androidx.test.filters.SdkSuppress import com.nextcloud.test.model.OtherTestData import com.nextcloud.test.model.TestData import com.nextcloud.test.model.TestDataParcelable @@ -48,6 +50,7 @@ class IntentExtensionTests { assertEquals(testObject, retrievedObject) } + @SdkSuppress(minSdkVersion = Build.VERSION_CODES.Q) @Test fun test_get_serializable_argument_when_given_valid_intent_and_wrong_class_type_should_return_null() { val intent = Intent() From 09baaa6e1b9de0927536b125bac0d364c090f7b1 Mon Sep 17 00:00:00 2001 From: alperozturk Date: Tue, 13 Feb 2024 16:42:22 +0100 Subject: [PATCH 16/31] Revert changes Signed-off-by: alperozturk --- .../java/com/nextcloud/extensions/BundleExtensionTests.kt | 3 --- .../java/com/nextcloud/extensions/IntentExtensionTests.kt | 3 --- 2 files changed, 6 deletions(-) diff --git a/app/src/androidTest/java/com/nextcloud/extensions/BundleExtensionTests.kt b/app/src/androidTest/java/com/nextcloud/extensions/BundleExtensionTests.kt index d838a68e70..f59aa377ce 100644 --- a/app/src/androidTest/java/com/nextcloud/extensions/BundleExtensionTests.kt +++ b/app/src/androidTest/java/com/nextcloud/extensions/BundleExtensionTests.kt @@ -21,10 +21,8 @@ package com.nextcloud.extensions -import android.os.Build import android.os.Bundle import androidx.test.ext.junit.runners.AndroidJUnit4 -import androidx.test.filters.SdkSuppress import com.nextcloud.test.model.OtherTestData import com.nextcloud.test.model.TestData import com.nextcloud.test.model.TestDataParcelable @@ -50,7 +48,6 @@ class BundleExtensionTests { assertEquals(testObject, retrievedObject) } - @SdkSuppress(minSdkVersion = Build.VERSION_CODES.Q) @Test fun test_get_serializable_argument_when_given_valid_bundle_and_wrong_class_type_should_return_null() { val bundle = Bundle() diff --git a/app/src/androidTest/java/com/nextcloud/extensions/IntentExtensionTests.kt b/app/src/androidTest/java/com/nextcloud/extensions/IntentExtensionTests.kt index 6d587b2114..0b7a29919b 100644 --- a/app/src/androidTest/java/com/nextcloud/extensions/IntentExtensionTests.kt +++ b/app/src/androidTest/java/com/nextcloud/extensions/IntentExtensionTests.kt @@ -22,9 +22,7 @@ package com.nextcloud.extensions import android.content.Intent -import android.os.Build import androidx.test.ext.junit.runners.AndroidJUnit4 -import androidx.test.filters.SdkSuppress import com.nextcloud.test.model.OtherTestData import com.nextcloud.test.model.TestData import com.nextcloud.test.model.TestDataParcelable @@ -50,7 +48,6 @@ class IntentExtensionTests { assertEquals(testObject, retrievedObject) } - @SdkSuppress(minSdkVersion = Build.VERSION_CODES.Q) @Test fun test_get_serializable_argument_when_given_valid_intent_and_wrong_class_type_should_return_null() { val intent = Intent() From cd54581320bd0ae410951aae6fb551c3a5284638 Mon Sep 17 00:00:00 2001 From: alperozturk Date: Wed, 14 Feb 2024 09:57:04 +0100 Subject: [PATCH 17/31] Fix tests Signed-off-by: alperozturk --- .../java/com/nextcloud/utils/extensions/BundleExtensions.kt | 6 +++++- .../java/com/nextcloud/utils/extensions/IntentExtensions.kt | 6 +++++- 2 files changed, 10 insertions(+), 2 deletions(-) diff --git a/app/src/main/java/com/nextcloud/utils/extensions/BundleExtensions.kt b/app/src/main/java/com/nextcloud/utils/extensions/BundleExtensions.kt index 7b4c471738..67e86f3ea6 100644 --- a/app/src/main/java/com/nextcloud/utils/extensions/BundleExtensions.kt +++ b/app/src/main/java/com/nextcloud/utils/extensions/BundleExtensions.kt @@ -40,7 +40,11 @@ fun Bundle?.getSerializableArgument(key: String, type: Class this.getSerializable(key, type) } else { @Suppress("UNCHECKED_CAST", "DEPRECATION") - this.getSerializable(key) as T + if (type.isInstance(this.getSerializable(key))) { + this.getSerializable(key) as T + } else { + null + } } } catch (e: ClassCastException) { Log_OC.e(tag, e.localizedMessage) diff --git a/app/src/main/java/com/nextcloud/utils/extensions/IntentExtensions.kt b/app/src/main/java/com/nextcloud/utils/extensions/IntentExtensions.kt index f52ddeffb5..30789ba423 100644 --- a/app/src/main/java/com/nextcloud/utils/extensions/IntentExtensions.kt +++ b/app/src/main/java/com/nextcloud/utils/extensions/IntentExtensions.kt @@ -40,7 +40,11 @@ fun Intent?.getSerializableArgument(key: String, type: Class this.getSerializableExtra(key, type) } else { @Suppress("UNCHECKED_CAST", "DEPRECATION") - this.getSerializableExtra(key) as T + if (type.isInstance(this.getSerializableExtra(key))) { + this.getSerializableExtra(key) as T + } else { + null + } } } catch (e: ClassCastException) { Log_OC.e(tag, e.localizedMessage) From 401a80b7ddd8822e5bcd1ee2ae1a02500d8893fc Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Wed, 14 Feb 2024 11:06:05 +0000 Subject: [PATCH 18/31] Update dependency com.mebigfatguy.fb-contrib:fb-contrib to v7.6.4 --- app/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/build.gradle b/app/build.gradle index c48aed6f95..c302a55c2f 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -291,7 +291,7 @@ dependencies { qaImplementation project(':appscan') spotbugsPlugins 'com.h3xstream.findsecbugs:findsecbugs-plugin:1.12.0' - spotbugsPlugins 'com.mebigfatguy.fb-contrib:fb-contrib:7.6.0' + spotbugsPlugins 'com.mebigfatguy.fb-contrib:fb-contrib:7.6.4' implementation "com.google.dagger:dagger:$daggerVersion" implementation "com.google.dagger:dagger-android:$daggerVersion" From 54401a9c18f28f92f5dbeb55c52159005ac5ea69 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Wed, 14 Feb 2024 11:06:38 +0000 Subject: [PATCH 19/31] Update dependency fastlane to v2.219.0 --- Gemfile.lock | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/Gemfile.lock b/Gemfile.lock index 836067fe7a..6f88626c37 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -8,8 +8,8 @@ GEM artifactory (3.0.15) atomos (0.1.3) aws-eventstream (1.3.0) - aws-partitions (1.887.0) - aws-sdk-core (3.191.0) + aws-partitions (1.890.0) + aws-sdk-core (3.191.1) aws-eventstream (~> 1, >= 1.3.0) aws-partitions (~> 1, >= 1.651.0) aws-sigv4 (~> 1.8) @@ -152,7 +152,7 @@ GEM mini_magick (4.12.0) mini_mime (1.1.5) multi_json (1.15.0) - multipart-post (2.3.0) + multipart-post (2.4.0) nanaimo (0.3.0) naturally (2.2.1) optparse (0.1.1) @@ -170,7 +170,7 @@ GEM ruby2_keywords (0.0.5) rubyzip (2.3.2) security (0.1.3) - signet (0.18.0) + signet (0.19.0) addressable (~> 2.8) faraday (>= 0.17.5, < 3.a) jwt (>= 1.5, < 3.0) From 3a929af8bb79a1f1a980892ffb55ff0f48bf9e5e Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Wed, 14 Feb 2024 11:06:47 +0000 Subject: [PATCH 20/31] Update gradle/gradle-build-action action to v3.1.0 --- .github/workflows/unit-tests.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/unit-tests.yml b/.github/workflows/unit-tests.yml index edb6551f40..d58330a807 100644 --- a/.github/workflows/unit-tests.yml +++ b/.github/workflows/unit-tests.yml @@ -30,7 +30,7 @@ jobs: if: ${{ always() }} run: scripts/deleteOldComments.sh "test" "Unit" ${{github.event.number}} - name: Run unit tests with coverage - uses: gradle/gradle-build-action@3b1b3b9a2104c2b47fbae53f3938079c00c9bb87 # v3.0.0 + uses: gradle/gradle-build-action@29c0906b64b8fc82467890bfb7a0a7ef34bda89e # v3.1.0 with: arguments: jacocoTestGplayDebugUnitTest - name: Upload failing results From 76bc48185e84f2f6dc11f1f689fa202c470aa57d Mon Sep 17 00:00:00 2001 From: Andy Scherzinger Date: Wed, 14 Feb 2024 12:48:41 +0100 Subject: [PATCH 21/31] Add further keys/metadata Signed-off-by: Andy Scherzinger --- gradle/verification-keyring.keys | 16 ++++++++++++++++ gradle/verification-metadata.xml | 1 + 2 files changed, 17 insertions(+) diff --git a/gradle/verification-keyring.keys b/gradle/verification-keyring.keys index 2095a4621a..3523cdbd8f 100644 --- a/gradle/verification-keyring.keys +++ b/gradle/verification-keyring.keys @@ -6354,6 +6354,22 @@ V3u1xg+t7/QlghTMoJAA0H5G =hS0U -----END PGP PUBLIC KEY BLOCK----- +pub 59E05CE618187ED4 +uid Taro L. Saito (For GitHub Actions) + +sub 8857595B73BFD468 +-----BEGIN PGP PUBLIC KEY BLOCK----- +Version: BCPG v1.68 + +mDMEYuRVGhYJKwYBBAHaRw8BAQdA2Dp4m1Yhtb1g94pQzzL24FuP6b9KXF8lP9Dh +hZnynhe0M1Rhcm8gTC4gU2FpdG8gKEZvciBHaXRIdWIgQWN0aW9ucykgPGxlb0B4 +ZXJpYWwub3JnPrg4BGLkVRoSCisGAQQBl1UBBQEBB0Atu9kejBi+6wfOT0a9z/LY +EEdNXM/VX6xt1onKToPPdQMBCAeIeAQYFgoAIBYhBMHLp17JvQuvgGGTVFngXOYY +GH7UBQJi5FUaAhsMAAoJEFngXOYYGH7UlMABAKyRCazhVyUFg5FOpAnmckBY38Ca +MGPPLXVyY8Kr6dYFAP9wYLu7nsDZCOXkAgS+et4Pk1WZCggoYUkxsX1o0KZXBQ== +=7Gio +-----END PGP PUBLIC KEY BLOCK----- + pub 5B05CCDE140C2876 sub 9D29AE4A6B50E01F -----BEGIN PGP PUBLIC KEY BLOCK----- diff --git a/gradle/verification-metadata.xml b/gradle/verification-metadata.xml index ea3fcfaf03..26dc1b944f 100644 --- a/gradle/verification-metadata.xml +++ b/gradle/verification-metadata.xml @@ -227,6 +227,7 @@ + From db7cd0033db8a9f839246123df6863c5dc3355ed Mon Sep 17 00:00:00 2001 From: Jonas Mayer Date: Tue, 13 Feb 2024 19:30:41 +0100 Subject: [PATCH 22/31] add new state manually cancelled Signed-off-by: Jonas Mayer --- .../datamodel/UploadsStorageManager.java | 31 ++++++++- .../com/owncloud/android/db/UploadResult.java | 5 +- .../android/ui/adapter/UploadListAdapter.java | 69 +++++++++++++++---- .../menu/upload_list_cancelled_options.xml | 32 +++++++++ app/src/main/res/values/strings.xml | 3 + 5 files changed, 123 insertions(+), 17 deletions(-) create mode 100644 app/src/main/res/menu/upload_list_cancelled_options.xml diff --git a/app/src/main/java/com/owncloud/android/datamodel/UploadsStorageManager.java b/app/src/main/java/com/owncloud/android/datamodel/UploadsStorageManager.java index a00fba2a52..195e4f979c 100644 --- a/app/src/main/java/com/owncloud/android/datamodel/UploadsStorageManager.java +++ b/app/src/main/java/com/owncloud/android/datamodel/UploadsStorageManager.java @@ -630,6 +630,13 @@ public class UploadsStorageManager extends Observable { ProviderTableMeta.UPLOADS_ACCOUNT_NAME + "== ?", user.getAccountName()); } + public OCUpload[] getManuallyCancelledUploadsForCurrentAccount() { + User user = currentAccountProvider.getUser(); + + return getUploads(ProviderTableMeta.UPLOADS_STATUS + "==" + UploadStatus.UPLOAD_MANUALLY_CANCELLED.value + AND + + ProviderTableMeta.UPLOADS_ACCOUNT_NAME + "== ?", user.getAccountName()); + } + /** * Get all uploads which where successfully completed. */ @@ -700,6 +707,21 @@ public class UploadsStorageManager extends Observable { return deleted; } + public long clearManuallyCancelledUploadsForCurrentAccount() { + User user = currentAccountProvider.getUser(); + final long deleted = getDB().delete( + ProviderTableMeta.CONTENT_URI_UPLOADS, + ProviderTableMeta.UPLOADS_STATUS + "==" + UploadStatus.UPLOAD_MANUALLY_CANCELLED.value + AND + + ProviderTableMeta.UPLOADS_ACCOUNT_NAME + "== ?", new String[]{user.getAccountName()} + ); + + Log_OC.d(TAG, "delete all manually cancelled uploads"); + if (deleted > 0) { + notifyObserversNow(); + } + return deleted; + } + public long clearSuccessfulUploads() { User user = currentAccountProvider.getUser(); final long deleted = getDB().delete( @@ -851,7 +873,12 @@ public class UploadsStorageManager extends Observable { /** * Upload was successful. */ - UPLOAD_SUCCEEDED(2); + UPLOAD_SUCCEEDED(2), + + /** + * Upload was cancelled by the user. + */ + UPLOAD_MANUALLY_CANCELLED(3); private final int value; @@ -867,6 +894,8 @@ public class UploadsStorageManager extends Observable { return UPLOAD_FAILED; case 2: return UPLOAD_SUCCEEDED; + case 3: + return UPLOAD_MANUALLY_CANCELLED; } return null; } diff --git a/app/src/main/java/com/owncloud/android/db/UploadResult.java b/app/src/main/java/com/owncloud/android/db/UploadResult.java index 919be585cb..2ba7be4253 100644 --- a/app/src/main/java/com/owncloud/android/db/UploadResult.java +++ b/app/src/main/java/com/owncloud/android/db/UploadResult.java @@ -46,7 +46,8 @@ public enum UploadResult { CANNOT_CREATE_FILE(20), LOCAL_STORAGE_NOT_COPIED(21), QUOTA_EXCEEDED(22), - SAME_FILE_CONFLICT(23); + SAME_FILE_CONFLICT(23), + MANUALLY_CANCELLED(24); private final int value; @@ -110,6 +111,8 @@ public enum UploadResult { return QUOTA_EXCEEDED; case 23: return SAME_FILE_CONFLICT; + case 24: + return MANUALLY_CANCELLED; } return UNKNOWN; } diff --git a/app/src/main/java/com/owncloud/android/ui/adapter/UploadListAdapter.java b/app/src/main/java/com/owncloud/android/ui/adapter/UploadListAdapter.java index 50168c5b0d..fb2ff668f4 100755 --- a/app/src/main/java/com/owncloud/android/ui/adapter/UploadListAdapter.java +++ b/app/src/main/java/com/owncloud/android/ui/adapter/UploadListAdapter.java @@ -33,6 +33,7 @@ import android.graphics.drawable.Drawable; import android.net.Uri; import android.text.format.DateUtils; import android.view.LayoutInflater; +import android.view.MenuItem; import android.view.View; import android.view.ViewGroup; import android.widget.PopupMenu; @@ -122,7 +123,8 @@ public class UploadListAdapter extends SectionedRecyclerViewAdapter headerViewHolder.binding.uploadListAction.setImageResource(R.drawable.ic_close); - case FAILED -> headerViewHolder.binding.uploadListAction.setImageResource(R.drawable.ic_dots_vertical); + case CANCELLED, FAILED -> headerViewHolder.binding.uploadListAction.setImageResource(R.drawable.ic_dots_vertical); + } headerViewHolder.binding.uploadListAction.setOnClickListener(v -> { @@ -143,6 +145,10 @@ public class UploadListAdapter extends SectionedRecyclerViewAdapter { + // show popup with option clear or retry manually cancelled uploads + createCancelledActionsPopupMenu(headerViewHolder); + } } }); } @@ -173,6 +179,30 @@ public class UploadListAdapter extends SectionedRecyclerViewAdapter { + int itemId = i.getItemId(); + + if (itemId == R.id.action_upload_list_cancelled_clear) { + uploadsStorageManager.clearManuallyCancelledUploadsForCurrentAccount(); + loadUploadItemsFromDb(); + } else if (itemId == R.id.action_upload_list_cancelled_resume) { + + new Thread(() -> { + parentActivity.runOnUiThread(this::loadUploadItemsFromDb); + // TODO Do something + }).start(); + + } + + return true; + }); + popup.show(); + } + @Override public void onBindFooterViewHolder(SectionedViewHolder holder, int section) { // not needed @@ -197,7 +227,7 @@ public class UploadListAdapter extends SectionedRecyclerViewAdapter 1; loadUploadItemsFromDb(); @@ -655,7 +693,7 @@ public class UploadListAdapter extends SectionedRecyclerViewAdapter status = getUploadFailedStatusText(upload.getLastResult()); + case UPLOAD_FAILED, UPLOAD_MANUALLY_CANCELLED -> status = getUploadFailedStatusText(upload.getLastResult()); default -> status = "Uncontrolled status: " + upload.getUploadStatus(); } return status; @@ -709,8 +747,8 @@ public class UploadListAdapter extends SectionedRecyclerViewAdapter + + + + + + diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 6fd30bc936..f06eeceb1b 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -852,6 +852,9 @@ Pause all uploads Resume all uploads Dismiss notification + Resume cancelled uploads + Clear cancelled uploads + Upload was cancelled by user Clear all notifications Loading is taking longer than expected Failed to clear notifications. From c6c5e8fbd67181c411b32ebf876c82d06d147628 Mon Sep 17 00:00:00 2001 From: Jonas Mayer Date: Wed, 14 Feb 2024 03:56:06 +0100 Subject: [PATCH 23/31] add resume functionality for uploads Signed-off-by: Jonas Mayer --- .../client/jobs/upload/FileUploadHelper.kt | 48 +++++++++++- .../client/jobs/upload/FileUploadWorker.kt | 2 + .../ui/activity/ConflictsResolveActivity.kt | 6 +- .../android/ui/adapter/UploadListAdapter.java | 77 ++++++++++++------- .../ui/helpers/FileOperationsHelper.java | 2 +- app/src/main/res/values/strings.xml | 1 + 6 files changed, 100 insertions(+), 36 deletions(-) diff --git a/app/src/main/java/com/nextcloud/client/jobs/upload/FileUploadHelper.kt b/app/src/main/java/com/nextcloud/client/jobs/upload/FileUploadHelper.kt index 99c86cbe36..d98bce9bfd 100644 --- a/app/src/main/java/com/nextcloud/client/jobs/upload/FileUploadHelper.kt +++ b/app/src/main/java/com/nextcloud/client/jobs/upload/FileUploadHelper.kt @@ -81,7 +81,6 @@ class FileUploadHelper { } } - @Suppress("ComplexCondition") fun retryFailedUploads( uploadsStorageManager: UploadsStorageManager, connectivityService: ConnectivityService, @@ -92,6 +91,42 @@ class FileUploadHelper { if (failedUploads == null || failedUploads.isEmpty()) { return } + retryUploads( + uploadsStorageManager, + connectivityService, + accountManager, + powerManagementService, + failedUploads + ) + } + + fun retryCancelledUploads( + uploadsStorageManager: UploadsStorageManager, + connectivityService: ConnectivityService, + accountManager: UserAccountManager, + powerManagementService: PowerManagementService + ) { + val cancelledUploads = uploadsStorageManager.manuallyCancelledUploadsForCurrentAccount + if (cancelledUploads == null || cancelledUploads.isEmpty()) { + return + } + retryUploads( + uploadsStorageManager, + connectivityService, + accountManager, + powerManagementService, + cancelledUploads + ) + } + + @Suppress("ComplexCondition") + private fun retryUploads( + uploadsStorageManager: UploadsStorageManager, + connectivityService: ConnectivityService, + accountManager: UserAccountManager, + powerManagementService: PowerManagementService, + failedUploads: Array + ) { val (gotNetwork, _, gotWifi) = connectivityService.connectivity val batteryStatus = powerManagementService.battery @@ -146,7 +181,7 @@ class FileUploadHelper { backgroundJobManager.startFilesUploadJob(user) } - fun cancelFileUpload(remotePath: String, accountName: String) { + fun removeFileUpload(remotePath: String, accountName: String) { try { val user = accountManager.getUser(accountName).get() @@ -160,6 +195,13 @@ class FileUploadHelper { } } + fun manuallyCancelFileUpload(remotePath: String, accountName: String) { + val upload = uploadsStorageManager.getUploadByRemotePath(remotePath) + removeFileUpload(remotePath, accountName) + upload.uploadStatus = UploadStatus.UPLOAD_MANUALLY_CANCELLED + uploadsStorageManager.storeUpload(upload) + } + fun cancelAndRestartUploadJob(user: User) { backgroundJobManager.run { cancelFilesUploadJob(user) @@ -293,7 +335,7 @@ class FileUploadHelper { return } - instance().cancelFileUpload(remotePath, accountName) + instance().manuallyCancelFileUpload(remotePath, accountName) } } } diff --git a/app/src/main/java/com/nextcloud/client/jobs/upload/FileUploadWorker.kt b/app/src/main/java/com/nextcloud/client/jobs/upload/FileUploadWorker.kt index 91b2586ef8..35e9c83de7 100644 --- a/app/src/main/java/com/nextcloud/client/jobs/upload/FileUploadWorker.kt +++ b/app/src/main/java/com/nextcloud/client/jobs/upload/FileUploadWorker.kt @@ -143,6 +143,8 @@ class FileUploadWorker( val accountName = inputData.getString(ACCOUNT) ?: return Result.failure() var currentPage = uploadsStorageManager.getCurrentAndPendingUploadsForAccountPageAscById(-1, accountName) + notificationManager.dismissWorkerNotifications() + while (currentPage.isNotEmpty() && !isStopped) { if (preferences.isGlobalUploadPaused) { Log_OC.d(TAG, "Upload is paused, skip uploading files!") diff --git a/app/src/main/java/com/owncloud/android/ui/activity/ConflictsResolveActivity.kt b/app/src/main/java/com/owncloud/android/ui/activity/ConflictsResolveActivity.kt index 40b06108b0..0b55719087 100644 --- a/app/src/main/java/com/owncloud/android/ui/activity/ConflictsResolveActivity.kt +++ b/app/src/main/java/com/owncloud/android/ui/activity/ConflictsResolveActivity.kt @@ -94,7 +94,7 @@ class ConflictsResolveActivity : FileActivity(), OnConflictDecisionMadeListener Decision.CANCEL -> {} Decision.KEEP_LOCAL -> { upload?.let { - FileUploadHelper.instance().cancelFileUpload(it.remotePath, it.accountName) + FileUploadHelper.instance().removeFileUpload(it.remotePath, it.accountName) } FileUploadHelper.instance().uploadUpdatedFile( user, @@ -106,7 +106,7 @@ class ConflictsResolveActivity : FileActivity(), OnConflictDecisionMadeListener Decision.KEEP_BOTH -> { upload?.let { - FileUploadHelper.instance().cancelFileUpload(it.remotePath, it.accountName) + FileUploadHelper.instance().removeFileUpload(it.remotePath, it.accountName) } FileUploadHelper.instance().uploadUpdatedFile( user, @@ -129,7 +129,7 @@ class ConflictsResolveActivity : FileActivity(), OnConflictDecisionMadeListener } upload?.let { - FileUploadHelper.instance().cancelFileUpload(it.remotePath, it.accountName) + FileUploadHelper.instance().removeFileUpload(it.remotePath, it.accountName) UploadNotificationManager( applicationContext, diff --git a/app/src/main/java/com/owncloud/android/ui/adapter/UploadListAdapter.java b/app/src/main/java/com/owncloud/android/ui/adapter/UploadListAdapter.java index fb2ff668f4..ecd80a2dca 100755 --- a/app/src/main/java/com/owncloud/android/ui/adapter/UploadListAdapter.java +++ b/app/src/main/java/com/owncloud/android/ui/adapter/UploadListAdapter.java @@ -33,7 +33,6 @@ import android.graphics.drawable.Drawable; import android.net.Uri; import android.text.format.DateUtils; import android.view.LayoutInflater; -import android.view.MenuItem; import android.view.View; import android.view.ViewGroup; import android.widget.PopupMenu; @@ -123,7 +122,8 @@ public class UploadListAdapter extends SectionedRecyclerViewAdapter headerViewHolder.binding.uploadListAction.setImageResource(R.drawable.ic_close); - case CANCELLED, FAILED -> headerViewHolder.binding.uploadListAction.setImageResource(R.drawable.ic_dots_vertical); + case CANCELLED, FAILED -> + headerViewHolder.binding.uploadListAction.setImageResource(R.drawable.ic_dots_vertical); } @@ -132,7 +132,7 @@ public class UploadListAdapter extends SectionedRecyclerViewAdapter { // cancel all current uploads for (OCUpload upload : group.getItems()) { - uploadHelper.cancelFileUpload(upload.getRemotePath(), upload.getAccountName()); + uploadHelper.manuallyCancelFileUpload(upload.getRemotePath(), upload.getAccountName()); } loadUploadItemsFromDb(); } @@ -179,7 +179,7 @@ public class UploadListAdapter extends SectionedRecyclerViewAdapter { + FileUploadHelper.Companion.instance().retryCancelledUploads( + uploadsStorageManager, + connectivityService, + accountManager, + powerManagementService); parentActivity.runOnUiThread(this::loadUploadItemsFromDb); - // TODO Do something }).start(); } @@ -247,7 +251,16 @@ public class UploadListAdapter extends SectionedRecyclerViewAdapter 1; loadUploadItemsFromDb(); @@ -365,8 +370,10 @@ public class UploadListAdapter extends SectionedRecyclerViewAdapter itemViewHolder.binding.uploadStatus.setVisibility(View.GONE); } - // show status if same file conflict or local file deleted - if (item.getUploadStatus() == UploadStatus.UPLOAD_SUCCEEDED && item.getLastResult() != UploadResult.UPLOADED) { + // show status if same file conflict or local file deleted or upload cancelled + if ((item.getUploadStatus() == UploadStatus.UPLOAD_SUCCEEDED && item.getLastResult() != UploadResult.UPLOADED) + || item.getUploadStatus() == UploadStatus.UPLOAD_MANUALLY_CANCELLED) { + itemViewHolder.binding.uploadStatus.setVisibility(View.VISIBLE); itemViewHolder.binding.uploadDate.setVisibility(View.GONE); itemViewHolder.binding.uploadFileSize.setVisibility(View.GONE); @@ -380,7 +387,7 @@ public class UploadListAdapter extends SectionedRecyclerViewAdapter { - uploadHelper.cancelFileUpload(item.getRemotePath(), item.getAccountName()); + uploadHelper.manuallyCancelFileUpload(item.getRemotePath(), item.getAccountName()); loadUploadItemsFromDb(); }); @@ -409,7 +416,9 @@ public class UploadListAdapter extends SectionedRecyclerViewAdapter { if (uploadResult == UploadResult.CREDENTIAL_ERROR) { @@ -693,8 +702,16 @@ public class UploadListAdapter extends SectionedRecyclerViewAdapter status = getUploadFailedStatusText(upload.getLastResult()); - default -> status = "Uncontrolled status: " + upload.getUploadStatus(); + case UPLOAD_FAILED -> { + status = getUploadFailedStatusText(upload.getLastResult()); + } + case UPLOAD_MANUALLY_CANCELLED -> { + status = parentActivity.getString(R.string.upload_manually_cancelled); + } + + default -> { + status = "Uncontrolled status: " + upload.getUploadStatus(); + } } return status; } @@ -747,8 +764,8 @@ public class UploadListAdapter extends SectionedRecyclerViewAdapterUploads Current Failed/pending restart + Cancelled Uploaded Completed Same file found on remote, skipping upload From 044e83548d7bbd35a10ab25f420d4183d820bce3 Mon Sep 17 00:00:00 2001 From: Jonas Mayer Date: Wed, 14 Feb 2024 04:07:19 +0100 Subject: [PATCH 24/31] fix spotless Signed-off-by: Jonas Mayer --- .../java/com/nextcloud/client/jobs/upload/FileUploadHelper.kt | 1 - 1 file changed, 1 deletion(-) diff --git a/app/src/main/java/com/nextcloud/client/jobs/upload/FileUploadHelper.kt b/app/src/main/java/com/nextcloud/client/jobs/upload/FileUploadHelper.kt index d98bce9bfd..4fcc4b8ac0 100644 --- a/app/src/main/java/com/nextcloud/client/jobs/upload/FileUploadHelper.kt +++ b/app/src/main/java/com/nextcloud/client/jobs/upload/FileUploadHelper.kt @@ -127,7 +127,6 @@ class FileUploadHelper { powerManagementService: PowerManagementService, failedUploads: Array ) { - val (gotNetwork, _, gotWifi) = connectivityService.connectivity val batteryStatus = powerManagementService.battery val charging = batteryStatus.isCharging || batteryStatus.isFull From 6d3b8897b3abbef4d3ca337574ddc843b723dbd5 Mon Sep 17 00:00:00 2001 From: Jonas Mayer Date: Wed, 14 Feb 2024 13:36:13 +0100 Subject: [PATCH 25/31] fix spot bugs Signed-off-by: Jonas Mayer --- .../com/owncloud/android/ui/adapter/UploadListAdapter.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/app/src/main/java/com/owncloud/android/ui/adapter/UploadListAdapter.java b/app/src/main/java/com/owncloud/android/ui/adapter/UploadListAdapter.java index ecd80a2dca..c18b1a0ba0 100755 --- a/app/src/main/java/com/owncloud/android/ui/adapter/UploadListAdapter.java +++ b/app/src/main/java/com/owncloud/android/ui/adapter/UploadListAdapter.java @@ -367,7 +367,8 @@ public class UploadListAdapter extends SectionedRecyclerViewAdapter itemViewHolder.binding.uploadDate.setVisibility(View.GONE); - case UPLOAD_SUCCEEDED -> itemViewHolder.binding.uploadStatus.setVisibility(View.GONE); + case UPLOAD_SUCCEEDED, UPLOAD_MANUALLY_CANCELLED -> + itemViewHolder.binding.uploadStatus.setVisibility(View.GONE); } // show status if same file conflict or local file deleted or upload cancelled From 6d06df9757d308bb677cdf21a384d259b2d13ba1 Mon Sep 17 00:00:00 2001 From: Jonas Mayer Date: Wed, 14 Feb 2024 14:24:09 +0100 Subject: [PATCH 26/31] rename functions Signed-off-by: Jonas Mayer --- .../client/jobs/upload/FileUploadHelper.kt | 15 ++++----- .../datamodel/UploadsStorageManager.java | 15 +++++---- .../com/owncloud/android/db/UploadResult.java | 5 +-- .../android/ui/adapter/UploadListAdapter.java | 31 +++++++------------ .../ui/helpers/FileOperationsHelper.java | 2 +- 5 files changed, 29 insertions(+), 39 deletions(-) diff --git a/app/src/main/java/com/nextcloud/client/jobs/upload/FileUploadHelper.kt b/app/src/main/java/com/nextcloud/client/jobs/upload/FileUploadHelper.kt index 4fcc4b8ac0..03f6020b05 100644 --- a/app/src/main/java/com/nextcloud/client/jobs/upload/FileUploadHelper.kt +++ b/app/src/main/java/com/nextcloud/client/jobs/upload/FileUploadHelper.kt @@ -106,7 +106,7 @@ class FileUploadHelper { accountManager: UserAccountManager, powerManagementService: PowerManagementService ) { - val cancelledUploads = uploadsStorageManager.manuallyCancelledUploadsForCurrentAccount + val cancelledUploads = uploadsStorageManager.cancelledUploadsForCurrentAccount if (cancelledUploads == null || cancelledUploads.isEmpty()) { return } @@ -194,11 +194,12 @@ class FileUploadHelper { } } - fun manuallyCancelFileUpload(remotePath: String, accountName: String) { - val upload = uploadsStorageManager.getUploadByRemotePath(remotePath) - removeFileUpload(remotePath, accountName) - upload.uploadStatus = UploadStatus.UPLOAD_MANUALLY_CANCELLED - uploadsStorageManager.storeUpload(upload) + fun cancelFileUpload(remotePath: String, accountName: String) { + uploadsStorageManager.getUploadByRemotePath(remotePath).run { + removeFileUpload(remotePath, accountName) + uploadStatus = UploadStatus.UPLOAD_CANCELLED + uploadsStorageManager.storeUpload(this) + } } fun cancelAndRestartUploadJob(user: User) { @@ -334,7 +335,7 @@ class FileUploadHelper { return } - instance().manuallyCancelFileUpload(remotePath, accountName) + instance().cancelFileUpload(remotePath, accountName) } } } diff --git a/app/src/main/java/com/owncloud/android/datamodel/UploadsStorageManager.java b/app/src/main/java/com/owncloud/android/datamodel/UploadsStorageManager.java index 195e4f979c..e5feb111e9 100644 --- a/app/src/main/java/com/owncloud/android/datamodel/UploadsStorageManager.java +++ b/app/src/main/java/com/owncloud/android/datamodel/UploadsStorageManager.java @@ -630,10 +630,10 @@ public class UploadsStorageManager extends Observable { ProviderTableMeta.UPLOADS_ACCOUNT_NAME + "== ?", user.getAccountName()); } - public OCUpload[] getManuallyCancelledUploadsForCurrentAccount() { + public OCUpload[] getCancelledUploadsForCurrentAccount() { User user = currentAccountProvider.getUser(); - return getUploads(ProviderTableMeta.UPLOADS_STATUS + "==" + UploadStatus.UPLOAD_MANUALLY_CANCELLED.value + AND + + return getUploads(ProviderTableMeta.UPLOADS_STATUS + "==" + UploadStatus.UPLOAD_CANCELLED.value + AND + ProviderTableMeta.UPLOADS_ACCOUNT_NAME + "== ?", user.getAccountName()); } @@ -707,19 +707,18 @@ public class UploadsStorageManager extends Observable { return deleted; } - public long clearManuallyCancelledUploadsForCurrentAccount() { + public void clearCancelledUploadsForCurrentAccount() { User user = currentAccountProvider.getUser(); final long deleted = getDB().delete( ProviderTableMeta.CONTENT_URI_UPLOADS, - ProviderTableMeta.UPLOADS_STATUS + "==" + UploadStatus.UPLOAD_MANUALLY_CANCELLED.value + AND + + ProviderTableMeta.UPLOADS_STATUS + "==" + UploadStatus.UPLOAD_CANCELLED.value + AND + ProviderTableMeta.UPLOADS_ACCOUNT_NAME + "== ?", new String[]{user.getAccountName()} ); - Log_OC.d(TAG, "delete all manually cancelled uploads"); + Log_OC.d(TAG, "delete all cancelled uploads"); if (deleted > 0) { notifyObserversNow(); } - return deleted; } public long clearSuccessfulUploads() { @@ -878,7 +877,7 @@ public class UploadsStorageManager extends Observable { /** * Upload was cancelled by the user. */ - UPLOAD_MANUALLY_CANCELLED(3); + UPLOAD_CANCELLED(3); private final int value; @@ -895,7 +894,7 @@ public class UploadsStorageManager extends Observable { case 2: return UPLOAD_SUCCEEDED; case 3: - return UPLOAD_MANUALLY_CANCELLED; + return UPLOAD_CANCELLED; } return null; } diff --git a/app/src/main/java/com/owncloud/android/db/UploadResult.java b/app/src/main/java/com/owncloud/android/db/UploadResult.java index 2ba7be4253..919be585cb 100644 --- a/app/src/main/java/com/owncloud/android/db/UploadResult.java +++ b/app/src/main/java/com/owncloud/android/db/UploadResult.java @@ -46,8 +46,7 @@ public enum UploadResult { CANNOT_CREATE_FILE(20), LOCAL_STORAGE_NOT_COPIED(21), QUOTA_EXCEEDED(22), - SAME_FILE_CONFLICT(23), - MANUALLY_CANCELLED(24); + SAME_FILE_CONFLICT(23); private final int value; @@ -111,8 +110,6 @@ public enum UploadResult { return QUOTA_EXCEEDED; case 23: return SAME_FILE_CONFLICT; - case 24: - return MANUALLY_CANCELLED; } return UNKNOWN; } diff --git a/app/src/main/java/com/owncloud/android/ui/adapter/UploadListAdapter.java b/app/src/main/java/com/owncloud/android/ui/adapter/UploadListAdapter.java index c18b1a0ba0..0a899fc9ae 100755 --- a/app/src/main/java/com/owncloud/android/ui/adapter/UploadListAdapter.java +++ b/app/src/main/java/com/owncloud/android/ui/adapter/UploadListAdapter.java @@ -130,30 +130,26 @@ public class UploadListAdapter extends SectionedRecyclerViewAdapter { switch (group.type) { case CURRENT -> { - // cancel all current uploads for (OCUpload upload : group.getItems()) { - uploadHelper.manuallyCancelFileUpload(upload.getRemotePath(), upload.getAccountName()); + uploadHelper.cancelFileUpload(upload.getRemotePath(), upload.getAccountName()); } loadUploadItemsFromDb(); } case FINISHED -> { - // clear successfully uploaded section uploadsStorageManager.clearSuccessfulUploads(); loadUploadItemsFromDb(); } case FAILED -> { - // show popup with option clear or retry filed uploads - createFailedPopupMenu(headerViewHolder); + showFailedPopupMenu(headerViewHolder); } case CANCELLED -> { - // show popup with option clear or retry manually cancelled uploads - createCancelledActionsPopupMenu(headerViewHolder); + showCancelledPopupMenu(headerViewHolder); } } }); } - private void createFailedPopupMenu(HeaderViewHolder headerViewHolder) { + private void showFailedPopupMenu(HeaderViewHolder headerViewHolder) { PopupMenu failedPopup = new PopupMenu(MainApp.getAppContext(), headerViewHolder.binding.uploadListAction); failedPopup.inflate(R.menu.upload_list_failed_options); failedPopup.setOnMenuItemClickListener(i -> { @@ -179,7 +175,7 @@ public class UploadListAdapter extends SectionedRecyclerViewAdapter itemViewHolder.binding.uploadDate.setVisibility(View.GONE); - case UPLOAD_SUCCEEDED, UPLOAD_MANUALLY_CANCELLED -> + case UPLOAD_SUCCEEDED, UPLOAD_CANCELLED -> itemViewHolder.binding.uploadStatus.setVisibility(View.GONE); } // show status if same file conflict or local file deleted or upload cancelled if ((item.getUploadStatus() == UploadStatus.UPLOAD_SUCCEEDED && item.getLastResult() != UploadResult.UPLOADED) - || item.getUploadStatus() == UploadStatus.UPLOAD_MANUALLY_CANCELLED) { + || item.getUploadStatus() == UploadStatus.UPLOAD_CANCELLED) { itemViewHolder.binding.uploadStatus.setVisibility(View.VISIBLE); itemViewHolder.binding.uploadDate.setVisibility(View.GONE); @@ -388,7 +384,7 @@ public class UploadListAdapter extends SectionedRecyclerViewAdapter { - uploadHelper.manuallyCancelFileUpload(item.getRemotePath(), item.getAccountName()); + uploadHelper.cancelFileUpload(item.getRemotePath(), item.getAccountName()); loadUploadItemsFromDb(); }); @@ -418,7 +414,7 @@ public class UploadListAdapter extends SectionedRecyclerViewAdapter { @@ -706,7 +702,7 @@ public class UploadListAdapter extends SectionedRecyclerViewAdapter { status = getUploadFailedStatusText(upload.getLastResult()); } - case UPLOAD_MANUALLY_CANCELLED -> { + case UPLOAD_CANCELLED -> { status = parentActivity.getString(R.string.upload_manually_cancelled); } @@ -799,9 +795,6 @@ public class UploadListAdapter extends SectionedRecyclerViewAdapter Date: Wed, 14 Feb 2024 14:52:07 +0100 Subject: [PATCH 27/31] Refactor, add info message for not existing cancelled uploads Signed-off-by: alperozturk --- .../client/jobs/upload/FileUploadHelper.kt | 18 ++++++---- .../com/owncloud/android/db/OCUpload.java | 4 +++ .../android/ui/adapter/UploadListAdapter.java | 35 +++++++++++++------ app/src/main/res/values/strings.xml | 1 + 4 files changed, 41 insertions(+), 17 deletions(-) diff --git a/app/src/main/java/com/nextcloud/client/jobs/upload/FileUploadHelper.kt b/app/src/main/java/com/nextcloud/client/jobs/upload/FileUploadHelper.kt index 03f6020b05..5e9ccd7d57 100644 --- a/app/src/main/java/com/nextcloud/client/jobs/upload/FileUploadHelper.kt +++ b/app/src/main/java/com/nextcloud/client/jobs/upload/FileUploadHelper.kt @@ -104,13 +104,14 @@ class FileUploadHelper { uploadsStorageManager: UploadsStorageManager, connectivityService: ConnectivityService, accountManager: UserAccountManager, - powerManagementService: PowerManagementService - ) { + powerManagementService: PowerManagementService, + ): Boolean { val cancelledUploads = uploadsStorageManager.cancelledUploadsForCurrentAccount if (cancelledUploads == null || cancelledUploads.isEmpty()) { - return + return false } - retryUploads( + + return retryUploads( uploadsStorageManager, connectivityService, accountManager, @@ -125,8 +126,9 @@ class FileUploadHelper { connectivityService: ConnectivityService, accountManager: UserAccountManager, powerManagementService: PowerManagementService, - failedUploads: Array - ) { + failedUploads: Array, + ): Boolean { + var showNotExistMessage = false val (gotNetwork, _, gotWifi) = connectivityService.connectivity val batteryStatus = powerManagementService.battery val charging = batteryStatus.isCharging || batteryStatus.isFull @@ -139,6 +141,8 @@ class FileUploadHelper { } val isDeleted = !File(failedUpload.localPath).exists() if (isDeleted) { + showNotExistMessage = true + // 2A. for deleted files, mark as permanently failed if (failedUpload.lastResult != UploadResult.FILE_NOT_FOUND) { failedUpload.lastResult = UploadResult.FILE_NOT_FOUND @@ -151,6 +155,8 @@ class FileUploadHelper { retryUpload(failedUpload, uploadUser.get()) } } + + return showNotExistMessage } @Suppress("LongParameterList") diff --git a/app/src/main/java/com/owncloud/android/db/OCUpload.java b/app/src/main/java/com/owncloud/android/db/OCUpload.java index 5de0074cf9..d88a6a3f29 100644 --- a/app/src/main/java/com/owncloud/android/db/OCUpload.java +++ b/app/src/main/java/com/owncloud/android/db/OCUpload.java @@ -390,6 +390,10 @@ public class OCUpload implements Parcelable { return this.useWifiOnly; } + public boolean exists() { + return new File(localPath).exists(); + } + public boolean isWhileChargingOnly() { return this.whileChargingOnly; } diff --git a/app/src/main/java/com/owncloud/android/ui/adapter/UploadListAdapter.java b/app/src/main/java/com/owncloud/android/ui/adapter/UploadListAdapter.java index 0a899fc9ae..73f8aa1df5 100755 --- a/app/src/main/java/com/owncloud/android/ui/adapter/UploadListAdapter.java +++ b/app/src/main/java/com/owncloud/android/ui/adapter/UploadListAdapter.java @@ -175,7 +175,7 @@ public class UploadListAdapter extends SectionedRecyclerViewAdapter { - FileUploadHelper.Companion.instance().retryCancelledUploads( - uploadsStorageManager, - connectivityService, - accountManager, - powerManagementService); - parentActivity.runOnUiThread(this::loadUploadItemsFromDb); - }).start(); - + retryCancelledUploads(); } return true; }); + popup.show(); } + private void retryCancelledUploads() { + new Thread(() -> { + boolean showNotExistMessage = FileUploadHelper.Companion.instance().retryCancelledUploads( + uploadsStorageManager, + connectivityService, + accountManager, + powerManagementService); + + parentActivity.runOnUiThread(this::loadUploadItemsFromDb); + parentActivity.runOnUiThread(() -> { + if (showNotExistMessage) { + showNotExistMessage(); + } + }); + }).start(); + } + + private void showNotExistMessage() { + DisplayUtils.showSnackMessage(parentActivity, R.string.upload_action_file_not_exist_message); + } + @Override public void onBindFooterViewHolder(SectionedViewHolder holder, int section) { // not needed diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index c95cffa45a..d1f9c83143 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -853,6 +853,7 @@ Pause all uploads Resume all uploads Dismiss notification + Some files not exists those files cannot be resumed Resume cancelled uploads Clear cancelled uploads Upload was cancelled by user From 86c6a553f64c0e9347215e07e805fbcd5d018232 Mon Sep 17 00:00:00 2001 From: Jonas Mayer Date: Wed, 14 Feb 2024 15:30:46 +0100 Subject: [PATCH 28/31] fix spotless Signed-off-by: Jonas Mayer --- .../java/com/nextcloud/client/jobs/upload/FileUploadHelper.kt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/app/src/main/java/com/nextcloud/client/jobs/upload/FileUploadHelper.kt b/app/src/main/java/com/nextcloud/client/jobs/upload/FileUploadHelper.kt index 5e9ccd7d57..c83a924b96 100644 --- a/app/src/main/java/com/nextcloud/client/jobs/upload/FileUploadHelper.kt +++ b/app/src/main/java/com/nextcloud/client/jobs/upload/FileUploadHelper.kt @@ -104,7 +104,7 @@ class FileUploadHelper { uploadsStorageManager: UploadsStorageManager, connectivityService: ConnectivityService, accountManager: UserAccountManager, - powerManagementService: PowerManagementService, + powerManagementService: PowerManagementService ): Boolean { val cancelledUploads = uploadsStorageManager.cancelledUploadsForCurrentAccount if (cancelledUploads == null || cancelledUploads.isEmpty()) { @@ -126,7 +126,7 @@ class FileUploadHelper { connectivityService: ConnectivityService, accountManager: UserAccountManager, powerManagementService: PowerManagementService, - failedUploads: Array, + failedUploads: Array ): Boolean { var showNotExistMessage = false val (gotNetwork, _, gotWifi) = connectivityService.connectivity From 984d99c165060febe017fd0b10f257c2c375a6bb Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Wed, 14 Feb 2024 14:23:36 +0000 Subject: [PATCH 29/31] Update dependency com.karumi:shot to v6 --- app/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/build.gradle b/app/build.gradle index c302a55c2f..5c712e031f 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -10,7 +10,7 @@ buildscript { classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version" classpath "io.gitlab.arturbosch.detekt:detekt-gradle-plugin:1.23.5" classpath "commons-httpclient:commons-httpclient:3.1@jar" // remove after entire switch to lib v2 - classpath 'com.karumi:shot:5.14.1' + classpath 'com.karumi:shot:6.1.0' classpath "org.jacoco:org.jacoco.core:$jacoco_version" classpath "org.jacoco:org.jacoco.report:$jacoco_version" classpath "org.jacoco:org.jacoco.agent:$jacoco_version" From 55e8ccea7739637831dbdfedde477917e48dad14 Mon Sep 17 00:00:00 2001 From: Andy Scherzinger Date: Wed, 14 Feb 2024 16:20:22 +0100 Subject: [PATCH 30/31] Add/Update dependency metadata Signed-off-by: Andy Scherzinger --- gradle/verification-keyring.keys | 208 ++++++++++++++++++++++++++++++ gradle/verification-metadata.xml | 209 ++++++++++++++++++++++++++++++- 2 files changed, 412 insertions(+), 5 deletions(-) diff --git a/gradle/verification-keyring.keys b/gradle/verification-keyring.keys index 3523cdbd8f..5c90cec442 100644 --- a/gradle/verification-keyring.keys +++ b/gradle/verification-keyring.keys @@ -2324,6 +2324,42 @@ ikmfPIGVw73RF3HXjJ8GVqTkqbo4ZpgTw/7Z3+fAYE/vxquhnpl2HvE= =5tlI -----END PGP PUBLIC KEY BLOCK----- +pub D56C721C1CFF1424 +uid Harald Kuhr + +sub 82889D6A1813F02D +-----BEGIN PGP PUBLIC KEY BLOCK----- +Version: BCPG v1.68 + +mQENBF+242IBCADRO5E77O+3zYLz2iYkOuIfmnrx31GjdLHGzWpX5WDin/PlTGnD +uUk2JoNwFCmHgAh6waBYVnjsaRTaAaj4W/22APeEQLK1Bfi8sBn1PPKsGDf/4f6s +ZsKcJ1INPo9WsN234INyz4YkFFnI7QSeCzqWsk/l0V5vir+cEX3JjQ4nGWluA0/d +BoTXGkGTofUBUt2KflnEn4p2/CXbbwGSpLnESSBdoI0JX2uAUTZvgSnvNjTDZD5c +Yr2o4/4zv7d+3lcHBXdCanuTa1m0nxWnROizqxetilPm5jxk53uhq5zHpamdnHUp +cAif9OhXtU2iUEu13jTd9oUktgVKRTxK8qhVABEBAAG0I0hhcmFsZCBLdWhyIDxo +YXJhbGQua3VockBnbWFpbC5jb20+uQENBF+242IBCAC623pjBREUo5VKRy7fC9Y2 +q5T/bVMJRuOk0FLHNnoxapaWjqpI7lmbfHq4xeRHlTjqs1Z230cW/gIJ2GzjVx2v +ecgo9eXgQu9djl5JtEblZyNZbYrJBik4Sr60Cs5iKpMovPIrEG3xOVTiizs88ca/ +WzuWuQgOiSFyf+XUDmv3JwFbKzpt8rJla6AR0adAr2CqBTJkSf6BgWVcIuGHbWzX +Ldl/+4LNn7hTnnMM+UeaUjnu6j6XTWbf+jn0extF6xJgS1f+3WGo9WyHlh7PXHAv +otJ04dAnR0fQadjS6zNkHzTuOlB6HEacF8szibG6yGWfElPj7N20haeFWPiZ9QXN +ABEBAAGJATwEGAEIACYCGwwWIQRFPqMTKN59iqpVrU7VbHIcHP8UJAUCY3uxyAUJ +B4c1ZgAKCRDVbHIcHP8UJNr5B/4p8PxIfUoQsshBcAYun4776BfNoM7OVzHQJyqz +Q3TcJUqspyHnROXBhQay212p1ft1u10QU4gB1JsK6T31OUxzwbHSUseqxS+ZBOrJ +Vt5C+PdhuhMXJonKPUNy+mSPb0lfOFb911/v4HgKCwwFpAr3X+A2a3FMgXE2pHYd +MTCt428cnKugiXBF8fPRk1MJgyg2Ykp188V2NCiE/H0k1eaqFP97VxFycPrFHii7 +1II4THdhIa9yo9TVPNjTMdaZRj4i/7yzTAhE3MgcllM2x6YQqzuYR+djQI7isATu +QOxHvi176qvZwDv4UEG6LbzRjCxEP+6ImXUfIBvlx/MM3EUiiQE8BBgBCAAmFiEE +RT6jEyjefYqqVa1O1WxyHBz/FCQFAl+242ICGwwFCQPCZwAACgkQ1WxyHBz/FCRg +3gf+KNRDkSlwwENVg+j14xlIKiwQad4I6/+HDjuAmhtWlTJCrrpQrJgxgyOSdXs5 +cm5ZEY/KEsFWjEz9dRqtmKN7W0wCkwAF0vl4sez73sZyD3X5z42vxF2JLavdUruY +03mKS5w1Umjwy7StcRWEdl/1hBBuV/U30vSslyuWkXNoqoBLYOR+Q0KjdkSeUpfv +jFNQROOg9dLKrCzmeF3O1HN/iDEe6K6bvSly3S8/f3OkdvE4VocZ7+ketcrg5lmN +lzltDy5yfsvU2/VVjGdI48J6i33CahJYT8diQcd+y7jH1B3bC+OZ0Jk3SIK97udJ +tJscrv0/jtIwo5zy8SqldnhB6g== +=OReJ +-----END PGP PUBLIC KEY BLOCK----- + pub D7C92B70FA1C814D uid Matthew Sicker (Signing Key) @@ -2953,6 +2989,43 @@ rg1uIDOAX2LIQbC3qLz9iwD2rdbOLOkCQDYIa5Vs3j3RT/cw1A== =r0Sk -----END PGP PUBLIC KEY BLOCK----- +pub ECEAC3B11AD0E0A0 +uid Priyanka + +sub 33BA5E7DBAA319CC +-----BEGIN PGP PUBLIC KEY BLOCK----- +Version: BCPG v1.68 + +mQGNBF+zYT4BDADOvqnDCp47DHqAxbJ5DmnKetnYyhJwNo4S5l+Wlx6x5lVJPR+7 +w6KfHXPDlBgoHJp3j0w6zWijHzGX1eK4Z4c95pE6S+7v/qM4otItJte+bYMNd+Lm +VkYVVaBwWUxI0vVlgqojRUvrQGPhey+iEfcGrp28xHpuZtoXE0GUjlAaSowp9sBm +SNxR3NMTXcE1joigGquwRzuSSXaFCTcCKdZ+xyvnjBpr+oVXv0WHfvGPhlgYKylq +jBaZGE88Wp20TZ7DQaMaP6XmZg6nSB0iKo1HO+VDMHgne/QvBiXEnkw72YnDEfk+ +eNomIvrumfhWfnC3SOqWY7k1FuKQrtbBdOhUTcqTaUFCezWoZ403jxc9DoKYDZvG +5LjQ07wcwrnB9ldBsyvdLqujp+LKcS+9KZMTGOnzyTQyyjpRHqFtP/zzZpNW5EWd +MIk51PebfGuBwCa+RgE8CSuEwoNhdA+GAqhr20Fivf4OJ134qm0xPmLmx/WYlugL +GnZgRfFjlv7bKgkAEQEAAbQdUHJpeWFua2EgPHByaWd1cHRhQGFkb2JlLmNvbT65 +AY0EX7NhPgEMANX4DBl2KhJ+52g6ehpK9f76xDWMd2J75qaY59feSN1+1D48dbVu +0YgHjdCOh5xk2KcKKo3oY3a/L4GFlucWvnnvwQAVKuZZSS2nP5ZTepFKah8pElWM +gtx2Bd+XgV5JCZgNSB+7LPXlBltcbPEdaguDbORCmy/ACuVEJ/IcJgDCpBWVjF8q +zmC47vCEUKSdcsZ2EIYr0tqrZYAt6AtNBlpV8EbrBgGIKmIxeg3b7Las8cj+0pQG +K2Nuszfpku2+HA7QlaaH2/W+sV8Hi0U7Hq/MRtx4V3+W8l3FzA+il0FVGijQgE3U +QoNpTy5Tl5Ic1yVw4gOFy6TreMNr3KbEU+J2MGtgPnbde8LuZ016NdmnA05/AzJ3 +CJ5aCyj/h5k5q4YRA0S0osqm47D8ooIZPGZ7LMVqrjm3vIuoJXav6rAmTgNnHU2N +CGHWMsMDOPfpG7dNMfn0aAb2DL9JNMdqEPTWOGhEqsXupvLSNe/mKxyN19fzIWst +pX2mWjBUtcTNFwARAQABiQG8BBgBCAAmFiEE71IUrWVM0F8NqRYJ7OrDsRrQ4KAF +Al+zYT4CGwwFCQPCZwAACgkQ7OrDsRrQ4KAwfAv/YfM2nS/19QDxnfgSaJAXdtit +OoXzIBVqZ44Z5LgqRkloLm/kSzOhzX53yxwAvVDkaH//5GUp7jqIg21ejULOfewC +Upbth1x9XUnOA55Tz54Z3Emfnshbp04XVj5V+7VJG0UoRfOl8typI2/RPN0h0rQD +KxO2h8cuIP9vlGY1AXFP9mirI02BLdm1S7ugAchrfEcvmKwXPcltlDA487S01iSd +nDSBOtAvIVIrpkV5eIu0e58KbdxLiqP+dvpvQyGRFx3ktOIoStqx5Qea+/ZX8uxI +X7cDvdPbYmi4jel/RfIg07HDjjLjGDnfUDw2gwHdlySWd/przYqAocjJUB+0tCc3 +kV4CM2caga5PRHuYRoFl/UeCKgZfH20jNjq6Fw88s5jlzMDyfGB5oBU1S9F5fiV1 +qQhnaRFDkP2iG/CN9kbL90vRVANHVw9odIiS4Yd3sTX2vnx4eP+6h4ynXL0p01y4 +K+jUtu4w+gsJ3GJvywKbXKy6DkVXcc+umnc318/Y +=UhYJ +-----END PGP PUBLIC KEY BLOCK----- + pub EE9E7DC9D92FC896 uid Eddie Aftandilian @@ -3208,6 +3281,35 @@ VDzc34e+Nr/b2pN05MDHA0dXmb/irwPBl0mTOgAgC805qkR14xhd1GeL6MEA34k8 =CmMl -----END PGP PUBLIC KEY BLOCK----- +pub FB63BCA973FAA119 +uid potato + +sub 28ECAB16140A23E5 +-----BEGIN PGP PUBLIC KEY BLOCK----- +Version: BCPG v1.68 + +mQENBFv8rqkBCAC8J4YBW1ZjXpovURQJcMd0kYgEjVzV0GHHVp9/NJwQ7NrhqGeE +ktSZV4ctxWoPXYqAMbCjqyRfXQw28olj7L55m1VUIT10i20uDixdeDmAPcI5d1z9 +yljknFcOWSUBX+cYUKiYmel1Xb8l8qlzp31jL7TJdeW7fyYBiQqoxgHzAbc8ju8S +TymAVhf8vCee21C/ppAU0uhK7yVi3Liuhjl3jKDFRz0j9MkmrHeKxr+LLZfAZI9M +UCShsmm66anJThtnvxqod/186/7LbNsOfhbb6zCAfPTmb9EB9AncFwNgW4OR+f/C +yAZfr+sIDywrtOt3LXj0yaIYxGEIwXzxJW0xABEBAAG0GHBvdGF0byA8emg3OTMy +NUAxNjMuY29tPrkBDQRb/K6pAQgA4QmtZ8QjosaPwwTGG2w5wVWG/gtvclcJO/ns +wlhWSDiVjmyMknDzP2/sKT50MGzFLf1Fd1B39keYcKoRVyonV0LtZ8KlWgNipi7h +b9MGfrYotVQsP0XWhqUVJE80SBvOiWwAnind07SP2Ivl5jlbrgsIzvO2JpGTzraQ +Ae+AyKkVaqWXc7EOw8kuU9Q5rcagcSLyl3/9K9vP1wYcXo5qfiWc9I1dAnsPOTyY +S9ajFRY20+7yP5Fbsl6MyP7kYHSdfLSmEwzdQrSgaZQbNE+63eNA0vzWXmbpc/A+ +hq4SMK87qKJMAkd8Aaba+U7icBJqmONdZyM1YiqOVrnnjL+QAwARAQABiQE8BBgB +CAAmFiEEUiV1UMUMAD+K0c9/+2O8qXP6oRkFAlv8rqkCGwwFCQPCZwAACgkQ+2O8 +qXP6oRnpeAf/UUxitjRhq7ueiq4pz3mJNwX9M2BbLLkg1dR80MGHGAACb2DaOTXg +Sb1H4ZkB9JzrJKXUJB5J4f2BB/yrDQKmS+szgSd+NeQyFs+r6VSDiSwpnye8yDJg +E6AhGzo5HKFHu17N1w6NGkAQBL+GEgvtojbZDaPzpRSu78rIP2rFymeCiL83eZgP +nqAgKXI+jMiAGQwn8z2TbaiaKHmKKNm4GTZOEfjIkMOLNDt+th82/rLA9cJk+Gna +Q7Q6jnMm02XFBUIiIOCDTzK9BSCAV7SVAwfdlO3Be1KNITO/Rsx4LpHbRMyEf7u8 +3ZOclcevOY17eceSCwjy3C4mU9FhaByKkg== +=kRMk +-----END PGP PUBLIC KEY BLOCK----- + pub FD116C1969FCCFF3 uid Sean Leary @@ -3383,6 +3485,35 @@ kYlgaHe+RYIWqM1P1t8RfE7OH4kAeRSawjrQjgVp =Uv6G -----END PGP PUBLIC KEY BLOCK----- +pub 02DE09238A0E4D34 +uid Drew Noakes + +sub FCF369F756EF6105 +-----BEGIN PGP PUBLIC KEY BLOCK----- +Version: BCPG v1.68 + +mQENBF0gmvMBCADCD96pOjHwsBOztrn7Vy22JMbGIK9LVTk0VC2HLNW/jcl0tTNi +wAIZ7F5Nat9H/fL20dlwvS81W5OlrFImY77HH9qzg+S+WuXlU5ze55kU6RaDWtee +VilasdwWxAMrtcPVo18DjDP+ey+hva8pvArdl3CEuva3gr9idz4GvWrGnkTCagJt +6VRig6XoalF4qVfvI5jkyX2vhUij/adpSXXFcPNcHcBCgUhD7BSgQIXtR/x8iaI8 +/RDCkto0mI/avZQvCjGKO1jleq1zpaD/h2Ga3Mb0hJpOL4HI4HYQcT0Hu0pfcUPx +AJrD1uZrR8h/2fZYtYgDYdpglYp0auZcGeHpABEBAAG0IERyZXcgTm9ha2VzIDxn +cGdAZHJld25vYWtlcy5jb20+uQENBF0gmvMBCAC3lRXIZGaFb9BZfF61dlDzZcpd +ctAN+WV7oLYVY+RECD83wxDqjDBTcsjgBgWXEbTJtaM4wgZ6ae3lQfPLiaL2dpuh +eZRYJx6fuRtYr0z4dqEmvLvoMFujAnb/fKVYm0dpHZw4D50BfDsIrEgMRNwoLJyr +z+rybU+fyygK6liuR6EoFLF2J5mw/WMW3il6Zv/Ly4NWWFvND9VPmiQYglItXXM5 +V5W0ifEe8Ckjajm7HlwqN7rl0MXLLnSGuC8ICB9xJQMOOb4m1wboASDi+yJ+54Gr +5BbrQ20DoWXahFSZhRO+QxEcWfcbB4FeEUSVSmQilZNjXgLKDN6/cMtK870vABEB +AAGJATwEGAEIACYWIQTgGqswFhjSOznb1BAC3gkjig5NNAUCXSCa8wIbDAUJA8Jn +AAAKCRAC3gkjig5NNGX8B/46vKeGgxJ5m+ZnPgi68hUuPM08TkyK6uYD27M60X0g +dVixchk0CRspycmeJvpvTh/6XDOiBStxD0zYcDoKjA7JNhIv3L+FIdP45VlyR6j9 +Ol1nNK9xVL3OifS942Q5vUaprZ+aakXGNfZXBpsVBAbnMrXdCNsjwNrgEZliNnEQ +iDwIQkjgM3c8gIllfn75y6PhYHJDYFj8M0IcWzpqRrCYiR+lqx17U4CavWJJXVfv +/n60Dd6u5MqL3Ket8Pc3bqknLMLzgp0YKlOYylOJpt7zkXz7X1AUSbkV7XfdOtUI +i+e239pgHg1ROFTbISLcgj+kLpKT/eb8cdbtzrx3q7CP +=PaUP +-----END PGP PUBLIC KEY BLOCK----- + pub 0374CF2E8DD1BDFD sub F2E4DE8FA750E060 -----BEGIN PGP PUBLIC KEY BLOCK----- @@ -3882,6 +4013,51 @@ jR7YX5D8RUnPYZnzIzID+ECD0JeFuyBMZI3y8Zog5w1Ce1wnzA== =T2aE -----END PGP PUBLIC KEY BLOCK----- +pub 08A4A4958D61FC3D +uid sksamuel + +sub 54EB00732104EF7A +-----BEGIN PGP PUBLIC KEY BLOCK----- +Version: BCPG v1.68 + +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 +tE3KtJP0/IOVuzK22tPjBdeoI9FptQ== +=c4O7 +-----END PGP PUBLIC KEY BLOCK----- + pub 0B45DDD344B5FFD1 uid Josh Holtz (For maven) @@ -4933,6 +5109,22 @@ HxWaEMJtpSkIvHIBz9qoAroGtNFzz2oF4ElRABEBAAE= =1QGy -----END PGP PUBLIC KEY BLOCK----- +pub 2838A2C567F74226 +uid Seth Tisue + +sub B293A312CEB2E9F6 +-----BEGIN PGP PUBLIC KEY BLOCK----- +Version: BCPG v1.68 + +mDMEYVOgzRYJKwYBBAHaRw8BAQdAPnTbK24vDd1YxFLwAmpdoemwlJMKH7PyGSe/ +ab65sry0JVNldGggVGlzdWUgPHNldGgudGlzdWVAbGlnaHRiZW5kLmNvbT64OARh +U6DNEgorBgEEAZdVAQUBAQdAsh50gWqK3tkXRhXWTv8bKOfUUFs7RLvna3KUwhIX +nXADAQgHiH4EGBYKACYWIQQI7z7CaKgEl+0gMIEoOKLFZ/dCJgUCYVOgzQIbDAUJ +A8JnAAAKCRAoOKLFZ/dCJtYHAQD90Eu8uvLofLKxoY+hbjn+dJ+fzcMZ5I2xoc1s +li442QEAp72J6Hz7p0Vyu1u05NZvb+jLBwWyI0P7Hq2pfR3qFg0= +=rrV8 +-----END PGP PUBLIC KEY BLOCK----- + pub 29579F18FA8FD93B sub 9DF7F2349731D55B -----BEGIN PGP PUBLIC KEY BLOCK----- @@ -6172,6 +6364,22 @@ eKej8y3YRDgQU+O9SrfNjf8PhhpG98C+k/yOh/tty5HGNfdvyMB8TdVxzTd5uHMN =m6Ii -----END PGP PUBLIC KEY BLOCK----- +pub 5365A8A69292AF1A +uid Seth Tisue + +sub 6DAC12FEF3928B80 +-----BEGIN PGP PUBLIC KEY BLOCK----- +Version: BCPG v1.68 + +mDMEYVTpMBYJKwYBBAHaRw8BAQdAgCkGHxDJ2ObI6x5cwp6Cl85hJQ5vIZFH/0+1 +wnaiXA20JVNldGggVGlzdWUgPHNldGgudGlzdWVAbGlnaHRiZW5kLmNvbT64OARh +VOkwEgorBgEEAZdVAQUBAQdAsJWY4kW6HpMZV8X5VYH0oq18gI8vVaQPTK+UXiu3 +FkEDAQgHiH4EGBYKACYWIQRgDSEhmWPyKCAKcjdTZaimkpKvGgUCYVTpMAIbDAUJ +A8JnAAAKCRBTZaimkpKvGlyYAQC0bd1I8QbHqLzhkSv7NyKCh8SDTj/xb9DXPF24 +09RywQEAjKh4ayeMU3KgTAoCps9UZ1tw/tySVUY0qIzV4dDP1w4= +=82EY +-----END PGP PUBLIC KEY BLOCK----- + pub 55C7E5E701832382 -----BEGIN PGP PUBLIC KEY BLOCK----- Version: BCPG v1.68 diff --git a/gradle/verification-metadata.xml b/gradle/verification-metadata.xml index 26dc1b944f..0f79bbb918 100644 --- a/gradle/verification-metadata.xml +++ b/gradle/verification-metadata.xml @@ -7,9 +7,6 @@ - - - @@ -25,6 +22,7 @@ + @@ -50,7 +48,10 @@ - + + + + @@ -92,9 +93,13 @@ + - + + + + @@ -121,12 +126,15 @@ + + + @@ -252,6 +260,7 @@ + @@ -261,6 +270,7 @@ + @@ -300,6 +310,11 @@ + + + + + @@ -308,6 +323,11 @@ + + + + + @@ -316,6 +336,14 @@ + + + + + + + + @@ -329,6 +357,19 @@ + + + + + + + + + + + + + @@ -337,6 +378,11 @@ + + + + + @@ -347,6 +393,14 @@ + + + + + + + + @@ -667,6 +721,11 @@ + + + + + @@ -675,6 +734,19 @@ + + + + + + + + + + + + + @@ -683,6 +755,19 @@ + + + + + + + + + + + + + @@ -691,6 +776,14 @@ + + + + + + + + @@ -699,6 +792,14 @@ + + + + + + + + @@ -707,6 +808,14 @@ + + + + + + + + @@ -715,6 +824,14 @@ + + + + + + + + @@ -723,6 +840,14 @@ + + + + + + + + @@ -731,6 +856,14 @@ + + + + + + + + @@ -739,6 +872,14 @@ + + + + + + + + @@ -747,6 +888,14 @@ + + + + + + + + @@ -855,6 +1004,11 @@ + + + + + @@ -887,6 +1041,11 @@ + + + + + @@ -1102,6 +1261,14 @@ + + + + + + + + @@ -1123,6 +1290,14 @@ + + + + + + + + @@ -1139,6 +1314,14 @@ + + + + + + + + @@ -1147,6 +1330,14 @@ + + + + + + + + @@ -1681,6 +1872,9 @@ + + + @@ -2912,6 +3106,11 @@ + + + + + From d7e52d2b51fb188dcd03d71752d2175a460a38af Mon Sep 17 00:00:00 2001 From: tobiasKaminsky Date: Mon, 29 Jan 2024 11:56:37 +0100 Subject: [PATCH 31/31] Fix test Signed-off-by: tobiasKaminsky --- .../android/ui/fragment/FileDetailFragmentStaticServerIT.kt | 2 ++ 1 file changed, 2 insertions(+) diff --git a/app/src/androidTest/java/com/owncloud/android/ui/fragment/FileDetailFragmentStaticServerIT.kt b/app/src/androidTest/java/com/owncloud/android/ui/fragment/FileDetailFragmentStaticServerIT.kt index 71213ff592..ef8bfaaa98 100644 --- a/app/src/androidTest/java/com/owncloud/android/ui/fragment/FileDetailFragmentStaticServerIT.kt +++ b/app/src/androidTest/java/com/owncloud/android/ui/fragment/FileDetailFragmentStaticServerIT.kt @@ -44,6 +44,8 @@ class FileDetailFragmentStaticServerIT : AbstractIT() { var file = getFile("gps.jpg") val oCFile = OCFile("/").apply { storagePath = file.absolutePath + fileId = 12 + fileDataStorageManager.saveFile(this) } @Test