feat: Implement moment follow/unfollow feature
This commit implements the follow/unfollow feature for moments in the Search, Timeline, and Explore tabs. It includes: - Adding a follow button to moment cards and implementing follow/unfollow logic in the respective ViewModels. - Updating the UI to reflect the follow status changes in the moment list. - Handling follow/unfollow API requests.
This commit is contained in:
@@ -54,6 +54,7 @@ import androidx.compose.ui.text.style.TextAlign
|
||||
import androidx.compose.ui.unit.dp
|
||||
import androidx.compose.ui.unit.sp
|
||||
import com.aiosman.riderpro.AppColors
|
||||
import com.aiosman.riderpro.AppState
|
||||
import com.aiosman.riderpro.LocalNavController
|
||||
import com.aiosman.riderpro.R
|
||||
import com.aiosman.riderpro.entity.MomentEntity
|
||||
@@ -70,17 +71,20 @@ fun MomentCard(
|
||||
onLikeClick: () -> Unit = {},
|
||||
onFavoriteClick: () -> Unit = {},
|
||||
onAddComment: () -> Unit = {},
|
||||
onFollowClick: () -> Unit = {},
|
||||
hideAction: Boolean = false
|
||||
) {
|
||||
var imageIndex by remember { mutableStateOf(0) }
|
||||
val navController = LocalNavController.current
|
||||
Column(
|
||||
modifier = Modifier.fillMaxWidth().background(AppColors.background)
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.background(AppColors.background)
|
||||
) {
|
||||
Box(
|
||||
modifier = Modifier.padding(start = 16.dp, end = 16.dp, top = 16.dp, bottom = 8.dp)
|
||||
) {
|
||||
MomentTopRowGroup(momentEntity = momentEntity)
|
||||
MomentTopRowGroup(momentEntity = momentEntity, onFollowClick = onFollowClick)
|
||||
}
|
||||
Column(
|
||||
modifier = Modifier
|
||||
@@ -163,9 +167,9 @@ fun ModificationListHeader() {
|
||||
}
|
||||
|
||||
@Composable
|
||||
fun MomentName(name: String) {
|
||||
fun MomentName(name: String, modifier: Modifier = Modifier) {
|
||||
Text(
|
||||
modifier = Modifier,
|
||||
modifier = modifier,
|
||||
textAlign = TextAlign.Start,
|
||||
text = name,
|
||||
color = AppColors.text,
|
||||
@@ -214,7 +218,10 @@ fun MomentPostTime(time: String) {
|
||||
}
|
||||
|
||||
@Composable
|
||||
fun MomentTopRowGroup(momentEntity: MomentEntity) {
|
||||
fun MomentTopRowGroup(
|
||||
momentEntity: MomentEntity,
|
||||
onFollowClick: () -> Unit = {}
|
||||
) {
|
||||
val navController = LocalNavController.current
|
||||
val context = LocalContext.current
|
||||
Row(
|
||||
@@ -239,7 +246,7 @@ fun MomentTopRowGroup(momentEntity: MomentEntity) {
|
||||
)
|
||||
Column(
|
||||
modifier = Modifier
|
||||
.defaultMinSize()
|
||||
.weight(1f)
|
||||
.padding(start = 12.dp, end = 12.dp)
|
||||
) {
|
||||
Row(
|
||||
@@ -248,8 +255,13 @@ fun MomentTopRowGroup(momentEntity: MomentEntity) {
|
||||
.height(22.dp),
|
||||
verticalAlignment = Alignment.CenterVertically
|
||||
) {
|
||||
MomentName(momentEntity.nickname)
|
||||
MomentName(
|
||||
modifier = Modifier.weight(1f),
|
||||
name = momentEntity.nickname
|
||||
)
|
||||
// MomentFollowBtn()
|
||||
Spacer(modifier = Modifier.width(16.dp))
|
||||
|
||||
}
|
||||
Row(
|
||||
modifier = Modifier
|
||||
@@ -262,6 +274,16 @@ fun MomentTopRowGroup(momentEntity: MomentEntity) {
|
||||
MomentPostLocation(momentEntity.location)
|
||||
}
|
||||
}
|
||||
Spacer(modifier = Modifier.width(16.dp))
|
||||
if (AppState.UserId != momentEntity.authorId) {
|
||||
FollowButton(
|
||||
isFollowing = momentEntity.followStatus
|
||||
) {
|
||||
onFollowClick()
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -72,7 +72,10 @@ fun ExploreMomentsList() {
|
||||
model.favoriteMoment(momentItem.id)
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
onFollowClick = {
|
||||
model.followAction(momentItem)
|
||||
},
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -11,7 +11,9 @@ import androidx.paging.PagingData
|
||||
import androidx.paging.cachedIn
|
||||
import androidx.paging.map
|
||||
import com.aiosman.riderpro.AppState
|
||||
import com.aiosman.riderpro.data.Moment
|
||||
import com.aiosman.riderpro.data.MomentService
|
||||
import com.aiosman.riderpro.data.UserServiceImpl
|
||||
import com.aiosman.riderpro.entity.MomentEntity
|
||||
import com.aiosman.riderpro.entity.MomentPagingSource
|
||||
import com.aiosman.riderpro.entity.MomentRemoteDataSource
|
||||
@@ -24,6 +26,7 @@ import kotlinx.coroutines.launch
|
||||
|
||||
object MomentExploreViewModel : ViewModel() {
|
||||
private val momentService: MomentService = MomentServiceImpl()
|
||||
private val userService = UserServiceImpl()
|
||||
private val _momentsFlow = MutableStateFlow<PagingData<MomentEntity>>(PagingData.empty())
|
||||
val momentsFlow = _momentsFlow.asStateFlow()
|
||||
var existsMoment = mutableStateOf(false)
|
||||
@@ -147,6 +150,31 @@ object MomentExploreViewModel : ViewModel() {
|
||||
momentService.unfavoriteMoment(id)
|
||||
updateUnfavoriteCount(id)
|
||||
}
|
||||
fun updateFollowStatus(authorId:Int,isFollow:Boolean) {
|
||||
val currentPagingData = _momentsFlow.value
|
||||
val updatedPagingData = currentPagingData.map { momentItem ->
|
||||
if (momentItem.authorId == authorId) {
|
||||
momentItem.copy(followStatus = isFollow)
|
||||
} else {
|
||||
momentItem
|
||||
}
|
||||
}
|
||||
_momentsFlow.value = updatedPagingData
|
||||
}
|
||||
fun followAction(moment: MomentEntity) {
|
||||
viewModelScope.launch {
|
||||
try {
|
||||
if (moment.followStatus) {
|
||||
userService.unFollowUser(moment.authorId.toString())
|
||||
} else {
|
||||
userService.followUser(moment.authorId.toString())
|
||||
}
|
||||
updateFollowStatus(moment.authorId, !moment.followStatus)
|
||||
} catch (e: Exception) {
|
||||
e.printStackTrace()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fun ResetModel() {
|
||||
_momentsFlow.value = PagingData.empty()
|
||||
|
||||
@@ -71,6 +71,9 @@ fun TimelineMomentsList() {
|
||||
model.favoriteMoment(momentItem.id)
|
||||
}
|
||||
}
|
||||
},
|
||||
onFollowClick = {
|
||||
model.followAction(momentItem)
|
||||
}
|
||||
)
|
||||
// Box(
|
||||
|
||||
@@ -13,6 +13,8 @@ import androidx.paging.filter
|
||||
import androidx.paging.map
|
||||
import com.aiosman.riderpro.AppState
|
||||
import com.aiosman.riderpro.data.MomentService
|
||||
import com.aiosman.riderpro.data.UserService
|
||||
import com.aiosman.riderpro.data.UserServiceImpl
|
||||
import com.aiosman.riderpro.entity.MomentEntity
|
||||
import com.aiosman.riderpro.entity.MomentPagingSource
|
||||
import com.aiosman.riderpro.entity.MomentRemoteDataSource
|
||||
@@ -26,6 +28,7 @@ import kotlinx.coroutines.launch
|
||||
object TimelineMomentViewModel : ViewModel() {
|
||||
private val momentService: MomentService = MomentServiceImpl()
|
||||
private val _momentsFlow = MutableStateFlow<PagingData<MomentEntity>>(PagingData.empty())
|
||||
private val userService :UserService = UserServiceImpl()
|
||||
val momentsFlow = _momentsFlow.asStateFlow()
|
||||
var existsMoment = mutableStateOf(false)
|
||||
var refreshing by mutableStateOf(false)
|
||||
@@ -173,6 +176,32 @@ object TimelineMomentViewModel : ViewModel() {
|
||||
_momentsFlow.value = updatedPagingData
|
||||
}
|
||||
|
||||
fun updateFollowStatus(authorId:Int,isFollow:Boolean) {
|
||||
val currentPagingData = _momentsFlow.value
|
||||
val updatedPagingData = currentPagingData.map { momentItem ->
|
||||
if (momentItem.authorId == authorId) {
|
||||
momentItem.copy(followStatus = isFollow)
|
||||
} else {
|
||||
momentItem
|
||||
}
|
||||
}
|
||||
_momentsFlow.value = updatedPagingData
|
||||
}
|
||||
fun followAction(moment: MomentEntity) {
|
||||
viewModelScope.launch {
|
||||
try {
|
||||
if (moment.followStatus) {
|
||||
userService.unFollowUser(moment.authorId.toString())
|
||||
} else {
|
||||
userService.followUser(moment.authorId.toString())
|
||||
}
|
||||
updateFollowStatus(moment.authorId, !moment.followStatus)
|
||||
} catch (e: Exception) {
|
||||
e.printStackTrace()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fun ResetModel() {
|
||||
_momentsFlow.value = PagingData.empty()
|
||||
isFirstLoad = true
|
||||
|
||||
@@ -265,7 +265,13 @@ fun MomentResultTab() {
|
||||
.fillMaxWidth()
|
||||
.background(Color.White)
|
||||
) {
|
||||
MomentCard(momentEntity = momentItem, hideAction = true)
|
||||
MomentCard(
|
||||
momentEntity = momentItem,
|
||||
hideAction = true,
|
||||
onFollowClick = {
|
||||
model.momentFollowAction(momentItem)
|
||||
}
|
||||
)
|
||||
}
|
||||
// Spacer(modifier = Modifier.padding(16.dp))
|
||||
}
|
||||
|
||||
@@ -10,15 +10,14 @@ import androidx.paging.PagingConfig
|
||||
import androidx.paging.PagingData
|
||||
import androidx.paging.cachedIn
|
||||
import androidx.paging.map
|
||||
import com.aiosman.riderpro.data.MomentService
|
||||
import com.aiosman.riderpro.data.UserServiceImpl
|
||||
import com.aiosman.riderpro.entity.AccountPagingSource
|
||||
import com.aiosman.riderpro.entity.AccountProfileEntity
|
||||
import com.aiosman.riderpro.entity.MomentEntity
|
||||
import com.aiosman.riderpro.entity.MomentPagingSource
|
||||
import com.aiosman.riderpro.entity.MomentRemoteDataSource
|
||||
import com.aiosman.riderpro.data.MomentService
|
||||
import com.aiosman.riderpro.entity.MomentServiceImpl
|
||||
import com.aiosman.riderpro.data.UserServiceImpl
|
||||
import com.aiosman.riderpro.entity.MomentEntity
|
||||
import com.aiosman.riderpro.ui.index.tabs.moment.MomentViewModel
|
||||
import kotlinx.coroutines.flow.MutableStateFlow
|
||||
import kotlinx.coroutines.flow.asStateFlow
|
||||
import kotlinx.coroutines.flow.collectLatest
|
||||
@@ -99,4 +98,30 @@ object SearchViewModel : ViewModel() {
|
||||
_usersFlow.value = PagingData.empty()
|
||||
showResult = false
|
||||
}
|
||||
|
||||
fun updateMomentFollowStatus(authorId:Int,isFollow:Boolean) {
|
||||
val currentPagingData = _momentsFlow.value
|
||||
val updatedPagingData = currentPagingData.map { momentItem ->
|
||||
if (momentItem.authorId == authorId) {
|
||||
momentItem.copy(followStatus = isFollow)
|
||||
} else {
|
||||
momentItem
|
||||
}
|
||||
}
|
||||
_momentsFlow.value = updatedPagingData
|
||||
}
|
||||
fun momentFollowAction(moment: MomentEntity) {
|
||||
viewModelScope.launch {
|
||||
try {
|
||||
if (moment.followStatus) {
|
||||
userService.unFollowUser(moment.authorId.toString())
|
||||
} else {
|
||||
userService.followUser(moment.authorId.toString())
|
||||
}
|
||||
updateMomentFollowStatus(moment.authorId, !moment.followStatus)
|
||||
} catch (e: Exception) {
|
||||
e.printStackTrace()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user