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 21f4f97a1..1aae7fa86 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.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; @@ -195,7 +195,7 @@ public class MainActivity extends AppCompatActivity { 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 421440ea7..0a5512c69 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 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); 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 000000000..d5b0e783d --- /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 d13e73090..99af27766 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.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:
- * - 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 @@ public final class SettingMigrations { && 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 @@ 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); - 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 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 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 @@ public final class SettingMigrations { * 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 6ab2fc7a5..cfc51f4e9 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 b8c2ff236..69cf17639 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 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.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 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; } 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 000000000..c297e8fd3 --- /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 cfc51f4e9..a8c8694ca 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 99af27766..67944075d 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.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; @@ -173,7 +172,7 @@ public final class SettingMigrations { && 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 @@ public final class SettingMigrations { // 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 + final List cleanedTabs = tabs.stream() + .filter(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); - } - } + && 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 @@ public final class SettingMigrations { // 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 @@ public final class SettingMigrations { * 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 a8c8694ca..c78845472 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 1aae7fa86..4fbd562b4 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 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) @@ -293,6 +280,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) @@ -312,10 +313,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: @@ -339,7 +343,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()); @@ -356,18 +360,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++; } } @@ -408,6 +413,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 diff --git a/app/src/main/res/menu/drawer_items.xml b/app/src/main/res/menu/drawer_items.xml index 24c321b8a..8214f3f02 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 69cf17639..5aa332159 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 final class KioskTranslator { 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 bd5463088..1073afffd 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 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 diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index c78845472..57f78c221 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 54bd86a72..d6c93c1f7 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 e1f61b7d1..f25b86cc1 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\" ማለቱ ድዩ፧