Skip to content

Commit

Permalink
Merge pull request #20 from AutSoft/dev
Browse files Browse the repository at this point in the history
Release 1.0.0
  • Loading branch information
zsmb13 authored Nov 29, 2020
2 parents 5287b99 + eb91fac commit 05d8774
Show file tree
Hide file tree
Showing 51 changed files with 869 additions and 168 deletions.
2 changes: 1 addition & 1 deletion .github/workflows/publish.yml
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ jobs:
SIGNING_SECRET_KEY_RING_FILE: ${{ secrets.SIGNING_SECRET_KEY_RING_FILE }}
run: sudo bash -c "echo '$GPG_KEY_CONTENTS' | base64 -d > '$SIGNING_SECRET_KEY_RING_FILE'"
- name: Release build and source jar generation
run: ./gradlew :krate:assembleRelease :krate-gson:assembleRelease :krate-moshi-stub:assembleRelease :krate-moshi-core:assembleRelease :krate-moshi-reflect:assembleRelease :krate-moshi-codegen:assembleRelease :krate:androidSourcesJar :krate-gson:androidSourcesJar :krate-moshi-stub:androidSourcesJar :krate-moshi-core:androidSourcesJar :krate-moshi-reflect:androidSourcesJar :krate-moshi-codegen:androidSourcesJar
run: ./gradlew :krate:assembleRelease :krate-gson:assembleRelease :krate-moshi-stub:assembleRelease :krate-moshi-core:assembleRelease :krate-moshi-reflect:assembleRelease :krate-moshi-codegen:assembleRelease :krate-kotlinx:assembleRelease :krate:androidSourcesJar :krate-gson:androidSourcesJar :krate-moshi-stub:androidSourcesJar :krate-moshi-core:androidSourcesJar :krate-moshi-reflect:androidSourcesJar :krate-moshi-codegen:androidSourcesJar :krate-kotlinx:androidSourcesJar
- name: Publish to MavenCentral
run: ./gradlew publishReleasePublicationToSonatypeRepository closeAndReleaseRepository
env:
Expand Down
111 changes: 72 additions & 39 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -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:0.5.0'
implementation 'hu.autsoft:krate:1.0.0'
```

# Optionals vs defaults
Expand Down Expand Up @@ -105,56 +105,28 @@ class EncryptedKrate(applicationContext: Context) : Krate {

# Validation

You can add validation rules to your Krate properties by providing an additional lambda parameter, `isValid`:
You can add validation rules to your Krate properties by calling `validate` on any of Krate's delegate functions:

```kotlin
var percentage: Int by intPref(
key = "percentage",
defaultValue = 0,
isValid = { it in 0..100 }
)
).validate { it in 0..100 }
```

If this validation fails, an `IllegalArgumentException` will be thrown.

# Addons

Krate, by default, supports the types that `SharedPreferences` supports. These are `Boolean`, `Float`, `Int`, `Long`, `String` and `Set<String>`. You may of course want to store additional types in Krate. For some common types, addon libraries are available, as described below.
Krate, by default, supports the types that `SharedPreferences` supports. These are `Boolean`, `Float`, `Int`, `Long`, `String` and `Set<String>`. You may of course want to store additional types in Krate.

If you don't find support for the type you're looking for, implementing your own delegate in your own project based on the code of existing delegates should be quite simple, this is very much a supported use case. If you think your type might be commonly used, you can also open an issue to ask for an addon library to provide for that type.
If you don't find support for the library or type you're looking for, implementing your own delegate in your own project based on the code of existing delegates should be quite simple, this is very much a supported use case. If you think your type might be commonly used, you can also open an issue to ask for an addon library for that type.

### Gson support

The `krate-gson` artifact provides you 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:0.5.0'
```
### Moshi support

Its basic usage is the same as with any of the base library's delegates:

```kotlin
class GsonKrate(context: Context) : SimpleKrate(context) {
var user: User? by gsonPref("user")
var savedArticles: List<Article>? by gsonPref("articles")
}
```
This addon provides a `moshiPref` delegate which can store any arbitrary type, as long as Moshi can serialize and deserialize it.

By default, the `Gson` instance created by a simple `Gson()` constructor call is used. If you want to provide your own `Gson` instance that you've configured, you can set the `gson` extension property on your Krate. Any `gsonPref` delegates within this Krate will use this instance for serialization and deserialization.

```kotlin
class CustomGsonKrate(context: Context) : SimpleKrate(context) {
init {
gson = GsonBuilder().create()
}
}
```

### Moshi support

Similarly to [krate-gson], the following artifacts add support for using Moshi to serialize values to `SharedPreferences` via Krate.

