Skip to content

Instantly share code, notes, and snippets.

@naeemdev
Created May 14, 2023 04:54
Show Gist options
  • Save naeemdev/e7f8c6c4b83a2767ca964f5d1edd0a69 to your computer and use it in GitHub Desktop.
Save naeemdev/e7f8c6c4b83a2767ca964f5d1edd0a69 to your computer and use it in GitHub Desktop.
import androidx.compose.runtime.Composable
import androidx.compose.runtime.LaunchedEffect
import androidx.compose.runtime.SideEffect
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.compose.runtime.setValue
private class Ref<T>(var value: T)
@Composable
fun ReDebugger(
trackMap: Map<String, Any?>,
logger: (tag: String, message: String) -> Unit = { tag, message ->
ReDebuggerConfig.logger.invoke(
tag,
message
)
},
composableName: String = Thread.currentThread().stackTrace[3].methodName,
) {
LaunchedEffect(Unit) {
logger(ReDebuggerConfig.tag, "🐞 ReDebugger activated on `$composableName`")
}
val count = remember { Ref(0) }
val flag = remember { Ref(false) }
SideEffect {
count.value++
}
val changeLog = StringBuilder()
for ((key, newArg) in trackMap) {
var recompositionTrigger by remember { mutableStateOf(false) }
val oldArg = remember(recompositionTrigger) { newArg }
if (oldArg != newArg) {
changeLog.append("\n\t `$key` changed from `$oldArg` to `$newArg`, ")
flag.value = true
recompositionTrigger = !recompositionTrigger
}
}
if (changeLog.isNotEmpty()) {
logger(ReDebuggerConfig.tag, "🐞$composableName recomposed because $changeLog")
} else {
if (count.value >= 1 && !flag.value) {
logger(ReDebuggerConfig.tag, "🐞$composableName recomposed, but reason is unknown. Are you sure you added all params to `trackMap`? πŸ€”")
} else {
flag.value = false
}
}
}
import android.util.Log
object ReDebuggerConfig {
/*Default values*/
private val defaultLogger: (tag: String, message: String) -> Unit = { tag, message ->
Log.d(tag, message)
}
private const val DEFAULT_TAG = "ReDebugger"
/**/
internal var tag = DEFAULT_TAG
internal var logger: (tag: String, message: String) -> Unit = defaultLogger
/**
* To override ReDebugger's default variables
*/
fun init(
tag: String = DEFAULT_TAG,
logger: (tag: String, message: String) -> Unit = defaultLogger
) {
this.tag = tag
this.logger = logger
}
}
import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.material.Button
import androidx.compose.material.Text
import androidx.compose.runtime.Composable
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.compose.runtime.setValue
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.unit.sp
data class Car(val name: String)
data class Bike(val name: String)
data class Human(val name: String)
@Composable
fun ReDebuggerSample() {
var car by remember { mutableStateOf(Car("Audi")) }
var bike by remember { mutableStateOf(Bike("Yamaha")) }
Column(
modifier = Modifier.fillMaxSize(),
verticalArrangement = Arrangement.Center,
horizontalAlignment = Alignment.CenterHorizontally,
) {
VehicleUi(
car = car,
bike = bike
)
Button(
onClick = {
car = Car("Audi - ${System.currentTimeMillis()}")
}
) {
Text("Create new Audi")
}
Button(
onClick = {
bike = Bike("Yamaha - ${System.currentTimeMillis()}")
}
) {
Text("Create new Yamaha")
}
Button(
onClick = {
car = Car("Audi - ${System.currentTimeMillis()}")
bike = Bike("Yamaha - ${System.currentTimeMillis()}")
}
) {
Text("Create Audi & Yamaha")
}
Text(text = "(see Logcat and search for 'ReDebugger')", fontSize = 23.sp)
}
}
@Composable
fun VehicleUi(
car: Car,
bike: Bike,
) {
println("Vehicle recomposed")
ReDebugger(
trackMap = mapOf(
"car" to car,
"bike" to bike,
),
)
Column {
Text("Car is $car")
Text("Bike is $bike")
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment