From 2c9cdcb0b62cac26bedc6ce491731957264cfd2f Mon Sep 17 00:00:00 2001 From: skykelsey Date: Wed, 28 Sep 2016 14:26:51 -0700 Subject: [PATCH 001/100] Reformat AppRelease classes. --- .../apptentive/android/sdk/model/AppRelease.java | 14 ++++++-------- .../android/sdk/model/AppReleaseFactory.java | 4 +--- .../android/sdk/storage/AppReleaseManager.java | 10 ++-------- 3 files changed, 9 insertions(+), 19 deletions(-) diff --git a/apptentive/src/main/java/com/apptentive/android/sdk/model/AppRelease.java b/apptentive/src/main/java/com/apptentive/android/sdk/model/AppRelease.java index 29c1f7f97..ef9a5e326 100644 --- a/apptentive/src/main/java/com/apptentive/android/sdk/model/AppRelease.java +++ b/apptentive/src/main/java/com/apptentive/android/sdk/model/AppRelease.java @@ -7,11 +7,9 @@ package com.apptentive.android.sdk.model; import com.apptentive.android.sdk.ApptentiveLog; + import org.json.JSONException; -/** - * @author Sky Kelsey - */ public class AppRelease extends Payload { private static final String KEY_VERSION = "version"; @@ -36,7 +34,7 @@ public void initBaseType() { public String getVersion() { try { - if(!isNull(KEY_VERSION)) { + if (!isNull(KEY_VERSION)) { return getString(KEY_VERSION); } } catch (JSONException e) { @@ -55,7 +53,7 @@ public void setVersion(String version) { public String getBuildNumber() { try { - if(!isNull(KEY_BUILD_NUMBER)) { + if (!isNull(KEY_BUILD_NUMBER)) { return getString(KEY_BUILD_NUMBER); } } catch (JSONException e) { @@ -74,7 +72,7 @@ public void setBuildNumber(String buildNumber) { public String getIdentifier() { try { - if(!isNull(KEY_IDENTIFIER)) { + if (!isNull(KEY_IDENTIFIER)) { return getString(KEY_IDENTIFIER); } } catch (JSONException e) { @@ -93,7 +91,7 @@ public void setIdentifier(String identifier) { public String getTargetSdkVersion() { try { - if(!isNull(KEY_TARGET_SDK_VERSION)) { + if (!isNull(KEY_TARGET_SDK_VERSION)) { return getString(KEY_TARGET_SDK_VERSION); } } catch (JSONException e) { @@ -112,7 +110,7 @@ public void setTargetSdkVersion(String targetSdkVersion) { public String getAppStore() { try { - if(!isNull(KEY_APP_STORE)) { + if (!isNull(KEY_APP_STORE)) { return getString(KEY_APP_STORE); } } catch (JSONException e) { diff --git a/apptentive/src/main/java/com/apptentive/android/sdk/model/AppReleaseFactory.java b/apptentive/src/main/java/com/apptentive/android/sdk/model/AppReleaseFactory.java index ad447e7ed..aa4236bfe 100644 --- a/apptentive/src/main/java/com/apptentive/android/sdk/model/AppReleaseFactory.java +++ b/apptentive/src/main/java/com/apptentive/android/sdk/model/AppReleaseFactory.java @@ -7,11 +7,9 @@ package com.apptentive.android.sdk.model; import com.apptentive.android.sdk.ApptentiveLog; + import org.json.JSONException; -/** - * @author Sky Kelsey - */ public class AppReleaseFactory { public static AppRelease fromJson(String json) { try { diff --git a/apptentive/src/main/java/com/apptentive/android/sdk/storage/AppReleaseManager.java b/apptentive/src/main/java/com/apptentive/android/sdk/storage/AppReleaseManager.java index e4d2f94eb..215a2eaa8 100644 --- a/apptentive/src/main/java/com/apptentive/android/sdk/storage/AppReleaseManager.java +++ b/apptentive/src/main/java/com/apptentive/android/sdk/storage/AppReleaseManager.java @@ -6,29 +6,23 @@ package com.apptentive.android.sdk.storage; -import android.content.Context; import android.content.SharedPreferences; -import android.content.pm.PackageInfo; -import android.content.pm.PackageManager; import com.apptentive.android.sdk.ApptentiveInternal; import com.apptentive.android.sdk.ApptentiveLog; import com.apptentive.android.sdk.model.AppRelease; import com.apptentive.android.sdk.util.Constants; import com.apptentive.android.sdk.util.JsonDiffer; -import com.apptentive.android.sdk.util.Util; + import org.json.JSONException; -/** - * @author Sky Kelsey - */ public class AppReleaseManager { public static AppRelease storeAppReleaseAndReturnDiff(AppRelease currentAppRelease) { AppRelease stored = getStoredAppRelease(); Object diff = JsonDiffer.getDiff(stored, currentAppRelease); - if(diff != null) { + if (diff != null) { try { storeAppRelease(currentAppRelease); return new AppRelease(diff.toString()); From 0e07ca5e135d084d0335f44391d36095a326e2c7 Mon Sep 17 00:00:00 2001 From: skykelsey Date: Wed, 28 Sep 2016 14:34:32 -0700 Subject: [PATCH 002/100] Start sending `AppRelease` with new format. ANDROID-771 --- .../android/sdk/ApptentiveInternal.java | 5 +- .../android/sdk/model/AppRelease.java | 48 ++++++++++++------- 2 files changed, 35 insertions(+), 18 deletions(-) diff --git a/apptentive/src/main/java/com/apptentive/android/sdk/ApptentiveInternal.java b/apptentive/src/main/java/com/apptentive/android/sdk/ApptentiveInternal.java index 7e6596a27..95b3e59d1 100644 --- a/apptentive/src/main/java/com/apptentive/android/sdk/ApptentiveInternal.java +++ b/apptentive/src/main/java/com/apptentive/android/sdk/ApptentiveInternal.java @@ -578,9 +578,10 @@ public boolean init() { currentVersionName = packageInfo.versionName; VersionHistoryEntry lastVersionEntrySeen = VersionHistoryStore.getLastVersionSeen(); AppRelease appRelease = new AppRelease(); - appRelease.setVersion(currentVersionName); + appRelease.setType("android"); + appRelease.setVersionName(currentVersionName); appRelease.setIdentifier(appPackageName); - appRelease.setBuildNumber(String.valueOf(currentVersionCode)); + appRelease.setVersionCode(currentVersionCode); appRelease.setTargetSdkVersion(String.valueOf(packageInfo.applicationInfo.targetSdkVersion)); appRelease.setAppStore(Util.getInstallerPackageName(appContext)); // Set Apptentive theme inheritance metrics diff --git a/apptentive/src/main/java/com/apptentive/android/sdk/model/AppRelease.java b/apptentive/src/main/java/com/apptentive/android/sdk/model/AppRelease.java index ef9a5e326..d7805fe89 100644 --- a/apptentive/src/main/java/com/apptentive/android/sdk/model/AppRelease.java +++ b/apptentive/src/main/java/com/apptentive/android/sdk/model/AppRelease.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2014, Apptentive, Inc. All Rights Reserved. + * Copyright (c) 2016, Apptentive, Inc. All Rights Reserved. * Please refer to the LICENSE file for the terms and conditions * under which redistribution and use of this file is permitted. */ @@ -12,8 +12,9 @@ public class AppRelease extends Payload { - private static final String KEY_VERSION = "version"; - private static final String KEY_BUILD_NUMBER = "build_number"; + private static final String KEY_TYPE = "type"; + private static final String KEY_VERSION_NAME = "version_name"; + private static final String KEY_VERSION_CODE = "version_code"; private static final String KEY_IDENTIFIER = "identifier"; private static final String KEY_TARGET_SDK_VERSION = "target_sdk_version"; private static final String KEY_APP_STORE = "app_store"; @@ -32,10 +33,25 @@ public void initBaseType() { setBaseType(BaseType.app_release); } - public String getVersion() { + public String getType() { + if (!isNull(KEY_TYPE)) { + return optString(KEY_TYPE, null); + } + return null; + } + + public void setType(String type) { + try { + put(KEY_TYPE, type); + } catch (JSONException e) { + ApptentiveLog.w("Error adding %s to AppRelease.", KEY_TYPE); + } + } + + public String getVersionName() { try { - if (!isNull(KEY_VERSION)) { - return getString(KEY_VERSION); + if (!isNull(KEY_VERSION_NAME)) { + return getString(KEY_VERSION_NAME); } } catch (JSONException e) { // Ignore @@ -43,30 +59,30 @@ public String getVersion() { return null; } - public void setVersion(String version) { + public void setVersionName(String versionName) { try { - put(KEY_VERSION, version); + put(KEY_VERSION_NAME, versionName); } catch (JSONException e) { - ApptentiveLog.w("Error adding %s to AppRelease.", KEY_VERSION); + ApptentiveLog.w("Error adding %s to AppRelease.", KEY_VERSION_NAME); } } - public String getBuildNumber() { + public int getVersionCode() { try { - if (!isNull(KEY_BUILD_NUMBER)) { - return getString(KEY_BUILD_NUMBER); + if (!isNull(KEY_VERSION_CODE)) { + return getInt(KEY_VERSION_CODE); } } catch (JSONException e) { // Ignore } - return null; + return -1; } - public void setBuildNumber(String buildNumber) { + public void setVersionCode(int versionCode) { try { - put(KEY_BUILD_NUMBER, buildNumber); + put(KEY_VERSION_CODE, versionCode); } catch (JSONException e) { - ApptentiveLog.w("Error adding %s to AppRelease.", KEY_BUILD_NUMBER); + ApptentiveLog.w("Error adding %s to AppRelease.", KEY_VERSION_CODE); } } From b3103e7abeb9446a793587dd8dc05ee7f9d1d73d Mon Sep 17 00:00:00 2001 From: skykelsey Date: Wed, 28 Sep 2016 15:13:22 -0700 Subject: [PATCH 003/100] Update getter scheme for app_release. --- .../android/sdk/model/AppRelease.java | 40 +++++-------------- 1 file changed, 10 insertions(+), 30 deletions(-) diff --git a/apptentive/src/main/java/com/apptentive/android/sdk/model/AppRelease.java b/apptentive/src/main/java/com/apptentive/android/sdk/model/AppRelease.java index d7805fe89..93de398b3 100644 --- a/apptentive/src/main/java/com/apptentive/android/sdk/model/AppRelease.java +++ b/apptentive/src/main/java/com/apptentive/android/sdk/model/AppRelease.java @@ -49,12 +49,8 @@ public void setType(String type) { } public String getVersionName() { - try { - if (!isNull(KEY_VERSION_NAME)) { - return getString(KEY_VERSION_NAME); - } - } catch (JSONException e) { - // Ignore + if (!isNull(KEY_VERSION_NAME)) { + return optString(KEY_VERSION_NAME, null); } return null; } @@ -68,12 +64,8 @@ public void setVersionName(String versionName) { } public int getVersionCode() { - try { - if (!isNull(KEY_VERSION_CODE)) { - return getInt(KEY_VERSION_CODE); - } - } catch (JSONException e) { - // Ignore + if (!isNull(KEY_VERSION_CODE)) { + return optInt(KEY_VERSION_CODE, -1); } return -1; } @@ -87,12 +79,8 @@ public void setVersionCode(int versionCode) { } public String getIdentifier() { - try { - if (!isNull(KEY_IDENTIFIER)) { - return getString(KEY_IDENTIFIER); - } - } catch (JSONException e) { - // Ignore + if (!isNull(KEY_IDENTIFIER)) { + return optString(KEY_IDENTIFIER, null); } return null; } @@ -106,12 +94,8 @@ public void setIdentifier(String identifier) { } public String getTargetSdkVersion() { - try { - if (!isNull(KEY_TARGET_SDK_VERSION)) { - return getString(KEY_TARGET_SDK_VERSION); - } - } catch (JSONException e) { - // Ignore + if (!isNull(KEY_TARGET_SDK_VERSION)) { + return optString(KEY_TARGET_SDK_VERSION); } return null; } @@ -125,12 +109,8 @@ public void setTargetSdkVersion(String targetSdkVersion) { } public String getAppStore() { - try { - if (!isNull(KEY_APP_STORE)) { - return getString(KEY_APP_STORE); - } - } catch (JSONException e) { - // Ignore + if (!isNull(KEY_APP_STORE)) { + return optString(KEY_APP_STORE, null); } return null; } From c954de88a2fac2bad1efa210d40d018365117790 Mon Sep 17 00:00:00 2001 From: skykelsey Date: Wed, 28 Sep 2016 15:24:57 -0700 Subject: [PATCH 004/100] Don't send AppRelease diffs. Send the whole update each time it needs updating. --- .../android/sdk/ApptentiveInternal.java | 7 ++-- .../sdk/storage/AppReleaseManager.java | 34 ++----------------- 2 files changed, 4 insertions(+), 37 deletions(-) diff --git a/apptentive/src/main/java/com/apptentive/android/sdk/ApptentiveInternal.java b/apptentive/src/main/java/com/apptentive/android/sdk/ApptentiveInternal.java index 95b3e59d1..b634d7227 100644 --- a/apptentive/src/main/java/com/apptentive/android/sdk/ApptentiveInternal.java +++ b/apptentive/src/main/java/com/apptentive/android/sdk/ApptentiveInternal.java @@ -667,11 +667,8 @@ public boolean init() { private void onVersionChanged(Integer previousVersionCode, Integer currentVersionCode, String previousVersionName, String currentVersionName, AppRelease currentAppRelease) { ApptentiveLog.i("Version changed: Name: %s => %s, Code: %d => %d", previousVersionName, currentVersionName, previousVersionCode, currentVersionCode); VersionHistoryStore.updateVersionHistory(currentVersionCode, currentVersionName); - AppRelease appRelease = AppReleaseManager.storeAppReleaseAndReturnDiff(currentAppRelease); - if (appRelease != null) { - ApptentiveLog.d("App release was updated."); - taskManager.addPayload(appRelease); - } + AppReleaseManager.storeAppRelease(currentAppRelease); + taskManager.addPayload(currentAppRelease); invalidateCaches(); } diff --git a/apptentive/src/main/java/com/apptentive/android/sdk/storage/AppReleaseManager.java b/apptentive/src/main/java/com/apptentive/android/sdk/storage/AppReleaseManager.java index 215a2eaa8..272678752 100644 --- a/apptentive/src/main/java/com/apptentive/android/sdk/storage/AppReleaseManager.java +++ b/apptentive/src/main/java/com/apptentive/android/sdk/storage/AppReleaseManager.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2014, Apptentive, Inc. All Rights Reserved. + * Copyright (c) 2016, Apptentive, Inc. All Rights Reserved. * Please refer to the LICENSE file for the terms and conditions * under which redistribution and use of this file is permitted. */ @@ -9,42 +9,12 @@ import android.content.SharedPreferences; import com.apptentive.android.sdk.ApptentiveInternal; -import com.apptentive.android.sdk.ApptentiveLog; import com.apptentive.android.sdk.model.AppRelease; import com.apptentive.android.sdk.util.Constants; -import com.apptentive.android.sdk.util.JsonDiffer; - -import org.json.JSONException; public class AppReleaseManager { - public static AppRelease storeAppReleaseAndReturnDiff(AppRelease currentAppRelease) { - AppRelease stored = getStoredAppRelease(); - - Object diff = JsonDiffer.getDiff(stored, currentAppRelease); - if (diff != null) { - try { - storeAppRelease(currentAppRelease); - return new AppRelease(diff.toString()); - } catch (JSONException e) { - ApptentiveLog.e("Error casting to AppRelease.", e); - } - } - return null; - } - - public static AppRelease getStoredAppRelease() { - SharedPreferences prefs = ApptentiveInternal.getInstance().getSharedPrefs(); - String appReleaseString = prefs.getString(Constants.PREF_KEY_APP_RELEASE, null); - try { - return new AppRelease(appReleaseString); - } catch (Exception e) { - // Ignore - } - return null; - } - - private static void storeAppRelease(AppRelease appRelease) { + public static void storeAppRelease(AppRelease appRelease) { SharedPreferences prefs = ApptentiveInternal.getInstance().getSharedPrefs(); prefs.edit().putString(Constants.PREF_KEY_APP_RELEASE, appRelease.toString()).apply(); } From 08ab27d170c6b7b3b6f49b10bf36c787b45da2d4 Mon Sep 17 00:00:00 2001 From: skykelsey Date: Mon, 3 Oct 2016 15:27:00 -0700 Subject: [PATCH 005/100] Only send SDK object when sdk info changes. Don't bother with sending diffs either. --- .../android/sdk/ApptentiveInternal.java | 16 +++---- .../android/sdk/storage/SdkManager.java | 47 +++---------------- .../engagement/DataObjectQueryTest.java | 4 +- 3 files changed, 15 insertions(+), 52 deletions(-) diff --git a/apptentive/src/main/java/com/apptentive/android/sdk/ApptentiveInternal.java b/apptentive/src/main/java/com/apptentive/android/sdk/ApptentiveInternal.java index b634d7227..c4fca70b7 100644 --- a/apptentive/src/main/java/com/apptentive/android/sdk/ApptentiveInternal.java +++ b/apptentive/src/main/java/com/apptentive/android/sdk/ApptentiveInternal.java @@ -449,7 +449,6 @@ public void onActivityStarted(Activity activity) { checkAndUpdateApptentiveConfigurations(); syncDevice(); - syncSdk(); syncPerson(); } @@ -675,6 +674,7 @@ private void onVersionChanged(Integer previousVersionCode, Integer currentVersio private void onSdkVersionChanged(Context context, String previousSdkVersion, String currentSdkVersion) { ApptentiveLog.i("SDK version changed: %s => %s", previousSdkVersion, currentSdkVersion); context.getSharedPreferences(Constants.PREF_NAME, Context.MODE_PRIVATE).edit().putString(Constants.PREF_KEY_LAST_SEEN_SDK_VERSION, currentSdkVersion).apply(); + syncSdk(); invalidateCaches(); } @@ -861,17 +861,13 @@ void syncDevice() { } /** - * Sends current Sdk to the server if it differs from the last time it was sent. + * Sends current SDK to the server. */ private void syncSdk() { - Sdk sdk = SdkManager.storeSdkAndReturnDiff(); - if (sdk != null) { - ApptentiveLog.d("Sdk was updated."); - ApptentiveLog.v(sdk.toString()); - taskManager.addPayload(sdk); - } else { - ApptentiveLog.d("Sdk was not updated."); - } + Sdk sdk = SdkManager.generateCurrentSdk(); + SdkManager.storeSdk(sdk); + ApptentiveLog.v(sdk.toString()); + taskManager.addPayload(sdk); } /** diff --git a/apptentive/src/main/java/com/apptentive/android/sdk/storage/SdkManager.java b/apptentive/src/main/java/com/apptentive/android/sdk/storage/SdkManager.java index 97b148f55..b8e7e5ee5 100644 --- a/apptentive/src/main/java/com/apptentive/android/sdk/storage/SdkManager.java +++ b/apptentive/src/main/java/com/apptentive/android/sdk/storage/SdkManager.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2014, Apptentive, Inc. All Rights Reserved. + * Copyright (c) 2016, Apptentive, Inc. All Rights Reserved. * Please refer to the LICENSE file for the terms and conditions * under which redistribution and use of this file is permitted. */ @@ -9,73 +9,38 @@ import android.content.SharedPreferences; import com.apptentive.android.sdk.ApptentiveInternal; -import com.apptentive.android.sdk.ApptentiveLog; import com.apptentive.android.sdk.model.Sdk; import com.apptentive.android.sdk.util.Constants; -import com.apptentive.android.sdk.util.JsonDiffer; import com.apptentive.android.sdk.util.Util; -import org.json.JSONException; -/** - * @author Sky Kelsey - */ public class SdkManager { - public static Sdk storeSdkAndReturnDiff() { - Sdk stored = getStoredSdk(); - Sdk current = generateCurrentSdk(); - - Object diff = JsonDiffer.getDiff(stored, current); - if(diff != null) { - try { - storeSdk(current); - return new Sdk(diff.toString()); - } catch (JSONException e) { - ApptentiveLog.e("Error casting to Sdk.", e); - } - } - return null; - } - public static Sdk storeSdkAndReturnIt() { Sdk current = generateCurrentSdk(); storeSdk(current); return current; } - private static Sdk generateCurrentSdk() { + public static Sdk generateCurrentSdk() { Sdk sdk = new Sdk(); // First, get all the information we can load from static resources. sdk.setVersion(Constants.APPTENTIVE_SDK_VERSION); sdk.setPlatform("Android"); - - // Distribution and distribution version are optionally set in the manifest by the wrapping platform (trigger, etc.) + // Distribution and distribution version are optionally set in the manifest by the wrapping platform (Cordova, mParticle, etc.) Object distribution = Util.getPackageMetaDataSingleQuotedString(ApptentiveInternal.getInstance().getApplicationContext(), Constants.MANIFEST_KEY_SDK_DISTRIBUTION); - if(distribution != null && distribution.toString().length() != 0) { + if (distribution != null && distribution.toString().length() != 0) { sdk.setDistribution(distribution.toString()); } Object distributionVersion = Util.getPackageMetaDataSingleQuotedString(ApptentiveInternal.getInstance().getApplicationContext(), Constants.MANIFEST_KEY_SDK_DISTRIBUTION_VERSION); - if(distributionVersion != null && distributionVersion.toString().length() != 0) { + if (distributionVersion != null && distributionVersion.toString().length() != 0) { sdk.setDistributionVersion(distributionVersion.toString()); } - return sdk; } - public static Sdk getStoredSdk() { - SharedPreferences prefs = ApptentiveInternal.getInstance().getSharedPrefs(); - String sdkString = prefs.getString(Constants.PREF_KEY_SDK, null); - try { - return new Sdk(sdkString); - } catch (Exception e) { - // Ignore - } - return null; - } - - private static void storeSdk(Sdk sdk) { + public static void storeSdk(Sdk sdk) { SharedPreferences prefs = ApptentiveInternal.getInstance().getSharedPrefs(); prefs.edit().putString(Constants.PREF_KEY_SDK, sdk.toString()).apply(); } diff --git a/tests/test-app/src/androidTest/java/com/apptentive/android/sdk/tests/module/engagement/DataObjectQueryTest.java b/tests/test-app/src/androidTest/java/com/apptentive/android/sdk/tests/module/engagement/DataObjectQueryTest.java index dbf522ba6..86b0b7d23 100644 --- a/tests/test-app/src/androidTest/java/com/apptentive/android/sdk/tests/module/engagement/DataObjectQueryTest.java +++ b/tests/test-app/src/androidTest/java/com/apptentive/android/sdk/tests/module/engagement/DataObjectQueryTest.java @@ -10,6 +10,7 @@ import com.apptentive.android.sdk.Apptentive; import com.apptentive.android.sdk.ApptentiveInternal; +import com.apptentive.android.sdk.model.Sdk; import com.apptentive.android.sdk.tests.ApptentiveInstrumentationTestCase; import com.apptentive.android.sdk.tests.util.FileUtil; import com.apptentive.android.sdk.ApptentiveLog; @@ -114,7 +115,8 @@ public void testQueriesAgainstSdk() { Interaction interaction; - SdkManager.storeSdkAndReturnDiff(); + Sdk sdk = SdkManager.generateCurrentSdk(); + SdkManager.storeSdk(sdk); // 0 interaction = ApptentiveInternal.getInstance().getInteractionManager().getApplicableInteraction("local#app#init"); From 6c0fe692e373e489752d01a94012d71ae08408ce Mon Sep 17 00:00:00 2001 From: skykelsey Date: Fri, 21 Oct 2016 15:02:59 -0700 Subject: [PATCH 006/100] Add release date to changelog --- CHANGELOG.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 951c12a5d..e35a756c5 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,4 +1,4 @@ -# 2016-10-?? - 3.3.0 +# 2016-10-21 - 3.3.0 #### Improvements From 746046248009e0bc538f69811291b313f39f0228 Mon Sep 17 00:00:00 2001 From: skykelsey Date: Sat, 29 Oct 2016 15:54:06 -0700 Subject: [PATCH 007/100] Begin refactor of Message Center to remove its ListView and replace if with a RecyclerView. --- .../fragment/MessageCenterFragment.java | 317 ++++++++++-------- .../model/MessageCenterInteraction.java | 26 ++ .../module/messagecenter/model/Composer.java | 31 ++ .../messagecenter/model/CompoundMessage.java | 11 + .../model/MessageCenterComposingItem.java | 7 + .../model/MessageCenterGreeting.java | 5 +- .../model/MessageCenterStatus.java | 5 +- .../model/MessageCenterUtil.java | 10 + .../module/messagecenter/model/WhoCard.java | 91 +++++ .../messagecenter/view/MessageAdapter.java | 56 +--- .../view/MessageCenterComposingView.java | 8 +- .../view/MessageCenterRecyclerView.java | 48 +++ .../MessageCenterRecyclerViewAdapter.java | 268 +++++++++++++++ .../view/holder/AutomatedMessageHolder.java | 26 +- .../view/holder/GreetingHolder.java | 50 +++ .../view/holder/HolderFactory.java | 34 -- .../holder/IncomingCompoundMessageHolder.java | 90 ++--- .../view/holder/MessageComposerHolder.java | 214 ++++++++++++ .../view/holder/MessageHolder.java | 43 +-- .../holder/OutgoingCompoundMessageHolder.java | 122 ++++--- .../view/holder/StatusHolder.java | 47 +-- .../view/holder/WhoCardHolder.java | 110 ++++++ .../sdk/view/ApptentiveAlertDialog.java | 1 + .../res/layout/apptentive_message_center.xml | 34 +- .../apptentive_message_center_composer.xml | 96 ++++++ .../layout/apptentive_message_incoming.xml | 1 + .../layout/apptentive_message_outgoing.xml | 1 + 27 files changed, 1336 insertions(+), 416 deletions(-) create mode 100644 apptentive/src/main/java/com/apptentive/android/sdk/module/messagecenter/model/Composer.java create mode 100644 apptentive/src/main/java/com/apptentive/android/sdk/module/messagecenter/model/WhoCard.java create mode 100644 apptentive/src/main/java/com/apptentive/android/sdk/module/messagecenter/view/MessageCenterRecyclerView.java create mode 100644 apptentive/src/main/java/com/apptentive/android/sdk/module/messagecenter/view/MessageCenterRecyclerViewAdapter.java create mode 100644 apptentive/src/main/java/com/apptentive/android/sdk/module/messagecenter/view/holder/GreetingHolder.java delete mode 100644 apptentive/src/main/java/com/apptentive/android/sdk/module/messagecenter/view/holder/HolderFactory.java create mode 100644 apptentive/src/main/java/com/apptentive/android/sdk/module/messagecenter/view/holder/MessageComposerHolder.java create mode 100644 apptentive/src/main/java/com/apptentive/android/sdk/module/messagecenter/view/holder/WhoCardHolder.java create mode 100644 apptentive/src/main/res/layout/apptentive_message_center_composer.xml diff --git a/apptentive/src/main/java/com/apptentive/android/sdk/module/engagement/interaction/fragment/MessageCenterFragment.java b/apptentive/src/main/java/com/apptentive/android/sdk/module/engagement/interaction/fragment/MessageCenterFragment.java index 6b8c20d89..fa293e89b 100644 --- a/apptentive/src/main/java/com/apptentive/android/sdk/module/engagement/interaction/fragment/MessageCenterFragment.java +++ b/apptentive/src/main/java/com/apptentive/android/sdk/module/engagement/interaction/fragment/MessageCenterFragment.java @@ -26,6 +26,7 @@ import android.support.v4.app.Fragment; import android.support.v4.app.FragmentTransaction; import android.support.v4.view.ViewCompat; +import android.support.v7.widget.LinearLayoutManager; import android.text.Editable; import android.text.Layout; import android.text.TextUtils; @@ -38,7 +39,6 @@ import android.view.WindowManager; import android.widget.AbsListView; import android.widget.EditText; -import android.widget.ListView; import com.apptentive.android.sdk.Apptentive; import com.apptentive.android.sdk.ApptentiveInternal; @@ -50,14 +50,18 @@ import com.apptentive.android.sdk.module.engagement.interaction.model.MessageCenterInteraction; import com.apptentive.android.sdk.module.messagecenter.MessageManager; import com.apptentive.android.sdk.module.messagecenter.model.ApptentiveMessage; +import com.apptentive.android.sdk.module.messagecenter.model.Composer; import com.apptentive.android.sdk.module.messagecenter.model.CompoundMessage; import com.apptentive.android.sdk.module.messagecenter.model.MessageCenterComposingItem; import com.apptentive.android.sdk.module.messagecenter.model.MessageCenterStatus; import com.apptentive.android.sdk.module.messagecenter.model.MessageCenterUtil; +import com.apptentive.android.sdk.module.messagecenter.model.WhoCard; import com.apptentive.android.sdk.module.messagecenter.view.AttachmentPreviewDialog; import com.apptentive.android.sdk.module.messagecenter.view.MessageAdapter; import com.apptentive.android.sdk.module.messagecenter.view.MessageCenterComposingActionBarView; import com.apptentive.android.sdk.module.messagecenter.view.MessageCenterListView; +import com.apptentive.android.sdk.module.messagecenter.view.MessageCenterRecyclerView; +import com.apptentive.android.sdk.module.messagecenter.view.MessageCenterRecyclerViewAdapter; import com.apptentive.android.sdk.module.metric.MetricModule; import com.apptentive.android.sdk.util.AnimationUtil; import com.apptentive.android.sdk.util.Constants; @@ -115,14 +119,14 @@ public class MessageCenterFragment extends ApptentiveBaseFragment hostingActivityRef; - private ListView messageCenterListView; // List of apptentive messages + private MessageCenterRecyclerView messageCenterRecyclerView; private EditText messageEditText; // Composing area private View fab; // Data backing of the listview private ArrayList messages = new ArrayList(); - private MessageAdapter messageCenterListAdapter; + private MessageCenterRecyclerViewAdapter messageCenterRecyclerViewAdapter; // MesssageCenterView is set to paused when it fails to send message private boolean isPaused = false; @@ -131,9 +135,9 @@ public class MessageCenterFragment extends ApptentiveBaseFragment imageAttachmentstList = new ArrayList(); @@ -260,9 +264,9 @@ public void onAttach(Context context) { @Override public void onDetach() { super.onDetach(); - // messageCenterListAdapter holds a reference to fragment context through Cstor. Need to set it to null to prevent leak - messageCenterListAdapter = null; - messageCenterListView.setAdapter(null); + // messageCenterRecyclerViewAdapter holds a reference to fragment context through Cstor. Need to set it to null to prevent leak + messageCenterRecyclerViewAdapter = null; + messageCenterRecyclerView.setAdapter(null); } public void onStart() { @@ -371,14 +375,18 @@ protected void updateMenuVisibility() { } private void setup(View rootView, boolean isInitMessages) { - messageCenterListView = (ListView) rootView.findViewById(R.id.message_list); - messageCenterListView.setTranscriptMode(ListView.TRANSCRIPT_MODE_NORMAL); - messageCenterListView.setOnScrollListener(this); + messageCenterRecyclerView = (MessageCenterRecyclerView) rootView.findViewById(R.id.message_center_recycler_view); if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { - messageCenterListView.setNestedScrollingEnabled(true); + messageCenterRecyclerView.setNestedScrollingEnabled(true); } + LinearLayoutManager layoutManager = new LinearLayoutManager(this.getContext()); + layoutManager.setOrientation(LinearLayoutManager.VERTICAL); + messageCenterRecyclerView.setLayoutManager(layoutManager); + + /* ((MessageCenterListView) messageCenterListView).setOnListViewResizeListener(this); messageCenterListView.setItemsCanFocus(true); +*/ fab = rootView.findViewById(R.id.composing_fab); @@ -422,8 +430,10 @@ else if (pendingWhoCardName != null || pendingWhoCardEmail != null || pendingWho } - messageCenterListAdapter = new MessageAdapter(this, messages, interaction); + messageCenterRecyclerViewAdapter = new MessageCenterRecyclerViewAdapter(this, interaction, messages); + messageCenterRecyclerView.setAdapter(messageCenterRecyclerViewAdapter); +/* if (whoCardItem != null) { showKeyboard = true; } else if (composingItem != null) { @@ -432,9 +442,7 @@ else if (pendingWhoCardName != null || pendingWhoCardEmail != null || pendingWho showKeyboard = false; } } - - messageCenterListAdapter.setForceShowKeyboard(showKeyboard); - messageCenterListView.setAdapter(messageCenterListAdapter); +*/ // Calculate FAB y-offset fabPaddingPixels = calculateFabPadding(rootView.getContext()); @@ -446,7 +454,7 @@ public boolean onMenuItemClick(MenuItem menuItem) { if (menuItemId == R.id.profile) { // Only allow profile editing when not already editing profile or in message composing - if (whoCardItem == null && composingItem == null) { + if (whoCardItem == null && composer == null) { final SharedPreferences prefs = ApptentiveInternal.getInstance().getSharedPrefs(); boolean bWhoCardSet = prefs.getBoolean(Constants.PREF_KEY_MESSAGE_CENTER_WHO_CARD_SET, false); @@ -468,16 +476,16 @@ public boolean onMenuItemClick(MenuItem menuItem) { @Override public void onSaveInstanceState(Bundle outState) { - int index = messageCenterListView.getFirstVisiblePosition(); - View v = messageCenterListView.getChildAt(0); - int top = (v == null) ? 0 : (v.getTop() - messageCenterListView.getPaddingTop()); - outState.putInt(LIST_TOP_INDEX, index); + //int index = messageCenterRecyclerView.getFirstVisiblePosition(); + View v = messageCenterRecyclerView.getChildAt(0); + int top = (v == null) ? 0 : (v.getTop() - messageCenterRecyclerView.getPaddingTop()); + //outState.putInt(LIST_TOP_INDEX, index); outState.putInt(LIST_TOP_OFFSET, top); outState.putParcelable(COMPOSING_EDITTEXT_STATE, saveEditTextInstanceState()); - if (messageCenterListAdapter != null) { - outState.putParcelable(WHO_CARD_NAME, messageCenterListAdapter.getWhoCardNameState()); - outState.putParcelable(WHO_CARD_EMAIL, messageCenterListAdapter.getWhoCardEmailState()); - outState.putString(WHO_CARD_AVATAR_FILE, messageCenterListAdapter.getWhoCardAvatarFileName()); + if (messageCenterRecyclerViewAdapter != null) { + outState.putParcelable(WHO_CARD_NAME, messageCenterRecyclerViewAdapter.getWhoCardNameState()); + outState.putParcelable(WHO_CARD_EMAIL, messageCenterRecyclerViewAdapter.getWhoCardEmailState()); + outState.putString(WHO_CARD_AVATAR_FILE, messageCenterRecyclerViewAdapter.getWhoCardAvatarFileName()); } outState.putInt(WHO_CARD_MODE, pendingWhoCardMode); if (contextualMessage == null) { @@ -567,10 +575,8 @@ public void addComposingCard() { public void addComposerMessageItems() { clearStatusItem(); - actionBarItem = interaction.getComposerBar(); - messages.add(actionBarItem); - composingItem = interaction.getComposerArea(); - messages.add(composingItem); + composer = interaction.getComposer(); + messages.add(composer); } private boolean checkAddWhoCardIfRequired() { @@ -603,9 +609,16 @@ public void addWhoCard(int mode) { public void addWhoCardAsMessageItem(int mode) { pendingWhoCardMode = mode; clearStatusItem(); - whoCardItem = (mode == WHO_CARD_MODE_INIT) ? interaction.getWhoCardInit() - : interaction.getWhoCardEdit(); - messages.add(whoCardItem); + JSONObject profile = interaction.getProfile(); + if (profile != null) { + try { + ApptentiveLog.e("Adding Who Card"); + whoCardItem = new WhoCard(profile.toString()); + messages.add(whoCardItem); + } catch (JSONException e) { + ApptentiveLog.w("Unable to instantiate Who Card"); + } + } } private boolean addExpectationStatusIfNeeded() { @@ -626,7 +639,7 @@ private boolean addExpectationStatusIfNeeded() { Double createdTime = apptentiveMessage.getCreatedAt(); if (createdTime != null && createdTime > Double.MIN_VALUE) { MessageCenterStatus newItem = interaction.getRegularStatus(); - if (newItem != null && whoCardItem == null && composingItem == null) { + if (newItem != null && whoCardItem == null && composer == null) { // Add expectation status message if the last is a sent clearStatusItem(); statusItem = newItem; @@ -641,7 +654,7 @@ private boolean addExpectationStatusIfNeeded() { public void addNewStatusItem(MessageCenterUtil.MessageCenterListItem item) { clearStatusItem(); - if (composingItem != null) { + if (composer != null) { return; } @@ -658,8 +671,8 @@ public void addNewOutGoingMessageItem(ApptentiveMessage message) { unsendMessagesCount++; isPaused = false; - if (messageCenterListAdapter != null) { - messageCenterListAdapter.setPaused(isPaused); + if (messageCenterRecyclerViewAdapter != null) { + messageCenterRecyclerViewAdapter.setPaused(isPaused); } } @@ -669,7 +682,7 @@ public void displayNewIncomingMessageItem(ApptentiveMessage message) { // Determine where to insert the new incoming message. It will be in front of any eidting // area, i.e. composing, Who Card ... int insertIndex = messages.size(); - if (composingItem != null) { + if (composer != null) { // when in composing mode, there are composing action bar and composing area insertIndex -= 2; if (contextualMessage != null) { @@ -683,23 +696,23 @@ public void displayNewIncomingMessageItem(ApptentiveMessage message) { } messages.add(insertIndex, message); - int firstIndex = messageCenterListView.getFirstVisiblePosition(); - int lastIndex = messageCenterListView.getLastVisiblePosition(); + int firstIndex = messageCenterRecyclerView.getFirstVisiblePosition(); + int lastIndex = messageCenterRecyclerView.getLastVisiblePosition(); boolean composingAreaTakesUpVisibleArea = firstIndex <= insertIndex && insertIndex < lastIndex; if (composingAreaTakesUpVisibleArea) { - View v = messageCenterListView.getChildAt(0); + View v = messageCenterRecyclerView.getChildAt(0); int top = (v == null) ? 0 : v.getTop(); updateMessageSentStates(); - if (messageCenterListAdapter != null) { - messageCenterListAdapter.notifyDataSetChanged(); + if (messageCenterRecyclerViewAdapter != null) { + messageCenterRecyclerViewAdapter.notifyDataSetChanged(); } // Restore the position of listview to composing view messagingActionHandler.sendMessage(messagingActionHandler.obtainMessage(MSG_SCROLL_FROM_TOP, insertIndex, top)); } else { updateMessageSentStates(); - if (messageCenterListAdapter != null) { - messageCenterListAdapter.notifyDataSetChanged(); + if (messageCenterRecyclerViewAdapter != null) { + messageCenterRecyclerViewAdapter.notifyDataSetChanged(); } } @@ -710,8 +723,8 @@ private void clearStatusItem() { if (statusItem != null) { messages.remove(statusItem); statusItem = null; - if (messageCenterListAdapter != null) { - messageCenterListAdapter.notifyDataSetChanged(); + if (messageCenterRecyclerViewAdapter != null) { + messageCenterRecyclerViewAdapter.notifyDataSetChanged(); } } } @@ -746,16 +759,16 @@ public void addAttachmentsToComposer(final List images) { } EngagementModule.engageInternal(hostingActivityRef.get(), interaction, MessageCenterInteraction.EVENT_NAME_ATTACHMENT_ADD); - View v = messageCenterListView.getChildAt(0); + View v = messageCenterRecyclerView.getChildAt(0); int top = (v == null) ? 0 : v.getTop(); - if (messageCenterListAdapter != null) { + if (messageCenterRecyclerViewAdapter != null) { // Only update composing view if image is attached successfully - messageCenterListAdapter.addImagestoComposer(uniqueImages); - messageCenterListAdapter.notifyDataSetChanged(); - messageCenterListAdapter.setForceShowKeyboard(false); + messageCenterRecyclerViewAdapter.addImagestoComposer(uniqueImages); + messageCenterRecyclerViewAdapter.notifyDataSetChanged(); + messageCenterRecyclerViewAdapter.setForceShowKeyboard(false); } - int firstIndex = messageCenterListView.getFirstVisiblePosition(); + int firstIndex = messageCenterRecyclerView.getFirstVisiblePosition(); messagingActionHandler.sendMessage(messagingActionHandler.obtainMessage(MSG_SCROLL_FROM_TOP, firstIndex, top)); @@ -765,16 +778,16 @@ public void addAttachmentsToComposer(final List images) { public void restoreSavedAttachmentsToComposer(final List images) { imageAttachmentstList.clear(); imageAttachmentstList.addAll(images); - View v = messageCenterListView.getChildAt(0); + View v = messageCenterRecyclerView.getChildAt(0); int top = (v == null) ? 0 : v.getTop(); // Only update composing view if image is attached successfully - if (messageCenterListAdapter != null) { - messageCenterListAdapter.addImagestoComposer(images); - messageCenterListAdapter.setForceShowKeyboard(false); + if (messageCenterRecyclerViewAdapter != null) { + messageCenterRecyclerViewAdapter.addImagestoComposer(images); + messageCenterRecyclerViewAdapter.setForceShowKeyboard(false); } - int firstIndex = messageCenterListView.getFirstVisiblePosition(); - if (messageCenterListAdapter != null) { - messageCenterListAdapter.notifyDataSetChanged(); + int firstIndex = messageCenterRecyclerView.getFirstVisiblePosition(); + if (messageCenterRecyclerViewAdapter != null) { + messageCenterRecyclerViewAdapter.notifyDataSetChanged(); } messagingActionHandler.sendMessage(messagingActionHandler.obtainMessage(MSG_SCROLL_FROM_TOP, firstIndex, top)); @@ -784,12 +797,12 @@ public void restoreSavedAttachmentsToComposer(final List images) { public void removeImageFromComposer(final int position) { EngagementModule.engageInternal(hostingActivityRef.get(), interaction, MessageCenterInteraction.EVENT_NAME_ATTACHMENT_DELETE); imageAttachmentstList.remove(position); - if (messageCenterListAdapter != null) { - messageCenterListAdapter.removeImageFromComposer(position); + if (messageCenterRecyclerViewAdapter != null) { + messageCenterRecyclerViewAdapter.removeImageFromComposer(position); int count = imageAttachmentstList.size(); // Show keyboard if all attachments have been removed - messageCenterListAdapter.setForceShowKeyboard(count == 0); - messageCenterListAdapter.notifyDataSetChanged(); + messageCenterRecyclerViewAdapter.setForceShowKeyboard(count == 0); + messageCenterRecyclerViewAdapter.notifyDataSetChanged(); } messagingActionHandler.sendEmptyMessageDelayed(MSG_SCROLL_TO_BOTTOM, DEFAULT_DELAYMILLIS); @@ -857,47 +870,57 @@ public synchronized void onResumeSending() { public void clearWhoCardUi(Animator.AnimatorListener al, ValueAnimator.AnimatorUpdateListener vl, long delay) { - if (whoCardItem != null && messageCenterListAdapter != null) { + if (whoCardItem != null && messageCenterRecyclerViewAdapter != null) { if (al != null) { - deleteItemWithAnimation(messageCenterListAdapter.getWhoCardView(), al, vl, delay); + deleteItemWithAnimation(messageCenterRecyclerViewAdapter.getWhoCardView(), al, vl, delay); } else { whoCardItem = null; pendingWhoCardName = null; pendingWhoCardEmail = null; pendingWhoCardAvatarFile = null; pendingWhoCardMode = 0; - messageCenterListAdapter.clearWhoCard(); + messageCenterRecyclerViewAdapter.clearWhoCard(); } } } - public void clearComposingUi(Animator.AnimatorListener al, - ValueAnimator.AnimatorUpdateListener vl, long delay) { - if (composingItem != null && messageCenterListAdapter != null) { - if (al != null) { - deleteItemWithAnimation(messageCenterListAdapter.getComposingActionBarView(), null, null, delay); - deleteItemWithAnimation(messageCenterListAdapter.getComposingAreaView(), al, vl, delay); - } else { - if (contextualMessage != null) { - messages.remove(contextualMessage); - contextualMessage = null; + public void clearComposingUi(Animator.AnimatorListener al, ValueAnimator.AnimatorUpdateListener vl, long delay) { + if (composer != null && messageCenterRecyclerViewAdapter != null) { + int contextMessageIndex = -1; + for (int i = 0; i < messages.size(); i++) { + MessageCenterUtil.MessageCenterListItem message = messages.get(i); + if (message.getListItemType() == MessageCenterUtil.MessageCenterListItem.MESSAGE_CONTEXT) { + contextMessageIndex = i; + break; + } + } + if (contextMessageIndex != -1) { + ApptentiveLog.e("Removing Context Message"); + messages.remove(contextMessageIndex); + messageCenterRecyclerViewAdapter.notifyItemRemoved(contextMessageIndex); + } + + int composerIndex = -1; + for (int i = 0; i < messages.size(); i++) { + MessageCenterUtil.MessageCenterListItem message = messages.get(i); + if (message.getListItemType() == MessageCenterUtil.MessageCenterListItem.MESSAGE_COMPOSER) { + composerIndex = i; + break; } - messages.remove(actionBarItem); - messages.remove(composingItem); - actionBarItem = null; - composingItem = null; - messageEditText = null; - messageCenterListAdapter.clearComposing(); - messageCenterListAdapter.notifyDataSetChanged(); - showFab(); } + if (composerIndex != -1) { + ApptentiveLog.e("Removing Composer"); + messages.remove(composerIndex); + messageCenterRecyclerViewAdapter.notifyItemRemoved(composerIndex); + } + showFab(); } } - @Override +// @Override public void updateComposingBar() { - if (messageCenterListAdapter != null) { - MessageCenterComposingActionBarView barView = messageCenterListAdapter.getComposingActionBarView(); + if (messageCenterRecyclerViewAdapter != null) { + MessageCenterComposingActionBarView barView = messageCenterRecyclerViewAdapter.getComposingActionBarView(); if (barView != null) { barView.showConfirmation = true; int attachmentCount = imageAttachmentstList.size(); @@ -930,15 +953,15 @@ public void updateComposingBar() { } } - @Override +// @Override public void onComposingViewCreated(View keyboardFocusedOnView) { hideProfileButton(); hideFab(); EngagementModule.engageInternal(hostingActivityRef.get(), interaction, MessageCenterInteraction.EVENT_NAME_COMPOSE_OPEN); - if (messageCenterListAdapter != null) { - messageEditText = messageCenterListAdapter.getEditTextInComposing(); + if (messageCenterRecyclerViewAdapter != null) { + messageEditText = messageCenterRecyclerViewAdapter.getEditTextInComposing(); } else { messageEditText = null; } @@ -996,14 +1019,14 @@ public void onComposingViewCreated(View keyboardFocusedOnView) { restoreSavedAttachmentsToComposer(savedAttachmentstList); savedAttachmentstList = null; } - messageCenterListView.setPadding(0, 0, 0, 0); + messageCenterRecyclerView.setPadding(0, 0, 0, 0); if (keyboardFocusedOnView != null) { Util.showSoftKeyboard(hostingActivityRef.get(), keyboardFocusedOnView); } } - @Override +// @Override public void onWhoCardViewCreated(EditText nameEditText, EditText emailEditText, View viewFocusedWithKeyboard) { if (pendingWhoCardName != null) { nameEditText.onRestoreInstanceState(pendingWhoCardName); @@ -1013,32 +1036,32 @@ public void onWhoCardViewCreated(EditText nameEditText, EditText emailEditText, emailEditText.onRestoreInstanceState(pendingWhoCardEmail); pendingWhoCardEmail = null; } - messageCenterListView.setPadding(0, 0, 0, 0); + messageCenterRecyclerView.setPadding(0, 0, 0, 0); if (viewFocusedWithKeyboard != null) { Util.showSoftKeyboard(hostingActivityRef.get(), viewFocusedWithKeyboard); } } - @Override +// @Override public void beforeComposingTextChanged(CharSequence str) { } - @Override +// @Override public void onComposingTextChanged(CharSequence str) { } - @Override +// @Override public void afterComposingTextChanged(String str) { // Update display status of composing bar buttons when composing text changes updateComposingBar(); } - @Override +// @Override public void onCancelComposing() { - if (messageCenterListAdapter != null) { - messageCenterListAdapter.setForceShowKeyboard(false); + if (messageCenterRecyclerViewAdapter != null) { + messageCenterRecyclerViewAdapter.setForceShowKeyboard(false); } Util.hideSoftKeyboard(hostingActivityRef.get(), getView()); @@ -1068,15 +1091,13 @@ public void onAnimationEnd(Animator animation) { messages.remove(contextualMessage); contextualMessage = null; } - messages.remove(actionBarItem); - messages.remove(composingItem); - actionBarItem = null; - composingItem = null; + messages.remove(composer); + composer = null; messageEditText = null; - if (messageCenterListAdapter != null) { - messageCenterListAdapter.clearComposing(); + if (messageCenterRecyclerViewAdapter != null) { + messageCenterRecyclerViewAdapter.clearComposing(); addExpectationStatusIfNeeded(); - messageCenterListAdapter.notifyDataSetChanged(); + messageCenterRecyclerViewAdapter.notifyDataSetChanged(); } imageAttachmentstList.clear(); showFab(); @@ -1094,10 +1115,10 @@ public void onAnimationCancel(Animator animation) { //clearComposingUi(null, null, 0); } - @Override +// @Override public void onFinishComposing() { - if (messageCenterListAdapter != null) { - messageCenterListAdapter.setForceShowKeyboard(false); + if (messageCenterRecyclerViewAdapter != null) { + messageCenterRecyclerViewAdapter.setForceShowKeyboard(false); } Util.hideSoftKeyboard(hostingActivityRef.get(), getView()); if (contextualMessage != null) { @@ -1122,14 +1143,12 @@ public void onAnimationRepeat(Animator animation) { @Override public void onAnimationEnd(Animator animation) { - messages.remove(actionBarItem); - messages.remove(composingItem); - actionBarItem = null; - composingItem = null; + messages.remove(composer); + composer = null; messageEditText = null; - if (messageCenterListAdapter != null) { - messageCenterListAdapter.clearComposing(); - messageCenterListAdapter.notifyDataSetChanged(); + if (messageCenterRecyclerViewAdapter != null) { + messageCenterRecyclerViewAdapter.clearComposing(); + messageCenterRecyclerViewAdapter.notifyDataSetChanged(); } clearPendingComposingMessage(); // Send out the new message. The delay is added to ensure the CardView showing animation @@ -1157,7 +1176,7 @@ public void onAnimationCancel(Animator animation) { DEFAULT_DELAYMILLIS); } - @Override +// @Override public void onSubmitWhoCard(String buttonLabel) { JSONObject data = new JSONObject(); try { @@ -1171,7 +1190,7 @@ public void onSubmitWhoCard(String buttonLabel) { cleanupWhoCard(); } - @Override +// @Override public void onCloseWhoCard(String buttonLabel) { JSONObject data = new JSONObject(); try { @@ -1186,8 +1205,8 @@ public void onCloseWhoCard(String buttonLabel) { } public void cleanupWhoCard() { - if (messageCenterListAdapter != null) { - messageCenterListAdapter.setForceShowKeyboard(false); + if (messageCenterRecyclerViewAdapter != null) { + messageCenterRecyclerViewAdapter.setForceShowKeyboard(false); } Util.hideSoftKeyboard(hostingActivityRef.get(), getView()); clearWhoCardUi( @@ -1209,10 +1228,10 @@ public void onAnimationEnd(Animator animation) { pendingWhoCardEmail = null; pendingWhoCardAvatarFile = null; pendingWhoCardMode = 0; - if (messageCenterListAdapter != null) { - messageCenterListAdapter.clearWhoCard(); + if (messageCenterRecyclerViewAdapter != null) { + messageCenterRecyclerViewAdapter.clearWhoCard(); addExpectationStatusIfNeeded(); - messageCenterListAdapter.notifyDataSetChanged(); + messageCenterRecyclerViewAdapter.notifyDataSetChanged(); } saveWhoCardSetState(); // If Who card is required, it might be displayed before proceeding to composing, for instance @@ -1266,11 +1285,11 @@ public void onScroll(AbsListView view, int firstVisibleItem, int visibleItemCoun public void OnListViewResize(int w, int h, int oldw, int oldh) { // detect keyboard launching. If height difference is more than 100 pixels, probably due to keyboard if (oldh > h && oldh - h > 100) { - if (composingItem != null) { + if (composer != null) { // When keyboard is up, adjust the scolling such that the cursor is always visible - final int firstIndex = messageCenterListView.getFirstVisiblePosition(); - int lastIndex = messageCenterListView.getLastVisiblePosition(); - View v = messageCenterListView.getChildAt(lastIndex - firstIndex); + final int firstIndex = messageCenterRecyclerView.getFirstVisiblePosition(); + int lastIndex = messageCenterRecyclerView.getLastVisiblePosition(); + View v = messageCenterRecyclerView.getChildAt(lastIndex - firstIndex); int top = (v == null) ? 0 : v.getTop(); if (messageEditText != null) { int pos = messageEditText.getSelectionStart(); @@ -1293,7 +1312,7 @@ public void OnListViewResize(int w, int h, int oldw, int oldh) { /* Callback when the attach button is clicked * */ - @Override +// @Override public void onAttachImage() { try { if (Build.VERSION.SDK_INT < Build.VERSION_CODES.KITKAT) {//prior Api level 19 @@ -1451,7 +1470,7 @@ private int calculateFabPadding(Context context) { } private void showFab() { - messageCenterListView.setPadding(0, 0, 0, fabPaddingPixels); + messageCenterRecyclerView.setPadding(0, 0, 0, fabPaddingPixels); // Re-enable Fab at the beginning of the animation fab.setEnabled(true); AnimationUtil.scaleFadeIn(fab); @@ -1522,7 +1541,7 @@ private void prepareMessages(final List messages.add(0, interaction.getGreeting()); } - @Override +// @Override public void onClickAttachment(final int position, final ImageItem image) { if (Util.isMimeTypeImage(image.mimeType)) { // "+" placeholder is clicked @@ -1579,26 +1598,26 @@ public MessagingActionHandler(MessageCenterFragment fragment) { public void handleMessage(Message msg) { MessageCenterFragment fragment = (MessageCenterFragment) messageCenterFragmentWeakReference.get(); /* Message can be delayed. If so, make sure fragment is still available and attached to activity - * messageCenterListAdapter will always be set null in onDetach(). it's a good indication if + * messageCenterRecyclerViewAdapter will always be set null in onDetach(). it's a good indication if * fragment is attached. */ - if (fragment == null || fragment.messageCenterListAdapter == null) { + if (fragment == null || fragment.messageCenterRecyclerViewAdapter == null) { return; } switch (msg.what) { case MSG_MESSAGE_ADD_WHOCARD: { // msg.arg1 is either WHO_CARD_MODE_INIT or WHO_CARD_MODE_EDIT fragment.addWhoCardAsMessageItem(msg.arg1); - fragment.messageCenterListAdapter.setForceShowKeyboard(true); - fragment.messageCenterListAdapter.notifyDataSetChanged(); - fragment.messageCenterListView.setSelection(fragment.messages.size() - 1); + fragment.messageCenterRecyclerViewAdapter.setForceShowKeyboard(true); + fragment.messageCenterRecyclerViewAdapter.notifyItemInserted(fragment.messages.size() - 1); + fragment.messageCenterRecyclerView.setSelection(fragment.messages.size() - 1); break; } case MSG_MESSAGE_ADD_COMPOSING: { fragment.addComposerMessageItems(); - fragment.messageCenterListAdapter.setForceShowKeyboard(true); - fragment.messageCenterListAdapter.notifyDataSetChanged(); - fragment.messageCenterListView.setSelection(fragment.messages.size() - 1); + fragment.messageCenterRecyclerViewAdapter.setForceShowKeyboard(true); + fragment.messageCenterRecyclerViewAdapter.notifyItemInserted(fragment.messages.size() - 1); + fragment.messageCenterRecyclerView.setSelection(fragment.messages.size() - 1); break; } case MSG_MESSAGE_ADD_INCOMING: { @@ -1607,13 +1626,13 @@ public void handleMessage(Message msg) { break; } case MSG_SCROLL_TO_BOTTOM: { - fragment.messageCenterListView.setSelection(fragment.messages.size() - 1); + fragment.messageCenterRecyclerView.setSelection(fragment.messages.size() - 1); break; } case MSG_SCROLL_FROM_TOP: { int index = msg.arg1; int top = msg.arg2; - fragment.messageCenterListView.setSelectionFromTop(index, top); + fragment.messageCenterRecyclerView.setSelectionFromTop(index, top); break; } case MSG_MESSAGE_SENT: { @@ -1637,11 +1656,11 @@ public void handleMessage(Message msg) { fragment.addExpectationStatusIfNeeded(); // Calculate the listview offset to make sure updating sent timestamp does not push the current view port - int firstIndex = fragment.messageCenterListView.getFirstVisiblePosition(); - View v = fragment.messageCenterListView.getChildAt(0); + int firstIndex = fragment.messageCenterRecyclerView.getFirstVisiblePosition(); + View v = fragment.messageCenterRecyclerView.getChildAt(0); int top = (v == null) ? 0 : v.getTop(); - fragment.messageCenterListAdapter.notifyDataSetChanged(); + fragment.messageCenterRecyclerViewAdapter.notifyDataSetChanged(); // If Who Card is being shown while a message is sent, make sure Who Card is still in view by scrolling to bottom if (fragment.whoCardItem != null) { sendEmptyMessageDelayed(MSG_SCROLL_TO_BOTTOM, DEFAULT_DELAYMILLIS); @@ -1664,7 +1683,7 @@ public void handleMessage(Message msg) { // Add new outgoing message with animation fragment.addNewOutGoingMessageItem(message); - fragment.messageCenterListAdapter.notifyDataSetChanged(); + fragment.messageCenterRecyclerViewAdapter.notifyDataSetChanged(); // After the message is sent, check if Who Card need to be shown for the 1st time(When Who Card is either requested or required) SharedPreferences prefs = ApptentiveInternal.getInstance().getSharedPrefs(); boolean bWhoCardSet = prefs.getBoolean(Constants.PREF_KEY_MESSAGE_CENTER_WHO_CARD_SET, false); @@ -1688,7 +1707,7 @@ public void handleMessage(Message msg) { if (!fragment.isPaused) { fragment.isPaused = true; if (fragment.unsendMessagesCount > 0) { - fragment.messageCenterListAdapter.setPaused(fragment.isPaused); + fragment.messageCenterRecyclerViewAdapter.setPaused(fragment.isPaused); int reason = msg.arg1; if (reason == MessageManager.SEND_PAUSE_REASON_NETWORK) { EngagementModule.engageInternal(fragment.hostingActivityRef.get(), fragment.interaction, MessageCenterInteraction.EVENT_NAME_MESSAGE_NETWORK_ERROR); @@ -1699,7 +1718,7 @@ public void handleMessage(Message msg) { MessageCenterStatus newItem = fragment.interaction.getErrorStatusServer(); fragment.addNewStatusItem(newItem); } - fragment.messageCenterListAdapter.notifyDataSetChanged(); + fragment.messageCenterRecyclerViewAdapter.notifyDataSetChanged(); } } break; @@ -1711,8 +1730,8 @@ public void handleMessage(Message msg) { fragment.clearStatusItem(); } - fragment.messageCenterListAdapter.setPaused(fragment.isPaused); - fragment.messageCenterListAdapter.notifyDataSetChanged(); + fragment.messageCenterRecyclerViewAdapter.setPaused(fragment.isPaused); + fragment.messageCenterRecyclerViewAdapter.notifyDataSetChanged(); } break; } diff --git a/apptentive/src/main/java/com/apptentive/android/sdk/module/engagement/interaction/model/MessageCenterInteraction.java b/apptentive/src/main/java/com/apptentive/android/sdk/module/engagement/interaction/model/MessageCenterInteraction.java index fb2da4101..97d3ac432 100644 --- a/apptentive/src/main/java/com/apptentive/android/sdk/module/engagement/interaction/model/MessageCenterInteraction.java +++ b/apptentive/src/main/java/com/apptentive/android/sdk/module/engagement/interaction/model/MessageCenterInteraction.java @@ -11,9 +11,11 @@ import com.apptentive.android.sdk.ApptentiveViewActivity; import com.apptentive.android.sdk.R; +import com.apptentive.android.sdk.module.messagecenter.model.Composer; import com.apptentive.android.sdk.module.messagecenter.model.MessageCenterComposingItem; import com.apptentive.android.sdk.module.messagecenter.model.MessageCenterGreeting; import com.apptentive.android.sdk.module.messagecenter.model.MessageCenterStatus; +import com.apptentive.android.sdk.module.messagecenter.model.WhoCard; import com.apptentive.android.sdk.util.Constants; import org.json.JSONException; @@ -141,6 +143,22 @@ public MessageCenterComposingItem getComposerBar() { null); } + public Composer getComposer() { + InteractionConfiguration configuration = getConfiguration(); + if (configuration == null) { + return null; + } + JSONObject composer = configuration.optJSONObject(KEY_COMPOSER); + return new Composer( + composer.optString(KEY_COMPOSER_TITLE, null), + composer.optString(KEY_COMPOSER_CLOSE_BODY, null), + composer.optString(KEY_COMPOSER_CLOSE_DISCARD, null), + composer.optString(KEY_COMPOSER_CLOSE_CANCEL, null), + composer.optString(KEY_COMPOSER_SEND_BUTTON, null), + composer.optString(KEY_COMPOSER_HINT_TEXT, null) + ); + } + //When enabled, display Who Card to request profile info public boolean getWhoCardRequestEnabled() { InteractionConfiguration configuration = getConfiguration(); @@ -189,6 +207,14 @@ public MessageCenterComposingItem getWhoCardInit() { profileInitial.optString(KEY_PROFILE_INIT_SAVE_BUTTON, null)); } + public JSONObject getProfile() { + InteractionConfiguration configuration = getConfiguration(); + if (configuration == null) { + return null; + } + return configuration.optJSONObject(KEY_PROFILE); + } + public MessageCenterComposingItem getWhoCardEdit() { InteractionConfiguration configuration = getConfiguration(); if (configuration == null) { diff --git a/apptentive/src/main/java/com/apptentive/android/sdk/module/messagecenter/model/Composer.java b/apptentive/src/main/java/com/apptentive/android/sdk/module/messagecenter/model/Composer.java new file mode 100644 index 000000000..4360508e7 --- /dev/null +++ b/apptentive/src/main/java/com/apptentive/android/sdk/module/messagecenter/model/Composer.java @@ -0,0 +1,31 @@ +/* + * Copyright (c) 2016, Apptentive, Inc. All Rights Reserved. + * Please refer to the LICENSE file for the terms and conditions + * under which redistribution and use of this file is permitted. + */ + +package com.apptentive.android.sdk.module.messagecenter.model; + +public class Composer implements MessageCenterUtil.MessageCenterListItem { + + public String title; + public String closeBody; + public String closeDiscard; + public String closeCancel; + public String sendButton; + public String messageHint; + + public Composer(String title, String closeBody, String closeDiscard, String closeCancel, String sendButton, String messageHint) { + this.title = title; + this.closeDiscard = closeDiscard; + this.closeBody = closeBody; + this.closeCancel = closeCancel; + this.sendButton = sendButton; + this.messageHint = messageHint; + } + + @Override + public int getListItemType() { + return MESSAGE_COMPOSER; + } +} diff --git a/apptentive/src/main/java/com/apptentive/android/sdk/module/messagecenter/model/CompoundMessage.java b/apptentive/src/main/java/com/apptentive/android/sdk/module/messagecenter/model/CompoundMessage.java index 255a26129..689786f85 100644 --- a/apptentive/src/main/java/com/apptentive/android/sdk/module/messagecenter/model/CompoundMessage.java +++ b/apptentive/src/main/java/com/apptentive/android/sdk/module/messagecenter/model/CompoundMessage.java @@ -286,4 +286,15 @@ private boolean parseAttachmentsArray(String messageString) throws JSONException } return false; } + + @Override + public int getListItemType() { + if (isAutomatedMessage()) { + return MESSAGE_AUTO; + } else if (isOutgoing) { + return MESSAGE_OUTGOING; + } else { + return MESSAGE_INCOMING; + } + } } diff --git a/apptentive/src/main/java/com/apptentive/android/sdk/module/messagecenter/model/MessageCenterComposingItem.java b/apptentive/src/main/java/com/apptentive/android/sdk/module/messagecenter/model/MessageCenterComposingItem.java index be13e9d05..e6510fa74 100644 --- a/apptentive/src/main/java/com/apptentive/android/sdk/module/messagecenter/model/MessageCenterComposingItem.java +++ b/apptentive/src/main/java/com/apptentive/android/sdk/module/messagecenter/model/MessageCenterComposingItem.java @@ -6,6 +6,8 @@ package com.apptentive.android.sdk.module.messagecenter.model; +import com.apptentive.android.sdk.ApptentiveLog; + /** * @author Sky Kelsey */ @@ -35,6 +37,7 @@ public class MessageCenterComposingItem implements MessageCenterUtil.MessageCent public MessageCenterComposingItem(int type, String str_1, String str_2, String str_3, String str_4, String button_1, String button_2) { + ApptentiveLog.e("HERE"); this.type = type; this.str_1 = str_1; this.str_2 = str_2; @@ -48,4 +51,8 @@ public int getType() { return type; } + @Override + public int getListItemType() { + return MESSAGE_COMPOSER; + } } \ No newline at end of file diff --git a/apptentive/src/main/java/com/apptentive/android/sdk/module/messagecenter/model/MessageCenterGreeting.java b/apptentive/src/main/java/com/apptentive/android/sdk/module/messagecenter/model/MessageCenterGreeting.java index 4b4329439..d192e87ea 100644 --- a/apptentive/src/main/java/com/apptentive/android/sdk/module/messagecenter/model/MessageCenterGreeting.java +++ b/apptentive/src/main/java/com/apptentive/android/sdk/module/messagecenter/model/MessageCenterGreeting.java @@ -23,5 +23,8 @@ public MessageCenterGreeting(String title, String body, String avatar) { this.avatar = avatar; } - + @Override + public int getListItemType() { + return GREETING; + } } diff --git a/apptentive/src/main/java/com/apptentive/android/sdk/module/messagecenter/model/MessageCenterStatus.java b/apptentive/src/main/java/com/apptentive/android/sdk/module/messagecenter/model/MessageCenterStatus.java index da77ad204..c766cd01f 100644 --- a/apptentive/src/main/java/com/apptentive/android/sdk/module/messagecenter/model/MessageCenterStatus.java +++ b/apptentive/src/main/java/com/apptentive/android/sdk/module/messagecenter/model/MessageCenterStatus.java @@ -21,5 +21,8 @@ public MessageCenterStatus(String body, Integer icon) { this.icon = icon; } - + @Override + public int getListItemType() { + return STATUS; + } } diff --git a/apptentive/src/main/java/com/apptentive/android/sdk/module/messagecenter/model/MessageCenterUtil.java b/apptentive/src/main/java/com/apptentive/android/sdk/module/messagecenter/model/MessageCenterUtil.java index 59fec42c3..8071be82d 100644 --- a/apptentive/src/main/java/com/apptentive/android/sdk/module/messagecenter/model/MessageCenterUtil.java +++ b/apptentive/src/main/java/com/apptentive/android/sdk/module/messagecenter/model/MessageCenterUtil.java @@ -10,6 +10,16 @@ public class MessageCenterUtil { public interface MessageCenterListItem { + int STATUS = 1; + int MESSAGE_COMPOSER = 2; + int GREETING = 3; + int MESSAGE_OUTGOING = 4; + int MESSAGE_INCOMING = 5; + int MESSAGE_CONTEXT = 6; + int MESSAGE_AUTO = 7; + int WHO_CARD = 8; + + int getListItemType(); } // Combine both incoming and outgoing interfaces into one diff --git a/apptentive/src/main/java/com/apptentive/android/sdk/module/messagecenter/model/WhoCard.java b/apptentive/src/main/java/com/apptentive/android/sdk/module/messagecenter/model/WhoCard.java new file mode 100644 index 000000000..02722996e --- /dev/null +++ b/apptentive/src/main/java/com/apptentive/android/sdk/module/messagecenter/model/WhoCard.java @@ -0,0 +1,91 @@ +/* + * Copyright (c) 2016, Apptentive, Inc. All Rights Reserved. + * Please refer to the LICENSE file for the terms and conditions + * under which redistribution and use of this file is permitted. + */ + +package com.apptentive.android.sdk.module.messagecenter.model; + +import org.json.JSONException; +import org.json.JSONObject; + +public class WhoCard extends JSONObject implements MessageCenterUtil.MessageCenterListItem { + + private static final String KEY_REQUEST = "request"; + private static final String KEY_REQUIRE = "require"; + private static final String KEY_INITIAL = "initial"; + private static final String KEY_EDIT = "edit"; + private static final String KEY_TITLE = "title"; + private static final String KEY_NAME_HINT = "name_hint"; + private static final String KEY_EMAIL_HINT = "email_hint"; + private static final String KEY_EMAIL_EXPLANATION = "email_explanation"; + private static final String KEY_SKIP_BUTTON = "skip_button"; + private static final String KEY_SAVE_BUTTON = "save_button"; + + private boolean initial; + + public WhoCard(String json) throws JSONException { + super(json); + } + + public boolean isInitial() { + return initial; + } + + public void setInitial(boolean initial) { + this.initial = initial; + } + + @Override + public int getListItemType() { + return WHO_CARD; + } + + public boolean isRequest() { + return optBoolean(KEY_REQUEST, false); + } + + public boolean isRequire() { + return optBoolean(KEY_REQUIRE, false); + } + + private JSONObject getInitial() { + return optJSONObject(KEY_INITIAL); + } + + private JSONObject getEdit() { + return optJSONObject(KEY_EDIT); + } + + private JSONObject getApplicableConfig() { + if (isInitial()) { + return getInitial(); + } else { + return getEdit(); + } + } + + public String getTitle() { + return getApplicableConfig().optString(KEY_TITLE, null); + } + + public String getNameHint() { + return getApplicableConfig().optString(KEY_NAME_HINT, null); + } + + public String getEmailHint() { + return getApplicableConfig().optString(KEY_EMAIL_HINT, null); + } + + public String getEmailExplanation() { + return getApplicableConfig().optString(KEY_EMAIL_EXPLANATION, null); + } + + public String getSkipButton() { + return getApplicableConfig().optString(KEY_SKIP_BUTTON, null); + } + + public String getSaveButton() { + return getApplicableConfig().optString(KEY_SAVE_BUTTON, null); + } +} diff --git a/apptentive/src/main/java/com/apptentive/android/sdk/module/messagecenter/view/MessageAdapter.java b/apptentive/src/main/java/com/apptentive/android/sdk/module/messagecenter/view/MessageAdapter.java index 2edf27a0f..ea0e19a81 100644 --- a/apptentive/src/main/java/com/apptentive/android/sdk/module/messagecenter/view/MessageAdapter.java +++ b/apptentive/src/main/java/com/apptentive/android/sdk/module/messagecenter/view/MessageAdapter.java @@ -38,7 +38,6 @@ import com.apptentive.android.sdk.module.messagecenter.model.MessageCenterUtil; import com.apptentive.android.sdk.module.messagecenter.model.MessageCenterUtil.MessageCenterListItem; import com.apptentive.android.sdk.module.messagecenter.view.holder.AutomatedMessageHolder; -import com.apptentive.android.sdk.module.messagecenter.view.holder.HolderFactory; import com.apptentive.android.sdk.module.messagecenter.view.holder.IncomingCompoundMessageHolder; import com.apptentive.android.sdk.module.messagecenter.view.holder.MessageCenterListItemHolder; import com.apptentive.android.sdk.module.messagecenter.view.holder.OutgoingCompoundMessageHolder; @@ -224,7 +223,7 @@ public View getView(final int position, View convertView, ViewGroup parent) { } case TYPE_COMPOSING_AREA: { if (composingView == null) { - composingView = new MessageCenterComposingView(fragment, (MessageCenterComposingItem) listItem, composingActionListener); + composingView = new MessageCenterComposingView(fragment); setupComposingView(position); } view = composingView; @@ -257,7 +256,7 @@ public View getView(final int position, View convertView, ViewGroup parent) { break; } if (view != null) { - holder = HolderFactory.createHolder((MessageCenterListItemView) view); +// holder = HolderFactory.createHolder((MessageCenterListItemView) view); view.setTag(holder); } } else { @@ -296,8 +295,8 @@ public View getView(final int position, View convertView, ViewGroup parent) { case TYPE_COMPOUND_INCOMING: { showMessageAnimation = true; if (bLoadAvatar) { - ImageUtil.startDownloadAvatarTask(((IncomingCompoundMessageHolder) holder).avatar, - ((CompoundMessage) listItem).getSenderProfilePhoto()); +// ImageUtil.startDownloadAvatarTask(((IncomingCompoundMessageHolder) holder).avatar, +// ((CompoundMessage) listItem).getSenderProfilePhoto()); } final CompoundMessage compoundMessage = (CompoundMessage) listItem; String datestamp = ((CompoundMessage) listItem).getDatestamp(); @@ -305,10 +304,10 @@ public View getView(final int position, View convertView, ViewGroup parent) { int widthMeasureSpec = View.MeasureSpec.makeMeasureSpec(parent.getWidth(), View.MeasureSpec.EXACTLY); view.measure(widthMeasureSpec, 0); int viewWidth = container.getMeasuredWidth(); - ((IncomingCompoundMessageHolder) holder).updateMessage(compoundMessage.getSenderUsername(), - datestamp, compoundMessage.getBody(), viewWidth - container.getPaddingLeft() - container.getPaddingRight(), - fragment.getResources().getInteger(R.integer.apptentive_image_grid_default_column_number_incoming), - compoundMessage.getRemoteAttachments()); +// ((IncomingCompoundMessageHolder) holder).updateMessage(compoundMessage.getSenderUsername(), +// datestamp, compoundMessage.getBody(), viewWidth - container.getPaddingLeft() - container.getPaddingRight(), +// fragment.getResources().getInteger(R.integer.apptentive_image_grid_default_column_number_incoming), +// compoundMessage.getRemoteAttachments()); if (!compoundMessage.isRead() && !positionsWithPendingUpdateTask.contains(position)) { positionsWithPendingUpdateTask.add(position); startUpdateUnreadMessageTask(compoundMessage, position); @@ -343,20 +342,20 @@ public View getView(final int position, View convertView, ViewGroup parent) { } int statusTextColor = getStatusColor(createdTime); - ((OutgoingCompoundMessageHolder) holder).updateMessage(datestamp, status, statusTextColor, - bShowProgress, messageBody, imagebandWidth, - fragment.getResources().getInteger(R.integer.apptentive_image_grid_default_column_number), files); +// ((OutgoingCompoundMessageHolder) holder).updateMessage(datestamp, status, statusTextColor, +// bShowProgress, messageBody, imagebandWidth, +// fragment.getResources().getInteger(R.integer.apptentive_image_grid_default_column_number), files); break; } case TYPE_STATUS: { MessageCenterStatus status = (MessageCenterStatus) listItem; - ((StatusHolder) holder).updateMessage(status.body, status.icon); +// ((StatusHolder) holder).updateMessage(status.body, status.icon); break; } case TYPE_AUTO: { CompoundMessage autoMessage = (CompoundMessage) listItem; String dateStamp = autoMessage.getDatestamp(); - ((AutomatedMessageHolder) holder).updateMessage(dateStamp, autoMessage); +// ((AutomatedMessageHolder) holder).updateMessage(dateStamp, autoMessage); break; } default: @@ -567,33 +566,6 @@ public boolean onTouch(View v, MotionEvent event) { } else { focusOnNameField = false; } - AnimatorSet set = AnimationUtil.buildListViewRowShowAnimator(whoCardView, new Animator.AnimatorListener() { - @Override - public void onAnimationStart(Animator animation) { - } - - @Override - public void onAnimationRepeat(Animator animation) { - } - - @Override - public void onAnimationEnd(Animator animation) { - View focusedView = null; - if (forceShowKeyboard) { - if (focusOnNameField) { - focusedView = nameEditText; - } else { - focusedView = emailEditText; - } - } - composingActionListener.onWhoCardViewCreated(nameEditText, emailEditText, focusedView); - } - - @Override - public void onAnimationCancel(Animator animation) { - } - }, null); - set.start(); } public View getWhoCardView() { @@ -799,9 +771,11 @@ protected void onPostExecute(Bitmap bitmap) { return; } OutgoingCompoundMessageHolder holder = holderRef.get(); +/* if (holder != null && holder.position == position) { //Todo: load image into imageview } +*/ } } diff --git a/apptentive/src/main/java/com/apptentive/android/sdk/module/messagecenter/view/MessageCenterComposingView.java b/apptentive/src/main/java/com/apptentive/android/sdk/module/messagecenter/view/MessageCenterComposingView.java index bd9712b04..6a840ff95 100644 --- a/apptentive/src/main/java/com/apptentive/android/sdk/module/messagecenter/view/MessageCenterComposingView.java +++ b/apptentive/src/main/java/com/apptentive/android/sdk/module/messagecenter/view/MessageCenterComposingView.java @@ -45,9 +45,10 @@ public class MessageCenterComposingView extends FrameLayout implements MessageCe private ApptentiveImageGridView imageBandView; List images = new ArrayList(); - public MessageCenterComposingView(Fragment fragment, final MessageCenterComposingItem item, final MessageAdapter.OnListviewItemActionListener listener) { + public MessageCenterComposingView(Fragment fragment) { super(fragment.getContext()); +/* LayoutInflater inflater = fragment.getActivity().getLayoutInflater(); View parentView = inflater.inflate(R.layout.apptentive_message_center_composing_area, this); et = (EditText) parentView.findViewById(R.id.composing_et); @@ -56,11 +57,11 @@ public MessageCenterComposingView(Fragment fragment, final MessageCenterComposin } et.setLinksClickable(true); et.setAutoLinkMask(Linkify.WEB_URLS | Linkify.PHONE_NUMBERS | Linkify.EMAIL_ADDRESSES | Linkify.MAP_ADDRESSES); - /* + *//* * LinkMovementMethod would enable clickable links in EditView, but disables copy/paste through Long Press. * Use a custom MovementMethod instead * - */ + *//* et.setMovementMethod(ApptentiveMovementMethod.getInstance()); //If the edit text contains previous text with potential links Linkify.addLinks(et, Linkify.WEB_URLS); @@ -98,6 +99,7 @@ public void onClick(int position, ImageItem image) { imageBandView.setImageIndicatorCallback((ImageGridViewAdapter.Callback) listener); // Initialize image attachments band with empty data clearImageAttachmentBand(); +*/ } public EditText getEditText() { diff --git a/apptentive/src/main/java/com/apptentive/android/sdk/module/messagecenter/view/MessageCenterRecyclerView.java b/apptentive/src/main/java/com/apptentive/android/sdk/module/messagecenter/view/MessageCenterRecyclerView.java new file mode 100644 index 000000000..5903be6e0 --- /dev/null +++ b/apptentive/src/main/java/com/apptentive/android/sdk/module/messagecenter/view/MessageCenterRecyclerView.java @@ -0,0 +1,48 @@ +/* + * Copyright (c) 2016, Apptentive, Inc. All Rights Reserved. + * Please refer to the LICENSE file for the terms and conditions + * under which redistribution and use of this file is permitted. + */ + +package com.apptentive.android.sdk.module.messagecenter.view; + +import android.content.Context; +import android.support.annotation.Nullable; +import android.support.v7.widget.RecyclerView; +import android.util.AttributeSet; + + +public class MessageCenterRecyclerView extends RecyclerView { + + public MessageCenterRecyclerView(Context context) { + super(context); + } + + public MessageCenterRecyclerView(Context context, @Nullable AttributeSet attrs) { + super(context, attrs); + } + + public MessageCenterRecyclerView(Context context, @Nullable AttributeSet attrs, int defStyle) { + super(context, attrs, defStyle); + } + + + + + + public int getFirstVisiblePosition() { + return 0; // TODO + } + + public int getLastVisiblePosition() { + return 0; // TODO + } + + public void setSelection(int selection) { + return; // TODO + } + + public void setSelectionFromTop(int selection, int top) { + return; // TODO + } +} diff --git a/apptentive/src/main/java/com/apptentive/android/sdk/module/messagecenter/view/MessageCenterRecyclerViewAdapter.java b/apptentive/src/main/java/com/apptentive/android/sdk/module/messagecenter/view/MessageCenterRecyclerViewAdapter.java new file mode 100644 index 000000000..6d143bd84 --- /dev/null +++ b/apptentive/src/main/java/com/apptentive/android/sdk/module/messagecenter/view/MessageCenterRecyclerViewAdapter.java @@ -0,0 +1,268 @@ +/* + * Copyright (c) 2016, Apptentive, Inc. All Rights Reserved. + * Please refer to the LICENSE file for the terms and conditions + * under which redistribution and use of this file is permitted. + */ + +package com.apptentive.android.sdk.module.messagecenter.view; + +import android.os.Parcel; +import android.os.Parcelable; +import android.preference.PreferenceManager; +import android.support.v4.app.Fragment; +import android.support.v7.widget.RecyclerView; +import android.text.TextUtils; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; +import android.widget.EditText; + +import com.apptentive.android.sdk.ApptentiveLog; +import com.apptentive.android.sdk.R; +import com.apptentive.android.sdk.model.StoredFile; +import com.apptentive.android.sdk.module.engagement.interaction.model.Interaction; +import com.apptentive.android.sdk.module.messagecenter.model.Composer; +import com.apptentive.android.sdk.module.messagecenter.model.CompoundMessage; +import com.apptentive.android.sdk.module.messagecenter.model.MessageCenterComposingItem; +import com.apptentive.android.sdk.module.messagecenter.model.MessageCenterGreeting; +import com.apptentive.android.sdk.module.messagecenter.model.MessageCenterStatus; +import com.apptentive.android.sdk.module.messagecenter.model.MessageCenterUtil; +import com.apptentive.android.sdk.module.messagecenter.model.WhoCard; +import com.apptentive.android.sdk.module.messagecenter.view.holder.AutomatedMessageHolder; +import com.apptentive.android.sdk.module.messagecenter.view.holder.GreetingHolder; +import com.apptentive.android.sdk.module.messagecenter.view.holder.IncomingCompoundMessageHolder; +import com.apptentive.android.sdk.module.messagecenter.view.holder.MessageComposerHolder; +import com.apptentive.android.sdk.module.messagecenter.view.holder.OutgoingCompoundMessageHolder; +import com.apptentive.android.sdk.module.messagecenter.view.holder.StatusHolder; +import com.apptentive.android.sdk.module.messagecenter.view.holder.WhoCardHolder; +import com.apptentive.android.sdk.util.image.ImageItem; +import com.apptentive.android.sdk.util.image.ImageUtil; + +import java.util.ArrayList; +import java.util.List; + +import static com.apptentive.android.sdk.module.messagecenter.model.MessageCenterUtil.MessageCenterListItem.GREETING; +import static com.apptentive.android.sdk.module.messagecenter.model.MessageCenterUtil.MessageCenterListItem.MESSAGE_AUTO; +import static com.apptentive.android.sdk.module.messagecenter.model.MessageCenterUtil.MessageCenterListItem.MESSAGE_COMPOSER; +import static com.apptentive.android.sdk.module.messagecenter.model.MessageCenterUtil.MessageCenterListItem.MESSAGE_INCOMING; +import static com.apptentive.android.sdk.module.messagecenter.model.MessageCenterUtil.MessageCenterListItem.MESSAGE_OUTGOING; +import static com.apptentive.android.sdk.module.messagecenter.model.MessageCenterUtil.MessageCenterListItem.STATUS; +import static com.apptentive.android.sdk.module.messagecenter.model.MessageCenterUtil.MessageCenterListItem.WHO_CARD; + +public class MessageCenterRecyclerViewAdapter extends RecyclerView.Adapter { + + Fragment fragment; + RecyclerView recyclerView; + Interaction interaction; + List messages; + + public MessageCenterRecyclerViewAdapter(Fragment fragment, Interaction interaction, List messages) { + this.fragment = fragment; + this.interaction = interaction; + this.messages = messages; + } + + @Override + public void onAttachedToRecyclerView(RecyclerView recyclerView) { + super.onAttachedToRecyclerView(recyclerView); + this.recyclerView = recyclerView; + } + + @Override + public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) { + ApptentiveLog.e("onCreateViewHolder()"); + switch (viewType) { + case MESSAGE_COMPOSER: { + ApptentiveLog.e("-> Message Composer"); + LayoutInflater inflater = LayoutInflater.from(parent.getContext()); + View view = inflater.inflate(R.layout.apptentive_message_center_composer, parent, false); + return new MessageComposerHolder(view); + } + case STATUS: { + ApptentiveLog.e("-> Status"); + LayoutInflater inflater = LayoutInflater.from(parent.getContext()); + View view = inflater.inflate(R.layout.apptentive_message_center_status, parent, false); + return new StatusHolder(view); + } + case GREETING: { + ApptentiveLog.e("-> Greeting"); + LayoutInflater inflater = LayoutInflater.from(parent.getContext()); + View view = inflater.inflate(R.layout.apptentive_message_center_greeting, parent, false); + return new GreetingHolder(view); + } + case MESSAGE_OUTGOING: { + ApptentiveLog.e("-> Message Outgoing"); + LayoutInflater inflater = LayoutInflater.from(parent.getContext()); + View view = inflater.inflate(R.layout.apptentive_message_outgoing, parent, false); + return new OutgoingCompoundMessageHolder(view); + } + case MESSAGE_INCOMING: { + ApptentiveLog.e("-> Message Incoming"); + LayoutInflater inflater = LayoutInflater.from(parent.getContext()); + View view = inflater.inflate(R.layout.apptentive_message_incoming, parent, false); + return new IncomingCompoundMessageHolder(view); + } + case MESSAGE_AUTO: { + ApptentiveLog.e("-> Message Auto"); + LayoutInflater inflater = LayoutInflater.from(parent.getContext()); + View view = inflater.inflate(R.layout.apptentive_message_auto, parent, false); + return new AutomatedMessageHolder(view); + } + case WHO_CARD: { + ApptentiveLog.e("-> Who Card"); + LayoutInflater inflater = LayoutInflater.from(parent.getContext()); + View view = inflater.inflate(R.layout.apptentive_message_center_who_card, parent, false); + return new WhoCardHolder(view); + } + } + return null; + } + + @Override + public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) { + ApptentiveLog.e("onBindViewHolder()"); + switch (getItemViewType(position)) { + case MESSAGE_COMPOSER: { + ApptentiveLog.e("-> Message Composer"); + Composer composer = (Composer) messages.get(position); + MessageComposerHolder composerHolder = (MessageComposerHolder) holder; + composerHolder.bindView(fragment, composer); + break; + } + case STATUS: { + ApptentiveLog.e("-> Status"); + MessageCenterStatus status = (MessageCenterStatus) messages.get(position); + StatusHolder statusHolder = (StatusHolder) holder; + statusHolder.body.setText(status.body); + + if (status.icon != null) { + statusHolder.icon.setImageResource(status.icon); + statusHolder.icon.setVisibility(View.VISIBLE); + } else { + statusHolder.icon.setVisibility(View.GONE); + } + break; + } + case GREETING: { + ApptentiveLog.e("-> Greeting"); + MessageCenterGreeting greeting = (MessageCenterGreeting) messages.get(position); + GreetingHolder greetingHolder = (GreetingHolder) holder; + greetingHolder.bindView(greeting); + break; + } + case MESSAGE_INCOMING: { + ApptentiveLog.e("-> Message Incoming"); + CompoundMessage compoundMessage = (CompoundMessage) messages.get(position); + IncomingCompoundMessageHolder compoundHolder = (IncomingCompoundMessageHolder) holder; + compoundHolder.bindView(recyclerView, compoundMessage); + break; + } + case MESSAGE_OUTGOING: { + ApptentiveLog.e("-> Message Outgoing"); + CompoundMessage compoundMessage = (CompoundMessage) messages.get(position); + OutgoingCompoundMessageHolder compoundHolder = (OutgoingCompoundMessageHolder) holder; + compoundHolder.bindView(recyclerView, compoundMessage); + break; + } + case MESSAGE_AUTO: { + ApptentiveLog.e("-> Message Auto"); + CompoundMessage autoMessage = (CompoundMessage) messages.get(position); + AutomatedMessageHolder autoHolder = (AutomatedMessageHolder) holder; + autoHolder.bindView(recyclerView, autoMessage); + break; + } + case WHO_CARD: { + ApptentiveLog.e("-> Who Card"); + WhoCard whoCard = (WhoCard) messages.get(position); + WhoCardHolder whoCardHolder = (WhoCardHolder) holder; + whoCardHolder.bindView(recyclerView, whoCard); + break; + } + } + } + + @Override + public int getItemCount() { + return messages.size(); + } + + @Override + public int getItemViewType(int position) { + MessageCenterUtil.MessageCenterListItem message = messages.get(position); + return message.getListItemType(); + } + + public void setPaused(boolean bPause) { + //isInPauseState = bPause; // TODO + } + + public Parcelable getWhoCardNameState() { + // TODO + return new Parcelable() { + @Override + public int describeContents() { + return 0; + } + + @Override + public void writeToParcel(Parcel dest, int flags) { + + } + }; + } + + public Parcelable getWhoCardEmailState() { + // TODO + return new Parcelable() { + @Override + public int describeContents() { + return 0; + } + + @Override + public void writeToParcel(Parcel dest, int flags) { + + } + }; + } + + public String getWhoCardAvatarFileName() { + return null; // TODO + } + + public void addImagestoComposer(List images) { + return; // TODO + } + + public void setForceShowKeyboard(boolean force) { + return; // TODO + } + + public void removeImageFromComposer(int position) { + return; // TODO + } + + public View getWhoCardView() { + return new View(fragment.getContext()); // TODO + } + + public void clearWhoCard() { + return; // TODO + } + + public MessageCenterComposingActionBarView getComposingActionBarView() { + return new MessageCenterComposingActionBarView(fragment, null, null); // TODO + } + + public View getComposingAreaView() { + return new View(fragment.getContext()); // TODO + } + + public void clearComposing() { + return; // TODO + } + + public EditText getEditTextInComposing() { + return new EditText(fragment.getContext()); // TODO + } +} diff --git a/apptentive/src/main/java/com/apptentive/android/sdk/module/messagecenter/view/holder/AutomatedMessageHolder.java b/apptentive/src/main/java/com/apptentive/android/sdk/module/messagecenter/view/holder/AutomatedMessageHolder.java index 0e63ef883..df6bdc28b 100644 --- a/apptentive/src/main/java/com/apptentive/android/sdk/module/messagecenter/view/holder/AutomatedMessageHolder.java +++ b/apptentive/src/main/java/com/apptentive/android/sdk/module/messagecenter/view/holder/AutomatedMessageHolder.java @@ -1,35 +1,27 @@ /* - * Copyright (c) 2015, Apptentive, Inc. All Rights Reserved. + * Copyright (c) 2016, Apptentive, Inc. All Rights Reserved. * Please refer to the LICENSE file for the terms and conditions * under which redistribution and use of this file is permitted. */ package com.apptentive.android.sdk.module.messagecenter.view.holder; +import android.support.v7.widget.RecyclerView; +import android.view.View; import android.widget.TextView; import com.apptentive.android.sdk.R; import com.apptentive.android.sdk.module.messagecenter.model.CompoundMessage; -import com.apptentive.android.sdk.module.messagecenter.view.AutomatedMessageView; -/** - * @author Barry Li - */ -public class AutomatedMessageHolder extends MessageHolder { +public class AutomatedMessageHolder extends RecyclerView.ViewHolder { public TextView body; - public AutomatedMessageHolder(AutomatedMessageView view) { - super(view); - body = (TextView) view.findViewById(R.id.apptentive_message_auto_body); + public AutomatedMessageHolder(View itemView) { + super(itemView); + body = (TextView) itemView.findViewById(R.id.apptentive_message_auto_body); } - public void updateMessage(String dateStamp, final CompoundMessage newMessage) { - super.updateMessage(dateStamp, 0, null); - body.post(new Runnable() { - @Override - public void run() { - body.setText(newMessage.getBody()); - } - }); + public void bindView(final RecyclerView parent, final CompoundMessage message) { + body.setText(message.getBody()); } } \ No newline at end of file diff --git a/apptentive/src/main/java/com/apptentive/android/sdk/module/messagecenter/view/holder/GreetingHolder.java b/apptentive/src/main/java/com/apptentive/android/sdk/module/messagecenter/view/holder/GreetingHolder.java new file mode 100644 index 000000000..7491632b1 --- /dev/null +++ b/apptentive/src/main/java/com/apptentive/android/sdk/module/messagecenter/view/holder/GreetingHolder.java @@ -0,0 +1,50 @@ +/* + * Copyright (c) 2016, Apptentive, Inc. All Rights Reserved. + * Please refer to the LICENSE file for the terms and conditions + * under which redistribution and use of this file is permitted. + */ + +package com.apptentive.android.sdk.module.messagecenter.view.holder; + +import android.support.v7.widget.RecyclerView; +import android.view.View; +import android.widget.ImageButton; +import android.widget.TextView; + +import com.apptentive.android.sdk.ApptentiveInternal; +import com.apptentive.android.sdk.R; +import com.apptentive.android.sdk.module.messagecenter.model.MessageCenterGreeting; +import com.apptentive.android.sdk.module.messagecenter.view.ApptentiveAvatarView; +import com.apptentive.android.sdk.util.Util; +import com.apptentive.android.sdk.util.image.ImageUtil; + + +public class GreetingHolder extends RecyclerView.ViewHolder { + + public TextView title; + public TextView body; + public ApptentiveAvatarView avatar; + public ImageButton infoButton; + + public GreetingHolder(View itemView) { + super(itemView); + + title = (TextView) itemView.findViewById(R.id.greeting_title); + body = (TextView) itemView.findViewById(R.id.greeting_body); + avatar = (ApptentiveAvatarView) itemView.findViewById(R.id.avatar); + infoButton = (ImageButton) itemView.findViewById(R.id.btn_info); + } + + public void bindView(MessageCenterGreeting greeting) { + title.setText(greeting.title); + body.setText(greeting.body); + ImageUtil.startDownloadAvatarTask(avatar, greeting.avatar); + infoButton.setOnClickListener(new View.OnClickListener() { + public void onClick(View view) { + view.setClickable(false); + ApptentiveInternal.getInstance().showAboutInternal(Util.castContextToActivity(itemView.getContext()), false); + } + }); + infoButton.setClickable(true); + } +} diff --git a/apptentive/src/main/java/com/apptentive/android/sdk/module/messagecenter/view/holder/HolderFactory.java b/apptentive/src/main/java/com/apptentive/android/sdk/module/messagecenter/view/holder/HolderFactory.java deleted file mode 100644 index e54bc1d67..000000000 --- a/apptentive/src/main/java/com/apptentive/android/sdk/module/messagecenter/view/holder/HolderFactory.java +++ /dev/null @@ -1,34 +0,0 @@ -/* - * Copyright (c) 2015, Apptentive, Inc. All Rights Reserved. - * Please refer to the LICENSE file for the terms and conditions - * under which redistribution and use of this file is permitted. - */ - -package com.apptentive.android.sdk.module.messagecenter.view.holder; - -import com.apptentive.android.sdk.module.messagecenter.view.AutomatedMessageView; -import com.apptentive.android.sdk.module.messagecenter.view.CompoundMessageView; -import com.apptentive.android.sdk.module.messagecenter.view.MessageCenterListItemView; -import com.apptentive.android.sdk.module.messagecenter.view.MessageCenterStatusView; - -/** - * @author Sky Kelsey - */ -public class HolderFactory { - - public static MessageCenterListItemHolder createHolder(MessageCenterListItemView messageCenterListItemView) { - MessageCenterListItemHolder holder = null; - if (messageCenterListItemView instanceof CompoundMessageView) { - CompoundMessageView textMessageView = (CompoundMessageView) messageCenterListItemView; - holder = (textMessageView.isViewShowingOutgoingMessage())? new OutgoingCompoundMessageHolder(textMessageView) : - new IncomingCompoundMessageHolder(textMessageView); - } else if (messageCenterListItemView instanceof AutomatedMessageView) { - AutomatedMessageView automatedView = (AutomatedMessageView) messageCenterListItemView; - holder = new AutomatedMessageHolder(automatedView); - } else if (messageCenterListItemView instanceof MessageCenterStatusView) { - MessageCenterStatusView messageCenterStatusView = (MessageCenterStatusView) messageCenterListItemView; - holder = new StatusHolder(messageCenterStatusView); - } - return holder; - } -} diff --git a/apptentive/src/main/java/com/apptentive/android/sdk/module/messagecenter/view/holder/IncomingCompoundMessageHolder.java b/apptentive/src/main/java/com/apptentive/android/sdk/module/messagecenter/view/holder/IncomingCompoundMessageHolder.java index 1a88446db..10c2638ec 100644 --- a/apptentive/src/main/java/com/apptentive/android/sdk/module/messagecenter/view/holder/IncomingCompoundMessageHolder.java +++ b/apptentive/src/main/java/com/apptentive/android/sdk/module/messagecenter/view/holder/IncomingCompoundMessageHolder.java @@ -1,90 +1,84 @@ /* - * Copyright (c) 2015, Apptentive, Inc. All Rights Reserved. + * Copyright (c) 2016, Apptentive, Inc. All Rights Reserved. * Please refer to the LICENSE file for the terms and conditions * under which redistribution and use of this file is permitted. */ package com.apptentive.android.sdk.module.messagecenter.view.holder; +import android.support.v7.widget.RecyclerView; import android.text.TextUtils; import android.view.View; import android.widget.TextView; import com.apptentive.android.sdk.R; - import com.apptentive.android.sdk.model.StoredFile; +import com.apptentive.android.sdk.module.messagecenter.model.CompoundMessage; import com.apptentive.android.sdk.module.messagecenter.view.ApptentiveAvatarView; -import com.apptentive.android.sdk.module.messagecenter.view.CompoundMessageView; import com.apptentive.android.sdk.module.messagecenter.view.MessageAdapter; import com.apptentive.android.sdk.util.Util; import com.apptentive.android.sdk.util.image.ApptentiveImageGridView; import com.apptentive.android.sdk.util.image.ImageItem; +import com.apptentive.android.sdk.util.image.ImageUtil; import java.io.File; import java.util.ArrayList; import java.util.List; -/** - * @author Barry Li - */ public class IncomingCompoundMessageHolder extends MessageHolder { public ApptentiveAvatarView avatar; + private View root; + private View container; private TextView messageBodyView; private TextView nameView; private ApptentiveImageGridView imageBandView; private MessageAdapter.OnListviewItemActionListener listener; - public IncomingCompoundMessageHolder(CompoundMessageView view) { - super(view); - avatar = (ApptentiveAvatarView) view.findViewById(R.id.avatar); - nameView = (TextView) view.findViewById(R.id.sender_name); - messageBodyView = (TextView) view.findViewById(R.id.apptentive_compound_message_body); - imageBandView =(ApptentiveImageGridView) view.findViewById(R.id.grid); - listener = view.getListener(); - } + private static final boolean loadAvatar = false; - public void updateMessage(final String name, final String datestamp, final String text, final int viewWidth, final int desiredColumn, final List imagesToAttach) { - super.updateMessage(datestamp, 0, null); + public IncomingCompoundMessageHolder(View itemView) { + super(itemView); + root = itemView.findViewById(R.id.message_root); + container = itemView.findViewById(R.id.apptentive_compound_message_body_container); + avatar = (ApptentiveAvatarView) itemView.findViewById(R.id.avatar); + nameView = (TextView) itemView.findViewById(R.id.sender_name); + messageBodyView = (TextView) itemView.findViewById(R.id.apptentive_compound_message_body); + imageBandView = (ApptentiveImageGridView) itemView.findViewById(R.id.grid); + //listener = view.getListener(); + } - if (messageBodyView != null) { - messageBodyView.post(new Runnable() { - @Override - public void run() { - messageBodyView.setText(text); - } - }); + public void bindView(final RecyclerView parent, final CompoundMessage message) { + super.bindView(parent, message); + if (loadAvatar) { + ImageUtil.startDownloadAvatarTask(avatar, message.getSenderProfilePhoto()); } + String datestamp = message.getDatestamp(); - if (nameView != null) { - if (name != null && !name.isEmpty()) { - nameView.post(new Runnable() { - @Override - public void run() { - nameView.setVisibility(View.VISIBLE); - nameView.setText(name); - } - }); - } else { - nameView.post(new Runnable() { - @Override - public void run() { - nameView.setVisibility(View.GONE); - } - }); - } + int widthMeasureSpec = View.MeasureSpec.makeMeasureSpec(parent.getWidth(), View.MeasureSpec.EXACTLY); + root.measure(widthMeasureSpec, 0); + int viewWidth = container.getMeasuredWidth(); + + messageBodyView.setText(message.getBody()); + + String name = message.getSenderUsername(); + if (name != null && !name.isEmpty()) { + nameView.setVisibility(View.VISIBLE); + nameView.setText(name); + } else { + nameView.setVisibility(View.GONE); } - // Set up attahments view + final List files = message.getRemoteAttachments(); if (imageBandView != null) { - if (imagesToAttach == null || imagesToAttach.size() == 0) { + if (files == null || files.size() == 0) { imageBandView.setVisibility(View.GONE); } else { imageBandView.setVisibility(View.VISIBLE); - imageBandView.setAdapterItemSize(viewWidth, desiredColumn); + imageBandView.setAdapterItemSize(viewWidth, itemView.getResources().getInteger(R.integer.apptentive_image_grid_default_column_number_incoming)); List images = new ArrayList(); final File cacheDir = Util.getDiskCacheDir(imageBandView.getContext()); - for (StoredFile file: imagesToAttach) { + for (StoredFile file : files) { String thumbnailUrl = file.getSourceUriOrPath(); String remoteUrl = file.getApptentiveUri(); String thumbnailStorageFilePath; @@ -100,7 +94,7 @@ public void run() { imageBandView.setListener(new ApptentiveImageGridView.ImageItemClickedListener() { @Override public void onClick(int position, ImageItem image) { - StoredFile file = imagesToAttach.get(position); + StoredFile file = files.get(position); String remoteUrl = file.getApptentiveUri(); String localFilePath = Util.generateCacheFileFullPath(remoteUrl, cacheDir); if (listener != null) { @@ -111,5 +105,11 @@ public void onClick(int position, ImageItem image) { } } +/* + if (!message.isRead() && !positionsWithPendingUpdateTask.contains(position)) { + positionsWithPendingUpdateTask.add(position); + startUpdateUnreadMessageTask(compoundMessage, position); + } +*/ } } \ No newline at end of file diff --git a/apptentive/src/main/java/com/apptentive/android/sdk/module/messagecenter/view/holder/MessageComposerHolder.java b/apptentive/src/main/java/com/apptentive/android/sdk/module/messagecenter/view/holder/MessageComposerHolder.java new file mode 100644 index 000000000..051a8c92e --- /dev/null +++ b/apptentive/src/main/java/com/apptentive/android/sdk/module/messagecenter/view/holder/MessageComposerHolder.java @@ -0,0 +1,214 @@ +/* + * Copyright (c) 2016, Apptentive, Inc. All Rights Reserved. + * Please refer to the LICENSE file for the terms and conditions + * under which redistribution and use of this file is permitted. + */ + +package com.apptentive.android.sdk.module.messagecenter.view.holder; + +import android.content.res.ColorStateList; +import android.graphics.drawable.Drawable; +import android.os.Build; +import android.os.Bundle; +import android.support.v4.app.Fragment; +import android.support.v4.content.ContextCompat; +import android.support.v4.graphics.drawable.DrawableCompat; +import android.support.v7.widget.RecyclerView; +import android.text.Editable; +import android.text.Layout; +import android.text.Selection; +import android.text.Spannable; +import android.text.TextWatcher; +import android.text.method.ArrowKeyMovementMethod; +import android.text.method.MovementMethod; +import android.text.style.ClickableSpan; +import android.text.util.Linkify; +import android.view.MotionEvent; +import android.view.View; +import android.widget.EditText; +import android.widget.ImageButton; +import android.widget.TextView; + +import com.apptentive.android.sdk.R; +import com.apptentive.android.sdk.module.messagecenter.model.Composer; +import com.apptentive.android.sdk.module.messagecenter.view.MessageAdapter; +import com.apptentive.android.sdk.module.messagecenter.view.MessageCenterComposingView; +import com.apptentive.android.sdk.util.Constants; +import com.apptentive.android.sdk.util.Util; +import com.apptentive.android.sdk.util.image.ApptentiveImageGridView; +import com.apptentive.android.sdk.util.image.ImageGridViewAdapter; +import com.apptentive.android.sdk.util.image.ImageItem; +import com.apptentive.android.sdk.view.ApptentiveAlertDialog; + + +public class MessageComposerHolder extends RecyclerView.ViewHolder { + + public ImageButton cancelButton; + public TextView title; + public ImageButton attachButton; + public ImageButton sendButton; + public EditText message; + public ApptentiveImageGridView attachments; + + public MessageComposerHolder(View itemView) { + super(itemView); + cancelButton = (ImageButton) itemView.findViewById(R.id.cancel_composing); + title = (TextView) itemView.findViewById(R.id.title); + attachButton = (ImageButton) itemView.findViewById(R.id.btn_attach_image); + sendButton = (ImageButton) itemView.findViewById(R.id.btn_send_message); + message = (EditText) itemView.findViewById(R.id.composing_et); + attachments = (ApptentiveImageGridView) itemView.findViewById(R.id.grid); + } + + public void bindView(final Fragment fragment, final Composer composer) { + title.setText(composer.title); + +////// + ColorStateList colors = ContextCompat.getColorStateList(itemView.getContext(), Util.getResourceIdFromAttribute(itemView.getContext().getTheme(), R.attr.apptentiveButtonTintColorStateList)); + + ImageButton closeButton = (ImageButton) itemView.findViewById(R.id.cancel_composing); + // Use a color state list for button tint state on Lollipop. On prior platforms, need to apply state color manually. + Drawable closeButtonDrawable = DrawableCompat.wrap(closeButton.getDrawable()); + DrawableCompat.setTintList(closeButtonDrawable, colors); + closeButton.setImageDrawable(closeButtonDrawable); + + closeButton.setOnClickListener(new View.OnClickListener() { + public void onClick(View view) { + if (message.getText().length() > 0) { + Bundle bundle = new Bundle(); + bundle.putString("message", composer.closeBody); + bundle.putString("positive", composer.closeDiscard); + bundle.putString("negative", composer.closeCancel); + ApptentiveAlertDialog.show(fragment, bundle, Constants.REQUEST_CODE_CLOSE_COMPOSING_CONFIRMATION); + } + } + }); + + // Use a color state list for button tint state on Lollipop. On prior platforms, need to apply state color manually. + Drawable sendButtonDrawable = DrawableCompat.wrap(sendButton.getDrawable()); + DrawableCompat.setTintList(sendButtonDrawable, colors); + sendButton.setImageDrawable(sendButtonDrawable); + if (Build.VERSION.SDK_INT < Build.VERSION_CODES.LOLLIPOP) { + sendButton.setColorFilter(Util.getThemeColor(fragment.getContext(), R.attr.apptentiveButtonTintColorDisabled)); + } + sendButton.setEnabled(false); + sendButton.setContentDescription(composer.sendButton); + sendButton.setOnClickListener(new View.OnClickListener() { + public void onClick(View view) { +/* TODO + MessageAdapter.OnListviewItemActionListener locallistener = listenerRef.get(); + if (locallistener == null) { + return; + } + locallistener.onFinishComposing(); +*/ + } + }); + + // Use a color state list for button tint state on Lollipop. On prior platforms, need to apply state color manually. + Drawable attachButtonDrawable = DrawableCompat.wrap(attachButton.getDrawable()); + DrawableCompat.setTintList(attachButtonDrawable, colors); + attachButton.setImageDrawable(attachButtonDrawable); + + attachButton.setOnClickListener(new View.OnClickListener() { + public void onClick(View view) { +/* TODO + MessageAdapter.OnListviewItemActionListener locallistener = listenerRef.get(); + if (locallistener == null) { + return; + } + locallistener.onAttachImage(); +*/ + } + }); + + ////// + message.setHint(composer.messageHint); + message.setLinksClickable(true); + message.setAutoLinkMask(Linkify.WEB_URLS | Linkify.PHONE_NUMBERS | Linkify.EMAIL_ADDRESSES | Linkify.MAP_ADDRESSES); + /* + * LinkMovementMethod would enable clickable links in EditView, but disables copy/paste through Long Press. + * Use a custom MovementMethod instead + * + */ + message.setMovementMethod(ApptentiveMovementMethod.getInstance()); + //If the edit text contains previous text with potential links + Linkify.addLinks(message, Linkify.WEB_URLS); + + message.addTextChangedListener(new TextWatcher() { + @Override + public void beforeTextChanged(CharSequence charSequence, int i, int i2, int i3) { +// listener.beforeComposingTextChanged(charSequence); + } + + @Override + public void onTextChanged(CharSequence charSequence, int start, int before, int count) { +// listener.onComposingTextChanged(charSequence); + } + + @Override + public void afterTextChanged(Editable editable) { +// listener.afterComposingTextChanged(editable.toString()); + Linkify.addLinks(editable, Linkify.WEB_URLS | Linkify.PHONE_NUMBERS | Linkify.EMAIL_ADDRESSES | Linkify.MAP_ADDRESSES); + } + }); + + +// attachments = (ApptentiveImageGridView) parentView.findViewById(R.id.grid); + attachments.setupUi(); + attachments.setupLayoutListener(); + attachments.setListener(new ApptentiveImageGridView.ImageItemClickedListener() { + @Override + public void onClick(int position, ImageItem image) { +// listener.onClickAttachment(position, image); + } + }); + attachments.setAdapterIndicator(R.drawable.apptentive_ic_remove_attachment); + +// attachments.setImageIndicatorCallback((ImageGridViewAdapter.Callback) listener); + // Initialize image attachments band with empty data +// clearImageAttachmentBand(); + } + + /* + * Extends Android default movement method to enable selecting text and openning the links at the same time + */ + private static class ApptentiveMovementMethod extends ArrowKeyMovementMethod { + + private static ApptentiveMovementMethod sInstance; + + public static MovementMethod getInstance() { + if (sInstance == null) { + sInstance = new ApptentiveMovementMethod(); + } + return sInstance; + } + + @Override + public boolean onTouchEvent(TextView widget, Spannable buffer, MotionEvent event) { + int action = event.getAction(); + if (action == MotionEvent.ACTION_UP || + action == MotionEvent.ACTION_DOWN) { + int x = (int) event.getX(); + int y = (int) event.getY(); + x -= widget.getTotalPaddingLeft(); + y -= widget.getTotalPaddingTop(); + x += widget.getScrollX(); + y += widget.getScrollY(); + Layout layout = widget.getLayout(); + int line = layout.getLineForVertical(y); + int off = layout.getOffsetForHorizontal(line, x); + ClickableSpan[] link = buffer.getSpans(off, off, ClickableSpan.class); + if (link.length != 0) { + if (action == MotionEvent.ACTION_UP) { + link[0].onClick(widget); + } else if (action == MotionEvent.ACTION_DOWN) { + Selection.setSelection(buffer, buffer.getSpanStart(link[0]), buffer.getSpanEnd(link[0])); + } + return true; + } + } + return super.onTouchEvent(widget, buffer, event); + } + } +} diff --git a/apptentive/src/main/java/com/apptentive/android/sdk/module/messagecenter/view/holder/MessageHolder.java b/apptentive/src/main/java/com/apptentive/android/sdk/module/messagecenter/view/holder/MessageHolder.java index 703784235..82dc2028f 100644 --- a/apptentive/src/main/java/com/apptentive/android/sdk/module/messagecenter/view/holder/MessageHolder.java +++ b/apptentive/src/main/java/com/apptentive/android/sdk/module/messagecenter/view/holder/MessageHolder.java @@ -1,50 +1,31 @@ /* - * Copyright (c) 2015, Apptentive, Inc. All Rights Reserved. + * Copyright (c) 2016, Apptentive, Inc. All Rights Reserved. * Please refer to the LICENSE file for the terms and conditions * under which redistribution and use of this file is permitted. */ package com.apptentive.android.sdk.module.messagecenter.view.holder; +import android.support.v7.widget.RecyclerView; import android.text.TextUtils; import android.view.View; import android.widget.TextView; import com.apptentive.android.sdk.R; -import com.apptentive.android.sdk.module.messagecenter.view.MessageView; +import com.apptentive.android.sdk.module.messagecenter.model.CompoundMessage; +import com.apptentive.android.sdk.util.Util; -/** - * @author Sky Kelsey - */ -public class MessageHolder extends MessageCenterListItemHolder { +public abstract class MessageHolder extends RecyclerView.ViewHolder { public TextView datestamp; - public TextView status; - - public MessageHolder(MessageView view) { - datestamp = (TextView) view.findViewById(R.id.datestamp); - status = (TextView) view.findViewById(R.id.status); + public MessageHolder(View itemView) { + super(itemView); + datestamp = (TextView) itemView.findViewById(R.id.datestamp); } - public void updateMessage(final String datestampString, final int statusColor, final String statusString) { - if (datestamp != null) { - datestamp.post(new Runnable() { - @Override - public void run() { - datestamp.setText(datestampString); - datestamp.setVisibility(!TextUtils.isEmpty(datestampString) ? View.VISIBLE : View.GONE); - } - }); - } - if (status != null) { - status.post(new Runnable() { - @Override - public void run() { - status.setText(statusString); - status.setTextColor(statusColor); - status.setVisibility(!TextUtils.isEmpty(statusString) ? View.VISIBLE : View.GONE); - } - }); - } + public void bindView(RecyclerView recyclerView, CompoundMessage message) { // final String datestampString, final int statusColor, final String statusString) { + String datestampString = message.getDatestamp(); + datestamp.setText(datestampString); + datestamp.setVisibility(!TextUtils.isEmpty(datestampString) ? View.VISIBLE : View.GONE); } } diff --git a/apptentive/src/main/java/com/apptentive/android/sdk/module/messagecenter/view/holder/OutgoingCompoundMessageHolder.java b/apptentive/src/main/java/com/apptentive/android/sdk/module/messagecenter/view/holder/OutgoingCompoundMessageHolder.java index a74bd325b..4f4236a57 100644 --- a/apptentive/src/main/java/com/apptentive/android/sdk/module/messagecenter/view/holder/OutgoingCompoundMessageHolder.java +++ b/apptentive/src/main/java/com/apptentive/android/sdk/module/messagecenter/view/holder/OutgoingCompoundMessageHolder.java @@ -1,17 +1,20 @@ /* - * Copyright (c) 2015, Apptentive, Inc. All Rights Reserved. + * Copyright (c) 2016, Apptentive, Inc. All Rights Reserved. * Please refer to the LICENSE file for the terms and conditions * under which redistribution and use of this file is permitted. */ package com.apptentive.android.sdk.module.messagecenter.view.holder; +import android.support.v7.widget.RecyclerView; +import android.text.TextUtils; import android.view.View; import android.widget.TextView; import com.apptentive.android.sdk.R; import com.apptentive.android.sdk.model.StoredFile; -import com.apptentive.android.sdk.module.messagecenter.view.CompoundMessageView; +import com.apptentive.android.sdk.module.messagecenter.model.CompoundMessage; +import com.apptentive.android.sdk.util.Util; import com.apptentive.android.sdk.util.image.ApptentiveImageGridView; import com.apptentive.android.sdk.util.image.ImageItem; import com.apptentive.android.sdk.view.ApptentiveMaterialIndeterminateProgressBar; @@ -19,52 +22,93 @@ import java.util.ArrayList; import java.util.List; - public class OutgoingCompoundMessageHolder extends MessageHolder { + + public View root; + public View container; public ApptentiveMaterialIndeterminateProgressBar progressBar; public TextView messageBodyView; - private ApptentiveImageGridView imageBandView; + public ApptentiveImageGridView imageBandView; + public TextView status; - public OutgoingCompoundMessageHolder(CompoundMessageView view) { - super(view); - progressBar = (ApptentiveMaterialIndeterminateProgressBar) view.findViewById(R.id.progressBar); - messageBodyView = (TextView) view.findViewById(R.id.apptentive_compound_message_body); - imageBandView = (ApptentiveImageGridView) view.findViewById(R.id.grid); + public OutgoingCompoundMessageHolder(View itemView) { + super(itemView); + root = itemView.findViewById(R.id.message_root); + container = itemView.findViewById(R.id.apptentive_compound_message_body_container); + progressBar = (ApptentiveMaterialIndeterminateProgressBar) itemView.findViewById(R.id.progressBar); + messageBodyView = (TextView) itemView.findViewById(R.id.apptentive_compound_message_body); + imageBandView = (ApptentiveImageGridView) itemView.findViewById(R.id.grid); + status = (TextView) itemView.findViewById(R.id.status); } - public void updateMessage(String datestamp, String status, int statusColor, - boolean progressBarVisible, final String body, final int viewWidth, final int desiredColumn, final List imagesToAttach) { - super.updateMessage(datestamp, statusColor, status); - if (progressBar != null) { - if (progressBarVisible) { - progressBar.start(); - progressBar.setVisibility(View.VISIBLE); - } else { - progressBar.stop(); - progressBar.setVisibility(View.GONE); - } + public void bindView(final RecyclerView recyclerView, final CompoundMessage message) { + super.bindView(recyclerView, message); + imageBandView.setupUi(); + messageBodyView.setText(message.getBody()); + + boolean isPaused = false; //TODO + boolean showProgress; + Double createdAt = message.getCreatedAt(); + String statusText; + if (createdAt == null || createdAt > Double.MIN_VALUE) { + // show progress bar if: 1. no sent time set, and 2. not paused, and 3. have either text or files to sent + showProgress = createdAt == null && !isPaused && (message.getAssociatedFiles() != null || !TextUtils.isEmpty(message.getBody())); + statusText = createStatus(createdAt, message.isLastSent()); + } else { + showProgress = false; + statusText = itemView.getResources().getString(R.string.apptentive_failed); } - if (messageBodyView != null) { - messageBodyView.post(new Runnable() { - @Override - public void run() { - messageBodyView.setText(body); - } - }); + + + if (showProgress) { + progressBar.start(); + progressBar.setVisibility(View.VISIBLE); + } else { + progressBar.stop(); + progressBar.setVisibility(View.GONE); + } + + List files = message.getAssociatedFiles(); + int imagebandWidth = 0; + if (files != null && files.size() > 0) { + int widthMeasureSpec = View.MeasureSpec.makeMeasureSpec(recyclerView.getWidth(), View.MeasureSpec.EXACTLY); + root.measure(widthMeasureSpec, 0); + int viewWidth = container.getMeasuredWidth(); + imagebandWidth = viewWidth - container.getPaddingLeft() - container.getPaddingRight(); } - // Set up attachments view - if (imageBandView != null) { - if (imagesToAttach == null || imagesToAttach.size() == 0) { - imageBandView.setVisibility(View.GONE); - } else { - imageBandView.setVisibility(View.VISIBLE); - imageBandView.setAdapterItemSize(viewWidth, desiredColumn); - List images = new ArrayList(); - for (StoredFile file : imagesToAttach) { - images.add(new ImageItem(file.getSourceUriOrPath(), file.getLocalFilePath(), file.getMimeType(), file.getCreationTime())); - } - imageBandView.setData(images); + + if (files == null || files.size() == 0) { + imageBandView.setVisibility(View.GONE); + } else { + imageBandView.setVisibility(View.VISIBLE); + imageBandView.setAdapterItemSize(imagebandWidth, itemView.getResources().getInteger(R.integer.apptentive_image_grid_default_column_number)); + List images = new ArrayList(); + for (StoredFile file : files) { + images.add(new ImageItem(file.getSourceUriOrPath(), file.getLocalFilePath(), file.getMimeType(), file.getCreationTime())); } + imageBandView.setData(images); } + + status.setText(statusText); + status.setTextColor(getStatusColor(createdAt, isPaused)); + status.setVisibility(!TextUtils.isEmpty(statusText) ? View.VISIBLE : View.GONE); + } + + protected String createStatus(Double seconds, boolean showSent) { + if (seconds == null) { + boolean isInPauseState = false; // TODO + return isInPauseState ? itemView.getResources().getString(R.string.apptentive_failed) : null; + } + return (showSent) ? itemView.getResources().getString(R.string.apptentive_sent) : null; } + + protected int getStatusColor(Double seconds, boolean isPaused) { + if (seconds == null) { + // failed color (red) + return isPaused ? Util.getThemeColor(itemView.getContext(), R.attr.apptentiveValidationFailedColor) : 0; + } + // other status color + return Util.getThemeColor(itemView.getContext(), android.R.attr.textColorSecondary); + } + } \ No newline at end of file diff --git a/apptentive/src/main/java/com/apptentive/android/sdk/module/messagecenter/view/holder/StatusHolder.java b/apptentive/src/main/java/com/apptentive/android/sdk/module/messagecenter/view/holder/StatusHolder.java index 10604c82b..d59ce11d8 100644 --- a/apptentive/src/main/java/com/apptentive/android/sdk/module/messagecenter/view/holder/StatusHolder.java +++ b/apptentive/src/main/java/com/apptentive/android/sdk/module/messagecenter/view/holder/StatusHolder.java @@ -1,54 +1,25 @@ /* - * Copyright (c) 2015, Apptentive, Inc. All Rights Reserved. + * Copyright (c) 2016, Apptentive, Inc. All Rights Reserved. * Please refer to the LICENSE file for the terms and conditions * under which redistribution and use of this file is permitted. */ package com.apptentive.android.sdk.module.messagecenter.view.holder; +import android.support.v7.widget.RecyclerView; import android.view.View; import android.widget.ImageView; import android.widget.TextView; import com.apptentive.android.sdk.R; -import com.apptentive.android.sdk.module.messagecenter.view.MessageCenterStatusView; -/** - * @author Sky Kelsey - */ -public class StatusHolder extends MessageCenterListItemHolder { - private TextView body; - private ImageView icon; - - public StatusHolder(MessageCenterStatusView view) { - body = (TextView) view.findViewById(R.id.status_body); - icon = (ImageView) view.findViewById(R.id.icon); - } - - public void updateMessage(final String bodyText, Integer iconRes) { - if (body != null && body != null) { - body.post(new Runnable() { - @Override - public void run() { - body.setVisibility(TextView.VISIBLE); - body.setText(bodyText); - } - }); +public class StatusHolder extends RecyclerView.ViewHolder { + public TextView body; + public ImageView icon; - } else { - body.post(new Runnable() { - @Override - public void run() { - body.setVisibility(View.GONE); - } - }); - } - if (icon != null && iconRes != null) { - icon.setImageResource(iconRes); - icon.setVisibility(View.VISIBLE); - } - else { - icon.setVisibility(View.GONE); - } + public StatusHolder(View itemView) { + super(itemView); + body = (TextView) itemView.findViewById(R.id.status_body); + icon = (ImageView) itemView.findViewById(R.id.icon); } } diff --git a/apptentive/src/main/java/com/apptentive/android/sdk/module/messagecenter/view/holder/WhoCardHolder.java b/apptentive/src/main/java/com/apptentive/android/sdk/module/messagecenter/view/holder/WhoCardHolder.java new file mode 100644 index 000000000..649596104 --- /dev/null +++ b/apptentive/src/main/java/com/apptentive/android/sdk/module/messagecenter/view/holder/WhoCardHolder.java @@ -0,0 +1,110 @@ +/* + * Copyright (c) 2016, Apptentive, Inc. All Rights Reserved. + * Please refer to the LICENSE file for the terms and conditions + * under which redistribution and use of this file is permitted. + */ + +package com.apptentive.android.sdk.module.messagecenter.view.holder; + +import android.support.design.widget.TextInputLayout; +import android.support.v7.widget.RecyclerView; +import android.text.Editable; +import android.text.TextUtils; +import android.text.TextWatcher; +import android.view.View; +import android.widget.Button; +import android.widget.EditText; +import android.widget.TextView; + +import com.apptentive.android.sdk.R; +import com.apptentive.android.sdk.module.messagecenter.model.WhoCard; +import com.apptentive.android.sdk.util.Util; + +public class WhoCardHolder extends RecyclerView.ViewHolder { + private TextView title; + private TextInputLayout nameLayout; + private EditText nameEditText; + private TextInputLayout emailLayout; + private EditText emailEditText; + private TextView emailExplanation; + private Button skipButton; + private Button saveButton; + + public WhoCardHolder(View itemView) { + super(itemView); + title = (TextView) itemView.findViewById(R.id.who_title); + nameEditText = (EditText) itemView.findViewById(R.id.who_name); + nameLayout = (TextInputLayout) itemView.findViewById(R.id.input_layout_who_name); + emailEditText = (EditText) itemView.findViewById(R.id.who_email); + emailLayout = (TextInputLayout) itemView.findViewById(R.id.input_layout_who_email); + emailExplanation = (TextView) itemView.findViewById(R.id.email_explanation); + skipButton = (Button) itemView.findViewById(R.id.btn_skip); + saveButton = (Button) itemView.findViewById(R.id.btn_send); + } + + public void bindView(RecyclerView recyclerView, final WhoCard whoCard) { + + title.setText(whoCard.getTitle()); + nameLayout.setHint(whoCard.getNameHint()); + emailExplanation.setText(whoCard.getEmailExplanation()); + emailLayout.setHint(whoCard.getEmailHint()); + skipButton.setText(whoCard.getSkipButton()); + saveButton.setText(whoCard.getSaveButton()); + + TextWatcher emailTextWatcher = new TextWatcher() { + @Override + public void beforeTextChanged(CharSequence existingContent, int i, int i2, int i3) { + // Disable send button when the content hasn't change yet + if (Util.isEmailValid(existingContent.toString())) { + saveButton.setEnabled(true); + } else { + saveButton.setEnabled(false); + } + } + + @Override + public void onTextChanged(CharSequence charSequence, int start, int before, int count) { + } + + @Override + public void afterTextChanged(Editable editable) { + String emailContent = editable.toString().trim(); + if (Util.isEmailValid(emailContent)) { + // email must be in valid format after the change. If it is, enable send button + saveButton.setEnabled(true); + } else + // Allow user remove email completely when editing profile of "Email Requested" + if (TextUtils.isEmpty(emailContent) && !whoCard.isRequire()) { + saveButton.setEnabled(true); + } else { + // email not valid after change, so disable the send button + saveButton.setEnabled(false); + } + } + }; + emailEditText.addTextChangedListener(emailTextWatcher); + + // TODO: Prepopulate with name and email if we already have them. +/* + emailEditText.setText(email); + nameEditText.setText(name); +*/ + /* // TODO: Hook up listeners + skipButton.setOnClickListener(new View.OnClickListener() { + public void onClick(View view) { + listener.onCloseWhoCard(item.button_1); + } + }); + + sendButton.setOnClickListener(new View.OnClickListener() { + public void onClick(View view) { + if (isWhoCardContentValid(item.getType())) { + Apptentive.setPersonEmail(emailEditText.getText().toString().trim()); + Apptentive.setPersonName(nameEditText.getText().toString().trim()); + listener.onSubmitWhoCard(item.button_2); + } + } + }); +*/ + } +} diff --git a/apptentive/src/main/java/com/apptentive/android/sdk/view/ApptentiveAlertDialog.java b/apptentive/src/main/java/com/apptentive/android/sdk/view/ApptentiveAlertDialog.java index b67410637..477337df4 100644 --- a/apptentive/src/main/java/com/apptentive/android/sdk/view/ApptentiveAlertDialog.java +++ b/apptentive/src/main/java/com/apptentive/android/sdk/view/ApptentiveAlertDialog.java @@ -72,6 +72,7 @@ public Dialog onCreateDialog(Bundle savedInstanceState) { @Override public void onClick(View v) { dismiss(); + // TODO getTargetFragment().onActivityResult(getTargetRequestCode(), Activity.RESULT_OK, getActivity().getIntent()); } }); diff --git a/apptentive/src/main/res/layout/apptentive_message_center.xml b/apptentive/src/main/res/layout/apptentive_message_center.xml index 99d3b2ec0..d4176a8e2 100644 --- a/apptentive/src/main/res/layout/apptentive_message_center.xml +++ b/apptentive/src/main/res/layout/apptentive_message_center.xml @@ -7,22 +7,22 @@ --> - + android:layout_width="match_parent" + android:layout_height="match_parent" + android:background="?attr/apptentiveViewBackground"> + + android:layout_width="wrap_content" + android:layout_height="wrap_content" + style="?attr/apptentiveFabStyle" + android:src="@drawable/apptentive_ic_compose"/> \ No newline at end of file diff --git a/apptentive/src/main/res/layout/apptentive_message_center_composer.xml b/apptentive/src/main/res/layout/apptentive_message_center_composer.xml new file mode 100644 index 000000000..d68f0ce81 --- /dev/null +++ b/apptentive/src/main/res/layout/apptentive_message_center_composer.xml @@ -0,0 +1,96 @@ + + + + + + + + + + + + + + + + + diff --git a/apptentive/src/main/res/layout/apptentive_message_incoming.xml b/apptentive/src/main/res/layout/apptentive_message_incoming.xml index 38e419208..7fee2a2f2 100644 --- a/apptentive/src/main/res/layout/apptentive_message_incoming.xml +++ b/apptentive/src/main/res/layout/apptentive_message_incoming.xml @@ -7,6 +7,7 @@ --> diff --git a/apptentive/src/main/res/layout/apptentive_message_outgoing.xml b/apptentive/src/main/res/layout/apptentive_message_outgoing.xml index 13295607d..8e7db29e2 100644 --- a/apptentive/src/main/res/layout/apptentive_message_outgoing.xml +++ b/apptentive/src/main/res/layout/apptentive_message_outgoing.xml @@ -7,6 +7,7 @@ --> From 6d688f6cd5decc7cfce11bf90e86eba43d326f93 Mon Sep 17 00:00:00 2001 From: skykelsey Date: Sun, 30 Oct 2016 16:31:54 -0700 Subject: [PATCH 008/100] Start hooking the Message Center listeners back up. Start with Message Composer. --- .../fragment/MessageCenterFragment.java | 26 ++++--- .../MessageCenterRecyclerViewAdapter.java | 27 ++++--- .../view/holder/MessageComposerHolder.java | 75 +++++++++++-------- 3 files changed, 75 insertions(+), 53 deletions(-) diff --git a/apptentive/src/main/java/com/apptentive/android/sdk/module/engagement/interaction/fragment/MessageCenterFragment.java b/apptentive/src/main/java/com/apptentive/android/sdk/module/engagement/interaction/fragment/MessageCenterFragment.java index fa293e89b..cdc1e7aa7 100644 --- a/apptentive/src/main/java/com/apptentive/android/sdk/module/engagement/interaction/fragment/MessageCenterFragment.java +++ b/apptentive/src/main/java/com/apptentive/android/sdk/module/engagement/interaction/fragment/MessageCenterFragment.java @@ -430,7 +430,7 @@ else if (pendingWhoCardName != null || pendingWhoCardEmail != null || pendingWho } - messageCenterRecyclerViewAdapter = new MessageCenterRecyclerViewAdapter(this, interaction, messages); + messageCenterRecyclerViewAdapter = new MessageCenterRecyclerViewAdapter(this, this, interaction, messages); messageCenterRecyclerView.setAdapter(messageCenterRecyclerViewAdapter); /* @@ -917,8 +917,9 @@ public void clearComposingUi(Animator.AnimatorListener al, ValueAnimator.Animato } } -// @Override + @Override public void updateComposingBar() { +/* TODO: What do we save here? if (messageCenterRecyclerViewAdapter != null) { MessageCenterComposingActionBarView barView = messageCenterRecyclerViewAdapter.getComposingActionBarView(); if (barView != null) { @@ -951,9 +952,10 @@ public void updateComposingBar() { } } } +*/ } -// @Override + @Override public void onComposingViewCreated(View keyboardFocusedOnView) { hideProfileButton(); @@ -1026,7 +1028,7 @@ public void onComposingViewCreated(View keyboardFocusedOnView) { } } -// @Override + @Override public void onWhoCardViewCreated(EditText nameEditText, EditText emailEditText, View viewFocusedWithKeyboard) { if (pendingWhoCardName != null) { nameEditText.onRestoreInstanceState(pendingWhoCardName); @@ -1043,22 +1045,22 @@ public void onWhoCardViewCreated(EditText nameEditText, EditText emailEditText, } } -// @Override + @Override public void beforeComposingTextChanged(CharSequence str) { } -// @Override + @Override public void onComposingTextChanged(CharSequence str) { } -// @Override + @Override public void afterComposingTextChanged(String str) { // Update display status of composing bar buttons when composing text changes updateComposingBar(); } -// @Override + @Override public void onCancelComposing() { if (messageCenterRecyclerViewAdapter != null) { messageCenterRecyclerViewAdapter.setForceShowKeyboard(false); @@ -1115,7 +1117,7 @@ public void onAnimationCancel(Animator animation) { //clearComposingUi(null, null, 0); } -// @Override + @Override public void onFinishComposing() { if (messageCenterRecyclerViewAdapter != null) { messageCenterRecyclerViewAdapter.setForceShowKeyboard(false); @@ -1176,7 +1178,7 @@ public void onAnimationCancel(Animator animation) { DEFAULT_DELAYMILLIS); } -// @Override + @Override public void onSubmitWhoCard(String buttonLabel) { JSONObject data = new JSONObject(); try { @@ -1190,7 +1192,7 @@ public void onSubmitWhoCard(String buttonLabel) { cleanupWhoCard(); } -// @Override + @Override public void onCloseWhoCard(String buttonLabel) { JSONObject data = new JSONObject(); try { @@ -1312,7 +1314,7 @@ public void OnListViewResize(int w, int h, int oldw, int oldh) { /* Callback when the attach button is clicked * */ -// @Override + @Override public void onAttachImage() { try { if (Build.VERSION.SDK_INT < Build.VERSION_CODES.KITKAT) {//prior Api level 19 diff --git a/apptentive/src/main/java/com/apptentive/android/sdk/module/messagecenter/view/MessageCenterRecyclerViewAdapter.java b/apptentive/src/main/java/com/apptentive/android/sdk/module/messagecenter/view/MessageCenterRecyclerViewAdapter.java index 6d143bd84..948ad41f5 100644 --- a/apptentive/src/main/java/com/apptentive/android/sdk/module/messagecenter/view/MessageCenterRecyclerViewAdapter.java +++ b/apptentive/src/main/java/com/apptentive/android/sdk/module/messagecenter/view/MessageCenterRecyclerViewAdapter.java @@ -8,10 +8,7 @@ import android.os.Parcel; import android.os.Parcelable; -import android.preference.PreferenceManager; -import android.support.v4.app.Fragment; import android.support.v7.widget.RecyclerView; -import android.text.TextUtils; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; @@ -19,11 +16,10 @@ import com.apptentive.android.sdk.ApptentiveLog; import com.apptentive.android.sdk.R; -import com.apptentive.android.sdk.model.StoredFile; +import com.apptentive.android.sdk.module.engagement.interaction.fragment.MessageCenterFragment; import com.apptentive.android.sdk.module.engagement.interaction.model.Interaction; import com.apptentive.android.sdk.module.messagecenter.model.Composer; import com.apptentive.android.sdk.module.messagecenter.model.CompoundMessage; -import com.apptentive.android.sdk.module.messagecenter.model.MessageCenterComposingItem; import com.apptentive.android.sdk.module.messagecenter.model.MessageCenterGreeting; import com.apptentive.android.sdk.module.messagecenter.model.MessageCenterStatus; import com.apptentive.android.sdk.module.messagecenter.model.MessageCenterUtil; @@ -36,9 +32,7 @@ import com.apptentive.android.sdk.module.messagecenter.view.holder.StatusHolder; import com.apptentive.android.sdk.module.messagecenter.view.holder.WhoCardHolder; import com.apptentive.android.sdk.util.image.ImageItem; -import com.apptentive.android.sdk.util.image.ImageUtil; -import java.util.ArrayList; import java.util.List; import static com.apptentive.android.sdk.module.messagecenter.model.MessageCenterUtil.MessageCenterListItem.GREETING; @@ -51,13 +45,15 @@ public class MessageCenterRecyclerViewAdapter extends RecyclerView.Adapter { - Fragment fragment; + MessageCenterFragment fragment; + MessageAdapter.OnListviewItemActionListener listener; RecyclerView recyclerView; Interaction interaction; List messages; - public MessageCenterRecyclerViewAdapter(Fragment fragment, Interaction interaction, List messages) { + public MessageCenterRecyclerViewAdapter(MessageCenterFragment fragment, MessageAdapter.OnListviewItemActionListener listener, Interaction interaction, List messages) { this.fragment = fragment; + this.listener = listener; this.interaction = interaction; this.messages = messages; } @@ -126,7 +122,7 @@ public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) { ApptentiveLog.e("-> Message Composer"); Composer composer = (Composer) messages.get(position); MessageComposerHolder composerHolder = (MessageComposerHolder) holder; - composerHolder.bindView(fragment, composer); + composerHolder.bindView(fragment, this, composer); break; } case STATUS: { @@ -181,6 +177,13 @@ public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) { } } + @Override + public void onViewRecycled(RecyclerView.ViewHolder holder) { + super.onViewRecycled(holder); + ApptentiveLog.e("View recycled: %s", holder.toString()); + // TODO: Remove listeners, and clean up here? + } + @Override public int getItemCount() { return messages.size(); @@ -265,4 +268,8 @@ public void clearComposing() { public EditText getEditTextInComposing() { return new EditText(fragment.getContext()); // TODO } + + public MessageAdapter.OnListviewItemActionListener getListener() { + return listener; + } } diff --git a/apptentive/src/main/java/com/apptentive/android/sdk/module/messagecenter/view/holder/MessageComposerHolder.java b/apptentive/src/main/java/com/apptentive/android/sdk/module/messagecenter/view/holder/MessageComposerHolder.java index 051a8c92e..a67e87a64 100644 --- a/apptentive/src/main/java/com/apptentive/android/sdk/module/messagecenter/view/holder/MessageComposerHolder.java +++ b/apptentive/src/main/java/com/apptentive/android/sdk/module/messagecenter/view/holder/MessageComposerHolder.java @@ -10,7 +10,6 @@ import android.graphics.drawable.Drawable; import android.os.Build; import android.os.Bundle; -import android.support.v4.app.Fragment; import android.support.v4.content.ContextCompat; import android.support.v4.graphics.drawable.DrawableCompat; import android.support.v7.widget.RecyclerView; @@ -18,6 +17,7 @@ import android.text.Layout; import android.text.Selection; import android.text.Spannable; +import android.text.TextUtils; import android.text.TextWatcher; import android.text.method.ArrowKeyMovementMethod; import android.text.method.MovementMethod; @@ -30,20 +30,19 @@ import android.widget.TextView; import com.apptentive.android.sdk.R; +import com.apptentive.android.sdk.module.engagement.interaction.fragment.MessageCenterFragment; import com.apptentive.android.sdk.module.messagecenter.model.Composer; -import com.apptentive.android.sdk.module.messagecenter.view.MessageAdapter; -import com.apptentive.android.sdk.module.messagecenter.view.MessageCenterComposingView; +import com.apptentive.android.sdk.module.messagecenter.view.MessageCenterRecyclerViewAdapter; import com.apptentive.android.sdk.util.Constants; import com.apptentive.android.sdk.util.Util; import com.apptentive.android.sdk.util.image.ApptentiveImageGridView; -import com.apptentive.android.sdk.util.image.ImageGridViewAdapter; import com.apptentive.android.sdk.util.image.ImageItem; import com.apptentive.android.sdk.view.ApptentiveAlertDialog; public class MessageComposerHolder extends RecyclerView.ViewHolder { - public ImageButton cancelButton; + public ImageButton closeButton; public TextView title; public ImageButton attachButton; public ImageButton sendButton; @@ -52,7 +51,7 @@ public class MessageComposerHolder extends RecyclerView.ViewHolder { public MessageComposerHolder(View itemView) { super(itemView); - cancelButton = (ImageButton) itemView.findViewById(R.id.cancel_composing); + closeButton = (ImageButton) itemView.findViewById(R.id.cancel_composing); title = (TextView) itemView.findViewById(R.id.title); attachButton = (ImageButton) itemView.findViewById(R.id.btn_attach_image); sendButton = (ImageButton) itemView.findViewById(R.id.btn_send_message); @@ -60,13 +59,11 @@ public MessageComposerHolder(View itemView) { attachments = (ApptentiveImageGridView) itemView.findViewById(R.id.grid); } - public void bindView(final Fragment fragment, final Composer composer) { + public void bindView(final MessageCenterFragment fragment, final MessageCenterRecyclerViewAdapter adapter, final Composer composer) { title.setText(composer.title); -////// ColorStateList colors = ContextCompat.getColorStateList(itemView.getContext(), Util.getResourceIdFromAttribute(itemView.getContext().getTheme(), R.attr.apptentiveButtonTintColorStateList)); - ImageButton closeButton = (ImageButton) itemView.findViewById(R.id.cancel_composing); // Use a color state list for button tint state on Lollipop. On prior platforms, need to apply state color manually. Drawable closeButtonDrawable = DrawableCompat.wrap(closeButton.getDrawable()); DrawableCompat.setTintList(closeButtonDrawable, colors); @@ -74,12 +71,16 @@ public void bindView(final Fragment fragment, final Composer composer) { closeButton.setOnClickListener(new View.OnClickListener() { public void onClick(View view) { - if (message.getText().length() > 0) { + if (!TextUtils.isEmpty(message.getText())) { Bundle bundle = new Bundle(); bundle.putString("message", composer.closeBody); bundle.putString("positive", composer.closeDiscard); bundle.putString("negative", composer.closeCancel); ApptentiveAlertDialog.show(fragment, bundle, Constants.REQUEST_CODE_CLOSE_COMPOSING_CONFIRMATION); + } else { + if (adapter.getListener() != null) { + adapter.getListener().onCancelComposing(); + } } } }); @@ -88,20 +89,13 @@ public void onClick(View view) { Drawable sendButtonDrawable = DrawableCompat.wrap(sendButton.getDrawable()); DrawableCompat.setTintList(sendButtonDrawable, colors); sendButton.setImageDrawable(sendButtonDrawable); - if (Build.VERSION.SDK_INT < Build.VERSION_CODES.LOLLIPOP) { - sendButton.setColorFilter(Util.getThemeColor(fragment.getContext(), R.attr.apptentiveButtonTintColorDisabled)); - } - sendButton.setEnabled(false); + setSendButtonEnabled(false); sendButton.setContentDescription(composer.sendButton); sendButton.setOnClickListener(new View.OnClickListener() { public void onClick(View view) { -/* TODO - MessageAdapter.OnListviewItemActionListener locallistener = listenerRef.get(); - if (locallistener == null) { - return; + if (adapter.getListener() != null) { + adapter.getListener().onFinishComposing(); } - locallistener.onFinishComposing(); -*/ } }); @@ -112,17 +106,12 @@ public void onClick(View view) { attachButton.setOnClickListener(new View.OnClickListener() { public void onClick(View view) { -/* TODO - MessageAdapter.OnListviewItemActionListener locallistener = listenerRef.get(); - if (locallistener == null) { - return; + if (adapter.getListener() != null) { + adapter.getListener().onAttachImage(); } - locallistener.onAttachImage(); -*/ } }); - ////// message.setHint(composer.messageHint); message.setLinksClickable(true); message.setAutoLinkMask(Linkify.WEB_URLS | Linkify.PHONE_NUMBERS | Linkify.EMAIL_ADDRESSES | Linkify.MAP_ADDRESSES); @@ -138,17 +127,24 @@ public void onClick(View view) { message.addTextChangedListener(new TextWatcher() { @Override public void beforeTextChanged(CharSequence charSequence, int i, int i2, int i3) { -// listener.beforeComposingTextChanged(charSequence); + if (adapter.getListener() != null) { + adapter.getListener().beforeComposingTextChanged(charSequence); + } } @Override public void onTextChanged(CharSequence charSequence, int start, int before, int count) { -// listener.onComposingTextChanged(charSequence); + if (adapter.getListener() != null) { + adapter.getListener().onComposingTextChanged(charSequence); + } } @Override public void afterTextChanged(Editable editable) { -// listener.afterComposingTextChanged(editable.toString()); + if (adapter.getListener() != null) { + adapter.getListener().afterComposingTextChanged(editable.toString()); + } + setSendButtonEnabled(!TextUtils.isEmpty(message.getText())); Linkify.addLinks(editable, Linkify.WEB_URLS | Linkify.PHONE_NUMBERS | Linkify.EMAIL_ADDRESSES | Linkify.MAP_ADDRESSES); } }); @@ -160,7 +156,9 @@ public void afterTextChanged(Editable editable) { attachments.setListener(new ApptentiveImageGridView.ImageItemClickedListener() { @Override public void onClick(int position, ImageItem image) { -// listener.onClickAttachment(position, image); + if (adapter.getListener() != null) { + adapter.getListener().onClickAttachment(position, image); + } } }); attachments.setAdapterIndicator(R.drawable.apptentive_ic_remove_attachment); @@ -211,4 +209,19 @@ public boolean onTouchEvent(TextView widget, Spannable buffer, MotionEvent event return super.onTouchEvent(widget, buffer, event); } } + + private void setSendButtonEnabled(boolean enabled) { + if (sendButton.isEnabled() ^ enabled) { // No change required + sendButton.setEnabled(enabled); + if (enabled) { + if (Build.VERSION.SDK_INT < Build.VERSION_CODES.LOLLIPOP) { + sendButton.setColorFilter(Util.getThemeColor(itemView.getContext(), R.attr.apptentiveButtonTintColor)); + } + } else { + if (Build.VERSION.SDK_INT < Build.VERSION_CODES.LOLLIPOP) { + sendButton.setColorFilter(Util.getThemeColor(itemView.getContext(), R.attr.apptentiveButtonTintColorDisabled)); + } + } + } + } } From 9bcd705d51282d3f100b5f6b487a4d497732a9fd Mon Sep 17 00:00:00 2001 From: skykelsey Date: Sun, 30 Oct 2016 18:11:59 -0700 Subject: [PATCH 009/100] Start hooking up attachments --- .../fragment/MessageCenterFragment.java | 6 +- .../view/holder/MessageComposerHolder.java | 90 +++++++++++++++---- 2 files changed, 75 insertions(+), 21 deletions(-) diff --git a/apptentive/src/main/java/com/apptentive/android/sdk/module/engagement/interaction/fragment/MessageCenterFragment.java b/apptentive/src/main/java/com/apptentive/android/sdk/module/engagement/interaction/fragment/MessageCenterFragment.java index cdc1e7aa7..45b18a0a1 100644 --- a/apptentive/src/main/java/com/apptentive/android/sdk/module/engagement/interaction/fragment/MessageCenterFragment.java +++ b/apptentive/src/main/java/com/apptentive/android/sdk/module/engagement/interaction/fragment/MessageCenterFragment.java @@ -805,9 +805,6 @@ public void removeImageFromComposer(final int position) { messageCenterRecyclerViewAdapter.notifyDataSetChanged(); } messagingActionHandler.sendEmptyMessageDelayed(MSG_SCROLL_TO_BOTTOM, DEFAULT_DELAYMILLIS); - - updateComposingBar(); - } public void openNonImageAttachment(final ImageItem image) { @@ -1057,7 +1054,8 @@ public void onComposingTextChanged(CharSequence str) { @Override public void afterComposingTextChanged(String str) { // Update display status of composing bar buttons when composing text changes - updateComposingBar(); + // TODO: Save state here? + //updateComposingBar(); } @Override diff --git a/apptentive/src/main/java/com/apptentive/android/sdk/module/messagecenter/view/holder/MessageComposerHolder.java b/apptentive/src/main/java/com/apptentive/android/sdk/module/messagecenter/view/holder/MessageComposerHolder.java index a67e87a64..f17f99b24 100644 --- a/apptentive/src/main/java/com/apptentive/android/sdk/module/messagecenter/view/holder/MessageComposerHolder.java +++ b/apptentive/src/main/java/com/apptentive/android/sdk/module/messagecenter/view/holder/MessageComposerHolder.java @@ -39,9 +39,14 @@ import com.apptentive.android.sdk.util.image.ImageItem; import com.apptentive.android.sdk.view.ApptentiveAlertDialog; +import java.util.ArrayList; +import java.util.List; + public class MessageComposerHolder extends RecyclerView.ViewHolder { + List images; + public ImageButton closeButton; public TextView title; public ImageButton attachButton; @@ -51,6 +56,7 @@ public class MessageComposerHolder extends RecyclerView.ViewHolder { public MessageComposerHolder(View itemView) { super(itemView); + images = new ArrayList(); closeButton = (ImageButton) itemView.findViewById(R.id.cancel_composing); title = (TextView) itemView.findViewById(R.id.title); attachButton = (ImageButton) itemView.findViewById(R.id.btn_attach_image); @@ -99,19 +105,6 @@ public void onClick(View view) { } }); - // Use a color state list for button tint state on Lollipop. On prior platforms, need to apply state color manually. - Drawable attachButtonDrawable = DrawableCompat.wrap(attachButton.getDrawable()); - DrawableCompat.setTintList(attachButtonDrawable, colors); - attachButton.setImageDrawable(attachButtonDrawable); - - attachButton.setOnClickListener(new View.OnClickListener() { - public void onClick(View view) { - if (adapter.getListener() != null) { - adapter.getListener().onAttachImage(); - } - } - }); - message.setHint(composer.messageHint); message.setLinksClickable(true); message.setAutoLinkMask(Linkify.WEB_URLS | Linkify.PHONE_NUMBERS | Linkify.EMAIL_ADDRESSES | Linkify.MAP_ADDRESSES); @@ -150,7 +143,19 @@ public void afterTextChanged(Editable editable) { }); -// attachments = (ApptentiveImageGridView) parentView.findViewById(R.id.grid); + // Use a color state list for button tint state on Lollipop. On prior platforms, need to apply state color manually. + Drawable attachButtonDrawable = DrawableCompat.wrap(attachButton.getDrawable()); + DrawableCompat.setTintList(attachButtonDrawable, colors); + attachButton.setImageDrawable(attachButtonDrawable); + + attachButton.setOnClickListener(new View.OnClickListener() { + public void onClick(View view) { + if (adapter.getListener() != null) { + adapter.getListener().onAttachImage(); + } + } + }); + attachments.setupUi(); attachments.setupLayoutListener(); attachments.setListener(new ApptentiveImageGridView.ImageItemClickedListener() { @@ -163,9 +168,60 @@ public void onClick(int position, ImageItem image) { }); attachments.setAdapterIndicator(R.drawable.apptentive_ic_remove_attachment); -// attachments.setImageIndicatorCallback((ImageGridViewAdapter.Callback) listener); - // Initialize image attachments band with empty data -// clearImageAttachmentBand(); + attachments.setImageIndicatorCallback(fragment); + //Initialize image attachments band with empty data + clearImageAttachmentBand(); + } + + /** + * Remove all images from attchment band. + */ + public void clearImageAttachmentBand() { + attachments.setVisibility(View.GONE); + images.clear(); + attachments.setData(null); + } + + /** + * Add new images to attachment band. + * + * @param imagesToAttach an array of new images to add + */ + public void addImagesToImageAttachmentBand(final List imagesToAttach) { + + if (imagesToAttach == null || imagesToAttach.size() == 0) { + return; + } + + attachments.setupLayoutListener(); + attachments.setVisibility(View.VISIBLE); + + images.addAll(imagesToAttach); + addAdditionalAttachItem(); + } + + /** + * Remove an image from attchment band. + * + * @param position the postion index of the image to be removed + */ + public void removeImageFromImageAttachmentBand(final int position) { + images.remove(position); + attachments.setupLayoutListener(); + if (images.size() == 0) { + // Hide attachment band after last attachment is removed + attachments.setVisibility(View.GONE); + return; + } + addAdditionalAttachItem(); + } + + private void addAdditionalAttachItem() { + ArrayList imagesToAdd = new ArrayList(images); + if (imagesToAdd.size() < itemView.getResources().getInteger(R.integer.apptentive_image_grid_default_attachments_total)) { + imagesToAdd.add(new ImageItem("", "", "Image/*", 0)); + } + attachments.setData(imagesToAdd); } /* From 929cb83f9dc2d3c3f102ba282a85120e8a6cef2b Mon Sep 17 00:00:00 2001 From: skykelsey Date: Mon, 31 Oct 2016 16:01:08 -0700 Subject: [PATCH 010/100] Fix display of Context Message. --- .../fragment/MessageCenterFragment.java | 194 +++++++----------- .../messagecenter/model/CompoundMessage.java | 15 -- .../messagecenter/model/ContextMessage.java | 25 +++ .../MessageCenterRecyclerViewAdapter.java | 17 ++ .../view/holder/ContextMessageHolder.java | 28 +++ ...tentive_message_center_context_message.xml | 37 ++++ 6 files changed, 179 insertions(+), 137 deletions(-) create mode 100644 apptentive/src/main/java/com/apptentive/android/sdk/module/messagecenter/model/ContextMessage.java create mode 100644 apptentive/src/main/java/com/apptentive/android/sdk/module/messagecenter/view/holder/ContextMessageHolder.java create mode 100644 apptentive/src/main/res/layout/apptentive_message_center_context_message.xml diff --git a/apptentive/src/main/java/com/apptentive/android/sdk/module/engagement/interaction/fragment/MessageCenterFragment.java b/apptentive/src/main/java/com/apptentive/android/sdk/module/engagement/interaction/fragment/MessageCenterFragment.java index 45b18a0a1..1709d351f 100644 --- a/apptentive/src/main/java/com/apptentive/android/sdk/module/engagement/interaction/fragment/MessageCenterFragment.java +++ b/apptentive/src/main/java/com/apptentive/android/sdk/module/engagement/interaction/fragment/MessageCenterFragment.java @@ -52,13 +52,12 @@ import com.apptentive.android.sdk.module.messagecenter.model.ApptentiveMessage; import com.apptentive.android.sdk.module.messagecenter.model.Composer; import com.apptentive.android.sdk.module.messagecenter.model.CompoundMessage; -import com.apptentive.android.sdk.module.messagecenter.model.MessageCenterComposingItem; +import com.apptentive.android.sdk.module.messagecenter.model.ContextMessage; import com.apptentive.android.sdk.module.messagecenter.model.MessageCenterStatus; import com.apptentive.android.sdk.module.messagecenter.model.MessageCenterUtil; import com.apptentive.android.sdk.module.messagecenter.model.WhoCard; import com.apptentive.android.sdk.module.messagecenter.view.AttachmentPreviewDialog; import com.apptentive.android.sdk.module.messagecenter.view.MessageAdapter; -import com.apptentive.android.sdk.module.messagecenter.view.MessageCenterComposingActionBarView; import com.apptentive.android.sdk.module.messagecenter.view.MessageCenterListView; import com.apptentive.android.sdk.module.messagecenter.view.MessageCenterRecyclerView; import com.apptentive.android.sdk.module.messagecenter.view.MessageCenterRecyclerViewAdapter; @@ -86,6 +85,8 @@ import java.util.ListIterator; import java.util.Set; +import static com.apptentive.android.sdk.module.messagecenter.model.MessageCenterUtil.MessageCenterListItem.MESSAGE_CONTEXT; + public class MessageCenterFragment extends ApptentiveBaseFragment implements OnMenuItemClickListener, MessageManager.AfterSendMessageListener, MessageAdapter.OnListviewItemActionListener, MessageManager.OnNewIncomingMessagesListener, @@ -131,14 +132,14 @@ public class MessageCenterFragment extends ApptentiveBaseFragment imageAttachmentstList = new ArrayList(); @@ -195,11 +196,6 @@ public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); // Make Message Center frgament retain its instance on orientation change setRetainInstance(true); - - if (interaction != null) { - String contextualMessageBody = interaction.getContextualMessageBody(); - contextualMessage = CompoundMessage.createAutoMessage(null, contextualMessageBody); - } } @Override @@ -405,8 +401,17 @@ public void onClick(View v) { prepareMessages(items); } - if (contextualMessage != null) { - addContextualMessageItem(); + String contextualMessageBody = interaction.getContextualMessageBody(); + if (contextualMessageBody != null) { + ContextMessage contextMessage = new ContextMessage(contextualMessageBody); + // Clear any pending composing message to present an empty composing area + clearPendingComposingMessage(); + clearStatusItem(); + messages.add(contextMessage); + // If checkAddWhoCardIfRequired returns true, it will add WhoCard, otherwise add composing card + if (!checkAddWhoCardIfRequired()) { + addComposingCard(); + } } /* Add who card with pending contents @@ -488,9 +493,6 @@ public void onSaveInstanceState(Bundle outState) { outState.putString(WHO_CARD_AVATAR_FILE, messageCenterRecyclerViewAdapter.getWhoCardAvatarFileName()); } outState.putInt(WHO_CARD_MODE, pendingWhoCardMode); - if (contextualMessage == null) { - interaction.clearContextualMessage(); - } super.onSaveInstanceState(outState); } @@ -515,7 +517,7 @@ public boolean onBackPressed(boolean hardwareButton) { public boolean cleanup() { savePendingComposingMessage(); clearPendingMessageCenterPushNotification(); - clearComposingUi(null, null, 0); + clearComposingUi(); clearWhoCardUi(null, null, 0); // Set to null, otherwise they will hold reference to the activity context MessageManager mgr = ApptentiveInternal.getInstance().getMessageManager(); @@ -553,17 +555,6 @@ private void clearPendingMessageCenterPushNotification() { } } - public void addContextualMessageItem() { - // Clear any pending composing message to present an empty composing area - clearPendingComposingMessage(); - clearStatusItem(); - messages.add(contextualMessage); - // If checkAddWhoCardIfRequired returns true, it will add WhoCard, otherwise add composing card - if (!checkAddWhoCardIfRequired()) { - addComposingCard(); - } - } - public void addComposingCard() { hideFab(); hideProfileButton(); @@ -668,7 +659,7 @@ public void addNewOutGoingMessageItem(ApptentiveMessage message) { clearStatusItem(); messages.add(message); - unsendMessagesCount++; + unsentMessagesCount++; isPaused = false; if (messageCenterRecyclerViewAdapter != null) { @@ -678,21 +669,25 @@ public void addNewOutGoingMessageItem(ApptentiveMessage message) { public void displayNewIncomingMessageItem(ApptentiveMessage message) { clearStatusItem(); - + // TODO: A simpler way to put the message in the correct place. // Determine where to insert the new incoming message. It will be in front of any eidting // area, i.e. composing, Who Card ... int insertIndex = messages.size(); if (composer != null) { // when in composing mode, there are composing action bar and composing area insertIndex -= 2; +/* if (contextualMessage != null) { insertIndex--; } +*/ } else if (whoCardItem != null) { insertIndex -= 1; +/* if (contextualMessage != null) { insertIndex--; } +*/ } messages.add(insertIndex, message); @@ -881,12 +876,13 @@ public void clearWhoCardUi(Animator.AnimatorListener al, } } - public void clearComposingUi(Animator.AnimatorListener al, ValueAnimator.AnimatorUpdateListener vl, long delay) { + public void clearComposingUi() { + clearPendingComposingMessage(); if (composer != null && messageCenterRecyclerViewAdapter != null) { int contextMessageIndex = -1; for (int i = 0; i < messages.size(); i++) { MessageCenterUtil.MessageCenterListItem message = messages.get(i); - if (message.getListItemType() == MessageCenterUtil.MessageCenterListItem.MESSAGE_CONTEXT) { + if (message.getListItemType() == MESSAGE_CONTEXT) { contextMessageIndex = i; break; } @@ -910,7 +906,6 @@ public void clearComposingUi(Animator.AnimatorListener al, ValueAnimator.Animato messages.remove(composerIndex); messageCenterRecyclerViewAdapter.notifyItemRemoved(composerIndex); } - showFab(); } } @@ -1075,44 +1070,21 @@ public void onCancelComposing() { } EngagementModule.engageInternal(hostingActivityRef.get(), interaction, MessageCenterInteraction.EVENT_NAME_COMPOSE_CLOSE, data.toString()); - clearComposingUi(new Animator.AnimatorListener() { - - @Override - public void onAnimationStart(Animator animation) { - } - - @Override - public void onAnimationRepeat(Animator animation) { - } - - @Override - public void onAnimationEnd(Animator animation) { - if (contextualMessage != null) { - messages.remove(contextualMessage); - contextualMessage = null; - } - messages.remove(composer); - composer = null; - messageEditText = null; - if (messageCenterRecyclerViewAdapter != null) { - messageCenterRecyclerViewAdapter.clearComposing(); - addExpectationStatusIfNeeded(); - messageCenterRecyclerViewAdapter.notifyDataSetChanged(); - } - imageAttachmentstList.clear(); - showFab(); - showProfileButton(); - // messageEditText has been set to null, pending composing message will reset - clearPendingComposingMessage(); - } - - @Override - public void onAnimationCancel(Animator animation) { - } - }, - null, - DEFAULT_DELAYMILLIS); - //clearComposingUi(null, null, 0); + // TODO: Remove Composer + // TODO: Remove context message + // TODO: Clear composer + // TODO: Clear any saved state like attachments, saved message state. + // TODO: Show FAB + // TODO: Show Profile Button + if (messageCenterRecyclerViewAdapter != null) { + messageCenterRecyclerViewAdapter.clearComposing(); + addExpectationStatusIfNeeded(); + messageCenterRecyclerViewAdapter.notifyDataSetChanged(); + } + imageAttachmentstList.clear(); + clearComposingUi(); + showFab(); + showProfileButton(); } @Override @@ -1121,59 +1093,36 @@ public void onFinishComposing() { messageCenterRecyclerViewAdapter.setForceShowKeyboard(false); } Util.hideSoftKeyboard(hostingActivityRef.get(), getView()); - if (contextualMessage != null) { - unsendMessagesCount++; - ApptentiveInternal.getInstance().getMessageManager().sendMessage(contextualMessage); - contextualMessage = null; + + for (MessageCenterUtil.MessageCenterListItem message : messages) { + if (message.getListItemType() == MESSAGE_CONTEXT) { + unsentMessagesCount++; + // TODO: Create a actual AutomatedMessage to send here. + //ApptentiveInternal.getInstance().getMessageManager().sendMessage(contextualMessage); + break; + } } Editable content = getPendingComposingContent(); final String messageText = (content != null) ? content.toString().trim() : ""; final ArrayList messageAttachments = new ArrayList(); messageAttachments.addAll(imageAttachmentstList); + if (!messageText.isEmpty() || imageAttachmentstList.size() != 0) { + Bundle b = new Bundle(); + b.putString(COMPOSING_EDITTEXT_STATE, messageText); + b.putParcelableArrayList(COMPOSING_ATTACHMENTS, messageAttachments); + Message msg = messagingActionHandler.obtainMessage(MSG_START_SENDING, messageText); + msg.setData(b); + ApptentiveLog.e("Send Send Message Message"); + messagingActionHandler.sendMessage(msg); + } + + // TODO: Remove Composer + // TODO: Do something with context message + // TODO: Clear composer + // TODO: Clear any saved state like attachments, saved message state. + // Close all composing UI - clearComposingUi(new Animator.AnimatorListener() { - - @Override - public void onAnimationStart(Animator animation) { - } - - @Override - public void onAnimationRepeat(Animator animation) { - } - - @Override - public void onAnimationEnd(Animator animation) { - messages.remove(composer); - composer = null; - messageEditText = null; - if (messageCenterRecyclerViewAdapter != null) { - messageCenterRecyclerViewAdapter.clearComposing(); - messageCenterRecyclerViewAdapter.notifyDataSetChanged(); - } - clearPendingComposingMessage(); - // Send out the new message. The delay is added to ensure the CardView showing animation - // is visible after the keyboard is hidden - if (!messageText.isEmpty() || imageAttachmentstList.size() != 0) { - Bundle b = new Bundle(); - b.putString(COMPOSING_EDITTEXT_STATE, messageText); - b.putParcelableArrayList(COMPOSING_ATTACHMENTS, messageAttachments); - Message msg = messagingActionHandler.obtainMessage(MSG_START_SENDING, - messageText); - msg.setData(b); - messagingActionHandler.sendMessageDelayed(msg, DEFAULT_DELAYMILLIS); - } - - imageAttachmentstList.clear(); - showFab(); - showProfileButton(); - } - - @Override - public void onAnimationCancel(Animator animation) { - } - }, - null, - DEFAULT_DELAYMILLIS); + clearComposingUi(); } @Override @@ -1237,7 +1186,7 @@ public void onAnimationEnd(Animator animation) { // If Who card is required, it might be displayed before proceeding to composing, for instance // when there was a contextual message or it was the first message. We need to resume composing // after dismissing Who Card - if ((messages.size() == 1 || contextualMessage != null) && interaction.getWhoCardRequired()) { + if (messages.size() == 1 && interaction.getWhoCardRequired()) { addComposingCard(); } else { showFab(); @@ -1499,14 +1448,14 @@ private void hideProfileButton() { */ private void prepareMessages(final List originalItems) { messages.clear(); - unsendMessagesCount = 0; + unsentMessagesCount = 0; // Loop through each message item retrieved from database for (MessageCenterUtil.MessageCenterListItem item : originalItems) { if (item instanceof ApptentiveMessage) { ApptentiveMessage apptentiveMessage = (ApptentiveMessage) item; Double createdAt = apptentiveMessage.getCreatedAt(); if (apptentiveMessage.isOutgoingMessage() && createdAt == null) { - unsendMessagesCount++; + unsentMessagesCount++; } /* @@ -1637,7 +1586,7 @@ public void handleMessage(Message msg) { } case MSG_MESSAGE_SENT: { // below is callback handling when receiving of message is acknowledged by server through POST response - fragment.unsendMessagesCount--; + fragment.unsentMessagesCount--; ApptentiveMessage apptentiveMessage = (ApptentiveMessage) msg.obj; for (MessageCenterUtil.MessageCenterListItem message : fragment.messages) { if (message instanceof ApptentiveMessage) { @@ -1678,6 +1627,7 @@ public void handleMessage(Message msg) { ArrayList imagesToAttach = b.getParcelableArrayList(COMPOSING_ATTACHMENTS); message.setAssociatedImages(imagesToAttach); + ApptentiveLog.e("Sending message"); ApptentiveInternal.getInstance().getMessageManager().sendMessage(message); @@ -1706,7 +1656,7 @@ public void handleMessage(Message msg) { case MSG_PAUSE_SENDING: { if (!fragment.isPaused) { fragment.isPaused = true; - if (fragment.unsendMessagesCount > 0) { + if (fragment.unsentMessagesCount > 0) { fragment.messageCenterRecyclerViewAdapter.setPaused(fragment.isPaused); int reason = msg.arg1; if (reason == MessageManager.SEND_PAUSE_REASON_NETWORK) { @@ -1726,7 +1676,7 @@ public void handleMessage(Message msg) { case MSG_RESUME_SENDING: { if (fragment.isPaused) { fragment.isPaused = false; - if (fragment.unsendMessagesCount > 0) { + if (fragment.unsentMessagesCount > 0) { fragment.clearStatusItem(); } diff --git a/apptentive/src/main/java/com/apptentive/android/sdk/module/messagecenter/model/CompoundMessage.java b/apptentive/src/main/java/com/apptentive/android/sdk/module/messagecenter/model/CompoundMessage.java index 689786f85..59e62eace 100644 --- a/apptentive/src/main/java/com/apptentive/android/sdk/module/messagecenter/model/CompoundMessage.java +++ b/apptentive/src/main/java/com/apptentive/android/sdk/module/messagecenter/model/CompoundMessage.java @@ -238,21 +238,6 @@ public boolean isOutgoingMessage() { return isOutgoing; } - public static CompoundMessage createAutoMessage(String title, String body) { - if (title == null && body == null) { - return null; - } - CompoundMessage message = new CompoundMessage(); - if (title != null) { - message.setTitle(title); - } - if (body != null) { - message.setBody(body); - } - message.setAutomated(true); - return message; - } - public List getRemoteAttachments() { return remoteAttachmentStoredFiles; } diff --git a/apptentive/src/main/java/com/apptentive/android/sdk/module/messagecenter/model/ContextMessage.java b/apptentive/src/main/java/com/apptentive/android/sdk/module/messagecenter/model/ContextMessage.java new file mode 100644 index 000000000..da7693e9a --- /dev/null +++ b/apptentive/src/main/java/com/apptentive/android/sdk/module/messagecenter/model/ContextMessage.java @@ -0,0 +1,25 @@ +/* + * Copyright (c) 2016, Apptentive, Inc. All Rights Reserved. + * Please refer to the LICENSE file for the terms and conditions + * under which redistribution and use of this file is permitted. + */ + +package com.apptentive.android.sdk.module.messagecenter.model; + +public class ContextMessage implements MessageCenterUtil.MessageCenterListItem { + + private String body; + + public ContextMessage(String body) { + this.body = body; + } + + @Override + public int getListItemType() { + return MESSAGE_CONTEXT; + } + + public String getBody() { + return body; + } +} diff --git a/apptentive/src/main/java/com/apptentive/android/sdk/module/messagecenter/view/MessageCenterRecyclerViewAdapter.java b/apptentive/src/main/java/com/apptentive/android/sdk/module/messagecenter/view/MessageCenterRecyclerViewAdapter.java index 948ad41f5..cbf08c64c 100644 --- a/apptentive/src/main/java/com/apptentive/android/sdk/module/messagecenter/view/MessageCenterRecyclerViewAdapter.java +++ b/apptentive/src/main/java/com/apptentive/android/sdk/module/messagecenter/view/MessageCenterRecyclerViewAdapter.java @@ -20,11 +20,13 @@ import com.apptentive.android.sdk.module.engagement.interaction.model.Interaction; import com.apptentive.android.sdk.module.messagecenter.model.Composer; import com.apptentive.android.sdk.module.messagecenter.model.CompoundMessage; +import com.apptentive.android.sdk.module.messagecenter.model.ContextMessage; import com.apptentive.android.sdk.module.messagecenter.model.MessageCenterGreeting; import com.apptentive.android.sdk.module.messagecenter.model.MessageCenterStatus; import com.apptentive.android.sdk.module.messagecenter.model.MessageCenterUtil; import com.apptentive.android.sdk.module.messagecenter.model.WhoCard; import com.apptentive.android.sdk.module.messagecenter.view.holder.AutomatedMessageHolder; +import com.apptentive.android.sdk.module.messagecenter.view.holder.ContextMessageHolder; import com.apptentive.android.sdk.module.messagecenter.view.holder.GreetingHolder; import com.apptentive.android.sdk.module.messagecenter.view.holder.IncomingCompoundMessageHolder; import com.apptentive.android.sdk.module.messagecenter.view.holder.MessageComposerHolder; @@ -38,6 +40,7 @@ import static com.apptentive.android.sdk.module.messagecenter.model.MessageCenterUtil.MessageCenterListItem.GREETING; import static com.apptentive.android.sdk.module.messagecenter.model.MessageCenterUtil.MessageCenterListItem.MESSAGE_AUTO; import static com.apptentive.android.sdk.module.messagecenter.model.MessageCenterUtil.MessageCenterListItem.MESSAGE_COMPOSER; +import static com.apptentive.android.sdk.module.messagecenter.model.MessageCenterUtil.MessageCenterListItem.MESSAGE_CONTEXT; import static com.apptentive.android.sdk.module.messagecenter.model.MessageCenterUtil.MessageCenterListItem.MESSAGE_INCOMING; import static com.apptentive.android.sdk.module.messagecenter.model.MessageCenterUtil.MessageCenterListItem.MESSAGE_OUTGOING; import static com.apptentive.android.sdk.module.messagecenter.model.MessageCenterUtil.MessageCenterListItem.STATUS; @@ -110,7 +113,14 @@ public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType View view = inflater.inflate(R.layout.apptentive_message_center_who_card, parent, false); return new WhoCardHolder(view); } + case MESSAGE_CONTEXT: { + ApptentiveLog.e("-> Message Context"); + LayoutInflater inflater = LayoutInflater.from(parent.getContext()); + View view = inflater.inflate(R.layout.apptentive_message_center_context_message, parent, false); + return new ContextMessageHolder(view); + } } + ApptentiveLog.e("onCreateViewHolder(%d) returning null.", viewType); return null; } @@ -174,6 +184,13 @@ public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) { whoCardHolder.bindView(recyclerView, whoCard); break; } + case MESSAGE_CONTEXT: { + ApptentiveLog.e("-> Message Context"); + ContextMessage contextMessage = (ContextMessage) messages.get(position); + ContextMessageHolder contextMessageHolder = (ContextMessageHolder) holder; + contextMessageHolder.bindView(contextMessage); + break; + } } } diff --git a/apptentive/src/main/java/com/apptentive/android/sdk/module/messagecenter/view/holder/ContextMessageHolder.java b/apptentive/src/main/java/com/apptentive/android/sdk/module/messagecenter/view/holder/ContextMessageHolder.java new file mode 100644 index 000000000..f1f1af45a --- /dev/null +++ b/apptentive/src/main/java/com/apptentive/android/sdk/module/messagecenter/view/holder/ContextMessageHolder.java @@ -0,0 +1,28 @@ +/* + * Copyright (c) 2016, Apptentive, Inc. All Rights Reserved. + * Please refer to the LICENSE file for the terms and conditions + * under which redistribution and use of this file is permitted. + */ + +package com.apptentive.android.sdk.module.messagecenter.view.holder; + +import android.support.v7.widget.RecyclerView; +import android.view.View; +import android.widget.TextView; + +import com.apptentive.android.sdk.R; +import com.apptentive.android.sdk.module.messagecenter.model.ContextMessage; + +public class ContextMessageHolder extends RecyclerView.ViewHolder { + + private TextView bodyTextView; + + public ContextMessageHolder(View itemView) { + super(itemView); + bodyTextView = (TextView) itemView.findViewById(R.id.body); + } + + public void bindView(ContextMessage contextMessage) { + bodyTextView.setText(contextMessage.getBody()); + } +} diff --git a/apptentive/src/main/res/layout/apptentive_message_center_context_message.xml b/apptentive/src/main/res/layout/apptentive_message_center_context_message.xml new file mode 100644 index 000000000..f725c7a8f --- /dev/null +++ b/apptentive/src/main/res/layout/apptentive_message_center_context_message.xml @@ -0,0 +1,37 @@ + + + + + + + + + + + \ No newline at end of file From 124eb94782a4cb10e9688216b8f9f058699080e5 Mon Sep 17 00:00:00 2001 From: skykelsey Date: Tue, 1 Nov 2016 14:10:56 -0700 Subject: [PATCH 011/100] Hook up who card save and cancel button. --- .../MessageCenterRecyclerViewAdapter.java | 2 +- .../view/holder/WhoCardHolder.java | 61 +++++++++++++------ 2 files changed, 43 insertions(+), 20 deletions(-) diff --git a/apptentive/src/main/java/com/apptentive/android/sdk/module/messagecenter/view/MessageCenterRecyclerViewAdapter.java b/apptentive/src/main/java/com/apptentive/android/sdk/module/messagecenter/view/MessageCenterRecyclerViewAdapter.java index cbf08c64c..62f1f630f 100644 --- a/apptentive/src/main/java/com/apptentive/android/sdk/module/messagecenter/view/MessageCenterRecyclerViewAdapter.java +++ b/apptentive/src/main/java/com/apptentive/android/sdk/module/messagecenter/view/MessageCenterRecyclerViewAdapter.java @@ -111,7 +111,7 @@ public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType ApptentiveLog.e("-> Who Card"); LayoutInflater inflater = LayoutInflater.from(parent.getContext()); View view = inflater.inflate(R.layout.apptentive_message_center_who_card, parent, false); - return new WhoCardHolder(view); + return new WhoCardHolder(this, view); } case MESSAGE_CONTEXT: { ApptentiveLog.e("-> Message Context"); diff --git a/apptentive/src/main/java/com/apptentive/android/sdk/module/messagecenter/view/holder/WhoCardHolder.java b/apptentive/src/main/java/com/apptentive/android/sdk/module/messagecenter/view/holder/WhoCardHolder.java index 649596104..f8fa70a7b 100644 --- a/apptentive/src/main/java/com/apptentive/android/sdk/module/messagecenter/view/holder/WhoCardHolder.java +++ b/apptentive/src/main/java/com/apptentive/android/sdk/module/messagecenter/view/holder/WhoCardHolder.java @@ -16,11 +16,17 @@ import android.widget.EditText; import android.widget.TextView; +import com.apptentive.android.sdk.Apptentive; +import com.apptentive.android.sdk.ApptentiveLog; import com.apptentive.android.sdk.R; import com.apptentive.android.sdk.module.messagecenter.model.WhoCard; +import com.apptentive.android.sdk.module.messagecenter.view.MessageCenterRecyclerViewAdapter; import com.apptentive.android.sdk.util.Util; public class WhoCardHolder extends RecyclerView.ViewHolder { + + private MessageCenterRecyclerViewAdapter adapter; + private TextView title; private TextInputLayout nameLayout; private EditText nameEditText; @@ -30,8 +36,11 @@ public class WhoCardHolder extends RecyclerView.ViewHolder { private Button skipButton; private Button saveButton; - public WhoCardHolder(View itemView) { + public WhoCardHolder(MessageCenterRecyclerViewAdapter adapter, View itemView) { super(itemView); + + this.adapter = adapter; + title = (TextView) itemView.findViewById(R.id.who_title); nameEditText = (EditText) itemView.findViewById(R.id.who_name); nameLayout = (TextInputLayout) itemView.findViewById(R.id.input_layout_who_name); @@ -85,26 +94,40 @@ public void afterTextChanged(Editable editable) { emailEditText.addTextChangedListener(emailTextWatcher); // TODO: Prepopulate with name and email if we already have them. -/* - emailEditText.setText(email); - nameEditText.setText(name); -*/ - /* // TODO: Hook up listeners - skipButton.setOnClickListener(new View.OnClickListener() { - public void onClick(View view) { - listener.onCloseWhoCard(item.button_1); + nameEditText.setText(Apptentive.getPersonName()); + emailEditText.setText(Apptentive.getPersonEmail()); + + // TODO: Hook up listeners + skipButton.setOnClickListener(new View.OnClickListener() { + public void onClick(View view) { + if (adapter.getListener() != null) { + adapter.getListener().onCloseWhoCard(skipButton.getText().toString()); } - }); - - sendButton.setOnClickListener(new View.OnClickListener() { - public void onClick(View view) { - if (isWhoCardContentValid(item.getType())) { - Apptentive.setPersonEmail(emailEditText.getText().toString().trim()); - Apptentive.setPersonName(nameEditText.getText().toString().trim()); - listener.onSubmitWhoCard(item.button_2); + } + }); + + saveButton.setOnClickListener(new View.OnClickListener() { + public void onClick(View view) { + if (isWhoCardContentValid(whoCard.isRequire())) { + Apptentive.setPersonEmail(emailEditText.getText().toString().trim()); + Apptentive.setPersonName(nameEditText.getText().toString().trim()); + if (adapter.getListener() != null) { + adapter.getListener().onCloseWhoCard(saveButton.getText().toString()); } } - }); -*/ + } + }); + } + + private boolean isWhoCardContentValid(boolean required) { + String emailContent = emailEditText.getText().toString(); + if (Util.isEmailValid(emailContent)) { + return true; + } + // Allow user only change name but leave email blank if profile is only requested, not required + if (TextUtils.isEmpty(emailContent) && !required) { + return true; + } + return false; } } From 18c879c61b2884bdf77ba083b00f860cc399d25b Mon Sep 17 00:00:00 2001 From: skykelsey Date: Tue, 1 Nov 2016 22:29:41 -0700 Subject: [PATCH 012/100] Get more behavior working using the handler. --- .../fragment/MessageCenterFragment.java | 346 ++++++++++-------- .../MessageCenterRecyclerViewAdapter.java | 40 +- .../view/holder/MessageComposerHolder.java | 7 +- 3 files changed, 205 insertions(+), 188 deletions(-) diff --git a/apptentive/src/main/java/com/apptentive/android/sdk/module/engagement/interaction/fragment/MessageCenterFragment.java b/apptentive/src/main/java/com/apptentive/android/sdk/module/engagement/interaction/fragment/MessageCenterFragment.java index 1709d351f..dfee3d0af 100644 --- a/apptentive/src/main/java/com/apptentive/android/sdk/module/engagement/interaction/fragment/MessageCenterFragment.java +++ b/apptentive/src/main/java/com/apptentive/android/sdk/module/engagement/interaction/fragment/MessageCenterFragment.java @@ -85,7 +85,11 @@ import java.util.ListIterator; import java.util.Set; +import static com.apptentive.android.sdk.module.messagecenter.model.MessageCenterUtil.MessageCenterListItem.MESSAGE_COMPOSER; import static com.apptentive.android.sdk.module.messagecenter.model.MessageCenterUtil.MessageCenterListItem.MESSAGE_CONTEXT; +import static com.apptentive.android.sdk.module.messagecenter.model.MessageCenterUtil.MessageCenterListItem.MESSAGE_OUTGOING; +import static com.apptentive.android.sdk.module.messagecenter.model.MessageCenterUtil.MessageCenterListItem.STATUS; +import static com.apptentive.android.sdk.module.messagecenter.model.MessageCenterUtil.MessageCenterListItem.WHO_CARD; public class MessageCenterFragment extends ApptentiveBaseFragment implements OnMenuItemClickListener, MessageManager.AfterSendMessageListener, MessageAdapter.OnListviewItemActionListener, @@ -101,6 +105,7 @@ public class MessageCenterFragment extends ApptentiveBaseFragment imageAttachmentstList = new ArrayList(); @@ -183,6 +189,11 @@ public class MessageCenterFragment extends ApptentiveBaseFragment items = ApptentiveInternal.getInstance().getMessageManager().getMessageCenterListItems(); @@ -403,10 +416,10 @@ public void onClick(View v) { String contextualMessageBody = interaction.getContextualMessageBody(); if (contextualMessageBody != null) { - ContextMessage contextMessage = new ContextMessage(contextualMessageBody); + contextMessage = new ContextMessage(contextualMessageBody); // Clear any pending composing message to present an empty composing area clearPendingComposingMessage(); - clearStatusItem(); + messagingActionHandler.sendEmptyMessage(MSG_REMOVE_STATUS); messages.add(contextMessage); // If checkAddWhoCardIfRequired returns true, it will add WhoCard, otherwise add composing card if (!checkAddWhoCardIfRequired()) { @@ -435,7 +448,6 @@ else if (pendingWhoCardName != null || pendingWhoCardEmail != null || pendingWho } - messageCenterRecyclerViewAdapter = new MessageCenterRecyclerViewAdapter(this, this, interaction, messages); messageCenterRecyclerView.setAdapter(messageCenterRecyclerViewAdapter); /* @@ -458,21 +470,18 @@ public boolean onMenuItemClick(MenuItem menuItem) { int menuItemId = menuItem.getItemId(); if (menuItemId == R.id.profile) { - // Only allow profile editing when not already editing profile or in message composing - if (whoCardItem == null && composer == null) { - final SharedPreferences prefs = ApptentiveInternal.getInstance().getSharedPrefs(); - boolean bWhoCardSet = prefs.getBoolean(Constants.PREF_KEY_MESSAGE_CENTER_WHO_CARD_SET, false); - - JSONObject data = new JSONObject(); - try { - data.put("required", interaction.getWhoCardRequired()); - data.put("trigger", "button"); - } catch (JSONException e) { - // - } - EngagementModule.engageInternal(hostingActivityRef.get(), interaction, MessageCenterInteraction.EVENT_NAME_PROFILE_OPEN, data.toString()); - addWhoCard((!bWhoCardSet) ? WHO_CARD_MODE_INIT : WHO_CARD_MODE_EDIT); + JSONObject data = new JSONObject(); + try { + data.put("required", interaction.getWhoCardRequired()); + data.put("trigger", "button"); + } catch (JSONException e) { + // } + EngagementModule.engageInternal(hostingActivityRef.get(), interaction, MessageCenterInteraction.EVENT_NAME_PROFILE_OPEN, data.toString()); + + final SharedPreferences prefs = ApptentiveInternal.getInstance().getSharedPrefs(); + boolean bWhoCardSet = prefs.getBoolean(Constants.PREF_KEY_MESSAGE_CENTER_WHO_CARD_SET, false); + addWhoCard((!bWhoCardSet) ? WHO_CARD_MODE_INIT : WHO_CARD_MODE_EDIT); return true; } else { return false; @@ -517,7 +526,6 @@ public boolean onBackPressed(boolean hardwareButton) { public boolean cleanup() { savePendingComposingMessage(); clearPendingMessageCenterPushNotification(); - clearComposingUi(); clearWhoCardUi(null, null, 0); // Set to null, otherwise they will hold reference to the activity context MessageManager mgr = ApptentiveInternal.getInstance().getMessageManager(); @@ -561,11 +569,12 @@ public void addComposingCard() { messagingActionHandler.removeMessages(MSG_MESSAGE_ADD_WHOCARD); messagingActionHandler.removeMessages(MSG_MESSAGE_ADD_COMPOSING); messagingActionHandler.sendEmptyMessage(MSG_MESSAGE_ADD_COMPOSING); + messagingActionHandler.sendEmptyMessage(MSG_SCROLL_TO_BOTTOM); } public void addComposerMessageItems() { - clearStatusItem(); + messagingActionHandler.sendEmptyMessage(MSG_REMOVE_STATUS); composer = interaction.getComposer(); messages.add(composer); } @@ -593,13 +602,13 @@ public void addWhoCard(int mode) { hideProfileButton(); messagingActionHandler.removeMessages(MSG_MESSAGE_ADD_WHOCARD); messagingActionHandler.removeMessages(MSG_MESSAGE_ADD_COMPOSING); - messagingActionHandler.sendMessage(messagingActionHandler.obtainMessage(MSG_MESSAGE_ADD_WHOCARD, - mode, 0)); + messagingActionHandler.sendMessage(messagingActionHandler.obtainMessage(MSG_MESSAGE_ADD_WHOCARD, mode, 0)); + messagingActionHandler.sendEmptyMessage(MSG_SCROLL_TO_BOTTOM); } public void addWhoCardAsMessageItem(int mode) { pendingWhoCardMode = mode; - clearStatusItem(); + messagingActionHandler.sendEmptyMessage(MSG_REMOVE_STATUS); JSONObject profile = interaction.getProfile(); if (profile != null) { try { @@ -619,22 +628,31 @@ private boolean addExpectationStatusIfNeeded() { return false; } - MessageCenterUtil.MessageCenterListItem message = messages.get(numOfMessages - 1); + MessageCenterUtil.MessageCenterListItem item = messages.get(messages.size() - 1); - if (message != null && message instanceof ApptentiveMessage) { - apptentiveMessage = (ApptentiveMessage) message; + if (item != null && item.getListItemType() == MESSAGE_OUTGOING) { + apptentiveMessage = (ApptentiveMessage) item; } // Check if the last message in the view is a sent message - if (apptentiveMessage != null && - (apptentiveMessage.isOutgoingMessage())) { + if (apptentiveMessage != null && (apptentiveMessage.isOutgoingMessage())) { Double createdTime = apptentiveMessage.getCreatedAt(); if (createdTime != null && createdTime > Double.MIN_VALUE) { MessageCenterStatus newItem = interaction.getRegularStatus(); if (newItem != null && whoCardItem == null && composer == null) { // Add expectation status message if the last is a sent - clearStatusItem(); + messagingActionHandler.sendEmptyMessage(MSG_REMOVE_STATUS); + + Bundle b = new Bundle(); + b.putString("body", newItem.body); + if (newItem.icon != null) { + b.putInt("icon", newItem.icon); + } + Message msg = messagingActionHandler.obtainMessage(MSG_INSERT_STATUS); + messagingActionHandler.sendEmptyMessage(MSG_REMOVE_STATUS); + statusItem = newItem; messages.add(newItem); + messageCenterRecyclerViewAdapter.notifyItemInserted(messages.size() - 1); return true; } } @@ -643,7 +661,8 @@ private boolean addExpectationStatusIfNeeded() { } public void addNewStatusItem(MessageCenterUtil.MessageCenterListItem item) { - clearStatusItem(); + + messagingActionHandler.sendEmptyMessage(MSG_REMOVE_STATUS); if (composer != null) { return; @@ -656,11 +675,11 @@ public void addNewStatusItem(MessageCenterUtil.MessageCenterListItem item) { } public void addNewOutGoingMessageItem(ApptentiveMessage message) { - clearStatusItem(); + messagingActionHandler.sendEmptyMessage(MSG_REMOVE_STATUS); messages.add(message); + messageCenterRecyclerViewAdapter.notifyItemInserted(messages.size() - 1); unsentMessagesCount++; - isPaused = false; if (messageCenterRecyclerViewAdapter != null) { messageCenterRecyclerViewAdapter.setPaused(isPaused); @@ -668,7 +687,7 @@ public void addNewOutGoingMessageItem(ApptentiveMessage message) { } public void displayNewIncomingMessageItem(ApptentiveMessage message) { - clearStatusItem(); + messagingActionHandler.sendEmptyMessage(MSG_REMOVE_STATUS); // TODO: A simpler way to put the message in the correct place. // Determine where to insert the new incoming message. It will be in front of any eidting // area, i.e. composing, Who Card ... @@ -713,16 +732,6 @@ public void displayNewIncomingMessageItem(ApptentiveMessage message) { } - private void clearStatusItem() { - // Remove the status message whenever a new incoming message is added - if (statusItem != null) { - messages.remove(statusItem); - statusItem = null; - if (messageCenterRecyclerViewAdapter != null) { - messageCenterRecyclerViewAdapter.notifyDataSetChanged(); - } - } - } public void addAttachmentsToComposer(final List images) { int numberOfExistingAttachments = imageAttachmentstList.size(); @@ -860,8 +869,7 @@ public synchronized void onResumeSending() { messagingActionHandler.sendEmptyMessage(MSG_RESUME_SENDING); } - public void clearWhoCardUi(Animator.AnimatorListener al, - ValueAnimator.AnimatorUpdateListener vl, long delay) { + public void clearWhoCardUi(Animator.AnimatorListener al, ValueAnimator.AnimatorUpdateListener vl, long delay) { if (whoCardItem != null && messageCenterRecyclerViewAdapter != null) { if (al != null) { deleteItemWithAnimation(messageCenterRecyclerViewAdapter.getWhoCardView(), al, vl, delay); @@ -871,40 +879,6 @@ public void clearWhoCardUi(Animator.AnimatorListener al, pendingWhoCardEmail = null; pendingWhoCardAvatarFile = null; pendingWhoCardMode = 0; - messageCenterRecyclerViewAdapter.clearWhoCard(); - } - } - } - - public void clearComposingUi() { - clearPendingComposingMessage(); - if (composer != null && messageCenterRecyclerViewAdapter != null) { - int contextMessageIndex = -1; - for (int i = 0; i < messages.size(); i++) { - MessageCenterUtil.MessageCenterListItem message = messages.get(i); - if (message.getListItemType() == MESSAGE_CONTEXT) { - contextMessageIndex = i; - break; - } - } - if (contextMessageIndex != -1) { - ApptentiveLog.e("Removing Context Message"); - messages.remove(contextMessageIndex); - messageCenterRecyclerViewAdapter.notifyItemRemoved(contextMessageIndex); - } - - int composerIndex = -1; - for (int i = 0; i < messages.size(); i++) { - MessageCenterUtil.MessageCenterListItem message = messages.get(i); - if (message.getListItemType() == MessageCenterUtil.MessageCenterListItem.MESSAGE_COMPOSER) { - composerIndex = i; - break; - } - } - if (composerIndex != -1) { - ApptentiveLog.e("Removing Composer"); - messages.remove(composerIndex); - messageCenterRecyclerViewAdapter.notifyItemRemoved(composerIndex); } } } @@ -1047,10 +1021,8 @@ public void onComposingTextChanged(CharSequence str) { } @Override - public void afterComposingTextChanged(String str) { - // Update display status of composing bar buttons when composing text changes - // TODO: Save state here? - //updateComposingBar(); + public void afterComposingTextChanged(String message) { + pendingMessage = message; } @Override @@ -1069,6 +1041,7 @@ public void onCancelComposing() { // } EngagementModule.engageInternal(hostingActivityRef.get(), interaction, MessageCenterInteraction.EVENT_NAME_COMPOSE_CLOSE, data.toString()); + messagingActionHandler.sendMessage(messagingActionHandler.obtainMessage(MSG_REMOVE_COMPOSER)); // TODO: Remove Composer // TODO: Remove context message @@ -1077,52 +1050,62 @@ public void onCancelComposing() { // TODO: Show FAB // TODO: Show Profile Button if (messageCenterRecyclerViewAdapter != null) { - messageCenterRecyclerViewAdapter.clearComposing(); addExpectationStatusIfNeeded(); - messageCenterRecyclerViewAdapter.notifyDataSetChanged(); } imageAttachmentstList.clear(); - clearComposingUi(); + pendingMessage = null; showFab(); showProfileButton(); } @Override public void onFinishComposing() { + messagingActionHandler.sendEmptyMessage(MSG_REMOVE_COMPOSER); + if (messageCenterRecyclerViewAdapter != null) { messageCenterRecyclerViewAdapter.setForceShowKeyboard(false); } Util.hideSoftKeyboard(hostingActivityRef.get(), getView()); - - for (MessageCenterUtil.MessageCenterListItem message : messages) { - if (message.getListItemType() == MESSAGE_CONTEXT) { - unsentMessagesCount++; - // TODO: Create a actual AutomatedMessage to send here. - //ApptentiveInternal.getInstance().getMessageManager().sendMessage(contextualMessage); - break; - } + if (contextMessage != null) { + Message sendContextMessage = messagingActionHandler.obtainMessage(MSG_SEND_CONTEXT_MESSAGE, contextMessage.getBody()); + unsentMessagesCount++; + messagingActionHandler.sendMessage(sendContextMessage); + contextMessage = null; } - Editable content = getPendingComposingContent(); - final String messageText = (content != null) ? content.toString().trim() : ""; - final ArrayList messageAttachments = new ArrayList(); - messageAttachments.addAll(imageAttachmentstList); - if (!messageText.isEmpty() || imageAttachmentstList.size() != 0) { + + + if (!pendingMessage.isEmpty() || imageAttachmentstList.size() != 0) { + Bundle b = new Bundle(); - b.putString(COMPOSING_EDITTEXT_STATE, messageText); - b.putParcelableArrayList(COMPOSING_ATTACHMENTS, messageAttachments); - Message msg = messagingActionHandler.obtainMessage(MSG_START_SENDING, messageText); + b.putString(COMPOSING_EDITTEXT_STATE, pendingMessage); + b.putParcelableArrayList(COMPOSING_ATTACHMENTS, imageAttachmentstList); + Message msg = messagingActionHandler.obtainMessage(MSG_START_SENDING, pendingMessage); msg.setData(b); ApptentiveLog.e("Send Send Message Message"); + unsentMessagesCount++; messagingActionHandler.sendMessage(msg); + pendingMessage = null; } - // TODO: Remove Composer - // TODO: Do something with context message - // TODO: Clear composer - // TODO: Clear any saved state like attachments, saved message state. + // Add status if needed? +/* + if (messageCenterRecyclerViewAdapter != null) { + addExpectationStatusIfNeeded(); + } +*/ - // Close all composing UI - clearComposingUi(); + showFab(); + showProfileButton(); + } + + private void removeItemsFromRecyclerView(int type) { + for (int i = 0; i < messages.size(); i++) { + MessageCenterUtil.MessageCenterListItem item = messages.get(i); + if (item.getListItemType() == type) { + messages.remove(i); + messageCenterRecyclerViewAdapter.notifyItemRemoved(i); + } + } } @Override @@ -1154,59 +1137,24 @@ public void onCloseWhoCard(String buttonLabel) { } public void cleanupWhoCard() { + messagingActionHandler.sendEmptyMessage(MSG_MESSAGE_REMOVE_WHOCARD); if (messageCenterRecyclerViewAdapter != null) { messageCenterRecyclerViewAdapter.setForceShowKeyboard(false); } Util.hideSoftKeyboard(hostingActivityRef.get(), getView()); - clearWhoCardUi( - new Animator.AnimatorListener() { - - @Override - public void onAnimationStart(Animator animation) { - } - - @Override - public void onAnimationRepeat(Animator animation) { - } - - @Override - public void onAnimationEnd(Animator animation) { - messages.remove(whoCardItem); - whoCardItem = null; - pendingWhoCardName = null; - pendingWhoCardEmail = null; - pendingWhoCardAvatarFile = null; - pendingWhoCardMode = 0; - if (messageCenterRecyclerViewAdapter != null) { - messageCenterRecyclerViewAdapter.clearWhoCard(); - addExpectationStatusIfNeeded(); - messageCenterRecyclerViewAdapter.notifyDataSetChanged(); - } - saveWhoCardSetState(); - // If Who card is required, it might be displayed before proceeding to composing, for instance - // when there was a contextual message or it was the first message. We need to resume composing - // after dismissing Who Card - if (messages.size() == 1 && interaction.getWhoCardRequired()) { - addComposingCard(); - } else { - showFab(); - showProfileButton(); - } - } - - @Override - public void onAnimationCancel(Animator animation) { - } - }, - null, - DEFAULT_DELAYMILLIS - ); + whoCardItem = null; + pendingWhoCardName = null; + pendingWhoCardEmail = null; + pendingWhoCardAvatarFile = null; + pendingWhoCardMode = 0; + addExpectationStatusIfNeeded(); + showFab(); + showProfileButton(); } @Override public void onNewMessageReceived(final CompoundMessage apptentiveMsg) { - messagingActionHandler.sendMessage(messagingActionHandler.obtainMessage(MSG_MESSAGE_ADD_INCOMING, - apptentiveMsg)); + messagingActionHandler.sendMessage(messagingActionHandler.obtainMessage(MSG_MESSAGE_ADD_INCOMING, apptentiveMsg)); } @Override @@ -1562,6 +1510,20 @@ public void handleMessage(Message msg) { fragment.messageCenterRecyclerView.setSelection(fragment.messages.size() - 1); break; } + case MSG_MESSAGE_REMOVE_WHOCARD: { + List messages = fragment.messages; + ListIterator messageIterator = messages.listIterator(); + while (messageIterator.hasNext()) { + int i = messageIterator.nextIndex(); + MessageCenterUtil.MessageCenterListItem next = messageIterator.next(); + if (next.getListItemType() == WHO_CARD) { + ApptentiveLog.e("Removing Who Card"); + messageIterator.remove(); + fragment.messageCenterRecyclerViewAdapter.notifyItemRemoved(i); + } + } + break; + } case MSG_MESSAGE_ADD_COMPOSING: { fragment.addComposerMessageItems(); fragment.messageCenterRecyclerViewAdapter.setForceShowKeyboard(true); @@ -1576,6 +1538,7 @@ public void handleMessage(Message msg) { } case MSG_SCROLL_TO_BOTTOM: { fragment.messageCenterRecyclerView.setSelection(fragment.messages.size() - 1); + fragment.messageCenterRecyclerView.smoothScrollToPosition(fragment.messages.size() - 1); break; } case MSG_SCROLL_FROM_TOP: { @@ -1627,13 +1590,13 @@ public void handleMessage(Message msg) { ArrayList imagesToAttach = b.getParcelableArrayList(COMPOSING_ATTACHMENTS); message.setAssociatedImages(imagesToAttach); + ApptentiveLog.e("Adding Message to list"); + fragment.messages.add(message); + ApptentiveLog.e("Sending message"); ApptentiveInternal.getInstance().getMessageManager().sendMessage(message); - - // Add new outgoing message with animation - fragment.addNewOutGoingMessageItem(message); - fragment.messageCenterRecyclerViewAdapter.notifyDataSetChanged(); + // TODO: Move this somewhere else? // After the message is sent, check if Who Card need to be shown for the 1st time(When Who Card is either requested or required) SharedPreferences prefs = ApptentiveInternal.getInstance().getSharedPrefs(); boolean bWhoCardSet = prefs.getBoolean(Constants.PREF_KEY_MESSAGE_CENTER_WHO_CARD_SET, false); @@ -1653,6 +1616,34 @@ public void handleMessage(Message msg) { } break; } + case MSG_SEND_CONTEXT_MESSAGE: { + List messages = fragment.messages; + // Remove fake ContextMessage from the RecyclerView + for (int i = 0; i < messages.size(); i++) { + MessageCenterUtil.MessageCenterListItem item = messages.get(i); + if (item.getListItemType() == MESSAGE_CONTEXT) { + ApptentiveLog.e("Removing Fake Context Message"); + messages.remove(i); + fragment.messageCenterRecyclerViewAdapter.notifyItemRemoved(i); + } + } + // Create a CompoundMessage for sending and final display + String body = (String) msg.obj; + CompoundMessage message = new CompoundMessage(); + message.setBody(body); + message.setAutomated(true); + message.setRead(true); + + // Add it to the RecyclerView + ApptentiveLog.e("Adding Real Context Message"); + messages.add(message); + fragment.messageCenterRecyclerViewAdapter.notifyItemInserted(messages.size() - 1); + + // Send it to the server + ApptentiveLog.e("Sending Real Context Message"); + ApptentiveInternal.getInstance().getMessageManager().sendMessage(message); + break; + } case MSG_PAUSE_SENDING: { if (!fragment.isPaused) { fragment.isPaused = true; @@ -1662,11 +1653,11 @@ public void handleMessage(Message msg) { if (reason == MessageManager.SEND_PAUSE_REASON_NETWORK) { EngagementModule.engageInternal(fragment.hostingActivityRef.get(), fragment.interaction, MessageCenterInteraction.EVENT_NAME_MESSAGE_NETWORK_ERROR); MessageCenterStatus newItem = fragment.interaction.getErrorStatusNetwork(); - fragment.addNewStatusItem(newItem); + // TODO: fragment.addNewStatusItem(newItem); } else if (reason == MessageManager.SEND_PAUSE_REASON_SERVER) { EngagementModule.engageInternal(fragment.hostingActivityRef.get(), fragment.interaction, MessageCenterInteraction.EVENT_NAME_MESSAGE_HTTP_ERROR); MessageCenterStatus newItem = fragment.interaction.getErrorStatusServer(); - fragment.addNewStatusItem(newItem); + // TODO: fragment.addNewStatusItem(newItem); } fragment.messageCenterRecyclerViewAdapter.notifyDataSetChanged(); } @@ -1677,7 +1668,7 @@ public void handleMessage(Message msg) { if (fragment.isPaused) { fragment.isPaused = false; if (fragment.unsentMessagesCount > 0) { - fragment.clearStatusItem(); + // TODO: fragment.clearStatusItem(); } fragment.messageCenterRecyclerViewAdapter.setPaused(fragment.isPaused); @@ -1685,6 +1676,39 @@ public void handleMessage(Message msg) { } break; } + case MSG_REMOVE_COMPOSER: { + List messages = fragment.messages; + for (int i = 0; i < messages.size(); i++) { + MessageCenterUtil.MessageCenterListItem item = messages.get(i); + if (item.getListItemType() == MESSAGE_COMPOSER) { + ApptentiveLog.e("Removing Composer"); + messages.remove(i); + fragment.messageCenterRecyclerViewAdapter.notifyItemRemoved(i); + } + } + } + case MSG_INSERT_STATUS: { + List messages = fragment.messages; + for (int i = 0; i < messages.size(); i++) { + MessageCenterUtil.MessageCenterListItem item = messages.get(i); + if (item.getListItemType() == MESSAGE_COMPOSER) { + ApptentiveLog.e("Removing Composer"); + messages.remove(i); + fragment.messageCenterRecyclerViewAdapter.notifyItemRemoved(i); + } + } + } + case MSG_REMOVE_STATUS: { + List messages = fragment.messages; + for (int i = 0; i < messages.size(); i++) { + MessageCenterUtil.MessageCenterListItem item = messages.get(i); + if (item.getListItemType() == STATUS) { + ApptentiveLog.e("Removing Status"); + messages.remove(i); + fragment.messageCenterRecyclerViewAdapter.notifyItemRemoved(i); + } + } + } } } } diff --git a/apptentive/src/main/java/com/apptentive/android/sdk/module/messagecenter/view/MessageCenterRecyclerViewAdapter.java b/apptentive/src/main/java/com/apptentive/android/sdk/module/messagecenter/view/MessageCenterRecyclerViewAdapter.java index 62f1f630f..0139769dc 100644 --- a/apptentive/src/main/java/com/apptentive/android/sdk/module/messagecenter/view/MessageCenterRecyclerViewAdapter.java +++ b/apptentive/src/main/java/com/apptentive/android/sdk/module/messagecenter/view/MessageCenterRecyclerViewAdapter.java @@ -72,49 +72,49 @@ public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType ApptentiveLog.e("onCreateViewHolder()"); switch (viewType) { case MESSAGE_COMPOSER: { - ApptentiveLog.e("-> Message Composer"); + ApptentiveLog.w("-> Message Composer"); LayoutInflater inflater = LayoutInflater.from(parent.getContext()); View view = inflater.inflate(R.layout.apptentive_message_center_composer, parent, false); return new MessageComposerHolder(view); } case STATUS: { - ApptentiveLog.e("-> Status"); + ApptentiveLog.w("-> Status"); LayoutInflater inflater = LayoutInflater.from(parent.getContext()); View view = inflater.inflate(R.layout.apptentive_message_center_status, parent, false); return new StatusHolder(view); } case GREETING: { - ApptentiveLog.e("-> Greeting"); + ApptentiveLog.w("-> Greeting"); LayoutInflater inflater = LayoutInflater.from(parent.getContext()); View view = inflater.inflate(R.layout.apptentive_message_center_greeting, parent, false); return new GreetingHolder(view); } case MESSAGE_OUTGOING: { - ApptentiveLog.e("-> Message Outgoing"); + ApptentiveLog.w("-> Message Outgoing"); LayoutInflater inflater = LayoutInflater.from(parent.getContext()); View view = inflater.inflate(R.layout.apptentive_message_outgoing, parent, false); return new OutgoingCompoundMessageHolder(view); } case MESSAGE_INCOMING: { - ApptentiveLog.e("-> Message Incoming"); + ApptentiveLog.w("-> Message Incoming"); LayoutInflater inflater = LayoutInflater.from(parent.getContext()); View view = inflater.inflate(R.layout.apptentive_message_incoming, parent, false); return new IncomingCompoundMessageHolder(view); } case MESSAGE_AUTO: { - ApptentiveLog.e("-> Message Auto"); + ApptentiveLog.w("-> Message Auto"); LayoutInflater inflater = LayoutInflater.from(parent.getContext()); View view = inflater.inflate(R.layout.apptentive_message_auto, parent, false); return new AutomatedMessageHolder(view); } case WHO_CARD: { - ApptentiveLog.e("-> Who Card"); + ApptentiveLog.w("-> Who Card"); LayoutInflater inflater = LayoutInflater.from(parent.getContext()); View view = inflater.inflate(R.layout.apptentive_message_center_who_card, parent, false); return new WhoCardHolder(this, view); } case MESSAGE_CONTEXT: { - ApptentiveLog.e("-> Message Context"); + ApptentiveLog.w("-> Message Context"); LayoutInflater inflater = LayoutInflater.from(parent.getContext()); View view = inflater.inflate(R.layout.apptentive_message_center_context_message, parent, false); return new ContextMessageHolder(view); @@ -129,14 +129,14 @@ public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) { ApptentiveLog.e("onBindViewHolder()"); switch (getItemViewType(position)) { case MESSAGE_COMPOSER: { - ApptentiveLog.e("-> Message Composer"); + ApptentiveLog.w("-> Message Composer"); Composer composer = (Composer) messages.get(position); MessageComposerHolder composerHolder = (MessageComposerHolder) holder; composerHolder.bindView(fragment, this, composer); break; } case STATUS: { - ApptentiveLog.e("-> Status"); + ApptentiveLog.w("-> Status"); MessageCenterStatus status = (MessageCenterStatus) messages.get(position); StatusHolder statusHolder = (StatusHolder) holder; statusHolder.body.setText(status.body); @@ -150,42 +150,42 @@ public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) { break; } case GREETING: { - ApptentiveLog.e("-> Greeting"); + ApptentiveLog.w("-> Greeting"); MessageCenterGreeting greeting = (MessageCenterGreeting) messages.get(position); GreetingHolder greetingHolder = (GreetingHolder) holder; greetingHolder.bindView(greeting); break; } case MESSAGE_INCOMING: { - ApptentiveLog.e("-> Message Incoming"); + ApptentiveLog.w("-> Message Incoming"); CompoundMessage compoundMessage = (CompoundMessage) messages.get(position); IncomingCompoundMessageHolder compoundHolder = (IncomingCompoundMessageHolder) holder; compoundHolder.bindView(recyclerView, compoundMessage); break; } case MESSAGE_OUTGOING: { - ApptentiveLog.e("-> Message Outgoing"); + ApptentiveLog.w("-> Message Outgoing"); CompoundMessage compoundMessage = (CompoundMessage) messages.get(position); OutgoingCompoundMessageHolder compoundHolder = (OutgoingCompoundMessageHolder) holder; compoundHolder.bindView(recyclerView, compoundMessage); break; } case MESSAGE_AUTO: { - ApptentiveLog.e("-> Message Auto"); + ApptentiveLog.w("-> Message Auto"); CompoundMessage autoMessage = (CompoundMessage) messages.get(position); AutomatedMessageHolder autoHolder = (AutomatedMessageHolder) holder; autoHolder.bindView(recyclerView, autoMessage); break; } case WHO_CARD: { - ApptentiveLog.e("-> Who Card"); + ApptentiveLog.w("-> Who Card"); WhoCard whoCard = (WhoCard) messages.get(position); WhoCardHolder whoCardHolder = (WhoCardHolder) holder; whoCardHolder.bindView(recyclerView, whoCard); break; } case MESSAGE_CONTEXT: { - ApptentiveLog.e("-> Message Context"); + ApptentiveLog.w("-> Message Context"); ContextMessage contextMessage = (ContextMessage) messages.get(position); ContextMessageHolder contextMessageHolder = (ContextMessageHolder) holder; contextMessageHolder.bindView(contextMessage); @@ -266,10 +266,6 @@ public View getWhoCardView() { return new View(fragment.getContext()); // TODO } - public void clearWhoCard() { - return; // TODO - } - public MessageCenterComposingActionBarView getComposingActionBarView() { return new MessageCenterComposingActionBarView(fragment, null, null); // TODO } @@ -278,10 +274,6 @@ public View getComposingAreaView() { return new View(fragment.getContext()); // TODO } - public void clearComposing() { - return; // TODO - } - public EditText getEditTextInComposing() { return new EditText(fragment.getContext()); // TODO } diff --git a/apptentive/src/main/java/com/apptentive/android/sdk/module/messagecenter/view/holder/MessageComposerHolder.java b/apptentive/src/main/java/com/apptentive/android/sdk/module/messagecenter/view/holder/MessageComposerHolder.java index f17f99b24..0f23ed0ab 100644 --- a/apptentive/src/main/java/com/apptentive/android/sdk/module/messagecenter/view/holder/MessageComposerHolder.java +++ b/apptentive/src/main/java/com/apptentive/android/sdk/module/messagecenter/view/holder/MessageComposerHolder.java @@ -137,8 +137,9 @@ public void afterTextChanged(Editable editable) { if (adapter.getListener() != null) { adapter.getListener().afterComposingTextChanged(editable.toString()); } - setSendButtonEnabled(!TextUtils.isEmpty(message.getText())); Linkify.addLinks(editable, Linkify.WEB_URLS | Linkify.PHONE_NUMBERS | Linkify.EMAIL_ADDRESSES | Linkify.MAP_ADDRESSES); + // TODO: Call this from the fragment instead? + setSendButtonEnabled(!TextUtils.isEmpty(message.getText())); } }); @@ -201,7 +202,7 @@ public void addImagesToImageAttachmentBand(final List imagesToAttach) } /** - * Remove an image from attchment band. + * Remove an image from attachment band. * * @param position the postion index of the image to be removed */ @@ -267,7 +268,7 @@ public boolean onTouchEvent(TextView widget, Spannable buffer, MotionEvent event } private void setSendButtonEnabled(boolean enabled) { - if (sendButton.isEnabled() ^ enabled) { // No change required + if (sendButton.isEnabled() ^ enabled) { // Only if changing value sendButton.setEnabled(enabled); if (enabled) { if (Build.VERSION.SDK_INT < Build.VERSION_CODES.LOLLIPOP) { From 7e13195e13de4a96fe84db9a5de70195b0626ed2 Mon Sep 17 00:00:00 2001 From: skykelsey Date: Tue, 1 Nov 2016 23:05:12 -0700 Subject: [PATCH 013/100] Set up status on view initialization. Fix context message as well. --- .../fragment/MessageCenterFragment.java | 149 +++++++++--------- 1 file changed, 76 insertions(+), 73 deletions(-) diff --git a/apptentive/src/main/java/com/apptentive/android/sdk/module/engagement/interaction/fragment/MessageCenterFragment.java b/apptentive/src/main/java/com/apptentive/android/sdk/module/engagement/interaction/fragment/MessageCenterFragment.java index dfee3d0af..cde0e9a75 100644 --- a/apptentive/src/main/java/com/apptentive/android/sdk/module/engagement/interaction/fragment/MessageCenterFragment.java +++ b/apptentive/src/main/java/com/apptentive/android/sdk/module/engagement/interaction/fragment/MessageCenterFragment.java @@ -30,10 +30,10 @@ import android.text.Editable; import android.text.Layout; import android.text.TextUtils; -import android.view.MenuItem.OnMenuItemClickListener; import android.view.LayoutInflater; import android.view.Menu; import android.view.MenuItem; +import android.view.MenuItem.OnMenuItemClickListener; import android.view.View; import android.view.ViewGroup; import android.view.WindowManager; @@ -92,11 +92,11 @@ import static com.apptentive.android.sdk.module.messagecenter.model.MessageCenterUtil.MessageCenterListItem.WHO_CARD; public class MessageCenterFragment extends ApptentiveBaseFragment implements OnMenuItemClickListener, MessageManager.AfterSendMessageListener, - MessageAdapter.OnListviewItemActionListener, - MessageManager.OnNewIncomingMessagesListener, - AbsListView.OnScrollListener, - MessageCenterListView.OnListviewResizeListener, - ImageGridViewAdapter.Callback { + MessageAdapter.OnListviewItemActionListener, + MessageManager.OnNewIncomingMessagesListener, + AbsListView.OnScrollListener, + MessageCenterListView.OnListviewResizeListener, + ImageGridViewAdapter.Callback { private MenuItem profileMenuItem; private boolean bShowProfileMenuItem = true; @@ -141,7 +141,7 @@ public class MessageCenterFragment extends ApptentiveBaseFragment Double.MIN_VALUE) { - MessageCenterStatus newItem = interaction.getRegularStatus(); - if (newItem != null && whoCardItem == null && composer == null) { - // Add expectation status message if the last is a sent - messagingActionHandler.sendEmptyMessage(MSG_REMOVE_STATUS); - - Bundle b = new Bundle(); - b.putString("body", newItem.body); - if (newItem.icon != null) { - b.putInt("icon", newItem.icon); - } - Message msg = messagingActionHandler.obtainMessage(MSG_INSERT_STATUS); - messagingActionHandler.sendEmptyMessage(MSG_REMOVE_STATUS); - - statusItem = newItem; - messages.add(newItem); - messageCenterRecyclerViewAdapter.notifyItemInserted(messages.size() - 1); - return true; - } - } - } - return false; + private void addExpectationStatusIfNeeded() { + messagingActionHandler.sendEmptyMessage(MSG_REMOVE_STATUS); + messagingActionHandler.sendEmptyMessage(MSG_OPT_INSERT_REGULAR_STATUS); } public void addNewStatusItem(MessageCenterUtil.MessageCenterListItem item) { @@ -722,7 +691,7 @@ public void displayNewIncomingMessageItem(ApptentiveMessage message) { } // Restore the position of listview to composing view messagingActionHandler.sendMessage(messagingActionHandler.obtainMessage(MSG_SCROLL_FROM_TOP, - insertIndex, top)); + insertIndex, top)); } else { updateMessageSentStates(); if (messageCenterRecyclerViewAdapter != null) { @@ -774,7 +743,7 @@ public void addAttachmentsToComposer(final List images) { } int firstIndex = messageCenterRecyclerView.getFirstVisiblePosition(); messagingActionHandler.sendMessage(messagingActionHandler.obtainMessage(MSG_SCROLL_FROM_TOP, - firstIndex, top)); + firstIndex, top)); updateComposingBar(); } @@ -794,7 +763,7 @@ public void restoreSavedAttachmentsToComposer(final List images) { messageCenterRecyclerViewAdapter.notifyDataSetChanged(); } messagingActionHandler.sendMessage(messagingActionHandler.obtainMessage(MSG_SCROLL_FROM_TOP, - firstIndex, top)); + firstIndex, top)); updateComposingBar(); } @@ -856,13 +825,13 @@ public void showAttachmentDialog(final ImageItem image) { public synchronized void onMessageSent(ApptentiveHttpResponse response, final ApptentiveMessage apptentiveMessage) { if (response.isSuccessful() || response.isRejectedPermanently() || response.isBadPayload()) { messagingActionHandler.sendMessage(messagingActionHandler.obtainMessage(MSG_MESSAGE_SENT, - apptentiveMessage)); + apptentiveMessage)); } } public synchronized void onPauseSending(int reason) { messagingActionHandler.sendMessage(messagingActionHandler.obtainMessage(MSG_PAUSE_SENDING, - reason, 0)); + reason, 0)); } public synchronized void onResumeSending() { @@ -1067,6 +1036,7 @@ public void onFinishComposing() { } Util.hideSoftKeyboard(hostingActivityRef.get(), getView()); if (contextMessage != null) { + // TODO: Maybe simply send any context messages in the list when a message is sent? Message sendContextMessage = messagingActionHandler.obtainMessage(MSG_SEND_CONTEXT_MESSAGE, contextMessage.getBody()); unsentMessagesCount++; messagingActionHandler.sendMessage(sendContextMessage); @@ -1170,8 +1140,8 @@ public void onScroll(AbsListView view, int firstVisibleItem, int visibleItemCoun boolean bCanScrollUp; if (android.os.Build.VERSION.SDK_INT < 14) { bCanScrollUp = view.getChildCount() > 0 - && (view.getFirstVisiblePosition() > 0 || - view.getChildAt(0).getTop() < view.getPaddingTop()); + && (view.getFirstVisiblePosition() > 0 || + view.getChildAt(0).getTop() < view.getPaddingTop()); } else { bCanScrollUp = ViewCompat.canScrollVertically(view, -1); } @@ -1194,12 +1164,12 @@ public void OnListViewResize(int w, int h, int oldw, int oldh) { int line = layout.getLineForOffset(pos); int baseline = layout.getLineBaseline(line); int ascent = layout.getLineAscent(line); - if ( top + baseline - ascent > oldh - h) { + if (top + baseline - ascent > oldh - h) { messagingActionHandler.sendMessageDelayed(messagingActionHandler.obtainMessage(MSG_SCROLL_FROM_TOP, - lastIndex, top - (oldh - h)), DEFAULT_DELAYMILLIS); + lastIndex, top - (oldh - h)), DEFAULT_DELAYMILLIS); } else { messagingActionHandler.sendMessageDelayed(messagingActionHandler.obtainMessage(MSG_SCROLL_FROM_TOP, - lastIndex, top), DEFAULT_DELAYMILLIS); + lastIndex, top), DEFAULT_DELAYMILLIS); } } } @@ -1425,7 +1395,7 @@ private void prepareMessages(final List } if (next == null || next.getCreatedAt() == null || createdAt == null || next.getCreatedAt() <= createdAt || - createdAt <= Double.MIN_VALUE) { + createdAt <= Double.MIN_VALUE) { listIterator.add(item); } else { // Add in front of the message that has later created_at time @@ -1438,7 +1408,7 @@ private void prepareMessages(final List messages.add(0, interaction.getGreeting()); } -// @Override + // @Override public void onClickAttachment(final int position, final ImageItem image) { if (Util.isMimeTypeImage(image.mimeType)) { // "+" placeholder is clicked @@ -1515,7 +1485,7 @@ public void handleMessage(Message msg) { ListIterator messageIterator = messages.listIterator(); while (messageIterator.hasNext()) { int i = messageIterator.nextIndex(); - MessageCenterUtil.MessageCenterListItem next = messageIterator.next(); + MessageCenterUtil.MessageCenterListItem next = messageIterator.next(); if (next.getListItemType() == WHO_CARD) { ApptentiveLog.e("Removing Who Card"); messageIterator.remove(); @@ -1686,9 +1656,11 @@ public void handleMessage(Message msg) { fragment.messageCenterRecyclerViewAdapter.notifyItemRemoved(i); } } + break; } - case MSG_INSERT_STATUS: { + case MSG_OPT_INSERT_REGULAR_STATUS: { List messages = fragment.messages; + MessageCenterStatus status = fragment.interaction.getRegularStatus(); for (int i = 0; i < messages.size(); i++) { MessageCenterUtil.MessageCenterListItem item = messages.get(i); if (item.getListItemType() == MESSAGE_COMPOSER) { @@ -1697,6 +1669,27 @@ public void handleMessage(Message msg) { fragment.messageCenterRecyclerViewAdapter.notifyItemRemoved(i); } } + + int numOfMessages = messages.size(); + if (numOfMessages > 0) { + // Check if the last message in the view is a sent message + MessageCenterUtil.MessageCenterListItem lastItem = messages.get(messages.size() - 1); + if (lastItem != null && lastItem.getListItemType() == MESSAGE_OUTGOING) { + ApptentiveMessage apptentiveMessage = (ApptentiveMessage) lastItem; + if (apptentiveMessage.isOutgoingMessage()) { + Double createdTime = apptentiveMessage.getCreatedAt(); + if (createdTime != null && createdTime > Double.MIN_VALUE) { + if (status != null) { + // Add expectation status message if the last is a sent + messages.add(status); + fragment.messageCenterRecyclerViewAdapter.notifyItemInserted(messages.size() - 1); + } + } + } + } + } + + break; } case MSG_REMOVE_STATUS: { List messages = fragment.messages; @@ -1708,6 +1701,16 @@ public void handleMessage(Message msg) { fragment.messageCenterRecyclerViewAdapter.notifyItemRemoved(i); } } + break; + } + case MSG_ADD_CONTEXT_MESSAGE: { + ApptentiveLog.e("Adding Context Message"); + List messages = fragment.messages; + String body = (String) msg.obj; + ContextMessage contextMessage = new ContextMessage(body); + messages.add(contextMessage); + fragment.messageCenterRecyclerViewAdapter.notifyItemInserted(messages.size() - 1); + break; } } } From f00c6d91eacdf7a6dc9a3ae1e71f6808d609af89 Mon Sep 17 00:00:00 2001 From: skykelsey Date: Wed, 2 Nov 2016 10:53:51 -0700 Subject: [PATCH 014/100] Focus Composer EditText when opened. --- .../fragment/MessageCenterFragment.java | 130 +++++++----------- .../messagecenter/view/MessageAdapter.java | 2 +- .../MessageCenterRecyclerViewAdapter.java | 11 +- 3 files changed, 54 insertions(+), 89 deletions(-) diff --git a/apptentive/src/main/java/com/apptentive/android/sdk/module/engagement/interaction/fragment/MessageCenterFragment.java b/apptentive/src/main/java/com/apptentive/android/sdk/module/engagement/interaction/fragment/MessageCenterFragment.java index cde0e9a75..4737650bd 100644 --- a/apptentive/src/main/java/com/apptentive/android/sdk/module/engagement/interaction/fragment/MessageCenterFragment.java +++ b/apptentive/src/main/java/com/apptentive/android/sdk/module/engagement/interaction/fragment/MessageCenterFragment.java @@ -28,7 +28,6 @@ import android.support.v4.view.ViewCompat; import android.support.v7.widget.LinearLayoutManager; import android.text.Editable; -import android.text.Layout; import android.text.TextUtils; import android.view.LayoutInflater; import android.view.Menu; @@ -50,7 +49,6 @@ import com.apptentive.android.sdk.module.engagement.interaction.model.MessageCenterInteraction; import com.apptentive.android.sdk.module.messagecenter.MessageManager; import com.apptentive.android.sdk.module.messagecenter.model.ApptentiveMessage; -import com.apptentive.android.sdk.module.messagecenter.model.Composer; import com.apptentive.android.sdk.module.messagecenter.model.CompoundMessage; import com.apptentive.android.sdk.module.messagecenter.model.ContextMessage; import com.apptentive.android.sdk.module.messagecenter.model.MessageCenterStatus; @@ -126,7 +124,7 @@ public class MessageCenterFragment extends ApptentiveBaseFragment hostingActivityRef; private MessageCenterRecyclerView messageCenterRecyclerView; - private EditText messageEditText; // Composing area + private EditText composerEditText; private View fab; @@ -139,10 +137,9 @@ public class MessageCenterFragment extends ApptentiveBaseFragment images) { // Only update composing view if image is attached successfully messageCenterRecyclerViewAdapter.addImagestoComposer(uniqueImages); messageCenterRecyclerViewAdapter.notifyDataSetChanged(); - messageCenterRecyclerViewAdapter.setForceShowKeyboard(false); } int firstIndex = messageCenterRecyclerView.getFirstVisiblePosition(); messagingActionHandler.sendMessage(messagingActionHandler.obtainMessage(MSG_SCROLL_FROM_TOP, @@ -756,7 +735,6 @@ public void restoreSavedAttachmentsToComposer(final List images) { // Only update composing view if image is attached successfully if (messageCenterRecyclerViewAdapter != null) { messageCenterRecyclerViewAdapter.addImagestoComposer(images); - messageCenterRecyclerViewAdapter.setForceShowKeyboard(false); } int firstIndex = messageCenterRecyclerView.getFirstVisiblePosition(); if (messageCenterRecyclerViewAdapter != null) { @@ -774,7 +752,6 @@ public void removeImageFromComposer(final int position) { messageCenterRecyclerViewAdapter.removeImageFromComposer(position); int count = imageAttachmentstList.size(); // Show keyboard if all attachments have been removed - messageCenterRecyclerViewAdapter.setForceShowKeyboard(count == 0); messageCenterRecyclerViewAdapter.notifyDataSetChanged(); } messagingActionHandler.sendEmptyMessageDelayed(MSG_SCROLL_TO_BOTTOM, DEFAULT_DELAYMILLIS); @@ -891,22 +868,17 @@ public void updateComposingBar() { } @Override - public void onComposingViewCreated(View keyboardFocusedOnView) { - - hideProfileButton(); - hideFab(); + public void onComposingViewCreated(final EditText composerEditText) { EngagementModule.engageInternal(hostingActivityRef.get(), interaction, MessageCenterInteraction.EVENT_NAME_COMPOSE_OPEN); - if (messageCenterRecyclerViewAdapter != null) { - messageEditText = messageCenterRecyclerViewAdapter.getEditTextInComposing(); - } else { - messageEditText = null; - } + + this.composerEditText = composerEditText; + SharedPreferences prefs = ApptentiveInternal.getInstance().getSharedPrefs(); // Restore composing text editing state, such as cursor position, after rotation if (composingViewSavedState != null) { - if (messageEditText != null) { - messageEditText.onRestoreInstanceState(composingViewSavedState); + if (this.composerEditText != null) { + this.composerEditText.onRestoreInstanceState(composingViewSavedState); } composingViewSavedState = null; SharedPreferences.Editor editor = prefs.edit(); @@ -915,8 +887,8 @@ public void onComposingViewCreated(View keyboardFocusedOnView) { // Restore composing text if (prefs.contains(Constants.PREF_KEY_MESSAGE_CENTER_PENDING_COMPOSING_MESSAGE)) { String messageText = prefs.getString(Constants.PREF_KEY_MESSAGE_CENTER_PENDING_COMPOSING_MESSAGE, null); - if (messageText != null && messageEditText != null) { - messageEditText.setText(messageText); + if (messageText != null && this.composerEditText != null) { + this.composerEditText.setText(messageText); } // Stored pending composing text has been restored, remove it from the persistent storage SharedPreferences.Editor editor = prefs.edit(); @@ -958,8 +930,14 @@ public void onComposingViewCreated(View keyboardFocusedOnView) { } messageCenterRecyclerView.setPadding(0, 0, 0, 0); - if (keyboardFocusedOnView != null) { - Util.showSoftKeyboard(hostingActivityRef.get(), keyboardFocusedOnView); + if (composerEditText != null) { + composerEditText.requestFocus(); + composerEditText.post(new Runnable() { + @Override + public void run() { + Util.showSoftKeyboard(hostingActivityRef.get(), composerEditText); + } + }); } } @@ -996,9 +974,6 @@ public void afterComposingTextChanged(String message) { @Override public void onCancelComposing() { - if (messageCenterRecyclerViewAdapter != null) { - messageCenterRecyclerViewAdapter.setForceShowKeyboard(false); - } Util.hideSoftKeyboard(hostingActivityRef.get(), getView()); JSONObject data = new JSONObject(); @@ -1031,9 +1006,6 @@ public void onCancelComposing() { public void onFinishComposing() { messagingActionHandler.sendEmptyMessage(MSG_REMOVE_COMPOSER); - if (messageCenterRecyclerViewAdapter != null) { - messageCenterRecyclerViewAdapter.setForceShowKeyboard(false); - } Util.hideSoftKeyboard(hostingActivityRef.get(), getView()); if (contextMessage != null) { // TODO: Maybe simply send any context messages in the list when a message is sent? @@ -1108,9 +1080,6 @@ public void onCloseWhoCard(String buttonLabel) { public void cleanupWhoCard() { messagingActionHandler.sendEmptyMessage(MSG_MESSAGE_REMOVE_WHOCARD); - if (messageCenterRecyclerViewAdapter != null) { - messageCenterRecyclerViewAdapter.setForceShowKeyboard(false); - } Util.hideSoftKeyboard(hostingActivityRef.get(), getView()); whoCardItem = null; pendingWhoCardName = null; @@ -1152,15 +1121,16 @@ public void onScroll(AbsListView view, int firstVisibleItem, int visibleItemCoun public void OnListViewResize(int w, int h, int oldw, int oldh) { // detect keyboard launching. If height difference is more than 100 pixels, probably due to keyboard if (oldh > h && oldh - h > 100) { - if (composer != null) { +/* TODO: Replace this? + if (messageCenterRecyclerViewAdapter.getComposerEditText() != null) { // When keyboard is up, adjust the scolling such that the cursor is always visible final int firstIndex = messageCenterRecyclerView.getFirstVisiblePosition(); int lastIndex = messageCenterRecyclerView.getLastVisiblePosition(); View v = messageCenterRecyclerView.getChildAt(lastIndex - firstIndex); int top = (v == null) ? 0 : v.getTop(); - if (messageEditText != null) { - int pos = messageEditText.getSelectionStart(); - Layout layout = messageEditText.getLayout(); + if (composerEditText != null) { + int pos = composerEditText.getSelectionStart(); + Layout layout = composerEditText.getLayout(); int line = layout.getLineForOffset(pos); int baseline = layout.getLineBaseline(line); int ascent = layout.getLineAscent(line); @@ -1173,6 +1143,7 @@ public void OnListViewResize(int w, int h, int oldw, int oldh) { } } } +*/ } } @@ -1212,7 +1183,7 @@ private void saveWhoCardSetState() { // Retrieve the content from the composing area public Editable getPendingComposingContent() { - return (messageEditText == null) ? null : messageEditText.getText(); + return (composerEditText == null) ? null : composerEditText.getText(); } @@ -1256,10 +1227,10 @@ public void clearPendingComposingMessage() { private Parcelable saveEditTextInstanceState() { savePendingComposingMessage(); - if (messageEditText != null) { + if (composerEditText != null) { // Hide keyboard if the keyboard was up prior to rotation Util.hideSoftKeyboard(hostingActivityRef.get(), getView()); - return messageEditText.onSaveInstanceState(); + return composerEditText.onSaveInstanceState(); } return null; } @@ -1435,7 +1406,7 @@ public void onRequestPermissionsResult(int requestCode, String[] permissions, in /* - * Called when attachment overlayed "selection" ui is tapped. The "selection" ui could be selection checkbox + * Called when attachment overlaid "selection" ui is tapped. The "selection" ui could be selection checkbox * or close button */ @Override @@ -1475,7 +1446,6 @@ public void handleMessage(Message msg) { case MSG_MESSAGE_ADD_WHOCARD: { // msg.arg1 is either WHO_CARD_MODE_INIT or WHO_CARD_MODE_EDIT fragment.addWhoCardAsMessageItem(msg.arg1); - fragment.messageCenterRecyclerViewAdapter.setForceShowKeyboard(true); fragment.messageCenterRecyclerViewAdapter.notifyItemInserted(fragment.messages.size() - 1); fragment.messageCenterRecyclerView.setSelection(fragment.messages.size() - 1); break; @@ -1495,8 +1465,8 @@ public void handleMessage(Message msg) { break; } case MSG_MESSAGE_ADD_COMPOSING: { - fragment.addComposerMessageItems(); - fragment.messageCenterRecyclerViewAdapter.setForceShowKeyboard(true); + //fragment.addComposerMessageItems(); + fragment.messages.add(fragment.interaction.getComposer()); fragment.messageCenterRecyclerViewAdapter.notifyItemInserted(fragment.messages.size() - 1); fragment.messageCenterRecyclerView.setSelection(fragment.messages.size() - 1); break; diff --git a/apptentive/src/main/java/com/apptentive/android/sdk/module/messagecenter/view/MessageAdapter.java b/apptentive/src/main/java/com/apptentive/android/sdk/module/messagecenter/view/MessageAdapter.java index ea0e19a81..43b1a23b2 100644 --- a/apptentive/src/main/java/com/apptentive/android/sdk/module/messagecenter/view/MessageAdapter.java +++ b/apptentive/src/main/java/com/apptentive/android/sdk/module/messagecenter/view/MessageAdapter.java @@ -115,7 +115,7 @@ public class MessageAdapter e private OnListviewItemActionListener composingActionListener; public interface OnListviewItemActionListener { - void onComposingViewCreated(View keyboardFocusedView); + void onComposingViewCreated(EditText composerEditText); void updateComposingBar(); diff --git a/apptentive/src/main/java/com/apptentive/android/sdk/module/messagecenter/view/MessageCenterRecyclerViewAdapter.java b/apptentive/src/main/java/com/apptentive/android/sdk/module/messagecenter/view/MessageCenterRecyclerViewAdapter.java index 0139769dc..80d232a22 100644 --- a/apptentive/src/main/java/com/apptentive/android/sdk/module/messagecenter/view/MessageCenterRecyclerViewAdapter.java +++ b/apptentive/src/main/java/com/apptentive/android/sdk/module/messagecenter/view/MessageCenterRecyclerViewAdapter.java @@ -133,6 +133,9 @@ public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) { Composer composer = (Composer) messages.get(position); MessageComposerHolder composerHolder = (MessageComposerHolder) holder; composerHolder.bindView(fragment, this, composer); + if (listener != null) { + listener.onComposingViewCreated(composerHolder.message); + } break; } case STATUS: { @@ -254,10 +257,6 @@ public void addImagestoComposer(List images) { return; // TODO } - public void setForceShowKeyboard(boolean force) { - return; // TODO - } - public void removeImageFromComposer(int position) { return; // TODO } @@ -274,10 +273,6 @@ public View getComposingAreaView() { return new View(fragment.getContext()); // TODO } - public EditText getEditTextInComposing() { - return new EditText(fragment.getContext()); // TODO - } - public MessageAdapter.OnListviewItemActionListener getListener() { return listener; } From 6d90a45099ac8136a9bbffd958349c18d817a9e8 Mon Sep 17 00:00:00 2001 From: skykelsey Date: Wed, 2 Nov 2016 10:58:55 -0700 Subject: [PATCH 015/100] Remove redundant code. --- .../interaction/fragment/MessageCenterFragment.java | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/apptentive/src/main/java/com/apptentive/android/sdk/module/engagement/interaction/fragment/MessageCenterFragment.java b/apptentive/src/main/java/com/apptentive/android/sdk/module/engagement/interaction/fragment/MessageCenterFragment.java index 4737650bd..87ee0589c 100644 --- a/apptentive/src/main/java/com/apptentive/android/sdk/module/engagement/interaction/fragment/MessageCenterFragment.java +++ b/apptentive/src/main/java/com/apptentive/android/sdk/module/engagement/interaction/fragment/MessageCenterFragment.java @@ -437,9 +437,7 @@ else if (pendingWhoCardName != null || pendingWhoCardEmail != null || pendingWho * If Who Card is required, show Who Card first */ if (messages.size() == 1) { // TODO: Don't use these magic numbers everywhere - messagingActionHandler.sendEmptyMessage(MSG_REMOVE_STATUS); - messagingActionHandler.sendEmptyMessage(MSG_MESSAGE_ADD_COMPOSING); - + addComposingCard(); } else { // Finally check if status message need to be restored addExpectationStatusIfNeeded(); From be1fbdfc8b804772580677fc42d4df79f3fc9163 Mon Sep 17 00:00:00 2001 From: skykelsey Date: Wed, 2 Nov 2016 12:24:35 -0700 Subject: [PATCH 016/100] Save and restore state of who card. Apply focus to name. --- .../fragment/MessageCenterFragment.java | 32 +++++++++++++------ .../messagecenter/view/MessageAdapter.java | 2 +- .../view/holder/WhoCardHolder.java | 7 ++-- 3 files changed, 29 insertions(+), 12 deletions(-) diff --git a/apptentive/src/main/java/com/apptentive/android/sdk/module/engagement/interaction/fragment/MessageCenterFragment.java b/apptentive/src/main/java/com/apptentive/android/sdk/module/engagement/interaction/fragment/MessageCenterFragment.java index 87ee0589c..3ff471999 100644 --- a/apptentive/src/main/java/com/apptentive/android/sdk/module/engagement/interaction/fragment/MessageCenterFragment.java +++ b/apptentive/src/main/java/com/apptentive/android/sdk/module/engagement/interaction/fragment/MessageCenterFragment.java @@ -119,12 +119,15 @@ public class MessageCenterFragment extends ApptentiveBaseFragment hostingActivityRef; private MessageCenterRecyclerView messageCenterRecyclerView; private EditText composerEditText; + private EditText whoCardNameEditText; + private EditText whoCardEmailEditText; + private View fab; @@ -169,7 +172,6 @@ public class MessageCenterFragment extends ApptentiveBaseFragment Date: Wed, 2 Nov 2016 12:43:04 -0700 Subject: [PATCH 017/100] Properly hide the FAB when the Who Card or Composer on on screen. --- .../fragment/MessageCenterFragment.java | 20 ++++++++++++++----- 1 file changed, 15 insertions(+), 5 deletions(-) diff --git a/apptentive/src/main/java/com/apptentive/android/sdk/module/engagement/interaction/fragment/MessageCenterFragment.java b/apptentive/src/main/java/com/apptentive/android/sdk/module/engagement/interaction/fragment/MessageCenterFragment.java index 3ff471999..19d90d9b0 100644 --- a/apptentive/src/main/java/com/apptentive/android/sdk/module/engagement/interaction/fragment/MessageCenterFragment.java +++ b/apptentive/src/main/java/com/apptentive/android/sdk/module/engagement/interaction/fragment/MessageCenterFragment.java @@ -869,7 +869,7 @@ public void updateComposingBar() { @Override public void onComposingViewCreated(final EditText composerEditText) { - + ApptentiveLog.e("onComposingViewCreated()"); EngagementModule.engageInternal(hostingActivityRef.get(), interaction, MessageCenterInteraction.EVENT_NAME_COMPOSE_OPEN); this.composerEditText = composerEditText; @@ -939,6 +939,7 @@ public void run() { } }); } + hideFab(); } @Override @@ -966,6 +967,7 @@ public void run() { }); } + hideFab(); } @Override @@ -1062,6 +1064,7 @@ private void removeItemsFromRecyclerView(int type) { @Override public void onSubmitWhoCard(String buttonLabel) { + ApptentiveLog.e("onSubmitWhoCard()"); JSONObject data = new JSONObject(); try { data.put("required", interaction.getWhoCardRequired()); @@ -1076,6 +1079,7 @@ public void onSubmitWhoCard(String buttonLabel) { @Override public void onCloseWhoCard(String buttonLabel) { + ApptentiveLog.e("onCloseWhoCard()"); JSONObject data = new JSONObject(); try { data.put("required", interaction.getWhoCardRequired()); @@ -1320,16 +1324,22 @@ private int calculateFabPadding(Context context) { } private void showFab() { + ApptentiveLog.e("showFab()"); messageCenterRecyclerView.setPadding(0, 0, 0, fabPaddingPixels); // Re-enable Fab at the beginning of the animation - fab.setEnabled(true); - AnimationUtil.scaleFadeIn(fab); + if (fab.getVisibility() != View.VISIBLE) { + fab.setEnabled(true); + AnimationUtil.scaleFadeIn(fab); + } } private void hideFab() { + ApptentiveLog.e("hideFab()"); // Make sure Fab is not clickable during fade-out animation - fab.setEnabled(false); - AnimationUtil.scaleFadeOutGone(fab); + if (fab.getVisibility() != View.GONE) { + fab.setEnabled(false); + AnimationUtil.scaleFadeOutGone(fab); + } } private void showProfileButton() { From 6d8ccea1a94f8c6f56a8615e969a1875d91cbea8 Mon Sep 17 00:00:00 2001 From: skykelsey Date: Wed, 2 Nov 2016 21:11:51 -0700 Subject: [PATCH 018/100] Get message attachment display and state save/restore working in composer. --- .../fragment/MessageCenterFragment.java | 224 ++++++++---------- .../messagecenter/view/MessageAdapter.java | 6 +- .../MessageCenterRecyclerViewAdapter.java | 14 +- .../view/holder/MessageComposerHolder.java | 21 +- .../sdk/util/image/ImageGridViewAdapter.java | 1 + 5 files changed, 126 insertions(+), 140 deletions(-) diff --git a/apptentive/src/main/java/com/apptentive/android/sdk/module/engagement/interaction/fragment/MessageCenterFragment.java b/apptentive/src/main/java/com/apptentive/android/sdk/module/engagement/interaction/fragment/MessageCenterFragment.java index 19d90d9b0..a936ef51e 100644 --- a/apptentive/src/main/java/com/apptentive/android/sdk/module/engagement/interaction/fragment/MessageCenterFragment.java +++ b/apptentive/src/main/java/com/apptentive/android/sdk/module/engagement/interaction/fragment/MessageCenterFragment.java @@ -59,11 +59,13 @@ import com.apptentive.android.sdk.module.messagecenter.view.MessageCenterListView; import com.apptentive.android.sdk.module.messagecenter.view.MessageCenterRecyclerView; import com.apptentive.android.sdk.module.messagecenter.view.MessageCenterRecyclerViewAdapter; +import com.apptentive.android.sdk.module.messagecenter.view.holder.MessageComposerHolder; import com.apptentive.android.sdk.module.metric.MetricModule; import com.apptentive.android.sdk.util.AnimationUtil; import com.apptentive.android.sdk.util.Constants; import com.apptentive.android.sdk.util.Util; import com.apptentive.android.sdk.util.image.ApptentiveAttachmentLoader; +import com.apptentive.android.sdk.util.image.ApptentiveImageGridView; import com.apptentive.android.sdk.util.image.ImageGridViewAdapter; import com.apptentive.android.sdk.util.image.ImageItem; @@ -124,6 +126,7 @@ public class MessageCenterFragment extends ApptentiveBaseFragment hostingActivityRef; private MessageCenterRecyclerView messageCenterRecyclerView; + private MessageComposerHolder composer; private EditText composerEditText; private EditText whoCardNameEditText; private EditText whoCardEmailEditText; @@ -143,18 +146,18 @@ public class MessageCenterFragment extends ApptentiveBaseFragment imageAttachmentstList = new ArrayList(); + //private ArrayList imageAttachmentstList = new ArrayList(); /** * Used to save the state of the message text box if the user closes Message Center for a moment, * , rotate device, attaches a file, etc. */ private Parcelable composingViewSavedState; - private ArrayList savedAttachmentstList; + private ArrayList pendingAttachments = new ArrayList(); /* * Set to true when user launches image picker, and set to false once an image is picked @@ -205,28 +208,19 @@ public static MessageCenterFragment newInstance(Bundle bundle) { public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); - // Make Message Center frgament retain its instance on orientation change + // Make Message Center fragment retain its instance on orientation change setRetainInstance(true); } @Override - public View onCreateView(LayoutInflater inflater, ViewGroup container, - Bundle savedInstanceState) { - listViewSavedTopIndex = (savedInstanceState == null) ? -1 : - savedInstanceState.getInt(LIST_TOP_INDEX); - listViewSavedTopOffset = (savedInstanceState == null) ? 0 : - savedInstanceState.getInt(LIST_TOP_OFFSET); - composingViewSavedState = (savedInstanceState == null) ? null : - savedInstanceState.getParcelable(COMPOSING_EDITTEXT_STATE); - pendingWhoCardName = (savedInstanceState == null) ? null : - savedInstanceState.getParcelable(WHO_CARD_NAME); - pendingWhoCardEmail = (savedInstanceState == null) ? null : - savedInstanceState.getParcelable(WHO_CARD_EMAIL); - pendingWhoCardAvatarFile = (savedInstanceState == null) ? null : - savedInstanceState.getString(WHO_CARD_AVATAR_FILE); - pendingWhoCardMode = (savedInstanceState == null) ? 0 : - savedInstanceState.getInt(WHO_CARD_MODE); - + public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { + listViewSavedTopIndex = (savedInstanceState == null) ? -1 : savedInstanceState.getInt(LIST_TOP_INDEX); + listViewSavedTopOffset = (savedInstanceState == null) ? 0 : savedInstanceState.getInt(LIST_TOP_OFFSET); + composingViewSavedState = (savedInstanceState == null) ? null : savedInstanceState.getParcelable(COMPOSING_EDITTEXT_STATE); + pendingWhoCardName = (savedInstanceState == null) ? null : savedInstanceState.getParcelable(WHO_CARD_NAME); + pendingWhoCardEmail = (savedInstanceState == null) ? null : savedInstanceState.getParcelable(WHO_CARD_EMAIL); + pendingWhoCardAvatarFile = (savedInstanceState == null) ? null : savedInstanceState.getString(WHO_CARD_AVATAR_FILE); + pendingWhoCardMode = (savedInstanceState == null) ? 0 : savedInstanceState.getInt(WHO_CARD_MODE); return inflater.inflate(R.layout.apptentive_message_center, container, false); } @@ -247,8 +241,7 @@ public void onViewCreated(View view, Bundle onSavedInstanceState) { // Needed to prevent the window from being pushed up when a text input area is focused. - getActivity().getWindow().setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_STATE_UNCHANGED | - WindowManager.LayoutParams.SOFT_INPUT_ADJUST_RESIZE); + getActivity().getWindow().setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_STATE_UNCHANGED | WindowManager.LayoutParams.SOFT_INPUT_ADJUST_RESIZE); // Restore listview scroll offset to where it was before rotation if (listViewSavedTopIndex != -1) { @@ -466,6 +459,37 @@ else if (pendingWhoCardName != null || pendingWhoCardEmail != null || pendingWho // Calculate FAB y-offset fabPaddingPixels = calculateFabPadding(rootView.getContext()); attachmentsAllowed = rootView.getContext().getResources().getInteger(R.integer.apptentive_image_grid_default_attachments_total); + + // Retrieve any saved attachments + final SharedPreferences prefs = ApptentiveInternal.getInstance().getSharedPrefs(); + if (prefs.contains(Constants.PREF_KEY_MESSAGE_CENTER_PENDING_COMPOSING_ATTACHMENTS)) { + JSONArray savedAttachmentsJsonArray = null; + try { + savedAttachmentsJsonArray = new JSONArray(prefs.getString(Constants.PREF_KEY_MESSAGE_CENTER_PENDING_COMPOSING_ATTACHMENTS, "")); + } catch (JSONException e) { + e.printStackTrace(); + } + if (savedAttachmentsJsonArray != null && savedAttachmentsJsonArray.length() > 0) { + if (pendingAttachments == null) { + pendingAttachments = new ArrayList(); + } else { + pendingAttachments.clear(); + } + for (int i = 0; i < savedAttachmentsJsonArray.length(); i++) { + try { + JSONObject savedAttachmentJson = savedAttachmentsJsonArray.getJSONObject(i); + if (savedAttachmentJson != null) { + pendingAttachments.add(new ImageItem(savedAttachmentJson)); + } + } catch (JSONException e) { + continue; + } + } + } + // Stored pending attachemnts have been restored, remove it from the persistent storage + SharedPreferences.Editor editor = prefs.edit(); + editor.remove(Constants.PREF_KEY_MESSAGE_CENTER_PENDING_COMPOSING_ATTACHMENTS).apply(); + } } public boolean onMenuItemClick(MenuItem menuItem) { @@ -492,6 +516,7 @@ public boolean onMenuItemClick(MenuItem menuItem) { @Override public void onSaveInstanceState(Bundle outState) { + savePendingComposingMessage(); //int index = messageCenterRecyclerView.getFirstVisiblePosition(); View v = messageCenterRecyclerView.getChildAt(0); int top = (v == null) ? 0 : (v.getTop() - messageCenterRecyclerView.getPaddingTop()); @@ -508,6 +533,7 @@ public void onSaveInstanceState(Bundle outState) { } public boolean onBackPressed(boolean hardwareButton) { + savePendingComposingMessage(); ApptentiveViewActivity hostingActivity = (ApptentiveViewActivity) hostingActivityRef.get(); if (hostingActivity != null) { DialogFragment myFrag = (DialogFragment) (hostingActivity.getSupportFragmentManager()).findFragmentByTag(DIALOG_IMAGE_PREVIEW); @@ -526,7 +552,6 @@ public boolean onBackPressed(boolean hardwareButton) { } public boolean cleanup() { - savePendingComposingMessage(); clearPendingMessageCenterPushNotification(); clearWhoCardUi(null, null, 0); // Set to null, otherwise they will hold reference to the activity context @@ -572,7 +597,7 @@ public void addComposingCard() { messagingActionHandler.removeMessages(MSG_MESSAGE_ADD_COMPOSING); messagingActionHandler.sendEmptyMessage(MSG_REMOVE_STATUS); messagingActionHandler.sendEmptyMessage(MSG_MESSAGE_ADD_COMPOSING); - messagingActionHandler.sendEmptyMessage(MSG_SCROLL_TO_BOTTOM); + //messagingActionHandler.sendEmptyMessage(MSG_SCROLL_TO_BOTTOM); } private boolean checkAddWhoCardIfRequired() { @@ -600,7 +625,7 @@ public void addWhoCard(int mode) { messagingActionHandler.removeMessages(MSG_MESSAGE_ADD_COMPOSING); messagingActionHandler.sendEmptyMessage(MSG_REMOVE_STATUS); messagingActionHandler.sendMessage(messagingActionHandler.obtainMessage(MSG_MESSAGE_ADD_WHOCARD, mode, 0)); - messagingActionHandler.sendEmptyMessage(MSG_SCROLL_TO_BOTTOM); + //messagingActionHandler.sendEmptyMessage(MSG_SCROLL_TO_BOTTOM); } public void addWhoCardAsMessageItem(int mode) { @@ -683,14 +708,13 @@ public void displayNewIncomingMessageItem(ApptentiveMessage message) { public void addAttachmentsToComposer(final List images) { - int numberOfExistingAttachments = imageAttachmentstList.size(); - ArrayList uniqueImages = new ArrayList(); + ArrayList newImages = new ArrayList(); // only add new images, and filter out duplicates if (images != null && images.size() > 0) { for (ImageItem newImage : images) { boolean bDupFound = false; - for (ImageItem existingImage : imageAttachmentstList) { - if (newImage.originalPath.equals(existingImage.originalPath)) { + for (ImageItem pendingAttachment : pendingAttachments) { + if (newImage.originalPath.equals(pendingAttachment.originalPath)) { bDupFound = true; break; } @@ -698,59 +722,48 @@ public void addAttachmentsToComposer(final List images) { if (bDupFound) { continue; } else { - uniqueImages.add(newImage); + pendingAttachments.add(newImage); + newImages.add(newImage); } } } - if (uniqueImages.size() == 0) { - return; - } - imageAttachmentstList.addAll(uniqueImages); - // New attachments are added to a composer with no prior attachment - if (imageAttachmentstList.size() > 0 && numberOfExistingAttachments == 0) { - EngagementModule.engageInternal(hostingActivityRef.get(), interaction, MessageCenterInteraction.EVENT_NAME_ATTACHMENT_LIST_SHOWN); - } - EngagementModule.engageInternal(hostingActivityRef.get(), interaction, MessageCenterInteraction.EVENT_NAME_ATTACHMENT_ADD); - View v = messageCenterRecyclerView.getChildAt(0); int top = (v == null) ? 0 : v.getTop(); + if (messageCenterRecyclerViewAdapter != null) { // Only update composing view if image is attached successfully - messageCenterRecyclerViewAdapter.addImagestoComposer(uniqueImages); - messageCenterRecyclerViewAdapter.notifyDataSetChanged(); + messageCenterRecyclerViewAdapter.addImagestoComposer(composer, newImages); + //messageCenterRecyclerViewAdapter.notify(); } int firstIndex = messageCenterRecyclerView.getFirstVisiblePosition(); - messagingActionHandler.sendMessage(messagingActionHandler.obtainMessage(MSG_SCROLL_FROM_TOP, - firstIndex, top)); - - updateComposingBar(); + messagingActionHandler.sendMessage(messagingActionHandler.obtainMessage(MSG_SCROLL_FROM_TOP, firstIndex, top)); } - public void restoreSavedAttachmentsToComposer(final List images) { - imageAttachmentstList.clear(); - imageAttachmentstList.addAll(images); + public void setAttachmentsInComposer(final List images) { + ApptentiveLog.e("setAttachmentsInComposer()"); View v = messageCenterRecyclerView.getChildAt(0); int top = (v == null) ? 0 : v.getTop(); // Only update composing view if image is attached successfully if (messageCenterRecyclerViewAdapter != null) { - messageCenterRecyclerViewAdapter.addImagestoComposer(images); + ApptentiveLog.e("Restoring attachments"); + messageCenterRecyclerViewAdapter.addImagestoComposer(composer, images); } int firstIndex = messageCenterRecyclerView.getFirstVisiblePosition(); +/* if (messageCenterRecyclerViewAdapter != null) { messageCenterRecyclerViewAdapter.notifyDataSetChanged(); } - messagingActionHandler.sendMessage(messagingActionHandler.obtainMessage(MSG_SCROLL_FROM_TOP, - firstIndex, top)); - updateComposingBar(); +*/ + messagingActionHandler.sendMessage(messagingActionHandler.obtainMessage(MSG_SCROLL_FROM_TOP, firstIndex, top)); } public void removeImageFromComposer(final int position) { EngagementModule.engageInternal(hostingActivityRef.get(), interaction, MessageCenterInteraction.EVENT_NAME_ATTACHMENT_DELETE); - imageAttachmentstList.remove(position); + pendingAttachments.remove(position); if (messageCenterRecyclerViewAdapter != null) { - messageCenterRecyclerViewAdapter.removeImageFromComposer(position); - int count = imageAttachmentstList.size(); + messageCenterRecyclerViewAdapter.removeImageFromComposer(composer, position); +// int count = imageAttachmentstList.size(); // Show keyboard if all attachments have been removed messageCenterRecyclerViewAdapter.notifyDataSetChanged(); } @@ -868,10 +881,11 @@ public void updateComposingBar() { } @Override - public void onComposingViewCreated(final EditText composerEditText) { + public void onComposingViewCreated(MessageComposerHolder composer, final EditText composerEditText, final ApptentiveImageGridView attachments) { ApptentiveLog.e("onComposingViewCreated()"); EngagementModule.engageInternal(hostingActivityRef.get(), interaction, MessageCenterInteraction.EVENT_NAME_COMPOSE_OPEN); + this.composer = composer; this.composerEditText = composerEditText; SharedPreferences prefs = ApptentiveInternal.getInstance().getSharedPrefs(); @@ -895,39 +909,8 @@ public void onComposingViewCreated(final EditText composerEditText) { editor.remove(Constants.PREF_KEY_MESSAGE_CENTER_PENDING_COMPOSING_MESSAGE).apply(); } + setAttachmentsInComposer(pendingAttachments); - // Restore composing attachments - if (prefs.contains(Constants.PREF_KEY_MESSAGE_CENTER_PENDING_COMPOSING_ATTACHMENTS)) { - JSONArray jArray = null; - try { - jArray = new JSONArray(prefs.getString(Constants.PREF_KEY_MESSAGE_CENTER_PENDING_COMPOSING_ATTACHMENTS, "")); - } catch (JSONException e) { - e.printStackTrace(); - } - if (jArray != null && jArray.length() > 0) { - if (savedAttachmentstList == null) { - savedAttachmentstList = new ArrayList(); - } - for (int i = 0; i < jArray.length(); i++) { - try { - JSONObject json = jArray.getJSONObject(i); - if (json != null) { - savedAttachmentstList.add(new ImageItem(json)); - } - } catch (JSONException e) { - continue; - } - } - } - // Stored pending attachemnts have been restored, remove it from the persistent storage - SharedPreferences.Editor editor = prefs.edit(); - editor.remove(Constants.PREF_KEY_MESSAGE_CENTER_PENDING_COMPOSING_ATTACHMENTS).apply(); - } - - if (savedAttachmentstList != null) { - restoreSavedAttachmentsToComposer(savedAttachmentstList); - savedAttachmentstList = null; - } messageCenterRecyclerView.setPadding(0, 0, 0, 0); if (composerEditText != null) { @@ -981,7 +964,7 @@ public void onComposingTextChanged(CharSequence str) { @Override public void afterComposingTextChanged(String message) { - pendingMessage = message; + //pendingMessage = message; } @Override @@ -998,18 +981,13 @@ public void onCancelComposing() { } EngagementModule.engageInternal(hostingActivityRef.get(), interaction, MessageCenterInteraction.EVENT_NAME_COMPOSE_CLOSE, data.toString()); messagingActionHandler.sendMessage(messagingActionHandler.obtainMessage(MSG_REMOVE_COMPOSER)); - - // TODO: Remove Composer - // TODO: Remove context message - // TODO: Clear composer - // TODO: Clear any saved state like attachments, saved message state. - // TODO: Show FAB - // TODO: Show Profile Button if (messageCenterRecyclerViewAdapter != null) { addExpectationStatusIfNeeded(); } - imageAttachmentstList.clear(); - pendingMessage = null; + pendingAttachments.clear(); + composerEditText.getText().clear(); + //pendingMessage = null; + clearPendingComposingMessage(); showFab(); showProfileButton(); } @@ -1026,28 +1004,20 @@ public void onFinishComposing() { messagingActionHandler.sendMessage(sendContextMessage); contextMessage = null; } - - - if (!pendingMessage.isEmpty() || imageAttachmentstList.size() != 0) { - + if (!TextUtils.isEmpty(composerEditText.getText()) || pendingAttachments.size() > 0) { Bundle b = new Bundle(); - b.putString(COMPOSING_EDITTEXT_STATE, pendingMessage); - b.putParcelableArrayList(COMPOSING_ATTACHMENTS, imageAttachmentstList); - Message msg = messagingActionHandler.obtainMessage(MSG_START_SENDING, pendingMessage); + b.putString(COMPOSING_EDITTEXT_STATE, composerEditText.getText().toString()); + b.putParcelableArrayList(COMPOSING_ATTACHMENTS, new ArrayList(pendingAttachments)); + Message msg = messagingActionHandler.obtainMessage(MSG_START_SENDING, composerEditText.getText().toString()); msg.setData(b); ApptentiveLog.e("Send Send Message Message"); unsentMessagesCount++; messagingActionHandler.sendMessage(msg); - pendingMessage = null; - } - - // Add status if needed? -/* - if (messageCenterRecyclerViewAdapter != null) { - addExpectationStatusIfNeeded(); + //pendingMessage = null; + composerEditText.getText().clear(); + pendingAttachments.clear(); + clearPendingComposingMessage(); } -*/ - showFab(); showProfileButton(); } @@ -1213,17 +1183,14 @@ public void savePendingComposingMessage() { editor.remove(Constants.PREF_KEY_MESSAGE_CENTER_PENDING_COMPOSING_MESSAGE); } - JSONArray jArray = new JSONArray(); + JSONArray pendingAttachmentsJsonArray = new JSONArray(); // Save pending attachment - for (ImageItem pendingAttachment : imageAttachmentstList) { - JSONObject jobject = pendingAttachment.toJSON(); - if (jobject != null) { - jArray.put(jobject); - } + for (ImageItem pendingAttachment : pendingAttachments) { + pendingAttachmentsJsonArray.put(pendingAttachment.toJSON()); } - if (jArray.length() > 0) { - editor.putString(Constants.PREF_KEY_MESSAGE_CENTER_PENDING_COMPOSING_ATTACHMENTS, jArray.toString()); + if (pendingAttachmentsJsonArray.length() > 0) { + editor.putString(Constants.PREF_KEY_MESSAGE_CENTER_PENDING_COMPOSING_ATTACHMENTS, pendingAttachmentsJsonArray.toString()); } else { editor.remove(Constants.PREF_KEY_MESSAGE_CENTER_PENDING_COMPOSING_ATTACHMENTS); } @@ -1235,14 +1202,13 @@ public void savePendingComposingMessage() { */ public void clearPendingComposingMessage() { SharedPreferences prefs = ApptentiveInternal.getInstance().getSharedPrefs(); - SharedPreferences.Editor editor = prefs.edit(); - editor.remove(Constants.PREF_KEY_MESSAGE_CENTER_PENDING_COMPOSING_MESSAGE); - editor.remove(Constants.PREF_KEY_MESSAGE_CENTER_PENDING_COMPOSING_ATTACHMENTS); - editor.apply(); + prefs.edit() + .remove(Constants.PREF_KEY_MESSAGE_CENTER_PENDING_COMPOSING_MESSAGE) + .remove(Constants.PREF_KEY_MESSAGE_CENTER_PENDING_COMPOSING_ATTACHMENTS) + .apply(); } private Parcelable saveEditTextInstanceState() { - savePendingComposingMessage(); if (composerEditText != null) { // Hide keyboard if the keyboard was up prior to rotation Util.hideSoftKeyboard(hostingActivityRef.get(), getView()); diff --git a/apptentive/src/main/java/com/apptentive/android/sdk/module/messagecenter/view/MessageAdapter.java b/apptentive/src/main/java/com/apptentive/android/sdk/module/messagecenter/view/MessageAdapter.java index 5594ca3d7..52f3fe930 100644 --- a/apptentive/src/main/java/com/apptentive/android/sdk/module/messagecenter/view/MessageAdapter.java +++ b/apptentive/src/main/java/com/apptentive/android/sdk/module/messagecenter/view/MessageAdapter.java @@ -40,9 +40,11 @@ import com.apptentive.android.sdk.module.messagecenter.view.holder.AutomatedMessageHolder; import com.apptentive.android.sdk.module.messagecenter.view.holder.IncomingCompoundMessageHolder; import com.apptentive.android.sdk.module.messagecenter.view.holder.MessageCenterListItemHolder; +import com.apptentive.android.sdk.module.messagecenter.view.holder.MessageComposerHolder; import com.apptentive.android.sdk.module.messagecenter.view.holder.OutgoingCompoundMessageHolder; import com.apptentive.android.sdk.module.messagecenter.view.holder.StatusHolder; import com.apptentive.android.sdk.util.AnimationUtil; +import com.apptentive.android.sdk.util.image.ApptentiveImageGridView; import com.apptentive.android.sdk.util.image.ImageItem; import com.apptentive.android.sdk.util.image.ImageUtil; import com.apptentive.android.sdk.util.Util; @@ -115,7 +117,7 @@ public class MessageAdapter e private OnListviewItemActionListener composingActionListener; public interface OnListviewItemActionListener { - void onComposingViewCreated(EditText composerEditText); + void onComposingViewCreated(MessageComposerHolder composer, EditText composerEditText, ApptentiveImageGridView attachments); void updateComposingBar(); @@ -508,7 +510,7 @@ public void onAnimationRepeat(Animator animation) { @Override public void onAnimationEnd(Animator animation) { - composingActionListener.onComposingViewCreated(forceShowKeyboard ? composingEditText : null); +// composingActionListener.onComposingViewCreated(forceShowKeyboard ? composingEditText : null); if (updateComposingViewImageBand) { updateComposingViewImageBand = false; } diff --git a/apptentive/src/main/java/com/apptentive/android/sdk/module/messagecenter/view/MessageCenterRecyclerViewAdapter.java b/apptentive/src/main/java/com/apptentive/android/sdk/module/messagecenter/view/MessageCenterRecyclerViewAdapter.java index 80d232a22..fae5a572a 100644 --- a/apptentive/src/main/java/com/apptentive/android/sdk/module/messagecenter/view/MessageCenterRecyclerViewAdapter.java +++ b/apptentive/src/main/java/com/apptentive/android/sdk/module/messagecenter/view/MessageCenterRecyclerViewAdapter.java @@ -133,9 +133,6 @@ public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) { Composer composer = (Composer) messages.get(position); MessageComposerHolder composerHolder = (MessageComposerHolder) holder; composerHolder.bindView(fragment, this, composer); - if (listener != null) { - listener.onComposingViewCreated(composerHolder.message); - } break; } case STATUS: { @@ -253,12 +250,15 @@ public String getWhoCardAvatarFileName() { return null; // TODO } - public void addImagestoComposer(List images) { - return; // TODO + public void addImagestoComposer(MessageComposerHolder composer, List images) { + composer.addImagesToImageAttachmentBand(images); + //notifyDataSetChanged(); } - public void removeImageFromComposer(int position) { - return; // TODO + public void removeImageFromComposer(MessageComposerHolder composer, int position) { + if (composer != null) { + composer.removeImageFromImageAttachmentBand(position); + } } public View getWhoCardView() { diff --git a/apptentive/src/main/java/com/apptentive/android/sdk/module/messagecenter/view/holder/MessageComposerHolder.java b/apptentive/src/main/java/com/apptentive/android/sdk/module/messagecenter/view/holder/MessageComposerHolder.java index 0f23ed0ab..0686fb5ba 100644 --- a/apptentive/src/main/java/com/apptentive/android/sdk/module/messagecenter/view/holder/MessageComposerHolder.java +++ b/apptentive/src/main/java/com/apptentive/android/sdk/module/messagecenter/view/holder/MessageComposerHolder.java @@ -29,6 +29,7 @@ import android.widget.ImageButton; import android.widget.TextView; +import com.apptentive.android.sdk.ApptentiveLog; import com.apptentive.android.sdk.R; import com.apptentive.android.sdk.module.engagement.interaction.fragment.MessageCenterFragment; import com.apptentive.android.sdk.module.messagecenter.model.Composer; @@ -66,6 +67,7 @@ public MessageComposerHolder(View itemView) { } public void bindView(final MessageCenterFragment fragment, final MessageCenterRecyclerViewAdapter adapter, final Composer composer) { + ApptentiveLog.e("BINDING IMAGE"); title.setText(composer.title); ColorStateList colors = ContextCompat.getColorStateList(itemView.getContext(), Util.getResourceIdFromAttribute(itemView.getContext().getTheme(), R.attr.apptentiveButtonTintColorStateList)); @@ -157,6 +159,7 @@ public void onClick(View view) { } }); + attachments.setupUi(); attachments.setupLayoutListener(); attachments.setListener(new ApptentiveImageGridView.ImageItemClickedListener() { @@ -172,12 +175,22 @@ public void onClick(int position, ImageItem image) { attachments.setImageIndicatorCallback(fragment); //Initialize image attachments band with empty data clearImageAttachmentBand(); + ApptentiveLog.e("HIDING"); + attachments.setVisibility(View.GONE); + attachments.setAdapterIndicator(0); + attachments.setData(new ArrayList()); + + if (adapter.getListener() != null) { + adapter.getListener().onComposingViewCreated(this, message, attachments); + } } /** - * Remove all images from attchment band. + * Remove all images from attachment band. */ public void clearImageAttachmentBand() { + ApptentiveLog.e("CLEARING ATTACHMENTS"); + ApptentiveLog.e("HIDING"); attachments.setVisibility(View.GONE); images.clear(); attachments.setData(null); @@ -189,12 +202,14 @@ public void clearImageAttachmentBand() { * @param imagesToAttach an array of new images to add */ public void addImagesToImageAttachmentBand(final List imagesToAttach) { + ApptentiveLog.e("ADDING IMAGE"); if (imagesToAttach == null || imagesToAttach.size() == 0) { return; } attachments.setupLayoutListener(); + ApptentiveLog.e("SHOWING"); attachments.setVisibility(View.VISIBLE); images.addAll(imagesToAttach); @@ -207,10 +222,12 @@ public void addImagesToImageAttachmentBand(final List imagesToAttach) * @param position the postion index of the image to be removed */ public void removeImageFromImageAttachmentBand(final int position) { + ApptentiveLog.e("REMOVING IMAGE"); images.remove(position); attachments.setupLayoutListener(); if (images.size() == 0) { // Hide attachment band after last attachment is removed + ApptentiveLog.e("HIDING"); attachments.setVisibility(View.GONE); return; } @@ -226,7 +243,7 @@ private void addAdditionalAttachItem() { } /* - * Extends Android default movement method to enable selecting text and openning the links at the same time + * Extends Android default movement method to enable selecting text and opening the links at the same time */ private static class ApptentiveMovementMethod extends ArrowKeyMovementMethod { diff --git a/apptentive/src/main/java/com/apptentive/android/sdk/util/image/ImageGridViewAdapter.java b/apptentive/src/main/java/com/apptentive/android/sdk/util/image/ImageGridViewAdapter.java index 90f4b6e88..fedb04060 100644 --- a/apptentive/src/main/java/com/apptentive/android/sdk/util/image/ImageGridViewAdapter.java +++ b/apptentive/src/main/java/com/apptentive/android/sdk/util/image/ImageGridViewAdapter.java @@ -258,6 +258,7 @@ public View getView(int i, View view, ViewGroup viewGroup) { } else if (type == TYPE_IMAGE) { ViewHolder holder; if (view == null) { + ApptentiveLog.e("Inflating attachment image"); view = inflater.inflate(R.layout.apptentive_image_grid_view_item, viewGroup, false); holder = new ViewHolder(view, i); } else { From a3ac24fccfc1bca7500959c8bc5325c986b16a87 Mon Sep 17 00:00:00 2001 From: skykelsey Date: Wed, 2 Nov 2016 21:20:41 -0700 Subject: [PATCH 019/100] Enable send button when either text or attachments are present in the Composer. --- .../interaction/fragment/MessageCenterFragment.java | 7 +++++-- .../view/MessageCenterRecyclerViewAdapter.java | 2 +- .../messagecenter/view/holder/MessageComposerHolder.java | 6 ++---- 3 files changed, 8 insertions(+), 7 deletions(-) diff --git a/apptentive/src/main/java/com/apptentive/android/sdk/module/engagement/interaction/fragment/MessageCenterFragment.java b/apptentive/src/main/java/com/apptentive/android/sdk/module/engagement/interaction/fragment/MessageCenterFragment.java index a936ef51e..bed400b16 100644 --- a/apptentive/src/main/java/com/apptentive/android/sdk/module/engagement/interaction/fragment/MessageCenterFragment.java +++ b/apptentive/src/main/java/com/apptentive/android/sdk/module/engagement/interaction/fragment/MessageCenterFragment.java @@ -730,7 +730,9 @@ public void addAttachmentsToComposer(final List images) { View v = messageCenterRecyclerView.getChildAt(0); int top = (v == null) ? 0 : v.getTop(); - + if (newImages.isEmpty()) { + return; + } if (messageCenterRecyclerViewAdapter != null) { // Only update composing view if image is attached successfully messageCenterRecyclerViewAdapter.addImagestoComposer(composer, newImages); @@ -923,6 +925,7 @@ public void run() { }); } hideFab(); + composer.setSendButtonState(); } @Override @@ -964,7 +967,7 @@ public void onComposingTextChanged(CharSequence str) { @Override public void afterComposingTextChanged(String message) { - //pendingMessage = message; + composer.setSendButtonState(); } @Override diff --git a/apptentive/src/main/java/com/apptentive/android/sdk/module/messagecenter/view/MessageCenterRecyclerViewAdapter.java b/apptentive/src/main/java/com/apptentive/android/sdk/module/messagecenter/view/MessageCenterRecyclerViewAdapter.java index fae5a572a..ba76847bc 100644 --- a/apptentive/src/main/java/com/apptentive/android/sdk/module/messagecenter/view/MessageCenterRecyclerViewAdapter.java +++ b/apptentive/src/main/java/com/apptentive/android/sdk/module/messagecenter/view/MessageCenterRecyclerViewAdapter.java @@ -252,7 +252,7 @@ public String getWhoCardAvatarFileName() { public void addImagestoComposer(MessageComposerHolder composer, List images) { composer.addImagesToImageAttachmentBand(images); - //notifyDataSetChanged(); + composer.setSendButtonState(); } public void removeImageFromComposer(MessageComposerHolder composer, int position) { diff --git a/apptentive/src/main/java/com/apptentive/android/sdk/module/messagecenter/view/holder/MessageComposerHolder.java b/apptentive/src/main/java/com/apptentive/android/sdk/module/messagecenter/view/holder/MessageComposerHolder.java index 0686fb5ba..87ff7e214 100644 --- a/apptentive/src/main/java/com/apptentive/android/sdk/module/messagecenter/view/holder/MessageComposerHolder.java +++ b/apptentive/src/main/java/com/apptentive/android/sdk/module/messagecenter/view/holder/MessageComposerHolder.java @@ -97,7 +97,6 @@ public void onClick(View view) { Drawable sendButtonDrawable = DrawableCompat.wrap(sendButton.getDrawable()); DrawableCompat.setTintList(sendButtonDrawable, colors); sendButton.setImageDrawable(sendButtonDrawable); - setSendButtonEnabled(false); sendButton.setContentDescription(composer.sendButton); sendButton.setOnClickListener(new View.OnClickListener() { public void onClick(View view) { @@ -140,8 +139,6 @@ public void afterTextChanged(Editable editable) { adapter.getListener().afterComposingTextChanged(editable.toString()); } Linkify.addLinks(editable, Linkify.WEB_URLS | Linkify.PHONE_NUMBERS | Linkify.EMAIL_ADDRESSES | Linkify.MAP_ADDRESSES); - // TODO: Call this from the fragment instead? - setSendButtonEnabled(!TextUtils.isEmpty(message.getText())); } }); @@ -284,7 +281,8 @@ public boolean onTouchEvent(TextView widget, Spannable buffer, MotionEvent event } } - private void setSendButtonEnabled(boolean enabled) { + public void setSendButtonState() { + boolean enabled = !TextUtils.isEmpty(message.getText()) || !images.isEmpty(); if (sendButton.isEnabled() ^ enabled) { // Only if changing value sendButton.setEnabled(enabled); if (enabled) { From 807f8a2b7d31bc8713723eaa0a9b72df7f17b290 Mon Sep 17 00:00:00 2001 From: skykelsey Date: Wed, 2 Nov 2016 21:38:56 -0700 Subject: [PATCH 020/100] Move listener into its own file. --- .../fragment/MessageCenterFragment.java | 46 ++----------------- .../OnListviewItemActionListener.java | 37 +++++++++++++++ .../messagecenter/view/MessageAdapter.java | 4 +- .../MessageCenterRecyclerViewAdapter.java | 8 ++-- 4 files changed, 47 insertions(+), 48 deletions(-) create mode 100644 apptentive/src/main/java/com/apptentive/android/sdk/module/messagecenter/OnListviewItemActionListener.java diff --git a/apptentive/src/main/java/com/apptentive/android/sdk/module/engagement/interaction/fragment/MessageCenterFragment.java b/apptentive/src/main/java/com/apptentive/android/sdk/module/engagement/interaction/fragment/MessageCenterFragment.java index bed400b16..b1d2d1275 100644 --- a/apptentive/src/main/java/com/apptentive/android/sdk/module/engagement/interaction/fragment/MessageCenterFragment.java +++ b/apptentive/src/main/java/com/apptentive/android/sdk/module/engagement/interaction/fragment/MessageCenterFragment.java @@ -48,6 +48,7 @@ import com.apptentive.android.sdk.module.engagement.EngagementModule; import com.apptentive.android.sdk.module.engagement.interaction.model.MessageCenterInteraction; import com.apptentive.android.sdk.module.messagecenter.MessageManager; +import com.apptentive.android.sdk.module.messagecenter.OnListviewItemActionListener; import com.apptentive.android.sdk.module.messagecenter.model.ApptentiveMessage; import com.apptentive.android.sdk.module.messagecenter.model.CompoundMessage; import com.apptentive.android.sdk.module.messagecenter.model.ContextMessage; @@ -55,7 +56,6 @@ import com.apptentive.android.sdk.module.messagecenter.model.MessageCenterUtil; import com.apptentive.android.sdk.module.messagecenter.model.WhoCard; import com.apptentive.android.sdk.module.messagecenter.view.AttachmentPreviewDialog; -import com.apptentive.android.sdk.module.messagecenter.view.MessageAdapter; import com.apptentive.android.sdk.module.messagecenter.view.MessageCenterListView; import com.apptentive.android.sdk.module.messagecenter.view.MessageCenterRecyclerView; import com.apptentive.android.sdk.module.messagecenter.view.MessageCenterRecyclerViewAdapter; @@ -91,9 +91,11 @@ import static com.apptentive.android.sdk.module.messagecenter.model.MessageCenterUtil.MessageCenterListItem.STATUS; import static com.apptentive.android.sdk.module.messagecenter.model.MessageCenterUtil.MessageCenterListItem.WHO_CARD; -public class MessageCenterFragment extends ApptentiveBaseFragment implements OnMenuItemClickListener, MessageManager.AfterSendMessageListener, - MessageAdapter.OnListviewItemActionListener, +public class MessageCenterFragment extends ApptentiveBaseFragment implements + OnListviewItemActionListener, + MessageManager.AfterSendMessageListener, MessageManager.OnNewIncomingMessagesListener, + OnMenuItemClickListener, AbsListView.OnScrollListener, MessageCenterListView.OnListviewResizeListener, ImageGridViewAdapter.Callback { @@ -844,44 +846,6 @@ public void clearWhoCardUi(Animator.AnimatorListener al, ValueAnimator.AnimatorU } } - @Override - public void updateComposingBar() { -/* TODO: What do we save here? - if (messageCenterRecyclerViewAdapter != null) { - MessageCenterComposingActionBarView barView = messageCenterRecyclerViewAdapter.getComposingActionBarView(); - if (barView != null) { - barView.showConfirmation = true; - int attachmentCount = imageAttachmentstList.size(); - if (attachmentCount == 0) { - Editable content = getPendingComposingContent(); - final String messageText = (content != null) ? content.toString().trim() : ""; - barView.showConfirmation = !(messageText.isEmpty()); - } - - if (attachmentCount == attachmentsAllowed) { - AnimationUtil.fadeOutGone(barView.attachButton); - } else { - if (barView.attachButton.getVisibility() != View.VISIBLE) { - AnimationUtil.fadeIn(barView.attachButton, null); - } - } - - if (barView.showConfirmation == true) { - barView.sendButton.setEnabled(true); - if (Build.VERSION.SDK_INT < Build.VERSION_CODES.LOLLIPOP) { - barView.sendButton.setColorFilter(Util.getThemeColor(hostingActivityRef.get(), R.attr.apptentiveButtonTintColor)); - } - } else { - barView.sendButton.setEnabled(false); - if (Build.VERSION.SDK_INT < Build.VERSION_CODES.LOLLIPOP) { - barView.sendButton.setColorFilter(Util.getThemeColor(hostingActivityRef.get(), R.attr.apptentiveButtonTintColorDisabled)); - } - } - } - } -*/ - } - @Override public void onComposingViewCreated(MessageComposerHolder composer, final EditText composerEditText, final ApptentiveImageGridView attachments) { ApptentiveLog.e("onComposingViewCreated()"); diff --git a/apptentive/src/main/java/com/apptentive/android/sdk/module/messagecenter/OnListviewItemActionListener.java b/apptentive/src/main/java/com/apptentive/android/sdk/module/messagecenter/OnListviewItemActionListener.java new file mode 100644 index 000000000..26e8e6e87 --- /dev/null +++ b/apptentive/src/main/java/com/apptentive/android/sdk/module/messagecenter/OnListviewItemActionListener.java @@ -0,0 +1,37 @@ +/* + * Copyright (c) 2016, Apptentive, Inc. All Rights Reserved. + * Please refer to the LICENSE file for the terms and conditions + * under which redistribution and use of this file is permitted. + */ + +package com.apptentive.android.sdk.module.messagecenter; + +import android.widget.EditText; + +import com.apptentive.android.sdk.module.messagecenter.view.holder.MessageComposerHolder; +import com.apptentive.android.sdk.util.image.ApptentiveImageGridView; +import com.apptentive.android.sdk.util.image.ImageItem; + +public interface OnListviewItemActionListener { + void onComposingViewCreated(MessageComposerHolder composer, EditText composerEditText, ApptentiveImageGridView attachments); + + void beforeComposingTextChanged(CharSequence str); + + void onComposingTextChanged(CharSequence str); + + void afterComposingTextChanged(String str); + + void onCancelComposing(); + + void onFinishComposing(); + + void onWhoCardViewCreated(EditText nameEditText, EditText emailEditText); + + void onSubmitWhoCard(String buttonLabel); + + void onCloseWhoCard(String buttonLabel); + + void onAttachImage(); + + void onClickAttachment(int position, ImageItem image); +} \ No newline at end of file diff --git a/apptentive/src/main/java/com/apptentive/android/sdk/module/messagecenter/view/MessageAdapter.java b/apptentive/src/main/java/com/apptentive/android/sdk/module/messagecenter/view/MessageAdapter.java index 52f3fe930..d1e062610 100644 --- a/apptentive/src/main/java/com/apptentive/android/sdk/module/messagecenter/view/MessageAdapter.java +++ b/apptentive/src/main/java/com/apptentive/android/sdk/module/messagecenter/view/MessageAdapter.java @@ -119,8 +119,6 @@ public class MessageAdapter e public interface OnListviewItemActionListener { void onComposingViewCreated(MessageComposerHolder composer, EditText composerEditText, ApptentiveImageGridView attachments); - void updateComposingBar(); - void beforeComposingTextChanged(CharSequence str); void onComposingTextChanged(CharSequence str); @@ -450,7 +448,7 @@ public void onAnimationRepeat(Animator animation) { @Override public void onAnimationEnd(Animator animation) { - composingActionListener.updateComposingBar(); + //composingActionListener.updateComposingBar(); } @Override diff --git a/apptentive/src/main/java/com/apptentive/android/sdk/module/messagecenter/view/MessageCenterRecyclerViewAdapter.java b/apptentive/src/main/java/com/apptentive/android/sdk/module/messagecenter/view/MessageCenterRecyclerViewAdapter.java index ba76847bc..0a8fb55ed 100644 --- a/apptentive/src/main/java/com/apptentive/android/sdk/module/messagecenter/view/MessageCenterRecyclerViewAdapter.java +++ b/apptentive/src/main/java/com/apptentive/android/sdk/module/messagecenter/view/MessageCenterRecyclerViewAdapter.java @@ -12,12 +12,12 @@ import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; -import android.widget.EditText; import com.apptentive.android.sdk.ApptentiveLog; import com.apptentive.android.sdk.R; import com.apptentive.android.sdk.module.engagement.interaction.fragment.MessageCenterFragment; import com.apptentive.android.sdk.module.engagement.interaction.model.Interaction; +import com.apptentive.android.sdk.module.messagecenter.OnListviewItemActionListener; import com.apptentive.android.sdk.module.messagecenter.model.Composer; import com.apptentive.android.sdk.module.messagecenter.model.CompoundMessage; import com.apptentive.android.sdk.module.messagecenter.model.ContextMessage; @@ -49,12 +49,12 @@ public class MessageCenterRecyclerViewAdapter extends RecyclerView.Adapter { MessageCenterFragment fragment; - MessageAdapter.OnListviewItemActionListener listener; + OnListviewItemActionListener listener; RecyclerView recyclerView; Interaction interaction; List messages; - public MessageCenterRecyclerViewAdapter(MessageCenterFragment fragment, MessageAdapter.OnListviewItemActionListener listener, Interaction interaction, List messages) { + public MessageCenterRecyclerViewAdapter(MessageCenterFragment fragment, OnListviewItemActionListener listener, Interaction interaction, List messages) { this.fragment = fragment; this.listener = listener; this.interaction = interaction; @@ -273,7 +273,7 @@ public View getComposingAreaView() { return new View(fragment.getContext()); // TODO } - public MessageAdapter.OnListviewItemActionListener getListener() { + public OnListviewItemActionListener getListener() { return listener; } } From 13eacb9507cfefe2e6f1e76a4b441eafa89fa69a Mon Sep 17 00:00:00 2001 From: skykelsey Date: Wed, 2 Nov 2016 21:51:37 -0700 Subject: [PATCH 021/100] Remove unneeded cleanup code. --- .../fragment/MessageCenterFragment.java | 15 --------------- 1 file changed, 15 deletions(-) diff --git a/apptentive/src/main/java/com/apptentive/android/sdk/module/engagement/interaction/fragment/MessageCenterFragment.java b/apptentive/src/main/java/com/apptentive/android/sdk/module/engagement/interaction/fragment/MessageCenterFragment.java index b1d2d1275..1ed59b4fb 100644 --- a/apptentive/src/main/java/com/apptentive/android/sdk/module/engagement/interaction/fragment/MessageCenterFragment.java +++ b/apptentive/src/main/java/com/apptentive/android/sdk/module/engagement/interaction/fragment/MessageCenterFragment.java @@ -555,7 +555,6 @@ public boolean onBackPressed(boolean hardwareButton) { public boolean cleanup() { clearPendingMessageCenterPushNotification(); - clearWhoCardUi(null, null, 0); // Set to null, otherwise they will hold reference to the activity context MessageManager mgr = ApptentiveInternal.getInstance().getMessageManager(); @@ -832,20 +831,6 @@ public synchronized void onResumeSending() { messagingActionHandler.sendEmptyMessage(MSG_RESUME_SENDING); } - public void clearWhoCardUi(Animator.AnimatorListener al, ValueAnimator.AnimatorUpdateListener vl, long delay) { - if (whoCardItem != null && messageCenterRecyclerViewAdapter != null) { - if (al != null) { - deleteItemWithAnimation(messageCenterRecyclerViewAdapter.getWhoCardView(), al, vl, delay); - } else { - whoCardItem = null; - pendingWhoCardName = null; - pendingWhoCardEmail = null; - pendingWhoCardAvatarFile = null; - pendingWhoCardMode = 0; - } - } - } - @Override public void onComposingViewCreated(MessageComposerHolder composer, final EditText composerEditText, final ApptentiveImageGridView attachments) { ApptentiveLog.e("onComposingViewCreated()"); From 61671a8d5508a2a516bf215654eaaba29b59b523 Mon Sep 17 00:00:00 2001 From: skykelsey Date: Wed, 2 Nov 2016 22:50:46 -0700 Subject: [PATCH 022/100] Tidy up Who Card insertion/removal. --- .../fragment/MessageCenterFragment.java | 54 ++++++++++--------- 1 file changed, 28 insertions(+), 26 deletions(-) diff --git a/apptentive/src/main/java/com/apptentive/android/sdk/module/engagement/interaction/fragment/MessageCenterFragment.java b/apptentive/src/main/java/com/apptentive/android/sdk/module/engagement/interaction/fragment/MessageCenterFragment.java index 1ed59b4fb..b401dec1f 100644 --- a/apptentive/src/main/java/com/apptentive/android/sdk/module/engagement/interaction/fragment/MessageCenterFragment.java +++ b/apptentive/src/main/java/com/apptentive/android/sdk/module/engagement/interaction/fragment/MessageCenterFragment.java @@ -128,6 +128,8 @@ public class MessageCenterFragment extends ApptentiveBaseFragment hostingActivityRef; private MessageCenterRecyclerView messageCenterRecyclerView; + + // Holder and view references private MessageComposerHolder composer; private EditText composerEditText; private EditText whoCardNameEditText; @@ -145,11 +147,7 @@ public class MessageCenterFragment extends ApptentiveBaseFragment imageAttachmentstList = new ArrayList(); @@ -428,7 +426,7 @@ public void onClick(View v) { ** Pending contents would be saved if the user was in composing Who card mode and exitted through back button */ else if (pendingWhoCardName != null || pendingWhoCardEmail != null || pendingWhoCardAvatarFile != null) { - addWhoCardAsMessageItem(pendingWhoCardMode); + addWhoCard(pendingWhoCardMode); } else if (!checkAddWhoCardIfRequired()) { /* If there is only greeting message, show composing. * If Who Card is required, show Who Card first @@ -622,25 +620,14 @@ private boolean checkAddWhoCardIfRequired() { public void addWhoCard(int mode) { hideFab(); hideProfileButton(); - messagingActionHandler.removeMessages(MSG_MESSAGE_ADD_WHOCARD); - messagingActionHandler.removeMessages(MSG_MESSAGE_ADD_COMPOSING); - messagingActionHandler.sendEmptyMessage(MSG_REMOVE_STATUS); - messagingActionHandler.sendMessage(messagingActionHandler.obtainMessage(MSG_MESSAGE_ADD_WHOCARD, mode, 0)); - //messagingActionHandler.sendEmptyMessage(MSG_SCROLL_TO_BOTTOM); - } - - public void addWhoCardAsMessageItem(int mode) { - pendingWhoCardMode = mode; - messagingActionHandler.sendEmptyMessage(MSG_REMOVE_STATUS); JSONObject profile = interaction.getProfile(); if (profile != null) { - try { - ApptentiveLog.e("Adding Who Card"); - whoCardItem = new WhoCard(profile.toString()); - messages.add(whoCardItem); - } catch (JSONException e) { - ApptentiveLog.w("Unable to instantiate Who Card"); - } + pendingWhoCardMode = mode; + messagingActionHandler.removeMessages(MSG_MESSAGE_ADD_WHOCARD); + messagingActionHandler.removeMessages(MSG_MESSAGE_ADD_COMPOSING); + messagingActionHandler.sendEmptyMessage(MSG_REMOVE_STATUS); + messagingActionHandler.sendMessage(messagingActionHandler.obtainMessage(MSG_MESSAGE_ADD_WHOCARD, mode, 0, profile)); + //messagingActionHandler.sendEmptyMessage(MSG_SCROLL_TO_BOTTOM); } } @@ -1017,7 +1004,6 @@ public void onCloseWhoCard(String buttonLabel) { public void cleanupWhoCard() { messagingActionHandler.sendEmptyMessage(MSG_MESSAGE_REMOVE_WHOCARD); Util.hideSoftKeyboard(hostingActivityRef.get(), getView()); - whoCardItem = null; pendingWhoCardName = null; pendingWhoCardEmail = null; pendingWhoCardAvatarFile = null; @@ -1384,8 +1370,15 @@ public void handleMessage(Message msg) { } switch (msg.what) { case MSG_MESSAGE_ADD_WHOCARD: { + ApptentiveLog.e("Adding Who Card"); // msg.arg1 is either WHO_CARD_MODE_INIT or WHO_CARD_MODE_EDIT - fragment.addWhoCardAsMessageItem(msg.arg1); + int mode = msg.arg1; // TODO: Do something with mode? + JSONObject profile = (JSONObject) msg.obj; + try { + fragment.messages.add(new WhoCard(profile.toString())); + } catch (JSONException e) { + ApptentiveLog.w("Unable to instantiate Who Card"); + } fragment.messageCenterRecyclerViewAdapter.notifyItemInserted(fragment.messages.size() - 1); fragment.messageCenterRecyclerView.setSelection(fragment.messages.size() - 1); break; @@ -1454,7 +1447,7 @@ public void handleMessage(Message msg) { fragment.messageCenterRecyclerViewAdapter.notifyDataSetChanged(); // If Who Card is being shown while a message is sent, make sure Who Card is still in view by scrolling to bottom - if (fragment.whoCardItem != null) { + if (fragment.recyclerViewContainsItemOfType(WHO_CARD)) { sendEmptyMessageDelayed(MSG_SCROLL_TO_BOTTOM, DEFAULT_DELAYMILLIS); } else { sendMessageDelayed(obtainMessage(MSG_SCROLL_FROM_TOP, firstIndex, top), DEFAULT_DELAYMILLIS); @@ -1625,4 +1618,13 @@ public void handleMessage(Message msg) { } } } + + public boolean recyclerViewContainsItemOfType(int type) { + for (MessageCenterUtil.MessageCenterListItem item : messages) { + if (item.getListItemType() == type) { + return true; + } + } + return false; + } } \ No newline at end of file From 9872b0f2434c2deec70313496df55d0ee92d5cd1 Mon Sep 17 00:00:00 2001 From: skykelsey Date: Thu, 3 Nov 2016 12:18:08 -0700 Subject: [PATCH 023/100] Don't show FAB when the Composer or Who Card are shown at Message Center launch. --- .../fragment/MessageCenterFragment.java | 57 ++++++++++++------- .../res/layout/apptentive_message_center.xml | 1 + 2 files changed, 39 insertions(+), 19 deletions(-) diff --git a/apptentive/src/main/java/com/apptentive/android/sdk/module/engagement/interaction/fragment/MessageCenterFragment.java b/apptentive/src/main/java/com/apptentive/android/sdk/module/engagement/interaction/fragment/MessageCenterFragment.java index b401dec1f..8aea4c342 100644 --- a/apptentive/src/main/java/com/apptentive/android/sdk/module/engagement/interaction/fragment/MessageCenterFragment.java +++ b/apptentive/src/main/java/com/apptentive/android/sdk/module/engagement/interaction/fragment/MessageCenterFragment.java @@ -137,6 +137,7 @@ public class MessageCenterFragment extends ApptentiveBaseFragment messages = new ArrayList(); @@ -245,8 +246,7 @@ public void onViewCreated(View view, Bundle onSavedInstanceState) { // Restore listview scroll offset to where it was before rotation if (listViewSavedTopIndex != -1) { - messagingActionHandler.sendMessageDelayed(messagingActionHandler.obtainMessage(MSG_SCROLL_FROM_TOP, - listViewSavedTopIndex, listViewSavedTopOffset), DEFAULT_DELAYMILLIS); + messagingActionHandler.sendMessageDelayed(messagingActionHandler.obtainMessage(MSG_SCROLL_FROM_TOP, listViewSavedTopIndex, listViewSavedTopOffset), DEFAULT_DELAYMILLIS); } else { messagingActionHandler.sendEmptyMessageDelayed(MSG_SCROLL_TO_BOTTOM, DEFAULT_DELAYMILLIS); } @@ -375,6 +375,8 @@ protected void updateMenuVisibility() { } private void setup(View rootView, boolean isInitMessages) { + boolean addedAnInteractiveCard = false; + messageCenterRecyclerView = (MessageCenterRecyclerView) rootView.findViewById(R.id.message_center_recycler_view); if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { messageCenterRecyclerView.setNestedScrollingEnabled(true); @@ -393,6 +395,7 @@ private void setup(View rootView, boolean isInitMessages) { fab.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { + forceShowKeyboard = true; addComposingCard(); } }); @@ -410,14 +413,13 @@ public void onClick(View v) { String contextualMessageBody = interaction.getContextualMessageBody(); if (contextualMessageBody != null) { // Clear any pending composing message to present an empty composing area - // TODO: Do we need this? clearPendingComposingMessage(); messagingActionHandler.sendEmptyMessage(MSG_REMOVE_STATUS); - ApptentiveLog.e("Telling to add Context Message"); - Message msg = messagingActionHandler.obtainMessage(MSG_ADD_CONTEXT_MESSAGE, contextualMessageBody); - messagingActionHandler.sendMessage(msg); + messagingActionHandler.sendMessage(messagingActionHandler.obtainMessage(MSG_ADD_CONTEXT_MESSAGE, contextualMessageBody)); // If checkAddWhoCardIfRequired returns true, it will add WhoCard, otherwise add composing card if (!checkAddWhoCardIfRequired()) { + addedAnInteractiveCard = true; + forceShowKeyboard = false; addComposingCard(); } } @@ -426,12 +428,14 @@ public void onClick(View v) { ** Pending contents would be saved if the user was in composing Who card mode and exitted through back button */ else if (pendingWhoCardName != null || pendingWhoCardEmail != null || pendingWhoCardAvatarFile != null) { + addedAnInteractiveCard = true; addWhoCard(pendingWhoCardMode); } else if (!checkAddWhoCardIfRequired()) { /* If there is only greeting message, show composing. * If Who Card is required, show Who Card first */ if (messages.size() == 1) { // TODO: Don't use these magic numbers everywhere + addedAnInteractiveCard = true; addComposingCard(); } else { // Finally check if status message need to be restored @@ -460,6 +464,10 @@ else if (pendingWhoCardName != null || pendingWhoCardEmail != null || pendingWho fabPaddingPixels = calculateFabPadding(rootView.getContext()); attachmentsAllowed = rootView.getContext().getResources().getInteger(R.integer.apptentive_image_grid_default_attachments_total); + if (!addedAnInteractiveCard) { + showFab(); + } + // Retrieve any saved attachments final SharedPreferences prefs = ApptentiveInternal.getInstance().getSharedPrefs(); if (prefs.contains(Constants.PREF_KEY_MESSAGE_CENTER_PENDING_COMPOSING_ATTACHMENTS)) { @@ -507,6 +515,7 @@ public boolean onMenuItemClick(MenuItem menuItem) { final SharedPreferences prefs = ApptentiveInternal.getInstance().getSharedPrefs(); boolean bWhoCardSet = prefs.getBoolean(Constants.PREF_KEY_MESSAGE_CENTER_WHO_CARD_SET, false); + forceShowKeyboard = true; addWhoCard((!bWhoCardSet) ? WHO_CARD_MODE_INIT : WHO_CARD_MODE_EDIT); return true; } else { @@ -853,12 +862,17 @@ public void onComposingViewCreated(MessageComposerHolder composer, final EditTex if (composerEditText != null) { composerEditText.requestFocus(); - composerEditText.post(new Runnable() { - @Override - public void run() { - Util.showSoftKeyboard(hostingActivityRef.get(), composerEditText); - } - }); + if (forceShowKeyboard) { + composerEditText.post(new Runnable() { + @Override + public void run() { + if (forceShowKeyboard) { + forceShowKeyboard = false; + Util.showSoftKeyboard(hostingActivityRef.get(), composerEditText); + } + } + }); + } } hideFab(); composer.setSendButtonState(); @@ -881,13 +895,17 @@ public void onWhoCardViewCreated(final EditText nameEditText, final EditText ema // TODO: Track which field has focus and apply correctly if (nameEditText != null) { nameEditText.requestFocus(); - nameEditText.post(new Runnable() { - @Override - public void run() { - Util.showSoftKeyboard(hostingActivityRef.get(), nameEditText); - } - }); - + if (forceShowKeyboard) { + nameEditText.post(new Runnable() { + @Override + public void run() { + if (forceShowKeyboard) { + forceShowKeyboard = false; + Util.showSoftKeyboard(hostingActivityRef.get(), nameEditText); + } + } + }); + } } hideFab(); } @@ -1484,6 +1502,7 @@ public void handleMessage(Message msg) { EngagementModule.engageInternal(fragment.hostingActivityRef.get(), fragment.interaction, MessageCenterInteraction.EVENT_NAME_PROFILE_OPEN, data.toString()); // The delay is to ensure the animation of adding Who Card play after the animation of new outgoing message if (fragment.interaction.getWhoCardRequestEnabled()) { + fragment.forceShowKeyboard = true; fragment.addWhoCard(WHO_CARD_MODE_INIT); } } diff --git a/apptentive/src/main/res/layout/apptentive_message_center.xml b/apptentive/src/main/res/layout/apptentive_message_center.xml index d4176a8e2..4e67616f0 100644 --- a/apptentive/src/main/res/layout/apptentive_message_center.xml +++ b/apptentive/src/main/res/layout/apptentive_message_center.xml @@ -24,5 +24,6 @@ android:layout_width="wrap_content" android:layout_height="wrap_content" style="?attr/apptentiveFabStyle" + android:visibility="gone" android:src="@drawable/apptentive_ic_compose"/> \ No newline at end of file From 44b915519ceb556283e86aa6372efc2a565cd713 Mon Sep 17 00:00:00 2001 From: skykelsey Date: Thu, 3 Nov 2016 15:40:11 -0700 Subject: [PATCH 024/100] Fix the required/requested/none and initial/edit behavior of the Who Card. --- .../fragment/MessageCenterFragment.java | 71 ++++++++----------- .../model/MessageCenterInteraction.java | 9 +++ .../module/messagecenter/model/WhoCard.java | 13 ++++ .../MessageCenterRecyclerViewAdapter.java | 30 -------- .../view/holder/WhoCardHolder.java | 62 +++++++++++----- .../android/sdk/util/Constants.java | 2 +- 6 files changed, 98 insertions(+), 89 deletions(-) diff --git a/apptentive/src/main/java/com/apptentive/android/sdk/module/engagement/interaction/fragment/MessageCenterFragment.java b/apptentive/src/main/java/com/apptentive/android/sdk/module/engagement/interaction/fragment/MessageCenterFragment.java index 8aea4c342..657dc6af1 100644 --- a/apptentive/src/main/java/com/apptentive/android/sdk/module/engagement/interaction/fragment/MessageCenterFragment.java +++ b/apptentive/src/main/java/com/apptentive/android/sdk/module/engagement/interaction/fragment/MessageCenterFragment.java @@ -7,9 +7,6 @@ package com.apptentive.android.sdk.module.engagement.interaction.fragment; -import android.animation.Animator; -import android.animation.AnimatorSet; -import android.animation.ValueAnimator; import android.app.Activity; import android.content.Context; import android.content.Intent; @@ -116,9 +113,6 @@ public class MessageCenterFragment extends ApptentiveBaseFragment Date: Thu, 3 Nov 2016 15:56:31 -0700 Subject: [PATCH 025/100] In the correct circumstances, the Composer should be opened automatically when the Who Card is submitted. --- .../fragment/MessageCenterFragment.java | 20 +++++++++++++++++-- 1 file changed, 18 insertions(+), 2 deletions(-) diff --git a/apptentive/src/main/java/com/apptentive/android/sdk/module/engagement/interaction/fragment/MessageCenterFragment.java b/apptentive/src/main/java/com/apptentive/android/sdk/module/engagement/interaction/fragment/MessageCenterFragment.java index 657dc6af1..aeec2f617 100644 --- a/apptentive/src/main/java/com/apptentive/android/sdk/module/engagement/interaction/fragment/MessageCenterFragment.java +++ b/apptentive/src/main/java/com/apptentive/android/sdk/module/engagement/interaction/fragment/MessageCenterFragment.java @@ -997,6 +997,13 @@ public void onSubmitWhoCard(String buttonLabel) { setWhoCardAsPreviouslyDisplayed(); cleanupWhoCard(); + + if (shouldOpenComposerAfterClosingWhoCard()) { + addComposingCard(); + } else { + showFab(); + showProfileButton(); + } } @Override @@ -1013,6 +1020,17 @@ public void onCloseWhoCard(String buttonLabel) { setWhoCardAsPreviouslyDisplayed(); cleanupWhoCard(); + + if (shouldOpenComposerAfterClosingWhoCard()) { + addComposingCard(); + } else { + showFab(); + showProfileButton(); + } + } + + private boolean shouldOpenComposerAfterClosingWhoCard() { + return interaction.getWhoCard().isRequire() && (recyclerViewContainsItemOfType(MESSAGE_CONTEXT) || recyclerViewContainsItemOfType(MESSAGE_OUTGOING)); } public void cleanupWhoCard() { @@ -1025,8 +1043,6 @@ public void cleanupWhoCard() { whoCardNameEditText = null; whoCardEmailEditText = null; addExpectationStatusIfNeeded(); - showFab(); - showProfileButton(); } @Override From d8da3aae76f9c724d932de977e7b2936fe593cfd Mon Sep 17 00:00:00 2001 From: skykelsey Date: Thu, 3 Nov 2016 17:08:17 -0700 Subject: [PATCH 026/100] Use handler to add greeting. Fix Composer focusing issue. --- .../fragment/MessageCenterFragment.java | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/apptentive/src/main/java/com/apptentive/android/sdk/module/engagement/interaction/fragment/MessageCenterFragment.java b/apptentive/src/main/java/com/apptentive/android/sdk/module/engagement/interaction/fragment/MessageCenterFragment.java index aeec2f617..c94cdd694 100644 --- a/apptentive/src/main/java/com/apptentive/android/sdk/module/engagement/interaction/fragment/MessageCenterFragment.java +++ b/apptentive/src/main/java/com/apptentive/android/sdk/module/engagement/interaction/fragment/MessageCenterFragment.java @@ -192,6 +192,7 @@ public class MessageCenterFragment extends ApptentiveBaseFragment } } } - // Finally, add greeting message - messages.add(0, interaction.getGreeting()); + messagingActionHandler.sendEmptyMessage(MSG_ADD_GREETING); } // @Override @@ -1419,7 +1419,6 @@ public void handleMessage(Message msg) { break; } case MSG_MESSAGE_ADD_COMPOSING: { - //fragment.addComposerMessageItems(); fragment.messages.add(fragment.interaction.getComposer()); fragment.messageCenterRecyclerViewAdapter.notifyItemInserted(fragment.messages.size() - 1); fragment.messageCenterRecyclerView.setSelection(fragment.messages.size() - 1); @@ -1432,7 +1431,7 @@ public void handleMessage(Message msg) { } case MSG_SCROLL_TO_BOTTOM: { fragment.messageCenterRecyclerView.setSelection(fragment.messages.size() - 1); - fragment.messageCenterRecyclerView.smoothScrollToPosition(fragment.messages.size() - 1); + fragment.messageCenterRecyclerView.scrollToPosition(fragment.messages.size() - 1); break; } case MSG_SCROLL_FROM_TOP: { @@ -1637,6 +1636,11 @@ public void handleMessage(Message msg) { fragment.messageCenterRecyclerViewAdapter.notifyItemInserted(messages.size() - 1); break; } + case MSG_ADD_GREETING: { + fragment.messages.add(0, fragment.interaction.getGreeting()); + fragment.messageCenterRecyclerViewAdapter.notifyItemInserted(0); + break; + } } } } From 6869852fb8a435cac7f3646e2f9419ba4d13d42b Mon Sep 17 00:00:00 2001 From: skykelsey Date: Thu, 3 Nov 2016 17:10:50 -0700 Subject: [PATCH 027/100] Remove old dead code. --- .../interaction/fragment/MessageCenterFragment.java | 13 ------------- 1 file changed, 13 deletions(-) diff --git a/apptentive/src/main/java/com/apptentive/android/sdk/module/engagement/interaction/fragment/MessageCenterFragment.java b/apptentive/src/main/java/com/apptentive/android/sdk/module/engagement/interaction/fragment/MessageCenterFragment.java index c94cdd694..4635d6bf0 100644 --- a/apptentive/src/main/java/com/apptentive/android/sdk/module/engagement/interaction/fragment/MessageCenterFragment.java +++ b/apptentive/src/main/java/com/apptentive/android/sdk/module/engagement/interaction/fragment/MessageCenterFragment.java @@ -175,7 +175,6 @@ public class MessageCenterFragment extends ApptentiveBaseFragment Date: Fri, 4 Nov 2016 11:29:04 -0700 Subject: [PATCH 028/100] Fix incoming message insertion. --- .../fragment/MessageCenterFragment.java | 39 ++++++++----------- 1 file changed, 17 insertions(+), 22 deletions(-) diff --git a/apptentive/src/main/java/com/apptentive/android/sdk/module/engagement/interaction/fragment/MessageCenterFragment.java b/apptentive/src/main/java/com/apptentive/android/sdk/module/engagement/interaction/fragment/MessageCenterFragment.java index 4635d6bf0..fe38d170e 100644 --- a/apptentive/src/main/java/com/apptentive/android/sdk/module/engagement/interaction/fragment/MessageCenterFragment.java +++ b/apptentive/src/main/java/com/apptentive/android/sdk/module/engagement/interaction/fragment/MessageCenterFragment.java @@ -640,28 +640,29 @@ public void addNewOutGoingMessageItem(ApptentiveMessage message) { } public void displayNewIncomingMessageItem(ApptentiveMessage message) { - // TODO: Use handler for this messagingActionHandler.sendEmptyMessage(MSG_REMOVE_STATUS); - // TODO: A simpler way to put the message in the correct place. // Determine where to insert the new incoming message. It will be in front of any eidting // area, i.e. composing, Who Card ... - int insertIndex = messages.size(); + int insertIndex = messages.size(); // If inserted onto the end, then the list will have grown by one. - for (MessageCenterUtil.MessageCenterListItem item : messages) { - if (item.getListItemType() == MESSAGE_COMPOSER) { - insertIndex -= 1; - continue; - } - if (item.getListItemType() == MESSAGE_CONTEXT) { - insertIndex -= 1; - continue; - } - if (item.getListItemType() == WHO_CARD) { - insertIndex -= 1; - continue; + outside_loop: + // Starting at end of list, go back up the list to find the proper place to insert the incoming message. + for (int i = messages.size() - 1; i > 0; i--) { + MessageCenterUtil.MessageCenterListItem item = messages.get(i); + switch(item.getListItemType()) { + case MESSAGE_COMPOSER: + case MESSAGE_CONTEXT: + case WHO_CARD: + case STATUS: + insertIndex--; + break; + default: + // Any other type means we are past the temporary items. + break outside_loop; } } messages.add(insertIndex, message); + messageCenterRecyclerViewAdapter.notifyItemInserted(insertIndex); int firstIndex = messageCenterRecyclerView.getFirstVisiblePosition(); int lastIndex = messageCenterRecyclerView.getLastVisiblePosition(); @@ -674,18 +675,12 @@ public void displayNewIncomingMessageItem(ApptentiveMessage message) { messageCenterRecyclerViewAdapter.notifyDataSetChanged(); } // Restore the position of listview to composing view - messagingActionHandler.sendMessage(messagingActionHandler.obtainMessage(MSG_SCROLL_FROM_TOP, - insertIndex, top)); + messagingActionHandler.sendMessage(messagingActionHandler.obtainMessage(MSG_SCROLL_FROM_TOP, insertIndex, top)); } else { updateMessageSentStates(); - if (messageCenterRecyclerViewAdapter != null) { - messageCenterRecyclerViewAdapter.notifyDataSetChanged(); - } } - } - public void addAttachmentsToComposer(final List images) { ArrayList newImages = new ArrayList(); // only add new images, and filter out duplicates From 40da42eeece4c58f615f7197c724f6fec2204532 Mon Sep 17 00:00:00 2001 From: skykelsey Date: Fri, 4 Nov 2016 12:07:44 -0700 Subject: [PATCH 029/100] Fix UnreadMessagesListener invocation. --- .../MessageCenterRecyclerViewAdapter.java | 69 ++++++++++++++++--- .../holder/IncomingCompoundMessageHolder.java | 9 +-- .../holder/OutgoingCompoundMessageHolder.java | 3 +- 3 files changed, 60 insertions(+), 21 deletions(-) diff --git a/apptentive/src/main/java/com/apptentive/android/sdk/module/messagecenter/view/MessageCenterRecyclerViewAdapter.java b/apptentive/src/main/java/com/apptentive/android/sdk/module/messagecenter/view/MessageCenterRecyclerViewAdapter.java index a6e272afa..d55f69e74 100644 --- a/apptentive/src/main/java/com/apptentive/android/sdk/module/messagecenter/view/MessageCenterRecyclerViewAdapter.java +++ b/apptentive/src/main/java/com/apptentive/android/sdk/module/messagecenter/view/MessageCenterRecyclerViewAdapter.java @@ -6,18 +6,22 @@ package com.apptentive.android.sdk.module.messagecenter.view; -import android.os.Parcel; -import android.os.Parcelable; +import android.os.AsyncTask; import android.support.v7.widget.RecyclerView; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; +import com.apptentive.android.sdk.ApptentiveInternal; import com.apptentive.android.sdk.ApptentiveLog; import com.apptentive.android.sdk.R; +import com.apptentive.android.sdk.module.engagement.EngagementModule; import com.apptentive.android.sdk.module.engagement.interaction.fragment.MessageCenterFragment; import com.apptentive.android.sdk.module.engagement.interaction.model.Interaction; +import com.apptentive.android.sdk.module.engagement.interaction.model.MessageCenterInteraction; +import com.apptentive.android.sdk.module.messagecenter.MessageManager; import com.apptentive.android.sdk.module.messagecenter.OnListviewItemActionListener; +import com.apptentive.android.sdk.module.messagecenter.model.ApptentiveMessage; import com.apptentive.android.sdk.module.messagecenter.model.Composer; import com.apptentive.android.sdk.module.messagecenter.model.CompoundMessage; import com.apptentive.android.sdk.module.messagecenter.model.ContextMessage; @@ -35,6 +39,10 @@ import com.apptentive.android.sdk.module.messagecenter.view.holder.WhoCardHolder; import com.apptentive.android.sdk.util.image.ImageItem; +import org.json.JSONException; +import org.json.JSONObject; + +import java.util.ArrayList; import java.util.List; import static com.apptentive.android.sdk.module.messagecenter.model.MessageCenterUtil.MessageCenterListItem.GREETING; @@ -53,6 +61,8 @@ public class MessageCenterRecyclerViewAdapter extends RecyclerView.Adapter { RecyclerView recyclerView; Interaction interaction; List messages; + // maps to prevent redundant asynctasks + private ArrayList messagesWithPendingReadStatusUpdate = new ArrayList(); public MessageCenterRecyclerViewAdapter(MessageCenterFragment fragment, OnListviewItemActionListener listener, Interaction interaction, List messages) { this.fragment = fragment; @@ -161,6 +171,12 @@ public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) { CompoundMessage compoundMessage = (CompoundMessage) messages.get(position); IncomingCompoundMessageHolder compoundHolder = (IncomingCompoundMessageHolder) holder; compoundHolder.bindView(recyclerView, compoundMessage); + // Mark as read + if (!compoundMessage.isRead() && !messagesWithPendingReadStatusUpdate.contains(compoundMessage)) { + messagesWithPendingReadStatusUpdate.add(compoundMessage); + startUpdateUnreadMessageTask(compoundMessage); + } + break; } case MESSAGE_OUTGOING: { @@ -231,19 +247,50 @@ public void removeImageFromComposer(MessageComposerHolder composer, int position } } - public View getWhoCardView() { - return new View(fragment.getContext()); // TODO + public OnListviewItemActionListener getListener() { + return listener; } - public MessageCenterComposingActionBarView getComposingActionBarView() { - return new MessageCenterComposingActionBarView(fragment, null, null); // TODO + private void startUpdateUnreadMessageTask(CompoundMessage message) { + UpdateUnreadMessageTask task = new UpdateUnreadMessageTask(message); + task.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR, message); } - public View getComposingAreaView() { - return new View(fragment.getContext()); // TODO - } + private class UpdateUnreadMessageTask extends AsyncTask { + private ApptentiveMessage message; - public OnListviewItemActionListener getListener() { - return listener; + public UpdateUnreadMessageTask(ApptentiveMessage message) { + this.message = message; + } + + @Override + protected Void doInBackground(ApptentiveMessage... messages) { + messages[0].setRead(true); + JSONObject data = new JSONObject(); + try { + data.put("message_id", messages[0].getId()); + data.put("message_type", messages[0].getType().name()); + } catch (JSONException e) { + // + } + EngagementModule.engageInternal(fragment.getContext(), interaction, MessageCenterInteraction.EVENT_NAME_READ, data.toString()); + + MessageManager mgr = ApptentiveInternal.getInstance().getMessageManager(); + if (mgr != null) { + mgr.updateMessage(messages[0]); + mgr.notifyHostUnreadMessagesListeners(mgr.getUnreadMessageCount()); + } + return null; + } + + @Override + protected void onCancelled() { + messagesWithPendingReadStatusUpdate.remove(message); + } + + @Override + protected void onPostExecute(Void result) { + messagesWithPendingReadStatusUpdate.remove(message); + } } } diff --git a/apptentive/src/main/java/com/apptentive/android/sdk/module/messagecenter/view/holder/IncomingCompoundMessageHolder.java b/apptentive/src/main/java/com/apptentive/android/sdk/module/messagecenter/view/holder/IncomingCompoundMessageHolder.java index 10c2638ec..7e3304388 100644 --- a/apptentive/src/main/java/com/apptentive/android/sdk/module/messagecenter/view/holder/IncomingCompoundMessageHolder.java +++ b/apptentive/src/main/java/com/apptentive/android/sdk/module/messagecenter/view/holder/IncomingCompoundMessageHolder.java @@ -45,11 +45,11 @@ public IncomingCompoundMessageHolder(View itemView) { nameView = (TextView) itemView.findViewById(R.id.sender_name); messageBodyView = (TextView) itemView.findViewById(R.id.apptentive_compound_message_body); imageBandView = (ApptentiveImageGridView) itemView.findViewById(R.id.grid); - //listener = view.getListener(); } public void bindView(final RecyclerView parent, final CompoundMessage message) { super.bindView(parent, message); + imageBandView.setupUi(); if (loadAvatar) { ImageUtil.startDownloadAvatarTask(avatar, message.getSenderProfilePhoto()); } @@ -102,14 +102,7 @@ public void onClick(int position, ImageItem image) { } } }); - } } -/* - if (!message.isRead() && !positionsWithPendingUpdateTask.contains(position)) { - positionsWithPendingUpdateTask.add(position); - startUpdateUnreadMessageTask(compoundMessage, position); - } -*/ } } \ No newline at end of file diff --git a/apptentive/src/main/java/com/apptentive/android/sdk/module/messagecenter/view/holder/OutgoingCompoundMessageHolder.java b/apptentive/src/main/java/com/apptentive/android/sdk/module/messagecenter/view/holder/OutgoingCompoundMessageHolder.java index 4f4236a57..20f7031ef 100644 --- a/apptentive/src/main/java/com/apptentive/android/sdk/module/messagecenter/view/holder/OutgoingCompoundMessageHolder.java +++ b/apptentive/src/main/java/com/apptentive/android/sdk/module/messagecenter/view/holder/OutgoingCompoundMessageHolder.java @@ -102,7 +102,7 @@ protected String createStatus(Double seconds, boolean showSent) { return (showSent) ? itemView.getResources().getString(R.string.apptentive_sent) : null; } - protected int getStatusColor(Double seconds, boolean isPaused) { + private int getStatusColor(Double seconds, boolean isPaused) { if (seconds == null) { // failed color (red) return isPaused ? Util.getThemeColor(itemView.getContext(), R.attr.apptentiveValidationFailedColor) : 0; @@ -110,5 +110,4 @@ protected int getStatusColor(Double seconds, boolean isPaused) { // other status color return Util.getThemeColor(itemView.getContext(), android.R.attr.textColorSecondary); } - } \ No newline at end of file From ad89367e87dbea2c2c999114320c0e1ddd3b9ded Mon Sep 17 00:00:00 2001 From: skykelsey Date: Fri, 4 Nov 2016 13:41:51 -0700 Subject: [PATCH 030/100] Fix message sent state and datestamp display. --- .../fragment/MessageCenterFragment.java | 32 ++++++++++++------- .../model/ApptentiveMessage.java | 29 ++++++++++++++--- .../view/holder/MessageHolder.java | 1 - 3 files changed, 45 insertions(+), 17 deletions(-) diff --git a/apptentive/src/main/java/com/apptentive/android/sdk/module/engagement/interaction/fragment/MessageCenterFragment.java b/apptentive/src/main/java/com/apptentive/android/sdk/module/engagement/interaction/fragment/MessageCenterFragment.java index fe38d170e..44758f8ea 100644 --- a/apptentive/src/main/java/com/apptentive/android/sdk/module/engagement/interaction/fragment/MessageCenterFragment.java +++ b/apptentive/src/main/java/com/apptentive/android/sdk/module/engagement/interaction/fragment/MessageCenterFragment.java @@ -436,9 +436,6 @@ else if (pendingWhoCardName != null || pendingWhoCardEmail != null || pendingWho addExpectationStatusIfNeeded(); } } - - updateMessageSentStates(); // Force timestamp recompilation. - } messageCenterRecyclerView.setAdapter(messageCenterRecyclerViewAdapter); @@ -480,6 +477,7 @@ else if (pendingWhoCardName != null || pendingWhoCardEmail != null || pendingWho SharedPreferences.Editor editor = prefs.edit(); editor.remove(Constants.PREF_KEY_MESSAGE_CENTER_PENDING_COMPOSING_ATTACHMENTS).apply(); } + updateMessageSentStates(); } public boolean onMenuItemClick(MenuItem menuItem) { @@ -671,9 +669,6 @@ public void displayNewIncomingMessageItem(ApptentiveMessage message) { View v = messageCenterRecyclerView.getChildAt(0); int top = (v == null) ? 0 : v.getTop(); updateMessageSentStates(); - if (messageCenterRecyclerViewAdapter != null) { - messageCenterRecyclerViewAdapter.notifyDataSetChanged(); - } // Restore the position of listview to composing view messagingActionHandler.sendMessage(messagingActionHandler.obtainMessage(MSG_SCROLL_FROM_TOP, insertIndex, top)); } else { @@ -1176,11 +1171,14 @@ private Parcelable saveEditTextInstanceState() { Set dateStampsSeen = new HashSet(); public void updateMessageSentStates() { + ApptentiveLog.e("Updating datestamps"); dateStampsSeen.clear(); MessageCenterUtil.CompoundMessageCommonInterface lastSent = null; Set uniqueNonce = new HashSet(); - Iterator messageIterator = messages.iterator(); + int removedItems = 0; + ListIterator messageIterator = messages.listIterator(); while (messageIterator.hasNext()) { + int adapterMessagePosition = messageIterator.nextIndex() - removedItems; MessageCenterUtil.MessageCenterListItem message = messageIterator.next(); if (message instanceof ApptentiveMessage) { /* Check if there is any duplicate messages and remove if found. @@ -1188,17 +1186,24 @@ public void updateMessageSentStates() { */ if (!uniqueNonce.add(((ApptentiveMessage) message).getNonce())) { messageIterator.remove(); + messageCenterRecyclerViewAdapter.notifyItemRemoved(adapterMessagePosition); + removedItems++; continue; } // Update timestamps ApptentiveMessage apptentiveMessage = (ApptentiveMessage) message; Double sentOrReceivedAt = apptentiveMessage.getCreatedAt(); String dateStamp = createDatestamp(sentOrReceivedAt); + ApptentiveLog.e("Looking at datestamp: %s", dateStamp); if (dateStamp != null) { if (dateStampsSeen.add(dateStamp)) { - apptentiveMessage.setDatestamp(dateStamp); + if (apptentiveMessage.setDatestamp(dateStamp)) { + messageCenterRecyclerViewAdapter.notifyItemChanged(adapterMessagePosition); + } } else { - apptentiveMessage.clearDatestamp(); + if (apptentiveMessage.clearDatestamp()) { + messageCenterRecyclerViewAdapter.notifyItemChanged(adapterMessagePosition); + } } } @@ -1426,13 +1431,16 @@ public void handleMessage(Message msg) { // below is callback handling when receiving of message is acknowledged by server through POST response fragment.unsentMessagesCount--; ApptentiveMessage apptentiveMessage = (ApptentiveMessage) msg.obj; - for (MessageCenterUtil.MessageCenterListItem message : fragment.messages) { + + for (int i = 0; i < fragment.messages.size(); i++) { + MessageCenterUtil.MessageCenterListItem message = fragment.messages.get(i); if (message instanceof ApptentiveMessage) { String nonce = ((ApptentiveMessage) message).getNonce(); if (nonce != null) { String sentNonce = apptentiveMessage.getNonce(); if (sentNonce != null && nonce.equals(sentNonce)) { ((ApptentiveMessage) message).setCreatedAt(apptentiveMessage.getCreatedAt()); + fragment.messageCenterRecyclerViewAdapter.notifyItemChanged(i); break; } } @@ -1447,7 +1455,6 @@ public void handleMessage(Message msg) { View v = fragment.messageCenterRecyclerView.getChildAt(0); int top = (v == null) ? 0 : v.getTop(); - fragment.messageCenterRecyclerViewAdapter.notifyDataSetChanged(); // If Who Card is being shown while a message is sent, make sure Who Card is still in view by scrolling to bottom if (fragment.recyclerViewContainsItemOfType(WHO_CARD)) { sendEmptyMessageDelayed(MSG_SCROLL_TO_BOTTOM, DEFAULT_DELAYMILLIS); @@ -1567,6 +1574,7 @@ public void handleMessage(Message msg) { case MSG_OPT_INSERT_REGULAR_STATUS: { List messages = fragment.messages; MessageCenterStatus status = fragment.interaction.getRegularStatus(); +/* for (int i = 0; i < messages.size(); i++) { MessageCenterUtil.MessageCenterListItem item = messages.get(i); if (item.getListItemType() == MESSAGE_COMPOSER) { @@ -1575,6 +1583,7 @@ public void handleMessage(Message msg) { fragment.messageCenterRecyclerViewAdapter.notifyItemRemoved(i); } } +*/ int numOfMessages = messages.size(); if (numOfMessages > 0) { @@ -1594,7 +1603,6 @@ public void handleMessage(Message msg) { } } } - break; } case MSG_REMOVE_STATUS: { diff --git a/apptentive/src/main/java/com/apptentive/android/sdk/module/messagecenter/model/ApptentiveMessage.java b/apptentive/src/main/java/com/apptentive/android/sdk/module/messagecenter/model/ApptentiveMessage.java index 03f1e3cba..e97898681 100644 --- a/apptentive/src/main/java/com/apptentive/android/sdk/module/messagecenter/model/ApptentiveMessage.java +++ b/apptentive/src/main/java/com/apptentive/android/sdk/module/messagecenter/model/ApptentiveMessage.java @@ -248,12 +248,33 @@ public String getDatestamp() { return datestamp; } - public void setDatestamp(String datestamp) { - this.datestamp = datestamp; + /** + * Sets the datestamp for this message. + * + * @param datestamp A datestamp + * @return true if the datestamp was added or changed. + */ + public boolean setDatestamp(String datestamp) { + if (this.datestamp == null || !this.datestamp.equals(datestamp)) { + this.datestamp = datestamp; + return true; + } else { + return false; + } } - public void clearDatestamp() { - this.datestamp = null; + /** + * Clears the datestamp from a message + * + * @return true If the datestamp existed and was cleared, false if it was already cleared. + */ + public boolean clearDatestamp() { + if (datestamp != null) { + this.datestamp = null; + return true; + } else { + return false; + } } public abstract boolean isOutgoingMessage(); diff --git a/apptentive/src/main/java/com/apptentive/android/sdk/module/messagecenter/view/holder/MessageHolder.java b/apptentive/src/main/java/com/apptentive/android/sdk/module/messagecenter/view/holder/MessageHolder.java index 82dc2028f..23de625fa 100644 --- a/apptentive/src/main/java/com/apptentive/android/sdk/module/messagecenter/view/holder/MessageHolder.java +++ b/apptentive/src/main/java/com/apptentive/android/sdk/module/messagecenter/view/holder/MessageHolder.java @@ -13,7 +13,6 @@ import com.apptentive.android.sdk.R; import com.apptentive.android.sdk.module.messagecenter.model.CompoundMessage; -import com.apptentive.android.sdk.util.Util; public abstract class MessageHolder extends RecyclerView.ViewHolder { public TextView datestamp; From 1ef8ce90964f7af12e3f086b2cc4176fd522e5de Mon Sep 17 00:00:00 2001 From: skykelsey Date: Fri, 4 Nov 2016 17:20:12 -0700 Subject: [PATCH 031/100] Scroll down when attachments are added to the Composer. Add some notes for further work. --- .../fragment/MessageCenterFragment.java | 31 +++++++++---------- .../view/holder/MessageComposerHolder.java | 3 +- 2 files changed, 15 insertions(+), 19 deletions(-) diff --git a/apptentive/src/main/java/com/apptentive/android/sdk/module/engagement/interaction/fragment/MessageCenterFragment.java b/apptentive/src/main/java/com/apptentive/android/sdk/module/engagement/interaction/fragment/MessageCenterFragment.java index 44758f8ea..c4d933871 100644 --- a/apptentive/src/main/java/com/apptentive/android/sdk/module/engagement/interaction/fragment/MessageCenterFragment.java +++ b/apptentive/src/main/java/com/apptentive/android/sdk/module/engagement/interaction/fragment/MessageCenterFragment.java @@ -77,7 +77,6 @@ import java.util.Arrays; import java.util.Date; import java.util.HashSet; -import java.util.Iterator; import java.util.List; import java.util.ListIterator; import java.util.Set; @@ -625,6 +624,7 @@ private void addExpectationStatusIfNeeded() { messagingActionHandler.sendEmptyMessage(MSG_OPT_INSERT_REGULAR_STATUS); } + // TODO: What do we do with this? public void addNewOutGoingMessageItem(ApptentiveMessage message) { messagingActionHandler.sendEmptyMessage(MSG_REMOVE_STATUS); @@ -637,6 +637,9 @@ public void addNewOutGoingMessageItem(ApptentiveMessage message) { } } + /** + * Call only from handler. + */ public void displayNewIncomingMessageItem(ApptentiveMessage message) { messagingActionHandler.sendEmptyMessage(MSG_REMOVE_STATUS); // Determine where to insert the new incoming message. It will be in front of any eidting @@ -647,7 +650,7 @@ public void displayNewIncomingMessageItem(ApptentiveMessage message) { // Starting at end of list, go back up the list to find the proper place to insert the incoming message. for (int i = messages.size() - 1; i > 0; i--) { MessageCenterUtil.MessageCenterListItem item = messages.get(i); - switch(item.getListItemType()) { + switch (item.getListItemType()) { case MESSAGE_COMPOSER: case MESSAGE_CONTEXT: case WHO_CARD: @@ -712,23 +715,13 @@ public void addAttachmentsToComposer(final List images) { } public void setAttachmentsInComposer(final List images) { - ApptentiveLog.e("setAttachmentsInComposer()"); - View v = messageCenterRecyclerView.getChildAt(0); - int top = (v == null) ? 0 : v.getTop(); - // Only update composing view if image is attached successfully - if (messageCenterRecyclerViewAdapter != null) { - ApptentiveLog.e("Restoring attachments"); - messageCenterRecyclerViewAdapter.addImagestoComposer(composer, images); - } - int firstIndex = messageCenterRecyclerView.getFirstVisiblePosition(); -/* - if (messageCenterRecyclerViewAdapter != null) { - messageCenterRecyclerViewAdapter.notifyDataSetChanged(); - } -*/ - messagingActionHandler.sendMessage(messagingActionHandler.obtainMessage(MSG_SCROLL_FROM_TOP, firstIndex, top)); + messageCenterRecyclerViewAdapter.addImagestoComposer(composer, images); + // The view will resize. Scroll it into view after a short delay to ensure the view has already resized. + messagingActionHandler.sendEmptyMessageDelayed(MSG_SCROLL_TO_BOTTOM, 50); + } + // TODO: This needs to be sent through the Handler public void removeImageFromComposer(final int position) { EngagementModule.engageInternal(hostingActivityRef.get(), interaction, MessageCenterInteraction.EVENT_NAME_ATTACHMENT_DELETE); pendingAttachments.remove(position); @@ -1528,6 +1521,7 @@ public void handleMessage(Message msg) { break; } case MSG_PAUSE_SENDING: { + ApptentiveLog.e("PAUSE"); if (!fragment.isPaused) { fragment.isPaused = true; if (fragment.unsentMessagesCount > 0) { @@ -1542,12 +1536,14 @@ public void handleMessage(Message msg) { MessageCenterStatus newItem = fragment.interaction.getErrorStatusServer(); // TODO: fragment.addNewStatusItem(newItem); } + //TODO: Do this better fragment.messageCenterRecyclerViewAdapter.notifyDataSetChanged(); } } break; } case MSG_RESUME_SENDING: { + ApptentiveLog.e("RESUME"); if (fragment.isPaused) { fragment.isPaused = false; if (fragment.unsentMessagesCount > 0) { @@ -1555,6 +1551,7 @@ public void handleMessage(Message msg) { } fragment.messageCenterRecyclerViewAdapter.setPaused(fragment.isPaused); + // TODO: Do this better fragment.messageCenterRecyclerViewAdapter.notifyDataSetChanged(); } break; diff --git a/apptentive/src/main/java/com/apptentive/android/sdk/module/messagecenter/view/holder/MessageComposerHolder.java b/apptentive/src/main/java/com/apptentive/android/sdk/module/messagecenter/view/holder/MessageComposerHolder.java index 87ff7e214..ba5666094 100644 --- a/apptentive/src/main/java/com/apptentive/android/sdk/module/messagecenter/view/holder/MessageComposerHolder.java +++ b/apptentive/src/main/java/com/apptentive/android/sdk/module/messagecenter/view/holder/MessageComposerHolder.java @@ -199,11 +199,10 @@ public void clearImageAttachmentBand() { * @param imagesToAttach an array of new images to add */ public void addImagesToImageAttachmentBand(final List imagesToAttach) { - ApptentiveLog.e("ADDING IMAGE"); - if (imagesToAttach == null || imagesToAttach.size() == 0) { return; } + ApptentiveLog.e("ADDING IMAGES"); attachments.setupLayoutListener(); ApptentiveLog.e("SHOWING"); From 907de448f5b96fb80f9765126712e4b2c12f243c Mon Sep 17 00:00:00 2001 From: skykelsey Date: Sat, 5 Nov 2016 13:17:51 -0700 Subject: [PATCH 032/100] Move some variables around to clean then up. --- .../fragment/MessageCenterFragment.java | 58 ++++++++----------- 1 file changed, 23 insertions(+), 35 deletions(-) diff --git a/apptentive/src/main/java/com/apptentive/android/sdk/module/engagement/interaction/fragment/MessageCenterFragment.java b/apptentive/src/main/java/com/apptentive/android/sdk/module/engagement/interaction/fragment/MessageCenterFragment.java index c4d933871..b1cda1993 100644 --- a/apptentive/src/main/java/com/apptentive/android/sdk/module/engagement/interaction/fragment/MessageCenterFragment.java +++ b/apptentive/src/main/java/com/apptentive/android/sdk/module/engagement/interaction/fragment/MessageCenterFragment.java @@ -120,6 +120,10 @@ public class MessageCenterFragment extends ApptentiveBaseFragment hostingActivityRef; + private View fab; + + private ArrayList messages = new ArrayList(); + private MessageCenterRecyclerViewAdapter messageCenterRecyclerViewAdapter; private MessageCenterRecyclerView messageCenterRecyclerView; // Holder and view references @@ -127,48 +131,32 @@ public class MessageCenterFragment extends ApptentiveBaseFragment pendingAttachments = new ArrayList(); - private View fab; + private boolean pendingWhoCardMode; + private String pendingWhoCardAvatarFile; + private Parcelable pendingWhoCardName; + private Parcelable pendingWhoCardEmail; private boolean forceShowKeyboard; - // Data backing of the listview - private ArrayList messages = new ArrayList(); - private MessageCenterRecyclerViewAdapter messageCenterRecyclerViewAdapter; // MesssageCenterView is set to paused when it fails to send message private boolean isPaused = false; // Count how many paused ongoing messages private int unsentMessagesCount = 0; + // TODO: Remove this? // Data Item references private ContextMessage contextMessage; - //private ArrayList imageAttachmentstList = new ArrayList(); - - /** - * Used to save the state of the message text box if the user closes Message Center for a moment, - * , rotate device, attaches a file, etc. - */ - private Parcelable composingViewSavedState; - private ArrayList pendingAttachments = new ArrayList(); - - /* - * Set to true when user launches image picker, and set to false once an image is picked - * This is used to track if the user tried to attach an image but abandoned the image picker - * without picking anything - */ - private boolean imagePickerLaunched = false; - - /** - * Used to save the state of the who card if the user closes Message Center for a moment, - * , rotate device, attaches a file, etc. - */ - private boolean pendingWhoCardMode; - private Parcelable pendingWhoCardName; - private Parcelable pendingWhoCardEmail; - private String pendingWhoCardAvatarFile; - private int listViewSavedTopIndex = -1; private int listViewSavedTopOffset; @@ -286,7 +274,7 @@ public void onActivityResult(int requestCode, int resultCode, Intent data) { ApptentiveLog.d("no image is picked"); return; } - imagePickerLaunched = false; + imagePickerStillOpen = false; Uri uri; Activity hostingActivity = hostingActivityRef.get(); //Android SDK less than 19 @@ -340,13 +328,13 @@ public void onResume() { super.onResume(); ApptentiveInternal.getInstance().getMessageManager().resumeSending(); - /* imagePickerLaunched was set true when the picker intent was launched. If user had picked an image, + /* imagePickerStillOpen was set true when the picker intent was launched. If user had picked an image, * it woud have been set to false. Otherwise, it indicates the user tried to attach an image but * abandoned the image picker without picking anything */ - if (imagePickerLaunched) { + if (imagePickerStillOpen) { EngagementModule.engageInternal(hostingActivityRef.get(), interaction, MessageCenterInteraction.EVENT_NAME_ATTACHMENT_CANCEL); - imagePickerLaunched = false; + imagePickerStillOpen = false; } } @@ -1091,10 +1079,10 @@ public void onAttachImage() { Intent chooserIntent = Intent.createChooser(intent, null); startActivityForResult(chooserIntent, Constants.REQUEST_CODE_PHOTO_FROM_SYSTEM_PICKER); } - imagePickerLaunched = true; + imagePickerStillOpen = true; } catch (Exception e) { e.printStackTrace(); - imagePickerLaunched = false; + imagePickerStillOpen = false; ApptentiveLog.d("can't launch image picker"); } } From a57181a1fd11adde8a86f5bc2e42b74d4c35e232 Mon Sep 17 00:00:00 2001 From: skykelsey Date: Sat, 5 Nov 2016 13:32:25 -0700 Subject: [PATCH 033/100] Fix Context Message sending. Remove dead code. --- .../fragment/MessageCenterFragment.java | 49 +++---------------- 1 file changed, 7 insertions(+), 42 deletions(-) diff --git a/apptentive/src/main/java/com/apptentive/android/sdk/module/engagement/interaction/fragment/MessageCenterFragment.java b/apptentive/src/main/java/com/apptentive/android/sdk/module/engagement/interaction/fragment/MessageCenterFragment.java index b1cda1993..d26e6bd5d 100644 --- a/apptentive/src/main/java/com/apptentive/android/sdk/module/engagement/interaction/fragment/MessageCenterFragment.java +++ b/apptentive/src/main/java/com/apptentive/android/sdk/module/engagement/interaction/fragment/MessageCenterFragment.java @@ -53,7 +53,6 @@ import com.apptentive.android.sdk.module.messagecenter.model.MessageCenterUtil; import com.apptentive.android.sdk.module.messagecenter.model.WhoCard; import com.apptentive.android.sdk.module.messagecenter.view.AttachmentPreviewDialog; -import com.apptentive.android.sdk.module.messagecenter.view.MessageCenterListView; import com.apptentive.android.sdk.module.messagecenter.view.MessageCenterRecyclerView; import com.apptentive.android.sdk.module.messagecenter.view.MessageCenterRecyclerViewAdapter; import com.apptentive.android.sdk.module.messagecenter.view.holder.MessageComposerHolder; @@ -93,7 +92,6 @@ public class MessageCenterFragment extends ApptentiveBaseFragment h && oldh - h > 100) { -/* TODO: Replace this? - if (messageCenterRecyclerViewAdapter.getComposerEditText() != null) { - // When keyboard is up, adjust the scolling such that the cursor is always visible - final int firstIndex = messageCenterRecyclerView.getFirstVisiblePosition(); - int lastIndex = messageCenterRecyclerView.getLastVisiblePosition(); - View v = messageCenterRecyclerView.getChildAt(lastIndex - firstIndex); - int top = (v == null) ? 0 : v.getTop(); - if (composerEditText != null) { - int pos = composerEditText.getSelectionStart(); - Layout layout = composerEditText.getLayout(); - int line = layout.getLineForOffset(pos); - int baseline = layout.getLineBaseline(line); - int ascent = layout.getLineAscent(line); - if (top + baseline - ascent > oldh - h) { - messagingActionHandler.sendMessageDelayed(messagingActionHandler.obtainMessage(MSG_SCROLL_FROM_TOP, - lastIndex, top - (oldh - h)), DEFAULT_DELAYMILLIS); - } else { - messagingActionHandler.sendMessageDelayed(messagingActionHandler.obtainMessage(MSG_SCROLL_FROM_TOP, - lastIndex, top), DEFAULT_DELAYMILLIS); - } - } - } -*/ - } - } - - /* Callback when the attach button is clicked - * - */ @Override public void onAttachImage() { try { @@ -1605,8 +1571,7 @@ public void handleMessage(Message msg) { case MSG_ADD_CONTEXT_MESSAGE: { ApptentiveLog.e("Adding Context Message"); List messages = fragment.messages; - String body = (String) msg.obj; - ContextMessage contextMessage = new ContextMessage(body); + ContextMessage contextMessage = (ContextMessage) msg.obj; messages.add(contextMessage); fragment.messageCenterRecyclerViewAdapter.notifyItemInserted(messages.size() - 1); break; From 15316c47c48a6f00a10f7e27b3ef2207d726ba63 Mon Sep 17 00:00:00 2001 From: skykelsey Date: Sun, 6 Nov 2016 15:41:25 -0800 Subject: [PATCH 034/100] Clean up status message insertion. --- .../fragment/MessageCenterFragment.java | 18 +++--------------- 1 file changed, 3 insertions(+), 15 deletions(-) diff --git a/apptentive/src/main/java/com/apptentive/android/sdk/module/engagement/interaction/fragment/MessageCenterFragment.java b/apptentive/src/main/java/com/apptentive/android/sdk/module/engagement/interaction/fragment/MessageCenterFragment.java index d26e6bd5d..0927b1ebe 100644 --- a/apptentive/src/main/java/com/apptentive/android/sdk/module/engagement/interaction/fragment/MessageCenterFragment.java +++ b/apptentive/src/main/java/com/apptentive/android/sdk/module/engagement/interaction/fragment/MessageCenterFragment.java @@ -1524,27 +1524,15 @@ public void handleMessage(Message msg) { } case MSG_OPT_INSERT_REGULAR_STATUS: { List messages = fragment.messages; - MessageCenterStatus status = fragment.interaction.getRegularStatus(); -/* - for (int i = 0; i < messages.size(); i++) { - MessageCenterUtil.MessageCenterListItem item = messages.get(i); - if (item.getListItemType() == MESSAGE_COMPOSER) { - ApptentiveLog.e("Removing Composer"); - messages.remove(i); - fragment.messageCenterRecyclerViewAdapter.notifyItemRemoved(i); - } - } -*/ - - int numOfMessages = messages.size(); - if (numOfMessages > 0) { - // Check if the last message in the view is a sent message + // Only add status if the last item in the list is a sent message. + if (messages.size() > 0) { MessageCenterUtil.MessageCenterListItem lastItem = messages.get(messages.size() - 1); if (lastItem != null && lastItem.getListItemType() == MESSAGE_OUTGOING) { ApptentiveMessage apptentiveMessage = (ApptentiveMessage) lastItem; if (apptentiveMessage.isOutgoingMessage()) { Double createdTime = apptentiveMessage.getCreatedAt(); if (createdTime != null && createdTime > Double.MIN_VALUE) { + MessageCenterStatus status = fragment.interaction.getRegularStatus(); if (status != null) { // Add expectation status message if the last is a sent messages.add(status); From fba11d2d5b776b4d6daccabbed2f280fd3d551f5 Mon Sep 17 00:00:00 2001 From: skykelsey Date: Sun, 6 Nov 2016 16:02:47 -0800 Subject: [PATCH 035/100] Clean up message sending handler code. --- .../fragment/MessageCenterFragment.java | 37 +++++++++++-------- 1 file changed, 21 insertions(+), 16 deletions(-) diff --git a/apptentive/src/main/java/com/apptentive/android/sdk/module/engagement/interaction/fragment/MessageCenterFragment.java b/apptentive/src/main/java/com/apptentive/android/sdk/module/engagement/interaction/fragment/MessageCenterFragment.java index 0927b1ebe..e31949697 100644 --- a/apptentive/src/main/java/com/apptentive/android/sdk/module/engagement/interaction/fragment/MessageCenterFragment.java +++ b/apptentive/src/main/java/com/apptentive/android/sdk/module/engagement/interaction/fragment/MessageCenterFragment.java @@ -907,21 +907,21 @@ public void onFinishComposing() { Util.hideSoftKeyboard(hostingActivityRef.get(), getView()); if (contextMessage != null) { - // TODO: Maybe simply send any context messages in the list when a message is sent? Message sendContextMessage = messagingActionHandler.obtainMessage(MSG_SEND_CONTEXT_MESSAGE, contextMessage.getBody()); unsentMessagesCount++; messagingActionHandler.sendMessage(sendContextMessage); contextMessage = null; } if (!TextUtils.isEmpty(composerEditText.getText()) || pendingAttachments.size() > 0) { - Bundle b = new Bundle(); - b.putString(COMPOSING_EDITTEXT_STATE, composerEditText.getText().toString()); - b.putParcelableArrayList(COMPOSING_ATTACHMENTS, new ArrayList(pendingAttachments)); - Message msg = messagingActionHandler.obtainMessage(MSG_START_SENDING, composerEditText.getText().toString()); - msg.setData(b); - ApptentiveLog.e("Send Send Message Message"); + CompoundMessage compoundMessage = new CompoundMessage(); + compoundMessage.setBody(composerEditText.getText().toString()); + compoundMessage.setRead(true); + compoundMessage.setCustomData(ApptentiveInternal.getInstance().getAndClearCustomData()); + compoundMessage.setAssociatedImages(new ArrayList(pendingAttachments)); + unsentMessagesCount++; - messagingActionHandler.sendMessage(msg); + isPaused = false; + messagingActionHandler.sendMessage(messagingActionHandler.obtainMessage(MSG_START_SENDING, compoundMessage)); composingViewSavedState = null; composerEditText.getText().clear(); pendingAttachments.clear(); @@ -1411,16 +1411,21 @@ public void handleMessage(Message msg) { break; } case MSG_START_SENDING: { - Bundle b = msg.getData(); - CompoundMessage message = new CompoundMessage(); - message.setBody(b.getString(COMPOSING_EDITTEXT_STATE)); - message.setRead(true); - message.setCustomData(ApptentiveInternal.getInstance().getAndClearCustomData()); - ArrayList imagesToAttach = b.getParcelableArrayList(COMPOSING_ATTACHMENTS); - message.setAssociatedImages(imagesToAttach); - + CompoundMessage message = (CompoundMessage) msg.obj; ApptentiveLog.e("Adding Message to list"); fragment.messages.add(message); + fragment.messageCenterRecyclerViewAdapter.notifyItemInserted(fragment.messages.size() - 1); + +/* + messagingActionHandler.sendEmptyMessage(MSG_REMOVE_STATUS); + messages.add(message); + messageCenterRecyclerViewAdapter.notifyItemInserted(messages.size() - 1); + unsentMessagesCount++; + isPaused = false; + if (messageCenterRecyclerViewAdapter != null) { + messageCenterRecyclerViewAdapter.setPaused(isPaused); + } +*/ ApptentiveLog.e("Sending message"); ApptentiveInternal.getInstance().getMessageManager().sendMessage(message); From 045d8a18c23569d4f326ce41c0d90717c895b9de Mon Sep 17 00:00:00 2001 From: skykelsey Date: Sun, 6 Nov 2016 21:12:56 -0800 Subject: [PATCH 036/100] Stop calling pause twice when a message fails to send. --- .../com/apptentive/android/sdk/storage/PayloadSendWorker.java | 3 --- 1 file changed, 3 deletions(-) diff --git a/apptentive/src/main/java/com/apptentive/android/sdk/storage/PayloadSendWorker.java b/apptentive/src/main/java/com/apptentive/android/sdk/storage/PayloadSendWorker.java index bd45b9039..f997d4c4e 100644 --- a/apptentive/src/main/java/com/apptentive/android/sdk/storage/PayloadSendWorker.java +++ b/apptentive/src/main/java/com/apptentive/android/sdk/storage/PayloadSendWorker.java @@ -183,9 +183,6 @@ public void run() { ApptentiveLog.v("Rejected json:", payload.toString()); ApptentiveInternal.getInstance().getApptentiveTaskManager().deletePayload(payload); } else if (response.isRejectedTemporarily()) { - if (mgr != null) { - mgr.pauseSending(MessageManager.SEND_PAUSE_REASON_SERVER); - } ApptentiveLog.d("Unable to send JSON. Leaving in queue."); if (response.isException()) { retryLater(NO_CONNECTION_SLEEP_TIME); From 3a72aaf15242303226de99b76282c22a8a0536cc Mon Sep 17 00:00:00 2001 From: skykelsey Date: Sun, 6 Nov 2016 21:13:27 -0800 Subject: [PATCH 037/100] Get message error pause/resume state working again. --- .../fragment/MessageCenterFragment.java | 88 ++++++++----------- .../MessageCenterRecyclerViewAdapter.java | 8 +- .../holder/IncomingCompoundMessageHolder.java | 6 +- .../view/holder/MessageHolder.java | 3 +- .../holder/OutgoingCompoundMessageHolder.java | 17 ++-- 5 files changed, 54 insertions(+), 68 deletions(-) diff --git a/apptentive/src/main/java/com/apptentive/android/sdk/module/engagement/interaction/fragment/MessageCenterFragment.java b/apptentive/src/main/java/com/apptentive/android/sdk/module/engagement/interaction/fragment/MessageCenterFragment.java index e31949697..d99ee9557 100644 --- a/apptentive/src/main/java/com/apptentive/android/sdk/module/engagement/interaction/fragment/MessageCenterFragment.java +++ b/apptentive/src/main/java/com/apptentive/android/sdk/module/engagement/interaction/fragment/MessageCenterFragment.java @@ -177,6 +177,7 @@ public class MessageCenterFragment extends ApptentiveBaseFragment(pendingAttachments)); - unsentMessagesCount++; - isPaused = false; messagingActionHandler.sendMessage(messagingActionHandler.obtainMessage(MSG_START_SENDING, compoundMessage)); composingViewSavedState = null; composerEditText.getText().clear(); @@ -1415,17 +1400,8 @@ public void handleMessage(Message msg) { ApptentiveLog.e("Adding Message to list"); fragment.messages.add(message); fragment.messageCenterRecyclerViewAdapter.notifyItemInserted(fragment.messages.size() - 1); - -/* - messagingActionHandler.sendEmptyMessage(MSG_REMOVE_STATUS); - messages.add(message); - messageCenterRecyclerViewAdapter.notifyItemInserted(messages.size() - 1); - unsentMessagesCount++; - isPaused = false; - if (messageCenterRecyclerViewAdapter != null) { - messageCenterRecyclerViewAdapter.setPaused(isPaused); - } -*/ + fragment.unsentMessagesCount++; + fragment.setPaused(false); ApptentiveLog.e("Sending message"); ApptentiveInternal.getInstance().getMessageManager().sendMessage(message); @@ -1481,37 +1457,23 @@ public void handleMessage(Message msg) { } case MSG_PAUSE_SENDING: { ApptentiveLog.e("PAUSE"); - if (!fragment.isPaused) { - fragment.isPaused = true; + if (!fragment.isPaused()) { + fragment.setPaused(true); if (fragment.unsentMessagesCount > 0) { - fragment.messageCenterRecyclerViewAdapter.setPaused(fragment.isPaused); int reason = msg.arg1; - if (reason == MessageManager.SEND_PAUSE_REASON_NETWORK) { - EngagementModule.engageInternal(fragment.hostingActivityRef.get(), fragment.interaction, MessageCenterInteraction.EVENT_NAME_MESSAGE_NETWORK_ERROR); - MessageCenterStatus newItem = fragment.interaction.getErrorStatusNetwork(); - // TODO: fragment.addNewStatusItem(newItem); - } else if (reason == MessageManager.SEND_PAUSE_REASON_SERVER) { - EngagementModule.engageInternal(fragment.hostingActivityRef.get(), fragment.interaction, MessageCenterInteraction.EVENT_NAME_MESSAGE_HTTP_ERROR); - MessageCenterStatus newItem = fragment.interaction.getErrorStatusServer(); - // TODO: fragment.addNewStatusItem(newItem); - } - //TODO: Do this better - fragment.messageCenterRecyclerViewAdapter.notifyDataSetChanged(); + Message handlerMessage = fragment.messagingActionHandler.obtainMessage(MSG_ADD_STATUS_ERROR, reason, 0); + fragment.messagingActionHandler.sendMessage(handlerMessage); } } break; } case MSG_RESUME_SENDING: { ApptentiveLog.e("RESUME"); - if (fragment.isPaused) { - fragment.isPaused = false; + if (fragment.isPaused()) { + fragment.setPaused(false); if (fragment.unsentMessagesCount > 0) { - // TODO: fragment.clearStatusItem(); + fragment.messagingActionHandler.sendEmptyMessage(MSG_REMOVE_STATUS); } - - fragment.messageCenterRecyclerViewAdapter.setPaused(fragment.isPaused); - // TODO: Do this better - fragment.messageCenterRecyclerViewAdapter.notifyDataSetChanged(); } break; } @@ -1574,6 +1536,22 @@ public void handleMessage(Message msg) { fragment.messageCenterRecyclerViewAdapter.notifyItemInserted(0); break; } + case MSG_ADD_STATUS_ERROR: { + int reason = msg.arg1; + MessageCenterStatus status = null; + if (reason == MessageManager.SEND_PAUSE_REASON_NETWORK) { + status = fragment.interaction.getErrorStatusNetwork(); + EngagementModule.engageInternal(fragment.hostingActivityRef.get(), fragment.interaction, MessageCenterInteraction.EVENT_NAME_MESSAGE_NETWORK_ERROR); + } else if (reason == MessageManager.SEND_PAUSE_REASON_SERVER) { + status = fragment.interaction.getErrorStatusServer(); + EngagementModule.engageInternal(fragment.hostingActivityRef.get(), fragment.interaction, MessageCenterInteraction.EVENT_NAME_MESSAGE_HTTP_ERROR); + } + if (status != null) { + fragment.messages.add(status); + fragment.messageCenterRecyclerViewAdapter.notifyItemInserted(fragment.messages.size() - 1); + } + break; + } } } } @@ -1586,4 +1564,16 @@ public boolean recyclerViewContainsItemOfType(int type) { } return false; } + + public void setPaused(boolean paused) { + if (isPaused ^ paused) { + // TODO: Do I want to invalidate all the views here? + messageCenterRecyclerViewAdapter.notifyDataSetChanged(); + } + isPaused = paused; + } + + public boolean isPaused() { + return isPaused; + } } \ No newline at end of file diff --git a/apptentive/src/main/java/com/apptentive/android/sdk/module/messagecenter/view/MessageCenterRecyclerViewAdapter.java b/apptentive/src/main/java/com/apptentive/android/sdk/module/messagecenter/view/MessageCenterRecyclerViewAdapter.java index d55f69e74..3ea845b3a 100644 --- a/apptentive/src/main/java/com/apptentive/android/sdk/module/messagecenter/view/MessageCenterRecyclerViewAdapter.java +++ b/apptentive/src/main/java/com/apptentive/android/sdk/module/messagecenter/view/MessageCenterRecyclerViewAdapter.java @@ -170,7 +170,7 @@ public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) { ApptentiveLog.w("-> Message Incoming"); CompoundMessage compoundMessage = (CompoundMessage) messages.get(position); IncomingCompoundMessageHolder compoundHolder = (IncomingCompoundMessageHolder) holder; - compoundHolder.bindView(recyclerView, compoundMessage); + compoundHolder.bindView(fragment, recyclerView, compoundMessage); // Mark as read if (!compoundMessage.isRead() && !messagesWithPendingReadStatusUpdate.contains(compoundMessage)) { messagesWithPendingReadStatusUpdate.add(compoundMessage); @@ -183,7 +183,7 @@ public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) { ApptentiveLog.w("-> Message Outgoing"); CompoundMessage compoundMessage = (CompoundMessage) messages.get(position); OutgoingCompoundMessageHolder compoundHolder = (OutgoingCompoundMessageHolder) holder; - compoundHolder.bindView(recyclerView, compoundMessage); + compoundHolder.bindView(fragment, recyclerView, compoundMessage); break; } case MESSAGE_AUTO: { @@ -228,10 +228,6 @@ public int getItemViewType(int position) { return message.getListItemType(); } - public void setPaused(boolean bPause) { - //isInPauseState = bPause; // TODO - } - public String getWhoCardAvatarFileName() { return null; // TODO } diff --git a/apptentive/src/main/java/com/apptentive/android/sdk/module/messagecenter/view/holder/IncomingCompoundMessageHolder.java b/apptentive/src/main/java/com/apptentive/android/sdk/module/messagecenter/view/holder/IncomingCompoundMessageHolder.java index 7e3304388..e0b7ce4d1 100644 --- a/apptentive/src/main/java/com/apptentive/android/sdk/module/messagecenter/view/holder/IncomingCompoundMessageHolder.java +++ b/apptentive/src/main/java/com/apptentive/android/sdk/module/messagecenter/view/holder/IncomingCompoundMessageHolder.java @@ -13,6 +13,7 @@ import com.apptentive.android.sdk.R; import com.apptentive.android.sdk.model.StoredFile; +import com.apptentive.android.sdk.module.engagement.interaction.fragment.MessageCenterFragment; import com.apptentive.android.sdk.module.messagecenter.model.CompoundMessage; import com.apptentive.android.sdk.module.messagecenter.view.ApptentiveAvatarView; import com.apptentive.android.sdk.module.messagecenter.view.MessageAdapter; @@ -47,13 +48,12 @@ public IncomingCompoundMessageHolder(View itemView) { imageBandView = (ApptentiveImageGridView) itemView.findViewById(R.id.grid); } - public void bindView(final RecyclerView parent, final CompoundMessage message) { - super.bindView(parent, message); + public void bindView(MessageCenterFragment fragment, final RecyclerView parent, final CompoundMessage message) { + super.bindView(fragment, parent, message); imageBandView.setupUi(); if (loadAvatar) { ImageUtil.startDownloadAvatarTask(avatar, message.getSenderProfilePhoto()); } - String datestamp = message.getDatestamp(); int widthMeasureSpec = View.MeasureSpec.makeMeasureSpec(parent.getWidth(), View.MeasureSpec.EXACTLY); root.measure(widthMeasureSpec, 0); diff --git a/apptentive/src/main/java/com/apptentive/android/sdk/module/messagecenter/view/holder/MessageHolder.java b/apptentive/src/main/java/com/apptentive/android/sdk/module/messagecenter/view/holder/MessageHolder.java index 23de625fa..fef57d5a4 100644 --- a/apptentive/src/main/java/com/apptentive/android/sdk/module/messagecenter/view/holder/MessageHolder.java +++ b/apptentive/src/main/java/com/apptentive/android/sdk/module/messagecenter/view/holder/MessageHolder.java @@ -12,6 +12,7 @@ import android.widget.TextView; import com.apptentive.android.sdk.R; +import com.apptentive.android.sdk.module.engagement.interaction.fragment.MessageCenterFragment; import com.apptentive.android.sdk.module.messagecenter.model.CompoundMessage; public abstract class MessageHolder extends RecyclerView.ViewHolder { @@ -22,7 +23,7 @@ public MessageHolder(View itemView) { datestamp = (TextView) itemView.findViewById(R.id.datestamp); } - public void bindView(RecyclerView recyclerView, CompoundMessage message) { // final String datestampString, final int statusColor, final String statusString) { + public void bindView(MessageCenterFragment fragment, RecyclerView recyclerView, CompoundMessage message) { String datestampString = message.getDatestamp(); datestamp.setText(datestampString); datestamp.setVisibility(!TextUtils.isEmpty(datestampString) ? View.VISIBLE : View.GONE); diff --git a/apptentive/src/main/java/com/apptentive/android/sdk/module/messagecenter/view/holder/OutgoingCompoundMessageHolder.java b/apptentive/src/main/java/com/apptentive/android/sdk/module/messagecenter/view/holder/OutgoingCompoundMessageHolder.java index 20f7031ef..39a8d9672 100644 --- a/apptentive/src/main/java/com/apptentive/android/sdk/module/messagecenter/view/holder/OutgoingCompoundMessageHolder.java +++ b/apptentive/src/main/java/com/apptentive/android/sdk/module/messagecenter/view/holder/OutgoingCompoundMessageHolder.java @@ -13,6 +13,7 @@ import com.apptentive.android.sdk.R; import com.apptentive.android.sdk.model.StoredFile; +import com.apptentive.android.sdk.module.engagement.interaction.fragment.MessageCenterFragment; import com.apptentive.android.sdk.module.messagecenter.model.CompoundMessage; import com.apptentive.android.sdk.util.Util; import com.apptentive.android.sdk.util.image.ApptentiveImageGridView; @@ -41,19 +42,18 @@ public OutgoingCompoundMessageHolder(View itemView) { status = (TextView) itemView.findViewById(R.id.status); } - public void bindView(final RecyclerView recyclerView, final CompoundMessage message) { - super.bindView(recyclerView, message); + public void bindView(MessageCenterFragment fragment, final RecyclerView recyclerView, final CompoundMessage message) { + super.bindView(fragment, recyclerView, message); imageBandView.setupUi(); messageBodyView.setText(message.getBody()); - boolean isPaused = false; //TODO boolean showProgress; Double createdAt = message.getCreatedAt(); String statusText; if (createdAt == null || createdAt > Double.MIN_VALUE) { // show progress bar if: 1. no sent time set, and 2. not paused, and 3. have either text or files to sent - showProgress = createdAt == null && !isPaused && (message.getAssociatedFiles() != null || !TextUtils.isEmpty(message.getBody())); - statusText = createStatus(createdAt, message.isLastSent()); + showProgress = createdAt == null && !fragment.isPaused() && (message.getAssociatedFiles() != null || !TextUtils.isEmpty(message.getBody())); + statusText = createStatus(createdAt, message.isLastSent(), fragment.isPaused()); } else { showProgress = false; statusText = itemView.getResources().getString(R.string.apptentive_failed); @@ -90,14 +90,13 @@ public void bindView(final RecyclerView recyclerView, final CompoundMessage mess } status.setText(statusText); - status.setTextColor(getStatusColor(createdAt, isPaused)); + status.setTextColor(getStatusColor(createdAt, fragment.isPaused())); status.setVisibility(!TextUtils.isEmpty(statusText) ? View.VISIBLE : View.GONE); } - protected String createStatus(Double seconds, boolean showSent) { + protected String createStatus(Double seconds, boolean showSent, boolean isPaused) { if (seconds == null) { - boolean isInPauseState = false; // TODO - return isInPauseState ? itemView.getResources().getString(R.string.apptentive_failed) : null; + return isPaused ? itemView.getResources().getString(R.string.apptentive_failed) : null; } return (showSent) ? itemView.getResources().getString(R.string.apptentive_sent) : null; } From da45bc303b393159fd614a2eade9ca29c6589545 Mon Sep 17 00:00:00 2001 From: skykelsey Date: Sun, 6 Nov 2016 22:23:59 -0800 Subject: [PATCH 038/100] Fix text selection and focusing issue with Composer View. --- .../fragment/MessageCenterFragment.java | 18 +++- .../MessageCenterRecyclerViewAdapter.java | 28 +++--- .../view/holder/MessageComposerHolder.java | 92 +++++-------------- .../sdk/util/image/ImageGridViewAdapter.java | 1 - 4 files changed, 50 insertions(+), 89 deletions(-) diff --git a/apptentive/src/main/java/com/apptentive/android/sdk/module/engagement/interaction/fragment/MessageCenterFragment.java b/apptentive/src/main/java/com/apptentive/android/sdk/module/engagement/interaction/fragment/MessageCenterFragment.java index d99ee9557..9a6ae9589 100644 --- a/apptentive/src/main/java/com/apptentive/android/sdk/module/engagement/interaction/fragment/MessageCenterFragment.java +++ b/apptentive/src/main/java/com/apptentive/android/sdk/module/engagement/interaction/fragment/MessageCenterFragment.java @@ -698,13 +698,14 @@ public void setAttachmentsInComposer(final List images) { // TODO: This needs to be sent through the Handler public void removeImageFromComposer(final int position) { + ApptentiveLog.e("removeImageFromComposer()"); EngagementModule.engageInternal(hostingActivityRef.get(), interaction, MessageCenterInteraction.EVENT_NAME_ATTACHMENT_DELETE); pendingAttachments.remove(position); if (messageCenterRecyclerViewAdapter != null) { messageCenterRecyclerViewAdapter.removeImageFromComposer(composer, position); // int count = imageAttachmentstList.size(); // Show keyboard if all attachments have been removed - messageCenterRecyclerViewAdapter.notifyDataSetChanged(); + messageCenterRecyclerViewAdapter.notifyDataSetChanged(); // TODO: Only invalidate the composer } messagingActionHandler.sendEmptyMessageDelayed(MSG_SCROLL_TO_BOTTOM, DEFAULT_DELAYMILLIS); } @@ -1103,7 +1104,6 @@ private Parcelable saveEditTextInstanceState() { Set dateStampsSeen = new HashSet(); public void updateMessageSentStates() { - ApptentiveLog.e("Updating datestamps"); dateStampsSeen.clear(); MessageCenterUtil.CompoundMessageCommonInterface lastSent = null; Set uniqueNonce = new HashSet(); @@ -1126,7 +1126,6 @@ public void updateMessageSentStates() { ApptentiveMessage apptentiveMessage = (ApptentiveMessage) message; Double sentOrReceivedAt = apptentiveMessage.getCreatedAt(); String dateStamp = createDatestamp(sentOrReceivedAt); - ApptentiveLog.e("Looking at datestamp: %s", dateStamp); if (dateStamp != null) { if (dateStampsSeen.add(dateStamp)) { if (apptentiveMessage.setDatestamp(dateStamp)) { @@ -1568,7 +1567,18 @@ public boolean recyclerViewContainsItemOfType(int type) { public void setPaused(boolean paused) { if (isPaused ^ paused) { // TODO: Do I want to invalidate all the views here? - messageCenterRecyclerViewAdapter.notifyDataSetChanged(); + //messageCenterRecyclerViewAdapter.notifyDataSetChanged(); + // Invalidate any unsent messages, as these will have status and progress bars that need to change. + for (int i = 0; i < messages.size(); i++) { + MessageCenterUtil.MessageCenterListItem item = messages.get(i); + if (item instanceof ApptentiveMessage) { + ApptentiveMessage message = (ApptentiveMessage) item; + if (message.isOutgoingMessage() && message.getCreatedAt() == null) { + messageCenterRecyclerViewAdapter.notifyItemChanged(i); + ApptentiveLog.e("Invalidated: %s", message.toString()); + } + } + } } isPaused = paused; } diff --git a/apptentive/src/main/java/com/apptentive/android/sdk/module/messagecenter/view/MessageCenterRecyclerViewAdapter.java b/apptentive/src/main/java/com/apptentive/android/sdk/module/messagecenter/view/MessageCenterRecyclerViewAdapter.java index 3ea845b3a..2916edae4 100644 --- a/apptentive/src/main/java/com/apptentive/android/sdk/module/messagecenter/view/MessageCenterRecyclerViewAdapter.java +++ b/apptentive/src/main/java/com/apptentive/android/sdk/module/messagecenter/view/MessageCenterRecyclerViewAdapter.java @@ -79,52 +79,52 @@ public void onAttachedToRecyclerView(RecyclerView recyclerView) { @Override public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) { - ApptentiveLog.e("onCreateViewHolder()"); +// ApptentiveLog.e("onCreateViewHolder()"); switch (viewType) { case MESSAGE_COMPOSER: { - ApptentiveLog.w("-> Message Composer"); +// ApptentiveLog.w("-> Message Composer"); LayoutInflater inflater = LayoutInflater.from(parent.getContext()); View view = inflater.inflate(R.layout.apptentive_message_center_composer, parent, false); return new MessageComposerHolder(view); } case STATUS: { - ApptentiveLog.w("-> Status"); +// ApptentiveLog.w("-> Status"); LayoutInflater inflater = LayoutInflater.from(parent.getContext()); View view = inflater.inflate(R.layout.apptentive_message_center_status, parent, false); return new StatusHolder(view); } case GREETING: { - ApptentiveLog.w("-> Greeting"); +// ApptentiveLog.w("-> Greeting"); LayoutInflater inflater = LayoutInflater.from(parent.getContext()); View view = inflater.inflate(R.layout.apptentive_message_center_greeting, parent, false); return new GreetingHolder(view); } case MESSAGE_OUTGOING: { - ApptentiveLog.w("-> Message Outgoing"); +// ApptentiveLog.w("-> Message Outgoing"); LayoutInflater inflater = LayoutInflater.from(parent.getContext()); View view = inflater.inflate(R.layout.apptentive_message_outgoing, parent, false); return new OutgoingCompoundMessageHolder(view); } case MESSAGE_INCOMING: { - ApptentiveLog.w("-> Message Incoming"); +// ApptentiveLog.w("-> Message Incoming"); LayoutInflater inflater = LayoutInflater.from(parent.getContext()); View view = inflater.inflate(R.layout.apptentive_message_incoming, parent, false); return new IncomingCompoundMessageHolder(view); } case MESSAGE_AUTO: { - ApptentiveLog.w("-> Message Auto"); +// ApptentiveLog.w("-> Message Auto"); LayoutInflater inflater = LayoutInflater.from(parent.getContext()); View view = inflater.inflate(R.layout.apptentive_message_auto, parent, false); return new AutomatedMessageHolder(view); } case WHO_CARD: { - ApptentiveLog.w("-> Who Card"); +// ApptentiveLog.w("-> Who Card"); LayoutInflater inflater = LayoutInflater.from(parent.getContext()); View view = inflater.inflate(R.layout.apptentive_message_center_who_card, parent, false); return new WhoCardHolder(this, view); } case MESSAGE_CONTEXT: { - ApptentiveLog.w("-> Message Context"); +// ApptentiveLog.w("-> Message Context"); LayoutInflater inflater = LayoutInflater.from(parent.getContext()); View view = inflater.inflate(R.layout.apptentive_message_center_context_message, parent, false); return new ContextMessageHolder(view); @@ -211,10 +211,12 @@ public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) { } @Override - public void onViewRecycled(RecyclerView.ViewHolder holder) { - super.onViewRecycled(holder); - ApptentiveLog.e("View recycled: %s", holder.toString()); - // TODO: Remove listeners, and clean up here? + public void onViewAttachedToWindow(RecyclerView.ViewHolder holder) { + super.onViewAttachedToWindow(holder); + if (holder instanceof MessageComposerHolder) { + MessageComposerHolder composer = (MessageComposerHolder) holder; + composer.onViewAttachedToWindow(); + } } @Override diff --git a/apptentive/src/main/java/com/apptentive/android/sdk/module/messagecenter/view/holder/MessageComposerHolder.java b/apptentive/src/main/java/com/apptentive/android/sdk/module/messagecenter/view/holder/MessageComposerHolder.java index ba5666094..e85fdee75 100644 --- a/apptentive/src/main/java/com/apptentive/android/sdk/module/messagecenter/view/holder/MessageComposerHolder.java +++ b/apptentive/src/main/java/com/apptentive/android/sdk/module/messagecenter/view/holder/MessageComposerHolder.java @@ -14,16 +14,9 @@ import android.support.v4.graphics.drawable.DrawableCompat; import android.support.v7.widget.RecyclerView; import android.text.Editable; -import android.text.Layout; -import android.text.Selection; -import android.text.Spannable; import android.text.TextUtils; import android.text.TextWatcher; -import android.text.method.ArrowKeyMovementMethod; -import android.text.method.MovementMethod; -import android.text.style.ClickableSpan; import android.text.util.Linkify; -import android.view.MotionEvent; import android.view.View; import android.widget.EditText; import android.widget.ImageButton; @@ -43,17 +36,18 @@ import java.util.ArrayList; import java.util.List; - public class MessageComposerHolder extends RecyclerView.ViewHolder { - List images; + private List images; - public ImageButton closeButton; - public TextView title; - public ImageButton attachButton; - public ImageButton sendButton; + private ImageButton closeButton; + private TextView title; + private ImageButton attachButton; + private ImageButton sendButton; public EditText message; - public ApptentiveImageGridView attachments; + private ApptentiveImageGridView attachments; + + private TextWatcher textWatcher; public MessageComposerHolder(View itemView) { super(itemView); @@ -107,18 +101,9 @@ public void onClick(View view) { }); message.setHint(composer.messageHint); - message.setLinksClickable(true); - message.setAutoLinkMask(Linkify.WEB_URLS | Linkify.PHONE_NUMBERS | Linkify.EMAIL_ADDRESSES | Linkify.MAP_ADDRESSES); - /* - * LinkMovementMethod would enable clickable links in EditView, but disables copy/paste through Long Press. - * Use a custom MovementMethod instead - * - */ - message.setMovementMethod(ApptentiveMovementMethod.getInstance()); - //If the edit text contains previous text with potential links - Linkify.addLinks(message, Linkify.WEB_URLS); - - message.addTextChangedListener(new TextWatcher() { + + message.removeTextChangedListener(textWatcher); + textWatcher = new TextWatcher() { @Override public void beforeTextChanged(CharSequence charSequence, int i, int i2, int i3) { if (adapter.getListener() != null) { @@ -140,7 +125,8 @@ public void afterTextChanged(Editable editable) { } Linkify.addLinks(editable, Linkify.WEB_URLS | Linkify.PHONE_NUMBERS | Linkify.EMAIL_ADDRESSES | Linkify.MAP_ADDRESSES); } - }); + }; + message.addTextChangedListener(textWatcher); // Use a color state list for button tint state on Lollipop. On prior platforms, need to apply state color manually. @@ -172,7 +158,6 @@ public void onClick(int position, ImageItem image) { attachments.setImageIndicatorCallback(fragment); //Initialize image attachments band with empty data clearImageAttachmentBand(); - ApptentiveLog.e("HIDING"); attachments.setVisibility(View.GONE); attachments.setAdapterIndicator(0); attachments.setData(new ArrayList()); @@ -182,12 +167,19 @@ public void onClick(int position, ImageItem image) { } } + /** + * Workaround for this issue: https://code.google.com/p/android/issues/detail?id=208169 + */ + public void onViewAttachedToWindow() { + message.setEnabled(false); + message.setEnabled(true); + } + /** * Remove all images from attachment band. */ public void clearImageAttachmentBand() { ApptentiveLog.e("CLEARING ATTACHMENTS"); - ApptentiveLog.e("HIDING"); attachments.setVisibility(View.GONE); images.clear(); attachments.setData(null); @@ -238,48 +230,6 @@ private void addAdditionalAttachItem() { attachments.setData(imagesToAdd); } - /* - * Extends Android default movement method to enable selecting text and opening the links at the same time - */ - private static class ApptentiveMovementMethod extends ArrowKeyMovementMethod { - - private static ApptentiveMovementMethod sInstance; - - public static MovementMethod getInstance() { - if (sInstance == null) { - sInstance = new ApptentiveMovementMethod(); - } - return sInstance; - } - - @Override - public boolean onTouchEvent(TextView widget, Spannable buffer, MotionEvent event) { - int action = event.getAction(); - if (action == MotionEvent.ACTION_UP || - action == MotionEvent.ACTION_DOWN) { - int x = (int) event.getX(); - int y = (int) event.getY(); - x -= widget.getTotalPaddingLeft(); - y -= widget.getTotalPaddingTop(); - x += widget.getScrollX(); - y += widget.getScrollY(); - Layout layout = widget.getLayout(); - int line = layout.getLineForVertical(y); - int off = layout.getOffsetForHorizontal(line, x); - ClickableSpan[] link = buffer.getSpans(off, off, ClickableSpan.class); - if (link.length != 0) { - if (action == MotionEvent.ACTION_UP) { - link[0].onClick(widget); - } else if (action == MotionEvent.ACTION_DOWN) { - Selection.setSelection(buffer, buffer.getSpanStart(link[0]), buffer.getSpanEnd(link[0])); - } - return true; - } - } - return super.onTouchEvent(widget, buffer, event); - } - } - public void setSendButtonState() { boolean enabled = !TextUtils.isEmpty(message.getText()) || !images.isEmpty(); if (sendButton.isEnabled() ^ enabled) { // Only if changing value diff --git a/apptentive/src/main/java/com/apptentive/android/sdk/util/image/ImageGridViewAdapter.java b/apptentive/src/main/java/com/apptentive/android/sdk/util/image/ImageGridViewAdapter.java index fedb04060..90f4b6e88 100644 --- a/apptentive/src/main/java/com/apptentive/android/sdk/util/image/ImageGridViewAdapter.java +++ b/apptentive/src/main/java/com/apptentive/android/sdk/util/image/ImageGridViewAdapter.java @@ -258,7 +258,6 @@ public View getView(int i, View view, ViewGroup viewGroup) { } else if (type == TYPE_IMAGE) { ViewHolder holder; if (view == null) { - ApptentiveLog.e("Inflating attachment image"); view = inflater.inflate(R.layout.apptentive_image_grid_view_item, viewGroup, false); holder = new ViewHolder(view, i); } else { From 666106c3b5b49ba3327013c262c631d1199fdbe8 Mon Sep 17 00:00:00 2001 From: skykelsey Date: Sun, 6 Nov 2016 22:30:33 -0800 Subject: [PATCH 039/100] Allow text to be selectable in sent, received messages, and context messages. --- apptentive/src/main/res/layout/apptentive_message_auto.xml | 1 + .../res/layout/apptentive_message_center_context_message.xml | 1 + apptentive/src/main/res/layout/apptentive_message_incoming.xml | 1 + apptentive/src/main/res/layout/apptentive_message_outgoing.xml | 1 + 4 files changed, 4 insertions(+) diff --git a/apptentive/src/main/res/layout/apptentive_message_auto.xml b/apptentive/src/main/res/layout/apptentive_message_auto.xml index 62960c3d7..11461b3b3 100644 --- a/apptentive/src/main/res/layout/apptentive_message_auto.xml +++ b/apptentive/src/main/res/layout/apptentive_message_auto.xml @@ -39,6 +39,7 @@ android:paddingBottom="@dimen/apptentive_message_center_default_margin_small" android:paddingLeft="10dp" android:paddingRight="10dp" + android:textIsSelectable="true" android:autoLink="all"/> diff --git a/apptentive/src/main/res/layout/apptentive_message_center_context_message.xml b/apptentive/src/main/res/layout/apptentive_message_center_context_message.xml index f725c7a8f..2899ece01 100644 --- a/apptentive/src/main/res/layout/apptentive_message_center_context_message.xml +++ b/apptentive/src/main/res/layout/apptentive_message_center_context_message.xml @@ -31,6 +31,7 @@ android:paddingBottom="@dimen/apptentive_message_center_default_margin_small" android:paddingLeft="10dp" android:paddingRight="10dp" + android:textIsSelectable="true" android:autoLink="all"/> diff --git a/apptentive/src/main/res/layout/apptentive_message_incoming.xml b/apptentive/src/main/res/layout/apptentive_message_incoming.xml index 7fee2a2f2..75ac05387 100644 --- a/apptentive/src/main/res/layout/apptentive_message_incoming.xml +++ b/apptentive/src/main/res/layout/apptentive_message_incoming.xml @@ -46,6 +46,7 @@ android:layout_width="wrap_content" android:layout_height="wrap_content" android:textAppearance="@style/Apptentive.TextAppearance.Body1" + android:textIsSelectable="true" android:autoLink="all"/> Date: Mon, 7 Nov 2016 11:55:50 -0800 Subject: [PATCH 040/100] Make sure the Composer is opened when MC is opened without any existing messages. --- .../interaction/fragment/MessageCenterFragment.java | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/apptentive/src/main/java/com/apptentive/android/sdk/module/engagement/interaction/fragment/MessageCenterFragment.java b/apptentive/src/main/java/com/apptentive/android/sdk/module/engagement/interaction/fragment/MessageCenterFragment.java index 9a6ae9589..aeb04277b 100644 --- a/apptentive/src/main/java/com/apptentive/android/sdk/module/engagement/interaction/fragment/MessageCenterFragment.java +++ b/apptentive/src/main/java/com/apptentive/android/sdk/module/engagement/interaction/fragment/MessageCenterFragment.java @@ -406,16 +406,17 @@ public void onClick(View v) { } /* Add who card with pending contents - ** Pending contents would be saved if the user was in composing Who card mode and exitted through back button + ** Pending contents would be saved if the user was in composing Who card mode and exited through back button */ else if (pendingWhoCardName != null || pendingWhoCardEmail != null || pendingWhoCardAvatarFile != null) { addedAnInteractiveCard = true; addWhoCard(pendingWhoCardMode); } else if (!checkAddWhoCardIfRequired()) { - /* If there is only greeting message, show composing. - * If Who Card is required, show Who Card first + /* If there are no items in the list, then it means that the Greeting will be added, but nothing else. + * In that case, show the COmposer, because Message Center hasn't been opened before. + * If Who Card is required, show Who Card first. */ - if (messages.size() == 1) { // TODO: Don't use these magic numbers everywhere + if (messages.size() == 0) { addedAnInteractiveCard = true; addComposingCard(); } else { From b6b6f01f52a2bd3af93c32deabfc1ce238cb215b Mon Sep 17 00:00:00 2001 From: skykelsey Date: Mon, 7 Nov 2016 12:01:08 -0800 Subject: [PATCH 041/100] Remove dead code and fix some comments. --- .../fragment/MessageCenterFragment.java | 24 ++++--------------- 1 file changed, 4 insertions(+), 20 deletions(-) diff --git a/apptentive/src/main/java/com/apptentive/android/sdk/module/engagement/interaction/fragment/MessageCenterFragment.java b/apptentive/src/main/java/com/apptentive/android/sdk/module/engagement/interaction/fragment/MessageCenterFragment.java index aeb04277b..173ae2984 100644 --- a/apptentive/src/main/java/com/apptentive/android/sdk/module/engagement/interaction/fragment/MessageCenterFragment.java +++ b/apptentive/src/main/java/com/apptentive/android/sdk/module/engagement/interaction/fragment/MessageCenterFragment.java @@ -481,7 +481,6 @@ public boolean onMenuItemClick(MenuItem menuItem) { } EngagementModule.engageInternal(hostingActivityRef.get(), interaction, MessageCenterInteraction.EVENT_NAME_PROFILE_OPEN, data.toString()); - final SharedPreferences prefs = ApptentiveInternal.getInstance().getSharedPrefs(); boolean whoCardDisplayedBefore = wasWhoCardAsPreviouslyDisplayed(); forceShowKeyboard = true; addWhoCard(!whoCardDisplayedBefore); @@ -497,7 +496,6 @@ public void onSaveInstanceState(Bundle outState) { //int index = messageCenterRecyclerView.getFirstVisiblePosition(); View v = messageCenterRecyclerView.getChildAt(0); int top = (v == null) ? 0 : (v.getTop() - messageCenterRecyclerView.getPaddingTop()); - //outState.putInt(LIST_TOP_INDEX, index); outState.putInt(LIST_TOP_OFFSET, top); outState.putParcelable(COMPOSING_EDITTEXT_STATE, saveEditTextInstanceState()); if (messageCenterRecyclerViewAdapter != null) { @@ -516,7 +514,6 @@ public boolean onBackPressed(boolean hardwareButton) { DialogFragment myFrag = (DialogFragment) (hostingActivity.getSupportFragmentManager()).findFragmentByTag(DIALOG_IMAGE_PREVIEW); if (myFrag != null) { myFrag.dismiss(); - myFrag = null; } cleanup(); if (hardwareButton) { @@ -577,7 +574,6 @@ public void addComposingCard() { } private boolean checkAddWhoCardIfRequired() { - SharedPreferences prefs = ApptentiveInternal.getInstance().getSharedPrefs(); boolean whoCardDisplayedBefore = wasWhoCardAsPreviouslyDisplayed(); if (interaction.getWhoCardRequestEnabled() && interaction.getWhoCardRequired()) { if (!whoCardDisplayedBefore) { @@ -604,7 +600,6 @@ public void addWhoCard(boolean initial) { messagingActionHandler.removeMessages(MSG_MESSAGE_ADD_COMPOSING); messagingActionHandler.sendEmptyMessage(MSG_REMOVE_STATUS); messagingActionHandler.sendMessage(messagingActionHandler.obtainMessage(MSG_MESSAGE_ADD_WHOCARD, initial ? 0 : 1, 0, profile)); - //messagingActionHandler.sendEmptyMessage(MSG_SCROLL_TO_BOTTOM); } } @@ -825,11 +820,11 @@ public void onWhoCardViewCreated(final EditText nameEditText, final EditText ema this.whoCardEmailEditText = emailEditText; if (pendingWhoCardName != null) { nameEditText.onRestoreInstanceState(pendingWhoCardName); - //pendingWhoCardName = null; + pendingWhoCardName = null; } if (pendingWhoCardEmail != null) { emailEditText.onRestoreInstanceState(pendingWhoCardEmail); - //pendingWhoCardEmail = null; + pendingWhoCardEmail = null; } messageCenterRecyclerView.setPadding(0, 0, 0, 0); @@ -918,16 +913,6 @@ public void onFinishComposing() { showProfileButton(); } - private void removeItemsFromRecyclerView(int type) { - for (int i = 0; i < messages.size(); i++) { - MessageCenterUtil.MessageCenterListItem item = messages.get(i); - if (item.getListItemType() == type) { - messages.remove(i); - messageCenterRecyclerViewAdapter.notifyItemRemoved(i); - } - } - } - @Override public void onSubmitWhoCard(String buttonLabel) { ApptentiveLog.e("onSubmitWhoCard()"); @@ -1248,7 +1233,8 @@ private void prepareMessages(final List messagingActionHandler.sendEmptyMessage(MSG_ADD_GREETING); } - // @Override + // TODO: Fix this. + @Override public void onClickAttachment(final int position, final ImageItem image) { if (Util.isMimeTypeImage(image.mimeType)) { // "+" placeholder is clicked @@ -1567,8 +1553,6 @@ public boolean recyclerViewContainsItemOfType(int type) { public void setPaused(boolean paused) { if (isPaused ^ paused) { - // TODO: Do I want to invalidate all the views here? - //messageCenterRecyclerViewAdapter.notifyDataSetChanged(); // Invalidate any unsent messages, as these will have status and progress bars that need to change. for (int i = 0; i < messages.size(); i++) { MessageCenterUtil.MessageCenterListItem item = messages.get(i); From a042e79acfa519bbaea3dcfaec77616b302f0304 Mon Sep 17 00:00:00 2001 From: skykelsey Date: Mon, 7 Nov 2016 12:20:39 -0800 Subject: [PATCH 042/100] Redesign ContextMessage so we don't need to hold a reference to one on the Fragment. --- .../fragment/MessageCenterFragment.java | 66 +++++++++---------- 1 file changed, 31 insertions(+), 35 deletions(-) diff --git a/apptentive/src/main/java/com/apptentive/android/sdk/module/engagement/interaction/fragment/MessageCenterFragment.java b/apptentive/src/main/java/com/apptentive/android/sdk/module/engagement/interaction/fragment/MessageCenterFragment.java index 173ae2984..4bf6e79ce 100644 --- a/apptentive/src/main/java/com/apptentive/android/sdk/module/engagement/interaction/fragment/MessageCenterFragment.java +++ b/apptentive/src/main/java/com/apptentive/android/sdk/module/engagement/interaction/fragment/MessageCenterFragment.java @@ -151,10 +151,6 @@ public class MessageCenterFragment extends ApptentiveBaseFragment 0) { CompoundMessage compoundMessage = new CompoundMessage(); compoundMessage.setBody(composerEditText.getText().toString()); @@ -1413,32 +1403,38 @@ public void handleMessage(Message msg) { } break; } - case MSG_SEND_CONTEXT_MESSAGE: { - List messages = fragment.messages; - // Remove fake ContextMessage from the RecyclerView - for (int i = 0; i < messages.size(); i++) { - MessageCenterUtil.MessageCenterListItem item = messages.get(i); + case MSG_SEND_PENDING_CONTEXT_MESSAGE: { + ContextMessage contextMessage = null; + // If the list has a context message, get it, remove it from the list, and notify the RecyclerView to update. + ListIterator iterator = fragment.messages.listIterator(); + while (iterator.hasNext()) { + int index = iterator.nextIndex(); + MessageCenterUtil.MessageCenterListItem item = iterator.next(); if (item.getListItemType() == MESSAGE_CONTEXT) { - ApptentiveLog.e("Removing Fake Context Message"); - messages.remove(i); - fragment.messageCenterRecyclerViewAdapter.notifyItemRemoved(i); + contextMessage = (ContextMessage) item; + iterator.remove(); + fragment.messageCenterRecyclerViewAdapter.notifyItemRemoved(index); + break; } } - // Create a CompoundMessage for sending and final display - String body = (String) msg.obj; - CompoundMessage message = new CompoundMessage(); - message.setBody(body); - message.setAutomated(true); - message.setRead(true); - - // Add it to the RecyclerView - ApptentiveLog.e("Adding Real Context Message"); - messages.add(message); - fragment.messageCenterRecyclerViewAdapter.notifyItemInserted(messages.size() - 1); - // Send it to the server - ApptentiveLog.e("Sending Real Context Message"); - ApptentiveInternal.getInstance().getMessageManager().sendMessage(message); + if (contextMessage != null) { + // Create a CompoundMessage for sending and final display + CompoundMessage message = new CompoundMessage(); + message.setBody(contextMessage.getBody()); + message.setAutomated(true); + message.setRead(true); + + // Add it to the RecyclerView + ApptentiveLog.e("Adding Real Context Message"); + fragment.unsentMessagesCount++; + fragment.messages.add(message); + fragment.messageCenterRecyclerViewAdapter.notifyItemInserted(fragment.messages.size() - 1); + + // Send it to the server + ApptentiveLog.e("Sending Real Context Message"); + ApptentiveInternal.getInstance().getMessageManager().sendMessage(message); + } break; } case MSG_PAUSE_SENDING: { From e6f025ab2d30bc3815a7589be2c9facf6a78e5fd Mon Sep 17 00:00:00 2001 From: skykelsey Date: Mon, 7 Nov 2016 12:43:28 -0800 Subject: [PATCH 043/100] Focus the correct input field of the Who Card when opened. Bring up the keyboard when the Who Card is dispayed as a requirement. --- .../interaction/fragment/MessageCenterFragment.java | 13 +++++++------ .../messagecenter/OnListviewItemActionListener.java | 3 ++- .../messagecenter/view/holder/WhoCardHolder.java | 5 ++++- 3 files changed, 13 insertions(+), 8 deletions(-) diff --git a/apptentive/src/main/java/com/apptentive/android/sdk/module/engagement/interaction/fragment/MessageCenterFragment.java b/apptentive/src/main/java/com/apptentive/android/sdk/module/engagement/interaction/fragment/MessageCenterFragment.java index 4bf6e79ce..81934a489 100644 --- a/apptentive/src/main/java/com/apptentive/android/sdk/module/engagement/interaction/fragment/MessageCenterFragment.java +++ b/apptentive/src/main/java/com/apptentive/android/sdk/module/engagement/interaction/fragment/MessageCenterFragment.java @@ -572,11 +572,13 @@ private boolean checkAddWhoCardIfRequired() { boolean whoCardDisplayedBefore = wasWhoCardAsPreviouslyDisplayed(); if (interaction.getWhoCardRequestEnabled() && interaction.getWhoCardRequired()) { if (!whoCardDisplayedBefore) { + forceShowKeyboard = true; addWhoCard(true); return true; } else { String savedEmail = Apptentive.getPersonEmail(); if (TextUtils.isEmpty(savedEmail)) { + forceShowKeyboard = true; addWhoCard(false); return true; } @@ -810,7 +812,7 @@ public void run() { } @Override - public void onWhoCardViewCreated(final EditText nameEditText, final EditText emailEditText) { + public void onWhoCardViewCreated(final EditText nameEditText, final EditText emailEditText, final View viewToFocus) { this.whoCardNameEditText = nameEditText; this.whoCardEmailEditText = emailEditText; if (pendingWhoCardName != null) { @@ -823,16 +825,15 @@ public void onWhoCardViewCreated(final EditText nameEditText, final EditText ema } messageCenterRecyclerView.setPadding(0, 0, 0, 0); - // TODO: Track which field has focus and apply correctly - if (nameEditText != null) { - nameEditText.requestFocus(); + if (viewToFocus != null) { + viewToFocus.requestFocus(); if (forceShowKeyboard) { - nameEditText.post(new Runnable() { + viewToFocus.post(new Runnable() { @Override public void run() { if (forceShowKeyboard) { forceShowKeyboard = false; - Util.showSoftKeyboard(hostingActivityRef.get(), nameEditText); + Util.showSoftKeyboard(hostingActivityRef.get(), viewToFocus); } } }); diff --git a/apptentive/src/main/java/com/apptentive/android/sdk/module/messagecenter/OnListviewItemActionListener.java b/apptentive/src/main/java/com/apptentive/android/sdk/module/messagecenter/OnListviewItemActionListener.java index 26e8e6e87..478a5fce7 100644 --- a/apptentive/src/main/java/com/apptentive/android/sdk/module/messagecenter/OnListviewItemActionListener.java +++ b/apptentive/src/main/java/com/apptentive/android/sdk/module/messagecenter/OnListviewItemActionListener.java @@ -6,6 +6,7 @@ package com.apptentive.android.sdk.module.messagecenter; +import android.view.View; import android.widget.EditText; import com.apptentive.android.sdk.module.messagecenter.view.holder.MessageComposerHolder; @@ -25,7 +26,7 @@ public interface OnListviewItemActionListener { void onFinishComposing(); - void onWhoCardViewCreated(EditText nameEditText, EditText emailEditText); + void onWhoCardViewCreated(EditText nameEditText, EditText emailEditText, View viewToFocus); void onSubmitWhoCard(String buttonLabel); diff --git a/apptentive/src/main/java/com/apptentive/android/sdk/module/messagecenter/view/holder/WhoCardHolder.java b/apptentive/src/main/java/com/apptentive/android/sdk/module/messagecenter/view/holder/WhoCardHolder.java index d8828afd5..57be5e07f 100644 --- a/apptentive/src/main/java/com/apptentive/android/sdk/module/messagecenter/view/holder/WhoCardHolder.java +++ b/apptentive/src/main/java/com/apptentive/android/sdk/module/messagecenter/view/holder/WhoCardHolder.java @@ -62,11 +62,14 @@ public void bindView(RecyclerView recyclerView, final WhoCard whoCard) { title.setHint(whoCard.getTitle()); } + View viewToFocus; if (TextUtils.isEmpty(whoCard.getNameHint())) { nameLayout.setVisibility(GONE); + viewToFocus = emailEditText; } else { nameLayout.setVisibility(VISIBLE); nameLayout.setHint(whoCard.getNameHint()); + viewToFocus = nameEditText; } // TODO: Restore pending text if view is for instance rotated before being submitted. nameEditText.setText(Apptentive.getPersonName()); @@ -148,7 +151,7 @@ public void onClick(View view) { } }); if (adapter.getListener() != null) { - adapter.getListener().onWhoCardViewCreated(nameEditText, emailEditText); + adapter.getListener().onWhoCardViewCreated(nameEditText, emailEditText, viewToFocus); } } From 1a98d584b94cb9585fea8a398d2def47d9ba81b3 Mon Sep 17 00:00:00 2001 From: skykelsey Date: Mon, 7 Nov 2016 14:58:14 -0800 Subject: [PATCH 044/100] Fix memory link by nulling views that contain references to the Activity when the MC fragment is detached. --- .../interaction/fragment/MessageCenterFragment.java | 10 ++++++---- .../sdk/util/image/ApptentiveImageGridView.java | 5 +---- 2 files changed, 7 insertions(+), 8 deletions(-) diff --git a/apptentive/src/main/java/com/apptentive/android/sdk/module/engagement/interaction/fragment/MessageCenterFragment.java b/apptentive/src/main/java/com/apptentive/android/sdk/module/engagement/interaction/fragment/MessageCenterFragment.java index 81934a489..33e223436 100644 --- a/apptentive/src/main/java/com/apptentive/android/sdk/module/engagement/interaction/fragment/MessageCenterFragment.java +++ b/apptentive/src/main/java/com/apptentive/android/sdk/module/engagement/interaction/fragment/MessageCenterFragment.java @@ -228,7 +228,6 @@ public void onViewCreated(View view, Bundle onSavedInstanceState) { } } - @Override public void onAttach(Context context) { super.onAttach(context); @@ -240,9 +239,13 @@ public void onAttach(Context context) { @Override public void onDetach() { super.onDetach(); - // messageCenterRecyclerViewAdapter holds a reference to fragment context through Cstor. Need to set it to null to prevent leak + // messageCenterRecyclerViewAdapter holds a reference to fragment context. Need to set it to null in this and other Views to prevent a memory leak. messageCenterRecyclerViewAdapter = null; messageCenterRecyclerView.setAdapter(null); + composer = null; + composerEditText = null; + whoCardNameEditText = null; + whoCardEmailEditText = null; } public void onStart() { @@ -408,7 +411,7 @@ else if (pendingWhoCardName != null || pendingWhoCardEmail != null || pendingWho addWhoCard(pendingWhoCardMode); } else if (!checkAddWhoCardIfRequired()) { /* If there are no items in the list, then it means that the Greeting will be added, but nothing else. - * In that case, show the COmposer, because Message Center hasn't been opened before. + * In that case, show the Composer, because Message Center hasn't been opened before. * If Who Card is required, show Who Card first. */ if (messages.size() == 0) { @@ -528,7 +531,6 @@ public boolean cleanup() { mgr.clearInternalOnMessagesUpdatedListeners(); mgr.setAfterSendMessageListener(null); - ApptentiveInternal.getInstance().getAndClearCustomData(); ApptentiveAttachmentLoader.getInstance().clearMemoryCache(); return true; diff --git a/apptentive/src/main/java/com/apptentive/android/sdk/util/image/ApptentiveImageGridView.java b/apptentive/src/main/java/com/apptentive/android/sdk/util/image/ApptentiveImageGridView.java index bb4219713..388496aba 100644 --- a/apptentive/src/main/java/com/apptentive/android/sdk/util/image/ApptentiveImageGridView.java +++ b/apptentive/src/main/java/com/apptentive/android/sdk/util/image/ApptentiveImageGridView.java @@ -26,12 +26,9 @@ public class ApptentiveImageGridView extends GridView implements AdapterView.OnI private ImageItemClickedListener listener; - private Context context; - public ApptentiveImageGridView(Context context, AttributeSet attrs) { super(context, attrs); setOnItemClickListener(this); - this.context = context; } @Override @@ -63,7 +60,7 @@ public void setListener(ImageItemClickedListener l) { } public void setupUi() { - imageBandAdapter = new ImageGridViewAdapter(context, false); + imageBandAdapter = new ImageGridViewAdapter(getContext(), false); setAdapter(imageBandAdapter); } From 96e6d7d3b43c405aad7fa7e1d3b99188a0b88ade Mon Sep 17 00:00:00 2001 From: skykelsey Date: Mon, 7 Nov 2016 14:58:53 -0800 Subject: [PATCH 045/100] Format code. --- .../android/sdk/util/image/ApptentiveImageGridView.java | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/apptentive/src/main/java/com/apptentive/android/sdk/util/image/ApptentiveImageGridView.java b/apptentive/src/main/java/com/apptentive/android/sdk/util/image/ApptentiveImageGridView.java index 388496aba..345b2ee55 100644 --- a/apptentive/src/main/java/com/apptentive/android/sdk/util/image/ApptentiveImageGridView.java +++ b/apptentive/src/main/java/com/apptentive/android/sdk/util/image/ApptentiveImageGridView.java @@ -36,11 +36,9 @@ protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { int heightSpec; if (getLayoutParams().height == LayoutParams.WRAP_CONTENT) { - // The two leftmost bits in the height measure spec have // a special meaning, hence we can't use them to describe height. - heightSpec = MeasureSpec.makeMeasureSpec( - Integer.MAX_VALUE >> 2, MeasureSpec.AT_MOST); + heightSpec = MeasureSpec.makeMeasureSpec(Integer.MAX_VALUE >> 2, MeasureSpec.AT_MOST); } else { // Any other height should be respected as is. heightSpec = heightMeasureSpec; @@ -91,7 +89,6 @@ public void onGlobalLayout() { public void setAdapterItemSize(int width, int desiredNumCount) { final int columnSpace = getResources().getDimensionPixelOffset(R.dimen.apptentive_image_grid_space_size); - int columnWidth = (width - columnSpace * (desiredNumCount - 1)) / desiredNumCount; Point point = Util.getScreenSize(getContext().getApplicationContext()); imageBandAdapter.setItemSize(columnWidth, (int) (((float) point.y / (float) point.x) * columnWidth)); @@ -107,7 +104,7 @@ public void setAdapterIndicator(int rid) { } public void setImageIndicatorCallback(ImageGridViewAdapter.Callback callback) { - imageBandAdapter.setIndicatorCallback(callback); + imageBandAdapter.setIndicatorCallback(callback); } public void setData(List images) { From eeb6a4c8d77790da0ae98a514474b68265446984 Mon Sep 17 00:00:00 2001 From: skykelsey Date: Mon, 7 Nov 2016 15:17:02 -0800 Subject: [PATCH 046/100] Don't show the FAB when the composer view is already in the message list after orientation change. --- .../fragment/MessageCenterFragment.java | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/apptentive/src/main/java/com/apptentive/android/sdk/module/engagement/interaction/fragment/MessageCenterFragment.java b/apptentive/src/main/java/com/apptentive/android/sdk/module/engagement/interaction/fragment/MessageCenterFragment.java index 33e223436..b03b8a58b 100644 --- a/apptentive/src/main/java/com/apptentive/android/sdk/module/engagement/interaction/fragment/MessageCenterFragment.java +++ b/apptentive/src/main/java/com/apptentive/android/sdk/module/engagement/interaction/fragment/MessageCenterFragment.java @@ -364,12 +364,6 @@ private void setup(View rootView, boolean isInitMessages) { layoutManager.setOrientation(LinearLayoutManager.VERTICAL); messageCenterRecyclerView.setLayoutManager(layoutManager); -/* - ((MessageCenterListView) messageCenterListView).setOnListViewResizeListener(this); - messageCenterListView.setItemsCanFocus(true); -*/ - - fab = rootView.findViewById(R.id.composing_fab); fab.setOnClickListener(new View.OnClickListener() { @Override @@ -381,7 +375,6 @@ public void onClick(View v) { messageCenterRecyclerViewAdapter = new MessageCenterRecyclerViewAdapter(this, this, interaction, messages); - boolean showKeyboard = false; if (isInitMessages) { List items = ApptentiveInternal.getInstance().getMessageManager().getMessageCenterListItems(); if (items != null) { @@ -422,6 +415,15 @@ else if (pendingWhoCardName != null || pendingWhoCardEmail != null || pendingWho addExpectationStatusIfNeeded(); } } + } else { + // Need to account for an input view that was added before orientation change, etc. + if (messages != null) { + for (MessageCenterUtil.MessageCenterListItem item : messages) { + if (item.getListItemType() == MESSAGE_COMPOSER || item.getListItemType() == WHO_CARD) { + addedAnInteractiveCard = true; + } + } + } } messageCenterRecyclerView.setAdapter(messageCenterRecyclerViewAdapter); From da226e15fd513e4f3c6d5607a990e51909974533 Mon Sep 17 00:00:00 2001 From: skykelsey Date: Mon, 7 Nov 2016 16:13:19 -0800 Subject: [PATCH 047/100] Rename `messages` to `listItems` since we are including other types in the list. --- .../fragment/MessageCenterFragment.java | 116 +++++++++--------- .../MessageCenterRecyclerViewAdapter.java | 26 ++-- 2 files changed, 69 insertions(+), 73 deletions(-) diff --git a/apptentive/src/main/java/com/apptentive/android/sdk/module/engagement/interaction/fragment/MessageCenterFragment.java b/apptentive/src/main/java/com/apptentive/android/sdk/module/engagement/interaction/fragment/MessageCenterFragment.java index b03b8a58b..c1823ac24 100644 --- a/apptentive/src/main/java/com/apptentive/android/sdk/module/engagement/interaction/fragment/MessageCenterFragment.java +++ b/apptentive/src/main/java/com/apptentive/android/sdk/module/engagement/interaction/fragment/MessageCenterFragment.java @@ -120,7 +120,7 @@ public class MessageCenterFragment extends ApptentiveBaseFragment messages = new ArrayList(); + private ArrayList listItems = new ArrayList(); private MessageCenterRecyclerViewAdapter messageCenterRecyclerViewAdapter; private MessageCenterRecyclerView messageCenterRecyclerView; @@ -353,7 +353,7 @@ protected void updateMenuVisibility() { profileMenuItem.setEnabled(bShowProfileMenuItem); } - private void setup(View rootView, boolean isInitMessages) { + private void setup(View rootView, boolean isInitialViewCreation) { boolean addedAnInteractiveCard = false; messageCenterRecyclerView = (MessageCenterRecyclerView) rootView.findViewById(R.id.message_center_recycler_view); @@ -373,12 +373,12 @@ public void onClick(View v) { } }); - messageCenterRecyclerViewAdapter = new MessageCenterRecyclerViewAdapter(this, this, interaction, messages); + messageCenterRecyclerViewAdapter = new MessageCenterRecyclerViewAdapter(this, this, interaction, listItems); - if (isInitMessages) { + if (isInitialViewCreation) { List items = ApptentiveInternal.getInstance().getMessageManager().getMessageCenterListItems(); if (items != null) { - // populate message list from db + // Get message list from DB, and use this as the starting point for the listItems array. prepareMessages(items); } @@ -407,7 +407,7 @@ else if (pendingWhoCardName != null || pendingWhoCardEmail != null || pendingWho * In that case, show the Composer, because Message Center hasn't been opened before. * If Who Card is required, show Who Card first. */ - if (messages.size() == 0) { + if (listItems.size() == 0) { addedAnInteractiveCard = true; addComposingCard(); } else { @@ -417,8 +417,8 @@ else if (pendingWhoCardName != null || pendingWhoCardEmail != null || pendingWho } } else { // Need to account for an input view that was added before orientation change, etc. - if (messages != null) { - for (MessageCenterUtil.MessageCenterListItem item : messages) { + if (listItems != null) { + for (MessageCenterUtil.MessageCenterListItem item : listItems) { if (item.getListItemType() == MESSAGE_COMPOSER || item.getListItemType() == WHO_CARD) { addedAnInteractiveCard = true; } @@ -616,12 +616,12 @@ public void displayNewIncomingMessageItem(ApptentiveMessage message) { messagingActionHandler.sendEmptyMessage(MSG_REMOVE_STATUS); // Determine where to insert the new incoming message. It will be in front of any eidting // area, i.e. composing, Who Card ... - int insertIndex = messages.size(); // If inserted onto the end, then the list will have grown by one. + int insertIndex = listItems.size(); // If inserted onto the end, then the list will have grown by one. outside_loop: // Starting at end of list, go back up the list to find the proper place to insert the incoming message. - for (int i = messages.size() - 1; i > 0; i--) { - MessageCenterUtil.MessageCenterListItem item = messages.get(i); + for (int i = listItems.size() - 1; i > 0; i--) { + MessageCenterUtil.MessageCenterListItem item = listItems.get(i); switch (item.getListItemType()) { case MESSAGE_COMPOSER: case MESSAGE_CONTEXT: @@ -634,7 +634,7 @@ public void displayNewIncomingMessageItem(ApptentiveMessage message) { break outside_loop; } } - messages.add(insertIndex, message); + listItems.add(insertIndex, message); messageCenterRecyclerViewAdapter.notifyItemInserted(insertIndex); int firstIndex = messageCenterRecyclerView.getFirstVisiblePosition(); @@ -1089,16 +1089,16 @@ public void updateMessageSentStates() { MessageCenterUtil.CompoundMessageCommonInterface lastSent = null; Set uniqueNonce = new HashSet(); int removedItems = 0; - ListIterator messageIterator = messages.listIterator(); - while (messageIterator.hasNext()) { - int adapterMessagePosition = messageIterator.nextIndex() - removedItems; - MessageCenterUtil.MessageCenterListItem message = messageIterator.next(); + ListIterator listItemIterator = listItems.listIterator(); + while (listItemIterator.hasNext()) { + int adapterMessagePosition = listItemIterator.nextIndex() - removedItems; + MessageCenterUtil.MessageCenterListItem message = listItemIterator.next(); if (message instanceof ApptentiveMessage) { /* Check if there is any duplicate messages and remove if found. * add() of a Set returns false if the element already exists. */ if (!uniqueNonce.add(((ApptentiveMessage) message).getNonce())) { - messageIterator.remove(); + listItemIterator.remove(); messageCenterRecyclerViewAdapter.notifyItemRemoved(adapterMessagePosition); removedItems++; continue; @@ -1186,7 +1186,7 @@ private void hideProfileButton() { * This method uses insertion sort to re-sort the messages retrieved from the database */ private void prepareMessages(final List originalItems) { - messages.clear(); + listItems.clear(); unsentMessagesCount = 0; // Loop through each message item retrieved from database for (MessageCenterUtil.MessageCenterListItem item : originalItems) { @@ -1198,9 +1198,9 @@ private void prepareMessages(final List } /* - * Find proper location to insert into the messages list of the listview. + * Find proper location to insert into the listItems list of the listview. */ - ListIterator listIterator = messages.listIterator(); + ListIterator listIterator = listItems.listIterator(); ApptentiveMessage next = null; while (listIterator.hasNext()) { next = (ApptentiveMessage) listIterator.next(); @@ -1299,14 +1299,13 @@ public void handleMessage(Message msg) { boolean initial = msg.arg1 == 0; // TODO: Do something with mode? WhoCard whoCard = fragment.interaction.getWhoCard(); whoCard.setInitial(initial); - fragment.messages.add(whoCard); - fragment.messageCenterRecyclerViewAdapter.notifyItemInserted(fragment.messages.size() - 1); - fragment.messageCenterRecyclerView.setSelection(fragment.messages.size() - 1); + fragment.listItems.add(whoCard); + fragment.messageCenterRecyclerViewAdapter.notifyItemInserted(fragment.listItems.size() - 1); + fragment.messageCenterRecyclerView.setSelection(fragment.listItems.size() - 1); break; } case MSG_MESSAGE_REMOVE_WHOCARD: { - List messages = fragment.messages; - ListIterator messageIterator = messages.listIterator(); + ListIterator messageIterator = fragment.listItems.listIterator(); while (messageIterator.hasNext()) { int i = messageIterator.nextIndex(); MessageCenterUtil.MessageCenterListItem next = messageIterator.next(); @@ -1319,9 +1318,9 @@ public void handleMessage(Message msg) { break; } case MSG_MESSAGE_ADD_COMPOSING: { - fragment.messages.add(fragment.interaction.getComposer()); - fragment.messageCenterRecyclerViewAdapter.notifyItemInserted(fragment.messages.size() - 1); - fragment.messageCenterRecyclerView.setSelection(fragment.messages.size() - 1); + fragment.listItems.add(fragment.interaction.getComposer()); + fragment.messageCenterRecyclerViewAdapter.notifyItemInserted(fragment.listItems.size() - 1); + fragment.messageCenterRecyclerView.setSelection(fragment.listItems.size() - 1); break; } case MSG_MESSAGE_ADD_INCOMING: { @@ -1330,8 +1329,8 @@ public void handleMessage(Message msg) { break; } case MSG_SCROLL_TO_BOTTOM: { - fragment.messageCenterRecyclerView.setSelection(fragment.messages.size() - 1); - fragment.messageCenterRecyclerView.scrollToPosition(fragment.messages.size() - 1); + fragment.messageCenterRecyclerView.setSelection(fragment.listItems.size() - 1); + fragment.messageCenterRecyclerView.scrollToPosition(fragment.listItems.size() - 1); break; } case MSG_SCROLL_FROM_TOP: { @@ -1345,8 +1344,8 @@ public void handleMessage(Message msg) { fragment.unsentMessagesCount--; ApptentiveMessage apptentiveMessage = (ApptentiveMessage) msg.obj; - for (int i = 0; i < fragment.messages.size(); i++) { - MessageCenterUtil.MessageCenterListItem message = fragment.messages.get(i); + for (int i = 0; i < fragment.listItems.size(); i++) { + MessageCenterUtil.MessageCenterListItem message = fragment.listItems.get(i); if (message instanceof ApptentiveMessage) { String nonce = ((ApptentiveMessage) message).getNonce(); if (nonce != null) { @@ -1379,8 +1378,8 @@ public void handleMessage(Message msg) { case MSG_START_SENDING: { CompoundMessage message = (CompoundMessage) msg.obj; ApptentiveLog.e("Adding Message to list"); - fragment.messages.add(message); - fragment.messageCenterRecyclerViewAdapter.notifyItemInserted(fragment.messages.size() - 1); + fragment.listItems.add(message); + fragment.messageCenterRecyclerViewAdapter.notifyItemInserted(fragment.listItems.size() - 1); fragment.unsentMessagesCount++; fragment.setPaused(false); @@ -1411,7 +1410,7 @@ public void handleMessage(Message msg) { case MSG_SEND_PENDING_CONTEXT_MESSAGE: { ContextMessage contextMessage = null; // If the list has a context message, get it, remove it from the list, and notify the RecyclerView to update. - ListIterator iterator = fragment.messages.listIterator(); + ListIterator iterator = fragment.listItems.listIterator(); while (iterator.hasNext()) { int index = iterator.nextIndex(); MessageCenterUtil.MessageCenterListItem item = iterator.next(); @@ -1433,8 +1432,8 @@ public void handleMessage(Message msg) { // Add it to the RecyclerView ApptentiveLog.e("Adding Real Context Message"); fragment.unsentMessagesCount++; - fragment.messages.add(message); - fragment.messageCenterRecyclerViewAdapter.notifyItemInserted(fragment.messages.size() - 1); + fragment.listItems.add(message); + fragment.messageCenterRecyclerViewAdapter.notifyItemInserted(fragment.listItems.size() - 1); // Send it to the server ApptentiveLog.e("Sending Real Context Message"); @@ -1465,22 +1464,21 @@ public void handleMessage(Message msg) { break; } case MSG_REMOVE_COMPOSER: { - List messages = fragment.messages; - for (int i = 0; i < messages.size(); i++) { - MessageCenterUtil.MessageCenterListItem item = messages.get(i); + for (int i = 0; i < fragment.listItems.size(); i++) { + MessageCenterUtil.MessageCenterListItem item = fragment.listItems.get(i); if (item.getListItemType() == MESSAGE_COMPOSER) { ApptentiveLog.e("Removing Composer"); - messages.remove(i); + fragment.listItems.remove(i); fragment.messageCenterRecyclerViewAdapter.notifyItemRemoved(i); } } break; } case MSG_OPT_INSERT_REGULAR_STATUS: { - List messages = fragment.messages; + List listItems = fragment.listItems; // Only add status if the last item in the list is a sent message. - if (messages.size() > 0) { - MessageCenterUtil.MessageCenterListItem lastItem = messages.get(messages.size() - 1); + if (listItems.size() > 0) { + MessageCenterUtil.MessageCenterListItem lastItem = listItems.get(listItems.size() - 1); if (lastItem != null && lastItem.getListItemType() == MESSAGE_OUTGOING) { ApptentiveMessage apptentiveMessage = (ApptentiveMessage) lastItem; if (apptentiveMessage.isOutgoingMessage()) { @@ -1489,8 +1487,8 @@ public void handleMessage(Message msg) { MessageCenterStatus status = fragment.interaction.getRegularStatus(); if (status != null) { // Add expectation status message if the last is a sent - messages.add(status); - fragment.messageCenterRecyclerViewAdapter.notifyItemInserted(messages.size() - 1); + listItems.add(status); + fragment.messageCenterRecyclerViewAdapter.notifyItemInserted(listItems.size() - 1); } } } @@ -1499,12 +1497,12 @@ public void handleMessage(Message msg) { break; } case MSG_REMOVE_STATUS: { - List messages = fragment.messages; - for (int i = 0; i < messages.size(); i++) { - MessageCenterUtil.MessageCenterListItem item = messages.get(i); + List listItems = fragment.listItems; + for (int i = 0; i < listItems.size(); i++) { + MessageCenterUtil.MessageCenterListItem item = listItems.get(i); if (item.getListItemType() == STATUS) { ApptentiveLog.e("Removing Status"); - messages.remove(i); + listItems.remove(i); fragment.messageCenterRecyclerViewAdapter.notifyItemRemoved(i); } } @@ -1512,14 +1510,13 @@ public void handleMessage(Message msg) { } case MSG_ADD_CONTEXT_MESSAGE: { ApptentiveLog.e("Adding Context Message"); - List messages = fragment.messages; ContextMessage contextMessage = (ContextMessage) msg.obj; - messages.add(contextMessage); - fragment.messageCenterRecyclerViewAdapter.notifyItemInserted(messages.size() - 1); + fragment.listItems.add(contextMessage); + fragment.messageCenterRecyclerViewAdapter.notifyItemInserted(fragment.listItems.size() - 1); break; } case MSG_ADD_GREETING: { - fragment.messages.add(0, fragment.interaction.getGreeting()); + fragment.listItems.add(0, fragment.interaction.getGreeting()); fragment.messageCenterRecyclerViewAdapter.notifyItemInserted(0); break; } @@ -1534,8 +1531,8 @@ public void handleMessage(Message msg) { EngagementModule.engageInternal(fragment.hostingActivityRef.get(), fragment.interaction, MessageCenterInteraction.EVENT_NAME_MESSAGE_HTTP_ERROR); } if (status != null) { - fragment.messages.add(status); - fragment.messageCenterRecyclerViewAdapter.notifyItemInserted(fragment.messages.size() - 1); + fragment.listItems.add(status); + fragment.messageCenterRecyclerViewAdapter.notifyItemInserted(fragment.listItems.size() - 1); } break; } @@ -1544,7 +1541,7 @@ public void handleMessage(Message msg) { } public boolean recyclerViewContainsItemOfType(int type) { - for (MessageCenterUtil.MessageCenterListItem item : messages) { + for (MessageCenterUtil.MessageCenterListItem item : listItems) { if (item.getListItemType() == type) { return true; } @@ -1555,13 +1552,12 @@ public boolean recyclerViewContainsItemOfType(int type) { public void setPaused(boolean paused) { if (isPaused ^ paused) { // Invalidate any unsent messages, as these will have status and progress bars that need to change. - for (int i = 0; i < messages.size(); i++) { - MessageCenterUtil.MessageCenterListItem item = messages.get(i); + for (int i = 0; i < listItems.size(); i++) { + MessageCenterUtil.MessageCenterListItem item = listItems.get(i); if (item instanceof ApptentiveMessage) { ApptentiveMessage message = (ApptentiveMessage) item; if (message.isOutgoingMessage() && message.getCreatedAt() == null) { messageCenterRecyclerViewAdapter.notifyItemChanged(i); - ApptentiveLog.e("Invalidated: %s", message.toString()); } } } diff --git a/apptentive/src/main/java/com/apptentive/android/sdk/module/messagecenter/view/MessageCenterRecyclerViewAdapter.java b/apptentive/src/main/java/com/apptentive/android/sdk/module/messagecenter/view/MessageCenterRecyclerViewAdapter.java index 2916edae4..98a1dae59 100644 --- a/apptentive/src/main/java/com/apptentive/android/sdk/module/messagecenter/view/MessageCenterRecyclerViewAdapter.java +++ b/apptentive/src/main/java/com/apptentive/android/sdk/module/messagecenter/view/MessageCenterRecyclerViewAdapter.java @@ -60,15 +60,15 @@ public class MessageCenterRecyclerViewAdapter extends RecyclerView.Adapter { OnListviewItemActionListener listener; RecyclerView recyclerView; Interaction interaction; - List messages; + List listItems; // maps to prevent redundant asynctasks private ArrayList messagesWithPendingReadStatusUpdate = new ArrayList(); - public MessageCenterRecyclerViewAdapter(MessageCenterFragment fragment, OnListviewItemActionListener listener, Interaction interaction, List messages) { + public MessageCenterRecyclerViewAdapter(MessageCenterFragment fragment, OnListviewItemActionListener listener, Interaction interaction, List listItems) { this.fragment = fragment; this.listener = listener; this.interaction = interaction; - this.messages = messages; + this.listItems = listItems; } @Override @@ -140,14 +140,14 @@ public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) { switch (getItemViewType(position)) { case MESSAGE_COMPOSER: { ApptentiveLog.w("-> Message Composer"); - Composer composer = (Composer) messages.get(position); + Composer composer = (Composer) listItems.get(position); MessageComposerHolder composerHolder = (MessageComposerHolder) holder; composerHolder.bindView(fragment, this, composer); break; } case STATUS: { ApptentiveLog.w("-> Status"); - MessageCenterStatus status = (MessageCenterStatus) messages.get(position); + MessageCenterStatus status = (MessageCenterStatus) listItems.get(position); StatusHolder statusHolder = (StatusHolder) holder; statusHolder.body.setText(status.body); @@ -161,14 +161,14 @@ public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) { } case GREETING: { ApptentiveLog.w("-> Greeting"); - MessageCenterGreeting greeting = (MessageCenterGreeting) messages.get(position); + MessageCenterGreeting greeting = (MessageCenterGreeting) listItems.get(position); GreetingHolder greetingHolder = (GreetingHolder) holder; greetingHolder.bindView(greeting); break; } case MESSAGE_INCOMING: { ApptentiveLog.w("-> Message Incoming"); - CompoundMessage compoundMessage = (CompoundMessage) messages.get(position); + CompoundMessage compoundMessage = (CompoundMessage) listItems.get(position); IncomingCompoundMessageHolder compoundHolder = (IncomingCompoundMessageHolder) holder; compoundHolder.bindView(fragment, recyclerView, compoundMessage); // Mark as read @@ -181,28 +181,28 @@ public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) { } case MESSAGE_OUTGOING: { ApptentiveLog.w("-> Message Outgoing"); - CompoundMessage compoundMessage = (CompoundMessage) messages.get(position); + CompoundMessage compoundMessage = (CompoundMessage) listItems.get(position); OutgoingCompoundMessageHolder compoundHolder = (OutgoingCompoundMessageHolder) holder; compoundHolder.bindView(fragment, recyclerView, compoundMessage); break; } case MESSAGE_AUTO: { ApptentiveLog.w("-> Message Auto"); - CompoundMessage autoMessage = (CompoundMessage) messages.get(position); + CompoundMessage autoMessage = (CompoundMessage) listItems.get(position); AutomatedMessageHolder autoHolder = (AutomatedMessageHolder) holder; autoHolder.bindView(recyclerView, autoMessage); break; } case WHO_CARD: { ApptentiveLog.w("-> Who Card"); - WhoCard whoCard = (WhoCard) messages.get(position); + WhoCard whoCard = (WhoCard) listItems.get(position); WhoCardHolder whoCardHolder = (WhoCardHolder) holder; whoCardHolder.bindView(recyclerView, whoCard); break; } case MESSAGE_CONTEXT: { ApptentiveLog.w("-> Message Context"); - ContextMessage contextMessage = (ContextMessage) messages.get(position); + ContextMessage contextMessage = (ContextMessage) listItems.get(position); ContextMessageHolder contextMessageHolder = (ContextMessageHolder) holder; contextMessageHolder.bindView(contextMessage); break; @@ -221,12 +221,12 @@ public void onViewAttachedToWindow(RecyclerView.ViewHolder holder) { @Override public int getItemCount() { - return messages.size(); + return listItems.size(); } @Override public int getItemViewType(int position) { - MessageCenterUtil.MessageCenterListItem message = messages.get(position); + MessageCenterUtil.MessageCenterListItem message = listItems.get(position); return message.getListItemType(); } From d791d77cb68a86dced7eac34d876cf0aa242a6f3 Mon Sep 17 00:00:00 2001 From: skykelsey Date: Mon, 7 Nov 2016 16:37:26 -0800 Subject: [PATCH 048/100] Fix a situation where the Who Card should be launched after a message is sent from teh Composer if the Who Card hasn't been shown before, and it is set to be requested in the config. --- .../fragment/MessageCenterFragment.java | 16 +++++----------- 1 file changed, 5 insertions(+), 11 deletions(-) diff --git a/apptentive/src/main/java/com/apptentive/android/sdk/module/engagement/interaction/fragment/MessageCenterFragment.java b/apptentive/src/main/java/com/apptentive/android/sdk/module/engagement/interaction/fragment/MessageCenterFragment.java index c1823ac24..5cc27ce86 100644 --- a/apptentive/src/main/java/com/apptentive/android/sdk/module/engagement/interaction/fragment/MessageCenterFragment.java +++ b/apptentive/src/main/java/com/apptentive/android/sdk/module/engagement/interaction/fragment/MessageCenterFragment.java @@ -1296,7 +1296,7 @@ public void handleMessage(Message msg) { case MSG_MESSAGE_ADD_WHOCARD: { ApptentiveLog.e("Adding Who Card"); // msg.arg1 is either WHO_CARD_MODE_INIT or WHO_CARD_MODE_EDIT - boolean initial = msg.arg1 == 0; // TODO: Do something with mode? + boolean initial = msg.arg1 == 0; WhoCard whoCard = fragment.interaction.getWhoCard(); whoCard.setInitial(initial); fragment.listItems.add(whoCard); @@ -1386,11 +1386,8 @@ public void handleMessage(Message msg) { ApptentiveLog.e("Sending message"); ApptentiveInternal.getInstance().getMessageManager().sendMessage(message); - // TODO: Move this somewhere else? - // After the message is sent, check if Who Card need to be shown for the 1st time(When Who Card is either requested or required) - SharedPreferences prefs = ApptentiveInternal.getInstance().getSharedPrefs(); - boolean whoCardDisplayedBefore = fragment.wasWhoCardAsPreviouslyDisplayed(); - if (!whoCardDisplayedBefore) { + // After the message is sent, show the Who Card if it has never been seen before, and the configuration specifies it should be requested. + if (!fragment.wasWhoCardAsPreviouslyDisplayed() && fragment.interaction.getWhoCardRequestEnabled()) { JSONObject data = new JSONObject(); try { data.put("required", fragment.interaction.getWhoCardRequired()); @@ -1399,11 +1396,8 @@ public void handleMessage(Message msg) { // } EngagementModule.engageInternal(fragment.hostingActivityRef.get(), fragment.interaction, MessageCenterInteraction.EVENT_NAME_PROFILE_OPEN, data.toString()); - // The delay is to ensure the animation of adding Who Card play after the animation of new outgoing message - if (fragment.interaction.getWhoCardRequestEnabled()) { - fragment.forceShowKeyboard = true; - fragment.addWhoCard(true); - } + fragment.forceShowKeyboard = true; + fragment.addWhoCard(true); } break; } From e67510ee40e5ef73f9fd22562ebe8ee3adeb5060 Mon Sep 17 00:00:00 2001 From: skykelsey Date: Mon, 7 Nov 2016 21:13:40 -0800 Subject: [PATCH 049/100] Clicks should open attachments in a larger size. --- .../fragment/MessageCenterFragment.java | 19 ++++++++----------- .../MessageCenterRecyclerViewAdapter.java | 5 ++--- .../holder/IncomingCompoundMessageHolder.java | 7 ++++--- .../holder/OutgoingCompoundMessageHolder.java | 12 ++++++++++-- 4 files changed, 24 insertions(+), 19 deletions(-) diff --git a/apptentive/src/main/java/com/apptentive/android/sdk/module/engagement/interaction/fragment/MessageCenterFragment.java b/apptentive/src/main/java/com/apptentive/android/sdk/module/engagement/interaction/fragment/MessageCenterFragment.java index 5cc27ce86..4be6b5c63 100644 --- a/apptentive/src/main/java/com/apptentive/android/sdk/module/engagement/interaction/fragment/MessageCenterFragment.java +++ b/apptentive/src/main/java/com/apptentive/android/sdk/module/engagement/interaction/fragment/MessageCenterFragment.java @@ -98,15 +98,13 @@ public class MessageCenterFragment extends ApptentiveBaseFragment messagingActionHandler.sendEmptyMessage(MSG_ADD_GREETING); } - // TODO: Fix this. @Override public void onClickAttachment(final int position, final ImageItem image) { if (Util.isMimeTypeImage(image.mimeType)) { - // "+" placeholder is clicked if (TextUtils.isEmpty(image.originalPath)) { + // "+" placeholder is clicked onAttachImage(); } else { // an image thumbnail is clicked diff --git a/apptentive/src/main/java/com/apptentive/android/sdk/module/messagecenter/view/MessageCenterRecyclerViewAdapter.java b/apptentive/src/main/java/com/apptentive/android/sdk/module/messagecenter/view/MessageCenterRecyclerViewAdapter.java index 98a1dae59..b3308bd52 100644 --- a/apptentive/src/main/java/com/apptentive/android/sdk/module/messagecenter/view/MessageCenterRecyclerViewAdapter.java +++ b/apptentive/src/main/java/com/apptentive/android/sdk/module/messagecenter/view/MessageCenterRecyclerViewAdapter.java @@ -170,20 +170,19 @@ public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) { ApptentiveLog.w("-> Message Incoming"); CompoundMessage compoundMessage = (CompoundMessage) listItems.get(position); IncomingCompoundMessageHolder compoundHolder = (IncomingCompoundMessageHolder) holder; - compoundHolder.bindView(fragment, recyclerView, compoundMessage); + compoundHolder.bindView(fragment, recyclerView, this, compoundMessage); // Mark as read if (!compoundMessage.isRead() && !messagesWithPendingReadStatusUpdate.contains(compoundMessage)) { messagesWithPendingReadStatusUpdate.add(compoundMessage); startUpdateUnreadMessageTask(compoundMessage); } - break; } case MESSAGE_OUTGOING: { ApptentiveLog.w("-> Message Outgoing"); CompoundMessage compoundMessage = (CompoundMessage) listItems.get(position); OutgoingCompoundMessageHolder compoundHolder = (OutgoingCompoundMessageHolder) holder; - compoundHolder.bindView(fragment, recyclerView, compoundMessage); + compoundHolder.bindView(fragment, recyclerView, this, compoundMessage); break; } case MESSAGE_AUTO: { diff --git a/apptentive/src/main/java/com/apptentive/android/sdk/module/messagecenter/view/holder/IncomingCompoundMessageHolder.java b/apptentive/src/main/java/com/apptentive/android/sdk/module/messagecenter/view/holder/IncomingCompoundMessageHolder.java index e0b7ce4d1..e63c118dd 100644 --- a/apptentive/src/main/java/com/apptentive/android/sdk/module/messagecenter/view/holder/IncomingCompoundMessageHolder.java +++ b/apptentive/src/main/java/com/apptentive/android/sdk/module/messagecenter/view/holder/IncomingCompoundMessageHolder.java @@ -17,6 +17,7 @@ import com.apptentive.android.sdk.module.messagecenter.model.CompoundMessage; import com.apptentive.android.sdk.module.messagecenter.view.ApptentiveAvatarView; import com.apptentive.android.sdk.module.messagecenter.view.MessageAdapter; +import com.apptentive.android.sdk.module.messagecenter.view.MessageCenterRecyclerViewAdapter; import com.apptentive.android.sdk.util.Util; import com.apptentive.android.sdk.util.image.ApptentiveImageGridView; import com.apptentive.android.sdk.util.image.ImageItem; @@ -48,7 +49,7 @@ public IncomingCompoundMessageHolder(View itemView) { imageBandView = (ApptentiveImageGridView) itemView.findViewById(R.id.grid); } - public void bindView(MessageCenterFragment fragment, final RecyclerView parent, final CompoundMessage message) { + public void bindView(MessageCenterFragment fragment, final RecyclerView parent, final MessageCenterRecyclerViewAdapter adapter, final CompoundMessage message) { super.bindView(fragment, parent, message); imageBandView.setupUi(); if (loadAvatar) { @@ -97,8 +98,8 @@ public void onClick(int position, ImageItem image) { StoredFile file = files.get(position); String remoteUrl = file.getApptentiveUri(); String localFilePath = Util.generateCacheFileFullPath(remoteUrl, cacheDir); - if (listener != null) { - listener.onClickAttachment(position, new ImageItem(remoteUrl, localFilePath, file.getMimeType(), file.getCreationTime())); + if (adapter.getListener() != null) { + adapter.getListener().onClickAttachment(position, new ImageItem(remoteUrl, localFilePath, file.getMimeType(), file.getCreationTime())); } } }); diff --git a/apptentive/src/main/java/com/apptentive/android/sdk/module/messagecenter/view/holder/OutgoingCompoundMessageHolder.java b/apptentive/src/main/java/com/apptentive/android/sdk/module/messagecenter/view/holder/OutgoingCompoundMessageHolder.java index 39a8d9672..2c23e9430 100644 --- a/apptentive/src/main/java/com/apptentive/android/sdk/module/messagecenter/view/holder/OutgoingCompoundMessageHolder.java +++ b/apptentive/src/main/java/com/apptentive/android/sdk/module/messagecenter/view/holder/OutgoingCompoundMessageHolder.java @@ -15,6 +15,7 @@ import com.apptentive.android.sdk.model.StoredFile; import com.apptentive.android.sdk.module.engagement.interaction.fragment.MessageCenterFragment; import com.apptentive.android.sdk.module.messagecenter.model.CompoundMessage; +import com.apptentive.android.sdk.module.messagecenter.view.MessageCenterRecyclerViewAdapter; import com.apptentive.android.sdk.util.Util; import com.apptentive.android.sdk.util.image.ApptentiveImageGridView; import com.apptentive.android.sdk.util.image.ImageItem; @@ -42,7 +43,7 @@ public OutgoingCompoundMessageHolder(View itemView) { status = (TextView) itemView.findViewById(R.id.status); } - public void bindView(MessageCenterFragment fragment, final RecyclerView recyclerView, final CompoundMessage message) { + public void bindView(MessageCenterFragment fragment, final RecyclerView recyclerView, final MessageCenterRecyclerViewAdapter adapter, final CompoundMessage message) { super.bindView(fragment, recyclerView, message); imageBandView.setupUi(); messageBodyView.setText(message.getBody()); @@ -87,8 +88,15 @@ public void bindView(MessageCenterFragment fragment, final RecyclerView recycler images.add(new ImageItem(file.getSourceUriOrPath(), file.getLocalFilePath(), file.getMimeType(), file.getCreationTime())); } imageBandView.setData(images); + imageBandView.setListener(new ApptentiveImageGridView.ImageItemClickedListener() { + @Override + public void onClick(int position, ImageItem image) { + if (adapter.getListener() != null) { + adapter.getListener().onClickAttachment(position, image); + } + } + }); } - status.setText(statusText); status.setTextColor(getStatusColor(createdAt, fragment.isPaused())); status.setVisibility(!TextUtils.isEmpty(statusText) ? View.VISIBLE : View.GONE); From d11d9f9bd9be2d7b6946e9e864411e1017c6e159 Mon Sep 17 00:00:00 2001 From: skykelsey Date: Mon, 7 Nov 2016 23:49:20 -0800 Subject: [PATCH 050/100] Fix attachment remove buttons. Also make the attachment layouts work well in RTL. --- .../fragment/MessageCenterFragment.java | 40 +++++++++---------- .../view/holder/MessageComposerHolder.java | 2 +- .../util/image/ApptentiveImageGridView.java | 8 ++-- .../apptentive_image_grid_view_item.xml | 12 +++++- 4 files changed, 36 insertions(+), 26 deletions(-) diff --git a/apptentive/src/main/java/com/apptentive/android/sdk/module/engagement/interaction/fragment/MessageCenterFragment.java b/apptentive/src/main/java/com/apptentive/android/sdk/module/engagement/interaction/fragment/MessageCenterFragment.java index 4be6b5c63..bb0e6d6fd 100644 --- a/apptentive/src/main/java/com/apptentive/android/sdk/module/engagement/interaction/fragment/MessageCenterFragment.java +++ b/apptentive/src/main/java/com/apptentive/android/sdk/module/engagement/interaction/fragment/MessageCenterFragment.java @@ -73,7 +73,6 @@ import java.lang.ref.WeakReference; import java.text.DateFormat; import java.util.ArrayList; -import java.util.Arrays; import java.util.Date; import java.util.HashSet; import java.util.List; @@ -172,6 +171,7 @@ public class MessageCenterFragment extends ApptentiveBaseFragment images) { + public void addAttachmentsToComposer(ImageItem... images) { ArrayList newImages = new ArrayList(); // only add new images, and filter out duplicates - if (images != null && images.size() > 0) { + if (images != null && images.length > 0) { for (ImageItem newImage : images) { boolean bDupFound = false; for (ImageItem pendingAttachment : pendingAttachments) { @@ -675,11 +678,8 @@ public void addAttachmentsToComposer(final List images) { if (newImages.isEmpty()) { return; } - if (messageCenterRecyclerViewAdapter != null) { - // Only update composing view if image is attached successfully - messageCenterRecyclerViewAdapter.addImagestoComposer(composer, newImages); - //messageCenterRecyclerViewAdapter.notify(); - } + messageCenterRecyclerViewAdapter.addImagestoComposer(composer, newImages); + messageCenterRecyclerViewAdapter.notifyItemChanged(listItems.size() - 1); int firstIndex = messageCenterRecyclerView.getFirstVisiblePosition(); messagingActionHandler.sendMessage(messagingActionHandler.obtainMessage(MSG_SCROLL_FROM_TOP, firstIndex, top)); } @@ -691,17 +691,9 @@ public void setAttachmentsInComposer(final List images) { } - // TODO: This needs to be sent through the Handler public void removeImageFromComposer(final int position) { - ApptentiveLog.e("removeImageFromComposer()"); EngagementModule.engageInternal(hostingActivityRef.get(), interaction, MessageCenterInteraction.EVENT_NAME_ATTACHMENT_DELETE); - pendingAttachments.remove(position); - if (messageCenterRecyclerViewAdapter != null) { - messageCenterRecyclerViewAdapter.removeImageFromComposer(composer, position); -// int count = imageAttachmentstList.size(); - // Show keyboard if all attachments have been removed - messageCenterRecyclerViewAdapter.notifyDataSetChanged(); // TODO: Only invalidate the composer - } + messagingActionHandler.sendMessage(messagingActionHandler.obtainMessage(MSG_REMOVE_ATTACHMENT, position, 0)); messagingActionHandler.sendEmptyMessageDelayed(MSG_SCROLL_TO_BOTTOM, DEFAULT_DELAYMILLIS); } @@ -1056,6 +1048,7 @@ public void savePendingComposingMessage() { editor.putString(Constants.PREF_KEY_MESSAGE_CENTER_PENDING_COMPOSING_ATTACHMENTS, pendingAttachmentsJsonArray.toString()); } else { editor.remove(Constants.PREF_KEY_MESSAGE_CENTER_PENDING_COMPOSING_ATTACHMENTS); + editor.remove(Constants.PREF_KEY_MESSAGE_CENTER_PENDING_COMPOSING_ATTACHMENTS); } editor.apply(); } @@ -1527,6 +1520,13 @@ public void handleMessage(Message msg) { } break; } + case MSG_REMOVE_ATTACHMENT: { + int position = msg.arg1; + fragment.pendingAttachments.remove(position); + fragment.messageCenterRecyclerViewAdapter.removeImageFromComposer(fragment.composer, position); + fragment.messageCenterRecyclerViewAdapter.notifyItemChanged(fragment.listItems.size() - 1); + break; + } } } } diff --git a/apptentive/src/main/java/com/apptentive/android/sdk/module/messagecenter/view/holder/MessageComposerHolder.java b/apptentive/src/main/java/com/apptentive/android/sdk/module/messagecenter/view/holder/MessageComposerHolder.java index e85fdee75..f2b32ddfd 100644 --- a/apptentive/src/main/java/com/apptentive/android/sdk/module/messagecenter/view/holder/MessageComposerHolder.java +++ b/apptentive/src/main/java/com/apptentive/android/sdk/module/messagecenter/view/holder/MessageComposerHolder.java @@ -159,7 +159,6 @@ public void onClick(int position, ImageItem image) { //Initialize image attachments band with empty data clearImageAttachmentBand(); attachments.setVisibility(View.GONE); - attachments.setAdapterIndicator(0); attachments.setData(new ArrayList()); if (adapter.getListener() != null) { @@ -202,6 +201,7 @@ public void addImagesToImageAttachmentBand(final List imagesToAttach) images.addAll(imagesToAttach); addAdditionalAttachItem(); + attachments.notifyDataSetChanged(); } /** diff --git a/apptentive/src/main/java/com/apptentive/android/sdk/util/image/ApptentiveImageGridView.java b/apptentive/src/main/java/com/apptentive/android/sdk/util/image/ApptentiveImageGridView.java index 345b2ee55..7b716e629 100644 --- a/apptentive/src/main/java/com/apptentive/android/sdk/util/image/ApptentiveImageGridView.java +++ b/apptentive/src/main/java/com/apptentive/android/sdk/util/image/ApptentiveImageGridView.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, Apptentive, Inc. All Rights Reserved. + * Copyright (c) 2016, Apptentive, Inc. All Rights Reserved. * Please refer to the LICENSE file for the terms and conditions * under which redistribution and use of this file is permitted. */ @@ -81,8 +81,6 @@ public void onGlobalLayout() { } else { getViewTreeObserver().removeGlobalOnLayoutListener(this); } - - } }); } @@ -114,4 +112,8 @@ public void setData(List images) { public interface ImageItemClickedListener { void onClick(int position, ImageItem image); } + + public void notifyDataSetChanged() { + imageBandAdapter.notifyDataSetChanged(); + } } \ No newline at end of file diff --git a/apptentive/src/main/res/layout/apptentive_image_grid_view_item.xml b/apptentive/src/main/res/layout/apptentive_image_grid_view_item.xml index 4b88bc5ed..43a87a201 100644 --- a/apptentive/src/main/res/layout/apptentive_image_grid_view_item.xml +++ b/apptentive/src/main/res/layout/apptentive_image_grid_view_item.xml @@ -1,7 +1,7 @@ @@ -34,9 +34,17 @@ Date: Tue, 8 Nov 2016 10:35:50 -0800 Subject: [PATCH 051/100] Remove development logging. --- .../fragment/MessageCenterFragment.java | 18 +--------------- .../MessageCenterRecyclerViewAdapter.java | 21 +------------------ .../view/holder/MessageComposerHolder.java | 9 -------- 3 files changed, 2 insertions(+), 46 deletions(-) diff --git a/apptentive/src/main/java/com/apptentive/android/sdk/module/engagement/interaction/fragment/MessageCenterFragment.java b/apptentive/src/main/java/com/apptentive/android/sdk/module/engagement/interaction/fragment/MessageCenterFragment.java index bb0e6d6fd..95e013ecc 100644 --- a/apptentive/src/main/java/com/apptentive/android/sdk/module/engagement/interaction/fragment/MessageCenterFragment.java +++ b/apptentive/src/main/java/com/apptentive/android/sdk/module/engagement/interaction/fragment/MessageCenterFragment.java @@ -200,7 +200,6 @@ public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle sa } public void onViewCreated(View view, Bundle onSavedInstanceState) { - ApptentiveLog.e("onViewCreated()"); super.onViewCreated(view, onSavedInstanceState); boolean isInitialViewCreation = (onSavedInstanceState == null); /* When isInitialViewCreation is false, the view is being recreated after orientation change. @@ -756,7 +755,6 @@ public synchronized void onResumeSending() { @Override public void onComposingViewCreated(MessageComposerHolder composer, final EditText composerEditText, final ApptentiveImageGridView attachments) { - ApptentiveLog.e("onComposingViewCreated()"); EngagementModule.engageInternal(hostingActivityRef.get(), interaction, MessageCenterInteraction.EVENT_NAME_COMPOSE_OPEN); this.composer = composer; @@ -900,7 +898,6 @@ public void onFinishComposing() { @Override public void onSubmitWhoCard(String buttonLabel) { - ApptentiveLog.e("onSubmitWhoCard()"); JSONObject data = new JSONObject(); try { data.put("required", interaction.getWhoCardRequired()); @@ -923,7 +920,6 @@ public void onSubmitWhoCard(String buttonLabel) { @Override public void onCloseWhoCard(String buttonLabel) { - ApptentiveLog.e("onCloseWhoCard()"); JSONObject data = new JSONObject(); try { data.put("required", interaction.getWhoCardRequired()); @@ -1061,6 +1057,7 @@ public void clearPendingComposingMessage() { prefs.edit() .remove(Constants.PREF_KEY_MESSAGE_CENTER_PENDING_COMPOSING_MESSAGE) .remove(Constants.PREF_KEY_MESSAGE_CENTER_PENDING_COMPOSING_ATTACHMENTS) + .remove(Constants.PREF_KEY_MESSAGE_CENTER_PENDING_COMPOSING_ATTACHMENTS) .apply(); } @@ -1143,7 +1140,6 @@ private int calculateFabPadding(Context context) { } private void showFab() { - ApptentiveLog.e("showFab()"); messageCenterRecyclerView.setPadding(0, 0, 0, fabPaddingPixels); // Re-enable Fab at the beginning of the animation if (fab.getVisibility() != View.VISIBLE) { @@ -1153,7 +1149,6 @@ private void showFab() { } private void hideFab() { - ApptentiveLog.e("hideFab()"); // Make sure Fab is not clickable during fade-out animation if (fab.getVisibility() != View.GONE) { fab.setEnabled(false); @@ -1284,7 +1279,6 @@ public void handleMessage(Message msg) { } switch (msg.what) { case MSG_MESSAGE_ADD_WHOCARD: { - ApptentiveLog.e("Adding Who Card"); // msg.arg1 is either WHO_CARD_MODE_INIT or WHO_CARD_MODE_EDIT boolean initial = msg.arg1 == 0; WhoCard whoCard = fragment.interaction.getWhoCard(); @@ -1300,7 +1294,6 @@ public void handleMessage(Message msg) { int i = messageIterator.nextIndex(); MessageCenterUtil.MessageCenterListItem next = messageIterator.next(); if (next.getListItemType() == WHO_CARD) { - ApptentiveLog.e("Removing Who Card"); messageIterator.remove(); fragment.messageCenterRecyclerViewAdapter.notifyItemRemoved(i); } @@ -1367,13 +1360,11 @@ public void handleMessage(Message msg) { } case MSG_START_SENDING: { CompoundMessage message = (CompoundMessage) msg.obj; - ApptentiveLog.e("Adding Message to list"); fragment.listItems.add(message); fragment.messageCenterRecyclerViewAdapter.notifyItemInserted(fragment.listItems.size() - 1); fragment.unsentMessagesCount++; fragment.setPaused(false); - ApptentiveLog.e("Sending message"); ApptentiveInternal.getInstance().getMessageManager().sendMessage(message); // After the message is sent, show the Who Card if it has never been seen before, and the configuration specifies it should be requested. @@ -1414,19 +1405,16 @@ public void handleMessage(Message msg) { message.setRead(true); // Add it to the RecyclerView - ApptentiveLog.e("Adding Real Context Message"); fragment.unsentMessagesCount++; fragment.listItems.add(message); fragment.messageCenterRecyclerViewAdapter.notifyItemInserted(fragment.listItems.size() - 1); // Send it to the server - ApptentiveLog.e("Sending Real Context Message"); ApptentiveInternal.getInstance().getMessageManager().sendMessage(message); } break; } case MSG_PAUSE_SENDING: { - ApptentiveLog.e("PAUSE"); if (!fragment.isPaused()) { fragment.setPaused(true); if (fragment.unsentMessagesCount > 0) { @@ -1438,7 +1426,6 @@ public void handleMessage(Message msg) { break; } case MSG_RESUME_SENDING: { - ApptentiveLog.e("RESUME"); if (fragment.isPaused()) { fragment.setPaused(false); if (fragment.unsentMessagesCount > 0) { @@ -1451,7 +1438,6 @@ public void handleMessage(Message msg) { for (int i = 0; i < fragment.listItems.size(); i++) { MessageCenterUtil.MessageCenterListItem item = fragment.listItems.get(i); if (item.getListItemType() == MESSAGE_COMPOSER) { - ApptentiveLog.e("Removing Composer"); fragment.listItems.remove(i); fragment.messageCenterRecyclerViewAdapter.notifyItemRemoved(i); } @@ -1485,7 +1471,6 @@ public void handleMessage(Message msg) { for (int i = 0; i < listItems.size(); i++) { MessageCenterUtil.MessageCenterListItem item = listItems.get(i); if (item.getListItemType() == STATUS) { - ApptentiveLog.e("Removing Status"); listItems.remove(i); fragment.messageCenterRecyclerViewAdapter.notifyItemRemoved(i); } @@ -1493,7 +1478,6 @@ public void handleMessage(Message msg) { break; } case MSG_ADD_CONTEXT_MESSAGE: { - ApptentiveLog.e("Adding Context Message"); ContextMessage contextMessage = (ContextMessage) msg.obj; fragment.listItems.add(contextMessage); fragment.messageCenterRecyclerViewAdapter.notifyItemInserted(fragment.listItems.size() - 1); diff --git a/apptentive/src/main/java/com/apptentive/android/sdk/module/messagecenter/view/MessageCenterRecyclerViewAdapter.java b/apptentive/src/main/java/com/apptentive/android/sdk/module/messagecenter/view/MessageCenterRecyclerViewAdapter.java index b3308bd52..4370c4245 100644 --- a/apptentive/src/main/java/com/apptentive/android/sdk/module/messagecenter/view/MessageCenterRecyclerViewAdapter.java +++ b/apptentive/src/main/java/com/apptentive/android/sdk/module/messagecenter/view/MessageCenterRecyclerViewAdapter.java @@ -79,78 +79,65 @@ public void onAttachedToRecyclerView(RecyclerView recyclerView) { @Override public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) { -// ApptentiveLog.e("onCreateViewHolder()"); switch (viewType) { case MESSAGE_COMPOSER: { -// ApptentiveLog.w("-> Message Composer"); LayoutInflater inflater = LayoutInflater.from(parent.getContext()); View view = inflater.inflate(R.layout.apptentive_message_center_composer, parent, false); return new MessageComposerHolder(view); } case STATUS: { -// ApptentiveLog.w("-> Status"); LayoutInflater inflater = LayoutInflater.from(parent.getContext()); View view = inflater.inflate(R.layout.apptentive_message_center_status, parent, false); return new StatusHolder(view); } case GREETING: { -// ApptentiveLog.w("-> Greeting"); LayoutInflater inflater = LayoutInflater.from(parent.getContext()); View view = inflater.inflate(R.layout.apptentive_message_center_greeting, parent, false); return new GreetingHolder(view); } case MESSAGE_OUTGOING: { -// ApptentiveLog.w("-> Message Outgoing"); LayoutInflater inflater = LayoutInflater.from(parent.getContext()); View view = inflater.inflate(R.layout.apptentive_message_outgoing, parent, false); return new OutgoingCompoundMessageHolder(view); } case MESSAGE_INCOMING: { -// ApptentiveLog.w("-> Message Incoming"); LayoutInflater inflater = LayoutInflater.from(parent.getContext()); View view = inflater.inflate(R.layout.apptentive_message_incoming, parent, false); return new IncomingCompoundMessageHolder(view); } case MESSAGE_AUTO: { -// ApptentiveLog.w("-> Message Auto"); LayoutInflater inflater = LayoutInflater.from(parent.getContext()); View view = inflater.inflate(R.layout.apptentive_message_auto, parent, false); return new AutomatedMessageHolder(view); } case WHO_CARD: { -// ApptentiveLog.w("-> Who Card"); LayoutInflater inflater = LayoutInflater.from(parent.getContext()); View view = inflater.inflate(R.layout.apptentive_message_center_who_card, parent, false); return new WhoCardHolder(this, view); } case MESSAGE_CONTEXT: { -// ApptentiveLog.w("-> Message Context"); LayoutInflater inflater = LayoutInflater.from(parent.getContext()); View view = inflater.inflate(R.layout.apptentive_message_center_context_message, parent, false); return new ContextMessageHolder(view); } } - ApptentiveLog.e("onCreateViewHolder(%d) returning null.", viewType); + ApptentiveLog.w("onCreateViewHolder(%d) returning null.", viewType); return null; } @Override public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) { - ApptentiveLog.e("onBindViewHolder()"); switch (getItemViewType(position)) { case MESSAGE_COMPOSER: { - ApptentiveLog.w("-> Message Composer"); Composer composer = (Composer) listItems.get(position); MessageComposerHolder composerHolder = (MessageComposerHolder) holder; composerHolder.bindView(fragment, this, composer); break; } case STATUS: { - ApptentiveLog.w("-> Status"); MessageCenterStatus status = (MessageCenterStatus) listItems.get(position); StatusHolder statusHolder = (StatusHolder) holder; statusHolder.body.setText(status.body); - if (status.icon != null) { statusHolder.icon.setImageResource(status.icon); statusHolder.icon.setVisibility(View.VISIBLE); @@ -160,14 +147,12 @@ public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) { break; } case GREETING: { - ApptentiveLog.w("-> Greeting"); MessageCenterGreeting greeting = (MessageCenterGreeting) listItems.get(position); GreetingHolder greetingHolder = (GreetingHolder) holder; greetingHolder.bindView(greeting); break; } case MESSAGE_INCOMING: { - ApptentiveLog.w("-> Message Incoming"); CompoundMessage compoundMessage = (CompoundMessage) listItems.get(position); IncomingCompoundMessageHolder compoundHolder = (IncomingCompoundMessageHolder) holder; compoundHolder.bindView(fragment, recyclerView, this, compoundMessage); @@ -179,28 +164,24 @@ public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) { break; } case MESSAGE_OUTGOING: { - ApptentiveLog.w("-> Message Outgoing"); CompoundMessage compoundMessage = (CompoundMessage) listItems.get(position); OutgoingCompoundMessageHolder compoundHolder = (OutgoingCompoundMessageHolder) holder; compoundHolder.bindView(fragment, recyclerView, this, compoundMessage); break; } case MESSAGE_AUTO: { - ApptentiveLog.w("-> Message Auto"); CompoundMessage autoMessage = (CompoundMessage) listItems.get(position); AutomatedMessageHolder autoHolder = (AutomatedMessageHolder) holder; autoHolder.bindView(recyclerView, autoMessage); break; } case WHO_CARD: { - ApptentiveLog.w("-> Who Card"); WhoCard whoCard = (WhoCard) listItems.get(position); WhoCardHolder whoCardHolder = (WhoCardHolder) holder; whoCardHolder.bindView(recyclerView, whoCard); break; } case MESSAGE_CONTEXT: { - ApptentiveLog.w("-> Message Context"); ContextMessage contextMessage = (ContextMessage) listItems.get(position); ContextMessageHolder contextMessageHolder = (ContextMessageHolder) holder; contextMessageHolder.bindView(contextMessage); diff --git a/apptentive/src/main/java/com/apptentive/android/sdk/module/messagecenter/view/holder/MessageComposerHolder.java b/apptentive/src/main/java/com/apptentive/android/sdk/module/messagecenter/view/holder/MessageComposerHolder.java index f2b32ddfd..ef5ad10b4 100644 --- a/apptentive/src/main/java/com/apptentive/android/sdk/module/messagecenter/view/holder/MessageComposerHolder.java +++ b/apptentive/src/main/java/com/apptentive/android/sdk/module/messagecenter/view/holder/MessageComposerHolder.java @@ -22,7 +22,6 @@ import android.widget.ImageButton; import android.widget.TextView; -import com.apptentive.android.sdk.ApptentiveLog; import com.apptentive.android.sdk.R; import com.apptentive.android.sdk.module.engagement.interaction.fragment.MessageCenterFragment; import com.apptentive.android.sdk.module.messagecenter.model.Composer; @@ -61,7 +60,6 @@ public MessageComposerHolder(View itemView) { } public void bindView(final MessageCenterFragment fragment, final MessageCenterRecyclerViewAdapter adapter, final Composer composer) { - ApptentiveLog.e("BINDING IMAGE"); title.setText(composer.title); ColorStateList colors = ContextCompat.getColorStateList(itemView.getContext(), Util.getResourceIdFromAttribute(itemView.getContext().getTheme(), R.attr.apptentiveButtonTintColorStateList)); @@ -178,7 +176,6 @@ public void onViewAttachedToWindow() { * Remove all images from attachment band. */ public void clearImageAttachmentBand() { - ApptentiveLog.e("CLEARING ATTACHMENTS"); attachments.setVisibility(View.GONE); images.clear(); attachments.setData(null); @@ -193,12 +190,8 @@ public void addImagesToImageAttachmentBand(final List imagesToAttach) if (imagesToAttach == null || imagesToAttach.size() == 0) { return; } - ApptentiveLog.e("ADDING IMAGES"); - attachments.setupLayoutListener(); - ApptentiveLog.e("SHOWING"); attachments.setVisibility(View.VISIBLE); - images.addAll(imagesToAttach); addAdditionalAttachItem(); attachments.notifyDataSetChanged(); @@ -210,12 +203,10 @@ public void addImagesToImageAttachmentBand(final List imagesToAttach) * @param position the postion index of the image to be removed */ public void removeImageFromImageAttachmentBand(final int position) { - ApptentiveLog.e("REMOVING IMAGE"); images.remove(position); attachments.setupLayoutListener(); if (images.size() == 0) { // Hide attachment band after last attachment is removed - ApptentiveLog.e("HIDING"); attachments.setVisibility(View.GONE); return; } From d7fa0d4e86733d61552190b9821732a77637ad30 Mon Sep 17 00:00:00 2001 From: skykelsey Date: Tue, 8 Nov 2016 10:39:20 -0800 Subject: [PATCH 052/100] Bump version and update changelog. --- CHANGELOG.md | 10 ++++++++++ README.md | 2 +- .../com/apptentive/android/sdk/util/Constants.java | 2 +- 3 files changed, 12 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index e35a756c5..02b6924d5 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,13 @@ +# 2016-11-?? - 3.4.0 + +#### Improvements + +* Rebuilt Message Center to use modern RecyclerView for better performance and stability. + +#### Bugs Fixed + +* Fixed a bug where the Profile Card in Message Center wouldn't let a user focus the email field. + # 2016-10-21 - 3.3.0 #### Improvements diff --git a/README.md b/README.md index c245a6f37..95eef975f 100644 --- a/README.md +++ b/README.md @@ -13,7 +13,7 @@ use your app, to talk to them at the right time, and in the right way. ##### Version history is tracked [here](CHANGELOG.md) -##### Binary releases are hosted for Maven [here](http://search.maven.org/#artifactdetails|com.apptentive|apptentive-android|3.3.0|aar) +##### Binary releases are hosted for Maven [here](http://search.maven.org/#artifactdetails|com.apptentive|apptentive-android|3.4.0|aar) #### Reporting Bugs diff --git a/apptentive/src/main/java/com/apptentive/android/sdk/util/Constants.java b/apptentive/src/main/java/com/apptentive/android/sdk/util/Constants.java index 89bb781bf..8a7ea6ce8 100644 --- a/apptentive/src/main/java/com/apptentive/android/sdk/util/Constants.java +++ b/apptentive/src/main/java/com/apptentive/android/sdk/util/Constants.java @@ -8,7 +8,7 @@ public class Constants { - public static final String APPTENTIVE_SDK_VERSION = "3.3.0"; + public static final String APPTENTIVE_SDK_VERSION = "3.4.0"; public static final int REQUEST_CODE_PHOTO_FROM_SYSTEM_PICKER = 10; From e7f317c9f138f3bc6fd7cd55c475aff17f657010 Mon Sep 17 00:00:00 2001 From: skykelsey Date: Tue, 8 Nov 2016 11:20:00 -0800 Subject: [PATCH 053/100] Fix typo. --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 95eef975f..e0b50f628 100644 --- a/README.md +++ b/README.md @@ -26,5 +26,5 @@ We appreciate contributions to make this SDK better. If you have an improvement #### Notes -* Make sure you have latest version or our SDK. We're always adding new features! +* Make sure you have latest version of our SDK. We're always adding new features! * Make sure to follow the repo to get updates about features and bug fixes. From 718cf8b67273d29f1fb23d0fb38303774cb05d5f Mon Sep 17 00:00:00 2001 From: skykelsey Date: Tue, 8 Nov 2016 11:22:31 -0800 Subject: [PATCH 054/100] Add MC attach event --- .../interaction/fragment/MessageCenterFragment.java | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/apptentive/src/main/java/com/apptentive/android/sdk/module/engagement/interaction/fragment/MessageCenterFragment.java b/apptentive/src/main/java/com/apptentive/android/sdk/module/engagement/interaction/fragment/MessageCenterFragment.java index 95e013ecc..ce3c80086 100644 --- a/apptentive/src/main/java/com/apptentive/android/sdk/module/engagement/interaction/fragment/MessageCenterFragment.java +++ b/apptentive/src/main/java/com/apptentive/android/sdk/module/engagement/interaction/fragment/MessageCenterFragment.java @@ -284,6 +284,7 @@ public void onActivityResult(int requestCode, int resultCode, Intent data) { } } + EngagementModule.engageInternal(getActivity(), interaction, MessageCenterInteraction.EVENT_NAME_ATTACH); String originalPath = Util.getRealFilePathFromUri(hostingActivity, uri); if (originalPath != null) { @@ -293,18 +294,14 @@ public void onActivityResult(int requestCode, int resultCode, Intent data) { long creation_time = Util.getContentCreationTime(hostingActivity, uri); Uri fileUri = Uri.fromFile(new File(originalPath)); File cacheDir = Util.getDiskCacheDir(hostingActivity); - addAttachmentsToComposer( - new ImageItem(originalPath, Util.generateCacheFileFullPath(fileUri, cacheDir, creation_time), Util.getMimeTypeFromUri(hostingActivity, uri), creation_time) - ); + addAttachmentsToComposer(new ImageItem(originalPath, Util.generateCacheFileFullPath(fileUri, cacheDir, creation_time), Util.getMimeTypeFromUri(hostingActivity, uri), creation_time)); } else { /* If not able to get image file path due to not having READ_EXTERNAL_STORAGE permission, * cache name will be generated from md5 of uri string */ File cacheDir = Util.getDiskCacheDir(hostingActivity); String cachedFileName = Util.generateCacheFileFullPath(uri, cacheDir, 0); - addAttachmentsToComposer( - new ImageItem(uri.toString(), cachedFileName, Util.getMimeTypeFromUri(hostingActivity, uri), 0) - ); + addAttachmentsToComposer(new ImageItem(uri.toString(), cachedFileName, Util.getMimeTypeFromUri(hostingActivity, uri), 0)); } break; From 58840bf98b6f691fb2550a7d499002ad332450bb Mon Sep 17 00:00:00 2001 From: skykelsey Date: Tue, 8 Nov 2016 12:04:34 -0800 Subject: [PATCH 055/100] Don't allow the MC info button to open multiple copies of the About page. --- .../messagecenter/view/holder/GreetingHolder.java | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/apptentive/src/main/java/com/apptentive/android/sdk/module/messagecenter/view/holder/GreetingHolder.java b/apptentive/src/main/java/com/apptentive/android/sdk/module/messagecenter/view/holder/GreetingHolder.java index 7491632b1..aa7005e58 100644 --- a/apptentive/src/main/java/com/apptentive/android/sdk/module/messagecenter/view/holder/GreetingHolder.java +++ b/apptentive/src/main/java/com/apptentive/android/sdk/module/messagecenter/view/holder/GreetingHolder.java @@ -12,6 +12,7 @@ import android.widget.TextView; import com.apptentive.android.sdk.ApptentiveInternal; +import com.apptentive.android.sdk.ApptentiveLog; import com.apptentive.android.sdk.R; import com.apptentive.android.sdk.module.messagecenter.model.MessageCenterGreeting; import com.apptentive.android.sdk.module.messagecenter.view.ApptentiveAvatarView; @@ -40,8 +41,15 @@ public void bindView(MessageCenterGreeting greeting) { body.setText(greeting.body); ImageUtil.startDownloadAvatarTask(avatar, greeting.avatar); infoButton.setOnClickListener(new View.OnClickListener() { - public void onClick(View view) { + public void onClick(final View view) { + // Don't let the info button open multiple copies of the About page. view.setClickable(false); + view.postDelayed(new Runnable() { + @Override + public void run() { + view.setClickable(true); + } + }, 300); ApptentiveInternal.getInstance().showAboutInternal(Util.castContextToActivity(itemView.getContext()), false); } }); From 480fb8c28e39deedbf2d87f1625c004b79b5b4cd Mon Sep 17 00:00:00 2001 From: skykelsey Date: Tue, 8 Nov 2016 12:04:58 -0800 Subject: [PATCH 056/100] Fix MC Error Fragment close event. --- .../interaction/fragment/MessageCenterErrorFragment.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apptentive/src/main/java/com/apptentive/android/sdk/module/engagement/interaction/fragment/MessageCenterErrorFragment.java b/apptentive/src/main/java/com/apptentive/android/sdk/module/engagement/interaction/fragment/MessageCenterErrorFragment.java index f50dac8f4..7e04ad23a 100644 --- a/apptentive/src/main/java/com/apptentive/android/sdk/module/engagement/interaction/fragment/MessageCenterErrorFragment.java +++ b/apptentive/src/main/java/com/apptentive/android/sdk/module/engagement/interaction/fragment/MessageCenterErrorFragment.java @@ -82,7 +82,7 @@ private boolean wasLastAttemptServerError(Context context) { } - public boolean onBackPressed() { + public boolean onBackPressed(boolean hardwareBackButtonWasPressed) { EngagementModule.engage(getActivity(), "com.apptentive", "MessageCenter", null, EVENT_NAME_NO_INTERACTION_CLOSE, null, null, (ExtendedData[]) null); return false; } From 2f0b6cf35f63509d3de417389bf7a28f60a1e4d8 Mon Sep 17 00:00:00 2001 From: skykelsey Date: Tue, 8 Nov 2016 12:05:50 -0800 Subject: [PATCH 057/100] Fix event sending for composer, who card, and status. --- .../fragment/MessageCenterFragment.java | 23 +++++++++++++++---- 1 file changed, 18 insertions(+), 5 deletions(-) diff --git a/apptentive/src/main/java/com/apptentive/android/sdk/module/engagement/interaction/fragment/MessageCenterFragment.java b/apptentive/src/main/java/com/apptentive/android/sdk/module/engagement/interaction/fragment/MessageCenterFragment.java index ce3c80086..e9168fe45 100644 --- a/apptentive/src/main/java/com/apptentive/android/sdk/module/engagement/interaction/fragment/MessageCenterFragment.java +++ b/apptentive/src/main/java/com/apptentive/android/sdk/module/engagement/interaction/fragment/MessageCenterFragment.java @@ -458,7 +458,7 @@ else if (pendingWhoCardName != null || pendingWhoCardEmail != null || pendingWho } } } - // Stored pending attachemnts have been restored, remove it from the persistent storage + // Stored pending attachments have been restored, remove it from the persistent storage SharedPreferences.Editor editor = prefs.edit(); editor.remove(Constants.PREF_KEY_MESSAGE_CENTER_PENDING_COMPOSING_ATTACHMENTS).apply(); } @@ -571,20 +571,32 @@ public void addComposingCard() { private boolean checkAddWhoCardIfRequired() { boolean whoCardDisplayedBefore = wasWhoCardAsPreviouslyDisplayed(); + boolean addedWhoCard = false; if (interaction.getWhoCardRequestEnabled() && interaction.getWhoCardRequired()) { if (!whoCardDisplayedBefore) { forceShowKeyboard = true; addWhoCard(true); - return true; + addedWhoCard = true; } else { String savedEmail = Apptentive.getPersonEmail(); if (TextUtils.isEmpty(savedEmail)) { forceShowKeyboard = true; addWhoCard(false); - return true; + addedWhoCard = true; } } } + if (addedWhoCard) { + JSONObject data = new JSONObject(); + try { + data.put("required", interaction.getWhoCardRequired()); + data.put("trigger", "automatic"); + } catch (JSONException e) { + // + } + EngagementModule.engageInternal(hostingActivityRef.get(), interaction, MessageCenterInteraction.EVENT_NAME_PROFILE_OPEN, data.toString()); + return true; + } return false; } @@ -752,8 +764,6 @@ public synchronized void onResumeSending() { @Override public void onComposingViewCreated(MessageComposerHolder composer, final EditText composerEditText, final ApptentiveImageGridView attachments) { - EngagementModule.engageInternal(hostingActivityRef.get(), interaction, MessageCenterInteraction.EVENT_NAME_COMPOSE_OPEN); - this.composer = composer; this.composerEditText = composerEditText; @@ -1298,6 +1308,7 @@ public void handleMessage(Message msg) { break; } case MSG_MESSAGE_ADD_COMPOSING: { + EngagementModule.engageInternal(fragment.hostingActivityRef.get(), fragment.interaction, MessageCenterInteraction.EVENT_NAME_COMPOSE_OPEN); fragment.listItems.add(fragment.interaction.getComposer()); fragment.messageCenterRecyclerViewAdapter.notifyItemInserted(fragment.listItems.size() - 1); fragment.messageCenterRecyclerView.setSelection(fragment.listItems.size() - 1); @@ -1453,6 +1464,7 @@ public void handleMessage(Message msg) { if (createdTime != null && createdTime > Double.MIN_VALUE) { MessageCenterStatus status = fragment.interaction.getRegularStatus(); if (status != null) { + EngagementModule.engageInternal(fragment.hostingActivityRef.get(), fragment.interaction, MessageCenterInteraction.EVENT_NAME_STATUS); // Add expectation status message if the last is a sent listItems.add(status); fragment.messageCenterRecyclerViewAdapter.notifyItemInserted(listItems.size() - 1); @@ -1496,6 +1508,7 @@ public void handleMessage(Message msg) { EngagementModule.engageInternal(fragment.hostingActivityRef.get(), fragment.interaction, MessageCenterInteraction.EVENT_NAME_MESSAGE_HTTP_ERROR); } if (status != null) { + EngagementModule.engageInternal(fragment.hostingActivityRef.get(), fragment.interaction, MessageCenterInteraction.EVENT_NAME_STATUS); fragment.listItems.add(status); fragment.messageCenterRecyclerViewAdapter.notifyItemInserted(fragment.listItems.size() - 1); } From 7ad9b833d7bde6936e7b0c9f0114514542782be1 Mon Sep 17 00:00:00 2001 From: skykelsey Date: Tue, 8 Nov 2016 12:08:31 -0800 Subject: [PATCH 058/100] Comment out unused MC events, reformat code. --- .../model/MessageCenterInteraction.java | 104 +++++++++--------- 1 file changed, 51 insertions(+), 53 deletions(-) diff --git a/apptentive/src/main/java/com/apptentive/android/sdk/module/engagement/interaction/model/MessageCenterInteraction.java b/apptentive/src/main/java/com/apptentive/android/sdk/module/engagement/interaction/model/MessageCenterInteraction.java index a7d1889c2..33d7c3bde 100644 --- a/apptentive/src/main/java/com/apptentive/android/sdk/module/engagement/interaction/model/MessageCenterInteraction.java +++ b/apptentive/src/main/java/com/apptentive/android/sdk/module/engagement/interaction/model/MessageCenterInteraction.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, Apptentive, Inc. All Rights Reserved. + * Copyright (c) 2016, Apptentive, Inc. All Rights Reserved. * Please refer to the LICENSE file for the terms and conditions * under which redistribution and use of this file is permitted. */ @@ -21,9 +21,6 @@ import org.json.JSONException; import org.json.JSONObject; -/** - * @author Sky Kelsey - */ public class MessageCenterInteraction extends Interaction { public static final String KEY_TITLE = "title"; @@ -65,31 +62,32 @@ public class MessageCenterInteraction extends Interaction { public static final String KEY_PROFILE_EDIT_SAVE_BUTTON = "save_button"; - // The server guarantees that an instance of this Interaction will be targetted to the following internal event name. + // The server guarantees that an instance of this Interaction will be targeted to the following internal event name. public static final String DEFAULT_INTERNAL_EVENT_NAME = "show_message_center"; // Events public static final String EVENT_NAME_CLOSE = "close"; public static final String EVENT_NAME_CANCEL = "cancel"; - public static final String EVENT_NAME_ATTACH = "attach"; public static final String EVENT_NAME_READ = "read"; - public static final String EVENT_NAME_GREETING_MESSAGE = "greeting_message"; public static final String EVENT_NAME_COMPOSE_OPEN = "compose_open"; public static final String EVENT_NAME_COMPOSE_CLOSE = "compose_close"; - public static final String EVENT_NAME_KEYBOARD_OPEN = "keyboard_open"; - public static final String EVENT_NAME_KEYBOARD_CLOSE = "keyboard_close"; public static final String EVENT_NAME_STATUS = "status"; public static final String EVENT_NAME_MESSAGE_HTTP_ERROR = "message_http_error"; public static final String EVENT_NAME_MESSAGE_NETWORK_ERROR = "message_network_error"; public static final String EVENT_NAME_PROFILE_OPEN = "profile_open"; public static final String EVENT_NAME_PROFILE_CLOSE = "profile_close"; - public static final String EVENT_NAME_PROFILE_NAME = "profile_name"; - public static final String EVENT_NAME_PROFILE_EMAIL = "profile_email"; public static final String EVENT_NAME_PROFILE_SUBMIT = "profile_submit"; - public static final String EVENT_NAME_ATTACHMENT_LIST_SHOWN = "attachment_list_open"; - public static final String EVENT_NAME_ATTACHMENT_ADD = "attachment_add"; + public static final String EVENT_NAME_ATTACH = "attach"; public static final String EVENT_NAME_ATTACHMENT_DELETE = "attachment_delete"; public static final String EVENT_NAME_ATTACHMENT_CANCEL = "attachment_cancel"; +/* + // Not implemented on Android + public static final String EVENT_NAME_GREETING_MESSAGE = "greeting_message"; + public static final String EVENT_NAME_KEYBOARD_OPEN = "keyboard_open"; + public static final String EVENT_NAME_KEYBOARD_CLOSE = "keyboard_close"; + public static final String EVENT_NAME_PROFILE_NAME = "profile_name"; + public static final String EVENT_NAME_PROFILE_EMAIL = "profile_email"; +*/ public MessageCenterInteraction(String json) throws JSONException { super(json); @@ -118,13 +116,13 @@ public MessageCenterComposingItem getComposerArea() { } JSONObject composer = configuration.optJSONObject(KEY_COMPOSER); return new MessageCenterComposingItem( - MessageCenterComposingItem.COMPOSING_ITEM_AREA, - null, - composer.optString(KEY_COMPOSER_HINT_TEXT, null), - null, - null, - null, - null); + MessageCenterComposingItem.COMPOSING_ITEM_AREA, + null, + composer.optString(KEY_COMPOSER_HINT_TEXT, null), + null, + null, + null, + null); } public MessageCenterComposingItem getComposerBar() { @@ -134,13 +132,13 @@ public MessageCenterComposingItem getComposerBar() { } JSONObject composer = configuration.optJSONObject(KEY_COMPOSER); return new MessageCenterComposingItem( - MessageCenterComposingItem.COMPOSING_ITEM_ACTIONBAR, - composer.optString(KEY_COMPOSER_TITLE, null), - composer.optString(KEY_COMPOSER_CLOSE_BODY, null), - composer.optString(KEY_COMPOSER_CLOSE_DISCARD, null), - composer.optString(KEY_COMPOSER_CLOSE_CANCEL, null), - composer.optString(KEY_COMPOSER_SEND_BUTTON, null), - null); + MessageCenterComposingItem.COMPOSING_ITEM_ACTIONBAR, + composer.optString(KEY_COMPOSER_TITLE, null), + composer.optString(KEY_COMPOSER_CLOSE_BODY, null), + composer.optString(KEY_COMPOSER_CLOSE_DISCARD, null), + composer.optString(KEY_COMPOSER_CLOSE_CANCEL, null), + composer.optString(KEY_COMPOSER_SEND_BUTTON, null), + null); } public Composer getComposer() { @@ -187,24 +185,24 @@ public MessageCenterComposingItem getWhoCardInit() { JSONObject profileInitial = profile.optJSONObject(KEY_PROFILE_INIT); if (profile.optBoolean(KEY_PROFILE_REQUIRE, false)) { return new MessageCenterComposingItem( - MessageCenterComposingItem.COMPOSING_ITEM_WHOCARD_REQUIRED_INIT, - profileInitial.optString(KEY_PROFILE_INIT_TITLE, null), - // Hide name field if profile is required and never set - null, - profileInitial.optString(KEY_PROFILE_INIT_EMAIL_HINT, null), - profileInitial.optString(KEY_PROFILE_INIT_EMAIL_EXPLANATION, null), - // Hide Skip button - null, - profileInitial.optString(KEY_PROFILE_INIT_SAVE_BUTTON, null)); - } - return new MessageCenterComposingItem( - MessageCenterComposingItem.COMPOSING_ITEM_WHOCARD_REQUESTED_INIT, + MessageCenterComposingItem.COMPOSING_ITEM_WHOCARD_REQUIRED_INIT, profileInitial.optString(KEY_PROFILE_INIT_TITLE, null), - profileInitial.optString(KEY_PROFILE_INIT_NAME_HINT, null), + // Hide name field if profile is required and never set + null, profileInitial.optString(KEY_PROFILE_INIT_EMAIL_HINT, null), profileInitial.optString(KEY_PROFILE_INIT_EMAIL_EXPLANATION, null), - profileInitial.optString(KEY_PROFILE_INIT_SKIP_BUTTON, null), + // Hide Skip button + null, profileInitial.optString(KEY_PROFILE_INIT_SAVE_BUTTON, null)); + } + return new MessageCenterComposingItem( + MessageCenterComposingItem.COMPOSING_ITEM_WHOCARD_REQUESTED_INIT, + profileInitial.optString(KEY_PROFILE_INIT_TITLE, null), + profileInitial.optString(KEY_PROFILE_INIT_NAME_HINT, null), + profileInitial.optString(KEY_PROFILE_INIT_EMAIL_HINT, null), + profileInitial.optString(KEY_PROFILE_INIT_EMAIL_EXPLANATION, null), + profileInitial.optString(KEY_PROFILE_INIT_SKIP_BUTTON, null), + profileInitial.optString(KEY_PROFILE_INIT_SAVE_BUTTON, null)); } public JSONObject getProfile() { @@ -234,22 +232,22 @@ public MessageCenterComposingItem getWhoCardEdit() { if (profile.optBoolean(KEY_PROFILE_REQUIRE, false)) { JSONObject profileInitial = profile.optJSONObject(KEY_PROFILE_INIT); return new MessageCenterComposingItem( - MessageCenterComposingItem.COMPOSING_ITEM_WHOCARD_REQUIRED_EDIT, - profileEdit.optString(KEY_PROFILE_EDIT_TITLE, null), - profileEdit.optString(KEY_PROFILE_EDIT_NAME_HINT, null), - profileInitial.optString(KEY_PROFILE_INIT_EMAIL_HINT, null), // Show "Email(required)" - profileEdit.optString(KEY_PROFILE_EDIT_EMAIL_EXPLANATION, null), - profileEdit.optString(KEY_PROFILE_EDIT_SKIP_BUTTON, null), - profileEdit.optString(KEY_PROFILE_EDIT_SAVE_BUTTON, null)); - } - return new MessageCenterComposingItem( - MessageCenterComposingItem.COMPOSING_ITEM_WHOCARD_REQUESTED_EDIT, + MessageCenterComposingItem.COMPOSING_ITEM_WHOCARD_REQUIRED_EDIT, profileEdit.optString(KEY_PROFILE_EDIT_TITLE, null), profileEdit.optString(KEY_PROFILE_EDIT_NAME_HINT, null), - profileEdit.optString(KEY_PROFILE_EDIT_EMAIL_HINT, null), + profileInitial.optString(KEY_PROFILE_INIT_EMAIL_HINT, null), // Show "Email(required)" profileEdit.optString(KEY_PROFILE_EDIT_EMAIL_EXPLANATION, null), profileEdit.optString(KEY_PROFILE_EDIT_SKIP_BUTTON, null), profileEdit.optString(KEY_PROFILE_EDIT_SAVE_BUTTON, null)); + } + return new MessageCenterComposingItem( + MessageCenterComposingItem.COMPOSING_ITEM_WHOCARD_REQUESTED_EDIT, + profileEdit.optString(KEY_PROFILE_EDIT_TITLE, null), + profileEdit.optString(KEY_PROFILE_EDIT_NAME_HINT, null), + profileEdit.optString(KEY_PROFILE_EDIT_EMAIL_HINT, null), + profileEdit.optString(KEY_PROFILE_EDIT_EMAIL_EXPLANATION, null), + profileEdit.optString(KEY_PROFILE_EDIT_SKIP_BUTTON, null), + profileEdit.optString(KEY_PROFILE_EDIT_SAVE_BUTTON, null)); } @@ -263,7 +261,7 @@ public MessageCenterGreeting getGreeting() { return null; } return new MessageCenterGreeting(greeting.optString(KEY_GREETING_TITLE, null), - greeting.optString(KEY_GREETING_BODY, null), greeting.optString(KEY_GREETING_IMAGE, null)); + greeting.optString(KEY_GREETING_BODY, null), greeting.optString(KEY_GREETING_IMAGE, null)); } public JSONObject getContextualMessage() { From e1e3712febdd77d883c90b959ee5a2dc13057c4a Mon Sep 17 00:00:00 2001 From: skykelsey Date: Tue, 8 Nov 2016 12:15:45 -0800 Subject: [PATCH 059/100] Remove the old Message Center code that has now been refactored into other classes. --- .../view/AutomatedMessageView.java | 29 - .../view/CompoundMessageView.java | 60 -- .../messagecenter/view/MessageAdapter.java | 782 ------------------ .../MessageCenterComposingActionBarView.java | 128 --- .../view/MessageCenterComposingView.java | 211 ----- .../view/MessageCenterGreetingView.java | 64 -- .../view/MessageCenterListView.java | 455 ---------- .../view/MessageCenterStatusView.java | 35 - .../view/MessageCenterWhoCardView.java | 183 ---- .../view/PersonalMessageView.java | 36 - .../view/ZeroMinSizeDrawable.java | 36 - .../holder/IncomingCompoundMessageHolder.java | 2 - 12 files changed, 2021 deletions(-) delete mode 100644 apptentive/src/main/java/com/apptentive/android/sdk/module/messagecenter/view/AutomatedMessageView.java delete mode 100644 apptentive/src/main/java/com/apptentive/android/sdk/module/messagecenter/view/CompoundMessageView.java delete mode 100644 apptentive/src/main/java/com/apptentive/android/sdk/module/messagecenter/view/MessageAdapter.java delete mode 100644 apptentive/src/main/java/com/apptentive/android/sdk/module/messagecenter/view/MessageCenterComposingActionBarView.java delete mode 100644 apptentive/src/main/java/com/apptentive/android/sdk/module/messagecenter/view/MessageCenterComposingView.java delete mode 100644 apptentive/src/main/java/com/apptentive/android/sdk/module/messagecenter/view/MessageCenterGreetingView.java delete mode 100644 apptentive/src/main/java/com/apptentive/android/sdk/module/messagecenter/view/MessageCenterListView.java delete mode 100644 apptentive/src/main/java/com/apptentive/android/sdk/module/messagecenter/view/MessageCenterStatusView.java delete mode 100644 apptentive/src/main/java/com/apptentive/android/sdk/module/messagecenter/view/MessageCenterWhoCardView.java delete mode 100644 apptentive/src/main/java/com/apptentive/android/sdk/module/messagecenter/view/PersonalMessageView.java delete mode 100644 apptentive/src/main/java/com/apptentive/android/sdk/module/messagecenter/view/ZeroMinSizeDrawable.java diff --git a/apptentive/src/main/java/com/apptentive/android/sdk/module/messagecenter/view/AutomatedMessageView.java b/apptentive/src/main/java/com/apptentive/android/sdk/module/messagecenter/view/AutomatedMessageView.java deleted file mode 100644 index 55be1eeae..000000000 --- a/apptentive/src/main/java/com/apptentive/android/sdk/module/messagecenter/view/AutomatedMessageView.java +++ /dev/null @@ -1,29 +0,0 @@ -/* - * Copyright (c) 2015, Apptentive, Inc. All Rights Reserved. - * Please refer to the LICENSE file for the terms and conditions - * under which redistribution and use of this file is permitted. - */ - -package com.apptentive.android.sdk.module.messagecenter.view; - -import android.content.Context; -import android.view.LayoutInflater; - -import com.apptentive.android.sdk.R; -import com.apptentive.android.sdk.module.messagecenter.model.CompoundMessage; - -/** - * @author Sky Kelsey - */ -public class AutomatedMessageView extends MessageView { - - public AutomatedMessageView(Context context, CompoundMessage message) { - super(context, message); - } - - protected void init(Context context, CompoundMessage message) { - super.init(context, message); - LayoutInflater inflater = LayoutInflater.from(context); - inflater.inflate(R.layout.apptentive_message_auto, this); - } -} diff --git a/apptentive/src/main/java/com/apptentive/android/sdk/module/messagecenter/view/CompoundMessageView.java b/apptentive/src/main/java/com/apptentive/android/sdk/module/messagecenter/view/CompoundMessageView.java deleted file mode 100644 index a086abbd0..000000000 --- a/apptentive/src/main/java/com/apptentive/android/sdk/module/messagecenter/view/CompoundMessageView.java +++ /dev/null @@ -1,60 +0,0 @@ -/* - * Copyright (c) 2015, Apptentive, Inc. All Rights Reserved. - * Please refer to the LICENSE file for the terms and conditions - * under which redistribution and use of this file is permitted. - */ - -package com.apptentive.android.sdk.module.messagecenter.view; - -import android.content.Context; -import android.view.View; -import com.apptentive.android.sdk.R; -import com.apptentive.android.sdk.module.messagecenter.model.CompoundMessage; -import com.apptentive.android.sdk.util.image.ApptentiveImageGridView; -import com.apptentive.android.sdk.util.image.ImageItem; - -import java.lang.ref.WeakReference; -import java.util.ArrayList; - -/** - * @author Barry Li - */ -public class CompoundMessageView extends PersonalMessageView { - - private WeakReference listenerRef; - private boolean isOutGoingView = false; - - public CompoundMessageView(Context context, CompoundMessage message, final MessageAdapter.OnListviewItemActionListener listener) { - super(context, message); - this.listenerRef = new WeakReference(listener); - isOutGoingView = message.isOutgoingMessage(); - } - - protected void init(Context context, CompoundMessage message) { - super.init(context, message); - ApptentiveImageGridView imageBandView = (ApptentiveImageGridView) findViewById(R.id.grid); - imageBandView.setupUi(); - - imageBandView.setListener(new ApptentiveImageGridView.ImageItemClickedListener() { - @Override - public void onClick(int position, ImageItem image) { - MessageAdapter.OnListviewItemActionListener listener = listenerRef.get(); - if (listener != null) { - listener.onClickAttachment(position, image); - } - } - }); - imageBandView.setVisibility(View.GONE); - imageBandView.setAdapterIndicator(0); - imageBandView.setData(new ArrayList()); - } - - public boolean isViewShowingOutgoingMessage() { - return isOutGoingView; - } - - public MessageAdapter.OnListviewItemActionListener getListener() { - return listenerRef.get(); - } - -} \ No newline at end of file diff --git a/apptentive/src/main/java/com/apptentive/android/sdk/module/messagecenter/view/MessageAdapter.java b/apptentive/src/main/java/com/apptentive/android/sdk/module/messagecenter/view/MessageAdapter.java deleted file mode 100644 index d1e062610..000000000 --- a/apptentive/src/main/java/com/apptentive/android/sdk/module/messagecenter/view/MessageAdapter.java +++ /dev/null @@ -1,782 +0,0 @@ -/* - * Copyright (c) 2016, Apptentive, Inc. All Rights Reserved. - * Please refer to the LICENSE file for the terms and conditions - * under which redistribution and use of this file is permitted. - */ - -package com.apptentive.android.sdk.module.messagecenter.view; - -import android.animation.Animator; -import android.animation.AnimatorSet; -import android.graphics.Bitmap; -import android.graphics.BitmapFactory; -import android.graphics.Point; -import android.os.Build; -import android.os.Parcelable; -import android.support.v4.app.Fragment; -import android.text.TextUtils; -import android.view.MotionEvent; -import android.view.View; -import android.view.ViewGroup; -import android.widget.ArrayAdapter; -import android.os.AsyncTask; -import android.widget.EditText; - -import com.apptentive.android.sdk.Apptentive; -import com.apptentive.android.sdk.ApptentiveInternal; -import com.apptentive.android.sdk.ApptentiveLog; -import com.apptentive.android.sdk.R; -import com.apptentive.android.sdk.model.*; -import com.apptentive.android.sdk.module.engagement.EngagementModule; -import com.apptentive.android.sdk.module.engagement.interaction.model.MessageCenterInteraction; -import com.apptentive.android.sdk.module.messagecenter.MessageManager; -import com.apptentive.android.sdk.module.messagecenter.model.ApptentiveMessage; -import com.apptentive.android.sdk.module.messagecenter.model.CompoundMessage; -import com.apptentive.android.sdk.module.messagecenter.model.MessageCenterComposingItem; -import com.apptentive.android.sdk.module.messagecenter.model.MessageCenterGreeting; -import com.apptentive.android.sdk.module.messagecenter.model.MessageCenterStatus; -import com.apptentive.android.sdk.module.messagecenter.model.MessageCenterUtil; -import com.apptentive.android.sdk.module.messagecenter.model.MessageCenterUtil.MessageCenterListItem; -import com.apptentive.android.sdk.module.messagecenter.view.holder.AutomatedMessageHolder; -import com.apptentive.android.sdk.module.messagecenter.view.holder.IncomingCompoundMessageHolder; -import com.apptentive.android.sdk.module.messagecenter.view.holder.MessageCenterListItemHolder; -import com.apptentive.android.sdk.module.messagecenter.view.holder.MessageComposerHolder; -import com.apptentive.android.sdk.module.messagecenter.view.holder.OutgoingCompoundMessageHolder; -import com.apptentive.android.sdk.module.messagecenter.view.holder.StatusHolder; -import com.apptentive.android.sdk.util.AnimationUtil; -import com.apptentive.android.sdk.util.image.ApptentiveImageGridView; -import com.apptentive.android.sdk.util.image.ImageItem; -import com.apptentive.android.sdk.util.image.ImageUtil; -import com.apptentive.android.sdk.util.Util; - -import org.json.JSONException; -import org.json.JSONObject; - -import java.io.FileInputStream; - -import java.lang.ref.WeakReference; - -import java.util.ArrayList; -import java.util.List; - -public class MessageAdapter extends ArrayAdapter - implements MessageCenterListView.ApptentiveMessageCenterListAdapter { - - private static final int - TYPE_COMPOUND_INCOMING = 0, - TYPE_COMPOUND_OUTGOING = 1, - TYPE_GREETING = 2, - TYPE_STATUS = 3, - TYPE_AUTO = 4, - TYPE_COMPOSING_AREA = 5, - TYPE_COMPOSING_BAR = 6, - TYPE_WHOCARD = 7; - - private static final int INVALID_POSITION = -1; - - private final static float MAX_IMAGE_SCREEN_PROPORTION_X = 0.5f; - private final static float MAX_IMAGE_SCREEN_PROPORTION_Y = 0.6f; - - // Some absolute size limits to keep bitmap sizes down. - private final static int MAX_IMAGE_DISPLAY_WIDTH = 800; - private final static int MAX_IMAGE_DISPLAY_HEIGHT = 800; - - // If message sending is paused or not - private boolean isInPauseState = false; - - private Fragment fragment; - - private MessageCenterInteraction interaction; - - // Variables used in composing message - private int composingViewIndex = INVALID_POSITION; - private MessageCenterComposingView composingView; - private EditText composingEditText; - private boolean updateComposingViewImageBand = true; - - private MessageCenterComposingActionBarView composingActionBarView; - - private boolean forceShowKeyboard = true; - - // Variables used in Who Card - private int whoCardViewIndex = INVALID_POSITION; - private boolean focusOnNameField = false; - private MessageCenterWhoCardView whoCardView; - private EditText emailEditText; - private EditText nameEditText; - - // Variables to track showing animation on incoming/outgoing messages - private int lastAnimatedMessagePosition; - private boolean showMessageAnimation; - - private boolean showComposingBarAnimation = true; - - // maps to prevent redundant asynctasks - private ArrayList positionsWithPendingUpdateTask = new ArrayList(); - - private OnListviewItemActionListener composingActionListener; - - public interface OnListviewItemActionListener { - void onComposingViewCreated(MessageComposerHolder composer, EditText composerEditText, ApptentiveImageGridView attachments); - - void beforeComposingTextChanged(CharSequence str); - - void onComposingTextChanged(CharSequence str); - - void afterComposingTextChanged(String str); - - void onCancelComposing(); - - void onFinishComposing(); - - void onWhoCardViewCreated(EditText nameEditText, EditText emailEditText); - - void onSubmitWhoCard(String buttonLabel); - - void onCloseWhoCard(String buttonLabel); - - void onAttachImage(); - - void onClickAttachment(int position, ImageItem image); - } - - public MessageAdapter(Fragment fragment, List items, MessageCenterInteraction interaction) { - super(fragment.getContext().getApplicationContext(), 0, (List) items); - this.fragment = fragment; - this.composingActionListener = (OnListviewItemActionListener) fragment; - this.interaction = interaction; - } - - @Override - public int getItemViewType(int position) { - MessageCenterListItem listItem = getItem(position); - if (listItem instanceof ApptentiveMessage) { - ApptentiveMessage apptentiveMessage = (ApptentiveMessage) listItem; - if (apptentiveMessage.getBaseType() == Payload.BaseType.message) { - switch (apptentiveMessage.getType()) { - case CompoundMessage: - if (apptentiveMessage.isAutomatedMessage()) { - return TYPE_AUTO; - } else if (!apptentiveMessage.isOutgoingMessage()) { - return TYPE_COMPOUND_INCOMING; - } else { - return TYPE_COMPOUND_OUTGOING; - } - default: - break; - } - } - } else if (listItem instanceof MessageCenterGreeting) { - return TYPE_GREETING; - } else if (listItem instanceof MessageCenterStatus) { - return TYPE_STATUS; - } else if (listItem instanceof MessageCenterComposingItem) { - if (((MessageCenterComposingItem) listItem).getType() == - MessageCenterComposingItem.COMPOSING_ITEM_AREA) { - return TYPE_COMPOSING_AREA; - } else if (((MessageCenterComposingItem) listItem).getType() == - MessageCenterComposingItem.COMPOSING_ITEM_ACTIONBAR) { - return TYPE_COMPOSING_BAR; - } else { - return TYPE_WHOCARD; - } - } - return IGNORE_ITEM_VIEW_TYPE; - } - - @Override - public int getViewTypeCount() { - return 8; - } - - @Override - public View getView(final int position, View convertView, ViewGroup parent) { - final View view; - showMessageAnimation = false; - - MessageCenterListItem listItem = getItem(position); - int type = getItemViewType(position); - MessageCenterListItemHolder holder = null; - boolean bLoadAvatar = false; - if (null == convertView) { - // TODO: Do we need this switch anymore? - switch (type) { - case TYPE_COMPOUND_INCOMING: - view = new CompoundMessageView(parent.getContext(), (CompoundMessage) listItem, composingActionListener); - bLoadAvatar = true; - break; - case TYPE_COMPOUND_OUTGOING: - view = new CompoundMessageView(parent.getContext(), (CompoundMessage) listItem, composingActionListener); - break; - case TYPE_GREETING: { - MessageCenterGreeting greeting = (MessageCenterGreeting) listItem; - MessageCenterGreetingView newView = new MessageCenterGreetingView(parent.getContext(), greeting); - ImageUtil.startDownloadAvatarTask(newView.avatar, - ((MessageCenterGreeting) listItem).avatar); - view = newView; - break; - } - case TYPE_STATUS: { - MessageCenterStatusView newView = new MessageCenterStatusView(parent.getContext()); - view = newView; - break; - } - case TYPE_COMPOSING_AREA: { - if (composingView == null) { - composingView = new MessageCenterComposingView(fragment); - setupComposingView(position); - } - view = composingView; - break; - } - case TYPE_COMPOSING_BAR: { - if (composingActionBarView == null) { - composingActionBarView = new MessageCenterComposingActionBarView(fragment, (MessageCenterComposingItem) listItem, composingActionListener); - } - showComposingBarAnimation(); - view = composingActionBarView; - break; - } - case TYPE_WHOCARD: { - if (whoCardView == null) { - whoCardView = new MessageCenterWhoCardView(fragment, composingActionListener); - whoCardView.updateUi((MessageCenterComposingItem) listItem, Apptentive.getPersonName(), - Apptentive.getPersonEmail()); - setupWhoCardView(position); - } - view = whoCardView; - break; - } - case TYPE_AUTO: - view = new AutomatedMessageView(parent.getContext(), (CompoundMessage) listItem); - break; - default: - view = null; - ApptentiveLog.i("Unrecognized type: %d", type); - break; - } - if (view != null) { -// holder = HolderFactory.createHolder((MessageCenterListItemView) view); - view.setTag(holder); - } - } else { - /* System may recycle the view after composing view - ** is removed and recreated - */ - if (type == TYPE_COMPOSING_AREA) { - if (composingView == null) { - updateComposingViewImageBand = true; - composingView = (MessageCenterComposingView) convertView; - setupComposingView(position); - } else if (updateComposingViewImageBand) { - updateComposingViewImageBand = false; - } - view = composingView; - } else if (type == TYPE_WHOCARD) { - if (whoCardView == null) { - whoCardView = (MessageCenterWhoCardView) convertView; - whoCardView.updateUi((MessageCenterComposingItem) listItem, Apptentive.getPersonName(), - Apptentive.getPersonEmail()); - setupWhoCardView(position); - } - view = whoCardView; - } else if (type == TYPE_COMPOSING_BAR) { - composingActionBarView = (MessageCenterComposingActionBarView) convertView; - showComposingBarAnimation(); - view = composingActionBarView; - } else { - view = convertView; - holder = (MessageCenterListItemHolder) convertView.getTag(); - } - } - - if (holder != null) { - switch (type) { - case TYPE_COMPOUND_INCOMING: { - showMessageAnimation = true; - if (bLoadAvatar) { -// ImageUtil.startDownloadAvatarTask(((IncomingCompoundMessageHolder) holder).avatar, -// ((CompoundMessage) listItem).getSenderProfilePhoto()); - } - final CompoundMessage compoundMessage = (CompoundMessage) listItem; - String datestamp = ((CompoundMessage) listItem).getDatestamp(); - View container = view.findViewById(R.id.apptentive_compound_message_body_container); - int widthMeasureSpec = View.MeasureSpec.makeMeasureSpec(parent.getWidth(), View.MeasureSpec.EXACTLY); - view.measure(widthMeasureSpec, 0); - int viewWidth = container.getMeasuredWidth(); -// ((IncomingCompoundMessageHolder) holder).updateMessage(compoundMessage.getSenderUsername(), -// datestamp, compoundMessage.getBody(), viewWidth - container.getPaddingLeft() - container.getPaddingRight(), -// fragment.getResources().getInteger(R.integer.apptentive_image_grid_default_column_number_incoming), -// compoundMessage.getRemoteAttachments()); - if (!compoundMessage.isRead() && !positionsWithPendingUpdateTask.contains(position)) { - positionsWithPendingUpdateTask.add(position); - startUpdateUnreadMessageTask(compoundMessage, position); - } - break; - } - case TYPE_COMPOUND_OUTGOING: { - showMessageAnimation = true; - - CompoundMessage textMessage = (CompoundMessage) listItem; - String datestamp = textMessage.getDatestamp(); - Double createdTime = textMessage.getCreatedAt(); - List files = textMessage.getAssociatedFiles(); - String messageBody = textMessage.getBody(); - String status; - boolean bShowProgress; - if (createdTime == null || createdTime > Double.MIN_VALUE) { - status = createStatus(createdTime, textMessage.isLastSent()); - // show progress bar if: 1. no sent time set, and 2. not paused, and 3. have either text or files to sent - bShowProgress = createdTime == null && !isInPauseState && (files != null || !TextUtils.isEmpty(messageBody)); - } else { - status = fragment.getResources().getString(R.string.apptentive_failed); - bShowProgress = false; - } - int imagebandWidth = 0; - if (files != null && files.size() > 0) { - View container = view.findViewById(R.id.apptentive_compound_message_body_container); - int widthMeasureSpec = View.MeasureSpec.makeMeasureSpec(parent.getWidth(), View.MeasureSpec.EXACTLY); - view.measure(widthMeasureSpec, 0); - int viewWidth = container.getMeasuredWidth(); - imagebandWidth = viewWidth - container.getPaddingLeft() - container.getPaddingRight(); - } - - int statusTextColor = getStatusColor(createdTime); -// ((OutgoingCompoundMessageHolder) holder).updateMessage(datestamp, status, statusTextColor, -// bShowProgress, messageBody, imagebandWidth, -// fragment.getResources().getInteger(R.integer.apptentive_image_grid_default_column_number), files); - break; - } - case TYPE_STATUS: { - MessageCenterStatus status = (MessageCenterStatus) listItem; -// ((StatusHolder) holder).updateMessage(status.body, status.icon); - break; - } - case TYPE_AUTO: { - CompoundMessage autoMessage = (CompoundMessage) listItem; - String dateStamp = autoMessage.getDatestamp(); -// ((AutomatedMessageHolder) holder).updateMessage(dateStamp, autoMessage); - break; - } - default: - return null; - } - holder.position = position; - } - if (composingEditText != null) { - if (composingViewIndex != INVALID_POSITION && composingViewIndex == position) { - composingEditText.post(new Runnable() { - public void run() { - if (composingEditText != null) { - if (!composingEditText.hasFocus()) { - composingEditText.requestFocus(); - } - } - } - }); - } - } else if (nameEditText != null) { - if (whoCardViewIndex != INVALID_POSITION && whoCardViewIndex == position) { - if (focusOnNameField) { - nameEditText.post( - new Runnable() { - public void run() { - if (nameEditText != null) { - nameEditText.requestFocus(); - } - } - } - ); - } else { - emailEditText.post( - new Runnable() { - public void run() { - if (emailEditText != null) { - emailEditText.requestFocus(); - } - } - } - ); - } - } - } - if (showMessageAnimation && position > lastAnimatedMessagePosition) { - AnimatorSet set = AnimationUtil.buildListViewRowShowAnimator(view, new Animator.AnimatorListener() { - @Override - public void onAnimationStart(Animator animation) { - } - - @Override - public void onAnimationRepeat(Animator animation) { - } - - @Override - public void onAnimationEnd(Animator animation) { - view.invalidate(); - } - - @Override - public void onAnimationCancel(Animator animation) { - } - }, null); - set.start(); - lastAnimatedMessagePosition = position; - } - return view; - } - - @Override - public boolean areAllItemsEnabled() { - return false; - } - - @Override - public boolean isEnabled(int position) { - return false; - } - - private void showComposingBarAnimation() { - if (showComposingBarAnimation) { - AnimatorSet set = AnimationUtil.buildListViewRowShowAnimator(composingActionBarView, new Animator.AnimatorListener() { - @Override - public void onAnimationStart(Animator animation) { - } - - @Override - public void onAnimationRepeat(Animator animation) { - } - - @Override - public void onAnimationEnd(Animator animation) { - //composingActionListener.updateComposingBar(); - } - - @Override - public void onAnimationCancel(Animator animation) { - } - }, null); - set.start(); - showComposingBarAnimation = false; - } - } - - public Parcelable getWhoCardNameState() { - if (whoCardView != null) { - return whoCardView.getNameField().onSaveInstanceState(); - } - return null; - } - - public Parcelable getWhoCardEmailState() { - if (whoCardView != null) { - return whoCardView.getEmailField().onSaveInstanceState(); - } - return null; - } - - public String getWhoCardAvatarFileName() { - return null; - } - - public EditText getEditTextInComposing() { - if (composingView != null) { - return composingView.getEditText(); - } - return null; - } - - private void setupComposingView(final int position) { - composingEditText = composingView.getEditText(); - composingViewIndex = position; - composingEditText.setOnTouchListener(new View.OnTouchListener() { - @Override - public boolean onTouch(View v, MotionEvent event) { - if (event.getAction() == MotionEvent.ACTION_UP) { - composingViewIndex = position; - } - return false; - } - }); - AnimatorSet set = AnimationUtil.buildListViewRowShowAnimator(composingView, new Animator.AnimatorListener() { - @Override - public void onAnimationStart(Animator animation) { - } - - @Override - public void onAnimationRepeat(Animator animation) { - } - - @Override - public void onAnimationEnd(Animator animation) { -// composingActionListener.onComposingViewCreated(forceShowKeyboard ? composingEditText : null); - if (updateComposingViewImageBand) { - updateComposingViewImageBand = false; - } - } - - @Override - public void onAnimationCancel(Animator animation) { - } - }, null); - set.start(); - } - - public void clearComposing() { - // Composing view may be recycled for later usage. Clear the content from previous usage - if (composingEditText != null) { - composingEditText.setText(""); - composingEditText = null; - } - if (composingView != null) { - composingView.clearImageAttachmentBand(); - } - composingView = null; - composingActionBarView = null; - composingViewIndex = INVALID_POSITION; - showComposingBarAnimation = true; - updateComposingViewImageBand = true; - } - - private void setupWhoCardView(final int position) { - emailEditText = whoCardView.getEmailField(); - whoCardViewIndex = position; - focusOnNameField = true; - emailEditText.setOnTouchListener(new View.OnTouchListener() { - @Override - public boolean onTouch(View v, MotionEvent event) { - if (event.getAction() == MotionEvent.ACTION_UP) { - whoCardViewIndex = position; - focusOnNameField = false; - } - return false; - } - }); - nameEditText = whoCardView.getNameField(); - if (nameEditText.getVisibility() == View.VISIBLE) { - nameEditText.setOnTouchListener(new View.OnTouchListener() { - @Override - public boolean onTouch(View v, MotionEvent event) { - if (event.getAction() == MotionEvent.ACTION_UP) { - whoCardViewIndex = position; - focusOnNameField = true; - } - return false; - } - }); - } else { - focusOnNameField = false; - } - } - - public View getWhoCardView() { - return whoCardView; - } - - public View getComposingAreaView() { - return composingView; - } - - public MessageCenterComposingActionBarView getComposingActionBarView() { - return composingActionBarView; - } - - public void clearWhoCard() { - whoCardView = null; - emailEditText = null; - nameEditText = null; - whoCardViewIndex = INVALID_POSITION; - } - - public void setPaused(boolean bPause) { - isInPauseState = bPause; - } - - public void setForceShowKeyboard(boolean bVal) { - forceShowKeyboard = bVal; - } - - public void addImagestoComposer(final List images) { - composingView.addImagesToImageAttachmentBand(images); - notifyDataSetChanged(); - } - - public void removeImageFromComposer(int position) { - composingView.removeImageFromImageAttachmentBand(position); - notifyDataSetChanged(); - } - - protected String createStatus(Double seconds, boolean showSent) { - if (seconds == null) { - return isInPauseState ? fragment.getResources().getString(R.string.apptentive_failed) : null; - } - return (showSent) ? fragment.getResources().getString(R.string.apptentive_sent) : null; - } - - protected int getStatusColor(Double seconds) { - if (seconds == null) { - // failed color (red) - return isInPauseState ? Util.getThemeColor(fragment.getContext(), R.attr.apptentiveValidationFailedColor) : 0; - } - // other status color - return Util.getThemeColor(fragment.getContext(), android.R.attr.textColorSecondary); - } - - private Point getBitmapDimensions(StoredFile storedFile) { - Point ret = null; - FileInputStream fis = null; - try { - fis = fragment.getContext().openFileInput(storedFile.getLocalFilePath()); - - final BitmapFactory.Options options = new BitmapFactory.Options(); - options.inJustDecodeBounds = true; - BitmapFactory.decodeStream(fis, null, options); - - Point point = Util.getScreenSize(fragment.getContext()); - int maxImageWidth = (int) (MAX_IMAGE_SCREEN_PROPORTION_X * point.x); - int maxImageHeight = (int) (MAX_IMAGE_SCREEN_PROPORTION_Y * point.x); - maxImageWidth = maxImageWidth > MAX_IMAGE_DISPLAY_WIDTH ? MAX_IMAGE_DISPLAY_WIDTH : maxImageWidth; - maxImageHeight = maxImageHeight > MAX_IMAGE_DISPLAY_HEIGHT ? MAX_IMAGE_DISPLAY_HEIGHT : maxImageHeight; - float scale = ImageUtil.calculateBitmapScaleFactor(options.outWidth, options.outHeight, maxImageWidth, maxImageHeight); - ret = new Point((int) (scale * options.outWidth), (int) (scale * options.outHeight)); - } catch (Exception e) { - ApptentiveLog.e("Error opening stored file.", e); - } finally { - Util.ensureClosed(fis); - } - return ret; - } - - private void startUpdateUnreadMessageTask(CompoundMessage message, int position) { - UpdateUnreadMessageTask task = new UpdateUnreadMessageTask(position); - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB) { - task.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR, message); - } else { - task.execute(message); - } - } - - @Override - public boolean isItemSticky(int viewType) { - return (viewType == TYPE_COMPOSING_BAR); - } - - private class UpdateUnreadMessageTask extends AsyncTask { - private int position; - - public UpdateUnreadMessageTask(int position) { - this.position = position; - } - - @Override - protected Void doInBackground(CompoundMessage... textMessages) { - textMessages[0].setRead(true); - JSONObject data = new JSONObject(); - try { - data.put("message_id", textMessages[0].getId()); - data.put("message_type", textMessages[0].getType().name()); - } catch (JSONException e) { - // - } - EngagementModule.engageInternal(fragment.getContext(), interaction, MessageCenterInteraction.EVENT_NAME_READ, data.toString()); - - MessageManager mgr = ApptentiveInternal.getInstance().getMessageManager(); - if (mgr != null) { - mgr.updateMessage(textMessages[0]); - mgr.notifyHostUnreadMessagesListeners(mgr.getUnreadMessageCount()); - } - return null; - } - - @Override - protected void onCancelled() { - positionsWithPendingUpdateTask.remove(Integer.valueOf(position)); - } - - @Override - protected void onPostExecute(Void result) { - positionsWithPendingUpdateTask.remove(Integer.valueOf(position)); - } - - } - - private void startLoadAttachedImageTask(CompoundMessage message, int position, OutgoingCompoundMessageHolder holder) { - List storedFiles = message.getAssociatedFiles(); - if (storedFiles == null || storedFiles.size() == 0) { - return; - } - for (int i = 0; i < storedFiles.size(); i++) { - StoredFile storedFile = storedFiles.get(i); - String mimeType = storedFile.getMimeType(); - String imagePath; - - if (mimeType != null) { - imagePath = storedFile.getLocalFilePath(); - if (mimeType.contains("image")) { - //holder.image.setVisibility(View.INVISIBLE); - - Point dimensions = getBitmapDimensions(storedFile); - if (dimensions != null) { - //holder.image.setPadding(dimensions.x, dimensions.y, 0, 0); - } - } - LoadAttachedImageTask task = new LoadAttachedImageTask(position, holder); - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB) { - task.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR, imagePath); - } else { - task.execute(imagePath); - } - } - } - } - - private class LoadAttachedImageTask extends AsyncTask { - private int position; - private WeakReference holderRef; - - public LoadAttachedImageTask(int position, OutgoingCompoundMessageHolder holder) { - this.position = position; - this.holderRef = new WeakReference(holder); - } - - @Override - protected Bitmap doInBackground(String... paths) { - Bitmap imageBitmap = null; - try { - Point point = Util.getScreenSize(fragment.getContext().getApplicationContext()); - int maxImageWidth = (int) (MAX_IMAGE_SCREEN_PROPORTION_X * point.x); - int maxImageHeight = (int) (MAX_IMAGE_SCREEN_PROPORTION_Y * point.x); - maxImageWidth = maxImageWidth > MAX_IMAGE_DISPLAY_WIDTH ? MAX_IMAGE_DISPLAY_WIDTH : maxImageWidth; - maxImageHeight = maxImageHeight > MAX_IMAGE_DISPLAY_HEIGHT ? MAX_IMAGE_DISPLAY_HEIGHT : maxImageHeight; - // Loading image from File Store. Pass 0 for orientation because images have been rotated when stored - imageBitmap = ImageUtil.createScaledBitmapFromLocalImageSource(paths[0], maxImageWidth, maxImageHeight, null, 0); - ApptentiveLog.v("Loaded bitmap and re-sized to: %d x %d", imageBitmap.getWidth(), imageBitmap.getHeight()); - } catch (Exception e) { - ApptentiveLog.e("Error opening stored image.", e); - } catch (OutOfMemoryError e) { - // It's generally not a good idea to catch an OutOfMemoryException. But in this case, the OutOfMemoryException - // had to result from allocating a bitmap, so the system should be in a good state. - // TODO: ApptentiveLog an event to the server so we know an OutOfMemoryException occurred. - ApptentiveLog.e("Ran out of memory opening image.", e); - } - return imageBitmap; - } - - @Override - protected void onCancelled() { - } - - @Override - protected void onPostExecute(Bitmap bitmap) { - if (null == bitmap) { - return; - } - OutgoingCompoundMessageHolder holder = holderRef.get(); -/* - if (holder != null && holder.position == position) { - //Todo: load image into imageview - } -*/ - } - } - -} diff --git a/apptentive/src/main/java/com/apptentive/android/sdk/module/messagecenter/view/MessageCenterComposingActionBarView.java b/apptentive/src/main/java/com/apptentive/android/sdk/module/messagecenter/view/MessageCenterComposingActionBarView.java deleted file mode 100644 index 052cdc8dd..000000000 --- a/apptentive/src/main/java/com/apptentive/android/sdk/module/messagecenter/view/MessageCenterComposingActionBarView.java +++ /dev/null @@ -1,128 +0,0 @@ -/* - * Copyright (c) 2016, Apptentive, Inc. All Rights Reserved. - * Please refer to the LICENSE file for the terms and conditions - * under which redistribution and use of this file is permitted. - */ - -package com.apptentive.android.sdk.module.messagecenter.view; - -import android.content.res.ColorStateList; -import android.graphics.drawable.Drawable; -import android.os.Build; -import android.os.Bundle; - -import android.support.v4.app.Fragment; -import android.support.v4.content.ContextCompat; -import android.support.v4.graphics.drawable.DrawableCompat; -import android.view.LayoutInflater; -import android.view.View; -import android.widget.FrameLayout; -import android.widget.ImageButton; -import android.widget.TextView; - -import com.apptentive.android.sdk.ApptentiveLog; -import com.apptentive.android.sdk.R; -import com.apptentive.android.sdk.module.messagecenter.model.MessageCenterComposingItem; -import com.apptentive.android.sdk.util.Constants; -import com.apptentive.android.sdk.util.Util; -import com.apptentive.android.sdk.view.ApptentiveAlertDialog; - -import java.lang.ref.WeakReference; - - -public class MessageCenterComposingActionBarView extends FrameLayout implements MessageCenterListItemView { - - public boolean showConfirmation = false; - public ImageButton sendButton; - public ImageButton attachButton; - private WeakReference listenerRef; - - public MessageCenterComposingActionBarView(final Fragment fragment, final MessageCenterComposingItem item, final MessageAdapter.OnListviewItemActionListener listener) { - super(fragment.getContext()); - this.listenerRef = new WeakReference(listener); - - LayoutInflater inflater = fragment.getActivity().getLayoutInflater(); - - try { - inflater.inflate(R.layout.apptentive_message_center_composing_actionbar, this); - } catch (Exception e) { - ApptentiveLog.e("Error:", e); - } - - ColorStateList colors = ContextCompat.getColorStateList(getContext(), Util.getResourceIdFromAttribute(getContext().getTheme(), R.attr.apptentiveButtonTintColorStateList)); - - ImageButton closeButton = (ImageButton) findViewById(R.id.cancel_composing); - // Use a color state list for button tint state on Lollipop. On prior platforms, need to apply state color manually. - Drawable closeButtonDrawable = DrawableCompat.wrap(closeButton.getDrawable()); - DrawableCompat.setTintList(closeButtonDrawable, colors); - closeButton.setImageDrawable(closeButtonDrawable); - - closeButton.setOnClickListener(new OnClickListener() { - public void onClick(View view) { - MessageAdapter.OnListviewItemActionListener locallistener = listenerRef.get(); - if (locallistener == null) { - return; - } - if (showConfirmation) { - Bundle bundle = new Bundle(); - bundle.putString("message", item.str_2); - bundle.putString("positive", item.str_3); - bundle.putString("negative", item.str_4); - ApptentiveAlertDialog.show(fragment, bundle, Constants.REQUEST_CODE_CLOSE_COMPOSING_CONFIRMATION); - } else { - locallistener.onCancelComposing(); - } - } - }); - - TextView composing = (TextView) findViewById(R.id.composing); - - if (item.str_1 != null) { - composing.setText(item.str_1); - } - - sendButton = (ImageButton) findViewById(R.id.btn_send_message); - // Use a color state list for button tint state on Lollipop. On prior platforms, need to apply state color manually. - Drawable sendButtonDrawable = DrawableCompat.wrap(sendButton.getDrawable()); - DrawableCompat.setTintList(sendButtonDrawable, colors); - sendButton.setImageDrawable(sendButtonDrawable); - if (Build.VERSION.SDK_INT < Build.VERSION_CODES.LOLLIPOP) { - sendButton.setColorFilter(Util.getThemeColor(fragment.getContext(), R.attr.apptentiveButtonTintColorDisabled)); - } - sendButton.setEnabled(false); - if (item.button_1 != null) { - sendButton.setContentDescription(item.button_1); - } - sendButton.setOnClickListener(new OnClickListener() { - public void onClick(View view) { - MessageAdapter.OnListviewItemActionListener locallistener = listenerRef.get(); - if (locallistener == null) { - return; - } - locallistener.onFinishComposing(); - } - }); - - attachButton = (ImageButton) findViewById(R.id.btn_attach_image); - // Use a color state list for button tint state on Lollipop. On prior platforms, need to apply state color manually. - Drawable attachButtonDrawable = DrawableCompat.wrap(attachButton.getDrawable()); - DrawableCompat.setTintList(attachButtonDrawable, colors); - attachButton.setImageDrawable(attachButtonDrawable); - - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.ICE_CREAM_SANDWICH) { - attachButton.setOnClickListener(new View.OnClickListener() { - public void onClick(View view) { - MessageAdapter.OnListviewItemActionListener locallistener = listenerRef.get(); - if (locallistener == null) { - return; - } - locallistener.onAttachImage(); - } - }); - } else { - attachButton.setVisibility(GONE); - } - } - - -} \ No newline at end of file diff --git a/apptentive/src/main/java/com/apptentive/android/sdk/module/messagecenter/view/MessageCenterComposingView.java b/apptentive/src/main/java/com/apptentive/android/sdk/module/messagecenter/view/MessageCenterComposingView.java deleted file mode 100644 index 6a840ff95..000000000 --- a/apptentive/src/main/java/com/apptentive/android/sdk/module/messagecenter/view/MessageCenterComposingView.java +++ /dev/null @@ -1,211 +0,0 @@ -/* - * Copyright (c) 2015, Apptentive, Inc. All Rights Reserved. - * Please refer to the LICENSE file for the terms and conditions - * under which redistribution and use of this file is permitted. - */ - -package com.apptentive.android.sdk.module.messagecenter.view; - -import android.support.v4.app.Fragment; -import android.text.Editable; - -import android.text.Layout; -import android.text.Selection; -import android.text.Spannable; -import android.text.TextWatcher; -import android.text.method.ArrowKeyMovementMethod; -import android.text.method.MovementMethod; -import android.text.style.ClickableSpan; -import android.text.util.Linkify; -import android.view.LayoutInflater; -import android.view.MotionEvent; -import android.view.View; -import android.widget.EditText; -import android.widget.FrameLayout; -import android.widget.TextView; - - -import com.apptentive.android.sdk.R; -import com.apptentive.android.sdk.module.messagecenter.model.MessageCenterComposingItem; -import com.apptentive.android.sdk.util.image.ApptentiveImageGridView; -import com.apptentive.android.sdk.util.image.ImageGridViewAdapter; -import com.apptentive.android.sdk.util.image.ImageItem; - -import java.util.ArrayList; -import java.util.List; - - -/** - * @author Barry Li - */ -public class MessageCenterComposingView extends FrameLayout implements MessageCenterListItemView { - - private EditText et; - // Image Band - private ApptentiveImageGridView imageBandView; - List images = new ArrayList(); - - public MessageCenterComposingView(Fragment fragment) { - super(fragment.getContext()); - -/* - LayoutInflater inflater = fragment.getActivity().getLayoutInflater(); - View parentView = inflater.inflate(R.layout.apptentive_message_center_composing_area, this); - et = (EditText) parentView.findViewById(R.id.composing_et); - if (item.str_2 != null) { - et.setHint(item.str_2); - } - et.setLinksClickable(true); - et.setAutoLinkMask(Linkify.WEB_URLS | Linkify.PHONE_NUMBERS | Linkify.EMAIL_ADDRESSES | Linkify.MAP_ADDRESSES); - *//* - * LinkMovementMethod would enable clickable links in EditView, but disables copy/paste through Long Press. - * Use a custom MovementMethod instead - * - *//* - et.setMovementMethod(ApptentiveMovementMethod.getInstance()); - //If the edit text contains previous text with potential links - Linkify.addLinks(et, Linkify.WEB_URLS); - - et.addTextChangedListener(new TextWatcher() { - @Override - public void beforeTextChanged(CharSequence charSequence, int i, int i2, int i3) { - listener.beforeComposingTextChanged(charSequence); - } - - @Override - public void onTextChanged(CharSequence charSequence, int start, int before, int count) { - listener.onComposingTextChanged(charSequence); - } - - @Override - public void afterTextChanged(Editable editable) { - listener.afterComposingTextChanged(editable.toString()); - Linkify.addLinks(editable, Linkify.WEB_URLS | Linkify.PHONE_NUMBERS | Linkify.EMAIL_ADDRESSES | Linkify.MAP_ADDRESSES); - } - }); - - - imageBandView = (ApptentiveImageGridView) parentView.findViewById(R.id.grid); - imageBandView.setupUi(); - imageBandView.setupLayoutListener(); - imageBandView.setListener(new ApptentiveImageGridView.ImageItemClickedListener() { - @Override - public void onClick(int position, ImageItem image) { - listener.onClickAttachment(position, image); - } - }); - imageBandView.setAdapterIndicator(R.drawable.apptentive_ic_remove_attachment); - - imageBandView.setImageIndicatorCallback((ImageGridViewAdapter.Callback) listener); - // Initialize image attachments band with empty data - clearImageAttachmentBand(); -*/ - } - - public EditText getEditText() { - return et; - } - - /** - * Remove all images from attchment band. - */ - public void clearImageAttachmentBand() { - imageBandView.setVisibility(View.GONE); - images.clear(); - - imageBandView.setData(images); - } - - /** - * Add new images to attchment band. - * - * @param imagesToAttach an array of new images to add - */ - public void addImagesToImageAttachmentBand(final List imagesToAttach) { - - if (imagesToAttach == null || imagesToAttach.size() == 0) { - return; - } - - imageBandView.setupLayoutListener(); - imageBandView.setVisibility(View.VISIBLE); - - images.addAll(imagesToAttach); - addAdditionalAttchItem(); - } - - /** - * Remove an image from attchment band. - * - * @param position the postion index of the image to be removed - */ - public void removeImageFromImageAttachmentBand(final int position) { - images.remove(position); - imageBandView.setupLayoutListener(); - if (images.size() == 0) { - // Hide attachment band after last attachment is removed - imageBandView.setVisibility(View.GONE); - return; - } - addAdditionalAttchItem(); - } - - private void addAdditionalAttchItem() { - ArrayList imagesToAdd = new ArrayList(images); - if (imagesToAdd.size() < getResources().getInteger(R.integer.apptentive_image_grid_default_attachments_total)) { - imagesToAdd.add(new ImageItem("", "", "Image/*", 0)); - } - imageBandView.setData(imagesToAdd); - } - /* - * Extends Android default movement method to enable selecting text and openning the links at the same time - */ - private static class ApptentiveMovementMethod extends ArrowKeyMovementMethod { - - private static ApptentiveMovementMethod sInstance; - - public static MovementMethod getInstance() { - if (sInstance == null) { - sInstance = new ApptentiveMovementMethod(); - } - return sInstance; - } - - @Override - public boolean onTouchEvent(TextView widget, Spannable buffer, MotionEvent event) { - int action = event.getAction(); - - if (action == MotionEvent.ACTION_UP || - action == MotionEvent.ACTION_DOWN) { - int x = (int) event.getX(); - int y = (int) event.getY(); - - x -= widget.getTotalPaddingLeft(); - y -= widget.getTotalPaddingTop(); - - x += widget.getScrollX(); - y += widget.getScrollY(); - - Layout layout = widget.getLayout(); - int line = layout.getLineForVertical(y); - int off = layout.getOffsetForHorizontal(line, x); - - ClickableSpan[] link = buffer.getSpans(off, off, ClickableSpan.class); - - if (link.length != 0) { - if (action == MotionEvent.ACTION_UP) { - link[0].onClick(widget); - } else if (action == MotionEvent.ACTION_DOWN) { - Selection.setSelection(buffer, buffer.getSpanStart(link[0]), buffer.getSpanEnd(link[0])); - } - - return true; - } - - } - - return super.onTouchEvent(widget, buffer, event); - } - - } -} \ No newline at end of file diff --git a/apptentive/src/main/java/com/apptentive/android/sdk/module/messagecenter/view/MessageCenterGreetingView.java b/apptentive/src/main/java/com/apptentive/android/sdk/module/messagecenter/view/MessageCenterGreetingView.java deleted file mode 100644 index 4ff905d0a..000000000 --- a/apptentive/src/main/java/com/apptentive/android/sdk/module/messagecenter/view/MessageCenterGreetingView.java +++ /dev/null @@ -1,64 +0,0 @@ -/* - * Copyright (c) 2016, Apptentive, Inc. All Rights Reserved. - * Please refer to the LICENSE file for the terms and conditions - * under which redistribution and use of this file is permitted. - */ - -package com.apptentive.android.sdk.module.messagecenter.view; - -import android.content.Context; -import android.os.Handler; -import android.os.Message; -import android.view.LayoutInflater; -import android.view.View; -import android.widget.FrameLayout; -import android.widget.ImageButton; -import android.widget.TextView; - -import com.apptentive.android.sdk.ApptentiveInternal; -import com.apptentive.android.sdk.R; -import com.apptentive.android.sdk.module.messagecenter.model.MessageCenterGreeting; -import com.apptentive.android.sdk.util.Util; - -public class MessageCenterGreetingView extends FrameLayout implements MessageCenterListItemView { - - public ApptentiveAvatarView avatar; - - // Prevent info button being clicked multiple time, resulting multiple About - protected static final int DELAY_TIME = 100; - - protected Handler mClickHandler = new Handler() { - - public void handleMessage(Message msg) { - - findViewById(msg.what).setClickable(true); - super.handleMessage(msg); - } - }; - - public MessageCenterGreetingView(final Context context, MessageCenterGreeting messageCenterGreeting) { - super(context); - - LayoutInflater inflater = LayoutInflater.from(context); - View view = inflater.inflate(R.layout.apptentive_message_center_greeting, this); - TextView title = (TextView) view.findViewById(R.id.greeting_title); - TextView body = (TextView) view.findViewById(R.id.greeting_body); - if (title != null) { - title.setText(messageCenterGreeting.title); - } - if (body != null) { - body.setText(messageCenterGreeting.body); - } - - avatar = (ApptentiveAvatarView) view.findViewById(R.id.avatar); - - ImageButton infoButton = (ImageButton) findViewById(R.id.btn_info); - infoButton.setOnClickListener(new OnClickListener() { - public void onClick(View view) { - view.setClickable(false); - mClickHandler.sendEmptyMessageDelayed(view.getId(), DELAY_TIME); - ApptentiveInternal.getInstance().showAboutInternal(Util.castContextToActivity(context), false); - } - }); - } -} diff --git a/apptentive/src/main/java/com/apptentive/android/sdk/module/messagecenter/view/MessageCenterListView.java b/apptentive/src/main/java/com/apptentive/android/sdk/module/messagecenter/view/MessageCenterListView.java deleted file mode 100644 index 68a4395c9..000000000 --- a/apptentive/src/main/java/com/apptentive/android/sdk/module/messagecenter/view/MessageCenterListView.java +++ /dev/null @@ -1,455 +0,0 @@ -/* - * Copyright (c) 2015, Apptentive, Inc. All Rights Reserved. - * Please refer to the LICENSE file for the terms and conditions - * under which redistribution and use of this file is permitted. - */ -package com.apptentive.android.sdk.module.messagecenter.view; - -import android.content.Context; -import android.database.DataSetObserver; -import android.graphics.Canvas; -import android.graphics.PointF; -import android.graphics.Rect; -import android.graphics.drawable.GradientDrawable; -import android.os.Parcelable; -import android.support.v4.content.ContextCompat; -import android.util.AttributeSet; -import android.view.MotionEvent; -import android.view.View; -import android.view.ViewConfiguration; -import android.view.ViewGroup; -import android.widget.AbsListView; - -import android.widget.HeaderViewListAdapter; -import android.widget.ListAdapter; -import android.widget.ListView; - -import com.apptentive.android.sdk.R; - - -public class MessageCenterListView extends ListView { - - public interface ApptentiveMessageCenterListAdapter extends ListAdapter { - /** - * True if views of given type will be sticky at the top - */ - boolean isItemSticky(int viewType); - } - - /** - * Wrapper class for sticky view and its position in the list. - */ - static class StickyWrapper { - public View view; - public int position; - public long id; - public int additionalIndent; - } - - private final Rect touchRect = new Rect(); - private final PointF touchPt = new PointF(); - private int touchSlop; - private View touchTarget; - private MotionEvent downEvent; - - // fields used for drawing shadow under the sticky header - private GradientDrawable shadowDrawable; - private int shadowHeight; - - // Optional delegating listener - OnScrollListener delegateScrollListener; - - // shadow for being recycled - StickyWrapper recycledHeaderView; - - /** - * shadow instance with a sticky view, can be null. - */ - StickyWrapper stickyWrapper; - - private OnListviewResizeListener resizeListener; - /** - * Scroll listener - */ - private final OnScrollListener mOnScrollListener = new OnScrollListener() { - - @Override - public void onScrollStateChanged(AbsListView view, int scrollState) { - if (delegateScrollListener != null) { - delegateScrollListener.onScrollStateChanged(view, scrollState); - } - } - - @Override - public void onScroll(AbsListView view, int firstVisibleItem, int visibleItemCount, int totalItemCount) { - - if (delegateScrollListener != null) { - delegateScrollListener.onScroll(view, firstVisibleItem, visibleItemCount, totalItemCount); - } - - ListAdapter adapter = getAdapter(); - if (adapter == null || visibleItemCount == 0) return; // nothing to do - - final boolean isFirstVisibleItemHeader = - isItemSticky(adapter, adapter.getItemViewType(firstVisibleItem)); - - if (isFirstVisibleItemHeader) { - View headerView = getChildAt(0); - int headerTop = headerView.getTop(); - int pad = getPaddingTop(); - if (headerTop == pad) { - // view sticks to the top, do not render shadow - destroyStickyShadow(); - } else { - tryCreateShadowAtPosition(firstVisibleItem, firstVisibleItem, visibleItemCount); - } - - } else { - // header is not at the first visible position - int headerPosition = findCurrentHeaderPosition(firstVisibleItem); - if (headerPosition > -1) { - tryCreateShadowAtPosition(headerPosition, firstVisibleItem, visibleItemCount); - } else { // there is no section for the first visible item, destroy shadow - destroyStickyShadow(); - } - } - } - - }; - - /** - * Default change observer. - */ - private final DataSetObserver dataSetObserver = new DataSetObserver() { - @Override - public void onChanged() { - recreateStickyShadow(); - } - - @Override - public void onInvalidated() { - recreateStickyShadow(); - } - }; - - public interface OnListviewResizeListener { - void OnListViewResize(int w, int h, int oldw, int oldh); - } - - public void setOnListViewResizeListener(OnListviewResizeListener l) { - resizeListener = l; - } - - public MessageCenterListView(Context context, AttributeSet attrs) { - super(context, attrs); - initView(); - } - - public MessageCenterListView(Context context, AttributeSet attrs, int defStyle) { - super(context, attrs, defStyle); - initView(); - } - - private void initView() { - setOnScrollListener(mOnScrollListener); - touchSlop = ViewConfiguration.get(getContext()).getScaledTouchSlop(); - initShadow(true); - } - - - public void initShadow(boolean visible) { - if (visible) { - if (shadowDrawable == null) { - shadowDrawable = (GradientDrawable) ContextCompat.getDrawable(getContext(), R.drawable.apptentive_listview_item_shadow); - shadowHeight = (int) (4 * getResources().getDisplayMetrics().density); - } - } else { - if (shadowDrawable != null) { - shadowDrawable = null; - shadowHeight = 0; - } - } - } - - /** - * Create shadow wrapper with a sticky view at given position - */ - void createStickyShadow(int position) { - - // recycle shadow - StickyWrapper stickyViewShadow = recycledHeaderView; - recycledHeaderView = null; - - // create new shadow, if needed - if (stickyViewShadow == null) { - stickyViewShadow = new StickyWrapper(); - } - // request new view using recycled view, if such - View stickyView = getAdapter().getView(position, stickyViewShadow.view, MessageCenterListView.this); - - // read layout parameters - LayoutParams layoutParams = (LayoutParams) stickyView.getLayoutParams(); - if (layoutParams == null) { - layoutParams = (LayoutParams) generateDefaultLayoutParams(); - stickyView.setLayoutParams(layoutParams); - } - - View childLayout = ((ViewGroup) stickyView).getChildAt(0); - int heightMode = MeasureSpec.getMode(layoutParams.height); - int heightSize = MeasureSpec.getSize(layoutParams.height); - - if (heightMode == MeasureSpec.UNSPECIFIED) { - heightMode = MeasureSpec.EXACTLY; - } - - int maxHeight = getHeight() - getListPaddingTop() - getListPaddingBottom(); - if (heightSize > maxHeight) { - heightSize = maxHeight; - } - // assuming left and right additional paddings are the same - int ws = MeasureSpec.makeMeasureSpec(getWidth() - getListPaddingLeft() - getListPaddingRight(), MeasureSpec.EXACTLY); - int hs = MeasureSpec.makeMeasureSpec(heightSize, heightMode); - stickyView.measure(ws, hs); - stickyView.layout(0, 0, stickyView.getMeasuredWidth(), stickyView.getMeasuredHeight()); - - // initialize shadow - stickyViewShadow.view = stickyView; - stickyViewShadow.position = position; - stickyViewShadow.id = getAdapter().getItemId(position); - stickyViewShadow.additionalIndent = childLayout.getPaddingLeft(); - - stickyWrapper = stickyViewShadow; - } - - /** - * Destroy shadow wrapper for current sticky view - */ - void destroyStickyShadow() { - if (stickyWrapper != null) { - // keep shadow for being recycled later - recycledHeaderView = stickyWrapper; - stickyWrapper = null; - } - } - - /** - * Create sticky shadowded view at a given item position. - */ - void tryCreateShadowAtPosition(int headerPosition, int firstVisibleItem, int visibleItemCount) { - if (visibleItemCount < 1) { - // no need for creating shadow if no visible item - destroyStickyShadow(); - return; - } - - if (stickyWrapper != null - && stickyWrapper.position != headerPosition) { - // invalidate shadow, if required - destroyStickyShadow(); - } - - if (stickyWrapper == null) { - createStickyShadow(headerPosition); - } - - } - - - int findCurrentHeaderPosition(int fromPosition) { - ListAdapter adapter = getAdapter(); - - if (fromPosition >= adapter.getCount()) return -1; // dataset has changed, no candidate - - // Only need to look through to the next section item above - for (int position = fromPosition; position >= 0; position--) { - int viewType = adapter.getItemViewType(position); - if (isItemSticky(adapter, viewType)) return position; - } - return -1; - } - - void recreateStickyShadow() { - destroyStickyShadow(); - ListAdapter adapter = getAdapter(); - if (adapter != null && adapter.getCount() > 0) { - int firstVisiblePosition = getFirstVisiblePosition(); - int headerPosition = findCurrentHeaderPosition(firstVisiblePosition); - if (headerPosition == -1) { - return; - } - tryCreateShadowAtPosition(headerPosition, - firstVisiblePosition, getLastVisiblePosition() - firstVisiblePosition + 1); - } - } - - @Override - public void setOnScrollListener(OnScrollListener listener) { - if (listener == mOnScrollListener) { - super.setOnScrollListener(listener); - } else { - delegateScrollListener = listener; - } - } - - @Override - public void onRestoreInstanceState(Parcelable state) { - super.onRestoreInstanceState(state); - post(new Runnable() { - @Override - public void run() { - // restore view after configuration change - recreateStickyShadow(); - } - }); - } - - @Override - public void setAdapter(ListAdapter adapter) { - // unregister observer at old adapter and register on new one - ListAdapter oldAdapter = getAdapter(); - if (oldAdapter != null) { - oldAdapter.unregisterDataSetObserver(dataSetObserver); - } - if (adapter != null) { - adapter.registerDataSetObserver(dataSetObserver); - } - - if (oldAdapter != adapter) { - destroyStickyShadow(); - } - - super.setAdapter(adapter); - } - - @Override - protected void onLayout(boolean changed, int l, int t, int r, int b) { - super.onLayout(changed, l, t, r, b); - if (stickyWrapper != null) { - int parentWidth = r - l - getPaddingLeft() - getPaddingRight(); - int shadowWidth = stickyWrapper.view.getWidth(); - if (parentWidth != shadowWidth) { - recreateStickyShadow(); - } - } - } - - @Override - protected void onSizeChanged(int w, int h, int oldw, int oldh) { - super.onSizeChanged(w, h, oldw, oldh); - if (resizeListener != null) { - resizeListener.OnListViewResize(w, h, oldw, oldh); - } - } - - @Override - protected void dispatchDraw(Canvas canvas) { - super.dispatchDraw(canvas); - - if (stickyWrapper != null) { - - int pLeft = getListPaddingLeft(); - int pTop = getListPaddingTop(); - View view = stickyWrapper.view; - int headerTop = view.getTop(); - pLeft += stickyWrapper.additionalIndent; - // draw child - canvas.save(); - - int clipHeight = view.getHeight() + - (shadowDrawable == null ? 0 : shadowHeight); - canvas.clipRect(pLeft, pTop, pLeft + view.getWidth() - 2 * stickyWrapper.additionalIndent, pTop + clipHeight); - - canvas.translate(pLeft - stickyWrapper.additionalIndent, pTop - headerTop); - drawChild(canvas, stickyWrapper.view, getDrawingTime()); - - if (shadowDrawable != null) { - shadowDrawable.setBounds(stickyWrapper.view.getLeft(), - stickyWrapper.view.getBottom(), - stickyWrapper.view.getRight(), - stickyWrapper.view.getBottom() + shadowHeight); - shadowDrawable.draw(canvas); - } - - canvas.restore(); - } - } - - - @Override - public boolean dispatchTouchEvent(MotionEvent ev) { - - final float x = ev.getX(); - final float y = ev.getY(); - final int action = ev.getAction(); - - if (action == MotionEvent.ACTION_DOWN - && touchTarget == null - && stickyWrapper != null - && isStickyViewTouched(stickyWrapper.view, x, y)) { - touchTarget = stickyWrapper.view; - touchPt.x = x; - touchPt.y = y; - - downEvent = MotionEvent.obtain(ev); - } - - if (touchTarget != null) { - if (isStickyViewTouched(touchTarget, x, y)) { - // forward event to header view - touchTarget.dispatchTouchEvent(ev); - } - - if (action == MotionEvent.ACTION_UP) { - super.dispatchTouchEvent(ev); - clearTouchTarget(); - - } else if (action == MotionEvent.ACTION_CANCEL) { - clearTouchTarget(); - - } else if (action == MotionEvent.ACTION_MOVE) { - if (Math.abs(y - touchPt.y) > touchSlop) { - - MotionEvent event = MotionEvent.obtain(ev); - event.setAction(MotionEvent.ACTION_CANCEL); - touchTarget.dispatchTouchEvent(event); - event.recycle(); - - super.dispatchTouchEvent(downEvent); - super.dispatchTouchEvent(ev); - clearTouchTarget(); - - } - } - - return true; - } - - return super.dispatchTouchEvent(ev); - } - - private boolean isStickyViewTouched(View view, float x, float y) { - view.getHitRect(touchRect); - - touchRect.bottom += getPaddingTop() - view.getTop(); - touchRect.left += getPaddingLeft(); - touchRect.right -= getPaddingRight(); - return touchRect.contains((int) x, (int) y); - } - - private void clearTouchTarget() { - touchTarget = null; - if (downEvent != null) { - downEvent.recycle(); - downEvent = null; - } - } - - - public static boolean isItemSticky(ListAdapter adapter, int viewType) { - if (adapter instanceof HeaderViewListAdapter) { - adapter = ((HeaderViewListAdapter) adapter).getWrappedAdapter(); - } - return ((ApptentiveMessageCenterListAdapter) adapter).isItemSticky(viewType); - } - -} \ No newline at end of file diff --git a/apptentive/src/main/java/com/apptentive/android/sdk/module/messagecenter/view/MessageCenterStatusView.java b/apptentive/src/main/java/com/apptentive/android/sdk/module/messagecenter/view/MessageCenterStatusView.java deleted file mode 100644 index 22e3d6bad..000000000 --- a/apptentive/src/main/java/com/apptentive/android/sdk/module/messagecenter/view/MessageCenterStatusView.java +++ /dev/null @@ -1,35 +0,0 @@ -/* - * Copyright (c) 2015, Apptentive, Inc. All Rights Reserved. - * Please refer to the LICENSE file for the terms and conditions - * under which redistribution and use of this file is permitted. - */ - -package com.apptentive.android.sdk.module.messagecenter.view; - -import android.content.Context; -import android.view.LayoutInflater; -import android.view.View; -import android.widget.FrameLayout; -import android.widget.ImageView; -import android.widget.TextView; - -import com.apptentive.android.sdk.R; - -/** - * @author Barry Li - */ -public class MessageCenterStatusView extends FrameLayout implements MessageCenterListItemView { - - public TextView bodyTextView; - public ImageView iconImageView; - - public MessageCenterStatusView(Context context) { - super(context); - - LayoutInflater inflater = LayoutInflater.from(context); - View view = inflater.inflate(R.layout.apptentive_message_center_status, this); - bodyTextView = (TextView) view.findViewById(R.id.body); - iconImageView = (ImageView) view.findViewById(R.id.icon); - } - -} diff --git a/apptentive/src/main/java/com/apptentive/android/sdk/module/messagecenter/view/MessageCenterWhoCardView.java b/apptentive/src/main/java/com/apptentive/android/sdk/module/messagecenter/view/MessageCenterWhoCardView.java deleted file mode 100644 index 71ba02d69..000000000 --- a/apptentive/src/main/java/com/apptentive/android/sdk/module/messagecenter/view/MessageCenterWhoCardView.java +++ /dev/null @@ -1,183 +0,0 @@ -/* - * Copyright (c) 2015, Apptentive, Inc. All Rights Reserved. - * Please refer to the LICENSE file for the terms and conditions - * under which redistribution and use of this file is permitted. - */ - -package com.apptentive.android.sdk.module.messagecenter.view; - - -import android.support.design.widget.TextInputLayout; -import android.support.v4.app.Fragment; -import android.text.Editable; -import android.text.TextUtils; -import android.text.TextWatcher; -import android.view.LayoutInflater; -import android.view.View; -import android.widget.Button; -import android.widget.EditText; -import android.widget.FrameLayout; -import android.widget.TextView; - - -import com.apptentive.android.sdk.Apptentive; -import com.apptentive.android.sdk.R; -import com.apptentive.android.sdk.module.messagecenter.model.MessageCenterComposingItem; -import com.apptentive.android.sdk.util.Util; - - -/** - * @author Barry Li - */ -public class MessageCenterWhoCardView extends FrameLayout implements MessageCenterListItemView { - - private MessageAdapter.OnListviewItemActionListener listener; - private EditText emailEditText; - private TextInputLayout emailLayout; - private EditText nameEditText; - private TextInputLayout nameLayout; - private TextView title; - private TextView emailExplanation; - private Button skipButton; - private Button sendButton; - - public MessageCenterWhoCardView(final Fragment fragment, final MessageAdapter.OnListviewItemActionListener listener) { - super(fragment.getContext()); - this.listener = listener; - - LayoutInflater inflater = fragment.getActivity().getLayoutInflater(); - View parentView = inflater.inflate(R.layout.apptentive_message_center_who_card, this); - title = (TextView) parentView.findViewById(R.id.who_title); - - sendButton = (Button) parentView.findViewById(R.id.btn_send); - - emailEditText = (EditText) parentView.findViewById(R.id.who_email); - emailLayout = (TextInputLayout) parentView.findViewById(R.id.input_layout_who_email); - - nameEditText = (EditText) parentView.findViewById(R.id.who_name); - nameLayout = (TextInputLayout) parentView.findViewById(R.id.input_layout_who_name); - - emailExplanation = (TextView) parentView.findViewById(R.id.email_explanation); - - skipButton = (Button) parentView.findViewById(R.id.btn_skip); - - } - - /** - * Update Who Card UI under different scenarios, defined in {@link com.apptentive.android.sdk.module.messagecenter.model.MessageCenterComposingItem} - * - * - * @param item The generic object containing the data to update composing view. - * @param name Stored profile name, maybe null - * @param email Stored profile email, maybe null - * @return - */ - public void updateUi(final MessageCenterComposingItem item, String name, String email) { - if (item.str_1 != null) { - title.setText(item.str_1); - } - if (item.str_2 != null) { - nameLayout.setVisibility(VISIBLE); - nameLayout.setHint(item.str_2); - } else { - nameLayout.setVisibility(GONE); - } - if (item.str_3 != null) { - emailLayout.setHint(item.str_3); - } - - if (item.str_4 != null) { - emailExplanation.setVisibility(VISIBLE); - emailExplanation.setText(item.str_4); - } else { - emailExplanation.setVisibility(GONE); - } - - skipButton.setEnabled(true); - skipButton.setActivated(true); - if (item.button_1 == null) { - skipButton.setVisibility(INVISIBLE); - } else { - skipButton.setVisibility(VISIBLE); - skipButton.setText(item.button_1); - skipButton.setOnClickListener(new OnClickListener() { - public void onClick(View view) { - listener.onCloseWhoCard(item.button_1); - } - }); - } - - if (item.button_2 != null) { - sendButton.setText(item.button_2); - sendButton.setActivated(true); - sendButton.setOnClickListener(new OnClickListener() { - public void onClick(View view) { - if (isWhoCardContentValid(item.getType())) { - Apptentive.setPersonEmail(emailEditText.getText().toString().trim()); - Apptentive.setPersonName(nameEditText.getText().toString().trim()); - listener.onSubmitWhoCard(item.button_2); - } - } - }); - } - - nameEditText.setText(name); - - TextWatcher emailTextWatcher = new TextWatcher() { - @Override - public void beforeTextChanged(CharSequence existingContent, int i, int i2, int i3) { - // Disable send button when the content hasn't change yet - if (Util.isEmailValid(existingContent.toString())) { - sendButton.setEnabled(true); - } else { - sendButton.setEnabled(false); - } - } - - @Override - public void onTextChanged(CharSequence charSequence, int start, int before, int count) { - } - - @Override - public void afterTextChanged(Editable editable) { - String emailContent = editable.toString().trim(); - if (Util.isEmailValid(emailContent)) { - // email must be in valid format after the change. If it is, enable send button - sendButton.setEnabled(true); - } else - // Allow user remove email completely when editing prifle of "Email Requested" - if (TextUtils.isEmpty(emailContent) && item.getType() >= MessageCenterComposingItem.COMPOSING_ITEM_WHOCARD_REQUESTED_INIT) { - sendButton.setEnabled(true); - } else { - // email not valid after change, so disable the send button - sendButton.setEnabled(false); - } - } - }; - - emailEditText.addTextChangedListener(emailTextWatcher); - emailEditText.setText(email); - - } - - public EditText getNameField() { - return nameEditText; - } - - public EditText getEmailField() { - return emailEditText; - } - - private boolean isWhoCardContentValid(int type) { - String emailContent = emailEditText.getText().toString(); - if (Util.isEmailValid(emailContent)) { - return true; - } - // Allow user only change name but leave email blank if profile is only requested, not required - if (TextUtils.isEmpty(emailContent) && type >= MessageCenterComposingItem.COMPOSING_ITEM_WHOCARD_REQUESTED_INIT) { - return true; - } - return false; - } - -} \ No newline at end of file diff --git a/apptentive/src/main/java/com/apptentive/android/sdk/module/messagecenter/view/PersonalMessageView.java b/apptentive/src/main/java/com/apptentive/android/sdk/module/messagecenter/view/PersonalMessageView.java deleted file mode 100644 index 32913e624..000000000 --- a/apptentive/src/main/java/com/apptentive/android/sdk/module/messagecenter/view/PersonalMessageView.java +++ /dev/null @@ -1,36 +0,0 @@ -/* - * Copyright (c) 2015, Apptentive, Inc. All Rights Reserved. - * Please refer to the LICENSE file for the terms and conditions - * under which redistribution and use of this file is permitted. - */ - -package com.apptentive.android.sdk.module.messagecenter.view; - -import android.content.Context; -import android.view.LayoutInflater; - -import com.apptentive.android.sdk.R; -import com.apptentive.android.sdk.module.messagecenter.model.ApptentiveMessage; - -/** - * @author Sky Kelsey - */ -abstract public class PersonalMessageView extends MessageView { - - public PersonalMessageView(Context context, final T message) { - super(context, message); - } - - /** - * Perform any view initialization here. Make sure to call super.init() first to initialise the parent hierarchy. - */ - protected void init(Context context, T message) { - super.init(context, message); - LayoutInflater inflater = LayoutInflater.from(context); - if (message.isOutgoingMessage()) { - inflater.inflate(R.layout.apptentive_message_outgoing, this); - } else { - inflater.inflate(R.layout.apptentive_message_incoming, this); - } - } -} diff --git a/apptentive/src/main/java/com/apptentive/android/sdk/module/messagecenter/view/ZeroMinSizeDrawable.java b/apptentive/src/main/java/com/apptentive/android/sdk/module/messagecenter/view/ZeroMinSizeDrawable.java deleted file mode 100644 index b23a864f4..000000000 --- a/apptentive/src/main/java/com/apptentive/android/sdk/module/messagecenter/view/ZeroMinSizeDrawable.java +++ /dev/null @@ -1,36 +0,0 @@ -/* - * Copyright (c) 2012, Apptentive, Inc. All Rights Reserved. - * Please refer to the LICENSE file for the terms and conditions - * under which redistribution and use of this file is permitted. - */ - -package com.apptentive.android.sdk.module.messagecenter.view; - -import android.content.res.Resources; -import android.graphics.drawable.BitmapDrawable; - -/** - * This class is a hack that lets you tile a bitmap that is actually larger in either dimension than the view it will - * tile into. - * @author Sky Kelsey - */ -public class ZeroMinSizeDrawable extends BitmapDrawable { - - public ZeroMinSizeDrawable(Resources res, int resId) { - super(res, ((BitmapDrawable)res.getDrawable(resId)).getBitmap()); - } - - public ZeroMinSizeDrawable(Resources res, BitmapDrawable drawable) { - super(res, drawable.getBitmap()); - } - - @Override - public int getMinimumWidth() { - return 0; - } - - @Override - public int getMinimumHeight() { - return 0; - } -} diff --git a/apptentive/src/main/java/com/apptentive/android/sdk/module/messagecenter/view/holder/IncomingCompoundMessageHolder.java b/apptentive/src/main/java/com/apptentive/android/sdk/module/messagecenter/view/holder/IncomingCompoundMessageHolder.java index e63c118dd..07e6a7fe1 100644 --- a/apptentive/src/main/java/com/apptentive/android/sdk/module/messagecenter/view/holder/IncomingCompoundMessageHolder.java +++ b/apptentive/src/main/java/com/apptentive/android/sdk/module/messagecenter/view/holder/IncomingCompoundMessageHolder.java @@ -16,7 +16,6 @@ import com.apptentive.android.sdk.module.engagement.interaction.fragment.MessageCenterFragment; import com.apptentive.android.sdk.module.messagecenter.model.CompoundMessage; import com.apptentive.android.sdk.module.messagecenter.view.ApptentiveAvatarView; -import com.apptentive.android.sdk.module.messagecenter.view.MessageAdapter; import com.apptentive.android.sdk.module.messagecenter.view.MessageCenterRecyclerViewAdapter; import com.apptentive.android.sdk.util.Util; import com.apptentive.android.sdk.util.image.ApptentiveImageGridView; @@ -35,7 +34,6 @@ public class IncomingCompoundMessageHolder extends MessageHolder { private TextView messageBodyView; private TextView nameView; private ApptentiveImageGridView imageBandView; - private MessageAdapter.OnListviewItemActionListener listener; private static final boolean loadAvatar = false; From dc9ce080896fdc05537fa96f145d690acf5afec9 Mon Sep 17 00:00:00 2001 From: skykelsey Date: Tue, 8 Nov 2016 12:20:47 -0800 Subject: [PATCH 060/100] Reformat MC holder and data objects. --- .../model/MessageCenterInteraction.java | 91 ------------------- .../model/ApptentiveMessage.java | 5 +- .../model/ApptentiveToastNotification.java | 2 +- .../messagecenter/model/CompoundMessage.java | 5 +- .../model/MessageCenterComposingItem.java | 58 ------------ .../model/MessageCenterGreeting.java | 8 +- .../model/MessageCenterStatus.java | 5 +- .../model/MessageCenterUtil.java | 12 +-- .../messagecenter/model/MessageFactory.java | 5 +- .../view/holder/GreetingHolder.java | 1 - .../holder/MessageCenterListItemHolder.java | 14 --- 11 files changed, 12 insertions(+), 194 deletions(-) delete mode 100644 apptentive/src/main/java/com/apptentive/android/sdk/module/messagecenter/model/MessageCenterComposingItem.java delete mode 100644 apptentive/src/main/java/com/apptentive/android/sdk/module/messagecenter/view/holder/MessageCenterListItemHolder.java diff --git a/apptentive/src/main/java/com/apptentive/android/sdk/module/engagement/interaction/model/MessageCenterInteraction.java b/apptentive/src/main/java/com/apptentive/android/sdk/module/engagement/interaction/model/MessageCenterInteraction.java index 33d7c3bde..816d6b689 100644 --- a/apptentive/src/main/java/com/apptentive/android/sdk/module/engagement/interaction/model/MessageCenterInteraction.java +++ b/apptentive/src/main/java/com/apptentive/android/sdk/module/engagement/interaction/model/MessageCenterInteraction.java @@ -12,7 +12,6 @@ import com.apptentive.android.sdk.ApptentiveViewActivity; import com.apptentive.android.sdk.R; import com.apptentive.android.sdk.module.messagecenter.model.Composer; -import com.apptentive.android.sdk.module.messagecenter.model.MessageCenterComposingItem; import com.apptentive.android.sdk.module.messagecenter.model.MessageCenterGreeting; import com.apptentive.android.sdk.module.messagecenter.model.MessageCenterStatus; import com.apptentive.android.sdk.module.messagecenter.model.WhoCard; @@ -109,38 +108,6 @@ public String getBranding() { return null; } - public MessageCenterComposingItem getComposerArea() { - InteractionConfiguration configuration = getConfiguration(); - if (configuration == null) { - return null; - } - JSONObject composer = configuration.optJSONObject(KEY_COMPOSER); - return new MessageCenterComposingItem( - MessageCenterComposingItem.COMPOSING_ITEM_AREA, - null, - composer.optString(KEY_COMPOSER_HINT_TEXT, null), - null, - null, - null, - null); - } - - public MessageCenterComposingItem getComposerBar() { - InteractionConfiguration configuration = getConfiguration(); - if (configuration == null) { - return null; - } - JSONObject composer = configuration.optJSONObject(KEY_COMPOSER); - return new MessageCenterComposingItem( - MessageCenterComposingItem.COMPOSING_ITEM_ACTIONBAR, - composer.optString(KEY_COMPOSER_TITLE, null), - composer.optString(KEY_COMPOSER_CLOSE_BODY, null), - composer.optString(KEY_COMPOSER_CLOSE_DISCARD, null), - composer.optString(KEY_COMPOSER_CLOSE_CANCEL, null), - composer.optString(KEY_COMPOSER_SEND_BUTTON, null), - null); - } - public Composer getComposer() { InteractionConfiguration configuration = getConfiguration(); if (configuration == null) { @@ -176,35 +143,6 @@ public boolean getWhoCardRequired() { return profile.optBoolean(KEY_PROFILE_REQUIRE, false); } - public MessageCenterComposingItem getWhoCardInit() { - InteractionConfiguration configuration = getConfiguration(); - if (configuration == null) { - return null; - } - JSONObject profile = configuration.optJSONObject(KEY_PROFILE); - JSONObject profileInitial = profile.optJSONObject(KEY_PROFILE_INIT); - if (profile.optBoolean(KEY_PROFILE_REQUIRE, false)) { - return new MessageCenterComposingItem( - MessageCenterComposingItem.COMPOSING_ITEM_WHOCARD_REQUIRED_INIT, - profileInitial.optString(KEY_PROFILE_INIT_TITLE, null), - // Hide name field if profile is required and never set - null, - profileInitial.optString(KEY_PROFILE_INIT_EMAIL_HINT, null), - profileInitial.optString(KEY_PROFILE_INIT_EMAIL_EXPLANATION, null), - // Hide Skip button - null, - profileInitial.optString(KEY_PROFILE_INIT_SAVE_BUTTON, null)); - } - return new MessageCenterComposingItem( - MessageCenterComposingItem.COMPOSING_ITEM_WHOCARD_REQUESTED_INIT, - profileInitial.optString(KEY_PROFILE_INIT_TITLE, null), - profileInitial.optString(KEY_PROFILE_INIT_NAME_HINT, null), - profileInitial.optString(KEY_PROFILE_INIT_EMAIL_HINT, null), - profileInitial.optString(KEY_PROFILE_INIT_EMAIL_EXPLANATION, null), - profileInitial.optString(KEY_PROFILE_INIT_SKIP_BUTTON, null), - profileInitial.optString(KEY_PROFILE_INIT_SAVE_BUTTON, null)); - } - public JSONObject getProfile() { InteractionConfiguration configuration = getConfiguration(); if (configuration == null) { @@ -222,35 +160,6 @@ public WhoCard getWhoCard() { return null; } - public MessageCenterComposingItem getWhoCardEdit() { - InteractionConfiguration configuration = getConfiguration(); - if (configuration == null) { - return null; - } - JSONObject profile = configuration.optJSONObject(KEY_PROFILE); - JSONObject profileEdit = configuration.optJSONObject(KEY_PROFILE).optJSONObject(KEY_PROFILE_EDIT); - if (profile.optBoolean(KEY_PROFILE_REQUIRE, false)) { - JSONObject profileInitial = profile.optJSONObject(KEY_PROFILE_INIT); - return new MessageCenterComposingItem( - MessageCenterComposingItem.COMPOSING_ITEM_WHOCARD_REQUIRED_EDIT, - profileEdit.optString(KEY_PROFILE_EDIT_TITLE, null), - profileEdit.optString(KEY_PROFILE_EDIT_NAME_HINT, null), - profileInitial.optString(KEY_PROFILE_INIT_EMAIL_HINT, null), // Show "Email(required)" - profileEdit.optString(KEY_PROFILE_EDIT_EMAIL_EXPLANATION, null), - profileEdit.optString(KEY_PROFILE_EDIT_SKIP_BUTTON, null), - profileEdit.optString(KEY_PROFILE_EDIT_SAVE_BUTTON, null)); - } - return new MessageCenterComposingItem( - MessageCenterComposingItem.COMPOSING_ITEM_WHOCARD_REQUESTED_EDIT, - profileEdit.optString(KEY_PROFILE_EDIT_TITLE, null), - profileEdit.optString(KEY_PROFILE_EDIT_NAME_HINT, null), - profileEdit.optString(KEY_PROFILE_EDIT_EMAIL_HINT, null), - profileEdit.optString(KEY_PROFILE_EDIT_EMAIL_EXPLANATION, null), - profileEdit.optString(KEY_PROFILE_EDIT_SKIP_BUTTON, null), - profileEdit.optString(KEY_PROFILE_EDIT_SAVE_BUTTON, null)); - } - - public MessageCenterGreeting getGreeting() { InteractionConfiguration configuration = getConfiguration(); if (configuration == null) { diff --git a/apptentive/src/main/java/com/apptentive/android/sdk/module/messagecenter/model/ApptentiveMessage.java b/apptentive/src/main/java/com/apptentive/android/sdk/module/messagecenter/model/ApptentiveMessage.java index e97898681..8ff549695 100644 --- a/apptentive/src/main/java/com/apptentive/android/sdk/module/messagecenter/model/ApptentiveMessage.java +++ b/apptentive/src/main/java/com/apptentive/android/sdk/module/messagecenter/model/ApptentiveMessage.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, Apptentive, Inc. All Rights Reserved. + * Copyright (c) 2016, Apptentive, Inc. All Rights Reserved. * Please refer to the LICENSE file for the terms and conditions * under which redistribution and use of this file is permitted. */ @@ -14,9 +14,6 @@ import java.util.Map; -/** - * @author Sky Kelsey - */ public abstract class ApptentiveMessage extends ConversationItem implements MessageCenterUtil.MessageCenterListItem { public static final String KEY_ID = "id"; diff --git a/apptentive/src/main/java/com/apptentive/android/sdk/module/messagecenter/model/ApptentiveToastNotification.java b/apptentive/src/main/java/com/apptentive/android/sdk/module/messagecenter/model/ApptentiveToastNotification.java index 7dda2fe45..1b595b07a 100644 --- a/apptentive/src/main/java/com/apptentive/android/sdk/module/messagecenter/model/ApptentiveToastNotification.java +++ b/apptentive/src/main/java/com/apptentive/android/sdk/module/messagecenter/model/ApptentiveToastNotification.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, Apptentive, Inc. All Rights Reserved. + * Copyright (c) 2016, Apptentive, Inc. All Rights Reserved. * Please refer to the LICENSE file for the terms and conditions * under which redistribution and use of this file is permitted. */ diff --git a/apptentive/src/main/java/com/apptentive/android/sdk/module/messagecenter/model/CompoundMessage.java b/apptentive/src/main/java/com/apptentive/android/sdk/module/messagecenter/model/CompoundMessage.java index 59e62eace..672587b8d 100644 --- a/apptentive/src/main/java/com/apptentive/android/sdk/module/messagecenter/model/CompoundMessage.java +++ b/apptentive/src/main/java/com/apptentive/android/sdk/module/messagecenter/model/CompoundMessage.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, Apptentive, Inc. All Rights Reserved. + * Copyright (c) 2016, Apptentive, Inc. All Rights Reserved. * Please refer to the LICENSE file for the terms and conditions * under which redistribution and use of this file is permitted. */ @@ -21,9 +21,6 @@ import java.util.concurrent.ExecutionException; import java.util.concurrent.Future; -/** - * @author Barry Li - */ public class CompoundMessage extends ApptentiveMessage implements MessageCenterUtil.CompoundMessageCommonInterface { private static final String KEY_BODY = "body"; diff --git a/apptentive/src/main/java/com/apptentive/android/sdk/module/messagecenter/model/MessageCenterComposingItem.java b/apptentive/src/main/java/com/apptentive/android/sdk/module/messagecenter/model/MessageCenterComposingItem.java deleted file mode 100644 index e6510fa74..000000000 --- a/apptentive/src/main/java/com/apptentive/android/sdk/module/messagecenter/model/MessageCenterComposingItem.java +++ /dev/null @@ -1,58 +0,0 @@ -/* - * Copyright (c) 2015, Apptentive, Inc. All Rights Reserved. - * Please refer to the LICENSE file for the terms and conditions - * under which redistribution and use of this file is permitted. - */ - -package com.apptentive.android.sdk.module.messagecenter.model; - -import com.apptentive.android.sdk.ApptentiveLog; - -/** - * @author Sky Kelsey - */ -public class MessageCenterComposingItem implements MessageCenterUtil.MessageCenterListItem { - public static int COMPOSING_ITEM_AREA = 0; - public static int COMPOSING_ITEM_ACTIONBAR = 1; - // Scenarios of presenting Who Card - public static int COMPOSING_ITEM_WHOCARD_REQUIRED_INIT = 2; - public static int COMPOSING_ITEM_WHOCARD_REQUIRED_EDIT = 3; - public static int COMPOSING_ITEM_WHOCARD_REQUESTED_INIT = 4; - public static int COMPOSING_ITEM_WHOCARD_REQUESTED_EDIT = 5; - - public final int type; - /* - * Refer to https://apptentive.atlassian.net/wiki/display/APPTENTIVE/Message+Center+Interaction - * for how following strings are mapped to different composing view strings - */ - public final String str_1; - public final String str_2; - public final String str_3; - public final String str_4; - public final String button_1; - public final String button_2; - - - - public MessageCenterComposingItem(int type, String str_1, String str_2, - String str_3, String str_4, - String button_1, String button_2) { - ApptentiveLog.e("HERE"); - this.type = type; - this.str_1 = str_1; - this.str_2 = str_2; - this.str_3 = str_3; - this.str_4 = str_4; - this.button_1 = button_1; - this.button_2 = button_2; - } - - public int getType() { - return type; - } - - @Override - public int getListItemType() { - return MESSAGE_COMPOSER; - } -} \ No newline at end of file diff --git a/apptentive/src/main/java/com/apptentive/android/sdk/module/messagecenter/model/MessageCenterGreeting.java b/apptentive/src/main/java/com/apptentive/android/sdk/module/messagecenter/model/MessageCenterGreeting.java index d192e87ea..996f84f16 100644 --- a/apptentive/src/main/java/com/apptentive/android/sdk/module/messagecenter/model/MessageCenterGreeting.java +++ b/apptentive/src/main/java/com/apptentive/android/sdk/module/messagecenter/model/MessageCenterGreeting.java @@ -1,17 +1,11 @@ /* - * Copyright (c) 2015, Apptentive, Inc. All Rights Reserved. + * Copyright (c) 2016, Apptentive, Inc. All Rights Reserved. * Please refer to the LICENSE file for the terms and conditions * under which redistribution and use of this file is permitted. */ package com.apptentive.android.sdk.module.messagecenter.model; -import org.json.JSONException; -import org.json.JSONObject; - -/** - * @author Sky Kelsey - */ public class MessageCenterGreeting implements MessageCenterUtil.MessageCenterListItem { public final String title; public final String body; diff --git a/apptentive/src/main/java/com/apptentive/android/sdk/module/messagecenter/model/MessageCenterStatus.java b/apptentive/src/main/java/com/apptentive/android/sdk/module/messagecenter/model/MessageCenterStatus.java index c766cd01f..5737eab99 100644 --- a/apptentive/src/main/java/com/apptentive/android/sdk/module/messagecenter/model/MessageCenterStatus.java +++ b/apptentive/src/main/java/com/apptentive/android/sdk/module/messagecenter/model/MessageCenterStatus.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, Apptentive, Inc. All Rights Reserved. + * Copyright (c) 2016, Apptentive, Inc. All Rights Reserved. * Please refer to the LICENSE file for the terms and conditions * under which redistribution and use of this file is permitted. */ @@ -8,9 +8,6 @@ import org.json.JSONObject; -/** - * @author Sky Kelsey - */ public class MessageCenterStatus extends JSONObject implements MessageCenterUtil.MessageCenterListItem { public final String body; diff --git a/apptentive/src/main/java/com/apptentive/android/sdk/module/messagecenter/model/MessageCenterUtil.java b/apptentive/src/main/java/com/apptentive/android/sdk/module/messagecenter/model/MessageCenterUtil.java index 8071be82d..916354c58 100644 --- a/apptentive/src/main/java/com/apptentive/android/sdk/module/messagecenter/model/MessageCenterUtil.java +++ b/apptentive/src/main/java/com/apptentive/android/sdk/module/messagecenter/model/MessageCenterUtil.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, Apptentive, Inc. All Rights Reserved. + * Copyright (c) 2016, Apptentive, Inc. All Rights Reserved. * Please refer to the LICENSE file for the terms and conditions * under which redistribution and use of this file is permitted. */ @@ -24,12 +24,12 @@ public interface MessageCenterListItem { // Combine both incoming and outgoing interfaces into one public interface CompoundMessageCommonInterface { + void setBody(String body); - public void setBody(String body); - public String getBody(); - public void setLastSent(boolean bVal); - public boolean isLastSent(); + String getBody(); - } + void setLastSent(boolean bVal); + boolean isLastSent(); + } } \ No newline at end of file diff --git a/apptentive/src/main/java/com/apptentive/android/sdk/module/messagecenter/model/MessageFactory.java b/apptentive/src/main/java/com/apptentive/android/sdk/module/messagecenter/model/MessageFactory.java index 5b09a56bc..0e160d268 100644 --- a/apptentive/src/main/java/com/apptentive/android/sdk/module/messagecenter/model/MessageFactory.java +++ b/apptentive/src/main/java/com/apptentive/android/sdk/module/messagecenter/model/MessageFactory.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, Apptentive, Inc. All Rights Reserved. + * Copyright (c) 2016, Apptentive, Inc. All Rights Reserved. * Please refer to the LICENSE file for the terms and conditions * under which redistribution and use of this file is permitted. */ @@ -14,9 +14,6 @@ import org.json.JSONException; import org.json.JSONObject; -/** - * @author Sky Kelsey - */ public class MessageFactory { public static ApptentiveMessage fromJson(String json) { try { diff --git a/apptentive/src/main/java/com/apptentive/android/sdk/module/messagecenter/view/holder/GreetingHolder.java b/apptentive/src/main/java/com/apptentive/android/sdk/module/messagecenter/view/holder/GreetingHolder.java index aa7005e58..6caa7937d 100644 --- a/apptentive/src/main/java/com/apptentive/android/sdk/module/messagecenter/view/holder/GreetingHolder.java +++ b/apptentive/src/main/java/com/apptentive/android/sdk/module/messagecenter/view/holder/GreetingHolder.java @@ -12,7 +12,6 @@ import android.widget.TextView; import com.apptentive.android.sdk.ApptentiveInternal; -import com.apptentive.android.sdk.ApptentiveLog; import com.apptentive.android.sdk.R; import com.apptentive.android.sdk.module.messagecenter.model.MessageCenterGreeting; import com.apptentive.android.sdk.module.messagecenter.view.ApptentiveAvatarView; diff --git a/apptentive/src/main/java/com/apptentive/android/sdk/module/messagecenter/view/holder/MessageCenterListItemHolder.java b/apptentive/src/main/java/com/apptentive/android/sdk/module/messagecenter/view/holder/MessageCenterListItemHolder.java deleted file mode 100644 index 652d35464..000000000 --- a/apptentive/src/main/java/com/apptentive/android/sdk/module/messagecenter/view/holder/MessageCenterListItemHolder.java +++ /dev/null @@ -1,14 +0,0 @@ -/* - * Copyright (c) 2015, Apptentive, Inc. All Rights Reserved. - * Please refer to the LICENSE file for the terms and conditions - * under which redistribution and use of this file is permitted. - */ - -package com.apptentive.android.sdk.module.messagecenter.view.holder; - -/** - * @author Sky Kelsey - */ -public class MessageCenterListItemHolder { - public int position = -1; -} From 2f28265779cc33841ecf2f4f948befe47c6d195c Mon Sep 17 00:00:00 2001 From: skykelsey Date: Tue, 8 Nov 2016 12:35:09 -0800 Subject: [PATCH 061/100] Extract MessageCenterListItem interface into its own file. --- .../fragment/MessageCenterFragment.java | 53 ++++++++++--------- .../module/messagecenter/MessageManager.java | 6 +-- .../model/ApptentiveMessage.java | 2 +- .../module/messagecenter/model/Composer.java | 2 +- .../messagecenter/model/ContextMessage.java | 2 +- .../model/MessageCenterGreeting.java | 2 +- .../model/MessageCenterListItem.java | 20 +++++++ .../model/MessageCenterStatus.java | 2 +- .../model/MessageCenterUtil.java | 14 ----- .../module/messagecenter/model/WhoCard.java | 2 +- .../MessageCenterRecyclerViewAdapter.java | 24 ++++----- 11 files changed, 68 insertions(+), 61 deletions(-) create mode 100644 apptentive/src/main/java/com/apptentive/android/sdk/module/messagecenter/model/MessageCenterListItem.java diff --git a/apptentive/src/main/java/com/apptentive/android/sdk/module/engagement/interaction/fragment/MessageCenterFragment.java b/apptentive/src/main/java/com/apptentive/android/sdk/module/engagement/interaction/fragment/MessageCenterFragment.java index e9168fe45..f5706a6fc 100644 --- a/apptentive/src/main/java/com/apptentive/android/sdk/module/engagement/interaction/fragment/MessageCenterFragment.java +++ b/apptentive/src/main/java/com/apptentive/android/sdk/module/engagement/interaction/fragment/MessageCenterFragment.java @@ -49,6 +49,7 @@ import com.apptentive.android.sdk.module.messagecenter.model.ApptentiveMessage; import com.apptentive.android.sdk.module.messagecenter.model.CompoundMessage; import com.apptentive.android.sdk.module.messagecenter.model.ContextMessage; +import com.apptentive.android.sdk.module.messagecenter.model.MessageCenterListItem; import com.apptentive.android.sdk.module.messagecenter.model.MessageCenterStatus; import com.apptentive.android.sdk.module.messagecenter.model.MessageCenterUtil; import com.apptentive.android.sdk.module.messagecenter.model.WhoCard; @@ -79,11 +80,11 @@ import java.util.ListIterator; import java.util.Set; -import static com.apptentive.android.sdk.module.messagecenter.model.MessageCenterUtil.MessageCenterListItem.MESSAGE_COMPOSER; -import static com.apptentive.android.sdk.module.messagecenter.model.MessageCenterUtil.MessageCenterListItem.MESSAGE_CONTEXT; -import static com.apptentive.android.sdk.module.messagecenter.model.MessageCenterUtil.MessageCenterListItem.MESSAGE_OUTGOING; -import static com.apptentive.android.sdk.module.messagecenter.model.MessageCenterUtil.MessageCenterListItem.STATUS; -import static com.apptentive.android.sdk.module.messagecenter.model.MessageCenterUtil.MessageCenterListItem.WHO_CARD; +import static com.apptentive.android.sdk.module.messagecenter.model.MessageCenterListItem.MESSAGE_COMPOSER; +import static com.apptentive.android.sdk.module.messagecenter.model.MessageCenterListItem.MESSAGE_CONTEXT; +import static com.apptentive.android.sdk.module.messagecenter.model.MessageCenterListItem.MESSAGE_OUTGOING; +import static com.apptentive.android.sdk.module.messagecenter.model.MessageCenterListItem.STATUS; +import static com.apptentive.android.sdk.module.messagecenter.model.MessageCenterListItem.WHO_CARD; public class MessageCenterFragment extends ApptentiveBaseFragment implements OnListviewItemActionListener, @@ -117,7 +118,7 @@ public class MessageCenterFragment extends ApptentiveBaseFragment listItems = new ArrayList(); + private ArrayList listItems = new ArrayList(); private MessageCenterRecyclerViewAdapter messageCenterRecyclerViewAdapter; private MessageCenterRecyclerView messageCenterRecyclerView; @@ -373,7 +374,7 @@ public void onClick(View v) { messageCenterRecyclerViewAdapter = new MessageCenterRecyclerViewAdapter(this, this, interaction, listItems); if (isInitialViewCreation) { - List items = ApptentiveInternal.getInstance().getMessageManager().getMessageCenterListItems(); + List items = ApptentiveInternal.getInstance().getMessageManager().getMessageCenterListItems(); if (items != null) { // Get message list from DB, and use this as the starting point for the listItems array. prepareMessages(items); @@ -415,7 +416,7 @@ else if (pendingWhoCardName != null || pendingWhoCardEmail != null || pendingWho } else { // Need to account for an input view that was added before orientation change, etc. if (listItems != null) { - for (MessageCenterUtil.MessageCenterListItem item : listItems) { + for (MessageCenterListItem item : listItems) { if (item.getListItemType() == MESSAGE_COMPOSER || item.getListItemType() == WHO_CARD) { addedAnInteractiveCard = true; } @@ -630,7 +631,7 @@ public void displayNewIncomingMessageItem(ApptentiveMessage message) { outside_loop: // Starting at end of list, go back up the list to find the proper place to insert the incoming message. for (int i = listItems.size() - 1; i > 0; i--) { - MessageCenterUtil.MessageCenterListItem item = listItems.get(i); + MessageCenterListItem item = listItems.get(i); switch (item.getListItemType()) { case MESSAGE_COMPOSER: case MESSAGE_CONTEXT: @@ -1084,10 +1085,10 @@ public void updateMessageSentStates() { MessageCenterUtil.CompoundMessageCommonInterface lastSent = null; Set uniqueNonce = new HashSet(); int removedItems = 0; - ListIterator listItemIterator = listItems.listIterator(); + ListIterator listItemIterator = listItems.listIterator(); while (listItemIterator.hasNext()) { int adapterMessagePosition = listItemIterator.nextIndex() - removedItems; - MessageCenterUtil.MessageCenterListItem message = listItemIterator.next(); + MessageCenterListItem message = listItemIterator.next(); if (message instanceof ApptentiveMessage) { /* Check if there is any duplicate messages and remove if found. * add() of a Set returns false if the element already exists. @@ -1178,11 +1179,11 @@ private void hideProfileButton() { * with seconds resolution. If messages were received by server within a second, messages may be out of order * This method uses insertion sort to re-sort the messages retrieved from the database */ - private void prepareMessages(final List originalItems) { + private void prepareMessages(final List originalItems) { listItems.clear(); unsentMessagesCount = 0; // Loop through each message item retrieved from database - for (MessageCenterUtil.MessageCenterListItem item : originalItems) { + for (MessageCenterListItem item : originalItems) { if (item instanceof ApptentiveMessage) { ApptentiveMessage apptentiveMessage = (ApptentiveMessage) item; Double createdAt = apptentiveMessage.getCreatedAt(); @@ -1193,7 +1194,7 @@ private void prepareMessages(final List /* * Find proper location to insert into the listItems list of the listview. */ - ListIterator listIterator = listItems.listIterator(); + ListIterator listIterator = listItems.listIterator(); ApptentiveMessage next = null; while (listIterator.hasNext()) { next = (ApptentiveMessage) listIterator.next(); @@ -1296,10 +1297,10 @@ public void handleMessage(Message msg) { break; } case MSG_MESSAGE_REMOVE_WHOCARD: { - ListIterator messageIterator = fragment.listItems.listIterator(); + ListIterator messageIterator = fragment.listItems.listIterator(); while (messageIterator.hasNext()) { int i = messageIterator.nextIndex(); - MessageCenterUtil.MessageCenterListItem next = messageIterator.next(); + MessageCenterListItem next = messageIterator.next(); if (next.getListItemType() == WHO_CARD) { messageIterator.remove(); fragment.messageCenterRecyclerViewAdapter.notifyItemRemoved(i); @@ -1336,7 +1337,7 @@ public void handleMessage(Message msg) { ApptentiveMessage apptentiveMessage = (ApptentiveMessage) msg.obj; for (int i = 0; i < fragment.listItems.size(); i++) { - MessageCenterUtil.MessageCenterListItem message = fragment.listItems.get(i); + MessageCenterListItem message = fragment.listItems.get(i); if (message instanceof ApptentiveMessage) { String nonce = ((ApptentiveMessage) message).getNonce(); if (nonce != null) { @@ -1393,10 +1394,10 @@ public void handleMessage(Message msg) { case MSG_SEND_PENDING_CONTEXT_MESSAGE: { ContextMessage contextMessage = null; // If the list has a context message, get it, remove it from the list, and notify the RecyclerView to update. - ListIterator iterator = fragment.listItems.listIterator(); + ListIterator iterator = fragment.listItems.listIterator(); while (iterator.hasNext()) { int index = iterator.nextIndex(); - MessageCenterUtil.MessageCenterListItem item = iterator.next(); + MessageCenterListItem item = iterator.next(); if (item.getListItemType() == MESSAGE_CONTEXT) { contextMessage = (ContextMessage) item; iterator.remove(); @@ -1444,7 +1445,7 @@ public void handleMessage(Message msg) { } case MSG_REMOVE_COMPOSER: { for (int i = 0; i < fragment.listItems.size(); i++) { - MessageCenterUtil.MessageCenterListItem item = fragment.listItems.get(i); + MessageCenterListItem item = fragment.listItems.get(i); if (item.getListItemType() == MESSAGE_COMPOSER) { fragment.listItems.remove(i); fragment.messageCenterRecyclerViewAdapter.notifyItemRemoved(i); @@ -1453,10 +1454,10 @@ public void handleMessage(Message msg) { break; } case MSG_OPT_INSERT_REGULAR_STATUS: { - List listItems = fragment.listItems; + List listItems = fragment.listItems; // Only add status if the last item in the list is a sent message. if (listItems.size() > 0) { - MessageCenterUtil.MessageCenterListItem lastItem = listItems.get(listItems.size() - 1); + MessageCenterListItem lastItem = listItems.get(listItems.size() - 1); if (lastItem != null && lastItem.getListItemType() == MESSAGE_OUTGOING) { ApptentiveMessage apptentiveMessage = (ApptentiveMessage) lastItem; if (apptentiveMessage.isOutgoingMessage()) { @@ -1476,9 +1477,9 @@ public void handleMessage(Message msg) { break; } case MSG_REMOVE_STATUS: { - List listItems = fragment.listItems; + List listItems = fragment.listItems; for (int i = 0; i < listItems.size(); i++) { - MessageCenterUtil.MessageCenterListItem item = listItems.get(i); + MessageCenterListItem item = listItems.get(i); if (item.getListItemType() == STATUS) { listItems.remove(i); fragment.messageCenterRecyclerViewAdapter.notifyItemRemoved(i); @@ -1526,7 +1527,7 @@ public void handleMessage(Message msg) { } public boolean recyclerViewContainsItemOfType(int type) { - for (MessageCenterUtil.MessageCenterListItem item : listItems) { + for (MessageCenterListItem item : listItems) { if (item.getListItemType() == type) { return true; } @@ -1538,7 +1539,7 @@ public void setPaused(boolean paused) { if (isPaused ^ paused) { // Invalidate any unsent messages, as these will have status and progress bars that need to change. for (int i = 0; i < listItems.size(); i++) { - MessageCenterUtil.MessageCenterListItem item = listItems.get(i); + MessageCenterListItem item = listItems.get(i); if (item instanceof ApptentiveMessage) { ApptentiveMessage message = (ApptentiveMessage) item; if (message.isOutgoingMessage() && message.getCreatedAt() == null) { diff --git a/apptentive/src/main/java/com/apptentive/android/sdk/module/messagecenter/MessageManager.java b/apptentive/src/main/java/com/apptentive/android/sdk/module/messagecenter/MessageManager.java index 0f7490db3..fa30bea25 100644 --- a/apptentive/src/main/java/com/apptentive/android/sdk/module/messagecenter/MessageManager.java +++ b/apptentive/src/main/java/com/apptentive/android/sdk/module/messagecenter/MessageManager.java @@ -25,7 +25,7 @@ import com.apptentive.android.sdk.module.messagecenter.model.ApptentiveMessage; import com.apptentive.android.sdk.module.messagecenter.model.ApptentiveToastNotification; import com.apptentive.android.sdk.module.messagecenter.model.CompoundMessage; -import com.apptentive.android.sdk.module.messagecenter.model.MessageCenterUtil; +import com.apptentive.android.sdk.module.messagecenter.model.MessageCenterListItem; import com.apptentive.android.sdk.module.messagecenter.model.MessageFactory; import com.apptentive.android.sdk.module.metric.MetricModule; import com.apptentive.android.sdk.storage.MessageStore; @@ -224,8 +224,8 @@ public synchronized boolean fetchAndStoreMessages(boolean isMessageCenterForegro return false; } - public List getMessageCenterListItems() { - List messagesToShow = new ArrayList(); + public List getMessageCenterListItems() { + List messagesToShow = new ArrayList(); try { List messagesAll = getMessageStore().getAllMessages().get(); // Do not display hidden messages on Message Center diff --git a/apptentive/src/main/java/com/apptentive/android/sdk/module/messagecenter/model/ApptentiveMessage.java b/apptentive/src/main/java/com/apptentive/android/sdk/module/messagecenter/model/ApptentiveMessage.java index 8ff549695..6f82cc376 100644 --- a/apptentive/src/main/java/com/apptentive/android/sdk/module/messagecenter/model/ApptentiveMessage.java +++ b/apptentive/src/main/java/com/apptentive/android/sdk/module/messagecenter/model/ApptentiveMessage.java @@ -14,7 +14,7 @@ import java.util.Map; -public abstract class ApptentiveMessage extends ConversationItem implements MessageCenterUtil.MessageCenterListItem { +public abstract class ApptentiveMessage extends ConversationItem implements MessageCenterListItem { public static final String KEY_ID = "id"; public static final String KEY_CREATED_AT = "created_at"; diff --git a/apptentive/src/main/java/com/apptentive/android/sdk/module/messagecenter/model/Composer.java b/apptentive/src/main/java/com/apptentive/android/sdk/module/messagecenter/model/Composer.java index 4360508e7..96dbd3701 100644 --- a/apptentive/src/main/java/com/apptentive/android/sdk/module/messagecenter/model/Composer.java +++ b/apptentive/src/main/java/com/apptentive/android/sdk/module/messagecenter/model/Composer.java @@ -6,7 +6,7 @@ package com.apptentive.android.sdk.module.messagecenter.model; -public class Composer implements MessageCenterUtil.MessageCenterListItem { +public class Composer implements MessageCenterListItem { public String title; public String closeBody; diff --git a/apptentive/src/main/java/com/apptentive/android/sdk/module/messagecenter/model/ContextMessage.java b/apptentive/src/main/java/com/apptentive/android/sdk/module/messagecenter/model/ContextMessage.java index da7693e9a..7fedb1ebc 100644 --- a/apptentive/src/main/java/com/apptentive/android/sdk/module/messagecenter/model/ContextMessage.java +++ b/apptentive/src/main/java/com/apptentive/android/sdk/module/messagecenter/model/ContextMessage.java @@ -6,7 +6,7 @@ package com.apptentive.android.sdk.module.messagecenter.model; -public class ContextMessage implements MessageCenterUtil.MessageCenterListItem { +public class ContextMessage implements MessageCenterListItem { private String body; diff --git a/apptentive/src/main/java/com/apptentive/android/sdk/module/messagecenter/model/MessageCenterGreeting.java b/apptentive/src/main/java/com/apptentive/android/sdk/module/messagecenter/model/MessageCenterGreeting.java index 996f84f16..d86db977a 100644 --- a/apptentive/src/main/java/com/apptentive/android/sdk/module/messagecenter/model/MessageCenterGreeting.java +++ b/apptentive/src/main/java/com/apptentive/android/sdk/module/messagecenter/model/MessageCenterGreeting.java @@ -6,7 +6,7 @@ package com.apptentive.android.sdk.module.messagecenter.model; -public class MessageCenterGreeting implements MessageCenterUtil.MessageCenterListItem { +public class MessageCenterGreeting implements MessageCenterListItem { public final String title; public final String body; public final String avatar; diff --git a/apptentive/src/main/java/com/apptentive/android/sdk/module/messagecenter/model/MessageCenterListItem.java b/apptentive/src/main/java/com/apptentive/android/sdk/module/messagecenter/model/MessageCenterListItem.java new file mode 100644 index 000000000..b1464227c --- /dev/null +++ b/apptentive/src/main/java/com/apptentive/android/sdk/module/messagecenter/model/MessageCenterListItem.java @@ -0,0 +1,20 @@ +/* + * Copyright (c) 2016, Apptentive, Inc. All Rights Reserved. + * Please refer to the LICENSE file for the terms and conditions + * under which redistribution and use of this file is permitted. + */ + +package com.apptentive.android.sdk.module.messagecenter.model; + +public interface MessageCenterListItem { + int GREETING = 1; + int STATUS = 2; + int MESSAGE_CONTEXT = 3; + int MESSAGE_AUTO = 4; + int MESSAGE_OUTGOING = 5; + int MESSAGE_INCOMING = 6; + int MESSAGE_COMPOSER = 7; + int WHO_CARD = 8; + + int getListItemType(); +} diff --git a/apptentive/src/main/java/com/apptentive/android/sdk/module/messagecenter/model/MessageCenterStatus.java b/apptentive/src/main/java/com/apptentive/android/sdk/module/messagecenter/model/MessageCenterStatus.java index 5737eab99..be337293a 100644 --- a/apptentive/src/main/java/com/apptentive/android/sdk/module/messagecenter/model/MessageCenterStatus.java +++ b/apptentive/src/main/java/com/apptentive/android/sdk/module/messagecenter/model/MessageCenterStatus.java @@ -8,7 +8,7 @@ import org.json.JSONObject; -public class MessageCenterStatus extends JSONObject implements MessageCenterUtil.MessageCenterListItem { +public class MessageCenterStatus extends JSONObject implements MessageCenterListItem { public final String body; public final Integer icon; diff --git a/apptentive/src/main/java/com/apptentive/android/sdk/module/messagecenter/model/MessageCenterUtil.java b/apptentive/src/main/java/com/apptentive/android/sdk/module/messagecenter/model/MessageCenterUtil.java index 916354c58..37ae80423 100644 --- a/apptentive/src/main/java/com/apptentive/android/sdk/module/messagecenter/model/MessageCenterUtil.java +++ b/apptentive/src/main/java/com/apptentive/android/sdk/module/messagecenter/model/MessageCenterUtil.java @@ -8,20 +8,6 @@ public class MessageCenterUtil { - public interface MessageCenterListItem { - - int STATUS = 1; - int MESSAGE_COMPOSER = 2; - int GREETING = 3; - int MESSAGE_OUTGOING = 4; - int MESSAGE_INCOMING = 5; - int MESSAGE_CONTEXT = 6; - int MESSAGE_AUTO = 7; - int WHO_CARD = 8; - - int getListItemType(); - } - // Combine both incoming and outgoing interfaces into one public interface CompoundMessageCommonInterface { void setBody(String body); diff --git a/apptentive/src/main/java/com/apptentive/android/sdk/module/messagecenter/model/WhoCard.java b/apptentive/src/main/java/com/apptentive/android/sdk/module/messagecenter/model/WhoCard.java index e11cda6a2..6fe5aee85 100644 --- a/apptentive/src/main/java/com/apptentive/android/sdk/module/messagecenter/model/WhoCard.java +++ b/apptentive/src/main/java/com/apptentive/android/sdk/module/messagecenter/model/WhoCard.java @@ -9,7 +9,7 @@ import org.json.JSONException; import org.json.JSONObject; -public class WhoCard extends JSONObject implements MessageCenterUtil.MessageCenterListItem { +public class WhoCard extends JSONObject implements MessageCenterListItem { private static final String KEY_REQUEST = "request"; private static final String KEY_REQUIRE = "require"; diff --git a/apptentive/src/main/java/com/apptentive/android/sdk/module/messagecenter/view/MessageCenterRecyclerViewAdapter.java b/apptentive/src/main/java/com/apptentive/android/sdk/module/messagecenter/view/MessageCenterRecyclerViewAdapter.java index 4370c4245..e024e034f 100644 --- a/apptentive/src/main/java/com/apptentive/android/sdk/module/messagecenter/view/MessageCenterRecyclerViewAdapter.java +++ b/apptentive/src/main/java/com/apptentive/android/sdk/module/messagecenter/view/MessageCenterRecyclerViewAdapter.java @@ -26,8 +26,8 @@ import com.apptentive.android.sdk.module.messagecenter.model.CompoundMessage; import com.apptentive.android.sdk.module.messagecenter.model.ContextMessage; import com.apptentive.android.sdk.module.messagecenter.model.MessageCenterGreeting; +import com.apptentive.android.sdk.module.messagecenter.model.MessageCenterListItem; import com.apptentive.android.sdk.module.messagecenter.model.MessageCenterStatus; -import com.apptentive.android.sdk.module.messagecenter.model.MessageCenterUtil; import com.apptentive.android.sdk.module.messagecenter.model.WhoCard; import com.apptentive.android.sdk.module.messagecenter.view.holder.AutomatedMessageHolder; import com.apptentive.android.sdk.module.messagecenter.view.holder.ContextMessageHolder; @@ -45,14 +45,14 @@ import java.util.ArrayList; import java.util.List; -import static com.apptentive.android.sdk.module.messagecenter.model.MessageCenterUtil.MessageCenterListItem.GREETING; -import static com.apptentive.android.sdk.module.messagecenter.model.MessageCenterUtil.MessageCenterListItem.MESSAGE_AUTO; -import static com.apptentive.android.sdk.module.messagecenter.model.MessageCenterUtil.MessageCenterListItem.MESSAGE_COMPOSER; -import static com.apptentive.android.sdk.module.messagecenter.model.MessageCenterUtil.MessageCenterListItem.MESSAGE_CONTEXT; -import static com.apptentive.android.sdk.module.messagecenter.model.MessageCenterUtil.MessageCenterListItem.MESSAGE_INCOMING; -import static com.apptentive.android.sdk.module.messagecenter.model.MessageCenterUtil.MessageCenterListItem.MESSAGE_OUTGOING; -import static com.apptentive.android.sdk.module.messagecenter.model.MessageCenterUtil.MessageCenterListItem.STATUS; -import static com.apptentive.android.sdk.module.messagecenter.model.MessageCenterUtil.MessageCenterListItem.WHO_CARD; +import static com.apptentive.android.sdk.module.messagecenter.model.MessageCenterListItem.GREETING; +import static com.apptentive.android.sdk.module.messagecenter.model.MessageCenterListItem.MESSAGE_AUTO; +import static com.apptentive.android.sdk.module.messagecenter.model.MessageCenterListItem.MESSAGE_COMPOSER; +import static com.apptentive.android.sdk.module.messagecenter.model.MessageCenterListItem.MESSAGE_CONTEXT; +import static com.apptentive.android.sdk.module.messagecenter.model.MessageCenterListItem.MESSAGE_INCOMING; +import static com.apptentive.android.sdk.module.messagecenter.model.MessageCenterListItem.MESSAGE_OUTGOING; +import static com.apptentive.android.sdk.module.messagecenter.model.MessageCenterListItem.STATUS; +import static com.apptentive.android.sdk.module.messagecenter.model.MessageCenterListItem.WHO_CARD; public class MessageCenterRecyclerViewAdapter extends RecyclerView.Adapter { @@ -60,11 +60,11 @@ public class MessageCenterRecyclerViewAdapter extends RecyclerView.Adapter { OnListviewItemActionListener listener; RecyclerView recyclerView; Interaction interaction; - List listItems; + List listItems; // maps to prevent redundant asynctasks private ArrayList messagesWithPendingReadStatusUpdate = new ArrayList(); - public MessageCenterRecyclerViewAdapter(MessageCenterFragment fragment, OnListviewItemActionListener listener, Interaction interaction, List listItems) { + public MessageCenterRecyclerViewAdapter(MessageCenterFragment fragment, OnListviewItemActionListener listener, Interaction interaction, List listItems) { this.fragment = fragment; this.listener = listener; this.interaction = interaction; @@ -206,7 +206,7 @@ public int getItemCount() { @Override public int getItemViewType(int position) { - MessageCenterUtil.MessageCenterListItem message = listItems.get(position); + MessageCenterListItem message = listItems.get(position); return message.getListItemType(); } From eab48afa6bda3b087064cce316c8151b8c541232 Mon Sep 17 00:00:00 2001 From: skykelsey Date: Tue, 8 Nov 2016 12:35:44 -0800 Subject: [PATCH 062/100] Update format of MessageManager --- .../android/sdk/module/messagecenter/MessageManager.java | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/apptentive/src/main/java/com/apptentive/android/sdk/module/messagecenter/MessageManager.java b/apptentive/src/main/java/com/apptentive/android/sdk/module/messagecenter/MessageManager.java index fa30bea25..ba0e8133d 100644 --- a/apptentive/src/main/java/com/apptentive/android/sdk/module/messagecenter/MessageManager.java +++ b/apptentive/src/main/java/com/apptentive/android/sdk/module/messagecenter/MessageManager.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, Apptentive, Inc. All Rights Reserved. + * Copyright (c) 2016, Apptentive, Inc. All Rights Reserved. * Please refer to the LICENSE file for the terms and conditions * under which redistribution and use of this file is permitted. */ @@ -43,9 +43,6 @@ import java.util.concurrent.Future; import java.util.concurrent.atomic.AtomicBoolean; -/** - * @author Sky Kelsey - */ public class MessageManager { // The reason of pause message sending @@ -502,7 +499,6 @@ public void run() { } } - public void appWentToForeground() { appInForeground.set(true); if (pollingWorker != null) { @@ -516,5 +512,4 @@ public void appWentToBackground() { pollingWorker.appWentToBackground(); } } - } From d98c913f265380ef6d91870993d6912feb0ef8cc Mon Sep 17 00:00:00 2001 From: skykelsey Date: Tue, 8 Nov 2016 16:50:58 -0800 Subject: [PATCH 063/100] Disable the MC Composer attach button when the number of allowed attachments has reached the limit. --- .../view/holder/MessageComposerHolder.java | 25 +++++++++++++++---- 1 file changed, 20 insertions(+), 5 deletions(-) diff --git a/apptentive/src/main/java/com/apptentive/android/sdk/module/messagecenter/view/holder/MessageComposerHolder.java b/apptentive/src/main/java/com/apptentive/android/sdk/module/messagecenter/view/holder/MessageComposerHolder.java index ef5ad10b4..2410f733d 100644 --- a/apptentive/src/main/java/com/apptentive/android/sdk/module/messagecenter/view/holder/MessageComposerHolder.java +++ b/apptentive/src/main/java/com/apptentive/android/sdk/module/messagecenter/view/holder/MessageComposerHolder.java @@ -48,6 +48,8 @@ public class MessageComposerHolder extends RecyclerView.ViewHolder { private TextWatcher textWatcher; + private int maxAllowedAttachments; + public MessageComposerHolder(View itemView) { super(itemView); images = new ArrayList(); @@ -57,6 +59,8 @@ public MessageComposerHolder(View itemView) { sendButton = (ImageButton) itemView.findViewById(R.id.btn_send_message); message = (EditText) itemView.findViewById(R.id.composing_et); attachments = (ApptentiveImageGridView) itemView.findViewById(R.id.grid); + + maxAllowedAttachments = itemView.getResources().getInteger(R.integer.apptentive_image_grid_default_attachments_total); } public void bindView(final MessageCenterFragment fragment, final MessageCenterRecyclerViewAdapter adapter, final Composer composer) { @@ -193,6 +197,7 @@ public void addImagesToImageAttachmentBand(final List imagesToAttach) attachments.setupLayoutListener(); attachments.setVisibility(View.VISIBLE); images.addAll(imagesToAttach); + setAttachButtonState(); addAdditionalAttachItem(); attachments.notifyDataSetChanged(); } @@ -205,6 +210,7 @@ public void addImagesToImageAttachmentBand(final List imagesToAttach) public void removeImageFromImageAttachmentBand(final int position) { images.remove(position); attachments.setupLayoutListener(); + setAttachButtonState(); if (images.size() == 0) { // Hide attachment band after last attachment is removed attachments.setVisibility(View.GONE); @@ -215,23 +221,32 @@ public void removeImageFromImageAttachmentBand(final int position) { private void addAdditionalAttachItem() { ArrayList imagesToAdd = new ArrayList(images); - if (imagesToAdd.size() < itemView.getResources().getInteger(R.integer.apptentive_image_grid_default_attachments_total)) { + if (imagesToAdd.size() < maxAllowedAttachments) { imagesToAdd.add(new ImageItem("", "", "Image/*", 0)); } attachments.setData(imagesToAdd); } + public void setAttachButtonState() { + boolean enabled = images.size() < maxAllowedAttachments; + setButtonState(attachButton, enabled); + } + public void setSendButtonState() { boolean enabled = !TextUtils.isEmpty(message.getText()) || !images.isEmpty(); - if (sendButton.isEnabled() ^ enabled) { // Only if changing value - sendButton.setEnabled(enabled); + setButtonState(sendButton, enabled); + } + + public void setButtonState(ImageButton button, boolean enabled) { + if (button.isEnabled() ^ enabled) { // Only if changing value + button.setEnabled(enabled); if (enabled) { if (Build.VERSION.SDK_INT < Build.VERSION_CODES.LOLLIPOP) { - sendButton.setColorFilter(Util.getThemeColor(itemView.getContext(), R.attr.apptentiveButtonTintColor)); + button.setColorFilter(Util.getThemeColor(itemView.getContext(), R.attr.apptentiveButtonTintColor)); } } else { if (Build.VERSION.SDK_INT < Build.VERSION_CODES.LOLLIPOP) { - sendButton.setColorFilter(Util.getThemeColor(itemView.getContext(), R.attr.apptentiveButtonTintColorDisabled)); + button.setColorFilter(Util.getThemeColor(itemView.getContext(), R.attr.apptentiveButtonTintColorDisabled)); } } } From 435e89829930ffdfa7153c7756b527f56fc6ef13 Mon Sep 17 00:00:00 2001 From: skykelsey Date: Tue, 8 Nov 2016 16:54:32 -0800 Subject: [PATCH 064/100] When user tries to discard Composer, show the confirmation if there are any attachments, not just when there is text. --- .../module/messagecenter/view/holder/MessageComposerHolder.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apptentive/src/main/java/com/apptentive/android/sdk/module/messagecenter/view/holder/MessageComposerHolder.java b/apptentive/src/main/java/com/apptentive/android/sdk/module/messagecenter/view/holder/MessageComposerHolder.java index 2410f733d..01d3d72da 100644 --- a/apptentive/src/main/java/com/apptentive/android/sdk/module/messagecenter/view/holder/MessageComposerHolder.java +++ b/apptentive/src/main/java/com/apptentive/android/sdk/module/messagecenter/view/holder/MessageComposerHolder.java @@ -75,7 +75,7 @@ public void bindView(final MessageCenterFragment fragment, final MessageCenterRe closeButton.setOnClickListener(new View.OnClickListener() { public void onClick(View view) { - if (!TextUtils.isEmpty(message.getText())) { + if (!TextUtils.isEmpty(message.getText()) || !images.isEmpty()) { Bundle bundle = new Bundle(); bundle.putString("message", composer.closeBody); bundle.putString("positive", composer.closeDiscard); From a48e0d339b4d850451cbbfc451f94542d4a402f5 Mon Sep 17 00:00:00 2001 From: skykelsey Date: Tue, 8 Nov 2016 17:00:42 -0800 Subject: [PATCH 065/100] Remove unneeded layouts. --- ...ive_message_center_composing_actionbar.xml | 62 ------------------- ...ptentive_message_center_composing_area.xml | 49 --------------- 2 files changed, 111 deletions(-) delete mode 100644 apptentive/src/main/res/layout/apptentive_message_center_composing_actionbar.xml delete mode 100644 apptentive/src/main/res/layout/apptentive_message_center_composing_area.xml diff --git a/apptentive/src/main/res/layout/apptentive_message_center_composing_actionbar.xml b/apptentive/src/main/res/layout/apptentive_message_center_composing_actionbar.xml deleted file mode 100644 index 0cd1073df..000000000 --- a/apptentive/src/main/res/layout/apptentive_message_center_composing_actionbar.xml +++ /dev/null @@ -1,62 +0,0 @@ - - - - - - - - - - - - \ No newline at end of file diff --git a/apptentive/src/main/res/layout/apptentive_message_center_composing_area.xml b/apptentive/src/main/res/layout/apptentive_message_center_composing_area.xml deleted file mode 100644 index 61f4def73..000000000 --- a/apptentive/src/main/res/layout/apptentive_message_center_composing_area.xml +++ /dev/null @@ -1,49 +0,0 @@ - - - - - - - - - - \ No newline at end of file From 75ba6f6c16000cf0d21168325daf533994a20674 Mon Sep 17 00:00:00 2001 From: skykelsey Date: Tue, 8 Nov 2016 17:00:59 -0800 Subject: [PATCH 066/100] Simplify layout id names. --- .../view/holder/MessageComposerHolder.java | 10 +++++----- .../apptentive_message_center_composer.xml | 18 +++++++++--------- 2 files changed, 14 insertions(+), 14 deletions(-) diff --git a/apptentive/src/main/java/com/apptentive/android/sdk/module/messagecenter/view/holder/MessageComposerHolder.java b/apptentive/src/main/java/com/apptentive/android/sdk/module/messagecenter/view/holder/MessageComposerHolder.java index 01d3d72da..8fb587a98 100644 --- a/apptentive/src/main/java/com/apptentive/android/sdk/module/messagecenter/view/holder/MessageComposerHolder.java +++ b/apptentive/src/main/java/com/apptentive/android/sdk/module/messagecenter/view/holder/MessageComposerHolder.java @@ -53,12 +53,12 @@ public class MessageComposerHolder extends RecyclerView.ViewHolder { public MessageComposerHolder(View itemView) { super(itemView); images = new ArrayList(); - closeButton = (ImageButton) itemView.findViewById(R.id.cancel_composing); + closeButton = (ImageButton) itemView.findViewById(R.id.close_button); title = (TextView) itemView.findViewById(R.id.title); - attachButton = (ImageButton) itemView.findViewById(R.id.btn_attach_image); - sendButton = (ImageButton) itemView.findViewById(R.id.btn_send_message); - message = (EditText) itemView.findViewById(R.id.composing_et); - attachments = (ApptentiveImageGridView) itemView.findViewById(R.id.grid); + attachButton = (ImageButton) itemView.findViewById(R.id.attach_button); + sendButton = (ImageButton) itemView.findViewById(R.id.send_button); + message = (EditText) itemView.findViewById(R.id.message); + attachments = (ApptentiveImageGridView) itemView.findViewById(R.id.attachments); maxAllowedAttachments = itemView.getResources().getInteger(R.integer.apptentive_image_grid_default_attachments_total); } diff --git a/apptentive/src/main/res/layout/apptentive_message_center_composer.xml b/apptentive/src/main/res/layout/apptentive_message_center_composer.xml index d68f0ce81..c9f0111bb 100644 --- a/apptentive/src/main/res/layout/apptentive_message_center_composer.xml +++ b/apptentive/src/main/res/layout/apptentive_message_center_composer.xml @@ -20,7 +20,7 @@ android:layout_height="wrap_content" android:minHeight="@dimen/apptentive_message_center_composing_bar_min_height" android:background="?apptentiveComposingBarBackground"> - - - @@ -66,7 +66,7 @@ android:orientation="vertical" android:layout_marginTop="-1.5dp" android:background="?apptentiveComposingAreaBackground"> - - Date: Tue, 8 Nov 2016 17:02:49 -0800 Subject: [PATCH 067/100] Remove unused namespace declartion and auto format. --- apptentive/src/main/res/layout/apptentive_message_auto.xml | 1 - .../src/main/res/layout/apptentive_message_center_composer.xml | 2 +- 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/apptentive/src/main/res/layout/apptentive_message_auto.xml b/apptentive/src/main/res/layout/apptentive_message_auto.xml index 11461b3b3..0e52e7450 100644 --- a/apptentive/src/main/res/layout/apptentive_message_auto.xml +++ b/apptentive/src/main/res/layout/apptentive_message_auto.xml @@ -7,7 +7,6 @@ --> Date: Tue, 8 Nov 2016 17:12:27 -0800 Subject: [PATCH 068/100] Fix typos in styles. --- .../apptentive_interaction_button_color_state_list.xml | 6 +++--- .../src/main/res/layout/apptentive_survey_question_base.xml | 2 +- apptentive/src/main/res/values/strings.xml | 2 +- apptentive/src/main/res/values/themes.xml | 4 ++-- 4 files changed, 7 insertions(+), 7 deletions(-) diff --git a/apptentive/src/main/res/color/apptentive_interaction_button_color_state_list.xml b/apptentive/src/main/res/color/apptentive_interaction_button_color_state_list.xml index 3069be385..983391fb4 100644 --- a/apptentive/src/main/res/color/apptentive_interaction_button_color_state_list.xml +++ b/apptentive/src/main/res/color/apptentive_interaction_button_color_state_list.xml @@ -23,9 +23,9 @@ Define color as: - - - + + + --> diff --git a/apptentive/src/main/res/layout/apptentive_survey_question_base.xml b/apptentive/src/main/res/layout/apptentive_survey_question_base.xml index f6922bd48..e8e28f68f 100644 --- a/apptentive/src/main/res/layout/apptentive_survey_question_base.xml +++ b/apptentive/src/main/res/layout/apptentive_survey_question_base.xml @@ -45,7 +45,7 @@ android:layout_width="wrap_content" android:layout_height="wrap_content" android:textAppearance="@style/Apptentive.TextAppearance.Caption" - android:text="@string/apptentive_instruction_text_separater"/> + android:text="@string/apptentive_instruction_text_separator"/> -  –  +  –  diff --git a/apptentive/src/main/res/values/themes.xml b/apptentive/src/main/res/values/themes.xml index b761c05ba..20faf05ca 100644 --- a/apptentive/src/main/res/values/themes.xml +++ b/apptentive/src/main/res/values/themes.xml @@ -177,7 +177,7 @@ ?apptentiveFontFamilyMediumDefault ?apptentiveFontFamilyMediumDefault - + @style/Apptentive.Widget.CheckBox @style/Apptentive.Widget.RadioButton @style/Apptentive.Widget.Button.Borderless @@ -205,7 +205,7 @@ 2dp - \ No newline at end of file diff --git a/apptentive/src/main/res/values/themes.xml b/apptentive/src/main/res/values/themes.xml index 20faf05ca..9bbe89b70 100644 --- a/apptentive/src/main/res/values/themes.xml +++ b/apptentive/src/main/res/values/themes.xml @@ -24,6 +24,7 @@ @drawable/apptentive_empty_image_background_light @color/apptentive_card_border_color_light @color/apptentive_attenuate_color_light + #FFD6D7D7 @color/apptentive_text_color_primary_light @color/apptentive_text_color_primary_dark @@ -51,6 +52,7 @@ @drawable/apptentive_empty_image_background_light @color/apptentive_card_border_color_light @color/apptentive_attenuate_color_light + #FFD6D7D7 @color/apptentive_text_color_primary_light @color/apptentive_text_color_primary_dark @@ -79,6 +81,7 @@ @drawable/apptentive_empty_image_background_dark @color/apptentive_card_border_color_dark @color/apptentive_attenuate_color_dark + #FF5A595B @color/apptentive_text_color_primary_dark @color/apptentive_text_color_primary_light @@ -107,6 +110,7 @@ @drawable/apptentive_empty_image_background_dark @color/apptentive_card_border_color_dark @color/apptentive_attenuate_color_dark + #FF5A595B @color/apptentive_text_color_primary_dark @color/apptentive_text_color_primary_light @@ -142,7 +146,6 @@ @color/apptentive_validation_failed_color ?attr/colorAccent - #FFD6D7D7 @color/apptentive_tinted_button @dimen/apptentive_text_size_headline From 34435299a32d99f0e81f987b94a65300812a333d Mon Sep 17 00:00:00 2001 From: skykelsey Date: Wed, 16 Nov 2016 09:36:28 -0800 Subject: [PATCH 081/100] MC Composer was jerking when any attachment was removed. Stop redrawing the Composer each time an attachment is removed. ANDROID-804 --- .../engagement/interaction/fragment/MessageCenterFragment.java | 1 - 1 file changed, 1 deletion(-) diff --git a/apptentive/src/main/java/com/apptentive/android/sdk/module/engagement/interaction/fragment/MessageCenterFragment.java b/apptentive/src/main/java/com/apptentive/android/sdk/module/engagement/interaction/fragment/MessageCenterFragment.java index 651881b7b..f50710ef9 100644 --- a/apptentive/src/main/java/com/apptentive/android/sdk/module/engagement/interaction/fragment/MessageCenterFragment.java +++ b/apptentive/src/main/java/com/apptentive/android/sdk/module/engagement/interaction/fragment/MessageCenterFragment.java @@ -1519,7 +1519,6 @@ public void handleMessage(Message msg) { int position = msg.arg1; fragment.pendingAttachments.remove(position); fragment.messageCenterRecyclerViewAdapter.removeImageFromComposer(fragment.composer, position); - fragment.messageCenterRecyclerViewAdapter.notifyItemChanged(fragment.listItems.size() - 1); break; } } From b12915a095d0452d43a38803ca9ebb1e53315d6d Mon Sep 17 00:00:00 2001 From: skykelsey Date: Wed, 16 Nov 2016 09:57:12 -0800 Subject: [PATCH 082/100] Fix javadoc generation warnings caused by improper use of paragraph

tags. --- .../apptentive/android/sdk/Apptentive.java | 30 ++++++------------- 1 file changed, 9 insertions(+), 21 deletions(-) diff --git a/apptentive/src/main/java/com/apptentive/android/sdk/Apptentive.java b/apptentive/src/main/java/com/apptentive/android/sdk/Apptentive.java index 475586911..373b8d1c0 100755 --- a/apptentive/src/main/java/com/apptentive/android/sdk/Apptentive.java +++ b/apptentive/src/main/java/com/apptentive/android/sdk/Apptentive.java @@ -495,23 +495,19 @@ public static boolean isApptentivePushNotification(Map data) { } /** - *

- * Use this method in your push receiver to build a pending Intent when an Apptentive push + *

Use this method in your push receiver to build a pending Intent when an Apptentive push * notification is received. Pass the generated PendingIntent to * {@link android.support.v4.app.NotificationCompat.Builder#setContentIntent} to allow Apptentive * to display Interactions such as Message Center. This method replaces the deprecated * {@link #setPendingPushNotification(Intent)}. Calling this method for a push {@Intent} that did * not come from Apptentive will return a null object. If you receive a null object, your app will - * need to handle this notification itself. - *

- *

- * This is the method you will likely need if you integrated using: + * need to handle this notification itself.

+ *

This is the method you will likely need if you integrated using:

*
    *
  • GCM
  • *
  • AWS SNS
  • *
  • Parse
  • *
- *

* * @param intent An {@link Intent} containing the Apptentive Push data. Pass in what you receive * in the Service or BroadcastReceiver that is used by your chosen push provider. @@ -526,21 +522,17 @@ public static PendingIntent buildPendingIntentFromPushNotification(@NonNull Inte } /** - *

- * Use this method in your push receiver to build a pending Intent when an Apptentive push + *

Use this method in your push receiver to build a pending Intent when an Apptentive push * notification is received. Pass the generated PendingIntent to * {@link android.support.v4.app.NotificationCompat.Builder#setContentIntent} to allow Apptentive * to display Interactions such as Message Center. This method replaces the deprecated * {@link #setPendingPushNotification(Bundle)}. Calling this method for a push {@link Bundle} that * did not come from Apptentive will return a null object. If you receive a null object, your app - * will need to handle this notification itself. - *

- *

- * This is the method you will likely need if you integrated using: + * will need to handle this notification itself.

+ *

This is the method you will likely need if you integrated using:

*
    *
  • Urban Airship
  • *
- *

* * @param bundle A {@link Bundle} containing the Apptentive Push data. Pass in what you receive in * the the Service or BroadcastReceiver that is used by your chosen push provider. @@ -555,21 +547,17 @@ public static PendingIntent buildPendingIntentFromPushNotification(@NonNull Bund } /** - *

- * Use this method in your push receiver to build a pending Intent when an Apptentive push + *

Use this method in your push receiver to build a pending Intent when an Apptentive push * notification is received. Pass the generated PendingIntent to * {@link android.support.v4.app.NotificationCompat.Builder#setContentIntent} to allow Apptentive * to display Interactions such as Message Center. This method replaces the deprecated * {@link #setPendingPushNotification(Bundle)}. Calling this method for a push {@link Bundle} that * did not come from Apptentive will return a null object. If you receive a null object, your app - * will need to handle this notification itself. - *

- *

- * This is the method you will likely need if you integrated using: + * will need to handle this notification itself.

+ *

This is the method you will likely need if you integrated using:

*
    *
  • Firebase Cloud Messaging (FCM)
  • *
- *

* * @param data A {@link Map}<{@link String},{@link String}> containing the Apptentive Push * data. Pass in what you receive in the the Service or BroadcastReceiver that is From 1b1466df0bdc70655772657f9764bd9fa481f6f3 Mon Sep 17 00:00:00 2001 From: skykelsey Date: Wed, 16 Nov 2016 09:58:04 -0800 Subject: [PATCH 083/100] Whitespace reformat and optimize imports. --- .../com/apptentive/android/sdk/Apptentive.java | 17 +++++++++++------ 1 file changed, 11 insertions(+), 6 deletions(-) diff --git a/apptentive/src/main/java/com/apptentive/android/sdk/Apptentive.java b/apptentive/src/main/java/com/apptentive/android/sdk/Apptentive.java index 373b8d1c0..5601691bc 100755 --- a/apptentive/src/main/java/com/apptentive/android/sdk/Apptentive.java +++ b/apptentive/src/main/java/com/apptentive/android/sdk/Apptentive.java @@ -17,7 +17,12 @@ import android.text.TextUtils; import android.webkit.MimeTypeMap; -import com.apptentive.android.sdk.model.*; +import com.apptentive.android.sdk.model.CommerceExtendedData; +import com.apptentive.android.sdk.model.CustomData; +import com.apptentive.android.sdk.model.ExtendedData; +import com.apptentive.android.sdk.model.LocationExtendedData; +import com.apptentive.android.sdk.model.StoredFile; +import com.apptentive.android.sdk.model.TimeExtendedData; import com.apptentive.android.sdk.module.engagement.EngagementModule; import com.apptentive.android.sdk.module.messagecenter.MessageManager; import com.apptentive.android.sdk.module.messagecenter.UnreadMessagesListener; @@ -25,7 +30,8 @@ import com.apptentive.android.sdk.module.metric.MetricModule; import com.apptentive.android.sdk.module.rating.IRatingProvider; import com.apptentive.android.sdk.module.survey.OnSurveyFinishedListener; -import com.apptentive.android.sdk.storage.*; +import com.apptentive.android.sdk.storage.DeviceManager; +import com.apptentive.android.sdk.storage.PersonManager; import com.apptentive.android.sdk.util.Constants; import com.apptentive.android.sdk.util.Util; @@ -33,9 +39,9 @@ import org.json.JSONObject; import java.io.ByteArrayInputStream; - import java.io.InputStream; -import java.util.*; +import java.util.ArrayList; +import java.util.Map; /** * This class contains the complete API for accessing Apptentive features from within your app. @@ -1074,8 +1080,7 @@ public static void sendAttachmentFile(InputStream is, String mimeType) { message.setSenderId(ApptentiveInternal.getInstance().getPersonId()); ArrayList attachmentStoredFiles = new ArrayList(); - String localFilePath = Util.generateCacheFilePathFromNonceOrPrefix(ApptentiveInternal.getInstance().getApplicationContext(), - message.getNonce(), null); + String localFilePath = Util.generateCacheFilePathFromNonceOrPrefix(ApptentiveInternal.getInstance().getApplicationContext(), message.getNonce(), null); String extension = MimeTypeMap.getSingleton().getExtensionFromMimeType(mimeType); if (!TextUtils.isEmpty(extension)) { From 734615ba1a1a7395e1b6d5664168e2a43fa627bf Mon Sep 17 00:00:00 2001 From: skykelsey Date: Wed, 16 Nov 2016 10:06:10 -0800 Subject: [PATCH 084/100] Fix two javadoc warnings. --- apptentive/build.gradle | 1 + .../src/main/java/com/apptentive/android/sdk/Apptentive.java | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/apptentive/build.gradle b/apptentive/build.gradle index 9367661d7..8eb7d47b4 100644 --- a/apptentive/build.gradle +++ b/apptentive/build.gradle @@ -129,6 +129,7 @@ task androidJavadocs(type: Javadoc) { include 'com/apptentive/android/sdk/module/rating/IRatingProvider.java' include 'com/apptentive/android/sdk/module/messagecenter/UnreadMessagesListener.java' include 'com/apptentive/android/sdk/module/survey/OnSurveyFinishedListener.java' + include 'com/apptentive/android/sdk/model/CustomData.java' include 'com/apptentive/android/sdk/model/ExtendedData.java' include 'com/apptentive/android/sdk/model/CommerceExtendedData.java' include 'com/apptentive/android/sdk/model/LocationExtendedData.java' diff --git a/apptentive/src/main/java/com/apptentive/android/sdk/Apptentive.java b/apptentive/src/main/java/com/apptentive/android/sdk/Apptentive.java index 5601691bc..98e065672 100755 --- a/apptentive/src/main/java/com/apptentive/android/sdk/Apptentive.java +++ b/apptentive/src/main/java/com/apptentive/android/sdk/Apptentive.java @@ -505,7 +505,7 @@ public static boolean isApptentivePushNotification(Map data) { * notification is received. Pass the generated PendingIntent to * {@link android.support.v4.app.NotificationCompat.Builder#setContentIntent} to allow Apptentive * to display Interactions such as Message Center. This method replaces the deprecated - * {@link #setPendingPushNotification(Intent)}. Calling this method for a push {@Intent} that did + * {@link #setPendingPushNotification(Intent)}. Calling this method for a push {@link Intent} that did * not come from Apptentive will return a null object. If you receive a null object, your app will * need to handle this notification itself.

*

This is the method you will likely need if you integrated using:

From 609395f8fc112131cde9089425dbafb45079d81b Mon Sep 17 00:00:00 2001 From: skykelsey Date: Wed, 16 Nov 2016 10:31:15 -0800 Subject: [PATCH 085/100] Fix test broken in merge by reimporting deleted classes. --- .../sdk/tests/module/engagement/DataObjectQueryTest.java | 3 --- 1 file changed, 3 deletions(-) diff --git a/tests/test-app/src/androidTest/java/com/apptentive/android/sdk/tests/module/engagement/DataObjectQueryTest.java b/tests/test-app/src/androidTest/java/com/apptentive/android/sdk/tests/module/engagement/DataObjectQueryTest.java index 96a3599bc..3c28fd3b9 100644 --- a/tests/test-app/src/androidTest/java/com/apptentive/android/sdk/tests/module/engagement/DataObjectQueryTest.java +++ b/tests/test-app/src/androidTest/java/com/apptentive/android/sdk/tests/module/engagement/DataObjectQueryTest.java @@ -12,9 +12,6 @@ import com.apptentive.android.sdk.Apptentive; import com.apptentive.android.sdk.ApptentiveInternal; import com.apptentive.android.sdk.model.Sdk; -import com.apptentive.android.sdk.tests.ApptentiveInstrumentationTestCase; -import com.apptentive.android.sdk.tests.util.FileUtil; -import com.apptentive.android.sdk.ApptentiveLog; import com.apptentive.android.sdk.module.engagement.interaction.model.Interaction; import com.apptentive.android.sdk.storage.DeviceManager; import com.apptentive.android.sdk.storage.PersonManager; From 3f54d65f988e64529a762526e906cac1b57f0859 Mon Sep 17 00:00:00 2001 From: skykelsey Date: Thu, 17 Nov 2016 12:10:25 -0800 Subject: [PATCH 086/100] Bring Message Center up to Google Talkback accessibility compliance. ANDROID-812 --- .../view/holder/IncomingCompoundMessageHolder.java | 11 ++++++++++- .../view/holder/OutgoingCompoundMessageHolder.java | 11 +++++++++++ .../sdk/util/image/ImageGridViewAdapter.java | 5 +++++ .../res/layout/apptentive_image_grid_view_item.xml | 6 ++++-- .../main/res/layout/apptentive_message_center.xml | 3 ++- .../layout/apptentive_message_center_composer.xml | 9 +++++---- .../layout/apptentive_message_center_who_card.xml | 12 ++++++------ apptentive/src/main/res/values/strings.xml | 14 +++++++++++++- 8 files changed, 56 insertions(+), 15 deletions(-) diff --git a/apptentive/src/main/java/com/apptentive/android/sdk/module/messagecenter/view/holder/IncomingCompoundMessageHolder.java b/apptentive/src/main/java/com/apptentive/android/sdk/module/messagecenter/view/holder/IncomingCompoundMessageHolder.java index 07e6a7fe1..3302f5b1a 100644 --- a/apptentive/src/main/java/com/apptentive/android/sdk/module/messagecenter/view/holder/IncomingCompoundMessageHolder.java +++ b/apptentive/src/main/java/com/apptentive/android/sdk/module/messagecenter/view/holder/IncomingCompoundMessageHolder.java @@ -6,9 +6,11 @@ package com.apptentive.android.sdk.module.messagecenter.view.holder; +import android.accessibilityservice.AccessibilityServiceInfo; import android.support.v7.widget.RecyclerView; import android.text.TextUtils; import android.view.View; +import android.view.accessibility.AccessibilityManager; import android.widget.TextView; import com.apptentive.android.sdk.R; @@ -26,6 +28,8 @@ import java.util.ArrayList; import java.util.List; +import static android.content.Context.ACCESSIBILITY_SERVICE; + public class IncomingCompoundMessageHolder extends MessageHolder { public ApptentiveAvatarView avatar; @@ -59,7 +63,12 @@ public void bindView(MessageCenterFragment fragment, final RecyclerView parent, int viewWidth = container.getMeasuredWidth(); messageBodyView.setText(message.getBody()); - + // We have to disable text selection, or the Google TalkBack won't read this unless it's selected. It's too tiny to select by itself easily. + AccessibilityManager accessibilityManager = (AccessibilityManager) fragment.getContext().getSystemService(ACCESSIBILITY_SERVICE); + if (accessibilityManager != null) { + boolean talkbackNotEnabled = accessibilityManager.getEnabledAccessibilityServiceList(AccessibilityServiceInfo.FEEDBACK_SPOKEN).isEmpty(); + messageBodyView.setTextIsSelectable(talkbackNotEnabled); + } String name = message.getSenderUsername(); if (name != null && !name.isEmpty()) { nameView.setVisibility(View.VISIBLE); diff --git a/apptentive/src/main/java/com/apptentive/android/sdk/module/messagecenter/view/holder/OutgoingCompoundMessageHolder.java b/apptentive/src/main/java/com/apptentive/android/sdk/module/messagecenter/view/holder/OutgoingCompoundMessageHolder.java index 2c23e9430..fa8583d7f 100644 --- a/apptentive/src/main/java/com/apptentive/android/sdk/module/messagecenter/view/holder/OutgoingCompoundMessageHolder.java +++ b/apptentive/src/main/java/com/apptentive/android/sdk/module/messagecenter/view/holder/OutgoingCompoundMessageHolder.java @@ -6,9 +6,11 @@ package com.apptentive.android.sdk.module.messagecenter.view.holder; +import android.accessibilityservice.AccessibilityServiceInfo; import android.support.v7.widget.RecyclerView; import android.text.TextUtils; import android.view.View; +import android.view.accessibility.AccessibilityManager; import android.widget.TextView; import com.apptentive.android.sdk.R; @@ -24,6 +26,8 @@ import java.util.ArrayList; import java.util.List; +import static android.content.Context.ACCESSIBILITY_SERVICE; + public class OutgoingCompoundMessageHolder extends MessageHolder { public View root; @@ -46,7 +50,14 @@ public OutgoingCompoundMessageHolder(View itemView) { public void bindView(MessageCenterFragment fragment, final RecyclerView recyclerView, final MessageCenterRecyclerViewAdapter adapter, final CompoundMessage message) { super.bindView(fragment, recyclerView, message); imageBandView.setupUi(); + messageBodyView.setText(message.getBody()); + // We have to disable text selection, or the Google TalkBack won't read this unless it's selected. It's too tiny to select by itself easily. + AccessibilityManager accessibilityManager = (AccessibilityManager) fragment.getContext().getSystemService(ACCESSIBILITY_SERVICE); + if (accessibilityManager != null) { + boolean talkbackNotEnabled = accessibilityManager.getEnabledAccessibilityServiceList(AccessibilityServiceInfo.FEEDBACK_SPOKEN).isEmpty(); + messageBodyView.setTextIsSelectable(talkbackNotEnabled); + } boolean showProgress; Double createdAt = message.getCreatedAt(); diff --git a/apptentive/src/main/java/com/apptentive/android/sdk/util/image/ImageGridViewAdapter.java b/apptentive/src/main/java/com/apptentive/android/sdk/util/image/ImageGridViewAdapter.java index 90f4b6e88..acfc3f1c0 100644 --- a/apptentive/src/main/java/com/apptentive/android/sdk/util/image/ImageGridViewAdapter.java +++ b/apptentive/src/main/java/com/apptentive/android/sdk/util/image/ImageGridViewAdapter.java @@ -347,10 +347,15 @@ public void onClick(View v) { } } + // Always reset contentDescription to original state. + image.setContentDescription(image.getContext().getResources().getString(R.string.apptentive_message_center_content_description_attachment)); + if (Util.isMimeTypeImage(data.mimeType)) { if (TextUtils.isEmpty(data.originalPath)) { + // This is the "Add Attachment" image image.setScaleType(ImageView.ScaleType.CENTER_INSIDE); placeholderResId = R.drawable.apptentive_ic_add; + image.setContentDescription(image.getContext().getResources().getString(R.string.apptentive_message_center_content_description_attachment_add)); indicator.setVisibility(View.GONE); bLoadThumbnail = false; progressBarLoading.setVisibility(View.GONE); diff --git a/apptentive/src/main/res/layout/apptentive_image_grid_view_item.xml b/apptentive/src/main/res/layout/apptentive_image_grid_view_item.xml index 43a87a201..c083144fb 100644 --- a/apptentive/src/main/res/layout/apptentive_image_grid_view_item.xml +++ b/apptentive/src/main/res/layout/apptentive_image_grid_view_item.xml @@ -15,7 +15,8 @@ android:layout_width="match_parent" android:layout_height="match_parent" android:scaleType="fitCenter" - android:src="@null"/> + android:src="@null" + android:contentDescription="@string/apptentive_message_center_content_description_attachment"/> + android:src="@drawable/apptentive_ic_image_picker_unselected" + android:contentDescription="@string/apptentive_message_center_content_description_attachment_delete"/> + android:src="@drawable/apptentive_ic_compose" + android:contentDescription="@string/apptentive_message_center_fab_content_description"/> \ No newline at end of file diff --git a/apptentive/src/main/res/layout/apptentive_message_center_composer.xml b/apptentive/src/main/res/layout/apptentive_message_center_composer.xml index b7f36d591..b233eaeb6 100644 --- a/apptentive/src/main/res/layout/apptentive_message_center_composer.xml +++ b/apptentive/src/main/res/layout/apptentive_message_center_composer.xml @@ -32,7 +32,7 @@ android:paddingRight="10dp" android:paddingEnd="10dp" android:src="@drawable/apptentive_ic_composing_close" - android:contentDescription="Close"/> + android:contentDescription="@string/apptentive_message_center_content_description_close_button"/> + android:contentDescription="@string/apptentive_message_center_content_description_send_button"/> + android:contentDescription="@string/apptentive_message_center_content_description_attach_button"/> + android:numColumns="@integer/apptentive_image_grid_default_column_number" + android:contentDescription="@string/apptentive_message_center_content_description_attachments_list"/>
diff --git a/apptentive/src/main/res/layout/apptentive_message_center_who_card.xml b/apptentive/src/main/res/layout/apptentive_message_center_who_card.xml index b8a7f616e..1d5fb2caf 100644 --- a/apptentive/src/main/res/layout/apptentive_message_center_who_card.xml +++ b/apptentive/src/main/res/layout/apptentive_message_center_who_card.xml @@ -43,7 +43,8 @@ android:layout_width="match_parent" android:layout_height="wrap_content" android:textAppearance="@style/Apptentive.TextAppearance.Body1" - android:inputType="textCapSentences"/> + android:inputType="textCapSentences" + android:contentDescription="@string/apptentive_name"/> + android:inputType="textEmailAddress" + android:contentDescription="@string/apptentive_email"/> + style="?apptentiveInteractionButtonStyle"/>