图片添加加载效果
- 为AsyncImage添加了Shimmer加载效果 - 优化了热门动态的加载逻辑 - 统一了ViewModel的重置方法名
This commit is contained in:
@@ -2,51 +2,86 @@ package com.aiosman.ravenow.ui.index.tabs.moment.tabs.hot
|
||||
|
||||
import androidx.lifecycle.ViewModel
|
||||
import androidx.lifecycle.viewModelScope
|
||||
import androidx.paging.Pager
|
||||
import androidx.paging.PagingConfig
|
||||
import androidx.paging.PagingData
|
||||
import androidx.paging.cachedIn
|
||||
import com.aiosman.ravenow.AppState
|
||||
import com.aiosman.ravenow.data.MomentService
|
||||
import com.aiosman.ravenow.entity.MomentEntity
|
||||
import com.aiosman.ravenow.entity.MomentLoaderExtraArgs
|
||||
import com.aiosman.ravenow.entity.MomentPagingSource
|
||||
import com.aiosman.ravenow.entity.MomentRemoteDataSource
|
||||
import com.aiosman.ravenow.entity.MomentServiceImpl
|
||||
import com.aiosman.ravenow.ui.index.tabs.moment.BaseMomentModel
|
||||
import kotlinx.coroutines.flow.MutableStateFlow
|
||||
import kotlinx.coroutines.flow.asStateFlow
|
||||
import kotlinx.coroutines.flow.collectLatest
|
||||
import kotlinx.coroutines.launch
|
||||
import org.greenrobot.eventbus.EventBus
|
||||
|
||||
|
||||
object HotMomentViewModel : ViewModel() {
|
||||
private val momentService: MomentService = MomentServiceImpl()
|
||||
private val _discoverMomentsFlow =
|
||||
MutableStateFlow<PagingData<MomentEntity>>(PagingData.empty())
|
||||
val discoverMomentsFlow = _discoverMomentsFlow.asStateFlow()
|
||||
var firstLoad = true
|
||||
fun refreshPager() {
|
||||
if (!firstLoad) {
|
||||
return
|
||||
}
|
||||
firstLoad = false
|
||||
private val _discoverMoments = MutableStateFlow<List<MomentEntity>>(emptyList())
|
||||
val discoverMoments = _discoverMoments.asStateFlow()
|
||||
|
||||
private val _isLoading = MutableStateFlow(false)
|
||||
val isLoading = _isLoading.asStateFlow()
|
||||
|
||||
private val _isRefreshing = MutableStateFlow(false)
|
||||
val isRefreshing = _isRefreshing.asStateFlow()
|
||||
|
||||
private var currentPage = 1
|
||||
private var hasMoreData = true
|
||||
private val pageSize = 20
|
||||
|
||||
fun loadMoments() {
|
||||
if (_isLoading.value || !hasMoreData) return
|
||||
|
||||
viewModelScope.launch {
|
||||
Pager(
|
||||
config = PagingConfig(pageSize = 5, enablePlaceholders = false),
|
||||
pagingSourceFactory = {
|
||||
MomentPagingSource(
|
||||
MomentRemoteDataSource(momentService),
|
||||
trend = true
|
||||
)
|
||||
_isLoading.value = true
|
||||
try {
|
||||
val response = momentService.getMoments(
|
||||
pageNumber = currentPage,
|
||||
trend = true
|
||||
)
|
||||
|
||||
if (response.list.isNotEmpty()) {
|
||||
if (currentPage == 1) {
|
||||
_discoverMoments.value = response.list
|
||||
} else {
|
||||
_discoverMoments.value = _discoverMoments.value + response.list
|
||||
}
|
||||
currentPage++
|
||||
hasMoreData = response.list.size >= response.pageSize
|
||||
} else {
|
||||
hasMoreData = false
|
||||
}
|
||||
).flow.cachedIn(viewModelScope).collectLatest {
|
||||
_discoverMomentsFlow.value = it
|
||||
} catch (e: Exception) {
|
||||
// 处理错误
|
||||
e.printStackTrace()
|
||||
} finally {
|
||||
_isLoading.value = false
|
||||
}
|
||||
}
|
||||
}
|
||||
fun ResetModel(){
|
||||
firstLoad = true
|
||||
|
||||
fun refreshMoments() {
|
||||
viewModelScope.launch {
|
||||
_isRefreshing.value = true
|
||||
currentPage = 1
|
||||
hasMoreData = true
|
||||
try {
|
||||
val response = momentService.getMoments(
|
||||
pageNumber = 1,
|
||||
trend = true
|
||||
)
|
||||
_discoverMoments.value = response.list
|
||||
currentPage = 2
|
||||
hasMoreData = response.list.size >= response.pageSize
|
||||
} catch (e: Exception) {
|
||||
e.printStackTrace()
|
||||
} finally {
|
||||
_isRefreshing.value = false
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fun resetModel() {
|
||||
currentPage = 1
|
||||
hasMoreData = true
|
||||
_discoverMoments.value = emptyList()
|
||||
_isLoading.value = false
|
||||
_isRefreshing.value = false
|
||||
}
|
||||
}
|
||||
@@ -15,6 +15,8 @@ import androidx.compose.foundation.layout.size
|
||||
import androidx.compose.foundation.lazy.LazyColumn
|
||||
import androidx.compose.foundation.lazy.grid.GridCells
|
||||
import androidx.compose.foundation.lazy.grid.LazyVerticalGrid
|
||||
import androidx.compose.foundation.lazy.grid.items
|
||||
import androidx.compose.foundation.lazy.grid.rememberLazyGridState
|
||||
import androidx.compose.foundation.lazy.rememberLazyListState
|
||||
import androidx.compose.foundation.shape.RoundedCornerShape
|
||||
import androidx.compose.material.ExperimentalMaterialApi
|
||||
@@ -29,13 +31,15 @@ import androidx.compose.runtime.mutableStateOf
|
||||
import androidx.compose.runtime.remember
|
||||
import androidx.compose.runtime.rememberCoroutineScope
|
||||
import androidx.compose.runtime.setValue
|
||||
import androidx.compose.runtime.snapshotFlow
|
||||
import kotlinx.coroutines.flow.collectLatest
|
||||
import androidx.compose.ui.Alignment
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.draw.clip
|
||||
import androidx.compose.ui.platform.LocalContext
|
||||
import androidx.compose.ui.res.painterResource
|
||||
import androidx.compose.ui.unit.dp
|
||||
import androidx.paging.compose.collectAsLazyPagingItems
|
||||
import androidx.compose.runtime.collectAsState
|
||||
import com.aiosman.ravenow.LocalAppTheme
|
||||
import com.aiosman.ravenow.LocalNavController
|
||||
import com.aiosman.ravenow.R
|
||||
@@ -57,12 +61,14 @@ fun HotMomentsList() {
|
||||
val navController = LocalNavController.current
|
||||
val navigationBarPaddings =
|
||||
WindowInsets.navigationBars.asPaddingValues().calculateBottomPadding() + 48.dp
|
||||
val isRefreshing by model.isRefreshing.collectAsState()
|
||||
|
||||
LaunchedEffect(Unit) {
|
||||
model.refreshPager()
|
||||
model.loadMoments()
|
||||
}
|
||||
var refreshing by remember { mutableStateOf(false) }
|
||||
val state = rememberPullRefreshState(refreshing, onRefresh = {
|
||||
model.refreshPager()
|
||||
|
||||
val state = rememberPullRefreshState(isRefreshing, onRefresh = {
|
||||
model.refreshMoments()
|
||||
})
|
||||
|
||||
Column(
|
||||
@@ -84,7 +90,7 @@ fun HotMomentsList() {
|
||||
.padding(2.dp)
|
||||
) {
|
||||
DiscoverView()
|
||||
PullRefreshIndicator(refreshing, state, Modifier.align(Alignment.TopCenter))
|
||||
PullRefreshIndicator(isRefreshing, state, Modifier.align(Alignment.TopCenter))
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -93,17 +99,37 @@ fun HotMomentsList() {
|
||||
@Composable
|
||||
fun DiscoverView() {
|
||||
val model = HotMomentViewModel
|
||||
var dataFlow = model.discoverMomentsFlow
|
||||
var moments = dataFlow.collectAsLazyPagingItems()
|
||||
val moments by model.discoverMoments.collectAsState()
|
||||
val isLoading by model.isLoading.collectAsState()
|
||||
val context = LocalContext.current
|
||||
val navController = LocalNavController.current
|
||||
val gridState = rememberLazyGridState()
|
||||
|
||||
// 监听滚动到底部,自动加载更多
|
||||
LaunchedEffect(gridState, moments.size) {
|
||||
snapshotFlow {
|
||||
val layoutInfo = gridState.layoutInfo
|
||||
val visibleItemsInfo = layoutInfo.visibleItemsInfo
|
||||
if (visibleItemsInfo.isNotEmpty() && moments.isNotEmpty()) {
|
||||
val lastVisibleItemIndex = visibleItemsInfo.lastOrNull()?.index ?: 0
|
||||
lastVisibleItemIndex >= moments.size - 6 // 距离底部还有6个项目时开始加载
|
||||
} else {
|
||||
false
|
||||
}
|
||||
}.collectLatest { shouldLoadMore ->
|
||||
if (shouldLoadMore && !isLoading) {
|
||||
model.loadMoments()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
LazyVerticalGrid(
|
||||
columns = GridCells.Fixed(3),
|
||||
state = gridState,
|
||||
modifier = Modifier.fillMaxSize().padding(bottom = 8.dp),
|
||||
// contentPadding = PaddingValues(8.dp)
|
||||
) {
|
||||
items(moments.itemCount) { idx ->
|
||||
val momentItem = moments[idx] ?: return@items
|
||||
items(moments) { momentItem ->
|
||||
Box(
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
@@ -122,7 +148,8 @@ fun DiscoverView() {
|
||||
contentDescription = "",
|
||||
modifier = Modifier
|
||||
.fillMaxSize(),
|
||||
context = context
|
||||
context = context,
|
||||
showShimmer = true
|
||||
)
|
||||
if (momentItem.images.size > 1) {
|
||||
Box(
|
||||
|
||||
Reference in New Issue
Block a user