Merge branch 'master' into dev
This commit is contained in:
commit
124ab56c5f
11 changed files with 238 additions and 75 deletions
|
|
@ -79,8 +79,8 @@ import org.schabi.newpipe.player.Player;
|
|||
import org.schabi.newpipe.player.event.OnKeyDownListener;
|
||||
import org.schabi.newpipe.player.helper.PlayerHolder;
|
||||
import org.schabi.newpipe.player.playqueue.PlayQueue;
|
||||
import org.schabi.newpipe.settings.SettingMigrations;
|
||||
import org.schabi.newpipe.settings.UpdateSettingsFragment;
|
||||
import org.schabi.newpipe.settings.migration.MigrationManager;
|
||||
import org.schabi.newpipe.util.Constants;
|
||||
import org.schabi.newpipe.util.DeviceUtils;
|
||||
import org.schabi.newpipe.util.KioskTranslator;
|
||||
|
|
@ -196,7 +196,7 @@ public class MainActivity extends AppCompatActivity {
|
|||
UpdateSettingsFragment.askForConsentToUpdateChecks(this);
|
||||
}
|
||||
|
||||
SettingMigrations.showUserInfoIfPresent(this);
|
||||
MigrationManager.showUserInfoIfPresent(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
@ -264,19 +264,6 @@ public class MainActivity extends AppCompatActivity {
|
|||
*/
|
||||
private void addDrawerMenuForCurrentService() throws ExtractionException {
|
||||
//Tabs
|
||||
final int currentServiceId = ServiceHelper.getSelectedServiceId(this);
|
||||
final StreamingService service = NewPipe.getService(currentServiceId);
|
||||
|
||||
int kioskMenuItemId = 0;
|
||||
|
||||
for (final String ks : service.getKioskList().getAvailableKiosks()) {
|
||||
drawerLayoutBinding.navigation.getMenu()
|
||||
.add(R.id.menu_tabs_group, kioskMenuItemId, 0, KioskTranslator
|
||||
.getTranslatedKioskName(ks, this))
|
||||
.setIcon(KioskTranslator.getKioskIcon(ks));
|
||||
kioskMenuItemId++;
|
||||
}
|
||||
|
||||
drawerLayoutBinding.navigation.getMenu()
|
||||
.add(R.id.menu_tabs_group, ITEM_ID_SUBSCRIPTIONS, ORDER,
|
||||
R.string.tab_subscriptions)
|
||||
|
|
@ -294,6 +281,20 @@ public class MainActivity extends AppCompatActivity {
|
|||
.add(R.id.menu_tabs_group, ITEM_ID_HISTORY, ORDER, R.string.action_history)
|
||||
.setIcon(R.drawable.ic_history);
|
||||
|
||||
//Kiosks
|
||||
final int currentServiceId = ServiceHelper.getSelectedServiceId(this);
|
||||
final StreamingService service = NewPipe.getService(currentServiceId);
|
||||
|
||||
int kioskMenuItemId = 0;
|
||||
|
||||
for (final String ks : service.getKioskList().getAvailableKiosks()) {
|
||||
drawerLayoutBinding.navigation.getMenu()
|
||||
.add(R.id.menu_kiosks_group, kioskMenuItemId, 0, KioskTranslator
|
||||
.getTranslatedKioskName(ks, this))
|
||||
.setIcon(KioskTranslator.getKioskIcon(ks));
|
||||
kioskMenuItemId++;
|
||||
}
|
||||
|
||||
//Settings and About
|
||||
drawerLayoutBinding.navigation.getMenu()
|
||||
.add(R.id.menu_options_about_group, ITEM_ID_SETTINGS, ORDER, R.string.settings)
|
||||
|
|
@ -313,10 +314,13 @@ public class MainActivity extends AppCompatActivity {
|
|||
changeService(item);
|
||||
break;
|
||||
case R.id.menu_tabs_group:
|
||||
tabSelected(item);
|
||||
break;
|
||||
case R.id.menu_kiosks_group:
|
||||
try {
|
||||
tabSelected(item);
|
||||
kioskSelected(item);
|
||||
} catch (final Exception e) {
|
||||
ErrorUtil.showUiErrorSnackbar(this, "Selecting main page tab", e);
|
||||
ErrorUtil.showUiErrorSnackbar(this, "Selecting drawer kiosk", e);
|
||||
}
|
||||
break;
|
||||
case R.id.menu_options_about_group:
|
||||
|
|
@ -340,7 +344,7 @@ public class MainActivity extends AppCompatActivity {
|
|||
.setChecked(true);
|
||||
}
|
||||
|
||||
private void tabSelected(final MenuItem item) throws ExtractionException {
|
||||
private void tabSelected(final MenuItem item) {
|
||||
switch (item.getItemId()) {
|
||||
case ITEM_ID_SUBSCRIPTIONS:
|
||||
NavigationHelper.openSubscriptionFragment(getSupportFragmentManager());
|
||||
|
|
@ -357,18 +361,19 @@ public class MainActivity extends AppCompatActivity {
|
|||
case ITEM_ID_HISTORY:
|
||||
NavigationHelper.openStatisticFragment(getSupportFragmentManager());
|
||||
break;
|
||||
default:
|
||||
final StreamingService currentService = ServiceHelper.getSelectedService(this);
|
||||
int kioskMenuItemId = 0;
|
||||
for (final String kioskId : currentService.getKioskList().getAvailableKiosks()) {
|
||||
if (kioskMenuItemId == item.getItemId()) {
|
||||
NavigationHelper.openKioskFragment(getSupportFragmentManager(),
|
||||
currentService.getServiceId(), kioskId);
|
||||
break;
|
||||
}
|
||||
kioskMenuItemId++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void kioskSelected(final MenuItem item) throws ExtractionException {
|
||||
final StreamingService currentService = ServiceHelper.getSelectedService(this);
|
||||
int kioskMenuItemId = 0;
|
||||
for (final String kioskId : currentService.getKioskList().getAvailableKiosks()) {
|
||||
if (kioskMenuItemId == item.getItemId()) {
|
||||
NavigationHelper.openKioskFragment(getSupportFragmentManager(),
|
||||
currentService.getServiceId(), kioskId);
|
||||
break;
|
||||
}
|
||||
kioskMenuItemId++;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -409,6 +414,7 @@ public class MainActivity extends AppCompatActivity {
|
|||
|
||||
drawerLayoutBinding.navigation.getMenu().removeGroup(R.id.menu_services_group);
|
||||
drawerLayoutBinding.navigation.getMenu().removeGroup(R.id.menu_tabs_group);
|
||||
drawerLayoutBinding.navigation.getMenu().removeGroup(R.id.menu_kiosks_group);
|
||||
drawerLayoutBinding.navigation.getMenu().removeGroup(R.id.menu_options_about_group);
|
||||
|
||||
// Show up or down arrow
|
||||
|
|
|
|||
|
|
@ -13,6 +13,7 @@ import androidx.preference.PreferenceManager;
|
|||
|
||||
import org.schabi.newpipe.App;
|
||||
import org.schabi.newpipe.R;
|
||||
import org.schabi.newpipe.settings.migration.MigrationManager;
|
||||
import org.schabi.newpipe.util.DeviceUtils;
|
||||
|
||||
import java.io.File;
|
||||
|
|
@ -46,7 +47,7 @@ public final class NewPipeSettings {
|
|||
|
||||
public static void initSettings(final Context context) {
|
||||
// first run migrations, then setDefaultValues, since the latter requires the correct types
|
||||
SettingMigrations.runMigrationsIfNeeded(context);
|
||||
MigrationManager.runMigrationsIfNeeded(context);
|
||||
|
||||
// readAgain is true so that if new settings are added their default value is set
|
||||
PreferenceManager.setDefaultValues(context, R.xml.main_settings, true);
|
||||
|
|
|
|||
|
|
@ -0,0 +1,103 @@
|
|||
package org.schabi.newpipe.settings.migration;
|
||||
|
||||
import android.content.Context;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.appcompat.app.AlertDialog;
|
||||
import androidx.core.util.Consumer;
|
||||
|
||||
import org.schabi.newpipe.R;
|
||||
import org.schabi.newpipe.error.ErrorUtil;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* MigrationManager is responsible for running migrations and showing the user information about
|
||||
* the migrations that were applied.
|
||||
*/
|
||||
public final class MigrationManager {
|
||||
|
||||
private static final String TAG = MigrationManager.class.getSimpleName();
|
||||
/**
|
||||
* List of UI actions that are performed after the UI is initialized (e.g. showing alert
|
||||
* dialogs) to inform the user about changes that were applied by migrations.
|
||||
*/
|
||||
private static final List<Consumer<Context>> MIGRATION_INFO = new ArrayList<>();
|
||||
|
||||
private MigrationManager() {
|
||||
// MigrationManager is a utility class that is completely static
|
||||
}
|
||||
|
||||
/**
|
||||
* Run all migrations that are needed for the current version of NewPipe.
|
||||
* This method should be called at the start of the application, before any other operations
|
||||
* that depend on the settings.
|
||||
*
|
||||
* @param context Context that can be used to run migrations
|
||||
*/
|
||||
public static void runMigrationsIfNeeded(@NonNull final Context context) {
|
||||
SettingMigrations.runMigrationsIfNeeded(context);
|
||||
}
|
||||
|
||||
/**
|
||||
* Perform UI actions informing about migrations that took place if they are present.
|
||||
* @param context Context that can be used to show dialogs/snackbars/toasts
|
||||
*/
|
||||
public static void showUserInfoIfPresent(@NonNull final Context context) {
|
||||
if (MIGRATION_INFO.isEmpty()) {
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
MIGRATION_INFO.get(0).accept(context);
|
||||
} catch (final Exception e) {
|
||||
ErrorUtil.showUiErrorSnackbar(context, "Showing migration info to the user", e);
|
||||
// Remove the migration that caused the error and continue with the next one
|
||||
MIGRATION_INFO.remove(0);
|
||||
showUserInfoIfPresent(context);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a migration info action that will be executed after the UI is initialized.
|
||||
* This can be used to show dialogs/snackbars/toasts to inform the user about changes that
|
||||
* were applied by migrations.
|
||||
*
|
||||
* @param info the action to be executed
|
||||
*/
|
||||
public static void addMigrationInfo(final Consumer<Context> info) {
|
||||
MIGRATION_INFO.add(info);
|
||||
}
|
||||
|
||||
/**
|
||||
* This method should be called when the user dismisses the migration info
|
||||
* to check if there are any more migration info actions to be shown.
|
||||
* @param context Context that can be used to show dialogs/snackbars/toasts
|
||||
*/
|
||||
public static void onMigrationInfoDismissed(@NonNull final Context context) {
|
||||
MIGRATION_INFO.remove(0);
|
||||
showUserInfoIfPresent(context);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a dialog to inform the user about the migration.
|
||||
* @param uiContext Context that can be used to show dialogs/snackbars/toasts
|
||||
* @param title the title of the dialog
|
||||
* @param message the message of the dialog
|
||||
* @return the dialog that can be shown to the user with a custom dismiss listener
|
||||
*/
|
||||
static AlertDialog createMigrationInfoDialog(@NonNull final Context uiContext,
|
||||
@NonNull final String title,
|
||||
@NonNull final String message) {
|
||||
return new AlertDialog.Builder(uiContext)
|
||||
.setTitle(title)
|
||||
.setMessage(message)
|
||||
.setPositiveButton(R.string.ok, null)
|
||||
.setOnDismissListener(dialog ->
|
||||
MigrationManager.onMigrationInfoDismissed(uiContext))
|
||||
.setCancelable(false) // prevents the dialog from being dismissed accidentally
|
||||
.create();
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -1,11 +1,14 @@
|
|||
package org.schabi.newpipe.settings;
|
||||
package org.schabi.newpipe.settings.migration;
|
||||
|
||||
import static org.schabi.newpipe.MainActivity.DEBUG;
|
||||
import static org.schabi.newpipe.extractor.ServiceList.SoundCloud;
|
||||
import static org.schabi.newpipe.extractor.ServiceList.YouTube;
|
||||
|
||||
import android.content.Context;
|
||||
import android.content.SharedPreferences;
|
||||
import android.util.Log;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.appcompat.app.AlertDialog;
|
||||
import androidx.core.util.Consumer;
|
||||
import androidx.preference.PreferenceManager;
|
||||
|
||||
|
|
@ -18,34 +21,34 @@ import org.schabi.newpipe.settings.tabs.Tab;
|
|||
import org.schabi.newpipe.settings.tabs.TabsManager;
|
||||
import org.schabi.newpipe.util.DeviceUtils;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import static org.schabi.newpipe.MainActivity.DEBUG;
|
||||
import static org.schabi.newpipe.extractor.ServiceList.SoundCloud;
|
||||
|
||||
/**
|
||||
* In order to add a migration, follow these steps, given P is the previous version:<br>
|
||||
* - in the class body add a new {@code MIGRATION_P_P+1 = new Migration(P, P+1) { ... }} and put in
|
||||
* the {@code migrate()} method the code that need to be run when migrating from P to P+1<br>
|
||||
* - add {@code MIGRATION_P_P+1} at the end of {@link SettingMigrations#SETTING_MIGRATIONS}<br>
|
||||
* - increment {@link SettingMigrations#VERSION}'s value by 1 (so it should become P+1)
|
||||
* This class contains the code to migrate the settings from one version to another.
|
||||
* Migrations are run automatically when the app is started and the settings version changed.
|
||||
* <br>
|
||||
* In order to add a migration, follow these steps, given {@code P} is the previous version:
|
||||
* <ul>
|
||||
* <li>in the class body add a new {@code MIGRATION_P_P+1 = new Migration(P, P+1) { ... }} and put
|
||||
* in the {@code migrate()} method the code that need to be run
|
||||
* when migrating from {@code P} to {@code P+1}</li>
|
||||
* <li>add {@code MIGRATION_P_P+1} at the end of {@link SettingMigrations#SETTING_MIGRATIONS}</li>
|
||||
* <li>increment {@link SettingMigrations#VERSION}'s value by 1
|
||||
* (so it becomes {@code P+1})</li>
|
||||
* </ul>
|
||||
* Migrations can register UI actions using {@link MigrationManager#addMigrationInfo(Consumer)}
|
||||
* that will be performed after the UI is initialized to inform the user about changes
|
||||
* that were applied by migrations.
|
||||
*/
|
||||
public final class SettingMigrations {
|
||||
|
||||
private static final String TAG = SettingMigrations.class.toString();
|
||||
private static SharedPreferences sp;
|
||||
|
||||
/**
|
||||
* List of UI actions that are performed after the UI is initialized (e.g. showing alert
|
||||
* dialogs) to inform the user about changes that were applied by migrations.
|
||||
*/
|
||||
private static final List<Consumer<Context>> MIGRATION_INFO = new ArrayList<>();
|
||||
|
||||
private static final Migration MIGRATION_0_1 = new Migration(0, 1) {
|
||||
@Override
|
||||
public void migrate(@NonNull final Context context) {
|
||||
|
|
@ -172,13 +175,48 @@ public final class SettingMigrations {
|
|||
if (tabs.size() != cleanedTabs.size()) {
|
||||
tabsManager.saveTabs(cleanedTabs);
|
||||
// create an AlertDialog to inform the user about the change
|
||||
MIGRATION_INFO.add((Context uiContext) -> new AlertDialog.Builder(uiContext)
|
||||
.setTitle(R.string.migration_info_6_7_title)
|
||||
.setMessage(R.string.migration_info_6_7_message)
|
||||
.setPositiveButton(R.string.ok, null)
|
||||
.setCancelable(false)
|
||||
.create()
|
||||
.show());
|
||||
MigrationManager.addMigrationInfo(uiContext ->
|
||||
MigrationManager.createMigrationInfoDialog(
|
||||
uiContext,
|
||||
uiContext.getString(R.string.migration_info_6_7_title),
|
||||
uiContext.getString(R.string.migration_info_6_7_message))
|
||||
.show());
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
private static final Migration MIGRATION_7_8 = new Migration(7, 8) {
|
||||
@Override
|
||||
protected void migrate(@NonNull final Context context) {
|
||||
// YouTube remove the combined Trending kiosk, see
|
||||
// https://github.com/TeamNewPipe/NewPipe/discussions/12445 for more information.
|
||||
// If the user has a dedicated YouTube/Trending kiosk tab,
|
||||
// it is removed and replaced with the new live kiosk tab.
|
||||
// The default trending kiosk tab is not touched
|
||||
// because it uses the default kiosk provided by the extractor
|
||||
// and is thus updated automatically.
|
||||
final TabsManager tabsManager = TabsManager.getManager(context);
|
||||
final List<Tab> tabs = tabsManager.getTabs();
|
||||
final List<Tab> cleanedTabs = tabs.stream()
|
||||
.filter(tab -> !(tab instanceof Tab.KioskTab kioskTab
|
||||
&& kioskTab.getKioskServiceId() == YouTube.getServiceId()
|
||||
&& kioskTab.getKioskId().equals("Trending")))
|
||||
.collect(Collectors.toUnmodifiableList());
|
||||
if (tabs.size() != cleanedTabs.size()) {
|
||||
tabsManager.saveTabs(cleanedTabs);
|
||||
}
|
||||
|
||||
final boolean hasDefaultTrendingTab = tabs.stream()
|
||||
.anyMatch(tab -> tab instanceof Tab.DefaultKioskTab);
|
||||
|
||||
if (tabs.size() != cleanedTabs.size() || hasDefaultTrendingTab) {
|
||||
// User is informed about the change
|
||||
MigrationManager.addMigrationInfo(uiContext ->
|
||||
MigrationManager.createMigrationInfoDialog(
|
||||
uiContext,
|
||||
uiContext.getString(R.string.migration_info_7_8_title),
|
||||
uiContext.getString(R.string.migration_info_7_8_message))
|
||||
.show());
|
||||
}
|
||||
}
|
||||
};
|
||||
|
|
@ -196,16 +234,17 @@ public final class SettingMigrations {
|
|||
MIGRATION_3_4,
|
||||
MIGRATION_4_5,
|
||||
MIGRATION_5_6,
|
||||
MIGRATION_6_7
|
||||
MIGRATION_6_7,
|
||||
MIGRATION_7_8,
|
||||
};
|
||||
|
||||
/**
|
||||
* Version number for preferences. Must be incremented every time a migration is necessary.
|
||||
*/
|
||||
private static final int VERSION = 7;
|
||||
private static final int VERSION = 8;
|
||||
|
||||
|
||||
public static void runMigrationsIfNeeded(@NonNull final Context context) {
|
||||
static void runMigrationsIfNeeded(@NonNull final Context context) {
|
||||
// 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);
|
||||
|
|
@ -249,21 +288,6 @@ public final class SettingMigrations {
|
|||
sp.edit().putInt(lastPrefVersionKey, currentVersion).apply();
|
||||
}
|
||||
|
||||
/**
|
||||
* Perform UI actions informing about migrations that took place if they are present.
|
||||
* @param context Context that can be used to show dialogs/snackbars/toasts
|
||||
*/
|
||||
public static void showUserInfoIfPresent(@NonNull final Context context) {
|
||||
for (final Consumer<Context> consumer : MIGRATION_INFO) {
|
||||
try {
|
||||
consumer.accept(context);
|
||||
} catch (final Exception e) {
|
||||
ErrorUtil.showUiErrorSnackbar(context, "Showing migration info to the user", e);
|
||||
}
|
||||
}
|
||||
MIGRATION_INFO.clear();
|
||||
}
|
||||
|
||||
private SettingMigrations() { }
|
||||
|
||||
abstract static class Migration {
|
||||
|
|
@ -52,6 +52,14 @@ public final class KioskTranslator {
|
|||
return c.getString(R.string.featured);
|
||||
case "Radio":
|
||||
return c.getString(R.string.radio);
|
||||
case "trending_gaming":
|
||||
return c.getString(R.string.trending_gaming);
|
||||
case "trending_music":
|
||||
return c.getString(R.string.trending_music);
|
||||
case "trending_movies_and_shows":
|
||||
return c.getString(R.string.trending_movies);
|
||||
case "trending_podcasts_episodes":
|
||||
return c.getString(R.string.trending_podcasts);
|
||||
default:
|
||||
return kioskId;
|
||||
}
|
||||
|
|
@ -77,6 +85,14 @@ public final class KioskTranslator {
|
|||
return R.drawable.ic_stars;
|
||||
case "Radio":
|
||||
return R.drawable.ic_radio;
|
||||
case "trending_gaming":
|
||||
return R.drawable.ic_videogame_asset;
|
||||
case "trending_music":
|
||||
return R.drawable.ic_music_note;
|
||||
case "trending_movies_and_shows":
|
||||
return R.drawable.ic_movie;
|
||||
case "trending_podcasts_episodes":
|
||||
return R.drawable.ic_podcasts;
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -388,9 +388,10 @@ public final class Localization {
|
|||
* {@code parsed != null} and the relevant setting is enabled, {@code textual} will
|
||||
* be appended to the returned string for debugging purposes.
|
||||
*/
|
||||
@Nullable
|
||||
public static String relativeTimeOrTextual(@Nullable final Context context,
|
||||
@Nullable final DateWrapper parsed,
|
||||
final String textual) {
|
||||
@Nullable final String textual) {
|
||||
if (parsed == null) {
|
||||
return textual;
|
||||
} else if (DEBUG && context != null && PreferenceManager
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue