Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -1,7 +1,30 @@
package com.paulcoding.hviewer.extensions

import androidx.compose.foundation.lazy.LazyListState
import androidx.compose.runtime.Composable
import androidx.compose.runtime.State
import androidx.compose.runtime.produceState
import androidx.compose.runtime.snapshotFlow

fun LazyListState.isScrolledToEnd(): Boolean {
return layoutInfo.visibleItemsInfo.lastOrNull()?.index == layoutInfo.totalItemsCount - 1
}

@Composable
fun LazyListState.isScrollingUp(): State<Boolean> {
return produceState(initialValue = true) {
var previousIndex = firstVisibleItemIndex
var previousOffset = firstVisibleItemScrollOffset

snapshotFlow { firstVisibleItemIndex to firstVisibleItemScrollOffset }
.collect { (index, offset) ->
value = if (index != previousIndex) {
index < previousIndex
} else {
offset < previousOffset
}
previousIndex = index
previousOffset = offset
}
}
}
43 changes: 43 additions & 0 deletions app/src/main/java/com/paulcoding/hviewer/ui/component/HGoTop.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
package com.paulcoding.hviewer.ui.component

import androidx.compose.animation.AnimatedVisibility
import androidx.compose.foundation.layout.BoxScope
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.lazy.LazyListState
import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.outlined.KeyboardArrowUp
import androidx.compose.material3.FloatingActionButton
import androidx.compose.material3.Icon
import androidx.compose.runtime.Composable
import androidx.compose.runtime.rememberCoroutineScope
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.unit.dp
import com.paulcoding.hviewer.extensions.isScrollingUp
import com.paulcoding.hviewer.ui.page.fadeInWithBlur
import com.paulcoding.hviewer.ui.page.fadeOutWithBlur
import kotlinx.coroutines.launch

@Composable
fun BoxScope.HGoTop(listState: LazyListState) {
val scope = rememberCoroutineScope()

AnimatedVisibility(
listState.isScrollingUp().value,
modifier = Modifier
.align(Alignment.BottomEnd)
.padding(16.dp),
enter = fadeInWithBlur(),
exit = fadeOutWithBlur(),
) {
FloatingActionButton(
onClick = {
scope.launch {
listState.animateScrollToItem(0, 0)
}
},
) {
Icon(Icons.Outlined.KeyboardArrowUp, "Go to Top")
}
}
}
52 changes: 5 additions & 47 deletions app/src/main/java/com/paulcoding/hviewer/ui/page/post/PostPage.kt
Original file line number Diff line number Diff line change
@@ -1,29 +1,23 @@
package com.paulcoding.hviewer.ui.page.post

import android.widget.Toast
import androidx.compose.animation.AnimatedVisibility
import androidx.compose.foundation.clickable
import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.lazy.LazyColumn
import androidx.compose.foundation.lazy.items
import androidx.compose.foundation.lazy.rememberLazyListState
import androidx.compose.foundation.shape.RoundedCornerShape
import androidx.compose.material3.ExperimentalMaterial3Api
import androidx.compose.material3.Scaffold
import androidx.compose.material3.Surface
import androidx.compose.material3.TopAppBar
import androidx.compose.runtime.Composable
import androidx.compose.runtime.LaunchedEffect
import androidx.compose.runtime.collectAsState
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.compose.runtime.setValue
import androidx.compose.runtime.snapshotFlow
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.unit.dp
Expand All @@ -34,19 +28,16 @@ import coil3.compose.AsyncImage
import com.paulcoding.hviewer.MainApp.Companion.appContext
import com.paulcoding.hviewer.extensions.isScrolledToEnd
import com.paulcoding.hviewer.helper.makeToast
import com.paulcoding.hviewer.model.SiteConfig
import com.paulcoding.hviewer.ui.component.HBackIcon
import com.paulcoding.hviewer.ui.component.HGoTop
import com.paulcoding.hviewer.ui.component.HImage
import com.paulcoding.hviewer.ui.component.HLoading
import com.paulcoding.hviewer.ui.component.HPageProgress
import com.paulcoding.hviewer.ui.component.HideSystemBars
import com.paulcoding.hviewer.ui.page.AppViewModel
import me.saket.telephoto.zoomable.DoubleClickToZoomListener
import me.saket.telephoto.zoomable.ZoomSpec
import me.saket.telephoto.zoomable.rememberZoomableState
import me.saket.telephoto.zoomable.zoomable

@OptIn(ExperimentalMaterial3Api::class)
@Composable
fun PostPage(appViewModel: AppViewModel, goBack: () -> Unit) {
val appState by appViewModel.stateFlow.collectAsState()
Expand Down Expand Up @@ -75,47 +66,11 @@ fun PostPage(appViewModel: AppViewModel, goBack: () -> Unit) {
}
}

