改包名com.aiosman.ravenow
This commit is contained in:
@@ -0,0 +1,132 @@
|
||||
package com.aiosman.ravenow.ui.favourite
|
||||
|
||||
import androidx.compose.foundation.Image
|
||||
import androidx.compose.foundation.background
|
||||
import androidx.compose.foundation.layout.Box
|
||||
import androidx.compose.foundation.layout.Column
|
||||
import androidx.compose.foundation.layout.aspectRatio
|
||||
import androidx.compose.foundation.layout.fillMaxSize
|
||||
import androidx.compose.foundation.layout.fillMaxWidth
|
||||
import androidx.compose.foundation.layout.padding
|
||||
import androidx.compose.foundation.layout.size
|
||||
import androidx.compose.foundation.lazy.grid.GridCells
|
||||
import androidx.compose.foundation.lazy.grid.LazyVerticalGrid
|
||||
import androidx.compose.foundation.shape.RoundedCornerShape
|
||||
import androidx.compose.material.ExperimentalMaterialApi
|
||||
import androidx.compose.material.pullrefresh.PullRefreshIndicator
|
||||
import androidx.compose.material.pullrefresh.pullRefresh
|
||||
import androidx.compose.material.pullrefresh.rememberPullRefreshState
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.LaunchedEffect
|
||||
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.res.stringResource
|
||||
import androidx.compose.ui.unit.dp
|
||||
import androidx.paging.compose.collectAsLazyPagingItems
|
||||
import com.aiosman.ravenow.LocalAppTheme
|
||||
import com.aiosman.ravenow.LocalNavController
|
||||
import com.aiosman.ravenow.R
|
||||
import com.aiosman.ravenow.ui.comment.NoticeScreenHeader
|
||||
import com.aiosman.ravenow.ui.composables.CustomAsyncImage
|
||||
import com.aiosman.ravenow.ui.composables.StatusBarSpacer
|
||||
import com.aiosman.ravenow.ui.favourite.FavouriteListViewModel.refreshPager
|
||||
import com.aiosman.ravenow.ui.modifiers.noRippleClickable
|
||||
import com.aiosman.ravenow.ui.navigateToPost
|
||||
|
||||
@OptIn(ExperimentalMaterialApi::class)
|
||||
@Composable
|
||||
fun FavouriteListPage() {
|
||||
val AppColors = LocalAppTheme.current
|
||||
val model = FavouriteListViewModel
|
||||
var dataFlow = model.favouriteMomentsFlow
|
||||
var moments = dataFlow.collectAsLazyPagingItems()
|
||||
val context = LocalContext.current
|
||||
val navController = LocalNavController.current
|
||||
val state = rememberPullRefreshState(FavouriteListViewModel.isLoading, onRefresh = {
|
||||
model.refreshPager(force = true)
|
||||
})
|
||||
LaunchedEffect(Unit) {
|
||||
refreshPager()
|
||||
}
|
||||
Column(
|
||||
modifier = Modifier.fillMaxSize().background(AppColors.background)
|
||||
) {
|
||||
StatusBarSpacer()
|
||||
Box(
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.weight(1f)
|
||||
.pullRefresh(state)
|
||||
) {
|
||||
Column(
|
||||
modifier = Modifier.fillMaxSize()
|
||||
) {
|
||||
Box(
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.padding(horizontal = 16.dp, vertical = 16.dp),
|
||||
) {
|
||||
NoticeScreenHeader(stringResource(R.string.favourites_upper), moreIcon = false)
|
||||
}
|
||||
LazyVerticalGrid(
|
||||
columns = GridCells.Fixed(3),
|
||||
modifier = Modifier.fillMaxSize().padding(horizontal = 16.dp)
|
||||
) {
|
||||
items(moments.itemCount) { idx ->
|
||||
val momentItem = moments[idx] ?: return@items
|
||||
Box(
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.aspectRatio(1f)
|
||||
.padding(2.dp)
|
||||
.noRippleClickable {
|
||||
navController.navigateToPost(
|
||||
id = momentItem.id,
|
||||
highlightCommentId = 0,
|
||||
initImagePagerIndex = 0
|
||||
)
|
||||
}
|
||||
) {
|
||||
CustomAsyncImage(
|
||||
imageUrl = momentItem.images[0].thumbnail,
|
||||
contentDescription = "",
|
||||
modifier = Modifier
|
||||
.fillMaxSize()
|
||||
.clip(RoundedCornerShape(8.dp)),
|
||||
context = context
|
||||
)
|
||||
if (momentItem.images.size > 1) {
|
||||
Box(
|
||||
modifier = Modifier
|
||||
.padding(top = 8.dp, end = 8.dp)
|
||||
.align(Alignment.TopEnd)
|
||||
) {
|
||||
Image(
|
||||
modifier = Modifier.size(24.dp),
|
||||
painter = painterResource(R.drawable.rider_pro_picture_more),
|
||||
contentDescription = "",
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
PullRefreshIndicator(
|
||||
FavouriteListViewModel.isLoading,
|
||||
state,
|
||||
Modifier.align(Alignment.TopCenter)
|
||||
)
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,52 @@
|
||||
package com.aiosman.ravenow.ui.favourite
|
||||
|
||||
import androidx.compose.runtime.getValue
|
||||
import androidx.compose.runtime.mutableStateOf
|
||||
import androidx.compose.runtime.setValue
|
||||
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.MomentPagingSource
|
||||
import com.aiosman.ravenow.entity.MomentRemoteDataSource
|
||||
import com.aiosman.ravenow.entity.MomentServiceImpl
|
||||
import kotlinx.coroutines.flow.MutableStateFlow
|
||||
import kotlinx.coroutines.flow.asStateFlow
|
||||
import kotlinx.coroutines.flow.collectLatest
|
||||
import kotlinx.coroutines.launch
|
||||
|
||||
object FavouriteListViewModel:ViewModel() {
|
||||
private val momentService: MomentService = MomentServiceImpl()
|
||||
private val _favouriteMomentsFlow =
|
||||
MutableStateFlow<PagingData<MomentEntity>>(PagingData.empty())
|
||||
val favouriteMomentsFlow = _favouriteMomentsFlow.asStateFlow()
|
||||
var isLoading by mutableStateOf(false)
|
||||
fun refreshPager(force:Boolean = false) {
|
||||
viewModelScope.launch {
|
||||
if (force) {
|
||||
isLoading = true
|
||||
}
|
||||
isLoading = false
|
||||
Pager(
|
||||
config = PagingConfig(pageSize = 5, enablePlaceholders = false),
|
||||
pagingSourceFactory = {
|
||||
MomentPagingSource(
|
||||
MomentRemoteDataSource(momentService),
|
||||
favoriteUserId = AppState.UserId
|
||||
)
|
||||
}
|
||||
).flow.cachedIn(viewModelScope).collectLatest {
|
||||
_favouriteMomentsFlow.value = it
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
fun ResetModel() {
|
||||
isLoading = false
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,85 @@
|
||||
package com.aiosman.ravenow.ui.favourite
|
||||
|
||||
import androidx.compose.foundation.background
|
||||
import androidx.compose.foundation.layout.Box
|
||||
import androidx.compose.foundation.layout.Column
|
||||
import androidx.compose.foundation.layout.fillMaxWidth
|
||||
import androidx.compose.foundation.layout.padding
|
||||
import androidx.compose.foundation.lazy.LazyColumn
|
||||
import androidx.compose.foundation.lazy.rememberLazyListState
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.LaunchedEffect
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.graphics.Color
|
||||
import androidx.compose.ui.res.stringResource
|
||||
import androidx.compose.ui.unit.dp
|
||||
import androidx.paging.compose.collectAsLazyPagingItems
|
||||
import com.aiosman.ravenow.AppState
|
||||
import com.aiosman.ravenow.R
|
||||
import com.aiosman.ravenow.ui.comment.NoticeScreenHeader
|
||||
import com.aiosman.ravenow.ui.composables.StatusBarMaskLayout
|
||||
import com.aiosman.ravenow.ui.composables.BottomNavigationPlaceholder
|
||||
import com.aiosman.ravenow.ui.like.ActionPostNoticeItem
|
||||
|
||||
/**
|
||||
* 收藏消息界面
|
||||
*/
|
||||
@Composable
|
||||
fun FavouriteNoticeScreen() {
|
||||
|
||||
val model = FavouriteNoticeViewModel
|
||||
val listState = rememberLazyListState()
|
||||
var dataFlow = model.favouriteItemsFlow
|
||||
var favourites = dataFlow.collectAsLazyPagingItems()
|
||||
LaunchedEffect(Unit) {
|
||||
model.reload()
|
||||
model.updateNotice()
|
||||
}
|
||||
StatusBarMaskLayout(
|
||||
darkIcons = !AppState.darkMode,
|
||||
maskBoxBackgroundColor = Color(0xFFFFFFFF)
|
||||
) {
|
||||
Column(
|
||||
modifier = Modifier
|
||||
.weight(1f)
|
||||
.background(color = Color(0xFFFFFFFF))
|
||||
.padding(horizontal = 16.dp)
|
||||
) {
|
||||
Box(
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.padding(vertical = 16.dp)
|
||||
) {
|
||||
NoticeScreenHeader(
|
||||
stringResource(R.string.favourites_upper),
|
||||
moreIcon = false
|
||||
)
|
||||
}
|
||||
LazyColumn(
|
||||
modifier = Modifier.weight(1f),
|
||||
state = listState,
|
||||
) {
|
||||
items(favourites.itemCount) {
|
||||
val favouriteItem = favourites[it]
|
||||
if (favouriteItem != null) {
|
||||
ActionPostNoticeItem(
|
||||
avatar = favouriteItem.user.avatar,
|
||||
nickName = favouriteItem.user.nickName,
|
||||
likeTime = favouriteItem.favoriteTime,
|
||||
thumbnail = favouriteItem.post.images[0].thumbnail,
|
||||
action = "favourite",
|
||||
userId = favouriteItem.user.id,
|
||||
postId = favouriteItem.post.id,
|
||||
)
|
||||
}
|
||||
}
|
||||
item {
|
||||
BottomNavigationPlaceholder()
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,62 @@
|
||||
package com.aiosman.ravenow.ui.favourite
|
||||
|
||||
import android.icu.util.Calendar
|
||||
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.entity.AccountFavouriteEntity
|
||||
import com.aiosman.ravenow.data.AccountService
|
||||
import com.aiosman.ravenow.entity.FavoriteItemPagingSource
|
||||
import com.aiosman.ravenow.data.AccountServiceImpl
|
||||
import com.aiosman.ravenow.data.api.ApiClient
|
||||
import com.aiosman.ravenow.data.api.UpdateNoticeRequestBody
|
||||
import kotlinx.coroutines.flow.MutableStateFlow
|
||||
import kotlinx.coroutines.flow.asStateFlow
|
||||
import kotlinx.coroutines.flow.collectLatest
|
||||
import kotlinx.coroutines.launch
|
||||
|
||||
/**
|
||||
* 收藏消息列表的 ViewModel
|
||||
*/
|
||||
object FavouriteNoticeViewModel : ViewModel() {
|
||||
private val accountService: AccountService = AccountServiceImpl()
|
||||
private val _favouriteItemsFlow =
|
||||
MutableStateFlow<PagingData<AccountFavouriteEntity>>(PagingData.empty())
|
||||
val favouriteItemsFlow = _favouriteItemsFlow.asStateFlow()
|
||||
var isFirstLoad = true
|
||||
|
||||
fun reload(force: Boolean = false) {
|
||||
if (!isFirstLoad && !force) {
|
||||
return
|
||||
}
|
||||
isFirstLoad = false
|
||||
viewModelScope.launch {
|
||||
Pager(
|
||||
config = PagingConfig(pageSize = 5, enablePlaceholders = false),
|
||||
pagingSourceFactory = {
|
||||
FavoriteItemPagingSource(
|
||||
accountService
|
||||
)
|
||||
}
|
||||
).flow.cachedIn(viewModelScope).collectLatest {
|
||||
_favouriteItemsFlow.value = it
|
||||
}
|
||||
}
|
||||
}
|
||||
// 更新收藏消息的查看时间
|
||||
suspend fun updateNotice() {
|
||||
var now = Calendar.getInstance().time
|
||||
accountService.updateNotice(
|
||||
UpdateNoticeRequestBody(
|
||||
lastLookFavouriteTime = ApiClient.formatTime(now)
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
fun ResetModel() {
|
||||
isFirstLoad = true
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user