diff --git a/core-api/src/commonMain/kotlin/com/github/diegoberaldin/raccoonforlemmy/core/api/dto/BlockSiteForm.kt b/core-api/src/commonMain/kotlin/com/github/diegoberaldin/raccoonforlemmy/core/api/dto/BlockSiteForm.kt new file mode 100644 index 000000000..059ecf8d7 --- /dev/null +++ b/core-api/src/commonMain/kotlin/com/github/diegoberaldin/raccoonforlemmy/core/api/dto/BlockSiteForm.kt @@ -0,0 +1,10 @@ +package com.github.diegoberaldin.raccoonforlemmy.core.api.dto + +import kotlinx.serialization.SerialName +import kotlinx.serialization.Serializable + +@Serializable +data class BlockSiteForm( + @SerialName("instance_id") val instanceId: InstanceId, + @SerialName("block") val block: Boolean, +) \ No newline at end of file diff --git a/core-api/src/commonMain/kotlin/com/github/diegoberaldin/raccoonforlemmy/core/api/dto/CommunityAggregates.kt b/core-api/src/commonMain/kotlin/com/github/diegoberaldin/raccoonforlemmy/core/api/dto/CommunityAggregates.kt index a0a7aba8e..759f50bc2 100644 --- a/core-api/src/commonMain/kotlin/com/github/diegoberaldin/raccoonforlemmy/core/api/dto/CommunityAggregates.kt +++ b/core-api/src/commonMain/kotlin/com/github/diegoberaldin/raccoonforlemmy/core/api/dto/CommunityAggregates.kt @@ -15,5 +15,5 @@ data class CommunityAggregates( @SerialName("users_active_week") val usersActiveWeek: Int, @SerialName("users_active_month") val usersActiveMonth: Int, @SerialName("users_active_half_year") val usersActiveHalfYear: Int, - @SerialName("hot_rank") val hotRank: Int, + @SerialName("hot_rank") val hotRank: Int? = null, ) diff --git a/core-api/src/commonMain/kotlin/com/github/diegoberaldin/raccoonforlemmy/core/api/dto/GetPostsResponse.kt b/core-api/src/commonMain/kotlin/com/github/diegoberaldin/raccoonforlemmy/core/api/dto/GetPostsResponse.kt index e96090925..998196cb9 100644 --- a/core-api/src/commonMain/kotlin/com/github/diegoberaldin/raccoonforlemmy/core/api/dto/GetPostsResponse.kt +++ b/core-api/src/commonMain/kotlin/com/github/diegoberaldin/raccoonforlemmy/core/api/dto/GetPostsResponse.kt @@ -6,4 +6,5 @@ import kotlinx.serialization.Serializable @Serializable data class GetPostsResponse( @SerialName("posts") val posts: List, + @SerialName("next_page") val nextPage: String? = null, ) diff --git a/core-api/src/commonMain/kotlin/com/github/diegoberaldin/raccoonforlemmy/core/api/dto/Person.kt b/core-api/src/commonMain/kotlin/com/github/diegoberaldin/raccoonforlemmy/core/api/dto/Person.kt index defb6e677..f277828e2 100644 --- a/core-api/src/commonMain/kotlin/com/github/diegoberaldin/raccoonforlemmy/core/api/dto/Person.kt +++ b/core-api/src/commonMain/kotlin/com/github/diegoberaldin/raccoonforlemmy/core/api/dto/Person.kt @@ -18,7 +18,7 @@ data class Person( @SerialName("banner") val banner: String? = null, @SerialName("deleted") val deleted: Boolean, @SerialName("matrix_user_id") val matrixUserId: String? = null, - @SerialName("admin") val admin: Boolean, + @SerialName("admin") val admin: Boolean? = null, @SerialName("bot_account") val botAccount: Boolean, @SerialName("ban_expires") val banExpires: String? = null, @SerialName("instance_id") val instanceId: InstanceId, diff --git a/core-api/src/commonMain/kotlin/com/github/diegoberaldin/raccoonforlemmy/core/api/dto/PostAggregates.kt b/core-api/src/commonMain/kotlin/com/github/diegoberaldin/raccoonforlemmy/core/api/dto/PostAggregates.kt index 333b02cfd..ff597767c 100644 --- a/core-api/src/commonMain/kotlin/com/github/diegoberaldin/raccoonforlemmy/core/api/dto/PostAggregates.kt +++ b/core-api/src/commonMain/kotlin/com/github/diegoberaldin/raccoonforlemmy/core/api/dto/PostAggregates.kt @@ -12,10 +12,10 @@ data class PostAggregates( @SerialName("upvotes") val upvotes: Int, @SerialName("downvotes") val downvotes: Int, @SerialName("published") val published: String, - @SerialName("newest_comment_time_necro") val newestCommentTimeNecro: String, - @SerialName("newest_comment_time") val newestCommentTime: String, - @SerialName("featured_community") val featuredCommunity: Boolean, - @SerialName("featured_local") val featuredLocal: Boolean, - @SerialName("hot_rank") val hotRank: Int, - @SerialName("hot_rank_active") val hotRankActive: Int, + @SerialName("newest_comment_time_necro") val newestCommentTimeNecro: String? = null, + @SerialName("newest_comment_time") val newestCommentTime: String? = null, + @SerialName("featured_community") val featuredCommunity: Boolean? = null, + @SerialName("featured_local") val featuredLocal: Boolean? = null, + @SerialName("hot_rank") val hotRank: Int? = null, + @SerialName("hot_rank_active") val hotRankActive: Int? = null, ) diff --git a/core-api/src/commonMain/kotlin/com/github/diegoberaldin/raccoonforlemmy/core/api/dto/SortType.kt b/core-api/src/commonMain/kotlin/com/github/diegoberaldin/raccoonforlemmy/core/api/dto/SortType.kt index ae3ca457b..d31a98e20 100644 --- a/core-api/src/commonMain/kotlin/com/github/diegoberaldin/raccoonforlemmy/core/api/dto/SortType.kt +++ b/core-api/src/commonMain/kotlin/com/github/diegoberaldin/raccoonforlemmy/core/api/dto/SortType.kt @@ -59,4 +59,7 @@ enum class SortType { @SerialName("Controversial") Controversial, + + @SerialName("Scaled") + Scaled, } diff --git a/core-api/src/commonMain/kotlin/com/github/diegoberaldin/raccoonforlemmy/core/api/service/CommentService.kt b/core-api/src/commonMain/kotlin/com/github/diegoberaldin/raccoonforlemmy/core/api/service/CommentService.kt index b03ca9830..33b799039 100644 --- a/core-api/src/commonMain/kotlin/com/github/diegoberaldin/raccoonforlemmy/core/api/service/CommentService.kt +++ b/core-api/src/commonMain/kotlin/com/github/diegoberaldin/raccoonforlemmy/core/api/service/CommentService.kt @@ -13,6 +13,7 @@ import com.github.diegoberaldin.raccoonforlemmy.core.api.dto.SaveCommentForm import de.jensklingenberg.ktorfit.Response import de.jensklingenberg.ktorfit.http.Body import de.jensklingenberg.ktorfit.http.GET +import de.jensklingenberg.ktorfit.http.Header import de.jensklingenberg.ktorfit.http.Headers import de.jensklingenberg.ktorfit.http.POST import de.jensklingenberg.ktorfit.http.PUT @@ -21,6 +22,7 @@ import de.jensklingenberg.ktorfit.http.Query interface CommentService { @GET("comment/list") suspend fun getAll( + @Header("Authorization") authHeader: String? = null, @Query("auth") auth: String? = null, @Query("limit") limit: Int? = null, @Query("sort") sort: CommentSortType? = null, @@ -36,27 +38,43 @@ interface CommentService { @GET("comment") suspend fun getBy( + @Header("Authorization") authHeader: String? = null, @Query("id") id: Int, @Query("auth") auth: String? = null, ): Response @PUT("comment/save") @Headers("Content-Type: application/json") - suspend fun save(@Body form: SaveCommentForm): Response + suspend fun save( + @Header("Authorization") authHeader: String? = null, + @Body form: SaveCommentForm, + ): Response @POST("comment/like") @Headers("Content-Type: application/json") - suspend fun like(@Body form: CreateCommentLikeForm): Response + suspend fun like( + @Header("Authorization") authHeader: String? = null, + @Body form: CreateCommentLikeForm, + ): Response @POST("comment") @Headers("Content-Type: application/json") - suspend fun create(@Body form: CreateCommentForm): Response + suspend fun create( + @Header("Authorization") authHeader: String? = null, + @Body form: CreateCommentForm, + ): Response @PUT("comment") @Headers("Content-Type: application/json") - suspend fun edit(@Body form: EditCommentForm): Response + suspend fun edit( + @Header("Authorization") authHeader: String? = null, + @Body form: EditCommentForm, + ): Response @POST("comment/delete") @Headers("Content-Type: application/json") - suspend fun delete(@Body form: DeleteCommentForm): Response + suspend fun delete( + @Header("Authorization") authHeader: String? = null, + @Body form: DeleteCommentForm, + ): Response } diff --git a/core-api/src/commonMain/kotlin/com/github/diegoberaldin/raccoonforlemmy/core/api/service/CommunityService.kt b/core-api/src/commonMain/kotlin/com/github/diegoberaldin/raccoonforlemmy/core/api/service/CommunityService.kt index 7ef8eda13..c52469c35 100644 --- a/core-api/src/commonMain/kotlin/com/github/diegoberaldin/raccoonforlemmy/core/api/service/CommunityService.kt +++ b/core-api/src/commonMain/kotlin/com/github/diegoberaldin/raccoonforlemmy/core/api/service/CommunityService.kt @@ -10,6 +10,7 @@ import com.github.diegoberaldin.raccoonforlemmy.core.api.dto.SortType import de.jensklingenberg.ktorfit.Response import de.jensklingenberg.ktorfit.http.Body import de.jensklingenberg.ktorfit.http.GET +import de.jensklingenberg.ktorfit.http.Header import de.jensklingenberg.ktorfit.http.Headers import de.jensklingenberg.ktorfit.http.POST import de.jensklingenberg.ktorfit.http.Query @@ -18,6 +19,7 @@ interface CommunityService { @GET("community") suspend fun get( + @Header("Authorization") authHeader: String? = null, @Query("auth") auth: String? = null, @Query("id") id: Int? = null, @Query("name") name: String? = null, @@ -25,6 +27,7 @@ interface CommunityService { @GET("community/list") suspend fun getAll( + @Header("Authorization") authHeader: String? = null, @Query("auth") auth: String? = null, @Query("page") page: Int? = null, @Query("limit") limit: Int? = null, @@ -34,9 +37,15 @@ interface CommunityService { @POST("community/follow") @Headers("Content-Type: application/json") - suspend fun follow(@Body form: FollowCommunityForm): Response + suspend fun follow( + @Header("Authorization") authHeader: String? = null, + @Body form: FollowCommunityForm, + ): Response @POST("community/block") @Headers("Content-Type: application/json") - suspend fun block(@Body form: BlockCommunityForm): Response + suspend fun block( + @Header("Authorization") authHeader: String? = null, + @Body form: BlockCommunityForm, + ): Response } diff --git a/core-api/src/commonMain/kotlin/com/github/diegoberaldin/raccoonforlemmy/core/api/service/PostService.kt b/core-api/src/commonMain/kotlin/com/github/diegoberaldin/raccoonforlemmy/core/api/service/PostService.kt index e79928ebb..a45117a4c 100644 --- a/core-api/src/commonMain/kotlin/com/github/diegoberaldin/raccoonforlemmy/core/api/service/PostService.kt +++ b/core-api/src/commonMain/kotlin/com/github/diegoberaldin/raccoonforlemmy/core/api/service/PostService.kt @@ -16,7 +16,6 @@ import de.jensklingenberg.ktorfit.http.Body import de.jensklingenberg.ktorfit.http.GET import de.jensklingenberg.ktorfit.http.Header import de.jensklingenberg.ktorfit.http.Headers -import de.jensklingenberg.ktorfit.http.Multipart import de.jensklingenberg.ktorfit.http.POST import de.jensklingenberg.ktorfit.http.PUT import de.jensklingenberg.ktorfit.http.Query @@ -27,10 +26,12 @@ interface PostService { @GET("post/list") suspend fun getAll( + @Header("Authorization") authHeader: String? = null, @Query("auth") auth: String? = null, @Query("limit") limit: Int? = null, @Query("sort") sort: SortType? = null, @Query("page") page: Int? = null, + @Query("page_cursor") pageCursor: String? = null, @Query("type_") type: ListingType? = null, @Query("community_id") communityId: Int? = null, @Query("community_name") communityName: String? = null, @@ -39,6 +40,7 @@ interface PostService { @GET("post") suspend fun get( + @Header("Authorization") authHeader: String? = null, @Query("auth") auth: String? = null, @Query("id") id: Int? = null, @Query("comment_id") commentId: Int? = null, @@ -46,28 +48,44 @@ interface PostService { @PUT("post/save") @Headers("Content-Type: application/json") - suspend fun save(@Body form: SavePostForm): Response + suspend fun save( + @Header("Authorization") authHeader: String? = null, + @Body form: SavePostForm, + ): Response @POST("post/like") @Headers("Content-Type: application/json") - suspend fun like(@Body form: CreatePostLikeForm): Response + suspend fun like( + @Header("Authorization") authHeader: String? = null, + @Body form: CreatePostLikeForm, + ): Response @POST("post") @Headers("Content-Type: application/json") - suspend fun create(@Body form: CreatePostForm): Response + suspend fun create( + @Header("Authorization") authHeader: String? = null, + @Body form: CreatePostForm, + ): Response @PUT("post") @Headers("Content-Type: application/json") - suspend fun edit(@Body form: EditPostForm): Response + suspend fun edit( + @Header("Authorization") authHeader: String? = null, + @Body form: EditPostForm, + ): Response @POST("post/delete") @Headers("Content-Type: application/json") - suspend fun delete(@Body form: DeletePostForm): Response + suspend fun delete( + @Header("Authorization") authHeader: String? = null, + @Body form: DeletePostForm, + ): Response @POST suspend fun uploadImage( @Url url: String, @Header("Cookie") token: String, + @Header("Authorization") authHeader: String? = null, @Body content: MultiPartFormDataContent, ): Response } diff --git a/core-api/src/commonMain/kotlin/com/github/diegoberaldin/raccoonforlemmy/core/api/service/PrivateMessageService.kt b/core-api/src/commonMain/kotlin/com/github/diegoberaldin/raccoonforlemmy/core/api/service/PrivateMessageService.kt index 36050896b..2de652500 100644 --- a/core-api/src/commonMain/kotlin/com/github/diegoberaldin/raccoonforlemmy/core/api/service/PrivateMessageService.kt +++ b/core-api/src/commonMain/kotlin/com/github/diegoberaldin/raccoonforlemmy/core/api/service/PrivateMessageService.kt @@ -7,6 +7,7 @@ import com.github.diegoberaldin.raccoonforlemmy.core.api.dto.PrivateMessagesResp import de.jensklingenberg.ktorfit.Response import de.jensklingenberg.ktorfit.http.Body import de.jensklingenberg.ktorfit.http.GET +import de.jensklingenberg.ktorfit.http.Header import de.jensklingenberg.ktorfit.http.Headers import de.jensklingenberg.ktorfit.http.POST import de.jensklingenberg.ktorfit.http.Query @@ -14,6 +15,7 @@ import de.jensklingenberg.ktorfit.http.Query interface PrivateMessageService { @GET("private_message/list") suspend fun getPrivateMessages( + @Header("Authorization") authHeader: String? = null, @Query("auth") auth: String? = null, @Query("page") page: Int? = null, @Query("limit") limit: Int? = null, @@ -22,9 +24,15 @@ interface PrivateMessageService { @POST("private_message") @Headers("Content-Type: application/json") - suspend fun createPrivateMessage(@Body form: CreatePrivateMessageForm): Response + suspend fun createPrivateMessage( + @Header("Authorization") authHeader: String? = null, + @Body form: CreatePrivateMessageForm, + ): Response @POST("private_message/mark_as_read") @Headers("Content-Type: application/json") - suspend fun markPrivateMessageAsRead(@Body form: MarkPrivateMessageAsReadForm): Response + suspend fun markPrivateMessageAsRead( + @Header("Authorization") authHeader: String? = null, + @Body form: MarkPrivateMessageAsReadForm, + ): Response } diff --git a/core-api/src/commonMain/kotlin/com/github/diegoberaldin/raccoonforlemmy/core/api/service/SearchService.kt b/core-api/src/commonMain/kotlin/com/github/diegoberaldin/raccoonforlemmy/core/api/service/SearchService.kt index 72c29b2fe..270dbc7f9 100644 --- a/core-api/src/commonMain/kotlin/com/github/diegoberaldin/raccoonforlemmy/core/api/service/SearchService.kt +++ b/core-api/src/commonMain/kotlin/com/github/diegoberaldin/raccoonforlemmy/core/api/service/SearchService.kt @@ -6,11 +6,13 @@ import com.github.diegoberaldin.raccoonforlemmy.core.api.dto.SearchType import com.github.diegoberaldin.raccoonforlemmy.core.api.dto.SortType import de.jensklingenberg.ktorfit.Response import de.jensklingenberg.ktorfit.http.GET +import de.jensklingenberg.ktorfit.http.Header import de.jensklingenberg.ktorfit.http.Query interface SearchService { @GET("search") suspend fun search( + @Header("Authorization") authHeader: String? = null, @Query("q") q: String, @Query("community_id") communityId: Int? = null, @Query("community_name") communityName: String? = null, diff --git a/core-api/src/commonMain/kotlin/com/github/diegoberaldin/raccoonforlemmy/core/api/service/SiteService.kt b/core-api/src/commonMain/kotlin/com/github/diegoberaldin/raccoonforlemmy/core/api/service/SiteService.kt index d218f4c8d..9884929c9 100644 --- a/core-api/src/commonMain/kotlin/com/github/diegoberaldin/raccoonforlemmy/core/api/service/SiteService.kt +++ b/core-api/src/commonMain/kotlin/com/github/diegoberaldin/raccoonforlemmy/core/api/service/SiteService.kt @@ -1,19 +1,33 @@ package com.github.diegoberaldin.raccoonforlemmy.core.api.service +import com.github.diegoberaldin.raccoonforlemmy.core.api.dto.BlockSiteForm import com.github.diegoberaldin.raccoonforlemmy.core.api.dto.GetSiteMetadataResponse import com.github.diegoberaldin.raccoonforlemmy.core.api.dto.GetSiteResponse import de.jensklingenberg.ktorfit.Response +import de.jensklingenberg.ktorfit.http.Body import de.jensklingenberg.ktorfit.http.GET +import de.jensklingenberg.ktorfit.http.Header +import de.jensklingenberg.ktorfit.http.Headers +import de.jensklingenberg.ktorfit.http.POST import de.jensklingenberg.ktorfit.http.Query interface SiteService { @GET("site") suspend fun get( + @Header("Authorization") authHeader: String? = null, @Query("auth") auth: String? = null, ): Response + @POST("site/block") + @Headers("Content-Type: application/json") + suspend fun block( + @Header("Authorization") authHeader: String? = null, + @Body form: BlockSiteForm, + ): Response + @GET("post/site_metadata") suspend fun getSiteMetadata( + @Header("Authorization") authHeader: String? = null, @Query("url") url: String, ): Response diff --git a/core-api/src/commonMain/kotlin/com/github/diegoberaldin/raccoonforlemmy/core/api/service/UserService.kt b/core-api/src/commonMain/kotlin/com/github/diegoberaldin/raccoonforlemmy/core/api/service/UserService.kt index 33db02745..490d5527e 100644 --- a/core-api/src/commonMain/kotlin/com/github/diegoberaldin/raccoonforlemmy/core/api/service/UserService.kt +++ b/core-api/src/commonMain/kotlin/com/github/diegoberaldin/raccoonforlemmy/core/api/service/UserService.kt @@ -14,6 +14,7 @@ import com.github.diegoberaldin.raccoonforlemmy.core.api.dto.PersonMentionRespon import de.jensklingenberg.ktorfit.Response import de.jensklingenberg.ktorfit.http.Body import de.jensklingenberg.ktorfit.http.GET +import de.jensklingenberg.ktorfit.http.Header import de.jensklingenberg.ktorfit.http.Headers import de.jensklingenberg.ktorfit.http.POST import de.jensklingenberg.ktorfit.http.Query @@ -22,6 +23,7 @@ interface UserService { @GET("user") suspend fun getDetails( + @Header("Authorization") authHeader: String? = null, @Query("auth") auth: String? = null, @Query("community_id") communityId: Int? = null, @Query("person_id") personId: Int? = null, @@ -34,6 +36,7 @@ interface UserService { @GET("user/mention") suspend fun getMentions( + @Header("Authorization") authHeader: String? = null, @Query("auth") auth: String? = null, @Query("page") page: Int? = null, @Query("limit") limit: Int? = null, @@ -43,6 +46,7 @@ interface UserService { @GET("user/replies") suspend fun getReplies( + @Header("Authorization") authHeader: String? = null, @Query("auth") auth: String? = null, @Query("page") page: Int? = null, @Query("limit") limit: Int? = null, @@ -52,17 +56,29 @@ interface UserService { @POST("user/mark_all_as_read") @Headers("Content-Type: application/json") - suspend fun markAllAsRead(@Body form: MarkAllAsReadForm): Response + suspend fun markAllAsRead( + @Header("Authorization") authHeader: String? = null, + @Body form: MarkAllAsReadForm, + ): Response @POST("user/mention/mark_as_read") @Headers("Content-Type: application/json") - suspend fun markPersonMentionAsRead(@Body form: MarkPersonMentionAsReadForm): Response + suspend fun markPersonMentionAsRead( + @Header("Authorization") authHeader: String? = null, + @Body form: MarkPersonMentionAsReadForm, + ): Response @POST("comment/mark_as_read") @Headers("Content-Type: application/json") - suspend fun markCommentReplyAsRead(@Body form: MarkCommentReplyAsReadForm): Response + suspend fun markCommentReplyAsRead( + @Header("Authorization") authHeader: String? = null, + @Body form: MarkCommentReplyAsReadForm, + ): Response @POST("user/block") @Headers("Content-Type: application/json") - suspend fun blockPerson(@Body form: BlockPersonForm): Response + suspend fun block( + @Header("Authorization") authHeader: String? = null, + @Body form: BlockPersonForm, + ): Response } diff --git a/core-commonui/src/commonMain/kotlin/com/github/diegoberaldin/raccoonforlemmy/core/commonui/communitydetail/CommunityDetailMviModel.kt b/core-commonui/src/commonMain/kotlin/com/github/diegoberaldin/raccoonforlemmy/core/commonui/communitydetail/CommunityDetailMviModel.kt index f8d952580..9476c19da 100644 --- a/core-commonui/src/commonMain/kotlin/com/github/diegoberaldin/raccoonforlemmy/core/commonui/communitydetail/CommunityDetailMviModel.kt +++ b/core-commonui/src/commonMain/kotlin/com/github/diegoberaldin/raccoonforlemmy/core/commonui/communitydetail/CommunityDetailMviModel.kt @@ -24,6 +24,7 @@ interface CommunityDetailMviModel : data class DeletePost(val id: Int) : Intent data class SharePost(val index: Int) : Intent data object Block : Intent + data object BlockInstance : Intent } data class UiState( diff --git a/core-commonui/src/commonMain/kotlin/com/github/diegoberaldin/raccoonforlemmy/core/commonui/communitydetail/CommunityDetailScreen.kt b/core-commonui/src/commonMain/kotlin/com/github/diegoberaldin/raccoonforlemmy/core/commonui/communitydetail/CommunityDetailScreen.kt index bec041ec9..dbc60dff2 100644 --- a/core-commonui/src/commonMain/kotlin/com/github/diegoberaldin/raccoonforlemmy/core/commonui/communitydetail/CommunityDetailScreen.kt +++ b/core-commonui/src/commonMain/kotlin/com/github/diegoberaldin/raccoonforlemmy/core/commonui/communitydetail/CommunityDetailScreen.kt @@ -285,15 +285,15 @@ class CommunityDetailScreen( stringResource(MR.strings.community_detail_info), stringResource(MR.strings.community_detail_instance_info), stringResource(MR.strings.community_detail_block), + stringResource(MR.strings.community_detail_block_instance), ), onOpenImage = { url -> navigator?.push(ZoomableImageScreen(url)) }, onOptionSelected = { optionIdx -> when (optionIdx) { - 2 -> { - model.reduce(CommunityDetailMviModel.Intent.Block) - } + 3 -> model.reduce(CommunityDetailMviModel.Intent.BlockInstance) + 2 -> model.reduce(CommunityDetailMviModel.Intent.Block) 1 -> { navigator?.push( diff --git a/core-commonui/src/commonMain/kotlin/com/github/diegoberaldin/raccoonforlemmy/core/commonui/communitydetail/CommunityDetailViewModel.kt b/core-commonui/src/commonMain/kotlin/com/github/diegoberaldin/raccoonforlemmy/core/commonui/communitydetail/CommunityDetailViewModel.kt index e82c3c01c..e3c03267d 100644 --- a/core-commonui/src/commonMain/kotlin/com/github/diegoberaldin/raccoonforlemmy/core/commonui/communitydetail/CommunityDetailViewModel.kt +++ b/core-commonui/src/commonMain/kotlin/com/github/diegoberaldin/raccoonforlemmy/core/commonui/communitydetail/CommunityDetailViewModel.kt @@ -37,6 +37,7 @@ class CommunityDetailViewModel( CommunityDetailMviModel { private var currentPage: Int = 1 + private var pageCursor: String? = null override fun onStarted() { mvi.onStarted() @@ -107,11 +108,13 @@ class CommunityDetailViewModel( ) CommunityDetailMviModel.Intent.Block -> blockCommunity() + CommunityDetailMviModel.Intent.BlockInstance -> blockInstance() } } private fun refresh() { currentPage = 1 + pageCursor = null mvi.updateState { it.copy(canFetchMore = true, refreshing = true) } val auth = identityRepository.authToken.value mvi.scope?.launch(Dispatchers.IO) { @@ -153,11 +156,12 @@ class CommunityDetailViewModel( val refreshing = currentState.refreshing val sort = currentState.sortType val communityId = currentState.community.id - val itemList = if (otherInstance.isNotEmpty()) { + val (itemList, nextPage) = if (otherInstance.isNotEmpty()) { postRepository.getAll( instance = otherInstance, communityId = communityId, page = currentPage, + pageCursor = pageCursor, sort = sort, ) } else { @@ -165,12 +169,28 @@ class CommunityDetailViewModel( auth = auth, communityId = communityId, page = currentPage, + pageCursor = pageCursor, sort = sort, ) - } + }?.let { + if (refreshing) { + it + } else { + // prevents accidental duplication + val posts = it.first + it.copy( + first = posts.filter { p1 -> + currentState.posts.none { p2 -> p2.id == p1.id } + }, + ) + } + } ?: (null to null) if (!itemList.isNullOrEmpty()) { currentPage++ } + if (nextPage != null) { + pageCursor = nextPage + } mvi.updateState { val newItems = if (refreshing) { itemList.orEmpty() @@ -383,4 +403,20 @@ class CommunityDetailViewModel( } } } + + private fun blockInstance() { + mvi.updateState { it.copy(asyncInProgress = true) } + mvi.scope?.launch(Dispatchers.IO) { + try { + val instanceId = community.instanceId + val auth = identityRepository.authToken.value + siteRepository.block(instanceId, true, auth).getOrThrow() + mvi.emitEffect(CommunityDetailMviModel.Effect.BlockSuccess) + } catch (e: Throwable) { + mvi.emitEffect(CommunityDetailMviModel.Effect.BlockError(e.message)) + } finally { + mvi.updateState { it.copy(asyncInProgress = false) } + } + } + } } diff --git a/core-commonui/src/commonMain/kotlin/com/github/diegoberaldin/raccoonforlemmy/core/commonui/di/CommonUiModule.kt b/core-commonui/src/commonMain/kotlin/com/github/diegoberaldin/raccoonforlemmy/core/commonui/di/CommonUiModule.kt index 12838d50f..c607b11e8 100644 --- a/core-commonui/src/commonMain/kotlin/com/github/diegoberaldin/raccoonforlemmy/core/commonui/di/CommonUiModule.kt +++ b/core-commonui/src/commonMain/kotlin/com/github/diegoberaldin/raccoonforlemmy/core/commonui/di/CommonUiModule.kt @@ -83,6 +83,7 @@ val commonUiModule = module { userRepository = get(), postRepository = get(), commentRepository = get(), + siteRepository = get(), themeRepository = get(), settingsRepository = get(), shareHelper = get(), diff --git a/core-commonui/src/commonMain/kotlin/com/github/diegoberaldin/raccoonforlemmy/core/commonui/instanceinfo/InstanceInfoViewModel.kt b/core-commonui/src/commonMain/kotlin/com/github/diegoberaldin/raccoonforlemmy/core/commonui/instanceinfo/InstanceInfoViewModel.kt index 6b71d4c00..213df2df8 100644 --- a/core-commonui/src/commonMain/kotlin/com/github/diegoberaldin/raccoonforlemmy/core/commonui/instanceinfo/InstanceInfoViewModel.kt +++ b/core-commonui/src/commonMain/kotlin/com/github/diegoberaldin/raccoonforlemmy/core/commonui/instanceinfo/InstanceInfoViewModel.kt @@ -35,6 +35,7 @@ class InstanceInfoViewModel( val metadata = siteRepository.getMetadata(url) if (metadata != null) { + metadata.title mvi.updateState { it.copy( title = metadata.title, diff --git a/core-commonui/src/commonMain/kotlin/com/github/diegoberaldin/raccoonforlemmy/core/commonui/modals/SortBottomSheet.kt b/core-commonui/src/commonMain/kotlin/com/github/diegoberaldin/raccoonforlemmy/core/commonui/modals/SortBottomSheet.kt index ce8fe2f84..76868739e 100644 --- a/core-commonui/src/commonMain/kotlin/com/github/diegoberaldin/raccoonforlemmy/core/commonui/modals/SortBottomSheet.kt +++ b/core-commonui/src/commonMain/kotlin/com/github/diegoberaldin/raccoonforlemmy/core/commonui/modals/SortBottomSheet.kt @@ -46,6 +46,7 @@ class SortBottomSheet( SortType.MostComments, SortType.Old, SortType.Controversial, + SortType.Scaled, SortType.Top.Generic, ), private val expandTop: Boolean = false, @@ -68,7 +69,6 @@ class SortBottomSheet( SortBottomSheetMain( values = values, expandTop = expandTop, - mainKey = key, ) ) } @@ -78,7 +78,6 @@ class SortBottomSheet( internal class SortBottomSheetMain( private val values: List, private val expandTop: Boolean = false, - private val mainKey: String, ) : Screen { @Composable override fun Content() { diff --git a/core-commonui/src/commonMain/kotlin/com/github/diegoberaldin/raccoonforlemmy/core/commonui/userdetail/UserDetailMviModel.kt b/core-commonui/src/commonMain/kotlin/com/github/diegoberaldin/raccoonforlemmy/core/commonui/userdetail/UserDetailMviModel.kt index 5347d9da6..80649d043 100644 --- a/core-commonui/src/commonMain/kotlin/com/github/diegoberaldin/raccoonforlemmy/core/commonui/userdetail/UserDetailMviModel.kt +++ b/core-commonui/src/commonMain/kotlin/com/github/diegoberaldin/raccoonforlemmy/core/commonui/userdetail/UserDetailMviModel.kt @@ -22,11 +22,11 @@ interface UserDetailMviModel : data class SavePost(val index: Int, val feedback: Boolean = false) : Intent data class UpVoteComment(val index: Int, val feedback: Boolean = false) : Intent data class DownVoteComment(val index: Int, val feedback: Boolean = false) : Intent - data class SaveComment(val index: Int, val feedback: Boolean = false) : Intent data object HapticIndication : Intent data class SharePost(val index: Int) : Intent data object Block : Intent + data object BlockInstance : Intent } data class UiState( diff --git a/core-commonui/src/commonMain/kotlin/com/github/diegoberaldin/raccoonforlemmy/core/commonui/userdetail/UserDetailScreen.kt b/core-commonui/src/commonMain/kotlin/com/github/diegoberaldin/raccoonforlemmy/core/commonui/userdetail/UserDetailScreen.kt index 24b83fdd9..2d1d8bfe6 100644 --- a/core-commonui/src/commonMain/kotlin/com/github/diegoberaldin/raccoonforlemmy/core/commonui/userdetail/UserDetailScreen.kt +++ b/core-commonui/src/commonMain/kotlin/com/github/diegoberaldin/raccoonforlemmy/core/commonui/userdetail/UserDetailScreen.kt @@ -263,15 +263,17 @@ class UserDetailScreen( UserHeader( user = uiState.user, autoLoadImages = uiState.autoLoadImages, - options = listOf(stringResource(MR.strings.community_detail_block)), + options = listOf( + stringResource(MR.strings.community_detail_block), + stringResource(MR.strings.community_detail_block_instance), + ), onOpenImage = { url -> navigator?.push(ZoomableImageScreen(url)) }, onOptionSelected = { optionIdx -> when (optionIdx) { - else -> { - model.reduce(UserDetailMviModel.Intent.Block) - } + 1 -> model.reduce(UserDetailMviModel.Intent.BlockInstance) + else -> model.reduce(UserDetailMviModel.Intent.Block) } }, ) diff --git a/core-commonui/src/commonMain/kotlin/com/github/diegoberaldin/raccoonforlemmy/core/commonui/userdetail/UserDetailViewModel.kt b/core-commonui/src/commonMain/kotlin/com/github/diegoberaldin/raccoonforlemmy/core/commonui/userdetail/UserDetailViewModel.kt index 19a81d29c..cd043bc33 100644 --- a/core-commonui/src/commonMain/kotlin/com/github/diegoberaldin/raccoonforlemmy/core/commonui/userdetail/UserDetailViewModel.kt +++ b/core-commonui/src/commonMain/kotlin/com/github/diegoberaldin/raccoonforlemmy/core/commonui/userdetail/UserDetailViewModel.kt @@ -17,6 +17,7 @@ import com.github.diegoberaldin.raccoonforlemmy.domain.lemmy.data.shareUrl 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.PostRepository +import com.github.diegoberaldin.raccoonforlemmy.domain.lemmy.repository.SiteRepository import com.github.diegoberaldin.raccoonforlemmy.domain.lemmy.repository.UserRepository import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.IO @@ -32,6 +33,7 @@ class UserDetailViewModel( private val userRepository: UserRepository, private val postRepository: PostRepository, private val commentRepository: CommentRepository, + private val siteRepository: SiteRepository, private val themeRepository: ThemeRepository, private val shareHelper: ShareHelper, private val hapticFeedback: HapticFeedback, @@ -129,6 +131,7 @@ class UserDetailViewModel( ) UserDetailMviModel.Intent.Block -> blockUser() + UserDetailMviModel.Intent.BlockInstance -> blockInstance() } } @@ -557,4 +560,20 @@ class UserDetailViewModel( } } } + + private fun blockInstance() { + mvi.updateState { it.copy(asyncInProgress = true) } + mvi.scope?.launch(Dispatchers.IO) { + try { + val instanceId = user.instanceId + val auth = identityRepository.authToken.value + siteRepository.block(instanceId, true, auth).getOrThrow() + mvi.emitEffect(UserDetailMviModel.Effect.BlockSuccess) + } catch (e: Throwable) { + mvi.emitEffect(UserDetailMviModel.Effect.BlockError(e.message)) + } finally { + mvi.updateState { it.copy(asyncInProgress = false) } + } + } + } } diff --git a/domain-lemmy/data/src/commonMain/kotlin/com/github/diegoberaldin/raccoonforlemmy/domain/lemmy/data/CommunityModel.kt b/domain-lemmy/data/src/commonMain/kotlin/com/github/diegoberaldin/raccoonforlemmy/domain/lemmy/data/CommunityModel.kt index afe8737f6..8c2751ea6 100644 --- a/domain-lemmy/data/src/commonMain/kotlin/com/github/diegoberaldin/raccoonforlemmy/domain/lemmy/data/CommunityModel.kt +++ b/domain-lemmy/data/src/commonMain/kotlin/com/github/diegoberaldin/raccoonforlemmy/domain/lemmy/data/CommunityModel.kt @@ -4,6 +4,7 @@ import com.github.diegoberaldin.raccoonforlemmy.core.utils.JavaSerializable data class CommunityModel( val id: Int = 0, + val instanceId: Int = 0, val name: String = "", val description: String = "", val title: String = "", diff --git a/domain-lemmy/data/src/commonMain/kotlin/com/github/diegoberaldin/raccoonforlemmy/domain/lemmy/data/SortType.kt b/domain-lemmy/data/src/commonMain/kotlin/com/github/diegoberaldin/raccoonforlemmy/domain/lemmy/data/SortType.kt index 8813da885..5872d620a 100644 --- a/domain-lemmy/data/src/commonMain/kotlin/com/github/diegoberaldin/raccoonforlemmy/domain/lemmy/data/SortType.kt +++ b/domain-lemmy/data/src/commonMain/kotlin/com/github/diegoberaldin/raccoonforlemmy/domain/lemmy/data/SortType.kt @@ -6,6 +6,7 @@ import androidx.compose.material.icons.filled.Forum import androidx.compose.material.icons.filled.LocalFireDepartment import androidx.compose.material.icons.filled.MarkUnreadChatAlt import androidx.compose.material.icons.filled.MilitaryTech +import androidx.compose.material.icons.filled.MonitorWeight import androidx.compose.material.icons.filled.RocketLaunch import androidx.compose.material.icons.filled.Thunderstorm import androidx.compose.material.icons.filled.TrendingUp @@ -33,6 +34,7 @@ sealed interface SortType { } data object Controversial : SortType + data object Scaled : SortType } fun SortType.toInt() = when (this) { @@ -50,6 +52,7 @@ fun SortType.toInt() = when (this) { SortType.Top.Year -> 12 SortType.Old -> 13 SortType.Controversial -> 14 + SortType.Scaled -> 15 else -> 0 } @@ -68,6 +71,7 @@ fun Int.toSortType() = when (this) { 12 -> SortType.Top.Year 13 -> SortType.Old 14 -> SortType.Controversial + 15 -> SortType.Scaled else -> SortType.Active } @@ -79,6 +83,7 @@ fun SortType.toIcon(): ImageVector = when (this) { SortType.NewComments -> Icons.Default.MarkUnreadChatAlt SortType.Old -> Icons.Default.ElderlyWoman SortType.Controversial -> Icons.Default.Thunderstorm + SortType.Scaled -> Icons.Default.MonitorWeight else -> Icons.Default.MilitaryTech } @@ -98,5 +103,6 @@ fun SortType.toReadableName(): String = when (this) { SortType.Top.Year -> stringResource(MR.strings.home_sort_type_top_year) SortType.Old -> stringResource(MR.strings.home_sort_type_old) SortType.Controversial -> stringResource(MR.strings.home_sort_type_controversial) + SortType.Scaled -> stringResource(MR.strings.home_sort_type_scaled) else -> stringResource(MR.strings.home_sort_type_top) } diff --git a/domain-lemmy/data/src/commonMain/kotlin/com/github/diegoberaldin/raccoonforlemmy/domain/lemmy/data/UserModel.kt b/domain-lemmy/data/src/commonMain/kotlin/com/github/diegoberaldin/raccoonforlemmy/domain/lemmy/data/UserModel.kt index 33833a927..556e61614 100644 --- a/domain-lemmy/data/src/commonMain/kotlin/com/github/diegoberaldin/raccoonforlemmy/domain/lemmy/data/UserModel.kt +++ b/domain-lemmy/data/src/commonMain/kotlin/com/github/diegoberaldin/raccoonforlemmy/domain/lemmy/data/UserModel.kt @@ -4,6 +4,7 @@ import com.github.diegoberaldin.raccoonforlemmy.core.utils.JavaSerializable data class UserModel( val id: Int = 0, + val instanceId: Int = 0, val name: String = "", val displayName: String = "", val avatar: String? = null, diff --git a/domain-lemmy/repository/src/commonMain/kotlin/com/github/diegoberaldin/raccoonforlemmy/domain/lemmy/repository/CommentRepository.kt b/domain-lemmy/repository/src/commonMain/kotlin/com/github/diegoberaldin/raccoonforlemmy/domain/lemmy/repository/CommentRepository.kt index 6ce52bc65..c8145b33a 100644 --- a/domain-lemmy/repository/src/commonMain/kotlin/com/github/diegoberaldin/raccoonforlemmy/domain/lemmy/repository/CommentRepository.kt +++ b/domain-lemmy/repository/src/commonMain/kotlin/com/github/diegoberaldin/raccoonforlemmy/domain/lemmy/repository/CommentRepository.kt @@ -10,6 +10,7 @@ import com.github.diegoberaldin.raccoonforlemmy.domain.lemmy.data.CommentModel import com.github.diegoberaldin.raccoonforlemmy.domain.lemmy.data.ListingType import com.github.diegoberaldin.raccoonforlemmy.domain.lemmy.data.PersonMentionModel import com.github.diegoberaldin.raccoonforlemmy.domain.lemmy.data.SortType +import com.github.diegoberaldin.raccoonforlemmy.domain.lemmy.repository.utils.toAuthHeader import com.github.diegoberaldin.raccoonforlemmy.domain.lemmy.repository.utils.toCommentDto import com.github.diegoberaldin.raccoonforlemmy.domain.lemmy.repository.utils.toDto import com.github.diegoberaldin.raccoonforlemmy.domain.lemmy.repository.utils.toModel @@ -35,6 +36,7 @@ class CommentRepository( ): List? = runCatching { val response = if (instance.isNullOrEmpty()) { services.comment.getAll( + authHeader = auth.toAuthHeader(), auth = auth, postId = postId, page = page, @@ -61,10 +63,14 @@ class CommentRepository( suspend fun getBy(id: Int, auth: String?, instance: String? = null): CommentModel? = runCatching { if (instance.isNullOrEmpty()) { - services.comment.getBy(id, auth).body() + services.comment.getBy( + authHeader = auth.toAuthHeader(), + id = id, + auth = auth, + ).body() } else { customServices.changeInstance(instance) - customServices.comment.getBy(id).body() + customServices.comment.getBy(id = id).body() }?.commentView?.toModel() }.getOrNull() @@ -79,6 +85,7 @@ class CommentRepository( ): List? = runCatching { val response = if (instance.isNullOrEmpty()) { services.comment.getAll( + authHeader = auth.toAuthHeader(), auth = auth, parentId = parentId, limit = limit, @@ -142,7 +149,7 @@ class CommentRepository( score = if (voted) 1 else 0, auth = auth, ) - services.comment.like(data) + services.comment.like(authHeader = auth.toAuthHeader(), form = data) } fun asDownVoted(comment: CommentModel, downVoted: Boolean) = comment.copy( @@ -187,7 +194,7 @@ class CommentRepository( score = if (downVoted) -1 else 0, auth = auth, ) - services.comment.like(data) + services.comment.like(authHeader = auth.toAuthHeader(), form = data) } fun asSaved(comment: CommentModel, saved: Boolean) = comment.copy(saved = saved) @@ -198,7 +205,7 @@ class CommentRepository( save = saved, auth = auth, ) - services.comment.save(data) + services.comment.save(authHeader = auth.toAuthHeader(), form = data) } suspend fun create( @@ -213,7 +220,7 @@ class CommentRepository( parentId = parentId, auth = auth, ) - services.comment.create(data) + services.comment.create(authHeader = auth.toAuthHeader(), form = data) } suspend fun edit( @@ -226,7 +233,7 @@ class CommentRepository( commentId = commentId, auth = auth, ) - services.comment.edit(data) + services.comment.edit(authHeader = auth.toAuthHeader(), form = data) } suspend fun delete( @@ -238,6 +245,6 @@ class CommentRepository( deleted = true, auth = auth ) - services.comment.delete(data) + services.comment.delete(authHeader = auth.toAuthHeader(), form = data) } } diff --git a/domain-lemmy/repository/src/commonMain/kotlin/com/github/diegoberaldin/raccoonforlemmy/domain/lemmy/repository/CommunityRepository.kt b/domain-lemmy/repository/src/commonMain/kotlin/com/github/diegoberaldin/raccoonforlemmy/domain/lemmy/repository/CommunityRepository.kt index 7642a8c3a..a147df7dd 100644 --- a/domain-lemmy/repository/src/commonMain/kotlin/com/github/diegoberaldin/raccoonforlemmy/domain/lemmy/repository/CommunityRepository.kt +++ b/domain-lemmy/repository/src/commonMain/kotlin/com/github/diegoberaldin/raccoonforlemmy/domain/lemmy/repository/CommunityRepository.kt @@ -9,6 +9,7 @@ import com.github.diegoberaldin.raccoonforlemmy.domain.lemmy.data.CommunityModel import com.github.diegoberaldin.raccoonforlemmy.domain.lemmy.data.ListingType import com.github.diegoberaldin.raccoonforlemmy.domain.lemmy.data.SearchResultType import com.github.diegoberaldin.raccoonforlemmy.domain.lemmy.data.SortType +import com.github.diegoberaldin.raccoonforlemmy.domain.lemmy.repository.utils.toAuthHeader import com.github.diegoberaldin.raccoonforlemmy.domain.lemmy.repository.utils.toDto import com.github.diegoberaldin.raccoonforlemmy.domain.lemmy.repository.utils.toModel @@ -33,6 +34,7 @@ class CommunityRepository( ): List? = runCatching { if (instance.isNullOrEmpty()) { val response = services.search.search( + authHeader = auth.toAuthHeader(), q = query, auth = auth, page = page, @@ -61,7 +63,10 @@ class CommunityRepository( suspend fun getSubscribed( auth: String? = null, ): List = runCatching { - val response = services.site.get(auth).body() + val response = services.site.get( + authHeader = auth.toAuthHeader(), + auth = auth, + ).body() response?.myUser?.follows?.map { it.community.toModel() }.orEmpty() }.getOrElse { emptyList() } @@ -73,16 +78,14 @@ class CommunityRepository( ): CommunityModel? = runCatching { val response = if (instance.isNullOrEmpty()) { services.community.get( + authHeader = auth.toAuthHeader(), auth = auth, id = id, name = name, ).body() } else { customServices.changeInstance(instance) - customServices.community.get( - auth = auth, - name = name, - ).body() + customServices.community.get(name = name).body() } response?.communityView?.toModel() }.getOrNull() @@ -96,7 +99,10 @@ class CommunityRepository( communityId = id, follow = true, ) - val response = services.community.follow(data) + val response = services.community.follow( + authHeader = auth.toAuthHeader(), + form = data + ) response.body()?.communityView?.toModel() }.getOrNull() @@ -109,7 +115,10 @@ class CommunityRepository( communityId = id, follow = false, ) - val response = services.community.follow(data) + val response = services.community.follow( + authHeader = auth.toAuthHeader(), + form = data + ) response.body()?.communityView?.toModel() }.getOrNull() @@ -119,7 +128,10 @@ class CommunityRepository( block = blocked, auth = auth.orEmpty(), ) - services.community.block(data) + services.community.block( + authHeader = auth.toAuthHeader(), + form = data, + ) } } diff --git a/domain-lemmy/repository/src/commonMain/kotlin/com/github/diegoberaldin/raccoonforlemmy/domain/lemmy/repository/PostRepository.kt b/domain-lemmy/repository/src/commonMain/kotlin/com/github/diegoberaldin/raccoonforlemmy/domain/lemmy/repository/PostRepository.kt index eea8b4c82..0fd4de608 100644 --- a/domain-lemmy/repository/src/commonMain/kotlin/com/github/diegoberaldin/raccoonforlemmy/domain/lemmy/repository/PostRepository.kt +++ b/domain-lemmy/repository/src/commonMain/kotlin/com/github/diegoberaldin/raccoonforlemmy/domain/lemmy/repository/PostRepository.kt @@ -9,6 +9,7 @@ import com.github.diegoberaldin.raccoonforlemmy.core.api.provider.ServiceProvide import com.github.diegoberaldin.raccoonforlemmy.domain.lemmy.data.ListingType import com.github.diegoberaldin.raccoonforlemmy.domain.lemmy.data.PostModel import com.github.diegoberaldin.raccoonforlemmy.domain.lemmy.data.SortType +import com.github.diegoberaldin.raccoonforlemmy.domain.lemmy.repository.utils.toAuthHeader import com.github.diegoberaldin.raccoonforlemmy.domain.lemmy.repository.utils.toDto import com.github.diegoberaldin.raccoonforlemmy.domain.lemmy.repository.utils.toModel import io.ktor.client.request.forms.MultiPartFormDataContent @@ -28,17 +29,20 @@ class PostRepository( suspend fun getAll( auth: String? = null, page: Int, + pageCursor: String? = null, limit: Int = DEFAULT_PAGE_SIZE, type: ListingType = ListingType.Local, sort: SortType = SortType.Active, communityId: Int? = null, instance: String? = null, - ): List? = runCatching { + ): Pair, String?>? = runCatching { val response = if (instance.isNullOrEmpty()) { services.post.getAll( + authHeader = auth.toAuthHeader(), auth = auth, communityId = communityId, page = page, + pageCursor = pageCursor, limit = limit, type = type.toDto(), sort = sort.toDto(), @@ -48,13 +52,15 @@ class PostRepository( customServices.post.getAll( communityId = communityId, page = page, + pageCursor = pageCursor, limit = limit, type = type.toDto(), sort = sort.toDto(), ) } - val dto = response.body()?.posts ?: emptyList() - dto.map { it.toModel() } + val body = response.body() + val posts = body?.posts?.map { it.toModel() } ?: emptyList() + posts to body?.nextPage }.getOrNull() suspend fun get( @@ -63,7 +69,11 @@ class PostRepository( instance: String? = null, ): PostModel? = runCatching { val response = if (instance.isNullOrEmpty()) { - services.post.get(auth, id).body() + services.post.get( + authHeader = auth.toAuthHeader(), + auth = auth, + id = id, + ).body() } else { customServices.changeInstance(instance) customServices.post.get(id = id).body() @@ -98,7 +108,10 @@ class PostRepository( score = if (voted) 1 else 0, auth = auth, ) - services.post.like(data) + services.post.like( + authHeader = auth.toAuthHeader(), + form = data, + ) } fun asDownVoted(post: PostModel, downVoted: Boolean) = post.copy( @@ -125,7 +138,10 @@ class PostRepository( score = if (downVoted) -1 else 0, auth = auth, ) - services.post.like(data) + services.post.like( + authHeader = auth.toAuthHeader(), + form = data, + ) } fun asSaved(post: PostModel, saved: Boolean): PostModel = post.copy(saved = saved) @@ -136,7 +152,10 @@ class PostRepository( save = saved, auth = auth, ) - services.post.save(data) + services.post.save( + authHeader = auth.toAuthHeader(), + form = data, + ) } suspend fun create( @@ -155,7 +174,10 @@ class PostRepository( nsfw = nsfw, auth = auth, ) - services.post.create(data) + services.post.create( + authHeader = auth.toAuthHeader(), + form = data, + ) } suspend fun edit( @@ -174,7 +196,10 @@ class PostRepository( nsfw = nsfw, auth = auth, ) - services.post.edit(data) + services.post.edit( + authHeader = auth.toAuthHeader(), + form = data, + ) } suspend fun delete(id: Int, auth: String) { @@ -183,7 +208,10 @@ class PostRepository( deleted = true, auth = auth ) - services.post.delete(data) + services.post.delete( + authHeader = auth.toAuthHeader(), + form = data, + ) } suspend fun uploadImage(auth: String, bytes: ByteArray): String? = try { @@ -194,7 +222,12 @@ class PostRepository( append(HttpHeaders.ContentDisposition, "filename=image.jpeg") }) }) - val images = services.post.uploadImage(url, "jwt=$auth", multipart).body() + val images = services.post.uploadImage( + url = url, + token = "jwt=$auth", + authHeader = auth.toAuthHeader(), + content = multipart, + ).body() "$url/${images?.files?.firstOrNull()?.file}" } catch (e: Exception) { e.printStackTrace() diff --git a/domain-lemmy/repository/src/commonMain/kotlin/com/github/diegoberaldin/raccoonforlemmy/domain/lemmy/repository/PrivateMessageRepository.kt b/domain-lemmy/repository/src/commonMain/kotlin/com/github/diegoberaldin/raccoonforlemmy/domain/lemmy/repository/PrivateMessageRepository.kt index b9d302444..bf29dcd3d 100644 --- a/domain-lemmy/repository/src/commonMain/kotlin/com/github/diegoberaldin/raccoonforlemmy/domain/lemmy/repository/PrivateMessageRepository.kt +++ b/domain-lemmy/repository/src/commonMain/kotlin/com/github/diegoberaldin/raccoonforlemmy/domain/lemmy/repository/PrivateMessageRepository.kt @@ -4,6 +4,7 @@ import com.github.diegoberaldin.raccoonforlemmy.core.api.dto.CreatePrivateMessag import com.github.diegoberaldin.raccoonforlemmy.core.api.dto.MarkPrivateMessageAsReadForm import com.github.diegoberaldin.raccoonforlemmy.core.api.provider.ServiceProvider import com.github.diegoberaldin.raccoonforlemmy.domain.lemmy.data.PrivateMessageModel +import com.github.diegoberaldin.raccoonforlemmy.domain.lemmy.repository.utils.toAuthHeader import com.github.diegoberaldin.raccoonforlemmy.domain.lemmy.repository.utils.toModel class PrivateMessageRepository( @@ -16,6 +17,7 @@ class PrivateMessageRepository( unreadOnly: Boolean = true, ): List? = runCatching { val response = serviceProvider.privateMessages.getPrivateMessages( + authHeader = auth.toAuthHeader(), auth = auth, limit = limit, page = page, @@ -35,7 +37,10 @@ class PrivateMessageRepository( auth = auth.orEmpty(), recipientId = recipiendId, ) - serviceProvider.privateMessages.createPrivateMessage(data) + serviceProvider.privateMessages.createPrivateMessage( + authHeader = auth.toAuthHeader(), + form = data, + ) } suspend fun markAsRead( @@ -48,6 +53,9 @@ class PrivateMessageRepository( auth = auth.orEmpty(), read = read, ) - serviceProvider.privateMessages.markPrivateMessageAsRead(data) + serviceProvider.privateMessages.markPrivateMessageAsRead( + authHeader = auth.toAuthHeader(), + form = data, + ) } } \ No newline at end of file diff --git a/domain-lemmy/repository/src/commonMain/kotlin/com/github/diegoberaldin/raccoonforlemmy/domain/lemmy/repository/SiteRepository.kt b/domain-lemmy/repository/src/commonMain/kotlin/com/github/diegoberaldin/raccoonforlemmy/domain/lemmy/repository/SiteRepository.kt index 03472fef7..d5e8cd7df 100644 --- a/domain-lemmy/repository/src/commonMain/kotlin/com/github/diegoberaldin/raccoonforlemmy/domain/lemmy/repository/SiteRepository.kt +++ b/domain-lemmy/repository/src/commonMain/kotlin/com/github/diegoberaldin/raccoonforlemmy/domain/lemmy/repository/SiteRepository.kt @@ -1,16 +1,21 @@ package com.github.diegoberaldin.raccoonforlemmy.domain.lemmy.repository +import com.github.diegoberaldin.raccoonforlemmy.core.api.dto.BlockSiteForm import com.github.diegoberaldin.raccoonforlemmy.core.api.dto.SiteMetadata import com.github.diegoberaldin.raccoonforlemmy.core.api.provider.ServiceProvider import com.github.diegoberaldin.raccoonforlemmy.domain.lemmy.data.MetadataModel import com.github.diegoberaldin.raccoonforlemmy.domain.lemmy.data.UserModel +import com.github.diegoberaldin.raccoonforlemmy.domain.lemmy.repository.utils.toAuthHeader import com.github.diegoberaldin.raccoonforlemmy.domain.lemmy.repository.utils.toModel class SiteRepository( private val serviceProvider: ServiceProvider, ) { suspend fun getCurrentUser(auth: String): UserModel? = runCatching { - val response = serviceProvider.site.get(auth = auth) + val response = serviceProvider.site.get( + auth = auth, + authHeader = auth.toAuthHeader(), + ) response.body()?.myUser?.let { val user = it.localUserView.person val counts = it.localUserView.counts @@ -18,8 +23,21 @@ class SiteRepository( } }.getOrNull() + suspend fun block(id: Int, blocked: Boolean, auth: String? = null): Result = runCatching { + val data = BlockSiteForm( + instanceId = id, + block = blocked, + ) + serviceProvider.site.block( + authHeader = auth.toAuthHeader(), + form = data, + ) + } + suspend fun getMetadata(url: String): MetadataModel? = runCatching { - val response = serviceProvider.site.getSiteMetadata(url = url) + val response = serviceProvider.site.getSiteMetadata( + url = url, + ) response.body()?.metadata?.toModel() }.getOrNull() } diff --git a/domain-lemmy/repository/src/commonMain/kotlin/com/github/diegoberaldin/raccoonforlemmy/domain/lemmy/repository/UserRepository.kt b/domain-lemmy/repository/src/commonMain/kotlin/com/github/diegoberaldin/raccoonforlemmy/domain/lemmy/repository/UserRepository.kt index ffcdb8cc7..3dfe835d3 100644 --- a/domain-lemmy/repository/src/commonMain/kotlin/com/github/diegoberaldin/raccoonforlemmy/domain/lemmy/repository/UserRepository.kt +++ b/domain-lemmy/repository/src/commonMain/kotlin/com/github/diegoberaldin/raccoonforlemmy/domain/lemmy/repository/UserRepository.kt @@ -10,6 +10,7 @@ import com.github.diegoberaldin.raccoonforlemmy.domain.lemmy.data.PersonMentionM import com.github.diegoberaldin.raccoonforlemmy.domain.lemmy.data.PostModel import com.github.diegoberaldin.raccoonforlemmy.domain.lemmy.data.SortType import com.github.diegoberaldin.raccoonforlemmy.domain.lemmy.data.UserModel +import com.github.diegoberaldin.raccoonforlemmy.domain.lemmy.repository.utils.toAuthHeader import com.github.diegoberaldin.raccoonforlemmy.domain.lemmy.repository.utils.toCommentDto import com.github.diegoberaldin.raccoonforlemmy.domain.lemmy.repository.utils.toHost import com.github.diegoberaldin.raccoonforlemmy.domain.lemmy.repository.utils.toModel @@ -25,6 +26,7 @@ class UserRepository( username: String? = null, ): UserModel? = runCatching { val response = serviceProvider.user.getDetails( + authHeader = auth.toAuthHeader(), auth = auth, personId = id, username = username, @@ -48,6 +50,7 @@ class UserRepository( ): UserModel? = runCatching { customServiceProvider.changeInstance(instance) val response = customServiceProvider.user.getDetails( + authHeader = auth.toAuthHeader(), auth = auth, username = username, ) @@ -71,6 +74,7 @@ class UserRepository( sort: SortType = SortType.Active, ): List? = runCatching { val response = serviceProvider.user.getDetails( + authHeader = auth.toAuthHeader(), auth = auth, personId = id, page = page, @@ -89,6 +93,7 @@ class UserRepository( sort: SortType = SortType.Active, ): List? = runCatching { val response = serviceProvider.user.getDetails( + authHeader = auth.toAuthHeader(), auth = auth, personId = id, page = page, @@ -108,6 +113,7 @@ class UserRepository( sort: SortType = SortType.Active, ): List? = runCatching { val response = serviceProvider.user.getDetails( + authHeader = auth.toAuthHeader(), auth = auth, personId = id, page = page, @@ -126,6 +132,7 @@ class UserRepository( sort: SortType = SortType.Active, ): List? = runCatching { val response = serviceProvider.user.getDetails( + authHeader = auth.toAuthHeader(), auth = auth, personId = id, page = page, @@ -145,6 +152,7 @@ class UserRepository( unreadOnly: Boolean = true, ): List? = runCatching { val response = serviceProvider.user.getMentions( + authHeader = auth.toAuthHeader(), auth = auth, limit = limit, sort = sort.toCommentDto(), @@ -163,6 +171,7 @@ class UserRepository( unreadOnly: Boolean = true, ): List? = runCatching { val response = serviceProvider.user.getReplies( + authHeader = auth.toAuthHeader(), auth = auth, limit = limit, sort = sort.toCommentDto(), @@ -177,7 +186,10 @@ class UserRepository( auth: String? = null, ) { val data = MarkAllAsReadForm(auth.orEmpty()) - serviceProvider.user.markAllAsRead(data) + serviceProvider.user.markAllAsRead( + authHeader = auth.toAuthHeader(), + form = data, + ) } suspend fun setMentionRead(read: Boolean, mentionId: Int, auth: String? = null) = runCatching { @@ -186,7 +198,10 @@ class UserRepository( read = read, auth = auth.orEmpty(), ) - serviceProvider.user.markPersonMentionAsRead(data) + serviceProvider.user.markPersonMentionAsRead( + authHeader = auth.toAuthHeader(), + form = data, + ) } suspend fun setReplyRead(read: Boolean, replyId: Int, auth: String? = null) = runCatching { @@ -195,7 +210,10 @@ class UserRepository( read = read, auth = auth.orEmpty(), ) - serviceProvider.user.markCommentReplyAsRead(data) + serviceProvider.user.markCommentReplyAsRead( + authHeader = auth.toAuthHeader(), + form = data, + ) } suspend fun block(id: Int, blocked: Boolean, auth: String? = null): Result = runCatching { @@ -204,6 +222,9 @@ class UserRepository( block = blocked, auth = auth.orEmpty(), ) - serviceProvider.user.blockPerson(data) + serviceProvider.user.block( + authHeader = auth.toAuthHeader(), + form = data, + ) } } diff --git a/domain-lemmy/repository/src/commonMain/kotlin/com/github/diegoberaldin/raccoonforlemmy/domain/lemmy/repository/utils/Mappings.kt b/domain-lemmy/repository/src/commonMain/kotlin/com/github/diegoberaldin/raccoonforlemmy/domain/lemmy/repository/utils/Mappings.kt index 0563bc477..0455bf6ec 100644 --- a/domain-lemmy/repository/src/commonMain/kotlin/com/github/diegoberaldin/raccoonforlemmy/domain/lemmy/repository/utils/Mappings.kt +++ b/domain-lemmy/repository/src/commonMain/kotlin/com/github/diegoberaldin/raccoonforlemmy/domain/lemmy/repository/utils/Mappings.kt @@ -80,6 +80,7 @@ internal fun SearchResultType.toDto(): SearchType = when (this) { internal fun Person.toModel() = UserModel( id = id, + instanceId = instanceId, name = name, displayName = displayName.orEmpty(), avatar = avatar, @@ -131,6 +132,7 @@ internal fun CommentView.toModel() = CommentModel( internal fun Community.toModel() = CommunityModel( id = id, + instanceId = instanceId, name = name, title = title, description = description.orEmpty(), @@ -222,6 +224,8 @@ internal fun PrivateMessageView.toModel() = PrivateMessageModel( read = privateMessage.read, ) +internal fun String?.toAuthHeader() = this?.let { "Bearer $it" } + internal fun String.toHost(): String = this.replace("https://", "").let { val index = it.indexOf("/") if (index < 0) { diff --git a/feature-home/src/commonMain/kotlin/com/github/diegoberaldin/raccoonforlemmy/feature/home/postlist/PostListViewModel.kt b/feature-home/src/commonMain/kotlin/com/github/diegoberaldin/raccoonforlemmy/feature/home/postlist/PostListViewModel.kt index 79afff4ff..5321d86bf 100644 --- a/feature-home/src/commonMain/kotlin/com/github/diegoberaldin/raccoonforlemmy/feature/home/postlist/PostListViewModel.kt +++ b/feature-home/src/commonMain/kotlin/com/github/diegoberaldin/raccoonforlemmy/feature/home/postlist/PostListViewModel.kt @@ -40,6 +40,7 @@ class PostListViewModel( MviModel by mvi { private var currentPage: Int = 1 + private var pageCursor: String? = null private var firstLoad = true init { @@ -150,6 +151,7 @@ class PostListViewModel( private fun refresh() { currentPage = 1 + pageCursor = null mvi.updateState { it.copy(canFetchMore = true, refreshing = true) } loadNextPage() } @@ -168,9 +170,10 @@ class PostListViewModel( val sort = currentState.sortType ?: SortType.Active val refreshing = currentState.refreshing val includeNsfw = settingsRepository.currentSettings.value.includeNsfw - val itemList = postRepository.getAll( + val (itemList, nextPage) = postRepository.getAll( auth = auth, page = currentPage, + pageCursor = pageCursor, type = type, sort = sort, )?.let { @@ -178,14 +181,20 @@ class PostListViewModel( it } else { // prevents accidental duplication - it.filter { p1 -> - currentState.posts.none { p2 -> p2.id == p1.id } - } + val posts = it.first + it.copy( + first = posts.filter { p1 -> + currentState.posts.none { p2 -> p2.id == p1.id } + }, + ) } - } + } ?: (null to null) if (!itemList.isNullOrEmpty()) { currentPage++ } + if (nextPage != null) { + pageCursor = nextPage + } mvi.updateState { val newPosts = if (refreshing) { itemList.orEmpty() @@ -375,6 +384,7 @@ class PostListViewModel( private fun handleLogout() { currentPage = 1 + pageCursor = null mvi.updateState { it.copy( posts = emptyList(), diff --git a/feature-search/src/commonMain/kotlin/com/github/diegoberaldin/raccoonforlemmy/feature/search/multicommunity/utils/CommunityPaginator.kt b/feature-search/src/commonMain/kotlin/com/github/diegoberaldin/raccoonforlemmy/feature/search/multicommunity/utils/CommunityPaginator.kt index 6b73f5051..3b14e52bc 100644 --- a/feature-search/src/commonMain/kotlin/com/github/diegoberaldin/raccoonforlemmy/feature/search/multicommunity/utils/CommunityPaginator.kt +++ b/feature-search/src/commonMain/kotlin/com/github/diegoberaldin/raccoonforlemmy/feature/search/multicommunity/utils/CommunityPaginator.kt @@ -10,11 +10,13 @@ internal class CommunityPaginator( private val postRepository: PostRepository, ) { private var currentPage: Int = 1 + private var pageCursor: String? = null var canFetchMore: Boolean = true private set fun reset() { currentPage = 1 + pageCursor = null canFetchMore = true } @@ -23,20 +25,29 @@ internal class CommunityPaginator( sort: SortType, currentIds: List, ): List { - val result = postRepository.getAll( + val (result, nextPage) = postRepository.getAll( auth = auth, page = currentPage, + pageCursor = pageCursor, limit = PostRepository.DEFAULT_PAGE_SIZE, type = ListingType.All, sort = sort, communityId = communityId, - )?.filter { + )?.let { // prevents accidental duplication - it.id !in currentIds - } + val posts = it.first + it.copy( + first = posts.filter { p1 -> + p1.id !in currentIds + }, + ) + } ?: (null to null) if (!result.isNullOrEmpty()) { currentPage++ } + if (nextPage != null) { + pageCursor = nextPage + } canFetchMore = result?.isEmpty() != true return result.orEmpty() } diff --git a/resources/src/commonMain/resources/MR/base/strings.xml b/resources/src/commonMain/resources/MR/base/strings.xml index 7fcb1e710..d824f930d 100644 --- a/resources/src/commonMain/resources/MR/base/strings.xml +++ b/resources/src/commonMain/resources/MR/base/strings.xml @@ -55,6 +55,7 @@ year Old Controversial + Scaled via %1$s h m @@ -152,6 +153,7 @@ Community info Instance details Block + Block instance Instance: %1$s Communities Back to top diff --git a/resources/src/commonMain/resources/MR/es/strings.xml b/resources/src/commonMain/resources/MR/es/strings.xml index bba06e91c..25c678d93 100644 --- a/resources/src/commonMain/resources/MR/es/strings.xml +++ b/resources/src/commonMain/resources/MR/es/strings.xml @@ -50,6 +50,7 @@ semana año Contravertidos + Proporcional Antiguos a través de %1$s h @@ -150,6 +151,7 @@ Info comunidad Detalles instancia Bloquear + Bloquear instancia Instancia: %1$s Comunidades Volver arriba diff --git a/resources/src/commonMain/resources/MR/it/strings.xml b/resources/src/commonMain/resources/MR/it/strings.xml index e1617bdce..54e1ee07f 100644 --- a/resources/src/commonMain/resources/MR/it/strings.xml +++ b/resources/src/commonMain/resources/MR/it/strings.xml @@ -51,6 +51,7 @@ anno Vecchi Controversi + Proporzionale via %1$s h m @@ -84,6 +85,7 @@ Nome istanza Nome utente (o email) Blocca + Blocca istanza Password TOTP 2FA token (opzionale)