aboutsummaryrefslogtreecommitdiff
path: root/WordPress/src/main/java/org/wordpress/android/ui/stats/StatsUIHelper.java
diff options
context:
space:
mode:
Diffstat (limited to 'WordPress/src/main/java/org/wordpress/android/ui/stats/StatsUIHelper.java')
-rw-r--r--WordPress/src/main/java/org/wordpress/android/ui/stats/StatsUIHelper.java344
1 files changed, 344 insertions, 0 deletions
diff --git a/WordPress/src/main/java/org/wordpress/android/ui/stats/StatsUIHelper.java b/WordPress/src/main/java/org/wordpress/android/ui/stats/StatsUIHelper.java
new file mode 100644
index 000000000..441ed3050
--- /dev/null
+++ b/WordPress/src/main/java/org/wordpress/android/ui/stats/StatsUIHelper.java
@@ -0,0 +1,344 @@
+package org.wordpress.android.ui.stats;
+
+import android.app.Activity;
+import android.content.Context;
+import android.graphics.Color;
+import android.graphics.Point;
+import android.text.Spannable;
+import android.text.style.URLSpan;
+import android.util.SparseBooleanArray;
+import android.view.Display;
+import android.view.View;
+import android.view.ViewGroup;
+import android.view.animation.AccelerateInterpolator;
+import android.view.animation.Animation;
+import android.view.animation.Interpolator;
+import android.view.animation.RotateAnimation;
+import android.view.animation.ScaleAnimation;
+import android.widget.ExpandableListAdapter;
+import android.widget.ImageView;
+import android.widget.LinearLayout;
+import android.widget.ListAdapter;
+
+import org.wordpress.android.R;
+import org.wordpress.android.WordPress;
+import org.wordpress.android.util.DisplayUtils;
+
+class StatsUIHelper {
+ // Max number of rows to show in a stats fragment
+ private static final int STATS_GROUP_MAX_ITEMS = 10;
+ private static final int STATS_CHILD_MAX_ITEMS = 50;
+ private static final int ANIM_DURATION = 150;
+
+ // Used for tablet UI
+ private static final int TABLET_720DP = 720;
+ private static final int TABLET_600DP = 600;
+
+ private static boolean isInLandscape(Activity act) {
+ Display display = act.getWindowManager().getDefaultDisplay();
+ Point point = new Point();
+ display.getSize(point);
+ return (point.y < point.x);
+ }
+
+ // Load more bars for 720DP tablets
+ private static boolean shouldLoadMoreBars() {
+ return (StatsUtils.getSmallestWidthDP() >= TABLET_720DP);
+ }
+
+ public static void reloadLinearLayout(Context ctx, ListAdapter adapter, LinearLayout linearLayout, int maxNumberOfItemsToshow) {
+ if (ctx == null || linearLayout == null || adapter == null) {
+ return;
+ }
+
+ // limit number of items to show otherwise it would cause performance issues on the LinearLayout
+ int count = Math.min(adapter.getCount(), maxNumberOfItemsToshow);
+
+ if (count == 0) {
+ linearLayout.removeAllViews();
+ return;
+ }
+
+ int numExistingViews = linearLayout.getChildCount();
+ // remove excess views
+ if (count < numExistingViews) {
+ int numToRemove = numExistingViews - count;
+ linearLayout.removeViews(count, numToRemove);
+ numExistingViews = count;
+ }
+
+ int bgColor = Color.TRANSPARENT;
+ for (int i = 0; i < count; i++) {
+ final View view;
+ // reuse existing view when possible
+ if (i < numExistingViews) {
+ View convertView = linearLayout.getChildAt(i);
+ view = adapter.getView(i, convertView, linearLayout);
+ view.setBackgroundColor(bgColor);
+ setViewBackgroundWithoutResettingPadding(view, i == 0 ? 0 : R.drawable.stats_list_item_background);
+ } else {
+ view = adapter.getView(i, null, linearLayout);
+ view.setBackgroundColor(bgColor);
+ setViewBackgroundWithoutResettingPadding(view, i == 0 ? 0 : R.drawable.stats_list_item_background);
+ linearLayout.addView(view);
+ }
+ }
+ linearLayout.invalidate();
+ }
+
+ /**
+ *
+ * Padding information are reset when changing the background Drawable on a View.
+ * The reason why setting an image resets the padding is because 9-patch images can encode padding.
+ *
+ * See http://stackoverflow.com/a/10469121 and
+ * http://www.mail-archive.com/android-developers@googlegroups.com/msg09595.html
+ *
+ * @param v The view to apply the background resource
+ * @param backgroundResId The resource ID
+ */
+ private static void setViewBackgroundWithoutResettingPadding(final View v, final int backgroundResId) {
+ final int paddingBottom = v.getPaddingBottom(), paddingLeft = v.getPaddingLeft();
+ final int paddingRight = v.getPaddingRight(), paddingTop = v.getPaddingTop();
+ v.setBackgroundResource(backgroundResId);
+ v.setPadding(paddingLeft, paddingTop, paddingRight, paddingBottom);
+ }
+
+ public static void reloadLinearLayout(Context ctx, ListAdapter adapter, LinearLayout linearLayout) {
+ reloadLinearLayout(ctx, adapter, linearLayout, STATS_GROUP_MAX_ITEMS);
+ }
+
+ public static void reloadGroupViews(final Context ctx,
+ final ExpandableListAdapter mAdapter,
+ final SparseBooleanArray mGroupIdToExpandedMap,
+ final LinearLayout mLinearLayout) {
+ reloadGroupViews(ctx, mAdapter, mGroupIdToExpandedMap, mLinearLayout, STATS_GROUP_MAX_ITEMS);
+ }
+
+ public static void reloadGroupViews(final Context ctx,
+ final ExpandableListAdapter mAdapter,
+ final SparseBooleanArray mGroupIdToExpandedMap,
+ final LinearLayout mLinearLayout,
+ final int maxNumberOfItemsToshow) {
+ if (ctx == null || mLinearLayout == null || mAdapter == null || mGroupIdToExpandedMap == null) {
+ return;
+ }
+
+ int groupCount = Math.min(mAdapter.getGroupCount(), maxNumberOfItemsToshow);
+ if (groupCount == 0) {
+ mLinearLayout.removeAllViews();
+ return;
+ }
+
+ int numExistingGroupViews = mLinearLayout.getChildCount();
+
+ // remove excess views
+ if (groupCount < numExistingGroupViews) {
+ int numToRemove = numExistingGroupViews - groupCount;
+ mLinearLayout.removeViews(groupCount, numToRemove);
+ numExistingGroupViews = groupCount;
+ }
+
+ int bgColor = Color.TRANSPARENT;
+
+ // add each group
+ for (int i = 0; i < groupCount; i++) {
+ boolean isExpanded = mGroupIdToExpandedMap.get(i);
+
+ // reuse existing view when possible
+ final View groupView;
+ if (i < numExistingGroupViews) {
+ View convertView = mLinearLayout.getChildAt(i);
+ groupView = mAdapter.getGroupView(i, isExpanded, convertView, mLinearLayout);
+ groupView.setBackgroundColor(bgColor);
+ setViewBackgroundWithoutResettingPadding(groupView, i == 0 ? 0 : R.drawable.stats_list_item_background);
+ } else {
+ groupView = mAdapter.getGroupView(i, isExpanded, null, mLinearLayout);
+ groupView.setBackgroundColor(bgColor);
+ setViewBackgroundWithoutResettingPadding(groupView, i == 0 ? 0 : R.drawable.stats_list_item_background);
+ mLinearLayout.addView(groupView);
+ }
+
+ // groupView is recycled, we need to reset it to the original state.
+ ViewGroup childContainer = (ViewGroup) groupView.findViewById(R.id.layout_child_container);
+ if (childContainer != null) {
+ childContainer.setVisibility(View.GONE);
+ }
+ // Remove any other prev animations set on the chevron
+ final ImageView chevron = (ImageView) groupView.findViewById(R.id.stats_list_cell_chevron);
+ if (chevron != null) {
+ chevron.clearAnimation();
+ chevron.setImageResource(R.drawable.stats_chevron_right);
+ }
+
+ // add children if this group is expanded
+ if (isExpanded) {
+ StatsUIHelper.showChildViews(mAdapter, mLinearLayout, i, groupView, false);
+ }
+
+ // toggle expand/collapse when group view is tapped
+ final int groupPosition = i;
+ groupView.setOnClickListener(new View.OnClickListener() {
+ @Override
+ public void onClick(View v) {
+ if (mAdapter.getChildrenCount(groupPosition) == 0) {
+ return;
+ }
+ boolean shouldExpand = !mGroupIdToExpandedMap.get(groupPosition);
+ mGroupIdToExpandedMap.put(groupPosition, shouldExpand);
+ if (shouldExpand) {
+ StatsUIHelper.showChildViews(mAdapter, mLinearLayout, groupPosition, groupView, true);
+ } else {
+ StatsUIHelper.hideChildViews(groupView, groupPosition, true);
+ }
+ }
+ });
+ }
+ }
+
+ /*
+ * interpolator for all expand/collapse animations
+ */
+ private static Interpolator getInterpolator() {
+ return new AccelerateInterpolator();
+ }
+
+ private static void hideChildViews(View groupView, int groupPosition, boolean animate) {
+ final ViewGroup childContainer = (ViewGroup) groupView.findViewById(R.id.layout_child_container);
+ if (childContainer == null) {
+ return;
+ }
+
+ if (childContainer.getVisibility() != View.GONE) {
+ if (animate) {
+ Animation expand = new ScaleAnimation(1.0f, 1.0f, 1.0f, 0.0f);
+ expand.setDuration(ANIM_DURATION);
+ expand.setInterpolator(getInterpolator());
+ expand.setAnimationListener(new Animation.AnimationListener() {
+ @Override
+ public void onAnimationStart(Animation animation) { }
+ @Override
+ public void onAnimationEnd(Animation animation) {
+ childContainer.setVisibility(View.GONE);
+ }
+ @Override
+ public void onAnimationRepeat(Animation animation) { }
+ });
+ childContainer.startAnimation(expand);
+ } else {
+ childContainer.setVisibility(View.GONE);
+ }
+ }
+ StatsUIHelper.setGroupChevron(false, groupView, groupPosition, animate);
+ }
+
+ /*
+ * shows the correct up/down chevron for the passed group
+ */
+ private static void setGroupChevron(final boolean isGroupExpanded, View groupView, int groupPosition, boolean animate) {
+ final ImageView chevron = (ImageView) groupView.findViewById(R.id.stats_list_cell_chevron);
+ if (chevron == null) {
+ return;
+ }
+ if (isGroupExpanded) {
+ // change the background of the parent
+ setViewBackgroundWithoutResettingPadding(groupView, R.drawable.stats_list_item_expanded_background);
+ } else {
+ setViewBackgroundWithoutResettingPadding(groupView, groupPosition == 0 ? 0 : R.drawable.stats_list_item_background);
+ }
+
+ chevron.clearAnimation(); // Remove any other prev animations set on the chevron
+ if (animate) {
+ // make sure we start with the correct chevron for the prior state before animating it
+ chevron.setImageResource(isGroupExpanded ? R.drawable.stats_chevron_right : R.drawable.stats_chevron_down);
+ float start = (isGroupExpanded ? 0.0f : 0.0f);
+ float end = (isGroupExpanded ? 90.0f : -90.0f);
+ Animation rotate = new RotateAnimation(start, end, Animation.RELATIVE_TO_SELF, 0.5f,
+ Animation.RELATIVE_TO_SELF, 0.5f);
+ rotate.setDuration(ANIM_DURATION);
+ rotate.setInterpolator(getInterpolator());
+ rotate.setFillAfter(true);
+ chevron.startAnimation(rotate);
+ } else {
+ chevron.setImageResource(isGroupExpanded ? R.drawable.stats_chevron_down : R.drawable.stats_chevron_right);
+ }
+ }
+
+ private static void showChildViews(ExpandableListAdapter mAdapter, LinearLayout mLinearLayout,
+ int groupPosition, View groupView, boolean animate) {
+ int childCount = Math.min(mAdapter.getChildrenCount(groupPosition), STATS_CHILD_MAX_ITEMS);
+ if (childCount == 0) {
+ return;
+ }
+
+ final ViewGroup childContainer = (ViewGroup) groupView.findViewById(R.id.layout_child_container);
+ if (childContainer == null) {
+ return;
+ }
+
+ int numExistingViews = childContainer.getChildCount();
+ if (childCount < numExistingViews) {
+ int numToRemove = numExistingViews - childCount;
+ childContainer.removeViews(childCount, numToRemove);
+ numExistingViews = childCount;
+ }
+
+ for (int i = 0; i < childCount; i++) {
+ boolean isLastChild = (i == childCount - 1);
+ if (i < numExistingViews) {
+ View convertView = childContainer.getChildAt(i);
+ mAdapter.getChildView(groupPosition, i, isLastChild, convertView, mLinearLayout);
+ } else {
+ View childView = mAdapter.getChildView(groupPosition, i, isLastChild, null, mLinearLayout);
+ // remove the right/left padding so the child total aligns to left
+ childView.setPadding(0,
+ childView.getPaddingTop(),
+ 0,
+ isLastChild ? 0 : childView.getPaddingBottom()); // No padding bottom on last child
+ setViewBackgroundWithoutResettingPadding(childView, R.drawable.stats_list_item_child_background);
+ childContainer.addView(childView);
+ }
+ }
+
+ if (childContainer.getVisibility() != View.VISIBLE) {
+ if (animate) {
+ Animation expand = new ScaleAnimation(1.0f, 1.0f, 0.0f, 1.0f);
+ expand.setDuration(ANIM_DURATION);
+ expand.setInterpolator(getInterpolator());
+ childContainer.startAnimation(expand);
+ }
+ childContainer.setVisibility(View.VISIBLE);
+ }
+
+ StatsUIHelper.setGroupChevron(true, groupView, groupPosition, animate);
+ }
+
+ /**
+ * Removes URL underlines in a string by replacing URLSpan occurrences by
+ * URLSpanNoUnderline objects.
+ *
+ * @param pText A Spannable object. For example, a TextView casted as
+ * Spannable.
+ */
+ public static void removeUnderlines(Spannable pText) {
+ URLSpan[] spans = pText.getSpans(0, pText.length(), URLSpan.class);
+
+ for(URLSpan span:spans) {
+ int start = pText.getSpanStart(span);
+ int end = pText.getSpanEnd(span);
+ pText.removeSpan(span);
+ span = new URLSpanNoUnderline(span.getURL());
+ pText.setSpan(span, start, end, 0);
+ }
+ }
+
+ public static int getNumOfBarsToShow() {
+ if (StatsUtils.getSmallestWidthDP() >= TABLET_720DP && DisplayUtils.isLandscape(WordPress.getContext())) {
+ return 15;
+ } else if (StatsUtils.getSmallestWidthDP() >= TABLET_600DP) {
+ return 10;
+ } else {
+ return 7;
+ }
+ }
+}