Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
21 commits
Select commit Hold shift + click to select a range
b888dc7
Support per-app language preferences
mileskrell Mar 12, 2025
87693a2
Redirect to per-app language settings on Android 13+
mileskrell Mar 16, 2025
3532ac9
Migrate from pre-Android 13 app language pref
mileskrell Mar 16, 2025
da106e2
Don't try to migrate "system" app language
mileskrell Mar 16, 2025
980a35a
Move migration to separate method
mileskrell Mar 16, 2025
70416e7
Move app language setting migration to SettingMigrations
mileskrell Mar 16, 2025
35abb99
Only show toast on Android <13
mileskrell Mar 17, 2025
c7bf498
Don't show toast because of changing content language or country
mileskrell Mar 17, 2025
6d6b73e
textview for download date added
malania02 Mar 22, 2025
536b78f
textview for download date added
malania02 Mar 22, 2025
63be322
Show download date
malania02 Mar 22, 2025
7f10312
Move migration to NewPipeSettings
mileskrell Mar 23, 2025
205466c
Move call to setApplicationLocales
mileskrell Mar 27, 2025
912f07a
Missing lines added
malania02 Mar 30, 2025
e1dedd4
[YouTube] Access first element if array size is one
FineFindus Apr 2, 2025
5840d3a
Merge pull request #12150 from FineFindus/fix/potoken-index
Stypox Apr 8, 2025
756327d
Merge pull request #12093 from mileskrell/mileskrell/support-per-app-…
Stypox Apr 8, 2025
f39eda0
Fix for overlapping
malania02 Apr 9, 2025
276bf39
Merge pull request #12117 from malania02/dev
Stypox Apr 11, 2025
7615f79
Merge branch 'dev' into Merge-dev-to-refactor
Isira-Seneviratne Apr 14, 2025
c9542ad
Update extractor
Isira-Seneviratne Apr 27, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions app/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -101,6 +101,10 @@ android {
androidTest.assets.srcDirs += files("$projectDir/schemas".toString())
}

androidResources {
generateLocaleConfig = true
}

buildFeatures {
viewBinding true
compose true
Expand Down
2 changes: 2 additions & 0 deletions app/src/main/java/org/schabi/newpipe/MainActivity.java
Original file line number Diff line number Diff line change
Expand Up @@ -186,6 +186,8 @@ protected void onCreate(final Bundle savedInstanceState) {
&& ReleaseVersionUtil.INSTANCE.isReleaseApk()) {
UpdateSettingsFragment.askForConsentToUpdateChecks(this);
}

Localization.migrateAppLanguageSettingIfNecessary(getApplicationContext());
}

@Override
Expand Down
Original file line number Diff line number Diff line change
@@ -1,10 +1,15 @@
package org.schabi.newpipe.settings;

import android.content.Context;
import android.content.Intent;
import android.net.Uri;
import android.os.Build;
import android.os.Bundle;
import android.provider.Settings;
import android.util.Log;
import android.widget.Toast;

import androidx.appcompat.app.AppCompatDelegate;
import androidx.preference.Preference;

import org.schabi.newpipe.DownloaderImpl;
Expand All @@ -15,13 +20,13 @@
import org.schabi.newpipe.util.image.ImageStrategy;
import org.schabi.newpipe.util.image.PreferredImageQuality;

import java.util.Locale;

import coil3.SingletonImageLoader;

