From ed93603815df0e58dcff19c72d412abd52444741 Mon Sep 17 00:00:00 2001 From: TobiGr Date: Tue, 22 Jul 2025 00:01:40 +0200 Subject: [PATCH 1/7] WIP: Add SettingsMigration to change YouTube trending kiosk tab --- .../java/org/schabi/newpipe/MainActivity.java | 4 +- .../newpipe/settings/NewPipeSettings.java | 3 +- .../settings/migration/MigrationManager.java | 103 ++++++++++++++ .../{ => migration}/SettingMigrations.java | 128 ++++++++++++------ app/src/main/res/values/strings.xml | 2 + 5 files changed, 192 insertions(+), 48 deletions(-) create mode 100644 app/src/main/java/org/schabi/newpipe/settings/migration/MigrationManager.java rename app/src/main/java/org/schabi/newpipe/settings/{ => migration}/SettingMigrations.java (69%) diff --git a/app/src/main/java/org/schabi/newpipe/MainActivity.java b/app/src/main/java/org/schabi/newpipe/MainActivity.java index 21f4f97a18f..1aae7fa8655 100644 --- a/app/src/main/java/org/schabi/newpipe/MainActivity.java +++ b/app/src/main/java/org/schabi/newpipe/MainActivity.java @@ -78,8 +78,8 @@ 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; @@ -195,7 +195,7 @@ protected void onCreate(final Bundle savedInstanceState) { UpdateSettingsFragment.askForConsentToUpdateChecks(this); } - SettingMigrations.showUserInfoIfPresent(this); + MigrationManager.showUserInfoIfPresent(this); } @Override diff --git a/app/src/main/java/org/schabi/newpipe/settings/NewPipeSettings.java b/app/src/main/java/org/schabi/newpipe/settings/NewPipeSettings.java index 421440ea7f8..0a5512c699f 100644 --- a/app/src/main/java/org/schabi/newpipe/settings/NewPipeSettings.java +++ b/app/src/main/java/org/schabi/newpipe/settings/NewPipeSettings.java @@ -13,6 +13,7 @@ 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 @@ private 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); diff --git a/app/src/main/java/org/schabi/newpipe/settings/migration/MigrationManager.java b/app/src/main/java/org/schabi/newpipe/settings/migration/MigrationManager.java new file mode 100644 index 00000000000..d5b0e783d00 --- /dev/null +++ b/app/src/main/java/org/schabi/newpipe/settings/migration/MigrationManager.java @@ -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> 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 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(); + } + +} diff --git a/app/src/main/java/org/schabi/newpipe/settings/SettingMigrations.java b/app/src/main/java/org/schabi/newpipe/settings/migration/SettingMigrations.java similarity index 69% rename from app/src/main/java/org/schabi/newpipe/settings/SettingMigrations.java rename to app/src/main/java/org/schabi/newpipe/settings/migration/SettingMigrations.java index d13e730908a..99af2776612 100644 --- a/app/src/main/java/org/schabi/newpipe/settings/SettingMigrations.java +++ b/app/src/main/java/org/schabi/newpipe/settings/migration/SettingMigrations.java @@ -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; @@ -25,27 +28,28 @@ 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:
- * - 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
- * - add {@code MIGRATION_P_P+1} at the end of {@link SettingMigrations#SETTING_MIGRATIONS}
- * - 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. + *
+ * In order to add a migration, follow these steps, given {@code P} is the previous version: + *
    + *
  • 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}
  • + *
  • add {@code MIGRATION_P_P+1} at the end of {@link SettingMigrations#SETTING_MIGRATIONS}
  • + *
  • increment {@link SettingMigrations#VERSION}'s value by 1 + * (so it becomes {@code P+1})
  • + *
+ * 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> MIGRATION_INFO = new ArrayList<>(); - private static final Migration MIGRATION_0_1 = new Migration(0, 1) { @Override public void migrate(@NonNull final Context context) { @@ -169,16 +173,63 @@ protected void migrate(@NonNull final Context context) { && kioskTab.getKioskServiceId() == SoundCloud.getServiceId() && kioskTab.getKioskId().equals("Top 50"))) .collect(Collectors.toUnmodifiableList()); - if (tabs.size() != cleanedTabs.size()) { + if (tabs.size() != cleanedTabs.size() || DEBUG) { // TODO: remove debug condition 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 tabs = tabsManager.getTabs(); + final boolean hadYtTrendingTab = tabs.stream() + .anyMatch(tab -> !(tab instanceof Tab.KioskTab kioskTab + && kioskTab.getKioskServiceId() == YouTube.getServiceId() + && kioskTab.getKioskId().equals("Trending"))); + if (hadYtTrendingTab) { + final List cleanedTabs = new ArrayList<>(); + for (final Tab tab : tabs) { + if (tab instanceof Tab.KioskTab kioskTab + && kioskTab.getKioskServiceId() == YouTube.getServiceId() + && kioskTab.getKioskId().equals("Trending")) { + // replace the YouTube Trending tab with the new live kiosk tab + // TODO: use the correct kiosk ID for the live kiosk tab + cleanedTabs.add(new Tab.KioskTab(YouTube.getServiceId(), "Live")); + } else { + cleanedTabs.add(tab); + } + } + tabsManager.saveTabs(cleanedTabs); + } + + final boolean hasDefaultTrendingTab = tabs.stream() + .anyMatch(tab -> tab instanceof Tab.DefaultKioskTab); + + // TODO: remove debugging code + if (hadYtTrendingTab || hasDefaultTrendingTab || newVersion == VERSION) { + // 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,26 +247,28 @@ protected void migrate(@NonNull final Context context) { 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); - final int lastPrefVersion = sp.getInt(lastPrefVersionKey, 0); + //final int lastPrefVersion = sp.getInt(lastPrefVersionKey, 0); + final int lastPrefVersion = 6; // TODO: remove this line after testing // no migration to run, already up to date if (App.getApp().isFirstRun()) { sp.edit().putInt(lastPrefVersionKey, VERSION).apply(); return; - } else if (lastPrefVersion == VERSION) { + } else if (lastPrefVersion == VERSION && !DEBUG) { // TODO: remove DEBUG check return; } @@ -249,21 +302,6 @@ public static void runMigrationsIfNeeded(@NonNull final Context context) { 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 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 { @@ -282,7 +320,7 @@ protected Migration(final int oldVersion, final int newVersion) { * the current settings version. */ private boolean shouldMigrate(final int currentVersion) { - return oldVersion >= currentVersion; + return oldVersion >= currentVersion || newVersion == VERSION; } protected abstract void migrate(@NonNull Context context); diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 6ab2fc7a541..cfc51f4e96e 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -866,4 +866,6 @@ The settings in the export being imported use a vulnerable format that was deprecated since NewPipe 0.27.0. Make sure the export being imported is from a trusted source, and prefer using only exports obtained from NewPipe 0.27.0 or newer in the future. Support for importing settings in this vulnerable format will soon be removed completely, and then old versions of NewPipe will not be able to import settings of exports from new versions anymore. SoundCloud Top 50 page removed SoundCloud has discontinued the original Top 50 charts. The corresponding tab has been removed from your main page. + YouTube combined trending removed + YouTube has discontinued the combined trending page as of 21st July 2025. NewPipe replaced the default trending page with the trending livestreams.\n\nYou can also select different ones in the content settings. From 7cecd11f721d49c8da357a63ef193dc19a42b3b0 Mon Sep 17 00:00:00 2001 From: Stypox Date: Mon, 28 Jul 2025 19:24:18 +0200 Subject: [PATCH 2/7] [YouTube] Add icons and strings for new trending pages --- .../org/schabi/newpipe/util/KioskTranslator.java | 16 ++++++++++++++++ app/src/main/res/drawable/ic_podcasts.xml | 5 +++++ app/src/main/res/values/strings.xml | 4 ++++ 3 files changed, 25 insertions(+) create mode 100644 app/src/main/res/drawable/ic_podcasts.xml diff --git a/app/src/main/java/org/schabi/newpipe/util/KioskTranslator.java b/app/src/main/java/org/schabi/newpipe/util/KioskTranslator.java index b8c2ff23699..69cf1763990 100644 --- a/app/src/main/java/org/schabi/newpipe/util/KioskTranslator.java +++ b/app/src/main/java/org/schabi/newpipe/util/KioskTranslator.java @@ -52,6 +52,14 @@ public static String getTranslatedKioskName(final String kioskId, final Context return c.getString(R.string.featured); case "Radio": return c.getString(R.string.radio); + case "trending_gaming": + return c.getString(R.string.gaming); + case "trending_music": + return c.getString(R.string.music); + case "trending_movies_and_shows": + return c.getString(R.string.movies); + case "trending_podcasts_episodes": + return c.getString(R.string.podcasts); default: return kioskId; } @@ -77,6 +85,14 @@ public static int getKioskIcon(final String kioskId) { 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; } diff --git a/app/src/main/res/drawable/ic_podcasts.xml b/app/src/main/res/drawable/ic_podcasts.xml new file mode 100644 index 00000000000..c297e8fd369 --- /dev/null +++ b/app/src/main/res/drawable/ic_podcasts.xml @@ -0,0 +1,5 @@ + + + + + diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index cfc51f4e96e..a8c8694ca90 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -868,4 +868,8 @@ SoundCloud has discontinued the original Top 50 charts. The corresponding tab has been removed from your main page. YouTube combined trending removed YouTube has discontinued the combined trending page as of 21st July 2025. NewPipe replaced the default trending page with the trending livestreams.\n\nYou can also select different ones in the content settings. + Gaming + Music + Movies + Podcasts From 8400a9ae8ec7a4361b9398f7e20177531d751119 Mon Sep 17 00:00:00 2001 From: Stypox Date: Mon, 28 Jul 2025 21:47:26 +0200 Subject: [PATCH 3/7] Remove DEBUG statements and don't replace yt trending with live You can use this command to test instead: adb shell run-as org.schabi.newpipe.debug.pr12450 'sed -i '"'"'s###'"'"' shared_prefs/org.schabi.newpipe.debug.pr12450_preferences.xml' && adb shell run-as org.schabi.newpipe.debug.pr12450 'sed -i '"'"'s#\]}#,{\"tab_id\":5,\"service_id\":0,\"kiosk_id\":\"Trending\"},{\"tab_id\":5,\"service_id\":1,\"kiosk_id\":\"Top 50\"}]}#'"'"' shared_prefs/org.schabi.newpipe.debug.pr12450_preferences.xml' --- .../settings/migration/SettingMigrations.java | 34 ++++++------------- app/src/main/res/values/strings.xml | 2 +- 2 files changed, 11 insertions(+), 25 deletions(-) diff --git a/app/src/main/java/org/schabi/newpipe/settings/migration/SettingMigrations.java b/app/src/main/java/org/schabi/newpipe/settings/migration/SettingMigrations.java index 99af2776612..67944075dc2 100644 --- a/app/src/main/java/org/schabi/newpipe/settings/migration/SettingMigrations.java +++ b/app/src/main/java/org/schabi/newpipe/settings/migration/SettingMigrations.java @@ -21,7 +21,6 @@ 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; @@ -173,7 +172,7 @@ protected void migrate(@NonNull final Context context) { && kioskTab.getKioskServiceId() == SoundCloud.getServiceId() && kioskTab.getKioskId().equals("Top 50"))) .collect(Collectors.toUnmodifiableList()); - if (tabs.size() != cleanedTabs.size() || DEBUG) { // TODO: remove debug condition + if (tabs.size() != cleanedTabs.size()) { tabsManager.saveTabs(cleanedTabs); // create an AlertDialog to inform the user about the change MigrationManager.addMigrationInfo(uiContext -> @@ -198,31 +197,19 @@ protected void migrate(@NonNull final Context context) { // and is thus updated automatically. final TabsManager tabsManager = TabsManager.getManager(context); final List tabs = tabsManager.getTabs(); - final boolean hadYtTrendingTab = tabs.stream() - .anyMatch(tab -> !(tab instanceof Tab.KioskTab kioskTab - && kioskTab.getKioskServiceId() == YouTube.getServiceId() - && kioskTab.getKioskId().equals("Trending"))); - if (hadYtTrendingTab) { - final List cleanedTabs = new ArrayList<>(); - for (final Tab tab : tabs) { - if (tab instanceof Tab.KioskTab kioskTab + final List cleanedTabs = tabs.stream() + .filter(tab -> !(tab instanceof Tab.KioskTab kioskTab && kioskTab.getKioskServiceId() == YouTube.getServiceId() - && kioskTab.getKioskId().equals("Trending")) { - // replace the YouTube Trending tab with the new live kiosk tab - // TODO: use the correct kiosk ID for the live kiosk tab - cleanedTabs.add(new Tab.KioskTab(YouTube.getServiceId(), "Live")); - } else { - cleanedTabs.add(tab); - } - } + && 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); - // TODO: remove debugging code - if (hadYtTrendingTab || hasDefaultTrendingTab || newVersion == VERSION) { + if (tabs.size() != cleanedTabs.size() || hasDefaultTrendingTab) { // User is informed about the change MigrationManager.addMigrationInfo(uiContext -> MigrationManager.createMigrationInfoDialog( @@ -261,14 +248,13 @@ 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); - //final int lastPrefVersion = sp.getInt(lastPrefVersionKey, 0); - final int lastPrefVersion = 6; // TODO: remove this line after testing + final int lastPrefVersion = sp.getInt(lastPrefVersionKey, 0); // no migration to run, already up to date if (App.getApp().isFirstRun()) { sp.edit().putInt(lastPrefVersionKey, VERSION).apply(); return; - } else if (lastPrefVersion == VERSION && !DEBUG) { // TODO: remove DEBUG check + } else if (lastPrefVersion == VERSION) { return; } @@ -320,7 +306,7 @@ protected Migration(final int oldVersion, final int newVersion) { * the current settings version. */ private boolean shouldMigrate(final int currentVersion) { - return oldVersion >= currentVersion || newVersion == VERSION; + return oldVersion >= currentVersion; } protected abstract void migrate(@NonNull Context context); diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index a8c8694ca90..c78845472e5 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -867,7 +867,7 @@ SoundCloud Top 50 page removed SoundCloud has discontinued the original Top 50 charts. The corresponding tab has been removed from your main page. YouTube combined trending removed - YouTube has discontinued the combined trending page as of 21st July 2025. NewPipe replaced the default trending page with the trending livestreams.\n\nYou can also select different ones in the content settings. + YouTube has discontinued the combined trending page as of 21st July 2025. NewPipe replaced the default trending page with the trending livestreams.\n\nYou can also select different trending pages in \"Settings > Content > Content of main page\". Gaming Music Movies From d96c0aebb1c2a893fb28e6cf40aa9af772ecb002 Mon Sep 17 00:00:00 2001 From: Stypox Date: Thu, 31 Jul 2025 22:48:13 +0200 Subject: [PATCH 4/7] Show tabs above kiosks in drawer --- .../java/org/schabi/newpipe/MainActivity.java | 60 ++++++++++--------- app/src/main/res/menu/drawer_items.xml | 1 + 2 files changed, 34 insertions(+), 27 deletions(-) diff --git a/app/src/main/java/org/schabi/newpipe/MainActivity.java b/app/src/main/java/org/schabi/newpipe/MainActivity.java index 1aae7fa8655..4fbd562b44c 100644 --- a/app/src/main/java/org/schabi/newpipe/MainActivity.java +++ b/app/src/main/java/org/schabi/newpipe/MainActivity.java @@ -263,19 +263,6 @@ public void onDrawerClosed(final View drawerView) { */ 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) @@ -293,6 +280,20 @@ private void addDrawerMenuForCurrentService() throws ExtractionException { .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) @@ -312,10 +313,13 @@ private boolean drawerItemSelected(final MenuItem item) { 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: @@ -339,7 +343,7 @@ private void changeService(final MenuItem item) { .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()); @@ -356,18 +360,19 @@ private void tabSelected(final MenuItem item) throws ExtractionException { 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++; } } @@ -408,6 +413,7 @@ private void toggleServices() { 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 diff --git a/app/src/main/res/menu/drawer_items.xml b/app/src/main/res/menu/drawer_items.xml index 24c321b8af4..8214f3f0275 100644 --- a/app/src/main/res/menu/drawer_items.xml +++ b/app/src/main/res/menu/drawer_items.xml @@ -2,5 +2,6 @@ + From b7b836e941a87a44a149775dc33c23a4f001055c Mon Sep 17 00:00:00 2001 From: Stypox Date: Thu, 31 Jul 2025 23:10:47 +0200 Subject: [PATCH 5/7] Update the names of YT kiosks --- .../java/org/schabi/newpipe/util/KioskTranslator.java | 8 ++++---- .../main/java/org/schabi/newpipe/util/Localization.java | 3 ++- app/src/main/res/values/strings.xml | 8 ++++---- 3 files changed, 10 insertions(+), 9 deletions(-) diff --git a/app/src/main/java/org/schabi/newpipe/util/KioskTranslator.java b/app/src/main/java/org/schabi/newpipe/util/KioskTranslator.java index 69cf1763990..5aa3321592e 100644 --- a/app/src/main/java/org/schabi/newpipe/util/KioskTranslator.java +++ b/app/src/main/java/org/schabi/newpipe/util/KioskTranslator.java @@ -53,13 +53,13 @@ public static String getTranslatedKioskName(final String kioskId, final Context case "Radio": return c.getString(R.string.radio); case "trending_gaming": - return c.getString(R.string.gaming); + return c.getString(R.string.trending_gaming); case "trending_music": - return c.getString(R.string.music); + return c.getString(R.string.trending_music); case "trending_movies_and_shows": - return c.getString(R.string.movies); + return c.getString(R.string.trending_movies); case "trending_podcasts_episodes": - return c.getString(R.string.podcasts); + return c.getString(R.string.trending_podcasts); default: return kioskId; } diff --git a/app/src/main/java/org/schabi/newpipe/util/Localization.java b/app/src/main/java/org/schabi/newpipe/util/Localization.java index bd5463088c8..1073afffd97 100644 --- a/app/src/main/java/org/schabi/newpipe/util/Localization.java +++ b/app/src/main/java/org/schabi/newpipe/util/Localization.java @@ -388,9 +388,10 @@ public static String relativeTime(@NonNull final OffsetDateTime offsetDateTime) * {@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 diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index c78845472e5..57f78c221ab 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -868,8 +868,8 @@ SoundCloud has discontinued the original Top 50 charts. The corresponding tab has been removed from your main page. YouTube combined trending removed YouTube has discontinued the combined trending page as of 21st July 2025. NewPipe replaced the default trending page with the trending livestreams.\n\nYou can also select different trending pages in \"Settings > Content > Content of main page\". - Gaming - Music - Movies - Podcasts + Gaming trends + Trending podcasts + Trending movies and shows + Trending music From b846746119fb037b39425775acbea53d92472673 Mon Sep 17 00:00:00 2001 From: Stypox Date: Thu, 31 Jul 2025 23:32:04 +0200 Subject: [PATCH 6/7] Update NewPipeExtractor to v0.24.8 --- app/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/build.gradle b/app/build.gradle index 54bd86a72c9..d6c93c1f77a 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -214,7 +214,7 @@ dependencies { // the corresponding commit hash, since JitPack sometimes deletes artifacts. // If there’s already a git hash, just add more of it to the end (or remove a letter) // to cause jitpack to regenerate the artifact. - implementation 'com.github.TeamNewPipe:NewPipeExtractor:7adbc48a0aa872c016b8ec089e278d5e12772054' + implementation 'com.github.TeamNewPipe:NewPipeExtractor:v0.24.8' implementation 'com.github.TeamNewPipe:NoNonsense-FilePicker:5.0.0' /** Checkstyle **/ From 5aefa4aff258487df72343ea5edcfbe43e1b3f2e Mon Sep 17 00:00:00 2001 From: Hosted Weblate Date: Thu, 31 Jul 2025 23:42:34 +0200 Subject: [PATCH 7/7] Translated using Weblate (Tigrinya) Currently translated at 12.7% (95 of 748 strings) Co-authored-by: fool --- app/src/main/res/values-ti/strings.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/src/main/res/values-ti/strings.xml b/app/src/main/res/values-ti/strings.xml index e1f61b7d15d..f25b86cc1b8 100644 --- a/app/src/main/res/values-ti/strings.xml +++ b/app/src/main/res/values-ti/strings.xml @@ -5,7 +5,7 @@ ውጽኢት ናይ፦ %s ንኽትጅምር ነቲ ምድላይ ምልክት ጠውቆ። ዝተሓትመሉ ዕለት %1$s - ናይ ዥረት ተጻዋታይ ኣይተረኽበን። VLC ኣውርድ፧ + ናይ ዥረት ተጻዋታይ ኣይተረኽበን። VLC ይውርድ፧ ሐራይ ቅጥዕታት \"%1$s\" ማለቱ ድዩ፧