diff --git a/app/src/main/java/com/xiaoyv/bangumi/ui/media/detail/chapter/MediaChapterFragment.kt b/app/src/main/java/com/xiaoyv/bangumi/ui/media/detail/chapter/MediaChapterFragment.kt index e8cb6b1b..dd404a18 100644 --- a/app/src/main/java/com/xiaoyv/bangumi/ui/media/detail/chapter/MediaChapterFragment.kt +++ b/app/src/main/java/com/xiaoyv/bangumi/ui/media/detail/chapter/MediaChapterFragment.kt @@ -13,6 +13,7 @@ import com.xiaoyv.blueprint.constant.NavKey import com.xiaoyv.common.api.parser.entity.MediaChapterEntity import com.xiaoyv.common.config.annotation.BgmPathType import com.xiaoyv.common.config.annotation.InterestType +import com.xiaoyv.common.config.annotation.MediaType import com.xiaoyv.common.config.annotation.TopicType import com.xiaoyv.common.helper.UserHelper import com.xiaoyv.common.kts.setOnDebouncedChildClickListener @@ -51,6 +52,13 @@ class MediaChapterFragment : BaseListFragment val chapterEntity = adapter.getItem(position) - if (chapterEntity != null && chapterEntity.splitter.not() && viewModel.canChangeEpProgress) { - showEpCollectDialog(chapterEntity) + if (chapterEntity != null && chapterEntity.splitter.not()) { + if (viewModel.canChangeEpProgress) { + showEpCollectDialog(chapterEntity) + } else { + RouteHelper.jumpTopicDetail(chapterEntity.id, TopicType.TYPE_EP) + } } }, onClickEpAdd = { entity, isAddEp -> diff --git a/app/src/main/java/com/xiaoyv/bangumi/ui/media/detail/review/MediaReviewAdapter.kt b/app/src/main/java/com/xiaoyv/bangumi/ui/media/detail/review/MediaReviewAdapter.kt index 731f3b44..ee2d7efe 100644 --- a/app/src/main/java/com/xiaoyv/bangumi/ui/media/detail/review/MediaReviewAdapter.kt +++ b/app/src/main/java/com/xiaoyv/bangumi/ui/media/detail/review/MediaReviewAdapter.kt @@ -2,7 +2,7 @@ package com.xiaoyv.bangumi.ui.media.detail.review import androidx.recyclerview.widget.DiffUtil import com.xiaoyv.bangumi.databinding.FragmentMediaReviewItemBinding -import com.xiaoyv.common.api.parser.entity.MediaReviewEntity +import com.xiaoyv.common.api.parser.entity.MediaReviewBlogEntity import com.xiaoyv.common.kts.loadImageAnimate import com.xiaoyv.widget.binder.BaseQuickBindingHolder import com.xiaoyv.widget.binder.BaseQuickDiffBindingAdapter @@ -13,27 +13,27 @@ import com.xiaoyv.widget.binder.BaseQuickDiffBindingAdapter * @author why * @since 11/24/23 */ -class MediaReviewAdapter : BaseQuickDiffBindingAdapter(ItemDiffItemCallback) { - override fun BaseQuickBindingHolder.converted(item: MediaReviewEntity) { + override fun BaseQuickBindingHolder.converted(item: MediaReviewBlogEntity) { binding.ivAvatar.loadImageAnimate(item.avatar) binding.tvTitle.text = String.format("日志:%s", item.title) binding.tvContent.text = item.comment binding.tvTime.text = item.time } - private object ItemDiffItemCallback : DiffUtil.ItemCallback() { + private object ItemDiffItemCallback : DiffUtil.ItemCallback() { override fun areItemsTheSame( - oldItem: MediaReviewEntity, - newItem: MediaReviewEntity + oldItem: MediaReviewBlogEntity, + newItem: MediaReviewBlogEntity ): Boolean { return oldItem.id == newItem.id } override fun areContentsTheSame( - oldItem: MediaReviewEntity, - newItem: MediaReviewEntity + oldItem: MediaReviewBlogEntity, + newItem: MediaReviewBlogEntity ): Boolean { return oldItem == newItem } diff --git a/app/src/main/java/com/xiaoyv/bangumi/ui/media/detail/review/MediaReviewFragment.kt b/app/src/main/java/com/xiaoyv/bangumi/ui/media/detail/review/MediaReviewFragment.kt index 9c7b495a..3987afe7 100644 --- a/app/src/main/java/com/xiaoyv/bangumi/ui/media/detail/review/MediaReviewFragment.kt +++ b/app/src/main/java/com/xiaoyv/bangumi/ui/media/detail/review/MediaReviewFragment.kt @@ -6,7 +6,7 @@ import com.xiaoyv.bangumi.R import com.xiaoyv.bangumi.base.BaseListFragment import com.xiaoyv.bangumi.helper.RouteHelper import com.xiaoyv.blueprint.constant.NavKey -import com.xiaoyv.common.api.parser.entity.MediaReviewEntity +import com.xiaoyv.common.api.parser.entity.MediaReviewBlogEntity import com.xiaoyv.common.kts.setOnDebouncedChildClickListener import com.xiaoyv.widget.binder.BaseQuickDiffBindingAdapter @@ -16,7 +16,7 @@ import com.xiaoyv.widget.binder.BaseQuickDiffBindingAdapter * @author why * @since 11/24/23 */ -class MediaReviewFragment : BaseListFragment() { +class MediaReviewFragment : BaseListFragment() { override val isOnlyOnePage: Boolean get() = false @@ -27,7 +27,7 @@ class MediaReviewFragment : BaseListFragment { + override fun onCreateContentAdapter(): BaseQuickDiffBindingAdapter { return MediaReviewAdapter() } diff --git a/app/src/main/java/com/xiaoyv/bangumi/ui/media/detail/review/MediaReviewViewModel.kt b/app/src/main/java/com/xiaoyv/bangumi/ui/media/detail/review/MediaReviewViewModel.kt index 2c60d6a6..264b728c 100644 --- a/app/src/main/java/com/xiaoyv/bangumi/ui/media/detail/review/MediaReviewViewModel.kt +++ b/app/src/main/java/com/xiaoyv/bangumi/ui/media/detail/review/MediaReviewViewModel.kt @@ -2,8 +2,8 @@ package com.xiaoyv.bangumi.ui.media.detail.review import com.xiaoyv.bangumi.base.BaseListViewModel import com.xiaoyv.common.api.BgmApiManager -import com.xiaoyv.common.api.parser.entity.MediaReviewEntity -import com.xiaoyv.common.api.parser.impl.parserMediaReviews +import com.xiaoyv.common.api.parser.entity.MediaReviewBlogEntity +import com.xiaoyv.common.api.parser.impl.parserMediaBlog import com.xiaoyv.common.config.annotation.MediaDetailType /** @@ -12,18 +12,18 @@ import com.xiaoyv.common.config.annotation.MediaDetailType * @author why * @since 11/24/23 */ -class MediaReviewViewModel : BaseListViewModel() { +class MediaReviewViewModel : BaseListViewModel() { /** * 媒体ID */ internal var mediaId: String = "" - override suspend fun onRequestListImpl(): List { + override suspend fun onRequestListImpl(): List { require(mediaId.isNotBlank()) { "媒体ID不存在" } return BgmApiManager.bgmWebApi.queryMediaDetail( mediaId = mediaId, type = MediaDetailType.TYPE_REVIEW, page = current - ).parserMediaReviews() + ).parserMediaBlog() } } \ No newline at end of file diff --git a/app/src/main/java/com/xiaoyv/bangumi/ui/timeline/page/TimelinePageFragment.kt b/app/src/main/java/com/xiaoyv/bangumi/ui/timeline/page/TimelinePageFragment.kt index 30299f4b..97836ca3 100644 --- a/app/src/main/java/com/xiaoyv/bangumi/ui/timeline/page/TimelinePageFragment.kt +++ b/app/src/main/java/com/xiaoyv/bangumi/ui/timeline/page/TimelinePageFragment.kt @@ -32,6 +32,9 @@ class TimelinePageFragment : BaseListFragment { return TimelinePageAdapter { diff --git a/app/src/main/java/com/xiaoyv/bangumi/ui/timeline/page/TimelinePageViewModel.kt b/app/src/main/java/com/xiaoyv/bangumi/ui/timeline/page/TimelinePageViewModel.kt index 47367f38..8ace1dfd 100644 --- a/app/src/main/java/com/xiaoyv/bangumi/ui/timeline/page/TimelinePageViewModel.kt +++ b/app/src/main/java/com/xiaoyv/bangumi/ui/timeline/page/TimelinePageViewModel.kt @@ -27,7 +27,7 @@ class TimelinePageViewModel : BaseListViewModel() { /** * 是否指定了用户 ID */ - private val userId: String + internal val userId: String get() = timelineTab?.userId.orEmpty() private val timelineType: String diff --git a/app/src/main/res/layout/fragment_media_chapter_item.xml b/app/src/main/res/layout/fragment_media_chapter_item.xml index 461f5160..d276cc7d 100644 --- a/app/src/main/res/layout/fragment_media_chapter_item.xml +++ b/app/src/main/res/layout/fragment_media_chapter_item.xml @@ -31,6 +31,7 @@ android:paddingHorizontal="@dimen/ui_layout_margin" android:paddingVertical="@dimen/ui_size_6" android:textAppearance="?attr/textAppearanceBodySmall" + android:textColor="?attr/colorOnSurface" app:layout_constraintTop_toBottomOf="@+id/title_native" tools:text="@tools:sample/lorem" /> @@ -52,7 +53,7 @@ android:id="@+id/tv_time" android:layout_width="@dimen/ui_size_0" android:layout_height="wrap_content" - android:layout_marginHorizontal="@dimen/ui_layout_margin" + android:layout_marginStart="@dimen/ui_layout_margin" android:layout_marginBottom="@dimen/ui_size_10" android:paddingVertical="@dimen/ui_size_6" android:textAppearance="?attr/textAppearanceLabelMedium" @@ -67,10 +68,15 @@ android:id="@+id/tv_comment" android:layout_width="wrap_content" android:layout_height="wrap_content" - android:paddingHorizontal="@dimen/ui_layout_margin" + android:drawablePadding="@dimen/ui_size_4" + android:gravity="center" android:paddingVertical="@dimen/ui_layout_margin" + android:paddingStart="@dimen/ui_size_12" + android:paddingEnd="@dimen/ui_layout_margin" android:textAppearance="?attr/textAppearanceLabelSmall" - android:textColor="?attr/colorPrimary" + android:textColor="?attr/colorOnSurface" + app:drawableStartCompat="@drawable/ic_comment_count" + app:drawableTint="?attr/colorOnSurfaceVariant" app:layout_constraintBaseline_toBaselineOf="@+id/tv_time" app:layout_constraintEnd_toEndOf="parent" app:layout_constraintStart_toEndOf="@+id/tv_time" diff --git a/lib-common/src/main/java/com/xiaoyv/common/api/parser/entity/MediaDetailEntity.kt b/lib-common/src/main/java/com/xiaoyv/common/api/parser/entity/MediaDetailEntity.kt index fdd18069..1a0cae13 100644 --- a/lib-common/src/main/java/com/xiaoyv/common/api/parser/entity/MediaDetailEntity.kt +++ b/lib-common/src/main/java/com/xiaoyv/common/api/parser/entity/MediaDetailEntity.kt @@ -48,7 +48,7 @@ data class MediaDetailEntity( @SerializedName("characters") var characters: List = emptyList(), @SerializedName("relativeMedia") var relativeMedia: List = emptyList(), @SerializedName("sameLikes") var sameLikes: List = emptyList(), - @SerializedName("reviews") var reviews: List = emptyList(), + @SerializedName("reviews") var reviews: List = emptyList(), @SerializedName("boards") var boards: List = emptyList(), @SerializedName("comments") var comments: List = emptyList(), @SerializedName("rating") var rating: MediaRating = MediaRating(), diff --git a/lib-common/src/main/java/com/xiaoyv/common/api/parser/entity/MediaReviewEntity.kt b/lib-common/src/main/java/com/xiaoyv/common/api/parser/entity/MediaReviewBlogEntity.kt similarity index 86% rename from lib-common/src/main/java/com/xiaoyv/common/api/parser/entity/MediaReviewEntity.kt rename to lib-common/src/main/java/com/xiaoyv/common/api/parser/entity/MediaReviewBlogEntity.kt index 65290678..da377047 100644 --- a/lib-common/src/main/java/com/xiaoyv/common/api/parser/entity/MediaReviewEntity.kt +++ b/lib-common/src/main/java/com/xiaoyv/common/api/parser/entity/MediaReviewBlogEntity.kt @@ -5,14 +5,14 @@ import androidx.annotation.Keep import kotlinx.parcelize.Parcelize /** - * Class: [MediaReviewEntity] + * Class: [MediaReviewBlogEntity] * * @author why * @since 11/29/23 */ @Parcelize @Keep -data class MediaReviewEntity( +data class MediaReviewBlogEntity( var id: String = "", var title: String = "", var avatar: String = "", diff --git a/lib-common/src/main/java/com/xiaoyv/common/api/parser/entity/UserDetailEntity.kt b/lib-common/src/main/java/com/xiaoyv/common/api/parser/entity/UserDetailEntity.kt index 1aabae90..2a078636 100644 --- a/lib-common/src/main/java/com/xiaoyv/common/api/parser/entity/UserDetailEntity.kt +++ b/lib-common/src/main/java/com/xiaoyv/common/api/parser/entity/UserDetailEntity.kt @@ -24,7 +24,7 @@ data class UserDetailEntity( var book: SaveOverview = SaveOverview(), var music: SaveOverview = SaveOverview(), var real: SaveOverview = SaveOverview(), - var blog: List = emptyList(), + var blog: List = emptyList(), ) { data class SaveOverview( var isEmpty: Boolean = true, diff --git a/lib-common/src/main/java/com/xiaoyv/common/api/parser/impl/MediaDetailParser.kt b/lib-common/src/main/java/com/xiaoyv/common/api/parser/impl/MediaDetailParser.kt index cdc588c5..b0aa3ab2 100644 --- a/lib-common/src/main/java/com/xiaoyv/common/api/parser/impl/MediaDetailParser.kt +++ b/lib-common/src/main/java/com/xiaoyv/common/api/parser/impl/MediaDetailParser.kt @@ -9,7 +9,7 @@ import com.xiaoyv.common.api.parser.entity.MediaCollectForm import com.xiaoyv.common.api.parser.entity.MediaCommentEntity import com.xiaoyv.common.api.parser.entity.MediaDetailEntity import com.xiaoyv.common.api.parser.entity.MediaMakerEntity -import com.xiaoyv.common.api.parser.entity.MediaReviewEntity +import com.xiaoyv.common.api.parser.entity.MediaReviewBlogEntity import com.xiaoyv.common.api.parser.fetchStyleBackgroundUrl import com.xiaoyv.common.api.parser.firsTextNode import com.xiaoyv.common.api.parser.hrefId @@ -30,26 +30,25 @@ import org.jsoup.nodes.Document import org.jsoup.nodes.Element /** - * @author why - * @since 11/29/23 + * 解析媒体的章节页面数据 */ fun Document.parserMediaChapters(mediaId: String): List { requireNoError() val elements = select(".line_detail > ul > li") val items = arrayListOf() - elements.forEachIndexed { index, it -> - if (index == elements.size - 1 && it.select("input").isNotEmpty()) { + elements.forEachIndexed { index, item -> + if (index == elements.size - 1 && item.select("input").isNotEmpty()) { return@forEachIndexed } - if (it.text() == "本篇") return@forEachIndexed + if (item.text() == "本篇") return@forEachIndexed // 分隔符 - if (it.select("h6").isEmpty()) { + if (item.select("h6").isEmpty()) { items.add( MediaChapterEntity( splitter = true, - id = it.text(), - number = it.text() + id = item.text(), + number = item.text() .replace("特别篇", "SP") .replace("预告/宣传/广告", "TPA") ) @@ -59,29 +58,29 @@ fun Document.parserMediaChapters(mediaId: String): List { val entity = MediaChapterEntity() entity.mediaId = mediaId - entity.id = it.select("h6 a").hrefId() - entity.titleCn = it.select("h6 .tip").text().substringAfterLast("/").trim() - entity.titleNative = it.select("h6 a").text() + entity.id = item.select("h6 a").hrefId() + entity.titleCn = item.select("h6 .tip").text().substringAfterLast("/").trim() + entity.titleNative = item.select("h6 a").text() val (number, type) = parserEpNumber(entity.titleNative) entity.number = number entity.epType = type - entity.isAired = it.select(".Air").isNotEmpty() - entity.isAiring = it.select(".Today").isNotEmpty() - entity.airedStateText = it.select(".epAirStatus").attr("title") + entity.isAired = item.select(".Air").isNotEmpty() + entity.isAiring = item.select(".Today").isNotEmpty() + entity.airedStateText = item.select(".epAirStatus").attr("title") when { - it.select(".statusWatched").isNotEmpty() -> { + item.select(".statusWatched").isNotEmpty() -> { entity.collectType = InterestType.TYPE_COLLECT - entity.collectStateText = it.select(".statusWatched").text() + entity.collectStateText = item.select(".statusWatched").text() } - it.select(".statusQueue").isNotEmpty() -> { + item.select(".statusQueue").isNotEmpty() -> { entity.collectType = InterestType.TYPE_WISH - entity.collectStateText = it.select(".statusQueue").text() + entity.collectStateText = item.select(".statusQueue").text() } - it.select(".statusDrop").isNotEmpty() -> { + item.select(".statusDrop").isNotEmpty() -> { entity.collectType = InterestType.TYPE_DROPPED - entity.collectStateText = it.select(".statusDrop").text() + entity.collectStateText = item.select(".statusDrop").text() } else -> { @@ -89,11 +88,19 @@ fun Document.parserMediaChapters(mediaId: String): List { } } - useNotNull(it.select("small")) { - entity.time = getOrNull(0)?.text().orEmpty() - .replace("时长:", "时长:") - .replace("首播:", "首播:") - entity.commentCount = getOrNull(1)?.text().orEmpty().parseCount() + item.select("small").apply { + // 动画或三次元的章节 + if (size > 1) { + entity.time = getOrNull(0)?.text().orEmpty() + .replace("时长:", "时长:") + .replace("首播:", "首播:") + entity.commentCount = getOrNull(1)?.text().orEmpty().parseCount() + } + // 音乐的曲目 + else { + entity.time = "" + entity.commentCount = firstOrNull()?.text().orEmpty().parseCount() + } } items.add(entity) @@ -101,6 +108,9 @@ fun Document.parserMediaChapters(mediaId: String): List { return items } +/** + * 解析媒体底部吐槽评论 + */ fun Element.parserMediaComments(): List { requireNoError() @@ -121,11 +131,14 @@ fun Element.parserMediaComments(): List { } } -fun Element.parserMediaReviews(): List { +/** + * 解析媒体的评论日志 + */ +fun Element.parserMediaBlog(): List { requireNoError() return select("#entry_list > .item").map { item -> - val entity = MediaReviewEntity() + val entity = MediaReviewBlogEntity() item.select(".entry .title").apply { entity.id = select("a").hrefId() entity.title = text() @@ -144,6 +157,9 @@ fun Element.parserMediaReviews(): List { } } +/** + * 解析媒体的话题讨论板 + */ fun Document.parserMediaBoards(): List { requireNoError() @@ -163,7 +179,9 @@ fun Document.parserMediaBoards(): List { }.filterNotNull() } - +/** + * 解析媒体的制作者 + */ fun Document.parserMediaMakers(): List { requireNoError() @@ -180,6 +198,9 @@ fun Document.parserMediaMakers(): List { } } +/** + * 解析媒体的角色 + */ fun Document.parserMediaCharacters(): List { requireNoError() @@ -204,7 +225,9 @@ fun Document.parserMediaCharacters(): List { } } - +/** + * 解析媒体详情 + */ fun Document.parserMediaDetail(): MediaDetailEntity { requireNoError() @@ -421,7 +444,7 @@ fun Document.parserMediaDetail(): MediaDetailEntity { rating } - entity.reviews = parserMediaReviews() + entity.reviews = parserMediaBlog() entity.boards = parserMediaBoards() entity.comments = parserMediaComments() return entity diff --git a/lib-common/src/main/java/com/xiaoyv/common/api/parser/impl/UserParser.kt b/lib-common/src/main/java/com/xiaoyv/common/api/parser/impl/UserParser.kt index 80804f0d..6ed38e2e 100644 --- a/lib-common/src/main/java/com/xiaoyv/common/api/parser/impl/UserParser.kt +++ b/lib-common/src/main/java/com/xiaoyv/common/api/parser/impl/UserParser.kt @@ -65,7 +65,7 @@ fun Document.parserUserInfo(userId: String): UserDetailEntity { entity.music = select("#music").parserUserSaveOverview(MediaType.TYPE_MUSIC) entity.game = select("#game").parserUserSaveOverview(MediaType.TYPE_GAME) entity.real = select("#real").parserUserSaveOverview(MediaType.TYPE_REAL) - entity.blog = select("#blog").firstOrNull()?.parserMediaReviews().orEmpty() + entity.blog = select("#blog").firstOrNull()?.parserMediaBlog().orEmpty() } entity.lastOnlineTime = select("#pinnedLayout .timeline > li") diff --git a/lib-common/src/main/res/drawable/ic_comment_count.xml b/lib-common/src/main/res/drawable/ic_comment_count.xml new file mode 100644 index 00000000..91be8fa7 --- /dev/null +++ b/lib-common/src/main/res/drawable/ic_comment_count.xml @@ -0,0 +1,9 @@ + + +