From 6ea556690322b0fef2f63a72581fe4bd9e0ce5c3 Mon Sep 17 00:00:00 2001 From: FongMi Date: Sun, 31 Jul 2022 02:13:06 +0800 Subject: [PATCH] Support recent - part 1 --- .../tv/ui/activity/DetailActivity.java | 26 +++++- .../android/tv/ui/activity/HomeActivity.java | 91 ++++++++++++++----- .../tv/ui/activity/SettingActivity.java | 28 +++--- .../android/tv/ui/fragment/VodFragment.java | 27 ++++-- .../tv/ui/presenter/HistoryPresenter.java | 74 +++++++++++++++ .../android/tv/ui/presenter/VodPresenter.java | 12 +-- app/src/leanback/res/layout/adapter_vod.xml | 14 +++ .../com/fongmi/android/tv/api/ApiConfig.java | 2 +- .../com/fongmi/android/tv/bean/History.java | 91 +++++++++++++++++++ .../com/fongmi/android/tv/bean/Result.java | 9 -- .../java/com/fongmi/android/tv/bean/Vod.java | 17 ---- .../com/fongmi/android/tv/db/AppDatabase.java | 34 +++++++ .../com/fongmi/android/tv/db/dao/BaseDao.java | 40 ++++++++ .../fongmi/android/tv/db/dao/HistoryDao.java | 18 ++++ .../fongmi/android/tv/event/RefreshEvent.java | 30 ++++++ .../com/fongmi/android/tv/utils/ImgUtil.java | 12 +++ app/src/main/res/values-zh-rCN/strings.xml | 3 + app/src/main/res/values-zh-rTW/strings.xml | 3 + app/src/main/res/values/strings.xml | 3 + 19 files changed, 456 insertions(+), 78 deletions(-) create mode 100644 app/src/leanback/java/com/fongmi/android/tv/ui/presenter/HistoryPresenter.java create mode 100644 app/src/main/java/com/fongmi/android/tv/bean/History.java create mode 100644 app/src/main/java/com/fongmi/android/tv/db/AppDatabase.java create mode 100644 app/src/main/java/com/fongmi/android/tv/db/dao/BaseDao.java create mode 100644 app/src/main/java/com/fongmi/android/tv/db/dao/HistoryDao.java create mode 100644 app/src/main/java/com/fongmi/android/tv/event/RefreshEvent.java diff --git a/app/src/leanback/java/com/fongmi/android/tv/ui/activity/DetailActivity.java b/app/src/leanback/java/com/fongmi/android/tv/ui/activity/DetailActivity.java index 445373a6a..1e5a2f9f0 100644 --- a/app/src/leanback/java/com/fongmi/android/tv/ui/activity/DetailActivity.java +++ b/app/src/leanback/java/com/fongmi/android/tv/ui/activity/DetailActivity.java @@ -19,12 +19,15 @@ import androidx.lifecycle.ViewModelProvider; import androidx.recyclerview.widget.RecyclerView; import androidx.viewbinding.ViewBinding; -import com.fongmi.android.tv.api.ApiConfig; import com.fongmi.android.tv.R; +import com.fongmi.android.tv.api.ApiConfig; +import com.fongmi.android.tv.bean.History; import com.fongmi.android.tv.bean.Vod; import com.fongmi.android.tv.databinding.ActivityDetailBinding; import com.fongmi.android.tv.databinding.ViewControllerBottomBinding; +import com.fongmi.android.tv.db.AppDatabase; import com.fongmi.android.tv.event.PlayerEvent; +import com.fongmi.android.tv.event.RefreshEvent; import com.fongmi.android.tv.model.SiteViewModel; import com.fongmi.android.tv.player.Players; import com.fongmi.android.tv.ui.presenter.EpisodePresenter; @@ -55,6 +58,7 @@ public class DetailActivity extends BaseActivity implements KeyDown.Listener { private SiteViewModel mSiteViewModel; private boolean mFullscreen; private KeyDown mKeyDown; + private History mHistory; private View mOldView; private int mCurrent; @@ -62,6 +66,10 @@ public class DetailActivity extends BaseActivity implements KeyDown.Listener { return getIntent().getStringExtra("id"); } + private String getVodKey() { + return ApiConfig.get().getHome().getKey() + "_" + getVodFlag().getFlag() + "_" + getId(); + } + private Vod.Flag getVodFlag() { return (Vod.Flag) mFlagAdapter.get(mBinding.flag.getSelectedPosition()); } @@ -88,6 +96,7 @@ public class DetailActivity extends BaseActivity implements KeyDown.Listener { @Override protected void initView() { + mHistory = new History(); mKeyDown = KeyDown.create(this); mFrameParams = mBinding.video.getLayoutParams(); mBinding.progressLayout.showProgress(); @@ -166,6 +175,7 @@ public class DetailActivity extends BaseActivity implements KeyDown.Listener { private void setDetail(Vod item) { mBinding.progressLayout.showContent(); + mBinding.video.setTag(item.getVodPic()); mBinding.name.setText(item.getVodName()); setText(mBinding.site, R.string.detail_site, ApiConfig.get().getHome().getName()); setText(mBinding.year, R.string.detail_year, item.getVodYear()); @@ -219,7 +229,7 @@ public class DetailActivity extends BaseActivity implements KeyDown.Listener { private void enterFullscreen() { mBinding.video.setForeground(null); mBinding.video.setLayoutParams(new RelativeLayout.LayoutParams(RelativeLayout.LayoutParams.MATCH_PARENT, RelativeLayout.LayoutParams.MATCH_PARENT)); - new Handler().postDelayed(() -> mBinding.video.setUseController(true),250); + new Handler().postDelayed(() -> mBinding.video.setUseController(true), 250); mBinding.flag.setSelectedPosition(mCurrent); mFullscreen = true; } @@ -255,10 +265,22 @@ public class DetailActivity extends BaseActivity implements KeyDown.Listener { Prefers.putScale(scale); } + private void newHistory() { + mHistory.setKey(getVodKey()); + mHistory.setEpisodeUrl(getEpisode().getUrl()); + mHistory.setVodRemarks(getEpisode().getName()); + mHistory.setCreateTime(System.currentTimeMillis()); + mHistory.setVodPic(mBinding.video.getTag().toString()); + mHistory.setVodName(mBinding.name.getText().toString()); + AppDatabase.get().getHistoryDao().insertOrUpdate(mHistory); + EventBus.getDefault().post(RefreshEvent.recent()); + } + @Subscribe(threadMode = ThreadMode.MAIN) public void onPlaybackStateChanged(PlayerEvent event) { mBinding.progress.getRoot().setVisibility(event.getState() == Player.STATE_BUFFERING ? View.VISIBLE : View.GONE); if (event.getState() == -1) Notify.show(R.string.error_play_parse); + if (event.getState() == Player.STATE_READY) newHistory(); } @Override diff --git a/app/src/leanback/java/com/fongmi/android/tv/ui/activity/HomeActivity.java b/app/src/leanback/java/com/fongmi/android/tv/ui/activity/HomeActivity.java index 6c4cdaa35..13bb3003e 100644 --- a/app/src/leanback/java/com/fongmi/android/tv/ui/activity/HomeActivity.java +++ b/app/src/leanback/java/com/fongmi/android/tv/ui/activity/HomeActivity.java @@ -15,27 +15,38 @@ import androidx.lifecycle.ViewModelProvider; import androidx.recyclerview.widget.RecyclerView; import androidx.viewbinding.ViewBinding; -import com.fongmi.android.tv.api.ApiConfig; import com.fongmi.android.tv.R; +import com.fongmi.android.tv.api.ApiConfig; import com.fongmi.android.tv.bean.Func; +import com.fongmi.android.tv.bean.History; +import com.fongmi.android.tv.bean.Result; import com.fongmi.android.tv.bean.Vod; import com.fongmi.android.tv.databinding.ActivityHomeBinding; +import com.fongmi.android.tv.db.AppDatabase; +import com.fongmi.android.tv.event.RefreshEvent; import com.fongmi.android.tv.model.SiteViewModel; import com.fongmi.android.tv.player.Players; import com.fongmi.android.tv.server.Server; import com.fongmi.android.tv.ui.custom.CustomRowPresenter; import com.fongmi.android.tv.ui.custom.CustomSelector; import com.fongmi.android.tv.ui.presenter.FuncPresenter; +import com.fongmi.android.tv.ui.presenter.HistoryPresenter; import com.fongmi.android.tv.ui.presenter.ProgressPresenter; import com.fongmi.android.tv.ui.presenter.TitlePresenter; import com.fongmi.android.tv.ui.presenter.VodPresenter; import com.fongmi.android.tv.utils.Clock; import com.fongmi.android.tv.utils.Notify; import com.fongmi.android.tv.utils.ResUtil; +import com.google.common.collect.Lists; +import org.greenrobot.eventbus.EventBus; +import org.greenrobot.eventbus.Subscribe; +import org.greenrobot.eventbus.ThreadMode; + +import java.util.ArrayList; import java.util.List; -public class HomeActivity extends BaseActivity implements VodPresenter.OnClickListener { +public class HomeActivity extends BaseActivity implements VodPresenter.OnClickListener, HistoryPresenter.OnClickListener { private ActivityHomeBinding mBinding; private SiteViewModel mSiteViewModel; @@ -61,11 +72,13 @@ public class HomeActivity extends BaseActivity implements VodPresenter.OnClickLi setRecyclerView(); setViewModel(); setAdapter(); + getRecent(); getVideo(); } @Override protected void initEvent() { + EventBus.getDefault().register(this); mFuncPresenter.setOnClickListener(this::onFuncClick); mBinding.recycler.addOnChildViewHolderSelectedListener(new OnChildViewHolderSelectedListener() { @Override @@ -81,6 +94,7 @@ public class HomeActivity extends BaseActivity implements VodPresenter.OnClickLi selector.addPresenter(String.class, new ProgressPresenter()); selector.addPresenter(ListRow.class, new CustomRowPresenter(16), VodPresenter.class); selector.addPresenter(ListRow.class, new CustomRowPresenter(16), FuncPresenter.class); + selector.addPresenter(ListRow.class, new CustomRowPresenter(16), HistoryPresenter.class); mBinding.recycler.setVerticalSpacing(ResUtil.dp2px(16)); mBinding.recycler.setAdapter(new ItemBridgeAdapter(mAdapter = new ArrayObjectAdapter(selector))); } @@ -89,14 +103,7 @@ public class HomeActivity extends BaseActivity implements VodPresenter.OnClickLi mSiteViewModel = new ViewModelProvider(this).get(SiteViewModel.class); mSiteViewModel.result.observe(this, result -> { mAdapter.remove("progress"); - if (result == null) return; - for (List items : result.partition()) { - VodPresenter presenter = new VodPresenter(result.getColumns()); - ArrayObjectAdapter adapter = new ArrayObjectAdapter(presenter); - presenter.setOnClickListener(this); - adapter.addAll(0, items); - mAdapter.add(new ListRow(adapter)); - } + if (result != null) addVideo(result); }); } @@ -108,12 +115,23 @@ public class HomeActivity extends BaseActivity implements VodPresenter.OnClickLi } private void getVideo() { - if (mAdapter.size() > 4) mAdapter.removeItems(4, mAdapter.size() - 4); + if (mAdapter.size() > getRecommendIndex()) mAdapter.removeItems(getRecommendIndex(), mAdapter.size() - getRecommendIndex()); if (ApiConfig.get().getHome().getKey().isEmpty()) return; mSiteViewModel.homeContent(); mAdapter.add("progress"); } + private void addVideo(Result result) { + int columns = result.getList().size() % 6 == 0 ? 6 : 5; + List rows = new ArrayList<>(); + for (List items : Lists.partition(result.getList(), columns)) { + ArrayObjectAdapter adapter = new ArrayObjectAdapter(new VodPresenter(this, columns)); + adapter.addAll(0, items); + rows.add(new ListRow(adapter)); + } + mAdapter.addAll(mAdapter.size(), rows); + } + private ListRow getFuncRow() { ArrayObjectAdapter adapter = new ArrayObjectAdapter(mFuncPresenter = new FuncPresenter()); adapter.add(Func.create(R.string.home_vod)); @@ -124,6 +142,19 @@ public class HomeActivity extends BaseActivity implements VodPresenter.OnClickLi return new ListRow(adapter); } + private void getRecent() { + int recentIndex = getRecentIndex(); + int recommendIndex = getRecommendIndex(); + if (recommendIndex - recentIndex == 2) mAdapter.removeItems(recentIndex, 1); + List items = AppDatabase.get().getHistoryDao().getAll(); + if (items.isEmpty()) return; + HistoryPresenter presenter = new HistoryPresenter(5); + ArrayObjectAdapter adapter = new ArrayObjectAdapter(presenter); + presenter.setOnClickListener(this); + adapter.addAll(0, items); + mAdapter.add(recentIndex, new ListRow(adapter)); + } + private void onFuncClick(Func item) { switch (item.getResId()) { case R.string.home_vod: @@ -135,18 +166,35 @@ public class HomeActivity extends BaseActivity implements VodPresenter.OnClickLi } } + private int getRecentIndex() { + for (int i = 0; i < mAdapter.size(); i++) if (mAdapter.get(i).equals(R.string.home_recent)) return i + 1; + return -1; + } + + private int getRecommendIndex() { + for (int i = 0; i < mAdapter.size(); i++) if (mAdapter.get(i).equals(R.string.home_recommend)) return i + 1; + return -1; + } + @Override public void onItemClick(Vod item) { DetailActivity.start(getActivity(), item.getVodId()); } @Override - protected void onActivityResult(int requestCode, int resultCode, @Nullable Intent data) { - super.onActivityResult(requestCode, resultCode, data); - if (resultCode != RESULT_OK) return; - String type = data != null ? data.getStringExtra("type") : ""; - if (type.equals("thumbnail")) mAdapter.notifyArrayItemRangeChanged(4, mAdapter.size() - 4); - else getVideo(); + public void onItemClick(History item) { + + } + + @Subscribe(threadMode = ThreadMode.MAIN) + public void onAdapterChanged(RefreshEvent event) { + if (event.getType() == RefreshEvent.Type.VIDEO) { + getVideo(); + } else if (event.getType() == RefreshEvent.Type.IMAGE) { + mAdapter.notifyArrayItemRangeChanged(getRecommendIndex(), mAdapter.size() - getRecommendIndex()); + } else if (event.getType() == RefreshEvent.Type.RECENT) { + getRecent(); + } } @Override @@ -162,10 +210,11 @@ public class HomeActivity extends BaseActivity implements VodPresenter.OnClickLi @Override protected void onDestroy() { - ApiConfig.get().release(); - Players.get().release(); - Clock.get().release(); - Server.get().stop(); super.onDestroy(); + Server.get().stop(); + Clock.get().release(); + Players.get().release(); + ApiConfig.get().release(); + EventBus.getDefault().unregister(this); } } \ No newline at end of file diff --git a/app/src/leanback/java/com/fongmi/android/tv/ui/activity/SettingActivity.java b/app/src/leanback/java/com/fongmi/android/tv/ui/activity/SettingActivity.java index e8034387f..5f064616f 100644 --- a/app/src/leanback/java/com/fongmi/android/tv/ui/activity/SettingActivity.java +++ b/app/src/leanback/java/com/fongmi/android/tv/ui/activity/SettingActivity.java @@ -20,24 +20,28 @@ import androidx.leanback.widget.ArrayObjectAdapter; import androidx.leanback.widget.ItemBridgeAdapter; import androidx.viewbinding.ViewBinding; -import com.fongmi.android.tv.api.ApiConfig; import com.fongmi.android.tv.R; +import com.fongmi.android.tv.api.ApiConfig; import com.fongmi.android.tv.bean.Site; import com.fongmi.android.tv.databinding.ActivitySettingBinding; import com.fongmi.android.tv.databinding.DialogConfigBinding; import com.fongmi.android.tv.databinding.DialogSiteBinding; +import com.fongmi.android.tv.db.AppDatabase; +import com.fongmi.android.tv.event.RefreshEvent; import com.fongmi.android.tv.net.Callback; import com.fongmi.android.tv.ui.presenter.SitePresenter; import com.fongmi.android.tv.utils.Notify; import com.fongmi.android.tv.utils.Prefers; import com.fongmi.android.tv.utils.ResUtil; +import org.greenrobot.eventbus.EventBus; + public class SettingActivity extends BaseActivity { private ActivitySettingBinding mBinding; public static void start(Activity activity) { - activity.startActivityForResult(new Intent(activity, SettingActivity.class), 1000); + activity.startActivity(new Intent(activity, SettingActivity.class)); } private final ActivityResultLauncher launcherString = registerForActivityResult(new ActivityResultContracts.RequestPermission(), isGranted -> loadConfig()); @@ -67,9 +71,11 @@ public class SettingActivity extends BaseActivity { bindingDialog.text.setText(Prefers.getUrl()); bindingDialog.text.setSelection(bindingDialog.text.getText().length()); AlertDialog dialog = Notify.show(this, bindingDialog.getRoot(), (dialogInterface, i) -> { + if (bindingDialog.text.getText().toString().equals(Prefers.getUrl())) return; Prefers.putUrl(bindingDialog.text.getText().toString().trim()); mBinding.url.setText(Prefers.getUrl()); Notify.progress(this); + AppDatabase.clear(); checkUrl(); }); bindingDialog.text.setOnEditorActionListener((textView, actionId, event) -> { @@ -93,14 +99,16 @@ public class SettingActivity extends BaseActivity { @Override public void success() { mBinding.home.setText(ApiConfig.get().getHome().getName()); - setResult(RESULT_OK); + EventBus.getDefault().post(RefreshEvent.recent()); + EventBus.getDefault().post(RefreshEvent.video()); Notify.dismiss(); } @Override public void error(int resId) { mBinding.home.setText(ApiConfig.get().getHome().getName()); - setResult(RESULT_OK); + EventBus.getDefault().post(RefreshEvent.recent()); + EventBus.getDefault().post(RefreshEvent.video()); Notify.dismiss(); Notify.show(resId); } @@ -122,11 +130,11 @@ public class SettingActivity extends BaseActivity { } public void setSite(ArrayObjectAdapter adapter, Site item) { + ApiConfig.get().setHome(item); + mBinding.home.setText(item.getName()); for (int i = 0; i < adapter.size(); i++) ((Site) adapter.get(i)).setHome(item); adapter.notifyArrayItemRangeChanged(0, adapter.size()); - mBinding.home.setText(item.getName()); - ApiConfig.get().setHome(item); - setResult(RESULT_OK); + EventBus.getDefault().post(RefreshEvent.video()); Notify.dismiss(); } @@ -134,10 +142,8 @@ public class SettingActivity extends BaseActivity { CharSequence[] array = ResUtil.getStringArray(R.array.select_thumbnail); int index = Prefers.getThumbnail(); index = index == 2 ? 0 : ++index; - mBinding.compress.setText(array[index]); Prefers.putThumbnail(index); - Intent intent = new Intent(); - intent.putExtra("type", "thumbnail"); - setResult(RESULT_OK, intent); + mBinding.compress.setText(array[index]); + EventBus.getDefault().post(RefreshEvent.image()); } } diff --git a/app/src/leanback/java/com/fongmi/android/tv/ui/fragment/VodFragment.java b/app/src/leanback/java/com/fongmi/android/tv/ui/fragment/VodFragment.java index ef4b47fef..8eefd72b6 100644 --- a/app/src/leanback/java/com/fongmi/android/tv/ui/fragment/VodFragment.java +++ b/app/src/leanback/java/com/fongmi/android/tv/ui/fragment/VodFragment.java @@ -15,19 +15,22 @@ import androidx.lifecycle.ViewModelProvider; import com.fongmi.android.tv.R; import com.fongmi.android.tv.bean.Filter; +import com.fongmi.android.tv.bean.Result; import com.fongmi.android.tv.bean.Vod; import com.fongmi.android.tv.databinding.FragmentVodBinding; import com.fongmi.android.tv.model.SiteViewModel; import com.fongmi.android.tv.ui.activity.DetailActivity; import com.fongmi.android.tv.ui.custom.CustomRowPresenter; -import com.fongmi.android.tv.ui.custom.CustomSelector; import com.fongmi.android.tv.ui.custom.CustomScroller; +import com.fongmi.android.tv.ui.custom.CustomSelector; import com.fongmi.android.tv.ui.presenter.FilterPresenter; import com.fongmi.android.tv.ui.presenter.ProgressPresenter; import com.fongmi.android.tv.ui.presenter.VodPresenter; import com.fongmi.android.tv.utils.ResUtil; +import com.google.common.collect.Lists; import com.google.gson.Gson; +import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Objects; @@ -90,15 +93,8 @@ public class VodFragment extends Fragment implements CustomScroller.Callback, Vo mSiteViewModel = new ViewModelProvider(this).get(SiteViewModel.class); mSiteViewModel.result.observe(getViewLifecycleOwner(), result -> { mAdapter.remove("progress"); - if (result == null) return; - mScroller.endLoading(result.getList().isEmpty()); - for (List items : result.partition()) { - VodPresenter presenter = new VodPresenter(result.getColumns()); - ArrayObjectAdapter adapter = new ArrayObjectAdapter(presenter); - presenter.setOnClickListener(this); - adapter.addAll(0, items); - mAdapter.add(new ListRow(adapter)); - } + mScroller.endLoading(result == null || result.getList().isEmpty()); + if (result != null) addVideo(result); }); } @@ -132,6 +128,17 @@ public class VodFragment extends Fragment implements CustomScroller.Callback, Vo mAdapter.add("progress"); } + private void addVideo(Result result) { + int columns = result.getList().size() % 6 == 0 ? 6 : 5; + List rows = new ArrayList<>(); + for (List items : Lists.partition(result.getList(), columns)) { + ArrayObjectAdapter adapter = new ArrayObjectAdapter(new VodPresenter(this, columns)); + adapter.addAll(0, items); + rows.add(new ListRow(adapter)); + } + mAdapter.addAll(mAdapter.size(), rows); + } + @Override public void onItemClick(Vod item) { DetailActivity.start(getActivity(), item.getVodId()); diff --git a/app/src/leanback/java/com/fongmi/android/tv/ui/presenter/HistoryPresenter.java b/app/src/leanback/java/com/fongmi/android/tv/ui/presenter/HistoryPresenter.java new file mode 100644 index 000000000..26ecaf646 --- /dev/null +++ b/app/src/leanback/java/com/fongmi/android/tv/ui/presenter/HistoryPresenter.java @@ -0,0 +1,74 @@ +package com.fongmi.android.tv.ui.presenter; + +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; + +import androidx.annotation.NonNull; +import androidx.leanback.widget.Presenter; + +import com.fongmi.android.tv.R; +import com.fongmi.android.tv.api.ApiConfig; +import com.fongmi.android.tv.bean.History; +import com.fongmi.android.tv.databinding.AdapterVodBinding; +import com.fongmi.android.tv.utils.ImgUtil; +import com.fongmi.android.tv.utils.ResUtil; + +public class HistoryPresenter extends Presenter { + + private OnClickListener mListener; + private int width, height; + + public HistoryPresenter(int columns) { + setLayoutSize(columns); + } + + public interface OnClickListener { + void onItemClick(History item); + } + + public void setOnClickListener(OnClickListener listener) { + this.mListener = listener; + } + + private void setLayoutSize(int columns) { + int space = ResUtil.dp2px(16) * (columns - 1) + ResUtil.dp2px(48); + int base = ResUtil.getScreenWidthPx() - space; + width = (int) base / columns; + height = (int) (width / 0.75); + } + + @Override + public Presenter.ViewHolder onCreateViewHolder(ViewGroup parent) { + ViewHolder holder = new ViewHolder(AdapterVodBinding.inflate(LayoutInflater.from(parent.getContext()), parent, false)); + holder.binding.getRoot().getLayoutParams().width = width; + holder.binding.getRoot().getLayoutParams().height = height; + return holder; + } + + @Override + public void onBindViewHolder(Presenter.ViewHolder viewHolder, Object object) { + History item = (History) object; + ViewHolder holder = (ViewHolder) viewHolder; + holder.binding.name.setText(item.getVodName()); + holder.binding.site.setVisibility(View.VISIBLE); + holder.binding.site.setText(ApiConfig.get().getSite(item.getSiteKey()).getName()); + holder.binding.remark.setText(ResUtil.getString(R.string.vod_last, item.getVodRemarks())); + ImgUtil.load(item.getVodName(), item.getVodPic(), holder.binding.image); + setOnClickListener(holder, view -> mListener.onItemClick(item)); + } + + @Override + public void onUnbindViewHolder(Presenter.ViewHolder viewHolder) { + } + + public static class ViewHolder extends Presenter.ViewHolder { + + private final AdapterVodBinding binding; + + public ViewHolder(@NonNull AdapterVodBinding binding) { + super(binding.getRoot()); + this.binding = binding; + } + } +} \ No newline at end of file diff --git a/app/src/leanback/java/com/fongmi/android/tv/ui/presenter/VodPresenter.java b/app/src/leanback/java/com/fongmi/android/tv/ui/presenter/VodPresenter.java index ba1be3374..2395c086f 100644 --- a/app/src/leanback/java/com/fongmi/android/tv/ui/presenter/VodPresenter.java +++ b/app/src/leanback/java/com/fongmi/android/tv/ui/presenter/VodPresenter.java @@ -8,14 +8,16 @@ import androidx.leanback.widget.Presenter; import com.fongmi.android.tv.bean.Vod; import com.fongmi.android.tv.databinding.AdapterVodBinding; +import com.fongmi.android.tv.utils.ImgUtil; import com.fongmi.android.tv.utils.ResUtil; public class VodPresenter extends Presenter { - private OnClickListener mListener; + private final OnClickListener mListener; private int width, height; - public VodPresenter(int columns) { + public VodPresenter(OnClickListener listener, int columns) { + this.mListener = listener; setLayoutSize(columns); } @@ -23,10 +25,6 @@ public class VodPresenter extends Presenter { void onItemClick(Vod item); } - public void setOnClickListener(OnClickListener listener) { - this.mListener = listener; - } - private void setLayoutSize(int columns) { int space = ResUtil.dp2px(16) * (columns - 1) + ResUtil.dp2px(48); int base = ResUtil.getScreenWidthPx() - space; @@ -46,10 +44,10 @@ public class VodPresenter extends Presenter { public void onBindViewHolder(Presenter.ViewHolder viewHolder, Object object) { Vod item = (Vod) object; ViewHolder holder = (ViewHolder) viewHolder; - item.loadImg(holder.binding.image); holder.binding.name.setText(item.getVodName()); holder.binding.remark.setText(item.getVodRemarks()); holder.binding.remark.setVisibility(item.getRemarkVisible()); + ImgUtil.load(item.getVodName(), item.getVodPic(), holder.binding.image); setOnClickListener(holder, view -> mListener.onItemClick(item)); } diff --git a/app/src/leanback/res/layout/adapter_vod.xml b/app/src/leanback/res/layout/adapter_vod.xml index 326aadb0d..fc665c80a 100644 --- a/app/src/leanback/res/layout/adapter_vod.xml +++ b/app/src/leanback/res/layout/adapter_vod.xml @@ -14,6 +14,20 @@ android:scaleType="center" tools:src="@drawable/ic_img_loading" /> + + callback.error(R.string.error_config_get)); } } diff --git a/app/src/main/java/com/fongmi/android/tv/bean/History.java b/app/src/main/java/com/fongmi/android/tv/bean/History.java new file mode 100644 index 000000000..d15908ede --- /dev/null +++ b/app/src/main/java/com/fongmi/android/tv/bean/History.java @@ -0,0 +1,91 @@ +package com.fongmi.android.tv.bean; + +import androidx.annotation.NonNull; +import androidx.room.Entity; +import androidx.room.PrimaryKey; + +@Entity +public class History { + + @NonNull + @PrimaryKey + private String key; + private String vodPic; + private String vodName; + private String vodRemarks; + private String episodeUrl; + private long createTime; + private long duration; + + public History() { + } + + @NonNull + public String getKey() { + return key; + } + + public void setKey(@NonNull String key) { + this.key = key; + } + + public String getVodPic() { + return vodPic; + } + + public void setVodPic(String vodPic) { + this.vodPic = vodPic; + } + + public String getVodName() { + return vodName; + } + + public void setVodName(String vodName) { + this.vodName = vodName; + } + + public String getVodRemarks() { + return vodRemarks; + } + + public void setVodRemarks(String vodRemarks) { + this.vodRemarks = vodRemarks; + } + + public String getEpisodeUrl() { + return episodeUrl; + } + + public void setEpisodeUrl(String episodeUrl) { + this.episodeUrl = episodeUrl; + } + + public long getCreateTime() { + return createTime; + } + + public void setCreateTime(long createTime) { + this.createTime = createTime; + } + + public long getDuration() { + return duration; + } + + public void setDuration(long duration) { + this.duration = duration; + } + + public String getSiteKey() { + return getKey().split("_")[0]; + } + + public String getFlag() { + return getKey().split("_")[1]; + } + + public String getVodId() { + return getKey().split("_")[2]; + } +} diff --git a/app/src/main/java/com/fongmi/android/tv/bean/Result.java b/app/src/main/java/com/fongmi/android/tv/bean/Result.java index 37d34348e..c53de544e 100644 --- a/app/src/main/java/com/fongmi/android/tv/bean/Result.java +++ b/app/src/main/java/com/fongmi/android/tv/bean/Result.java @@ -2,7 +2,6 @@ package com.fongmi.android.tv.bean; import androidx.annotation.NonNull; -import com.google.common.collect.Lists; import com.google.gson.Gson; import com.google.gson.GsonBuilder; import com.google.gson.JsonDeserializationContext; @@ -81,14 +80,6 @@ public class Result { return filters == null ? new LinkedHashMap<>() : filters; } - public List> partition() { - return Lists.partition(getList(), getColumns()); - } - - public int getColumns() { - return getList().size() % 6 == 0 ? 6 : 5; - } - @NonNull @Override public String toString() { diff --git a/app/src/main/java/com/fongmi/android/tv/bean/Vod.java b/app/src/main/java/com/fongmi/android/tv/bean/Vod.java index c405c9426..c53bb4216 100644 --- a/app/src/main/java/com/fongmi/android/tv/bean/Vod.java +++ b/app/src/main/java/com/fongmi/android/tv/bean/Vod.java @@ -2,14 +2,10 @@ package com.fongmi.android.tv.bean; import android.text.TextUtils; import android.view.View; -import android.widget.ImageView; import androidx.annotation.NonNull; -import com.amulyakhare.textdrawable.TextDrawable; -import com.amulyakhare.textdrawable.util.ColorGenerator; import com.fongmi.android.tv.R; -import com.fongmi.android.tv.utils.ImgUtil; import com.fongmi.android.tv.utils.ResUtil; import com.google.gson.Gson; import com.google.gson.annotations.SerializedName; @@ -77,10 +73,6 @@ public class Vod { @ElementList(entry = "dd", required = false, inline = true) private List vodFlags; - public static Vod objectFrom(String str) { - return new Gson().fromJson(str, Vod.class); - } - public String getVodId() { return TextUtils.isEmpty(vodId) ? "" : vodId; } @@ -137,15 +129,6 @@ public class Vod { return getVodRemarks().isEmpty() ? View.GONE : View.VISIBLE; } - public void loadImg(ImageView view) { - if (TextUtils.isEmpty(getVodPic())) { - String text = getVodName().isEmpty() ? "" : getVodName().substring(0, 1); - view.setImageDrawable(TextDrawable.builder().buildRect(text, ColorGenerator.MATERIAL.getColor(text))); - } else { - ImgUtil.load(getVodPic(), view); - } - } - public void setVodFlags() { String[] playFlags = getVodPlayFrom().split("\\$\\$\\$"); String[] playUrls = getVodPlayUrl().split("\\$\\$\\$"); diff --git a/app/src/main/java/com/fongmi/android/tv/db/AppDatabase.java b/app/src/main/java/com/fongmi/android/tv/db/AppDatabase.java new file mode 100644 index 000000000..1945684ae --- /dev/null +++ b/app/src/main/java/com/fongmi/android/tv/db/AppDatabase.java @@ -0,0 +1,34 @@ +package com.fongmi.android.tv.db; + +import android.content.Context; + +import androidx.room.Database; +import androidx.room.Room; +import androidx.room.RoomDatabase; + +import com.fongmi.android.tv.App; +import com.fongmi.android.tv.bean.History; +import com.fongmi.android.tv.db.dao.HistoryDao; + +@Database(entities = {History.class}, version = AppDatabase.VERSION, exportSchema = false) +public abstract class AppDatabase extends RoomDatabase { + + public static final int VERSION = 1; + + private static volatile AppDatabase instance; + + public static synchronized AppDatabase get() { + if (instance == null) instance = create(App.get()); + return instance; + } + + private static AppDatabase create(Context context) { + return Room.databaseBuilder(context, AppDatabase.class, "tv").allowMainThreadQueries().fallbackToDestructiveMigration().build(); + } + + public abstract HistoryDao getHistoryDao(); + + public static void clear() { + get().getHistoryDao().delete(); + } +} diff --git a/app/src/main/java/com/fongmi/android/tv/db/dao/BaseDao.java b/app/src/main/java/com/fongmi/android/tv/db/dao/BaseDao.java new file mode 100644 index 000000000..98b3c3967 --- /dev/null +++ b/app/src/main/java/com/fongmi/android/tv/db/dao/BaseDao.java @@ -0,0 +1,40 @@ +package com.fongmi.android.tv.db.dao; + +import androidx.room.Dao; +import androidx.room.Insert; +import androidx.room.OnConflictStrategy; +import androidx.room.Transaction; +import androidx.room.Update; + +import java.util.ArrayList; +import java.util.List; + +@Dao +public abstract class BaseDao { + + @Insert(onConflict = OnConflictStrategy.IGNORE) + public abstract Long insert(T item); + + @Insert(onConflict = OnConflictStrategy.IGNORE) + public abstract List insert(List items); + + @Update + public abstract void update(T item); + + @Update + public abstract void update(List items); + + @Transaction + public void insertOrUpdate(T item) { + long id = insert(item); + if (id == -1) update(item); + } + + @Transaction + public void insertOrUpdate(List items) { + List result = insert(items); + List list = new ArrayList<>(); + for (int i = 0; i < result.size(); i++) if (result.get(i) == -1) list.add(items.get(i)); + if (list.size() > 0) update(list); + } +} diff --git a/app/src/main/java/com/fongmi/android/tv/db/dao/HistoryDao.java b/app/src/main/java/com/fongmi/android/tv/db/dao/HistoryDao.java new file mode 100644 index 000000000..077a10209 --- /dev/null +++ b/app/src/main/java/com/fongmi/android/tv/db/dao/HistoryDao.java @@ -0,0 +1,18 @@ +package com.fongmi.android.tv.db.dao; + +import androidx.room.Dao; +import androidx.room.Query; + +import com.fongmi.android.tv.bean.History; + +import java.util.List; + +@Dao +public abstract class HistoryDao extends BaseDao { + + @Query("SELECT * FROM history ORDER BY createTime DESC") + public abstract List getAll(); + + @Query("DELETE FROM history") + public abstract void delete(); +} diff --git a/app/src/main/java/com/fongmi/android/tv/event/RefreshEvent.java b/app/src/main/java/com/fongmi/android/tv/event/RefreshEvent.java new file mode 100644 index 000000000..28205f45a --- /dev/null +++ b/app/src/main/java/com/fongmi/android/tv/event/RefreshEvent.java @@ -0,0 +1,30 @@ +package com.fongmi.android.tv.event; + +public class RefreshEvent { + + private final Type type; + + public static RefreshEvent image() { + return new RefreshEvent(Type.IMAGE); + } + + public static RefreshEvent video() { + return new RefreshEvent(Type.VIDEO); + } + + public static RefreshEvent recent() { + return new RefreshEvent(Type.RECENT); + } + + public RefreshEvent(Type type) { + this.type = type; + } + + public Type getType() { + return type; + } + + public enum Type { + IMAGE, VIDEO, RECENT + } +} diff --git a/app/src/main/java/com/fongmi/android/tv/utils/ImgUtil.java b/app/src/main/java/com/fongmi/android/tv/utils/ImgUtil.java index a7a925e06..4127315c1 100644 --- a/app/src/main/java/com/fongmi/android/tv/utils/ImgUtil.java +++ b/app/src/main/java/com/fongmi/android/tv/utils/ImgUtil.java @@ -1,10 +1,13 @@ package com.fongmi.android.tv.utils; import android.graphics.drawable.Drawable; +import android.text.TextUtils; import android.widget.ImageView; import androidx.annotation.Nullable; +import com.amulyakhare.textdrawable.TextDrawable; +import com.amulyakhare.textdrawable.util.ColorGenerator; import com.bumptech.glide.Glide; import com.bumptech.glide.load.DataSource; import com.bumptech.glide.load.engine.GlideException; @@ -16,6 +19,15 @@ import com.fongmi.android.tv.R; public class ImgUtil { + public static void load(String vodName, String vodPic, ImageView view) { + if (TextUtils.isEmpty(vodPic)) { + String text = vodName.isEmpty() ? "" : vodName.substring(0, 1); + view.setImageDrawable(TextDrawable.builder().buildRect(text, ColorGenerator.MATERIAL.getColor(text))); + } else { + ImgUtil.load(vodPic, view); + } + } + public static void load(String url, ImageView view) { float thumbnail = 1 - Prefers.getThumbnail() * 0.3f; Glide.with(App.get()).load(url).thumbnail(thumbnail).signature(new ObjectKey(url + "_" + thumbnail)).placeholder(R.drawable.ic_img_loading).error(R.drawable.ic_img_error).listener(getListener(view)).into(view); diff --git a/app/src/main/res/values-zh-rCN/strings.xml b/app/src/main/res/values-zh-rCN/strings.xml index b52ebf5f5..33c300823 100644 --- a/app/src/main/res/values-zh-rCN/strings.xml +++ b/app/src/main/res/values-zh-rCN/strings.xml @@ -16,6 +16,9 @@ 最近观看 更新推荐 + + 上次看到%s + 站源:%s 年份:%s diff --git a/app/src/main/res/values-zh-rTW/strings.xml b/app/src/main/res/values-zh-rTW/strings.xml index 5682f69c8..aef71ec96 100644 --- a/app/src/main/res/values-zh-rTW/strings.xml +++ b/app/src/main/res/values-zh-rTW/strings.xml @@ -16,6 +16,9 @@ 最近觀看 更新推薦 + + 上次看到%s + 站源:%s 年份:%s diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 8bdcd0021..909f2de6a 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -16,6 +16,9 @@ Recent Recommend + + Last seen %s + Site: %s Year: %s