diff --git a/Habitica/build.gradle b/Habitica/build.gradle index 34fa27a2b..2dbde8c1d 100644 --- a/Habitica/build.gradle +++ b/Habitica/build.gradle @@ -35,7 +35,6 @@ dependencies { exclude module: 'okhttp' } implementation "com.squareup.retrofit2:converter-gson:$retrofit_version" - implementation "com.squareup.retrofit2:adapter-rxjava3:$retrofit_version" //Dependency Injection implementation "com.google.dagger:dagger:$daggerhilt_version" @@ -54,17 +53,11 @@ dependencies { implementation('com.jaredrummler:android-device-names:2.1.0') // IAP Handling / Verification - implementation "com.android.billingclient:billing-ktx:5.0.0" + implementation "com.android.billingclient:billing-ktx:5.1.0" 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.4' - implementation 'io.reactivex.rxjava3:rxkotlin:3.0.1' - implementation 'io.reactivex.rxjava2:rxjava:2.2.21' - implementation "com.github.akarnokd:rxjava3-bridge:3.0.2" //Analytics - implementation "com.amplitude:android-sdk:$amplitude_version" + implementation "com.amplitude:analytics-android:$amplitude_version" //Tests testImplementation 'io.kotest:kotest-runner-junit5:5.3.0' @@ -80,9 +73,9 @@ dependencies { androidTestImplementation 'androidx.test:runner:1.4.0' androidTestImplementation 'androidx.test:rules:1.4.0' debugImplementation 'androidx.fragment:fragment-testing:1.5.4' - androidTestImplementation 'androidx.test.ext:junit:1.1.3' + androidTestImplementation 'androidx.test.ext:junit:1.1.4' androidTestImplementation 'androidx.test:core-ktx:1.4.0' - androidTestImplementation 'androidx.test.ext:junit-ktx:1.1.3' + androidTestImplementation 'androidx.test.ext:junit-ktx:1.1.4' androidTestImplementation 'io.mockk:mockk-android:1.12.3' androidTestImplementation 'io.kotest:kotest-assertions-core:5.3.0' androidTestUtil("androidx.test:orchestrator:1.4.1") @@ -172,7 +165,7 @@ android { } composeOptions { - kotlinCompilerExtensionVersion = "1.3.2" + kotlinCompilerExtensionVersion = "1.4.0-alpha02" } signingConfigs { 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 276ea59d2..c2f65d854 100644 --- a/Habitica/src/main/java/com/habitrpg/android/habitica/HabiticaBaseApplication.kt +++ b/Habitica/src/main/java/com/habitrpg/android/habitica/HabiticaBaseApplication.kt @@ -18,8 +18,6 @@ import android.util.Log import androidx.appcompat.app.AppCompatDelegate import androidx.core.content.edit import androidx.preference.PreferenceManager -import com.amplitude.api.Amplitude -import com.amplitude.api.Identify import com.google.android.gms.wearable.Wearable import com.google.firebase.analytics.FirebaseAnalytics import com.google.firebase.installations.FirebaseInstallations @@ -29,6 +27,7 @@ import com.habitrpg.android.habitica.components.AppComponent import com.habitrpg.android.habitica.components.UserComponent import com.habitrpg.android.habitica.data.ApiClient import com.habitrpg.android.habitica.helpers.AdHandler +import com.habitrpg.android.habitica.helpers.AmplitudeManager import com.habitrpg.android.habitica.helpers.ExceptionHandler import com.habitrpg.android.habitica.helpers.notifications.PushNotificationManager import com.habitrpg.android.habitica.modules.UserModule @@ -76,11 +75,7 @@ abstract class HabiticaBaseApplication : Application(), Application.ActivityLife if (!BuildConfig.DEBUG) { try { - Amplitude.getInstance().initialize(this, getString(R.string.amplitude_app_id)).enableForegroundTracking(this) - val identify = Identify() - .setOnce("androidStore", BuildConfig.STORE) - .set("launch_screen", sharedPrefs.getString("launch_screen", "")) - Amplitude.getInstance().identify(identify) + AmplitudeManager.initialize(this, sharedPrefs) } catch (ignored: Resources.NotFoundException) { } } 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 3b56c2116..c56099ff0 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 @@ -1,7 +1,6 @@ package com.habitrpg.android.habitica.data.implementation import android.content.Context -import com.amplitude.api.Amplitude import com.google.gson.JsonSyntaxException import com.habitrpg.android.habitica.BuildConfig import com.habitrpg.android.habitica.HabiticaBaseApplication @@ -51,7 +50,6 @@ import com.habitrpg.shared.habitica.models.responses.FeedResponse import com.habitrpg.shared.habitica.models.responses.Status import com.habitrpg.shared.habitica.models.responses.TaskDirectionData import com.habitrpg.shared.habitica.models.responses.VerifyUsernameResponse -import io.reactivex.rxjava3.functions.Consumer import okhttp3.Cache import okhttp3.OkHttpClient import okhttp3.Request @@ -59,7 +57,6 @@ import okhttp3.logging.HttpLoggingInterceptor import retrofit2.Converter import retrofit2.HttpException import retrofit2.Retrofit -import retrofit2.adapter.rxjava3.RxJava3CallAdapterFactory import retrofit2.converter.gson.GsonConverterFactory import java.io.File import java.io.IOException @@ -76,7 +73,7 @@ class ApiClientImpl( private val analyticsManager: AnalyticsManager, private val notificationsManager: NotificationsManager, private val context: Context -) : Consumer, ApiClient { +): ApiClient { private lateinit var retrofitAdapter: Retrofit @@ -157,7 +154,6 @@ class ApiClientImpl( retrofitAdapter = Retrofit.Builder() .client(client) .baseUrl(server.toString()) - .addCallAdapterFactory(RxJava3CallAdapterFactory.create()) .addConverterFactory(converter) .build() @@ -211,7 +207,7 @@ class ApiClientImpl( return process { apiService.loginApple(mapOf(Pair("code", authToken))) } } - override fun accept(throwable: Throwable) { + fun accept(throwable: Throwable) { val throwableClass = throwable.javaClass if (SocketTimeoutException::class.java.isAssignableFrom(throwableClass)) { return @@ -221,7 +217,7 @@ class ApiClientImpl( this.showConnectionProblemDialog(R.string.internal_error_api) } else if (throwableClass == SocketTimeoutException::class.java || UnknownHostException::class.java == throwableClass || IOException::class.java == throwableClass) { this.showConnectionProblemDialog(R.string.network_error_no_network_body) - } else if (retrofit2.adapter.rxjava3.HttpException::class.java.isAssignableFrom(throwable.javaClass) || HttpException::class.java.isAssignableFrom(throwable.javaClass)) { + } else if (HttpException::class.java.isAssignableFrom(throwable.javaClass)) { val error = throwable as HttpException val res = getErrorResponse(error) val status = error.code() @@ -319,7 +315,6 @@ class ApiClientImpl( this.hostConfig.userID = userID ?: "" this.hostConfig.apiKey = apiToken ?: "" analyticsManager.setUserIdentifier(this.hostConfig.userID) - Amplitude.getInstance().userId = this.hostConfig.userID } override suspend fun getStatus(): Status? = process { apiService.getStatus() } diff --git a/Habitica/src/main/java/com/habitrpg/android/habitica/data/local/ContentLocalRepository.kt b/Habitica/src/main/java/com/habitrpg/android/habitica/data/local/ContentLocalRepository.kt index 670a0dbce..d8a664dea 100644 --- a/Habitica/src/main/java/com/habitrpg/android/habitica/data/local/ContentLocalRepository.kt +++ b/Habitica/src/main/java/com/habitrpg/android/habitica/data/local/ContentLocalRepository.kt @@ -2,7 +2,6 @@ package com.habitrpg.android.habitica.data.local import com.habitrpg.android.habitica.models.ContentResult import com.habitrpg.android.habitica.models.WorldState -import io.reactivex.rxjava3.core.Flowable import kotlinx.coroutines.flow.Flow interface ContentLocalRepository : BaseLocalRepository { diff --git a/Habitica/src/main/java/com/habitrpg/android/habitica/data/local/TagLocalRepository.kt b/Habitica/src/main/java/com/habitrpg/android/habitica/data/local/TagLocalRepository.kt index b4a2cf921..6ca4b3c14 100644 --- a/Habitica/src/main/java/com/habitrpg/android/habitica/data/local/TagLocalRepository.kt +++ b/Habitica/src/main/java/com/habitrpg/android/habitica/data/local/TagLocalRepository.kt @@ -1,7 +1,6 @@ package com.habitrpg.android.habitica.data.local import com.habitrpg.android.habitica.models.Tag -import io.reactivex.rxjava3.core.Flowable import kotlinx.coroutines.flow.Flow interface TagLocalRepository : BaseLocalRepository { diff --git a/Habitica/src/main/java/com/habitrpg/android/habitica/data/local/TaskLocalRepository.kt b/Habitica/src/main/java/com/habitrpg/android/habitica/data/local/TaskLocalRepository.kt index e8a3a0f24..710518cfc 100644 --- a/Habitica/src/main/java/com/habitrpg/android/habitica/data/local/TaskLocalRepository.kt +++ b/Habitica/src/main/java/com/habitrpg/android/habitica/data/local/TaskLocalRepository.kt @@ -5,7 +5,6 @@ import com.habitrpg.android.habitica.models.tasks.TaskList import com.habitrpg.android.habitica.models.user.User import com.habitrpg.shared.habitica.models.tasks.TaskType import com.habitrpg.shared.habitica.models.tasks.TasksOrder -import io.reactivex.rxjava3.core.Maybe import kotlinx.coroutines.flow.Flow interface TaskLocalRepository : BaseLocalRepository { @@ -26,7 +25,7 @@ interface TaskLocalRepository : BaseLocalRepository { fun getTaskAtPosition(taskType: String, position: Int): Flow - fun updateIsdue(daily: TaskList): Maybe + fun updateIsdue(daily: TaskList): TaskList fun updateTaskPositions(taskOrder: List) fun saveCompletedTodos(userId: String, tasks: MutableCollection) diff --git a/Habitica/src/main/java/com/habitrpg/android/habitica/data/local/implementation/RealmBaseLocalRepository.kt b/Habitica/src/main/java/com/habitrpg/android/habitica/data/local/implementation/RealmBaseLocalRepository.kt index a6c661e3d..8ece9e579 100644 --- a/Habitica/src/main/java/com/habitrpg/android/habitica/data/local/implementation/RealmBaseLocalRepository.kt +++ b/Habitica/src/main/java/com/habitrpg/android/habitica/data/local/implementation/RealmBaseLocalRepository.kt @@ -1,12 +1,9 @@ package com.habitrpg.android.habitica.data.local.implementation import com.habitrpg.android.habitica.data.local.BaseLocalRepository -import com.habitrpg.android.habitica.extensions.filterMap import com.habitrpg.android.habitica.models.BaseMainObject import com.habitrpg.android.habitica.models.BaseObject import com.habitrpg.android.habitica.models.user.User -import hu.akarnokd.rxjava3.bridge.RxJavaBridge -import io.reactivex.rxjava3.core.Flowable import io.realm.Realm import io.realm.RealmObject import io.realm.kotlin.deleteFromRealm @@ -115,15 +112,4 @@ abstract class RealmBaseLocalRepository internal constructor(override var realm: .filter { it.isLoaded && it.isValid && !it.isEmpty() } .map { it.firstOrNull() } } - - fun queryUserFlowable(userID: String): Flowable { - return RxJavaBridge.toV3Flowable( - realm.where(User::class.java) - .equalTo("id", userID) - .findAll() - .asFlowable() - ) - .filter { it.isLoaded && it.isValid && !it.isEmpty() } - .filterMap { it.first() } - } } diff --git a/Habitica/src/main/java/com/habitrpg/android/habitica/data/local/implementation/RealmTaskLocalRepository.kt b/Habitica/src/main/java/com/habitrpg/android/habitica/data/local/implementation/RealmTaskLocalRepository.kt index 51ff44e96..239cfee26 100644 --- a/Habitica/src/main/java/com/habitrpg/android/habitica/data/local/implementation/RealmTaskLocalRepository.kt +++ b/Habitica/src/main/java/com/habitrpg/android/habitica/data/local/implementation/RealmTaskLocalRepository.kt @@ -8,8 +8,6 @@ import com.habitrpg.android.habitica.models.tasks.TaskList import com.habitrpg.android.habitica.models.user.User import com.habitrpg.shared.habitica.models.tasks.TaskType import com.habitrpg.shared.habitica.models.tasks.TasksOrder -import io.reactivex.rxjava3.core.Flowable -import io.reactivex.rxjava3.core.Maybe import io.realm.Realm import io.realm.RealmResults import io.realm.Sort @@ -227,15 +225,12 @@ class RealmTaskLocalRepository(realm: Realm) : RealmBaseLocalRepository(realm), .filterNotNull() } - override fun updateIsdue(daily: TaskList): Maybe { - return Flowable.just(realm.where(Task::class.java).equalTo("typeValue", TaskType.DAILY.value).findAll()) - .firstElement() - .map { tasks -> - realm.beginTransaction() - tasks.filter { daily.tasks.containsKey(it.id) }.forEach { it.isDue = daily.tasks[it.id]?.isDue } - realm.commitTransaction() - daily - } + override fun updateIsdue(daily: TaskList): TaskList { + val tasks = realm.where(Task::class.java).equalTo("typeValue", TaskType.DAILY.value).findAll() + realm.beginTransaction() + tasks.filter { daily.tasks.containsKey(it.id) }.forEach { it.isDue = daily.tasks[it.id]?.isDue } + realm.commitTransaction() + return daily } override fun updateTaskPositions(taskOrder: List) { diff --git a/Habitica/src/main/java/com/habitrpg/android/habitica/data/local/implementation/RealmUserLocalRepository.kt b/Habitica/src/main/java/com/habitrpg/android/habitica/data/local/implementation/RealmUserLocalRepository.kt index f835f4017..a6485a566 100644 --- a/Habitica/src/main/java/com/habitrpg/android/habitica/data/local/implementation/RealmUserLocalRepository.kt +++ b/Habitica/src/main/java/com/habitrpg/android/habitica/data/local/implementation/RealmUserLocalRepository.kt @@ -1,7 +1,6 @@ package com.habitrpg.android.habitica.data.local.implementation import com.habitrpg.android.habitica.data.local.UserLocalRepository -import com.habitrpg.android.habitica.extensions.filterMap import com.habitrpg.android.habitica.models.Achievement import com.habitrpg.android.habitica.models.QuestAchievement import com.habitrpg.android.habitica.models.Skill @@ -12,12 +11,10 @@ import com.habitrpg.android.habitica.models.social.ChatMessage import com.habitrpg.android.habitica.models.social.Group import com.habitrpg.android.habitica.models.user.User import com.habitrpg.android.habitica.models.user.UserQuestStatus -import hu.akarnokd.rxjava3.bridge.RxJavaBridge import io.realm.Realm import io.realm.kotlin.toFlow import kotlinx.coroutines.ExperimentalCoroutinesApi import kotlinx.coroutines.flow.Flow -import kotlinx.coroutines.flow.distinctUntilChanged import kotlinx.coroutines.flow.emptyFlow import kotlinx.coroutines.flow.filter import kotlinx.coroutines.flow.filterNotNull diff --git a/Habitica/src/main/java/com/habitrpg/android/habitica/executors/PostExecutionThread.java b/Habitica/src/main/java/com/habitrpg/android/habitica/executors/PostExecutionThread.java deleted file mode 100644 index a8b6b9ba5..000000000 --- a/Habitica/src/main/java/com/habitrpg/android/habitica/executors/PostExecutionThread.java +++ /dev/null @@ -1,8 +0,0 @@ -package com.habitrpg.android.habitica.executors; - - -import io.reactivex.rxjava3.core.Scheduler; - -public interface PostExecutionThread { - Scheduler getScheduler(); -} diff --git a/Habitica/src/main/java/com/habitrpg/android/habitica/executors/UIThread.java b/Habitica/src/main/java/com/habitrpg/android/habitica/executors/UIThread.java deleted file mode 100644 index 9617314a2..000000000 --- a/Habitica/src/main/java/com/habitrpg/android/habitica/executors/UIThread.java +++ /dev/null @@ -1,19 +0,0 @@ -package com.habitrpg.android.habitica.executors; - -import javax.inject.Inject; -import javax.inject.Singleton; - -import io.reactivex.rxjava3.android.schedulers.AndroidSchedulers; -import io.reactivex.rxjava3.core.Scheduler; - -@Singleton -public class UIThread implements PostExecutionThread { - - @Inject - public UIThread() {} - - @Override - public Scheduler getScheduler() { - return AndroidSchedulers.mainThread(); - } -} diff --git a/Habitica/src/main/java/com/habitrpg/android/habitica/extensions/Base-Extensions.kt b/Habitica/src/main/java/com/habitrpg/android/habitica/extensions/Base-Extensions.kt index afab812d6..d2514ac9c 100644 --- a/Habitica/src/main/java/com/habitrpg/android/habitica/extensions/Base-Extensions.kt +++ b/Habitica/src/main/java/com/habitrpg/android/habitica/extensions/Base-Extensions.kt @@ -1,13 +1,18 @@ package com.habitrpg.android.habitica.extensions -import io.reactivex.rxjava3.core.Completable -import java.util.concurrent.TimeUnit +import com.habitrpg.android.habitica.helpers.launchCatching +import kotlinx.coroutines.MainScope +import kotlinx.coroutines.delay +import kotlin.time.DurationUnit +import kotlin.time.toDuration /** * Created by phillip on 01.02.18. */ -fun runDelayed(interval: Long, timeUnit: TimeUnit, function: () -> Unit) { - Completable.complete().delay(interval, timeUnit) - .subscribe(function) +fun runDelayed(interval: Long, timeUnit: DurationUnit, function: () -> Unit) { + MainScope().launchCatching { + delay(interval.toDuration(timeUnit)) + function() + } } diff --git a/Habitica/src/main/java/com/habitrpg/android/habitica/extensions/Flowable-Extensions.kt b/Habitica/src/main/java/com/habitrpg/android/habitica/extensions/Flowable-Extensions.kt deleted file mode 100644 index c27f2de98..000000000 --- a/Habitica/src/main/java/com/habitrpg/android/habitica/extensions/Flowable-Extensions.kt +++ /dev/null @@ -1,10 +0,0 @@ -package com.habitrpg.android.habitica.extensions - -import com.habitrpg.android.habitica.helpers.ExceptionHandler -import io.reactivex.rxjava3.core.Flowable -import io.reactivex.rxjava3.disposables.Disposable -import io.reactivex.rxjava3.functions.Consumer - -fun Flowable.subscribeWithErrorHandler(function: Consumer): Disposable { - return subscribe(function, ExceptionHandler.rx()) -} diff --git a/Habitica/src/main/java/com/habitrpg/android/habitica/extensions/RxJava-Extensions.kt b/Habitica/src/main/java/com/habitrpg/android/habitica/extensions/RxJava-Extensions.kt deleted file mode 100644 index 52ef4419f..000000000 --- a/Habitica/src/main/java/com/habitrpg/android/habitica/extensions/RxJava-Extensions.kt +++ /dev/null @@ -1,63 +0,0 @@ -package com.habitrpg.android.habitica.extensions - -import com.habitrpg.common.habitica.extensions.Optional -import io.reactivex.rxjava3.core.Flowable -import io.reactivex.rxjava3.core.Maybe -import io.reactivex.rxjava3.core.Observable -import io.reactivex.rxjava3.core.Single - -fun > Flowable.filterOptionalDoOnEmpty(function: () -> Unit): Flowable { - return this.doOnNext { if (it.isEmpty) function() } - .filter { !it.isEmpty } - .map { it.assertedValue } -} - -fun > Flowable.filterMapEmpty(): Flowable { - return this.filter { !it.isEmpty } - .map { it.assertedValue } -} - -fun Flowable.filterMap(function: (T) -> S?): Flowable { - return this.map { Optional(function(it)) } - .filter { !it.isEmpty } - .map { it.assertedValue } -} - -fun > Observable.filterOptionalDoOnEmpty(function: () -> Unit): Observable { - return this.doOnNext { if (it.isEmpty) function() } - .filter { !it.isEmpty } - .map { it.assertedValue } -} - -fun > Observable.filterMapEmpty(): Observable { - return this.filter { !it.isEmpty } - .map { it.assertedValue } -} - -fun Observable.filterMap(function: (T) -> S?): Observable { - return this.map { Optional(function(it)) } - .filter { !it.isEmpty } - .map { it.assertedValue } -} - -fun > Single.filterOptionalDoOnEmpty(function: () -> Unit): Maybe { - return this.doOnSuccess { if (it.isEmpty) function() } - .filter { !it.isEmpty } - .map { it.assertedValue } -} - -fun > Single.filterMapEmpty(): Maybe { - return this.filter { !it.isEmpty } - .map { it.assertedValue } -} - -fun > Maybe.filterOptionalDoOnEmpty(function: () -> Unit): Maybe { - return this.doOnSuccess { if (it.isEmpty) function() } - .filter { !it.isEmpty } - .map { it.assertedValue } -} - -fun > Maybe.filterMapEmpty(): Maybe { - return this.filter { !it.isEmpty } - .map { it.assertedValue } -} diff --git a/Habitica/src/main/java/com/habitrpg/android/habitica/helpers/AmplitudeManager.kt b/Habitica/src/main/java/com/habitrpg/android/habitica/helpers/AmplitudeManager.kt index bcbe7b826..c8e33ed26 100644 --- a/Habitica/src/main/java/com/habitrpg/android/habitica/helpers/AmplitudeManager.kt +++ b/Habitica/src/main/java/com/habitrpg/android/habitica/helpers/AmplitudeManager.kt @@ -1,9 +1,12 @@ package com.habitrpg.android.habitica.helpers -import com.amplitude.api.Amplitude +import android.content.Context +import android.content.SharedPreferences +import com.amplitude.android.Amplitude +import com.amplitude.android.Configuration +import com.amplitude.android.events.Identify import com.habitrpg.android.habitica.BuildConfig -import org.json.JSONException -import org.json.JSONObject +import com.habitrpg.android.habitica.R object AmplitudeManager { var EVENT_CATEGORY_BEHAVIOUR = "behaviour" @@ -14,6 +17,8 @@ object AmplitudeManager { var EVENT_HITTYPE_REMOVE_WIDGET = "remove" var EVENT_HITTYPE_UPDATE_WIDGET = "update" + lateinit var amplitude: Amplitude + @JvmOverloads fun sendEvent( eventAction: String?, @@ -24,20 +29,20 @@ object AmplitudeManager { if (BuildConfig.DEBUG) { return } - val eventProperties = JSONObject() - try { - eventProperties.put("eventAction", eventAction) - eventProperties.put("eventCategory", eventCategory) - eventProperties.put("hitType", hitType) - eventProperties.put("status", "displayed") - if (additionalData != null) { - for ((key, value) in additionalData) { - eventProperties.put(key, value) - } + val data = mutableMapOf( + "eventAction" to eventAction, + "eventCategory" to eventCategory, + "hitType" to hitType, + "status" to "displayed" + ) + if (additionalData != null) { + for ((key, value) in additionalData) { + data.put(key, value) } - } catch (exception: JSONException) { } - Amplitude.getInstance().logEvent(eventAction, eventProperties) + if (eventAction != null) { + amplitude.track(eventAction, data) + } } fun sendNavigationEvent(page: String) { @@ -45,4 +50,20 @@ object AmplitudeManager { additionalData["page"] = page sendEvent("navigated", EVENT_CATEGORY_NAVIGATION, EVENT_HITTYPE_PAGEVIEW, additionalData) } + + fun initialize(context: Context, sharedPrefs: SharedPreferences) { + amplitude = Amplitude( + Configuration( + context.getString(R.string.amplitude_app_id), + context + ) + ) + + val identify = Identify() + .setOnce("androidStore", BuildConfig.STORE) + sharedPrefs.getString("launch_screen", "")?.let { + identify.set("launch_screen", it) + } + amplitude.identify(identify) + } } diff --git a/Habitica/src/main/java/com/habitrpg/android/habitica/helpers/ExceptionHandler.kt b/Habitica/src/main/java/com/habitrpg/android/habitica/helpers/ExceptionHandler.kt index 2e52bb4ec..ea1bce780 100644 --- a/Habitica/src/main/java/com/habitrpg/android/habitica/helpers/ExceptionHandler.kt +++ b/Habitica/src/main/java/com/habitrpg/android/habitica/helpers/ExceptionHandler.kt @@ -3,7 +3,6 @@ package com.habitrpg.android.habitica.helpers import android.util.Log import com.habitrpg.android.habitica.BuildConfig import com.habitrpg.android.habitica.proxy.AnalyticsManager -import io.reactivex.rxjava3.functions.Consumer import kotlinx.coroutines.CoroutineExceptionHandler import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.launch @@ -30,11 +29,6 @@ class ExceptionHandler { } } - fun rx(): Consumer { - // Can't be turned into a lambda, because it then doesn't work for some reason. - return Consumer { reportError(it) } - } - fun reportError(throwable: Throwable) { if (BuildConfig.DEBUG) { try { @@ -46,7 +40,6 @@ class ExceptionHandler { !HttpException::class.java.isAssignableFrom(throwable.javaClass) && !retrofit2.HttpException::class.java.isAssignableFrom(throwable.javaClass) && !EOFException::class.java.isAssignableFrom(throwable.javaClass) && - !retrofit2.adapter.rxjava3.HttpException::class.java.isAssignableFrom(throwable.javaClass) && throwable !is ConnectionShutdownException ) { instance.analyticsManager?.logException(throwable) diff --git a/Habitica/src/main/java/com/habitrpg/android/habitica/helpers/SoundFileLoader.kt b/Habitica/src/main/java/com/habitrpg/android/habitica/helpers/SoundFileLoader.kt index 98033f7d1..0e61f48af 100644 --- a/Habitica/src/main/java/com/habitrpg/android/habitica/helpers/SoundFileLoader.kt +++ b/Habitica/src/main/java/com/habitrpg/android/habitica/helpers/SoundFileLoader.kt @@ -4,16 +4,15 @@ import android.annotation.SuppressLint import android.content.Context import android.os.Environment import com.habitrpg.android.habitica.HabiticaBaseApplication -import io.reactivex.rxjava3.core.Observable -import io.reactivex.rxjava3.core.Single -import io.reactivex.rxjava3.schedulers.Schedulers -import java.io.File -import java.io.IOException +import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.withContext import okhttp3.OkHttpClient import okhttp3.Request import okhttp3.Response import okio.buffer import okio.sink +import java.io.File +import java.io.IOException // based on http://stackoverflow.com/questions/29838565/downloading-files-using-okhttp-okio-and-rxjava class SoundFileLoader(private val context: Context) { @@ -26,52 +25,42 @@ class SoundFileLoader(private val context: Context) { } @SuppressLint("SetWorldReadable", "ReturnCount") - fun download(files: List): Single> { - return Observable.fromIterable(files) - .flatMap( - { audioFile -> + suspend fun download(files: List): List { + return files.map { audioFile -> + withContext(Dispatchers.IO) { val file = File(getFullAudioFilePath(audioFile)) if (file.exists() && file.length() > 5000) { // Important, or else the MediaPlayer can't access this file file.setReadable(true, false) audioFile.file = file - return@flatMap Observable.just(audioFile) + return@withContext audioFile + } + val request = Request.Builder().url(audioFile.webUrl).build() + + val response: Response + try { + response = client.newCall(request).execute() + if (!response.isSuccessful) { + throw IOException() + } + } catch (io: IOException) { + return@withContext audioFile } - val fileObservable = Observable.create { sub -> - val request = Request.Builder().url(audioFile.webUrl).build() - - val response: Response - try { - response = client.newCall(request).execute() - if (!response.isSuccessful) { - throw IOException() - } - } catch (io: IOException) { - sub.onComplete() - return@create - } - - try { - val sink = file.sink().buffer() - sink.writeAll(response.body!!.source()) - sink.flush() - sink.close() - } catch (io: IOException) { - sub.onComplete() - return@create - } - - file.setReadable(true, false) - audioFile.file = file - sub.onNext(audioFile) - sub.onComplete() + try { + val sink = file.sink().buffer() + sink.writeAll(response.body!!.source()) + sink.flush() + sink.close() + } catch (io: IOException) { + return@withContext audioFile } - fileObservable.subscribeOn(Schedulers.io()) - }, - 5 - ) - .toList() + + file.setReadable(true, false) + audioFile.file = file + return@withContext audioFile + } + } } private fun getFullAudioFilePath(soundFile: SoundFile): String = diff --git a/Habitica/src/main/java/com/habitrpg/android/habitica/helpers/SoundManager.kt b/Habitica/src/main/java/com/habitrpg/android/habitica/helpers/SoundManager.kt index 178e461e4..4eba474b2 100644 --- a/Habitica/src/main/java/com/habitrpg/android/habitica/helpers/SoundManager.kt +++ b/Habitica/src/main/java/com/habitrpg/android/habitica/helpers/SoundManager.kt @@ -1,7 +1,7 @@ package com.habitrpg.android.habitica.helpers import com.habitrpg.android.habitica.HabiticaBaseApplication -import io.reactivex.rxjava3.schedulers.Schedulers +import kotlinx.coroutines.MainScope import javax.inject.Inject class SoundManager { @@ -33,8 +33,9 @@ class SoundManager { soundFiles.add(SoundFile(soundTheme, SoundPlusHabit)) soundFiles.add(SoundFile(soundTheme, SoundReward)) soundFiles.add(SoundFile(soundTheme, SoundTodo)) - soundFileLoader.download(soundFiles) - .subscribe({}, ExceptionHandler.rx()) + MainScope().launchCatching { + soundFileLoader.download(soundFiles) + } } fun loadAndPlayAudio(type: String) { @@ -48,14 +49,12 @@ class SoundManager { val soundFiles = ArrayList() soundFiles.add(SoundFile(soundTheme, type)) - soundFileLoader.download(soundFiles).observeOn(Schedulers.newThread()).subscribe( - { - val file = soundFiles[0] - loadedSoundFiles[type] = file - file.play() - }, - ExceptionHandler.rx() - ) + MainScope().launchCatching { + val newFiles = soundFileLoader.download(soundFiles) + val file = newFiles[0] + loadedSoundFiles[type] = file + file.play() + } } } diff --git a/Habitica/src/main/java/com/habitrpg/android/habitica/interactors/CheckClassSelectionUseCase.kt b/Habitica/src/main/java/com/habitrpg/android/habitica/interactors/CheckClassSelectionUseCase.kt index ecbace013..1c2cf3fb7 100644 --- a/Habitica/src/main/java/com/habitrpg/android/habitica/interactors/CheckClassSelectionUseCase.kt +++ b/Habitica/src/main/java/com/habitrpg/android/habitica/interactors/CheckClassSelectionUseCase.kt @@ -3,12 +3,11 @@ package com.habitrpg.android.habitica.interactors import android.app.Activity import android.content.Intent import android.os.Bundle -import com.habitrpg.android.habitica.executors.PostExecutionThread import com.habitrpg.android.habitica.models.user.User import com.habitrpg.android.habitica.ui.activities.ClassSelectionActivity import javax.inject.Inject -class CheckClassSelectionUseCase @Inject constructor(postExecutionThread: PostExecutionThread) : FlowUseCase() { +class CheckClassSelectionUseCase @Inject constructor() : FlowUseCase() { override suspend fun run(requestValues: RequestValues) { val user = requestValues.user diff --git a/Habitica/src/main/java/com/habitrpg/android/habitica/interactors/UseCase.kt b/Habitica/src/main/java/com/habitrpg/android/habitica/interactors/UseCase.kt index 45e028064..82222ccf0 100644 --- a/Habitica/src/main/java/com/habitrpg/android/habitica/interactors/UseCase.kt +++ b/Habitica/src/main/java/com/habitrpg/android/habitica/interactors/UseCase.kt @@ -1,21 +1,8 @@ package com.habitrpg.android.habitica.interactors -import com.habitrpg.android.habitica.executors.PostExecutionThread -import io.reactivex.rxjava3.core.Flowable import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.withContext -abstract class UseCase protected constructor(private val postExecutionThread: PostExecutionThread) { - protected abstract fun buildUseCaseObservable(requestValues: Q): Flowable - fun observable(requestValues: Q): Flowable { - return buildUseCaseObservable(requestValues) - .subscribeOn(postExecutionThread.scheduler) - .observeOn(postExecutionThread.scheduler) - } - - interface RequestValues -} - abstract class FlowUseCase { protected abstract suspend fun run(requestValues: Q): T suspend fun callInteractor(requestValues: Q): T { 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 66ee1e4f2..56d23b7f7 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 @@ -14,7 +14,6 @@ import com.habitrpg.common.habitica.helpers.KeyHelper import dagger.Module import dagger.Provides import retrofit2.Retrofit -import retrofit2.adapter.rxjava3.RxJava3CallAdapterFactory import retrofit2.converter.gson.GsonConverterFactory import java.lang.ref.WeakReference import javax.inject.Singleton @@ -66,7 +65,6 @@ open class ApiModule { 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/modules/AppModule.kt b/Habitica/src/main/java/com/habitrpg/android/habitica/modules/AppModule.kt index 1737dc1f0..25e29814e 100644 --- a/Habitica/src/main/java/com/habitrpg/android/habitica/modules/AppModule.kt +++ b/Habitica/src/main/java/com/habitrpg/android/habitica/modules/AppModule.kt @@ -7,8 +7,6 @@ import android.content.res.Resources import androidx.preference.PreferenceManager import com.habitrpg.android.habitica.data.ApiClient import com.habitrpg.android.habitica.data.ContentRepository -import com.habitrpg.android.habitica.executors.PostExecutionThread -import com.habitrpg.android.habitica.executors.UIThread import com.habitrpg.android.habitica.helpers.AppConfigManager import com.habitrpg.android.habitica.helpers.SoundFileLoader import com.habitrpg.android.habitica.helpers.SoundManager @@ -84,12 +82,6 @@ class AppModule(private val application: Application) { return SoundManager() } - @Provides - @Singleton - fun providePostExecutionThread(uiThread: UIThread): PostExecutionThread { - return uiThread - } - @Provides @Singleton fun pushNotificationManager( diff --git a/Habitica/src/main/java/com/habitrpg/android/habitica/ui/activities/GroupInviteActivity.kt b/Habitica/src/main/java/com/habitrpg/android/habitica/ui/activities/GroupInviteActivity.kt index 8ad8fbf1e..aca79ac48 100644 --- a/Habitica/src/main/java/com/habitrpg/android/habitica/ui/activities/GroupInviteActivity.kt +++ b/Habitica/src/main/java/com/habitrpg/android/habitica/ui/activities/GroupInviteActivity.kt @@ -19,9 +19,9 @@ import com.habitrpg.android.habitica.ui.fragments.social.party.PartyInviteFragme import com.habitrpg.android.habitica.ui.helpers.dismissKeyboard import com.habitrpg.android.habitica.ui.views.HabiticaSnackbar import com.habitrpg.android.habitica.ui.views.HabiticaSnackbar.Companion.showSnackbar -import java.util.concurrent.TimeUnit import javax.inject.Inject import javax.inject.Named +import kotlin.time.DurationUnit class GroupInviteActivity : BaseActivity() { @@ -70,7 +70,7 @@ class GroupInviteActivity : BaseActivity() { dismissKeyboard() if (fragments.size > binding.viewPager.currentItem && fragments[binding.viewPager.currentItem].values.isNotEmpty()) { showSnackbar(binding.snackbarView, "Invite Sent!", HabiticaSnackbar.SnackbarDisplayType.SUCCESS) - runDelayed(1, TimeUnit.SECONDS, this::finish) + runDelayed(1, DurationUnit.SECONDS, this::finish) } else { finish() } diff --git a/Habitica/src/main/java/com/habitrpg/android/habitica/ui/activities/SetupActivity.kt b/Habitica/src/main/java/com/habitrpg/android/habitica/ui/activities/SetupActivity.kt index 54e51ff75..09f88528b 100644 --- a/Habitica/src/main/java/com/habitrpg/android/habitica/ui/activities/SetupActivity.kt +++ b/Habitica/src/main/java/com/habitrpg/android/habitica/ui/activities/SetupActivity.kt @@ -32,7 +32,6 @@ import com.habitrpg.android.habitica.ui.fragments.setup.TaskSetupFragment import com.habitrpg.android.habitica.ui.fragments.setup.WelcomeFragment import com.habitrpg.common.habitica.api.HostConfig import com.viewpagerindicator.IconPagerAdapter -import io.reactivex.rxjava3.core.BackpressureStrategy import kotlinx.coroutines.launch import java.util.Calendar import java.util.Locale @@ -260,9 +259,7 @@ class SetupActivity : BaseActivity(), ViewPager.OnPageChangeListener { else -> { val fragment = WelcomeFragment() welcomeFragment = fragment - welcomeFragment?.nameValidEvents?.toFlowable(BackpressureStrategy.DROP)?.subscribe { - setNextButtonEnabled(it) - } + welcomeFragment?.onNameValid = { setNextButtonEnabled(it == true) } fragment } } @@ -283,9 +280,7 @@ class SetupActivity : BaseActivity(), ViewPager.OnPageChangeListener { } is WelcomeFragment -> { welcomeFragment = item - item.nameValidEvents.toFlowable(BackpressureStrategy.DROP).subscribe { - setNextButtonEnabled(it) - } + item.onNameValid = { setNextButtonEnabled(it == true) } } } return item diff --git a/Habitica/src/main/java/com/habitrpg/android/habitica/ui/adapter/CustomizationEquipmentRecyclerViewAdapter.kt b/Habitica/src/main/java/com/habitrpg/android/habitica/ui/adapter/CustomizationEquipmentRecyclerViewAdapter.kt deleted file mode 100644 index a1e8f30ba..000000000 --- a/Habitica/src/main/java/com/habitrpg/android/habitica/ui/adapter/CustomizationEquipmentRecyclerViewAdapter.kt +++ /dev/null @@ -1,159 +0,0 @@ -package com.habitrpg.android.habitica.ui.adapter - -import android.view.LayoutInflater -import android.view.View -import android.view.ViewGroup -import android.widget.ImageView -import android.widget.LinearLayout -import android.widget.TextView -import androidx.core.content.ContextCompat -import androidx.core.os.bundleOf -import com.habitrpg.android.habitica.R -import com.habitrpg.android.habitica.databinding.CustomizationGridItemBinding -import com.habitrpg.android.habitica.helpers.MainNavigationController -import com.habitrpg.android.habitica.models.inventory.CustomizationSet -import com.habitrpg.android.habitica.models.inventory.Equipment -import com.habitrpg.common.habitica.extensions.loadImage -import com.habitrpg.android.habitica.ui.views.HabiticaIconsHelper -import com.habitrpg.common.habitica.views.PixelArtView -import com.habitrpg.android.habitica.ui.views.dialogs.HabiticaAlertDialog -import io.reactivex.rxjava3.core.BackpressureStrategy -import io.reactivex.rxjava3.core.Flowable -import io.reactivex.rxjava3.subjects.PublishSubject - -class CustomizationEquipmentRecyclerViewAdapter : androidx.recyclerview.widget.RecyclerView.Adapter() { - - var gemBalance: Int = 0 - var equipmentList: MutableList = - ArrayList() - set(value) { - field = value - notifyDataSetChanged() - } - var activeEquipment: String? = null - set(value) { - field = value - this.notifyDataSetChanged() - } - - private val selectCustomizationEvents = PublishSubject.create() - private val unlockCustomizationEvents = PublishSubject.create() - - override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): androidx.recyclerview.widget.RecyclerView.ViewHolder { - val viewID: Int = R.layout.customization_grid_item - - val view = LayoutInflater.from(parent.context).inflate(viewID, parent, false) - return EquipmentViewHolder(view) - } - - override fun onBindViewHolder( - holder: androidx.recyclerview.widget.RecyclerView.ViewHolder, - position: Int - ) { - (holder as EquipmentViewHolder).bind(equipmentList[position]) - } - - override fun getItemCount(): Int { - return equipmentList.size - } - - override fun getItemViewType(position: Int): Int { - if (equipmentList.size <= position) return 0 - return if (this.equipmentList[position].javaClass == CustomizationSet::class.java) { - 0 - } else { - 1 - } - } - - fun setEquipment(newEquipmentList: List) { - this.equipmentList = newEquipmentList.toMutableList() - val emptyEquipment = Equipment() - equipmentList.add(0, emptyEquipment) - this.notifyDataSetChanged() - } - - fun getSelectCustomizationEvents(): Flowable { - return selectCustomizationEvents.toFlowable(BackpressureStrategy.DROP) - } - - fun getUnlockCustomizationEvents(): Flowable { - return unlockCustomizationEvents.toFlowable(BackpressureStrategy.DROP) - } - - internal inner class EquipmentViewHolder(itemView: View) : androidx.recyclerview.widget.RecyclerView.ViewHolder(itemView), View.OnClickListener { - - private val binding = CustomizationGridItemBinding.bind(itemView) - var equipment: Equipment? = null - - init { - itemView.setOnClickListener(this) - } - - fun bind(equipment: Equipment) { - this.equipment = equipment - binding.imageView.loadImage("shop_" + this.equipment?.key) - if (equipment.owned == true || equipment.value == 0.0) { - binding.buyButton.visibility = View.GONE - } else { - binding.buyButton.visibility = View.VISIBLE - binding.priceLabel.currency = "gems" - binding.priceLabel.value = if (equipment.gearSet == "animal") { - 2.0 - } else { - equipment.value - } - } - - if (activeEquipment == equipment.key || (activeEquipment?.contains("base_0") == true && equipment.key?.isNotBlank() != true)) { - binding.wrapper.background = ContextCompat.getDrawable(itemView.context, R.drawable.layout_rounded_bg_window_tint_border) - } else { - binding.wrapper.background = ContextCompat.getDrawable(itemView.context, R.drawable.layout_rounded_bg_window) - } - } - - override fun onClick(v: View) { - if (equipment?.owned != true && (equipment?.value ?: 0.0) > 0.0) { - val dialogContent = LayoutInflater.from(itemView.context).inflate(R.layout.dialog_purchase_customization, null) as LinearLayout - - val imageView = dialogContent.findViewById(R.id.imageView) - imageView.loadImage("shop_" + this.equipment?.key) - - val priceLabel = dialogContent.findViewById(R.id.priceLabel) - priceLabel.text = if (equipment?.gearSet == "animal") { - 2.0 - } else { - equipment?.value ?: 0 - }.toString() - - (dialogContent.findViewById(R.id.gem_icon) as? ImageView)?.setImageBitmap( - HabiticaIconsHelper.imageOfGem()) - - val dialog = HabiticaAlertDialog(itemView.context) - dialog.addButton(R.string.purchase_button, true) { _, _ -> - if (equipment?.value ?: 0.0 > gemBalance) { - MainNavigationController.navigate(R.id.gemPurchaseActivity, bundleOf(Pair("openSubscription", false))) - return@addButton - } - - equipment?.let { - unlockCustomizationEvents.onNext(it) - } - } - dialog.setTitle(R.string.purchase_customization) - dialog.setAdditionalContentView(dialogContent) - dialog.addButton(R.string.reward_dialog_dismiss, false) - dialog.show() - return - } - - if (equipment?.key == activeEquipment) { - return - } - - equipment?.let { - selectCustomizationEvents.onNext(it) - } - } - } -} diff --git a/Habitica/src/main/java/com/habitrpg/android/habitica/ui/adapter/NavigationDrawerAdapter.kt b/Habitica/src/main/java/com/habitrpg/android/habitica/ui/adapter/NavigationDrawerAdapter.kt index 23e19efff..870e5985c 100644 --- a/Habitica/src/main/java/com/habitrpg/android/habitica/ui/adapter/NavigationDrawerAdapter.kt +++ b/Habitica/src/main/java/com/habitrpg/android/habitica/ui/adapter/NavigationDrawerAdapter.kt @@ -14,9 +14,6 @@ import com.habitrpg.android.habitica.ui.views.promo.PromoMenuViewHolder import com.habitrpg.android.habitica.ui.views.promo.SubscriptionBuyGemsPromoView import com.habitrpg.android.habitica.ui.views.promo.SubscriptionBuyGemsPromoViewHolder import com.habitrpg.common.habitica.extensions.dpToPx -import io.reactivex.rxjava3.core.BackpressureStrategy -import io.reactivex.rxjava3.core.Flowable -import io.reactivex.rxjava3.subjects.PublishSubject class NavigationDrawerAdapter(tintColor: Int, backgroundTintColor: Int) : RecyclerView.Adapter() { @@ -46,14 +43,11 @@ class NavigationDrawerAdapter(tintColor: Int, backgroundTintColor: Int) : Recycl notifyDataSetChanged() } - private val itemSelectedEvents = PublishSubject.create() - private val promoClosedSubject = PublishSubject.create() + var itemSelectedEvents: ((HabiticaDrawerItem) -> Unit)? = null + var promoClosedSubject: ((String) -> Unit)? = null var activePromo: HabiticaPromotion? = null - fun getItemSelectionEvents(): Flowable = itemSelectedEvents.toFlowable(BackpressureStrategy.DROP) - fun getPromoCloseEvents(): Flowable = promoClosedSubject.toFlowable(BackpressureStrategy.DROP) - fun getItemWithIdentifier(identifier: String): HabiticaDrawerItem? = items.find { it.identifier == identifier } @@ -81,7 +75,7 @@ class NavigationDrawerAdapter(tintColor: Int, backgroundTintColor: Int) : Recycl val itemHolder = holder as? DrawerItemViewHolder itemHolder?.tintColor = tintColor itemHolder?.bind(drawerItem, drawerItem.transitionId == selectedItem) - itemHolder?.itemView?.setOnClickListener { itemSelectedEvents.onNext(drawerItem) } + itemHolder?.itemView?.setOnClickListener { itemSelectedEvents?.invoke(drawerItem) } } getItemViewType(position) == 1 -> { (holder as? SectionHeaderViewHolder)?.backgroundTintColor = backgroundTintColor @@ -91,7 +85,7 @@ class NavigationDrawerAdapter(tintColor: Int, backgroundTintColor: Int) : Recycl activePromo?.let { promo -> (holder as? PromoMenuViewHolder)?.bind(promo) (holder as? PromoMenuViewHolder)?.promoView?.binding?.closeButton?.setOnClickListener { - promoClosedSubject.onNext(promo.identifier) + promoClosedSubject?.invoke(promo.identifier) } } } diff --git a/Habitica/src/main/java/com/habitrpg/android/habitica/ui/adapter/SkillsRecyclerViewAdapter.kt b/Habitica/src/main/java/com/habitrpg/android/habitica/ui/adapter/SkillsRecyclerViewAdapter.kt index 043b5a1cd..26f0b6121 100644 --- a/Habitica/src/main/java/com/habitrpg/android/habitica/ui/adapter/SkillsRecyclerViewAdapter.kt +++ b/Habitica/src/main/java/com/habitrpg/android/habitica/ui/adapter/SkillsRecyclerViewAdapter.kt @@ -10,20 +10,16 @@ import androidx.recyclerview.widget.RecyclerView import com.habitrpg.android.habitica.R import com.habitrpg.android.habitica.databinding.SkillListItemBinding import com.habitrpg.android.habitica.extensions.inflate -import com.habitrpg.common.habitica.extensions.isUsingNightModeResources import com.habitrpg.android.habitica.models.Skill import com.habitrpg.android.habitica.models.user.OwnedItem -import com.habitrpg.common.habitica.extensions.loadImage import com.habitrpg.android.habitica.ui.views.HabiticaIconsHelper -import io.reactivex.rxjava3.core.BackpressureStrategy -import io.reactivex.rxjava3.core.Flowable -import io.reactivex.rxjava3.subjects.PublishSubject +import com.habitrpg.common.habitica.extensions.isUsingNightModeResources +import com.habitrpg.common.habitica.extensions.loadImage import io.realm.RealmList class SkillsRecyclerViewAdapter : RecyclerView.Adapter() { - private val useSkillSubject = PublishSubject.create() - val useSkillEvents: Flowable = useSkillSubject.toFlowable(BackpressureStrategy.DROP) + var onUseSkill: ((Skill) -> Unit)? = null var mana: Double = 0.0 set(value) { @@ -130,7 +126,7 @@ class SkillsRecyclerViewAdapter : RecyclerView.Adapter() { var onEquip: ((String) -> Unit)? = null private var ownedMounts: Map? = null - private val equipEvents = PublishSubject.create() var currentMount: String? = null set(value) { field = value diff --git a/Habitica/src/main/java/com/habitrpg/android/habitica/ui/adapter/inventory/PetDetailRecyclerAdapter.kt b/Habitica/src/main/java/com/habitrpg/android/habitica/ui/adapter/inventory/PetDetailRecyclerAdapter.kt index f8452d3d0..9f030f4ce 100644 --- a/Habitica/src/main/java/com/habitrpg/android/habitica/ui/adapter/inventory/PetDetailRecyclerAdapter.kt +++ b/Habitica/src/main/java/com/habitrpg/android/habitica/ui/adapter/inventory/PetDetailRecyclerAdapter.kt @@ -20,7 +20,6 @@ import com.habitrpg.android.habitica.ui.viewHolders.SectionViewHolder import com.habitrpg.android.habitica.ui.views.dialogs.PetSuggestHatchDialog import com.habitrpg.common.habitica.extensions.loadImage import com.habitrpg.common.habitica.helpers.Animations -import io.reactivex.rxjava3.subjects.PublishSubject class PetDetailRecyclerAdapter : androidx.recyclerview.widget.RecyclerView.Adapter() { var onFeed: ((Pet, Food?) -> Unit)? = null @@ -34,8 +33,6 @@ class PetDetailRecyclerAdapter : androidx.recyclerview.widget.RecyclerView.Adapt field = value notifyDataSetChanged() } - private val equipEvents = PublishSubject.create() - private val feedEvents = PublishSubject.create>() private var ownsSaddles: Boolean = false private var itemList: List = ArrayList() diff --git a/Habitica/src/main/java/com/habitrpg/android/habitica/ui/adapter/inventory/ShopRecyclerAdapter.kt b/Habitica/src/main/java/com/habitrpg/android/habitica/ui/adapter/inventory/ShopRecyclerAdapter.kt index 08bdeea26..f6103f4a0 100644 --- a/Habitica/src/main/java/com/habitrpg/android/habitica/ui/adapter/inventory/ShopRecyclerAdapter.kt +++ b/Habitica/src/main/java/com/habitrpg/android/habitica/ui/adapter/inventory/ShopRecyclerAdapter.kt @@ -18,9 +18,6 @@ import com.habitrpg.android.habitica.models.user.OwnedItem import com.habitrpg.android.habitica.models.user.User import com.habitrpg.android.habitica.ui.viewHolders.SectionViewHolder import com.habitrpg.android.habitica.ui.viewHolders.ShopItemViewHolder -import io.reactivex.rxjava3.core.BackpressureStrategy -import io.reactivex.rxjava3.core.Flowable -import io.reactivex.rxjava3.subjects.BehaviorSubject class ShopRecyclerAdapter : androidx.recyclerview.widget.RecyclerView.Adapter() { @@ -28,8 +25,7 @@ class ShopRecyclerAdapter : androidx.recyclerview.widget.RecyclerView.Adapter = HashMap() - private val changeClassSubject = BehaviorSubject.create() - val changeClassEvents: Flowable = changeClassSubject.toFlowable(BackpressureStrategy.DROP) + var changeClassEvents: ((String) -> Unit)? = null var shopSpriteSuffix: String = "" set(value) { @@ -128,7 +124,7 @@ class ShopRecyclerAdapter : androidx.recyclerview.widget.RecyclerView.Adapter? = null private var challengeMemberships: List? = null - private val openChallengeFragmentEvents = PublishSubject.create() + var onOpenChallengeFragment: ((String) -> Unit)? = null override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ChallengeViewHolder { return ChallengeViewHolder(parent.inflate(R.layout.challenge_item), viewUserChallengesOnly) @@ -36,7 +34,7 @@ class ChallengesListViewAdapter( holder.itemView.setOnClickListener { if (challenge.isManaged && challenge.isValid) { challenge.id?.let { - openChallengeFragmentEvents.onNext(it) + onOpenChallengeFragment?.invoke(it) } } } @@ -76,10 +74,6 @@ class ChallengesListViewAdapter( } } - fun getOpenDetailFragmentFlowable(): Flowable { - return openChallengeFragmentEvents.toFlowable(BackpressureStrategy.DROP) - } - class ChallengeViewHolder internal constructor( itemView: View, private val viewUserChallengesOnly: Boolean diff --git a/Habitica/src/main/java/com/habitrpg/android/habitica/ui/adapter/social/ChatRecyclerViewAdapter.kt b/Habitica/src/main/java/com/habitrpg/android/habitica/ui/adapter/social/ChatRecyclerViewAdapter.kt index 52e936006..867050fdc 100644 --- a/Habitica/src/main/java/com/habitrpg/android/habitica/ui/adapter/social/ChatRecyclerViewAdapter.kt +++ b/Habitica/src/main/java/com/habitrpg/android/habitica/ui/adapter/social/ChatRecyclerViewAdapter.kt @@ -12,9 +12,6 @@ import com.habitrpg.android.habitica.models.user.User import com.habitrpg.android.habitica.ui.adapter.BaseRecyclerViewAdapter import com.habitrpg.android.habitica.ui.adapter.DiffCallback import com.habitrpg.android.habitica.ui.viewHolders.ChatRecyclerMessageViewHolder -import io.reactivex.rxjava3.core.BackpressureStrategy -import io.reactivex.rxjava3.core.Flowable -import io.reactivex.rxjava3.subjects.PublishSubject class ChatDiffCallback(oldList: List, newList: List) : DiffCallback(oldList, newList) { @@ -39,11 +36,11 @@ class ChatRecyclerViewAdapter(user: User?, private val isTavern: Boolean) : Base private var expandedMessageId: String? = null var onMessageLike: ((ChatMessage) -> Unit)? = null - private val userLabelClickEvents = PublishSubject.create() - private val deleteMessageEvents = PublishSubject.create() - private val flagMessageEvents = PublishSubject.create() - private val replyMessageEvents = PublishSubject.create() - private val copyMessageEvents = PublishSubject.create() + var onOpenProfile: ((String) -> Unit)? = null + var onDeleteMessage: ((ChatMessage) -> Unit)? = null + var onFlagMessage: ((ChatMessage) -> Unit)? = null + var onReply: ((String) -> Unit)? = null + var onCopyMessage: ((ChatMessage) -> Unit)? = null override fun getDiffCallback( oldList: List, @@ -83,12 +80,12 @@ class ChatRecyclerViewAdapter(user: User?, private val isTavern: Boolean) : Base expandedMessageId == message.id ) chatHolder.onShouldExpand = { expandMessage(message, position) } - chatHolder.onLikeMessage = { onMessageLike?.invoke(it) } - chatHolder.onOpenProfile = { userLabelClickEvents.onNext(it) } - chatHolder.onReply = { replyMessageEvents.onNext(it) } - chatHolder.onCopyMessage = { copyMessageEvents.onNext(it) } - chatHolder.onFlagMessage = { flagMessageEvents.onNext(it) } - chatHolder.onDeleteMessage = { deleteMessageEvents.onNext(it) } + chatHolder.onLikeMessage = onMessageLike + chatHolder.onOpenProfile = onOpenProfile + chatHolder.onReply = onReply + chatHolder.onCopyMessage = onCopyMessage + chatHolder.onFlagMessage = onFlagMessage + chatHolder.onDeleteMessage = onDeleteMessage } } @@ -97,26 +94,6 @@ class ChatRecyclerViewAdapter(user: User?, private val isTavern: Boolean) : Base return if (data[position].isSystemMessage) 0 else 1 } - fun getUserLabelClickFlowable(): Flowable { - return userLabelClickEvents.toFlowable(BackpressureStrategy.DROP) - } - - fun getFlagMessageClickFlowable(): Flowable { - return flagMessageEvents.toFlowable(BackpressureStrategy.DROP) - } - - fun getDeleteMessageFlowable(): Flowable { - return deleteMessageEvents.toFlowable(BackpressureStrategy.DROP) - } - - fun getReplyMessageEvents(): Flowable { - return replyMessageEvents.toFlowable(BackpressureStrategy.DROP) - } - - fun getCopyMessageFlowable(): Flowable { - return copyMessageEvents.toFlowable(BackpressureStrategy.DROP) - } - private fun expandMessage(message: ChatMessage, position: Int?) { expandedMessageId = if (expandedMessageId == message.id) { null diff --git a/Habitica/src/main/java/com/habitrpg/android/habitica/ui/adapter/social/InboxAdapter.kt b/Habitica/src/main/java/com/habitrpg/android/habitica/ui/adapter/social/InboxAdapter.kt index f9db46083..829ea2315 100644 --- a/Habitica/src/main/java/com/habitrpg/android/habitica/ui/adapter/social/InboxAdapter.kt +++ b/Habitica/src/main/java/com/habitrpg/android/habitica/ui/adapter/social/InboxAdapter.kt @@ -11,20 +11,17 @@ import com.habitrpg.android.habitica.models.user.User import com.habitrpg.android.habitica.ui.viewHolders.ChatRecyclerIntroViewHolder import com.habitrpg.android.habitica.ui.viewHolders.ChatRecyclerMessageViewHolder import com.habitrpg.android.habitica.ui.viewHolders.ChatRecyclerViewHolder -import io.reactivex.rxjava3.core.BackpressureStrategy -import io.reactivex.rxjava3.core.Flowable -import io.reactivex.rxjava3.subjects.PublishSubject class InboxAdapter(private var user: User?, private var replyToUser: Member?) : PagedListAdapter(DIFF_CALLBACK) { private val FIRST_MESSAGE = 0 private val NORMAL_MESSAGE = 1 private var expandedMessageId: String? = null - private val userLabelClickEvents = PublishSubject.create() - private val deleteMessageEvents = PublishSubject.create() - private val flagMessageEvents = PublishSubject.create() - private val replyMessageEvents = PublishSubject.create() - private val copyMessageEvents = PublishSubject.create() + var onOpenProfile: ((String) -> Unit)? = null + var onDeleteMessage: ((ChatMessage) -> Unit)? = null + var onFlagMessage: ((ChatMessage) -> Unit)? = null + var onReply: ((String) -> Unit)? = null + var onCopyMessage: ((ChatMessage) -> Unit)? = null private fun isPositionIntroMessage(position: Int): Boolean { return (position == super.getItemCount() - 1) @@ -52,7 +49,7 @@ class InboxAdapter(private var user: User?, private var replyToUser: Member?) : if (firstMessage) { val introHolder = holder as ChatRecyclerIntroViewHolder introHolder.bind(replyToUser) - introHolder.onOpenProfile = { userLabelClickEvents.onNext(it) } + introHolder.onOpenProfile = onOpenProfile } else { val message: ChatMessage = getItem(position) ?: return val messageHolder = holder as ChatRecyclerMessageViewHolder @@ -63,30 +60,14 @@ class InboxAdapter(private var user: User?, private var replyToUser: Member?) : expandedMessageId == message.id ) messageHolder.onShouldExpand = { expandMessage(message.id, position) } - messageHolder.onOpenProfile = { userLabelClickEvents.onNext(it) } - messageHolder.onReply = { replyMessageEvents.onNext(it) } - messageHolder.onCopyMessage = { copyMessageEvents.onNext(it) } - messageHolder.onFlagMessage = { flagMessageEvents.onNext(it) } - messageHolder.onDeleteMessage = { deleteMessageEvents.onNext(it) } + messageHolder.onOpenProfile = onOpenProfile + messageHolder.onReply = onReply + messageHolder.onCopyMessage = onCopyMessage + messageHolder.onFlagMessage = onFlagMessage + messageHolder.onDeleteMessage = onDeleteMessage } } - fun getUserLabelClickFlowable(): Flowable { - return userLabelClickEvents.toFlowable(BackpressureStrategy.DROP) - } - - fun getFlagMessageClickFlowable(): Flowable { - return flagMessageEvents.toFlowable(BackpressureStrategy.DROP) - } - - fun getDeleteMessageFlowable(): Flowable { - return deleteMessageEvents.toFlowable(BackpressureStrategy.DROP) - } - - fun getCopyMessageFlowable(): Flowable { - return copyMessageEvents.toFlowable(BackpressureStrategy.DROP) - } - private fun expandMessage(id: String, position: Int) { if (isPositionIntroMessage(position)) return diff --git a/Habitica/src/main/java/com/habitrpg/android/habitica/ui/adapter/tasks/DailiesRecyclerViewHolder.kt b/Habitica/src/main/java/com/habitrpg/android/habitica/ui/adapter/tasks/DailiesRecyclerViewHolder.kt index 4dde8bfa9..ed6562879 100644 --- a/Habitica/src/main/java/com/habitrpg/android/habitica/ui/adapter/tasks/DailiesRecyclerViewHolder.kt +++ b/Habitica/src/main/java/com/habitrpg/android/habitica/ui/adapter/tasks/DailiesRecyclerViewHolder.kt @@ -10,14 +10,14 @@ class DailiesRecyclerViewHolder(layoutResource: Int, viewModel: TasksViewModel) override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): RecyclerView.ViewHolder { return if (viewType == 0) { DailyViewHolder( - getContentView(parent), { task, direction -> taskScoreEventsSubject.onNext(Pair(task, direction)) }, - { task, item -> checklistItemScoreSubject.onNext(Pair(task, item)) }, + getContentView(parent), { task, direction -> taskScoreEvents?.invoke(task, direction) }, + { task, item -> checklistItemScoreEvents?.invoke(task, item) }, { task -> - taskOpenEventsSubject.onNext(task) + taskOpenEvents?.invoke(task.first, task.second) }, { task -> - brokenTaskEventsSubject.onNext(task) + brokenTaskEvents?.invoke(task) }, viewModel) } else { super.onCreateViewHolder(parent, viewType) diff --git a/Habitica/src/main/java/com/habitrpg/android/habitica/ui/adapter/tasks/HabitsRecyclerViewAdapter.kt b/Habitica/src/main/java/com/habitrpg/android/habitica/ui/adapter/tasks/HabitsRecyclerViewAdapter.kt index f61beed69..61bbde0e2 100644 --- a/Habitica/src/main/java/com/habitrpg/android/habitica/ui/adapter/tasks/HabitsRecyclerViewAdapter.kt +++ b/Habitica/src/main/java/com/habitrpg/android/habitica/ui/adapter/tasks/HabitsRecyclerViewAdapter.kt @@ -10,13 +10,13 @@ class HabitsRecyclerViewAdapter(layoutResource: Int, viewModel: TasksViewModel) override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): RecyclerView.ViewHolder { return if (viewType == 0) { HabitViewHolder( - getContentView(parent), { task, direction -> taskScoreEventsSubject.onNext(Pair(task, direction)) }, + getContentView(parent), { task, direction -> taskScoreEvents?.invoke(task, direction) }, { task -> - taskOpenEventsSubject.onNext(task) + taskOpenEvents?.invoke(task.first, task.second) }, { task -> - brokenTaskEventsSubject.onNext(task) + brokenTaskEvents?.invoke(task) }, viewModel) } else { super.onCreateViewHolder(parent, viewType) diff --git a/Habitica/src/main/java/com/habitrpg/android/habitica/ui/adapter/tasks/RealmBaseTasksRecyclerViewAdapter.kt b/Habitica/src/main/java/com/habitrpg/android/habitica/ui/adapter/tasks/RealmBaseTasksRecyclerViewAdapter.kt index 801e10a1c..eca730ce2 100644 --- a/Habitica/src/main/java/com/habitrpg/android/habitica/ui/adapter/tasks/RealmBaseTasksRecyclerViewAdapter.kt +++ b/Habitica/src/main/java/com/habitrpg/android/habitica/ui/adapter/tasks/RealmBaseTasksRecyclerViewAdapter.kt @@ -19,10 +19,6 @@ import com.habitrpg.android.habitica.ui.views.HabiticaIconsHelper import com.habitrpg.common.habitica.extensions.dpToPx import com.habitrpg.common.habitica.extensions.layoutInflater import com.habitrpg.shared.habitica.models.responses.TaskDirection -import io.reactivex.rxjava3.core.BackpressureStrategy -import io.reactivex.rxjava3.core.Flowable -import io.reactivex.rxjava3.functions.Action -import io.reactivex.rxjava3.subjects.PublishSubject import io.realm.OrderedRealmCollection abstract class RealmBaseTasksRecyclerViewAdapter( @@ -50,18 +46,12 @@ abstract class RealmBaseTasksRecyclerViewAdapter( } } - private var errorButtonEventsSubject: PublishSubject = PublishSubject.create() - override val errorButtonEvents: Flowable = errorButtonEventsSubject.toFlowable(BackpressureStrategy.DROP) - protected var taskScoreEventsSubject: PublishSubject> = PublishSubject.create() - override val taskScoreEvents: Flowable> = taskScoreEventsSubject.toFlowable(BackpressureStrategy.DROP) - protected var checklistItemScoreSubject: PublishSubject> = PublishSubject.create() - override val checklistItemScoreEvents: Flowable> = checklistItemScoreSubject.toFlowable(BackpressureStrategy.DROP) - protected var taskOpenEventsSubject: PublishSubject> = PublishSubject.create() - override val taskOpenEvents: Flowable> = taskOpenEventsSubject.toFlowable(BackpressureStrategy.DROP) - protected var brokenTaskEventsSubject: PublishSubject = PublishSubject.create() - override val brokenTaskEvents: Flowable = brokenTaskEventsSubject.toFlowable(BackpressureStrategy.DROP) - protected var adventureGuideOpenSubject: PublishSubject = PublishSubject.create() - override val adventureGuideOpenEvents: Flowable = adventureGuideOpenSubject.toFlowable(BackpressureStrategy.DROP) + override var errorButtonEvents: ((String) -> Unit)? = null + override var taskScoreEvents: ((Task, TaskDirection) -> Unit)? = null + override var checklistItemScoreEvents: ((Task, ChecklistItem) -> Unit)? = null + override var taskOpenEvents: ((Task, View) -> Unit)? = null + override var brokenTaskEvents: ((Task) -> Unit)? = null + override var adventureGuideOpenEvents: ((Boolean) -> Unit)? = null override fun getItemId(index: Int): Long = index.toLong() @@ -82,11 +72,11 @@ abstract class RealmBaseTasksRecyclerViewAdapter( holder.userID = user?.id holder.isLocked = !viewModel.canScoreTask(item) holder.bind(item, position, taskDisplayMode, viewModel.ownerID.value) - holder.errorButtonClicked = Action { - errorButtonEventsSubject.onNext("") + holder.errorButtonClicked = { + errorButtonEvents?.invoke("") } } else if (holder is AdventureGuideViewHolder) { - holder.itemView.setOnClickListener { adventureGuideOpenSubject.onNext(true) } + holder.itemView.setOnClickListener { adventureGuideOpenEvents?.invoke(true) } user?.let { holder.update(it) } } } diff --git a/Habitica/src/main/java/com/habitrpg/android/habitica/ui/adapter/tasks/RewardsRecyclerViewAdapter.kt b/Habitica/src/main/java/com/habitrpg/android/habitica/ui/adapter/tasks/RewardsRecyclerViewAdapter.kt index cdd5ee55f..3eae1407f 100644 --- a/Habitica/src/main/java/com/habitrpg/android/habitica/ui/adapter/tasks/RewardsRecyclerViewAdapter.kt +++ b/Habitica/src/main/java/com/habitrpg/android/habitica/ui/adapter/tasks/RewardsRecyclerViewAdapter.kt @@ -14,9 +14,6 @@ import com.habitrpg.android.habitica.ui.viewHolders.ShopItemViewHolder import com.habitrpg.android.habitica.ui.viewHolders.tasks.RewardViewHolder import com.habitrpg.android.habitica.ui.viewmodels.TasksViewModel import com.habitrpg.shared.habitica.models.responses.TaskDirection -import io.reactivex.rxjava3.core.BackpressureStrategy -import io.reactivex.rxjava3.core.Flowable -import io.reactivex.rxjava3.subjects.PublishSubject class RewardsRecyclerViewAdapter( private var customRewards: List?, @@ -34,19 +31,13 @@ class RewardsRecyclerViewAdapter( override var showAdventureGuide: Boolean = false private var inAppRewards: List? = null - private val errorButtonEventsSubject: PublishSubject = PublishSubject.create() - override val errorButtonEvents: Flowable = errorButtonEventsSubject.toFlowable(BackpressureStrategy.DROP) - private var taskScoreEventsSubject: PublishSubject> = PublishSubject.create() - override val taskScoreEvents: Flowable> = taskScoreEventsSubject.toFlowable(BackpressureStrategy.LATEST) - private var checklistItemScoreSubject: PublishSubject> = PublishSubject.create() - override val checklistItemScoreEvents: Flowable> = checklistItemScoreSubject.toFlowable(BackpressureStrategy.DROP) - private var taskOpenEventsSubject: PublishSubject> = PublishSubject.create() - override val taskOpenEvents: Flowable> = taskOpenEventsSubject.toFlowable(BackpressureStrategy.LATEST) - private var brokenTaskEventsSubject: PublishSubject = PublishSubject.create() - override val brokenTaskEvents: Flowable = brokenTaskEventsSubject.toFlowable(BackpressureStrategy.DROP) - override val adventureGuideOpenEvents: Flowable? = null - private var purchaseCardSubject: PublishSubject = PublishSubject.create() - val purchaseCardEvents: Flowable = purchaseCardSubject.toFlowable(BackpressureStrategy.LATEST) + override var errorButtonEvents: ((String) -> Unit)? = null + override var taskScoreEvents: ((Task, TaskDirection) -> Unit)? = null + override var checklistItemScoreEvents: ((Task, ChecklistItem) -> Unit)? = null + override var taskOpenEvents: ((Task, View) -> Unit)? = null + override var brokenTaskEvents: ((Task) -> Unit)? = null + override var adventureGuideOpenEvents: ((Boolean) -> Unit)? = null + var purchaseCardEvents: ((ShopItem) -> Unit)? = null override var taskDisplayMode: String = "standard" set(value) { @@ -78,16 +69,16 @@ class RewardsRecyclerViewAdapter( getContentView(parent), { task, direction -> if (task.value <= (user?.stats?.gp ?: 0.0)) { - taskScoreEventsSubject.onNext(Pair(task, direction)) + taskScoreEvents?.invoke(task, direction) } }, - { task -> taskOpenEventsSubject.onNext(task) }, { + { task -> taskOpenEvents?.invoke(task.first, task.second) }, { task -> - brokenTaskEventsSubject.onNext(task) + brokenTaskEvents?.invoke(task) }, viewModel) } else { val viewHolder = ShopItemViewHolder(LayoutInflater.from(parent.context).inflate(R.layout.row_shopitem, parent, false)) - viewHolder.purchaseCardAction = { purchaseCardSubject.onNext(it) } + viewHolder.purchaseCardAction = { purchaseCardEvents?.invoke(it) } viewHolder } } diff --git a/Habitica/src/main/java/com/habitrpg/android/habitica/ui/adapter/tasks/TaskRecyclerViewAdapter.kt b/Habitica/src/main/java/com/habitrpg/android/habitica/ui/adapter/tasks/TaskRecyclerViewAdapter.kt index 73e650fa3..fd240c504 100644 --- a/Habitica/src/main/java/com/habitrpg/android/habitica/ui/adapter/tasks/TaskRecyclerViewAdapter.kt +++ b/Habitica/src/main/java/com/habitrpg/android/habitica/ui/adapter/tasks/TaskRecyclerViewAdapter.kt @@ -5,14 +5,13 @@ import com.habitrpg.android.habitica.models.tasks.ChecklistItem import com.habitrpg.android.habitica.models.tasks.Task import com.habitrpg.android.habitica.models.user.User import com.habitrpg.shared.habitica.models.responses.TaskDirection -import io.reactivex.rxjava3.core.Flowable interface TaskRecyclerViewAdapter { var user: User? var showAdventureGuide: Boolean var data: List - val errorButtonEvents: Flowable + var errorButtonEvents: ((String) -> Unit)? var taskDisplayMode: String @@ -24,9 +23,9 @@ interface TaskRecyclerViewAdapter { fun updateUnfilteredData(data: List?) - val taskScoreEvents: Flowable> - val checklistItemScoreEvents: Flowable> - val taskOpenEvents: Flowable> - val brokenTaskEvents: Flowable - val adventureGuideOpenEvents: Flowable? + var taskScoreEvents: ((Task, TaskDirection) -> Unit)? + var checklistItemScoreEvents: ((Task, ChecklistItem) -> Unit)? + var taskOpenEvents: ((Task, View) -> Unit)? + var brokenTaskEvents: ((Task) -> Unit)? + var adventureGuideOpenEvents: ((Boolean) -> Unit)? } diff --git a/Habitica/src/main/java/com/habitrpg/android/habitica/ui/adapter/tasks/TodosRecyclerViewAdapter.kt b/Habitica/src/main/java/com/habitrpg/android/habitica/ui/adapter/tasks/TodosRecyclerViewAdapter.kt index 5be12d9b6..da757abc4 100644 --- a/Habitica/src/main/java/com/habitrpg/android/habitica/ui/adapter/tasks/TodosRecyclerViewAdapter.kt +++ b/Habitica/src/main/java/com/habitrpg/android/habitica/ui/adapter/tasks/TodosRecyclerViewAdapter.kt @@ -10,14 +10,14 @@ class TodosRecyclerViewAdapter(layoutResource: Int, viewModel: TasksViewModel) : override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): RecyclerView.ViewHolder { return if (viewType == 0) { TodoViewHolder( - getContentView(parent), { task, direction -> taskScoreEventsSubject.onNext(Pair(task, direction)) }, - { task, item -> checklistItemScoreSubject.onNext(Pair(task, item)) }, + getContentView(parent), { task, direction -> taskScoreEvents?.invoke(task, direction) }, + { task, item -> checklistItemScoreEvents?.invoke(task, item) }, { task -> - taskOpenEventsSubject.onNext(task) + taskOpenEvents?.invoke(task.first, task.second) }, { task -> - brokenTaskEventsSubject.onNext(task) + brokenTaskEvents?.invoke(task) }, viewModel) } else { super.onCreateViewHolder(parent, viewType) diff --git a/Habitica/src/main/java/com/habitrpg/android/habitica/ui/fragments/BaseDialogFragment.kt b/Habitica/src/main/java/com/habitrpg/android/habitica/ui/fragments/BaseDialogFragment.kt index ff6881ffe..8b895d801 100644 --- a/Habitica/src/main/java/com/habitrpg/android/habitica/ui/fragments/BaseDialogFragment.kt +++ b/Habitica/src/main/java/com/habitrpg/android/habitica/ui/fragments/BaseDialogFragment.kt @@ -13,7 +13,6 @@ import com.habitrpg.android.habitica.data.TutorialRepository import com.habitrpg.android.habitica.helpers.AmplitudeManager import com.habitrpg.android.habitica.helpers.launchCatching import com.habitrpg.android.habitica.ui.activities.MainActivity -import io.reactivex.rxjava3.disposables.CompositeDisposable import kotlinx.coroutines.delay import kotlinx.coroutines.flow.firstOrNull import javax.inject.Inject @@ -32,8 +31,6 @@ abstract class BaseDialogFragment : BottomSheetDialogFragment( protected var tutorialCanBeDeferred = true var tutorialTexts: MutableList = ArrayList() - protected var compositeSubscription: CompositeDisposable = CompositeDisposable() - open val displayedClassName: String? get() = this.javaClass.simpleName @@ -51,8 +48,6 @@ abstract class BaseDialogFragment : BottomSheetDialogFragment( container: ViewGroup?, savedInstanceState: Bundle? ): View? { - compositeSubscription = CompositeDisposable() - val additionalData = HashMap() additionalData["page"] = this.javaClass.simpleName AmplitudeManager.sendEvent("navigate", AmplitudeManager.EVENT_CATEGORY_NAVIGATION, AmplitudeManager.EVENT_HITTYPE_PAGEVIEW, additionalData) @@ -89,10 +84,6 @@ abstract class BaseDialogFragment : BottomSheetDialogFragment( override fun onDestroyView() { binding = null - if (!compositeSubscription.isDisposed) { - compositeSubscription.dispose() - } - super.onDestroyView() } 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 9a9653b41..df1c81f81 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 @@ -13,7 +13,6 @@ import com.habitrpg.android.habitica.data.TutorialRepository import com.habitrpg.android.habitica.helpers.launchCatching import com.habitrpg.android.habitica.proxy.AnalyticsManager import com.habitrpg.android.habitica.ui.activities.MainActivity -import io.reactivex.rxjava3.disposables.CompositeDisposable import kotlinx.coroutines.delay import kotlinx.coroutines.flow.firstOrNull import javax.inject.Inject @@ -34,8 +33,6 @@ abstract class BaseFragment : Fragment() { protected var tutorialCanBeDeferred = true var tutorialTexts: List = ArrayList() - protected var compositeSubscription: CompositeDisposable = CompositeDisposable() - var shouldInitializeComponent = true open val displayedClassName: String? @@ -60,8 +57,6 @@ abstract class BaseFragment : Fragment() { container: ViewGroup?, savedInstanceState: Bundle? ): View? { - compositeSubscription = CompositeDisposable() - binding = createBinding(inflater, container) return binding?.root } @@ -92,10 +87,6 @@ abstract class BaseFragment : Fragment() { override fun onDestroyView() { binding = null - if (!compositeSubscription.isDisposed) { - compositeSubscription.dispose() - } - super.onDestroyView() } diff --git a/Habitica/src/main/java/com/habitrpg/android/habitica/ui/fragments/NavigationDrawerFragment.kt b/Habitica/src/main/java/com/habitrpg/android/habitica/ui/fragments/NavigationDrawerFragment.kt index ea8444cfe..7d2141e62 100644 --- a/Habitica/src/main/java/com/habitrpg/android/habitica/ui/fragments/NavigationDrawerFragment.kt +++ b/Habitica/src/main/java/com/habitrpg/android/habitica/ui/fragments/NavigationDrawerFragment.kt @@ -30,7 +30,6 @@ import com.habitrpg.android.habitica.extensions.getMinuteOrSeconds import com.habitrpg.android.habitica.extensions.getRemainingString import com.habitrpg.android.habitica.extensions.getShortRemainingString import com.habitrpg.android.habitica.helpers.AppConfigManager -import com.habitrpg.android.habitica.helpers.ExceptionHandler import com.habitrpg.android.habitica.helpers.MainNavigationController import com.habitrpg.android.habitica.helpers.launchCatching import com.habitrpg.android.habitica.models.WorldStateEvent @@ -47,7 +46,6 @@ import com.habitrpg.android.habitica.ui.viewmodels.MainUserViewModel import com.habitrpg.android.habitica.ui.viewmodels.NotificationsViewModel import com.habitrpg.android.habitica.ui.views.HabiticaSnackbar import com.habitrpg.common.habitica.extensions.getThemeColor -import io.reactivex.rxjava3.disposables.CompositeDisposable import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.Job import kotlinx.coroutines.delay @@ -97,8 +95,6 @@ class NavigationDrawerFragment : DialogFragment() { private lateinit var adapter: NavigationDrawerAdapter - private var subscriptions: CompositeDisposable? = null - val isDrawerOpen: Boolean get() = drawerLayout?.isDrawerOpen(GravityCompat.START) ?: false @@ -114,7 +110,6 @@ class NavigationDrawerFragment : DialogFragment() { } else { NavigationDrawerAdapter(0, 0) } - subscriptions = CompositeDisposable() HabiticaBaseApplication.userComponent?.inject(this) super.onCreate(savedInstanceState) @@ -145,25 +140,15 @@ class NavigationDrawerFragment : DialogFragment() { false initializeMenuItems() - subscriptions?.add( - adapter.getItemSelectionEvents().subscribe( - { + adapter.itemSelectedEvents = { setSelection(it.transitionId, it.bundle, true) - }, - ExceptionHandler.rx() - ) - ) - subscriptions?.add( - adapter.getPromoCloseEvents().subscribe( - { + } + adapter.promoClosedSubject = { sharedPreferences.edit { putBoolean("hide$it", true) } updatePromo() - }, - ExceptionHandler.rx() - ) - ) + } lifecycleScope.launchCatching { contentRepository.getWorldState() @@ -354,7 +339,6 @@ class NavigationDrawerFragment : DialogFragment() { } override fun onDestroy() { - subscriptions?.dispose() socialRepository.close() inventoryRepository.close() userRepository.close() diff --git a/Habitica/src/main/java/com/habitrpg/android/habitica/ui/fragments/inventory/items/ItemDialogFragment.kt b/Habitica/src/main/java/com/habitrpg/android/habitica/ui/fragments/inventory/items/ItemDialogFragment.kt index d89dce1ee..fafd3ead9 100644 --- a/Habitica/src/main/java/com/habitrpg/android/habitica/ui/fragments/inventory/items/ItemDialogFragment.kt +++ b/Habitica/src/main/java/com/habitrpg/android/habitica/ui/fragments/inventory/items/ItemDialogFragment.kt @@ -36,7 +36,6 @@ import com.habitrpg.android.habitica.ui.viewmodels.MainUserViewModel import com.habitrpg.android.habitica.ui.views.dialogs.OpenedMysteryitemDialog import com.habitrpg.common.habitica.extensions.loadImage import com.habitrpg.common.habitica.helpers.EmptyItem -import io.reactivex.rxjava3.disposables.CompositeDisposable import kotlinx.coroutines.flow.firstOrNull import kotlinx.coroutines.flow.map import kotlinx.coroutines.flow.onEach @@ -45,8 +44,6 @@ import javax.inject.Inject class ItemDialogFragment : BaseDialogFragment() { - var parentSubscription: CompositeDisposable? = null - @Inject lateinit var inventoryRepository: InventoryRepository @Inject diff --git a/Habitica/src/main/java/com/habitrpg/android/habitica/ui/fragments/inventory/items/ItemRecyclerFragment.kt b/Habitica/src/main/java/com/habitrpg/android/habitica/ui/fragments/inventory/items/ItemRecyclerFragment.kt index 92dbffea9..b654c31c0 100644 --- a/Habitica/src/main/java/com/habitrpg/android/habitica/ui/fragments/inventory/items/ItemRecyclerFragment.kt +++ b/Habitica/src/main/java/com/habitrpg/android/habitica/ui/fragments/inventory/items/ItemRecyclerFragment.kt @@ -190,7 +190,6 @@ class ItemRecyclerFragment : BaseFragment(), SwipeRefreshL } fragment.isHatching = true fragment.isFeeding = false - fragment.parentSubscription = compositeSubscription parentFragmentManager.let { fragment.show(it, "hatchingDialog") } } 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 f54215d23..3003204cd 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 @@ -93,9 +93,9 @@ open class ShopFragment : BaseMainFragment() adapter?.context = context binding?.recyclerView?.adapter = adapter binding?.recyclerView?.itemAnimator = SafeDefaultItemAnimator() - adapter?.changeClassEvents?.subscribe { + adapter?.changeClassEvents = { showClassChangeDialog(it) - }?.let { compositeSubscription.add(it) } + } } if (binding?.recyclerView?.layoutManager == null) { diff --git a/Habitica/src/main/java/com/habitrpg/android/habitica/ui/fragments/inventory/stable/PetDetailRecyclerFragment.kt b/Habitica/src/main/java/com/habitrpg/android/habitica/ui/fragments/inventory/stable/PetDetailRecyclerFragment.kt index abfc35864..a085a2a91 100644 --- a/Habitica/src/main/java/com/habitrpg/android/habitica/ui/fragments/inventory/stable/PetDetailRecyclerFragment.kt +++ b/Habitica/src/main/java/com/habitrpg/android/habitica/ui/fragments/inventory/stable/PetDetailRecyclerFragment.kt @@ -11,7 +11,6 @@ import com.habitrpg.android.habitica.components.UserComponent import com.habitrpg.android.habitica.data.InventoryRepository import com.habitrpg.android.habitica.databinding.FragmentRefreshRecyclerviewBinding import com.habitrpg.android.habitica.extensions.getTranslatedType -import com.habitrpg.android.habitica.extensions.subscribeWithErrorHandler import com.habitrpg.android.habitica.helpers.ExceptionHandler import com.habitrpg.android.habitica.helpers.launchCatching import com.habitrpg.android.habitica.interactors.FeedPetUseCase @@ -243,7 +242,6 @@ class PetDetailRecyclerFragment : fragment.isHatching = false fragment.itemType = "food" fragment.itemTypeText = getString(R.string.food) - fragment.parentSubscription = compositeSubscription parentFragmentManager.let { fragment.show(it, "feedDialog") } } diff --git a/Habitica/src/main/java/com/habitrpg/android/habitica/ui/fragments/preferences/BasePreferencesFragment.kt b/Habitica/src/main/java/com/habitrpg/android/habitica/ui/fragments/preferences/BasePreferencesFragment.kt index 1a2d9c3d9..ee1baa742 100644 --- a/Habitica/src/main/java/com/habitrpg/android/habitica/ui/fragments/preferences/BasePreferencesFragment.kt +++ b/Habitica/src/main/java/com/habitrpg/android/habitica/ui/fragments/preferences/BasePreferencesFragment.kt @@ -9,7 +9,6 @@ import com.habitrpg.android.habitica.R import com.habitrpg.android.habitica.data.UserRepository import com.habitrpg.android.habitica.models.user.User import com.habitrpg.android.habitica.ui.viewmodels.MainUserViewModel -import io.reactivex.rxjava3.disposables.CompositeDisposable import javax.inject.Inject abstract class BasePreferencesFragment : PreferenceFragmentCompat() { @@ -21,8 +20,6 @@ abstract class BasePreferencesFragment : PreferenceFragmentCompat() { internal open var user: User? = null - internal val compositeSubscription = CompositeDisposable() - override fun onCreateView( inflater: LayoutInflater, container: ViewGroup?, @@ -34,7 +31,6 @@ abstract class BasePreferencesFragment : PreferenceFragmentCompat() { override fun onDestroy() { userRepository.close() - compositeSubscription.dispose() super.onDestroy() } diff --git a/Habitica/src/main/java/com/habitrpg/android/habitica/ui/fragments/setup/WelcomeFragment.kt b/Habitica/src/main/java/com/habitrpg/android/habitica/ui/fragments/setup/WelcomeFragment.kt index d4721ab31..a196ddb15 100644 --- a/Habitica/src/main/java/com/habitrpg/android/habitica/ui/fragments/setup/WelcomeFragment.kt +++ b/Habitica/src/main/java/com/habitrpg/android/habitica/ui/fragments/setup/WelcomeFragment.kt @@ -18,7 +18,6 @@ import com.habitrpg.android.habitica.helpers.ExceptionHandler import com.habitrpg.android.habitica.helpers.launchCatching import com.habitrpg.android.habitica.ui.fragments.BaseFragment import com.habitrpg.android.habitica.ui.views.HabiticaIconsHelper -import io.reactivex.rxjava3.subjects.PublishSubject import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.flow.filter import kotlinx.coroutines.flow.filterNotNull @@ -29,7 +28,7 @@ import javax.inject.Inject class WelcomeFragment : BaseFragment() { - val nameValidEvents = PublishSubject.create() + var onNameValid: ((Boolean?) -> Unit)? = null @Inject lateinit var userRepository: UserRepository @@ -132,7 +131,7 @@ class WelcomeFragment : BaseFragment() { binding?.issuesTextView?.visibility = View.VISIBLE binding?.issuesTextView?.text = it?.issues?.joinToString("\n") } - nameValidEvents.onNext(it?.isUsable) + onNameValid?.invoke(it?.isUsable) } } diff --git a/Habitica/src/main/java/com/habitrpg/android/habitica/ui/fragments/skills/SkillsFragment.kt b/Habitica/src/main/java/com/habitrpg/android/habitica/ui/fragments/skills/SkillsFragment.kt index ba043322a..1166cb6c3 100644 --- a/Habitica/src/main/java/com/habitrpg/android/habitica/ui/fragments/skills/SkillsFragment.kt +++ b/Habitica/src/main/java/com/habitrpg/android/habitica/ui/fragments/skills/SkillsFragment.kt @@ -13,7 +13,6 @@ import androidx.lifecycle.lifecycleScope import com.habitrpg.android.habitica.R import com.habitrpg.android.habitica.components.UserComponent import com.habitrpg.android.habitica.databinding.FragmentSkillsBinding -import com.habitrpg.android.habitica.extensions.subscribeWithErrorHandler import com.habitrpg.android.habitica.helpers.ExceptionHandler import com.habitrpg.android.habitica.helpers.launchCatching import com.habitrpg.android.habitica.models.Skill @@ -52,7 +51,7 @@ class SkillsFragment : BaseMainFragment() { savedInstanceState: Bundle? ): View? { adapter = SkillsRecyclerViewAdapter() - adapter?.useSkillEvents?.subscribeWithErrorHandler { onSkillSelected(it) }?.let { compositeSubscription.add(it) } + adapter?.onUseSkill = { onSkillSelected(it) } this.tutorialStepIdentifier = "skills" this.tutorialTexts = listOf(getString(R.string.tutorial_skills)) diff --git a/Habitica/src/main/java/com/habitrpg/android/habitica/ui/fragments/social/ChatFragment.kt b/Habitica/src/main/java/com/habitrpg/android/habitica/ui/fragments/social/ChatFragment.kt index 62347b671..9f783fa7d 100644 --- a/Habitica/src/main/java/com/habitrpg/android/habitica/ui/fragments/social/ChatFragment.kt +++ b/Habitica/src/main/java/com/habitrpg/android/habitica/ui/fragments/social/ChatFragment.kt @@ -7,13 +7,13 @@ import android.os.Bundle import android.view.LayoutInflater import android.view.View import android.view.ViewGroup +import androidx.lifecycle.lifecycleScope import androidx.recyclerview.widget.LinearLayoutManager import com.habitrpg.android.habitica.MainNavDirections import com.habitrpg.android.habitica.R import com.habitrpg.android.habitica.components.UserComponent import com.habitrpg.android.habitica.databinding.FragmentChatBinding import com.habitrpg.android.habitica.helpers.AppConfigManager -import com.habitrpg.android.habitica.helpers.ExceptionHandler import com.habitrpg.android.habitica.helpers.MainNavigationController import com.habitrpg.android.habitica.models.social.ChatMessage import com.habitrpg.android.habitica.ui.activities.FullProfileActivity @@ -25,11 +25,10 @@ import com.habitrpg.android.habitica.ui.viewmodels.GroupViewModel import com.habitrpg.android.habitica.ui.views.HabiticaSnackbar.Companion.showSnackbar import com.habitrpg.android.habitica.ui.views.HabiticaSnackbar.SnackbarDisplayType import com.habitrpg.android.habitica.ui.views.dialogs.HabiticaAlertDialog -import io.reactivex.rxjava3.android.schedulers.AndroidSchedulers -import io.reactivex.rxjava3.core.Observable -import io.reactivex.rxjava3.disposables.Disposable -import java.util.concurrent.TimeUnit +import kotlinx.coroutines.delay import javax.inject.Inject +import kotlin.time.DurationUnit +import kotlin.time.toDuration class ChatFragment() : BaseFragment() { @@ -52,7 +51,6 @@ class ChatFragment() : BaseFragment() { private var navigatedOnceToFragment = false private var isScrolledToBottom = true private var isFirstRefresh = true - private var refreshDisposable: Disposable? = null var autocompleteContext: String = "" override fun injectFragment(component: UserComponent) { @@ -69,16 +67,11 @@ class ChatFragment() : BaseFragment() { chatAdapter = ChatRecyclerViewAdapter(null, true) chatAdapter?.let { adapter -> - compositeSubscription.add( - adapter.getUserLabelClickFlowable().subscribe( - { userId -> FullProfileActivity.open(userId) }, - ExceptionHandler.rx() - ) - ) - compositeSubscription.add(adapter.getDeleteMessageFlowable().subscribe({ this.showDeleteConfirmationDialog(it) }, ExceptionHandler.rx())) - compositeSubscription.add(adapter.getFlagMessageClickFlowable().subscribe({ this.showFlagConfirmationDialog(it) }, ExceptionHandler.rx())) - compositeSubscription.add(adapter.getReplyMessageEvents().subscribe({ setReplyTo(it) }, ExceptionHandler.rx())) - compositeSubscription.add(adapter.getCopyMessageFlowable().subscribe({ this.copyMessageToClipboard(it) }, ExceptionHandler.rx())) + adapter.onOpenProfile = { userId -> FullProfileActivity.open(userId) } + adapter.onDeleteMessage = { this.showDeleteConfirmationDialog(it) } + adapter.onFlagMessage = { this.showFlagConfirmationDialog(it) } + adapter.onReply = { setReplyTo(it) } + adapter.onCopyMessage = { this.copyMessageToClipboard(it) } adapter.onMessageLike = { viewModel?.likeMessage(it) } } @@ -108,48 +101,18 @@ class ChatFragment() : BaseFragment() { } viewModel?.user?.observe( - viewLifecycleOwner, - { - chatAdapter?.user = it - binding?.chatBarView?.hasAcceptedGuidelines = it?.flags?.communityGuidelinesAccepted == true - } - ) - } - - override fun onDestroyView() { - super.onDestroyView() - stopAutoRefreshing() - } - - override fun onResume() { - super.onResume() - startAutoRefreshing() - } - - override fun onPause() { - super.onPause() - stopAutoRefreshing() - } - - private fun startAutoRefreshing() { - if (refreshDisposable?.isDisposed != true) { - refreshDisposable?.dispose() + viewLifecycleOwner + ) { + chatAdapter?.user = it + binding?.chatBarView?.hasAcceptedGuidelines = + it?.flags?.communityGuidelinesAccepted == true } - refreshDisposable = Observable.interval(30, TimeUnit.SECONDS) - .observeOn(AndroidSchedulers.mainThread()) - .subscribe( - { - refresh() - }, - ExceptionHandler.rx() - ) - refresh() - } - private fun stopAutoRefreshing() { - if (refreshDisposable?.isDisposed != true) { - refreshDisposable?.dispose() - refreshDisposable = null + lifecycleScope.launchWhenResumed { + while (true) { + refresh() + delay(30.toDuration(DurationUnit.SECONDS)) + } } } diff --git a/Habitica/src/main/java/com/habitrpg/android/habitica/ui/fragments/social/InboxMessageListFragment.kt b/Habitica/src/main/java/com/habitrpg/android/habitica/ui/fragments/social/InboxMessageListFragment.kt index dd37586d8..76baff135 100644 --- a/Habitica/src/main/java/com/habitrpg/android/habitica/ui/fragments/social/InboxMessageListFragment.kt +++ b/Habitica/src/main/java/com/habitrpg/android/habitica/ui/fragments/social/InboxMessageListFragment.kt @@ -35,12 +35,8 @@ import com.habitrpg.android.habitica.ui.viewmodels.InboxViewModelFactory import com.habitrpg.android.habitica.ui.views.HabiticaSnackbar import com.habitrpg.android.habitica.ui.views.HabiticaSnackbar.Companion.showSnackbar import com.habitrpg.android.habitica.ui.views.dialogs.HabiticaAlertDialog -import io.reactivex.rxjava3.android.schedulers.AndroidSchedulers -import io.reactivex.rxjava3.core.Observable -import io.reactivex.rxjava3.disposables.Disposable import kotlinx.coroutines.delay import kotlinx.coroutines.launch -import java.util.concurrent.TimeUnit import javax.inject.Inject import kotlin.time.DurationUnit import kotlin.time.toDuration @@ -65,7 +61,6 @@ class InboxMessageListFragment : BaseMainFragment - compositeSubscription.add( - adapter.getUserLabelClickFlowable().subscribe( - { + adapter.onOpenProfile = { FullProfileActivity.open(it) - }, - ExceptionHandler.rx() - ) - ) - compositeSubscription.add(adapter.getDeleteMessageFlowable().subscribe({ showDeleteConfirmationDialog(it) }, ExceptionHandler.rx())) - compositeSubscription.add(adapter.getFlagMessageClickFlowable().subscribe({ showFlagConfirmationDialog(it) }, ExceptionHandler.rx())) - compositeSubscription.add(adapter.getCopyMessageFlowable().subscribe({ copyMessageToClipboard(it) }, ExceptionHandler.rx())) + } + adapter.onDeleteMessage = { showDeleteConfirmationDialog(it) } + adapter.onFlagMessage = { showFlagConfirmationDialog(it) } + adapter.onCopyMessage = { copyMessageToClipboard(it) } } } @@ -132,13 +122,19 @@ class InboxMessageListFragment : BaseMainFragment() super.onViewCreated(view, savedInstanceState) challengeAdapter = ChallengesListViewAdapter(viewUserChallengesOnly, userId) - challengeAdapter?.getOpenDetailFragmentFlowable() - ?.subscribe({ openDetailFragment(it) }, ExceptionHandler.rx()) - ?.let { compositeSubscription.add(it) } - + challengeAdapter?.onOpenChallengeFragment = { openDetailFragment(it) } binding?.refreshLayout?.setOnRefreshListener(this) if (viewUserChallengesOnly) { diff --git a/Habitica/src/main/java/com/habitrpg/android/habitica/ui/fragments/tasks/RewardsRecyclerviewFragment.kt b/Habitica/src/main/java/com/habitrpg/android/habitica/ui/fragments/tasks/RewardsRecyclerviewFragment.kt index 45f7fcd56..cd86dd2e4 100644 --- a/Habitica/src/main/java/com/habitrpg/android/habitica/ui/fragments/tasks/RewardsRecyclerviewFragment.kt +++ b/Habitica/src/main/java/com/habitrpg/android/habitica/ui/fragments/tasks/RewardsRecyclerviewFragment.kt @@ -13,7 +13,6 @@ import androidx.lifecycle.lifecycleScope import androidx.recyclerview.widget.GridLayoutManager import androidx.recyclerview.widget.LinearLayoutManager import com.habitrpg.android.habitica.R -import com.habitrpg.android.habitica.extensions.subscribeWithErrorHandler import com.habitrpg.android.habitica.helpers.ExceptionHandler import com.habitrpg.android.habitica.helpers.launchCatching import com.habitrpg.android.habitica.models.shops.ShopItem @@ -68,15 +67,12 @@ class RewardsRecyclerviewFragment : TaskRecyclerViewFragment() { } } - (recyclerAdapter as? RewardsRecyclerViewAdapter)?.purchaseCardEvents?.subscribe( - { + (recyclerAdapter as? RewardsRecyclerViewAdapter)?.purchaseCardEvents = { selectedCard = it val intent = Intent(activity, SkillMemberActivity::class.java) cardSelectedResult.launch(intent) - }, - ExceptionHandler.rx() - )?.let { compositeSubscription.add(it) } - recyclerAdapter?.brokenTaskEvents?.subscribeWithErrorHandler { showBrokenChallengeDialog(it) }?.let { compositeSubscription.add(it) } + } + recyclerAdapter?.brokenTaskEvents = { showBrokenChallengeDialog(it) } viewModel.user.observe(viewLifecycleOwner) { (recyclerAdapter as? RewardsRecyclerViewAdapter)?.user = it diff --git a/Habitica/src/main/java/com/habitrpg/android/habitica/ui/fragments/tasks/TaskRecyclerViewFragment.kt b/Habitica/src/main/java/com/habitrpg/android/habitica/ui/fragments/tasks/TaskRecyclerViewFragment.kt index f964224de..2ca698d74 100644 --- a/Habitica/src/main/java/com/habitrpg/android/habitica/ui/fragments/tasks/TaskRecyclerViewFragment.kt +++ b/Habitica/src/main/java/com/habitrpg/android/habitica/ui/fragments/tasks/TaskRecyclerViewFragment.kt @@ -22,7 +22,6 @@ import com.habitrpg.android.habitica.data.UserRepository import com.habitrpg.android.habitica.databinding.FragmentRefreshRecyclerviewBinding import com.habitrpg.android.habitica.extensions.observeOnce import com.habitrpg.android.habitica.extensions.setScaledPadding -import com.habitrpg.android.habitica.extensions.subscribeWithErrorHandler import com.habitrpg.android.habitica.helpers.AppConfigManager import com.habitrpg.android.habitica.helpers.ExceptionHandler import com.habitrpg.android.habitica.helpers.HapticFeedbackManager @@ -51,7 +50,6 @@ import com.habitrpg.common.habitica.helpers.EmptyItem import com.habitrpg.shared.habitica.models.responses.TaskDirection import com.habitrpg.shared.habitica.models.responses.TaskScoringResult import com.habitrpg.shared.habitica.models.tasks.TaskType -import io.reactivex.rxjava3.disposables.CompositeDisposable import kotlinx.coroutines.Job import kotlinx.coroutines.flow.distinctUntilChanged import kotlinx.coroutines.flow.distinctUntilChangedBy @@ -79,7 +77,6 @@ open class TaskRecyclerViewFragment : BaseFragment val adapter: BaseRecyclerViewAdapter<*, *>? = when (this.taskType) { TaskType.HABIT -> HabitsRecyclerViewAdapter(R.layout.habit_item_card, viewModel) @@ -142,33 +135,28 @@ open class TaskRecyclerViewFragment : BaseFragment notificationsManager.dismissTaskNotification(it1, it.first) } - }?.subscribeWithErrorHandler { scoreTask(it.first, it.second) } - ?.let { recyclerSubscription.add(it) } - recyclerAdapter?.checklistItemScoreEvents?.subscribeWithErrorHandler { - scoreChecklistItem(it.first, it.second) - }?.let { recyclerSubscription.add(it) } - recyclerAdapter?.brokenTaskEvents?.subscribeWithErrorHandler { showBrokenChallengeDialog(it) } - ?.let { recyclerSubscription.add(it) } - recyclerAdapter?.adventureGuideOpenEvents?.subscribeWithErrorHandler { + } + recyclerAdapter?.taskOpenEvents = { task, view -> + openTaskForm(task) + } + recyclerAdapter?.taskScoreEvents = { task, direction -> + playSound(direction) + context?.let { it1 -> notificationsManager.dismissTaskNotification(it1, task) } + scoreTask(task, direction) + } + recyclerAdapter?.checklistItemScoreEvents = { task, item -> + scoreChecklistItem(task, item) + } + recyclerAdapter?.brokenTaskEvents = { showBrokenChallengeDialog(it) } + recyclerAdapter?.adventureGuideOpenEvents = { MainNavigationController.navigate( R.id.adventureGuideActivity ) - }?.let { recyclerSubscription.add(it) } + } viewModel.ownerID.observe(viewLifecycleOwner) { canEditTasks = viewModel.isPersonalBoard diff --git a/Habitica/src/main/java/com/habitrpg/android/habitica/ui/viewHolders/ChatRecyclerViewHolder.kt b/Habitica/src/main/java/com/habitrpg/android/habitica/ui/viewHolders/ChatRecyclerViewHolder.kt index 517fbed3f..ce016af29 100644 --- a/Habitica/src/main/java/com/habitrpg/android/habitica/ui/viewHolders/ChatRecyclerViewHolder.kt +++ b/Habitica/src/main/java/com/habitrpg/android/habitica/ui/viewHolders/ChatRecyclerViewHolder.kt @@ -13,7 +13,6 @@ import com.habitrpg.android.habitica.databinding.ChatItemBinding import com.habitrpg.android.habitica.databinding.TavernChatIntroItemBinding import com.habitrpg.android.habitica.extensions.getAgoString import com.habitrpg.android.habitica.extensions.setScaledPadding -import com.habitrpg.android.habitica.helpers.ExceptionHandler import com.habitrpg.android.habitica.models.members.Member import com.habitrpg.android.habitica.models.social.ChatMessage import com.habitrpg.android.habitica.models.user.User @@ -24,9 +23,10 @@ import com.habitrpg.common.habitica.extensions.DataBindingUtils import com.habitrpg.common.habitica.extensions.dpToPx import com.habitrpg.common.habitica.helpers.MarkdownParser import com.habitrpg.common.habitica.helpers.setParsedMarkdown -import io.reactivex.rxjava3.android.schedulers.AndroidSchedulers -import io.reactivex.rxjava3.core.Maybe -import io.reactivex.rxjava3.schedulers.Schedulers +import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.MainScope +import kotlinx.coroutines.launch +import kotlinx.coroutines.withContext open class ChatRecyclerViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView) @@ -185,17 +185,13 @@ class ChatRecyclerMessageViewHolder( binding.messageText.setParsedMarkdown(chatMessage?.parsedText) if (msg.parsedText == null) { binding.messageText.text = chatMessage?.text - Maybe.just(chatMessage?.text ?: "") - .map { MarkdownParser.parseMarkdown(it) } - .subscribeOn(Schedulers.io()) - .observeOn(AndroidSchedulers.mainThread()) - .subscribe( - { parsedText -> - chatMessage?.parsedText = parsedText - binding.messageText.setParsedMarkdown(parsedText) - }, - ExceptionHandler.rx() - ) + MainScope().launch(Dispatchers.IO) { + val parsedText = MarkdownParser.parseMarkdown(chatMessage?.text ?: "") + withContext(Dispatchers.Main) { + chatMessage?.parsedText = parsedText + binding.messageText.setParsedMarkdown(parsedText) + } + } } val username = user?.formattedUsername diff --git a/Habitica/src/main/java/com/habitrpg/android/habitica/ui/viewHolders/tasks/BaseTaskViewHolder.kt b/Habitica/src/main/java/com/habitrpg/android/habitica/ui/viewHolders/tasks/BaseTaskViewHolder.kt index 1af36d06d..81b1e558e 100644 --- a/Habitica/src/main/java/com/habitrpg/android/habitica/ui/viewHolders/tasks/BaseTaskViewHolder.kt +++ b/Habitica/src/main/java/com/habitrpg/android/habitica/ui/viewHolders/tasks/BaseTaskViewHolder.kt @@ -14,7 +14,6 @@ import android.widget.TextView import androidx.core.content.ContextCompat import com.habitrpg.android.habitica.R import com.habitrpg.android.habitica.helpers.GroupPlanInfoProvider -import com.habitrpg.android.habitica.helpers.ExceptionHandler import com.habitrpg.android.habitica.models.tasks.Task import com.habitrpg.android.habitica.ui.viewHolders.BindableViewHolder import com.habitrpg.android.habitica.ui.views.EllipsisTextView @@ -23,13 +22,10 @@ import com.habitrpg.common.habitica.extensions.getThemeColor import com.habitrpg.common.habitica.helpers.MarkdownParser import com.habitrpg.common.habitica.helpers.setParsedMarkdown import com.habitrpg.shared.habitica.models.responses.TaskDirection -import io.reactivex.rxjava3.android.schedulers.AndroidSchedulers -import io.reactivex.rxjava3.core.Single -import io.reactivex.rxjava3.functions.Action -import io.reactivex.rxjava3.schedulers.Schedulers import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.MainScope import kotlinx.coroutines.launch +import kotlinx.coroutines.withContext abstract class BaseTaskViewHolder constructor( itemView: View, @@ -42,7 +38,7 @@ abstract class BaseTaskViewHolder constructor( var task: Task? = null var movingFromPosition: Int? = null - var errorButtonClicked: Action? = null + var errorButtonClicked: (() -> Unit)? = null var userID: String? = null var isLocked = false protected var context: Context @@ -101,7 +97,7 @@ abstract class BaseTaskViewHolder constructor( titleTextView.setOnClickListener { onTouch(it, null) } notesTextView?.setOnClickListener { onTouch(it, null) } - errorIconView?.setOnClickListener { errorButtonClicked?.run() } + errorIconView?.setOnClickListener { errorButtonClicked?.invoke() } notesTextView?.movementMethod = LinkMovementMethod.getInstance() titleTextView.movementMethod = LinkMovementMethod.getInstance() @@ -169,17 +165,13 @@ abstract class BaseTaskViewHolder constructor( } else { titleTextView.text = data.text if (data.text.isNotEmpty()) { - Single.just(data.text) - .map { MarkdownParser.parseMarkdown(it) } - .subscribeOn(Schedulers.io()) - .observeOn(AndroidSchedulers.mainThread()) - .subscribe( - { parsedText -> - data.parsedText = parsedText - titleTextView.setParsedMarkdown(parsedText) - }, - ExceptionHandler.rx() - ) + scope.launch(Dispatchers.IO) { + val parsedText = MarkdownParser.parseMarkdown(data.text) + withContext(Dispatchers.Main) { + data.parsedText = parsedText + titleTextView.setParsedMarkdown(parsedText) + } + } } } if (displayMode != "minimal") { @@ -196,17 +188,13 @@ abstract class BaseTaskViewHolder constructor( if (notes.isEmpty()) { return@let } - Single.just(notes) - .map { MarkdownParser.parseMarkdown(it) } - .subscribeOn(Schedulers.io()) - .observeOn(AndroidSchedulers.mainThread()) - .subscribe( - { parsedNotes -> - data.parsedNotes = parsedNotes - notesTextView?.setParsedMarkdown(parsedNotes) - }, - ExceptionHandler.rx() - ) + scope.launch(Dispatchers.IO) { + val parsedNotes = MarkdownParser.parseMarkdown(notes) + withContext(Dispatchers.Main) { + data.parsedNotes = parsedNotes + notesTextView?.setParsedMarkdown(parsedNotes) + } + } } } } diff --git a/Habitica/src/main/java/com/habitrpg/android/habitica/ui/viewHolders/tasks/ChecklistedViewHolder.kt b/Habitica/src/main/java/com/habitrpg/android/habitica/ui/viewHolders/tasks/ChecklistedViewHolder.kt index 499445b24..cae10b607 100644 --- a/Habitica/src/main/java/com/habitrpg/android/habitica/ui/viewHolders/tasks/ChecklistedViewHolder.kt +++ b/Habitica/src/main/java/com/habitrpg/android/habitica/ui/viewHolders/tasks/ChecklistedViewHolder.kt @@ -22,9 +22,10 @@ import com.habitrpg.common.habitica.helpers.MarkdownParser import com.habitrpg.common.habitica.helpers.setParsedMarkdown import com.habitrpg.shared.habitica.models.responses.TaskDirection import com.habitrpg.shared.habitica.models.tasks.TaskType -import io.reactivex.rxjava3.android.schedulers.AndroidSchedulers -import io.reactivex.rxjava3.core.Observable -import io.reactivex.rxjava3.schedulers.Schedulers +import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.MainScope +import kotlinx.coroutines.launch +import kotlinx.coroutines.withContext abstract class ChecklistedViewHolder( itemView: View, @@ -131,16 +132,12 @@ abstract class ChecklistedViewHolder( textView?.text = item.text textView?.setTextColor(ContextCompat.getColor(context, if (item.completed) R.color.text_dimmed else R.color.text_secondary)) if (item.text != null) { - Observable.just(item.text ?: "") - .map { MarkdownParser.parseMarkdown(it) } - .subscribeOn(Schedulers.io()) - .observeOn(AndroidSchedulers.mainThread()) - .subscribe( - { - textView?.setParsedMarkdown(it) - }, - ExceptionHandler.rx() - ) + MainScope().launch(Dispatchers.IO) { + val parsedText = MarkdownParser.parseMarkdown(item.text ?: "") + withContext(Dispatchers.Main) { + textView?.setParsedMarkdown(parsedText) + } + } } val checkmark = itemView?.findViewById(R.id.checkmark) checkmark?.drawable?.setTintMode(PorterDuff.Mode.SRC_ATOP) 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 dce3fc33d..c73bd6e2f 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 @@ -33,7 +33,6 @@ import com.habitrpg.common.habitica.api.HostConfig import com.habitrpg.common.habitica.helpers.KeyHelper import com.habitrpg.common.habitica.models.auth.UserAuthResponse import com.willowtreeapps.signinwithapplebutton.SignInWithAppleConfiguration -import io.reactivex.rxjava3.disposables.CompositeDisposable import kotlinx.coroutines.MainScope import javax.inject.Inject @@ -52,8 +51,6 @@ class AuthenticationViewModel() { @JvmField var keyHelper: KeyHelper? = null - private var compositeSubscription = CompositeDisposable() - var googleEmail: String? = null init { diff --git a/Habitica/src/main/java/com/habitrpg/android/habitica/ui/viewmodels/MainUserViewModel.kt b/Habitica/src/main/java/com/habitrpg/android/habitica/ui/viewmodels/MainUserViewModel.kt index a141c608d..ba0b0ec5b 100644 --- a/Habitica/src/main/java/com/habitrpg/android/habitica/ui/viewmodels/MainUserViewModel.kt +++ b/Habitica/src/main/java/com/habitrpg/android/habitica/ui/viewmodels/MainUserViewModel.kt @@ -9,7 +9,6 @@ import com.habitrpg.android.habitica.models.TeamPlan import com.habitrpg.android.habitica.models.invitations.PartyInvite import com.habitrpg.android.habitica.models.members.Member import com.habitrpg.android.habitica.models.user.User -import io.reactivex.rxjava3.disposables.CompositeDisposable import kotlinx.coroutines.ExperimentalCoroutinesApi import kotlinx.coroutines.MainScope import kotlinx.coroutines.flow.MutableStateFlow @@ -55,11 +54,8 @@ class MainUserViewModel(private val providedUserID: String, val userRepository: fun onCleared() { userRepository.close() - disposable.clear() } - internal val disposable = CompositeDisposable() - fun updateUser(path: String, value: Any) { MainScope().launch(ExceptionHandler.coroutine()) { userRepository.updateUser(path, value) diff --git a/Habitica/src/main/java/com/habitrpg/android/habitica/ui/viewmodels/TasksViewModel.kt b/Habitica/src/main/java/com/habitrpg/android/habitica/ui/viewmodels/TasksViewModel.kt index 2a63d6f42..72f6b0510 100644 --- a/Habitica/src/main/java/com/habitrpg/android/habitica/ui/viewmodels/TasksViewModel.kt +++ b/Habitica/src/main/java/com/habitrpg/android/habitica/ui/viewmodels/TasksViewModel.kt @@ -20,7 +20,6 @@ import com.habitrpg.android.habitica.models.tasks.Task import com.habitrpg.shared.habitica.models.responses.TaskDirection import com.habitrpg.shared.habitica.models.responses.TaskScoringResult import com.habitrpg.shared.habitica.models.tasks.TaskType -import io.reactivex.rxjava3.disposables.CompositeDisposable import io.realm.Case import io.realm.OrderedRealmCollection import io.realm.RealmQuery @@ -30,8 +29,6 @@ import java.util.Date import javax.inject.Inject class TasksViewModel : BaseViewModel(), GroupPlanInfoProvider { - private var compositeSubscription: CompositeDisposable = CompositeDisposable() - override fun inject(component: UserComponent) { component.inject(this) } diff --git a/Habitica/src/main/java/com/habitrpg/android/habitica/ui/views/dialogs/PetSuggestHatchDialog.kt b/Habitica/src/main/java/com/habitrpg/android/habitica/ui/views/dialogs/PetSuggestHatchDialog.kt index 566af2cb9..468bed602 100644 --- a/Habitica/src/main/java/com/habitrpg/android/habitica/ui/views/dialogs/PetSuggestHatchDialog.kt +++ b/Habitica/src/main/java/com/habitrpg/android/habitica/ui/views/dialogs/PetSuggestHatchDialog.kt @@ -11,7 +11,6 @@ import com.habitrpg.android.habitica.HabiticaBaseApplication import com.habitrpg.android.habitica.R import com.habitrpg.android.habitica.databinding.DialogHatchPetButtonBinding import com.habitrpg.android.habitica.databinding.DialogPetSuggestHatchBinding -import com.habitrpg.android.habitica.helpers.ExceptionHandler import com.habitrpg.android.habitica.helpers.launchCatching import com.habitrpg.android.habitica.interactors.HatchPetUseCase import com.habitrpg.android.habitica.models.inventory.Animal @@ -22,8 +21,7 @@ import com.habitrpg.android.habitica.ui.activities.BaseActivity import com.habitrpg.android.habitica.ui.activities.MainActivity import com.habitrpg.common.habitica.extensions.DataBindingUtils import com.habitrpg.common.habitica.extensions.loadImage -import io.reactivex.rxjava3.android.schedulers.AndroidSchedulers -import io.reactivex.rxjava3.core.Observable +import kotlinx.coroutines.MainScope import java.util.Locale import javax.inject.Inject @@ -162,14 +160,9 @@ class PetSuggestHatchDialog(context: Context) : HabiticaAlertDialog(context) { DataBindingUtils.loadImage(context, imageName) { val resources = context.resources ?: return@loadImage val drawable = if (hasMount) it else BitmapDrawable(resources, it.toBitmap().extractAlpha()) - Observable.just(drawable) - .observeOn(AndroidSchedulers.mainThread()) - .subscribe( - { - binding.petView.bitmap = drawable.toBitmap() - }, - ExceptionHandler.rx() - ) + MainScope().launchCatching { + binding.petView.bitmap = drawable.toBitmap() + } } } diff --git a/Habitica/src/main/java/com/habitrpg/android/habitica/ui/views/shops/PurchaseDialog.kt b/Habitica/src/main/java/com/habitrpg/android/habitica/ui/views/shops/PurchaseDialog.kt index fde907d89..aaf51f764 100644 --- a/Habitica/src/main/java/com/habitrpg/android/habitica/ui/views/shops/PurchaseDialog.kt +++ b/Habitica/src/main/java/com/habitrpg/android/habitica/ui/views/shops/PurchaseDialog.kt @@ -40,8 +40,6 @@ import com.habitrpg.android.habitica.ui.views.insufficientCurrency.InsufficientG import com.habitrpg.android.habitica.ui.views.insufficientCurrency.InsufficientHourglassesDialog import com.habitrpg.android.habitica.ui.views.insufficientCurrency.InsufficientSubscriberGemsDialog import com.habitrpg.android.habitica.ui.views.tasks.form.StepperValueFormView -import io.reactivex.rxjava3.disposables.CompositeDisposable -import kotlinx.coroutines.DelicateCoroutinesApi import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.Job import kotlinx.coroutines.MainScope @@ -221,7 +219,6 @@ class PurchaseDialog(context: Context, component: UserComponent?, val item: Shop } } - private val compositeSubscription: CompositeDisposable = CompositeDisposable() var shopIdentifier: String? = null private var user: User? = null var isPinned: Boolean = false @@ -313,13 +310,9 @@ class PurchaseDialog(context: Context, component: UserComponent?, val item: Shop userRepository.close() inventoryRepository.close() limitedTextViewJob?.cancel() - if (!compositeSubscription.isDisposed) { - compositeSubscription.dispose() - } super.dismiss() } - @OptIn(DelicateCoroutinesApi::class) private fun onBuyButtonClicked() { if (shopItem.isValid && !shopItem.locked) { val gemsLeft = if (shopItem.limitedNumberLeft != null) shopItem.limitedNumberLeft else 0 @@ -368,7 +361,7 @@ class PurchaseDialog(context: Context, component: UserComponent?, val item: Shop ) HapticFeedbackManager.tap(contentView) val snackbarText = arrayOf("") - val observable: (suspend () -> Unit) + val observable: (suspend () -> Any?) if (shopIdentifier != null && shopIdentifier == Shop.TIME_TRAVELERS_SHOP || "mystery_set" == shopItem.purchaseType || shopItem.currency == "hourglasses") { observable = if (shopItem.purchaseType == "gear") { { inventoryRepository.purchaseMysterySet(shopItem.key) } @@ -408,10 +401,8 @@ class PurchaseDialog(context: Context, component: UserComponent?, val item: Shop observable = { inventoryRepository.purchaseItem(shopItem.purchaseType, shopItem.key, quantity) } } lifecycleScope.launchCatching { - observable() - val text = if (snackbarText[0].isNotEmpty()) { - snackbarText[0] - } else { + val result = observable() ?: return@launchCatching + val text = snackbarText[0].ifEmpty { context.getString(R.string.successful_purchase, shopItem.text) } val rightTextColor = when (item.currency) { diff --git a/Habitica/src/main/java/com/habitrpg/android/habitica/ui/views/social/QuestProgressView.kt b/Habitica/src/main/java/com/habitrpg/android/habitica/ui/views/social/QuestProgressView.kt index 0ffdf322c..fa8e349ed 100644 --- a/Habitica/src/main/java/com/habitrpg/android/habitica/ui/views/social/QuestProgressView.kt +++ b/Habitica/src/main/java/com/habitrpg/android/habitica/ui/views/social/QuestProgressView.kt @@ -20,6 +20,7 @@ import com.habitrpg.android.habitica.R import com.habitrpg.android.habitica.databinding.QuestCollectBinding import com.habitrpg.android.habitica.databinding.QuestProgressBinding import com.habitrpg.android.habitica.helpers.ExceptionHandler +import com.habitrpg.android.habitica.helpers.launchCatching import com.habitrpg.android.habitica.models.inventory.Quest import com.habitrpg.android.habitica.models.inventory.QuestContent import com.habitrpg.android.habitica.models.inventory.QuestProgressCollect @@ -32,8 +33,7 @@ import com.habitrpg.common.habitica.extensions.DataBindingUtils import com.habitrpg.common.habitica.extensions.layoutInflater import com.habitrpg.common.habitica.extensions.loadImage import com.habitrpg.common.habitica.helpers.setMarkdown -import io.reactivex.rxjava3.android.schedulers.AndroidSchedulers -import io.reactivex.rxjava3.core.Observable +import kotlinx.coroutines.MainScope class QuestProgressView : LinearLayout { private val binding = QuestProgressBinding.inflate(context.layoutInflater, this, true) @@ -181,22 +181,17 @@ class QuestProgressView : LinearLayout { val iconView = ImageView(context) if (strike.wasHit) { DataBindingUtils.loadImage(context, "rage_strike_${strike.key}") { - Observable.just(it) - .observeOn(AndroidSchedulers.mainThread()) - .subscribe( - { drawable -> - val bitmap = drawable.toBitmap() - val displayDensity = resources.displayMetrics.density - val width = bitmap.width * displayDensity - val height = bitmap.height * displayDensity - val scaledImage = Bitmap.createScaledBitmap(bitmap, width.toInt(), height.toInt(), false) - iconView.setImageBitmap(HabiticaIconsHelper.imageOfRageStrikeActive(context, scaledImage)) - iconView.setOnClickListener { - showActiveStrikeAlert(strike.key) - } - }, - ExceptionHandler.rx() - ) + MainScope().launchCatching { + val bitmap = it.toBitmap() + val displayDensity = resources.displayMetrics.density + val width = bitmap.width * displayDensity + val height = bitmap.height * displayDensity + val scaledImage = Bitmap.createScaledBitmap(bitmap, width.toInt(), height.toInt(), false) + iconView.setImageBitmap(HabiticaIconsHelper.imageOfRageStrikeActive(context, scaledImage)) + iconView.setOnClickListener { + showActiveStrikeAlert(strike.key) + } + } } } else { iconView.setImageBitmap(HabiticaIconsHelper.imageOfRageStrikeInactive()) diff --git a/Habitica/src/main/java/com/habitrpg/android/habitica/ui/views/stats/BulkAllocateStatsDialog.kt b/Habitica/src/main/java/com/habitrpg/android/habitica/ui/views/stats/BulkAllocateStatsDialog.kt index dbc0415fe..056e47016 100644 --- a/Habitica/src/main/java/com/habitrpg/android/habitica/ui/views/stats/BulkAllocateStatsDialog.kt +++ b/Habitica/src/main/java/com/habitrpg/android/habitica/ui/views/stats/BulkAllocateStatsDialog.kt @@ -14,7 +14,6 @@ import com.habitrpg.android.habitica.helpers.ExceptionHandler import com.habitrpg.android.habitica.helpers.launchCatching import com.habitrpg.common.habitica.extensions.getThemeColor import com.habitrpg.common.habitica.extensions.layoutInflater -import io.reactivex.rxjava3.disposables.Disposable import kotlinx.coroutines.MainScope import kotlinx.coroutines.flow.filterNotNull import kotlinx.coroutines.launch @@ -25,8 +24,6 @@ class BulkAllocateStatsDialog(context: Context, component: UserComponent?) : Ale @Inject lateinit var userRepository: UserRepository - var subscription: Disposable? = null - private val allocatedPoints: Int get() { var value = 0 @@ -137,11 +134,6 @@ class BulkAllocateStatsDialog(context: Context, component: UserComponent?) : Ale } } - override fun dismiss() { - subscription?.dispose() - super.dismiss() - } - @SuppressLint("SetTextI18n") private fun updateTitle() { binding.allocatedTitle.text = "$allocatedPoints/$pointsToAllocate" 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 index 666fb780d..b9340c9b8 100644 --- a/Habitica/src/release/java/com/habitrpg/android/habitica/proxy/AnalyticsManagerImpl.kt +++ b/Habitica/src/release/java/com/habitrpg/android/habitica/proxy/AnalyticsManagerImpl.kt @@ -2,7 +2,6 @@ package com.habitrpg.android.habitica.proxy import android.content.Context import android.os.Bundle -import com.amplitude.api.Amplitude import com.google.firebase.analytics.FirebaseAnalytics import com.google.firebase.crashlytics.FirebaseCrashlytics @@ -16,7 +15,7 @@ class AnalyticsManagerImpl(context: Context) : AnalyticsManager { override fun setUserIdentifier(identifier: String) { FirebaseCrashlytics.getInstance().setUserId(identifier) - Amplitude.getInstance().userId = identifier + AmplitudeManager.amplitude.userId = identifier } override fun setUserProperty(identifier: String, value: String) { diff --git a/build.gradle b/build.gradle index 2df4a4e19..76a6daafa 100644 --- a/build.gradle +++ b/build.gradle @@ -7,20 +7,20 @@ buildscript { app_version_name = '' app_version_code = 0 - amplitude_version = '3.35.1' + amplitude_version = '1.5.1' appcompat_version = '1.5.1' - coil_version = '2.1.0' - compose_version = '1.3.0' + coil_version = '2.2.2' + compose_version = '1.3.1' core_ktx_version = '1.9.0' coroutines_version = '1.6.4' - daggerhilt_version = '2.42' + daggerhilt_version = '2.44.2' firebase_bom = '30.2.0' - kotlin_version = '1.7.20' + kotlin_version = '1.7.21' lifecycle_version = '2.5.1' markwon_version = '4.6.2' - moshi_version = '1.13.0' + moshi_version = '1.14.0' navigation_version = '2.5.3' - okhttp_version = '4.9.3' + okhttp_version = '4.10.0' play_wearables_version = '18.0.0' play_auth_version = '20.3.0' preferences_version = '1.2.0'