Last active
January 25, 2022 13:57
-
-
Save ckarthickit/3c29388de382e514bcd11836e089dfcc to your computer and use it in GitHub Desktop.
Compose Utilities
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Utility functions |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| class ComposeCountRef(var counter: Int) | |
| @Suppress("NOTHING_TO_INLINE") | |
| @Composable | |
| inline fun LogCompositions(tag: String, msg: String) { | |
| val compositionCountRef = remember { ComposeCountRef(0) } | |
| SideEffect { | |
| compositionCountRef.counter ++ | |
| } | |
| Timber.tag(tag).d("Compositions $msg : ${compositionCountRef.counter}") | |
| if(compositionCountRef.counter > 0) { | |
| Exception("Compositions recomposing_$msg").printStackTrace() | |
| }else { | |
| Exception("Compositions composing_$msg").printStackTrace() | |
| } | |
| } |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| import android.os.SystemClock | |
| import androidx.compose.foundation.Indication | |
| import androidx.compose.foundation.LocalIndication | |
| import androidx.compose.foundation.clickable | |
| import androidx.compose.foundation.interaction.MutableInteractionSource | |
| import androidx.compose.runtime.getValue | |
| import androidx.compose.runtime.mutableStateOf | |
| import androidx.compose.runtime.remember | |
| import androidx.compose.runtime.rememberUpdatedState | |
| import androidx.compose.runtime.setValue | |
| import androidx.compose.ui.Modifier | |
| import androidx.compose.ui.composed | |
| import androidx.compose.ui.platform.debugInspectorInfo | |
| import androidx.compose.ui.semantics.Role | |
| import androidx.compose.ui.semantics.selected | |
| import androidx.compose.ui.semantics.semantics | |
| import timber.log.Timber | |
| fun Modifier.debounceSelectable( | |
| debounceInMillis: Long = 2000, | |
| selected: Boolean, | |
| interactionSource: MutableInteractionSource, | |
| indication: Indication?, | |
| enabled: Boolean = true, | |
| role: Role? = null, | |
| onClick: () -> Unit | |
| ) = debounceSelectableInternal( | |
| debounceInMillis = debounceInMillis, | |
| selected = selected, | |
| interactionSource = interactionSource, | |
| indication = indication, | |
| enabled = enabled, | |
| role = role, | |
| onClick = onClick | |
| ) | |
| fun Modifier.debouncedClickable( | |
| debounceInMillis: Long = 2000, | |
| enabled: Boolean = true, | |
| onClickLabel: String? = null, | |
| role: Role? = null, | |
| indication: Indication?, | |
| onClick: () -> Unit | |
| ) = debounceSelectableInternal( | |
| debounceInMillis = debounceInMillis, | |
| enabled = enabled, | |
| onClickLabel = onClickLabel, | |
| role = role, | |
| indication = indication, | |
| onClick = onClick | |
| ) | |
| internal fun Modifier.debounceSelectableInternal( | |
| debounceInMillis: Long = 2000, | |
| selected: Boolean? = null, | |
| interactionSource: MutableInteractionSource? = null, | |
| indication: Indication?, | |
| enabled: Boolean = true, | |
| onClickLabel: String? = null, | |
| role: Role? = null, | |
| onClick: () -> Unit | |
| ) = composed( | |
| inspectorInfo = debugInspectorInfo { | |
| name = "debounceSelectable" | |
| properties["debounceInMillis"] = debounceInMillis | |
| properties["selected"] = selected | |
| properties["interactionSource"] = interactionSource | |
| properties["indication"] = indication | |
| properties["enabled"] = enabled | |
| properties["onClickLabel"] = onClickLabel | |
| properties["role"] = role | |
| properties["onClick"] = onClick | |
| }) { | |
| val currentOnClick = rememberUpdatedState(newValue = onClick) | |
| var lastClickTime by remember { | |
| mutableStateOf(SystemClock.elapsedRealtime()) | |
| } | |
| Modifier | |
| .clickable( | |
| enabled = enabled, | |
| onClickLabel = onClickLabel, | |
| role = role, | |
| indication = indication ?: LocalIndication.current, | |
| interactionSource = interactionSource ?: remember { MutableInteractionSource() }, | |
| onClick = { | |
| val timeSinceLastClick = SystemClock.elapsedRealtime() - lastClickTime | |
| if (timeSinceLastClick > debounceInMillis) { | |
| lastClickTime = SystemClock.elapsedRealtime() | |
| currentOnClick.value.invoke() | |
| } else { | |
| Timber.d("Ignoring Click until ${debounceInMillis - timeSinceLastClick}ms") | |
| } | |
| } | |
| ).apply { | |
| if (selected != null) { | |
| this.semantics { | |
| this.selected = selected | |
| } | |
| } | |
| } | |
| } |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| /** | |
| * A Side Effect that is invoked whenever the [Lifecycle.Event] fired by the [Lifecycle] | |
| * associated with the current [LocalLifecycleOwner] | |
| * matches the passed [lifecycleEvent] param | |
| */ | |
| @Composable | |
| fun LifecycleLaunchedEffect( | |
| lifecycleEvent: Lifecycle.Event = Lifecycle.Event.ON_RESUME, | |
| onLifecycleEvent: suspend CoroutineScope.() -> Unit | |
| ) { | |
| val coroutineScope = rememberCoroutineScope() | |
| val currentLifecycleEventCallback = rememberUpdatedState(newValue = onLifecycleEvent) | |
| val lifecycleEventObserver = remember { | |
| LifecycleEventObserver { _, event -> | |
| if (event == lifecycleEvent) { | |
| coroutineScope.launch(block = currentLifecycleEventCallback.value) | |
| } | |
| } | |
| } | |
| val lifecycle = LocalLifecycleOwner.current.lifecycle | |
| DisposableEffect(lifecycle, lifecycleEventObserver) { | |
| lifecycle.addObserver(lifecycleEventObserver) | |
| onDispose { | |
| lifecycle.removeObserver(lifecycleEventObserver) | |
| } | |
| } | |
| } |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment