Skip to content
This repository was archived by the owner on Jul 18, 2026. It is now read-only.

Commit abdeb20

Browse files
authored
修复一些问题
修复: 1、播放页系列影片间隔过大的问题; 2、从详情页跳转到其他页 面再返回页面闪烁、内容被刷新的问题; 3、头图推荐进入播放页后项目无法点击的问题; 4、已下载的视频点击播放器返回按钮、主页按钮崩溃的问题;
2 parents bacb7a4 + fbdc56c commit abdeb20

9 files changed

Lines changed: 119 additions & 56 deletions

File tree

README.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
# <font color='red'>🚫请不要在任何公开平台宣传本软件,本软件不接受任何形式的公开宣传,否则仓库主将随时归档隐藏该仓库并删除已编译的发行版🚫</font>
2+
# 本应用没有任何官方网站,仅Github Release、CI持续构建产物为唯一下载及更新渠道
23
# Han1meViewer
34
🔞R18警告,未满18岁禁止下载使用!\
45
Han1meViewer 是一个基于 Kotlin 开发的 Android 应用,用于播放和浏览 hanime 视频资源,支持双栏与单栏布局切换、ExoPlayer 自定义播放内核、系列视频导航、播放列表和推荐内容展示等功能。

app/src/main/java/com/yenaly/han1meviewer/ui/adapter/HanimeVideoRvAdapter.kt

