From 8c2d98a1cde47bef6502812d27d10a27c4900459 Mon Sep 17 00:00:00 2001 From: FongMi Date: Wed, 24 Jan 2024 15:19:25 +0800 Subject: [PATCH] Support epg - part 1 --- .../java/com/fongmi/android/tv/bean/Epg.java | 34 +++++++++- .../android/tv/ui/activity/LiveActivity.java | 20 ++++-- .../android/tv/ui/adapter/EpgAdapter.java | 67 +++++++++++++++++++ app/src/mobile/res/color/epg.xml | 6 ++ app/src/mobile/res/layout/activity_live.xml | 21 +++++- app/src/mobile/res/layout/adapter_channel.xml | 8 +++ app/src/mobile/res/layout/adapter_epg.xml | 42 ++++++++++++ app/src/mobile/res/layout/adapter_group.xml | 4 ++ 8 files changed, 193 insertions(+), 9 deletions(-) create mode 100644 app/src/mobile/java/com/fongmi/android/tv/ui/adapter/EpgAdapter.java create mode 100644 app/src/mobile/res/color/epg.xml create mode 100644 app/src/mobile/res/layout/adapter_epg.xml diff --git a/app/src/main/java/com/fongmi/android/tv/bean/Epg.java b/app/src/main/java/com/fongmi/android/tv/bean/Epg.java index 4138f9d8f..43ddc1cb5 100644 --- a/app/src/main/java/com/fongmi/android/tv/bean/Epg.java +++ b/app/src/main/java/com/fongmi/android/tv/bean/Epg.java @@ -2,6 +2,8 @@ package com.fongmi.android.tv.bean; import android.text.TextUtils; +import androidx.annotation.Nullable; + import com.fongmi.android.tv.App; import com.fongmi.android.tv.R; import com.fongmi.android.tv.utils.ResUtil; @@ -10,7 +12,9 @@ import com.github.catvod.utils.Trans; import com.google.gson.annotations.SerializedName; import java.text.SimpleDateFormat; +import java.util.ArrayList; import java.util.Collections; +import java.util.LinkedHashSet; import java.util.List; public class Epg { @@ -58,6 +62,10 @@ public class Epg { return list == null ? Collections.emptyList() : list; } + public void setList(List list) { + this.list = list; + } + public String getTitle() { return TextUtils.isEmpty(title) ? "" : title; } @@ -95,6 +103,7 @@ public class Epg { } private void setTime(SimpleDateFormat format) { + setList(new ArrayList<>(new LinkedHashSet<>(getList()))); for (Epg item : getList()) { item.setStartTime(Util.format(format, getDate().concat(item.getStart()))); item.setEndTime(Util.format(format, getDate().concat(item.getEnd()))); @@ -102,18 +111,39 @@ public class Epg { } } - private boolean isInRange() { + public boolean isInRange() { return getStartTime() <= System.currentTimeMillis() && System.currentTimeMillis() <= getEndTime(); } private String format() { if (getTitle().isEmpty()) return ""; - if (getStart().isEmpty() || getEnd().isEmpty()) return ResUtil.getString(R.string.play_now, getTitle()); + if (getStart().isEmpty() && getEnd().isEmpty()) return ResUtil.getString(R.string.play_now, getTitle()); return getStart() + " ~ " + getEnd() + " " + getTitle(); } + public String getTime() { + if (getStart().isEmpty() && getEnd().isEmpty()) return ""; + return getStart() + " ~ " + getEnd(); + } + public String getEpg() { for (Epg item : getList()) if (item.isInRange()) return item.format(); return ""; } + + @Override + public boolean equals(@Nullable Object obj) { + if (this == obj) return true; + if (!(obj instanceof Epg)) return false; + Epg it = (Epg) obj; + return getTitle().equals(it.getTitle()) && getEnd().equals(it.getEnd()) && getStart().equals(it.getStart()); + } + + @Override + public int hashCode() { + int result = getTitle().hashCode(); + result = 31 * result + getEnd().hashCode(); + result = 31 * result + getStart().hashCode(); + return result; + } } diff --git a/app/src/mobile/java/com/fongmi/android/tv/ui/activity/LiveActivity.java b/app/src/mobile/java/com/fongmi/android/tv/ui/activity/LiveActivity.java index 1b51295ba..deb861135 100644 --- a/app/src/mobile/java/com/fongmi/android/tv/ui/activity/LiveActivity.java +++ b/app/src/mobile/java/com/fongmi/android/tv/ui/activity/LiveActivity.java @@ -51,6 +51,7 @@ import com.fongmi.android.tv.player.Source; import com.fongmi.android.tv.server.Server; import com.fongmi.android.tv.service.PlaybackService; import com.fongmi.android.tv.ui.adapter.ChannelAdapter; +import com.fongmi.android.tv.ui.adapter.EpgAdapter; import com.fongmi.android.tv.ui.adapter.GroupAdapter; import com.fongmi.android.tv.ui.base.BaseActivity; import com.fongmi.android.tv.ui.custom.CustomKeyDownLive; @@ -87,6 +88,7 @@ public class LiveActivity extends BaseActivity implements CustomKeyDownLive.List private GroupAdapter mGroupAdapter; private Observer mObserveEpg; private LiveViewModel mViewModel; + private EpgAdapter mEpgAdapter; private List mHides; private Players mPlayers; private Channel mChannel; @@ -205,8 +207,10 @@ public class LiveActivity extends BaseActivity implements CustomKeyDownLive.List } private void setRecyclerView() { + mBinding.epg.setItemAnimator(null); mBinding.group.setItemAnimator(null); mBinding.channel.setItemAnimator(null); + mBinding.epg.setAdapter(mEpgAdapter = new EpgAdapter()); mBinding.group.setAdapter(mGroupAdapter = new GroupAdapter(this)); mBinding.channel.setAdapter(mChannelAdapter = new ChannelAdapter(this)); } @@ -299,10 +303,10 @@ public class LiveActivity extends BaseActivity implements CustomKeyDownLive.List } private void setWidth(Live live) { - int base = ResUtil.dp2px(45); + int base = ResUtil.dp2px(44); for (Group group : live.getGroups()) live.setWidth(Math.max(live.getWidth(), ResUtil.getTextWidth(group.getName(), 14))); - mBinding.group.getLayoutParams().width = live.getWidth() == 0 ? 0 : Math.min(live.getWidth() + base, ResUtil.dp2px(200)); - mBinding.divide.setVisibility(live.getWidth() == 0 ? View.GONE : View.VISIBLE); + mBinding.group.getLayoutParams().width = live.getWidth() == 0 ? 0 : Math.min(live.getWidth() + base, ResUtil.dp2px(180)); + mBinding.divide1.setVisibility(live.getWidth() == 0 ? View.GONE : View.VISIBLE); } private void setPosition(int[] position) { @@ -324,6 +328,7 @@ public class LiveActivity extends BaseActivity implements CustomKeyDownLive.List if (change) mChannelAdapter.addAll(mGroup.getChannel()); mChannelAdapter.setSelected(mGroup.getPosition()); mBinding.channel.scrollToPosition(mGroup.getPosition()); + mBinding.epg.scrollToPosition(mEpgAdapter.getPosition()); } private void onCast() { @@ -518,8 +523,11 @@ public class LiveActivity extends BaseActivity implements CustomKeyDownLive.List private void showEpg() { String epg = mChannel.getData().getEpg(); - mBinding.widget.name.setMaxEms(epg.isEmpty() ? mChannel.getName().length() : 12); mBinding.widget.play.setText(epg); + mBinding.widget.name.setMaxEms(epg.isEmpty() ? mChannel.getName().length() : 12); + mBinding.epg.setVisibility(mChannel.getData().getList().isEmpty() ? View.GONE : View.VISIBLE); + mBinding.divide2.setVisibility(mChannel.getData().getList().isEmpty() ? View.GONE : View.VISIBLE); + mEpgAdapter.addAll(mChannel.getData().getList()); setMetadata(); } @@ -658,9 +666,11 @@ public class LiveActivity extends BaseActivity implements CustomKeyDownLive.List } private void resetAdapter() { - mBinding.divide.setVisibility(View.GONE); + mBinding.divide1.setVisibility(View.GONE); + mBinding.divide2.setVisibility(View.GONE); mChannelAdapter.clear(); mGroupAdapter.clear(); + mEpgAdapter.clear(); mHides.clear(); mChannel = null; mGroup = null; diff --git a/app/src/mobile/java/com/fongmi/android/tv/ui/adapter/EpgAdapter.java b/app/src/mobile/java/com/fongmi/android/tv/ui/adapter/EpgAdapter.java new file mode 100644 index 000000000..6425fc6d0 --- /dev/null +++ b/app/src/mobile/java/com/fongmi/android/tv/ui/adapter/EpgAdapter.java @@ -0,0 +1,67 @@ +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.Epg; +import com.fongmi.android.tv.databinding.AdapterEpgBinding; + +import java.util.ArrayList; +import java.util.List; + +public class EpgAdapter extends RecyclerView.Adapter { + + private final List mItems; + + public EpgAdapter() { + this.mItems = new ArrayList<>(); + } + + public void clear() { + mItems.clear(); + notifyDataSetChanged(); + } + + public void addAll(List items) { + mItems.clear(); + mItems.addAll(items); + notifyDataSetChanged(); + } + + public int getPosition() { + for (int i = 0; i < mItems.size(); i++) if (mItems.get(i).isInRange()) return i; + return 0; + } + + @Override + public int getItemCount() { + return mItems.size(); + } + + @NonNull + @Override + public ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) { + return new ViewHolder(AdapterEpgBinding.inflate(LayoutInflater.from(parent.getContext()), parent, false)); + } + + @Override + public void onBindViewHolder(@NonNull ViewHolder holder, int position) { + Epg item = mItems.get(position); + holder.binding.time.setText(item.getTime()); + holder.binding.title.setText(item.getTitle()); + holder.binding.getRoot().setSelected(item.isInRange()); + } + + static class ViewHolder extends RecyclerView.ViewHolder { + + private final AdapterEpgBinding binding; + + ViewHolder(@NonNull AdapterEpgBinding binding) { + super(binding.getRoot()); + this.binding = binding; + } + } +} diff --git a/app/src/mobile/res/color/epg.xml b/app/src/mobile/res/color/epg.xml new file mode 100644 index 000000000..024612b9b --- /dev/null +++ b/app/src/mobile/res/color/epg.xml @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/app/src/mobile/res/layout/activity_live.xml b/app/src/mobile/res/layout/activity_live.xml index bc82cf86e..63c52c703 100644 --- a/app/src/mobile/res/layout/activity_live.xml +++ b/app/src/mobile/res/layout/activity_live.xml @@ -72,7 +72,7 @@ tools:listitem="@layout/adapter_group" /> + + + + diff --git a/app/src/mobile/res/layout/adapter_channel.xml b/app/src/mobile/res/layout/adapter_channel.xml index 5f6edeecf..6902f041d 100644 --- a/app/src/mobile/res/layout/adapter_channel.xml +++ b/app/src/mobile/res/layout/adapter_channel.xml @@ -19,6 +19,10 @@ android:layout_height="wrap_content" android:layout_marginEnd="12dp" android:duplicateParentState="true" + android:shadowColor="@color/grey_900" + android:shadowDx="2" + android:shadowDy="2" + android:shadowRadius="1" android:textColor="@color/channel" android:textSize="14sp" tools:text="01" /> @@ -37,6 +41,10 @@ android:layout_height="wrap_content" android:duplicateParentState="true" android:ellipsize="marquee" + android:shadowColor="@color/grey_900" + android:shadowDx="2" + android:shadowDy="2" + android:shadowRadius="1" android:singleLine="true" android:textColor="@color/channel" android:textSize="14sp" diff --git a/app/src/mobile/res/layout/adapter_epg.xml b/app/src/mobile/res/layout/adapter_epg.xml new file mode 100644 index 000000000..0aed9cdaf --- /dev/null +++ b/app/src/mobile/res/layout/adapter_epg.xml @@ -0,0 +1,42 @@ + + + + + + + + \ No newline at end of file diff --git a/app/src/mobile/res/layout/adapter_group.xml b/app/src/mobile/res/layout/adapter_group.xml index 50dd4490e..56307de5f 100644 --- a/app/src/mobile/res/layout/adapter_group.xml +++ b/app/src/mobile/res/layout/adapter_group.xml @@ -19,6 +19,10 @@ android:layout_height="wrap_content" android:duplicateParentState="true" android:ellipsize="marquee" + android:shadowColor="@color/grey_900" + android:shadowDx="2" + android:shadowDy="2" + android:shadowRadius="1" android:singleLine="true" android:textColor="@color/group" android:textSize="14sp"