From 832dea2b51915c0b59b16eaa3ac23105683e47b2 Mon Sep 17 00:00:00 2001 From: Anggrayudi Hardiannico Date: Fri, 17 Jan 2025 17:28:23 +0700 Subject: [PATCH 1/6] Upgraded target SDK to 35 --- build.gradle | 16 +++++++++------- gradle/wrapper/gradle-wrapper.properties | 2 +- sample/build.gradle | 3 +-- storage/build.gradle | 2 +- 4 files changed, 12 insertions(+), 11 deletions(-) diff --git a/build.gradle b/build.gradle index b0e0fdee..894cdb6f 100644 --- a/build.gradle +++ b/build.gradle @@ -1,16 +1,18 @@ +import org.jetbrains.kotlin.gradle.tasks.KotlinCompile + // Top-level build file where you can add configuration options common to all sub-projects/modules. buildscript { apply from: 'versions.gradle' addRepos(repositories) - ext.kotlin_version = '2.0.0' + ext.kotlin_version = '2.0.21' dependencies { - classpath 'com.android.tools.build:gradle:8.4.1' + classpath 'com.android.tools.build:gradle:8.8.0' classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version" classpath 'com.vanniktech:gradle-maven-publish-plugin:0.22.0' - classpath 'org.jetbrains.dokka:dokka-gradle-plugin:1.7.20' + classpath 'org.jetbrains.dokka:dokka-gradle-plugin:1.8.20' } } @@ -18,7 +20,7 @@ allprojects { addRepos(repositories) //Support @JvmDefault - tasks.withType(org.jetbrains.kotlin.gradle.tasks.KotlinCompile).configureEach { + tasks.withType(KotlinCompile).configureEach { kotlinOptions { freeCompilerArgs = ['-Xjvm-default=all', '-opt-in=kotlin.RequiresOptIn'] jvmTarget = '1.8' @@ -41,11 +43,11 @@ subprojects { afterEvaluate { android { - compileSdkVersion 34 + compileSdkVersion 35 defaultConfig { minSdkVersion 21 - targetSdkVersion 34 + targetSdkVersion 35 versionCode 1 versionName "$VERSION_NAME" testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" @@ -80,5 +82,5 @@ subprojects { } tasks.register('clean', Delete) { - delete rootProject.buildDir + delete rootProject.layout.buildDirectory } \ No newline at end of file diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties index befbbe69..d02422ab 100644 --- a/gradle/wrapper/gradle-wrapper.properties +++ b/gradle/wrapper/gradle-wrapper.properties @@ -3,4 +3,4 @@ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-8.6-all.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-8.10.2-all.zip diff --git a/sample/build.gradle b/sample/build.gradle index a9e7c861..1f210689 100644 --- a/sample/build.gradle +++ b/sample/build.gradle @@ -36,7 +36,6 @@ android { release { minifyEnabled true shrinkResources false - zipAlignEnabled true proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro' signingConfig signingConfigs.release } @@ -50,7 +49,7 @@ android { viewBinding = true } - flavorDimensions "libSource" + flavorDimensions = ["libSource"] productFlavors { local { dimension "libSource" diff --git a/storage/build.gradle b/storage/build.gradle index 8ba4bf7f..fe273698 100644 --- a/storage/build.gradle +++ b/storage/build.gradle @@ -33,7 +33,7 @@ dependencies { api deps.documentfile api deps.coroutines.core api deps.coroutines.android - implementation "androidx.lifecycle:lifecycle-viewmodel-ktx:2.8.2" + implementation "androidx.lifecycle:lifecycle-viewmodel-ktx:2.8.7" testImplementation deps.junit testImplementation deps.mockk From a45164247ee265549d26c657aa0ca394e36bcbb4 Mon Sep 17 00:00:00 2001 From: Anggrayudi Hardiannico Date: Fri, 17 Jan 2025 18:19:22 +0700 Subject: [PATCH 2/6] Migrated to DSL --- build.gradle | 86 ------------- build.gradle.kts | 6 + gradle.properties | 3 +- gradle/libs.versions.toml | 55 +++++++++ gradle/wrapper/gradle-wrapper.properties | 4 +- sample/build.gradle | 86 ------------- sample/build.gradle.kts | 115 ++++++++++++++++++ settings.gradle | 3 - settings.gradle.kts | 26 ++++ storage/build.gradle | 49 -------- storage/build.gradle.kts | 65 ++++++++++ .../storage/file/DocumentFileCompat.kt | 2 +- .../com/anggrayudi/storage/file/FileExt.kt | 4 +- .../com/anggrayudi/storage/ExampleUnitTest.kt | 17 --- versions.gradle | 58 --------- 15 files changed, 274 insertions(+), 305 deletions(-) delete mode 100644 build.gradle create mode 100644 build.gradle.kts create mode 100644 gradle/libs.versions.toml delete mode 100644 sample/build.gradle create mode 100644 sample/build.gradle.kts delete mode 100644 settings.gradle create mode 100644 settings.gradle.kts delete mode 100644 storage/build.gradle create mode 100644 storage/build.gradle.kts delete mode 100644 storage/src/test/java/com/anggrayudi/storage/ExampleUnitTest.kt delete mode 100644 versions.gradle diff --git a/build.gradle b/build.gradle deleted file mode 100644 index 894cdb6f..00000000 --- a/build.gradle +++ /dev/null @@ -1,86 +0,0 @@ -import org.jetbrains.kotlin.gradle.tasks.KotlinCompile - -// Top-level build file where you can add configuration options common to all sub-projects/modules. -buildscript { - apply from: 'versions.gradle' - - addRepos(repositories) - - ext.kotlin_version = '2.0.21' - - dependencies { - classpath 'com.android.tools.build:gradle:8.8.0' - classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version" - classpath 'com.vanniktech:gradle-maven-publish-plugin:0.22.0' - classpath 'org.jetbrains.dokka:dokka-gradle-plugin:1.8.20' - } -} - -allprojects { - addRepos(repositories) - - //Support @JvmDefault - tasks.withType(KotlinCompile).configureEach { - kotlinOptions { - freeCompilerArgs = ['-Xjvm-default=all', '-opt-in=kotlin.RequiresOptIn'] - jvmTarget = '1.8' - } - } -} - -subprojects { - if (name != 'sample') { - apply plugin: "com.vanniktech.maven.publish" - - repositories { - maven { - url = version.toString().endsWith("SNAPSHOT") - ? 'https://oss.sonatype.org/content/repositories/snapshots/' - : 'https://oss.sonatype.org/service/local/staging/deploy/maven2' - } - } - } - - afterEvaluate { - android { - compileSdkVersion 35 - - defaultConfig { - minSdkVersion 21 - targetSdkVersion 35 - versionCode 1 - versionName "$VERSION_NAME" - testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" - vectorDrawables.useSupportLibrary = true - } - - compileOptions { - sourceCompatibility JavaVersion.VERSION_1_8 - targetCompatibility JavaVersion.VERSION_1_8 - } - - buildFeatures { - buildConfig true - } - } - configurations.configureEach { - resolutionStrategy { - // Force Kotlin to use current version - force "org.jetbrains.kotlin:kotlin-stdlib:$kotlin_version" - force "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version" - force "org.jetbrains.kotlin:kotlin-stdlib-jdk8:$kotlin_version" - force "org.jetbrains.kotlin:kotlin-stdlib-common:$kotlin_version" - force "org.jetbrains.kotlin:kotlin-android-extensions-runtime:$kotlin_version" - } - } - // global dependencies for all modules - dependencies { - implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk8:$kotlin_version" - testImplementation "org.jetbrains.kotlin:kotlin-test-junit:$kotlin_version" - } - } -} - -tasks.register('clean', Delete) { - delete rootProject.layout.buildDirectory -} \ No newline at end of file diff --git a/build.gradle.kts b/build.gradle.kts new file mode 100644 index 00000000..844615f1 --- /dev/null +++ b/build.gradle.kts @@ -0,0 +1,6 @@ +// Top-level build file where you can add configuration options common to all sub-projects/modules. +plugins { + alias(libs.plugins.android.application) apply false + alias(libs.plugins.kotlin.android) apply false + alias(libs.plugins.kotlin.compose) apply false +} diff --git a/gradle.properties b/gradle.properties index 84e697f6..e8e8cba7 100644 --- a/gradle.properties +++ b/gradle.properties @@ -19,10 +19,11 @@ android.useAndroidX=true android.enableJetifier=true # Kotlin code style for this project: "official" or "obsolete": kotlin.code.style=official +org.jetbrains.dokka.experimental.gradle.pluginMode=V2EnabledWithHelpers # For publishing: GROUP=com.anggrayudi POM_ARTIFACT_ID=storage -VERSION_NAME=2.0.0-SNAPSHOT +VERSION_NAME=2.1.0-SNAPSHOT RELEASE_SIGNING_ENABLED=false SONATYPE_AUTOMATIC_RELEASE=true SONATYPE_HOST=DEFAULT diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml new file mode 100644 index 00000000..89b2d466 --- /dev/null +++ b/gradle/libs.versions.toml @@ -0,0 +1,55 @@ +[versions] +kotlin = "2.1.20" +activityCompose = "1.10.1" +coroutines = "1.10.2" +mockito = "3.10.0" +powermock = "2.0.9" + +[libraries] +androidx-core = { group = "androidx.core", name = "core-ktx", version = "1.16.0" } +junit = { group = "junit", name = "junit", version = "4.13.2" } +androidx-junit = { group = "androidx.test.ext", name = "junit", version = "1.2.1" } +androidx-espresso-core = { group = "androidx.test.espresso", name = "espresso-core", version = "3.6.1" } +androidx-lifecycle-runtime = { group = "androidx.lifecycle", name = "lifecycle-runtime-ktx", version = "2.9.1" } +androidx-appcompat = { group = "androidx.appcompat", name = "appcompat", version = "1.7.1" } +androidx-activity = { group = "androidx.activity", name = "activity-ktx", version.ref = "activityCompose" } +androidx-activity-compose = { group = "androidx.activity", name = "activity-compose", version.ref = "activityCompose" } +androidx-compose-bom = { group = "androidx.compose", name = "compose-bom", version = "2025.06.00" } +androidx-ui = { group = "androidx.compose.ui", name = "ui" } +androidx-ui-graphics = { group = "androidx.compose.ui", name = "ui-graphics" } +androidx-ui-tooling = { group = "androidx.compose.ui", name = "ui-tooling" } +androidx-ui-tooling-preview = { group = "androidx.compose.ui", name = "ui-tooling-preview" } +androidx-ui-test-manifest = { group = "androidx.compose.ui", name = "ui-test-manifest" } +androidx-ui-test-junit4 = { group = "androidx.compose.ui", name = "ui-test-junit4" } +androidx-material3 = { group = "androidx.compose.material3", name = "material3" } +androidx-multidex = { group = "androidx.multidex", name = "multidex", version = "2.0.1" } +androidx-navigation-compose = { group = "androidx.navigation", name = "navigation-compose", version = "2.9.0" } +androidx-datastore = { group = "androidx.datastore", name = "datastore-preferences-android", version = "1.1.7" } +androidx-preference = { group = "androidx.preference", name = "preference-ktx", version = "1.2.1" } +androidx-document-file = { group = "androidx.documentfile", name = "documentfile", version = "1.1.0" } +androidx-fragment = { group = "androidx.fragment", name = "fragment-ktx", version = "1.8.8" } +material-icons-ext = { group = "androidx.compose.material", name = "material-icons-extended", version = "1.7.8" } + +material-dialogs-files = { group = "com.afollestad.material-dialogs", name = "files", version = "3.3.0" } +material-progress-bar = { group = "me.zhanghai.android.materialprogressbar", name = "library", version = "1.6.1" } +timber = { group = "com.jakewharton.timber", name = "timber", version = "5.0.1" } +coroutines-android = { group = "org.jetbrains.kotlinx", name = "kotlinx-coroutines-android", version.ref = "coroutines" } +coroutines-test = { group = "org.jetbrains.kotlinx", name = "kotlinx-coroutines-test", version.ref = "coroutines" } + +mockk = { group = "io.mockk", name = "mockk", version = "1.13.17" } +kotlin-test = { group = "org.jetbrains.kotlin", name = "kotlin-test", version.ref = "kotlin" } +robolectric = { group = "org.robolectric", name = "robolectric", version = "4.10.3" } +mockito-core = { group = "org.mockito", name = "mockito-core", version.ref = "mockito" } +mockito-inline = { group = "org.mockito", name = "mockito-inline", version.ref = "mockito" } +mockito-all = { group = "org.mockito", name = "mockito-all", version = "1.10.19" } +mockito-kotlin = { group = "com.nhaarman.mockitokotlin2", name = "mockito-kotlin", version = "2.2.0" } +powermock-junit4 = { group = "org.powermock", name = "powermock-module-junit4", version.ref = "powermock" } +powermock-api-mockito = { group = "org.powermock", name = "powermock-api-mockito2", version.ref = "powermock" } + +[plugins] +android-application = { id = "com.android.application", version = "8.9.3" } +kotlin-android = { id = "org.jetbrains.kotlin.android", version.ref = "kotlin" } +kotlin-compose = { id = "org.jetbrains.kotlin.plugin.compose", version.ref = "kotlin" } +ksp = { id = "com.google.devtools.ksp", version = "2.1.20-1.0.32" } +maven-publish = { id = "com.vanniktech.maven.publish", version = "0.22.0" } +dokka = { id = "org.jetbrains.dokka", version = "2.0.0" } diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties index d02422ab..343461a4 100644 --- a/gradle/wrapper/gradle-wrapper.properties +++ b/gradle/wrapper/gradle-wrapper.properties @@ -1,6 +1,6 @@ -#Tue Dec 01 18:57:30 WIB 2020 +#Tue Jun 10 19:14:26 WIB 2025 distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists +distributionUrl=https\://services.gradle.org/distributions/gradle-8.11.1-bin.zip zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-8.10.2-all.zip diff --git a/sample/build.gradle b/sample/build.gradle deleted file mode 100644 index 1f210689..00000000 --- a/sample/build.gradle +++ /dev/null @@ -1,86 +0,0 @@ -apply plugin: 'com.android.application' -apply plugin: 'kotlin-android' - -def properties = new Properties() -properties.load(rootProject.file('local.properties').newDataInputStream()) - -android { - signingConfigs { - def debugKeystore = file("${System.properties['user.home']}${File.separator}.android${File.separator}debug.keystore") - debug { - keyAlias 'androiddebugkey' - keyPassword 'android' - storePassword 'android' - storeFile debugKeystore - } - release { - keyAlias 'androiddebugkey' - keyPassword 'android' - storePassword 'android' - storeFile debugKeystore - } - } - - namespace 'com.anggrayudi.storage.sample' - defaultConfig { - applicationId "com.anggrayudi.storage.sample" - multiDexEnabled true - } - - buildTypes { - debug { - minifyEnabled false - proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro' - signingConfig signingConfigs.debug - } - release { - minifyEnabled true - shrinkResources false - proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro' - signingConfig signingConfigs.release - } - } - - lint { - abortOnError false - } - - buildFeatures { - viewBinding = true - } - - flavorDimensions = ["libSource"] - productFlavors { - local { - dimension "libSource" - getIsDefault().set(true) - } - maven { - dimension "libSource" - configurations.all { - // Check for updates every build - resolutionStrategy.cacheChangingModulesFor 0, 'seconds' - } - } - } -} - -dependencies { - implementation fileTree(dir: "libs", include: ["*.jar"]) - implementation project(":storage") -// localImplementation project(":storage") -// mavenImplementation("$GROUP:$POM_ARTIFACT_ID:$VERSION_NAME") { changing = true } - - implementation deps.core_ktx - implementation deps.appcompat - implementation deps.multidex - - implementation deps.timber - implementation deps.material_progressbar - implementation 'androidx.preference:preference-ktx:1.2.1' - implementation 'com.afollestad.material-dialogs:files:3.3.0' - - //test - testImplementation deps.junit - testImplementation deps.mockk -} \ No newline at end of file diff --git a/sample/build.gradle.kts b/sample/build.gradle.kts new file mode 100644 index 00000000..9fb955ed --- /dev/null +++ b/sample/build.gradle.kts @@ -0,0 +1,115 @@ +plugins { + alias(libs.plugins.android.application) + alias(libs.plugins.kotlin.android) + alias(libs.plugins.kotlin.compose) + alias(libs.plugins.ksp) +} + +android { + namespace = "com.anggrayudi.storage.sample" + compileSdk = 35 + + signingConfigs { + val debugKeystore = + file( + "${System.getProperty("user.home")}${File.separator}.android${File.separator}debug.keystore" + ) + getByName("debug") { + keyAlias = "androiddebugkey" + keyPassword = "android" + storePassword = "android" + storeFile = debugKeystore + } + create("release") { + keyAlias = "androiddebugkey" + keyPassword = "android" + storePassword = "android" + storeFile = debugKeystore + } + } + + defaultConfig { + applicationId = "com.anggrayudi.storage.sample" + minSdk = 21 + targetSdk = 35 + versionCode = 1 + versionName = rootProject.extra["VERSION_NAME"] as String + multiDexEnabled = true + testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner" + } + + buildTypes { + debug { signingConfig = signingConfigs.getByName("debug") } + release { + isMinifyEnabled = true + proguardFiles(getDefaultProguardFile("proguard-android-optimize.txt"), "proguard-rules.pro") + signingConfig = signingConfigs.getByName("release") + } + } + + buildFeatures { + viewBinding = true + compose = true + } + + compileOptions { + sourceCompatibility = JavaVersion.VERSION_11 + targetCompatibility = JavaVersion.VERSION_11 + } + kotlinOptions { jvmTarget = "11" } + + flavorDimensions += "libSource" + productFlavors { + create("local") { dimension = "libSource" } + create("maven") { + dimension = "libSource" + configurations.all { + // Check for updates every build + resolutionStrategy.cacheChangingModulesFor(0, TimeUnit.SECONDS) + } + } + } + + applicationVariants.forEach { variant -> + variant.sourceSets.forEach { + it.javaDirectories += files("build/generated/ksp/${variant.name}/kotlin") + } + } +} + +dependencies { + implementation(project(":storage")) + // implementation("com.anggrayudi:storage:${rootProject.extra["VERSION_NAME"]}") + + implementation(libs.androidx.core) + implementation(libs.androidx.lifecycle.runtime) + implementation(libs.androidx.activity.compose) + implementation(platform(libs.androidx.compose.bom)) + implementation(libs.androidx.ui) + implementation(libs.androidx.ui.graphics) + implementation(libs.androidx.ui.tooling.preview) + implementation(libs.androidx.material3) + implementation(libs.androidx.multidex) + implementation(libs.androidx.navigation.compose) + implementation(libs.androidx.datastore) + implementation(libs.androidx.preference) + implementation(libs.material.icons.ext) + + implementation(libs.timber) + implementation(libs.coroutines.android) + implementation(libs.material.progress.bar) + implementation(libs.material.dialogs.files) + + testImplementation(libs.junit) + testImplementation(libs.coroutines.test) + testImplementation(libs.mockk) + testImplementation(libs.kotlin.test) + + androidTestImplementation(libs.androidx.junit) + androidTestImplementation(libs.androidx.espresso.core) + androidTestImplementation(platform(libs.androidx.compose.bom)) + androidTestImplementation(libs.androidx.ui.test.junit4) + + debugImplementation(libs.androidx.ui.tooling) + debugImplementation(libs.androidx.ui.test.manifest) +} diff --git a/settings.gradle b/settings.gradle deleted file mode 100644 index bc5878b7..00000000 --- a/settings.gradle +++ /dev/null @@ -1,3 +0,0 @@ -include ':storage' -include ':sample' -rootProject.name = "SimpleStorage" \ No newline at end of file diff --git a/settings.gradle.kts b/settings.gradle.kts new file mode 100644 index 00000000..2b2c09d1 --- /dev/null +++ b/settings.gradle.kts @@ -0,0 +1,26 @@ +pluginManagement { + repositories { + google { + content { + includeGroupByRegex("com\\.android.*") + includeGroupByRegex("com\\.google.*") + includeGroupByRegex("androidx.*") + } + } + mavenCentral() + gradlePluginPortal() + } +} + +dependencyResolutionManagement { + repositoriesMode.set(RepositoriesMode.FAIL_ON_PROJECT_REPOS) + repositories { + google() + mavenCentral() + maven { url = uri("https://oss.sonatype.org/content/repositories/snapshots") } + } +} + +rootProject.name = "SimpleStorage" + +include(":sample", ":storage") diff --git a/storage/build.gradle b/storage/build.gradle deleted file mode 100644 index fe273698..00000000 --- a/storage/build.gradle +++ /dev/null @@ -1,49 +0,0 @@ -apply plugin: 'com.android.library' -apply plugin: 'kotlin-android' - -android { - namespace 'com.anggrayudi.storage' - resourcePrefix 'ss_' - - defaultConfig { - consumerProguardFiles "consumer-rules.pro" - } - - buildTypes { - release { - minifyEnabled false - proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro' - } - } - - lint { - abortOnError false - } - - buildFeatures { - viewBinding = true - } -} - -dependencies { - api deps.appcompat - api deps.activity - api deps.core_ktx - api deps.fragment - api deps.documentfile - api deps.coroutines.core - api deps.coroutines.android - implementation "androidx.lifecycle:lifecycle-viewmodel-ktx:2.8.7" - - testImplementation deps.junit - testImplementation deps.mockk - testImplementation deps.robolectric - - // TODO: Replace with MockK after feature "mock java.io.File" has been fixed: https://github.com/mockk/mockk/issues/603 - testImplementation "org.mockito:mockito-core:3.10.0" - testImplementation "org.mockito:mockito-inline:3.10.0" - testImplementation "org.mockito:mockito-all:1.10.19" - testImplementation "com.nhaarman.mockitokotlin2:mockito-kotlin:2.2.0" - testImplementation "org.powermock:powermock-api-mockito2:2.0.9" - testImplementation "org.powermock:powermock-module-junit4:2.0.9" -} diff --git a/storage/build.gradle.kts b/storage/build.gradle.kts new file mode 100644 index 00000000..b5ed5f3e --- /dev/null +++ b/storage/build.gradle.kts @@ -0,0 +1,65 @@ +plugins { + id("com.android.library") + alias(libs.plugins.kotlin.android) + alias(libs.plugins.dokka) + alias(libs.plugins.maven.publish) +} + +android { + namespace = "com.anggrayudi.storage" + compileSdk = 35 + resourcePrefix = "ss_" + + defaultConfig { + minSdk = 21 + consumerProguardFiles("consumer-rules.pro") + } + + testOptions { targetSdk = 35 } + + lint { targetSdk = 35 } + + buildTypes { + release { + isMinifyEnabled = false + proguardFiles(getDefaultProguardFile("proguard-android-optimize.txt"), "proguard-rules.pro") + } + } + + buildFeatures { buildConfig = true } + + compileOptions { + sourceCompatibility = JavaVersion.VERSION_11 + targetCompatibility = JavaVersion.VERSION_11 + } + + kotlinOptions { + jvmTarget = "11" + // Support @JvmDefault + freeCompilerArgs = listOf("-Xjvm-default=all", "-opt-in=kotlin.RequiresOptIn") + } +} + +dependencies { + api(libs.androidx.core) + api(libs.androidx.appcompat) + api(libs.androidx.activity) + api(libs.androidx.fragment) + api(libs.androidx.document.file) + implementation(libs.androidx.lifecycle.runtime) + + implementation(libs.timber) + implementation(libs.coroutines.android) + + testImplementation(libs.junit) + testImplementation(libs.coroutines.test) + testImplementation(libs.mockk) + testImplementation(libs.kotlin.test) + testImplementation(libs.robolectric) + testImplementation(libs.mockito.core) + testImplementation(libs.mockito.inline) + testImplementation(libs.mockito.all) + testImplementation(libs.mockito.kotlin) + testImplementation(libs.powermock.junit4) + testImplementation(libs.powermock.api.mockito) +} diff --git a/storage/src/main/java/com/anggrayudi/storage/file/DocumentFileCompat.kt b/storage/src/main/java/com/anggrayudi/storage/file/DocumentFileCompat.kt index 9669ae9d..8bb01413 100644 --- a/storage/src/main/java/com/anggrayudi/storage/file/DocumentFileCompat.kt +++ b/storage/src/main/java/com/anggrayudi/storage/file/DocumentFileCompat.kt @@ -467,7 +467,7 @@ object DocumentFileCompat { @JvmStatic fun getStorageIds(context: Context): List { val externalStoragePath = SimpleStorage.externalStoragePath - val storageIds = ContextCompat.getExternalFilesDirs(context, null).filterNotNull().map { + val storageIds = context.getExternalFilesDirs(null).filterNotNull().map { val path = it.path if (path.startsWith(externalStoragePath)) { // Path -> /storage/emulated/0/Android/data/com.anggrayudi.storage.sample/files diff --git a/storage/src/main/java/com/anggrayudi/storage/file/FileExt.kt b/storage/src/main/java/com/anggrayudi/storage/file/FileExt.kt index 025304fa..5a0eb085 100644 --- a/storage/src/main/java/com/anggrayudi/storage/file/FileExt.kt +++ b/storage/src/main/java/com/anggrayudi/storage/file/FileExt.kt @@ -152,8 +152,8 @@ fun File.isExternalStorageManager(context: Context) = Build.VERSION.SDK_INT > Bu val Context.writableDirs: Set get() { val dirs = mutableSetOf(dataDirectory) - dirs.addAll(ContextCompat.getObbDirs(this).filterNotNull()) - dirs.addAll(ContextCompat.getExternalFilesDirs(this, null).mapNotNull { it?.parentFile }) + dirs.addAll(obbDirs.filterNotNull()) + dirs.addAll(getExternalFilesDirs(null).mapNotNull { it?.parentFile }) return dirs } diff --git a/storage/src/test/java/com/anggrayudi/storage/ExampleUnitTest.kt b/storage/src/test/java/com/anggrayudi/storage/ExampleUnitTest.kt deleted file mode 100644 index 14ce55c7..00000000 --- a/storage/src/test/java/com/anggrayudi/storage/ExampleUnitTest.kt +++ /dev/null @@ -1,17 +0,0 @@ -package com.anggrayudi.storage - -import org.junit.Test - -import org.junit.Assert.* - -/** - * Example local unit test, which will execute on the development machine (host). - * - * See [testing documentation](http://d.android.com/tools/testing). - */ -class ExampleUnitTest { - @Test - fun addition_isCorrect() { - assertEquals(4, 2 + 2) - } -} \ No newline at end of file diff --git a/versions.gradle b/versions.gradle deleted file mode 100644 index bfd65815..00000000 --- a/versions.gradle +++ /dev/null @@ -1,58 +0,0 @@ -/** - * Shared file between builds so that they can all use the same dependencies and - * maven repositories. - **/ -ext.deps = [:] -def versions = [:] -versions.activity = "1.9.0" -versions.appcompat = "1.7.0" -versions.core_ktx = "1.13.1" -versions.coroutines = "1.8.1" -versions.documentfile = "1.0.1" -versions.fragment = "1.8.0" -versions.junit = "5.9.1" -versions.material_dialogs = "3.3.0" -versions.material_progressbar = "1.6.1" -versions.mockk = "1.13.5" -versions.multidex = "2.0.1" -versions.robolectric = "4.10.3" -versions.timber = "5.0.1" - -ext.versions = versions - -def deps = [:] - -// Google ------------------------------- -deps.activity = "androidx.activity:activity:$versions.activity" -deps.appcompat = "androidx.appcompat:appcompat:$versions.appcompat" -deps.fragment = "androidx.fragment:fragment:$versions.fragment" -deps.core_ktx = "androidx.core:core-ktx:$versions.core_ktx" -deps.multidex = "androidx.multidex:multidex:$versions.multidex" -deps.documentfile = "androidx.documentfile:documentfile:$versions.documentfile" - -def coroutines = [:] -coroutines.core = "org.jetbrains.kotlinx:kotlinx-coroutines-core:$versions.coroutines" -coroutines.android = "org.jetbrains.kotlinx:kotlinx-coroutines-android:$versions.coroutines" -coroutines.test = "org.jetbrains.kotlinx:kotlinx-coroutines-test:$versions.coroutines" -deps.coroutines = coroutines - -// Testing ------------------------------ -deps.junit = "org.junit.jupiter:junit-jupiter-engine:$versions.junit" -deps.robolectric = "org.robolectric:robolectric:$versions.robolectric" -deps.mockk = "io.mockk:mockk:$versions.mockk" - -// Others ------------------------------- -deps.material_dialogs = "com.afollestad.material-dialogs:core:$versions.material_dialogs" -deps.material_progressbar = "me.zhanghai.android.materialprogressbar:library:$versions.material_progressbar" -deps.timber = "com.jakewharton.timber:timber:$versions.timber" - -// End of dependencies ------------------ -ext.deps = deps - -def addRepos(RepositoryHandler handler) { - handler.google() - handler.mavenCentral() - handler.maven { url 'https://oss.sonatype.org/content/repositories/snapshots' } -} - -ext.addRepos = this.&addRepos \ No newline at end of file From 70c0dd92b18a0c2459ffb2e0a0450cc1dcdfe19e Mon Sep 17 00:00:00 2001 From: Anggrayudi Hardiannico Date: Wed, 11 Jun 2025 00:15:07 +0700 Subject: [PATCH 3/6] Reformat code with ktfmt (Google style) --- .../java/com/anggrayudi/storage/sample/App.kt | 10 +- .../storage/sample/StorageInfoAdapter.kt | 112 +- .../storage/sample/activity/BaseActivity.kt | 55 +- .../activity/FileCompressionActivity.kt | 215 +- .../activity/FileDecompressionActivity.kt | 176 +- .../storage/sample/activity/JavaActivity.java | 26 +- .../storage/sample/activity/MainActivity.kt | 1660 +++--- .../sample/activity/SampleFragmentActivity.kt | 11 +- .../sample/activity/SettingsActivity.kt | 16 +- .../storage/sample/fragment/SampleFragment.kt | 153 +- .../sample/fragment/SettingsFragment.java | 10 +- .../storage/sample/ExampleUnitTest.kt | 10 +- storage/src/main/AndroidManifest.xml | 3 +- .../com/anggrayudi/storage/ActivityWrapper.kt | 25 +- .../storage/ComponentActivityWrapper.kt | 39 +- .../anggrayudi/storage/ComponentWrapper.kt | 9 +- .../com/anggrayudi/storage/FileWrapper.kt | 115 +- .../com/anggrayudi/storage/FragmentWrapper.kt | 36 +- .../com/anggrayudi/storage/SimpleStorage.kt | 1253 ++-- .../anggrayudi/storage/SimpleStorageHelper.kt | 759 +-- .../storage/callback/CreateFileCallback.kt | 17 +- .../storage/callback/FilePickerCallback.kt | 27 +- .../storage/callback/FileReceiverCallback.kt | 8 +- .../storage/callback/FolderPickerCallback.kt | 40 +- .../callback/MultipleFilesConflictCallback.kt | 118 +- .../callback/SingleFileConflictCallback.kt | 96 +- .../callback/SingleFolderConflictCallback.kt | 149 +- .../storage/callback/StorageAccessCallback.kt | 62 +- .../storage/extension/ContextExt.kt | 45 +- .../storage/extension/CoroutineExt.kt | 72 +- .../com/anggrayudi/storage/extension/IOExt.kt | 70 +- .../storage/extension/PrimitivesExt.kt | 3 +- .../anggrayudi/storage/extension/TextExt.kt | 77 +- .../anggrayudi/storage/extension/UriExt.kt | 79 +- .../com/anggrayudi/storage/file/CreateMode.kt | 82 +- .../storage/file/DocumentFileCompat.kt | 1881 +++--- .../storage/file/DocumentFileExt.kt | 5060 +++++++++-------- .../storage/file/DocumentFileType.kt | 9 +- .../com/anggrayudi/storage/file/FileExt.kt | 482 +- .../anggrayudi/storage/file/FileFullPath.kt | 174 +- .../com/anggrayudi/storage/file/FileSize.kt | 10 +- .../com/anggrayudi/storage/file/MimeType.kt | 155 +- .../storage/file/PublicDirectory.kt | 116 +- .../com/anggrayudi/storage/file/StorageId.kt | 27 +- .../anggrayudi/storage/file/StorageType.kt | 46 +- .../storage/media/AudioMediaDirectory.kt | 13 +- .../storage/media/FileDescription.kt | 41 +- .../storage/media/ImageMediaDirectory.kt | 7 +- .../com/anggrayudi/storage/media/MediaFile.kt | 1136 ++-- .../anggrayudi/storage/media/MediaFileExt.kt | 394 +- .../storage/media/MediaStoreCompat.kt | 718 ++- .../com/anggrayudi/storage/media/MediaType.kt | 71 +- .../storage/media/VideoMediaDirectory.kt | 7 +- .../permission/ActivityPermissionRequest.kt | 220 +- .../permission/FragmentPermissionRequest.kt | 145 +- .../storage/permission/PermissionCallback.kt | 31 +- .../storage/permission/PermissionReport.kt | 9 +- .../storage/permission/PermissionRequest.kt | 10 +- .../storage/permission/PermissionResult.kt | 7 +- .../storage/result/FilePropertiesResult.kt | 31 +- .../storage/result/MultipleFilesResult.kt | 77 +- .../storage/result/SingleFileResult.kt | 52 +- .../storage/result/SingleFolderResult.kt | 89 +- .../storage/result/ZipCompressionResult.kt | 41 +- .../storage/result/ZipDecompressionResult.kt | 46 +- .../storage/DocumentFileCompatTest.kt | 48 +- .../anggrayudi/storage/SimpleStorageTest.kt | 117 +- .../storage/extension/TextExtKtTest.kt | 141 +- .../storage/file/DocumentFileCompatTest.kt | 176 +- .../anggrayudi/storage/file/FileExtKtTest.kt | 162 +- .../anggrayudi/storage/file/MimeTypeTest.kt | 58 +- 71 files changed, 9602 insertions(+), 7843 deletions(-) diff --git a/sample/src/main/java/com/anggrayudi/storage/sample/App.kt b/sample/src/main/java/com/anggrayudi/storage/sample/App.kt index ee8dbbc7..938a34d2 100644 --- a/sample/src/main/java/com/anggrayudi/storage/sample/App.kt +++ b/sample/src/main/java/com/anggrayudi/storage/sample/App.kt @@ -9,8 +9,8 @@ import timber.log.Timber */ class App : MultiDexApplication() { - override fun onCreate() { - super.onCreate() - Timber.plant(Timber.DebugTree()) - } -} \ No newline at end of file + override fun onCreate() { + super.onCreate() + Timber.plant(Timber.DebugTree()) + } +} diff --git a/sample/src/main/java/com/anggrayudi/storage/sample/StorageInfoAdapter.kt b/sample/src/main/java/com/anggrayudi/storage/sample/StorageInfoAdapter.kt index 8f4b2976..2c82b626 100644 --- a/sample/src/main/java/com/anggrayudi/storage/sample/StorageInfoAdapter.kt +++ b/sample/src/main/java/com/anggrayudi/storage/sample/StorageInfoAdapter.kt @@ -19,71 +19,75 @@ import kotlinx.coroutines.launch /** * Created on 12/14/20 + * * @author Anggrayudi H */ class StorageInfoAdapter( - private val context: Context, - private val ioScope: CoroutineScope, - private val uiScope: CoroutineScope + private val context: Context, + private val ioScope: CoroutineScope, + private val uiScope: CoroutineScope, ) : RecyclerView.Adapter() { - private val storageIds = DocumentFileCompat.getStorageIds(context) + private val storageIds = DocumentFileCompat.getStorageIds(context) - override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder { - return ViewHolder(LayoutInflater.from(parent.context).inflate(R.layout.view_item_storage_info, parent, false)) - } + override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder { + return ViewHolder( + LayoutInflater.from(parent.context).inflate(R.layout.view_item_storage_info, parent, false) + ) + } - @SuppressLint("SetTextI18n") - override fun onBindViewHolder(holder: ViewHolder, position: Int) { - ioScope.launch { - val storageId = storageIds[position] - val storageName = if (storageId == PRIMARY) "External Storage" else storageId - val storageCapacity = Formatter.formatFileSize(context, DocumentFileCompat.getStorageCapacity(context, storageId)) - val storageUsedSpace = Formatter.formatFileSize(context, DocumentFileCompat.getUsedSpace(context, storageId)) - val storageFreeSpace = Formatter.formatFileSize(context, DocumentFileCompat.getFreeSpace(context, storageId)) - uiScope.launch { - holder.run { - tvStorageName.text = storageName - tvStorageCapacity.text = "Capacity: $storageCapacity" - tvStorageUsedSpace.text = "Used Space: $storageUsedSpace" - tvStorageFreeSpace.text = "Free Space: $storageFreeSpace" - btnShowGrantedUri.setOnClickListener { showGrantedUris(it.context, storageId) } - if (storageId == PRIMARY && Build.VERSION.SDK_INT < Build.VERSION_CODES.Q) { - // No URI permission required for external storage - btnShowGrantedUri.visibility = View.GONE - } - } - } + @SuppressLint("SetTextI18n") + override fun onBindViewHolder(holder: ViewHolder, position: Int) { + ioScope.launch { + val storageId = storageIds[position] + val storageName = if (storageId == PRIMARY) "External Storage" else storageId + val storageCapacity = + Formatter.formatFileSize(context, DocumentFileCompat.getStorageCapacity(context, storageId)) + val storageUsedSpace = + Formatter.formatFileSize(context, DocumentFileCompat.getUsedSpace(context, storageId)) + val storageFreeSpace = + Formatter.formatFileSize(context, DocumentFileCompat.getFreeSpace(context, storageId)) + uiScope.launch { + holder.run { + tvStorageName.text = storageName + tvStorageCapacity.text = "Capacity: $storageCapacity" + tvStorageUsedSpace.text = "Used Space: $storageUsedSpace" + tvStorageFreeSpace.text = "Free Space: $storageFreeSpace" + btnShowGrantedUri.setOnClickListener { showGrantedUris(it.context, storageId) } + if (storageId == PRIMARY && Build.VERSION.SDK_INT < Build.VERSION_CODES.Q) { + // No URI permission required for external storage + btnShowGrantedUri.visibility = View.GONE + } } + } } + } - /** - * A storageId may contains more than one granted URIs - */ - @SuppressLint("NewApi") - private fun showGrantedUris(context: Context, filterStorageId: String) { - val grantedPaths = DocumentFileCompat.getAccessibleAbsolutePaths(context)[filterStorageId] - if (grantedPaths == null) { - MaterialDialog(context) - .message(text = "No permission granted on storage ID \"$filterStorageId\"") - .positiveButton() - .show() - } else { - MaterialDialog(context) - .title(text = "Granted paths for \"$filterStorageId\"") - .listItems(items = grantedPaths.toList().sorted()) - .show() - } + /** A storageId may contains more than one granted URIs */ + @SuppressLint("NewApi") + private fun showGrantedUris(context: Context, filterStorageId: String) { + val grantedPaths = DocumentFileCompat.getAccessibleAbsolutePaths(context)[filterStorageId] + if (grantedPaths == null) { + MaterialDialog(context) + .message(text = "No permission granted on storage ID \"$filterStorageId\"") + .positiveButton() + .show() + } else { + MaterialDialog(context) + .title(text = "Granted paths for \"$filterStorageId\"") + .listItems(items = grantedPaths.toList().sorted()) + .show() } + } - override fun getItemCount() = storageIds.size + override fun getItemCount() = storageIds.size - class ViewHolder(view: View) : RecyclerView.ViewHolder(view) { + class ViewHolder(view: View) : RecyclerView.ViewHolder(view) { - internal val tvStorageName = view.findViewById(R.id.tvStorageName) - internal val tvStorageCapacity = view.findViewById(R.id.tvStorageCapacity) - internal val tvStorageUsedSpace = view.findViewById(R.id.tvStorageUsedSpace) - internal val tvStorageFreeSpace = view.findViewById(R.id.tvStorageFreeSpace) - internal val btnShowGrantedUri = view.findViewById