mirror of
https://github.com/LiveFastEatTrashRaccoon/RaccoonForLemmy.git
synced 2025-02-08 14:58:40 +01:00
fix: avoid concurrency issue while posts are being marked as read before opening detail (#262)
* update PostListScreen * update CommunityDetailScreen * update FilteredContentsScreen * update MultiCommunityScreen * update UserDetailScreen * update ProfileLoggedScreen * update InboxChatScreen * update InboxMentionsScreen * update InboxRepliesScreen
This commit is contained in:
parent
9f4ebbcf38
commit
705c0893e2
@ -277,7 +277,7 @@ class InboxChatScreen(
|
|||||||
items(
|
items(
|
||||||
items = uiState.messages,
|
items = uiState.messages,
|
||||||
key = {
|
key = {
|
||||||
it.id.toString() + (it.updateDate ?: it.publishDate) + it.read
|
it.id.toString() + (it.updateDate ?: it.publishDate)
|
||||||
},
|
},
|
||||||
) { message ->
|
) { message ->
|
||||||
val isMyMessage = message.creator?.id == uiState.currentUserId
|
val isMyMessage = message.creator?.id == uiState.currentUserId
|
||||||
|
@ -166,21 +166,19 @@ class InboxChatViewModel(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun markAsRead(
|
private suspend fun markAsRead(
|
||||||
read: Boolean,
|
read: Boolean,
|
||||||
messageId: Long,
|
messageId: Long,
|
||||||
) {
|
) {
|
||||||
val auth = identityRepository.authToken.value
|
val auth = identityRepository.authToken.value
|
||||||
screenModelScope.launch {
|
val newMessage =
|
||||||
val newMessage =
|
messageRepository.markAsRead(
|
||||||
messageRepository.markAsRead(
|
read = read,
|
||||||
read = read,
|
messageId = messageId,
|
||||||
messageId = messageId,
|
auth = auth,
|
||||||
auth = auth,
|
)
|
||||||
)
|
if (newMessage != null) {
|
||||||
if (newMessage != null) {
|
handleMessageUpdate(newMessage)
|
||||||
handleMessageUpdate(newMessage)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -102,7 +102,9 @@ interface CommunityDetailMviModel :
|
|||||||
val value: Boolean,
|
val value: Boolean,
|
||||||
) : Intent
|
) : Intent
|
||||||
|
|
||||||
data object WillOpenDetail : Intent
|
data class WillOpenDetail(
|
||||||
|
val id: Long,
|
||||||
|
) : Intent
|
||||||
|
|
||||||
data object UnhideCommunity : Intent
|
data object UnhideCommunity : Intent
|
||||||
|
|
||||||
@ -175,5 +177,9 @@ interface CommunityDetailMviModel :
|
|||||||
) : Effect
|
) : Effect
|
||||||
|
|
||||||
data object Back : Effect
|
data object Back : Effect
|
||||||
|
|
||||||
|
data class OpenDetail(
|
||||||
|
val post: PostModel,
|
||||||
|
) : Effect
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -246,6 +246,8 @@ class CommunityDetailScreen(
|
|||||||
}
|
}
|
||||||
|
|
||||||
CommunityDetailMviModel.Effect.Back -> navigationCoordinator.popScreen()
|
CommunityDetailMviModel.Effect.Back -> navigationCoordinator.popScreen()
|
||||||
|
is CommunityDetailMviModel.Effect.OpenDetail ->
|
||||||
|
detailOpener.openPostDetail(effect.post)
|
||||||
}
|
}
|
||||||
}.launchIn(this)
|
}.launchIn(this)
|
||||||
}
|
}
|
||||||
@ -822,7 +824,7 @@ class CommunityDetailScreen(
|
|||||||
items(
|
items(
|
||||||
items = uiState.posts,
|
items = uiState.posts,
|
||||||
key = {
|
key = {
|
||||||
it.id.toString() + (it.updateDate ?: it.publishDate) + it.read
|
it.id.toString() + (it.updateDate ?: it.publishDate)
|
||||||
},
|
},
|
||||||
) { post ->
|
) { post ->
|
||||||
LaunchedEffect(post.id) {
|
LaunchedEffect(post.id) {
|
||||||
@ -977,11 +979,10 @@ class CommunityDetailScreen(
|
|||||||
meTagColor = uiState.meTagColor,
|
meTagColor = uiState.meTagColor,
|
||||||
onClick = {
|
onClick = {
|
||||||
model.reduce(
|
model.reduce(
|
||||||
CommunityDetailMviModel.Intent.MarkAsRead(
|
CommunityDetailMviModel.Intent.WillOpenDetail(
|
||||||
post.id,
|
post.id,
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
model.reduce(CommunityDetailMviModel.Intent.WillOpenDetail)
|
|
||||||
detailOpener.openPostDetail(
|
detailOpener.openPostDetail(
|
||||||
post = post,
|
post = post,
|
||||||
otherInstance = otherInstanceName,
|
otherInstance = otherInstanceName,
|
||||||
@ -1027,11 +1028,10 @@ class CommunityDetailScreen(
|
|||||||
onReply =
|
onReply =
|
||||||
{
|
{
|
||||||
model.reduce(
|
model.reduce(
|
||||||
CommunityDetailMviModel.Intent.MarkAsRead(
|
CommunityDetailMviModel.Intent.WillOpenDetail(
|
||||||
post.id,
|
post.id,
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
model.reduce(CommunityDetailMviModel.Intent.WillOpenDetail)
|
|
||||||
detailOpener.openPostDetail(post)
|
detailOpener.openPostDetail(post)
|
||||||
}.takeIf { uiState.isLogged && !isOnOtherInstance },
|
}.takeIf { uiState.isLogged && !isOnOtherInstance },
|
||||||
onOpenImage = { url ->
|
onOpenImage = { url ->
|
||||||
|
@ -299,8 +299,9 @@ class CommunityDetailViewModel(
|
|||||||
|
|
||||||
CommunityDetailMviModel.Intent.Block -> blockCommunity()
|
CommunityDetailMviModel.Intent.Block -> blockCommunity()
|
||||||
CommunityDetailMviModel.Intent.BlockInstance -> blockInstance()
|
CommunityDetailMviModel.Intent.BlockInstance -> blockInstance()
|
||||||
is CommunityDetailMviModel.Intent.MarkAsRead -> {
|
is CommunityDetailMviModel.Intent.MarkAsRead ->
|
||||||
markAsRead(uiState.value.posts.first { it.id == intent.id })
|
screenModelScope.launch {
|
||||||
|
markAsRead(uiState.value.posts.first { it.id == intent.id })
|
||||||
}
|
}
|
||||||
|
|
||||||
CommunityDetailMviModel.Intent.ClearRead -> clearRead()
|
CommunityDetailMviModel.Intent.ClearRead -> clearRead()
|
||||||
@ -367,9 +368,15 @@ class CommunityDetailViewModel(
|
|||||||
|
|
||||||
is CommunityDetailMviModel.Intent.SetSearch -> updateSearchText(intent.value)
|
is CommunityDetailMviModel.Intent.SetSearch -> updateSearchText(intent.value)
|
||||||
|
|
||||||
CommunityDetailMviModel.Intent.WillOpenDetail -> {
|
is CommunityDetailMviModel.Intent.WillOpenDetail ->
|
||||||
val state = postPaginationManager.extractState()
|
screenModelScope.launch {
|
||||||
postNavigationManager.push(state)
|
uiState.value.posts
|
||||||
|
.firstOrNull { it.id == intent.id }
|
||||||
|
?.also { post ->
|
||||||
|
markAsRead(post)
|
||||||
|
val state = postPaginationManager.extractState()
|
||||||
|
postNavigationManager.push(state)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
CommunityDetailMviModel.Intent.UnhideCommunity -> {
|
CommunityDetailMviModel.Intent.UnhideCommunity -> {
|
||||||
@ -552,24 +559,22 @@ class CommunityDetailViewModel(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun markAsRead(post: PostModel) {
|
private suspend fun markAsRead(post: PostModel) {
|
||||||
if (post.read) {
|
if (post.read) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
val newPost = post.copy(read = true)
|
val newPost = post.copy(read = true)
|
||||||
screenModelScope.launch {
|
try {
|
||||||
try {
|
val auth = identityRepository.authToken.value.orEmpty()
|
||||||
val auth = identityRepository.authToken.value.orEmpty()
|
postRepository.setRead(
|
||||||
postRepository.setRead(
|
read = true,
|
||||||
read = true,
|
postId = post.id,
|
||||||
postId = post.id,
|
auth = auth,
|
||||||
auth = auth,
|
)
|
||||||
)
|
handlePostUpdate(newPost)
|
||||||
handlePostUpdate(newPost)
|
} catch (e: Throwable) {
|
||||||
} catch (e: Throwable) {
|
e.printStackTrace()
|
||||||
e.printStackTrace()
|
handlePostUpdate(post)
|
||||||
handlePostUpdate(post)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -100,7 +100,10 @@ interface FilteredContentsMviModel :
|
|||||||
val commentId: Long,
|
val commentId: Long,
|
||||||
) : Intent
|
) : Intent
|
||||||
|
|
||||||
data object WillOpenDetail : Intent
|
data class WillOpenDetail(
|
||||||
|
val postId: Long,
|
||||||
|
val commentId: Long? = null,
|
||||||
|
) : Intent
|
||||||
}
|
}
|
||||||
|
|
||||||
data class State(
|
data class State(
|
||||||
@ -136,5 +139,10 @@ interface FilteredContentsMviModel :
|
|||||||
|
|
||||||
sealed interface Effect {
|
sealed interface Effect {
|
||||||
data object BackToTop : Effect
|
data object BackToTop : Effect
|
||||||
|
|
||||||
|
data class OpenDetail(
|
||||||
|
val postId: Long,
|
||||||
|
val commentId: Long? = null,
|
||||||
|
) : Effect
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -154,6 +154,13 @@ class FilteredContentsScreen(
|
|||||||
topAppBarState.contentOffset = 0f
|
topAppBarState.contentOffset = 0f
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
is FilteredContentsMviModel.Effect.OpenDetail ->
|
||||||
|
detailOpener.openPostDetail(
|
||||||
|
post = PostModel(id = effect.postId),
|
||||||
|
highlightCommentId = effect.commentId,
|
||||||
|
isMod = true,
|
||||||
|
)
|
||||||
}
|
}
|
||||||
}.launchIn(this)
|
}.launchIn(this)
|
||||||
}
|
}
|
||||||
@ -369,7 +376,7 @@ class FilteredContentsScreen(
|
|||||||
items(
|
items(
|
||||||
items = uiState.posts,
|
items = uiState.posts,
|
||||||
key = {
|
key = {
|
||||||
it.id.toString() + (it.updateDate ?: it.publishDate) + it.read
|
it.id.toString() + (it.updateDate ?: it.publishDate)
|
||||||
},
|
},
|
||||||
) { post ->
|
) { post ->
|
||||||
|
|
||||||
@ -482,8 +489,11 @@ class FilteredContentsScreen(
|
|||||||
botTagColor = uiState.botTagColor,
|
botTagColor = uiState.botTagColor,
|
||||||
meTagColor = uiState.meTagColor,
|
meTagColor = uiState.meTagColor,
|
||||||
onClick = {
|
onClick = {
|
||||||
model.reduce(FilteredContentsMviModel.Intent.WillOpenDetail)
|
model.reduce(
|
||||||
detailOpener.openPostDetail(post)
|
FilteredContentsMviModel.Intent.WillOpenDetail(
|
||||||
|
postId = post.id,
|
||||||
|
),
|
||||||
|
)
|
||||||
},
|
},
|
||||||
onOpenCommunity = { community, instance ->
|
onOpenCommunity = { community, instance ->
|
||||||
detailOpener.openCommunityDetail(
|
detailOpener.openCommunityDetail(
|
||||||
@ -512,8 +522,11 @@ class FilteredContentsScreen(
|
|||||||
)
|
)
|
||||||
},
|
},
|
||||||
onReply = {
|
onReply = {
|
||||||
model.reduce(FilteredContentsMviModel.Intent.WillOpenDetail)
|
model.reduce(
|
||||||
detailOpener.openPostDetail(post)
|
FilteredContentsMviModel.Intent.WillOpenDetail(
|
||||||
|
postId = post.id,
|
||||||
|
),
|
||||||
|
)
|
||||||
},
|
},
|
||||||
onOpenImage = { url ->
|
onOpenImage = { url ->
|
||||||
navigationCoordinator.pushScreen(
|
navigationCoordinator.pushScreen(
|
||||||
@ -820,11 +833,11 @@ class FilteredContentsScreen(
|
|||||||
detailOpener.openUserDetail(user, instance)
|
detailOpener.openUserDetail(user, instance)
|
||||||
},
|
},
|
||||||
onOpen = {
|
onOpen = {
|
||||||
model.reduce(FilteredContentsMviModel.Intent.WillOpenDetail)
|
model.reduce(
|
||||||
detailOpener.openPostDetail(
|
FilteredContentsMviModel.Intent.WillOpenDetail(
|
||||||
post = PostModel(id = comment.postId),
|
postId = comment.postId,
|
||||||
highlightCommentId = comment.id,
|
commentId = comment.id,
|
||||||
isMod = true,
|
),
|
||||||
)
|
)
|
||||||
},
|
},
|
||||||
onUpVote = {
|
onUpVote = {
|
||||||
|
@ -212,10 +212,19 @@ class FilteredContentsViewModel(
|
|||||||
distinguish(comment)
|
distinguish(comment)
|
||||||
}
|
}
|
||||||
|
|
||||||
FilteredContentsMviModel.Intent.WillOpenDetail -> {
|
is FilteredContentsMviModel.Intent.WillOpenDetail ->
|
||||||
val state = postPaginationManager.extractState()
|
screenModelScope.launch {
|
||||||
postNavigationManager.push(state)
|
if (intent.commentId == null) {
|
||||||
}
|
val state = postPaginationManager.extractState()
|
||||||
|
postNavigationManager.push(state)
|
||||||
|
}
|
||||||
|
emitEffect(
|
||||||
|
FilteredContentsMviModel.Effect.OpenDetail(
|
||||||
|
postId = intent.postId,
|
||||||
|
commentId = intent.commentId,
|
||||||
|
),
|
||||||
|
)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -7,6 +7,7 @@ import com.livefast.eattrash.raccoonforlemmy.core.appearance.data.VoteFormat
|
|||||||
import com.livefast.eattrash.raccoonforlemmy.core.architecture.MviModel
|
import com.livefast.eattrash.raccoonforlemmy.core.architecture.MviModel
|
||||||
import com.livefast.eattrash.raccoonforlemmy.core.persistence.data.ActionOnSwipe
|
import com.livefast.eattrash.raccoonforlemmy.core.persistence.data.ActionOnSwipe
|
||||||
import com.livefast.eattrash.raccoonforlemmy.domain.lemmy.data.PersonMentionModel
|
import com.livefast.eattrash.raccoonforlemmy.domain.lemmy.data.PersonMentionModel
|
||||||
|
import com.livefast.eattrash.raccoonforlemmy.domain.lemmy.data.PostModel
|
||||||
|
|
||||||
@Stable
|
@Stable
|
||||||
interface InboxMentionsMviModel :
|
interface InboxMentionsMviModel :
|
||||||
@ -31,6 +32,12 @@ interface InboxMentionsMviModel :
|
|||||||
data class DownVoteComment(
|
data class DownVoteComment(
|
||||||
val id: Long,
|
val id: Long,
|
||||||
) : Intent
|
) : Intent
|
||||||
|
|
||||||
|
data class WillOpenDetail(
|
||||||
|
val id: Long,
|
||||||
|
val post: PostModel,
|
||||||
|
val commentId: Long,
|
||||||
|
) : Intent
|
||||||
}
|
}
|
||||||
|
|
||||||
data class UiState(
|
data class UiState(
|
||||||
@ -58,5 +65,10 @@ interface InboxMentionsMviModel :
|
|||||||
) : Effect
|
) : Effect
|
||||||
|
|
||||||
data object BackToTop : Effect
|
data object BackToTop : Effect
|
||||||
|
|
||||||
|
data class OpenDetail(
|
||||||
|
val post: PostModel,
|
||||||
|
val commentId: Long,
|
||||||
|
) : Effect
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -99,6 +99,12 @@ class InboxMentionsScreen : Tab {
|
|||||||
lazyListState.scrollToItem(0)
|
lazyListState.scrollToItem(0)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
is InboxMentionsMviModel.Effect.OpenDetail ->
|
||||||
|
detailOpener.openPostDetail(
|
||||||
|
post = effect.post,
|
||||||
|
highlightCommentId = effect.commentId,
|
||||||
|
)
|
||||||
}
|
}
|
||||||
}.launchIn(this)
|
}.launchIn(this)
|
||||||
}
|
}
|
||||||
@ -138,7 +144,7 @@ class InboxMentionsScreen : Tab {
|
|||||||
}
|
}
|
||||||
items(
|
items(
|
||||||
items = uiState.mentions,
|
items = uiState.mentions,
|
||||||
key = { it.id.toString() + it.read + uiState.unreadOnly },
|
key = { it.id.toString() + uiState.unreadOnly },
|
||||||
) { mention ->
|
) { mention ->
|
||||||
@Composable
|
@Composable
|
||||||
fun List<ActionOnSwipe>.toSwipeActions(): List<SwipeAction> =
|
fun List<ActionOnSwipe>.toSwipeActions(): List<SwipeAction> =
|
||||||
@ -233,18 +239,12 @@ class InboxMentionsScreen : Tab {
|
|||||||
downVoteEnabled = uiState.downVoteEnabled,
|
downVoteEnabled = uiState.downVoteEnabled,
|
||||||
previewMaxLines = uiState.previewMaxLines,
|
previewMaxLines = uiState.previewMaxLines,
|
||||||
onClick = { post ->
|
onClick = { post ->
|
||||||
if (!mention.read) {
|
model.reduce(
|
||||||
model.reduce(
|
InboxMentionsMviModel.Intent.WillOpenDetail(
|
||||||
InboxMentionsMviModel.Intent.MarkAsRead(
|
id = mention.id,
|
||||||
read = true,
|
post = post,
|
||||||
id = mention.id,
|
commentId = mention.comment.id,
|
||||||
),
|
),
|
||||||
)
|
|
||||||
}
|
|
||||||
detailOpener.openPostDetail(
|
|
||||||
post = post,
|
|
||||||
highlightCommentId = mention.comment.id,
|
|
||||||
otherInstance = "",
|
|
||||||
)
|
)
|
||||||
},
|
},
|
||||||
onOpenCreator = { user, instance ->
|
onOpenCreator = { user, instance ->
|
||||||
|
@ -101,13 +101,14 @@ class InboxMentionsViewModel(
|
|||||||
emitEffect(InboxMentionsMviModel.Effect.BackToTop)
|
emitEffect(InboxMentionsMviModel.Effect.BackToTop)
|
||||||
}
|
}
|
||||||
|
|
||||||
is InboxMentionsMviModel.Intent.MarkAsRead -> {
|
is InboxMentionsMviModel.Intent.MarkAsRead ->
|
||||||
val mention = uiState.value.mentions.first { it.id == intent.id }
|
screenModelScope.launch {
|
||||||
markAsRead(
|
val mention = uiState.value.mentions.first { it.id == intent.id }
|
||||||
read = intent.read,
|
markAsRead(
|
||||||
mention = mention,
|
read = intent.read,
|
||||||
)
|
mention = mention,
|
||||||
}
|
)
|
||||||
|
}
|
||||||
|
|
||||||
InboxMentionsMviModel.Intent.HapticIndication -> hapticFeedback.vibrate()
|
InboxMentionsMviModel.Intent.HapticIndication -> hapticFeedback.vibrate()
|
||||||
is InboxMentionsMviModel.Intent.DownVoteComment -> {
|
is InboxMentionsMviModel.Intent.DownVoteComment -> {
|
||||||
@ -119,6 +120,24 @@ class InboxMentionsViewModel(
|
|||||||
val mention = uiState.value.mentions.first { it.id == intent.id }
|
val mention = uiState.value.mentions.first { it.id == intent.id }
|
||||||
toggleUpVoteComment(mention)
|
toggleUpVoteComment(mention)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
is InboxMentionsMviModel.Intent.WillOpenDetail ->
|
||||||
|
screenModelScope.launch {
|
||||||
|
uiState.value.mentions.firstOrNull { it.id == intent.id }?.also { mention ->
|
||||||
|
if (!mention.read) {
|
||||||
|
markAsRead(
|
||||||
|
mention = mention,
|
||||||
|
read = true,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
emitEffect(
|
||||||
|
InboxMentionsMviModel.Effect.OpenDetail(
|
||||||
|
post = intent.post,
|
||||||
|
commentId = intent.commentId,
|
||||||
|
),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -202,33 +221,31 @@ class InboxMentionsViewModel(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun markAsRead(
|
private suspend fun markAsRead(
|
||||||
read: Boolean,
|
read: Boolean,
|
||||||
mention: PersonMentionModel,
|
mention: PersonMentionModel,
|
||||||
) {
|
) {
|
||||||
val auth = identityRepository.authToken.value
|
val auth = identityRepository.authToken.value
|
||||||
screenModelScope.launch {
|
userRepository.setMentionRead(
|
||||||
userRepository.setMentionRead(
|
read = read,
|
||||||
read = read,
|
mentionId = mention.id,
|
||||||
mentionId = mention.id,
|
auth = auth,
|
||||||
auth = auth,
|
)
|
||||||
)
|
val currentState = uiState.value
|
||||||
val currentState = uiState.value
|
if (read && currentState.unreadOnly) {
|
||||||
if (read && currentState.unreadOnly) {
|
updateState {
|
||||||
updateState {
|
it.copy(
|
||||||
it.copy(
|
mentions =
|
||||||
mentions =
|
currentState.mentions.filter { m ->
|
||||||
currentState.mentions.filter { m ->
|
m.id != mention.id
|
||||||
m.id != mention.id
|
},
|
||||||
},
|
)
|
||||||
)
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
val newMention = mention.copy(read = read)
|
|
||||||
handleItemUpdate(newMention)
|
|
||||||
}
|
}
|
||||||
updateUnreadItems()
|
} else {
|
||||||
|
val newMention = mention.copy(read = read)
|
||||||
|
handleItemUpdate(newMention)
|
||||||
}
|
}
|
||||||
|
updateUnreadItems()
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun toggleUpVoteComment(mention: PersonMentionModel) {
|
private fun toggleUpVoteComment(mention: PersonMentionModel) {
|
||||||
|
@ -48,7 +48,9 @@ interface MultiCommunityMviModel :
|
|||||||
val url: String,
|
val url: String,
|
||||||
) : Intent
|
) : Intent
|
||||||
|
|
||||||
data object WillOpenDetail : Intent
|
data class WillOpenDetail(
|
||||||
|
val id: Long,
|
||||||
|
) : Intent
|
||||||
}
|
}
|
||||||
|
|
||||||
data class UiState(
|
data class UiState(
|
||||||
@ -83,5 +85,9 @@ interface MultiCommunityMviModel :
|
|||||||
|
|
||||||
sealed interface Effect {
|
sealed interface Effect {
|
||||||
data object BackToTop : Effect
|
data object BackToTop : Effect
|
||||||
|
|
||||||
|
data class OpenDetail(
|
||||||
|
val post: PostModel,
|
||||||
|
) : Effect
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -138,6 +138,9 @@ class MultiCommunityScreen(
|
|||||||
topAppBarState.contentOffset = 0f
|
topAppBarState.contentOffset = 0f
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
is MultiCommunityMviModel.Effect.OpenDetail ->
|
||||||
|
detailOpener.openPostDetail(post = effect.post)
|
||||||
}
|
}
|
||||||
}.launchIn(this)
|
}.launchIn(this)
|
||||||
}
|
}
|
||||||
@ -282,7 +285,7 @@ class MultiCommunityScreen(
|
|||||||
items(
|
items(
|
||||||
items = uiState.posts,
|
items = uiState.posts,
|
||||||
key = {
|
key = {
|
||||||
it.id.toString() + (it.updateDate ?: it.publishDate) + it.read
|
it.id.toString() + (it.updateDate ?: it.publishDate)
|
||||||
},
|
},
|
||||||
) { post ->
|
) { post ->
|
||||||
LaunchedEffect(post.id) {
|
LaunchedEffect(post.id) {
|
||||||
@ -404,9 +407,9 @@ class MultiCommunityScreen(
|
|||||||
botTagColor = uiState.botTagColor,
|
botTagColor = uiState.botTagColor,
|
||||||
meTagColor = uiState.meTagColor,
|
meTagColor = uiState.meTagColor,
|
||||||
onClick = {
|
onClick = {
|
||||||
model.reduce(MultiCommunityMviModel.Intent.MarkAsRead(post.id))
|
model.reduce(
|
||||||
model.reduce(MultiCommunityMviModel.Intent.WillOpenDetail)
|
MultiCommunityMviModel.Intent.WillOpenDetail(post.id),
|
||||||
detailOpener.openPostDetail(post)
|
)
|
||||||
},
|
},
|
||||||
onDoubleClick =
|
onDoubleClick =
|
||||||
{
|
{
|
||||||
@ -439,8 +442,9 @@ class MultiCommunityScreen(
|
|||||||
)
|
)
|
||||||
},
|
},
|
||||||
onReply = {
|
onReply = {
|
||||||
model.reduce(MultiCommunityMviModel.Intent.WillOpenDetail)
|
model.reduce(
|
||||||
detailOpener.openPostDetail(post)
|
MultiCommunityMviModel.Intent.WillOpenDetail(post.id),
|
||||||
|
)
|
||||||
},
|
},
|
||||||
onOpenImage = { url ->
|
onOpenImage = { url ->
|
||||||
model.reduce(MultiCommunityMviModel.Intent.MarkAsRead(post.id))
|
model.reduce(MultiCommunityMviModel.Intent.MarkAsRead(post.id))
|
||||||
|
@ -191,19 +191,26 @@ class MultiCommunityViewModel(
|
|||||||
|
|
||||||
MultiCommunityMviModel.Intent.ClearRead -> clearRead()
|
MultiCommunityMviModel.Intent.ClearRead -> clearRead()
|
||||||
is MultiCommunityMviModel.Intent.MarkAsRead ->
|
is MultiCommunityMviModel.Intent.MarkAsRead ->
|
||||||
markAsRead(
|
screenModelScope.launch {
|
||||||
post = uiState.value.posts.first { it.id == intent.id },
|
markAsRead(
|
||||||
)
|
post = uiState.value.posts.first { it.id == intent.id },
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
is MultiCommunityMviModel.Intent.Hide ->
|
is MultiCommunityMviModel.Intent.Hide ->
|
||||||
hide(
|
hide(
|
||||||
post = uiState.value.posts.first { it.id == intent.id },
|
post = uiState.value.posts.first { it.id == intent.id },
|
||||||
)
|
)
|
||||||
|
|
||||||
MultiCommunityMviModel.Intent.WillOpenDetail -> {
|
is MultiCommunityMviModel.Intent.WillOpenDetail ->
|
||||||
val state = postPaginationManager.extractState()
|
screenModelScope.launch {
|
||||||
postNavigationManager.push(state)
|
uiState.value.posts.firstOrNull { it.id == intent.id }?.also { post ->
|
||||||
}
|
markAsRead(post)
|
||||||
|
val state = postPaginationManager.extractState()
|
||||||
|
postNavigationManager.push(state)
|
||||||
|
emitEffect(MultiCommunityMviModel.Effect.OpenDetail(post))
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -314,24 +321,22 @@ class MultiCommunityViewModel(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun markAsRead(post: PostModel) {
|
private suspend fun markAsRead(post: PostModel) {
|
||||||
if (post.read) {
|
if (post.read) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
val newPost = post.copy(read = true)
|
val newPost = post.copy(read = true)
|
||||||
screenModelScope.launch {
|
try {
|
||||||
try {
|
val auth = identityRepository.authToken.value.orEmpty()
|
||||||
val auth = identityRepository.authToken.value.orEmpty()
|
postRepository.setRead(
|
||||||
postRepository.setRead(
|
read = true,
|
||||||
read = true,
|
postId = post.id,
|
||||||
postId = post.id,
|
auth = auth,
|
||||||
auth = auth,
|
)
|
||||||
)
|
handlePostUpdate(newPost)
|
||||||
handlePostUpdate(newPost)
|
} catch (e: Throwable) {
|
||||||
} catch (e: Throwable) {
|
e.printStackTrace()
|
||||||
e.printStackTrace()
|
handlePostUpdate(post)
|
||||||
handlePostUpdate(post)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -63,7 +63,10 @@ interface ProfileLoggedMviModel :
|
|||||||
val feedback: Boolean = false,
|
val feedback: Boolean = false,
|
||||||
) : Intent
|
) : Intent
|
||||||
|
|
||||||
data object WillOpenDetail : Intent
|
data class WillOpenDetail(
|
||||||
|
val postId: Long,
|
||||||
|
val commentId: Long? = null,
|
||||||
|
) : Intent
|
||||||
|
|
||||||
data class RestorePost(
|
data class RestorePost(
|
||||||
val id: Long,
|
val id: Long,
|
||||||
@ -96,5 +99,10 @@ interface ProfileLoggedMviModel :
|
|||||||
val isModerator: Boolean = false,
|
val isModerator: Boolean = false,
|
||||||
)
|
)
|
||||||
|
|
||||||
sealed interface Effect
|
sealed interface Effect {
|
||||||
|
data class OpenDetail(
|
||||||
|
val postId: Long,
|
||||||
|
val commentId: Long? = null,
|
||||||
|
) : Effect
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -123,6 +123,18 @@ object ProfileLoggedScreen : Tab {
|
|||||||
model.reduce(ProfileLoggedMviModel.Intent.Refresh)
|
model.reduce(ProfileLoggedMviModel.Intent.Refresh)
|
||||||
}.launchIn(this)
|
}.launchIn(this)
|
||||||
}
|
}
|
||||||
|
LaunchedEffect(model) {
|
||||||
|
model.effects
|
||||||
|
.onEach { effect ->
|
||||||
|
when (effect) {
|
||||||
|
is ProfileLoggedMviModel.Effect.OpenDetail ->
|
||||||
|
detailOpener.openPostDetail(
|
||||||
|
post = PostModel(id = effect.postId),
|
||||||
|
highlightCommentId = effect.commentId,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}.launchIn(this)
|
||||||
|
}
|
||||||
|
|
||||||
if (uiState.initial) {
|
if (uiState.initial) {
|
||||||
ProgressHud()
|
ProgressHud()
|
||||||
@ -277,7 +289,7 @@ object ProfileLoggedScreen : Tab {
|
|||||||
items(
|
items(
|
||||||
items = uiState.posts,
|
items = uiState.posts,
|
||||||
key = {
|
key = {
|
||||||
it.id.toString() + (it.updateDate ?: it.publishDate) + it.read
|
it.id.toString() + (it.updateDate ?: it.publishDate)
|
||||||
},
|
},
|
||||||
) { post ->
|
) { post ->
|
||||||
PostCard(
|
PostCard(
|
||||||
@ -295,12 +307,18 @@ object ProfileLoggedScreen : Tab {
|
|||||||
blurNsfw = false,
|
blurNsfw = false,
|
||||||
downVoteEnabled = uiState.downVoteEnabled,
|
downVoteEnabled = uiState.downVoteEnabled,
|
||||||
onClick = {
|
onClick = {
|
||||||
model.reduce(ProfileLoggedMviModel.Intent.WillOpenDetail)
|
model.reduce(
|
||||||
detailOpener.openPostDetail(post)
|
ProfileLoggedMviModel.Intent.WillOpenDetail(
|
||||||
|
postId = post.id,
|
||||||
|
),
|
||||||
|
)
|
||||||
},
|
},
|
||||||
onReply = {
|
onReply = {
|
||||||
model.reduce(ProfileLoggedMviModel.Intent.WillOpenDetail)
|
model.reduce(
|
||||||
detailOpener.openPostDetail(post)
|
ProfileLoggedMviModel.Intent.WillOpenDetail(
|
||||||
|
postId = post.id,
|
||||||
|
),
|
||||||
|
)
|
||||||
},
|
},
|
||||||
onOpenCommunity = { community, instance ->
|
onOpenCommunity = { community, instance ->
|
||||||
detailOpener.openCommunityDetail(community, instance)
|
detailOpener.openCommunityDetail(community, instance)
|
||||||
@ -494,9 +512,11 @@ object ProfileLoggedScreen : Tab {
|
|||||||
detailOpener.openCommunityDetail(community, instance)
|
detailOpener.openCommunityDetail(community, instance)
|
||||||
},
|
},
|
||||||
onClick = {
|
onClick = {
|
||||||
detailOpener.openPostDetail(
|
model.reduce(
|
||||||
post = PostModel(id = comment.postId),
|
ProfileLoggedMviModel.Intent.WillOpenDetail(
|
||||||
highlightCommentId = comment.id,
|
postId = comment.postId,
|
||||||
|
commentId = comment.id,
|
||||||
|
),
|
||||||
)
|
)
|
||||||
},
|
},
|
||||||
onReply = {
|
onReply = {
|
||||||
|
@ -217,9 +217,18 @@ class ProfileLoggedViewModel(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
ProfileLoggedMviModel.Intent.WillOpenDetail -> {
|
is ProfileLoggedMviModel.Intent.WillOpenDetail ->
|
||||||
val state = postPaginationManager.extractState()
|
screenModelScope.launch {
|
||||||
postNavigationManager.push(state)
|
if (intent.commentId == null) {
|
||||||
|
val state = postPaginationManager.extractState()
|
||||||
|
postNavigationManager.push(state)
|
||||||
|
}
|
||||||
|
emitEffect(
|
||||||
|
ProfileLoggedMviModel.Effect.OpenDetail(
|
||||||
|
postId = intent.postId,
|
||||||
|
commentId = intent.commentId,
|
||||||
|
),
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
is ProfileLoggedMviModel.Intent.RestorePost -> {
|
is ProfileLoggedMviModel.Intent.RestorePost -> {
|
||||||
|
@ -66,7 +66,9 @@ interface PostListMviModel :
|
|||||||
|
|
||||||
data object PauseZombieMode : Intent
|
data object PauseZombieMode : Intent
|
||||||
|
|
||||||
data object WillOpenDetail : Intent
|
data class WillOpenDetail(
|
||||||
|
val id: Long,
|
||||||
|
) : Intent
|
||||||
}
|
}
|
||||||
|
|
||||||
data class UiState(
|
data class UiState(
|
||||||
@ -107,5 +109,9 @@ interface PostListMviModel :
|
|||||||
data class ZombieModeTick(
|
data class ZombieModeTick(
|
||||||
val index: Int,
|
val index: Int,
|
||||||
) : Effect
|
) : Effect
|
||||||
|
|
||||||
|
data class OpenDetail(
|
||||||
|
val post: PostModel,
|
||||||
|
) : Effect
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -188,6 +188,9 @@ class PostListScreen : Screen {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
is PostListMviModel.Effect.OpenDetail ->
|
||||||
|
detailOpener.openPostDetail(effect.post)
|
||||||
}
|
}
|
||||||
}.launchIn(this)
|
}.launchIn(this)
|
||||||
}
|
}
|
||||||
@ -361,7 +364,7 @@ class PostListScreen : Screen {
|
|||||||
key = {
|
key = {
|
||||||
it.id.toString() + (
|
it.id.toString() + (
|
||||||
it.updateDate ?: it.publishDate
|
it.updateDate ?: it.publishDate
|
||||||
) + it.read + uiState.isLogged
|
) + uiState.isLogged
|
||||||
},
|
},
|
||||||
) { post ->
|
) { post ->
|
||||||
LaunchedEffect(post.id) {
|
LaunchedEffect(post.id) {
|
||||||
@ -504,9 +507,7 @@ class PostListScreen : Screen {
|
|||||||
botTagColor = uiState.botTagColor,
|
botTagColor = uiState.botTagColor,
|
||||||
meTagColor = uiState.meTagColor,
|
meTagColor = uiState.meTagColor,
|
||||||
onClick = {
|
onClick = {
|
||||||
model.reduce(PostListMviModel.Intent.MarkAsRead(post.id))
|
model.reduce(PostListMviModel.Intent.WillOpenDetail(post.id))
|
||||||
model.reduce(PostListMviModel.Intent.WillOpenDetail)
|
|
||||||
detailOpener.openPostDetail(post)
|
|
||||||
},
|
},
|
||||||
onDoubleClick =
|
onDoubleClick =
|
||||||
{
|
{
|
||||||
@ -549,9 +550,9 @@ class PostListScreen : Screen {
|
|||||||
},
|
},
|
||||||
onReply = {
|
onReply = {
|
||||||
if (uiState.isLogged) {
|
if (uiState.isLogged) {
|
||||||
model.reduce(PostListMviModel.Intent.MarkAsRead(post.id))
|
model.reduce(
|
||||||
model.reduce(PostListMviModel.Intent.WillOpenDetail)
|
PostListMviModel.Intent.WillOpenDetail(post.id),
|
||||||
detailOpener.openPostDetail(post)
|
)
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
onOpenImage = { url ->
|
onOpenImage = { url ->
|
||||||
|
@ -268,11 +268,12 @@ class PostListViewModel(
|
|||||||
shareHelper.share(intent.url)
|
shareHelper.share(intent.url)
|
||||||
}
|
}
|
||||||
|
|
||||||
is PostListMviModel.Intent.MarkAsRead -> {
|
is PostListMviModel.Intent.MarkAsRead ->
|
||||||
uiState.value.posts.firstOrNull { it.id == intent.id }?.also { post ->
|
screenModelScope.launch {
|
||||||
markAsRead(post = post)
|
uiState.value.posts.firstOrNull { it.id == intent.id }?.also { post ->
|
||||||
|
markAsRead(post = post)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
PostListMviModel.Intent.ClearRead -> clearRead()
|
PostListMviModel.Intent.ClearRead -> clearRead()
|
||||||
is PostListMviModel.Intent.Hide -> {
|
is PostListMviModel.Intent.Hide -> {
|
||||||
@ -298,9 +299,15 @@ class PostListViewModel(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
PostListMviModel.Intent.WillOpenDetail -> {
|
is PostListMviModel.Intent.WillOpenDetail -> {
|
||||||
val state = postPaginationManager.extractState()
|
screenModelScope.launch {
|
||||||
postNavigationManager.push(state)
|
uiState.value.posts.firstOrNull { it.id == intent.id }?.also { post ->
|
||||||
|
markAsRead(post)
|
||||||
|
val state = postPaginationManager.extractState()
|
||||||
|
postNavigationManager.push(state)
|
||||||
|
emitEffect(PostListMviModel.Effect.OpenDetail(post))
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -427,24 +434,22 @@ class PostListViewModel(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun markAsRead(post: PostModel) {
|
private suspend fun markAsRead(post: PostModel) {
|
||||||
if (post.read) {
|
if (post.read) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
val newPost = post.copy(read = true)
|
val newPost = post.copy(read = true)
|
||||||
screenModelScope.launch {
|
try {
|
||||||
try {
|
val auth = identityRepository.authToken.value.orEmpty()
|
||||||
val auth = identityRepository.authToken.value.orEmpty()
|
postRepository.setRead(
|
||||||
postRepository.setRead(
|
read = true,
|
||||||
read = true,
|
postId = post.id,
|
||||||
postId = post.id,
|
auth = auth,
|
||||||
auth = auth,
|
)
|
||||||
)
|
handlePostUpdate(newPost)
|
||||||
handlePostUpdate(newPost)
|
} catch (e: Throwable) {
|
||||||
} catch (e: Throwable) {
|
e.printStackTrace()
|
||||||
e.printStackTrace()
|
handlePostUpdate(post)
|
||||||
handlePostUpdate(post)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -7,6 +7,7 @@ import com.livefast.eattrash.raccoonforlemmy.core.appearance.data.VoteFormat
|
|||||||
import com.livefast.eattrash.raccoonforlemmy.core.architecture.MviModel
|
import com.livefast.eattrash.raccoonforlemmy.core.architecture.MviModel
|
||||||
import com.livefast.eattrash.raccoonforlemmy.core.persistence.data.ActionOnSwipe
|
import com.livefast.eattrash.raccoonforlemmy.core.persistence.data.ActionOnSwipe
|
||||||
import com.livefast.eattrash.raccoonforlemmy.domain.lemmy.data.PersonMentionModel
|
import com.livefast.eattrash.raccoonforlemmy.domain.lemmy.data.PersonMentionModel
|
||||||
|
import com.livefast.eattrash.raccoonforlemmy.domain.lemmy.data.PostModel
|
||||||
|
|
||||||
@Stable
|
@Stable
|
||||||
interface InboxRepliesMviModel :
|
interface InboxRepliesMviModel :
|
||||||
@ -31,6 +32,12 @@ interface InboxRepliesMviModel :
|
|||||||
data class DownVoteComment(
|
data class DownVoteComment(
|
||||||
val id: Long,
|
val id: Long,
|
||||||
) : Intent
|
) : Intent
|
||||||
|
|
||||||
|
data class WillOpenDetail(
|
||||||
|
val id: Long,
|
||||||
|
val post: PostModel,
|
||||||
|
val commentId: Long,
|
||||||
|
) : Intent
|
||||||
}
|
}
|
||||||
|
|
||||||
data class UiState(
|
data class UiState(
|
||||||
@ -58,5 +65,10 @@ interface InboxRepliesMviModel :
|
|||||||
) : Effect
|
) : Effect
|
||||||
|
|
||||||
data object BackToTop : Effect
|
data object BackToTop : Effect
|
||||||
|
|
||||||
|
data class OpenDetail(
|
||||||
|
val post: PostModel,
|
||||||
|
val commentId: Long,
|
||||||
|
) : Effect
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -99,6 +99,12 @@ class InboxRepliesScreen : Tab {
|
|||||||
lazyListState.scrollToItem(0)
|
lazyListState.scrollToItem(0)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
is InboxRepliesMviModel.Effect.OpenDetail ->
|
||||||
|
detailOpener.openPostDetail(
|
||||||
|
post = effect.post,
|
||||||
|
highlightCommentId = effect.commentId,
|
||||||
|
)
|
||||||
}
|
}
|
||||||
}.launchIn(this)
|
}.launchIn(this)
|
||||||
}
|
}
|
||||||
@ -138,7 +144,7 @@ class InboxRepliesScreen : Tab {
|
|||||||
}
|
}
|
||||||
items(
|
items(
|
||||||
items = uiState.replies,
|
items = uiState.replies,
|
||||||
key = { it.id.toString() + it.read + uiState.unreadOnly },
|
key = { it.id.toString() + uiState.unreadOnly },
|
||||||
) { reply ->
|
) { reply ->
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
@ -234,17 +240,12 @@ class InboxRepliesScreen : Tab {
|
|||||||
downVoteEnabled = uiState.downVoteEnabled,
|
downVoteEnabled = uiState.downVoteEnabled,
|
||||||
previewMaxLines = uiState.previewMaxLines,
|
previewMaxLines = uiState.previewMaxLines,
|
||||||
onClick = { post ->
|
onClick = { post ->
|
||||||
if (!reply.read) {
|
model.reduce(
|
||||||
model.reduce(
|
InboxRepliesMviModel.Intent.WillOpenDetail(
|
||||||
InboxRepliesMviModel.Intent.MarkAsRead(
|
id = reply.id,
|
||||||
read = true,
|
post = post,
|
||||||
id = reply.id,
|
commentId = reply.comment.id,
|
||||||
),
|
),
|
||||||
)
|
|
||||||
}
|
|
||||||
detailOpener.openPostDetail(
|
|
||||||
post = post,
|
|
||||||
highlightCommentId = reply.comment.id,
|
|
||||||
)
|
)
|
||||||
},
|
},
|
||||||
onOpenCreator = { user, instance ->
|
onOpenCreator = { user, instance ->
|
||||||
|
@ -101,10 +101,11 @@ class InboxRepliesViewModel(
|
|||||||
emitEffect(InboxRepliesMviModel.Effect.BackToTop)
|
emitEffect(InboxRepliesMviModel.Effect.BackToTop)
|
||||||
}
|
}
|
||||||
|
|
||||||
is InboxRepliesMviModel.Intent.MarkAsRead -> {
|
is InboxRepliesMviModel.Intent.MarkAsRead ->
|
||||||
val reply = uiState.value.replies.first { it.id == intent.id }
|
screenModelScope.launch {
|
||||||
markAsRead(read = intent.read, reply = reply)
|
val reply = uiState.value.replies.first { it.id == intent.id }
|
||||||
}
|
markAsRead(read = intent.read, reply = reply)
|
||||||
|
}
|
||||||
|
|
||||||
InboxRepliesMviModel.Intent.HapticIndication -> hapticFeedback.vibrate()
|
InboxRepliesMviModel.Intent.HapticIndication -> hapticFeedback.vibrate()
|
||||||
is InboxRepliesMviModel.Intent.DownVoteComment -> {
|
is InboxRepliesMviModel.Intent.DownVoteComment -> {
|
||||||
@ -116,6 +117,24 @@ class InboxRepliesViewModel(
|
|||||||
val reply = uiState.value.replies.first { it.id == intent.id }
|
val reply = uiState.value.replies.first { it.id == intent.id }
|
||||||
toggleUpVoteComment(reply)
|
toggleUpVoteComment(reply)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
is InboxRepliesMviModel.Intent.WillOpenDetail ->
|
||||||
|
screenModelScope.launch {
|
||||||
|
uiState.value.replies.firstOrNull { it.id == intent.id }?.also { reply ->
|
||||||
|
if (!reply.read) {
|
||||||
|
markAsRead(
|
||||||
|
reply = reply,
|
||||||
|
read = true,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
emitEffect(
|
||||||
|
InboxRepliesMviModel.Effect.OpenDetail(
|
||||||
|
post = intent.post,
|
||||||
|
commentId = intent.commentId,
|
||||||
|
),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -199,33 +218,31 @@ class InboxRepliesViewModel(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun markAsRead(
|
private suspend fun markAsRead(
|
||||||
read: Boolean,
|
read: Boolean,
|
||||||
reply: PersonMentionModel,
|
reply: PersonMentionModel,
|
||||||
) {
|
) {
|
||||||
val auth = identityRepository.authToken.value
|
val auth = identityRepository.authToken.value
|
||||||
screenModelScope.launch {
|
userRepository.setReplyRead(
|
||||||
userRepository.setReplyRead(
|
read = read,
|
||||||
read = read,
|
replyId = reply.id,
|
||||||
replyId = reply.id,
|
auth = auth,
|
||||||
auth = auth,
|
)
|
||||||
)
|
val currentState = uiState.value
|
||||||
val currentState = uiState.value
|
if (read && currentState.unreadOnly) {
|
||||||
if (read && currentState.unreadOnly) {
|
updateState {
|
||||||
updateState {
|
it.copy(
|
||||||
it.copy(
|
replies =
|
||||||
replies =
|
currentState.replies.filter { r ->
|
||||||
currentState.replies.filter { r ->
|
r.id != reply.id
|
||||||
r.id != reply.id
|
},
|
||||||
},
|
)
|
||||||
)
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
val newItem = reply.copy(read = read)
|
|
||||||
handleItemUpdate(newItem)
|
|
||||||
}
|
}
|
||||||
updateUnreadItems()
|
} else {
|
||||||
|
val newItem = reply.copy(read = read)
|
||||||
|
handleItemUpdate(newItem)
|
||||||
}
|
}
|
||||||
|
updateUnreadItems()
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun toggleUpVoteComment(mention: PersonMentionModel) {
|
private fun toggleUpVoteComment(mention: PersonMentionModel) {
|
||||||
|
@ -66,7 +66,10 @@ interface UserDetailMviModel :
|
|||||||
|
|
||||||
data object BlockInstance : Intent
|
data object BlockInstance : Intent
|
||||||
|
|
||||||
data object WillOpenDetail : Intent
|
data class WillOpenDetail(
|
||||||
|
val postId: Long,
|
||||||
|
val commentId: Long? = null,
|
||||||
|
) : Intent
|
||||||
|
|
||||||
data class UpdateTags(
|
data class UpdateTags(
|
||||||
val ids: List<Long>,
|
val ids: List<Long>,
|
||||||
@ -122,5 +125,10 @@ interface UserDetailMviModel :
|
|||||||
) : Effect
|
) : Effect
|
||||||
|
|
||||||
data object BackToTop : Effect
|
data object BackToTop : Effect
|
||||||
|
|
||||||
|
data class OpenDetail(
|
||||||
|
val postId: Long,
|
||||||
|
val commentId: Long? = null,
|
||||||
|
) : Effect
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -197,6 +197,12 @@ class UserDetailScreen(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
is UserDetailMviModel.Effect.OpenDetail ->
|
||||||
|
detailOpener.openPostDetail(
|
||||||
|
post = PostModel(id = effect.postId),
|
||||||
|
highlightCommentId = effect.commentId,
|
||||||
|
)
|
||||||
}
|
}
|
||||||
}.launchIn(this)
|
}.launchIn(this)
|
||||||
}
|
}
|
||||||
@ -546,7 +552,7 @@ class UserDetailScreen(
|
|||||||
items(
|
items(
|
||||||
items = uiState.posts,
|
items = uiState.posts,
|
||||||
key = {
|
key = {
|
||||||
it.id.toString() + (it.updateDate ?: it.publishDate) + it.read
|
it.id.toString() + (it.updateDate ?: it.publishDate)
|
||||||
},
|
},
|
||||||
) { post ->
|
) { post ->
|
||||||
|
|
||||||
@ -665,8 +671,11 @@ class UserDetailScreen(
|
|||||||
actionButtonsActive = uiState.isLogged,
|
actionButtonsActive = uiState.isLogged,
|
||||||
downVoteEnabled = uiState.downVoteEnabled,
|
downVoteEnabled = uiState.downVoteEnabled,
|
||||||
onClick = {
|
onClick = {
|
||||||
model.reduce(UserDetailMviModel.Intent.WillOpenDetail)
|
model.reduce(
|
||||||
detailOpener.openPostDetail(post)
|
UserDetailMviModel.Intent.WillOpenDetail(
|
||||||
|
postId = post.id,
|
||||||
|
),
|
||||||
|
)
|
||||||
},
|
},
|
||||||
onDoubleClick =
|
onDoubleClick =
|
||||||
{
|
{
|
||||||
@ -709,8 +718,11 @@ class UserDetailScreen(
|
|||||||
},
|
},
|
||||||
onReply =
|
onReply =
|
||||||
{
|
{
|
||||||
model.reduce(UserDetailMviModel.Intent.WillOpenDetail)
|
model.reduce(
|
||||||
detailOpener.openPostDetail(post)
|
UserDetailMviModel.Intent.WillOpenDetail(
|
||||||
|
postId = post.id,
|
||||||
|
),
|
||||||
|
)
|
||||||
}.takeIf { uiState.isLogged && !isOnOtherInstance },
|
}.takeIf { uiState.isLogged && !isOnOtherInstance },
|
||||||
onOpenImage = { url ->
|
onOpenImage = { url ->
|
||||||
navigationCoordinator.pushScreen(
|
navigationCoordinator.pushScreen(
|
||||||
@ -969,9 +981,11 @@ class UserDetailScreen(
|
|||||||
downVoteEnabled = uiState.downVoteEnabled,
|
downVoteEnabled = uiState.downVoteEnabled,
|
||||||
actionButtonsActive = uiState.isLogged,
|
actionButtonsActive = uiState.isLogged,
|
||||||
onClick = {
|
onClick = {
|
||||||
detailOpener.openPostDetail(
|
model.reduce(
|
||||||
post = PostModel(id = comment.postId),
|
UserDetailMviModel.Intent.WillOpenDetail(
|
||||||
highlightCommentId = comment.id,
|
postId = comment.postId,
|
||||||
|
commentId = comment.id,
|
||||||
|
),
|
||||||
)
|
)
|
||||||
},
|
},
|
||||||
onImageClick = { url ->
|
onImageClick = { url ->
|
||||||
|
@ -308,10 +308,19 @@ class UserDetailViewModel(
|
|||||||
UserDetailMviModel.Intent.Block -> blockUser()
|
UserDetailMviModel.Intent.Block -> blockUser()
|
||||||
UserDetailMviModel.Intent.BlockInstance -> blockInstance()
|
UserDetailMviModel.Intent.BlockInstance -> blockInstance()
|
||||||
|
|
||||||
UserDetailMviModel.Intent.WillOpenDetail -> {
|
is UserDetailMviModel.Intent.WillOpenDetail ->
|
||||||
val state = postPaginationManager.extractState()
|
screenModelScope.launch {
|
||||||
postNavigationManager.push(state)
|
if (intent.commentId == null) {
|
||||||
}
|
val state = postPaginationManager.extractState()
|
||||||
|
postNavigationManager.push(state)
|
||||||
|
}
|
||||||
|
emitEffect(
|
||||||
|
UserDetailMviModel.Effect.OpenDetail(
|
||||||
|
postId = intent.postId,
|
||||||
|
commentId = intent.commentId,
|
||||||
|
),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
is UserDetailMviModel.Intent.AddUserTag ->
|
is UserDetailMviModel.Intent.AddUserTag ->
|
||||||
addUserTag(name = intent.name, color = intent.color)
|
addUserTag(name = intent.name, color = intent.color)
|
||||||
|
Loading…
x
Reference in New Issue
Block a user