mirror of
https://github.com/yuliskov/SmartTube.git
synced 2025-05-17 11:25:54 +08:00
persist state between the sessions
This commit is contained in:
@ -25,8 +25,7 @@ public class MainPlayerEventBridge implements PlayerEventListener {
|
||||
private final ArrayList<PlayerHandlerEventListener> mEventListeners;
|
||||
@SuppressLint("StaticFieldLeak")
|
||||
private static MainPlayerEventBridge sInstance;
|
||||
private PlaybackController mController;
|
||||
private Activity mMainActivity;
|
||||
private boolean mInitDone;
|
||||
|
||||
public MainPlayerEventBridge() {
|
||||
mEventListeners = new ArrayList<>();
|
||||
@ -63,16 +62,12 @@ public class MainPlayerEventBridge implements PlayerEventListener {
|
||||
Fragment fragment = (Fragment) controller;
|
||||
Activity mainActivity = fragment.getActivity();
|
||||
|
||||
if (mMainActivity != mainActivity) {
|
||||
mMainActivity = mainActivity;
|
||||
process(listener -> listener.onActivity(mainActivity));
|
||||
process(listener -> listener.onController(controller));
|
||||
|
||||
process(listener -> listener.onActivity(mainActivity));
|
||||
}
|
||||
|
||||
if (mController != controller) {
|
||||
mController = controller;
|
||||
|
||||
process(listener -> listener.onController(controller));
|
||||
if (!mInitDone) {
|
||||
mInitDone = true;
|
||||
process(PlayerHandlerEventListener::onInitDone);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -20,6 +20,11 @@ public abstract class PlayerEventListenerHelper implements PlayerHandlerEventLis
|
||||
mActivity = activity;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onInitDone() {
|
||||
// NOP
|
||||
}
|
||||
|
||||
@Override
|
||||
public void openVideo(Video item) {
|
||||
// NOP
|
||||
|
@ -10,4 +10,5 @@ public interface PlayerHandlerEventListener extends PlayerUiEventListener, Playe
|
||||
void openVideo(Video item);
|
||||
void onController(PlaybackController controller);
|
||||
void onActivity(Activity activity);
|
||||
void onInitDone();
|
||||
}
|
||||
|
@ -1,6 +1,5 @@
|
||||
package com.liskovsoft.smartyoutubetv2.common.app.models.playback.managers;
|
||||
|
||||
import android.app.Activity;
|
||||
import androidx.annotation.NonNull;
|
||||
import com.liskovsoft.sharedutils.mylogger.Log;
|
||||
import com.liskovsoft.smartyoutubetv2.common.R;
|
||||
@ -18,7 +17,6 @@ import java.util.List;
|
||||
public class AutoFrameRateManager extends PlayerEventListenerHelper {
|
||||
private static final String TAG = AutoFrameRateManager.class.getSimpleName();
|
||||
private final HqDialogManager mUiManager;
|
||||
private boolean mMainActivityRunOnce;
|
||||
private FormatItem mSelectedVideoTrack;
|
||||
private final AutoFrameRateHelper mAutoFrameRateHelper;
|
||||
private final ModeSyncManager mModeSyncManager;
|
||||
@ -67,17 +65,10 @@ public class AutoFrameRateManager extends PlayerEventListenerHelper {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onActivity(Activity activity) {
|
||||
super.onActivity(activity);
|
||||
|
||||
if (!mMainActivityRunOnce) {
|
||||
restoreAfrData();
|
||||
|
||||
addUiOptions();
|
||||
mAutoFrameRateHelper.saveOriginalState(activity);
|
||||
|
||||
mMainActivityRunOnce = true;
|
||||
}
|
||||
public void onInitDone() {
|
||||
restoreAfrData();
|
||||
addUiOptions();
|
||||
mAutoFrameRateHelper.saveOriginalState(mActivity);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -1,10 +1,8 @@
|
||||
package com.liskovsoft.smartyoutubetv2.common.app.models.playback.managers;
|
||||
|
||||
import android.app.Activity;
|
||||
import android.os.Build.VERSION;
|
||||
import com.liskovsoft.smartyoutubetv2.common.R;
|
||||
import com.liskovsoft.smartyoutubetv2.common.app.models.playback.PlayerEventListenerHelper;
|
||||
import com.liskovsoft.smartyoutubetv2.common.app.models.playback.controller.PlaybackController;
|
||||
import com.liskovsoft.smartyoutubetv2.common.app.models.playback.controller.PlaybackEngineController;
|
||||
import com.liskovsoft.smartyoutubetv2.common.app.models.playback.ui.OptionItem;
|
||||
import com.liskovsoft.smartyoutubetv2.common.app.models.playback.ui.UiOptionItem;
|
||||
@ -30,17 +28,9 @@ public class HqDialogManager extends PlayerEventListenerHelper {
|
||||
private final List<Runnable> mHideListeners = new ArrayList<>();
|
||||
|
||||
@Override
|
||||
public void onActivity(Activity activity) {
|
||||
super.onActivity(activity);
|
||||
|
||||
public void onInitDone() {
|
||||
mSettingsPresenter = AppSettingsPresenter.instance(mActivity);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onController(PlaybackController controller) {
|
||||
super.onController(controller);
|
||||
|
||||
controller.setBuffer(AppPrefs.instance(mActivity).getVideoBufferType(PlaybackEngineController.BUFFER_LOW));
|
||||
mController.setBuffer(AppPrefs.instance(mActivity).getVideoBufferType(PlaybackEngineController.BUFFER_LOW));
|
||||
}
|
||||
|
||||
private void addQualityCategories() {
|
||||
|
@ -53,10 +53,8 @@ public class PlayerUiManager extends PlayerEventListenerHelper implements Metada
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onActivity(Activity activity) {
|
||||
super.onActivity(activity);
|
||||
|
||||
AppSettingsPresenter.instance(activity).setPlayerUiManager(this);
|
||||
public void onInitDone() {
|
||||
AppSettingsPresenter.instance(mActivity).setPlayerUiManager(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -1,6 +1,6 @@
|
||||
package com.liskovsoft.smartyoutubetv2.common.app.models.playback.managers;
|
||||
|
||||
import android.app.Activity;
|
||||
import androidx.annotation.NonNull;
|
||||
import com.liskovsoft.sharedutils.helpers.Helpers;
|
||||
import com.liskovsoft.smartyoutubetv2.common.R;
|
||||
import com.liskovsoft.smartyoutubetv2.common.app.models.data.Video;
|
||||
@ -17,43 +17,26 @@ import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
public class StateUpdater extends PlayerEventListenerHelper {
|
||||
private static final long MUSIC_VIDEO_LENGTH_MS = 6 * 60 * 1000;
|
||||
private static final int MAX_STATE_SIZE = 10;
|
||||
private boolean mIsPlaying;
|
||||
private FormatItem mVideoFormat;
|
||||
private FormatItem mAudioFormat;
|
||||
private FormatItem mSubtitleFormat;
|
||||
private static final long MUSIC_VIDEO_LENGTH_MS = 6 * 60 * 1000;
|
||||
// Don't store state inside Video object.
|
||||
// As one video might correspond to multiple Video objects.
|
||||
private final Map<String, State> mStates = new HashMap<>();
|
||||
private float mLastSpeed = -1;
|
||||
|
||||
private static class State {
|
||||
public final long positionMs;
|
||||
private final long lengthMs;
|
||||
public final float speed;
|
||||
|
||||
public State(long positionMs) {
|
||||
this(positionMs, -1);
|
||||
}
|
||||
|
||||
public State(long positionMs, long lengthMs) {
|
||||
this(positionMs, lengthMs, 1.0f);
|
||||
}
|
||||
|
||||
public State(long positionMs, long lengthMs, float speed) {
|
||||
this.positionMs = positionMs;
|
||||
this.lengthMs = lengthMs;
|
||||
this.speed = speed;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onActivity(Activity activity) {
|
||||
super.onActivity(activity);
|
||||
public void onInitDone() {
|
||||
AppPrefs prefs = AppPrefs.instance(mActivity);
|
||||
mVideoFormat = prefs.getFormat(FormatItem.TYPE_VIDEO, FormatItem.VIDEO_HD_AVC);
|
||||
mAudioFormat = prefs.getFormat(FormatItem.TYPE_AUDIO, FormatItem.AUDIO_HQ_MP4A);
|
||||
mSubtitleFormat = prefs.getFormat(FormatItem.TYPE_SUBTITLE, null);
|
||||
|
||||
mVideoFormat = AppPrefs.instance(mActivity).getFormat(FormatItem.TYPE_VIDEO, FormatItem.VIDEO_HD_AVC);
|
||||
mAudioFormat = AppPrefs.instance(mActivity).getFormat(FormatItem.TYPE_AUDIO, FormatItem.AUDIO_HQ_MP4A);
|
||||
mSubtitleFormat = AppPrefs.instance(mActivity).getFormat(FormatItem.TYPE_SUBTITLE, null);
|
||||
String data = prefs.getStateUpdaterData();
|
||||
restoreState(data);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -103,6 +86,7 @@ public class StateUpdater extends PlayerEventListenerHelper {
|
||||
@Override
|
||||
public void onEngineReleased() {
|
||||
saveState();
|
||||
persistState();
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -173,12 +157,50 @@ public class StateUpdater extends PlayerEventListenerHelper {
|
||||
Video video = mController.getVideo();
|
||||
|
||||
if (video != null) {
|
||||
mStates.put(video.videoId, new State(mController.getPositionMs(), mController.getLengthMs(), mController.getSpeed()));
|
||||
mStates.put(video.videoId, new State(video.videoId, mController.getPositionMs(), mController.getLengthMs(), mController.getSpeed()));
|
||||
}
|
||||
|
||||
mLastSpeed = mController.getSpeed();
|
||||
}
|
||||
|
||||
private void persistState() {
|
||||
AppPrefs prefs = AppPrefs.instance(mActivity);
|
||||
StringBuilder sb = new StringBuilder();
|
||||
int counter = 0;
|
||||
|
||||
for (State state : mStates.values()) {
|
||||
counter++;
|
||||
|
||||
if (sb.length() != 0) {
|
||||
sb.append("|");
|
||||
}
|
||||
|
||||
sb.append(state);
|
||||
|
||||
if (counter >= MAX_STATE_SIZE) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
prefs.setStateUpdaterData(sb.toString());
|
||||
}
|
||||
|
||||
private void restoreState(String data) {
|
||||
if (data == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
String[] split = data.split("\\|");
|
||||
|
||||
for (String spec : split) {
|
||||
State state = State.from(spec);
|
||||
|
||||
if (state != null) {
|
||||
mStates.put(state.videoId, state);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void trimStorage() {
|
||||
// NOP
|
||||
}
|
||||
@ -208,7 +230,7 @@ public class StateUpdater extends PlayerEventListenerHelper {
|
||||
|
||||
// internal storage has priority over item data loaded from network
|
||||
if (state == null && item.percentWatched > 0 && item.percentWatched < 100) {
|
||||
state = new State(getNewPosition(item.percentWatched));
|
||||
state = new State(item.videoId, getNewPosition(item.percentWatched));
|
||||
}
|
||||
|
||||
if (state != null) {
|
||||
@ -269,10 +291,55 @@ public class StateUpdater extends PlayerEventListenerHelper {
|
||||
for (float speed : speedValues) {
|
||||
items.add(UiOptionItem.from(
|
||||
String.valueOf(speed),
|
||||
optionItem -> {
|
||||
mController.setSpeed(speed);
|
||||
},
|
||||
optionItem -> mController.setSpeed(speed),
|
||||
mController.getSpeed() == speed));
|
||||
}
|
||||
}
|
||||
|
||||
private static class State {
|
||||
public final String videoId;
|
||||
public final long positionMs;
|
||||
private final long lengthMs;
|
||||
public final float speed;
|
||||
|
||||
public State(String videoId, long positionMs) {
|
||||
this(videoId, positionMs, -1);
|
||||
}
|
||||
|
||||
public State(String videoId, long positionMs, long lengthMs) {
|
||||
this(videoId, positionMs, lengthMs, 1.0f);
|
||||
}
|
||||
|
||||
public State(String videoId, long positionMs, long lengthMs, float speed) {
|
||||
this.videoId = videoId;
|
||||
this.positionMs = positionMs;
|
||||
this.lengthMs = lengthMs;
|
||||
this.speed = speed;
|
||||
}
|
||||
|
||||
public static State from(String spec) {
|
||||
if (spec == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
String[] split = spec.split(",");
|
||||
|
||||
if (split.length != 4) {
|
||||
return null;
|
||||
}
|
||||
|
||||
String videoId = split[0];
|
||||
long positionMs = Helpers.parseInt(split[1]);
|
||||
long lengthMs = Helpers.parseInt(split[2]);
|
||||
float speed = Helpers.parseFloat(split[3]);
|
||||
|
||||
return new State(videoId, positionMs, lengthMs, speed);
|
||||
}
|
||||
|
||||
@NonNull
|
||||
@Override
|
||||
public String toString() {
|
||||
return String.format("%s,%s,%s,%s", videoId, positionMs, lengthMs, speed);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -36,10 +36,8 @@ public class VideoLoader extends PlayerEventListenerHelper implements MetadataLi
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onActivity(Activity activity) {
|
||||
super.onActivity(activity);
|
||||
|
||||
mRepeatMode = AppPrefs.instance(activity).getVideoLoaderData(PlaybackUiController.REPEAT_ALL);
|
||||
public void onInitDone() {
|
||||
mRepeatMode = AppPrefs.instance(mActivity).getVideoLoaderData(PlaybackUiController.REPEAT_ALL);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -16,6 +16,7 @@ public class AppPrefs extends SharedPreferencesBase {
|
||||
private static final String AUTO_FRAME_RATE_DATA = "auto_frame_rate_data";
|
||||
private static final String BACKUP_DATA = "backup_data";
|
||||
private static final String VIDEO_LOADER_DATA = "video_loader_data";
|
||||
private static final String STATE_UPDATER_DATA = "state_updater_data";
|
||||
private String mDefaultDisplayMode;
|
||||
private String mCurrentDisplayMode;
|
||||
|
||||
@ -95,4 +96,12 @@ public class AppPrefs extends SharedPreferencesBase {
|
||||
public void setVideoLoaderData(int data) {
|
||||
putInt(VIDEO_LOADER_DATA, data);
|
||||
}
|
||||
|
||||
public String getStateUpdaterData() {
|
||||
return getString(STATE_UPDATER_DATA, null);
|
||||
}
|
||||
|
||||
public void setStateUpdaterData(String data) {
|
||||
putString(STATE_UPDATER_DATA, data);
|
||||
}
|
||||
}
|
||||
|
BIN
images/screen.png
Normal file
BIN
images/screen.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 1.6 MiB |
@ -1,9 +1,10 @@
|
||||
package com.liskovsoft.smartyoutubetv2.tv.ui.widgets.textbadgecard;
|
||||
|
||||
import android.content.Context;
|
||||
import android.os.Handler;
|
||||
import android.os.Looper;
|
||||
import android.text.TextUtils.TruncateAt;
|
||||
import android.util.AttributeSet;
|
||||
import android.view.ViewGroup;
|
||||
import android.widget.ImageView.ScaleType;
|
||||
import android.widget.TextView;
|
||||
import androidx.leanback.widget.ImageCardView;
|
||||
@ -11,6 +12,8 @@ import com.liskovsoft.smartyoutubetv2.tv.R;
|
||||
|
||||
public class TextBadgeImageCardView extends ImageCardView {
|
||||
private TextBadgeImageView mTextBadgeImageLayout;
|
||||
private Handler mHandler;
|
||||
private Runnable mEnableMarquee;
|
||||
|
||||
public TextBadgeImageCardView(Context context) {
|
||||
super(context);
|
||||
@ -30,6 +33,11 @@ public class TextBadgeImageCardView extends ImageCardView {
|
||||
init();
|
||||
}
|
||||
|
||||
private void init() {
|
||||
mTextBadgeImageLayout = findViewById(R.id.main_image_wrapper);
|
||||
mHandler = new Handler(Looper.getMainLooper());
|
||||
}
|
||||
|
||||
private void enableTextAnimation(boolean enable) {
|
||||
TextView title = findViewById(R.id.title_text);
|
||||
TextView content = findViewById(R.id.content_text);
|
||||
@ -39,21 +47,39 @@ public class TextBadgeImageCardView extends ImageCardView {
|
||||
}
|
||||
|
||||
if (enable) {
|
||||
title.setEllipsize(TruncateAt.MARQUEE);
|
||||
title.setMarqueeRepeatLimit(-1);
|
||||
title.setHorizontallyScrolling(true);
|
||||
mEnableMarquee = () -> enableMarquee(title, content);
|
||||
|
||||
content.setEllipsize(TruncateAt.MARQUEE);
|
||||
content.setMarqueeRepeatLimit(-1);
|
||||
content.setHorizontallyScrolling(true);
|
||||
mHandler.postDelayed(mEnableMarquee, 1_000);
|
||||
} else {
|
||||
title.setEllipsize(TruncateAt.END);
|
||||
content.setEllipsize(TruncateAt.END);
|
||||
if (mEnableMarquee != null) {
|
||||
mHandler.removeCallbacks(mEnableMarquee);
|
||||
mEnableMarquee = null;
|
||||
}
|
||||
|
||||
disableMarquee(title, content);
|
||||
}
|
||||
}
|
||||
|
||||
private void init() {
|
||||
mTextBadgeImageLayout = findViewById(R.id.main_image_wrapper);
|
||||
private void disableMarquee(TextView... textViews) {
|
||||
if (textViews == null || textViews.length == 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
for (TextView textView : textViews) {
|
||||
textView.setEllipsize(TruncateAt.END);
|
||||
}
|
||||
}
|
||||
|
||||
private void enableMarquee(TextView... textViews) {
|
||||
if (textViews == null || textViews.length == 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
for (TextView textView : textViews) {
|
||||
textView.setEllipsize(TruncateAt.MARQUEE);
|
||||
textView.setMarqueeRepeatLimit(-1);
|
||||
textView.setHorizontallyScrolling(true);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
Reference in New Issue
Block a user