mirror of
https://github.com/JustinZeus/Wholphin.git
synced 2026-07-08 15:50:16 +02:00
Fix cut off cards on grids with show details enabled (#963)
## Description Fixes the previous row of cards showing the bottom cut off when the "Show details" view option is enabled. ### Related issues Fixes #404 Fixes #877 Related to #882 ### Testing Emulator ## Screenshots  ## AI or LLM usage None
This commit is contained in:
parent
3b162a2f98
commit
348a3022d6
2 changed files with 104 additions and 82 deletions
|
|
@ -6,7 +6,9 @@ import androidx.compose.animation.fadeIn
|
||||||
import androidx.compose.animation.fadeOut
|
import androidx.compose.animation.fadeOut
|
||||||
import androidx.compose.animation.slideInVertically
|
import androidx.compose.animation.slideInVertically
|
||||||
import androidx.compose.animation.slideOutVertically
|
import androidx.compose.animation.slideOutVertically
|
||||||
|
import androidx.compose.foundation.ExperimentalFoundationApi
|
||||||
import androidx.compose.foundation.background
|
import androidx.compose.foundation.background
|
||||||
|
import androidx.compose.foundation.gestures.LocalBringIntoViewSpec
|
||||||
import androidx.compose.foundation.layout.Arrangement
|
import androidx.compose.foundation.layout.Arrangement
|
||||||
import androidx.compose.foundation.layout.Box
|
import androidx.compose.foundation.layout.Box
|
||||||
import androidx.compose.foundation.layout.Column
|
import androidx.compose.foundation.layout.Column
|
||||||
|
|
@ -33,6 +35,7 @@ import androidx.compose.ui.focus.FocusRequester
|
||||||
import androidx.compose.ui.focus.focusRequester
|
import androidx.compose.ui.focus.focusRequester
|
||||||
import androidx.compose.ui.layout.ContentScale
|
import androidx.compose.ui.layout.ContentScale
|
||||||
import androidx.compose.ui.platform.LocalContext
|
import androidx.compose.ui.platform.LocalContext
|
||||||
|
import androidx.compose.ui.platform.LocalDensity
|
||||||
import androidx.compose.ui.res.stringResource
|
import androidx.compose.ui.res.stringResource
|
||||||
import androidx.compose.ui.text.style.TextAlign
|
import androidx.compose.ui.text.style.TextAlign
|
||||||
import androidx.compose.ui.text.style.TextOverflow
|
import androidx.compose.ui.text.style.TextOverflow
|
||||||
|
|
@ -84,6 +87,7 @@ import com.github.damontecres.wholphin.ui.setValueOnMain
|
||||||
import com.github.damontecres.wholphin.ui.toServerString
|
import com.github.damontecres.wholphin.ui.toServerString
|
||||||
import com.github.damontecres.wholphin.ui.tryRequestFocus
|
import com.github.damontecres.wholphin.ui.tryRequestFocus
|
||||||
import com.github.damontecres.wholphin.ui.util.FilterUtils
|
import com.github.damontecres.wholphin.ui.util.FilterUtils
|
||||||
|
import com.github.damontecres.wholphin.ui.util.ScrollToTopBringIntoViewSpec
|
||||||
import com.github.damontecres.wholphin.util.ApiRequestPager
|
import com.github.damontecres.wholphin.util.ApiRequestPager
|
||||||
import com.github.damontecres.wholphin.util.DataLoadingState
|
import com.github.damontecres.wholphin.util.DataLoadingState
|
||||||
import com.github.damontecres.wholphin.util.ExceptionHandler
|
import com.github.damontecres.wholphin.util.ExceptionHandler
|
||||||
|
|
@ -735,6 +739,7 @@ fun CollectionFolderGrid(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@OptIn(ExperimentalFoundationApi::class)
|
||||||
@Composable
|
@Composable
|
||||||
fun CollectionFolderGridContent(
|
fun CollectionFolderGridContent(
|
||||||
preferences: UserPreferences,
|
preferences: UserPreferences,
|
||||||
|
|
@ -879,14 +884,16 @@ fun CollectionFolderGridContent(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
val defaultBringIntoViewSpec = LocalBringIntoViewSpec.current
|
||||||
|
val density = LocalDensity.current
|
||||||
AnimatedVisibility(viewOptions.showDetails) {
|
AnimatedVisibility(viewOptions.showDetails) {
|
||||||
HomePageHeader(
|
HomePageHeader(
|
||||||
item = focusedItem,
|
item = focusedItem,
|
||||||
modifier =
|
modifier =
|
||||||
Modifier
|
Modifier
|
||||||
.fillMaxWidth()
|
.fillMaxWidth()
|
||||||
.height(140.dp)
|
.height(200.dp)
|
||||||
.padding(16.dp),
|
.padding(top = 48.dp, bottom = 32.dp, start = 8.dp),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
when (val state = loadingState) {
|
when (val state = loadingState) {
|
||||||
|
|
@ -932,6 +939,15 @@ fun CollectionFolderGridContent(
|
||||||
},
|
},
|
||||||
columns = viewOptions.columns,
|
columns = viewOptions.columns,
|
||||||
spacing = viewOptions.spacing.dp,
|
spacing = viewOptions.spacing.dp,
|
||||||
|
bringIntoViewSpec =
|
||||||
|
remember(viewOptions) {
|
||||||
|
val spacingPx = with(density) { viewOptions.spacing.dp.toPx() }
|
||||||
|
if (viewOptions.showDetails) {
|
||||||
|
ScrollToTopBringIntoViewSpec(spacingPx)
|
||||||
|
} else {
|
||||||
|
defaultBringIntoViewSpec
|
||||||
|
}
|
||||||
|
},
|
||||||
)
|
)
|
||||||
AnimatedVisibility(showViewOptions) {
|
AnimatedVisibility(showViewOptions) {
|
||||||
ViewOptionsDialog(
|
ViewOptionsDialog(
|
||||||
|
|
|
||||||
|
|
@ -4,6 +4,8 @@ import androidx.annotation.StringRes
|
||||||
import androidx.compose.foundation.ExperimentalFoundationApi
|
import androidx.compose.foundation.ExperimentalFoundationApi
|
||||||
import androidx.compose.foundation.background
|
import androidx.compose.foundation.background
|
||||||
import androidx.compose.foundation.focusGroup
|
import androidx.compose.foundation.focusGroup
|
||||||
|
import androidx.compose.foundation.gestures.BringIntoViewSpec
|
||||||
|
import androidx.compose.foundation.gestures.LocalBringIntoViewSpec
|
||||||
import androidx.compose.foundation.interaction.MutableInteractionSource
|
import androidx.compose.foundation.interaction.MutableInteractionSource
|
||||||
import androidx.compose.foundation.interaction.collectIsFocusedAsState
|
import androidx.compose.foundation.interaction.collectIsFocusedAsState
|
||||||
import androidx.compose.foundation.layout.Arrangement
|
import androidx.compose.foundation.layout.Arrangement
|
||||||
|
|
@ -24,6 +26,7 @@ import androidx.compose.foundation.lazy.layout.LazyLayoutCacheWindow
|
||||||
import androidx.compose.foundation.lazy.rememberLazyListState
|
import androidx.compose.foundation.lazy.rememberLazyListState
|
||||||
import androidx.compose.foundation.shape.CircleShape
|
import androidx.compose.foundation.shape.CircleShape
|
||||||
import androidx.compose.runtime.Composable
|
import androidx.compose.runtime.Composable
|
||||||
|
import androidx.compose.runtime.CompositionLocalProvider
|
||||||
import androidx.compose.runtime.LaunchedEffect
|
import androidx.compose.runtime.LaunchedEffect
|
||||||
import androidx.compose.runtime.getValue
|
import androidx.compose.runtime.getValue
|
||||||
import androidx.compose.runtime.mutableIntStateOf
|
import androidx.compose.runtime.mutableIntStateOf
|
||||||
|
|
@ -112,6 +115,7 @@ fun <T : CardGridItem> CardGrid(
|
||||||
},
|
},
|
||||||
columns: Int = 6,
|
columns: Int = 6,
|
||||||
spacing: Dp = 16.dp,
|
spacing: Dp = 16.dp,
|
||||||
|
bringIntoViewSpec: BringIntoViewSpec = LocalBringIntoViewSpec.current,
|
||||||
) {
|
) {
|
||||||
val startPosition = initialPosition.coerceIn(0, (pager.size - 1).coerceAtLeast(0))
|
val startPosition = initialPosition.coerceIn(0, (pager.size - 1).coerceAtLeast(0))
|
||||||
|
|
||||||
|
|
@ -269,100 +273,102 @@ fun <T : CardGridItem> CardGrid(
|
||||||
Box(
|
Box(
|
||||||
modifier = Modifier.weight(1f),
|
modifier = Modifier.weight(1f),
|
||||||
) {
|
) {
|
||||||
LazyVerticalGrid(
|
CompositionLocalProvider(LocalBringIntoViewSpec provides bringIntoViewSpec) {
|
||||||
columns = GridCells.Fixed(columns),
|
LazyVerticalGrid(
|
||||||
horizontalArrangement = Arrangement.spacedBy(spacing),
|
columns = GridCells.Fixed(columns),
|
||||||
verticalArrangement = Arrangement.spacedBy(spacing),
|
horizontalArrangement = Arrangement.spacedBy(spacing),
|
||||||
state = gridState,
|
verticalArrangement = Arrangement.spacedBy(spacing),
|
||||||
contentPadding = PaddingValues(vertical = 16.dp),
|
state = gridState,
|
||||||
modifier =
|
contentPadding = PaddingValues(vertical = 16.dp),
|
||||||
Modifier
|
modifier =
|
||||||
.fillMaxSize()
|
Modifier
|
||||||
.focusGroup()
|
.fillMaxSize()
|
||||||
.focusRestorer(firstFocus)
|
.focusGroup()
|
||||||
.focusProperties {
|
.focusRestorer(firstFocus)
|
||||||
onExit = {
|
.focusProperties {
|
||||||
// Leaving the grid, so "forget" the position
|
onExit = {
|
||||||
|
// Leaving the grid, so "forget" the position
|
||||||
// focusedIndex = -1
|
// focusedIndex = -1
|
||||||
}
|
|
||||||
onEnter = {
|
|
||||||
if (focusedIndex < 0 && gridState.firstVisibleItemIndex <= startPosition) {
|
|
||||||
focusedIndex = startPosition
|
|
||||||
}
|
}
|
||||||
}
|
onEnter = {
|
||||||
},
|
if (focusedIndex < 0 && gridState.firstVisibleItemIndex <= startPosition) {
|
||||||
) {
|
focusedIndex = startPosition
|
||||||
items(pager.size) { index ->
|
}
|
||||||
val mod =
|
|
||||||
if ((index == focusedIndex) or (focusedIndex < 0 && index == 0)) {
|
|
||||||
if (DEBUG) Timber.d("Adding firstFocus to focusedIndex $index")
|
|
||||||
Modifier
|
|
||||||
.focusRequester(firstFocus)
|
|
||||||
.focusRequester(gridFocusRequester)
|
|
||||||
.focusRequester(alphabetFocusRequester)
|
|
||||||
} else {
|
|
||||||
Modifier
|
|
||||||
}
|
|
||||||
val item = pager[index]
|
|
||||||
cardContent(
|
|
||||||
item,
|
|
||||||
{
|
|
||||||
if (item != null) {
|
|
||||||
focusedIndex = index
|
|
||||||
onClickItem.invoke(index, item)
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{ if (item != null) onLongClickItem.invoke(index, item) },
|
|
||||||
mod
|
|
||||||
.ifElse(index == 0, Modifier.focusRequester(zeroFocus))
|
|
||||||
.onFocusChanged { focusState ->
|
|
||||||
if (DEBUG) {
|
|
||||||
Timber.v(
|
|
||||||
"$index isFocused=${focusState.isFocused}",
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
if (focusState.isFocused) {
|
},
|
||||||
// Focused, so set that up
|
) {
|
||||||
focusOn(index)
|
items(pager.size) { index ->
|
||||||
positionCallback?.invoke(columns, index)
|
val mod =
|
||||||
} else if (focusedIndex == index) {
|
if ((index == focusedIndex) or (focusedIndex < 0 && index == 0)) {
|
||||||
|
if (DEBUG) Timber.d("Adding firstFocus to focusedIndex $index")
|
||||||
|
Modifier
|
||||||
|
.focusRequester(firstFocus)
|
||||||
|
.focusRequester(gridFocusRequester)
|
||||||
|
.focusRequester(alphabetFocusRequester)
|
||||||
|
} else {
|
||||||
|
Modifier
|
||||||
|
}
|
||||||
|
val item = pager[index]
|
||||||
|
cardContent(
|
||||||
|
item,
|
||||||
|
{
|
||||||
|
if (item != null) {
|
||||||
|
focusedIndex = index
|
||||||
|
onClickItem.invoke(index, item)
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{ if (item != null) onLongClickItem.invoke(index, item) },
|
||||||
|
mod
|
||||||
|
.ifElse(index == 0, Modifier.focusRequester(zeroFocus))
|
||||||
|
.onFocusChanged { focusState ->
|
||||||
|
if (DEBUG) {
|
||||||
|
Timber.v(
|
||||||
|
"$index isFocused=${focusState.isFocused}",
|
||||||
|
)
|
||||||
|
}
|
||||||
|
if (focusState.isFocused) {
|
||||||
|
// Focused, so set that up
|
||||||
|
focusOn(index)
|
||||||
|
positionCallback?.invoke(columns, index)
|
||||||
|
} else if (focusedIndex == index) {
|
||||||
// savedFocusedIndex = index
|
// savedFocusedIndex = index
|
||||||
// // Was focused on this, so mark unfocused
|
// // Was focused on this, so mark unfocused
|
||||||
// focusedIndex = -1
|
// focusedIndex = -1
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
if (pager.isEmpty()) {
|
||||||
if (pager.isEmpty()) {
|
|
||||||
// focusedIndex = -1
|
// focusedIndex = -1
|
||||||
Box(modifier = Modifier.fillMaxSize()) {
|
Box(modifier = Modifier.fillMaxSize()) {
|
||||||
Text(
|
Text(
|
||||||
text = stringResource(R.string.no_results),
|
text = stringResource(R.string.no_results),
|
||||||
color = MaterialTheme.colorScheme.onBackground,
|
color = MaterialTheme.colorScheme.onBackground,
|
||||||
modifier = Modifier.align(Alignment.Center),
|
modifier = Modifier.align(Alignment.Center),
|
||||||
)
|
)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
if (showFooter) {
|
||||||
if (showFooter) {
|
// Footer
|
||||||
// Footer
|
Box(
|
||||||
Box(
|
modifier =
|
||||||
modifier =
|
Modifier
|
||||||
Modifier
|
.align(Alignment.BottomCenter)
|
||||||
.align(Alignment.BottomCenter)
|
.background(AppColors.TransparentBlack50),
|
||||||
.background(AppColors.TransparentBlack50),
|
) {
|
||||||
) {
|
val index = (focusedIndex + 1).takeIf { it > 0 } ?: "?"
|
||||||
val index = (focusedIndex + 1).takeIf { it > 0 } ?: "?"
|
|
||||||
// if (focusedIndex >= 0) {
|
// if (focusedIndex >= 0) {
|
||||||
// focusedIndex + 1
|
// focusedIndex + 1
|
||||||
// } else {
|
// } else {
|
||||||
// max(savedFocusedIndex, focusedIndexOnExit) + 1
|
// max(savedFocusedIndex, focusedIndexOnExit) + 1
|
||||||
// }
|
// }
|
||||||
Text(
|
Text(
|
||||||
modifier = Modifier.padding(4.dp),
|
modifier = Modifier.padding(4.dp),
|
||||||
color = MaterialTheme.colorScheme.onBackground,
|
color = MaterialTheme.colorScheme.onBackground,
|
||||||
text = "$index / ${pager.size}",
|
text = "$index / ${pager.size}",
|
||||||
)
|
)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue