Skip to content

Commit

Permalink
AppLinkChooserSheet: use material3 bottom sheet
Browse files Browse the repository at this point in the history
  • Loading branch information
ivaniskandar committed Jan 12, 2025
1 parent 140b359 commit 4715a83
Show file tree
Hide file tree
Showing 2 changed files with 39 additions and 139 deletions.
2 changes: 0 additions & 2 deletions app/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -85,7 +85,6 @@ dependencies {

implementation platform("androidx.compose:compose-bom-alpha:$compose_bom_version")
implementation "androidx.compose.ui:ui"
implementation "androidx.compose.material:material"
implementation "androidx.compose.material:material-icons-extended"
implementation "androidx.compose.material3:material3"
implementation "androidx.compose.ui:ui-text-google-fonts"
Expand Down Expand Up @@ -125,7 +124,6 @@ kotlin {
jvmTarget = JvmTarget.JVM_17

freeCompilerArgs.addAll(
"-opt-in=androidx.compose.material.ExperimentalMaterialApi",
"-opt-in=androidx.compose.material3.ExperimentalMaterial3Api",
"-opt-in=androidx.compose.foundation.ExperimentalFoundationApi",
"-opt-in=androidx.compose.animation.ExperimentalAnimationApi",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,62 +6,37 @@ import android.content.pm.PackageManager
import android.os.Bundle
import android.provider.Settings
import androidx.activity.ComponentActivity
import androidx.activity.compose.BackHandler
import androidx.activity.compose.setContent
import androidx.compose.animation.core.TweenSpec
import androidx.compose.animation.core.animateFloatAsState
import androidx.compose.foundation.Canvas
import androidx.compose.foundation.Image
import androidx.compose.foundation.combinedClickable
import androidx.compose.foundation.gestures.detectTapGestures
import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.PaddingValues
import androidx.compose.foundation.layout.WindowInsets
import androidx.compose.foundation.layout.WindowInsetsSides
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.navigationBars
import androidx.compose.foundation.layout.only
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.size
import androidx.compose.foundation.layout.widthIn
import androidx.compose.foundation.layout.windowInsetsPadding
import androidx.compose.foundation.lazy.LazyColumn
import androidx.compose.foundation.lazy.items
import androidx.compose.foundation.shape.RoundedCornerShape
import androidx.compose.material.ModalBottomSheetLayout
import androidx.compose.material.ModalBottomSheetValue
import androidx.compose.material.rememberModalBottomSheetState
import androidx.compose.material3.ListItem
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.ModalBottomSheet
import androidx.compose.material3.Text
import androidx.compose.material3.surfaceColorAtElevation
import androidx.compose.runtime.Composable
import androidx.compose.runtime.LaunchedEffect
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.compose.runtime.rememberCoroutineScope
import androidx.compose.runtime.setValue
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.graphics.ImageBitmap
import androidx.compose.ui.graphics.asImageBitmap
import androidx.compose.ui.graphics.isSpecified
import androidx.compose.ui.hapticfeedback.HapticFeedbackType
import androidx.compose.ui.input.pointer.pointerInput
import androidx.compose.ui.platform.LocalHapticFeedback
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.semantics.onClick
import androidx.compose.ui.semantics.semantics
import androidx.compose.ui.text.style.TextAlign
import androidx.compose.ui.unit.dp
import androidx.core.graphics.drawable.toBitmap
import androidx.core.net.toUri
import androidx.core.view.WindowCompat
import kotlinx.coroutines.launch
import xyz.ivaniskandar.shouko.R
import xyz.ivaniskandar.shouko.feature.LinkCleaner
import xyz.ivaniskandar.shouko.ui.IconDrawableShadowWrapper
Expand Down Expand Up @@ -159,123 +134,50 @@ private fun AppLinkChooserSheet(
onItemLongClick: (ComponentName) -> Unit,
onFinish: () -> Unit,
) {
val state = rememberModalBottomSheetState(initialValue = ModalBottomSheetValue.Hidden)
val scope = rememberCoroutineScope()
val haptic = LocalHapticFeedback.current

Box {
Scrim(
color = MaterialTheme.colorScheme.scrim.copy(alpha = 0.32f),
onDismiss = {
scope.launch { state.hide() }
},
visible = state.targetValue != ModalBottomSheetValue.Hidden,
)
ModalBottomSheetLayout(
ModalBottomSheet(onDismissRequest = onFinish) {
Text(
text = stringResource(R.string.link_chooser_dialog_title),
modifier = Modifier
.widthIn(max = 640.dp)
.align(Alignment.BottomCenter),
scrimColor = Color.Transparent,
sheetState = state,
sheetShape = RoundedCornerShape(topStart = 28.dp, topEnd = 28.dp),
sheetElevation = 0.dp,
sheetBackgroundColor = MaterialTheme.colorScheme.surfaceColorAtElevation(1.dp),
sheetContentColor = MaterialTheme.colorScheme.onSurface,
sheetContent = {
Text(
text = stringResource(R.string.link_chooser_dialog_title),
.fillMaxWidth()
.padding(bottom = 16.dp),
color = MaterialTheme.colorScheme.onSurface,
textAlign = TextAlign.Center,
style = MaterialTheme.typography.titleMedium,
)
SoftDivider()
LazyColumn(
modifier = Modifier.windowInsetsPadding(WindowInsets.navigationBars.only(WindowInsetsSides.Bottom)),
contentPadding = PaddingValues(vertical = 8.dp),
verticalArrangement = Arrangement.spacedBy(2.dp),
) {
items(targets) { item ->
ListItem(
modifier = Modifier
.fillMaxWidth()
.padding(vertical = 16.dp),
color = MaterialTheme.colorScheme.onSurface,
textAlign = TextAlign.Center,
style = MaterialTheme.typography.titleMedium,
)
SoftDivider(modifier = Modifier.padding(horizontal = 16.dp))
LazyColumn(
modifier = Modifier.windowInsetsPadding(WindowInsets.navigationBars.only(WindowInsetsSides.Bottom)),
contentPadding = PaddingValues(vertical = 8.dp),
verticalArrangement = Arrangement.spacedBy(2.dp),
) {
items(targets) { item ->
ListItem(
modifier = Modifier
.combinedClickable(
onLongClick = {
scope.launch { state.hide() }
haptic.performHapticFeedback(HapticFeedbackType.LongPress)
onItemLongClick(item.component)
},
onClick = {
scope.launch { state.hide() }
onItemClick(item.component)
},
),
leadingContent = {
Image(
bitmap = item.icon,
contentDescription = null,
modifier = Modifier.size(36.dp),
)
.combinedClickable(
onLongClick = {
haptic.performHapticFeedback(HapticFeedbackType.LongPress)
onItemLongClick(item.component)
},
headlineContent = {
Text(
text = item.title,
style = MaterialTheme.typography.bodyLarge,
)
onClick = {
onItemClick(item.component)
},
tonalElevation = 1.dp,
),
leadingContent = {
Image(
bitmap = item.icon,
contentDescription = null,
modifier = Modifier.size(36.dp),
)
}
}
},
content = { /* Empty */ },
)
}
var opened by remember { mutableStateOf(false) }
LaunchedEffect(state.currentValue, onFinish) {
if (!opened) scope.launch { state.show() }
when (state.currentValue) {
ModalBottomSheetValue.Hidden -> if (opened) onFinish()
ModalBottomSheetValue.Expanded, ModalBottomSheetValue.HalfExpanded -> opened = true
}
}
BackHandler {
scope.launch { state.hide() }
}
}

@Composable
private fun Scrim(
color: Color,
onDismiss: () -> Unit,
visible: Boolean,
) {
if (color.isSpecified) {
val alpha by animateFloatAsState(
targetValue = if (visible) 1f else 0f,
animationSpec = TweenSpec(),
label = "scrim",
)
val dismissModifier = if (visible) {
Modifier
.pointerInput(onDismiss) { detectTapGestures { onDismiss() } }
.semantics(mergeDescendants = true) {
onClick {
onDismiss()
true
}
}
} else {
Modifier
}

Canvas(
Modifier
.fillMaxSize()
.then(dismissModifier),
) {
drawRect(color = color, alpha = alpha)
},
headlineContent = {
Text(
text = item.title,
style = MaterialTheme.typography.bodyLarge,
)
},
)
}
}
}
}

0 comments on commit 4715a83

Please sign in to comment.