diff --git a/Habitica/src/androidTest/java/com/habitrpg/android/habitica/HabiticaTestCase.kt b/Habitica/src/androidTest/java/com/habitrpg/android/habitica/HabiticaTestCase.kt index 1377331c3..89f8aa7fb 100644 --- a/Habitica/src/androidTest/java/com/habitrpg/android/habitica/HabiticaTestCase.kt +++ b/Habitica/src/androidTest/java/com/habitrpg/android/habitica/HabiticaTestCase.kt @@ -27,7 +27,6 @@ import com.habitrpg.android.habitica.models.inventory.QuestContent import com.habitrpg.android.habitica.models.user.User import com.habitrpg.android.habitica.ui.viewmodels.MainUserViewModel import com.habitrpg.common.habitica.api.HostConfig -import com.habitrpg.common.habitica.helpers.AnalyticsManager import com.habitrpg.common.habitica.helpers.ExceptionHandler import com.kaspersky.kaspresso.testcases.api.testcase.TestCase import io.mockk.clearAllMocks @@ -61,7 +60,6 @@ open class HabiticaTestCase : TestCase() { val soundManager: SoundManager = mockk(relaxed = true) val notificationsManager: NotificationsManager = mockk(relaxed = true) val hostConfig: HostConfig = mockk(relaxed = true) - val analyticsManager: AnalyticsManager = mockk(relaxed = true) val maintenanceService: MaintenanceApiService = mockk(relaxed = true) val tagRepository: TagRepository = mockk(relaxed = true) val hatchPetUseCase: HatchPetUseCase = mockk(relaxed = true) @@ -126,7 +124,6 @@ open class HabiticaTestCase : TestCase() { if (it.returnType == SharedPreferences::class.starProjectedType) assign(it, obj, sharedPreferences) if (it.returnType == NotificationsManager::class.starProjectedType) assign(it, obj, notificationsManager) if (it.returnType == HostConfig::class.starProjectedType) assign(it, obj, hostConfig) - if (it.returnType == AnalyticsManager::class.starProjectedType) assign(it, obj, analyticsManager) if (it.returnType == MaintenanceApiService::class.starProjectedType) assign(it, obj, maintenanceService) if (it.returnType == TagRepository::class.starProjectedType) assign(it, obj, tagRepository) if (it.returnType == FeedPetUseCase::class.starProjectedType) assign(it, obj, feedPetUseCase) diff --git a/Habitica/src/main/java/com/habitrpg/android/habitica/HabiticaBaseApplication.kt b/Habitica/src/main/java/com/habitrpg/android/habitica/HabiticaBaseApplication.kt index 1bc558b63..f0d5d823a 100644 --- a/Habitica/src/main/java/com/habitrpg/android/habitica/HabiticaBaseApplication.kt +++ b/Habitica/src/main/java/com/habitrpg/android/habitica/HabiticaBaseApplication.kt @@ -17,12 +17,19 @@ import android.os.Bundle import android.util.Log import androidx.appcompat.app.AppCompatDelegate import androidx.core.content.edit +import androidx.lifecycle.DefaultLifecycleObserver +import androidx.lifecycle.Lifecycle +import androidx.lifecycle.LifecycleObserver +import androidx.lifecycle.LifecycleOwner +import androidx.lifecycle.OnLifecycleEvent +import androidx.lifecycle.ProcessLifecycleOwner import androidx.preference.PreferenceManager import com.google.android.gms.wearable.Wearable import com.google.firebase.installations.FirebaseInstallations import com.google.firebase.remoteconfig.FirebaseRemoteConfig import com.google.firebase.remoteconfig.FirebaseRemoteConfigSettings import com.habitrpg.android.habitica.data.ApiClient +import com.habitrpg.android.habitica.extensions.DateUtils import com.habitrpg.android.habitica.helpers.AdHandler import com.habitrpg.android.habitica.helpers.Analytics import com.habitrpg.android.habitica.helpers.notifications.PushNotificationManager @@ -31,7 +38,6 @@ import com.habitrpg.android.habitica.ui.activities.BaseActivity import com.habitrpg.android.habitica.ui.activities.LoginActivity import com.habitrpg.android.habitica.ui.views.HabiticaIconsHelper import com.habitrpg.common.habitica.extensions.setupCoil -import com.habitrpg.common.habitica.helpers.AnalyticsManager import com.habitrpg.common.habitica.helpers.ExceptionHandler import com.habitrpg.common.habitica.helpers.LanguageHelper import com.habitrpg.common.habitica.helpers.MarkdownParser @@ -41,8 +47,52 @@ import io.realm.Realm import io.realm.RealmConfiguration import kotlinx.coroutines.MainScope import java.lang.ref.WeakReference +import java.util.Date import javax.inject.Inject +class ApplicationLifecycleTracker(private val sharedPreferences: SharedPreferences): DefaultLifecycleObserver { + private var lastResumeTime = 0L + override fun onResume(owner : LifecycleOwner) { + super.onResume(owner) + lastResumeTime = Date().time + } + + override fun onPause(owner : LifecycleOwner) { + super.onPause(owner) + val duration = Date().time - lastResumeTime + addDurationToDay(duration / 1000) + } + + private fun addDurationToDay(duration: Long) { + var currentTotal = sharedPreferences.getLong("usage_time_total", 0L) + currentTotal += duration + var currentDay = Date() + if (sharedPreferences.contains("usage_time_day")) { + currentDay = Date(sharedPreferences.getLong("usage_time_day", 0L)) + } + var current = sharedPreferences.getLong("usage_time_current", 0L) + if (!DateUtils.isSameDay(currentDay, Date())) { + var average = sharedPreferences.getLong("usage_time_daily_average", 0L) + var observedDays = sharedPreferences.getInt("usage_time_day_count", 0) + average = ((average * observedDays) + current) / (observedDays + 1) + sharedPreferences.edit { + putInt("usage_time_day_count", ++observedDays) + putLong("usage_time_daily_average", average) + } + Analytics.setUserProperty("usage_time_daily_average", average) + Analytics.setUserProperty("usage_time_total", currentTotal) + current = 0 + currentDay = Date() + } + current += duration + sharedPreferences.edit { + putLong("usage_time_current", current) + putLong("usage_time_total", currentTotal) + putLong("usage_time_day", currentDay.time) + } + } +} + @HiltAndroidApp abstract class HabiticaBaseApplication : Application(), Application.ActivityLifecycleCallbacks { @Inject @@ -51,15 +101,14 @@ abstract class HabiticaBaseApplication : Application(), Application.ActivityLife @Inject internal lateinit var sharedPrefs: SharedPreferences - @Inject - internal lateinit var analyticsManager: AnalyticsManager - @Inject internal lateinit var pushNotificationManager: PushNotificationManager @Inject internal lateinit var authenticationHandler: AuthenticationHandler + private lateinit var lifecycleTracker: ApplicationLifecycleTracker + /** * For better performance billing class should be used as singleton */ @@ -67,6 +116,9 @@ abstract class HabiticaBaseApplication : Application(), Application.ActivityLife override fun onCreate() { super.onCreate() + lifecycleTracker = ApplicationLifecycleTracker(sharedPrefs) + ProcessLifecycleOwner.get().lifecycle.addObserver(lifecycleTracker); + if (!BuildConfig.DEBUG) { try { Analytics.initialize(this) @@ -96,8 +148,9 @@ abstract class HabiticaBaseApplication : Application(), Application.ActivityLife checkIfNewVersion() } + private fun setupAdHandler() { - AdHandler.setup(sharedPrefs, analyticsManager) + AdHandler.setup(sharedPrefs) } private fun setLocale() { diff --git a/Habitica/src/main/java/com/habitrpg/android/habitica/data/implementation/ApiClientImpl.kt b/Habitica/src/main/java/com/habitrpg/android/habitica/data/implementation/ApiClientImpl.kt index 23cdce4b4..077027ea0 100644 --- a/Habitica/src/main/java/com/habitrpg/android/habitica/data/implementation/ApiClientImpl.kt +++ b/Habitica/src/main/java/com/habitrpg/android/habitica/data/implementation/ApiClientImpl.kt @@ -39,7 +39,6 @@ import com.habitrpg.android.habitica.models.user.Stats import com.habitrpg.android.habitica.models.user.User import com.habitrpg.common.habitica.api.HostConfig import com.habitrpg.common.habitica.api.Server -import com.habitrpg.common.habitica.helpers.AnalyticsManager import com.habitrpg.common.habitica.models.HabitResponse import com.habitrpg.common.habitica.models.PurchaseValidationRequest import com.habitrpg.common.habitica.models.PurchaseValidationResult @@ -73,7 +72,6 @@ import javax.net.ssl.SSLException class ApiClientImpl( private val converter: Converter.Factory, override val hostConfig: HostConfig, - private val analyticsManager: AnalyticsManager, private val notificationsManager: NotificationsManager, private val context: Context ) : ApiClient { @@ -104,7 +102,6 @@ class ApiClientImpl( private var hadError = false init { - Analytics.setUserID(this.hostConfig.userID) buildRetrofit() } diff --git a/Habitica/src/main/java/com/habitrpg/android/habitica/data/implementation/TaskRepositoryImpl.kt b/Habitica/src/main/java/com/habitrpg/android/habitica/data/implementation/TaskRepositoryImpl.kt index a6de4d653..2e9f31ad0 100644 --- a/Habitica/src/main/java/com/habitrpg/android/habitica/data/implementation/TaskRepositoryImpl.kt +++ b/Habitica/src/main/java/com/habitrpg/android/habitica/data/implementation/TaskRepositoryImpl.kt @@ -1,11 +1,12 @@ package com.habitrpg.android.habitica.data.implementation -import androidx.core.os.bundleOf import com.habitrpg.android.habitica.data.ApiClient import com.habitrpg.android.habitica.data.TaskRepository import com.habitrpg.android.habitica.data.local.TaskLocalRepository import com.habitrpg.android.habitica.helpers.Analytics import com.habitrpg.android.habitica.helpers.AppConfigManager +import com.habitrpg.android.habitica.helpers.EventCategory +import com.habitrpg.android.habitica.helpers.HitType import com.habitrpg.android.habitica.interactors.ScoreTaskLocallyInteractor import com.habitrpg.android.habitica.models.BaseMainObject import com.habitrpg.android.habitica.models.responses.BulkTaskScoringData @@ -15,7 +16,6 @@ import com.habitrpg.android.habitica.models.tasks.TaskList import com.habitrpg.android.habitica.models.user.OwnedItem import com.habitrpg.android.habitica.models.user.User import com.habitrpg.android.habitica.modules.AuthenticationHandler -import com.habitrpg.common.habitica.helpers.AnalyticsManager import com.habitrpg.common.habitica.helpers.launchCatching import com.habitrpg.shared.habitica.models.responses.TaskDirection import com.habitrpg.shared.habitica.models.responses.TaskDirectionData @@ -39,7 +39,6 @@ class TaskRepositoryImpl( apiClient: ApiClient, authenticationHandler: AuthenticationHandler, val appConfigManager: AppConfigManager, - val analyticsManager: AnalyticsManager ) : BaseRepositoryImpl(localRepository, apiClient, authenticationHandler), TaskRepository { private var lastTaskAction: Long = 0 @@ -102,12 +101,14 @@ class TaskRepositoryImpl( val thisUser = user ?: localRepository.getUser(authenticationHandler.currentUserID ?: "").firstOrNull() ?: return null // save local task changes - Analytics.logEvent( + Analytics.sendEvent( "task_scored", - bundleOf( - Pair("type", task.type), - Pair("scored_up", up), - Pair("value", task.value) + EventCategory.BEHAVIOUR, + HitType.EVENT, + mapOf( + "type" to (task.type ?: ""), + "scored_up" to up, + "value" to task.value ) ) if (res.lvl == 0) { diff --git a/Habitica/src/main/java/com/habitrpg/android/habitica/data/implementation/UserRepositoryImpl.kt b/Habitica/src/main/java/com/habitrpg/android/habitica/data/implementation/UserRepositoryImpl.kt index d0df7a16c..0631e7810 100644 --- a/Habitica/src/main/java/com/habitrpg/android/habitica/data/implementation/UserRepositoryImpl.kt +++ b/Habitica/src/main/java/com/habitrpg/android/habitica/data/implementation/UserRepositoryImpl.kt @@ -18,7 +18,6 @@ import com.habitrpg.android.habitica.models.user.Stats import com.habitrpg.android.habitica.models.user.User import com.habitrpg.android.habitica.models.user.UserQuestStatus import com.habitrpg.android.habitica.modules.AuthenticationHandler -import com.habitrpg.common.habitica.helpers.AnalyticsManager import com.habitrpg.common.habitica.models.Notification import com.habitrpg.common.habitica.models.notifications.NewStuffData import com.habitrpg.shared.habitica.models.responses.TaskDirection @@ -41,7 +40,6 @@ class UserRepositoryImpl( authenticationHandler: AuthenticationHandler, private val taskRepository: TaskRepository, private val appConfigManager: AppConfigManager, - private val analyticsManager: AnalyticsManager ) : BaseRepositoryImpl(localRepository, apiClient, authenticationHandler), UserRepository { companion object { diff --git a/Habitica/src/main/java/com/habitrpg/android/habitica/extensions/DateExtensions.kt b/Habitica/src/main/java/com/habitrpg/android/habitica/extensions/DateExtensions.kt index 1042c46e3..511196698 100644 --- a/Habitica/src/main/java/com/habitrpg/android/habitica/extensions/DateExtensions.kt +++ b/Habitica/src/main/java/com/habitrpg/android/habitica/extensions/DateExtensions.kt @@ -24,6 +24,15 @@ class DateUtils { cal.set(Calendar.MILLISECOND, 0) return cal.time } + + fun isSameDay(date1 : Date, date2 : Date) : Boolean { + val cal1 = Calendar.getInstance() + val cal2 = Calendar.getInstance() + cal1.time = date1 + cal2.time = date2 + return cal1[Calendar.DAY_OF_YEAR] == cal2[Calendar.DAY_OF_YEAR] && + cal1[Calendar.YEAR] == cal2[Calendar.YEAR] + } } } diff --git a/Habitica/src/main/java/com/habitrpg/android/habitica/helpers/AdHandler.kt b/Habitica/src/main/java/com/habitrpg/android/habitica/helpers/AdHandler.kt index ec589a6d3..b39063d09 100644 --- a/Habitica/src/main/java/com/habitrpg/android/habitica/helpers/AdHandler.kt +++ b/Habitica/src/main/java/com/habitrpg/android/habitica/helpers/AdHandler.kt @@ -18,7 +18,6 @@ import com.google.android.gms.ads.rewarded.RewardedAdLoadCallback import com.google.firebase.analytics.FirebaseAnalytics import com.google.firebase.crashlytics.FirebaseCrashlytics import com.habitrpg.android.habitica.BuildConfig -import com.habitrpg.common.habitica.helpers.AnalyticsManager import java.io.UnsupportedEncodingException import java.security.MessageDigest import java.util.Date @@ -75,7 +74,6 @@ class AdHandler(val activity: Activity, val type: AdType, val rewardAction: (Boo DISABLED } - private lateinit var analyticsManager: AnalyticsManager private lateinit var sharedPreferences: SharedPreferences const val TAG = "AdHandler" @@ -144,9 +142,8 @@ class AdHandler(val activity: Activity, val type: AdType, val rewardAction: (Boo } } - fun setup(sharedPrefs: SharedPreferences, analyticsManager: AnalyticsManager) { + fun setup(sharedPrefs: SharedPreferences) { this.sharedPreferences = sharedPrefs - this.analyticsManager = analyticsManager for (type in AdType.values()) { val time = sharedPrefs.getLong("nextAd${type.name}", 0) @@ -228,10 +225,12 @@ class AdHandler(val activity: Activity, val type: AdType, val rewardAction: (Boo } override fun onUserEarnedReward(rewardItem: RewardItem) { - analyticsManager.logEvent( + Analytics.sendEvent( "adRewardEarned", - bundleOf( - Pair("type", type.name) + EventCategory.BEHAVIOUR, + HitType.EVENT, + mapOf( + "type" to type.name ) ) FirebaseAnalytics.getInstance(activity).logEvent( diff --git a/Habitica/src/main/java/com/habitrpg/android/habitica/helpers/Analytics.kt b/Habitica/src/main/java/com/habitrpg/android/habitica/helpers/Analytics.kt index aa5e1b440..79e4ead14 100644 --- a/Habitica/src/main/java/com/habitrpg/android/habitica/helpers/Analytics.kt +++ b/Habitica/src/main/java/com/habitrpg/android/habitica/helpers/Analytics.kt @@ -54,11 +54,15 @@ object Analytics { data.putAll(additionalData) } if (eventAction != null) { - if (target == null || target == AnalyticsTarget.AMPLITUDE) { - amplitude.track(eventAction, data) + if (this::amplitude.isInitialized) { + if (target == null || target == AnalyticsTarget.AMPLITUDE) { + amplitude.track(eventAction, data) + } } - if (target == null || target == AnalyticsTarget.FIREBASE) { - firebase.logEvent(eventAction, bundleOf(*data.toList().toTypedArray())) + if (this::firebase.isInitialized) { + if (target == null || target == AnalyticsTarget.FIREBASE) { + firebase.logEvent(eventAction, bundleOf(*data.toList().toTypedArray())) + } } } } @@ -85,17 +89,28 @@ object Analytics { sharedPrefs.getString("launch_screen", "")?.let { identify.set("launch_screen", it) } - amplitude.identify(identify) + if (this::amplitude.isInitialized) { + amplitude.identify(identify) + } } fun setUserID(userID: String) { - amplitude.setUserId(userID) + if (this::amplitude.isInitialized) { + amplitude.setUserId(userID) + } FirebaseCrashlytics.getInstance().setUserId(userID) - firebase.setUserId(userID) + if (this::firebase.isInitialized) { + firebase.setUserId(userID) + } } - fun setUserProperty(identifier: String, value: String) { - firebase.setUserProperty(identifier, value) + fun setUserProperty(identifier: String, value: Any?) { + if (this::amplitude.isInitialized) { + amplitude.identify(mapOf(identifier to value)) + } + if (this::firebase.isInitialized) { + firebase.setUserProperty(identifier, value?.toString()) + } } fun logError(msg: String) { diff --git a/Habitica/src/main/java/com/habitrpg/android/habitica/helpers/PurchaseHandler.kt b/Habitica/src/main/java/com/habitrpg/android/habitica/helpers/PurchaseHandler.kt index 73a62ce30..6bf30f8ae 100644 --- a/Habitica/src/main/java/com/habitrpg/android/habitica/helpers/PurchaseHandler.kt +++ b/Habitica/src/main/java/com/habitrpg/android/habitica/helpers/PurchaseHandler.kt @@ -4,7 +4,6 @@ import android.app.Activity import android.content.Context import android.content.SharedPreferences import androidx.core.content.edit -import androidx.core.os.bundleOf import androidx.lifecycle.asFlow import com.android.billingclient.api.AcknowledgePurchaseParams import com.android.billingclient.api.BillingClient @@ -32,7 +31,6 @@ import com.habitrpg.android.habitica.models.user.User import com.habitrpg.android.habitica.ui.activities.PurchaseActivity import com.habitrpg.android.habitica.ui.viewmodels.MainUserViewModel import com.habitrpg.android.habitica.ui.views.dialogs.HabiticaAlertDialog -import com.habitrpg.common.habitica.helpers.AnalyticsManager import com.habitrpg.common.habitica.helpers.ExceptionHandler import com.habitrpg.common.habitica.helpers.launchCatching import com.habitrpg.common.habitica.models.IAPGift @@ -55,7 +53,6 @@ import kotlin.time.toDuration class PurchaseHandler( private val context: Context, - private val analyticsManager: AnalyticsManager, private val apiClient: ApiClient, private val userViewModel: MainUserViewModel ) : PurchasesUpdatedListener, PurchasesResponseListener { @@ -349,7 +346,7 @@ class PurchaseHandler( try { apiClient.validateSubscription(validationRequest) processedPurchase(purchase) - Analytics.sendEvent("user_subscribed", bundleOf(Pair("sku", sku))) + Analytics.sendEvent("user_subscribed", EventCategory.BEHAVIOUR, HitType.EVENT, mapOf("sku" to (sku ?: ""))) CoroutineScope(Dispatchers.IO).launch(ExceptionHandler.coroutine()) { acknowledgePurchase(purchase) } diff --git a/Habitica/src/main/java/com/habitrpg/android/habitica/modules/ApiModule.kt b/Habitica/src/main/java/com/habitrpg/android/habitica/modules/ApiModule.kt index 8268b89f5..d8d6fd128 100644 --- a/Habitica/src/main/java/com/habitrpg/android/habitica/modules/ApiModule.kt +++ b/Habitica/src/main/java/com/habitrpg/android/habitica/modules/ApiModule.kt @@ -9,7 +9,6 @@ import com.habitrpg.android.habitica.data.implementation.ApiClientImpl.Companion import com.habitrpg.android.habitica.helpers.MainNotificationsManager import com.habitrpg.android.habitica.helpers.NotificationsManager import com.habitrpg.common.habitica.api.HostConfig -import com.habitrpg.common.habitica.helpers.AnalyticsManager import com.habitrpg.common.habitica.helpers.KeyHelper import dagger.Module import dagger.Provides @@ -50,14 +49,12 @@ open class ApiModule { fun providesApiHelper( gsonConverter: GsonConverterFactory, hostConfig: HostConfig, - analyticsManager: AnalyticsManager, notificationsManager: NotificationsManager, @ApplicationContext context: Context ): ApiClient { val apiClient = ApiClientImpl( gsonConverter, hostConfig, - analyticsManager, notificationsManager, context ) diff --git a/Habitica/src/main/java/com/habitrpg/android/habitica/modules/DeveloperModule.kt b/Habitica/src/main/java/com/habitrpg/android/habitica/modules/DeveloperModule.kt index 91b2e8339..9557b6514 100644 --- a/Habitica/src/main/java/com/habitrpg/android/habitica/modules/DeveloperModule.kt +++ b/Habitica/src/main/java/com/habitrpg/android/habitica/modules/DeveloperModule.kt @@ -1,22 +1,12 @@ package com.habitrpg.android.habitica.modules -import android.content.Context -import com.habitrpg.android.habitica.proxy.implementation.EmptyAnalyticsManager -import com.habitrpg.common.habitica.helpers.AnalyticsManager import dagger.Module -import dagger.Provides import dagger.hilt.InstallIn -import dagger.hilt.android.qualifiers.ApplicationContext import dagger.hilt.components.SingletonComponent -import javax.inject.Singleton // provide proxy class for libraries(to avoid 65k limit) @InstallIn(SingletonComponent::class) @Module open class DeveloperModule { - @Provides - @Singleton - open fun provideAnalyticsManager(@ApplicationContext context: Context): AnalyticsManager { - return EmptyAnalyticsManager() - } + } diff --git a/Habitica/src/main/java/com/habitrpg/android/habitica/modules/UserRepositoryModule.kt b/Habitica/src/main/java/com/habitrpg/android/habitica/modules/UserRepositoryModule.kt index 6c6bffc7b..b27cd90d7 100644 --- a/Habitica/src/main/java/com/habitrpg/android/habitica/modules/UserRepositoryModule.kt +++ b/Habitica/src/main/java/com/habitrpg/android/habitica/modules/UserRepositoryModule.kt @@ -43,7 +43,6 @@ import com.habitrpg.android.habitica.data.local.implementation.RealmUserLocalRep import com.habitrpg.android.habitica.helpers.AppConfigManager import com.habitrpg.android.habitica.helpers.PurchaseHandler import com.habitrpg.android.habitica.ui.viewmodels.MainUserViewModel -import com.habitrpg.common.habitica.helpers.AnalyticsManager import dagger.Module import dagger.Provides import dagger.hilt.InstallIn @@ -71,14 +70,12 @@ class UserRepositoryModule { apiClient: ApiClient, authenticationHandler: AuthenticationHandler, appConfigManager: AppConfigManager, - analyticsManager: AnalyticsManager ): TaskRepository { return TaskRepositoryImpl( localRepository, apiClient, authenticationHandler, - appConfigManager, - analyticsManager + appConfigManager ) } @@ -122,7 +119,6 @@ class UserRepositoryModule { authenticationHandler: AuthenticationHandler, taskRepository: TaskRepository, appConfigManager: AppConfigManager, - analyticsManager: AnalyticsManager ): UserRepository { return UserRepositoryImpl( localRepository, @@ -130,7 +126,6 @@ class UserRepositoryModule { authenticationHandler, taskRepository, appConfigManager, - analyticsManager ) } @@ -211,10 +206,9 @@ class UserRepositoryModule { @Singleton fun providesPurchaseHandler( @ApplicationContext context: Context, - analyticsManager: AnalyticsManager, apiClient: ApiClient, userViewModel: MainUserViewModel ): PurchaseHandler { - return PurchaseHandler(context, analyticsManager, apiClient, userViewModel) + return PurchaseHandler(context, apiClient, userViewModel) } } diff --git a/Habitica/src/main/java/com/habitrpg/android/habitica/proxy/implementation/EmptyAnalyticsManager.kt b/Habitica/src/main/java/com/habitrpg/android/habitica/proxy/implementation/EmptyAnalyticsManager.kt deleted file mode 100644 index c368747f7..000000000 --- a/Habitica/src/main/java/com/habitrpg/android/habitica/proxy/implementation/EmptyAnalyticsManager.kt +++ /dev/null @@ -1,8 +0,0 @@ -package com.habitrpg.android.habitica.proxy.implementation - -import android.os.Bundle -import com.habitrpg.common.habitica.helpers.AnalyticsManager - -class EmptyAnalyticsManager : AnalyticsManager { - -} diff --git a/Habitica/src/main/java/com/habitrpg/android/habitica/ui/activities/BaseActivity.kt b/Habitica/src/main/java/com/habitrpg/android/habitica/ui/activities/BaseActivity.kt index 9147b28e7..467a02a06 100644 --- a/Habitica/src/main/java/com/habitrpg/android/habitica/ui/activities/BaseActivity.kt +++ b/Habitica/src/main/java/com/habitrpg/android/habitica/ui/activities/BaseActivity.kt @@ -16,7 +16,6 @@ import androidx.appcompat.app.AppCompatActivity import androidx.appcompat.app.AppCompatDelegate import androidx.appcompat.widget.Toolbar import androidx.core.content.ContextCompat -import androidx.core.os.bundleOf import androidx.lifecycle.lifecycleScope import androidx.preference.PreferenceManager import com.habitrpg.android.habitica.HabiticaApplication @@ -24,13 +23,15 @@ import com.habitrpg.android.habitica.R import com.habitrpg.android.habitica.data.UserRepository import com.habitrpg.android.habitica.extensions.forceLocale import com.habitrpg.android.habitica.extensions.updateStatusBarColor +import com.habitrpg.android.habitica.helpers.Analytics +import com.habitrpg.android.habitica.helpers.EventCategory +import com.habitrpg.android.habitica.helpers.HitType import com.habitrpg.android.habitica.helpers.NotificationsManager import com.habitrpg.android.habitica.interactors.ShowNotificationInteractor import com.habitrpg.android.habitica.ui.helpers.ToolbarColorHelper import com.habitrpg.android.habitica.ui.views.dialogs.HabiticaAlertDialog import com.habitrpg.common.habitica.extensions.getThemeColor import com.habitrpg.common.habitica.extensions.isUsingNightModeResources -import com.habitrpg.common.habitica.helpers.AnalyticsManager import com.habitrpg.common.habitica.helpers.ExceptionHandler import com.habitrpg.common.habitica.helpers.LanguageHelper import com.habitrpg.common.habitica.helpers.launchCatching @@ -45,9 +46,6 @@ abstract class BaseActivity : AppCompatActivity() { @Inject lateinit var userRepository: UserRepository - @Inject - internal lateinit var analyticsManager: AnalyticsManager - private var currentTheme: String? = null private var isNightMode: Boolean = false internal var forcedTheme: String? = null @@ -227,7 +225,7 @@ abstract class BaseActivity : AppCompatActivity() { } fun shareContent(identifier: String, message: String, image: Bitmap? = null) { - analyticsManager.logEvent("shared", bundleOf(Pair("identifier", identifier))) + Analytics.sendEvent("shared", EventCategory.BEHAVIOUR, HitType.EVENT, mapOf("identifier" to identifier)) val sharingIntent = Intent(Intent.ACTION_SEND) sharingIntent.type = "*/*" sharingIntent.putExtra(Intent.EXTRA_TEXT, message) diff --git a/Habitica/src/main/java/com/habitrpg/android/habitica/ui/activities/TaskFormActivity.kt b/Habitica/src/main/java/com/habitrpg/android/habitica/ui/activities/TaskFormActivity.kt index 99df1541b..738b8e774 100644 --- a/Habitica/src/main/java/com/habitrpg/android/habitica/ui/activities/TaskFormActivity.kt +++ b/Habitica/src/main/java/com/habitrpg/android/habitica/ui/activities/TaskFormActivity.kt @@ -27,7 +27,6 @@ import androidx.compose.runtime.mutableStateListOf import androidx.compose.runtime.mutableStateMapOf import androidx.compose.runtime.toMutableStateList import androidx.core.content.ContextCompat -import androidx.core.os.bundleOf import androidx.core.view.children import androidx.core.view.forEachIndexed import androidx.core.view.isVisible @@ -81,6 +80,8 @@ import javax.inject.Inject @AndroidEntryPoint class TaskFormActivity : BaseActivity() { + + private val viewModel: TaskFormViewModel by viewModels() private lateinit var binding: ActivityTaskFormBinding @@ -123,10 +124,14 @@ class TaskFormActivity : BaseActivity() { val alert = HabiticaAlertDialog(this) alert.setTitle(R.string.push_notification_system_settings_title) alert.setMessage(R.string.push_notification_system_settings_description) - alert.addButton(R.string.settings, true, false) { _, _ -> - val notifSettingIntent: Intent = Intent(Settings.ACTION_APP_NOTIFICATION_SETTINGS) - .addFlags(Intent.FLAG_ACTIVITY_NEW_TASK) - .putExtra(Settings.EXTRA_APP_PACKAGE, applicationContext?.packageName) + alert.addButton(R.string.settings, isPrimary = true, isDestructive = false) { _, _ -> + val notifSettingIntent: Intent = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { + Intent(Settings.ACTION_APP_NOTIFICATION_SETTINGS) + .addFlags(Intent.FLAG_ACTIVITY_NEW_TASK) + .putExtra(Settings.EXTRA_APP_PACKAGE, applicationContext?.packageName) + } else { + return@addButton + } startActivity(notifSettingIntent) } alert.addButton(R.string.cancel, false) { _, _ -> @@ -416,8 +421,7 @@ class TaskFormActivity : BaseActivity() { val alert = HabiticaAlertDialog(this) alert.setTitle(R.string.unsaved_changes) alert.setMessage(R.string.discard_changes_to_task_message) - alert.addButton(R.string.discard, true, true) { _, _ -> - analyticsManager.logEvent("discard_task", bundleOf(Pair("is_creating", isCreating))) + alert.addButton(R.string.discard, isPrimary = true, isDestructive = true) { _, _ -> super.onBackPressed() } alert.addButton(R.string.cancel, false) { _, _ -> @@ -657,7 +661,7 @@ class TaskFormActivity : BaseActivity() { binding.habitResetStreakButtons.visibility = View.GONE assignedIDs = - task.group?.assignedUsersDetail?.map { it.assignedUserID }?.filterNotNull() + task.group?.assignedUsersDetail?.mapNotNull { it.assignedUserID } ?.toMutableStateList() ?: mutableStateListOf() task.group?.assignedUsersDetail?.forEach { it.completedDate?.let { date -> @@ -770,7 +774,7 @@ class TaskFormActivity : BaseActivity() { val assignChanges = mapOf( "assign" to mutableListOf(), - "unassign" to mutableListOf() + "unassign" to mutableListOf() ) if (groupID != null && thisTask.group?.groupID == null) { thisTask.group = TaskGroupPlan() @@ -795,9 +799,6 @@ class TaskFormActivity : BaseActivity() { } else { taskRepository.updateTaskInBackground(thisTask, assignChanges) } - if (isDiscardCancelled) { - analyticsManager.logEvent("back_to_task", bundleOf(Pair("is_creating", isCreating))) - } if (thisTask.type == TaskType.DAILY || thisTask.type == TaskType.TODO) { taskAlarmManager.scheduleAlarmsForTask(thisTask) @@ -877,7 +878,7 @@ class TaskFormActivity : BaseActivity() { lifecycleScope.launch(Dispatchers.Main) { challengeRepository.leaveChallenge(it, "keep-all") taskRepository.deleteTask(task?.id ?: "") - userRepository.retrieveUser(true, true) + userRepository.retrieveUser(withTasks = true, forced = true) } } } @@ -889,7 +890,7 @@ class TaskFormActivity : BaseActivity() { challenge?.let { lifecycleScope.launch(Dispatchers.Main) { challengeRepository.leaveChallenge(it, "remove-all") - userRepository.retrieveUser(true, true) + userRepository.retrieveUser(withTasks = true, forced = true) } } } @@ -921,17 +922,17 @@ class TaskFormActivity : BaseActivity() { ) { _, _ -> lifecycleScope.launch(Dispatchers.Main) { taskRepository.unlinkAllTasks(task.challengeID, "keep-all") - userRepository.retrieveUser(true, true) + userRepository.retrieveUser(withTasks = true, forced = true) } } dialog.addButton( getString(R.string.delete_x_tasks, taskCount), - false, - true + isPrimary = false, + isDestructive = true ) { _, _ -> lifecycleScope.launch(Dispatchers.Main) { taskRepository.unlinkAllTasks(task.challengeID, "remove-all") - userRepository.retrieveUser(true, true) + userRepository.retrieveUser(withTasks = true, forced = true) } } dialog.setExtraCloseButtonVisibility(View.VISIBLE) diff --git a/Habitica/src/main/java/com/habitrpg/android/habitica/ui/fragments/BaseFragment.kt b/Habitica/src/main/java/com/habitrpg/android/habitica/ui/fragments/BaseFragment.kt index b9428f7cd..9ad62c4ab 100644 --- a/Habitica/src/main/java/com/habitrpg/android/habitica/ui/fragments/BaseFragment.kt +++ b/Habitica/src/main/java/com/habitrpg/android/habitica/ui/fragments/BaseFragment.kt @@ -9,7 +9,6 @@ import androidx.lifecycle.lifecycleScope import androidx.viewbinding.ViewBinding import com.habitrpg.android.habitica.data.TutorialRepository import com.habitrpg.android.habitica.ui.activities.MainActivity -import com.habitrpg.common.habitica.helpers.AnalyticsManager import com.habitrpg.common.habitica.helpers.launchCatching import kotlinx.coroutines.delay import kotlinx.coroutines.flow.firstOrNull @@ -25,9 +24,6 @@ abstract class BaseFragment : Fragment() { @Inject lateinit var tutorialRepository: TutorialRepository - @Inject - lateinit var analyticsManager: AnalyticsManager - var tutorialStepIdentifier: String? = null protected var tutorialCanBeDeferred = true var tutorialTexts: List = ArrayList() diff --git a/Habitica/src/main/java/com/habitrpg/android/habitica/ui/fragments/inventory/shops/ShopFragment.kt b/Habitica/src/main/java/com/habitrpg/android/habitica/ui/fragments/inventory/shops/ShopFragment.kt index c7e8b0249..6cc90337e 100644 --- a/Habitica/src/main/java/com/habitrpg/android/habitica/ui/fragments/inventory/shops/ShopFragment.kt +++ b/Habitica/src/main/java/com/habitrpg/android/habitica/ui/fragments/inventory/shops/ShopFragment.kt @@ -9,7 +9,6 @@ import androidx.compose.foundation.layout.Row import androidx.compose.runtime.mutableStateOf import androidx.compose.ui.platform.ComposeView import androidx.compose.ui.unit.dp -import androidx.core.os.bundleOf import androidx.lifecycle.lifecycleScope import androidx.recyclerview.widget.GridLayoutManager import com.habitrpg.android.habitica.R @@ -206,8 +205,6 @@ open class ShopFragment : BaseMainFragment() view.post { setGridSpanCount(view.width) } - context?.let { analyticsManager.logEvent("open_shop", bundleOf(Pair("shopIdentifier", shopIdentifier))) } - lifecycleScope.launchCatching { inventoryRepository.getOwnedItems() .collect { adapter?.setOwnedItems(it) } diff --git a/Habitica/src/main/java/com/habitrpg/android/habitica/ui/viewmodels/AuthenticationViewModel.kt b/Habitica/src/main/java/com/habitrpg/android/habitica/ui/viewmodels/AuthenticationViewModel.kt index 510834f01..e9b7ae7d7 100644 --- a/Habitica/src/main/java/com/habitrpg/android/habitica/ui/viewmodels/AuthenticationViewModel.kt +++ b/Habitica/src/main/java/com/habitrpg/android/habitica/ui/viewmodels/AuthenticationViewModel.kt @@ -24,7 +24,6 @@ import com.habitrpg.android.habitica.helpers.Analytics import com.habitrpg.android.habitica.modules.AuthenticationHandler import com.habitrpg.android.habitica.ui.views.dialogs.HabiticaAlertDialog import com.habitrpg.common.habitica.api.HostConfig -import com.habitrpg.common.habitica.helpers.AnalyticsManager import com.habitrpg.common.habitica.helpers.KeyHelper import com.habitrpg.common.habitica.helpers.launchCatching import com.habitrpg.common.habitica.models.auth.UserAuthResponse @@ -38,7 +37,6 @@ class AuthenticationViewModel @Inject constructor( val sharedPrefs: SharedPreferences, val authenticationHandler: AuthenticationHandler, val hostConfig: HostConfig, - val analyticsManager: AnalyticsManager, private val keyHelper: KeyHelper? ) { var googleEmail: String? = null diff --git a/Habitica/src/main/java/com/habitrpg/android/habitica/ui/viewmodels/MainActivityViewModel.kt b/Habitica/src/main/java/com/habitrpg/android/habitica/ui/viewmodels/MainActivityViewModel.kt index 1afa628e3..9df149b78 100644 --- a/Habitica/src/main/java/com/habitrpg/android/habitica/ui/viewmodels/MainActivityViewModel.kt +++ b/Habitica/src/main/java/com/habitrpg/android/habitica/ui/viewmodels/MainActivityViewModel.kt @@ -20,7 +20,6 @@ import com.habitrpg.android.habitica.models.TutorialStep import com.habitrpg.android.habitica.models.inventory.Egg import com.habitrpg.android.habitica.ui.TutorialView import com.habitrpg.common.habitica.api.HostConfig -import com.habitrpg.common.habitica.helpers.AnalyticsManager import com.habitrpg.common.habitica.helpers.ExceptionHandler import com.habitrpg.common.habitica.helpers.launchCatching import com.habitrpg.shared.habitica.models.responses.MaintenanceResponse @@ -42,7 +41,6 @@ class MainActivityViewModel @Inject constructor( val taskRepository: TaskRepository, val inventoryRepository: InventoryRepository, val taskAlarmManager: TaskAlarmManager, - val analyticsManager: AnalyticsManager, val maintenanceService: MaintenanceApiService ) : BaseViewModel(userRepository, userViewModel), TutorialView.OnTutorialReaction { diff --git a/Habitica/src/main/java/com/habitrpg/android/habitica/ui/views/insufficientCurrency/InsufficientGemsDialog.kt b/Habitica/src/main/java/com/habitrpg/android/habitica/ui/views/insufficientCurrency/InsufficientGemsDialog.kt index dc9418d10..3b5bdc8c3 100644 --- a/Habitica/src/main/java/com/habitrpg/android/habitica/ui/views/insufficientCurrency/InsufficientGemsDialog.kt +++ b/Habitica/src/main/java/com/habitrpg/android/habitica/ui/views/insufficientCurrency/InsufficientGemsDialog.kt @@ -15,7 +15,6 @@ import com.habitrpg.android.habitica.helpers.MainNavigationController import com.habitrpg.android.habitica.helpers.PurchaseHandler import com.habitrpg.android.habitica.helpers.PurchaseTypes import com.habitrpg.android.habitica.interactors.InsufficientGemsUseCase -import com.habitrpg.common.habitica.helpers.AnalyticsManager import com.habitrpg.common.habitica.helpers.launchCatching import dagger.hilt.EntryPoint import dagger.hilt.InstallIn @@ -37,9 +36,6 @@ class InsufficientGemsDialog(val parentActivity: Activity, var gemPrice: Int) : @Inject lateinit var configManager: AppConfigManager - @Inject - lateinit var analyticsManager: AnalyticsManager - @Inject lateinit var purchaseHandler: PurchaseHandler @@ -47,7 +43,6 @@ class InsufficientGemsDialog(val parentActivity: Activity, var gemPrice: Int) : @InstallIn(SingletonComponent::class) interface InsufficientGemsDialogEntryPoint { fun configManager(): AppConfigManager - fun analyticsManager(): AnalyticsManager fun purchaseHandler(): PurchaseHandler fun insufficientGemsUseCase(): InsufficientGemsUseCase } @@ -57,7 +52,6 @@ class InsufficientGemsDialog(val parentActivity: Activity, var gemPrice: Int) : val hiltEntryPoint = EntryPointAccessors.fromApplication(parentActivity, InsufficientGemsDialogEntryPoint::class.java) insufficientGemsUseCase = hiltEntryPoint.insufficientGemsUseCase() configManager = hiltEntryPoint.configManager() - analyticsManager = hiltEntryPoint.analyticsManager() purchaseHandler = hiltEntryPoint.purchaseHandler() } diff --git a/Habitica/src/release/java/com/habitrpg/android/habitica/ReleaseDeveloperModule.kt b/Habitica/src/release/java/com/habitrpg/android/habitica/ReleaseDeveloperModule.kt index dcbabac7a..5de847b34 100644 --- a/Habitica/src/release/java/com/habitrpg/android/habitica/ReleaseDeveloperModule.kt +++ b/Habitica/src/release/java/com/habitrpg/android/habitica/ReleaseDeveloperModule.kt @@ -2,11 +2,6 @@ package com.habitrpg.android.habitica import android.content.Context import com.habitrpg.android.habitica.modules.DeveloperModule -import com.habitrpg.android.habitica.proxy.AnalyticsManagerImpl -import com.habitrpg.common.habitica.helpers.AnalyticsManager class ReleaseDeveloperModule : DeveloperModule() { - override fun provideAnalyticsManager(context: Context): AnalyticsManager { - return AnalyticsManagerImpl(context) - } } diff --git a/Habitica/src/release/java/com/habitrpg/android/habitica/proxy/AnalyticsManagerImpl.kt b/Habitica/src/release/java/com/habitrpg/android/habitica/proxy/AnalyticsManagerImpl.kt deleted file mode 100644 index 7a8a70649..000000000 --- a/Habitica/src/release/java/com/habitrpg/android/habitica/proxy/AnalyticsManagerImpl.kt +++ /dev/null @@ -1,13 +0,0 @@ -package com.habitrpg.android.habitica.proxy - -import android.content.Context -import android.os.Bundle -import com.google.firebase.analytics.FirebaseAnalytics -import com.google.firebase.crashlytics.FirebaseCrashlytics -import com.habitrpg.common.habitica.helpers.AnalyticsManager - -class AnalyticsManagerImpl(context: Context) : AnalyticsManager { - - private val firebaseAnalytics = FirebaseAnalytics.getInstance(context) - -} diff --git a/common/src/main/java/com/habitrpg/common/habitica/helpers/AnalyticsManager.kt b/common/src/main/java/com/habitrpg/common/habitica/helpers/AnalyticsManager.kt deleted file mode 100644 index d89714757..000000000 --- a/common/src/main/java/com/habitrpg/common/habitica/helpers/AnalyticsManager.kt +++ /dev/null @@ -1,4 +0,0 @@ -package com.habitrpg.common.habitica.helpers - -interface AnalyticsManager { -} diff --git a/version.properties b/version.properties index db9fad675..6ce5f9c8a 100644 --- a/version.properties +++ b/version.properties @@ -1,2 +1,2 @@ NAME=4.2.4 -CODE=6271 \ No newline at end of file +CODE=6291 \ No newline at end of file