public class ContentSettingsFragment extends BasePreferenceFragment {
private String youtubeRestrictedModeEnabledKey;

private Localization initialSelectedLocalization;
private ContentCountry initialSelectedContentCountry;
private String initialLanguage;

@Override
Expand All @@ -30,12 +35,28 @@ public void onCreatePreferences(final Bundle savedInstanceState, final String ro

addPreferencesFromResourceRegistry();

initialSelectedLocalization = org.schabi.newpipe.util.Localization
.getPreferredLocalization(requireContext());
initialSelectedContentCountry = org.schabi.newpipe.util.Localization
.getPreferredContentCountry(requireContext());
initialLanguage = defaultPreferences.getString(getString(R.string.app_language_key), "en");

if (Build.VERSION.SDK_INT >= 33) {
requirePreference(R.string.app_language_key).setVisible(false);
final Preference newAppLanguagePref =
requirePreference(R.string.app_language_android_13_and_up_key);
newAppLanguagePref.setSummaryProvider(preference -> {
final Locale customLocale = AppCompatDelegate.getApplicationLocales().get(0);
if (customLocale != null) {
return customLocale.getDisplayName();
}
return getString(R.string.systems_language);
});
newAppLanguagePref.setOnPreferenceClickListener(preference -> {
final Intent intent = new Intent(Settings.ACTION_APP_LOCALE_SETTINGS)
.setData(Uri.fromParts("package", requireContext().getPackageName(), null));
startActivity(intent);
return true;
});
newAppLanguagePref.setVisible(true);
}

final Preference imageQualityPreference = requirePreference(R.string.image_quality_key);
imageQualityPreference.setOnPreferenceChangeListener(
(preference, newValue) -> {
Expand Down Expand Up @@ -70,19 +91,21 @@ public boolean onPreferenceTreeClick(final Preference preference) {
public void onDestroy() {
super.onDestroy();

final Localization selectedLocalization = org.schabi.newpipe.util.Localization
.getPreferredLocalization(requireContext());
final ContentCountry selectedContentCountry = org.schabi.newpipe.util.Localization
.getPreferredContentCountry(requireContext());
final String selectedLanguage =
defaultPreferences.getString(getString(R.string.app_language_key), "en");

if (!selectedLocalization.equals(initialSelectedLocalization)
|| !selectedContentCountry.equals(initialSelectedContentCountry)
|| !selectedLanguage.equals(initialLanguage)) {
Toast.makeText(requireContext(), R.string.localization_changes_requires_app_restart,
Toast.LENGTH_LONG).show();

if (!selectedLanguage.equals(initialLanguage)) {
if (Build.VERSION.SDK_INT < 33) {
Toast.makeText(
requireContext(),
R.string.localization_changes_requires_app_restart,
Toast.LENGTH_LONG
).show();
}
final Localization selectedLocalization = org.schabi.newpipe.util.Localization
.getPreferredLocalization(requireContext());
final ContentCountry selectedContentCountry = org.schabi.newpipe.util.Localization
.getPreferredContentCountry(requireContext());
NewPipe.setupLocalization(selectedLocalization, selectedContentCountry);
}
}
Expand Down
37 changes: 37 additions & 0 deletions app/src/main/java/org/schabi/newpipe/util/Localization.java
Original file line number Diff line number Diff line change
Expand Up @@ -12,12 +12,15 @@
import android.text.TextUtils;
import android.text.format.DateUtils;
import android.util.DisplayMetrics;
import android.util.Log;

import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.annotation.PluralsRes;
import androidx.annotation.StringRes;
import androidx.appcompat.app.AppCompatDelegate;
import androidx.core.math.MathUtils;
import androidx.core.os.LocaleListCompat;
import androidx.preference.PreferenceManager;

import org.ocpsoft.prettytime.PrettyTime;
Expand All @@ -39,6 +42,7 @@
import java.util.Arrays;
import java.util.List;
import java.util.Locale;
import java.util.Objects;
import java.util.stream.Collectors;


Expand All @@ -63,6 +67,7 @@
*/

public final class Localization {
private static final String TAG = Localization.class.toString();
public static final String DOT_SEPARATOR = " • ";
private static PrettyTime prettyTime;

Expand Down Expand Up @@ -101,6 +106,10 @@ public static Locale getPreferredLocale(@NonNull final Context context) {
}

public static Locale getAppLocale(@NonNull final Context context) {
if (Build.VERSION.SDK_INT >= 33) {
final Locale customLocale = AppCompatDelegate.getApplicationLocales().get(0);
return Objects.requireNonNullElseGet(customLocale, Locale::getDefault);
}
return getLocaleFromPrefs(context, R.string.app_language_key);
}

Expand Down Expand Up @@ -422,4 +431,32 @@ private static String getQuantity(@NonNull final Context context,
final int safeCount = (int) MathUtils.clamp(count, Integer.MIN_VALUE, Integer.MAX_VALUE);
return context.getResources().getQuantityString(pluralId, safeCount, formattedCount);
}

public static void migrateAppLanguageSettingIfNecessary(@NonNull final Context context) {
// Starting with pull request #12093, NewPipe on Android 13+ exclusively uses Android's
// public per-app language APIs to read and set the UI language for NewPipe.
// If running on Android 13+, the following code will migrate any existing custom
// app language in SharedPreferences to use the public per-app language APIs instead.
if (Build.VERSION.SDK_INT >= 33) {
final SharedPreferences sp = PreferenceManager.getDefaultSharedPreferences(context);
final String appLanguageKey = context.getString(R.string.app_language_key);
final String appLanguageValue = sp.getString(appLanguageKey, null);
if (appLanguageValue != null) {
sp.edit().remove(appLanguageKey).apply();
final String appLanguageDefaultValue =
context.getString(R.string.default_localization_key);
if (!appLanguageValue.equals(appLanguageDefaultValue)) {
try {
AppCompatDelegate.setApplicationLocales(
LocaleListCompat.forLanguageTags(appLanguageValue)
);
} catch (final RuntimeException e) {
Log.e(TAG, "Failed to migrate previous custom app language "
+ "setting to public per-app language APIs"
);
}
}
}
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ fun parseChallengeData(rawChallengeData: String): String {
val descrambled = descramble(scrambled.getString(1))
JsonParser.array().from(descrambled)
} else {
scrambled.getArray(1)
scrambled.getArray(0)
}

val messageId = challengeData.getString(0)
Expand Down
11 changes: 11 additions & 0 deletions app/src/main/java/us/shandian/giga/ui/adapter/MissionAdapter.java
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,9 @@
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Iterator;
import java.util.Date;
import java.util.Locale;
import java.text.DateFormat;

import io.reactivex.rxjava3.android.schedulers.AndroidSchedulers;
import io.reactivex.rxjava3.core.Observable;
Expand Down Expand Up @@ -208,11 +211,17 @@ public void onBindViewHolder(@NonNull ViewHolder view, @SuppressLint("RecyclerVi
h.pause.setTitle(mission.unknownLength ? R.string.stop : R.string.pause);
updateProgress(h);
mPendingDownloadsItems.add(h);

h.date.setText("");
} else {
h.progress.setMarquee(false);
h.status.setText("100%");
h.progress.setProgress(1.0f);
h.size.setText(Utility.formatBytes(item.mission.length));

DateFormat dateFormat = DateFormat.getDateInstance(DateFormat.MEDIUM, Locale.getDefault());
Date date = new Date(item.mission.timestamp);
h.date.setText(dateFormat.format(date));
}
}

Expand Down Expand Up @@ -832,6 +841,7 @@ class ViewHolderItem extends RecyclerView.ViewHolder {
ImageView icon;
TextView name;
TextView size;
TextView date;
ProgressDrawable progress;

PopupMenu popupMenu;
Expand Down Expand Up @@ -862,6 +872,7 @@ class ViewHolderItem extends RecyclerView.ViewHolder {
name = itemView.findViewById(R.id.item_name);
icon = itemView.findViewById(R.id.item_icon);
size = itemView.findViewById(R.id.item_size);
date = itemView.findViewById(R.id.item_date);

name.setSelected(true);

Expand Down
12 changes: 12 additions & 0 deletions app/src/main/res/layout/mission_item.xml
Original file line number Diff line number Diff line change
Expand Up @@ -82,6 +82,18 @@
android:textColor="@color/white"
android:textSize="12sp" />

<org.schabi.newpipe.views.NewPipeTextView
android:id="@+id/item_date"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_below="@id/item_name"
android:layout_alignParentRight="true"
android:padding="6dp"
android:singleLine="true"
android:text=""
android:textColor="@color/white"
android:textSize="12sp" />

</RelativeLayout>

</RelativeLayout>
12 changes: 12 additions & 0 deletions app/src/main/res/layout/mission_item_linear.xml
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,18 @@
android:textSize="12sp"
android:textStyle="bold" />

<org.schabi.newpipe.views.NewPipeTextView
android:id="@+id/item_date"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_below="@id/item_name"
android:layout_toLeftOf="@id/item_more"
android:padding="6dp"
android:singleLine="true"
android:text=""
android:textColor="@color/white"
android:textSize="12sp" />

<ImageView
android:id="@+id/item_more"
style="?attr/buttonBarButtonStyle"
Expand Down
1 change: 1 addition & 0 deletions app/src/main/res/resources.properties
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
unqualifiedResLocale=en-US
1 change: 1 addition & 0 deletions app/src/main/res/values/settings_keys.xml
Original file line number Diff line number Diff line change
Expand Up @@ -353,6 +353,7 @@
<string name="playback_skip_silence_key">playback_skip_silence_key</string>

<string name="app_language_key">app_language_key</string>
<string name="app_language_android_13_and_up_key">app_language_android_13_and_up_key</string>

<string name="feed_update_threshold_key">feed_update_threshold_key</string>
<string name="feed_update_threshold_default_value">300</string>
Expand Down
7 changes: 7 additions & 0 deletions app/src/main/res/xml/content_settings.xml
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,13 @@
app:iconSpaceReserved="false"
app:useSimpleSummaryProvider="true" />

<Preference
android:key="@string/app_language_android_13_and_up_key"
android:title="@string/app_language_title"
app:isPreferenceVisible="false"
app:singleLineTitle="false"
app:iconSpaceReserved="false" />

<ListPreference
android:defaultValue="@string/default_localization_key"
android:entries="@array/language_names"
Expand Down
2 changes: 1 addition & 1 deletion gradle/libs.versions.toml
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,7 @@ swiperefreshlayout = "1.1.0"
# This works thanks to JitPack: https://jitpack.io/
teamnewpipe-filepicker = "5.0.0"
teamnewpipe-nanojson = "1d9e1aea9049fc9f85e68b43ba39fe7be1c1f751"
teamnewpipe-newpipe-extractor = "0b99100db"
teamnewpipe-newpipe-extractor = "67f3301d9"
webkit = "1.9.0"
work = "2.8.1"

Expand Down