// Copyright 2014 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
package org.chromium.chrome.browser.dom_distiller;
import android.content.Context;
import android.graphics.Typeface;
import android.support.v7.app.AlertDialog;
import android.util.AttributeSet;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.AdapterView;
import android.widget.AdapterView.OnItemSelectedListener;
import android.widget.ArrayAdapter;
import android.widget.LinearLayout;
import android.widget.RadioButton;
import android.widget.RadioGroup;
import android.widget.SeekBar;
import android.widget.Spinner;
import android.widget.TextView;
import org.chromium.chrome.R;
import org.chromium.chrome.browser.profiles.Profile;
import org.chromium.components.dom_distiller.core.DistilledPagePrefs;
import org.chromium.components.dom_distiller.core.FontFamily;
import org.chromium.components.dom_distiller.core.Theme;
import java.text.NumberFormat;
import java.util.EnumMap;
import java.util.Locale;
import java.util.Map;
/**
* A view which displays preferences for distilled pages. This allows users
* to change the theme, font size, etc. of distilled pages.
*/
public class DistilledPagePrefsView extends LinearLayout
implements DistilledPagePrefs.Observer, SeekBar.OnSeekBarChangeListener {
// XML layout for View.
private static final int VIEW_LAYOUT = R.layout.distilled_page_prefs_view;
// RadioGroup for color mode buttons.
private RadioGroup mRadioGroup;
// Buttons for color mode.
private final Map<Theme, RadioButton> mColorModeButtons;
private final DistilledPagePrefs mDistilledPagePrefs;
// Text field showing font scale percentage.
private TextView mFontScaleTextView;
// SeekBar for font scale. Has range of [0, 30].
private SeekBar mFontScaleSeekBar;
// Spinner for choosing a font family.
private Spinner mFontFamilySpinner;
private final NumberFormat mPercentageFormatter;
/**
* Creates a DistilledPagePrefsView.
*
* @param context Context for acquiring resources.
* @param attrs Attributes from the XML layout inflation.
*/
public DistilledPagePrefsView(Context context, AttributeSet attrs) {
super(context, attrs);
mDistilledPagePrefs = DomDistillerServiceFactory.getForProfile(
Profile.getLastUsedProfile()).getDistilledPagePrefs();
mColorModeButtons = new EnumMap<Theme, RadioButton>(Theme.class);
mPercentageFormatter = NumberFormat.getPercentInstance(Locale.getDefault());
}
public static DistilledPagePrefsView create(Context context) {
return (DistilledPagePrefsView) LayoutInflater.from(context)
.inflate(VIEW_LAYOUT, null);
}
public static void showDialog(Context context) {
AlertDialog.Builder builder = new AlertDialog.Builder(context, R.style.AlertDialogTheme);
builder.setView(DistilledPagePrefsView.create(context));
builder.show();
}
@Override
public void onFinishInflate() {
super.onFinishInflate();
mRadioGroup = (RadioGroup) findViewById(R.id.radio_button_group);
mColorModeButtons.put(Theme.LIGHT,
initializeAndGetButton(R.id.light_mode, Theme.LIGHT));
mColorModeButtons.put(Theme.DARK,
initializeAndGetButton(R.id.dark_mode, Theme.DARK));
mColorModeButtons.put(Theme.SEPIA,
initializeAndGetButton(R.id.sepia_mode, Theme.SEPIA));
mColorModeButtons.get(mDistilledPagePrefs.getTheme()).setChecked(true);
mFontScaleSeekBar = (SeekBar) findViewById(R.id.font_size);
mFontScaleTextView = (TextView) findViewById(R.id.font_size_percentage);
mFontFamilySpinner = (Spinner) findViewById(R.id.font_family);
initFontFamilySpinner();
// Setting initial progress on font scale seekbar.
onChangeFontScaling(mDistilledPagePrefs.getFontScaling());
mFontScaleSeekBar.setOnSeekBarChangeListener(this);
}
private void initFontFamilySpinner() {
ArrayAdapter<CharSequence> adapter = new ArrayAdapter<CharSequence>(getContext(),
android.R.layout.simple_spinner_item, getResources().getStringArray(
R.array.distiller_mode_font_family_values)) {
@Override
public View getView(int position, View convertView, ViewGroup parent) {
View view = super.getView(position, convertView, parent);
return overrideTypeFace(view, position);
}
@Override
public View getDropDownView(int position, View convertView, ViewGroup parent) {
View view = super.getDropDownView(position, convertView, parent);
return overrideTypeFace(view, position);
}
private View overrideTypeFace(View view, int position) {
if (view instanceof TextView) {
TextView textView = (TextView) view;
FontFamily family = FontFamily.values()[position];
if (family == FontFamily.MONOSPACE) {
textView.setTypeface(Typeface.MONOSPACE);
} else if (family == FontFamily.SANS_SERIF) {
textView.setTypeface(Typeface.SANS_SERIF);
} else if (family == FontFamily.SERIF) {
textView.setTypeface(Typeface.SERIF);
}
}
return view;
}
};
adapter.setDropDownViewResource(R.layout.distilled_page_font_family_spinner);
mFontFamilySpinner.setAdapter(adapter);
mFontFamilySpinner.setSelection(mDistilledPagePrefs.getFontFamily().ordinal());
mFontFamilySpinner.setOnItemSelectedListener(new OnItemSelectedListener() {
@Override
public void onItemSelected(AdapterView<?> parent, View view, int position, long id) {
FontFamily family = FontFamily.getFontFamilyForValue(position);
if (family != null) {
mDistilledPagePrefs.setFontFamily(family);
}
}
@Override
public void onNothingSelected(AdapterView<?> parent) {
// Nothing to do.
}
});
}
@Override
public void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
mRadioGroup.setOrientation(HORIZONTAL);
for (RadioButton button : mColorModeButtons.values()) {
ViewGroup.LayoutParams layoutParams = button.getLayoutParams();
layoutParams.width = 0;
}
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
// If text is wider than button, change layout so that buttons are stacked on
// top of each other.
for (RadioButton button : mColorModeButtons.values()) {
if (button.getLineCount() > 1) {
mRadioGroup.setOrientation(VERTICAL);
for (RadioButton innerLoopButton : mColorModeButtons.values()) {
ViewGroup.LayoutParams layoutParams = innerLoopButton.getLayoutParams();
layoutParams.width = LayoutParams.MATCH_PARENT;
}
break;
}
}
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
}
@Override
public void onAttachedToWindow() {
super.onAttachedToWindow();
mDistilledPagePrefs.addObserver(this);
}
@Override
public void onDetachedFromWindow() {
super.onDetachedFromWindow();
mDistilledPagePrefs.removeObserver(this);
}
// DistilledPagePrefs.Observer
@Override
public void onChangeFontFamily(FontFamily fontFamily) {
mFontFamilySpinner.setSelection(fontFamily.ordinal());
}
/**
* Changes which button is selected if the theme is changed in another tab.
*/
@Override
public void onChangeTheme(Theme theme) {
mColorModeButtons.get(theme).setChecked(true);
}
@Override
public void onChangeFontScaling(float scaling) {
setFontScaleTextView(scaling);
setFontScaleProgress(scaling);
}
// SeekBar.OnSeekBarChangeListener
@Override
public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) {
// progress = [0, 30]
// newValue = .50, .55, .60, ..., 1.95, 2.00 (supported font scales)
float newValue = (progress / 20f + .5f);
setFontScaleTextView(newValue);
if (fromUser) {
mDistilledPagePrefs.setFontScaling(newValue);
}
}
@Override
public void onStartTrackingTouch(SeekBar seekBar) {}
@Override
public void onStopTrackingTouch(SeekBar seekBar) {}
/**
* Initiatializes a Button and selects it if it corresponds to the current
* theme.
*/
private RadioButton initializeAndGetButton(int id, final Theme theme) {
final RadioButton button = (RadioButton) findViewById(id);
button.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
mDistilledPagePrefs.setTheme(theme);
}
});
return button;
}
/**
* Sets the progress of mFontScaleSeekBar.
*/
private void setFontScaleProgress(float newValue) {
// newValue = .50, .55, .60, ..., 1.95, 2.00 (supported font scales)
// progress = [0, 30]
int progress = (int) Math.round((newValue - .5) * 20);
mFontScaleSeekBar.setProgress(progress);
}
/**
* Sets the text for the font scale text view.
*/
private void setFontScaleTextView(float newValue) {
mFontScaleTextView.setText(mPercentageFormatter.format(newValue));
}
}