From 4b80c78e3067126faf1c2e67edecb8d20b6d26e9 Mon Sep 17 00:00:00 2001 From: Diego Beraldin Date: Wed, 26 Jul 2023 22:43:30 +0200 Subject: [PATCH] feat(posts): improve post view --- .../raccoonforlemmy/core_api/ApiModule.kt | 4 + .../core_api/dto/BlockCommunityForm.kt | 11 ++ .../core_api/dto/BlockCommunityResponse.kt | 10 ++ .../raccoonforlemmy/core_api/dto/Comment.kt | 21 +++ .../core_api/dto/CommentAggregates.kt | 16 +++ .../core_api/dto/CommentView.kt | 18 +++ .../core_api/dto/CommunityResponse.kt | 10 ++ .../raccoonforlemmy/core_api/dto/Constants.kt | 1 + .../core_api/dto/CreatePostForm.kt | 16 +++ .../core_api/dto/DeletePostForm.kt | 11 ++ .../core_api/dto/EditPostForm.kt | 15 ++ .../core_api/dto/FollowCommunityForm.kt | 11 ++ .../core_api/dto/GetCommunityResponse.kt | 13 ++ .../core_api/dto/GetPersonDetailsResponse.kt | 12 ++ .../core_api/dto/PersonAggregates.kt | 14 ++ .../core_api/dto/PersonView.kt | 10 ++ .../core_api/dto/PostResponse.kt | 10 ++ .../core_api/dto/SavePostForm.kt | 11 ++ .../raccoonforlemmy/core_api/dto/Site.kt | 22 +++ .../provider/DefaultServiceProvider.kt | 7 +- .../core_api/provider/ServiceProvider.kt | 2 + .../core_api/service/CommunityService.kt | 29 ++++ .../core_api/service/PostService.kt | 21 +++ .../core_api/service/UserService.kt | 22 +++ .../raccoonforlemmy/data/CommunityModel.kt | 8 ++ .../raccoonforlemmy/data/PostModel.kt | 5 + .../raccoonforlemmy/data/UserModel.kt | 5 + .../repository/CommunityRepository.kt | 20 +++ .../domain_post/repository/PostsRepository.kt | 10 +- .../repository/PostsRepositoryModule.kt | 3 +- feature-home/build.gradle.kts | 1 + .../feature_home/HomeModule.kt | 1 + .../feature_home/HomeScreenModel.kt | 24 +++- .../raccoonforlemmy/feature_home/HomeTab.kt | 116 +++------------- .../raccoonforlemmy/feature_home/PostCard.kt | 128 ++++++++++++++++++ .../feature_home/PostsTopBar.kt | 76 +++++++++++ feature-search/build.gradle.kts | 1 + .../feature_search/SearchTab.kt | 4 +- 38 files changed, 617 insertions(+), 102 deletions(-) create mode 100644 core-api/src/commonMain/kotlin/com/github/diegoberaldin/raccoonforlemmy/core_api/dto/BlockCommunityForm.kt create mode 100644 core-api/src/commonMain/kotlin/com/github/diegoberaldin/raccoonforlemmy/core_api/dto/BlockCommunityResponse.kt create mode 100644 core-api/src/commonMain/kotlin/com/github/diegoberaldin/raccoonforlemmy/core_api/dto/Comment.kt create mode 100644 core-api/src/commonMain/kotlin/com/github/diegoberaldin/raccoonforlemmy/core_api/dto/CommentAggregates.kt create mode 100644 core-api/src/commonMain/kotlin/com/github/diegoberaldin/raccoonforlemmy/core_api/dto/CommentView.kt create mode 100644 core-api/src/commonMain/kotlin/com/github/diegoberaldin/raccoonforlemmy/core_api/dto/CommunityResponse.kt create mode 100644 core-api/src/commonMain/kotlin/com/github/diegoberaldin/raccoonforlemmy/core_api/dto/CreatePostForm.kt create mode 100644 core-api/src/commonMain/kotlin/com/github/diegoberaldin/raccoonforlemmy/core_api/dto/DeletePostForm.kt create mode 100644 core-api/src/commonMain/kotlin/com/github/diegoberaldin/raccoonforlemmy/core_api/dto/EditPostForm.kt create mode 100644 core-api/src/commonMain/kotlin/com/github/diegoberaldin/raccoonforlemmy/core_api/dto/FollowCommunityForm.kt create mode 100644 core-api/src/commonMain/kotlin/com/github/diegoberaldin/raccoonforlemmy/core_api/dto/GetCommunityResponse.kt create mode 100644 core-api/src/commonMain/kotlin/com/github/diegoberaldin/raccoonforlemmy/core_api/dto/GetPersonDetailsResponse.kt create mode 100644 core-api/src/commonMain/kotlin/com/github/diegoberaldin/raccoonforlemmy/core_api/dto/PersonAggregates.kt create mode 100644 core-api/src/commonMain/kotlin/com/github/diegoberaldin/raccoonforlemmy/core_api/dto/PersonView.kt create mode 100644 core-api/src/commonMain/kotlin/com/github/diegoberaldin/raccoonforlemmy/core_api/dto/PostResponse.kt create mode 100644 core-api/src/commonMain/kotlin/com/github/diegoberaldin/raccoonforlemmy/core_api/dto/SavePostForm.kt create mode 100644 core-api/src/commonMain/kotlin/com/github/diegoberaldin/raccoonforlemmy/core_api/dto/Site.kt create mode 100644 core-api/src/commonMain/kotlin/com/github/diegoberaldin/raccoonforlemmy/core_api/service/CommunityService.kt create mode 100644 core-api/src/commonMain/kotlin/com/github/diegoberaldin/raccoonforlemmy/core_api/service/UserService.kt create mode 100644 domain-post/data/src/commonMain/kotlin/com/github/diegoberaldin/raccoonforlemmy/data/CommunityModel.kt create mode 100644 domain-post/data/src/commonMain/kotlin/com/github/diegoberaldin/raccoonforlemmy/data/UserModel.kt create mode 100644 domain-post/repository/src/commonMain/kotlin/com/github/diegoberaldin/raccoonforlemmy/domain_post/repository/CommunityRepository.kt create mode 100644 feature-home/src/commonMain/kotlin/com/github/diegoberaldin/raccoonforlemmy/feature_home/PostCard.kt create mode 100644 feature-home/src/commonMain/kotlin/com/github/diegoberaldin/raccoonforlemmy/feature_home/PostsTopBar.kt diff --git a/core-api/src/commonMain/kotlin/com/github/diegoberaldin/raccoonforlemmy/core_api/ApiModule.kt b/core-api/src/commonMain/kotlin/com/github/diegoberaldin/raccoonforlemmy/core_api/ApiModule.kt index df7ba9b40..5c8249e96 100644 --- a/core-api/src/commonMain/kotlin/com/github/diegoberaldin/raccoonforlemmy/core_api/ApiModule.kt +++ b/core-api/src/commonMain/kotlin/com/github/diegoberaldin/raccoonforlemmy/core_api/ApiModule.kt @@ -12,4 +12,8 @@ val coreApiModule = module { val provider: ServiceProvider = get() provider.postService } + single { + val provider: ServiceProvider = get() + provider.communityService + } } \ No newline at end of file diff --git a/core-api/src/commonMain/kotlin/com/github/diegoberaldin/raccoonforlemmy/core_api/dto/BlockCommunityForm.kt b/core-api/src/commonMain/kotlin/com/github/diegoberaldin/raccoonforlemmy/core_api/dto/BlockCommunityForm.kt new file mode 100644 index 000000000..ca4d0c9b9 --- /dev/null +++ b/core-api/src/commonMain/kotlin/com/github/diegoberaldin/raccoonforlemmy/core_api/dto/BlockCommunityForm.kt @@ -0,0 +1,11 @@ +package com.github.diegoberaldin.raccoonforlemmy.core_api.dto + +import kotlinx.serialization.SerialName +import kotlinx.serialization.Serializable + +@Serializable +data class BlockCommunityForm( + @SerialName("community_id") val communityId: CommunityId, + @SerialName("block") val block: Boolean, + @SerialName("auth") val auth: String, +) diff --git a/core-api/src/commonMain/kotlin/com/github/diegoberaldin/raccoonforlemmy/core_api/dto/BlockCommunityResponse.kt b/core-api/src/commonMain/kotlin/com/github/diegoberaldin/raccoonforlemmy/core_api/dto/BlockCommunityResponse.kt new file mode 100644 index 000000000..e01aaa2bb --- /dev/null +++ b/core-api/src/commonMain/kotlin/com/github/diegoberaldin/raccoonforlemmy/core_api/dto/BlockCommunityResponse.kt @@ -0,0 +1,10 @@ +package com.github.diegoberaldin.raccoonforlemmy.core_api.dto + +import kotlinx.serialization.SerialName +import kotlinx.serialization.Serializable + +@Serializable +data class BlockCommunityResponse( + @SerialName("community_view") val communityView: CommunityView, + @SerialName("blocked") val blocked: Boolean, +) \ No newline at end of file diff --git a/core-api/src/commonMain/kotlin/com/github/diegoberaldin/raccoonforlemmy/core_api/dto/Comment.kt b/core-api/src/commonMain/kotlin/com/github/diegoberaldin/raccoonforlemmy/core_api/dto/Comment.kt new file mode 100644 index 000000000..54ba47baf --- /dev/null +++ b/core-api/src/commonMain/kotlin/com/github/diegoberaldin/raccoonforlemmy/core_api/dto/Comment.kt @@ -0,0 +1,21 @@ +package com.github.diegoberaldin.raccoonforlemmy.core_api.dto + +import kotlinx.serialization.SerialName +import kotlinx.serialization.Serializable + +@Serializable +data class Comment( + @SerialName("id") val id: CommentId, + @SerialName("creator_id") val creatorId: PersonId, + @SerialName("post_id") val postId: PostId, + @SerialName("content") val content: String, + @SerialName("removed") val removed: Boolean, + @SerialName("published") val published: String, + @SerialName("updated") val updated: String? = null, + @SerialName("deleted") val deleted: Boolean, + @SerialName("ap_id") val apId: String, + @SerialName("local") val local: Boolean, + @SerialName("path") val path: String, + @SerialName("distinguished") val distinguished: Boolean, + @SerialName("language_id") val languageId: LanguageId, +) \ No newline at end of file diff --git a/core-api/src/commonMain/kotlin/com/github/diegoberaldin/raccoonforlemmy/core_api/dto/CommentAggregates.kt b/core-api/src/commonMain/kotlin/com/github/diegoberaldin/raccoonforlemmy/core_api/dto/CommentAggregates.kt new file mode 100644 index 000000000..015979230 --- /dev/null +++ b/core-api/src/commonMain/kotlin/com/github/diegoberaldin/raccoonforlemmy/core_api/dto/CommentAggregates.kt @@ -0,0 +1,16 @@ +package com.github.diegoberaldin.raccoonforlemmy.core_api.dto + +import kotlinx.serialization.SerialName +import kotlinx.serialization.Serializable + +@Serializable +data class CommentAggregates( + @SerialName("id") val id: Int, + @SerialName("comment_id") val commentId: CommentId, + @SerialName("score") val score: Int, + @SerialName("upvotes") val upvotes: Int, + @SerialName("downvotes") val downvotes: Int, + @SerialName("published") val published: String, + @SerialName("child_count") val childCount: Int, + @SerialName("hot_rank") val hotRank: Int, +) \ No newline at end of file diff --git a/core-api/src/commonMain/kotlin/com/github/diegoberaldin/raccoonforlemmy/core_api/dto/CommentView.kt b/core-api/src/commonMain/kotlin/com/github/diegoberaldin/raccoonforlemmy/core_api/dto/CommentView.kt new file mode 100644 index 000000000..e48eecaf2 --- /dev/null +++ b/core-api/src/commonMain/kotlin/com/github/diegoberaldin/raccoonforlemmy/core_api/dto/CommentView.kt @@ -0,0 +1,18 @@ +package com.github.diegoberaldin.raccoonforlemmy.core_api.dto + +import kotlinx.serialization.SerialName +import kotlinx.serialization.Serializable + +@Serializable +data class CommentView( + @SerialName("comment") val comment: Comment, + @SerialName("creator") val creator: Person, + @SerialName("post") val post: Post, + @SerialName("community") val community: Community, + @SerialName("counts") val counts: CommentAggregates, + @SerialName("creator_banned_from_community") val creatorBannedFromCommunity: Boolean, + @SerialName("subscribed") val subscribed: SubscribedType, + @SerialName("saved") val saved: Boolean, + @SerialName("creator_blocked") val creatorBlocked: Boolean, + @SerialName("my_vote") val myVote: Int? = null, +) \ No newline at end of file diff --git a/core-api/src/commonMain/kotlin/com/github/diegoberaldin/raccoonforlemmy/core_api/dto/CommunityResponse.kt b/core-api/src/commonMain/kotlin/com/github/diegoberaldin/raccoonforlemmy/core_api/dto/CommunityResponse.kt new file mode 100644 index 000000000..a5f9d2085 --- /dev/null +++ b/core-api/src/commonMain/kotlin/com/github/diegoberaldin/raccoonforlemmy/core_api/dto/CommunityResponse.kt @@ -0,0 +1,10 @@ +package com.github.diegoberaldin.raccoonforlemmy.core_api.dto + +import kotlinx.serialization.SerialName +import kotlinx.serialization.Serializable + +@Serializable +data class CommunityResponse( + @SerialName("community_view") val communityView: CommunityView, + @SerialName("discussion_languages") val discussionLanguages: List, +) diff --git a/core-api/src/commonMain/kotlin/com/github/diegoberaldin/raccoonforlemmy/core_api/dto/Constants.kt b/core-api/src/commonMain/kotlin/com/github/diegoberaldin/raccoonforlemmy/core_api/dto/Constants.kt index ce2066d81..c2a66ced8 100644 --- a/core-api/src/commonMain/kotlin/com/github/diegoberaldin/raccoonforlemmy/core_api/dto/Constants.kt +++ b/core-api/src/commonMain/kotlin/com/github/diegoberaldin/raccoonforlemmy/core_api/dto/Constants.kt @@ -6,3 +6,4 @@ typealias CommunityId = Int typealias LanguageId = Int typealias InstanceId = Int typealias CommentId = Int +typealias SiteId = Int diff --git a/core-api/src/commonMain/kotlin/com/github/diegoberaldin/raccoonforlemmy/core_api/dto/CreatePostForm.kt b/core-api/src/commonMain/kotlin/com/github/diegoberaldin/raccoonforlemmy/core_api/dto/CreatePostForm.kt new file mode 100644 index 000000000..e3cddbaa0 --- /dev/null +++ b/core-api/src/commonMain/kotlin/com/github/diegoberaldin/raccoonforlemmy/core_api/dto/CreatePostForm.kt @@ -0,0 +1,16 @@ +package com.github.diegoberaldin.raccoonforlemmy.core_api.dto + +import kotlinx.serialization.SerialName +import kotlinx.serialization.Serializable + +@Serializable +data class CreatePostForm( + @SerialName("name") val name: String, + @SerialName("community_id") val communityId: CommunityId, + @SerialName("url") val url: String? = null, + @SerialName("body") val body: String? = null, + @SerialName("honeypot") val honeypot: String? = null, + @SerialName("nsfw") val nsfw: Boolean? = null, + @SerialName("language_id") val languageId: LanguageId? = null, + @SerialName("auth") val auth: String, +) \ No newline at end of file diff --git a/core-api/src/commonMain/kotlin/com/github/diegoberaldin/raccoonforlemmy/core_api/dto/DeletePostForm.kt b/core-api/src/commonMain/kotlin/com/github/diegoberaldin/raccoonforlemmy/core_api/dto/DeletePostForm.kt new file mode 100644 index 000000000..b1ff544a0 --- /dev/null +++ b/core-api/src/commonMain/kotlin/com/github/diegoberaldin/raccoonforlemmy/core_api/dto/DeletePostForm.kt @@ -0,0 +1,11 @@ +package com.github.diegoberaldin.raccoonforlemmy.core_api.dto + +import kotlinx.serialization.SerialName +import kotlinx.serialization.Serializable + +@Serializable +data class DeletePostForm( + @SerialName("post_id") val postId: PostId, + @SerialName("deleted") val deleted: Boolean, + @SerialName("auth") val auth: String, +) \ No newline at end of file diff --git a/core-api/src/commonMain/kotlin/com/github/diegoberaldin/raccoonforlemmy/core_api/dto/EditPostForm.kt b/core-api/src/commonMain/kotlin/com/github/diegoberaldin/raccoonforlemmy/core_api/dto/EditPostForm.kt new file mode 100644 index 000000000..b3a3c26ff --- /dev/null +++ b/core-api/src/commonMain/kotlin/com/github/diegoberaldin/raccoonforlemmy/core_api/dto/EditPostForm.kt @@ -0,0 +1,15 @@ +package com.github.diegoberaldin.raccoonforlemmy.core_api.dto + +import kotlinx.serialization.SerialName +import kotlinx.serialization.Serializable + +@Serializable +data class EditPostForm( + @SerialName("post_id") val postId: PostId, + @SerialName("name") val name: String? = null, + @SerialName("url") val url: String? = null, + @SerialName("body") val body: String? = null, + @SerialName("nsfw") val nsfw: Boolean? = null, + @SerialName("language_id") val languageId: LanguageId? = null, + @SerialName("auth") val auth: String, +) \ No newline at end of file diff --git a/core-api/src/commonMain/kotlin/com/github/diegoberaldin/raccoonforlemmy/core_api/dto/FollowCommunityForm.kt b/core-api/src/commonMain/kotlin/com/github/diegoberaldin/raccoonforlemmy/core_api/dto/FollowCommunityForm.kt new file mode 100644 index 000000000..41f66c9da --- /dev/null +++ b/core-api/src/commonMain/kotlin/com/github/diegoberaldin/raccoonforlemmy/core_api/dto/FollowCommunityForm.kt @@ -0,0 +1,11 @@ +package com.github.diegoberaldin.raccoonforlemmy.core_api.dto + +import kotlinx.serialization.SerialName +import kotlinx.serialization.Serializable + +@Serializable +data class FollowCommunityForm( + @SerialName("community_id") val communityId: CommunityId, + @SerialName("follow") val follow: Boolean, + @SerialName("auth") val auth: String, +) \ No newline at end of file diff --git a/core-api/src/commonMain/kotlin/com/github/diegoberaldin/raccoonforlemmy/core_api/dto/GetCommunityResponse.kt b/core-api/src/commonMain/kotlin/com/github/diegoberaldin/raccoonforlemmy/core_api/dto/GetCommunityResponse.kt new file mode 100644 index 000000000..789050f33 --- /dev/null +++ b/core-api/src/commonMain/kotlin/com/github/diegoberaldin/raccoonforlemmy/core_api/dto/GetCommunityResponse.kt @@ -0,0 +1,13 @@ +package com.github.diegoberaldin.raccoonforlemmy.core_api.dto + +import kotlinx.serialization.SerialName +import kotlinx.serialization.Serializable + +@Serializable +data class GetCommunityResponse( + @SerialName("community_view") val communityView: CommunityView, + @SerialName("site") val site: Site? = null, + @SerialName("moderators") val moderators: List, + @SerialName("discussion_languages") val discussionLanguages: List, +) + diff --git a/core-api/src/commonMain/kotlin/com/github/diegoberaldin/raccoonforlemmy/core_api/dto/GetPersonDetailsResponse.kt b/core-api/src/commonMain/kotlin/com/github/diegoberaldin/raccoonforlemmy/core_api/dto/GetPersonDetailsResponse.kt new file mode 100644 index 000000000..9be55179b --- /dev/null +++ b/core-api/src/commonMain/kotlin/com/github/diegoberaldin/raccoonforlemmy/core_api/dto/GetPersonDetailsResponse.kt @@ -0,0 +1,12 @@ +package com.github.diegoberaldin.raccoonforlemmy.core_api.dto + +import kotlinx.serialization.SerialName +import kotlinx.serialization.Serializable + +@Serializable +data class GetPersonDetailsResponse( + @SerialName("person_view") val personView: PersonView, + @SerialName("comments") val comments: List, + @SerialName("posts") val posts: List, + @SerialName("moderates") val moderates: List, +) \ No newline at end of file diff --git a/core-api/src/commonMain/kotlin/com/github/diegoberaldin/raccoonforlemmy/core_api/dto/PersonAggregates.kt b/core-api/src/commonMain/kotlin/com/github/diegoberaldin/raccoonforlemmy/core_api/dto/PersonAggregates.kt new file mode 100644 index 000000000..8e155eb7e --- /dev/null +++ b/core-api/src/commonMain/kotlin/com/github/diegoberaldin/raccoonforlemmy/core_api/dto/PersonAggregates.kt @@ -0,0 +1,14 @@ +package com.github.diegoberaldin.raccoonforlemmy.core_api.dto + +import kotlinx.serialization.SerialName +import kotlinx.serialization.Serializable + +@Serializable +data class PersonAggregates( + @SerialName("id") val id: Int, + @SerialName("person_id") val personId: PersonId, + @SerialName("post_count") val postCount: Int, + @SerialName("post_score") val postScore: Int, + @SerialName("comment_count") val commentCount: Int, + @SerialName("comment_score") val commentScore: Int, +) \ No newline at end of file diff --git a/core-api/src/commonMain/kotlin/com/github/diegoberaldin/raccoonforlemmy/core_api/dto/PersonView.kt b/core-api/src/commonMain/kotlin/com/github/diegoberaldin/raccoonforlemmy/core_api/dto/PersonView.kt new file mode 100644 index 000000000..39c970cec --- /dev/null +++ b/core-api/src/commonMain/kotlin/com/github/diegoberaldin/raccoonforlemmy/core_api/dto/PersonView.kt @@ -0,0 +1,10 @@ +package com.github.diegoberaldin.raccoonforlemmy.core_api.dto + +import kotlinx.serialization.SerialName +import kotlinx.serialization.Serializable + +@Serializable +data class PersonView( + @SerialName("person") val person: Person, + @SerialName("counts") val counts: PersonAggregates, +) \ No newline at end of file diff --git a/core-api/src/commonMain/kotlin/com/github/diegoberaldin/raccoonforlemmy/core_api/dto/PostResponse.kt b/core-api/src/commonMain/kotlin/com/github/diegoberaldin/raccoonforlemmy/core_api/dto/PostResponse.kt new file mode 100644 index 000000000..ac4c51f11 --- /dev/null +++ b/core-api/src/commonMain/kotlin/com/github/diegoberaldin/raccoonforlemmy/core_api/dto/PostResponse.kt @@ -0,0 +1,10 @@ +package com.github.diegoberaldin.raccoonforlemmy.core_api.dto + +import kotlinx.serialization.SerialName +import kotlinx.serialization.Serializable + +@Serializable +data class PostResponse( + @SerialName("post_view") + val postView: PostView, +) \ No newline at end of file diff --git a/core-api/src/commonMain/kotlin/com/github/diegoberaldin/raccoonforlemmy/core_api/dto/SavePostForm.kt b/core-api/src/commonMain/kotlin/com/github/diegoberaldin/raccoonforlemmy/core_api/dto/SavePostForm.kt new file mode 100644 index 000000000..7ef393ab7 --- /dev/null +++ b/core-api/src/commonMain/kotlin/com/github/diegoberaldin/raccoonforlemmy/core_api/dto/SavePostForm.kt @@ -0,0 +1,11 @@ +package com.github.diegoberaldin.raccoonforlemmy.core_api.dto + +import kotlinx.serialization.SerialName +import kotlinx.serialization.Serializable + +@Serializable +data class SavePostForm( + @SerialName("post_id") val postId: PostId, + @SerialName("save") val save: Boolean, + @SerialName("auth") val auth: String, +) \ No newline at end of file diff --git a/core-api/src/commonMain/kotlin/com/github/diegoberaldin/raccoonforlemmy/core_api/dto/Site.kt b/core-api/src/commonMain/kotlin/com/github/diegoberaldin/raccoonforlemmy/core_api/dto/Site.kt new file mode 100644 index 000000000..99ddb60a2 --- /dev/null +++ b/core-api/src/commonMain/kotlin/com/github/diegoberaldin/raccoonforlemmy/core_api/dto/Site.kt @@ -0,0 +1,22 @@ +package com.github.diegoberaldin.raccoonforlemmy.core_api.dto + +import kotlinx.serialization.SerialName +import kotlinx.serialization.Serializable + +@Serializable +data class Site( + @SerialName("id") val id: SiteId, + @SerialName("name") val name: String, + @SerialName("sidebar") val sidebar: String? = null, + @SerialName("published") val published: String, + @SerialName("updated") val updated: String? = null, + @SerialName("icon") val icon: String? = null, + @SerialName("banner") val banner: String? = null, + @SerialName("description") val description: String? = null, + @SerialName("actor_id") val actorId: String, + @SerialName("last_refreshed_at") val lastRefreshedAt: String, + @SerialName("inbox_url") val inboxUrl: String, + @SerialName("private_key") val privateKey: String? = null, + @SerialName("public_key") val publicKey: String, + @SerialName("instance_id") val instanceId: InstanceId, +) diff --git a/core-api/src/commonMain/kotlin/com/github/diegoberaldin/raccoonforlemmy/core_api/provider/DefaultServiceProvider.kt b/core-api/src/commonMain/kotlin/com/github/diegoberaldin/raccoonforlemmy/core_api/provider/DefaultServiceProvider.kt index 8a5f8c8b7..52173b9aa 100644 --- a/core-api/src/commonMain/kotlin/com/github/diegoberaldin/raccoonforlemmy/core_api/provider/DefaultServiceProvider.kt +++ b/core-api/src/commonMain/kotlin/com/github/diegoberaldin/raccoonforlemmy/core_api/provider/DefaultServiceProvider.kt @@ -1,5 +1,6 @@ package com.github.diegoberaldin.raccoonforlemmy.core_api.provider +import com.github.diegoberaldin.raccoonforlemmy.core_api.service.CommunityService import com.github.diegoberaldin.raccoonforlemmy.core_api.service.PostService import de.jensklingenberg.ktorfit.Ktorfit import io.ktor.client.HttpClient @@ -12,7 +13,7 @@ import kotlinx.serialization.json.Json internal class DefaultServiceProvider : ServiceProvider { companion object { - private const val DEFAULT_INSTANCE = "enterprise.lemmy.ml" + private const val DEFAULT_INSTANCE = "lemmy.world" private const val VERSION = "v3" } @@ -22,6 +23,9 @@ internal class DefaultServiceProvider : ServiceProvider { override lateinit var postService: PostService private set + override lateinit var communityService: CommunityService + private set + private val baseUrl: String get() = "https://$currentInstance/api/$VERSION/" private val client = HttpClient { install(Logging) { @@ -49,5 +53,6 @@ internal class DefaultServiceProvider : ServiceProvider { .httpClient(client) .build() postService = ktorfit.create() + communityService = ktorfit.create() } } \ No newline at end of file diff --git a/core-api/src/commonMain/kotlin/com/github/diegoberaldin/raccoonforlemmy/core_api/provider/ServiceProvider.kt b/core-api/src/commonMain/kotlin/com/github/diegoberaldin/raccoonforlemmy/core_api/provider/ServiceProvider.kt index 3176aaca5..a71a4eac0 100644 --- a/core-api/src/commonMain/kotlin/com/github/diegoberaldin/raccoonforlemmy/core_api/provider/ServiceProvider.kt +++ b/core-api/src/commonMain/kotlin/com/github/diegoberaldin/raccoonforlemmy/core_api/provider/ServiceProvider.kt @@ -1,11 +1,13 @@ package com.github.diegoberaldin.raccoonforlemmy.core_api.provider +import com.github.diegoberaldin.raccoonforlemmy.core_api.service.CommunityService import com.github.diegoberaldin.raccoonforlemmy.core_api.service.PostService interface ServiceProvider { val currentInstance: String val postService: PostService + val communityService: CommunityService fun changeInstance(value: String) } 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 new file mode 100644 index 000000000..44648e738 --- /dev/null +++ b/core-api/src/commonMain/kotlin/com/github/diegoberaldin/raccoonforlemmy/core_api/service/CommunityService.kt @@ -0,0 +1,29 @@ +package com.github.diegoberaldin.raccoonforlemmy.core_api.service + +import com.github.diegoberaldin.raccoonforlemmy.core_api.dto.BlockCommunityForm +import com.github.diegoberaldin.raccoonforlemmy.core_api.dto.BlockCommunityResponse +import com.github.diegoberaldin.raccoonforlemmy.core_api.dto.CommunityResponse +import com.github.diegoberaldin.raccoonforlemmy.core_api.dto.FollowCommunityForm +import com.github.diegoberaldin.raccoonforlemmy.core_api.dto.GetCommunityResponse +import de.jensklingenberg.ktorfit.Response +import de.jensklingenberg.ktorfit.http.Body +import de.jensklingenberg.ktorfit.http.GET +import de.jensklingenberg.ktorfit.http.POST +import de.jensklingenberg.ktorfit.http.Query + +interface CommunityService { + + @GET("community") + suspend fun getCommunity( + @Query("auth") auth: String? = null, + @Query("id") id: Int? = null, + @Query("name") name: String? = null, + ): Response + + @POST("community/follow") + suspend fun followCommunity(@Body form: FollowCommunityForm): Response + + @POST("community/block") + suspend fun blockCommunity(@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 233ee356b..43820eed1 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 @@ -1,11 +1,19 @@ package com.github.diegoberaldin.raccoonforlemmy.core_api.service +import com.github.diegoberaldin.raccoonforlemmy.core_api.dto.CreatePostForm +import com.github.diegoberaldin.raccoonforlemmy.core_api.dto.DeletePostForm +import com.github.diegoberaldin.raccoonforlemmy.core_api.dto.EditPostForm import com.github.diegoberaldin.raccoonforlemmy.core_api.dto.GetPostResponse import com.github.diegoberaldin.raccoonforlemmy.core_api.dto.GetPostsResponse import com.github.diegoberaldin.raccoonforlemmy.core_api.dto.ListingType +import com.github.diegoberaldin.raccoonforlemmy.core_api.dto.PostResponse +import com.github.diegoberaldin.raccoonforlemmy.core_api.dto.SavePostForm 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.POST +import de.jensklingenberg.ktorfit.http.PUT import de.jensklingenberg.ktorfit.http.Query interface PostService { @@ -28,4 +36,17 @@ interface PostService { @Query("id") id: Int? = null, @Query("comment_id") commentId: Int? = null, ): Response + + @PUT("post/save") + suspend fun savePost(@Body form: SavePostForm): Response + + @POST("post") + suspend fun createPost(@Body form: CreatePostForm): Response + + @PUT("post") + suspend fun editPost(@Body form: EditPostForm): Response + + @POST("post/delete") + suspend fun deletePost(@Body form: DeletePostForm): Response + } \ No newline at end of file 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 new file mode 100644 index 000000000..ecd7e21e4 --- /dev/null +++ b/core-api/src/commonMain/kotlin/com/github/diegoberaldin/raccoonforlemmy/core_api/service/UserService.kt @@ -0,0 +1,22 @@ +package com.github.diegoberaldin.raccoonforlemmy.core_api.service + +import com.github.diegoberaldin.raccoonforlemmy.core_api.dto.GetPersonDetailsResponse +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.Query + +interface UserService { + + @GET("user") + suspend fun getPersonDetails( + @Query("auth") auth: String? = null, + @Query("community_id") communityId: Int? = null, + @Query("person_id") personId: Int? = null, + @Query("page") page: Int? = null, + @Query("limit") limit: Int? = null, + @Query("sort") sort: SortType, + @Query("username") username: String? = null, + @Query("saved_only") savedOnly: Boolean? = null, + ): Response +} \ No newline at end of file diff --git a/domain-post/data/src/commonMain/kotlin/com/github/diegoberaldin/raccoonforlemmy/data/CommunityModel.kt b/domain-post/data/src/commonMain/kotlin/com/github/diegoberaldin/raccoonforlemmy/data/CommunityModel.kt new file mode 100644 index 000000000..2098e4222 --- /dev/null +++ b/domain-post/data/src/commonMain/kotlin/com/github/diegoberaldin/raccoonforlemmy/data/CommunityModel.kt @@ -0,0 +1,8 @@ +package com.github.diegoberaldin.raccoonforlemmy.data + +data class CommunityModel( + val id: Int = 0, + val name: String = "", + val instance: String = "", + val icon: String? = null, +) diff --git a/domain-post/data/src/commonMain/kotlin/com/github/diegoberaldin/raccoonforlemmy/data/PostModel.kt b/domain-post/data/src/commonMain/kotlin/com/github/diegoberaldin/raccoonforlemmy/data/PostModel.kt index bf6a9575a..e723fd83a 100644 --- a/domain-post/data/src/commonMain/kotlin/com/github/diegoberaldin/raccoonforlemmy/data/PostModel.kt +++ b/domain-post/data/src/commonMain/kotlin/com/github/diegoberaldin/raccoonforlemmy/data/PostModel.kt @@ -1,6 +1,11 @@ package com.github.diegoberaldin.raccoonforlemmy.data data class PostModel( + val id: Int = 0, val title: String = "", val text: String = "", + val score: Int = 0, + val comments: Int = 0, + val thumbnailUrl: String? = null, + val community: CommunityModel? = null, ) \ No newline at end of file diff --git a/domain-post/data/src/commonMain/kotlin/com/github/diegoberaldin/raccoonforlemmy/data/UserModel.kt b/domain-post/data/src/commonMain/kotlin/com/github/diegoberaldin/raccoonforlemmy/data/UserModel.kt new file mode 100644 index 000000000..b6e098120 --- /dev/null +++ b/domain-post/data/src/commonMain/kotlin/com/github/diegoberaldin/raccoonforlemmy/data/UserModel.kt @@ -0,0 +1,5 @@ +package com.github.diegoberaldin.raccoonforlemmy.data + +data class UserModel( + val name: String = "", +) \ No newline at end of file diff --git a/domain-post/repository/src/commonMain/kotlin/com/github/diegoberaldin/raccoonforlemmy/domain_post/repository/CommunityRepository.kt b/domain-post/repository/src/commonMain/kotlin/com/github/diegoberaldin/raccoonforlemmy/domain_post/repository/CommunityRepository.kt new file mode 100644 index 000000000..0f10c016d --- /dev/null +++ b/domain-post/repository/src/commonMain/kotlin/com/github/diegoberaldin/raccoonforlemmy/domain_post/repository/CommunityRepository.kt @@ -0,0 +1,20 @@ +package com.github.diegoberaldin.raccoonforlemmy.domain_post.repository + +import com.github.diegoberaldin.raccoonforlemmy.core_api.dto.CommunityView +import com.github.diegoberaldin.raccoonforlemmy.core_api.service.CommunityService +import com.github.diegoberaldin.raccoonforlemmy.data.CommunityModel + +class CommunityRepository( + private val communityService: CommunityService, +) { + + suspend fun getCommunity(id: Int): CommunityModel? { + val response = communityService.getCommunity(id = id).body() + return response?.communityView?.toModel() + } +} + +private fun CommunityView.toModel() = CommunityModel( + name = community.name, + icon = community.icon, +) \ No newline at end of file diff --git a/domain-post/repository/src/commonMain/kotlin/com/github/diegoberaldin/raccoonforlemmy/domain_post/repository/PostsRepository.kt b/domain-post/repository/src/commonMain/kotlin/com/github/diegoberaldin/raccoonforlemmy/domain_post/repository/PostsRepository.kt index d52de5eb5..ec17cd056 100644 --- a/domain-post/repository/src/commonMain/kotlin/com/github/diegoberaldin/raccoonforlemmy/domain_post/repository/PostsRepository.kt +++ b/domain-post/repository/src/commonMain/kotlin/com/github/diegoberaldin/raccoonforlemmy/domain_post/repository/PostsRepository.kt @@ -2,6 +2,7 @@ package com.github.diegoberaldin.raccoonforlemmy.domain_post.repository import com.github.diegoberaldin.raccoonforlemmy.core_api.dto.PostView import com.github.diegoberaldin.raccoonforlemmy.core_api.service.PostService +import com.github.diegoberaldin.raccoonforlemmy.data.CommunityModel import com.github.diegoberaldin.raccoonforlemmy.data.ListingType import com.github.diegoberaldin.raccoonforlemmy.data.PostModel import com.github.diegoberaldin.raccoonforlemmy.data.SortType @@ -34,8 +35,13 @@ class PostsRepository( } private fun PostView.toModel() = PostModel( - title = this.post.name, - text = this.post.body.orEmpty(), + id = post.id, + title = post.name, + text = post.body.orEmpty(), + score = counts.score, + comments = counts.comments, + thumbnailUrl = post.thumbnailUrl.orEmpty(), + community = CommunityModel(id = post.communityId) ) private fun ListingType.toDto() = when (this) { diff --git a/domain-post/repository/src/commonMain/kotlin/com/github/diegoberaldin/raccoonforlemmy/domain_post/repository/PostsRepositoryModule.kt b/domain-post/repository/src/commonMain/kotlin/com/github/diegoberaldin/raccoonforlemmy/domain_post/repository/PostsRepositoryModule.kt index 816f8ebb7..afce64251 100644 --- a/domain-post/repository/src/commonMain/kotlin/com/github/diegoberaldin/raccoonforlemmy/domain_post/repository/PostsRepositoryModule.kt +++ b/domain-post/repository/src/commonMain/kotlin/com/github/diegoberaldin/raccoonforlemmy/domain_post/repository/PostsRepositoryModule.kt @@ -4,6 +4,7 @@ import org.koin.core.module.dsl.singleOf import org.koin.dsl.module val postsRepositoryModule = module { - singleOf(::PostsRepository) singleOf(::ApiConfigurationRepository) + singleOf(::PostsRepository) + singleOf(::CommunityRepository) } \ No newline at end of file diff --git a/feature-home/build.gradle.kts b/feature-home/build.gradle.kts index 6993efc1a..5e4c30298 100644 --- a/feature-home/build.gradle.kts +++ b/feature-home/build.gradle.kts @@ -45,6 +45,7 @@ kotlin { implementation(libs.voyager.navigator) implementation(libs.voyager.tab) + implementation(libs.compose.imageloader) implementation(projects.resources) implementation(projects.coreAppearance) diff --git a/feature-home/src/androidMain/kotlin/com/github/diegoberaldin/raccoonforlemmy/feature_home/HomeModule.kt b/feature-home/src/androidMain/kotlin/com/github/diegoberaldin/raccoonforlemmy/feature_home/HomeModule.kt index 318b195c1..d7e720458 100644 --- a/feature-home/src/androidMain/kotlin/com/github/diegoberaldin/raccoonforlemmy/feature_home/HomeModule.kt +++ b/feature-home/src/androidMain/kotlin/com/github/diegoberaldin/raccoonforlemmy/feature_home/HomeModule.kt @@ -11,6 +11,7 @@ actual val homeTabModule = module { HomeScreenModel( mvi = DefaultMviModel(HomeScreenMviModel.UiState()), postsRepository = get(), + communityRepository = get(), apiConfigRepository = get(), ) } diff --git a/feature-home/src/commonMain/kotlin/com/github/diegoberaldin/raccoonforlemmy/feature_home/HomeScreenModel.kt b/feature-home/src/commonMain/kotlin/com/github/diegoberaldin/raccoonforlemmy/feature_home/HomeScreenModel.kt index ad2177744..2647303dc 100644 --- a/feature-home/src/commonMain/kotlin/com/github/diegoberaldin/raccoonforlemmy/feature_home/HomeScreenModel.kt +++ b/feature-home/src/commonMain/kotlin/com/github/diegoberaldin/raccoonforlemmy/feature_home/HomeScreenModel.kt @@ -6,6 +6,7 @@ import com.github.diegoberaldin.raccoonforlemmy.core_architecture.MviModel import com.github.diegoberaldin.raccoonforlemmy.data.ListingType import com.github.diegoberaldin.raccoonforlemmy.data.SortType import com.github.diegoberaldin.raccoonforlemmy.domain_post.repository.ApiConfigurationRepository +import com.github.diegoberaldin.raccoonforlemmy.domain_post.repository.CommunityRepository import com.github.diegoberaldin.raccoonforlemmy.domain_post.repository.PostsRepository import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.IO @@ -14,6 +15,7 @@ import kotlinx.coroutines.launch class HomeScreenModel( private val mvi: DefaultMviModel, private val postsRepository: PostsRepository, + private val communityRepository: CommunityRepository, private val apiConfigRepository: ApiConfigurationRepository, ) : ScreenModel, MviModel by mvi { @@ -56,12 +58,30 @@ class HomeScreenModel( page = currentPage, type = type, sort = sort, - ) + ).map { + val community = it.community + if (community?.id != null) { + val remoteCommunity = communityRepository.getCommunity(community.id) + it.copy( + community = it.community?.copy( + name = remoteCommunity?.name.orEmpty(), + icon = remoteCommunity?.icon, + ) + ) + } else { + it + } + } currentPage++ val canFetchMore = postList.size >= PostsRepository.DEFAULT_PAGE_SIZE mvi.updateState { + val newPosts = if (refreshing) { + postList + } else { + it.posts + postList + } it.copy( - posts = if (refreshing) postList else it.posts + postList, + posts = newPosts, loading = false, canFetchMore = canFetchMore, refreshing = false, diff --git a/feature-home/src/commonMain/kotlin/com/github/diegoberaldin/raccoonforlemmy/feature_home/HomeTab.kt b/feature-home/src/commonMain/kotlin/com/github/diegoberaldin/raccoonforlemmy/feature_home/HomeTab.kt index a24190377..f9fab466d 100644 --- a/feature-home/src/commonMain/kotlin/com/github/diegoberaldin/raccoonforlemmy/feature_home/HomeTab.kt +++ b/feature-home/src/commonMain/kotlin/com/github/diegoberaldin/raccoonforlemmy/feature_home/HomeTab.kt @@ -1,49 +1,36 @@ package com.github.diegoberaldin.raccoonforlemmy.feature_home -import androidx.compose.foundation.Image -import androidx.compose.foundation.background import androidx.compose.foundation.layout.Arrangement import androidx.compose.foundation.layout.Box -import androidx.compose.foundation.layout.Column -import androidx.compose.foundation.layout.Row -import androidx.compose.foundation.layout.Spacer import androidx.compose.foundation.layout.fillMaxSize import androidx.compose.foundation.layout.fillMaxWidth -import androidx.compose.foundation.layout.height import androidx.compose.foundation.layout.padding import androidx.compose.foundation.layout.size import androidx.compose.foundation.lazy.LazyColumn import androidx.compose.foundation.lazy.items -import androidx.compose.foundation.shape.RoundedCornerShape import androidx.compose.material.ExperimentalMaterialApi import androidx.compose.material.icons.Icons import androidx.compose.material.icons.filled.SpaceDashboard import androidx.compose.material.pullrefresh.PullRefreshIndicator import androidx.compose.material.pullrefresh.pullRefresh import androidx.compose.material.pullrefresh.rememberPullRefreshState -import androidx.compose.material3.Card import androidx.compose.material3.CircularProgressIndicator import androidx.compose.material3.ExperimentalMaterial3Api import androidx.compose.material3.MaterialTheme import androidx.compose.material3.Scaffold -import androidx.compose.material3.Text import androidx.compose.runtime.Composable import androidx.compose.runtime.collectAsState import androidx.compose.runtime.getValue import androidx.compose.runtime.remember import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier -import androidx.compose.ui.graphics.ColorFilter import androidx.compose.ui.graphics.vector.rememberVectorPainter import androidx.compose.ui.unit.dp import cafe.adriel.voyager.core.model.rememberScreenModel import cafe.adriel.voyager.navigator.tab.Tab import cafe.adriel.voyager.navigator.tab.TabOptions -import com.github.diegoberaldin.racconforlemmy.core_utils.onClick -import com.github.diegoberaldin.raccoonforlemmy.core_appearance.theme.CornerSize import com.github.diegoberaldin.raccoonforlemmy.core_appearance.theme.Spacing import com.github.diegoberaldin.raccoonforlemmy.core_architecture.bindToLifecycle -import com.github.diegoberaldin.raccoonforlemmy.core_md.compose.Markdown import com.github.diegoberaldin.raccoonforlemmy.feature_home.modals.ListingTypeBottomSheet import com.github.diegoberaldin.raccoonforlemmy.feature_home.modals.SortBottomSheet import com.github.diegoberaldin.raccoonforlemmy.resources.MR @@ -81,7 +68,27 @@ object HomeTab : Tab { Scaffold( modifier = Modifier.padding(Spacing.xxs), topBar = { - PostsTopBar(model, uiState) + PostsTopBar( + currentInstance = uiState.instance, + listingType = uiState.listingType, + sortType = uiState.sortType, + onSelectListingType = { + bottomSheetChannel.trySend @Composable { + ListingTypeBottomSheet { type -> + model.reduce(HomeScreenMviModel.Intent.ChangeListing(type)) + bottomSheetChannel.trySend(null) + } + } + }, + onSelectSortType = { + bottomSheetChannel.trySend @Composable { + SortBottomSheet { type -> + model.reduce(HomeScreenMviModel.Intent.ChangeSort(type)) + bottomSheetChannel.trySend(null) + } + } + }, + ) } ) { val pullRefreshState = rememberPullRefreshState(uiState.refreshing, { @@ -95,25 +102,7 @@ object HomeTab : Tab { verticalArrangement = Arrangement.spacedBy(Spacing.xs) ) { items(uiState.posts) { post -> - Card( - modifier = Modifier - .fillMaxWidth() - .background( - color = MaterialTheme.colorScheme.surfaceVariant, - shape = RoundedCornerShape(CornerSize.m) - ).padding(Spacing.s) - ) { - Column { - Text( - text = post.title, - style = MaterialTheme.typography.titleMedium, - ) - val body = post.text - if (body.isNotEmpty()) { - Markdown(content = body) - } - } - } + PostCard(post) } item { if (!uiState.loading && !uiState.refreshing && uiState.canFetchMore) { @@ -143,65 +132,4 @@ object HomeTab : Tab { } } } - - @Composable - private fun PostsTopBar( - model: HomeScreenModel, - uiState: HomeScreenMviModel.UiState, - ) { - Row( - modifier = Modifier.height(64.dp).padding(Spacing.s), - verticalAlignment = Alignment.CenterVertically, - ) { - Row( - modifier = Modifier.onClick { - bottomSheetChannel.trySend @Composable { - ListingTypeBottomSheet { type -> - model.reduce(HomeScreenMviModel.Intent.ChangeListing(type)) - bottomSheetChannel.trySend(null) - } - } - }, - verticalAlignment = Alignment.CenterVertically, - horizontalArrangement = Arrangement.spacedBy(Spacing.m), - ) { - Image( - imageVector = uiState.listingType.toIcon(), - contentDescription = null, - colorFilter = ColorFilter.tint(MaterialTheme.colorScheme.onBackground) - ) - Column( - verticalArrangement = Arrangement.spacedBy(Spacing.xxxs) - ) { - Text( - text = uiState.listingType.toReadableName(), - style = MaterialTheme.typography.titleMedium - ) - Text( - text = stringResource( - MR.strings.home_instance_via, - uiState.instance - ), - style = MaterialTheme.typography.titleSmall - ) - } - } - - Spacer(modifier = Modifier.weight(1f)) - - Image( - modifier = Modifier.onClick { - bottomSheetChannel.trySend @Composable { - SortBottomSheet { type -> - model.reduce(HomeScreenMviModel.Intent.ChangeSort(type)) - bottomSheetChannel.trySend(null) - } - } - }, - imageVector = uiState.sortType.toIcon(), - contentDescription = null, - colorFilter = ColorFilter.tint(MaterialTheme.colorScheme.onBackground) - ) - } - } } diff --git a/feature-home/src/commonMain/kotlin/com/github/diegoberaldin/raccoonforlemmy/feature_home/PostCard.kt b/feature-home/src/commonMain/kotlin/com/github/diegoberaldin/raccoonforlemmy/feature_home/PostCard.kt new file mode 100644 index 000000000..81def0c3e --- /dev/null +++ b/feature-home/src/commonMain/kotlin/com/github/diegoberaldin/raccoonforlemmy/feature_home/PostCard.kt @@ -0,0 +1,128 @@ +package com.github.diegoberaldin.raccoonforlemmy.feature_home + +import androidx.compose.foundation.Image +import androidx.compose.foundation.background +import androidx.compose.foundation.layout.Arrangement +import androidx.compose.foundation.layout.Column +import androidx.compose.foundation.layout.Row +import androidx.compose.foundation.layout.Spacer +import androidx.compose.foundation.layout.fillMaxWidth +import androidx.compose.foundation.layout.padding +import androidx.compose.foundation.layout.size +import androidx.compose.foundation.shape.RoundedCornerShape +import androidx.compose.material.icons.Icons +import androidx.compose.material.icons.filled.ArrowDropDown +import androidx.compose.material.icons.filled.ArrowDropUp +import androidx.compose.material.icons.filled.Chat +import androidx.compose.material3.Card +import androidx.compose.material3.MaterialTheme +import androidx.compose.material3.Text +import androidx.compose.runtime.Composable +import androidx.compose.ui.Alignment +import androidx.compose.ui.Modifier +import androidx.compose.ui.draw.clip +import androidx.compose.ui.graphics.ColorFilter +import androidx.compose.ui.layout.ContentScale +import androidx.compose.ui.unit.dp +import com.github.diegoberaldin.raccoonforlemmy.core_appearance.theme.CornerSize +import com.github.diegoberaldin.raccoonforlemmy.core_appearance.theme.Spacing +import com.github.diegoberaldin.raccoonforlemmy.core_md.compose.Markdown +import com.github.diegoberaldin.raccoonforlemmy.data.PostModel +import com.seiko.imageloader.rememberImagePainter + +@Composable +fun PostCard( + post: PostModel, +) { + Card( + modifier = Modifier + .fillMaxWidth() + .background( + color = MaterialTheme.colorScheme.surfaceVariant, + shape = RoundedCornerShape(CornerSize.m) + ).padding( + vertical = Spacing.lHalf, + horizontal = Spacing.s, + ) + ) { + Column( + verticalArrangement = Arrangement.spacedBy(Spacing.s) + ) { + Text( + text = post.title, + style = MaterialTheme.typography.titleMedium, + ) + + val communityName = post.community?.name.orEmpty() + val communityIcon = post.community?.icon.orEmpty() + val iconSize = 21.dp + if (communityName.isNotEmpty()) { + Row( + verticalAlignment = Alignment.CenterVertically, + horizontalArrangement = Arrangement.spacedBy(Spacing.s), + ) { + if (communityIcon.isNotEmpty()) { + val painter = rememberImagePainter(communityIcon) + Image( + modifier = Modifier.size(iconSize) + .clip(RoundedCornerShape(iconSize / 2)), + painter = painter, + contentDescription = null, + contentScale = ContentScale.FillWidth, + ) + } + Text( + text = communityName, + style = MaterialTheme.typography.titleSmall, + ) + } + } + + val imageUrl = post.thumbnailUrl + if (!imageUrl.isNullOrEmpty()) { + val painter = rememberImagePainter(imageUrl) + Image( + modifier = Modifier.fillMaxWidth(), + painter = painter, + contentDescription = null, + contentScale = ContentScale.FillWidth, + ) + } + val body = post.text + if (body.isNotEmpty()) { + Markdown(content = body) + } + Row( + verticalAlignment = Alignment.CenterVertically, + horizontalArrangement = Arrangement.spacedBy(Spacing.xxs), + ) { + val buttonModifier = Modifier.size(42.dp) + Image( + modifier = buttonModifier, + imageVector = Icons.Default.ArrowDropUp, + contentDescription = null, + colorFilter = ColorFilter.tint(color = MaterialTheme.colorScheme.onSurface) + ) + Text( + text = "${post.score}" + ) + Image( + modifier = buttonModifier, + imageVector = Icons.Default.ArrowDropDown, + contentDescription = null, + colorFilter = ColorFilter.tint(color = MaterialTheme.colorScheme.onSurface) + ) + Spacer(modifier = Modifier.weight(1f)) + Image( + modifier = buttonModifier.padding(10.dp), + imageVector = Icons.Default.Chat, + contentDescription = null, + colorFilter = ColorFilter.tint(color = MaterialTheme.colorScheme.onSurface) + ) + Text( + text = "${post.comments}" + ) + } + } + } +} \ No newline at end of file diff --git a/feature-home/src/commonMain/kotlin/com/github/diegoberaldin/raccoonforlemmy/feature_home/PostsTopBar.kt b/feature-home/src/commonMain/kotlin/com/github/diegoberaldin/raccoonforlemmy/feature_home/PostsTopBar.kt new file mode 100644 index 000000000..ab94f1e18 --- /dev/null +++ b/feature-home/src/commonMain/kotlin/com/github/diegoberaldin/raccoonforlemmy/feature_home/PostsTopBar.kt @@ -0,0 +1,76 @@ +package com.github.diegoberaldin.raccoonforlemmy.feature_home + +import androidx.compose.foundation.Image +import androidx.compose.foundation.layout.Arrangement +import androidx.compose.foundation.layout.Column +import androidx.compose.foundation.layout.Row +import androidx.compose.foundation.layout.Spacer +import androidx.compose.foundation.layout.height +import androidx.compose.foundation.layout.padding +import androidx.compose.material3.MaterialTheme +import androidx.compose.material3.Text +import androidx.compose.runtime.Composable +import androidx.compose.ui.Alignment +import androidx.compose.ui.Modifier +import androidx.compose.ui.graphics.ColorFilter +import androidx.compose.ui.unit.dp +import com.github.diegoberaldin.racconforlemmy.core_utils.onClick +import com.github.diegoberaldin.raccoonforlemmy.core_appearance.theme.Spacing +import com.github.diegoberaldin.raccoonforlemmy.data.ListingType +import com.github.diegoberaldin.raccoonforlemmy.data.SortType +import com.github.diegoberaldin.raccoonforlemmy.resources.MR +import dev.icerock.moko.resources.compose.stringResource + +@Composable +internal fun PostsTopBar( + currentInstance: String, + listingType: ListingType, + sortType: SortType, + onSelectListingType: () -> Unit, + onSelectSortType: () -> Unit, +) { + Row( + modifier = Modifier.height(64.dp).padding(Spacing.s), + verticalAlignment = Alignment.CenterVertically, + ) { + Row( + modifier = Modifier.onClick { + onSelectListingType() + }, + verticalAlignment = Alignment.CenterVertically, + horizontalArrangement = Arrangement.spacedBy(Spacing.m), + ) { + Image( + imageVector = listingType.toIcon(), + contentDescription = null, + colorFilter = ColorFilter.tint(MaterialTheme.colorScheme.onBackground) + ) + Column( + verticalArrangement = Arrangement.spacedBy(Spacing.xxxs) + ) { + Text( + text = listingType.toReadableName(), + style = MaterialTheme.typography.titleMedium + ) + Text( + text = stringResource( + MR.strings.home_instance_via, + currentInstance, + ), + style = MaterialTheme.typography.titleSmall + ) + } + } + + Spacer(modifier = Modifier.weight(1f)) + + Image( + modifier = Modifier.onClick { + onSelectSortType() + }, + imageVector = sortType.toIcon(), + contentDescription = null, + colorFilter = ColorFilter.tint(MaterialTheme.colorScheme.onBackground) + ) + } +} \ No newline at end of file diff --git a/feature-search/build.gradle.kts b/feature-search/build.gradle.kts index 33b4ecab5..ce31db390 100644 --- a/feature-search/build.gradle.kts +++ b/feature-search/build.gradle.kts @@ -38,6 +38,7 @@ kotlin { implementation(compose.runtime) implementation(compose.foundation) implementation(compose.material3) + implementation(compose.materialIconsExtended) @OptIn(org.jetbrains.compose.ExperimentalComposeLibrary::class) implementation(compose.components.resources) diff --git a/feature-search/src/commonMain/kotlin/com/github/diegoberaldin/raccoonforlemmy/feature_search/SearchTab.kt b/feature-search/src/commonMain/kotlin/com/github/diegoberaldin/raccoonforlemmy/feature_search/SearchTab.kt index 7abbede3e..3115bcb1f 100644 --- a/feature-search/src/commonMain/kotlin/com/github/diegoberaldin/raccoonforlemmy/feature_search/SearchTab.kt +++ b/feature-search/src/commonMain/kotlin/com/github/diegoberaldin/raccoonforlemmy/feature_search/SearchTab.kt @@ -3,7 +3,7 @@ package com.github.diegoberaldin.raccoonforlemmy.feature_search import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.padding import androidx.compose.material.icons.Icons -import androidx.compose.material.icons.filled.Search +import androidx.compose.material.icons.filled.Explore import androidx.compose.material3.Text import androidx.compose.runtime.Composable import androidx.compose.runtime.remember @@ -23,7 +23,7 @@ object SearchTab : Tab { @Composable get() { val title = stringResource(MR.strings.navigation_search) - val icon = rememberVectorPainter(Icons.Default.Search) + val icon = rememberVectorPainter(Icons.Default.Explore) return remember { TabOptions(