From 2f9f342768e4a29c5ee12df3e9c6cd3281ff5aa1 Mon Sep 17 00:00:00 2001 From: Phillip Thelen Date: Thu, 6 Jan 2022 13:36:08 +0100 Subject: [PATCH] Improve notification handling --- Habitica/build.gradle | 50 +++--- .../data/implementation/ApiClientImpl.kt | 2 - .../habitica/events/BoughtGemsEvent.kt | 6 - .../habitica/events/GearPurchasedEvent.kt | 2 +- .../habitica/events/ShowAchievementDialog.kt | 3 - .../habitica/events/ShowCheckinDialog.kt | 5 - .../habitica/events/ShowFirstDropDialog.kt | 3 - .../habitica/events/ShowWonChallengeDialog.kt | 5 - .../habitica/helpers/NotificationsManager.kt | 164 ++++++----------- .../habitica/helpers/PurchaseHandler.kt | 1 - .../interactors/ShowNotificationInteractor.kt | 169 ++++++++++++++++++ .../models/notifications/AchievementData.kt | 1 + .../android/habitica/modules/ApiModule.java | 58 ------ .../android/habitica/modules/ApiModule.kt | 73 ++++++++ .../habitica/ui/AvatarWithBarsViewModel.kt | 9 - .../habitica/ui/activities/BaseActivity.kt | 14 ++ .../ui/activities/GemPurchaseActivity.kt | 1 - .../habitica/ui/activities/MainActivity.kt | 75 -------- .../ui/viewmodels/AuthenticationViewModel.kt | 22 ++- build.gradle | 5 +- gradle/wrapper/gradle-wrapper.properties | 2 +- shared/build.gradle | 4 +- 22 files changed, 358 insertions(+), 316 deletions(-) delete mode 100644 Habitica/src/main/java/com/habitrpg/android/habitica/events/BoughtGemsEvent.kt delete mode 100644 Habitica/src/main/java/com/habitrpg/android/habitica/events/ShowAchievementDialog.kt delete mode 100644 Habitica/src/main/java/com/habitrpg/android/habitica/events/ShowCheckinDialog.kt delete mode 100644 Habitica/src/main/java/com/habitrpg/android/habitica/events/ShowFirstDropDialog.kt delete mode 100644 Habitica/src/main/java/com/habitrpg/android/habitica/events/ShowWonChallengeDialog.kt create mode 100644 Habitica/src/main/java/com/habitrpg/android/habitica/interactors/ShowNotificationInteractor.kt delete mode 100644 Habitica/src/main/java/com/habitrpg/android/habitica/modules/ApiModule.java create mode 100644 Habitica/src/main/java/com/habitrpg/android/habitica/modules/ApiModule.kt diff --git a/Habitica/build.gradle b/Habitica/build.gradle index de3c045cf..54c1ecb59 100644 --- a/Habitica/build.gradle +++ b/Habitica/build.gradle @@ -13,7 +13,6 @@ buildscript { mavenLocal() google() mavenCentral() - jcenter() } dependencies { classpath 'com.android.tools.build:gradle:7.0.4' @@ -47,8 +46,8 @@ dependencies { implementation 'com.squareup.retrofit2:adapter-rxjava3:2.9.0' //Dependency Injection - implementation 'com.google.dagger:dagger:2.39.1' - kapt 'com.google.dagger:dagger-compiler:2.39.1' + implementation 'com.google.dagger:dagger:2.40.5' + kapt 'com.google.dagger:dagger-compiler:2.40.5' compileOnly 'javax.annotation:javax.annotation-api:1.3.2' compileOnly 'com.github.pengrad:jdk9-deps:1.0' //App Compatibility and Material Design @@ -64,44 +63,51 @@ dependencies { implementation "io.noties.markwon:image:4.6.2" implementation "io.noties.markwon:recycler:4.6.2" //Eventbus - implementation 'org.greenrobot:eventbus:3.2.0' + implementation 'org.greenrobot:eventbus:3.3.1' // IAP Handling / Verification implementation 'org.solovyev.android:checkout:1.2.3' //Facebook - implementation('com.facebook.android:facebook-android-sdk:11.3.0') { + implementation('com.facebook.android:facebook-android-sdk:12.2.0') { transitive = true } implementation 'fr.avianey.com.viewpagerindicator:library:2.4.1@aar' //RxJava implementation 'io.reactivex.rxjava3:rxandroid:3.0.0' - implementation 'io.reactivex.rxjava3:rxjava:3.1.1' + implementation 'io.reactivex.rxjava3:rxjava:3.1.3' implementation 'io.reactivex.rxjava3:rxkotlin:3.0.1' implementation 'io.reactivex.rxjava2:rxjava:2.2.21' - implementation "com.github.akarnokd:rxjava3-bridge:3.0.0" + implementation "com.github.akarnokd:rxjava3-bridge:3.0.2" //Analytics - implementation 'com.amplitude:android-sdk:2.30.0' + implementation 'com.amplitude:android-sdk:3.35.1' // Image Management Library implementation("io.coil-kt:coil:1.4.0") implementation("io.coil-kt:coil-gif:1.4.0") //Tests - testImplementation 'io.kotest:kotest-runner-junit5:4.6.2' + testImplementation 'io.kotest:kotest-runner-junit5:5.0.3' testImplementation 'androidx.test:core:1.4.0' - testImplementation "io.mockk:mockk:1.12.0" - testImplementation "io.mockk:mockk-android:1.12.0" - testImplementation 'io.kotest:kotest-assertions-core:4.6.2' + testImplementation "io.mockk:mockk:1.12.2" + testImplementation "io.mockk:mockk-android:1.12.2" + testImplementation 'io.kotest:kotest-assertions-core:5.0.3' testImplementation 'io.kotest:kotest-framework-datatest:4.6.2' - androidTestImplementation 'com.kaspersky.android-components:kaspresso:1.2.1' + androidTestImplementation 'com.kaspersky.android-components:kaspresso:1.4.0' androidTestImplementation 'androidx.test.espresso:espresso-core:3.4.0' androidTestImplementation 'androidx.test:runner:1.4.0' androidTestImplementation 'androidx.test:rules:1.4.0' androidTestImplementation 'androidx.test.ext:junit:1.1.3' - androidTestImplementation "io.mockk:mockk-android:1.12.0" + androidTestImplementation "io.mockk:mockk-android:1.12.2" + + implementation 'androidx.activity:activity-compose:1.4.0' + implementation 'androidx.compose.material:material:1.0.5' + implementation 'androidx.compose.animation:animation:1.0.5' + implementation 'androidx.compose.ui:ui-tooling:1.0.5' + implementation 'androidx.lifecycle:lifecycle-viewmodel-compose:2.4.0' + implementation "com.google.accompanist:accompanist-appcompat-theme:0.16.0" //Leak Detection - debugImplementation 'com.squareup.leakcanary:leakcanary-android:2.7' + debugImplementation 'com.squareup.leakcanary:leakcanary-android:2.8' //Push Notifications implementation platform('com.google.firebase:firebase-bom:29.0.0') implementation 'com.google.firebase:firebase-crashlytics-ktx' @@ -109,7 +115,7 @@ dependencies { implementation 'com.google.firebase:firebase-messaging-ktx' implementation 'com.google.firebase:firebase-config-ktx' implementation 'com.google.firebase:firebase-perf-ktx' - implementation 'com.google.android.gms:play-services-auth:19.2.0' + implementation 'com.google.android.gms:play-services-auth:20.0.0' implementation 'com.nex3z:flow-layout:1.2.2' implementation 'androidx.core:core-ktx:1.7.0' @@ -121,14 +127,14 @@ dependencies { implementation 'com.plattysoft.leonids:LeonidsLib:1.3.2' implementation "androidx.fragment:fragment-ktx:1.4.0" implementation "androidx.paging:paging-runtime-ktx:3.1.0" - implementation 'org.jetbrains.kotlinx:kotlinx-coroutines-core:1.5.2' - implementation 'org.jetbrains.kotlinx:kotlinx-coroutines-android:1.5.2' + implementation 'org.jetbrains.kotlinx:kotlinx-coroutines-core:1.6.0' + implementation 'org.jetbrains.kotlinx:kotlinx-coroutines-android:1.6.0' implementation 'com.willowtreeapps:signinwithapplebutton:0.3' implementation project(':shared') - ktlint("com.pinterest:ktlint:0.42.1") { + ktlint("com.pinterest:ktlint:0.43.2") { attributes { attribute(Bundling.BUNDLING_ATTRIBUTE, getObjects().named(Bundling, Bundling.EXTERNAL)) } @@ -136,7 +142,7 @@ dependencies { } android { - compileSdkVersion 31 + compileSdkVersion 32 buildToolsVersion '30.0.2' testOptions { unitTests { @@ -153,9 +159,9 @@ android { resConfigs "en", "bg", "de", "en-rGB", "es", "fr", "hr-rHR", "in", "it", "iw", "ja", "ko", "lt", "nl", "pl", "pt-rBR", "pt-rPT", "ru", "tr", "zh", "zh-rTW" versionCode 3128 - versionName "3.4.2" + versionName "3.5" - targetSdkVersion 31 + targetSdkVersion 32 testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" } 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 a38588643..f1aa27bb8 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 @@ -80,8 +80,6 @@ class ApiClientImpl // private OnHabitsAPIResult mResultListener; private var lastAPICallURL: String? = null init { - this.notificationsManager.setApiClient(this) - HabiticaBaseApplication.userComponent?.inject(this) analyticsManager.setUserIdentifier(this.hostConfig.userID) buildRetrofit() diff --git a/Habitica/src/main/java/com/habitrpg/android/habitica/events/BoughtGemsEvent.kt b/Habitica/src/main/java/com/habitrpg/android/habitica/events/BoughtGemsEvent.kt deleted file mode 100644 index 4b73530fc..000000000 --- a/Habitica/src/main/java/com/habitrpg/android/habitica/events/BoughtGemsEvent.kt +++ /dev/null @@ -1,6 +0,0 @@ -package com.habitrpg.android.habitica.events - -/** - * Created by Negue on 29.11.2015. - */ -class BoughtGemsEvent(var NewGemsToAdd: Int) diff --git a/Habitica/src/main/java/com/habitrpg/android/habitica/events/GearPurchasedEvent.kt b/Habitica/src/main/java/com/habitrpg/android/habitica/events/GearPurchasedEvent.kt index 36dd4fab0..2b1384cb0 100644 --- a/Habitica/src/main/java/com/habitrpg/android/habitica/events/GearPurchasedEvent.kt +++ b/Habitica/src/main/java/com/habitrpg/android/habitica/events/GearPurchasedEvent.kt @@ -2,4 +2,4 @@ package com.habitrpg.android.habitica.events import com.habitrpg.android.habitica.models.shops.ShopItem -class GearPurchasedEvent(val item: ShopItem) +class GearPurchasedEvent(val item: ShopItem) diff --git a/Habitica/src/main/java/com/habitrpg/android/habitica/events/ShowAchievementDialog.kt b/Habitica/src/main/java/com/habitrpg/android/habitica/events/ShowAchievementDialog.kt deleted file mode 100644 index 081a69e33..000000000 --- a/Habitica/src/main/java/com/habitrpg/android/habitica/events/ShowAchievementDialog.kt +++ /dev/null @@ -1,3 +0,0 @@ -package com.habitrpg.android.habitica.events - -class ShowAchievementDialog(var type: String, val id: String, val message: String? = null, val text: String? = null, val isLastOnboardingAchievement: Boolean = false) diff --git a/Habitica/src/main/java/com/habitrpg/android/habitica/events/ShowCheckinDialog.kt b/Habitica/src/main/java/com/habitrpg/android/habitica/events/ShowCheckinDialog.kt deleted file mode 100644 index 733f3dfa5..000000000 --- a/Habitica/src/main/java/com/habitrpg/android/habitica/events/ShowCheckinDialog.kt +++ /dev/null @@ -1,5 +0,0 @@ -package com.habitrpg.android.habitica.events - -import com.habitrpg.android.habitica.models.Notification - -class ShowCheckinDialog(var notification: Notification, var nextUnlockText: String, var nextUnlockCount: Int) diff --git a/Habitica/src/main/java/com/habitrpg/android/habitica/events/ShowFirstDropDialog.kt b/Habitica/src/main/java/com/habitrpg/android/habitica/events/ShowFirstDropDialog.kt deleted file mode 100644 index 7f2accb6e..000000000 --- a/Habitica/src/main/java/com/habitrpg/android/habitica/events/ShowFirstDropDialog.kt +++ /dev/null @@ -1,3 +0,0 @@ -package com.habitrpg.android.habitica.events - -class ShowFirstDropDialog(val egg: String, val hatchingPotion: String, val id: String) diff --git a/Habitica/src/main/java/com/habitrpg/android/habitica/events/ShowWonChallengeDialog.kt b/Habitica/src/main/java/com/habitrpg/android/habitica/events/ShowWonChallengeDialog.kt deleted file mode 100644 index 5a0dabdbc..000000000 --- a/Habitica/src/main/java/com/habitrpg/android/habitica/events/ShowWonChallengeDialog.kt +++ /dev/null @@ -1,5 +0,0 @@ -package com.habitrpg.android.habitica.events - -import com.habitrpg.android.habitica.models.notifications.ChallengeWonData - -class ShowWonChallengeDialog(val id: String, val data: ChallengeWonData?) diff --git a/Habitica/src/main/java/com/habitrpg/android/habitica/helpers/NotificationsManager.kt b/Habitica/src/main/java/com/habitrpg/android/habitica/helpers/NotificationsManager.kt index a854de30a..57b80ed41 100644 --- a/Habitica/src/main/java/com/habitrpg/android/habitica/helpers/NotificationsManager.kt +++ b/Habitica/src/main/java/com/habitrpg/android/habitica/helpers/NotificationsManager.kt @@ -1,6 +1,7 @@ package com.habitrpg.android.habitica.helpers import android.content.Context +import androidx.lifecycle.MutableLiveData import com.google.firebase.analytics.FirebaseAnalytics import com.habitrpg.android.habitica.R import com.habitrpg.android.habitica.data.ApiClient @@ -12,22 +13,35 @@ import com.habitrpg.android.habitica.models.notifications.FirstDropData import com.habitrpg.android.habitica.models.notifications.LoginIncentiveData import com.habitrpg.android.habitica.models.user.User import com.habitrpg.android.habitica.ui.views.HabiticaSnackbar +import com.habitrpg.android.habitica.ui.views.dialogs.WonChallengeDialog import io.reactivex.rxjava3.core.BackpressureStrategy import io.reactivex.rxjava3.core.Completable import io.reactivex.rxjava3.core.Flowable import io.reactivex.rxjava3.subjects.BehaviorSubject +import io.reactivex.rxjava3.subjects.PublishSubject +import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.GlobalScope +import kotlinx.coroutines.launch import org.greenrobot.eventbus.EventBus +import java.lang.ref.WeakReference import java.util.* import java.util.concurrent.TimeUnit +import kotlin.coroutines.CoroutineContext + +class NotificationsManager { + private val displayNotificationSubject = PublishSubject.create() -class NotificationsManager(private val context: Context) { private val seenNotifications: MutableMap - private var apiClient: ApiClient? = null - + lateinit var apiClient: WeakReference private val notifications: BehaviorSubject> private var lastNotificationHandling: Date? = null + val displayNotificationEvents: Flowable + get() { + return displayNotificationSubject.toFlowable(BackpressureStrategy.DROP) + } + init { this.seenNotifications = HashMap() this.notifications = BehaviorSubject.create() @@ -48,11 +62,7 @@ class NotificationsManager(private val context: Context) { return this.notifications.value?.find { it.id == id } } - fun setApiClient(apiClient: ApiClient?) { - this.apiClient = apiClient - } - - private fun handlePopupNotifications(notifications: List): Boolean? { + private fun handlePopupNotifications(notifications: List): Boolean { val now = Date() if (now.time - (lastNotificationHandling?.time ?: 0) < 300) { return true @@ -62,116 +72,56 @@ class NotificationsManager(private val context: Context) { .filter { !this.seenNotifications.containsKey(it.id) } .map { val notificationDisplayed = when (it.type) { - Notification.Type.LOGIN_INCENTIVE.type -> displayLoginIncentiveNotification(it) - Notification.Type.ACHIEVEMENT_PARTY_UP.type -> displayAchievementNotification(it) - Notification.Type.ACHIEVEMENT_PARTY_ON.type -> displayAchievementNotification(it) - Notification.Type.ACHIEVEMENT_BEAST_MASTER.type -> displayAchievementNotification(it) - Notification.Type.ACHIEVEMENT_MOUNT_MASTER.type -> displayAchievementNotification(it) - Notification.Type.ACHIEVEMENT_TRIAD_BINGO.type -> displayAchievementNotification(it) - Notification.Type.ACHIEVEMENT_GUILD_JOINED.type -> displayAchievementNotification(it) - Notification.Type.ACHIEVEMENT_CHALLENGE_JOINED.type -> displayAchievementNotification(it) - Notification.Type.ACHIEVEMENT_INVITED_FRIEND.type -> displayAchievementNotification(it) - Notification.Type.WON_CHALLENGE.type -> displayWonChallengeNotificaiton(it) + Notification.Type.ACHIEVEMENT_PARTY_UP.type -> true + Notification.Type.ACHIEVEMENT_PARTY_ON.type -> true + Notification.Type.ACHIEVEMENT_BEAST_MASTER.type -> true + Notification.Type.ACHIEVEMENT_MOUNT_MASTER.type -> true + Notification.Type.ACHIEVEMENT_TRIAD_BINGO.type -> true + Notification.Type.ACHIEVEMENT_GUILD_JOINED.type -> true + Notification.Type.ACHIEVEMENT_CHALLENGE_JOINED.type -> true + Notification.Type.ACHIEVEMENT_INVITED_FRIEND.type -> true - Notification.Type.ACHIEVEMENT_ALL_YOUR_BASE.type -> displayAchievementNotification(it) - Notification.Type.ACHIEVEMENT_BACK_TO_BASICS.type -> displayAchievementNotification(it) - Notification.Type.ACHIEVEMENT_JUST_ADD_WATER.type -> displayAchievementNotification(it) - Notification.Type.ACHIEVEMENT_LOST_MASTERCLASSER.type -> displayAchievementNotification(it) - Notification.Type.ACHIEVEMENT_MIND_OVER_MATTER.type -> displayAchievementNotification(it) - Notification.Type.ACHIEVEMENT_DUST_DEVIL.type -> displayAchievementNotification(it) - Notification.Type.ACHIEVEMENT_ARID_AUTHORITY.type -> displayAchievementNotification(it) - Notification.Type.ACHIEVEMENT_MONSTER_MAGUS.type -> displayAchievementNotification(it) - Notification.Type.ACHIEVEMENT_UNDEAD_UNDERTAKER.type -> displayAchievementNotification(it) - Notification.Type.ACHIEVEMENT_PRIMED_FOR_PAINTING.type -> displayAchievementNotification(it) - Notification.Type.ACHIEVEMENT_PEARLY_PRO.type -> displayAchievementNotification(it) - Notification.Type.ACHIEVEMENT_TICKLED_PINK.type -> displayAchievementNotification(it) - Notification.Type.ACHIEVEMENT_ROSY_OUTLOOK.type -> displayAchievementNotification(it) - Notification.Type.ACHIEVEMENT_BUG_BONANZA.type -> displayAchievementNotification(it) - Notification.Type.ACHIEVEMENT_BARE_NECESSITIES.type -> displayAchievementNotification(it) - Notification.Type.ACHIEVEMENT_FRESHWATER_FRIENDS.type -> displayAchievementNotification(it) - Notification.Type.ACHIEVEMENT_GOOD_AS_GOLD.type -> displayAchievementNotification(it) - Notification.Type.ACHIEVEMENT_ALL_THAT_GLITTERS.type -> displayAchievementNotification(it) - Notification.Type.ACHIEVEMENT_GOOD_AS_GOLD.type -> displayAchievementNotification(it) - Notification.Type.ACHIEVEMENT_BONE_COLLECTOR.type -> displayAchievementNotification(it) - Notification.Type.ACHIEVEMENT_SKELETON_CREW.type -> displayAchievementNotification(it) - Notification.Type.ACHIEVEMENT_SEEING_RED.type -> displayAchievementNotification(it) - Notification.Type.ACHIEVEMENT_RED_LETTER_DAY.type -> displayAchievementNotification(it) + Notification.Type.ACHIEVEMENT_ALL_YOUR_BASE.type -> true + Notification.Type.ACHIEVEMENT_BACK_TO_BASICS.type -> true + Notification.Type.ACHIEVEMENT_JUST_ADD_WATER.type -> true + Notification.Type.ACHIEVEMENT_LOST_MASTERCLASSER.type -> true + Notification.Type.ACHIEVEMENT_MIND_OVER_MATTER.type -> true + Notification.Type.ACHIEVEMENT_DUST_DEVIL.type -> true + Notification.Type.ACHIEVEMENT_ARID_AUTHORITY.type -> true + Notification.Type.ACHIEVEMENT_MONSTER_MAGUS.type -> true + Notification.Type.ACHIEVEMENT_UNDEAD_UNDERTAKER.type -> true + Notification.Type.ACHIEVEMENT_PRIMED_FOR_PAINTING.type -> true + Notification.Type.ACHIEVEMENT_PEARLY_PRO.type -> true + Notification.Type.ACHIEVEMENT_TICKLED_PINK.type -> true + Notification.Type.ACHIEVEMENT_ROSY_OUTLOOK.type -> true + Notification.Type.ACHIEVEMENT_BUG_BONANZA.type -> true + Notification.Type.ACHIEVEMENT_BARE_NECESSITIES.type -> true + Notification.Type.ACHIEVEMENT_FRESHWATER_FRIENDS.type -> true + Notification.Type.ACHIEVEMENT_GOOD_AS_GOLD.type -> true + Notification.Type.ACHIEVEMENT_ALL_THAT_GLITTERS.type -> true + Notification.Type.ACHIEVEMENT_GOOD_AS_GOLD.type -> true + Notification.Type.ACHIEVEMENT_BONE_COLLECTOR.type -> true + Notification.Type.ACHIEVEMENT_SKELETON_CREW.type -> true + Notification.Type.ACHIEVEMENT_SEEING_RED.type -> true + Notification.Type.ACHIEVEMENT_RED_LETTER_DAY.type -> true - Notification.Type.ACHIEVEMENT_GENERIC.type -> displayAchievementNotification( - it, - notifications.find { notif -> - notif.type == Notification.Type.ACHIEVEMENT_ONBOARDING_COMPLETE.type - } != null - ) - Notification.Type.ACHIEVEMENT_ONBOARDING_COMPLETE.type -> displayAchievementNotification(it) - Notification.Type.FIRST_DROP.type -> displayFirstDropNotification(it) + Notification.Type.ACHIEVEMENT_GENERIC.type -> true + Notification.Type.ACHIEVEMENT_ONBOARDING_COMPLETE.type -> true else -> false } - if (notificationDisplayed == true) { + if (notificationDisplayed) { + displayNotificationSubject.onNext(it) this.seenNotifications[it.id] = true + readNotification(it) } } return true } - private fun displayWonChallengeNotificaiton(notification: Notification): Boolean { - EventBus.getDefault().post(ShowWonChallengeDialog(notification.id, notification.data as? ChallengeWonData)) - return true - } - - private fun displayFirstDropNotification(notification: Notification): Boolean { - val data = (notification.data as? FirstDropData) - EventBus.getDefault().post(ShowFirstDropDialog(data?.egg ?: "", data?.hatchingPotion ?: "", notification.id)) - return true - } - - private fun displayLoginIncentiveNotification(notification: Notification): Boolean? { - val notificationData = notification.data as? LoginIncentiveData - val nextUnlockText = context.getString(R.string.nextPrizeUnlocks, notificationData?.nextRewardAt) - if (notificationData?.rewardKey != null) { - val event = ShowCheckinDialog(notification, nextUnlockText, notificationData.nextRewardAt ?: 0) - EventBus.getDefault().post(event) - } else { - val event = ShowSnackbarEvent() - event.title = notificationData?.message - event.text = nextUnlockText - event.type = HabiticaSnackbar.SnackbarDisplayType.BLUE - EventBus.getDefault().post(event) - if (apiClient != null) { - apiClient?.readNotification(notification.id) - ?.subscribe({}, RxErrorHandler.handleEmptyError()) - } - } - return true - } - - private fun displayAchievementNotification(notification: Notification, isLastOnboardingAchievement: Boolean = false): Boolean { - val data = (notification.data as? AchievementData) - val achievement = data?.achievement ?: notification.type ?: "" - val delay: Long = if (achievement == "createdTask" || achievement == Notification.Type.ACHIEVEMENT_ONBOARDING_COMPLETE.type) { - 1000 - } else { - 200 - } - val sub = Completable.complete() - .delay(delay, TimeUnit.MILLISECONDS) - .subscribe( - { - EventBus.getDefault().post(ShowAchievementDialog(achievement, notification.id, data?.message, data?.modalText, isLastOnboardingAchievement)) - }, - RxErrorHandler.handleEmptyError() - ) - logOnboardingEvents(achievement) - return true - } - - private fun logOnboardingEvents(type: String) { - if (User.ONBOARDING_ACHIEVEMENT_KEYS.contains(type)) { - FirebaseAnalytics.getInstance(context).logEvent(type, null) - } else if (type == Notification.Type.ACHIEVEMENT_ONBOARDING_COMPLETE.type) { - FirebaseAnalytics.getInstance(context).logEvent(type, null) - } + private fun readNotification(notification: Notification) { + apiClient.get()?.readNotification(notification.id) + ?.subscribe({ }, RxErrorHandler.handleEmptyError()) } } 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 5959c6f57..d3509639c 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 @@ -156,7 +156,6 @@ open class PurchaseHandler(activity: Activity, val analyticsManager: AnalyticsMa purchase.token, object : RequestListener { override fun onSuccess(o: Any) { - // EventBus.getDefault().post(new BoughtGemsEvent(GEMS_TO_ADD)); } override fun onError(i: Int, e: Exception) { diff --git a/Habitica/src/main/java/com/habitrpg/android/habitica/interactors/ShowNotificationInteractor.kt b/Habitica/src/main/java/com/habitrpg/android/habitica/interactors/ShowNotificationInteractor.kt new file mode 100644 index 000000000..54c908708 --- /dev/null +++ b/Habitica/src/main/java/com/habitrpg/android/habitica/interactors/ShowNotificationInteractor.kt @@ -0,0 +1,169 @@ +package com.habitrpg.android.habitica.interactors + +import android.app.Activity +import android.view.LayoutInflater +import android.view.View +import android.widget.ImageView +import android.widget.TextView +import androidx.lifecycle.LifecycleCoroutineScope +import androidx.lifecycle.lifecycleScope +import com.google.firebase.analytics.FirebaseAnalytics +import com.habitrpg.android.habitica.R +import com.habitrpg.android.habitica.events.* +import com.habitrpg.android.habitica.helpers.RxErrorHandler +import com.habitrpg.android.habitica.models.Notification +import com.habitrpg.android.habitica.models.notifications.AchievementData +import com.habitrpg.android.habitica.models.notifications.ChallengeWonData +import com.habitrpg.android.habitica.models.notifications.FirstDropData +import com.habitrpg.android.habitica.models.notifications.LoginIncentiveData +import com.habitrpg.android.habitica.models.user.User +import com.habitrpg.android.habitica.ui.helpers.DataBindingUtils +import com.habitrpg.android.habitica.ui.views.HabiticaSnackbar +import com.habitrpg.android.habitica.ui.views.dialogs.AchievementDialog +import com.habitrpg.android.habitica.ui.views.dialogs.FirstDropDialog +import com.habitrpg.android.habitica.ui.views.dialogs.HabiticaAlertDialog +import com.habitrpg.android.habitica.ui.views.dialogs.WonChallengeDialog +import io.reactivex.rxjava3.core.Completable +import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.delay +import kotlinx.coroutines.launch +import org.greenrobot.eventbus.EventBus +import org.greenrobot.eventbus.Subscribe +import java.util.concurrent.TimeUnit + +class ShowNotificationInteractor(private val activity: Activity, private val lifecycleScope: LifecycleCoroutineScope) { + + fun handleNotification(notification: Notification) { + when (notification.type) { + Notification.Type.LOGIN_INCENTIVE.type -> showCheckinDialog(notification) + Notification.Type.ACHIEVEMENT_PARTY_UP.type -> showAchievementDialog(notification) + Notification.Type.ACHIEVEMENT_PARTY_ON.type -> showAchievementDialog(notification) + Notification.Type.ACHIEVEMENT_BEAST_MASTER.type -> showAchievementDialog(notification) + Notification.Type.ACHIEVEMENT_MOUNT_MASTER.type -> showAchievementDialog(notification) + Notification.Type.ACHIEVEMENT_TRIAD_BINGO.type -> showAchievementDialog(notification) + Notification.Type.ACHIEVEMENT_GUILD_JOINED.type -> showAchievementDialog(notification) + Notification.Type.ACHIEVEMENT_CHALLENGE_JOINED.type -> showAchievementDialog(notification) + Notification.Type.ACHIEVEMENT_INVITED_FRIEND.type -> showAchievementDialog(notification) + Notification.Type.WON_CHALLENGE.type -> showWonChallengeDialog(notification) + + Notification.Type.ACHIEVEMENT_ALL_YOUR_BASE.type -> showAchievementDialog(notification) + Notification.Type.ACHIEVEMENT_BACK_TO_BASICS.type -> showAchievementDialog(notification) + Notification.Type.ACHIEVEMENT_JUST_ADD_WATER.type -> showAchievementDialog(notification) + Notification.Type.ACHIEVEMENT_LOST_MASTERCLASSER.type -> showAchievementDialog(notification) + Notification.Type.ACHIEVEMENT_MIND_OVER_MATTER.type -> showAchievementDialog(notification) + Notification.Type.ACHIEVEMENT_DUST_DEVIL.type -> showAchievementDialog(notification) + Notification.Type.ACHIEVEMENT_ARID_AUTHORITY.type -> showAchievementDialog(notification) + Notification.Type.ACHIEVEMENT_MONSTER_MAGUS.type -> showAchievementDialog(notification) + Notification.Type.ACHIEVEMENT_UNDEAD_UNDERTAKER.type -> showAchievementDialog(notification) + Notification.Type.ACHIEVEMENT_PRIMED_FOR_PAINTING.type -> showAchievementDialog(notification) + Notification.Type.ACHIEVEMENT_PEARLY_PRO.type -> showAchievementDialog(notification) + Notification.Type.ACHIEVEMENT_TICKLED_PINK.type -> showAchievementDialog(notification) + Notification.Type.ACHIEVEMENT_ROSY_OUTLOOK.type -> showAchievementDialog(notification) + Notification.Type.ACHIEVEMENT_BUG_BONANZA.type -> showAchievementDialog(notification) + Notification.Type.ACHIEVEMENT_BARE_NECESSITIES.type -> showAchievementDialog(notification) + Notification.Type.ACHIEVEMENT_FRESHWATER_FRIENDS.type -> showAchievementDialog(notification) + Notification.Type.ACHIEVEMENT_GOOD_AS_GOLD.type -> showAchievementDialog(notification) + Notification.Type.ACHIEVEMENT_ALL_THAT_GLITTERS.type -> showAchievementDialog(notification) + Notification.Type.ACHIEVEMENT_GOOD_AS_GOLD.type -> showAchievementDialog(notification) + Notification.Type.ACHIEVEMENT_BONE_COLLECTOR.type -> showAchievementDialog(notification) + Notification.Type.ACHIEVEMENT_SKELETON_CREW.type -> showAchievementDialog(notification) + Notification.Type.ACHIEVEMENT_SEEING_RED.type -> showAchievementDialog(notification) + Notification.Type.ACHIEVEMENT_RED_LETTER_DAY.type -> showAchievementDialog(notification) + + Notification.Type.ACHIEVEMENT_GENERIC.type -> showAchievementDialog(notification) + Notification.Type.ACHIEVEMENT_ONBOARDING_COMPLETE.type -> showAchievementDialog(notification) + Notification.Type.FIRST_DROP.type -> showFirstDropDialog(notification) + else -> false + } + } + + @Subscribe + fun showCheckinDialog(notification: Notification) { + val notificationData = notification.data as? LoginIncentiveData + val nextUnlockText = activity.getString(R.string.nextPrizeUnlocks, notificationData?.nextRewardAt) + if (notificationData?.rewardKey != null) { + val title = notificationData.message + + val factory = LayoutInflater.from(activity) + val view = factory.inflate(R.layout.dialog_login_incentive, null) + + val imageView = view.findViewById(R.id.imageView) as? ImageView + var imageKey = notificationData?.rewardKey?.get(0) + if (imageKey?.contains("armor") == true) { + imageKey = "slim_$imageKey" + } + DataBindingUtils.loadImage(imageView, imageKey) + + val youEarnedMessage = activity.getString(R.string.checkInRewardEarned, notificationData?.rewardText) + val youEarnedTexView = view.findViewById(R.id.you_earned_message) as? TextView + youEarnedTexView?.text = youEarnedMessage + + val nextUnlockTextView = view.findViewById(R.id.next_unlock_message) as? TextView + if ((notificationData.nextRewardAt ?: 0) > 0) { + nextUnlockTextView?.text = nextUnlockText + } else { + nextUnlockTextView?.visibility = View.GONE + } + + lifecycleScope.launch(context = Dispatchers.Main) { + val alert = HabiticaAlertDialog(activity) + alert.setAdditionalContentView(view) + alert.setTitle(title) + alert.addButton(R.string.see_you_tomorrow, true) + alert.show() + } + } else { + val event = ShowSnackbarEvent() + event.title = notificationData?.message + event.text = nextUnlockText + event.type = HabiticaSnackbar.SnackbarDisplayType.BLUE + EventBus.getDefault().post(event) + } + } + + @Subscribe + fun showAchievementDialog(notification: Notification) { + val data = (notification.data as? AchievementData) ?: return + val achievement = data.achievement ?: notification.type ?: "" + val delayTime: Long = if (achievement == "createdTask" || achievement == Notification.Type.ACHIEVEMENT_ONBOARDING_COMPLETE.type) { + 1000 + } else { + 200 + } + lifecycleScope.launch() { + delay(delayTime) + lifecycleScope.launch(context = Dispatchers.Main) { + val dialog = AchievementDialog(activity) + dialog.isLastOnboardingAchievement = data.isLastOnboardingAchievement + dialog.setType(data.achievement ?: "", data.message, data.modalText) + dialog.enqueue() + } + } + logOnboardingEvents(achievement) + } + + private fun showFirstDropDialog(notification: Notification) { + val data = notification.data as? FirstDropData ?: return + lifecycleScope.launch(context = Dispatchers.Main) { + val dialog = FirstDropDialog(activity) + dialog.configure(data.egg ?: "", data.hatchingPotion ?: "") + dialog.enqueue() + } + } + + private fun showWonChallengeDialog(notification: Notification) { + lifecycleScope.launch(context = Dispatchers.Main) { + val dialog = WonChallengeDialog(activity) + dialog.configure(notification.data as? ChallengeWonData) + dialog.enqueue() + } + } + + private fun logOnboardingEvents(type: String) { + if (User.ONBOARDING_ACHIEVEMENT_KEYS.contains(type)) { + FirebaseAnalytics.getInstance(activity).logEvent(type, null) + } else if (type == Notification.Type.ACHIEVEMENT_ONBOARDING_COMPLETE.type) { + FirebaseAnalytics.getInstance(activity).logEvent(type, null) + } + } +} diff --git a/Habitica/src/main/java/com/habitrpg/android/habitica/models/notifications/AchievementData.kt b/Habitica/src/main/java/com/habitrpg/android/habitica/models/notifications/AchievementData.kt index 3fe34cd06..c00a6ca85 100644 --- a/Habitica/src/main/java/com/habitrpg/android/habitica/models/notifications/AchievementData.kt +++ b/Habitica/src/main/java/com/habitrpg/android/habitica/models/notifications/AchievementData.kt @@ -2,6 +2,7 @@ package com.habitrpg.android.habitica.models.notifications open class AchievementData : NotificationData { + val isLastOnboardingAchievement: Boolean = false var achievement: String? = null var message: String? = null var modalText: String? = null diff --git a/Habitica/src/main/java/com/habitrpg/android/habitica/modules/ApiModule.java b/Habitica/src/main/java/com/habitrpg/android/habitica/modules/ApiModule.java deleted file mode 100644 index e753b8cdf..000000000 --- a/Habitica/src/main/java/com/habitrpg/android/habitica/modules/ApiModule.java +++ /dev/null @@ -1,58 +0,0 @@ -package com.habitrpg.android.habitica.modules; - -import android.content.Context; -import android.content.SharedPreferences; - -import com.habitrpg.android.habitica.api.HostConfig; -import com.habitrpg.android.habitica.api.MaintenanceApiService; -import com.habitrpg.android.habitica.data.ApiClient; -import com.habitrpg.android.habitica.data.implementation.ApiClientImpl; -import com.habitrpg.android.habitica.helpers.NotificationsManager; -import com.habitrpg.android.habitica.helpers.KeyHelper; -import com.habitrpg.android.habitica.proxy.AnalyticsManager; - -import javax.annotation.Nullable; -import javax.inject.Singleton; - -import dagger.Module; -import dagger.Provides; -import retrofit2.Retrofit; -import retrofit2.adapter.rxjava3.RxJava3CallAdapterFactory; -import retrofit2.converter.gson.GsonConverterFactory; - -@Module -public class ApiModule { - - @Provides - @Singleton - public HostConfig providesHostConfig(SharedPreferences sharedPreferences, @Nullable KeyHelper keyHelper, Context context) { - return new HostConfig(sharedPreferences, keyHelper, context); - } - - @Provides - public GsonConverterFactory providesGsonConverterFactory() { - return ApiClientImpl.Companion.createGsonFactory(); - } - - @Provides - @Singleton - public NotificationsManager providesPopupNotificationsManager(Context context) { - return new NotificationsManager(context); - } - - @Provides - @Singleton - public ApiClient providesApiHelper(GsonConverterFactory gsonConverter, HostConfig hostConfig, AnalyticsManager analyticsManager, NotificationsManager notificationsManager, Context context) { - return new ApiClientImpl(gsonConverter, hostConfig, analyticsManager, notificationsManager, context); - } - - @Provides - public MaintenanceApiService providesMaintenanceApiService(GsonConverterFactory gsonConverter) { - Retrofit adapter = new Retrofit.Builder() - .baseUrl("https://habitica-assets.s3.amazonaws.com/mobileApp/endpoint/") - .addCallAdapterFactory(RxJava3CallAdapterFactory.create()) - .addConverterFactory(gsonConverter) - .build(); - return adapter.create(MaintenanceApiService.class); - } -} 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 new file mode 100644 index 000000000..c98cc4b0b --- /dev/null +++ b/Habitica/src/main/java/com/habitrpg/android/habitica/modules/ApiModule.kt @@ -0,0 +1,73 @@ +package com.habitrpg.android.habitica.modules + +import android.content.Context +import com.habitrpg.android.habitica.data.implementation.ApiClientImpl.Companion.createGsonFactory +import android.content.SharedPreferences +import com.habitrpg.android.habitica.helpers.KeyHelper +import com.habitrpg.android.habitica.api.HostConfig +import retrofit2.converter.gson.GsonConverterFactory +import com.habitrpg.android.habitica.data.implementation.ApiClientImpl +import com.habitrpg.android.habitica.helpers.NotificationsManager +import com.habitrpg.android.habitica.proxy.AnalyticsManager +import com.habitrpg.android.habitica.data.ApiClient +import com.habitrpg.android.habitica.api.MaintenanceApiService +import dagger.Module +import dagger.Provides +import retrofit2.Retrofit +import retrofit2.adapter.rxjava3.RxJava3CallAdapterFactory +import java.lang.ref.WeakReference +import javax.inject.Singleton + +@Module +open class ApiModule { + @Provides + @Singleton + fun providesHostConfig( + sharedPreferences: SharedPreferences, + keyHelper: KeyHelper?, + context: Context + ): HostConfig { + return HostConfig(sharedPreferences, keyHelper, context) + } + + @Provides + fun providesGsonConverterFactory(): GsonConverterFactory { + return createGsonFactory() + } + + @Provides + @Singleton + fun providesPopupNotificationsManager(): NotificationsManager { + return NotificationsManager() + } + + @Provides + @Singleton + fun providesApiHelper( + gsonConverter: GsonConverterFactory, + hostConfig: HostConfig, + analyticsManager: AnalyticsManager, + notificationsManager: NotificationsManager, + context: Context + ): ApiClient { + val apiClient = ApiClientImpl( + gsonConverter, + hostConfig, + analyticsManager, + notificationsManager, + context + ) + notificationsManager.apiClient = WeakReference(apiClient) + return apiClient + } + + @Provides + fun providesMaintenanceApiService(gsonConverter: GsonConverterFactory): MaintenanceApiService { + val adapter = Retrofit.Builder() + .baseUrl("https://habitica-assets.s3.amazonaws.com/mobileApp/endpoint/") + .addCallAdapterFactory(RxJava3CallAdapterFactory.create()) + .addConverterFactory(gsonConverter) + .build() + return adapter.create(MaintenanceApiService::class.java) + } +} diff --git a/Habitica/src/main/java/com/habitrpg/android/habitica/ui/AvatarWithBarsViewModel.kt b/Habitica/src/main/java/com/habitrpg/android/habitica/ui/AvatarWithBarsViewModel.kt index 03a6e92ac..ccb64cf42 100644 --- a/Habitica/src/main/java/com/habitrpg/android/habitica/ui/AvatarWithBarsViewModel.kt +++ b/Habitica/src/main/java/com/habitrpg/android/habitica/ui/AvatarWithBarsViewModel.kt @@ -9,7 +9,6 @@ import androidx.core.os.bundleOf import com.habitrpg.android.habitica.R import com.habitrpg.android.habitica.data.UserRepository import com.habitrpg.android.habitica.databinding.AvatarWithBarsBinding -import com.habitrpg.android.habitica.events.BoughtGemsEvent import com.habitrpg.android.habitica.helpers.HealthFormatter import com.habitrpg.android.habitica.helpers.MainNavigationController import com.habitrpg.android.habitica.models.Avatar @@ -17,7 +16,6 @@ import com.habitrpg.android.habitica.models.user.Stats import com.habitrpg.android.habitica.models.user.User import com.habitrpg.android.habitica.ui.views.HabiticaIconsHelper import io.reactivex.rxjava3.disposables.Disposable -import org.greenrobot.eventbus.Subscribe import java.util.* import kotlin.math.floor @@ -111,13 +109,6 @@ class AvatarWithBarsViewModel(private val context: Context, private val binding: binding.mpBar.set(floor(value.toDouble()), cachedMaxMana.toDouble()) } - @Subscribe - fun onEvent(gemsEvent: BoughtGemsEvent) { - var gems = userObject?.gemCount ?: 0 - gems += gemsEvent.NewGemsToAdd - binding.currencyView.gems = gems.toDouble() - } - companion object { private fun setUserLevel(context: Context, textView: TextView, level: Int?) { textView.text = context.getString(R.string.user_level, level) 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 335d7ff5f..74265b933 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 @@ -14,6 +14,7 @@ import androidx.appcompat.app.AppCompatActivity import androidx.appcompat.app.AppCompatDelegate import androidx.appcompat.widget.Toolbar import androidx.core.content.ContextCompat +import androidx.lifecycle.lifecycleScope import androidx.preference.PreferenceManager import com.habitrpg.android.habitica.HabiticaApplication import com.habitrpg.android.habitica.HabiticaBaseApplication @@ -24,14 +25,21 @@ import com.habitrpg.android.habitica.extensions.getThemeColor import com.habitrpg.android.habitica.extensions.isUsingNightModeResources import com.habitrpg.android.habitica.extensions.updateStatusBarColor import com.habitrpg.android.habitica.helpers.LanguageHelper +import com.habitrpg.android.habitica.helpers.NotificationsManager +import com.habitrpg.android.habitica.helpers.RxErrorHandler +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 io.reactivex.rxjava3.disposables.CompositeDisposable import org.greenrobot.eventbus.EventBus import org.greenrobot.eventbus.Subscribe import java.util.* +import javax.inject.Inject abstract class BaseActivity : AppCompatActivity() { + @Inject + lateinit var notificationsManager: NotificationsManager + private var currentTheme: String? = null private var isNightMode: Boolean = false internal var forcedTheme: String? = null @@ -76,6 +84,12 @@ abstract class BaseActivity : AppCompatActivity() { injectActivity(HabiticaBaseApplication.userComponent) setContentView(getContentView()) compositeSubscription = CompositeDisposable() + compositeSubscription.add(notificationsManager.displayNotificationEvents.subscribe( + { + ShowNotificationInteractor(this, lifecycleScope).handleNotification(it) + }, + RxErrorHandler.handleEmptyError() + )) } override fun onRestart() { diff --git a/Habitica/src/main/java/com/habitrpg/android/habitica/ui/activities/GemPurchaseActivity.kt b/Habitica/src/main/java/com/habitrpg/android/habitica/ui/activities/GemPurchaseActivity.kt index df45d1046..dd83e36e0 100644 --- a/Habitica/src/main/java/com/habitrpg/android/habitica/ui/activities/GemPurchaseActivity.kt +++ b/Habitica/src/main/java/com/habitrpg/android/habitica/ui/activities/GemPurchaseActivity.kt @@ -103,7 +103,6 @@ class GemPurchaseActivity : BaseActivity() { fun onConsumablePurchased(event: ConsumablePurchasedEvent) { if (isActivityVisible) { purchaseHandler?.consumePurchase(event.purchase) - compositeSubscription.add(userRepository.retrieveUser(false).subscribe({}, RxErrorHandler.handleEmptyError())) } } diff --git a/Habitica/src/main/java/com/habitrpg/android/habitica/ui/activities/MainActivity.kt b/Habitica/src/main/java/com/habitrpg/android/habitica/ui/activities/MainActivity.kt index a1f9e4625..631b43659 100755 --- a/Habitica/src/main/java/com/habitrpg/android/habitica/ui/activities/MainActivity.kt +++ b/Habitica/src/main/java/com/habitrpg/android/habitica/ui/activities/MainActivity.kt @@ -783,81 +783,6 @@ open class MainActivity : BaseActivity(), TutorialView.OnTutorialReaction { HabiticaSnackbar.showSnackbar(snackbarContainer, event.leftImage, event.title, event.text, event.specialView, event.rightIcon, event.rightTextColor, event.rightText, event.type) } - @Subscribe - fun showCheckinDialog(event: ShowCheckinDialog) { - val notificationData = event.notification.data as? LoginIncentiveData - val title = notificationData?.message - - val factory = LayoutInflater.from(this) - val view = factory.inflate(R.layout.dialog_login_incentive, null) - - val imageView = view.findViewById(R.id.imageView) as? ImageView - var imageKey = notificationData?.rewardKey?.get(0) - if (imageKey?.contains("armor") == true) { - imageKey = "slim_$imageKey" - } - DataBindingUtils.loadImage(imageView, imageKey) - - val youEarnedMessage = this.getString(R.string.checkInRewardEarned, notificationData?.rewardText) - val youEarnedTexView = view.findViewById(R.id.you_earned_message) as? TextView - youEarnedTexView?.text = youEarnedMessage - - val nextUnlockTextView = view.findViewById(R.id.next_unlock_message) as? TextView - if (event.nextUnlockCount > 0) { - nextUnlockTextView?.text = event.nextUnlockText - } else { - nextUnlockTextView?.visibility = View.GONE - } - - lifecycleScope.launch(context = Dispatchers.Main) { - val alert = HabiticaAlertDialog(this@MainActivity) - alert.setAdditionalContentView(view) - alert.setTitle(title) - alert.addButton(R.string.see_you_tomorrow, true) { _, _ -> - apiClient.readNotification(event.notification.id) - .subscribe({ }, RxErrorHandler.handleEmptyError()) - } - alert.show() - } - } - - @Subscribe - fun showAchievementDialog(event: ShowAchievementDialog) { - retrieveUser(true) - lifecycleScope.launch(context = Dispatchers.Main) { - val dialog = AchievementDialog(this@MainActivity) - dialog.isLastOnboardingAchievement = event.isLastOnboardingAchievement - dialog.setType(event.type, event.message, event.text) - dialog.enqueue() - apiClient.readNotification(event.id) - .subscribe({ }, RxErrorHandler.handleEmptyError()) - } - } - - @Subscribe - fun showFirstDropDialog(event: ShowFirstDropDialog) { - retrieveUser(true) - lifecycleScope.launch(context = Dispatchers.Main) { - val dialog = FirstDropDialog(this@MainActivity) - dialog.configure(event.egg, event.hatchingPotion) - dialog.enqueue() - apiClient.readNotification(event.id) - .subscribe({ }, RxErrorHandler.handleEmptyError()) - } - } - - @Subscribe - fun showWonChallengeDialog(event: ShowWonChallengeDialog) { - retrieveUser(true) - lifecycleScope.launch(context = Dispatchers.Main) { - val dialog = WonChallengeDialog(this@MainActivity) - dialog.configure(event.data) - dialog.enqueue() - apiClient.readNotification(event.id) - .subscribe({ }, RxErrorHandler.handleEmptyError()) - } - } - override fun onEvent(event: ShowConnectionProblemEvent) { if (event.title != null) { super.onEvent(event) 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 b7fb3f59e..ecfab96be 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 @@ -8,7 +8,6 @@ import android.content.SharedPreferences import android.os.Build import androidx.activity.result.ActivityResultLauncher import androidx.core.content.edit -import androidx.fragment.app.Fragment import androidx.fragment.app.FragmentManager import com.facebook.AccessToken import com.facebook.CallbackManager @@ -92,6 +91,9 @@ class AuthenticationViewModel() { response.newUser = result.newUser onSuccess(response) } + else -> { + + } } }.show() } @@ -101,7 +103,7 @@ class AuthenticationViewModel() { loginManager.registerCallback( callbackManager, object : FacebookCallback { - override fun onSuccess(loginResult: LoginResult) { + override fun onSuccess(result: LoginResult) { val accessToken = AccessToken.getCurrentAccessToken() compositeSubscription.add( apiClient.connectSocial("facebook", accessToken?.userId ?: "", accessToken?.token ?: "") @@ -113,8 +115,8 @@ class AuthenticationViewModel() { override fun onCancel() { /* no-on */ } - override fun onError(exception: FacebookException) { - RxErrorHandler.reportError(exception) + override fun onError(error: FacebookException) { + RxErrorHandler.reportError(error) } } ) @@ -124,10 +126,6 @@ class AuthenticationViewModel() { loginManager.logInWithReadPermissions(activity, listOf("user_friends")) } - fun handleFacebookLogin(fragment: Fragment) { - loginManager.logInWithReadPermissions(fragment, listOf("user_friends")) - } - fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?, onSuccess: (UserAuthResponse) -> Unit) { callbackManager.onActivityResult(requestCode, resultCode, data) @@ -180,7 +178,7 @@ class AuthenticationViewModel() { Flowable.defer { try { @Suppress("Deprecation") - return@defer Flowable.just(GoogleAuthUtil.getToken(activity, googleEmail, scopes)) + return@defer Flowable.just(GoogleAuthUtil.getToken(activity, googleEmail ?: "", scopes)) } catch (e: IOException) { throw Exceptions.propagate(e) } catch (e: GoogleAuthException) { @@ -225,7 +223,7 @@ class AuthenticationViewModel() { e.connectionStatusCode, activity, null, - AuthenticationViewModel.REQUEST_CODE_RECOVER_FROM_PLAY_SERVICES_ERROR + REQUEST_CODE_RECOVER_FROM_PLAY_SERVICES_ERROR ) { } return @@ -247,8 +245,8 @@ class AuthenticationViewModel() { if (result != ConnectionResult.SUCCESS) { if (googleAPI.isUserResolvableError(result)) { googleAPI.getErrorDialog(activity, result, - AuthenticationViewModel.PLAY_SERVICES_RESOLUTION_REQUEST - ).show() + PLAY_SERVICES_RESOLUTION_REQUEST + )?.show() } return false } diff --git a/build.gradle b/build.gradle index 933ffb6b1..92d9f55ba 100644 --- a/build.gradle +++ b/build.gradle @@ -1,11 +1,10 @@ // Top-level build file where you can add configuration options common to all sub-projects/modules. buildscript { - ext.kotlin_version = '1.6.0' + ext.kotlin_version = '1.6.10' repositories { google() - jcenter() maven { url "https://plugins.gradle.org/m2/" } } dependencies { @@ -15,7 +14,7 @@ buildscript { classpath 'com.google.firebase:firebase-crashlytics-gradle:2.8.1' classpath "io.realm:realm-gradle-plugin:10.8.1" classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version" - classpath "io.gitlab.arturbosch.detekt:detekt-gradle-plugin:1.18.1" + classpath "io.gitlab.arturbosch.detekt:detekt-gradle-plugin:1.19.0" classpath "androidx.navigation:navigation-safe-args-gradle-plugin:2.3.5" classpath 'com.google.firebase:perf-plugin:1.4.0' } diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties index 6f68226a8..42c46ff72 100644 --- a/gradle/wrapper/gradle-wrapper.properties +++ b/gradle/wrapper/gradle-wrapper.properties @@ -3,4 +3,4 @@ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-7.0.2-all.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-7.3.3-all.zip diff --git a/shared/build.gradle b/shared/build.gradle index bd0129fec..8c8867ca0 100644 --- a/shared/build.gradle +++ b/shared/build.gradle @@ -3,11 +3,11 @@ apply plugin: 'kotlin-multiplatform' apply plugin: 'kotlin-kapt' android { - compileSdkVersion 31 + compileSdkVersion 32 defaultConfig { minSdkVersion 21 - targetSdkVersion 31 + targetSdkVersion 32 } buildTypes { release {