Lines changed: 28 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -21,9 +21,9 @@ import com.yenaly.han1meviewer.getHanimeShareText
2121
import com.yenaly.han1meviewer.logic.model.HanimeInfo
2222
import com.yenaly.han1meviewer.ui.activity.MainActivity
2323
import com.yenaly.han1meviewer.ui.activity.PreviewActivity
24-
import com.yenaly.han1meviewer.ui.activity.SearchActivity
25-
import com.yenaly.han1meviewer.ui.activity.VideoActivity
2624
import com.yenaly.han1meviewer.ui.fragment.home.HomePageFragment
25+
import com.yenaly.han1meviewer.ui.fragment.search.SearchFragment
26+
import com.yenaly.han1meviewer.ui.fragment.video.VideoFragment
2727
import com.yenaly.yenaly_libs.utils.copyTextToClipboard
2828
import com.yenaly.yenaly_libs.utils.dp
2929
import com.yenaly.yenaly_libs.utils.requireActivity
@@ -133,38 +133,39 @@ class HanimeVideoRvAdapter(private val videoWidthType: Int = -1) : // videoWidth
133133
when (viewType) {
134134
HanimeInfo.SIMPLIFIED -> {
135135
when (context) {
136-
is SearchActivity -> {
137-
viewHolder.getView<View>(R.id.frame).widthMatchParent()
138-
}
139-
140-
is VideoActivity -> when (videoWidthType) {
141-
VIDEO_LAYOUT_MATCH_PARENT ->
142-
viewHolder.getView<View>(R.id.frame).widthMatchParent()
143-
144-
VIDEO_LAYOUT_WRAP_CONTENT ->
145-
viewHolder.getView<View>(R.id.frame).widthWrapContent()
136+
is MainActivity -> {
137+
val fragment = context.currentFragment
138+
when (fragment) {
139+
is SearchFragment -> {
140+
viewHolder.getView<View>(R.id.frame).widthMatchParent()
141+
}
142+
143+
is VideoFragment -> when (videoWidthType) {
144+
VIDEO_LAYOUT_MATCH_PARENT ->
145+
viewHolder.getView<View>(R.id.frame).widthMatchParent()
146+
VIDEO_LAYOUT_WRAP_CONTENT ->
147+
viewHolder.getView<View>(R.id.frame).widthWrapContent()
148+
}
149+
}
146150
}
147151
}
148-
with(VideoCoverSize.Simplified) {
149-
viewHolder.getView<ViewGroup>(R.id.cover_wrapper).resizeForVideoCover()
150-
}
152+
151153
}
152154

153155
HanimeInfo.NORMAL -> {
154156
when (context) {
155-
is VideoActivity -> when (videoWidthType) {
156-
VIDEO_LAYOUT_MATCH_PARENT ->
157-
viewHolder.getView<View>(R.id.frame).widthMatchParent()
158-
159-
VIDEO_LAYOUT_WRAP_CONTENT ->
160-
viewHolder.getView<View>(R.id.frame).widthWrapContent()
161-
}
162-
163157
is MainActivity -> {
164-
val activity = context
165-
val fragment = activity.currentFragment
166-
if (fragment is HomePageFragment) {
167-
viewHolder.getView<View>(R.id.frame).widthWrapContent()
158+
val fragment = context.currentFragment
159+
when (fragment) {
160+
is VideoFragment -> when (videoWidthType) {
161+
VIDEO_LAYOUT_MATCH_PARENT ->
162+
viewHolder.getView<View>(R.id.frame).widthMatchParent()
163+
VIDEO_LAYOUT_WRAP_CONTENT ->
164+
viewHolder.getView<View>(R.id.frame).widthWrapContent()
165+
}
166+
is HomePageFragment -> {
167+
viewHolder.getView<View>(R.id.frame).widthWrapContent()
168+
}
168169
}
169170
}
170171
}

app/src/main/java/com/yenaly/han1meviewer/ui/fragment/home/HomePageFragment.kt

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -37,15 +37,13 @@ import com.google.android.material.dialog.MaterialAlertDialogBuilder
3737
import com.yenaly.han1meviewer.ADVANCED_SEARCH_MAP
3838
import com.yenaly.han1meviewer.HAdvancedSearch
3939
import com.yenaly.han1meviewer.R
40-
import com.yenaly.han1meviewer.VIDEO_CODE
4140
import com.yenaly.han1meviewer.advancedSearchMapOf
4241
import com.yenaly.han1meviewer.databinding.FragmentHomePageBinding
4342
import com.yenaly.han1meviewer.logic.model.HomePage
4443
import com.yenaly.han1meviewer.logic.state.WebsiteState
4544
import com.yenaly.han1meviewer.ui.StateLayoutMixin
4645
import com.yenaly.han1meviewer.ui.activity.MainActivity
4746
import com.yenaly.han1meviewer.ui.activity.PreviewActivity
48-
import com.yenaly.han1meviewer.ui.activity.VideoActivity
4947
import com.yenaly.han1meviewer.ui.adapter.HanimeVideoRvAdapter
5048
import com.yenaly.han1meviewer.ui.adapter.RvWrapper.Companion.wrappedWith
5149
import com.yenaly.han1meviewer.ui.adapter.VideoColumnTitleAdapter
@@ -287,7 +285,7 @@ class HomePageFragment : YenalyFragment<FragmentHomePageBinding>(),
287285
binding.btnBanner.isEnabled = banner.videoCode != null
288286
binding.btnBanner.setOnClickListener {
289287
banner.videoCode?.let { videoCode ->
290-
requireActivity().startActivity<VideoActivity>(VIDEO_CODE to videoCode)
288+
(requireActivity() as? MainActivity)?.showVideoDetailFragment(videoCode)
291289
}
292290
}
293291
}

app/src/main/java/com/yenaly/han1meviewer/ui/fragment/search/SearchFragment.kt

Lines changed: 10 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ import androidx.lifecycle.Lifecycle
1919
import androidx.lifecycle.flowWithLifecycle
2020
import androidx.lifecycle.lifecycleScope
2121
import androidx.lifecycle.repeatOnLifecycle
22-
import androidx.navigation.findNavController
22+
import androidx.navigation.fragment.findNavController
2323
import androidx.recyclerview.widget.GridLayoutManager
2424
import androidx.recyclerview.widget.RecyclerView
2525
import com.yenaly.han1meviewer.ADVANCED_SEARCH_MAP
@@ -150,15 +150,15 @@ class SearchFragment : YenalyFragment<FragmentSearchBinding>(), StateLayoutMixin
150150
}
151151
}
152152

153-
override fun onDestroyView() {
154-
binding.searchRv.apply {
155-
adapter = null
156-
layoutManager = null
157-
clearOnScrollListeners()
158-
}
159-
super.onDestroyView()
160-
_binding?.unbind()
161-
}
153+
// override fun onDestroyView() {
154+
// binding.searchRv.apply {
155+
// adapter = null
156+
// layoutManager = null
157+
// clearOnScrollListeners()
158+
// }
159+
// super.onDestroyView()
160+
// _binding?.unbind()
161+
// }
162162

163163
@SuppressLint("SetTextI18n")
164164
override fun bindDataObservers() {

app/src/main/java/com/yenaly/han1meviewer/ui/fragment/video/VideoFragment.kt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -60,7 +60,7 @@ import kotlinx.datetime.Clock
6060

6161
class VideoFragment : YenalyFragment<FragmentVideoBinding>(), OrientationManager.OrientationChangeListener {
6262

63-
private val viewModel by viewModels<VideoViewModel>()
63+
val viewModel by viewModels<VideoViewModel>()
6464
private val commentViewModel by activityViewModels<CommentViewModel>()
6565
private val kernel = HMediaKernel.Type.fromString(Preferences.switchPlayerKernel)
6666

app/src/main/java/com/yenaly/han1meviewer/ui/fragment/video/VideoIntroductionFragment.kt

Lines changed: 44 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ import android.provider.Settings
99
import android.util.Log
1010
import android.view.LayoutInflater
1111
import android.view.MotionEvent
12+
import android.view.View
1213
import android.view.ViewGroup
1314
import android.widget.Toast
1415
import androidx.appcompat.app.AlertDialog
@@ -172,6 +173,25 @@ class VideoIntroductionFragment : YenalyFragment<FragmentVideoIntroductionBindin
172173
WindowInsetsCompat.CONSUMED
173174
}
174175
}
176+
177+
override fun onDestroyView() {
178+
super.onDestroyView()
179+
val code = viewModel.videoCode
180+
viewModel.scrollPositionMap[code] = binding.rvVideoIntro.layoutManager?.onSaveInstanceState()
181+
viewModel.videoIntroDataMap[code] = viewModel.hanimeVideoFlow.value
182+
viewModel.videoIntroRestoredSet.remove(code)
183+
}
184+
185+
186+
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
187+
super.onViewCreated(view, savedInstanceState)
188+
val code = viewModel.videoCode
189+
if (!viewModel.restoreFromCacheIfExists(code)) {
190+
viewModel.getHanimeVideo(code)
191+
}
192+
}
193+
194+
175195
private fun createLayoutManager(spanCount: Int): GridLayoutManager {
176196
return GridLayoutManager(requireContext(), spanCount).apply {
177197
spanSizeLookup = object : GridLayoutManager.SpanSizeLookup() {
@@ -197,33 +217,47 @@ class VideoIntroductionFragment : YenalyFragment<FragmentVideoIntroductionBindin
197217

198218
is VideoLoadingState.Success -> {
199219
val video = state.info
220+
val code = viewModel.videoCode
221+
222+
if (viewModel.videoIntroRestoredSet.contains(code)) return@collect
223+
val savedState = viewModel.scrollPositionMap[code]
200224
multi = ConcatAdapter()
201225
binding.rvVideoIntro.adapter = multi
202-
203-
val newSpanCount = video.relatedHanimes.eachGridCounts
204-
layoutManager = createLayoutManager(newSpanCount)
226+
layoutManager = createLayoutManager(video.relatedHanimes.eachGridCounts)
205227
binding.rvVideoIntro.layoutManager = layoutManager
206228

207229
mutex.withLock {
208-
videoIntroAdapter.submit(video) // 挂起是为了让它在首位
230+
videoIntroAdapter.submit(video)
209231
}
232+
210233
multi.addAdapter(videoIntroAdapter)
234+
val cached = viewModel.videoIntroDataMap[code]
235+
211236
if (video.playlist != null && !viewModel.fromDownload) {
212237
playlistTitleAdapter.subtitle = video.playlist.playlistName
213238
multi.addAdapter(playlistTitleAdapter)
214239
multi.addAdapter(playlistWrapper)
215-
playlistAdapter.submitList(video.playlist.video)
216-
} else {
217-
multi.removeAdapter(playlistTitleAdapter)
218-
multi.removeAdapter(playlistWrapper)
240+
if (cached?.playlist?.video != video.playlist.video) {
241+
playlistAdapter.submitList(video.playlist.video)
242+
}
219243
}
244+
220245
if (!viewModel.fromDownload) {
221246
multi.addAdapter(relatedTitleAdapter)
222247
multi.addAdapter(relatedAdapter)
223-
relatedAdapter.submitList(video.relatedHanimes)
248+
if (cached?.relatedHanimes != video.relatedHanimes) {
249+
relatedAdapter.submitList(video.relatedHanimes)
250+
}
224251
}
225-
}
226252

253+
viewModel.videoIntroDataMap[code] = video
254+
viewModel.videoIntroRestoredSet.add(code)
255+
savedState?.let { state ->
256+
binding.rvVideoIntro.post {
257+
binding.rvVideoIntro.layoutManager?.onRestoreInstanceState(state)
258+
}
259+
}
260+
}
227261
is VideoLoadingState.NoContent -> Unit
228262
}
229263
}

