package org.wordpress.android.ui.stats;
import android.app.FragmentManager;
import android.app.FragmentTransaction;
import android.content.Context;
import android.content.Intent;
import android.os.Bundle;
import android.support.v7.app.ActionBar;
import android.support.v7.app.AppCompatActivity;
import android.support.v7.app.AppCompatDialogFragment;
import android.support.v7.widget.Toolbar;
import android.view.LayoutInflater;
import android.view.MenuItem;
import android.view.View;
import android.view.ViewGroup;
import android.widget.AdapterView;
import android.widget.BaseAdapter;
import android.widget.ScrollView;
import android.widget.Spinner;
import android.widget.TextView;
import android.widget.Toast;
import org.apache.commons.lang3.StringUtils;
import org.greenrobot.eventbus.Subscribe;
import org.greenrobot.eventbus.ThreadMode;
import org.wordpress.android.R;
import org.wordpress.android.WordPress;
import org.wordpress.android.analytics.AnalyticsTracker;
import org.wordpress.android.fluxc.Dispatcher;
import org.wordpress.android.fluxc.generated.SiteActionBuilder;
import org.wordpress.android.fluxc.model.SiteModel;
import org.wordpress.android.fluxc.store.AccountStore;
import org.wordpress.android.fluxc.store.SiteStore;
import org.wordpress.android.fluxc.store.SiteStore.OnSiteChanged;
import org.wordpress.android.ui.ActivityId;
import org.wordpress.android.ui.RequestCodes;
import org.wordpress.android.ui.accounts.SignInActivity;
import org.wordpress.android.ui.posts.PromoDialog;
import org.wordpress.android.ui.prefs.AppPrefs;
import org.wordpress.android.util.AnalyticsUtils;
import org.wordpress.android.util.AppLog;
import org.wordpress.android.util.AppLog.T;
import org.wordpress.android.util.JetpackUtils;
import org.wordpress.android.util.NetworkUtils;
import org.wordpress.android.util.RateLimitedTask;
import org.wordpress.android.util.SiteUtils;
import org.wordpress.android.util.ToastUtils;
import org.wordpress.android.util.helpers.SwipeToRefreshHelper;
import org.wordpress.android.util.helpers.SwipeToRefreshHelper.RefreshListener;
import org.wordpress.android.util.widgets.CustomSwipeRefreshLayout;
import javax.inject.Inject;
import de.greenrobot.event.EventBus;
/**
* The native stats activity
* <p>
* By pressing a spinner on the action bar, the user can select which timeframe they wish to see.
* </p>
*/
public class StatsActivity extends AppCompatActivity
implements NestedScrollViewExt.ScrollViewListener,
StatsVisitorsAndViewsFragment.OnDateChangeListener,
StatsVisitorsAndViewsFragment.OnOverviewItemChangeListener,
StatsInsightsTodayFragment.OnInsightsTodayClickListener {
private static final String SAVED_WP_LOGIN_STATE = "SAVED_WP_LOGIN_STATE";
private static final String SAVED_STATS_TIMEFRAME = "SAVED_STATS_TIMEFRAME";
private static final String SAVED_STATS_REQUESTED_DATE = "SAVED_STATS_REQUESTED_DATE";
private static final String SAVED_STATS_SCROLL_POSITION = "SAVED_STATS_SCROLL_POSITION";
private static final String SAVED_THERE_WAS_AN_ERROR_LOADING_STATS = "SAVED_THERE_WAS_AN_ERROR_LOADING_STATS";
private Spinner mSpinner;
private NestedScrollViewExt mOuterScrollView;
public static final String ARG_LOCAL_TABLE_SITE_ID = "ARG_LOCAL_TABLE_SITE_ID";
public static final String ARG_LAUNCHED_FROM = "ARG_LAUNCHED_FROM";
public static final String ARG_DESIRED_TIMEFRAME = "ARG_DESIRED_TIMEFRAME";
public enum StatsLaunchedFrom {
STATS_WIDGET,
NOTIFICATIONS
}
@Inject AccountStore mAccountStore;
@Inject SiteStore mSiteStore;
@Inject Dispatcher mDispatcher;
private int mResultCode = -1;
private SiteModel mSite;
private boolean mIsInFront;
private StatsTimeframe mCurrentTimeframe = StatsTimeframe.INSIGHTS;
private String mRequestedDate;
private boolean mIsUpdatingStats;
private SwipeToRefreshHelper mSwipeToRefreshHelper;
private TimeframeSpinnerAdapter mTimeframeSpinnerAdapter;
private final StatsTimeframe[] timeframes = {StatsTimeframe.INSIGHTS, StatsTimeframe.DAY, StatsTimeframe.WEEK,
StatsTimeframe.MONTH, StatsTimeframe.YEAR};
private StatsVisitorsAndViewsFragment.OverviewLabel mTabToSelectOnGraph = StatsVisitorsAndViewsFragment.OverviewLabel.VIEWS;
private boolean mThereWasAnErrorLoadingStats = false;
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
((WordPress) getApplication()).component().inject(this);
if (WordPress.wpDB == null) {
Toast.makeText(this, R.string.fatal_db_error, Toast.LENGTH_LONG).show();
finish();
return;
}
if (savedInstanceState == null) {
mSite = (SiteModel) getIntent().getSerializableExtra(WordPress.SITE);
} else {
mSite = (SiteModel) savedInstanceState.getSerializable(WordPress.SITE);
}
if (mSite == null) {
ToastUtils.showToast(this, R.string.blog_not_found, ToastUtils.Duration.SHORT);
finish();
return;
}
setContentView(R.layout.stats_activity);
Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar);
setSupportActionBar(toolbar);
ActionBar actionBar = getSupportActionBar();
if (actionBar != null) {
actionBar.setElevation(0);
actionBar.setTitle(R.string.stats);
actionBar.setDisplayShowTitleEnabled(true);
actionBar.setDisplayHomeAsUpEnabled(true);
}
mSwipeToRefreshHelper = new SwipeToRefreshHelper(this, (CustomSwipeRefreshLayout) findViewById(R.id.ptr_layout),
new RefreshListener() {
@Override
public void onRefreshStarted() {
if (!NetworkUtils.checkConnection(getBaseContext())) {
mSwipeToRefreshHelper.setRefreshing(false);
return;
}
refreshStatsFromCurrentDate();
}
});
setTitle(R.string.stats);
mOuterScrollView = (NestedScrollViewExt) findViewById(R.id.scroll_view_stats);
mOuterScrollView.setScrollViewListener(this);
if (savedInstanceState != null) {
mResultCode = savedInstanceState.getInt(SAVED_WP_LOGIN_STATE);
mCurrentTimeframe = (StatsTimeframe) savedInstanceState.getSerializable(SAVED_STATS_TIMEFRAME);
mRequestedDate = savedInstanceState.getString(SAVED_STATS_REQUESTED_DATE);
mThereWasAnErrorLoadingStats = savedInstanceState.getBoolean(SAVED_THERE_WAS_AN_ERROR_LOADING_STATS);
final int yScrollPosition = savedInstanceState.getInt(SAVED_STATS_SCROLL_POSITION);
if (yScrollPosition != 0) {
mOuterScrollView.postDelayed(new Runnable() {
public void run() {
if (!isFinishing()) {
mOuterScrollView.scrollTo(0, yScrollPosition);
}
}
}, StatsConstants.STATS_SCROLL_TO_DELAY);
}
} else if (getIntent() != null) {
if (getIntent().hasExtra(SAVED_STATS_TIMEFRAME)) {
mCurrentTimeframe = (StatsTimeframe) getIntent().getSerializableExtra(SAVED_STATS_TIMEFRAME);
} else if (getIntent().hasExtra(ARG_DESIRED_TIMEFRAME)) {
mCurrentTimeframe = (StatsTimeframe) getIntent().getSerializableExtra(ARG_DESIRED_TIMEFRAME);
} else {
// Read the value from app preferences here. Default to 0 - Insights
mCurrentTimeframe = AppPrefs.getStatsTimeframe();
}
mRequestedDate = StatsUtils.getCurrentDateTZ(mSite);
if (getIntent().hasExtra(ARG_LAUNCHED_FROM)) {
StatsLaunchedFrom from = (StatsLaunchedFrom) getIntent().getSerializableExtra(ARG_LAUNCHED_FROM);
if (from == StatsLaunchedFrom.STATS_WIDGET) {
AnalyticsUtils.trackWithSiteDetails(AnalyticsTracker.Stat.STATS_WIDGET_TAPPED, mSite);
}
}
}
if (!mAccountStore.hasAccessToken()) {
// If the user is not connected to WordPress.com, ask him to connect first.
startWPComLoginActivity();
return;
}
checkIfSiteHasAccessibleStats(mSite);
// create the fragments without forcing the re-creation. If the activity is restarted fragments can already
// be there, and ready to be displayed without making any network connections. A fragment calls the stats service
// if its internal datamodel is empty.
createFragments(false);
if (mSpinner == null) {
mSpinner = (Spinner) findViewById(R.id.filter_spinner);
mTimeframeSpinnerAdapter = new TimeframeSpinnerAdapter(this, timeframes);
mSpinner.setAdapter(mTimeframeSpinnerAdapter);
mSpinner.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() {
@Override
public void onItemSelected(AdapterView<?> parent, View view, int position, long id) {
if (isFinishing()) {
return;
}
final StatsTimeframe selectedTimeframe = (StatsTimeframe) mTimeframeSpinnerAdapter.getItem(position);
if (mCurrentTimeframe == selectedTimeframe) {
AppLog.d(T.STATS, "The selected TIME FRAME is already active: " + selectedTimeframe.getLabel());
return;
}
AppLog.d(T.STATS, "NEW TIME FRAME : " + selectedTimeframe.getLabel());
mCurrentTimeframe = selectedTimeframe;
AppPrefs.setStatsTimeframe(mCurrentTimeframe);
mRequestedDate = StatsUtils.getCurrentDateTZ(mSite);
createFragments(true); // Need to recreate fragment here, since a new timeline was selected.
mSpinner.postDelayed(new Runnable() {
@Override
public void run() {
if (!isFinishing()) {
scrollToTop();
}
}
}, StatsConstants.STATS_SCROLL_TO_DELAY);
trackStatsAnalytics();
}
@Override
public void onNothingSelected(AdapterView<?> parent) {
// nop
}
});
Toolbar spinnerToolbar = (Toolbar) findViewById(R.id.toolbar_filter);
spinnerToolbar.setBackgroundColor(getResources().getColor(R.color.blue_medium));
}
selectCurrentTimeframeInActionBar();
TextView otherRecentStatsMovedLabel = (TextView) findViewById(R.id.stats_other_recent_stats_moved);
otherRecentStatsMovedLabel.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
for (int i = 0; i < timeframes.length; i++) {
if (timeframes[i] == StatsTimeframe.INSIGHTS) {
mSpinner.setSelection(i);
break;
}
}
mSpinner.postDelayed(new Runnable() {
@Override
public void run() {
if (!isFinishing()) {
scrollToTop();
}
}
}, StatsConstants.STATS_SCROLL_TO_DELAY);
}
});
// Track usage here
if (savedInstanceState == null) {
AnalyticsUtils.trackWithSiteDetails(AnalyticsTracker.Stat.STATS_ACCESSED, mSite);
trackStatsAnalytics();
}
}
private boolean checkIfSiteHasAccessibleStats(SiteModel site) {
// If the site is not accessible via wpcom (Jetpack included), then show a dialog to the user.
if (!SiteUtils.isAccessedViaWPComRest(mSite)) {
if (!site.isJetpackInstalled()) {
JetpackUtils.showInstallJetpackAlert(this, site);
return false;
}
if (!site.isJetpackConnected()) {
JetpackUtils.showJetpackNonConnectedAlert(this, site);
return false;
}
// TODO: if Jetpack site, we should check the stats option is enabled
}
return true;
}
private void startWPComLoginActivity() {
mResultCode = RESULT_CANCELED;
Intent signInIntent = new Intent(this, SignInActivity.class);
signInIntent.putExtra(SignInActivity.EXTRA_JETPACK_SITE_AUTH, mSite.getId());
signInIntent.putExtra(SignInActivity.EXTRA_JETPACK_MESSAGE_AUTH,
getString(R.string.stats_sign_in_jetpack_different_com_account)
);
startActivityForResult(signInIntent, SignInActivity.REQUEST_CODE);
}
private void trackStatsAnalytics() {
// Track usage here
switch (mCurrentTimeframe) {
case INSIGHTS:
AnalyticsUtils.trackWithSiteDetails(AnalyticsTracker.Stat.STATS_INSIGHTS_ACCESSED, mSite);
break;
case DAY:
AnalyticsUtils.trackWithSiteDetails(AnalyticsTracker.Stat.STATS_PERIOD_DAYS_ACCESSED, mSite);
break;
case WEEK:
AnalyticsUtils.trackWithSiteDetails(AnalyticsTracker.Stat.STATS_PERIOD_WEEKS_ACCESSED, mSite);
break;
case MONTH:
AnalyticsUtils.trackWithSiteDetails(AnalyticsTracker.Stat.STATS_PERIOD_MONTHS_ACCESSED, mSite);
break;
case YEAR:
AnalyticsUtils.trackWithSiteDetails(AnalyticsTracker.Stat.STATS_PERIOD_YEARS_ACCESSED, mSite);
break;
}
}
@Override
protected void onStop() {
mDispatcher.unregister(this);
EventBus.getDefault().unregister(this);
super.onStop();
}
@Override
protected void onStart() {
super.onStart();
EventBus.getDefault().register(this);
mDispatcher.register(this);
}
@Override
protected void onResume() {
super.onResume();
mIsInFront = true;
if (!NetworkUtils.checkConnection(this)) {
mSwipeToRefreshHelper.setRefreshing(false);
}
ActivityId.trackLastActivity(ActivityId.STATS);
}
@Override
protected void onPause() {
super.onPause();
mIsInFront = false;
mIsUpdatingStats = false;
mSwipeToRefreshHelper.setRefreshing(false);
}
@Override
protected void onSaveInstanceState(Bundle outState) {
outState.putInt(SAVED_WP_LOGIN_STATE, mResultCode);
outState.putSerializable(WordPress.SITE, mSite);
outState.putSerializable(SAVED_STATS_TIMEFRAME, mCurrentTimeframe);
outState.putString(SAVED_STATS_REQUESTED_DATE, mRequestedDate);
outState.putBoolean(SAVED_THERE_WAS_AN_ERROR_LOADING_STATS, mThereWasAnErrorLoadingStats);
if (mOuterScrollView.getScrollY() != 0) {
outState.putInt(SAVED_STATS_SCROLL_POSITION, mOuterScrollView.getScrollY());
}
super.onSaveInstanceState(outState);
}
private void createFragments(boolean forceRecreationOfFragments) {
if (isFinishing()) {
return;
}
// Make the labels invisible see: https://github.com/wordpress-mobile/WordPress-Android/issues/3279
findViewById(R.id.stats_other_recent_stats_label_insights).setVisibility(View.INVISIBLE);
findViewById(R.id.stats_other_recent_stats_label_timeline).setVisibility(View.INVISIBLE);
findViewById(R.id.stats_other_recent_stats_moved).setVisibility(View.INVISIBLE);
FragmentManager fm = getFragmentManager();
FragmentTransaction ft = fm.beginTransaction();
StatsAbstractFragment fragment;
if (mCurrentTimeframe != StatsTimeframe.INSIGHTS) {
findViewById(R.id.stats_timeline_fragments_container).setVisibility(View.VISIBLE);
findViewById(R.id.stats_insights_fragments_container).setVisibility(View.GONE);
if (fm.findFragmentByTag(StatsVisitorsAndViewsFragment.TAG) == null || forceRecreationOfFragments) {
fragment = StatsAbstractFragment.newVisitorsAndViewsInstance(StatsViewType.GRAPH_AND_SUMMARY,
mSite.getId(), mCurrentTimeframe, mRequestedDate, mTabToSelectOnGraph);
ft.replace(R.id.stats_visitors_and_views_container, fragment, StatsVisitorsAndViewsFragment.TAG);
}
if (fm.findFragmentByTag(StatsTopPostsAndPagesFragment.TAG) == null || forceRecreationOfFragments) {
fragment = StatsAbstractFragment.newInstance(StatsViewType.TOP_POSTS_AND_PAGES, mSite.getId(),
mCurrentTimeframe, mRequestedDate);
ft.replace(R.id.stats_top_posts_container, fragment, StatsTopPostsAndPagesFragment.TAG);
}
if (fm.findFragmentByTag(StatsReferrersFragment.TAG) == null || forceRecreationOfFragments) {
fragment = StatsAbstractFragment.newInstance(StatsViewType.REFERRERS, mSite.getId(),
mCurrentTimeframe, mRequestedDate);
ft.replace(R.id.stats_referrers_container, fragment, StatsReferrersFragment.TAG);
}
if (fm.findFragmentByTag(StatsClicksFragment.TAG) == null || forceRecreationOfFragments) {
fragment = StatsAbstractFragment.newInstance(StatsViewType.CLICKS, mSite.getId(),
mCurrentTimeframe, mRequestedDate);
ft.replace(R.id.stats_clicks_container, fragment, StatsClicksFragment.TAG);
}
if (fm.findFragmentByTag(StatsGeoviewsFragment.TAG) == null || forceRecreationOfFragments) {
fragment = StatsAbstractFragment.newInstance(StatsViewType.GEOVIEWS, mSite.getId(),
mCurrentTimeframe, mRequestedDate);
ft.replace(R.id.stats_geoviews_container, fragment, StatsGeoviewsFragment.TAG);
}
if (fm.findFragmentByTag(StatsAuthorsFragment.TAG) == null || forceRecreationOfFragments) {
fragment = StatsAbstractFragment.newInstance(StatsViewType.AUTHORS, mSite.getId(),
mCurrentTimeframe, mRequestedDate);
ft.replace(R.id.stats_top_authors_container, fragment, StatsAuthorsFragment.TAG);
}
if (fm.findFragmentByTag(StatsVideoplaysFragment.TAG) == null || forceRecreationOfFragments) {
fragment = StatsAbstractFragment.newInstance(StatsViewType.VIDEO_PLAYS, mSite.getId(),
mCurrentTimeframe, mRequestedDate);
ft.replace(R.id.stats_video_container, fragment, StatsVideoplaysFragment.TAG);
}
if (fm.findFragmentByTag(StatsSearchTermsFragment.TAG) == null || forceRecreationOfFragments) {
fragment = StatsAbstractFragment.newInstance(StatsViewType.SEARCH_TERMS, mSite.getId(),
mCurrentTimeframe, mRequestedDate);
ft.replace(R.id.stats_search_terms_container, fragment, StatsSearchTermsFragment.TAG);
}
} else {
findViewById(R.id.stats_timeline_fragments_container).setVisibility(View.GONE);
findViewById(R.id.stats_insights_fragments_container).setVisibility(View.VISIBLE);
if (fm.findFragmentByTag(StatsInsightsMostPopularFragment.TAG) == null || forceRecreationOfFragments) {
fragment = StatsAbstractFragment.newInstance(StatsViewType.INSIGHTS_MOST_POPULAR, mSite.getId(),
mCurrentTimeframe, mRequestedDate);
ft.replace(R.id.stats_insights_most_popular_container, fragment, StatsInsightsMostPopularFragment.TAG);
}
if (fm.findFragmentByTag(StatsInsightsAllTimeFragment.TAG) == null || forceRecreationOfFragments) {
fragment = StatsAbstractFragment.newInstance(StatsViewType.INSIGHTS_ALL_TIME, mSite.getId(),
mCurrentTimeframe, mRequestedDate);
ft.replace(R.id.stats_insights_all_time_container, fragment, StatsInsightsAllTimeFragment.TAG);
}
if (fm.findFragmentByTag(StatsInsightsTodayFragment.TAG) == null || forceRecreationOfFragments) {
fragment = StatsAbstractFragment.newInstance(StatsViewType.INSIGHTS_TODAY, mSite.getId(),
StatsTimeframe.DAY, mRequestedDate);
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, mSite.getId(),
mCurrentTimeframe, mRequestedDate);
ft.replace(R.id.stats_insights_latest_post_summary_container, fragment, StatsInsightsLatestPostSummaryFragment.TAG);
}
if (fm.findFragmentByTag(StatsCommentsFragment.TAG) == null || forceRecreationOfFragments) {
fragment = StatsAbstractFragment.newInstance(StatsViewType.COMMENTS, mSite.getId(),
mCurrentTimeframe, mRequestedDate);
ft.replace(R.id.stats_comments_container, fragment, StatsCommentsFragment.TAG);
}
if (fm.findFragmentByTag(StatsTagsAndCategoriesFragment.TAG) == null || forceRecreationOfFragments) {
fragment = StatsAbstractFragment.newInstance(StatsViewType.TAGS_AND_CATEGORIES, mSite.getId(),
mCurrentTimeframe, mRequestedDate);
ft.replace(R.id.stats_tags_and_categories_container, fragment, StatsTagsAndCategoriesFragment.TAG);
}
if (fm.findFragmentByTag(StatsPublicizeFragment.TAG) == null || forceRecreationOfFragments) {
fragment = StatsAbstractFragment.newInstance(StatsViewType.PUBLICIZE, mSite.getId(),
mCurrentTimeframe, mRequestedDate);
ft.replace(R.id.stats_publicize_container, fragment, StatsPublicizeFragment.TAG);
}
if (fm.findFragmentByTag(StatsFollowersFragment.TAG) == null || forceRecreationOfFragments) {
fragment = StatsAbstractFragment.newInstance(StatsViewType.FOLLOWERS, mSite.getId(),
mCurrentTimeframe, mRequestedDate);
ft.replace(R.id.stats_followers_container, fragment, StatsFollowersFragment.TAG);
}
}
ft.commitAllowingStateLoss();
// Slightly delayed labels setup: see https://github.com/wordpress-mobile/WordPress-Android/issues/3279
mOuterScrollView.postDelayed(new Runnable() {
@Override
public void run() {
if (isFinishing()) {
return;
}
boolean isInsights = mCurrentTimeframe == StatsTimeframe.INSIGHTS;
findViewById(R.id.stats_other_recent_stats_label_insights).setVisibility(isInsights ? View.VISIBLE : View.GONE);
findViewById(R.id.stats_other_recent_stats_label_timeline).setVisibility(isInsights ? View.GONE : View.VISIBLE);
findViewById(R.id.stats_other_recent_stats_moved).setVisibility(isInsights ? View.GONE : View.VISIBLE);
}
}, StatsConstants.STATS_LABELS_SETUP_DELAY);
}
private void updateTimeframeAndDateAndStartRefreshOfFragments(boolean includeGraph) {
if (isFinishing()) {
return;
}
FragmentManager fm = getFragmentManager();
if (mCurrentTimeframe != StatsTimeframe.INSIGHTS) {
updateTimeframeAndDateAndStartRefreshInFragment(fm, StatsTopPostsAndPagesFragment.TAG);
updateTimeframeAndDateAndStartRefreshInFragment(fm, StatsReferrersFragment.TAG);
updateTimeframeAndDateAndStartRefreshInFragment(fm, StatsClicksFragment.TAG);
updateTimeframeAndDateAndStartRefreshInFragment(fm, StatsGeoviewsFragment.TAG);
updateTimeframeAndDateAndStartRefreshInFragment(fm, StatsAuthorsFragment.TAG);
updateTimeframeAndDateAndStartRefreshInFragment(fm, StatsVideoplaysFragment.TAG);
updateTimeframeAndDateAndStartRefreshInFragment(fm, StatsSearchTermsFragment.TAG);
if (includeGraph) {
updateTimeframeAndDateAndStartRefreshInFragment(fm, StatsVisitorsAndViewsFragment.TAG);
}
} else {
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);
updateTimeframeAndDateAndStartRefreshInFragment(fm, StatsFollowersFragment.TAG);
}
}
private boolean updateTimeframeAndDateAndStartRefreshInFragment(FragmentManager fm , String fragmentTAG) {
StatsAbstractFragment fragment = (StatsAbstractFragment) fm.findFragmentByTag(fragmentTAG);
if (fragment != null) {
fragment.setDate(mRequestedDate);
fragment.setTimeframe(mCurrentTimeframe);
fragment.refreshStats();
return true;
}
return false;
}
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
if (requestCode == SignInActivity.REQUEST_CODE) {
if (resultCode == RESULT_CANCELED) {
finish();
}
}
if (requestCode == RequestCodes.REQUEST_JETPACK) {
// Refresh the site in case we're back from Jetpack install Webview
mDispatcher.dispatch(SiteActionBuilder.newFetchSiteAction(mSite));
}
}
@Override
public boolean onOptionsItemSelected(MenuItem item) {
int i = item.getItemId();
if (i == android.R.id.home) {
onBackPressed();
return true;
}
return super.onOptionsItemSelected(item);
}
private void scrollToTop() {
mOuterScrollView.fullScroll(ScrollView.FOCUS_UP);
}
// StatsInsightsTodayFragment calls this when the user taps on a item in Today's Stats
@Override
public void onInsightsTodayClicked(final StatsVisitorsAndViewsFragment.OverviewLabel item) {
mTabToSelectOnGraph = item;
for (int i = 0; i < timeframes.length; i++) {
if (timeframes[i] == StatsTimeframe.DAY) {
mSpinner.setSelection(i);
break;
}
}
}
private void refreshStatsFromCurrentDate() {
if (mIsUpdatingStats) {
AppLog.w(T.STATS, "stats are already updating, refresh cancelled");
return;
}
mRequestedDate = StatsUtils.getCurrentDateTZ(mSite);
updateTimeframeAndDateAndStartRefreshOfFragments(true);
}
// StatsVisitorsAndViewsFragment calls this when the user taps on a bar in the graph
@Override
public void onDateChanged(long siteId, StatsTimeframe timeframe, String date) {
if (isFinishing()) {
return;
}
mRequestedDate = date;
updateTimeframeAndDateAndStartRefreshOfFragments(false);
if (NetworkUtils.checkConnection(StatsActivity.this)) {
mSwipeToRefreshHelper.setRefreshing(true);
} else {
mSwipeToRefreshHelper.setRefreshing(false);
}
}
// StatsVisitorsAndViewsFragment calls this when the user taps on the tab bar to change the type of the graph
@Override
public void onOverviewItemChanged(StatsVisitorsAndViewsFragment.OverviewLabel newItem) {
mTabToSelectOnGraph = newItem;
}
private void bumpPromoAnalyticsAndShowPromoDialogIfNecessary() {
if (mIsUpdatingStats || mThereWasAnErrorLoadingStats) {
// Do nothing in case of errors or when it's still loading
return;
}
if (!StringUtils.isEmpty(AppPrefs.getStatsWidgetsKeys())) {
// Stats widgets already used!!
return;
}
// Bump analytics that drives the Promo widget when the loading is completed without errors.
AppPrefs.bumpAnalyticsForStatsWidgetPromo();
// Should we display the widget promo?
int counter = AppPrefs.getAnalyticsForStatsWidgetPromo();
if (counter == 3 || counter == 1000 || counter == 10000) {
AppCompatDialogFragment newFragment = PromoDialog.newInstance(R.drawable.stats_widget_promo_header,
R.string.stats_widget_promo_title, R.string.stats_widget_promo_desc,
R.string.stats_widget_promo_ok_btn_label);
newFragment.show(getSupportFragmentManager(), "promote_widget_dialog");
}
}
@SuppressWarnings("unused")
public void onEventMainThread(StatsEvents.UpdateStatusChanged event) {
if (isFinishing() || !mIsInFront) {
return;
}
mSwipeToRefreshHelper.setRefreshing(event.mUpdating);
mIsUpdatingStats = event.mUpdating;
if (!mIsUpdatingStats && !mThereWasAnErrorLoadingStats) {
// Do not bump promo analytics or show the dialog in case of errors or when it's still loading
bumpPromoAnalyticsAndShowPromoDialogIfNecessary();
}
}
@SuppressWarnings("unused")
public void onEventMainThread(StatsEvents.SectionUpdateError event) {
// There was an error loading Stats. Don't bump stats for promo widget.
if (isFinishing() || !mIsInFront) {
return;
}
// There was an error loading Stats. Don't bump stats for promo widget.
mThereWasAnErrorLoadingStats = true;
}
/*
* make sure the passed timeframe is the one selected in the actionbar
*/
private void selectCurrentTimeframeInActionBar() {
if (isFinishing()) {
return;
}
if (mTimeframeSpinnerAdapter == null || mSpinner == null) {
return;
}
int position = mTimeframeSpinnerAdapter.getIndexOfTimeframe(mCurrentTimeframe);
if (position > -1 && position != mSpinner.getSelectedItemPosition()) {
mSpinner.setSelection(position);
}
}
/*
* adapter used by the timeframe spinner
*/
private class TimeframeSpinnerAdapter extends BaseAdapter {
private final StatsTimeframe[] mTimeframes;
private final LayoutInflater mInflater;
TimeframeSpinnerAdapter(Context context, StatsTimeframe[] timeframeNames) {
super();
mInflater = (LayoutInflater)context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
mTimeframes = timeframeNames;
}
@Override
public int getCount() {
return (mTimeframes != null ? mTimeframes.length : 0);
}
@Override
public Object getItem(int position) {
if (position < 0 || position >= getCount())
return "";
return mTimeframes[position];
}
@Override
public long getItemId(int position) {
return position;
}
@Override
public View getView(int position, View convertView, ViewGroup parent) {
final View view;
if (convertView == null) {
view = mInflater.inflate(R.layout.filter_spinner_item, parent, false);
} else {
view = convertView;
}
final TextView text = (TextView) view.findViewById(R.id.text);
StatsTimeframe selectedTimeframe = (StatsTimeframe)getItem(position);
text.setText(selectedTimeframe.getLabel());
return view;
}
@Override
public View getDropDownView(int position, View convertView, ViewGroup parent) {
StatsTimeframe selectedTimeframe = (StatsTimeframe)getItem(position);
final TagViewHolder holder;
if (convertView == null) {
convertView = mInflater.inflate(R.layout.toolbar_spinner_dropdown_item, parent, false);
holder = new TagViewHolder(convertView);
convertView.setTag(holder);
} else {
holder = (TagViewHolder) convertView.getTag();
}
holder.textView.setText(selectedTimeframe.getLabel());
return convertView;
}
private class TagViewHolder {
private final TextView textView;
TagViewHolder(View view) {
textView = (TextView) view.findViewById(R.id.text);
}
}
public int getIndexOfTimeframe(StatsTimeframe tm) {
int pos = 0;
for (int i = 0; i < mTimeframes.length; i++) {
if (mTimeframes[i] == tm) {
pos = i;
return pos;
}
}
return pos;
}
}
@Override
public void onScrollChanged(NestedScrollViewExt scrollView, int x, int y, int oldx, int oldy) {
// We take the last son in the scrollview
View view = scrollView.getChildAt(scrollView.getChildCount() - 1);
if (view == null) {
return;
}
int diff = (view.getBottom() - (scrollView.getHeight() + scrollView.getScrollY() + view.getTop()));
// if diff is zero, then the bottom has been reached
if (diff == 0) {
sTrackBottomReachedStats.runIfNotLimited();
}
}
private static final RateLimitedTask sTrackBottomReachedStats = new RateLimitedTask(2) {
protected boolean run() {
AnalyticsTracker.track(AnalyticsTracker.Stat.STATS_SCROLLED_TO_BOTTOM);
return true;
}
};
// FluxC events
@SuppressWarnings("unused")
@Subscribe(threadMode = ThreadMode.MAIN)
public void onSiteChanged(OnSiteChanged event) {
// "Reload" current site from the db, would be smarter if the OnSiteChanged provided the list of changed sites.
SiteModel site = mSiteStore.getSiteByLocalId(mSite.getId());
if (site != null) {
mSite = site;
}
// Make sure the update site is accessible
checkIfSiteHasAccessibleStats(mSite);
// Refresh Stats
refreshStatsFromCurrentDate();
}
}