Skip to content

Commit

Permalink
Merge pull request #21 from RedMadRobot/feature/add-konfeature-plugin
Browse files Browse the repository at this point in the history
[PLUGINS] add konfeature plugin
  • Loading branch information
AleksandrTabolin authored Aug 8, 2024
2 parents f45eb01 + b6908b3 commit 1d631f9
Show file tree
Hide file tree
Showing 25 changed files with 1,041 additions and 8 deletions.
1 change: 1 addition & 0 deletions common/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,7 @@ dependencies {
api(androidx.room.runtime)
api(rmr.flipper)
api(rmr.itemsadapter.viewbinding)
api(libs.konfeature)
api(stack.accompanist.themeadapter.core)
api(stack.accompanist.themeadapter.material)
api(stack.kotlinx.coroutines.android)
Expand Down
5 changes: 5 additions & 0 deletions gradle/libs.versions.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
[versions]
konfeature = "0.1.0"

[libraries]
konfeature = { module = "com.redmadrobot.konfeature:konfeature", version.ref = "konfeature" }
1 change: 1 addition & 0 deletions no-op/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -43,5 +43,6 @@ dependencies {
implementation(stack.okhttp)
implementation(androidx.appcompat)
implementation(rmr.flipper)
implementation(libs.konfeature)
implementation(stack.kotlinx.coroutines.android)
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
package com.redmadrobot.debug.plugin.konfeature

import android.content.Context
import com.redmadrobot.konfeature.source.FeatureValueSource
import com.redmadrobot.konfeature.source.Interceptor


public class KonfeatureDebugPanelInterceptor(context: Context) : Interceptor {

override val name: String = "NoopDebugPanelInterceptor"

override fun intercept(valueSource: FeatureValueSource, key: String, value: Any): Any? = null
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
package com.redmadrobot.debug.plugin.konfeature

import com.redmadrobot.konfeature.Konfeature

public class KonfeaturePlugin(
private val debugPanelInterceptor: KonfeatureDebugPanelInterceptor,
private val konfeature: Konfeature,
)
1 change: 1 addition & 0 deletions plugins/konfeature/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
/build
54 changes: 54 additions & 0 deletions plugins/konfeature/build.gradle.kts
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
plugins {
id(Plugins.Android.libraryPlagin)
kotlin(Plugins.Kotlin.androidPlugin)
kotlin(Plugins.Kotlin.kapt)
id("convention-publish")
}

description = "Plugin for konfeature library integration"

android {
compileSdk = Project.COMPILE_SDK
lint.targetSdk = Project.TARGET_SDK

defaultConfig {
minSdk = Project.MIN_SDK

consumerProguardFile("consumer-rules.pro")
}

buildTypes {
getByName(Project.BuildTypes.release) {
isMinifyEnabled = false
proguardFiles(
getDefaultProguardFile(Project.Proguard.androidOptimizedRules),
Project.Proguard.projectRules
)
}
}

compileOptions {
sourceCompatibility = JavaVersion.VERSION_1_8
targetCompatibility = JavaVersion.VERSION_1_8
}

kotlinOptions {
jvmTarget = "1.8"
freeCompilerArgs += "-Xexplicit-api=strict"
}

buildFeatures {
compose = true
}

composeOptions {
kotlinCompilerExtensionVersion = androidx.versions.compose.compiler.get()
}
namespace = "com.redmadrobot.debug.plugin.konfeature"
}

dependencies {
implementation(project(":core"))
implementation(project(":common"))
implementation(androidx.lifecycle.runtime)
}
Empty file.
3 changes: 3 additions & 0 deletions plugins/konfeature/library.properties
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
lib_name = plugin-konfeature
lib_vcs=https://github.com/RedMadRobot/debug-panel-android.git
lib_issue_tracker=https://github.com/RedMadRobot/debug-panel-android/issues
21 changes: 21 additions & 0 deletions plugins/konfeature/proguard-rules.pro
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
# Add project specific ProGuard rules here.
# You can control the set of applied configuration files using the
# proguardFiles setting in build.gradle.kts.kts.kts.kts.kts.kts.kts.kts.
#
# For more details, see
# http://developer.android.com/guide/developing/tools/proguard.html

# If your project uses WebView with JS, uncomment the following
# and specify the fully qualified class name to the JavaScript interface
# class:
#-keepclassmembers class fqcn.of.javascript.interface.for.webview {
# public *;
#}

# Uncomment this to preserve the line number information for
# debugging stack traces.
#-keepattributes SourceFile,LineNumberTable

# If you keep the line number information, uncomment this to
# hide the original source file name.
#-renamesourcefileattribute SourceFile
Original file line number Diff line number Diff line change
@@ -0,0 +1,115 @@
package com.redmadrobot.debug.plugin.konfeature

import android.content.Context
import android.content.SharedPreferences
import androidx.core.content.edit
import com.redmadrobot.debug.plugin.konfeature.util.JsonConverter
import com.redmadrobot.konfeature.source.FeatureValueSource
import com.redmadrobot.konfeature.source.Interceptor
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.coroutineScope
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.asStateFlow
import kotlinx.coroutines.flow.update
import kotlinx.coroutines.launch
import kotlinx.coroutines.sync.Mutex
import kotlinx.coroutines.sync.withLock
import org.json.JSONObject
import timber.log.Timber

public class KonfeatureDebugPanelInterceptor(context: Context) : Interceptor {

private val preferences by lazy {
context.getSharedPreferences(FILE_NAME, Context.MODE_PRIVATE)
}

private val _valuesFlow = MutableStateFlow(emptyMap<String, Any>())

internal val valuesFlow = _valuesFlow.asStateFlow()

private val mutex = Mutex()

override val name: String = "DebugPanelInterceptor"

init {
CoroutineScope(Dispatchers.IO).launch {
_valuesFlow.value = mutex.withLock { fetchValues(preferences) }
}
}

override fun intercept(valueSource: FeatureValueSource, key: String, value: Any): Any? {
return _valuesFlow.value[key]
?.let { convertTypeIfNeeded(it, value) }
?.takeIf { it != value }
}

/*
* map debugValue from Int to Long,
* from Float to Double,
* from Long to Double if value is Double
*/
private fun convertTypeIfNeeded(debugValue: Any, value: Any): Any {
var result = when {
debugValue is Int -> debugValue.toLong()
debugValue is Float -> debugValue.toDouble()
else -> debugValue
}
if (result is Long && value is Double) {
result = result.toDouble()
}
return result
}

internal suspend fun setValue(key: String, value: Any) {
_valuesFlow.update { it + (key to value) }
updateValues(_valuesFlow.value)
}

internal suspend fun resetValue(key: String) {
_valuesFlow.update { it - key }
updateValues(_valuesFlow.value)
}

internal suspend fun resetAllValues() {
_valuesFlow.value = emptyMap<String, Any>()
updateValues(_valuesFlow.value)
}

private suspend fun updateValues(map: Map<String, Any>) {
coroutineScope {
launch(Dispatchers.IO) {
mutex.withLock { updateValues(preferences, map) }
}
}
}

private fun fetchValues(preferences: SharedPreferences): Map<String, Any> {
return try {
val jsonValues = preferences.getString(KEY, EMPTY_MAP) ?: EMPTY_MAP
JsonConverter.toMap(JSONObject(jsonValues))
} catch (error: Exception) {
Timber.tag(TAG).e(error, "cant fetch debug values")
preferences.edit(commit = true) { remove(KEY) }
emptyMap<String, Any>()
}
}

private fun updateValues(preferences: SharedPreferences, map: Map<String, Any>) {
try {
val jsonValues = JSONObject(map).toString()
preferences.edit(commit = true) {
putString(KEY, jsonValues)
}
} catch (error: Exception) {
Timber.tag(TAG).e(error, "cant update debug values")
}
}

private companion object {
private const val EMPTY_MAP = "{}"
private const val FILE_NAME = "debug_panel_interceptor_values"
private const val KEY = "values"
private const val TAG = "DebugPanelInterceptor"
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
package com.redmadrobot.debug.plugin.konfeature

import androidx.compose.runtime.Composable
import com.redmadrobot.debug.core.internal.CommonContainer
import com.redmadrobot.debug.core.internal.PluginDependencyContainer
import com.redmadrobot.debug.core.plugin.Plugin
import com.redmadrobot.debug.plugin.konfeaure.ui.KonfeatureScreen
import com.redmadrobot.konfeature.Konfeature

public class KonfeaturePlugin(
private val debugPanelInterceptor: KonfeatureDebugPanelInterceptor,
private val konfeature: Konfeature,
) : Plugin() {

private companion object {
private const val NAME = "KONFEATURE"
}

override fun getName(): String = NAME

override fun getPluginContainer(commonContainer: CommonContainer): PluginDependencyContainer {
return KonfeaturePluginContainer(konfeature, debugPanelInterceptor)
}

@Composable
override fun content() {
KonfeatureScreen()
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
package com.redmadrobot.debug.plugin.konfeature

import com.redmadrobot.debug.core.internal.PluginDependencyContainer
import com.redmadrobot.debug.plugin.konfeature.ui.KonfeatureViewModel
import com.redmadrobot.konfeature.Konfeature

internal class KonfeaturePluginContainer(
private val konfeature: Konfeature,
private val debugPanelInterceptor: KonfeatureDebugPanelInterceptor,
) : PluginDependencyContainer {

fun createKonfeatureViewModel(): KonfeatureViewModel {
return KonfeatureViewModel(konfeature, debugPanelInterceptor)
}
}
Loading

0 comments on commit 1d631f9

Please sign in to comment.