Skip to content

Commit

Permalink
Merge pull request #900 from StepicOrg/release/1.195
Browse files Browse the repository at this point in the history
Release/1.195
  • Loading branch information
rostikjoystick authored Oct 21, 2021
2 parents a4c8d03 + 5c46eba commit 284a218
Show file tree
Hide file tree
Showing 51 changed files with 1,275 additions and 70 deletions.
4 changes: 4 additions & 0 deletions app/src/main/java/org/stepic/droid/analytic/Analytic.java
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.stepik.android.domain.base.analytic.AnalyticEvent;
import org.stepik.android.domain.base.analytic.UserProperty;

import java.util.Map;

Expand Down Expand Up @@ -361,10 +362,13 @@ interface Traces {
void setStreaksNotificationsEnabled(boolean isEnabled);
void setTeachingCoursesCount(int coursesCount);
void setGoogleServicesAvailable(boolean isAvailable);


void reportAmplitudeEvent(@NotNull String eventName, @Nullable Map<String, Object> params);
void reportAmplitudeEvent(@NotNull String eventName);

void report(@NotNull AnalyticEvent analyticEvent);
void reportUserProperty(@NotNull UserProperty userProperty);

void setUserProperty(@NotNull String name, @NotNull String value);

Expand Down
67 changes: 57 additions & 10 deletions app/src/main/java/org/stepic/droid/analytic/AnalyticImpl.kt
Original file line number Diff line number Diff line change
Expand Up @@ -18,10 +18,13 @@ import com.yandex.metrica.profile.UserProfile
import org.json.JSONObject
import org.stepic.droid.base.App
import org.stepic.droid.configuration.Config
import org.stepic.droid.configuration.RemoteConfig
import org.stepic.droid.di.AppSingleton
import org.stepic.droid.util.isARSupported
import org.stepik.android.domain.base.analytic.AnalyticEvent
import org.stepik.android.domain.base.analytic.AnalyticSource
import org.stepik.android.domain.base.analytic.UserProperty
import org.stepik.android.domain.base.analytic.UserPropertySource
import ru.nobird.android.view.base.ui.extension.isNightModeEnabled
import java.util.HashMap
import java.util.Locale
Expand All @@ -36,6 +39,8 @@ constructor(
private val stepikAnalytic: StepikAnalytic
) : Analytic {
private companion object {
private const val FIREBASE_USER_PROPERTY_NAME_LIMIT = 24
private const val FIREBASE_USER_PROPERTY_VALUE_LIMIT = 36
private const val FIREBASE_LENGTH_LIMIT = 40

inline fun updateYandexUserProfile(mutation: UserProfile.Builder.() -> Unit) {
Expand Down Expand Up @@ -69,9 +74,9 @@ constructor(
apply(Attribute.customBoolean(AmplitudeAnalytic.Properties.IS_AR_SUPPORTED).withValue(context.isARSupported()))
}

firebaseAnalytics.setUserProperty(AmplitudeAnalytic.Properties.PUSH_PERMISSION, if (isNotificationsEnabled) "granted" else "not_granted")
firebaseAnalytics.setUserProperty(AmplitudeAnalytic.Properties.IS_NIGHT_MODE_ENABLED, context.isNightModeEnabled().toString())
firebaseAnalytics.setUserProperty(AmplitudeAnalytic.Properties.IS_AR_SUPPORTED, context.isARSupported().toString())
setFirebaseUserProperty(AmplitudeAnalytic.Properties.PUSH_PERMISSION, if (isNotificationsEnabled) "granted" else "not_granted")
setFirebaseUserProperty(AmplitudeAnalytic.Properties.IS_NIGHT_MODE_ENABLED, context.isNightModeEnabled().toString())
setFirebaseUserProperty(AmplitudeAnalytic.Properties.IS_AR_SUPPORTED, context.isARSupported().toString())
}

// Amplitude properties
Expand All @@ -89,38 +94,38 @@ constructor(
override fun setCoursesCount(coursesCount: Int) {
amplitude.identify(Identify().set(AmplitudeAnalytic.Properties.COURSES_COUNT, coursesCount))
updateYandexUserProfile { apply(Attribute.customNumber(AmplitudeAnalytic.Properties.COURSES_COUNT).withValue(coursesCount.toDouble())) }
firebaseAnalytics.setUserProperty(AmplitudeAnalytic.Properties.COURSES_COUNT, coursesCount.toString())
setFirebaseUserProperty(AmplitudeAnalytic.Properties.COURSES_COUNT, coursesCount.toString())
}

override fun setSubmissionsCount(submissionsCount: Long, delta: Long) {
amplitude.identify(Identify().set(AmplitudeAnalytic.Properties.SUBMISSIONS_COUNT, submissionsCount + delta))
updateYandexUserProfile { apply(Attribute.customCounter(AmplitudeAnalytic.Properties.SUBMISSIONS_COUNT).withDelta(delta.toDouble())) }
firebaseAnalytics.setUserProperty(AmplitudeAnalytic.Properties.SUBMISSIONS_COUNT, (submissionsCount + delta).toString())
setFirebaseUserProperty(AmplitudeAnalytic.Properties.SUBMISSIONS_COUNT, (submissionsCount + delta).toString())
}

override fun setScreenOrientation(orientation: Int) {
val orientationName = if (orientation == Configuration.ORIENTATION_PORTRAIT) "portrait" else "landscape"
amplitude.identify(Identify().set(AmplitudeAnalytic.Properties.SCREEN_ORIENTATION, orientationName))
updateYandexUserProfile { apply(Attribute.customString(AmplitudeAnalytic.Properties.SCREEN_ORIENTATION).withValue(orientationName)) }
firebaseAnalytics.setUserProperty(AmplitudeAnalytic.Properties.SCREEN_ORIENTATION, orientationName)
setFirebaseUserProperty(AmplitudeAnalytic.Properties.SCREEN_ORIENTATION, orientationName)
}

override fun setStreaksNotificationsEnabled(isEnabled: Boolean) {
amplitude.identify(Identify().set(AmplitudeAnalytic.Properties.STREAKS_NOTIFICATIONS_ENABLED, if (isEnabled) "enabled" else "disabled"))
updateYandexUserProfile { apply(Attribute.customBoolean(AmplitudeAnalytic.Properties.STREAKS_NOTIFICATIONS_ENABLED).withValue(isEnabled)) }
firebaseAnalytics.setUserProperty(AmplitudeAnalytic.Properties.STREAKS_NOTIFICATIONS_ENABLED.substring(0, 24), if (isEnabled) "enabled" else "disabled")
setFirebaseUserProperty(AmplitudeAnalytic.Properties.STREAKS_NOTIFICATIONS_ENABLED, if (isEnabled) "enabled" else "disabled")
}

override fun setTeachingCoursesCount(coursesCount: Int) {
amplitude.identify(Identify().set(AmplitudeAnalytic.Properties.TEACHING_COURSES_COUNT, coursesCount))
updateYandexUserProfile { apply(Attribute.customNumber(AmplitudeAnalytic.Properties.TEACHING_COURSES_COUNT).withValue(coursesCount.toDouble())) }
firebaseAnalytics.setUserProperty(AmplitudeAnalytic.Properties.TEACHING_COURSES_COUNT, coursesCount.toString())
setFirebaseUserProperty(AmplitudeAnalytic.Properties.TEACHING_COURSES_COUNT, coursesCount.toString())
}

override fun setGoogleServicesAvailable(isAvailable: Boolean) {
amplitude.identify(Identify().set(AmplitudeAnalytic.Properties.IS_GOOGLE_SERVICES_AVAILABLE, isAvailable.toString()))
updateYandexUserProfile { apply(Attribute.customBoolean(AmplitudeAnalytic.Properties.IS_GOOGLE_SERVICES_AVAILABLE).withValue(isAvailable)) }
firebaseAnalytics.setUserProperty(AmplitudeAnalytic.Properties.IS_GOOGLE_SERVICES_AVAILABLE.substring(0, 24), isAvailable.toString())
setFirebaseUserProperty(AmplitudeAnalytic.Properties.IS_GOOGLE_SERVICES_AVAILABLE, isAvailable.toString())
}

override fun report(analyticEvent: AnalyticEvent) {
Expand Down Expand Up @@ -149,6 +154,44 @@ constructor(
}
}

override fun reportUserProperty(userProperty: UserProperty) {
if (UserPropertySource.YANDEX in userProperty.sources) {
val userProfileUpdate =
when (val value = userProperty.value) {
is String ->
Attribute.customString(userProperty.name).withValue(value)
is Boolean ->
Attribute.customBoolean(userProperty.name).withValue(value)
is Number ->
Attribute.customNumber(userProperty.name).withValue(value.toDouble())
else ->
throw IllegalArgumentException("Invalid argument type")
}
updateYandexUserProfile { apply(userProfileUpdate) }
}

if (UserPropertySource.AMPLITUDE in userProperty.sources) {
val identify =
when (val value = userProperty.value) {
is String ->
Identify().set(userProperty.name, value)
is Boolean ->
Identify().set(userProperty.name, value)
is Long ->
Identify().set(userProperty.name, value)
is Double ->
Identify().set(userProperty.name, value)
else ->
throw IllegalArgumentException("Invalid argument type")
}
amplitude.identify(identify)
}

if (UserPropertySource.FIREBASE in userProperty.sources) {
setFirebaseUserProperty(userProperty.name, userProperty.value.toString())
}
}

override fun reportAmplitudeEvent(eventName: String) = reportAmplitudeEvent(eventName, null)
override fun reportAmplitudeEvent(eventName: String, params: Map<String, Any>?) {
syncAmplitudeProperties()
Expand All @@ -171,7 +214,7 @@ constructor(
amplitude.identify(Identify().set(name, value))
updateYandexUserProfile { apply(Attribute.customString(name).withValue(value)) }
firebaseCrashlytics.setCustomKey(name, value)
firebaseAnalytics.setUserProperty(name, value)
setFirebaseUserProperty(name, value)
}
// End of amplitude properties

Expand Down Expand Up @@ -226,6 +269,10 @@ constructor(
reportEvent(eventName, bundle)
}

private fun setFirebaseUserProperty(name: String, value: String) {
firebaseAnalytics.setUserProperty(name.take(FIREBASE_USER_PROPERTY_NAME_LIMIT), value.take(FIREBASE_USER_PROPERTY_VALUE_LIMIT))
}

private fun castStringToFirebaseEvent(eventName: String): String {
val firebaseEventName = eventName
.decapitalize(Locale.ENGLISH)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,14 +5,12 @@ object RemoteConfig {

const val MIN_DELAY_RATE_DIALOG_SEC = "min_delay_rate_dialog_sec"
const val SHOW_STREAK_DIALOG_AFTER_LOGIN = "show_streak_dialog_after_login"
const val SHOW_NOTIFICATIONS_BADGES = "show_notifications_badges"
const val ADAPTIVE_COURSES = "adaptive_courses_android"
const val ADAPTIVE_BACKEND_URL = "adaptive_backend_url"
const val IS_LOCAL_SUBMISSIONS_ENABLED = "is_local_submissions_enabled"
const val IS_PEER_REVIEW_ENABLED = "is_peer_review_enabled"
const val IS_DISABLED_STEPS_SUPPORTED = "is_disabled_steps_supported"
const val SEARCH_QUERY_PARAMS_ANDROID = "search_query_params_android"
const val IS_NEW_HOME_SCREEN_ENABLED = "is_new_home_screen_enabled"
const val PERSONALIZED_ONBOARDING_COURSE_LISTS = "personalized_onboarding_course_lists"
const val IS_COURSE_REVENUE_AVAILABLE_ANDROID = "is_course_revenue_available_android"
const val PURCHASE_FLOW_ANDROID = "purchase_flow_android"
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
package org.stepic.droid.configuration.analytic

import org.stepic.droid.configuration.RemoteConfig
import org.stepik.android.domain.base.analytic.UserProperty

class AdaptiveBackendUrlUserProperty(adaptiveBackendUrl: String) : UserProperty {
override val name: String =
RemoteConfig.PREFIX + RemoteConfig.ADAPTIVE_BACKEND_URL

override val value: String =
adaptiveBackendUrl
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
package org.stepic.droid.configuration.analytic

import org.stepic.droid.configuration.RemoteConfig
import org.stepik.android.domain.base.analytic.UserProperty

class AdaptiveCoursesUserProperty(adaptiveCourses: String) : UserProperty {
override val name: String =
RemoteConfig.PREFIX + RemoteConfig.ADAPTIVE_COURSES

override val value: String =
adaptiveCourses
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
package org.stepic.droid.configuration.analytic

import org.stepic.droid.configuration.RemoteConfig
import org.stepik.android.domain.base.analytic.UserProperty

class CourseRevenueAvailableUserProperty(isCourseRevenueAvailable: Boolean) : UserProperty {
override val name: String =
RemoteConfig.PREFIX + RemoteConfig.IS_COURSE_REVENUE_AVAILABLE_ANDROID

override val value: Boolean =
isCourseRevenueAvailable
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
package org.stepic.droid.configuration.analytic

import org.stepic.droid.configuration.RemoteConfig
import org.stepik.android.domain.base.analytic.UserProperty

class LocalSubmissionsEnabledUserProperty(isLocalSubmissionsEnabled: Boolean) : UserProperty {
override val name: String =
RemoteConfig.PREFIX + RemoteConfig.IS_LOCAL_SUBMISSIONS_ENABLED

override val value: Boolean =
isLocalSubmissionsEnabled
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
package org.stepic.droid.configuration.analytic

import org.stepic.droid.configuration.RemoteConfig
import org.stepik.android.domain.base.analytic.UserProperty

class MinDelayRateDialogUserProperty(delay: Long) : UserProperty {
override val name: String =
RemoteConfig.PREFIX + RemoteConfig.MIN_DELAY_RATE_DIALOG_SEC

override val value: Long =
delay
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
package org.stepic.droid.configuration.analytic

import org.stepic.droid.configuration.RemoteConfig
import org.stepik.android.domain.base.analytic.UserProperty

class NewHomeScreenEnabledUserProperty(isNewHomeScreenEnabled: Boolean) : UserProperty {
override val name: String =
RemoteConfig.PREFIX + RemoteConfig.IS_NEW_HOME_SCREEN_ENABLED

override val value: Boolean =
isNewHomeScreenEnabled
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
package org.stepic.droid.configuration.analytic

import org.stepic.droid.configuration.RemoteConfig
import org.stepik.android.domain.base.analytic.UserProperty

class PersonalizedOnboardingCourseListsUserProperty(
personalizedOnboardingCourseLists: String
) : UserProperty {
override val name: String =
RemoteConfig.PREFIX + RemoteConfig.PERSONALIZED_ONBOARDING_COURSE_LISTS

override val value: String =
personalizedOnboardingCourseLists
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
package org.stepic.droid.configuration.analytic

import org.stepic.droid.configuration.RemoteConfig
import org.stepik.android.domain.base.analytic.UserProperty

class SearchQueryParamsUserProperty(searchQueryParams: String) : UserProperty {
override val name: String =
RemoteConfig.PREFIX + RemoteConfig.SEARCH_QUERY_PARAMS_ANDROID

override val value: String =
searchQueryParams
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
package org.stepic.droid.configuration.analytic

import org.stepic.droid.configuration.RemoteConfig
import org.stepik.android.domain.base.analytic.UserProperty

class ShowStreakDialogAfterLoginUserProperty(showStreak: Boolean) : UserProperty {
override val name: String =
RemoteConfig.PREFIX + RemoteConfig.SHOW_STREAK_DIALOG_AFTER_LOGIN

override val value: Boolean =
showStreak
}
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ import org.stepic.droid.analytic.Analytic
import org.stepic.droid.analytic.experiments.DeferredAuthSplitTest
import org.stepic.droid.analytic.experiments.OnboardingSplitTestVersion2
import org.stepic.droid.configuration.RemoteConfig
import org.stepic.droid.configuration.analytic.*
import org.stepic.droid.core.GoogleApiChecker
import org.stepic.droid.core.StepikDevicePoster
import org.stepic.droid.core.presenters.contracts.SplashView
Expand Down Expand Up @@ -173,12 +174,7 @@ constructor(
} else {
analytic.reportEvent(Analytic.RemoteConfig.FETCHED_UNSUCCESSFUL)
}

analytic
.setUserProperty(
RemoteConfig.PREFIX + RemoteConfig.IS_LOCAL_SUBMISSIONS_ENABLED,
firebaseRemoteConfig[RemoteConfig.IS_LOCAL_SUBMISSIONS_ENABLED].asBoolean().toString()
)
logRemoteConfig()
}
try {
Tasks.await(remoteConfigTask)
Expand All @@ -188,6 +184,18 @@ constructor(
}
}

private fun logRemoteConfig() {
analytic.reportUserProperty(MinDelayRateDialogUserProperty(firebaseRemoteConfig[RemoteConfig.MIN_DELAY_RATE_DIALOG_SEC].asLong()))
analytic.reportUserProperty(ShowStreakDialogAfterLoginUserProperty(firebaseRemoteConfig[RemoteConfig.SHOW_STREAK_DIALOG_AFTER_LOGIN].asBoolean()))
analytic.reportUserProperty(AdaptiveCoursesUserProperty(firebaseRemoteConfig[RemoteConfig.ADAPTIVE_COURSES].asString()))
analytic.reportUserProperty(AdaptiveBackendUrlUserProperty(firebaseRemoteConfig[RemoteConfig.ADAPTIVE_BACKEND_URL].asString()))
analytic.reportUserProperty(LocalSubmissionsEnabledUserProperty(firebaseRemoteConfig[RemoteConfig.IS_LOCAL_SUBMISSIONS_ENABLED].asBoolean()))
analytic.reportUserProperty(SearchQueryParamsUserProperty(firebaseRemoteConfig[RemoteConfig.SEARCH_QUERY_PARAMS_ANDROID].asString()))
analytic.reportUserProperty(NewHomeScreenEnabledUserProperty(firebaseRemoteConfig[RemoteConfig.IS_NEW_HOME_SCREEN_ENABLED].asBoolean()))
analytic.reportUserProperty(PersonalizedOnboardingCourseListsUserProperty(firebaseRemoteConfig[RemoteConfig.PERSONALIZED_ONBOARDING_COURSE_LISTS].asString()))
analytic.reportUserProperty(CourseRevenueAvailableUserProperty(firebaseRemoteConfig[RemoteConfig.IS_COURSE_REVENUE_AVAILABLE_ANDROID].asBoolean()))
}

private fun countNumberOfLaunches() {
val numberOfLaunches = sharedPreferenceHelper.incrementNumberOfLaunches()
//after first increment it is 0, because of default value is -1.
Expand Down
3 changes: 3 additions & 0 deletions app/src/main/java/org/stepic/droid/di/AppCoreComponent.kt
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,7 @@ import org.stepik.android.view.injection.course_list.user.CourseListUserComponen
import org.stepik.android.view.injection.course_list.visited.CourseListVisitedComponent
import org.stepik.android.view.injection.course_list.wishlist.CourseListWishComponent
import org.stepik.android.view.injection.course_payments.CoursePaymentsDataModule
import org.stepik.android.view.injection.course_purchase.CoursePurchaseComponent
import org.stepik.android.view.injection.course_reviews.ComposeCourseReviewComponent
import org.stepik.android.view.injection.course_search.CourseSearchComponent
import org.stepik.android.view.injection.debug.DebugComponent
Expand Down Expand Up @@ -286,6 +287,8 @@ interface AppCoreComponent {

fun courseSearchComponentBuilder(): CourseSearchComponent.Builder

fun coursePurchaseComponentBuilder(): CoursePurchaseComponent.Builder

fun inject(someActivity: FragmentActivityBase)

fun inject(adapter: StepikRadioGroupAdapter)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,7 @@ constructor(

@MainThread
private fun updateCounter(count: Int) {
if (firebaseRemoteConfig[RemoteConfig.SHOW_NOTIFICATIONS_BADGES].asBoolean() && count != 0) {
if (count != 0) {
ShortcutBadger.applyCount(context, count)
listenerContainer.asIterable().forEach {
it.onBadgeCountChanged(count)
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
package org.stepik.android.domain.base.analytic

import java.util.EnumSet

interface UserProperty {
val name: String
val value: Any

val sources: EnumSet<UserPropertySource>
get() = EnumSet.allOf(UserPropertySource::class.java)
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
package org.stepik.android.domain.base.analytic

enum class UserPropertySource {
AMPLITUDE, YANDEX, FIREBASE
}
Loading

0 comments on commit 284a218

Please sign in to comment.