diff --git a/README.md b/README.md index 535be7f..2ae3a2d 100644 --- a/README.md +++ b/README.md @@ -8,7 +8,7 @@ [![Build](https://github.com/alorma/FireAndForget/actions/workflows/main.yml/badge.svg)](https://github.com/alorma/FireAndForget/actions/workflows/main.yml) -[![Maven Central](https://img.shields.io/maven-central/v/com.alorma.fireandforget/core.svg)](https://central.sonatype.com/namespace/com.alorma.fireandforget) +[![Maven Central](https://img.shields.io/maven-central/v/com.github.alorma.fire-and-forget/core.svg)](https://central.sonatype.com/namespace/com.github.alorma.fire-and-forget) [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT) ![Kotlin](https://img.shields.io/badge/Kotlin-2.3.0-blue.svg?logo=kotlin) @@ -148,7 +148,7 @@ For temporary state that doesn't need to persist: class InMemoryRunner : FireAndForgetRunner() { private val map = mutableMapOf() - override fun isEnabled(fireAndForget: FireAndForget): Boolean { + override fun checkEnabled(fireAndForget: FireAndForget): Boolean { return map[fireAndForget.name] ?: fireAndForget.defaultValue } @@ -170,7 +170,7 @@ Implement `FireAndForgetRunner` with your preferred storage solution (Room, Data class DataStoreRunner( private val dataStore: DataStore ) : FireAndForgetRunner() { - override fun isEnabled(fireAndForget: FireAndForget): Boolean { + override fun checkEnabled(fireAndForget: FireAndForget): Boolean { // Your DataStore implementation } @@ -213,6 +213,7 @@ abstract class FireAndForget( val fireAndForgetRunner: FireAndForgetRunner, val name: String, val defaultValue: Boolean = true, + val autoDisable: Boolean = false, ) ``` @@ -221,6 +222,7 @@ abstract class FireAndForget( - `fireAndForgetRunner`: The runner implementation that handles state persistence - `name`: Unique identifier for this flag (used as storage key) - `defaultValue`: Initial state (default: `true` = enabled) +- `autoDisable`: When `true`, automatically disables the flag on first call to `isEnabled()` (default: `false`) #### Methods @@ -232,12 +234,15 @@ abstract class FireAndForget( ```kotlin abstract class FireAndForgetRunner { - abstract fun isEnabled(fireAndForget: FireAndForget): Boolean + fun isEnabled(fireAndForget: FireAndForget): Boolean + protected abstract fun checkEnabled(fireAndForget: FireAndForget): Boolean abstract fun disable(fireAndForget: FireAndForget) abstract fun reset(fireAndForget: FireAndForget) } ``` +**Implementation Note**: When creating a custom runner, you must override `checkEnabled()` instead of `isEnabled()`. The `isEnabled()` method is final and handles the `autoDisable` logic internally, ensuring it cannot be bypassed by runner implementations. + ## Usage Examples ### Basic One-Time Execution @@ -338,6 +343,34 @@ fun initializeApp() { } ``` +### Auto-Disable Feature + +Use `autoDisable = true` to automatically disable the flag on first access without manually calling `disable()`: + +```kotlin +class QuickTip(runner: FireAndForgetRunner) : FireAndForget( + fireAndForgetRunner = runner, + name = "quick_tip", + autoDisable = true // Automatically disables after first isEnabled() call +) + +fun showScreen() { + val runner = SettingsFireAndForgetRunner(Settings()) + val quickTip = QuickTip(runner) + + // First call: returns true and automatically disables + if (quickTip.isEnabled()) { + showTooltip("Here's a quick tip!") + // No need to call quickTip.disable() + } + + // Subsequent calls: returns false + quickTip.isEnabled() // false +} +``` + +This is perfect for fire-and-forget operations where you don't have a natural completion callback to call `disable()`. The flag automatically marks itself as executed when accessed for the first time. + ## Project Structure This repository contains: diff --git a/core/src/commonMain/kotlin/com/alorma/fireandforget/FireAndForget.kt b/core/src/commonMain/kotlin/com/alorma/fireandforget/FireAndForget.kt index 665f701..d677c8e 100644 --- a/core/src/commonMain/kotlin/com/alorma/fireandforget/FireAndForget.kt +++ b/core/src/commonMain/kotlin/com/alorma/fireandforget/FireAndForget.kt @@ -1,13 +1,14 @@ package com.alorma.fireandforget -abstract class FireAndForget( +open class FireAndForget( val fireAndForgetRunner: FireAndForgetRunner, val name: String, val defaultValue: Boolean = true, + val autoDisable: Boolean = false, ) { - fun isEnabled() = fireAndForgetRunner.isEnabled(this) + open fun isEnabled() = fireAndForgetRunner.isEnabled(this) - fun disable() = fireAndForgetRunner.disable(this) + open fun disable() = fireAndForgetRunner.disable(this) - fun reset() = fireAndForgetRunner.reset(this) + open fun reset() = fireAndForgetRunner.reset(this) } \ No newline at end of file diff --git a/core/src/commonMain/kotlin/com/alorma/fireandforget/FireAndForgetRunner.kt b/core/src/commonMain/kotlin/com/alorma/fireandforget/FireAndForgetRunner.kt index 85a6f08..4e1e69a 100644 --- a/core/src/commonMain/kotlin/com/alorma/fireandforget/FireAndForgetRunner.kt +++ b/core/src/commonMain/kotlin/com/alorma/fireandforget/FireAndForgetRunner.kt @@ -1,7 +1,15 @@ package com.alorma.fireandforget abstract class FireAndForgetRunner { - abstract fun isEnabled(fireAndForget: FireAndForget): Boolean + fun isEnabled(fireAndForget: FireAndForget): Boolean { + val enabled = checkEnabled(fireAndForget) + if (enabled && fireAndForget.autoDisable) { + disable(fireAndForget) + } + return enabled + } + + protected abstract fun checkEnabled(fireAndForget: FireAndForget): Boolean abstract fun disable(fireAndForget: FireAndForget) abstract fun reset(fireAndForget: FireAndForget) } \ No newline at end of file diff --git a/multiplatform-settings/src/commonMain/kotlin/com/alorma/fireandforget/mukltiplatform/settings/SettingsFireAndForgetRunner.kt b/multiplatform-settings/src/commonMain/kotlin/com/alorma/fireandforget/mukltiplatform/settings/SettingsFireAndForgetRunner.kt index 0f5af20..926ec40 100644 --- a/multiplatform-settings/src/commonMain/kotlin/com/alorma/fireandforget/mukltiplatform/settings/SettingsFireAndForgetRunner.kt +++ b/multiplatform-settings/src/commonMain/kotlin/com/alorma/fireandforget/mukltiplatform/settings/SettingsFireAndForgetRunner.kt @@ -9,7 +9,7 @@ class SettingsFireAndForgetRunner( val settings: Settings, ) : FireAndForgetRunner() { - override fun isEnabled(fireAndForget: FireAndForget): Boolean { + override fun checkEnabled(fireAndForget: FireAndForget): Boolean { return settings.getBoolean( key = buildKey(fireAndForget = fireAndForget), defaultValue = fireAndForget.defaultValue, diff --git a/samples/androidApp/build.gradle.kts b/samples/androidApp/build.gradle.kts index c9e9420..8ea1c9f 100644 --- a/samples/androidApp/build.gradle.kts +++ b/samples/androidApp/build.gradle.kts @@ -1,3 +1,5 @@ +import org.jetbrains.kotlin.gradle.dsl.JvmTarget + plugins { alias(libs.plugins.androidApplication) alias(libs.plugins.kotlinAndroid) @@ -45,6 +47,12 @@ android { } } +kotlin { + compilerOptions { + jvmTarget.set(JvmTarget.JVM_17) + } +} + dependencies { implementation(projects.samples.shared) implementation(libs.androidx.activity.compose) diff --git a/samples/shared/src/commonMain/kotlin/com/alorma/fireandforget/shared/FireTwo.kt b/samples/shared/src/commonMain/kotlin/com/alorma/fireandforget/shared/FireTwo.kt index b0be11c..8fcd985 100644 --- a/samples/shared/src/commonMain/kotlin/com/alorma/fireandforget/shared/FireTwo.kt +++ b/samples/shared/src/commonMain/kotlin/com/alorma/fireandforget/shared/FireTwo.kt @@ -8,4 +8,5 @@ class FireTwo( ) : FireAndForget( fireAndForgetRunner = fireAndForgetRunner, name = "fire_two", + autoDisable = true, // Automatically disables on first access ) \ No newline at end of file diff --git a/samples/shared/src/commonMain/kotlin/com/alorma/fireandforget/shared/InMemoryFireAndForgetRunner.kt b/samples/shared/src/commonMain/kotlin/com/alorma/fireandforget/shared/InMemoryFireAndForgetRunner.kt index b04ac7d..baa8fa4 100644 --- a/samples/shared/src/commonMain/kotlin/com/alorma/fireandforget/shared/InMemoryFireAndForgetRunner.kt +++ b/samples/shared/src/commonMain/kotlin/com/alorma/fireandforget/shared/InMemoryFireAndForgetRunner.kt @@ -7,7 +7,7 @@ class InMemoryFireAndForgetRunner: FireAndForgetRunner() { val map: MutableMap = mutableMapOf() - override fun isEnabled(fireAndForget: FireAndForget): Boolean { + override fun checkEnabled(fireAndForget: FireAndForget): Boolean { return map[fireAndForget.name] ?: fireAndForget.defaultValue }