Skip to content

Commit

Permalink
feat: patch options (ReVanced#81)
Browse files Browse the repository at this point in the history
* feat: Patch Options

* refactor: remove delegate property

* feat: List patch options

* refactor: add setter example to PatchOptionsUsage.kt

* docs: add docs for PatchOptions

* docs: tidy docs
  • Loading branch information
Sculas committed Aug 1, 2022
1 parent 9a4d30e commit fbb09f3
Show file tree
Hide file tree
Showing 4 changed files with 151 additions and 0 deletions.
5 changes: 5 additions & 0 deletions src/main/kotlin/app/revanced/patcher/patch/Patch.kt
Expand Up @@ -17,4 +17,9 @@ abstract class Patch<out T : Data> {
* The main function of the [Patch] which the patcher will call.
*/
abstract fun execute(data: @UnsafeVariance T): PatchResult

/**
* A list of [PatchOption]s.
*/
open val options: Iterable<PatchOption<*>> = listOf()
}
100 changes: 100 additions & 0 deletions src/main/kotlin/app/revanced/patcher/patch/PatchOption.kt
@@ -0,0 +1,100 @@
package app.revanced.patcher.patch

/**
* A [Patch] option.
* @param key Unique identifier of the option. Example: _`settings.microg.enabled`_
* @param default The default value of the option.
* @param title A human-readable title of the option. Example: _MicroG Settings_
* @param description A human-readable description of the option. Example: _Settings integration for MicroG._
* @param required Whether the option is required.
*/
@Suppress("MemberVisibilityCanBePrivate")
sealed class PatchOption<T>(
val key: String,
default: T?,
val title: String,
val description: String,
val required: Boolean
) {
var value: T? = default

/**
* A [PatchOption] representing a [String].
* @see PatchOption
*/
class StringOption(
key: String,
default: String?,
title: String,
description: String,
required: Boolean = false
) : PatchOption<String>(
key, default, title, description, required
)

/**
* A [PatchOption] representing a [Boolean].
* @see PatchOption
*/
class BooleanOption(
key: String,
default: Boolean?,
title: String,
description: String,
required: Boolean = false
) : PatchOption<Boolean>(
key, default, title, description, required
)

/**
* A [PatchOption] with a list of allowed options.
* @param options A list of allowed options for the [ListOption].
* @see PatchOption
*/
sealed class ListOption<E>(
key: String,
default: E?,
val options: Iterable<E>,
title: String,
description: String,
required: Boolean = false
) : PatchOption<E>(
key, default, title, description, required
) {
init {
if (default !in options) {
throw IllegalStateException("Default option must be an allowed options")
}
}
}

/**
* A [ListOption] of type [String].
* @see ListOption
*/
class StringListOption(
key: String,
default: String?,
options: Iterable<String>,
title: String,
description: String,
required: Boolean = false
) : ListOption<String>(
key, default, options, title, description, required
)

/**
* A [ListOption] of type [Int].
* @see ListOption
*/
class IntListOption(
key: String,
default: Int?,
options: Iterable<Int>,
title: String,
description: String,
required: Boolean = false
) : ListOption<Int>(
key, default, options, title, description, required
)
}
30 changes: 30 additions & 0 deletions src/test/kotlin/app/revanced/patcher/usage/PatchOptionsUsage.kt
@@ -0,0 +1,30 @@
package app.revanced.patcher.usage

import app.revanced.patcher.patch.PatchOption
import app.revanced.patcher.usage.bytecode.ExampleBytecodePatch

fun patchOptionsUsage() {
val options = ExampleBytecodePatch().options
for (option in options) {
when (option) {
is PatchOption.StringOption -> {
option.value = "Hello World"
}
is PatchOption.BooleanOption -> {
option.value = false
}
is PatchOption.StringListOption -> {
option.value = option.options.first()
for (choice in option.options) {
println(choice)
}
}
is PatchOption.IntListOption -> {
option.value = option.options.first()
for (choice in option.options) {
println(choice)
}
}
}
}
}
Expand Up @@ -7,6 +7,7 @@ import app.revanced.patcher.data.impl.BytecodeData
import app.revanced.patcher.extensions.addInstructions
import app.revanced.patcher.extensions.or
import app.revanced.patcher.extensions.replaceInstruction
import app.revanced.patcher.patch.PatchOption
import app.revanced.patcher.patch.PatchResult
import app.revanced.patcher.patch.PatchResultSuccess
import app.revanced.patcher.patch.annotations.DependencyType
Expand Down Expand Up @@ -162,4 +163,19 @@ class ExampleBytecodePatch : BytecodePatch(listOf(ExampleFingerprint)) {
)
)
}

override val options = listOf(
PatchOption.StringOption(
"key", "default", "title", "description", true
),
PatchOption.BooleanOption(
"key", true, "title", "description" // required defaults to false
),
PatchOption.StringListOption(
"key", "TEST", listOf("TEST", "TEST1", "TEST2"), "title", "description"
),
PatchOption.IntListOption(
"key", 1, listOf(1, 2, 3), "title", "description"
),
)
}

0 comments on commit fbb09f3

Please sign in to comment.