From 30003d37873d19ac377bbaa30afc2a573f0f423a Mon Sep 17 00:00:00 2001 From: M M Arif Date: Thu, 26 Jun 2025 12:41:31 +0500 Subject: [PATCH] Move appearance to bottom sheet --- app/src/main/AndroidManifest.xml | 3 - .../SettingsAppearanceActivity.java | 463 ---------------- ...BottomSheetSettingsAppearanceFragment.java | 492 ++++++++++++++++++ .../gitnex/fragments/SettingsFragment.java | 5 +- .../layout/activity_settings_appearance.xml | 405 -------------- .../bottom_sheet_settings_appearance.xml | 402 ++++++++++++++ app/src/main/res/layout/chip_item.xml | 9 + app/src/main/res/values/settings.xml | 1 - 8 files changed, 906 insertions(+), 874 deletions(-) delete mode 100644 app/src/main/java/org/mian/gitnex/activities/SettingsAppearanceActivity.java create mode 100644 app/src/main/java/org/mian/gitnex/fragments/BottomSheetSettingsAppearanceFragment.java delete mode 100644 app/src/main/res/layout/activity_settings_appearance.xml create mode 100644 app/src/main/res/layout/bottom_sheet_settings_appearance.xml create mode 100644 app/src/main/res/layout/chip_item.xml diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index 9605011c..b7471095 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -127,9 +127,6 @@ android:name=".activities.CommitDetailActivity" android:configChanges="orientation|screenSize|smallestScreenSize|density|screenLayout|keyboard|keyboardHidden|navigation" android:theme="@android:style/Theme.NoTitleBar"/> - diff --git a/app/src/main/java/org/mian/gitnex/activities/SettingsAppearanceActivity.java b/app/src/main/java/org/mian/gitnex/activities/SettingsAppearanceActivity.java deleted file mode 100644 index d038141d..00000000 --- a/app/src/main/java/org/mian/gitnex/activities/SettingsAppearanceActivity.java +++ /dev/null @@ -1,463 +0,0 @@ -package org.mian.gitnex.activities; - -import android.os.Build; -import android.os.Bundle; -import android.os.Handler; -import android.view.View; -import com.google.android.material.dialog.MaterialAlertDialogBuilder; -import com.google.android.material.timepicker.MaterialTimePicker; -import java.util.LinkedHashMap; -import java.util.Locale; -import org.mian.gitnex.R; -import org.mian.gitnex.databinding.ActivitySettingsAppearanceBinding; -import org.mian.gitnex.fragments.SettingsFragment; -import org.mian.gitnex.helpers.AppDatabaseSettings; -import org.mian.gitnex.helpers.AppUtil; -import org.mian.gitnex.helpers.FontsOverride; -import org.mian.gitnex.helpers.SnackBar; - -/** - * @author M M Arif - */ -public class SettingsAppearanceActivity extends BaseActivity { - - private static String[] customFontList; - private static int customFontSelectedChoice; - private static String[] themeList; - private static int themeSelectedChoice; - private static int langSelectedChoice; - private static String[] fragmentTabsAnimationList; - private static int fragmentTabsAnimationSelectedChoice; - - @Override - public void onCreate(Bundle savedInstanceState) { - - super.onCreate(savedInstanceState); - - ActivitySettingsAppearanceBinding activitySettingsAppearanceBinding = - ActivitySettingsAppearanceBinding.inflate(getLayoutInflater()); - setContentView(activitySettingsAppearanceBinding.getRoot()); - - LinkedHashMap lang = new LinkedHashMap<>(); - lang.put("sys", getString(R.string.settingsLanguageSystem)); - for (String langCode : getResources().getStringArray(R.array.languages)) { - lang.put(langCode, getLanguageDisplayName(langCode)); - } - - customFontList = getResources().getStringArray(R.array.fonts); - - fragmentTabsAnimationList = getResources().getStringArray(R.array.fragmentTabsAnimation); - - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S || "S".equals(Build.VERSION.CODENAME)) { - themeList = getResources().getStringArray(R.array.themesAndroid12); - } else { - themeList = getResources().getStringArray(R.array.themes); - } - - activitySettingsAppearanceBinding.topAppBar.setNavigationOnClickListener(v -> finish()); - - String lightMinute = - String.valueOf( - AppDatabaseSettings.getSettingsValue( - ctx, AppDatabaseSettings.APP_THEME_AUTO_LIGHT_MIN_KEY)); - String lightHour = - String.valueOf( - AppDatabaseSettings.getSettingsValue( - ctx, AppDatabaseSettings.APP_THEME_AUTO_LIGHT_HOUR_KEY)); - if (lightMinute.length() == 1) { - lightMinute = "0" + lightMinute; - } - if (lightHour.length() == 1) { - lightHour = "0" + lightHour; - } - - String darkMinute = - String.valueOf( - AppDatabaseSettings.getSettingsValue( - ctx, AppDatabaseSettings.APP_THEME_AUTO_DARK_MIN_KEY)); - String darkHour = - String.valueOf( - AppDatabaseSettings.getSettingsValue( - ctx, AppDatabaseSettings.APP_THEME_AUTO_DARK_HOUR_KEY)); - if (darkMinute.length() == 1) { - darkMinute = "0" + darkMinute; - } - if (darkHour.length() == 1) { - darkHour = "0" + darkHour; - } - - fragmentTabsAnimationSelectedChoice = - Integer.parseInt( - AppDatabaseSettings.getSettingsValue( - ctx, AppDatabaseSettings.APP_TABS_ANIMATION_KEY)); - customFontSelectedChoice = - Integer.parseInt( - AppDatabaseSettings.getSettingsValue( - ctx, AppDatabaseSettings.APP_FONT_KEY)); - themeSelectedChoice = - Integer.parseInt( - AppDatabaseSettings.getSettingsValue( - ctx, AppDatabaseSettings.APP_THEME_KEY)); - - activitySettingsAppearanceBinding.lightThemeSelectedTime.setText( - ctx.getResources() - .getString(R.string.settingsThemeTimeSelectedHint, lightHour, lightMinute)); - activitySettingsAppearanceBinding.darkThemeSelectedTime.setText( - ctx.getResources() - .getString(R.string.settingsThemeTimeSelectedHint, darkHour, darkMinute)); - activitySettingsAppearanceBinding.customFontSelected.setText( - customFontList[customFontSelectedChoice]); - activitySettingsAppearanceBinding.themeSelected.setText(themeList[themeSelectedChoice]); - activitySettingsAppearanceBinding.fragmentTabsAnimationFrameSelected.setText( - fragmentTabsAnimationList[fragmentTabsAnimationSelectedChoice]); - - if (themeList[themeSelectedChoice].startsWith("Auto")) { - activitySettingsAppearanceBinding.darkThemeTimeSelectionFrame.setVisibility( - View.VISIBLE); - activitySettingsAppearanceBinding.lightThemeTimeSelectionFrame.setVisibility( - View.VISIBLE); - } else { - activitySettingsAppearanceBinding.darkThemeTimeSelectionFrame.setVisibility(View.GONE); - activitySettingsAppearanceBinding.lightThemeTimeSelectionFrame.setVisibility(View.GONE); - } - - activitySettingsAppearanceBinding.switchCounterBadge.setChecked( - Boolean.parseBoolean( - AppDatabaseSettings.getSettingsValue( - ctx, AppDatabaseSettings.APP_COUNTER_KEY))); - - // counter badge switcher - activitySettingsAppearanceBinding.switchCounterBadge.setOnCheckedChangeListener( - (buttonView, isChecked) -> { - AppDatabaseSettings.updateSettingsValue( - ctx, String.valueOf(isChecked), AppDatabaseSettings.APP_COUNTER_KEY); - SnackBar.success( - ctx, - findViewById(android.R.id.content), - getString(R.string.settingsSave)); - }); - activitySettingsAppearanceBinding.counterBadgeFrame.setOnClickListener( - v -> - activitySettingsAppearanceBinding.switchCounterBadge.setChecked( - !activitySettingsAppearanceBinding.switchCounterBadge.isChecked())); - - // hide email and language in user profile screen switcher - activitySettingsAppearanceBinding.switchHideEmailLangInProfile.setChecked( - Boolean.parseBoolean( - AppDatabaseSettings.getSettingsValue( - ctx, - AppDatabaseSettings.APP_USER_PROFILE_HIDE_EMAIL_LANGUAGE_KEY))); - - activitySettingsAppearanceBinding.switchHideEmailLangInProfile.setOnCheckedChangeListener( - (buttonView, isChecked) -> { - AppDatabaseSettings.updateSettingsValue( - ctx, - String.valueOf(isChecked), - AppDatabaseSettings.APP_USER_PROFILE_HIDE_EMAIL_LANGUAGE_KEY); - SnackBar.success( - ctx, - findViewById(android.R.id.content), - getString(R.string.settingsSave)); - }); - activitySettingsAppearanceBinding.hideEmailLangInProfileFrame.setOnClickListener( - v -> - activitySettingsAppearanceBinding.switchHideEmailLangInProfile.setChecked( - !activitySettingsAppearanceBinding.switchHideEmailLangInProfile - .isChecked())); - - // hide email in app navigation drawer switcher - activitySettingsAppearanceBinding.switchHideEmailNavDrawer.setChecked( - Boolean.parseBoolean( - AppDatabaseSettings.getSettingsValue( - ctx, AppDatabaseSettings.APP_USER_HIDE_EMAIL_IN_NAV_KEY))); - - activitySettingsAppearanceBinding.switchHideEmailNavDrawer.setOnCheckedChangeListener( - (buttonView, isChecked) -> { - AppDatabaseSettings.updateSettingsValue( - ctx, - String.valueOf(isChecked), - AppDatabaseSettings.APP_USER_HIDE_EMAIL_IN_NAV_KEY); - SnackBar.success( - ctx, - findViewById(android.R.id.content), - getString(R.string.settingsSave)); - }); - activitySettingsAppearanceBinding.hideEmailNavDrawerFrame.setOnClickListener( - v -> - activitySettingsAppearanceBinding.switchHideEmailNavDrawer.setChecked( - !activitySettingsAppearanceBinding.switchHideEmailNavDrawer - .isChecked())); - - // show labels in lists(issues, pr) - default is color dots - activitySettingsAppearanceBinding.switchLabelsInListBadge.setChecked( - Boolean.parseBoolean( - AppDatabaseSettings.getSettingsValue( - ctx, AppDatabaseSettings.APP_LABELS_IN_LIST_KEY))); - - activitySettingsAppearanceBinding.switchLabelsInListBadge.setOnCheckedChangeListener( - (buttonView, isChecked) -> { - AppDatabaseSettings.updateSettingsValue( - ctx, - String.valueOf(isChecked), - AppDatabaseSettings.APP_LABELS_IN_LIST_KEY); - SnackBar.success( - ctx, - findViewById(android.R.id.content), - getString(R.string.settingsSave)); - }); - activitySettingsAppearanceBinding.labelsInListFrame.setOnClickListener( - v -> - activitySettingsAppearanceBinding.switchLabelsInListBadge.setChecked( - !activitySettingsAppearanceBinding.switchLabelsInListBadge - .isChecked())); - - // theme selection dialog - activitySettingsAppearanceBinding.themeSelectionFrame.setOnClickListener( - view -> { - MaterialAlertDialogBuilder materialAlertDialogBuilder = - new MaterialAlertDialogBuilder(ctx) - .setTitle(R.string.themeSelectorDialogTitle) - .setSingleChoiceItems( - themeList, - themeSelectedChoice, - (dialogInterfaceTheme, i) -> { - themeSelectedChoice = i; - activitySettingsAppearanceBinding.themeSelected - .setText(themeList[i]); - AppDatabaseSettings.updateSettingsValue( - ctx, - String.valueOf(i), - AppDatabaseSettings.APP_THEME_KEY); - - SettingsFragment.refreshParent = true; - this.recreate(); - this.overridePendingTransition(0, 0); - dialogInterfaceTheme.dismiss(); - SnackBar.success( - ctx, - findViewById(android.R.id.content), - getString(R.string.settingsSave)); - }); - - materialAlertDialogBuilder.create().show(); - }); - - activitySettingsAppearanceBinding.lightThemeTimeSelectionFrame.setOnClickListener( - view -> lightTimePicker()); - - activitySettingsAppearanceBinding.darkThemeTimeSelectionFrame.setOnClickListener( - view -> darkTimePicker()); - - // custom font dialog - activitySettingsAppearanceBinding.customFontFrame.setOnClickListener( - view -> { - MaterialAlertDialogBuilder materialAlertDialogBuilder = - new MaterialAlertDialogBuilder(ctx) - .setTitle(R.string.settingsCustomFontSelectorDialogTitle) - .setCancelable(customFontSelectedChoice != -1) - .setSingleChoiceItems( - customFontList, - customFontSelectedChoice, - (dialogInterfaceCustomFont, i) -> { - customFontSelectedChoice = i; - activitySettingsAppearanceBinding.customFontSelected - .setText(customFontList[i]); - AppDatabaseSettings.updateSettingsValue( - ctx, - String.valueOf(i), - AppDatabaseSettings.APP_FONT_KEY); - - new Handler() - .postDelayed( - () -> { - AppUtil.typeface = - null; // reset typeface - FontsOverride.setDefaultFont( - this); - SettingsFragment.refreshParent = - true; - this.recreate(); - this.overridePendingTransition( - 0, 0); - }, - 1000); - - dialogInterfaceCustomFont.dismiss(); - SnackBar.success( - ctx, - findViewById(android.R.id.content), - getString(R.string.settingsSave)); - }); - - materialAlertDialogBuilder.create().show(); - }); - - // fragment tabs animation dialog - activitySettingsAppearanceBinding.fragmentTabsAnimationFrame.setOnClickListener( - view -> { - MaterialAlertDialogBuilder materialAlertDialogBuilder = - new MaterialAlertDialogBuilder(ctx) - .setTitle(R.string.fragmentTabsAnimationHeader) - .setCancelable(fragmentTabsAnimationSelectedChoice != -1) - .setSingleChoiceItems( - fragmentTabsAnimationList, - fragmentTabsAnimationSelectedChoice, - (dialogInterfaceTabsAnimation, i) -> { - fragmentTabsAnimationSelectedChoice = i; - activitySettingsAppearanceBinding - .fragmentTabsAnimationFrameSelected.setText( - fragmentTabsAnimationList[i]); - AppDatabaseSettings.updateSettingsValue( - ctx, - String.valueOf(i), - AppDatabaseSettings.APP_TABS_ANIMATION_KEY); - - SettingsFragment.refreshParent = true; - this.recreate(); - this.overridePendingTransition(0, 0); - dialogInterfaceTabsAnimation.dismiss(); - SnackBar.success( - ctx, - findViewById(android.R.id.content), - getString(R.string.settingsSave)); - }); - - materialAlertDialogBuilder.create().show(); - }); - - // language selector dialog - activitySettingsAppearanceBinding.helpTranslate.setOnClickListener( - v12 -> - AppUtil.openUrlInBrowser( - this, getResources().getString(R.string.crowdInLink))); - - String[] locale = - AppDatabaseSettings.getSettingsValue(ctx, AppDatabaseSettings.APP_LOCALE_KEY) - .split("\\|"); - langSelectedChoice = Integer.parseInt(locale[0]); - activitySettingsAppearanceBinding.tvLanguageSelected.setText( - lang.get(lang.keySet().toArray(new String[0])[langSelectedChoice])); - - // language dialog - activitySettingsAppearanceBinding.langFrame.setOnClickListener( - view -> { - MaterialAlertDialogBuilder materialAlertDialogBuilder = - new MaterialAlertDialogBuilder(ctx) - .setTitle(R.string.settingsLanguageSelectorDialogTitle) - .setCancelable(langSelectedChoice != -1) - .setNeutralButton(getString(R.string.cancelButton), null) - .setSingleChoiceItems( - lang.values().toArray(new String[0]), - langSelectedChoice, - (dialogInterface, i) -> { - String selectedLanguage = - lang.keySet().toArray(new String[0])[i]; - AppDatabaseSettings.updateSettingsValue( - ctx, - i + "|" + selectedLanguage, - AppDatabaseSettings.APP_LOCALE_KEY); - - SettingsFragment.refreshParent = true; - this.overridePendingTransition(0, 0); - dialogInterface.dismiss(); - SnackBar.success( - ctx, - findViewById(android.R.id.content), - getString(R.string.settingsSave)); - this.recreate(); - }); - - materialAlertDialogBuilder.create().show(); - }); - } - - public void lightTimePicker() { - - int hour = - Integer.parseInt( - AppDatabaseSettings.getSettingsValue( - ctx, AppDatabaseSettings.APP_THEME_AUTO_LIGHT_HOUR_KEY)); - int minute = - Integer.parseInt( - AppDatabaseSettings.getSettingsValue( - ctx, AppDatabaseSettings.APP_THEME_AUTO_LIGHT_MIN_KEY)); - - MaterialTimePicker materialTimePicker = - new MaterialTimePicker.Builder().setHour(hour).setMinute(minute).build(); - - materialTimePicker.addOnPositiveButtonClickListener( - selection -> { - AppDatabaseSettings.updateSettingsValue( - ctx, - String.valueOf(materialTimePicker.getHour()), - AppDatabaseSettings.APP_THEME_AUTO_LIGHT_HOUR_KEY); - AppDatabaseSettings.updateSettingsValue( - ctx, - String.valueOf(materialTimePicker.getMinute()), - AppDatabaseSettings.APP_THEME_AUTO_LIGHT_MIN_KEY); - SettingsFragment.refreshParent = true; - overridePendingTransition(0, 0); - SnackBar.success( - ctx, - findViewById(android.R.id.content), - getString(R.string.settingsSave)); - recreate(); - }); - - materialTimePicker.show(getSupportFragmentManager(), "fragmentManager"); - } - - public void darkTimePicker() { - - int hour = - Integer.parseInt( - AppDatabaseSettings.getSettingsValue( - ctx, AppDatabaseSettings.APP_THEME_AUTO_DARK_HOUR_KEY)); - int minute = - Integer.parseInt( - AppDatabaseSettings.getSettingsValue( - ctx, AppDatabaseSettings.APP_THEME_AUTO_DARK_MIN_KEY)); - - MaterialTimePicker materialTimePicker = - new MaterialTimePicker.Builder().setHour(hour).setMinute(minute).build(); - - materialTimePicker.addOnPositiveButtonClickListener( - selection -> { - AppDatabaseSettings.updateSettingsValue( - ctx, - String.valueOf(materialTimePicker.getHour()), - AppDatabaseSettings.APP_THEME_AUTO_DARK_HOUR_KEY); - AppDatabaseSettings.updateSettingsValue( - ctx, - String.valueOf(materialTimePicker.getMinute()), - AppDatabaseSettings.APP_THEME_AUTO_DARK_MIN_KEY); - SettingsFragment.refreshParent = true; - overridePendingTransition(0, 0); - SnackBar.success( - ctx, - findViewById(android.R.id.content), - getString(R.string.settingsSave)); - recreate(); - }); - - materialTimePicker.show(getSupportFragmentManager(), "fragmentManager"); - } - - private static String getLanguageDisplayName(String langCode) { - Locale english = new Locale("en"); - - String[] multiCodeLang = langCode.split("-"); - String countryCode; - if (langCode.contains("-")) { - langCode = multiCodeLang[0]; - countryCode = multiCodeLang[1]; - } else { - countryCode = ""; - } - - Locale translated = new Locale(langCode, countryCode); - return String.format( - "%s (%s)", - translated.getDisplayName(translated), translated.getDisplayName(english)); - } -} diff --git a/app/src/main/java/org/mian/gitnex/fragments/BottomSheetSettingsAppearanceFragment.java b/app/src/main/java/org/mian/gitnex/fragments/BottomSheetSettingsAppearanceFragment.java new file mode 100644 index 00000000..53c0bfe1 --- /dev/null +++ b/app/src/main/java/org/mian/gitnex/fragments/BottomSheetSettingsAppearanceFragment.java @@ -0,0 +1,492 @@ +package org.mian.gitnex.fragments; + +import android.os.Build; +import android.os.Bundle; +import android.os.Handler; +import android.util.Log; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; +import com.google.android.material.bottomsheet.BottomSheetDialogFragment; +import com.google.android.material.chip.Chip; +import com.google.android.material.dialog.MaterialAlertDialogBuilder; +import com.google.android.material.timepicker.MaterialTimePicker; +import java.util.LinkedHashMap; +import java.util.Locale; +import org.mian.gitnex.R; +import org.mian.gitnex.databinding.BottomSheetSettingsAppearanceBinding; +import org.mian.gitnex.helpers.AppDatabaseSettings; +import org.mian.gitnex.helpers.AppUtil; +import org.mian.gitnex.helpers.FontsOverride; +import org.mian.gitnex.helpers.SnackBar; + +/** + * @author mmarif + */ +public class BottomSheetSettingsAppearanceFragment extends BottomSheetDialogFragment { + + private static final String TAG = "BottomSheetSettingsAppearance"; + private BottomSheetSettingsAppearanceBinding binding; + private static int customFontSelectedChoice; + private static String[] themeList; + private static int themeSelectedChoice; + private static int langSelectedChoice; + private static int fragmentTabsAnimationSelectedChoice; + private LinkedHashMap lang; + + @Nullable @Override + public View onCreateView( + @NonNull LayoutInflater inflater, + @Nullable ViewGroup container, + @Nullable Bundle savedInstanceState) { + binding = BottomSheetSettingsAppearanceBinding.inflate(inflater, container, false); + + lang = new LinkedHashMap<>(); + lang.put("sys", getString(R.string.settingsLanguageSystem)); + for (String langCode : getResources().getStringArray(R.array.languages)) { + lang.put(langCode, getLanguageDisplayName(langCode)); + } + + String[] customFontList = getResources().getStringArray(R.array.fonts); + String[] fragmentTabsAnimationList = + getResources().getStringArray(R.array.fragmentTabsAnimation); + themeList = + Build.VERSION.SDK_INT >= Build.VERSION_CODES.S || "S".equals(Build.VERSION.CODENAME) + ? getResources().getStringArray(R.array.themesAndroid12) + : getResources().getStringArray(R.array.themes); + + customFontSelectedChoice = + Integer.parseInt( + AppDatabaseSettings.getSettingsValue( + requireContext(), AppDatabaseSettings.APP_FONT_KEY)); + themeSelectedChoice = + Integer.parseInt( + AppDatabaseSettings.getSettingsValue( + requireContext(), AppDatabaseSettings.APP_THEME_KEY)); + fragmentTabsAnimationSelectedChoice = + Integer.parseInt( + AppDatabaseSettings.getSettingsValue( + requireContext(), AppDatabaseSettings.APP_TABS_ANIMATION_KEY)); + String[] locale = + AppDatabaseSettings.getSettingsValue( + requireContext(), AppDatabaseSettings.APP_LOCALE_KEY) + .split("\\|"); + langSelectedChoice = Integer.parseInt(locale[0]); + + String lightMinute = + String.valueOf( + AppDatabaseSettings.getSettingsValue( + requireContext(), + AppDatabaseSettings.APP_THEME_AUTO_LIGHT_MIN_KEY)); + String lightHour = + String.valueOf( + AppDatabaseSettings.getSettingsValue( + requireContext(), + AppDatabaseSettings.APP_THEME_AUTO_LIGHT_HOUR_KEY)); + lightMinute = lightMinute.length() == 1 ? "0" + lightMinute : lightMinute; + lightHour = lightHour.length() == 1 ? "0" + lightHour : lightHour; + + String darkMinute = + String.valueOf( + AppDatabaseSettings.getSettingsValue( + requireContext(), AppDatabaseSettings.APP_THEME_AUTO_DARK_MIN_KEY)); + String darkHour = + String.valueOf( + AppDatabaseSettings.getSettingsValue( + requireContext(), + AppDatabaseSettings.APP_THEME_AUTO_DARK_HOUR_KEY)); + darkMinute = darkMinute.length() == 1 ? "0" + darkMinute : darkMinute; + darkHour = darkHour.length() == 1 ? "0" + darkHour : darkHour; + + for (int i = 0; i < themeList.length; i++) { + Chip chip = (Chip) inflater.inflate(R.layout.chip_item, binding.themeChipGroup, false); + chip.setId(View.generateViewId()); + chip.setText(themeList[i]); + chip.setCheckable(true); + chip.setClickable(true); + chip.setFocusable(true); + if (i == themeSelectedChoice) chip.setChecked(true); + binding.themeChipGroup.addView(chip); + } + + for (int i = 0; i < customFontList.length; i++) { + Chip chip = + (Chip) inflater.inflate(R.layout.chip_item, binding.customFontChipGroup, false); + chip.setId(View.generateViewId()); + chip.setText(customFontList[i]); + chip.setCheckable(true); + chip.setClickable(true); + chip.setFocusable(true); + if (i == customFontSelectedChoice) chip.setChecked(true); + binding.customFontChipGroup.addView(chip); + } + + for (int i = 0; i < fragmentTabsAnimationList.length; i++) { + Chip chip = + (Chip) + inflater.inflate( + R.layout.chip_item, + binding.fragmentTabsAnimationChipGroup, + false); + chip.setId(View.generateViewId()); + chip.setText(fragmentTabsAnimationList[i]); + chip.setCheckable(true); + chip.setClickable(true); + chip.setFocusable(true); + if (i == fragmentTabsAnimationSelectedChoice) chip.setChecked(true); + binding.fragmentTabsAnimationChipGroup.addView(chip); + } + + binding.lightThemeSelectedTime.setText( + getResources() + .getString(R.string.settingsThemeTimeSelectedHint, lightHour, lightMinute)); + binding.darkThemeSelectedTime.setText( + getResources() + .getString(R.string.settingsThemeTimeSelectedHint, darkHour, darkMinute)); + binding.tvLanguageSelected.setText( + lang.get(lang.keySet().toArray(new String[0])[langSelectedChoice])); + binding.switchCounterBadge.setChecked( + Boolean.parseBoolean( + AppDatabaseSettings.getSettingsValue( + requireContext(), AppDatabaseSettings.APP_COUNTER_KEY))); + binding.switchHideEmailLangInProfile.setChecked( + Boolean.parseBoolean( + AppDatabaseSettings.getSettingsValue( + requireContext(), + AppDatabaseSettings.APP_USER_PROFILE_HIDE_EMAIL_LANGUAGE_KEY))); + binding.switchHideEmailNavDrawer.setChecked( + Boolean.parseBoolean( + AppDatabaseSettings.getSettingsValue( + requireContext(), + AppDatabaseSettings.APP_USER_HIDE_EMAIL_IN_NAV_KEY))); + binding.switchLabelsInListBadge.setChecked( + Boolean.parseBoolean( + AppDatabaseSettings.getSettingsValue( + requireContext(), AppDatabaseSettings.APP_LABELS_IN_LIST_KEY))); + + binding.lightThemeTimeSelectionFrame.setVisibility( + themeList[themeSelectedChoice].startsWith("Auto") ? View.VISIBLE : View.GONE); + binding.darkThemeTimeSelectionFrame.setVisibility( + themeList[themeSelectedChoice].startsWith("Auto") ? View.VISIBLE : View.GONE); + + binding.themeChipGroup.setOnCheckedStateChangeListener( + (group, checkedIds) -> { + Log.d(TAG, "Theme chip checked: " + checkedIds); + if (checkedIds.size() == 1) { + int newSelection = getThemeChipPosition(checkedIds.get(0)); + Log.d(TAG, "Theme new selection: " + newSelection); + if (newSelection != themeSelectedChoice) { + themeSelectedChoice = newSelection; + AppDatabaseSettings.updateSettingsValue( + requireContext(), + String.valueOf(newSelection), + AppDatabaseSettings.APP_THEME_KEY); + binding.lightThemeTimeSelectionFrame.setVisibility( + themeList[newSelection].startsWith("Auto") + ? View.VISIBLE + : View.GONE); + binding.darkThemeTimeSelectionFrame.setVisibility( + themeList[newSelection].startsWith("Auto") + ? View.VISIBLE + : View.GONE); + SettingsFragment.refreshParent = true; + requireActivity().recreate(); + SnackBar.success( + requireContext(), + requireActivity().findViewById(android.R.id.content), + getString(R.string.settingsSave)); + } + } + }); + + binding.lightThemeTimeSelectionFrame.setOnClickListener(v -> lightTimePicker()); + binding.darkThemeTimeSelectionFrame.setOnClickListener(v -> darkTimePicker()); + + binding.customFontChipGroup.setOnCheckedStateChangeListener( + (group, checkedIds) -> { + Log.d(TAG, "Font chip checked: " + checkedIds); + if (checkedIds.size() == 1) { + int newSelection = getCustomFontChipPosition(checkedIds.get(0)); + Log.d(TAG, "Font new selection: " + newSelection); + if (newSelection != customFontSelectedChoice) { + customFontSelectedChoice = newSelection; + AppDatabaseSettings.updateSettingsValue( + requireContext(), + String.valueOf(newSelection), + AppDatabaseSettings.APP_FONT_KEY); + new Handler() + .postDelayed( + () -> { + AppUtil.typeface = null; // reset typeface + FontsOverride.setDefaultFont(requireContext()); + SettingsFragment.refreshParent = true; + requireActivity().recreate(); + }, + 1000); + SnackBar.success( + requireContext(), + requireActivity().findViewById(android.R.id.content), + getString(R.string.settingsSave)); + } + } + }); + + binding.fragmentTabsAnimationChipGroup.setOnCheckedStateChangeListener( + (group, checkedIds) -> { + Log.d(TAG, "Tabs animation chip checked: " + checkedIds); + if (checkedIds.size() == 1) { + int newSelection = getFragmentTabsAnimationChipPosition(checkedIds.get(0)); + Log.d(TAG, "Tabs animation new selection: " + newSelection); + if (newSelection != fragmentTabsAnimationSelectedChoice) { + fragmentTabsAnimationSelectedChoice = newSelection; + AppDatabaseSettings.updateSettingsValue( + requireContext(), + String.valueOf(newSelection), + AppDatabaseSettings.APP_TABS_ANIMATION_KEY); + SettingsFragment.refreshParent = true; + requireActivity().recreate(); + SnackBar.success( + requireContext(), + requireActivity().findViewById(android.R.id.content), + getString(R.string.settingsSave)); + } + } + }); + + binding.counterBadgeFrame.setOnClickListener( + v -> + binding.switchCounterBadge.setChecked( + !binding.switchCounterBadge.isChecked())); + binding.switchCounterBadge.setOnCheckedChangeListener( + (buttonView, isChecked) -> { + AppDatabaseSettings.updateSettingsValue( + requireContext(), + String.valueOf(isChecked), + AppDatabaseSettings.APP_COUNTER_KEY); + SnackBar.success( + requireContext(), + requireActivity().findViewById(android.R.id.content), + getString(R.string.settingsSave)); + }); + + binding.hideEmailLangInProfileFrame.setOnClickListener( + v -> + binding.switchHideEmailLangInProfile.setChecked( + !binding.switchHideEmailLangInProfile.isChecked())); + binding.switchHideEmailLangInProfile.setOnCheckedChangeListener( + (buttonView, isChecked) -> { + AppDatabaseSettings.updateSettingsValue( + requireContext(), + String.valueOf(isChecked), + AppDatabaseSettings.APP_USER_PROFILE_HIDE_EMAIL_LANGUAGE_KEY); + SnackBar.success( + requireContext(), + requireActivity().findViewById(android.R.id.content), + getString(R.string.settingsSave)); + }); + + binding.hideEmailNavDrawerFrame.setOnClickListener( + v -> + binding.switchHideEmailNavDrawer.setChecked( + !binding.switchHideEmailNavDrawer.isChecked())); + binding.switchHideEmailNavDrawer.setOnCheckedChangeListener( + (buttonView, isChecked) -> { + AppDatabaseSettings.updateSettingsValue( + requireContext(), + String.valueOf(isChecked), + AppDatabaseSettings.APP_USER_HIDE_EMAIL_IN_NAV_KEY); + SnackBar.success( + requireContext(), + requireActivity().findViewById(android.R.id.content), + getString(R.string.settingsSave)); + }); + + binding.labelsInListFrame.setOnClickListener( + v -> + binding.switchLabelsInListBadge.setChecked( + !binding.switchLabelsInListBadge.isChecked())); + binding.switchLabelsInListBadge.setOnCheckedChangeListener( + (buttonView, isChecked) -> { + AppDatabaseSettings.updateSettingsValue( + requireContext(), + String.valueOf(isChecked), + AppDatabaseSettings.APP_LABELS_IN_LIST_KEY); + SnackBar.success( + requireContext(), + requireActivity().findViewById(android.R.id.content), + getString(R.string.settingsSave)); + }); + + binding.langFrame.setOnClickListener( + v -> { + MaterialAlertDialogBuilder builder = + new MaterialAlertDialogBuilder(requireContext()) + .setTitle(R.string.settingsLanguageSelectorDialogTitle) + .setCancelable(langSelectedChoice != -1) + .setNeutralButton(R.string.cancelButton, null) + .setSingleChoiceItems( + lang.values().toArray(new String[0]), + langSelectedChoice, + (dialog, i) -> { + String selectedLanguage = + lang.keySet().toArray(new String[0])[i]; + AppDatabaseSettings.updateSettingsValue( + requireContext(), + i + "|" + selectedLanguage, + AppDatabaseSettings.APP_LOCALE_KEY); + SettingsFragment.refreshParent = true; + requireActivity().recreate(); + dialog.dismiss(); + SnackBar.success( + requireContext(), + requireActivity() + .findViewById(android.R.id.content), + getString(R.string.settingsSave)); + }); + builder.create().show(); + }); + + binding.helpTranslate.setOnClickListener( + v -> + AppUtil.openUrlInBrowser( + requireContext(), getResources().getString(R.string.crowdInLink))); + + return binding.getRoot(); + } + + private void lightTimePicker() { + int hour = + Integer.parseInt( + AppDatabaseSettings.getSettingsValue( + requireContext(), + AppDatabaseSettings.APP_THEME_AUTO_LIGHT_HOUR_KEY)); + int minute = + Integer.parseInt( + AppDatabaseSettings.getSettingsValue( + requireContext(), + AppDatabaseSettings.APP_THEME_AUTO_LIGHT_MIN_KEY)); + MaterialTimePicker picker = + new MaterialTimePicker.Builder().setHour(hour).setMinute(minute).build(); + picker.addOnPositiveButtonClickListener( + v -> { + AppDatabaseSettings.updateSettingsValue( + requireContext(), + String.valueOf(picker.getHour()), + AppDatabaseSettings.APP_THEME_AUTO_LIGHT_HOUR_KEY); + AppDatabaseSettings.updateSettingsValue( + requireContext(), + String.valueOf(picker.getMinute()), + AppDatabaseSettings.APP_THEME_AUTO_LIGHT_MIN_KEY); + SettingsFragment.refreshParent = true; + requireActivity().recreate(); + String minuteStr = + picker.getMinute() < 10 + ? "0" + picker.getMinute() + : String.valueOf(picker.getMinute()); + String hourStr = + picker.getHour() < 10 + ? "0" + picker.getHour() + : String.valueOf(picker.getHour()); + binding.lightThemeSelectedTime.setText( + getResources() + .getString( + R.string.settingsThemeTimeSelectedHint, + hourStr, + minuteStr)); + SnackBar.success( + requireContext(), + requireActivity().findViewById(android.R.id.content), + getString(R.string.settingsSave)); + }); + picker.show(getParentFragmentManager(), "lightTimePicker"); + } + + private void darkTimePicker() { + int hour = + Integer.parseInt( + AppDatabaseSettings.getSettingsValue( + requireContext(), + AppDatabaseSettings.APP_THEME_AUTO_DARK_HOUR_KEY)); + int minute = + Integer.parseInt( + AppDatabaseSettings.getSettingsValue( + requireContext(), AppDatabaseSettings.APP_THEME_AUTO_DARK_MIN_KEY)); + MaterialTimePicker picker = + new MaterialTimePicker.Builder().setHour(hour).setMinute(minute).build(); + picker.addOnPositiveButtonClickListener( + v -> { + AppDatabaseSettings.updateSettingsValue( + requireContext(), + String.valueOf(picker.getHour()), + AppDatabaseSettings.APP_THEME_AUTO_DARK_HOUR_KEY); + AppDatabaseSettings.updateSettingsValue( + requireContext(), + String.valueOf(picker.getMinute()), + AppDatabaseSettings.APP_THEME_AUTO_DARK_MIN_KEY); + SettingsFragment.refreshParent = true; + requireActivity().recreate(); + String minuteStr = + picker.getMinute() < 10 + ? "0" + picker.getMinute() + : String.valueOf(picker.getMinute()); + String hourStr = + picker.getHour() < 10 + ? "0" + picker.getHour() + : String.valueOf(picker.getHour()); + binding.darkThemeSelectedTime.setText( + getResources() + .getString( + R.string.settingsThemeTimeSelectedHint, + hourStr, + minuteStr)); + SnackBar.success( + requireContext(), + requireActivity().findViewById(android.R.id.content), + getString(R.string.settingsSave)); + }); + picker.show(getParentFragmentManager(), "darkTimePicker"); + } + + private int getThemeChipPosition(int checkedId) { + for (int i = 0; i < binding.themeChipGroup.getChildCount(); i++) { + Chip chip = (Chip) binding.themeChipGroup.getChildAt(i); + if (chip.getId() == checkedId) return i; + } + return themeSelectedChoice; + } + + private int getCustomFontChipPosition(int checkedId) { + for (int i = 0; i < binding.customFontChipGroup.getChildCount(); i++) { + Chip chip = (Chip) binding.customFontChipGroup.getChildAt(i); + if (chip.getId() == checkedId) return i; + } + return customFontSelectedChoice; + } + + private int getFragmentTabsAnimationChipPosition(int checkedId) { + for (int i = 0; i < binding.fragmentTabsAnimationChipGroup.getChildCount(); i++) { + Chip chip = (Chip) binding.fragmentTabsAnimationChipGroup.getChildAt(i); + if (chip.getId() == checkedId) return i; + } + return fragmentTabsAnimationSelectedChoice; + } + + private String getLanguageDisplayName(String langCode) { + Locale english = new Locale("en"); + String[] multiCodeLang = langCode.split("-"); + String countryCode = langCode.contains("-") ? multiCodeLang[1] : ""; + langCode = multiCodeLang[0]; + Locale translated = new Locale(langCode, countryCode); + return String.format( + "%s (%s)", + translated.getDisplayName(translated), translated.getDisplayName(english)); + } + + @Override + public void onDestroyView() { + super.onDestroyView(); + binding = null; + } +} diff --git a/app/src/main/java/org/mian/gitnex/fragments/SettingsFragment.java b/app/src/main/java/org/mian/gitnex/fragments/SettingsFragment.java index 255abd1e..320e073f 100644 --- a/app/src/main/java/org/mian/gitnex/fragments/SettingsFragment.java +++ b/app/src/main/java/org/mian/gitnex/fragments/SettingsFragment.java @@ -12,7 +12,6 @@ import androidx.annotation.NonNull; import androidx.annotation.Nullable; import androidx.fragment.app.Fragment; import org.mian.gitnex.R; -import org.mian.gitnex.activities.SettingsAppearanceActivity; import org.mian.gitnex.databinding.FragmentSettingsBinding; /** @@ -43,7 +42,9 @@ public class SettingsFragment extends Fragment { .show(getChildFragmentManager(), "BottomSheetSettingsGeneral")); fragmentSettingsBinding.appearanceFrame.setOnClickListener( - v1 -> startActivity(new Intent(ctx, SettingsAppearanceActivity.class))); + v1 -> + new BottomSheetSettingsAppearanceFragment() + .show(getChildFragmentManager(), "BottomSheetSettingsAppearance")); fragmentSettingsBinding.codeEditorFrame.setOnClickListener( v1 -> diff --git a/app/src/main/res/layout/activity_settings_appearance.xml b/app/src/main/res/layout/activity_settings_appearance.xml deleted file mode 100644 index 8477eee7..00000000 --- a/app/src/main/res/layout/activity_settings_appearance.xml +++ /dev/null @@ -1,405 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/app/src/main/res/layout/bottom_sheet_settings_appearance.xml b/app/src/main/res/layout/bottom_sheet_settings_appearance.xml new file mode 100644 index 00000000..2910c94e --- /dev/null +++ b/app/src/main/res/layout/bottom_sheet_settings_appearance.xml @@ -0,0 +1,402 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/app/src/main/res/layout/chip_item.xml b/app/src/main/res/layout/chip_item.xml new file mode 100644 index 00000000..e19195c3 --- /dev/null +++ b/app/src/main/res/layout/chip_item.xml @@ -0,0 +1,9 @@ + + diff --git a/app/src/main/res/values/settings.xml b/app/src/main/res/values/settings.xml index 8207247f..29eaf48b 100644 --- a/app/src/main/res/values/settings.xml +++ b/app/src/main/res/values/settings.xml @@ -39,7 +39,6 @@ Pitch Black @string/followSystem @string/followSystemBlack -