mirror of
https://github.com/LiveFastEatTrashRaccoon/RaccoonForLemmy.git
synced 2025-02-03 01:57:31 +01:00
refactor(posts, communities): immediate feedback after actions
This commit is contained in:
parent
9e39f240ee
commit
c26ad24358
@ -1,23 +1,23 @@
|
||||
package com.github.diegoberaldin.raccoonforlemmy.core.commonui.di
|
||||
|
||||
import com.github.diegoberaldin.raccoonforlemmy.core.commonui.communitydetail.CommunityDetailScreenViewModel
|
||||
import com.github.diegoberaldin.raccoonforlemmy.core.commonui.postdetail.PostDetailScreenViewModel
|
||||
import com.github.diegoberaldin.raccoonforlemmy.core.commonui.communitydetail.CommunityDetailViewModel
|
||||
import com.github.diegoberaldin.raccoonforlemmy.core.commonui.postdetail.PostDetailViewModel
|
||||
import com.github.diegoberaldin.raccoonforlemmy.domain.lemmy.data.CommunityModel
|
||||
import com.github.diegoberaldin.raccoonforlemmy.domain.lemmy.data.PostModel
|
||||
import org.koin.core.parameter.parametersOf
|
||||
import org.koin.java.KoinJavaComponent.inject
|
||||
|
||||
actual fun getPostDetailScreenViewModel(post: PostModel): PostDetailScreenViewModel {
|
||||
val res: PostDetailScreenViewModel by inject(
|
||||
clazz = PostDetailScreenViewModel::class.java,
|
||||
actual fun getPostDetailScreenViewModel(post: PostModel): PostDetailViewModel {
|
||||
val res: PostDetailViewModel by inject(
|
||||
clazz = PostDetailViewModel::class.java,
|
||||
parameters = { parametersOf(post) },
|
||||
)
|
||||
return res
|
||||
}
|
||||
|
||||
actual fun getCommunityDetailScreenViewModel(community: CommunityModel): CommunityDetailScreenViewModel {
|
||||
val res: CommunityDetailScreenViewModel by inject(
|
||||
clazz = CommunityDetailScreenViewModel::class.java,
|
||||
actual fun getCommunityDetailScreenViewModel(community: CommunityModel): CommunityDetailViewModel {
|
||||
val res: CommunityDetailViewModel by inject(
|
||||
clazz = CommunityDetailViewModel::class.java,
|
||||
parameters = { parametersOf(community) },
|
||||
)
|
||||
return res
|
||||
|
@ -4,8 +4,8 @@ import com.github.diegoberaldin.raccoonforlemmy.core.architecture.MviModel
|
||||
import com.github.diegoberaldin.raccoonforlemmy.domain.lemmy.data.CommunityModel
|
||||
import com.github.diegoberaldin.raccoonforlemmy.domain.lemmy.data.PostModel
|
||||
|
||||
interface CommunityDetailScreenMviModel :
|
||||
MviModel<CommunityDetailScreenMviModel.Intent, CommunityDetailScreenMviModel.UiState, CommunityDetailScreenMviModel.Effect> {
|
||||
interface CommunityDetailMviModel :
|
||||
MviModel<CommunityDetailMviModel.Intent, CommunityDetailMviModel.UiState, CommunityDetailMviModel.Effect> {
|
||||
|
||||
sealed interface Intent {
|
||||
object Refresh : Intent
|
@ -93,7 +93,7 @@ class CommunityDetailScreen(
|
||||
) { padding ->
|
||||
val community = uiState.community
|
||||
val pullRefreshState = rememberPullRefreshState(uiState.refreshing, {
|
||||
model.reduce(CommunityDetailScreenMviModel.Intent.Refresh)
|
||||
model.reduce(CommunityDetailMviModel.Intent.Refresh)
|
||||
})
|
||||
Box(
|
||||
modifier = Modifier.pullRefresh(pullRefreshState),
|
||||
@ -186,7 +186,7 @@ class CommunityDetailScreen(
|
||||
post = post,
|
||||
onUpVote = {
|
||||
model.reduce(
|
||||
CommunityDetailScreenMviModel.Intent.UpVotePost(
|
||||
CommunityDetailMviModel.Intent.UpVotePost(
|
||||
it,
|
||||
post,
|
||||
),
|
||||
@ -194,7 +194,7 @@ class CommunityDetailScreen(
|
||||
},
|
||||
onDownVote = {
|
||||
model.reduce(
|
||||
CommunityDetailScreenMviModel.Intent.DownVotePost(
|
||||
CommunityDetailMviModel.Intent.DownVotePost(
|
||||
it,
|
||||
post,
|
||||
),
|
||||
@ -202,7 +202,7 @@ class CommunityDetailScreen(
|
||||
},
|
||||
onSave = {
|
||||
model.reduce(
|
||||
CommunityDetailScreenMviModel.Intent.SavePost(
|
||||
CommunityDetailMviModel.Intent.SavePost(
|
||||
it,
|
||||
post,
|
||||
),
|
||||
@ -212,7 +212,7 @@ class CommunityDetailScreen(
|
||||
}
|
||||
item {
|
||||
if (!uiState.loading && !uiState.refreshing && uiState.canFetchMore) {
|
||||
model.reduce(CommunityDetailScreenMviModel.Intent.LoadNextPage)
|
||||
model.reduce(CommunityDetailMviModel.Intent.LoadNextPage)
|
||||
}
|
||||
if (uiState.loading && !uiState.refreshing) {
|
||||
Box(
|
||||
|
@ -1,164 +0,0 @@
|
||||
package com.github.diegoberaldin.raccoonforlemmy.core.commonui.communitydetail
|
||||
|
||||
import cafe.adriel.voyager.core.model.ScreenModel
|
||||
import com.github.diegoberaldin.raccoonforlemmy.core.architecture.DefaultMviModel
|
||||
import com.github.diegoberaldin.raccoonforlemmy.core.architecture.MviModel
|
||||
import com.github.diegoberaldin.raccoonforlemmy.core.preferences.KeyStoreKeys
|
||||
import com.github.diegoberaldin.raccoonforlemmy.core.preferences.TemporaryKeyStore
|
||||
import com.github.diegoberaldin.raccoonforlemmy.domain.identity.repository.IdentityRepository
|
||||
import com.github.diegoberaldin.raccoonforlemmy.domain.lemmy.data.CommunityModel
|
||||
import com.github.diegoberaldin.raccoonforlemmy.domain.lemmy.data.PostModel
|
||||
import com.github.diegoberaldin.raccoonforlemmy.domain.lemmy.data.toSortType
|
||||
import com.github.diegoberaldin.raccoonforlemmy.domain.lemmy.repository.CommentRepository
|
||||
import com.github.diegoberaldin.raccoonforlemmy.domain.lemmy.repository.PostsRepository
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.IO
|
||||
import kotlinx.coroutines.launch
|
||||
|
||||
class CommunityDetailScreenViewModel(
|
||||
private val mvi: DefaultMviModel<CommunityDetailScreenMviModel.Intent, CommunityDetailScreenMviModel.UiState, CommunityDetailScreenMviModel.Effect>,
|
||||
private val community: CommunityModel,
|
||||
private val identityRepository: IdentityRepository,
|
||||
private val postsRepository: PostsRepository,
|
||||
private val keyStore: TemporaryKeyStore,
|
||||
) : MviModel<CommunityDetailScreenMviModel.Intent, CommunityDetailScreenMviModel.UiState, CommunityDetailScreenMviModel.Effect> by mvi,
|
||||
ScreenModel {
|
||||
private var currentPage: Int = 1
|
||||
override fun onStarted() {
|
||||
mvi.onStarted()
|
||||
mvi.updateState { it.copy(community = community) }
|
||||
|
||||
if (mvi.uiState.value.posts.isEmpty()) {
|
||||
refresh()
|
||||
}
|
||||
}
|
||||
|
||||
override fun reduce(intent: CommunityDetailScreenMviModel.Intent) {
|
||||
when (intent) {
|
||||
CommunityDetailScreenMviModel.Intent.LoadNextPage -> loadNextPage()
|
||||
CommunityDetailScreenMviModel.Intent.Refresh -> refresh()
|
||||
|
||||
is CommunityDetailScreenMviModel.Intent.DownVotePost -> downVotePost(
|
||||
intent.post,
|
||||
intent.value,
|
||||
)
|
||||
|
||||
is CommunityDetailScreenMviModel.Intent.SavePost -> savePost(
|
||||
intent.post,
|
||||
intent.value,
|
||||
)
|
||||
|
||||
is CommunityDetailScreenMviModel.Intent.UpVotePost -> upVotePost(
|
||||
intent.post,
|
||||
intent.value,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
private fun refresh() {
|
||||
currentPage = 1
|
||||
mvi.updateState { it.copy(canFetchMore = true, refreshing = true) }
|
||||
loadNextPage()
|
||||
}
|
||||
|
||||
private fun loadNextPage() {
|
||||
val currentState = mvi.uiState.value
|
||||
if (!currentState.canFetchMore || currentState.loading) {
|
||||
return
|
||||
}
|
||||
|
||||
mvi.scope.launch(Dispatchers.IO) {
|
||||
mvi.updateState { it.copy(loading = true) }
|
||||
val auth = identityRepository.authToken.value
|
||||
val refreshing = currentState.refreshing
|
||||
val sort = keyStore[KeyStoreKeys.DefaultCommentSortType, 3].toSortType()
|
||||
val commentList = postsRepository.getAll(
|
||||
auth = auth,
|
||||
communityId = community.id,
|
||||
page = currentPage,
|
||||
sort = sort,
|
||||
)
|
||||
currentPage++
|
||||
val canFetchMore = commentList.size >= CommentRepository.DEFAULT_PAGE_SIZE
|
||||
mvi.updateState {
|
||||
val newItems = if (refreshing) {
|
||||
commentList
|
||||
} else {
|
||||
it.posts + commentList
|
||||
}
|
||||
it.copy(
|
||||
posts = newItems,
|
||||
loading = false,
|
||||
canFetchMore = canFetchMore,
|
||||
refreshing = false,
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun upVotePost(post: PostModel, value: Boolean) {
|
||||
mvi.scope.launch(Dispatchers.IO) {
|
||||
val auth = identityRepository.authToken.value.orEmpty()
|
||||
val newItem = postsRepository.upVote(
|
||||
auth = auth,
|
||||
post = post,
|
||||
voted = value,
|
||||
)
|
||||
mvi.updateState {
|
||||
it.copy(
|
||||
posts = it.posts.map { p ->
|
||||
if (p.id == post.id) {
|
||||
newItem
|
||||
} else {
|
||||
p
|
||||
}
|
||||
},
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun downVotePost(post: PostModel, value: Boolean) {
|
||||
mvi.scope.launch(Dispatchers.IO) {
|
||||
val auth = identityRepository.authToken.value.orEmpty()
|
||||
val newItem = postsRepository.downVote(
|
||||
auth = auth,
|
||||
post = post,
|
||||
downVoted = value,
|
||||
)
|
||||
mvi.updateState {
|
||||
it.copy(
|
||||
posts = it.posts.map { p ->
|
||||
if (p.id == post.id) {
|
||||
newItem
|
||||
} else {
|
||||
p
|
||||
}
|
||||
},
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun savePost(post: PostModel, value: Boolean) {
|
||||
mvi.scope.launch(Dispatchers.IO) {
|
||||
val auth = identityRepository.authToken.value.orEmpty()
|
||||
val newItem = postsRepository.save(
|
||||
auth = auth,
|
||||
post = post,
|
||||
saved = value,
|
||||
)
|
||||
mvi.updateState {
|
||||
it.copy(
|
||||
posts = it.posts.map { p ->
|
||||
if (p.id == post.id) {
|
||||
newItem
|
||||
} else {
|
||||
p
|
||||
}
|
||||
},
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,212 @@
|
||||
package com.github.diegoberaldin.raccoonforlemmy.core.commonui.communitydetail
|
||||
|
||||
import cafe.adriel.voyager.core.model.ScreenModel
|
||||
import com.github.diegoberaldin.raccoonforlemmy.core.architecture.DefaultMviModel
|
||||
import com.github.diegoberaldin.raccoonforlemmy.core.architecture.MviModel
|
||||
import com.github.diegoberaldin.raccoonforlemmy.core.preferences.KeyStoreKeys
|
||||
import com.github.diegoberaldin.raccoonforlemmy.core.preferences.TemporaryKeyStore
|
||||
import com.github.diegoberaldin.raccoonforlemmy.domain.identity.repository.IdentityRepository
|
||||
import com.github.diegoberaldin.raccoonforlemmy.domain.lemmy.data.CommunityModel
|
||||
import com.github.diegoberaldin.raccoonforlemmy.domain.lemmy.data.PostModel
|
||||
import com.github.diegoberaldin.raccoonforlemmy.domain.lemmy.data.toSortType
|
||||
import com.github.diegoberaldin.raccoonforlemmy.domain.lemmy.repository.CommentRepository
|
||||
import com.github.diegoberaldin.raccoonforlemmy.domain.lemmy.repository.PostsRepository
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.IO
|
||||
import kotlinx.coroutines.launch
|
||||
|
||||
class CommunityDetailViewModel(
|
||||
private val mvi: DefaultMviModel<CommunityDetailMviModel.Intent, CommunityDetailMviModel.UiState, CommunityDetailMviModel.Effect>,
|
||||
private val community: CommunityModel,
|
||||
private val identityRepository: IdentityRepository,
|
||||
private val postsRepository: PostsRepository,
|
||||
private val keyStore: TemporaryKeyStore,
|
||||
) : MviModel<CommunityDetailMviModel.Intent, CommunityDetailMviModel.UiState, CommunityDetailMviModel.Effect> by mvi,
|
||||
ScreenModel {
|
||||
private var currentPage: Int = 1
|
||||
override fun onStarted() {
|
||||
mvi.onStarted()
|
||||
mvi.updateState { it.copy(community = community) }
|
||||
|
||||
if (mvi.uiState.value.posts.isEmpty()) {
|
||||
refresh()
|
||||
}
|
||||
}
|
||||
|
||||
override fun reduce(intent: CommunityDetailMviModel.Intent) {
|
||||
when (intent) {
|
||||
CommunityDetailMviModel.Intent.LoadNextPage -> loadNextPage()
|
||||
CommunityDetailMviModel.Intent.Refresh -> refresh()
|
||||
|
||||
is CommunityDetailMviModel.Intent.DownVotePost -> downVotePost(
|
||||
intent.post,
|
||||
intent.value,
|
||||
)
|
||||
|
||||
is CommunityDetailMviModel.Intent.SavePost -> savePost(
|
||||
intent.post,
|
||||
intent.value,
|
||||
)
|
||||
|
||||
is CommunityDetailMviModel.Intent.UpVotePost -> upVotePost(
|
||||
intent.post,
|
||||
intent.value,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
private fun refresh() {
|
||||
currentPage = 1
|
||||
mvi.updateState { it.copy(canFetchMore = true, refreshing = true) }
|
||||
loadNextPage()
|
||||
}
|
||||
|
||||
private fun loadNextPage() {
|
||||
val currentState = mvi.uiState.value
|
||||
if (!currentState.canFetchMore || currentState.loading) {
|
||||
return
|
||||
}
|
||||
|
||||
mvi.scope.launch(Dispatchers.IO) {
|
||||
mvi.updateState { it.copy(loading = true) }
|
||||
val auth = identityRepository.authToken.value
|
||||
val refreshing = currentState.refreshing
|
||||
val sort = keyStore[KeyStoreKeys.DefaultCommentSortType, 3].toSortType()
|
||||
val commentList = postsRepository.getAll(
|
||||
auth = auth,
|
||||
communityId = community.id,
|
||||
page = currentPage,
|
||||
sort = sort,
|
||||
)
|
||||
currentPage++
|
||||
val canFetchMore = commentList.size >= CommentRepository.DEFAULT_PAGE_SIZE
|
||||
mvi.updateState {
|
||||
val newItems = if (refreshing) {
|
||||
commentList
|
||||
} else {
|
||||
it.posts + commentList
|
||||
}
|
||||
it.copy(
|
||||
posts = newItems,
|
||||
loading = false,
|
||||
canFetchMore = canFetchMore,
|
||||
refreshing = false,
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun upVotePost(post: PostModel, value: Boolean) {
|
||||
val newPost = postsRepository.asUpVoted(post, value)
|
||||
mvi.updateState {
|
||||
it.copy(
|
||||
posts = it.posts.map { p ->
|
||||
if (p.id == post.id) {
|
||||
newPost
|
||||
} else {
|
||||
p
|
||||
}
|
||||
},
|
||||
)
|
||||
}
|
||||
mvi.scope.launch(Dispatchers.IO) {
|
||||
try {
|
||||
val auth = identityRepository.authToken.value.orEmpty()
|
||||
postsRepository.upVote(
|
||||
auth = auth,
|
||||
post = post,
|
||||
voted = value,
|
||||
)
|
||||
} catch (e: Throwable) {
|
||||
e.printStackTrace()
|
||||
mvi.updateState {
|
||||
it.copy(
|
||||
posts = it.posts.map { p ->
|
||||
if (p.id == post.id) {
|
||||
post
|
||||
} else {
|
||||
p
|
||||
}
|
||||
},
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun downVotePost(post: PostModel, value: Boolean) {
|
||||
val newPost = postsRepository.asDownVoted(post, value)
|
||||
mvi.updateState {
|
||||
it.copy(
|
||||
posts = it.posts.map { p ->
|
||||
if (p.id == post.id) {
|
||||
newPost
|
||||
} else {
|
||||
p
|
||||
}
|
||||
},
|
||||
)
|
||||
}
|
||||
mvi.scope.launch(Dispatchers.IO) {
|
||||
try {
|
||||
val auth = identityRepository.authToken.value.orEmpty()
|
||||
postsRepository.downVote(
|
||||
auth = auth,
|
||||
post = post,
|
||||
downVoted = value,
|
||||
)
|
||||
} catch (e: Throwable) {
|
||||
e.printStackTrace()
|
||||
mvi.updateState {
|
||||
it.copy(
|
||||
posts = it.posts.map { p ->
|
||||
if (p.id == post.id) {
|
||||
post
|
||||
} else {
|
||||
p
|
||||
}
|
||||
},
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun savePost(post: PostModel, value: Boolean) {
|
||||
val newPost = postsRepository.asSaved(post, value)
|
||||
mvi.updateState {
|
||||
it.copy(
|
||||
posts = it.posts.map { p ->
|
||||
if (p.id == post.id) {
|
||||
newPost
|
||||
} else {
|
||||
p
|
||||
}
|
||||
},
|
||||
)
|
||||
}
|
||||
mvi.scope.launch(Dispatchers.IO) {
|
||||
try {
|
||||
val auth = identityRepository.authToken.value.orEmpty()
|
||||
postsRepository.save(
|
||||
auth = auth,
|
||||
post = post,
|
||||
saved = value,
|
||||
)
|
||||
} catch (e: Throwable) {
|
||||
e.printStackTrace()
|
||||
mvi.updateState {
|
||||
it.copy(
|
||||
posts = it.posts.map { p ->
|
||||
if (p.id == post.id) {
|
||||
post
|
||||
} else {
|
||||
p
|
||||
}
|
||||
},
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -1,16 +1,16 @@
|
||||
package com.github.diegoberaldin.raccoonforlemmy.core.commonui.di
|
||||
|
||||
import com.github.diegoberaldin.raccoonforlemmy.core.architecture.DefaultMviModel
|
||||
import com.github.diegoberaldin.raccoonforlemmy.core.commonui.communitydetail.CommunityDetailScreenMviModel
|
||||
import com.github.diegoberaldin.raccoonforlemmy.core.commonui.communitydetail.CommunityDetailScreenViewModel
|
||||
import com.github.diegoberaldin.raccoonforlemmy.core.commonui.postdetail.PostDetailScreenMviModel
|
||||
import com.github.diegoberaldin.raccoonforlemmy.core.commonui.postdetail.PostDetailScreenViewModel
|
||||
import com.github.diegoberaldin.raccoonforlemmy.core.commonui.communitydetail.CommunityDetailMviModel
|
||||
import com.github.diegoberaldin.raccoonforlemmy.core.commonui.communitydetail.CommunityDetailViewModel
|
||||
import com.github.diegoberaldin.raccoonforlemmy.core.commonui.postdetail.PostDetailMviModel
|
||||
import com.github.diegoberaldin.raccoonforlemmy.core.commonui.postdetail.PostDetailViewModel
|
||||
import org.koin.dsl.module
|
||||
|
||||
val commonUiModule = module {
|
||||
factory { params ->
|
||||
PostDetailScreenViewModel(
|
||||
mvi = DefaultMviModel(PostDetailScreenMviModel.UiState()),
|
||||
PostDetailViewModel(
|
||||
mvi = DefaultMviModel(PostDetailMviModel.UiState()),
|
||||
post = params[0],
|
||||
identityRepository = get(),
|
||||
postsRepository = get(),
|
||||
@ -20,8 +20,8 @@ val commonUiModule = module {
|
||||
)
|
||||
}
|
||||
factory { params ->
|
||||
CommunityDetailScreenViewModel(
|
||||
mvi = DefaultMviModel(CommunityDetailScreenMviModel.UiState()),
|
||||
CommunityDetailViewModel(
|
||||
mvi = DefaultMviModel(CommunityDetailMviModel.UiState()),
|
||||
community = params[0],
|
||||
identityRepository = get(),
|
||||
postsRepository = get(),
|
||||
|
@ -1,10 +1,10 @@
|
||||
package com.github.diegoberaldin.raccoonforlemmy.core.commonui.di
|
||||
|
||||
import com.github.diegoberaldin.raccoonforlemmy.core.commonui.communitydetail.CommunityDetailScreenViewModel
|
||||
import com.github.diegoberaldin.raccoonforlemmy.core.commonui.postdetail.PostDetailScreenViewModel
|
||||
import com.github.diegoberaldin.raccoonforlemmy.core.commonui.communitydetail.CommunityDetailViewModel
|
||||
import com.github.diegoberaldin.raccoonforlemmy.core.commonui.postdetail.PostDetailViewModel
|
||||
import com.github.diegoberaldin.raccoonforlemmy.domain.lemmy.data.CommunityModel
|
||||
import com.github.diegoberaldin.raccoonforlemmy.domain.lemmy.data.PostModel
|
||||
|
||||
expect fun getPostDetailScreenViewModel(post: PostModel): PostDetailScreenViewModel
|
||||
expect fun getPostDetailScreenViewModel(post: PostModel): PostDetailViewModel
|
||||
|
||||
expect fun getCommunityDetailScreenViewModel(community: CommunityModel): CommunityDetailScreenViewModel
|
||||
expect fun getCommunityDetailScreenViewModel(community: CommunityModel): CommunityDetailViewModel
|
||||
|
@ -4,8 +4,8 @@ import com.github.diegoberaldin.raccoonforlemmy.core.architecture.MviModel
|
||||
import com.github.diegoberaldin.raccoonforlemmy.domain.lemmy.data.CommentModel
|
||||
import com.github.diegoberaldin.raccoonforlemmy.domain.lemmy.data.PostModel
|
||||
|
||||
interface PostDetailScreenMviModel :
|
||||
MviModel<PostDetailScreenMviModel.Intent, PostDetailScreenMviModel.UiState, PostDetailScreenMviModel.Effect> {
|
||||
interface PostDetailMviModel :
|
||||
MviModel<PostDetailMviModel.Intent, PostDetailMviModel.UiState, PostDetailMviModel.Effect> {
|
||||
|
||||
sealed interface Intent {
|
||||
object Refresh : Intent
|
@ -75,7 +75,7 @@ class PostDetailScreen(
|
||||
) { padding ->
|
||||
val post = uiState.post
|
||||
val pullRefreshState = rememberPullRefreshState(uiState.refreshing, {
|
||||
model.reduce(PostDetailScreenMviModel.Intent.Refresh)
|
||||
model.reduce(PostDetailMviModel.Intent.Refresh)
|
||||
})
|
||||
Box(
|
||||
modifier = Modifier.pullRefresh(pullRefreshState),
|
||||
@ -111,13 +111,13 @@ class PostDetailScreen(
|
||||
downVoted = post.myVote < 0,
|
||||
saved = post.saved,
|
||||
onUpVote = {
|
||||
model.reduce(PostDetailScreenMviModel.Intent.UpVotePost(it, post))
|
||||
model.reduce(PostDetailMviModel.Intent.UpVotePost(it, post))
|
||||
},
|
||||
onDownVote = {
|
||||
model.reduce(PostDetailScreenMviModel.Intent.DownVotePost(it, post))
|
||||
model.reduce(PostDetailMviModel.Intent.DownVotePost(it, post))
|
||||
},
|
||||
onSave = {
|
||||
model.reduce(PostDetailScreenMviModel.Intent.SavePost(it, post))
|
||||
model.reduce(PostDetailMviModel.Intent.SavePost(it, post))
|
||||
},
|
||||
)
|
||||
}
|
||||
@ -126,7 +126,7 @@ class PostDetailScreen(
|
||||
comment = comment,
|
||||
onUpVote = {
|
||||
model.reduce(
|
||||
PostDetailScreenMviModel.Intent.UpVoteComment(
|
||||
PostDetailMviModel.Intent.UpVoteComment(
|
||||
it,
|
||||
comment,
|
||||
),
|
||||
@ -134,7 +134,7 @@ class PostDetailScreen(
|
||||
},
|
||||
onDownVote = {
|
||||
model.reduce(
|
||||
PostDetailScreenMviModel.Intent.DownVoteComment(
|
||||
PostDetailMviModel.Intent.DownVoteComment(
|
||||
it,
|
||||
comment,
|
||||
),
|
||||
@ -142,7 +142,7 @@ class PostDetailScreen(
|
||||
},
|
||||
onSave = {
|
||||
model.reduce(
|
||||
PostDetailScreenMviModel.Intent.SaveComment(
|
||||
PostDetailMviModel.Intent.SaveComment(
|
||||
it,
|
||||
comment,
|
||||
),
|
||||
@ -152,7 +152,7 @@ class PostDetailScreen(
|
||||
}
|
||||
item {
|
||||
if (!uiState.loading && !uiState.refreshing && uiState.canFetchMore) {
|
||||
model.reduce(PostDetailScreenMviModel.Intent.LoadNextPage)
|
||||
model.reduce(PostDetailMviModel.Intent.LoadNextPage)
|
||||
}
|
||||
if (uiState.loading && !uiState.refreshing) {
|
||||
Box(
|
||||
|
@ -1,223 +0,0 @@
|
||||
package com.github.diegoberaldin.raccoonforlemmy.core.commonui.postdetail
|
||||
|
||||
import cafe.adriel.voyager.core.model.ScreenModel
|
||||
import com.github.diegoberaldin.raccoonforlemmy.core.architecture.DefaultMviModel
|
||||
import com.github.diegoberaldin.raccoonforlemmy.core.architecture.MviModel
|
||||
import com.github.diegoberaldin.raccoonforlemmy.core.notifications.NotificationCenter
|
||||
import com.github.diegoberaldin.raccoonforlemmy.core.preferences.KeyStoreKeys
|
||||
import com.github.diegoberaldin.raccoonforlemmy.core.preferences.TemporaryKeyStore
|
||||
import com.github.diegoberaldin.raccoonforlemmy.domain.identity.repository.IdentityRepository
|
||||
import com.github.diegoberaldin.raccoonforlemmy.domain.lemmy.data.CommentModel
|
||||
import com.github.diegoberaldin.raccoonforlemmy.domain.lemmy.data.PostModel
|
||||
import com.github.diegoberaldin.raccoonforlemmy.domain.lemmy.data.toSortType
|
||||
import com.github.diegoberaldin.raccoonforlemmy.domain.lemmy.repository.CommentRepository
|
||||
import com.github.diegoberaldin.raccoonforlemmy.domain.lemmy.repository.PostsRepository
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.IO
|
||||
import kotlinx.coroutines.launch
|
||||
|
||||
class PostDetailScreenViewModel(
|
||||
private val mvi: DefaultMviModel<PostDetailScreenMviModel.Intent, PostDetailScreenMviModel.UiState, PostDetailScreenMviModel.Effect>,
|
||||
private val post: PostModel,
|
||||
private val identityRepository: IdentityRepository,
|
||||
private val postsRepository: PostsRepository,
|
||||
private val commentRepository: CommentRepository,
|
||||
private val keyStore: TemporaryKeyStore,
|
||||
private val notificationCenter: NotificationCenter,
|
||||
) : MviModel<PostDetailScreenMviModel.Intent, PostDetailScreenMviModel.UiState, PostDetailScreenMviModel.Effect> by mvi,
|
||||
ScreenModel {
|
||||
private var currentPage: Int = 1
|
||||
override fun onStarted() {
|
||||
mvi.onStarted()
|
||||
mvi.updateState { it.copy(post = post) }
|
||||
|
||||
if (mvi.uiState.value.comments.isEmpty()) {
|
||||
refresh()
|
||||
}
|
||||
}
|
||||
|
||||
override fun reduce(intent: PostDetailScreenMviModel.Intent) {
|
||||
when (intent) {
|
||||
PostDetailScreenMviModel.Intent.LoadNextPage -> loadNextPage()
|
||||
PostDetailScreenMviModel.Intent.Refresh -> refresh()
|
||||
is PostDetailScreenMviModel.Intent.DownVoteComment -> downVoteComment(
|
||||
intent.comment,
|
||||
intent.value,
|
||||
)
|
||||
|
||||
is PostDetailScreenMviModel.Intent.DownVotePost -> downVotePost(
|
||||
intent.post,
|
||||
intent.value,
|
||||
)
|
||||
|
||||
is PostDetailScreenMviModel.Intent.SaveComment -> saveComment(
|
||||
intent.comment,
|
||||
intent.value,
|
||||
)
|
||||
|
||||
is PostDetailScreenMviModel.Intent.SavePost -> savePost(
|
||||
intent.post,
|
||||
intent.value,
|
||||
)
|
||||
|
||||
is PostDetailScreenMviModel.Intent.UpVoteComment -> upVoteComment(
|
||||
intent.comment,
|
||||
intent.value,
|
||||
)
|
||||
|
||||
is PostDetailScreenMviModel.Intent.UpVotePost -> upVotePost(
|
||||
intent.post,
|
||||
intent.value,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
private fun refresh() {
|
||||
currentPage = 1
|
||||
mvi.updateState { it.copy(canFetchMore = true, refreshing = true) }
|
||||
loadNextPage()
|
||||
}
|
||||
|
||||
private fun loadNextPage() {
|
||||
val currentState = mvi.uiState.value
|
||||
if (!currentState.canFetchMore || currentState.loading) {
|
||||
return
|
||||
}
|
||||
|
||||
mvi.scope.launch(Dispatchers.IO) {
|
||||
mvi.updateState { it.copy(loading = true) }
|
||||
val auth = identityRepository.authToken.value
|
||||
val refreshing = currentState.refreshing
|
||||
val sort = keyStore[KeyStoreKeys.DefaultCommentSortType, 3].toSortType()
|
||||
val commentList = commentRepository.getAll(
|
||||
auth = auth,
|
||||
postId = post.id,
|
||||
page = currentPage,
|
||||
sort = sort,
|
||||
)
|
||||
currentPage++
|
||||
val canFetchMore = commentList.size >= CommentRepository.DEFAULT_PAGE_SIZE
|
||||
mvi.updateState {
|
||||
val newcomments = if (refreshing) {
|
||||
commentList
|
||||
} else {
|
||||
it.comments + commentList
|
||||
}
|
||||
it.copy(
|
||||
comments = newcomments,
|
||||
loading = false,
|
||||
canFetchMore = canFetchMore,
|
||||
refreshing = false,
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun upVotePost(post: PostModel, value: Boolean) {
|
||||
mvi.scope.launch(Dispatchers.IO) {
|
||||
val auth = identityRepository.authToken.value.orEmpty()
|
||||
val newPost = postsRepository.upVote(
|
||||
auth = auth,
|
||||
post = post,
|
||||
voted = value,
|
||||
)
|
||||
mvi.updateState { it.copy(post = newPost) }
|
||||
notificationCenter.send(NotificationCenter.Event.PostUpdate(newPost))
|
||||
}
|
||||
}
|
||||
|
||||
private fun downVotePost(post: PostModel, value: Boolean) {
|
||||
mvi.scope.launch(Dispatchers.IO) {
|
||||
val auth = identityRepository.authToken.value.orEmpty()
|
||||
val newPost = postsRepository.downVote(
|
||||
auth = auth,
|
||||
post = post,
|
||||
downVoted = value,
|
||||
)
|
||||
mvi.updateState { it.copy(post = newPost) }
|
||||
notificationCenter.send(NotificationCenter.Event.PostUpdate(newPost))
|
||||
}
|
||||
}
|
||||
|
||||
private fun savePost(post: PostModel, value: Boolean) {
|
||||
mvi.scope.launch(Dispatchers.IO) {
|
||||
val auth = identityRepository.authToken.value.orEmpty()
|
||||
val newPost = postsRepository.save(
|
||||
auth = auth,
|
||||
post = post,
|
||||
saved = value,
|
||||
)
|
||||
mvi.updateState { it.copy(post = newPost) }
|
||||
notificationCenter.send(NotificationCenter.Event.PostUpdate(newPost))
|
||||
}
|
||||
}
|
||||
|
||||
private fun upVoteComment(comment: CommentModel, value: Boolean) {
|
||||
mvi.scope.launch(Dispatchers.IO) {
|
||||
val auth = identityRepository.authToken.value.orEmpty()
|
||||
val newComment = commentRepository.upVote(
|
||||
auth = auth,
|
||||
comment = comment,
|
||||
voted = value,
|
||||
)
|
||||
mvi.updateState {
|
||||
it.copy(
|
||||
comments = it.comments.map { c ->
|
||||
if (c.id == comment.id) {
|
||||
newComment
|
||||
} else {
|
||||
c
|
||||
}
|
||||
},
|
||||
)
|
||||
}
|
||||
notificationCenter.send(NotificationCenter.Event.CommentUpdate(newComment))
|
||||
}
|
||||
}
|
||||
|
||||
private fun downVoteComment(comment: CommentModel, value: Boolean) {
|
||||
mvi.scope.launch(Dispatchers.IO) {
|
||||
val auth = identityRepository.authToken.value.orEmpty()
|
||||
val newComment = commentRepository.downVote(
|
||||
auth = auth,
|
||||
comment = comment,
|
||||
downVoted = value,
|
||||
)
|
||||
mvi.updateState {
|
||||
it.copy(
|
||||
comments = it.comments.map { c ->
|
||||
if (c.id == comment.id) {
|
||||
newComment
|
||||
} else {
|
||||
c
|
||||
}
|
||||
},
|
||||
)
|
||||
}
|
||||
notificationCenter.send(NotificationCenter.Event.CommentUpdate(newComment))
|
||||
}
|
||||
}
|
||||
|
||||
private fun saveComment(comment: CommentModel, value: Boolean) {
|
||||
mvi.scope.launch(Dispatchers.IO) {
|
||||
val auth = identityRepository.authToken.value.orEmpty()
|
||||
val newComment = commentRepository.save(
|
||||
auth = auth,
|
||||
comment = comment,
|
||||
saved = value,
|
||||
)
|
||||
mvi.updateState {
|
||||
it.copy(
|
||||
comments = it.comments.map { c ->
|
||||
if (c.id == comment.id) {
|
||||
newComment
|
||||
} else {
|
||||
c
|
||||
}
|
||||
},
|
||||
)
|
||||
}
|
||||
notificationCenter.send(NotificationCenter.Event.CommentUpdate(newComment))
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,290 @@
|
||||
package com.github.diegoberaldin.raccoonforlemmy.core.commonui.postdetail
|
||||
|
||||
import cafe.adriel.voyager.core.model.ScreenModel
|
||||
import com.github.diegoberaldin.raccoonforlemmy.core.architecture.DefaultMviModel
|
||||
import com.github.diegoberaldin.raccoonforlemmy.core.architecture.MviModel
|
||||
import com.github.diegoberaldin.raccoonforlemmy.core.notifications.NotificationCenter
|
||||
import com.github.diegoberaldin.raccoonforlemmy.core.preferences.KeyStoreKeys
|
||||
import com.github.diegoberaldin.raccoonforlemmy.core.preferences.TemporaryKeyStore
|
||||
import com.github.diegoberaldin.raccoonforlemmy.domain.identity.repository.IdentityRepository
|
||||
import com.github.diegoberaldin.raccoonforlemmy.domain.lemmy.data.CommentModel
|
||||
import com.github.diegoberaldin.raccoonforlemmy.domain.lemmy.data.PostModel
|
||||
import com.github.diegoberaldin.raccoonforlemmy.domain.lemmy.data.toSortType
|
||||
import com.github.diegoberaldin.raccoonforlemmy.domain.lemmy.repository.CommentRepository
|
||||
import com.github.diegoberaldin.raccoonforlemmy.domain.lemmy.repository.PostsRepository
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.IO
|
||||
import kotlinx.coroutines.launch
|
||||
|
||||
class PostDetailViewModel(
|
||||
private val mvi: DefaultMviModel<PostDetailMviModel.Intent, PostDetailMviModel.UiState, PostDetailMviModel.Effect>,
|
||||
private val post: PostModel,
|
||||
private val identityRepository: IdentityRepository,
|
||||
private val postsRepository: PostsRepository,
|
||||
private val commentRepository: CommentRepository,
|
||||
private val keyStore: TemporaryKeyStore,
|
||||
private val notificationCenter: NotificationCenter,
|
||||
) : MviModel<PostDetailMviModel.Intent, PostDetailMviModel.UiState, PostDetailMviModel.Effect> by mvi,
|
||||
ScreenModel {
|
||||
private var currentPage: Int = 1
|
||||
override fun onStarted() {
|
||||
mvi.onStarted()
|
||||
mvi.updateState { it.copy(post = post) }
|
||||
|
||||
if (mvi.uiState.value.comments.isEmpty()) {
|
||||
refresh()
|
||||
}
|
||||
}
|
||||
|
||||
override fun reduce(intent: PostDetailMviModel.Intent) {
|
||||
when (intent) {
|
||||
PostDetailMviModel.Intent.LoadNextPage -> loadNextPage()
|
||||
PostDetailMviModel.Intent.Refresh -> refresh()
|
||||
is PostDetailMviModel.Intent.DownVoteComment -> downVoteComment(
|
||||
intent.comment,
|
||||
intent.value,
|
||||
)
|
||||
|
||||
is PostDetailMviModel.Intent.DownVotePost -> downVotePost(
|
||||
intent.post,
|
||||
intent.value,
|
||||
)
|
||||
|
||||
is PostDetailMviModel.Intent.SaveComment -> saveComment(
|
||||
intent.comment,
|
||||
intent.value,
|
||||
)
|
||||
|
||||
is PostDetailMviModel.Intent.SavePost -> savePost(
|
||||
intent.post,
|
||||
intent.value,
|
||||
)
|
||||
|
||||
is PostDetailMviModel.Intent.UpVoteComment -> upVoteComment(
|
||||
intent.comment,
|
||||
intent.value,
|
||||
)
|
||||
|
||||
is PostDetailMviModel.Intent.UpVotePost -> upVotePost(
|
||||
intent.post,
|
||||
intent.value,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
private fun refresh() {
|
||||
currentPage = 1
|
||||
mvi.updateState { it.copy(canFetchMore = true, refreshing = true) }
|
||||
loadNextPage()
|
||||
}
|
||||
|
||||
private fun loadNextPage() {
|
||||
val currentState = mvi.uiState.value
|
||||
if (!currentState.canFetchMore || currentState.loading) {
|
||||
return
|
||||
}
|
||||
|
||||
mvi.scope.launch(Dispatchers.IO) {
|
||||
mvi.updateState { it.copy(loading = true) }
|
||||
val auth = identityRepository.authToken.value
|
||||
val refreshing = currentState.refreshing
|
||||
val sort = keyStore[KeyStoreKeys.DefaultCommentSortType, 3].toSortType()
|
||||
val commentList = commentRepository.getAll(
|
||||
auth = auth,
|
||||
postId = post.id,
|
||||
page = currentPage,
|
||||
sort = sort,
|
||||
)
|
||||
currentPage++
|
||||
val canFetchMore = commentList.size >= CommentRepository.DEFAULT_PAGE_SIZE
|
||||
mvi.updateState {
|
||||
val newcomments = if (refreshing) {
|
||||
commentList
|
||||
} else {
|
||||
it.comments + commentList
|
||||
}
|
||||
it.copy(
|
||||
comments = newcomments,
|
||||
loading = false,
|
||||
canFetchMore = canFetchMore,
|
||||
refreshing = false,
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun upVotePost(post: PostModel, value: Boolean) {
|
||||
val newPost = postsRepository.asUpVoted(post, value)
|
||||
mvi.updateState { it.copy(post = newPost) }
|
||||
mvi.scope.launch(Dispatchers.IO) {
|
||||
try {
|
||||
val auth = identityRepository.authToken.value.orEmpty()
|
||||
postsRepository.upVote(
|
||||
auth = auth,
|
||||
post = post,
|
||||
voted = value,
|
||||
)
|
||||
notificationCenter.send(NotificationCenter.Event.PostUpdate(newPost))
|
||||
} catch (e: Throwable) {
|
||||
e.printStackTrace()
|
||||
mvi.updateState { it.copy(post = post) }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun downVotePost(post: PostModel, value: Boolean) {
|
||||
val newPost = postsRepository.asDownVoted(post, value)
|
||||
mvi.updateState { it.copy(post = newPost) }
|
||||
|
||||
mvi.scope.launch(Dispatchers.IO) {
|
||||
try {
|
||||
val auth = identityRepository.authToken.value.orEmpty()
|
||||
postsRepository.downVote(
|
||||
auth = auth,
|
||||
post = post,
|
||||
downVoted = value,
|
||||
)
|
||||
notificationCenter.send(NotificationCenter.Event.PostUpdate(newPost))
|
||||
} catch (e: Throwable) {
|
||||
e.printStackTrace()
|
||||
mvi.updateState { it.copy(post = post) }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun savePost(post: PostModel, value: Boolean) {
|
||||
val newPost = postsRepository.asSaved(post, value)
|
||||
mvi.updateState { it.copy(post = newPost) }
|
||||
mvi.scope.launch(Dispatchers.IO) {
|
||||
try {
|
||||
val auth = identityRepository.authToken.value.orEmpty()
|
||||
postsRepository.save(
|
||||
auth = auth,
|
||||
post = post,
|
||||
saved = value,
|
||||
)
|
||||
notificationCenter.send(NotificationCenter.Event.PostUpdate(newPost))
|
||||
} catch (e: Throwable) {
|
||||
e.printStackTrace()
|
||||
mvi.updateState { it.copy(post = post) }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun upVoteComment(comment: CommentModel, value: Boolean) {
|
||||
val newComment = commentRepository.asUpVoted(comment, value)
|
||||
mvi.updateState {
|
||||
it.copy(
|
||||
comments = it.comments.map { c ->
|
||||
if (c.id == comment.id) {
|
||||
newComment
|
||||
} else {
|
||||
c
|
||||
}
|
||||
},
|
||||
)
|
||||
}
|
||||
mvi.scope.launch(Dispatchers.IO) {
|
||||
try {
|
||||
val auth = identityRepository.authToken.value.orEmpty()
|
||||
commentRepository.upVote(
|
||||
auth = auth,
|
||||
comment = comment,
|
||||
voted = value,
|
||||
)
|
||||
notificationCenter.send(NotificationCenter.Event.CommentUpdate(newComment))
|
||||
} catch (e: Throwable) {
|
||||
e.printStackTrace()
|
||||
mvi.updateState {
|
||||
it.copy(
|
||||
comments = it.comments.map { c ->
|
||||
if (c.id == comment.id) {
|
||||
comment
|
||||
} else {
|
||||
c
|
||||
}
|
||||
},
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun downVoteComment(comment: CommentModel, value: Boolean) {
|
||||
val newComment = commentRepository.asDownVoted(comment, value)
|
||||
mvi.updateState {
|
||||
it.copy(
|
||||
comments = it.comments.map { c ->
|
||||
if (c.id == comment.id) {
|
||||
newComment
|
||||
} else {
|
||||
c
|
||||
}
|
||||
},
|
||||
)
|
||||
}
|
||||
mvi.scope.launch(Dispatchers.IO) {
|
||||
try {
|
||||
val auth = identityRepository.authToken.value.orEmpty()
|
||||
commentRepository.downVote(
|
||||
auth = auth,
|
||||
comment = comment,
|
||||
downVoted = value,
|
||||
)
|
||||
notificationCenter.send(NotificationCenter.Event.CommentUpdate(newComment))
|
||||
} catch (e: Throwable) {
|
||||
e.printStackTrace()
|
||||
mvi.updateState {
|
||||
it.copy(
|
||||
comments = it.comments.map { c ->
|
||||
if (c.id == comment.id) {
|
||||
comment
|
||||
} else {
|
||||
c
|
||||
}
|
||||
},
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun saveComment(comment: CommentModel, value: Boolean) {
|
||||
val newComment = commentRepository.asSaved(comment, value)
|
||||
mvi.updateState {
|
||||
it.copy(
|
||||
comments = it.comments.map { c ->
|
||||
if (c.id == comment.id) {
|
||||
newComment
|
||||
} else {
|
||||
c
|
||||
}
|
||||
},
|
||||
)
|
||||
}
|
||||
mvi.scope.launch(Dispatchers.IO) {
|
||||
try {
|
||||
val auth = identityRepository.authToken.value.orEmpty()
|
||||
commentRepository.save(
|
||||
auth = auth,
|
||||
comment = comment,
|
||||
saved = value,
|
||||
)
|
||||
notificationCenter.send(NotificationCenter.Event.CommentUpdate(newComment))
|
||||
} catch (e: Throwable) {
|
||||
e.printStackTrace()
|
||||
mvi.updateState {
|
||||
it.copy(
|
||||
comments = it.comments.map { c ->
|
||||
if (c.id == comment.id) {
|
||||
comment
|
||||
} else {
|
||||
c
|
||||
}
|
||||
},
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -1,30 +1,30 @@
|
||||
package com.github.diegoberaldin.raccoonforlemmy.core.commonui.di
|
||||
|
||||
import com.github.diegoberaldin.raccoonforlemmy.core.commonui.communitydetail.CommunityDetailScreenViewModel
|
||||
import com.github.diegoberaldin.raccoonforlemmy.core.commonui.postdetail.PostDetailScreenViewModel
|
||||
import com.github.diegoberaldin.raccoonforlemmy.core.commonui.communitydetail.CommunityDetailViewModel
|
||||
import com.github.diegoberaldin.raccoonforlemmy.core.commonui.postdetail.PostDetailViewModel
|
||||
import com.github.diegoberaldin.raccoonforlemmy.domain.lemmy.data.CommunityModel
|
||||
import com.github.diegoberaldin.raccoonforlemmy.domain.lemmy.data.PostModel
|
||||
import org.koin.core.component.KoinComponent
|
||||
import org.koin.core.component.inject
|
||||
import org.koin.core.parameter.parametersOf
|
||||
|
||||
actual fun getPostDetailScreenViewModel(post: PostModel): PostDetailScreenViewModel =
|
||||
actual fun getPostDetailScreenViewModel(post: PostModel): PostDetailViewModel =
|
||||
PostDetailScreenViewModelHelper.getPostDetailModel(post)
|
||||
|
||||
actual fun getCommunityDetailScreenViewModel(community: CommunityModel): CommunityDetailScreenViewModel =
|
||||
actual fun getCommunityDetailScreenViewModel(community: CommunityModel): CommunityDetailViewModel =
|
||||
PostDetailScreenViewModelHelper.getCommunityDetailModel(community)
|
||||
|
||||
object PostDetailScreenViewModelHelper : KoinComponent {
|
||||
|
||||
fun getPostDetailModel(post: PostModel): PostDetailScreenViewModel {
|
||||
val model: PostDetailScreenViewModel by inject(
|
||||
fun getPostDetailModel(post: PostModel): PostDetailViewModel {
|
||||
val model: PostDetailViewModel by inject(
|
||||
parameters = { parametersOf(post) },
|
||||
)
|
||||
return model
|
||||
}
|
||||
|
||||
fun getCommunityDetailModel(community: CommunityModel): CommunityDetailScreenViewModel {
|
||||
val model: CommunityDetailScreenViewModel by inject(
|
||||
fun getCommunityDetailModel(community: CommunityModel): CommunityDetailViewModel {
|
||||
val model: CommunityDetailViewModel by inject(
|
||||
parameters = { parametersOf(community) },
|
||||
)
|
||||
return model
|
||||
|
@ -36,49 +36,52 @@ class CommentRepository(
|
||||
return dto.map { it.toModel() }
|
||||
}
|
||||
|
||||
suspend fun upVote(comment: CommentModel, auth: String, voted: Boolean): CommentModel {
|
||||
fun asUpVoted(comment: CommentModel, voted: Boolean) = comment.copy(
|
||||
myVote = if (voted) 1 else 0,
|
||||
score = when {
|
||||
voted && comment.myVote < 0 -> comment.score + 2
|
||||
voted -> comment.score + 1
|
||||
!voted -> comment.score - 1
|
||||
else -> comment.score
|
||||
},
|
||||
)
|
||||
|
||||
suspend fun upVote(comment: CommentModel, auth: String, voted: Boolean) {
|
||||
val data = CreateCommentLikeForm(
|
||||
commentId = comment.id,
|
||||
score = if (voted) 1 else 0,
|
||||
auth = auth,
|
||||
)
|
||||
services.comment.like(data)
|
||||
return comment.copy(
|
||||
myVote = if (voted) 1 else 0,
|
||||
score = when {
|
||||
voted && comment.myVote < 0 -> comment.score + 2
|
||||
voted -> comment.score + 1
|
||||
!voted -> comment.score - 1
|
||||
else -> comment.score
|
||||
},
|
||||
)
|
||||
}
|
||||
|
||||
suspend fun downVote(comment: CommentModel, auth: String, downVoted: Boolean): CommentModel {
|
||||
fun asDownVoted(comment: CommentModel, downVoted: Boolean) = comment.copy(
|
||||
myVote = if (downVoted) -1 else 0,
|
||||
score = when {
|
||||
downVoted && comment.myVote > 0 -> comment.score - 2
|
||||
downVoted -> comment.score - 1
|
||||
!downVoted -> comment.score + 1
|
||||
else -> comment.score
|
||||
},
|
||||
)
|
||||
|
||||
suspend fun downVote(comment: CommentModel, auth: String, downVoted: Boolean) {
|
||||
val data = CreateCommentLikeForm(
|
||||
commentId = comment.id,
|
||||
score = if (downVoted) -1 else 0,
|
||||
auth = auth,
|
||||
)
|
||||
services.comment.like(data)
|
||||
return comment.copy(
|
||||
myVote = if (downVoted) -1 else 0,
|
||||
score = when {
|
||||
downVoted && comment.myVote > 0 -> comment.score - 2
|
||||
downVoted -> comment.score - 1
|
||||
!downVoted -> comment.score + 1
|
||||
else -> comment.score
|
||||
},
|
||||
)
|
||||
}
|
||||
|
||||
suspend fun save(comment: CommentModel, auth: String, saved: Boolean): CommentModel {
|
||||
fun asSaved(comment: CommentModel, saved: Boolean) = comment.copy(saved = saved)
|
||||
|
||||
suspend fun save(comment: CommentModel, auth: String, saved: Boolean) {
|
||||
val data = SaveCommentForm(
|
||||
commentId = comment.id,
|
||||
save = saved,
|
||||
auth = auth,
|
||||
)
|
||||
services.comment.save(data)
|
||||
return comment.copy(saved = saved)
|
||||
}
|
||||
}
|
||||
|
@ -37,49 +37,52 @@ class PostsRepository(
|
||||
return dto.map { it.toModel() }
|
||||
}
|
||||
|
||||
suspend fun upVote(post: PostModel, auth: String, voted: Boolean): PostModel {
|
||||
fun asUpVoted(post: PostModel, voted: Boolean) = post.copy(
|
||||
myVote = if (voted) 1 else 0,
|
||||
score = when {
|
||||
voted && post.myVote < 0 -> post.score + 2
|
||||
voted -> post.score + 1
|
||||
!voted -> post.score - 1
|
||||
else -> post.score
|
||||
},
|
||||
)
|
||||
|
||||
suspend fun upVote(post: PostModel, auth: String, voted: Boolean) {
|
||||
val data = CreatePostLikeForm(
|
||||
postId = post.id,
|
||||
score = if (voted) 1 else 0,
|
||||
auth = auth,
|
||||
)
|
||||
services.post.like(data)
|
||||
return post.copy(
|
||||
myVote = if (voted) 1 else 0,
|
||||
score = when {
|
||||
voted && post.myVote < 0 -> post.score + 2
|
||||
voted -> post.score + 1
|
||||
!voted -> post.score - 1
|
||||
else -> post.score
|
||||
},
|
||||
)
|
||||
}
|
||||
|
||||
suspend fun downVote(post: PostModel, auth: String, downVoted: Boolean): PostModel {
|
||||
fun asDownVoted(post: PostModel, downVoted: Boolean) = post.copy(
|
||||
myVote = if (downVoted) -1 else 0,
|
||||
score = when {
|
||||
downVoted && post.myVote > 0 -> post.score - 2
|
||||
downVoted -> post.score - 1
|
||||
!downVoted -> post.score + 1
|
||||
else -> post.score
|
||||
},
|
||||
)
|
||||
|
||||
suspend fun downVote(post: PostModel, auth: String, downVoted: Boolean) {
|
||||
val data = CreatePostLikeForm(
|
||||
postId = post.id,
|
||||
score = if (downVoted) -1 else 0,
|
||||
auth = auth,
|
||||
)
|
||||
services.post.like(data)
|
||||
return post.copy(
|
||||
myVote = if (downVoted) -1 else 0,
|
||||
score = when {
|
||||
downVoted && post.myVote > 0 -> post.score - 2
|
||||
downVoted -> post.score - 1
|
||||
!downVoted -> post.score + 1
|
||||
else -> post.score
|
||||
},
|
||||
)
|
||||
}
|
||||
|
||||
suspend fun save(post: PostModel, auth: String, saved: Boolean): PostModel {
|
||||
fun asSaved(post: PostModel, saved: Boolean): PostModel = post.copy(saved = saved)
|
||||
|
||||
suspend fun save(post: PostModel, auth: String, saved: Boolean) {
|
||||
val data = SavePostForm(
|
||||
postId = post.id,
|
||||
save = saved,
|
||||
auth = auth,
|
||||
)
|
||||
services.post.save(data)
|
||||
return post.copy(saved = saved)
|
||||
}
|
||||
}
|
||||
|
@ -1,9 +1,9 @@
|
||||
package com.github.diegoberaldin.raccoonforlemmy.feature.home.di
|
||||
|
||||
import com.github.diegoberaldin.raccoonforlemmy.feature.home.viewmodel.HomeScreenModel
|
||||
import com.github.diegoberaldin.raccoonforlemmy.feature.home.postlist.PostListViewModel
|
||||
import org.koin.java.KoinJavaComponent.inject
|
||||
|
||||
actual fun getHomeScreenModel(): HomeScreenModel {
|
||||
val res: HomeScreenModel by inject(HomeScreenModel::class.java)
|
||||
actual fun getHomeScreenModel(): PostListViewModel {
|
||||
val res: PostListViewModel by inject(PostListViewModel::class.java)
|
||||
return res
|
||||
}
|
||||
|
@ -3,8 +3,8 @@ package com.github.diegoberaldin.raccoonforlemmy.feature.home.di
|
||||
import com.github.diegoberaldin.raccoonforlemmy.core.architecture.DefaultMviModel
|
||||
import com.github.diegoberaldin.raccoonforlemmy.core.commonui.di.commonUiModule
|
||||
import com.github.diegoberaldin.raccoonforlemmy.domain.lemmy.repository.di.postsRepositoryModule
|
||||
import com.github.diegoberaldin.raccoonforlemmy.feature.home.viewmodel.HomeScreenModel
|
||||
import com.github.diegoberaldin.raccoonforlemmy.feature.home.viewmodel.HomeScreenMviModel
|
||||
import com.github.diegoberaldin.raccoonforlemmy.feature.home.postlist.PostListViewModel
|
||||
import com.github.diegoberaldin.raccoonforlemmy.feature.home.postlist.PostListMviModel
|
||||
import org.koin.dsl.module
|
||||
|
||||
val homeTabModule = module {
|
||||
@ -13,8 +13,8 @@ val homeTabModule = module {
|
||||
commonUiModule,
|
||||
)
|
||||
factory {
|
||||
HomeScreenModel(
|
||||
mvi = DefaultMviModel(HomeScreenMviModel.UiState()),
|
||||
PostListViewModel(
|
||||
mvi = DefaultMviModel(PostListMviModel.UiState()),
|
||||
postsRepository = get(),
|
||||
apiConfigRepository = get(),
|
||||
identityRepository = get(),
|
||||
|
@ -1,5 +1,5 @@
|
||||
package com.github.diegoberaldin.raccoonforlemmy.feature.home.di
|
||||
|
||||
import com.github.diegoberaldin.raccoonforlemmy.feature.home.viewmodel.HomeScreenModel
|
||||
import com.github.diegoberaldin.raccoonforlemmy.feature.home.postlist.PostListViewModel
|
||||
|
||||
expect fun getHomeScreenModel(): HomeScreenModel
|
||||
expect fun getHomeScreenModel(): PostListViewModel
|
||||
|
@ -1,12 +1,12 @@
|
||||
package com.github.diegoberaldin.raccoonforlemmy.feature.home.viewmodel
|
||||
package com.github.diegoberaldin.raccoonforlemmy.feature.home.postlist
|
||||
|
||||
import com.github.diegoberaldin.raccoonforlemmy.core.architecture.MviModel
|
||||
import com.github.diegoberaldin.raccoonforlemmy.domain.lemmy.data.ListingType
|
||||
import com.github.diegoberaldin.raccoonforlemmy.domain.lemmy.data.PostModel
|
||||
import com.github.diegoberaldin.raccoonforlemmy.domain.lemmy.data.SortType
|
||||
|
||||
interface HomeScreenMviModel :
|
||||
MviModel<HomeScreenMviModel.Intent, HomeScreenMviModel.UiState, HomeScreenMviModel.Effect> {
|
||||
interface PostListMviModel :
|
||||
MviModel<PostListMviModel.Intent, PostListMviModel.UiState, PostListMviModel.Effect> {
|
||||
|
||||
sealed interface Intent {
|
||||
object Refresh : Intent
|
@ -1,4 +1,4 @@
|
||||
package com.github.diegoberaldin.raccoonforlemmy.feature.home.ui
|
||||
package com.github.diegoberaldin.raccoonforlemmy.feature.home.postlist
|
||||
|
||||
import androidx.compose.foundation.layout.Arrangement
|
||||
import androidx.compose.foundation.layout.Box
|
||||
@ -36,7 +36,6 @@ import com.github.diegoberaldin.raccoonforlemmy.core.commonui.modals.ListingType
|
||||
import com.github.diegoberaldin.raccoonforlemmy.core.commonui.modals.SortBottomSheet
|
||||
import com.github.diegoberaldin.raccoonforlemmy.core.commonui.postdetail.PostDetailScreen
|
||||
import com.github.diegoberaldin.raccoonforlemmy.feature.home.di.getHomeScreenModel
|
||||
import com.github.diegoberaldin.raccoonforlemmy.feature.home.viewmodel.HomeScreenMviModel
|
||||
|
||||
class PostListScreen : Screen {
|
||||
@OptIn(ExperimentalMaterial3Api::class, ExperimentalMaterialApi::class)
|
||||
@ -60,7 +59,7 @@ class PostListScreen : Screen {
|
||||
ListingTypeBottomSheet(
|
||||
isLogged = uiState.isLogged,
|
||||
onSelected = {
|
||||
model.reduce(HomeScreenMviModel.Intent.ChangeListing(it))
|
||||
model.reduce(PostListMviModel.Intent.ChangeListing(it))
|
||||
},
|
||||
onHide = {
|
||||
bottomSheetNavigator.hide()
|
||||
@ -72,7 +71,7 @@ class PostListScreen : Screen {
|
||||
bottomSheetNavigator.show(
|
||||
SortBottomSheet(
|
||||
onSelected = {
|
||||
model.reduce(HomeScreenMviModel.Intent.ChangeSort(it))
|
||||
model.reduce(PostListMviModel.Intent.ChangeSort(it))
|
||||
},
|
||||
onHide = {
|
||||
bottomSheetNavigator.hide()
|
||||
@ -84,7 +83,7 @@ class PostListScreen : Screen {
|
||||
},
|
||||
) { padding ->
|
||||
val pullRefreshState = rememberPullRefreshState(uiState.refreshing, {
|
||||
model.reduce(HomeScreenMviModel.Intent.Refresh)
|
||||
model.reduce(PostListMviModel.Intent.Refresh)
|
||||
})
|
||||
Box(
|
||||
modifier = Modifier.padding(padding).pullRefresh(pullRefreshState),
|
||||
@ -117,19 +116,19 @@ class PostListScreen : Screen {
|
||||
)
|
||||
},
|
||||
onUpVote = {
|
||||
model.reduce(HomeScreenMviModel.Intent.UpVotePost(it, post))
|
||||
model.reduce(PostListMviModel.Intent.UpVotePost(it, post))
|
||||
},
|
||||
onDownVote = {
|
||||
model.reduce(HomeScreenMviModel.Intent.DownVotePost(it, post))
|
||||
model.reduce(PostListMviModel.Intent.DownVotePost(it, post))
|
||||
},
|
||||
onSave = {
|
||||
model.reduce(HomeScreenMviModel.Intent.SavePost(it, post))
|
||||
model.reduce(PostListMviModel.Intent.SavePost(it, post))
|
||||
},
|
||||
)
|
||||
}
|
||||
item {
|
||||
if (!uiState.loading && !uiState.refreshing && uiState.canFetchMore) {
|
||||
model.reduce(HomeScreenMviModel.Intent.LoadNextPage)
|
||||
model.reduce(PostListMviModel.Intent.LoadNextPage)
|
||||
}
|
||||
if (uiState.loading && !uiState.refreshing) {
|
||||
Box(
|
@ -1,4 +1,4 @@
|
||||
package com.github.diegoberaldin.raccoonforlemmy.feature.home.viewmodel
|
||||
package com.github.diegoberaldin.raccoonforlemmy.feature.home.postlist
|
||||
|
||||
import cafe.adriel.voyager.core.model.ScreenModel
|
||||
import com.github.diegoberaldin.raccoonforlemmy.core.architecture.DefaultMviModel
|
||||
@ -22,27 +22,27 @@ import kotlinx.coroutines.flow.map
|
||||
import kotlinx.coroutines.flow.onEach
|
||||
import kotlinx.coroutines.launch
|
||||
|
||||
class HomeScreenModel(
|
||||
private val mvi: DefaultMviModel<HomeScreenMviModel.Intent, HomeScreenMviModel.UiState, HomeScreenMviModel.Effect>,
|
||||
class PostListViewModel(
|
||||
private val mvi: DefaultMviModel<PostListMviModel.Intent, PostListMviModel.UiState, PostListMviModel.Effect>,
|
||||
private val postsRepository: PostsRepository,
|
||||
private val apiConfigRepository: ApiConfigurationRepository,
|
||||
private val identityRepository: IdentityRepository,
|
||||
private val keyStore: TemporaryKeyStore,
|
||||
private val notificationCenter: NotificationCenter,
|
||||
) : ScreenModel,
|
||||
MviModel<HomeScreenMviModel.Intent, HomeScreenMviModel.UiState, HomeScreenMviModel.Effect> by mvi {
|
||||
MviModel<PostListMviModel.Intent, PostListMviModel.UiState, PostListMviModel.Effect> by mvi {
|
||||
|
||||
private var currentPage: Int = 1
|
||||
|
||||
override fun reduce(intent: HomeScreenMviModel.Intent) {
|
||||
override fun reduce(intent: PostListMviModel.Intent) {
|
||||
when (intent) {
|
||||
HomeScreenMviModel.Intent.LoadNextPage -> loadNextPage()
|
||||
HomeScreenMviModel.Intent.Refresh -> refresh()
|
||||
is HomeScreenMviModel.Intent.ChangeSort -> applySortType(intent.value)
|
||||
is HomeScreenMviModel.Intent.ChangeListing -> applyListingType(intent.value)
|
||||
is HomeScreenMviModel.Intent.DownVotePost -> downVote(intent.post, intent.value)
|
||||
is HomeScreenMviModel.Intent.SavePost -> save(intent.post, intent.value)
|
||||
is HomeScreenMviModel.Intent.UpVotePost -> upVote(intent.post, intent.value)
|
||||
PostListMviModel.Intent.LoadNextPage -> loadNextPage()
|
||||
PostListMviModel.Intent.Refresh -> refresh()
|
||||
is PostListMviModel.Intent.ChangeSort -> applySortType(intent.value)
|
||||
is PostListMviModel.Intent.ChangeListing -> applyListingType(intent.value)
|
||||
is PostListMviModel.Intent.DownVotePost -> downVote(intent.post, intent.value)
|
||||
is PostListMviModel.Intent.SavePost -> save(intent.post, intent.value)
|
||||
is PostListMviModel.Intent.UpVotePost -> upVote(intent.post, intent.value)
|
||||
}
|
||||
}
|
||||
|
||||
@ -143,67 +143,115 @@ class HomeScreenModel(
|
||||
}
|
||||
|
||||
private fun upVote(post: PostModel, value: Boolean) {
|
||||
mvi.scope.launch(Dispatchers.IO) {
|
||||
val auth = identityRepository.authToken.value.orEmpty()
|
||||
val newPost = postsRepository.upVote(
|
||||
post = post,
|
||||
auth = auth,
|
||||
voted = value,
|
||||
val newPost = postsRepository.asUpVoted(post, value)
|
||||
mvi.updateState {
|
||||
it.copy(
|
||||
posts = it.posts.map { p ->
|
||||
if (p.id == post.id) {
|
||||
newPost
|
||||
} else {
|
||||
p
|
||||
}
|
||||
},
|
||||
)
|
||||
mvi.updateState {
|
||||
it.copy(
|
||||
posts = it.posts.map { p ->
|
||||
if (p.id == post.id) {
|
||||
newPost
|
||||
} else {
|
||||
p
|
||||
}
|
||||
},
|
||||
}
|
||||
mvi.scope.launch(Dispatchers.IO) {
|
||||
try {
|
||||
val auth = identityRepository.authToken.value.orEmpty()
|
||||
postsRepository.upVote(
|
||||
post = post,
|
||||
auth = auth,
|
||||
voted = value,
|
||||
)
|
||||
} catch (e: Throwable) {
|
||||
e.printStackTrace()
|
||||
mvi.updateState {
|
||||
it.copy(
|
||||
posts = it.posts.map { p ->
|
||||
if (p.id == post.id) {
|
||||
post
|
||||
} else {
|
||||
p
|
||||
}
|
||||
},
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun downVote(post: PostModel, value: Boolean) {
|
||||
mvi.scope.launch(Dispatchers.IO) {
|
||||
val auth = identityRepository.authToken.value.orEmpty()
|
||||
val newPost = postsRepository.downVote(
|
||||
post = post,
|
||||
auth = auth,
|
||||
downVoted = value,
|
||||
val newPost = postsRepository.asDownVoted(post, value)
|
||||
mvi.updateState {
|
||||
it.copy(
|
||||
posts = it.posts.map { p ->
|
||||
if (p.id == post.id) {
|
||||
newPost
|
||||
} else {
|
||||
p
|
||||
}
|
||||
},
|
||||
)
|
||||
mvi.updateState {
|
||||
it.copy(
|
||||
posts = it.posts.map { p ->
|
||||
if (p.id == post.id) {
|
||||
newPost
|
||||
} else {
|
||||
p
|
||||
}
|
||||
},
|
||||
}
|
||||
mvi.scope.launch(Dispatchers.IO) {
|
||||
try {
|
||||
val auth = identityRepository.authToken.value.orEmpty()
|
||||
postsRepository.downVote(
|
||||
post = post,
|
||||
auth = auth,
|
||||
downVoted = value,
|
||||
)
|
||||
} catch (e: Throwable) {
|
||||
e.printStackTrace()
|
||||
mvi.updateState {
|
||||
it.copy(
|
||||
posts = it.posts.map { p ->
|
||||
if (p.id == post.id) {
|
||||
post
|
||||
} else {
|
||||
p
|
||||
}
|
||||
},
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun save(post: PostModel, value: Boolean) {
|
||||
mvi.scope.launch(Dispatchers.IO) {
|
||||
val auth = identityRepository.authToken.value.orEmpty()
|
||||
val newPost = postsRepository.save(
|
||||
post = post,
|
||||
auth = auth,
|
||||
saved = value,
|
||||
val newPost = postsRepository.asSaved(post, value)
|
||||
mvi.updateState {
|
||||
it.copy(
|
||||
posts = it.posts.map { p ->
|
||||
if (p.id == post.id) {
|
||||
newPost
|
||||
} else {
|
||||
p
|
||||
}
|
||||
},
|
||||
)
|
||||
mvi.updateState {
|
||||
it.copy(
|
||||
posts = it.posts.map { p ->
|
||||
if (p.id == post.id) {
|
||||
newPost
|
||||
} else {
|
||||
p
|
||||
}
|
||||
},
|
||||
}
|
||||
mvi.scope.launch(Dispatchers.IO) {
|
||||
try {
|
||||
val auth = identityRepository.authToken.value.orEmpty()
|
||||
postsRepository.save(
|
||||
post = post,
|
||||
auth = auth,
|
||||
saved = value,
|
||||
)
|
||||
} catch (e: Throwable) {
|
||||
e.printStackTrace()
|
||||
mvi.updateState {
|
||||
it.copy(
|
||||
posts = it.posts.map { p ->
|
||||
if (p.id == post.id) {
|
||||
post
|
||||
} else {
|
||||
p
|
||||
}
|
||||
},
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -1,4 +1,4 @@
|
||||
package com.github.diegoberaldin.raccoonforlemmy.feature.home.ui
|
||||
package com.github.diegoberaldin.raccoonforlemmy.feature.home.postlist
|
||||
|
||||
import androidx.compose.foundation.Image
|
||||
import androidx.compose.foundation.layout.Arrangement
|
@ -10,6 +10,7 @@ import androidx.compose.ui.graphics.vector.rememberVectorPainter
|
||||
import cafe.adriel.voyager.navigator.Navigator
|
||||
import cafe.adriel.voyager.navigator.tab.Tab
|
||||
import cafe.adriel.voyager.navigator.tab.TabOptions
|
||||
import com.github.diegoberaldin.raccoonforlemmy.feature.home.postlist.PostListScreen
|
||||
import com.github.diegoberaldin.raccoonforlemmy.resources.MR
|
||||
import com.github.diegoberaldin.raccoonforlemmy.resources.di.getLanguageRepository
|
||||
import com.github.diegoberaldin.raccoonforlemmy.resources.di.staticString
|
||||
|
@ -1,11 +1,11 @@
|
||||
package com.github.diegoberaldin.raccoonforlemmy.feature.home.di
|
||||
|
||||
import com.github.diegoberaldin.raccoonforlemmy.feature.home.viewmodel.HomeScreenModel
|
||||
import com.github.diegoberaldin.raccoonforlemmy.feature.home.postlist.PostListViewModel
|
||||
import org.koin.core.component.KoinComponent
|
||||
import org.koin.core.component.inject
|
||||
|
||||
actual fun getHomeScreenModel() = HomeScreenModelHelper.model
|
||||
|
||||
object HomeScreenModelHelper : KoinComponent {
|
||||
val model: HomeScreenModel by inject()
|
||||
val model: PostListViewModel by inject()
|
||||
}
|
||||
|
@ -5,12 +5,12 @@ import com.github.diegoberaldin.raccoonforlemmy.feature.profile.content.logged.P
|
||||
import com.github.diegoberaldin.raccoonforlemmy.feature.profile.content.logged.comments.ProfileCommentsViewModel
|
||||
import com.github.diegoberaldin.raccoonforlemmy.feature.profile.content.logged.posts.ProfilePostsViewModel
|
||||
import com.github.diegoberaldin.raccoonforlemmy.feature.profile.login.LoginBottomSheetViewModel
|
||||
import com.github.diegoberaldin.raccoonforlemmy.feature.profile.viewmodel.ProfileScreenModel
|
||||
import com.github.diegoberaldin.raccoonforlemmy.feature.profile.content.ProfileContentViewModel
|
||||
import org.koin.core.parameter.parametersOf
|
||||
import org.koin.java.KoinJavaComponent.inject
|
||||
|
||||
actual fun getProfileScreenModel(): ProfileScreenModel {
|
||||
val res: ProfileScreenModel by inject(ProfileScreenModel::class.java)
|
||||
actual fun getProfileScreenModel(): ProfileContentViewModel {
|
||||
val res: ProfileContentViewModel by inject(ProfileContentViewModel::class.java)
|
||||
return res
|
||||
}
|
||||
|
||||
|
@ -1,10 +1,10 @@
|
||||
package com.github.diegoberaldin.raccoonforlemmy.feature.profile.viewmodel
|
||||
package com.github.diegoberaldin.raccoonforlemmy.feature.profile.content
|
||||
|
||||
import com.github.diegoberaldin.raccoonforlemmy.core.architecture.MviModel
|
||||
import com.github.diegoberaldin.raccoonforlemmy.domain.lemmy.data.UserModel
|
||||
|
||||
interface ProfileScreenMviModel :
|
||||
MviModel<ProfileScreenMviModel.Intent, ProfileScreenMviModel.UiState, ProfileScreenMviModel.Effect> {
|
||||
interface ProfileContentMviModel :
|
||||
MviModel<ProfileContentMviModel.Intent, ProfileContentMviModel.UiState, ProfileContentMviModel.Effect> {
|
||||
|
||||
sealed interface Intent {
|
||||
object Logout : Intent
|
@ -1,4 +1,4 @@
|
||||
package com.github.diegoberaldin.raccoonforlemmy.feature.profile.ui
|
||||
package com.github.diegoberaldin.raccoonforlemmy.feature.profile.content
|
||||
|
||||
import androidx.compose.foundation.Image
|
||||
import androidx.compose.foundation.layout.Box
|
||||
@ -28,7 +28,6 @@ import com.github.diegoberaldin.raccoonforlemmy.feature.profile.content.logged.P
|
||||
import com.github.diegoberaldin.raccoonforlemmy.feature.profile.content.notlogged.ProfileNotLoggedContent
|
||||
import com.github.diegoberaldin.raccoonforlemmy.feature.profile.di.getProfileScreenModel
|
||||
import com.github.diegoberaldin.raccoonforlemmy.feature.profile.login.LoginBottomSheet
|
||||
import com.github.diegoberaldin.raccoonforlemmy.feature.profile.viewmodel.ProfileScreenMviModel
|
||||
import com.github.diegoberaldin.raccoonforlemmy.resources.MR
|
||||
import com.github.diegoberaldin.raccoonforlemmy.resources.di.getLanguageRepository
|
||||
import com.github.diegoberaldin.raccoonforlemmy.resources.di.staticString
|
||||
@ -61,7 +60,7 @@ internal class ProfileContentScreen : Screen {
|
||||
if (uiState.currentUser != null) {
|
||||
Image(
|
||||
modifier = Modifier.onClick {
|
||||
model.reduce(ProfileScreenMviModel.Intent.Logout)
|
||||
model.reduce(ProfileContentMviModel.Intent.Logout)
|
||||
},
|
||||
imageVector = Icons.Default.Logout,
|
||||
contentDescription = null,
|
@ -1,4 +1,4 @@
|
||||
package com.github.diegoberaldin.raccoonforlemmy.feature.profile.viewmodel
|
||||
package com.github.diegoberaldin.raccoonforlemmy.feature.profile.content
|
||||
|
||||
import cafe.adriel.voyager.core.model.ScreenModel
|
||||
import com.github.diegoberaldin.raccoonforlemmy.core.architecture.DefaultMviModel
|
||||
@ -11,12 +11,12 @@ import kotlinx.coroutines.flow.launchIn
|
||||
import kotlinx.coroutines.flow.onEach
|
||||
import kotlinx.coroutines.launch
|
||||
|
||||
class ProfileScreenModel(
|
||||
private val mvi: DefaultMviModel<ProfileScreenMviModel.Intent, ProfileScreenMviModel.UiState, ProfileScreenMviModel.Effect>,
|
||||
class ProfileContentViewModel(
|
||||
private val mvi: DefaultMviModel<ProfileContentMviModel.Intent, ProfileContentMviModel.UiState, ProfileContentMviModel.Effect>,
|
||||
private val identityRepository: IdentityRepository,
|
||||
private val siteRepository: SiteRepository,
|
||||
) : ScreenModel,
|
||||
MviModel<ProfileScreenMviModel.Intent, ProfileScreenMviModel.UiState, ProfileScreenMviModel.Effect> by mvi {
|
||||
MviModel<ProfileContentMviModel.Intent, ProfileContentMviModel.UiState, ProfileContentMviModel.Effect> by mvi {
|
||||
|
||||
override fun onStarted() {
|
||||
mvi.onStarted()
|
||||
@ -35,9 +35,9 @@ class ProfileScreenModel(
|
||||
}.launchIn(mvi.scope)
|
||||
}
|
||||
|
||||
override fun reduce(intent: ProfileScreenMviModel.Intent) {
|
||||
override fun reduce(intent: ProfileContentMviModel.Intent) {
|
||||
when (intent) {
|
||||
ProfileScreenMviModel.Intent.Logout -> identityRepository.clearToken()
|
||||
ProfileContentMviModel.Intent.Logout -> identityRepository.clearToken()
|
||||
}
|
||||
}
|
||||
|
@ -9,14 +9,14 @@ import com.github.diegoberaldin.raccoonforlemmy.feature.profile.content.logged.p
|
||||
import com.github.diegoberaldin.raccoonforlemmy.feature.profile.content.logged.posts.ProfilePostsViewModel
|
||||
import com.github.diegoberaldin.raccoonforlemmy.feature.profile.login.LoginBottomSheetMviModel
|
||||
import com.github.diegoberaldin.raccoonforlemmy.feature.profile.login.LoginBottomSheetViewModel
|
||||
import com.github.diegoberaldin.raccoonforlemmy.feature.profile.viewmodel.ProfileScreenModel
|
||||
import com.github.diegoberaldin.raccoonforlemmy.feature.profile.viewmodel.ProfileScreenMviModel
|
||||
import com.github.diegoberaldin.raccoonforlemmy.feature.profile.content.ProfileContentViewModel
|
||||
import com.github.diegoberaldin.raccoonforlemmy.feature.profile.content.ProfileContentMviModel
|
||||
import org.koin.dsl.module
|
||||
|
||||
val profileTabModule = module {
|
||||
factory {
|
||||
ProfileScreenModel(
|
||||
mvi = DefaultMviModel(ProfileScreenMviModel.UiState()),
|
||||
ProfileContentViewModel(
|
||||
mvi = DefaultMviModel(ProfileContentMviModel.UiState()),
|
||||
identityRepository = get(),
|
||||
siteRepository = get(),
|
||||
)
|
||||
|
@ -5,9 +5,9 @@ import com.github.diegoberaldin.raccoonforlemmy.feature.profile.content.logged.P
|
||||
import com.github.diegoberaldin.raccoonforlemmy.feature.profile.content.logged.comments.ProfileCommentsViewModel
|
||||
import com.github.diegoberaldin.raccoonforlemmy.feature.profile.content.logged.posts.ProfilePostsViewModel
|
||||
import com.github.diegoberaldin.raccoonforlemmy.feature.profile.login.LoginBottomSheetViewModel
|
||||
import com.github.diegoberaldin.raccoonforlemmy.feature.profile.viewmodel.ProfileScreenModel
|
||||
import com.github.diegoberaldin.raccoonforlemmy.feature.profile.content.ProfileContentViewModel
|
||||
|
||||
expect fun getProfileScreenModel(): ProfileScreenModel
|
||||
expect fun getProfileScreenModel(): ProfileContentViewModel
|
||||
|
||||
expect fun getLoginBottomSheetViewModel(): LoginBottomSheetViewModel
|
||||
|
||||
|
@ -11,6 +11,7 @@ import cafe.adriel.voyager.navigator.Navigator
|
||||
import cafe.adriel.voyager.navigator.tab.Tab
|
||||
import cafe.adriel.voyager.navigator.tab.TabOptions
|
||||
import com.github.diegoberaldin.raccoonforlemmy.domain.identity.di.getApiConfigurationRepository
|
||||
import com.github.diegoberaldin.raccoonforlemmy.feature.profile.content.ProfileContentScreen
|
||||
|
||||
object ProfileTab : Tab {
|
||||
|
||||
|
@ -5,7 +5,7 @@ import com.github.diegoberaldin.raccoonforlemmy.feature.profile.content.logged.P
|
||||
import com.github.diegoberaldin.raccoonforlemmy.feature.profile.content.logged.comments.ProfileCommentsViewModel
|
||||
import com.github.diegoberaldin.raccoonforlemmy.feature.profile.content.logged.posts.ProfilePostsViewModel
|
||||
import com.github.diegoberaldin.raccoonforlemmy.feature.profile.login.LoginBottomSheetViewModel
|
||||
import com.github.diegoberaldin.raccoonforlemmy.feature.profile.viewmodel.ProfileScreenModel
|
||||
import com.github.diegoberaldin.raccoonforlemmy.feature.profile.content.ProfileContentViewModel
|
||||
import org.koin.core.component.KoinComponent
|
||||
import org.koin.core.component.inject
|
||||
import org.koin.core.parameter.parametersOf
|
||||
@ -27,7 +27,7 @@ actual fun getProfileCommentsViewModel(user: UserModel): ProfileCommentsViewMode
|
||||
ProfileScreenModelHelper.getCommentsModel(user)
|
||||
|
||||
object ProfileScreenModelHelper : KoinComponent {
|
||||
val profileModel: ProfileScreenModel by inject()
|
||||
val profileModel: ProfileContentViewModel by inject()
|
||||
val loginModel: LoginBottomSheetViewModel by inject()
|
||||
val loggedModel: ProfileLoggedViewModel by inject()
|
||||
|
||||
|
@ -1,9 +1,9 @@
|
||||
package com.github.diegoberaldin.raccoonforlemmy.feature.search.di
|
||||
|
||||
import com.github.diegoberaldin.raccoonforlemmy.feature.search.viewmodel.SearchScreenModel
|
||||
import com.github.diegoberaldin.raccoonforlemmy.feature.search.communitylist.CommunityListViewModel
|
||||
import org.koin.java.KoinJavaComponent.inject
|
||||
|
||||
actual fun getSearchScreenModel(): SearchScreenModel {
|
||||
val res: SearchScreenModel by inject(SearchScreenModel::class.java)
|
||||
actual fun getSearchScreenModel(): CommunityListViewModel {
|
||||
val res: CommunityListViewModel by inject(CommunityListViewModel::class.java)
|
||||
return res
|
||||
}
|
||||
|
@ -1,10 +1,10 @@
|
||||
package com.github.diegoberaldin.raccoonforlemmy.feature.search.viewmodel
|
||||
package com.github.diegoberaldin.raccoonforlemmy.feature.search.communitylist
|
||||
|
||||
import com.github.diegoberaldin.raccoonforlemmy.core.architecture.MviModel
|
||||
import com.github.diegoberaldin.raccoonforlemmy.domain.lemmy.data.CommunityModel
|
||||
|
||||
interface SearchScreenMviModel :
|
||||
MviModel<SearchScreenMviModel.Intent, SearchScreenMviModel.UiState, SearchScreenMviModel.Effect> {
|
||||
interface CommunityListMviModel :
|
||||
MviModel<CommunityListMviModel.Intent, CommunityListMviModel.UiState, CommunityListMviModel.Effect> {
|
||||
sealed interface Intent {
|
||||
object Refresh : Intent
|
||||
object LoadNextPage : Intent
|
@ -1,4 +1,4 @@
|
||||
package com.github.diegoberaldin.raccoonforlemmy.feature.search.ui
|
||||
package com.github.diegoberaldin.raccoonforlemmy.feature.search.communitylist
|
||||
|
||||
import androidx.compose.foundation.layout.Arrangement
|
||||
import androidx.compose.foundation.layout.Box
|
||||
@ -40,7 +40,7 @@ import com.github.diegoberaldin.raccoonforlemmy.core.appearance.theme.Spacing
|
||||
import com.github.diegoberaldin.raccoonforlemmy.core.architecture.bindToLifecycle
|
||||
import com.github.diegoberaldin.raccoonforlemmy.core.commonui.communitydetail.CommunityDetailScreen
|
||||
import com.github.diegoberaldin.raccoonforlemmy.feature.search.di.getSearchScreenModel
|
||||
import com.github.diegoberaldin.raccoonforlemmy.feature.search.viewmodel.SearchScreenMviModel
|
||||
import com.github.diegoberaldin.raccoonforlemmy.feature.search.ui.CommunityItem
|
||||
import com.github.diegoberaldin.raccoonforlemmy.resources.MR
|
||||
import dev.icerock.moko.resources.compose.stringResource
|
||||
|
||||
@ -71,7 +71,7 @@ class CommunityListScreen : Screen {
|
||||
keyboardType = KeyboardType.Text,
|
||||
),
|
||||
onValueChange = { value ->
|
||||
model.reduce(SearchScreenMviModel.Intent.SetSearch(value))
|
||||
model.reduce(CommunityListMviModel.Intent.SetSearch(value))
|
||||
},
|
||||
)
|
||||
Row(
|
||||
@ -82,7 +82,7 @@ class CommunityListScreen : Screen {
|
||||
Checkbox(
|
||||
checked = uiState.subscribedOnly,
|
||||
onCheckedChange = {
|
||||
model.reduce(SearchScreenMviModel.Intent.SetSubscribedOnly(it))
|
||||
model.reduce(CommunityListMviModel.Intent.SetSubscribedOnly(it))
|
||||
},
|
||||
colors = CheckboxDefaults.colors(checkedColor = MaterialTheme.colorScheme.primary),
|
||||
)
|
||||
@ -93,7 +93,7 @@ class CommunityListScreen : Screen {
|
||||
}
|
||||
Spacer(modifier = Modifier.weight(1f))
|
||||
Button(onClick = {
|
||||
model.reduce(SearchScreenMviModel.Intent.SearchFired)
|
||||
model.reduce(CommunityListMviModel.Intent.SearchFired)
|
||||
}) {
|
||||
Text(
|
||||
text = stringResource(MR.strings.button_search),
|
||||
@ -103,7 +103,7 @@ class CommunityListScreen : Screen {
|
||||
}
|
||||
|
||||
val pullRefreshState = rememberPullRefreshState(uiState.refreshing, {
|
||||
model.reduce(SearchScreenMviModel.Intent.Refresh)
|
||||
model.reduce(CommunityListMviModel.Intent.Refresh)
|
||||
})
|
||||
Box(
|
||||
modifier = Modifier.padding(Spacing.xxs).pullRefresh(pullRefreshState),
|
||||
@ -129,7 +129,7 @@ class CommunityListScreen : Screen {
|
||||
}
|
||||
item {
|
||||
if (!uiState.loading && !uiState.refreshing && uiState.canFetchMore) {
|
||||
model.reduce(SearchScreenMviModel.Intent.LoadNextPage)
|
||||
model.reduce(CommunityListMviModel.Intent.LoadNextPage)
|
||||
}
|
||||
if (uiState.loading && !uiState.refreshing) {
|
||||
Box(
|
@ -1,4 +1,4 @@
|
||||
package com.github.diegoberaldin.raccoonforlemmy.feature.search.viewmodel
|
||||
package com.github.diegoberaldin.raccoonforlemmy.feature.search.communitylist
|
||||
|
||||
import cafe.adriel.voyager.core.model.ScreenModel
|
||||
import com.github.diegoberaldin.raccoonforlemmy.core.architecture.DefaultMviModel
|
||||
@ -14,13 +14,13 @@ import kotlinx.coroutines.flow.map
|
||||
import kotlinx.coroutines.flow.onEach
|
||||
import kotlinx.coroutines.launch
|
||||
|
||||
class SearchScreenModel(
|
||||
private val mvi: DefaultMviModel<SearchScreenMviModel.Intent, SearchScreenMviModel.UiState, SearchScreenMviModel.Effect>,
|
||||
class CommunityListViewModel(
|
||||
private val mvi: DefaultMviModel<CommunityListMviModel.Intent, CommunityListMviModel.UiState, CommunityListMviModel.Effect>,
|
||||
private val apiConfigRepository: ApiConfigurationRepository,
|
||||
private val identityRepository: IdentityRepository,
|
||||
private val communityRepository: CommunityRepository,
|
||||
) : ScreenModel,
|
||||
MviModel<SearchScreenMviModel.Intent, SearchScreenMviModel.UiState, SearchScreenMviModel.Effect> by mvi {
|
||||
MviModel<CommunityListMviModel.Intent, CommunityListMviModel.UiState, CommunityListMviModel.Effect> by mvi {
|
||||
|
||||
private var currentPage: Int = 1
|
||||
|
||||
@ -44,13 +44,13 @@ class SearchScreenModel(
|
||||
}
|
||||
}
|
||||
|
||||
override fun reduce(intent: SearchScreenMviModel.Intent) {
|
||||
override fun reduce(intent: CommunityListMviModel.Intent) {
|
||||
when (intent) {
|
||||
SearchScreenMviModel.Intent.LoadNextPage -> loadNextPage()
|
||||
SearchScreenMviModel.Intent.Refresh -> refresh()
|
||||
SearchScreenMviModel.Intent.SearchFired -> refresh()
|
||||
is SearchScreenMviModel.Intent.SetSearch -> setSearch(intent.value)
|
||||
is SearchScreenMviModel.Intent.SetSubscribedOnly -> applySubscribedOnly(intent.value)
|
||||
CommunityListMviModel.Intent.LoadNextPage -> loadNextPage()
|
||||
CommunityListMviModel.Intent.Refresh -> refresh()
|
||||
CommunityListMviModel.Intent.SearchFired -> refresh()
|
||||
is CommunityListMviModel.Intent.SetSearch -> setSearch(intent.value)
|
||||
is CommunityListMviModel.Intent.SetSubscribedOnly -> applySubscribedOnly(intent.value)
|
||||
}
|
||||
}
|
||||
|
@ -1,14 +1,14 @@
|
||||
package com.github.diegoberaldin.raccoonforlemmy.feature.search.di
|
||||
|
||||
import com.github.diegoberaldin.raccoonforlemmy.core.architecture.DefaultMviModel
|
||||
import com.github.diegoberaldin.raccoonforlemmy.feature.search.viewmodel.SearchScreenModel
|
||||
import com.github.diegoberaldin.raccoonforlemmy.feature.search.viewmodel.SearchScreenMviModel
|
||||
import com.github.diegoberaldin.raccoonforlemmy.feature.search.communitylist.CommunityListViewModel
|
||||
import com.github.diegoberaldin.raccoonforlemmy.feature.search.communitylist.CommunityListMviModel
|
||||
import org.koin.dsl.module
|
||||
|
||||
val searchTabModule = module {
|
||||
factory {
|
||||
SearchScreenModel(
|
||||
mvi = DefaultMviModel(SearchScreenMviModel.UiState()),
|
||||
CommunityListViewModel(
|
||||
mvi = DefaultMviModel(CommunityListMviModel.UiState()),
|
||||
apiConfigRepository = get(),
|
||||
identityRepository = get(),
|
||||
communityRepository = get(),
|
||||
|
@ -1,5 +1,5 @@
|
||||
package com.github.diegoberaldin.raccoonforlemmy.feature.search.di
|
||||
|
||||
import com.github.diegoberaldin.raccoonforlemmy.feature.search.viewmodel.SearchScreenModel
|
||||
import com.github.diegoberaldin.raccoonforlemmy.feature.search.communitylist.CommunityListViewModel
|
||||
|
||||
expect fun getSearchScreenModel(): SearchScreenModel
|
||||
expect fun getSearchScreenModel(): CommunityListViewModel
|
@ -10,6 +10,7 @@ import androidx.compose.ui.graphics.vector.rememberVectorPainter
|
||||
import cafe.adriel.voyager.navigator.Navigator
|
||||
import cafe.adriel.voyager.navigator.tab.Tab
|
||||
import cafe.adriel.voyager.navigator.tab.TabOptions
|
||||
import com.github.diegoberaldin.raccoonforlemmy.feature.search.communitylist.CommunityListScreen
|
||||
import com.github.diegoberaldin.raccoonforlemmy.resources.MR
|
||||
import com.github.diegoberaldin.raccoonforlemmy.resources.di.getLanguageRepository
|
||||
import com.github.diegoberaldin.raccoonforlemmy.resources.di.staticString
|
||||
|
@ -1,11 +1,11 @@
|
||||
package com.github.diegoberaldin.raccoonforlemmy.feature.search.di
|
||||
|
||||
import com.github.diegoberaldin.raccoonforlemmy.feature.search.viewmodel.SearchScreenModel
|
||||
import com.github.diegoberaldin.raccoonforlemmy.feature.search.communitylist.CommunityListViewModel
|
||||
import org.koin.core.component.KoinComponent
|
||||
import org.koin.core.component.inject
|
||||
|
||||
actual fun getSearchScreenModel() = SearchScreenModelHelper.model
|
||||
|
||||
object SearchScreenModelHelper : KoinComponent {
|
||||
val model: SearchScreenModel by inject()
|
||||
val model: CommunityListViewModel by inject()
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user