blob: 230064f6f6fcb1e7c51fa1b3cb3d0ea13e7ef116 [file] [log] [blame]
package org.wordpress.android.ui.stats;
import android.app.Activity;
import android.content.Context;
import android.graphics.drawable.Drawable;
import android.os.Build;
import android.os.Bundle;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.CheckBox;
import android.widget.CheckedTextView;
import android.widget.ImageView;
import android.widget.LinearLayout;
import android.widget.TextView;
import com.jjoe64.graphview.GraphView;
import com.jjoe64.graphview.GraphViewSeries;
import org.wordpress.android.R;
import org.wordpress.android.WordPress;
import org.wordpress.android.analytics.AnalyticsTracker;
import org.wordpress.android.models.Blog;
import org.wordpress.android.ui.stats.models.VisitModel;
import org.wordpress.android.ui.stats.models.VisitsModel;
import org.wordpress.android.ui.stats.service.StatsService;
import org.wordpress.android.util.AnalyticsUtils;
import org.wordpress.android.util.AppLog;
import org.wordpress.android.util.DisplayUtils;
import org.wordpress.android.util.FormatUtils;
import org.wordpress.android.util.NetworkUtils;
import org.wordpress.android.util.StringUtils;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Calendar;
import java.util.Date;
import java.util.List;
public class StatsVisitorsAndViewsFragment extends StatsAbstractFragment
implements StatsBarGraph.OnGestureListener {
public static final String TAG = StatsVisitorsAndViewsFragment.class.getSimpleName();
private static final String ARG_SELECTED_GRAPH_BAR = "ARG_SELECTED_GRAPH_BAR";
private static final String ARG_PREV_NUMBER_OF_BARS = "ARG_PREV_NUMBER_OF_BARS";
private static final String ARG_SELECTED_OVERVIEW_ITEM = "ARG_SELECTED_OVERVIEW_ITEM";
private static final String ARG_CHECKBOX_SELECTED = "ARG_CHECKBOX_SELECTED";
private LinearLayout mGraphContainer;
private LinearLayout mNoActivtyThisPeriodContainer;
private StatsBarGraph mGraphView;
private LinearLayout mModuleButtonsContainer;
private TextView mDateTextView;
private String[] mStatsDate;
private LinearLayout mLegendContainer;
private CheckedTextView mLegendLabel;
private LinearLayout mVisitorsCheckboxContainer;
private CheckBox mVisitorsCheckbox;
private boolean mIsCheckboxChecked = true;
private OnDateChangeListener mListener;
private OnOverviewItemChangeListener mOverviewItemChangeListener;
private final OverviewLabel[] overviewItems = {OverviewLabel.VIEWS, OverviewLabel.VISITORS, OverviewLabel.LIKES,
OverviewLabel.COMMENTS};
// Restore the following variables on restart
private VisitsModel mVisitsData;
private int mSelectedOverviewItemIndex = 0;
private int mSelectedBarGraphBarIndex = -1;
private int mPrevNumberOfBarsGraph = -1;
// Container Activity must implement this interface
public interface OnDateChangeListener {
void onDateChanged(String blogID, StatsTimeframe timeframe, String newDate);
}
// Container Activity must implement this interface
public interface OnOverviewItemChangeListener {
void onOverviewItemChanged(OverviewLabel newItem);
}
@Override
public void onAttach(Activity activity) {
super.onAttach(activity);
try {
mListener = (OnDateChangeListener) activity;
} catch (ClassCastException e) {
throw new ClassCastException(activity.toString() + " must implement OnDateChangeListener");
}
try {
mOverviewItemChangeListener = (OnOverviewItemChangeListener) activity;
} catch (ClassCastException e) {
throw new ClassCastException(activity.toString() + " must implement OnOverviewItemChangeListener");
}
}
void setSelectedOverviewItem(OverviewLabel itemToSelect) {
for (int i = 0; i < overviewItems.length; i++) {
if (overviewItems[i] == itemToSelect) {
mSelectedOverviewItemIndex = i;
return;
}
}
}
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.stats_visitors_and_views_fragment, container, false);
mDateTextView = (TextView) view.findViewById(R.id.stats_summary_date);
mGraphContainer = (LinearLayout) view.findViewById(R.id.stats_bar_chart_fragment_container);
mModuleButtonsContainer = (LinearLayout) view.findViewById(R.id.stats_pager_tabs);
mNoActivtyThisPeriodContainer = (LinearLayout) view.findViewById(R.id.stats_bar_chart_no_activity);
mLegendContainer = (LinearLayout) view.findViewById(R.id.stats_legend_container);
mLegendLabel = (CheckedTextView) view.findViewById(R.id.stats_legend_label);
mLegendLabel.setCheckMarkDrawable(null); // Make sure to set a null drawable here. Otherwise the touching area is the same of a TextView
mVisitorsCheckboxContainer = (LinearLayout) view.findViewById(R.id.stats_checkbox_visitors_container);
mVisitorsCheckbox = (CheckBox) view.findViewById(R.id.stats_checkbox_visitors);
mVisitorsCheckbox.setOnClickListener(onCheckboxClicked);
// Fix an issue on devices with 4.1 or lower, where the Checkbox already uses padding by default internally and overriding it with paddingLeft
// causes the issue report here https://github.com/wordpress-mobile/WordPress-Android/pull/2377#issuecomment-77067993
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1) {
mVisitorsCheckbox.setPadding(getResources().getDimensionPixelSize(R.dimen.margin_medium), 0, 0, 0);
}
// Make sure we've all the info to build the tab correctly. This is ALWAYS true
if (mModuleButtonsContainer.getChildCount() == overviewItems.length) {
for (int i = 0; i < mModuleButtonsContainer.getChildCount(); i++) {
LinearLayout currentTab = (LinearLayout) mModuleButtonsContainer.getChildAt(i);
boolean isLastItem = i == (overviewItems.length - 1);
boolean isChecked = i == mSelectedOverviewItemIndex;
TabViewHolder currentTabViewHolder = new TabViewHolder(currentTab, overviewItems[i], isChecked, isLastItem);
currentTab.setOnClickListener(TopButtonsOnClickListener);
currentTab.setTag(currentTabViewHolder);
}
mModuleButtonsContainer.setVisibility(View.VISIBLE);
}
return view;
}
private class TabViewHolder {
final LinearLayout tab;
final LinearLayout innerContainer;
final TextView label;
final TextView value;
final ImageView icon;
final OverviewLabel labelItem;
boolean isChecked = false;
boolean isLastItem = false;
public TabViewHolder(LinearLayout currentTab, OverviewLabel labelItem, boolean checked, boolean isLastItem) {
tab = currentTab;
innerContainer = (LinearLayout) currentTab.findViewById(R.id.stats_visitors_and_views_tab_inner_container);
label = (TextView) currentTab.findViewById(R.id.stats_visitors_and_views_tab_label);
label.setText(labelItem.getLabel());
value = (TextView) currentTab.findViewById(R.id.stats_visitors_and_views_tab_value);
icon = (ImageView) currentTab.findViewById(R.id.stats_visitors_and_views_tab_icon);
this.labelItem = labelItem;
this.isChecked = checked;
this.isLastItem = isLastItem;
updateBackGroundAndIcon(0);
}
private Drawable getTabIcon() {
switch (labelItem) {
case VISITORS:
return getResources().getDrawable(R.drawable.stats_icon_visitors);
case COMMENTS:
return getResources().getDrawable(R.drawable.stats_icon_comments);
case LIKES:
return getResources().getDrawable(R.drawable.stats_icon_likes);
default:
// Views and when no prev match
return getResources().getDrawable(R.drawable.stats_icon_views);
}
}
public void updateBackGroundAndIcon(int currentValue) {
if (isChecked) {
value.setTextColor(getResources().getColor(R.color.orange_jazzy));
} else {
if (currentValue == 0) {
value.setTextColor(getResources().getColor(R.color.grey));
} else {
value.setTextColor(getResources().getColor(R.color.blue_wordpress));
}
}
icon.setImageDrawable(getTabIcon());
if (isLastItem) {
if (isChecked) {
tab.setBackgroundResource(R.drawable.stats_visitors_and_views_button_latest_white);
} else {
tab.setBackgroundResource(R.drawable.stats_visitors_and_views_button_latest_blue_light);
}
} else {
if (isChecked) {
tab.setBackgroundResource(R.drawable.stats_visitors_and_views_button_white);
} else {
tab.setBackgroundResource(R.drawable.stats_visitors_and_views_button_blue_light);
}
}
}
public void setChecked(boolean checked) {
this.isChecked = checked;
}
}
private final View.OnClickListener TopButtonsOnClickListener = new View.OnClickListener() {
@Override
public void onClick(View v) {
if (!isAdded()) {
return;
}
//LinearLayout tab = (LinearLayout) v;
TabViewHolder tabViewHolder = (TabViewHolder) v.getTag();
if (tabViewHolder.isChecked) {
// already checked. Do nothing
return;
}
int numberOfTabs = mModuleButtonsContainer.getChildCount();
int checkedId = -1;
for (int i = 0; i < numberOfTabs; i++) {
LinearLayout currentTab = (LinearLayout) mModuleButtonsContainer.getChildAt(i);
TabViewHolder currentTabViewHolder = (TabViewHolder) currentTab.getTag();
if (tabViewHolder == currentTab.getTag()) {
checkedId = i;
currentTabViewHolder.setChecked(true);
} else {
currentTabViewHolder.setChecked(false);
}
}
if (checkedId == -1)
return;
mSelectedOverviewItemIndex = checkedId;
if (mOverviewItemChangeListener != null) {
mOverviewItemChangeListener.onOverviewItemChanged(
overviewItems[mSelectedOverviewItemIndex]
);
}
updateUI();
}
};
private final View.OnClickListener onCheckboxClicked = new View.OnClickListener() {
@Override
public void onClick(View view) {
// Is the view now checked?
mIsCheckboxChecked = ((CheckBox) view).isChecked();
updateUI();
}
};
@Override
protected boolean hasDataAvailable() {
return mVisitsData != null;
}
@Override
protected void saveStatsData(Bundle outState) {
if (hasDataAvailable()) {
outState.putSerializable(ARG_REST_RESPONSE, mVisitsData);
}
outState.putInt(ARG_SELECTED_GRAPH_BAR, mSelectedBarGraphBarIndex);
outState.putInt(ARG_PREV_NUMBER_OF_BARS, mPrevNumberOfBarsGraph);
outState.putInt(ARG_SELECTED_OVERVIEW_ITEM, mSelectedOverviewItemIndex);
outState.putBoolean(ARG_CHECKBOX_SELECTED, mVisitorsCheckbox.isChecked());
}
@Override
protected void restoreStatsData(Bundle savedInstanceState) {
if (savedInstanceState != null) {
if (savedInstanceState.containsKey(ARG_REST_RESPONSE)) {
mVisitsData = (VisitsModel) savedInstanceState.getSerializable(ARG_REST_RESPONSE);
}
if (savedInstanceState.containsKey(ARG_SELECTED_OVERVIEW_ITEM)) {
mSelectedOverviewItemIndex = savedInstanceState.getInt(ARG_SELECTED_OVERVIEW_ITEM, 0);
}
if (savedInstanceState.containsKey(ARG_SELECTED_GRAPH_BAR)) {
mSelectedBarGraphBarIndex = savedInstanceState.getInt(ARG_SELECTED_GRAPH_BAR, -1);
}
if (savedInstanceState.containsKey(ARG_PREV_NUMBER_OF_BARS)) {
mPrevNumberOfBarsGraph = savedInstanceState.getInt(ARG_PREV_NUMBER_OF_BARS, -1);
}
mIsCheckboxChecked = savedInstanceState.getBoolean(ARG_CHECKBOX_SELECTED, true);
}
}
@Override
protected void showErrorUI(String label) {
setupNoResultsUI(false);
}
@Override
protected void showPlaceholderUI() {
setupNoResultsUI(true);
}
private VisitModel[] getDataToShowOnGraph(VisitsModel visitsData) {
List<VisitModel> visitModels = visitsData.getVisits();
int numPoints = Math.min(StatsUIHelper.getNumOfBarsToShow(), visitModels.size());
int currentPointIndex = numPoints - 1;
VisitModel[] visitModelsToShow = new VisitModel[numPoints];
for (int i = visitModels.size() -1; i >= 0 && currentPointIndex >= 0; i--) {
VisitModel currentVisitModel = visitModels.get(i);
visitModelsToShow[currentPointIndex] = currentVisitModel;
currentPointIndex--;
}
return visitModelsToShow;
}
protected void updateUI() {
if (!isAdded()) {
return;
}
if (mVisitsData == null) {
setupNoResultsUI(false);
return;
}
final VisitModel[] dataToShowOnGraph = getDataToShowOnGraph(mVisitsData);
if (dataToShowOnGraph == null || dataToShowOnGraph.length == 0) {
setupNoResultsUI(false);
return;
}
// Hide the "no-activity this period" message
mNoActivtyThisPeriodContainer.setVisibility(View.GONE);
// Read the selected Tab in the UI
OverviewLabel selectedStatsType = overviewItems[mSelectedOverviewItemIndex];
// Update the Legend and enable/disable the visitors checkboxes
mLegendContainer.setVisibility(View.VISIBLE);
mLegendLabel.setText(StringUtils.capitalize(selectedStatsType.getLabel().toLowerCase()));
switch(selectedStatsType) {
case VIEWS:
mVisitorsCheckboxContainer.setVisibility(View.VISIBLE);
mVisitorsCheckbox.setEnabled(true);
mVisitorsCheckbox.setChecked(mIsCheckboxChecked);
break;
default:
mVisitorsCheckboxContainer.setVisibility(View.GONE);
break;
}
// Setting Up labels and prepare variables that hold series
final String[] horLabels = new String[dataToShowOnGraph.length];
mStatsDate = new String[dataToShowOnGraph.length];
GraphView.GraphViewData[] mainSeriesItems = new GraphView.GraphViewData[dataToShowOnGraph.length];
GraphView.GraphViewData[] secondarySeriesItems = null;
if (mIsCheckboxChecked && selectedStatsType == OverviewLabel.VIEWS) {
secondarySeriesItems = new GraphView.GraphViewData[dataToShowOnGraph.length];
}
// index of days that should be XXX on the graph
final boolean[] weekendDays;
if (getTimeframe() == StatsTimeframe.DAY) {
weekendDays = new boolean[dataToShowOnGraph.length];
} else {
weekendDays = null;
}
// Check we have at least one result in the current section.
boolean atLeastOneResultIsAvailable = false;
// Fill series variables with data
for (int i = 0; i < dataToShowOnGraph.length; i++) {
int currentItemValue = 0;
switch(selectedStatsType) {
case VIEWS:
currentItemValue = dataToShowOnGraph[i].getViews();
break;
case VISITORS:
currentItemValue = dataToShowOnGraph[i].getVisitors();
break;
case LIKES:
currentItemValue = dataToShowOnGraph[i].getLikes();
break;
case COMMENTS:
currentItemValue = dataToShowOnGraph[i].getComments();
break;
}
mainSeriesItems[i] = new GraphView.GraphViewData(i, currentItemValue);
if (currentItemValue > 0) {
atLeastOneResultIsAvailable = true;
}
if (mIsCheckboxChecked && secondarySeriesItems != null) {
secondarySeriesItems[i] = new GraphView.GraphViewData(i, dataToShowOnGraph[i].getVisitors());
}
String currentItemStatsDate = dataToShowOnGraph[i].getPeriod();
horLabels[i] = getDateLabelForBarInGraph(currentItemStatsDate);
mStatsDate[i] = currentItemStatsDate;
if (weekendDays != null) {
SimpleDateFormat from = new SimpleDateFormat(StatsConstants.STATS_INPUT_DATE_FORMAT);
try {
Date date = from.parse(currentItemStatsDate);
Calendar c = Calendar.getInstance();
c.setFirstDayOfWeek(Calendar.MONDAY);
c.setTimeInMillis(date.getTime());
weekendDays[i] = c.get(Calendar.DAY_OF_WEEK) == Calendar.SUNDAY || c.get(Calendar.DAY_OF_WEEK) == Calendar.SATURDAY;
} catch (ParseException e) {
weekendDays[i] = false;
AppLog.e(AppLog.T.STATS, e);
}
}
}
if (mGraphContainer.getChildCount() >= 1 && mGraphContainer.getChildAt(0) instanceof GraphView) {
mGraphView = (StatsBarGraph) mGraphContainer.getChildAt(0);
} else {
mGraphContainer.removeAllViews();
mGraphView = new StatsBarGraph(getActivity());
mGraphContainer.addView(mGraphView);
}
mGraphView.removeAllSeries();
GraphViewSeries mainSeriesOnScreen = new GraphViewSeries(mainSeriesItems);
mainSeriesOnScreen.getStyle().color = getResources().getColor(R.color.stats_bar_graph_main_series);
mainSeriesOnScreen.getStyle().outerColor = getResources().getColor(R.color.translucent_grey_lighten_30);
mainSeriesOnScreen.getStyle().highlightColor = getResources().getColor(R.color.stats_bar_graph_main_series_highlight);
mainSeriesOnScreen.getStyle().outerhighlightColor = getResources().getColor(R.color.stats_bar_graph_outer_highlight);
mainSeriesOnScreen.getStyle().padding = DisplayUtils.dpToPx(getActivity(), 5);
mGraphView.addSeries(mainSeriesOnScreen);
// Add the Visitors series if it's checked in the legend
if (mIsCheckboxChecked && secondarySeriesItems != null && selectedStatsType == OverviewLabel.VIEWS) {
GraphViewSeries secondarySeries = new GraphViewSeries(secondarySeriesItems);
secondarySeries.getStyle().padding = DisplayUtils.dpToPx(getActivity(), 10);
secondarySeries.getStyle().color = getResources().getColor(R.color.stats_bar_graph_secondary_series);
secondarySeries.getStyle().highlightColor = getResources().getColor(R.color.orange_fire);
mGraphView.addSeries(secondarySeries);
}
// Setup the Y-axis on Visitors and Views Tabs.
// Views and Visitors tabs have the exact same Y-axis as shifting from one Y-axis to another defeats
// the purpose of making these bars visually easily to compare.
switch(selectedStatsType) {
case VISITORS:
double maxYValue = getMaxYValueForVisitorsAndView(dataToShowOnGraph);
mGraphView.setManualYAxisBounds(maxYValue, 0d);
break;
default:
mGraphView.setManualYAxis(false);
break;
}
// Set the Graph Style
mGraphView.getGraphViewStyle().setNumHorizontalLabels(dataToShowOnGraph.length);
// Set the maximum size a column can get on the screen in PX
mGraphView.getGraphViewStyle().setMaxColumnWidth(
DisplayUtils.dpToPx(getActivity(), StatsConstants.STATS_GRAPH_BAR_MAX_COLUMN_WIDTH_DP)
);
mGraphView.setHorizontalLabels(horLabels);
mGraphView.setGestureListener(this);
// If zero results in the current section disable clicks on the graph and show the dialog.
mNoActivtyThisPeriodContainer.setVisibility(atLeastOneResultIsAvailable ? View.GONE : View.VISIBLE);
mGraphView.setClickable(atLeastOneResultIsAvailable);
// Draw the background on weekend days
mGraphView.setWeekendDays(weekendDays);
// Reset the bar selected upon rotation of the device when the no. of bars can change with orientation.
// Only happens on 720DP tablets
if (mPrevNumberOfBarsGraph != -1 && mPrevNumberOfBarsGraph != dataToShowOnGraph.length) {
mSelectedBarGraphBarIndex = -1;
mPrevNumberOfBarsGraph = dataToShowOnGraph.length;
onBarTapped(dataToShowOnGraph.length - 1);
mGraphView.highlightBar(dataToShowOnGraph.length - 1);
return;
}
mPrevNumberOfBarsGraph = dataToShowOnGraph.length;
int barSelectedOnGraph;
if (mSelectedBarGraphBarIndex == -1) {
// No previous bar was highlighted, highlight the most recent one
barSelectedOnGraph = dataToShowOnGraph.length - 1;
} else if (mSelectedBarGraphBarIndex < dataToShowOnGraph.length) {
barSelectedOnGraph = mSelectedBarGraphBarIndex;
} else {
// A previous bar was highlighted, but it's out of the screen now. This should never happen atm.
barSelectedOnGraph = dataToShowOnGraph.length - 1;
mSelectedBarGraphBarIndex = barSelectedOnGraph;
}
updateUIBelowTheGraph(barSelectedOnGraph);
mGraphView.highlightBar(barSelectedOnGraph);
}
// Find the max value in Visitors and Views data.
// Only checks the Views data, since Visitors is for sure less-equals than Views.
private double getMaxYValueForVisitorsAndView(final VisitModel[] dataToShowOnGraph) {
if (dataToShowOnGraph == null || dataToShowOnGraph.length == 0) {
return 0d;
}
double largest = Integer.MIN_VALUE;
for (VisitModel aDataToShowOnGraph : dataToShowOnGraph) {
int currentItemValue = aDataToShowOnGraph.getViews();
if (currentItemValue > largest) {
largest = currentItemValue;
}
}
return largest;
}
//update the area right below the graph
private void updateUIBelowTheGraph(int itemPosition) {
if (!isAdded()) {
return;
}
if (mVisitsData == null) {
setupNoResultsUI(false);
return;
}
final VisitModel[] dataToShowOnGraph = getDataToShowOnGraph(mVisitsData);
// Make sure we've data to show on the screen
if (dataToShowOnGraph.length == 0) {
return;
}
// This check should never be true, since we put a check on the index in the calling function updateUI()
if (dataToShowOnGraph.length <= itemPosition || itemPosition == -1) {
// Make sure we're not highlighting
itemPosition = dataToShowOnGraph.length -1;
}
String date = mStatsDate[itemPosition];
if (date == null) {
AppLog.w(AppLog.T.STATS, "Cannot update the area below the graph if a null date is passed!!");
return;
}
mDateTextView.setText(getDateForDisplayInLabels(date, getTimeframe()));
VisitModel modelTapped = dataToShowOnGraph[itemPosition];
for (int i=0 ; i < mModuleButtonsContainer.getChildCount(); i++) {
View o = mModuleButtonsContainer.getChildAt(i);
if (o instanceof LinearLayout && o.getTag() instanceof TabViewHolder) {
TabViewHolder tabViewHolder = (TabViewHolder)o.getTag();
int currentValue = 0;
switch (tabViewHolder.labelItem) {
case VIEWS:
currentValue = modelTapped.getViews();
break;
case VISITORS:
currentValue = modelTapped.getVisitors();
break;
case LIKES:
currentValue = modelTapped.getLikes();
break;
case COMMENTS:
currentValue = modelTapped.getComments();
break;
}
tabViewHolder.value.setText(FormatUtils.formatDecimal(currentValue));
tabViewHolder.updateBackGroundAndIcon(currentValue);
}
}
}
private String getDateForDisplayInLabels(String date, StatsTimeframe timeframe) {
String prefix = getString(R.string.stats_for);
switch (timeframe) {
case DAY:
return String.format(prefix, StatsUtils.parseDate(date, StatsConstants.STATS_INPUT_DATE_FORMAT, StatsConstants.STATS_OUTPUT_DATE_MONTH_LONG_DAY_SHORT_FORMAT));
case WEEK:
try {
SimpleDateFormat sdf;
Calendar c;
final Date parsedDate;
// Used in bar graph
// first four digits are the year
// followed by Wxx where xx is the month
// followed by Wxx where xx is the day of the month
// ex: 2013W07W22 = July 22, 2013
sdf = new SimpleDateFormat("yyyy'W'MM'W'dd");
//Calculate the end of the week
parsedDate = sdf.parse(date);
c = Calendar.getInstance();
c.setFirstDayOfWeek(Calendar.MONDAY);
c.setTime(parsedDate);
// first day of this week
c.set(Calendar.DAY_OF_WEEK, Calendar.MONDAY );
String startDateLabel = StatsUtils.msToString(c.getTimeInMillis(), StatsConstants.STATS_OUTPUT_DATE_MONTH_LONG_DAY_LONG_FORMAT);
// last day of this week
c.add(Calendar.DAY_OF_WEEK, + 6);
String endDateLabel = StatsUtils.msToString(c.getTimeInMillis(), StatsConstants.STATS_OUTPUT_DATE_MONTH_LONG_DAY_LONG_FORMAT);
return String.format(prefix, startDateLabel + " - " + endDateLabel);
} catch (ParseException e) {
AppLog.e(AppLog.T.UTILS, e);
return "";
}
case MONTH:
return String.format(prefix, StatsUtils.parseDate(date, StatsConstants.STATS_INPUT_DATE_FORMAT, StatsConstants.STATS_OUTPUT_DATE_MONTH_LONG_FORMAT));
case YEAR:
return String.format(prefix, StatsUtils.parseDate(date, StatsConstants.STATS_INPUT_DATE_FORMAT, StatsConstants.STATS_OUTPUT_DATE_YEAR_FORMAT));
}
return "";
}
/**
* Return the date string that is displayed under each bar in the graph
*/
private String getDateLabelForBarInGraph(String dateToFormat) {
switch (getTimeframe()) {
case DAY:
return StatsUtils.parseDate(
dateToFormat,
StatsConstants.STATS_INPUT_DATE_FORMAT,
StatsConstants.STATS_OUTPUT_DATE_MONTH_SHORT_DAY_SHORT_FORMAT
);
case WEEK:
// first four digits are the year
// followed by Wxx where xx is the month
// followed by Wxx where xx is the day of the month
// ex: 2013W07W22 = July 22, 2013
return StatsUtils.parseDate(dateToFormat, "yyyy'W'MM'W'dd", StatsConstants.STATS_OUTPUT_DATE_MONTH_SHORT_DAY_SHORT_FORMAT);
case MONTH:
return StatsUtils.parseDate(dateToFormat, "yyyy-MM", "MMM");
case YEAR:
return StatsUtils.parseDate(dateToFormat, StatsConstants.STATS_INPUT_DATE_FORMAT, StatsConstants.STATS_OUTPUT_DATE_YEAR_FORMAT);
default:
return dateToFormat;
}
}
private void setupNoResultsUI(boolean isLoading) {
if (!isAdded()) {
return;
}
// Hide the legend
mLegendContainer.setVisibility(View.GONE);
mVisitorsCheckboxContainer.setVisibility(View.GONE);
mSelectedBarGraphBarIndex = -1;
Context context = mGraphContainer.getContext();
if (context != null) {
LayoutInflater inflater = LayoutInflater.from(context);
View emptyBarGraphView = inflater.inflate(R.layout.stats_bar_graph_empty, mGraphContainer, false);
final TextView emptyLabel = (TextView) emptyBarGraphView.findViewById(R.id.stats_bar_graph_empty_label);
emptyLabel.setText("");
if (!isLoading) {
mNoActivtyThisPeriodContainer.setVisibility(View.VISIBLE);
}
if (emptyBarGraphView != null) {
mGraphContainer.removeAllViews();
mGraphContainer.addView(emptyBarGraphView);
}
}
mDateTextView.setText("");
for (int i=0 ; i < mModuleButtonsContainer.getChildCount(); i++) {
View o = mModuleButtonsContainer.getChildAt(i);
if (o instanceof CheckedTextView) {
CheckedTextView currentBtm = (CheckedTextView)o;
OverviewLabel overviewItem = (OverviewLabel)currentBtm.getTag();
String labelPrefix = overviewItem.getLabel() + "\n 0" ;
currentBtm.setText(labelPrefix);
}
}
}
@Override
protected String getTitle() {
return getString(R.string.stats_view_visitors_and_views);
}
@SuppressWarnings("unused")
public void onEventMainThread(StatsEvents.VisitorsAndViewsUpdated event) {
if (!shouldUpdateFragmentOnUpdateEvent(event)) {
return;
}
mVisitsData = event.mVisitsAndViews;
mSelectedBarGraphBarIndex = -1;
// Reset the bar to highlight
if (mGraphView != null) {
mGraphView.resetHighlightBar();
}
updateUI();
}
@SuppressWarnings("unused")
public void onEventMainThread(StatsEvents.SectionUpdateError event) {
if (!shouldUpdateFragmentOnErrorEvent(event)) {
return;
}
mVisitsData = null;
mSelectedBarGraphBarIndex = -1;
// Reset the bar to highlight
if (mGraphView != null) {
mGraphView.resetHighlightBar();
}
updateUI();
}
@Override
public void onBarTapped(int tappedBar) {
if (!isAdded()) {
return;
}
//AppLog.d(AppLog.T.STATS, " Tapped bar date " + mStatsDate[tappedBar]);
mSelectedBarGraphBarIndex = tappedBar;
updateUIBelowTheGraph(tappedBar);
if (!NetworkUtils.checkConnection(getActivity())) {
return;
}
// Update Stats here
String date = mStatsDate[tappedBar];
if (date == null) {
AppLog.w(AppLog.T.STATS, "A bar was tapped but a null date is received!!");
return;
}
//Calculate the correct end date for the selected period
String calculatedDate = null;
try {
SimpleDateFormat sdf;
Calendar c = Calendar.getInstance();
c.setFirstDayOfWeek(Calendar.MONDAY);
final Date parsedDate;
switch (getTimeframe()) {
case DAY:
calculatedDate = date;
break;
case WEEK:
// first four digits are the year
// followed by Wxx where xx is the month
// followed by Wxx where xx is the day of the month
// ex: 2013W07W22 = July 22, 2013
sdf = new SimpleDateFormat("yyyy'W'MM'W'dd");
//Calculate the end of the week
parsedDate = sdf.parse(date);
c.setTime(parsedDate);
// first day of this week
c.set(Calendar.DAY_OF_WEEK, Calendar.MONDAY);
// last day of this week
c.add(Calendar.DAY_OF_WEEK, +6);
calculatedDate = StatsUtils.msToString(c.getTimeInMillis(), StatsConstants.STATS_INPUT_DATE_FORMAT);
break;
case MONTH:
sdf = new SimpleDateFormat("yyyy-MM");
//Calculate the end of the month
parsedDate = sdf.parse(date);
c.setTime(parsedDate);
// last day of this month
c.set(Calendar.DAY_OF_MONTH, c.getActualMaximum(Calendar.DAY_OF_MONTH));
calculatedDate = StatsUtils.msToString(c.getTimeInMillis(), StatsConstants.STATS_INPUT_DATE_FORMAT);
break;
case YEAR:
sdf = new SimpleDateFormat(StatsConstants.STATS_INPUT_DATE_FORMAT);
//Calculate the end of the week
parsedDate = sdf.parse(date);
c.setTime(parsedDate);
c.set(Calendar.MONTH, Calendar.DECEMBER);
c.set(Calendar.DAY_OF_MONTH, 31);
calculatedDate = StatsUtils.msToString(c.getTimeInMillis(), StatsConstants.STATS_INPUT_DATE_FORMAT);
break;
}
} catch (ParseException e) {
AppLog.e(AppLog.T.UTILS, e);
}
if (calculatedDate == null) {
AppLog.w(AppLog.T.STATS, "A call to request new stats stats is made but date received cannot be parsed!! " + date);
return;
}
// Update the data below the graph
if (mListener!= null) {
// Should never be null
final Blog currentBlog = WordPress.getBlog(getLocalTableBlogID());
if (currentBlog != null && currentBlog.getDotComBlogId() != null) {
mListener.onDateChanged(currentBlog.getDotComBlogId(), getTimeframe(), calculatedDate);
}
}
AnalyticsUtils.trackWithBlogDetails(
AnalyticsTracker.Stat.STATS_TAPPED_BAR_CHART,
WordPress.getBlog(getLocalTableBlogID())
);
}
public enum OverviewLabel {
VIEWS(R.string.stats_views),
VISITORS(R.string.stats_visitors),
LIKES(R.string.stats_likes),
COMMENTS(R.string.stats_comments),
;
private final int mLabelResId;
OverviewLabel(int labelResId) {
mLabelResId = labelResId;
}
public String getLabel() {
return WordPress.getContext().getString(mLabelResId).toUpperCase();
}
}
@Override
protected StatsService.StatsEndpointsEnum[] sectionsToUpdate() {
return new StatsService.StatsEndpointsEnum[]{
StatsService.StatsEndpointsEnum.VISITS
};
}
}