app/src/main/java/com/yenaly/han1meviewer/ui/view/video/HJzvdStd.kt

Lines changed: 15 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -42,12 +42,14 @@ import com.yenaly.han1meviewer.Preferences
4242
import com.yenaly.han1meviewer.R
4343
import com.yenaly.han1meviewer.logic.entity.HKeyframeEntity
4444
import com.yenaly.han1meviewer.ui.activity.MainActivity
45+
import com.yenaly.han1meviewer.ui.activity.VideoActivity
4546
import com.yenaly.han1meviewer.ui.adapter.HKeyframeRvAdapter
4647
import com.yenaly.han1meviewer.ui.adapter.VideoSpeedAdapter
4748
import com.yenaly.han1meviewer.ui.fragment.video.VideoFragment
4849
import com.yenaly.han1meviewer.util.setStateViewLayout
4950
import com.yenaly.han1meviewer.util.showAlertDialog
5051
import com.yenaly.yenaly_libs.utils.OrientationManager
52+
import com.yenaly.yenaly_libs.utils.activity
5153
import com.yenaly.yenaly_libs.utils.appScreenWidth
5254
import com.yenaly.yenaly_libs.utils.navBarHeight
5355
import com.yenaly.yenaly_libs.utils.statusBarHeight
@@ -460,12 +462,18 @@ class HJzvdStd @JvmOverloads constructor(
460462
}
461463

