Skip to content

Commit

Permalink
[修复] 首页头图不显示
Browse files Browse the repository at this point in the history
[新增] 可选择年月或月
[新增] 订阅功能
  • Loading branch information
YenalyLiew committed Aug 18, 2024
1 parent cbf829f commit ae7830e
Show file tree
Hide file tree
Showing 28 changed files with 505 additions and 44 deletions.
2 changes: 1 addition & 1 deletion .idea/gradle.xml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

5 changes: 4 additions & 1 deletion .idea/kotlinc.xml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions .idea/misc.xml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

5 changes: 5 additions & 0 deletions .idea/vcs.xml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions app/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -145,6 +145,7 @@ dependencies {
implementation(libs.about)
implementation(libs.statelayout)
implementation(libs.circular.reveal.switch)
implementation(libs.asynclayoutinflater)

ksp(libs.room.compiler)

Expand Down
23 changes: 23 additions & 0 deletions app/src/main/java/com/yenaly/han1meviewer/logic/NetworkRepo.kt
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@ object NetworkRepo {
action = Parse::homePageVer2
)

@Suppress("DEPRECATION")
fun getHanimeSearchTags() = websiteIOFlow(
request = { HanimeNetwork.hanimeService.getHanimeSearchResult() },
action = Parse::hanimeSearchTags
Expand Down Expand Up @@ -288,6 +289,28 @@ object NetworkRepo {

//</editor-fold>

//<editor-fold desc="Subscription">

fun subscribeArtist(
csrfToken: String?,
userId: String,
artistId: String,
// 这里表示目标状态
status: Boolean,
) = websiteIOFlow(
request = {
HanimeNetwork.subscriptionService.subscribeArtist(
csrfToken, userId, artistId,
if (status) "" else "1"
)
}
) {
Log.d("subscribe_artist_body", it)
return@websiteIOFlow WebsiteState.Success(status)
}

//</editor-fold>

//<editor-fold desc="Base">

fun getLatestVersion(forceCheck: Boolean = true) = flow {
Expand Down
32 changes: 29 additions & 3 deletions app/src/main/java/com/yenaly/han1meviewer/logic/Parse.kt
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ import com.yenaly.han1meviewer.toVideoCode
import kotlinx.datetime.LocalDate
import org.json.JSONObject
import org.jsoup.Jsoup
import org.jsoup.nodes.Comment
import org.jsoup.nodes.Element
import org.jsoup.select.Elements

Expand Down Expand Up @@ -59,10 +60,21 @@ object Parse {
val bannerPic = bannerImg?.select("img")?.getOrNull(1)?.absUrl("src")
.logIfParseNull(Parse::homePageVer2.name, "bannerPic")
val bannerDesc = bannerCSS?.selectFirst("h4")?.ownText()
val bannerVideoCode =
var bannerVideoCode =
bannerCSS?.selectFirst("a[class~=play-btn]")?.absUrl("href")?.toVideoCode()
.logIfParseNull(Parse::homePageVer2.name, "bannerVideoCode")
val banner = if (bannerTitle != null && bannerPic != null && bannerVideoCode != null) {
// 目前先判断注释里的,以后可能会有变化
if (bannerVideoCode == null) {
bannerCSS?.traverse { node, _ ->
if (node is Comment) {
node.data.toVideoCode()?.let {
bannerVideoCode = it
return@traverse
}
}
}
}
bannerVideoCode.logIfParseNull(Parse::homePageVer2.name, "bannerVideoCode")
val banner = if (bannerTitle != null && bannerPic != null) {
HomePage.Banner(
title = bannerTitle, description = bannerDesc,
picUrl = bannerPic, videoCode = bannerVideoCode,
Expand Down Expand Up @@ -500,11 +512,25 @@ object Parse {
val artistNameCSS = parseBody.getElementById("video-artist-name")
val artistGenre = artistNameCSS?.nextElementSibling()?.text()?.trim()
val artistName = artistNameCSS?.text()?.trim()
val postCSS = parseBody.getElementById("video-subscribe-form")
val post = postCSS?.let {
val userId = it.selectFirst("input[name=subscribe-user-id]")?.attr("value")
val artistId = it.selectFirst("input[name=subscribe-artist-id]")?.attr("value")
val isSubscribed = it.selectFirst("input[name=subscribe-status]")?.attr("value")
if (userId != null && artistId != null && isSubscribed != null) {
HanimeVideo.Artist.POST(
userId = userId,
artistId = artistId,
isSubscribed = isSubscribed == "1"
)
} else null
}
val artist = if (artistAvatarUrl != null && artistName != null && artistGenre != null) {
HanimeVideo.Artist(
name = artistName,
avatarUrl = artistAvatarUrl,
genre = artistGenre,
post = post,
)
} else null

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -70,5 +70,14 @@ data class HanimeVideo(
val name: String,
val avatarUrl: String,
val genre: String,
)
val post: POST?,
) {
val isSubscribed: Boolean get() = post != null && post.isSubscribed

data class POST(
val userId: String,
val artistId: String,
val isSubscribed: Boolean,
)
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,8 @@ data class HomePage(
val title: String,
val description: String?,
val picUrl: String,
val videoCode: String,
// 目前网站的策略是,先你吗加载广告,然后再让你跳转
// 我不敢保证他会把 videoCode 放在哪里,所以暂时可以为空
val videoCode: String?,
)
}
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import com.yenaly.han1meviewer.logic.network.service.HGitHubService
import com.yenaly.han1meviewer.logic.network.service.HanimeBaseService
import com.yenaly.han1meviewer.logic.network.service.HanimeCommentService
import com.yenaly.han1meviewer.logic.network.service.HanimeMyListService
import com.yenaly.han1meviewer.logic.network.service.HanimeSubscriptionService

/**
* @project Hanime1
Expand All @@ -20,14 +21,23 @@ object HanimeNetwork {
private set
var myListService = _myListService
private set
var subscriptionService = _subscriptionService
private set

private val _hanimeService
get() = ServiceCreator.create<HanimeBaseService>(HANIME_BASE_URL)

private val _hanimeService get() = ServiceCreator.create<HanimeBaseService>(HANIME_BASE_URL)
private val _githubService
get() = ServiceCreator.createGitHubApi<HGitHubService>()

private val _githubService get() = ServiceCreator.createGitHubApi<HGitHubService>()
private val _commentService
get() = ServiceCreator.create<HanimeCommentService>(HANIME_BASE_URL)

private val _commentService get() = ServiceCreator.create<HanimeCommentService>(HANIME_BASE_URL)
private val _myListService
get() = ServiceCreator.create<HanimeMyListService>(HANIME_BASE_URL)

private val _myListService get() = ServiceCreator.create<HanimeMyListService>(HANIME_BASE_URL)
private val _subscriptionService
get() = ServiceCreator.create<HanimeSubscriptionService>(HANIME_BASE_URL)

fun rebuildNetwork() {
ServiceCreator.rebuildOkHttpClient()
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
package com.yenaly.han1meviewer.logic.network.service

import okhttp3.ResponseBody
import retrofit2.Response
import retrofit2.http.Field
import retrofit2.http.FormUrlEncoded
import retrofit2.http.Header
import retrofit2.http.POST

interface HanimeSubscriptionService {

@FormUrlEncoded
@POST("subscribe")
suspend fun subscribeArtist(
@Field("_token") csrfToken: String?,
@Field("subscribe-user-id") userId: String,
@Field("subscribe-artist-id") artistId: String,
// 如果当前未订阅会发送空字符串,否则发1
@Field("subscribe-status") status: String,
@Header("X-CSRF-TOKEN") csrfToken_1: String? = csrfToken,
): Response<ResponseBody>
}
Original file line number Diff line number Diff line change
Expand Up @@ -235,8 +235,11 @@ class HomePageFragment : YenalyFragment<FragmentHomePageBinding, MainViewModel>(
}
)
}
binding.btnBanner.isEnabled = banner.videoCode != null
binding.btnBanner.setOnClickListener {
requireActivity().startActivity<VideoActivity>(VIDEO_CODE to banner.videoCode)
banner.videoCode?.let { videoCode ->
requireActivity().startActivity<VideoActivity>(VIDEO_CODE to videoCode)
}
}
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -83,6 +83,7 @@ class VideoIntroductionFragment :
companion object {
private const val FAV = 1
private const val PLAYLIST = 1 shl 1
private const val SUBSCRIBE = 1 shl 2

val COMPARATOR = object : DiffUtil.ItemCallback<HanimeVideo>() {
override fun areItemsTheSame(oldItem: HanimeVideo, newItem: HanimeVideo): Boolean {
Expand All @@ -99,6 +100,8 @@ class VideoIntroductionFragment :
bitset = bitset or FAV
if (!(oldItem.myList?.isSelectedArray contentEquals newItem.myList?.isSelectedArray))
bitset = bitset or PLAYLIST
if (oldItem.artist?.isSubscribed != newItem.artist?.isSubscribed)
bitset = bitset or SUBSCRIBE
return bitset
}
}
Expand Down Expand Up @@ -242,6 +245,25 @@ class VideoIntroductionFragment :
}
}
}

viewLifecycleOwner.lifecycleScope.launch {
viewModel.subscribeArtistFlow.collect { state ->
when (state) {
is WebsiteState.Error -> {
showShortToast(R.string.subscribe_failed)
}

is WebsiteState.Loading -> Unit
is WebsiteState.Success -> {
if (state.info) {
showShortToast(R.string.subscribe_success)
} else {
showShortToast(R.string.unsubscribe_success)
}
}
}
}
}
}

private fun notifyDownload(title: String, quality: String, action: () -> Unit) {
Expand Down Expand Up @@ -384,6 +406,9 @@ class VideoIntroductionFragment :
if (bitset and FAV != 0) {
holder.binding.handleFavButton(item.isFav)
}
if (bitset and SUBSCRIBE != 0) {
holder.binding.initArtist(item.artist)
}
}

override fun onCreateViewHolder(
Expand Down Expand Up @@ -443,6 +468,38 @@ class VideoIntroductionFragment :
crossfade(true)
transformations(CircleCropTransformation())
}
btnSubscribe.isVisible = artist.post != null
if (btnSubscribe.isVisible && artist.post != null) {
btnSubscribe.text = if (artist.isSubscribed) {
getString(R.string.subscribed)
} else {
getString(R.string.subscribe)
}
btnSubscribe.clickTrigger(viewLifecycleOwner.lifecycle) {
if (isAlreadyLogin) {
if (artist.isSubscribed) {
context.showAlertDialog {
setTitle(R.string.unsubscribe_artist)
setMessage(R.string.sure_to_unsubscribe)
setPositiveButton(R.string.sure) { _, _ ->
viewModel.unsubscribeArtist(
artist.post.userId,
artist.post.artistId
)
}
setNegativeButton(R.string.no, null)
}
} else {
viewModel.subscribeArtist(
artist.post.userId,
artist.post.artistId
)
}
} else {
showShortToast(R.string.login_first)
}
}
}
}
}

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
package com.yenaly.han1meviewer.ui.popup

import android.content.Context
import com.google.android.material.button.MaterialButton
import com.lxj.xpopupext.popup.TimePickerPopup
import com.yenaly.han1meviewer.R

/**
* #issue-161: 高级搜索可以选择年或年月
*/
class HTimePickerPopup(context: Context) : TimePickerPopup(context) {

private lateinit var btnSwitch: MaterialButton

var mode: Mode = Mode.YM
private set

override fun getImplLayoutId(): Int = R.layout.pop_up_ext_h_time_picker

override fun onCreate() {
super.onCreate()
btnSwitch = findViewById(R.id.btnSwitch)
btnSwitch.text = when (mode) {
Mode.YM -> context.getString(R.string.switch_to_year)
else -> context.getString(R.string.switch_to_year_month)
}
btnSwitch.setOnClickListener {
when (mode) {
Mode.YM -> setMode(Mode.Y)
else -> setMode(Mode.YM)
}
onCreate()
}
}

override fun setMode(mode: Mode): TimePickerPopup {
this.mode = mode
return super.setMode(mode)
}
}
Loading

0 comments on commit ae7830e

Please sign in to comment.