Since Moshi supports both reflection-based serialization and code generation, there are multiple Krate artifacts for different use cases. You should always include only one of the dependencies below, otherwise you'll end up with a dexing error.
Since Moshi supports both reflection-based serialization and code generation, there are multiple Krate artifacts for different use cases. *You should always include only one of the dependencies below, otherwise you'll end up with a dexing error.*

The usage of the Krate integration is the same for both setups:

Expand All @@ -180,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:0.5.0'
implementation 'hu.autsoft:krate-moshi-codegen:1.0.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.
Expand All @@ -190,12 +162,73 @@ 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:0.5.0'
implementation 'hu.autsoft:krate-moshi-reflect:1.0.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.

You may choose to use Moshi's codegen for some classes in your project, and serialize the ones with no adapters generated with the default approach via reflection. For this mixed use case, you should probably choose this dependency.
You may choose to use Moshi's codegen for some classes in your project, and serialize the ones with no adapters generated with the default approach via reflection. For this mixed use case, you should also choose this dependency (unless you set your own custom Moshi instances as described above).

### Kotlinx.serialization support

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.0.0'
```

Its usage is the same as with any of the base library's delegates:

```kotlin
class KotlinxKrate(context: Context) : SimpleKrate(context) {
var user: User? by kotlinxPref("user")
var savedArticles: List<Article>? by kotlinxPref("articles")
}
```

By default, the `Json.Default` is used. If you want to provide your own customized `Json` instance, you can set the `json` extension property on your Krate. Any `kotlinxPref` delegates within this Krate will use this instance for serialization and deserialization.

```kotlin
class CustomKotlinxKrate(context: Context) : SimpleKrate(context) {
init {
json = Json {
coerceInputValues = true
...
}
}

var user: User? by kotlinxPref("user")
}
```

### Gson support

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.0.0'
```

Its basic usage is the same as with any of the base library's delegates:

```kotlin
class GsonKrate(context: Context) : SimpleKrate(context) {
var user: User? by gsonPref("user")
var savedArticles: List<Article>? by gsonPref("articles")
}
```

By default, the `Gson` instance created by a simple `Gson()` constructor call is used. If you want to provide your own `Gson` instance that you've configured, you can set the `gson` extension property on your Krate. Any `gsonPref` delegates within this Krate will use this instance for serialization and deserialization.

```kotlin
class CustomGsonKrate(context: Context) : SimpleKrate(context) {
init {
gson = GsonBuilder().create()
}

var user: User? by gsonPref("user")
}
```

# License