462464
override fun clickBack() {
463-
Log.i("fun_clickBack", "backPressed")
465+
Log.i("fun_clickBack", "player_backBtn_clicked")
464466
if (context is MainActivity && screen == SCREEN_FULLSCREEN) {
465467
gotoNormalScreen()
466468
return
467469
}
468-
findNavController().navigateUp()
470+
if (context is VideoActivity){
471+
when(screen){
472+
SCREEN_FULLSCREEN -> gotoNormalScreen()
473+
SCREEN_NORMAL -> context.activity?.finish()
474+
}
475+
return
476+
}
469477
when {
470478
CONTAINER_LIST.isNotEmpty() && CURRENT_JZVD != null -> { //判断条件,因为当前所有goBack都是回到普通窗口
471479
CURRENT_JZVD.gotoNormalScreen()
@@ -474,8 +482,7 @@ class HJzvdStd @JvmOverloads constructor(
474482
CONTAINER_LIST.isEmpty() && CURRENT_JZVD != null && CURRENT_JZVD.screen != SCREEN_NORMAL -> { //退出直接进入的全屏
475483
CURRENT_JZVD.clearFloatScreen()
476484
}
477-
else -> { //剩餘情況直接退出
478-
//context.activity?.finish()
485+
else -> {
479486
findNavController().navigateUp()
480487
}
481488
}
@@ -488,6 +495,10 @@ class HJzvdStd @JvmOverloads constructor(
488495
R.id.tv_keyframe -> onKeyframeClickListener?.invoke(v)
489496
R.id.go_home -> {
490497
if (screen != SCREEN_FULLSCREEN) {
498+
if (context is VideoActivity){
499+
context.activity?.finish()
500+
return
501+
}
491502
findNavController().navigate(
492503
R.id.nv_home_page,
493504
null,

app/src/main/java/com/yenaly/han1meviewer/ui/viewmodel/VideoViewModel.kt

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
package com.yenaly.han1meviewer.ui.viewmodel
22

33
import android.app.Application
4+
import android.os.Parcelable
45
import android.util.Log
56
import androidx.lifecycle.viewModelScope
67
import com.yenaly.han1meviewer.EMPTY_STRING
@@ -60,7 +61,14 @@ class VideoViewModel(application: Application) : YenalyViewModel(application) {
6061
private val _hanimeVideoFlow = MutableStateFlow<HanimeVideo?>(null)
6162
val hanimeVideoFlow = _hanimeVideoFlow.asStateFlow()
6263

64+
// 保存当前 videoCode及请求数据以及对应的滚动位置
65+
val scrollPositionMap = mutableMapOf<String, Parcelable?>()
66+
val videoIntroDataMap = mutableMapOf<String, HanimeVideo?>()
67+
// 表示已经还原过的数据
68+
val videoIntroRestoredSet = mutableSetOf<String>()
69+
6370
fun getHanimeVideo(videoCode: String) {
71+
if (videoIntroRestoredSet.contains(videoCode)) return
6472
viewModelScope.launch {
6573
val flow = if (fromDownload) {
6674
HCacheManager.loadHanimeVideoInfo(application,videoCode).map { hv ->
@@ -83,6 +91,16 @@ class VideoViewModel(application: Application) : YenalyViewModel(application) {
8391
}
8492
}
8593

94+
fun restoreFromCacheIfExists(code: String): Boolean {
95+
val cached = videoIntroDataMap[code] ?: return false
96+
videoIntroRestoredSet.add(code) //
97+
_hanimeVideoFlow.value = cached
98+
_hanimeVideoStateFlow.value = VideoLoadingState.Success(cached)
99+
return true
100+
}
101+
102+
103+
86104
private val _addToFavVideoFlow = MutableSharedFlow<WebsiteState<Boolean>>()
87105
val addToFavVideoFlow = _addToFavVideoFlow.asSharedFlow()
88106

yenaly_libs/src/main/java/com/yenaly/yenaly_libs/base/YenalyFragment.kt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ import com.yenaly.yenaly_libs.base.frame.FrameFragment
1616
*/
1717
abstract class YenalyFragment<DB : ViewDataBinding> : FrameFragment(), IViewBinding<DB> {
1818

19-
var _binding: DB? = null
19+
private var _binding: DB? = null
2020
override val binding get() = _binding!!
2121
val bindingOrNull get() = _binding
2222

0 commit comments

Comments
 (0)