Skip to content

Commit

Permalink
Refactored the ktx-preferences module. #255
Browse files Browse the repository at this point in the history
  • Loading branch information
czyzby committed Mar 25, 2020
1 parent 81bbdbf commit addd746
Show file tree
Hide file tree
Showing 5 changed files with 496 additions and 174 deletions.
1 change: 1 addition & 0 deletions .github/CONTRIBUTORS.md
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,7 @@ Project contributors listed chronologically.
* Author of the [Tiled](../tiled) module.
* Contributed [actors](../actors) utilities.
* Wrote a complete [KTX tutorial](https://github.com/Quillraven/SimpleKtxGame/wiki) based on the original LibGDX introduction.
* Author of the [preferences](../preferences) module.
* [@FocusPo1nt](https://github.com/FocusPo1nt)
* Added utilities to [style module](../style).
* [@maltaisn](https://github.com/maltaisn)
Expand Down
10 changes: 6 additions & 4 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,13 @@
- **[FEATURE]** (`ktx-ashley`) Added `Entity.contains` (`in` operator) that checks if an `Entity` has a `Component`.
- **[FEATURE]** (`ktx-async`) Added `RenderingScope` factory function for custom scopes using rendering thread dispatcher.
- **[FEATURE]** (`ktx-math`) Added `lerp` and `interpolate` extension functions for `Float` ranges.
- **[FEATURE]** (`ktx-vis`) Added `image` (`VisImage`) factory methods consuming `Texture`, `TextureRegion` and `NinePatch`.
- **[FEATURE]** (`ktx-preferences`) Added a new KTX module: Preferences API extensions.
- Added `set` operators for String, Int, Float, Long, Boolean, Pair<String, Any> and Any
- Added `get` operator
- Added `flush` extension function that takes additional `Preferences` calls as a Lambda
- Added `set` operators for `String`, `Int`, `Float`, `Double`, `Long`, `Boolean`, `Pair<String, Any>` and `Any`
- Added `get` operator which automatically determines preference type and retrieves them with the correct method.
- `get` and `set` will automatically attempt to (de)serialize non-basic preferences to and from JSON.
- `set(String, Double)` is deprecated, since the LibGDX `Preferences` do not support doubles.
- Added `flush` inlined extension method that executes a lambda and automatically calls `Preferences.flush`.
- **[FEATURE]** (`ktx-vis`) Added `image` (`VisImage`) factory methods consuming `Texture`, `TextureRegion` and `NinePatch`.

#### 1.9.10-b4

Expand Down
204 changes: 143 additions & 61 deletions preferences/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,79 +6,161 @@ Utilities and extension function for LibGDX preferences.

### Why?

LibGDX [Preferences](https://github.com/libgdx/libgdx/wiki/Preferences) do not support a generic way to
set and get values. Since they work very similar to a Map, they should ideally support a similar
syntax. Especially with Kotlin we can use the advantage of square bracket operators.
LibGDX [`Preferences`](https://github.com/libgdx/libgdx/wiki/Preferences) do not provide a consistent
API for setting and getting values, and they do not support Kotlin operators either. Since in principle
`Preferences` work very similarly to a `Map`, ideally they should support a similar syntax -
especially since in Kotlin you can take advantage of the square bracket operators.

### Guide

- Values can be set via new `set` operators using the square bracket syntax. It is no longer needed
to call type specific methods like `putString` or `putBoolean`. `Set` already supports any type.
- Values can be retrieved via new generic `get` operator.
- Preferences now support `Pair<String, Any>` parameter. Values can be set by using the `infix to` function
- New `flush` extension that supports a Lambda to easily update the Preferences before flushing.
- `set` and `get` support objects of any type. If the type is not a String, Boolean, Int, Float or Long value
then the value is stored and retrieved using [Json](https://github.com/libgdx/libgdx/wiki/Reading-and-writing-JSON).
.
- Values can be set and read via the new `set` and `get` operators using the square bracket (`[]`) syntax.
It is no longer necessary to call type specific methods like `putString` or `getBoolean` for
each type separately. `set` and `get` support objects of any type. If the type is not of `String`, `Boolean`,
`Int`, `Float`, `Double` or `Long` type, the value is stored and retrieved using
[JSON](https://github.com/libgdx/libgdx/wiki/Reading-and-writing-JSON) serialization.
- Note that `Double` type is not supported by LibGDX `Preferences` and converted to `Float`
instead. Use explicit casts (`toFloat()`) or wrap the value with a JSON-serializable object
when storing numbers that do not fit in a `Float`.
- Preferences can now be set with a `Pair<String, Any>` parameter. Keys and values can be paired using
the standard library `to` infix function.
- New `flush` extension supports a lambda parameter to easily update the `Preferences` before flushing.

### Usage examples

Reading basic application preferences:

```kotlin
import com.badlogic.gdx.Gdx
import ktx.preferences.flush
import ktx.preferences.get
import ktx.preferences.set

private class Player(val name: String = "Player 1", val life: Int = 100)

fun main() {
val prefs = Gdx.app.getPreferences("MyPreferences")

// set values with new set operator functions
prefs["Key1"] = "someStringValue"
prefs["Key2"] = 1
prefs["Key3"] = 1.23f
prefs["Key4"] = 100L
prefs["Key5"] = true
// Any classes are automatically converted to a Json string
prefs["Key6"] = Player()

prefs.run {
// use Pair<String, Any> to update preference values
set("Key7" to 123)
set("Key8" to "someOtherStringValue")
import ktx.preferences.*

fun readValuesFromPreferences() {
val preferences = Gdx.app.getPreferences("myPreferences")
// Accessing preferences by keys passed as parameters:
val string: String? = preferences["SomeString"]
val float: Float? = preferences["SomeFloat"]
val boolean: Boolean? = preferences["SomeBoolean"]
val integer: Int? = preferences["SomeInt"]
val long: Long? = preferences["SomeLong"]
// Do something with preferences here.
}
```

Reading basic preferences with custom default values in case they are missing:

```kotlin
import com.badlogic.gdx.Preferences
import ktx.preferences.*

fun readValuesWithDefaultsFromPreferences(preferences: Preferences) {
// If the key (given as the first parameter) is absent in the preferences,
// the default value (passed as the second parameter) will be returned:
val string: String = preferences["SomeString", "default value"]
val float: Float = preferences["SomeFloat", 2.0f]
val boolean: Boolean = preferences["SomeBoolean", true]
val integer: Int = preferences["SomeInt", 42]
val long: Long = preferences["SomeLong", 3L]
// Alternative syntax without the [] operator:
val preference = preferences.get<Int>("Key", defaultValue = 42)
// Do something with preferences here.
}
```

Loading objects serialized as JSON from preferences:

```kotlin
import com.badlogic.gdx.Preferences
import ktx.preferences.*

/**
* This class will be serialized.
*
* Remember to add default values for each variable,
* so the class remains JSON-serializable!
*/
data class Player(val name: String = "Player", val life: Int = 100)

fun readObjectFromPreferences(preferences: Preferences): Player? {
// Will automatically deserialize the object from JSON:
return preferences["Player"]
}
```

Saving preferences:

```kotlin
import com.badlogic.gdx.Preferences
import ktx.preferences.*

fun saveInPreferences(
preferences: Preferences,
string: String, float: Float, bool: Boolean, int: Int, long: Long) {
// The values will be stored in preferences under the given keys:
preferences["SomeString"] = string
preferences["SomeFloat"] = float
preferences["SomeBoolean"] = bool
preferences["SomeInt"] = int
preferences["SomeLong"] = long
// Remember to call flush in order to save the preferences:
preferences.flush()
}
```

Saving preferences with automatic flushing using `flush` extension method:

```kotlin
import com.badlogic.gdx.Preferences
import ktx.preferences.*

fun saveInPreferencesWithFlush(
preferences: Preferences,
string: String, float: Float, bool: Boolean, int: Int, long: Long) {
preferences.flush {
// This extension method changes `this` to preferences within the scope:
this["SomeString"] = string
this["SomeFloat"] = float
this["SomeBoolean"] = bool
this["SomeInt"] = int
this["SomeLong"] = long
// preferences.flush() will be called automatically after this block.
}
}
```

Saving objects as JSON in preferences:

// get values with new get operator function
val value1: String = prefs["Key1"]
val value2: Int = prefs["Key2"]
val value3: Float = prefs["Key3"]
val value4: Long = prefs["Key4"]
val value5: Boolean = prefs["Key5"]
// Any classes are automatically loaded from a Json string
val value6: Player = prefs["Key6"]
val value7: Int = prefs["Key7"]
val value8: String = prefs["Key8"]

println(value1) // prints 'someStringValue'
println(value2) // prints 1
println(value3) // prints 1.23
println(value4) // prints 100
println(value5) // prints true
println("${value6.name} - ${value6.life}") // prints 'Player 1 - 100'
println(value7) // prints 123
println(value8) // prints 'someOtherStringValue'

// adjust preferences before calling flush
// Key9 and Key10 will be flushed as well
prefs.flush {
set("Key9" to 10000)
set("Key10" to true)
```kotlin
import com.badlogic.gdx.Preferences
import ktx.preferences.*

data class Player(val name: String = "Player", val life: Int = 100)

fun saveObjectInPreferences(preferences: Preferences, player: Player) {
preferences.flush {
// Will automatically serialize the object to JSON:
this["Player"] = player
}
}
```

Setting preferences using Kotlin pairs and `to` infix function:

```kotlin
import com.badlogic.gdx.Preferences
import ktx.preferences.*

data class Player(val name: String = "Player", val life: Int = 100)

fun addPreferencesUsingKotlinPairs(preferences: Preferences) {
preferences.set("SomeInt" to 1)
preferences.set("SomeFloat" to 1.0f)
preferences.set("SomeLong" to 1L)
preferences.set("SomeBoolean" to true)
preferences.set("SomeString" to "value")
preferences.set("Player" to Player(name = "Example", life = 75))
}
```

### Additional documentation

- [LibGDX Json](https://github.com/libgdx/libgdx/wiki/Reading-and-writing-JSON)
- [LibGDX Preferences](https://github.com/libgdx/libgdx/wiki/Preferences)
- [Kotlin infix to function for Pair](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin/to.html)
- [Official LibGDX `Preferences` article](https://github.com/libgdx/libgdx/wiki/Preferences).
- [Official LibGDX `Json` article](https://github.com/libgdx/libgdx/wiki/Reading-and-writing-JSON).
Loading

0 comments on commit addd746

Please sign in to comment.