mirror of
https://github.com/LiveFastEatTrashRaccoon/RaccoonForLemmy.git
synced 2025-02-02 03:47:09 +01:00
refactor: screen params (state restoration) (#402)
* chore: add local cache * chore: remove possibility to disable bottom sheet gestures * chore: add cache to detail opener and create entry points * chore: add query by id to multi-community * chore: update community detail * chore: update community info * chore: update create comment * chore: update create post * chore: update multi-community screens * chore: update user detail * chore: update user info * chore: update post detail * chore: update post list * chore: update modal drawer * chore: update subscription management * chore: update profile * chore: update saved items * chore: remove JavaSerializable closes #316
This commit is contained in:
parent
d28f843a51
commit
e206de2e16
@ -1,6 +1,7 @@
|
||||
package com.github.diegoberaldin.raccoonforlemmy.core.commonui.detailopener.api
|
||||
|
||||
import androidx.compose.runtime.Stable
|
||||
import com.github.diegoberaldin.raccoonforlemmy.domain.lemmy.data.CommentModel
|
||||
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.UserModel
|
||||
@ -23,4 +24,17 @@ interface DetailOpener {
|
||||
highlightCommentId: Int? = null,
|
||||
isMod: Boolean = false,
|
||||
)
|
||||
|
||||
fun openReply(
|
||||
originalPost: PostModel? = null,
|
||||
originalComment: CommentModel? = null,
|
||||
editedComment: CommentModel? = null,
|
||||
initialText: String? = null,
|
||||
)
|
||||
|
||||
fun openCreatePost(
|
||||
editedPost: PostModel? = null,
|
||||
crossPost: PostModel? = null,
|
||||
communityId: Int? = null,
|
||||
)
|
||||
}
|
||||
|
@ -44,11 +44,15 @@ kotlin {
|
||||
|
||||
implementation(projects.core.navigation)
|
||||
implementation(projects.core.commonui.detailopenerApi)
|
||||
|
||||
implementation(projects.domain.lemmy.data)
|
||||
implementation(projects.domain.lemmy.repository)
|
||||
|
||||
implementation(projects.unit.postdetail)
|
||||
implementation(projects.unit.communitydetail)
|
||||
implementation(projects.unit.userdetail)
|
||||
|
||||
implementation(projects.domain.lemmy.data)
|
||||
implementation(projects.unit.createpost)
|
||||
implementation(projects.unit.createcomment)
|
||||
|
||||
implementation(projects.resources)
|
||||
}
|
||||
|
@ -2,33 +2,50 @@ package com.github.diegoberaldin.raccoonforlemmy.core.commonui.detailopener.impl
|
||||
|
||||
import com.github.diegoberaldin.raccoonforlemmy.core.commonui.detailopener.api.DetailOpener
|
||||
import com.github.diegoberaldin.raccoonforlemmy.core.navigation.NavigationCoordinator
|
||||
import com.github.diegoberaldin.raccoonforlemmy.domain.lemmy.data.CommentModel
|
||||
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.UserModel
|
||||
import com.github.diegoberaldin.raccoonforlemmy.domain.lemmy.repository.LemmyItemCache
|
||||
import com.github.diegoberaldin.raccoonforlemmy.unit.communitydetail.CommunityDetailScreen
|
||||
import com.github.diegoberaldin.raccoonforlemmy.unit.createcomment.CreateCommentScreen
|
||||
import com.github.diegoberaldin.raccoonforlemmy.unit.createpost.CreatePostScreen
|
||||
import com.github.diegoberaldin.raccoonforlemmy.unit.postdetail.PostDetailScreen
|
||||
import com.github.diegoberaldin.raccoonforlemmy.unit.userdetail.UserDetailScreen
|
||||
import kotlinx.coroutines.CoroutineScope
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.SupervisorJob
|
||||
import kotlinx.coroutines.launch
|
||||
|
||||
class DefaultDetailOpener(
|
||||
private val navigationCoordinator: NavigationCoordinator,
|
||||
private val itemCache: LemmyItemCache,
|
||||
) : DetailOpener {
|
||||
|
||||
private val scope = CoroutineScope(SupervisorJob() + Dispatchers.Main)
|
||||
|
||||
override fun openCommunityDetail(community: CommunityModel, otherInstance: String) {
|
||||
navigationCoordinator.pushScreen(
|
||||
CommunityDetailScreen(
|
||||
community = community,
|
||||
otherInstance = otherInstance,
|
||||
),
|
||||
)
|
||||
scope.launch {
|
||||
itemCache.putCommunity(community)
|
||||
navigationCoordinator.pushScreen(
|
||||
CommunityDetailScreen(
|
||||
communityId = community.id,
|
||||
otherInstance = otherInstance,
|
||||
),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
override fun openUserDetail(user: UserModel, otherInstance: String) {
|
||||
navigationCoordinator.pushScreen(
|
||||
UserDetailScreen(
|
||||
user = user,
|
||||
otherInstance = otherInstance,
|
||||
),
|
||||
)
|
||||
scope.launch {
|
||||
itemCache.putUser(user)
|
||||
navigationCoordinator.pushScreen(
|
||||
UserDetailScreen(
|
||||
userId = user.id,
|
||||
otherInstance = otherInstance,
|
||||
),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
override fun openPostDetail(
|
||||
@ -37,13 +54,63 @@ class DefaultDetailOpener(
|
||||
highlightCommentId: Int?,
|
||||
isMod: Boolean,
|
||||
) {
|
||||
navigationCoordinator.pushScreen(
|
||||
PostDetailScreen(
|
||||
post = post,
|
||||
highlightCommentId = highlightCommentId,
|
||||
otherInstance = otherInstance,
|
||||
isMod = isMod,
|
||||
),
|
||||
)
|
||||
scope.launch {
|
||||
itemCache.putPost(post)
|
||||
navigationCoordinator.pushScreen(
|
||||
PostDetailScreen(
|
||||
postId = post.id,
|
||||
highlightCommentId = highlightCommentId,
|
||||
otherInstance = otherInstance,
|
||||
isMod = isMod,
|
||||
),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
override fun openReply(
|
||||
originalPost: PostModel?,
|
||||
originalComment: CommentModel?,
|
||||
editedComment: CommentModel?,
|
||||
initialText: String?,
|
||||
) {
|
||||
scope.launch {
|
||||
if (originalPost != null) {
|
||||
itemCache.putPost(originalPost)
|
||||
}
|
||||
if (originalComment != null) {
|
||||
itemCache.putComment(originalComment)
|
||||
}
|
||||
if (editedComment != null) {
|
||||
itemCache.putComment(editedComment)
|
||||
}
|
||||
val screen = CreateCommentScreen(
|
||||
originalPostId = originalPost?.id,
|
||||
originalCommentId = originalComment?.id,
|
||||
editedCommentId = editedComment?.id,
|
||||
initialText = initialText,
|
||||
)
|
||||
navigationCoordinator.pushScreen(screen)
|
||||
}
|
||||
}
|
||||
|
||||
override fun openCreatePost(
|
||||
editedPost: PostModel?,
|
||||
crossPost: PostModel?,
|
||||
communityId: Int?,
|
||||
) {
|
||||
scope.launch {
|
||||
if (editedPost != null) {
|
||||
itemCache.putPost(editedPost)
|
||||
}
|
||||
if (crossPost != null) {
|
||||
itemCache.putPost(crossPost)
|
||||
}
|
||||
val screen = CreatePostScreen(
|
||||
editedPostId = editedPost?.id,
|
||||
crossPostId = crossPost?.id,
|
||||
communityId = communityId,
|
||||
)
|
||||
navigationCoordinator.pushScreen(screen)
|
||||
}
|
||||
}
|
||||
}
|
@ -40,7 +40,6 @@ internal class DefaultNavigationCoordinator : NavigationCoordinator {
|
||||
override val inboxUnread = MutableStateFlow(0)
|
||||
override val canPop = MutableStateFlow(false)
|
||||
override val exitMessageVisible = MutableStateFlow(false)
|
||||
override val bottomSheetGesturesEnabled = MutableStateFlow(true)
|
||||
|
||||
private var connection: NestedScrollConnection? = null
|
||||
private var navigator: Navigator? = null
|
||||
@ -72,7 +71,6 @@ internal class DefaultNavigationCoordinator : NavigationCoordinator {
|
||||
|
||||
NavigationEvent.Hide -> {
|
||||
bottomNavigator?.hide()
|
||||
setBottomSheetGesturesEnabled(true)
|
||||
}
|
||||
}
|
||||
}.launchIn(this)
|
||||
@ -175,10 +173,6 @@ internal class DefaultNavigationCoordinator : NavigationCoordinator {
|
||||
exitMessageVisible.value = value
|
||||
}
|
||||
|
||||
override fun setBottomSheetGesturesEnabled(value: Boolean) {
|
||||
bottomSheetGesturesEnabled.value = value
|
||||
}
|
||||
|
||||
override fun setTabNavigator(value: TabNavigator) {
|
||||
tabNavigator = value
|
||||
}
|
||||
|
@ -27,7 +27,6 @@ interface NavigationCoordinator {
|
||||
val deepLinkUrl: Flow<String?>
|
||||
val canPop: StateFlow<Boolean>
|
||||
val exitMessageVisible: StateFlow<Boolean>
|
||||
val bottomSheetGesturesEnabled: StateFlow<Boolean>
|
||||
|
||||
fun setCurrentSection(section: TabNavigationSection)
|
||||
fun submitDeeplink(url: String)
|
||||
@ -43,7 +42,6 @@ interface NavigationCoordinator {
|
||||
fun pushScreen(screen: Screen)
|
||||
fun popScreen()
|
||||
fun setExitMessageVisible(value: Boolean)
|
||||
fun setBottomSheetGesturesEnabled(value: Boolean)
|
||||
fun setTabNavigator(value: TabNavigator)
|
||||
fun changeTab(value: Tab)
|
||||
}
|
@ -1,6 +1,5 @@
|
||||
package com.github.diegoberaldin.raccoonforlemmy.core.persistence.data
|
||||
|
||||
import com.github.diegoberaldin.raccoonforlemmy.core.utils.JavaSerializable
|
||||
|
||||
data class AccountModel(
|
||||
val id: Long? = null,
|
||||
@ -9,4 +8,4 @@ data class AccountModel(
|
||||
val instance: String,
|
||||
val jwt: String,
|
||||
val active: Boolean = false,
|
||||
) : JavaSerializable
|
||||
)
|
||||
|
@ -1,8 +1,6 @@
|
||||
package com.github.diegoberaldin.raccoonforlemmy.core.persistence.data
|
||||
|
||||
import com.github.diegoberaldin.raccoonforlemmy.core.utils.JavaSerializable
|
||||
|
||||
data class FavoriteCommunityModel(
|
||||
val id: Long? = null,
|
||||
val communityId: Int? = null,
|
||||
) : JavaSerializable
|
||||
)
|
@ -1,10 +1,8 @@
|
||||
package com.github.diegoberaldin.raccoonforlemmy.core.persistence.data
|
||||
|
||||
import com.github.diegoberaldin.raccoonforlemmy.core.utils.JavaSerializable
|
||||
|
||||
data class MultiCommunityModel(
|
||||
val id: Long? = null,
|
||||
val name: String = "",
|
||||
val communityIds: List<Int> = emptyList(),
|
||||
val icon: String? = null,
|
||||
) : JavaSerializable
|
||||
)
|
@ -1,7 +1,6 @@
|
||||
package com.github.diegoberaldin.raccoonforlemmy.core.persistence.data
|
||||
|
||||
import com.github.diegoberaldin.raccoonforlemmy.core.appearance.data.VoteFormat
|
||||
import com.github.diegoberaldin.raccoonforlemmy.core.utils.JavaSerializable
|
||||
import kotlin.time.Duration
|
||||
import kotlin.time.Duration.Companion.seconds
|
||||
|
||||
@ -40,4 +39,4 @@ data class SettingsModel(
|
||||
val replyColor: Int? = null,
|
||||
val searchPostTitleOnly: Boolean = false,
|
||||
val edgeToEdge: Boolean = true,
|
||||
) : JavaSerializable
|
||||
)
|
||||
|
@ -13,12 +13,17 @@ internal class DefaultMultiCommunityRepository(
|
||||
|
||||
private val db = provider.getDatabase()
|
||||
|
||||
override suspend fun getAll(accountId: Long?): List<MultiCommunityModel> =
|
||||
override suspend fun getAll(accountId: Long): List<MultiCommunityModel> =
|
||||
withContext(Dispatchers.IO) {
|
||||
db.multicommunitiesQueries.getAll(accountId)
|
||||
.executeAsList().map { it.toModel() }
|
||||
}
|
||||
|
||||
override suspend fun getById(id: Long): MultiCommunityModel? =
|
||||
withContext(Dispatchers.IO) {
|
||||
db.multicommunitiesQueries.getById(id).executeAsOneOrNull()?.toModel()
|
||||
}
|
||||
|
||||
override suspend fun create(model: MultiCommunityModel, accountId: Long): Long =
|
||||
withContext(Dispatchers.IO) {
|
||||
db.multicommunitiesQueries.create(
|
||||
|
@ -3,7 +3,8 @@ package com.github.diegoberaldin.raccoonforlemmy.core.persistence.repository
|
||||
import com.github.diegoberaldin.raccoonforlemmy.core.persistence.data.MultiCommunityModel
|
||||
|
||||
interface MultiCommunityRepository {
|
||||
suspend fun getAll(accountId: Long?): List<MultiCommunityModel>
|
||||
suspend fun getById(id: Long): MultiCommunityModel?
|
||||
suspend fun getAll(accountId: Long): List<MultiCommunityModel>
|
||||
|
||||
suspend fun create(model: MultiCommunityModel, accountId: Long): Long
|
||||
|
||||
|
@ -18,6 +18,11 @@ SELECT *
|
||||
FROM MultiCommunityEntity
|
||||
WHERE name = ? AND account_id = ?;
|
||||
|
||||
getById:
|
||||
SELECT *
|
||||
FROM MultiCommunityEntity
|
||||
WHERE id = ?;
|
||||
|
||||
create:
|
||||
INSERT OR IGNORE INTO MultiCommunityEntity (
|
||||
name,
|
||||
|
@ -1,3 +0,0 @@
|
||||
package com.github.diegoberaldin.raccoonforlemmy.core.utils
|
||||
|
||||
actual typealias JavaSerializable = java.io.Serializable
|
@ -1,3 +0,0 @@
|
||||
package com.github.diegoberaldin.raccoonforlemmy.core.utils
|
||||
|
||||
expect interface JavaSerializable
|
@ -0,0 +1,51 @@
|
||||
package com.github.diegoberaldin.raccoonforlemmy.core.utils.cache
|
||||
|
||||
import kotlinx.coroutines.sync.Mutex
|
||||
import kotlinx.coroutines.sync.withLock
|
||||
|
||||
internal class DefaultLruCache<T>(val size: Int) : LruCache<T> {
|
||||
|
||||
private val values: MutableMap<Int, T> = mutableMapOf()
|
||||
private var lastUsedIds: List<Int> = listOf()
|
||||
private val mutex = Mutex()
|
||||
|
||||
override suspend fun get(key: Int): T? = mutex.withLock {
|
||||
val res = values[key]
|
||||
if (res != null) {
|
||||
moveAtTheBeginning(key)
|
||||
}
|
||||
return res
|
||||
}
|
||||
|
||||
override suspend fun put(value: T, key: Int) = mutex.withLock {
|
||||
val old = values[key]
|
||||
if (old != null) {
|
||||
// already existing element
|
||||
moveAtTheBeginning(key)
|
||||
} else {
|
||||
// new element
|
||||
values[key] = value
|
||||
lastUsedIds = buildList {
|
||||
this += key
|
||||
this += lastUsedIds
|
||||
}
|
||||
if (lastUsedIds.size > size) {
|
||||
dropOldest()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun dropOldest() {
|
||||
lastUsedIds.lastOrNull()?.also { oldest ->
|
||||
values.remove(oldest)
|
||||
lastUsedIds = lastUsedIds - oldest
|
||||
}
|
||||
}
|
||||
|
||||
private fun moveAtTheBeginning(key: Int) {
|
||||
lastUsedIds = buildList {
|
||||
this += key
|
||||
this += (lastUsedIds - key)
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,11 @@
|
||||
package com.github.diegoberaldin.raccoonforlemmy.core.utils.cache
|
||||
|
||||
interface LruCache<T> {
|
||||
suspend fun get(key: Int): T?
|
||||
|
||||
suspend fun put(value: T, key: Int)
|
||||
|
||||
companion object {
|
||||
fun <T> factory(size: Int): LruCache<T> = DefaultLruCache(size)
|
||||
}
|
||||
}
|
@ -1,3 +0,0 @@
|
||||
package com.github.diegoberaldin.raccoonforlemmy.core.utils
|
||||
|
||||
actual interface JavaSerializable
|
@ -1,9 +1,7 @@
|
||||
package com.github.diegoberaldin.raccoonforlemmy.domain.lemmy.data
|
||||
|
||||
import com.github.diegoberaldin.raccoonforlemmy.core.utils.JavaSerializable
|
||||
|
||||
data class AccountBansModel(
|
||||
val users: List<UserModel> = emptyList(),
|
||||
val communities: List<CommunityModel> = emptyList(),
|
||||
val instances: List<InstanceModel> = emptyList(),
|
||||
) : JavaSerializable
|
||||
)
|
@ -1,7 +1,5 @@
|
||||
package com.github.diegoberaldin.raccoonforlemmy.domain.lemmy.data
|
||||
|
||||
import com.github.diegoberaldin.raccoonforlemmy.core.utils.JavaSerializable
|
||||
|
||||
data class AccountSettingsModel(
|
||||
val avatar: String? = null,
|
||||
val banner: String? = null,
|
||||
@ -16,4 +14,4 @@ data class AccountSettingsModel(
|
||||
val showNsfw: Boolean? = null,
|
||||
val defaultListingType: ListingType? = null,
|
||||
val defaultSortType: SortType? = null,
|
||||
) : JavaSerializable
|
||||
)
|
@ -1,6 +1,5 @@
|
||||
package com.github.diegoberaldin.raccoonforlemmy.domain.lemmy.data
|
||||
|
||||
import com.github.diegoberaldin.raccoonforlemmy.core.utils.JavaSerializable
|
||||
import kotlin.jvm.Transient
|
||||
|
||||
data class CommentModel(
|
||||
@ -27,7 +26,7 @@ data class CommentModel(
|
||||
@Transient
|
||||
val loadMoreButtonVisible: Boolean = false,
|
||||
val languageId: Int = 0,
|
||||
) : JavaSerializable {
|
||||
) {
|
||||
val depth: Int get() = (path.split(".").size - 2).coerceAtLeast(0)
|
||||
val parentId: String?
|
||||
get() = path.split(".")
|
||||
|
@ -1,7 +1,5 @@
|
||||
package com.github.diegoberaldin.raccoonforlemmy.domain.lemmy.data
|
||||
|
||||
import com.github.diegoberaldin.raccoonforlemmy.core.utils.JavaSerializable
|
||||
|
||||
data class CommentReportModel(
|
||||
val id: Int = 0,
|
||||
val creator: UserModel? = null,
|
||||
@ -13,4 +11,4 @@ data class CommentReportModel(
|
||||
val resolver: UserModel? = null,
|
||||
val publishDate: String? = null,
|
||||
val updateDate: String? = null,
|
||||
) : JavaSerializable
|
||||
)
|
||||
|
@ -1,6 +1,5 @@
|
||||
package com.github.diegoberaldin.raccoonforlemmy.domain.lemmy.data
|
||||
|
||||
import com.github.diegoberaldin.raccoonforlemmy.core.utils.JavaSerializable
|
||||
import kotlin.jvm.Transient
|
||||
|
||||
data class CommunityModel(
|
||||
@ -23,4 +22,4 @@ data class CommunityModel(
|
||||
val comments: Int = 0,
|
||||
val creationDate: String? = null,
|
||||
@Transient val favorite: Boolean = false,
|
||||
) : JavaSerializable
|
||||
)
|
||||
|
@ -1,8 +1,6 @@
|
||||
package com.github.diegoberaldin.raccoonforlemmy.domain.lemmy.data
|
||||
|
||||
import com.github.diegoberaldin.raccoonforlemmy.core.utils.JavaSerializable
|
||||
|
||||
data class InstanceModel(
|
||||
val id: Int = 0,
|
||||
val domain: String = "",
|
||||
) : JavaSerializable
|
||||
)
|
@ -5,11 +5,10 @@ import androidx.compose.material.icons.filled.Book
|
||||
import androidx.compose.material.icons.filled.Cottage
|
||||
import androidx.compose.material.icons.filled.Public
|
||||
import androidx.compose.runtime.Composable
|
||||
import com.github.diegoberaldin.raccoonforlemmy.core.utils.JavaSerializable
|
||||
import com.github.diegoberaldin.raccoonforlemmy.resources.MR
|
||||
import dev.icerock.moko.resources.compose.stringResource
|
||||
|
||||
sealed interface ListingType : JavaSerializable {
|
||||
sealed interface ListingType {
|
||||
data object All : ListingType
|
||||
data object Subscribed : ListingType
|
||||
data object Local : ListingType
|
||||
|
@ -1,8 +1,6 @@
|
||||
package com.github.diegoberaldin.raccoonforlemmy.domain.lemmy.data
|
||||
|
||||
import com.github.diegoberaldin.raccoonforlemmy.core.utils.JavaSerializable
|
||||
|
||||
data class MetadataModel(
|
||||
val title: String = "",
|
||||
val description: String = "",
|
||||
) : JavaSerializable
|
||||
)
|
||||
|
@ -1,10 +1,8 @@
|
||||
package com.github.diegoberaldin.raccoonforlemmy.domain.lemmy.data
|
||||
|
||||
import com.github.diegoberaldin.raccoonforlemmy.core.utils.JavaSerializable
|
||||
|
||||
sealed class ModlogItem(
|
||||
val type: ModlogItemType,
|
||||
) : JavaSerializable {
|
||||
) {
|
||||
|
||||
abstract val id: Int
|
||||
abstract val date: String?
|
||||
|
@ -1,8 +1,6 @@
|
||||
package com.github.diegoberaldin.raccoonforlemmy.domain.lemmy.data
|
||||
|
||||
import com.github.diegoberaldin.raccoonforlemmy.core.utils.JavaSerializable
|
||||
|
||||
sealed interface ModlogItemType : JavaSerializable {
|
||||
sealed interface ModlogItemType {
|
||||
data object All : ModlogItemType
|
||||
data object ModRemovePost : ModlogItemType
|
||||
data object ModLockPost : ModlogItemType
|
||||
|
@ -1,7 +1,5 @@
|
||||
package com.github.diegoberaldin.raccoonforlemmy.domain.lemmy.data
|
||||
|
||||
import com.github.diegoberaldin.raccoonforlemmy.core.utils.JavaSerializable
|
||||
|
||||
data class PersonMentionModel(
|
||||
val id: Int = 0,
|
||||
val post: PostModel,
|
||||
@ -16,4 +14,4 @@ data class PersonMentionModel(
|
||||
val isOwnPost: Boolean = false,
|
||||
val publishDate: String? = null,
|
||||
val read: Boolean = false,
|
||||
) : JavaSerializable
|
||||
)
|
||||
|
@ -1,6 +1,5 @@
|
||||
package com.github.diegoberaldin.raccoonforlemmy.domain.lemmy.data
|
||||
|
||||
import com.github.diegoberaldin.raccoonforlemmy.core.utils.JavaSerializable
|
||||
import com.github.diegoberaldin.raccoonforlemmy.core.utils.looksLikeAnImage
|
||||
|
||||
data class PostModel(
|
||||
@ -28,7 +27,7 @@ data class PostModel(
|
||||
val removed: Boolean = false,
|
||||
val locked: Boolean = false,
|
||||
val languageId: Int = 0,
|
||||
) : JavaSerializable
|
||||
)
|
||||
|
||||
val PostModel.imageUrl: String
|
||||
get() = url?.takeIf { it.looksLikeAnImage }?.takeIf { it.isNotEmpty() } ?: run {
|
||||
|
@ -1,6 +1,5 @@
|
||||
package com.github.diegoberaldin.raccoonforlemmy.domain.lemmy.data
|
||||
|
||||
import com.github.diegoberaldin.raccoonforlemmy.core.utils.JavaSerializable
|
||||
import com.github.diegoberaldin.raccoonforlemmy.core.utils.looksLikeAnImage
|
||||
|
||||
data class PostReportModel(
|
||||
@ -16,7 +15,7 @@ data class PostReportModel(
|
||||
val resolver: UserModel? = null,
|
||||
val publishDate: String? = null,
|
||||
val updateDate: String? = null,
|
||||
) : JavaSerializable
|
||||
)
|
||||
|
||||
val PostReportModel.imageUrl: String
|
||||
get() = originalUrl?.takeIf { it.looksLikeAnImage }?.takeIf { it.isNotEmpty() } ?: run {
|
||||
|
@ -1,7 +1,5 @@
|
||||
package com.github.diegoberaldin.raccoonforlemmy.domain.lemmy.data
|
||||
|
||||
import com.github.diegoberaldin.raccoonforlemmy.core.utils.JavaSerializable
|
||||
|
||||
data class PrivateMessageModel(
|
||||
val id: Int = 0,
|
||||
val content: String? = null,
|
||||
@ -10,7 +8,7 @@ data class PrivateMessageModel(
|
||||
val publishDate: String? = null,
|
||||
val updateDate: String? = null,
|
||||
val read: Boolean = false,
|
||||
) : JavaSerializable
|
||||
)
|
||||
|
||||
fun PrivateMessageModel.otherUser(currentUserId: Int): UserModel? = when (currentUserId) {
|
||||
creator?.id -> recipient
|
||||
|
@ -1,8 +1,6 @@
|
||||
package com.github.diegoberaldin.raccoonforlemmy.domain.lemmy.data
|
||||
|
||||
import com.github.diegoberaldin.raccoonforlemmy.core.utils.JavaSerializable
|
||||
|
||||
sealed interface SearchResult : JavaSerializable {
|
||||
sealed interface SearchResult {
|
||||
data class Post(val model: PostModel) : SearchResult
|
||||
data class Comment(val model: CommentModel) : SearchResult
|
||||
data class User(val model: UserModel) : SearchResult
|
||||
|
@ -1,8 +1,6 @@
|
||||
package com.github.diegoberaldin.raccoonforlemmy.domain.lemmy.data
|
||||
|
||||
import com.github.diegoberaldin.raccoonforlemmy.core.utils.JavaSerializable
|
||||
|
||||
sealed interface SearchResultType : JavaSerializable {
|
||||
sealed interface SearchResultType {
|
||||
data object All : SearchResultType
|
||||
data object Posts : SearchResultType
|
||||
data object Comments : SearchResultType
|
||||
|
@ -12,11 +12,10 @@ import androidx.compose.material.icons.filled.Thunderstorm
|
||||
import androidx.compose.material.icons.filled.TrendingUp
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.ui.graphics.vector.ImageVector
|
||||
import com.github.diegoberaldin.raccoonforlemmy.core.utils.JavaSerializable
|
||||
import com.github.diegoberaldin.raccoonforlemmy.resources.MR
|
||||
import dev.icerock.moko.resources.compose.stringResource
|
||||
|
||||
sealed interface SortType : JavaSerializable {
|
||||
sealed interface SortType {
|
||||
data object Active : SortType
|
||||
data object Hot : SortType
|
||||
data object New : SortType
|
||||
|
@ -1,7 +1,5 @@
|
||||
package com.github.diegoberaldin.raccoonforlemmy.domain.lemmy.data
|
||||
|
||||
import com.github.diegoberaldin.raccoonforlemmy.core.utils.JavaSerializable
|
||||
|
||||
data class UserModel(
|
||||
val id: Int = 0,
|
||||
val instanceId: Int = 0,
|
||||
@ -17,6 +15,6 @@ data class UserModel(
|
||||
val banned: Boolean = false,
|
||||
val updateDate: String? = null,
|
||||
val admin: Boolean = false,
|
||||
) : JavaSerializable
|
||||
)
|
||||
|
||||
fun List<UserModel>.containsId(value: Int?): Boolean = any { it.id == value }
|
||||
|
@ -1,8 +1,6 @@
|
||||
package com.github.diegoberaldin.raccoonforlemmy.domain.lemmy.data
|
||||
|
||||
import com.github.diegoberaldin.raccoonforlemmy.core.utils.JavaSerializable
|
||||
|
||||
data class UserScoreModel(
|
||||
val postScore: Int = 0,
|
||||
val commentScore: Int = 0,
|
||||
) : JavaSerializable
|
||||
)
|
@ -29,7 +29,10 @@ kotlin {
|
||||
dependencies {
|
||||
implementation(libs.koin.core)
|
||||
implementation(libs.ktorfit.lib)
|
||||
|
||||
implementation(projects.core.api)
|
||||
implementation(projects.core.utils)
|
||||
|
||||
implementation(projects.domain.lemmy.data)
|
||||
}
|
||||
}
|
||||
|
@ -0,0 +1,39 @@
|
||||
package com.github.diegoberaldin.raccoonforlemmy.domain.lemmy.repository
|
||||
|
||||
import com.github.diegoberaldin.raccoonforlemmy.core.utils.cache.LruCache
|
||||
import com.github.diegoberaldin.raccoonforlemmy.domain.lemmy.data.CommentModel
|
||||
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.UserModel
|
||||
|
||||
internal class DefaultLemmyItemCache(
|
||||
private val postCache: LruCache<PostModel>,
|
||||
private val communityCache: LruCache<CommunityModel>,
|
||||
private val commentCache: LruCache<CommentModel>,
|
||||
private val userCache: LruCache<UserModel>,
|
||||
) : LemmyItemCache {
|
||||
|
||||
override suspend fun putPost(value: PostModel) {
|
||||
postCache.put(value = value, key = value.id)
|
||||
}
|
||||
|
||||
override suspend fun getPost(id: Int): PostModel? = postCache.get(id)
|
||||
|
||||
override suspend fun putComment(value: CommentModel) {
|
||||
commentCache.put(value = value, key = value.id)
|
||||
}
|
||||
|
||||
override suspend fun getComment(id: Int): CommentModel? = commentCache.get(id)
|
||||
|
||||
override suspend fun putCommunity(value: CommunityModel) {
|
||||
communityCache.put(value = value, key = value.id)
|
||||
}
|
||||
|
||||
override suspend fun getCommunity(id: Int): CommunityModel? = communityCache.get(id)
|
||||
|
||||
override suspend fun putUser(value: UserModel) {
|
||||
userCache.put(value = value, key = value.id)
|
||||
}
|
||||
|
||||
override suspend fun getUser(id: Int): UserModel? = userCache.get(id)
|
||||
}
|
@ -0,0 +1,20 @@
|
||||
package com.github.diegoberaldin.raccoonforlemmy.domain.lemmy.repository
|
||||
|
||||
import com.github.diegoberaldin.raccoonforlemmy.domain.lemmy.data.CommentModel
|
||||
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.UserModel
|
||||
|
||||
interface LemmyItemCache {
|
||||
suspend fun putPost(value: PostModel)
|
||||
suspend fun getPost(id: Int): PostModel?
|
||||
|
||||
suspend fun putComment(value: CommentModel)
|
||||
suspend fun getComment(id: Int): CommentModel?
|
||||
|
||||
suspend fun putCommunity(value: CommunityModel)
|
||||
suspend fun getCommunity(id: Int): CommunityModel?
|
||||
|
||||
suspend fun putUser(value: UserModel)
|
||||
suspend fun getUser(id: Int): UserModel?
|
||||
}
|
@ -1,16 +1,19 @@
|
||||
package com.github.diegoberaldin.raccoonforlemmy.domain.lemmy.repository.di
|
||||
|
||||
import com.github.diegoberaldin.raccoonforlemmy.core.utils.cache.LruCache
|
||||
import com.github.diegoberaldin.raccoonforlemmy.domain.lemmy.repository.CommentRepository
|
||||
import com.github.diegoberaldin.raccoonforlemmy.domain.lemmy.repository.CommunityRepository
|
||||
import com.github.diegoberaldin.raccoonforlemmy.domain.lemmy.repository.DefaultCommentRepository
|
||||
import com.github.diegoberaldin.raccoonforlemmy.domain.lemmy.repository.DefaultCommunityRepository
|
||||
import com.github.diegoberaldin.raccoonforlemmy.domain.lemmy.repository.DefaultGetSortTypesUseCase
|
||||
import com.github.diegoberaldin.raccoonforlemmy.domain.lemmy.repository.DefaultLemmyItemCache
|
||||
import com.github.diegoberaldin.raccoonforlemmy.domain.lemmy.repository.DefaultModlogRepository
|
||||
import com.github.diegoberaldin.raccoonforlemmy.domain.lemmy.repository.DefaultPostRepository
|
||||
import com.github.diegoberaldin.raccoonforlemmy.domain.lemmy.repository.DefaultPrivateMessageRepository
|
||||
import com.github.diegoberaldin.raccoonforlemmy.domain.lemmy.repository.DefaultSiteRepository
|
||||
import com.github.diegoberaldin.raccoonforlemmy.domain.lemmy.repository.DefaultUserRepository
|
||||
import com.github.diegoberaldin.raccoonforlemmy.domain.lemmy.repository.GetSortTypesUseCase
|
||||
import com.github.diegoberaldin.raccoonforlemmy.domain.lemmy.repository.LemmyItemCache
|
||||
import com.github.diegoberaldin.raccoonforlemmy.domain.lemmy.repository.ModlogRepository
|
||||
import com.github.diegoberaldin.raccoonforlemmy.domain.lemmy.repository.PostRepository
|
||||
import com.github.diegoberaldin.raccoonforlemmy.domain.lemmy.repository.PrivateMessageRepository
|
||||
@ -65,4 +68,12 @@ val repositoryModule = module {
|
||||
services = get(named("default")),
|
||||
)
|
||||
}
|
||||
single<LemmyItemCache> {
|
||||
DefaultLemmyItemCache(
|
||||
postCache = LruCache.factory(5),
|
||||
commentCache = LruCache.factory(5),
|
||||
communityCache = LruCache.factory(5),
|
||||
userCache = LruCache.factory(5),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
@ -90,7 +90,6 @@ fun App(onLoadingFinished: () -> Unit = {}) {
|
||||
val drawerState = rememberDrawerState(initialValue = DrawerValue.Closed)
|
||||
val drawerCoordinator = remember { getDrawerCoordinator() }
|
||||
val drawerGesturesEnabled by drawerCoordinator.gesturesEnabled.collectAsState()
|
||||
val bottomSheetGesturesEnabled by navigationCoordinator.bottomSheetGesturesEnabled.collectAsState()
|
||||
val detailOpener = remember { getDetailOpener() }
|
||||
|
||||
LaunchedEffect(Unit) {
|
||||
@ -203,7 +202,9 @@ fun App(onLoadingFinished: () -> Unit = {}) {
|
||||
}
|
||||
|
||||
is DrawerEvent.OpenMultiCommunity -> {
|
||||
navigationCoordinator.pushScreen(MultiCommunityScreen(evt.community))
|
||||
evt.community.id?.toInt()?.also {
|
||||
navigationCoordinator.pushScreen(MultiCommunityScreen(it))
|
||||
}
|
||||
}
|
||||
|
||||
DrawerEvent.ManageSubscriptions -> {
|
||||
@ -240,7 +241,6 @@ fun App(onLoadingFinished: () -> Unit = {}) {
|
||||
topEnd = CornerSize.xl
|
||||
),
|
||||
sheetBackgroundColor = MaterialTheme.colorScheme.background,
|
||||
sheetGesturesEnabled = bottomSheetGesturesEnabled,
|
||||
) { bottomNavigator ->
|
||||
navigationCoordinator.setBottomNavigator(bottomNavigator)
|
||||
|
||||
|
@ -17,6 +17,7 @@ internal val internalSharedModule = module {
|
||||
single<DetailOpener> {
|
||||
DefaultDetailOpener(
|
||||
navigationCoordinator = get(),
|
||||
itemCache = get(),
|
||||
)
|
||||
}
|
||||
}
|
@ -101,15 +101,12 @@ import com.github.diegoberaldin.raccoonforlemmy.core.utils.compose.rememberCallb
|
||||
import com.github.diegoberaldin.raccoonforlemmy.core.utils.keepscreenon.rememberKeepScreenOn
|
||||
import com.github.diegoberaldin.raccoonforlemmy.core.utils.toLocalDp
|
||||
import com.github.diegoberaldin.raccoonforlemmy.domain.lemmy.data.CommentModel
|
||||
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.containsId
|
||||
import com.github.diegoberaldin.raccoonforlemmy.domain.lemmy.data.toIcon
|
||||
import com.github.diegoberaldin.raccoonforlemmy.resources.MR
|
||||
import com.github.diegoberaldin.raccoonforlemmy.unit.ban.BanUserScreen
|
||||
import com.github.diegoberaldin.raccoonforlemmy.unit.communityinfo.CommunityInfoScreen
|
||||
import com.github.diegoberaldin.raccoonforlemmy.unit.createcomment.CreateCommentScreen
|
||||
import com.github.diegoberaldin.raccoonforlemmy.unit.createpost.CreatePostScreen
|
||||
import com.github.diegoberaldin.raccoonforlemmy.unit.createreport.CreateReportScreen
|
||||
import com.github.diegoberaldin.raccoonforlemmy.unit.instanceinfo.InstanceInfoScreen
|
||||
import com.github.diegoberaldin.raccoonforlemmy.unit.modlog.ModlogScreen
|
||||
@ -125,21 +122,21 @@ import kotlinx.coroutines.launch
|
||||
import org.koin.core.parameter.parametersOf
|
||||
|
||||
class CommunityDetailScreen(
|
||||
private val community: CommunityModel,
|
||||
private val communityId: Int,
|
||||
private val otherInstance: String = "",
|
||||
) : Screen {
|
||||
|
||||
override val key: ScreenKey
|
||||
get() = super.key + community.id.toString()
|
||||
get() = super.key + communityId.toString()
|
||||
|
||||
@OptIn(ExperimentalMaterial3Api::class, ExperimentalMaterialApi::class)
|
||||
@Composable
|
||||
override fun Content() {
|
||||
val model = getScreenModel<CommunityDetailMviModel>(
|
||||
tag = community.id.toString() + community.name,
|
||||
parameters = { parametersOf(community, otherInstance) },
|
||||
tag = communityId.toString(),
|
||||
parameters = { parametersOf(communityId, otherInstance) },
|
||||
)
|
||||
model.bindToLifecycle(key + community.id.toString())
|
||||
model.bindToLifecycle(key + communityId.toString())
|
||||
val uiState by model.uiState.collectAsState()
|
||||
val lazyListState = rememberLazyListState()
|
||||
val scope = rememberCoroutineScope()
|
||||
@ -366,7 +363,7 @@ class CommunityDetailScreen(
|
||||
|
||||
OptionId.Info -> {
|
||||
navigationCoordinator.showBottomSheet(
|
||||
CommunityInfoScreen(uiState.community),
|
||||
CommunityInfoScreen(uiState.community.id),
|
||||
)
|
||||
}
|
||||
|
||||
@ -475,13 +472,9 @@ class CommunityDetailScreen(
|
||||
icon = Icons.Default.Create,
|
||||
text = stringResource(MR.strings.action_create_post),
|
||||
onSelected = rememberCallback {
|
||||
with(navigationCoordinator) {
|
||||
setBottomSheetGesturesEnabled(false)
|
||||
val screen = CreatePostScreen(
|
||||
communityId = uiState.community.id,
|
||||
)
|
||||
showBottomSheet(screen = screen)
|
||||
}
|
||||
detailOpener.openCreatePost(
|
||||
communityId = uiState.community.id,
|
||||
)
|
||||
},
|
||||
)
|
||||
}
|
||||
@ -612,13 +605,9 @@ class CommunityDetailScreen(
|
||||
)
|
||||
},
|
||||
onSecondDismissToStart = rememberCallback(model) {
|
||||
with(navigationCoordinator) {
|
||||
setBottomSheetGesturesEnabled(false)
|
||||
val screen = CreateCommentScreen(
|
||||
originalPost = post,
|
||||
)
|
||||
showBottomSheet(screen)
|
||||
}
|
||||
detailOpener.openReply(
|
||||
originalPost = post,
|
||||
)
|
||||
},
|
||||
onDismissToEnd = rememberCallback(model) {
|
||||
model.reduce(
|
||||
@ -808,12 +797,7 @@ class CommunityDetailScreen(
|
||||
)
|
||||
|
||||
OptionId.Edit -> {
|
||||
with(navigationCoordinator) {
|
||||
setBottomSheetGesturesEnabled(false)
|
||||
showBottomSheet(
|
||||
CreatePostScreen(editedPost = post),
|
||||
)
|
||||
}
|
||||
detailOpener.openCreatePost(editedPost = post)
|
||||
}
|
||||
|
||||
OptionId.Report -> {
|
||||
@ -823,12 +807,7 @@ class CommunityDetailScreen(
|
||||
}
|
||||
|
||||
OptionId.CrossPost -> {
|
||||
with(navigationCoordinator) {
|
||||
setBottomSheetGesturesEnabled(false)
|
||||
showBottomSheet(
|
||||
CreatePostScreen(crossPost = post),
|
||||
)
|
||||
}
|
||||
detailOpener.openCreatePost(crossPost = post)
|
||||
}
|
||||
|
||||
OptionId.SeeRaw -> {
|
||||
@ -943,7 +922,8 @@ class CommunityDetailScreen(
|
||||
if (rawContent != null) {
|
||||
when (val content = rawContent) {
|
||||
is PostModel -> {
|
||||
RawContentDialog(title = content.title,
|
||||
RawContentDialog(
|
||||
title = content.title,
|
||||
publishDate = content.publishDate,
|
||||
updateDate = content.updateDate,
|
||||
url = content.url,
|
||||
@ -954,20 +934,17 @@ class CommunityDetailScreen(
|
||||
onQuote = rememberCallbackArgs { quotation ->
|
||||
rawContent = null
|
||||
if (quotation != null) {
|
||||
with(navigationCoordinator) {
|
||||
setBottomSheetGesturesEnabled(false)
|
||||
val screen = CreateCommentScreen(
|
||||
originalPost = content,
|
||||
initialText = buildString {
|
||||
append("> ")
|
||||
append(quotation)
|
||||
append("\n\n")
|
||||
},
|
||||
)
|
||||
showBottomSheet(screen)
|
||||
}
|
||||
detailOpener.openReply(
|
||||
originalPost = content,
|
||||
initialText = buildString {
|
||||
append("> ")
|
||||
append(quotation)
|
||||
append("\n\n")
|
||||
},
|
||||
)
|
||||
}
|
||||
})
|
||||
},
|
||||
)
|
||||
}
|
||||
|
||||
is CommentModel -> {
|
||||
@ -981,16 +958,14 @@ class CommunityDetailScreen(
|
||||
onQuote = rememberCallbackArgs { quotation ->
|
||||
rawContent = null
|
||||
if (quotation != null) {
|
||||
with(navigationCoordinator) {
|
||||
setBottomSheetGesturesEnabled(false)
|
||||
val screen = CreateCommentScreen(originalComment = content,
|
||||
initialText = buildString {
|
||||
append("> ")
|
||||
append(quotation)
|
||||
append("\n\n")
|
||||
})
|
||||
showBottomSheet(screen)
|
||||
}
|
||||
detailOpener.openReply(
|
||||
originalComment = content,
|
||||
initialText = buildString {
|
||||
append("> ")
|
||||
append(quotation)
|
||||
append("\n\n")
|
||||
},
|
||||
)
|
||||
}
|
||||
},
|
||||
)
|
||||
|
@ -23,6 +23,7 @@ import com.github.diegoberaldin.raccoonforlemmy.domain.lemmy.data.imageUrl
|
||||
import com.github.diegoberaldin.raccoonforlemmy.domain.lemmy.data.toSortType
|
||||
import com.github.diegoberaldin.raccoonforlemmy.domain.lemmy.repository.CommunityRepository
|
||||
import com.github.diegoberaldin.raccoonforlemmy.domain.lemmy.repository.GetSortTypesUseCase
|
||||
import com.github.diegoberaldin.raccoonforlemmy.domain.lemmy.repository.LemmyItemCache
|
||||
import com.github.diegoberaldin.raccoonforlemmy.domain.lemmy.repository.PostRepository
|
||||
import com.github.diegoberaldin.raccoonforlemmy.domain.lemmy.repository.SiteRepository
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
@ -33,7 +34,7 @@ import kotlinx.coroutines.launch
|
||||
|
||||
class CommunityDetailViewModel(
|
||||
private val mvi: DefaultMviModel<CommunityDetailMviModel.Intent, CommunityDetailMviModel.UiState, CommunityDetailMviModel.Effect>,
|
||||
private val community: CommunityModel,
|
||||
private val communityId: Int,
|
||||
private val otherInstance: String,
|
||||
private val identityRepository: IdentityRepository,
|
||||
private val apiConfigurationRepository: ApiConfigurationRepository,
|
||||
@ -50,6 +51,7 @@ class CommunityDetailViewModel(
|
||||
private val imagePreloadManager: ImagePreloadManager,
|
||||
private val getSortTypesUseCase: GetSortTypesUseCase,
|
||||
private val notificationCenter: NotificationCenter,
|
||||
private val itemCache: LemmyItemCache,
|
||||
) : CommunityDetailMviModel,
|
||||
MviModel<CommunityDetailMviModel.Intent, CommunityDetailMviModel.UiState, CommunityDetailMviModel.Effect> by mvi {
|
||||
|
||||
@ -59,16 +61,18 @@ class CommunityDetailViewModel(
|
||||
|
||||
override fun onStarted() {
|
||||
mvi.onStarted()
|
||||
|
||||
mvi.updateState {
|
||||
it.copy(
|
||||
community = it.community.takeIf { c -> c.id != 0 } ?: community,
|
||||
instance = otherInstance.takeIf { n -> n.isNotEmpty() }
|
||||
?: apiConfigurationRepository.instance.value,
|
||||
)
|
||||
}
|
||||
|
||||
mvi.scope?.launch {
|
||||
if (uiState.value.community.id == 0) {
|
||||
val community = itemCache.getCommunity(communityId) ?: CommunityModel()
|
||||
mvi.updateState {
|
||||
it.copy(
|
||||
community = community,
|
||||
instance = otherInstance.takeIf { n -> n.isNotEmpty() }
|
||||
?: apiConfigurationRepository.instance.value,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
themeRepository.postLayout.onEach { layout ->
|
||||
mvi.updateState { it.copy(postLayout = layout) }
|
||||
}.launchIn(this)
|
||||
@ -252,6 +256,7 @@ class CommunityDetailViewModel(
|
||||
pageCursor = null
|
||||
hideReadPosts = false
|
||||
mvi.updateState { it.copy(canFetchMore = true, refreshing = true) }
|
||||
val community = uiState.value.community
|
||||
val auth = identityRepository.authToken.value
|
||||
val accountId = accountRepository.getActive()?.id
|
||||
val isFavorite = favoriteCommunityRepository.getBy(accountId, community.id) != null
|
||||
@ -298,11 +303,11 @@ class CommunityDetailViewModel(
|
||||
val auth = identityRepository.authToken.value
|
||||
val refreshing = currentState.refreshing
|
||||
val sort = currentState.sortType
|
||||
val communityId = currentState.community.id
|
||||
val community = currentState.community
|
||||
val (itemList, nextPage) = postRepository.getAll(
|
||||
auth = auth,
|
||||
otherInstance = otherInstance,
|
||||
communityId = communityId,
|
||||
communityId = community.id,
|
||||
communityName = community.name,
|
||||
page = currentPage,
|
||||
pageCursor = pageCursor,
|
||||
@ -459,7 +464,7 @@ class CommunityDetailViewModel(
|
||||
mvi.scope?.launch(Dispatchers.IO) {
|
||||
communityRepository.subscribe(
|
||||
auth = identityRepository.authToken.value,
|
||||
id = community.id,
|
||||
id = communityId,
|
||||
)
|
||||
// the first response isn't immediately true, simulate here
|
||||
mvi.updateState { it.copy(community = it.community.copy(subscribed = true)) }
|
||||
@ -471,7 +476,7 @@ class CommunityDetailViewModel(
|
||||
mvi.scope?.launch(Dispatchers.IO) {
|
||||
val community = communityRepository.unsubscribe(
|
||||
auth = identityRepository.authToken.value,
|
||||
id = community.id,
|
||||
id = communityId,
|
||||
)
|
||||
if (community != null) {
|
||||
mvi.updateState { it.copy(community = community) }
|
||||
@ -501,7 +506,6 @@ class CommunityDetailViewModel(
|
||||
mvi.updateState { it.copy(asyncInProgress = true) }
|
||||
mvi.scope?.launch(Dispatchers.IO) {
|
||||
try {
|
||||
val communityId = community.id
|
||||
val auth = identityRepository.authToken.value
|
||||
communityRepository.block(communityId, true, auth).getOrThrow()
|
||||
mvi.emitEffect(CommunityDetailMviModel.Effect.BlockSuccess)
|
||||
@ -517,6 +521,7 @@ class CommunityDetailViewModel(
|
||||
mvi.updateState { it.copy(asyncInProgress = true) }
|
||||
mvi.scope?.launch(Dispatchers.IO) {
|
||||
try {
|
||||
val community = uiState.value.community
|
||||
val instanceId = community.instanceId
|
||||
val auth = identityRepository.authToken.value
|
||||
siteRepository.block(instanceId, true, auth).getOrThrow()
|
||||
@ -583,7 +588,7 @@ class CommunityDetailViewModel(
|
||||
val auth = identityRepository.authToken.value.orEmpty()
|
||||
val newModerators = communityRepository.addModerator(
|
||||
auth = auth,
|
||||
communityId = community.id,
|
||||
communityId = communityId,
|
||||
added = !isModerator,
|
||||
userId = userId,
|
||||
)
|
||||
@ -594,10 +599,9 @@ class CommunityDetailViewModel(
|
||||
}
|
||||
|
||||
private fun toggleFavorite() {
|
||||
val communityId = community.id
|
||||
mvi.scope?.launch(Dispatchers.IO) {
|
||||
val accountId = accountRepository.getActive()?.id ?: 0L
|
||||
val newValue = !community.favorite
|
||||
val newValue = !uiState.value.community.favorite
|
||||
if (newValue) {
|
||||
val model = FavoriteCommunityModel(communityId = communityId)
|
||||
favoriteCommunityRepository.create(model, accountId)
|
||||
|
@ -9,7 +9,7 @@ val communityDetailModule = module {
|
||||
factory<CommunityDetailMviModel> { params ->
|
||||
CommunityDetailViewModel(
|
||||
mvi = DefaultMviModel(CommunityDetailMviModel.UiState()),
|
||||
community = params[0],
|
||||
communityId = params[0],
|
||||
otherInstance = params[1],
|
||||
identityRepository = get(),
|
||||
apiConfigurationRepository = get(),
|
||||
@ -26,6 +26,7 @@ val communityDetailModule = module {
|
||||
getSortTypesUseCase = get(),
|
||||
accountRepository = get(),
|
||||
favoriteCommunityRepository = get(),
|
||||
itemCache = get(),
|
||||
)
|
||||
}
|
||||
}
|
@ -32,7 +32,6 @@ import androidx.compose.runtime.rememberCoroutineScope
|
||||
import androidx.compose.ui.Alignment
|
||||
import androidx.compose.ui.Modifier
|
||||
import cafe.adriel.voyager.core.screen.Screen
|
||||
import com.github.diegoberaldin.raccoonforlemmy.core.navigation.getScreenModel
|
||||
import com.github.diegoberaldin.raccoonforlemmy.core.appearance.theme.Spacing
|
||||
import com.github.diegoberaldin.raccoonforlemmy.core.architecture.bindToLifecycle
|
||||
import com.github.diegoberaldin.raccoonforlemmy.core.commonui.components.BottomSheetHandle
|
||||
@ -41,10 +40,10 @@ import com.github.diegoberaldin.raccoonforlemmy.core.commonui.detailopener.api.g
|
||||
import com.github.diegoberaldin.raccoonforlemmy.core.commonui.lemmyui.DetailInfoItem
|
||||
import com.github.diegoberaldin.raccoonforlemmy.core.commonui.lemmyui.PostCardBody
|
||||
import com.github.diegoberaldin.raccoonforlemmy.core.navigation.di.getNavigationCoordinator
|
||||
import com.github.diegoberaldin.raccoonforlemmy.core.navigation.getScreenModel
|
||||
import com.github.diegoberaldin.raccoonforlemmy.core.utils.compose.rememberCallbackArgs
|
||||
import com.github.diegoberaldin.raccoonforlemmy.core.utils.datetime.prettifyDate
|
||||
import com.github.diegoberaldin.raccoonforlemmy.core.utils.getPrettyNumber
|
||||
import com.github.diegoberaldin.raccoonforlemmy.domain.lemmy.data.CommunityModel
|
||||
import com.github.diegoberaldin.raccoonforlemmy.resources.MR
|
||||
import com.github.diegoberaldin.raccoonforlemmy.unit.communityinfo.components.ModeratorCell
|
||||
import com.github.diegoberaldin.raccoonforlemmy.unit.web.WebViewScreen
|
||||
@ -55,14 +54,14 @@ import kotlinx.coroutines.launch
|
||||
import org.koin.core.parameter.parametersOf
|
||||
|
||||
class CommunityInfoScreen(
|
||||
private val community: CommunityModel,
|
||||
private val communityId: Int,
|
||||
) : Screen {
|
||||
@OptIn(ExperimentalMaterial3Api::class)
|
||||
@Composable
|
||||
override fun Content() {
|
||||
val model = getScreenModel<CommunityInfoMviModel>(
|
||||
tag = community.id.toString() + community.name,
|
||||
parameters = { parametersOf(community) },
|
||||
tag = communityId.toString(),
|
||||
parameters = { parametersOf(communityId) },
|
||||
)
|
||||
model.bindToLifecycle(key)
|
||||
val uiState by model.uiState.collectAsState()
|
||||
|
@ -5,30 +5,35 @@ import com.github.diegoberaldin.raccoonforlemmy.core.architecture.MviModel
|
||||
import com.github.diegoberaldin.raccoonforlemmy.core.persistence.repository.SettingsRepository
|
||||
import com.github.diegoberaldin.raccoonforlemmy.domain.lemmy.data.CommunityModel
|
||||
import com.github.diegoberaldin.raccoonforlemmy.domain.lemmy.repository.CommunityRepository
|
||||
import com.github.diegoberaldin.raccoonforlemmy.domain.lemmy.repository.LemmyItemCache
|
||||
import kotlinx.coroutines.flow.launchIn
|
||||
import kotlinx.coroutines.flow.onEach
|
||||
import kotlinx.coroutines.launch
|
||||
|
||||
class CommunityInfoViewModel(
|
||||
private val mvi: DefaultMviModel<CommunityInfoMviModel.Intent, CommunityInfoMviModel.UiState, CommunityInfoMviModel.Effect>,
|
||||
private val community: CommunityModel,
|
||||
private val communityId: Int,
|
||||
private val communityRepository: CommunityRepository,
|
||||
private val settingsRepository: SettingsRepository,
|
||||
private val itemCache: LemmyItemCache,
|
||||
) : CommunityInfoMviModel,
|
||||
MviModel<CommunityInfoMviModel.Intent, CommunityInfoMviModel.UiState, CommunityInfoMviModel.Effect> by mvi {
|
||||
|
||||
override fun onStarted() {
|
||||
mvi.onStarted()
|
||||
mvi.updateState { it.copy(community = community) }
|
||||
|
||||
mvi.scope?.launch {
|
||||
if (uiState.value.community.id == 0) {
|
||||
val community = itemCache.getCommunity(communityId) ?: CommunityModel()
|
||||
mvi.updateState { it.copy(community = community) }
|
||||
}
|
||||
settingsRepository.currentSettings.onEach {
|
||||
mvi.updateState { it.copy(autoLoadImages = it.autoLoadImages) }
|
||||
}.launchIn(this)
|
||||
|
||||
if (uiState.value.moderators.isEmpty()) {
|
||||
val moderators = communityRepository.getModerators(
|
||||
id = community.id
|
||||
id = communityId
|
||||
)
|
||||
mvi.updateState { it.copy(moderators = moderators) }
|
||||
}
|
||||
|
@ -9,9 +9,10 @@ val communityInfoModule = module {
|
||||
factory<CommunityInfoMviModel> { params ->
|
||||
CommunityInfoViewModel(
|
||||
mvi = DefaultMviModel(CommunityInfoMviModel.UiState()),
|
||||
community = params[0],
|
||||
communityId = params[0],
|
||||
communityRepository = get(),
|
||||
settingsRepository = get(),
|
||||
itemCache = get(),
|
||||
)
|
||||
}
|
||||
}
|
@ -6,7 +6,9 @@ import com.github.diegoberaldin.raccoonforlemmy.core.appearance.data.PostLayout
|
||||
import com.github.diegoberaldin.raccoonforlemmy.core.appearance.data.VoteFormat
|
||||
import com.github.diegoberaldin.raccoonforlemmy.core.architecture.MviModel
|
||||
import com.github.diegoberaldin.raccoonforlemmy.core.commonui.lemmyui.CreatePostSection
|
||||
import com.github.diegoberaldin.raccoonforlemmy.domain.lemmy.data.CommentModel
|
||||
import com.github.diegoberaldin.raccoonforlemmy.domain.lemmy.data.LanguageModel
|
||||
import com.github.diegoberaldin.raccoonforlemmy.domain.lemmy.data.PostModel
|
||||
import dev.icerock.moko.resources.desc.StringDesc
|
||||
|
||||
@Stable
|
||||
@ -37,6 +39,9 @@ interface CreateCommentMviModel :
|
||||
}
|
||||
|
||||
data class UiState(
|
||||
val originalPost: PostModel? = null,
|
||||
val originalComment: CommentModel? = null,
|
||||
val editedComment: CommentModel? = null,
|
||||
val postLayout: PostLayout = PostLayout.Card,
|
||||
val fullHeightImages: Boolean = true,
|
||||
val voteFormat: VoteFormat = VoteFormat.Aggregated,
|
||||
|
@ -82,9 +82,9 @@ import kotlinx.coroutines.flow.onEach
|
||||
import org.koin.core.parameter.parametersOf
|
||||
|
||||
class CreateCommentScreen(
|
||||
private val originalPost: PostModel? = null,
|
||||
private val originalComment: CommentModel? = null,
|
||||
private val editedComment: CommentModel? = null,
|
||||
private val originalPostId: Int? = null,
|
||||
private val originalCommentId: Int? = null,
|
||||
private val editedCommentId: Int? = null,
|
||||
private val initialText: String? = null,
|
||||
) : Screen {
|
||||
@OptIn(ExperimentalMaterial3Api::class)
|
||||
@ -92,9 +92,9 @@ class CreateCommentScreen(
|
||||
override fun Content() {
|
||||
val model = getScreenModel<CreateCommentMviModel> {
|
||||
parametersOf(
|
||||
originalPost?.id,
|
||||
originalComment?.id,
|
||||
editedComment?.id,
|
||||
originalPostId,
|
||||
originalCommentId,
|
||||
editedCommentId,
|
||||
)
|
||||
}
|
||||
model.bindToLifecycle(key)
|
||||
@ -109,7 +109,7 @@ class CreateCommentScreen(
|
||||
var textFieldValue by remember {
|
||||
mutableStateOf(
|
||||
TextFieldValue(
|
||||
text = (initialText ?: editedComment?.text).orEmpty()
|
||||
text = (initialText ?: uiState.editedComment?.text).orEmpty()
|
||||
)
|
||||
)
|
||||
}
|
||||
@ -122,7 +122,7 @@ class CreateCommentScreen(
|
||||
var selectLanguageDialogOpen by remember { mutableStateOf(false) }
|
||||
|
||||
LaunchedEffect(model) {
|
||||
if (editedComment != null) {
|
||||
uiState.editedComment?.also { editedComment ->
|
||||
model.reduce(CreateCommentMviModel.Intent.ChangeLanguage(editedComment.languageId))
|
||||
}
|
||||
model.effects.onEach { effect ->
|
||||
@ -133,7 +133,7 @@ class CreateCommentScreen(
|
||||
|
||||
is CreateCommentMviModel.Effect.Success -> {
|
||||
notificationCenter.send(event = NotificationCenterEvent.CommentCreated)
|
||||
if (originalPost != null) {
|
||||
uiState.originalPost?.also { originalPost ->
|
||||
notificationCenter.send(
|
||||
event = NotificationCenterEvent.PostUpdated(
|
||||
originalPost.copy(
|
||||
@ -146,7 +146,7 @@ class CreateCommentScreen(
|
||||
),
|
||||
)
|
||||
}
|
||||
navigationCoordinator.hideBottomSheet()
|
||||
navigationCoordinator.popScreen()
|
||||
}
|
||||
|
||||
is CreateCommentMviModel.Effect.AddImageToText -> {
|
||||
@ -167,7 +167,7 @@ class CreateCommentScreen(
|
||||
Image(
|
||||
modifier = Modifier.padding(start = Spacing.s).onClick(
|
||||
onClick = rememberCallback {
|
||||
navigationCoordinator.hideBottomSheet()
|
||||
navigationCoordinator.popScreen()
|
||||
},
|
||||
),
|
||||
imageVector = Icons.Default.Close,
|
||||
@ -189,7 +189,7 @@ class CreateCommentScreen(
|
||||
BottomSheetHandle()
|
||||
Text(
|
||||
text = when {
|
||||
editedComment != null -> {
|
||||
uiState.editedComment != null -> {
|
||||
stringResource(MR.strings.edit_comment_title)
|
||||
}
|
||||
|
||||
@ -345,57 +345,55 @@ class CreateCommentScreen(
|
||||
modifier = Modifier.padding(padding),
|
||||
) {
|
||||
item {
|
||||
when {
|
||||
originalComment != null -> {
|
||||
CommentCard(
|
||||
modifier = referenceModifier,
|
||||
comment = originalComment,
|
||||
hideIndent = true,
|
||||
voteFormat = uiState.voteFormat,
|
||||
autoLoadImages = uiState.autoLoadImages,
|
||||
options = buildList {
|
||||
add(
|
||||
Option(
|
||||
OptionId.SeeRaw,
|
||||
stringResource(MR.strings.post_action_see_raw)
|
||||
)
|
||||
val originalComment = uiState.originalComment
|
||||
val originalPost = uiState.originalPost
|
||||
if (originalComment != null) {
|
||||
CommentCard(
|
||||
modifier = referenceModifier,
|
||||
comment = originalComment,
|
||||
hideIndent = true,
|
||||
voteFormat = uiState.voteFormat,
|
||||
autoLoadImages = uiState.autoLoadImages,
|
||||
options = buildList {
|
||||
add(
|
||||
Option(
|
||||
OptionId.SeeRaw,
|
||||
stringResource(MR.strings.post_action_see_raw)
|
||||
)
|
||||
},
|
||||
onOptionSelected = {
|
||||
rawContent = originalComment
|
||||
},
|
||||
)
|
||||
Divider()
|
||||
}
|
||||
|
||||
originalPost != null -> {
|
||||
PostCard(
|
||||
modifier = referenceModifier,
|
||||
postLayout = if (uiState.postLayout == PostLayout.Card) {
|
||||
uiState.postLayout
|
||||
} else {
|
||||
PostLayout.Full
|
||||
},
|
||||
fullHeightImage = uiState.fullHeightImages,
|
||||
post = originalPost,
|
||||
limitBodyHeight = true,
|
||||
blurNsfw = false,
|
||||
includeFullBody = true,
|
||||
voteFormat = uiState.voteFormat,
|
||||
autoLoadImages = uiState.autoLoadImages,
|
||||
options = buildList {
|
||||
add(
|
||||
Option(
|
||||
OptionId.SeeRaw,
|
||||
stringResource(MR.strings.post_action_see_raw)
|
||||
)
|
||||
)
|
||||
},
|
||||
onOptionSelected = {
|
||||
rawContent = originalComment
|
||||
},
|
||||
)
|
||||
Divider()
|
||||
} else if (originalPost != null) {
|
||||
PostCard(
|
||||
modifier = referenceModifier,
|
||||
postLayout = if (uiState.postLayout == PostLayout.Card) {
|
||||
uiState.postLayout
|
||||
} else {
|
||||
PostLayout.Full
|
||||
},
|
||||
fullHeightImage = uiState.fullHeightImages,
|
||||
post = originalPost,
|
||||
limitBodyHeight = true,
|
||||
blurNsfw = false,
|
||||
includeFullBody = true,
|
||||
voteFormat = uiState.voteFormat,
|
||||
autoLoadImages = uiState.autoLoadImages,
|
||||
options = buildList {
|
||||
add(
|
||||
Option(
|
||||
OptionId.SeeRaw,
|
||||
stringResource(MR.strings.post_action_see_raw)
|
||||
)
|
||||
},
|
||||
onOptionSelected = {
|
||||
rawContent = originalPost
|
||||
},
|
||||
)
|
||||
}
|
||||
)
|
||||
},
|
||||
onOptionSelected = {
|
||||
rawContent = originalPost
|
||||
},
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -8,6 +8,7 @@ import com.github.diegoberaldin.raccoonforlemmy.core.notifications.NotificationC
|
||||
import com.github.diegoberaldin.raccoonforlemmy.core.persistence.repository.SettingsRepository
|
||||
import com.github.diegoberaldin.raccoonforlemmy.domain.identity.repository.IdentityRepository
|
||||
import com.github.diegoberaldin.raccoonforlemmy.domain.lemmy.repository.CommentRepository
|
||||
import com.github.diegoberaldin.raccoonforlemmy.domain.lemmy.repository.LemmyItemCache
|
||||
import com.github.diegoberaldin.raccoonforlemmy.domain.lemmy.repository.PostRepository
|
||||
import com.github.diegoberaldin.raccoonforlemmy.domain.lemmy.repository.SiteRepository
|
||||
import com.github.diegoberaldin.raccoonforlemmy.resources.MR.strings.message_missing_field
|
||||
@ -30,15 +31,28 @@ class CreateCommentViewModel(
|
||||
private val themeRepository: ThemeRepository,
|
||||
private val settingsRepository: SettingsRepository,
|
||||
private val notificationCenter: NotificationCenter,
|
||||
private val itemCache: LemmyItemCache,
|
||||
) : CreateCommentMviModel,
|
||||
MviModel<CreateCommentMviModel.Intent, CreateCommentMviModel.UiState, CreateCommentMviModel.Effect> by mvi {
|
||||
|
||||
override fun onStarted() {
|
||||
mvi.onStarted()
|
||||
mvi.scope?.launch {
|
||||
val originalPost = postId?.let { itemCache.getPost(it) }
|
||||
val originalComment = parentId?.let { itemCache.getComment(it) }
|
||||
val editedComment = editedCommentId?.let { itemCache.getComment(it) }
|
||||
mvi.updateState {
|
||||
it.copy(
|
||||
originalPost = originalPost,
|
||||
originalComment = originalComment,
|
||||
editedComment = editedComment,
|
||||
)
|
||||
}
|
||||
|
||||
themeRepository.postLayout.onEach { layout ->
|
||||
mvi.updateState { it.copy(postLayout = layout) }
|
||||
}.launchIn(this)
|
||||
|
||||
if (uiState.value.currentUser.isEmpty()) {
|
||||
val auth = identityRepository.authToken.value.orEmpty()
|
||||
val currentUser = siteRepository.getCurrentUser(auth)
|
||||
|
@ -19,6 +19,7 @@ val createCommentModule = module {
|
||||
themeRepository = get(),
|
||||
settingsRepository = get(),
|
||||
notificationCenter = get(),
|
||||
itemCache = get(),
|
||||
)
|
||||
}
|
||||
}
|
@ -8,6 +8,7 @@ import com.github.diegoberaldin.raccoonforlemmy.core.architecture.MviModel
|
||||
import com.github.diegoberaldin.raccoonforlemmy.core.commonui.lemmyui.CreatePostSection
|
||||
import com.github.diegoberaldin.raccoonforlemmy.domain.lemmy.data.CommunityModel
|
||||
import com.github.diegoberaldin.raccoonforlemmy.domain.lemmy.data.LanguageModel
|
||||
import com.github.diegoberaldin.raccoonforlemmy.domain.lemmy.data.PostModel
|
||||
import dev.icerock.moko.resources.desc.StringDesc
|
||||
|
||||
@Stable
|
||||
@ -57,6 +58,8 @@ interface CreatePostMviModel :
|
||||
}
|
||||
|
||||
data class UiState(
|
||||
val editedPost: PostModel? = null,
|
||||
val crossPost: PostModel? = null,
|
||||
val communityInfo: String = "",
|
||||
val communityId: Int? = null,
|
||||
val communityError: StringDesc? = null,
|
||||
|
@ -87,14 +87,14 @@ import org.koin.core.parameter.parametersOf
|
||||
|
||||
class CreatePostScreen(
|
||||
private val communityId: Int? = null,
|
||||
private val editedPost: PostModel? = null,
|
||||
private val crossPost: PostModel? = null,
|
||||
private val editedPostId: Int? = null,
|
||||
private val crossPostId: Int? = null,
|
||||
) : Screen {
|
||||
@OptIn(ExperimentalMaterial3Api::class)
|
||||
@Composable
|
||||
override fun Content() {
|
||||
val model = getScreenModel<CreatePostMviModel> {
|
||||
parametersOf(editedPost?.id)
|
||||
parametersOf(editedPostId, crossPostId)
|
||||
}
|
||||
model.bindToLifecycle(key)
|
||||
val uiState by model.uiState.collectAsState()
|
||||
@ -103,22 +103,21 @@ class CreatePostScreen(
|
||||
val notificationCenter = remember { getNotificationCenter() }
|
||||
val galleryHelper = remember { getGalleryHelper() }
|
||||
val crossPostText = stringResource(MR.strings.create_post_cross_post_text)
|
||||
val crossPost = uiState.crossPost
|
||||
val editedPost = uiState.editedPost
|
||||
var bodyTextFieldValue by remember {
|
||||
val text = when {
|
||||
crossPost != null -> buildString {
|
||||
val text = buildString {
|
||||
if (crossPost != null) {
|
||||
append(crossPostText)
|
||||
append(" ")
|
||||
append(crossPost.originalUrl)
|
||||
} else if (editedPost != null) {
|
||||
append(editedPost.text)
|
||||
}
|
||||
|
||||
editedPost != null -> {
|
||||
editedPost.text
|
||||
}
|
||||
|
||||
else -> ""
|
||||
}
|
||||
mutableStateOf(TextFieldValue(text = text))
|
||||
}
|
||||
|
||||
val bodyFocusRequester = remember { FocusRequester() }
|
||||
val urlFocusRequester = remember { FocusRequester() }
|
||||
val focusManager = LocalFocusManager.current
|
||||
@ -137,6 +136,7 @@ class CreatePostScreen(
|
||||
model.reduce(CreatePostMviModel.Intent.InsertImageInBody(bytes))
|
||||
}
|
||||
}
|
||||
|
||||
var openSelectCommunity by remember { mutableStateOf(false) }
|
||||
val topAppBarState = rememberTopAppBarState()
|
||||
val scrollBehavior = TopAppBarDefaults.pinnedScrollBehavior(topAppBarState)
|
||||
@ -146,7 +146,7 @@ class CreatePostScreen(
|
||||
var selectLanguageDialogOpen by remember { mutableStateOf(false) }
|
||||
|
||||
LaunchedEffect(model) {
|
||||
val referencePost = editedPost ?: crossPost
|
||||
val referencePost = uiState.editedPost ?: uiState.crossPost
|
||||
model.reduce(CreatePostMviModel.Intent.SetTitle(referencePost?.title.orEmpty()))
|
||||
model.reduce(CreatePostMviModel.Intent.SetUrl(referencePost?.url.orEmpty()))
|
||||
if (editedPost != null) {
|
||||
@ -178,7 +178,7 @@ class CreatePostScreen(
|
||||
notificationCenter.send(
|
||||
event = NotificationCenterEvent.PostCreated,
|
||||
)
|
||||
navigationCoordinator.hideBottomSheet()
|
||||
navigationCoordinator.popScreen()
|
||||
}
|
||||
|
||||
is CreatePostMviModel.Effect.AddImageToBody -> {
|
||||
@ -189,7 +189,8 @@ class CreatePostScreen(
|
||||
}
|
||||
}.launchIn(this)
|
||||
}
|
||||
LaunchedEffect(notificationCenter) {
|
||||
LaunchedEffect(notificationCenter)
|
||||
{
|
||||
notificationCenter.subscribe(NotificationCenterEvent.SelectCommunity::class)
|
||||
.onEach { evt ->
|
||||
model.reduce(CreatePostMviModel.Intent.SetCommunity(evt.model))
|
||||
@ -211,7 +212,7 @@ class CreatePostScreen(
|
||||
Image(
|
||||
modifier = Modifier.padding(start = Spacing.s).onClick(
|
||||
onClick = rememberCallback {
|
||||
navigationCoordinator.hideBottomSheet()
|
||||
navigationCoordinator.popScreen()
|
||||
},
|
||||
),
|
||||
imageVector = Icons.Default.Close,
|
||||
@ -232,7 +233,6 @@ class CreatePostScreen(
|
||||
Text(
|
||||
text = when {
|
||||
editedPost != null -> stringResource(MR.strings.edit_post_title)
|
||||
|
||||
else -> stringResource(MR.strings.create_post_title)
|
||||
},
|
||||
style = MaterialTheme.typography.titleLarge,
|
||||
@ -254,7 +254,8 @@ class CreatePostScreen(
|
||||
)
|
||||
},
|
||||
)
|
||||
}, snackbarHost = {
|
||||
}, snackbarHost =
|
||||
{
|
||||
SnackbarHost(snackbarHostState) { data ->
|
||||
Snackbar(
|
||||
containerColor = MaterialTheme.colorScheme.surfaceVariant,
|
||||
@ -262,7 +263,8 @@ class CreatePostScreen(
|
||||
snackbarData = data,
|
||||
)
|
||||
}
|
||||
}) { padding ->
|
||||
})
|
||||
{ padding ->
|
||||
Column(
|
||||
modifier = Modifier.padding(padding).verticalScroll(rememberScrollState()),
|
||||
) {
|
||||
|
@ -6,6 +6,7 @@ import com.github.diegoberaldin.raccoonforlemmy.core.architecture.MviModel
|
||||
import com.github.diegoberaldin.raccoonforlemmy.core.persistence.repository.SettingsRepository
|
||||
import com.github.diegoberaldin.raccoonforlemmy.core.utils.StringUtils.isValidUrl
|
||||
import com.github.diegoberaldin.raccoonforlemmy.domain.identity.repository.IdentityRepository
|
||||
import com.github.diegoberaldin.raccoonforlemmy.domain.lemmy.repository.LemmyItemCache
|
||||
import com.github.diegoberaldin.raccoonforlemmy.domain.lemmy.repository.PostRepository
|
||||
import com.github.diegoberaldin.raccoonforlemmy.domain.lemmy.repository.SiteRepository
|
||||
import com.github.diegoberaldin.raccoonforlemmy.resources.MR.strings.message_invalid_field
|
||||
@ -18,19 +19,29 @@ import kotlinx.coroutines.flow.onEach
|
||||
import kotlinx.coroutines.launch
|
||||
|
||||
class CreatePostViewModel(
|
||||
private val editedPostId: Int?,
|
||||
private val mvi: DefaultMviModel<CreatePostMviModel.Intent, CreatePostMviModel.UiState, CreatePostMviModel.Effect>,
|
||||
private val editedPostId: Int?,
|
||||
private val crossPostId: Int?,
|
||||
private val identityRepository: IdentityRepository,
|
||||
private val postRepository: PostRepository,
|
||||
private val siteRepository: SiteRepository,
|
||||
private val themeRepository: ThemeRepository,
|
||||
private val settingsRepository: SettingsRepository,
|
||||
private val itemCache: LemmyItemCache,
|
||||
) : CreatePostMviModel,
|
||||
MviModel<CreatePostMviModel.Intent, CreatePostMviModel.UiState, CreatePostMviModel.Effect> by mvi {
|
||||
|
||||
override fun onStarted() {
|
||||
mvi.onStarted()
|
||||
mvi.scope?.launch {
|
||||
val editedPost = editedPostId?.let {
|
||||
itemCache.getPost(it)
|
||||
}
|
||||
val crossPost = crossPostId?.let {
|
||||
itemCache.getPost(it)
|
||||
}
|
||||
mvi.updateState { it.copy(editedPost = editedPost, crossPost = crossPost) }
|
||||
|
||||
themeRepository.postLayout.onEach { layout ->
|
||||
mvi.updateState { it.copy(postLayout = layout) }
|
||||
}.launchIn(this)
|
||||
|
@ -10,11 +10,13 @@ val createPostModule = module {
|
||||
CreatePostViewModel(
|
||||
mvi = DefaultMviModel(CreatePostMviModel.UiState()),
|
||||
editedPostId = params[0],
|
||||
crossPostId = params[1],
|
||||
identityRepository = get(),
|
||||
postRepository = get(),
|
||||
siteRepository = get(),
|
||||
themeRepository = get(),
|
||||
settingsRepository = get(),
|
||||
itemCache = get(),
|
||||
)
|
||||
}
|
||||
}
|
@ -152,8 +152,9 @@ class ModalDrawerViewModel(
|
||||
val res = it - favorites.toSet()
|
||||
favorites + res
|
||||
}
|
||||
val multiCommunitites = multiCommunityRepository.getAll(accountId).sortedBy { it.name }
|
||||
|
||||
val multiCommunitites = accountId?.let {
|
||||
multiCommunityRepository.getAll(it).sortedBy { e -> e.name }
|
||||
}.orEmpty()
|
||||
mvi.updateState {
|
||||
it.copy(
|
||||
refreshing = false,
|
||||
|
@ -190,9 +190,11 @@ class ManageSubscriptionsScreen : Screen {
|
||||
modifier = Modifier.fillMaxWidth()
|
||||
.background(MaterialTheme.colorScheme.background).onClick(
|
||||
onClick = rememberCallback {
|
||||
navigatorCoordinator.pushScreen(
|
||||
MultiCommunityScreen(community),
|
||||
)
|
||||
community.id?.toInt()?.also {
|
||||
navigatorCoordinator.pushScreen(
|
||||
MultiCommunityScreen(it),
|
||||
)
|
||||
}
|
||||
},
|
||||
),
|
||||
community = community,
|
||||
@ -211,7 +213,7 @@ class ManageSubscriptionsScreen : Screen {
|
||||
when (optionId) {
|
||||
OptionId.Edit -> {
|
||||
navigatorCoordinator.pushScreen(
|
||||
MultiCommunityEditorScreen(community),
|
||||
MultiCommunityEditorScreen(community.id?.toInt()),
|
||||
)
|
||||
}
|
||||
|
||||
|
@ -4,6 +4,7 @@ import cafe.adriel.voyager.core.model.ScreenModel
|
||||
import com.github.diegoberaldin.raccoonforlemmy.core.appearance.data.PostLayout
|
||||
import com.github.diegoberaldin.raccoonforlemmy.core.appearance.data.VoteFormat
|
||||
import com.github.diegoberaldin.raccoonforlemmy.core.architecture.MviModel
|
||||
import com.github.diegoberaldin.raccoonforlemmy.core.persistence.data.MultiCommunityModel
|
||||
import com.github.diegoberaldin.raccoonforlemmy.domain.lemmy.data.PostModel
|
||||
import com.github.diegoberaldin.raccoonforlemmy.domain.lemmy.data.SortType
|
||||
|
||||
@ -32,6 +33,7 @@ interface MultiCommunityMviModel :
|
||||
val instance: String = "",
|
||||
val isLogged: Boolean = false,
|
||||
val sortType: SortType? = null,
|
||||
val community: MultiCommunityModel = MultiCommunityModel(),
|
||||
val posts: List<PostModel> = emptyList(),
|
||||
val blurNsfw: Boolean = true,
|
||||
val swipeActionsEnabled: Boolean = true,
|
||||
|
@ -75,7 +75,6 @@ import com.github.diegoberaldin.raccoonforlemmy.core.commonui.lemmyui.di.getFabN
|
||||
import com.github.diegoberaldin.raccoonforlemmy.core.commonui.modals.ShareBottomSheet
|
||||
import com.github.diegoberaldin.raccoonforlemmy.core.commonui.modals.SortBottomSheet
|
||||
import com.github.diegoberaldin.raccoonforlemmy.core.navigation.di.getNavigationCoordinator
|
||||
import com.github.diegoberaldin.raccoonforlemmy.core.persistence.data.MultiCommunityModel
|
||||
import com.github.diegoberaldin.raccoonforlemmy.core.persistence.di.getSettingsRepository
|
||||
import com.github.diegoberaldin.raccoonforlemmy.core.utils.compose.onClick
|
||||
import com.github.diegoberaldin.raccoonforlemmy.core.utils.compose.rememberCallback
|
||||
@ -83,7 +82,6 @@ import com.github.diegoberaldin.raccoonforlemmy.core.utils.compose.rememberCallb
|
||||
import com.github.diegoberaldin.raccoonforlemmy.domain.lemmy.data.getAdditionalLabel
|
||||
import com.github.diegoberaldin.raccoonforlemmy.domain.lemmy.data.toIcon
|
||||
import com.github.diegoberaldin.raccoonforlemmy.resources.MR
|
||||
import com.github.diegoberaldin.raccoonforlemmy.unit.createcomment.CreateCommentScreen
|
||||
import com.github.diegoberaldin.raccoonforlemmy.unit.createreport.CreateReportScreen
|
||||
import com.github.diegoberaldin.raccoonforlemmy.unit.web.WebViewScreen
|
||||
import com.github.diegoberaldin.raccoonforlemmy.unit.zoomableimage.ZoomableImageScreen
|
||||
@ -91,15 +89,18 @@ import dev.icerock.moko.resources.compose.stringResource
|
||||
import kotlinx.coroutines.flow.launchIn
|
||||
import kotlinx.coroutines.flow.onEach
|
||||
import kotlinx.coroutines.launch
|
||||
import org.koin.core.parameter.parametersOf
|
||||
|
||||
class MultiCommunityScreen(
|
||||
private val community: MultiCommunityModel,
|
||||
private val communityId: Int,
|
||||
) : Screen {
|
||||
|
||||
@OptIn(ExperimentalMaterial3Api::class, ExperimentalMaterialApi::class)
|
||||
@Composable
|
||||
override fun Content() {
|
||||
val model = getScreenModel<MultiCommunityMviModel>()
|
||||
val model = getScreenModel<MultiCommunityMviModel>(parameters = {
|
||||
parametersOf(communityId)
|
||||
})
|
||||
model.bindToLifecycle(key)
|
||||
val uiState by model.uiState.collectAsState()
|
||||
val topAppBarState = rememberTopAppBarState()
|
||||
@ -136,7 +137,7 @@ class MultiCommunityScreen(
|
||||
},
|
||||
title = {
|
||||
Text(
|
||||
text = community.name,
|
||||
text = uiState.community.name,
|
||||
maxLines = 1,
|
||||
overflow = TextOverflow.Ellipsis,
|
||||
)
|
||||
@ -302,13 +303,9 @@ class MultiCommunityScreen(
|
||||
model.reduce(MultiCommunityMviModel.Intent.UpVotePost(post.id))
|
||||
},
|
||||
onSecondDismissToStart = rememberCallback(model) {
|
||||
with(navigationCoordinator) {
|
||||
setBottomSheetGesturesEnabled(false)
|
||||
val screen = CreateCommentScreen(
|
||||
originalPost = post,
|
||||
)
|
||||
showBottomSheet(screen)
|
||||
}
|
||||
detailOpener.openReply(
|
||||
originalPost = post,
|
||||
)
|
||||
},
|
||||
onDismissToEnd = {
|
||||
model.reduce(MultiCommunityMviModel.Intent.DownVotePost(post.id))
|
||||
|
@ -6,11 +6,11 @@ import com.github.diegoberaldin.raccoonforlemmy.core.architecture.MviModel
|
||||
import com.github.diegoberaldin.raccoonforlemmy.core.notifications.NotificationCenter
|
||||
import com.github.diegoberaldin.raccoonforlemmy.core.notifications.NotificationCenterEvent
|
||||
import com.github.diegoberaldin.raccoonforlemmy.core.persistence.data.MultiCommunityModel
|
||||
import com.github.diegoberaldin.raccoonforlemmy.core.persistence.repository.MultiCommunityRepository
|
||||
import com.github.diegoberaldin.raccoonforlemmy.core.persistence.repository.SettingsRepository
|
||||
import com.github.diegoberaldin.raccoonforlemmy.core.utils.imagepreload.ImagePreloadManager
|
||||
import com.github.diegoberaldin.raccoonforlemmy.core.utils.share.ShareHelper
|
||||
import com.github.diegoberaldin.raccoonforlemmy.core.utils.vibrate.HapticFeedback
|
||||
import com.github.diegoberaldin.raccoonforlemmy.domain.identity.repository.ApiConfigurationRepository
|
||||
import com.github.diegoberaldin.raccoonforlemmy.domain.identity.repository.IdentityRepository
|
||||
import com.github.diegoberaldin.raccoonforlemmy.domain.lemmy.data.PostModel
|
||||
import com.github.diegoberaldin.raccoonforlemmy.domain.lemmy.data.SortType
|
||||
@ -25,13 +25,14 @@ import kotlinx.coroutines.IO
|
||||
import kotlinx.coroutines.flow.launchIn
|
||||
import kotlinx.coroutines.flow.onEach
|
||||
import kotlinx.coroutines.launch
|
||||
import kotlinx.coroutines.withContext
|
||||
|
||||
class MultiCommunityViewModel(
|
||||
private val mvi: DefaultMviModel<MultiCommunityMviModel.Intent, MultiCommunityMviModel.UiState, MultiCommunityMviModel.Effect>,
|
||||
private val community: MultiCommunityModel,
|
||||
private val communityId: Int,
|
||||
private val postRepository: PostRepository,
|
||||
private val identityRepository: IdentityRepository,
|
||||
private val apiConfigurationRepository: ApiConfigurationRepository,
|
||||
private val multiCommunityRepository: MultiCommunityRepository,
|
||||
private val siteRepository: SiteRepository,
|
||||
private val themeRepository: ThemeRepository,
|
||||
private val shareHelper: ShareHelper,
|
||||
@ -49,6 +50,11 @@ class MultiCommunityViewModel(
|
||||
override fun onStarted() {
|
||||
mvi.onStarted()
|
||||
mvi.scope?.launch {
|
||||
if ((uiState.value.community.id ?: 0) == 0L) {
|
||||
val community =
|
||||
multiCommunityRepository.getById(communityId.toLong()) ?: MultiCommunityModel()
|
||||
mvi.updateState { it.copy(community = community) }
|
||||
}
|
||||
themeRepository.postLayout.onEach { layout ->
|
||||
mvi.updateState { it.copy(postLayout = layout) }
|
||||
}.launchIn(this)
|
||||
@ -80,20 +86,19 @@ class MultiCommunityViewModel(
|
||||
val user = siteRepository.getCurrentUser(auth)
|
||||
mvi.updateState { it.copy(currentUserId = user?.id ?: 0) }
|
||||
}
|
||||
}
|
||||
|
||||
mvi.scope?.launch(Dispatchers.IO) {
|
||||
if (uiState.value.posts.isEmpty()) {
|
||||
val settings = settingsRepository.currentSettings.value
|
||||
val sortTypes = getSortTypesUseCase.getTypesForPosts()
|
||||
mvi.updateState {
|
||||
it.copy(
|
||||
sortType = settings.defaultPostSortType.toSortType(),
|
||||
availableSortTypes = sortTypes,
|
||||
)
|
||||
withContext(Dispatchers.IO) {
|
||||
if (uiState.value.posts.isEmpty()) {
|
||||
val settings = settingsRepository.currentSettings.value
|
||||
val sortTypes = getSortTypesUseCase.getTypesForPosts()
|
||||
mvi.updateState {
|
||||
it.copy(
|
||||
sortType = settings.defaultPostSortType.toSortType(),
|
||||
availableSortTypes = sortTypes,
|
||||
)
|
||||
}
|
||||
paginator.setCommunities(uiState.value.community.communityIds)
|
||||
refresh()
|
||||
}
|
||||
paginator.setCommunities(community.communityIds)
|
||||
refresh()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -13,10 +13,9 @@ val multiCommunityModule = module {
|
||||
factory<MultiCommunityMviModel> { params ->
|
||||
MultiCommunityViewModel(
|
||||
mvi = DefaultMviModel(MultiCommunityMviModel.UiState()),
|
||||
community = params[0],
|
||||
communityId = params[0],
|
||||
postRepository = get(),
|
||||
identityRepository = get(),
|
||||
apiConfigurationRepository = get(),
|
||||
siteRepository = get(),
|
||||
themeRepository = get(),
|
||||
shareHelper = get(),
|
||||
@ -26,6 +25,7 @@ val multiCommunityModule = module {
|
||||
paginator = get(),
|
||||
imagePreloadManager = get(),
|
||||
getSortTypesUseCase = get(),
|
||||
multiCommunityRepository = get(),
|
||||
)
|
||||
}
|
||||
factory<MultiCommunityPaginator> {
|
||||
@ -36,7 +36,7 @@ val multiCommunityModule = module {
|
||||
factory<MultiCommunityEditorMviModel> { params ->
|
||||
MultiCommunityEditorViewModel(
|
||||
mvi = DefaultMviModel(MultiCommunityEditorMviModel.UiState()),
|
||||
editedCommunity = params[0],
|
||||
communityId = params[0],
|
||||
identityRepository = get(),
|
||||
communityRepository = get(),
|
||||
accountRepository = get(),
|
||||
|
@ -60,7 +60,6 @@ import com.github.diegoberaldin.raccoonforlemmy.core.architecture.bindToLifecycl
|
||||
import com.github.diegoberaldin.raccoonforlemmy.core.commonui.components.CustomImage
|
||||
import com.github.diegoberaldin.raccoonforlemmy.core.commonui.lemmyui.CommunityItem
|
||||
import com.github.diegoberaldin.raccoonforlemmy.core.navigation.di.getNavigationCoordinator
|
||||
import com.github.diegoberaldin.raccoonforlemmy.core.persistence.data.MultiCommunityModel
|
||||
import com.github.diegoberaldin.raccoonforlemmy.core.utils.compose.onClick
|
||||
import com.github.diegoberaldin.raccoonforlemmy.core.utils.compose.rememberCallback
|
||||
import com.github.diegoberaldin.raccoonforlemmy.resources.MR
|
||||
@ -71,13 +70,13 @@ import kotlinx.coroutines.flow.onEach
|
||||
import org.koin.core.parameter.parametersOf
|
||||
|
||||
class MultiCommunityEditorScreen(
|
||||
private val editedCommunity: MultiCommunityModel? = null,
|
||||
private val communityId: Int? = null,
|
||||
) : Screen {
|
||||
|
||||
@OptIn(ExperimentalMaterial3Api::class)
|
||||
@Composable
|
||||
override fun Content() {
|
||||
val model = getScreenModel<MultiCommunityEditorMviModel> { parametersOf(editedCommunity) }
|
||||
val model = getScreenModel<MultiCommunityEditorMviModel> { parametersOf(communityId) }
|
||||
model.bindToLifecycle(key)
|
||||
val uiState by model.uiState.collectAsState()
|
||||
val navigationCoordinator = remember { getNavigationCoordinator() }
|
||||
|
@ -23,7 +23,7 @@ import kotlinx.coroutines.launch
|
||||
|
||||
class MultiCommunityEditorViewModel(
|
||||
private val mvi: DefaultMviModel<MultiCommunityEditorMviModel.Intent, MultiCommunityEditorMviModel.UiState, MultiCommunityEditorMviModel.Effect>,
|
||||
private val editedCommunity: MultiCommunityModel? = null,
|
||||
private val communityId: Int?,
|
||||
private val identityRepository: IdentityRepository,
|
||||
private val communityRepository: CommunityRepository,
|
||||
private val multiCommunityRepository: MultiCommunityRepository,
|
||||
@ -60,6 +60,9 @@ class MultiCommunityEditorViewModel(
|
||||
|
||||
private fun populate() {
|
||||
mvi.scope?.launch(Dispatchers.IO) {
|
||||
val editedCommunity = communityId?.toLong()?.let {
|
||||
multiCommunityRepository.getById(it)
|
||||
}
|
||||
val auth = identityRepository.authToken.value
|
||||
communities = communityRepository.getSubscribed(auth).sortedBy { it.name }.map { c ->
|
||||
c to (editedCommunity?.communityIds?.contains(c.id) == true)
|
||||
@ -145,19 +148,21 @@ class MultiCommunityEditorViewModel(
|
||||
return
|
||||
}
|
||||
|
||||
val icon = currentState.icon
|
||||
val communityIds = currentState.communities.filter { it.second }.map { it.first.id }
|
||||
val multiCommunity = editedCommunity?.copy(
|
||||
name = name,
|
||||
icon = icon,
|
||||
communityIds = communityIds,
|
||||
) ?: MultiCommunityModel(
|
||||
name = name,
|
||||
icon = icon,
|
||||
communityIds = communityIds,
|
||||
)
|
||||
|
||||
mvi.scope?.launch(Dispatchers.IO) {
|
||||
val icon = currentState.icon
|
||||
val communityIds = currentState.communities.filter { it.second }.map { it.first.id }
|
||||
val editedCommunity = communityId?.toLong()?.let {
|
||||
multiCommunityRepository.getById(it)
|
||||
}
|
||||
val multiCommunity = editedCommunity?.copy(
|
||||
name = name,
|
||||
icon = icon,
|
||||
communityIds = communityIds,
|
||||
) ?: MultiCommunityModel(
|
||||
name = name,
|
||||
icon = icon,
|
||||
communityIds = communityIds,
|
||||
)
|
||||
val accountId = accountRepository.getActive()?.id ?: return@launch
|
||||
if (multiCommunity.id == null) {
|
||||
val id = multiCommunityRepository.create(multiCommunity, accountId)
|
||||
|
@ -58,8 +58,6 @@ import com.github.diegoberaldin.raccoonforlemmy.core.utils.compose.rememberCallb
|
||||
import com.github.diegoberaldin.raccoonforlemmy.domain.lemmy.data.CommentModel
|
||||
import com.github.diegoberaldin.raccoonforlemmy.domain.lemmy.data.PostModel
|
||||
import com.github.diegoberaldin.raccoonforlemmy.resources.MR
|
||||
import com.github.diegoberaldin.raccoonforlemmy.unit.createcomment.CreateCommentScreen
|
||||
import com.github.diegoberaldin.raccoonforlemmy.unit.createpost.CreatePostScreen
|
||||
import com.github.diegoberaldin.raccoonforlemmy.unit.rawcontent.RawContentDialog
|
||||
import com.github.diegoberaldin.raccoonforlemmy.unit.web.WebViewScreen
|
||||
import com.github.diegoberaldin.raccoonforlemmy.unit.zoomableimage.ZoomableImageScreen
|
||||
@ -259,14 +257,9 @@ object ProfileLoggedScreen : Tab {
|
||||
)
|
||||
|
||||
OptionId.Edit -> {
|
||||
with(navigationCoordinator) {
|
||||
setBottomSheetGesturesEnabled(false)
|
||||
showBottomSheet(
|
||||
CreatePostScreen(
|
||||
editedPost = post,
|
||||
)
|
||||
)
|
||||
}
|
||||
detailOpener.openCreatePost(
|
||||
editedPost = post,
|
||||
)
|
||||
}
|
||||
|
||||
OptionId.SeeRaw -> {
|
||||
@ -327,8 +320,7 @@ object ProfileLoggedScreen : Tab {
|
||||
items = uiState.comments,
|
||||
key = { it.id.toString() + it.updateDate },
|
||||
) { comment ->
|
||||
CommentCard(
|
||||
modifier = Modifier.background(MaterialTheme.colorScheme.background),
|
||||
CommentCard(modifier = Modifier.background(MaterialTheme.colorScheme.background),
|
||||
comment = comment,
|
||||
voteFormat = uiState.voteFormat,
|
||||
autoLoadImages = uiState.autoLoadImages,
|
||||
@ -396,12 +388,9 @@ object ProfileLoggedScreen : Tab {
|
||||
}
|
||||
|
||||
OptionId.Edit -> {
|
||||
with(navigationCoordinator) {
|
||||
setBottomSheetGesturesEnabled(false)
|
||||
showBottomSheet(
|
||||
CreateCommentScreen(editedComment = comment)
|
||||
)
|
||||
}
|
||||
detailOpener.openReply(
|
||||
editedComment = comment,
|
||||
)
|
||||
}
|
||||
|
||||
OptionId.SeeRaw -> {
|
||||
@ -410,8 +399,7 @@ object ProfileLoggedScreen : Tab {
|
||||
|
||||
else -> Unit
|
||||
}
|
||||
}
|
||||
)
|
||||
})
|
||||
Divider(
|
||||
modifier = Modifier.padding(vertical = Spacing.xxxs),
|
||||
thickness = 0.25.dp
|
||||
@ -466,8 +454,7 @@ object ProfileLoggedScreen : Tab {
|
||||
if (rawContent != null) {
|
||||
when (val content = rawContent) {
|
||||
is PostModel -> {
|
||||
RawContentDialog(
|
||||
title = content.title,
|
||||
RawContentDialog(title = content.title,
|
||||
publishDate = content.publishDate,
|
||||
updateDate = content.updateDate,
|
||||
url = content.url,
|
||||
@ -478,27 +465,20 @@ object ProfileLoggedScreen : Tab {
|
||||
onQuote = rememberCallbackArgs { quotation ->
|
||||
rawContent = null
|
||||
if (quotation != null) {
|
||||
with(navigationCoordinator) {
|
||||
setBottomSheetGesturesEnabled(false)
|
||||
val screen =
|
||||
CreateCommentScreen(
|
||||
originalPost = content,
|
||||
initialText = buildString {
|
||||
append("> ")
|
||||
append(quotation)
|
||||
append("\n\n")
|
||||
}
|
||||
)
|
||||
showBottomSheet(screen)
|
||||
}
|
||||
detailOpener.openReply(
|
||||
originalPost = content,
|
||||
initialText = buildString {
|
||||
append("> ")
|
||||
append(quotation)
|
||||
append("\n\n")
|
||||
},
|
||||
)
|
||||
}
|
||||
}
|
||||
)
|
||||
})
|
||||
}
|
||||
|
||||
is CommentModel -> {
|
||||
RawContentDialog(
|
||||
text = content.text,
|
||||
RawContentDialog(text = content.text,
|
||||
publishDate = content.publishDate,
|
||||
updateDate = content.updateDate,
|
||||
onDismiss = {
|
||||
@ -507,21 +487,16 @@ object ProfileLoggedScreen : Tab {
|
||||
onQuote = rememberCallbackArgs { quotation ->
|
||||
rawContent = null
|
||||
if (quotation != null) {
|
||||
with(navigationCoordinator) {
|
||||
setBottomSheetGesturesEnabled(false)
|
||||
val screen = CreateCommentScreen(
|
||||
originalComment = content,
|
||||
initialText = buildString {
|
||||
append("> ")
|
||||
append(quotation)
|
||||
append("\n\n")
|
||||
}
|
||||
)
|
||||
showBottomSheet(screen)
|
||||
}
|
||||
detailOpener.openReply(
|
||||
originalComment = content,
|
||||
initialText = buildString {
|
||||
append("> ")
|
||||
append(quotation)
|
||||
append("\n\n")
|
||||
},
|
||||
)
|
||||
}
|
||||
}
|
||||
)
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -100,8 +100,6 @@ import com.github.diegoberaldin.raccoonforlemmy.domain.lemmy.data.containsId
|
||||
import com.github.diegoberaldin.raccoonforlemmy.domain.lemmy.data.toIcon
|
||||
import com.github.diegoberaldin.raccoonforlemmy.resources.MR
|
||||
import com.github.diegoberaldin.raccoonforlemmy.unit.ban.BanUserScreen
|
||||
import com.github.diegoberaldin.raccoonforlemmy.unit.createcomment.CreateCommentScreen
|
||||
import com.github.diegoberaldin.raccoonforlemmy.unit.createpost.CreatePostScreen
|
||||
import com.github.diegoberaldin.raccoonforlemmy.unit.createreport.CreateReportScreen
|
||||
import com.github.diegoberaldin.raccoonforlemmy.unit.rawcontent.RawContentDialog
|
||||
import com.github.diegoberaldin.raccoonforlemmy.unit.remove.RemoveScreen
|
||||
@ -114,14 +112,14 @@ import kotlinx.coroutines.launch
|
||||
import org.koin.core.parameter.parametersOf
|
||||
|
||||
class PostDetailScreen(
|
||||
private val post: PostModel,
|
||||
private val postId: Int,
|
||||
private val otherInstance: String = "",
|
||||
private val highlightCommentId: Int? = null,
|
||||
private val isMod: Boolean = false,
|
||||
) : Screen {
|
||||
|
||||
override val key: ScreenKey
|
||||
get() = super.key + post.id.toString()
|
||||
get() = super.key + postId.toString()
|
||||
|
||||
@OptIn(
|
||||
ExperimentalMaterial3Api::class,
|
||||
@ -131,17 +129,16 @@ class PostDetailScreen(
|
||||
@Composable
|
||||
override fun Content() {
|
||||
val model = getScreenModel<PostDetailMviModel>(
|
||||
tag = post.id.toString() + highlightCommentId.toString(),
|
||||
tag = postId.toString() + highlightCommentId.toString(),
|
||||
parameters = {
|
||||
parametersOf(
|
||||
post,
|
||||
postId,
|
||||
otherInstance,
|
||||
highlightCommentId,
|
||||
isMod,
|
||||
)
|
||||
}
|
||||
)
|
||||
model.bindToLifecycle(key + post.id.toString())
|
||||
})
|
||||
model.bindToLifecycle(key + postId.toString())
|
||||
val uiState by model.uiState.collectAsState()
|
||||
val isOnOtherInstance = remember { otherInstance.isNotEmpty() }
|
||||
val otherInstanceName = remember { otherInstance }
|
||||
@ -169,9 +166,6 @@ class PostDetailScreen(
|
||||
LaunchedEffect(notificationCenter) {
|
||||
notificationCenter.resetCache()
|
||||
}
|
||||
LaunchedEffect(navigationCoordinator) {
|
||||
navigationCoordinator.setBottomSheetGesturesEnabled(true)
|
||||
}
|
||||
LaunchedEffect(model) {
|
||||
model.effects.onEach { evt ->
|
||||
when (evt) {
|
||||
@ -193,8 +187,7 @@ class PostDetailScreen(
|
||||
}
|
||||
|
||||
Scaffold(
|
||||
modifier = Modifier
|
||||
.background(MaterialTheme.colorScheme.background)
|
||||
modifier = Modifier.background(MaterialTheme.colorScheme.background)
|
||||
.padding(Spacing.xs),
|
||||
topBar = {
|
||||
TopAppBar(
|
||||
@ -268,13 +261,9 @@ class PostDetailScreen(
|
||||
icon = Icons.Default.Reply,
|
||||
text = stringResource(MR.strings.action_reply),
|
||||
onSelected = rememberCallback {
|
||||
with(navigationCoordinator) {
|
||||
setBottomSheetGesturesEnabled(false)
|
||||
val screen = CreateCommentScreen(
|
||||
originalPost = uiState.post,
|
||||
)
|
||||
showBottomSheet(screen)
|
||||
}
|
||||
detailOpener.openReply(
|
||||
originalPost = uiState.post,
|
||||
)
|
||||
},
|
||||
)
|
||||
}
|
||||
@ -297,8 +286,7 @@ class PostDetailScreen(
|
||||
} else {
|
||||
it
|
||||
}
|
||||
}.nestedScroll(fabNestedScrollConnection)
|
||||
.pullRefresh(pullRefreshState),
|
||||
}.nestedScroll(fabNestedScrollConnection).pullRefresh(pullRefreshState),
|
||||
) {
|
||||
LazyColumn(
|
||||
state = lazyListState
|
||||
@ -357,13 +345,9 @@ class PostDetailScreen(
|
||||
},
|
||||
onReply = rememberCallback {
|
||||
if (uiState.isLogged && !isOnOtherInstance) {
|
||||
with(navigationCoordinator) {
|
||||
setBottomSheetGesturesEnabled(false)
|
||||
val screen = CreateCommentScreen(
|
||||
originalPost = uiState.post,
|
||||
)
|
||||
showBottomSheet(screen)
|
||||
}
|
||||
detailOpener.openReply(
|
||||
originalPost = uiState.post,
|
||||
)
|
||||
}
|
||||
},
|
||||
options = buildList {
|
||||
@ -441,12 +425,7 @@ class PostDetailScreen(
|
||||
OptionId.Delete -> model.reduce(PostDetailMviModel.Intent.DeletePost)
|
||||
|
||||
OptionId.Edit -> {
|
||||
with(navigationCoordinator) {
|
||||
setBottomSheetGesturesEnabled(false)
|
||||
showBottomSheet(
|
||||
CreatePostScreen(editedPost = uiState.post),
|
||||
)
|
||||
}
|
||||
detailOpener.openCreatePost(editedPost = uiState.post)
|
||||
}
|
||||
|
||||
OptionId.Report -> {
|
||||
@ -456,12 +435,7 @@ class PostDetailScreen(
|
||||
}
|
||||
|
||||
OptionId.CrossPost -> {
|
||||
with(navigationCoordinator) {
|
||||
setBottomSheetGesturesEnabled(false)
|
||||
showBottomSheet(
|
||||
CreatePostScreen(crossPost = uiState.post),
|
||||
)
|
||||
}
|
||||
detailOpener.openCreatePost(crossPost = uiState.post)
|
||||
}
|
||||
|
||||
OptionId.SeeRaw -> {
|
||||
@ -649,14 +623,10 @@ class PostDetailScreen(
|
||||
)
|
||||
},
|
||||
onSecondDismissToStart = rememberCallback(model) {
|
||||
with(navigationCoordinator) {
|
||||
setBottomSheetGesturesEnabled(false)
|
||||
val screen = CreateCommentScreen(
|
||||
originalPost = uiState.post,
|
||||
originalComment = comment,
|
||||
)
|
||||
showBottomSheet(screen)
|
||||
}
|
||||
detailOpener.openReply(
|
||||
originalPost = uiState.post,
|
||||
originalComment = comment,
|
||||
)
|
||||
},
|
||||
onDismissToEnd = rememberCallback(model) {
|
||||
model.reduce(
|
||||
@ -762,14 +732,10 @@ class PostDetailScreen(
|
||||
},
|
||||
onReply = rememberCallback {
|
||||
if (uiState.isLogged && !isOnOtherInstance) {
|
||||
with(navigationCoordinator) {
|
||||
setBottomSheetGesturesEnabled(false)
|
||||
val screen = CreateCommentScreen(
|
||||
originalPost = uiState.post,
|
||||
originalComment = comment,
|
||||
)
|
||||
showBottomSheet(screen)
|
||||
}
|
||||
detailOpener.openReply(
|
||||
originalPost = uiState.post,
|
||||
originalComment = comment,
|
||||
)
|
||||
}
|
||||
},
|
||||
onOpenCreator = rememberCallbackArgs { user, instance ->
|
||||
@ -777,8 +743,7 @@ class PostDetailScreen(
|
||||
},
|
||||
onOpenCommunity = rememberCallbackArgs { community, instance ->
|
||||
detailOpener.openCommunityDetail(
|
||||
community,
|
||||
instance
|
||||
community, instance
|
||||
)
|
||||
},
|
||||
onOpenPost = rememberCallbackArgs { p, instance ->
|
||||
@ -862,16 +827,9 @@ class PostDetailScreen(
|
||||
)
|
||||
|
||||
OptionId.Edit -> {
|
||||
with(navigationCoordinator) {
|
||||
setBottomSheetGesturesEnabled(
|
||||
false,
|
||||
)
|
||||
showBottomSheet(
|
||||
CreateCommentScreen(
|
||||
editedComment = comment,
|
||||
),
|
||||
)
|
||||
}
|
||||
detailOpener.openReply(
|
||||
editedComment = comment,
|
||||
)
|
||||
}
|
||||
|
||||
OptionId.Report -> {
|
||||
@ -979,14 +937,10 @@ class PostDetailScreen(
|
||||
},
|
||||
onReply = rememberCallback(model) {
|
||||
if (uiState.isLogged && !isOnOtherInstance) {
|
||||
with(navigationCoordinator) {
|
||||
setBottomSheetGesturesEnabled(false)
|
||||
val screen = CreateCommentScreen(
|
||||
originalPost = uiState.post,
|
||||
originalComment = comment,
|
||||
)
|
||||
showBottomSheet(screen)
|
||||
}
|
||||
detailOpener.openReply(
|
||||
originalPost = uiState.post,
|
||||
originalComment = comment,
|
||||
)
|
||||
}
|
||||
},
|
||||
onOpenCreator = rememberCallbackArgs { user ->
|
||||
@ -1058,14 +1012,9 @@ class PostDetailScreen(
|
||||
)
|
||||
|
||||
OptionId.Edit -> {
|
||||
with(navigationCoordinator) {
|
||||
setBottomSheetGesturesEnabled(false)
|
||||
showBottomSheet(
|
||||
CreateCommentScreen(
|
||||
editedComment = comment,
|
||||
),
|
||||
)
|
||||
}
|
||||
detailOpener.openReply(
|
||||
editedComment = comment,
|
||||
)
|
||||
}
|
||||
|
||||
OptionId.Report -> {
|
||||
@ -1174,8 +1123,7 @@ class PostDetailScreen(
|
||||
Column {
|
||||
if (uiState.post.comments == 0) {
|
||||
Text(
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
modifier = Modifier.fillMaxWidth()
|
||||
.padding(top = Spacing.xs),
|
||||
textAlign = TextAlign.Center,
|
||||
text = stringResource(MR.strings.message_empty_comments),
|
||||
@ -1184,8 +1132,7 @@ class PostDetailScreen(
|
||||
)
|
||||
} else {
|
||||
Text(
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
modifier = Modifier.fillMaxWidth()
|
||||
.padding(top = Spacing.xs),
|
||||
textAlign = TextAlign.Center,
|
||||
text = stringResource(MR.strings.message_error_loading_comments),
|
||||
@ -1240,18 +1187,14 @@ class PostDetailScreen(
|
||||
onQuote = rememberCallbackArgs { quotation ->
|
||||
rawContent = null
|
||||
if (quotation != null) {
|
||||
with(navigationCoordinator) {
|
||||
setBottomSheetGesturesEnabled(false)
|
||||
val screen = CreateCommentScreen(
|
||||
originalPost = content,
|
||||
initialText = buildString {
|
||||
append("> ")
|
||||
append(quotation)
|
||||
append("\n\n")
|
||||
},
|
||||
)
|
||||
showBottomSheet(screen)
|
||||
}
|
||||
detailOpener.openReply(
|
||||
originalPost = content,
|
||||
initialText = buildString {
|
||||
append("> ")
|
||||
append(quotation)
|
||||
append("\n\n")
|
||||
},
|
||||
)
|
||||
}
|
||||
},
|
||||
)
|
||||
@ -1268,19 +1211,15 @@ class PostDetailScreen(
|
||||
onQuote = rememberCallbackArgs { quotation ->
|
||||
rawContent = null
|
||||
if (quotation != null) {
|
||||
with(navigationCoordinator) {
|
||||
setBottomSheetGesturesEnabled(false)
|
||||
val screen = CreateCommentScreen(
|
||||
originalPost = uiState.post,
|
||||
originalComment = content,
|
||||
initialText = buildString {
|
||||
append("> ")
|
||||
append(quotation)
|
||||
append("\n\n")
|
||||
},
|
||||
)
|
||||
showBottomSheet(screen)
|
||||
}
|
||||
detailOpener.openReply(
|
||||
originalPost = uiState.post,
|
||||
originalComment = content,
|
||||
initialText = buildString {
|
||||
append("> ")
|
||||
append(quotation)
|
||||
append("\n\n")
|
||||
},
|
||||
)
|
||||
}
|
||||
},
|
||||
)
|
||||
|
@ -18,6 +18,7 @@ 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.CommunityRepository
|
||||
import com.github.diegoberaldin.raccoonforlemmy.domain.lemmy.repository.GetSortTypesUseCase
|
||||
import com.github.diegoberaldin.raccoonforlemmy.domain.lemmy.repository.LemmyItemCache
|
||||
import com.github.diegoberaldin.raccoonforlemmy.domain.lemmy.repository.PostRepository
|
||||
import com.github.diegoberaldin.raccoonforlemmy.domain.lemmy.repository.SiteRepository
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
@ -28,7 +29,7 @@ import kotlinx.coroutines.launch
|
||||
|
||||
class PostDetailViewModel(
|
||||
private val mvi: DefaultMviModel<PostDetailMviModel.Intent, PostDetailMviModel.UiState, PostDetailMviModel.Effect>,
|
||||
private val post: PostModel,
|
||||
private val postId: Int,
|
||||
private val otherInstance: String,
|
||||
private val highlightCommentId: Int?,
|
||||
private val isModerator: Boolean,
|
||||
@ -44,6 +45,7 @@ class PostDetailViewModel(
|
||||
private val notificationCenter: NotificationCenter,
|
||||
private val hapticFeedback: HapticFeedback,
|
||||
private val getSortTypesUseCase: GetSortTypesUseCase,
|
||||
private val itemCache: LemmyItemCache,
|
||||
) : PostDetailMviModel,
|
||||
MviModel<PostDetailMviModel.Intent, PostDetailMviModel.UiState, PostDetailMviModel.Effect> by mvi {
|
||||
|
||||
@ -60,6 +62,15 @@ class PostDetailViewModel(
|
||||
)
|
||||
}
|
||||
mvi.scope?.launch {
|
||||
if (uiState.value.post.id == 0) {
|
||||
val post = itemCache.getPost(postId) ?: PostModel()
|
||||
mvi.updateState {
|
||||
it.copy(
|
||||
post = post,
|
||||
isModerator = isModerator,
|
||||
)
|
||||
}
|
||||
}
|
||||
notificationCenter.subscribe(NotificationCenterEvent.PostUpdated::class).onEach { evt ->
|
||||
handlePostUpdate(evt.model)
|
||||
}.launchIn(this)
|
||||
@ -121,12 +132,11 @@ class PostDetailViewModel(
|
||||
notificationCenter.subscribe(NotificationCenterEvent.Share::class).onEach { evt ->
|
||||
shareHelper.share(evt.url)
|
||||
}.launchIn(this)
|
||||
}
|
||||
|
||||
mvi.scope?.launch(Dispatchers.IO) {
|
||||
identityRepository.isLogged.onEach { logged ->
|
||||
mvi.updateState { it.copy(isLogged = logged ?: false) }
|
||||
}.launchIn(this)
|
||||
|
||||
if (uiState.value.currentUserId == null) {
|
||||
val auth = identityRepository.authToken.value.orEmpty()
|
||||
val user = siteRepository.getCurrentUser(auth)
|
||||
@ -135,16 +145,9 @@ class PostDetailViewModel(
|
||||
}
|
||||
}
|
||||
|
||||
mvi.updateState {
|
||||
it.copy(
|
||||
post = post,
|
||||
isModerator = isModerator,
|
||||
)
|
||||
}
|
||||
|
||||
val auth = identityRepository.authToken.value
|
||||
val updatedPost = postRepository.get(
|
||||
id = post.id,
|
||||
id = postId,
|
||||
auth = auth,
|
||||
instance = otherInstance,
|
||||
)
|
||||
@ -163,7 +166,7 @@ class PostDetailViewModel(
|
||||
highlightCommentPath = comment?.path
|
||||
}
|
||||
if (isModerator) {
|
||||
post.community?.id?.also { communityId ->
|
||||
uiState.value.post.community?.id?.also { communityId ->
|
||||
val moderators = communityRepository.getModerators(
|
||||
auth = auth,
|
||||
id = communityId
|
||||
@ -174,7 +177,7 @@ class PostDetailViewModel(
|
||||
}
|
||||
|
||||
}
|
||||
if (post.text.isEmpty() && post.title.isEmpty()) {
|
||||
if (uiState.value.post.text.isEmpty() && uiState.value.post.title.isEmpty()) {
|
||||
refreshPost()
|
||||
}
|
||||
if (mvi.uiState.value.comments.isEmpty()) {
|
||||
@ -315,10 +318,10 @@ class PostDetailViewModel(
|
||||
mvi.scope?.launch(Dispatchers.IO) {
|
||||
val auth = identityRepository.authToken.value
|
||||
val updatedPost = postRepository.get(
|
||||
id = post.id,
|
||||
id = postId,
|
||||
auth = auth,
|
||||
instance = otherInstance,
|
||||
) ?: post
|
||||
) ?: uiState.value.post
|
||||
mvi.updateState {
|
||||
it.copy(post = updatedPost)
|
||||
}
|
||||
@ -345,7 +348,7 @@ class PostDetailViewModel(
|
||||
val sort = currentState.sortType
|
||||
val itemList = commentRepository.getAll(
|
||||
auth = auth,
|
||||
postId = post.id,
|
||||
postId = postId,
|
||||
instance = otherInstance,
|
||||
page = currentPage,
|
||||
sort = sort,
|
||||
@ -633,9 +636,9 @@ class PostDetailViewModel(
|
||||
private fun deletePost() {
|
||||
mvi.scope?.launch(Dispatchers.IO) {
|
||||
val auth = identityRepository.authToken.value.orEmpty()
|
||||
postRepository.delete(id = post.id, auth = auth)
|
||||
postRepository.delete(id = postId, auth = auth)
|
||||
notificationCenter.send(
|
||||
event = NotificationCenterEvent.PostDeleted(post),
|
||||
event = NotificationCenterEvent.PostDeleted(uiState.value.post),
|
||||
)
|
||||
mvi.emitEffect(PostDetailMviModel.Effect.Close)
|
||||
}
|
||||
@ -719,6 +722,7 @@ class PostDetailViewModel(
|
||||
mvi.scope?.launch(Dispatchers.IO) {
|
||||
val isModerator = uiState.value.moderators.containsId(userId)
|
||||
val auth = identityRepository.authToken.value.orEmpty()
|
||||
val post = uiState.value.post
|
||||
val communityId = post.community?.id
|
||||
if (communityId != null) {
|
||||
val newModerators = communityRepository.addModerator(
|
||||
|
@ -9,7 +9,7 @@ val postDetailModule = module {
|
||||
factory<PostDetailMviModel> { params ->
|
||||
PostDetailViewModel(
|
||||
mvi = DefaultMviModel(PostDetailMviModel.UiState()),
|
||||
post = params[0],
|
||||
postId = params[0],
|
||||
otherInstance = params[1],
|
||||
highlightCommentId = params[2],
|
||||
isModerator = params[3],
|
||||
@ -25,6 +25,7 @@ val postDetailModule = module {
|
||||
notificationCenter = get(),
|
||||
hapticFeedback = get(),
|
||||
getSortTypesUseCase = get(),
|
||||
itemCache = get(),
|
||||
)
|
||||
}
|
||||
}
|
@ -80,8 +80,6 @@ import com.github.diegoberaldin.raccoonforlemmy.core.utils.compose.rememberCallb
|
||||
import com.github.diegoberaldin.raccoonforlemmy.core.utils.keepscreenon.rememberKeepScreenOn
|
||||
import com.github.diegoberaldin.raccoonforlemmy.domain.lemmy.data.PostModel
|
||||
import com.github.diegoberaldin.raccoonforlemmy.resources.MR
|
||||
import com.github.diegoberaldin.raccoonforlemmy.unit.createcomment.CreateCommentScreen
|
||||
import com.github.diegoberaldin.raccoonforlemmy.unit.createpost.CreatePostScreen
|
||||
import com.github.diegoberaldin.raccoonforlemmy.unit.createreport.CreateReportScreen
|
||||
import com.github.diegoberaldin.raccoonforlemmy.unit.rawcontent.RawContentDialog
|
||||
import com.github.diegoberaldin.raccoonforlemmy.unit.web.WebViewScreen
|
||||
@ -345,13 +343,9 @@ class PostListScreen : Screen {
|
||||
model.reduce(PostListMviModel.Intent.UpVotePost(post.id))
|
||||
},
|
||||
onSecondDismissToStart = rememberCallback(model) {
|
||||
with(navigationCoordinator) {
|
||||
setBottomSheetGesturesEnabled(false)
|
||||
val screen = CreateCommentScreen(
|
||||
originalPost = post,
|
||||
)
|
||||
showBottomSheet(screen)
|
||||
}
|
||||
detailOpener.openReply(
|
||||
originalPost = post,
|
||||
)
|
||||
},
|
||||
onDismissToEnd = rememberCallback(model) {
|
||||
model.reduce(PostListMviModel.Intent.DownVotePost(post.id))
|
||||
@ -518,12 +512,7 @@ class PostListScreen : Screen {
|
||||
)
|
||||
|
||||
OptionId.Edit -> {
|
||||
with(navigationCoordinator) {
|
||||
setBottomSheetGesturesEnabled(false)
|
||||
showBottomSheet(
|
||||
CreatePostScreen(editedPost = post),
|
||||
)
|
||||
}
|
||||
detailOpener.openCreatePost(editedPost = post)
|
||||
}
|
||||
|
||||
OptionId.Report -> {
|
||||
@ -533,12 +522,7 @@ class PostListScreen : Screen {
|
||||
}
|
||||
|
||||
OptionId.CrossPost -> {
|
||||
with(navigationCoordinator) {
|
||||
setBottomSheetGesturesEnabled(false)
|
||||
showBottomSheet(
|
||||
CreatePostScreen(crossPost = post),
|
||||
)
|
||||
}
|
||||
detailOpener.openCreatePost(crossPost = post)
|
||||
}
|
||||
|
||||
OptionId.SeeRaw -> {
|
||||
@ -668,19 +652,14 @@ class PostListScreen : Screen {
|
||||
onQuote = rememberCallbackArgs { quotation ->
|
||||
rawContent = null
|
||||
if (quotation != null) {
|
||||
with(navigationCoordinator) {
|
||||
setBottomSheetGesturesEnabled(false)
|
||||
val screen =
|
||||
CreateCommentScreen(
|
||||
originalPost = content,
|
||||
initialText = buildString {
|
||||
append("> ")
|
||||
append(quotation)
|
||||
append("\n\n")
|
||||
},
|
||||
)
|
||||
showBottomSheet(screen)
|
||||
}
|
||||
detailOpener.openReply(
|
||||
originalPost = content,
|
||||
initialText = buildString {
|
||||
append("> ")
|
||||
append(quotation)
|
||||
append("\n\n")
|
||||
},
|
||||
)
|
||||
}
|
||||
}
|
||||
)
|
||||
|
@ -69,7 +69,6 @@ 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.toIcon
|
||||
import com.github.diegoberaldin.raccoonforlemmy.resources.MR
|
||||
import com.github.diegoberaldin.raccoonforlemmy.unit.createcomment.CreateCommentScreen
|
||||
import com.github.diegoberaldin.raccoonforlemmy.unit.createreport.CreateReportScreen
|
||||
import com.github.diegoberaldin.raccoonforlemmy.unit.rawcontent.RawContentDialog
|
||||
import com.github.diegoberaldin.raccoonforlemmy.unit.web.WebViewScreen
|
||||
@ -373,14 +372,11 @@ class SavedItemsScreen : Screen {
|
||||
)
|
||||
},
|
||||
onReply = {
|
||||
with(navigationCoordinator) {
|
||||
setBottomSheetGesturesEnabled(false)
|
||||
val screen = CreateCommentScreen(
|
||||
originalPost = PostModel(id = comment.postId),
|
||||
originalComment = comment,
|
||||
)
|
||||
showBottomSheet(screen)
|
||||
}
|
||||
detailOpener.openReply(
|
||||
originalPost = PostModel(id = comment.postId),
|
||||
originalComment = comment,
|
||||
)
|
||||
|
||||
},
|
||||
options = buildList {
|
||||
add(
|
||||
@ -475,18 +471,14 @@ class SavedItemsScreen : Screen {
|
||||
onQuote = rememberCallbackArgs { quotation ->
|
||||
rawContent = null
|
||||
if (quotation != null) {
|
||||
with(navigationCoordinator) {
|
||||
setBottomSheetGesturesEnabled(false)
|
||||
val screen = CreateCommentScreen(
|
||||
originalPost = content,
|
||||
initialText = buildString {
|
||||
append("> ")
|
||||
append(quotation)
|
||||
append("\n\n")
|
||||
},
|
||||
)
|
||||
showBottomSheet(screen)
|
||||
}
|
||||
detailOpener.openReply(
|
||||
originalPost = content,
|
||||
initialText = buildString {
|
||||
append("> ")
|
||||
append(quotation)
|
||||
append("\n\n")
|
||||
},
|
||||
)
|
||||
}
|
||||
},
|
||||
)
|
||||
@ -503,18 +495,14 @@ class SavedItemsScreen : Screen {
|
||||
onQuote = rememberCallbackArgs { quotation ->
|
||||
rawContent = null
|
||||
if (quotation != null) {
|
||||
with(navigationCoordinator) {
|
||||
setBottomSheetGesturesEnabled(false)
|
||||
val screen = CreateCommentScreen(
|
||||
originalComment = content,
|
||||
initialText = buildString {
|
||||
append("> ")
|
||||
append(quotation)
|
||||
append("\n\n")
|
||||
},
|
||||
)
|
||||
showBottomSheet(screen)
|
||||
}
|
||||
detailOpener.openReply(
|
||||
originalComment = content,
|
||||
initialText = buildString {
|
||||
append("> ")
|
||||
append(quotation)
|
||||
append("\n\n")
|
||||
},
|
||||
)
|
||||
}
|
||||
}
|
||||
)
|
||||
|
@ -100,12 +100,9 @@ import com.github.diegoberaldin.raccoonforlemmy.core.utils.compose.rememberCallb
|
||||
import com.github.diegoberaldin.raccoonforlemmy.core.utils.toLocalDp
|
||||
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.UserModel
|
||||
import com.github.diegoberaldin.raccoonforlemmy.domain.lemmy.data.toIcon
|
||||
import com.github.diegoberaldin.raccoonforlemmy.resources.MR
|
||||
import com.github.diegoberaldin.raccoonforlemmy.unit.chat.InboxChatScreen
|
||||
import com.github.diegoberaldin.raccoonforlemmy.unit.createcomment.CreateCommentScreen
|
||||
import com.github.diegoberaldin.raccoonforlemmy.unit.createpost.CreatePostScreen
|
||||
import com.github.diegoberaldin.raccoonforlemmy.unit.createreport.CreateReportScreen
|
||||
import com.github.diegoberaldin.raccoonforlemmy.unit.rawcontent.RawContentDialog
|
||||
import com.github.diegoberaldin.raccoonforlemmy.unit.userinfo.UserInfoScreen
|
||||
@ -118,21 +115,19 @@ import kotlinx.coroutines.launch
|
||||
import org.koin.core.parameter.parametersOf
|
||||
|
||||
class UserDetailScreen(
|
||||
private val user: UserModel,
|
||||
private val userId: Int,
|
||||
private val otherInstance: String = "",
|
||||
) : Screen {
|
||||
|
||||
override val key: ScreenKey
|
||||
get() = super.key + user.id.toString()
|
||||
get() = super.key + userId.toString()
|
||||
|
||||
@OptIn(ExperimentalMaterial3Api::class, ExperimentalMaterialApi::class)
|
||||
@Composable
|
||||
override fun Content() {
|
||||
val model = getScreenModel<UserDetailMviModel>(
|
||||
tag = user.id.toString(),
|
||||
parameters = { parametersOf(user, otherInstance) }
|
||||
)
|
||||
model.bindToLifecycle(key + user.id.toString())
|
||||
val model = getScreenModel<UserDetailMviModel>(tag = userId.toString(),
|
||||
parameters = { parametersOf(userId, otherInstance) })
|
||||
model.bindToLifecycle(key + userId.toString())
|
||||
val uiState by model.uiState.collectAsState()
|
||||
val lazyListState = rememberLazyListState()
|
||||
val scope = rememberCoroutineScope()
|
||||
@ -181,194 +176,185 @@ class UserDetailScreen(
|
||||
}.launchIn(this)
|
||||
}
|
||||
|
||||
Scaffold(
|
||||
modifier = Modifier
|
||||
.background(MaterialTheme.colorScheme.background)
|
||||
.padding(Spacing.xs),
|
||||
topBar = {
|
||||
val userName = user.name
|
||||
val userHost = user.host
|
||||
val maxTopInset = Dimensions.topBarHeight.value.toInt()
|
||||
var topInset by remember { mutableStateOf(maxTopInset) }
|
||||
snapshotFlow { topAppBarState.collapsedFraction }.onEach {
|
||||
topInset = (maxTopInset * (1 - it)).toInt()
|
||||
}.launchIn(scope)
|
||||
Scaffold(modifier = Modifier.background(MaterialTheme.colorScheme.background)
|
||||
.padding(Spacing.xs), topBar = {
|
||||
val userName = uiState.user.name
|
||||
val userHost = uiState.user.host
|
||||
val maxTopInset = Dimensions.topBarHeight.value.toInt()
|
||||
var topInset by remember { mutableStateOf(maxTopInset) }
|
||||
snapshotFlow { topAppBarState.collapsedFraction }.onEach {
|
||||
topInset = (maxTopInset * (1 - it)).toInt()
|
||||
}.launchIn(scope)
|
||||
|
||||
TopAppBar(
|
||||
windowInsets = if (settings.edgeToEdge) {
|
||||
WindowInsets(0, topInset, 0, 0)
|
||||
} else {
|
||||
TopAppBarDefaults.windowInsets
|
||||
},
|
||||
scrollBehavior = scrollBehavior,
|
||||
title = {
|
||||
Text(
|
||||
modifier = Modifier.padding(horizontal = Spacing.s),
|
||||
text = buildString {
|
||||
append(userName)
|
||||
if (userHost.isNotEmpty()) {
|
||||
append("@$userHost")
|
||||
}
|
||||
TopAppBar(
|
||||
windowInsets = if (settings.edgeToEdge) {
|
||||
WindowInsets(0, topInset, 0, 0)
|
||||
} else {
|
||||
TopAppBarDefaults.windowInsets
|
||||
},
|
||||
scrollBehavior = scrollBehavior,
|
||||
title = {
|
||||
Text(
|
||||
modifier = Modifier.padding(horizontal = Spacing.s),
|
||||
text = buildString {
|
||||
append(userName)
|
||||
if (userHost.isNotEmpty()) {
|
||||
append("@$userHost")
|
||||
}
|
||||
},
|
||||
maxLines = 1,
|
||||
overflow = TextOverflow.Ellipsis,
|
||||
)
|
||||
},
|
||||
actions = {
|
||||
// sort button
|
||||
Image(
|
||||
modifier = Modifier.onClick(
|
||||
onClick = rememberCallback {
|
||||
val sheet = SortBottomSheet(
|
||||
sheetKey = key,
|
||||
values = uiState.availableSortTypes,
|
||||
comments = false,
|
||||
expandTop = true,
|
||||
)
|
||||
navigationCoordinator.showBottomSheet(sheet)
|
||||
},
|
||||
maxLines = 1,
|
||||
overflow = TextOverflow.Ellipsis,
|
||||
),
|
||||
imageVector = uiState.sortType.toIcon(),
|
||||
contentDescription = null,
|
||||
colorFilter = ColorFilter.tint(MaterialTheme.colorScheme.onBackground),
|
||||
)
|
||||
|
||||
// options menu
|
||||
Box {
|
||||
val options = listOf(
|
||||
Option(
|
||||
OptionId.Info, stringResource(MR.strings.user_detail_info)
|
||||
),
|
||||
Option(
|
||||
OptionId.Block,
|
||||
stringResource(MR.strings.community_detail_block)
|
||||
),
|
||||
Option(
|
||||
OptionId.BlockInstance,
|
||||
stringResource(MR.strings.community_detail_block_instance)
|
||||
),
|
||||
)
|
||||
},
|
||||
actions = {
|
||||
// sort button
|
||||
var optionsExpanded by remember { mutableStateOf(false) }
|
||||
var optionsOffset by remember { mutableStateOf(Offset.Zero) }
|
||||
Image(
|
||||
modifier = Modifier.onClick(
|
||||
modifier = Modifier.onGloballyPositioned {
|
||||
optionsOffset = it.positionInParent()
|
||||
}.padding(start = Spacing.s).onClick(
|
||||
onClick = rememberCallback {
|
||||
val sheet = SortBottomSheet(
|
||||
sheetKey = key,
|
||||
values = uiState.availableSortTypes,
|
||||
comments = false,
|
||||
expandTop = true,
|
||||
)
|
||||
navigationCoordinator.showBottomSheet(sheet)
|
||||
optionsExpanded = true
|
||||
},
|
||||
),
|
||||
imageVector = uiState.sortType.toIcon(),
|
||||
imageVector = Icons.Default.MoreVert,
|
||||
contentDescription = null,
|
||||
colorFilter = ColorFilter.tint(MaterialTheme.colorScheme.onBackground),
|
||||
)
|
||||
CustomDropDown(
|
||||
expanded = optionsExpanded,
|
||||
onDismiss = {
|
||||
optionsExpanded = false
|
||||
},
|
||||
offset = DpOffset(
|
||||
x = optionsOffset.x.toLocalDp(),
|
||||
y = optionsOffset.y.toLocalDp(),
|
||||
),
|
||||
) {
|
||||
options.forEach { option ->
|
||||
Text(
|
||||
modifier = Modifier.padding(
|
||||
horizontal = Spacing.m,
|
||||
vertical = Spacing.s,
|
||||
).onClick(
|
||||
onClick = rememberCallback {
|
||||
optionsExpanded = false
|
||||
when (option.id) {
|
||||
OptionId.BlockInstance -> model.reduce(
|
||||
UserDetailMviModel.Intent.BlockInstance
|
||||
)
|
||||
|
||||
// options menu
|
||||
Box {
|
||||
val options = listOf(
|
||||
Option(
|
||||
OptionId.Info,
|
||||
stringResource(MR.strings.user_detail_info)
|
||||
),
|
||||
Option(
|
||||
OptionId.Block,
|
||||
stringResource(MR.strings.community_detail_block)
|
||||
),
|
||||
Option(
|
||||
OptionId.BlockInstance,
|
||||
stringResource(MR.strings.community_detail_block_instance)
|
||||
),
|
||||
)
|
||||
var optionsExpanded by remember { mutableStateOf(false) }
|
||||
var optionsOffset by remember { mutableStateOf(Offset.Zero) }
|
||||
Image(
|
||||
modifier = Modifier.onGloballyPositioned {
|
||||
optionsOffset = it.positionInParent()
|
||||
}.padding(start = Spacing.s).onClick(
|
||||
onClick = rememberCallback {
|
||||
optionsExpanded = true
|
||||
},
|
||||
),
|
||||
imageVector = Icons.Default.MoreVert,
|
||||
contentDescription = null,
|
||||
colorFilter = ColorFilter.tint(MaterialTheme.colorScheme.onBackground),
|
||||
)
|
||||
CustomDropDown(
|
||||
expanded = optionsExpanded,
|
||||
onDismiss = {
|
||||
optionsExpanded = false
|
||||
},
|
||||
offset = DpOffset(
|
||||
x = optionsOffset.x.toLocalDp(),
|
||||
y = optionsOffset.y.toLocalDp(),
|
||||
),
|
||||
) {
|
||||
options.forEach { option ->
|
||||
Text(
|
||||
modifier = Modifier.padding(
|
||||
horizontal = Spacing.m,
|
||||
vertical = Spacing.s,
|
||||
).onClick(
|
||||
onClick = rememberCallback {
|
||||
optionsExpanded = false
|
||||
when (option.id) {
|
||||
OptionId.BlockInstance -> model.reduce(
|
||||
UserDetailMviModel.Intent.BlockInstance
|
||||
OptionId.Block -> model.reduce(
|
||||
UserDetailMviModel.Intent.Block
|
||||
)
|
||||
|
||||
OptionId.Info -> {
|
||||
navigationCoordinator.showBottomSheet(
|
||||
UserInfoScreen(uiState.user.id),
|
||||
)
|
||||
|
||||
OptionId.Block -> model.reduce(
|
||||
UserDetailMviModel.Intent.Block
|
||||
)
|
||||
|
||||
OptionId.Info -> {
|
||||
navigationCoordinator.showBottomSheet(
|
||||
UserInfoScreen(uiState.user),
|
||||
)
|
||||
}
|
||||
|
||||
else -> Unit
|
||||
}
|
||||
},
|
||||
),
|
||||
text = option.text,
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
navigationIcon = {
|
||||
if (navigationCoordinator.canPop.value) {
|
||||
Image(
|
||||
modifier = Modifier.onClick(
|
||||
onClick = rememberCallback {
|
||||
navigationCoordinator.popScreen()
|
||||
},
|
||||
),
|
||||
imageVector = Icons.Default.ArrowBack,
|
||||
contentDescription = null,
|
||||
colorFilter = ColorFilter.tint(MaterialTheme.colorScheme.onBackground),
|
||||
)
|
||||
}
|
||||
},
|
||||
)
|
||||
},
|
||||
floatingActionButton = {
|
||||
AnimatedVisibility(
|
||||
visible = isFabVisible,
|
||||
enter = slideInVertically(
|
||||
initialOffsetY = { it * 2 },
|
||||
),
|
||||
exit = slideOutVertically(
|
||||
targetOffsetY = { it * 2 },
|
||||
),
|
||||
) {
|
||||
FloatingActionButtonMenu(
|
||||
items = buildList {
|
||||
this += FloatingActionButtonMenuItem(
|
||||
icon = Icons.Default.ExpandLess,
|
||||
text = stringResource(MR.strings.action_back_to_top),
|
||||
onSelected = rememberCallback {
|
||||
scope.launch {
|
||||
lazyListState.scrollToItem(0)
|
||||
topAppBarState.heightOffset = 0f
|
||||
topAppBarState.contentOffset = 0f
|
||||
}
|
||||
},
|
||||
)
|
||||
if (uiState.isLogged && !isOnOtherInstance) {
|
||||
this += FloatingActionButtonMenuItem(
|
||||
icon = Icons.Default.Chat,
|
||||
text = stringResource(MR.strings.action_chat),
|
||||
onSelected = rememberCallback {
|
||||
val screen = InboxChatScreen(otherUserId = user.id)
|
||||
navigationCoordinator.pushScreen(screen)
|
||||
},
|
||||
|
||||
else -> Unit
|
||||
}
|
||||
},
|
||||
),
|
||||
text = option.text,
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
navigationIcon = {
|
||||
if (navigationCoordinator.canPop.value) {
|
||||
Image(
|
||||
modifier = Modifier.onClick(
|
||||
onClick = rememberCallback {
|
||||
navigationCoordinator.popScreen()
|
||||
},
|
||||
),
|
||||
imageVector = Icons.Default.ArrowBack,
|
||||
contentDescription = null,
|
||||
colorFilter = ColorFilter.tint(MaterialTheme.colorScheme.onBackground),
|
||||
)
|
||||
}
|
||||
},
|
||||
)
|
||||
}, floatingActionButton = {
|
||||
AnimatedVisibility(
|
||||
visible = isFabVisible,
|
||||
enter = slideInVertically(
|
||||
initialOffsetY = { it * 2 },
|
||||
),
|
||||
exit = slideOutVertically(
|
||||
targetOffsetY = { it * 2 },
|
||||
),
|
||||
) {
|
||||
FloatingActionButtonMenu(items = buildList {
|
||||
this += FloatingActionButtonMenuItem(
|
||||
icon = Icons.Default.ExpandLess,
|
||||
text = stringResource(MR.strings.action_back_to_top),
|
||||
onSelected = rememberCallback {
|
||||
scope.launch {
|
||||
lazyListState.scrollToItem(0)
|
||||
topAppBarState.heightOffset = 0f
|
||||
topAppBarState.contentOffset = 0f
|
||||
}
|
||||
},
|
||||
)
|
||||
}
|
||||
},
|
||||
snackbarHost = {
|
||||
SnackbarHost(snackbarHostState) { data ->
|
||||
Snackbar(
|
||||
containerColor = MaterialTheme.colorScheme.surfaceVariant,
|
||||
contentColor = MaterialTheme.colorScheme.onSurfaceVariant,
|
||||
snackbarData = data,
|
||||
)
|
||||
}
|
||||
if (uiState.isLogged && !isOnOtherInstance) {
|
||||
this += FloatingActionButtonMenuItem(
|
||||
icon = Icons.Default.Chat,
|
||||
text = stringResource(MR.strings.action_chat),
|
||||
onSelected = rememberCallback {
|
||||
val screen = InboxChatScreen(otherUserId = userId)
|
||||
navigationCoordinator.pushScreen(screen)
|
||||
},
|
||||
)
|
||||
}
|
||||
})
|
||||
}
|
||||
) { padding ->
|
||||
}, snackbarHost = {
|
||||
SnackbarHost(snackbarHostState) { data ->
|
||||
Snackbar(
|
||||
containerColor = MaterialTheme.colorScheme.surfaceVariant,
|
||||
contentColor = MaterialTheme.colorScheme.onSurfaceVariant,
|
||||
snackbarData = data,
|
||||
)
|
||||
}
|
||||
}) { padding ->
|
||||
val pullRefreshState = rememberPullRefreshState(
|
||||
refreshing = uiState.refreshing,
|
||||
onRefresh = rememberCallback(model) {
|
||||
@ -376,17 +362,13 @@ class UserDetailScreen(
|
||||
},
|
||||
)
|
||||
Box(
|
||||
modifier = Modifier
|
||||
.padding(padding)
|
||||
.let {
|
||||
if (settings.hideNavigationBarWhileScrolling) {
|
||||
it.nestedScroll(scrollBehavior.nestedScrollConnection)
|
||||
} else {
|
||||
it
|
||||
}
|
||||
modifier = Modifier.padding(padding).let {
|
||||
if (settings.hideNavigationBarWhileScrolling) {
|
||||
it.nestedScroll(scrollBehavior.nestedScrollConnection)
|
||||
} else {
|
||||
it
|
||||
}
|
||||
.nestedScroll(fabNestedScrollConnection)
|
||||
.pullRefresh(pullRefreshState),
|
||||
}.nestedScroll(fabNestedScrollConnection).pullRefresh(pullRefreshState),
|
||||
) {
|
||||
LazyColumn(
|
||||
state = lazyListState,
|
||||
@ -506,13 +488,9 @@ class UserDetailScreen(
|
||||
)
|
||||
},
|
||||
onSecondDismissToStart = rememberCallback(model) {
|
||||
with(navigationCoordinator) {
|
||||
setBottomSheetGesturesEnabled(false)
|
||||
val screen = CreateCommentScreen(
|
||||
originalPost = post,
|
||||
)
|
||||
showBottomSheet(screen)
|
||||
}
|
||||
detailOpener.openReply(
|
||||
originalPost = post,
|
||||
)
|
||||
},
|
||||
onDismissToEnd = rememberCallback(model) {
|
||||
model.reduce(
|
||||
@ -642,12 +620,7 @@ class UserDetailScreen(
|
||||
}
|
||||
|
||||
OptionId.CrossPost -> {
|
||||
with(navigationCoordinator) {
|
||||
setBottomSheetGesturesEnabled(false)
|
||||
showBottomSheet(
|
||||
CreatePostScreen(crossPost = post),
|
||||
)
|
||||
}
|
||||
detailOpener.openCreatePost(crossPost = post)
|
||||
}
|
||||
|
||||
OptionId.SeeRaw -> {
|
||||
@ -773,14 +746,10 @@ class UserDetailScreen(
|
||||
)
|
||||
},
|
||||
onSecondDismissToStart = rememberCallback(model) {
|
||||
with(navigationCoordinator) {
|
||||
setBottomSheetGesturesEnabled(false)
|
||||
val screen = CreateCommentScreen(
|
||||
originalPost = PostModel(id = comment.postId),
|
||||
originalComment = comment,
|
||||
)
|
||||
showBottomSheet(screen)
|
||||
}
|
||||
detailOpener.openReply(
|
||||
originalPost = PostModel(id = comment.postId),
|
||||
originalComment = comment,
|
||||
)
|
||||
},
|
||||
onDismissToEnd = rememberCallback(model) {
|
||||
model.reduce(
|
||||
@ -855,14 +824,10 @@ class UserDetailScreen(
|
||||
null
|
||||
} else {
|
||||
rememberCallback {
|
||||
with(navigationCoordinator) {
|
||||
setBottomSheetGesturesEnabled(false)
|
||||
val screen = CreateCommentScreen(
|
||||
originalPost = PostModel(id = comment.postId),
|
||||
originalComment = comment,
|
||||
)
|
||||
showBottomSheet(screen)
|
||||
}
|
||||
detailOpener.openReply(
|
||||
originalPost = PostModel(id = comment.postId),
|
||||
originalComment = comment,
|
||||
)
|
||||
}
|
||||
},
|
||||
onOpenCommunity = rememberCallbackArgs { community, instance ->
|
||||
@ -982,26 +947,21 @@ class UserDetailScreen(
|
||||
onQuote = rememberCallbackArgs { quotation ->
|
||||
rawContent = null
|
||||
if (quotation != null) {
|
||||
with(navigationCoordinator) {
|
||||
setBottomSheetGesturesEnabled(false)
|
||||
val screen = CreateCommentScreen(
|
||||
originalPost = content,
|
||||
initialText = buildString {
|
||||
append("> ")
|
||||
append(quotation)
|
||||
append("\n\n")
|
||||
},
|
||||
)
|
||||
showBottomSheet(screen)
|
||||
}
|
||||
detailOpener.openReply(
|
||||
originalPost = content,
|
||||
initialText = buildString {
|
||||
append("> ")
|
||||
append(quotation)
|
||||
append("\n\n")
|
||||
},
|
||||
)
|
||||
}
|
||||
}
|
||||
},
|
||||
)
|
||||
}
|
||||
|
||||
is CommentModel -> {
|
||||
RawContentDialog(
|
||||
text = content.text,
|
||||
RawContentDialog(text = content.text,
|
||||
publishDate = content.publishDate,
|
||||
updateDate = content.updateDate,
|
||||
onDismiss = {
|
||||
@ -1010,21 +970,16 @@ class UserDetailScreen(
|
||||
onQuote = rememberCallbackArgs { quotation ->
|
||||
rawContent = null
|
||||
if (quotation != null) {
|
||||
with(navigationCoordinator) {
|
||||
setBottomSheetGesturesEnabled(false)
|
||||
val screen = CreateCommentScreen(
|
||||
originalComment = content,
|
||||
initialText = buildString {
|
||||
append("> ")
|
||||
append(quotation)
|
||||
append("\n\n")
|
||||
},
|
||||
)
|
||||
showBottomSheet(screen)
|
||||
}
|
||||
detailOpener.openReply(
|
||||
originalComment = content,
|
||||
initialText = buildString {
|
||||
append("> ")
|
||||
append(quotation)
|
||||
append("\n\n")
|
||||
},
|
||||
)
|
||||
}
|
||||
}
|
||||
)
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -20,6 +20,7 @@ import com.github.diegoberaldin.raccoonforlemmy.domain.lemmy.data.imageUrl
|
||||
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.GetSortTypesUseCase
|
||||
import com.github.diegoberaldin.raccoonforlemmy.domain.lemmy.repository.LemmyItemCache
|
||||
import com.github.diegoberaldin.raccoonforlemmy.domain.lemmy.repository.PostRepository
|
||||
import com.github.diegoberaldin.raccoonforlemmy.domain.lemmy.repository.SiteRepository
|
||||
import com.github.diegoberaldin.raccoonforlemmy.domain.lemmy.repository.UserRepository
|
||||
@ -34,7 +35,7 @@ import kotlinx.coroutines.withContext
|
||||
|
||||
class UserDetailViewModel(
|
||||
private val mvi: DefaultMviModel<UserDetailMviModel.Intent, UserDetailMviModel.UiState, UserDetailMviModel.Effect>,
|
||||
private val user: UserModel,
|
||||
private val userId: Int,
|
||||
private val otherInstance: String = "",
|
||||
private val identityRepository: IdentityRepository,
|
||||
private val apiConfigurationRepository: ApiConfigurationRepository,
|
||||
@ -49,6 +50,7 @@ class UserDetailViewModel(
|
||||
private val notificationCenter: NotificationCenter,
|
||||
private val imagePreloadManager: ImagePreloadManager,
|
||||
private val getSortTypesUseCase: GetSortTypesUseCase,
|
||||
private val itemCache: LemmyItemCache,
|
||||
) : UserDetailMviModel,
|
||||
MviModel<UserDetailMviModel.Intent, UserDetailMviModel.UiState, UserDetailMviModel.Effect> by mvi {
|
||||
|
||||
@ -63,6 +65,12 @@ class UserDetailViewModel(
|
||||
)
|
||||
}
|
||||
mvi.scope?.launch {
|
||||
if (uiState.value.user.id == 0) {
|
||||
val user = itemCache.getUser(userId) ?: UserModel()
|
||||
mvi.updateState {
|
||||
it.copy(user = user)
|
||||
}
|
||||
}
|
||||
themeRepository.postLayout.onEach { layout ->
|
||||
mvi.updateState { it.copy(postLayout = layout) }
|
||||
}.launchIn(this)
|
||||
@ -77,11 +85,7 @@ class UserDetailViewModel(
|
||||
shareHelper.share(evt.url)
|
||||
}.launchIn(this)
|
||||
}
|
||||
mvi.updateState {
|
||||
it.copy(
|
||||
user = it.user.takeIf { u -> u.id != 0 } ?: user,
|
||||
)
|
||||
}
|
||||
|
||||
mvi.scope?.launch {
|
||||
settingsRepository.currentSettings.onEach { settings ->
|
||||
mvi.updateState {
|
||||
@ -236,10 +240,10 @@ class UserDetailViewModel(
|
||||
}
|
||||
val auth = identityRepository.authToken.value
|
||||
val refreshedUser = userRepository.get(
|
||||
id = user.id,
|
||||
id = userId,
|
||||
auth = auth,
|
||||
otherInstance = otherInstance,
|
||||
username = user.name,
|
||||
username = uiState.value.user.name,
|
||||
)
|
||||
if (refreshedUser != null) {
|
||||
mvi.updateState { it.copy(user = refreshedUser) }
|
||||
@ -266,7 +270,7 @@ class UserDetailViewModel(
|
||||
id = userId,
|
||||
page = currentPage,
|
||||
sort = currentState.sortType,
|
||||
username = user.name,
|
||||
username = uiState.value.user.name,
|
||||
otherInstance = otherInstance,
|
||||
)
|
||||
}.await()
|
||||
@ -279,7 +283,7 @@ class UserDetailViewModel(
|
||||
id = userId,
|
||||
page = currentPage,
|
||||
sort = currentState.sortType,
|
||||
username = user.name,
|
||||
username = uiState.value.user.name,
|
||||
otherInstance = otherInstance,
|
||||
).orEmpty()
|
||||
} else {
|
||||
@ -502,7 +506,6 @@ class UserDetailViewModel(
|
||||
mvi.updateState { it.copy(asyncInProgress = true) }
|
||||
mvi.scope?.launch(Dispatchers.IO) {
|
||||
try {
|
||||
val userId = user.id
|
||||
val auth = identityRepository.authToken.value
|
||||
userRepository.block(userId, true, auth).getOrThrow()
|
||||
mvi.emitEffect(UserDetailMviModel.Effect.BlockSuccess)
|
||||
@ -518,6 +521,7 @@ class UserDetailViewModel(
|
||||
mvi.updateState { it.copy(asyncInProgress = true) }
|
||||
mvi.scope?.launch(Dispatchers.IO) {
|
||||
try {
|
||||
val user = uiState.value.user
|
||||
val instanceId = user.instanceId
|
||||
val auth = identityRepository.authToken.value
|
||||
siteRepository.block(instanceId, true, auth).getOrThrow()
|
||||
|
@ -9,7 +9,7 @@ val userDetailModule = module {
|
||||
factory<UserDetailMviModel> { params ->
|
||||
UserDetailViewModel(
|
||||
mvi = DefaultMviModel(UserDetailMviModel.UiState()),
|
||||
user = params[0],
|
||||
userId = params[0],
|
||||
otherInstance = params[1],
|
||||
identityRepository = get(),
|
||||
apiConfigurationRepository = get(),
|
||||
@ -24,6 +24,7 @@ val userDetailModule = module {
|
||||
notificationCenter = get(),
|
||||
imagePreloadManager = get(),
|
||||
getSortTypesUseCase = get(),
|
||||
itemCache = get(),
|
||||
)
|
||||
}
|
||||
}
|
@ -46,7 +46,6 @@ import com.github.diegoberaldin.raccoonforlemmy.core.navigation.di.getNavigation
|
||||
import com.github.diegoberaldin.raccoonforlemmy.core.utils.compose.rememberCallbackArgs
|
||||
import com.github.diegoberaldin.raccoonforlemmy.core.utils.datetime.prettifyDate
|
||||
import com.github.diegoberaldin.raccoonforlemmy.core.utils.getPrettyNumber
|
||||
import com.github.diegoberaldin.raccoonforlemmy.domain.lemmy.data.UserModel
|
||||
import com.github.diegoberaldin.raccoonforlemmy.resources.MR
|
||||
import com.github.diegoberaldin.raccoonforlemmy.unit.userinfo.components.ModeratedCommunityCell
|
||||
import com.github.diegoberaldin.raccoonforlemmy.unit.web.WebViewScreen
|
||||
@ -57,12 +56,12 @@ import kotlinx.coroutines.launch
|
||||
import org.koin.core.parameter.parametersOf
|
||||
|
||||
class UserInfoScreen(
|
||||
private val user: UserModel,
|
||||
private val userId: Int,
|
||||
) : Screen {
|
||||
@OptIn(ExperimentalMaterial3Api::class)
|
||||
@Composable
|
||||
override fun Content() {
|
||||
val model = getScreenModel<UserInfoMviModel> { parametersOf(user) }
|
||||
val model = getScreenModel<UserInfoMviModel> { parametersOf(userId) }
|
||||
model.bindToLifecycle(key)
|
||||
val uiState by model.uiState.collectAsState()
|
||||
val navigationCoordinator = remember { getNavigationCoordinator() }
|
||||
|
@ -4,27 +4,29 @@ import com.github.diegoberaldin.raccoonforlemmy.core.architecture.DefaultMviMode
|
||||
import com.github.diegoberaldin.raccoonforlemmy.core.architecture.MviModel
|
||||
import com.github.diegoberaldin.raccoonforlemmy.core.persistence.repository.SettingsRepository
|
||||
import com.github.diegoberaldin.raccoonforlemmy.domain.lemmy.data.UserModel
|
||||
import com.github.diegoberaldin.raccoonforlemmy.domain.lemmy.repository.LemmyItemCache
|
||||
import com.github.diegoberaldin.raccoonforlemmy.domain.lemmy.repository.UserRepository
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.IO
|
||||
import kotlinx.coroutines.flow.launchIn
|
||||
import kotlinx.coroutines.flow.onEach
|
||||
import kotlinx.coroutines.launch
|
||||
|
||||
class UserInfoViewModel(
|
||||
private val mvi: DefaultMviModel<UserInfoMviModel.Intent, UserInfoMviModel.UiState, UserInfoMviModel.Effect>,
|
||||
private val user: UserModel,
|
||||
private val userId: Int,
|
||||
private val userRepository: UserRepository,
|
||||
private val settingsRepository: SettingsRepository,
|
||||
private val itemCache: LemmyItemCache,
|
||||
) : UserInfoMviModel,
|
||||
MviModel<UserInfoMviModel.Intent, UserInfoMviModel.UiState, UserInfoMviModel.Effect> by mvi {
|
||||
|
||||
override fun onStarted() {
|
||||
mvi.onStarted()
|
||||
mvi.updateState {
|
||||
it.copy(user = user)
|
||||
}
|
||||
mvi.scope?.launch(Dispatchers.IO) {
|
||||
|
||||
mvi.scope?.launch {
|
||||
val user = itemCache.getUser(userId) ?: UserModel()
|
||||
mvi.updateState {
|
||||
it.copy(user = user)
|
||||
}
|
||||
settingsRepository.currentSettings.onEach {
|
||||
mvi.updateState { it.copy(autoLoadImages = it.autoLoadImages) }
|
||||
}.launchIn(this)
|
||||
|
@ -9,9 +9,10 @@ val userInfoModule = module {
|
||||
factory<UserInfoMviModel> { params ->
|
||||
UserInfoViewModel(
|
||||
mvi = DefaultMviModel(UserInfoMviModel.UiState()),
|
||||
user = params[0],
|
||||
userId = params[0],
|
||||
userRepository = get(),
|
||||
settingsRepository = get(),
|
||||
itemCache = get(),
|
||||
)
|
||||
}
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user