diff --git a/app/src/main/java/com/gh/common/history/HistoryHelper.kt b/app/src/main/java/com/gh/common/history/HistoryHelper.kt index ee3efa0e90..9c096fd90f 100644 --- a/app/src/main/java/com/gh/common/history/HistoryHelper.kt +++ b/app/src/main/java/com/gh/common/history/HistoryHelper.kt @@ -97,6 +97,11 @@ object HistoryHelper { runOnIoThread { tryCatchInRelease { HistoryDatabase.instance.videoHistoryDao().deleteVideo(MyVideoEntity().apply { id = videoId }) } } } + @JvmStatic + fun deleteAttentionVideoRecord() { + runOnIoThread { tryCatchInRelease { HistoryDatabase.instance.videoHistoryDao().deleteAttentionVideoRecord() } } + } + @JvmStatic fun emptyDatabase() { runOnIoThread { tryCatchInRelease { HistoryDatabase.instance.clearAllTables() } } diff --git a/app/src/main/java/com/gh/common/view/vertical_recycler/PagerLayoutManager.java b/app/src/main/java/com/gh/common/view/vertical_recycler/PagerLayoutManager.java index 1222868002..c7b7b197b2 100644 --- a/app/src/main/java/com/gh/common/view/vertical_recycler/PagerLayoutManager.java +++ b/app/src/main/java/com/gh/common/view/vertical_recycler/PagerLayoutManager.java @@ -120,8 +120,8 @@ public class PagerLayoutManager extends LinearLayoutManager { if (viewIdle != null) { positionIdle = getPosition(viewIdle); } - int childCount = getChildCount(); -// if (mOnViewPagerListener != null && childCount == 1) { +// int childCount = getChildCount(); + int childCount = getItemCount(); if (mOnViewPagerListener != null && positionIdle != mLastPosition) { mOnViewPagerListener.onPageSelected(positionIdle, positionIdle == childCount - 1); diff --git a/app/src/main/java/com/gh/download/cache/ExoCacheManager.kt b/app/src/main/java/com/gh/download/cache/ExoCacheManager.kt index ca9d60b012..e21f7d6f4e 100644 --- a/app/src/main/java/com/gh/download/cache/ExoCacheManager.kt +++ b/app/src/main/java/com/gh/download/cache/ExoCacheManager.kt @@ -70,9 +70,9 @@ object ExoCacheManager { if (requestLength == bytesCached) { threads.remove(videoUri) } - if (BuildConfig.DEBUG) { - Utils.log("$requestLength--$bytesCached--$newBytesCached") - } +// if (BuildConfig.DEBUG) { +// Utils.log("$requestLength--$bytesCached--$newBytesCached") +// } }, threads[videoUri]) } catch (e: Throwable) { threads.remove(videoUri) diff --git a/app/src/main/java/com/gh/gamecenter/MainActivity.java b/app/src/main/java/com/gh/gamecenter/MainActivity.java index cc6615dd77..1cc9dd5329 100644 --- a/app/src/main/java/com/gh/gamecenter/MainActivity.java +++ b/app/src/main/java/com/gh/gamecenter/MainActivity.java @@ -32,6 +32,8 @@ import com.gh.common.avoidcallback.AvoidOnResultManager; import com.gh.common.constant.Config; import com.gh.common.constant.Constants; import com.gh.common.exposure.meta.MetaUtil; +import com.gh.common.history.HistoryDatabase; +import com.gh.common.history.HistoryHelper; import com.gh.common.repository.ReservationRepository; import com.gh.common.simulator.SimulatorGameManager; import com.gh.common.util.ActivationHelper; @@ -77,6 +79,7 @@ import com.gh.gamecenter.manager.UserManager; import com.gh.gamecenter.normal.NormalFragment; import com.gh.gamecenter.packagehelper.PackageViewModel; import com.gh.gamecenter.qa.CommunityFragment; +import com.gh.gamecenter.retrofit.BiResponse; import com.gh.gamecenter.retrofit.Response; import com.gh.gamecenter.retrofit.RetrofitManager; import com.gh.gamecenter.suggest.SuggestSelectFragment; @@ -94,6 +97,7 @@ import com.lightgame.utils.Utils; import org.greenrobot.eventbus.EventBus; import org.greenrobot.eventbus.Subscribe; import org.greenrobot.eventbus.ThreadMode; +import org.jetbrains.annotations.NotNull; import org.json.JSONObject; import java.io.BufferedReader; @@ -102,14 +106,19 @@ import java.io.IOException; import java.io.InputStream; import java.io.InputStreamReader; import java.lang.reflect.Field; +import java.util.ArrayList; import java.util.Enumeration; +import java.util.HashMap; import java.util.List; +import java.util.Map; import java.util.Timer; import java.util.TimerTask; import java.util.zip.ZipEntry; import java.util.zip.ZipFile; +import io.reactivex.SingleSource; import io.reactivex.android.schedulers.AndroidSchedulers; +import io.reactivex.functions.Function; import io.reactivex.schedulers.Schedulers; import kotlin.jvm.functions.Function1; import okhttp3.MediaType; @@ -260,10 +269,11 @@ public class MainActivity extends BaseActivity { // 上传数据 DataCollectionManager.getInstance(getApplicationContext()).upload(); // 获取默认配置 + if (Config.getSettings() == null) { Config.getGhzsSettings(); } - + // 初始化PlatformUtils PlatformUtils.getInstance(getApplicationContext()); // // 友盟记录启动 @@ -288,6 +298,33 @@ public class MainActivity extends BaseActivity { SPUtils.setBoolean(Constants.SP_NON_WIFI_TIPS, true); //重置首页视频播放进度 SPUtils.setString(Constants.SP_HOME_VIDEO_PLAY_RECORD, ""); + + postAttentionVideoRecord(); + } + + //上传关注视频浏览记录 + @SuppressLint("CheckResult") + private void postAttentionVideoRecord() { + if (UserManager.getInstance().isLoggedIn()) { + Map requestMap = new HashMap<>(); + HistoryDatabase.Companion.getInstance().videoHistoryDao() + .getAttentionVideoRecord() + .flatMap((Function, SingleSource>) strings -> { + requestMap.put("cache_video_ids", strings); + RequestBody body = ExtensionsKt.toRequestBody(requestMap); + return RetrofitManager.getInstance(HaloApp.getInstance()) + .getApi() + .postAttentionVideoRecord(UserManager.getInstance().getUserId(), body); + }) + .subscribeOn(Schedulers.io()) + .subscribe(new BiResponse() { + @Override + public void onSuccess(ResponseBody data) { + HistoryHelper.deleteAttentionVideoRecord(); + } + }); + + } } @Override @@ -375,11 +412,11 @@ public class MainActivity extends BaseActivity { getIntent().putExtra(SHOW_AD, false); findViewById(R.id.maskContainer).setVisibility(View.GONE); mMainWrapperFragment.getWelcomeDialog(); - + checkDialog(); } } - + private void checkDialog() { // 检查通知权限 checkNotificationPermission(); diff --git a/app/src/main/java/com/gh/gamecenter/entity/VideoEntity.kt b/app/src/main/java/com/gh/gamecenter/entity/VideoEntity.kt index 7155761e29..66538cdba2 100644 --- a/app/src/main/java/com/gh/gamecenter/entity/VideoEntity.kt +++ b/app/src/main/java/com/gh/gamecenter/entity/VideoEntity.kt @@ -42,6 +42,8 @@ open class VideoEntity( @SerializedName("share") var shareCount: Int = 0,//分享数量 v3.7.5新增 val time: Time = Time(), + var watched: Boolean = false, + val watermark: Boolean = false, val audit: Boolean = false, val original: String = "",//是否原创 yes/no 默认为空字符串 @@ -50,7 +52,12 @@ open class VideoEntity( val tagActivityName: String = "", @SerializedName("tag_activity_id") var tagActivityId: String = "",//活动标签的id, 当 original=true - var videoIsMuted: Boolean = false//是否静音标记 + + //本地数据 + @IgnoredOnParcel + var videoIsMuted: Boolean = false,//是否静音标记 + @IgnoredOnParcel + var isFirstBind: Boolean = false ) : Parcelable { @IgnoredOnParcel diff --git a/app/src/main/java/com/gh/gamecenter/eventbus/EBRecommed.java b/app/src/main/java/com/gh/gamecenter/eventbus/EBRecommed.java new file mode 100644 index 0000000000..a305da3f5c --- /dev/null +++ b/app/src/main/java/com/gh/gamecenter/eventbus/EBRecommed.java @@ -0,0 +1,4 @@ +package com.gh.gamecenter.eventbus; + +public class EBRecommed { +} diff --git a/app/src/main/java/com/gh/gamecenter/retrofit/service/ApiService.java b/app/src/main/java/com/gh/gamecenter/retrofit/service/ApiService.java index 2a8988b727..fa64bc03d0 100644 --- a/app/src/main/java/com/gh/gamecenter/retrofit/service/ApiService.java +++ b/app/src/main/java/com/gh/gamecenter/retrofit/service/ApiService.java @@ -1992,11 +1992,24 @@ public interface ApiService { Single> getGameDetailVideoStream(@Query("type") String type, @Body RequestBody cacheVideoIds, @Query("video_id") String videoId, @Query("game_id") String gameId, @Query("page") int page); /** + * @deprecated 4.8.0废弃 * 获取最新排序的视频流(首页最新Tab) */ @GET("videos/stream?page_size=20") Single> getVideoStream(@Query("page") int page); + /** + * 获取关注用户的视频流(首页关注Tab) + */ + @POST("users/{user_id}/followers/videos?page_size=20") + Single>> getAttentionVideoStream(@Path("user_id") String userId, @Body RequestBody cacheVideoIds, @Query("page") int page); + + /** + * 上传关注视频浏览记录 + */ + @POST("users/{user_id}/followers/videos?view=no_return") + Single postAttentionVideoRecord(@Path("user_id") String userId, @Body RequestBody cacheVideoIds); + /** * 获取活动的视频流 * diff --git a/app/src/main/java/com/gh/gamecenter/room/dao/VideoHistoryDao.kt b/app/src/main/java/com/gh/gamecenter/room/dao/VideoHistoryDao.kt index 195eb5c1f8..3cd196c98d 100644 --- a/app/src/main/java/com/gh/gamecenter/room/dao/VideoHistoryDao.kt +++ b/app/src/main/java/com/gh/gamecenter/room/dao/VideoHistoryDao.kt @@ -9,12 +9,18 @@ interface VideoHistoryDao { @Insert(onConflict = OnConflictStrategy.REPLACE) fun addVideo(video: MyVideoEntity) - @Query("select * from MyVideoEntity where user!='' order by time desc limit :pageSize offset :offset ") + @Query("select * from MyVideoEntity where user!='' order by time desc limit :pageSize offset :offset") fun getVideoWithOffset(pageSize: Int, offset: Int): Single> - @Query("select * from MyVideoEntity where videoStreamRecord=1 order by time desc limit :pageSize offset :offset ") - fun getVideoStreamRecord(pageSize: Int, offset: Int): Single> + @Query("select id from MyVideoEntity where videoStreamRecord=2 order by time desc") + fun getAttentionVideoRecord(): Single> + + @Query("select id from MyVideoEntity where videoStreamRecord=1 order by time desc limit :pageSize offset :offset") + fun getVideoStreamRecord(pageSize: Int, offset: Int): Single> @Delete fun deleteVideo(video: MyVideoEntity) + + @Query("delete from MyVideoEntity where videoStreamRecord=2") + fun deleteAttentionVideoRecord() } \ No newline at end of file diff --git a/app/src/main/java/com/gh/gamecenter/video/detail/DetailPlayerView.kt b/app/src/main/java/com/gh/gamecenter/video/detail/DetailPlayerView.kt index f41520ea55..cbcc35eb2a 100644 --- a/app/src/main/java/com/gh/gamecenter/video/detail/DetailPlayerView.kt +++ b/app/src/main/java/com/gh/gamecenter/video/detail/DetailPlayerView.kt @@ -15,6 +15,7 @@ import android.view.View import android.widget.ImageView import android.widget.RelativeLayout import android.widget.SeekBar +import android.widget.TextView import androidx.appcompat.app.AppCompatActivity import androidx.core.content.ContextCompat import com.airbnb.lottie.LottieAnimationView @@ -29,6 +30,7 @@ import com.gh.download.cache.ExoCacheManager import com.gh.gamecenter.GameDetailActivity import com.gh.gamecenter.R import com.gh.gamecenter.entity.VideoEntity +import com.gh.gamecenter.eventbus.EBRecommed import com.gh.gamecenter.manager.UserManager import com.gh.gamecenter.qa.comment.CommentActivity import com.gh.gamecenter.video.game.GameVideoActivity @@ -47,6 +49,7 @@ import com.squareup.picasso.Picasso import io.reactivex.disposables.Disposable import kotlinx.android.synthetic.main.layout_video_detail_base.view.* import kotlinx.android.synthetic.main.layout_video_detail_surface.view.* +import org.greenrobot.eventbus.EventBus import java.util.concurrent.TimeUnit class DetailPlayerView @JvmOverloads constructor(context: Context, attrs: AttributeSet? = null) @@ -63,7 +66,6 @@ class DetailPlayerView @JvmOverloads constructor(context: Context, attrs: Attrib private var mRetry = false private var byStartedClick = false //第一次进入不显示mBottomContainer private var mContentLength = 0.0 - var repeatPlayCount = 0 //重复播放次数 private var mIsDragSeek = false//是否拖动进度条 private var mMuteCallback: MuteCallback private var mVolumeObserver: VolumeObserver @@ -73,6 +75,9 @@ class DetailPlayerView @JvmOverloads constructor(context: Context, attrs: Attrib private var mHandler: Handler? = null private var weChatAnimate: AnimatorSet? = null private var mPlayRetryCount = 0//播放错误重试次数 + var repeatPlayCount = 0 //重复播放次数 + var watchedContainer = findViewById(R.id.watchedContainer) + var watchedTv = findViewById(R.id.watchedTv) init { mHandler = Handler(Handler.Callback { @@ -308,6 +313,14 @@ class DetailPlayerView @JvmOverloads constructor(context: Context, attrs: Attrib } } + watchedContainer.setOnClickListener { + EventBus.getDefault().post(EBRecommed()) + } + + closeIv.setOnClickListener { + watchedContainer.visibility = View.GONE + } + censoringContainer.setOnClickListener { DirectUtils.directToWebView(context, "https://resource.ghzs.com/page/video_rule/video_rule.html", mEntrance) } errorBtn.setOnClickListener { @@ -889,6 +902,7 @@ class DetailPlayerView @JvmOverloads constructor(context: Context, attrs: Attrib fun hideAllButton(isHide: Boolean) { containerRl.goneIf(isHide) actionLayout.goneIf(isHide) + watchedContainer.goneIf(isHide) } private fun showBackBtn() { diff --git a/app/src/main/java/com/gh/gamecenter/video/detail/HomeVideoFragment.kt b/app/src/main/java/com/gh/gamecenter/video/detail/HomeVideoFragment.kt index 24010d95ce..248acb0ad5 100644 --- a/app/src/main/java/com/gh/gamecenter/video/detail/HomeVideoFragment.kt +++ b/app/src/main/java/com/gh/gamecenter/video/detail/HomeVideoFragment.kt @@ -17,9 +17,12 @@ import com.gh.gamecenter.R import com.gh.gamecenter.WebActivity import com.gh.gamecenter.entity.LinkEntity import com.gh.gamecenter.entity.SettingsEntity -import com.squareup.picasso.Picasso +import com.gh.gamecenter.eventbus.EBRecommed +import com.gh.gamecenter.eventbus.EBShare import io.reactivex.disposables.Disposable import kotlinx.android.synthetic.main.fragment_home_video.* +import org.greenrobot.eventbus.Subscribe +import org.greenrobot.eventbus.ThreadMode import java.util.* import kotlin.collections.ArrayList @@ -32,7 +35,7 @@ class HomeVideoFragment : BaseLazyFragment() { private var newestVideoDetailFragment: VideoDetailContainerFragment? = null private var recommendVideoDetailFragment: VideoDetailContainerFragment? = null private val fragments = ArrayList() - private var titles = arrayListOf("最新", "推荐") + private var titles = arrayListOf("关注", "推荐") private var mAdCountDownTimer: Disposable? = null private var mAdLeftCountDownTimer: Disposable? = null private var mAdRightCountDownTimer: Disposable? = null @@ -66,15 +69,15 @@ class HomeVideoFragment : BaseLazyFragment() { super.onFragmentFirstVisible() val mIsHomeVideo = arguments?.getBoolean(EntranceUtils.KEY_IS_HOME_VIDEO, false) ?: false titles = if (mIsHomeVideo) { - arrayListOf("最新", "推荐") + arrayListOf("关注", "推荐") } else { arrayListOf("推荐") } if (mIsHomeVideo) { val newestBundle = bundleOf(EntranceUtils.KEY_UUID to UUID.randomUUID().toString()) newestBundle.putAll(arguments) - newestBundle.putString(EntranceUtils.KEY_PATH, "视频流-最新Tab") - newestBundle.putString(EntranceUtils.KEY_LOCATION, VideoDetailContainerViewModel.Location.VIDEO_NEWEST.value) + newestBundle.putString(EntranceUtils.KEY_PATH, "视频流-关注Tab") + newestBundle.putString(EntranceUtils.KEY_LOCATION, VideoDetailContainerViewModel.Location.VIDEO_ATTENTION.value) newestVideoDetailFragment = VideoDetailContainerFragment() newestVideoDetailFragment?.with(newestBundle) fragments.add(newestVideoDetailFragment!!) @@ -197,7 +200,7 @@ class HomeVideoFragment : BaseLazyFragment() { marquee_ad_title.isSelected = true marquee_ad.setOnClickListener { - val pos = getCurrentFragment()?.mViewPagerLayoutManager?.findFirstCompletelyVisibleItemPosition() + val pos = getCurrentFragment()?.viewPagerLayoutManager?.findFirstCompletelyVisibleItemPosition() ?: -1 if (pos < 0) return@setOnClickListener MtaHelper.onEvent("视频详情", "视频广告", center!![0].title) @@ -234,7 +237,7 @@ class HomeVideoFragment : BaseLazyFragment() { banner.visibility = View.VISIBLE banner.start(ads) banner.onItemClick = { pos -> - val videoPos = getCurrentFragment()?.mViewPagerLayoutManager?.findFirstCompletelyVisibleItemPosition() + val videoPos = getCurrentFragment()?.viewPagerLayoutManager?.findFirstCompletelyVisibleItemPosition() ?: -1 if (videoPos >= 0) { MtaHelper.onEvent("视频详情", "视频广告", ads[pos].title) @@ -297,4 +300,11 @@ class HomeVideoFragment : BaseLazyFragment() { super.onActivityResult(requestCode, resultCode, data) getCurrentFragment()?.onActivityResult(requestCode, resultCode, data) } + + @Subscribe(threadMode = ThreadMode.MAIN) + fun onEventMainThread(event: EBRecommed?) { + if (fragments.size > 1) { + mViewPager.currentItem = 1 + } + } } \ No newline at end of file diff --git a/app/src/main/java/com/gh/gamecenter/video/detail/VideoAdapter.kt b/app/src/main/java/com/gh/gamecenter/video/detail/VideoAdapter.kt index 914b3c3bff..b0af534e64 100644 --- a/app/src/main/java/com/gh/gamecenter/video/detail/VideoAdapter.kt +++ b/app/src/main/java/com/gh/gamecenter/video/detail/VideoAdapter.kt @@ -112,6 +112,23 @@ class VideoAdapter(val mContext: Context, val mRecyclerView: RecyclerView, val r videoView.isNeedShowWifiTip = HaloApp.get(Constants.SHOULD_SHOW_VIDEO_MOBILE_WARNING, false) as Boolean? ?: false + + if (it.watched && !it.isFirstBind) { + if (position == 0) { + videoView.watchedContainer.visibility = View.VISIBLE + videoView.watchedTv.text = "暂无关注up主动态,前往 “推荐” 查看更多视频" + } else { + if (position - 1 >= 0 && !videoList[position - 1].watched) { + videoView.watchedContainer.visibility = View.VISIBLE + videoView.watchedTv.text = "上次看到这里,前往 “推荐” 查看更多视频" + } else { + videoView.watchedContainer.visibility = View.GONE + } + } + } else { + videoView.watchedContainer.visibility = View.GONE + } + it.isFirstBind = true } if (position == mViewModel.startPosition && isVisible) { diff --git a/app/src/main/java/com/gh/gamecenter/video/detail/VideoDetailContainerFragment.kt b/app/src/main/java/com/gh/gamecenter/video/detail/VideoDetailContainerFragment.kt index 195cc3f24f..282a551027 100644 --- a/app/src/main/java/com/gh/gamecenter/video/detail/VideoDetailContainerFragment.kt +++ b/app/src/main/java/com/gh/gamecenter/video/detail/VideoDetailContainerFragment.kt @@ -12,6 +12,7 @@ import android.widget.PopupWindow import android.widget.RelativeLayout import android.widget.TextView import androidx.appcompat.app.AppCompatActivity +import androidx.lifecycle.Observer import androidx.recyclerview.widget.OrientationHelper import androidx.recyclerview.widget.RecyclerView import com.gh.base.fragment.BaseLazyFragment @@ -25,12 +26,14 @@ import com.gh.download.DownloadManager import com.gh.download.cache.ExoCacheManager import com.gh.gamecenter.R import com.gh.gamecenter.SuggestionActivity +import com.gh.gamecenter.databinding.FragmentVideoDetailContainerBinding import com.gh.gamecenter.entity.VideoEntity import com.gh.gamecenter.eventbus.* import com.gh.gamecenter.manager.UserManager import com.gh.gamecenter.qa.comment.CommentActivity import com.gh.gamecenter.qa.comment.NewCommentFragment import com.gh.gamecenter.suggest.SuggestType +import com.gh.gamecenter.user.UserViewModel import com.halo.assistant.HaloApp import com.lightgame.download.DataWatcher import com.lightgame.download.DownloadEntity @@ -39,31 +42,28 @@ import com.lightgame.utils.AppManager import com.scwang.smartrefresh.layout.footer.ClassicsFooter import com.squareup.picasso.Picasso import io.reactivex.disposables.Disposable -import kotlinx.android.synthetic.main.fragment_video_detail_container.* -import kotlinx.android.synthetic.main.reuse_no_connection.* -import kotlinx.android.synthetic.main.reuse_none_data.* import org.greenrobot.eventbus.Subscribe import org.greenrobot.eventbus.ThreadMode class VideoDetailContainerFragment : BaseLazyFragment(), OnBackPressedListener { - lateinit var mViewModel: VideoDetailContainerViewModel - lateinit var mAdapter: VideoAdapter + private lateinit var mViewModel: VideoDetailContainerViewModel + private lateinit var mAdapter: VideoAdapter + private lateinit var mInitialVideoId: String + private lateinit var mLocation: String + private lateinit var mUserViewModel: UserViewModel + private lateinit var mBinding: FragmentVideoDetailContainerBinding - lateinit var mInitialVideoId: String - lateinit var mLocation: String private var mIsFirstIn = true - private val mOldList = ArrayList() - val mViewPagerLayoutManager = PagerLayoutManager(context, OrientationHelper.VERTICAL) private var mLastPosition = -1 private var mIsHomeVideo = false//是否是视频总入口 private var mBrowseTimer: Disposable? = null//视频浏览计时器 private var mBrowseDuration = 0L//浏览总时长 - private var referer: String = "" + private var mReferer: String = "" private var mToastDisposable: Disposable? = null - private var mExposureListener: ExposureListener? = null + val viewPagerLayoutManager = PagerLayoutManager(context, OrientationHelper.VERTICAL) private val dataWatcher = object : DataWatcher() { override fun onDataChanged(downloadEntity: DownloadEntity) { @@ -73,8 +73,12 @@ class VideoDetailContainerFragment : BaseLazyFragment(), OnBackPressedListener { } } - override fun getLayoutId(): Int { - return R.layout.fragment_video_detail_container + override fun getLayoutId(): Int = 0 + + override fun getInflatedLayout(): View { + return FragmentVideoDetailContainerBinding.inflate(LayoutInflater.from(requireContext()), null, false).apply { + mBinding = this + }.root } override fun onCreate(savedInstanceState: Bundle?) { @@ -82,8 +86,9 @@ class VideoDetailContainerFragment : BaseLazyFragment(), OnBackPressedListener { mInitialVideoId = arguments?.getString(EntranceUtils.KEY_ID) ?: "" mLocation = arguments?.getString(EntranceUtils.KEY_LOCATION) ?: "" - referer = arguments?.getString(EntranceUtils.KEY_REFERER) ?: "" + mReferer = arguments?.getString(EntranceUtils.KEY_REFERER) ?: "" + mUserViewModel = viewModelProviderFromParent(UserViewModel.Factory(HaloApp.getInstance().application)) mViewModel = viewModelProvider() mViewModel.path = arguments?.getString(EntranceUtils.KEY_PATH) ?: "" mViewModel.entrance = arguments?.getString(EntranceUtils.KEY_ENTRANCE) ?: "" @@ -107,24 +112,40 @@ class VideoDetailContainerFragment : BaseLazyFragment(), OnBackPressedListener { override fun onFragmentFirstVisible() { super.onFragmentFirstVisible() - mViewModel.setRecyclerView(recyclerview) + mViewModel.setRecyclerView(mBinding.recyclerview) initListener() if (!mIsHomeVideo) { - toolbar.setNavigationIcon(R.drawable.ic_toolbar_back_white) - toolbar.setNavigationOnClickListener { requireActivity().finish() } - refresh.isEnabled = false + mBinding.toolbar.setNavigationIcon(R.drawable.ic_toolbar_back_white) + mBinding.toolbar.setNavigationOnClickListener { requireActivity().finish() } + mBinding.refresh.isEnabled = false } - smartRefreshLayout.setNoMoreData(true) - refresh.setProgressViewOffset(false, 0, 50F.dip2px() + DisplayUtils.getStatusBarHeight(requireContext().resources)) + mBinding.smartRefreshLayout.setNoMoreData(true) + mBinding.refresh.setProgressViewOffset(false, 0, 50F.dip2px() + DisplayUtils.getStatusBarHeight(requireContext().resources)) + observeData() + + if (UserManager.getInstance().isLoggedIn || mLocation != VideoDetailContainerViewModel.Location.VIDEO_ATTENTION.value) { + mViewModel.getVideoDetailList(mInitialVideoId, mLocation, isLoadNext = true) + } else { + mBinding.attentionNoLoginContainer.visibility = View.VISIBLE + } + + mBinding.loginBtn.setOnClickListener { + CheckLoginUtils.checkLogin(requireContext(), "视频流-关注", null) + } + } + + private fun observeData() { mViewModel.videoList.observeNonNull(this) { hideNetworkErrorView() + mBinding.recyclerview.visibility = View.VISIBLE + mBinding.attentionNoDataContainer.visibility = View.GONE if (!::mAdapter.isInitialized) { - mAdapter = VideoAdapter(requireContext(), recyclerview, refresh, mViewModel) + mAdapter = VideoAdapter(requireContext(), mBinding.recyclerview, mBinding.refresh, mViewModel) mExposureListener = ExposureListener(this, mAdapter) - recyclerview.addOnScrollListener(mExposureListener!!) - recyclerview.adapter = mAdapter - recyclerview.layoutManager = mViewPagerLayoutManager + mBinding.recyclerview.addOnScrollListener(mExposureListener!!) + mBinding.recyclerview.adapter = mAdapter + mBinding.recyclerview.layoutManager = viewPagerLayoutManager if (it.isNotEmpty()) { val isShowSlide = SPUtils.getBoolean(Constants.SP_SHOW_SLIDE_GUIDE) @@ -139,14 +160,14 @@ class VideoDetailContainerFragment : BaseLazyFragment(), OnBackPressedListener { if (mIsFirstIn) { mAdapter.isVisible = isSupportVisible mViewModel.currentDisplayingVideo = it[mViewModel.startPosition] - recyclerview.scrollToPosition(mViewModel.startPosition) - LogUtils.uploadVideoStreamingEnter(mViewModel.path, referer, mViewModel.currentDisplayingVideo?.id, mViewModel.uuid) + mBinding.recyclerview.scrollToPosition(mViewModel.startPosition) + LogUtils.uploadVideoStreamingEnter(mViewModel.path, mReferer, mViewModel.currentDisplayingVideo?.id, mViewModel.uuid) mIsFirstIn = false } //下拉刷新 - if (refresh.isRefreshing) { - refresh.isRefreshing = false + if (mBinding.refresh.isRefreshing) { + mBinding.refresh.isRefreshing = false showRefreshSuccessToast() clearPlayerViewInfo(findVisibleVideoViewByPosition()) ExoCacheManager.cancelAll() @@ -177,8 +198,12 @@ class VideoDetailContainerFragment : BaseLazyFragment(), OnBackPressedListener { mViewModel.noDataError.observeNonNull(this) { if (it) { - showNoDataErrorView() - toast("内容可能已被删除") + if (mLocation == VideoDetailContainerViewModel.Location.VIDEO_ATTENTION.value) { + mBinding.attentionNoDataContainer.visibility = View.VISIBLE + } else { + showNoDataErrorView() + toast("内容可能已被删除") + } } } @@ -190,21 +215,38 @@ class VideoDetailContainerFragment : BaseLazyFragment(), OnBackPressedListener { } mViewModel.refreshFinish.observeNonNull(this) { if (it) { - refresh.isRefreshing = false + mBinding.refresh.isRefreshing = false } } - - mViewModel.getVideoDetailList(mInitialVideoId, mLocation, isLoadNext = true) + mUserViewModel.loginObsUserinfo.observe(requireActivity(), Observer { + if (mLocation == VideoDetailContainerViewModel.Location.VIDEO_ATTENTION.value) { + mBinding.refresh.isEnabled = it != null + if (it != null) { + mBinding.attentionNoLoginContainer.visibility = View.GONE + mViewModel.getVideoDetailList(mInitialVideoId, mLocation, isLoadNext = true) + } else { + if (::mAdapter.isInitialized) { + mBinding.recyclerview.visibility = View.GONE + mIsFirstIn = true + mViewModel.reset() + mAdapter.videoList.clear() + mAdapter.notifyDataSetChanged() + } + mBinding.errorContainer.visibility = View.GONE + mBinding.attentionNoLoginContainer.visibility = View.VISIBLE + } + } + }) } private fun showRefreshSuccessToast() { mToastDisposable?.dispose() - toastTv.alpha = 0f - toastTv.animate().alpha(1f).setDuration(200).setStartDelay(150).start() + mBinding.toastTv.alpha = 0f + mBinding.toastTv.animate().alpha(1f).setDuration(200).setStartDelay(150).start() mToastDisposable = rxTimer(1) { if (it >= 2000) { - toastTv.animate().alpha(0f).setDuration(200).start() + mBinding.toastTv.animate().alpha(0f).setDuration(200).start() mToastDisposable?.dispose() } } @@ -212,9 +254,9 @@ class VideoDetailContainerFragment : BaseLazyFragment(), OnBackPressedListener { private fun initListener() { // 根据闪退反馈,离开页面一段时间以后,有时候这里的 recyclerview 会为空 - if (recyclerview == null) return + if (mBinding.recyclerview == null) return - recyclerview.addOnScrollListener(object : RecyclerView.OnScrollListener() { + mBinding.recyclerview.addOnScrollListener(object : RecyclerView.OnScrollListener() { override fun onScrolled(recyclerView: RecyclerView, dx: Int, dy: Int) { super.onScrolled(recyclerView, dx, dy) val (itemHeight, distance) = getDistance() @@ -228,16 +270,16 @@ class VideoDetailContainerFragment : BaseLazyFragment(), OnBackPressedListener { } }) - refresh.setOnRefreshListener { + mBinding.refresh.setOnRefreshListener { mToastDisposable?.dispose() - toastTv.alpha = 0f + mBinding.toastTv.alpha = 0f mIsFirstIn = true mViewModel.getVideoDetailList(mViewModel.currentDisplayingVideo?.id ?: "", mLocation, isLoadNext = false) findVisibleVideoViewByPosition()?.uploadVideoStreamingPlaying("视频流刷新") } - mViewPagerLayoutManager.setOnViewPagerListener(object : OnPagerListener { + viewPagerLayoutManager.setOnViewPagerListener(object : OnPagerListener { override fun onInitComplete() { } @@ -262,14 +304,15 @@ class VideoDetailContainerFragment : BaseLazyFragment(), OnBackPressedListener { mViewModel.entranceDetail, mViewModel.videoList.value?.get(position - 1)?.id, mViewModel.uuid, 0.0, 0, 0, "play") } } - val detailPlayerView = recyclerview.findViewHolderForAdapterPosition(position)?.itemView as? DetailPlayerView + val detailPlayerView = mBinding.recyclerview.findViewHolderForAdapterPosition(position)?.itemView as? DetailPlayerView clearPlayerViewInfo(detailPlayerView) } } override fun onPageSelected(position: Int, isBottom: Boolean) { - smartRefreshLayout.isEnableLoadMore = isBottom - smartRefreshLayout.setNoMoreData(isBottom) + val isNoMoreData = isBottom && mLocation != VideoDetailContainerViewModel.Location.VIDEO_CHOICENESS.value + mBinding.smartRefreshLayout.isEnableLoadMore = isNoMoreData + mBinding.smartRefreshLayout.setNoMoreData(isNoMoreData) val isShowClick = SPUtils.getBoolean(Constants.SP_SHOW_CLICK_GUIDE) if (!isShowClick) { showClickGuide() @@ -287,9 +330,9 @@ class VideoDetailContainerFragment : BaseLazyFragment(), OnBackPressedListener { } }) - guideRl.setOnTouchListener { _, _ -> - slideGuideAnimation.cancelAnimation() - guideRl.visibility = View.GONE + mBinding.guideRl.setOnTouchListener { _, _ -> + mBinding.slideGuideAnimation.cancelAnimation() + mBinding.guideRl.visibility = View.GONE false } @@ -334,7 +377,8 @@ class VideoDetailContainerFragment : BaseLazyFragment(), OnBackPressedListener { mViewModel.getVideoDetailList(videoId, mLocation, isLoadNext = true) } //防止视频流分页获取的数据为空不会触发循环 - if (pos == size - 1 && mLocation == VideoDetailContainerViewModel.Location.VIDEO_CHOICENESS.value) { + if (pos == size - 1 && (mLocation == VideoDetailContainerViewModel.Location.VIDEO_CHOICENESS.value || + mLocation == VideoDetailContainerViewModel.Location.VIDEO_ATTENTION.value)) { mViewModel.getVideoDetailList(videoId, mLocation, isLoadNext = true) } val homeVideoFragment = this@VideoDetailContainerFragment.parentFragment as? HomeVideoFragment @@ -355,25 +399,25 @@ class VideoDetailContainerFragment : BaseLazyFragment(), OnBackPressedListener { //显示滑动引导 private fun showSlideGuide() { mBaseHandler.postDelayed({ - guideRl.visibility = View.VISIBLE - guideTitle.text = "上滑查看下一个视频" + mBinding.guideRl.visibility = View.VISIBLE + mBinding.guideTitle.text = "上滑查看下一个视频" val heightPixels = requireContext().resources.displayMetrics.heightPixels - val layoutParams = slideGuideAnimation.layoutParams as RelativeLayout.LayoutParams + val layoutParams = mBinding.slideGuideAnimation.layoutParams as RelativeLayout.LayoutParams layoutParams.height = DisplayUtils.dip2px(195f) layoutParams.topMargin = heightPixels / 2 - DisplayUtils.dip2px(195f) / 2 - slideGuideAnimation.layoutParams = layoutParams + mBinding.slideGuideAnimation.layoutParams = layoutParams - val guideTitleLayoutParams = guideTitle.layoutParams as RelativeLayout.LayoutParams + val guideTitleLayoutParams = mBinding.guideTitle.layoutParams as RelativeLayout.LayoutParams guideTitleLayoutParams.topMargin = layoutParams.topMargin + DisplayUtils.dip2px(195f) - guideTitle.gravity = Gravity.CENTER - guideTitle.layoutParams = guideTitleLayoutParams + mBinding.guideTitle.gravity = Gravity.CENTER + mBinding.guideTitle.layoutParams = guideTitleLayoutParams - slideGuideAnimation.setAnimation("lottie/slide_guide.json") - slideGuideAnimation.playAnimation() - slideGuideAnimation.doOnAnimationEnd { - guideRl.visibility = View.GONE + mBinding.slideGuideAnimation.setAnimation("lottie/slide_guide.json") + mBinding.slideGuideAnimation.playAnimation() + mBinding.slideGuideAnimation.doOnAnimationEnd { + mBinding.guideRl.visibility = View.GONE } }, 200) } @@ -383,27 +427,27 @@ class VideoDetailContainerFragment : BaseLazyFragment(), OnBackPressedListener { mBaseHandler.postDelayed({ val pos = findVisibleItemPosition() if (pos != mLastPosition) return@postDelayed - guideRl.visibility = View.VISIBLE - guideTitle.text = "点击查看更多视频" + mBinding.guideRl.visibility = View.VISIBLE + mBinding.guideTitle.text = "点击查看更多视频" val gameTitleY = findVisibleVideoViewByPosition()?.getGameTitleY() ?: 0 - val layoutParams = slideGuideAnimation.layoutParams as RelativeLayout.LayoutParams + val layoutParams = mBinding.slideGuideAnimation.layoutParams as RelativeLayout.LayoutParams layoutParams.height = DisplayUtils.dip2px(68f) val topMargin = gameTitleY - DisplayUtils.dip2px(68f) / 5 layoutParams.topMargin = topMargin - slideGuideAnimation.layoutParams = layoutParams + mBinding.slideGuideAnimation.layoutParams = layoutParams - val guideTitleLayoutParams = guideTitle.layoutParams as RelativeLayout.LayoutParams + val guideTitleLayoutParams = mBinding.guideTitle.layoutParams as RelativeLayout.LayoutParams val guideTitleBottomMargin = layoutParams.topMargin - DisplayUtils.dip2px(30f) guideTitleLayoutParams.topMargin = guideTitleBottomMargin - guideTitle.gravity = Gravity.LEFT - guideTitle.layoutParams = guideTitleLayoutParams + mBinding.guideTitle.gravity = Gravity.LEFT + mBinding.guideTitle.layoutParams = guideTitleLayoutParams - slideGuideAnimation.setAnimation("lottie/click_guide.json") - slideGuideAnimation.playAnimation() - slideGuideAnimation.doOnAnimationEnd { - guideRl.visibility = View.GONE + mBinding.slideGuideAnimation.setAnimation("lottie/click_guide.json") + mBinding.slideGuideAnimation.playAnimation() + mBinding.slideGuideAnimation.doOnAnimationEnd { + mBinding.guideRl.visibility = View.GONE } }, 200) } @@ -413,25 +457,25 @@ class VideoDetailContainerFragment : BaseLazyFragment(), OnBackPressedListener { mBaseHandler.postDelayed({ val pos = findVisibleItemPosition() if (pos != mLastPosition) return@postDelayed - guideRl.visibility = View.VISIBLE - guideTitle.text = "双击点个赞" + mBinding.guideRl.visibility = View.VISIBLE + mBinding.guideTitle.text = "双击点个赞" val heightPixels = requireContext().resources.displayMetrics.heightPixels - val layoutParams = slideGuideAnimation.layoutParams as RelativeLayout.LayoutParams + val layoutParams = mBinding.slideGuideAnimation.layoutParams as RelativeLayout.LayoutParams layoutParams.height = DisplayUtils.dip2px(68f) layoutParams.topMargin = heightPixels / 2 - DisplayUtils.dip2px(68f) / 2 - slideGuideAnimation.layoutParams = layoutParams + mBinding.slideGuideAnimation.layoutParams = layoutParams - val guideTitleLayoutParams = guideTitle.layoutParams as RelativeLayout.LayoutParams + val guideTitleLayoutParams = mBinding.guideTitle.layoutParams as RelativeLayout.LayoutParams guideTitleLayoutParams.topMargin = layoutParams.topMargin + DisplayUtils.dip2px(68f) + DisplayUtils.dip2px(16f) - guideTitle.gravity = Gravity.CENTER - guideTitle.layoutParams = guideTitleLayoutParams + mBinding.guideTitle.gravity = Gravity.CENTER + mBinding.guideTitle.layoutParams = guideTitleLayoutParams - slideGuideAnimation.setAnimation("lottie/double_click_guide.json") - slideGuideAnimation.playAnimation() - slideGuideAnimation.doOnAnimationEnd { - guideRl.visibility = View.GONE + mBinding.slideGuideAnimation.setAnimation("lottie/double_click_guide.json") + mBinding.slideGuideAnimation.playAnimation() + mBinding.slideGuideAnimation.doOnAnimationEnd { + mBinding.guideRl.visibility = View.GONE } }, 200) @@ -440,8 +484,8 @@ class VideoDetailContainerFragment : BaseLazyFragment(), OnBackPressedListener { //获取RecyclerView滑动距离 private fun getDistance(): Pair { - val position = mViewPagerLayoutManager.findFirstVisibleItemPosition() - val firstVisiableChildView = mViewPagerLayoutManager.findViewByPosition(position) + val position = viewPagerLayoutManager.findFirstVisibleItemPosition() + val firstVisiableChildView = viewPagerLayoutManager.findViewByPosition(position) val itemHeight = firstVisiableChildView?.height ?: 0 val itemTop = firstVisiableChildView?.top ?: 0 val iposition = position * itemHeight @@ -487,9 +531,9 @@ class VideoDetailContainerFragment : BaseLazyFragment(), OnBackPressedListener { } } } ?: CustomManager.releaseAllVideos("detail_${mViewModel.uuid}") - if (slideGuideAnimation.isAnimating) { - slideGuideAnimation.cancelAnimation() - guideRl.visibility = View.GONE + if (mBinding.slideGuideAnimation.isAnimating) { + mBinding.slideGuideAnimation.cancelAnimation() + mBinding.guideRl.visibility = View.GONE } super.onFragmentPause() ExoCacheManager.cancelAll() @@ -508,18 +552,18 @@ class VideoDetailContainerFragment : BaseLazyFragment(), OnBackPressedListener { fun findVisibleVideoViewByPosition(): DetailPlayerView? { val pos = findVisibleItemPosition() - val holder = recyclerview?.findViewHolderForAdapterPosition(pos) + val holder = mBinding.recyclerview?.findViewHolderForAdapterPosition(pos) return holder?.itemView as? DetailPlayerView } private fun findVisibleItemPosition(): Int { - var pos = mViewPagerLayoutManager.findLastCompletelyVisibleItemPosition() + var pos = viewPagerLayoutManager.findLastCompletelyVisibleItemPosition() if (pos == -1) { - pos = if (mViewPagerLayoutManager.isSlideDown) { - mViewPagerLayoutManager.findLastVisibleItemPosition() + pos = if (viewPagerLayoutManager.isSlideDown) { + viewPagerLayoutManager.findLastVisibleItemPosition() } else { - mViewPagerLayoutManager.findFirstVisibleItemPosition() + viewPagerLayoutManager.findFirstVisibleItemPosition() } } @@ -528,29 +572,29 @@ class VideoDetailContainerFragment : BaseLazyFragment(), OnBackPressedListener { private fun showNetworkErrorView() { if (!mIsHomeVideo) { - toolbar.setNavigationIcon(R.drawable.ic_bar_back) + mBinding.toolbar.setNavigationIcon(R.drawable.ic_bar_back) } - errorContainer.visibility = View.VISIBLE - reuse_no_connection.visibility = View.VISIBLE - reuse_no_connection.setOnClickListener { + mBinding.errorContainer.visibility = View.VISIBLE + mBinding.reuseNoConnection.root.visibility = View.VISIBLE + mBinding.reuseNoConnection.root.setOnClickListener { mViewModel.getVideoDetailList(mInitialVideoId, mLocation, isLoadNext = true) } } private fun showNoDataErrorView() { if (!mIsHomeVideo) { - toolbar.setNavigationIcon(R.drawable.ic_bar_back) + mBinding.toolbar.setNavigationIcon(R.drawable.ic_bar_back) } - errorContainer.visibility = View.VISIBLE - reuse_none_data.visibility = View.VISIBLE + mBinding.errorContainer.visibility = View.VISIBLE + mBinding.reuseNoneData.root.visibility = View.VISIBLE } private fun hideNetworkErrorView() { if (!mIsHomeVideo) { - toolbar.setNavigationIcon(R.drawable.ic_toolbar_back_white) + mBinding.toolbar.setNavigationIcon(R.drawable.ic_toolbar_back_white) } - errorContainer.visibility = View.GONE - reuse_no_connection.visibility = View.GONE + mBinding.errorContainer.visibility = View.GONE + mBinding.reuseNoConnection.root.visibility = View.GONE } fun showMoreMenuDialog(targetView: View) { @@ -581,7 +625,7 @@ class VideoDetailContainerFragment : BaseLazyFragment(), OnBackPressedListener { layout.measure(0, 0) val viewWidth = layout.measuredWidth if (view == null) { - popupWindow.showAsDropDown(toolbar.menu.getItem(1).actionView, -viewWidth - 10, 10) + popupWindow.showAsDropDown(mBinding.toolbar.menu.getItem(1).actionView, -viewWidth - 10, 10) } else { popupWindow.showAsDropDown(view, -viewWidth + 80, 10) } @@ -748,7 +792,7 @@ class VideoDetailContainerFragment : BaseLazyFragment(), OnBackPressedListener { mAdapter.videoList.forEachIndexed { index, videoEntity -> if (userId == videoEntity.user.id) { videoEntity.me.isFollower = isFollow - val detailPlayerView = recyclerview.findViewHolderForAdapterPosition(index)?.itemView as? DetailPlayerView + val detailPlayerView = mBinding.recyclerview.findViewHolderForAdapterPosition(index)?.itemView as? DetailPlayerView if (mViewModel.currentDisplayingVideo == videoEntity) { detailPlayerView?.updateViewDetail(videoEntity) } else { @@ -788,6 +832,7 @@ class VideoDetailContainerFragment : BaseLazyFragment(), OnBackPressedListener { detailPlayerView?.repeatPlayCount = 0 detailPlayerView?.unObserveVolume(requireActivity() as AppCompatActivity) detailPlayerView?.removeAnimation() + detailPlayerView?.watchedContainer?.visibility = View.GONE } override fun onHandleBackPressed(): Boolean { diff --git a/app/src/main/java/com/gh/gamecenter/video/detail/VideoDetailContainerViewModel.kt b/app/src/main/java/com/gh/gamecenter/video/detail/VideoDetailContainerViewModel.kt index 047bee0d94..4e4e5e39e7 100644 --- a/app/src/main/java/com/gh/gamecenter/video/detail/VideoDetailContainerViewModel.kt +++ b/app/src/main/java/com/gh/gamecenter/video/detail/VideoDetailContainerViewModel.kt @@ -7,6 +7,7 @@ import androidx.lifecycle.MutableLiveData import androidx.recyclerview.widget.RecyclerView import com.gh.common.exposure.meta.MetaUtil import com.gh.common.history.HistoryDatabase +import com.gh.common.history.HistoryHelper import com.gh.common.runOnIoThread import com.gh.common.util.* import com.gh.download.DownloadManager @@ -25,6 +26,7 @@ import io.reactivex.schedulers.Schedulers import okhttp3.ResponseBody import java.lang.ref.WeakReference import java.util.* +import kotlin.collections.ArrayList import kotlin.random.Random @SuppressLint("CheckResult") @@ -59,6 +61,7 @@ class VideoDetailContainerViewModel(application: Application) : AndroidViewModel private var cacheVideoIds: MutableList? = null private var cacheId = "" private var mRecyclerViewRef: WeakReference? = null + private var total = 0 // 是否为第一次加载(即没有进行加载更多) private var mIsFirstLoad = true @@ -96,12 +99,20 @@ class VideoDetailContainerViewModel(application: Application) : AndroidViewModel getVideoStream(location, videoId, isLoadNext) } } - Location.VIDEO_NEWEST.value -> { + /* Location.VIDEO_NEWEST.value -> { + if (!isLoadNext) { + page = 1 + mIsFirstLoad = true + } + getNewestVideoStream(isLoadNext) + }*/ + Location.VIDEO_ATTENTION.value -> { if (!isLoadNext) { page = 1 mIsFirstLoad = true + total = 0 } - getNewestVideoStream(isLoadNext) + getAttentionVideoStream(isLoadNext) } Location.VIDEO_ACTIVITY.value -> { //判断是否是老版本活动,老版本活动使用page分页,新版本使用filter @@ -175,10 +186,6 @@ class VideoDetailContainerViewModel(application: Application) : AndroidViewModel } page++ //下拉刷新清除列表数据 -// if (!isLoadNext) { -// videoList.value?.clear() -// } -// mergeVideoList(data, isLoadNext) if (isLoadNext) { mergeVideoList(data, isLoadNext) } else if (!isLoadNext && mRecyclerViewRef?.get()?.computeVerticalScrollOffset() == 0) { @@ -202,6 +209,54 @@ class VideoDetailContainerViewModel(application: Application) : AndroidViewModel }) } + //获取关注用户的视频流 + private fun getAttentionVideoStream(isLoadNext: Boolean) { + if (!mIsFirstLoad && total <= videoList.value?.size ?: 0) return + val requestMap = hashMapOf() + getAttentionCacheVideoIds().flatMap { + requestMap["cache_video_ids"] = it + val body = requestMap.createRequestBodyAny() + RetrofitManager.getInstance(getApplication()) + .api.getAttentionVideoStream(UserManager.getInstance().userId, body, page) + }.subscribeOn(Schedulers.io()) + .subscribe(object : BiResponse>>() { + override fun onSuccess(data: retrofit2.Response>) { + val headers = data.headers() + total = headers.get("total")?.toInt() ?: 0 + + val videoEntities = data.body() ?: arrayListOf() + + if (mIsFirstLoad) { + // 无数据时直接显示无数据页面 + if (videoEntities.isEmpty()) { + noDataError.postValue(true) + return + } + } + page++ + if (isLoadNext) { + mergeVideoList(videoEntities, isLoadNext) + } else if (!isLoadNext && mRecyclerViewRef?.get()?.computeVerticalScrollOffset() == 0) { + //下拉刷新并且列表没有滚动清除列表数据,数据发生变化 + videoList.value?.clear() + mergeVideoList(videoEntities, isLoadNext) + } else { + //下拉刷新并且列表滚动中关闭下拉刷新动画,数据不变 + refreshFinish.postValue(true) + } + + mIsFirstLoad = false + } + + override fun onFailure(exception: Exception) { + if (mIsFirstLoad) { + networkError.postValue(true) + mIsFirstLoad = false + } + } + }) + } + private fun getVideoStream(type: String, videoId: String, isLoadNext: Boolean) { val requestMap = hashMapOf() getCacheVideoIds().flatMap { @@ -236,10 +291,6 @@ class VideoDetailContainerViewModel(application: Application) : AndroidViewModel } if (mIsFirstLoad || !(data.size == 1 && data[0].id == videoId)) { //下拉刷新清除列表数据 -// if (!isLoadNext) { -// videoList.value?.clear() -// } -// mergeVideoList(data, isLoadNext) if (isLoadNext) { mergeVideoList(data, isLoadNext) } else if (!isLoadNext && mRecyclerViewRef?.get()?.computeVerticalScrollOffset() == 0) { @@ -300,10 +351,15 @@ class VideoDetailContainerViewModel(application: Application) : AndroidViewModel } else { HistoryDatabase.instance.videoHistoryDao() .getVideoStreamRecord(100, 0) - .map { t -> t.map { it.id }.toMutableList() } } } + //获取关注视频缓存ids + private fun getAttentionCacheVideoIds(): Single> { + return HistoryDatabase.instance.videoHistoryDao() + .getAttentionVideoRecord() + } + fun mergeVideoList(receivedDataList: ArrayList, isLoadNext: Boolean = true) { if (receivedDataList.isNullOrEmpty()) return @@ -446,7 +502,17 @@ class VideoDetailContainerViewModel(application: Application) : AndroidViewModel user = User(videoEntity.user.id ?: "", videoEntity.user.name ?: "", videoEntity.user.icon ?: "") commentCount = videoEntity.commentCount - videoStreamRecord = if (location == Location.VIDEO_CHOICENESS.value || location == Location.VIDEO_HOT.value) 1 else 0 + videoStreamRecord = when (location) { + Location.VIDEO_CHOICENESS.value, Location.VIDEO_HOT.value -> { + 1 + } + Location.VIDEO_ATTENTION.value -> { + 2 + } + else -> { + 0 + } + } } runOnIoThread { tryCatchInRelease { HistoryDatabase.instance.videoHistoryDao().addVideo(videoHistory) } } @@ -500,6 +566,14 @@ class VideoDetailContainerViewModel(application: Application) : AndroidViewModel game.setEntryMap(DownloadManager.getInstance(getApplication()).getEntryMap(game.name)) } + fun reset() { + startPosition = 0 + page = 1 + total = 0 + mIsFirstLoad = true + videoList.value?.clear() + } + /** * 后台定义的类型 [https://gitlab.ghzs.com/halo/halo-api/wikis/v3.7/%E6%B8%B8%E6%88%8F%E8%A7%86%E9%A2%91#get-videosvideo_id] * hottest_game_video 视频合集(最热), @@ -526,6 +600,9 @@ class VideoDetailContainerViewModel(application: Application) : AndroidViewModel * * v410新增 * game_zone 游戏专区视频播放算法 + * + * v480新增 + * attention 首页关注视频流 */ enum class Location(val value: String) { HOTTEST_GAME_VIDEO("hottest_game_video"), @@ -550,7 +627,9 @@ class VideoDetailContainerViewModel(application: Application) : AndroidViewModel GAME_DETAIL("game_detail"), - GAME_ZONE("game_zone") + GAME_ZONE("game_zone"), + + VIDEO_ATTENTION("attention") } } \ No newline at end of file diff --git a/app/src/main/res/drawable-xxhdpi/ic_video_detail_close.png b/app/src/main/res/drawable-xxhdpi/ic_video_detail_close.png new file mode 100644 index 0000000000..aee5936417 Binary files /dev/null and b/app/src/main/res/drawable-xxhdpi/ic_video_detail_close.png differ diff --git a/app/src/main/res/drawable-xxhdpi/ic_video_detail_jump_arrow.png b/app/src/main/res/drawable-xxhdpi/ic_video_detail_jump_arrow.png new file mode 100644 index 0000000000..15602dd3ff Binary files /dev/null and b/app/src/main/res/drawable-xxhdpi/ic_video_detail_jump_arrow.png differ diff --git a/app/src/main/res/drawable-xxhdpi/icon_video_detail_attention_no_data.webp b/app/src/main/res/drawable-xxhdpi/icon_video_detail_attention_no_data.webp new file mode 100644 index 0000000000..8a2632f4c1 Binary files /dev/null and b/app/src/main/res/drawable-xxhdpi/icon_video_detail_attention_no_data.webp differ diff --git a/app/src/main/res/drawable-xxhdpi/icon_video_detail_not_login.webp b/app/src/main/res/drawable-xxhdpi/icon_video_detail_not_login.webp new file mode 100644 index 0000000000..ac40eeb36a Binary files /dev/null and b/app/src/main/res/drawable-xxhdpi/icon_video_detail_not_login.webp differ diff --git a/app/src/main/res/layout/fragment_video_detail_container.xml b/app/src/main/res/layout/fragment_video_detail_container.xml index c048eda9a6..bd56f55379 100644 --- a/app/src/main/res/layout/fragment_video_detail_container.xml +++ b/app/src/main/res/layout/fragment_video_detail_container.xml @@ -70,9 +70,13 @@ android:background="@color/white" android:visibility="gone"> - + - + @@ -126,4 +130,80 @@ app:lottie_loop="true" app:lottie_repeatCount="2" /> + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/layout/layout_video_detail_surface.xml b/app/src/main/res/layout/layout_video_detail_surface.xml index f896f97714..783cb017f6 100644 --- a/app/src/main/res/layout/layout_video_detail_surface.xml +++ b/app/src/main/res/layout/layout_video_detail_surface.xml @@ -63,6 +63,7 @@ android:id="@+id/containerRl" android:layout_width="match_parent" android:layout_height="wrap_content" + android:layout_marginBottom="16dp" android:orientation="horizontal"> + android:layout_centerInParent="true" + android:visibility="invisible" /> @@ -406,11 +407,41 @@ + + + + + + + diff --git a/app/src/main/res/values/colors.xml b/app/src/main/res/values/colors.xml index 680f112a15..e83c962dcd 100644 --- a/app/src/main/res/values/colors.xml +++ b/app/src/main/res/values/colors.xml @@ -233,7 +233,9 @@ #80EFFF #00BFDB #00DFFF + #3682C2 #99666666 + #6621282E \ No newline at end of file