Proper support RTL (#1562)

This commit is contained in:
LoveSy 2022-01-26 11:50:47 +08:00 committed by GitHub
parent 66b196d5a7
commit 303def1344
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
23 changed files with 114 additions and 54 deletions

View File

@ -174,7 +174,7 @@ afterEvaluate {
doLast { doLast {
val langList = File(projectDir, "src/main/res").listFiles { dir -> val langList = File(projectDir, "src/main/res").listFiles { dir ->
dir.name.startsWith("values-") && File(dir, "strings.xml").exists() dir.name.startsWith("values-") && File(dir, "strings.xml").exists()
}.orEmpty().map { }.orEmpty().sorted().map {
it.name.substring(7).split("-", limit = 2) it.name.substring(7).split("-", limit = 2)
}.map { }.map {
if (it.size == 1) Locale(it[0]) if (it.size == 1) Locale(it[0])

View File

@ -1,5 +1,5 @@
<!DOCTYPE html> <!DOCTYPE html>
<html> <html dir="@dir@">
<head> <head>
<meta charset="utf-8"> <meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=0"> <meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=0">

View File

@ -95,6 +95,7 @@ public class SubtitleCollapsingToolbarLayout extends FrameLayout {
collapsingTextHelper = new SubtitleCollapsingTextHelper(this); collapsingTextHelper = new SubtitleCollapsingTextHelper(this);
collapsingTextHelper.setTextSizeInterpolator(AnimationUtils.DECELERATE_INTERPOLATOR); collapsingTextHelper.setTextSizeInterpolator(AnimationUtils.DECELERATE_INTERPOLATOR);
collapsingTextHelper.setRtlTextDirectionHeuristicsEnabled(false);
TypedArray a = ThemeEnforcement.obtainStyledAttributes( TypedArray a = ThemeEnforcement.obtainStyledAttributes(
context, context,
@ -1073,6 +1074,22 @@ public class SubtitleCollapsingToolbarLayout extends FrameLayout {
requestLayout(); requestLayout();
} }
/**
* Sets whether {@code TextDirectionHeuristics} should be used to determine whether the title text
* is RTL. Experimental Feature.
*/
public void setRtlTextDirectionHeuristicsEnabled(boolean rtlTextDirectionHeuristicsEnabled) {
collapsingTextHelper.setRtlTextDirectionHeuristicsEnabled(rtlTextDirectionHeuristicsEnabled);
}
/**
* Gets whether {@code TextDirectionHeuristics} should be used to determine whether the title text
* is RTL. Experimental Feature.
*/
public boolean isRtlTextDirectionHeuristicsEnabled() {
return collapsingTextHelper.isRtlTextDirectionHeuristicsEnabled();
}
/** /**
* Set the amount of visible height in pixels used to define when to trigger a scrim visibility * Set the amount of visible height in pixels used to define when to trigger a scrim visibility
* change. * change.

View File

@ -85,6 +85,7 @@ public final class SubtitleCollapsingTextHelper {
@Nullable @Nullable
private CharSequence titleToDraw, subtitleToDraw; private CharSequence titleToDraw, subtitleToDraw;
private boolean isRtl; private boolean isRtl;
private boolean isRtlTextDirectionHeuristicsEnabled = true;
private boolean useTexture; private boolean useTexture;
@Nullable @Nullable
@ -615,6 +616,14 @@ public final class SubtitleCollapsingTextHelper {
return expandedSubtitleTextSize; return expandedSubtitleTextSize;
} }
public void setRtlTextDirectionHeuristicsEnabled(boolean rtlTextDirectionHeuristicsEnabled) {
isRtlTextDirectionHeuristicsEnabled = rtlTextDirectionHeuristicsEnabled;
}
public boolean isRtlTextDirectionHeuristicsEnabled() {
return isRtlTextDirectionHeuristicsEnabled;
}
private void calculateCurrentOffsets() { private void calculateCurrentOffsets() {
calculateOffsets(expandedFraction); calculateOffsets(expandedFraction);
} }
@ -889,10 +898,21 @@ public final class SubtitleCollapsingTextHelper {
} }
private boolean calculateIsRtl(@NonNull CharSequence text) { private boolean calculateIsRtl(@NonNull CharSequence text) {
final boolean defaultIsRtl = ViewCompat.getLayoutDirection(view) == ViewCompat.LAYOUT_DIRECTION_RTL; final boolean defaultIsRtl = isDefaultIsRtl();
return isRtlTextDirectionHeuristicsEnabled
? isTextDirectionHeuristicsIsRtl(text, defaultIsRtl)
: defaultIsRtl;
}
private boolean isDefaultIsRtl() {
return ViewCompat.getLayoutDirection(view) == ViewCompat.LAYOUT_DIRECTION_RTL;
}
private boolean isTextDirectionHeuristicsIsRtl(@NonNull CharSequence text, boolean defaultIsRtl) {
return (defaultIsRtl return (defaultIsRtl
? TextDirectionHeuristicsCompat.FIRSTSTRONG_RTL ? TextDirectionHeuristicsCompat.FIRSTSTRONG_RTL
: TextDirectionHeuristicsCompat.FIRSTSTRONG_LTR).isRtl(text, 0, text.length()); : TextDirectionHeuristicsCompat.FIRSTSTRONG_LTR)
.isRtl(text, 0, text.length());
} }
private void setInterpolatedTitleTextSize(float textSize) { private void setInterpolatedTitleTextSize(float textSize) {

View File

@ -78,7 +78,7 @@ public class App extends Application {
return result.toString(StandardCharsets.UTF_8.name()); return result.toString(StandardCharsets.UTF_8.name());
} catch (IOException e) { } catch (IOException e) {
Log.e(App.TAG, "read webview HTML", e); Log.e(App.TAG, "read webview HTML", e);
return "<html><body>@body@</body></html>"; return "<html dir\"@dir@\"><body>@body@</body></html>";
} }
} }

View File

@ -78,12 +78,12 @@ import java.util.ArrayList;
import java.util.Comparator; import java.util.Comparator;
import java.util.HashSet; import java.util.HashSet;
import java.util.List; import java.util.List;
import java.util.Locale;
import java.util.Objects; import java.util.Objects;
import java.util.Set; import java.util.Set;
import java.util.stream.Collectors; import java.util.stream.Collectors;
import rikka.core.util.ResourceUtils; import rikka.core.util.ResourceUtils;
import rikka.material.app.LocaleDelegate;
import rikka.widget.switchbar.SwitchBar; import rikka.widget.switchbar.SwitchBar;
@SuppressLint("NotifyDataSetChanged") @SuppressLint("NotifyDataSetChanged")
@ -253,7 +253,7 @@ public class ScopeAdapter extends EmptyStateRecyclerView.EmptyStateAdapter<Scope
preferences.edit().putBoolean("filter_denylist", item.isChecked()).apply(); preferences.edit().putBoolean("filter_denylist", item.isChecked()).apply();
} else if (itemId == R.id.backup) { } else if (itemId == R.id.backup) {
LocalDateTime now = LocalDateTime.now(); LocalDateTime now = LocalDateTime.now();
fragment.backupLauncher.launch(String.format(Locale.ROOT, fragment.backupLauncher.launch(String.format(LocaleDelegate.getDefaultLocale(),
"%s_%s.lsp", module.getAppName(), now.toString())); "%s_%s.lsp", module.getAppName(), now.toString()));
return true; return true;
} else if (itemId == R.id.restore) { } else if (itemId == R.id.restore) {

View File

@ -38,6 +38,8 @@ import org.lsposed.manager.util.NavUtil;
import java.time.LocalDateTime; import java.time.LocalDateTime;
import rikka.material.app.LocaleDelegate;
public class CrashReportActivity extends AppCompatActivity { public class CrashReportActivity extends AppCompatActivity {
ActivityCrashReportBinding binding; ActivityCrashReportBinding binding;
@ -67,7 +69,7 @@ public class CrashReportActivity extends AppCompatActivity {
} }
public String getAllErrorDetailsFromIntent(@NonNull Intent intent) { public String getAllErrorDetailsFromIntent(@NonNull Intent intent) {
String versionName = String.format("%s (%s)", BuildConfig.VERSION_NAME, BuildConfig.VERSION_CODE); String versionName = String.format(LocaleDelegate.getDefaultLocale(), "%s (%d)", BuildConfig.VERSION_NAME, BuildConfig.VERSION_CODE);
return "Build version: " + versionName + " \n" + return "Build version: " + versionName + " \n" +
"Current date: " + LocalDateTime.now() + " \n" + "Current date: " + LocalDateTime.now() + " \n" +

View File

@ -45,8 +45,7 @@ import org.lsposed.manager.databinding.FragmentAppListBinding;
import org.lsposed.manager.util.BackupUtils; import org.lsposed.manager.util.BackupUtils;
import org.lsposed.manager.util.ModuleUtil; import org.lsposed.manager.util.ModuleUtil;
import java.util.Locale; import rikka.material.app.LocaleDelegate;
import rikka.recyclerview.RecyclerViewKt; import rikka.recyclerview.RecyclerViewKt;
public class AppListFragment extends BaseFragment { public class AppListFragment extends BaseFragment {
@ -79,7 +78,7 @@ public class AppListFragment extends BaseFragment {
binding.appBar.setLiftable(true); binding.appBar.setLiftable(true);
String title; String title;
if (module.userId != 0) { if (module.userId != 0) {
title = String.format(Locale.ROOT, "%s (%d)", module.getAppName(), module.userId); title = String.format(LocaleDelegate.getDefaultLocale(), "%s (%d)", module.getAppName(), module.userId);
} else { } else {
title = module.getAppName(); title = module.getAppName();
} }
@ -207,6 +206,7 @@ public class AppListFragment extends BaseFragment {
binding.recyclerView.setNestedScrollingEnabled(true); binding.recyclerView.setNestedScrollingEnabled(true);
} }
}); });
searchView.findViewById(androidx.appcompat.R.id.search_edit_frame).setLayoutDirection(View.LAYOUT_DIRECTION_INHERIT);
scopeAdapter.onPrepareOptionsMenu(menu); scopeAdapter.onPrepareOptionsMenu(menu);
} }

View File

@ -46,9 +46,8 @@ import org.lsposed.manager.util.NavUtil;
import org.lsposed.manager.util.UpdateUtil; import org.lsposed.manager.util.UpdateUtil;
import org.lsposed.manager.util.chrome.LinkTransformationMethod; import org.lsposed.manager.util.chrome.LinkTransformationMethod;
import java.util.Locale;
import rikka.core.util.ClipboardUtils; import rikka.core.util.ClipboardUtils;
import rikka.material.app.LocaleDelegate;
public class HomeFragment extends BaseFragment { public class HomeFragment extends BaseFragment {
@ -125,7 +124,7 @@ public class HomeFragment extends BaseFragment {
binding.statusTitle.setText(R.string.activated); binding.statusTitle.setText(R.string.activated);
binding.statusIcon.setImageResource(R.drawable.ic_round_check_circle_24); binding.statusIcon.setImageResource(R.drawable.ic_round_check_circle_24);
} }
binding.statusSummary.setText(String.format(Locale.ROOT, "%s (%d) - %s", binding.statusSummary.setText(String.format(LocaleDelegate.getDefaultLocale(), "%s (%d) - %s",
ConfigManager.getXposedVersionName(), ConfigManager.getXposedVersionCode(), ConfigManager.getApi())); ConfigManager.getXposedVersionName(), ConfigManager.getXposedVersionCode(), ConfigManager.getApi()));
} else { } else {
boolean isMagiskInstalled = ConfigManager.isMagiskInstalled(); boolean isMagiskInstalled = ConfigManager.isMagiskInstalled();
@ -152,18 +151,18 @@ public class HomeFragment extends BaseFragment {
if (ConfigManager.isBinderAlive()) { if (ConfigManager.isBinderAlive()) {
binding.apiVersion.setText(String.valueOf(ConfigManager.getXposedApiVersion())); binding.apiVersion.setText(String.valueOf(ConfigManager.getXposedApiVersion()));
binding.api.setText(ConfigManager.getApi()); binding.api.setText(ConfigManager.getApi());
binding.frameworkVersion.setText(String.format(Locale.ROOT, "%s (%s)", ConfigManager.getXposedVersionName(), ConfigManager.getXposedVersionCode())); binding.frameworkVersion.setText(String.format(LocaleDelegate.getDefaultLocale(), "%1$s (%2$d)", ConfigManager.getXposedVersionName(), ConfigManager.getXposedVersionCode()));
} else { } else {
binding.apiVersion.setText(R.string.not_installed); binding.apiVersion.setText(R.string.not_installed);
binding.api.setText(R.string.not_installed); binding.api.setText(R.string.not_installed);
binding.frameworkVersion.setText(R.string.not_installed); binding.frameworkVersion.setText(R.string.not_installed);
} }
binding.managerVersion.setText(String.format(Locale.ROOT, "%s (%s)", BuildConfig.VERSION_NAME, BuildConfig.VERSION_CODE)); binding.managerVersion.setText(String.format(LocaleDelegate.getDefaultLocale(), "%1$s (%2$d)", BuildConfig.VERSION_NAME, BuildConfig.VERSION_CODE));
if (Build.VERSION.PREVIEW_SDK_INT != 0) { if (Build.VERSION.PREVIEW_SDK_INT != 0) {
binding.systemVersion.setText(String.format(Locale.ROOT, "%1$s Preview (API %2$d)", Build.VERSION.CODENAME, Build.VERSION.SDK_INT)); binding.systemVersion.setText(String.format(LocaleDelegate.getDefaultLocale(), "%1$s Preview (API %2$d)", Build.VERSION.CODENAME, Build.VERSION.SDK_INT));
} else { } else {
binding.systemVersion.setText(String.format(Locale.ROOT, "%1$s (API %2$d)", Build.VERSION.RELEASE, Build.VERSION.SDK_INT)); binding.systemVersion.setText(String.format(LocaleDelegate.getDefaultLocale(), "%1$s (API %2$d)", Build.VERSION.RELEASE, Build.VERSION.SDK_INT));
} }
binding.device.setText(getDevice()); binding.device.setText(getDevice());
@ -222,7 +221,7 @@ public class HomeFragment extends BaseFragment {
R.string.about_view_source_code, R.string.about_view_source_code,
"<b><a href=\"https://github.com/LSPosed/LSPosed\">GitHub</a></b>", "<b><a href=\"https://github.com/LSPosed/LSPosed\">GitHub</a></b>",
"<b><a href=\"https://t.me/LSPosed\">Telegram</a></b>"), HtmlCompat.FROM_HTML_MODE_LEGACY)); "<b><a href=\"https://t.me/LSPosed\">Telegram</a></b>"), HtmlCompat.FROM_HTML_MODE_LEGACY));
binding.designAboutVersion.setText(String.format(Locale.ROOT, "%s (%s)", BuildConfig.VERSION_NAME, BuildConfig.VERSION_CODE)); binding.designAboutVersion.setText(String.format(LocaleDelegate.getDefaultLocale(), "%s (%d)", BuildConfig.VERSION_NAME, BuildConfig.VERSION_CODE));
return new BlurBehindDialogBuilder(requireContext()) return new BlurBehindDialogBuilder(requireContext())
.setView(binding.getRoot()).create(); .setView(binding.getRoot()).create();
} }

View File

@ -60,7 +60,6 @@ import java.time.LocalDateTime;
import java.util.Arrays; import java.util.Arrays;
import java.util.Collections; import java.util.Collections;
import java.util.List; import java.util.List;
import java.util.Locale;
import java.util.stream.Collectors; import java.util.stream.Collectors;
import java.util.stream.IntStream; import java.util.stream.IntStream;
import java.util.zip.Deflater; import java.util.zip.Deflater;
@ -68,6 +67,7 @@ import java.util.zip.ZipEntry;
import java.util.zip.ZipOutputStream; import java.util.zip.ZipOutputStream;
import rikka.core.os.FileUtils; import rikka.core.os.FileUtils;
import rikka.material.app.LocaleDelegate;
import rikka.recyclerview.RecyclerViewKt; import rikka.recyclerview.RecyclerViewKt;
public class LogsFragment extends BaseFragment { public class LogsFragment extends BaseFragment {
@ -166,7 +166,7 @@ public class LogsFragment extends BaseFragment {
private void save() { private void save() {
LocalDateTime now = LocalDateTime.now(); LocalDateTime now = LocalDateTime.now();
String filename = String.format(Locale.ROOT, "LSPosed_%s.zip", now.toString()); String filename = String.format(LocaleDelegate.getDefaultLocale(), "LSPosed_%s.zip", now.toString());
saveLogsLauncher.launch(filename); saveLogsLauncher.launch(filename);
} }
@ -275,6 +275,8 @@ public class LogsFragment extends BaseFragment {
binding.recyclerView.setAdapter(adaptor); binding.recyclerView.setAdapter(adaptor);
layoutManager = new LinearLayoutManager(requireActivity()); layoutManager = new LinearLayoutManager(requireActivity());
binding.recyclerView.setLayoutManager(layoutManager); binding.recyclerView.setLayoutManager(layoutManager);
// ltr even for rtl languages because of log format
binding.recyclerView.setLayoutDirection(View.LAYOUT_DIRECTION_LTR);
binding.swipeRefreshLayout.setProgressViewEndTarget(true, binding.swipeRefreshLayout.getProgressViewEndOffset()); binding.swipeRefreshLayout.setProgressViewEndTarget(true, binding.swipeRefreshLayout.getProgressViewEndOffset());
RecyclerViewKt.fixEdgeEffect(binding.recyclerView, false, true); RecyclerViewKt.fixEdgeEffect(binding.recyclerView, false, true);
binding.swipeRefreshLayout.setOnRefreshListener(adaptor::fullRefresh); binding.swipeRefreshLayout.setOnRefreshListener(adaptor::fullRefresh);
@ -378,6 +380,7 @@ public class LogsFragment extends BaseFragment {
HorizontalScrollView horizontalScrollView = new HorizontalScrollView(getContext()); HorizontalScrollView horizontalScrollView = new HorizontalScrollView(getContext());
horizontalScrollView.setFillViewport(true); horizontalScrollView.setFillViewport(true);
horizontalScrollView.setHorizontalScrollBarEnabled(false); horizontalScrollView.setHorizontalScrollBarEnabled(false);
horizontalScrollView.setLayoutDirection(View.LAYOUT_DIRECTION_LTR);
binding.swipeRefreshLayout.addView(horizontalScrollView); binding.swipeRefreshLayout.addView(horizontalScrollView);
horizontalScrollView.addView(binding.recyclerView); horizontalScrollView.addView(binding.recyclerView);
binding.recyclerView.getLayoutParams().width = ViewGroup.LayoutParams.WRAP_CONTENT; binding.recyclerView.getLayoutParams().width = ViewGroup.LayoutParams.WRAP_CONTENT;

View File

@ -90,6 +90,7 @@ import java.util.function.Consumer;
import java.util.stream.IntStream; import java.util.stream.IntStream;
import rikka.core.util.ResourceUtils; import rikka.core.util.ResourceUtils;
import rikka.material.app.LocaleDelegate;
import rikka.recyclerview.RecyclerViewKt; import rikka.recyclerview.RecyclerViewKt;
public class ModulesFragment extends BaseFragment implements ModuleUtil.ModuleListener, RepoLoader.RepoListener { public class ModulesFragment extends BaseFragment implements ModuleUtil.ModuleListener, RepoLoader.RepoListener {
@ -203,6 +204,7 @@ public class ModulesFragment extends BaseFragment implements ModuleUtil.ModuleLi
public void onViewDetachedFromWindow(View v) { public void onViewDetachedFromWindow(View v) {
} }
}); });
searchView.findViewById(androidx.appcompat.R.id.search_edit_frame).setLayoutDirection(View.LAYOUT_DIRECTION_INHERIT);
} }
@Override @Override
@ -515,7 +517,7 @@ public class ModulesFragment extends BaseFragment implements ModuleUtil.ModuleLi
ModuleUtil.InstalledModule item = showList.get(position); ModuleUtil.InstalledModule item = showList.get(position);
String appName; String appName;
if (item.userId != 0) { if (item.userId != 0) {
appName = String.format("%s (%s)", item.getAppName(), item.userId); appName = String.format(LocaleDelegate.getDefaultLocale(), "%s (%d)", item.getAppName(), item.userId);
} else { } else {
appName = item.getAppName(); appName = item.getAppName();
} }

View File

@ -183,6 +183,7 @@ public class RepoFragment extends BaseFragment implements RepoLoader.RepoListene
binding.recyclerView.setNestedScrollingEnabled(true); binding.recyclerView.setNestedScrollingEnabled(true);
} }
}); });
searchView.findViewById(androidx.appcompat.R.id.search_edit_frame).setLayoutDirection(View.LAYOUT_DIRECTION_INHERIT);
int sort = App.getPreferences().getInt("repo_sort", 0); int sort = App.getPreferences().getInt("repo_sort", 0);
if (sort == 0) { if (sort == 0) {
menu.findItem(R.id.item_sort_by_name).setChecked(true); menu.findItem(R.id.item_sort_by_name).setChecked(true);

View File

@ -79,7 +79,6 @@ import java.nio.charset.StandardCharsets;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
import java.util.ListIterator; import java.util.ListIterator;
import java.util.Locale;
import java.util.stream.Collectors; import java.util.stream.Collectors;
import java.util.stream.IntStream; import java.util.stream.IntStream;
@ -87,6 +86,7 @@ import okhttp3.Headers;
import okhttp3.Request; import okhttp3.Request;
import okhttp3.Response; import okhttp3.Response;
import rikka.core.util.ResourceUtils; import rikka.core.util.ResourceUtils;
import rikka.material.app.LocaleDelegate;
import rikka.recyclerview.RecyclerViewKt; import rikka.recyclerview.RecyclerViewKt;
import rikka.widget.borderview.BorderView; import rikka.widget.borderview.BorderView;
@ -152,10 +152,16 @@ public class RepoItemFragment extends BaseFragment implements RepoLoader.RepoLis
setting.setCacheMode(WebSettings.LOAD_CACHE_ELSE_NETWORK); setting.setCacheMode(WebSettings.LOAD_CACHE_ELSE_NETWORK);
setting.setTextZoom(80); setting.setTextZoom(80);
String body; String body;
if (ResourceUtils.isNightMode(getResources().getConfiguration())) { String direction;
body = App.HTML_TEMPLATE_DARK.get().replace("@body@", text); if (getResources().getConfiguration().getLayoutDirection() == View.LAYOUT_DIRECTION_RTL) {
direction = "rtl";
} else { } else {
body = App.HTML_TEMPLATE.get().replace("@body@", text); direction = "ltr";
}
if (ResourceUtils.isNightMode(getResources().getConfiguration())) {
body = App.HTML_TEMPLATE_DARK.get().replace("@dir@", direction).replace("@body@", text);
} else {
body = App.HTML_TEMPLATE.get().replace("@dir@", direction).replace("@body@", text);
} }
view.setWebViewClient(new WebViewClient() { view.setWebViewClient(new WebViewClient() {
@Override @Override
@ -353,12 +359,12 @@ public class RepoItemFragment extends BaseFragment implements RepoLoader.RepoLis
if (channel.equals(channels[0])) { if (channel.equals(channels[0])) {
this.items = releases.parallelStream().filter(t -> { this.items = releases.parallelStream().filter(t -> {
if (t.getIsPrerelease()) return false; if (t.getIsPrerelease()) return false;
var name = t.getName().toLowerCase(Locale.ROOT); var name = t.getName().toLowerCase(LocaleDelegate.getDefaultLocale());
return !name.startsWith("snapshot") && !name.startsWith("nightly"); return !name.startsWith("snapshot") && !name.startsWith("nightly");
}).collect(Collectors.toList()); }).collect(Collectors.toList());
} else if (channel.equals(channels[1])) { } else if (channel.equals(channels[1])) {
this.items = releases.parallelStream().filter(t -> { this.items = releases.parallelStream().filter(t -> {
var name = t.getName().toLowerCase(Locale.ROOT); var name = t.getName().toLowerCase(LocaleDelegate.getDefaultLocale());
return !name.startsWith("snapshot") && !name.startsWith("nightly"); return !name.startsWith("snapshot") && !name.startsWith("nightly");
}).collect(Collectors.toList()); }).collect(Collectors.toList());
} else this.items = releases; } else this.items = releases;

View File

@ -77,10 +77,10 @@ public class SettingsFragment extends BaseFragment {
.add(R.id.setting_container, new PreferenceFragment()).commitNow(); .add(R.id.setting_container, new PreferenceFragment()).commitNow();
} }
if (ConfigManager.isBinderAlive()) { if (ConfigManager.isBinderAlive()) {
binding.toolbar.setSubtitle(String.format(Locale.ROOT, "%s (%d) - %s", binding.toolbar.setSubtitle(String.format(LocaleDelegate.getDefaultLocale(), "%s (%d) - %s",
ConfigManager.getXposedVersionName(), ConfigManager.getXposedVersionCode(), ConfigManager.getApi())); ConfigManager.getXposedVersionName(), ConfigManager.getXposedVersionCode(), ConfigManager.getApi()));
} else { } else {
binding.toolbar.setSubtitle(String.format(Locale.ROOT, "%s (%d) - %s", binding.toolbar.setSubtitle(String.format(LocaleDelegate.getDefaultLocale(), "%s (%d) - %s",
BuildConfig.VERSION_NAME, BuildConfig.VERSION_CODE, getString(R.string.not_installed))); BuildConfig.VERSION_NAME, BuildConfig.VERSION_CODE, getString(R.string.not_installed)));
} }
return binding.getRoot(); return binding.getRoot();
@ -163,7 +163,7 @@ public class SettingsFragment extends BaseFragment {
backup.setEnabled(installed); backup.setEnabled(installed);
backup.setOnPreferenceClickListener(preference -> { backup.setOnPreferenceClickListener(preference -> {
LocalDateTime now = LocalDateTime.now(); LocalDateTime now = LocalDateTime.now();
backupLauncher.launch(String.format(Locale.ROOT, backupLauncher.launch(String.format(LocaleDelegate.getDefaultLocale(),
"LSPosed_%s.lsp", now.toString())); "LSPosed_%s.lsp", now.toString()));
return true; return true;
}); });

View File

@ -16,13 +16,13 @@ import java.io.File;
import java.io.IOException; import java.io.IOException;
import java.time.Instant; import java.time.Instant;
import java.time.ZoneOffset; import java.time.ZoneOffset;
import java.util.Locale;
import okhttp3.Call; import okhttp3.Call;
import okhttp3.Callback; import okhttp3.Callback;
import okhttp3.Request; import okhttp3.Request;
import okhttp3.Response; import okhttp3.Response;
import okio.Okio; import okio.Okio;
import rikka.material.app.LocaleDelegate;
public class UpdateUtil { public class UpdateUtil {
public static void loadRemoteVersion() { public static void loadRemoteVersion() {
@ -42,7 +42,7 @@ public class UpdateUtil {
var notes = info.get("body").getAsString(); var notes = info.get("body").getAsString();
var assetsArray = info.getAsJsonArray("assets"); var assetsArray = info.getAsJsonArray("assets");
for (var assets : assetsArray) { for (var assets : assetsArray) {
checkAssets(assets.getAsJsonObject(), notes, api.toLowerCase(Locale.ROOT)); checkAssets(assets.getAsJsonObject(), notes, api.toLowerCase(LocaleDelegate.getDefaultLocale()));
} }
} catch (Throwable t) { } catch (Throwable t) {
Log.e(App.TAG, t.getMessage(), t); Log.e(App.TAG, t.getMessage(), t);

View File

@ -35,8 +35,8 @@
android:background="?android:colorBackground" android:background="?android:colorBackground"
app:defaultNavHost="true" app:defaultNavHost="true"
app:layout_constraintBottom_toBottomOf="parent" app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintLeft_toRightOf="@id/nav" app:layout_constraintStart_toEndOf="@id/nav"
app:layout_constraintRight_toRightOf="parent" app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintTop_toTopOf="parent" app:layout_constraintTop_toTopOf="parent"
app:navGraph="@navigation/main_nav" /> app:navGraph="@navigation/main_nav" />
@ -45,7 +45,7 @@
android:layout_width="wrap_content" android:layout_width="wrap_content"
android:layout_height="match_parent" android:layout_height="match_parent"
app:layout_constraintBottom_toBottomOf="parent" app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintLeft_toLeftOf="parent" app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" app:layout_constraintTop_toTopOf="parent"
app:menu="@menu/navigation_menu" app:menu="@menu/navigation_menu"
app:menuGravity="center" /> app:menuGravity="center" />

View File

@ -36,8 +36,8 @@
android:background="?android:colorBackground" android:background="?android:colorBackground"
app:defaultNavHost="true" app:defaultNavHost="true"
app:layout_constraintBottom_toTopOf="@id/nav" app:layout_constraintBottom_toTopOf="@id/nav"
app:layout_constraintLeft_toLeftOf="parent" app:layout_constraintStart_toStartOf="parent"
app:layout_constraintRight_toRightOf="parent" app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintTop_toTopOf="parent" app:layout_constraintTop_toTopOf="parent"
app:navGraph="@navigation/main_nav" /> app:navGraph="@navigation/main_nav" />
@ -47,8 +47,8 @@
android:layout_height="wrap_content" android:layout_height="wrap_content"
app:fitsSystemWindowsInsets="bottom" app:fitsSystemWindowsInsets="bottom"
app:layout_constraintBottom_toBottomOf="parent" app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintLeft_toLeftOf="parent" app:layout_constraintStart_toStartOf="parent"
app:layout_constraintRight_toRightOf="parent" app:layout_constraintEnd_toEndOf="parent"
app:menu="@menu/navigation_menu" /> app:menu="@menu/navigation_menu" />
</androidx.constraintlayout.widget.ConstraintLayout> </androidx.constraintlayout.widget.ConstraintLayout>
</androidx.coordinatorlayout.widget.CoordinatorLayout> </androidx.coordinatorlayout.widget.CoordinatorLayout>

View File

@ -52,6 +52,7 @@
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="?attr/actionBarSize" android:layout_height="?attr/actionBarSize"
android:elevation="0dp" android:elevation="0dp"
android:theme="@style/ThemeOverlay.MaterialComponents.ActionBar"
app:layout_collapseMode="pin" /> app:layout_collapseMode="pin" />
</com.google.android.material.appbar.SubtitleCollapsingToolbarLayout> </com.google.android.material.appbar.SubtitleCollapsingToolbarLayout>

View File

@ -25,19 +25,19 @@
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:background="?selectableItemBackground" android:background="?selectableItemBackground"
android:clickable="true" android:clickable="true"
android:clipChildren="false"
android:clipToPadding="false"
android:focusable="true" android:focusable="true"
android:minHeight="?attr/listPreferredItemHeight" android:minHeight="?attr/listPreferredItemHeight"
android:paddingVertical="16dp" android:paddingVertical="16dp"
android:paddingStart="16dp" android:paddingStart="16dp"
android:paddingEnd="24dp" android:paddingEnd="24dp">
android:clipToPadding="false"
android:clipChildren="false">
<androidx.constraintlayout.widget.ConstraintLayout <androidx.constraintlayout.widget.ConstraintLayout
android:id="@+id/item_root" android:id="@+id/item_root"
android:layout_gravity="center"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="match_parent" android:layout_height="match_parent"
android:layout_gravity="center"
tools:ignore="RtlSymmetry"> tools:ignore="RtlSymmetry">
<com.google.android.material.textview.MaterialTextView <com.google.android.material.textview.MaterialTextView
@ -46,10 +46,10 @@
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:textAppearance="?android:attr/textAppearanceListItem" android:textAppearance="?android:attr/textAppearanceListItem"
android:textSize="16sp" android:textSize="16sp"
app:layout_constraintBottom_toTopOf="@id/description"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintBottom_toBottomOf="parent" app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintBottom_toTopOf="@id/description"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
tools:text="@tools:sample/lorem" /> tools:text="@tools:sample/lorem" />
<org.lsposed.manager.ui.widget.ScrollWebView <org.lsposed.manager.ui.widget.ScrollWebView
@ -57,37 +57,39 @@
android:layout_width="0dp" android:layout_width="0dp"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:layout_gravity="center_vertical" android:layout_gravity="center_vertical"
android:scrollbars="none"
android:textAppearance="?android:attr/textAppearanceSmall" android:textAppearance="?android:attr/textAppearanceSmall"
app:layout_constraintEnd_toEndOf="parent" app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintHorizontal_bias="1.0" app:layout_constraintHorizontal_bias="1.0"
app:layout_constraintStart_toStartOf="@+id/title" app:layout_constraintStart_toStartOf="@+id/title"
app:layout_constraintTop_toBottomOf="@id/title" app:layout_constraintTop_toBottomOf="@id/title"
android:scrollbars="none"
tools:text="@tools:sample/lorem" /> tools:text="@tools:sample/lorem" />
<com.google.android.material.button.MaterialButton <com.google.android.material.button.MaterialButton
android:id="@+id/view_assets" android:id="@+id/view_assets"
style="@style/Widget.MaterialComponents.Button.Icon"
android:layout_width="wrap_content" android:layout_width="wrap_content"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:text="@string/module_release_view_assets"
android:layout_marginTop="4dp" android:layout_marginTop="4dp"
android:text="@string/module_release_view_assets"
android:tooltipText="@string/module_release_view_assets"
app:icon="@drawable/ic_attach_file" app:icon="@drawable/ic_attach_file"
app:layout_constraintBottom_toBottomOf="parent" app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintStart_toStartOf="@id/description" app:layout_constraintStart_toStartOf="@id/description"
app:layout_constraintTop_toBottomOf="@id/description" app:layout_constraintTop_toBottomOf="@id/description" />
style="@style/Widget.MaterialComponents.Button.Icon" />
<com.google.android.material.button.MaterialButton <com.google.android.material.button.MaterialButton
android:id="@+id/open_in_browser" android:id="@+id/open_in_browser"
style="@style/Widget.App.Button.OutlinedButton.IconOnly"
android:layout_width="wrap_content" android:layout_width="wrap_content"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:layout_marginStart="6dp" android:layout_marginStart="6dp"
android:layout_marginTop="4dp" android:layout_marginTop="4dp"
android:tooltipText="@string/menu_open_in_browser"
app:icon="@drawable/ic_open_in_browser" app:icon="@drawable/ic_open_in_browser"
app:layout_constraintBottom_toBottomOf="parent" app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintStart_toEndOf="@+id/view_assets" app:layout_constraintStart_toEndOf="@+id/view_assets"
app:layout_constraintTop_toBottomOf="@id/description" app:layout_constraintTop_toBottomOf="@id/description" />
style="@style/Widget.App.Button.OutlinedButton.IconOnly" />
</androidx.constraintlayout.widget.ConstraintLayout> </androidx.constraintlayout.widget.ConstraintLayout>
</FrameLayout> </FrameLayout>

View File

@ -31,4 +31,8 @@
<item name="android:textColor">?android:attr/textColorSecondary</item> <item name="android:textColor">?android:attr/textColorSecondary</item>
</style> </style>
<style name="language_menu_style" parent="ThemeOverlay.Preference.SimpleMenuPreference.PopupMenu">
<item name="android:textAlignment">textStart</item>
</style>
</resources> </resources>

View File

@ -32,6 +32,7 @@
<item name="android:colorAccent">?colorPrimary</item> <item name="android:colorAccent">?colorPrimary</item>
<!-- Preference switch --> <!-- Preference switch -->
<item name="android:colorControlActivated">?colorPrimary</item> <item name="android:colorControlActivated">?colorPrimary</item>
<item name="android:textAlignment">viewStart</item>
</style> </style>
<style name="Theme.Light" parent="Base.AppTheme.Light" /> <style name="Theme.Light" parent="Base.AppTheme.Light" />
@ -48,6 +49,7 @@
<item name="android:colorAccent">?colorPrimary</item> <item name="android:colorAccent">?colorPrimary</item>
<!-- Preference switch --> <!-- Preference switch -->
<item name="android:colorControlActivated">?colorPrimary</item> <item name="android:colorControlActivated">?colorPrimary</item>
<item name="android:textAlignment">viewStart</item>
</style> </style>
<style name="Theme" parent="Base.AppTheme" /> <style name="Theme" parent="Base.AppTheme" />

View File

@ -36,6 +36,7 @@
android:defaultValue="SYSTEM" android:defaultValue="SYSTEM"
android:icon="@drawable/ic_outline_language_24" android:icon="@drawable/ic_outline_language_24"
android:key="language" android:key="language"
android:popupTheme="@style/language_menu_style"
android:summary="%s" android:summary="%s"
android:title="@string/settings_language" /> android:title="@string/settings_language" />

View File

@ -81,7 +81,7 @@ public class ServiceManager {
} }
} }
Log.i(TAG, "starting server..."); Log.i(TAG, "starting server...");
Log.i(TAG, String.format("version %s (%s)", BuildConfig.VERSION_NAME, BuildConfig.VERSION_CODE)); Log.i(TAG, String.format("version %s (%d)", BuildConfig.VERSION_NAME, BuildConfig.VERSION_CODE));
Thread.setDefaultUncaughtExceptionHandler((t, e) -> { Thread.setDefaultUncaughtExceptionHandler((t, e) -> {
Log.e(TAG, "Uncaught exception", e); Log.e(TAG, "Uncaught exception", e);