From 176e0acce23101069d577b82a61d03c5a38ffe0e Mon Sep 17 00:00:00 2001 From: althafvly Date: Wed, 29 Oct 2025 13:14:21 +0530 Subject: [PATCH 01/10] chore: Update gradle dependencies --- .gitlab-ci.yml | 5 +- app/build.gradle | 88 +++++++++++++----------- app/src/main/AndroidManifest.xml | 3 +- build.gradle | 12 ++-- gradle.properties | 4 +- gradle/wrapper/gradle-wrapper.properties | 4 +- settings.gradle | 4 +- 7 files changed, 63 insertions(+), 57 deletions(-) diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index 41652897..2ddf5d1e 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -14,6 +14,7 @@ stages: - gitlab_release before_script: + - export JAVA_HOME=/usr/lib/jvm/java-21-openjdk-amd64 - export GRADLE_USER_HOME=$(pwd)/.gradle - chmod +x ./gradlew @@ -47,7 +48,7 @@ build: fi cd "release" - unsigned_build=$(ls *.apk | grep "unsigned") - - cp $unsigned_build $UNSIGNED_APK + - mv $unsigned_build $UNSIGNED_APK artifacts: paths: - app/build/outputs/apk/ @@ -158,4 +159,4 @@ create-release: ./systemAppsUpdateInfo/scripts/create-release.sh \ "$APK_PATH" "$UNSIGNED_APK" "$COMMUNITY_APK" "$OFFICIAL_APK" allow_failure: true - \ No newline at end of file + diff --git a/app/build.gradle b/app/build.gradle index 91943658..f83bc625 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -35,15 +35,16 @@ def getSentryDsn = { -> } android { - compileSdk 34 + namespace = 'foundation.e.drive' + compileSdk = 36 + defaultConfig { - applicationId "foundation.e.drive" - minSdk 26 - targetSdk 34 - versionCode versionMajor * 1000000 + versionMinor * 1000 + versionPatch - versionName "${versionMajor}.${versionMinor}.${versionPatch}" - setProperty("archivesBaseName", "eDrive-$versionName") - testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" + applicationId = "foundation.e.drive" + minSdk = 26 + targetSdk = 36 + versionCode = versionMajor * 1000000 + versionMinor * 1000 + versionPatch + versionName = "${versionMajor}.${versionMinor}.${versionPatch}" + testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner" manifestPlaceholders = [ 'appAuthRedirectScheme': applicationId, @@ -52,30 +53,26 @@ android { signingConfigs { debugConfig { - storeFile file("../keystore/platform.keystore") - storePassword 'android' - keyAlias 'platform' - keyPassword 'android' + storeFile = file("../keystore/platform.keystore") + storePassword = 'android' + keyAlias = 'platform' + keyPassword = 'android' } } buildTypes { release { - minifyEnabled false - proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' + minifyEnabled = false + proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro' buildConfigField("String", "SENTRY_DSN", "\"${getSentryDsn()}\"") } debug { - signingConfig signingConfigs.debugConfig + signingConfig = signingConfigs.debugConfig buildConfigField("String", "SENTRY_DSN", "\"dummy\"") } } - kotlinOptions { - jvmTarget = "11" - } - testOptions { unitTests { returnDefaultValues = true @@ -87,12 +84,19 @@ android { } } } + buildFeatures { - viewBinding true + buildConfig = true + viewBinding = true } + compileOptions { - sourceCompatibility JavaVersion.VERSION_11 - targetCompatibility JavaVersion.VERSION_11 + sourceCompatibility = JavaVersion.VERSION_21 + targetCompatibility = JavaVersion.VERSION_21 + } + + kotlinOptions { + jvmTarget = "21" } } @@ -102,35 +106,35 @@ dependencies { exclude group: 'com.github.bitfireAT', module: 'dav4jvm' exclude group: 'org.ogce', module: 'xpp3' // unused in Android and brings wrong Junit version } - + implementation "commons-httpclient:commons-httpclient:3.1@jar" implementation fileTree(include: ['*.jar'], dir: 'libs') - api 'androidx.annotation:annotation:1.7.0' - implementation 'androidx.appcompat:appcompat:1.6.1' - implementation "androidx.constraintlayout:constraintlayout:2.1.4" - implementation 'com.google.android.material:material:1.10.0' - implementation 'com.github.bumptech.glide:glide:4.15.1' - implementation 'com.github.bumptech.glide:annotations:4.15.1' - implementation 'androidx.core:core-ktx:1.12.0' - annotationProcessor 'com.github.bumptech.glide:compiler:4.15.1' - implementation "androidx.work:work-runtime:2.9.0" - implementation 'androidx.test:core:1.5.0' + api 'androidx.annotation:annotation:1.9.1' + implementation 'androidx.appcompat:appcompat:1.7.1' + implementation "androidx.constraintlayout:constraintlayout:2.2.1" + implementation 'com.google.android.material:material:1.13.0' + implementation 'com.github.bumptech.glide:glide:5.0.5' + implementation 'com.github.bumptech.glide:annotations:5.0.5' + implementation 'androidx.core:core-ktx:1.17.0' + annotationProcessor 'com.github.bumptech.glide:compiler:5.0.5' + implementation "androidx.work:work-runtime:2.11.0" + implementation 'androidx.test:core:1.7.0' implementation 'com.jakewharton.timber:timber:5.0.1' implementation 'foundation.e:elib:0.0.1-alpha11' implementation 'foundation.e.lib:telemetry:1.0.1-release' - androidTestImplementation 'androidx.test:runner:1.5.2' - androidTestImplementation 'androidx.test:rules:1.5.0' - androidTestImplementation 'androidx.annotation:annotation:1.7.0' - androidTestImplementation 'androidx.test.espresso:espresso-core:3.5.1' + androidTestImplementation 'androidx.test:runner:1.7.0' + androidTestImplementation 'androidx.test:rules:1.7.0' + androidTestImplementation 'androidx.annotation:annotation:1.9.1' + androidTestImplementation 'androidx.test.espresso:espresso-core:3.7.0' androidTestImplementation 'junit:junit:4.13.2' - testImplementation 'androidx.test:runner:1.5.2' - testImplementation 'androidx.test:rules:1.5.0' + testImplementation 'androidx.test:runner:1.7.0' + testImplementation 'androidx.test:rules:1.7.0' testImplementation 'junit:junit:4.13.2' - testImplementation 'org.robolectric:robolectric:4.7.3' - testImplementation 'org.mockito:mockito-core:5.0.0' - testImplementation 'androidx.work:work-testing:2.9.0' + testImplementation 'org.robolectric:robolectric:4.16' + testImplementation 'org.mockito:mockito-core:5.20.0' + testImplementation 'androidx.work:work-testing:2.11.0' } diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index a4b19720..a3a1581e 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -1,7 +1,6 @@ + xmlns:tools="http://schemas.android.com/tools"> diff --git a/build.gradle b/build.gradle index 45313851..6948579d 100644 --- a/build.gradle +++ b/build.gradle @@ -1,18 +1,18 @@ // Top-level build file where you can add configuration options common to all sub-projects/modules. plugins { - id 'com.android.application' version '7.1.3' apply false - id 'com.android.library' version '7.1.3' apply false - id 'org.jetbrains.kotlin.android' version '1.8.22' apply false - id 'io.gitlab.arturbosch.detekt' version '1.23.1' + id 'com.android.application' version '8.13.0' apply false + id 'com.android.library' version '8.13.0' apply false + id 'org.jetbrains.kotlin.android' version '2.2.21' apply false + id 'io.gitlab.arturbosch.detekt' version '1.23.8' } -task clean(type: Delete) { +tasks.register('clean', Delete) { delete rootProject.buildDir } subprojects { detekt { - toolVersion = "1.23.1" + toolVersion = "1.23.8" source = files( "src/main/java" diff --git a/gradle.properties b/gradle.properties index c79c8471..795f5ad3 100644 --- a/gradle.properties +++ b/gradle.properties @@ -15,4 +15,6 @@ org.gradle.jvmargs=-Xmx1536m # This option should only be used with decoupled projects. More details, visit # http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects # org.gradle.parallel=true -android.useAndroidX=true \ No newline at end of file +android.useAndroidX=true +android.nonTransitiveRClass=false +android.nonFinalResIds=false \ No newline at end of file diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties index 75a02d86..42929e8b 100644 --- a/gradle/wrapper/gradle-wrapper.properties +++ b/gradle/wrapper/gradle-wrapper.properties @@ -1,6 +1,6 @@ -#Mon Aug 06 14:01:55 CEST 2018 +#Wed Oct 29 12:58:31 IST 2025 distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists +distributionUrl=https\://services.gradle.org/distributions/gradle-9.1.0-bin.zip zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-7.2-all.zip diff --git a/settings.gradle b/settings.gradle index 35988f79..8aca839c 100644 --- a/settings.gradle +++ b/settings.gradle @@ -10,8 +10,8 @@ dependencyResolutionManagement { repositories { google() mavenCentral() - maven { url "https://jitpack.io" } - maven { url 'https://gitlab.e.foundation/api/v4/groups/9/-/packages/maven'} + maven { url = "https://jitpack.io" } + maven { url = 'https://gitlab.e.foundation/api/v4/groups/9/-/packages/maven'} } } rootProject.name = "eDrive" -- GitLab From 7df8bb50362039e6a6a6bffb52f5876d4765fe64 Mon Sep 17 00:00:00 2001 From: althafvly Date: Wed, 29 Oct 2025 13:32:57 +0530 Subject: [PATCH 02/10] chore: Use version catalog --- app/build.gradle | 69 ++++++++++++++++++++------------------- build.gradle | 10 +++--- gradle/libs.versions.toml | 51 +++++++++++++++++++++++++++++ settings.gradle | 1 + 4 files changed, 92 insertions(+), 39 deletions(-) create mode 100644 gradle/libs.versions.toml diff --git a/app/build.gradle b/app/build.gradle index f83bc625..c355dfb2 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -1,6 +1,6 @@ plugins { - id 'com.android.application' - id 'org.jetbrains.kotlin.android' + alias(libs.plugins.android.application) + alias(libs.plugins.kotlin.android) } def versionMajor = 1 @@ -101,40 +101,43 @@ android { } dependencies { - implementation("foundation.e:Nextcloud-Android-Library:2.0.3-u2.17-release") { + implementation fileTree(include: ['*.jar'], dir: 'libs') + + implementation(libs.nextcloud.android.library) { exclude group: 'com.gitlab.bitfireAT', module: 'dav4jvm' // Got from AccountManager exclude group: 'com.github.bitfireAT', module: 'dav4jvm' exclude group: 'org.ogce', module: 'xpp3' // unused in Android and brings wrong Junit version } - implementation "commons-httpclient:commons-httpclient:3.1@jar" - implementation fileTree(include: ['*.jar'], dir: 'libs') - api 'androidx.annotation:annotation:1.9.1' - implementation 'androidx.appcompat:appcompat:1.7.1' - implementation "androidx.constraintlayout:constraintlayout:2.2.1" - implementation 'com.google.android.material:material:1.13.0' - implementation 'com.github.bumptech.glide:glide:5.0.5' - implementation 'com.github.bumptech.glide:annotations:5.0.5' - implementation 'androidx.core:core-ktx:1.17.0' - annotationProcessor 'com.github.bumptech.glide:compiler:5.0.5' - implementation "androidx.work:work-runtime:2.11.0" - implementation 'androidx.test:core:1.7.0' - implementation 'com.jakewharton.timber:timber:5.0.1' - implementation 'foundation.e:elib:0.0.1-alpha11' - implementation 'foundation.e.lib:telemetry:1.0.1-release' - - - androidTestImplementation 'androidx.test:runner:1.7.0' - androidTestImplementation 'androidx.test:rules:1.7.0' - androidTestImplementation 'androidx.annotation:annotation:1.9.1' - androidTestImplementation 'androidx.test.espresso:espresso-core:3.7.0' - androidTestImplementation 'junit:junit:4.13.2' - - testImplementation 'androidx.test:runner:1.7.0' - testImplementation 'androidx.test:rules:1.7.0' - - testImplementation 'junit:junit:4.13.2' - testImplementation 'org.robolectric:robolectric:4.16' - testImplementation 'org.mockito:mockito-core:5.20.0' - testImplementation 'androidx.work:work-testing:2.11.0' + annotationProcessor libs.compiler + + api libs.annotation + + implementation libs.appcompat + implementation(libs.commons.httpclient) { + exclude group: 'commons-logging', module: 'commons-logging' + } + implementation libs.constraintlayout + implementation libs.core + implementation libs.core.ktx + implementation libs.elib + implementation libs.glide + implementation libs.glide.annotations + implementation libs.material + implementation libs.telemetry + implementation libs.timber + implementation libs.work.runtime + + androidTestImplementation libs.annotation + androidTestImplementation libs.espresso.core + androidTestImplementation libs.junit + androidTestImplementation libs.rules + androidTestImplementation libs.runner + + testImplementation libs.junit + testImplementation libs.mockito.core + testImplementation libs.robolectric + testImplementation libs.rules + testImplementation libs.runner + testImplementation libs.work.testing } diff --git a/build.gradle b/build.gradle index 6948579d..012dcc0a 100644 --- a/build.gradle +++ b/build.gradle @@ -1,9 +1,9 @@ // Top-level build file where you can add configuration options common to all sub-projects/modules. plugins { - id 'com.android.application' version '8.13.0' apply false - id 'com.android.library' version '8.13.0' apply false - id 'org.jetbrains.kotlin.android' version '2.2.21' apply false - id 'io.gitlab.arturbosch.detekt' version '1.23.8' + alias(libs.plugins.android.application) apply false + alias(libs.plugins.android.library) apply false + alias(libs.plugins.kotlin.android) apply false + alias(libs.plugins.detekt) } tasks.register('clean', Delete) { @@ -12,8 +12,6 @@ tasks.register('clean', Delete) { subprojects { detekt { - toolVersion = "1.23.8" - source = files( "src/main/java" ) diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml new file mode 100644 index 00000000..a96b43bb --- /dev/null +++ b/gradle/libs.versions.toml @@ -0,0 +1,51 @@ +[versions] +androidGradlePlugin = "8.13.0" +annotation = "1.9.1" +appcompat = "1.7.1" +commonsHttpclient = "3.1" +constraintlayout = "2.2.1" +core = "1.7.0" +coreKtx = "1.17.0" +detekt = "1.23.8" +elib = "0.0.1-alpha11" +espressoCore = "3.7.0" +glide = "5.0.5" +junit = "4.13.2" +kotlin = "2.2.21" +material = "1.13.0" +mockitoCore = "5.20.0" +nextcloudAndroidLibrary = "2.0.3-u2.17-release" +robolectric = "4.16" +telemetry = "1.0.1-release" +timber = "5.0.1" +workRuntime = "2.11.0" + +[libraries] +annotation = { module = "androidx.annotation:annotation", version.ref = "annotation" } +appcompat = { module = "androidx.appcompat:appcompat", version.ref = "appcompat" } +commons-httpclient = { module = "commons-httpclient:commons-httpclient", version.ref = "commonsHttpclient" } +compiler = { module = "com.github.bumptech.glide:compiler", version.ref = "glide" } +constraintlayout = { module = "androidx.constraintlayout:constraintlayout", version.ref = "constraintlayout" } +core = { module = "androidx.test:core", version.ref = "core" } +core-ktx = { module = "androidx.core:core-ktx", version.ref = "coreKtx" } +elib = { module = "foundation.e:elib", version.ref = "elib" } +espresso-core = { module = "androidx.test.espresso:espresso-core", version.ref = "espressoCore" } +glide = { module = "com.github.bumptech.glide:glide", version.ref = "glide" } +glide-annotations = { module = "com.github.bumptech.glide:annotations", version.ref = "glide" } +junit = { module = "junit:junit", version.ref = "junit" } +material = { module = "com.google.android.material:material", version.ref = "material" } +mockito-core = { module = "org.mockito:mockito-core", version.ref = "mockitoCore" } +nextcloud-android-library = { module = "foundation.e:Nextcloud-Android-Library", version.ref = "nextcloudAndroidLibrary" } +robolectric = { module = "org.robolectric:robolectric", version.ref = "robolectric" } +rules = { module = "androidx.test:rules", version.ref = "core" } +runner = { module = "androidx.test:runner", version.ref = "core" } +telemetry = { module = "foundation.e.lib:telemetry", version.ref = "telemetry" } +timber = { module = "com.jakewharton.timber:timber", version.ref = "timber" } +work-runtime = { module = "androidx.work:work-runtime", version.ref = "workRuntime" } +work-testing = { module = "androidx.work:work-testing", version.ref = "workRuntime" } + +[plugins] +android-application = { id = "com.android.application", version.ref = "androidGradlePlugin" } +android-library = { id = "com.android.library", version.ref = "androidGradlePlugin" } +detekt = { id = "io.gitlab.arturbosch.detekt", version.ref = "detekt" } +kotlin-android = { id = "org.jetbrains.kotlin.android", version.ref = "kotlin" } diff --git a/settings.gradle b/settings.gradle index 8aca839c..75188eef 100644 --- a/settings.gradle +++ b/settings.gradle @@ -5,6 +5,7 @@ pluginManagement { mavenCentral() } } + dependencyResolutionManagement { repositoriesMode.set(RepositoriesMode.FAIL_ON_PROJECT_REPOS) repositories { -- GitLab From 4aae5f720f27f8636e59da6dd44d8ab4a0c073a0 Mon Sep 17 00:00:00 2001 From: althafvly Date: Wed, 29 Oct 2025 13:38:08 +0530 Subject: [PATCH 03/10] chore: Drop legacy httpclient usage --- app/build.gradle | 3 --- .../java/foundation/e/drive/account/GetAliasOperation.java | 4 ++-- gradle/libs.versions.toml | 2 -- 3 files changed, 2 insertions(+), 7 deletions(-) diff --git a/app/build.gradle b/app/build.gradle index c355dfb2..2acbb19a 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -114,9 +114,6 @@ dependencies { api libs.annotation implementation libs.appcompat - implementation(libs.commons.httpclient) { - exclude group: 'commons-logging', module: 'commons-logging' - } implementation libs.constraintlayout implementation libs.core implementation libs.core.ktx diff --git a/app/src/main/java/foundation/e/drive/account/GetAliasOperation.java b/app/src/main/java/foundation/e/drive/account/GetAliasOperation.java index 63776386..3003ea0f 100644 --- a/app/src/main/java/foundation/e/drive/account/GetAliasOperation.java +++ b/app/src/main/java/foundation/e/drive/account/GetAliasOperation.java @@ -16,11 +16,11 @@ import com.nextcloud.operations.GetMethod; import com.owncloud.android.lib.common.operations.RemoteOperation; import com.owncloud.android.lib.common.operations.RemoteOperationResult; -import org.apache.commons.httpclient.HttpStatus; import org.json.JSONArray; import org.json.JSONException; import org.json.JSONObject; +import java.net.HttpURLConnection; import java.util.ArrayList; import java.util.HashMap; import java.util.Map; @@ -43,7 +43,7 @@ public class GetAliasOperation extends RemoteOperation> { private final String mID; private boolean isSuccess(int status) { - return (status == HttpStatus.SC_OK); + return status == HttpURLConnection.HTTP_OK; } public GetAliasOperation(@NonNull String id) { diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index a96b43bb..c6ab62b8 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -2,7 +2,6 @@ androidGradlePlugin = "8.13.0" annotation = "1.9.1" appcompat = "1.7.1" -commonsHttpclient = "3.1" constraintlayout = "2.2.1" core = "1.7.0" coreKtx = "1.17.0" @@ -23,7 +22,6 @@ workRuntime = "2.11.0" [libraries] annotation = { module = "androidx.annotation:annotation", version.ref = "annotation" } appcompat = { module = "androidx.appcompat:appcompat", version.ref = "appcompat" } -commons-httpclient = { module = "commons-httpclient:commons-httpclient", version.ref = "commonsHttpclient" } compiler = { module = "com.github.bumptech.glide:compiler", version.ref = "glide" } constraintlayout = { module = "androidx.constraintlayout:constraintlayout", version.ref = "constraintlayout" } core = { module = "androidx.test:core", version.ref = "core" } -- GitLab From ed504f443502b1b1e11f3d34d6ba05c6e621618a Mon Sep 17 00:00:00 2001 From: althafvly Date: Wed, 29 Oct 2025 14:14:56 +0530 Subject: [PATCH 04/10] chore: Fix lint issues --- .../foundation/e/drive/account/AccountAdder.kt | 7 ++++--- .../e/drive/account/AccountRemover.kt | 14 ++++++++------ .../e/drive/activity/AccountsActivity.java | 14 +++++--------- .../e/drive/periodicScan/FullScanWorker.kt | 7 ++++--- .../e/drive/recovery/RecoveryPreferences.kt | 5 +++-- .../e/drive/widgets/EDriveWidget.java | 18 +++++++++++++----- .../main/res/drawable/widget_preview_image.xml | 4 ++-- app/src/main/res/mipmap-anydpi/ic_launcher.xml | 4 +++- app/src/main/res/values-es/strings.xml | 1 + app/src/main/res/values-fr/strings.xml | 10 +++++----- app/src/main/res/values-it/strings.xml | 2 +- app/src/main/res/values-nl/strings.xml | 6 +++--- app/src/main/res/values/strings.xml | 12 ++++++------ lint.xml | 12 ++++-------- 14 files changed, 62 insertions(+), 54 deletions(-) diff --git a/app/src/main/java/foundation/e/drive/account/AccountAdder.kt b/app/src/main/java/foundation/e/drive/account/AccountAdder.kt index 0cbba530..a40a3221 100644 --- a/app/src/main/java/foundation/e/drive/account/AccountAdder.kt +++ b/app/src/main/java/foundation/e/drive/account/AccountAdder.kt @@ -26,6 +26,7 @@ import foundation.e.drive.utils.AppConstants import foundation.e.drive.utils.DavClientProvider import foundation.e.drive.work.WorkLauncher import timber.log.Timber +import androidx.core.content.edit class AccountAdder(private val context: Context) { @@ -48,9 +49,9 @@ class AccountAdder(private val context: Context) { } private fun updateAccountNameOnPreference(name: String) { - preferences.edit() - .putString(AccountManager.KEY_ACCOUNT_NAME, name) - .apply() + preferences.edit { + putString(AccountManager.KEY_ACCOUNT_NAME, name) + } } /** diff --git a/app/src/main/java/foundation/e/drive/account/AccountRemover.kt b/app/src/main/java/foundation/e/drive/account/AccountRemover.kt index fe6acc51..9d8476b7 100644 --- a/app/src/main/java/foundation/e/drive/account/AccountRemover.kt +++ b/app/src/main/java/foundation/e/drive/account/AccountRemover.kt @@ -33,6 +33,7 @@ import foundation.e.drive.utils.AppConstants.SETUP_COMPLETED import foundation.e.drive.utils.DavClientProvider import timber.log.Timber import java.io.File +import androidx.core.content.edit class AccountRemover( private val context: Context, @@ -74,12 +75,13 @@ class AccountRemover( private fun cleanSharedPreferences() { if (!context.applicationContext.deleteSharedPreferences(AppConstants.SHARED_PREFERENCE_NAME)) { //If removal failed, clear all data inside - preferences.edit().remove(AccountManager.KEY_ACCOUNT_NAME) - .remove(AccountManager.KEY_ACCOUNT_TYPE) - .remove(SETUP_COMPLETED) - .remove(INITIAL_FOLDER_NUMBER) - .remove(AppConstants.KEY_LAST_SCAN_TIME) - .apply() + preferences.edit { + remove(AccountManager.KEY_ACCOUNT_NAME) + .remove(AccountManager.KEY_ACCOUNT_TYPE) + .remove(SETUP_COMPLETED) + .remove(INITIAL_FOLDER_NUMBER) + .remove(AppConstants.KEY_LAST_SCAN_TIME) + } } context.applicationContext.deleteSharedPreferences(FailedSyncPrefsManager.PREF_NAME) } diff --git a/app/src/main/java/foundation/e/drive/activity/AccountsActivity.java b/app/src/main/java/foundation/e/drive/activity/AccountsActivity.java index b995fcad..c6f5cf45 100644 --- a/app/src/main/java/foundation/e/drive/activity/AccountsActivity.java +++ b/app/src/main/java/foundation/e/drive/activity/AccountsActivity.java @@ -13,9 +13,6 @@ import static foundation.e.drive.utils.AppConstants.ACCOUNT_DATA_EMAIL; import static foundation.e.drive.utils.AppConstants.ACCOUNT_DATA_NAME; import static foundation.e.drive.utils.AppConstants.ACCOUNT_DATA_TOTAL_QUOTA_KEY; import static foundation.e.drive.utils.AppConstants.ACCOUNT_DATA_USED_QUOTA_KEY; -import static foundation.e.drive.widgets.EDriveWidget.buildIntent; -import static foundation.e.drive.widgets.EDriveWidget.convertIntoMB; -import static foundation.e.drive.widgets.EDriveWidget.dataForWeb; import android.accounts.Account; import android.accounts.AccountManager; @@ -61,7 +58,7 @@ public class AccountsActivity extends AppCompatActivity { binding.toolbar.setNavigationOnClickListener(v -> onBackPressed()); binding.settings.setOnClickListener(v -> { - final Intent settingsIntent = buildIntent("", "") + final Intent settingsIntent = EDriveWidget.buildIntent("", "") .setComponent(new ComponentName( ACCOUNT_MANAGER_PACKAGE_NAME, ACCOUNT_SETTINGS)); startActivity(settingsIntent); @@ -89,8 +86,8 @@ public class AccountsActivity extends AppCompatActivity { binding.name.setText(name); binding.email.setText(email); - binding.progress.setMax(convertIntoMB(totalQuota)); - binding.progress.setProgress(convertIntoMB(usedQuota)); + binding.progress.setMax(EDriveWidget.convertIntoMB(totalQuota)); + binding.progress.setProgress(EDriveWidget.convertIntoMB(usedQuota)); binding.progress.setVisibility(View.VISIBLE); String totalShownQuota = "?"; @@ -141,9 +138,8 @@ public class AccountsActivity extends AppCompatActivity { binding.upgrade.setVisibility(View.VISIBLE); binding.upgrade.setOnClickListener(v -> { - final Intent upgradeIntent = buildIntent(Intent.ACTION_VIEW, - String.format(EDriveWidget.WEBPAGE, email, token, - dataForWeb(totalQuota))); + final Intent upgradeIntent = EDriveWidget.buildIntent(Intent.ACTION_VIEW, + EDriveWidget.buildUpgradeUrl(email, token, totalQuota)); startActivity(upgradeIntent); }); diff --git a/app/src/main/java/foundation/e/drive/periodicScan/FullScanWorker.kt b/app/src/main/java/foundation/e/drive/periodicScan/FullScanWorker.kt index 194dea8d..d309cafb 100644 --- a/app/src/main/java/foundation/e/drive/periodicScan/FullScanWorker.kt +++ b/app/src/main/java/foundation/e/drive/periodicScan/FullScanWorker.kt @@ -29,6 +29,7 @@ import foundation.e.drive.utils.AppConstants.KEY_LAST_SCAN_TIME import foundation.e.drive.utils.CommonUtils import foundation.e.drive.utils.DavClientProvider import timber.log.Timber +import androidx.core.content.edit class FullScanWorker(private val context: Context, private val workerParams: WorkerParameters) : Worker(context, workerParams) @@ -73,9 +74,9 @@ class FullScanWorker(private val context: Context, private val workerParams: Wor syncRequests.putAll(localSyncRequests) Timber.d("${localSyncRequests.size} request collected from device") - prefs.edit() - .putLong(KEY_LAST_SCAN_TIME, System.currentTimeMillis()) - .apply(); + prefs.edit { + putLong(KEY_LAST_SCAN_TIME, System.currentTimeMillis()) + } if (syncRequests.isEmpty()) { Timber.d("Nothing to sync") diff --git a/app/src/main/java/foundation/e/drive/recovery/RecoveryPreferences.kt b/app/src/main/java/foundation/e/drive/recovery/RecoveryPreferences.kt index 8824e778..4b95dab7 100644 --- a/app/src/main/java/foundation/e/drive/recovery/RecoveryPreferences.kt +++ b/app/src/main/java/foundation/e/drive/recovery/RecoveryPreferences.kt @@ -20,6 +20,7 @@ package foundation.e.drive.recovery import android.content.Context import foundation.e.drive.recovery.RecoveryPreferences.RecoveryStatus.RecoveryCompleted import foundation.e.drive.recovery.RecoveryPreferences.RecoveryStatus.RecoveryNeeded +import androidx.core.content.edit object RecoveryPreferences { @@ -44,11 +45,11 @@ object RecoveryPreferences { context.getSharedPreferences(PREFERENCES_NAME, Context.MODE_PRIVATE) when (status) { RecoveryCompleted -> { - preferences.edit().putBoolean(KEY_IS_DATA_ALREADY_RECOVERED, true).apply() + preferences.edit { putBoolean(KEY_IS_DATA_ALREADY_RECOVERED, true) } } RecoveryNeeded -> { - preferences.edit().putBoolean(KEY_IS_DATA_ALREADY_RECOVERED, false).apply() + preferences.edit { putBoolean(KEY_IS_DATA_ALREADY_RECOVERED, false) } } } } diff --git a/app/src/main/java/foundation/e/drive/widgets/EDriveWidget.java b/app/src/main/java/foundation/e/drive/widgets/EDriveWidget.java index 0e9558b4..38bc1b7b 100644 --- a/app/src/main/java/foundation/e/drive/widgets/EDriveWidget.java +++ b/app/src/main/java/foundation/e/drive/widgets/EDriveWidget.java @@ -50,9 +50,6 @@ import timber.log.Timber; * Implementation of App Widget functionality. */ public class EDriveWidget extends AppWidgetProvider { - - public static final String WEBPAGE = - "https://murena.com/ecloud-subscriptions/?username=%s&token=%s¤t-quota=%s&from=wp"; private static final String ADD_ACCOUNT_WEBPAGE = "https://murena.io/signup/e-email-invite"; private static final String ACCOUNT_PROVIDER_EELO = "e.foundation.webdav.eelo"; @@ -70,6 +67,17 @@ public class EDriveWidget extends AppWidgetProvider { private RemoteViews views; private Account account = null; + public static @NonNull String buildUpgradeUrl( + @NonNull String email, + @NonNull String token, + @NonNull String totalQuota) { + return "https://murena.com/ecloud-subscriptions/" + + "?username=" + email + + "&token=" + token + + "¤t-quota=" + dataForWeb(totalQuota) + + "&from=wp"; + } + @NonNull public static String dataForWeb(@NonNull String bytes) { long convertedBytes = 0; @@ -303,8 +311,8 @@ public class EDriveWidget extends AppWidgetProvider { views.setOnClickPendingIntent(R.id.settings, pendingIntentSettings); final PendingIntent pendingIntentUpgrade = PendingIntent.getActivity(context, 0, - buildIntent(Intent.ACTION_VIEW, String.format(WEBPAGE, email, token, - dataForWeb(totalQuota))), PendingIntent.FLAG_IMMUTABLE); + buildIntent(Intent.ACTION_VIEW, buildUpgradeUrl(email, token, + totalQuota)), PendingIntent.FLAG_IMMUTABLE); views.setOnClickPendingIntent(R.id.upgrade, pendingIntentUpgrade); } diff --git a/app/src/main/res/drawable/widget_preview_image.xml b/app/src/main/res/drawable/widget_preview_image.xml index 16319bb0..68fa20fb 100644 --- a/app/src/main/res/drawable/widget_preview_image.xml +++ b/app/src/main/res/drawable/widget_preview_image.xml @@ -16,8 +16,8 @@ --> . --> - + \ No newline at end of file diff --git a/app/src/main/res/values-es/strings.xml b/app/src/main/res/values-es/strings.xml index efcd3e27..f9ff2bd7 100644 --- a/app/src/main/res/values-es/strings.xml +++ b/app/src/main/res/values-es/strings.xml @@ -36,6 +36,7 @@ Sincronizar el canal de trabajador %d archivo a sincronizar + %d archivos a sincronizar %d archivos a sincronizar Notificación sobre el contenido que está en sincronización diff --git a/app/src/main/res/values-fr/strings.xml b/app/src/main/res/values-fr/strings.xml index e8775c8a..aa5f6abc 100644 --- a/app/src/main/res/values-fr/strings.xml +++ b/app/src/main/res/values-fr/strings.xml @@ -4,20 +4,20 @@ Paramètres additionnels du compte Paramètres %1$s copié dans le presse-papier - L\'espace de stockage cloud qui vous est alloué est rempli à 80%. - 99% de l\'espace de stockage cloud qui vous est alloué est utilisé. Merci de faire le nécessaire. - L\'espace de stockage cloud qui vous est alloué est rempli à 90%. + L’espace de stockage cloud qui vous est alloué est rempli à 80%. + 99% de l’espace de stockage cloud qui vous est alloué est utilisé. Merci de faire le nécessaire. + L’espace de stockage cloud qui vous est alloué est rempli à 90%. Votre stockage cloud est presque plein. Votre stockage cloud est plein. Canal de notification eDrive - Aucune connexion internet détectée, le widget se mettra à jour dès qu\'il détectera une connexion + Aucune connexion internet détectée, le widget se mettra à jour dès qu’il détectera une connexion Alias alias Masquer les alias copier •   Créer un compte - S\'identifier + S’identifier Synchronisez vos photos et vidéos \nde façon sécurisée avec le cloud Dernière synchronisation : %1$s diff --git a/app/src/main/res/values-it/strings.xml b/app/src/main/res/values-it/strings.xml index 3322eb1d..8f4c50e1 100644 --- a/app/src/main/res/values-it/strings.xml +++ b/app/src/main/res/values-it/strings.xml @@ -1,7 +1,7 @@ /e/ Drive - Impostazioni aggiuntive per l\'account + Impostazioni aggiuntive per l’account Impostazioni Copiato %1$s negli appunti Hai riempito il tuo spazio di archiviazione cloud al 80%. diff --git a/app/src/main/res/values-nl/strings.xml b/app/src/main/res/values-nl/strings.xml index 2da1bcc2..1dbd24d3 100644 --- a/app/src/main/res/values-nl/strings.xml +++ b/app/src/main/res/values-nl/strings.xml @@ -7,8 +7,8 @@ Abonnement:  Upgraden Laatst gesynchroniseerd: %1$s - Synchroniseer je foto\'s en -\nvideo\'s met de cloud + Synchroniseer je foto’s en +\nvideo’s met de cloud Inloggen Account aanmaken •   @@ -27,7 +27,7 @@ Verberg aliassen %1$s gekopieerd naar klembord Geen internet verbinding gedetecteerd. Widget zal automatisch updaten bij een actieve internet verbinding - Afbeeldingen en video\'s + Afbeeldingen en video’s Applicatie instellingen Sta synchronisatie toe op netwerken met data limiet Mijn Account diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 1ebbd1a2..b0cfba3e 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -1,7 +1,7 @@ /e/ Drive e.foundation.webdav.eelo - Allow files\' sync on metered network + Allow files’ sync on metered network Pictures and videos Application settings @@ -24,19 +24,19 @@ Aliases No internet connection detected, widget will auto update upon active internet connection - eDrive\'s notification - eDrive\'s notification channel + eDrive’s notification + eDrive’s notification channel Your cloud storage is full. Your cloud storage is nearly full. 99% of your allotted cloud storage is used. Please take action. - You\'ve filled your allotted cloud storage up to 90%. - You\'ve filled your allotted cloud storage up to 80%. + You’ve filled your allotted cloud storage up to 90%. + You’ve filled your allotted cloud storage up to 80%. File synchronization %d file to sync %d files to sync - Sync worker\'s channel + Sync worker’s channel Notification about content being synchronized Copied %1$s to clipboard Settings diff --git a/lint.xml b/lint.xml index 405e69b8..89849851 100644 --- a/lint.xml +++ b/lint.xml @@ -1,16 +1,12 @@ - - - - - - - - + + + + -- GitLab From d53853cd53a61178a5a0ab260260876cd6199be7 Mon Sep 17 00:00:00 2001 From: althafvly Date: Wed, 29 Oct 2025 15:14:27 +0530 Subject: [PATCH 05/10] chore: update baseline after Detekt upgrade --- app/detekt-baseline.xml | 21 +++------------------ 1 file changed, 3 insertions(+), 18 deletions(-) diff --git a/app/detekt-baseline.xml b/app/detekt-baseline.xml index 1475cca0..cfa61a75 100644 --- a/app/detekt-baseline.xml +++ b/app/detekt-baseline.xml @@ -1,26 +1,19 @@ - + - EmptyDefaultConstructor:AccountAddedReceiver.kt$AccountAddedReceiver$() - EmptyElseBlock:SyncTask.kt$SyncTask$if (filePath.isEmpty()) return - MagicNumber:FileDiffUtils.kt$FileDiffUtils$1000 MagicNumber:SyncProxy.kt$SyncProxy$1000 MagicNumber:SyncProxy.kt$SyncProxy$18000 MagicNumber:SyncProxy.kt$SyncProxy$3 MagicNumber:SyncProxy.kt$SyncProxy$3600 MagicNumber:SyncProxy.kt$SyncProxy$7200 MagicNumber:SyncWorker.kt$SyncWorker$30 - MaxLineLength:FullScanWorker.kt$FullScanWorker$if (isFileSyncDisabled(account)) return false MaxLineLength:FullScanWorker.kt$FullScanWorker$private MaxLineLength:RootSyncedFolderProvider.kt$RootSyncedFolderProvider$private MaxLineLength:RootSyncedFolderProvider.kt$RootSyncedFolderProvider$private val REMOTE_ROM_SETTINGS_PATH = PATH_SEPARATOR + "Devices" + PATH_SEPARATOR + BRAND + "_" + MODEL + "_" + Build.getSerial() + "/rom_settings/" - MaxLineLength:SyncProxy.kt$SyncProxy$private val syncRequestQueue: ConcurrentLinkedQueue<SyncRequest> = ConcurrentLinkedQueue() //could we use channel instead ? + MaxLineLength:SyncProxy.kt$SyncProxy$private val syncRequestQueue: ConcurrentLinkedQueue<SyncRequest> = ConcurrentLinkedQueue() //could we use channel instead ? MaxLineLength:SyncTask.kt$SyncTask$if - NewLineAtEndOfFile:AccountAddedReceiver.kt$foundation.e.drive.account.receivers.AccountAddedReceiver.kt - NewLineAtEndOfFile:AppConstants.kt$foundation.e.drive.utils.AppConstants.kt NewLineAtEndOfFile:FileDiffUtils.kt$foundation.e.drive.periodicScan.contentScanner.FileDiffUtils.kt - NewLineAtEndOfFile:FileUtils.kt$foundation.e.drive.utils.FileUtils.kt NewLineAtEndOfFile:FullScanWorker.kt$foundation.e.drive.periodicScan.FullScanWorker.kt NewLineAtEndOfFile:RootSyncedFolderProvider.kt$foundation.e.drive.utils.RootSyncedFolderProvider.kt NewLineAtEndOfFile:StateMachine.kt$foundation.e.drive.synchronization.StateMachine.kt @@ -28,16 +21,10 @@ NewLineAtEndOfFile:SyncTask.kt$foundation.e.drive.synchronization.SyncTask.kt NewLineAtEndOfFile:SyncWorker.kt$foundation.e.drive.synchronization.SyncWorker.kt NewLineAtEndOfFile:SyncedFileState.kt$foundation.e.drive.models.SyncedFileState.kt - ReturnCount:AccountAddedReceiver.kt$AccountAddedReceiver$private fun canStart( accountName: String, accountType: String, prefs: SharedPreferences, context: Context ): Boolean ReturnCount:FileDiffUtils.kt$FileDiffUtils$@JvmStatic fun getActionForFileDiff(remoteFile: RemoteFile, fileState: SyncedFileState): Action ReturnCount:FullScanWorker.kt$FullScanWorker$override fun doWork(): Result ReturnCount:FullScanWorker.kt$FullScanWorker$private fun checkStartConditions(account: Account?, prefs : SharedPreferences, requestCollector: SyncRequestCollector): Boolean - ReturnCount:FullScanWorker.kt$FullScanWorker$private fun scanLocalFiles(syncedFolders: List<SyncedFolder>): HashMap<Int, SyncRequest> - ReturnCount:FullScanWorker.kt$FullScanWorker$private fun scanRemoteFiles(account: Account, syncedFolders: List<SyncedFolder>): HashMap<Int, SyncRequest> - ReturnCount:StateMachine.kt$StateMachine$private fun setPeriodicScanState(): Boolean - ReturnCount:SyncProxy.kt$SyncProxy$override fun onPeriodicScanStart(application: Application): Boolean - ReturnCount:SyncProxy.kt$SyncProxy$override fun queueSyncRequest(request: SyncRequest, context: Context): Boolean - ReturnCount:SyncProxy.kt$SyncProxy$override fun startSynchronization(context: Context) + ReturnCount:FullScanWorker.kt$FullScanWorker$private fun scanLocalFiles(syncedFolders: List<SyncedFolder>): HashMap<Int, SyncRequest> ReturnCount:SyncProxy.kt$SyncProxy$private fun skipBecauseOfPreviousFail(request: SyncRequest, context: Context): Boolean ReturnCount:SyncTask.kt$SyncTask$private fun canStart(): Boolean ReturnCount:SyncTask.kt$SyncTask$private fun runDownload(syncWrapper: SyncWrapper): Boolean @@ -48,7 +35,5 @@ TooGenericExceptionCaught:FullScanWorker.kt$FullScanWorker$exception: Exception TooGenericExceptionCaught:SyncWorker.kt$SyncWorker$exception: Exception TooManyFunctions:SyncProxy.kt$SyncProxy : SyncRequestCollectorSyncManager - WildcardImport:AccountAddedReceiver.kt$import foundation.e.drive.work.WorkRequestFactory.* - WildcardImport:SyncTask.kt$import foundation.e.drive.models.SyncRequest.Type.* -- GitLab From a0e5152d915f392e12b6b0bfb61dde227ad45048 Mon Sep 17 00:00:00 2001 From: althafvly Date: Wed, 29 Oct 2025 16:59:57 +0530 Subject: [PATCH 06/10] chore: Build seperate apk for abis --- .gitlab-ci.yml | 2 +- app/build.gradle | 9 +++++++++ 2 files changed, 10 insertions(+), 1 deletion(-) diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index 2ddf5d1e..dd03dbd7 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -47,7 +47,7 @@ build: exit 1 fi cd "release" - - unsigned_build=$(ls *.apk | grep "unsigned") + - unsigned_build=$(ls *.apk | grep "universal-release-unsigned") - mv $unsigned_build $UNSIGNED_APK artifacts: paths: diff --git a/app/build.gradle b/app/build.gradle index 2acbb19a..d5438ea7 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -51,6 +51,15 @@ android { ] } + splits { + abi { + enable true + reset() + include 'armeabi-v7a', 'arm64-v8a', 'x86', 'x86_64' + universalApk true + } + } + signingConfigs { debugConfig { storeFile = file("../keystore/platform.keystore") -- GitLab From 56a7cf0c55a009c3a53517187c39573a1c06304b Mon Sep 17 00:00:00 2001 From: Jonathan Klee Date: Wed, 29 Oct 2025 13:55:23 +0100 Subject: [PATCH 07/10] chore: Add ktlint plugin in Detekt --- app/detekt-baseline.xml | 126 ++++++++++++++++++++++++++++++++++++++ build.gradle | 4 ++ gradle/libs.versions.toml | 1 + 3 files changed, 131 insertions(+) diff --git a/app/detekt-baseline.xml b/app/detekt-baseline.xml index cfa61a75..179702b1 100644 --- a/app/detekt-baseline.xml +++ b/app/detekt-baseline.xml @@ -2,6 +2,63 @@ + AnnotationOnSeparateLine:SyncTask.kt$SyncTask$@Suppress("DEPRECATION") + ArgumentListWrapping:AccountAdder.kt$AccountAdder$( AppConstants.SHARED_PREFERENCE_NAME, Context.MODE_PRIVATE ) + ArgumentListWrapping:AccountRemover.kt$AccountRemover$( AppConstants.SHARED_PREFERENCE_NAME, Context.MODE_PRIVATE ) + ArgumentListWrapping:DownloadFileOperation.kt$DownloadFileOperation$("Local's size $tmpFileSize and remote's size $remoteFileSize " + "of ${remoteFile.remotePath} don't match") + ArgumentListWrapping:DownloadFileOperation.kt$DownloadFileOperation$(context, arrayOf(filePath), arrayOf(remoteFile.mimeType)) + ArgumentListWrapping:DownloadFileOperation.kt$DownloadFileOperation$(illegalArgumentException, "remoteFile's lastModifiedTimestamp : ${remoteFile.modifiedTimestamp}") + ArgumentListWrapping:WorkLauncher.kt$WorkLauncher$(FullScanWorker.UNIQUE_WORK_NAME, ExistingWorkPolicy.KEEP, request) + ArgumentListWrapping:WorkLauncher.kt$WorkLauncher$(FullScanWorker.UNIQUE_WORK_NAME, ExistingWorkPolicy.REPLACE, request) + ArgumentListWrapping:WorkLauncher.kt$WorkLauncher$(OneTimeWorkType.FULL_SCAN, null) + ArgumentListWrapping:WorkLauncher.kt$WorkLauncher$(OneTimeWorkType.LIST_APPS, null) + ArgumentListWrapping:WorkLauncher.kt$WorkLauncher$(OneTimeWorkType.USER_TRIGGERED_FULL_SCAN, null) + ArgumentListWrapping:WorkLauncher.kt$WorkLauncher$(PeriodicScanWorker.UNIQUE_WORK_NAME, ExistingPeriodicWorkPolicy.KEEP, request) + ArgumentListWrapping:WorkRequestFactory.kt$WorkRequestFactory$( PERIODIC_WORK_REPEAT_INTERVAL_IN_MIN, MINUTES) + ArgumentListWrapping:WorkRequestFactory.kt$WorkRequestFactory$( PERIODIC_WORK_REPEAT_INTERVAL_IN_MIN, MINUTES, PERIODIC_SCAN_FLEX_TIME_IN_MIN,MINUTES) + ChainWrapping:DownloadFileOperation.kt$DownloadFileOperation$&& + ChainWrapping:DownloadFileOperation.kt$DownloadFileOperation$|| + ChainWrapping:FileFilterFactory.kt$FileFilterFactory.<no name provided>$&& + ChainWrapping:FileFilterFactory.kt$FileFilterFactory.<no name provided>$|| + ChainWrapping:SyncTask.kt$SyncTask$|| + CommentSpacing:AccountRemover.kt$AccountRemover$//If removal failed, clear all data inside + CommentSpacing:DownloadFileOperation.kt$DownloadFileOperation$//already checked in "isFileUpToDate()" + CommentSpacing:FileEventHandler.kt$FileEventHandler$//File update + CommentSpacing:FileEventHandler.kt$FileEventHandler$//If already in DB + CommentSpacing:FileEventHandler.kt$FileEventHandler$//It's a directory update + CommentSpacing:FileEventHandler.kt$FileEventHandler$//New file discovered + CommentSpacing:FileEventHandler.kt$FileEventHandler$//look for parent + CommentSpacing:FileEventHandler.kt$FileEventHandler$//todo check if really relevant + CommentSpacing:FileEventHandler.kt$FileEventHandler$//todo: if file is already sync disabled, we should probably remove file from DB + CommentSpacing:FileUtils.kt$FileUtils$//todo why not simply always use getAbsolutePath? + CommentSpacing:StateMachine.kt$StateMachine$//todo use it to prevent apps to be blocked in one state + CommentSpacing:SyncProxy.kt$SyncProxy$//1h + CommentSpacing:SyncProxy.kt$SyncProxy$//2h + CommentSpacing:SyncProxy.kt$SyncProxy$//could we use channel instead ? + FinalNewline:FileDiffUtils.kt$foundation.e.drive.periodicScan.contentScanner.FileDiffUtils.kt + FinalNewline:FullScanWorker.kt$foundation.e.drive.periodicScan.FullScanWorker.kt + FinalNewline:RootSyncedFolderProvider.kt$foundation.e.drive.utils.RootSyncedFolderProvider.kt + FinalNewline:StateMachine.kt$foundation.e.drive.synchronization.StateMachine.kt + FinalNewline:SyncProxy.kt$foundation.e.drive.synchronization.SyncProxy.kt + FinalNewline:SyncTask.kt$foundation.e.drive.synchronization.SyncTask.kt + FinalNewline:SyncWorker.kt$foundation.e.drive.synchronization.SyncWorker.kt + FinalNewline:SyncedFileState.kt$foundation.e.drive.models.SyncedFileState.kt + FunctionReturnTypeSpacing:FullScanWorker.kt$FullScanWorker$private fun isFileSyncDisabled(account: Account) : Boolean + FunctionReturnTypeSpacing:SyncedFileState.kt$SyncedFileState$fun isLastEtagStored() : Boolean + ImportOrdering:AccountAdder.kt$import android.accounts.AccountManager import android.content.Context import android.content.SharedPreferences import foundation.e.drive.R import foundation.e.drive.utils.AppConstants import foundation.e.drive.utils.DavClientProvider import foundation.e.drive.work.WorkLauncher import timber.log.Timber import androidx.core.content.edit + ImportOrdering:AccountRemover.kt$import android.accounts.AccountManager import android.app.Application import android.app.NotificationManager import android.content.Context import android.content.SharedPreferences import androidx.work.WorkManager import foundation.e.drive.database.DbHelper import foundation.e.drive.database.FailedSyncPrefsManager import foundation.e.drive.synchronization.SyncProxy import foundation.e.drive.utils.AppConstants import foundation.e.drive.utils.AppConstants.INITIAL_FOLDER_NUMBER import foundation.e.drive.utils.AppConstants.SETUP_COMPLETED import foundation.e.drive.utils.DavClientProvider import timber.log.Timber import java.io.File import androidx.core.content.edit + ImportOrdering:DownloadFileOperation.kt$import android.content.Context import android.media.MediaScannerConnection import com.owncloud.android.lib.common.OwnCloudClient import com.owncloud.android.lib.common.operations.RemoteOperation import com.owncloud.android.lib.common.operations.RemoteOperationResult import com.owncloud.android.lib.common.operations.RemoteOperationResult.ResultCode import com.owncloud.android.lib.resources.files.DownloadFileRemoteOperation import com.owncloud.android.lib.resources.files.model.RemoteFile import foundation.e.drive.database.DbHelper import foundation.e.drive.models.SyncedFileState import foundation.e.drive.utils.AppConstants.CORRUPTED_TIMESTAMP_IN_MILLISECOND import foundation.e.drive.utils.FileUtils import timber.log.Timber import java.io.File import java.util.stream.IntStream.range + ImportOrdering:FullScanWorker.kt$import android.accounts.Account import android.app.Application import android.content.Context import android.content.SharedPreferences import androidx.work.Worker import androidx.work.WorkerParameters import com.owncloud.android.lib.common.operations.RemoteOperationResult import com.owncloud.android.lib.resources.files.model.RemoteFile import foundation.e.drive.account.AccountUtils import foundation.e.drive.database.DbHelper import foundation.e.drive.models.SyncRequest import foundation.e.drive.models.SyncedFolder import foundation.e.drive.periodicScan.contentScanner.LocalContentScanner import foundation.e.drive.periodicScan.contentScanner.LocalFileLister import foundation.e.drive.periodicScan.contentScanner.RemoteContentScanner import foundation.e.drive.synchronization.SyncProxy import foundation.e.drive.synchronization.SyncRequestCollector import foundation.e.drive.utils.AppConstants import foundation.e.drive.utils.AppConstants.KEY_LAST_SCAN_TIME import foundation.e.drive.utils.CommonUtils import foundation.e.drive.utils.DavClientProvider import timber.log.Timber import androidx.core.content.edit + ImportOrdering:RecoveryPreferences.kt$import android.content.Context import foundation.e.drive.recovery.RecoveryPreferences.RecoveryStatus.RecoveryCompleted import foundation.e.drive.recovery.RecoveryPreferences.RecoveryStatus.RecoveryNeeded import androidx.core.content.edit + ImportOrdering:SyncTask.kt$import android.accounts.Account import android.content.Context import com.owncloud.android.lib.common.OwnCloudClient import com.owncloud.android.lib.common.operations.RemoteOperationResult import com.owncloud.android.lib.common.operations.RemoteOperationResult.ResultCode.HOST_NOT_AVAILABLE import com.owncloud.android.lib.common.operations.RemoteOperationResult.ResultCode.NO_NETWORK_CONNECTION import com.owncloud.android.lib.common.operations.RemoteOperationResult.ResultCode.WRONG_CONNECTION import foundation.e.drive.database.DbHelper import foundation.e.drive.database.FailedSyncPrefsManager import foundation.e.drive.models.SyncRequest import foundation.e.drive.models.SyncRequest.Type.UPLOAD import foundation.e.drive.models.SyncRequest.Type.DISABLE_SYNCING import foundation.e.drive.models.SyncRequest.Type.DOWNLOAD import foundation.e.drive.models.SyncWrapper import foundation.e.drive.synchronization.tasks.UploadFileOperation import foundation.e.drive.utils.CommonUtils import timber.log.Timber import java.io.File + ImportOrdering:SyncWorker.kt$import android.accounts.Account import android.content.Context import androidx.work.Worker import androidx.work.WorkerParameters import com.owncloud.android.lib.common.OwnCloudClient import foundation.e.drive.EdriveApplication import foundation.e.drive.account.AccountUtils import foundation.e.drive.utils.DavClientProvider import timber.log.Timber import java.util.concurrent.Executors import java.util.concurrent.Future import java.util.concurrent.TimeUnit import java.util.concurrent.atomic.AtomicInteger + Indentation:DirectoryObserver.kt$DirectoryObserver.Companion$ + Indentation:DownloadFileOperation.kt$DownloadFileOperation$ + Indentation:FileFilterFactory.kt$FileFilterFactory.<no name provided>$ + Indentation:FileUtils.kt$FileUtils$ + Indentation:SyncProxy.kt$SyncProxy$ + Indentation:SyncTask.kt$SyncTask$ + Indentation:SyncedFileState.kt$SyncedFileState$ MagicNumber:SyncProxy.kt$SyncProxy$1000 MagicNumber:SyncProxy.kt$SyncProxy$18000 MagicNumber:SyncProxy.kt$SyncProxy$3 @@ -13,6 +70,19 @@ MaxLineLength:RootSyncedFolderProvider.kt$RootSyncedFolderProvider$private val REMOTE_ROM_SETTINGS_PATH = PATH_SEPARATOR + "Devices" + PATH_SEPARATOR + BRAND + "_" + MODEL + "_" + Build.getSerial() + "/rom_settings/" MaxLineLength:SyncProxy.kt$SyncProxy$private val syncRequestQueue: ConcurrentLinkedQueue<SyncRequest> = ConcurrentLinkedQueue() //could we use channel instead ? MaxLineLength:SyncTask.kt$SyncTask$if + MaximumLineLength:FullScanWorker.kt$FullScanWorker$ + MaximumLineLength:RootSyncedFolderProvider.kt$RootSyncedFolderProvider$ + MaximumLineLength:SyncProxy.kt$SyncProxy$ + MaximumLineLength:SyncTask.kt$SyncTask$ + ModifierListSpacing:FileUtils.kt$FileUtils$@JvmStatic + ModifierListSpacing:StateMachine.kt$StateMachine$@Synchronized + MultiLineIfElse:AccountUtils.kt$AccountUtils$null + MultiLineIfElse:AccountUtils.kt$AccountUtils$splitPremiumGroup[1] + MultiLineIfElse:FileDiffUtils.kt$FileDiffUtils$Action.Skip + MultiLineIfElse:FullScanWorker.kt$FullScanWorker$ArrayList() + MultiLineIfElse:FullScanWorker.kt$FullScanWorker$DbHelper.getAllSyncedFolders(context) + MultiLineIfElse:FullScanWorker.kt$FullScanWorker$DbHelper.getSyncedFolderList(context, false) + MultiLineIfElse:FullScanWorker.kt$FullScanWorker$DbHelper.getSyncedFolderList(context, true) NewLineAtEndOfFile:FileDiffUtils.kt$foundation.e.drive.periodicScan.contentScanner.FileDiffUtils.kt NewLineAtEndOfFile:FullScanWorker.kt$foundation.e.drive.periodicScan.FullScanWorker.kt NewLineAtEndOfFile:RootSyncedFolderProvider.kt$foundation.e.drive.utils.RootSyncedFolderProvider.kt @@ -21,6 +91,25 @@ NewLineAtEndOfFile:SyncTask.kt$foundation.e.drive.synchronization.SyncTask.kt NewLineAtEndOfFile:SyncWorker.kt$foundation.e.drive.synchronization.SyncWorker.kt NewLineAtEndOfFile:SyncedFileState.kt$foundation.e.drive.models.SyncedFileState.kt + NoBlankLineBeforeRbrace:FileUtils.kt$FileUtils$ + NoBlankLineBeforeRbrace:FullScanWorker.kt$FullScanWorker$ + NoBlankLineBeforeRbrace:WorkRequestFactory.kt$WorkRequestFactory$ + NoConsecutiveBlankLines:FileDiffUtils.kt$FileDiffUtils$ + NoConsecutiveBlankLines:StateMachine.kt$StateMachine$ + NoConsecutiveBlankLines:SyncProxy.kt$SyncProxy$ + NoConsecutiveBlankLines:SyncTask.kt$SyncTask$ + NoConsecutiveBlankLines:SyncedFileState.kt$ + NoConsecutiveBlankLines:WorkLauncher.kt$WorkLauncher$ + NoConsecutiveBlankLines:WorkRequestFactory.kt$ + NoMultipleSpaces:DownloadFileOperation.kt$DownloadFileOperation$ + NoMultipleSpaces:FileEventHandler.kt$FileEventHandler$ + NoMultipleSpaces:RootSyncedFolderProvider.kt$RootSyncedFolderProvider$ + NoSemicolons:FileFilterFactory.kt$; + NoSemicolons:SyncProxy.kt$SyncProxy$; + NoTrailingSpaces:DownloadFileOperation.kt$DownloadFileOperation$ + NoTrailingSpaces:StateMachine.kt$StateMachine$ + ParameterListWrapping:DownloadFileOperation.kt$DownloadFileOperation$(private val remoteFile: RemoteFile, private val fileState: SyncedFileState, private val context: Context) + ParameterListWrapping:SyncedFileState.kt$SyncedFileState$(var id: Int, val name: String, val localPath: String, val remotePath: String, var lastEtag: String, var lastModified: Long, val syncedFolderId: Long, val isMediaType: Boolean, var scanScope: Int) ReturnCount:FileDiffUtils.kt$FileDiffUtils$@JvmStatic fun getActionForFileDiff(remoteFile: RemoteFile, fileState: SyncedFileState): Action ReturnCount:FullScanWorker.kt$FullScanWorker$override fun doWork(): Result ReturnCount:FullScanWorker.kt$FullScanWorker$private fun checkStartConditions(account: Account?, prefs : SharedPreferences, requestCollector: SyncRequestCollector): Boolean @@ -31,9 +120,46 @@ ReturnCount:SyncTask.kt$SyncTask$private fun runUpload(syncWrapper: SyncWrapper): Boolean ReturnCount:SyncTask.kt$SyncTask$private fun updateFailureCounter(request: SyncRequest, success: Boolean) ReturnCount:SyncWorker.kt$SyncWorker$override fun doWork(): Result + SpacingAroundColon:DownloadFileOperation.kt$DownloadFileOperation$: + SpacingAroundColon:FullScanWorker.kt$FullScanWorker$: + SpacingAroundColon:RootSyncedFolderProvider.kt$RootSyncedFolderProvider$: + SpacingAroundColon:SyncProxy.kt$SyncProxy$: + SpacingAroundColon:SyncedFileState.kt$SyncedFileState$: + SpacingAroundComma:WorkRequestFactory.kt$WorkRequestFactory$, + SpacingAroundCurly:FullScanWorker.kt$FullScanWorker${ + SpacingAroundCurly:SyncTask.kt$SyncTask${ + SpacingAroundCurly:WorkRequestFactory.kt$PeriodicWorkType$} + SpacingAroundKeyword:DownloadFileOperation.kt$DownloadFileOperation$catch + SpacingAroundKeyword:FileUtils.kt$FileUtils$catch + SpacingAroundKeyword:FullScanWorker.kt$FullScanWorker$catch + SpacingAroundOperators:FullScanWorker.kt$FullScanWorker$?: + SpacingAroundOperators:SyncWorker.kt$SyncWorker$?: + SpacingAroundParens:DownloadFileOperation.kt$DownloadFileOperation$( + SpacingAroundParens:DownloadFileOperation.kt$DownloadFileOperation$) + SpacingAroundParens:FileUtils.kt$FileUtils$) + SpacingAroundParens:SyncedFileState.kt$SyncedFileState$( + SpacingBetweenDeclarationsWithAnnotations:FileDiffUtils.kt$FileDiffUtils$@JvmStatic fun getActionForFileDiff(remoteFile: RemoteFile, fileState: SyncedFileState): Action + SpacingBetweenDeclarationsWithComments:FileDiffUtils.kt$FileDiffUtils$/** * Define what to do of RemoteFile for which we know the Database equivalent * @param remoteFile RemoteFile * @param fileState SyncedFileState instance * @return Action from Enum */ + StringTemplate:SyncedFileState.kt$SyncedFileState$${id} + StringTemplate:SyncedFileState.kt$SyncedFileState$${isMediaType} + StringTemplate:SyncedFileState.kt$SyncedFileState$${lastEtag} + StringTemplate:SyncedFileState.kt$SyncedFileState$${lastModified} + StringTemplate:SyncedFileState.kt$SyncedFileState$${localPath} + StringTemplate:SyncedFileState.kt$SyncedFileState$${name} + StringTemplate:SyncedFileState.kt$SyncedFileState$${remotePath} + StringTemplate:SyncedFileState.kt$SyncedFileState$${scanScope} + StringTemplate:SyncedFileState.kt$SyncedFileState$${syncedFolderId} SwallowedException:FileUtils.kt$FileUtils$e: java.lang.NullPointerException TooGenericExceptionCaught:FullScanWorker.kt$FullScanWorker$exception: Exception TooGenericExceptionCaught:SyncWorker.kt$SyncWorker$exception: Exception TooManyFunctions:SyncProxy.kt$SyncProxy : SyncRequestCollectorSyncManager + Wrapping:DirectoryObserver.kt$DirectoryObserver.Companion$( + Wrapping:DownloadFileOperation.kt$DownloadFileOperation$( + Wrapping:DownloadFileOperation.kt$DownloadFileOperation$-> + Wrapping:FileFilterFactory.kt$FileFilterFactory.<no name provided>$( + Wrapping:SyncTask.kt$SyncTask$( + Wrapping:SyncedFileState.kt$SyncedFileState$( + Wrapping:WorkLauncher.kt$WorkLauncher$( + Wrapping:WorkRequestFactory.kt$WorkRequestFactory$( diff --git a/build.gradle b/build.gradle index 012dcc0a..534e42e4 100644 --- a/build.gradle +++ b/build.gradle @@ -27,3 +27,7 @@ subprojects { basePath = projectDir } } + +dependencies { + detektPlugins libs.detekt.formatting +} diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index c6ab62b8..049d82de 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -26,6 +26,7 @@ compiler = { module = "com.github.bumptech.glide:compiler", version.ref = "glide constraintlayout = { module = "androidx.constraintlayout:constraintlayout", version.ref = "constraintlayout" } core = { module = "androidx.test:core", version.ref = "core" } core-ktx = { module = "androidx.core:core-ktx", version.ref = "coreKtx" } +detekt-formatting = { module = "io.gitlab.arturbosch.detekt:detekt-formatting", version.ref = "detekt" } elib = { module = "foundation.e:elib", version.ref = "elib" } espresso-core = { module = "androidx.test.espresso:espresso-core", version.ref = "espressoCore" } glide = { module = "com.github.bumptech.glide:glide", version.ref = "glide" } -- GitLab From 8a94cffa5e1ca683e7242b3824be12506898a85d Mon Sep 17 00:00:00 2001 From: althafvly Date: Thu, 30 Oct 2025 10:38:12 +0530 Subject: [PATCH 08/10] chore: Bump version to 1.9.0 --- app/build.gradle | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/app/build.gradle b/app/build.gradle index d5438ea7..7ebfcc3e 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -4,8 +4,8 @@ plugins { } def versionMajor = 1 -def versionMinor = 8 -def versionPatch = 1 +def versionMinor = 9 +def versionPatch = 0 def getTestProp(String propName) { def result = "" -- GitLab From de6a1e53b9f3254339cd65ab2f30986bec29e2d5 Mon Sep 17 00:00:00 2001 From: althafvly Date: Thu, 30 Oct 2025 10:47:48 +0530 Subject: [PATCH 09/10] chore: Sign release with platform key --- .gitlab-ci.yml | 2 +- app/build.gradle | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index dd03dbd7..5b8dbb3f 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -47,7 +47,7 @@ build: exit 1 fi cd "release" - - unsigned_build=$(ls *.apk | grep "universal-release-unsigned") + - unsigned_build=$(ls *.apk | grep "universal-release") - mv $unsigned_build $UNSIGNED_APK artifacts: paths: diff --git a/app/build.gradle b/app/build.gradle index 7ebfcc3e..1635e9d2 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -73,6 +73,7 @@ android { release { minifyEnabled = false proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro' + signingConfig = signingConfigs.debugConfig buildConfigField("String", "SENTRY_DSN", "\"${getSentryDsn()}\"") } -- GitLab From c09b7a48adb39eb3ffe51971682d0442f7af70b4 Mon Sep 17 00:00:00 2001 From: althafvly Date: Thu, 30 Oct 2025 10:58:54 +0530 Subject: [PATCH 10/10] chore: Fix layout overlap with status bar --- app/src/main/res/values/style.xml | 1 + 1 file changed, 1 insertion(+) diff --git a/app/src/main/res/values/style.xml b/app/src/main/res/values/style.xml index 52ae0a51..d8f30661 100644 --- a/app/src/main/res/values/style.xml +++ b/app/src/main/res/values/style.xml @@ -13,6 +13,7 @@ @bool/isLight @bool/isLight @color/background + true