From 0a44f5186641b91f52dc37f65795f0e9821af713 Mon Sep 17 00:00:00 2001 From: Klymentiy haykov Date: Mon, 24 Jun 2019 16:38:49 -0500 Subject: [PATCH 01/15] Adding a 10 seconds delay between completion of AT and fetching of plugin directory. --- .../android/ui/plugins/PluginDetailActivity.java | 16 ++++++++++++---- 1 file changed, 12 insertions(+), 4 deletions(-) diff --git a/WordPress/src/main/java/org/wordpress/android/ui/plugins/PluginDetailActivity.java b/WordPress/src/main/java/org/wordpress/android/ui/plugins/PluginDetailActivity.java index 9e11d23f43e2..9fef3503a3db 100644 --- a/WordPress/src/main/java/org/wordpress/android/ui/plugins/PluginDetailActivity.java +++ b/WordPress/src/main/java/org/wordpress/android/ui/plugins/PluginDetailActivity.java @@ -1514,10 +1514,18 @@ public void onSiteChanged(OnSiteChanged event) { // We try to fetch the site after Automated Transfer is completed so that we can fetch its plugins. If // we are still showing the AT progress and the site is AT site, we can continue with plugins fetch if (mSite.isAutomatedTransfer()) { - AppLog.v(T.PLUGINS, "Site is successfully fetched after Automated Transfer, fetching the site plugins " - + "to complete the process..."); - mDispatcher.dispatch(PluginActionBuilder.newFetchPluginDirectoryAction(new PluginStore - .FetchPluginDirectoryPayload(PluginDirectoryType.SITE, mSite, false))); + // There is a little bit of delay after AT is completed and plugin installation is reflected on + // server side, so we delay fetching plugin directory to accommodate this + mHandler.postDelayed(new Runnable() { + @Override + public void run() { + AppLog.v(T.PLUGINS, + "Site is successfully fetched after Automated Transfer, fetching the site plugins " + + "to complete the process..."); + mDispatcher.dispatch(PluginActionBuilder.newFetchPluginDirectoryAction(new PluginStore + .FetchPluginDirectoryPayload(PluginDirectoryType.SITE, mSite, false))); + } + }, 10000); } else { // Either an error occurred while fetching the site or Automated Transfer is not yet reflected in the // API response. We need to keep fetching the site until we get the updated site. Otherwise, any changes From 2ee6582628c70e553728ac4cdea791e07f8e4486 Mon Sep 17 00:00:00 2001 From: Klymentiy haykov Date: Tue, 25 Jun 2019 21:58:15 -0700 Subject: [PATCH 02/15] Added retry logic for fetching plugin directory. Removed "Congrats" screen after domain registration. Start plugin installation imidiately after domain registration is complete. --- .../android/ui/ActivityLauncher.java | 9 ++ .../wordpress/android/ui/RequestCodes.java | 1 + .../ui/domains/DomainRegistrationActivity.kt | 41 +++++-- .../DomainRegistrationResultFragment.kt | 2 + .../ui/plugins/PluginDetailActivity.java | 101 +++++++++++++----- WordPress/src/main/res/values/strings.xml | 2 + 6 files changed, 117 insertions(+), 39 deletions(-) diff --git a/WordPress/src/main/java/org/wordpress/android/ui/ActivityLauncher.java b/WordPress/src/main/java/org/wordpress/android/ui/ActivityLauncher.java index f9188015476f..c56379d7c049 100644 --- a/WordPress/src/main/java/org/wordpress/android/ui/ActivityLauncher.java +++ b/WordPress/src/main/java/org/wordpress/android/ui/ActivityLauncher.java @@ -36,6 +36,7 @@ import org.wordpress.android.ui.activitylog.list.ActivityLogListActivity; import org.wordpress.android.ui.comments.CommentsActivity; import org.wordpress.android.ui.domains.DomainRegistrationActivity; +import org.wordpress.android.ui.domains.DomainRegistrationActivity.DomainRegistrationPurpose; import org.wordpress.android.ui.giphy.GiphyPickerActivity; import org.wordpress.android.ui.history.HistoryDetailActivity; import org.wordpress.android.ui.history.HistoryDetailContainerFragment; @@ -414,6 +415,14 @@ public static void viewDomainRegistrationActivity(Activity activity, SiteModel s activity.startActivity(intent); } + public static void viewDomainRegistrationActivityForResult(Activity activity, SiteModel site, + DomainRegistrationPurpose purpose) { + Intent intent = new Intent(activity, DomainRegistrationActivity.class); + intent.putExtra(WordPress.SITE, site); + intent.putExtra(DomainRegistrationActivity.DOMAIN_REGISTRATION_PURPOSE_KEY, purpose); + activity.startActivityForResult(intent, RequestCodes.DOMAIN_REGISTRATION); + } + public static void viewActivityLogList(Activity activity, SiteModel site) { if (site == null) { ToastUtils.showToast(activity, R.string.blog_not_found, ToastUtils.Duration.SHORT); diff --git a/WordPress/src/main/java/org/wordpress/android/ui/RequestCodes.java b/WordPress/src/main/java/org/wordpress/android/ui/RequestCodes.java index d4fb98a8e5c8..a278f9ad5633 100644 --- a/WordPress/src/main/java/org/wordpress/android/ui/RequestCodes.java +++ b/WordPress/src/main/java/org/wordpress/android/ui/RequestCodes.java @@ -25,6 +25,7 @@ public class RequestCodes { public static final int ACTIVITY_LOG_DETAIL = 1700; public static final int PAGE_PARENT = 1800; public static final int HISTORY_DETAIL = 1900; + public static final int DOMAIN_REGISTRATION = 2000; // Media public static final int PICTURE_LIBRARY = 2000; diff --git a/WordPress/src/main/java/org/wordpress/android/ui/domains/DomainRegistrationActivity.kt b/WordPress/src/main/java/org/wordpress/android/ui/domains/DomainRegistrationActivity.kt index f6d46f0875d3..92d782a758db 100644 --- a/WordPress/src/main/java/org/wordpress/android/ui/domains/DomainRegistrationActivity.kt +++ b/WordPress/src/main/java/org/wordpress/android/ui/domains/DomainRegistrationActivity.kt @@ -1,17 +1,33 @@ package org.wordpress.android.ui.domains +import android.app.Activity import android.os.Bundle import android.view.MenuItem import androidx.appcompat.app.AppCompatActivity import kotlinx.android.synthetic.main.toolbar.* import org.wordpress.android.R +import org.wordpress.android.ui.domains.DomainRegistrationActivity.DomainRegistrationPurpose.CTA_DOMAIN_CREDIT_REDEMPTION class DomainRegistrationActivity : AppCompatActivity(), DomainRegistrationStepsListener { + enum class DomainRegistrationPurpose { + AUTOMATED_TRANSFER, + CTA_DOMAIN_CREDIT_REDEMPTION + } + + companion object { + const val DOMAIN_REGISTRATION_PURPOSE_KEY = "DOMAIN_REGISTRATION_PURPOSE_KEY" + } + + var domainRegistrationPurpose: DomainRegistrationPurpose? = null + override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContentView(R.layout.activity_domain_suggestions_activity) + domainRegistrationPurpose = intent.getSerializableExtra(DOMAIN_REGISTRATION_PURPOSE_KEY) + as DomainRegistrationPurpose + setSupportActionBar(toolbar) supportActionBar?.let { it.setHomeButtonEnabled(true) @@ -50,15 +66,20 @@ class DomainRegistrationActivity : AppCompatActivity(), DomainRegistrationStepsL } override fun onDomainRegistered(domainName: String) { - supportFragmentManager.beginTransaction() - .setCustomAnimations( - R.anim.activity_slide_in_from_right, R.anim.activity_slide_out_to_left, - R.anim.activity_slide_in_from_left, R.anim.activity_slide_out_to_right - ) - .replace( - R.id.fragment_container, - DomainRegistrationResultFragment.newInstance(domainName) - ) - .commit() + if (domainRegistrationPurpose == null || domainRegistrationPurpose == CTA_DOMAIN_CREDIT_REDEMPTION) { + supportFragmentManager.beginTransaction() + .setCustomAnimations( + R.anim.activity_slide_in_from_right, R.anim.activity_slide_out_to_left, + R.anim.activity_slide_in_from_left, R.anim.activity_slide_out_to_right + ) + .replace( + R.id.fragment_container, + DomainRegistrationResultFragment.newInstance(domainName) + ) + .commit() + } else { + setResult(Activity.RESULT_OK) + finish() + } } } diff --git a/WordPress/src/main/java/org/wordpress/android/ui/domains/DomainRegistrationResultFragment.kt b/WordPress/src/main/java/org/wordpress/android/ui/domains/DomainRegistrationResultFragment.kt index 6524c1a787b2..119093d9ea1a 100644 --- a/WordPress/src/main/java/org/wordpress/android/ui/domains/DomainRegistrationResultFragment.kt +++ b/WordPress/src/main/java/org/wordpress/android/ui/domains/DomainRegistrationResultFragment.kt @@ -1,5 +1,6 @@ package org.wordpress.android.ui.domains +import android.app.Activity import android.os.Bundle import android.view.LayoutInflater import android.view.View @@ -41,6 +42,7 @@ class DomainRegistrationResultFragment : Fragment() { checkNotNull((activity?.application as WordPress).component()) continue_button.setOnClickListener { + activity!!.setResult(Activity.RESULT_OK) activity!!.finish() } diff --git a/WordPress/src/main/java/org/wordpress/android/ui/plugins/PluginDetailActivity.java b/WordPress/src/main/java/org/wordpress/android/ui/plugins/PluginDetailActivity.java index 9fef3503a3db..b8ebbc231b92 100644 --- a/WordPress/src/main/java/org/wordpress/android/ui/plugins/PluginDetailActivity.java +++ b/WordPress/src/main/java/org/wordpress/android/ui/plugins/PluginDetailActivity.java @@ -1,10 +1,12 @@ package org.wordpress.android.ui.plugins; import android.animation.ObjectAnimator; +import android.app.Activity; import android.app.Dialog; import android.app.ProgressDialog; import android.content.Context; import android.content.DialogInterface; +import android.content.Intent; import android.os.Bundle; import android.os.Handler; import android.text.Html; @@ -71,6 +73,8 @@ import org.wordpress.android.fluxc.store.SiteStore.OnPlansFetched; import org.wordpress.android.fluxc.store.SiteStore.OnSiteChanged; import org.wordpress.android.ui.ActivityLauncher; +import org.wordpress.android.ui.RequestCodes; +import org.wordpress.android.ui.domains.DomainRegistrationActivity.DomainRegistrationPurpose; import org.wordpress.android.util.AniUtils; import org.wordpress.android.util.AppLog; import org.wordpress.android.util.AppLog.T; @@ -119,6 +123,10 @@ public class PluginDetailActivity extends AppCompatActivity implements OnDomainR = "KEY_IS_SHOWING_AUTOMATED_TRANSFER_PROGRESS"; private static final String KEY_IS_SHOWING_DOMAIN_CREDIT_CHECK_PROGRESS = "KEY_IS_SHOWING_DOMAIN_CREDIT_CHECK_PROGRESS"; + private static final String KEY_PLUGIN_RECHECKED_TIMES = "KEY_PLUGIN_RECHECKED_TIMES"; + + private static final int MAX_PLUGIN_CHECK_TRIES = 10; + private static final int RETRY_DELAY_MS = 3000; private SiteModel mSite; private String mSlug; @@ -162,6 +170,8 @@ public class PluginDetailActivity extends AppCompatActivity implements OnDomainR protected boolean mIsShowingInstallFirstPluginConfirmationDialog; protected boolean mIsShowingAutomatedTransferProgress; + private int mPluginReCheckTimer = 0; + // These flags reflects the UI state protected boolean mIsActive; protected boolean mIsAutoUpdateEnabled; @@ -226,6 +236,7 @@ public void onCreate(Bundle savedInstanceState) { .getBoolean(KEY_IS_SHOWING_AUTOMATED_TRANSFER_PROGRESS); isShowingDomainCreditCheckProgress = savedInstanceState .getBoolean(KEY_IS_SHOWING_DOMAIN_CREDIT_CHECK_PROGRESS); + mPluginReCheckTimer = savedInstanceState.getInt(KEY_PLUGIN_RECHECKED_TIMES, 0); } setContentView(R.layout.plugin_detail_activity); @@ -310,7 +321,22 @@ public void onPlansFetched(OnPlansFetched event) { @Override public void onDomainRegistrationRequested() { - ActivityLauncher.viewDomainRegistrationActivity(this, mSite); + ActivityLauncher.viewDomainRegistrationActivityForResult(this, mSite, + DomainRegistrationPurpose.AUTOMATED_TRANSFER); + } + + @Override + protected void onActivityResult(int requestCode, int resultCode, @Nullable Intent data) { + super.onActivityResult(requestCode, resultCode, data); + if (requestCode == RequestCodes.DOMAIN_REGISTRATION) { + if (resultCode != Activity.RESULT_OK || isFinishing()) { + return; + } + showAutomatedTransferProgressDialog(); + AppLog.v(T.PLUGINS, "Domain Registration step of Automated Transfer is completed." + + " Initiating the transfer..."); + initiateAutomatedTransferProcess(); + } } public static class DomainRegistrationPromptDialog extends DialogFragment { @@ -412,6 +438,7 @@ public void onSaveInstanceState(Bundle outState) { outState.putBoolean(KEY_IS_SHOWING_AUTOMATED_TRANSFER_PROGRESS, mIsShowingAutomatedTransferProgress); outState.putBoolean(KEY_IS_SHOWING_DOMAIN_CREDIT_CHECK_PROGRESS, mCheckingDomainCreditsProgressDialog != null && mCheckingDomainCreditsProgressDialog.isShowing()); + outState.putInt(KEY_PLUGIN_RECHECKED_TIMES, mPluginReCheckTimer); } // UI Helpers @@ -1403,12 +1430,16 @@ public void onAutomatedTransferEligibilityChecked(OnAutomatedTransferEligibility } } else { AppLog.v(T.PLUGINS, "The site is eligible for Automated Transfer. Initiating the transfer..."); - AnalyticsUtils.trackWithSiteDetails(Stat.AUTOMATED_TRANSFER_INITIATE, mSite); - mDispatcher.dispatch(SiteActionBuilder - .newInitiateAutomatedTransferAction(new InitiateAutomatedTransferPayload(mSite, mSlug))); + initiateAutomatedTransferProcess(); } } + private void initiateAutomatedTransferProcess() { + AnalyticsUtils.trackWithSiteDetails(Stat.AUTOMATED_TRANSFER_INITIATE, mSite); + mDispatcher.dispatch(SiteActionBuilder + .newInitiateAutomatedTransferAction(new InitiateAutomatedTransferPayload(mSite, mSlug))); + } + /** * After we check the eligibility of a site, the Automated Transfer will be initiated. This is its callback and it * should be a fairly quick one, that's why we are not updating the progress bar. The event contains the plugin that @@ -1483,7 +1514,7 @@ public void run() { // Wait 3 seconds before checking the status again mDispatcher.dispatch(SiteActionBuilder.newCheckAutomatedTransferStatusAction(mSite)); } - }, 3000); + }, RETRY_DELAY_MS); } } } @@ -1514,18 +1545,10 @@ public void onSiteChanged(OnSiteChanged event) { // We try to fetch the site after Automated Transfer is completed so that we can fetch its plugins. If // we are still showing the AT progress and the site is AT site, we can continue with plugins fetch if (mSite.isAutomatedTransfer()) { - // There is a little bit of delay after AT is completed and plugin installation is reflected on - // server side, so we delay fetching plugin directory to accommodate this - mHandler.postDelayed(new Runnable() { - @Override - public void run() { - AppLog.v(T.PLUGINS, - "Site is successfully fetched after Automated Transfer, fetching the site plugins " - + "to complete the process..."); - mDispatcher.dispatch(PluginActionBuilder.newFetchPluginDirectoryAction(new PluginStore - .FetchPluginDirectoryPayload(PluginDirectoryType.SITE, mSite, false))); - } - }, 10000); + AppLog.v(T.PLUGINS, + "Site is successfully fetched after Automated Transfer, fetching the site plugins " + + "to complete the process..."); + fetchPluginDirectory(0); } else { // Either an error occurred while fetching the site or Automated Transfer is not yet reflected in the // API response. We need to keep fetching the site until we get the updated site. Otherwise, any changes @@ -1540,7 +1563,7 @@ public void run() { // Wait 3 seconds before fetching the site again mDispatcher.dispatch(SiteActionBuilder.newFetchSiteAction(mSite)); } - }, 3000); + }, RETRY_DELAY_MS); } } } @@ -1559,26 +1582,34 @@ public void onPluginDirectoryFetched(OnPluginDirectoryFetched event) { if (isFinishing()) { return; } + + refreshPluginFromStore(); + if (event.isError()) { if (mIsShowingAutomatedTransferProgress) { AppLog.e(T.PLUGINS, "Fetching the plugin directory after Automated Transfer has failed with error type" + event.error.type + " and message: " + event.error.message); // Although unlikely, fetching the plugins after a successful Automated Transfer can result in an error. // This should hopefully be an edge case and fetching the plugins again should - mHandler.postDelayed(new Runnable() { - @Override - public void run() { - AppLog.v(T.PLUGINS, "Fetching the site plugins again after Automated Transfer since the" - + " changes are not yet reflected"); - // Wait 3 seconds before fetching the site plugins again - mDispatcher.dispatch(PluginActionBuilder.newFetchPluginDirectoryAction(new PluginStore - .FetchPluginDirectoryPayload(PluginDirectoryType.SITE, mSite, false))); - } - }, 3000); + fetchPluginDirectory(RETRY_DELAY_MS); } // We are safe to ignore the errors for this event unless it's for Automated Transfer since that's the only // one triggered in this page and only one we care about. return; + } else if (!mPlugin.isInstalled()) { + // it sometimes take a bit of time for plugin to get marked as installed, especially when + // Automated Transfer is performed right after domain registration + if (mIsShowingAutomatedTransferProgress) { + if (mPluginReCheckTimer < MAX_PLUGIN_CHECK_TRIES) { + fetchPluginDirectory(RETRY_DELAY_MS); + mPluginReCheckTimer++; + return; + } else { + // if plugin is still not marked as installed, we ask user to check back later, and proceed to + // finish Automated Transfer + ToastUtils.showToast(this, R.string.plugin_fetching_error_after_at, Duration.LONG); + } + } } if (event.type == PluginDirectoryType.SITE && mIsShowingAutomatedTransferProgress) { // After Automated Transfer flow is completed, we fetch the site and then it's plugins. The only way site's @@ -1588,11 +1619,23 @@ public void run() { } else { // Although it's unlikely that a directory might be fetched while we are in the plugin detail page, we // should be safe to refresh the plugin and the view in case the plugin we are showing has changed - refreshPluginFromStore(); refreshViews(); } } + private void fetchPluginDirectory(int delay) { + mHandler.postDelayed(new Runnable() { + @Override + public void run() { + AppLog.v(T.PLUGINS, "Fetching the site plugins again after Automated Transfer since the" + + " changes are not yet reflected"); + // Wait 3 seconds before fetching the site plugins again + mDispatcher.dispatch(PluginActionBuilder.newFetchPluginDirectoryAction(new PluginStore + .FetchPluginDirectoryPayload(PluginDirectoryType.SITE, mSite, false))); + } + }, delay); + } + private String getEligibilityErrorMessage(String errorCode) { int errorMessageRes; switch (errorCode) { diff --git a/WordPress/src/main/res/values/strings.xml b/WordPress/src/main/res/values/strings.xml index a516a371459d..b9e9b41c8379 100644 --- a/WordPress/src/main/res/values/strings.xml +++ b/WordPress/src/main/res/values/strings.xml @@ -2063,6 +2063,8 @@ External link Toggle text + It takes longer then usual to refresh plugin details. Please check again later. + My Profile First name From e40005ed440f82714cc83cb900e283633db024e9 Mon Sep 17 00:00:00 2001 From: Klymentiy haykov Date: Tue, 25 Jun 2019 22:15:08 -0700 Subject: [PATCH 03/15] Fixed request code, updated logging, removed redundant code. --- .../org/wordpress/android/ui/RequestCodes.java | 4 +++- .../ui/domains/DomainRegistrationResultFragment.kt | 2 -- .../android/ui/plugins/PluginDetailActivity.java | 14 +++++++------- 3 files changed, 10 insertions(+), 10 deletions(-) diff --git a/WordPress/src/main/java/org/wordpress/android/ui/RequestCodes.java b/WordPress/src/main/java/org/wordpress/android/ui/RequestCodes.java index a278f9ad5633..3860953e1eee 100644 --- a/WordPress/src/main/java/org/wordpress/android/ui/RequestCodes.java +++ b/WordPress/src/main/java/org/wordpress/android/ui/RequestCodes.java @@ -25,7 +25,6 @@ public class RequestCodes { public static final int ACTIVITY_LOG_DETAIL = 1700; public static final int PAGE_PARENT = 1800; public static final int HISTORY_DETAIL = 1900; - public static final int DOMAIN_REGISTRATION = 2000; // Media public static final int PICTURE_LIBRARY = 2000; @@ -47,4 +46,7 @@ public class RequestCodes { public static final int QUICK_START_REMINDER_NOTIFICATION = 4001; public static final int GIPHY_PICKER = 3200; + + // Domain Registration + public static final int DOMAIN_REGISTRATION = 5000; } diff --git a/WordPress/src/main/java/org/wordpress/android/ui/domains/DomainRegistrationResultFragment.kt b/WordPress/src/main/java/org/wordpress/android/ui/domains/DomainRegistrationResultFragment.kt index 119093d9ea1a..6524c1a787b2 100644 --- a/WordPress/src/main/java/org/wordpress/android/ui/domains/DomainRegistrationResultFragment.kt +++ b/WordPress/src/main/java/org/wordpress/android/ui/domains/DomainRegistrationResultFragment.kt @@ -1,6 +1,5 @@ package org.wordpress.android.ui.domains -import android.app.Activity import android.os.Bundle import android.view.LayoutInflater import android.view.View @@ -42,7 +41,6 @@ class DomainRegistrationResultFragment : Fragment() { checkNotNull((activity?.application as WordPress).component()) continue_button.setOnClickListener { - activity!!.setResult(Activity.RESULT_OK) activity!!.finish() } diff --git a/WordPress/src/main/java/org/wordpress/android/ui/plugins/PluginDetailActivity.java b/WordPress/src/main/java/org/wordpress/android/ui/plugins/PluginDetailActivity.java index b8ebbc231b92..fadf0216497c 100644 --- a/WordPress/src/main/java/org/wordpress/android/ui/plugins/PluginDetailActivity.java +++ b/WordPress/src/main/java/org/wordpress/android/ui/plugins/PluginDetailActivity.java @@ -1545,10 +1545,9 @@ public void onSiteChanged(OnSiteChanged event) { // We try to fetch the site after Automated Transfer is completed so that we can fetch its plugins. If // we are still showing the AT progress and the site is AT site, we can continue with plugins fetch if (mSite.isAutomatedTransfer()) { - AppLog.v(T.PLUGINS, - "Site is successfully fetched after Automated Transfer, fetching the site plugins " - + "to complete the process..."); - fetchPluginDirectory(0); + AppLog.v(T.PLUGINS, "Site is successfully fetched after Automated Transfer, fetching" + + " the site plugins to complete the process..."); + fetchPluginDirectory(0); } else { // Either an error occurred while fetching the site or Automated Transfer is not yet reflected in the // API response. We need to keep fetching the site until we get the updated site. Otherwise, any changes @@ -1591,6 +1590,8 @@ public void onPluginDirectoryFetched(OnPluginDirectoryFetched event) { + event.error.type + " and message: " + event.error.message); // Although unlikely, fetching the plugins after a successful Automated Transfer can result in an error. // This should hopefully be an edge case and fetching the plugins again should + AppLog.v(T.PLUGINS, "Fetching the site plugins again after Automated Transfer since the" + + " changes are not yet reflected"); fetchPluginDirectory(RETRY_DELAY_MS); } // We are safe to ignore the errors for this event unless it's for Automated Transfer since that's the only @@ -1601,6 +1602,8 @@ public void onPluginDirectoryFetched(OnPluginDirectoryFetched event) { // Automated Transfer is performed right after domain registration if (mIsShowingAutomatedTransferProgress) { if (mPluginReCheckTimer < MAX_PLUGIN_CHECK_TRIES) { + AppLog.v(T.PLUGINS, "Targeted plugin is not marked as installed after Automated Transfer." + + " Fetching the site plugins to reflect the changes."); fetchPluginDirectory(RETRY_DELAY_MS); mPluginReCheckTimer++; return; @@ -1627,9 +1630,6 @@ private void fetchPluginDirectory(int delay) { mHandler.postDelayed(new Runnable() { @Override public void run() { - AppLog.v(T.PLUGINS, "Fetching the site plugins again after Automated Transfer since the" - + " changes are not yet reflected"); - // Wait 3 seconds before fetching the site plugins again mDispatcher.dispatch(PluginActionBuilder.newFetchPluginDirectoryAction(new PluginStore .FetchPluginDirectoryPayload(PluginDirectoryType.SITE, mSite, false))); } From 0f531df0eb9bde91835f33311f0dce52b845f457 Mon Sep 17 00:00:00 2001 From: Klymentiy haykov Date: Tue, 25 Jun 2019 22:58:16 -0700 Subject: [PATCH 04/15] Increased plugin retry delay to 10 seconds. --- .../android/ui/plugins/PluginDetailActivity.java | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/WordPress/src/main/java/org/wordpress/android/ui/plugins/PluginDetailActivity.java b/WordPress/src/main/java/org/wordpress/android/ui/plugins/PluginDetailActivity.java index fadf0216497c..2e3438f1792e 100644 --- a/WordPress/src/main/java/org/wordpress/android/ui/plugins/PluginDetailActivity.java +++ b/WordPress/src/main/java/org/wordpress/android/ui/plugins/PluginDetailActivity.java @@ -126,7 +126,8 @@ public class PluginDetailActivity extends AppCompatActivity implements OnDomainR private static final String KEY_PLUGIN_RECHECKED_TIMES = "KEY_PLUGIN_RECHECKED_TIMES"; private static final int MAX_PLUGIN_CHECK_TRIES = 10; - private static final int RETRY_DELAY_MS = 3000; + private static final int DEFAULT_RETRY_DELAY_MS = 3000; + private static final int PLUGIN_RETRY_DELAY_MS = 10000; private SiteModel mSite; private String mSlug; @@ -1514,7 +1515,7 @@ public void run() { // Wait 3 seconds before checking the status again mDispatcher.dispatch(SiteActionBuilder.newCheckAutomatedTransferStatusAction(mSite)); } - }, RETRY_DELAY_MS); + }, DEFAULT_RETRY_DELAY_MS); } } } @@ -1562,7 +1563,7 @@ public void run() { // Wait 3 seconds before fetching the site again mDispatcher.dispatch(SiteActionBuilder.newFetchSiteAction(mSite)); } - }, RETRY_DELAY_MS); + }, DEFAULT_RETRY_DELAY_MS); } } } @@ -1592,7 +1593,7 @@ public void onPluginDirectoryFetched(OnPluginDirectoryFetched event) { // This should hopefully be an edge case and fetching the plugins again should AppLog.v(T.PLUGINS, "Fetching the site plugins again after Automated Transfer since the" + " changes are not yet reflected"); - fetchPluginDirectory(RETRY_DELAY_MS); + fetchPluginDirectory(PLUGIN_RETRY_DELAY_MS); } // We are safe to ignore the errors for this event unless it's for Automated Transfer since that's the only // one triggered in this page and only one we care about. @@ -1604,7 +1605,7 @@ public void onPluginDirectoryFetched(OnPluginDirectoryFetched event) { if (mPluginReCheckTimer < MAX_PLUGIN_CHECK_TRIES) { AppLog.v(T.PLUGINS, "Targeted plugin is not marked as installed after Automated Transfer." + " Fetching the site plugins to reflect the changes."); - fetchPluginDirectory(RETRY_DELAY_MS); + fetchPluginDirectory(PLUGIN_RETRY_DELAY_MS); mPluginReCheckTimer++; return; } else { From effc13941cc844de16744ee10f413f394218658c Mon Sep 17 00:00:00 2001 From: Klymentiy haykov Date: Wed, 26 Jun 2019 02:19:39 -0700 Subject: [PATCH 05/15] Added descriptive SSL error message, delay when registering domain name. --- .../ui/plugins/PluginDetailActivity.java | 20 ++++----- .../DomainRegistrationDetailsViewModel.kt | 45 ++++++++++++++++--- WordPress/src/main/res/values/strings.xml | 1 + 3 files changed, 49 insertions(+), 17 deletions(-) diff --git a/WordPress/src/main/java/org/wordpress/android/ui/plugins/PluginDetailActivity.java b/WordPress/src/main/java/org/wordpress/android/ui/plugins/PluginDetailActivity.java index 2e3438f1792e..b4f5a3d97da5 100644 --- a/WordPress/src/main/java/org/wordpress/android/ui/plugins/PluginDetailActivity.java +++ b/WordPress/src/main/java/org/wordpress/android/ui/plugins/PluginDetailActivity.java @@ -333,10 +333,7 @@ protected void onActivityResult(int requestCode, int resultCode, @Nullable Inten if (resultCode != Activity.RESULT_OK || isFinishing()) { return; } - showAutomatedTransferProgressDialog(); - AppLog.v(T.PLUGINS, "Domain Registration step of Automated Transfer is completed." - + " Initiating the transfer..."); - initiateAutomatedTransferProcess(); + startAutomatedTransfer(); } } @@ -1431,16 +1428,12 @@ public void onAutomatedTransferEligibilityChecked(OnAutomatedTransferEligibility } } else { AppLog.v(T.PLUGINS, "The site is eligible for Automated Transfer. Initiating the transfer..."); - initiateAutomatedTransferProcess(); + AnalyticsUtils.trackWithSiteDetails(Stat.AUTOMATED_TRANSFER_INITIATE, mSite); + mDispatcher.dispatch(SiteActionBuilder + .newInitiateAutomatedTransferAction(new InitiateAutomatedTransferPayload(mSite, mSlug))); } } - private void initiateAutomatedTransferProcess() { - AnalyticsUtils.trackWithSiteDetails(Stat.AUTOMATED_TRANSFER_INITIATE, mSite); - mDispatcher.dispatch(SiteActionBuilder - .newInitiateAutomatedTransferAction(new InitiateAutomatedTransferPayload(mSite, mSlug))); - } - /** * After we check the eligibility of a site, the Automated Transfer will be initiated. This is its callback and it * should be a fairly quick one, that's why we are not updating the progress bar. The event contains the plugin that @@ -1667,8 +1660,11 @@ private String getEligibilityErrorMessage(String errorCode) { case "site_private": errorMessageRes = R.string.plugin_install_site_ineligible_site_private; break; + case "no_ssl_certificate": + errorMessageRes = R.string.plugin_install_site_ineligible_no_ssl; + break; default: - // no_jetpack_sites, no_ssl_certificate, no_wpcom_nameservers, not_resolving_to_wpcom + // no_jetpack_sites, no_wpcom_nameservers, not_resolving_to_wpcom errorMessageRes = R.string.plugin_install_site_ineligible_default_error; break; } diff --git a/WordPress/src/main/java/org/wordpress/android/viewmodel/domains/DomainRegistrationDetailsViewModel.kt b/WordPress/src/main/java/org/wordpress/android/viewmodel/domains/DomainRegistrationDetailsViewModel.kt index 1e19d365b0b9..31a7848ee2a5 100644 --- a/WordPress/src/main/java/org/wordpress/android/viewmodel/domains/DomainRegistrationDetailsViewModel.kt +++ b/WordPress/src/main/java/org/wordpress/android/viewmodel/domains/DomainRegistrationDetailsViewModel.kt @@ -3,7 +3,9 @@ package org.wordpress.android.viewmodel.domains import android.text.TextUtils import androidx.lifecycle.LiveData import androidx.lifecycle.MutableLiveData -import androidx.lifecycle.ViewModel +import kotlinx.coroutines.CoroutineDispatcher +import kotlinx.coroutines.delay +import kotlinx.coroutines.launch import org.greenrobot.eventbus.Subscribe import org.greenrobot.eventbus.ThreadMode import org.wordpress.android.fluxc.Dispatcher @@ -16,6 +18,7 @@ import org.wordpress.android.fluxc.model.SiteModel import org.wordpress.android.fluxc.network.rest.wpcom.site.SupportedStateResponse import org.wordpress.android.fluxc.network.rest.wpcom.transactions.SupportedDomainCountry import org.wordpress.android.fluxc.store.AccountStore.OnDomainContactFetched +import org.wordpress.android.fluxc.store.SiteStore import org.wordpress.android.fluxc.store.SiteStore.OnDomainSupportedStatesFetched import org.wordpress.android.fluxc.store.SiteStore.OnSiteChanged import org.wordpress.android.fluxc.store.TransactionsStore @@ -25,21 +28,31 @@ import org.wordpress.android.fluxc.store.TransactionsStore.OnShoppingCartRedeeme import org.wordpress.android.fluxc.store.TransactionsStore.OnSupportedCountriesFetched import org.wordpress.android.fluxc.store.TransactionsStore.RedeemShoppingCartError import org.wordpress.android.fluxc.store.TransactionsStore.RedeemShoppingCartPayload +import org.wordpress.android.modules.UI_THREAD import org.wordpress.android.ui.domains.DomainProductDetails import org.wordpress.android.util.AppLog import org.wordpress.android.util.AppLog.T +import org.wordpress.android.viewmodel.ScopedViewModel import org.wordpress.android.viewmodel.SingleLiveEvent import javax.inject.Inject +import javax.inject.Named + +const val SITE_CHECK_DELAY_MS = 5000L +const val MAX_SITE_RETRIEVALS_TRIES = 10 class DomainRegistrationDetailsViewModel @Inject constructor( private val dispatcher: Dispatcher, - private val transactionsStore: TransactionsStore // needed for events to work -) : ViewModel() { + private val transactionsStore: TransactionsStore, // needed for events to work + private val siteStore: SiteStore, + @param:Named(UI_THREAD) private val uiDispatcher: CoroutineDispatcher +) : ScopedViewModel(uiDispatcher) { private lateinit var site: SiteModel private lateinit var domainProductDetails: DomainProductDetails private var isStarted = false + private var siteRetrievalsTries = 0 + private var supportedCountries: List? = null private val _supportedStates = MutableLiveData>() @@ -213,16 +226,38 @@ class DomainRegistrationDetailsViewModel @Inject constructor( @Subscribe(threadMode = ThreadMode.MAIN) fun onSiteChanged(event: OnSiteChanged) { - _uiState.value = uiState.value?.copy(isRegistrationProgressIndicatorVisible = false) if (event.isError) { AppLog.e( T.DOMAIN_REGISTRATION, "An error occurred while updating site details : " + event.error.message ) _showErrorMessage.value = event.error.message + _uiState.value = uiState.value?.copy(isRegistrationProgressIndicatorVisible = false) + _handleCompletedDomainRegistration.postValue(domainProductDetails.domainName) + return } - _handleCompletedDomainRegistration.postValue(domainProductDetails.domainName) + val updatedSite = siteStore.getSiteByLocalId(site.id) + + // New domain is not is not reflected in SiteModel yet, try refreshing a site until we get it + if (updatedSite.url.endsWith(".wordpress.com") && siteRetrievalsTries < MAX_SITE_RETRIEVALS_TRIES) { + AppLog.v( + T.DOMAIN_REGISTRATION, + "Newly registered domain is still not reflected in site model. Refreshing site model..." + ) + launch { + delay(SITE_CHECK_DELAY_MS) + dispatcher.dispatch(SiteActionBuilder.newFetchSiteAction(site)) + siteRetrievalsTries++ + } + } else { + // Everything looks good! Let's wait a bit before moving on + launch { + delay(SITE_CHECK_DELAY_MS) + _uiState.value = uiState.value?.copy(isRegistrationProgressIndicatorVisible = false) + _handleCompletedDomainRegistration.postValue(domainProductDetails.domainName) + } + } } fun onCountrySelectorClicked() { diff --git a/WordPress/src/main/res/values/strings.xml b/WordPress/src/main/res/values/strings.xml index b9e9b41c8379..4ea0bcf19376 100644 --- a/WordPress/src/main/res/values/strings.xml +++ b/WordPress/src/main/res/values/strings.xml @@ -2022,6 +2022,7 @@ Plugin feature requires a custom domain. Plugin feature requires a business plan. Plugin feature requires the site to be public. + Can\'t find SSL certificate. If you just registered a new domain name it may take us a few minutes to set it up. Plugin feature requires a verified email address. Plugin cannot be installed due to disk space limitations. Plugin cannot be installed on VIP sites. From 8fbb9187a86b4070976ffbaded4af2f1247231e2 Mon Sep 17 00:00:00 2001 From: Klymentiy haykov Date: Wed, 26 Jun 2019 02:22:12 -0700 Subject: [PATCH 06/15] Naming. --- .../domains/DomainRegistrationDetailsViewModel.kt | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/WordPress/src/main/java/org/wordpress/android/viewmodel/domains/DomainRegistrationDetailsViewModel.kt b/WordPress/src/main/java/org/wordpress/android/viewmodel/domains/DomainRegistrationDetailsViewModel.kt index 31a7848ee2a5..17a82bab93fe 100644 --- a/WordPress/src/main/java/org/wordpress/android/viewmodel/domains/DomainRegistrationDetailsViewModel.kt +++ b/WordPress/src/main/java/org/wordpress/android/viewmodel/domains/DomainRegistrationDetailsViewModel.kt @@ -38,7 +38,7 @@ import javax.inject.Inject import javax.inject.Named const val SITE_CHECK_DELAY_MS = 5000L -const val MAX_SITE_RETRIEVALS_TRIES = 10 +const val MAX_SITE_RETRIEVAL_TRIES = 10 class DomainRegistrationDetailsViewModel @Inject constructor( private val dispatcher: Dispatcher, @@ -51,7 +51,7 @@ class DomainRegistrationDetailsViewModel @Inject constructor( private var isStarted = false - private var siteRetrievalsTries = 0 + private var siteRetrievalTries = 0 private var supportedCountries: List? = null private val _supportedStates = MutableLiveData>() @@ -240,7 +240,7 @@ class DomainRegistrationDetailsViewModel @Inject constructor( val updatedSite = siteStore.getSiteByLocalId(site.id) // New domain is not is not reflected in SiteModel yet, try refreshing a site until we get it - if (updatedSite.url.endsWith(".wordpress.com") && siteRetrievalsTries < MAX_SITE_RETRIEVALS_TRIES) { + if (updatedSite.url.endsWith(".wordpress.com") && siteRetrievalTries < MAX_SITE_RETRIEVAL_TRIES) { AppLog.v( T.DOMAIN_REGISTRATION, "Newly registered domain is still not reflected in site model. Refreshing site model..." @@ -248,7 +248,7 @@ class DomainRegistrationDetailsViewModel @Inject constructor( launch { delay(SITE_CHECK_DELAY_MS) dispatcher.dispatch(SiteActionBuilder.newFetchSiteAction(site)) - siteRetrievalsTries++ + siteRetrievalTries++ } } else { // Everything looks good! Let's wait a bit before moving on From 4093d051b34b438c43e90d53fef5fc6821fad186 Mon Sep 17 00:00:00 2001 From: Klymentiy haykov Date: Wed, 26 Jun 2019 14:53:56 -0700 Subject: [PATCH 07/15] Changed action after domain registration and dispatching plugin configure action after AT. --- .../org/wordpress/android/ui/plugins/PluginDetailActivity.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/WordPress/src/main/java/org/wordpress/android/ui/plugins/PluginDetailActivity.java b/WordPress/src/main/java/org/wordpress/android/ui/plugins/PluginDetailActivity.java index b4f5a3d97da5..227401a8ed93 100644 --- a/WordPress/src/main/java/org/wordpress/android/ui/plugins/PluginDetailActivity.java +++ b/WordPress/src/main/java/org/wordpress/android/ui/plugins/PluginDetailActivity.java @@ -333,7 +333,7 @@ protected void onActivityResult(int requestCode, int resultCode, @Nullable Inten if (resultCode != Activity.RESULT_OK || isFinishing()) { return; } - startAutomatedTransfer(); + confirmInstallPluginForAutomatedTransfer(); } } @@ -1378,6 +1378,7 @@ private void automatedTransferCompleted() { AnalyticsUtils.trackWithSiteDetails(Stat.AUTOMATED_TRANSFER_FLOW_COMPLETE, mSite); cancelAutomatedTransferDialog(); refreshPluginFromStore(); + dispatchConfigurePluginAction(true); refreshViews(); showSuccessfulInstallSnackbar(); invalidateOptionsMenu(); From 79797c11b923baf028c26d06917e34104ed7016c Mon Sep 17 00:00:00 2001 From: Klymentiy haykov Date: Wed, 26 Jun 2019 14:54:23 -0700 Subject: [PATCH 08/15] Removed dedicated message for no ssl error in favor of more general one. --- .../wordpress/android/ui/plugins/PluginDetailActivity.java | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/WordPress/src/main/java/org/wordpress/android/ui/plugins/PluginDetailActivity.java b/WordPress/src/main/java/org/wordpress/android/ui/plugins/PluginDetailActivity.java index 227401a8ed93..22ff927386d0 100644 --- a/WordPress/src/main/java/org/wordpress/android/ui/plugins/PluginDetailActivity.java +++ b/WordPress/src/main/java/org/wordpress/android/ui/plugins/PluginDetailActivity.java @@ -1661,11 +1661,8 @@ private String getEligibilityErrorMessage(String errorCode) { case "site_private": errorMessageRes = R.string.plugin_install_site_ineligible_site_private; break; - case "no_ssl_certificate": - errorMessageRes = R.string.plugin_install_site_ineligible_no_ssl; - break; default: - // no_jetpack_sites, no_wpcom_nameservers, not_resolving_to_wpcom + // no_jetpack_sites, no_ssl_certificate, no_wpcom_nameservers, not_resolving_to_wpcom errorMessageRes = R.string.plugin_install_site_ineligible_default_error; break; } From d8453031d791281c986c300f40a9e0e3e850236b Mon Sep 17 00:00:00 2001 From: Klymentiy haykov Date: Wed, 26 Jun 2019 14:55:12 -0700 Subject: [PATCH 09/15] Manually setting domain as a primary after it registered. --- .../DomainRegistrationDetailsViewModel.kt | 26 +++++++++++++++++++ WordPress/src/main/res/values/strings.xml | 3 +-- build.gradle | 2 +- 3 files changed, 28 insertions(+), 3 deletions(-) diff --git a/WordPress/src/main/java/org/wordpress/android/viewmodel/domains/DomainRegistrationDetailsViewModel.kt b/WordPress/src/main/java/org/wordpress/android/viewmodel/domains/DomainRegistrationDetailsViewModel.kt index 17a82bab93fe..7dac7d1c7b4c 100644 --- a/WordPress/src/main/java/org/wordpress/android/viewmodel/domains/DomainRegistrationDetailsViewModel.kt +++ b/WordPress/src/main/java/org/wordpress/android/viewmodel/domains/DomainRegistrationDetailsViewModel.kt @@ -19,7 +19,9 @@ import org.wordpress.android.fluxc.network.rest.wpcom.site.SupportedStateRespons import org.wordpress.android.fluxc.network.rest.wpcom.transactions.SupportedDomainCountry import org.wordpress.android.fluxc.store.AccountStore.OnDomainContactFetched import org.wordpress.android.fluxc.store.SiteStore +import org.wordpress.android.fluxc.store.SiteStore.DesignatePrimaryDomainPayload import org.wordpress.android.fluxc.store.SiteStore.OnDomainSupportedStatesFetched +import org.wordpress.android.fluxc.store.SiteStore.OnPrimaryDomainDesignated import org.wordpress.android.fluxc.store.SiteStore.OnSiteChanged import org.wordpress.android.fluxc.store.TransactionsStore import org.wordpress.android.fluxc.store.TransactionsStore.CreateShoppingCartPayload @@ -221,6 +223,30 @@ class DomainRegistrationDetailsViewModel @Inject constructor( return } + launch { + delay(SITE_CHECK_DELAY_MS) + dispatcher.dispatch( + SiteActionBuilder.newDesignatePrimaryDomainAction( + DesignatePrimaryDomainPayload( + site, + domainProductDetails.domainName + ) + ) + ) + } + } + + @Subscribe(threadMode = ThreadMode.MAIN) + fun onPrimaryDomainDesignated(event: OnPrimaryDomainDesignated) { + if (event.isError) { + _showErrorMessage.value = event.error.message + AppLog.e( + T.DOMAIN_REGISTRATION, + "An error occurred while redeeming a shopping cart : " + event.error.type + + " " + event.error.message + ) + } + dispatcher.dispatch(SiteActionBuilder.newFetchSiteAction(site)) } diff --git a/WordPress/src/main/res/values/strings.xml b/WordPress/src/main/res/values/strings.xml index 4ea0bcf19376..00d7807d7ff9 100644 --- a/WordPress/src/main/res/values/strings.xml +++ b/WordPress/src/main/res/values/strings.xml @@ -2018,11 +2018,10 @@ - Plugin feature is not available for this site. + Plugin feature is not available for this site. If you just registered a domain name, it might take us a few minutes to set it up. Plugin feature requires a custom domain. Plugin feature requires a business plan. Plugin feature requires the site to be public. - Can\'t find SSL certificate. If you just registered a new domain name it may take us a few minutes to set it up. Plugin feature requires a verified email address. Plugin cannot be installed due to disk space limitations. Plugin cannot be installed on VIP sites. diff --git a/build.gradle b/build.gradle index 027fad70bd24..ac680a2cf474 100644 --- a/build.gradle +++ b/build.gradle @@ -105,5 +105,5 @@ buildScan { ext { daggerVersion = '2.22.1' - fluxCVersion = 'f49752fbd271e8c745b58fd28de20c2106a29ce9' + fluxCVersion = '2b5eb6db391180e3eeba8fd36196b62d712f43c5' } From 58baf9e0802a1372b15ed10837b905472bea5ada Mon Sep 17 00:00:00 2001 From: Klymentiy haykov Date: Wed, 26 Jun 2019 14:55:29 -0700 Subject: [PATCH 10/15] Updated tests. --- .../util/NoDelayCoroutineDispatcher.kt | 19 ++++++ .../DomainRegistrationDetailsViewModelTest.kt | 60 ++++++++++++++++--- 2 files changed, 72 insertions(+), 7 deletions(-) create mode 100644 WordPress/src/test/java/org/wordpress/android/util/NoDelayCoroutineDispatcher.kt diff --git a/WordPress/src/test/java/org/wordpress/android/util/NoDelayCoroutineDispatcher.kt b/WordPress/src/test/java/org/wordpress/android/util/NoDelayCoroutineDispatcher.kt new file mode 100644 index 000000000000..8614bc1c5194 --- /dev/null +++ b/WordPress/src/test/java/org/wordpress/android/util/NoDelayCoroutineDispatcher.kt @@ -0,0 +1,19 @@ +package org.wordpress.android.util + +import kotlinx.coroutines.CancellableContinuation +import kotlinx.coroutines.CoroutineDispatcher +import kotlinx.coroutines.Delay +import kotlinx.coroutines.InternalCoroutinesApi +import kotlin.coroutines.CoroutineContext +import kotlin.coroutines.resume + +@UseExperimental(InternalCoroutinesApi::class) +class NoDelayCoroutineDispatcher : CoroutineDispatcher(), Delay { + override fun scheduleResumeAfterDelay(timeMillis: Long, continuation: CancellableContinuation) { + continuation.resume(Unit) + } + + override fun dispatch(context: CoroutineContext, block: Runnable) { + block.run() // dispatch on calling thread + } +} \ No newline at end of file diff --git a/WordPress/src/test/java/org/wordpress/android/viewmodel/domains/DomainRegistrationDetailsViewModelTest.kt b/WordPress/src/test/java/org/wordpress/android/viewmodel/domains/DomainRegistrationDetailsViewModelTest.kt index 1a85cfd8f40d..14f063f5dd80 100644 --- a/WordPress/src/test/java/org/wordpress/android/viewmodel/domains/DomainRegistrationDetailsViewModelTest.kt +++ b/WordPress/src/test/java/org/wordpress/android/viewmodel/domains/DomainRegistrationDetailsViewModelTest.kt @@ -3,6 +3,7 @@ package org.wordpress.android.viewmodel.domains import androidx.lifecycle.Observer import com.nhaarman.mockitokotlin2.any import com.nhaarman.mockitokotlin2.argWhere +import com.nhaarman.mockitokotlin2.doReturn import com.nhaarman.mockitokotlin2.times import com.nhaarman.mockitokotlin2.verify import com.nhaarman.mockitokotlin2.whenever @@ -29,9 +30,14 @@ import org.wordpress.android.fluxc.network.rest.wpcom.transactions.TransactionsR import org.wordpress.android.fluxc.store.AccountStore.DomainContactError import org.wordpress.android.fluxc.store.AccountStore.DomainContactErrorType import org.wordpress.android.fluxc.store.AccountStore.OnDomainContactFetched +import org.wordpress.android.fluxc.store.SiteStore +import org.wordpress.android.fluxc.store.SiteStore.DesignatePrimaryDomainError +import org.wordpress.android.fluxc.store.SiteStore.DesignatePrimaryDomainErrorType +import org.wordpress.android.fluxc.store.SiteStore.DesignatePrimaryDomainPayload import org.wordpress.android.fluxc.store.SiteStore.DomainSupportedStatesError import org.wordpress.android.fluxc.store.SiteStore.DomainSupportedStatesErrorType import org.wordpress.android.fluxc.store.SiteStore.OnDomainSupportedStatesFetched +import org.wordpress.android.fluxc.store.SiteStore.OnPrimaryDomainDesignated import org.wordpress.android.fluxc.store.SiteStore.OnSiteChanged import org.wordpress.android.fluxc.store.SiteStore.SiteError import org.wordpress.android.fluxc.store.SiteStore.SiteErrorType @@ -49,12 +55,14 @@ import org.wordpress.android.fluxc.store.TransactionsStore.RedeemShoppingCartPay import org.wordpress.android.fluxc.store.TransactionsStore.TransactionErrorType.PHONE import org.wordpress.android.test import org.wordpress.android.ui.domains.DomainProductDetails +import org.wordpress.android.util.NoDelayCoroutineDispatcher import org.wordpress.android.viewmodel.domains.DomainRegistrationDetailsViewModel.DomainRegistrationDetailsUiState class DomainRegistrationDetailsViewModelTest : BaseUnitTest() { - @Mock private lateinit var store: TransactionsStore + @Mock private lateinit var transactionsStore: TransactionsStore + @Mock private lateinit var siteStore: SiteStore @Mock private lateinit var dispatcher: Dispatcher - @Mock private lateinit var site: SiteModel + private var site: SiteModel = SiteModel() @Mock private lateinit var domainContactDetailsObserver: Observer @Mock private lateinit var countryPickerDialogObserver: Observer> @@ -98,6 +106,10 @@ class DomainRegistrationDetailsViewModelTest : BaseUnitTest() { private val shoppingCartCreateError = CreateShoppingCartError(GENERIC_ERROR, "Error Creating Cart") private val shoppingCartRedeemError = RedeemShoppingCartError(PHONE, "Wrong phone number") private val siteChangedError = SiteError(SiteErrorType.GENERIC_ERROR, "Error fetching site") + private val primaryDomainError = DesignatePrimaryDomainError( + DesignatePrimaryDomainErrorType.GENERIC_ERROR, + "Error designating primary domain" + ) private val domainContactInformationFetchError = DomainContactError( DomainContactErrorType.GENERIC_ERROR, "Error fetching domain contact information" @@ -122,8 +134,16 @@ class DomainRegistrationDetailsViewModelTest : BaseUnitTest() { @Before fun setUp() { site.siteId = siteId + site.url = testDomainName + + whenever(siteStore.getSiteByLocalId(any())).doReturn(site) - viewModel = DomainRegistrationDetailsViewModel(dispatcher, store) + viewModel = DomainRegistrationDetailsViewModel( + dispatcher, + transactionsStore, + siteStore, + NoDelayCoroutineDispatcher() + ) // Setting up chain of actions setupFetchSupportedCountriesDispatcher(false) setupFetchDomainContactInformationDispatcher(false) @@ -131,6 +151,7 @@ class DomainRegistrationDetailsViewModelTest : BaseUnitTest() { setupCreateShoppingCartDispatcher(false) setupRedeemShoppingCartDispatcher(false) setupFetchSiteDispatcher(false) + setupPrimaryDomainDispatcher(false) uiStateResults.clear() viewModel.uiState.observeForever { if (it != null) uiStateResults.add(it) } @@ -402,17 +423,19 @@ class DomainRegistrationDetailsViewModelTest : BaseUnitTest() { viewModel.onRegisterDomainButtonClicked() + assertThat(viewModel.domainContactDetails.value?.countryCode).isEqualTo(primaryCountry.code) assertThat(viewModel.domainContactDetails.value?.state).isEqualTo(primaryState.code) val captor = ArgumentCaptor.forClass(Action::class.java) - verify(dispatcher, times(6)).dispatch(captor.capture()) + verify(dispatcher, times(7)).dispatch(captor.capture()) val actionsDispatched = captor.allValues validateCreateCartAction(actionsDispatched[3]) validateRedeemCartAction(actionsDispatched[4]) - validateFetchSiteAction(actionsDispatched[5]) + validateDesignatePrimaryDomainActions(actionsDispatched[5]) + validateFetchSiteAction(actionsDispatched[6]) assertThat(uiStateResults.size).isEqualTo(2) @@ -488,13 +511,14 @@ class DomainRegistrationDetailsViewModelTest : BaseUnitTest() { viewModel.onRegisterDomainButtonClicked() val captor = ArgumentCaptor.forClass(Action::class.java) - verify(dispatcher, times(6)).dispatch(captor.capture()) + verify(dispatcher, times(7)).dispatch(captor.capture()) val actionsDispatched = captor.allValues validateCreateCartAction(actionsDispatched[3]) validateRedeemCartAction(actionsDispatched[4]) - validateFetchSiteAction(actionsDispatched[5]) + validateDesignatePrimaryDomainActions(actionsDispatched[5]) + validateFetchSiteAction(actionsDispatched[6]) assertThat(uiStateResults.size).isEqualTo(2) @@ -618,6 +642,18 @@ class DomainRegistrationDetailsViewModelTest : BaseUnitTest() { } } + private fun setupPrimaryDomainDispatcher(isError: Boolean) { + val event = OnPrimaryDomainDesignated(site, isError) + if (isError) { + event.error = primaryDomainError + } + whenever(dispatcher.dispatch(argWhere> { + it.type == SiteAction.DESIGNATE_PRIMARY_DOMAIN + })).then { + viewModel.onPrimaryDomainDesignated(event) + } + } + private fun validateFetchSupportedCountriesAction(action: Action<*>) { assertThat(action.type).isEqualTo(FETCH_SUPPORTED_COUNTRIES) assertThat(action.payload).isNull() @@ -664,6 +700,16 @@ class DomainRegistrationDetailsViewModelTest : BaseUnitTest() { assertThat(fetchSitePayload).isEqualTo(site) } + private fun validateDesignatePrimaryDomainActions(action: Action<*>) { + assertThat(action.type).isEqualTo(SiteAction.DESIGNATE_PRIMARY_DOMAIN) + assertThat(action.payload).isNotNull + assertThat(action.payload).isInstanceOf(DesignatePrimaryDomainPayload::class.java) + + val designatePrimaryDomainPayload = action.payload as DesignatePrimaryDomainPayload + assertThat(designatePrimaryDomainPayload.site).isEqualTo(site) + assertThat(designatePrimaryDomainPayload.domain).isEqualTo(testDomainName) + } + private fun clearPreLoadUiStateResult() { uiStateResults.clear() } From 0491d03b5d3e0d9d683274213ab98c782f5fdf87 Mon Sep 17 00:00:00 2001 From: Klymentiy haykov Date: Wed, 26 Jun 2019 15:16:57 -0700 Subject: [PATCH 11/15] Fixed checkstyle issues, naming. --- .../domains/DomainRegistrationDetailsViewModel.kt | 11 ++++++----- .../android/util/NoDelayCoroutineDispatcher.kt | 2 +- .../domains/DomainRegistrationDetailsViewModelTest.kt | 1 - 3 files changed, 7 insertions(+), 7 deletions(-) diff --git a/WordPress/src/main/java/org/wordpress/android/viewmodel/domains/DomainRegistrationDetailsViewModel.kt b/WordPress/src/main/java/org/wordpress/android/viewmodel/domains/DomainRegistrationDetailsViewModel.kt index 7dac7d1c7b4c..f6dc46f00b6b 100644 --- a/WordPress/src/main/java/org/wordpress/android/viewmodel/domains/DomainRegistrationDetailsViewModel.kt +++ b/WordPress/src/main/java/org/wordpress/android/viewmodel/domains/DomainRegistrationDetailsViewModel.kt @@ -40,7 +40,7 @@ import javax.inject.Inject import javax.inject.Named const val SITE_CHECK_DELAY_MS = 5000L -const val MAX_SITE_RETRIEVAL_TRIES = 10 +const val MAX_SITE_CHECK_TRIES = 10 class DomainRegistrationDetailsViewModel @Inject constructor( private val dispatcher: Dispatcher, @@ -53,7 +53,7 @@ class DomainRegistrationDetailsViewModel @Inject constructor( private var isStarted = false - private var siteRetrievalTries = 0 + private var siteCheckTries = 0 private var supportedCountries: List? = null private val _supportedStates = MutableLiveData>() @@ -223,6 +223,7 @@ class DomainRegistrationDetailsViewModel @Inject constructor( return } + // after cart is redeemed, wait for a bit before manually setting domain as primary launch { delay(SITE_CHECK_DELAY_MS) dispatcher.dispatch( @@ -238,7 +239,7 @@ class DomainRegistrationDetailsViewModel @Inject constructor( @Subscribe(threadMode = ThreadMode.MAIN) fun onPrimaryDomainDesignated(event: OnPrimaryDomainDesignated) { - if (event.isError) { + if (event.isError) { // in case of error we notify used and proceed to next step _showErrorMessage.value = event.error.message AppLog.e( T.DOMAIN_REGISTRATION, @@ -266,7 +267,7 @@ class DomainRegistrationDetailsViewModel @Inject constructor( val updatedSite = siteStore.getSiteByLocalId(site.id) // New domain is not is not reflected in SiteModel yet, try refreshing a site until we get it - if (updatedSite.url.endsWith(".wordpress.com") && siteRetrievalTries < MAX_SITE_RETRIEVAL_TRIES) { + if (updatedSite.url.endsWith(".wordpress.com") && siteCheckTries < MAX_SITE_CHECK_TRIES) { AppLog.v( T.DOMAIN_REGISTRATION, "Newly registered domain is still not reflected in site model. Refreshing site model..." @@ -274,7 +275,7 @@ class DomainRegistrationDetailsViewModel @Inject constructor( launch { delay(SITE_CHECK_DELAY_MS) dispatcher.dispatch(SiteActionBuilder.newFetchSiteAction(site)) - siteRetrievalTries++ + siteCheckTries++ } } else { // Everything looks good! Let's wait a bit before moving on diff --git a/WordPress/src/test/java/org/wordpress/android/util/NoDelayCoroutineDispatcher.kt b/WordPress/src/test/java/org/wordpress/android/util/NoDelayCoroutineDispatcher.kt index 8614bc1c5194..11aec7c8acdd 100644 --- a/WordPress/src/test/java/org/wordpress/android/util/NoDelayCoroutineDispatcher.kt +++ b/WordPress/src/test/java/org/wordpress/android/util/NoDelayCoroutineDispatcher.kt @@ -16,4 +16,4 @@ class NoDelayCoroutineDispatcher : CoroutineDispatcher(), Delay { override fun dispatch(context: CoroutineContext, block: Runnable) { block.run() // dispatch on calling thread } -} \ No newline at end of file +} diff --git a/WordPress/src/test/java/org/wordpress/android/viewmodel/domains/DomainRegistrationDetailsViewModelTest.kt b/WordPress/src/test/java/org/wordpress/android/viewmodel/domains/DomainRegistrationDetailsViewModelTest.kt index 14f063f5dd80..5c5f4eded1d0 100644 --- a/WordPress/src/test/java/org/wordpress/android/viewmodel/domains/DomainRegistrationDetailsViewModelTest.kt +++ b/WordPress/src/test/java/org/wordpress/android/viewmodel/domains/DomainRegistrationDetailsViewModelTest.kt @@ -423,7 +423,6 @@ class DomainRegistrationDetailsViewModelTest : BaseUnitTest() { viewModel.onRegisterDomainButtonClicked() - assertThat(viewModel.domainContactDetails.value?.countryCode).isEqualTo(primaryCountry.code) assertThat(viewModel.domainContactDetails.value?.state).isEqualTo(primaryState.code) From 5d469e109d8c16432f5e5790d021cda9b4533bf5 Mon Sep 17 00:00:00 2001 From: Klymentiy haykov Date: Wed, 26 Jun 2019 15:21:37 -0700 Subject: [PATCH 12/15] Removed multispaces. --- .../org/wordpress/android/util/NoDelayCoroutineDispatcher.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/WordPress/src/test/java/org/wordpress/android/util/NoDelayCoroutineDispatcher.kt b/WordPress/src/test/java/org/wordpress/android/util/NoDelayCoroutineDispatcher.kt index 11aec7c8acdd..150806b57d6b 100644 --- a/WordPress/src/test/java/org/wordpress/android/util/NoDelayCoroutineDispatcher.kt +++ b/WordPress/src/test/java/org/wordpress/android/util/NoDelayCoroutineDispatcher.kt @@ -14,6 +14,6 @@ class NoDelayCoroutineDispatcher : CoroutineDispatcher(), Delay { } override fun dispatch(context: CoroutineContext, block: Runnable) { - block.run() // dispatch on calling thread + block.run() } } From afa7ffe96b87a9a84a8c00b77dcbf00ae211879e Mon Sep 17 00:00:00 2001 From: Klymentiy haykov Date: Thu, 27 Jun 2019 07:13:42 -0700 Subject: [PATCH 13/15] Null guard for DomainRegistrationPurpose passed with intent, private domainRegistrationPurpose. --- .../android/ui/domains/DomainRegistrationActivity.kt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/WordPress/src/main/java/org/wordpress/android/ui/domains/DomainRegistrationActivity.kt b/WordPress/src/main/java/org/wordpress/android/ui/domains/DomainRegistrationActivity.kt index 92d782a758db..7b877c54fc20 100644 --- a/WordPress/src/main/java/org/wordpress/android/ui/domains/DomainRegistrationActivity.kt +++ b/WordPress/src/main/java/org/wordpress/android/ui/domains/DomainRegistrationActivity.kt @@ -18,7 +18,7 @@ class DomainRegistrationActivity : AppCompatActivity(), DomainRegistrationStepsL const val DOMAIN_REGISTRATION_PURPOSE_KEY = "DOMAIN_REGISTRATION_PURPOSE_KEY" } - var domainRegistrationPurpose: DomainRegistrationPurpose? = null + private var domainRegistrationPurpose: DomainRegistrationPurpose? = null override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) @@ -26,7 +26,7 @@ class DomainRegistrationActivity : AppCompatActivity(), DomainRegistrationStepsL setContentView(R.layout.activity_domain_suggestions_activity) domainRegistrationPurpose = intent.getSerializableExtra(DOMAIN_REGISTRATION_PURPOSE_KEY) - as DomainRegistrationPurpose + as? DomainRegistrationPurpose setSupportActionBar(toolbar) supportActionBar?.let { From 28b390552cbcb3cf073a526c0c7a57722e634baf Mon Sep 17 00:00:00 2001 From: Klymentiy haykov Date: Thu, 27 Jun 2019 08:33:06 -0700 Subject: [PATCH 14/15] Updated error message handling. --- .../ui/plugins/PluginDetailActivity.java | 17 +++++++++++++++-- WordPress/src/main/res/values/strings.xml | 2 +- 2 files changed, 16 insertions(+), 3 deletions(-) diff --git a/WordPress/src/main/java/org/wordpress/android/ui/plugins/PluginDetailActivity.java b/WordPress/src/main/java/org/wordpress/android/ui/plugins/PluginDetailActivity.java index 22ff927386d0..921fb7b99c3b 100644 --- a/WordPress/src/main/java/org/wordpress/android/ui/plugins/PluginDetailActivity.java +++ b/WordPress/src/main/java/org/wordpress/android/ui/plugins/PluginDetailActivity.java @@ -43,6 +43,7 @@ import org.greenrobot.eventbus.Subscribe; import org.greenrobot.eventbus.ThreadMode; +import org.jetbrains.annotations.NotNull; import org.wordpress.android.BuildConfig; import org.wordpress.android.R; import org.wordpress.android.WordPress; @@ -75,6 +76,8 @@ import org.wordpress.android.ui.ActivityLauncher; import org.wordpress.android.ui.RequestCodes; import org.wordpress.android.ui.domains.DomainRegistrationActivity.DomainRegistrationPurpose; +import org.wordpress.android.ui.posts.BasicFragmentDialog; +import org.wordpress.android.ui.posts.BasicFragmentDialog.BasicDialogPositiveClickInterface; import org.wordpress.android.util.AniUtils; import org.wordpress.android.util.AppLog; import org.wordpress.android.util.AppLog.T; @@ -107,7 +110,8 @@ import javax.inject.Inject; -public class PluginDetailActivity extends AppCompatActivity implements OnDomainRegistrationRequestedListener { +public class PluginDetailActivity extends AppCompatActivity implements OnDomainRegistrationRequestedListener, + BasicDialogPositiveClickInterface { public static final String KEY_PLUGIN_SLUG = "KEY_PLUGIN_SLUG"; private static final String KEY_IS_CONFIGURING_PLUGIN = "KEY_IS_CONFIGURING_PLUGIN"; private static final String KEY_IS_INSTALLING_PLUGIN = "KEY_IS_INSTALLING_PLUGIN"; @@ -124,6 +128,7 @@ public class PluginDetailActivity extends AppCompatActivity implements OnDomainR private static final String KEY_IS_SHOWING_DOMAIN_CREDIT_CHECK_PROGRESS = "KEY_IS_SHOWING_DOMAIN_CREDIT_CHECK_PROGRESS"; private static final String KEY_PLUGIN_RECHECKED_TIMES = "KEY_PLUGIN_RECHECKED_TIMES"; + private static final String TAG_ERROR_DIALOG = "ERROR_DIALOG"; private static final int MAX_PLUGIN_CHECK_TRIES = 10; private static final int DEFAULT_RETRY_DELAY_MS = 3000; @@ -337,6 +342,11 @@ protected void onActivityResult(int requestCode, int resultCode, @Nullable Inten } } + @Override + public void onPositiveClicked(@NotNull String instanceTag) { + // do nothing + } + public static class DomainRegistrationPromptDialog extends DialogFragment { static final String DOMAIN_REGISTRATION_PROMPT_DIALOG_TAG = "DOMAIN_REGISTRATION_PROMPT_DIALOG"; @@ -1390,7 +1400,10 @@ private void automatedTransferCompleted() { */ private void handleAutomatedTransferFailed(String errorMessage) { cancelAutomatedTransferDialog(); - ToastUtils.showToast(this, errorMessage, Duration.LONG); + BasicFragmentDialog errorDialog = new BasicFragmentDialog(); + errorDialog.initialize(TAG_ERROR_DIALOG, null, errorMessage, + getString(R.string.dialog_button_ok), null, null); + errorDialog.show(getSupportFragmentManager(), TAG_ERROR_DIALOG); } /** diff --git a/WordPress/src/main/res/values/strings.xml b/WordPress/src/main/res/values/strings.xml index 00d7807d7ff9..87a933ab61d8 100644 --- a/WordPress/src/main/res/values/strings.xml +++ b/WordPress/src/main/res/values/strings.xml @@ -2018,7 +2018,7 @@ - Plugin feature is not available for this site. If you just registered a domain name, it might take us a few minutes to set it up. + If you just registered a domain name, please wait until we finish setting it up and try again.\n\nIf not, looks like something went wrong and plugin feature might not be available for this site. Plugin feature requires a custom domain. Plugin feature requires a business plan. Plugin feature requires the site to be public. From 066fd32e3baae70572e7da1ac6127ca23eae0886 Mon Sep 17 00:00:00 2001 From: Klymentiy haykov Date: Fri, 28 Jun 2019 07:39:05 -0700 Subject: [PATCH 15/15] Fresh flux-c commit hash. --- build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build.gradle b/build.gradle index ac680a2cf474..857c6d4550b3 100644 --- a/build.gradle +++ b/build.gradle @@ -105,5 +105,5 @@ buildScan { ext { daggerVersion = '2.22.1' - fluxCVersion = '2b5eb6db391180e3eeba8fd36196b62d712f43c5' + fluxCVersion = 'f07192bb7b8bf9aa7c5f8717988d9f17590a0db3' }