mirror of
https://github.com/revanced/revanced-patches
synced 2024-12-27 09:45:51 +01:00
feat(TikTok): Add ReVanced settings about screen (#4009)
This commit is contained in:
parent
c65f642074
commit
12ea26b10d
@ -1,6 +1,5 @@
|
|||||||
package app.revanced.extension.shared.settings.preference;
|
package app.revanced.extension.shared.settings.preference;
|
||||||
|
|
||||||
import static app.revanced.extension.shared.StringRef.sf;
|
|
||||||
import static app.revanced.extension.shared.StringRef.str;
|
import static app.revanced.extension.shared.StringRef.str;
|
||||||
import static app.revanced.extension.youtube.requests.Route.Method.GET;
|
import static app.revanced.extension.youtube.requests.Route.Method.GET;
|
||||||
|
|
||||||
@ -13,6 +12,8 @@ import android.content.res.Configuration;
|
|||||||
import android.graphics.Color;
|
import android.graphics.Color;
|
||||||
import android.net.Uri;
|
import android.net.Uri;
|
||||||
import android.os.Bundle;
|
import android.os.Bundle;
|
||||||
|
import android.os.Handler;
|
||||||
|
import android.os.Looper;
|
||||||
import android.preference.Preference;
|
import android.preference.Preference;
|
||||||
import android.util.AttributeSet;
|
import android.util.AttributeSet;
|
||||||
import android.view.Window;
|
import android.view.Window;
|
||||||
@ -37,7 +38,7 @@ import app.revanced.extension.youtube.requests.Requester;
|
|||||||
import app.revanced.extension.youtube.requests.Route;
|
import app.revanced.extension.youtube.requests.Route;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Opens a dialog showing the links from {@link SocialLinksRoutes}.
|
* Opens a dialog showing official links.
|
||||||
*/
|
*/
|
||||||
@SuppressWarnings({"unused", "deprecation"})
|
@SuppressWarnings({"unused", "deprecation"})
|
||||||
public class ReVancedAboutPreference extends Preference {
|
public class ReVancedAboutPreference extends Preference {
|
||||||
@ -72,7 +73,16 @@ public class ReVancedAboutPreference extends Preference {
|
|||||||
return Color.BLACK;
|
return Color.BLACK;
|
||||||
}
|
}
|
||||||
|
|
||||||
private String createDialogHtml(WebLink[] socialLinks) {
|
/**
|
||||||
|
* Apps that do not support bundling resources must override this.
|
||||||
|
*
|
||||||
|
* @return A localized string to display for the key.
|
||||||
|
*/
|
||||||
|
protected String getString(String key, Object ... args) {
|
||||||
|
return str(key, args);
|
||||||
|
}
|
||||||
|
|
||||||
|
private String createDialogHtml(WebLink[] aboutLinks) {
|
||||||
final boolean isNetworkConnected = Utils.isNetworkConnected();
|
final boolean isNetworkConnected = Utils.isNetworkConnected();
|
||||||
|
|
||||||
StringBuilder builder = new StringBuilder();
|
StringBuilder builder = new StringBuilder();
|
||||||
@ -91,7 +101,7 @@ public class ReVancedAboutPreference extends Preference {
|
|||||||
builder.append("<img style=\"width: 100px; height: 100px;\" "
|
builder.append("<img style=\"width: 100px; height: 100px;\" "
|
||||||
// Hide the image if it does not load.
|
// Hide the image if it does not load.
|
||||||
+ "onerror=\"this.style.display='none';\" "
|
+ "onerror=\"this.style.display='none';\" "
|
||||||
+ "src=\"https://revanced.app/favicon.ico\" />");
|
+ "src=\"").append(AboutLinksRoutes.aboutLogoUrl).append("\" />");
|
||||||
}
|
}
|
||||||
|
|
||||||
String patchesVersion = Utils.getPatchesReleaseVersion();
|
String patchesVersion = Utils.getPatchesReleaseVersion();
|
||||||
@ -103,29 +113,29 @@ public class ReVancedAboutPreference extends Preference {
|
|||||||
|
|
||||||
builder.append("<p>")
|
builder.append("<p>")
|
||||||
// Replace hyphens with non breaking dashes so the version number does not break lines.
|
// Replace hyphens with non breaking dashes so the version number does not break lines.
|
||||||
.append(useNonBreakingHyphens(str("revanced_settings_about_links_body", patchesVersion)))
|
.append(useNonBreakingHyphens(getString("revanced_settings_about_links_body", patchesVersion)))
|
||||||
.append("</p>");
|
.append("</p>");
|
||||||
|
|
||||||
// Add a disclaimer if using a dev release.
|
// Add a disclaimer if using a dev release.
|
||||||
if (patchesVersion.contains("dev")) {
|
if (patchesVersion.contains("dev")) {
|
||||||
builder.append("<h3>")
|
builder.append("<h3>")
|
||||||
// English text 'Pre-release' can break lines.
|
// English text 'Pre-release' can break lines.
|
||||||
.append(useNonBreakingHyphens(str("revanced_settings_about_links_dev_header")))
|
.append(useNonBreakingHyphens(getString("revanced_settings_about_links_dev_header")))
|
||||||
.append("</h3>");
|
.append("</h3>");
|
||||||
|
|
||||||
builder.append("<p>")
|
builder.append("<p>")
|
||||||
.append(str("revanced_settings_about_links_dev_body"))
|
.append(getString("revanced_settings_about_links_dev_body"))
|
||||||
.append("</p>");
|
.append("</p>");
|
||||||
}
|
}
|
||||||
|
|
||||||
builder.append("<h2 style=\"margin-top: 30px;\">")
|
builder.append("<h2 style=\"margin-top: 30px;\">")
|
||||||
.append(str("revanced_settings_about_links_header"))
|
.append(getString("revanced_settings_about_links_header"))
|
||||||
.append("</h2>");
|
.append("</h2>");
|
||||||
|
|
||||||
builder.append("<div>");
|
builder.append("<div>");
|
||||||
for (WebLink social : socialLinks) {
|
for (WebLink link : aboutLinks) {
|
||||||
builder.append("<div style=\"margin-bottom: 20px;\">");
|
builder.append("<div style=\"margin-bottom: 20px;\">");
|
||||||
builder.append(String.format("<a href=\"%s\">%s</a>", social.url, social.name));
|
builder.append(String.format("<a href=\"%s\">%s</a>", link.url, link.name));
|
||||||
builder.append("</div>");
|
builder.append("</div>");
|
||||||
}
|
}
|
||||||
builder.append("</div>");
|
builder.append("</div>");
|
||||||
@ -137,25 +147,44 @@ public class ReVancedAboutPreference extends Preference {
|
|||||||
{
|
{
|
||||||
setOnPreferenceClickListener(pref -> {
|
setOnPreferenceClickListener(pref -> {
|
||||||
// Show a progress spinner if the social links are not fetched yet.
|
// Show a progress spinner if the social links are not fetched yet.
|
||||||
if (!SocialLinksRoutes.hasFetchedLinks() && Utils.isNetworkConnected()) {
|
if (!AboutLinksRoutes.hasFetchedLinks() && Utils.isNetworkConnected()) {
|
||||||
|
// Show a progress spinner, but only if the api fetch takes more than a half a second.
|
||||||
|
final long delayToShowProgressSpinner = 500;
|
||||||
ProgressDialog progress = new ProgressDialog(getContext());
|
ProgressDialog progress = new ProgressDialog(getContext());
|
||||||
progress.setProgressStyle(ProgressDialog.STYLE_SPINNER);
|
progress.setProgressStyle(ProgressDialog.STYLE_SPINNER);
|
||||||
progress.show();
|
|
||||||
Utils.runOnBackgroundThread(() -> fetchLinksAndShowDialog(progress));
|
Handler handler = new Handler(Looper.getMainLooper());
|
||||||
|
Runnable showDialogRunnable = progress::show;
|
||||||
|
handler.postDelayed(showDialogRunnable, delayToShowProgressSpinner);
|
||||||
|
|
||||||
|
Utils.runOnBackgroundThread(() ->
|
||||||
|
fetchLinksAndShowDialog(handler, showDialogRunnable, progress));
|
||||||
} else {
|
} else {
|
||||||
// No network call required and can run now.
|
// No network call required and can run now.
|
||||||
fetchLinksAndShowDialog(null);
|
fetchLinksAndShowDialog(null, null, null);
|
||||||
}
|
}
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
private void fetchLinksAndShowDialog(@Nullable ProgressDialog progress) {
|
private void fetchLinksAndShowDialog(@Nullable Handler handler,
|
||||||
WebLink[] socialLinks = SocialLinksRoutes.fetchSocialLinks();
|
Runnable showDialogRunnable,
|
||||||
String htmlDialog = createDialogHtml(socialLinks);
|
@Nullable ProgressDialog progress) {
|
||||||
|
WebLink[] links = AboutLinksRoutes.fetchAboutLinks();
|
||||||
|
String htmlDialog = createDialogHtml(links);
|
||||||
|
|
||||||
|
// Enable to randomly force a delay to debug the spinner logic.
|
||||||
|
final boolean debugSpinnerDelayLogic = false;
|
||||||
|
//noinspection ConstantConditions
|
||||||
|
if (debugSpinnerDelayLogic && handler != null && Math.random() < 0.5f) {
|
||||||
|
Utils.doNothingForDuration((long) (Math.random() * 4000));
|
||||||
|
}
|
||||||
|
|
||||||
Utils.runOnMainThreadNowOrLater(() -> {
|
Utils.runOnMainThreadNowOrLater(() -> {
|
||||||
|
if (handler != null) {
|
||||||
|
handler.removeCallbacks(showDialogRunnable);
|
||||||
|
}
|
||||||
if (progress != null) {
|
if (progress != null) {
|
||||||
progress.dismiss();
|
progress.dismiss();
|
||||||
}
|
}
|
||||||
@ -224,7 +253,7 @@ class WebViewDialog extends Dialog {
|
|||||||
|
|
||||||
class WebLink {
|
class WebLink {
|
||||||
final boolean preferred;
|
final boolean preferred;
|
||||||
final String name;
|
String name;
|
||||||
final String url;
|
final String url;
|
||||||
|
|
||||||
WebLink(JSONObject json) throws JSONException {
|
WebLink(JSONObject json) throws JSONException {
|
||||||
@ -243,7 +272,7 @@ class WebLink {
|
|||||||
@NonNull
|
@NonNull
|
||||||
@Override
|
@Override
|
||||||
public String toString() {
|
public String toString() {
|
||||||
return "ReVancedSocialLink{" +
|
return "WebLink{" +
|
||||||
"preferred=" + preferred +
|
"preferred=" + preferred +
|
||||||
", name='" + name + '\'' +
|
", name='" + name + '\'' +
|
||||||
", url='" + url + '\'' +
|
", url='" + url + '\'' +
|
||||||
@ -251,25 +280,21 @@ class WebLink {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
class SocialLinksRoutes {
|
class AboutLinksRoutes {
|
||||||
/**
|
/**
|
||||||
* Simple link to the website donate page,
|
* Backup icon url if the API call fails.
|
||||||
* rather than fetching and parsing the donation links using the API.
|
|
||||||
*/
|
*/
|
||||||
public static final WebLink DONATE_LINK = new WebLink(true,
|
public static volatile String aboutLogoUrl = "https://revanced.app/favicon.ico";
|
||||||
sf("revanced_settings_about_links_donate").toString(),
|
|
||||||
"https://revanced.app/donate");
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Links to use if fetch links api call fails.
|
* Links to use if fetch links api call fails.
|
||||||
*/
|
*/
|
||||||
private static final WebLink[] NO_CONNECTION_STATIC_LINKS = {
|
private static final WebLink[] NO_CONNECTION_STATIC_LINKS = {
|
||||||
new WebLink(true, "ReVanced.app", "https://revanced.app"),
|
new WebLink(true, "ReVanced.app", "https://revanced.app")
|
||||||
DONATE_LINK,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
private static final String SOCIAL_LINKS_PROVIDER = "https://api.revanced.app/v2";
|
private static final String SOCIAL_LINKS_PROVIDER = "https://api.revanced.app/v4";
|
||||||
private static final Route.CompiledRoute GET_SOCIAL = new Route(GET, "/socials").compile();
|
private static final Route.CompiledRoute GET_SOCIAL = new Route(GET, "/about").compile();
|
||||||
|
|
||||||
@Nullable
|
@Nullable
|
||||||
private static volatile WebLink[] fetchedLinks;
|
private static volatile WebLink[] fetchedLinks;
|
||||||
@ -278,7 +303,7 @@ class SocialLinksRoutes {
|
|||||||
return fetchedLinks != null;
|
return fetchedLinks != null;
|
||||||
}
|
}
|
||||||
|
|
||||||
static WebLink[] fetchSocialLinks() {
|
static WebLink[] fetchAboutLinks() {
|
||||||
try {
|
try {
|
||||||
if (hasFetchedLinks()) return fetchedLinks;
|
if (hasFetchedLinks()) return fetchedLinks;
|
||||||
|
|
||||||
@ -298,11 +323,22 @@ class SocialLinksRoutes {
|
|||||||
}
|
}
|
||||||
|
|
||||||
JSONObject json = Requester.parseJSONObjectAndDisconnect(connection);
|
JSONObject json = Requester.parseJSONObjectAndDisconnect(connection);
|
||||||
JSONArray socials = json.getJSONArray("socials");
|
aboutLogoUrl = json.getJSONObject("branding").getString("logo");
|
||||||
|
|
||||||
List<WebLink> links = new ArrayList<>();
|
List<WebLink> links = new ArrayList<>();
|
||||||
|
|
||||||
links.add(DONATE_LINK); // Show donate link first.
|
JSONArray donations = json.getJSONObject("donations").getJSONArray("links");
|
||||||
|
for (int i = 0, length = donations.length(); i < length; i++) {
|
||||||
|
WebLink link = new WebLink(donations.getJSONObject(i));
|
||||||
|
if (link.preferred) {
|
||||||
|
// This could be localized, but TikTok does not support localized resources.
|
||||||
|
// All link names returned by the api are also non localized.
|
||||||
|
link.name = "Donate";
|
||||||
|
links.add(link);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
JSONArray socials = json.getJSONArray("socials");
|
||||||
for (int i = 0, length = socials.length(); i < length; i++) {
|
for (int i = 0, length = socials.length(); i < length; i++) {
|
||||||
WebLink link = new WebLink(socials.getJSONObject(i));
|
WebLink link = new WebLink(socials.getJSONObject(i));
|
||||||
links.add(link);
|
links.add(link);
|
||||||
|
@ -0,0 +1,56 @@
|
|||||||
|
package app.revanced.extension.tiktok.settings.preference;
|
||||||
|
|
||||||
|
import android.content.Context;
|
||||||
|
import android.util.AttributeSet;
|
||||||
|
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
import app.revanced.extension.shared.Logger;
|
||||||
|
import app.revanced.extension.shared.settings.preference.ReVancedAboutPreference;
|
||||||
|
|
||||||
|
@SuppressWarnings("unused")
|
||||||
|
public class ReVancedTikTokAboutPreference extends ReVancedAboutPreference {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Because resources cannot be added to TikTok,
|
||||||
|
* these strings are copied from the shared strings.xml file.
|
||||||
|
*
|
||||||
|
* Changes here must also be made in strings.xml
|
||||||
|
*/
|
||||||
|
private final Map<String, String> aboutStrings = Map.of(
|
||||||
|
"revanced_settings_about_links_body", "You are using ReVanced Patches version <i>%s</i>",
|
||||||
|
"revanced_settings_about_links_dev_header", "Note",
|
||||||
|
"revanced_settings_about_links_dev_body", "This version is a pre-release and you may experience unexpected issues",
|
||||||
|
"revanced_settings_about_links_header", "Official links"
|
||||||
|
);
|
||||||
|
|
||||||
|
{
|
||||||
|
//noinspection deprecation
|
||||||
|
setTitle("About");
|
||||||
|
}
|
||||||
|
|
||||||
|
public ReVancedTikTokAboutPreference(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
|
||||||
|
super(context, attrs, defStyleAttr, defStyleRes);
|
||||||
|
}
|
||||||
|
public ReVancedTikTokAboutPreference(Context context, AttributeSet attrs, int defStyleAttr) {
|
||||||
|
super(context, attrs, defStyleAttr);
|
||||||
|
}
|
||||||
|
public ReVancedTikTokAboutPreference(Context context, AttributeSet attrs) {
|
||||||
|
super(context, attrs);
|
||||||
|
}
|
||||||
|
public ReVancedTikTokAboutPreference(Context context) {
|
||||||
|
super(context);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected String getString(String key, Object ... args) {
|
||||||
|
String format = aboutStrings.get(key);
|
||||||
|
|
||||||
|
if (format == null) {
|
||||||
|
Logger.printException(() -> "Unknown key: " + key);
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
|
||||||
|
return String.format(format, args);
|
||||||
|
}
|
||||||
|
}
|
@ -4,13 +4,14 @@ import android.content.Context;
|
|||||||
import android.preference.PreferenceScreen;
|
import android.preference.PreferenceScreen;
|
||||||
|
|
||||||
import app.revanced.extension.shared.settings.BaseSettings;
|
import app.revanced.extension.shared.settings.BaseSettings;
|
||||||
|
import app.revanced.extension.tiktok.settings.preference.ReVancedTikTokAboutPreference;
|
||||||
import app.revanced.extension.tiktok.settings.preference.TogglePreference;
|
import app.revanced.extension.tiktok.settings.preference.TogglePreference;
|
||||||
|
|
||||||
@SuppressWarnings("deprecation")
|
@SuppressWarnings("deprecation")
|
||||||
public class ExtensionPreferenceCategory extends ConditionalPreferenceCategory {
|
public class ExtensionPreferenceCategory extends ConditionalPreferenceCategory {
|
||||||
public ExtensionPreferenceCategory(Context context, PreferenceScreen screen) {
|
public ExtensionPreferenceCategory(Context context, PreferenceScreen screen) {
|
||||||
super(context, screen);
|
super(context, screen);
|
||||||
setTitle("Extension");
|
setTitle("Miscellaneous");
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -20,6 +21,8 @@ public class ExtensionPreferenceCategory extends ConditionalPreferenceCategory {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void addPreferences(Context context) {
|
public void addPreferences(Context context) {
|
||||||
|
addPreference(new ReVancedTikTokAboutPreference(context));
|
||||||
|
|
||||||
addPreference(new TogglePreference(context,
|
addPreference(new TogglePreference(context,
|
||||||
"Enable debug log",
|
"Enable debug log",
|
||||||
"Show extension debug log.",
|
"Show extension debug log.",
|
||||||
|
@ -60,7 +60,8 @@ This is because Crowdin requires temporarily flattening this file and removing t
|
|||||||
<string name="revanced_settings_about_links_dev_header">Note</string>
|
<string name="revanced_settings_about_links_dev_header">Note</string>
|
||||||
<string name="revanced_settings_about_links_dev_body">This version is a pre-release and you may experience unexpected issues</string>
|
<string name="revanced_settings_about_links_dev_body">This version is a pre-release and you may experience unexpected issues</string>
|
||||||
<string name="revanced_settings_about_links_header">Official links</string>
|
<string name="revanced_settings_about_links_header">Official links</string>
|
||||||
<string name="revanced_settings_about_links_donate">Donate</string>
|
<!-- NOTE: the about strings above are duplicated in the TikTok about screen code,
|
||||||
|
and changes made here must also be made there. -->
|
||||||
</patch>
|
</patch>
|
||||||
<patch id="misc.gms.gmsCoreSupportResourcePatch">
|
<patch id="misc.gms.gmsCoreSupportResourcePatch">
|
||||||
<!-- Translations of this should not be longer than the original English text, otherwise the text can be clipped and not entirely shown. -->
|
<!-- Translations of this should not be longer than the original English text, otherwise the text can be clipped and not entirely shown. -->
|
||||||
|
Loading…
Reference in New Issue
Block a user