Merge Wholphin v1.1.0 while preserving Wolfskin features #27
4 changed files with 397 additions and 725 deletions
|
|
@ -44,7 +44,6 @@ import com.github.damontecres.wholphin.ui.detail.CardGrid
|
||||||
import com.github.damontecres.wholphin.ui.detail.GridItemDetails
|
import com.github.damontecres.wholphin.ui.detail.GridItemDetails
|
||||||
import com.github.damontecres.wholphin.ui.ifElse
|
import com.github.damontecres.wholphin.ui.ifElse
|
||||||
import com.github.damontecres.wholphin.ui.main.HomePageHeader
|
import com.github.damontecres.wholphin.ui.main.HomePageHeader
|
||||||
import com.github.damontecres.wholphin.ui.playback.scale
|
|
||||||
import com.github.damontecres.wholphin.ui.util.ScrollToTopBringIntoViewSpec
|
import com.github.damontecres.wholphin.ui.util.ScrollToTopBringIntoViewSpec
|
||||||
import org.jellyfin.sdk.model.api.BaseItemKind
|
import org.jellyfin.sdk.model.api.BaseItemKind
|
||||||
import org.jellyfin.sdk.model.api.CollectionType
|
import org.jellyfin.sdk.model.api.CollectionType
|
||||||
|
|
@ -53,19 +52,18 @@ import kotlin.time.Duration
|
||||||
|
|
||||||
@OptIn(ExperimentalFoundationApi::class)
|
@OptIn(ExperimentalFoundationApi::class)
|
||||||
@Composable
|
@Composable
|
||||||
fun CollectionFolderGrid(
|
fun CollectionFolderViewScope.CollectionFolderGrid(
|
||||||
preferences: UserPreferences,
|
preferences: UserPreferences,
|
||||||
collectionType: CollectionType?,
|
|
||||||
focusedItem: BaseItem?,
|
focusedItem: BaseItem?,
|
||||||
items: List<BaseItem?>,
|
items: List<BaseItem?>,
|
||||||
sortAndDirection: SortAndDirection,
|
sortAndDirection: SortAndDirection,
|
||||||
onClickItem: (Int, BaseItem) -> Unit,
|
onClickItem: (Int, BaseItem) -> Unit,
|
||||||
onLongClickItem: (Int, BaseItem) -> Unit,
|
onLongClickItem: (Int, BaseItem) -> Unit,
|
||||||
letterPosition: suspend (Char) -> Int,
|
letterPosition: suspend (Char) -> Int,
|
||||||
viewOptions: ViewOptions,
|
|
||||||
onClickPlay: (Int, BaseItem) -> Unit,
|
onClickPlay: (Int, BaseItem) -> Unit,
|
||||||
initialPosition: Int,
|
initialPosition: Int,
|
||||||
gridFocusRequester: FocusRequester,
|
gridFocusRequester: FocusRequester,
|
||||||
|
cardContent: @Composable CollectionFolderViewScope.(GridItemDetails<BaseItem>) -> Unit,
|
||||||
modifier: Modifier = Modifier,
|
modifier: Modifier = Modifier,
|
||||||
positionCallback: ((columns: Int, position: Int) -> Unit)? = null,
|
positionCallback: ((columns: Int, position: Int) -> Unit)? = null,
|
||||||
) {
|
) {
|
||||||
|
|
@ -99,18 +97,8 @@ fun CollectionFolderGrid(
|
||||||
modifier = Modifier.fillMaxSize(),
|
modifier = Modifier.fillMaxSize(),
|
||||||
initialPosition = initialPosition,
|
initialPosition = initialPosition,
|
||||||
positionCallback = positionCallback,
|
positionCallback = positionCallback,
|
||||||
cardContent = { (item, index, onClick, onLongClick, widthPx, mod) ->
|
cardContent = { details ->
|
||||||
GridCard(
|
cardContent.invoke(this@CollectionFolderGrid, details)
|
||||||
item = item,
|
|
||||||
onClick = onClick,
|
|
||||||
onLongClick = onLongClick,
|
|
||||||
imageContentScale = viewOptions.contentScale.scale,
|
|
||||||
imageAspectRatio = viewOptions.aspectRatio.ratio,
|
|
||||||
imageType = viewOptions.imageType,
|
|
||||||
showTitle = viewOptions.showTitles,
|
|
||||||
fillWidth = widthPx,
|
|
||||||
modifier = mod,
|
|
||||||
)
|
|
||||||
},
|
},
|
||||||
columns = viewOptions.columns,
|
columns = viewOptions.columns,
|
||||||
spacing = viewOptions.spacing.dp,
|
spacing = viewOptions.spacing.dp,
|
||||||
|
|
|
||||||
|
|
@ -28,6 +28,7 @@ import androidx.compose.runtime.getValue
|
||||||
import androidx.compose.runtime.mutableStateOf
|
import androidx.compose.runtime.mutableStateOf
|
||||||
import androidx.compose.runtime.remember
|
import androidx.compose.runtime.remember
|
||||||
import androidx.compose.runtime.rememberCoroutineScope
|
import androidx.compose.runtime.rememberCoroutineScope
|
||||||
|
import androidx.compose.runtime.rememberUpdatedState
|
||||||
import androidx.compose.runtime.saveable.rememberSaveable
|
import androidx.compose.runtime.saveable.rememberSaveable
|
||||||
import androidx.compose.runtime.setValue
|
import androidx.compose.runtime.setValue
|
||||||
import androidx.compose.ui.Alignment
|
import androidx.compose.ui.Alignment
|
||||||
|
|
@ -59,6 +60,7 @@ import com.github.damontecres.wholphin.ui.cards.FavoriteIndicator
|
||||||
import com.github.damontecres.wholphin.ui.cards.WatchedIcon
|
import com.github.damontecres.wholphin.ui.cards.WatchedIcon
|
||||||
import com.github.damontecres.wholphin.ui.data.SortAndDirection
|
import com.github.damontecres.wholphin.ui.data.SortAndDirection
|
||||||
import com.github.damontecres.wholphin.ui.detail.AlphabetButtons
|
import com.github.damontecres.wholphin.ui.detail.AlphabetButtons
|
||||||
|
import com.github.damontecres.wholphin.ui.detail.GridItemDetails
|
||||||
import com.github.damontecres.wholphin.ui.enableMarquee
|
import com.github.damontecres.wholphin.ui.enableMarquee
|
||||||
import com.github.damontecres.wholphin.ui.formatDuration
|
import com.github.damontecres.wholphin.ui.formatDuration
|
||||||
import com.github.damontecres.wholphin.ui.ifElse
|
import com.github.damontecres.wholphin.ui.ifElse
|
||||||
|
|
@ -75,7 +77,7 @@ import org.jellyfin.sdk.model.api.ItemSortBy
|
||||||
import org.jellyfin.sdk.model.extensions.ticks
|
import org.jellyfin.sdk.model.extensions.ticks
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
fun CollectionFolderList(
|
fun CollectionFolderViewScope.CollectionFolderList(
|
||||||
preferences: UserPreferences,
|
preferences: UserPreferences,
|
||||||
collectionType: CollectionType?,
|
collectionType: CollectionType?,
|
||||||
focusedItem: BaseItem?,
|
focusedItem: BaseItem?,
|
||||||
|
|
@ -84,10 +86,10 @@ fun CollectionFolderList(
|
||||||
onClickItem: (Int, BaseItem) -> Unit,
|
onClickItem: (Int, BaseItem) -> Unit,
|
||||||
onLongClickItem: (Int, BaseItem) -> Unit,
|
onLongClickItem: (Int, BaseItem) -> Unit,
|
||||||
letterPosition: suspend (Char) -> Int,
|
letterPosition: suspend (Char) -> Int,
|
||||||
viewOptions: ViewOptions,
|
|
||||||
onClickPlay: (Int, BaseItem) -> Unit,
|
onClickPlay: (Int, BaseItem) -> Unit,
|
||||||
initialPosition: Int,
|
initialPosition: Int,
|
||||||
gridFocusRequester: FocusRequester,
|
gridFocusRequester: FocusRequester,
|
||||||
|
itemContent: @Composable CollectionFolderViewScope.(GridItemDetails<BaseItem>) -> Unit,
|
||||||
modifier: Modifier = Modifier,
|
modifier: Modifier = Modifier,
|
||||||
positionCallback: ((columns: Int, position: Int) -> Unit)? = null,
|
positionCallback: ((columns: Int, position: Int) -> Unit)? = null,
|
||||||
) {
|
) {
|
||||||
|
|
@ -153,10 +155,8 @@ fun CollectionFolderList(
|
||||||
).padding(8.dp),
|
).padding(8.dp),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
CollectionFolderContent(
|
this@CollectionFolderList.CollectionFolderListContent(
|
||||||
items = items,
|
items = items,
|
||||||
viewOptions = viewOptions,
|
|
||||||
collectionType = collectionType,
|
|
||||||
listState = listState,
|
listState = listState,
|
||||||
position = position,
|
position = position,
|
||||||
positionFocusRequester = positionFocusRequester,
|
positionFocusRequester = positionFocusRequester,
|
||||||
|
|
@ -167,6 +167,7 @@ fun CollectionFolderList(
|
||||||
},
|
},
|
||||||
onClickItem = onClickItem,
|
onClickItem = onClickItem,
|
||||||
onLongClickItem = onLongClickItem,
|
onLongClickItem = onLongClickItem,
|
||||||
|
itemContent = itemContent,
|
||||||
modifier =
|
modifier =
|
||||||
Modifier
|
Modifier
|
||||||
.weight(1f)
|
.weight(1f)
|
||||||
|
|
@ -266,45 +267,44 @@ fun CollectionFolderListDetails(
|
||||||
}
|
}
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
fun CollectionFolderContent(
|
fun CollectionFolderViewScope.CollectionFolderListContent(
|
||||||
items: List<BaseItem?>,
|
items: List<BaseItem?>,
|
||||||
viewOptions: ViewOptions,
|
|
||||||
collectionType: CollectionType?,
|
|
||||||
listState: LazyListState,
|
listState: LazyListState,
|
||||||
position: Int,
|
position: Int,
|
||||||
positionFocusRequester: FocusRequester,
|
positionFocusRequester: FocusRequester,
|
||||||
onClickItem: (Int, BaseItem) -> Unit,
|
onClickItem: (Int, BaseItem) -> Unit,
|
||||||
onLongClickItem: (Int, BaseItem) -> Unit,
|
onLongClickItem: (Int, BaseItem) -> Unit,
|
||||||
onPositionChange: (Int) -> Unit,
|
onPositionChange: (Int) -> Unit,
|
||||||
|
itemContent: @Composable CollectionFolderViewScope.(GridItemDetails<BaseItem>) -> Unit,
|
||||||
modifier: Modifier = Modifier,
|
modifier: Modifier = Modifier,
|
||||||
) {
|
) {
|
||||||
|
val currentPosition by rememberUpdatedState(position)
|
||||||
LazyColumn(
|
LazyColumn(
|
||||||
state = listState,
|
state = listState,
|
||||||
verticalArrangement = Arrangement.spacedBy(viewOptions.spacing.dp),
|
verticalArrangement = Arrangement.spacedBy(viewOptions.spacing.dp),
|
||||||
modifier = modifier.focusRestorer(positionFocusRequester),
|
modifier = modifier.focusRestorer(positionFocusRequester),
|
||||||
) {
|
) {
|
||||||
itemsIndexed(items) { index, item ->
|
itemsIndexed(items) { index, item ->
|
||||||
val onClick: () -> Unit =
|
val details =
|
||||||
remember(index, item) {
|
remember(item, index, onClickItem, onLongClickItem, onPositionChange) {
|
||||||
{ item?.let { onClickItem.invoke(index, item) } }
|
GridItemDetails(
|
||||||
}
|
|
||||||
val onLongClick: () -> Unit =
|
|
||||||
remember(index, item) {
|
|
||||||
{ item?.let { onLongClickItem.invoke(index, item) } }
|
|
||||||
}
|
|
||||||
CollectionFolderListItem(
|
|
||||||
item = item,
|
item = item,
|
||||||
dense = viewOptions.type == ViewOptionsType.DENSE_LIST,
|
index = index,
|
||||||
collectionType = collectionType,
|
onClick = { item?.let { onClickItem.invoke(index, item) } },
|
||||||
onClick = onClick,
|
onLongClick = { item?.let { onLongClickItem.invoke(index, item) } },
|
||||||
onLongClick = onLongClick,
|
widthPx = -1,
|
||||||
modifier =
|
mod =
|
||||||
Modifier
|
Modifier
|
||||||
.onFocusChanged {
|
.onFocusChanged {
|
||||||
if (it.isFocused) onPositionChange.invoke(index)
|
if (it.isFocused) onPositionChange.invoke(index)
|
||||||
}.ifElse(index == position, Modifier.focusRequester(positionFocusRequester)),
|
}.ifElse(
|
||||||
|
index == currentPosition,
|
||||||
|
Modifier.focusRequester(positionFocusRequester),
|
||||||
|
),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
itemContent.invoke(this@CollectionFolderListContent, details)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -54,12 +54,15 @@ import com.github.damontecres.wholphin.services.ThemeSongPlayer
|
||||||
import com.github.damontecres.wholphin.services.UserPreferencesService
|
import com.github.damontecres.wholphin.services.UserPreferencesService
|
||||||
import com.github.damontecres.wholphin.services.deleteItem
|
import com.github.damontecres.wholphin.services.deleteItem
|
||||||
import com.github.damontecres.wholphin.ui.SlimItemFields
|
import com.github.damontecres.wholphin.ui.SlimItemFields
|
||||||
|
import com.github.damontecres.wholphin.ui.cards.GridCard
|
||||||
import com.github.damontecres.wholphin.ui.data.SortAndDirection
|
import com.github.damontecres.wholphin.ui.data.SortAndDirection
|
||||||
|
import com.github.damontecres.wholphin.ui.detail.GridItemDetails
|
||||||
import com.github.damontecres.wholphin.ui.detail.music.addToQueue
|
import com.github.damontecres.wholphin.ui.detail.music.addToQueue
|
||||||
import com.github.damontecres.wholphin.ui.equalsNotNull
|
import com.github.damontecres.wholphin.ui.equalsNotNull
|
||||||
import com.github.damontecres.wholphin.ui.launchDefault
|
import com.github.damontecres.wholphin.ui.launchDefault
|
||||||
import com.github.damontecres.wholphin.ui.launchIO
|
import com.github.damontecres.wholphin.ui.launchIO
|
||||||
import com.github.damontecres.wholphin.ui.nav.Destination
|
import com.github.damontecres.wholphin.ui.nav.Destination
|
||||||
|
import com.github.damontecres.wholphin.ui.playback.scale
|
||||||
import com.github.damontecres.wholphin.ui.rememberInt
|
import com.github.damontecres.wholphin.ui.rememberInt
|
||||||
import com.github.damontecres.wholphin.ui.showToast
|
import com.github.damontecres.wholphin.ui.showToast
|
||||||
import com.github.damontecres.wholphin.ui.toServerString
|
import com.github.damontecres.wholphin.ui.toServerString
|
||||||
|
|
@ -843,6 +846,33 @@ fun CollectionFolderViewContent(
|
||||||
positionCallback: ((columns: Int, position: Int) -> Unit)? = null,
|
positionCallback: ((columns: Int, position: Int) -> Unit)? = null,
|
||||||
filterOptions: List<ItemFilterBy<*>> = DefaultFilterOptions,
|
filterOptions: List<ItemFilterBy<*>> = DefaultFilterOptions,
|
||||||
focusRequesterOnEmpty: FocusRequester? = null,
|
focusRequesterOnEmpty: FocusRequester? = null,
|
||||||
|
gridCardContent: @Composable CollectionFolderViewScope.(
|
||||||
|
GridItemDetails<BaseItem>,
|
||||||
|
) -> Unit = { (item, index, onClick, onLongClick, widthPx, mod) ->
|
||||||
|
GridCard(
|
||||||
|
item = item,
|
||||||
|
onClick = onClick,
|
||||||
|
onLongClick = onLongClick,
|
||||||
|
imageContentScale = viewOptions.contentScale.scale,
|
||||||
|
imageAspectRatio = viewOptions.aspectRatio.ratio,
|
||||||
|
imageType = viewOptions.imageType,
|
||||||
|
showTitle = viewOptions.showTitles,
|
||||||
|
fillWidth = widthPx,
|
||||||
|
modifier = mod,
|
||||||
|
)
|
||||||
|
},
|
||||||
|
listItemContent: @Composable CollectionFolderViewScope.(
|
||||||
|
GridItemDetails<BaseItem>,
|
||||||
|
) -> Unit = { (item, index, onClick, onLongClick, _, mod) ->
|
||||||
|
CollectionFolderListItem(
|
||||||
|
item = item,
|
||||||
|
dense = viewOptions.type == ViewOptionsType.DENSE_LIST,
|
||||||
|
collectionType = collectionType,
|
||||||
|
onClick = onClick,
|
||||||
|
onLongClick = onLongClick,
|
||||||
|
modifier = mod,
|
||||||
|
)
|
||||||
|
},
|
||||||
) {
|
) {
|
||||||
var position by rememberInt(savedPosition)
|
var position by rememberInt(savedPosition)
|
||||||
|
|
||||||
|
|
@ -1005,11 +1035,22 @@ fun CollectionFolderViewContent(
|
||||||
focusRequester?.tryRequestFocus()
|
focusRequester?.tryRequestFocus()
|
||||||
clickedRandom = false
|
clickedRandom = false
|
||||||
}
|
}
|
||||||
|
val scope =
|
||||||
|
object : CollectionFolderViewScope {
|
||||||
|
override val viewOptions: ViewOptions
|
||||||
|
get() = state.viewOptions
|
||||||
|
override val collectionType: CollectionType?
|
||||||
|
get() = item?.data?.collectionType
|
||||||
|
override val sortAndDirection: SortAndDirection
|
||||||
|
get() = state.sortAndDirection
|
||||||
|
override val collectionSize: Int
|
||||||
|
get() = pager.data.size
|
||||||
|
}
|
||||||
|
|
||||||
Box(Modifier.fillMaxSize()) {
|
Box(Modifier.fillMaxSize()) {
|
||||||
if (state.viewOptions.type == ViewOptionsType.GRID) {
|
if (state.viewOptions.type == ViewOptionsType.GRID) {
|
||||||
CollectionFolderGrid(
|
scope.CollectionFolderGrid(
|
||||||
preferences = preferences,
|
preferences = preferences,
|
||||||
collectionType = item?.data?.collectionType,
|
|
||||||
initialPosition = savedPosition,
|
initialPosition = savedPosition,
|
||||||
items = pager.data,
|
items = pager.data,
|
||||||
sortAndDirection = state.sortAndDirection,
|
sortAndDirection = state.sortAndDirection,
|
||||||
|
|
@ -1023,12 +1064,12 @@ fun CollectionFolderViewContent(
|
||||||
positionCallback?.invoke(columns, pos)
|
positionCallback?.invoke(columns, pos)
|
||||||
},
|
},
|
||||||
letterPosition = { viewActions.positionOfLetter(it) ?: -1 },
|
letterPosition = { viewActions.positionOfLetter(it) ?: -1 },
|
||||||
viewOptions = state.viewOptions,
|
|
||||||
onClickPlay = gridActions.onClickPlayRemoteButton!!,
|
onClickPlay = gridActions.onClickPlayRemoteButton!!,
|
||||||
focusedItem = focusedItem,
|
focusedItem = focusedItem,
|
||||||
|
cardContent = gridCardContent,
|
||||||
)
|
)
|
||||||
} else {
|
} else {
|
||||||
CollectionFolderList(
|
scope.CollectionFolderList(
|
||||||
preferences = preferences,
|
preferences = preferences,
|
||||||
collectionType = item?.data?.collectionType,
|
collectionType = item?.data?.collectionType,
|
||||||
initialPosition = savedPosition,
|
initialPosition = savedPosition,
|
||||||
|
|
@ -1044,9 +1085,9 @@ fun CollectionFolderViewContent(
|
||||||
positionCallback?.invoke(columns, pos)
|
positionCallback?.invoke(columns, pos)
|
||||||
},
|
},
|
||||||
letterPosition = { viewActions.positionOfLetter(it) ?: -1 },
|
letterPosition = { viewActions.positionOfLetter(it) ?: -1 },
|
||||||
viewOptions = state.viewOptions,
|
|
||||||
onClickPlay = gridActions.onClickPlayRemoteButton!!,
|
onClickPlay = gridActions.onClickPlayRemoteButton!!,
|
||||||
focusedItem = focusedItem,
|
focusedItem = focusedItem,
|
||||||
|
itemContent = listItemContent,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
androidx.compose.animation.AnimatedVisibility(
|
androidx.compose.animation.AnimatedVisibility(
|
||||||
|
|
@ -1085,3 +1126,13 @@ fun CollectionFolderViewContent(
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Scope with global data for [CollectionFolderView], [CollectionFolderGrid], [CollectionFolderList], and individual items
|
||||||
|
*/
|
||||||
|
interface CollectionFolderViewScope {
|
||||||
|
val viewOptions: ViewOptions
|
||||||
|
val collectionType: CollectionType?
|
||||||
|
val sortAndDirection: SortAndDirection
|
||||||
|
val collectionSize: Int
|
||||||
|
}
|
||||||
|
|
|
||||||
File diff suppressed because it is too large
Load diff
Loading…
Add table
Add a link
Reference in a new issue