Expand Down
7 changes: 4 additions & 3 deletions build.gradle
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
buildscript {
ext.kotlin_version = '1.4.10'
ext.krate_version = '0.5.0'
ext.kotlin_version = '1.4.20'
ext.krate_version = '1.0.0'

ext.moshi_version = '1.9.3'
ext.junit_version = '4.13'
Expand All @@ -16,9 +16,10 @@ buildscript {
jcenter()
}
dependencies {
classpath 'com.android.tools.build:gradle:4.1.0'
classpath 'com.android.tools.build:gradle:4.1.1'
classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
classpath "io.codearte.gradle.nexus:gradle-nexus-staging-plugin:0.21.0"
classpath "org.jetbrains.kotlin:kotlin-serialization:$kotlin_version"
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,17 +7,25 @@ import hu.autsoft.krate.Krate
import hu.autsoft.krate.gson.default.GsonDelegateWithDefault
import hu.autsoft.krate.gson.optional.GsonDelegate
import hu.autsoft.krate.internal.InternalKrateApi
import hu.autsoft.krate.validated.ValidatedPreferenceDelegate
import hu.autsoft.krate.validation.ValidatedPreferenceDelegate
import java.lang.reflect.Type
import kotlin.properties.ReadWriteProperty

/**
* Creates an validated, optional preference of type T with the given [key] in this [Krate] instance.
* Creates a validated, optional preference of type T with the given [key] in this [Krate] instance.
* This value will be serialized using Gson.
*/
@Deprecated(
message = "Use .validate {} on a gsonPref instead",
level = DeprecationLevel.WARNING,
replaceWith = ReplaceWith(
"this.gsonPref<T>(key).validate(isValid)",
imports = arrayOf("hu.autsoft.krate.validation.validate"),
),
)
public inline fun <reified T : Any> Krate.gsonPref(
key: String,
noinline isValid: (newValue: T?) -> Boolean
noinline isValid: (newValue: T?) -> Boolean,
): ReadWriteProperty<Krate, T?> {
return gsonPrefImpl(key, object : TypeToken<T>() {}.type, isValid)
}
Expand All @@ -26,7 +34,7 @@ public inline fun <reified T : Any> Krate.gsonPref(
internal fun <T : Any> Krate.gsonPrefImpl(
key: String,
type: Type,
isValid: (newValue: T?) -> Boolean
isValid: (newValue: T?) -> Boolean,
): ReadWriteProperty<Krate, T?> {
return ValidatedPreferenceDelegate(GsonDelegate(key, type), isValid)
}
Expand All @@ -36,10 +44,18 @@ internal fun <T : Any> Krate.gsonPrefImpl(
* in this [Krate] instance.
* 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"),
),
)
public inline fun <reified T : Any> Krate.gsonPref(
key: String,
defaultValue: T,
noinline isValid: (newValue: T) -> Boolean
noinline isValid: (newValue: T) -> Boolean,
): ReadWriteProperty<Krate, T> {
return gsonPrefImpl(key, defaultValue, object : TypeToken<T>() {}.type, isValid)
}
Expand All @@ -49,7 +65,7 @@ internal fun <T : Any> Krate.gsonPrefImpl(
key: String,
defaultValue: T,
type: Type,
isValid: (newValue: T) -> Boolean
isValid: (newValue: T) -> Boolean,
): ReadWriteProperty<Krate, T> {
return ValidatedPreferenceDelegate(GsonDelegateWithDefault(key, defaultValue, type), isValid)
}
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ import kotlin.reflect.KProperty
internal class GsonDelegateWithDefault<T : Any>(
private val key: String,
private val default: T,
private val type: Type
private val type: Type,
) : ReadWriteProperty<Krate, T> {

override operator fun getValue(thisRef: Krate, property: KProperty<*>): T {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ import kotlin.reflect.KProperty

internal class GsonDelegate<T : Any>(
private val key: String,
private val type: Type
private val type: Type,
) : ReadWriteProperty<Krate, T?> {

override operator fun getValue(thisRef: Krate, property: KProperty<*>): T? {
Expand Down
26 changes: 12 additions & 14 deletions krate-gson/src/test/java/hu/autsoft/krate/gson/GsonTestKrate.kt
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package hu.autsoft.krate.gson

import android.content.Context
import hu.autsoft.krate.SimpleKrate
import hu.autsoft.krate.validation.validate


internal class GsonTestKrate(context: Context) : SimpleKrate(context) {
Expand All @@ -25,19 +26,16 @@ internal class GsonTestKrate(context: Context) : SimpleKrate(context) {
var listOfValuesWithDefault: List<TestModel>
by gsonPref("listOfValuesWithDefault", defaultValue = DEFAULT_LIST_VALUE)

var validatedValue: TestModel by gsonPref(
key = "validatedValue",
defaultValue = DEFAULT_SIMPLE_VALUE,
isValid = { newValue ->
newValue.x < newValue.y // arbitrary rule
}
)

var validatedOptionalValue: List<TestModel>? by gsonPref(
key = "validatedOptionalValue",
isValid = { newValue ->
newValue.isNullOrEmpty().not()
}
)
var validatedValue: TestModel
by gsonPref(key = "validatedValue", defaultValue = DEFAULT_SIMPLE_VALUE)
.validate { newValue ->
newValue.x < newValue.y // arbitrary rule
}

var validatedOptionalValue: List<TestModel>?
by gsonPref<List<TestModel>>(key = "validatedOptionalValue")
.validate { newValue ->
newValue.isNullOrEmpty().not()
}

}
1 change: 1 addition & 0 deletions krate-kotlinx/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
/build
47 changes: 47 additions & 0 deletions krate-kotlinx/build.gradle
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
apply plugin: 'com.android.library'
apply plugin: 'kotlin-android'
apply plugin: 'kotlinx-serialization'

android {
compileSdkVersion compile_sdk

defaultConfig {
minSdkVersion min_sdk
targetSdkVersion target_sdk
versionName krate_version
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
}

sourceSets {
main.java.srcDirs += 'src/main/kotlin'
}
}

tasks.withType(org.jetbrains.kotlin.gradle.tasks.KotlinCompile).all {
kotlinOptions {
freeCompilerArgs += [
'-progressive',
'-Xexplicit-api=strict',
'-Xopt-in=kotlin.RequiresOptIn',
]
}
}

dependencies {
implementation project(':krate')
implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version"

implementation "org.jetbrains.kotlinx:kotlinx-serialization-json:1.0.1"

testImplementation "junit:junit:$junit_version"
testImplementation 'org.robolectric:robolectric:4.3.1'
}

// Publishing
ext {
PUBLISH_GROUP_ID = 'hu.autsoft'
PUBLISH_ARTIFACT_ID = 'krate-kotlinx'
PUBLISH_VERSION = android.defaultConfig.versionName
}

apply from: "${rootProject.projectDir}/scripts/publish-mavencentral.gradle"
1 change: 1 addition & 0 deletions krate-kotlinx/src/main/AndroidManifest.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
<manifest package="hu.autsoft.krate.kotlinx" />
Loading

0 comments on commit 05d8774

Please sign in to comment.