diff options
author | Danilo Ercoli <ercoli@gmail.com> | 2015-08-11 18:04:07 +0200 |
---|---|---|
committer | Danilo Ercoli <ercoli@gmail.com> | 2015-08-11 18:04:07 +0200 |
commit | 3627a281f387c7f9a5d50f5904ccbcececf1b101 (patch) | |
tree | 372b7f75ef575fdaa254fc88ccf5930ea8f7d9e3 | |
parent | b9111e0c6b37c8fdb7c886c144822a70f0494807 (diff) | |
download | gradle-perf-android-medium-3627a281f387c7f9a5d50f5904ccbcececf1b101.tar.gz |
Add most of the code for "Latest Post Summary" module.
I changed a bit of other things while adding the module since some of the required code was already there, but in private class/method.
18 files changed, 699 insertions, 198 deletions
diff --git a/WordPress/src/main/java/org/wordpress/android/ui/stats/StatsAbstractFragment.java b/WordPress/src/main/java/org/wordpress/android/ui/stats/StatsAbstractFragment.java index c11b0869a..c4d3eac04 100644 --- a/WordPress/src/main/java/org/wordpress/android/ui/stats/StatsAbstractFragment.java +++ b/WordPress/src/main/java/org/wordpress/android/ui/stats/StatsAbstractFragment.java @@ -192,6 +192,9 @@ public abstract class StatsAbstractFragment extends Fragment { case INSIGHTS_TODAY: fragment = new StatsInsightsTodayFragment(); break; + case INSIGHTS_LATEST_POST_SUMMARY: + fragment = new StatsInsightsLatestPostSummaryFragment(); + break; } fragment.setTimeframe(timeframe); diff --git a/WordPress/src/main/java/org/wordpress/android/ui/stats/StatsAbstractInsightsFragment.java b/WordPress/src/main/java/org/wordpress/android/ui/stats/StatsAbstractInsightsFragment.java index aa38913e0..5b8899261 100644 --- a/WordPress/src/main/java/org/wordpress/android/ui/stats/StatsAbstractInsightsFragment.java +++ b/WordPress/src/main/java/org/wordpress/android/ui/stats/StatsAbstractInsightsFragment.java @@ -141,7 +141,7 @@ public abstract class StatsAbstractInsightsFragment extends StatsAbstractFragmen customizeUIWithResults(); // call the subclass and draw the real UI here } - private void showPlaceholderUI() { + void showPlaceholderUI() { mErrorLabel.setVisibility(View.GONE); mResultContainer.setVisibility(View.GONE); mEmptyModulePlaceholder.setVisibility(View.VISIBLE); @@ -158,6 +158,14 @@ public abstract class StatsAbstractInsightsFragment extends StatsAbstractFragmen label += "<br/>" + getString(R.string.no_network_message); } + showErrorUI(label); + } + + protected final void showErrorUI(String label) { + if (!isAdded()) { + return; + } + if (label.contains("<")) { mErrorLabel.setText(Html.fromHtml(label)); } else { @@ -168,6 +176,7 @@ public abstract class StatsAbstractInsightsFragment extends StatsAbstractFragmen mEmptyModulePlaceholder.setVisibility(View.GONE); } + boolean isDataEmpty(int index) { return mDatamodels == null || mDatamodels[index] == null 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 11ee67635..2d8c7a73e 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 @@ -398,6 +398,11 @@ public class StatsActivity extends AppCompatActivity ft.replace(R.id.stats_insights_today_container, fragment, StatsInsightsTodayFragment.TAG); } + if (fm.findFragmentByTag(StatsInsightsLatestPostSummaryFragment.TAG) == null || forceRecreationOfFragments) { + fragment = StatsAbstractFragment.newInstance(StatsViewType.INSIGHTS_LATEST_POST_SUMMARY, mLocalBlogID, StatsTimeframe.DAY, mRequestedDate); + ft.replace(R.id.stats_insights_latest_post_summary_container, fragment, StatsInsightsTodayFragment.TAG); + } + if (fm.findFragmentByTag(StatsCommentsFragment.TAG) == null || forceRecreationOfFragments) { fragment = StatsAbstractFragment.newInstance(StatsViewType.COMMENTS, mLocalBlogID, mCurrentTimeframe, mRequestedDate); ft.replace(R.id.stats_comments_container, fragment, StatsCommentsFragment.TAG); @@ -443,6 +448,7 @@ public class StatsActivity extends AppCompatActivity updateTimeframeAndDateAndStartRefreshInFragment(fm, StatsInsightsTodayFragment.TAG); updateTimeframeAndDateAndStartRefreshInFragment(fm, StatsInsightsAllTimeFragment.TAG); updateTimeframeAndDateAndStartRefreshInFragment(fm, StatsInsightsMostPopularFragment.TAG); + updateTimeframeAndDateAndStartRefreshInFragment(fm, StatsInsightsLatestPostSummaryFragment.TAG); updateTimeframeAndDateAndStartRefreshInFragment(fm, StatsCommentsFragment.TAG); updateTimeframeAndDateAndStartRefreshInFragment(fm, StatsTagsAndCategoriesFragment.TAG); updateTimeframeAndDateAndStartRefreshInFragment(fm, StatsPublicizeFragment.TAG); @@ -643,7 +649,7 @@ public class StatsActivity extends AppCompatActivity // StatsInsightsTodayFragment calls this when the user taps on a item in Today's Stats @Override - public void onInsightsClicked(final StatsVisitorsAndViewsFragment.OverviewLabel item) { + public void onInsightsTodayClicked(final StatsVisitorsAndViewsFragment.OverviewLabel item) { mTabToSelectOnGraph = item; for (int i = 0; i < timeframes.length; i++) { if (timeframes[i] == StatsTimeframe.DAY) { diff --git a/WordPress/src/main/java/org/wordpress/android/ui/stats/StatsFollowersFragment.java b/WordPress/src/main/java/org/wordpress/android/ui/stats/StatsFollowersFragment.java index 2a1584ba9..07ae992ea 100644 --- a/WordPress/src/main/java/org/wordpress/android/ui/stats/StatsFollowersFragment.java +++ b/WordPress/src/main/java/org/wordpress/android/ui/stats/StatsFollowersFragment.java @@ -329,7 +329,12 @@ public class StatsFollowersFragment extends StatsAbstractListFragment { } // since date - holder.totalsTextView.setText(getSinceLabel(currentRowData.getDateSubscribed())); + holder.totalsTextView.setText( + StatsUtils.getSinceLabel( + context, + currentRowData.getDateSubscribed() + ) + ); // Avatar holder.networkImageView.setImageUrl( @@ -354,94 +359,7 @@ public class StatsFollowersFragment extends StatsAbstractListFragment { return rowView; } - private int roundUp(double num, double divisor) { - double unrounded = num / divisor; - return (int) (unrounded + 0.5); - } - - private String getSinceLabel(String dataSubscribed) { - - Date currentDateTime = new Date(); - - try { - SimpleDateFormat from = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ssZ"); - Date date = from.parse(dataSubscribed); - - // See http://momentjs.com/docs/#/displaying/fromnow/ - long currentDifference = Math.abs( - StatsUtils.getDateDiff(date, currentDateTime, TimeUnit.SECONDS) - ); - - if (currentDifference <= 45 ) { - return getString(R.string.stats_followers_seconds_ago); - } - if (currentDifference < 90 ) { - return getString(R.string.stats_followers_a_minute_ago); - } - // 90 seconds to 45 minutes - if (currentDifference <= 2700 ) { - long minutes = this.roundUp(currentDifference, 60); - String followersMinutes = getString(R.string.stats_followers_minutes); - return String.format(followersMinutes, minutes); - } - - // 45 to 90 minutes - if (currentDifference <= 5400 ) { - return getString(R.string.stats_followers_an_hour_ago); - } - - // 90 minutes to 22 hours - if (currentDifference <= 79200 ) { - long hours = this.roundUp(currentDifference, 60*60); - String followersHours = getString(R.string.stats_followers_hours); - return String.format(followersHours, hours); - } - - // 22 to 36 hours - if (currentDifference <= 129600 ) { - return getString(R.string.stats_followers_a_day); - } - - // 36 hours to 25 days - // 86400 secs in a day - 2160000 secs in 25 days - if (currentDifference <= 2160000 ) { - long days = this.roundUp(currentDifference, 86400); - String followersDays = getString(R.string.stats_followers_days); - return String.format(followersDays, days); - } - - // 25 to 45 days - // 3888000 secs in 45 days - if (currentDifference <= 3888000 ) { - return getString(R.string.stats_followers_a_month); - } - - // 45 to 345 days - // 2678400 secs in a month - 29808000 secs in 345 days - if (currentDifference <= 29808000 ) { - long months = this.roundUp(currentDifference, 2678400); - String followersMonths = getString(R.string.stats_followers_months); - return String.format(followersMonths, months); - } - - // 345 to 547 days (1.5 years) - if (currentDifference <= 47260800 ) { - return getString(R.string.stats_followers_a_year); - } - - // 548 days+ - // 31536000 secs in a year - long years = this.roundUp(currentDifference, 31536000); - String followersYears = getString(R.string.stats_followers_years); - return String.format(followersYears, years); - - } catch (ParseException e) { - AppLog.e(AppLog.T.STATS, e); - } - - return ""; - } } private static String normalizeAndRemoveScheme(String url) { diff --git a/WordPress/src/main/java/org/wordpress/android/ui/stats/StatsInsightsLatestPostSummaryFragment.java b/WordPress/src/main/java/org/wordpress/android/ui/stats/StatsInsightsLatestPostSummaryFragment.java new file mode 100644 index 000000000..a3cfa4eb3 --- /dev/null +++ b/WordPress/src/main/java/org/wordpress/android/ui/stats/StatsInsightsLatestPostSummaryFragment.java @@ -0,0 +1,277 @@ +package org.wordpress.android.ui.stats; + +import android.app.Activity; +import android.graphics.Color; +import android.graphics.drawable.Drawable; +import android.os.Bundle; +import android.os.Handler; +import android.text.Spannable; +import android.text.SpannableString; +import android.text.style.ForegroundColorSpan; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; +import android.widget.ImageView; +import android.widget.LinearLayout; +import android.widget.TextView; + +import com.android.volley.VolleyError; +import com.wordpress.rest.RestRequest; + +import org.json.JSONException; +import org.json.JSONObject; +import org.wordpress.android.R; +import org.wordpress.android.WordPress; +import org.wordpress.android.networking.RestClientUtils; +import org.wordpress.android.ui.ActivityLauncher; +import org.wordpress.android.ui.stats.models.InsightsLatestPostModel; +import org.wordpress.android.ui.stats.models.PostModel; +import org.wordpress.android.ui.stats.service.StatsService; +import org.wordpress.android.util.AppLog; +import org.wordpress.android.util.FormatUtils; + +import java.lang.ref.WeakReference; +import java.util.concurrent.Executors; +import java.util.concurrent.ThreadPoolExecutor; + +public class StatsInsightsLatestPostSummaryFragment extends StatsAbstractInsightsFragment { + public static final String TAG = StatsInsightsLatestPostSummaryFragment.class.getSimpleName(); + + private Handler mHandler = new Handler(); + + @Override + public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { + View view = super.onCreateView(inflater, container, savedInstanceState); + return view; + } + + void customizeUIWithResults() { + if (!isAdded()) { + return; + } + mResultContainer.removeAllViews(); + + // Another check that the data is available + if (isDataEmpty(0) || !(mDatamodels[0] instanceof InsightsLatestPostModel)) { + showErrorUI(null); + return; + } + + final InsightsLatestPostModel latestPostModel = (InsightsLatestPostModel) mDatamodels[0]; + + // check if the latest post is available on the blog + View mainView = getView(); + if (mainView != null) { + mainView.setVisibility(latestPostModel.isLatestPostAvailable() ? View.VISIBLE : View.GONE); + } + if (!latestPostModel.isLatestPostAvailable()) { + // No need to go further into UI updating + return; + } + + // Check if the we already have the number of views for this post + if (latestPostModel.getPostViewsCount() == Integer.MIN_VALUE) { + // we don't have the views count. Need to call the server again. + final RestClientUtils restClientUtils = WordPress.getRestClientUtilsV1_1(); + + final String singlePostRestPath = String.format( + "/sites/%s/stats/post/%s?fields=views", latestPostModel.getBlogID(), latestPostModel.getPostID()); + //AppLog.d(AppLog.T.STATS, "Enqueuing the following request " + singlePostRestPath); + RestCallListener vListener = new RestCallListener(getActivity()); + restClientUtils.get(singlePostRestPath, vListener, vListener); + showPlaceholderUI(); + return; + } + + TextView moduleTitle = (TextView) mainView.findViewById(R.id.stats_module_title); + moduleTitle.setOnClickListener(ButtonsOnClickListener); + moduleTitle.setTextColor(getResources().getColor(R.color.stats_link_text_color)); + + // update the tabs now and the text now + LinearLayout ll = (LinearLayout) getActivity().getLayoutInflater() + .inflate(R.layout.stats_insights_latest_post_item, (ViewGroup) mResultContainer.getRootView(), false); + + String trendLabel = getString(R.string.stats_insights_latest_post_trend); + String sinceLabel = StatsUtils.getSinceLabel( + getActivity(), + latestPostModel.getPostDate() + ); + + final String trendLabelFormatted = String.format( + trendLabel, sinceLabel, latestPostModel.getPostTitle()); + + int startIndex, endIndex; + startIndex = trendLabelFormatted.indexOf(latestPostModel.getPostTitle()); + endIndex = startIndex + latestPostModel.getPostTitle().length() +1; + + Spannable wordtoSpan = new SpannableString(trendLabelFormatted); + wordtoSpan.setSpan(new ForegroundColorSpan(getResources().getColor(R.color.stats_link_text_color)), + startIndex, endIndex, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE); + TextView trendLabelTextField = (TextView) ll.findViewById(R.id.stats_post_trend_label); + trendLabelTextField.setText(wordtoSpan); + trendLabelTextField.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + StatsUtils.openPostInReaderOrInAppWebview(getActivity(), + latestPostModel.getBlogID(), + String.valueOf(latestPostModel.getPostID()), + StatsConstants.ITEM_TYPE_POST, + latestPostModel.getPostURL()); + } + }); + + LinearLayout tabs = (LinearLayout) ll.findViewById(R.id.stats_latest_post_tabs); + + for (int i = 0; i < tabs.getChildCount(); i++) { + LinearLayout currentTab = (LinearLayout) tabs.getChildAt(i); + switch (i) { + case 0: + setupTab(currentTab, FormatUtils.formatDecimal(latestPostModel.getPostViewsCount()), StatsVisitorsAndViewsFragment.OverviewLabel.VIEWS); + break; + case 1: + setupTab(currentTab, FormatUtils.formatDecimal(latestPostModel.getPostLikeCount()), StatsVisitorsAndViewsFragment.OverviewLabel.LIKES); + break; + case 2: + setupTab(currentTab, FormatUtils.formatDecimal(latestPostModel.getPostCommentCount()), StatsVisitorsAndViewsFragment.OverviewLabel.COMMENTS); + break; + } + } + + mResultContainer.addView(ll); + } + + + private class RestCallListener implements RestRequest.Listener, RestRequest.ErrorListener { + + private final WeakReference<Activity> mActivityRef; + + public RestCallListener(Activity activity) { + mActivityRef = new WeakReference<>(activity); + } + + @Override + public void onResponse(final JSONObject response) { + if (mActivityRef.get() == null || mActivityRef.get().isFinishing() || !isAdded()) { + return; + } + + final InsightsLatestPostModel latestPostModel = (InsightsLatestPostModel) mDatamodels[0]; + + // single background thread used to parse the response in BG. + ThreadPoolExecutor parseResponseExecutor = (ThreadPoolExecutor) Executors.newFixedThreadPool(1); + parseResponseExecutor.submit(new Thread() { + @Override + public void run() { + AppLog.d(AppLog.T.STATS, "The REST response: " + response.toString()); + try { + + int view = response.getInt("views"); + latestPostModel.setPostViewsCount(view); + } catch (JSONException e) { + AppLog.e(AppLog.T.STATS, "Cannot parse the JSON response", e); + } + + // Update the UI + mHandler.post(new Runnable() { + @Override + public void run() { + updateUI(); + } + }); + } + }); + } + + @Override + public void onErrorResponse(final VolleyError volleyError) { + StatsUtils.logVolleyErrorDetails(volleyError); + if (mActivityRef.get() == null || mActivityRef.get().isFinishing() || !isAdded()) { + return; + } + InsightsLatestPostModel latestPostModel = (InsightsLatestPostModel) mDatamodels[0]; + latestPostModel.setPostViewsCount(0); + // Update the UI + mHandler.post(new Runnable() { + @Override + public void run() { + updateUI(); + } + }); + } + } + + + private void setupTab(LinearLayout currentTab, String total, final StatsVisitorsAndViewsFragment.OverviewLabel itemType) { + final TextView label; + final TextView value; + final ImageView icon; + + currentTab.setTag(itemType); + currentTab.setOnClickListener(ButtonsOnClickListener); + + label = (TextView) currentTab.findViewById(R.id.stats_visitors_and_views_tab_label); + label.setText(itemType.getLabel()); + value = (TextView) currentTab.findViewById(R.id.stats_visitors_and_views_tab_value); + value.setText(total); + label.setTextColor(getResources().getColor(R.color.grey_darken_20)); + value.setTextColor(getResources().getColor(R.color.blue_wordpress)); + icon = (ImageView) currentTab.findViewById(R.id.stats_visitors_and_views_tab_icon); + icon.setImageDrawable(getTabIcon(itemType)); + + if (itemType == StatsVisitorsAndViewsFragment.OverviewLabel.COMMENTS) { + currentTab.setBackgroundResource(R.drawable.stats_visitors_and_views_button_latest_white); + } else { + currentTab.setBackgroundResource(R.drawable.stats_visitors_and_views_button_white); + } + } + + private final View.OnClickListener ButtonsOnClickListener = new View.OnClickListener() { + @Override + public void onClick(View v) { + if (!isAdded()) { + return; + } + + // Another check that the data is available + if (isDataEmpty(0) || !(mDatamodels[0] instanceof InsightsLatestPostModel)) { + showErrorUI(null); + return; + } + InsightsLatestPostModel latestPostModel = (InsightsLatestPostModel) mDatamodels[0]; + + PostModel postModel = new PostModel( + latestPostModel.getBlogID(), + String.valueOf(latestPostModel.getPostID()), + latestPostModel.getPostTitle(), + latestPostModel.getPostURL(), + StatsConstants.ITEM_TYPE_POST); + ActivityLauncher.viewStatsSinglePostDetails(getActivity(), postModel); + } + }; + + private Drawable getTabIcon(final StatsVisitorsAndViewsFragment.OverviewLabel labelItem) { + 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); + } + } + + @Override + protected StatsService.StatsEndpointsEnum[] getSectionsToUpdate() { + return new StatsService.StatsEndpointsEnum[]{ + StatsService.StatsEndpointsEnum.INSIGHTS_LATEST_POST_SUMMARY + }; + } + + @Override + public String getTitle() { + return getString(R.string.stats_insights_latest_post_summary); + } +}
\ No newline at end of file diff --git a/WordPress/src/main/java/org/wordpress/android/ui/stats/StatsInsightsTodayFragment.java b/WordPress/src/main/java/org/wordpress/android/ui/stats/StatsInsightsTodayFragment.java index 01f02cf49..d554d11d2 100644 --- a/WordPress/src/main/java/org/wordpress/android/ui/stats/StatsInsightsTodayFragment.java +++ b/WordPress/src/main/java/org/wordpress/android/ui/stats/StatsInsightsTodayFragment.java @@ -24,7 +24,7 @@ public class StatsInsightsTodayFragment extends StatsAbstractInsightsFragment { // Container Activity must implement this interface public interface OnInsightsTodayClickListener { - void onInsightsClicked(StatsVisitorsAndViewsFragment.OverviewLabel item); + void onInsightsTodayClicked(StatsVisitorsAndViewsFragment.OverviewLabel item); } private OnInsightsTodayClickListener mListener; @@ -65,13 +65,15 @@ public class StatsInsightsTodayFragment extends StatsAbstractInsightsFragment { } List<VisitModel> visits = visitsModel.getVisits(); - VisitModel data = visits.get(visits.size()-1); + VisitModel data = visits.get(visits.size() - 1); LinearLayout ll = (LinearLayout) getActivity().getLayoutInflater() .inflate(R.layout.stats_insights_today_item, (ViewGroup) mResultContainer.getRootView(), false); - for (int i = 0; i < ll.getChildCount(); i++) { - LinearLayout currentTab = (LinearLayout) ll.getChildAt(i); + LinearLayout tabs = (LinearLayout) ll.findViewById(R.id.stats_post_tabs); + + for (int i = 0; i < tabs.getChildCount(); i++) { + LinearLayout currentTab = (LinearLayout) tabs.getChildAt(i); switch (i) { case 0: setupTab(currentTab, FormatUtils.formatDecimal(data.getViews()), StatsVisitorsAndViewsFragment.OverviewLabel.VIEWS); @@ -125,7 +127,7 @@ public class StatsInsightsTodayFragment extends StatsAbstractInsightsFragment { return; } StatsVisitorsAndViewsFragment.OverviewLabel tag = (StatsVisitorsAndViewsFragment.OverviewLabel) v.getTag(); - mListener.onInsightsClicked(tag); + mListener.onInsightsTodayClicked(tag); } }; 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 489f2f1c4..3c0ba0ff9 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 @@ -22,6 +22,7 @@ import org.wordpress.android.ui.stats.models.CommentsModel; import org.wordpress.android.ui.stats.models.FollowersModel; import org.wordpress.android.ui.stats.models.GeoviewsModel; import org.wordpress.android.ui.stats.models.InsightsAllTimeModel; +import org.wordpress.android.ui.stats.models.InsightsLatestPostModel; import org.wordpress.android.ui.stats.models.InsightsPopularModel; import org.wordpress.android.ui.stats.models.InsightsTodayModel; import org.wordpress.android.ui.stats.models.PostModel; @@ -407,6 +408,9 @@ public class StatsUtils { case INSIGHTS_TODAY: model = new InsightsTodayModel(blogID, response); break; + case INSIGHTS_LATEST_POST_SUMMARY: + model = new InsightsLatestPostModel(blogID, response); + break; } return model; } @@ -473,4 +477,95 @@ public class StatsUtils { // Error string should be localized here, but don't want to pass a context return new StatsError("Stats couldn't be refreshed at this time"); } + + + private static int roundUp(double num, double divisor) { + double unrounded = num / divisor; + //return (int) Math.ceil(unrounded); + return (int) (unrounded + 0.5); + } + + public static String getSinceLabel(Context ctx, String dataSubscribed) { + + Date currentDateTime = new Date(); + + try { + SimpleDateFormat from = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ssZ"); + Date date = from.parse(dataSubscribed); + + // See http://momentjs.com/docs/#/displaying/fromnow/ + long currentDifference = Math.abs( + StatsUtils.getDateDiff(date, currentDateTime, TimeUnit.SECONDS) + ); + + if (currentDifference <= 45 ) { + return ctx.getString(R.string.stats_followers_seconds_ago); + } + if (currentDifference < 90 ) { + return ctx.getString(R.string.stats_followers_a_minute_ago); + } + + // 90 seconds to 45 minutes + if (currentDifference <= 2700 ) { + long minutes = StatsUtils.roundUp(currentDifference, 60); + String followersMinutes = ctx.getString(R.string.stats_followers_minutes); + return String.format(followersMinutes, minutes); + } + + // 45 to 90 minutes + if (currentDifference <= 5400 ) { + return ctx.getString(R.string.stats_followers_an_hour_ago); + } + + // 90 minutes to 22 hours + if (currentDifference <= 79200 ) { + long hours = StatsUtils.roundUp(currentDifference, 60 * 60); + String followersHours = ctx.getString(R.string.stats_followers_hours); + return String.format(followersHours, hours); + } + + // 22 to 36 hours + if (currentDifference <= 129600 ) { + return ctx.getString(R.string.stats_followers_a_day); + } + + // 36 hours to 25 days + // 86400 secs in a day - 2160000 secs in 25 days + if (currentDifference <= 2160000 ) { + long days = StatsUtils.roundUp(currentDifference, 86400); + String followersDays = ctx.getString(R.string.stats_followers_days); + return String.format(followersDays, days); + } + + // 25 to 45 days + // 3888000 secs in 45 days + if (currentDifference <= 3888000 ) { + return ctx.getString(R.string.stats_followers_a_month); + } + + // 45 to 345 days + // 2678400 secs in a month - 29808000 secs in 345 days + if (currentDifference <= 29808000 ) { + long months = StatsUtils.roundUp(currentDifference, 2678400); + String followersMonths = ctx.getString(R.string.stats_followers_months); + return String.format(followersMonths, months); + } + + // 345 to 547 days (1.5 years) + if (currentDifference <= 47260800 ) { + return ctx.getString(R.string.stats_followers_a_year); + } + + // 548 days+ + // 31536000 secs in a year + long years = StatsUtils.roundUp(currentDifference, 31536000); + String followersYears = ctx.getString(R.string.stats_followers_years); + return String.format(followersYears, years); + + } catch (ParseException e) { + AppLog.e(AppLog.T.STATS, e); + } + + return ""; + } } diff --git a/WordPress/src/main/java/org/wordpress/android/ui/stats/StatsViewType.java b/WordPress/src/main/java/org/wordpress/android/ui/stats/StatsViewType.java index 6c8df6c62..2510d61e0 100644 --- a/WordPress/src/main/java/org/wordpress/android/ui/stats/StatsViewType.java +++ b/WordPress/src/main/java/org/wordpress/android/ui/stats/StatsViewType.java @@ -21,4 +21,5 @@ public enum StatsViewType { INSIGHTS_MOST_POPULAR, INSIGHTS_ALL_TIME, INSIGHTS_TODAY, + INSIGHTS_LATEST_POST_SUMMARY, } diff --git a/WordPress/src/main/java/org/wordpress/android/ui/stats/models/InsightsLatestPostModel.java b/WordPress/src/main/java/org/wordpress/android/ui/stats/models/InsightsLatestPostModel.java new file mode 100644 index 000000000..bd95afad3 --- /dev/null +++ b/WordPress/src/main/java/org/wordpress/android/ui/stats/models/InsightsLatestPostModel.java @@ -0,0 +1,89 @@ +package org.wordpress.android.ui.stats.models; + +import org.json.JSONArray; +import org.json.JSONException; +import org.json.JSONObject; + +import java.io.Serializable; + + +public class InsightsLatestPostModel implements Serializable { + private String mBlogID; + private String mPostTitle; + private String mPostURL; + private String mPostDate; + private int mPostID; + private int mPostViewsCount = Integer.MIN_VALUE; + private int mPostCommentCount; + private int mPostLikeCount; + private int mPostsFound; // if 0 there are no posts on the blog. + + public InsightsLatestPostModel(String blogID, JSONObject response) throws JSONException { + this.mBlogID = blogID; + + mPostsFound = response.optInt("found", 0); + if (mPostsFound == 0) { + // No latest post found! + return; + } + + JSONArray postsObject = response.getJSONArray("posts"); + if (postsObject.length() == 0) { + throw new JSONException("Invalid document returned from the REST API"); + } + + // Read the first post + JSONObject firstPostObject = postsObject.getJSONObject(0); + + this.mPostID = firstPostObject.getInt("ID"); + this.mPostTitle = firstPostObject.getString("title"); + this.mPostDate = firstPostObject.getString("date"); + this.mPostURL = firstPostObject.getString("URL"); + this.mPostLikeCount = firstPostObject.getInt("like_count"); + + JSONObject discussionObject = response.optJSONObject("discussion"); + if (discussionObject != null) { + this.mPostCommentCount = discussionObject.optInt("comment_count", 0); + } + } + + public boolean isLatestPostAvailable() { + return mPostsFound > 0; + } + + public String getBlogID() { + return mBlogID; + } + + public String getPostDate() { + return mPostDate; + } + + public String getPostTitle() { + return mPostTitle; + } + + public String getPostURL() { + return mPostURL; + } + + public int getPostID() { + return mPostID; + } + + public int getPostViewsCount() { + return mPostViewsCount; + } + + public void setPostViewsCount(int mPostViewsCount) { + this.mPostViewsCount = mPostViewsCount; + } + + public int getPostCommentCount() { + return mPostCommentCount; + } + + public int getPostLikeCount() { + return mPostLikeCount; + } +} 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 b66d65757..0c5414f3b 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 @@ -64,7 +64,9 @@ public class StatsService extends Service { SEARCH_TERMS, INSIGHTS_POPULAR, INSIGHTS_ALL_TIME, - INSIGHTS_TODAY; + INSIGHTS_TODAY, + INSIGHTS_LATEST_POST_SUMMARY, + POST; public String getRestEndpointPath() { switch (this) { @@ -102,6 +104,8 @@ public class StatsService extends Service { return ""; case INSIGHTS_TODAY: return "summary"; + case INSIGHTS_LATEST_POST_SUMMARY: + return "posts"; default: AppLog.i(T.STATS, "Called an update of Stats of unknown section!?? " + this.name()); return ""; @@ -300,6 +304,10 @@ public class StatsService extends Service { case INSIGHTS_TODAY: path = String.format(path + "?period=day&date=%s", date); break; + case INSIGHTS_LATEST_POST_SUMMARY: + // This is an edge cases since we're not loading stats but posts + path = String.format("/sites/%s/%s", blogId, sectionToUpdate.getRestEndpointPath() + "?order_by=date&number=1&type=post"); + break; default: AppLog.i(T.STATS, "Called an update of Stats of unknown section!?? " + sectionToUpdate.name()); return; diff --git a/WordPress/src/main/res/layout-sw720dp/stats_activity.xml b/WordPress/src/main/res/layout-sw720dp/stats_activity.xml index 2cde5603d..3102e5f34 100644 --- a/WordPress/src/main/res/layout-sw720dp/stats_activity.xml +++ b/WordPress/src/main/res/layout-sw720dp/stats_activity.xml @@ -56,6 +56,13 @@ android:layout_height="wrap_content" android:layout_marginTop="@dimen/margin_large" /> + <!-- LATEST POST SUMMARY SECTION --> + <FrameLayout + android:id="@+id/stats_insights_latest_post_summary_container" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:layout_marginTop="@dimen/margin_large" /> + <org.wordpress.android.widgets.WPTextView android:textAppearance="?android:attr/textAppearance" android:textSize="@dimen/text_sz_large" diff --git a/WordPress/src/main/res/layout/stats_activity.xml b/WordPress/src/main/res/layout/stats_activity.xml index 928da8d3a..b37176fd0 100644 --- a/WordPress/src/main/res/layout/stats_activity.xml +++ b/WordPress/src/main/res/layout/stats_activity.xml @@ -55,6 +55,13 @@ android:layout_height="wrap_content" android:layout_marginTop="@dimen/margin_large" /> + <!-- LATEST POST SUMMARY SECTION --> + <FrameLayout + android:id="@+id/stats_insights_latest_post_summary_container" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:layout_marginTop="@dimen/margin_large" /> + <org.wordpress.android.widgets.WPTextView android:textAppearance="?android:attr/textAppearance" android:textSize="@dimen/text_sz_large" diff --git a/WordPress/src/main/res/layout/stats_activity_single_post_details.xml b/WordPress/src/main/res/layout/stats_activity_single_post_details.xml index 0c7efe0a0..bdfeef2f2 100644 --- a/WordPress/src/main/res/layout/stats_activity_single_post_details.xml +++ b/WordPress/src/main/res/layout/stats_activity_single_post_details.xml @@ -25,6 +25,8 @@ android:layout_height="wrap_content" android:layout_marginTop="@dimen/margin_large" android:layout_marginBottom="@dimen/margin_medium" + android:layout_marginLeft="@dimen/content_margin" + android:layout_marginRight="@dimen/content_margin" android:textColor="@color/grey_darken_20" android:gravity="center" android:text="Title"/> diff --git a/WordPress/src/main/res/layout/stats_insights_generic_fragment.xml b/WordPress/src/main/res/layout/stats_insights_generic_fragment.xml index 74c521a5f..1a72e9103 100644 --- a/WordPress/src/main/res/layout/stats_insights_generic_fragment.xml +++ b/WordPress/src/main/res/layout/stats_insights_generic_fragment.xml @@ -25,8 +25,6 @@ android:paddingBottom="@dimen/margin_small" style="@style/StatsModuleTitle" /> - <include layout="@layout/stats_insights_header_line" /> - <include android:id="@+id/stats_empty_module_placeholder" layout="@layout/stats_empty_module_placeholder" diff --git a/WordPress/src/main/res/layout/stats_insights_latest_post_item.xml b/WordPress/src/main/res/layout/stats_insights_latest_post_item.xml new file mode 100644 index 000000000..66ea0d4fb --- /dev/null +++ b/WordPress/src/main/res/layout/stats_insights_latest_post_item.xml @@ -0,0 +1,60 @@ +<?xml version="1.0" encoding="utf-8"?> +<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" + android:id="@+id/stats_pager_tabs" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:orientation="vertical"> + + <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:paddingTop="@dimen/margin_large" + android:paddingBottom="@dimen/margin_medium" + android:layout_marginLeft="@dimen/content_margin" + android:layout_marginRight="@dimen/content_margin" + android:orientation="horizontal"> + + <org.wordpress.android.widgets.WPTextView + android:id="@+id/stats_post_trend_label" + android:background="?android:selectableItemBackground" + android:textAppearance="?android:attr/textAppearance" + android:textColor="@color/stats_module_content_list_header" + android:textSize="@dimen/text_sz_small" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:gravity="center"/> + + </LinearLayout> + + <include layout="@layout/stats_insights_header_line" /> + + <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" + android:id="@+id/stats_latest_post_tabs" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:orientation="horizontal"> + <!-- VIEWS tab--> + <include + layout="@layout/stats_visitors_and_views_tab" + android:layout_width="0dp" + android:layout_height="match_parent" + android:layout_weight="1" + android:orientation="horizontal" /> + + <!-- LIKES tab --> + <include + layout="@layout/stats_visitors_and_views_tab" + android:layout_width="0dp" + android:layout_height="match_parent" + android:layout_weight="1" + android:orientation="horizontal" /> + + <!-- COMMENTS tab --> + <include + layout="@layout/stats_visitors_and_views_tab" + android:layout_width="0dp" + android:layout_height="match_parent" + android:layout_weight="1" + android:orientation="horizontal" /> + </LinearLayout> +</LinearLayout>
\ No newline at end of file diff --git a/WordPress/src/main/res/layout/stats_insights_most_popular_item.xml b/WordPress/src/main/res/layout/stats_insights_most_popular_item.xml index 6f6e45134..caf4a5e24 100644 --- a/WordPress/src/main/res/layout/stats_insights_most_popular_item.xml +++ b/WordPress/src/main/res/layout/stats_insights_most_popular_item.xml @@ -1,91 +1,100 @@ <?xml version="1.0" encoding="utf-8"?> + <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="wrap_content" - android:baselineAligned="false" - android:padding="@dimen/margin_extra_large" - android:gravity="center_vertical|center_horizontal" android:orientation="vertical"> - <LinearLayout + <include layout="@layout/stats_insights_header_line" /> + + <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="wrap_content" - android:paddingBottom="@dimen/margin_medium" - android:gravity="center_vertical|center_horizontal" > + android:baselineAligned="false" + android:padding="@dimen/margin_extra_large" + android:gravity="center_vertical|center_horizontal" + android:orientation="vertical"> - <org.wordpress.android.widgets.WPAutoResizeTextView - style="@style/StatsInsightsLabel" - android:gravity="center_vertical|center_horizontal" - android:layout_width="0dp" - android:layout_weight="1" + <LinearLayout + android:layout_width="match_parent" android:layout_height="wrap_content" - android:text="@string/stats_insights_most_popular_day" - android:textAllCaps="true" /> + android:paddingBottom="@dimen/margin_medium" + android:gravity="center_vertical|center_horizontal" > - <org.wordpress.android.widgets.WPAutoResizeTextView - style="@style/StatsInsightsLabel" - android:gravity="center_vertical|center_horizontal" - android:layout_height="wrap_content" - android:layout_width="0dp" - android:layout_weight="1" - android:text="@string/stats_insights_most_popular_hour" - android:textAllCaps="true" /> - </LinearLayout> + <org.wordpress.android.widgets.WPAutoResizeTextView + style="@style/StatsInsightsLabel" + android:gravity="center_vertical|center_horizontal" + android:layout_width="0dp" + android:layout_weight="1" + android:layout_height="wrap_content" + android:text="@string/stats_insights_most_popular_day" + android:textAllCaps="true" /> - <LinearLayout - android:layout_width="match_parent" - android:layout_height="wrap_content" - android:orientation="horizontal" - android:gravity="center_vertical|center_horizontal"> + <org.wordpress.android.widgets.WPAutoResizeTextView + style="@style/StatsInsightsLabel" + android:gravity="center_vertical|center_horizontal" + android:layout_height="wrap_content" + android:layout_width="0dp" + android:layout_weight="1" + android:text="@string/stats_insights_most_popular_hour" + android:textAllCaps="true" /> + </LinearLayout> - <org.wordpress.android.widgets.WPAutoResizeTextView - android:gravity="center_vertical|center_horizontal" - android:layout_gravity="center_vertical|center_horizontal" - android:id="@+id/stats_most_popular_day" - style="@style/StatsInsightsValues" - android:layout_width="0dp" - android:layout_weight="1" + <LinearLayout + android:layout_width="match_parent" android:layout_height="wrap_content" - android:text="0" - android:textColor="@color/grey_darken_30" /> + android:orientation="horizontal" + android:gravity="center_vertical|center_horizontal"> - <org.wordpress.android.widgets.WPAutoResizeTextView - android:gravity="center_vertical|center_horizontal" - android:layout_gravity="center_vertical|center_horizontal" - android:id="@+id/stats_most_popular_hour" - style="@style/StatsInsightsValues" - android:layout_width="0dp" - android:layout_weight="1" - android:layout_height="wrap_content" - android:text="0" - android:textColor="@color/grey_darken_30" /> - </LinearLayout> + <org.wordpress.android.widgets.WPAutoResizeTextView + android:gravity="center_vertical|center_horizontal" + android:layout_gravity="center_vertical|center_horizontal" + android:id="@+id/stats_most_popular_day" + style="@style/StatsInsightsValues" + android:layout_width="0dp" + android:layout_weight="1" + android:layout_height="wrap_content" + android:text="0" + android:textColor="@color/grey_darken_30" /> - <LinearLayout - android:layout_width="match_parent" - android:layout_height="wrap_content" - android:paddingTop="@dimen/margin_medium" - android:gravity="center_vertical|center_horizontal" > + <org.wordpress.android.widgets.WPAutoResizeTextView + android:gravity="center_vertical|center_horizontal" + android:layout_gravity="center_vertical|center_horizontal" + android:id="@+id/stats_most_popular_hour" + style="@style/StatsInsightsValues" + android:layout_width="0dp" + android:layout_weight="1" + android:layout_height="wrap_content" + android:text="0" + android:textColor="@color/grey_darken_30" /> + </LinearLayout> - <org.wordpress.android.widgets.WPAutoResizeTextView - style="@style/StatsInsightsLabel" - android:id="@+id/stats_most_popular_day_percent" - android:gravity="center_vertical|center_horizontal" - android:layout_width="0dp" - android:layout_weight="1" + <LinearLayout + android:layout_width="match_parent" android:layout_height="wrap_content" - android:text="@string/stats_insights_most_popular_percent_views" - android:textColor="@color/grey_darken_10" /> + android:paddingTop="@dimen/margin_medium" + android:gravity="center_vertical|center_horizontal" > - <org.wordpress.android.widgets.WPAutoResizeTextView - style="@style/StatsInsightsLabel" - android:id="@+id/stats_most_popular_hour_percent" - android:gravity="center_vertical|center_horizontal" - android:layout_height="wrap_content" - android:layout_width="0dp" - android:layout_weight="1" - android:text="@string/stats_insights_most_popular_percent_views" - android:textColor="@color/grey_darken_10" /> - </LinearLayout> + <org.wordpress.android.widgets.WPAutoResizeTextView + style="@style/StatsInsightsLabel" + android:id="@+id/stats_most_popular_day_percent" + android:gravity="center_vertical|center_horizontal" + android:layout_width="0dp" + android:layout_weight="1" + android:layout_height="wrap_content" + android:text="@string/stats_insights_most_popular_percent_views" + android:textColor="@color/grey_darken_10" /> + + <org.wordpress.android.widgets.WPAutoResizeTextView + style="@style/StatsInsightsLabel" + android:id="@+id/stats_most_popular_hour_percent" + android:gravity="center_vertical|center_horizontal" + android:layout_height="wrap_content" + android:layout_width="0dp" + android:layout_weight="1" + android:text="@string/stats_insights_most_popular_percent_views" + android:textColor="@color/grey_darken_10" /> + </LinearLayout> + </LinearLayout> </LinearLayout>
\ No newline at end of file diff --git a/WordPress/src/main/res/layout/stats_insights_today_item.xml b/WordPress/src/main/res/layout/stats_insights_today_item.xml index 5c016458d..5c0fabc8f 100644 --- a/WordPress/src/main/res/layout/stats_insights_today_item.xml +++ b/WordPress/src/main/res/layout/stats_insights_today_item.xml @@ -1,40 +1,48 @@ <?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" - android:id="@+id/stats_pager_tabs" android:layout_width="match_parent" android:layout_height="wrap_content" - android:orientation="horizontal"> + android:orientation="vertical"> - <!-- VIEWS tab--> - <include - layout="@layout/stats_visitors_and_views_tab" - android:layout_width="0dp" - android:layout_height="match_parent" - android:layout_weight="1" - android:orientation="horizontal" /> + <include layout="@layout/stats_insights_header_line" /> - <!-- VISITORS tab --> - <include - layout="@layout/stats_visitors_and_views_tab" - android:layout_width="0dp" - android:layout_height="match_parent" - android:layout_weight="1" - android:orientation="horizontal" /> + <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" + android:id="@+id/stats_post_tabs" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:orientation="horizontal"> - <!-- LIKES tab --> - <include - layout="@layout/stats_visitors_and_views_tab" - android:layout_width="0dp" - android:layout_height="match_parent" - android:layout_weight="1" - android:orientation="horizontal" /> + <!-- VIEWS tab--> + <include + layout="@layout/stats_visitors_and_views_tab" + android:layout_width="0dp" + android:layout_height="match_parent" + android:layout_weight="1" + android:orientation="horizontal" /> - <!-- COMMENTS tab --> - <include - layout="@layout/stats_visitors_and_views_tab" - android:layout_width="0dp" - android:layout_height="match_parent" - android:layout_weight="1" - android:orientation="horizontal" /> + <!-- VISITORS tab --> + <include + layout="@layout/stats_visitors_and_views_tab" + android:layout_width="0dp" + android:layout_height="match_parent" + android:layout_weight="1" + android:orientation="horizontal" /> + <!-- LIKES tab --> + <include + layout="@layout/stats_visitors_and_views_tab" + android:layout_width="0dp" + android:layout_height="match_parent" + android:layout_weight="1" + android:orientation="horizontal" /> + + <!-- COMMENTS tab --> + <include + layout="@layout/stats_visitors_and_views_tab" + android:layout_width="0dp" + android:layout_height="match_parent" + android:layout_weight="1" + android:orientation="horizontal" /> + + </LinearLayout> </LinearLayout>
\ No newline at end of file diff --git a/WordPress/src/main/res/values/strings.xml b/WordPress/src/main/res/values/strings.xml index ea7b32c06..94093775f 100644 --- a/WordPress/src/main/res/values/strings.xml +++ b/WordPress/src/main/res/values/strings.xml @@ -542,6 +542,8 @@ <string name="stats_insights">Insights</string> <string name="stats_insights_all_time">All-time posts, views, and visitors</string> <string name="stats_insights_today">Today\'s Stats</string> + <string name="stats_insights_latest_post_summary">Latest Post Summary</string> + <string name="stats_insights_latest_post_trend">It\'s been %1$s since %2$s was published. Here\'s how the post has performed so far...</string> <string name="stats_insights_popular">Most popular day and hour</string> <string name="stats_insights_most_popular_day">Most popular day</string> <string name="stats_insights_most_popular_hour">Most popular hour</string> |