Merge pull request #4259 from TeamNewPipe/pref_migration
Add settings migration, remove "Detail page" option from share dialog and minimize to background by default
This commit is contained in:
commit
d5f603303d
7 changed files with 225 additions and 35 deletions
|
@ -39,6 +39,7 @@ import org.schabi.newpipe.extractor.exceptions.ExtractionException;
|
||||||
import org.schabi.newpipe.extractor.playlist.PlaylistInfo;
|
import org.schabi.newpipe.extractor.playlist.PlaylistInfo;
|
||||||
import org.schabi.newpipe.extractor.stream.StreamInfo;
|
import org.schabi.newpipe.extractor.stream.StreamInfo;
|
||||||
import org.schabi.newpipe.extractor.stream.VideoStream;
|
import org.schabi.newpipe.extractor.stream.VideoStream;
|
||||||
|
import org.schabi.newpipe.player.helper.PlayerHelper;
|
||||||
import org.schabi.newpipe.player.playqueue.ChannelPlayQueue;
|
import org.schabi.newpipe.player.playqueue.ChannelPlayQueue;
|
||||||
import org.schabi.newpipe.player.playqueue.PlayQueue;
|
import org.schabi.newpipe.player.playqueue.PlayQueue;
|
||||||
import org.schabi.newpipe.player.playqueue.PlaylistPlayQueue;
|
import org.schabi.newpipe.player.playqueue.PlaylistPlayQueue;
|
||||||
|
@ -278,6 +279,7 @@ public class RouterActivity extends AppCompatActivity {
|
||||||
|
|
||||||
handleChoice(choice.key);
|
handleChoice(choice.key);
|
||||||
|
|
||||||
|
// open future streams always like this one, because "always" button was used by user
|
||||||
if (which == DialogInterface.BUTTON_POSITIVE) {
|
if (which == DialogInterface.BUTTON_POSITIVE) {
|
||||||
preferences.edit()
|
preferences.edit()
|
||||||
.putString(getString(R.string.preferred_open_action_key), choice.key)
|
.putString(getString(R.string.preferred_open_action_key), choice.key)
|
||||||
|
@ -377,23 +379,50 @@ public class RouterActivity extends AppCompatActivity {
|
||||||
final boolean isExtAudioEnabled = preferences.getBoolean(
|
final boolean isExtAudioEnabled = preferences.getBoolean(
|
||||||
getString(R.string.use_external_audio_player_key), false);
|
getString(R.string.use_external_audio_player_key), false);
|
||||||
|
|
||||||
returnList.add(new AdapterChoiceItem(getString(R.string.show_info_key),
|
final AdapterChoiceItem videoPlayer = new AdapterChoiceItem(
|
||||||
getString(R.string.show_info),
|
getString(R.string.video_player_key), getString(R.string.video_player),
|
||||||
resolveResourceIdFromAttr(context, R.attr.ic_info_outline)));
|
resolveResourceIdFromAttr(context, R.attr.ic_play_arrow));
|
||||||
|
final AdapterChoiceItem showInfo = new AdapterChoiceItem(
|
||||||
|
getString(R.string.show_info_key), getString(R.string.show_info),
|
||||||
|
resolveResourceIdFromAttr(context, R.attr.ic_info_outline));
|
||||||
|
final AdapterChoiceItem popupPlayer = new AdapterChoiceItem(
|
||||||
|
getString(R.string.popup_player_key), getString(R.string.popup_player),
|
||||||
|
resolveResourceIdFromAttr(context, R.attr.ic_popup));
|
||||||
|
final AdapterChoiceItem backgroundPlayer = new AdapterChoiceItem(
|
||||||
|
getString(R.string.background_player_key), getString(R.string.background_player),
|
||||||
|
resolveResourceIdFromAttr(context, R.attr.ic_headset));
|
||||||
|
|
||||||
if (capabilities.contains(VIDEO) && !(isExtVideoEnabled && linkType != LinkType.STREAM)) {
|
if (linkType == LinkType.STREAM) {
|
||||||
returnList.add(new AdapterChoiceItem(getString(R.string.video_player_key),
|
if (isExtVideoEnabled) {
|
||||||
getString(R.string.video_player),
|
// show both "show info" and "video player", they are two different activities
|
||||||
resolveResourceIdFromAttr(context, R.attr.ic_play_arrow)));
|
returnList.add(showInfo);
|
||||||
returnList.add(new AdapterChoiceItem(getString(R.string.popup_player_key),
|
returnList.add(videoPlayer);
|
||||||
getString(R.string.popup_player),
|
} else if (capabilities.contains(VIDEO)
|
||||||
resolveResourceIdFromAttr(context, R.attr.ic_popup)));
|
&& PlayerHelper.isAutoplayAllowedByUser(context)) {
|
||||||
|
// show only "video player" since the details activity will be opened and the video
|
||||||
|
// will be autoplayed there and "show info" would do the exact same thing
|
||||||
|
returnList.add(videoPlayer);
|
||||||
|
} else {
|
||||||
|
// show only "show info" if video player is not applicable or autoplay is disabled
|
||||||
|
returnList.add(showInfo);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (capabilities.contains(AUDIO) && !(isExtAudioEnabled && linkType != LinkType.STREAM)) {
|
if (capabilities.contains(VIDEO)) {
|
||||||
returnList.add(new AdapterChoiceItem(getString(R.string.background_player_key),
|
returnList.add(popupPlayer);
|
||||||
getString(R.string.background_player),
|
}
|
||||||
resolveResourceIdFromAttr(context, R.attr.ic_headset)));
|
if (capabilities.contains(AUDIO)) {
|
||||||
|
returnList.add(backgroundPlayer);
|
||||||
|
}
|
||||||
|
|
||||||
|
} else {
|
||||||
|
returnList.add(showInfo);
|
||||||
|
if (capabilities.contains(VIDEO) && !isExtVideoEnabled) {
|
||||||
|
returnList.add(videoPlayer);
|
||||||
|
returnList.add(popupPlayer);
|
||||||
|
}
|
||||||
|
if (capabilities.contains(AUDIO) && !isExtAudioEnabled) {
|
||||||
|
returnList.add(backgroundPlayer);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
returnList.add(new AdapterChoiceItem(getString(R.string.download_key),
|
returnList.add(new AdapterChoiceItem(getString(R.string.download_key),
|
||||||
|
|
|
@ -1236,7 +1236,7 @@ public class VideoDetailFragment
|
||||||
}
|
}
|
||||||
|
|
||||||
private boolean isExternalPlayerEnabled() {
|
private boolean isExternalPlayerEnabled() {
|
||||||
return PreferenceManager.getDefaultSharedPreferences(getContext())
|
return PreferenceManager.getDefaultSharedPreferences(requireContext())
|
||||||
.getBoolean(getString(R.string.use_external_video_player_key), false);
|
.getBoolean(getString(R.string.use_external_video_player_key), false);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1247,23 +1247,7 @@ public class VideoDetailFragment
|
||||||
&& !isExternalPlayerEnabled()
|
&& !isExternalPlayerEnabled()
|
||||||
&& (player == null || player.videoPlayerSelected())
|
&& (player == null || player.videoPlayerSelected())
|
||||||
&& bottomSheetState != BottomSheetBehavior.STATE_HIDDEN
|
&& bottomSheetState != BottomSheetBehavior.STATE_HIDDEN
|
||||||
&& isAutoplayAllowedByUser();
|
&& PlayerHelper.isAutoplayAllowedByUser(requireContext());
|
||||||
}
|
|
||||||
|
|
||||||
private boolean isAutoplayAllowedByUser() {
|
|
||||||
if (activity == null) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
switch (PlayerHelper.getAutoplayType(activity)) {
|
|
||||||
case PlayerHelper.AutoplayType.AUTOPLAY_TYPE_NEVER:
|
|
||||||
return false;
|
|
||||||
case PlayerHelper.AutoplayType.AUTOPLAY_TYPE_WIFI:
|
|
||||||
return !ListHelper.isMeteredNetwork(activity);
|
|
||||||
case PlayerHelper.AutoplayType.AUTOPLAY_TYPE_ALWAYS:
|
|
||||||
default:
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void addVideoPlayerView() {
|
private void addVideoPlayerView() {
|
||||||
|
|
|
@ -28,6 +28,7 @@ import org.schabi.newpipe.extractor.stream.VideoStream;
|
||||||
import org.schabi.newpipe.player.playqueue.PlayQueue;
|
import org.schabi.newpipe.player.playqueue.PlayQueue;
|
||||||
import org.schabi.newpipe.player.playqueue.PlayQueueItem;
|
import org.schabi.newpipe.player.playqueue.PlayQueueItem;
|
||||||
import org.schabi.newpipe.player.playqueue.SinglePlayQueue;
|
import org.schabi.newpipe.player.playqueue.SinglePlayQueue;
|
||||||
|
import org.schabi.newpipe.util.ListHelper;
|
||||||
|
|
||||||
import java.lang.annotation.Retention;
|
import java.lang.annotation.Retention;
|
||||||
import java.text.DecimalFormat;
|
import java.text.DecimalFormat;
|
||||||
|
@ -248,6 +249,18 @@ public final class PlayerHelper {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static boolean isAutoplayAllowedByUser(@NonNull final Context context) {
|
||||||
|
switch (PlayerHelper.getAutoplayType(context)) {
|
||||||
|
case PlayerHelper.AutoplayType.AUTOPLAY_TYPE_NEVER:
|
||||||
|
return false;
|
||||||
|
case PlayerHelper.AutoplayType.AUTOPLAY_TYPE_WIFI:
|
||||||
|
return !ListHelper.isMeteredNetwork(context);
|
||||||
|
case PlayerHelper.AutoplayType.AUTOPLAY_TYPE_ALWAYS:
|
||||||
|
default:
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@NonNull
|
@NonNull
|
||||||
public static SeekParameters getSeekParameters(@NonNull final Context context) {
|
public static SeekParameters getSeekParameters(@NonNull final Context context) {
|
||||||
return isUsingInexactSeek(context) ? SeekParameters.CLOSEST_SYNC : SeekParameters.EXACT;
|
return isUsingInexactSeek(context) ? SeekParameters.CLOSEST_SYNC : SeekParameters.EXACT;
|
||||||
|
|
|
@ -20,7 +20,8 @@ public enum UserAction {
|
||||||
DELETE_FROM_HISTORY("delete from history"),
|
DELETE_FROM_HISTORY("delete from history"),
|
||||||
PLAY_STREAM("Play stream"),
|
PLAY_STREAM("Play stream"),
|
||||||
DOWNLOAD_POSTPROCESSING("download post-processing"),
|
DOWNLOAD_POSTPROCESSING("download post-processing"),
|
||||||
DOWNLOAD_FAILED("download failed");
|
DOWNLOAD_FAILED("download failed"),
|
||||||
|
PREFERENCES_MIGRATION("migration of preferences");
|
||||||
|
|
||||||
|
|
||||||
private final String message;
|
private final String message;
|
||||||
|
|
|
@ -10,6 +10,7 @@ import androidx.preference.PreferenceManager;
|
||||||
import org.schabi.newpipe.R;
|
import org.schabi.newpipe.R;
|
||||||
|
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
|
import java.util.Set;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Created by k3b on 07.01.2016.
|
* Created by k3b on 07.01.2016.
|
||||||
|
@ -38,6 +39,22 @@ public final class NewPipeSettings {
|
||||||
private NewPipeSettings() { }
|
private NewPipeSettings() { }
|
||||||
|
|
||||||
public static void initSettings(final Context context) {
|
public static void initSettings(final Context context) {
|
||||||
|
// check if there are entries in the prefs to determine whether this is the first app run
|
||||||
|
Boolean isFirstRun = null;
|
||||||
|
final Set<String> prefsKeys = PreferenceManager.getDefaultSharedPreferences(context)
|
||||||
|
.getAll().keySet();
|
||||||
|
for (final String key: prefsKeys) {
|
||||||
|
// ACRA stores some info in the prefs during app initialization
|
||||||
|
// which happens before this method is called. Therefore ignore ACRA-related keys.
|
||||||
|
if (!key.toLowerCase().startsWith("acra")) {
|
||||||
|
isFirstRun = false;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (isFirstRun == null) {
|
||||||
|
isFirstRun = true;
|
||||||
|
}
|
||||||
|
|
||||||
PreferenceManager.setDefaultValues(context, R.xml.appearance_settings, true);
|
PreferenceManager.setDefaultValues(context, R.xml.appearance_settings, true);
|
||||||
PreferenceManager.setDefaultValues(context, R.xml.content_settings, true);
|
PreferenceManager.setDefaultValues(context, R.xml.content_settings, true);
|
||||||
PreferenceManager.setDefaultValues(context, R.xml.download_settings, true);
|
PreferenceManager.setDefaultValues(context, R.xml.download_settings, true);
|
||||||
|
@ -48,6 +65,8 @@ public final class NewPipeSettings {
|
||||||
|
|
||||||
getVideoDownloadFolder(context);
|
getVideoDownloadFolder(context);
|
||||||
getAudioDownloadFolder(context);
|
getAudioDownloadFolder(context);
|
||||||
|
|
||||||
|
SettingMigrations.initMigrations(context, isFirstRun);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void getVideoDownloadFolder(final Context context) {
|
private static void getVideoDownloadFolder(final Context context) {
|
||||||
|
|
|
@ -0,0 +1,140 @@
|
||||||
|
package org.schabi.newpipe.settings;
|
||||||
|
|
||||||
|
import android.content.Context;
|
||||||
|
import android.content.SharedPreferences;
|
||||||
|
import android.util.Log;
|
||||||
|
|
||||||
|
import androidx.preference.PreferenceManager;
|
||||||
|
|
||||||
|
import org.schabi.newpipe.R;
|
||||||
|
import org.schabi.newpipe.report.ErrorActivity;
|
||||||
|
import org.schabi.newpipe.report.ErrorActivity.ErrorInfo;
|
||||||
|
import org.schabi.newpipe.report.UserAction;
|
||||||
|
|
||||||
|
import static org.schabi.newpipe.MainActivity.DEBUG;
|
||||||
|
|
||||||
|
public final class SettingMigrations {
|
||||||
|
private static final String TAG = SettingMigrations.class.toString();
|
||||||
|
/**
|
||||||
|
* Version number for preferences. Must be incremented every time a migration is necessary.
|
||||||
|
*/
|
||||||
|
public static final int VERSION = 2;
|
||||||
|
private static SharedPreferences sp;
|
||||||
|
|
||||||
|
public static final Migration MIGRATION_0_1 = new Migration(0, 1) {
|
||||||
|
@Override
|
||||||
|
public void migrate(final Context context) {
|
||||||
|
// We changed the content of the dialog which opens when sharing a link to NewPipe
|
||||||
|
// by removing the "open detail page" option.
|
||||||
|
// Therefore, show the dialog once again to ensure users need to choose again and are
|
||||||
|
// aware of the changed dialog.
|
||||||
|
final SharedPreferences.Editor editor = sp.edit();
|
||||||
|
editor.putString(context.getString(R.string.preferred_open_action_key),
|
||||||
|
context.getString(R.string.always_ask_open_action_key));
|
||||||
|
editor.apply();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
public static final Migration MIGRATION_1_2 = new Migration(1, 2) {
|
||||||
|
@Override
|
||||||
|
protected void migrate(final Context context) {
|
||||||
|
// The new application workflow introduced in #2907 allows minimizing videos
|
||||||
|
// while playing to do other stuff within the app.
|
||||||
|
// For an even better workflow, we minimize a stream when switching the app to play in
|
||||||
|
// background.
|
||||||
|
// Therefore, set default value to background, if it has not been changed yet.
|
||||||
|
final String minimizeOnExitKey = context.getString(R.string.minimize_on_exit_key);
|
||||||
|
if (sp.getString(minimizeOnExitKey, "")
|
||||||
|
.equals(context.getString(R.string.minimize_on_exit_none_key))) {
|
||||||
|
final SharedPreferences.Editor editor = sp.edit();
|
||||||
|
editor.putString(minimizeOnExitKey,
|
||||||
|
context.getString(R.string.minimize_on_exit_background_key));
|
||||||
|
editor.apply();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* List of all implemented migrations.
|
||||||
|
* <p>
|
||||||
|
* <b>Append new migrations to the end of the list</b> to keep it sorted ascending.
|
||||||
|
* If not sorted correctly, migrations which depend on each other, may fail.
|
||||||
|
*/
|
||||||
|
private static final Migration[] SETTING_MIGRATIONS = {
|
||||||
|
MIGRATION_0_1,
|
||||||
|
MIGRATION_1_2
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
public static void initMigrations(final Context context, final boolean isFirstRun) {
|
||||||
|
// setup migrations and check if there is something to do
|
||||||
|
sp = PreferenceManager.getDefaultSharedPreferences(context);
|
||||||
|
final String lastPrefVersionKey = context.getString(R.string.last_used_preferences_version);
|
||||||
|
final int lastPrefVersion = sp.getInt(lastPrefVersionKey, 0);
|
||||||
|
|
||||||
|
// no migration to run, already up to date
|
||||||
|
if (isFirstRun) {
|
||||||
|
sp.edit().putInt(lastPrefVersionKey, VERSION).apply();
|
||||||
|
return;
|
||||||
|
} else if (lastPrefVersion == VERSION) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// run migrations
|
||||||
|
int currentVersion = lastPrefVersion;
|
||||||
|
for (final Migration currentMigration : SETTING_MIGRATIONS) {
|
||||||
|
try {
|
||||||
|
if (currentMigration.shouldMigrate(currentVersion)) {
|
||||||
|
if (DEBUG) {
|
||||||
|
Log.d(TAG, "Migrating preferences from version "
|
||||||
|
+ currentVersion + " to " + currentMigration.newVersion);
|
||||||
|
}
|
||||||
|
currentMigration.migrate(context);
|
||||||
|
currentVersion = currentMigration.newVersion;
|
||||||
|
}
|
||||||
|
} catch (final Exception e) {
|
||||||
|
// save the version with the last successful migration and report the error
|
||||||
|
sp.edit().putInt(lastPrefVersionKey, currentVersion).apply();
|
||||||
|
final ErrorInfo errorInfo = ErrorInfo.make(
|
||||||
|
UserAction.PREFERENCES_MIGRATION,
|
||||||
|
"none",
|
||||||
|
"Migrating preferences from version " + lastPrefVersion + " to "
|
||||||
|
+ VERSION + ". "
|
||||||
|
+ "Error at " + currentVersion + " => " + ++currentVersion,
|
||||||
|
0
|
||||||
|
);
|
||||||
|
ErrorActivity.reportError(context, e, SettingMigrations.class, null, errorInfo);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// store the current preferences version
|
||||||
|
sp.edit().putInt(lastPrefVersionKey, currentVersion).apply();
|
||||||
|
}
|
||||||
|
|
||||||
|
private SettingMigrations() { }
|
||||||
|
|
||||||
|
abstract static class Migration {
|
||||||
|
public final int oldVersion;
|
||||||
|
public final int newVersion;
|
||||||
|
|
||||||
|
protected Migration(final int oldVersion, final int newVersion) {
|
||||||
|
this.oldVersion = oldVersion;
|
||||||
|
this.newVersion = newVersion;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param currentVersion current settings version
|
||||||
|
* @return Returns whether this migration should be run.
|
||||||
|
* A migration is necessary if the old version of this migration is lower than or equal to
|
||||||
|
* the current settings version.
|
||||||
|
*/
|
||||||
|
private boolean shouldMigrate(final int currentVersion) {
|
||||||
|
return oldVersion >= currentVersion;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected abstract void migrate(Context context);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -1,5 +1,9 @@
|
||||||
<?xml version="1.0" encoding="utf-8"?>
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
<resources translatable="false">
|
<resources translatable="false">
|
||||||
|
<!-- App versioning -->
|
||||||
|
<string name="last_used_version" translatable="false">last_used_version</string>
|
||||||
|
<string name="last_used_preferences_version" translatable="false">last_used_preferences_version</string>
|
||||||
|
|
||||||
<!-- Service -->
|
<!-- Service -->
|
||||||
<string-array name="service_list" translatable="false">
|
<string-array name="service_list" translatable="false">
|
||||||
<item>@string/youtube</item>
|
<item>@string/youtube</item>
|
||||||
|
@ -52,7 +56,7 @@
|
||||||
</string-array>
|
</string-array>
|
||||||
|
|
||||||
<string name="minimize_on_exit_key" translatable="false">minimize_on_exit_key</string>
|
<string name="minimize_on_exit_key" translatable="false">minimize_on_exit_key</string>
|
||||||
<string name="minimize_on_exit_value" translatable="false">@string/minimize_on_exit_none_key</string>
|
<string name="minimize_on_exit_value" translatable="false">@string/minimize_on_exit_background_key</string>
|
||||||
<string name="minimize_on_exit_none_key" translatable="false">minimize_on_exit_none_key</string>
|
<string name="minimize_on_exit_none_key" translatable="false">minimize_on_exit_none_key</string>
|
||||||
<string name="minimize_on_exit_background_key" translatable="false">minimize_on_exit_background_key</string>
|
<string name="minimize_on_exit_background_key" translatable="false">minimize_on_exit_background_key</string>
|
||||||
<string name="minimize_on_exit_popup_key" translatable="false">minimize_on_exit_popup_key</string>
|
<string name="minimize_on_exit_popup_key" translatable="false">minimize_on_exit_popup_key</string>
|
||||||
|
|
Loading…
Reference in a new issue