From 2341d26298942aea56ca910ef5fbb6700638b4f9 Mon Sep 17 00:00:00 2001 From: Danilo Ercoli Date: Sun, 10 Apr 2016 22:30:59 +0200 Subject: [PATCH 01/50] Use our logger in IabHelper --- .../android/ui/plans/util/IabHelper.java | 20 ++++--------------- 1 file changed, 4 insertions(+), 16 deletions(-) diff --git a/WordPress/src/main/java/org/wordpress/android/ui/plans/util/IabHelper.java b/WordPress/src/main/java/org/wordpress/android/ui/plans/util/IabHelper.java index 86bff92d00f8..530b2b689744 100644 --- a/WordPress/src/main/java/org/wordpress/android/ui/plans/util/IabHelper.java +++ b/WordPress/src/main/java/org/wordpress/android/ui/plans/util/IabHelper.java @@ -32,6 +32,7 @@ import com.android.vending.billing.IInAppBillingService; import org.json.JSONException; +import org.wordpress.android.util.AppLog; import java.util.ArrayList; import java.util.List; @@ -68,9 +69,6 @@ * */ public class IabHelper { - // Is debug logging enabled? - boolean mDebugLog = false; - String mDebugTag = "IabHelper"; // Is setup done? boolean mSetupDone = false; @@ -169,18 +167,8 @@ public IabHelper(Context ctx, String base64PublicKey) { logDebug("IAB helper created."); } - /** - * Enables or disable debug logging through LogCat. - */ - public void enableDebugLogging(boolean enable, String tag) { - checkNotDisposed(); - mDebugLog = enable; - mDebugTag = tag; - } - public void enableDebugLogging(boolean enable) { checkNotDisposed(); - mDebugLog = enable; } /** @@ -1037,14 +1025,14 @@ public void run() { } void logDebug(String msg) { - if (mDebugLog) Log.d(mDebugTag, msg); + AppLog.d(AppLog.T.PLANS, msg); } void logError(String msg) { - Log.e(mDebugTag, "In-app billing error: " + msg); + AppLog.d(AppLog.T.PLANS, "In-app billing error: " + msg); } void logWarn(String msg) { - Log.w(mDebugTag, "In-app billing warning: " + msg); + AppLog.w(AppLog.T.PLANS, "In-app billing warning: " + msg); } } From 9cda45df745e759a1c4aedbc0a91535a0d4a4277 Mon Sep 17 00:00:00 2001 From: Danilo Ercoli Date: Sun, 10 Apr 2016 22:31:17 +0200 Subject: [PATCH 02/50] Start integrating the store calls --- .../ui/plans/PlanPostPurchaseActivity.java | 2 + .../android/ui/plans/PlansActivity.java | 87 ++++++++++++++++--- 2 files changed, 77 insertions(+), 12 deletions(-) diff --git a/WordPress/src/main/java/org/wordpress/android/ui/plans/PlanPostPurchaseActivity.java b/WordPress/src/main/java/org/wordpress/android/ui/plans/PlanPostPurchaseActivity.java index 0264d113286f..a59357e151a4 100644 --- a/WordPress/src/main/java/org/wordpress/android/ui/plans/PlanPostPurchaseActivity.java +++ b/WordPress/src/main/java/org/wordpress/android/ui/plans/PlanPostPurchaseActivity.java @@ -37,6 +37,8 @@ public class PlanPostPurchaseActivity extends AppCompatActivity { static final int PAGE_NUMBER_THEMES = 3; // business only static final String ARG_IS_BUSINESS_PLAN = "is_business_plan"; + public static final String ARG_LOCAL_TABLE_BLOG_ID = "ARG_LOCAL_TABLE_BLOG_ID"; + public static final String ARG_PURCHASE_SKU = "ARG_PURCHASE_SKU"; private ViewPager mViewPager; private PageAdapter mPageAdapter; diff --git a/WordPress/src/main/java/org/wordpress/android/ui/plans/PlansActivity.java b/WordPress/src/main/java/org/wordpress/android/ui/plans/PlansActivity.java index 40bdd43c167f..ffb35a187336 100644 --- a/WordPress/src/main/java/org/wordpress/android/ui/plans/PlansActivity.java +++ b/WordPress/src/main/java/org/wordpress/android/ui/plans/PlansActivity.java @@ -21,13 +21,20 @@ import android.widget.TextView; import android.widget.Toast; +import org.json.JSONException; +import org.json.JSONObject; import org.wordpress.android.BuildConfig; import org.wordpress.android.R; import org.wordpress.android.WordPress; +import org.wordpress.android.models.AccountHelper; +import org.wordpress.android.models.Blog; import org.wordpress.android.ui.plans.adapters.PlansPagerAdapter; import org.wordpress.android.ui.plans.models.Plan; +import org.wordpress.android.ui.plans.util.IabException; import org.wordpress.android.ui.plans.util.IabHelper; import org.wordpress.android.ui.plans.util.IabResult; +import org.wordpress.android.ui.plans.util.Inventory; +import org.wordpress.android.ui.plans.util.Purchase; import org.wordpress.android.ui.prefs.AppPrefs; import org.wordpress.android.util.AniUtils; import org.wordpress.android.util.AppLog; @@ -35,6 +42,7 @@ import org.wordpress.android.widgets.WPViewPager; import java.io.Serializable; +import java.util.ArrayList; import java.util.List; import de.greenrobot.event.EventBus; @@ -43,6 +51,7 @@ public class PlansActivity extends AppCompatActivity { public static final String ARG_LOCAL_TABLE_BLOG_ID = "ARG_LOCAL_TABLE_BLOG_ID"; private static final String ARG_LOCAL_AVAILABLE_PLANS = "ARG_LOCAL_AVAILABLE_PLANS"; + private static final int PURCHASE_PLAN_REQUEST = 0; private int mLocalBlogID = -1; private Plan[] mAvailablePlans; @@ -136,7 +145,7 @@ public void onPause() { } private void updatePurchaseUI(int position) { - Plan plan = getPageAdapter().getPlan(position); + final Plan plan = getPageAdapter().getPlan(position); boolean showPurchaseButton; if (plan.isCurrentPlan()) { showPurchaseButton = false; @@ -155,7 +164,7 @@ private void updatePurchaseUI(int position) { containerPurchase.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { - startPurchaseProcess(); + startPurchaseProcess(plan); } }); } else { @@ -170,7 +179,7 @@ public void onClick(View v) { } private void setupPlansUI() { - if (mAvailablePlans == null || mAvailablePlans.length == 0) { + if (mAvailablePlans == null || mAvailablePlans.length == 0) { // This should never be called with empty plans. Toast.makeText(PlansActivity.this, R.string.plans_loading_error, Toast.LENGTH_LONG).show(); finish(); @@ -301,14 +310,69 @@ public boolean onOptionsItemSelected(MenuItem item) { return super.onOptionsItemSelected(item); } - private void startPurchaseProcess() { - // TODO: this should start the Google Play purchase process, for now it shows the - // post-purchase on-boarding + private void listPurchaseForTesting () { + ArrayList skuList = new ArrayList (); + skuList.add("test_plan_premium_001"); + skuList.add("danilo_test_plan_premium_sub_001"); + try { + Inventory inventory = mIabHelper.queryInventory(true, skuList, skuList); + for (String sku: skuList) { + if ( inventory.hasPurchase(sku) ) { + Purchase pur = inventory.getPurchase(sku); + AppLog.d(AppLog.T.PLANS, "Original purchase JSON " + pur.getOriginalJson()); + } + } + } catch (IabException e) { + AppLog.e(AppLog.T.PLANS, "Unable to load IAP details", e); + } + } + + private void startPurchaseProcess(Plan plan) { + //listPurchaseForTesting(); + + // TODO: remove when updated the rest api boolean isBusinessPlan = (mViewPager.getCurrentItem() == mViewPager.getAdapter().getCount() - 1); - Intent intent = new Intent(this, PlanPostPurchaseActivity.class); - intent.putExtra(PlanPostPurchaseActivity.ARG_IS_BUSINESS_PLAN, isBusinessPlan); - startActivity(intent); - finish(); + String sku = isBusinessPlan ? "sub_test_plan_business_001" : "sub_test_plan_premium_001"; + + Blog currentBlog = WordPress.getBlog(mLocalBlogID); + JSONObject extraData = new JSONObject(); + try { + extraData.put("blog_id", currentBlog.getDotComBlogId()); + extraData.put("user_id", AccountHelper.getDefaultAccount().getUserId()); + } catch (JSONException e) { + AppLog.e(AppLog.T.PLANS, "Can't add extra info to purchase data!", e); + } + + mIabHelper.launchSubscriptionPurchaseFlow(this, sku, PURCHASE_PLAN_REQUEST, + new IabHelper.OnIabPurchaseFinishedListener() { + public void onIabPurchaseFinished(IabResult result, Purchase info) { + if (result != null) { + AppLog.d(AppLog.T.PLANS, "IabResult: " + result.toString()); + if (result.isSuccess()) { + if (info != null) { + AppLog.d(AppLog.T.PLANS, "Purchase: " + info.toString()); + AppLog.d(AppLog.T.PLANS, "You have bought the " + info.getSku() + ". Excellent choice, adventurer!"); + boolean isBusinessPlan = (mViewPager.getCurrentItem() == mViewPager.getAdapter().getCount() - 1); + Intent intent = new Intent(PlansActivity.this, PlanPostPurchaseActivity.class); + intent.putExtra(PlanPostPurchaseActivity.ARG_IS_BUSINESS_PLAN, isBusinessPlan); + intent.putExtra(PlanPostPurchaseActivity.ARG_LOCAL_TABLE_BLOG_ID, mLocalBlogID); + intent.putExtra(PlanPostPurchaseActivity.ARG_PURCHASE_SKU, info.getSku()); + startActivity(intent); + } + } else { + // not a success. It seems that the buy activity already shows an error. + // or at least, it shows an error if you try to purchase a subscription you already own. + } + } + } + }, + extraData.toString()); + } + + @Override + protected void onActivityResult(int requestCode, int resultCode, Intent data) { + super.onActivityResult(requestCode, resultCode, data); + boolean handled = mIabHelper.handleActivityResult(requestCode, resultCode, data); } /* @@ -319,8 +383,7 @@ private void startPurchaseProcess() { private void startInAppBillingHelper() { mIabHelper = new IabHelper(this, BuildConfig.APP_LICENSE_KEY); if (BuildConfig.DEBUG) { - String tag = AppLog.TAG + "-" + AppLog.T.PLANS.toString(); - mIabHelper.enableDebugLogging(true, tag); + mIabHelper.enableDebugLogging(true); } try { mIabHelper.startSetup(new IabHelper.OnIabSetupFinishedListener() { From db846cf42c725bb99ef0a3c7f282035c55eabc41 Mon Sep 17 00:00:00 2001 From: Danilo Ercoli Date: Mon, 11 Apr 2016 17:50:20 +0200 Subject: [PATCH 03/50] Re-synch purchases with wpcom server on startup and periodically. (The user could have cancelled them on the PlayStore). Re-synch purchases when the user buys a subscription from the store. --- .../java/org/wordpress/android/WordPress.java | 18 +++ .../ui/plans/PlanPostPurchaseActivity.java | 2 - .../android/ui/plans/PlansActivity.java | 27 +--- .../android/ui/plans/UpdateIAPTask.java | 133 ++++++++++++++++++ .../android/ui/plans/util/Inventory.java | 6 +- 5 files changed, 159 insertions(+), 27 deletions(-) create mode 100644 WordPress/src/main/java/org/wordpress/android/ui/plans/UpdateIAPTask.java diff --git a/WordPress/src/main/java/org/wordpress/android/WordPress.java b/WordPress/src/main/java/org/wordpress/android/WordPress.java index 41fc5c1b98c3..47ff742a0f08 100644 --- a/WordPress/src/main/java/org/wordpress/android/WordPress.java +++ b/WordPress/src/main/java/org/wordpress/android/WordPress.java @@ -49,6 +49,8 @@ import org.wordpress.android.ui.accounts.helpers.UpdateBlogListTask.GenericUpdateBlogListTask; import org.wordpress.android.ui.notifications.utils.NotificationsUtils; import org.wordpress.android.ui.notifications.utils.SimperiumUtils; +import org.wordpress.android.ui.plans.PlansUtils; +import org.wordpress.android.ui.plans.UpdateIAPTask; import org.wordpress.android.ui.prefs.AppPrefs; import org.wordpress.android.ui.stats.StatsWidgetProvider; import org.wordpress.android.ui.stats.datasets.StatsDatabaseHelper; @@ -101,6 +103,7 @@ public class WordPress extends Application { private static final int SECONDS_BETWEEN_OPTIONS_UPDATE = 10 * 60; private static final int SECONDS_BETWEEN_BLOGLIST_UPDATE = 6 * 60 * 60; + private static final int SECONDS_BETWEEN_IAP_UPDATE = 5 * 60; private static final int SECONDS_BETWEEN_DELETE_STATS = 5 * 60; // 5 minutes private static Context mContext; @@ -134,6 +137,20 @@ protected boolean run() { } }; + /** + * Update IAPs. This need to be called to remove upgrades on wpcom side, those upgrades the user has already cancelled on mobile side + * (from the Google Store). + * + */ + public static RateLimitedTask sUpdateWordPressComIAP = new RateLimitedTask(SECONDS_BETWEEN_IAP_UPDATE) { + protected boolean run() { + if (AccountHelper.isSignedInWordPressDotCom()) { + new UpdateIAPTask(getContext()).executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR); + } + return true; + } + }; + /** * Delete stats cache that is already expired */ @@ -803,6 +820,7 @@ public void onAppComesFromBackground() { sUpdateCurrentBlogOption.runIfNotLimited(); } sDeleteExpiredStats.runIfNotLimited(); + sUpdateWordPressComIAP.forceRun(); // TODO: changes to run if not limited } @Override diff --git a/WordPress/src/main/java/org/wordpress/android/ui/plans/PlanPostPurchaseActivity.java b/WordPress/src/main/java/org/wordpress/android/ui/plans/PlanPostPurchaseActivity.java index a59357e151a4..0264d113286f 100644 --- a/WordPress/src/main/java/org/wordpress/android/ui/plans/PlanPostPurchaseActivity.java +++ b/WordPress/src/main/java/org/wordpress/android/ui/plans/PlanPostPurchaseActivity.java @@ -37,8 +37,6 @@ public class PlanPostPurchaseActivity extends AppCompatActivity { static final int PAGE_NUMBER_THEMES = 3; // business only static final String ARG_IS_BUSINESS_PLAN = "is_business_plan"; - public static final String ARG_LOCAL_TABLE_BLOG_ID = "ARG_LOCAL_TABLE_BLOG_ID"; - public static final String ARG_PURCHASE_SKU = "ARG_PURCHASE_SKU"; private ViewPager mViewPager; private PageAdapter mPageAdapter; diff --git a/WordPress/src/main/java/org/wordpress/android/ui/plans/PlansActivity.java b/WordPress/src/main/java/org/wordpress/android/ui/plans/PlansActivity.java index ffb35a187336..888bb5142c89 100644 --- a/WordPress/src/main/java/org/wordpress/android/ui/plans/PlansActivity.java +++ b/WordPress/src/main/java/org/wordpress/android/ui/plans/PlansActivity.java @@ -310,25 +310,7 @@ public boolean onOptionsItemSelected(MenuItem item) { return super.onOptionsItemSelected(item); } - private void listPurchaseForTesting () { - ArrayList skuList = new ArrayList (); - skuList.add("test_plan_premium_001"); - skuList.add("danilo_test_plan_premium_sub_001"); - try { - Inventory inventory = mIabHelper.queryInventory(true, skuList, skuList); - for (String sku: skuList) { - if ( inventory.hasPurchase(sku) ) { - Purchase pur = inventory.getPurchase(sku); - AppLog.d(AppLog.T.PLANS, "Original purchase JSON " + pur.getOriginalJson()); - } - } - } catch (IabException e) { - AppLog.e(AppLog.T.PLANS, "Unable to load IAP details", e); - } - } - private void startPurchaseProcess(Plan plan) { - //listPurchaseForTesting(); // TODO: remove when updated the rest api boolean isBusinessPlan = (mViewPager.getCurrentItem() == mViewPager.getAdapter().getCount() - 1); @@ -341,6 +323,7 @@ private void startPurchaseProcess(Plan plan) { extraData.put("user_id", AccountHelper.getDefaultAccount().getUserId()); } catch (JSONException e) { AppLog.e(AppLog.T.PLANS, "Can't add extra info to purchase data!", e); + return; } mIabHelper.launchSubscriptionPurchaseFlow(this, sku, PURCHASE_PLAN_REQUEST, @@ -350,18 +333,18 @@ public void onIabPurchaseFinished(IabResult result, Purchase info) { AppLog.d(AppLog.T.PLANS, "IabResult: " + result.toString()); if (result.isSuccess()) { if (info != null) { + WordPress.sUpdateWordPressComIAP.forceRun(); // refresh purchase on wpcom AppLog.d(AppLog.T.PLANS, "Purchase: " + info.toString()); AppLog.d(AppLog.T.PLANS, "You have bought the " + info.getSku() + ". Excellent choice, adventurer!"); boolean isBusinessPlan = (mViewPager.getCurrentItem() == mViewPager.getAdapter().getCount() - 1); Intent intent = new Intent(PlansActivity.this, PlanPostPurchaseActivity.class); intent.putExtra(PlanPostPurchaseActivity.ARG_IS_BUSINESS_PLAN, isBusinessPlan); - intent.putExtra(PlanPostPurchaseActivity.ARG_LOCAL_TABLE_BLOG_ID, mLocalBlogID); - intent.putExtra(PlanPostPurchaseActivity.ARG_PURCHASE_SKU, info.getSku()); startActivity(intent); } } else { - // not a success. It seems that the buy activity already shows an error. - // or at least, it shows an error if you try to purchase a subscription you already own. + AppLog.e(AppLog.T.PLANS, "Purchase failure " + result.getMessage()); + // Not a success. It seems that the buy activity already shows an error. + // Or at least, it shows an error if you try to purchase a subscription you already own. } } } diff --git a/WordPress/src/main/java/org/wordpress/android/ui/plans/UpdateIAPTask.java b/WordPress/src/main/java/org/wordpress/android/ui/plans/UpdateIAPTask.java new file mode 100644 index 000000000000..e0a7ec1f3c88 --- /dev/null +++ b/WordPress/src/main/java/org/wordpress/android/ui/plans/UpdateIAPTask.java @@ -0,0 +1,133 @@ +package org.wordpress.android.ui.plans; + +import android.content.Context; +import android.os.AsyncTask; + +import com.android.volley.VolleyError; +import com.wordpress.rest.RestRequest; + +import org.json.JSONException; +import org.json.JSONObject; +import org.wordpress.android.BuildConfig; +import org.wordpress.android.WordPress; +import org.wordpress.android.models.AccountHelper; +import org.wordpress.android.ui.plans.util.IabException; +import org.wordpress.android.ui.plans.util.IabHelper; +import org.wordpress.android.ui.plans.util.IabResult; +import org.wordpress.android.ui.plans.util.Inventory; +import org.wordpress.android.ui.plans.util.Purchase; +import org.wordpress.android.util.AppLog; + +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.concurrent.CountDownLatch; +import java.util.concurrent.TimeUnit; + +public class UpdateIAPTask extends AsyncTask { + private static final int GET_IAP_BINDER_TIMEOUT = 30000; + private static final String IAP_ENDPOINT = "/iap/refresh"; + protected Context mContext; + private IabHelper mIabHelper; + + public UpdateIAPTask(Context context) { + mContext = context; + } + + @Override + protected Void doInBackground(Void... args) { + if (!AccountHelper.isSignedInWordPressDotCom()) { + return null; + } + + final CountDownLatch countDownLatch = new CountDownLatch(1); + + mIabHelper = new IabHelper(this.mContext, BuildConfig.APP_LICENSE_KEY); + if (BuildConfig.DEBUG) { + mIabHelper.enableDebugLogging(true); + } + try { + mIabHelper.startSetup(new IabHelper.OnIabSetupFinishedListener() { + @Override + public void onIabSetupFinished(IabResult result) { + if (result.isSuccess()) { + AppLog.d(AppLog.T.PLANS, "IAB started successfully"); + } else { + AppLog.w(AppLog.T.PLANS, "IAB failed with " + result); + } + countDownLatch.countDown(); + } + }); + try { + countDownLatch.await(GET_IAP_BINDER_TIMEOUT, TimeUnit.MILLISECONDS); + } catch (InterruptedException e) { + AppLog.e(AppLog.T.PLANS, "IAP setup took too long! > " + GET_IAP_BINDER_TIMEOUT + " msecs!", e); + return null; + } + } catch (NullPointerException e) { + // will happen when play store isn't available on device + //AppLog.e(AppLog.T.PLANS, e); + AppLog.w(AppLog.T.PLANS, "Unable to start IAB helper. Happen when Play Store isn't available on device."); + return null; + } + + listIAPs(); + stopInAppBillingHelper(); + return null; + } + + private void listIAPs() { + if (mIabHelper == null) { + return; + } + try { + Inventory inventory = mIabHelper.queryInventory(true, null, null); + List iaps = inventory.getAllPurchases(); + for (Purchase purchase : iaps) { + AppLog.d(AppLog.T.PLANS, "Original purchase JSON " + purchase.getOriginalJson()); + try { + JSONObject developerPayload = new JSONObject(purchase.getDeveloperPayload()); + Map params = new HashMap<>(); + params.put("blog_id", developerPayload.getString("blog_id")); + params.put("iap_sku", purchase.getSku()); + params.put("iap_token", purchase.getToken()); + params.put("iap_package_name", purchase.getPackageName()); + params.put("client_id", BuildConfig.OAUTH_APP_ID); + params.put("client_secret", BuildConfig.OAUTH_APP_SECRET); + WordPress.getRestClientUtilsV1_1().post(IAP_ENDPOINT, params, null, + new RestRequest.Listener() { + @Override + public void onResponse(JSONObject response) { + if (response != null) { + AppLog.d(AppLog.T.PLANS, "Response from the server: " + response.toString()); + } + } + }, + new RestRequest.ErrorListener() { + @Override + public void onErrorResponse(VolleyError error) { + AppLog.e(AppLog.T.PLANS, "Response from the server", error); + } + }); + } catch (JSONException e) { + AppLog.e(AppLog.T.PLANS, "Unable to parse IAP info - " + purchase.getOriginalJson(), e); + } + } + } catch (IabException e) { + AppLog.e(AppLog.T.PLANS, "Unable to refresh the inventory", e); + } + } + + private void stopInAppBillingHelper() { + if (mIabHelper != null) { + try { + mIabHelper.dispose(); + } catch (IllegalArgumentException e) { + // this can happen if the IAB helper was created but failed to bind to its service + // when started, which will occur on emulators + AppLog.w(AppLog.T.PLANS, "Unable to dispose IAB helper"); + } + mIabHelper = null; + } + } +} diff --git a/WordPress/src/main/java/org/wordpress/android/ui/plans/util/Inventory.java b/WordPress/src/main/java/org/wordpress/android/ui/plans/util/Inventory.java index b4508beecb99..9c8467e984f2 100644 --- a/WordPress/src/main/java/org/wordpress/android/ui/plans/util/Inventory.java +++ b/WordPress/src/main/java/org/wordpress/android/ui/plans/util/Inventory.java @@ -63,12 +63,12 @@ public void erasePurchase(String sku) { } /** Returns a list of all owned product IDs. */ - List getAllOwnedSkus() { + public List getAllOwnedSkus() { return new ArrayList(mPurchaseMap.keySet()); } /** Returns a list of all owned product IDs of a given type */ - List getAllOwnedSkus(String itemType) { + public List getAllOwnedSkus(String itemType) { List result = new ArrayList(); for (Purchase p : mPurchaseMap.values()) { if (p.getItemType().equals(itemType)) result.add(p.getSku()); @@ -77,7 +77,7 @@ List getAllOwnedSkus(String itemType) { } /** Returns a list of all purchases. */ - List getAllPurchases() { + public List getAllPurchases() { return new ArrayList(mPurchaseMap.values()); } From 443d963254dec78249b53749d052411316c0e96d Mon Sep 17 00:00:00 2001 From: Danilo Ercoli Date: Mon, 11 Apr 2016 18:08:40 +0200 Subject: [PATCH 04/50] Remove unused imports. Add comments. --- .../src/main/java/org/wordpress/android/WordPress.java | 9 ++++----- .../org/wordpress/android/ui/plans/PlansActivity.java | 5 +---- .../org/wordpress/android/ui/plans/UpdateIAPTask.java | 4 ++++ 3 files changed, 9 insertions(+), 9 deletions(-) diff --git a/WordPress/src/main/java/org/wordpress/android/WordPress.java b/WordPress/src/main/java/org/wordpress/android/WordPress.java index 47ff742a0f08..3618922d2404 100644 --- a/WordPress/src/main/java/org/wordpress/android/WordPress.java +++ b/WordPress/src/main/java/org/wordpress/android/WordPress.java @@ -49,7 +49,6 @@ import org.wordpress.android.ui.accounts.helpers.UpdateBlogListTask.GenericUpdateBlogListTask; import org.wordpress.android.ui.notifications.utils.NotificationsUtils; import org.wordpress.android.ui.notifications.utils.SimperiumUtils; -import org.wordpress.android.ui.plans.PlansUtils; import org.wordpress.android.ui.plans.UpdateIAPTask; import org.wordpress.android.ui.prefs.AppPrefs; import org.wordpress.android.ui.stats.StatsWidgetProvider; @@ -138,11 +137,11 @@ protected boolean run() { }; /** - * Update IAPs. This need to be called to remove upgrades on wpcom side, those upgrades the user has already cancelled on mobile side - * (from the Google Store). + * Synch IAPs with wpcom backend. This need to be called to add/remove upgrades on wpcom side. + * Those upgrades the user has already bought/cancelled on mobile side (from the Google Store). * */ - public static RateLimitedTask sUpdateWordPressComIAP = new RateLimitedTask(SECONDS_BETWEEN_IAP_UPDATE) { + public static RateLimitedTask sUpdateIAPsWordPressCom = new RateLimitedTask(SECONDS_BETWEEN_IAP_UPDATE) { protected boolean run() { if (AccountHelper.isSignedInWordPressDotCom()) { new UpdateIAPTask(getContext()).executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR); @@ -820,7 +819,7 @@ public void onAppComesFromBackground() { sUpdateCurrentBlogOption.runIfNotLimited(); } sDeleteExpiredStats.runIfNotLimited(); - sUpdateWordPressComIAP.forceRun(); // TODO: changes to run if not limited + sUpdateIAPsWordPressCom.forceRun(); // TODO: changes to run if not limited } @Override diff --git a/WordPress/src/main/java/org/wordpress/android/ui/plans/PlansActivity.java b/WordPress/src/main/java/org/wordpress/android/ui/plans/PlansActivity.java index 888bb5142c89..8028c53883b6 100644 --- a/WordPress/src/main/java/org/wordpress/android/ui/plans/PlansActivity.java +++ b/WordPress/src/main/java/org/wordpress/android/ui/plans/PlansActivity.java @@ -30,10 +30,8 @@ import org.wordpress.android.models.Blog; import org.wordpress.android.ui.plans.adapters.PlansPagerAdapter; import org.wordpress.android.ui.plans.models.Plan; -import org.wordpress.android.ui.plans.util.IabException; import org.wordpress.android.ui.plans.util.IabHelper; import org.wordpress.android.ui.plans.util.IabResult; -import org.wordpress.android.ui.plans.util.Inventory; import org.wordpress.android.ui.plans.util.Purchase; import org.wordpress.android.ui.prefs.AppPrefs; import org.wordpress.android.util.AniUtils; @@ -42,7 +40,6 @@ import org.wordpress.android.widgets.WPViewPager; import java.io.Serializable; -import java.util.ArrayList; import java.util.List; import de.greenrobot.event.EventBus; @@ -333,7 +330,7 @@ public void onIabPurchaseFinished(IabResult result, Purchase info) { AppLog.d(AppLog.T.PLANS, "IabResult: " + result.toString()); if (result.isSuccess()) { if (info != null) { - WordPress.sUpdateWordPressComIAP.forceRun(); // refresh purchase on wpcom + WordPress.sUpdateIAPsWordPressCom.forceRun(); // refresh purchase on wpcom AppLog.d(AppLog.T.PLANS, "Purchase: " + info.toString()); AppLog.d(AppLog.T.PLANS, "You have bought the " + info.getSku() + ". Excellent choice, adventurer!"); boolean isBusinessPlan = (mViewPager.getCurrentItem() == mViewPager.getAdapter().getCount() - 1); diff --git a/WordPress/src/main/java/org/wordpress/android/ui/plans/UpdateIAPTask.java b/WordPress/src/main/java/org/wordpress/android/ui/plans/UpdateIAPTask.java index e0a7ec1f3c88..5abe819afe1a 100644 --- a/WordPress/src/main/java/org/wordpress/android/ui/plans/UpdateIAPTask.java +++ b/WordPress/src/main/java/org/wordpress/android/ui/plans/UpdateIAPTask.java @@ -24,6 +24,10 @@ import java.util.concurrent.CountDownLatch; import java.util.concurrent.TimeUnit; +/** + * Synch IAPs on the wpcom backend. This need to be called to add/remove upgrades on wpcom side. + * + */ public class UpdateIAPTask extends AsyncTask { private static final int GET_IAP_BINDER_TIMEOUT = 30000; private static final String IAP_ENDPOINT = "/iap/refresh"; From 8f553c9845d0ac872f2fc82d8afb383a7a74c9b0 Mon Sep 17 00:00:00 2001 From: Danilo Ercoli Date: Tue, 12 Apr 2016 15:18:35 +0200 Subject: [PATCH 05/50] Remove custom hardcoded SKUs since REST Endpoint has been updated. --- .../java/org/wordpress/android/ui/plans/PlansActivity.java | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/WordPress/src/main/java/org/wordpress/android/ui/plans/PlansActivity.java b/WordPress/src/main/java/org/wordpress/android/ui/plans/PlansActivity.java index 8028c53883b6..c83221de17f0 100644 --- a/WordPress/src/main/java/org/wordpress/android/ui/plans/PlansActivity.java +++ b/WordPress/src/main/java/org/wordpress/android/ui/plans/PlansActivity.java @@ -308,11 +308,7 @@ public boolean onOptionsItemSelected(MenuItem item) { } private void startPurchaseProcess(Plan plan) { - - // TODO: remove when updated the rest api - boolean isBusinessPlan = (mViewPager.getCurrentItem() == mViewPager.getAdapter().getCount() - 1); - String sku = isBusinessPlan ? "sub_test_plan_business_001" : "sub_test_plan_premium_001"; - + String sku = plan.getAndroidSKU(); Blog currentBlog = WordPress.getBlog(mLocalBlogID); JSONObject extraData = new JSONObject(); try { From 2b9d5a6dcae412812047cbb9cec01c78dfc23cee Mon Sep 17 00:00:00 2001 From: Danilo Ercoli Date: Tue, 12 Apr 2016 16:00:26 +0200 Subject: [PATCH 06/50] Fix log message --- .../main/java/org/wordpress/android/ui/plans/PlansActivity.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/WordPress/src/main/java/org/wordpress/android/ui/plans/PlansActivity.java b/WordPress/src/main/java/org/wordpress/android/ui/plans/PlansActivity.java index c83221de17f0..38aa8cd3e40b 100644 --- a/WordPress/src/main/java/org/wordpress/android/ui/plans/PlansActivity.java +++ b/WordPress/src/main/java/org/wordpress/android/ui/plans/PlansActivity.java @@ -335,7 +335,7 @@ public void onIabPurchaseFinished(IabResult result, Purchase info) { startActivity(intent); } } else { - AppLog.e(AppLog.T.PLANS, "Purchase failure " + result.getMessage()); + AppLog.e(AppLog.T.PLANS, "Purchase failure: " + result.getMessage()); // Not a success. It seems that the buy activity already shows an error. // Or at least, it shows an error if you try to purchase a subscription you already own. } From 691e6a801e0c540ab31ad3d225d9d2786cf92097 Mon Sep 17 00:00:00 2001 From: Danilo Ercoli Date: Fri, 29 Apr 2016 15:16:03 +0200 Subject: [PATCH 07/50] Use the new endpoint name, and remove unused parameters. --- .../java/org/wordpress/android/ui/plans/UpdateIAPTask.java | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/WordPress/src/main/java/org/wordpress/android/ui/plans/UpdateIAPTask.java b/WordPress/src/main/java/org/wordpress/android/ui/plans/UpdateIAPTask.java index 5abe819afe1a..98ecf383a4f7 100644 --- a/WordPress/src/main/java/org/wordpress/android/ui/plans/UpdateIAPTask.java +++ b/WordPress/src/main/java/org/wordpress/android/ui/plans/UpdateIAPTask.java @@ -30,7 +30,7 @@ */ public class UpdateIAPTask extends AsyncTask { private static final int GET_IAP_BINDER_TIMEOUT = 30000; - private static final String IAP_ENDPOINT = "/iap/refresh"; + private static final String IAP_ENDPOINT = "/iap/validate"; protected Context mContext; private IabHelper mIabHelper; @@ -95,9 +95,6 @@ private void listIAPs() { params.put("blog_id", developerPayload.getString("blog_id")); params.put("iap_sku", purchase.getSku()); params.put("iap_token", purchase.getToken()); - params.put("iap_package_name", purchase.getPackageName()); - params.put("client_id", BuildConfig.OAUTH_APP_ID); - params.put("client_secret", BuildConfig.OAUTH_APP_SECRET); WordPress.getRestClientUtilsV1_1().post(IAP_ENDPOINT, params, null, new RestRequest.Listener() { @Override From d18fb252c734cf67bc8e85141da9e673b56b425e Mon Sep 17 00:00:00 2001 From: Maxime Biais Date: Mon, 2 May 2016 14:29:34 +0100 Subject: [PATCH 08/50] add a "wp." prefix to crashlytics.apikey so that value will be tested during release checksum --- WordPress/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/WordPress/build.gradle b/WordPress/build.gradle index 46d13e0de978..4bfa656d1f56 100644 --- a/WordPress/build.gradle +++ b/WordPress/build.gradle @@ -147,7 +147,7 @@ task generateCrashlyticsConfig(group: "generate", description: "Generate Crashly inputFile.withInputStream { stream -> properties.load(stream) } - def crashlyticsApiKey = properties.getProperty('crashlytics.apikey', '0') + def crashlyticsApiKey = properties.getProperty('wp.crashlytics.apikey', '0') def writer = new FileWriter(outputFile) writer.write("""// auto-generated file from ${rootDir}/gradle.properties do not modify apiKey=${crashlyticsApiKey}""") From c5253cab8f136be04522232def2478078d288393 Mon Sep 17 00:00:00 2001 From: Maxime Biais Date: Mon, 2 May 2016 14:38:03 +0100 Subject: [PATCH 09/50] update release check sha1sum with optimizely and crashlytics keys --- tools/release-checks.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tools/release-checks.sh b/tools/release-checks.sh index 74abfda3aacb..de7fc21932d0 100755 --- a/tools/release-checks.sh +++ b/tools/release-checks.sh @@ -92,7 +92,7 @@ function printVersion() { function checkGradleProperties() { /bin/echo -n "Check WordPress/gradle.properties..." checksum=`cat WordPress/gradle.properties|grep "^wp."|tr "[A-Z]" "[a-z]"|sed "s/ //g"|sort|sha1sum |cut -d- -f1| sed "s/ //g"` - known_checksum="2a9fd98ebd7244da4fa3476cc3acddc37f8d529c" + known_checksum="4058cdf3d784e4b79f63514d4780e92c28b5ab78" if [ x$checksum != x$known_checksum ]; then pFail exit 5 From 569e2b0e61ab32186509890de14182b1f1c6f98c Mon Sep 17 00:00:00 2001 From: Danilo Ercoli Date: Tue, 3 May 2016 16:41:26 +0200 Subject: [PATCH 10/50] Change the label to "upgrade" when the selected blog already has a plan subscription, and redirect the user to support. We're not going to enable upgrades whitin the apps. --- .../java/org/wordpress/android/WordPress.java | 4 +- .../android/ui/plans/PlansActivity.java | 82 ++++++++++++++++--- .../android/ui/plans/PlansUtils.java | 18 ++++ .../src/main/res/layout/plans_activity.xml | 1 + WordPress/src/main/res/values/strings.xml | 3 + 5 files changed, 95 insertions(+), 13 deletions(-) diff --git a/WordPress/src/main/java/org/wordpress/android/WordPress.java b/WordPress/src/main/java/org/wordpress/android/WordPress.java index 0bbb8c682342..bb7083fa7955 100644 --- a/WordPress/src/main/java/org/wordpress/android/WordPress.java +++ b/WordPress/src/main/java/org/wordpress/android/WordPress.java @@ -102,7 +102,7 @@ public class WordPress extends Application { private static final int SECONDS_BETWEEN_OPTIONS_UPDATE = 10 * 60; private static final int SECONDS_BETWEEN_BLOGLIST_UPDATE = 6 * 60 * 60; - private static final int SECONDS_BETWEEN_IAP_UPDATE = 5 * 60; + private static final int SECONDS_BETWEEN_IAP_UPDATE = 5 * 60; // 5 minutes private static final int SECONDS_BETWEEN_DELETE_STATS = 5 * 60; // 5 minutes private static Context mContext; @@ -829,7 +829,7 @@ public void onAppComesFromBackground() { sUpdateCurrentBlogOption.runIfNotLimited(); } sDeleteExpiredStats.runIfNotLimited(); - sUpdateIAPsWordPressCom.forceRun(); // TODO: changes to run if not limited + sUpdateIAPsWordPressCom.runIfNotLimited(); } @Override diff --git a/WordPress/src/main/java/org/wordpress/android/ui/plans/PlansActivity.java b/WordPress/src/main/java/org/wordpress/android/ui/plans/PlansActivity.java index 38aa8cd3e40b..e8703f65a5e9 100644 --- a/WordPress/src/main/java/org/wordpress/android/ui/plans/PlansActivity.java +++ b/WordPress/src/main/java/org/wordpress/android/ui/plans/PlansActivity.java @@ -2,6 +2,8 @@ import android.animation.Animator; import android.annotation.TargetApi; +import android.app.AlertDialog; +import android.content.DialogInterface; import android.content.Intent; import android.graphics.Point; import android.os.Build; @@ -37,6 +39,7 @@ import org.wordpress.android.util.AniUtils; import org.wordpress.android.util.AppLog; import org.wordpress.android.util.DisplayUtils; +import org.wordpress.android.util.HelpshiftHelper; import org.wordpress.android.widgets.WPViewPager; import java.io.Serializable; @@ -141,27 +144,62 @@ public void onPause() { EventBus.getDefault().unregister(this); } - private void updatePurchaseUI(int position) { + /** + * The 'Buy' button should be available if the current plan is free, and the selected plan upgrade is available. + * @param position + * @return boolean - true if the current plan could be added to the blog. + */ + private boolean isBuyButtonAvailable(int position) { + long currentPlanProductId = WordPress.wpDB.getPlanIdForLocalTableBlogId(mLocalBlogID); + if (!PlansUtils.isFreePlan(currentPlanProductId)) { + return false; + } final Plan plan = getPageAdapter().getPlan(position); - boolean showPurchaseButton; - if (plan.isCurrentPlan()) { - showPurchaseButton = false; - } else { - // don't show the purchase button unless the plan at this position is "greater" than - // the current plan for this site - long currentPlanProductId = WordPress.wpDB.getPlanIdForLocalTableBlogId(mLocalBlogID); - showPurchaseButton = plan.isAvailable() && plan.getProductID() > currentPlanProductId; + return plan.isAvailable() && !plan.isCurrentPlan(); + } + + /** + * The 'Upgrade' button should be available if the current plan is NOT free, + * and the selected plan upgrade is available, and the current plan ID < new plan ID. + * @param position + * @return boolean - true if the current plan could be upgraded to the blog. + */ + private boolean isUpgradeButtonAvailable(int position) { + long currentPlanProductId = WordPress.wpDB.getPlanIdForLocalTableBlogId(mLocalBlogID); + if (isBuyButtonAvailable(position) || PlansUtils.isFreePlan(currentPlanProductId)) { + return false; } + final Plan plan = getPageAdapter().getPlan(position); + + // No downgrade! + if (PlansUtils.isFreePlan(plan) || currentPlanProductId > plan.getProductID()) { + return false; + } + + return plan.isAvailable() && !plan.isCurrentPlan(); + } + + private void updatePurchaseUI(final int position) { + final Plan plan = getPageAdapter().getPlan(position); + boolean showPurchaseButton = isBuyButtonAvailable(position) || isUpgradeButtonAvailable(position); + ViewGroup framePurchase = (ViewGroup) findViewById(R.id.frame_purchase); ViewGroup containerPurchase = (ViewGroup) findViewById(R.id.purchase_container); if (showPurchaseButton) { TextView txtPurchasePrice = (TextView) framePurchase.findViewById(R.id.text_purchase_price); txtPurchasePrice.setText(PlansUtils.getPlanDisplayPrice(plan)); + + TextView txtPurchaseLabel = (TextView) framePurchase.findViewById(R.id.text_purchase_label); + if (isBuyButtonAvailable(position)) { + txtPurchaseLabel.setText(getString(R.string.plan_purchase_now)); + } else if (isUpgradeButtonAvailable(position)) { + txtPurchaseLabel.setText(getString(R.string.plan_upgrade_now)); + } containerPurchase.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { - startPurchaseProcess(plan); + startPurchaseProcess(position); } }); } else { @@ -307,7 +345,29 @@ public boolean onOptionsItemSelected(MenuItem item) { return super.onOptionsItemSelected(item); } - private void startPurchaseProcess(Plan plan) { + private void startPurchaseProcess(int position) { + final Plan plan = getPageAdapter().getPlan(position); + + // if it's an upgrade show the message and return. We don't handle upgrades in app. + if (isUpgradeButtonAvailable(position)) { + String upgradeText = getString(R.string.plan_upgrade_contact_support_text, plan.getProductName()); + AlertDialog.Builder builder = new AlertDialog.Builder(this); + builder.setMessage(upgradeText) + .setTitle(getString(R.string.plan_upgrade_not_available)); + builder.setPositiveButton(R.string.yes, new DialogInterface.OnClickListener() { + public void onClick(DialogInterface dialog, int id) { + HelpshiftHelper.getInstance().showConversation(PlansActivity.this, HelpshiftHelper.Tag.ORIGIN_UNKNOWN); + } + }); + builder.setNegativeButton(R.string.no, new DialogInterface.OnClickListener() { + public void onClick(DialogInterface dialog, int id) { + // User cancelled the dialog. Do nothing + } + }); + builder.create().show(); + return; + } + String sku = plan.getAndroidSKU(); Blog currentBlog = WordPress.getBlog(mLocalBlogID); JSONObject extraData = new JSONObject(); diff --git a/WordPress/src/main/java/org/wordpress/android/ui/plans/PlansUtils.java b/WordPress/src/main/java/org/wordpress/android/ui/plans/PlansUtils.java index 10299596a95e..bf6939789ad3 100644 --- a/WordPress/src/main/java/org/wordpress/android/ui/plans/PlansUtils.java +++ b/WordPress/src/main/java/org/wordpress/android/ui/plans/PlansUtils.java @@ -94,6 +94,24 @@ public static String getIconUrlForPlan(Plan plan, int iconSize) { return PhotonUtils.getPhotonImageUrl(plan.getIconUrl(), iconSize, iconSize); } + public static boolean isFreePlan(Plan plan) { + return plan.getProductSlug().equals("free_plan") || + plan.getProductSlug().equals("jetpack_free"); + } + + /** + * Weather the plan ID is a free plan. + * + * 2002 = Jetpack free + * 1 = WordPress.com free + * + * @param planID - The plan ID + * @return boolean - true if the current blog is on a free plan. + */ + public static boolean isFreePlan(long planID) { + return planID == 2002 || planID == 1; + } + /** * Removes stored plan data - for testing purposes */ diff --git a/WordPress/src/main/res/layout/plans_activity.xml b/WordPress/src/main/res/layout/plans_activity.xml index 2d679d4aa1b2..d8a718c048cf 100644 --- a/WordPress/src/main/res/layout/plans_activity.xml +++ b/WordPress/src/main/res/layout/plans_activity.xml @@ -84,6 +84,7 @@ android:textSize="@dimen/text_sz_large"/> Plans Unable to load plans Purchase Now + Upgrade Now + Upgrade not available + This blog already has a plan subscription. Please contact our support team to upgrade to %1$s. Do you want to contact support now? It\'s all yours, way to go! From 20c733578723f66f40ad069e1b09401a53d1e898 Mon Sep 17 00:00:00 2001 From: Danilo Ercoli Date: Tue, 3 May 2016 17:44:09 +0200 Subject: [PATCH 11/50] Remove links to unused subprojects used during development --- settings.gradle | 4 ---- 1 file changed, 4 deletions(-) diff --git a/settings.gradle b/settings.gradle index c61872f05c87..d00ff04c5efe 100644 --- a/settings.gradle +++ b/settings.gradle @@ -1,9 +1,5 @@ include ':WordPress' include ':libs:utils:WordPressUtils' -include ':libs:android-wordpress-com-rest:WordPressComRest' include ':libs:networking:WordPressNetworking' include ':libs:analytics:WordPressAnalytics' include ':libs:editor:WordPressEditor' -include ':libs:automattictracks:AutomatticTracks' -include ':libs:Android-Passcodelock:library' - From 27765fb20f5449f9d5b2bb8103f0685625e27288 Mon Sep 17 00:00:00 2001 From: Danilo Ercoli Date: Tue, 3 May 2016 17:47:42 +0200 Subject: [PATCH 12/50] Revert unwanted commits --- WordPress/build.gradle | 26 ++++++++++++-------------- 1 file changed, 12 insertions(+), 14 deletions(-) diff --git a/WordPress/build.gradle b/WordPress/build.gradle index a6e86882267c..46d13e0de978 100644 --- a/WordPress/build.gradle +++ b/WordPress/build.gradle @@ -4,7 +4,7 @@ buildscript { maven { url 'https://maven.fabric.io/public' } } dependencies { - classpath 'com.android.tools.build:gradle:2.0.0' + classpath 'com.android.tools.build:gradle:2.1.0' classpath 'io.fabric.tools:gradle:1.+' } } @@ -13,6 +13,7 @@ repositories { jcenter() maven { url 'http://wordpress-mobile.github.io/WordPress-Android' } maven { url 'https://maven.fabric.io/public' } + maven { url 'http://dl.bintray.com/optimizely/optimizely' } } apply plugin: 'com.android.application' @@ -30,8 +31,8 @@ android { defaultConfig { applicationId "org.wordpress.android" - versionName "alpha-6" - versionCode 252 + versionName "alpha-7" + versionCode 253 minSdkVersion 14 targetSdkVersion 23 @@ -59,9 +60,8 @@ android { release { // Proguard is only used to fix an issue with some Samsung device // https://github.com/wordpress-mobile/WordPress-Android/issues/2151 - // minifyEnabled true - // proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard.cfg' - debuggable true + minifyEnabled true + proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard.cfg' } debug { @@ -76,6 +76,10 @@ dependencies { transitive = true; } + compile('com.optimizely:optimizely:+@aar') { + transitive = true + } + // Provided by maven central compile ('org.wordpress:mediapicker:1.2.4') { exclude group:'com.android.support' @@ -93,7 +97,7 @@ dependencies { compile 'com.github.chrisbanes.photoview:library:1.2.4' compile 'com.helpshift:android-helpshift-aar:4.4.0' compile 'de.greenrobot:eventbus:2.4.0' - // compile 'com.automattic:rest:1.0.3' + compile 'com.automattic:rest:1.0.3' compile 'org.wordpress:graphview:3.4.0' compile 'org.wordpress:persistentedittext:1.0.1' @@ -106,7 +110,7 @@ dependencies { // Provided by the WordPress-Android Repository compile 'org.wordpress:drag-sort-listview:0.6.1' // not found in maven central compile 'org.wordpress:slidinguppanel:1.0.0' // not found in maven central - // compile 'org.wordpress:passcodelock:1.1.0' + compile 'org.wordpress:passcodelock:1.1.0' compile 'org.wordpress:emailchecker:0.3' // Simperium @@ -120,12 +124,6 @@ dependencies { debugCompile project(path:':libs:analytics:WordPressAnalytics', configuration: 'debug') releaseCompile project(path:':libs:editor:WordPressEditor', configuration: 'release') debugCompile project(path:':libs:editor:WordPressEditor', configuration: 'debug') - - releaseCompile project(path:':libs:android-wordpress-com-rest:WordPressComRest', configuration: 'release') - debugCompile project(path:':libs:android-wordpress-com-rest:WordPressComRest', configuration: 'debug') - - releaseCompile project(path:':libs:Android-Passcodelock:library', configuration: 'release') - debugCompile project(path:':libs:Android-Passcodelock:library', configuration: 'debug') } configurations.all { From ef9b80da330e56d9c029e7e50b1e4006be4b63d9 Mon Sep 17 00:00:00 2001 From: Danilo Ercoli Date: Tue, 3 May 2016 17:50:50 +0200 Subject: [PATCH 13/50] Fix merge conflicts --- WordPress/build.gradle | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/WordPress/build.gradle b/WordPress/build.gradle index 46d13e0de978..6fbbc1265fe0 100644 --- a/WordPress/build.gradle +++ b/WordPress/build.gradle @@ -14,6 +14,7 @@ repositories { maven { url 'http://wordpress-mobile.github.io/WordPress-Android' } maven { url 'https://maven.fabric.io/public' } maven { url 'http://dl.bintray.com/optimizely/optimizely' } + maven { url "https://jitpack.io" } } apply plugin: 'com.android.application' @@ -31,8 +32,8 @@ android { defaultConfig { applicationId "org.wordpress.android" - versionName "alpha-7" - versionCode 253 + versionName "alpha-8" + versionCode 259 minSdkVersion 14 targetSdkVersion 23 @@ -84,7 +85,7 @@ dependencies { compile ('org.wordpress:mediapicker:1.2.4') { exclude group:'com.android.support' } - compile 'com.google.code.gson:gson:2.2.2' + compile 'com.google.code.gson:gson:2.6.+' compile 'org.ccil.cowan.tagsoup:tagsoup:1.2.1' compile 'com.android.support:support-v13:23.1.1' compile 'com.android.support:appcompat-v7:23.1.1' @@ -97,10 +98,13 @@ dependencies { compile 'com.github.chrisbanes.photoview:library:1.2.4' compile 'com.helpshift:android-helpshift-aar:4.4.0' compile 'de.greenrobot:eventbus:2.4.0' - compile 'com.automattic:rest:1.0.3' + compile 'com.automattic:rest:1.0.5' compile 'org.wordpress:graphview:3.4.0' compile 'org.wordpress:persistentedittext:1.0.1' + compile 'com.yalantis:ucrop:1.2.4' + compile 'com.github.xizzhu:simple-tool-tip:0.5.0' + androidTestCompile 'com.google.dexmaker:dexmaker-mockito:1.0' androidTestCompile 'org.objenesis:objenesis:2.1' androidTestCompile 'org.mockito:mockito-core:+' From 97baa8c5dbbc353ee353af96426753df19df35a5 Mon Sep 17 00:00:00 2001 From: Danilo Ercoli Date: Tue, 3 May 2016 17:52:25 +0200 Subject: [PATCH 14/50] Fix merge conflicts - tentative #2 --- libs/networking/WordPressNetworking/build.gradle | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/libs/networking/WordPressNetworking/build.gradle b/libs/networking/WordPressNetworking/build.gradle index a9f79dabc2a0..76a09ba62a60 100644 --- a/libs/networking/WordPressNetworking/build.gradle +++ b/libs/networking/WordPressNetworking/build.gradle @@ -30,10 +30,7 @@ android { dependencies { compile 'org.wordpress:utils:1.9.0' - //compile 'com.automattic:rest:1.0.3' - - releaseCompile project(path:':libs:android-wordpress-com-rest:WordPressComRest', configuration: 'release') - debugCompile project(path:':libs:android-wordpress-com-rest:WordPressComRest', configuration: 'debug') + compile 'com.automattic:rest:1.0.3' } uploadArchives { From 7c2824359ec495a4d960241609aa29c4ca492742 Mon Sep 17 00:00:00 2001 From: Danilo Ercoli Date: Tue, 3 May 2016 17:53:08 +0200 Subject: [PATCH 15/50] New plans strings --- WordPress/src/main/res/values/strings.xml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/WordPress/src/main/res/values/strings.xml b/WordPress/src/main/res/values/strings.xml index bd627876001b..009fda1c0d7f 100644 --- a/WordPress/src/main/res/values/strings.xml +++ b/WordPress/src/main/res/values/strings.xml @@ -1410,6 +1410,9 @@ Unable to load plans Purchase Now Enter your password instead + Upgrade Now + Upgrade not available + This blog already has a plan subscription. Please contact our support team to upgrade to %1$s. Do you want to contact support now? It\'s all yours, way to go! From 90e71a478a9115dac0025d812df050537e015f9e Mon Sep 17 00:00:00 2001 From: Danilo Ercoli Date: Wed, 4 May 2016 16:15:29 +0200 Subject: [PATCH 16/50] Do not show the Upgrade|Purchase button when the blog already has a plan attached to it. --- .../android/ui/plans/PlansActivity.java | 36 +++---------------- .../src/main/res/layout/plans_activity.xml | 1 - WordPress/src/main/res/values/strings.xml | 3 -- 3 files changed, 4 insertions(+), 36 deletions(-) diff --git a/WordPress/src/main/java/org/wordpress/android/ui/plans/PlansActivity.java b/WordPress/src/main/java/org/wordpress/android/ui/plans/PlansActivity.java index e8703f65a5e9..864e11f81051 100644 --- a/WordPress/src/main/java/org/wordpress/android/ui/plans/PlansActivity.java +++ b/WordPress/src/main/java/org/wordpress/android/ui/plans/PlansActivity.java @@ -2,8 +2,6 @@ import android.animation.Animator; import android.annotation.TargetApi; -import android.app.AlertDialog; -import android.content.DialogInterface; import android.content.Intent; import android.graphics.Point; import android.os.Build; @@ -39,7 +37,6 @@ import org.wordpress.android.util.AniUtils; import org.wordpress.android.util.AppLog; import org.wordpress.android.util.DisplayUtils; -import org.wordpress.android.util.HelpshiftHelper; import org.wordpress.android.widgets.WPViewPager; import java.io.Serializable; @@ -161,6 +158,9 @@ private boolean isBuyButtonAvailable(int position) { /** * The 'Upgrade' button should be available if the current plan is NOT free, * and the selected plan upgrade is available, and the current plan ID < new plan ID. + * + * Note: Not used now, but will be when we'll implement upgrade of plan within the app. + * * @param position * @return boolean - true if the current plan could be upgraded to the blog. */ @@ -182,20 +182,13 @@ private boolean isUpgradeButtonAvailable(int position) { private void updatePurchaseUI(final int position) { final Plan plan = getPageAdapter().getPlan(position); - boolean showPurchaseButton = isBuyButtonAvailable(position) || isUpgradeButtonAvailable(position); + boolean showPurchaseButton = isBuyButtonAvailable(position); ViewGroup framePurchase = (ViewGroup) findViewById(R.id.frame_purchase); ViewGroup containerPurchase = (ViewGroup) findViewById(R.id.purchase_container); if (showPurchaseButton) { TextView txtPurchasePrice = (TextView) framePurchase.findViewById(R.id.text_purchase_price); txtPurchasePrice.setText(PlansUtils.getPlanDisplayPrice(plan)); - - TextView txtPurchaseLabel = (TextView) framePurchase.findViewById(R.id.text_purchase_label); - if (isBuyButtonAvailable(position)) { - txtPurchaseLabel.setText(getString(R.string.plan_purchase_now)); - } else if (isUpgradeButtonAvailable(position)) { - txtPurchaseLabel.setText(getString(R.string.plan_upgrade_now)); - } containerPurchase.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { @@ -347,27 +340,6 @@ public boolean onOptionsItemSelected(MenuItem item) { private void startPurchaseProcess(int position) { final Plan plan = getPageAdapter().getPlan(position); - - // if it's an upgrade show the message and return. We don't handle upgrades in app. - if (isUpgradeButtonAvailable(position)) { - String upgradeText = getString(R.string.plan_upgrade_contact_support_text, plan.getProductName()); - AlertDialog.Builder builder = new AlertDialog.Builder(this); - builder.setMessage(upgradeText) - .setTitle(getString(R.string.plan_upgrade_not_available)); - builder.setPositiveButton(R.string.yes, new DialogInterface.OnClickListener() { - public void onClick(DialogInterface dialog, int id) { - HelpshiftHelper.getInstance().showConversation(PlansActivity.this, HelpshiftHelper.Tag.ORIGIN_UNKNOWN); - } - }); - builder.setNegativeButton(R.string.no, new DialogInterface.OnClickListener() { - public void onClick(DialogInterface dialog, int id) { - // User cancelled the dialog. Do nothing - } - }); - builder.create().show(); - return; - } - String sku = plan.getAndroidSKU(); Blog currentBlog = WordPress.getBlog(mLocalBlogID); JSONObject extraData = new JSONObject(); diff --git a/WordPress/src/main/res/layout/plans_activity.xml b/WordPress/src/main/res/layout/plans_activity.xml index d8a718c048cf..2d679d4aa1b2 100644 --- a/WordPress/src/main/res/layout/plans_activity.xml +++ b/WordPress/src/main/res/layout/plans_activity.xml @@ -84,7 +84,6 @@ android:textSize="@dimen/text_sz_large"/> Unable to load plans Purchase Now Enter your password instead - Upgrade Now - Upgrade not available - This blog already has a plan subscription. Please contact our support team to upgrade to %1$s. Do you want to contact support now? It\'s all yours, way to go! From 2c25280ec467d1ee21496cbc9502f1817a31be82 Mon Sep 17 00:00:00 2001 From: Nick Bradbury Date: Wed, 4 May 2016 21:10:41 -0400 Subject: [PATCH 17/50] First pass at adding toolbar above reader post list --- .../ui/reader/ReaderPostListFragment.java | 23 ++++++++++++-- ...filtered_recyclerview_settings_control.xml | 8 ----- .../reader_filtered_recyclerview_controls.xml | 31 +++++++++++++++++++ 3 files changed, 51 insertions(+), 11 deletions(-) delete mode 100644 WordPress/src/main/res/layout/filtered_recyclerview_settings_control.xml create mode 100644 WordPress/src/main/res/layout/reader_filtered_recyclerview_controls.xml diff --git a/WordPress/src/main/java/org/wordpress/android/ui/reader/ReaderPostListFragment.java b/WordPress/src/main/java/org/wordpress/android/ui/reader/ReaderPostListFragment.java index 0edfb543cd43..bb2695306ecf 100644 --- a/WordPress/src/main/java/org/wordpress/android/ui/reader/ReaderPostListFragment.java +++ b/WordPress/src/main/java/org/wordpress/android/ui/reader/ReaderPostListFragment.java @@ -459,16 +459,33 @@ public void onShowCustomEmptyView (EmptyViewMessageType emptyViewMsgType) { int spacingVertical = context.getResources().getDimensionPixelSize(R.dimen.reader_card_gutters); mRecyclerView.addItemDecoration(new RecyclerItemDecoration(spacingHorizontal, spacingVertical, false)); + // add buttons to the filtered recyclerview's toolbar if (!ReaderUtils.isLoggedOutReader()) { - View settingsControl = inflater.inflate(R.layout.filtered_recyclerview_settings_control, null); - mRecyclerView.addToolbarCustomControl(settingsControl, new View.OnClickListener() { + ViewGroup controls = (ViewGroup) inflater.inflate(R.layout.reader_filtered_recyclerview_controls, null); + + // settings - shows tags & followed sites + View btnSettings = controls.findViewById(R.id.btn_settings); + ReaderUtils.setBackgroundToRoundRipple(btnSettings); + btnSettings.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { ReaderActivityLauncher.showReaderSubs(v.getContext()); } }); - ReaderUtils.setBackgroundToRoundRipple(settingsControl); + + // search - a work in progress + View btnSearch = controls.findViewById(R.id.btn_search); + ReaderUtils.setBackgroundToRoundRipple(btnSearch); + btnSearch.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + // TODO + } + }); + + mRecyclerView.addToolbarCustomControl(controls, null); } + // the following will change the look and feel of the toolbar to match the current design mRecyclerView.setToolbarBackgroundColor(getResources().getColor(R.color.blue_medium)); mRecyclerView.setToolbarSpinnerTextColor(getResources().getColor(R.color.white)); diff --git a/WordPress/src/main/res/layout/filtered_recyclerview_settings_control.xml b/WordPress/src/main/res/layout/filtered_recyclerview_settings_control.xml deleted file mode 100644 index 606ba8dcc8a9..000000000000 --- a/WordPress/src/main/res/layout/filtered_recyclerview_settings_control.xml +++ /dev/null @@ -1,8 +0,0 @@ - - diff --git a/WordPress/src/main/res/layout/reader_filtered_recyclerview_controls.xml b/WordPress/src/main/res/layout/reader_filtered_recyclerview_controls.xml new file mode 100644 index 000000000000..05a2be2a6cee --- /dev/null +++ b/WordPress/src/main/res/layout/reader_filtered_recyclerview_controls.xml @@ -0,0 +1,31 @@ + + + + + + + + + \ No newline at end of file From 56f0beea99528dd2368b955ea17c0b51dab932c5 Mon Sep 17 00:00:00 2001 From: Nick Bradbury Date: Thu, 5 May 2016 06:53:58 -0400 Subject: [PATCH 18/50] Replaced filtered recycler's ability to add components with a simpler approach - just add a menu --- .../android/ui/FilteredRecyclerView.java | 18 ++++----- .../ui/reader/ReaderPostListFragment.java | 36 +++++++---------- .../res/layout/filtered_list_component.xml | 40 +++++-------------- .../reader_filtered_recyclerview_controls.xml | 31 -------------- WordPress/src/main/res/menu/reader_list.xml | 18 +++++++++ 5 files changed, 50 insertions(+), 93 deletions(-) delete mode 100644 WordPress/src/main/res/layout/reader_filtered_recyclerview_controls.xml create mode 100644 WordPress/src/main/res/menu/reader_list.xml diff --git a/WordPress/src/main/java/org/wordpress/android/ui/FilteredRecyclerView.java b/WordPress/src/main/java/org/wordpress/android/ui/FilteredRecyclerView.java index e41604179971..c1350e1fd0e4 100644 --- a/WordPress/src/main/java/org/wordpress/android/ui/FilteredRecyclerView.java +++ b/WordPress/src/main/java/org/wordpress/android/ui/FilteredRecyclerView.java @@ -1,6 +1,7 @@ package org.wordpress.android.ui; import android.content.Context; +import android.support.annotation.MenuRes; import android.support.design.widget.AppBarLayout; import android.support.v7.widget.LinearLayoutManager; import android.support.v7.widget.RecyclerView; @@ -12,7 +13,6 @@ import android.view.ViewGroup; import android.widget.AdapterView; import android.widget.BaseAdapter; -import android.widget.LinearLayout; import android.widget.ProgressBar; import android.widget.RelativeLayout; import android.widget.Spinner; @@ -41,7 +41,6 @@ public class FilteredRecyclerView extends RelativeLayout { private RecyclerView mRecyclerView; private TextView mEmptyView; private View mCustomEmptyView; - private LinearLayout mCustomComponentsContainer; private Toolbar mToolbar; private AppBarLayout mAppBarLayout; @@ -124,7 +123,6 @@ private void init() { mRecyclerView.setLayoutManager(new LinearLayoutManager(getContext())); mRecyclerView.addItemDecoration(new RecyclerItemDecoration(spacingHorizontal, spacingVertical)); - mCustomComponentsContainer = (LinearLayout) findViewById(R.id.custom_components_toolbar_container); mToolbar = (Toolbar) findViewById(R.id.toolbar_with_spinner); mAppBarLayout = (AppBarLayout) findViewById(R.id.app_bar_layout); @@ -278,14 +276,12 @@ public void hideLoadingProgress() { } /* - * use this to add custom control/component views to your toolbar. Components are added on the right side of the - * toolbar */ - public void addToolbarCustomControl(View v, OnClickListener clickListener){ - if (v != null){ - mCustomComponentsContainer.addView(v); - if (clickListener != null){ - v.setOnClickListener(clickListener); - } + * add a menu to the right side of the toolbar + */ + public void addToolbarMenu(@MenuRes int menuResId, Toolbar.OnMenuItemClickListener listener) { + mToolbar.inflateMenu(menuResId); + if (listener != null) { + mToolbar.setOnMenuItemClickListener(listener); } } diff --git a/WordPress/src/main/java/org/wordpress/android/ui/reader/ReaderPostListFragment.java b/WordPress/src/main/java/org/wordpress/android/ui/reader/ReaderPostListFragment.java index bb2695306ecf..09d0ea8d754d 100644 --- a/WordPress/src/main/java/org/wordpress/android/ui/reader/ReaderPostListFragment.java +++ b/WordPress/src/main/java/org/wordpress/android/ui/reader/ReaderPostListFragment.java @@ -7,7 +7,10 @@ import android.support.design.widget.Snackbar; import android.support.v7.widget.ListPopupWindow; import android.support.v7.widget.RecyclerView; +import android.support.v7.widget.Toolbar; import android.view.LayoutInflater; +import android.view.Menu; +import android.view.MenuItem; import android.view.View; import android.view.ViewGroup; import android.view.animation.Animation; @@ -461,29 +464,20 @@ public void onShowCustomEmptyView (EmptyViewMessageType emptyViewMsgType) { // add buttons to the filtered recyclerview's toolbar if (!ReaderUtils.isLoggedOutReader()) { - ViewGroup controls = (ViewGroup) inflater.inflate(R.layout.reader_filtered_recyclerview_controls, null); - - // settings - shows tags & followed sites - View btnSettings = controls.findViewById(R.id.btn_settings); - ReaderUtils.setBackgroundToRoundRipple(btnSettings); - btnSettings.setOnClickListener(new View.OnClickListener() { - @Override - public void onClick(View v) { - ReaderActivityLauncher.showReaderSubs(v.getContext()); - } - }); - - // search - a work in progress - View btnSearch = controls.findViewById(R.id.btn_search); - ReaderUtils.setBackgroundToRoundRipple(btnSearch); - btnSearch.setOnClickListener(new View.OnClickListener() { + Toolbar.OnMenuItemClickListener toolbarListener = new Toolbar.OnMenuItemClickListener() { @Override - public void onClick(View v) { - // TODO + public boolean onMenuItemClick(MenuItem item) { + if (item.getItemId() == R.id.menu_settings) { + ReaderActivityLauncher.showReaderSubs(getActivity()); + return true; + } else if (item.getItemId() == R.id.menu_search) { + // TODO + return true; + } + return false; } - }); - - mRecyclerView.addToolbarCustomControl(controls, null); + }; + mRecyclerView.addToolbarMenu(R.menu.reader_list, toolbarListener); } // the following will change the look and feel of the toolbar to match the current design diff --git a/WordPress/src/main/res/layout/filtered_list_component.xml b/WordPress/src/main/res/layout/filtered_list_component.xml index 42bb96442589..41a7fec7f182 100644 --- a/WordPress/src/main/res/layout/filtered_list_component.xml +++ b/WordPress/src/main/res/layout/filtered_list_component.xml @@ -1,6 +1,5 @@ - + android:layout_width="match_parent" + android:layout_height="@dimen/toolbar_subtitle_height"> - - - - - - - - + android:layout_centerVertical="true" + android:overlapAnchor="false" /> diff --git a/WordPress/src/main/res/layout/reader_filtered_recyclerview_controls.xml b/WordPress/src/main/res/layout/reader_filtered_recyclerview_controls.xml deleted file mode 100644 index 05a2be2a6cee..000000000000 --- a/WordPress/src/main/res/layout/reader_filtered_recyclerview_controls.xml +++ /dev/null @@ -1,31 +0,0 @@ - - - - - - - - - \ No newline at end of file diff --git a/WordPress/src/main/res/menu/reader_list.xml b/WordPress/src/main/res/menu/reader_list.xml new file mode 100644 index 000000000000..aab3f4983684 --- /dev/null +++ b/WordPress/src/main/res/menu/reader_list.xml @@ -0,0 +1,18 @@ + + + + + + + + \ No newline at end of file From f9e5ca3d9dfa9fccc4582e70bb40013735eb5fd6 Mon Sep 17 00:00:00 2001 From: Nick Bradbury Date: Thu, 5 May 2016 07:00:51 -0400 Subject: [PATCH 19/50] Check isAdded() in toolbar listener --- .../wordpress/android/ui/reader/ReaderPostListFragment.java | 3 +++ 1 file changed, 3 insertions(+) diff --git a/WordPress/src/main/java/org/wordpress/android/ui/reader/ReaderPostListFragment.java b/WordPress/src/main/java/org/wordpress/android/ui/reader/ReaderPostListFragment.java index 09d0ea8d754d..ffc4d32c3413 100644 --- a/WordPress/src/main/java/org/wordpress/android/ui/reader/ReaderPostListFragment.java +++ b/WordPress/src/main/java/org/wordpress/android/ui/reader/ReaderPostListFragment.java @@ -467,6 +467,9 @@ public void onShowCustomEmptyView (EmptyViewMessageType emptyViewMsgType) { Toolbar.OnMenuItemClickListener toolbarListener = new Toolbar.OnMenuItemClickListener() { @Override public boolean onMenuItemClick(MenuItem item) { + if (!isAdded()) { + return false; + } if (item.getItemId() == R.id.menu_settings) { ReaderActivityLauncher.showReaderSubs(getActivity()); return true; From 518db3355258e566a5d34d19242c29ab5a8db5c7 Mon Sep 17 00:00:00 2001 From: Nick Bradbury Date: Thu, 5 May 2016 19:04:51 -0400 Subject: [PATCH 20/50] First pass at adding SearchView --- WordPress/src/main/AndroidManifest.xml | 6 +- .../android/ui/FilteredRecyclerView.java | 7 +- .../ui/reader/ReaderPostListFragment.java | 68 +++++++++++++------ WordPress/src/main/res/menu/reader_list.xml | 4 +- 4 files changed, 58 insertions(+), 27 deletions(-) diff --git a/WordPress/src/main/AndroidManifest.xml b/WordPress/src/main/AndroidManifest.xml index 3985170bcd6c..5676e33c18bb 100644 --- a/WordPress/src/main/AndroidManifest.xml +++ b/WordPress/src/main/AndroidManifest.xml @@ -256,7 +256,11 @@ + android:theme="@style/Calypso.NoActionBar"> + + + + + app:actionViewClass="android.support.v7.widget.SearchView" + app:showAsAction="always|collapseActionView" /> \ No newline at end of file From ca0890d049a55e4489a7c56e729164315a52e36b Mon Sep 17 00:00:00 2001 From: Nick Bradbury Date: Thu, 5 May 2016 20:55:41 -0400 Subject: [PATCH 21/50] Fixed centering of menu items in toolbar --- .../android/ui/reader/ReaderPostListFragment.java | 11 ++++++----- .../src/main/res/layout/filtered_list_component.xml | 4 ++-- WordPress/src/main/res/values/strings.xml | 1 + 3 files changed, 9 insertions(+), 7 deletions(-) diff --git a/WordPress/src/main/java/org/wordpress/android/ui/reader/ReaderPostListFragment.java b/WordPress/src/main/java/org/wordpress/android/ui/reader/ReaderPostListFragment.java index b6390cc69f49..ac2abf9e0990 100644 --- a/WordPress/src/main/java/org/wordpress/android/ui/reader/ReaderPostListFragment.java +++ b/WordPress/src/main/java/org/wordpress/android/ui/reader/ReaderPostListFragment.java @@ -510,27 +510,28 @@ public boolean onMenuItemClick(MenuItem item) { if (item.getItemId() == R.id.menu_settings) { ReaderActivityLauncher.showReaderSubs(getActivity()); return true; - } else if (item.getItemId() == R.id.menu_search) { - // TODO - return true; } return false; } }; - Menu menu = mRecyclerView.addToolbarMenu(R.menu.reader_list, toolbarListener); + Menu menu = mRecyclerView.addToolbarMenu(R.menu.reader_list, toolbarListener); + MenuItem settingsItem = menu.findItem(R.id.menu_settings); MenuItem searchItem = menu.findItem(R.id.menu_search); + mSearchView = (SearchView) searchItem.getActionView(); SearchManager searchManager = (SearchManager) getActivity().getSystemService(Context.SEARCH_SERVICE); mSearchView.setSearchableInfo(searchManager.getSearchableInfo(getActivity().getComponentName())); - mSearchView.setQueryHint("Search hint"); + mSearchView.setQueryHint(getString(R.string.reader_hint_post_search)); mSearchView.setIconifiedByDefault(false); mSearchView.setSubmitButtonEnabled(false); mSearchView.setIconified(true); mSearchView.setFocusable(false); + + //mSearchView.setOnQueryTextListener(this); } diff --git a/WordPress/src/main/res/layout/filtered_list_component.xml b/WordPress/src/main/res/layout/filtered_list_component.xml index 41a7fec7f182..23dad694fed5 100644 --- a/WordPress/src/main/res/layout/filtered_list_component.xml +++ b/WordPress/src/main/res/layout/filtered_list_component.xml @@ -8,13 +8,13 @@ + android:layout_height="wrap_content"> diff --git a/WordPress/src/main/res/values/strings.xml b/WordPress/src/main/res/values/strings.xml index 89aa349a6779..f18067fd0f5f 100644 --- a/WordPress/src/main/res/values/strings.xml +++ b/WordPress/src/main/res/values/strings.xml @@ -1095,6 +1095,7 @@ Reply to post… Reply to comment… Enter a URL or tag to follow + Search for posts New posts From 56669422c59875a0472c1b7455f137011cdb28f0 Mon Sep 17 00:00:00 2001 From: Nick Bradbury Date: Thu, 5 May 2016 21:15:10 -0400 Subject: [PATCH 22/50] Toggle settings icon with search --- .../ui/reader/ReaderPostListFragment.java | 22 ++++++++++++++++--- .../res/layout/filtered_list_component.xml | 1 - 2 files changed, 19 insertions(+), 4 deletions(-) diff --git a/WordPress/src/main/java/org/wordpress/android/ui/reader/ReaderPostListFragment.java b/WordPress/src/main/java/org/wordpress/android/ui/reader/ReaderPostListFragment.java index ac2abf9e0990..2f1599c4f0a5 100644 --- a/WordPress/src/main/java/org/wordpress/android/ui/reader/ReaderPostListFragment.java +++ b/WordPress/src/main/java/org/wordpress/android/ui/reader/ReaderPostListFragment.java @@ -6,6 +6,7 @@ import android.os.AsyncTask; import android.os.Bundle; import android.support.design.widget.Snackbar; +import android.support.v4.view.MenuItemCompat; import android.support.v7.widget.ListPopupWindow; import android.support.v7.widget.RecyclerView; import android.support.v7.widget.SearchView; @@ -84,7 +85,10 @@ public class ReaderPostListFragment extends Fragment private View mNewPostsBar; private View mEmptyView; private ProgressBar mProgress; + private SearchView mSearchView; + private MenuItem mSettingsMenuItem; + private MenuItem mSearchMenuItem; private ReaderTag mCurrentTag; private long mCurrentBlogId; @@ -517,10 +521,10 @@ public boolean onMenuItemClick(MenuItem item) { Menu menu = mRecyclerView.addToolbarMenu(R.menu.reader_list, toolbarListener); - MenuItem settingsItem = menu.findItem(R.id.menu_settings); - MenuItem searchItem = menu.findItem(R.id.menu_search); + mSettingsMenuItem = menu.findItem(R.id.menu_settings); + mSearchMenuItem = menu.findItem(R.id.menu_search); - mSearchView = (SearchView) searchItem.getActionView(); + mSearchView = (SearchView) mSearchMenuItem.getActionView(); SearchManager searchManager = (SearchManager) getActivity().getSystemService(Context.SEARCH_SERVICE); mSearchView.setSearchableInfo(searchManager.getSearchableInfo(getActivity().getComponentName())); @@ -530,7 +534,19 @@ public boolean onMenuItemClick(MenuItem item) { mSearchView.setIconified(true); mSearchView.setFocusable(false); + MenuItemCompat.setOnActionExpandListener(mSearchMenuItem, new MenuItemCompat.OnActionExpandListener() { + @Override + public boolean onMenuItemActionExpand(MenuItem item) { + mSettingsMenuItem.setVisible(false); + return true; + } + @Override + public boolean onMenuItemActionCollapse(MenuItem item) { + mSettingsMenuItem.setVisible(true); + return true; + } + }); //mSearchView.setOnQueryTextListener(this); } diff --git a/WordPress/src/main/res/layout/filtered_list_component.xml b/WordPress/src/main/res/layout/filtered_list_component.xml index 23dad694fed5..358dc1e73667 100644 --- a/WordPress/src/main/res/layout/filtered_list_component.xml +++ b/WordPress/src/main/res/layout/filtered_list_component.xml @@ -24,7 +24,6 @@ style="@style/FilteredRecyclerViewSpinner.WordPress" android:layout_width="wrap_content" android:layout_height="wrap_content" - android:layout_centerVertical="true" android:overlapAnchor="false" /> From b295c041bfb9e3bae2dfcfab702df030aa3cb45e Mon Sep 17 00:00:00 2001 From: Nick Bradbury Date: Thu, 5 May 2016 21:27:17 -0400 Subject: [PATCH 23/50] Removed toolbar listener from addToolbarMenu --- WordPress/src/main/AndroidManifest.xml | 3 -- .../android/ui/FilteredRecyclerView.java | 5 +-- .../ui/reader/ReaderPostListFragment.java | 38 ++++++++++--------- 3 files changed, 22 insertions(+), 24 deletions(-) diff --git a/WordPress/src/main/AndroidManifest.xml b/WordPress/src/main/AndroidManifest.xml index 5676e33c18bb..429fd210a423 100644 --- a/WordPress/src/main/AndroidManifest.xml +++ b/WordPress/src/main/AndroidManifest.xml @@ -257,9 +257,6 @@ android:name=".ui.reader.ReaderPostListActivity" android:label="@string/reader" android:theme="@style/Calypso.NoActionBar"> - - - Date: Thu, 5 May 2016 21:31:10 -0400 Subject: [PATCH 24/50] Simplified search view config --- .../android/ui/reader/ReaderPostListFragment.java | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/WordPress/src/main/java/org/wordpress/android/ui/reader/ReaderPostListFragment.java b/WordPress/src/main/java/org/wordpress/android/ui/reader/ReaderPostListFragment.java index a791840c54a6..e0b2d6ca823e 100644 --- a/WordPress/src/main/java/org/wordpress/android/ui/reader/ReaderPostListFragment.java +++ b/WordPress/src/main/java/org/wordpress/android/ui/reader/ReaderPostListFragment.java @@ -1,7 +1,6 @@ package org.wordpress.android.ui.reader; import android.app.Fragment; -import android.app.SearchManager; import android.content.Context; import android.os.AsyncTask; import android.os.Bundle; @@ -517,14 +516,10 @@ public boolean onMenuItemClick(MenuItem item) { }); mSearchView = (SearchView) mSearchMenuItem.getActionView(); - SearchManager searchManager = (SearchManager) getActivity().getSystemService(Context.SEARCH_SERVICE); - mSearchView.setSearchableInfo(searchManager.getSearchableInfo(getActivity().getComponentName())); - mSearchView.setQueryHint(getString(R.string.reader_hint_post_search)); - mSearchView.setIconifiedByDefault(false); mSearchView.setSubmitButtonEnabled(false); + mSearchView.setIconifiedByDefault(false); mSearchView.setIconified(true); - mSearchView.setFocusable(false); MenuItemCompat.setOnActionExpandListener(mSearchMenuItem, new MenuItemCompat.OnActionExpandListener() { @Override From ec694f25e2b11506d1540100bbfe542168533855 Mon Sep 17 00:00:00 2001 From: Nick Bradbury Date: Fri, 6 May 2016 14:13:04 -0400 Subject: [PATCH 25/50] Added bare-bones SearchViewStyle --- .../android/ui/reader/ReaderActivityLauncher.java | 14 ++++++++++++++ .../android/ui/reader/ReaderConstants.java | 1 + .../android/ui/reader/ReaderPostListFragment.java | 8 +++++++- .../wordpress/android/ui/reader/ReaderTypes.java | 5 +++-- WordPress/src/main/res/values/styles.xml | 4 ++++ 5 files changed, 29 insertions(+), 3 deletions(-) diff --git a/WordPress/src/main/java/org/wordpress/android/ui/reader/ReaderActivityLauncher.java b/WordPress/src/main/java/org/wordpress/android/ui/reader/ReaderActivityLauncher.java index f79347c1d6b8..3ec16df08c3b 100644 --- a/WordPress/src/main/java/org/wordpress/android/ui/reader/ReaderActivityLauncher.java +++ b/WordPress/src/main/java/org/wordpress/android/ui/reader/ReaderActivityLauncher.java @@ -134,6 +134,20 @@ public static void showReaderTagPreview(Context context, ReaderTag tag) { context.startActivity(intent); } + // TODO: implement search in ReaderPostListActivity for a future PR + public static void showReaderSearchResults(Context context, String query) { + if (TextUtils.isEmpty(query)) { + return; + } + + // TODO: track this + //AnalyticsTracker.track(AnalyticsTracker.Stat.READER_BLOG_PREVIEWED); + Intent intent = new Intent(context, ReaderPostListActivity.class); + intent.putExtra(ReaderConstants.ARG_SEARCH_QUERY, query); + intent.putExtra(ReaderConstants.ARG_POST_LIST_TYPE, ReaderPostListType.SEARCH_RESULTS); + context.startActivity(intent); + } + /* * show comments for the passed Ids diff --git a/WordPress/src/main/java/org/wordpress/android/ui/reader/ReaderConstants.java b/WordPress/src/main/java/org/wordpress/android/ui/reader/ReaderConstants.java index b5f7181799bf..f4732f21ec5c 100644 --- a/WordPress/src/main/java/org/wordpress/android/ui/reader/ReaderConstants.java +++ b/WordPress/src/main/java/org/wordpress/android/ui/reader/ReaderConstants.java @@ -23,6 +23,7 @@ public class ReaderConstants { static final String ARG_POST_LIST_TYPE = "post_list_type"; static final String ARG_CONTENT = "content"; static final String ARG_IS_SINGLE_POST = "is_single_post"; + static final String ARG_SEARCH_QUERY = "search_query"; static final String KEY_ALREADY_UPDATED = "already_updated"; static final String KEY_ALREADY_REQUESTED = "already_requested"; diff --git a/WordPress/src/main/java/org/wordpress/android/ui/reader/ReaderPostListFragment.java b/WordPress/src/main/java/org/wordpress/android/ui/reader/ReaderPostListFragment.java index e0b2d6ca823e..500a99d47129 100644 --- a/WordPress/src/main/java/org/wordpress/android/ui/reader/ReaderPostListFragment.java +++ b/WordPress/src/main/java/org/wordpress/android/ui/reader/ReaderPostListFragment.java @@ -521,6 +521,7 @@ public boolean onMenuItemClick(MenuItem item) { mSearchView.setIconifiedByDefault(false); mSearchView.setIconified(true); + // toggle settings icon when search expands/collapses MenuItemCompat.setOnActionExpandListener(mSearchMenuItem, new MenuItemCompat.OnActionExpandListener() { @Override public boolean onMenuItemActionExpand(MenuItem item) { @@ -539,7 +540,12 @@ public boolean onMenuItemActionCollapse(MenuItem item) { @Override public boolean onQueryTextSubmit(String query) { // TODO: perform search - return false; + if (getPostListType() == ReaderPostListType.SEARCH_RESULTS) { + // reuse existing fragment + } else { + ReaderActivityLauncher.showReaderSearchResults(getActivity(), query); + } + return true; } @Override diff --git a/WordPress/src/main/java/org/wordpress/android/ui/reader/ReaderTypes.java b/WordPress/src/main/java/org/wordpress/android/ui/reader/ReaderTypes.java index 74718bddd643..9b94773dada6 100644 --- a/WordPress/src/main/java/org/wordpress/android/ui/reader/ReaderTypes.java +++ b/WordPress/src/main/java/org/wordpress/android/ui/reader/ReaderTypes.java @@ -5,10 +5,11 @@ public class ReaderTypes { public static final ReaderPostListType DEFAULT_POST_LIST_TYPE = ReaderPostListType.TAG_FOLLOWED; - public static enum ReaderPostListType { + public enum ReaderPostListType { TAG_FOLLOWED, // list posts in a followed tag TAG_PREVIEW, // list posts in a specific tag - BLOG_PREVIEW; // list posts in a specific blog/feed + BLOG_PREVIEW, // list posts in a specific blog/feed + SEARCH_RESULTS; // list posts matching a specific search keyword or phrase public boolean isTagType() { return this.equals(TAG_FOLLOWED) || this.equals(TAG_PREVIEW); diff --git a/WordPress/src/main/res/values/styles.xml b/WordPress/src/main/res/values/styles.xml index 56ee2b3ce2d7..1edaff040e9b 100644 --- a/WordPress/src/main/res/values/styles.xml +++ b/WordPress/src/main/res/values/styles.xml @@ -27,8 +27,12 @@ true @style/WordPress.SwipeToRefresh + @style/WordPress.SearchViewStyle + + From 5b1463e272f6038e4f6be4efe72c277ff67b82a8 Mon Sep 17 00:00:00 2001 From: Nick Bradbury Date: Fri, 6 May 2016 15:26:59 -0400 Subject: [PATCH 26/50] Implemented shell for search results, including empty message --- .../ui/reader/ReaderActivityLauncher.java | 3 +- .../ui/reader/ReaderPostListActivity.java | 21 ++++++ .../ui/reader/ReaderPostListFragment.java | 67 ++++++++++++------- .../ui/reader/adapters/ReaderPostAdapter.java | 19 ++++++ WordPress/src/main/res/values/strings.xml | 5 +- 5 files changed, 89 insertions(+), 26 deletions(-) diff --git a/WordPress/src/main/java/org/wordpress/android/ui/reader/ReaderActivityLauncher.java b/WordPress/src/main/java/org/wordpress/android/ui/reader/ReaderActivityLauncher.java index 3ec16df08c3b..b666e8cc0ca8 100644 --- a/WordPress/src/main/java/org/wordpress/android/ui/reader/ReaderActivityLauncher.java +++ b/WordPress/src/main/java/org/wordpress/android/ui/reader/ReaderActivityLauncher.java @@ -134,14 +134,13 @@ public static void showReaderTagPreview(Context context, ReaderTag tag) { context.startActivity(intent); } - // TODO: implement search in ReaderPostListActivity for a future PR public static void showReaderSearchResults(Context context, String query) { if (TextUtils.isEmpty(query)) { return; } // TODO: track this - //AnalyticsTracker.track(AnalyticsTracker.Stat.READER_BLOG_PREVIEWED); + //AnalyticsTracker.track(AnalyticsTracker.Stat.???); Intent intent = new Intent(context, ReaderPostListActivity.class); intent.putExtra(ReaderConstants.ARG_SEARCH_QUERY, query); intent.putExtra(ReaderConstants.ARG_POST_LIST_TYPE, ReaderPostListType.SEARCH_RESULTS); diff --git a/WordPress/src/main/java/org/wordpress/android/ui/reader/ReaderPostListActivity.java b/WordPress/src/main/java/org/wordpress/android/ui/reader/ReaderPostListActivity.java index b1ea96be4c1f..6b0277ee7acb 100644 --- a/WordPress/src/main/java/org/wordpress/android/ui/reader/ReaderPostListActivity.java +++ b/WordPress/src/main/java/org/wordpress/android/ui/reader/ReaderPostListActivity.java @@ -8,6 +8,7 @@ import android.support.v7.app.ActionBar; import android.support.v7.app.AppCompatActivity; import android.support.v7.widget.Toolbar; +import android.text.TextUtils; import android.view.MenuItem; import org.wordpress.android.R; @@ -58,6 +59,12 @@ public void onCreate(Bundle savedInstanceState) { if (tag != null && savedInstanceState == null) { showListFragmentForTag(tag, mPostListType); } + } else if (getPostListType() == ReaderPostListType.SEARCH_RESULTS) { + String query = getIntent().getStringExtra(ReaderConstants.ARG_SEARCH_QUERY); + if (!TextUtils.isEmpty(query) && savedInstanceState == null) { + setTitle(String.format(getString(R.string.reader_title_search_results), query)); + showListFragmentForSearch(query); + } } } @@ -158,6 +165,20 @@ private void showListFragmentForFeed(long feedId) { .commit(); } + /* + * show fragment containing list of posts matching the passed search query + */ + private void showListFragmentForSearch(@NonNull String query) { + if (isFinishing()) { + return; + } + Fragment fragment = ReaderPostListFragment.newInstanceForSearch(query); + getFragmentManager() + .beginTransaction() + .replace(R.id.fragment_container, fragment, getString(R.string.fragment_tag_reader_post_list)) + .commit(); + } + private ReaderPostListFragment getListFragment() { Fragment fragment = getFragmentManager().findFragmentByTag(getString(R.string.fragment_tag_reader_post_list)); if (fragment == null) { diff --git a/WordPress/src/main/java/org/wordpress/android/ui/reader/ReaderPostListFragment.java b/WordPress/src/main/java/org/wordpress/android/ui/reader/ReaderPostListFragment.java index 500a99d47129..89bc772a9803 100644 --- a/WordPress/src/main/java/org/wordpress/android/ui/reader/ReaderPostListFragment.java +++ b/WordPress/src/main/java/org/wordpress/android/ui/reader/ReaderPostListFragment.java @@ -4,6 +4,7 @@ import android.content.Context; import android.os.AsyncTask; import android.os.Bundle; +import android.support.annotation.NonNull; import android.support.design.widget.Snackbar; import android.support.v4.view.MenuItemCompat; import android.support.v7.widget.ListPopupWindow; @@ -91,6 +92,7 @@ public class ReaderPostListFragment extends Fragment private ReaderTag mCurrentTag; private long mCurrentBlogId; private long mCurrentFeedId; + private String mCurrentSearchQuery; private ReaderPostListType mPostListType; private int mRestorePosition; @@ -182,6 +184,19 @@ public static ReaderPostListFragment newInstanceForFeed(long feedId) { return fragment; } + public static ReaderPostListFragment newInstanceForSearch(@NonNull String query) { + AppLog.d(T.READER, "reader post list > newInstance (search)"); + + Bundle args = new Bundle(); + args.putString(ReaderConstants.ARG_SEARCH_QUERY, query); + args.putSerializable(ReaderConstants.ARG_POST_LIST_TYPE, ReaderPostListType.SEARCH_RESULTS); + + ReaderPostListFragment fragment = new ReaderPostListFragment(); + fragment.setArguments(args); + + return fragment; + } + @Override public void setArguments(Bundle args) { super.setArguments(args); @@ -196,6 +211,7 @@ public void setArguments(Bundle args) { mCurrentBlogId = args.getLong(ReaderConstants.ARG_BLOG_ID); mCurrentFeedId = args.getLong(ReaderConstants.ARG_FEED_ID); + mCurrentSearchQuery = args.getString(ReaderConstants.ARG_SEARCH_QUERY); if (getPostListType() == ReaderPostListType.TAG_PREVIEW && hasCurrentTag()) { mTagPreviewHistory.push(getCurrentTagName()); @@ -218,6 +234,9 @@ public void onCreate(Bundle savedInstanceState) { if (savedInstanceState.containsKey(ReaderConstants.ARG_FEED_ID)) { mCurrentFeedId = savedInstanceState.getLong(ReaderConstants.ARG_FEED_ID); } + if (savedInstanceState.containsKey(ReaderConstants.ARG_SEARCH_QUERY)) { + mCurrentSearchQuery = savedInstanceState.getString(ReaderConstants.ARG_SEARCH_QUERY); + } if (savedInstanceState.containsKey(ReaderConstants.ARG_POST_LIST_TYPE)) { mPostListType = (ReaderPostListType) savedInstanceState.getSerializable(ReaderConstants.ARG_POST_LIST_TYPE); } @@ -352,6 +371,7 @@ public void onSaveInstanceState(Bundle outState) { outState.putLong(ReaderConstants.ARG_BLOG_ID, mCurrentBlogId); outState.putLong(ReaderConstants.ARG_FEED_ID, mCurrentFeedId); + outState.putString(ReaderConstants.ARG_SEARCH_QUERY, mCurrentSearchQuery); outState.putBoolean(ReaderConstants.KEY_WAS_PAUSED, mWasPaused); outState.putBoolean(ReaderConstants.KEY_ALREADY_UPDATED, mHasUpdatedPosts); outState.putBoolean(ReaderConstants.KEY_FIRST_LOAD, mFirstLoad); @@ -637,9 +657,7 @@ private boolean shouldShowBoxAndPagesAnimation() { return getPostListType().isTagType(); } private void startBoxAndPagesAnimation() { - if (!isAdded()) { - return; - } + if (!isAdded()) return; ImageView page1 = (ImageView) mEmptyView.findViewById(R.id.empty_tags_box_page1); ImageView page2 = (ImageView) mEmptyView.findViewById(R.id.empty_tags_box_page2); @@ -651,49 +669,50 @@ private void startBoxAndPagesAnimation() { } private void setEmptyTitleAndDescription(boolean requestFailed) { - if (!isAdded()) { - return; - } + if (!isAdded()) return; - int titleResId; - int descriptionResId = 0; + String title; + String description = null; if (!NetworkUtils.isNetworkAvailable(getActivity())) { - titleResId = R.string.reader_empty_posts_no_connection; + title = getString(R.string.reader_empty_posts_no_connection); } else if (requestFailed) { - titleResId = R.string.reader_empty_posts_request_failed; + title = getString(R.string.reader_empty_posts_request_failed); } else if (isUpdating()) { - titleResId = R.string.reader_empty_posts_in_tag_updating; + title = getString(R.string.reader_empty_posts_in_tag_updating); } else if (getPostListType() == ReaderPostListType.BLOG_PREVIEW) { - titleResId = R.string.reader_empty_posts_in_blog; + title = getString(R.string.reader_empty_posts_in_blog); } else if (getPostListType() == ReaderPostListType.TAG_FOLLOWED && hasCurrentTag()) { if (getCurrentTag().isFollowedSites()) { if (ReaderBlogTable.hasFollowedBlogs()) { - titleResId = R.string.reader_empty_followed_blogs_no_recent_posts_title; - descriptionResId = R.string.reader_empty_followed_blogs_no_recent_posts_description; + title = getString(R.string.reader_empty_followed_blogs_no_recent_posts_title); + description = getString(R.string.reader_empty_followed_blogs_no_recent_posts_description); } else { - titleResId = R.string.reader_empty_followed_blogs_title; - descriptionResId = R.string.reader_empty_followed_blogs_description; + title = getString(R.string.reader_empty_followed_blogs_title); + description = getString(R.string.reader_empty_followed_blogs_description); } } else if (getCurrentTag().isPostsILike()) { - titleResId = R.string.reader_empty_posts_liked; + title = getString(R.string.reader_empty_posts_liked); } else if (getCurrentTag().tagType == ReaderTagType.CUSTOM_LIST) { - titleResId = R.string.reader_empty_posts_in_custom_list; + title = getString(R.string.reader_empty_posts_in_custom_list); } else { - titleResId = R.string.reader_empty_posts_in_tag; + title = getString(R.string.reader_empty_posts_in_tag); } + } else if (getPostListType() == ReaderPostListType.SEARCH_RESULTS) { + title = getString(R.string.reader_empty_posts_in_search_title); + description = String.format(getString(R.string.reader_empty_posts_in_search_description), mCurrentSearchQuery); } else { - titleResId = R.string.reader_empty_posts_in_tag; + title = getString(R.string.reader_empty_posts_in_tag); } TextView titleView = (TextView) mEmptyView.findViewById(R.id.title_empty); - titleView.setText(getString(titleResId)); + titleView.setText(title); TextView descriptionView = (TextView) mEmptyView.findViewById(R.id.description_empty); - if (descriptionResId == 0) { + if (description == null) { descriptionView.setVisibility(View.INVISIBLE); } else { - descriptionView.setText(getString(descriptionResId)); + descriptionView.setText(description); descriptionView.setVisibility(View.VISIBLE); } } @@ -780,6 +799,8 @@ private ReaderPostAdapter getPostAdapter() { mPostAdapter.setCurrentTag(getCurrentTag()); } else if (getPostListType() == ReaderPostListType.BLOG_PREVIEW) { mPostAdapter.setCurrentBlogAndFeed(mCurrentBlogId, mCurrentFeedId); + } else if (getPostListType() == ReaderPostListType.SEARCH_RESULTS) { + mPostAdapter.setCurrentSearchQuery(mCurrentSearchQuery); } } return mPostAdapter; diff --git a/WordPress/src/main/java/org/wordpress/android/ui/reader/adapters/ReaderPostAdapter.java b/WordPress/src/main/java/org/wordpress/android/ui/reader/adapters/ReaderPostAdapter.java index 5d18ea78917e..08f422170f2e 100644 --- a/WordPress/src/main/java/org/wordpress/android/ui/reader/adapters/ReaderPostAdapter.java +++ b/WordPress/src/main/java/org/wordpress/android/ui/reader/adapters/ReaderPostAdapter.java @@ -2,6 +2,7 @@ import android.content.Context; import android.os.AsyncTask; +import android.support.annotation.NonNull; import android.support.v7.widget.CardView; import android.support.v7.widget.RecyclerView; import android.text.TextUtils; @@ -46,6 +47,7 @@ public class ReaderPostAdapter extends RecyclerView.AdapterTags & Blogs %1$d of %2$d @string/comments + Search for %s Followed tags @@ -1095,7 +1096,7 @@ Reply to post… Reply to comment… Enter a URL or tag to follow - Search for posts + Search on WordPress.com New posts @@ -1177,6 +1178,8 @@ You haven\'t liked any posts No comments yet This blog is empty + No Results + No posts found for \"%s\" for your language Originally posted by %1$s on %2$s From d1594cae8e0e8c87eff86c1578f0d81ae77bfd88 Mon Sep 17 00:00:00 2001 From: Nick Bradbury Date: Fri, 6 May 2016 15:55:21 -0400 Subject: [PATCH 27/50] Clear the post list when search is expanded, reload the list when search is collapsed --- .../android/ui/reader/ReaderPostListFragment.java | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) diff --git a/WordPress/src/main/java/org/wordpress/android/ui/reader/ReaderPostListFragment.java b/WordPress/src/main/java/org/wordpress/android/ui/reader/ReaderPostListFragment.java index 89bc772a9803..aa17a871de61 100644 --- a/WordPress/src/main/java/org/wordpress/android/ui/reader/ReaderPostListFragment.java +++ b/WordPress/src/main/java/org/wordpress/android/ui/reader/ReaderPostListFragment.java @@ -541,17 +541,20 @@ public boolean onMenuItemClick(MenuItem item) { mSearchView.setIconifiedByDefault(false); mSearchView.setIconified(true); - // toggle settings icon when search expands/collapses MenuItemCompat.setOnActionExpandListener(mSearchMenuItem, new MenuItemCompat.OnActionExpandListener() { @Override public boolean onMenuItemActionExpand(MenuItem item) { + // hide settings icon and clear post list when search input is expanded mSettingsMenuItem.setVisible(false); + getPostAdapter().clear(); return true; } @Override public boolean onMenuItemActionCollapse(MenuItem item) { + // redisplay settings icon and reload post list when search input is collapsed mSettingsMenuItem.setVisible(true); + reloadPosts(); return true; } }); @@ -576,6 +579,12 @@ public boolean onQueryTextChange(String newText) { ); } + /* + * is the search input showing? + */ + private boolean isSearchViewExpanded() { + return mSearchView != null && !mSearchView.isIconified(); + } /* * called when user taps follow item in popup menu for a post */ @@ -1258,9 +1267,7 @@ private void trackTagLoaded(ReaderTag tag) { */ @Override public void onShowPostPopup(View view, final ReaderPost post) { - if (view == null || post == null || !isAdded()) { - return; - } + if (view == null || post == null || !isAdded()) return; Context context = view.getContext(); final ListPopupWindow listPopup = new ListPopupWindow(context); From 5bdb33d45147f6741a9ecef95c9ac4936f0e2d01 Mon Sep 17 00:00:00 2001 From: Nick Bradbury Date: Fri, 6 May 2016 16:06:07 -0400 Subject: [PATCH 28/50] Renamed FilteredRecyclerViewFilterContainer style to FilteredRecyclerViewToolbar --- WordPress/src/main/res/layout-sw720dp/stats_activity.xml | 2 +- WordPress/src/main/res/layout/filtered_list_component.xml | 2 +- WordPress/src/main/res/layout/stats_activity.xml | 2 +- WordPress/src/main/res/values/styles.xml | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/WordPress/src/main/res/layout-sw720dp/stats_activity.xml b/WordPress/src/main/res/layout-sw720dp/stats_activity.xml index 68c844301037..54585e28cd93 100644 --- a/WordPress/src/main/res/layout-sw720dp/stats_activity.xml +++ b/WordPress/src/main/res/layout-sw720dp/stats_activity.xml @@ -21,7 +21,7 @@ android:id="@+id/toolbar_filter" android:layout_width="match_parent" android:layout_height="wrap_content" - style="@style/FilteredRecyclerViewFilterContainer" + style="@style/FilteredRecyclerViewToolbar" app:layout_scrollFlags="scroll|enterAlways"> diff --git a/WordPress/src/main/res/values/styles.xml b/WordPress/src/main/res/values/styles.xml index 1edaff040e9b..2d3b127415bc 100644 --- a/WordPress/src/main/res/values/styles.xml +++ b/WordPress/src/main/res/values/styles.xml @@ -90,7 +90,7 @@ @dimen/text_sz_large - -