8000 [🆕] NT-790 Additional Qualtrics properties by eoji · Pull Request #715 · kickstarter/android-oss · GitHub
[go: up one dir, main page]
More Web Proxy on the site http://driver.im/
Skip to content

[🆕] NT-790 Additional Qualtrics properties #715

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 3 commits into from
Jan 17, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 11 additions & 0 deletions app/src/main/java/com/kickstarter/ApplicationModule.java
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,7 @@
import com.kickstarter.libs.qualifiers.AppRatingPreference;
import com.kickstarter.libs.qualifiers.ApplicationContext;
import com.kickstarter.libs.qualifiers.ConfigPreference;
import com.kickstarter.libs.qualifiers.FirstSessionPreference;
import com.kickstarter.libs.qualifiers.GamesNewsletterPreference;
import com.kickstarter.libs.qualifiers.GoRewardlessPreference;
import com.kickstarter.libs.qualifiers.KoalaEndpoint;
Expand Down Expand Up @@ -117,6 +118,7 @@ static Environment provideEnvironment(final @NonNull @ActivitySamplePreference I
final @NonNull CookieManager cookieManager,
final @NonNull CurrentConfigType currentConfig,
final @NonNull CurrentUserType currentUser,
final @NonNull @FirstSessionPreference BooleanPreferenceType firstSessionPreference,
final @NonNull @GoRewardlessPreference BooleanPreferenceType goRewardlessPreference,
final @NonNull Gson gson,
final @NonNull @AppRatingPreference BooleanPreferenceType hasSeenAppRatingPreference,
Expand Down Expand Up @@ -144,6 +146,7 @@ static Environment provideEnvironment(final @NonNull @ActivitySamplePreference I
.cookieManager(cookieManager)
.currentConfig(currentConfig)
.currentUser(currentUser)
.firstSessionPreference(firstSessionPreference)
.goRewardlessPreference(goRewardlessPreference)
.gson(gson)
.hasSeenAppRatingPreference(hasSeenAppRatingPreference)
Expand Down Expand Up @@ -382,6 +385,14 @@ static BooleanPreferenceType provideAppRatingPreference(final @NonNull SharedPre
return new BooleanPreference(sharedPreferences, SharedPreferenceKey.HAS_SEEN_APP_RATING);
}

@Provides
@Singleton
@FirstSessionPreference
@NonNull
static BooleanPreferenceType provideFirstSessionPreference(final @NonNull SharedPreferences sharedPreferences) {
return new BooleanPreference(sharedPreferences, SharedPreferenceKey.FIRST_SESSION);
}

@Provides
@Singleton
@NativeCheckoutPreference
Expand Down
2 changes: 2 additions & 0 deletions app/src/main/java/com/kickstarter/libs/Environment.java
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ public abstract class Environment implements Parcelable {
public abstract CookieManager cookieManager();
public abstract CurrentConfigType currentConfig();
public abstract CurrentUserType currentUser();
public abstract BooleanPreferenceType firstSessionPreference();
public abstract BooleanPreferenceType goRewardlessPreference();
public abstract Gson gson();
public abstract BooleanPreferenceType hasSeenAppRatingPreference();
Expand Down Expand Up @@ -55,6 +56,7 @@ public abstract static class Builder {
public abstract Builder cookieManager(CookieManager __);
public abstract Builder currentConfig(CurrentConfigType __);
public abstract Builder currentUser(CurrentUserType __);
public abstract Builder firstSessionPreference(BooleanPreferenceType __);
public abstract Builder goRewardlessPreference(BooleanPreferenceType __);
public abstract Builder gson(Gson __);
public abstract Builder hasSeenAppRatingPreference(BooleanPreferenceType __);
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
package com.kickstarter.libs.qualifiers

import javax.inject.Qualifier

@Qualifier
annotation class FirstSessionPreference
8000
Original file line number Diff line number Diff line change
Expand Up @@ -9,4 +9,8 @@ enum class QualtricsIntercept(private val prodId: String, private val testId: St
else -> testId
}
}

fun impressionCountKey(packageName: String): String {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I was under the impression (lol) that we didn't need the impression count anymore if we're confident that Qualtrics won't prompt us once we've taken the survey? Anyway, suppose no real harm in keeping it unless you wanted to simplify your code without it.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This count is so we don't show users the prompt more than 3 times. Otherwise, we'd be hounding them until they took the survey.

return id(packageName) + "_impression_count"
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ private SharedPreferenceKey() {}

public static final String ACCESS_TOKEN = "access_token";
public static final String CONFIG = "config";
public static final String FIRST_SESSION = "first_session";
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do you need to persist this outside of Qualtrics? I figured since you're able to get the value stored in Qualtrics' properties you could check if there is already something there otherwise set it (for the first time user thing).

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I learned the hard way that Qualtrics calls the initialization block more than once 😒 so that's why I'm moved it here

public static final String GO_REWARDLESS = "go_rewardless";
public static final String HAS_SEEN_APP_RATING = "has_seen_app_rating";
public static final String HAS_SEEN_GAMES_NEWSLETTER = "has_seen_games_newsletter";
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,6 @@
import com.kickstarter.libs.utils.ViewUtils;
import com.kickstarter.models.QualtricsIntercept;
import com.kickstarter.models.QualtricsResult;
import com.kickstarter.models.User;
import com.kickstarter.services.apiresponses.InternalBuildEnvelope;
import com.kickstarter.ui.IntentKey;
import com.kickstarter.ui.adapters.DiscoveryDrawerAdapter;
Expand Down Expand Up @@ -104,11 +103,6 @@ protected void onCreate(final @Nullable Bundle savedInstanceState) {
this.sortTabLayout.setupWithViewPager(this.sortViewPager);
addTabSelectedListenerToTabLayout();

this.viewModel.outputs.currentUser()
.compose(bindToLifecycle())
.compose(observeForUI())
.subscribe(this::setUpQualtrics);

this.viewModel.outputs.expandSortTabLayout()
.compose(bindToLifecycle())
.compose(observeForUI())
Expand Down Expand Up @@ -174,16 +168,6 @@ protected void onCreate(final @Nullable Bundle savedInstanceState) {
.compose(observeForUI())
.subscribe(__ -> this.startProfileActivity());

this.viewModel.outputs.qualtricsPromptIsGone()
.compose(bindToLifecycle())
.compose(observeForUI())
.subscribe(ViewUtils.setInvisible(this.qualtricsPrompt));

this.viewModel.outputs.showQualtricsSurvey()
.compose(bindToLifecycle())
.compose(observeForUI())
.subscribe(this::showQualtricsSurvey);

this.viewModel.outputs.showSettings()
.compose(bindToLifecycle())
.compose(observeForUI())
Expand All @@ -204,6 +188,28 @@ protected void onCreate(final @Nullable Bundle savedInstanceState) {
.compose(observeForUI())
.subscribe(this::showMenuIconWithIndicator);

//region Qualtrics
this.viewModel.outputs.qualtricsPromptIsGone()
.compose(bindToLifecycle())
.compose(observeForUI())
.subscribe(ViewUtils.setInvisible(this.qualtricsPrompt));

this.viewModel.outputs.setUpQualtrics()
.compose(bindToLifecycle())
.compose(observeForUI())
.subscribe(this::setUpQualtrics);

this.viewModel.outputs.showQualtricsSurvey()
.compose(bindToLifecycle())
.compose(observeForUI())
.subscribe(this::showQualtricsSurvey);

this.viewModel.outputs.updateImpressionCount()
.compose(bindToLifecycle())
.compose(observeForUI())
.subscribe(this::updateImpressionCount);
//endregion

RxDrawerLayout.drawerOpen(this.discoveryLayout, GravityCompat.START)
.skip(1)
.compose(bindToLifecycle())
Expand Down Expand Up @@ -257,16 +263,14 @@ public void onTabReselected(final TabLayout.Tab tab) {
});
}

private void setUpQualtrics(final @Nullable User user) {
private void setUpQualtrics(final boolean firstAppSession) {
Qualtrics.instance().initialize(Secrets.Qualtrics.BRAND_ID,
Secrets.Qualtrics.ZONE_ID,
QualtricsIntercept.NATIVE_APP_FEEDBACK.id(BuildConfig.APPLICATION_ID),
this,
initializationResult -> {
if (initializationResult.passed()) {
Qualtrics.instance().properties.setString("package_name", BuildConfig.APPLICATION_ID);
Qualtrics.instance().properties.setString("language", Locale.getDefault().getLanguage());
Qualtrics.instance().properties.setString("logged_in", Boolean.toString(ObjectUtils.isNotNull(user)));
updateQualtricsProperties(firstAppSession);

Qualtrics.instance().evaluateTargetingLogic(targetingResult -> DiscoveryActivity.this.viewModel.inputs.qualtricsResult(new QualtricsResult(targetingResult)));
}
Expand Down Expand Up @@ -343,4 +347,17 @@ private void showBuildAlert(final @NonNull InternalBuildEnvelope envelope) {
.show();
}

private void updateImpressionCount(final @NonNull QualtricsIntercept qualtricsIntercept) {
final String key = qualtricsIntercept.impressionCountKey(BuildConfig.APPLICATION_ID);

final double initialCount = ObjectUtils.coalesce(Qualtrics.instance().properties.getNumber(key), 0.0);
Qualtrics.instance().properties.setNumber(key, initialCount + 1.0);
}

private void updateQualtricsProperties(final boolean firstAppSession) {
Qualtrics.instance().properties.setString("first_app_session", Boolean.toString(firstAppSession));
Qualtrics.instance().properties.setString("language", Locale.getDefault().getLanguage());
Qualtrics.instance().properties.setString("package_name", BuildConfig.APPLICATION_ID);
}

}
10000
Original file line number Diff line number Diff line change
Expand Up @@ -8,15 +8,18 @@
import com.kickstarter.libs.CurrentConfigType;
import com.kickstarter.libs.CurrentUserType;
import com.kickstarter.libs.Environment;
import com.kickstarter.libs.preferences.BooleanPreferenceType;
import com.kickstarter.libs.rx.transformers.Transformers;
import com.kickstarter.libs.utils.BooleanUtils;
import com.kickstarter.libs.utils.DiscoveryDrawerUtils;
import com.kickstarter.libs.utils.DiscoveryUtils;
import com.kickstarter.libs.utils.IntegerUtils;
import com.kickstarter.libs.utils.ObjectUtils;
import com.kickstarter.libs.utils.StringUtils;
import com.kickstarter.libs.utils.UrlUtils;
import com.kickstarter.libs.utils.UserUtils;
import com.kickstarter.models.Category;
import com.kickstarter.models.QualtricsIntercept;
import com.kickstarter.models.QualtricsResult;
import com.kickstarter.models.User;
import com.kickstarter.services.ApiClientType;
Expand Down Expand Up @@ -46,7 +49,6 @@

import static com.kickstarter.libs.rx.transformers.Transformers.combineLatestPair;
import static com.kickstarter.libs.rx.transformers.Transformers.neverError;
import static com.kickstarter.libs.rx.transformers.Transformers.takePairWhen;
import static com.kickstarter.libs.rx.transformers.Transformers.takeWhen;

public interface DiscoveryViewModel {
Expand All @@ -69,9 +71,6 @@ interface Inputs extends DiscoveryDrawerAdapter.Delegate, DiscoveryPagerAdapter.
}

interface Outputs {
/** Emits the current user. */
Observable<User> currentUser();

/** Emits a boolean that determines if the drawer is open or not. */
Observable<Boolean> drawerIsOpen();

Expand All @@ -97,6 +96,9 @@ interface Outputs {
/** Emits a list of pages that should be cleared of all their content. */
Observable<List<Integer>> clearPages();

/** Emits when we should set up {@link com.qualtrics.digital.Qualtrics} with first app session boolean. */
Observable<Boolean> setUpQualtrics();

/** Emits when a newer build is available and an alert should be shown. */
Observable<InternalBuildEnvelope> showBuildCheckAlert();

Expand Down Expand Up @@ -129,13 +131,17 @@ interface Outputs {

/** Start settings activity. */
Observable<Void> showSettings();

/** Emits a {@link QualtricsIntercept} whose impression count property should be incremented. */
Observable<QualtricsIntercept> updateImpressionCount();
}

final class ViewModel extends ActivityViewModel<DiscoveryActivity> implements Inputs, Outputs {
private final ApiClientType apiClient;
private final BuildCheck buildCheck;
private final CurrentUserType currentUserType;
private final CurrentConfigType currentConfigType;
private final BooleanPreferenceType firstSessionPreference;
private final WebClientType webClient;

public ViewModel(final @NonNull Environment environment) {
Expand All @@ -145,6 +151,7 @@ public ViewModel(final @NonNull Environment environment) {
this.buildCheck = environment.buildCheck();
this.currentConfigType = environment.currentConfig();
this.currentUserType = environment.currentUser();
this.firstSessionPreference = environment.firstSessionPreference();
this.webClient = environment.webClient();

this.buildCheck.bind(this, this.webClient);
Expand All @@ -164,10 +171,6 @@ public ViewModel(final @NonNull Environment environment) {
final Observable<User> changedUser = currentUser
.distinctUntilChanged((u1, u2) -> !UserUtils.userHasChanged(u1, u2));

changedUser
.compose(bindToLifecycle())
.subscribe(this.currentUser);

changedUser
.compose(bindToLifecycle())
.subscribe(updatedUser ->
Expand Down Expand Up @@ -316,6 +319,18 @@ public ViewModel(final @NonNull Environment environment) {
.distinctUntilChanged()
.compose(bindToLifecycle());

Observable.just(this.firstSessionPreference)
.map(pref -> {
if (pref.isSet()) {
pref.set(false);
} else {
pref.set(true);
}
return pref.get();
})
.compose(bindToLifecycle())
.subscribe(this.setUpQualtrics::onNext);

this.qualtricsResult
.map(QualtricsResult::resultPassed)
.map(BooleanUtils::negate)
Expand All @@ -328,18 +343,39 @@ public ViewModel CEB7 (final @NonNull Environment environment) {
.compose(bindToLifecycle())
.subscribe(this.qualtricsPromptIsGone);

this.qualtricsResult
final Observable<QualtricsResult> passedQualtricsResult = this.qualtricsResult
.filter(QualtricsResult::resultPassed)
.distinctUntilChanged();

passedQualtricsResult
.map(__ -> QualtricsIntercept.NATIVE_APP_FEEDBACK)
.compose(bindToLifecycle())
.subscribe(this.updateImpressionCount);

passedQualtricsResult
.map(result -> {
result.recordImpression();
return result;
})
.compose(takePairWhen(this.qualtricsConfirmClicked))
.map(resultAndClick -> {
resultAndClick.first.recordClick();
return resultAndClick.first.surveyUrl();
.compose(combineLatestPair(currentUser))
.compose(takeWhen(this.qualtricsConfirmClicked))
.map(resultAndUser -> {
final QualtricsResult qualtricsResult = resultAndUser.first;
qualtricsResult.recordClick();
final User user = resultAndUser.second;
return Pair.create(qualtricsResult.surveyUrl(), user);
})
.filter(surveyAndUser -> StringUtils.isPresent(surveyAndUser.first))
.map(surveyAndUser -> {
final String surveyUrl = surveyAndUser.first;
final User user = surveyAndUser.second;
final boolean userLoggedIn = user != null;
String url = UrlUtils.INSTANCE.appendQueryParameter(surveyUrl, "logged_in", Boolean.toString(userLoggedIn));
if (userLoggedIn) {
url = UrlUtils.INSTANCE.appendQueryParameter(url, "user_uid", Long.toString(user.id()));
}
return url;
})
.filter(StringUtils::isPresent)
.compose(bindToLifecycle())
.subscribe(this.showQualtricsSurvey);
}
Expand Down Expand Up @@ -372,13 +408,13 @@ private boolean userHasNoUnreadMessagesOrUnseenActivity(final @Nullable User use
private final PublishSubject<Void> settingsClick = PublishSubject.create();
private final PublishSubject<NavigationDrawerData.Section.Row> topFilterRowClick = PublishSubject.create();

private final BehaviorSubject<User> currentUser = BehaviorSubject.create();
private final BehaviorSubject<List<Integer>> clearPages = BehaviorSubject.create();
private final BehaviorSubject<Boolean> drawerIsOpen = BehaviorSubject.create();
private final BehaviorSubject<Boolean> expandSortTabLayout = BehaviorSubject.create();
private final BehaviorSubject<NavigationDrawerData> navigationDrawerData = BehaviorSubject.create();
private final BehaviorSubject<Boolean> qualtricsPromptIsGone = BehaviorSubject.create();
private final BehaviorSubject<Pair<List<Category>, Integer>> rootCategoriesAndPosition = BehaviorSubject.create();
private final BehaviorSubject<Boolean> setUpQualtrics = BehaviorSubject.create();
private final Observable<Void> showActivityFeed;
private final Observable<InternalBuildEnvelope> showBuildCheckAlert;
private final Observable<Void> showCreatorDashboard;
Expand All @@ -390,6 +426,7 @@ private boolean userHasNoUnreadMessagesOrUnseenActivity(final @Nullable User use
private final Observable<Void> showProfile;
private final PublishSubject<String> showQualtricsSurvey = PublishSubject.create();
private final Observable<Void> showSettings;
private final PublishSubject<QualtricsIntercept> updateImpressionCount = PublishSubject.create();
private final BehaviorSubject<DiscoveryParams> updateParamsForPage = BehaviorSubject.create();
private final BehaviorSubject<DiscoveryParams> updateToolbarWithParams = BehaviorSubject.create();

Expand Down Expand Up @@ -454,9 +491,6 @@ private boolean userHasNoUnreadMessagesOrUnseenActivity(final @Nullable User use
this.topFilterRowClick.onNext(row);
}

@Override public @NonNull Observable<User> currentUser() {
return this.currentUser;
}
@Override public @NonNull Observable<List<Integer>> clearPages() {
return this.clearPages;
}
Expand All @@ -475,6 +509,9 @@ private boolean userHasNoUnreadMessagesOrUnseenActivity(final @Nullable User use
@Override public @NonNull Observable<Pair<List<Category>, Integer>> rootCategoriesAndPosition() {
return this.rootCategoriesAndPosition;
}
@Override public @NonNull Observable<Boolean> setUpQualtrics() {
return this.setUpQualtrics;
}
@Override public @NonNull Observable<Void> showActivityFeed() {
return this.showActivityFeed;
}
Expand Down Expand Up @@ -508,6 +545,9 @@ private boolean userHasNoUnreadMessagesOrUnseenActivity(final @Nullable User use
@Override public @NonNull Observable<Void> showSettings() {
return this.showSettings;
}
@Override public @NonNull Observable<QualtricsIntercept> updateImpressionCount() {
return this.updateImpressionCount;
}
@Override public @NonNull Observable<DiscoveryParams> updateParamsForPage() {
return this.updateParamsForPage;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,4 +13,13 @@ class QualtricsInterceptTest : KSRobolectricTestCase() {
TestCase.assertEquals("SI_6nSwomRDiWXeXEV", QualtricsIntercept.NATIVE_APP_FEEDBACK.id("com.kickstarter.kickstarter.internal.debug"))
TestCase.assertEquals("SI_6nSwomRDiWXeXEV", QualtricsIntercept.NATIVE_APP_FEEDBACK.id("boop"))
}

@Test
fun testImpressionCountKey() {
TestCase.assertEquals("SI_3VjP7wWiUZg2wBf_impression_count", QualtricsIntercept.NATIVE_APP_FEEDBACK.impressionCountKey("com.kickstarter.kickstarter"))
TestCase.assertEquals("SI_6nSwomRDiWXeXEV_impression_count", QualtricsIntercept.NATIVE_APP_FEEDBACK.impressionCountKey("com.kickstarter.kickstarter.debug"))
TestCase.assertEquals("SI_6nSwomRDiWXeXEV_impression_count", QualtricsIntercept.NATIVE_APP_FEEDBACK.impressionCountKey("com.kickstarter.kickstarter.internal"))
TestCase.assertEquals("SI_6nSwomRDiWXeXEV_impression_count", QualtricsIntercept.NATIVE_APP_FEEDBACK.impressionCountKey("com.kickstarter.kickstarter.internal.debug"))
TestCase.assertEquals("SI_6nSwomRDiWXeXEV_impression_count", QualtricsIntercept.NATIVE_APP_FEEDBACK.impressionCountKey("boop"))
}
}
Loading
0