diff --git a/.github/workflows/build-and-test.yml b/.github/workflows/build-and-test.yml index 1e1d8a0..bbe24c0 100644 --- a/.github/workflows/build-and-test.yml +++ b/.github/workflows/build-and-test.yml @@ -9,10 +9,11 @@ jobs: steps: - name: Check out code uses: actions/checkout@v2 - - name: Set up JDK 1.8 - uses: actions/setup-java@v1 + - name: Set up JDK 11 + uses: actions/setup-java@v2 with: - java-version: 1.8 + distribution: adopt + java-version: 11 - name: Debug build run: ./gradlew assembleDebug --stacktrace - name: Unit test diff --git a/.github/workflows/publish.yml b/.github/workflows/publish.yml index 2097f0f..7bfc28a 100644 --- a/.github/workflows/publish.yml +++ b/.github/workflows/publish.yml @@ -1,9 +1,8 @@ name: Publish on: - push: - tags: - - "*-RELEASE" + release: + types: [ released ] jobs: publish: @@ -12,10 +11,11 @@ jobs: steps: - name: Check out code uses: actions/checkout@v2 - - name: Set up JDK 1.8 - uses: actions/setup-java@v1 + - name: Set up JDK 11 + uses: actions/setup-java@v2 with: - java-version: 1.8 + distribution: adopt + java-version: 11 - name: Release build and source jar generation run: ./gradlew assembleRelease androidSourcesJar -x :app:assembleRelease - name: Publish to MavenCentral diff --git a/README.md b/README.md index 6318ef6..530f808 100644 --- a/README.md +++ b/README.md @@ -27,7 +27,7 @@ Log.d("LOGIN_COUNT", "Count: ${settings.loginCount}") You can include _Krate_ in your project from the `mavenCentral()` repository, like so: ```groovy -implementation 'hu.autsoft:krate:1.1.0' +implementation 'hu.autsoft:krate:1.2.0' ``` # Optionals vs defaults @@ -152,7 +152,7 @@ class CustomMoshiKrate(context: Context) : SimpleKrate(context) { If you only want to use Moshi adapters that you generate via Moshi's [codegen facilities](https://github.com/square/moshi#codegen), you can use the following Krate artifact in your project to make use of these adapters: ```groovy -implementation 'hu.autsoft:krate-moshi-codegen:1.1.0' +implementation 'hu.autsoft:krate-moshi-codegen:1.2.0' ``` This will give you a default `Moshi` instance created by a call to `Moshi.Builder().build()`. This instance will find and use any of the adapters generated by Moshi's codegen automatically. @@ -162,7 +162,7 @@ This will give you a default `Moshi` instance created by a call to `Moshi.Builde If you rely on [reflection](https://github.com/square/moshi#reflection) for your Moshi serialization, and therefore need a `KotlinJsonAdapterFactory` included in your `Moshi` instance, use the following Krate Moshi dependency: ```groovy -implementation 'hu.autsoft:krate-moshi-reflect:1.1.0' +implementation 'hu.autsoft:krate-moshi-reflect:1.2.0' ``` The default `Moshi` instance from this dependency will include the aforementioned factory, and be able to serialize any Kotlin class. Note that this approach relies on the `kotlin-reflect` library, which is a large dependency. @@ -174,7 +174,7 @@ You may choose to use Moshi's codegen for some classes in your project, and seri The `krate-kotlinx` artifact provides a `kotlinxPref` delegate which can store any arbitrary type, as long as Kotlinx.serializazion can serialize and deserialize it. This addon, like the base library, is available from `mavenCentral()`: ```groovy -implementation 'hu.autsoft:krate-kotlinx:1.1.0' +implementation 'hu.autsoft:krate-kotlinx:1.2.0' ``` Its usage is the same as with any of the base library's delegates: @@ -206,7 +206,7 @@ class CustomKotlinxKrate(context: Context) : SimpleKrate(context) { The `krate-gson` artifact provides a `gsonPref` delegate which can store any arbitrary type, as long as Gson can serialize and deserialize it. This addon, like the base library, is available from `mavenCentral()`: ```groovy -implementation 'hu.autsoft:krate-gson:1.1.0' +implementation 'hu.autsoft:krate-gson:1.2.0' ``` Its basic usage is the same as with any of the base library's delegates: diff --git a/app/build.gradle b/app/build.gradle index cad617e..3d85abb 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -1,6 +1,5 @@ apply plugin: 'com.android.application' apply plugin: 'kotlin-android' -apply plugin: 'kotlin-android-extensions' android { compileSdkVersion compile_sdk @@ -17,16 +16,18 @@ android { proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' } } + buildFeatures { + viewBinding true + } } dependencies { - implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version" - implementation 'com.google.android.material:material:1.2.1' - implementation 'androidx.appcompat:appcompat:1.2.0' - implementation 'androidx.constraintlayout:constraintlayout:2.0.2' + implementation 'com.google.android.material:material:1.4.0' + implementation 'androidx.appcompat:appcompat:1.3.1' + implementation 'androidx.constraintlayout:constraintlayout:2.1.0' // Third-party SharedPreferences implementations - implementation "androidx.security:security-crypto:1.1.0-alpha02" + implementation "androidx.security:security-crypto:1.1.0-alpha03" implementation 'com.frybits.harmony:harmony:1.1.2' implementation project(path: ':krate') diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index 6a4a625..d36d87a 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -3,13 +3,15 @@ package="hu.autsoft.krateexample"> - + diff --git a/app/src/main/java/hu/autsoft/krateexample/ExampleActivity.kt b/app/src/main/java/hu/autsoft/krateexample/ExampleActivity.kt index ca9bd79..7af8757 100644 --- a/app/src/main/java/hu/autsoft/krateexample/ExampleActivity.kt +++ b/app/src/main/java/hu/autsoft/krateexample/ExampleActivity.kt @@ -2,10 +2,10 @@ package hu.autsoft.krateexample import android.os.Bundle import androidx.appcompat.app.AppCompatActivity +import hu.autsoft.krateexample.databinding.ActivityExampleBinding import hu.autsoft.krateexample.krates.ExampleCustomKrate import hu.autsoft.krateexample.krates.ExampleSettings import hu.autsoft.krateexample.krates.ExampleSimpleKrate -import kotlinx.android.synthetic.main.activity_example.* class ExampleActivity : AppCompatActivity() { @@ -17,9 +17,13 @@ class ExampleActivity : AppCompatActivity() { lateinit var exampleSettings: ExampleSettings + private lateinit var binding: ActivityExampleBinding + override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) - setContentView(R.layout.activity_example) + + binding = ActivityExampleBinding.inflate(layoutInflater) + setContentView(binding.root) when (intent.getStringExtra(KEY_KRATE_TYPE)) { TYPE_SIMPLE -> { @@ -37,23 +41,24 @@ class ExampleActivity : AppCompatActivity() { override fun onResume() { super.onResume() - booleanPreference.isChecked = exampleSettings.exampleBoolean - floatPreferenceInput.setText(exampleSettings.exampleFloat.toString()) - intPreferenceInput.setText(exampleSettings.exampleInt.toString()) - longPreferenceInput.setText(exampleSettings.exampleLong.toString()) - stringPreferenceInput.setText(exampleSettings.exampleString) - stringSetPreferenceInput.setText(exampleSettings.exampleStringSet.joinToString(separator = ", ")) + binding.booleanPreference.isChecked = exampleSettings.exampleBoolean + binding.floatPreferenceInput.setText(exampleSettings.exampleFloat.toString()) + binding.intPreferenceInput.setText(exampleSettings.exampleInt.toString()) + binding.longPreferenceInput.setText(exampleSettings.exampleLong.toString()) + binding.stringPreferenceInput.setText(exampleSettings.exampleString) + binding.stringSetPreferenceInput.setText(exampleSettings.exampleStringSet.joinToString(separator = ", ")) } override fun onPause() { super.onPause() - exampleSettings.exampleBoolean = booleanPreference.isChecked - exampleSettings.exampleFloat = floatPreferenceInput.text.toString().toFloat() - exampleSettings.exampleInt = intPreferenceInput.text.toString().toInt() - exampleSettings.exampleLong = longPreferenceInput.text.toString().toLong() - exampleSettings.exampleString = stringPreferenceInput.text.toString() - exampleSettings.exampleStringSet = stringSetPreferenceInput.text.toString().split(",").map(String::trim).toSet() + exampleSettings.exampleBoolean = binding.booleanPreference.isChecked + exampleSettings.exampleFloat = binding.floatPreferenceInput.text.toString().toFloat() + exampleSettings.exampleInt = binding.intPreferenceInput.text.toString().toInt() + exampleSettings.exampleLong = binding.longPreferenceInput.text.toString().toLong() + exampleSettings.exampleString = binding.stringPreferenceInput.text.toString() + exampleSettings.exampleStringSet = + binding.stringSetPreferenceInput.text.toString().split(",").map(String::trim).toSet() } } diff --git a/app/src/main/java/hu/autsoft/krateexample/MainActivity.kt b/app/src/main/java/hu/autsoft/krateexample/MainActivity.kt index 2cbb509..d34453e 100644 --- a/app/src/main/java/hu/autsoft/krateexample/MainActivity.kt +++ b/app/src/main/java/hu/autsoft/krateexample/MainActivity.kt @@ -3,22 +3,26 @@ package hu.autsoft.krateexample import android.content.Intent import android.os.Bundle import androidx.appcompat.app.AppCompatActivity -import kotlinx.android.synthetic.main.activity_main.* +import hu.autsoft.krateexample.databinding.ActivityMainBinding class MainActivity : AppCompatActivity() { + private lateinit var binding: ActivityMainBinding + override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) - setContentView(R.layout.activity_main) - btnSimpleKrate.setOnClickListener { + binding = ActivityMainBinding.inflate(layoutInflater) + setContentView(binding.root) + + binding.btnSimpleKrate.setOnClickListener { val intent = Intent(this, ExampleActivity::class.java) - .putExtra(ExampleActivity.KEY_KRATE_TYPE, ExampleActivity.TYPE_SIMPLE) + .putExtra(ExampleActivity.KEY_KRATE_TYPE, ExampleActivity.TYPE_SIMPLE) startActivity(intent) } - btnCustomKrate.setOnClickListener { + binding.btnCustomKrate.setOnClickListener { val intent = Intent(this, ExampleActivity::class.java) - .putExtra(ExampleActivity.KEY_KRATE_TYPE, ExampleActivity.TYPE_CUSTOM) + .putExtra(ExampleActivity.KEY_KRATE_TYPE, ExampleActivity.TYPE_CUSTOM) startActivity(intent) } } diff --git a/app/src/main/java/hu/autsoft/krateexample/krates/ExampleThirdPartyKrates.kt b/app/src/main/java/hu/autsoft/krateexample/krates/ExampleThirdPartyKrates.kt index 80b0a23..fcca564 100644 --- a/app/src/main/java/hu/autsoft/krateexample/krates/ExampleThirdPartyKrates.kt +++ b/app/src/main/java/hu/autsoft/krateexample/krates/ExampleThirdPartyKrates.kt @@ -19,16 +19,16 @@ class EncryptedKrate(applicationContext: Context) : Krate { // https://developer.android.com/topic/security/data // https://developer.android.com/reference/kotlin/androidx/security/crypto/EncryptedSharedPreferences val masterKeyAlias = MasterKey.Builder(applicationContext) - .setKeyScheme(MasterKey.KeyScheme.AES256_GCM) - .build() + .setKeyScheme(MasterKey.KeyScheme.AES256_GCM) + .build() val sharedPrefsFile = "my_sensitive_data.txt" sharedPreferences = EncryptedSharedPreferences.create( - applicationContext, - sharedPrefsFile, - masterKeyAlias, - EncryptedSharedPreferences.PrefKeyEncryptionScheme.AES256_SIV, - EncryptedSharedPreferences.PrefValueEncryptionScheme.AES256_GCM + applicationContext, + sharedPrefsFile, + masterKeyAlias, + EncryptedSharedPreferences.PrefKeyEncryptionScheme.AES256_SIV, + EncryptedSharedPreferences.PrefValueEncryptionScheme.AES256_GCM ) } diff --git a/build.gradle b/build.gradle index af90496..b8dcff9 100644 --- a/build.gradle +++ b/build.gradle @@ -1,14 +1,14 @@ buildscript { - ext.kotlin_version = '1.5.20' - ext.krate_version = '1.1.0' + ext.kotlin_version = '1.5.31' + ext.krate_version = '1.2.0' ext.moshi_version = '1.12.0' ext.junit_version = '4.13.2' - ext.robolectric_version = '4.5.1' + ext.robolectric_version = '4.6.1' ext.min_sdk = 15 - ext.compile_sdk = 29 - ext.target_sdk = 29 + ext.compile_sdk = 31 + ext.target_sdk = 31 repositories { google() @@ -17,7 +17,7 @@ buildscript { maven { url "https://plugins.gradle.org/m2/" } } dependencies { - classpath 'com.android.tools.build:gradle:4.2.2' + classpath 'com.android.tools.build:gradle:7.0.2' classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version" classpath "org.jetbrains.kotlin:kotlin-serialization:$kotlin_version" classpath "io.github.gradle-nexus:publish-plugin:1.1.0" diff --git a/gradle/wrapper/gradle-wrapper.jar b/gradle/wrapper/gradle-wrapper.jar index e708b1c..7454180 100644 Binary files a/gradle/wrapper/gradle-wrapper.jar and b/gradle/wrapper/gradle-wrapper.jar differ diff --git a/gradlew b/gradlew index 4f906e0..744e882 100755 --- a/gradlew +++ b/gradlew @@ -72,7 +72,7 @@ case "`uname`" in Darwin* ) darwin=true ;; - MINGW* ) + MSYS* | MINGW* ) msys=true ;; NONSTOP* ) diff --git a/krate-gson/build.gradle b/krate-gson/build.gradle index e4db252..2c5f7c7 100644 --- a/krate-gson/build.gradle +++ b/krate-gson/build.gradle @@ -11,10 +11,6 @@ android { testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" } - sourceSets { - main.java.srcDirs += 'src/main/kotlin' - } - buildFeatures { buildConfig false } @@ -32,8 +28,7 @@ tasks.withType(org.jetbrains.kotlin.gradle.tasks.KotlinCompile).all { dependencies { implementation project(':krate') - implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version" - api 'com.google.code.gson:gson:2.8.7' + api 'com.google.code.gson:gson:2.8.8' testImplementation "junit:junit:$junit_version" testImplementation "org.robolectric:robolectric:$robolectric_version" diff --git a/krate-gson/src/main/kotlin/hu/autsoft/krate/gson/Functions.kt b/krate-gson/src/main/kotlin/hu/autsoft/krate/gson/Functions.kt index ddfad47..6719f75 100644 --- a/krate-gson/src/main/kotlin/hu/autsoft/krate/gson/Functions.kt +++ b/krate-gson/src/main/kotlin/hu/autsoft/krate/gson/Functions.kt @@ -4,33 +4,46 @@ package hu.autsoft.krate.gson import com.google.gson.reflect.TypeToken import hu.autsoft.krate.Krate -import hu.autsoft.krate.gson.default.GsonDelegateWithDefault -import hu.autsoft.krate.gson.optional.GsonDelegate +import hu.autsoft.krate.gson.default.GsonDelegateWithDefaultFactory +import hu.autsoft.krate.gson.optional.GsonDelegateFactory import java.lang.reflect.Type +import kotlin.properties.PropertyDelegateProvider import kotlin.properties.ReadWriteProperty /** * Creates an optional preference of type T with the given [key] in this [Krate] instance. * This instance will be serialized using Gson. */ -public inline fun Krate.gsonPref(key: String): ReadWriteProperty { +public inline fun Krate.gsonPref( + key: String, +): PropertyDelegateProvider> { return gsonPrefImpl(key, object : TypeToken() {}.type) } @PublishedApi -internal fun Krate.gsonPrefImpl(key: String, type: Type): ReadWriteProperty { - return GsonDelegate(key, type) +internal fun Krate.gsonPrefImpl( + key: String, + type: Type, +): PropertyDelegateProvider> { + return GsonDelegateFactory(key, type) } /** * Creates a non-optional preference of type T with the given [key] and [defaultValue] in this [Krate] instance. * This instance will be serialized using Gson. */ -public inline fun Krate.gsonPref(key: String, defaultValue: T): ReadWriteProperty { +public inline fun Krate.gsonPref( + key: String, + defaultValue: T, +): PropertyDelegateProvider> { return gsonPrefImpl(key, defaultValue, object : TypeToken() {}.type) } @PublishedApi -internal fun Krate.gsonPrefImpl(key: String, defaultValue: T, type: Type): ReadWriteProperty { - return GsonDelegateWithDefault(key, defaultValue, type) +internal fun Krate.gsonPrefImpl( + key: String, + defaultValue: T, + type: Type, +): PropertyDelegateProvider> { + return GsonDelegateWithDefaultFactory(key, defaultValue, type) } diff --git a/krate-gson/src/main/kotlin/hu/autsoft/krate/gson/ValidatedFunctions.kt b/krate-gson/src/main/kotlin/hu/autsoft/krate/gson/ValidatedFunctions.kt index 2366d9e..4dd05b3 100644 --- a/krate-gson/src/main/kotlin/hu/autsoft/krate/gson/ValidatedFunctions.kt +++ b/krate-gson/src/main/kotlin/hu/autsoft/krate/gson/ValidatedFunctions.kt @@ -4,11 +4,12 @@ package hu.autsoft.krate.gson import com.google.gson.reflect.TypeToken import hu.autsoft.krate.Krate -import hu.autsoft.krate.gson.default.GsonDelegateWithDefault -import hu.autsoft.krate.gson.optional.GsonDelegate +import hu.autsoft.krate.gson.default.GsonDelegateWithDefaultFactory +import hu.autsoft.krate.gson.optional.GsonDelegateFactory import hu.autsoft.krate.internal.InternalKrateApi -import hu.autsoft.krate.validation.ValidatedPreferenceDelegate +import hu.autsoft.krate.validation.ValidatedPreferenceDelegateFactory import java.lang.reflect.Type +import kotlin.properties.PropertyDelegateProvider import kotlin.properties.ReadWriteProperty /** @@ -16,27 +17,27 @@ import kotlin.properties.ReadWriteProperty * This value will be serialized using Gson. */ @Deprecated( - message = "Use .validate {} on a gsonPref instead", - level = DeprecationLevel.WARNING, - replaceWith = ReplaceWith( - "this.gsonPref(key).validate(isValid)", - imports = arrayOf("hu.autsoft.krate.validation.validate"), - ), + message = "Use .validate {} on a gsonPref instead", + level = DeprecationLevel.ERROR, + replaceWith = ReplaceWith( + "this.gsonPref(key).validate(isValid)", + imports = arrayOf("hu.autsoft.krate.validation.validate"), + ), ) public inline fun Krate.gsonPref( - key: String, - noinline isValid: (newValue: T?) -> Boolean, -): ReadWriteProperty { + key: String, + noinline isValid: (newValue: T?) -> Boolean, +): PropertyDelegateProvider> { return gsonPrefImpl(key, object : TypeToken() {}.type, isValid) } @PublishedApi internal fun Krate.gsonPrefImpl( - key: String, - type: Type, - isValid: (newValue: T?) -> Boolean, -): ReadWriteProperty { - return ValidatedPreferenceDelegate(GsonDelegate(key, type), isValid) + key: String, + type: Type, + isValid: (newValue: T?) -> Boolean, +): PropertyDelegateProvider> { + return ValidatedPreferenceDelegateFactory(GsonDelegateFactory(key, type), isValid) } /** @@ -45,27 +46,27 @@ internal fun Krate.gsonPrefImpl( * This value will be serialized using Gson. */ @Deprecated( - message = "Use .validate {} on a gsonPref instead", - level = DeprecationLevel.WARNING, - replaceWith = ReplaceWith( - "this.gsonPref(key, defaultValue).validate(isValid)", - imports = arrayOf("hu.autsoft.krate.validation.validate"), - ), + message = "Use .validate {} on a gsonPref instead", + level = DeprecationLevel.ERROR, + replaceWith = ReplaceWith( + "this.gsonPref(key, defaultValue).validate(isValid)", + imports = arrayOf("hu.autsoft.krate.validation.validate"), + ), ) public inline fun Krate.gsonPref( - key: String, - defaultValue: T, - noinline isValid: (newValue: T) -> Boolean, -): ReadWriteProperty { + key: String, + defaultValue: T, + noinline isValid: (newValue: T) -> Boolean, +): PropertyDelegateProvider> { return gsonPrefImpl(key, defaultValue, object : TypeToken() {}.type, isValid) } @PublishedApi internal fun Krate.gsonPrefImpl( - key: String, - defaultValue: T, - type: Type, - isValid: (newValue: T) -> Boolean, -): ReadWriteProperty { - return ValidatedPreferenceDelegate(GsonDelegateWithDefault(key, defaultValue, type), isValid) + key: String, + defaultValue: T, + type: Type, + isValid: (newValue: T) -> Boolean, +): PropertyDelegateProvider> { + return ValidatedPreferenceDelegateFactory(GsonDelegateWithDefaultFactory(key, defaultValue, type), isValid) } diff --git a/krate-gson/src/main/kotlin/hu/autsoft/krate/gson/default/GsonDelegateWithDefault.kt b/krate-gson/src/main/kotlin/hu/autsoft/krate/gson/default/GsonDelegateWithDefault.kt index b776597..febc78d 100644 --- a/krate-gson/src/main/kotlin/hu/autsoft/krate/gson/default/GsonDelegateWithDefault.kt +++ b/krate-gson/src/main/kotlin/hu/autsoft/krate/gson/default/GsonDelegateWithDefault.kt @@ -1,32 +1,44 @@ package hu.autsoft.krate.gson.default +import com.google.gson.TypeAdapter +import com.google.gson.reflect.TypeToken import hu.autsoft.krate.Krate import hu.autsoft.krate.gson.internalGson import hu.autsoft.krate.gson.util.edit import java.lang.reflect.Type +import kotlin.properties.PropertyDelegateProvider import kotlin.properties.ReadWriteProperty import kotlin.reflect.KProperty - -internal class GsonDelegateWithDefault( - private val key: String, - private val default: T, - private val type: Type, +private class GsonDelegateWithDefault( + private val key: String, + private val default: T, + private val adapter: TypeAdapter, ) : ReadWriteProperty { - override operator fun getValue(thisRef: Krate, property: KProperty<*>): T { if (!thisRef.sharedPreferences.contains(key)) { return default } val string = thisRef.sharedPreferences.getString(key, null) - return thisRef.internalGson.fromJson(string, type) + return adapter.fromJson(string) } override operator fun setValue(thisRef: Krate, property: KProperty<*>, value: T) { thisRef.sharedPreferences.edit { - putString(key, thisRef.internalGson.toJson(value)) + putString(key, adapter.toJson(value)) } } +} +internal class GsonDelegateWithDefaultFactory( + private val key: String, + private val default: T, + private val type: Type, +) : PropertyDelegateProvider> { + override fun provideDelegate(thisRef: Krate, property: KProperty<*>): ReadWriteProperty { + @Suppress("UNCHECKED_CAST") + val adapter: TypeAdapter = thisRef.internalGson.getAdapter(TypeToken.get(type)) as TypeAdapter + return GsonDelegateWithDefault(key, default, adapter) + } } diff --git a/krate-gson/src/main/kotlin/hu/autsoft/krate/gson/optional/GsonDelegate.kt b/krate-gson/src/main/kotlin/hu/autsoft/krate/gson/optional/GsonDelegate.kt index f912abc..01dde64 100644 --- a/krate-gson/src/main/kotlin/hu/autsoft/krate/gson/optional/GsonDelegate.kt +++ b/krate-gson/src/main/kotlin/hu/autsoft/krate/gson/optional/GsonDelegate.kt @@ -1,24 +1,25 @@ package hu.autsoft.krate.gson.optional +import com.google.gson.TypeAdapter +import com.google.gson.reflect.TypeToken import hu.autsoft.krate.Krate import hu.autsoft.krate.gson.internalGson import hu.autsoft.krate.gson.util.edit import java.lang.reflect.Type +import kotlin.properties.PropertyDelegateProvider import kotlin.properties.ReadWriteProperty import kotlin.reflect.KProperty - -internal class GsonDelegate( - private val key: String, - private val type: Type, +private class GsonDelegate( + private val key: String, + private val adapter: TypeAdapter, ) : ReadWriteProperty { - override operator fun getValue(thisRef: Krate, property: KProperty<*>): T? { return if (!thisRef.sharedPreferences.contains(key)) { null } else { val string = thisRef.sharedPreferences.getString(key, null) - thisRef.internalGson.fromJson(string, type) + adapter.fromJson(string) } } @@ -29,9 +30,19 @@ internal class GsonDelegate( } } else { thisRef.sharedPreferences.edit { - putString(key, thisRef.internalGson.toJson(value)) + putString(key, adapter.toJson(value)) } } } +} +internal class GsonDelegateFactory( + private val key: String, + private val type: Type, +) : PropertyDelegateProvider> { + override fun provideDelegate(thisRef: Krate, property: KProperty<*>): ReadWriteProperty { + @Suppress("UNCHECKED_CAST") + val adapter: TypeAdapter = thisRef.internalGson.getAdapter(TypeToken.get(type)) as TypeAdapter + return GsonDelegate(key, adapter) + } } diff --git a/krate-gson/src/test/java/hu/autsoft/krate/gson/GsonTestKrate.kt b/krate-gson/src/test/java/hu/autsoft/krate/gson/GsonTestKrate.kt index 985229a..ee46f64 100644 --- a/krate-gson/src/test/java/hu/autsoft/krate/gson/GsonTestKrate.kt +++ b/krate-gson/src/test/java/hu/autsoft/krate/gson/GsonTestKrate.kt @@ -28,14 +28,14 @@ internal class GsonTestKrate(context: Context) : SimpleKrate(context) { var validatedValue: TestModel by gsonPref(key = "validatedValue", defaultValue = DEFAULT_SIMPLE_VALUE) - .validate { newValue -> - newValue.x < newValue.y // arbitrary rule - } + .validate { newValue -> + newValue.x < newValue.y // arbitrary rule + } var validatedOptionalValue: List? by gsonPref>(key = "validatedOptionalValue") - .validate { newValue -> - newValue.isNullOrEmpty().not() - } + .validate { newValue -> + newValue.isNullOrEmpty().not() + } } diff --git a/krate-gson/src/test/java/hu/autsoft/krate/gson/test/GsonDelegateTest.kt b/krate-gson/src/test/java/hu/autsoft/krate/gson/test/GsonDelegateTest.kt index f6bbaf4..e0122da 100644 --- a/krate-gson/src/test/java/hu/autsoft/krate/gson/test/GsonDelegateTest.kt +++ b/krate-gson/src/test/java/hu/autsoft/krate/gson/test/GsonDelegateTest.kt @@ -47,9 +47,9 @@ internal class GsonDelegateTest { @Test fun testSetListOfValues() { val list = listOf( - TestModel(x = 42, y = 3.141592, z = "shibboleth"), - TestModel(x = 13, y = 6.283185, z = "signal"), - TestModel(x = 34, y = 2.718182, z = "bingo") + TestModel(x = 42, y = 3.141592, z = "shibboleth"), + TestModel(x = 13, y = 6.283185, z = "signal"), + TestModel(x = 34, y = 2.718182, z = "bingo") ) krate.listOfValues = list @@ -60,9 +60,9 @@ internal class GsonDelegateTest { @Test fun testRemoveListOfValues() { val list = listOf( - TestModel(x = 42, y = 3.141592, z = "shibboleth"), - TestModel(x = 13, y = 6.283185, z = "signal"), - TestModel(x = 34, y = 2.718182, z = "bingo") + TestModel(x = 42, y = 3.141592, z = "shibboleth"), + TestModel(x = 13, y = 6.283185, z = "signal"), + TestModel(x = 34, y = 2.718182, z = "bingo") ) krate.listOfValues = list diff --git a/krate-gson/src/test/java/hu/autsoft/krate/gson/test/GsonDelegateWithDefaultTest.kt b/krate-gson/src/test/java/hu/autsoft/krate/gson/test/GsonDelegateWithDefaultTest.kt index bf302c6..1be43fe 100644 --- a/krate-gson/src/test/java/hu/autsoft/krate/gson/test/GsonDelegateWithDefaultTest.kt +++ b/krate-gson/src/test/java/hu/autsoft/krate/gson/test/GsonDelegateWithDefaultTest.kt @@ -37,9 +37,9 @@ internal class GsonDelegateWithDefaultTest { @Test fun testListOfValues() { val list = listOf( - TestModel(x = 42, y = 3.141592, z = "shibboleth"), - TestModel(x = 13, y = 6.283185, z = "signal"), - TestModel(x = 34, y = 2.718182, z = "bingo") + TestModel(x = 42, y = 3.141592, z = "shibboleth"), + TestModel(x = 13, y = 6.283185, z = "signal"), + TestModel(x = 34, y = 2.718182, z = "bingo") ) krate.listOfValuesWithDefault = list diff --git a/krate-gson/src/test/java/hu/autsoft/krate/gson/test/ValidatedGsonDelegateTest.kt b/krate-gson/src/test/java/hu/autsoft/krate/gson/test/ValidatedGsonDelegateTest.kt index bc4014c..65d1712 100644 --- a/krate-gson/src/test/java/hu/autsoft/krate/gson/test/ValidatedGsonDelegateTest.kt +++ b/krate-gson/src/test/java/hu/autsoft/krate/gson/test/ValidatedGsonDelegateTest.kt @@ -36,8 +36,8 @@ internal class ValidatedGsonDelegateTest { @Test fun testValidOptionalValue() { val newValue = listOf( - TestModel(20, 21.0, ""), - TestModel(10, 5.0, "") + TestModel(20, 21.0, ""), + TestModel(10, 5.0, "") ) krate.validatedOptionalValue = newValue diff --git a/krate-kotlinx/build.gradle b/krate-kotlinx/build.gradle index 7f5ff1c..51b2146 100644 --- a/krate-kotlinx/build.gradle +++ b/krate-kotlinx/build.gradle @@ -12,10 +12,6 @@ android { testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" } - sourceSets { - main.java.srcDirs += 'src/main/kotlin' - } - buildFeatures { buildConfig false } @@ -33,9 +29,8 @@ tasks.withType(org.jetbrains.kotlin.gradle.tasks.KotlinCompile).all { dependencies { implementation project(':krate') - implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version" - implementation "org.jetbrains.kotlinx:kotlinx-serialization-json:1.2.1" + implementation "org.jetbrains.kotlinx:kotlinx-serialization-json:1.2.2" testImplementation "junit:junit:$junit_version" testImplementation "org.robolectric:robolectric:$robolectric_version" diff --git a/krate-kotlinx/src/main/kotlin/hu/autsoft/krate/kotlinx/Functions.kt b/krate-kotlinx/src/main/kotlin/hu/autsoft/krate/kotlinx/Functions.kt index 7bfc65c..c128239 100644 --- a/krate-kotlinx/src/main/kotlin/hu/autsoft/krate/kotlinx/Functions.kt +++ b/krate-kotlinx/src/main/kotlin/hu/autsoft/krate/kotlinx/Functions.kt @@ -3,8 +3,9 @@ package hu.autsoft.krate.kotlinx import hu.autsoft.krate.Krate -import hu.autsoft.krate.kotlinx.default.KotlinxDelegateWithDefault -import hu.autsoft.krate.kotlinx.optional.KotlinxDelegate +import hu.autsoft.krate.kotlinx.default.KotlinxDelegateWithDefaultFactory +import hu.autsoft.krate.kotlinx.optional.KotlinxDelegateFactory +import kotlin.properties.PropertyDelegateProvider import kotlin.properties.ReadWriteProperty import kotlin.reflect.KType import kotlin.reflect.typeOf @@ -14,13 +15,18 @@ import kotlin.reflect.typeOf * This instance will be serialized using kotlinx.serialization. */ @OptIn(ExperimentalStdlibApi::class) -public inline fun Krate.kotlinxPref(key: String): ReadWriteProperty { +public inline fun Krate.kotlinxPref( + key: String, +): PropertyDelegateProvider> { return kotlinxPrefImpl(key, typeOf()) } @PublishedApi -internal fun Krate.kotlinxPrefImpl(key: String, type: KType): ReadWriteProperty { - return KotlinxDelegate(key, type) +internal fun Krate.kotlinxPrefImpl( + key: String, + type: KType, +): PropertyDelegateProvider> { + return KotlinxDelegateFactory(key, type) } /** @@ -28,11 +34,18 @@ internal fun Krate.kotlinxPrefImpl(key: String, type: KType): ReadWrit * This instance will be serialized using kotlinx.serialization. */ @OptIn(ExperimentalStdlibApi::class) -public inline fun Krate.kotlinxPref(key: String, defaultValue: T): ReadWriteProperty { +public inline fun Krate.kotlinxPref( + key: String, + defaultValue: T, +): PropertyDelegateProvider> { return kotlinxPrefImpl(key, defaultValue, typeOf()) } @PublishedApi -internal fun Krate.kotlinxPrefImpl(key: String, defaultValue: T, type: KType): ReadWriteProperty { - return KotlinxDelegateWithDefault(key, defaultValue, type) +internal fun Krate.kotlinxPrefImpl( + key: String, + defaultValue: T, + type: KType, +): PropertyDelegateProvider> { + return KotlinxDelegateWithDefaultFactory(key, defaultValue, type) } diff --git a/krate-kotlinx/src/main/kotlin/hu/autsoft/krate/kotlinx/default/KotlinxDelegateWithDefault.kt b/krate-kotlinx/src/main/kotlin/hu/autsoft/krate/kotlinx/default/KotlinxDelegateWithDefault.kt index 5e080fc..0a467c1 100644 --- a/krate-kotlinx/src/main/kotlin/hu/autsoft/krate/kotlinx/default/KotlinxDelegateWithDefault.kt +++ b/krate-kotlinx/src/main/kotlin/hu/autsoft/krate/kotlinx/default/KotlinxDelegateWithDefault.kt @@ -1,38 +1,43 @@ package hu.autsoft.krate.kotlinx.default import hu.autsoft.krate.Krate +import hu.autsoft.krate.kotlinx.internalJson import hu.autsoft.krate.kotlinx.util.edit import kotlinx.serialization.KSerializer -import kotlinx.serialization.json.Json import kotlinx.serialization.serializer +import kotlin.properties.PropertyDelegateProvider import kotlin.properties.ReadWriteProperty import kotlin.reflect.KProperty import kotlin.reflect.KType - -internal class KotlinxDelegateWithDefault( - private val key: String, - private val default: T, - private val type: KType, +private class KotlinxDelegateWithDefault( + private val key: String, + private val default: T, + private val serializer: KSerializer, ) : ReadWriteProperty { - - @Suppress("UNCHECKED_CAST") - private inline val serializer: KSerializer - get() = Json.serializersModule.serializer(type) as KSerializer - override operator fun getValue(thisRef: Krate, property: KProperty<*>): T { if (!thisRef.sharedPreferences.contains(key)) { return default } - val string = requireNotNull(thisRef.sharedPreferences.getString(key, null)) - return Json.decodeFromString(serializer, string) + return thisRef.internalJson.decodeFromString(serializer, string) } override operator fun setValue(thisRef: Krate, property: KProperty<*>, value: T) { thisRef.sharedPreferences.edit { - putString(key, Json.encodeToString(serializer, value)) + putString(key, thisRef.internalJson.encodeToString(serializer, value)) } } +} +internal class KotlinxDelegateWithDefaultFactory( + private val key: String, + private val default: T, + private val type: KType, +) : PropertyDelegateProvider> { + override fun provideDelegate(thisRef: Krate, property: KProperty<*>): ReadWriteProperty { + @Suppress("UNCHECKED_CAST") + val serializer = thisRef.internalJson.serializersModule.serializer(type) as KSerializer + return KotlinxDelegateWithDefault(key, default, serializer) + } } diff --git a/krate-kotlinx/src/main/kotlin/hu/autsoft/krate/kotlinx/optional/KotlinxDelegate.kt b/krate-kotlinx/src/main/kotlin/hu/autsoft/krate/kotlinx/optional/KotlinxDelegate.kt index e41e1e8..bbf269f 100644 --- a/krate-kotlinx/src/main/kotlin/hu/autsoft/krate/kotlinx/optional/KotlinxDelegate.kt +++ b/krate-kotlinx/src/main/kotlin/hu/autsoft/krate/kotlinx/optional/KotlinxDelegate.kt @@ -1,30 +1,26 @@ package hu.autsoft.krate.kotlinx.optional import hu.autsoft.krate.Krate +import hu.autsoft.krate.kotlinx.internalJson import hu.autsoft.krate.kotlinx.util.edit import kotlinx.serialization.KSerializer -import kotlinx.serialization.json.Json import kotlinx.serialization.serializer +import kotlin.properties.PropertyDelegateProvider import kotlin.properties.ReadWriteProperty import kotlin.reflect.KProperty import kotlin.reflect.KType -internal class KotlinxDelegate( - private val key: String, - private val type: KType, +private class KotlinxDelegate( + private val key: String, + private val serializer: KSerializer, ) : ReadWriteProperty { - - @Suppress("UNCHECKED_CAST") - private inline val serializer: KSerializer - get() = Json.serializersModule.serializer(type) as KSerializer - override operator fun getValue(thisRef: Krate, property: KProperty<*>): T? { return if (!thisRef.sharedPreferences.contains(key)) { null } else { val string = requireNotNull(thisRef.sharedPreferences.getString(key, null)) - Json.decodeFromString(serializer, string) + thisRef.internalJson.decodeFromString(serializer, string) } } @@ -35,9 +31,19 @@ internal class KotlinxDelegate( } } else { thisRef.sharedPreferences.edit { - putString(key, Json.encodeToString(serializer, value)) + putString(key, thisRef.internalJson.encodeToString(serializer, value)) } } } +} +internal class KotlinxDelegateFactory( + private val key: String, + private val type: KType, +) : PropertyDelegateProvider> { + override fun provideDelegate(thisRef: Krate, property: KProperty<*>): ReadWriteProperty { + @Suppress("UNCHECKED_CAST") + val serializer = thisRef.internalJson.serializersModule.serializer(type) as KSerializer + return KotlinxDelegate(key, serializer) + } } diff --git a/krate-kotlinx/src/test/java/hu/autsoft/krate/kotlinx/KotlinxTestKrate.kt b/krate-kotlinx/src/test/java/hu/autsoft/krate/kotlinx/KotlinxTestKrate.kt index 9b2486d..315797b 100644 --- a/krate-kotlinx/src/test/java/hu/autsoft/krate/kotlinx/KotlinxTestKrate.kt +++ b/krate-kotlinx/src/test/java/hu/autsoft/krate/kotlinx/KotlinxTestKrate.kt @@ -28,14 +28,14 @@ internal class KotlinxTestKrate(context: Context) : SimpleKrate(context) { var validatedValue: TestModel by kotlinxPref(key = "validatedValue", defaultValue = DEFAULT_SIMPLE_VALUE) - .validate { newValue -> - newValue.x < newValue.y // arbitrary rule - } + .validate { newValue -> + newValue.x < newValue.y // arbitrary rule + } var validatedOptionalValue: List? by kotlinxPref>(key = "validatedOptionalValue") - .validate { newValue -> - newValue.isNullOrEmpty().not() // arbitrary rule - } + .validate { newValue -> + newValue.isNullOrEmpty().not() // arbitrary rule + } } diff --git a/krate-kotlinx/src/test/java/hu/autsoft/krate/kotlinx/test/KotlinxDelegateTest.kt b/krate-kotlinx/src/test/java/hu/autsoft/krate/kotlinx/test/KotlinxDelegateTest.kt index aab0bde..f36fd1f 100644 --- a/krate-kotlinx/src/test/java/hu/autsoft/krate/kotlinx/test/KotlinxDelegateTest.kt +++ b/krate-kotlinx/src/test/java/hu/autsoft/krate/kotlinx/test/KotlinxDelegateTest.kt @@ -47,9 +47,9 @@ internal class KotlinxDelegateTest { @Test fun testSetListOfValues() { val list = listOf( - TestModel(x = 42, y = 3.141592, z = "shibboleth"), - TestModel(x = 13, y = 6.283185, z = "signal"), - TestModel(x = 34, y = 2.718182, z = "bingo") + TestModel(x = 42, y = 3.141592, z = "shibboleth"), + TestModel(x = 13, y = 6.283185, z = "signal"), + TestModel(x = 34, y = 2.718182, z = "bingo") ) krate.listOfValues = list @@ -60,9 +60,9 @@ internal class KotlinxDelegateTest { @Test fun testRemoveListOfValues() { val list = listOf( - TestModel(x = 42, y = 3.141592, z = "shibboleth"), - TestModel(x = 13, y = 6.283185, z = "signal"), - TestModel(x = 34, y = 2.718182, z = "bingo") + TestModel(x = 42, y = 3.141592, z = "shibboleth"), + TestModel(x = 13, y = 6.283185, z = "signal"), + TestModel(x = 34, y = 2.718182, z = "bingo") ) krate.listOfValues = list diff --git a/krate-kotlinx/src/test/java/hu/autsoft/krate/kotlinx/test/KotlinxDelegateWithDefaultTest.kt b/krate-kotlinx/src/test/java/hu/autsoft/krate/kotlinx/test/KotlinxDelegateWithDefaultTest.kt index af7b754..a5f5bca 100644 --- a/krate-kotlinx/src/test/java/hu/autsoft/krate/kotlinx/test/KotlinxDelegateWithDefaultTest.kt +++ b/krate-kotlinx/src/test/java/hu/autsoft/krate/kotlinx/test/KotlinxDelegateWithDefaultTest.kt @@ -37,9 +37,9 @@ internal class KotlinxDelegateWithDefaultTest { @Test fun testListOfValues() { val list = listOf( - TestModel(x = 42, y = 3.141592, z = "shibboleth"), - TestModel(x = 13, y = 6.283185, z = "signal"), - TestModel(x = 34, y = 2.718182, z = "bingo") + TestModel(x = 42, y = 3.141592, z = "shibboleth"), + TestModel(x = 13, y = 6.283185, z = "signal"), + TestModel(x = 34, y = 2.718182, z = "bingo") ) krate.listOfValuesWithDefault = list diff --git a/krate-kotlinx/src/test/java/hu/autsoft/krate/kotlinx/test/ValidatedKotlinxDelegateTest.kt b/krate-kotlinx/src/test/java/hu/autsoft/krate/kotlinx/test/ValidatedKotlinxDelegateTest.kt index 06bad97..cbb6c0d 100644 --- a/krate-kotlinx/src/test/java/hu/autsoft/krate/kotlinx/test/ValidatedKotlinxDelegateTest.kt +++ b/krate-kotlinx/src/test/java/hu/autsoft/krate/kotlinx/test/ValidatedKotlinxDelegateTest.kt @@ -36,8 +36,8 @@ internal class ValidatedKotlinxDelegateTest { @Test fun testValidOptionalValue() { val newValue = listOf( - TestModel(20, 21.0, ""), - TestModel(10, 5.0, "") + TestModel(20, 21.0, ""), + TestModel(10, 5.0, "") ) krate.validatedOptionalValue = newValue diff --git a/krate-moshi-codegen/build.gradle b/krate-moshi-codegen/build.gradle index 79a48d5..e5d0326 100644 --- a/krate-moshi-codegen/build.gradle +++ b/krate-moshi-codegen/build.gradle @@ -12,10 +12,6 @@ android { testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" } - sourceSets { - main.java.srcDirs += 'src/main/kotlin' - } - buildFeatures { buildConfig false } @@ -33,7 +29,6 @@ tasks.withType(org.jetbrains.kotlin.gradle.tasks.KotlinCompile).all { dependencies { implementation project(':krate') api project(':krate-moshi-core') - implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version" api "com.squareup.moshi:moshi:$moshi_version" kaptTest "com.squareup.moshi:moshi-kotlin-codegen:$moshi_version" diff --git a/krate-moshi-codegen/src/main/kotlin/hu/autsoft/krate/moshi/DefaultMoshiInstance.kt b/krate-moshi-codegen/src/main/kotlin/hu/autsoft/krate/moshi/DefaultMoshiInstance.kt index 0d7008f..ca47f43 100644 --- a/krate-moshi-codegen/src/main/kotlin/hu/autsoft/krate/moshi/DefaultMoshiInstance.kt +++ b/krate-moshi-codegen/src/main/kotlin/hu/autsoft/krate/moshi/DefaultMoshiInstance.kt @@ -4,5 +4,5 @@ import com.squareup.moshi.Moshi internal val defaultMoshi by lazy { Moshi.Builder() - .build() + .build() } diff --git a/krate-moshi-codegen/src/test/java/hu/autsoft/krate/moshi/MoshiTestKrate.kt b/krate-moshi-codegen/src/test/java/hu/autsoft/krate/moshi/MoshiTestKrate.kt index f945413..800ff45 100644 --- a/krate-moshi-codegen/src/test/java/hu/autsoft/krate/moshi/MoshiTestKrate.kt +++ b/krate-moshi-codegen/src/test/java/hu/autsoft/krate/moshi/MoshiTestKrate.kt @@ -28,14 +28,14 @@ internal class MoshiTestKrate(context: Context) : SimpleKrate(context) { var validatedValue: TestModel by moshiPref(key = "validatedValue", defaultValue = DEFAULT_SIMPLE_VALUE) - .validate { newValue -> - newValue.x < newValue.y // arbitrary rule - } + .validate { newValue -> + newValue.x < newValue.y // arbitrary rule + } var validatedOptionalValue: List? by moshiPref>(key = "validatedOptionalValue") - .validate { newValue -> - newValue.isNullOrEmpty().not() // arbitrary rule - } + .validate { newValue -> + newValue.isNullOrEmpty().not() // arbitrary rule + } } diff --git a/krate-moshi-codegen/src/test/java/hu/autsoft/krate/moshi/test/CustomMoshiInstanceTest.kt b/krate-moshi-codegen/src/test/java/hu/autsoft/krate/moshi/test/CustomMoshiInstanceTest.kt index 567a961..d238322 100644 --- a/krate-moshi-codegen/src/test/java/hu/autsoft/krate/moshi/test/CustomMoshiInstanceTest.kt +++ b/krate-moshi-codegen/src/test/java/hu/autsoft/krate/moshi/test/CustomMoshiInstanceTest.kt @@ -81,7 +81,7 @@ internal class CustomMoshiInstanceTest { private fun createCustomTestMoshi(): Moshi { return Moshi.Builder() - .build() + .build() } } diff --git a/krate-moshi-codegen/src/test/java/hu/autsoft/krate/moshi/test/MoshiDelegateTest.kt b/krate-moshi-codegen/src/test/java/hu/autsoft/krate/moshi/test/MoshiDelegateTest.kt index f4264f6..524ea87 100644 --- a/krate-moshi-codegen/src/test/java/hu/autsoft/krate/moshi/test/MoshiDelegateTest.kt +++ b/krate-moshi-codegen/src/test/java/hu/autsoft/krate/moshi/test/MoshiDelegateTest.kt @@ -47,9 +47,9 @@ internal class MoshiDelegateTest { @Test fun testSetListOfValues() { val list = listOf( - TestModel(x = 42, y = 3.141592, z = "shibboleth"), - TestModel(x = 13, y = 6.283185, z = "signal"), - TestModel(x = 34, y = 2.718182, z = "bingo") + TestModel(x = 42, y = 3.141592, z = "shibboleth"), + TestModel(x = 13, y = 6.283185, z = "signal"), + TestModel(x = 34, y = 2.718182, z = "bingo") ) krate.listOfValues = list @@ -60,9 +60,9 @@ internal class MoshiDelegateTest { @Test fun testRemoveListOfValues() { val list = listOf( - TestModel(x = 42, y = 3.141592, z = "shibboleth"), - TestModel(x = 13, y = 6.283185, z = "signal"), - TestModel(x = 34, y = 2.718182, z = "bingo") + TestModel(x = 42, y = 3.141592, z = "shibboleth"), + TestModel(x = 13, y = 6.283185, z = "signal"), + TestModel(x = 34, y = 2.718182, z = "bingo") ) krate.listOfValues = list diff --git a/krate-moshi-codegen/src/test/java/hu/autsoft/krate/moshi/test/MoshiDelegateWithDefaultTest.kt b/krate-moshi-codegen/src/test/java/hu/autsoft/krate/moshi/test/MoshiDelegateWithDefaultTest.kt index de0293b..7b963c2 100644 --- a/krate-moshi-codegen/src/test/java/hu/autsoft/krate/moshi/test/MoshiDelegateWithDefaultTest.kt +++ b/krate-moshi-codegen/src/test/java/hu/autsoft/krate/moshi/test/MoshiDelegateWithDefaultTest.kt @@ -37,9 +37,9 @@ internal class MoshiDelegateWithDefaultTest { @Test fun testListOfValues() { val list = listOf( - TestModel(x = 42, y = 3.141592, z = "shibboleth"), - TestModel(x = 13, y = 6.283185, z = "signal"), - TestModel(x = 34, y = 2.718182, z = "bingo") + TestModel(x = 42, y = 3.141592, z = "shibboleth"), + TestModel(x = 13, y = 6.283185, z = "signal"), + TestModel(x = 34, y = 2.718182, z = "bingo") ) krate.listOfValuesWithDefault = list diff --git a/krate-moshi-codegen/src/test/java/hu/autsoft/krate/moshi/test/ValidatedMoshiDelegateTest.kt b/krate-moshi-codegen/src/test/java/hu/autsoft/krate/moshi/test/ValidatedMoshiDelegateTest.kt index eb82bd4..8724b5d 100644 --- a/krate-moshi-codegen/src/test/java/hu/autsoft/krate/moshi/test/ValidatedMoshiDelegateTest.kt +++ b/krate-moshi-codegen/src/test/java/hu/autsoft/krate/moshi/test/ValidatedMoshiDelegateTest.kt @@ -41,8 +41,8 @@ internal class ValidatedMoshiDelegateTest { @Test fun testValidOptionalValue() { val newValue = listOf( - TestModel(20, 21.0, ""), - TestModel(10, 5.0, "") + TestModel(20, 21.0, ""), + TestModel(10, 5.0, "") ) krate.validatedOptionalValue = newValue diff --git a/krate-moshi-core/build.gradle b/krate-moshi-core/build.gradle index 4c00973..934842a 100644 --- a/krate-moshi-core/build.gradle +++ b/krate-moshi-core/build.gradle @@ -11,10 +11,6 @@ android { testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" } - sourceSets { - main.java.srcDirs += 'src/main/kotlin' - } - buildFeatures { buildConfig false } @@ -32,7 +28,6 @@ tasks.withType(org.jetbrains.kotlin.gradle.tasks.KotlinCompile).all { dependencies { implementation project(':krate') - implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version" compileOnly project(':krate-moshi-stub') diff --git a/krate-moshi-core/src/main/kotlin/hu/autsoft/krate/moshi/Functions.kt b/krate-moshi-core/src/main/kotlin/hu/autsoft/krate/moshi/Functions.kt index ff22a6b..fc18755 100644 --- a/krate-moshi-core/src/main/kotlin/hu/autsoft/krate/moshi/Functions.kt +++ b/krate-moshi-core/src/main/kotlin/hu/autsoft/krate/moshi/Functions.kt @@ -3,9 +3,10 @@ package hu.autsoft.krate.moshi import hu.autsoft.krate.Krate -import hu.autsoft.krate.moshi.default.MoshiDelegateWithDefault -import hu.autsoft.krate.moshi.optional.MoshiDelegate +import hu.autsoft.krate.moshi.default.MoshiDelegateWithDefaultFactory +import hu.autsoft.krate.moshi.optional.MoshiDelegateFactory import java.lang.reflect.Type +import kotlin.properties.PropertyDelegateProvider import kotlin.properties.ReadWriteProperty import kotlin.reflect.javaType import kotlin.reflect.typeOf @@ -15,13 +16,18 @@ import kotlin.reflect.typeOf * This instance will be serialized using Moshi. */ @OptIn(ExperimentalStdlibApi::class) -public inline fun Krate.moshiPref(key: String): ReadWriteProperty { +public inline fun Krate.moshiPref( + key: String, +): PropertyDelegateProvider> { return moshiPrefImpl(key, typeOf().javaType) } @PublishedApi -internal fun Krate.moshiPrefImpl(key: String, type: Type): ReadWriteProperty { - return MoshiDelegate(key, type) +internal fun Krate.moshiPrefImpl( + key: String, + type: Type, +): PropertyDelegateProvider> { + return MoshiDelegateFactory(key, type) } /** @@ -29,11 +35,18 @@ internal fun Krate.moshiPrefImpl(key: String, type: Type): ReadWritePr * This instance will be serialized using Moshi. */ @OptIn(ExperimentalStdlibApi::class) -public inline fun Krate.moshiPref(key: String, defaultValue: T): ReadWriteProperty { +public inline fun Krate.moshiPref( + key: String, + defaultValue: T, +): PropertyDelegateProvider> { return moshiPrefImpl(key, defaultValue, typeOf().javaType) } @PublishedApi -internal fun Krate.moshiPrefImpl(key: String, defaultValue: T, type: Type): ReadWriteProperty { - return MoshiDelegateWithDefault(key, defaultValue, type) +internal fun Krate.moshiPrefImpl( + key: String, + defaultValue: T, + type: Type, +): PropertyDelegateProvider> { + return MoshiDelegateWithDefaultFactory(key, defaultValue, type) } diff --git a/krate-moshi-core/src/main/kotlin/hu/autsoft/krate/moshi/MoshiInstances.kt b/krate-moshi-core/src/main/kotlin/hu/autsoft/krate/moshi/MoshiInstances.kt index 7284f1e..6736288 100644 --- a/krate-moshi-core/src/main/kotlin/hu/autsoft/krate/moshi/MoshiInstances.kt +++ b/krate-moshi-core/src/main/kotlin/hu/autsoft/krate/moshi/MoshiInstances.kt @@ -7,7 +7,12 @@ internal val moshiInstances: MutableMap = mutableMapOf(key).validate(isValid)", - imports = arrayOf("hu.autsoft.krate.validation.validate"), - ), + message = "Use .validate {} on a moshiPref instead", + level = DeprecationLevel.ERROR, + replaceWith = ReplaceWith( + "this.moshiPref(key).validate(isValid)", + imports = arrayOf("hu.autsoft.krate.validation.validate"), + ), ) public inline fun Krate.moshiPref( - key: String, - noinline isValid: (newValue: T?) -> Boolean, -): ReadWriteProperty { + key: String, + noinline isValid: (newValue: T?) -> Boolean, +): PropertyDelegateProvider> { return moshiPrefImpl(key, typeOf().javaType, isValid) } @PublishedApi internal fun Krate.moshiPrefImpl( - key: String, - type: Type, - isValid: (newValue: T?) -> Boolean, -): ReadWriteProperty { - return ValidatedPreferenceDelegate(MoshiDelegate(key, type), isValid) + key: String, + type: Type, + isValid: (newValue: T?) -> Boolean, +): PropertyDelegateProvider> { + return ValidatedPreferenceDelegateFactory(MoshiDelegateFactory(key, type), isValid) } /** @@ -48,27 +49,27 @@ internal fun Krate.moshiPrefImpl( */ @OptIn(ExperimentalStdlibApi::class) @Deprecated( - message = "Use .validate {} on a moshiPref instead", - level = DeprecationLevel.WARNING, - replaceWith = ReplaceWith( - "this.moshiPref(key, defaultValue).validate(isValid)", - imports = arrayOf("hu.autsoft.krate.validation.validate"), - ), + message = "Use .validate {} on a moshiPref instead", + level = DeprecationLevel.ERROR, + replaceWith = ReplaceWith( + "this.moshiPref(key, defaultValue).validate(isValid)", + imports = arrayOf("hu.autsoft.krate.validation.validate"), + ), ) public inline fun Krate.moshiPref( - key: String, - defaultValue: T, - noinline isValid: (newValue: T) -> Boolean, -): ReadWriteProperty { + key: String, + defaultValue: T, + noinline isValid: (newValue: T) -> Boolean, +): PropertyDelegateProvider> { return moshiPrefImpl(key, defaultValue, typeOf().javaType, isValid) } @PublishedApi internal fun Krate.moshiPrefImpl( - key: String, - defaultValue: T, - type: Type, - isValid: (newValue: T) -> Boolean, -): ReadWriteProperty { - return ValidatedPreferenceDelegate(MoshiDelegateWithDefault(key, defaultValue, type), isValid) + key: String, + defaultValue: T, + type: Type, + isValid: (newValue: T) -> Boolean, +): PropertyDelegateProvider> { + return ValidatedPreferenceDelegateFactory(MoshiDelegateWithDefaultFactory(key, defaultValue, type), isValid) } diff --git a/krate-moshi-core/src/main/kotlin/hu/autsoft/krate/moshi/default/MoshiDelegateWithDefault.kt b/krate-moshi-core/src/main/kotlin/hu/autsoft/krate/moshi/default/MoshiDelegateWithDefault.kt index e71304d..7ebbd06 100644 --- a/krate-moshi-core/src/main/kotlin/hu/autsoft/krate/moshi/default/MoshiDelegateWithDefault.kt +++ b/krate-moshi-core/src/main/kotlin/hu/autsoft/krate/moshi/default/MoshiDelegateWithDefault.kt @@ -1,34 +1,42 @@ package hu.autsoft.krate.moshi.default +import com.squareup.moshi.JsonAdapter import hu.autsoft.krate.Krate import hu.autsoft.krate.moshi.realMoshiInstance import hu.autsoft.krate.moshi.util.edit import java.lang.reflect.Type +import kotlin.properties.PropertyDelegateProvider import kotlin.properties.ReadWriteProperty import kotlin.reflect.KProperty -internal class MoshiDelegateWithDefault( - private val key: String, - private val default: T, - private val type: Type, +private class MoshiDelegateWithDefault( + private val key: String, + private val default: T, + private val adapter: JsonAdapter, ) : ReadWriteProperty { - override operator fun getValue(thisRef: Krate, property: KProperty<*>): T { if (!thisRef.sharedPreferences.contains(key)) { return default } - val string = requireNotNull(thisRef.sharedPreferences.getString(key, null)) - val adapter = thisRef.realMoshiInstance.adapter(type) return requireNotNull(adapter.fromJson(string)) } override operator fun setValue(thisRef: Krate, property: KProperty<*>, value: T) { thisRef.sharedPreferences.edit { - val adapter = thisRef.realMoshiInstance.adapter(type) putString(key, adapter.toJson(value)) } } +} +internal class MoshiDelegateWithDefaultFactory( + private val key: String, + private val default: T, + private val type: Type, +) : PropertyDelegateProvider> { + override fun provideDelegate(thisRef: Krate, property: KProperty<*>): ReadWriteProperty { + val adapter = thisRef.realMoshiInstance.adapter(type) + return MoshiDelegateWithDefault(key, default, adapter) + } } diff --git a/krate-moshi-core/src/main/kotlin/hu/autsoft/krate/moshi/optional/MoshiDelegate.kt b/krate-moshi-core/src/main/kotlin/hu/autsoft/krate/moshi/optional/MoshiDelegate.kt index d758971..ee70320 100644 --- a/krate-moshi-core/src/main/kotlin/hu/autsoft/krate/moshi/optional/MoshiDelegate.kt +++ b/krate-moshi-core/src/main/kotlin/hu/autsoft/krate/moshi/optional/MoshiDelegate.kt @@ -1,24 +1,23 @@ package hu.autsoft.krate.moshi.optional +import com.squareup.moshi.JsonAdapter import hu.autsoft.krate.Krate import hu.autsoft.krate.moshi.realMoshiInstance import hu.autsoft.krate.moshi.util.edit import java.lang.reflect.Type +import kotlin.properties.PropertyDelegateProvider import kotlin.properties.ReadWriteProperty import kotlin.reflect.KProperty - -internal class MoshiDelegate( - private val key: String, - private val type: Type, +private class MoshiDelegate( + private val key: String, + private val adapter: JsonAdapter, ) : ReadWriteProperty { - override fun getValue(thisRef: Krate, property: KProperty<*>): T? { return if (!thisRef.sharedPreferences.contains(key)) { null } else { val string = requireNotNull(thisRef.sharedPreferences.getString(key, null)) - val adapter = thisRef.realMoshiInstance.adapter(type) adapter.fromJson(string) } } @@ -30,10 +29,18 @@ internal class MoshiDelegate( } } else { thisRef.sharedPreferences.edit { - val adapter = thisRef.realMoshiInstance.adapter(type) putString(key, adapter.toJson(value)) } } } +} +internal class MoshiDelegateFactory( + private val key: String, + private val type: Type, +) : PropertyDelegateProvider> { + override fun provideDelegate(thisRef: Krate, property: KProperty<*>): ReadWriteProperty { + val adapter = thisRef.realMoshiInstance.adapter(type) + return MoshiDelegate(key, adapter) + } } diff --git a/krate-moshi-reflect/build.gradle b/krate-moshi-reflect/build.gradle index ce61f3f..a5b3f6b 100644 --- a/krate-moshi-reflect/build.gradle +++ b/krate-moshi-reflect/build.gradle @@ -11,10 +11,6 @@ android { testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" } - sourceSets { - main.java.srcDirs += 'src/main/kotlin' - } - buildFeatures { buildConfig false } @@ -32,7 +28,6 @@ tasks.withType(org.jetbrains.kotlin.gradle.tasks.KotlinCompile).all { dependencies { implementation project(':krate') api project(':krate-moshi-core') - implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version" api "com.squareup.moshi:moshi:$moshi_version" api "com.squareup.moshi:moshi-kotlin:$moshi_version" diff --git a/krate-moshi-reflect/src/main/kotlin/hu/autsoft/krate/moshi/DefaultMoshiInstance.kt b/krate-moshi-reflect/src/main/kotlin/hu/autsoft/krate/moshi/DefaultMoshiInstance.kt index 6d1e210..29bbff0 100644 --- a/krate-moshi-reflect/src/main/kotlin/hu/autsoft/krate/moshi/DefaultMoshiInstance.kt +++ b/krate-moshi-reflect/src/main/kotlin/hu/autsoft/krate/moshi/DefaultMoshiInstance.kt @@ -5,6 +5,6 @@ import com.squareup.moshi.kotlin.reflect.KotlinJsonAdapterFactory internal val defaultMoshi by lazy { Moshi.Builder() - .add(KotlinJsonAdapterFactory()) - .build() + .add(KotlinJsonAdapterFactory()) + .build() } diff --git a/krate-moshi-reflect/src/test/java/hu/autsoft/krate/moshi/MoshiTestKrate.kt b/krate-moshi-reflect/src/test/java/hu/autsoft/krate/moshi/MoshiTestKrate.kt index f945413..800ff45 100644 --- a/krate-moshi-reflect/src/test/java/hu/autsoft/krate/moshi/MoshiTestKrate.kt +++ b/krate-moshi-reflect/src/test/java/hu/autsoft/krate/moshi/MoshiTestKrate.kt @@ -28,14 +28,14 @@ internal class MoshiTestKrate(context: Context) : SimpleKrate(context) { var validatedValue: TestModel by moshiPref(key = "validatedValue", defaultValue = DEFAULT_SIMPLE_VALUE) - .validate { newValue -> - newValue.x < newValue.y // arbitrary rule - } + .validate { newValue -> + newValue.x < newValue.y // arbitrary rule + } var validatedOptionalValue: List? by moshiPref>(key = "validatedOptionalValue") - .validate { newValue -> - newValue.isNullOrEmpty().not() // arbitrary rule - } + .validate { newValue -> + newValue.isNullOrEmpty().not() // arbitrary rule + } } diff --git a/krate-moshi-reflect/src/test/java/hu/autsoft/krate/moshi/test/CustomMoshiInstanceTest.kt b/krate-moshi-reflect/src/test/java/hu/autsoft/krate/moshi/test/CustomMoshiInstanceTest.kt index e1691d4..6080a46 100644 --- a/krate-moshi-reflect/src/test/java/hu/autsoft/krate/moshi/test/CustomMoshiInstanceTest.kt +++ b/krate-moshi-reflect/src/test/java/hu/autsoft/krate/moshi/test/CustomMoshiInstanceTest.kt @@ -82,8 +82,8 @@ internal class CustomMoshiInstanceTest { private fun createCustomTestMoshi(): Moshi { return Moshi.Builder() - .add(KotlinJsonAdapterFactory()) - .build() + .add(KotlinJsonAdapterFactory()) + .build() } } diff --git a/krate-moshi-reflect/src/test/java/hu/autsoft/krate/moshi/test/MoshiDelegateTest.kt b/krate-moshi-reflect/src/test/java/hu/autsoft/krate/moshi/test/MoshiDelegateTest.kt index f4264f6..524ea87 100644 --- a/krate-moshi-reflect/src/test/java/hu/autsoft/krate/moshi/test/MoshiDelegateTest.kt +++ b/krate-moshi-reflect/src/test/java/hu/autsoft/krate/moshi/test/MoshiDelegateTest.kt @@ -47,9 +47,9 @@ internal class MoshiDelegateTest { @Test fun testSetListOfValues() { val list = listOf( - TestModel(x = 42, y = 3.141592, z = "shibboleth"), - TestModel(x = 13, y = 6.283185, z = "signal"), - TestModel(x = 34, y = 2.718182, z = "bingo") + TestModel(x = 42, y = 3.141592, z = "shibboleth"), + TestModel(x = 13, y = 6.283185, z = "signal"), + TestModel(x = 34, y = 2.718182, z = "bingo") ) krate.listOfValues = list @@ -60,9 +60,9 @@ internal class MoshiDelegateTest { @Test fun testRemoveListOfValues() { val list = listOf( - TestModel(x = 42, y = 3.141592, z = "shibboleth"), - TestModel(x = 13, y = 6.283185, z = "signal"), - TestModel(x = 34, y = 2.718182, z = "bingo") + TestModel(x = 42, y = 3.141592, z = "shibboleth"), + TestModel(x = 13, y = 6.283185, z = "signal"), + TestModel(x = 34, y = 2.718182, z = "bingo") ) krate.listOfValues = list diff --git a/krate-moshi-reflect/src/test/java/hu/autsoft/krate/moshi/test/MoshiDelegateWithDefaultTest.kt b/krate-moshi-reflect/src/test/java/hu/autsoft/krate/moshi/test/MoshiDelegateWithDefaultTest.kt index de0293b..7b963c2 100644 --- a/krate-moshi-reflect/src/test/java/hu/autsoft/krate/moshi/test/MoshiDelegateWithDefaultTest.kt +++ b/krate-moshi-reflect/src/test/java/hu/autsoft/krate/moshi/test/MoshiDelegateWithDefaultTest.kt @@ -37,9 +37,9 @@ internal class MoshiDelegateWithDefaultTest { @Test fun testListOfValues() { val list = listOf( - TestModel(x = 42, y = 3.141592, z = "shibboleth"), - TestModel(x = 13, y = 6.283185, z = "signal"), - TestModel(x = 34, y = 2.718182, z = "bingo") + TestModel(x = 42, y = 3.141592, z = "shibboleth"), + TestModel(x = 13, y = 6.283185, z = "signal"), + TestModel(x = 34, y = 2.718182, z = "bingo") ) krate.listOfValuesWithDefault = list diff --git a/krate-moshi-reflect/src/test/java/hu/autsoft/krate/moshi/test/ValidatedMoshiDelegateTest.kt b/krate-moshi-reflect/src/test/java/hu/autsoft/krate/moshi/test/ValidatedMoshiDelegateTest.kt index 4f761a6..43e2fba 100644 --- a/krate-moshi-reflect/src/test/java/hu/autsoft/krate/moshi/test/ValidatedMoshiDelegateTest.kt +++ b/krate-moshi-reflect/src/test/java/hu/autsoft/krate/moshi/test/ValidatedMoshiDelegateTest.kt @@ -36,8 +36,8 @@ internal class ValidatedMoshiDelegateTest { @Test fun testValidOptionalValue() { val newValue = listOf( - TestModel(20, 21.0, ""), - TestModel(10, 5.0, "") + TestModel(20, 21.0, ""), + TestModel(10, 5.0, "") ) krate.validatedOptionalValue = newValue diff --git a/krate-moshi-stub/build.gradle b/krate-moshi-stub/build.gradle index 3331865..47cf44b 100644 --- a/krate-moshi-stub/build.gradle +++ b/krate-moshi-stub/build.gradle @@ -11,10 +11,6 @@ android { testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" } - sourceSets { - main.java.srcDirs += 'src/main/kotlin' - } - buildFeatures { buildConfig false } @@ -31,7 +27,6 @@ tasks.withType(org.jetbrains.kotlin.gradle.tasks.KotlinCompile).all { dependencies { implementation project(':krate') - implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version" api "com.squareup.moshi:moshi:$moshi_version" } diff --git a/krate/build.gradle b/krate/build.gradle index 4b1ac89..18fde1d 100644 --- a/krate/build.gradle +++ b/krate/build.gradle @@ -11,10 +11,6 @@ android { testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" } - sourceSets { - main.java.srcDirs += 'src/main/kotlin' - } - buildFeatures { buildConfig false } @@ -26,12 +22,12 @@ tasks.withType(org.jetbrains.kotlin.gradle.tasks.KotlinCompile).all { '-progressive', '-Xexplicit-api=strict', '-Xopt-in=kotlin.RequiresOptIn', + '-Xopt-in=hu.autsoft.krate.internal.InternalKrateApi', ] } } dependencies { - implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version" implementation 'androidx.preference:preference-ktx:1.1.1' testImplementation "junit:junit:$junit_version" diff --git a/krate/src/main/kotlin/hu/autsoft/krate/SimpleKrate.kt b/krate/src/main/kotlin/hu/autsoft/krate/SimpleKrate.kt index 2945fb3..e6d04a5 100644 --- a/krate/src/main/kotlin/hu/autsoft/krate/SimpleKrate.kt +++ b/krate/src/main/kotlin/hu/autsoft/krate/SimpleKrate.kt @@ -13,8 +13,8 @@ import androidx.preference.PreferenceManager * [PreferenceManager.getDefaultSharedPreferences]. */ public abstract class SimpleKrate( - context: Context, - name: String? = null, + context: Context, + name: String? = null, ) : Krate { public override val sharedPreferences: SharedPreferences = when (name) { diff --git a/krate/src/main/kotlin/hu/autsoft/krate/ValidatedFunctions.kt b/krate/src/main/kotlin/hu/autsoft/krate/ValidatedFunctions.kt index 56d70ac..1e1d27c 100644 --- a/krate/src/main/kotlin/hu/autsoft/krate/ValidatedFunctions.kt +++ b/krate/src/main/kotlin/hu/autsoft/krate/ValidatedFunctions.kt @@ -23,16 +23,16 @@ import kotlin.properties.ReadWriteProperty * an [IllegalArgumentException] will be thrown. */ @Deprecated( - message = "Use .validate {} on a floatPref instead", - level = DeprecationLevel.WARNING, - replaceWith = ReplaceWith( - "this.floatPref(key).validate(isValid)", - imports = arrayOf("hu.autsoft.krate.validation.validate"), - ), + message = "Use .validate {} on a floatPref instead", + level = DeprecationLevel.ERROR, + replaceWith = ReplaceWith( + "this.floatPref(key).validate(isValid)", + imports = arrayOf("hu.autsoft.krate.validation.validate"), + ), ) public fun Krate.floatPref( - key: String, - isValid: (newValue: Float?) -> Boolean, + key: String, + isValid: (newValue: Float?) -> Boolean, ): ReadWriteProperty { return ValidatedPreferenceDelegate(FloatDelegate(key), isValid) } @@ -44,17 +44,17 @@ public fun Krate.floatPref( * an [IllegalArgumentException] will be thrown. */ @Deprecated( - message = "Use .validate {} on a floatPref instead", - level = DeprecationLevel.WARNING, - replaceWith = ReplaceWith( - "this.floatPref(key, defaultValue).validate(isValid)", - imports = arrayOf("hu.autsoft.krate.validation.validate"), - ), + message = "Use .validate {} on a floatPref instead", + level = DeprecationLevel.ERROR, + replaceWith = ReplaceWith( + "this.floatPref(key, defaultValue).validate(isValid)", + imports = arrayOf("hu.autsoft.krate.validation.validate"), + ), ) public fun Krate.floatPref( - key: String, - defaultValue: Float, - isValid: (newValue: Float) -> Boolean, + key: String, + defaultValue: Float, + isValid: (newValue: Float) -> Boolean, ): ReadWriteProperty { return ValidatedPreferenceDelegate(FloatDelegateWithDefault(key, defaultValue), isValid) } @@ -66,16 +66,16 @@ public fun Krate.floatPref( * an [IllegalArgumentException] will be thrown. */ @Deprecated( - message = "Use .validate {} on an intPref instead", - level = DeprecationLevel.WARNING, - replaceWith = ReplaceWith( - "this.intPref(key).validate(isValid)", - imports = arrayOf("hu.autsoft.krate.validation.validate"), - ), + message = "Use .validate {} on an intPref instead", + level = DeprecationLevel.ERROR, + replaceWith = ReplaceWith( + "this.intPref(key).validate(isValid)", + imports = arrayOf("hu.autsoft.krate.validation.validate"), + ), ) public fun Krate.intPref( - key: String, - isValid: (newValue: Int?) -> Boolean, + key: String, + isValid: (newValue: Int?) -> Boolean, ): ReadWriteProperty { return ValidatedPreferenceDelegate(IntDelegate(key), isValid) } @@ -87,17 +87,17 @@ public fun Krate.intPref( * an [IllegalArgumentException] will be thrown. */ @Deprecated( - message = "Use .validate {} on an intPref instead", - level = DeprecationLevel.WARNING, - replaceWith = ReplaceWith( - "this.intPref(key, defaultValue).validate(isValid)", - imports = arrayOf("hu.autsoft.krate.validation.validate"), - ), + message = "Use .validate {} on an intPref instead", + level = DeprecationLevel.ERROR, + replaceWith = ReplaceWith( + "this.intPref(key, defaultValue).validate(isValid)", + imports = arrayOf("hu.autsoft.krate.validation.validate"), + ), ) public fun Krate.intPref( - key: String, - defaultValue: Int, - isValid: (newValue: Int) -> Boolean, + key: String, + defaultValue: Int, + isValid: (newValue: Int) -> Boolean, ): ReadWriteProperty { return ValidatedPreferenceDelegate(IntDelegateWithDefault(key, defaultValue), isValid) } @@ -109,16 +109,16 @@ public fun Krate.intPref( * an [IllegalArgumentException] will be thrown. */ @Deprecated( - message = "Use .validate {} on a longPref instead", - level = DeprecationLevel.WARNING, - replaceWith = ReplaceWith( - "this.longPref(key).validate(isValid)", - imports = arrayOf("hu.autsoft.krate.validation.validate"), - ), + message = "Use .validate {} on a longPref instead", + level = DeprecationLevel.ERROR, + replaceWith = ReplaceWith( + "this.longPref(key).validate(isValid)", + imports = arrayOf("hu.autsoft.krate.validation.validate"), + ), ) public fun Krate.longPref( - key: String, - isValid: (newValue: Long?) -> Boolean, + key: String, + isValid: (newValue: Long?) -> Boolean, ): ReadWriteProperty { return ValidatedPreferenceDelegate(LongDelegate(key), isValid) } @@ -130,17 +130,17 @@ public fun Krate.longPref( * an [IllegalArgumentException] will be thrown. */ @Deprecated( - message = "Use .validate {} on a longPref instead", - level = DeprecationLevel.WARNING, - replaceWith = ReplaceWith( - "this.longPref(key, defaultValue).validate(isValid)", - imports = arrayOf("hu.autsoft.krate.validation.validate"), - ), + message = "Use .validate {} on a longPref instead", + level = DeprecationLevel.ERROR, + replaceWith = ReplaceWith( + "this.longPref(key, defaultValue).validate(isValid)", + imports = arrayOf("hu.autsoft.krate.validation.validate"), + ), ) public fun Krate.longPref( - key: String, - defaultValue: Long, - isValid: (newValue: Long) -> Boolean, + key: String, + defaultValue: Long, + isValid: (newValue: Long) -> Boolean, ): ReadWriteProperty { return ValidatedPreferenceDelegate(LongDelegateWithDefault(key, defaultValue), isValid) } @@ -152,16 +152,16 @@ public fun Krate.longPref( * an [IllegalArgumentException] will be thrown. */ @Deprecated( - message = "Use .validate {} on a stringPref instead", - level = DeprecationLevel.WARNING, - replaceWith = ReplaceWith( - "this.stringPref(key).validate(isValid)", - imports = arrayOf("hu.autsoft.krate.validation.validate"), - ), + message = "Use .validate {} on a stringPref instead", + level = DeprecationLevel.ERROR, + replaceWith = ReplaceWith( + "this.stringPref(key).validate(isValid)", + imports = arrayOf("hu.autsoft.krate.validation.validate"), + ), ) public fun Krate.stringPref( - key: String, - isValid: (newValue: String?) -> Boolean, + key: String, + isValid: (newValue: String?) -> Boolean, ): ReadWriteProperty { return ValidatedPreferenceDelegate(StringDelegate(key), isValid) } @@ -173,17 +173,17 @@ public fun Krate.stringPref( * an [IllegalArgumentException] will be thrown. */ @Deprecated( - message = "Use .validate {} on a stringPref instead", - level = DeprecationLevel.WARNING, - replaceWith = ReplaceWith( - "this.stringPref(key, defaultValue).validate(isValid)", - imports = arrayOf("hu.autsoft.krate.validation.validate"), - ), + message = "Use .validate {} on a stringPref instead", + level = DeprecationLevel.ERROR, + replaceWith = ReplaceWith( + "this.stringPref(key, defaultValue).validate(isValid)", + imports = arrayOf("hu.autsoft.krate.validation.validate"), + ), ) public fun Krate.stringPref( - key: String, - defaultValue: String, - isValid: (newValue: String) -> Boolean, + key: String, + defaultValue: String, + isValid: (newValue: String) -> Boolean, ): ReadWriteProperty { return ValidatedPreferenceDelegate(StringDelegateWithDefault(key, defaultValue), isValid) } @@ -195,16 +195,16 @@ public fun Krate.stringPref( * an [IllegalArgumentException] will be thrown. */ @Deprecated( - message = "Use .validate {} on a stringSetPref instead", - level = DeprecationLevel.WARNING, - replaceWith = ReplaceWith( - "this.stringSetPref(key).validate(isValid)", - imports = arrayOf("hu.autsoft.krate.validation.validate"), - ), + message = "Use .validate {} on a stringSetPref instead", + level = DeprecationLevel.ERROR, + replaceWith = ReplaceWith( + "this.stringSetPref(key).validate(isValid)", + imports = arrayOf("hu.autsoft.krate.validation.validate"), + ), ) public fun Krate.stringSetPref( - key: String, - isValid: (newValue: Set?) -> Boolean, + key: String, + isValid: (newValue: Set?) -> Boolean, ): ReadWriteProperty?> { return ValidatedPreferenceDelegate(StringSetDelegate(key), isValid) } @@ -216,17 +216,17 @@ public fun Krate.stringSetPref( * an [IllegalArgumentException] will be thrown. */ @Deprecated( - message = "Use .validate {} on a stringSetPref instead", - level = DeprecationLevel.WARNING, - replaceWith = ReplaceWith( - "this.stringSetPref(key, defaultValue).validate(isValid)", - imports = arrayOf("hu.autsoft.krate.validation.validate"), - ), + message = "Use .validate {} on a stringSetPref instead", + level = DeprecationLevel.ERROR, + replaceWith = ReplaceWith( + "this.stringSetPref(key, defaultValue).validate(isValid)", + imports = arrayOf("hu.autsoft.krate.validation.validate"), + ), ) public fun Krate.stringSetPref( - key: String, - defaultValue: Set, - isValid: (newValue: Set) -> Boolean, + key: String, + defaultValue: Set, + isValid: (newValue: Set) -> Boolean, ): ReadWriteProperty> { return ValidatedPreferenceDelegate(StringSetDelegateWithDefault(key, defaultValue), isValid) } diff --git a/krate/src/main/kotlin/hu/autsoft/krate/default/BooleanDelegateWithDefault.kt b/krate/src/main/kotlin/hu/autsoft/krate/default/BooleanDelegateWithDefault.kt index 9fadb17..2586b44 100644 --- a/krate/src/main/kotlin/hu/autsoft/krate/default/BooleanDelegateWithDefault.kt +++ b/krate/src/main/kotlin/hu/autsoft/krate/default/BooleanDelegateWithDefault.kt @@ -6,8 +6,8 @@ import kotlin.properties.ReadWriteProperty import kotlin.reflect.KProperty internal class BooleanDelegateWithDefault( - private val key: String, - private val default: Boolean, + private val key: String, + private val default: Boolean, ) : ReadWriteProperty { override operator fun getValue(thisRef: Krate, property: KProperty<*>): Boolean { diff --git a/krate/src/main/kotlin/hu/autsoft/krate/default/FloatDelegateWithDefault.kt b/krate/src/main/kotlin/hu/autsoft/krate/default/FloatDelegateWithDefault.kt index 262bf3c..f7498d0 100644 --- a/krate/src/main/kotlin/hu/autsoft/krate/default/FloatDelegateWithDefault.kt +++ b/krate/src/main/kotlin/hu/autsoft/krate/default/FloatDelegateWithDefault.kt @@ -6,8 +6,8 @@ import kotlin.properties.ReadWriteProperty import kotlin.reflect.KProperty internal class FloatDelegateWithDefault( - private val key: String, - private val default: Float, + private val key: String, + private val default: Float, ) : ReadWriteProperty { override operator fun getValue(thisRef: Krate, property: KProperty<*>): Float { diff --git a/krate/src/main/kotlin/hu/autsoft/krate/default/IntDelegateWithDefault.kt b/krate/src/main/kotlin/hu/autsoft/krate/default/IntDelegateWithDefault.kt index f75d21a..2eea0d7 100644 --- a/krate/src/main/kotlin/hu/autsoft/krate/default/IntDelegateWithDefault.kt +++ b/krate/src/main/kotlin/hu/autsoft/krate/default/IntDelegateWithDefault.kt @@ -6,8 +6,8 @@ import kotlin.properties.ReadWriteProperty import kotlin.reflect.KProperty internal class IntDelegateWithDefault( - private val key: String, - private val default: Int, + private val key: String, + private val default: Int, ) : ReadWriteProperty { override operator fun getValue(thisRef: Krate, property: KProperty<*>): Int { diff --git a/krate/src/main/kotlin/hu/autsoft/krate/default/LongDelegateWithDefault.kt b/krate/src/main/kotlin/hu/autsoft/krate/default/LongDelegateWithDefault.kt index 4763965..3ec5562 100644 --- a/krate/src/main/kotlin/hu/autsoft/krate/default/LongDelegateWithDefault.kt +++ b/krate/src/main/kotlin/hu/autsoft/krate/default/LongDelegateWithDefault.kt @@ -6,8 +6,8 @@ import kotlin.properties.ReadWriteProperty import kotlin.reflect.KProperty internal class LongDelegateWithDefault( - private val key: String, - private val default: Long, + private val key: String, + private val default: Long, ) : ReadWriteProperty { override operator fun getValue(thisRef: Krate, property: KProperty<*>): Long { diff --git a/krate/src/main/kotlin/hu/autsoft/krate/default/StringDelegateWithDefault.kt b/krate/src/main/kotlin/hu/autsoft/krate/default/StringDelegateWithDefault.kt index fb686c0..721fa1c 100644 --- a/krate/src/main/kotlin/hu/autsoft/krate/default/StringDelegateWithDefault.kt +++ b/krate/src/main/kotlin/hu/autsoft/krate/default/StringDelegateWithDefault.kt @@ -6,8 +6,8 @@ import kotlin.properties.ReadWriteProperty import kotlin.reflect.KProperty internal class StringDelegateWithDefault( - private val key: String, - private val default: String, + private val key: String, + private val default: String, ) : ReadWriteProperty { @Suppress("NULLABILITY_MISMATCH_BASED_ON_JAVA_ANNOTATIONS") diff --git a/krate/src/main/kotlin/hu/autsoft/krate/default/StringSetDelegateWithDefault.kt b/krate/src/main/kotlin/hu/autsoft/krate/default/StringSetDelegateWithDefault.kt index 00d9d0a..3bd5a96 100644 --- a/krate/src/main/kotlin/hu/autsoft/krate/default/StringSetDelegateWithDefault.kt +++ b/krate/src/main/kotlin/hu/autsoft/krate/default/StringSetDelegateWithDefault.kt @@ -6,8 +6,8 @@ import kotlin.properties.ReadWriteProperty import kotlin.reflect.KProperty internal class StringSetDelegateWithDefault( - private val key: String, - private val default: Set, + private val key: String, + private val default: Set, ) : ReadWriteProperty> { @Suppress("NULLABILITY_MISMATCH_BASED_ON_JAVA_ANNOTATIONS") diff --git a/krate/src/main/kotlin/hu/autsoft/krate/internal/InternalKrateApi.kt b/krate/src/main/kotlin/hu/autsoft/krate/internal/InternalKrateApi.kt index 213fa5d..2601bbb 100644 --- a/krate/src/main/kotlin/hu/autsoft/krate/internal/InternalKrateApi.kt +++ b/krate/src/main/kotlin/hu/autsoft/krate/internal/InternalKrateApi.kt @@ -1,8 +1,8 @@ package hu.autsoft.krate.internal @RequiresOptIn( - message = "This API is meant to be used by Krate's own modules, and third-party extensions to Krate. " + - "If you're a client of the Krate library, you probably shouldn't be using it.", - level = RequiresOptIn.Level.ERROR + message = "This API is meant to be used by Krate's own modules, and third-party extensions to Krate. " + + "If you're a client of the Krate library, you probably shouldn't be using it.", + level = RequiresOptIn.Level.ERROR ) public annotation class InternalKrateApi diff --git a/krate/src/main/kotlin/hu/autsoft/krate/optional/BooleanDelegate.kt b/krate/src/main/kotlin/hu/autsoft/krate/optional/BooleanDelegate.kt index 5e559f9..0e54d1c 100644 --- a/krate/src/main/kotlin/hu/autsoft/krate/optional/BooleanDelegate.kt +++ b/krate/src/main/kotlin/hu/autsoft/krate/optional/BooleanDelegate.kt @@ -6,7 +6,7 @@ import kotlin.properties.ReadWriteProperty import kotlin.reflect.KProperty internal class BooleanDelegate( - private val key: String, + private val key: String, ) : ReadWriteProperty { override operator fun getValue(thisRef: Krate, property: KProperty<*>): Boolean? { diff --git a/krate/src/main/kotlin/hu/autsoft/krate/optional/FloatDelegate.kt b/krate/src/main/kotlin/hu/autsoft/krate/optional/FloatDelegate.kt index e7414f8..3d1285c 100644 --- a/krate/src/main/kotlin/hu/autsoft/krate/optional/FloatDelegate.kt +++ b/krate/src/main/kotlin/hu/autsoft/krate/optional/FloatDelegate.kt @@ -6,7 +6,7 @@ import kotlin.properties.ReadWriteProperty import kotlin.reflect.KProperty internal class FloatDelegate( - private val key: String, + private val key: String, ) : ReadWriteProperty { override operator fun getValue(thisRef: Krate, property: KProperty<*>): Float? { diff --git a/krate/src/main/kotlin/hu/autsoft/krate/optional/IntDelegate.kt b/krate/src/main/kotlin/hu/autsoft/krate/optional/IntDelegate.kt index 2249794..7797cdb 100644 --- a/krate/src/main/kotlin/hu/autsoft/krate/optional/IntDelegate.kt +++ b/krate/src/main/kotlin/hu/autsoft/krate/optional/IntDelegate.kt @@ -6,7 +6,7 @@ import kotlin.properties.ReadWriteProperty import kotlin.reflect.KProperty internal class IntDelegate( - private val key: String, + private val key: String, ) : ReadWriteProperty { override operator fun getValue(thisRef: Krate, property: KProperty<*>): Int? { diff --git a/krate/src/main/kotlin/hu/autsoft/krate/optional/LongDelegate.kt b/krate/src/main/kotlin/hu/autsoft/krate/optional/LongDelegate.kt index 3ba63ea..fab65f3 100644 --- a/krate/src/main/kotlin/hu/autsoft/krate/optional/LongDelegate.kt +++ b/krate/src/main/kotlin/hu/autsoft/krate/optional/LongDelegate.kt @@ -6,7 +6,7 @@ import kotlin.properties.ReadWriteProperty import kotlin.reflect.KProperty internal class LongDelegate( - private val key: String, + private val key: String, ) : ReadWriteProperty { override operator fun getValue(thisRef: Krate, property: KProperty<*>): Long? { diff --git a/krate/src/main/kotlin/hu/autsoft/krate/optional/StringDelegate.kt b/krate/src/main/kotlin/hu/autsoft/krate/optional/StringDelegate.kt index d382c92..46fce62 100644 --- a/krate/src/main/kotlin/hu/autsoft/krate/optional/StringDelegate.kt +++ b/krate/src/main/kotlin/hu/autsoft/krate/optional/StringDelegate.kt @@ -6,7 +6,7 @@ import kotlin.properties.ReadWriteProperty import kotlin.reflect.KProperty internal class StringDelegate( - private val key: String, + private val key: String, ) : ReadWriteProperty { override operator fun getValue(thisRef: Krate, property: KProperty<*>): String? { diff --git a/krate/src/main/kotlin/hu/autsoft/krate/optional/StringSetDelegate.kt b/krate/src/main/kotlin/hu/autsoft/krate/optional/StringSetDelegate.kt index 272bce6..2f58ab5 100644 --- a/krate/src/main/kotlin/hu/autsoft/krate/optional/StringSetDelegate.kt +++ b/krate/src/main/kotlin/hu/autsoft/krate/optional/StringSetDelegate.kt @@ -6,7 +6,7 @@ import kotlin.properties.ReadWriteProperty import kotlin.reflect.KProperty internal class StringSetDelegate( - private val key: String, + private val key: String, ) : ReadWriteProperty?> { override operator fun getValue(thisRef: Krate, property: KProperty<*>): Set? { diff --git a/krate/src/main/kotlin/hu/autsoft/krate/validation/ValidatedPreferenceDelegate.kt b/krate/src/main/kotlin/hu/autsoft/krate/validation/ValidatedPreferenceDelegate.kt index 3a7a0dd..0f40cf8 100644 --- a/krate/src/main/kotlin/hu/autsoft/krate/validation/ValidatedPreferenceDelegate.kt +++ b/krate/src/main/kotlin/hu/autsoft/krate/validation/ValidatedPreferenceDelegate.kt @@ -2,6 +2,7 @@ package hu.autsoft.krate.validation import hu.autsoft.krate.Krate import hu.autsoft.krate.internal.InternalKrateApi +import kotlin.properties.PropertyDelegateProvider import kotlin.properties.ReadWriteProperty import kotlin.reflect.KProperty @@ -14,8 +15,8 @@ import kotlin.reflect.KProperty */ @InternalKrateApi public class ValidatedPreferenceDelegate( - private val delegate: ReadWriteProperty, - private val isValid: (newValue: T) -> Boolean, + private val delegate: ReadWriteProperty, + private val isValid: (newValue: T) -> Boolean, ) : ReadWriteProperty by delegate { override operator fun setValue(thisRef: Krate, property: KProperty<*>, value: T) { @@ -26,6 +27,20 @@ public class ValidatedPreferenceDelegate( } +@InternalKrateApi +public class ValidatedPreferenceDelegateFactory( + private val propertyDelegateProvider: PropertyDelegateProvider>, + private val isValid: (newValue: T) -> Boolean, +) : PropertyDelegateProvider> { + + override fun provideDelegate(thisRef: Krate, property: KProperty<*>): ReadWriteProperty { + return ValidatedPreferenceDelegate( + delegate = propertyDelegateProvider.provideDelegate(thisRef, property), + isValid = isValid, + ) + } +} + /** * Adds validation to a Krate delegate. * @@ -42,8 +57,30 @@ public class ValidatedPreferenceDelegate( * ``` */ public fun ReadWriteProperty.validate( - isValid: (newValue: T) -> Boolean, + isValid: (newValue: T) -> Boolean, ): ReadWriteProperty { @OptIn(InternalKrateApi::class) return ValidatedPreferenceDelegate(this, isValid) } + +/** + * Adds validation to a Krate delegate factory. + * + * If a value being set to this preference returns `false` when checked by [isValid], + * an [IllegalArgumentException] will be thrown. + * + * Example property using this function for validation: + * + * ```kotlin + * var validatedModel by kotlinxPref("validatedModel") + * .validate { newValue -> + * newValue.x > 3 // arbitrary condition + * } + * ``` + */ +public fun PropertyDelegateProvider>.validate( + isValid: (newValue: T) -> Boolean, +): PropertyDelegateProvider> { + @OptIn(InternalKrateApi::class) + return ValidatedPreferenceDelegateFactory(this, isValid) +} diff --git a/krate/src/test/java/hu/autsoft/krate/TestKrate.kt b/krate/src/test/java/hu/autsoft/krate/TestKrate.kt index c138410..f9a11fc 100644 --- a/krate/src/test/java/hu/autsoft/krate/TestKrate.kt +++ b/krate/src/test/java/hu/autsoft/krate/TestKrate.kt @@ -16,8 +16,8 @@ internal class TestKrate(context: Context) : SimpleKrate(context) { var optionalString by stringPref("optionalString") var optionalStringSet by stringSetPref("optionalStringSet") var optionalValidatedString by stringPref("optionalValidatedString") - .validate { it?.length ?: 5 == 5 } + .validate { it?.length ?: 5 == 5 } var defaultValidatedFloat by floatPref("defaultValidatedFloat", 0.0f) - .validate { it in 0.0f..1.0f } + .validate { it in 0.0f..1.0f } }