From a7521e59df640019aedac77bf447b2dd412d6c7a Mon Sep 17 00:00:00 2001 From: FongMi Date: Mon, 8 Aug 2022 18:21:43 +0800 Subject: [PATCH] Support search - part 1 --- app/src/leanback/AndroidManifest.xml | 11 +- .../tv/ui/activity/DetailActivity.java | 2 +- .../android/tv/ui/activity/HomeActivity.java | 16 +- .../tv/ui/activity/SearchActivity.java | 145 ++++++++++++++++++ .../android/tv/ui/activity/VodActivity.java | 2 +- .../tv/ui/custom/CustomVerticalGridView.java | 8 +- .../android/tv/ui/fragment/VodFragment.java | 2 - .../tv/ui/presenter/TitlePresenter.java | 2 +- .../leanback/res/layout/activity_search.xml | 58 +++++++ .../java/com/fongmi/android/tv/bean/Site.java | 12 +- .../java/com/fongmi/android/tv/bean/Vod.java | 10 ++ .../android/tv/model/SiteViewModel.java | 36 ++++- 12 files changed, 278 insertions(+), 26 deletions(-) create mode 100644 app/src/leanback/java/com/fongmi/android/tv/ui/activity/SearchActivity.java create mode 100644 app/src/leanback/res/layout/activity_search.xml diff --git a/app/src/leanback/AndroidManifest.xml b/app/src/leanback/AndroidManifest.xml index b6c54d647..6b39a67a5 100644 --- a/app/src/leanback/AndroidManifest.xml +++ b/app/src/leanback/AndroidManifest.xml @@ -35,12 +35,12 @@ @@ -50,7 +50,7 @@ android:screenOrientation="sensorLandscape" /> @@ -59,5 +59,10 @@ android:configChanges="screenSize|smallestScreenSize|screenLayout|orientation" android:screenOrientation="sensorLandscape" /> + + \ No newline at end of file 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 5a1c1bd29..d38b54e64 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 @@ -49,9 +49,9 @@ import java.util.List; public class DetailActivity extends BaseActivity implements KeyDown.Listener { + private ActivityDetailBinding mBinding; private ViewControllerBottomBinding mControl; private ViewGroup.LayoutParams mFrameParams; - private ActivityDetailBinding mBinding; private ArrayObjectAdapter mFlagAdapter; private ArrayObjectAdapter mGroupAdapter; private ArrayObjectAdapter mEpisodeAdapter; 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 b4cfad076..2893d605d 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 @@ -51,11 +51,11 @@ import java.util.List; public class HomeActivity extends BaseActivity implements VodPresenter.OnClickListener, FuncPresenter.OnClickListener, HistoryPresenter.OnClickListener { private ActivityHomeBinding mBinding; - private SiteViewModel mSiteViewModel; private ArrayObjectAdapter mAdapter; private ArrayObjectAdapter mHistoryAdapter; private HistoryPresenter mHistoryPresenter; private FuncPresenter mFuncPresenter; + private SiteViewModel mSiteViewModel; private boolean mConfirmExit; public static void start(Activity activity) { @@ -174,6 +174,9 @@ public class HomeActivity extends BaseActivity implements VodPresenter.OnClickLi case R.string.home_vod: VodActivity.start(this, mSiteViewModel.getResult().getValue()); break; + case R.string.home_search: + SearchActivity.start(this); + break; case R.string.home_push: PushActivity.start(this); break; @@ -223,8 +226,15 @@ public class HomeActivity extends BaseActivity implements VodPresenter.OnClickLi @Subscribe(threadMode = ThreadMode.MAIN) public void onServerEvent(ServerEvent event) { - if (event.getType() != ServerEvent.Type.PUSH || ApiConfig.get().getSite("push_agent") == null) return; - DetailActivity.start(this, "push_agent", event.getText()); + switch (event.getType()) { + case SEARCH: + SearchActivity.start(this, event.getText()); + break; + case PUSH: + if (ApiConfig.get().getSite("push_agent") == null) return; + DetailActivity.start(this, "push_agent", event.getText()); + break; + } } @Override diff --git a/app/src/leanback/java/com/fongmi/android/tv/ui/activity/SearchActivity.java b/app/src/leanback/java/com/fongmi/android/tv/ui/activity/SearchActivity.java new file mode 100644 index 000000000..f2d3ad626 --- /dev/null +++ b/app/src/leanback/java/com/fongmi/android/tv/ui/activity/SearchActivity.java @@ -0,0 +1,145 @@ +package com.fongmi.android.tv.ui.activity; + +import android.app.Activity; +import android.content.Intent; +import android.text.TextUtils; +import android.view.View; +import android.view.inputmethod.EditorInfo; + +import androidx.leanback.widget.ArrayObjectAdapter; +import androidx.leanback.widget.ItemBridgeAdapter; +import androidx.leanback.widget.ListRow; +import androidx.lifecycle.ViewModelProvider; +import androidx.viewbinding.ViewBinding; + +import com.fongmi.android.tv.api.ApiConfig; +import com.fongmi.android.tv.bean.Result; +import com.fongmi.android.tv.bean.Site; +import com.fongmi.android.tv.bean.Vod; +import com.fongmi.android.tv.databinding.ActivitySearchBinding; +import com.fongmi.android.tv.model.SiteViewModel; +import com.fongmi.android.tv.ui.custom.CustomRowPresenter; +import com.fongmi.android.tv.ui.custom.CustomSelector; +import com.fongmi.android.tv.ui.presenter.TitlePresenter; +import com.fongmi.android.tv.ui.presenter.VodPresenter; +import com.fongmi.android.tv.utils.ResUtil; +import com.google.common.collect.Lists; + +import java.util.ArrayList; +import java.util.List; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; + +public class SearchActivity extends BaseActivity implements VodPresenter.OnClickListener { + + private ActivitySearchBinding mBinding; + private SiteViewModel mSiteViewModel; + private ArrayObjectAdapter mAdapter; + private ExecutorService mService; + + public static void start(Activity activity) { + start(activity, ""); + } + + public static void start(Activity activity, String keyword) { + Intent intent = new Intent(activity, SearchActivity.class); + intent.putExtra("keyword", keyword); + //activity.startActivity(intent); + } + + @Override + protected ViewBinding getBinding() { + return mBinding = ActivitySearchBinding.inflate(getLayoutInflater()); + } + + @Override + protected void initView() { + setRecyclerView(); + setViewModel(); + } + + @Override + protected void initEvent() { + mBinding.search.setOnClickListener(view -> startSearch()); + mBinding.keyword.setOnEditorActionListener((textView, actionId, event) -> { + if (actionId == EditorInfo.IME_ACTION_DONE) mBinding.search.performClick(); + return true; + }); + } + + private void setRecyclerView() { + CustomSelector selector = new CustomSelector(); + selector.addPresenter(String.class, new TitlePresenter()); + selector.addPresenter(ListRow.class, new CustomRowPresenter(16), VodPresenter.class); + mBinding.recycler.setVerticalSpacing(ResUtil.dp2px(16)); + mBinding.recycler.setAdapter(new ItemBridgeAdapter(mAdapter = new ArrayObjectAdapter(selector))); + } + + private void setViewModel() { + mSiteViewModel = new ViewModelProvider(this).get(SiteViewModel.class); + mSiteViewModel.result.observe(this, this::addVideo); + } + + private void addVideo(Result result) { + List rows = new ArrayList<>(); + for (List items : Lists.partition(result.getList(), 5)) { + ArrayObjectAdapter adapter = new ArrayObjectAdapter(new VodPresenter(this, 5)); + adapter.addAll(0, items); + rows.add(new ListRow(adapter)); + } + mAdapter.add(result.getList().get(0).getSite().getName()); + mAdapter.addAll(mAdapter.size(), rows); + } + + private void startSearch() { + String keyword = mBinding.keyword.getText().toString().trim(); + if (TextUtils.isEmpty(keyword)) return; + hideLayout(); + mService = Executors.newFixedThreadPool(5); + for (Site item : ApiConfig.get().getSites()) { + if (item.isSearchable()) { + mService.execute(() -> mSiteViewModel.searchContent(item.getKey(), keyword)); + } + } + } + + private void stopSearch() { + if (mService != null) { + mService.shutdownNow(); + mService = null; + } + } + + private void showLayout() { + mAdapter.clear(); + mBinding.layout.setVisibility(View.VISIBLE); + mBinding.recycler.setVisibility(View.INVISIBLE); + } + + private void hideLayout() { + mBinding.keyword.setText(""); + mBinding.layout.setVisibility(View.GONE); + mBinding.recycler.setVisibility(View.VISIBLE); + } + + @Override + public void onItemClick(Vod item) { + DetailActivity.start(this, item.getSite().getKey(), item.getVodId()); + } + + @Override + public void onBackPressed() { + if (mBinding.recycler.getVisibility() == View.VISIBLE) { + stopSearch(); + showLayout(); + } else { + super.onBackPressed(); + } + } + + @Override + protected void onDestroy() { + super.onDestroy(); + stopSearch(); + } +} diff --git a/app/src/leanback/java/com/fongmi/android/tv/ui/activity/VodActivity.java b/app/src/leanback/java/com/fongmi/android/tv/ui/activity/VodActivity.java index 2fec56d5e..e7a41996c 100644 --- a/app/src/leanback/java/com/fongmi/android/tv/ui/activity/VodActivity.java +++ b/app/src/leanback/java/com/fongmi/android/tv/ui/activity/VodActivity.java @@ -30,8 +30,8 @@ import java.util.List; public class VodActivity extends BaseActivity { - private TypePresenter mTypePresenter; private ActivityVodBinding mBinding; + private TypePresenter mTypePresenter; private Result mResult; private View mOldView; diff --git a/app/src/leanback/java/com/fongmi/android/tv/ui/custom/CustomVerticalGridView.java b/app/src/leanback/java/com/fongmi/android/tv/ui/custom/CustomVerticalGridView.java index 5fb76ac07..429f91e87 100644 --- a/app/src/leanback/java/com/fongmi/android/tv/ui/custom/CustomVerticalGridView.java +++ b/app/src/leanback/java/com/fongmi/android/tv/ui/custom/CustomVerticalGridView.java @@ -35,6 +35,7 @@ public class CustomVerticalGridView extends VerticalGridView { setOnChildViewHolderSelectedListener(new OnChildViewHolderSelectedListener() { @Override public void onChildViewHolderSelected(@NonNull RecyclerView parent, @Nullable ViewHolder child, int position, int subposition) { + if (mTabView == null) return; if (pressUp && position == 0) { mTabView.setVisibility(View.VISIBLE); } else if (pressDown && position == 1) { @@ -61,16 +62,17 @@ public class CustomVerticalGridView extends VerticalGridView { pressDown = true; return super.dispatchKeyEvent(event); case KeyEvent.KEYCODE_BACK: - moveToTop(); - return true; + return moveToTop(); default: return super.dispatchKeyEvent(event); } } - public void moveToTop() { + public boolean moveToTop() { + if (mTabView == null) return false; mTabView.setVisibility(View.VISIBLE); mTabView.requestFocus(); scrollToPosition(0); + return true; } } 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 ece440f86..95f796b2b 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 @@ -24,7 +24,6 @@ import com.fongmi.android.tv.ui.custom.CustomRowPresenter; 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; @@ -80,7 +79,6 @@ public class VodFragment extends Fragment implements CustomScroller.Callback, Vo private void setRecyclerView() { CustomSelector selector = new CustomSelector(); - selector.addPresenter(String.class, new ProgressPresenter()); selector.addPresenter(ListRow.class, new CustomRowPresenter(16), VodPresenter.class); selector.addPresenter(ListRow.class, new CustomRowPresenter(8), FilterPresenter.class); mBinding.recycler.addOnScrollListener(mScroller = new CustomScroller(this)); diff --git a/app/src/leanback/java/com/fongmi/android/tv/ui/presenter/TitlePresenter.java b/app/src/leanback/java/com/fongmi/android/tv/ui/presenter/TitlePresenter.java index 6cab2986a..6fe1c1659 100644 --- a/app/src/leanback/java/com/fongmi/android/tv/ui/presenter/TitlePresenter.java +++ b/app/src/leanback/java/com/fongmi/android/tv/ui/presenter/TitlePresenter.java @@ -19,7 +19,7 @@ public class TitlePresenter extends Presenter { @Override public void onBindViewHolder(Presenter.ViewHolder viewHolder, Object object) { TitlePresenter.ViewHolder holder = (TitlePresenter.ViewHolder) viewHolder; - holder.binding.text.setText(ResUtil.getString((int) object)); + holder.binding.text.setText(object instanceof String ? object.toString() : ResUtil.getString((int) object)); } @Override diff --git a/app/src/leanback/res/layout/activity_search.xml b/app/src/leanback/res/layout/activity_search.xml new file mode 100644 index 000000000..15e96e2ed --- /dev/null +++ b/app/src/leanback/res/layout/activity_search.xml @@ -0,0 +1,58 @@ + + + + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/java/com/fongmi/android/tv/bean/Site.java b/app/src/main/java/com/fongmi/android/tv/bean/Site.java index 1669127a5..e46a94880 100644 --- a/app/src/main/java/com/fongmi/android/tv/bean/Site.java +++ b/app/src/main/java/com/fongmi/android/tv/bean/Site.java @@ -68,16 +68,16 @@ public class Site { return TextUtils.isEmpty(playerUrl) ? "" : playerUrl; } - public Integer getSearchable() { - return searchable == null ? 1 : searchable; + public boolean isSearchable() { + return searchable == null || searchable == 1; } - public Integer getQuickSearch() { - return quickSearch == null ? 1 : quickSearch; + public boolean isQuickSearch() { + return quickSearch == null || quickSearch == 1; } - public Integer getFilterable() { - return filterable == null ? 1 : filterable; + public boolean isFilterable() { + return filterable == null || filterable == 1; } public String getExt() { 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 1e149c472..fc71a367d 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 @@ -73,6 +73,8 @@ public class Vod { @ElementList(entry = "dd", required = false, inline = true) private List vodFlags; + private Site site; + public String getVodId() { return TextUtils.isEmpty(vodId) ? "" : vodId; } @@ -125,6 +127,14 @@ public class Vod { return vodFlags = vodFlags == null ? new ArrayList<>() : vodFlags; } + public Site getSite() { + return site; + } + + public void setSite(Site site) { + this.site = site; + } + public int getRemarkVisible() { return getVodRemarks().isEmpty() ? View.GONE : View.VISIBLE; } diff --git a/app/src/main/java/com/fongmi/android/tv/model/SiteViewModel.java b/app/src/main/java/com/fongmi/android/tv/model/SiteViewModel.java index 3fb572404..b0aa902bd 100644 --- a/app/src/main/java/com/fongmi/android/tv/model/SiteViewModel.java +++ b/app/src/main/java/com/fongmi/android/tv/model/SiteViewModel.java @@ -6,6 +6,7 @@ import androidx.lifecycle.ViewModel; import com.fongmi.android.tv.api.ApiConfig; import com.fongmi.android.tv.bean.Result; import com.fongmi.android.tv.bean.Site; +import com.fongmi.android.tv.bean.Vod; import com.fongmi.android.tv.net.OKHttp; import com.fongmi.android.tv.utils.Utils; import com.github.catvod.crawler.Spider; @@ -52,8 +53,7 @@ public class SiteViewModel extends ViewModel { String body = OKHttp.newCall(home.getApi()).execute().body().string(); SpiderDebug.log(body); if (home.getType() == 0) return Result.fromXml(body); - else if (home.getType() == 1) return Result.fromJson(body); - else return new Result(); + else return Result.fromJson(body); } }); } @@ -71,8 +71,7 @@ public class SiteViewModel extends ViewModel { String body = OKHttp.newCall(url).execute().body().string(); SpiderDebug.log(body); if (home.getType() == 0) return Result.fromXml(body); - else if (home.getType() == 1) return Result.fromJson(body); - return new Result(); + else return Result.fromJson(body); } }); } @@ -93,8 +92,7 @@ public class SiteViewModel extends ViewModel { SpiderDebug.log(body); Result result; if (site.getType() == 0) result = Result.fromXml(body); - else if (site.getType() == 1) result = Result.fromJson(body); - else result = new Result(); + else result = Result.fromJson(body); if (!result.getList().isEmpty()) result.getList().get(0).setVodFlags(); return result; } @@ -122,6 +120,32 @@ public class SiteViewModel extends ViewModel { }); } + public void searchContent(String key, String keyword) { + try { + Site site = ApiConfig.get().getSite(key); + if (site.getType() == 3) { + Spider spider = ApiConfig.get().getCSP(site); + String searchContent = spider.searchContent(keyword, false); + SpiderDebug.log(searchContent); + postSearch(site, Result.fromJson(searchContent)); + } else { + HttpUrl.Builder builder = HttpUrl.parse(site.getApi()).newBuilder().addQueryParameter("wd", keyword); + if (site.getType() == 1) builder.addQueryParameter("ac", "detail"); + String body = OKHttp.newCall(builder.build()).execute().body().string(); + SpiderDebug.log(body); + if (site.getType() == 0) postSearch(site, Result.fromXml(body)); + else postSearch(site, Result.fromJson(body)); + } + } catch (Exception e) { + e.printStackTrace(); + } + } + + private void postSearch(Site site, Result item) { + for (Vod vod : item.getList()) vod.setSite(site); + if (!item.getList().isEmpty()) result.postValue(item); + } + private void execute(MutableLiveData result, Callable callable) { if (service != null) service.shutdownNow(); service = Executors.newFixedThreadPool(2);