Support search - part 1

pull/21/head
FongMi 4 years ago
parent d4e42ef5ba
commit a7521e59df
  1. 11
      app/src/leanback/AndroidManifest.xml
  2. 2
      app/src/leanback/java/com/fongmi/android/tv/ui/activity/DetailActivity.java
  3. 16
      app/src/leanback/java/com/fongmi/android/tv/ui/activity/HomeActivity.java
  4. 145
      app/src/leanback/java/com/fongmi/android/tv/ui/activity/SearchActivity.java
  5. 2
      app/src/leanback/java/com/fongmi/android/tv/ui/activity/VodActivity.java
  6. 8
      app/src/leanback/java/com/fongmi/android/tv/ui/custom/CustomVerticalGridView.java
  7. 2
      app/src/leanback/java/com/fongmi/android/tv/ui/fragment/VodFragment.java
  8. 2
      app/src/leanback/java/com/fongmi/android/tv/ui/presenter/TitlePresenter.java
  9. 58
      app/src/leanback/res/layout/activity_search.xml
  10. 12
      app/src/main/java/com/fongmi/android/tv/bean/Site.java
  11. 10
      app/src/main/java/com/fongmi/android/tv/bean/Vod.java
  12. 36
      app/src/main/java/com/fongmi/android/tv/model/SiteViewModel.java

@ -35,12 +35,12 @@
</activity>
<activity
android:name=".ui.activity.HomeActivity"
android:name=".ui.activity.DetailActivity"
android:configChanges="screenSize|smallestScreenSize|screenLayout|orientation"
android:screenOrientation="sensorLandscape" />
<activity
android:name=".ui.activity.VodActivity"
android:name=".ui.activity.HomeActivity"
android:configChanges="screenSize|smallestScreenSize|screenLayout|orientation"
android:screenOrientation="sensorLandscape" />
@ -50,7 +50,7 @@
android:screenOrientation="sensorLandscape" />
<activity
android:name=".ui.activity.DetailActivity"
android:name=".ui.activity.SearchActivity"
android:configChanges="screenSize|smallestScreenSize|screenLayout|orientation"
android:screenOrientation="sensorLandscape" />
@ -59,5 +59,10 @@
android:configChanges="screenSize|smallestScreenSize|screenLayout|orientation"
android:screenOrientation="sensorLandscape" />
<activity
android:name=".ui.activity.VodActivity"
android:configChanges="screenSize|smallestScreenSize|screenLayout|orientation"
android:screenOrientation="sensorLandscape" />
</application>
</manifest>

@ -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;

@ -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

@ -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<ListRow> rows = new ArrayList<>();
for (List<Vod> 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();
}
}

@ -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;

@ -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;
}
}

@ -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));

@ -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

@ -0,0 +1,58 @@
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:keepScreenOn="true">
<androidx.leanback.widget.VerticalGridView
android:id="@+id/recycler"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:clipChildren="false"
android:clipToPadding="false"
android:paddingStart="24dp"
android:paddingTop="24dp"
android:paddingEnd="24dp"
android:paddingBottom="24dp"
android:visibility="gone"
app:focusOutEnd="true"
app:focusOutFront="true" />
<LinearLayout
android:id="@+id/layout"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerInParent="true"
android:layout_marginStart="24dp"
android:layout_marginEnd="24dp"
android:gravity="center"
android:orientation="horizontal">
<EditText
android:id="@+id/keyword"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginEnd="24dp"
android:background="@drawable/selector_item"
android:hint="輸入關鍵字..."
android:importantForAutofill="no"
android:inputType="textCapCharacters|textAutoCorrect|textAutoComplete"
android:maxLength="20"
android:singleLine="true"
android:textColor="@color/white"
android:textColorHint="@color/white"
android:textSize="24sp" />
<ImageView
android:id="@+id/search"
android:layout_width="48dp"
android:layout_height="48dp"
android:background="@drawable/selector_item"
android:focusable="true"
android:focusableInTouchMode="true"
android:scaleType="fitCenter"
android:src="@drawable/ic_search" />
</LinearLayout>
</RelativeLayout>

@ -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() {

@ -73,6 +73,8 @@ public class Vod {
@ElementList(entry = "dd", required = false, inline = true)
private List<Flag> 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;
}

@ -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> result, Callable<Result> callable) {
if (service != null) service.shutdownNow();
service = Executors.newFixedThreadPool(2);

Loading…
Cancel
Save