diff options
author | Maxime Biais <maxime.biais@gmail.com> | 2015-03-05 10:30:08 +0100 |
---|---|---|
committer | Maxime Biais <maxime.biais@gmail.com> | 2015-03-05 10:30:08 +0100 |
commit | e062faec6a63223494bf4ef21a1bf438f1036a7f (patch) | |
tree | 54177c80c1a1aa2380f95f19836d4f0c6d6c2897 /WordPress/src/main/java/org/wordpress | |
parent | 38c196a37ff236713d75060d9d0d5185302a4447 (diff) | |
parent | 2c6eb865f4aeefabdd0a7f66a058fe3f6e400829 (diff) | |
download | gradle-perf-android-medium-e062faec6a63223494bf4ef21a1bf438f1036a7f.tar.gz |
Merge branch 'develop' into update/color-values
Diffstat (limited to 'WordPress/src/main/java/org/wordpress')
17 files changed, 244 insertions, 103 deletions
diff --git a/WordPress/src/main/java/org/wordpress/android/datasets/ReaderPostTable.java b/WordPress/src/main/java/org/wordpress/android/datasets/ReaderPostTable.java index 0a1231c81..e9ea6801d 100644 --- a/WordPress/src/main/java/org/wordpress/android/datasets/ReaderPostTable.java +++ b/WordPress/src/main/java/org/wordpress/android/datasets/ReaderPostTable.java @@ -383,6 +383,20 @@ public class ReaderPostTable { } /* + * returns the id of the newest post with the passed tag + */ + public static long getNewestPostIdWithTag(final ReaderTag tag) { + if (tag == null) { + return 0; + } + String sql = "SELECT tbl_posts.post_id FROM tbl_posts, tbl_post_tags" + + " WHERE tbl_posts.post_id = tbl_post_tags.post_id AND tbl_posts.blog_id = tbl_post_tags.blog_id" + + " AND tbl_post_tags.tag_name=? AND tbl_post_tags.tag_type=?" + + " ORDER BY published DESC LIMIT 1"; + String[] args = {tag.getTagName(), Integer.toString(tag.tagType.toInt())}; + return SqlUtils.longForQuery(ReaderDatabase.getReadableDb(), sql, args); + } + /* * returns the iso8601 published date of the oldest post with the passed tag */ public static String getOldestPubDateWithTag(final ReaderTag tag) { diff --git a/WordPress/src/main/java/org/wordpress/android/ui/WPDrawerActivity.java b/WordPress/src/main/java/org/wordpress/android/ui/WPDrawerActivity.java index aae0b5572..9e0223864 100644 --- a/WordPress/src/main/java/org/wordpress/android/ui/WPDrawerActivity.java +++ b/WordPress/src/main/java/org/wordpress/android/ui/WPDrawerActivity.java @@ -57,6 +57,7 @@ import org.wordpress.android.util.WPActivityUtils; import org.xmlrpc.android.ApiHelper; import org.xmlrpc.android.ApiHelper.ErrorType; +import java.util.IllegalFormatCodePointException; import java.util.List; import java.util.Map; @@ -291,7 +292,13 @@ public abstract class WPDrawerActivity extends ActionBarActivity { FragmentManager fm = getFragmentManager(); if (fm.getBackStackEntryCount() > 0) { - fm.popBackStack(); + try { + fm.popBackStack(); + } catch (IllegalStateException e) { + // onClick event can be fired after the onSaveInstanceState call, + // and make the app crash. Catching this exception avoid the crash. If this existed, + // we would use popBackStackAllowingStateLoss. + } } else if (isStaticMenuDrawer()) { finish(); } else { diff --git a/WordPress/src/main/java/org/wordpress/android/ui/reader/ReaderCommentListActivity.java b/WordPress/src/main/java/org/wordpress/android/ui/reader/ReaderCommentListActivity.java index 78cc71e6d..3c963979d 100644 --- a/WordPress/src/main/java/org/wordpress/android/ui/reader/ReaderCommentListActivity.java +++ b/WordPress/src/main/java/org/wordpress/android/ui/reader/ReaderCommentListActivity.java @@ -71,6 +71,7 @@ public class ReaderCommentListActivity extends ActionBarActivity { private boolean mIsUpdatingComments; private boolean mHasUpdatedComments; + private boolean mIsSubmittingComment; private long mReplyToCommentId; private int mRestorePosition; @@ -358,7 +359,9 @@ public class ReaderCommentListActivity extends ActionBarActivity { private void checkEmptyView() { TextView txtEmpty = (TextView) findViewById(R.id.text_empty); - boolean isEmpty = hasCommentAdapter() && getCommentAdapter().isEmpty(); + boolean isEmpty = hasCommentAdapter() + && getCommentAdapter().isEmpty() + && !mIsSubmittingComment; if (isEmpty && !NetworkUtils.isNetworkAvailable(this)) { txtEmpty.setText(R.string.no_network_message); txtEmpty.setVisibility(View.VISIBLE); @@ -406,6 +409,7 @@ public class ReaderCommentListActivity extends ActionBarActivity { mImgSubmitComment.setEnabled(false); mEditComment.setEnabled(false); + mIsSubmittingComment = true; // generate a "fake" comment id to assign to the new comment so we can add it to the db // and reflect it in the adapter before the API call returns @@ -417,6 +421,7 @@ public class ReaderCommentListActivity extends ActionBarActivity { if (isFinishing()) { return; } + mIsSubmittingComment = false; mImgSubmitComment.setEnabled(true); mEditComment.setEnabled(true); if (succeeded) { @@ -431,6 +436,7 @@ public class ReaderCommentListActivity extends ActionBarActivity { ToastUtils.showToast( ReaderCommentListActivity.this, R.string.reader_toast_err_comment_failed, ToastUtils.Duration.LONG); } + checkEmptyView(); } }; @@ -449,6 +455,7 @@ public class ReaderCommentListActivity extends ActionBarActivity { getCommentAdapter().addComment(newComment); // make sure it's scrolled into view scrollToCommentId(fakeCommentId); + checkEmptyView(); } } diff --git a/WordPress/src/main/java/org/wordpress/android/ui/reader/ReaderPostListFragment.java b/WordPress/src/main/java/org/wordpress/android/ui/reader/ReaderPostListFragment.java index f5790086b..8b04df9eb 100644 --- a/WordPress/src/main/java/org/wordpress/android/ui/reader/ReaderPostListFragment.java +++ b/WordPress/src/main/java/org/wordpress/android/ui/reader/ReaderPostListFragment.java @@ -999,10 +999,26 @@ public class ReaderPostListFragment extends Fragment return; } + // show "new posts" bar if new posts were downloaded in a followed tag and the adapter + // isn't empty (if it's empty, we want to display the new posts immediately) + boolean showNewPostsBar; if (event.getResult() == ReaderActions.UpdateResult.HAS_NEW && !isPostAdapterEmpty() && event.getAction() == UpdateAction.REQUEST_NEWER && getPostListType() == ReaderPostListType.TAG_FOLLOWED) { + // make sure that these new posts will actually appear at the top of the list - we + // don't want to show "new posts" if the new posts are older ones since the user + // expects to see the new posts at the top of the list. we do this by getting the + // id of the newest post in the database (which will contain the newly downloaded + // posts) and comparing it to the id of the first post in the adapter + long newestPostId = ReaderPostTable.getNewestPostIdWithTag(getCurrentTag()); + ReaderPost post = getPostAdapter().getItem(0); + showNewPostsBar = (post != null && post.postId != newestPostId); + } else { + showNewPostsBar = false; + } + + if (showNewPostsBar) { showNewPostsBar(); refreshPosts(); } else if (event.getResult().isNewOrChanged()) { diff --git a/WordPress/src/main/java/org/wordpress/android/ui/reader/adapters/ReaderPostAdapter.java b/WordPress/src/main/java/org/wordpress/android/ui/reader/adapters/ReaderPostAdapter.java index b57517eb8..6ad8c2722 100644 --- a/WordPress/src/main/java/org/wordpress/android/ui/reader/adapters/ReaderPostAdapter.java +++ b/WordPress/src/main/java/org/wordpress/android/ui/reader/adapters/ReaderPostAdapter.java @@ -450,7 +450,7 @@ public class ReaderPostAdapter extends RecyclerView.Adapter<ReaderPostAdapter.Re new LoadPostsTask().executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR); } - ReaderPost getItem(int position) { + public ReaderPost getItem(int position) { if (isValidPosition(position)) { return mPosts.get(position); } else { diff --git a/WordPress/src/main/java/org/wordpress/android/ui/stats/StatsActivity.java b/WordPress/src/main/java/org/wordpress/android/ui/stats/StatsActivity.java index cb51da028..090fbae97 100644 --- a/WordPress/src/main/java/org/wordpress/android/ui/stats/StatsActivity.java +++ b/WordPress/src/main/java/org/wordpress/android/ui/stats/StatsActivity.java @@ -47,9 +47,9 @@ import org.wordpress.android.util.RateLimitedTask; import org.wordpress.android.util.StringUtils; import org.wordpress.android.util.ToastUtils; import org.wordpress.android.util.ToastUtils.Duration; +import org.wordpress.android.util.ptr.CustomSwipeRefreshLayout; import org.wordpress.android.util.ptr.SwipeToRefreshHelper; import org.wordpress.android.util.ptr.SwipeToRefreshHelper.RefreshListener; -import org.wordpress.android.util.ptr.CustomSwipeRefreshLayout; import org.xmlrpc.android.ApiHelper; import org.xmlrpc.android.XMLRPCCallback; import org.xmlrpc.android.XMLRPCClientInterface; @@ -67,7 +67,6 @@ import java.util.Map; * </p> */ public class StatsActivity extends WPDrawerActivity implements ScrollViewExt.ScrollViewListener, - StatsAuthorsFragment.OnAuthorsSectionChangeListener, StatsVisitorsAndViewsFragment.OnDateChangeListener, StatsAbstractListFragment.OnRequestDataListener, StatsAbstractFragment.TimeframeDateProvider { @@ -368,14 +367,6 @@ public class StatsActivity extends WPDrawerActivity implements ScrollViewExt.Scr ft.commitAllowingStateLoss(); } - // AuthorsFragment should be dismissed when 0 or 1 author. - public void onAuthorsVisibilityChange(boolean isEmpty) { - View authorsContainer = this.findViewById(R.id.stats_top_authors_container); - if (authorsContainer != null) { - authorsContainer.setVisibility(isEmpty ? View.GONE : View.VISIBLE); - } - } - @Override public void onMoreDataRequested(StatsService.StatsEndpointsEnum endPointNeedUpdate, int pageNumber) { // nope diff --git a/WordPress/src/main/java/org/wordpress/android/ui/stats/StatsAuthorsFragment.java b/WordPress/src/main/java/org/wordpress/android/ui/stats/StatsAuthorsFragment.java index 303e67d13..96aec4595 100644 --- a/WordPress/src/main/java/org/wordpress/android/ui/stats/StatsAuthorsFragment.java +++ b/WordPress/src/main/java/org/wordpress/android/ui/stats/StatsAuthorsFragment.java @@ -20,22 +20,6 @@ import java.util.List; public class StatsAuthorsFragment extends StatsAbstractListFragment { public static final String TAG = StatsAuthorsFragment.class.getSimpleName(); - private OnAuthorsSectionChangeListener mListener; - - // Container Activity must implement this interface - public interface OnAuthorsSectionChangeListener { - public void onAuthorsVisibilityChange(boolean isEmpty); - } - - @Override - public void onAttach(Activity activity) { - super.onAttach(activity); - try { - mListener = (OnAuthorsSectionChangeListener) activity; - } catch (ClassCastException e) { - throw new ClassCastException(activity.toString() + " must implement OnAuthorsSectionChangeListener"); - } - } @Override protected void updateUI() { @@ -50,22 +34,18 @@ public class StatsAuthorsFragment extends StatsAbstractListFragment { if (isDataEmpty()) { showHideNoResultsUI(true); - mListener.onAuthorsVisibilityChange(true); // Hide the authors section if completely empty return; } List<AuthorModel> authors = ((AuthorsModel) mDatamodels[0]).getAuthors(); - // Do not show the authors section if there is one author only - if (authors == null || authors.size() <= 1) { + if (authors == null || authors.size() == 0) { showHideNoResultsUI(true); - mListener.onAuthorsVisibilityChange(true); return; } BaseExpandableListAdapter adapter = new MyExpandableListAdapter(getActivity(), authors); StatsUIHelper.reloadGroupViews(getActivity(), adapter, mGroupIdToExpandedMap, mList, getMaxNumberOfItemsToShowInList()); showHideNoResultsUI(false); - mListener.onAuthorsVisibilityChange(false); } @Override @@ -97,7 +77,7 @@ public class StatsAuthorsFragment extends StatsAbstractListFragment { } @Override protected int getEmptyLabelTitleResId() { - return R.string.stats_empty_top_authors; + return R.string.stats_empty_top_posts_title; } @Override protected int getEmptyLabelDescResId() { diff --git a/WordPress/src/main/java/org/wordpress/android/ui/stats/StatsBarGraph.java b/WordPress/src/main/java/org/wordpress/android/ui/stats/StatsBarGraph.java index 473948420..1f1853ffa 100644 --- a/WordPress/src/main/java/org/wordpress/android/ui/stats/StatsBarGraph.java +++ b/WordPress/src/main/java/org/wordpress/android/ui/stats/StatsBarGraph.java @@ -110,20 +110,9 @@ class StatsBarGraph extends GraphView { } } - private class HorizontalLabelsBackgroundColor implements IndexDependentColor { - public int get(int index) { - if (mBarPositionToHighlight == index) { - return getResources().getColor(R.color.notification_status_unapproved_dark); - } else { - return Color.WHITE; - } - } - } - private void setProperties() { GraphViewStyle gStyle = getGraphViewStyle(); gStyle.setHorizontalLabelsIndexDependentColor(new HorizontalLabelsColor()); - gStyle.setHorizontalLabelsBackgroundIndexDependentColor(new HorizontalLabelsBackgroundColor()); gStyle.setHorizontalLabelsColor(getResources().getColor(R.color.blue_dark)); gStyle.setVerticalLabelsColor(getResources().getColor(R.color.stats_bar_graph_vertical_label)); gStyle.setTextSize(getResources().getDimensionPixelSize(R.dimen.text_sz_extra_small)); @@ -158,6 +147,10 @@ class StatsBarGraph extends GraphView { double minY, double diffX, double diffY, float horstart, GraphViewSeriesStyle style) { float colwidth = graphwidth / values.length; + int maxColumnSize = getGraphViewStyle().getMaxColumnWidth(); + if (maxColumnSize > 0 && colwidth > maxColumnSize) { + colwidth = maxColumnSize; + } paint.setStrokeWidth(style.thickness); paint.setColor(style.color); @@ -184,9 +177,8 @@ class StatsBarGraph extends GraphView { float bottom = graphheight + border - 1; // Draw the orange selection behind the selected bar - if (mBarPositionToHighlight == i) { - paint.setColor(getResources().getColor(R.color.notification_status_unapproved_dark)); - paint.setAlpha(50); + if (mBarPositionToHighlight == i && style.outerhighlightColor != 0x00ffffff) { + paint.setColor(style.outerhighlightColor); canvas.drawRect(left, 10f, right, bottom, paint); } @@ -204,7 +196,7 @@ class StatsBarGraph extends GraphView { // draw a real bar paint.setAlpha(255); if (mBarPositionToHighlight == i) { - paint.setColor(getResources().getColor(R.color.notification_status_unapproved_dark)); + paint.setColor(style.highlightColor); } else { paint.setColor(style.color); } diff --git a/WordPress/src/main/java/org/wordpress/android/ui/stats/StatsConstants.java b/WordPress/src/main/java/org/wordpress/android/ui/stats/StatsConstants.java index 614064b81..267b6a250 100644 --- a/WordPress/src/main/java/org/wordpress/android/ui/stats/StatsConstants.java +++ b/WordPress/src/main/java/org/wordpress/android/ui/stats/StatsConstants.java @@ -10,6 +10,6 @@ public class StatsConstants { public static final String STATS_OUTPUT_DATE_MONTH_LONG_FORMAT = "MMMM"; public static final String STATS_OUTPUT_DATE_YEAR_FORMAT = "yyyy"; - + public static final int STATS_GRAPH_BAR_MAX_COLUMN_WIDTH_DP = 100; } diff --git a/WordPress/src/main/java/org/wordpress/android/ui/stats/StatsSinglePostDetailsActivity.java b/WordPress/src/main/java/org/wordpress/android/ui/stats/StatsSinglePostDetailsActivity.java index 70a1d6346..b27c49fa9 100644 --- a/WordPress/src/main/java/org/wordpress/android/ui/stats/StatsSinglePostDetailsActivity.java +++ b/WordPress/src/main/java/org/wordpress/android/ui/stats/StatsSinglePostDetailsActivity.java @@ -36,8 +36,8 @@ import org.wordpress.android.util.DisplayUtils; import org.wordpress.android.util.FormatUtils; import org.wordpress.android.util.NetworkUtils; import org.wordpress.android.util.ToastUtils; -import org.wordpress.android.util.ptr.SwipeToRefreshHelper; import org.wordpress.android.util.ptr.CustomSwipeRefreshLayout; +import org.wordpress.android.util.ptr.SwipeToRefreshHelper; import java.lang.ref.WeakReference; import java.util.List; @@ -342,6 +342,9 @@ public class StatsSinglePostDetailsActivity extends ActionBarActivity mGraphView.addSeries(mCurrentSeriesOnScreen); //mGraphView.getGraphViewStyle().setNumHorizontalLabels(getNumOfHorizontalLabels(dataToShowOnGraph.length)); mGraphView.getGraphViewStyle().setNumHorizontalLabels(dataToShowOnGraph.length); + mGraphView.getGraphViewStyle().setMaxColumnWidth( + DisplayUtils.dpToPx(this, StatsConstants.STATS_GRAPH_BAR_MAX_COLUMN_WIDTH_DP) + ); mGraphView.setHorizontalLabels(horLabels); mGraphView.setGestureListener(this); mSelectedBarGraphIndex = (mSelectedBarGraphIndex != -1) ? mSelectedBarGraphIndex : dataToShowOnGraph.length - 1; diff --git a/WordPress/src/main/java/org/wordpress/android/ui/stats/StatsUtils.java b/WordPress/src/main/java/org/wordpress/android/ui/stats/StatsUtils.java index 42cfbd852..4bcb76602 100644 --- a/WordPress/src/main/java/org/wordpress/android/ui/stats/StatsUtils.java +++ b/WordPress/src/main/java/org/wordpress/android/ui/stats/StatsUtils.java @@ -5,13 +5,13 @@ import android.content.Context; import android.content.SharedPreferences; import android.preference.PreferenceManager; +import com.android.volley.NetworkResponse; import com.android.volley.VolleyError; import org.json.JSONException; import org.json.JSONObject; import org.wordpress.android.R; import org.wordpress.android.WordPress; -import org.wordpress.android.WordPressDB; import org.wordpress.android.models.Blog; import org.wordpress.android.ui.WPWebViewActivity; import org.wordpress.android.ui.reader.ReaderActivityLauncher; @@ -270,6 +270,20 @@ public class StatsUtils { } } + public static synchronized void logVolleyErrorDetails(final VolleyError volleyError) { + if (volleyError == null) { + AppLog.e(T.STATS, "Tried to log a VolleyError, but the error obj was null!"); + return; + } + if (volleyError.networkResponse != null) { + NetworkResponse networkResponse = volleyError.networkResponse; + AppLog.e(T.STATS, "Network status code: " + networkResponse.statusCode); + if (networkResponse.data != null) { + AppLog.e(T.STATS, "Network data: " + new String(networkResponse.data)); + } + } + AppLog.e(T.STATS, "Volley Error details: " + volleyError.getMessage(), volleyError); + } public static synchronized Serializable parseResponse(StatsService.StatsEndpointsEnum endpointName, String blogID, JSONObject response) throws JSONException { diff --git a/WordPress/src/main/java/org/wordpress/android/ui/stats/StatsViewAllActivity.java b/WordPress/src/main/java/org/wordpress/android/ui/stats/StatsViewAllActivity.java index 7fcb5d93a..4f5c50308 100644 --- a/WordPress/src/main/java/org/wordpress/android/ui/stats/StatsViewAllActivity.java +++ b/WordPress/src/main/java/org/wordpress/android/ui/stats/StatsViewAllActivity.java @@ -26,8 +26,8 @@ import org.wordpress.android.ui.stats.service.StatsService; import org.wordpress.android.util.AppLog; import org.wordpress.android.util.NetworkUtils; import org.wordpress.android.util.ToastUtils; -import org.wordpress.android.util.ptr.SwipeToRefreshHelper; import org.wordpress.android.util.ptr.CustomSwipeRefreshLayout; +import org.wordpress.android.util.ptr.SwipeToRefreshHelper; import java.io.Serializable; import java.lang.ref.WeakReference; @@ -43,8 +43,7 @@ import java.util.concurrent.ThreadPoolExecutor; * Single item details activity. */ public class StatsViewAllActivity extends ActionBarActivity - implements StatsAuthorsFragment.OnAuthorsSectionChangeListener, - StatsAbstractListFragment.OnRequestDataListener, + implements StatsAbstractListFragment.OnRequestDataListener, StatsAbstractFragment.TimeframeDateProvider { private boolean mIsInFront; @@ -383,11 +382,6 @@ public class StatsViewAllActivity extends ActionBarActivity }, 75L); } - @Override - public void onAuthorsVisibilityChange(boolean isEmpty) { - // Nothing to do here, since the section must not disappear here. - } - private class RestListener implements RestRequest.Listener, RestRequest.ErrorListener { private final String mRequestBlogId; private final StatsTimeframe mTimeframe; @@ -431,10 +425,9 @@ public class StatsViewAllActivity extends ActionBarActivity @Override public void onErrorResponse(final VolleyError volleyError) { - if (volleyError != null) { - AppLog.e(AppLog.T.STATS, "Error while reading Stats details " - + volleyError.getMessage(), volleyError); - } + AppLog.e(AppLog.T.STATS, "Error while reading Stats details!"); + StatsUtils.logVolleyErrorDetails(volleyError); + if (mActivityRef.get() == null || mActivityRef.get().isFinishing()) { return; } diff --git a/WordPress/src/main/java/org/wordpress/android/ui/stats/StatsViewHolder.java b/WordPress/src/main/java/org/wordpress/android/ui/stats/StatsViewHolder.java index 5a1eeff80..562381915 100644 --- a/WordPress/src/main/java/org/wordpress/android/ui/stats/StatsViewHolder.java +++ b/WordPress/src/main/java/org/wordpress/android/ui/stats/StatsViewHolder.java @@ -14,7 +14,6 @@ import android.widget.TextView; import org.wordpress.android.R; import org.wordpress.android.WordPress; -import org.wordpress.android.WordPressDB; import org.wordpress.android.ui.WPWebViewActivity; import org.wordpress.android.ui.stats.models.PostModel; import org.wordpress.android.util.AppLog; diff --git a/WordPress/src/main/java/org/wordpress/android/ui/stats/StatsVisitorsAndViewsFragment.java b/WordPress/src/main/java/org/wordpress/android/ui/stats/StatsVisitorsAndViewsFragment.java index e58bbfbf4..ca8c95ce7 100644 --- a/WordPress/src/main/java/org/wordpress/android/ui/stats/StatsVisitorsAndViewsFragment.java +++ b/WordPress/src/main/java/org/wordpress/android/ui/stats/StatsVisitorsAndViewsFragment.java @@ -6,16 +6,16 @@ import android.content.Context; import android.content.Intent; import android.content.IntentFilter; import android.graphics.drawable.Drawable; +import android.os.Build; import android.os.Bundle; import android.support.v4.content.LocalBroadcastManager; -import android.view.Gravity; 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.RadioGroup; import android.widget.TextView; import com.android.volley.VolleyError; @@ -35,7 +35,6 @@ 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 org.wordpress.android.widgets.TypefaceCache; import java.io.Serializable; import java.text.ParseException; @@ -51,14 +50,21 @@ public class StatsVisitorsAndViewsFragment extends StatsAbstractFragment 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_SELECTED_OVERVIEW_ITEM = "ARG_SELECTED_OVERVIEW_ITEM"; + private static final String ARG_CHECKBOX_SELECTED = "ARG_CHECKBOX_SELECTED"; + private LinearLayout mGraphContainer; private StatsBarGraph mGraphView; - private GraphViewSeries mCurrentSeriesOnScreen; private LinearLayout mModuleButtonsContainer; private TextView mDateTextView; private String[] mStatsDate; + private LinearLayout mLegendContainer; + private CheckedTextView mLegendLabel; + private LinearLayout mVisitorsCheckboxContainer; + private CheckBox mVisitorsCheckbox; + private boolean mIsCheckboxChecked; + private OnDateChangeListener mListener; final OverviewLabel[] overviewItems = {OverviewLabel.VIEWS, OverviewLabel.VISITORS, OverviewLabel.LIKES, @@ -92,6 +98,19 @@ public class StatsVisitorsAndViewsFragment extends StatsAbstractFragment mGraphContainer = (LinearLayout) view.findViewById(R.id.stats_bar_chart_fragment_container); mModuleButtonsContainer = (LinearLayout) view.findViewById(R.id.stats_pager_tabs); + 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++) { @@ -213,6 +232,16 @@ public class StatsVisitorsAndViewsFragment extends StatsAbstractFragment } }; + + View.OnClickListener onCheckboxClicked = new View.OnClickListener() { + @Override + public void onClick(View view) { + // Is the view now checked? + mIsCheckboxChecked = ((CheckBox) view).isChecked(); + updateUI(); + } + }; + @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); @@ -227,6 +256,10 @@ public class StatsVisitorsAndViewsFragment extends StatsAbstractFragment if (savedInstanceState.containsKey(ARG_SELECTED_GRAPH_BAR)) { mSelectedBarGraphBarIndex = savedInstanceState.getInt(ARG_SELECTED_GRAPH_BAR, -1); } + + mIsCheckboxChecked = savedInstanceState.getBoolean(ARG_CHECKBOX_SELECTED, true); + } else { + mIsCheckboxChecked = true; } } @@ -242,6 +275,7 @@ public class StatsVisitorsAndViewsFragment extends StatsAbstractFragment outState.putSerializable(ARG_REST_RESPONSE, mVisitsData); outState.putInt(ARG_SELECTED_GRAPH_BAR, mSelectedBarGraphBarIndex); outState.putInt(ARG_SELECTED_OVERVIEW_ITEM, mSelectedOverviewItemIndex); + outState.putBoolean(ARG_CHECKBOX_SELECTED, mVisitorsCheckbox.isChecked()); super.onSaveInstanceState(outState); } @@ -302,13 +336,34 @@ public class StatsVisitorsAndViewsFragment extends StatsAbstractFragment return; } + // 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[] views = new GraphView.GraphViewData[dataToShowOnGraph.length]; + GraphView.GraphViewData[] mainSeriesItems = new GraphView.GraphViewData[dataToShowOnGraph.length]; - OverviewLabel selectedStatsType = overviewItems[mSelectedOverviewItemIndex]; + GraphView.GraphViewData[] secondarySeriesItems = null; + if (mIsCheckboxChecked && selectedStatsType == OverviewLabel.VIEWS) { + secondarySeriesItems = new GraphView.GraphViewData[dataToShowOnGraph.length]; + } + // Fill series variables with data for (int i = 0; i < dataToShowOnGraph.length; i++) { int currentItemValue = 0; switch(selectedStatsType) { @@ -325,18 +380,17 @@ public class StatsVisitorsAndViewsFragment extends StatsAbstractFragment currentItemValue = dataToShowOnGraph[i].getComments(); break; } - views[i] = new GraphView.GraphViewData(i, currentItemValue); + mainSeriesItems[i] = new GraphView.GraphViewData(i, currentItemValue); + + 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; } - mCurrentSeriesOnScreen = new GraphViewSeries(views); - mCurrentSeriesOnScreen.getStyle().color = getResources().getColor(R.color.stats_bar_graph_views); - mCurrentSeriesOnScreen.getStyle().padding = DisplayUtils.dpToPx(getActivity(), 5); - - if (mGraphContainer.getChildCount() >= 1 && mGraphContainer.getChildAt(0) instanceof GraphView) { mGraphView = (StatsBarGraph) mGraphContainer.getChildAt(0); } else { @@ -346,10 +400,44 @@ public class StatsVisitorsAndViewsFragment extends StatsAbstractFragment } mGraphView.removeAllSeries(); - mGraphView.addSeries(mCurrentSeriesOnScreen); - //mGraphView.getGraphViewStyle().setNumHorizontalLabels(getNumOfHorizontalLabels(dataToShowOnGraph.length)); + + GraphViewSeries mainSeriesOnScreen = new GraphViewSeries(mainSeriesItems); + mainSeriesOnScreen.getStyle().color = getResources().getColor(R.color.stats_bar_graph_views); + mainSeriesOnScreen.getStyle().highlightColor = getResources().getColor(R.color.calypso_orange_dark); + 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_views_inner); + secondarySeries.getStyle().highlightColor = getResources().getColor(R.color.orange_dark); + 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); int barSelectedOnGraph; @@ -371,6 +459,23 @@ public class StatsVisitorsAndViewsFragment extends StatsAbstractFragment 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 (int i = 0; i < dataToShowOnGraph.length; i++) { + int currentItemValue = dataToShowOnGraph[i].getViews(); + if (currentItemValue > largest) { + largest = currentItemValue; + } + } + return largest; + } + //update the area right below the graph private void updateUIBelowTheGraph(int itemPosition) { if (!isAdded()) { @@ -503,6 +608,11 @@ public class StatsVisitorsAndViewsFragment extends StatsAbstractFragment if (!isAdded()) { return; } + + // Hide the legend + mLegendContainer.setVisibility(View.GONE); + mVisitorsCheckboxContainer.setVisibility(View.GONE); + mSelectedBarGraphBarIndex = -1; Context context = mGraphContainer.getContext(); if (context != null) { diff --git a/WordPress/src/main/java/org/wordpress/android/ui/stats/StatsWPLinkMovementMethod.java b/WordPress/src/main/java/org/wordpress/android/ui/stats/StatsWPLinkMovementMethod.java index e77d73daa..e6b26a73c 100644 --- a/WordPress/src/main/java/org/wordpress/android/ui/stats/StatsWPLinkMovementMethod.java +++ b/WordPress/src/main/java/org/wordpress/android/ui/stats/StatsWPLinkMovementMethod.java @@ -9,7 +9,6 @@ import android.view.MotionEvent; import android.widget.TextView; import org.wordpress.android.WordPress; -import org.wordpress.android.WordPressDB; import org.wordpress.android.ui.WPWebViewActivity; import org.wordpress.android.util.AppLog; import org.wordpress.android.util.UrlUtils; diff --git a/WordPress/src/main/java/org/wordpress/android/ui/stats/service/StatsService.java b/WordPress/src/main/java/org/wordpress/android/ui/stats/service/StatsService.java index c1211739d..246c7e5bf 100644 --- a/WordPress/src/main/java/org/wordpress/android/ui/stats/service/StatsService.java +++ b/WordPress/src/main/java/org/wordpress/android/ui/stats/service/StatsService.java @@ -6,6 +6,7 @@ import android.os.IBinder; import android.support.v4.content.LocalBroadcastManager; import android.text.TextUtils; +import com.android.volley.NetworkResponse; import com.android.volley.Request; import com.android.volley.VolleyError; import com.wordpress.rest.RestRequest; @@ -303,9 +304,7 @@ public class StatsService extends Service { } mNumberOfFinishedNetworkCalls++; AppLog.e(T.STATS, this.getClass().getName() + " responded with an Error"); - if (volleyError != null) { - AppLog.e(T.STATS, "Error details: \n" + volleyError.getMessage(), volleyError); - } + StatsUtils.logVolleyErrorDetails(volleyError); mResponseObjectModel = volleyError; notifySectionUpdated(); checkAllRequestsFinished(); diff --git a/WordPress/src/main/java/org/wordpress/android/widgets/TypefaceCache.java b/WordPress/src/main/java/org/wordpress/android/widgets/TypefaceCache.java index 6db0fe359..98c32c23d 100644 --- a/WordPress/src/main/java/org/wordpress/android/widgets/TypefaceCache.java +++ b/WordPress/src/main/java/org/wordpress/android/widgets/TypefaceCache.java @@ -11,33 +11,50 @@ import org.wordpress.android.R; import java.util.Hashtable; public class TypefaceCache { - protected static final int VARIATION_NORMAL = 0; - protected static final int VARIATION_LIGHT = 1; + private static final int VARIATION_NORMAL = 0; + private static final int VARIATION_LIGHT = 1; - private static final Hashtable<String, Typeface> mTypefaceCache = new Hashtable<String, Typeface>(); + private static final Hashtable<String, Typeface> mTypefaceCache = new Hashtable<>(); public static Typeface getTypeface(Context context) { return getTypeface(context, Typeface.NORMAL, VARIATION_NORMAL); } - public static Typeface getTypeface(Context context, int fontStyle, int variation) { - if (context == null) + private static Typeface getTypeface(Context context, int fontStyle, int variation) { + if (context == null) { return null; + } - // note that the "light" variation doesn't support bold or bold-italic final String typefaceName; - switch (fontStyle) { - case Typeface.BOLD: - typefaceName = "OpenSans-Bold.ttf"; - break; - case Typeface.ITALIC: - typefaceName = (variation == VARIATION_LIGHT ? "OpenSans-LightItalic.ttf" : "OpenSans-Italic.ttf"); - break; - case Typeface.BOLD_ITALIC: - typefaceName = "OpenSans-BoldItalic.ttf"; - break; - default: - typefaceName = (variation == VARIATION_LIGHT ? "OpenSans-Light.ttf" : "OpenSans-Regular.ttf"); - break; + if (variation == VARIATION_LIGHT) { + switch (fontStyle) { + case Typeface.BOLD: + typefaceName = "OpenSans-LightBold.ttf"; + break; + case Typeface.ITALIC: + typefaceName = "OpenSans-LightItalic.ttf"; + break; + case Typeface.BOLD_ITALIC: + typefaceName = "OpenSans-LightBoldItalic.ttf"; + break; + default: + typefaceName = "OpenSans-Light.ttf"; + break; + } + } else { + switch (fontStyle) { + case Typeface.BOLD: + typefaceName = "OpenSans-Bold.ttf"; + break; + case Typeface.ITALIC: + typefaceName = "OpenSans-Italic.ttf"; + break; + case Typeface.BOLD_ITALIC: + typefaceName = "OpenSans-BoldItalic.ttf"; + break; + default: + typefaceName = "OpenSans-Regular.ttf"; + break; + } } return getTypefaceForTypefaceName(context, typefaceName); |