diff --git a/app/src/leanback/java/com/fongmi/android/tv/ui/activity/CastActivity.java b/app/src/leanback/java/com/fongmi/android/tv/ui/activity/CastActivity.java index de94fc636..8adfd368e 100644 --- a/app/src/leanback/java/com/fongmi/android/tv/ui/activity/CastActivity.java +++ b/app/src/leanback/java/com/fongmi/android/tv/ui/activity/CastActivity.java @@ -465,7 +465,7 @@ public class CastActivity extends BaseActivity implements CustomKeyDownCast.List @Override public void onSpeedUp() { if (!mPlayers.isPlaying() || !mPlayers.canAdjustSpeed()) return; - mBinding.control.speed.setText(mPlayers.setSpeed(mPlayers.getSpeed() < 3 ? 3 : 5)); + mBinding.control.speed.setText(mPlayers.setSpeed(Setting.getSpeed())); mBinding.widget.speed.startAnimation(ResUtil.getAnim(R.anim.forward)); mBinding.widget.speed.setVisibility(View.VISIBLE); } diff --git a/app/src/leanback/java/com/fongmi/android/tv/ui/activity/SettingPlayerActivity.java b/app/src/leanback/java/com/fongmi/android/tv/ui/activity/SettingPlayerActivity.java index ea58b1ad9..42b1de66d 100644 --- a/app/src/leanback/java/com/fongmi/android/tv/ui/activity/SettingPlayerActivity.java +++ b/app/src/leanback/java/com/fongmi/android/tv/ui/activity/SettingPlayerActivity.java @@ -11,17 +11,22 @@ import com.fongmi.android.tv.R; import com.fongmi.android.tv.Setting; import com.fongmi.android.tv.databinding.ActivitySettingPlayerBinding; import com.fongmi.android.tv.impl.BufferCallback; +import com.fongmi.android.tv.impl.SpeedCallback; import com.fongmi.android.tv.impl.SubtitleCallback; import com.fongmi.android.tv.impl.UaCallback; import com.fongmi.android.tv.ui.base.BaseActivity; import com.fongmi.android.tv.ui.dialog.BufferDialog; +import com.fongmi.android.tv.ui.dialog.SpeedDialog; import com.fongmi.android.tv.ui.dialog.SubtitleDialog; import com.fongmi.android.tv.ui.dialog.UaDialog; import com.fongmi.android.tv.utils.ResUtil; -public class SettingPlayerActivity extends BaseActivity implements UaCallback, BufferCallback, SubtitleCallback { +import java.text.DecimalFormat; + +public class SettingPlayerActivity extends BaseActivity implements UaCallback, BufferCallback, SpeedCallback, SubtitleCallback { private ActivitySettingPlayerBinding mBinding; + private DecimalFormat format; private String[] caption; private String[] render; private String[] scale; @@ -43,9 +48,11 @@ public class SettingPlayerActivity extends BaseActivity implements UaCallback, B @Override protected void initView() { setVisible(); + format = new DecimalFormat("0.#"); mBinding.render.requestFocus(); mBinding.uaText.setText(Setting.getUa()); mBinding.tunnelText.setText(getSwitch(Setting.isTunnel())); + mBinding.speedText.setText(format.format(Setting.getSpeed())); mBinding.bufferText.setText(String.valueOf(Setting.getBuffer())); mBinding.subtitleText.setText(String.valueOf(Setting.getSubtitle())); mBinding.rtspText.setText((rtsp = ResUtil.getStringArray(R.array.select_rtsp))[Setting.getRtsp()]); @@ -59,6 +66,7 @@ public class SettingPlayerActivity extends BaseActivity implements UaCallback, B mBinding.ua.setOnClickListener(this::onUa); mBinding.rtsp.setOnClickListener(this::setRtsp); mBinding.scale.setOnClickListener(this::setScale); + mBinding.speed.setOnClickListener(this::onSpeed); mBinding.buffer.setOnClickListener(this::onBuffer); mBinding.render.setOnClickListener(this::setRender); mBinding.tunnel.setOnClickListener(this::setTunnel); @@ -93,6 +101,16 @@ public class SettingPlayerActivity extends BaseActivity implements UaCallback, B mBinding.scaleText.setText(scale[index]); } + private void onSpeed(View view) { + SpeedDialog.create(this).show(); + } + + @Override + public void setSpeed(float speed) { + mBinding.speedText.setText(format.format(speed)); + Setting.putSpeed(speed); + } + private void onBuffer(View view) { BufferDialog.create(this).show(); } diff --git a/app/src/leanback/java/com/fongmi/android/tv/ui/activity/VideoActivity.java b/app/src/leanback/java/com/fongmi/android/tv/ui/activity/VideoActivity.java index 71f12b4ca..8d37b4556 100644 --- a/app/src/leanback/java/com/fongmi/android/tv/ui/activity/VideoActivity.java +++ b/app/src/leanback/java/com/fongmi/android/tv/ui/activity/VideoActivity.java @@ -1369,7 +1369,7 @@ public class VideoActivity extends BaseActivity implements CustomKeyDownVod.List @Override public void onSpeedUp() { if (!mPlayers.isPlaying() || !mPlayers.canAdjustSpeed()) return; - mBinding.control.speed.setText(mPlayers.setSpeed(mPlayers.getSpeed() < 3 ? 3 : 5)); + mBinding.control.speed.setText(mPlayers.setSpeed(Setting.getSpeed())); mBinding.widget.speed.startAnimation(ResUtil.getAnim(R.anim.forward)); mBinding.widget.speed.setVisibility(View.VISIBLE); } diff --git a/app/src/leanback/java/com/fongmi/android/tv/ui/dialog/SpeedDialog.java b/app/src/leanback/java/com/fongmi/android/tv/ui/dialog/SpeedDialog.java new file mode 100644 index 000000000..fe83d208f --- /dev/null +++ b/app/src/leanback/java/com/fongmi/android/tv/ui/dialog/SpeedDialog.java @@ -0,0 +1,53 @@ +package com.fongmi.android.tv.ui.dialog; + +import android.view.LayoutInflater; + +import androidx.appcompat.app.AlertDialog; +import androidx.fragment.app.FragmentActivity; + +import com.fongmi.android.tv.Setting; +import com.fongmi.android.tv.databinding.DialogSpeedBinding; +import com.fongmi.android.tv.impl.SpeedCallback; +import com.fongmi.android.tv.utils.KeyUtil; +import com.google.android.material.dialog.MaterialAlertDialogBuilder; + +public class SpeedDialog { + + private final DialogSpeedBinding binding; + private final SpeedCallback callback; + private final AlertDialog dialog; + + public static SpeedDialog create(FragmentActivity activity) { + return new SpeedDialog(activity); + } + + public SpeedDialog(FragmentActivity activity) { + this.callback = (SpeedCallback) activity; + this.binding = DialogSpeedBinding.inflate(LayoutInflater.from(activity)); + this.dialog = new MaterialAlertDialogBuilder(activity).setView(binding.getRoot()).create(); + } + + public void show() { + initDialog(); + initView(); + initEvent(); + } + + private void initDialog() { + dialog.getWindow().setBackgroundDrawableResource(android.R.color.transparent); + dialog.show(); + } + + private void initView() { + binding.slider.setValue(Setting.getSpeed()); + } + + private void initEvent() { + binding.slider.addOnChangeListener((slider, value, fromUser) -> callback.setSpeed(value)); + binding.slider.setOnKeyListener((view, keyCode, event) -> { + boolean enter = KeyUtil.isEnterKey(event); + if (enter) dialog.dismiss(); + return enter; + }); + } +} diff --git a/app/src/leanback/res/layout/activity_setting_player.xml b/app/src/leanback/res/layout/activity_setting_player.xml index 2edf0517b..8b66f7ee6 100644 --- a/app/src/leanback/res/layout/activity_setting_player.xml +++ b/app/src/leanback/res/layout/activity_setting_player.xml @@ -167,6 +167,44 @@ + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/java/com/fongmi/android/tv/Setting.java b/app/src/main/java/com/fongmi/android/tv/Setting.java index 7ef9a9ed6..05ce7ebbf 100644 --- a/app/src/main/java/com/fongmi/android/tv/Setting.java +++ b/app/src/main/java/com/fongmi/android/tv/Setting.java @@ -257,6 +257,14 @@ public class Setting { Prefers.put("zhuyin", zhuyin); } + public static float getSpeed() { + return Math.min(Math.max(Prefers.getFloat("speed", 3), 2), 5); + } + + public static void putSpeed(float speed) { + Prefers.put("speed", speed); + } + public static float getThumbnail() { return 0.3f * getQuality() + 0.4f; } diff --git a/app/src/main/java/com/fongmi/android/tv/impl/SpeedCallback.java b/app/src/main/java/com/fongmi/android/tv/impl/SpeedCallback.java new file mode 100644 index 000000000..cb72e5a0c --- /dev/null +++ b/app/src/main/java/com/fongmi/android/tv/impl/SpeedCallback.java @@ -0,0 +1,6 @@ +package com.fongmi.android.tv.impl; + +public interface SpeedCallback { + + void setSpeed(float speed); +} diff --git a/app/src/main/java/com/fongmi/android/tv/player/Players.java b/app/src/main/java/com/fongmi/android/tv/player/Players.java index 501651541..7b69b8247 100644 --- a/app/src/main/java/com/fongmi/android/tv/player/Players.java +++ b/app/src/main/java/com/fongmi/android/tv/player/Players.java @@ -273,7 +273,7 @@ public class Players implements Player.Listener, ParseCallback { public String toggleSpeed() { float speed = getSpeed(); - speed = speed == 1 ? 3f : 1f; + speed = speed == 1 ? Setting.getSpeed() : 1; return setSpeed(speed); } diff --git a/app/src/main/res/values-zh-rCN/strings.xml b/app/src/main/res/values-zh-rCN/strings.xml index c1fbebf16..758a1b786 100644 --- a/app/src/main/res/values-zh-rCN/strings.xml +++ b/app/src/main/res/values-zh-rCN/strings.xml @@ -86,6 +86,7 @@ 后台播放 隧道模式 缓冲时间 + 长按倍速 RTSP 通道 User-Agent diff --git a/app/src/main/res/values-zh-rTW/strings.xml b/app/src/main/res/values-zh-rTW/strings.xml index 0e3ffb089..b743d3d30 100644 --- a/app/src/main/res/values-zh-rTW/strings.xml +++ b/app/src/main/res/values-zh-rTW/strings.xml @@ -86,6 +86,7 @@ 背景播放 隧道模式 緩衝時間 + 長按倍速 RTSP 通道 User-Agent diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 3ee7ddf50..87b5a0054 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -87,6 +87,7 @@ Background play Tunnel mode Buffer time + Press speed RTSP channel User-Agent 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 a0b390b89..10e631be7 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 @@ -946,7 +946,7 @@ public class LiveActivity extends BaseActivity implements CustomKeyDownLive.List @Override public void onSpeedUp() { if (mPlayers.isLive() || !mPlayers.isPlaying() || !mPlayers.canAdjustSpeed()) return; - mBinding.control.action.speed.setText(mPlayers.setSpeed(mPlayers.getSpeed() < 3 ? 3 : 5)); + mBinding.control.action.speed.setText(mPlayers.setSpeed(Setting.getSpeed())); mBinding.widget.speed.startAnimation(ResUtil.getAnim(R.anim.forward)); mBinding.widget.speed.setVisibility(View.VISIBLE); } diff --git a/app/src/mobile/java/com/fongmi/android/tv/ui/activity/VideoActivity.java b/app/src/mobile/java/com/fongmi/android/tv/ui/activity/VideoActivity.java index 8b289f1f2..d02dc01eb 100644 --- a/app/src/mobile/java/com/fongmi/android/tv/ui/activity/VideoActivity.java +++ b/app/src/mobile/java/com/fongmi/android/tv/ui/activity/VideoActivity.java @@ -1412,7 +1412,7 @@ public class VideoActivity extends BaseActivity implements Clock.Callback, Custo @Override public void onSpeedUp() { if (!mPlayers.isPlaying() || !mPlayers.canAdjustSpeed()) return; - mBinding.control.action.speed.setText(mPlayers.setSpeed(mPlayers.getSpeed() < 3 ? 3 : 5)); + mBinding.control.action.speed.setText(mPlayers.setSpeed(Setting.getSpeed())); mBinding.widget.speed.startAnimation(ResUtil.getAnim(R.anim.forward)); mBinding.widget.speed.setVisibility(View.VISIBLE); } diff --git a/app/src/mobile/java/com/fongmi/android/tv/ui/dialog/SpeedDialog.java b/app/src/mobile/java/com/fongmi/android/tv/ui/dialog/SpeedDialog.java new file mode 100644 index 000000000..d0ef1efd9 --- /dev/null +++ b/app/src/mobile/java/com/fongmi/android/tv/ui/dialog/SpeedDialog.java @@ -0,0 +1,54 @@ +package com.fongmi.android.tv.ui.dialog; + +import android.content.DialogInterface; +import android.view.LayoutInflater; + +import androidx.appcompat.app.AlertDialog; +import androidx.fragment.app.Fragment; + +import com.fongmi.android.tv.R; +import com.fongmi.android.tv.Setting; +import com.fongmi.android.tv.databinding.DialogSpeedBinding; +import com.fongmi.android.tv.impl.SpeedCallback; +import com.google.android.material.dialog.MaterialAlertDialogBuilder; + +public class SpeedDialog { + + private final DialogSpeedBinding binding; + private final SpeedCallback callback; + private float value; + + public static SpeedDialog create(Fragment fragment) { + return new SpeedDialog(fragment); + } + + public SpeedDialog(Fragment fragment) { + this.callback = (SpeedCallback) fragment; + this.binding = DialogSpeedBinding.inflate(LayoutInflater.from(fragment.getContext())); + } + + public void show() { + initDialog(); + initView(); + } + + private void initDialog() { + AlertDialog dialog = new MaterialAlertDialogBuilder(binding.getRoot().getContext()).setTitle(R.string.player_speed).setView(binding.getRoot()).setPositiveButton(R.string.dialog_positive, this::onPositive).setNegativeButton(R.string.dialog_negative, this::onNegative).create(); + dialog.getWindow().setDimAmount(0); + dialog.show(); + } + + private void initView() { + binding.slider.setValue(value = Setting.getSpeed()); + } + + private void onPositive(DialogInterface dialog, int which) { + callback.setSpeed(binding.slider.getValue()); + dialog.dismiss(); + } + + private void onNegative(DialogInterface dialog, int which) { + callback.setSpeed(value); + dialog.dismiss(); + } +} diff --git a/app/src/mobile/java/com/fongmi/android/tv/ui/fragment/SettingPlayerFragment.java b/app/src/mobile/java/com/fongmi/android/tv/ui/fragment/SettingPlayerFragment.java index dad9d7fb9..75450c173 100644 --- a/app/src/mobile/java/com/fongmi/android/tv/ui/fragment/SettingPlayerFragment.java +++ b/app/src/mobile/java/com/fongmi/android/tv/ui/fragment/SettingPlayerFragment.java @@ -14,18 +14,23 @@ import com.fongmi.android.tv.R; import com.fongmi.android.tv.Setting; import com.fongmi.android.tv.databinding.FragmentSettingPlayerBinding; import com.fongmi.android.tv.impl.BufferCallback; +import com.fongmi.android.tv.impl.SpeedCallback; import com.fongmi.android.tv.impl.SubtitleCallback; import com.fongmi.android.tv.impl.UaCallback; import com.fongmi.android.tv.ui.base.BaseFragment; import com.fongmi.android.tv.ui.dialog.BufferDialog; +import com.fongmi.android.tv.ui.dialog.SpeedDialog; import com.fongmi.android.tv.ui.dialog.SubtitleDialog; import com.fongmi.android.tv.ui.dialog.UaDialog; import com.fongmi.android.tv.utils.ResUtil; import com.google.android.material.dialog.MaterialAlertDialogBuilder; -public class SettingPlayerFragment extends BaseFragment implements UaCallback, BufferCallback, SubtitleCallback { +import java.text.DecimalFormat; + +public class SettingPlayerFragment extends BaseFragment implements UaCallback, BufferCallback, SpeedCallback, SubtitleCallback { private FragmentSettingPlayerBinding mBinding; + private DecimalFormat format; private String[] background; private String[] caption; private String[] render; @@ -48,8 +53,10 @@ public class SettingPlayerFragment extends BaseFragment implements UaCallback, B @Override protected void initView() { setVisible(); + format = new DecimalFormat("0.#"); mBinding.uaText.setText(Setting.getUa()); mBinding.tunnelText.setText(getSwitch(Setting.isTunnel())); + mBinding.speedText.setText(format.format(Setting.getSpeed())); mBinding.bufferText.setText(String.valueOf(Setting.getBuffer())); mBinding.subtitleText.setText(String.valueOf(Setting.getSubtitle())); mBinding.rtspText.setText((rtsp = ResUtil.getStringArray(R.array.select_rtsp))[Setting.getRtsp()]); @@ -64,6 +71,7 @@ public class SettingPlayerFragment extends BaseFragment implements UaCallback, B mBinding.ua.setOnClickListener(this::onUa); mBinding.rtsp.setOnClickListener(this::setRtsp); mBinding.scale.setOnClickListener(this::onScale); + mBinding.speed.setOnClickListener(this::onSpeed); mBinding.buffer.setOnClickListener(this::onBuffer); mBinding.render.setOnClickListener(this::setRender); mBinding.tunnel.setOnClickListener(this::setTunnel); @@ -101,6 +109,16 @@ public class SettingPlayerFragment extends BaseFragment implements UaCallback, B }).show(); } + private void onSpeed(View view) { + SpeedDialog.create(this).show(); + } + + @Override + public void setSpeed(float speed) { + mBinding.speedText.setText(format.format(speed)); + Setting.putSpeed(speed); + } + private void onBuffer(View view) { BufferDialog.create(this).show(); } diff --git a/app/src/mobile/res/layout/dialog_speed.xml b/app/src/mobile/res/layout/dialog_speed.xml new file mode 100644 index 000000000..5fc653028 --- /dev/null +++ b/app/src/mobile/res/layout/dialog_speed.xml @@ -0,0 +1,21 @@ + + + + + + \ No newline at end of file diff --git a/app/src/mobile/res/layout/fragment_setting_player.xml b/app/src/mobile/res/layout/fragment_setting_player.xml index b307a9253..f5e5b8241 100644 --- a/app/src/mobile/res/layout/fragment_setting_player.xml +++ b/app/src/mobile/res/layout/fragment_setting_player.xml @@ -188,6 +188,42 @@ + + + + + + + + + + floats = Arrays.asList("speed"); + private static SharedPreferences getPrefers() { return PreferenceManager.getDefaultSharedPreferences(Init.context()); } @@ -104,6 +108,10 @@ public class Prefers { } private static Object convert(Map.Entry entry) { - return entry.getValue(); + if (floats.contains(entry.getKey())) { + return Float.parseFloat(entry.getValue().toString()); + } else { + return entry.getValue(); + } } } diff --git a/catvod/src/main/java/com/github/catvod/utils/UriUtil.java b/catvod/src/main/java/com/github/catvod/utils/UriUtil.java index 0b07bf974..4140e0abd 100644 --- a/catvod/src/main/java/com/github/catvod/utils/UriUtil.java +++ b/catvod/src/main/java/com/github/catvod/utils/UriUtil.java @@ -159,7 +159,7 @@ public final class UriUtil { } else if (i == segmentStart + 2 && uri.charAt(segmentStart) == '.' && uri.charAt(segmentStart + 1) == '.') { // Given "abc/def/../ghi", remove "def/../" to get "abc/ghi". int prevSegmentStart = uri.lastIndexOf("/", segmentStart - 2) + 1; - int removeFrom = prevSegmentStart > offset ? prevSegmentStart : offset; + int removeFrom = Math.max(prevSegmentStart, offset); uri.delete(removeFrom, nextSegmentStart); limit -= nextSegmentStart - removeFrom; segmentStart = prevSegmentStart;