[mobile] add vod fragment

pull/137/head
FongMi 4 years ago
parent db10346659
commit 89ca49302b
  1. 9
      app/src/main/java/com/fongmi/android/tv/bean/Class.java
  2. 1
      app/src/main/java/com/fongmi/android/tv/utils/ImgUtil.java
  3. 92
      app/src/mobile/java/com/fongmi/android/tv/ui/adapter/TypeAdapter.java
  4. 3
      app/src/mobile/java/com/fongmi/android/tv/ui/adapter/VodAdapter.java
  5. 127
      app/src/mobile/java/com/fongmi/android/tv/ui/fragment/ChildFragment.java
  6. 5
      app/src/mobile/java/com/fongmi/android/tv/ui/fragment/HomeFragment.java
  7. 81
      app/src/mobile/java/com/fongmi/android/tv/ui/fragment/VodFragment.java
  8. 5
      app/src/mobile/res/drawable/selector_item_round.xml
  9. 15
      app/src/mobile/res/drawable/shape_item_round_activated.xml
  10. 15
      app/src/mobile/res/drawable/shape_item_round_normal.xml
  11. 12
      app/src/mobile/res/layout/adapter_type.xml
  12. 18
      app/src/mobile/res/layout/fragment_child.xml
  13. 23
      app/src/mobile/res/layout/fragment_home.xml
  14. 35
      app/src/mobile/res/layout/fragment_vod.xml
  15. 4
      app/src/mobile/res/values-zh-rCN/strings.xml
  16. 4
      app/src/mobile/res/values-zh-rTW/strings.xml
  17. 4
      app/src/mobile/res/values/strings.xml

