summaryrefslogtreecommitdiff
path: root/app/src/main/java/se
diff options
context:
space:
mode:
authorNorbel Ambanumben <nambanumben@riseup.net>2024-10-07 21:31:33 +0000
committercyberta <cyberta@riseup.net>2024-10-07 21:31:33 +0000
commit61106968cbdf96a4fa578d16aff03865b985e547 (patch)
tree8ff5d3ea1f2b562e885f4c7e3297ec3bda804fd3 /app/src/main/java/se
parente15787e844ffe1c74b0ba783a9e37c7daa72b72a (diff)
feat: add language selection
Diffstat (limited to 'app/src/main/java/se')
-rw-r--r--app/src/main/java/se/leap/bitmaskclient/base/fragments/LanguageSelectionFragment.java166
-rw-r--r--app/src/main/java/se/leap/bitmaskclient/base/fragments/NavigationDrawerFragment.java25
2 files changed, 191 insertions, 0 deletions
diff --git a/app/src/main/java/se/leap/bitmaskclient/base/fragments/LanguageSelectionFragment.java b/app/src/main/java/se/leap/bitmaskclient/base/fragments/LanguageSelectionFragment.java
new file mode 100644
index 00000000..263a8d46
--- /dev/null
+++ b/app/src/main/java/se/leap/bitmaskclient/base/fragments/LanguageSelectionFragment.java
@@ -0,0 +1,166 @@
+package se.leap.bitmaskclient.base.fragments;
+
+import static se.leap.bitmaskclient.base.utils.ViewHelper.setActionBarSubtitle;
+
+import android.os.Bundle;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.TextView;
+
+import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
+import androidx.appcompat.app.AppCompatDelegate;
+import androidx.core.os.LocaleListCompat;
+import androidx.recyclerview.widget.LinearLayoutManager;
+import androidx.recyclerview.widget.RecyclerView;
+
+import com.google.android.material.bottomsheet.BottomSheetDialogFragment;
+
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.Comparator;
+import java.util.List;
+import java.util.Locale;
+
+import se.leap.bitmaskclient.R;
+import se.leap.bitmaskclient.base.views.SimpleCheckBox;
+import se.leap.bitmaskclient.databinding.FLanguageSelectionBinding;
+import se.leap.bitmaskclient.databinding.VSelectTextListItemBinding;
+
+public class LanguageSelectionFragment extends BottomSheetDialogFragment {
+ static final String TAG = LanguageSelectionFragment.class.getSimpleName();
+ static final String SYSTEM_LOCALE = "systemLocale";
+ private FLanguageSelectionBinding binding;
+
+ public static LanguageSelectionFragment newInstance(Locale defaultLocale) {
+ LanguageSelectionFragment fragment = new LanguageSelectionFragment();
+ Bundle args = new Bundle();
+ args.putString(SYSTEM_LOCALE, defaultLocale.toLanguageTag());
+ fragment.setArguments(args);
+ return fragment;
+ }
+
+ @Nullable
+ @Override
+ public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
+ binding = FLanguageSelectionBinding.inflate(inflater, container, false);
+ return binding.getRoot();
+ }
+
+ @Override
+ public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) {
+ super.onViewCreated(view, savedInstanceState);
+ setActionBarSubtitle(this, R.string.select_language);
+
+ initRecyclerView(Arrays.asList(getResources().getStringArray(R.array.supported_languages)));
+ }
+
+ private static void customizeSelectionItem(VSelectTextListItemBinding binding) {
+ binding.title.setVisibility(View.GONE);
+ binding.bridgeImage.setVisibility(View.GONE);
+ binding.quality.setVisibility(View.GONE);
+ }
+
+ private void initRecyclerView(List<String> supportedLanguages) {
+ Locale defaultLocale = AppCompatDelegate.getApplicationLocales().get(0);
+ if (defaultLocale == null) {
+ defaultLocale = LocaleListCompat.getDefault().get(0);
+ }
+ // NOTE: Sort the supported languages by their display names.
+ // This would make updating supported languages easier as we don't have to tip toe around the order
+ Collections.sort(supportedLanguages, (lang1, lang2) -> {
+ String displayName1 = Locale.forLanguageTag(lang1).getDisplayName(Locale.ENGLISH);
+ String displayName2 = Locale.forLanguageTag(lang2).getDisplayName(Locale.ENGLISH);
+ return displayName1.compareTo(displayName2);
+ });
+ binding.languages.setAdapter(
+ new LanguageSelectionAdapter(supportedLanguages, this::updateLocale, defaultLocale)
+ );
+ binding.languages.setLayoutManager(new LinearLayoutManager(getContext()));
+ }
+
+ public static Locale getCurrentLocale() {
+ Locale defaultLocale = AppCompatDelegate.getApplicationLocales().get(0);
+ if (defaultLocale == null) {
+ defaultLocale = LocaleListCompat.getDefault().get(0);
+ }
+ return defaultLocale;
+ }
+
+ /**
+ * Update the locale of the application
+ *
+ * @param languageTag the language tag to set the locale to
+ */
+ private void updateLocale(String languageTag) {
+ if (languageTag.isEmpty()) {
+ AppCompatDelegate.setApplicationLocales(LocaleListCompat.getEmptyLocaleList());
+ } else {
+ AppCompatDelegate.setApplicationLocales(LocaleListCompat.forLanguageTags(languageTag));
+ }
+ }
+
+ /**
+ * Adapter for the language selection recycler view.
+ */
+ static class LanguageSelectionAdapter extends RecyclerView.Adapter<LanguageSelectionAdapter.LanguageViewHolder> {
+
+ private final List<String> languages;
+ private final LanguageClickListener clickListener;
+ private final Locale selectedLocale;
+
+ public LanguageSelectionAdapter(List<String> languages, LanguageClickListener clickListener, Locale defaultLocale) {
+ this.languages = languages;
+ this.clickListener = clickListener;
+ this.selectedLocale = defaultLocale;
+ }
+
+ @NonNull
+ @Override
+ public LanguageViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
+ VSelectTextListItemBinding binding = VSelectTextListItemBinding.inflate(LayoutInflater.from(parent.getContext()), parent, false);
+ return new LanguageViewHolder(binding);
+ }
+
+ @Override
+ public void onBindViewHolder(@NonNull LanguageViewHolder holder, int position) {
+ String languageTag = languages.get(position);
+ holder.languageName.setText(Locale.forLanguageTag(languageTag).getDisplayName(Locale.ENGLISH));
+ if (languages.contains(selectedLocale.toLanguageTag())) {
+ holder.selected.setChecked(selectedLocale.toLanguageTag().equals(languageTag));
+ } else {
+ holder.selected.setChecked(selectedLocale.getLanguage().equals(languageTag));
+ }
+ holder.itemView.setOnClickListener(v -> clickListener.onLanguageClick(languageTag));
+ }
+
+ @Override
+ public int getItemCount() {
+ return languages.size();
+ }
+
+ /**
+ * View holder for the language item
+ */
+ static class LanguageViewHolder extends RecyclerView.ViewHolder {
+ TextView languageName;
+ SimpleCheckBox selected;
+
+ public LanguageViewHolder(@NonNull VSelectTextListItemBinding binding) {
+ super(binding.getRoot());
+ languageName = binding.location;
+ selected = binding.selected;
+ customizeSelectionItem(binding);
+ }
+ }
+ }
+
+
+ /**
+ * Interface for the language click listener
+ */
+ interface LanguageClickListener {
+ void onLanguageClick(String languageTag);
+ }
+}
diff --git a/app/src/main/java/se/leap/bitmaskclient/base/fragments/NavigationDrawerFragment.java b/app/src/main/java/se/leap/bitmaskclient/base/fragments/NavigationDrawerFragment.java
index cbab1d32..41e102bb 100644
--- a/app/src/main/java/se/leap/bitmaskclient/base/fragments/NavigationDrawerFragment.java
+++ b/app/src/main/java/se/leap/bitmaskclient/base/fragments/NavigationDrawerFragment.java
@@ -46,15 +46,19 @@ import androidx.annotation.NonNull;
import androidx.appcompat.app.ActionBarDrawerToggle;
import androidx.appcompat.app.AlertDialog;
import androidx.appcompat.app.AppCompatActivity;
+import androidx.appcompat.app.AppCompatDelegate;
import androidx.appcompat.graphics.drawable.DrawerArrowDrawable;
import androidx.appcompat.widget.Toolbar;
import androidx.core.content.ContextCompat;
+import androidx.core.os.LocaleListCompat;
import androidx.core.view.GravityCompat;
import androidx.drawerlayout.widget.DrawerLayout;
import androidx.fragment.app.Fragment;
import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
+import java.util.Locale;
+import java.util.Map;
import se.leap.bitmaskclient.BuildConfig;
import se.leap.bitmaskclient.R;
@@ -211,6 +215,7 @@ public class NavigationDrawerFragment extends Fragment implements SharedPreferen
initSwitchProviderEntry();
initSaveBatteryEntry();
initManualGatewayEntry();
+ initLanguageSettingsEntry();
initAdvancedSettingsEntry();
initDonateEntry();
initLogEntry();
@@ -314,6 +319,26 @@ public class NavigationDrawerFragment extends Fragment implements SharedPreferen
});
}
+
+ private void initLanguageSettingsEntry() {
+ IconTextEntry languageSwitcher = drawerView.findViewById(R.id.language_switcher);
+
+ Locale currentLocale = LanguageSelectionFragment.getCurrentLocale();
+ languageSwitcher.setSubtitle(currentLocale.getDisplayName(Locale.ENGLISH));
+
+ languageSwitcher.setOnClickListener(v -> {
+ FragmentManagerEnhanced fragmentManager = new FragmentManagerEnhanced(getActivity().getSupportFragmentManager());
+ closeDrawer();
+ Fragment current = fragmentManager.findFragmentByTag(MainActivity.TAG);
+ if (current instanceof LanguageSelectionFragment) {
+ return;
+ }
+ Fragment fragment = LanguageSelectionFragment.newInstance(Locale.getDefault());
+ setDrawerToggleColor(drawerView.getContext(), ContextCompat.getColor(drawerView.getContext(), R.color.colorActionBarTitleFont));
+ fragmentManager.replace(R.id.main_container, fragment, MainActivity.TAG);
+ });
+ }
+
private void initDonateEntry() {
if (ENABLE_DONATION) {
IconTextEntry donate = drawerView.findViewById(R.id.donate);