var isScrollingUp by remember { mutableStateOf(false) }

// Detect scroll direction
LaunchedEffect(listState) {
var previousIndex = listState.firstVisibleItemIndex
var previousOffset = listState.firstVisibleItemScrollOffset

snapshotFlow { listState.firstVisibleItemIndex to listState.firstVisibleItemScrollOffset }
.collect { (index, offset) ->
isScrollingUp = if (index != previousIndex) {
index < previousIndex
} else {
offset < previousOffset
}
previousIndex = index
previousOffset = offset
}
}

HideSystemBars()

Scaffold(topBar = {
AnimatedVisibility(
visible = isScrollingUp
) {
TopAppBar(
navigationIcon = {
HBackIcon { goBack() }
},
title = {},
actions = {
if (uiState.images.isNotEmpty())
HPageProgress(uiState.postPage, uiState.postTotalPage)
}
)
}
}) {

Box(modifier = Modifier.fillMaxSize()) {
LazyColumn(
state = listState,
modifier = Modifier.padding(it),
verticalArrangement = Arrangement.spacedBy(8.dp)
) {
items(uiState.images) { image ->
Expand All @@ -128,8 +83,11 @@ fun PostPage(appViewModel: AppViewModel, goBack: () -> Unit) {
item {
HLoading()
}

}

HGoTop(listState)

if (selectedImage != null) {
ImageModal(url = selectedImage!!) {
selectedImage = null
Expand Down
43 changes: 24 additions & 19 deletions app/src/main/java/com/paulcoding/hviewer/ui/page/posts/PostsPage.kt
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package com.paulcoding.hviewer.ui.page.posts

import android.widget.Toast
import androidx.compose.foundation.clickable
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.fillMaxWidth
Expand Down Expand Up @@ -36,6 +37,7 @@ import com.paulcoding.hviewer.model.PostItem
import com.paulcoding.hviewer.model.SiteConfig
import com.paulcoding.hviewer.ui.component.HBackIcon
import com.paulcoding.hviewer.ui.component.HEmpty
import com.paulcoding.hviewer.ui.component.HGoTop
import com.paulcoding.hviewer.ui.component.HIcon
import com.paulcoding.hviewer.ui.component.HImage
import com.paulcoding.hviewer.ui.component.HLoading
Expand Down Expand Up @@ -144,27 +146,30 @@ fun PageContent(
onPageChange(uiState.postsPage, uiState.postsTotalPage)
}

LazyColumn(
state = listState
) {
items(uiState.postItems) { post ->
PostItemView(post) {
onClick(post)
}
}
if (uiState.isLoading)
item {
HLoading()
}
else if (uiState.postItems.isEmpty())
item {
HEmpty(
title = "No posts found",
message = "Refresh?"
) {
viewModel.getPosts(1)
Box(modifier = Modifier.fillMaxSize()) {
LazyColumn(
state = listState
) {
items(uiState.postItems) { post ->
PostItemView(post) {
onClick(post)
}
}
if (uiState.isLoading)
item {
HLoading()
}
else if (uiState.postItems.isEmpty())
item {
HEmpty(
title = "No posts found",
message = "Refresh?"
) {
viewModel.getPosts(1)
}
}
}
HGoTop(listState)
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,10 @@ package com.paulcoding.hviewer.ui.page.search

import android.widget.Toast
import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.lazy.LazyColumn
import androidx.compose.foundation.lazy.items
Expand Down Expand Up @@ -37,6 +39,7 @@ import com.paulcoding.hviewer.extensions.isScrolledToEnd
import com.paulcoding.hviewer.model.PostItem
import com.paulcoding.hviewer.ui.component.HBackIcon
import com.paulcoding.hviewer.ui.component.HEmpty
import com.paulcoding.hviewer.ui.component.HGoTop
import com.paulcoding.hviewer.ui.component.HLoading
import com.paulcoding.hviewer.ui.component.HPageProgress
import com.paulcoding.hviewer.ui.icon.EditIcon
Expand Down Expand Up @@ -130,23 +133,27 @@ fun PageContent(
}
}

LazyColumn(
state = listState
) {
items(uiState.postItems) { post ->
PostItemView(post) {
onClick(post)
Box(modifier = Modifier.fillMaxSize()) {
LazyColumn(
state = listState
) {
items(uiState.postItems) { post ->
PostItemView(post) {
onClick(post)
}
}
if (uiState.isLoading)
item {
HLoading()
}
else if (uiState.postItems.isEmpty() && uiState.query.isNotEmpty())
item {
HEmpty(
title = "No posts found",
)
}
}
if (uiState.isLoading)
item {
HLoading()
}
else if (uiState.postItems.isEmpty() && uiState.query.isNotEmpty())
item {
HEmpty(
title = "No posts found",
)
}
HGoTop(listState)
}
}