@ -24,6 +24,7 @@ public class Class {
private String typeFlag;
private Boolean filter;
private boolean activated;
public String getTypeId() {
return typeId;
@ -45,6 +46,14 @@ public class Class {
return filter;
}
public boolean isActivated() {
return activated;
}
public void setActivated(boolean activated) {
this.activated = activated;
}
public Class toggleFilter() {
setFilter(!getFilter());
return this;

@ -18,6 +18,7 @@ import com.fongmi.android.tv.R;
public class ImgUtil {
public static void load(String vodPic, ImageView view) {
view.setScaleType(ImageView.ScaleType.CENTER);
if (TextUtils.isEmpty(vodPic)) view.setImageResource(R.drawable.ic_img_error);
else Glide.with(App.get()).asBitmap().load(vodPic).skipMemoryCache(true).sizeMultiplier(Prefers.getThumbnail()).signature(new ObjectKey(vodPic + "_" + Prefers.getQuality())).placeholder(R.drawable.ic_img_loading).listener(getListener(view)).into(view);
}

@ -0,0 +1,92 @@
package com.fongmi.android.tv.ui.adapter;
import android.view.LayoutInflater;
import android.view.ViewGroup;
import androidx.annotation.NonNull;
import androidx.recyclerview.widget.RecyclerView;
import com.fongmi.android.tv.bean.Class;
import com.fongmi.android.tv.databinding.AdapterTypeBinding;
import com.fongmi.android.tv.utils.ResUtil;
import java.util.ArrayList;
import java.util.List;
public class TypeAdapter extends RecyclerView.Adapter<TypeAdapter.ViewHolder> {
private OnClickListener mListener;
private final List<Class> mItems;
public TypeAdapter() {
this.mItems = new ArrayList<>();
}
public void setListener(OnClickListener listener) {
this.mListener = listener;
}
public interface OnClickListener {
void onItemClick(Class item);
}
static class ViewHolder extends RecyclerView.ViewHolder {
private final AdapterTypeBinding binding;
ViewHolder(@NonNull AdapterTypeBinding binding) {
super(binding.getRoot());
this.binding = binding;
}
}
public void addAll(List<Class> items) {
if (items.isEmpty()) return;
mItems.clear();
mItems.addAll(items);
mItems.get(0).setActivated(true);
notifyDataSetChanged();
}
public int setActivated(Class item) {
int position = mItems.indexOf(item);
setActivated(position);
return position;
}
public void setActivated(int position) {
for (Class item : mItems) item.setActivated(false);
mItems.get(position).setActivated(true);
notifyItemRangeChanged(0, mItems.size());
}
public List<Class> getTypes() {
return mItems;
}
public Class get(int position) {
return mItems.get(position);
}
@Override
public int getItemCount() {
return mItems.size();
}
@NonNull
@Override
public ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
return new ViewHolder(AdapterTypeBinding.inflate(LayoutInflater.from(parent.getContext()), parent, false));
}
@Override
public void onBindViewHolder(@NonNull ViewHolder holder, int position) {
Class item = mItems.get(position);
holder.binding.text.setText(item.getTypeName());
holder.binding.text.setActivated(item.isActivated());
holder.binding.text.setCompoundDrawablePadding(ResUtil.dp2px(4));
holder.binding.text.setCompoundDrawablesRelativeWithIntrinsicBounds(0, 0, item.getIcon(), 0);
holder.binding.getRoot().setOnClickListener(v -> mListener.onItemClick(item));
}
}

@ -51,9 +51,8 @@ public class VodAdapter extends RecyclerView.Adapter<VodAdapter.ViewHolder> {
}
public void addAll(List<Vod> items) {
mItems.clear();
mItems.addAll(items);
notifyDataSetChanged();
notifyItemRangeInserted(mItems.size(), items.size());
}
@Override

@ -0,0 +1,127 @@
package com.fongmi.android.tv.ui.fragment;
import android.os.Bundle;
import android.view.LayoutInflater;
import android.view.ViewGroup;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.lifecycle.ViewModelProvider;
import androidx.recyclerview.widget.GridLayoutManager;
import androidx.viewbinding.ViewBinding;
import com.fongmi.android.tv.bean.Filter;
import com.fongmi.android.tv.bean.Vod;
import com.fongmi.android.tv.databinding.FragmentChildBinding;
import com.fongmi.android.tv.model.SiteViewModel;
import com.fongmi.android.tv.ui.activity.BaseFragment;
import com.fongmi.android.tv.ui.adapter.VodAdapter;
import com.fongmi.android.tv.ui.custom.CustomScroller;
import com.fongmi.android.tv.ui.custom.SpaceItemDecoration;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
public class ChildFragment extends BaseFragment implements CustomScroller.Callback, VodAdapter.OnClickListener {
private FragmentChildBinding mBinding;
private HashMap<String, String> mExtend;
private SiteViewModel mViewModel;
private CustomScroller mScroller;
private List<Filter> mFilters;
private List<String> mTypeIds;
private VodAdapter mAdapter;
private String getTypeId() {
return getArguments().getString("typeId");
}
private String getFilter() {
return getArguments().getString("filter");
}
private boolean isFolder() {
return getArguments().getBoolean("folder");
}
public static ChildFragment newInstance(String typeId, String filter, boolean folder) {
Bundle args = new Bundle();
args.putString("typeId", typeId);
args.putString("filter", filter);
args.putBoolean("folder", folder);
ChildFragment fragment = new ChildFragment();
fragment.setArguments(args);
return fragment;
}
@Override
protected ViewBinding getBinding(@NonNull LayoutInflater inflater, @Nullable ViewGroup container) {
return mBinding = FragmentChildBinding.inflate(inflater, container, false);
}
@Override
protected void initView() {
mTypeIds = new ArrayList<>();
mExtend = new HashMap<>();
mFilters = Filter.arrayFrom(getFilter());
mBinding.progressLayout.showProgress();
setRecyclerView();
setViewModel();
getVideo();
}
private void setRecyclerView() {
mBinding.recycler.setHasFixedSize(true);
mBinding.recycler.setAdapter(mAdapter = new VodAdapter(this));
mBinding.recycler.addOnScrollListener(mScroller = new CustomScroller(this));
mBinding.recycler.setLayoutManager(new GridLayoutManager(getContext(), 3));
mBinding.recycler.addItemDecoration(new SpaceItemDecoration(3, 16));
}
private void setViewModel() {
mViewModel = new ViewModelProvider(this).get(SiteViewModel.class);
mViewModel.result.observe(getViewLifecycleOwner(), result -> {
mScroller.endLoading(result.getList().isEmpty());
mBinding.progressLayout.showContent();
mAdapter.addAll(result.getList());
checkPage();
});
}
private void getVideo() {
mScroller.reset();
getVideo(getTypeId(), "1");
}
private void checkPage() {
if (mScroller.getPage() != 1 || mAdapter.getItemCount() >= 4 || isFolder()) return;
mScroller.addPage();
getVideo(getTypeId(), "2");
}
private void getVideo(String typeId, String page) {
if (isFolder()) mTypeIds.add(typeId);
if (isFolder()) mBinding.recycler.scrollToPosition(0);
boolean clear = page.equals("1") && mAdapter.getItemCount() > mFilters.size();
//if (clear) mAdapter.removeItems(mFilters.size(), mAdapter.size() - mFilters.size());
mViewModel.categoryContent(typeId, page, true, mExtend);
}
@Override
public void onLoadMore(String page) {
if (isFolder()) return;
mScroller.setLoading(true);
getVideo(getTypeId(), page);
}
@Override
public void onItemClick(Vod item) {
}
@Override
public boolean onLongClick(Vod item) {
return false;
}
}

@ -19,6 +19,8 @@ import com.fongmi.android.tv.ui.adapter.HistoryAdapter;
import com.fongmi.android.tv.ui.adapter.VodAdapter;
import com.fongmi.android.tv.ui.custom.SpaceItemDecoration;
import org.greenrobot.eventbus.EventBus;
public class HomeFragment extends BaseFragment implements VodAdapter.OnClickListener, HistoryAdapter.OnClickListener {
private FragmentHomeBinding mBinding;
@ -37,6 +39,7 @@ public class HomeFragment extends BaseFragment implements VodAdapter.OnClickList
@Override
protected void initView() {
mBinding.progressLayout.showProgress();
setRecyclerView();
setViewModel();
getHistory();
@ -63,6 +66,8 @@ public class HomeFragment extends BaseFragment implements VodAdapter.OnClickList
mViewModel = new ViewModelProvider(this).get(SiteViewModel.class);
mViewModel.result.observe(getViewLifecycleOwner(), result -> {
if (result != null) mVodAdapter.addAll(result.getList());
mBinding.progressLayout.showContent();
EventBus.getDefault().post(result);
});
}

@ -5,14 +5,32 @@ import android.view.ViewGroup;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.fragment.app.Fragment;
import androidx.fragment.app.FragmentManager;
import androidx.fragment.app.FragmentStatePagerAdapter;
import androidx.viewbinding.ViewBinding;
import androidx.viewpager.widget.ViewPager;
import com.fongmi.android.tv.api.ApiConfig;
import com.fongmi.android.tv.bean.Class;
import com.fongmi.android.tv.bean.Result;
import com.fongmi.android.tv.databinding.FragmentVodBinding;
import com.fongmi.android.tv.ui.activity.BaseFragment;
import com.fongmi.android.tv.ui.adapter.TypeAdapter;
import com.google.gson.Gson;
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 VodFragment extends BaseFragment {
private FragmentVodBinding mBinding;
private TypeAdapter mAdapter;
private Result mResult;
public static VodFragment newInstance() {
return new VodFragment();
@ -22,4 +40,67 @@ public class VodFragment extends BaseFragment {
protected ViewBinding getBinding(@NonNull LayoutInflater inflater, @Nullable ViewGroup container) {
return mBinding = FragmentVodBinding.inflate(inflater, container, false);
}
@Override
protected void initView() {
mBinding.recycler.setHasFixedSize(true);
mBinding.recycler.setAdapter(mAdapter = new TypeAdapter());
mBinding.pager.setAdapter(new PageAdapter(getChildFragmentManager()));
}
@Override
protected void initEvent() {
EventBus.getDefault().register(this);
mAdapter.setListener(item -> mBinding.pager.setCurrentItem(mAdapter.setActivated(item)));
mBinding.pager.addOnPageChangeListener(new ViewPager.SimpleOnPageChangeListener() {
@Override
public void onPageSelected(int position) {
mBinding.recycler.smoothScrollToPosition(position);
mAdapter.setActivated(position);
}
});
}
@Subscribe(threadMode = ThreadMode.MAIN)
public void onResult(Result result) {
setAdapter(mResult = result);
}
private void setAdapter(Result result) {
result.setTypes(getTypes());
mAdapter.addAll(result.getTypes());
Boolean filter = ApiConfig.get().getHome().isFilterable() ? false : null;
for (Class item : mAdapter.getTypes()) if (result.getFilters().containsKey(item.getTypeId())) item.setFilter(filter);
mBinding.pager.getAdapter().notifyDataSetChanged();
}
private List<Class> getTypes() {
List<Class> types = new ArrayList<>();
for (String cate : ApiConfig.get().getHome().getCategories()) for (Class item : mResult.getTypes()) if (cate.equals(item.getTypeName())) types.add(item);
return types;
}
class PageAdapter extends FragmentStatePagerAdapter {
public PageAdapter(@NonNull FragmentManager fm) {
super(fm);
}
@NonNull
@Override
public Fragment getItem(int position) {
Class type = mAdapter.get(position);
String filter = new Gson().toJson(mResult.getFilters().get(type.getTypeId()));
return ChildFragment.newInstance(type.getTypeId(), filter, type.getTypeFlag().equals("1"));
}
@Override
public int getCount() {
return mAdapter.getItemCount();
}
@Override
public void destroyItem(@NonNull ViewGroup container, int position, @NonNull Object object) {
}
}
}

@ -0,0 +1,5 @@
<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:drawable="@drawable/shape_item_round_activated" android:state_activated="true" />
<item android:drawable="@drawable/shape_item_round_normal" />
</selector>

@ -0,0 +1,15 @@
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android"
android:shape="rectangle">
<solid android:color="@color/black_40" />
<corners android:radius="20dp" />
<padding
android:bottom="6dp"
android:left="12dp"
android:right="12dp"
android:top="6dp" />
</shape>

@ -0,0 +1,15 @@
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android"
android:shape="rectangle">
<solid android:color="@color/black_20" />
<corners android:radius="20dp" />
<padding
android:bottom="6dp"
android:left="12dp"
android:right="12dp"
android:top="6dp" />
</shape>

@ -0,0 +1,12 @@
<?xml version="1.0" encoding="utf-8"?>
<TextView xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/text"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_margin="8dp"
android:background="@drawable/selector_item_round"
android:gravity="center"
android:textColor="@color/white"
android:textSize="14sp"
tools:text="電影" />

@ -0,0 +1,18 @@
<?xml version="1.0" encoding="utf-8"?>
<com.fongmi.android.tv.ui.custom.ProgressLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/progressLayout"
android:layout_width="match_parent"
android:layout_height="match_parent">
<androidx.recyclerview.widget.RecyclerView
android:id="@+id/recycler"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:clipChildren="false"
android:clipToPadding="false"
android:paddingStart="16dp"
android:paddingTop="8dp"
android:paddingEnd="16dp"
android:paddingBottom="16dp" />
</com.fongmi.android.tv.ui.custom.ProgressLayout>

@ -1,7 +1,8 @@
<?xml version="1.0" encoding="utf-8"?>
<androidx.core.widget.NestedScrollView xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent">
android:layout_height="match_parent"
android:fillViewport="true">
<LinearLayout
android:layout_width="match_parent"
@ -21,7 +22,7 @@
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="16dp"
android:text="最近觀看"
android:text="@string/home_history"
android:textColor="@color/white"
android:textSize="18sp" />
@ -36,16 +37,22 @@
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="16dp"
android:text="更新推薦"
android:text="@string/home_recommend"
android:textColor="@color/white"
android:textSize="18sp" />
<androidx.recyclerview.widget.RecyclerView
android:id="@+id/recommend"
<com.fongmi.android.tv.ui.custom.ProgressLayout
android:id="@+id/progressLayout"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="16dp"
android:nestedScrollingEnabled="false" />
android:layout_height="match_parent"
android:layout_marginTop="16dp">
<androidx.recyclerview.widget.RecyclerView
android:id="@+id/recommend"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:nestedScrollingEnabled="false" />
</com.fongmi.android.tv.ui.custom.ProgressLayout>
</LinearLayout>
</androidx.core.widget.NestedScrollView>

@ -1,6 +1,37 @@
<?xml version="1.0" encoding="utf-8"?>
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
<androidx.coordinatorlayout.widget.CoordinatorLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent">
</FrameLayout>
<com.google.android.material.appbar.AppBarLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="@color/transparent"
android:elevation="0dp"
app:elevation="0dp">
<androidx.recyclerview.widget.RecyclerView
android:id="@+id/recycler"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:clipChildren="false"
android:clipToPadding="false"
android:orientation="horizontal"
android:paddingStart="8dp"
android:paddingTop="8dp"
android:paddingEnd="8dp"
app:layoutManager="androidx.recyclerview.widget.LinearLayoutManager"
app:layout_scrollFlags="scroll|enterAlways"
tools:listitem="@layout/adapter_type" />
</com.google.android.material.appbar.AppBarLayout>
<androidx.viewpager.widget.ViewPager
android:id="@+id/pager"
android:layout_width="match_parent"
android:layout_height="match_parent"
app:layout_behavior="@string/appbar_scrolling_view_behavior" />
</androidx.coordinatorlayout.widget.CoordinatorLayout>

@ -5,4 +5,8 @@
<string name="nav_vod">片库</string>
<string name="nav_setting">设定</string>
<!-- Home -->
<string name="home_history">最近观看</string>
<string name="home_recommend">更新推荐</string>
</resources>

@ -5,4 +5,8 @@
<string name="nav_vod">片庫</string>
<string name="nav_setting">設定</string>
<!-- Home -->
<string name="home_history">最近觀看</string>
<string name="home_recommend">更新推薦</string>
</resources>

@ -5,4 +5,8 @@
<string name="nav_vod">Vod</string>
<string name="nav_setting">Setting</string>
<!-- Home -->
<string name="home_history">History</string>
<string name="home_recommend">Recommend</string>
</resources>
Loading…
Cancel
Save