mirror of
https://github.com/sudoxnym/habitica-android.git
synced 2026-04-14 19:56:32 +00:00
Fully remove RxJava
This commit is contained in:
parent
c4a482eac8
commit
3bd68fedf0
66 changed files with 309 additions and 916 deletions
|
|
@ -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 {
|
||||
|
|
|
|||
|
|
@ -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) {
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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<Throwable>, 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() }
|
||||
|
|
|
|||
|
|
@ -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 {
|
||||
|
|
|
|||
|
|
@ -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 {
|
||||
|
|
|
|||
|
|
@ -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<Task>
|
||||
|
||||
fun updateIsdue(daily: TaskList): Maybe<TaskList>
|
||||
fun updateIsdue(daily: TaskList): TaskList
|
||||
|
||||
fun updateTaskPositions(taskOrder: List<String>)
|
||||
fun saveCompletedTodos(userId: String, tasks: MutableCollection<Task>)
|
||||
|
|
|
|||
|
|
@ -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<User> {
|
||||
return RxJavaBridge.toV3Flowable(
|
||||
realm.where(User::class.java)
|
||||
.equalTo("id", userID)
|
||||
.findAll()
|
||||
.asFlowable()
|
||||
)
|
||||
.filter { it.isLoaded && it.isValid && !it.isEmpty() }
|
||||
.filterMap { it.first() }
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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<TaskList> {
|
||||
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<String>) {
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -1,8 +0,0 @@
|
|||
package com.habitrpg.android.habitica.executors;
|
||||
|
||||
|
||||
import io.reactivex.rxjava3.core.Scheduler;
|
||||
|
||||
public interface PostExecutionThread {
|
||||
Scheduler getScheduler();
|
||||
}
|
||||
|
|
@ -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();
|
||||
}
|
||||
}
|
||||
|
|
@ -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()
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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 <T : Any> Flowable<T>.subscribeWithErrorHandler(function: Consumer<T>): Disposable {
|
||||
return subscribe(function, ExceptionHandler.rx())
|
||||
}
|
||||
|
|
@ -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 <S : Any, T : Optional<S>> Flowable<T>.filterOptionalDoOnEmpty(function: () -> Unit): Flowable<S> {
|
||||
return this.doOnNext { if (it.isEmpty) function() }
|
||||
.filter { !it.isEmpty }
|
||||
.map { it.assertedValue }
|
||||
}
|
||||
|
||||
fun <S : Any, T : Optional<S>> Flowable<T>.filterMapEmpty(): Flowable<S> {
|
||||
return this.filter { !it.isEmpty }
|
||||
.map { it.assertedValue }
|
||||
}
|
||||
|
||||
fun <S : Any, T : Any> Flowable<T>.filterMap(function: (T) -> S?): Flowable<S> {
|
||||
return this.map { Optional(function(it)) }
|
||||
.filter { !it.isEmpty }
|
||||
.map { it.assertedValue }
|
||||
}
|
||||
|
||||
fun <S : Any, T : Optional<S>> Observable<T>.filterOptionalDoOnEmpty(function: () -> Unit): Observable<S> {
|
||||
return this.doOnNext { if (it.isEmpty) function() }
|
||||
.filter { !it.isEmpty }
|
||||
.map { it.assertedValue }
|
||||
}
|
||||
|
||||
fun <S : Any, T : Optional<S>> Observable<T>.filterMapEmpty(): Observable<S> {
|
||||
return this.filter { !it.isEmpty }
|
||||
.map { it.assertedValue }
|
||||
}
|
||||
|
||||
fun <S : Any, T : Any> Observable<T>.filterMap(function: (T) -> S?): Observable<S> {
|
||||
return this.map { Optional(function(it)) }
|
||||
.filter { !it.isEmpty }
|
||||
.map { it.assertedValue }
|
||||
}
|
||||
|
||||
fun <S, T : Optional<S>> Single<T>.filterOptionalDoOnEmpty(function: () -> Unit): Maybe<S> {
|
||||
return this.doOnSuccess { if (it.isEmpty) function() }
|
||||
.filter { !it.isEmpty }
|
||||
.map { it.assertedValue }
|
||||
}
|
||||
|
||||
fun <S, T : Optional<S>> Single<T>.filterMapEmpty(): Maybe<S> {
|
||||
return this.filter { !it.isEmpty }
|
||||
.map { it.assertedValue }
|
||||
}
|
||||
|
||||
fun <S, T : Optional<S>> Maybe<T>.filterOptionalDoOnEmpty(function: () -> Unit): Maybe<S> {
|
||||
return this.doOnSuccess { if (it.isEmpty) function() }
|
||||
.filter { !it.isEmpty }
|
||||
.map { it.assertedValue }
|
||||
}
|
||||
|
||||
fun <S, T : Optional<S>> Maybe<T>.filterMapEmpty(): Maybe<S> {
|
||||
return this.filter { !it.isEmpty }
|
||||
.map { it.assertedValue }
|
||||
}
|
||||
|
|
@ -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<String, Any?>(
|
||||
"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)
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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<Throwable> {
|
||||
// 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)
|
||||
|
|
|
|||
|
|
@ -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<SoundFile>): Single<List<SoundFile>> {
|
||||
return Observable.fromIterable(files)
|
||||
.flatMap(
|
||||
{ audioFile ->
|
||||
suspend fun download(files: List<SoundFile>): List<SoundFile> {
|
||||
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<SoundFile> { 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 =
|
||||
|
|
|
|||
|
|
@ -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<SoundFile>()
|
||||
|
||||
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()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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<CheckClassSelectionUseCase.RequestValues, Unit>() {
|
||||
class CheckClassSelectionUseCase @Inject constructor() : FlowUseCase<CheckClassSelectionUseCase.RequestValues, Unit>() {
|
||||
|
||||
override suspend fun run(requestValues: RequestValues) {
|
||||
val user = requestValues.user
|
||||
|
|
|
|||
|
|
@ -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<Q : UseCase.RequestValues?, T: Any> protected constructor(private val postExecutionThread: PostExecutionThread) {
|
||||
protected abstract fun buildUseCaseObservable(requestValues: Q): Flowable<T>
|
||||
fun observable(requestValues: Q): Flowable<T> {
|
||||
return buildUseCaseObservable(requestValues)
|
||||
.subscribeOn(postExecutionThread.scheduler)
|
||||
.observeOn(postExecutionThread.scheduler)
|
||||
}
|
||||
|
||||
interface RequestValues
|
||||
}
|
||||
|
||||
abstract class FlowUseCase<Q : FlowUseCase.RequestValues?, T> {
|
||||
protected abstract suspend fun run(requestValues: Q): T
|
||||
suspend fun callInteractor(requestValues: Q): T {
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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(
|
||||
|
|
|
|||
|
|
@ -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()
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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<androidx.recyclerview.widget.RecyclerView.ViewHolder>() {
|
||||
|
||||
var gemBalance: Int = 0
|
||||
var equipmentList: MutableList<Equipment> =
|
||||
ArrayList()
|
||||
set(value) {
|
||||
field = value
|
||||
notifyDataSetChanged()
|
||||
}
|
||||
var activeEquipment: String? = null
|
||||
set(value) {
|
||||
field = value
|
||||
this.notifyDataSetChanged()
|
||||
}
|
||||
|
||||
private val selectCustomizationEvents = PublishSubject.create<Equipment>()
|
||||
private val unlockCustomizationEvents = PublishSubject.create<Equipment>()
|
||||
|
||||
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<Equipment>) {
|
||||
this.equipmentList = newEquipmentList.toMutableList()
|
||||
val emptyEquipment = Equipment()
|
||||
equipmentList.add(0, emptyEquipment)
|
||||
this.notifyDataSetChanged()
|
||||
}
|
||||
|
||||
fun getSelectCustomizationEvents(): Flowable<Equipment> {
|
||||
return selectCustomizationEvents.toFlowable(BackpressureStrategy.DROP)
|
||||
}
|
||||
|
||||
fun getUnlockCustomizationEvents(): Flowable<Equipment> {
|
||||
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<PixelArtView>(R.id.imageView)
|
||||
imageView.loadImage("shop_" + this.equipment?.key)
|
||||
|
||||
val priceLabel = dialogContent.findViewById<TextView>(R.id.priceLabel)
|
||||
priceLabel.text = if (equipment?.gearSet == "animal") {
|
||||
2.0
|
||||
} else {
|
||||
equipment?.value ?: 0
|
||||
}.toString()
|
||||
|
||||
(dialogContent.findViewById<View>(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)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -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<RecyclerView.ViewHolder>() {
|
||||
|
||||
|
|
@ -46,14 +43,11 @@ class NavigationDrawerAdapter(tintColor: Int, backgroundTintColor: Int) : Recycl
|
|||
notifyDataSetChanged()
|
||||
}
|
||||
|
||||
private val itemSelectedEvents = PublishSubject.create<HabiticaDrawerItem>()
|
||||
private val promoClosedSubject = PublishSubject.create<String>()
|
||||
var itemSelectedEvents: ((HabiticaDrawerItem) -> Unit)? = null
|
||||
var promoClosedSubject: ((String) -> Unit)? = null
|
||||
|
||||
var activePromo: HabiticaPromotion? = null
|
||||
|
||||
fun getItemSelectionEvents(): Flowable<HabiticaDrawerItem> = itemSelectedEvents.toFlowable(BackpressureStrategy.DROP)
|
||||
fun getPromoCloseEvents(): Flowable<String> = 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)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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<SkillsRecyclerViewAdapter.SkillViewHolder>() {
|
||||
|
||||
private val useSkillSubject = PublishSubject.create<Skill>()
|
||||
val useSkillEvents: Flowable<Skill> = useSkillSubject.toFlowable(BackpressureStrategy.DROP)
|
||||
var onUseSkill: ((Skill) -> Unit)? = null
|
||||
|
||||
var mana: Double = 0.0
|
||||
set(value) {
|
||||
|
|
@ -130,7 +126,7 @@ class SkillsRecyclerViewAdapter : RecyclerView.Adapter<SkillsRecyclerViewAdapter
|
|||
|
||||
override fun onClick(v: View) {
|
||||
if ((skill?.lvl ?: 0) <= level) {
|
||||
skill?.let { useSkillSubject.onNext(it) }
|
||||
skill?.let { onUseSkill?.invoke(it) }
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -6,13 +6,11 @@ import com.habitrpg.android.habitica.models.inventory.StableSection
|
|||
import com.habitrpg.android.habitica.models.user.OwnedMount
|
||||
import com.habitrpg.android.habitica.ui.viewHolders.MountViewHolder
|
||||
import com.habitrpg.android.habitica.ui.viewHolders.SectionViewHolder
|
||||
import io.reactivex.rxjava3.subjects.PublishSubject
|
||||
|
||||
class MountDetailRecyclerAdapter : androidx.recyclerview.widget.RecyclerView.Adapter<androidx.recyclerview.widget.RecyclerView.ViewHolder>() {
|
||||
var onEquip: ((String) -> Unit)? = null
|
||||
private var ownedMounts: Map<String, OwnedMount>? = null
|
||||
|
||||
private val equipEvents = PublishSubject.create<String>()
|
||||
var currentMount: String? = null
|
||||
set(value) {
|
||||
field = value
|
||||
|
|
|
|||
|
|
@ -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<androidx.recyclerview.widget.RecyclerView.ViewHolder>() {
|
||||
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<String>()
|
||||
private val feedEvents = PublishSubject.create<Pair<Pet, Food?>>()
|
||||
private var ownsSaddles: Boolean = false
|
||||
|
||||
private var itemList: List<Any> = ArrayList()
|
||||
|
|
|
|||
|
|
@ -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<androidx.recyclerview.widget.RecyclerView.ViewHolder>() {
|
||||
|
||||
|
|
@ -28,8 +25,7 @@ class ShopRecyclerAdapter : androidx.recyclerview.widget.RecyclerView.Adapter<an
|
|||
private var shopIdentifier: String? = null
|
||||
private var ownedItems: Map<String, OwnedItem> = HashMap()
|
||||
|
||||
private val changeClassSubject = BehaviorSubject.create<String>()
|
||||
val changeClassEvents: Flowable<String> = 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<an
|
|||
sectionHolder.notesView?.text = context.getString(R.string.class_gear_disclaimer)
|
||||
if (user?.hasClass == true) {
|
||||
sectionHolder.switchClassButton?.setOnClickListener {
|
||||
changeClassSubject.onNext(selectedGearCategory)
|
||||
changeClassEvents?.invoke(selectedGearCategory)
|
||||
}
|
||||
// TODO: Enable this again when we have a nicer design
|
||||
sectionHolder.switchClassButton?.visibility = View.GONE
|
||||
|
|
|
|||
|
|
@ -12,9 +12,7 @@ import com.habitrpg.android.habitica.ui.adapter.BaseRecyclerViewAdapter
|
|||
import com.habitrpg.android.habitica.ui.fragments.social.challenges.ChallengeFilterOptions
|
||||
import com.habitrpg.android.habitica.ui.views.HabiticaIconsHelper
|
||||
import com.habitrpg.common.habitica.helpers.EmojiParser
|
||||
import io.reactivex.rxjava3.core.BackpressureStrategy
|
||||
import io.reactivex.rxjava3.core.Flowable
|
||||
import io.reactivex.rxjava3.subjects.PublishSubject
|
||||
|
||||
import io.realm.OrderedRealmCollection
|
||||
|
||||
class ChallengesListViewAdapter(
|
||||
|
|
@ -24,7 +22,7 @@ class ChallengesListViewAdapter(
|
|||
private var unfilteredData: List<Challenge>? = null
|
||||
private var challengeMemberships: List<ChallengeMembership>? = null
|
||||
|
||||
private val openChallengeFragmentEvents = PublishSubject.create<String>()
|
||||
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<String> {
|
||||
return openChallengeFragmentEvents.toFlowable(BackpressureStrategy.DROP)
|
||||
}
|
||||
|
||||
class ChallengeViewHolder internal constructor(
|
||||
itemView: View,
|
||||
private val viewUserChallengesOnly: Boolean
|
||||
|
|
|
|||
|
|
@ -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<BaseMainObject>, newList: List<BaseMainObject>) :
|
||||
DiffCallback<ChatMessage>(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<String>()
|
||||
private val deleteMessageEvents = PublishSubject.create<ChatMessage>()
|
||||
private val flagMessageEvents = PublishSubject.create<ChatMessage>()
|
||||
private val replyMessageEvents = PublishSubject.create<String>()
|
||||
private val copyMessageEvents = PublishSubject.create<ChatMessage>()
|
||||
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<ChatMessage>,
|
||||
|
|
@ -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<String> {
|
||||
return userLabelClickEvents.toFlowable(BackpressureStrategy.DROP)
|
||||
}
|
||||
|
||||
fun getFlagMessageClickFlowable(): Flowable<ChatMessage> {
|
||||
return flagMessageEvents.toFlowable(BackpressureStrategy.DROP)
|
||||
}
|
||||
|
||||
fun getDeleteMessageFlowable(): Flowable<ChatMessage> {
|
||||
return deleteMessageEvents.toFlowable(BackpressureStrategy.DROP)
|
||||
}
|
||||
|
||||
fun getReplyMessageEvents(): Flowable<String> {
|
||||
return replyMessageEvents.toFlowable(BackpressureStrategy.DROP)
|
||||
}
|
||||
|
||||
fun getCopyMessageFlowable(): Flowable<ChatMessage> {
|
||||
return copyMessageEvents.toFlowable(BackpressureStrategy.DROP)
|
||||
}
|
||||
|
||||
private fun expandMessage(message: ChatMessage, position: Int?) {
|
||||
expandedMessageId = if (expandedMessageId == message.id) {
|
||||
null
|
||||
|
|
|
|||
|
|
@ -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<ChatMessage, ChatRecyclerViewHolder>(DIFF_CALLBACK) {
|
||||
private val FIRST_MESSAGE = 0
|
||||
private val NORMAL_MESSAGE = 1
|
||||
|
||||
private var expandedMessageId: String? = null
|
||||
private val userLabelClickEvents = PublishSubject.create<String>()
|
||||
private val deleteMessageEvents = PublishSubject.create<ChatMessage>()
|
||||
private val flagMessageEvents = PublishSubject.create<ChatMessage>()
|
||||
private val replyMessageEvents = PublishSubject.create<String>()
|
||||
private val copyMessageEvents = PublishSubject.create<ChatMessage>()
|
||||
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<String> {
|
||||
return userLabelClickEvents.toFlowable(BackpressureStrategy.DROP)
|
||||
}
|
||||
|
||||
fun getFlagMessageClickFlowable(): Flowable<ChatMessage> {
|
||||
return flagMessageEvents.toFlowable(BackpressureStrategy.DROP)
|
||||
}
|
||||
|
||||
fun getDeleteMessageFlowable(): Flowable<ChatMessage> {
|
||||
return deleteMessageEvents.toFlowable(BackpressureStrategy.DROP)
|
||||
}
|
||||
|
||||
fun getCopyMessageFlowable(): Flowable<ChatMessage> {
|
||||
return copyMessageEvents.toFlowable(BackpressureStrategy.DROP)
|
||||
}
|
||||
|
||||
private fun expandMessage(id: String, position: Int) {
|
||||
if (isPositionIntroMessage(position))
|
||||
return
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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<String> = PublishSubject.create()
|
||||
override val errorButtonEvents: Flowable<String> = errorButtonEventsSubject.toFlowable(BackpressureStrategy.DROP)
|
||||
protected var taskScoreEventsSubject: PublishSubject<Pair<Task, TaskDirection>> = PublishSubject.create()
|
||||
override val taskScoreEvents: Flowable<Pair<Task, TaskDirection>> = taskScoreEventsSubject.toFlowable(BackpressureStrategy.DROP)
|
||||
protected var checklistItemScoreSubject: PublishSubject<Pair<Task, ChecklistItem>> = PublishSubject.create()
|
||||
override val checklistItemScoreEvents: Flowable<Pair<Task, ChecklistItem>> = checklistItemScoreSubject.toFlowable(BackpressureStrategy.DROP)
|
||||
protected var taskOpenEventsSubject: PublishSubject<Pair<Task, View>> = PublishSubject.create()
|
||||
override val taskOpenEvents: Flowable<Pair<Task, View>> = taskOpenEventsSubject.toFlowable(BackpressureStrategy.DROP)
|
||||
protected var brokenTaskEventsSubject: PublishSubject<Task> = PublishSubject.create()
|
||||
override val brokenTaskEvents: Flowable<Task> = brokenTaskEventsSubject.toFlowable(BackpressureStrategy.DROP)
|
||||
protected var adventureGuideOpenSubject: PublishSubject<Boolean> = PublishSubject.create()
|
||||
override val adventureGuideOpenEvents: Flowable<Boolean> = 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) }
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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<Task>?,
|
||||
|
|
@ -34,19 +31,13 @@ class RewardsRecyclerViewAdapter(
|
|||
override var showAdventureGuide: Boolean = false
|
||||
private var inAppRewards: List<ShopItem>? = null
|
||||
|
||||
private val errorButtonEventsSubject: PublishSubject<String> = PublishSubject.create()
|
||||
override val errorButtonEvents: Flowable<String> = errorButtonEventsSubject.toFlowable(BackpressureStrategy.DROP)
|
||||
private var taskScoreEventsSubject: PublishSubject<Pair<Task, TaskDirection>> = PublishSubject.create()
|
||||
override val taskScoreEvents: Flowable<Pair<Task, TaskDirection>> = taskScoreEventsSubject.toFlowable(BackpressureStrategy.LATEST)
|
||||
private var checklistItemScoreSubject: PublishSubject<Pair<Task, ChecklistItem>> = PublishSubject.create()
|
||||
override val checklistItemScoreEvents: Flowable<Pair<Task, ChecklistItem>> = checklistItemScoreSubject.toFlowable(BackpressureStrategy.DROP)
|
||||
private var taskOpenEventsSubject: PublishSubject<Pair<Task, View>> = PublishSubject.create()
|
||||
override val taskOpenEvents: Flowable<Pair<Task, View>> = taskOpenEventsSubject.toFlowable(BackpressureStrategy.LATEST)
|
||||
private var brokenTaskEventsSubject: PublishSubject<Task> = PublishSubject.create()
|
||||
override val brokenTaskEvents: Flowable<Task> = brokenTaskEventsSubject.toFlowable(BackpressureStrategy.DROP)
|
||||
override val adventureGuideOpenEvents: Flowable<Boolean>? = null
|
||||
private var purchaseCardSubject: PublishSubject<ShopItem> = PublishSubject.create()
|
||||
val purchaseCardEvents: Flowable<ShopItem> = 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
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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<Task>
|
||||
|
||||
val errorButtonEvents: Flowable<String>
|
||||
var errorButtonEvents: ((String) -> Unit)?
|
||||
|
||||
var taskDisplayMode: String
|
||||
|
||||
|
|
@ -24,9 +23,9 @@ interface TaskRecyclerViewAdapter {
|
|||
|
||||
fun updateUnfilteredData(data: List<Task>?)
|
||||
|
||||
val taskScoreEvents: Flowable<Pair<Task, TaskDirection>>
|
||||
val checklistItemScoreEvents: Flowable<Pair<Task, ChecklistItem>>
|
||||
val taskOpenEvents: Flowable<Pair<Task, View>>
|
||||
val brokenTaskEvents: Flowable<Task>
|
||||
val adventureGuideOpenEvents: Flowable<Boolean>?
|
||||
var taskScoreEvents: ((Task, TaskDirection) -> Unit)?
|
||||
var checklistItemScoreEvents: ((Task, ChecklistItem) -> Unit)?
|
||||
var taskOpenEvents: ((Task, View) -> Unit)?
|
||||
var brokenTaskEvents: ((Task) -> Unit)?
|
||||
var adventureGuideOpenEvents: ((Boolean) -> Unit)?
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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<VB : ViewBinding> : BottomSheetDialogFragment(
|
|||
protected var tutorialCanBeDeferred = true
|
||||
var tutorialTexts: MutableList<String> = ArrayList()
|
||||
|
||||
protected var compositeSubscription: CompositeDisposable = CompositeDisposable()
|
||||
|
||||
open val displayedClassName: String?
|
||||
get() = this.javaClass.simpleName
|
||||
|
||||
|
|
@ -51,8 +48,6 @@ abstract class BaseDialogFragment<VB : ViewBinding> : BottomSheetDialogFragment(
|
|||
container: ViewGroup?,
|
||||
savedInstanceState: Bundle?
|
||||
): View? {
|
||||
compositeSubscription = CompositeDisposable()
|
||||
|
||||
val additionalData = HashMap<String, Any>()
|
||||
additionalData["page"] = this.javaClass.simpleName
|
||||
AmplitudeManager.sendEvent("navigate", AmplitudeManager.EVENT_CATEGORY_NAVIGATION, AmplitudeManager.EVENT_HITTYPE_PAGEVIEW, additionalData)
|
||||
|
|
@ -89,10 +84,6 @@ abstract class BaseDialogFragment<VB : ViewBinding> : BottomSheetDialogFragment(
|
|||
|
||||
override fun onDestroyView() {
|
||||
binding = null
|
||||
if (!compositeSubscription.isDisposed) {
|
||||
compositeSubscription.dispose()
|
||||
}
|
||||
|
||||
super.onDestroyView()
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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<VB : ViewBinding> : Fragment() {
|
|||
protected var tutorialCanBeDeferred = true
|
||||
var tutorialTexts: List<String> = ArrayList()
|
||||
|
||||
protected var compositeSubscription: CompositeDisposable = CompositeDisposable()
|
||||
|
||||
var shouldInitializeComponent = true
|
||||
|
||||
open val displayedClassName: String?
|
||||
|
|
@ -60,8 +57,6 @@ abstract class BaseFragment<VB : ViewBinding> : Fragment() {
|
|||
container: ViewGroup?,
|
||||
savedInstanceState: Bundle?
|
||||
): View? {
|
||||
compositeSubscription = CompositeDisposable()
|
||||
|
||||
binding = createBinding(inflater, container)
|
||||
return binding?.root
|
||||
}
|
||||
|
|
@ -92,10 +87,6 @@ abstract class BaseFragment<VB : ViewBinding> : Fragment() {
|
|||
|
||||
override fun onDestroyView() {
|
||||
binding = null
|
||||
if (!compositeSubscription.isDisposed) {
|
||||
compositeSubscription.dispose()
|
||||
}
|
||||
|
||||
super.onDestroyView()
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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()
|
||||
|
|
|
|||
|
|
@ -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<FragmentItemsDialogBinding>() {
|
||||
|
||||
var parentSubscription: CompositeDisposable? = null
|
||||
|
||||
@Inject
|
||||
lateinit var inventoryRepository: InventoryRepository
|
||||
@Inject
|
||||
|
|
|
|||
|
|
@ -190,7 +190,6 @@ class ItemRecyclerFragment : BaseFragment<FragmentItemsBinding>(), SwipeRefreshL
|
|||
}
|
||||
fragment.isHatching = true
|
||||
fragment.isFeeding = false
|
||||
fragment.parentSubscription = compositeSubscription
|
||||
parentFragmentManager.let { fragment.show(it, "hatchingDialog") }
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -93,9 +93,9 @@ open class ShopFragment : BaseMainFragment<FragmentRefreshRecyclerviewBinding>()
|
|||
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) {
|
||||
|
|
|
|||
|
|
@ -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") }
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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()
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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<FragmentWelcomeBinding>() {
|
||||
|
||||
val nameValidEvents = PublishSubject.create<Boolean>()
|
||||
var onNameValid: ((Boolean?) -> Unit)? = null
|
||||
|
||||
@Inject
|
||||
lateinit var userRepository: UserRepository
|
||||
|
|
@ -132,7 +131,7 @@ class WelcomeFragment : BaseFragment<FragmentWelcomeBinding>() {
|
|||
binding?.issuesTextView?.visibility = View.VISIBLE
|
||||
binding?.issuesTextView?.text = it?.issues?.joinToString("\n")
|
||||
}
|
||||
nameValidEvents.onNext(it?.isUsable)
|
||||
onNameValid?.invoke(it?.isUsable)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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<FragmentSkillsBinding>() {
|
|||
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))
|
||||
|
|
|
|||
|
|
@ -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<FragmentChatBinding>() {
|
||||
|
||||
|
|
@ -52,7 +51,6 @@ class ChatFragment() : BaseFragment<FragmentChatBinding>() {
|
|||
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<FragmentChatBinding>() {
|
|||
|
||||
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<FragmentChatBinding>() {
|
|||
}
|
||||
|
||||
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))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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<FragmentInboxMessageListBindin
|
|||
private val viewModel: InboxViewModel by viewModels(factoryProducer = {
|
||||
InboxViewModelFactory(replyToUserUUID, chatRoomUser)
|
||||
})
|
||||
private var refreshDisposable: Disposable? = null
|
||||
|
||||
override fun onCreateView(
|
||||
inflater: LayoutInflater,
|
||||
|
|
@ -108,17 +103,12 @@ class InboxMessageListFragment : BaseMainFragment<FragmentInboxMessageListBindin
|
|||
binding?.recyclerView?.adapter = chatAdapter
|
||||
binding?.recyclerView?.itemAnimator = SafeDefaultItemAnimator()
|
||||
chatAdapter?.let { adapter ->
|
||||
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<FragmentInboxMessageListBindin
|
|||
binding?.chatBarView?.maxChatLength = configManager.maxChatLength()
|
||||
|
||||
binding?.chatBarView?.hasAcceptedGuidelines = true
|
||||
|
||||
lifecycleScope.launchWhenResumed {
|
||||
while (true) {
|
||||
refreshConversation()
|
||||
delay(30.toDuration(DurationUnit.SECONDS))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override fun onResume() {
|
||||
if (replyToUserUUID?.isNotBlank() != true && chatRoomUser?.isNotBlank() != true) {
|
||||
parentFragmentManager.popBackStack()
|
||||
}
|
||||
startAutoRefreshing()
|
||||
super.onResume()
|
||||
}
|
||||
|
||||
|
|
@ -149,16 +145,6 @@ class InboxMessageListFragment : BaseMainFragment<FragmentInboxMessageListBindin
|
|||
super.onAttach(context)
|
||||
}
|
||||
|
||||
override fun onDestroyView() {
|
||||
super.onDestroyView()
|
||||
stopAutoRefreshing()
|
||||
}
|
||||
|
||||
override fun onPause() {
|
||||
super.onPause()
|
||||
stopAutoRefreshing()
|
||||
}
|
||||
|
||||
override fun onDestroy() {
|
||||
socialRepository.close()
|
||||
super.onDestroy()
|
||||
|
|
@ -187,28 +173,6 @@ class InboxMessageListFragment : BaseMainFragment<FragmentInboxMessageListBindin
|
|||
socialRepository.markSomePrivateMessagesAsRead(viewModel.user.value, messages)
|
||||
}
|
||||
|
||||
private fun startAutoRefreshing() {
|
||||
if (refreshDisposable != null && refreshDisposable?.isDisposed != true) {
|
||||
refreshDisposable?.dispose()
|
||||
}
|
||||
refreshDisposable = Observable.interval(30, TimeUnit.SECONDS)
|
||||
.observeOn(AndroidSchedulers.mainThread())
|
||||
.subscribe(
|
||||
{
|
||||
refreshConversation()
|
||||
},
|
||||
ExceptionHandler.rx()
|
||||
)
|
||||
refreshConversation()
|
||||
}
|
||||
|
||||
private fun stopAutoRefreshing() {
|
||||
if (refreshDisposable?.isDisposed != true) {
|
||||
refreshDisposable?.dispose()
|
||||
refreshDisposable = null
|
||||
}
|
||||
}
|
||||
|
||||
private fun refreshConversation() {
|
||||
if (viewModel.memberID?.isNotBlank() != true) { return }
|
||||
lifecycleScope.launch(ExceptionHandler.coroutine()) {
|
||||
|
|
|
|||
|
|
@ -75,10 +75,7 @@ class ChallengeListFragment : BaseFragment<FragmentRefreshRecyclerviewBinding>()
|
|||
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) {
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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<FragmentRefreshRecyclerviewBi
|
|||
return FragmentRefreshRecyclerviewBinding.inflate(inflater, container, false)
|
||||
}
|
||||
|
||||
private var recyclerSubscription: CompositeDisposable = CompositeDisposable()
|
||||
var recyclerAdapter: TaskRecyclerViewAdapter? = null
|
||||
var itemAnimator = SafeDefaultItemAnimator()
|
||||
|
||||
|
|
@ -113,13 +110,9 @@ open class TaskRecyclerViewFragment : BaseFragment<FragmentRefreshRecyclerviewBi
|
|||
get() = this.taskType
|
||||
|
||||
private fun setInnerAdapter() {
|
||||
if (binding?.recyclerView?.adapter != null && binding?.recyclerView?.adapter == recyclerAdapter && !recyclerSubscription.isDisposed) {
|
||||
if (binding?.recyclerView?.adapter != null && binding?.recyclerView?.adapter == recyclerAdapter) {
|
||||
return
|
||||
}
|
||||
if (!recyclerSubscription.isDisposed) {
|
||||
recyclerSubscription.dispose()
|
||||
}
|
||||
recyclerSubscription = CompositeDisposable()
|
||||
viewModel.let { viewModel ->
|
||||
val adapter: BaseRecyclerViewAdapter<*, *>? = when (this.taskType) {
|
||||
TaskType.HABIT -> HabitsRecyclerViewAdapter(R.layout.habit_item_card, viewModel)
|
||||
|
|
@ -142,33 +135,28 @@ open class TaskRecyclerViewFragment : BaseFragment<FragmentRefreshRecyclerviewBi
|
|||
}
|
||||
context?.let { recyclerAdapter?.taskDisplayMode = configManager.taskDisplayMode(it) }
|
||||
|
||||
recyclerAdapter?.errorButtonEvents?.subscribe(
|
||||
{
|
||||
recyclerAdapter?.errorButtonEvents = {
|
||||
lifecycleScope.launchCatching {
|
||||
taskRepository.syncErroredTasks()
|
||||
}
|
||||
},
|
||||
ExceptionHandler.rx()
|
||||
)?.let { recyclerSubscription.add(it) }
|
||||
recyclerAdapter?.taskOpenEvents?.subscribeWithErrorHandler {
|
||||
openTaskForm(it.first)
|
||||
}?.let { recyclerSubscription.add(it) }
|
||||
recyclerAdapter?.taskScoreEvents
|
||||
?.doOnNext {
|
||||
playSound(it.second)
|
||||
context?.let { it1 -> 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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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<ImageView>(R.id.checkmark)
|
||||
checkmark?.drawable?.setTintMode(PorterDuff.Mode.SRC_ATOP)
|
||||
|
|
|
|||
|
|
@ -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 {
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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) {
|
||||
|
|
|
|||
|
|
@ -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())
|
||||
|
|
|
|||
|
|
@ -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"
|
||||
|
|
|
|||
|
|
@ -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) {
|
||||
|
|
|
|||
14
build.gradle
14
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'
|
||||
|
|
|
|||
Loading…
Reference in a new issue