Skip to content

Commit

Permalink
Refactor: Update details screen and add FAB menu
Browse files Browse the repository at this point in the history
This commit refactors the details screen to improve the user experience and adds a floating action button (FAB) menu.

- Added a FAB menu to the details screen that expands when clicked.
- Added options to the FAB menu to save, remove, and search.
- Added the ability to blur the FAB menu when it is expanded.
- Updated `DetailFloatingActionButtonMenu` to use `fabMenuExpanded` for the expanded state.
- Updated `DetailsView` to use `fabMenuExpanded` for controlling the FAB menu and collapsing behavior.
- Added a `fabBlur` modifier to blur the background when the FAB menu is expanded.
- Added a check for `!fabMenuExpanded` to determine if the user can scroll in `CollapsableColumn`.
- Updated `DetailsHeader` to show if the item is a favorite and to add/remove it from the favorite list.
- Updated `DetailsViewModel` to update blur hash on changes and adding/removing favorites.
- Removed old code to add blur hash on item add to favorites, now it is checked on `infoAndFavoriteFlow`.
- Updated dependencies.
  • Loading branch information
jacobrein committed Jan 31, 2025
1 parent 95069c0 commit 8641a59
Show file tree
Hide file tree
Showing 4 changed files with 59 additions and 53 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,7 @@ import androidx.compose.ui.unit.dp
import androidx.compose.ui.unit.sp
import androidx.compose.ui.window.DialogProperties
import androidx.core.graphics.ColorUtils
import androidx.core.graphics.createBitmap
import com.bumptech.glide.load.model.GlideUrl
import com.kmpalette.palette.graphics.Palette
import com.programmersbox.models.InfoModel
Expand Down Expand Up @@ -104,7 +105,7 @@ internal fun DetailsHeader(
GlideUrl(model.imageUrl) { model.extras.map { it.key to it.value.toString() }.toMap() }
} catch (e: IllegalArgumentException) {
e.printStackTrace()
val b = Bitmap.createBitmap(5, 5, Bitmap.Config.ARGB_8888)
val b = createBitmap(5, 5)
Canvas(b).drawColor(surface.toArgb())
b
}
Expand Down Expand Up @@ -253,28 +254,30 @@ internal fun DetailsHeader(
overflow = TextOverflow.Ellipsis,
maxLines = if (descriptionVisibility) Int.MAX_VALUE else 3,
)
Crossfade(targetState = isFavorite, label = "") { target ->
Row(
horizontalArrangement = Arrangement.spacedBy(4.dp),
verticalAlignment = Alignment.CenterVertically,
modifier = Modifier
.clip(MaterialTheme.shapes.medium)
.clickable(
interactionSource = null,
indication = ripple()
) { favoriteClick(isFavorite) }
.padding(4.dp)
.semantics(true) {}
.fillMaxWidth()
) {
Icon(
if (target) Icons.Default.Favorite else Icons.Default.FavoriteBorder,
contentDescription = null,
modifier = Modifier.size(20.dp)
)

Row(
modifier = Modifier
.clickable(
interactionSource = null,
indication = ripple()
) { favoriteClick(isFavorite) }
.semantics(true) {}
.fillMaxWidth(),
horizontalArrangement = Arrangement.spacedBy(4.dp)
) {
Icon(
if (isFavorite) Icons.Default.Favorite else Icons.Default.FavoriteBorder,
contentDescription = null,
modifier = Modifier.align(Alignment.CenterVertically)
)
Crossfade(targetState = isFavorite, label = "") { target ->
Text(
stringResource(if (target) R.string.removeFromFavorites else R.string.addToFavorites),
style = MaterialTheme.typography.headlineSmall,
fontSize = 20.sp,
modifier = Modifier.align(Alignment.CenterVertically),
style = MaterialTheme.typography.titleSmall,
fontSize = 16.sp,
)
}
}
Expand Down Expand Up @@ -356,7 +359,6 @@ internal fun PlaceHolderHeader(
}

Row(modifier = Modifier.padding(4.dp)) {

Card(
shape = RoundedCornerShape(4.dp),
modifier = Modifier
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,6 @@ import androidx.compose.runtime.derivedStateOf
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.compose.runtime.saveable.rememberSaveable
import androidx.compose.runtime.setValue
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
Expand Down Expand Up @@ -422,6 +421,8 @@ fun DetailBottomBar(
@Composable
fun DetailFloatingActionButtonMenu(
navController: NavController,
fabMenuExpanded: Boolean,
onFabMenuExpandedChange: (Boolean) -> Unit,
isVisible: Boolean,
onShowLists: () -> Unit,
info: InfoModel,
Expand All @@ -434,9 +435,8 @@ fun DetailFloatingActionButtonMenu(
isFavorite: Boolean,
onFavoriteClick: (Boolean) -> Unit,
) {
var fabMenuExpanded by rememberSaveable { mutableStateOf(false) }

BackHandler(fabMenuExpanded) { fabMenuExpanded = false }
BackHandler(fabMenuExpanded) { onFabMenuExpandedChange(false) }

FloatingActionButtonMenu(
expanded = fabMenuExpanded,
Expand All @@ -455,7 +455,7 @@ fun DetailFloatingActionButtonMenu(
alphaAnimationSpec = MaterialTheme.motionScheme.defaultEffectsSpec(),
),
checked = fabMenuExpanded,
onCheckedChange = { fabMenuExpanded = !fabMenuExpanded }
onCheckedChange = { onFabMenuExpandedChange(!fabMenuExpanded) }
) {
val imageVector by remember {
derivedStateOf {
Expand All @@ -469,12 +469,12 @@ fun DetailFloatingActionButtonMenu(
)
}
},
modifier = modifier,
modifier = modifier
) {
if (isSaved) {
FloatingActionButtonMenuItem(
onClick = {
fabMenuExpanded = false
onFabMenuExpandedChange(false)
removeFromSaved()
},
icon = { Icon(Icons.Default.BookmarkRemove, contentDescription = null) },
Expand All @@ -483,7 +483,7 @@ fun DetailFloatingActionButtonMenu(
} else {
FloatingActionButtonMenuItem(
onClick = {
fabMenuExpanded = false
onFabMenuExpandedChange(false)
addToSaved()
},
icon = { Icon(Icons.Default.Save, null) },
Expand All @@ -493,7 +493,7 @@ fun DetailFloatingActionButtonMenu(

FloatingActionButtonMenuItem(
onClick = {
fabMenuExpanded = false
onFabMenuExpandedChange(false)
onShowLists()
},
icon = { Icon(Icons.AutoMirrored.Filled.PlaylistAdd, contentDescription = null) },
Expand All @@ -502,7 +502,7 @@ fun DetailFloatingActionButtonMenu(

FloatingActionButtonMenuItem(
onClick = {
fabMenuExpanded = false
onFabMenuExpandedChange(false)
navController.navigate(Screen.GlobalSearchScreen(info.title))
},
icon = { Icon(Icons.Default.Search, contentDescription = null) },
Expand Down
Original file line number Diff line number Diff line change
@@ -1,11 +1,10 @@
@file:Suppress("INLINE_FROM_HIGHER_PLATFORM")

package com.programmersbox.uiviews.presentation.details

import android.graphics.Bitmap
import androidx.activity.compose.BackHandler
import androidx.compose.animation.ExperimentalAnimationApi
import androidx.compose.animation.animateContentSize
import androidx.compose.animation.core.animateDpAsState
import androidx.compose.foundation.ExperimentalFoundationApi
import androidx.compose.foundation.basicMarquee
import androidx.compose.foundation.combinedClickable
Expand Down Expand Up @@ -46,10 +45,12 @@ import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.compose.runtime.rememberCoroutineScope
import androidx.compose.runtime.saveable.rememberSaveable
import androidx.compose.runtime.setValue
import androidx.compose.ui.Alignment
import androidx.compose.ui.ExperimentalComposeUiApi
import androidx.compose.ui.Modifier
import androidx.compose.ui.draw.blur
import androidx.compose.ui.draw.rotate
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.graphics.painter.BitmapPainter
Expand Down Expand Up @@ -140,6 +141,8 @@ fun DetailsView(

val context = LocalContext.current

var fabMenuExpanded by rememberSaveable { mutableStateOf(false) }

BackHandler(scaffoldState.isOpen) {
scope.launch {
try {
Expand Down Expand Up @@ -189,13 +192,21 @@ fun DetailsView(
) {

val collapsableBehavior = rememberCollapsableTopBehavior(
enterAlways = false
enterAlways = false,
canScroll = { !fabMenuExpanded }
)

val fabBlur = Modifier.blur(
animateDpAsState(
if (fabMenuExpanded) 2.dp else 0.dp
).value
)

OtakuScaffold(
topBar = {
CollapsableColumn(
behavior = collapsableBehavior
behavior = collapsableBehavior,
modifier = fabBlur
) {
InsetSmallTopAppBar(
modifier = Modifier
Expand Down Expand Up @@ -244,7 +255,7 @@ fun DetailsView(
info.imageUrl,
info.source.serviceName
)
} ?: false
} == true

hostState.showSnackbar(
context.getString(
Expand Down Expand Up @@ -292,7 +303,7 @@ fun DetailsView(
onPaletteSet = onPaletteSet,
onBitmapSet = onBitmapSet,
blurHash = blurHash,
modifier = Modifier.collapse()
modifier = Modifier.collapse(),
)
}
},
Expand Down Expand Up @@ -337,6 +348,8 @@ fun DetailsView(
notifyAction = notifyAction,
isFavorite = isFavorite,
onFavoriteClick = onFavoriteClick,
fabMenuExpanded = fabMenuExpanded,
onFabMenuExpandedChange = { fabMenuExpanded = it },
modifier = Modifier.padding(LocalNavHostPadding.current)
)
},
Expand Down Expand Up @@ -370,6 +383,7 @@ fun DetailsView(
verticalArrangement = Arrangement.spacedBy(4.dp),
state = listState,
contentPadding = modifiedPaddingValues,
userScrollEnabled = !fabMenuExpanded,
modifier = Modifier
.fillMaxHeight()
.padding(vertical = 4.dp)
Expand All @@ -378,7 +392,8 @@ fun DetailsView(
it.hazeSource(hazeState)
else
it
},
}
.then(fabBlur),
) {
if (info.description.isNotEmpty()) {
item {
Expand Down Expand Up @@ -437,4 +452,4 @@ fun DetailsView(
}
}
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -130,6 +130,7 @@ class DetailsViewModel(
}
.onEach { blurHash = BitmapPainter(it) }
.onEach { if (palette == null) palette = Palette.from(it).generate() }
.dispatchIo()
.launchIn(viewModelScope)

combine(
Expand All @@ -145,6 +146,7 @@ class DetailsViewModel(
imageUrl = image
)
}
.dispatchIo()
.onEach {
if (it.blurHashItem == null && it.bitmap != null && it.isFavorite && it.imageUrl != null) {
blurHashDao.insertHash(
Expand All @@ -153,6 +155,8 @@ class DetailsViewModel(
BlurHash.encode(it.bitmap, 4, 3)
)
)
} else if (it.blurHashItem != null && !it.isFavorite) {
blurHashDao.deleteHash(it.blurHashItem)
}
}
.launchIn(viewModelScope)
Expand Down Expand Up @@ -232,17 +236,6 @@ class DetailsViewModel(
addRemoveFavoriteJob = viewModelScope.launch(Dispatchers.IO) {
favoritesRepository.addFavorite(db)
}

imageBitmap?.let {
viewModelScope.launch(Dispatchers.IO) {
blurHashDao.insertHash(
BlurHashItem(
action.info.imageUrl,
BlurHash.encode(it, 4, 3)
)
)
}
}
}

is DetailFavoriteAction.Remove -> {
Expand All @@ -251,10 +244,6 @@ class DetailsViewModel(
addRemoveFavoriteJob = viewModelScope.launch(Dispatchers.IO) {
favoritesRepository.removeFavorite(db)
}

viewModelScope.launch(Dispatchers.IO) {
blurHashItem?.let { blurHashDao.deleteHash(it) }
}
}
}
}
Expand Down

0 comments on commit 8641a59

Please sign in to comment.