package org.wordpress.android.util; import android.app.Activity; import android.preference.Preference; import android.preference.PreferenceCategory; import android.preference.PreferenceFragment; import android.preference.PreferenceGroup; import android.support.annotation.Nullable; import android.text.TextUtils; import android.util.Pair; import android.util.TypedValue; import android.widget.EditText; import android.widget.TextView; import org.wordpress.android.R; import org.wordpress.android.WordPress; import java.text.Collator; import java.util.ArrayList; import java.util.Collections; import java.util.HashMap; import java.util.Locale; import java.util.Map; /** * Design guidelines for Calypso-styled Site Settings (and likely other screens) */ public class WPPrefUtils { /** * Length of a {@link String} (representing a language code) when there is no region included. * For example: "en" contains no region, "en_US" contains a region (US) * * Used to parse a language code {@link String} when creating a {@link Locale}. */ private static final int NO_REGION_LANG_CODE_LEN = 2; /** * Index of a language code {@link String} where the region code begins. The language code * format is cc_rr, where cc is the country code (e.g. en, es, az) and rr is the region code * (e.g. us, au, gb). */ private static final int REGION_SUBSTRING_INDEX = 3; /** * Gets a preference and sets the {@link android.preference.Preference.OnPreferenceChangeListener}. */ public static Preference getPrefAndSetClickListener(PreferenceFragment prefFrag, int id, Preference.OnPreferenceClickListener listener) { Preference pref = prefFrag.findPreference(prefFrag.getString(id)); if (pref != null) pref.setOnPreferenceClickListener(listener); return pref; } /** * Gets a preference and sets the {@link android.preference.Preference.OnPreferenceChangeListener}. */ public static Preference getPrefAndSetChangeListener(PreferenceFragment prefFrag, int id, Preference.OnPreferenceChangeListener listener) { Preference pref = prefFrag.findPreference(prefFrag.getString(id)); if (pref != null) pref.setOnPreferenceChangeListener(listener); return pref; } /** * Removes a {@link Preference} from the {@link PreferenceCategory} with the given key. */ public static void removePreference(PreferenceFragment prefFrag, int parentKey, int prefKey) { String parentName = prefFrag.getString(parentKey); String prefName = prefFrag.getString(prefKey); PreferenceGroup parent = (PreferenceGroup) prefFrag.findPreference(parentName); Preference child = prefFrag.findPreference(prefName); if (parent != null && child != null) { parent.removePreference(child); } } /** * Styles a {@link TextView} to display a large title against a dark background. */ public static void layoutAsLightTitle(TextView view) { int size = view.getResources().getDimensionPixelSize(R.dimen.text_sz_extra_large); setTextViewAttributes(view, size, R.color.white); } /** * Styles a {@link TextView} to display a large title against a light background. */ public static void layoutAsDarkTitle(TextView view) { int size = view.getResources().getDimensionPixelSize(R.dimen.text_sz_extra_large); setTextViewAttributes(view, size, R.color.grey_dark); } /** * Styles a {@link TextView} to display medium sized text as a header with sub-elements. */ public static void layoutAsSubhead(TextView view) { int color = view.isEnabled() ? R.color.grey_dark : R.color.grey_lighten_10; int size = view.getResources().getDimensionPixelSize(R.dimen.text_sz_large); setTextViewAttributes(view, size, color); } /** * Styles a {@link TextView} to display smaller text. */ public static void layoutAsBody1(TextView view) { int color = view.isEnabled() ? R.color.grey_darken_10 : R.color.grey_lighten_10; int size = view.getResources().getDimensionPixelSize(R.dimen.text_sz_medium); setTextViewAttributes(view, size, color); } /** * Styles a {@link TextView} to display smaller text with a dark grey color. */ public static void layoutAsBody2(TextView view) { int size = view.getResources().getDimensionPixelSize(R.dimen.text_sz_medium); setTextViewAttributes(view, size, R.color.grey_darken_10); } /** * Styles a {@link TextView} to display very small helper text. */ public static void layoutAsCaption(TextView view) { int size = view.getResources().getDimensionPixelSize(R.dimen.text_sz_small); setTextViewAttributes(view, size, R.color.grey_darken_10); } /** * Styles a {@link TextView} to display text in a button. */ public static void layoutAsFlatButton(TextView view) { int size = view.getResources().getDimensionPixelSize(R.dimen.text_sz_medium); setTextViewAttributes(view, size, R.color.blue_medium); } /** * Styles a {@link TextView} to display text in a button. */ public static void layoutAsRaisedButton(TextView view) { int size = view.getResources().getDimensionPixelSize(R.dimen.text_sz_medium); setTextViewAttributes(view, size, R.color.white); } /** * Styles a {@link TextView} to display text in an editable text field. */ public static void layoutAsInput(EditText view) { int size = view.getResources().getDimensionPixelSize(R.dimen.text_sz_large); setTextViewAttributes(view, size, R.color.grey_dark); view.setHintTextColor(view.getResources().getColor(R.color.grey_lighten_10)); view.setTextColor(view.getResources().getColor(R.color.grey_dark)); view.setSingleLine(true); } /** * Styles a {@link TextView} to display selected numbers in a {@link android.widget.NumberPicker}. */ public static void layoutAsNumberPickerSelected(TextView view) { int size = view.getResources().getDimensionPixelSize(R.dimen.text_sz_triple_extra_large); setTextViewAttributes(view, size, R.color.blue_medium); } /** * Styles a {@link TextView} to display non-selected numbers in a {@link android.widget.NumberPicker}. */ public static void layoutAsNumberPickerPeek(TextView view) { int size = view.getResources().getDimensionPixelSize(R.dimen.text_sz_large); setTextViewAttributes(view, size, R.color.grey_dark); } /** * Styles a {@link TextView} to display text in a dialog message. */ public static void layoutAsDialogMessage(TextView view) { int size = view.getResources().getDimensionPixelSize(R.dimen.text_sz_small); setTextViewAttributes(view, size, R.color.grey_darken_10); } public static void setTextViewAttributes(TextView textView, int size, int colorRes) { textView.setTextSize(TypedValue.COMPLEX_UNIT_PX, size); textView.setTextColor(textView.getResources().getColor(colorRes)); } /** * Gets a locale for the given language code. */ public static Locale languageLocale(String languageCode) { if (TextUtils.isEmpty(languageCode)) return LanguageUtils.getCurrentDeviceLanguage(WordPress.getContext()); if (languageCode.length() > NO_REGION_LANG_CODE_LEN) { return new Locale(languageCode.substring(0, NO_REGION_LANG_CODE_LEN), languageCode.substring(REGION_SUBSTRING_INDEX)); } return new Locale(languageCode); } /** * Creates a map from language codes to WordPress language IDs. */ public static Map<String, String> generateLanguageMap(Activity activity) { String[] languageIds = activity.getResources().getStringArray(R.array.lang_ids); String[] languageCodes = activity.getResources().getStringArray(R.array.language_codes); Map<String, String> languageMap = new HashMap<>(); for (int i = 0; i < languageIds.length && i < languageCodes.length; ++i) { languageMap.put(languageCodes[i], languageIds[i]); } return languageMap; } /** * Generates display strings for given language codes. Used as entries in language preference. */ @Nullable public static Pair<String[], String[]> createSortedLanguageDisplayStrings(CharSequence[] languageCodes, Locale locale) { if (languageCodes == null || languageCodes.length < 1) return null; ArrayList<String> entryStrings = new ArrayList<>(languageCodes.length); for (int i = 0; i < languageCodes.length; ++i) { // "__" is used to sort the language code with the display string so both arrays are sorted at the same time entryStrings.add(i, StringUtils.capitalize( getLanguageString(languageCodes[i].toString(), locale)) + "__" + languageCodes[i]); } Collections.sort(entryStrings, Collator.getInstance(locale)); String[] sortedEntries = new String[languageCodes.length]; String[] sortedValues = new String[languageCodes.length]; for (int i = 0; i < entryStrings.size(); ++i) { // now, we can split the sorted array to extract the display string and the language code String[] split = entryStrings.get(i).split("__"); sortedEntries[i] = split[0]; sortedValues[i] = split[1]; } return new Pair<>(sortedEntries, sortedValues); } /** * Generates detail display strings in the currently selected locale. Used as detail text * in language preference dialog. */ @Nullable public static String[] createLanguageDetailDisplayStrings(CharSequence[] languageCodes) { if (languageCodes == null || languageCodes.length < 1) return null; String[] detailStrings = new String[languageCodes.length]; for (int i = 0; i < languageCodes.length; ++i) { detailStrings[i] = StringUtils.capitalize(getLanguageString( languageCodes[i].toString(), WPPrefUtils.languageLocale(languageCodes[i].toString()))); } return detailStrings; } /** * Return a non-null display string for a given language code. */ public static String getLanguageString(String languageCode, Locale displayLocale) { if (languageCode == null || languageCode.length() < 2 || languageCode.length() > 6) { return ""; } Locale languageLocale = WPPrefUtils.languageLocale(languageCode); String displayLanguage = StringUtils.capitalize(languageLocale.getDisplayLanguage(displayLocale)); String displayCountry = languageLocale.getDisplayCountry(displayLocale); if (!TextUtils.isEmpty(displayCountry)) { return displayLanguage + " (" + displayCountry + ")"; } return displayLanguage; } }