Skip to content

Instantly share code, notes, and snippets.

@shuhart
Created December 26, 2022 20:03
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save shuhart/6fc34afd55e74274b58c0bd23bafee0c to your computer and use it in GitHub Desktop.
Save shuhart/6fc34afd55e74274b58c0bd23bafee0c to your computer and use it in GitHub Desktop.
import android.util.Log
import android.view.ViewGroup
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.size
import androidx.compose.foundation.shape.RoundedCornerShape
import androidx.compose.material.ModalBottomSheetLayout
import androidx.compose.material.ModalBottomSheetValue
import androidx.compose.material.rememberModalBottomSheetState
import androidx.compose.runtime.*
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.platform.ComposeView
import androidx.compose.ui.unit.dp
import androidx.fragment.app.Fragment
import utils.ui.compose.roundedBackground
import utils.ui.compose.theme.ComposeTheme
import kotlinx.coroutines.launch
interface BottomSheetContainer {
val dismissBottomSheet: State<Boolean>
val onDismissed: () -> Unit
}
fun Fragment.showAsBottomSheetOverTabs(
onDismissed: (() -> Unit)? = null,
content: @Composable (() -> Unit) -> Unit,
) {
val activity = requireActivity()
val container = activity.supportFragmentManager.fragments.firstOrNull { it is BottomSheetContainer }
if (container == null) {
Log.e("TAG", "No fragment is found to implement BottomSheetContainer")
return
}
val viewGroup = container.requireView() as ViewGroup
val bottomSheetContainer = container as BottomSheetContainer
viewGroup.addView(
ComposeView(viewGroup.context).apply {
tag = BottomSheetContainer::class.java.name
setContent {
ComposeTheme {
BottomSheetWrapper(
bottomSheetContainer.dismissBottomSheet,
content,
onDismissed = {
container.onDismissed()
onDismissed?.invoke()
}
)
}
}
}
)
}
@Composable
private fun BottomSheetWrapper(
dismissState: State<Boolean>,
content: @Composable (() -> Unit) -> Unit,
onDismissed: () -> Unit
) {
val coroutineScope = rememberCoroutineScope()
val modalBottomSheetState = rememberModalBottomSheetState(ModalBottomSheetValue.Hidden)
var isSheetOpened by remember { mutableStateOf(false) }
ModalBottomSheetLayout(
sheetBackgroundColor = ComposeTheme.colors.shades.n0,
sheetShape = RoundedCornerShape(24.dp),
sheetState = modalBottomSheetState,
sheetContent = {
Box(
modifier = Modifier
.padding(top = 8.dp)
.size(width = 32.dp, height = 4.dp)
.roundedBackground(color = ComposeTheme.colors.shades.n200, radius = 2.dp)
.align(Alignment.CenterHorizontally)
)
content {
// Action passed for clicking close button in the content
coroutineScope.launch {
modalBottomSheetState.hide() // will trigger the LaunchedEffect
}
}
}
) {}
// todo uncomment when we we switch to onBackPressedDispatcher. Also need to clean code from TabsFragment:onBackPressed
// BackHandler {
// coroutineScope.launch {
// modalBottomSheetState.hide() // will trigger the LaunchedEffect
// }
// }
// Take action based on hidden state
LaunchedEffect(modalBottomSheetState.currentValue) {
when (modalBottomSheetState.currentValue) {
ModalBottomSheetValue.Hidden -> {
when {
isSheetOpened -> onDismissed()
else -> {
isSheetOpened = true
modalBottomSheetState.show()
}
}
}
else -> {
// ignore
}
}
}
LaunchedEffect(dismissState.value) {
if (dismissState.value) {
modalBottomSheetState.hide()
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment