diff --git a/.github/scripts/copy_env_variables.sh b/.github/scripts/copy_env_variables.sh index a29b65b..e40fa58 100755 --- a/.github/scripts/copy_env_variables.sh +++ b/.github/scripts/copy_env_variables.sh @@ -1,6 +1,10 @@ # Append suffix -SNAPSHOT if [[ ! ($(grep "MATERIAL_PREFERENCE_VERSION=" gradle.properties) == *"-SNAPSHOT") ]]; then sed -ie "s/MATERIAL_PREFERENCE_VERSION.*$/&-SNAPSHOT/g" gradle.properties +fi + +if [[ ! ($(grep "PROCESSOR_VERSION=" gradle.properties) == *"-SNAPSHOT") ]]; then + sed -ie "s/PROCESSOR_VERSION.*$/&-SNAPSHOT/g" gradle.properties rm -f gradle.propertiese fi diff --git a/.github/scripts/deploy_snapshot.sh b/.github/scripts/deploy_snapshot.sh index ee8b241..bc5cea0 100755 --- a/.github/scripts/deploy_snapshot.sh +++ b/.github/scripts/deploy_snapshot.sh @@ -10,6 +10,6 @@ elif [ "${GITHUB_REF##*/}" != "master" ]; then echo "Skipping deployment: wrong branch. Expected 'master' but was '${GITHUB_REF##*/}'." else echo "Deploying snapshot..." - ./gradlew :materialpreference:uploadArchives --no-daemon --no-parallel --stacktrace + ./gradlew :materialpreference:publishAllPublicationsToMavenCentral --no-daemon --no-parallel --stacktrace echo "Snapshot released!" fi diff --git a/.github/workflows/android.yml b/.github/workflows/android.yml index 26c6b7f..ea418d5 100644 --- a/.github/workflows/android.yml +++ b/.github/workflows/android.yml @@ -19,19 +19,31 @@ jobs: steps: - uses: actions/checkout@v2 - - name: Setup JDK 1.8 + - name: Setup JDK 11 uses: actions/setup-java@v1 with: - java-version: 1.8 + java-version: 11 - name: Copy environment variables run: ./.github/scripts/copy_env_variables.sh - name: Build with Gradle + if: ${{ github.repository_owner == 'anggrayudi' }} + env: + ORG_GRADLE_PROJECT_mavenCentralUsername: ${{ secrets.OSS_SONATYPE_NEXUS_USERNAME }} + ORG_GRADLE_PROJECT_mavenCentralPassword: ${{ secrets.OSS_SONATYPE_NEXUS_PASSWORD }} + run: ./gradlew build test check + + - name: Build with Gradle (default) + if: ${{ github.repository_owner != 'anggrayudi' }} + env: + ORG_GRADLE_PROJECT_mavenCentralUsername: 'abc' + ORG_GRADLE_PROJECT_mavenCentralPassword: 'xyz' run: ./gradlew build test check - name: Upload snapshot archives + if: ${{ github.repository_owner == 'anggrayudi' }} env: ORG_GRADLE_PROJECT_mavenCentralUsername: ${{ secrets.OSS_SONATYPE_NEXUS_USERNAME }} ORG_GRADLE_PROJECT_mavenCentralPassword: ${{ secrets.OSS_SONATYPE_NEXUS_PASSWORD }} - run: ./.github/scripts/deploy_snapshot.sh + run: ./.github/scripts/deploy_snapshot.sh \ No newline at end of file diff --git a/.run/publish.run.xml b/.run/publish.run.xml new file mode 100644 index 0000000..697c16c --- /dev/null +++ b/.run/publish.run.xml @@ -0,0 +1,17 @@ + + + + \ No newline at end of file diff --git a/.run/publishAllToCentral.run.xml b/.run/publishAllToCentral.run.xml new file mode 100644 index 0000000..d6fca41 --- /dev/null +++ b/.run/publishAllToCentral.run.xml @@ -0,0 +1,17 @@ + + + + \ No newline at end of file diff --git a/.run/publishToLocal.run.xml b/.run/publishToLocal.run.xml new file mode 100644 index 0000000..8f3dac7 --- /dev/null +++ b/.run/publishToLocal.run.xml @@ -0,0 +1,17 @@ + + + + \ No newline at end of file diff --git a/LICENSE b/LICENSE index e5189c2..ee45572 100644 --- a/LICENSE +++ b/LICENSE @@ -186,7 +186,7 @@ same "printed page" as the copyright notice for easier identification within third-party archives. - Copyright © 2018-2021 Anggrayudi Hardiannicko A. + Copyright © 2018-2022 Anggrayudi Hardiannicko A. Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. diff --git a/README.md b/README.md index 9dbd64f..41e5dd0 100644 --- a/README.md +++ b/README.md @@ -163,7 +163,7 @@ apply plugin: 'kotlin-kapt' // Add this line dependencies { implementation 'com.anggrayudi:materialpreference:3.x.x' - kapt 'com.anggrayudi:materialpreference-compiler:1.7' + kapt 'com.anggrayudi:materialpreference-compiler:1.8' } ```` @@ -328,7 +328,7 @@ Don't forget to check this runtime permission before opening ringtone picker on ## License - Copyright 2018-2021 Anggrayudi Hardiannicko A. + Copyright 2018-2022 Anggrayudi Hardiannicko A. Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. diff --git a/annotation/build.gradle b/annotation/build.gradle index 928e222..7ddee39 100644 --- a/annotation/build.gradle +++ b/annotation/build.gradle @@ -1,9 +1,8 @@ apply plugin: 'java-library' apply plugin: 'kotlin' -group = 'com.anggrayudi' version = "$PROCESSOR_VERSION" -archivesBaseName = 'materialpreference-api' +archivesBaseName = "$POM_ARTIFACT_ID" compileKotlin { kotlinOptions { @@ -18,14 +17,7 @@ compileTestKotlin { } } -ext { - // POM - POM_ARTIFACT_ID = archivesBaseName - VERSION_NAME = version - - POM_NAME = archivesBaseName - POM_PACKAGING = 'jar' - POM_DESCRIPTION = 'Annotation processor API for library MaterialPreference.' +java { + sourceCompatibility = JavaVersion.VERSION_1_8 + targetCompatibility = JavaVersion.VERSION_1_8 } - -apply plugin: "com.vanniktech.maven.publish" \ No newline at end of file diff --git a/annotation/gradle.properties b/annotation/gradle.properties new file mode 100644 index 0000000..26dd801 --- /dev/null +++ b/annotation/gradle.properties @@ -0,0 +1,3 @@ +POM_ARTIFACT_ID=materialpreference-api +POM_NAME=materialpreference-api +POM_DESCRIPTION=Annotation processor API for library MaterialPreference. \ No newline at end of file diff --git a/build.gradle b/build.gradle index 19d7f49..5754468 100644 --- a/build.gradle +++ b/build.gradle @@ -2,7 +2,7 @@ apply from: 'extensions.gradle' buildscript { - ext.kotlin_version = '1.5.10' + ext.kotlin_version = '1.7.20' repositories { google() @@ -11,11 +11,11 @@ buildscript { } dependencies { - classpath 'com.android.tools.build:gradle:4.2.1' - classpath 'com.google.gms:google-services:4.3.8' + classpath 'com.android.tools.build:gradle:7.3.1' + classpath 'com.google.gms:google-services:4.3.14' classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version" - classpath 'com.vanniktech:gradle-maven-publish-plugin:0.15.1' - classpath 'org.jetbrains.dokka:dokka-gradle-plugin:1.4.20' + classpath 'com.vanniktech:gradle-maven-publish-plugin:0.22.0' + classpath 'org.jetbrains.dokka:dokka-gradle-plugin:1.7.20' } } @@ -25,18 +25,33 @@ allprojects { mavenCentral() maven { url "https://oss.sonatype.org/content/repositories/snapshots" } } +} + +subprojects { + if (name != 'sample') { + apply plugin: "com.vanniktech.maven.publish" - //Support @JvmDefault - tasks.withType(org.jetbrains.kotlin.gradle.tasks.KotlinCompile).all { - kotlinOptions { - freeCompilerArgs = ['-Xjvm-default=all', '-Xopt-in=kotlin.RequiresOptIn'] - jvmTarget = '1.8' - includeRuntime = true + repositories { + maven { + url = version.toString().endsWith("SNAPSHOT") + ? 'https://oss.sonatype.org/content/repositories/snapshots/' + : 'https://oss.sonatype.org/service/local/staging/deploy/maven2' + } + } + } + + configurations.all { + 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" + force "junit:junit:4.13.2" } } -} -subprojects { afterEvaluate { // global dependencies for all modules dependencies { diff --git a/extensions.gradle b/extensions.gradle index 240896a..48771ce 100644 --- a/extensions.gradle +++ b/extensions.gradle @@ -1,31 +1,8 @@ ext { appVersionCode = 19 minSdkVersion = 17 - targetSdkVersion = 30 - compileSdkVersion = 30 - buildToolsVersion = '30.0.2' + targetSdkVersion = 33 + compileSdkVersion = 33 dialogVersion = '3.3.0' - coroutinesVersion = '1.4.3' - - // Project - VCS_URL = "https://github.com/anggrayudi/MaterialPreference.git" - GROUP = "com.anggrayudi" - - // POM Project - POM_URL = "https://github.com/anggrayudi/MaterialPreference" - - // POM SCM - POM_SCM_URL = "https://github.com/anggrayudi/MaterialPreference" - POM_SCM_CONNECTION = "scm:git:git://github.com/anggrayudi/MaterialPreference.git" - POM_SCM_DEV_CONNECTION = "scm:git:ssh://github.com:anggrayudi/MaterialPreference.git" - - // POM Licenses - POM_LICENCE_NAME = "The Apache Software License, Version 2.0" - POM_LICENCE_URL = "https://github.com/anggrayudi/MaterialPreference/blob/master/LICENSE" - //POM_LICENCE_DIST = " - - // POM Developers - POM_DEVELOPER_ID = "anggrayudi" - POM_DEVELOPER_NAME = "Anggrayudi H" - POM_DEVELOPER_URL = "https://github.com/anggrayudi/" + coroutinesVersion = '1.6.4' } \ No newline at end of file diff --git a/gradle.properties b/gradle.properties index de7a791..aef352e 100644 --- a/gradle.properties +++ b/gradle.properties @@ -6,5 +6,21 @@ org.gradle.daemon=false #kapt.incremental.apt=true #kapt.use.worker.api=true # ------- Library versions -PROCESSOR_VERSION=1.7 -MATERIAL_PREFERENCE_VERSION=3.7.1 \ No newline at end of file +PROCESSOR_VERSION=1.8 +MATERIAL_PREFERENCE_VERSION=3.8.0-SNAPSHOT +# For publishing: +GROUP=com.anggrayudi +SONATYPE_HOST=DEFAULT +SONATYPE_AUTOMATIC_RELEASE=true +RELEASE_SIGNING_ENABLED=true +POM_INCEPTION_YEAR=2018 +POM_URL=https://github.com/anggrayudi/MaterialPreference +POM_LICENSE_NAME=The Apache Software License, Version 2.0 +POM_LICENSE_URL=https://github.com/anggrayudi/MaterialPreference/blob/master/LICENSE +POM_LICENSE_DIST=https://www.apache.org/licenses/LICENSE-2.0.txt +POM_SCM_URL=https://github.com/anggrayudi/MaterialPreference +POM_SCM_CONNECTION=scm:git:git://github.com/anggrayudi/MaterialPreference.git +POM_SCM_DEV_CONNECTION=scm:git:ssh://github.com:anggrayudi/MaterialPreference.git +POM_DEVELOPER_ID=anggrayudi +POM_DEVELOPER_NAME=Anggrayudi H +POM_DEVELOPER_URL=https://github.com/anggrayudi/ diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties index cd1be81..7e78024 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-6.7.1-bin.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-7.4-all.zip diff --git a/materialpreference/build.gradle b/materialpreference/build.gradle index c153375..38c9b42 100644 --- a/materialpreference/build.gradle +++ b/materialpreference/build.gradle @@ -1,12 +1,11 @@ apply plugin: 'com.android.library' apply plugin: 'kotlin-android' -group = 'com.anggrayudi' version = "$MATERIAL_PREFERENCE_VERSION" +archivesBaseName = "$POM_ARTIFACT_ID" android { compileSdkVersion rootProject.ext.compileSdkVersion - buildToolsVersion rootProject.ext.buildToolsVersion defaultConfig { minSdkVersion rootProject.ext.minSdkVersion @@ -33,33 +32,26 @@ android { } dependencies { - api 'androidx.appcompat:appcompat:1.3.0' - api 'com.google.android.material:material:1.3.0' + api 'androidx.appcompat:appcompat:1.5.1' + api 'com.google.android.material:material:1.7.0' api 'androidx.documentfile:documentfile:1.0.1' api 'androidx.cardview:cardview:1.0.0' - api 'com.karumi:dexter:6.2.2' api 'com.wdullaer:materialdatetimepicker:4.2.3' api "com.afollestad.material-dialogs:core:$dialogVersion" api "com.afollestad.material-dialogs:files:$dialogVersion" api "com.afollestad.material-dialogs:color:$dialogVersion" api "com.anggrayudi:materialpreference-api:$PROCESSOR_VERSION" + compileOnly project(':annotation') api "org.jetbrains.kotlinx:kotlinx-coroutines-core:$coroutinesVersion" api "org.jetbrains.kotlinx:kotlinx-coroutines-android:$coroutinesVersion" - api "com.anggrayudi:storage:0.8.0" -// api("com.anggrayudi:storage:0.6.0-SNAPSHOT") { changing = true } + api "com.anggrayudi:storage:1.5.1" +// api("com.anggrayudi:storage:1.5.1-SNAPSHOT") { changing = true } } -ext { - // POM - POM_ARTIFACT_ID = archivesBaseName - VERSION_NAME = version - - POM_NAME = archivesBaseName - POM_PACKAGING = 'aar' - POM_DESCRIPTION = 'A library designed to replace default preferences on Android framework with something beauty.' +configurations.all { + // Check for updates every build + resolutionStrategy.cacheChangingModulesFor 0, 'seconds' } - -apply plugin: "com.vanniktech.maven.publish" \ No newline at end of file diff --git a/materialpreference/gradle.properties b/materialpreference/gradle.properties new file mode 100644 index 0000000..ab77513 --- /dev/null +++ b/materialpreference/gradle.properties @@ -0,0 +1,3 @@ +POM_ARTIFACT_ID=materialpreference +POM_NAME=materialpreference +POM_DESCRIPTION=A library designed to replace default preferences on Android framework with something beauty. \ No newline at end of file diff --git a/materialpreference/src/main/java/com/anggrayudi/materialpreference/FolderPreference.kt b/materialpreference/src/main/java/com/anggrayudi/materialpreference/FolderPreference.kt index 01aad7b..a712b12 100644 --- a/materialpreference/src/main/java/com/anggrayudi/materialpreference/FolderPreference.kt +++ b/materialpreference/src/main/java/com/anggrayudi/materialpreference/FolderPreference.kt @@ -2,20 +2,13 @@ package com.anggrayudi.materialpreference import android.annotation.SuppressLint import android.annotation.TargetApi -import android.app.Dialog import android.content.Context -import android.os.Build -import android.os.Bundle import android.util.AttributeSet import androidx.annotation.Keep -import androidx.fragment.app.DialogFragment -import com.afollestad.materialdialogs.MaterialDialog -import com.afollestad.materialdialogs.files.folderChooser -import com.afollestad.materialdialogs.files.selectedFolder import com.anggrayudi.materialpreference.util.FolderType -import com.anggrayudi.storage.SimpleStorageHelper +import com.anggrayudi.storage.SimpleStorage +import com.anggrayudi.storage.file.FileFullPath import com.anggrayudi.storage.file.getAbsolutePath -import java.io.File /** * | Attribute | Value Type | @@ -68,46 +61,21 @@ open class FolderPreference @Keep @JvmOverloads constructor( a.recycle() onPreferenceClickListener = { - SimpleStorageHelper.requestStoragePermission(context) { openFolderSelector() } + openFolderSelector() true } } private fun openFolderSelector() { val fragment = preferenceFragment ?: return - if (Build.VERSION.SDK_INT < Build.VERSION_CODES.LOLLIPOP) { - FolderPreferenceDialog().apply { - arguments = Bundle().apply { putString("folder", folder) } - show(fragment.parentFragmentManager, key) + fragment.storageHelper.run { + onFolderSelected = { _, folder -> + this@FolderPreference.folder = folder.getAbsolutePath(context) } - } else { - fragment.storageHelper.run { - onFolderSelected = { _, folder -> - this@FolderPreference.folder = folder.getAbsolutePath(context) - } - openFolderPicker(REQUEST_CODE_STORAGE_GET_FOLDER) - } - } - } - - class FolderPreferenceDialog : DialogFragment() { - - private var dialog: MaterialDialog? = null - - override fun onCreateDialog(savedInstanceState: Bundle?): Dialog { - dialog = MaterialDialog(requireContext()) - .negativeButton(android.R.string.cancel) - .folderChooser(requireContext(), File(requireArguments().getString("folder")!!), allowFolderCreation = true) { _, file -> - val preference = (activity as PreferenceActivityMaterial) - .visiblePreferenceFragment!!.findPreference(tag!!) as FolderPreference - preference.folder = file.absolutePath - } - return dialog as MaterialDialog - } - - override fun onSaveInstanceState(outState: Bundle) { - super.onSaveInstanceState(outState) - requireArguments().putString("folder", dialog!!.selectedFolder()!!.absolutePath) + openFolderPicker( + REQUEST_CODE_STORAGE_GET_FOLDER, + initialPath = FileFullPath(fragment.requireContext(), folder ?: SimpleStorage.externalStoragePath) + ) } } diff --git a/materialpreference/src/main/java/com/anggrayudi/materialpreference/PreferenceFragmentMaterial.kt b/materialpreference/src/main/java/com/anggrayudi/materialpreference/PreferenceFragmentMaterial.kt index e5f1754..1117273 100644 --- a/materialpreference/src/main/java/com/anggrayudi/materialpreference/PreferenceFragmentMaterial.kt +++ b/materialpreference/src/main/java/com/anggrayudi/materialpreference/PreferenceFragmentMaterial.kt @@ -20,12 +20,7 @@ import androidx.fragment.app.DialogFragment import androidx.fragment.app.Fragment import com.anggrayudi.materialpreference.dialog.* import com.anggrayudi.storage.SimpleStorageHelper -import com.karumi.dexter.Dexter -import com.karumi.dexter.PermissionToken -import com.karumi.dexter.listener.PermissionDeniedResponse -import com.karumi.dexter.listener.PermissionGrantedResponse -import com.karumi.dexter.listener.PermissionRequest -import com.karumi.dexter.listener.single.PermissionListener +import com.anggrayudi.storage.permission.* /** * A fragment class to manage and display all preferences. @@ -61,6 +56,9 @@ abstract class PreferenceFragmentMaterial : Fragment(), } } + private lateinit var ringtonePermissionRequest: FragmentPermissionRequest + private var ringtonePreferenceKey: String? = null + private val requestFocus = Runnable { scrollView?.focusableViewAvailable(scrollView) } private var selectPreferenceRunnable: Runnable? = null @@ -161,6 +159,25 @@ abstract class PreferenceFragmentMaterial : Fragment(), (activity as PreferenceActivityMaterial).onCreatePreferences(this, rootKey) storageHelper = SimpleStorageHelper(this, savedInstanceState) + + ringtonePermissionRequest = FragmentPermissionRequest.Builder(this) + .withPermissions(Manifest.permission.READ_EXTERNAL_STORAGE) + .withCallback(object : PermissionCallback { + override fun onPermissionsChecked(result: PermissionResult, fromSystemDialog: Boolean) { + if (ringtonePreferenceKey != null && result.areAllPermissionsGranted) { + RingtonePreferenceDialogFragment.newInstance(ringtonePreferenceKey!!).let { + it.requireArguments().putString(TAG, requireTag()) + it.show(parentFragmentManager, DIALOG_FRAGMENT_TAG) + } + } + ringtonePreferenceKey = null + } + + override fun onShouldRedirectToSystemSettings(blockedPermissions: List) { + SimpleStorageHelper.redirectToSystemSettings(requireContext()) + } + }) + .build() } /** @@ -360,7 +377,6 @@ abstract class PreferenceFragmentMaterial : Fragment(), * @param preference The Preference object requesting the dialog. */ override fun onDisplayPreferenceDialog(preference: Preference) { - var handled = false if (callbackFragment is OnPreferenceDisplayDialogCallback) { handled = (callbackFragment as OnPreferenceDisplayDialogCallback) @@ -380,10 +396,9 @@ abstract class PreferenceFragmentMaterial : Fragment(), return } - val preferenceFragmentTag = tag ?: throw IllegalStateException("${javaClass.name} must have a tag.") - if (preference is RingtonePreference) { - openRingtonePreference(preference.key!!, preferenceFragmentTag) + ringtonePreferenceKey = preference.key + ringtonePermissionRequest.check() return } @@ -396,30 +411,11 @@ abstract class PreferenceFragmentMaterial : Fragment(), is ColorPreference -> ColorPreferenceDialogFragment.newInstance(preference.key!!) else -> throw IllegalArgumentException("Tried to display dialog for unknown preference type. Did you forget to override onDisplayPreferenceDialog()?") } - f.requireArguments().putString(TAG, preferenceFragmentTag) + f.requireArguments().putString(TAG, requireTag()) f.show(parentFragmentManager, DIALOG_FRAGMENT_TAG) } - private fun openRingtonePreference(preferenceKey: String, preferenceFragmentTag: String) { - Dexter.withContext(requireContext()) - .withPermission(Manifest.permission.READ_EXTERNAL_STORAGE) - .withListener(object : PermissionListener { - override fun onPermissionGranted(response: PermissionGrantedResponse) { - RingtonePreferenceDialogFragment.newInstance(preferenceKey).let { - it.requireArguments().putString(TAG, preferenceFragmentTag) - it.show(parentFragmentManager, DIALOG_FRAGMENT_TAG) - } - } - - override fun onPermissionDenied(response: PermissionDeniedResponse) { - // no-op - } - - override fun onPermissionRationaleShouldBeShown(request: PermissionRequest, token: PermissionToken) { - // no-op - } - }).check() - } + private fun requireTag() = tag ?: throw IllegalStateException("${javaClass.name} must have a tag.") fun scrollToPreference(key: String) { scrollToPreferenceInternal(null, key) diff --git a/materialpreference/src/main/java/com/anggrayudi/materialpreference/dialog/RingtonePreferenceDialogFragment.kt b/materialpreference/src/main/java/com/anggrayudi/materialpreference/dialog/RingtonePreferenceDialogFragment.kt index 243ccbd..09ac111 100644 --- a/materialpreference/src/main/java/com/anggrayudi/materialpreference/dialog/RingtonePreferenceDialogFragment.kt +++ b/materialpreference/src/main/java/com/anggrayudi/materialpreference/dialog/RingtonePreferenceDialogFragment.kt @@ -1,6 +1,7 @@ package com.anggrayudi.materialpreference.dialog import android.app.Activity +import android.content.ActivityNotFoundException import android.database.Cursor import android.media.AudioManager import android.media.Ringtone @@ -18,8 +19,6 @@ import com.afollestad.materialdialogs.list.listItemsSingleChoice import com.anggrayudi.materialpreference.RingtoneManagerCompat import com.anggrayudi.materialpreference.RingtonePreference import com.anggrayudi.materialpreference.SafeRingtone -import com.anggrayudi.storage.extension.hasActivityHandler -import java.util.* /** * Created by Eugen on 07.12.2015. @@ -144,9 +143,9 @@ class RingtonePreferenceDialogFragment : PreferenceDialogFragment(), Runnable { // Alternatively try starting system picker. val intent = preference.buildRingtonePickerIntent() - if (intent.hasActivityHandler(requireContext())) { + try { ringtonePickerLauncher.launch(intent) - } else { + } catch (e: ActivityNotFoundException) { onRingtonePickerNotFound() } } diff --git a/processor/build.gradle b/processor/build.gradle index 8b2eb92..691354c 100644 --- a/processor/build.gradle +++ b/processor/build.gradle @@ -2,9 +2,8 @@ apply plugin: 'java-library' apply plugin: 'kotlin' apply plugin: 'kotlin-kapt' -group = 'com.anggrayudi' version = "$PROCESSOR_VERSION" -archivesBaseName = 'materialpreference-compiler' +archivesBaseName = "$POM_ARTIFACT_ID" compileKotlin { kotlinOptions { @@ -34,25 +33,18 @@ sourceSets { } } +java { + sourceCompatibility = JavaVersion.VERSION_1_8 + targetCompatibility = JavaVersion.VERSION_1_8 +} + dependencies { compileOnly project(':annotation') implementation 'org.ogce:xpp3:1.1.6' implementation 'xmlpull:xmlpull:1.1.3.1' - implementation 'com.squareup:kotlinpoet:1.5.0' + implementation 'com.squareup:kotlinpoet:1.12.0' - def autoServiceVersion = '1.0-rc6' + def autoServiceVersion = '1.0.1' implementation "com.google.auto.service:auto-service:$autoServiceVersion" kapt "com.google.auto.service:auto-service:$autoServiceVersion" } - -ext { - // POM - POM_ARTIFACT_ID = archivesBaseName - VERSION_NAME = version - - POM_NAME = archivesBaseName - POM_PACKAGING = 'jar' - POM_DESCRIPTION = 'Annotation processor for library MaterialPreference.' -} - -apply plugin: "com.vanniktech.maven.publish" \ No newline at end of file diff --git a/processor/gradle.properties b/processor/gradle.properties new file mode 100644 index 0000000..6b3523d --- /dev/null +++ b/processor/gradle.properties @@ -0,0 +1,3 @@ +POM_ARTIFACT_ID=materialpreference-compiler +POM_NAME=materialpreference-compiler +POM_DESCRIPTION=Annotation processor for library MaterialPreference. \ No newline at end of file diff --git a/processor/src/main/java/com/anggrayudi/materialpreference/processor/PreferencesProcessor.kt b/processor/src/main/java/com/anggrayudi/materialpreference/processor/PreferencesProcessor.kt index 8bef2dd..282e1a0 100644 --- a/processor/src/main/java/com/anggrayudi/materialpreference/processor/PreferencesProcessor.kt +++ b/processor/src/main/java/com/anggrayudi/materialpreference/processor/PreferencesProcessor.kt @@ -27,8 +27,10 @@ class PreferencesProcessor : AbstractProcessor() { } // D:\YourProjectDirs\app\build\generated\source\kaptKotlin\debug - val resFile = File(File(generatedSourcesRoot).parentFile.parentFile.parentFile.parentFile.parentFile, - "src${File.separator}main${File.separator}res${File.separator}") + val resFile = File( + File(generatedSourcesRoot).parentFile.parentFile.parentFile.parentFile.parentFile, + "src${File.separator}main${File.separator}res${File.separator}" + ) val a = it.getAnnotation(PreferencesConfig::class.java) val xmlRes = a.preferencesXmlRes.toXmlFileName() @@ -41,16 +43,20 @@ class PreferencesProcessor : AbstractProcessor() { val prefKeyClassBuilder = TypeSpec.objectBuilder(a.prefKeyClassName) val prefHelperClassBuilder = TypeSpec.classBuilder(a.prefHelperClassName) - .primaryConstructor(FunSpec.constructorBuilder().addParameter("context", ClassName("android.content", "Context")).build()) - .addProperty(PropertySpec.builder("preferences", ClassName("android.content", "SharedPreferences")) - .initializer("%T.getDefaultSharedPreferences(context)", ClassName("com.anggrayudi.materialpreference", "PreferenceManager")) - .build()) + .primaryConstructor(FunSpec.constructorBuilder().addParameter("context", ClassName("android.content", "Context")).build()) + .addProperty( + PropertySpec.builder("preferences", ClassName("android.content", "SharedPreferences")) + .initializer("%T.getDefaultSharedPreferences(context)", ClassName("com.anggrayudi.materialpreference", "PreferenceManager")) + .build() + ) val specs = getPreferenceSpecs(xmlFile, a.capitalStyle) specs.forEach { spec -> - prefKeyClassBuilder.addProperty(PropertySpec.builder(spec.constantName, String::class, KModifier.CONST) + prefKeyClassBuilder.addProperty( + PropertySpec.builder(spec.constantName, String::class, KModifier.CONST) .initializer("%S", spec.key) - .build()) + .build() + ) if (spec.dataType != PreferenceDataType.NOTHING && spec.methodName != null) { val getterBuilder = FunSpec.getterBuilder() @@ -62,13 +68,18 @@ class PreferencesProcessor : AbstractProcessor() { val defaultValue = getStringSetDefaultValue(spec) if (defaultValue.isNotEmpty()) { - getterBuilder.addStatement("return preferences.getStringSet(%S, mutableSetOf(%L)) ?: mutableSetOf(%L)", spec.key, defaultValue, defaultValue) + getterBuilder.addStatement( + "return preferences.getStringSet(%S, mutableSetOf(%L)) ?: mutableSetOf(%L)", + spec.key, + defaultValue, + defaultValue + ) } else { getterBuilder.addStatement("return preferences.getStringSet(%S, mutableSetOf()) ?: mutableSetOf()", spec.key) } setterBuilder.addParameter("value", parameterSpec) - .addStatement("preferences.edit().putStringSet(%S, value).apply()", spec.key) + .addStatement("preferences.edit().putStringSet(%S, value).apply()", spec.key) PropertySpec.builder(spec.methodName!!, parameterSpec) } @@ -81,7 +92,7 @@ class PreferencesProcessor : AbstractProcessor() { } setterBuilder.addParameter("value", Boolean::class) - .addStatement("preferences.edit().putBoolean(%S, value).apply()", spec.key) + .addStatement("preferences.edit().putBoolean(%S, value).apply()", spec.key) PropertySpec.builder(spec.methodName!!, Boolean::class) } @@ -94,7 +105,7 @@ class PreferencesProcessor : AbstractProcessor() { } setterBuilder.addParameter("value", Int::class) - .addStatement("preferences.edit().putInt(%S, value).apply()", spec.key) + .addStatement("preferences.edit().putInt(%S, value).apply()", spec.key) PropertySpec.builder(spec.methodName!!, Int::class) } @@ -107,7 +118,7 @@ class PreferencesProcessor : AbstractProcessor() { } setterBuilder.addParameter("value", Float::class) - .addStatement("preferences.edit().putFloat(%S, value).apply()", spec.key) + .addStatement("preferences.edit().putFloat(%S, value).apply()", spec.key) PropertySpec.builder(spec.methodName!!, Float::class) } @@ -120,7 +131,7 @@ class PreferencesProcessor : AbstractProcessor() { } setterBuilder.addParameter("value", Long::class) - .addStatement("preferences.edit().putLong(%S, value).apply()", spec.key) + .addStatement("preferences.edit().putLong(%S, value).apply()", spec.key) PropertySpec.builder(spec.methodName!!, Long::class) } @@ -129,19 +140,19 @@ class PreferencesProcessor : AbstractProcessor() { val timeClass = ClassName("com.anggrayudi.materialpreference", "TimePreference").nestedClass("Time") if (spec.defaultValue != null && spec.defaultValue != "@null") { getterBuilder.addStatement("val time = preferences.getString(%S, %S) ?: %S", spec.key, spec.defaultValue!!, spec.defaultValue!!) - .addStatement("return TimePreference.toTime(time)") + .addStatement("return TimePreference.toTime(time)") setterBuilder.addParameter("value", timeClass) - .addStatement("preferences.edit().putString(%S, value.toString()).apply()", spec.key) + .addStatement("preferences.edit().putString(%S, value.toString()).apply()", spec.key) PropertySpec.builder(spec.methodName!!, timeClass) } else { getterBuilder.addStatement("val time = preferences.getString(%S, null)", spec.key) - .addStatement("return if (time != null) TimePreference.toTime(time) else null", spec.key) + .addStatement("return if (time != null) TimePreference.toTime(time) else null", spec.key) val nullableTime = timeClass.copy(nullable = true) setterBuilder.addParameter("value", nullableTime) - .addStatement("preferences.edit().putString(%S, value?.toString()).apply()", spec.key) + .addStatement("preferences.edit().putString(%S, value?.toString()).apply()", spec.key) PropertySpec.builder(spec.methodName!!, nullableTime) } @@ -152,7 +163,7 @@ class PreferencesProcessor : AbstractProcessor() { getterBuilder.addStatement("return preferences.getString(%S, %S) ?: %S", spec.key, spec.defaultValue!!, spec.defaultValue!!) setterBuilder.addParameter("value", String::class) - .addStatement("preferences.edit().putString(%S, value).apply()", spec.key) + .addStatement("preferences.edit().putString(%S, value).apply()", spec.key) PropertySpec.builder(spec.methodName!!, String::class) } else { @@ -160,7 +171,7 @@ class PreferencesProcessor : AbstractProcessor() { val parameterSpec = String::class.asTypeName().copy(nullable = true) setterBuilder.addParameter("value", parameterSpec) - .addStatement("preferences.edit().putString(%S, value).apply()", spec.key) + .addStatement("preferences.edit().putString(%S, value).apply()", spec.key) PropertySpec.builder(spec.methodName!!, parameterSpec) } @@ -168,8 +179,8 @@ class PreferencesProcessor : AbstractProcessor() { } propertyBuilder.mutable(true) - .getter(getterBuilder.build()) - .setter(setterBuilder.build()) + .getter(getterBuilder.build()) + .setter(setterBuilder.build()) prefHelperClassBuilder.addProperty(propertyBuilder.build()).build() } @@ -178,11 +189,13 @@ class PreferencesProcessor : AbstractProcessor() { val withDefaultValue = specs.filter { spec -> spec.defaultValue != null || spec.dataType == PreferenceDataType.STRING_SET } if (withDefaultValue.isNotEmpty()) { val functionBuilder = FunSpec.builder("setDefaultPreferenceValues") - .addKdoc("All preferences that do not define `android:defaultValue` wont be included into this method." + - "\nBTW, you can use `@null` to define `null` value like this => `android:defaultValue=\"@null\"`") - .addAnnotation(JvmStatic::class) - .addParameter("context", ClassName("android.content", "Context")) - .addStatement("%T.getDefaultSharedPreferences(context).edit()", ClassName("com.anggrayudi.materialpreference", "PreferenceManager")) + .addKdoc( + "All preferences that do not define `android:defaultValue` wont be included into this method." + + "\nBTW, you can use `@null` to define `null` value like this => `android:defaultValue=\"@null\"`" + ) + .addAnnotation(JvmStatic::class) + .addParameter("context", ClassName("android.content", "Context")) + .addStatement("%T.getDefaultSharedPreferences(context).edit()", ClassName("com.anggrayudi.materialpreference", "PreferenceManager")) withDefaultValue.forEach { spec -> when (spec.dataType) { @@ -223,8 +236,8 @@ class PreferencesProcessor : AbstractProcessor() { functionBuilder.addStatement(".apply()") val companionBlock = TypeSpec.companionObjectBuilder() - .addFunction(functionBuilder.build()) - .build() + .addFunction(functionBuilder.build()) + .build() prefHelperClassBuilder.addType(companionBlock) } @@ -232,14 +245,14 @@ class PreferencesProcessor : AbstractProcessor() { val packageName = processingEnv.elementUtils.getPackageOf(it).qualifiedName.toString().substringBeforeLast(".java") FileSpec.builder(packageName, a.prefKeyClassName) - .addType(prefKeyClassBuilder.build()) - .build() - .writeTo(File(generatedSourcesRoot).apply { mkdirs() }) + .addType(prefKeyClassBuilder.build()) + .build() + .writeTo(File(generatedSourcesRoot).apply { mkdirs() }) FileSpec.builder(packageName, a.prefHelperClassName) - .addType(prefHelperClassBuilder.build()) - .build() - .writeTo(File(generatedSourcesRoot)) + .addType(prefHelperClassBuilder.build()) + .build() + .writeTo(File(generatedSourcesRoot)) return false } return false @@ -360,9 +373,9 @@ class PreferencesProcessor : AbstractProcessor() { return if (!capitalStyle) key else if (key.contains("_")) { - key.toUpperCase(Locale.US) + key.uppercase() } else { - val resolvedKey = key.split(Regex("(?=[A-Z])")).joinToString("_").toUpperCase(Locale.US) + val resolvedKey = key.split(Regex("(?=[A-Z])")).joinToString("_").uppercase() if (resolvedKey.startsWith("_")) resolvedKey.replaceFirst("_", "") else @@ -373,17 +386,18 @@ class PreferencesProcessor : AbstractProcessor() { private fun createMethodName(key: String, dataType: PreferenceDataType): String { val methodWords = (if (key.contains("_")) key.split("_") else key.split(Regex("(?=[A-Z])"))).filter { it.isNotBlank() } return if (dataType == PreferenceDataType.BOOLEAN) { - "is" + methodWords.joinToString("") { it.capitalize() } + "is" + methodWords.joinToString("") { it.replaceFirstChar { c -> c.uppercase() } } } else { - methodWords[0].decapitalize() + methodWords.takeLast(methodWords.size - 1).joinToString("") { it.capitalize() } + methodWords[0].replaceFirstChar { it.lowercase() } + methodWords.takeLast(methodWords.size - 1) + .joinToString("") { it.replaceFirstChar { c -> c.uppercase() } } } } private fun getStringSetDefaultValue(spec: PreferenceSpec) = spec.defaultValue?.toString().orEmpty() - .split(",") - .map { s -> s.trim() } - .filter { s -> s.isNotEmpty() } - .joinToString(",") { s -> "\"$s\"" } + .split(",") + .map { s -> s.trim() } + .filter { s -> s.isNotEmpty() } + .joinToString(",") { s -> "\"$s\"" } private fun String.toXmlFileName() = if (endsWith(".xml")) this else "$this.xml" diff --git a/sample/build.gradle b/sample/build.gradle index e1df268..c300d99 100644 --- a/sample/build.gradle +++ b/sample/build.gradle @@ -13,7 +13,6 @@ android { } compileSdkVersion rootProject.ext.compileSdkVersion - buildToolsVersion rootProject.ext.buildToolsVersion defaultConfig { applicationId "com.anggrayudi.materialpreference.sample" @@ -21,6 +20,7 @@ android { targetSdkVersion rootProject.ext.targetSdkVersion versionCode rootProject.ext.appVersionCode versionName "$MATERIAL_PREFERENCE_VERSION" + multiDexEnabled true testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" } buildTypes { @@ -69,23 +69,24 @@ configurations { dependencies { testImplementation 'junit:junit:4.13.2' - androidTestImplementation 'androidx.test:runner:1.3.0' - androidTestImplementation 'androidx.test.espresso:espresso-core:3.3.0' + androidTestImplementation 'androidx.test:runner:1.5.1' + androidTestImplementation 'androidx.test.espresso:espresso-core:3.5.0' implementation 'androidx.recyclerview:recyclerview:1.2.1' - implementation "io.insert-koin:koin-android:3.0.1" + implementation 'io.insert-koin:koin-android:3.3.0' + implementation 'androidx.multidex:multidex:2.0.1' implementation project(':materialpreference') compileOnly project(':annotation') kapt project(':processor') -// kapt 'com.anggrayudi:materialpreference-compiler:1.7' +// kapt 'com.anggrayudi:materialpreference-compiler:1.8' // localImplementation project(":materialpreference") // localCompileOnly project(':annotation') // mavenImplementation("com.anggrayudi:materialpreference:$MATERIAL_PREFERENCE_VERSION") { changing = true } -// mavenImplementation 'com.anggrayudi:materialpreference-api:1.7' +// mavenImplementation 'com.anggrayudi:materialpreference-api:1.8' } tasks.withType(JavaCompile) { diff --git a/sample/src/main/AndroidManifest.xml b/sample/src/main/AndroidManifest.xml index 392e5a0..ea1d88a 100644 --- a/sample/src/main/AndroidManifest.xml +++ b/sample/src/main/AndroidManifest.xml @@ -3,9 +3,9 @@ xmlns:tools="http://schemas.android.com/tools" package="com.anggrayudi.materialpreference.sample"> - - - + + + - + - - + + - - \ No newline at end of file diff --git a/sample/src/main/java/com/anggrayudi/materialpreference/sample/App.kt b/sample/src/main/java/com/anggrayudi/materialpreference/sample/App.kt index 501271e..71105c6 100644 --- a/sample/src/main/java/com/anggrayudi/materialpreference/sample/App.kt +++ b/sample/src/main/java/com/anggrayudi/materialpreference/sample/App.kt @@ -1,10 +1,10 @@ package com.anggrayudi.materialpreference.sample -import android.app.Application import android.content.Context import android.content.SharedPreferences import android.graphics.Color import android.os.Environment +import androidx.multidex.MultiDexApplication import com.anggrayudi.materialpreference.PreferenceManager import com.anggrayudi.materialpreference.PreferenceManager.Companion.KEY_HAS_SET_DEFAULT_VALUES import com.anggrayudi.materialpreference.migration.MigrationPlan @@ -14,7 +14,7 @@ import org.koin.android.ext.koin.androidContext import org.koin.core.context.startKoin import org.koin.dsl.module -class App : Application() { +class App : MultiDexApplication() { override fun onCreate() { super.onCreate() diff --git a/sample/src/main/java/com/anggrayudi/materialpreference/sample/SettingsFragment.kt b/sample/src/main/java/com/anggrayudi/materialpreference/sample/SettingsFragment.kt index ce17ade..e3a8e2a 100644 --- a/sample/src/main/java/com/anggrayudi/materialpreference/sample/SettingsFragment.kt +++ b/sample/src/main/java/com/anggrayudi/materialpreference/sample/SettingsFragment.kt @@ -19,7 +19,7 @@ import com.anggrayudi.materialpreference.annotation.PreferencesConfig * * dependencies { * implementation 'com.anggrayudi:materialpreference:3.7.0' - * kapt 'com.anggrayudi:materialpreference-compiler:1.7' + * kapt 'com.anggrayudi:materialpreference-compiler:1.' * } */ @PreferencesConfig