{"id":13536765,"url":"https://github.com/kotlingang/kds","last_synced_at":"2025-04-02T03:31:05.196Z","repository":{"id":49562675,"uuid":"312492409","full_name":"kotlingang/kds","owner":"kotlingang","description":"Kotlin Data Storage is a multiplatform coroutine-based kotlin library for storing Serializables with kotlinx.serialization and delegates","archived":false,"fork":false,"pushed_at":"2021-10-17T06:59:36.000Z","size":274,"stargazers_count":36,"open_issues_count":4,"forks_count":2,"subscribers_count":2,"default_branch":"master","last_synced_at":"2024-11-03T01:33:21.397Z","etag":null,"topics":["kotlin","kotlinx-coroutines","kotlinx-serialization","multiplatform-kotlin-library","sharedpreferences"],"latest_commit_sha":null,"homepage":"","language":"Kotlin","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/kotlingang.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2020-11-13T06:32:01.000Z","updated_at":"2024-08-05T15:17:28.000Z","dependencies_parsed_at":"2022-09-02T09:53:12.698Z","dependency_job_id":null,"html_url":"https://github.com/kotlingang/kds","commit_stats":null,"previous_names":[],"tags_count":8,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/kotlingang%2Fkds","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/kotlingang%2Fkds/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/kotlingang%2Fkds/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/kotlingang%2Fkds/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/kotlingang","download_url":"https://codeload.github.com/kotlingang/kds/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":246751027,"owners_count":20827819,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["kotlin","kotlinx-coroutines","kotlinx-serialization","multiplatform-kotlin-library","sharedpreferences"],"created_at":"2024-08-01T09:00:49.085Z","updated_at":"2025-04-02T03:31:04.151Z","avatar_url":"https://github.com/kotlingang.png","language":"Kotlin","funding_links":[],"categories":["Libraries"],"sub_categories":["Storage"],"readme":"[![Last Version](https://badge.kotlingang.fun/maven/fun/kotlingang/kds/core/)](https://maven.kotlingang.fun/fun/kotlingang/kds/)\n[![Hits-of-Code](https://hitsofcode.com/github/kotlingang/kds)](https://hitsofcode.com/view/github/kotlingang/kds) \u003cbr\u003e\n\n![badge][badge-nodejs]\n![badge][badge-js]\n![badge][badge-jvm]\n![badge][badge-android]\n\n# kds\nKotlin Data Storage is a multiplatform coroutine-based kotlin library for storing Serializables with kotlinx.serialization and delegates.  \n\n## Use case\nIf you need to store any kind of preferences in your app, you would probably use this framework since it has a common API for any platform you need.\n\n## Examples\n\n### Files Storage\n\n\u003cdetails\u003e\n\u003csummary\u003eExpand\u003c/summary\u003e\n\u003cp\u003e\n\n```kotlin\nimport ProgramData.userName\n\nobject ProgramData : KFileDataStorage() {\n    val userName by property\u003cString\u003e()  // shortcut for property\u003cString?\u003e { null }\n}\n\nfun main() {\n    if(userName == null) {\n        println(\"Hi dear user, how should I call you?\")\n        userName = readLine() ?: \"Anonymous\"\n        println(\"Okay ${userName}, see you\")\n    } else {\n        println(\"Glad to see you again, $userName\")\n    }\n}\n```\n\n\u003c/p\u003e\n\u003c/details\u003e\n\n### Web Storage\n\n\u003cdetails\u003e\n\u003csummary\u003eExpand\u003c/summary\u003e\n\u003cp\u003e\n    \n```kotlin\nobject CookiesStorage : KLocalDataStorage() {\n    val uniqueADId by property { Random.nextLong() }\n}\n\nfun main() {\n    console.log(\"🙈 I'm tracking you, ${CookiesStorage.uniqueADId}!\")\n}\n```\n    \n\u003c/p\u003e\n\u003c/details\u003e\n\n### SharedPreferences\n\n\u003cdetails\u003e\n\u003csummary\u003eExpand\u003c/summary\u003e\n\u003cp\u003e\n\n```kotlin\n// Initialize context first:\nclass App : Application() {\n    override fun onCreate() {\n        super.onCreate()\n        KDS.onCreate(app = this)\n    }\n}\n...\nobject SharedStorage : KSharedDataStorage() {\n    var clicks by int { 0 }\n}\n...\nimport SharedStorage.clicks\n\nclass MainActivity : Activity() {\n    override fun onCreate(bundle: Bundle?) {\n        ...\n        main.setOnClickListener {\n            updateClicks(++clicks)\n        }\n    }\n}\n```\n\n\u003c/p\u003e\n\u003c/details\u003e\n        \n### Android Bundle State\n\n\u003cdetails\u003e\n\u003csummary\u003eExpand\u003c/summary\u003e\n\u003cp\u003e\n\nYou can also store android app state with the library\n```kotlin\nclass MainActivity : Activity() {\n    private val state = object : KBundleDataStorage() {\n        var score by int { 0 }  // This will be automatically saved and restored\n    }\n    \n    override fun onCreate(bundle: Bundle?) = state.fillState(bundle) {\n        super.onCreate(bundle)\n    }\n    // OR\n    override fun onCreate(bundle: Bundle?) {\n        super.onCreate(bundle)\n        state.restoreInstanceState(bundle)\n    }\n    \n    override fun onSaveInstanceState(outState: Bundle) {\n        super.onSaveInstanceState(outState)\n        state.saveInstanceState(outState)\n    }\n}\n```\n\u003e Custom `property` are also allowed there made with serialization to string followed by `bundle.putString`\n\n\u003c/p\u003e\n\u003c/details\u003e\n\n### Mutate Example\n\n\u003cdetails\u003e\n\u003csummary\u003eExpand\u003c/summary\u003e\n\u003cp\u003e\n\nThere is also an API to use mutable objects\n```kotlin\ndata class Item (\n    var foo: Foo? = null\n)\n\nobject MainStorage : ... {\n    val item by property(::Item)\n}\n\n// Launches an asynchronous commit after block()\nfun editItem() = MainStorage.mutate {\n    item.foo = ...\n}\n// Suspends until commit\nsuspend fun editItem() = MainStorage.mutateCommit {\n    item.foo = ...\n}\n// Blocking mutation\nfun editItem() = MainStorage.mutateBlocking {\n    item.foo = ...\n}\n\nsuspend fun main() {\n    // Launches a commit and cancels the previous one\n    MainStorage.launchCommit()\n    // Suspends until commit\n    MainStorage.commit()\n    // Blocking commit\n    MainStorage.commitBlocking()\n}\n```\n\n\u003c/p\u003e\n\u003c/details\u003e\n\n### Mutate Entities\n\n\u003cdetails\u003e\n\u003csummary\u003eExpand\u003c/summary\u003e\n\u003cp\u003e\n\nThere are some (experimental for now) entities which may automatically perform save operation on mutate:\n```kotlin\nobject MainStorage : ... {\n    val list by storageList\u003cBoolean\u003e()\n    val map by storageMap\u003cString, Int\u003e()\n    val set by storageSet { mutableSetOf(1, 2, 3) }\n}\n\nfun main() {\n    // Then any mutation on this entities will perform save\n    // The saving operation will same as operation when assigning variable to new value\n    // It means that in KFileDataStorage async save will be invoked, while in KLocalDataStorage blocking `put` method\n    MainStorage.list += true\n}\n```\n\n\u003c/p\u003e\n\u003c/details\u003e\n\nNote that the library is written in a way where you may **fully** customize it (add xml format for files/etc, implement java.Serializable support and so on, interfaces are common, so you may still use delegates, commits, mutations on it)\n\n## Integrations\nLibrary integrates with some other libraries providing convenient API for storing androidx `MutableState`. Integrations still require including storage dependency.\n\n\u003cdetails\u003e\n\u003csummary\u003eExpand\u003c/summary\u003e\n\n### Androidx MutableState\n\u003cdetails\u003e\n\u003csummary\u003eExpand\u003c/summary\u003e\n\n```kotlin\nobject ComposeStorage : ... {\n    val username by mutableState\u003cString\u003e()\n}\n...\n@Composable\nfun UserNameText() {\n    val username by remember { ComposeStorage.username }\n    Text (\n        text = username\n    )\n}\n```\n\n\u003c/details\u003e\n\n### KVision ObservableValue\n\u003cdetails\u003e\n\u003csummary\u003eExpand\u003c/summary\u003e\n\n```kotlin\nobject AppData : KLocalDataStorage() {\n    val clicks by observableValue { 0 }\n}\n\nclass App : Application() {\n    override fun start() {\n        root(id = \"root\") {\n            vPanel {\n                h1(AppData.clicks) { clicks -\u003e\n                    + \"Clicked $clicks times\"\n                }\n                button(text = \"Click!\") {\n                    onClick {\n                        // Changes still handled by storage\n                        clicks.value++\n                    }\n                }\n            }\n        }\n    }\n}\n\nfun main() = startApplication(::App)\n```\n\n\u003c/details\u003e\n\n### Coroutines MutableStateFlow\n\u003cdetails\u003e\n\u003csummary\u003eExpand\u003c/summary\u003e\n\n```kotlin\nobject CoroutinesStorage : ... {\n    // Use it everywhere you need to save state flow values\n    val stateFlow by mutableStateFlow\u003cString\u003e()\n}\n```\n\n\u003c/details\u003e\n\n\u003c/details\u003e\n\n## Implementation\n\u003e When targeting JS, only IR is supported\n\n`$version` - the library version, can be found in badge above \u003cbr\u003e\n\nAll `kds` packages are located at repository [maven.kotlingang.fun](https://maven.kotlingang.fun/fun/kotlingang/kds), so make sure you include one.\n\n### KFileDataStorage\n\u003e KDataStorage async/sync [implementation](json/json-files) with files.\n\n**Platforms**: ![jvm][badge-jvm] ![nodejs][badge-nodejs] \u003cbr\u003e\n**Dependency**: `fun.kotlingang.kds:json-files:$version`\n\n### KLocalDataStorage\n\u003e KDataStorage sync [implementation](json/json-local-storage) with browser `localStorage`\n\n**Platforms**: ![js][badge-js] \u003cbr\u003e\n**Dependency**: `fun.kotlingang.kds:json-local-storage:$version`\n\n### KSharedDataStorage\n\u003e KDataStorage async [implementation](json/json-shared-preferences) with android `SharedPreferences`\n\n**Platforms**: ![android][badge-android] \u003cbr\u003e\n**Dependency**: `fun.kotlingang.kds:json-shared-preferences:$version` \u003cbr\u003e\n**Example**: GitHub [repo](https://github.com/kotlingang/kds-android-example)\n\n### KBundleDataStorage\n\u003e KDataStorage sync [implementation](json/json-bundle) with android `Bundle`\n\n**Platforms**: ![android][badge-android] \u003cbr\u003e\n**Dependency**: `fun.kotlingang.kds:json-bundle:$version` \u003cbr\u003e\n**Example**: GitHub [repo](https://github.com/kotlingang/kds-android-example)\n\n## Integrations implementation\n\n### Androidx Extensions\n\u003e MutableState [implementation](extensions/extensions-androidx/src/main/java/fun/kotlingang/kds/compose/mutable_state/StorageMutableState.kt)\n\n**Platforms**: ![android][badge-android] \u003cbr\u003e\n**Dependency**: `fun.kotlingang.kds:extensions-androidx:$version`\n\n### Coroutines Extensions\n\u003e MutableStateFlow [implementation](extensions/extensions-coroutines/src/commonMain/kotlin/fun/kotlingang/kds/coroutines/mutable_state_flow/StorageMutableStateFlow.kt)\n\n**Platform**: Any  \n**Dependency**: `fun.kotlingang.kds:extensions-coroutines:$version`\n\n### KVision Extensions\n\u003e ObservableState [implementation](extensions/extensions-kvision/src/main/kotlin/fun/kotlingang/kds/kvision/observable_value/StorageObservableValue.kt)\n\n**Platform**: ![js][badge-js]  \n**Dependency**: `fun.kotlingang.kds:extensions-kvision:$version`\n\n## Custom\nIf you want to create your own implementation, take a look at the following dependencies\n\n#### Core\n\u003e The core module with delegates and main interfaces\n\n**Platforms**: Any \u003cbr\u003e\n**Dependency**: `fun.kotlingang.kds:core:$version`\n\n#### Json\n\u003e The json module with abstraction over any storage uses json serialization (also proxies references to allow mutations)\n\n**Platforms**: Any\u003cbr\u003e\n**Dependency**: `fun.kotlingang.kds:json:$version`\n\n[badge-android]: http://img.shields.io/badge/platform-android-6EDB8D.svg?style=flat\n[badge-ios]: http://img.shields.io/badge/platform-ios-CDCDCD.svg?style=flat\n[badge-js]: http://img.shields.io/badge/platform-js-F8DB5D.svg?style=flat\n[badge-nodejs]: http://img.shields.io/badge/platform-nodejs-68a063.svg?style=flat\n[badge-jvm]: http://img.shields.io/badge/platform-jvm-DB413D.svg?style=flat\n[badge-linux]: http://img.shields.io/badge/platform-linux-2D3F6C.svg?style=flat\n[badge-windows]: http://img.shields.io/badge/platform-windows-4D76CD.svg?style=flat\n[badge-mac]: http://img.shields.io/badge/platform-macos-111111.svg?style=flat\n[badge-watchos]: http://img.shields.io/badge/platform-watchos-C0C0C0.svg?style=flat\n[badge-tvos]: http://img.shields.io/badge/platform-tvos-808080.svg?style=flat\n[badge-wasm]: https://img.shields.io/badge/platform-wasm-624FE8.svg?style=flat\n\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fkotlingang%2Fkds","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fkotlingang%2Fkds","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fkotlingang%2Fkds/lists"}