diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 8af8b18..360c8d8 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -1,33 +1,33 @@ name: Deploy Release on: - # Trigger the workflow on push action in develop branch + # Trigger the workflow on push action in main branch # So it will trigger when the PR of the feature branch was merged. push: branches: - main + jobs: app_deploy: name: Deploy and upload to JitPack runs-on: ubuntu-latest + permissions: + contents: write steps: - name: Checkout code - uses: actions/checkout@v2 + uses: actions/checkout@v5 - - name: Read version.properties - uses: madhead/read-java-properties@latest + - name: Extract version from version catalog id: version - with: - file: version.properties - all: true + run: | + VERSION=$(grep '^libVersionName = ' gradle/libs.versions.toml | sed 's/libVersionName = "\(.*\)"/\1/') + echo "versionName=$VERSION" >> $GITHUB_OUTPUT - name: Create Release id: create_release - uses: actions/create-release@v1 - env: - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} # This token is provided by Actions, you do not need to create your own token + uses: softprops/action-gh-release@v2 with: tag_name: '${{ steps.version.outputs.versionName }}' - release_name: 'Release ${{ steps.version.outputs.versionName }}' + name: 'Release ${{ steps.version.outputs.versionName }}' draft: false prerelease: false diff --git a/.github/workflows/review_pull_request.yml b/.github/workflows/review_pull_request.yml index f12ad4f..71195f8 100644 --- a/.github/workflows/review_pull_request.yml +++ b/.github/workflows/review_pull_request.yml @@ -15,15 +15,16 @@ jobs: timeout-minutes: 30 steps: - name: Set up JDK 1.8 - uses: actions/setup-java@v1 + uses: actions/setup-java@v5 with: - java-version: 1.8 + distribution: 'temurin' + java-version: '17' - name: Checkout source code - uses: actions/checkout@v2.3.2 + uses: actions/checkout@v5 - name: Cache Gradle - uses: actions/cache@v2 + uses: actions/cache@v4 with: path: | ~/.gradle/caches/modules-* @@ -44,7 +45,7 @@ jobs: - name: Set up Ruby uses: ruby/setup-ruby@v1 with: - ruby-version: '2.7' + ruby-version: '3.4.6' bundler-cache: true - name: Run Danger to wrap up the review diff --git a/Gemfile.lock b/Gemfile.lock index 7ac4ede..8f44005 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -1,32 +1,50 @@ GEM remote: https://rubygems.org/ specs: - addressable (2.8.0) - public_suffix (>= 2.0.2, < 5.0) + activesupport (8.1.1) + base64 + bigdecimal + concurrent-ruby (~> 1.0, >= 1.3.1) + connection_pool (>= 2.2.5) + drb + i18n (>= 1.6, < 2) + json + logger (>= 1.4.2) + minitest (>= 5.1) + securerandom (>= 0.3) + tzinfo (~> 2.0, >= 2.0.5) + uri (>= 0.13.1) + addressable (2.8.8) + public_suffix (>= 2.0.2, < 8.0) ansi (1.5.0) - ast (2.4.2) - claide (1.0.3) + ast (2.4.3) + base64 (0.3.0) + bigdecimal (3.3.1) + claide (1.1.0) claide-plugins (0.9.2) cork nap open4 (~> 1.3) colored2 (3.1.2) + concurrent-ruby (1.3.5) + connection_pool (3.0.2) cork (0.3.0) colored2 (~> 3.1) - danger (8.4.0) + danger (9.5.3) + base64 (~> 0.2) claide (~> 1.0) claide-plugins (>= 0.9.2) - colored2 (~> 3.1) + colored2 (>= 3.1, < 5) cork (~> 0.1) - faraday (>= 0.9.0, < 2.0) + faraday (>= 0.9.0, < 3.0) faraday-http-cache (~> 2.0) - git (~> 1.7) - kramdown (~> 2.3) + git (>= 1.13, < 3.0) + kramdown (>= 2.5.1, < 3.0) kramdown-parser-gfm (~> 1.0) - no_proxy_fix - octokit (~> 4.7) - terminal-table (>= 1, < 4) - danger-android_lint (0.0.9) + octokit (>= 4.0) + pstore (~> 0.1) + terminal-table (>= 1, < 5) + danger-android_lint (0.0.12) danger-plugin-api (~> 1.0) oga danger-commit_lint (0.0.7) @@ -35,66 +53,72 @@ GEM danger-plugin-api (~> 1.0) danger-plugin-api (1.0.0) danger (> 2.0) - danger-shroud (0.0.3) + danger-shroud (2.0.0) danger-plugin-api (~> 1.0) nokogiri - faraday (1.8.0) - faraday-em_http (~> 1.0) - faraday-em_synchrony (~> 1.0) - faraday-excon (~> 1.1) - faraday-httpclient (~> 1.0.1) - faraday-net_http (~> 1.0) - faraday-net_http_persistent (~> 1.1) - faraday-patron (~> 1.0) - faraday-rack (~> 1.0) - multipart-post (>= 1.2, < 3) - ruby2_keywords (>= 0.0.4) - faraday-em_http (1.0.0) - faraday-em_synchrony (1.0.0) - faraday-excon (1.1.0) - faraday-http-cache (2.2.0) + drb (2.2.3) + faraday (2.14.0) + faraday-net_http (>= 2.0, < 3.5) + json + logger + faraday-http-cache (2.5.1) faraday (>= 0.8) - faraday-httpclient (1.0.1) - faraday-net_http (1.0.1) - faraday-net_http_persistent (1.2.0) - faraday-patron (1.0.0) - faraday-rack (1.0.0) - git (1.9.1) + faraday-net_http (3.4.2) + net-http (~> 0.5) + git (2.3.3) + activesupport (>= 5.0) + addressable (~> 2.8) + process_executer (~> 1.1) rchardet (~> 1.8) - kramdown (2.3.1) - rexml + i18n (1.14.7) + concurrent-ruby (~> 1.0) + json (2.18.0) + kramdown (2.5.1) + rexml (>= 3.3.9) kramdown-parser-gfm (1.1.0) kramdown (~> 2.0) - multipart-post (2.1.1) + logger (1.7.0) + minitest (5.27.0) nap (1.1.0) - no_proxy_fix (0.1.2) - nokogiri (1.12.5-x86_64-darwin) + net-http (0.8.0) + uri (>= 0.11.1) + nokogiri (1.18.10-arm64-darwin) + racc (~> 1.4) + nokogiri (1.18.10-x86_64-darwin) racc (~> 1.4) - nokogiri (1.12.5-x86_64-linux) + nokogiri (1.18.10-x86_64-linux-gnu) racc (~> 1.4) - octokit (4.21.0) - faraday (>= 0.9) - sawyer (~> 0.8.0, >= 0.5.3) - oga (3.3) + octokit (10.0.0) + faraday (>= 1, < 3) + sawyer (~> 0.9) + oga (3.4) ast ruby-ll (~> 2.1) open4 (1.3.4) - public_suffix (4.0.6) - racc (1.5.2) - rchardet (1.8.0) - rexml (3.2.5) - ruby-ll (2.1.2) + process_executer (1.3.0) + pstore (0.2.0) + public_suffix (7.0.0) + racc (1.8.1) + rchardet (1.10.0) + rexml (3.4.4) + ruby-ll (2.1.4) ansi ast - ruby2_keywords (0.0.5) - sawyer (0.8.2) + sawyer (0.9.3) addressable (>= 2.3.5) - faraday (> 0.8, < 2.0) - terminal-table (3.0.2) - unicode-display_width (>= 1.1.1, < 3) - unicode-display_width (2.1.0) + faraday (>= 0.17.3, < 3) + securerandom (0.4.1) + terminal-table (4.0.0) + unicode-display_width (>= 1.1.1, < 4) + tzinfo (2.0.6) + concurrent-ruby (~> 1.0) + unicode-display_width (3.2.0) + unicode-emoji (~> 4.1) + unicode-emoji (4.1.0) + uri (1.1.1) PLATFORMS + arm64-darwin-24 universal-darwin-23 x86_64-darwin-19 x86_64-linux @@ -107,4 +131,4 @@ DEPENDENCIES danger-shroud BUNDLED WITH - 2.2.22 + 2.7.1 diff --git a/app/build.gradle b/app/build.gradle deleted file mode 100644 index c1d4f44..0000000 --- a/app/build.gradle +++ /dev/null @@ -1,42 +0,0 @@ -plugins { - id 'com.android.application' - id 'kotlin-android' -} - -android { - compileSdk 31 - - defaultConfig { - applicationId "co.nimblehq.extensions" - minSdk 21 - targetSdk 31 - versionCode 1 - versionName "1.0" - - testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" - } - - buildTypes { - release { - minifyEnabled false - proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro' - } - } - compileOptions { - sourceCompatibility JavaVersion.VERSION_1_8 - targetCompatibility JavaVersion.VERSION_1_8 - } - kotlinOptions { - jvmTarget = '1.8' - } -} - -dependencies { - - implementation 'androidx.core:core-ktx:1.6.0' - implementation 'androidx.appcompat:appcompat:1.3.1' - implementation 'com.google.android.material:material:1.4.0' - testImplementation 'junit:junit:4.+' - androidTestImplementation 'androidx.test.ext:junit:1.1.3' - androidTestImplementation 'androidx.test.espresso:espresso-core:3.4.0' -} diff --git a/app/build.gradle.kts b/app/build.gradle.kts new file mode 100644 index 0000000..92c43fa --- /dev/null +++ b/app/build.gradle.kts @@ -0,0 +1,53 @@ +import org.jetbrains.kotlin.gradle.dsl.JvmTarget + +plugins { + alias(libs.plugins.android.application) + alias(libs.plugins.kotlin.android) +} + +android { + namespace = "co.nimblehq.extensions" + + compileSdk = libs.versions.androidCompileSdk.get().toInt() + + defaultConfig { + applicationId = "co.nimblehq.extensions" + minSdk = libs.versions.androidMinSdk.get().toInt() + targetSdk = libs.versions.androidTargetSdk.get().toInt() + versionCode = libs.versions.androidVersionCode.get().toInt() + versionName = libs.versions.androidVersionName.get() + + testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner" + } + + buildTypes { + release { + isMinifyEnabled = false + proguardFiles( + getDefaultProguardFile("proguard-android-optimize.txt"), + "proguard-rules.pro" + ) + } + } + + compileOptions { + sourceCompatibility = JavaVersion.VERSION_1_8 + targetCompatibility = JavaVersion.VERSION_1_8 + } + + kotlin { + compilerOptions { + jvmTarget.set(JvmTarget.JVM_1_8) + } + } +} + +dependencies { + implementation(libs.androidx.core.ktx) + implementation(libs.androidx.appcompat) + implementation(libs.material) + + testImplementation(libs.test.junit) + androidTestImplementation(libs.test.ext.junit) + androidTestImplementation(libs.test.espresso.core) +} diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index a608d66..b232e31 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -1,6 +1,5 @@ - + "${module.projectDir}/src/main/java" }) + ) + + parallel = false + buildUponDefaultConfig = false + disableDefaultRuleSets = false + + debug = false + ignoreFailures = false + + ignoredBuildTypes = listOf("release") + ignoredFlavors = listOf("production") +} + +jacoco { + toolVersion = libs.versions.jacoco.get() +} + +val fileGenerated = listOf( + "android/**/*.*", + "**/R.class", + "**/R\$*.class", + "**/*\$ViewBinder*.*", + "**/*\$InjectAdapter*.*", + "**/*Injector*.*", + "**/BuildConfig.*", + "**/Manifest*.*", + "**/*_ViewBinding*.*", + "**/*_Factory*.*", + "**/app/ui/screens/**/*DiffCallback*.*", + "**/*Test*.*", + // navigation component + "**/*FragmentArgs*", + "**/*FragmentDirections*", + "**/FragmentNavArgsLazy.kt", + "**/*Fragment*navArgs*", + "**/screens/common/StartFragment.*", + // kotlin enum Creator + "**/*\$Creator*" +) + +val packagesExcluded = listOf( + "co/nimblehq/extensions/app/**", + "com/bumptech/glide" +) + +val fileFilter = fileGenerated + packagesExcluded + +tasks.register("jacocoTestReport") { + group = "Reporting" + description = "Generate Jacoco coverage reports for Debug build" + + dependsOn(":app:testDebugUnitTest") + dependsOn(":common-ktx:testDebugUnitTest") + + classDirectories.setFrom( + fileTree("${project.rootDir}/app/build/intermediates/javac/debug/classes") { + exclude(fileFilter) + }, + fileTree("${project.rootDir}/common-ktx/build/intermediates/javac/debug/classes") { + exclude(fileFilter) + }, + fileTree("${project.rootDir}/app/build/tmp/kotlin-classes/debug") { + exclude(fileFilter) + }, + fileTree("${project.rootDir}/common-ktx/build/tmp/kotlin-classes/debug") { + exclude(fileFilter) + } + ) + + sourceDirectories.setFrom( + files( + "${project.rootDir}/app/src/main/java", + "${project.rootDir}/common-ktx/src/main/java" + ) + ) + + executionData.setFrom( + fileTree(project.rootDir) { + include( + "app/build/jacoco/testDebugUnitTest.exec", + "common-ktx/build/jacoco/testDebugUnitTest.exec" + ) + } + ) + + reports { + xml.required.set(true) + html.required.set(true) + } +} + +tasks.withType { + testLogging { + events("passed", "skipped", "failed") + } +} diff --git a/common-ktx/build.gradle b/common-ktx/build.gradle deleted file mode 100644 index 08e4c34..0000000 --- a/common-ktx/build.gradle +++ /dev/null @@ -1,73 +0,0 @@ -plugins { - id 'com.android.library' - id 'kotlin-android' - id 'maven-publish' -} - -apply from: '../config/jacoco.gradle' -apply from: '../config/detekt.gradle' - -def versionPropertiesFile = rootProject.file("./version.properties") -def versionProperties = new Properties() -versionProperties.load(new FileInputStream(versionPropertiesFile)) - -android { - compileSdk 31 - - defaultConfig { - minSdk 21 - targetSdk 31 - versionCode 1 - versionName "1.0" - - testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" - } - - buildTypes { - release { - minifyEnabled false - proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro' - } - } - compileOptions { - sourceCompatibility JavaVersion.VERSION_1_8 - targetCompatibility JavaVersion.VERSION_1_8 - } - kotlinOptions { - jvmTarget = '1.8' - } -} - -dependencies { - implementation( - "androidx.core:core-ktx:1.6.0", - "androidx.appcompat:appcompat:1.3.1", - "com.google.android.material:material:1.4.0", - "com.google.code.gson:gson:2.8.9" - ) - - androidTestImplementation( - "androidx.test.ext:junit:1.1.3", - "androidx.test.espresso:espresso-core:3.4.0", - "org.hamcrest:hamcrest-library:1.3" - ) - - testImplementation "junit:junit:4.13.2" -} - -afterEvaluate { - publishing { - publications { - // Creates a Maven publication called "release". - release(MavenPublication) { - // Applies the component for the release build variant. - from components.release - - // You can then customize attributes of the publication as shown below. - groupId = 'co.nimblehq' - artifactId = 'extensions' - version = versionProperties['versionName'] - } - } - } -} diff --git a/common-ktx/build.gradle.kts b/common-ktx/build.gradle.kts new file mode 100644 index 0000000..4fd222a --- /dev/null +++ b/common-ktx/build.gradle.kts @@ -0,0 +1,77 @@ +import org.jetbrains.kotlin.gradle.dsl.JvmTarget + +plugins { + alias(libs.plugins.android.library) + alias(libs.plugins.kotlin.android) + id("maven-publish") +} + +android { + namespace = "co.nimblehq.common.extensions" + + compileSdk = libs.versions.androidCompileSdk.get().toInt() + + defaultConfig { + minSdk = libs.versions.androidMinSdk.get().toInt() + testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner" + + consumerProguardFiles("consumer-rules.pro") + } + + buildTypes { + release { + isMinifyEnabled = false + proguardFiles( + getDefaultProguardFile("proguard-android-optimize.txt"), + "proguard-rules.pro" + ) + } + } + + compileOptions { + sourceCompatibility = JavaVersion.VERSION_1_8 + targetCompatibility = JavaVersion.VERSION_1_8 + } + + kotlin { + compilerOptions { + jvmTarget.set(JvmTarget.JVM_1_8) + } + } + + publishing { + singleVariant("release") { + withSourcesJar() + } + } +} + +dependencies { + implementation(libs.androidx.core.ktx) + implementation(libs.androidx.appcompat) + implementation(libs.material) + implementation(libs.gson) + + androidTestImplementation(libs.test.ext.junit) + androidTestImplementation(libs.test.espresso.core) + androidTestImplementation(libs.test.hamcrest) + + testImplementation(libs.test.junit) +} + +afterEvaluate { + publishing { + publications { + // Creates a Maven publication called "release". + create("release") { + // Applies the component for the release build variant. + from(components["release"]) + + // You can then customize attributes of the publication as shown below. + groupId = "co.nimblehq" + artifactId = "extensions" + version = libs.versions.libVersionName.get() + } + } + } +} diff --git a/common-ktx/consumer-rules.pro b/common-ktx/consumer-rules.pro new file mode 100644 index 0000000..e703d69 --- /dev/null +++ b/common-ktx/consumer-rules.pro @@ -0,0 +1,7 @@ +# Add project specific ProGuard rules for library consumers here. +# Rules in this file will be applied to library consumers. + +# Keep extension functions +-keepclassmembers class co.nimblehq.common.extensions.** { + public *; +} diff --git a/common-ktx/src/androidTest/java/co/nimblehq/common/extensions/SharedPreferencesExtTest.kt b/common-ktx/src/androidTest/java/co/nimblehq/common/extensions/SharedPreferencesExtTest.kt index 25f6789..95d94fe 100644 --- a/common-ktx/src/androidTest/java/co/nimblehq/common/extensions/SharedPreferencesExtTest.kt +++ b/common-ktx/src/androidTest/java/co/nimblehq/common/extensions/SharedPreferencesExtTest.kt @@ -3,7 +3,6 @@ package co.nimblehq.common.extensions import android.content.Context import android.content.SharedPreferences import androidx.test.ext.junit.runners.AndroidJUnit4 -import androidx.test.filters.SmallTest import androidx.test.platform.app.InstrumentationRegistry import org.hamcrest.MatcherAssert.assertThat import org.hamcrest.Matchers.`is` @@ -16,10 +15,10 @@ import org.junit.runner.RunWith class SharedPreferencesExtTest { private var context: Context = InstrumentationRegistry.getInstrumentation().context private lateinit var sharedPreferences: SharedPreferences - private val TEST_KEY = "TEST_KEY" + private val testKey = "TEST_KEY" @Before - private fun setup() { + fun setup() { sharedPreferences = context.getSharedPreferences( "test_${this.javaClass.simpleName}", Context.MODE_PRIVATE @@ -27,94 +26,94 @@ class SharedPreferencesExtTest { } @Test - private fun when_set_with_boolean_value_then_return_the_correct_one() { + fun when_set_with_boolean_value_then_return_the_correct_one() { val testValue = true - sharedPreferences[TEST_KEY] = testValue - val test = sharedPreferences.get(TEST_KEY, false) + sharedPreferences[testKey] = testValue + val test = sharedPreferences.get(testKey, false) assertThat(test, `is`(testValue)) } @Test - private fun when_set_with_float_value_then_return_the_correct_one() { + fun when_set_with_float_value_then_return_the_correct_one() { val testValue = 2.1f - sharedPreferences[TEST_KEY] = testValue - val test = sharedPreferences.get(TEST_KEY, 0f) + sharedPreferences[testKey] = testValue + val test = sharedPreferences.get(testKey, 0f) assertThat(test, `is`(testValue)) } @Test - private fun when_set_with_double_value_then_return_the_correct_one() { + fun when_set_with_double_value_then_return_the_correct_one() { val testValue = 2.2 - sharedPreferences[TEST_KEY] = testValue - val test = sharedPreferences.get(TEST_KEY, 0.0) + sharedPreferences[testKey] = testValue + val test = sharedPreferences.get(testKey, 0.0) assertThat(test, `is`(testValue)) } @Test - private fun when_set_with_int_value_then_return_the_correct_one() { + fun when_set_with_int_value_then_return_the_correct_one() { val testValue = 9 - sharedPreferences[TEST_KEY] = testValue - val test = sharedPreferences.get(TEST_KEY, 0) + sharedPreferences[testKey] = testValue + val test = sharedPreferences.get(testKey, 0) assertThat(test, `is`(testValue)) } @Test - private fun when_set_with_long_value_then_return_the_correct_one() { + fun when_set_with_long_value_then_return_the_correct_one() { val testValue = 1000L - sharedPreferences[TEST_KEY] = testValue - val test = sharedPreferences.get(TEST_KEY, 0L) + sharedPreferences[testKey] = testValue + val test = sharedPreferences.get(testKey, 0L) assertThat(test, `is`(testValue)) } @Test - private fun when_set_with_string_value_then_return_the_correct_one() { + fun when_set_with_string_value_then_return_the_correct_one() { val testValue = "Nimble" - sharedPreferences[TEST_KEY] = testValue - val test = sharedPreferences.get(TEST_KEY, "") + sharedPreferences[testKey] = testValue + val test = sharedPreferences.get(testKey, "") assertThat(test, `is`(testValue)) } @Test - private fun when_set_with_set_string_value_then_return_the_correct_one() { + fun when_set_with_set_string_value_then_return_the_correct_one() { val testValue = setOf("Nimble", "Family") - sharedPreferences[TEST_KEY] = testValue - val test = sharedPreferences.get(TEST_KEY, setOf()) + sharedPreferences[testKey] = testValue + val test = sharedPreferences.get(testKey, setOf()) assertThat(test, `is`(testValue)) } @Test - private fun when_set_with_object_value_then_return_the_correct_one() { + fun when_set_with_object_value_then_return_the_correct_one() { val testValue = TestClass() - sharedPreferences[TEST_KEY] = testValue - val test = sharedPreferences.getObject(TEST_KEY) + sharedPreferences[testKey] = testValue + val test = sharedPreferences.getObject(testKey) assertThat(test, isA(TestClass::class.java)) } @Test - private fun when_get_with_wrong_type_then_return_null_value() { - val testValue = Integer(1) - sharedPreferences[TEST_KEY] = testValue - val test = sharedPreferences.getObject(TEST_KEY) + fun when_get_with_wrong_type_then_return_null_value() { + val testValue = Integer.valueOf(1) + sharedPreferences[testKey] = testValue + val test = sharedPreferences.getObject(testKey) assert(test == null) } @Test(expected = Exception::class) - private fun when_get_with_wrong_object_type_then_return_exception() { + fun when_get_with_wrong_object_type_then_return_exception() { val testValue = mapOf("one" to 1) - sharedPreferences[TEST_KEY] = testValue - sharedPreferences.get(TEST_KEY, mapOf()) + sharedPreferences[testKey] = testValue + sharedPreferences.get(testKey, mapOf()) } @Test - private fun when_calling_clear_all_then_all_data_should_be_cleard() { + fun when_calling_clear_all_then_all_data_should_be_cleard() { val testValue = "Nimble" - sharedPreferences[TEST_KEY] = testValue - var test = sharedPreferences.get(TEST_KEY, "") + sharedPreferences[testKey] = testValue + var test = sharedPreferences.get(testKey, "") assertThat(test, `is`(testValue)) sharedPreferences.clearAll() - test = sharedPreferences.get(TEST_KEY, "") + test = sharedPreferences.get(testKey, "") assertThat(test, `is`("")) } - inner class TestClass + class TestClass } diff --git a/common-ktx/src/main/AndroidManifest.xml b/common-ktx/src/main/AndroidManifest.xml deleted file mode 100644 index b4a4d98..0000000 --- a/common-ktx/src/main/AndroidManifest.xml +++ /dev/null @@ -1,2 +0,0 @@ - - diff --git a/common-ktx/src/main/java/co/nimblehq/common/extensions/DateExt.kt b/common-ktx/src/main/java/co/nimblehq/common/extensions/DateExt.kt index f0a022b..8554022 100644 --- a/common-ktx/src/main/java/co/nimblehq/common/extensions/DateExt.kt +++ b/common-ktx/src/main/java/co/nimblehq/common/extensions/DateExt.kt @@ -1,9 +1,13 @@ +@file:Suppress("TooManyFunctions") + package co.nimblehq.common.extensions import co.nimblehq.common.extensions.date.DateRange import co.nimblehq.common.extensions.date.TimeInterval import java.text.SimpleDateFormat -import java.util.* +import java.util.Calendar +import java.util.Date +import java.util.Locale val tomorrow: Date get() = shiftDate(value = 1) @@ -76,6 +80,7 @@ operator fun Date.rangeTo(endDate: Date) = DateRange(this, endDate) * * @return Date with inputted values */ +@Suppress("LongParameterList") fun Date.with( year: Int = -1, month: Int = -1, @@ -83,7 +88,7 @@ fun Date.with( hour: Int = -1, minute: Int = -1, second: Int = -1, - millisecond: Int = -1 + millisecond: Int = -1, ): Date { val calendar = Calendar.getInstance() calendar.time = this @@ -302,9 +307,9 @@ private fun isDateIn(date: Date, valueOfDate: Int = 0): Boolean { now.add(Calendar.DATE, valueOfDate) - return now.get(Calendar.YEAR) == cdate.get(Calendar.YEAR) - && now.get(Calendar.MONTH) == cdate.get(Calendar.MONTH) - && now.get(Calendar.DATE) == cdate.get(Calendar.DATE) + return now.get(Calendar.YEAR) == cdate.get(Calendar.YEAR) && + now.get(Calendar.MONTH) == cdate.get(Calendar.MONTH) && + now.get(Calendar.DATE) == cdate.get(Calendar.DATE) } /** @@ -315,8 +320,6 @@ private fun isDateIn(date: Date, valueOfDate: Int = 0): Boolean { * * @return Return Date object from String with provided format */ -fun String.toDate(format: String, locale: Locale = Locale.getDefault()): Date? = try { +fun String.toDate(format: String, locale: Locale = Locale.getDefault()): Date? = runCatching { SimpleDateFormat(format, locale).parse(this) -} catch (e: Exception) { - null -} +}.getOrNull() diff --git a/common-ktx/src/main/java/co/nimblehq/common/extensions/SharedPreferencesExt.kt b/common-ktx/src/main/java/co/nimblehq/common/extensions/SharedPreferencesExt.kt index 8f0a72e..b8f87d0 100644 --- a/common-ktx/src/main/java/co/nimblehq/common/extensions/SharedPreferencesExt.kt +++ b/common-ktx/src/main/java/co/nimblehq/common/extensions/SharedPreferencesExt.kt @@ -1,25 +1,22 @@ package co.nimblehq.common.extensions import android.content.SharedPreferences +import androidx.core.content.edit import com.google.gson.Gson inline fun SharedPreferences.getObject(key: String): T? { - return try { + return runCatching { Gson().fromJson(getString(key, null), T::class.java) - } catch (e: Exception) { - null - } + }.getOrNull() } -@Suppress("UNCHECKED_CAST") +@Suppress("UNCHECKED_CAST", "CyclomaticComplexMethod") inline fun SharedPreferences.get(key: String, defaultValue: T? = null): T { return when (T::class) { Boolean::class -> getBoolean(key, defaultValue as? Boolean? ?: false) as T Float::class -> getFloat(key, defaultValue as? Float? ?: 0.0f) as T // We need convert toString() before toDouble() to ensure the exact value - Double::class -> getFloat( - key, (defaultValue as? Double?)?.toFloat() ?: 0.0f - ).toString().toDouble() as T + Double::class -> getFloat(key, (defaultValue as? Double?)?.toFloat() ?: 0.0f).toString().toDouble() as T Int::class -> getInt(key, defaultValue as? Int? ?: 0) as T Long::class -> getLong(key, defaultValue as? Long? ?: 0L) as T String::class -> getString(key, defaultValue as? String? ?: "") as T @@ -28,9 +25,7 @@ inline fun SharedPreferences.get(key: String, defaultValue: T? getStringSet(key, defaultValue as Set) as T } else { val typeName = T::class.java.simpleName - throw Exception( - "Unable to get shared preference with value type '$typeName'. Use getObject" - ) + error("Unable to get shared preference with value type '$typeName'. Use getObject") } } } @@ -39,7 +34,7 @@ inline fun SharedPreferences.get(key: String, defaultValue: T? @Suppress("UNCHECKED_CAST") @Throws(Exception::class) inline operator fun SharedPreferences.set(key: String, value: T) { - with(edit()) { + edit { when (T::class) { Boolean::class -> putBoolean(key, value as Boolean) Float::class -> putFloat(key, value as Float) @@ -57,12 +52,9 @@ inline operator fun SharedPreferences.set(key: String, value: } } } - commit() } } fun SharedPreferences.clearAll() { - with(edit()) { - clear() - }.apply() + edit { clear() } } diff --git a/common-ktx/src/main/java/co/nimblehq/common/extensions/TypedArrayExt.kt b/common-ktx/src/main/java/co/nimblehq/common/extensions/TypedArrayExt.kt index 42b3199..87ff7bf 100644 --- a/common-ktx/src/main/java/co/nimblehq/common/extensions/TypedArrayExt.kt +++ b/common-ktx/src/main/java/co/nimblehq/common/extensions/TypedArrayExt.kt @@ -60,16 +60,15 @@ fun Context.getFontCompat(@FontRes fontId: Int): Typeface? = * @param index - Styleable Resource index, sample: R.styleable.your_custom_attribute */ fun TypedArray.getColorStateList(context: Context, @StyleableRes index: Int): ColorStateList? { - if (hasValue(index)) { - val resourceId = getResourceId(index, 0) - if (resourceId != 0) { - val value = AppCompatResources.getColorStateList(context, resourceId) - if (value != null) { - return value - } - } + val colorStateList = if (hasValue(index)) { + getResourceId(index, 0) + .takeIf { resourceId -> resourceId != 0 } + ?.let { resourceId -> AppCompatResources.getColorStateList(context, resourceId) } + } else { + null } - return getColorStateList(index) + + return colorStateList ?: getColorStateList(index) } /** @@ -79,14 +78,12 @@ fun TypedArray.getColorStateList(context: Context, @StyleableRes index: Int): Co * @param index - Styleable Resource index, sample: R.styleable.your_custom_attribute */ fun TypedArray.getDrawable(context: Context, @StyleableRes index: Int): Drawable? { - if (hasValue(index)) { - val resourceId = getResourceId(index, 0) - if (resourceId != 0) { - val value = AppCompatResources.getDrawable(context, resourceId) - if (value != null) { - return value - } - } + val drawable = if (hasValue(index)) { + getResourceId(index, 0) + .takeIf { resourceId -> resourceId != 0 } + ?.let { resourceId -> AppCompatResources.getDrawable(context, resourceId) } + } else { + null } - return getDrawable(index) + return drawable ?: getDrawable(index) } diff --git a/common-ktx/src/main/java/co/nimblehq/common/extensions/ViewExt.kt b/common-ktx/src/main/java/co/nimblehq/common/extensions/ViewExt.kt index 79a5469..1a28860 100644 --- a/common-ktx/src/main/java/co/nimblehq/common/extensions/ViewExt.kt +++ b/common-ktx/src/main/java/co/nimblehq/common/extensions/ViewExt.kt @@ -1,11 +1,17 @@ +@file:Suppress("TooManyFunctions") + package co.nimblehq.common.extensions import android.app.Activity import android.content.Context -import android.graphics.* +import android.graphics.Bitmap +import android.graphics.Canvas +import android.graphics.Color import android.view.View import androidx.annotation.DimenRes import androidx.annotation.Px +import androidx.core.graphics.createBitmap +import androidx.core.view.isVisible import java.lang.ref.WeakReference /** @@ -77,7 +83,7 @@ fun View.visibleOrInvisible(visible: Boolean) { * @param listener The function would be called after checking view is visible. */ inline fun View.ifVisibleThen(listener: (View) -> Unit) { - if (this.visibility == View.VISIBLE) { + if (this.isVisible) { listener.invoke(this) } } @@ -143,9 +149,9 @@ fun View.convertSpToPx(sp: Float): Int { */ @Throws(java.lang.IllegalArgumentException::class) fun View.getBitmap(resultHeight: Int, resultWidth: Int): Bitmap { - if (resultHeight <= 0 || resultWidth <= 0) throw IllegalArgumentException("Invalid arguments") + require(resultWidth > 0 && resultHeight > 0) { "Invalid arguments" } - val bitmap = Bitmap.createBitmap(resultWidth, resultHeight, Bitmap.Config.ARGB_8888) + val bitmap = createBitmap(resultWidth, resultHeight) val canvas = Canvas(bitmap) val bgDrawable = this.background diff --git a/common-ktx/src/test/java/co/nimblehq/common/extensions/DateExtTest.kt b/common-ktx/src/test/java/co/nimblehq/common/extensions/DateExtTest.kt index c2776bd..a9ad854 100644 --- a/common-ktx/src/test/java/co/nimblehq/common/extensions/DateExtTest.kt +++ b/common-ktx/src/test/java/co/nimblehq/common/extensions/DateExtTest.kt @@ -1,6 +1,8 @@ package co.nimblehq.common.extensions -import org.junit.Assert.* +import junit.framework.TestCase.assertEquals +import org.junit.Assert.assertFalse +import org.junit.Assert.assertTrue import org.junit.Test import java.text.SimpleDateFormat import java.util.* diff --git a/config/detekt.gradle b/config/detekt.gradle deleted file mode 100644 index 77bf065..0000000 --- a/config/detekt.gradle +++ /dev/null @@ -1,9 +0,0 @@ -apply plugin: 'io.gitlab.arturbosch.detekt' - -detekt { - config = files("$rootDir/config/detekt.yml") -} - -dependencies { - detektPlugins "io.gitlab.arturbosch.detekt:detekt-formatting:$detekt_version" -} diff --git a/config/detekt.yml b/config/detekt.yml index 6ca504a..341b013 100644 --- a/config/detekt.yml +++ b/config/detekt.yml @@ -1,22 +1,14 @@ build: - maxIssues: 3 - excludeCorrectable: false + maxIssues: 10 weights: - # complexity: 2 - # LongParameterList: 1 - # style: 1 - # comments: 1 - -config: - validation: true - # when writing own rules with new properties, - # exclude the property path e.g.: 'my_rule_set,.*>.*>[my_property]' - excludes: '' + complexity: 2 + formatting: 1 + LongParameterList: 1 + comments: 1 processors: active: true exclude: - - 'DetektProgressListener' # - 'FunctionCountProcessor' # - 'PropertyCountProcessor' # - 'ClassCountProcessor' @@ -26,24 +18,27 @@ processors: console-reports: active: true exclude: - - 'ProjectStatisticsReport' - - 'ComplexityReport' - - 'NotificationReport' - # - 'FindingsReport' - - 'FileBasedFindingsReport' + # - 'ProjectStatisticsReport' + # - 'ComplexityReport' + # - 'NotificationReport' + # - 'FindingsReport' + # - 'BuildFailureReport' + +output-reports: + active: true + exclude: + # - 'PlainOutputReport' + # - 'XmlOutputReport' comments: active: true - AbsentOrWrongFileLicense: - active: false - licenseTemplateFile: 'license.template' CommentOverPrivateFunction: active: false CommentOverPrivateProperty: active: false EndOfSentenceFormat: active: false - endOfSentenceFormat: '([.?!][ \t\n\r\f<])|([.?!:]$)' + endOfSentenceFormat: ([.?!][ \t\n\r\f<])|([.?!]$) UndocumentedPublicClass: active: false searchInNestedClass: true @@ -52,74 +47,63 @@ comments: searchInInnerInterface: true UndocumentedPublicFunction: active: false - UndocumentedPublicProperty: - active: false complexity: - active: false + active: true ComplexCondition: active: true - threshold: 4 + threshold: 3 ComplexInterface: active: false threshold: 10 includeStaticDeclarations: false - includePrivateDeclarations: false ComplexMethod: active: true - threshold: 15 - ignoreSingleWhenExpression: false - ignoreSimpleWhenEntries: false - ignoreNestingFunctions: false - nestingFunctions: [ run, let, apply, with, also, use, forEach, isNotNull, ifNull ] + threshold: 10 LabeledExpression: active: false - ignoredLabels: [ ] LargeClass: active: true - threshold: 600 + threshold: 150 + excludes: + - '**/test/**' + - '**/androidTest/**' + - '**/*.Test.kt' LongMethod: active: true threshold: 60 LongParameterList: active: true - functionThreshold: 6 - constructorThreshold: 7 - ignoreDefaultParameters: false - ignoreDataClasses: true - ignoreAnnotated: [ ] + functionThreshold: 5 + ignoreDefaultParameters: true MethodOverloading: active: false - threshold: 6 + threshold: 5 NestedBlockDepth: active: true - threshold: 4 + threshold: 3 StringLiteralDuplication: active: false - threshold: 3 + threshold: 2 ignoreAnnotation: true excludeStringsWithLessThan5Characters: true ignoreStringsRegex: '$^' TooManyFunctions: active: true - thresholdInFiles: 25 - thresholdInClasses: 30 - thresholdInInterfaces: 20 - thresholdInObjects: 20 - thresholdInEnums: 20 - -coroutines: - active: false - GlobalCoroutineUsage: - active: false - RedundantSuspendModifier: - active: false + thresholdInFiles: 10 + thresholdInClasses: 10 + thresholdInInterfaces: 10 + thresholdInObjects: 10 + thresholdInEnums: 10 + excludes: + - '**/test/**' + - '**/androidTest/**' + - '**/*.Test.kt' empty-blocks: active: true EmptyCatchBlock: active: true - allowedExceptionNameRegex: '_|(ignore|expected).*' EmptyClassBlock: active: true EmptyDefaultConstructor: @@ -134,7 +118,6 @@ empty-blocks: active: true EmptyFunctionBlock: active: false - ignoreOverridden: false EmptyIfBlock: active: true EmptyInitBlock: @@ -143,8 +126,6 @@ empty-blocks: active: true EmptySecondaryConstructor: active: true - EmptyTryBlock: - active: true EmptyWhenBlock: active: true EmptyWhileBlock: @@ -154,7 +135,7 @@ exceptions: active: true ExceptionRaisedInUnexpectedLocation: active: false - methodNames: [ toString, hashCode, equals, finalize ] + methodNames: [ 'toString', 'hashCode', 'equals', 'finalize' ] InstanceOfCheckForException: active: false NotImplementedDeclaration: @@ -165,29 +146,19 @@ exceptions: active: false ReturnFromFinally: active: false - ignoreLabeled: false SwallowedException: active: false - ignoredExceptionTypes: - - InterruptedException - - NumberFormatException - - ParseException - - MalformedURLException - allowedExceptionNameRegex: '_|(ignore|expected).*' ThrowingExceptionFromFinally: active: false ThrowingExceptionInMain: active: false ThrowingExceptionsWithoutMessageOrCause: active: false - exceptions: - - IllegalArgumentException - - IllegalStateException - - IOException + exceptions: [ 'IllegalArgumentException', 'IllegalStateException', 'IOException' ] ThrowingNewInstanceOfSameException: active: false TooGenericExceptionCaught: - active: false + active: true exceptionNames: - ArrayIndexOutOfBoundsException - Error @@ -197,179 +168,53 @@ exceptions: - IndexOutOfBoundsException - RuntimeException - Throwable - allowedExceptionNameRegex: '_|(ignore|expected).*' TooGenericExceptionThrown: - active: false + active: true exceptionNames: - Error - Exception + - NullPointerException - Throwable - RuntimeException -formatting: - active: true - android: false - autoCorrect: true - AnnotationOnSeparateLine: - active: false - autoCorrect: true - ChainWrapping: - active: false - autoCorrect: true - CommentSpacing: - active: true - autoCorrect: true - EnumEntryNameCase: - active: true - autoCorrect: true - Filename: - active: true - FinalNewline: - active: true - autoCorrect: true - insertFinalNewLine: true - ImportOrdering: - active: false - autoCorrect: true - Indentation: - active: true - autoCorrect: false - indentSize: 4 - continuationIndentSize: 4 - MaximumLineLength: - active: true - maxLineLength: 100 - ModifierOrdering: - active: true - autoCorrect: true - MultiLineIfElse: - active: true - autoCorrect: true - NoBlankLineBeforeRbrace: - active: true - autoCorrect: true - NoConsecutiveBlankLines: - active: true - autoCorrect: true - NoEmptyClassBody: - active: true - autoCorrect: true - NoEmptyFirstLineInMethodBlock: - active: true - autoCorrect: true - NoLineBreakAfterElse: - active: true - autoCorrect: true - NoLineBreakBeforeAssignment: - active: true - autoCorrect: true - NoMultipleSpaces: - active: true - autoCorrect: true - NoSemicolons: - active: true - autoCorrect: true - NoTrailingSpaces: - active: true - autoCorrect: true - NoUnitReturn: - active: true - autoCorrect: true - NoUnusedImports: - active: true - autoCorrect: true - NoWildcardImports: - active: false - PackageName: - active: true - autoCorrect: true - ParameterListWrapping: - active: true - autoCorrect: true - indentSize: 4 - SpacingAroundColon: - active: true - autoCorrect: true - SpacingAroundComma: - active: true - autoCorrect: true - SpacingAroundCurly: - active: true - autoCorrect: true - SpacingAroundDot: - active: true - autoCorrect: true - SpacingAroundKeyword: - active: true - autoCorrect: true - SpacingAroundOperators: - active: true - autoCorrect: true - SpacingAroundParens: - active: true - autoCorrect: true - SpacingAroundRangeOperator: - active: true - autoCorrect: true - StringTemplate: - active: true - autoCorrect: true - naming: active: true ClassNaming: active: true - classPattern: '[A-Z][a-zA-Z0-9]*' - ConstructorParameterNaming: - active: true - parameterPattern: '(_)?[a-z][A-Za-z0-9]*' - privateParameterPattern: '(_)?[a-z][A-Za-z0-9]*' - excludeClassPattern: '$^' - ignoreOverridden: true + classPattern: '[A-Z$][a-zA-Z0-9$]*' EnumNaming: active: true - enumEntryPattern: '[A-Z][_a-zA-Z0-9]*' + enumEntryPattern: '^[A-Z$][a-zA-Z_$]*$' ForbiddenClassName: active: false - forbiddenName: [ ] + forbiddenName: [ '' ] FunctionMaxLength: active: false maximumFunctionNameLength: 30 + ignoreAnnotated: [ 'Test' ] FunctionMinLength: active: false minimumFunctionNameLength: 3 FunctionNaming: active: true - functionPattern: '([a-z][a-zA-Z0-9]*)|(`.*`)' - excludeClassPattern: '$^' - ignoreOverridden: true - FunctionParameterNaming: - active: true - parameterPattern: '[a-z][A-Za-z0-9]*' - excludeClassPattern: '$^' - ignoreOverridden: true - InvalidPackageDeclaration: - active: false - rootPackage: '' + functionPattern: '[a-zA-Z][a-zA-Z0-9]*' + ignoreAnnotated: [ 'Test' ] MatchingDeclarationName: active: true - mustBeFirst: true MemberNameEqualsClassName: - active: true + active: false ignoreOverridden: true ObjectPropertyNaming: active: true - constantPattern: '[A-Za-z][_A-Za-z0-9]*' propertyPattern: '[A-Za-z][_A-Za-z0-9]*' - privatePropertyPattern: '(_)?[A-Za-z][_A-Za-z0-9]*' PackageNaming: active: true - packagePattern: '[a-z]+(\.[a-z][A-Za-z0-9]*)*' + packagePattern: '^[a-z]+(\.[a-z][a-z0-9]*)*$' TopLevelPropertyNaming: active: true - constantPattern: '[A-Z][_A-Z0-9]*' - propertyPattern: '[A-Za-z][_A-Za-z0-9]*' - privatePropertyPattern: '_?[A-Za-z][_A-Za-z0-9]*' + constantPattern: '[A-Z][_A-Za-z0-9]*' + propertyPattern: '[A-Za-z][A-Za-z0-9]*' + privatePropertyPattern: '(_)?[A-Za-z][A-Za-z0-9]*' VariableMaxLength: active: false maximumVariableNameLength: 64 @@ -380,223 +225,135 @@ naming: active: true variablePattern: '(_)?[a-z][A-Za-z0-9]*' privateVariablePattern: '(_)?[a-z][A-Za-z0-9]*' - excludeClassPattern: '$^' - ignoreOverridden: true performance: active: true - ArrayPrimitive: - active: true ForEachOnRange: active: true SpreadOperator: - active: false + active: true UnnecessaryTemporaryInstantiation: active: true potential-bugs: active: true - Deprecation: - active: false DuplicateCaseInWhenExpression: active: true EqualsAlwaysReturnsTrueOrFalse: - active: true + active: false EqualsWithHashCodeExist: active: true ExplicitGarbageCollectionCall: active: true - HasPlatformType: - active: false - ImplicitDefaultLocale: - active: false InvalidRange: - active: true + active: false IteratorHasNextCallsNextMethod: - active: true + active: false IteratorNotThrowingNoSuchElementException: - active: true - LateinitUsage: active: false - excludeAnnotatedProperties: [ ] - ignoreOnClassesPattern: '' - MapGetWithNotNullAssertionOperator: + LateinitUsage: active: false - MissingWhenCase: - active: true - RedundantElseInWhen: - active: true + ignoreAnnotated: [ '' ] + ignoreOnClassesPattern: "" UnconditionalJumpStatementInLoop: active: false - UnnecessaryNotNullOperator: - active: false - UnnecessarySafeCall: - active: false UnreachableCode: active: true UnsafeCallOnNullableType: - active: true + active: false UnsafeCast: active: false UselessPostfixExpression: active: false WrongEqualsTypeParameter: - active: true + active: false style: active: true CollapsibleIfStatements: - active: true + active: false DataClassContainsFunctions: active: false conversionFunctionPrefix: 'to' - DataClassShouldBeImmutable: - active: false EqualsNullCall: - active: true - EqualsOnSignatureLine: - active: false - ExplicitCollectionElementAccessMethod: - active: false - ExplicitItLambdaParameter: active: false ExpressionBodySyntax: active: false - includeLineWrapping: false ForbiddenComment: active: true - values: [ 'TODO:', 'FIXME:', '[TODO]', '[FIXME]' ] - allowedPatterns: '' + values: [ 'FIXME:', 'STOPSHIP:' ] ForbiddenImport: active: false - imports: [ ] - forbiddenPatterns: '' - ForbiddenMethodCall: - active: false - methods: [ ] - ForbiddenPublicDataClass: - active: false - ignorePackages: [ '*.internal', '*.internal.*' ] - ForbiddenVoid: - active: false - ignoreOverridden: false - ignoreUsageInGenerics: false + imports: [ '' ] FunctionOnlyReturningConstant: - active: true + active: false ignoreOverridableFunction: true excludedFunctions: 'describeContents' - excludeAnnotatedFunction: [ 'dagger.Provides' ] - LibraryCodeMustSpecifyReturnType: - active: true LoopWithTooManyJumpStatements: - active: true + active: false maxJumpCount: 1 MagicNumber: active: true ignoreNumbers: [ '-1', '0', '1', '2' ] - ignoreHashCodeFunction: true - ignorePropertyDeclaration: false - ignoreLocalVariableDeclaration: false + ignoreAnnotated: [ 'Test' ] + ignoreHashCodeFunction: false + ignorePropertyDeclaration: true ignoreConstantDeclaration: true ignoreCompanionObjectPropertyDeclaration: true ignoreAnnotation: false ignoreNamedArgument: true ignoreEnums: false - ignoreRanges: false - MandatoryBracesIfStatements: - active: false - MandatoryBracesLoops: - active: false MaxLineLength: active: true - maxLineLength: 100 - excludePackageStatements: true - excludeImportStatements: true - excludeCommentStatements: false - MayBeConst: - active: true + maxLineLength: 120 + excludePackageStatements: false + excludeImportStatements: false + ignoreAnnotated: [ 'Test' ] ModifierOrder: active: true NestedClassesVisibility: active: false NewLineAtEndOfFile: - active: true - NoTabs: - active: true + active: false OptionalAbstractKeyword: active: true OptionalUnit: active: false OptionalWhenBraces: active: false - PreferToOverPairSyntax: - active: true ProtectedMemberInFinalClass: - active: true - RedundantExplicitType: active: false RedundantVisibilityModifierRule: - active: true - ReturnCount: active: false + ReturnCount: + active: true max: 2 - excludedFunctions: 'equals' - excludeLabeled: false - excludeReturnFromLambda: true - excludeGuardClauses: false + excludedFunctions: "equals" SafeCast: active: true SerialVersionUIDInSerializableClass: active: false SpacingBetweenPackageAndImports: - active: true + active: false ThrowsCount: active: true max: 2 - TrailingWhitespace: - active: true - UnderscoresInNumericLiterals: - active: false - acceptableDecimalLength: 5 UnnecessaryAbstractClass: - active: true - UnnecessaryAnnotationUseSiteTarget: active: false - UnnecessaryApply: - active: true UnnecessaryInheritance: - active: true - UnnecessaryLet: - active: true + active: false UnnecessaryParentheses: - active: true + active: false UntilInsteadOfRangeTo: active: false UnusedImports: active: true - UnusedPrivateClass: - active: true UnusedPrivateMember: active: true - allowedNames: '(_|ignored|expected|serialVersionUID)' - UseArrayLiteralsInAnnotations: - active: false - UseCheckOrError: - active: false UseDataClass: active: false - excludeAnnotatedClasses: [ ] - allowVars: false - UseIfInsteadOfWhen: - active: false - UseRequire: - active: false - UselessCallOnNotNull: - active: true + ignoreAnnotated: [ '' ] UtilityClassWithPublicConstructor: - active: true - VarCouldBeVal: - active: true - WildcardImport: active: false - excludeImports: [ 'java.util.*', 'kotlinx.android.synthetic.*' ] + WildcardImport: + active: true diff --git a/config/jacoco.gradle b/config/jacoco.gradle deleted file mode 100644 index e0975ba..0000000 --- a/config/jacoco.gradle +++ /dev/null @@ -1,74 +0,0 @@ -apply plugin: 'jacoco' - -jacoco { - toolVersion = "0.8.5" -} - -def fileGenerated = [ - 'android/**/*.*', - '**/R.class', - '**/R$*.class', - '**/*$ViewBinder*.*', - '**/*$InjectAdapter*.*', - '**/*Injector*.*', - '**/BuildConfig.*', - '**/Manifest*.*', - '**/*_ViewBinding*.*', - '**/*_Factory*.*', - '**/app/ui/screens/**/*DiffCallback*.*', - '**/*Test*.*', - // navigation component - '**/*FragmentArgs*', - '**/*FragmentDirections*', - '**/FragmentNavArgsLazy.kt', - '**/*Fragment*navArgs*', - '**/screens/common/StartFragment.*', - // kotlin enum Creator - '**/*$Creator*' -] - -def packagesExcluded = [ - 'co/nimblehq/extensions/app/**', - 'com/bumptech/glide' -] - -def fileFilter = fileGenerated + packagesExcluded - -task jacocoTestReport(type: JacocoReport) { - group = "Reporting" - description = "Generate Jacoco coverage reports for Debug build" - - dependsOn ":app:testDebugUnitTest" - dependsOn ":common-ktx:testDebugUnitTest" - - classDirectories.from = fileTree( - dir: "$project.rootDir/app/build/intermediates/javac/stagingDebug/classes", - excludes: fileFilter - ) + fileTree( - dir: "$project.rootDir/common-ktx/build/intermediates/javac/stagingDebug/classes", - excludes: fileFilter - ) + fileTree( - dir: "$project.rootDir/app/build/tmp/kotlin-classes/stagingDebug", - excludes: fileFilter - ) + fileTree( - dir: "$project.rootDir/common-ktx/build/tmp/kotlin-classes/stagingDebug", - excludes: fileFilter - ) - - sourceDirectories.from = files([ - "$project.rootDir/app/src/main/java", - "$project.rootDir/common-ktx/src/main/java" - ]) - - executionData.from = fileTree(dir: project.rootDir, includes: [ - "app/build/jacoco/testStagingDebugUnitTest.exec", - "common-ktx/build/jacoco/testStagingDebugUnitTest.exec" - ]) - -} - -tasks.withType(Test) { - testLogging { - events "passed", "skipped", "failed" - } -} diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml new file mode 100644 index 0000000..f05cf5b --- /dev/null +++ b/gradle/libs.versions.toml @@ -0,0 +1,45 @@ +[versions] +# SDK versions +androidCompileSdk = "36" +androidMinSdk = "21" +androidTargetSdk = "36" +androidVersionCode = "1" +androidVersionName = "1.0.0" +libVersionName = "0.1.0" + +androidx-appcompat = "1.3.1" +androidx-core-ktx = "1.6.0" +androidx-test-espresso = "3.4.0" +androidx-test-junit = "1.1.3" +detekt = "1.23.8" +gradle = "8.13.0" +gson = "2.8.9" +hamcrest = "1.3" +jacoco = "0.8.12" +junit = "4.13.2" +kotlin = "2.2.21" +material = "1.4.0" + +[libraries] +# AndroidX +androidx-core-ktx = { group = "androidx.core", name = "core-ktx", version.ref = "androidx-core-ktx" } +androidx-appcompat = { group = "androidx.appcompat", name = "appcompat", version.ref = "androidx-appcompat" } + +# Material +material = { group = "com.google.android.material", name = "material", version.ref = "material" } + +# Test +test-espresso-core = { group = "androidx.test.espresso", name = "espresso-core", version.ref = "androidx-test-espresso" } +test-ext-junit = { group = "androidx.test.ext", name = "junit", version.ref = "androidx-test-junit" } +test-hamcrest = { group = "org.hamcrest", name = "hamcrest-library", version.ref = "hamcrest" } +test-junit = { group = "junit", name = "junit", version.ref = "junit" } + +# Utilities +gson = { group = "com.google.code.gson", name = "gson", version.ref = "gson" } +detekt-formatting = { group = "io.gitlab.arturbosch.detekt", name = "detekt-formatting", version.ref = "detekt" } + +[plugins] +android-application = { id = "com.android.application", version.ref = "gradle" } +android-library = { id = "com.android.library", version.ref = "gradle" } +detekt = { id = "io.gitlab.arturbosch.detekt", version.ref = "detekt" } +kotlin-android = { id = "org.jetbrains.kotlin.android", version.ref = "kotlin" } diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties index ffed3a2..3ae1e2f 100644 --- a/gradle/wrapper/gradle-wrapper.properties +++ b/gradle/wrapper/gradle-wrapper.properties @@ -1,5 +1,5 @@ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-7.2-bin.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-8.14.3-bin.zip zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists diff --git a/settings.gradle b/settings.gradle.kts similarity index 56% rename from settings.gradle rename to settings.gradle.kts index c2bb6f6..8e60b82 100644 --- a/settings.gradle +++ b/settings.gradle.kts @@ -1,11 +1,19 @@ +pluginManagement { + repositories { + google() + mavenCentral() + gradlePluginPortal() + } +} + dependencyResolutionManagement { repositoriesMode.set(RepositoriesMode.FAIL_ON_PROJECT_REPOS) repositories { google() mavenCentral() - jcenter() // Warning: this repository is going to shut down soon } } + rootProject.name = "Android Extensions" -include ':app' -include ':common-ktx' +include(":app") +include(":common-ktx") diff --git a/version.properties b/version.properties deleted file mode 100644 index 44e6291..0000000 --- a/version.properties +++ /dev/null @@ -1 +0,0 @@ -versionName=0.1.0